cogpit-memory 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,7 @@ export { AGENT_KINDS } from "./types";
21
21
  * point: a fourth CLI adds one row here instead of a new arm in 40 conditionals.
22
22
  */
23
23
  export interface AgentCapabilities {
24
- /** Git worktrees, which Cogpit stores under the Claude projects tree. */
24
+ /** Launch a session in a worktree managed by its CLI. */
25
25
  readonly worktrees: boolean;
26
26
  /** MCP server configuration can be passed at spawn time. */
27
27
  readonly mcp: boolean;
@@ -59,8 +59,18 @@ export interface AgentCapabilities {
59
59
  * exist only for models whose live catalog entry advertises them.
60
60
  */
61
61
  readonly reasoningEffort: boolean;
62
+ readonly configurableContextWindow: boolean;
62
63
  /** A faster/priority service tier can be requested. */
63
64
  readonly fastTier: boolean;
65
+ /**
66
+ * The CLI can carry a session past a spent session allowance by continuing at
67
+ * lower priority, spending the weekly allowance to do it. The mode is reached
68
+ * only from the CLI's own terminal UI — no flag, no setting, and nothing on
69
+ * the programmatic interface Cogpit drives — so the hand-off is all Cogpit
70
+ * can offer. Never true for an agent billed per request, which has no
71
+ * allowance to run out of in the first place.
72
+ */
73
+ readonly lowPriorityInTerminal: boolean;
64
74
  /**
65
75
  * Images may be attached when the selected model's catalog entry says nothing
66
76
  * about its input modalities. When false, vision has to be advertised.
@@ -68,6 +78,8 @@ export interface AgentCapabilities {
68
78
  readonly imageInput: boolean;
69
79
  /** A message can be delivered into an already-running turn. */
70
80
  readonly midTurnSteering: boolean;
81
+ /** Shared informational input can join active work at the provider's next opportunity. */
82
+ readonly activeNotifications: boolean;
71
83
  /** The whole session can be shut down from the composer. */
72
84
  readonly stopSession: boolean;
73
85
  /** Maximum-effort orchestration mode, pinned to the top effort level. */
@@ -85,6 +97,7 @@ export interface AgentCapabilities {
85
97
  readonly modelFallbackNotices: boolean;
86
98
  /** Whether an unattended "auto" permission mode can be offered. */
87
99
  readonly autoPermissionMode: "never" | "per-model" | "always";
100
+ readonly toolPermissionRules: boolean;
88
101
  /** Whether composer settings take effect immediately or on the next turn. */
89
102
  readonly settingsApply: "live" | "next-turn";
90
103
  /**
@@ -107,6 +120,8 @@ export interface AgentDirNameCodec {
107
120
  readonly lossy: boolean;
108
121
  /** True when `dirName` belongs to this agent. */
109
122
  owns(dirName: string | null | undefined): boolean;
123
+ /** True when `dirName` is a name `encode` produces, rather than one this agent merely owns. */
124
+ recognizes(dirName: string): boolean;
110
125
  /** Encode a project path as this agent's dirName. */
111
126
  encode(cwd: string): string;
112
127
  /** Decode one of this agent's dirNames back to a project path. */
@@ -125,6 +140,22 @@ export interface AgentSessionFileCodec {
125
140
  urlId(fileName: string): string;
126
141
  /** Exact inverse of `urlId`. */
127
142
  fileNameFromUrlId(urlId: string): string;
143
+ /**
144
+ * The top-level session a transcript belongs to, so a sub-agent or workflow
145
+ * transcript answers with the session that spawned it. Takes the file's
146
+ * canonical path — symlinks resolved, `/`-separated — relative to the
147
+ * project directory where the agent has one on disk, to the sessions root
148
+ * otherwise; `AgentStore.transcriptRoot` produces exactly that. Null for a
149
+ * path that could step outside it or names no session.
150
+ */
151
+ transcriptRoot(relativePath: string): TranscriptRoot | null;
152
+ }
153
+ /** The top-level session a transcript belongs to. */
154
+ export interface TranscriptRoot {
155
+ /** Lowercased. */
156
+ rootSessionId: string;
157
+ /** False for a sub-agent's or workflow's transcript filed under that session. */
158
+ isRootTranscript: boolean;
128
159
  }
129
160
  export interface AgentResumeCodec {
130
161
  /** Copy-pasteable shell command that reopens the session in a terminal. */
@@ -184,6 +215,9 @@ export interface AgentCli {
184
215
  readonly homeDirName: string;
185
216
  /** Environment variable overriding that directory, if the CLI has one. */
186
217
  readonly homeEnvVar: string | null;
218
+ readonly sdkHomeEnvVar?: string;
219
+ /** The native session ID this CLI supplies to its shell commands. */
220
+ readonly sessionIdEnvVar?: string;
187
221
  /**
188
222
  * Path inside the home whose existence proves the CLI has been used. Empty
189
223
  * when the home directory itself is the evidence.
@@ -195,6 +229,7 @@ export interface AgentCli {
195
229
  * that configuration is missing; the rest sit at a fixed, env-overridable
196
230
  * location and can be found on a first run.
197
231
  */
232
+ readonly requiresConfiguration?: boolean;
198
233
  readonly homeIsDiscoverable: boolean;
199
234
  readonly process: AgentProcessMatch;
200
235
  }
@@ -211,6 +246,8 @@ export interface AgentConfigFile {
211
246
  readonly scopes: readonly AgentConfigScope[];
212
247
  /** Tree label; defaults to `path`. */
213
248
  readonly label?: string;
249
+ /** Read only when none of the agent's other instruction files exist at that scope. */
250
+ readonly fallback?: true;
214
251
  }
215
252
  /**
216
253
  * Where a CLI reads its instructions, settings and extensions from. Drives the
@@ -329,6 +366,8 @@ export interface AgentDescriptor {
329
366
  readonly binName: string;
330
367
  readonly dirName: AgentDirNameCodec;
331
368
  readonly sessionFile: AgentSessionFileCodec;
369
+ /** Folder inside a project where the CLI cuts its worktrees; null when they live elsewhere. */
370
+ readonly projectWorktreeDir: string | null;
332
371
  /**
333
372
  * Whether header metadata is complete after reading only the first bytes of a
334
373
  * transcript. False when an exact line count or the last user message matters
@@ -385,3 +424,6 @@ export declare function projectDirNameFor(kind: AgentKind, cwd: string, knownDir
385
424
  export declare function sessionIdFromFileName(kind: AgentKind, fileName: string): string | null;
386
425
  /** True when `value` is a bare session UUID. */
387
426
  export declare function isSessionUuid(value: string): boolean;
427
+ /** Canonical access identity, preserving the instance token's case. */
428
+ export declare function canonicalSessionId(value: string): string | null;
429
+ export declare const PERSISTED_AGENT_HOME_FIELD = "claudeDir";
@@ -42,12 +42,25 @@ export interface AgentFormat {
42
42
  /** Status derived from raw records. */
43
43
  status(records: readonly RawRecord[]): SessionStatusInfo;
44
44
  /**
45
- * The first record of a transcript, rewritten for a branch: it now names
46
- * `sessionId` and records the session and turn it was cut from. Returns the
47
- * id the record carried before, which is what the branch reports as its
48
- * origin.
45
+ * True for a raw line the CLI writes for its own bookkeeping that no reader
46
+ * of the transcript uses. The server drops these before paging or streaming,
47
+ * so they never take a page's byte budget or line floor.
49
48
  */
50
- brandBranch(firstRecord: Record<string, unknown>, sessionId: string, turnIndex: number | null): {
49
+ isNoiseLine(line: string): boolean;
50
+ /**
51
+ * The transcript's first line as a page of it carries it, when a reader of
52
+ * one page needs facts about the rest of the file. `lastLines` reads the
53
+ * file's last complete lines.
54
+ */
55
+ pageHeaderLine?(firstLine: string, lastLines: () => Promise<readonly string[]>): Promise<string>;
56
+ /**
57
+ * The first record of a transcript, rewritten for a branch cut at
58
+ * `branchedAt`: it now names `sessionId` and records the session and turn
59
+ * it was cut from, and when, where the copied lines cannot otherwise be
60
+ * told from the branch's own. Returns the id the record carried before,
61
+ * which is what the branch reports as its origin.
62
+ */
63
+ brandBranch(firstRecord: Record<string, unknown>, sessionId: string, turnIndex: number | null, branchedAt: number): {
51
64
  record: Record<string, unknown>;
52
65
  originalId: string;
53
66
  };
@@ -74,6 +87,8 @@ export declare function formatForText(jsonlText: string): AgentFormat;
74
87
  export declare function formatForRecords(records: readonly {
75
88
  type?: unknown;
76
89
  }[]): AgentFormat;
90
+ /** `isNoiseLine` for a scan that reads lines before it knows which agent wrote them. */
91
+ export declare function isAnyAgentNoiseLine(line: string): boolean;
77
92
  /**
78
93
  * Boundary indexes for raw JSONL lines rather than parsed records.
79
94
  *
@@ -94,15 +109,25 @@ export declare function cutLineForTurnCount(format: AgentFormat, lines: readonly
94
109
  */
95
110
  export declare function cutLineAfterTurnIndex(format: AgentFormat, lines: readonly string[], turnIndex: number): number | null;
96
111
  /**
97
- * The line to cut at to keep everything through the turn containing the record
98
- * whose `uuid` is `turnUuid`. Correct even when the caller has only a tail of
99
- * the transcript loaded, so its turn indexes do not match file order.
112
+ * Each turn's first line paired with the id the parser gives that turn, in file
113
+ * order. Null when the two do not pair up, which would mean the ids cannot be
114
+ * trusted to name these lines.
115
+ *
116
+ * This is what lets a caller holding only the loaded tail of a transcript name
117
+ * a turn: its window index says nothing about file order, but its id does.
118
+ */
119
+ export declare function turnStartsWithIds(format: AgentFormat, lines: readonly string[]): {
120
+ line: number;
121
+ id: string;
122
+ }[] | null;
123
+ /**
124
+ * The line to cut at to keep everything through the turn whose id is `turnId`.
100
125
  *
101
- * `"keep-all"` means the uuid was found in the last turn (nothing to remove);
102
- * null means it was not found at all, and the caller should fall back to an
103
- * index-based cut.
126
+ * `"keep-all"` means it is the last turn (nothing to remove); null means no
127
+ * turn has that id — an agent may leave a turn unlabelled — and the caller
128
+ * should fall back to an index-based cut.
104
129
  */
105
- export declare function cutLineAfterUuid(format: AgentFormat, lines: readonly string[], turnUuid: string): number | "keep-all" | null;
130
+ export declare function cutLineAfterTurnId(format: AgentFormat, lines: readonly string[], turnId: string): number | "keep-all" | null;
106
131
  /**
107
132
  * The tool calls a recorded call actually ran. Every format records one call
108
133
  * per tool use except Codex code mode, which persists a whole script of them as
@@ -0,0 +1,16 @@
1
+ import type { BackgroundAgent, SessionStatusInfo } from "./types";
2
+ /** A launched background agent, placed by the transcript records that started and ended it. */
3
+ export interface AgentLaunch {
4
+ agent: Omit<BackgroundAgent, "done">;
5
+ /** Index of the record that launched it */
6
+ launchedAt: number;
7
+ /** Index of the record that completed, failed or stopped it; absent while it runs */
8
+ endedAt?: number;
9
+ }
10
+ /**
11
+ * The awaiting-agents status for a session's background agents, or null when
12
+ * none is still running. The batch is every agent launched since the last
13
+ * moment no agent was running, so agents that already finished in this wait
14
+ * still count toward its progress.
15
+ */
16
+ export declare function awaitingAgentsStatus(launches: readonly AgentLaunch[], pendingQueue?: number): SessionStatusInfo | null;
@@ -9,6 +9,16 @@ import type { ParseSessionOptions, ParsedSession, RawRecord, SessionStatusInfo }
9
9
  * registry exists to remove.
10
10
  */
11
11
  export declare function isClaudeSessionText(): boolean;
12
+ /**
13
+ * True for the `api-request`, `api-request-blob` and `api-request-shape`
14
+ * records Claude Code 2.1.300+ logs for every API call. Nothing reads them,
15
+ * and they can be most of a transcript's bytes.
16
+ *
17
+ * Inside a JSON string every quote is escaped, so `"type":"api-request` can
18
+ * only be a key and its value; with no `{` before it but the line's own, it is
19
+ * the top-level key, wherever the writer put it.
20
+ */
21
+ export declare function isClaudeNoiseLine(line: string): boolean;
12
22
  export interface ClaudeMetadata {
13
23
  sessionId: string;
14
24
  version: string;
@@ -25,6 +25,38 @@ interface CodexMetadata {
25
25
  /** Canonical collaboration path for the agent that owns this rollout. */
26
26
  agentPath: string;
27
27
  }
28
+ /**
29
+ * The session a rollout was forked or spawned from, read from its
30
+ * `session_meta` payload. Forks name it in `forked_from_id`; spawned threads
31
+ * and reviews in `parent_thread_id`, and some spawned threads only under
32
+ * `source.subagent.thread_spawn`.
33
+ */
34
+ export declare function codexParentId(payload: Record<string, unknown>): string | null;
35
+ /**
36
+ * A rollout's first line as a page of it carries it: a sub-agent's
37
+ * `session_meta` gains the ordinal of the rollout's last record, so a page
38
+ * holding only copied history still knows its history boundary is real.
39
+ */
40
+ export declare function codexPageHeaderLine(firstLine: string, lastLines: () => Promise<readonly string[]>): Promise<string>;
41
+ /**
42
+ * The prompt a record carries, or "" for any other record, including the
43
+ * AGENTS.md, environment and other context Codex injects as user messages.
44
+ */
45
+ export declare function codexPromptText(record: {
46
+ type?: unknown;
47
+ payload?: unknown;
48
+ }): string;
49
+ /**
50
+ * Reads each prompt in a rollout once, fed its records in order.
51
+ *
52
+ * Codex 0.15x+ writes a prompt only as a `response_item` user message. Older
53
+ * CLIs follow that record with an `event_msg` `user_message` echo of it, which
54
+ * this skips.
55
+ */
56
+ export declare function createCodexPromptReader(): (record: {
57
+ type?: unknown;
58
+ payload?: unknown;
59
+ }) => string;
28
60
  export declare function isCodexSessionText(jsonlText: string): boolean;
29
61
  /** True when already-parsed raw records came from this CLI. */
30
62
  export declare function isCodexRawRecords(records: readonly {
@@ -42,8 +74,12 @@ export declare function parseCodexSession(jsonlText: string, options?: ParseSess
42
74
  export declare function appendCodexSession(existing: ParsedSession, newJsonlText: string): ParsedSession;
43
75
  /** Derive status by walking backward through a rollout's records. */
44
76
  export declare function deriveCodexSessionStatus(rawMessages: readonly RawRecord[]): SessionStatusInfo;
45
- /** A branch keeps the `session_meta` record, renamed and pointed back at its origin. */
46
- export declare function brandCodexBranch(firstRecord: Record<string, unknown>, sessionId: string, turnIndex: number | null): {
77
+ /**
78
+ * A branch keeps the `session_meta` record, renamed and pointed back at its
79
+ * origin. The copied lines keep their origin's timestamps, so `at` is what
80
+ * tells them from the branch's own.
81
+ */
82
+ export declare function brandCodexBranch(firstRecord: Record<string, unknown>, sessionId: string, turnIndex: number | null, branchedAt: number): {
47
83
  record: Record<string, unknown>;
48
84
  originalId: string;
49
85
  };
@@ -12,6 +12,7 @@ export declare const dirs: {
12
12
  TASKS_DIR: string;
13
13
  CODEX_SESSIONS_DIR: string;
14
14
  COPILOT_SESSIONS_DIR: string;
15
+ ACP_PROJECTS_DIR: string;
15
16
  };
16
17
  /** Default database path for the FTS5 search index. */
17
18
  export declare const DEFAULT_DB_PATH: string;
@@ -0,0 +1,12 @@
1
+ import type { ParsedSession } from "./types";
2
+ export declare function instanceSessionId(instanceId: string, nativeId: string): string;
3
+ export declare function splitInstanceSessionId(id: string): {
4
+ instanceId: string;
5
+ nativeId: string;
6
+ };
7
+ export declare function instanceDirName(instanceId: string, nativeDirName: string): string;
8
+ export declare function splitInstanceDirName(dirName: string | null | undefined): {
9
+ instanceId: string;
10
+ nativeDirName: string;
11
+ };
12
+ export declare function scopeParsedSession(session: ParsedSession, instanceId: string): ParsedSession;
@@ -0,0 +1 @@
1
+ export declare function parseTranscript(content: string, filePath: string): import("./types").ParsedSession;
@@ -11,6 +11,7 @@ export interface SessionFile {
11
11
  export type SessionFileIdentity = Omit<SessionFile, "path" | "mtimeMs">;
12
12
  export interface AgentSessionStore {
13
13
  readonly kind: AgentKind;
14
+ readonly instanceId: string;
14
15
  readonly descriptor: AgentDescriptor;
15
16
  /** Absolute root this agent's transcripts live under. */
16
17
  root(): string;
@@ -0,0 +1,12 @@
1
+ import type { ToolCall, ToolFileDiff } from "./types";
2
+ export declare function toolResultMetadata(name: string, value: unknown): Pick<ToolCall, "awaitingReview" | "fileDiffs" | "additionalFileDiffs">;
3
+ export declare function formatToolFileDiff(file: ToolFileDiff): string;
4
+ export declare function toolDiffEdits(files: readonly ToolFileDiff[]): Array<{
5
+ filePath: string;
6
+ oldString: string;
7
+ newString: string;
8
+ diffLineCounts: {
9
+ add: number;
10
+ del: number;
11
+ };
12
+ }>;
@@ -0,0 +1,22 @@
1
+ export declare function isCompressedTranscript(filePath: string): boolean;
2
+ /** The name a transcript has uncompressed. */
3
+ export declare function uncompressedTranscriptName(fileName: string): string;
4
+ /**
5
+ * Whether a directory entry is a transcript this runtime can read, given its
6
+ * siblings: mid-compression both forms exist, and the plain one is current.
7
+ */
8
+ export declare function isListableTranscript(name: string, siblings: ReadonlySet<string>): boolean;
9
+ export declare function readTranscriptTextSync(filePath: string): string;
10
+ export declare function readTranscriptText(filePath: string): Promise<string>;
11
+ /** The subset of a `FileHandle` transcript readers use. */
12
+ export interface TranscriptHandle {
13
+ read(buffer: Buffer, offset: number, length: number, position: number): Promise<{
14
+ bytesRead: number;
15
+ }>;
16
+ stat(): Promise<{
17
+ size: number;
18
+ mtimeMs: number;
19
+ }>;
20
+ close(): Promise<void>;
21
+ }
22
+ export declare function openTranscript(filePath: string): Promise<TranscriptHandle>;
@@ -1,5 +1,5 @@
1
1
  /** The agent CLIs Cogpit can drive. */
2
- export type AgentKind = "claude" | "codex" | "copilot";
2
+ export type AgentKind = "claude" | "codex" | "copilot" | "acp";
3
3
  /**
4
4
  * Every agent kind, in transcript-detection order. Codex and Copilot carry
5
5
  * positive discriminators in their records; Claude is the terminal fallback and
@@ -19,6 +19,19 @@ export interface SessionStatusInfo {
19
19
  pendingAgents?: number;
20
20
  /** Short descriptions of the pending background agents, oldest first */
21
21
  pendingAgentDescriptions?: string[];
22
+ /** Agents launched since the oldest one still running, in launch order (status awaiting_agents) */
23
+ backgroundAgents?: BackgroundAgent[];
24
+ }
25
+ /** A background agent launched by the session. */
26
+ export interface BackgroundAgent {
27
+ /** What the agent was asked to do; empty when the launch carried no description */
28
+ description: string;
29
+ /** When the agent was launched (ISO), if the transcript records it */
30
+ startedAt?: string;
31
+ /** The launching tool call, which keys the agent's live progress summaries */
32
+ toolUseId?: string;
33
+ /** Finished, failed or stopped */
34
+ done: boolean;
22
35
  }
23
36
  /** A raw transcript record, before any agent-specific interpretation. */
24
37
  export type RawRecord = {
@@ -126,7 +139,10 @@ export interface UserMessage extends BaseMessage {
126
139
  thinkingMetadata?: {
127
140
  maxThinkingTokens: number;
128
141
  };
129
- toolUseResult?: AgentToolUseResult;
142
+ toolUseResult?: Partial<AgentToolUseResult> & {
143
+ staged?: boolean;
144
+ bashEditDiff?: unknown;
145
+ };
130
146
  sourceToolAssistantUUID?: string;
131
147
  }
132
148
  export interface TokenUsage {
@@ -199,8 +215,17 @@ export interface AgentProgressData {
199
215
  };
200
216
  prompt: string;
201
217
  agentId: string;
218
+ /**
219
+ * Written by Cogpit's subagent watcher. The Agent call that launched this
220
+ * agent, when that differs from the record's `parentToolUseID` — a nested
221
+ * agent's records are filed under the main-thread call it descends from.
222
+ */
223
+ toolUseId?: string;
224
+ /** The subagent that launched this one (the CLI's `parent_task_id`). */
225
+ parentAgentId?: string;
226
+ subagentType?: string;
202
227
  }
203
- export type HookEventName = "PreToolUse" | "PostToolUse" | "PostToolUseFailure" | "UserPromptSubmit" | "SessionStart" | "SessionEnd" | "Stop" | "StopFailure" | "SubagentStop" | "PreCompact" | "PostCompact" | "PermissionDenied" | "TaskCreated" | "WorktreeCreate" | "CwdChanged" | "FileChanged" | "Elicitation" | "ElicitationResult" | "Notification";
228
+ export type HookEventName = "PreToolUse" | "PostToolUse" | "PostToolUseFailure" | "UserPromptSubmit" | "SessionStart" | "SessionEnd" | "Stop" | "StopFailure" | "SubagentStop" | "PreCompact" | "PostCompact" | "PreModelSwitch" | "PostModelSwitch" | "PermissionDenied" | "TaskCreated" | "WorktreeCreate" | "CwdChanged" | "FileChanged" | "Elicitation" | "ElicitationResult" | "Notification";
204
229
  export interface HookProgressData {
205
230
  type: "hook_progress";
206
231
  /** Event name (newer SDK: hook_event_name; older SDK: hookEvent) */
@@ -268,9 +293,14 @@ export interface SystemMessage extends BaseMessage {
268
293
  isMeta?: boolean;
269
294
  content?: string;
270
295
  compactMetadata?: CompactionMeta;
296
+ /** On a `local_command` record answering `/context`. */
297
+ contextUsage?: LocalCommandContextUsage;
298
+ /** On a `local_command` record answering `/usage`. */
299
+ usageReport?: LocalCommandUsageReport;
271
300
  }
272
301
  export interface CompactionMeta {
273
- trigger: "auto" | "manual";
302
+ /** "idle" (Claude Code 2.1.290+) compacts while the session waits for the user. */
303
+ trigger: "auto" | "manual" | "idle";
274
304
  preTokens: number;
275
305
  postTokens?: number;
276
306
  }
@@ -346,6 +376,16 @@ export interface AgentSettingMessage extends BaseMessage {
346
376
  agentSetting?: string;
347
377
  }
348
378
  export type RawMessage = UserMessage | AssistantMessage | ProgressMessage | SystemMessage | FileHistorySnapshotMessage | SummaryMessage | QueueOperationMessage | AttachmentMessage;
379
+ export interface ToolFileDiff {
380
+ filePath: string;
381
+ hunks: Array<{
382
+ oldStart: number;
383
+ oldLines: number;
384
+ newStart: number;
385
+ newLines: number;
386
+ lines: string[];
387
+ }>;
388
+ }
349
389
  export interface ToolCall {
350
390
  id: string;
351
391
  name: string;
@@ -354,6 +394,14 @@ export interface ToolCall {
354
394
  /** Binary images returned by a tool, when the provider persists them. */
355
395
  resultImages?: ImageBlock[];
356
396
  isError: boolean;
397
+ awaitingReview?: boolean;
398
+ fileDiffs?: ToolFileDiff[];
399
+ additionalFileDiffs?: number;
400
+ /** Counts from one structured file diff, before combining it with later edits. */
401
+ diffLineCounts?: {
402
+ add: number;
403
+ del: number;
404
+ };
357
405
  timestamp: string;
358
406
  /**
359
407
  * A question whose tool result is only an acceptance receipt. Codex's
@@ -372,6 +420,8 @@ export interface SubAgentMessage {
372
420
  agentId: string;
373
421
  /** The Task/Agent tool_use id this agent belongs to (streaming overlay key) */
374
422
  parentToolUseId?: string;
423
+ /** The subagent that launched this one; absent when the main thread did. */
424
+ parentAgentId?: string;
375
425
  agentName: string | null;
376
426
  subagentType: string | null;
377
427
  type: "user" | "assistant";
@@ -382,6 +432,8 @@ export interface SubAgentMessage {
382
432
  timestamp: string;
383
433
  tokenUsage: TokenUsage | null;
384
434
  model: string | null;
435
+ /** Reasoning effort the agent ran at, when its spawn recorded one. */
436
+ effort?: string;
385
437
  isBackground: boolean;
386
438
  /** Summary fields from toolUseResult (new format, v2.1.63+) */
387
439
  prompt?: string;
@@ -468,7 +520,103 @@ export type TurnContentBlock = {
468
520
  kind: "task_notification";
469
521
  content: string;
470
522
  timestamp?: string;
523
+ }
524
+ /**
525
+ * Output of a slash command that ran locally and answered the user directly
526
+ * (`/usage`, `/context`, `/recap`), recorded as a `local_command` system
527
+ * record. `content` is the raw record text, `<local-command-stdout>` tags
528
+ * included, left for the renderers like `task_notification`. Newer CLIs
529
+ * record a structured twin of `/context` and `/usage` beside the text.
530
+ */
531
+ | {
532
+ kind: "local_command";
533
+ content: string;
534
+ timestamp?: string;
535
+ contextUsage?: LocalCommandContextUsage;
536
+ usageReport?: LocalCommandUsageReport;
471
537
  };
538
+ /** One `/context` category row. Classify on `kind`, never on the display name. */
539
+ export interface ContextUsageCategory {
540
+ name: string;
541
+ tokens: number;
542
+ /** `deferred` rows sit outside the window and stay out of the usage math. */
543
+ kind: "used" | "free" | "buffer" | "deferred";
544
+ }
545
+ /** The structured twin of a `/context` reply, as the CLI records it. */
546
+ export interface LocalCommandContextUsage {
547
+ model: string;
548
+ total_tokens: number;
549
+ /** The window usage is measured against. */
550
+ raw_max_tokens: number;
551
+ percentage: number;
552
+ over_limit?: {
553
+ tokens_over: number;
554
+ kind: "hard_limit" | "compaction_window";
555
+ };
556
+ categories: ContextUsageCategory[];
557
+ mcp_tools?: {
558
+ name: string;
559
+ server_name: string;
560
+ tokens: number;
561
+ }[];
562
+ memory_files?: {
563
+ path: string;
564
+ type: string;
565
+ tokens: number;
566
+ }[];
567
+ agents?: {
568
+ agent_type: string;
569
+ source: string;
570
+ tokens: number;
571
+ }[];
572
+ skills?: {
573
+ name: string;
574
+ source: string;
575
+ plugin_name?: string;
576
+ tokens: number;
577
+ }[];
578
+ }
579
+ /** One plan meter of a `/usage` reply, rendered in the server's order and grading. */
580
+ export interface UsageLimitRow {
581
+ /** The meter kind, e.g. `session`, `weekly_all`, `weekly_scoped`. */
582
+ kind: string;
583
+ group: string;
584
+ percent: number;
585
+ resets_at: string | null;
586
+ scope?: {
587
+ model?: {
588
+ display_name: string;
589
+ } | null;
590
+ surface?: {
591
+ display_name: string;
592
+ } | null;
593
+ } | null;
594
+ /** e.g. `normal`, `warning`, `critical`. */
595
+ severity: string;
596
+ is_active: boolean;
597
+ }
598
+ /** The structured twin of a `/usage` reply, as the CLI records it. */
599
+ export interface LocalCommandUsageReport {
600
+ session: {
601
+ total_cost_usd: number;
602
+ total_api_duration_ms: number;
603
+ total_duration_ms: number;
604
+ total_lines_added: number;
605
+ total_lines_removed: number;
606
+ };
607
+ /** Null when the plan's usage could not be fetched (no plan, API key). */
608
+ rate_limits: {
609
+ limits: UsageLimitRow[] | null;
610
+ /** Amounts are in minor units of `currency`. */
611
+ extra_usage?: {
612
+ is_enabled: boolean;
613
+ monthly_limit: number | null;
614
+ used_credits: number | null;
615
+ utilization: number | null;
616
+ currency?: string | null;
617
+ } | null;
618
+ } | null;
619
+ }
472
620
  export interface Turn {
473
621
  id: string;
474
622
  userMessage: UserContent | null;
@@ -553,6 +701,7 @@ export interface ParsedSession {
553
701
  * of truth — the session's dirName is (see `shared/session/agents.ts`).
554
702
  */
555
703
  agentKind?: AgentKind;
704
+ instanceId?: string;
556
705
  }
557
706
  export interface ArchivedToolCall {
558
707
  type: "Edit" | "Write";
@@ -564,6 +713,8 @@ export interface ArchivedToolCall {
564
713
  }
565
714
  export interface ArchivedTurn {
566
715
  index: number;
716
+ /** The archived turn's `Turn.id`. Absent on archives written before ids were kept. */
717
+ id?: string;
567
718
  userMessage: string | null;
568
719
  toolCalls: ArchivedToolCall[];
569
720
  thinkingBlocks: string[];
@@ -574,7 +725,14 @@ export interface ArchivedTurn {
574
725
  export interface Branch {
575
726
  id: string;
576
727
  createdAt: string;
728
+ /**
729
+ * Position of the fork turn among the turns loaded when this was written.
730
+ * Only a long session's tail is loaded, so it is re-resolved from
731
+ * `branchPointTurnId` on every read and trusted as stored only without one.
732
+ */
577
733
  branchPointTurnIndex: number;
734
+ /** `Turn.id` of the last turn kept before the fork; null when none was kept. */
735
+ branchPointTurnId?: string | null;
578
736
  label: string;
579
737
  turns: ArchivedTurn[];
580
738
  jsonlLines: string[];
@@ -583,8 +741,6 @@ export interface Branch {
583
741
  }
584
742
  export interface UndoState {
585
743
  sessionId: string;
586
- currentTurnIndex: number;
587
- totalTurns: number;
588
744
  branches: Branch[];
589
745
  activeBranchId: string | null;
590
746
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogpit-memory",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "CLI tool for Claude Code, Codex, and GitHub Copilot CLI session introspection",
5
5
  "license": "MIT",
6
6
  "repository": {