@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,118 +0,0 @@
1
- /**
2
- * Session-idle availability override for delivery decisions.
3
- *
4
- * Operator (2026-07-22): *"also check the last update of session (from
5
- * sessionid), if it is been idle for 10 minute, then it is available (this
6
- * does not change terminal pid)."*
7
- *
8
- * THRESHOLD: 60 minutes, NOT the 10 initially requested. Do not "fix" this
9
- * back to 10 without re-running the numbers below.
10
- *
11
- * A misfire is not benign: the reclaim force-steals a lease from a LIVE holder
12
- * and starts a second turn on the same sessionid — the concurrent-resume abort
13
- * `b85c5a1` exists to prevent. So the threshold has to clear real turn
14
- * durations. Measured over completed chat turns, SPLIT BY OUTCOME — the split
15
- * is the whole point, an unsplit number is misleading in both directions:
16
- *
17
- * SELECT status, COUNT(*), SUM(CASE WHEN m>60 THEN 1 END), MAX(m)
18
- * FROM (SELECT status, (julianday(ended_at)-julianday(started_at))*1440 AS m
19
- * FROM tracked_invocation WHERE ended_at IS NOT NULL AND kind='chat')
20
- * GROUP BY status;
21
- *
22
- * status='done' n=2056 >60min: 0 longest: 51.8 min
23
- * status='error' n=1054 >60min: 191 longest: 2709 min (~45h)
24
- * status='busy' n=727 >60min: 0
25
- *
26
- * NO SUCCESSFULLY-COMPLETED CHAT TURN HAS EVER EXCEEDED 60 MINUTES. The longest
27
- * was 51.8 min, so 60min sits ~16% above the worst observed healthy turn. Every
28
- * one of the 191 turns past 60min ended in `error` — hung, aborted, abandoned:
29
- * exactly the population this feature exists to reclaim.
30
- *
31
- * Beware the unsplit figure: "5.0% of all turns exceed 60min" is arithmetically
32
- * true and materially misleading, because it counts already-failed turns as if
33
- * they were healthy ones at risk of a wrongful steal. Exposure among healthy
34
- * turns is zero in the observed record. (Turn DURATION is also only an upper
35
- * bound — the trigger needs a >60min GAP BETWEEN WRITES, and a turn making tool
36
- * calls keeps `modifiedAt` fresh.) 60min also still beats the 8h inflight TTL
37
- * by ~8x, which is the actual complaint being solved.
38
- *
39
- * Re-run the query rather than trusting these figures; if you retune, split by
40
- * status or the number will mislead you.
41
- * See `backlog/DESIGN-session-idle-availability-scope.md`.
42
- *
43
- * THE PROBLEM. An `in-flight` lease taken by `lmctl prompt`/relay delivery keeps
44
- * a receiver unreachable until the holder releases it or the 8h TTL expires.
45
- * A hung turn therefore blocks that receiver for hours. Holder-pid liveness
46
- * alone cannot detect this: the process is alive, it is just not progressing.
47
- *
48
- * THE SIGNAL. `SessionDetail.modifiedAt` — the provider's own session file
49
- * mtime, i.e. real conversation activity. Deliberately NOT the chat/terminal
50
- * heartbeat (`tracked_invocation.last_heartbeat_at`), which a timer in the
51
- * holder process refreshes every 30s whether the turn is working OR wedged.
52
- * The heartbeat distinguishes process-alive (already covered by the pid
53
- * check), not stuck-vs-working, so it cannot detect a hung turn at all.
54
- *
55
- * FAILS CLOSED, ALWAYS. Every failure path returns `false` = "not idle, keep
56
- * treating as busy". A false "available" lets two deliveries resume the same
57
- * held session and collide; a false "busy" only means the message waits
58
- * longer. Those costs are not symmetric, so the ambiguous cases (session not
59
- * found, ambiguous provider, read error, unresolvable member) all resolve to
60
- * busy. Same lesson as the reboot/pid-reuse work: never fail open on a
61
- * liveness question.
62
- *
63
- * SCOPE. This is an ADDITIVE override consulted only at the synchronous
64
- * chat delivery decision point (`chat-exec`) and only for the `in-flight`
65
- * busy reason. `terminal-held` is NEVER overridden at any idle duration — see
66
- * `isInflightButSessionIdle` below for why. It does not touch
67
- * `getReceiverBusyState`, the terminal lock, or any pid.
68
- */
69
- import type { Dal } from '../db/index.js';
70
- /**
71
- * Threshold override, matching the existing staleness-window convention in
72
- * this codebase (`LMCTL_INFLIGHT_TTL_MS`, `LMCTL_TERMINAL_LOCK_STALE_MS`):
73
- * ignore unset/blank/non-finite/non-positive values and fall back to the
74
- * 60-minute default.
75
- */
76
- export declare function sessionIdleTimeoutMsFromEnv(env?: NodeJS.ProcessEnv): number;
77
- /**
78
- * Has this receiver's underlying provider session been quiet for at least
79
- * `thresholdMs`?
80
- *
81
- * `true` ONLY when the session was found and its last activity is at or past
82
- * the threshold. Anything else — including every error — is `false`.
83
- */
84
- export declare function isReceiverIdleTimedOut(dal: Pick<Dal, 'getRootTeam' | 'listRootTeams'>, teamfile: string, alias: string, thresholdMs?: number): Promise<boolean>;
85
- /**
86
- * How long has this receiver's session been quiet, in ms? `null` when that
87
- * cannot be established for ANY reason — the fail-closed signal, and also what
88
- * the reclaim log reports so a steal can be judged after the fact.
89
- */
90
- export declare function sessionIdleMs(dal: Pick<Dal, 'getRootTeam' | 'listRootTeams'>, teamfile: string, alias: string): Promise<number | null>;
91
- /**
92
- * The delivery-side question, in one call: given the busy state we already
93
- * computed synchronously, may we deliver anyway because the session is idle?
94
- *
95
- * SCOPE — `in-flight` ONLY. Operator (2026-07-22): *"terminal-held is alway
96
- * regarded as busy, no matter how long idle is. session idle is only for
97
- * non-terminal session, that is through lmctl prompt."*
98
- *
99
- * `terminal-held` is NEVER overridden, at any idle duration. That case is a
100
- * human's interactive terminal — including a live codex/opencode TUI with a
101
- * persistent process attached — and declaring it available on a timestamp
102
- * would reintroduce exactly the concurrent-resume collision `b85c5a1`
103
- * ("Protect held sessions from stale lease steals") was written to prevent.
104
- * A quiet terminal is someone thinking, not an absent holder.
105
- *
106
- * `in-flight`, by contrast, is a lease taken by `lmctl prompt`/relay delivery:
107
- * bounded, ephemeral, non-interactive work. A live pid there with no session
108
- * file activity for the full window is most plausibly a hung turn, so it
109
- * is a reasonable reclaim target — the same spirit as the existing dead-pid
110
- * reclaim, adding long-idle-with-live-pid as a second trigger on the
111
- * chat-invoked path only.
112
- *
113
- * See `backlog/DESIGN-session-idle-availability-scope.md`.
114
- */
115
- export declare function isInflightButSessionIdle(dal: Pick<Dal, 'getRootTeam' | 'listRootTeams'>, busy: {
116
- busy: boolean;
117
- reason?: string;
118
- }, teamfile: string, alias: string, thresholdMs?: number): Promise<boolean>;
@@ -1,22 +0,0 @@
1
- import { type CliIo } from './common.js';
2
- /**
3
- * Path to the rolling intent log written by `status` (and, in future, by
4
- * other verbs that want a breadcrumb trail). Plain JSONL — one event per
5
- * line — so a troubleshooting bundle can ship it verbatim. Override via
6
- * `LMCTL_INTENT_LOG` for tests / non-default homes.
7
- */
8
- export declare function resolveIntentLogPath(): string;
9
- /**
10
- * Append a single intent record to the rolling log. Failures are
11
- * swallowed — the log is best-effort breadcrumbs, never load-bearing.
12
- */
13
- export declare function appendIntent(record: {
14
- verb: string;
15
- args: ReadonlyArray<string>;
16
- cwd?: string;
17
- ts?: string;
18
- }): void;
19
- export declare function runStatus(args: string[], io: CliIo): Promise<number>;
20
- export declare function formatDuration(ms: number): string;
21
- export declare function formatAge(iso: string): string;
22
- export declare function shortIdentity(identity: string): string;
@@ -1,18 +0,0 @@
1
- import type { ConversationMessage } from '../providers/types.js';
2
- import { type CliIo } from './common.js';
3
- export declare function runTail(args: string[], io?: CliIo): Promise<number>;
4
- /** Plain renderer (no chalk/ANSI per design R3). Indents continuation
5
- * lines so multi-line messages remain visually grouped. */
6
- export declare function renderMessage(msg: ConversationMessage): string;
7
- export declare function applyMaxBytes(output: string, maxBytes: number): string;
8
- /**
9
- * Same grammar as status.ts's parseStatusSince parser: a relative
10
- * duration (<n>s|m|h|d) or an absolute ISO8601
11
- * timestamp. Unlike status's version, `undefined` here means "no filter"
12
- * (tail's existing default is unchanged), not a default window.
13
- */
14
- export declare function parseTailSince(value: string | undefined): {
15
- date: Date | undefined;
16
- } | {
17
- error: string;
18
- };
@@ -1,139 +0,0 @@
1
- import type { Dal } from '../db/index.js';
2
- /**
3
- * Usage-class error for target-resolution failures (ported verbatim from
4
- * lmctl0 resolve-target.ts:32-37). The filesystem-backed resolvers throw
5
- * this; callers exit 2 on catch. The pure `classifyTarget` does NOT
6
- * throw — it returns an `{ mode: 'error' }` discriminated variant.
7
- */
8
- export declare class ChatTargetError extends Error {
9
- constructor(message: string);
10
- }
11
- /**
12
- * Valid alias grammar (letter-initial, then alphanumerics + `_`/`-`).
13
- * Matches lmctl-next's team-config alias grammar and lmctl0
14
- * resolve-target.ts:84 verbatim. Permissive enough for `researcher1`,
15
- * `backend-fixer`; strict enough to reject `./foo.lmctl:Coder;ls`.
16
- */
17
- export declare const ALIAS_RE: RegExp;
18
- /** True iff `arg` is a UUID- or `ses_`-shaped native session id.
19
- * (lmctl0 resolve-target.ts:86-88) */
20
- export declare function looksLikeSessionId(arg: string): boolean;
21
- /** Same alias validation surface as the colon parser. (lmctl0 :120-122) */
22
- export declare function isValidAlias(arg: string): boolean;
23
- /**
24
- * Detect the `<teamfile>:<alias>` shape WITHOUT touching the disk.
25
- * Returns the split parts if `arg` matches `<*.lmctl>:<alias>` with a
26
- * valid alias, else null. Splits on the LAST `:` so a Windows-style
27
- * absolute path like `C:\path\to\team.lmctl:Coder` still parses.
28
- * (lmctl0 resolve-target.ts:103-113, ported verbatim.)
29
- */
30
- export declare function parseTeamfileColonAlias(arg: string): {
31
- teamfile: string;
32
- alias: string;
33
- } | null;
34
- /** Concrete result of resolving `<teamfile> <alias>` (or the colon
35
- * shorthand) against a teamfile on disk. Mirrors lmctl0's `ResolvedMember`
36
- * shape (`session` → `sessionid`). */
37
- export interface ResolvedMember {
38
- /** Absolute path to the teamfile that contained the alias. */
39
- teamfile: string;
40
- /** Canonical alias casing as recorded in the teamfile. */
41
- alias: string;
42
- provider: string;
43
- sessionid: string;
44
- sessiondir: string;
45
- /** True when the concrete provider turn is a Lead session. */
46
- isLead: boolean;
47
- /** Model override from the concrete member line, if set. */
48
- model?: string;
49
- /** Effort / variant override from the concrete member line, if set. */
50
- effort?: string;
51
- }
52
- /**
53
- * Resolve `<teamfile>:<alias>` / `<teamfile> <alias>` against a real
54
- * teamfile and return the member's session coordinates. Throws
55
- * `ChatTargetError` on every usage failure (caller exits 2). Adapted
56
- * from lmctl0 resolve-target.ts:163-225: team-config import swapped, the
57
- * lmctl-next `TeamConfig.parseErrors` surface is honored (the copied
58
- * parser reports parse failures as a field, not by throwing — mirror
59
- * `src/cli/chat.ts:111`), and `member.session`/`member.sessiondir` are
60
- * optional in lmctl-next's `MemberConfig`.
61
- */
62
- export declare function resolveTeamMember(teamfileArg: string, aliasArg: string, dal?: Pick<Dal, 'getRootTeam' | 'listRootTeams'>): ResolvedMember;
63
- /**
64
- * Smart-target dispatch for sessionid-scoped commands. Accepts the same
65
- * three input shapes the verbs advertise. Throws `ChatTargetError` on
66
- * usage failure. Ported from lmctl0 resolve-target.ts:249-276 (import
67
- * adapted via `resolveTeamMember` above).
68
- */
69
- export declare function resolveSessionTarget(command: string, target: string, alias: string | undefined): {
70
- sessionid: string;
71
- providerOverride?: string;
72
- };
73
- /** Per-verb acceptance rules (preserve lmctl0's per-verb behavior). */
74
- export interface VerbCaps {
75
- /** Verb name, used verbatim in error messages. */
76
- name: string;
77
- /** A bare `<path>.lmctl` (no alias) is meaningful for this verb
78
- * (e.g. `info` team rollup). When false a bare teamfile is a usage
79
- * error (terminal/chat/tail require an alias). */
80
- allowsBareTeamfile: boolean;
81
- /** A bare `<sessionid>` (AI-team raw) is accepted (tail/info/chat).
82
- * `terminal` is teamfile-only (lmctl0 terminal-cmd.ts:64-69). */
83
- supportsRaw: boolean;
84
- }
85
- /** The classifier's input — the verb's already-split positionals + the
86
- * managed/legacy flags. No disk state is consulted. */
87
- export interface TargetInput {
88
- /** First positional (teamfile / teamfile:alias / sessionid), if any. */
89
- target?: string;
90
- /** Second positional (the two-positional `<teamfile> <alias>` form). */
91
- alias?: string;
92
- flags: {
93
- /** Managed selectors (NET-NEW vs lmctl0). */
94
- run?: string;
95
- project?: string;
96
- workflow?: string;
97
- /** Legacy raw form back-compat (lmctl0 `--session`/`--provider`). */
98
- session?: string;
99
- provider?: string;
100
- };
101
- }
102
- export type ClassifiedTarget = {
103
- mode: 'managed';
104
- run?: string;
105
- project?: string;
106
- workflow?: string;
107
- } | {
108
- mode: 'ai-team';
109
- teamfile: string;
110
- alias?: string;
111
- } | {
112
- mode: 'ai-team-raw';
113
- sessionid: string;
114
- provider?: string;
115
- } | {
116
- mode: 'error';
117
- message: string;
118
- };
119
- /**
120
- * Classify `(flags, target?, alias?)` into exactly one of the 3 modes,
121
- * per design §0.1 precedence (verbatim):
122
- *
123
- * 1. managed flag (`--run`/`--project`/`--workflow`) present → MANAGED,
124
- * mutually exclusive with a positional target (both ⇒ error).
125
- * 2. positional target present:
126
- * 2a. parseTeamfileColonAlias matches → AI-TEAM
127
- * 2b. target ends ".lmctl":
128
- * - second positional alias present → AI-TEAM
129
- * - no alias, verb allows bare-teamfile → AI-TEAM (rollup)
130
- * - no alias, verb requires alias → error
131
- * 2c. looksLikeSessionId & verb.supportsRaw → AI-TEAM RAW
132
- * (else error: bare sessionid unsupported)
133
- * 2d. none of the above → error (can't infer)
134
- * 3. no positional, legacy --session set → AI-TEAM RAW
135
- * 4. nothing → error (usage)
136
- *
137
- * Pure: no I/O, deterministic, never throws.
138
- */
139
- export declare function classifyTarget(verb: VerbCaps, input: TargetInput): ClassifiedTarget;
@@ -1,91 +0,0 @@
1
- import type { Dal } from '../db/index.js';
2
- import type { SessionLimitState } from '../providers/session-limit.js';
3
- import type { SessionDetail } from '../providers/types.js';
4
- import { type CliIo } from './common.js';
5
- export declare function formatTokens(n: number): string;
6
- export interface GitWorkingStatus {
7
- uncommittedTracked: number | null;
8
- untracked: number | null;
9
- }
10
- export type GitProgress = {
11
- kind: 'unavailable';
12
- teamDir: string;
13
- reason: 'no-repo' | 'no-commits';
14
- } | {
15
- kind: 'repo';
16
- teamDir: string;
17
- since: Date;
18
- commits: Array<{
19
- ref: string;
20
- timestamp: Date;
21
- }>;
22
- working: GitWorkingStatus;
23
- };
24
- export interface MemberLiveness {
25
- state: 'idle' | 'busy';
26
- reason: 'terminal-held' | 'in-flight' | null;
27
- inFlight: {
28
- senderTeamfile: string;
29
- senderAlias: string;
30
- startedAt: string;
31
- activeCount: number;
32
- holderPid: number | null;
33
- } | null;
34
- terminalLock: {
35
- startedAt: string;
36
- lastHeartbeat: string;
37
- holderPid: number;
38
- holderHost: string;
39
- } | null;
40
- terminalInvocation: {
41
- id: number;
42
- startedAt: string;
43
- lastHeartbeat: string | null;
44
- holderPid: number | null;
45
- holderHost: string | null;
46
- } | null;
47
- reclaimable: {
48
- source: 'terminal-lock' | 'terminal-invocation' | 'in-flight';
49
- holderPid: number | null;
50
- holderHost: string | null;
51
- reason: 'dead-pid' | 'stale';
52
- } | null;
53
- }
54
- export interface TeamHealthTarget {
55
- teamfile: string;
56
- alias: string;
57
- reportPath: string;
58
- provider: string;
59
- /** Null for an unseeded member (planned but never seeded) -- the roster
60
- * keeps the entry so `status <teamfile>` shows it explicitly as
61
- * not-seeded; only session probing is gated on a sessionid existing. */
62
- sessionid: string | null;
63
- /** The teamfile's DECLARED model= for this member -- what was asked for,
64
- * read straight from config with no live probe. Distinct from (and can
65
- * disagree with) the OBSERVED model a live session probe reports, which
66
- * is what the provider actually used -- real incident, 2026-09-29
67
- * (math.lmctl differential test): agy/codex sessions running on models
68
- * their teamfiles do not declare. Null when the member has no model=. */
69
- model: string | null;
70
- }
71
- /** Task #232: the most recent tracked_invocation for this target that
72
- * actually recorded a config-drop -- `ORDER BY started_at DESC LIMIT 1`
73
- * scoped to rows where config_warnings is set, so a later CLEAN turn
74
- * doesn't shadow an earlier drop the operator still needs to see, and a
75
- * config-drop from days ago doesn't look like it just happened. */
76
- export declare function latestConfigWarnings(io: CliIo, target: {
77
- teamfile: string;
78
- alias: string;
79
- }): Promise<string[] | undefined>;
80
- export declare function collectHealthTargets(teamfileArg: string, dal: Dal, seen: Set<string>, prefix: string[]): TeamHealthTarget[];
81
- export declare function loadTeamLiveness(io: CliIo, targets: TeamHealthTarget[]): Promise<Map<string, MemberLiveness>>;
82
- export declare function memberKey(teamfile: string, alias: string): string;
83
- export declare function idleLiveness(reclaimable?: MemberLiveness['reclaimable']): MemberLiveness;
84
- export declare function livenessLabel(value: MemberLiveness): string;
85
- export declare function formatSessionLimitReset(value: SessionLimitState): string;
86
- export declare function formatKnownNumber(value: number | undefined | null): string;
87
- export declare function formatProviderRollupNumber(value: number | null | undefined | 'n/a'): string;
88
- export declare function formatOptionalProviderNumber(value: number | undefined, loaded: boolean, format?: (value: number) => string): string;
89
- export declare function readGitProgress(teamfile: string): GitProgress;
90
- export declare function countMessagesSince(detail: SessionDetail, since: Date): number;
91
- export declare function cumulativeSessionTokens(detail: SessionDetail | null): number | null;
@@ -1,116 +0,0 @@
1
- import { type AgyModelsRunResult, type CodexModelsRunResult } from '../providers/config/model-selection-lint.js';
2
- import type { CatalogSnapshot } from '../providers/pricing.js';
3
- import { type OpenCodeAcpConfigProbeOptions, type OpenCodeAcpConfigProbeResult } from '../providers/transports/acp.js';
4
- import type { ProviderName } from '../providers/types.js';
5
- import type { Dal, RootTeamInput, RootTeamRow } from '../db/index.js';
6
- export declare const GEMINI_PROVIDER_NOTICE = "notice: member \"%s\" uses provider=gemini \u2014 the Gemini CLI requires an API/enterprise Google account; personal Google subscriptions should use provider=agy (Antigravity).";
7
- export interface TeamfileCliIo {
8
- stdout: {
9
- write(chunk: string): unknown;
10
- };
11
- stderr: {
12
- write(chunk: string): unknown;
13
- };
14
- dal?: Dal;
15
- env?: NodeJS.ProcessEnv;
16
- }
17
- type SeedFn = (opts: {
18
- provider: ProviderName;
19
- cwd: string;
20
- model?: string;
21
- effort?: string;
22
- prompt?: string;
23
- }) => Promise<{
24
- sessionId?: string;
25
- error?: string;
26
- warnings?: string[];
27
- }>;
28
- type OpenCodeConfigProbeFn = (opts: OpenCodeAcpConfigProbeOptions) => Promise<OpenCodeAcpConfigProbeResult>;
29
- interface LintSessiondirFsOps {
30
- existsSync(path: string): boolean;
31
- statSync(path: string): {
32
- isDirectory(): boolean;
33
- };
34
- accessSync(path: string, mode: number): unknown;
35
- }
36
- /** Test-only seam: inject a fixed lmprice catalog snapshot so lint/seed
37
- * catalog-resolution tests never touch the network/cache/bundled data.
38
- * `null` restores the real loader (loadCatalogSnapshot). */
39
- export declare function _setCatalogSnapshotForTests(snapshot: CatalogSnapshot | null): void;
40
- /** Test-only seam: inject a fake `agy models` result so lint/seed tests
41
- * don't depend on the real `agy` binary being installed/authenticated (or
42
- * on its live catalog staying stable). `null` restores the real command. */
43
- export declare function _setAgyModelsRunnerForTests(fn: (() => AgyModelsRunResult) | null): void;
44
- /** Test-only seam: inject a fake `codex debug models` result, same
45
- * rationale as `_setAgyModelsRunnerForTests` above. */
46
- export declare function _setCodexModelsRunnerForTests(fn: (() => CodexModelsRunResult) | null): void;
47
- export declare function _setTeamfileSeedForTests(fn: SeedFn | null): void;
48
- export declare function _setLintSessiondirFsOpsForTests(ops: Partial<LintSessiondirFsOps> | null): void;
49
- export declare function _setLintOpenCodeConfigProbeForTests(fn: OpenCodeConfigProbeFn | null): void;
50
- export declare function runLint(args: string[], io?: TeamfileCliIo): Promise<number>;
51
- export interface LintFinding {
52
- /** Real member alias the finding is about, or "" when it's about the file itself. */
53
- alias: string;
54
- message: string;
55
- }
56
- export interface LintStructuredResult {
57
- /** "error" ONLY for a genuine validation error (unparseable file, bad
58
- * _MEMBER_ line, confirmed wrong-provider model). Warnings never flip
59
- * this to "error" -- matches the CLI's own exit-0-on-warnings contract. */
60
- status: 'ok' | 'error';
61
- errors: LintFinding[];
62
- warnings: LintFinding[];
63
- counts: {
64
- errors: number;
65
- warnings: number;
66
- };
67
- }
68
- /**
69
- * Structured form of the exact same lint computation `lmctl lint` runs
70
- * (queue#22208): a workflow reads errors/warnings/counts directly instead
71
- * of string-matching "warning:"-prefixed lines, which breaks silently the
72
- * day that prefix changes -- the failure shape math named as the reason
73
- * this exists. Both lists are always arrays, never null/undefined.
74
- */
75
- export declare function lintTeamfileStructured(teamfile: string, io: TeamfileCliIo): Promise<LintStructuredResult>;
76
- export declare function runSeed(args: string[], io?: TeamfileCliIo): Promise<number>;
77
- /**
78
- * Per-alias seed prompt override (lmscript's lm_seed, operator 2026-09-30:
79
- * "this is a simple seed. the user want more... use lmscript (lmscript
80
- * should access internal, have full control of preamble)"). A bare string
81
- * is shorthand for "whichever alias gets a custom prompt today" (Lead
82
- * only); a map keys by alias (case-insensitive) so e.g. a Reviewer can get
83
- * its own framing distinct from Lead's. REPLACES the default prompt
84
- * entirely for a matched alias -- it is not appended to.
85
- */
86
- export interface SeedTeamfileOptions {
87
- /** Inferred onboarding must not overwrite edits made while a provider starts. */
88
- guardFile?: boolean;
89
- /** Internal confirmed refresh: never exposed as a force flag. Preserve the old ID on failure. */
90
- replaceSession?: {
91
- alias: string;
92
- sessionid: string;
93
- };
94
- preamble?: string | Record<string, string>;
95
- }
96
- export declare function seedTeamfile(teamfile: string, io: TeamfileCliIo, opts?: SeedTeamfileOptions): Promise<number>;
97
- export interface RootTeamRegistrationInput {
98
- teamfilePath: string;
99
- name: string | null;
100
- rawText: string;
101
- now: string;
102
- }
103
- export declare function sha256Text(text: string): string;
104
- export declare function buildRootTeamRegistrationRow(existing: RootTeamRow | null, input: RootTeamRegistrationInput): RootTeamInput;
105
- export declare function registerRootTeam(dal: Dal, input: RootTeamRegistrationInput): RootTeamInput;
106
- /**
107
- * Shared member-spec validation for surfaces that build _MEMBER_ lines from
108
- * user input (`lmctl plan --member`, the plan wizard): alias shape + known
109
- * provider name. Returns an error message, or undefined when the spec is
110
- * valid.
111
- */
112
- export declare function validateMemberSpec(spec: {
113
- alias: string;
114
- provider: string;
115
- }): string | undefined;
116
- export {};
@@ -1,18 +0,0 @@
1
- import type { Dal } from '../db/index.js';
2
- import { type TeamConfig } from '../providers/config/team-config.js';
3
- type TeamfileLookupDal = Pick<Dal, 'getRootTeam' | 'listRootTeams'>;
4
- type TeamfileStoreDal = Pick<Dal, 'getRootTeam' | 'listRootTeams' | 'upsertRootTeam'>;
5
- type TeamfileRegistrationWarning = (warning: string) => void;
6
- export declare function canonicalTeamfileKey(teamfile: string, dal?: TeamfileLookupDal): string;
7
- export declare function parseStoredTeamConfig(rawText: string, teamfileKey: string): TeamConfig;
8
- export declare function readTeamConfigFromStore(teamfile: string, dal?: TeamfileStoreDal | Pick<Dal, 'getRootTeam'>, warn?: TeamfileRegistrationWarning): TeamConfig;
9
- /**
10
- * Registration-time ownership guard for provider sessions.
11
- *
12
- * A session id identifies one concrete provider conversation, so two live
13
- * registered teamfiles must never claim it as different members. Registry
14
- * rows whose files have been renamed/deleted are inert and deliberately
15
- * excluded: re-seeding the same team at its new path must remain possible.
16
- */
17
- export declare function assertNoForeignSessionidOwnership(dal: TeamfileLookupDal, key: string, config: TeamConfig): void;
18
- export {};
@@ -1,47 +0,0 @@
1
- /**
2
- * Teamfile construction primitives for `lmctl plan`:
3
- * member-spec parsing (`Alias:provider[:model]`), the 1/2/3 member patterns,
4
- * the canonical teamfile renderer, and the session-key stripper used by
5
- * `--from` template mode. Kept free of I/O so both the flags path and the
6
- * wizard render byte-identical documents.
7
- */
8
- export interface MemberSpec {
9
- alias: string;
10
- provider: string;
11
- model?: string;
12
- }
13
- /** Named and numeric patterns → member alias lists. Pattern 1 is Lead-only. */
14
- export declare const MEMBER_PATTERNS: Record<string, string[]>;
15
- export declare const PATTERN_USAGE = "1|2|3|lead|lead-reviewer|lead-coder-reviewer";
16
- export declare function resolvePattern(value: string): string[] | undefined;
17
- /**
18
- * Parse one `--member Alias:provider[:model]` value. Validation matches the
19
- * shared member-spec rules (validateMemberSpec in teamfile-compat.ts).
20
- */
21
- export declare function parseMemberSpec(raw: string): {
22
- spec?: MemberSpec;
23
- error?: string;
24
- };
25
- export declare function renderMemberLine(member: MemberSpec): string;
26
- /**
27
- * Render the canonical starter teamfile. Session ids are never generated
28
- * here — that is `lmctl seed`'s job.
29
- *
30
- * Operator, 2026-09-29 (onboarding revamp, queued#21811): the header
31
- * teaches the loop -- generate, edit, lint, seed -- and points at ONE page
32
- * covering the teamfile format plus what lint and seed each do, rather
33
- * than explaining any of that inline. Deliberately ONE link, not two:
34
- * lmctl-lead.md is dropped (the seed prompt is cut to bare minimum for the
35
- * same reason -- an arriving Lead isn't front-loaded with an operating
36
- * guide) and the previously-inline no-`timeout` paragraph is cut entirely
37
- * (queued#21813/#21814/#21820, operator: a warning that never stopped
38
- * anyone who hit it is noise for everyone who has not).
39
- */
40
- export declare function renderTeamfile(opts: {
41
- teamName: string;
42
- members: MemberSpec[];
43
- }): string;
44
- /** Strip sessionid= and sessiondir= from _MEMBER_ lines (template mode). */
45
- export declare function stripSessionKeys(text: string): string;
46
- /** Read the member roster back out of teamfile text (reporting / --json). */
47
- export declare function parseMembersFromTeamfile(text: string): MemberSpec[];
@@ -1,25 +0,0 @@
1
- export interface TemplateEnvContext {
2
- workdir: string;
3
- teamfile: string;
4
- date: string;
5
- }
6
- declare const TEMPLATE_ENV_REGISTRY: {
7
- workdir: (ctx: TemplateEnvContext) => string;
8
- teamfile: (ctx: TemplateEnvContext) => string;
9
- teamname: (ctx: TemplateEnvContext) => string;
10
- home: () => string;
11
- date: (ctx: TemplateEnvContext) => string;
12
- };
13
- export type TemplateEnvName = keyof typeof TEMPLATE_ENV_REGISTRY;
14
- export interface TemplateEnvSubstitution {
15
- text: string;
16
- unknownNames: string[];
17
- }
18
- export declare function substituteTemplateEnv(text: string, ctx: TemplateEnvContext): TemplateEnvSubstitution;
19
- export declare function templateEnvContext(input: {
20
- workdir: string;
21
- teamfile: string;
22
- date: Date;
23
- }): TemplateEnvContext;
24
- export declare function formatTemplateDate(date: Date): string;
25
- export {};
@@ -1,25 +0,0 @@
1
- import type { TerminalLockRecord } from '../db/terminal-lock.js';
2
- export type TerminalLockLiveness = {
3
- live: true;
4
- reason: 'local-pid-alive' | 'remote-heartbeat-fresh';
5
- } | {
6
- live: false;
7
- reason: 'dead-pid' | 'stale-heartbeat';
8
- };
9
- export declare function createTerminalLockRecord(input: {
10
- teamfile: string;
11
- alias: string;
12
- now?: Date;
13
- pid?: number;
14
- host?: string;
15
- ips?: string[];
16
- }): TerminalLockRecord;
17
- export declare function terminalLockHeartbeatMsFromEnv(env?: NodeJS.ProcessEnv): number;
18
- export declare function terminalLockStaleMsFromEnv(env?: NodeJS.ProcessEnv): number;
19
- export declare function evaluateTerminalLockLiveness(lock: TerminalLockRecord, opts?: {
20
- now?: Date;
21
- localHost?: string;
22
- staleMs?: number;
23
- isProcessAlive?: (pid: number) => boolean;
24
- }): TerminalLockLiveness;
25
- export declare function terminalHeldMessage(lock: TerminalLockRecord): string;
@@ -1,23 +0,0 @@
1
- import { type CliIo } from './common.js';
2
- /** Operator-decided non-blocking guide/trip-wire (design §4.3 / §10.A).
3
- * NEVER gates or auto-acts — informational only. */
4
- export declare const SIZE_WARN_EST_TOKENS = 200000;
5
- export declare function runTerminal(args: string[], io: CliIo): Promise<number>;
6
- /**
7
- * Local, provider-agnostic token ESTIMATE (design §4.2). Σ message
8
- * content chars (preferred) ÷ 4, else file bytes ÷ 4. NEVER a provider
9
- * round-trip / `tokens` call. The /4 ("~4 chars/token") is the
10
- * widely-cited BPE midpoint; this is a trip-wire, not a billing meter
11
- * (bias documented in --help).
12
- */
13
- export declare function estimateTokens(detail: {
14
- messages?: Array<{
15
- content?: string;
16
- }>;
17
- filePath?: string;
18
- } | null): {
19
- chars: number;
20
- est: number;
21
- messages: number | null;
22
- bytes: number | null;
23
- };
@@ -1,10 +0,0 @@
1
- /**
2
- * Shared `--since`/`--until` grammar: a relative duration (`<n>s|m|h|d`,
3
- * e.g. `24h`) or an absolute ISO8601 timestamp. One parser so `tail` and
4
- * `session` (and anything else that grows a time filter) can't drift.
5
- */
6
- export declare function parseSinceUntil(value: string | undefined, flagName: string): {
7
- date: Date | undefined;
8
- } | {
9
- error: string;
10
- };