@lmctl-ai/lmctl 0.1.342 → 0.2.3

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 +122 -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,90 @@
1
+ import type { ConversationMessage, SessionDetail, SessionProvider, SessionSummary, WatchPathInfo } from "./types.js";
2
+ import type { ForkResult, InjectionInfo, ManualSeedHint, ProviderAdapter, ProviderCapabilities, SeedOptions, SeedResult, TurnOptions, TurnResult } from "./adapter.js";
3
+ interface MockSession {
4
+ sessionId: string;
5
+ cwd: string;
6
+ filePath: string;
7
+ createdAt: Date;
8
+ modifiedAt: Date;
9
+ messages: ConversationMessage[];
10
+ totalInputTokens: number;
11
+ totalOutputTokens: number;
12
+ }
13
+ interface StoredConversationMessage extends Omit<ConversationMessage, "timestamp"> {
14
+ timestamp: string;
15
+ }
16
+ interface StoredMockSession extends Omit<MockSession, "createdAt" | "modifiedAt" | "messages"> {
17
+ createdAt: string;
18
+ modifiedAt: string;
19
+ messages: StoredConversationMessage[];
20
+ }
21
+ type ScriptedResponse = string | {
22
+ text: string;
23
+ error?: never;
24
+ delayMs?: number;
25
+ } | {
26
+ error: string;
27
+ text?: never;
28
+ delayMs?: number;
29
+ };
30
+ interface ClaudeMockStore {
31
+ schemaVersion: 1;
32
+ defaultDelayMs?: number;
33
+ script?: Record<string, ScriptedResponse>;
34
+ /**
35
+ * Substring-match scripting, checked LAST (after exact + first-line miss).
36
+ * A key matches when it is a substring of the prompt, so a prompt with
37
+ * dynamic content before AND after a stable anchor phrase can be scripted
38
+ * deterministically. Kept as its own field (not a prefixed key inside
39
+ * `script`) so the two lookup modes stay independently typed and a literal
40
+ * prompt can never be mistaken for a substring pattern.
41
+ */
42
+ scriptContains?: Record<string, ScriptedResponse>;
43
+ sessions: Record<string, StoredMockSession>;
44
+ }
45
+ declare function mockStorePath(cwd?: string): string;
46
+ declare function readStore(path: string): ClaudeMockStore;
47
+ declare function acquireStoreLock(path: string): string;
48
+ declare function releaseStoreLock(lockDir: string): void;
49
+ declare function withStoreLock<T>(path: string, fn: () => T): T;
50
+ declare function savePersistentSession(session: MockSession): void;
51
+ declare function deletePersistentSession(sessionId: string, cwd?: string): boolean;
52
+ export declare function _resetClaudeMockSessionsForTests(): void;
53
+ export declare const _claudeMockStoreInternals: {
54
+ savePersistentSession: typeof savePersistentSession;
55
+ deletePersistentSession: typeof deletePersistentSession;
56
+ acquireStoreLock: typeof acquireStoreLock;
57
+ releaseStoreLock: typeof releaseStoreLock;
58
+ withStoreLock: typeof withStoreLock;
59
+ readStore: typeof readStore;
60
+ mockStorePath: typeof mockStorePath;
61
+ STORE_LOCK_STALE_MS: number;
62
+ STORE_LOCK_MAX_WAIT_MS: number;
63
+ };
64
+ export declare class ClaudeMockProvider implements SessionProvider {
65
+ name: "ClaudeMock";
66
+ discoverSessions(): Promise<SessionSummary[]>;
67
+ loadSession(sessionId: string): Promise<SessionDetail | null>;
68
+ resolveSessionPath(sessionId: string): Promise<string | null>;
69
+ deleteSession(sessionId: string): Promise<boolean>;
70
+ }
71
+ export declare class ClaudeMockAdapter implements ProviderAdapter {
72
+ readonly name: "ClaudeMock";
73
+ readonly capabilities: ProviderCapabilities;
74
+ readonly injection: InjectionInfo;
75
+ private readonly provider;
76
+ discover(): Promise<SessionSummary[]>;
77
+ load(sessionId: string): Promise<SessionDetail | null>;
78
+ resolvePath(sessionId: string): Promise<string | null>;
79
+ delete(sessionId: string): Promise<boolean>;
80
+ getWatchPaths(): WatchPathInfo[];
81
+ seed(cwd: string, opts?: SeedOptions): Promise<SeedResult>;
82
+ resumeCommand(sessionId: string): string;
83
+ startCommand(): string;
84
+ manualSeedHint(sessiondir: string): ManualSeedHint;
85
+ forkHint(_sessionId: string): string;
86
+ fork(_sessionId: string, _tag: string): Promise<ForkResult>;
87
+ sendTurn(prompt: string, opts: TurnOptions): Promise<TurnResult>;
88
+ }
89
+ export declare function createClaudeMockAdapter(): ClaudeMockAdapter;
90
+ export {};
@@ -0,0 +1,21 @@
1
+ import type { SessionProvider, SessionSummary, SessionDetail } from "./types.js";
2
+ interface ClaudeProviderOptions {
3
+ claudeDir?: string;
4
+ }
5
+ export declare class ClaudeProvider implements SessionProvider {
6
+ name: "claude";
7
+ private claudeDir;
8
+ private projectsDir;
9
+ constructor(options?: ClaudeProviderOptions);
10
+ getWatchPaths(): {
11
+ directory: string;
12
+ filePattern: RegExp;
13
+ }[];
14
+ discoverSessions(): Promise<SessionSummary[]>;
15
+ private extractSummary;
16
+ loadSession(sessionId: string): Promise<SessionDetail | null>;
17
+ resolveSessionPath(sessionId: string): Promise<string | null>;
18
+ deleteSession(sessionId: string): Promise<boolean>;
19
+ private resolveSessionFile;
20
+ }
21
+ export {};
@@ -0,0 +1,15 @@
1
+ /** Compatibility no-op for retired Codex lmctl-MCP injection. */
2
+ import type { McpExecutableWarningOptions } from "../mcp/path-warning.js";
3
+ /**
4
+ * Per-server tool request timeout. Codex's MCP config uses seconds
5
+ * (`tool_timeout_sec`); keep the ms constant for parity with
6
+ * opencode's config and derive seconds for the TOML override.
7
+ */
8
+ export declare const CODEX_LMCTL_MCP_TIMEOUT_MS = 86400000;
9
+ export declare const CODEX_LMCTL_MCP_TIMEOUT_SEC: number;
10
+ /**
11
+ * The lmctl MCP server remains in-tree, but provider MCP injection is
12
+ * retired. Keep the helper as a compatibility no-op for callers that
13
+ * still append its result into codex argv.
14
+ */
15
+ export declare function buildCodexMcpFlags(_options?: McpExecutableWarningOptions): string[];
@@ -0,0 +1,25 @@
1
+ import type { SessionProvider, SessionSummary, SessionDetail } from "./types.js";
2
+ interface CodexProviderOptions {
3
+ codexDirs?: string[];
4
+ codexDir?: string;
5
+ codeDir?: string;
6
+ }
7
+ export declare class CodexProvider implements SessionProvider {
8
+ name: "codex";
9
+ private codexDirs;
10
+ constructor(options?: CodexProviderOptions);
11
+ getWatchPaths(): {
12
+ directory: string;
13
+ filePattern: RegExp;
14
+ }[];
15
+ private getSessionsDirs;
16
+ discoverSessions(): Promise<SessionSummary[]>;
17
+ private findSessionFiles;
18
+ private extractSessionIdFromFilename;
19
+ private extractSummary;
20
+ loadSession(sessionId: string): Promise<SessionDetail | null>;
21
+ resolveSessionPath(sessionId: string): Promise<string | null>;
22
+ deleteSession(sessionId: string): Promise<boolean>;
23
+ private resolveSessionFile;
24
+ }
25
+ export {};
@@ -0,0 +1,45 @@
1
+ import { type CatalogSnapshot } from "../pricing.js";
2
+ import type { MemberConfig } from "./team-config.js";
3
+ export interface AgyModelsRunResult {
4
+ status: number | null;
5
+ stdout: string;
6
+ error?: Error;
7
+ }
8
+ export interface CodexModelsRunResult {
9
+ status: number | null;
10
+ stdout: string;
11
+ error?: Error;
12
+ }
13
+ export interface OpencodeModelsRunResult {
14
+ status: number | null;
15
+ stdout: string;
16
+ error?: Error;
17
+ }
18
+ export declare function modelSelectionWarnings(members: MemberConfig[], opts?: {
19
+ opencodeConfigPath?: string;
20
+ kimiConfigPath?: string;
21
+ agyModelsRunner?: () => AgyModelsRunResult;
22
+ opencodeModelsRunner?: (provider: string) => OpencodeModelsRunResult;
23
+ codexModelsRunner?: () => CodexModelsRunResult;
24
+ }): string[];
25
+ /**
26
+ * lmprice catalog resolution for lint/seed (design v2 sections 2+5). Runs
27
+ * resolveModel() for every member with model= on an adapter-covered
28
+ * provider against ONE snapshot load (loadCatalogSnapshot is memoized per
29
+ * process):
30
+ * - unknown -> warning (`provider may still accept it`)
31
+ * - known-unpriced -> warning (operator invariant 2026-09-25: "if we can
32
+ * lint, then we can cost" -- a lint-recognized model that cost cannot
33
+ * price must be surfaced at lint time; lmprice build validation is
34
+ * tasked with never publishing such half-bindings again)
35
+ * - priced/estimated -> ok
36
+ * - unresolved -> silent (deliberate non-binding in lmprice's alias
37
+ * table, not lint's claim to second-guess)
38
+ * - no-catalog / catalog unavailable -> skip silently
39
+ * The returned warnings wire into lint/seed's standard warnings array, so
40
+ * `lint --strict` promotes them exactly like every other warning.
41
+ */
42
+ export declare function catalogModelWarnings(members: MemberConfig[], opts?: {
43
+ snapshot?: CatalogSnapshot;
44
+ }): Promise<string[]>;
45
+ export declare function resolveModelSelectionDocPathFromHere(here: string): string;
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Team config — one <team>.lmctl file per team.
3
+ *
4
+ * Free-form markdown with embedded `_MEMBER_` lines for the team's
5
+ * sessions:
6
+ *
7
+ * # Frontend Team
8
+ *
9
+ * _MEMBER_ alias=Lead provider=claude sessionid=abc-123
10
+ * _MEMBER_ alias=Coder provider=claude sessionid=def-456
11
+ * _MEMBER_ alias=Reviewer provider=codex sessionid=ghi-789
12
+ *
13
+ * `sessiondir=` is optional; when omitted, the teamfile's own directory is
14
+ * used at resolution time. Keep explicit sessiondir only for members that run
15
+ * in a different repository.
16
+ *
17
+ * Everything outside `_MEMBER_` lines is natural language (policy,
18
+ * notes, context). Legacy frontmatter is parsed when present, but it
19
+ * is optional. When the team declares a Lead, the full document is
20
+ * injected into that Lead's context as-is.
21
+ *
22
+ * Wire format renames (one cutover at this commit):
23
+ * - `_SESSION_` → `_MEMBER_` (matches the codebase's `MemberEntry`
24
+ * type)
25
+ * - `id=` → `sessionid=` (matches `mcp__lmctl__lmctl_chat`'s
26
+ * `sessionid` parameter; an LLM can copy the identity quadruple
27
+ * from a member line straight to a tool call without renaming
28
+ * fields)
29
+ *
30
+ * Legacy `_SESSION_` is rejected with a clear migration error.
31
+ *
32
+ * alias=Lead has special bootstrap/default-routing behavior when
33
+ * present (at most one per team), but a Lead is not required.
34
+ */
35
+ import { type Frontmatter } from "../frontmatter.js";
36
+ export interface MemberConfig {
37
+ alias: string;
38
+ provider: string;
39
+ session?: string;
40
+ sessiondir?: string;
41
+ /** Provider-specific model name (e.g. "claude-sonnet-4-6"). Optional.
42
+ * The transport maps this through each provider's supported model
43
+ * selection surface; unsupported providers ignore with provider-
44
+ * specific diagnostics. */
45
+ model?: string;
46
+ /** Provider-specific effort / variant selection. Currently used by
47
+ * OpenCode ACP as the provider's effort config option. Kimi has no
48
+ * genuine per-turn effort override (its `thinking` option is on/off
49
+ * only, resolved per-model) so lint warns and ignores this for kimi. */
50
+ effort?: string;
51
+ /** Path to a sub-team's .lmctl file. When set, this member is a
52
+ * team reference — provider/id/sessiondir come from the
53
+ * referenced teamfile's lead session at resolution time. */
54
+ teamfile?: string;
55
+ /** Extra key=value pairs from the session line */
56
+ extra: Record<string, string>;
57
+ }
58
+ export interface TeamConfig {
59
+ /** Team name (from filename without .lmctl extension). */
60
+ name: string;
61
+ /** All members parsed from session lines. */
62
+ members: MemberConfig[];
63
+ /** The full raw document text (for leader injection). */
64
+ rawText: string;
65
+ /** Errors from malformed session lines, invalid legacy frontmatter,
66
+ * legacy `_SESSION_` prefix, etc. `validateTeamConfig` upgrades
67
+ * these to validation errors so CLI commands surface them. */
68
+ parseErrors: string[];
69
+ /** Parsed legacy frontmatter, or `null` if the file lacks it / had
70
+ * a malformed block. Frontmatter is optional for current teamfiles. */
71
+ frontmatter: Frontmatter | null;
72
+ }
73
+ export interface TeamValidationError {
74
+ field: string;
75
+ message: string;
76
+ }
77
+ /** The conventional alias that triggers Lead bootstrap/default routing. */
78
+ export declare const LEADER_ALIAS = "Lead";
79
+ export declare function teamNameFromPath(filePath: string): string;
80
+ export declare function readTeamConfig(filePath: string): TeamConfig;
81
+ export interface ParseTeamConfigOptions {
82
+ baseDir?: string;
83
+ sourcePath?: string;
84
+ }
85
+ export declare function parseTeamConfigText(raw: string, name: string, options?: ParseTeamConfigOptions): TeamConfig;
86
+ /**
87
+ * Diff frontmatter `members:` against the aliases on `_MEMBER_` lines.
88
+ * Returns null if they agree (sorted-set equal); else returns a
89
+ * human-readable warning string. Caller decides how to surface it.
90
+ */
91
+ export declare function checkMemberDrift(config: TeamConfig): string | null;
92
+ export declare function serializeTeamConfig(config: TeamConfig): string;
93
+ export declare function writeTeamConfig(filePath: string, config: TeamConfig): void;
94
+ export declare function validateTeamConfig(config: TeamConfig, parentDir?: string): TeamValidationError[];
95
+ export declare function getLeader(config: TeamConfig): MemberConfig | undefined;
96
+ /**
97
+ * Resolved details from a team reference — the sub-team's lead
98
+ * session's provider, id, sessiondir, and model override.
99
+ */
100
+ export interface ResolvedTeamMember {
101
+ provider: string;
102
+ session: string;
103
+ sessiondir: string;
104
+ alias: string;
105
+ resolvedFrom: string;
106
+ /** Model override from the sub-team's lead (Task A). Undefined if unset. */
107
+ model?: string;
108
+ /** Effort override from the sub-team's lead. Undefined if unset. */
109
+ effort?: string;
110
+ }
111
+ export interface ResolveTeamReferenceOptions {
112
+ requireSession?: boolean;
113
+ }
114
+ /**
115
+ * Resolve a `teamfile=` reference to the sub-team's lead session.
116
+ *
117
+ * @param member The member with `teamfile` set.
118
+ * @param parentDir Directory of the PARENT teamfile (for resolving
119
+ * relative paths in `teamfile=`).
120
+ * @param visited Circular-reference guard. Callers should NOT pass
121
+ * this — it's used internally for recursion.
122
+ *
123
+ * Throws on: missing teamfile, no lead, no session ID, circular ref.
124
+ */
125
+ export declare function resolveTeamReference(member: MemberConfig, parentDir: string, visited?: Set<string>, options?: ResolveTeamReferenceOptions): ResolvedTeamMember;
126
+ export declare function getMemberByAlias(config: TeamConfig, alias: string): MemberConfig | undefined;
127
+ /** Reserved aliases for the mechanical review loop. */
128
+ export declare const CODER_ALIAS = "Coder";
129
+ export declare const REVIEWER_ALIAS = "Reviewer";
130
+ /**
131
+ * Check whether a team is a leadless Coder+Reviewer team, which
132
+ * triggers the mechanical review loop (Task 77).
133
+ */
134
+ export declare function isLeadlessReviewTeam(config: TeamConfig): boolean;
135
+ /**
136
+ * Resolve the target alias for a team given the routing rules:
137
+ * 1. --alias specified → that alias (direct addressing)
138
+ * 2. Exactly 1 member → that member (regardless of alias; solo-worker
139
+ * teams are a first-class shape)
140
+ * 3. No Lead + Coder + Reviewer → "__review__" (mechanical review)
141
+ * 4. Has Lead → Lead's alias (case-insensitive via getLeader)
142
+ * 5. >1 members with no Lead → error listing available aliases
143
+ */
144
+ export declare function resolveTeamTarget(config: TeamConfig, targetAlias?: string): {
145
+ kind: "direct";
146
+ alias: string;
147
+ } | {
148
+ kind: "review";
149
+ } | {
150
+ kind: "error";
151
+ message: string;
152
+ };
153
+ /** A node in the team tree (or DAG if diamonds exist). */
154
+ export interface TeamTreeNode {
155
+ /** Absolute path to this node's .lmctl file. */
156
+ filePath: string;
157
+ /** Parsed team config. */
158
+ config: TeamConfig;
159
+ /** Children: member alias → child node (only for teamfile= members). */
160
+ children: Map<string, TeamTreeNode>;
161
+ }
162
+ /**
163
+ * Build a team tree (DAG) by recursively resolving all `teamfile=`
164
+ * references starting from `rootPath`.
165
+ *
166
+ * Uses two data structures for correctness:
167
+ * - `chain` (Set): tracks the current ancestor path from root to
168
+ * detect cycles. Added on entry, deleted on backtrack. A path
169
+ * appearing twice in the chain IS a cycle.
170
+ * - `visited` (Map): deduplicates diamonds. If a file was already
171
+ * built by a sibling branch, returns the existing node instead of
172
+ * re-reading. A path appearing in visited but not in chain is a
173
+ * diamond (safe), not a cycle.
174
+ *
175
+ * Throws on: cycles, missing files, parse errors.
176
+ */
177
+ export declare function buildTeamTree(rootPath: string, chain?: Set<string>, visited?: Map<string, TeamTreeNode>): TeamTreeNode;
178
+ /**
179
+ * Collect all unique nodes in the tree in post-order (children before
180
+ * parent). Used by `create` for depth-first seeding and by `lint`
181
+ * for per-node reporting.
182
+ */
183
+ export declare function postOrderNodes(root: TeamTreeNode): TeamTreeNode[];
@@ -0,0 +1,146 @@
1
+ import type { ProviderName } from "../types.js";
2
+ export type { ProviderName };
3
+ /** Valid member roles. */
4
+ export type MemberRole = "coder" | "reviewer" | "leader";
5
+ /** A team member — corresponds to [team.member] section. */
6
+ export interface MemberEntry {
7
+ /** Team name (from section name, before the dot). */
8
+ team: string;
9
+ /** Member alias (from section name, after the dot). */
10
+ alias: string;
11
+ /** Provider name = tool identity. */
12
+ provider: ProviderName;
13
+ /** Native session ID. Absent for pending slots. */
14
+ session?: string;
15
+ /** Role within the team. */
16
+ role: MemberRole;
17
+ /** Absolute runtime sessiondir for this session. */
18
+ sessiondir?: string;
19
+ /** Optional profile name. */
20
+ profile?: string;
21
+ /** Optional description. */
22
+ description?: string;
23
+ }
24
+ /** An orphaned session — corresponds to [orphaned.name] section. */
25
+ export interface OrphanedEntry {
26
+ /** Alias (from section name, after "orphaned."). */
27
+ alias: string;
28
+ /** Provider name = tool identity. */
29
+ provider: ProviderName;
30
+ /** Native session ID. */
31
+ session?: string;
32
+ /** Absolute path to session working directory. */
33
+ sessiondir: string;
34
+ /** Optional description. */
35
+ description?: string;
36
+ /** Optional profile name. */
37
+ profile?: string;
38
+ }
39
+ /** A team — corresponds to [team] section. */
40
+ export interface TeamEntry {
41
+ /** Team name (from section header). */
42
+ name: string;
43
+ /** Team description. */
44
+ description?: string;
45
+ /** Absolute path to the actual code/project directory for this team. */
46
+ workdir?: string;
47
+ }
48
+ /** Full parsed representation of an lmctl.config file. */
49
+ export interface WorkspaceConfig {
50
+ /** Workspace name (bare key at top of file). */
51
+ name: string;
52
+ /** Teams indexed by name. */
53
+ teams: Record<string, TeamEntry>;
54
+ /** All team members. */
55
+ members: MemberEntry[];
56
+ /** Standalone sessions not in any team. */
57
+ orphaned: OrphanedEntry[];
58
+ /** PM session pointer (top-level, optional). */
59
+ pmProvider?: ProviderName;
60
+ pmSession?: string;
61
+ /** Absolute runtime sessiondir for the PM session. */
62
+ pmSessiondir?: string;
63
+ }
64
+ /** A validation error found by validateConfig. */
65
+ export interface ValidationError {
66
+ field: string;
67
+ message: string;
68
+ }
69
+ /** Result of a find operation (append-only discovery). */
70
+ export interface FindResult {
71
+ added: number;
72
+ errors: string[];
73
+ }
74
+ /** Provider names that cannot be used as member aliases. */
75
+ export declare const RESERVED_NAMES: ReadonlySet<string>;
76
+ /** All valid provider names. */
77
+ export declare const VALID_PROVIDERS: ReadonlySet<string>;
78
+ /** Providers allowed for orchestrator roles (leader).
79
+ * All providers allowed. Codex leaders use exec_command with yield-based
80
+ * polling for shell commands. Long lmctl chat turns may need multiple
81
+ * polls (yield_time_ms up to 30s, then re-poll). The Codex model
82
+ * sometimes gives up too early — a behavioral issue, not a platform limit. */
83
+ export declare const VALID_ORCHESTRATOR_PROVIDERS: ReadonlySet<string>;
84
+ /** All valid member roles. */
85
+ export declare const VALID_ROLES: ReadonlySet<string>;
86
+ /** User-scoped tool configuration from ~/.lmctl/config.toml. */
87
+ export interface ToolProfileConfig {
88
+ description?: string;
89
+ flags?: string;
90
+ }
91
+ export interface ToolConfig {
92
+ start?: string;
93
+ resume?: string;
94
+ /** Optional override for the non-interactive one-shot command. */
95
+ agent?: string;
96
+ profiles?: Record<string, ToolProfileConfig>;
97
+ /** Legacy fallback for older configs written before named profiles existed. */
98
+ profile_flag?: string;
99
+ }
100
+ /** Per-provider compact threshold overrides. Either or both may be present. */
101
+ export interface CompactProviderConfig {
102
+ /** Minimum context tokens before `lmctl compact` will even prompt. */
103
+ min?: number;
104
+ /** Context tokens at or above which `lmctl compact` auto-runs without prompting. */
105
+ max?: number;
106
+ }
107
+ /** Compaction-gate configuration parsed from the [compact] / [compact.<provider>]
108
+ * sections of ~/.lmctl/config.toml. The resolver
109
+ * (`resolveCompactThresholds`) applies precedence: provider override beats
110
+ * global beats built-in defaults. */
111
+ export interface CompactConfig {
112
+ /** Global defaults for any provider that has no override. */
113
+ global?: CompactProviderConfig;
114
+ /** Per-provider overrides keyed by provider name (claude, codex, ...). */
115
+ providers?: Record<string, CompactProviderConfig>;
116
+ }
117
+ /** Full parsed representation of ~/.lmctl/config.toml. */
118
+ export interface UserConfig {
119
+ tools: Record<string, ToolConfig>;
120
+ /** Optional compaction gating thresholds. Absent ⇒ all defaults. */
121
+ compact?: CompactConfig;
122
+ /** Optional operator-chosen name for this environment/computer (flat
123
+ * top-level `site_name = "..."` key). Purely informational today; the
124
+ * forward motivation is cross-site agent identification, but nothing
125
+ * requires it — readers must treat absence as normal. */
126
+ site_name?: string;
127
+ }
128
+ /** Get the leader of a team (if any). */
129
+ export declare function getTeamLeader(config: WorkspaceConfig, teamName: string): MemberEntry | undefined;
130
+ /** Get all members of a team. */
131
+ export declare function getTeamMembers(config: WorkspaceConfig, teamName: string): MemberEntry[];
132
+ /** Check if a team is managed (has a leader). */
133
+ export declare function isTeamManaged(config: WorkspaceConfig, teamName: string): boolean;
134
+ /** Check whether a provider can be used for orchestrator roles (PM, leader). */
135
+ export declare function isValidOrchestratorProvider(provider: string): boolean;
136
+ /**
137
+ * Find any member or orphaned entry by native session ID.
138
+ * Returns the entry and whether it's a member or orphaned.
139
+ */
140
+ export declare function findBySessionId(config: WorkspaceConfig, sessionId: string): {
141
+ type: "member";
142
+ entry: MemberEntry;
143
+ } | {
144
+ type: "orphaned";
145
+ entry: OrphanedEntry;
146
+ } | null;
@@ -0,0 +1,88 @@
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 {};
@@ -0,0 +1,21 @@
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 {};