@lmctl-ai/lmctl 0.1.342 → 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.
Files changed (182) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +11 -51
  3. package/data/price-aliases.json +1 -0
  4. package/data/price-data.json +1 -1
  5. package/dist/cli/batch.d.ts +2 -0
  6. package/dist/cli/busy-evidence.d.ts +27 -0
  7. package/dist/cli/chat-cycle.d.ts +59 -0
  8. package/dist/cli/chat-exec.d.ts +83 -0
  9. package/dist/cli/chat-policy.d.ts +22 -0
  10. package/dist/cli/chat.d.ts +23 -0
  11. package/dist/cli/code-resolver.d.ts +8 -0
  12. package/dist/cli/common.d.ts +54 -0
  13. package/dist/cli/context.d.ts +12 -0
  14. package/dist/cli/cost.d.ts +2 -0
  15. package/dist/cli/export.d.ts +2 -0
  16. package/dist/cli/index.d.ts +3 -0
  17. package/dist/cli/index.js +1062 -1400
  18. package/dist/cli/infra.d.ts +78 -0
  19. package/dist/cli/ls.d.ts +2 -0
  20. package/dist/cli/mailbox-cli.d.ts +6 -0
  21. package/dist/cli/managed.d.ts +62 -0
  22. package/dist/cli/mcp-install.d.ts +23 -0
  23. package/dist/cli/mcp.d.ts +2 -0
  24. package/dist/cli/paths.d.ts +50 -0
  25. package/dist/cli/plan-wizard.d.ts +42 -0
  26. package/dist/cli/plan.d.ts +20 -0
  27. package/dist/cli/queue-delivery.d.ts +107 -0
  28. package/dist/cli/ratelimit.d.ts +3 -0
  29. package/dist/cli/remote-fetch.d.ts +7 -0
  30. package/dist/cli/run-queries.d.ts +82 -0
  31. package/dist/cli/running.d.ts +5 -0
  32. package/dist/cli/schema.sql +20 -1
  33. package/dist/cli/script.d.ts +6 -0
  34. package/dist/cli/script.js +2097 -0
  35. package/dist/cli/self-identity.d.ts +25 -0
  36. package/dist/cli/session-idle.d.ts +118 -0
  37. package/dist/cli/status.d.ts +22 -0
  38. package/dist/cli/tail.d.ts +18 -0
  39. package/dist/cli/target-resolver.d.ts +139 -0
  40. package/dist/cli/team-status.d.ts +91 -0
  41. package/dist/cli/teamfile-compat.d.ts +71 -0
  42. package/dist/cli/teamfile-store.d.ts +18 -0
  43. package/dist/cli/teamfile-template.d.ts +40 -0
  44. package/dist/cli/template-env.d.ts +25 -0
  45. package/dist/cli/terminal-lock.d.ts +25 -0
  46. package/dist/cli/terminal.d.ts +23 -0
  47. package/dist/cli/time-filter.d.ts +10 -0
  48. package/dist/cli/update-notifier.d.ts +11 -0
  49. package/dist/cli/version-util.d.ts +2 -0
  50. package/dist/config/seed_templates.d.ts +1 -0
  51. package/dist/db/backfill-event-log.d.ts +26 -0
  52. package/dist/db/delegation.d.ts +37 -0
  53. package/dist/db/escalation_vocab.d.ts +45 -0
  54. package/dist/db/event-log.d.ts +40 -0
  55. package/dist/db/index.d.ts +1213 -0
  56. package/dist/db/inflight-acquire.d.ts +70 -0
  57. package/dist/db/invocation-event-projections.d.ts +65 -0
  58. package/dist/db/ledger-identity.test.d.ts +1 -0
  59. package/dist/db/live-event-projections.d.ts +92 -0
  60. package/dist/db/migrate.d.ts +51 -0
  61. package/dist/db/open-readonly.d.ts +2 -0
  62. package/dist/db/process-liveness.d.ts +37 -0
  63. package/dist/db/sqlite.d.ts +47 -0
  64. package/dist/db/sqlite.test.d.ts +1 -0
  65. package/dist/db/terminal-lock.d.ts +14 -0
  66. package/dist/db/tracked-invocation-reconcile.d.ts +52 -0
  67. package/dist/db/tracked-invocation.d.ts +116 -0
  68. package/dist/mcp/dispatch.d.ts +45 -0
  69. package/dist/mcp/mediation.d.ts +128 -0
  70. package/dist/mcp/path-warning.d.ts +7 -0
  71. package/dist/mcp/server.d.ts +63 -0
  72. package/dist/mcp/tools.d.ts +24 -0
  73. package/dist/providers/adapter.d.ts +265 -0
  74. package/dist/providers/adapters/agy-adapter.d.ts +17 -0
  75. package/dist/providers/adapters/claude-adapter.d.ts +20 -0
  76. package/dist/providers/adapters/codex-adapter.d.ts +22 -0
  77. package/dist/providers/adapters/copilot-adapter.d.ts +16 -0
  78. package/dist/providers/adapters/dsh-adapter.d.ts +89 -0
  79. package/dist/providers/adapters/gemini-adapter.d.ts +44 -0
  80. package/dist/providers/adapters/hermes-adapter.d.ts +71 -0
  81. package/dist/providers/adapters/index.d.ts +35 -0
  82. package/dist/providers/adapters/kimi-adapter.d.ts +16 -0
  83. package/dist/providers/adapters/lmplayer-adapter.d.ts +14 -0
  84. package/dist/providers/adapters/opencode-adapter.d.ts +11 -0
  85. package/dist/providers/adapters/pi-adapter.d.ts +17 -0
  86. package/dist/providers/adapters/print-turn.d.ts +29 -0
  87. package/dist/providers/adapters/qwen-adapter.d.ts +11 -0
  88. package/dist/providers/agy.d.ts +32 -0
  89. package/dist/providers/base-adapter.d.ts +107 -0
  90. package/dist/providers/base.d.ts +12 -0
  91. package/dist/providers/binary-check.d.ts +102 -0
  92. package/dist/providers/bundle.d.ts +118 -0
  93. package/dist/providers/claude-mock.d.ts +90 -0
  94. package/dist/providers/claude.d.ts +21 -0
  95. package/dist/providers/codex-config.d.ts +15 -0
  96. package/dist/providers/codex.d.ts +25 -0
  97. package/dist/providers/config/model-selection-lint.d.ts +45 -0
  98. package/dist/providers/config/team-config.d.ts +183 -0
  99. package/dist/providers/config/types.d.ts +146 -0
  100. package/dist/providers/config/user-config.d.ts +88 -0
  101. package/dist/providers/copilot.d.ts +21 -0
  102. package/dist/providers/debug.d.ts +128 -0
  103. package/dist/providers/dsh-sidecar.d.ts +65 -0
  104. package/dist/providers/dsh-zstd.d.ts +27 -0
  105. package/dist/providers/dsh.d.ts +37 -0
  106. package/dist/providers/frontmatter.d.ts +46 -0
  107. package/dist/providers/gemini-session-reader.d.ts +151 -0
  108. package/dist/providers/gemini.d.ts +39 -0
  109. package/dist/providers/hermes.d.ts +90 -0
  110. package/dist/providers/index.d.ts +421 -0
  111. package/dist/providers/kimi.d.ts +37 -0
  112. package/dist/providers/model-catalog.d.ts +141 -0
  113. package/dist/providers/one-shot-timeout.d.ts +1 -0
  114. package/dist/providers/opencode-config.d.ts +62 -0
  115. package/dist/providers/opencode.d.ts +40 -0
  116. package/dist/providers/parsers/acp.d.ts +47 -0
  117. package/dist/providers/parsers/codex-app-server.d.ts +60 -0
  118. package/dist/providers/parsers/stream-json.d.ts +57 -0
  119. package/dist/providers/passive-readers/agy.d.ts +155 -0
  120. package/dist/providers/passive-readers/copilot.d.ts +173 -0
  121. package/dist/providers/passive-readers/dsh.d.ts +34 -0
  122. package/dist/providers/passive-readers/kimi.d.ts +44 -0
  123. package/dist/providers/passive-readers/opencode.d.ts +89 -0
  124. package/dist/providers/passive-readers/qwen.d.ts +151 -0
  125. package/dist/providers/passive-readers/shared.d.ts +138 -0
  126. package/dist/providers/passive-session-reader.d.ts +188 -0
  127. package/dist/providers/path-utils.d.ts +1 -0
  128. package/dist/providers/pi.d.ts +32 -0
  129. package/dist/providers/pricing.d.ts +107 -0
  130. package/dist/providers/qwen.d.ts +22 -0
  131. package/dist/providers/ratelimit-readings.d.ts +32 -0
  132. package/dist/providers/registry.d.ts +31 -0
  133. package/dist/providers/resume.d.ts +43 -0
  134. package/dist/providers/seed-instruction.d.ts +3 -0
  135. package/dist/providers/self-session-env.d.ts +21 -0
  136. package/dist/providers/session-limit.d.ts +9 -0
  137. package/dist/providers/strip-ansi.d.ts +5 -0
  138. package/dist/providers/transport-errors.d.ts +94 -0
  139. package/dist/providers/transport-lifecycle.d.ts +63 -0
  140. package/dist/providers/transport-wrappers.d.ts +110 -0
  141. package/dist/providers/transports/acp-profiles/config-option-step.d.ts +24 -0
  142. package/dist/providers/transports/acp-profiles/copilot.d.ts +12 -0
  143. package/dist/providers/transports/acp-profiles/gemini.d.ts +22 -0
  144. package/dist/providers/transports/acp-profiles/hermes.d.ts +27 -0
  145. package/dist/providers/transports/acp-profiles/index.d.ts +19 -0
  146. package/dist/providers/transports/acp-profiles/kimi.d.ts +24 -0
  147. package/dist/providers/transports/acp-profiles/opencode.d.ts +26 -0
  148. package/dist/providers/transports/acp-profiles/types.d.ts +258 -0
  149. package/dist/providers/transports/acp-rpc.d.ts +18 -0
  150. package/dist/providers/transports/acp.d.ts +215 -0
  151. package/dist/providers/transports/codex-app-server.d.ts +190 -0
  152. package/dist/providers/transports/hold-open.d.ts +120 -0
  153. package/dist/providers/transports/manager.d.ts +21 -0
  154. package/dist/providers/transports/stream-json.d.ts +162 -0
  155. package/dist/providers/transports/types.d.ts +56 -0
  156. package/dist/providers/types.d.ts +154 -0
  157. package/dist/providers/yolo-contract.d.ts +131 -0
  158. package/dist/script/adapter.d.ts +101 -0
  159. package/dist/script/batch-script.d.ts +7 -0
  160. package/dist/script/index.d.ts +3 -0
  161. package/dist/script/lmscript.d.ts +550 -0
  162. package/dist/shared/policy.d.ts +74 -0
  163. package/dist/shared-lib/db.d.ts +25 -0
  164. package/dist/shared-lib/passive-session-reader.d.ts +2 -0
  165. package/dist/shared-lib/provider-parse.d.ts +6 -0
  166. package/dist/templates/basedir.d.ts +52 -0
  167. package/dist/uri/lmctl_uri.d.ts +38 -0
  168. package/durable-memory/model_selection.md +108 -25
  169. package/examples/README.md +103 -0
  170. package/examples/anonymous-panel.lms +3 -0
  171. package/examples/batch-prompts.txt +9 -0
  172. package/examples/batchscript.lms +67 -0
  173. package/examples/n8n/agent-lib.lms +56 -0
  174. package/examples/n8n/git-lib.lms +93 -0
  175. package/examples/n8n/mock-support.db +0 -0
  176. package/examples/n8n/multi-agent-review.lms +107 -0
  177. package/examples/n8n/news-digest.lms +159 -0
  178. package/examples/n8n/rag-search.lms +163 -0
  179. package/examples/n8n/support-agent.lms +88 -0
  180. package/examples/n8n/ticket-triage.lms +156 -0
  181. package/package.json +13 -17
  182. package/dist/cli/side_effect_classifier.json +0 -19
@@ -0,0 +1,2 @@
1
+ import { type CliIo } from './common.js';
2
+ export declare function runBatch(args: string[], io?: CliIo): Promise<number>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared "who holds this, and are they alive / how long" evidence for busy/held
3
+ * errors — the same instinct as the #80 terminal busy/held-evidence, factored
4
+ * out so the chat busy-now path and terminal.ts do not each re-derive the
5
+ * live/dead verdict.
6
+ */
7
+ export type HolderLiveness = 'live' | 'dead' | null;
8
+ export interface BusyHolderEvidence {
9
+ holder_pid: number | null;
10
+ holder_liveness: HolderLiveness;
11
+ /** ISO timestamp the current turn/hold started. */
12
+ since: string;
13
+ /** Wall-clock ms since `since` (time the target has been active) — the
14
+ * "time-since-last-activity" evidence; null when `since` is unparseable. */
15
+ idle_ms: number | null;
16
+ }
17
+ /** live/dead/null verdict for a holder pid — null means "no pid recorded". */
18
+ export declare function holderLiveness(holderPid: number | null): HolderLiveness;
19
+ export declare function busyHolderEvidence(input: {
20
+ holderPid: number | null;
21
+ since: string;
22
+ nowMs?: number;
23
+ }): BusyHolderEvidence;
24
+ /** Human duration via lmformat, e.g. "0s", "45s", "3m 12s", "2h 5m". */
25
+ export declare function formatElapsed(ms: number): string;
26
+ /** Parenthesised evidence suffix: `(active 3m 12s; holder_pid=123, live)`. */
27
+ export declare function formatBusyEvidence(ev: BusyHolderEvidence): string;
@@ -0,0 +1,59 @@
1
+ import type { Dal } from '../db/index.js';
2
+ export declare const CYCLE_FRESH_WINDOW_MS = 60000;
3
+ /**
4
+ * How many cross-team hops must be SIMULTANEOUSLY IN FLIGHT before a revisit is
5
+ * treated as a runaway loop rather than a normal exchange.
6
+ *
7
+ * WHY THIS IS A HOP COUNT AND NOT A COUNT OF REVISITS. The obvious reading of
8
+ * the name is "how many times has this target already appeared in the chain",
9
+ * but that number can never exceed 1: `ancestorChain` walks parent pointers and
10
+ * breaks on the first node it has already seen, so the chain it returns is
11
+ * DEDUPLICATED. Gating on `priorTargetEntries.length >= 2` would therefore be
12
+ * dead code that disables cycle detection entirely.
13
+ *
14
+ * Counting repeats over time does not work either: `releaseAgentInflight`
15
+ * deletes the row when an exchange completes, so a finished hop leaves no trace
16
+ * here, and the lease forbids two concurrent holds of the same lane. The live
17
+ * table only ever shows what is in flight RIGHT NOW.
18
+ *
19
+ * What that table can tell us is how deep the live cross-team call stack is,
20
+ * and that is the signal that actually separates the two cases:
21
+ *
22
+ * 1 hop — A is holding B, and B messages A back. One outstanding call: a
23
+ * reply, an acknowledgement, a bounded handshake. NOT a loop. This
24
+ * is the case that was being blocked (`lmmol → diagramkit → lmmol`,
25
+ * a 3-node chain), stalling a real cross-team review.
26
+ * 2 hops — A is holding B AND B is holding A, and another cross-team call is
27
+ * being opened on top. Both parties are now blocked inside each
28
+ * other; nothing can unwind. That is a live deadlock, and it is what
29
+ * this mechanism exists to stop.
30
+ *
31
+ * So: one outstanding hop is allowed, two or more is refused. Raising this
32
+ * further would let genuinely stuck stacks keep growing, which is the failure
33
+ * mode the whole check is here to prevent.
34
+ */
35
+ export declare const CYCLE_MAX_REVISITS = 2;
36
+ export interface ChatCycleNode {
37
+ teamfile: string;
38
+ alias: string;
39
+ }
40
+ export interface DetectCrossTeamCycleInput {
41
+ root: string;
42
+ sender: ChatCycleNode;
43
+ receiverTeamfile: string;
44
+ receiverAlias: string;
45
+ now: Date;
46
+ }
47
+ export interface DetectCrossTeamCycleResult {
48
+ stop: boolean;
49
+ chain: string;
50
+ }
51
+ type ChatCycleDal = Pick<Dal, 'listAgentInflight' | 'clearAgentInflightOlderThan'>;
52
+ export declare function detectCrossTeamCycle(dal: ChatCycleDal, input: DetectCrossTeamCycleInput): DetectCrossTeamCycleResult;
53
+ export declare function deriveRootFromLiveInflight(dal: ChatCycleDal, input: {
54
+ sender: ChatCycleNode;
55
+ now: Date;
56
+ }): string | null;
57
+ export declare function agentInflightTtlMsFromEnv(env?: NodeJS.ProcessEnv): number;
58
+ export declare function crossTeamCycleMessage(chain: string): string;
59
+ export {};
@@ -0,0 +1,83 @@
1
+ import type { ProgressEvent } from '../providers/index.js';
2
+ import type { BundleSession } from '../providers/bundle.js';
3
+ import type { PermissionMode } from '../providers/yolo-contract.js';
4
+ import type { AgentInflightInput } from '../db/index.js';
5
+ import { type CliIo } from './common.js';
6
+ export type AiTeamChatEvent = {
7
+ kind: 'delta';
8
+ chunk: string;
9
+ } | {
10
+ kind: 'progress';
11
+ alias: string;
12
+ event: ProgressEvent;
13
+ } | {
14
+ kind: 'warning';
15
+ message: string;
16
+ };
17
+ export type AiTeamChatResult = {
18
+ status: 'ok';
19
+ replyText: string;
20
+ wroteDelta: boolean;
21
+ teamChatLogId: number | null;
22
+ messageId: string | null;
23
+ durationMs?: number;
24
+ } | {
25
+ status: 'stalled';
26
+ replyText: string;
27
+ wroteDelta: boolean;
28
+ teamChatLogId: number | null;
29
+ messageId: string | null;
30
+ durationMs?: number;
31
+ } | {
32
+ status: 'busy';
33
+ message: string;
34
+ teamChatLogId: number | null;
35
+ } | {
36
+ status: 'error';
37
+ errorKind: 'cycle' | 'provider' | 'target';
38
+ message: string;
39
+ teamChatLogId: number | null;
40
+ messageId: string | null;
41
+ };
42
+ export interface ExecuteAiTeamChatTurnInput {
43
+ teamfile: string;
44
+ alias: string;
45
+ prompt: string;
46
+ /** Refuse to dispatch if a multi-turn caller's target session changed. */
47
+ expectedSession?: {
48
+ provider: string;
49
+ sessionid: string;
50
+ };
51
+ permissionMode: PermissionMode;
52
+ idleTimeoutMs?: number;
53
+ rootFlag?: string;
54
+ env?: NodeJS.ProcessEnv;
55
+ /** v61: per-message framing for the team_chat_log row — 'batch' when this
56
+ * turn is one prompt of a `lmctl batch` run; omitted (NULL) otherwise. */
57
+ messageType?: 'batch';
58
+ /**
59
+ * Caller-held in-flight lease (batch bundle mode): the caller
60
+ * acquired the `agent_inflight` lease once for the whole bundle, so this
61
+ * turn skips the receiver busy check AND the acquire/release/heartbeat —
62
+ * they all moved to bundle scope. Instead the turn VERIFIES per prompt
63
+ * that the caller still holds the lease, matched by lease identity AND
64
+ * holder pid (the heartbeat call doubles as a lease-CAS touch); a lost
65
+ * lease fails the turn, aborting the bundle instead of dispatching
66
+ * unsynchronized. The per-turn chat pointer, tracked_invocation, and
67
+ * team_chat_log row are unaffected.
68
+ */
69
+ heldLease?: {
70
+ row: AgentInflightInput;
71
+ leaseId: string;
72
+ };
73
+ /**
74
+ * Caller-held bundle provider session (batch bundle mode): the turn
75
+ * goes through the already-open provider process. See
76
+ * src/providers/bundle.ts for the lifecycle contract.
77
+ */
78
+ bundleSession?: BundleSession;
79
+ io: CliIo;
80
+ onEvent?: (event: AiTeamChatEvent) => void;
81
+ onAccepted?: (messageId: string) => void;
82
+ }
83
+ export declare function executeAiTeamChatTurn(input: ExecuteAiTeamChatTurnInput): Promise<AiTeamChatResult>;
@@ -0,0 +1,22 @@
1
+ export interface ChatPolicyTeam {
2
+ teamfile: string;
3
+ aliases: readonly string[];
4
+ leadAlias: string | null;
5
+ }
6
+ export interface ChatPolicyRegistry {
7
+ teams: readonly ChatPolicyTeam[];
8
+ }
9
+ export interface CanSendInput {
10
+ rootTeamfile: string;
11
+ fromTeamfile: string;
12
+ fromAlias: string;
13
+ toTeamfile: string;
14
+ toAlias: string;
15
+ registry: ChatPolicyRegistry;
16
+ }
17
+ export interface CanSendResult {
18
+ allowed: boolean;
19
+ reason: string;
20
+ outOfPolicy: boolean;
21
+ }
22
+ export declare function canSend(input: CanSendInput): CanSendResult;
@@ -0,0 +1,23 @@
1
+ import { type CliIo } from './common.js';
2
+ export declare function runChat(args: string[], io?: CliIo): Promise<number>;
3
+ /**
4
+ * Resolve `--prompt-file` to the prompt text. Reads the file (or stdin for
5
+ * `-`) as UTF-8 and returns it byte-for-byte EXCEPT for exactly one trailing
6
+ * newline, which is stripped so `--prompt-file f` matches what the author sees
7
+ * in the editor (files conventionally end with a newline). A CRLF terminator
8
+ * counts as that one newline.
9
+ *
10
+ * No shell is involved at any point, which is the entire purpose.
11
+ */
12
+ export declare function resolvePromptInput(promptFile: string, io: CliIo, stdin?: NodeJS.ReadableStream): Promise<string | {
13
+ error: string;
14
+ }>;
15
+ /**
16
+ * Parse `--idle-timeout <duration>` per lmctl0 grammar: `<n>(s|m|h|d)`,
17
+ * a bare integer >= 1000 (raw milliseconds), or `0` (disables the timer —
18
+ * libraryChat semantics). A bare integer under 1000 is refused (see inline
19
+ * comment) rather than silently treated as milliseconds — always give an
20
+ * explicit unit for anything meant as seconds. Returns ms (number), or an
21
+ * error string the caller surfaces verbatim. Pure.
22
+ */
23
+ export declare function parseIdleTimeoutMs(value: string): number | string;
@@ -0,0 +1,8 @@
1
+ import type { Dal, ProjectRow, TeamMemberRow, TeamRow } from '../db/index.js';
2
+ import { type CliIo } from './common.js';
3
+ export interface ProjectResolvingIo extends CliIo {
4
+ cwd?: string;
5
+ }
6
+ export declare function resolveProject(io: ProjectResolvingIo, dal: Dal, override?: string): ProjectRow | number;
7
+ export declare function resolveTeam(io: ProjectResolvingIo, dal: Dal, project: ProjectRow, override?: string): TeamRow | number;
8
+ export declare function resolveAlias(io: ProjectResolvingIo, dal: Dal, team: TeamRow, override?: string): TeamMemberRow | number;
@@ -0,0 +1,54 @@
1
+ import { type Dal } from '../db/index.js';
2
+ export interface CliWriter {
3
+ write(chunk: string): unknown;
4
+ }
5
+ export interface CliReader {
6
+ isTTY?: boolean;
7
+ setEncoding?(encoding: BufferEncoding): unknown;
8
+ resume?(): unknown;
9
+ pause?(): unknown;
10
+ once(event: 'data', listener: (chunk: string | Buffer) => void): unknown;
11
+ }
12
+ export interface CliIo {
13
+ stdout: CliWriter;
14
+ stderr: CliWriter;
15
+ stdin?: CliReader;
16
+ dal?: Dal;
17
+ cwd?: string;
18
+ env?: NodeJS.ProcessEnv;
19
+ }
20
+ export interface ParsedFlags {
21
+ positionals: string[];
22
+ flags: Record<string, string | boolean>;
23
+ error?: string;
24
+ }
25
+ export declare function withDal<T>(io: CliIo, fn: (dal: Dal) => Promise<T> | T): Promise<T>;
26
+ export declare function parseFlags(args: string[], valueFlags: string[], boolFlags?: string[]): ParsedFlags;
27
+ export declare function flagString(parsed: ParsedFlags, name: string): string | undefined;
28
+ export declare function flagBool(parsed: ParsedFlags, name: string): boolean;
29
+ export declare function writeJson(io: CliIo, value: unknown): void;
30
+ export declare function userError(io: CliIo, message: string): number;
31
+ /** Local wall-clock `HH:MM:SS` for progress-narration lines (batch, and any
32
+ * command whose stderr narration benefits from a when-did-this-happen marker
33
+ * without a full date). */
34
+ export declare function hhmmss(): string;
35
+ /** Silence-aware heartbeat for waits that can run long (provider seed spawn,
36
+ * a multi-minute chat turn, a batch prompt). Writes `renderLine(elapsedSeconds)`
37
+ * to stderr every `intervalMs`, but SKIPS the tick when `poke()` was called
38
+ * within the last interval -- streaming events already tell the user work is
39
+ * happening, so only true silence earns a "still running" line. The timer is
40
+ * unref'd; callers must `stop()` in a finally. */
41
+ export declare function startSilenceHeartbeat(io: CliIo, renderLine: (elapsedSeconds: number) => string, intervalMs?: number): {
42
+ poke: () => void;
43
+ stop: () => void;
44
+ };
45
+ export declare function internalError(io: CliIo, error: unknown): number;
46
+ /** Reads the LMCTL_INVOCATION_ID env var a parent turn's own dispatch set on
47
+ * this process -- the dispatch-lineage edge `lmctl running --tree` walks.
48
+ * Malformed/absent -> null (this dispatch is a root, e.g. a human's direct
49
+ * `lmctl prompt`/`lmctl terminal`). Shared by chat-exec.ts and terminal.ts,
50
+ * the two places a tracked_invocation row gets created. */
51
+ export declare function parseInvocationIdEnv(value: string | undefined): number | null;
52
+ export declare function installStdoutEpipeGuard(io: CliIo): void;
53
+ /** Test-only: reset the once-flag so install behaviour can be asserted. */
54
+ export declare function _resetStdoutEpipeGuardForTests(): void;
@@ -0,0 +1,12 @@
1
+ import type { Dal, ProjectRow } from '../db/index.js';
2
+ /**
3
+ * Walk from `cwd` (and each ancestor up to the filesystem root) looking
4
+ * for a project whose `local_path` is that exact path. Returns the first
5
+ * hit, or `null` when none match.
6
+ *
7
+ * Path comparison is exact-string after `resolve()` normalization on
8
+ * both the query path and the DB value. On Linux + WSL2 (per § 12 of the
9
+ * design decisions) we don't normalize case or separators beyond what
10
+ * `node:path` provides.
11
+ */
12
+ export declare function resolveActiveProject(cwd: string, dal: Dal): ProjectRow | null;
@@ -0,0 +1,2 @@
1
+ import { type CliIo } from './common.js';
2
+ export declare function runCost(args: string[], io?: CliIo): Promise<number>;
@@ -0,0 +1,2 @@
1
+ import { type CliIo } from './common.js';
2
+ export declare function runExport(args: string[], io?: CliIo): Promise<number>;
@@ -0,0 +1,3 @@
1
+ import type { CliIo } from './common.js';
2
+ export declare const COMMANDS: Set<string>;
3
+ export declare function runCli(args: string[], io?: CliIo): Promise<number>;