overmind-mcp 2.7.0 → 2.8.1

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 (104) hide show
  1. package/.mcp.json.example +21 -21
  2. package/README.md +179 -187
  3. package/bin/README.md +44 -34
  4. package/bin/install-overmind-windows.bat +51 -7
  5. package/bin/overmind-pool.mjs +248 -0
  6. package/dist/bin/cli.js +115 -24
  7. package/dist/bin/cli.js.map +1 -1
  8. package/dist/bin/overmind-client.d.ts +77 -0
  9. package/dist/bin/overmind-client.d.ts.map +1 -0
  10. package/dist/bin/overmind-client.js +221 -0
  11. package/dist/bin/overmind-client.js.map +1 -0
  12. package/dist/lib/agent_lifecycle.d.ts +91 -0
  13. package/dist/lib/agent_lifecycle.d.ts.map +1 -0
  14. package/dist/lib/agent_lifecycle.js +155 -0
  15. package/dist/lib/agent_lifecycle.js.map +1 -0
  16. package/dist/lib/config.d.ts +5 -26
  17. package/dist/lib/config.d.ts.map +1 -1
  18. package/dist/lib/config.js +33 -12
  19. package/dist/lib/config.js.map +1 -1
  20. package/dist/lib/envUtils.d.ts +1 -1
  21. package/dist/lib/envUtils.d.ts.map +1 -1
  22. package/dist/lib/envUtils.js +11 -4
  23. package/dist/lib/envUtils.js.map +1 -1
  24. package/dist/lib/loadEnv.d.ts.map +1 -1
  25. package/dist/lib/loadEnv.js +9 -4
  26. package/dist/lib/loadEnv.js.map +1 -1
  27. package/dist/lib/logger.d.ts.map +1 -1
  28. package/dist/lib/logger.js +20 -4
  29. package/dist/lib/logger.js.map +1 -1
  30. package/dist/lib/orchestration/dispatcher.d.ts.map +1 -1
  31. package/dist/lib/orchestration/dispatcher.js +10 -1
  32. package/dist/lib/orchestration/dispatcher.js.map +1 -1
  33. package/dist/lib/orchestration/swarm.d.ts +1 -0
  34. package/dist/lib/orchestration/swarm.d.ts.map +1 -1
  35. package/dist/lib/orchestration/swarm.js +11 -8
  36. package/dist/lib/orchestration/swarm.js.map +1 -1
  37. package/dist/lib/processRegistry.d.ts +2 -40
  38. package/dist/lib/processRegistry.d.ts.map +1 -1
  39. package/dist/lib/processRegistry.js +191 -230
  40. package/dist/lib/processRegistry.js.map +1 -1
  41. package/dist/memory/MemoryFactory.d.ts.map +1 -1
  42. package/dist/memory/MemoryFactory.js +2 -1
  43. package/dist/memory/MemoryFactory.js.map +1 -1
  44. package/dist/memory/PostgresMemoryProvider.d.ts +1 -0
  45. package/dist/memory/PostgresMemoryProvider.d.ts.map +1 -1
  46. package/dist/memory/PostgresMemoryProvider.js +11 -4
  47. package/dist/memory/PostgresMemoryProvider.js.map +1 -1
  48. package/dist/server.d.ts +1 -1
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +84 -80
  51. package/dist/server.js.map +1 -1
  52. package/dist/services/AgentManager.d.ts +1 -0
  53. package/dist/services/AgentManager.d.ts.map +1 -1
  54. package/dist/services/AgentManager.js +17 -0
  55. package/dist/services/AgentManager.js.map +1 -1
  56. package/dist/services/ClaudeRunner.d.ts.map +1 -1
  57. package/dist/services/ClaudeRunner.js +25 -6
  58. package/dist/services/ClaudeRunner.js.map +1 -1
  59. package/dist/services/ClineRunner.d.ts.map +1 -1
  60. package/dist/services/ClineRunner.js +16 -7
  61. package/dist/services/ClineRunner.js.map +1 -1
  62. package/dist/services/GeminiRunner.d.ts.map +1 -1
  63. package/dist/services/GeminiRunner.js +13 -6
  64. package/dist/services/GeminiRunner.js.map +1 -1
  65. package/dist/services/KiloRunner.d.ts.map +1 -1
  66. package/dist/services/KiloRunner.js +7 -4
  67. package/dist/services/KiloRunner.js.map +1 -1
  68. package/dist/services/OpenClawRunner.d.ts.map +1 -1
  69. package/dist/services/OpenClawRunner.js +16 -7
  70. package/dist/services/OpenClawRunner.js.map +1 -1
  71. package/dist/services/OpenCodeRunner.d.ts.map +1 -1
  72. package/dist/services/OpenCodeRunner.js +16 -7
  73. package/dist/services/OpenCodeRunner.js.map +1 -1
  74. package/dist/services/PromptManager.d.ts.map +1 -1
  75. package/dist/services/PromptManager.js +4 -0
  76. package/dist/services/PromptManager.js.map +1 -1
  77. package/dist/services/QwenCliRunner.d.ts.map +1 -1
  78. package/dist/services/QwenCliRunner.js +16 -7
  79. package/dist/services/QwenCliRunner.js.map +1 -1
  80. package/dist/tools/agent_control.d.ts +2 -69
  81. package/dist/tools/agent_control.d.ts.map +1 -1
  82. package/dist/tools/agent_control.js +186 -241
  83. package/dist/tools/agent_control.js.map +1 -1
  84. package/dist/tools/config_example.d.ts +2 -2
  85. package/dist/tools/config_example.d.ts.map +1 -1
  86. package/dist/tools/config_example.js +2 -4
  87. package/dist/tools/config_example.js.map +1 -1
  88. package/dist/tools/create_agent.d.ts.map +1 -1
  89. package/dist/tools/create_agent.js +11 -0
  90. package/dist/tools/create_agent.js.map +1 -1
  91. package/dist/tools/manage_agents.d.ts.map +1 -1
  92. package/dist/tools/manage_agents.js +3 -2
  93. package/dist/tools/manage_agents.js.map +1 -1
  94. package/dist/tools/run_agent.d.ts +1 -1
  95. package/dist/tools/run_agent.d.ts.map +1 -1
  96. package/dist/tools/run_agent.js +1 -2
  97. package/dist/tools/run_agent.js.map +1 -1
  98. package/dist/tools/run_agent_cli.d.ts +4 -10
  99. package/dist/tools/run_agent_cli.d.ts.map +1 -1
  100. package/dist/tools/run_agent_cli.js +10 -82
  101. package/dist/tools/run_agent_cli.js.map +1 -1
  102. package/dist/tools/run_agents_parallel.d.ts +1 -1
  103. package/docs/agent-http-tutorial.md +524 -0
  104. package/package.json +3 -3
@@ -0,0 +1,221 @@
1
+ /**
2
+ * overmind-client.ts — Native Node.js client for Overmind HTTP MCP
3
+ * ═══════════════════════════════════════════════════════════════════
4
+ *
5
+ * Import this module to programmatically control agents.
6
+ * No MCP library needed — raw HTTP + JSON-RPC 2.0.
7
+ *
8
+ * Usage:
9
+ * npm run build && node dist/overmind-client.js
10
+ *
11
+ * Or import in your TypeScript:
12
+ * import { OvermindClient } from './overmind-client.js';
13
+ */
14
+ const DEFAULT_BASE = 'http://localhost:3099/mcp';
15
+ const DEFAULT_AUTH = process.env.OVERMIND_AUTH || 'changeme';
16
+ const HEALTH_URL = 'http://localhost:3099/health';
17
+ // ─── JSON-RPC helpers ─────────────────────────────────────────────────────────
18
+ function jsonrpc(id, method, params = {}) {
19
+ return { jsonrpc: '2.0', id, method, params };
20
+ }
21
+ async function callMcp(url, auth, method, params, timeoutMs = 60_000) {
22
+ const res = await fetch(url, {
23
+ method: 'POST',
24
+ headers: {
25
+ 'Content-Type': 'application/json',
26
+ 'Accept': 'application/json, text/event-stream',
27
+ 'Authorization': `Bearer ${auth}`,
28
+ },
29
+ body: JSON.stringify(jsonrpc(Date.now(), method, params)),
30
+ signal: AbortSignal.timeout(timeoutMs),
31
+ });
32
+ if (!res.ok) {
33
+ throw new Error(`HTTP ${res.status} ${res.statusText}`);
34
+ }
35
+ // SSE stream — read all chunks
36
+ const text = await res.text();
37
+ // Parse SSE: each line is "data: {json}"
38
+ const lines = text.split('\n');
39
+ for (const line of lines) {
40
+ const trimmed = line.trim();
41
+ if (trimmed.startsWith('data: ')) {
42
+ const data = JSON.parse(trimmed.slice(6));
43
+ if (data.result)
44
+ return { result: data.result };
45
+ if (data.error)
46
+ return { error: data.error };
47
+ }
48
+ }
49
+ throw new Error('No result in SSE response');
50
+ }
51
+ // ─── OvermindClient ───────────────────────────────────────────────────────────
52
+ export class OvermindClient {
53
+ url;
54
+ auth;
55
+ id = 0;
56
+ nextId() { return ++this.id; }
57
+ constructor(opts = {}) {
58
+ this.url = opts.url ?? DEFAULT_BASE;
59
+ this.auth = opts.auth ?? DEFAULT_AUTH;
60
+ }
61
+ // ─── Health ──────────────────────────────────────────────────────────────
62
+ async health() {
63
+ try {
64
+ const res = await fetch(HEALTH_URL, {
65
+ headers: { 'Authorization': `Bearer ${this.auth}` },
66
+ signal: AbortSignal.timeout(3000),
67
+ });
68
+ return res.ok;
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ // ─── Agent CRUD ──────────────────────────────────────────────────────────
75
+ /** Create a new agent definition (stored in registry) */
76
+ async createAgent(opts) {
77
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
78
+ name: 'create_agent',
79
+ arguments: opts,
80
+ });
81
+ if ('error' in res)
82
+ throw new Error(`create_agent failed: ${res.error?.message}`);
83
+ return { name: opts.name, runner: opts.runner };
84
+ }
85
+ /** List all registered agents */
86
+ async listAgents() {
87
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
88
+ name: 'list_agents',
89
+ arguments: {},
90
+ });
91
+ if ('error' in res)
92
+ throw new Error(`list_agents failed: ${res.error?.message}`);
93
+ const text = res.result.content[0].text;
94
+ // Parse the markdown list
95
+ return text.split('\n').filter(l => l.trim().startsWith('- ')).map(l => l.trim().slice(2));
96
+ }
97
+ /** Delete an agent from the registry */
98
+ async deleteAgent(name) {
99
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
100
+ name: 'delete_agent',
101
+ arguments: { agentName: name },
102
+ });
103
+ if ('error' in res)
104
+ throw new Error(`delete_agent failed: ${res.error?.message}`);
105
+ }
106
+ // ─── Run agents ─────────────────────────────────────────────────────────
107
+ /**
108
+ * Run a single agent and wait for its output.
109
+ * Timeout is per-agent, not global.
110
+ */
111
+ async runAgent(opts) {
112
+ const start = Date.now();
113
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
114
+ name: 'run_agent',
115
+ arguments: {
116
+ agentName: opts.agentName,
117
+ prompt: opts.prompt,
118
+ timeoutMs: opts.timeoutMs ?? 90_000,
119
+ },
120
+ }, opts.timeoutMs ?? 120_000);
121
+ if ('error' in res) {
122
+ return { agentName: opts.agentName, runner: 'claude', output: '', error: res.error?.message, durationMs: Date.now() - start };
123
+ }
124
+ const result = res.result;
125
+ return {
126
+ agentName: opts.agentName,
127
+ runner: 'claude',
128
+ output: result.content?.[0]?.text ?? '',
129
+ sessionId: result.sessionId,
130
+ durationMs: Date.now() - start,
131
+ };
132
+ }
133
+ /**
134
+ * Run multiple agents in parallel. Returns results in the same order.
135
+ */
136
+ async runPool(agents) {
137
+ return Promise.all(agents.map(a => this.runAgent({ agentName: a.name, prompt: a.prompt, timeoutMs: a.timeoutMs })));
138
+ }
139
+ // ─── Lifecycle control ──────────────────────────────────────────────────
140
+ /** Get status of a running agent (reads from RAM, no disk I/O) */
141
+ async agentStatus(agentName, runner) {
142
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
143
+ name: 'agent_control',
144
+ arguments: { agentName, runner, action: 'status' },
145
+ });
146
+ if ('error' in res)
147
+ return `Error: ${res.error?.message}`;
148
+ const text = res.result.content[0].text;
149
+ return text;
150
+ }
151
+ /** Stream output from a running agent (non-blocking) */
152
+ async agentStream(agentName, runner) {
153
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
154
+ name: 'agent_control',
155
+ arguments: { agentName, runner, action: 'stream' },
156
+ });
157
+ if ('error' in res)
158
+ return { output: `Error: ${res.error?.message}`, isComplete: true };
159
+ const text = res.result.content[0].text;
160
+ const isComplete = text.includes('isComplete: true') || text.includes('**isComplete:** true');
161
+ return { output: text, isComplete };
162
+ }
163
+ /** Wait for an agent to finish (blocking, polls every 1s) */
164
+ async agentWait(agentName, timeoutMs = 900_000, runner) {
165
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
166
+ name: 'agent_control',
167
+ arguments: { agentName, runner, action: 'wait', timeoutMs },
168
+ }, timeoutMs + 10_000);
169
+ if ('error' in res)
170
+ return `Error: ${res.error?.message}`;
171
+ return res.result.content[0].text;
172
+ }
173
+ /** Kill a running agent */
174
+ async agentKill(agentName, runner) {
175
+ const res = await callMcp(this.url, this.auth, 'tools/call', {
176
+ name: 'agent_control',
177
+ arguments: { agentName, runner, action: 'kill' },
178
+ });
179
+ if ('error' in res)
180
+ return `Error: ${res.error?.message}`;
181
+ return res.result.content[0].text;
182
+ }
183
+ }
184
+ // ─── CLI demo ────────────────────────────────────────────────────────────────
185
+ async function demo() {
186
+ const client = new OvermindClient();
187
+ console.log('\n═══ Overmind Client Demo ═══\n');
188
+ // Health
189
+ const ok = await client.health();
190
+ console.log(`[health] ${ok ? '✓' : '✗'} Overmind MCP server`);
191
+ // List agents
192
+ const agents = await client.listAgents();
193
+ console.log(`[list_agents] ${agents.length} agents registered`);
194
+ // Demo: create + run a probe agent
195
+ const TEST_AGENT = 'client_demo_probe';
196
+ try {
197
+ await client.createAgent({
198
+ name: TEST_AGENT,
199
+ runner: 'claude',
200
+ prompt: 'Réponds exactement: PONG',
201
+ });
202
+ console.log(`[create_agent] ${TEST_AGENT} créé`);
203
+ const result = await client.runAgent({
204
+ agentName: TEST_AGENT,
205
+ prompt: 'PING',
206
+ timeoutMs: 30_000,
207
+ });
208
+ console.log(`[run_agent] ✓ (${result.durationMs}ms)`);
209
+ console.log(` Output: ${result.output.slice(0, 120).trim()}`);
210
+ await client.deleteAgent(TEST_AGENT);
211
+ console.log(`[delete_agent] ${TEST_AGENT} supprimé`);
212
+ }
213
+ catch (e) {
214
+ console.error('[demo] Erreur:', e);
215
+ }
216
+ }
217
+ // Run demo if executed directly
218
+ demo().catch(console.error);
219
+ // Export for use as module
220
+ export { OvermindClient as default };
221
+ //# sourceMappingURL=overmind-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overmind-client.js","sourceRoot":"","sources":["../../src/bin/overmind-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,YAAY,GAAG,2BAA2B,CAAC;AACjD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,UAAU,CAAC;AAC7D,MAAM,UAAU,GAAI,8BAA8B,CAAC;AAEnD,iFAAiF;AAEjF,SAAS,OAAO,CAAC,EAAU,EAAE,MAAc,EAAE,SAAkC,EAAE;IAC/E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,GAAW,EACX,IAAY,EACZ,MAAc,EACd,MAA+B,EAC/B,SAAS,GAAG,MAAM;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,QAAQ,EAAE,qCAAqC;YAC/C,eAAe,EAAE,UAAU,IAAI,EAAE;SAClC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;KACvC,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,+BAA+B;IAC/B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,yCAAyC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,KAAK;gBAAG,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAA0C,EAAE,CAAC;QACrF,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AAC/C,CAAC;AAiBD,iFAAiF;AAEjF,MAAM,OAAO,cAAc;IACjB,GAAG,CAAS;IACZ,IAAI,CAAS;IACb,EAAE,GAAG,CAAC,CAAC;IACP,MAAM,KAAa,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAE9C,YAAY,OAAwC,EAAE;QACpD,IAAI,CAAC,GAAG,GAAK,IAAI,CAAC,GAAG,IAAM,YAAY,CAAC;QACxC,IAAI,CAAC,IAAI,GAAI,IAAI,CAAC,IAAI,IAAK,YAAY,CAAC;IAC1C,CAAC;IAED,4EAA4E;IAE5E,KAAK,CAAC,MAAM;QACV,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE;gBAClC,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,IAAI,CAAC,IAAI,EAAE,EAAE;gBACnD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;aAClC,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,KAAK,CAAC;QAAC,CAAC;IAC3B,CAAC;IAED,4EAA4E;IAE5E,yDAAyD;IACzD,KAAK,CAAC,WAAW,CAAC,IAIjB;QACC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAClD,CAAC;IAED,iCAAiC;IACjC,KAAK,CAAC,UAAU;QACd,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,EAAE;SACd,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACjF,MAAM,IAAI,GAAI,GAAG,CAAC,MAA+C,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClF,0BAA0B;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,wCAAwC;IACxC,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;SAC/B,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,2EAA2E;IAE3E;;;OAGG;IACH,KAAK,CAAC,QAAQ,CAAC,IAId;QACC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,WAAW;YACjB,SAAS,EAAE;gBACT,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,MAAM,EAAK,IAAI,CAAC,MAAM;gBACtB,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,MAAM;aACpC;SACF,EAAE,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC;QAE9B,IAAI,OAAO,IAAI,GAAG,EAAE,CAAC;YACnB,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;QAChI,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,MAAmE,CAAC;QACvF,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE;YACvC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC/B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,MAKZ;QACA,OAAO,OAAO,CAAC,GAAG,CAChB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAChG,CAAC;IACJ,CAAC;IAED,2EAA2E;IAE3E,kEAAkE;IAClE,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,MAAmB;QACtD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE;SACnD,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,GAAG;YAAE,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAI,GAAG,CAAC,MAA+C,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,MAAmB;QACtD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE;SACnD,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QACxF,MAAM,IAAI,GAAI,GAAG,CAAC,MAA+C,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClF,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;QAC9F,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IACtC,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,SAAS,GAAG,OAAO,EAAE,MAAmB;QACzE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE;SAC5D,EAAE,SAAS,GAAG,MAAM,CAAC,CAAC;QACvB,IAAI,OAAO,IAAI,GAAG;YAAE,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QAC1D,OAAQ,GAAG,CAAC,MAA+C,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9E,CAAC;IAED,2BAA2B;IAC3B,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,MAAmB;QACpD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE;YAC3D,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;SACjD,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,GAAG;YAAE,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QAC1D,OAAQ,GAAG,CAAC,MAA+C,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9E,CAAC;CACF;AAED,gFAAgF;AAEhF,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;IAEpC,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAEhD,SAAS;IACT,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,sBAAsB,CAAC,CAAC;IAE9D,cAAc;IACd,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,MAAM,oBAAoB,CAAC,CAAC;IAEhE,mCAAmC;IACnC,MAAM,UAAU,GAAG,mBAAmB,CAAC;IAEvC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,WAAW,CAAC;YACvB,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,0BAA0B;SACnC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,kBAAkB,UAAU,OAAO,CAAC,CAAC;QAEjD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;YACnC,SAAS,EAAE,UAAU;YACrB,MAAM,EAAE,MAAM;YACd,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,UAAU,KAAK,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAE/D,MAAM,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,UAAU,WAAW,CAAC,CAAC;IAEvD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,gCAAgC;AAChC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAE5B,2BAA2B;AAC3B,OAAO,EAAE,cAAc,IAAI,OAAO,EAAE,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * agent_lifecycle.ts — Lightweight in-memory agent lifecycle manager
3
+ * =================================================================
4
+ *
5
+ * Single source of truth for LIVE agent state during execution.
6
+ * No disk I/O, no async on the hot path.
7
+ *
8
+ * Two layers working together:
9
+ * - agent_lifecycle (RAM): outputBuffer, status, sessionId, PID → O(1) access
10
+ * - processRegistry (disk): persistence, sweeper, OS-level kill
11
+ *
12
+ * Design goals:
13
+ * - appendLiveOutput() → O(1) in-memory string concat, zero disk I/O
14
+ * - agent_control → direct Map read, no disk poll
15
+ * - 10+ agents → all in RAM, zero contention
16
+ * - wait() → AbortController-based, instant resolution
17
+ */
18
+ import { ChildProcess } from 'child_process';
19
+ export type LifecycleStatus = 'running' | 'done' | 'failed' | 'orphaned';
20
+ export interface LiveAgent {
21
+ pid: number;
22
+ runner: string;
23
+ agentName: string;
24
+ sessionId: string;
25
+ status: LifecycleStatus;
26
+ outputBuffer: string;
27
+ exitCode: number | null;
28
+ startedAt: number;
29
+ lastOutputAt: number;
30
+ abortController?: AbortController;
31
+ cleanupFn: () => Promise<void>;
32
+ childRef: ChildProcess | null;
33
+ }
34
+ /**
35
+ * Register a new running agent. Call once per spawn.
36
+ */
37
+ export declare function registerLiveAgent(agent: {
38
+ pid: number;
39
+ runner: string;
40
+ agentName: string;
41
+ sessionId: string;
42
+ abortController?: AbortController;
43
+ cleanupFn: () => Promise<void>;
44
+ childRef: ChildProcess | null;
45
+ }): void;
46
+ /**
47
+ * Append a text chunk to the agent's ring buffer. O(1).
48
+ */
49
+ export declare function appendLiveOutput(pid: number, chunk: string): void;
50
+ /**
51
+ * Update sessionId after the runner resolves it from the JSON response.
52
+ */
53
+ export declare function linkLiveSession(pid: number, sessionId: string): void;
54
+ /**
55
+ * Transition an agent to a terminal state.
56
+ * Resolves any pending wait() via AbortController.abort().
57
+ */
58
+ export declare function setLiveStatus(pid: number, status: LifecycleStatus, exitCode?: number | null): void;
59
+ /**
60
+ * Unregister and remove from map. Called after 'exit' event in the runner.
61
+ */
62
+ export declare function unregisterLiveAgent(pid: number): void;
63
+ /**
64
+ * Get a live agent by agentName (+ optionally by runner).
65
+ */
66
+ export declare function getLiveAgent(agentName: string, runner?: string): LiveAgent | undefined;
67
+ /**
68
+ * Get a live agent by PID.
69
+ */
70
+ export declare function getLiveAgentByPid(pid: number): LiveAgent | undefined;
71
+ /**
72
+ * All currently running agents.
73
+ */
74
+ export declare function getRunningAgents(): LiveAgent[];
75
+ /**
76
+ * Agent counts.
77
+ */
78
+ export declare function getAgentCount(): {
79
+ running: number;
80
+ total: number;
81
+ };
82
+ /**
83
+ * Attach an AbortController to a running agent (for wait() resolution).
84
+ */
85
+ export declare function setLiveAbortController(pid: number, ac: AbortController): void;
86
+ /**
87
+ * Drain all agents — called on SIGTERM/SIGINT.
88
+ * Best-effort cleanup of all running processes.
89
+ */
90
+ export declare function drainAllAgents(): Promise<void>;
91
+ //# sourceMappingURL=agent_lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent_lifecycle.d.ts","sourceRoot":"","sources":["../../src/lib/agent_lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEzE,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B;AAoBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B,GAAG,IAAI,CAoBP;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAKjE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAKpE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,EACvB,QAAQ,GAAE,MAAM,GAAG,IAAW,GAC7B,IAAI,CASN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAMrD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAOtF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,EAAE,CAE9C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMlE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,eAAe,GAAG,IAAI,CAG7E;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAMpD"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * agent_lifecycle.ts — Lightweight in-memory agent lifecycle manager
3
+ * =================================================================
4
+ *
5
+ * Single source of truth for LIVE agent state during execution.
6
+ * No disk I/O, no async on the hot path.
7
+ *
8
+ * Two layers working together:
9
+ * - agent_lifecycle (RAM): outputBuffer, status, sessionId, PID → O(1) access
10
+ * - processRegistry (disk): persistence, sweeper, OS-level kill
11
+ *
12
+ * Design goals:
13
+ * - appendLiveOutput() → O(1) in-memory string concat, zero disk I/O
14
+ * - agent_control → direct Map read, no disk poll
15
+ * - 10+ agents → all in RAM, zero contention
16
+ * - wait() → AbortController-based, instant resolution
17
+ */
18
+ const MAX_BUFFER = 256 * 1024;
19
+ // ─── In-memory store ───────────────────────────────────────────────────────────
20
+ const lifecycleMap = new Map();
21
+ const sessionIndex = new Map(); // sessionId → pid
22
+ // ─── Ring-buffer ───────────────────────────────────────────────────────────────
23
+ function appendToRing(existing, chunk) {
24
+ const combined = existing + chunk;
25
+ return combined.length > MAX_BUFFER
26
+ ? combined.slice(-MAX_BUFFER)
27
+ : combined;
28
+ }
29
+ // ─── Lifecycle API ─────────────────────────────────────────────────────────────
30
+ /**
31
+ * Register a new running agent. Call once per spawn.
32
+ */
33
+ export function registerLiveAgent(agent) {
34
+ // Evict any stale entry for the same agentName that is still 'running'
35
+ for (const [pid, a] of lifecycleMap) {
36
+ if (a.agentName === agent.agentName && a.status === 'running') {
37
+ a.status = 'orphaned';
38
+ lifecycleMap.delete(pid);
39
+ }
40
+ }
41
+ const live = {
42
+ ...agent,
43
+ status: 'running',
44
+ outputBuffer: '',
45
+ exitCode: null,
46
+ startedAt: Date.now(),
47
+ lastOutputAt: Date.now(),
48
+ };
49
+ lifecycleMap.set(agent.pid, live);
50
+ if (agent.sessionId)
51
+ sessionIndex.set(agent.sessionId, agent.pid);
52
+ }
53
+ /**
54
+ * Append a text chunk to the agent's ring buffer. O(1).
55
+ */
56
+ export function appendLiveOutput(pid, chunk) {
57
+ const agent = lifecycleMap.get(pid);
58
+ if (!agent)
59
+ return;
60
+ agent.outputBuffer = appendToRing(agent.outputBuffer, chunk);
61
+ agent.lastOutputAt = Date.now();
62
+ }
63
+ /**
64
+ * Update sessionId after the runner resolves it from the JSON response.
65
+ */
66
+ export function linkLiveSession(pid, sessionId) {
67
+ const agent = lifecycleMap.get(pid);
68
+ if (!agent)
69
+ return;
70
+ agent.sessionId = sessionId;
71
+ sessionIndex.set(sessionId, pid);
72
+ }
73
+ /**
74
+ * Transition an agent to a terminal state.
75
+ * Resolves any pending wait() via AbortController.abort().
76
+ */
77
+ export function setLiveStatus(pid, status, exitCode = null) {
78
+ const agent = lifecycleMap.get(pid);
79
+ if (!agent)
80
+ return;
81
+ agent.status = status;
82
+ agent.exitCode = exitCode;
83
+ agent.lastOutputAt = Date.now();
84
+ if (status !== 'running' && agent.abortController) {
85
+ agent.abortController.abort();
86
+ }
87
+ }
88
+ /**
89
+ * Unregister and remove from map. Called after 'exit' event in the runner.
90
+ */
91
+ export function unregisterLiveAgent(pid) {
92
+ const agent = lifecycleMap.get(pid);
93
+ if (agent) {
94
+ if (agent.sessionId)
95
+ sessionIndex.delete(agent.sessionId);
96
+ lifecycleMap.delete(pid);
97
+ }
98
+ }
99
+ /**
100
+ * Get a live agent by agentName (+ optionally by runner).
101
+ */
102
+ export function getLiveAgent(agentName, runner) {
103
+ for (const agent of lifecycleMap.values()) {
104
+ if (agent.agentName === agentName && (runner === undefined || agent.runner === runner)) {
105
+ return agent;
106
+ }
107
+ }
108
+ return undefined;
109
+ }
110
+ /**
111
+ * Get a live agent by PID.
112
+ */
113
+ export function getLiveAgentByPid(pid) {
114
+ return lifecycleMap.get(pid);
115
+ }
116
+ /**
117
+ * All currently running agents.
118
+ */
119
+ export function getRunningAgents() {
120
+ return [...lifecycleMap.values()].filter((a) => a.status === 'running');
121
+ }
122
+ /**
123
+ * Agent counts.
124
+ */
125
+ export function getAgentCount() {
126
+ let running = 0;
127
+ for (const a of lifecycleMap.values()) {
128
+ if (a.status === 'running')
129
+ running++;
130
+ }
131
+ return { running, total: lifecycleMap.size };
132
+ }
133
+ /**
134
+ * Attach an AbortController to a running agent (for wait() resolution).
135
+ */
136
+ export function setLiveAbortController(pid, ac) {
137
+ const agent = lifecycleMap.get(pid);
138
+ if (agent)
139
+ agent.abortController = ac;
140
+ }
141
+ /**
142
+ * Drain all agents — called on SIGTERM/SIGINT.
143
+ * Best-effort cleanup of all running processes.
144
+ */
145
+ export async function drainAllAgents() {
146
+ for (const agent of lifecycleMap.values()) {
147
+ if (agent.status === 'running') {
148
+ try {
149
+ await agent.cleanupFn();
150
+ }
151
+ catch { /* best-effort */ }
152
+ }
153
+ }
154
+ }
155
+ //# sourceMappingURL=agent_lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent_lifecycle.js","sourceRoot":"","sources":["../../src/lib/agent_lifecycle.ts"],"names":[],"mappings":"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"}
@@ -24,34 +24,13 @@ export interface ConfigType {
24
24
  HARD_TIMEOUT_MS: number;
25
25
  KEEPALIVE_INTERVAL_MS: number;
26
26
  }
27
+ declare let PKG_VERSION: string;
28
+ export { PKG_VERSION };
27
29
  export declare const DEFAULT_CONFIG: ConfigType;
28
- export declare const CONFIG: {
29
- CLAUDE: {
30
- CORE: string;
31
- PERMISSIONS: string;
32
- PATHS: {
33
- SETTINGS: string;
34
- MCP: string;
35
- };
36
- };
37
- KILO: {
38
- CORE: string;
39
- DEFAULT_MODEL: string;
40
- PATHS: {
41
- SETTINGS: string;
42
- };
43
- };
44
- HERMES: {
45
- CORE: string;
46
- PATHS: {
47
- SETTINGS: string;
48
- };
49
- };
50
- TIMEOUT_MS: number;
51
- HARD_TIMEOUT_MS: number;
52
- KEEPALIVE_INTERVAL_MS: number;
53
- };
30
+ export declare const CONFIG: ConfigType;
54
31
  export declare function resetWorkspaceCache(): void;
32
+ /** Validate agent name to prevent path traversal */
33
+ export declare function isValidAgentName(name: string): boolean;
55
34
  export declare function getWorkspaceDir(): string;
56
35
  export declare function resolveConfigPath(configPath: string, workspaceDirOverride?: string): string;
57
36
  export declare function updateConfig(newSettingsPath?: string, newMcpPath?: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;YACjB,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;KACH,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAKD,eAAO,MAAM,cAAc,EAAE,UAyB5B,CAAC;AAEF,eAAO,MAAM,MAAM;YAxDT;QACN,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;YACjB,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;KACH;UACK;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH;YACO;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH;gBACW,MAAM;qBACD,MAAM;2BACA,MAAM;CAiCY,CAAC;AAI5C,wBAAgB,mBAAmB,SAElC;AAED,wBAAgB,eAAe,IAAI,MAAM,CA0DxC;AAKD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,MAAM,CAa3F;AAED,wBAAgB,YAAY,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,QAGzE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;YACjB,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;KACH,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAQD,QAAA,IAAI,WAAW,QAAU,CAAC;AAM1B,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,eAAO,MAAM,cAAc,EAAE,UAyB5B,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,UAAuD,CAAC;AAI7E,wBAAgB,mBAAmB,SAElC;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,eAAe,IAAI,MAAM,CA2DxC;AAKD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,MAAM,CAkB3F;AAED,wBAAgB,YAAY,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,QAGzE"}
@@ -5,16 +5,26 @@ import { fileURLToPath } from 'url';
5
5
  import { loadEnvQuietly } from './loadEnv.js';
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
+ // Version read from package.json at build time
9
+ import { createRequire } from 'module';
10
+ const require = createRequire(import.meta.url);
11
+ let PKG_VERSION = '2.7.0';
12
+ try {
13
+ const pkg = require('../../package.json');
14
+ PKG_VERSION = pkg.version || PKG_VERSION;
15
+ }
16
+ catch { /* fallback */ }
17
+ export { PKG_VERSION };
8
18
  export const DEFAULT_CONFIG = {
9
- TIMEOUT_MS: 900000, // 15 minutes (was 50min — zombies undetected for too long)
10
- KEEPALIVE_INTERVAL_MS: 900000, // 15 minutes
19
+ TIMEOUT_MS: 900000, // 15 minutes
20
+ KEEPALIVE_INTERVAL_MS: 300000, // 5 minutes (must be < TIMEOUT_MS to actually extend)
11
21
  HARD_TIMEOUT_MS: 60000, // 1 minute extra after keepalive
12
22
  CLAUDE: {
13
23
  CORE: '--output-format json',
14
- PERMISSIONS: '--dangerously-skip-permissions',
24
+ PERMISSIONS: '--dangerously-skip-permissions', // Feature: autonomous mode by default
15
25
  PATHS: {
16
26
  SETTINGS: './.claude/settings.json',
17
- MCP: '.mcp.json', // Will be resolved dynamically
27
+ MCP: '.mcp.json',
18
28
  },
19
29
  },
20
30
  KILO: {
@@ -31,11 +41,16 @@ export const DEFAULT_CONFIG = {
31
41
  },
32
42
  },
33
43
  };
34
- export const CONFIG = { ...DEFAULT_CONFIG };
44
+ // Deep clone to prevent shared references with DEFAULT_CONFIG
45
+ export const CONFIG = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
35
46
  let cachedWorkspaceDir = null;
36
47
  export function resetWorkspaceCache() {
37
48
  cachedWorkspaceDir = null;
38
49
  }
50
+ /** Validate agent name to prevent path traversal */
51
+ export function isValidAgentName(name) {
52
+ return /^[a-zA-Z0-9_-]+$/.test(name) && name.length > 0 && name.length <= 128;
53
+ }
39
54
  export function getWorkspaceDir() {
40
55
  if (cachedWorkspaceDir && process.env.NODE_ENV !== 'test')
41
56
  return cachedWorkspaceDir;
@@ -44,14 +59,12 @@ export function getWorkspaceDir() {
44
59
  workspaceDir = path.resolve(process.env.OVERMIND_WORKSPACE);
45
60
  }
46
61
  else {
47
- // 2. Local Project mode if config exists in current working directory
48
62
  const cwd = process.cwd();
49
63
  if (fs.existsSync(path.join(cwd, '.mcp.json')) ||
50
64
  fs.existsSync(path.join(cwd, '.mcp.local.json'))) {
51
65
  workspaceDir = cwd;
52
66
  }
53
67
  else {
54
- // 3. Search up the tree
55
68
  let current = cwd;
56
69
  while (path.dirname(current) !== current) {
57
70
  if (fs.existsSync(path.join(current, '.mcp.json')) ||
@@ -62,19 +75,23 @@ export function getWorkspaceDir() {
62
75
  current = path.dirname(current);
63
76
  }
64
77
  if (!workspaceDir) {
65
- // 4. Auto-detect from code location
66
78
  const codeRoot = path.resolve(__dirname, '../..');
67
79
  if (fs.existsSync(path.join(codeRoot, '.mcp.json')) ||
68
80
  fs.existsSync(path.join(codeRoot, '.mcp.local.json'))) {
69
81
  workspaceDir = codeRoot;
70
82
  }
71
83
  else {
72
- // 4. Global fallback
73
84
  const homedir = os.homedir();
74
85
  workspaceDir = path.join(homedir, '.overmind-mcp');
75
- if (!fs.existsSync(workspaceDir)) {
76
- fs.mkdirSync(workspaceDir, { recursive: true });
77
- fs.writeFileSync(path.join(workspaceDir, '.mcp.json'), JSON.stringify({ mcpServers: {} }, null, 2));
86
+ try {
87
+ if (!fs.existsSync(workspaceDir)) {
88
+ fs.mkdirSync(workspaceDir, { recursive: true });
89
+ fs.writeFileSync(path.join(workspaceDir, '.mcp.json'), JSON.stringify({ mcpServers: {} }, null, 2));
90
+ }
91
+ }
92
+ catch {
93
+ // Permission errors — fall back to cwd
94
+ workspaceDir = cwd;
78
95
  }
79
96
  }
80
97
  }
@@ -93,6 +110,10 @@ export function resolveConfigPath(configPath, workspaceDirOverride) {
93
110
  return configPath;
94
111
  const workspaceDir = workspaceDirOverride || getWorkspaceDir();
95
112
  const fullPath = path.resolve(workspaceDir, configPath);
113
+ // Prevent path traversal beyond workspace
114
+ if (!fullPath.startsWith(path.resolve(workspaceDir))) {
115
+ throw new Error(`Path traversal detected: ${configPath} resolves outside workspace`);
116
+ }
96
117
  // Special handling for MCP config to support .local variant
97
118
  if (configPath === '.mcp.json' && !fs.existsSync(fullPath)) {
98
119
  const localPath = path.resolve(workspaceDir, '.mcp.local.json');