@lmctl-ai/lmctl 0.1.341 → 0.2.2
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.
- package/CHANGELOG.md +131 -0
- package/README.md +11 -51
- package/data/price-aliases.json +1 -0
- package/data/price-data.json +1 -1
- package/dist/cli/batch.d.ts +2 -0
- package/dist/cli/busy-evidence.d.ts +27 -0
- package/dist/cli/chat-cycle.d.ts +59 -0
- package/dist/cli/chat-exec.d.ts +83 -0
- package/dist/cli/chat-policy.d.ts +22 -0
- package/dist/cli/chat.d.ts +23 -0
- package/dist/cli/code-resolver.d.ts +8 -0
- package/dist/cli/common.d.ts +54 -0
- package/dist/cli/context.d.ts +12 -0
- package/dist/cli/cost.d.ts +2 -0
- package/dist/cli/export.d.ts +2 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +1081 -1891
- package/dist/cli/infra.d.ts +78 -0
- package/dist/cli/ls.d.ts +2 -0
- package/dist/cli/mailbox-cli.d.ts +6 -0
- package/dist/cli/managed.d.ts +62 -0
- package/dist/cli/mcp-install.d.ts +23 -0
- package/dist/cli/mcp.d.ts +2 -0
- package/dist/cli/paths.d.ts +50 -0
- package/dist/cli/plan-wizard.d.ts +42 -0
- package/dist/cli/plan.d.ts +20 -0
- package/dist/cli/queue-delivery.d.ts +107 -0
- package/dist/cli/ratelimit.d.ts +3 -0
- package/dist/cli/remote-fetch.d.ts +7 -0
- package/dist/cli/run-queries.d.ts +82 -0
- package/dist/cli/running.d.ts +5 -0
- package/dist/cli/schema.sql +20 -1
- package/dist/cli/script.d.ts +6 -0
- package/dist/cli/script.js +2097 -0
- package/dist/cli/self-identity.d.ts +25 -0
- package/dist/cli/session-idle.d.ts +118 -0
- package/dist/cli/status.d.ts +22 -0
- package/dist/cli/tail.d.ts +18 -0
- package/dist/cli/target-resolver.d.ts +139 -0
- package/dist/cli/team-status.d.ts +91 -0
- package/dist/cli/teamfile-compat.d.ts +71 -0
- package/dist/cli/teamfile-store.d.ts +18 -0
- package/dist/cli/teamfile-template.d.ts +40 -0
- package/dist/cli/template-env.d.ts +25 -0
- package/dist/cli/terminal-lock.d.ts +25 -0
- package/dist/cli/terminal.d.ts +23 -0
- package/dist/cli/time-filter.d.ts +10 -0
- package/dist/cli/update-notifier.d.ts +11 -0
- package/dist/cli/version-util.d.ts +2 -0
- package/dist/config/seed_templates.d.ts +1 -0
- package/dist/db/backfill-event-log.d.ts +26 -0
- package/dist/db/delegation.d.ts +37 -0
- package/dist/db/escalation_vocab.d.ts +45 -0
- package/dist/db/event-log.d.ts +40 -0
- package/dist/db/index.d.ts +1213 -0
- package/dist/db/inflight-acquire.d.ts +70 -0
- package/dist/db/invocation-event-projections.d.ts +65 -0
- package/dist/db/ledger-identity.test.d.ts +1 -0
- package/dist/db/live-event-projections.d.ts +92 -0
- package/dist/db/migrate.d.ts +51 -0
- package/dist/db/open-readonly.d.ts +2 -0
- package/dist/db/process-liveness.d.ts +37 -0
- package/dist/db/sqlite.d.ts +47 -0
- package/dist/db/sqlite.test.d.ts +1 -0
- package/dist/db/terminal-lock.d.ts +14 -0
- package/dist/db/tracked-invocation-reconcile.d.ts +52 -0
- package/dist/db/tracked-invocation.d.ts +116 -0
- package/dist/mcp/dispatch.d.ts +45 -0
- package/dist/mcp/mediation.d.ts +128 -0
- package/dist/mcp/path-warning.d.ts +7 -0
- package/dist/mcp/server.d.ts +63 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/providers/adapter.d.ts +265 -0
- package/dist/providers/adapters/agy-adapter.d.ts +17 -0
- package/dist/providers/adapters/claude-adapter.d.ts +20 -0
- package/dist/providers/adapters/codex-adapter.d.ts +22 -0
- package/dist/providers/adapters/copilot-adapter.d.ts +16 -0
- package/dist/providers/adapters/dsh-adapter.d.ts +89 -0
- package/dist/providers/adapters/gemini-adapter.d.ts +44 -0
- package/dist/providers/adapters/hermes-adapter.d.ts +71 -0
- package/dist/providers/adapters/index.d.ts +35 -0
- package/dist/providers/adapters/kimi-adapter.d.ts +16 -0
- package/dist/providers/adapters/lmplayer-adapter.d.ts +14 -0
- package/dist/providers/adapters/opencode-adapter.d.ts +11 -0
- package/dist/providers/adapters/pi-adapter.d.ts +17 -0
- package/dist/providers/adapters/print-turn.d.ts +29 -0
- package/dist/providers/adapters/qwen-adapter.d.ts +11 -0
- package/dist/providers/agy.d.ts +32 -0
- package/dist/providers/base-adapter.d.ts +107 -0
- package/dist/providers/base.d.ts +12 -0
- package/dist/providers/binary-check.d.ts +102 -0
- package/dist/providers/bundle.d.ts +118 -0
- package/dist/providers/claude-mock.d.ts +90 -0
- package/dist/providers/claude.d.ts +21 -0
- package/dist/providers/codex-config.d.ts +15 -0
- package/dist/providers/codex.d.ts +25 -0
- package/dist/providers/config/model-selection-lint.d.ts +45 -0
- package/dist/providers/config/team-config.d.ts +183 -0
- package/dist/providers/config/types.d.ts +146 -0
- package/dist/providers/config/user-config.d.ts +88 -0
- package/dist/providers/copilot.d.ts +21 -0
- package/dist/providers/debug.d.ts +128 -0
- package/dist/providers/dsh-sidecar.d.ts +65 -0
- package/dist/providers/dsh-zstd.d.ts +27 -0
- package/dist/providers/dsh.d.ts +37 -0
- package/dist/providers/frontmatter.d.ts +46 -0
- package/dist/providers/gemini-session-reader.d.ts +151 -0
- package/dist/providers/gemini.d.ts +39 -0
- package/dist/providers/hermes.d.ts +90 -0
- package/dist/providers/index.d.ts +421 -0
- package/dist/providers/kimi.d.ts +37 -0
- package/dist/providers/model-catalog.d.ts +141 -0
- package/dist/providers/one-shot-timeout.d.ts +1 -0
- package/dist/providers/opencode-config.d.ts +62 -0
- package/dist/providers/opencode.d.ts +40 -0
- package/dist/providers/parsers/acp.d.ts +47 -0
- package/dist/providers/parsers/codex-app-server.d.ts +60 -0
- package/dist/providers/parsers/stream-json.d.ts +57 -0
- package/dist/providers/passive-readers/agy.d.ts +155 -0
- package/dist/providers/passive-readers/copilot.d.ts +173 -0
- package/dist/providers/passive-readers/dsh.d.ts +34 -0
- package/dist/providers/passive-readers/kimi.d.ts +44 -0
- package/dist/providers/passive-readers/opencode.d.ts +89 -0
- package/dist/providers/passive-readers/qwen.d.ts +151 -0
- package/dist/providers/passive-readers/shared.d.ts +138 -0
- package/dist/providers/passive-session-reader.d.ts +188 -0
- package/dist/providers/path-utils.d.ts +1 -0
- package/dist/providers/pi.d.ts +32 -0
- package/dist/providers/pricing.d.ts +107 -0
- package/dist/providers/qwen.d.ts +22 -0
- package/dist/providers/ratelimit-readings.d.ts +32 -0
- package/dist/providers/registry.d.ts +31 -0
- package/dist/providers/resume.d.ts +43 -0
- package/dist/providers/seed-instruction.d.ts +3 -0
- package/dist/providers/self-session-env.d.ts +21 -0
- package/dist/providers/session-limit.d.ts +9 -0
- package/dist/providers/strip-ansi.d.ts +5 -0
- package/dist/providers/transport-errors.d.ts +94 -0
- package/dist/providers/transport-lifecycle.d.ts +63 -0
- package/dist/providers/transport-wrappers.d.ts +110 -0
- package/dist/providers/transports/acp-profiles/config-option-step.d.ts +24 -0
- package/dist/providers/transports/acp-profiles/copilot.d.ts +12 -0
- package/dist/providers/transports/acp-profiles/gemini.d.ts +22 -0
- package/dist/providers/transports/acp-profiles/hermes.d.ts +27 -0
- package/dist/providers/transports/acp-profiles/index.d.ts +19 -0
- package/dist/providers/transports/acp-profiles/kimi.d.ts +24 -0
- package/dist/providers/transports/acp-profiles/opencode.d.ts +26 -0
- package/dist/providers/transports/acp-profiles/types.d.ts +258 -0
- package/dist/providers/transports/acp-rpc.d.ts +18 -0
- package/dist/providers/transports/acp.d.ts +215 -0
- package/dist/providers/transports/codex-app-server.d.ts +190 -0
- package/dist/providers/transports/hold-open.d.ts +120 -0
- package/dist/providers/transports/manager.d.ts +21 -0
- package/dist/providers/transports/stream-json.d.ts +162 -0
- package/dist/providers/transports/types.d.ts +56 -0
- package/dist/providers/types.d.ts +154 -0
- package/dist/providers/yolo-contract.d.ts +131 -0
- package/dist/script/adapter.d.ts +101 -0
- package/dist/script/batch-script.d.ts +7 -0
- package/dist/script/index.d.ts +3 -0
- package/dist/script/lmscript.d.ts +550 -0
- package/dist/shared/policy.d.ts +74 -0
- package/dist/shared-lib/db.d.ts +25 -0
- package/dist/shared-lib/passive-session-reader.d.ts +2 -0
- package/dist/shared-lib/provider-parse.d.ts +6 -0
- package/dist/templates/basedir.d.ts +52 -0
- package/dist/uri/lmctl_uri.d.ts +38 -0
- package/durable-memory/model_selection.md +108 -25
- package/examples/README.md +103 -0
- package/examples/anonymous-panel.lms +3 -0
- package/examples/batch-prompts.txt +9 -0
- package/examples/batchscript.lms +67 -0
- package/examples/n8n/agent-lib.lms +56 -0
- package/examples/n8n/git-lib.lms +93 -0
- package/examples/n8n/mock-support.db +0 -0
- package/examples/n8n/multi-agent-review.lms +107 -0
- package/examples/n8n/news-digest.lms +159 -0
- package/examples/n8n/rag-search.lms +163 -0
- package/examples/n8n/support-agent.lms +88 -0
- package/examples/n8n/ticket-triage.lms +156 -0
- package/package.json +13 -17
- package/dist/cli/side_effect_classifier.json +0 -19
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { SessionProvider, SessionSummary, SessionDetail } from "./types.js";
|
|
2
|
+
type OpenCodeCompatibleProviderName = "opencode" | "lmplayer";
|
|
3
|
+
interface OpenCodeProviderOptions {
|
|
4
|
+
dbPath?: string;
|
|
5
|
+
providerName?: OpenCodeCompatibleProviderName;
|
|
6
|
+
startCommand?: string;
|
|
7
|
+
/** Read-only connection `PRAGMA busy_timeout` in ms. Default 5000; lower
|
|
8
|
+
* for tests that need to observe the retry-then-give-up path quickly. */
|
|
9
|
+
busyTimeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class OpenCodeProvider implements SessionProvider {
|
|
12
|
+
readonly name: OpenCodeCompatibleProviderName;
|
|
13
|
+
private readonly startCommand;
|
|
14
|
+
private readonly dbPaths;
|
|
15
|
+
private readonly busyTimeoutMs;
|
|
16
|
+
constructor(opts?: OpenCodeProviderOptions);
|
|
17
|
+
private existingDbPaths;
|
|
18
|
+
private openDb;
|
|
19
|
+
discoverSessions(): Promise<SessionSummary[]>;
|
|
20
|
+
loadSession(sessionId: string): Promise<SessionDetail | null>;
|
|
21
|
+
private buildSessionDetail;
|
|
22
|
+
private extractText;
|
|
23
|
+
resolveSessionPath(sessionId: string): Promise<string | null>;
|
|
24
|
+
deleteSession(sessionId: string): Promise<boolean>;
|
|
25
|
+
private findSessionRow;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Bundle-identity probe (batch bundle mode): does the opencode session store
|
|
29
|
+
* hold a session with EXACTLY this id, and which directory does it belong
|
|
30
|
+
* to? opencode's `session/load` response does not echo the sessionId
|
|
31
|
+
* (verified on the wire, 2026-09-25), so the bundle driver verifies the
|
|
32
|
+
* resume target here instead. Read-only, with the same busy_timeout
|
|
33
|
+
* rationale as OpenCodeProvider.openDb.
|
|
34
|
+
*/
|
|
35
|
+
export declare function opencodeSessionStoreEntry(sessionId: string, opts?: {
|
|
36
|
+
dbPath?: string;
|
|
37
|
+
}): {
|
|
38
|
+
directory: string;
|
|
39
|
+
} | null;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface AcpResult {
|
|
2
|
+
result: string;
|
|
3
|
+
sessionId: string;
|
|
4
|
+
durationMs: number;
|
|
5
|
+
stopReason: string;
|
|
6
|
+
exitCode: number | null;
|
|
7
|
+
/** Human-readable strings when this turn's provider silently dropped a
|
|
8
|
+
* declared model=/effort= (task #232) -- e.g. a `session/set_config_option`
|
|
9
|
+
* rejection the turn proceeded past anyway. Omitted when nothing was
|
|
10
|
+
* dropped. */
|
|
11
|
+
warnings?: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface AcpOutputProcessorResult {
|
|
14
|
+
result: string;
|
|
15
|
+
sessionId: string;
|
|
16
|
+
stopReason: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AcpOutputProcessor {
|
|
19
|
+
setSessionId(sessionId: string): void;
|
|
20
|
+
beginTurn(): void;
|
|
21
|
+
completeTurn(promptResponse: Record<string, unknown>): AcpOutputProcessorResult;
|
|
22
|
+
/**
|
|
23
|
+
* Abandon the in-flight turn WITHOUT recording a result (bundle
|
|
24
|
+
* cancellation): stops collecting, discards the partial text, and leaves
|
|
25
|
+
* `gotResult` untouched so a late-arriving prompt response cannot be
|
|
26
|
+
* mistaken for a completed turn. The next `beginTurn()` starts clean.
|
|
27
|
+
*/
|
|
28
|
+
cancelTurn(): void;
|
|
29
|
+
processMessage(message: Record<string, unknown>): boolean;
|
|
30
|
+
finalize(): AcpOutputProcessorResult | null;
|
|
31
|
+
}
|
|
32
|
+
export declare function isolateGeminiLatestAgentMessage(text: string): string;
|
|
33
|
+
export declare function acpSessionIdFromResponse(response: Record<string, unknown>, fallback?: string): string;
|
|
34
|
+
export declare function acpStopReasonFromResponse(response: Record<string, unknown>): string;
|
|
35
|
+
export declare function createAcpOutputProcessor(opts?: {
|
|
36
|
+
tool?: string;
|
|
37
|
+
onDelta?: (text: string) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Result-text isolation for providers that replay prior turns (gemini's
|
|
40
|
+
* latest-agent-message isolation). Supplied by the provider's ACP
|
|
41
|
+
* profile (transports/acp-profiles/); when absent, falls back to the
|
|
42
|
+
* historical `tool === "gemini"` keying so direct callers that pass
|
|
43
|
+
* only a tool name keep their behavior.
|
|
44
|
+
*/
|
|
45
|
+
isolateResult?: (text: string) => string;
|
|
46
|
+
}): AcpOutputProcessor;
|
|
47
|
+
export declare function supportsAcp(tool: string): boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type CodexPermissionMode = "plan" | "yolo";
|
|
2
|
+
export declare function codexSandboxForPermissionMode(mode: CodexPermissionMode): string;
|
|
3
|
+
export declare function buildCodexThreadStartParams(opts: {
|
|
4
|
+
cwd: string;
|
|
5
|
+
permissionMode?: CodexPermissionMode;
|
|
6
|
+
model?: string;
|
|
7
|
+
}): Record<string, unknown>;
|
|
8
|
+
export declare function buildCodexThreadResumeParams(opts: {
|
|
9
|
+
threadId: string;
|
|
10
|
+
permissionMode?: CodexPermissionMode;
|
|
11
|
+
model?: string;
|
|
12
|
+
}): Record<string, unknown>;
|
|
13
|
+
export interface CodexInitializePayload extends Record<string, unknown> {
|
|
14
|
+
clientInfo: {
|
|
15
|
+
name: string;
|
|
16
|
+
title: string;
|
|
17
|
+
version: string;
|
|
18
|
+
};
|
|
19
|
+
capabilities: {
|
|
20
|
+
experimentalApi: boolean;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare function buildInitializePayload(version?: string): CodexInitializePayload;
|
|
24
|
+
export type AgentMessagePhase = "commentary" | "final_answer";
|
|
25
|
+
export interface AgentMessageItemState {
|
|
26
|
+
phase: AgentMessagePhase | undefined;
|
|
27
|
+
buffer: string;
|
|
28
|
+
}
|
|
29
|
+
export interface CodexAgentAccumulatorState {
|
|
30
|
+
agentItems: Map<string, AgentMessageItemState>;
|
|
31
|
+
resultText: string;
|
|
32
|
+
}
|
|
33
|
+
export interface CodexItemMismatchInfo {
|
|
34
|
+
itemId: string;
|
|
35
|
+
threadId?: string;
|
|
36
|
+
turnId?: string;
|
|
37
|
+
expectedFromItemText: string;
|
|
38
|
+
gotFromBuffer: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function createCodexAgentAccumulator(): CodexAgentAccumulatorState;
|
|
41
|
+
export declare function processCodexAgentNotification(notification: Record<string, unknown>, state: CodexAgentAccumulatorState, onDelta?: (text: string) => void, onItemMismatch?: (info: CodexItemMismatchInfo) => void): boolean;
|
|
42
|
+
export declare function flushCodexAgentAccumulator(state: CodexAgentAccumulatorState): void;
|
|
43
|
+
export type CodexErrorDisposition = {
|
|
44
|
+
willRetry: true;
|
|
45
|
+
} | {
|
|
46
|
+
willRetry: false;
|
|
47
|
+
turnError: Error;
|
|
48
|
+
};
|
|
49
|
+
export declare function classifyCodexErrorDisposition(notification: Record<string, unknown>): CodexErrorDisposition;
|
|
50
|
+
export interface CodexTurnState {
|
|
51
|
+
pendingCodexError: Error | null;
|
|
52
|
+
}
|
|
53
|
+
export declare function createCodexTurnState(): CodexTurnState;
|
|
54
|
+
export declare function recordCodexErrorNotification(notification: Record<string, unknown>, state: CodexTurnState): CodexErrorDisposition;
|
|
55
|
+
export declare function resolveCodexTurnCompletion(notification: Record<string, unknown>, state: CodexTurnState): {
|
|
56
|
+
shouldReject: true;
|
|
57
|
+
turnError: Error;
|
|
58
|
+
} | {
|
|
59
|
+
shouldReject: false;
|
|
60
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface StreamJsonResult {
|
|
2
|
+
result: string;
|
|
3
|
+
sessionId: string;
|
|
4
|
+
durationMs: number;
|
|
5
|
+
numTurns: number;
|
|
6
|
+
exitCode: number | null;
|
|
7
|
+
/** Set only by the result-grace-timeout fallback in transports/stream-json.ts
|
|
8
|
+
* (BUG-claude-cli-stalls-after-end-turn.md): the model finished responding
|
|
9
|
+
* but the CLI never emitted its own closing `result` event. Same convention
|
|
10
|
+
* as TurnResult.warnings -- informational, does not change the outcome. */
|
|
11
|
+
warnings?: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface StreamJsonProcessor {
|
|
14
|
+
processLine(line: string): void;
|
|
15
|
+
sawResult(): boolean;
|
|
16
|
+
finalize(): {
|
|
17
|
+
result: string;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
durationMs: number;
|
|
20
|
+
numTurns: number;
|
|
21
|
+
/**
|
|
22
|
+
* True when the aggregated turn produced NO usable text and at least
|
|
23
|
+
* one `result` event reported `is_error: true` — see
|
|
24
|
+
* AggregatedResultEvents.isError below for why this must not be
|
|
25
|
+
* conflated with "the model genuinely returned nothing."
|
|
26
|
+
*/
|
|
27
|
+
isError: boolean;
|
|
28
|
+
errorMessage?: string;
|
|
29
|
+
} | null;
|
|
30
|
+
}
|
|
31
|
+
export interface AggregatedResultEvents {
|
|
32
|
+
resultTexts: string[];
|
|
33
|
+
durationMs: number;
|
|
34
|
+
numTurns: number;
|
|
35
|
+
sessionId: string;
|
|
36
|
+
/**
|
|
37
|
+
* A `result` event can report `is_error: true` with NO `result` field at
|
|
38
|
+
* all (confirmed live, 2026-09-16, against a real `claude` CLI resuming
|
|
39
|
+
* an evicted/unresolvable session id: subtype "error_during_execution",
|
|
40
|
+
* no "result" key, the actual message only in an `errors: string[]`
|
|
41
|
+
* array). Without this flag that shape reads as a genuine empty
|
|
42
|
+
* response — "status: ok, content: (empty)" — indistinguishable from a
|
|
43
|
+
* model that legitimately said nothing, when the two need completely
|
|
44
|
+
* different remedies (a member refresh vs. investigating the prompt).
|
|
45
|
+
* `errorMessage` is the joined `errors` array, or a subtype-based
|
|
46
|
+
* fallback when `errors` is absent.
|
|
47
|
+
*/
|
|
48
|
+
isError: boolean;
|
|
49
|
+
errorMessage?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare function joinResultTurns(texts: string[]): string;
|
|
52
|
+
export declare function createStreamJsonProcessor(opts?: {
|
|
53
|
+
onEvent?: (event: Record<string, unknown>) => void;
|
|
54
|
+
onText?: (text: string) => void;
|
|
55
|
+
}): StreamJsonProcessor;
|
|
56
|
+
export declare function aggregateResultEvents(events: Array<Record<string, unknown>>): AggregatedResultEvents;
|
|
57
|
+
export declare function supportsStreamJson(tool: string): boolean;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Passive (read-only, bounded, certified) reader for Antigravity CLI (`agy`)
|
|
3
|
+
* sessions.
|
|
4
|
+
*
|
|
5
|
+
* `agy` lives under `~/.gemini/antigravity-cli` but is NOT Gemini CLI — the
|
|
6
|
+
* shared parent directory is a naming coincidence, and nothing in this reader is
|
|
7
|
+
* shared with a Gemini/ACP path.
|
|
8
|
+
*
|
|
9
|
+
* ## The two candidate sources, and why only one is used
|
|
10
|
+
*
|
|
11
|
+
* 1. `conversations/<session>.db` — SQLite. Tables: `trajectory_meta`, `steps`,
|
|
12
|
+
* `gen_metadata`, `executor_metadata`, `parent_references`,
|
|
13
|
+
* `trajectory_metadata_blob`, `battle_mode_infos`. **Every payload column is
|
|
14
|
+
* an opaque protobuf blob** (`google3/third_party/jetski/cortex_pb`), not
|
|
15
|
+
* JSON. One `gen_metadata` row == one model generation.
|
|
16
|
+
* 2. `brain/<session>/.system_generated/logs/transcript_full.jsonl` (and the
|
|
17
|
+
* older compact `transcript.jsonl`) — readable JSONL.
|
|
18
|
+
*
|
|
19
|
+
* A census of every local transcript (141 files, 13 801 records) shows the JSONL
|
|
20
|
+
* carries ONLY: `step_index`, `source`, `type`, `status`, `created_at`,
|
|
21
|
+
* `content`, `tool_calls`, `thinking`, `exit_code`, `error`, `error_code`.
|
|
22
|
+
* There is **no token field, no model field and no per-response id anywhere in
|
|
23
|
+
* it**, so it cannot supply a `response_id` and cannot be the response source.
|
|
24
|
+
* It is therefore not read here at all; see the owner report for why joining it
|
|
25
|
+
* back to a generation is a separate, larger piece of work.
|
|
26
|
+
*
|
|
27
|
+
* ## What IS certified from the database
|
|
28
|
+
*
|
|
29
|
+
* Read with a schema-less protobuf wire walker (field numbers only — no
|
|
30
|
+
* generated stubs, nothing evaluated), cross-checked across 4 sessions and 2
|
|
31
|
+
* model families:
|
|
32
|
+
*
|
|
33
|
+
* - `gen_metadata.data` field 1 is the generation's chat-model metadata message.
|
|
34
|
+
* - Inside it, field 20 is a repeated `{1:key, 2:value}` string map. It contains
|
|
35
|
+
* `request_id` (`<trajectory_id>-<n>`), which is unique per generation and is
|
|
36
|
+
* used as `response_id`. It also contains `trajectory_id`, `last_step_index`,
|
|
37
|
+
* `model_enum`, `last_execution_id` and `used_claude`/`used_non_gemini_model`
|
|
38
|
+
* flags. Cross-checked: the top-level field-4 UUID is NOT per-generation (it
|
|
39
|
+
* repeats across rows) and is deliberately not used as an id.
|
|
40
|
+
* - Field 19 is the response model name string (`gemini-3.8-flash`,
|
|
41
|
+
* `gemini-pro-default` locally).
|
|
42
|
+
* - `last_step_index` indexes the `steps` table, whose `step_payload` field 5
|
|
43
|
+
* sub-field 1 is a `google.protobuf.Timestamp`. That join gives a real
|
|
44
|
+
* per-generation timestamp and is verified monotonic against generation order.
|
|
45
|
+
*
|
|
46
|
+
* ## What is NOT certified: tokens
|
|
47
|
+
*
|
|
48
|
+
* ## Tokens — RESOLVED via the installed client's own embedded schema
|
|
49
|
+
*
|
|
50
|
+
* Field 4 of the chat-model metadata was long treated as an unnamed counter
|
|
51
|
+
* block because no `.proto` was available and the standard `UsageMetadata`
|
|
52
|
+
* interpretation was directly ruled out (its assumed field 3 was smaller than
|
|
53
|
+
* its assumed field 2 — impossible for total-vs-candidates under that guess).
|
|
54
|
+
* That block is NOT a guess anymore: the installed `agy` binary is a Go build
|
|
55
|
+
* of `google.golang.org/protobuf`, which embeds each compiled `.proto` file's
|
|
56
|
+
* real `FileDescriptorProto` bytes for reflection. Locating the descriptor's
|
|
57
|
+
* self-declared name field (`third_party/jetski/cortex_pb/cortex.proto`,
|
|
58
|
+
* tag `0x0a` immediately preceding it — distinguishing it from the many
|
|
59
|
+
* `0x1a` dependency-reference copies of the same string elsewhere in the
|
|
60
|
+
* binary) and parsing the schema-less-walked byte range with the real
|
|
61
|
+
* `google.protobuf` library recovers the ACTUAL message: field 4 is
|
|
62
|
+
* `exa.codeium_common_pb.ModelUsageStats`, not a generic `UsageMetadata`.
|
|
63
|
+
* Its real fields (confirmed against 6,662 real local rows, independently
|
|
64
|
+
* re-derived and cross-checked by a second reviewer against the raw binary):
|
|
65
|
+
* 2 input_tokens, 3 output_tokens, 4 cache_write_tokens (never observed
|
|
66
|
+
* non-null locally — genuinely rare/unused, not unread), 5 cache_read_tokens
|
|
67
|
+
* (absent on some rows — no cache yet), 9 thinking_output_tokens,
|
|
68
|
+
* 10 response_output_tokens, 1 model (enum; the string alias is already
|
|
69
|
+
* separately captured from field 19 above), 7/11/12 assorted opaque id
|
|
70
|
+
* strings (message_id/response_id/provider_assigned_message_id — these,
|
|
71
|
+
* not a "bot id"/"session id", are what the pre-schema walk was seeing).
|
|
72
|
+
* `response_output_tokens + thinking_output_tokens === output_tokens` EXACTLY
|
|
73
|
+
* on all 6,662/6,662 rows carrying both — proof (not inference) that
|
|
74
|
+
* `output_tokens` is the total and `thinking_output_tokens` is its reasoning
|
|
75
|
+
* subset. `cache_write_tokens`'s relationship (if any) to `input_uncached` is
|
|
76
|
+
* deliberately left unasserted — see `agyUsage`'s own doc comment below; a
|
|
77
|
+
* shared field name across providers is not evidence of shared semantics.
|
|
78
|
+
* `input_tokens` is used directly as `input_uncached`, never subtracted from:
|
|
79
|
+
* real rows show `input_tokens < cache_read_tokens` (e.g. 3280 vs 12145),
|
|
80
|
+
* which is only possible if the two are independent additive counts, not an
|
|
81
|
+
* inclusive total/subset pair — ruling out subtraction the same way the
|
|
82
|
+
* original block-level guess was ruled out (an impossible relation under the
|
|
83
|
+
* wrong model). Missing/invalid buckets stay NULL per-field (never a guessed
|
|
84
|
+
* 0) — `cache_write_tokens` in particular is null on every locally observed
|
|
85
|
+
* row precisely because it has genuinely never been populated here, not
|
|
86
|
+
* because it is unread.
|
|
87
|
+
*
|
|
88
|
+
* `files_read` / `files_written` / `external_io` are NULL (unknown), not `[]`:
|
|
89
|
+
* tool calls live in `steps.step_payload`, a different opaque message, and in
|
|
90
|
+
* the un-joinable transcript. NULL correctly forces `read_bytes`/`write_bytes`
|
|
91
|
+
* to NULL rather than presenting "no tools observed" as "no I/O occurred".
|
|
92
|
+
*/
|
|
93
|
+
import type { ReadLimits, Snapshot, Source, SourceState } from "../passive-session-reader.js";
|
|
94
|
+
import { type TokenValues } from "./shared.js";
|
|
95
|
+
export declare const AGY_PROVIDER = "agy";
|
|
96
|
+
export declare const AGY_EXTRACTION_REVISION_TAG = "agy-tokens-v1";
|
|
97
|
+
/**
|
|
98
|
+
* `steps.step_payload` → ISO timestamp, via field 5 (step metadata) sub-field 1
|
|
99
|
+
* (`google.protobuf.Timestamp` {1:seconds, 2:nanos}). Returns null when the
|
|
100
|
+
* shape is absent — never a fabricated or file-mtime-derived time.
|
|
101
|
+
*/
|
|
102
|
+
export declare function agyStepTimestamp(stepPayload: Buffer): string | null;
|
|
103
|
+
/** One generation extracted from a `gen_metadata` row. */
|
|
104
|
+
export interface AgyGeneration {
|
|
105
|
+
/** Native `request_id` — `<trajectory_id>-<n>`, unique per generation. */
|
|
106
|
+
requestId: string;
|
|
107
|
+
model: string | null;
|
|
108
|
+
/** `steps.idx` this generation ended on; the timestamp join key. */
|
|
109
|
+
lastStepIndex: number | null;
|
|
110
|
+
tokens: TokenValues;
|
|
111
|
+
thinkingOutputTokens: number | null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Extract the certified facts from one `gen_metadata.data` blob. Returns null
|
|
115
|
+
* when the row carries no `request_id` — without a native id the generation
|
|
116
|
+
* cannot be addressed, and inventing one is forbidden.
|
|
117
|
+
*/
|
|
118
|
+
export declare function parseAgyGeneration(data: Buffer): AgyGeneration | null;
|
|
119
|
+
export interface AgyPassiveReaderOptions {
|
|
120
|
+
/** Defaults to `$HOME/.gemini/antigravity-cli/conversations`. */
|
|
121
|
+
agyConversationsDir?: string;
|
|
122
|
+
}
|
|
123
|
+
export declare class AgyPassiveReader {
|
|
124
|
+
private readonly conversationsDir;
|
|
125
|
+
private readonly sqliteBusyTimeoutMs;
|
|
126
|
+
constructor(options?: AgyPassiveReaderOptions & {
|
|
127
|
+
sqliteBusyTimeoutMs?: number;
|
|
128
|
+
});
|
|
129
|
+
/**
|
|
130
|
+
* Enumerate up to `cap` `<conversationsDir>/<session>.db` files ordered by real
|
|
131
|
+
* path. A flat listing, so there is no traversal budget to exhaust; `truncated`
|
|
132
|
+
* is always false and is returned only to match the other readers' shape.
|
|
133
|
+
*
|
|
134
|
+
* `.db-wal` / `.db-shm` companions are excluded by the exact `.db` suffix test:
|
|
135
|
+
* they are not sources, and treating one as a session would mint a bogus id.
|
|
136
|
+
*/
|
|
137
|
+
discover(limits: ReadLimits, cap: number, afterPath?: string | null): Promise<{
|
|
138
|
+
sources: Source[];
|
|
139
|
+
truncated: boolean;
|
|
140
|
+
}>;
|
|
141
|
+
/**
|
|
142
|
+
* Open the conversation database read-only, after proving the path is a real,
|
|
143
|
+
* non-symlink file inside the configured conversations directory AND that its
|
|
144
|
+
* basename is the claimed session id.
|
|
145
|
+
*
|
|
146
|
+
* Returns null (→ `unavailable`) rather than throwing when the file is not a
|
|
147
|
+
* usable SQLite database. A live session's `-wal`/`-shm` companions are read
|
|
148
|
+
* through by SQLite itself; a read-only open that cannot reach them fails
|
|
149
|
+
* closed here instead of returning a half-visible snapshot.
|
|
150
|
+
*/
|
|
151
|
+
private open;
|
|
152
|
+
inspect(source: Source, limits: ReadLimits): Promise<SourceState>;
|
|
153
|
+
read(source: Source, revision: string, limits: ReadLimits): Promise<Snapshot>;
|
|
154
|
+
}
|
|
155
|
+
export declare function createAgyPassiveReader(options?: AgyPassiveReaderOptions): AgyPassiveReader;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Passive (read-only, bounded, certified) reader for GitHub Copilot CLI sessions.
|
|
3
|
+
*
|
|
4
|
+
* ## What the native store actually is (real records, not assumed)
|
|
5
|
+
*
|
|
6
|
+
* Copilot writes one append-only event log per session:
|
|
7
|
+
* `$HOME/.copilot/session-state/<uuid>/events.jsonl` (+ a `workspace.yaml`).
|
|
8
|
+
* Each line is a JSON object `{ type, id, timestamp, data }`. The event TYPES seen
|
|
9
|
+
* locally: `session.start`, `session.model_change`, `session.info`,
|
|
10
|
+
* `system.message`, `user.message`, `assistant.turn_start`, `assistant.message`,
|
|
11
|
+
* `assistant.turn_end`, `tool.execution_start`, `tool.execution_complete`,
|
|
12
|
+
* `session.shutdown`.
|
|
13
|
+
*
|
|
14
|
+
* ## Token semantics — the copilot warning, verified on disk
|
|
15
|
+
*
|
|
16
|
+
* lmbi's directive: "Copilot has cumulative per-model shutdown totals and some
|
|
17
|
+
* per-message usage; NEVER distribute a session total over responses without
|
|
18
|
+
* evidence." Measured against real sessions:
|
|
19
|
+
*
|
|
20
|
+
* - `assistant.message.outputTokens` IS a genuine PER-RESPONSE count.
|
|
21
|
+
* - There is NO per-message input / cache / reasoning field anywhere on the wire.
|
|
22
|
+
* Those counters exist only in `session.shutdown.modelMetrics` snapshots.
|
|
23
|
+
*
|
|
24
|
+
* CORRECTED (real evidence, not the original assumption): `session.shutdown`
|
|
25
|
+
* is NOT a proven session-wide cumulative. A session can carry MANY shutdown
|
|
26
|
+
* events (measured: up to 24 in one real session), and a shutdown's
|
|
27
|
+
* `requests.count`/`outputTokens` can be far smaller than the session's real
|
|
28
|
+
* total turn count/output sum (measured: a 201-turn session's last shutdown
|
|
29
|
+
* reported `requests.count=7`, `outputTokens=1984` against a real per-message
|
|
30
|
+
* sum of 82,375 — a ~97.6% undercount). So each shutdown snapshot's semantics
|
|
31
|
+
* are `"reported_scope_unknown"`, never asserted cumulative.
|
|
32
|
+
*
|
|
33
|
+
* Therefore each response record here carries `tokens.output` (real, per-message)
|
|
34
|
+
* and leaves `input_uncached` / `input_cached` / `input_cache_write` NULL — the
|
|
35
|
+
* shutdown snapshot's input is NEVER divided across responses. Every shutdown
|
|
36
|
+
* snapshot is surfaced SEPARATELY and RAW as `CopilotSessionUsage` (see
|
|
37
|
+
* `readCopilot`/`readWithUsage`) — never spread over the per-response rows,
|
|
38
|
+
* never emitted as a fabricated pseudo-response, and never renamed/normalized
|
|
39
|
+
* into this reader's own canonical token vocabulary (that's lmbi's own
|
|
40
|
+
* downstream decision to make, not this reader's).
|
|
41
|
+
*
|
|
42
|
+
* ## Identity, revision, attribution
|
|
43
|
+
*
|
|
44
|
+
* - `response_id` = `assistant.message.data.messageId` (a real uuid); never
|
|
45
|
+
* invented. Repeated events for one messageId sum their `outputTokens`.
|
|
46
|
+
* - The revision is the sha256 of the exact `events.jsonl` bytes (extraction-
|
|
47
|
+
* semantics-tagged, see EXTRACTION_SEMANTICS) with
|
|
48
|
+
* a dev/ino/size/mtime recheck: a live append caught mid-write is `partial`,
|
|
49
|
+
* never a clean revision, and a file not ending on a record boundary is refused.
|
|
50
|
+
* - Prompt admission: `user.message.data.content` bytes attach to the FIRST
|
|
51
|
+
* assistant response of the same `interactionId`; later responses in that
|
|
52
|
+
* interaction are a real 0 (the prompt was already admitted). A response whose
|
|
53
|
+
* interaction has no visible user admission (truncated history / system-driven
|
|
54
|
+
* turn) gets an unknown coverage marker — "no input" cannot be certified.
|
|
55
|
+
*
|
|
56
|
+
* ## File / external-I/O (bx2), conservative by contract
|
|
57
|
+
*
|
|
58
|
+
* `create` ({path,file_text}) and `apply_patch` (<patch string>) are KNOWN writes
|
|
59
|
+
* with measurable added bytes. `view` ({path}) is a KNOWN read whose bytes are
|
|
60
|
+
* NULL — the result content is line-decorated with no clean chunk to count, so the
|
|
61
|
+
* honest size is unavailable (not guessed). `report_intent` is internal control
|
|
62
|
+
* (neither direction). Everything else opaque (`bash`/`read_bash`/`write_bash`/
|
|
63
|
+
* `stop_bash`/`list_bash`/`rg`/`glob`/`sql`/`fetch_*`/…) is unknown in BOTH
|
|
64
|
+
* directions, forcing that direction's aggregate NULL.
|
|
65
|
+
*/
|
|
66
|
+
import type { ReadLimits, Snapshot, Source, SourceState } from "../passive-session-reader.js";
|
|
67
|
+
export declare const COPILOT_PROVIDER = "copilot";
|
|
68
|
+
/**
|
|
69
|
+
* One event line of a copilot `events.jsonl`. Only the fields this reader reads.
|
|
70
|
+
*/
|
|
71
|
+
interface CopilotEvent {
|
|
72
|
+
type?: unknown;
|
|
73
|
+
id?: unknown;
|
|
74
|
+
timestamp?: unknown;
|
|
75
|
+
data?: unknown;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* One native model's RAW `session.shutdown` counters. Field NAMES are copied
|
|
79
|
+
* directly from the native wire (`usage.inputTokens` -> `input_tokens`,
|
|
80
|
+
* `tokenDetails.input.tokenCount` -> `input_other_tokens`, etc.) — this reader
|
|
81
|
+
* does NOT compute, clamp, infer, or rename a "canonical uncached" figure here.
|
|
82
|
+
* Per lmbi's explicit instruction: raw naming preserves the native facts while
|
|
83
|
+
* this snapshot's own window/scope semantics remain unproven; normalizing
|
|
84
|
+
* (e.g. `input_uncached = input_tokens - cache_read_tokens`) is a downstream
|
|
85
|
+
* decision for the consumer, not this reader's to bake in.
|
|
86
|
+
*/
|
|
87
|
+
export interface CopilotModelUsage {
|
|
88
|
+
model: string;
|
|
89
|
+
requests_count: number | null;
|
|
90
|
+
/** `usage.inputTokens`, copied as-is. */
|
|
91
|
+
input_tokens: number | null;
|
|
92
|
+
/** `tokenDetails.input.tokenCount`, copied as-is — a real native "fresh"
|
|
93
|
+
* figure, narrower than `input_tokens`. NOT a canonical uncached total. */
|
|
94
|
+
input_other_tokens: number | null;
|
|
95
|
+
cache_read_tokens: number | null;
|
|
96
|
+
cache_write_tokens: number | null;
|
|
97
|
+
output_tokens: number | null;
|
|
98
|
+
reasoning_tokens: number | null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* One native `session.shutdown` EVENT, with every model in its `modelMetrics`
|
|
102
|
+
* grouped underneath (mirrors the native shape: one event, many models) —
|
|
103
|
+
* surfaced beside, never inside, the per-response rows.
|
|
104
|
+
*
|
|
105
|
+
* CORRECTED (real evidence, not assumption): a session can carry MULTIPLE
|
|
106
|
+
* `session.shutdown` events (measured: up to 24 in one real session on this box),
|
|
107
|
+
* and a shutdown's `requests.count`/`usage.outputTokens` can be far smaller than
|
|
108
|
+
* the session's real total turn count/output sum (measured: a 201-turn session's
|
|
109
|
+
* last shutdown reported `requests.count=7`, `outputTokens=1984` against a real
|
|
110
|
+
* per-message sum of 82,375 — a ~97.6% undercount). So this is NOT a proven
|
|
111
|
+
* session-wide cumulative; `semantics: "reported_scope_unknown"` reflects that
|
|
112
|
+
* honestly. Every shutdown event is retained (never "last wins", exact
|
|
113
|
+
* duplicate `native_id` replays coalesce to one), each with its own native
|
|
114
|
+
* event id/timestamp, so later analysis isn't precluded by discarding earlier
|
|
115
|
+
* snapshots.
|
|
116
|
+
*/
|
|
117
|
+
export interface CopilotSessionUsage {
|
|
118
|
+
/** The `session.shutdown` event's own top-level `id` (a real uuid). An event
|
|
119
|
+
* with no real id is never given a fabricated one — it is excluded from this
|
|
120
|
+
* array entirely (an explicit capture gap, not silently-fine metadata). */
|
|
121
|
+
native_id: string;
|
|
122
|
+
/** The `session.shutdown` event's own top-level `timestamp`, canonicalized. */
|
|
123
|
+
recorded_at: string | null;
|
|
124
|
+
kind: "copilot_session_shutdown";
|
|
125
|
+
semantics: "reported_scope_unknown";
|
|
126
|
+
models: CopilotModelUsage[];
|
|
127
|
+
}
|
|
128
|
+
export interface CopilotReadResult {
|
|
129
|
+
snapshot: Snapshot;
|
|
130
|
+
/** null when the session has no shutdown event with a real id yet (live/torn,
|
|
131
|
+
* or every shutdown event on this session lacked an id) — normal. */
|
|
132
|
+
sessionUsage: CopilotSessionUsage[] | null;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Extract the per-response snapshot AND the retained session-usage snapshots
|
|
136
|
+
* (scope-unknown, never asserted cumulative) from a parsed copilot event log.
|
|
137
|
+
* Pure and deterministic. A malformed event never throws; the
|
|
138
|
+
* whole snapshot is only refused (`partial`) when a response row count exceeds the
|
|
139
|
+
* budget — otherwise unrecognized shapes degrade to conservative NULL markers.
|
|
140
|
+
*/
|
|
141
|
+
export declare function readCopilot(events: CopilotEvent[], source: Source, revision: string, limits: ReadLimits): CopilotReadResult;
|
|
142
|
+
export interface CopilotPassiveReaderOptions {
|
|
143
|
+
/** Defaults to `$HOME/.copilot/session-state`. */
|
|
144
|
+
copilotSessionStateDir?: string;
|
|
145
|
+
}
|
|
146
|
+
export declare class CopilotPassiveReader {
|
|
147
|
+
private readonly sessionStateDir;
|
|
148
|
+
constructor(options?: CopilotPassiveReaderOptions);
|
|
149
|
+
/**
|
|
150
|
+
* Enumerate up to `cap` sources ordered by real path. `afterKey` (a
|
|
151
|
+
* `source_id\0sessionid` sourceKey) continues a previous page. Discovery is a
|
|
152
|
+
* single-level scan of the session-state directory (no deep recursion), so
|
|
153
|
+
* there is no traversal budget to exhaust — `truncated` is always false.
|
|
154
|
+
*/
|
|
155
|
+
discover(limits: ReadLimits, cap: number, afterKey?: string | null): Promise<{
|
|
156
|
+
sources: Source[];
|
|
157
|
+
truncated: boolean;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* A source is ours only when its real path is `<dir>/events.jsonl` contained by
|
|
161
|
+
* the session-state directory AND `<dir>` basename is the claimed session id.
|
|
162
|
+
*/
|
|
163
|
+
private matches;
|
|
164
|
+
inspect(source: Source, limits: ReadLimits): Promise<SourceState>;
|
|
165
|
+
/** Contract-shaped read: per-response Snapshot only. Use `readWithUsage` to also
|
|
166
|
+
* obtain the retained session-usage snapshots that must not be distributed
|
|
167
|
+
* over responses (see the module header — their scope is unproven, never
|
|
168
|
+
* asserted cumulative). */
|
|
169
|
+
read(source: Source, revision: string, limits: ReadLimits): Promise<Snapshot>;
|
|
170
|
+
readWithUsage(source: Source, revision: string, limits: ReadLimits): Promise<CopilotReadResult>;
|
|
171
|
+
}
|
|
172
|
+
export declare function createCopilotPassiveReader(options?: CopilotPassiveReaderOptions): CopilotPassiveReader;
|
|
173
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ReadLimits, Snapshot, Source, SourceState } from "../passive-session-reader.js";
|
|
2
|
+
export declare const DSH_PROVIDER = "dsh";
|
|
3
|
+
interface DshRecord {
|
|
4
|
+
type?: unknown;
|
|
5
|
+
seq?: unknown;
|
|
6
|
+
time?: unknown;
|
|
7
|
+
data?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface DshPassiveReaderOptions {
|
|
10
|
+
/** Defaults to `$DSH_HOME/sessions`, then `~/.dsh/sessions`. */
|
|
11
|
+
dshHome?: string;
|
|
12
|
+
maxDiscoveryTraversalVisits?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function readDsh(records: DshRecord[], source: Source, revision: string, limits: ReadLimits): Snapshot;
|
|
15
|
+
export declare class DshPassiveReader {
|
|
16
|
+
private readonly sessionsDir;
|
|
17
|
+
private readonly maxDiscoveryTraversalVisits;
|
|
18
|
+
constructor(options?: DshPassiveReaderOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Enumerate up to `cap` sources ordered by real path. `afterPath` continues a
|
|
21
|
+
* previous page. The caller owns cursor encoding and the cross-provider merge.
|
|
22
|
+
*/
|
|
23
|
+
discover(limits: ReadLimits, cap: number, afterPath?: string | null): Promise<{
|
|
24
|
+
sources: Source[];
|
|
25
|
+
truncated: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
/** Ours only when a real, non-symlink `session.jsonl.zstd` whose parent dir name
|
|
28
|
+
* is the claimed session id. */
|
|
29
|
+
private matches;
|
|
30
|
+
inspect(source: Source, limits: ReadLimits): Promise<SourceState>;
|
|
31
|
+
read(source: Source, revision: string, limits: ReadLimits): Promise<Snapshot>;
|
|
32
|
+
}
|
|
33
|
+
export declare function createDshPassiveReader(options?: DshPassiveReaderOptions): DshPassiveReader;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ReadLimits, Snapshot, Source, SourceState } from "../passive-session-reader.js";
|
|
2
|
+
export declare const KIMI_PROVIDER = "kimi";
|
|
3
|
+
export interface KimiPassiveReaderOptions {
|
|
4
|
+
/** Defaults to `$KIMI_CODE_HOME`, then `~/.kimi-code`. */
|
|
5
|
+
kimiHome?: string;
|
|
6
|
+
maxDiscoveryTraversalVisits?: number;
|
|
7
|
+
}
|
|
8
|
+
interface WireLine {
|
|
9
|
+
type?: unknown;
|
|
10
|
+
agentId?: unknown;
|
|
11
|
+
event?: unknown;
|
|
12
|
+
time?: unknown;
|
|
13
|
+
model?: unknown;
|
|
14
|
+
modelAlias?: unknown;
|
|
15
|
+
turnStep?: unknown;
|
|
16
|
+
input?: unknown;
|
|
17
|
+
origin?: unknown;
|
|
18
|
+
promptId?: unknown;
|
|
19
|
+
protocol_version?: unknown;
|
|
20
|
+
usage?: unknown;
|
|
21
|
+
}
|
|
22
|
+
export declare function readKimi(lines: WireLine[], source: Source, revision: string, limits: ReadLimits): Snapshot;
|
|
23
|
+
export declare class KimiPassiveReader {
|
|
24
|
+
private readonly home;
|
|
25
|
+
private readonly sessionsDir;
|
|
26
|
+
private readonly indexPath;
|
|
27
|
+
private readonly maxDiscoveryTraversalVisits;
|
|
28
|
+
constructor(options?: KimiPassiveReaderOptions);
|
|
29
|
+
/**
|
|
30
|
+
* Enumerate up to `cap` agent-wire sources ordered by real path. `afterPath`
|
|
31
|
+
* continues a previous page. Unions the directory walk with the append-only
|
|
32
|
+
* index so a missing/damaged index still recovers sessions.
|
|
33
|
+
*/
|
|
34
|
+
discover(limits: ReadLimits, cap: number, afterPath?: string | null): Promise<{
|
|
35
|
+
sources: Source[];
|
|
36
|
+
truncated: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
private unionIndex;
|
|
39
|
+
private matches;
|
|
40
|
+
inspect(source: Source, limits: ReadLimits): Promise<SourceState>;
|
|
41
|
+
read(source: Source, revision: string, limits: ReadLimits): Promise<Snapshot>;
|
|
42
|
+
}
|
|
43
|
+
export declare function createKimiPassiveReader(options?: KimiPassiveReaderOptions): KimiPassiveReader;
|
|
44
|
+
export {};
|