@lmctl-ai/lmctl 0.2.37 → 0.2.39

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 (199) hide show
  1. package/README.md +16 -0
  2. package/THIRD_PARTY_NOTICES.md +35 -0
  3. package/bin/lmbee +2 -0
  4. package/bin/lmscript +3 -0
  5. package/build-info.json +1 -0
  6. package/dist/cli/index.js +569 -494
  7. package/dist/cli/schema.sql +0 -169
  8. package/dist/cli/script.js +273 -266
  9. package/dist/lmbee.js +960 -0
  10. package/dist/lmscript.js +388 -0
  11. package/dist/public/app.js +379 -0
  12. package/dist/public/index.html +78 -0
  13. package/dist/public/styles.css +160 -0
  14. package/dist/schema.sql +455 -0
  15. package/dist/vendor-webui/index.html +18 -0
  16. package/dist/vendor-webui/local.js +231 -0
  17. package/dist/vendor-webui/styles.css +1852 -0
  18. package/package.json +12 -7
  19. package/dist/cli/batch.d.ts +0 -2
  20. package/dist/cli/busy-evidence.d.ts +0 -27
  21. package/dist/cli/chat-cycle.d.ts +0 -59
  22. package/dist/cli/chat-exec.d.ts +0 -91
  23. package/dist/cli/chat-policy.d.ts +0 -22
  24. package/dist/cli/chat.d.ts +0 -14
  25. package/dist/cli/code-resolver.d.ts +0 -8
  26. package/dist/cli/common.d.ts +0 -57
  27. package/dist/cli/context.d.ts +0 -12
  28. package/dist/cli/cost.d.ts +0 -2
  29. package/dist/cli/export.d.ts +0 -2
  30. package/dist/cli/hello.d.ts +0 -10
  31. package/dist/cli/index.d.ts +0 -3
  32. package/dist/cli/infra.d.ts +0 -78
  33. package/dist/cli/init.d.ts +0 -21
  34. package/dist/cli/intent-input.d.ts +0 -16
  35. package/dist/cli/intent-match.d.ts +0 -30
  36. package/dist/cli/intent-sessions.d.ts +0 -24
  37. package/dist/cli/intent-team.d.ts +0 -25
  38. package/dist/cli/intent.d.ts +0 -22
  39. package/dist/cli/ls.d.ts +0 -2
  40. package/dist/cli/mailbox-cli.d.ts +0 -6
  41. package/dist/cli/managed.d.ts +0 -62
  42. package/dist/cli/mcp-install.d.ts +0 -23
  43. package/dist/cli/mcp.d.ts +0 -2
  44. package/dist/cli/model.d.ts +0 -21
  45. package/dist/cli/paths.d.ts +0 -50
  46. package/dist/cli/plan-wizard.d.ts +0 -42
  47. package/dist/cli/plan.d.ts +0 -20
  48. package/dist/cli/queue-delivery.d.ts +0 -122
  49. package/dist/cli/quickrun.d.ts +0 -14
  50. package/dist/cli/ratelimit.d.ts +0 -2
  51. package/dist/cli/remote-fetch.d.ts +0 -7
  52. package/dist/cli/run-queries.d.ts +0 -82
  53. package/dist/cli/running.d.ts +0 -5
  54. package/dist/cli/save-script.d.ts +0 -41
  55. package/dist/cli/script.d.ts +0 -6
  56. package/dist/cli/seed-flight.d.ts +0 -2
  57. package/dist/cli/self-identity.d.ts +0 -25
  58. package/dist/cli/session-idle.d.ts +0 -118
  59. package/dist/cli/status.d.ts +0 -22
  60. package/dist/cli/tail.d.ts +0 -18
  61. package/dist/cli/target-resolver.d.ts +0 -139
  62. package/dist/cli/team-status.d.ts +0 -91
  63. package/dist/cli/teamfile-compat.d.ts +0 -116
  64. package/dist/cli/teamfile-store.d.ts +0 -18
  65. package/dist/cli/teamfile-template.d.ts +0 -47
  66. package/dist/cli/template-env.d.ts +0 -25
  67. package/dist/cli/terminal-lock.d.ts +0 -25
  68. package/dist/cli/terminal.d.ts +0 -23
  69. package/dist/cli/time-filter.d.ts +0 -10
  70. package/dist/cli/update-notifier.d.ts +0 -11
  71. package/dist/cli/version-util.d.ts +0 -23
  72. package/dist/config/seed_templates.d.ts +0 -1
  73. package/dist/db/backfill-event-log.d.ts +0 -26
  74. package/dist/db/delegation.d.ts +0 -37
  75. package/dist/db/escalation_vocab.d.ts +0 -45
  76. package/dist/db/event-log.d.ts +0 -40
  77. package/dist/db/index.d.ts +0 -1213
  78. package/dist/db/inflight-acquire.d.ts +0 -70
  79. package/dist/db/invocation-event-projections.d.ts +0 -65
  80. package/dist/db/ledger-identity.test.d.ts +0 -1
  81. package/dist/db/live-event-projections.d.ts +0 -92
  82. package/dist/db/migrate.d.ts +0 -51
  83. package/dist/db/open-readonly.d.ts +0 -2
  84. package/dist/db/process-liveness.d.ts +0 -37
  85. package/dist/db/sqlite.d.ts +0 -53
  86. package/dist/db/sqlite.test.d.ts +0 -1
  87. package/dist/db/terminal-lock.d.ts +0 -14
  88. package/dist/db/tracked-invocation-reconcile.d.ts +0 -52
  89. package/dist/db/tracked-invocation.d.ts +0 -116
  90. package/dist/mcp/dispatch.d.ts +0 -45
  91. package/dist/mcp/mediation.d.ts +0 -128
  92. package/dist/mcp/path-warning.d.ts +0 -7
  93. package/dist/mcp/server.d.ts +0 -63
  94. package/dist/mcp/tools.d.ts +0 -24
  95. package/dist/providers/adapter.d.ts +0 -271
  96. package/dist/providers/adapters/agy-adapter.d.ts +0 -18
  97. package/dist/providers/adapters/claude-adapter.d.ts +0 -20
  98. package/dist/providers/adapters/codex-adapter.d.ts +0 -22
  99. package/dist/providers/adapters/copilot-adapter.d.ts +0 -16
  100. package/dist/providers/adapters/dsh-adapter.d.ts +0 -89
  101. package/dist/providers/adapters/gemini-adapter.d.ts +0 -44
  102. package/dist/providers/adapters/hermes-adapter.d.ts +0 -71
  103. package/dist/providers/adapters/index.d.ts +0 -35
  104. package/dist/providers/adapters/kimi-adapter.d.ts +0 -16
  105. package/dist/providers/adapters/lmplayer-adapter.d.ts +0 -14
  106. package/dist/providers/adapters/opencode-adapter.d.ts +0 -11
  107. package/dist/providers/adapters/pi-adapter.d.ts +0 -17
  108. package/dist/providers/adapters/print-turn.d.ts +0 -29
  109. package/dist/providers/adapters/qwen-adapter.d.ts +0 -11
  110. package/dist/providers/agy.d.ts +0 -32
  111. package/dist/providers/base-adapter.d.ts +0 -110
  112. package/dist/providers/base.d.ts +0 -12
  113. package/dist/providers/binary-check.d.ts +0 -102
  114. package/dist/providers/bundle.d.ts +0 -124
  115. package/dist/providers/claude-mock.d.ts +0 -90
  116. package/dist/providers/claude.d.ts +0 -21
  117. package/dist/providers/codex-config.d.ts +0 -15
  118. package/dist/providers/codex.d.ts +0 -25
  119. package/dist/providers/config/init-config.d.ts +0 -43
  120. package/dist/providers/config/model-selection-lint.d.ts +0 -70
  121. package/dist/providers/config/team-config.d.ts +0 -184
  122. package/dist/providers/config/types.d.ts +0 -146
  123. package/dist/providers/config/user-config.d.ts +0 -88
  124. package/dist/providers/copilot.d.ts +0 -21
  125. package/dist/providers/debug.d.ts +0 -128
  126. package/dist/providers/dsh-sidecar.d.ts +0 -65
  127. package/dist/providers/dsh-zstd.d.ts +0 -27
  128. package/dist/providers/dsh.d.ts +0 -37
  129. package/dist/providers/frontmatter.d.ts +0 -46
  130. package/dist/providers/gemini-session-reader.d.ts +0 -151
  131. package/dist/providers/gemini.d.ts +0 -39
  132. package/dist/providers/hermes.d.ts +0 -90
  133. package/dist/providers/index.d.ts +0 -423
  134. package/dist/providers/kimi.d.ts +0 -37
  135. package/dist/providers/model-catalog.d.ts +0 -145
  136. package/dist/providers/model-suggestions.d.ts +0 -4
  137. package/dist/providers/one-shot-timeout.d.ts +0 -1
  138. package/dist/providers/opencode-config.d.ts +0 -62
  139. package/dist/providers/opencode.d.ts +0 -40
  140. package/dist/providers/parsers/acp.d.ts +0 -71
  141. package/dist/providers/parsers/codex-app-server.d.ts +0 -60
  142. package/dist/providers/parsers/stream-json.d.ts +0 -57
  143. package/dist/providers/passive-readers/agy.d.ts +0 -155
  144. package/dist/providers/passive-readers/copilot.d.ts +0 -173
  145. package/dist/providers/passive-readers/dsh.d.ts +0 -34
  146. package/dist/providers/passive-readers/kimi.d.ts +0 -44
  147. package/dist/providers/passive-readers/opencode.d.ts +0 -89
  148. package/dist/providers/passive-readers/qwen.d.ts +0 -151
  149. package/dist/providers/passive-readers/shared.d.ts +0 -138
  150. package/dist/providers/passive-session-reader.d.ts +0 -188
  151. package/dist/providers/path-utils.d.ts +0 -1
  152. package/dist/providers/pi.d.ts +0 -32
  153. package/dist/providers/pricing.d.ts +0 -107
  154. package/dist/providers/qwen.d.ts +0 -22
  155. package/dist/providers/ratelimit/agy.d.ts +0 -22
  156. package/dist/providers/ratelimit/claude-auth.d.ts +0 -13
  157. package/dist/providers/ratelimit/claude.d.ts +0 -6
  158. package/dist/providers/ratelimit/codex.d.ts +0 -7
  159. package/dist/providers/ratelimit/kimi-auth.d.ts +0 -15
  160. package/dist/providers/ratelimit/kimi.d.ts +0 -6
  161. package/dist/providers/ratelimit/schema.d.ts +0 -28
  162. package/dist/providers/ratelimit-readings.d.ts +0 -19
  163. package/dist/providers/registry.d.ts +0 -31
  164. package/dist/providers/resume.d.ts +0 -43
  165. package/dist/providers/seed-instruction.d.ts +0 -3
  166. package/dist/providers/self-session-env.d.ts +0 -21
  167. package/dist/providers/session-limit.d.ts +0 -9
  168. package/dist/providers/strip-ansi.d.ts +0 -5
  169. package/dist/providers/transport-errors.d.ts +0 -94
  170. package/dist/providers/transport-lifecycle.d.ts +0 -63
  171. package/dist/providers/transport-wrappers.d.ts +0 -110
  172. package/dist/providers/transports/acp-profiles/config-option-step.d.ts +0 -24
  173. package/dist/providers/transports/acp-profiles/copilot.d.ts +0 -12
  174. package/dist/providers/transports/acp-profiles/gemini.d.ts +0 -22
  175. package/dist/providers/transports/acp-profiles/hermes.d.ts +0 -27
  176. package/dist/providers/transports/acp-profiles/index.d.ts +0 -19
  177. package/dist/providers/transports/acp-profiles/kimi.d.ts +0 -24
  178. package/dist/providers/transports/acp-profiles/opencode.d.ts +0 -26
  179. package/dist/providers/transports/acp-profiles/types.d.ts +0 -258
  180. package/dist/providers/transports/acp-rpc.d.ts +0 -18
  181. package/dist/providers/transports/acp.d.ts +0 -217
  182. package/dist/providers/transports/codex-app-server.d.ts +0 -190
  183. package/dist/providers/transports/hold-open.d.ts +0 -120
  184. package/dist/providers/transports/manager.d.ts +0 -21
  185. package/dist/providers/transports/stream-json.d.ts +0 -162
  186. package/dist/providers/transports/types.d.ts +0 -56
  187. package/dist/providers/types.d.ts +0 -154
  188. package/dist/providers/yolo-contract.d.ts +0 -131
  189. package/dist/script/adapter.d.ts +0 -104
  190. package/dist/script/batch-script.d.ts +0 -7
  191. package/dist/script/index.d.ts +0 -3
  192. package/dist/script/lmbee-module.d.ts +0 -2
  193. package/dist/script/lmscript.d.ts +0 -616
  194. package/dist/shared/policy.d.ts +0 -74
  195. package/dist/shared-lib/db.d.ts +0 -25
  196. package/dist/shared-lib/passive-session-reader.d.ts +0 -2
  197. package/dist/shared-lib/provider-parse.d.ts +0 -6
  198. package/dist/templates/basedir.d.ts +0 -52
  199. package/dist/uri/lmctl_uri.d.ts +0 -38
@@ -1,88 +0,0 @@
1
- import type { UserConfig } from "./types.js";
2
- type OneShotMode = "argv" | "stdin";
3
- type OneShotProviderConfig = {
4
- mode: OneShotMode;
5
- argv: string[];
6
- };
7
- export declare const DEFAULT_ONE_SHOT_OPTIONS: Record<string, OneShotProviderConfig>;
8
- /** Default path for the user config file. */
9
- export declare function getDefaultUserConfigPath(): string;
10
- /**
11
- * Read and parse the user config file.
12
- *
13
- * The format is INI-like with:
14
- * - [tool.<name>] sections containing key=value pairs for start/resume
15
- * - [tool.<name>.profile.<profile>] sections containing description/flags
16
- *
17
- * If the file does not exist, returns an empty config.
18
- */
19
- export declare function readUserConfig(filePath?: string): UserConfig;
20
- /**
21
- * Parse a token-count value with optional shorthand suffix.
22
- *
23
- * Accepted forms:
24
- * - "128000" → 128000
25
- * - "128K" → 128000 (K = ×1000)
26
- * - "1.5K" → 1500 (fractional allowed)
27
- * - "1M" → 1000000 (M = ×1000000)
28
- * - 128000 → 128000 (raw number)
29
- *
30
- * Returns null on unparseable input. Suffix matching is case-insensitive
31
- * (lowercase `k` / `m` are accepted).
32
- */
33
- export declare function parseTokenShorthand(raw: string | number): number | null;
34
- /** Internal: parse user config from string. */
35
- export declare function parseUserConfigText(raw: string): UserConfig;
36
- /**
37
- * Safe reader for the optional site name. Null when unset — the value is
38
- * informational and never required, so callers must not treat null as an
39
- * error. (NOTE: `debug=true` handling lives in src/providers/debug.ts with
40
- * its own scan and is deliberately untouched by the top-level capture here.)
41
- */
42
- export declare function getSiteName(cfg: UserConfig): string | null;
43
- /** Built-in defaults applied when neither config nor CLI flag overrides. */
44
- export declare const COMPACT_DEFAULT_MIN = 128000;
45
- export declare const COMPACT_DEFAULT_MAX = 300000;
46
- /**
47
- * Resolve effective {min, max} compact thresholds for a given provider.
48
- *
49
- * Precedence (highest wins, per-key):
50
- * 1. `[compact.<provider>]` from user config
51
- * 2. `[compact]` global from user config
52
- * 3. Built-in defaults (`COMPACT_DEFAULT_MIN` / `COMPACT_DEFAULT_MAX`)
53
- *
54
- * `min` and `max` are resolved independently — a provider override may
55
- * supply only `min` and inherit `max` from the global. Same for global
56
- * inheriting from defaults.
57
- */
58
- export declare function resolveCompactThresholds(cfg: UserConfig, provider: string): {
59
- min: number;
60
- max: number;
61
- };
62
- /**
63
- * Check if the user has an explicit [tool.<name>] section in their config.
64
- * Returns false if only DEFAULT_TOOLS would be used.
65
- */
66
- export declare function hasUserToolConfig(cfg: UserConfig, toolName: string): boolean;
67
- export declare function hasConfiguredProfile(cfg: UserConfig, toolName: string, profile?: string): boolean;
68
- export declare function buildResumeCommand(cfg: UserConfig, toolName: string, sessionId: string, profile?: string): string;
69
- /**
70
- * Build a shell command to start a new session.
71
- *
72
- * If a named profile is specified, its configured flags are appended.
73
- */
74
- export declare function buildStartCommand(cfg: UserConfig, toolName: string, profile?: string): string;
75
- /**
76
- * Build a non-interactive (one-shot) command to send a prompt to an existing
77
- * session and get the response back. The tool runs, prints output, and exits.
78
- *
79
- * Replaces {{session_id}} and {{prompt}} placeholders. The prompt is
80
- * shell-escaped (single-quoted with internal single-quotes escaped).
81
- */
82
- export declare function buildAgentCommand(cfg: UserConfig, toolName: string, sessionId: string, prompt: string, profile?: string): string;
83
- /**
84
- * Create a default user config file with templates for all supported tools.
85
- * Creates parent directories as needed.
86
- */
87
- export declare function writeDefaultUserConfig(filePath: string): void;
88
- export {};
@@ -1,21 +0,0 @@
1
- import type { SessionProvider, SessionSummary, SessionDetail } from "./types.js";
2
- interface CopilotProviderOptions {
3
- copilotDir?: string;
4
- }
5
- export declare class CopilotProvider implements SessionProvider {
6
- name: "copilot";
7
- private sessionStateDir;
8
- constructor(options?: CopilotProviderOptions);
9
- getWatchPaths(): {
10
- directory: string;
11
- filePattern: RegExp;
12
- }[];
13
- discoverSessions(): Promise<SessionSummary[]>;
14
- loadSession(sessionId: string): Promise<SessionDetail | null>;
15
- private extractSummary;
16
- private readWorkspaceYaml;
17
- resolveSessionPath(sessionId: string): Promise<string | null>;
18
- deleteSession(sessionId: string): Promise<boolean>;
19
- private resolveSessionDir;
20
- }
21
- export {};
@@ -1,128 +0,0 @@
1
- /**
2
- * Global debug logging.
3
- *
4
- * Usage:
5
- * initDebug(command) — call once at startup from the root action
6
- * dlog("message") — append to ~/.lmctl/debug-YYYY-MM-DD-HH.log if debug, no-op otherwise
7
- * isDebug() — check current state (re-reads config every 5s)
8
- *
9
- * Four sources, any one enables debug:
10
- * 1. --verbose CLI flag (sets _cliDebug at startup)
11
- * 2. LMCTL_DEBUG=1 env var (checked at startup)
12
- * 3. debug = true in ~/.lmctl/config.toml (re-read with 5s TTL)
13
- * 4. {"debug": true} in ~/.lmctl/config.json (re-read with 5s TTL)
14
- *
15
- * All debug output goes to ~/.lmctl/debug-YYYY-MM-DD-HH.log
16
- * (one file per hour, append mode) — NOT stderr. stderr is consumed by the transport layer and progress
17
- * formatting; debug lines on stderr get lost or mixed with progress
18
- * events. The log file can be examined after the fact with
19
- * `ls -lt ~/.lmctl/debug-*.log | head -1` to find the latest, then
20
- * `tail -f` on it.
21
- *
22
- * The file-based config check means you can enable debug mid-session
23
- * by adding 'debug = true' to config.toml or {"debug": true} to config.json — it takes effect within
24
- * 5s without restarting any running processes.
25
- */
26
- interface Command {
27
- opts(): Record<string, unknown>;
28
- optsWithGlobals: () => Record<string, unknown>;
29
- }
30
- /**
31
- * Initialize debug state. Call once at program startup.
32
- * Reads from Commander --verbose flag or LMCTL_DEBUG env.
33
- */
34
- /**
35
- * Force CLI-level debug on (the top-level `lmctl --debug` flag). Equivalent to
36
- * `--verbose` / `LMCTL_DEBUG=1` but driven by the parsed CLI flag in
37
- * src/cli/index.ts, before any subcommand's Commander instance exists. Also
38
- * exports LMCTL_DEBUG=1 so spawned children / env-based checks inherit it.
39
- */
40
- export declare function enableCliDebug(): void;
41
- export interface CliDebugStateSnapshot {
42
- cliDebug: boolean;
43
- lmctlDebugEnv: string | undefined;
44
- }
45
- export declare function snapshotCliDebugState(): CliDebugStateSnapshot;
46
- export declare function restoreCliDebugState(snapshot: CliDebugStateSnapshot): void;
47
- export declare function initDebug(command?: Command): void;
48
- /**
49
- * Check if debug mode is enabled. Cheap: the file-based check is
50
- * cached with a 5-second TTL so repeated calls in a hot loop are free.
51
- */
52
- export declare function isDebug(): boolean;
53
- export declare function isCliDebug(): boolean;
54
- /**
55
- * Write a structured JSONL event to the debug log file.
56
- * Every line has `ts`, `pid`, and `event` base fields plus any
57
- * additional fields from the event object.
58
- *
59
- * @param event Object with at least `event: string`. Extra fields
60
- * are spread into the JSON record.
61
- * @param opts `verbose: true` restricts to CLI-level debug only
62
- * (--verbose or LMCTL_DEBUG=1, not config.toml).
63
- */
64
- export declare function debugLog(event: {
65
- event: string;
66
- [key: string]: unknown;
67
- }, opts?: {
68
- verbose?: boolean;
69
- always?: boolean;
70
- }): void;
71
- /**
72
- * Append a debug message. Wraps in JSONL `{"event":"legacy","msg":"..."}`.
73
- * No-op if debug is disabled. Never throws.
74
- */
75
- export declare function dlog(...args: string[]): void;
76
- /**
77
- * Verbose-only debug log. Same as dlog() but only fires when debug was
78
- * enabled via --verbose or LMCTL_DEBUG=1 (the CLI sources). Config.toml
79
- * debug=true does NOT enable verbose — it only enables the default level.
80
- *
81
- * Use dlogv() for high-volume / low-value lines (transport request/response,
82
- * idle warnings, CWD, seed status). Use dlog() for MCP lifecycle + chat
83
- * invocation lines that matter even in config-only debug mode.
84
- */
85
- export declare function dlogv(...args: string[]): void;
86
- /**
87
- * Unconditional structured error log. Bypasses the `isDebug()` gate so
88
- * transport-layer failures (errors, timeouts, aborts, unhandled
89
- * incoming requests) are ALWAYS recorded to `~/.lmctl/debug-*.log` for
90
- * post-mortem — without forcing the user to set `LMCTL_DEBUG=1` ahead
91
- * of time. Motivated by the opencode06 hang where the chat ran for
92
- * 42+ minutes with no diagnostic in the debug log.
93
- *
94
- * The convention for the event payload is the same as `debugLog`:
95
- * { event: "transport_error" | "transport_timeout" | "transport_abort"
96
- * | "acp_unhandled_request" | ...,
97
- * provider: "claude"|"codex"|...,
98
- * session_id_short?: string,
99
- * error_class?: string,
100
- * error_message?: string,
101
- * elapsed_ms?: number,
102
- * ...kind-specific fields }
103
- *
104
- * Never throws (inherits `debugLog`'s best-effort guarantee).
105
- */
106
- export declare function errorLog(event: {
107
- event: string;
108
- [key: string]: unknown;
109
- }): void;
110
- /**
111
- * Remove old hourly debug log files, keeping the most recent `keep`
112
- * files. Default: keep 24 (one day of hourly logs). Best-effort —
113
- * never throws.
114
- *
115
- * @param keep Number of newest files to retain.
116
- * @param lmctlDir Directory to scan; defaults to `~/.lmctl/`.
117
- * Task 81 cleanup invokes this with a custom home
118
- * so tests don't have to override HOME.
119
- * @returns `{ kept, removed }` filenames in their respective
120
- * buckets — both arrays are sorted ascending
121
- * (oldest first within each bucket). Failure
122
- * produces a partial / empty result; never throws.
123
- */
124
- export declare function rotateDebugLogs(keep?: number, lmctlDir?: string): {
125
- kept: string[];
126
- removed: string[];
127
- };
128
- export {};
@@ -1,65 +0,0 @@
1
- /**
2
- * dsh `web` profile sidecar manager.
3
- *
4
- * dsh's headless profile is one-shot-only (no session resume, verified in
5
- * `backlog/DESIGN-add-dsh-provider.md`). The only proven continuity path is
6
- * `dsh web`'s internal HTTP RPC surface: it can cold-resume any session
7
- * (headless- or web-created) by caller-supplied id, and `session.prompt`
8
- * genuinely carries context forward turn to turn — proven end-to-end in the
9
- * design doc's research.
10
- *
11
- * This module owns exactly one `dsh web` child process per lmctl process,
12
- * spawned lazily on first use and reused for every `provider=dsh` member's
13
- * turns (sessions are addressed by id over RPC, so one sidecar can serve
14
- * many members/teams concurrently — there is no per-member sidecar needed).
15
- *
16
- * Verified live (2026-08-23): `dsh web --no-open --port 0` prints exactly
17
- * one line, `dsh web: http://127.0.0.1:<port>`, once it's ready to accept
18
- * connections.
19
- */
20
- export interface DshRpcError {
21
- message?: string;
22
- code?: string;
23
- [key: string]: unknown;
24
- }
25
- export declare class DshRpcCallError extends Error {
26
- readonly method: string;
27
- readonly detail: unknown;
28
- constructor(method: string, detail: unknown);
29
- }
30
- export declare class DshSidecar {
31
- readonly baseUrl: string;
32
- private readonly child;
33
- private constructor();
34
- /** Test seam: a handle bound to an arbitrary base URL with no child
35
- * process (alive reports false; shutdown is a no-op). */
36
- static forTesting(baseUrl: string): DshSidecar;
37
- /**
38
- * POST to `${baseUrl}/api/<method>` wrapped in the required envelope
39
- * `{type: "client-request", rpcId, method, payload}` — verified live
40
- * (2026-08-23) that the server rejects unwrapped bodies with a
41
- * self-describing zod validation error naming exactly these four
42
- * fields as missing/wrong, for `session.prompt` specifically (an
43
- * earlier reading of the design doc's research assumed this endpoint
44
- * took an unwrapped body; that was wrong, corrected here against the
45
- * real server).
46
- */
47
- rpc(method: string, payload: unknown): Promise<unknown>;
48
- /** True while the sidecar's child process is still alive. */
49
- get alive(): boolean;
50
- shutdown(): void;
51
- static spawn(env: NodeJS.ProcessEnv): Promise<DshSidecar>;
52
- }
53
- /**
54
- * Lazily spawn (once) and return the shared `dsh web` sidecar for this
55
- * lmctl process. If a previously-spawned sidecar's process has died, spawns
56
- * a fresh one rather than returning a dead handle. A FAILED boot attempt
57
- * must not poison future calls either (F2): the rejected promise is dropped
58
- * from the cache so the next call retries with whatever environment it
59
- * brings, instead of rethrowing the stale boot error forever.
60
- *
61
- * `spawnFn` is a test seam — production callers always use the default.
62
- */
63
- export declare function ensureDshSidecar(env: NodeJS.ProcessEnv, spawnFn?: (env: NodeJS.ProcessEnv) => Promise<DshSidecar>): Promise<DshSidecar>;
64
- /** Test/shutdown seam — not used by normal adapter turns. */
65
- export declare function shutdownDshSidecar(): Promise<void>;
@@ -1,27 +0,0 @@
1
- /**
2
- * Concatenated-frame zstd decoding for dsh session files.
3
- *
4
- * dsh's `dsh-session-persistence-jsonl` appends to `session.jsonl.zstd`
5
- * in flush batches, producing MULTIPLE concatenated zstd frames in one
6
- * file (verified against real sessions: 12 frames in a 25 KB file, frame
7
- * descriptor 0x04 = windowed frames with a 4-byte content checksum).
8
- * Node's `zstdDecompressSync` / `createZstdDecompress` decode only the
9
- * FIRST frame and silently drop the rest — so the frames must be walked
10
- * and split manually before decoding.
11
- *
12
- * Frame layout (https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md):
13
- * magic (4) | frame header (variable) | blocks... | checksum (0|4)
14
- * Frame header:
15
- * descriptor (1) | window descriptor (0|1) | dict id (0|1|2|4) | content size (0|1|2|4|8)
16
- * Block header (3 bytes LE): bit0 = last, bits1-2 = type, bits3-23 = size.
17
- */
18
- /**
19
- * Split a buffer of concatenated zstd frames into per-frame slices.
20
- * Trailing non-frame garbage (a torn append) is dropped silently.
21
- */
22
- export declare function splitZstdFrames(buf: Buffer): Buffer[];
23
- /**
24
- * Decode a dsh `session.jsonl.zstd` buffer (one or more concatenated
25
- * zstd frames) to its full JSONL text.
26
- */
27
- export declare function decompressDshSessionFile(buf: Buffer): string;
@@ -1,37 +0,0 @@
1
- /**
2
- * DeepSeek Harness (`dsh`) session provider.
3
- *
4
- * Reads dsh's own on-disk session files directly (`~/.dsh/sessions/<mangled-
5
- * cwd>/session-<id>/session.jsonl.zstd`) — same read path whether the
6
- * session was created by the `headless` profile or the `web` sidecar this
7
- * provider's adapter drives (verified in `backlog/DESIGN-add-dsh-provider.md`:
8
- * both profiles share one session store).
9
- *
10
- * cwd mangling (verified live, 2026-08-23): the absolute cwd has its
11
- * leading/trailing slashes stripped, remaining `/` replaced with `-`, then
12
- * the whole thing wrapped in `--` on both ends — e.g. `/tmp/dsh-probe` ->
13
- * `--tmp-dsh-probe--`. Since a sessionId alone doesn't reveal which mangled
14
- * directory it lives under, lookups by id scan all of them.
15
- */
16
- import type { SessionDetail, SessionProvider, SessionSummary } from "./types.js";
17
- interface DshProviderOptions {
18
- dshHome?: string;
19
- }
20
- export declare class DshProvider implements SessionProvider {
21
- name: "dsh";
22
- private sessionsDir;
23
- constructor(opts?: DshProviderOptions);
24
- discoverSessions(): Promise<SessionSummary[]>;
25
- loadSession(sessionId: string): Promise<SessionDetail | null>;
26
- resolveSessionPath(sessionId: string): Promise<string | null>;
27
- deleteSession(sessionId: string): Promise<boolean>;
28
- /** Absolute path a fresh session for `cwd` will be written to, given a
29
- * caller-chosen `sessionId` — used by the adapter to poll for the
30
- * session file after `session.create` + `session.prompt`, without a
31
- * discovery scan (it already knows both inputs). */
32
- sessionFilePath(cwd: string, sessionId: string): string;
33
- private findSessionDir;
34
- private readRecords;
35
- private readSummary;
36
- }
37
- export {};
@@ -1,46 +0,0 @@
1
- /**
2
- * Legacy strict-subset YAML-style frontmatter for `.lmctl` files.
3
- *
4
- * Format (visually SKILL.md-like, parser hand-rolled — no js-yaml dep):
5
- *
6
- * ---
7
- * title: Frontend Team
8
- * description: Builds and maintains the frontend UI
9
- * members: Lead, Coder, Reviewer
10
- * ---
11
- * # Frontend Team
12
- * …body…
13
- *
14
- * Current `.lmctl` files do not require frontmatter. This parser is
15
- * still used for older files and custom templates that choose to carry
16
- * metadata. When a file does start with `---`, the block must list the
17
- * three required keys (`title`, `description`, `members`) and close
18
- * with `---` on its own line. Anything else — multi-line values, lists,
19
- * unknown keys — is a hard error.
20
- *
21
- * `members` is a comma-separated alias list; whitespace around each
22
- * is stripped, empty entries dropped (so `"a, , b"` parses as
23
- * `["a", "b"]`; `""` parses as `[]`).
24
- */
25
- export interface Frontmatter {
26
- title: string;
27
- description: string;
28
- /** Aliases as written, in source order. May be `[]` if the value
29
- * was empty. Caller decides if empty is a problem. */
30
- members: string[];
31
- /** Character offset in the original text where the body starts —
32
- * i.e., the character right after the closing `---` newline. Use
33
- * `text.slice(bodyOffset)` to get the post-frontmatter content. */
34
- bodyOffset: number;
35
- }
36
- export declare class FrontmatterError extends Error {
37
- constructor(message: string);
38
- }
39
- /**
40
- * Parse the strict-subset frontmatter block at the start of `text`.
41
- *
42
- * Throws `FrontmatterError` for any deviation: missing leading `---`,
43
- * missing closing `---`, malformed key/value line, unknown key, or
44
- * absent required key.
45
- */
46
- export declare function parseFrontmatter(text: string): Frontmatter;
@@ -1,151 +0,0 @@
1
- /**
2
- * Format-aware reader for Gemini session files.
3
- *
4
- * Gemini ships TWO on-disk formats and both must coexist indefinitely:
5
- *
6
- * ── Old format ─ `.json`, single pretty-printed document
7
- *
8
- * {
9
- * "sessionId": "<uuid>",
10
- * "projectHash": "<sha>",
11
- * "startTime": "...",
12
- * "lastUpdated": "...",
13
- * "messages": [
14
- * { "id": "...", "timestamp": "...", "type": "user|gemini",
15
- * "content": "...", "tokens": { ... } },
16
- * ...
17
- * ]
18
- * }
19
- *
20
- * `tokens.input` is per-call prompt usage; cached prompt tokens
21
- * are a subset carried in `tokens.cached`.
22
- *
23
- * ── New format ─ `.jsonl`, line-delimited
24
- *
25
- * Line 1 (metadata, no `messages`):
26
- * {"sessionId":"...","projectHash":"...","startTime":"...",
27
- * "lastUpdated":"...","kind":"main"}
28
- *
29
- * Subsequent lines are EITHER messages (same shape as old
30
- * `messages[]` entries, with `content` possibly an array of
31
- * `{text}` parts) OR `$set` patches that mutate metadata fields:
32
- *
33
- * {"id":"...","timestamp":"...","type":"user","content":[{"text":"..."}]}
34
- * {"$set":{"lastUpdated":"..."}}
35
- * {"id":"...","type":"gemini","tokens":{"input":N,...}}
36
- *
37
- * `$set` patches apply in order; last write wins. We reconstruct
38
- * the equivalent of the old document's top-level fields plus a
39
- * synthesized `messages[]` so downstream code stays unchanged.
40
- *
41
- * ── Detection (content-based, NOT extension-based) ─
42
- *
43
- * Try `JSON.parse(rawText)`. Success AND result has an array
44
- * `messages` field → old shape. Anything else (parse throws, OR
45
- * parsed object lacks `messages`) → JSONL. The extension is a
46
- * hint, not a decision; a renamed `.jsonl` containing a single
47
- * whole-doc JSON still parses as old, and a `.json`-named JSONL
48
- * still falls through to the line-by-line path.
49
- */
50
- /**
51
- * Result of `detectGeminiSessionFormat`. The third state — `"unknown"` —
52
- * is Round 11 correction: rather than silently classifying garbage as
53
- * one format and letting the parser fall over later, detection
54
- * surfaces it explicitly so callers can emit a structured warning
55
- * (`gemini_session_format_unknown`) and skip the file. Loud failure
56
- * on future format drift instead of silent disappearance from
57
- * `lmctl ls`.
58
- */
59
- export type GeminiSessionFormat = "json" | "jsonl" | "unknown";
60
- /** Common shape returned by the parser regardless of source format.
61
- * Mirrors the old document's top-level fields plus an optional
62
- * `kind` (new-format marker). */
63
- export interface ParsedGeminiSession {
64
- sessionId?: string;
65
- projectHash?: string;
66
- startTime?: string;
67
- lastUpdated?: string;
68
- /** "main" | "compact" on JSONL files; absent on old JSON files. */
69
- kind?: string;
70
- messages: ParsedGeminiMessage[];
71
- }
72
- /** Loose message shape covering both formats — `tokens` and
73
- * `thoughts` are the audit-relevant fields; `content` is the
74
- * display-relevant one and may be a string or an array of parts. */
75
- export interface ParsedGeminiMessage {
76
- id?: string;
77
- timestamp?: string;
78
- type?: string;
79
- content?: string | Array<{
80
- text?: string;
81
- }>;
82
- thoughts?: Array<{
83
- subject?: string;
84
- description?: string;
85
- timestamp?: string;
86
- }>;
87
- model?: string;
88
- tokens?: {
89
- input?: number;
90
- output?: number;
91
- cached?: number;
92
- thoughts?: number;
93
- tool?: number;
94
- total?: number;
95
- };
96
- }
97
- /**
98
- * Detect the on-disk format of a Gemini session purely from its raw
99
- * text content. Does NOT touch the filesystem and does NOT consult
100
- * the file's extension.
101
- *
102
- * Detection order — JSONL FIRST (Round 11 correction):
103
- *
104
- * 1. JSONL fast path: file has multiple non-blank lines AND line
105
- * 1 parses as a JSON object with a `kind` field (the de-facto
106
- * version marker for the new format). This is cheaper than a
107
- * whole-file parse on large old-format documents and matches
108
- * the format users will increasingly see going forward.
109
- * 2. Whole-file JSON parse: if the file parses as a single object,
110
- * classify by content — `messages` array means old format;
111
- * a `kind` field (no messages yet) means a fresh JSONL session
112
- * that's just one metadata line so far.
113
- * 3. Anything else → `"unknown"`.
114
- *
115
- * Empty / blank input also returns `"unknown"` — callers emit the
116
- * `gemini_session_format_unknown` warning and skip the file. Throwing
117
- * here would force every caller to wrap in try/catch and risks the
118
- * "silently dropped session" failure mode this round was opened to fix.
119
- */
120
- export declare function detectGeminiSessionFormat(raw: string): GeminiSessionFormat;
121
- /**
122
- * Parse a Gemini session file's raw text into a uniform shape.
123
- * Detects format via `detectGeminiSessionFormat`; old documents are
124
- * returned as-is, new JSONL is replayed line-by-line into the
125
- * equivalent old shape (metadata + synthesized `messages[]`).
126
- *
127
- * Throws when format is unknown (empty, malformed, or matching
128
- * neither known shape). Callers — production code paths that read
129
- * sessions — should detect with `detectGeminiSessionFormat` FIRST
130
- * and emit a `gemini_session_format_unknown` warning before letting
131
- * this function throw, so users see "which file was skipped, why"
132
- * in the debug log.
133
- *
134
- * Individual subsequent JSONL lines that fail to parse (after the
135
- * metadata line) are skipped silently — partial corruption shouldn't
136
- * take out the rest of the session.
137
- */
138
- export declare function parseGeminiSessionContent(raw: string): ParsedGeminiSession;
139
- /**
140
- * Serialize a ParsedGeminiSession back to disk text in the requested
141
- * format. Used by the fork path to preserve the source file's format
142
- * (forking a `.jsonl` produces a `.jsonl`; forking a `.json` produces
143
- * a `.json`).
144
- *
145
- * For JSONL output we DO NOT emit `$set` patches — those are append-
146
- * only history that gemini writes incrementally; a fresh fork has
147
- * already merged everything into its top-level metadata, so the
148
- * minimal valid JSONL (metadata line + message lines) round-trips
149
- * cleanly through gemini's own loader.
150
- */
151
- export declare function serializeGeminiSession(session: ParsedGeminiSession, format: GeminiSessionFormat): string;
@@ -1,39 +0,0 @@
1
- import type { SessionDetail, SessionProvider, SessionSummary } from "./types.js";
2
- interface GeminiProviderOptions {
3
- geminiDir?: string;
4
- claudeDir?: string;
5
- codexDirs?: string[];
6
- codexDir?: string;
7
- codeDir?: string;
8
- extraWorkspacePaths?: string[];
9
- }
10
- export declare class GeminiProvider implements SessionProvider {
11
- name: "gemini";
12
- private workspaceHashMap?;
13
- private geminiProjectsFile;
14
- private geminiTmpDir;
15
- private claudeProjectsDir;
16
- private codexSessionDirs;
17
- private extraWorkspacePaths;
18
- constructor(options?: GeminiProviderOptions);
19
- getWatchPaths(): {
20
- directory: string;
21
- filePattern: RegExp;
22
- }[];
23
- discoverSessions(): Promise<SessionSummary[]>;
24
- loadSession(sessionId: string): Promise<SessionDetail | null>;
25
- private extractSummary;
26
- private readSessionFile;
27
- private extractSessionIdFromFilename;
28
- private findSessionFiles;
29
- resolveSessionPath(sessionId: string): Promise<string | null>;
30
- deleteSession(sessionId: string): Promise<boolean>;
31
- private resolveSessionFile;
32
- private resolveWorkspace;
33
- private getWorkspaceHashMap;
34
- private collectGeminiProjectPaths;
35
- private collectCodexCwds;
36
- private collectClaudeCwds;
37
- private findJsonlFiles;
38
- }
39
- export {};