@almyty/runner 1.2.0

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 (59) hide show
  1. package/README.md +72 -0
  2. package/dist/binaries.d.ts +30 -0
  3. package/dist/binaries.js +99 -0
  4. package/dist/binaries.js.map +1 -0
  5. package/dist/cli.d.ts +12 -0
  6. package/dist/cli.js +128 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/coding-agents/detect.d.ts +12 -0
  9. package/dist/coding-agents/detect.js +35 -0
  10. package/dist/coding-agents/detect.js.map +1 -0
  11. package/dist/coding-agents/index.d.ts +15 -0
  12. package/dist/coding-agents/index.js +15 -0
  13. package/dist/coding-agents/index.js.map +1 -0
  14. package/dist/coding-agents/registry.d.ts +9 -0
  15. package/dist/coding-agents/registry.js +260 -0
  16. package/dist/coding-agents/registry.js.map +1 -0
  17. package/dist/coding-agents/spawn-spec.d.ts +47 -0
  18. package/dist/coding-agents/spawn-spec.js +58 -0
  19. package/dist/coding-agents/spawn-spec.js.map +1 -0
  20. package/dist/coding-agents/status.d.ts +38 -0
  21. package/dist/coding-agents/status.js +111 -0
  22. package/dist/coding-agents/status.js.map +1 -0
  23. package/dist/coding-agents/types.d.ts +104 -0
  24. package/dist/coding-agents/types.js +18 -0
  25. package/dist/coding-agents/types.js.map +1 -0
  26. package/dist/coding-sessions.d.ts +80 -0
  27. package/dist/coding-sessions.js +121 -0
  28. package/dist/coding-sessions.js.map +1 -0
  29. package/dist/config.d.ts +49 -0
  30. package/dist/config.js +180 -0
  31. package/dist/config.js.map +1 -0
  32. package/dist/daemon.d.ts +71 -0
  33. package/dist/daemon.js +353 -0
  34. package/dist/daemon.js.map +1 -0
  35. package/dist/handlers.d.ts +39 -0
  36. package/dist/handlers.js +299 -0
  37. package/dist/handlers.js.map +1 -0
  38. package/dist/index.d.ts +17 -0
  39. package/dist/index.js +18 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/policy.d.ts +16 -0
  42. package/dist/policy.js +134 -0
  43. package/dist/policy.js.map +1 -0
  44. package/dist/process-manager.d.ts +107 -0
  45. package/dist/process-manager.js +334 -0
  46. package/dist/process-manager.js.map +1 -0
  47. package/dist/protocol.d.ts +53 -0
  48. package/dist/protocol.js +39 -0
  49. package/dist/protocol.js.map +1 -0
  50. package/dist/runtime-info.d.ts +23 -0
  51. package/dist/runtime-info.js +35 -0
  52. package/dist/runtime-info.js.map +1 -0
  53. package/dist/streamable-client.d.ts +69 -0
  54. package/dist/streamable-client.js +204 -0
  55. package/dist/streamable-client.js.map +1 -0
  56. package/dist/types.d.ts +112 -0
  57. package/dist/types.js +21 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +54 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Coding-agent platform catalog — the runner's port of maco's driver registry.
3
+ *
4
+ * One entry per CLI. Binary names, provider families, API-key env vars,
5
+ * config-dir env vars, auto-approve flags, resume mechanisms, and status-marker
6
+ * tables are sourced from maco's drivers (maco-core/src/drivers/*.rs) and the
7
+ * researched feature matrix (maco/docs/briefs/cli-feature-matrix.md, 2026-06-24).
8
+ *
9
+ * Adding a platform = adding a row here. No code branches anywhere else key off
10
+ * the CLI id; everything (detection, spawn-spec, status) reads this table.
11
+ */
12
+ import { SPINNER_GLYPHS, PULSE_GLYPHS } from './status.js';
13
+ /** Most CLIs share Claude's prompt/busy shape; start from this and tweak. */
14
+ function defaultStatus(over = {}) {
15
+ return {
16
+ busySubstrings: ['esc to interrupt', 'ctrl+c to interrupt'],
17
+ spinnerGlyphs: SPINNER_GLYPHS,
18
+ promptPrefixes: ['> '],
19
+ promptContains: [],
20
+ promptExact: ['>'],
21
+ ...over,
22
+ };
23
+ }
24
+ export const CODING_AGENTS = {
25
+ claude: {
26
+ id: 'claude',
27
+ displayName: 'Claude Code',
28
+ shortCode: 'cl',
29
+ binary: 'claude',
30
+ binaryAliases: [],
31
+ providerFamily: 'anthropic',
32
+ apiKeyEnvVars: ['ANTHROPIC_API_KEY'],
33
+ configDirEnvVar: 'CLAUDE_CONFIG_DIR',
34
+ autoApproveArgs: ['--dangerously-skip-permissions'],
35
+ baseArgs: [],
36
+ session: { kind: 'resume-flag' },
37
+ supportsMcp: true,
38
+ canManage: true,
39
+ status: defaultStatus({ promptPrefixes: ['>'], promptContains: ['│ >'] }),
40
+ },
41
+ codex: {
42
+ id: 'codex',
43
+ displayName: 'Codex',
44
+ shortCode: 'cx',
45
+ binary: 'codex',
46
+ binaryAliases: [],
47
+ providerFamily: 'openai',
48
+ apiKeyEnvVars: ['OPENAI_API_KEY'],
49
+ configDirEnvVar: 'CODEX_HOME',
50
+ autoApproveArgs: ['--dangerously-bypass-approvals-and-sandbox'],
51
+ baseArgs: [],
52
+ session: { kind: 'exec-resume' },
53
+ supportsMcp: true,
54
+ canManage: true,
55
+ status: defaultStatus({
56
+ busySubstrings: ['esc to interrupt', 'working'],
57
+ promptPrefixes: ['>>', '> '],
58
+ promptExact: ['>'],
59
+ }),
60
+ },
61
+ gemini: {
62
+ id: 'gemini',
63
+ displayName: 'Gemini CLI',
64
+ shortCode: 'gm',
65
+ binary: 'gemini',
66
+ binaryAliases: [],
67
+ providerFamily: 'google',
68
+ apiKeyEnvVars: ['GEMINI_API_KEY', 'GOOGLE_API_KEY'],
69
+ configDirEnvVar: null,
70
+ autoApproveArgs: ['--yolo'],
71
+ baseArgs: [],
72
+ session: { kind: 'resume-flag' },
73
+ supportsMcp: true,
74
+ canManage: true,
75
+ status: defaultStatus({
76
+ busySubstrings: ['esc to interrupt', 'esc to cancel'],
77
+ promptContains: ['gemini>'],
78
+ }),
79
+ },
80
+ cursor: {
81
+ id: 'cursor',
82
+ displayName: 'Cursor Agent',
83
+ shortCode: 'cu',
84
+ binary: 'cursor-agent',
85
+ // NOTE: no bare 'agent' alias — it collides with other tools that install
86
+ // an `agent` binary (e.g. grok), causing false-positive detection. The real
87
+ // Cursor CLI binary is `cursor-agent`.
88
+ binaryAliases: [],
89
+ providerFamily: 'cursor',
90
+ apiKeyEnvVars: ['CURSOR_API_KEY'],
91
+ configDirEnvVar: null,
92
+ autoApproveArgs: ['--force'],
93
+ baseArgs: [],
94
+ session: { kind: 'resume-flag' },
95
+ supportsMcp: true,
96
+ canManage: true,
97
+ status: defaultStatus(),
98
+ },
99
+ opencode: {
100
+ id: 'opencode',
101
+ displayName: 'OpenCode',
102
+ shortCode: 'oc',
103
+ binary: 'opencode',
104
+ binaryAliases: [],
105
+ providerFamily: 'unknown',
106
+ apiKeyEnvVars: ['ANTHROPIC_API_KEY', 'OPENAI_API_KEY'],
107
+ configDirEnvVar: null,
108
+ autoApproveArgs: [],
109
+ baseArgs: [],
110
+ session: { kind: 'session-flag' },
111
+ supportsMcp: true,
112
+ canManage: true,
113
+ status: defaultStatus({
114
+ busySubstrings: ['esc interrupt', 'esc to exit', 'thinking...', 'generating...'],
115
+ spinnerGlyphs: PULSE_GLYPHS,
116
+ promptContains: ['ask anything'],
117
+ }),
118
+ },
119
+ crush: {
120
+ id: 'crush',
121
+ displayName: 'Crush',
122
+ shortCode: 'cr',
123
+ binary: 'crush',
124
+ binaryAliases: [],
125
+ providerFamily: 'unknown',
126
+ apiKeyEnvVars: ['ANTHROPIC_API_KEY', 'OPENAI_API_KEY'],
127
+ configDirEnvVar: null,
128
+ autoApproveArgs: ['--yolo'],
129
+ baseArgs: [],
130
+ session: { kind: 'session-flag' },
131
+ supportsMcp: true,
132
+ canManage: true,
133
+ status: defaultStatus(),
134
+ },
135
+ copilot: {
136
+ id: 'copilot',
137
+ displayName: 'GitHub Copilot CLI',
138
+ shortCode: 'cp',
139
+ binary: 'copilot',
140
+ binaryAliases: [],
141
+ providerFamily: 'github',
142
+ apiKeyEnvVars: ['COPILOT_GITHUB_TOKEN', 'GITHUB_TOKEN'],
143
+ configDirEnvVar: 'COPILOT_HOME',
144
+ autoApproveArgs: ['--yolo'],
145
+ baseArgs: [],
146
+ session: { kind: 'session-id-flag' },
147
+ supportsMcp: true,
148
+ canManage: true,
149
+ status: defaultStatus({ promptContains: ['copilot>'] }),
150
+ },
151
+ grok: {
152
+ id: 'grok',
153
+ displayName: 'Grok CLI',
154
+ shortCode: 'gr',
155
+ binary: 'grok',
156
+ binaryAliases: [],
157
+ providerFamily: 'xai',
158
+ apiKeyEnvVars: ['XAI_API_KEY'],
159
+ configDirEnvVar: null,
160
+ // grok needs --no-alt-screen so its output renders in the scrollback we scrape.
161
+ autoApproveArgs: ['--always-approve', '--no-alt-screen'],
162
+ baseArgs: [],
163
+ session: { kind: 'session-id-flag' },
164
+ supportsMcp: true,
165
+ canManage: true,
166
+ status: defaultStatus(),
167
+ },
168
+ hermes: {
169
+ id: 'hermes',
170
+ displayName: 'Hermes',
171
+ shortCode: 'hr',
172
+ binary: 'hermes',
173
+ binaryAliases: [],
174
+ providerFamily: 'nous',
175
+ apiKeyEnvVars: ['ANTHROPIC_API_KEY', 'OPENAI_API_KEY'],
176
+ configDirEnvVar: 'HERMES_HOME',
177
+ autoApproveArgs: ['--yolo'],
178
+ baseArgs: [],
179
+ session: { kind: 'resume-flag' },
180
+ supportsMcp: true,
181
+ canManage: true,
182
+ status: defaultStatus(),
183
+ },
184
+ mistral_vibe: {
185
+ id: 'mistral_vibe',
186
+ displayName: 'Mistral Vibe',
187
+ shortCode: 'mv',
188
+ binary: 'vibe',
189
+ binaryAliases: ['mistral-vibe'],
190
+ providerFamily: 'mistral',
191
+ apiKeyEnvVars: ['MISTRAL_API_KEY'],
192
+ configDirEnvVar: 'VIBE_HOME',
193
+ autoApproveArgs: ['--yolo'],
194
+ baseArgs: [],
195
+ session: { kind: 'resume-flag' },
196
+ supportsMcp: true,
197
+ canManage: true,
198
+ status: defaultStatus(),
199
+ },
200
+ openclaw: {
201
+ id: 'openclaw',
202
+ displayName: 'OpenClaw',
203
+ shortCode: 'ow',
204
+ binary: 'openclaw',
205
+ binaryAliases: [],
206
+ providerFamily: 'unknown',
207
+ apiKeyEnvVars: ['OPENAI_API_KEY', 'ANTHROPIC_API_KEY'],
208
+ configDirEnvVar: 'OPENCLAW_CONFIG_PATH',
209
+ autoApproveArgs: ['exec-policy', 'preset', 'yolo'],
210
+ baseArgs: ['chat', '--local'],
211
+ session: { kind: 'session-id-flag' },
212
+ supportsMcp: true,
213
+ canManage: true,
214
+ status: defaultStatus(),
215
+ },
216
+ // aider is not a maco driver, but the runner already probed it and it's a
217
+ // widely used coding CLI; include it so detection/spawn cover it too.
218
+ aider: {
219
+ id: 'aider',
220
+ displayName: 'Aider',
221
+ shortCode: 'ai',
222
+ binary: 'aider',
223
+ binaryAliases: [],
224
+ providerFamily: 'unknown',
225
+ apiKeyEnvVars: ['ANTHROPIC_API_KEY', 'OPENAI_API_KEY'],
226
+ configDirEnvVar: null,
227
+ autoApproveArgs: ['--yes-always'],
228
+ baseArgs: [],
229
+ session: { kind: 'none' },
230
+ supportsMcp: false,
231
+ canManage: false,
232
+ status: defaultStatus(),
233
+ },
234
+ };
235
+ export const CODING_AGENT_IDS = Object.keys(CODING_AGENTS);
236
+ export function listCodingAgents() {
237
+ return CODING_AGENT_IDS.map((id) => CODING_AGENTS[id]);
238
+ }
239
+ export function getCodingAgent(id) {
240
+ return CODING_AGENTS[id];
241
+ }
242
+ /** Resolve a spec by binary name or alias (e.g. "cursor-agent" → cursor). */
243
+ export function findByBinary(binaryName) {
244
+ for (const spec of listCodingAgents()) {
245
+ if (spec.binary === binaryName || spec.binaryAliases.includes(binaryName))
246
+ return spec;
247
+ }
248
+ return undefined;
249
+ }
250
+ /** Every binary name (primary + aliases) for the probe list. */
251
+ export function allProbeBinaries() {
252
+ const set = new Set();
253
+ for (const spec of listCodingAgents()) {
254
+ set.add(spec.binary);
255
+ for (const a of spec.binaryAliases)
256
+ set.add(a);
257
+ }
258
+ return [...set];
259
+ }
260
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/coding-agents/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Build a runner SpawnOptions for a coding-agent platform.
3
+ *
4
+ * This is the lever maco drives from its driver layer (`coordination_argv`,
5
+ * `coordination_env`, auto-approve, resume), narrowed to what the runner needs
6
+ * to launch an unattended member:
7
+ *
8
+ * - inject the provider API key into the CLI's env (headless auth — under an
9
+ * isolated config home the normal credential file is absent);
10
+ * - isolate the CLI's config/auth/session home via its dedicated env var
11
+ * (CODEX_HOME, CLAUDE_CONFIG_DIR, …) so parallel members don't collide;
12
+ * - add the auto-approve flag so the member doesn't stop on per-tool prompts;
13
+ * - add resume argv when continuing a prior session;
14
+ * - optionally pin a model.
15
+ *
16
+ * The result is a plain SpawnOptions the existing ProcessManager runs as-is;
17
+ * the runner's execution policy still applies on top.
18
+ */
19
+ import type { SpawnOptions } from '../types.js';
20
+ import type { CodingAgentSpec } from './types.js';
21
+ export interface AgentSpawnInput {
22
+ /** Provider API key to inject (matched to the CLI's first apiKeyEnvVar). */
23
+ apiKey?: string;
24
+ /** Explicit env var name for the key, overriding the spec's default order. */
25
+ apiKeyEnvVar?: string;
26
+ /**
27
+ * Isolated config/auth/session home for this member. Set on the CLI's
28
+ * dedicated env var if it has one; otherwise exported as HOME so the CLI's
29
+ * default ~/.<cli> path relocates under it.
30
+ */
31
+ configDir?: string;
32
+ /** Skip per-tool permission prompts (unattended member). Default true. */
33
+ autoApprove?: boolean;
34
+ /** Pin a model where the CLI's argv supports it (best-effort, claude/gemini). */
35
+ model?: string;
36
+ /** Resume a prior session id (uses the spec's SessionFlavor). */
37
+ resumeSessionId?: string;
38
+ /** Extra argv appended last (e.g. a one-shot prompt or CLI-specific flags). */
39
+ extraArgs?: string[];
40
+ /** Working directory for the member. */
41
+ cwd?: string;
42
+ /** Base env to extend. Defaults to {} (policy/process-manager add the rest). */
43
+ baseEnv?: Record<string, string>;
44
+ }
45
+ /** Argv that resumes a session for this CLI, or [] if unsupported. */
46
+ export declare function resumeArgv(spec: CodingAgentSpec, sessionId: string): string[];
47
+ export declare function buildAgentSpawn(spec: CodingAgentSpec, input?: AgentSpawnInput): SpawnOptions;
@@ -0,0 +1,58 @@
1
+ /** Argv that resumes a session for this CLI, or [] if unsupported. */
2
+ export function resumeArgv(spec, sessionId) {
3
+ switch (spec.session.kind) {
4
+ case 'resume-flag': return ['--resume', sessionId];
5
+ case 'session-id-flag': return ['--session-id', sessionId];
6
+ case 'session-flag': return ['--session', sessionId];
7
+ case 'exec-resume': return ['exec', 'resume', sessionId];
8
+ case 'none': return [];
9
+ }
10
+ }
11
+ /** Best-effort model-pin argv (only the CLIs that take a plain --model flag). */
12
+ function modelArgv(spec, model) {
13
+ if (spec.id === 'claude' || spec.id === 'gemini')
14
+ return ['--model', model];
15
+ return [];
16
+ }
17
+ export function buildAgentSpawn(spec, input = {}) {
18
+ const args = [...spec.baseArgs];
19
+ // Resume vs fresh session.
20
+ if (input.resumeSessionId) {
21
+ args.push(...resumeArgv(spec, input.resumeSessionId));
22
+ }
23
+ // Auto-approve (default on — these members run unattended).
24
+ if (input.autoApprove !== false) {
25
+ args.push(...spec.autoApproveArgs);
26
+ }
27
+ // Model pin where supported.
28
+ if (input.model) {
29
+ args.push(...modelArgv(spec, input.model));
30
+ }
31
+ // Caller extras last so they can override.
32
+ if (input.extraArgs?.length) {
33
+ args.push(...input.extraArgs);
34
+ }
35
+ const env = { ...(input.baseEnv ?? {}) };
36
+ // Headless auth: inject the provider key on the CLI's expected env var.
37
+ if (input.apiKey) {
38
+ const keyVar = input.apiKeyEnvVar ?? spec.apiKeyEnvVars[0];
39
+ if (keyVar)
40
+ env[keyVar] = input.apiKey;
41
+ }
42
+ // Config/auth/session isolation. Prefer the CLI's dedicated env var; fall
43
+ // back to HOME so the default ~/.<cli> path relocates under the isolated dir.
44
+ if (input.configDir) {
45
+ if (spec.configDirEnvVar)
46
+ env[spec.configDirEnvVar] = input.configDir;
47
+ else
48
+ env.HOME = input.configDir;
49
+ }
50
+ return {
51
+ binary: spec.binary,
52
+ args,
53
+ env: Object.keys(env).length ? env : undefined,
54
+ pty: true,
55
+ cwd: input.cwd,
56
+ };
57
+ }
58
+ //# sourceMappingURL=spawn-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn-spec.js","sourceRoot":"","sources":["../../src/coding-agents/spawn-spec.ts"],"names":[],"mappings":"AA8CA,sEAAsE;AACtE,MAAM,UAAU,UAAU,CAAC,IAAqB,EAAE,SAAiB;IACjE,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC1B,KAAK,aAAa,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACnD,KAAK,iBAAiB,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QAC3D,KAAK,cAAc,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACrD,KAAK,aAAa,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,SAAS,SAAS,CAAC,IAAqB,EAAE,KAAa;IACrD,IAAI,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC5E,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAqB,EAAE,QAAyB,EAAE;IAChF,MAAM,IAAI,GAAa,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE1C,2BAA2B;IAC3B,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,4DAA4D;IAC5D,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,6BAA6B;IAC7B,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,2CAA2C;IAC3C,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,GAAG,GAA2B,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;IAEjE,wEAAwE;IACxE,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC3D,IAAI,MAAM;YAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACzC,CAAC;IAED,0EAA0E;IAC1E,8EAA8E;IAC9E,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,IAAI,IAAI,CAAC,eAAe;YAAE,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;;YACjE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,CAAC;IAED,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,IAAI;QACJ,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QAC9C,GAAG,EAAE,IAAI;QACT,GAAG,EAAE,KAAK,CAAC,GAAG;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Two-tier status detection — Tier 2 (VT scrape), ported from maco's
3
+ * `state/patterns.rs` + `detector.rs`.
4
+ *
5
+ * When no fresh lifecycle signal is available, scrape the rendered terminal
6
+ * screen for busy/prompt markers. Detection is BUSY-FIRST: a live
7
+ * "esc to interrupt" marker or an active spinner glyph is authoritative; only
8
+ * when NOT busy do we look at the prompt. Auth/error gates are checked before
9
+ * the prompt so a member stuck on a sign-in screen reads as `awaiting_auth`,
10
+ * not idle.
11
+ *
12
+ * The per-CLI markers are DATA (registry.ts → spec.status), so tuning a CLI is
13
+ * a table edit. This module is the matcher only.
14
+ */
15
+ import type { AgentStatus, StatusPatterns } from './types.js';
16
+ /** Spinner glyphs shared across most CLIs (verbatim from maco). */
17
+ export declare const SPINNER_GLYPHS: string[];
18
+ /** opencode adds a block-shaded pulse on top of the braille set. */
19
+ export declare const PULSE_GLYPHS: string[];
20
+ /**
21
+ * Cross-CLI auth-gate markers. A member stuck here is blocked on a human, not
22
+ * working — surfaced as a distinct state so an orchestrator can inject a key or
23
+ * answer the prompt rather than waiting forever. (maco's AwaitingAuth state.)
24
+ */
25
+ export declare const AUTH_MARKERS: string[];
26
+ /** Cross-CLI fatal-error markers. */
27
+ export declare const ERROR_MARKERS: string[];
28
+ export declare function stripVtEscapes(s: string): string;
29
+ export declare function lastFrameResetIndex(s: string): number;
30
+ /**
31
+ * Classify a rendered screen for one CLI. `screen` is the visible VT text
32
+ * (already de-escaped to plain characters by the caller / process manager).
33
+ *
34
+ * Order: busy → auth → error → idle-prompt → unknown. Busy wins because a CLI
35
+ * often keeps a prompt line on screen while working; the active-work marker is
36
+ * the truth.
37
+ */
38
+ export declare function classifyStatus(patterns: StatusPatterns, screen: string): AgentStatus;
@@ -0,0 +1,111 @@
1
+ /** Spinner glyphs shared across most CLIs (verbatim from maco). */
2
+ export const SPINNER_GLYPHS = [
3
+ '·', '✶', '✷', '✸', '✹', '★', '◐', '◓', '◑', '◒',
4
+ '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏',
5
+ ];
6
+ /** opencode adds a block-shaded pulse on top of the braille set. */
7
+ export const PULSE_GLYPHS = [...SPINNER_GLYPHS, '█', '▓', '▒', '░'];
8
+ /**
9
+ * Cross-CLI auth-gate markers. A member stuck here is blocked on a human, not
10
+ * working — surfaced as a distinct state so an orchestrator can inject a key or
11
+ * answer the prompt rather than waiting forever. (maco's AwaitingAuth state.)
12
+ */
13
+ export const AUTH_MARKERS = [
14
+ 'sign in to', 'sign in with', 'please log in', 'please sign in',
15
+ 'press enter to authenticate', 'press enter to login', 'paste your api key',
16
+ 'enter your api key', 'authentication required', 'select auth', 'how would you like to authenticate',
17
+ 'login with', '/login', 'terms of service', 'accept the terms', 'waiting for authentication',
18
+ ];
19
+ /** Cross-CLI fatal-error markers. */
20
+ export const ERROR_MARKERS = [
21
+ 'panic:', 'fatal error', 'traceback (most recent call last)',
22
+ 'segmentation fault', 'command not found', 'econnrefused',
23
+ 'rate limit exceeded', 'quota exceeded', 'authentication failed',
24
+ 'invalid api key', 'unhandled exception',
25
+ ];
26
+ /**
27
+ * Strip VT/ANSI escape sequences so the classifier sees plain text. PTY output
28
+ * is full of CSI color/cursor codes and OSC title sets; the markers we match
29
+ * (prompts, "esc to interrupt") are plain characters underneath.
30
+ */
31
+ // eslint-disable-next-line no-control-regex
32
+ const ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;
33
+ export function stripVtEscapes(s) {
34
+ return s.replace(ANSI_RE, '');
35
+ }
36
+ /**
37
+ * Alt-screen TUIs (claude, gemini, …) repaint each frame from the top: an
38
+ * erase-display or cursor-home sequence starts a fresh frame, so everything
39
+ * before it on the previous frame is stale. Return the index in `s` where the
40
+ * LAST such frame-reset begins, or -1 if there is none. The caller keeps only
41
+ * the bytes from that point so a status line that has since been cleared (e.g.
42
+ * "esc to interrupt") doesn't linger in an append log and falsely read busy.
43
+ */
44
+ // eslint-disable-next-line no-control-regex
45
+ const FRAME_RESET_RE = /\x1b\[(?:2J|3J|H|1;1H|0;0H)/g;
46
+ export function lastFrameResetIndex(s) {
47
+ let idx = -1;
48
+ for (const m of s.matchAll(FRAME_RESET_RE))
49
+ idx = m.index;
50
+ return idx;
51
+ }
52
+ /** The last N non-blank lines of the screen — where prompts live. */
53
+ function tailLines(screen, n) {
54
+ const lines = screen.split('\n').map((l) => l.replace(/\r$/, ''));
55
+ const nonBlank = lines.filter((l) => l.trim().length > 0);
56
+ return nonBlank.slice(-n);
57
+ }
58
+ function anyLineStartsWithSpinner(screen, glyphs) {
59
+ for (const raw of screen.split('\n')) {
60
+ const line = raw.replace(/\r$/, '');
61
+ const trimmed = line.trimStart();
62
+ if (trimmed.length > 0 && glyphs.includes(trimmed[0]))
63
+ return true;
64
+ }
65
+ return false;
66
+ }
67
+ /**
68
+ * Classify a rendered screen for one CLI. `screen` is the visible VT text
69
+ * (already de-escaped to plain characters by the caller / process manager).
70
+ *
71
+ * Order: busy → auth → error → idle-prompt → unknown. Busy wins because a CLI
72
+ * often keeps a prompt line on screen while working; the active-work marker is
73
+ * the truth.
74
+ */
75
+ export function classifyStatus(patterns, screen) {
76
+ const lower = screen.toLowerCase();
77
+ // ── Tier 2a: BUSY (authoritative) ──
78
+ for (const sub of patterns.busySubstrings) {
79
+ if (lower.includes(sub))
80
+ return 'busy';
81
+ }
82
+ if (anyLineStartsWithSpinner(screen, patterns.spinnerGlyphs))
83
+ return 'busy';
84
+ // ── auth gate before prompt: a sign-in screen is not "idle" ──
85
+ const tail = tailLines(screen, 12);
86
+ const tailLower = tail.join('\n').toLowerCase();
87
+ for (const m of AUTH_MARKERS) {
88
+ if (tailLower.includes(m))
89
+ return 'awaiting_auth';
90
+ }
91
+ for (const m of ERROR_MARKERS) {
92
+ if (lower.includes(m))
93
+ return 'error';
94
+ }
95
+ // ── Tier 2b: IDLE PROMPT ──
96
+ const bottom = tailLines(screen, 3);
97
+ for (const line of bottom) {
98
+ const trimmedStart = line.trimStart();
99
+ const trimmed = line.trim();
100
+ if (patterns.promptExact.includes(trimmed))
101
+ return 'idle';
102
+ if (patterns.promptPrefixes.some((p) => trimmedStart.startsWith(p)))
103
+ return 'idle';
104
+ if (patterns.promptContains.some((c) => line.includes(c)))
105
+ return 'idle';
106
+ }
107
+ // No marker matched. The caller decides; for an actively-streaming pane this
108
+ // usually means "still busy", but we don't assert it here.
109
+ return 'unknown';
110
+ }
111
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/coding-agents/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Coding-agent platform model.
3
+ *
4
+ * The runner's generic process surface can spawn any binary, but driving a
5
+ * coding CLI unattended needs per-CLI knowledge: the real binary name, the
6
+ * provider API-key env var, the "relocate my whole config/auth/session home"
7
+ * env var (so members don't fight over one shared ~/.config), the auto-approve
8
+ * flag that skips per-tool permission prompts, the resume mechanism, and the
9
+ * VT markers that say whether the pane is busy / idle / waiting on the human.
10
+ *
11
+ * This mirrors maco's `CliDriver` trait, narrowed to what the runner needs:
12
+ * detect → build a spawn spec → classify live status. The catalog is DATA
13
+ * (one entry per CLI in registry.ts) so adding a platform is a table edit,
14
+ * never a new code branch — same design point as maco's driver registry and
15
+ * its config-driven status-pattern tables.
16
+ */
17
+ /** Every coding CLI maco supports, by stable id. */
18
+ export type CodingAgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'crush' | 'copilot' | 'grok' | 'hermes' | 'mistral_vibe' | 'openclaw' | 'aider';
19
+ /**
20
+ * How a CLI resumes a prior session. The runner builds the resume argv from
21
+ * this + a session id. (Some CLIs have no resume mechanism we drive yet.)
22
+ */
23
+ export type SessionFlavor = {
24
+ kind: 'resume-flag';
25
+ } | {
26
+ kind: 'session-id-flag';
27
+ } | {
28
+ kind: 'session-flag';
29
+ } | {
30
+ kind: 'exec-resume';
31
+ } | {
32
+ kind: 'none';
33
+ };
34
+ /**
35
+ * Two-tier live status of a spawned coding-agent pane (maco's model):
36
+ * - busy: actively working (spinner / "esc to interrupt" present)
37
+ * - idle: at its prompt, ready for the next instruction
38
+ * - awaiting_input: stopped on a question/permission prompt for the human
39
+ * - awaiting_auth: stopped on a sign-in / API-key / ToS gate
40
+ * - error: a crash/fatal marker is on screen
41
+ * - unknown: no marker matched (caller decides; usually treat as busy)
42
+ */
43
+ export type AgentStatus = 'busy' | 'idle' | 'awaiting_input' | 'awaiting_auth' | 'error' | 'unknown';
44
+ /** Per-CLI VT scrape table — markers are data, matched busy-first. */
45
+ export interface StatusPatterns {
46
+ /** Lowercased substrings; presence anywhere ⇒ busy. Keep SPECIFIC. */
47
+ busySubstrings: string[];
48
+ /** First non-space char of any line is one of these ⇒ busy (spinner). */
49
+ spinnerGlyphs: string[];
50
+ /** A bottom line whose trimStart() starts with one of these ⇒ idle prompt. */
51
+ promptPrefixes: string[];
52
+ /** A bottom line that contains one of these (raw) ⇒ idle prompt. */
53
+ promptContains: string[];
54
+ /** A bottom line whose trim() equals one of these ⇒ idle prompt. */
55
+ promptExact: string[];
56
+ }
57
+ export interface CodingAgentSpec {
58
+ /** Stable id used by the agent.* RPC surface. */
59
+ id: CodingAgentId;
60
+ /** Human label, e.g. "Claude Code". */
61
+ displayName: string;
62
+ /** Two-letter code mirroring maco's short_code (status table key). */
63
+ shortCode: string;
64
+ /** The real executable name. */
65
+ binary: string;
66
+ /** Alternate names to also probe (e.g. cursor → cursor-agent). */
67
+ binaryAliases: string[];
68
+ /** Throttle-reroute family (maco's provider_family): 'anthropic', 'openai', … */
69
+ providerFamily: string;
70
+ /**
71
+ * Provider API-key env vars, in priority order. Under an isolated config
72
+ * home the normal credential file is absent, so the key is injected at spawn.
73
+ */
74
+ apiKeyEnvVars: string[];
75
+ /**
76
+ * The CLI's dedicated "relocate config+auth+sessions" env var, if it has one
77
+ * (CODEX_HOME, CLAUDE_CONFIG_DIR, COPILOT_HOME, …). Null ⇒ isolate via HOME.
78
+ */
79
+ configDirEnvVar: string | null;
80
+ /** Argv that skips per-tool permission prompts for an unattended member. */
81
+ autoApproveArgs: string[];
82
+ /** Argv prepended before everything (e.g. openclaw: ['chat','--local']). */
83
+ baseArgs: string[];
84
+ /** How to resume a prior session. */
85
+ session: SessionFlavor;
86
+ /** Does the CLI speak MCP (so the runner can inject coordination tools)? */
87
+ supportsMcp: boolean;
88
+ /** Can it act as the orchestrating manager (vs member-only)? */
89
+ canManage: boolean;
90
+ /** VT status-detection table. */
91
+ status: StatusPatterns;
92
+ }
93
+ /** A detected, on-PATH coding agent. */
94
+ export interface DetectedCodingAgent {
95
+ id: CodingAgentId;
96
+ displayName: string;
97
+ binary: string;
98
+ /** The binary name that actually resolved (may be an alias). */
99
+ resolvedBinary: string;
100
+ version: string;
101
+ providerFamily: string;
102
+ supportsMcp: boolean;
103
+ canManage: boolean;
104
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Coding-agent platform model.
3
+ *
4
+ * The runner's generic process surface can spawn any binary, but driving a
5
+ * coding CLI unattended needs per-CLI knowledge: the real binary name, the
6
+ * provider API-key env var, the "relocate my whole config/auth/session home"
7
+ * env var (so members don't fight over one shared ~/.config), the auto-approve
8
+ * flag that skips per-tool permission prompts, the resume mechanism, and the
9
+ * VT markers that say whether the pane is busy / idle / waiting on the human.
10
+ *
11
+ * This mirrors maco's `CliDriver` trait, narrowed to what the runner needs:
12
+ * detect → build a spawn spec → classify live status. The catalog is DATA
13
+ * (one entry per CLI in registry.ts) so adding a platform is a table edit,
14
+ * never a new code branch — same design point as maco's driver registry and
15
+ * its config-driven status-pattern tables.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=types.js.map