chasm-cli 1.5.4

Universal chat session manager - harvest, merge, and analyze AI chat history from VS Code, Cursor, and other editors
Documentation
"""Check what the 'response' field actually is in sessions."""
import json, os

WS_BASE = r"C:\Users\adamm\AppData\Roaming\Code\User\workspaceStorage"

files = {
    "WORKING_44f0": os.path.join(WS_BASE, "82cdabb21413f2ff42168423e82c8bdf", "chatSessions", "44f0cf62-331e-43c9-b32c-25d91ebab0b8.jsonl"),
    "BROKEN_6be2": os.path.join(WS_BASE, "5ec71800c69c79b96b06a37e38537907", "chatSessions", "6be29cba-331e-4aa4-bc58-659cc20f4800.jsonl"),
    "BROKEN_4e5d": os.path.join(WS_BASE, "724ab159cbc91cdd8242d9b5aa690c3b", "chatSessions", "4e5dd6b4-ea53-475b-8f9e-8fad3bf59388.jsonl"),
    "BROKEN_53a6": os.path.join(WS_BASE, "c8f466664b769ee6a567242b576fb955", "chatSessions", "53a6df5c-02ef-462f-8046-e06b6738d0d3.jsonl"),  # Framewerx
    "BROKEN_Cyborg": os.path.join(WS_BASE, "cc60bfebb242bac1578d7b49a44033db", "chatSessions", "527646cd-d49e-4b0c-b51b-83abd51f9080.jsonl"),
}

for label, path in files.items():
    print(f"\n{'='*70}")
    print(f"{label}")
    print(f"{'='*70}")
    
    with open(path, 'r', encoding='utf-8') as f:
        text = f.read()
    
    # Parse all objects
    objects = []
    decoder = json.JSONDecoder()
    for line in text.split('\n'):
        line = line.strip()
        if not line:
            continue
        p = 0
        while p < len(line):
            try:
                obj, end = decoder.raw_decode(line, p)
                objects.append(obj)
                p = end
                while p < len(line) and line[p] in ' \t':
                    p += 1
            except:
                break
    
    # Find the kind:0 object
    for obj in objects:
        if obj.get('kind') == 0:
            v = obj['v']
            requests = v.get('requests', [])
            print(f"Session: {v.get('sessionId', '?')}")
            print(f"Requests: {len(requests)}")
            
            for ri, req in enumerate(requests):
                print(f"\n  Request {ri}:")
                resp = req.get('response')
                print(f"    response type: {type(resp).__name__}")
                if resp is None:
                    print(f"    response is None!")
                elif isinstance(resp, list):
                    print(f"    response is LIST with {len(resp)} items")
                    for pi, part in enumerate(resp[:3]):
                        print(f"      [{pi}] type={type(part).__name__}")
                        if isinstance(part, dict):
                            print(f"      [{pi}] keys={sorted(part.keys())}")
                            print(f"      [{pi}] kind={part.get('kind', 'NO_KIND')}")
                elif isinstance(resp, dict):
                    print(f"    response keys: {sorted(resp.keys())}")
                    val = resp.get('value')
                    print(f"    response.value type: {type(val).__name__}")
                    if isinstance(val, list):
                        print(f"    response.value parts: {len(val)}")
                        for pi, part in enumerate(val[:3]):
                            if isinstance(part, dict):
                                print(f"      [{pi}] kind={part.get('kind', 'NO_KIND')}, keys={sorted(part.keys())}")
                    elif isinstance(val, dict):
                        print(f"    response.value is dict: {sorted(val.keys())}")
                else:
                    print(f"    response is {type(resp).__name__}: {str(resp)[:200]}")
                
                # Also check modelState
                ms = req.get('modelState')
                print(f"    modelState: {json.dumps(ms)}")
                
                # Check message
                msg = req.get('message', {})
                if isinstance(msg, dict):
                    print(f"    message.text: {msg.get('text', '')[:100]}")
                    parts = msg.get('parts', [])
                    print(f"    message.parts: {len(parts)} items")
            break  # Only first kind:0

# Also directly check: what does VS Code log about these sessions?
# Check if any session files are completely missing content
print(f"\n\n{'='*70}")
print("FULL KEY DIFF: working va broken request fields")
print(f"{'='*70}")

# Collect all request field keys from multiple sessions
working_keys = set()
broken_keys = set()

working_sessions = [
    os.path.join(WS_BASE, "82cdabb21413f2ff42168423e82c8bdf", "chatSessions", "44f0cf62-331e-43c9-b32c-25d91ebab0b8.jsonl"),
    os.path.join(WS_BASE, "82cdabb21413f2ff42168423e82c8bdf", "chatSessions", "bc6d5655-0778-4d67-8d68-660821103ca8.jsonl"),
]

broken_sessions = [
    os.path.join(WS_BASE, "5ec71800c69c79b96b06a37e38537907", "chatSessions", "6be29cba-331e-4aa4-bc58-659cc20f4800.jsonl"),
    os.path.join(WS_BASE, "724ab159cbc91cdd8242d9b5aa690c3b", "chatSessions", "4e5dd6b4-ea53-475b-8f9e-8fad3bf59388.jsonl"),
    os.path.join(WS_BASE, "c8f466664b769ee6a567242b576fb955", "chatSessions", "53a6df5c-02ef-462f-8046-e06b6738d0d3.jsonl"),
]

for path in working_sessions:
    with open(path, 'r') as f:
        text = f.read()
    decoder = json.JSONDecoder()
    for line in text.split('\n'):
        line = line.strip()
        if not line: continue
        p = 0
        while p < len(line):
            try:
                obj, end = decoder.raw_decode(line, p)
                if obj.get('kind') == 0:
                    for req in obj['v'].get('requests', []):
                        working_keys.update(req.keys())
                        resp = req.get('response')
                        if isinstance(resp, dict):
                            working_keys.update(f"response.{k}" for k in resp.keys())
                        elif isinstance(resp, list):
                            working_keys.add("response=LIST")
                p = end
                while p < len(line) and line[p] in ' \t': p += 1
            except: break

for path in broken_sessions:
    with open(path, 'r') as f:
        text = f.read()
    decoder = json.JSONDecoder()
    for line in text.split('\n'):
        line = line.strip()
        if not line: continue
        p = 0
        while p < len(line):
            try:
                obj, end = decoder.raw_decode(line, p)
                if obj.get('kind') == 0:
                    for req in obj['v'].get('requests', []):
                        broken_keys.update(req.keys())
                        resp = req.get('response')
                        if isinstance(resp, dict):
                            broken_keys.update(f"response.{k}" for k in resp.keys())
                        elif isinstance(resp, list):
                            broken_keys.add("response=LIST")
                p = end
                while p < len(line) and line[p] in ' \t': p += 1
            except: break

print(f"\nWorking request keys: {sorted(working_keys)}")
print(f"\nBroken request keys: {sorted(broken_keys)}")
print(f"\nOnly in working: {sorted(working_keys - broken_keys)}")
print(f"Only in broken: {sorted(broken_keys - working_keys)}")