@lmctl-ai/lmctl 0.2.38 → 0.2.40

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.
Files changed (202) hide show
  1. package/README.md +16 -0
  2. package/bin/lmbee +2 -0
  3. package/bin/lmscript +3 -0
  4. package/build-info.json +1 -0
  5. package/dist/cli/index.js +485 -460
  6. package/dist/cli/schema.sql +0 -169
  7. package/dist/cli/script.js +246 -246
  8. package/dist/lmbee.js +960 -0
  9. package/dist/lmscript.js +388 -0
  10. package/dist/public/app.js +379 -0
  11. package/dist/public/index.html +78 -0
  12. package/dist/public/styles.css +160 -0
  13. package/dist/schema.sql +455 -0
  14. package/dist/vendor-webui/index.html +18 -0
  15. package/dist/vendor-webui/local.js +231 -0
  16. package/dist/vendor-webui/styles.css +1852 -0
  17. package/package.json +11 -7
  18. package/dist/cli/batch.d.ts +0 -2
  19. package/dist/cli/busy-evidence.d.ts +0 -27
  20. package/dist/cli/chat-cycle.d.ts +0 -59
  21. package/dist/cli/chat-exec.d.ts +0 -91
  22. package/dist/cli/chat-policy.d.ts +0 -22
  23. package/dist/cli/chat.d.ts +0 -14
  24. package/dist/cli/code-resolver.d.ts +0 -8
  25. package/dist/cli/common.d.ts +0 -57
  26. package/dist/cli/context.d.ts +0 -12
  27. package/dist/cli/cost.d.ts +0 -2
  28. package/dist/cli/export.d.ts +0 -2
  29. package/dist/cli/hello.d.ts +0 -10
  30. package/dist/cli/index.d.ts +0 -3
  31. package/dist/cli/infra.d.ts +0 -78
  32. package/dist/cli/init.d.ts +0 -8
  33. package/dist/cli/intent-input.d.ts +0 -16
  34. package/dist/cli/intent-match.d.ts +0 -30
  35. package/dist/cli/intent-sessions.d.ts +0 -24
  36. package/dist/cli/intent-team.d.ts +0 -25
  37. package/dist/cli/intent.d.ts +0 -22
  38. package/dist/cli/ls.d.ts +0 -2
  39. package/dist/cli/mailbox-cli.d.ts +0 -6
  40. package/dist/cli/managed.d.ts +0 -62
  41. package/dist/cli/mcp-install.d.ts +0 -23
  42. package/dist/cli/mcp.d.ts +0 -2
  43. package/dist/cli/model.d.ts +0 -21
  44. package/dist/cli/paths.d.ts +0 -50
  45. package/dist/cli/plan-wizard.d.ts +0 -42
  46. package/dist/cli/plan.d.ts +0 -20
  47. package/dist/cli/queue-delivery.d.ts +0 -122
  48. package/dist/cli/quickrun.d.ts +0 -14
  49. package/dist/cli/ratelimit.d.ts +0 -2
  50. package/dist/cli/remote-fetch.d.ts +0 -7
  51. package/dist/cli/run-queries.d.ts +0 -82
  52. package/dist/cli/running.d.ts +0 -5
  53. package/dist/cli/save-script.d.ts +0 -41
  54. package/dist/cli/script.d.ts +0 -6
  55. package/dist/cli/seed-flight.d.ts +0 -2
  56. package/dist/cli/self-identity.d.ts +0 -25
  57. package/dist/cli/session-idle.d.ts +0 -118
  58. package/dist/cli/status.d.ts +0 -22
  59. package/dist/cli/tail.d.ts +0 -18
  60. package/dist/cli/target-resolver.d.ts +0 -139
  61. package/dist/cli/team-status.d.ts +0 -91
  62. package/dist/cli/teamfile-compat.d.ts +0 -116
  63. package/dist/cli/teamfile-store.d.ts +0 -18
  64. package/dist/cli/teamfile-template.d.ts +0 -47
  65. package/dist/cli/template-env.d.ts +0 -25
  66. package/dist/cli/terminal-lock.d.ts +0 -25
  67. package/dist/cli/terminal.d.ts +0 -23
  68. package/dist/cli/time-filter.d.ts +0 -10
  69. package/dist/cli/update-notifier.d.ts +0 -11
  70. package/dist/cli/version-util.d.ts +0 -23
  71. package/dist/config/seed_templates.d.ts +0 -1
  72. package/dist/db/backfill-event-log.d.ts +0 -26
  73. package/dist/db/delegation.d.ts +0 -37
  74. package/dist/db/escalation_vocab.d.ts +0 -45
  75. package/dist/db/event-log.d.ts +0 -40
  76. package/dist/db/index.d.ts +0 -1213
  77. package/dist/db/inflight-acquire.d.ts +0 -70
  78. package/dist/db/invocation-event-projections.d.ts +0 -65
  79. package/dist/db/ledger-identity.test.d.ts +0 -1
  80. package/dist/db/live-event-projections.d.ts +0 -92
  81. package/dist/db/migrate.d.ts +0 -51
  82. package/dist/db/open-readonly.d.ts +0 -2
  83. package/dist/db/process-liveness.d.ts +0 -37
  84. package/dist/db/sqlite.d.ts +0 -53
  85. package/dist/db/sqlite.test.d.ts +0 -1
  86. package/dist/db/terminal-lock.d.ts +0 -14
  87. package/dist/db/tracked-invocation-reconcile.d.ts +0 -52
  88. package/dist/db/tracked-invocation.d.ts +0 -116
  89. package/dist/mcp/dispatch.d.ts +0 -45
  90. package/dist/mcp/mediation.d.ts +0 -128
  91. package/dist/mcp/path-warning.d.ts +0 -7
  92. package/dist/mcp/server.d.ts +0 -63
  93. package/dist/mcp/tools.d.ts +0 -24
  94. package/dist/providers/adapter.d.ts +0 -271
  95. package/dist/providers/adapters/agy-adapter.d.ts +0 -18
  96. package/dist/providers/adapters/claude-adapter.d.ts +0 -20
  97. package/dist/providers/adapters/codex-adapter.d.ts +0 -22
  98. package/dist/providers/adapters/copilot-adapter.d.ts +0 -16
  99. package/dist/providers/adapters/dsh-adapter.d.ts +0 -89
  100. package/dist/providers/adapters/gemini-adapter.d.ts +0 -44
  101. package/dist/providers/adapters/hermes-adapter.d.ts +0 -71
  102. package/dist/providers/adapters/index.d.ts +0 -35
  103. package/dist/providers/adapters/kimi-adapter.d.ts +0 -16
  104. package/dist/providers/adapters/lmplayer-adapter.d.ts +0 -14
  105. package/dist/providers/adapters/opencode-adapter.d.ts +0 -11
  106. package/dist/providers/adapters/pi-adapter.d.ts +0 -17
  107. package/dist/providers/adapters/print-turn.d.ts +0 -29
  108. package/dist/providers/adapters/qwen-adapter.d.ts +0 -11
  109. package/dist/providers/agy.d.ts +0 -32
  110. package/dist/providers/base-adapter.d.ts +0 -110
  111. package/dist/providers/base.d.ts +0 -12
  112. package/dist/providers/binary-check.d.ts +0 -102
  113. package/dist/providers/bundle.d.ts +0 -124
  114. package/dist/providers/claude-mock.d.ts +0 -90
  115. package/dist/providers/claude.d.ts +0 -21
  116. package/dist/providers/codex-config.d.ts +0 -15
  117. package/dist/providers/codex.d.ts +0 -25
  118. package/dist/providers/config/init-config.d.ts +0 -59
  119. package/dist/providers/config/init-edit.d.ts +0 -3
  120. package/dist/providers/config/init-file.d.ts +0 -20
  121. package/dist/providers/config/init-write.d.ts +0 -2
  122. package/dist/providers/config/model-selection-lint.d.ts +0 -70
  123. package/dist/providers/config/team-config.d.ts +0 -184
  124. package/dist/providers/config/types.d.ts +0 -146
  125. package/dist/providers/config/user-config.d.ts +0 -88
  126. package/dist/providers/copilot.d.ts +0 -21
  127. package/dist/providers/debug.d.ts +0 -128
  128. package/dist/providers/dsh-sidecar.d.ts +0 -65
  129. package/dist/providers/dsh-zstd.d.ts +0 -27
  130. package/dist/providers/dsh.d.ts +0 -37
  131. package/dist/providers/frontmatter.d.ts +0 -46
  132. package/dist/providers/gemini-session-reader.d.ts +0 -151
  133. package/dist/providers/gemini.d.ts +0 -39
  134. package/dist/providers/hermes.d.ts +0 -90
  135. package/dist/providers/index.d.ts +0 -423
  136. package/dist/providers/kimi.d.ts +0 -37
  137. package/dist/providers/model-catalog.d.ts +0 -145
  138. package/dist/providers/model-suggestions.d.ts +0 -4
  139. package/dist/providers/one-shot-timeout.d.ts +0 -1
  140. package/dist/providers/opencode-config.d.ts +0 -62
  141. package/dist/providers/opencode.d.ts +0 -40
  142. package/dist/providers/parsers/acp.d.ts +0 -71
  143. package/dist/providers/parsers/codex-app-server.d.ts +0 -60
  144. package/dist/providers/parsers/stream-json.d.ts +0 -57
  145. package/dist/providers/passive-readers/agy.d.ts +0 -155
  146. package/dist/providers/passive-readers/copilot.d.ts +0 -173
  147. package/dist/providers/passive-readers/dsh.d.ts +0 -34
  148. package/dist/providers/passive-readers/kimi.d.ts +0 -44
  149. package/dist/providers/passive-readers/opencode.d.ts +0 -89
  150. package/dist/providers/passive-readers/qwen.d.ts +0 -151
  151. package/dist/providers/passive-readers/shared.d.ts +0 -138
  152. package/dist/providers/passive-session-reader.d.ts +0 -188
  153. package/dist/providers/path-utils.d.ts +0 -1
  154. package/dist/providers/pi.d.ts +0 -32
  155. package/dist/providers/pricing.d.ts +0 -107
  156. package/dist/providers/qwen.d.ts +0 -22
  157. package/dist/providers/ratelimit/agy.d.ts +0 -22
  158. package/dist/providers/ratelimit/claude-auth.d.ts +0 -13
  159. package/dist/providers/ratelimit/claude.d.ts +0 -6
  160. package/dist/providers/ratelimit/codex.d.ts +0 -7
  161. package/dist/providers/ratelimit/kimi-auth.d.ts +0 -15
  162. package/dist/providers/ratelimit/kimi.d.ts +0 -6
  163. package/dist/providers/ratelimit/schema.d.ts +0 -28
  164. package/dist/providers/ratelimit-readings.d.ts +0 -19
  165. package/dist/providers/registry.d.ts +0 -31
  166. package/dist/providers/resume.d.ts +0 -43
  167. package/dist/providers/seed-instruction.d.ts +0 -3
  168. package/dist/providers/self-session-env.d.ts +0 -21
  169. package/dist/providers/session-limit.d.ts +0 -9
  170. package/dist/providers/strip-ansi.d.ts +0 -5
  171. package/dist/providers/transport-errors.d.ts +0 -94
  172. package/dist/providers/transport-lifecycle.d.ts +0 -63
  173. package/dist/providers/transport-wrappers.d.ts +0 -110
  174. package/dist/providers/transports/acp-profiles/config-option-step.d.ts +0 -24
  175. package/dist/providers/transports/acp-profiles/copilot.d.ts +0 -12
  176. package/dist/providers/transports/acp-profiles/gemini.d.ts +0 -22
  177. package/dist/providers/transports/acp-profiles/hermes.d.ts +0 -27
  178. package/dist/providers/transports/acp-profiles/index.d.ts +0 -19
  179. package/dist/providers/transports/acp-profiles/kimi.d.ts +0 -24
  180. package/dist/providers/transports/acp-profiles/opencode.d.ts +0 -26
  181. package/dist/providers/transports/acp-profiles/types.d.ts +0 -258
  182. package/dist/providers/transports/acp-rpc.d.ts +0 -18
  183. package/dist/providers/transports/acp.d.ts +0 -217
  184. package/dist/providers/transports/codex-app-server.d.ts +0 -190
  185. package/dist/providers/transports/hold-open.d.ts +0 -120
  186. package/dist/providers/transports/manager.d.ts +0 -21
  187. package/dist/providers/transports/stream-json.d.ts +0 -162
  188. package/dist/providers/transports/types.d.ts +0 -56
  189. package/dist/providers/types.d.ts +0 -154
  190. package/dist/providers/yolo-contract.d.ts +0 -131
  191. package/dist/script/adapter.d.ts +0 -107
  192. package/dist/script/batch-script.d.ts +0 -7
  193. package/dist/script/index.d.ts +0 -3
  194. package/dist/script/init-environment.d.ts +0 -8
  195. package/dist/script/lmbee-module.d.ts +0 -2
  196. package/dist/script/lmscript.d.ts +0 -647
  197. package/dist/shared/policy.d.ts +0 -74
  198. package/dist/shared-lib/db.d.ts +0 -25
  199. package/dist/shared-lib/passive-session-reader.d.ts +0 -2
  200. package/dist/shared-lib/provider-parse.d.ts +0 -6
  201. package/dist/templates/basedir.d.ts +0 -52
  202. package/dist/uri/lmctl_uri.d.ts +0 -38
@@ -1,173 +0,0 @@
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 {};
@@ -1,34 +0,0 @@
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 {};
@@ -1,44 +0,0 @@
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 {};
@@ -1,89 +0,0 @@
1
- /**
2
- * Passive (read-only, bounded, certified) reader for OpenCode sessions.
3
- *
4
- * ## Relationship to lmplayer (the investigated finding, from real stores)
5
- *
6
- * lmplayer IS an opencode fork/wrapper, and the two share the opencode SQLite
7
- * schema EXACTLY: `message(id,session_id,time_created,time_updated,data)`,
8
- * `part(id,message_id,session_id,time_created,time_updated,data)`,
9
- * `session(id,project_id,…)`, with the per-row `data` column holding JSON. Verified
10
- * on this box: an opencode assistant `message.data` is
11
- * `{parentID, role:"assistant", tokens:{input,output,reasoning,cache:{read,write}},
12
- * modelID, providerID, time:{created,completed}}` and a tool `part.data` is
13
- * `{type:"tool", tool, callID, state:{status,input,output,metadata:{display}}}` —
14
- * byte-for-byte the shapes the dispatcher's lmplayer reader already handles.
15
- *
16
- * What DIFFERS is ONLY the store location and the label:
17
- * - opencode canonical store: `$XDG_DATA_HOME/opencode/opencode.db` (large, live)
18
- * and `…/opencode/opencode-local.db`, plus `$XDG_CONFIG_HOME/opencode/opencode.db`.
19
- * - lmplayer store: `$XDG_DATA_HOME/lmplayer/opencode*.db` (with extra
20
- * lmplayer-only `session_job*` tables — the source of the
21
- * `session-job-notification` synthetic part type, filtered here too).
22
- *
23
- * So this reader reuses the lmplayer extraction verbatim but labels every source
24
- * `provider:"opencode"` — NEVER "lmplayer", even though the SQLite shape is
25
- * identical (lmbi's explicit "no cross-provider mislabeling" requirement). The
26
- * label flows from `source.provider`, which discovery sets to `"opencode"`.
27
- *
28
- * LANDMINE for wiring: the `OPENCODE_DB` env var currently routes the dispatcher's
29
- * LMPLAYER default paths — pointing it at the opencode store would label opencode
30
- * data as `lmplayer`. This reader deliberately does NOT read that env; an explicit
31
- * store override goes through `OpencodePassiveReaderOptions.dbPaths`.
32
- *
33
- * De-duplicate the mirrored helpers (parseApplyPatch / classifyTool / firstPath /
34
- * writeInputBytes / sqliteRevision / the row reader) against the dispatcher's own
35
- * copies at wiring time.
36
- */
37
- import type { ReadLimits, Snapshot, Source, SourceState } from "../passive-session-reader.js";
38
- export declare const OPENCODE_PROVIDER = "opencode";
39
- /** opencode's own canonical stores (NOT lmplayer's, NOT the OPENCODE_DB env). */
40
- export declare function defaultOpencodeDbPaths(): string[];
41
- interface OpencodeMessageRow extends Record<string, unknown> {
42
- id: string;
43
- time_created: number;
44
- time_updated: number;
45
- data: string;
46
- }
47
- interface OpencodePartRow extends Record<string, unknown> {
48
- id: string;
49
- message_id: string;
50
- time_created: number;
51
- time_updated: number;
52
- data: string;
53
- }
54
- /** Extract per-response metadata from an opencode session's rows. Verbatim
55
- * lmplayer logic, labeled through `source.provider` (= "opencode"). */
56
- export declare function readOpencodeRows(source: Source, revision: string, rows: {
57
- messages: OpencodeMessageRow[];
58
- parts: OpencodePartRow[];
59
- }, limits: ReadLimits): Snapshot;
60
- export interface OpencodePassiveReaderOptions {
61
- /** Overrides the default opencode store paths (does NOT read `OPENCODE_DB`). */
62
- dbPaths?: string[];
63
- sqliteBusyTimeoutMs?: number;
64
- }
65
- /** Keyset watermark for cross-DB discovery (one page continues after this key). */
66
- export interface OpencodeDiscoveryCursor {
67
- source_id: string;
68
- sessionid: string;
69
- }
70
- export declare class OpencodePassiveReader {
71
- private readonly dbPaths;
72
- private readonly sqliteBusyTimeoutMs;
73
- constructor(options?: OpencodePassiveReaderOptions);
74
- private openDb;
75
- /**
76
- * Enumerate up to `cap` sources ordered by `source_id\0sessionid`, deduped by
77
- * session id (the first configured DB that holds it is canonical). `after`
78
- * continues a previous page. Bounded SQL (`LIMIT`) — no traversal budget, so
79
- * `truncated` is always false.
80
- */
81
- discover(limits: ReadLimits, cap: number, after?: OpencodeDiscoveryCursor | null): Promise<{
82
- sources: Source[];
83
- truncated: boolean;
84
- }>;
85
- inspect(source: Source, limits: ReadLimits): SourceState;
86
- read(source: Source, revision: string, limits: ReadLimits): Snapshot;
87
- }
88
- export declare function createOpencodePassiveReader(options?: OpencodePassiveReaderOptions): OpencodePassiveReader;
89
- export {};
@@ -1,151 +0,0 @@
1
- /**
2
- * Passive (read-only, bounded, certified) reader for Qwen Code sessions.
3
- *
4
- * ## Why this reader does not follow either of qwen.ts's own headers
5
- *
6
- * `src/providers/qwen.ts` carries two conflicting claims: its file header says
7
- * "Qwen Code is a Claude Code fork — same JSONL session format", while its
8
- * `QwenUsageMetadata` comment says "Qwen Code is a Gemini CLI fork; usageMetadata
9
- * follows Gemini API semantics". Neither label alone describes the records on
10
- * disk, so this reader was written from the records instead. What a census of
11
- * every `*.jsonl` under the local projects store actually shows (1155 records,
12
- * 0 parse failures):
13
- *
14
- * - The ENVELOPE is Claude-shaped: `uuid`, `parentUuid`, `sessionId`,
15
- * `timestamp`, `type`, `cwd`, `version`, `gitBranch` on 1155/1155 records.
16
- * - The record TYPES diverge from Claude: `system` (592), `assistant` (276),
17
- * `tool_result` (238), `user` (49). Claude folds tool results into `user`
18
- * rows; qwen gives them their own type. That makes a `user` row an
19
- * unambiguous external prompt admission here — no tool_result sniffing.
20
- * - Usage exists in TWO shapes simultaneously, so "which fork" is the wrong
21
- * question:
22
- * 1. `assistant.usageMetadata` — Gemini camelCase
23
- * (`promptTokenCount` / `candidatesTokenCount` / `thoughtsTokenCount` /
24
- * `totalTokenCount` / `cachedContentTokenCount`), on 276 records, with
25
- * NO per-response identity of any kind.
26
- * 2. `system` rows with `subtype:"ui_telemetry"` and
27
- * `systemPayload.uiEvent["event.name"] === "qwen-code.api_response"` —
28
- * snake_case (`input_token_count` / `output_token_count` /
29
- * `cached_content_token_count` / `thoughts_token_count` /
30
- * `total_token_count`), on 289 records, each carrying a native
31
- * `response_id` (`chatcmpl-…`).
32
- *
33
- * This reader treats shape (2) as authoritative, because it is the ONLY source
34
- * with a native per-response id — the contract forbids fabricating a
35
- * `response_id` out of an envelope uuid — and it strictly covers shape (1)
36
- * (289 ≥ 276; the extra 13 are `subagent_name` responses that have no
37
- * top-level assistant row at all).
38
- *
39
- * ## Token semantics: measured, not assumed
40
- *
41
- * All 289 local api_response records satisfy, with zero violations:
42
- * input_token_count + output_token_count === total_token_count
43
- * cached_content_token_count <= input_token_count
44
- * thoughts_token_count <= output_token_count
45
- *
46
- * i.e. cached is a SUBSET of input and thoughts a SUBSET of output — Gemini
47
- * semantics, now verified on real records rather than inherited from a comment.
48
- * The three invariants are re-checked at read time; a violation makes the whole
49
- * snapshot `partial` rather than emitting numbers whose meaning we cannot stand
50
- * behind.
51
- *
52
- * `input_cache_write` is NULL, not 0: no cache-write counter exists anywhere in
53
- * this wire (no such key on any of the 289 records), so its value is unrecorded,
54
- * not known-zero.
55
- *
56
- * `model_provider` is NULL. The nearest native field is `auth_type`
57
- * (`openai` / `qwen-oauth` locally), which is an AUTHENTICATION method, not a
58
- * model-provider identity; reporting `qwen-oauth` as a provider would be a
59
- * mislabel. See the note in the owner report.
60
- */
61
- import type { ReadLimits, Snapshot, Source, SourceState } from "../passive-session-reader.js";
62
- import { type TokenValues } from "./shared.js";
63
- export declare const QWEN_PROVIDER = "qwen";
64
- /** One raw line of a qwen chat transcript. Only fields this reader reads. */
65
- interface QwenLine {
66
- uuid?: unknown;
67
- parentUuid?: unknown;
68
- sessionId?: unknown;
69
- type?: unknown;
70
- subtype?: unknown;
71
- timestamp?: unknown;
72
- message?: unknown;
73
- systemPayload?: unknown;
74
- }
75
- export interface QwenPassiveReaderOptions {
76
- /**
77
- * Discovery roots, in the caller's preferred order. Defaults to the live store
78
- * plus every retained backup store (see `defaultQwenProjectRoots`).
79
- */
80
- qwenProjectsDirs?: string[];
81
- maxDiscoveryTraversalVisits?: number;
82
- }
83
- /**
84
- * Default qwen discovery roots.
85
- *
86
- * `~/.qwen.bk1/projects` is a RETAINED ACCOUNT HISTORY store, not a redundant
87
- * copy to skip. Verified on this box: 30 transcripts there against 27 in the
88
- * live root, with **zero identity overlap** — 0 shared file names, 0 shared
89
- * in-record `sessionId`s and 0 shared `response_id`s — over disjoint telemetry
90
- * spans (backup 2026-03-14 → 04-12, live 2026-04-14 → 07-02). Excluding it
91
- * would silently drop 89 real responses from any cost total.
92
- */
93
- export declare function defaultQwenProjectRoots(): string[];
94
- /**
95
- * Map one api_response telemetry event onto the contract's four token slots.
96
- * Returns null when a required counter is missing/not a non-negative integer, or
97
- * when any of the three measured invariants fails — the caller turns that into a
98
- * `partial` snapshot rather than guessing.
99
- */
100
- export declare function qwenTokens(event: Record<string, unknown>): TokenValues | null;
101
- export declare function readQwen(lines: QwenLine[], source: Source, revision: string, limits: ReadLimits): Snapshot;
102
- /**
103
- * Do the records agree with the session id the caller asked for? True when no
104
- * record names a session at all (nothing to contradict) or when every named
105
- * session equals `sessionid`. False on any disagreement, including a transcript
106
- * that names two different sessions.
107
- */
108
- export declare function qwenRecordsMatchSession(lines: QwenLine[], sessionid: string): boolean;
109
- export declare class QwenPassiveReader {
110
- /**
111
- * Resolved discovery roots, in configured order. Exposed so a caller can map a
112
- * `source_id` back to the root it came from without re-deriving the defaults.
113
- */
114
- readonly roots: readonly string[];
115
- private readonly maxDiscoveryTraversalVisits;
116
- constructor(options?: QwenPassiveReaderOptions);
117
- /**
118
- * Enumerate up to `cap` sources across EVERY configured root, ordered by real
119
- * path. `afterPath` continues a previous page; real-path order is total, so one
120
- * cursor resumes the merged stream correctly.
121
- *
122
- * ## Provenance and cross-root identity
123
- *
124
- * `source_id` is the file's absolute real path, so it names the root a session
125
- * came from (`…/.qwen/projects/…` vs `…/.qwen.bk1/projects/…`) without any
126
- * extra field on the shared `Source` shape. Two sessions that happen to share a
127
- * `sessionid` across roots therefore stay two DISTINCT sources with distinct
128
- * `source_id`s, and both are read.
129
- *
130
- * This reader performs **no identity dedup** — that is the consumer's job, on
131
- * real ids. The only collapsing done here is by real path, which removes a file
132
- * reachable through two configured roots (e.g. one root symlinked inside
133
- * another); that is the same physical file, never two sessions that merely look
134
- * alike. Nothing is ever dropped because a similarly-named file exists
135
- * elsewhere.
136
- */
137
- discover(limits: ReadLimits, cap: number, afterPath?: string | null): Promise<{
138
- sources: Source[];
139
- truncated: boolean;
140
- }>;
141
- /**
142
- * A source_id is only ours when it is a real, non-symlink file contained by one
143
- * of the configured roots AND its basename is the claimed session id. Both
144
- * checks run before any read.
145
- */
146
- private matches;
147
- inspect(source: Source, limits: ReadLimits): Promise<SourceState>;
148
- read(source: Source, revision: string, limits: ReadLimits): Promise<Snapshot>;
149
- }
150
- export declare function createQwenPassiveReader(options?: QwenPassiveReaderOptions): QwenPassiveReader;
151
- export {};
@@ -1,138 +0,0 @@
1
- /**
2
- * Self-contained primitives for the per-provider passive readers that live in
3
- * this directory (agy, qwen).
4
- *
5
- * WHY THIS FILE EXISTS: the equivalent helpers inside
6
- * `src/providers/passive-session-reader.ts` are module-private, and that file is
7
- * concurrently owned by the discovery-fairness redesign. Re-implementing the
8
- * handful we need here keeps this slice landable without touching the shared
9
- * dispatcher. Only the PUBLIC contract types are imported from it, so there is
10
- * exactly one definition of the wire shape.
11
- *
12
- * At wiring time these should be de-duplicated against the dispatcher's own
13
- * copies (see PASSIVE_EXTRACTION_SEMANTICS below — that constant in particular
14
- * MUST stay equal to the dispatcher's `EXTRACTION_SEMANTICS`).
15
- */
16
- import type { ExternalIoEntry, PricingFacts, ReadLimits } from "../passive-session-reader.js";
17
- /**
18
- * Extraction-semantics tag folded into every revision string.
19
- *
20
- * MUST equal `EXTRACTION_SEMANTICS` in `../passive-session-reader.ts` (currently
21
- * "bx3"). A revision is compared by lmbi as a plain string, so a reader emitting
22
- * a different tag for the same native bytes would look permanently un-indexed.
23
- * Bump both together whenever extraction semantics change — this file's real
24
- * de-dup against the dispatcher's copy is still pending (see file header);
25
- * until then a bump here is easy to miss, as happened with the bx2→bx3 change.
26
- */
27
- export declare const PASSIVE_EXTRACTION_SEMANTICS = "bx3";
28
- export type FileDirection = "read" | "written";
29
- export interface FileObservation {
30
- path: string;
31
- bytes: number | null;
32
- }
33
- export interface TokenValues {
34
- input_uncached: number | null;
35
- input_cached: number | null;
36
- input_cache_write: number | null;
37
- output: number | null;
38
- }
39
- export declare const EMPTY_TOKENS: TokenValues;
40
- export declare function record(value: unknown): Record<string, unknown> | null;
41
- export declare function nonnegativeInteger(value: unknown): number | null;
42
- /** Non-negative integer counter, or null. Used for pricing_facts counts. */
43
- export declare function optCount(value: unknown): number | null;
44
- export declare function canonicalTimestamp(value: unknown): string | null;
45
- export declare function checkedLimits(limits: ReadLimits): void;
46
- /**
47
- * Deterministic UTF-16 code-unit ordering for opaque identifiers/paths. ICU
48
- * collation can differ across Node builds; two processes must agree on cursor
49
- * order, so code-unit comparison is the safe primitive.
50
- */
51
- export declare function compareCodeUnits(left: string, right: string): number;
52
- /**
53
- * Per-response file observations keyed by (call id, direction, path) — the
54
- * "smallest honest unit". Two DIFFERENT call ids to the same path stay separate;
55
- * a replayed record of the SAME call id coalesces (first recorded wins).
56
- * `bytes` is UTF-8 content size: a number (including 0), or null when the
57
- * content is genuinely unavailable.
58
- */
59
- export declare class ObservationSet {
60
- private readonly map;
61
- record(callId: string, direction: FileDirection, path: unknown, bytes: number | null): void;
62
- files(direction: FileDirection): FileObservation[];
63
- }
64
- /**
65
- * Collector for non-file external-I/O entries. Deduplicates by native
66
- * (id, direction, kind); a MEASURED id-less entry is never deduplicated
67
- * (content/byte dedup is forbidden by the contract), while id-less null-byte
68
- * coverage markers may merge (one unknown marker forces NULL as well as two).
69
- */
70
- export declare class ExternalIoSet {
71
- private readonly map;
72
- record(entry: ExternalIoEntry): void;
73
- entries(): ExternalIoEntry[];
74
- }
75
- /**
76
- * Per-direction aggregate: numeric ONLY when the whole direction is known —
77
- * `files` non-null with every byte numeric AND every external_io entry in this
78
- * direction numeric. ANY null contributor → null (never a partial sum posing as
79
- * a total). A fully-classified direction with no contributors → 0.
80
- */
81
- export declare function aggregateDirection(files: FileObservation[] | null, io: ExternalIoEntry[] | null, direction: FileDirection): number | null;
82
- /**
83
- * Build a validated pricing_facts object, dropping fields that are not present
84
- * as non-negative integers and enforcing the two invariants: reasoning ≤ output,
85
- * and (5m + 1h) cache-write TTL counts ≤ the known cache-write total. Returns
86
- * null when nothing valid is present. A recorded 0 is preserved (0 ≠ unknown).
87
- */
88
- export declare function buildPricingFacts(raw: {
89
- cacheWrite5m?: unknown;
90
- cacheWrite1h?: unknown;
91
- reasoning?: unknown;
92
- webSearch?: unknown;
93
- webFetch?: unknown;
94
- }, outputTokens: number | null, cacheWriteTotal: number | null): PricingFacts | null;
95
- export declare function isInternalControlTool(name: unknown): boolean;
96
- /** Record an opaque/uncertified tool call as unknown in BOTH directions. */
97
- export declare function recordUnattributedBoth(io: ExternalIoSet, callId: string | null): void;
98
- /**
99
- * UTF-8 byte size of the content WRITTEN by a write call, taken from the call's
100
- * OWN input (never the file on disk). Returns 0 for a genuinely empty write,
101
- * null when no content field is present.
102
- */
103
- export declare function writeInputBytes(input: unknown): number | null;
104
- /**
105
- * Resolve `path` to its real location and require it to be a regular,
106
- * non-symlink file contained by one of `roots`. Returns the real path, or null.
107
- */
108
- export declare function containedRealFile(path: string, roots: string[]): Promise<string | null>;
109
- /**
110
- * Read a JSONL file within the byte budget and hash its exact native bytes.
111
- * Returns null when the file is missing, oversized, or changed underneath the
112
- * read (dev/ino/size/mtime re-checked after) — a torn read is never reported as
113
- * a clean revision.
114
- */
115
- export declare function jsonlRevision(path: string, limits: ReadLimits): Promise<{
116
- revision: string;
117
- data: Buffer;
118
- } | null>;
119
- /**
120
- * Parse a complete JSONL buffer. Returns null when the file does not end on a
121
- * record boundary (a live append caught mid-line) or any line is not a JSON
122
- * object — a torn/partial file is never silently treated as complete.
123
- */
124
- export declare function parseJsonl<T>(data: Buffer, limits: ReadLimits): T[] | null;
125
- /** Minimal read-only `node:sqlite` surface used by the sqlite-backed readers. */
126
- export interface SqliteStatement {
127
- all(...params: unknown[]): unknown[];
128
- get(...params: unknown[]): unknown;
129
- }
130
- export interface SqliteDatabase {
131
- close(): void;
132
- exec(sql: string): void;
133
- prepare(sql: string): SqliteStatement;
134
- }
135
- export type SqliteDatabaseConstructor = new (path: string, options?: {
136
- open?: boolean;
137
- readOnly?: boolean;
138
- }) => SqliteDatabase;