overmind-mcp 2.2.4 → 2.3.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 (74) hide show
  1. package/.mcp.json.example +21 -0
  2. package/README.md +59 -6
  3. package/bin/.gitkeep +0 -0
  4. package/bin/README.md +34 -0
  5. package/dist/lib/InstallHelper.js +1 -1
  6. package/dist/lib/processRegistry.d.ts +71 -0
  7. package/dist/lib/processRegistry.d.ts.map +1 -0
  8. package/dist/lib/processRegistry.js +275 -0
  9. package/dist/lib/processRegistry.js.map +1 -0
  10. package/dist/server.d.ts +14 -1
  11. package/dist/server.d.ts.map +1 -1
  12. package/dist/server.js +58 -1
  13. package/dist/server.js.map +1 -1
  14. package/dist/services/ClaudeRunner.d.ts.map +1 -1
  15. package/dist/services/ClaudeRunner.js +59 -4
  16. package/dist/services/ClaudeRunner.js.map +1 -1
  17. package/dist/services/ClineRunner.d.ts.map +1 -1
  18. package/dist/services/ClineRunner.js +12 -1
  19. package/dist/services/ClineRunner.js.map +1 -1
  20. package/dist/services/GeminiRunner.d.ts.map +1 -1
  21. package/dist/services/GeminiRunner.js +18 -0
  22. package/dist/services/GeminiRunner.js.map +1 -1
  23. package/dist/services/KiloRunner.d.ts.map +1 -1
  24. package/dist/services/KiloRunner.js +28 -1
  25. package/dist/services/KiloRunner.js.map +1 -1
  26. package/dist/services/NousHermesRunner.d.ts.map +1 -1
  27. package/dist/services/NousHermesRunner.js +18 -5
  28. package/dist/services/NousHermesRunner.js.map +1 -1
  29. package/dist/services/OpenClawRunner.d.ts.map +1 -1
  30. package/dist/services/OpenClawRunner.js +12 -2
  31. package/dist/services/OpenClawRunner.js.map +1 -1
  32. package/dist/services/OpenCodeRunner.d.ts.map +1 -1
  33. package/dist/services/OpenCodeRunner.js +12 -1
  34. package/dist/services/OpenCodeRunner.js.map +1 -1
  35. package/dist/services/QwenCliRunner.d.ts.map +1 -1
  36. package/dist/services/QwenCliRunner.js +12 -1
  37. package/dist/services/QwenCliRunner.js.map +1 -1
  38. package/dist/tools/config_example.d.ts.map +1 -1
  39. package/dist/tools/config_example.js +23 -7
  40. package/dist/tools/config_example.js.map +1 -1
  41. package/dist/tools/get_agent_status.d.ts +29 -0
  42. package/dist/tools/get_agent_status.d.ts.map +1 -0
  43. package/dist/tools/get_agent_status.js +45 -0
  44. package/dist/tools/get_agent_status.js.map +1 -0
  45. package/dist/tools/kill_agent.d.ts +22 -0
  46. package/dist/tools/kill_agent.d.ts.map +1 -0
  47. package/dist/tools/kill_agent.js +33 -0
  48. package/dist/tools/kill_agent.js.map +1 -0
  49. package/dist/tools/stream_agent_output.d.ts +30 -0
  50. package/dist/tools/stream_agent_output.d.ts.map +1 -0
  51. package/dist/tools/stream_agent_output.js +44 -0
  52. package/dist/tools/stream_agent_output.js.map +1 -0
  53. package/dist/tools/wait_agent.d.ts +30 -0
  54. package/dist/tools/wait_agent.d.ts.map +1 -0
  55. package/dist/tools/wait_agent.js +68 -0
  56. package/dist/tools/wait_agent.js.map +1 -0
  57. package/docs/ASYNC_AGENT_INTEGRATION.md +311 -0
  58. package/docs/INDEX.md +144 -144
  59. package/docs/docs/OVERMIND_WORKFLOW_GUIDE.md +595 -0
  60. package/docs/docs/PROJECT_STRUCTURE.md +101 -0
  61. package/docs/docs/README_POSTGRES_INTEGRATION.md +229 -0
  62. package/package.json +5 -5
  63. package/scripts/auto-install.mjs +8 -8
  64. package/scripts/postgres-manager.mjs +1 -1
  65. package/scripts/postinstall.mjs +2 -2
  66. package/scripts/setup.mjs +8 -5
  67. package/docs/guides/DEPLOYMENT.md +0 -418
  68. package/docs/guides/SWARM_USAGE.md +0 -444
  69. /package/{install-overmind-unix.sh → bin/install-overmind-unix.sh} +0 -0
  70. /package/{install-overmind-windows.bat → bin/install-overmind-windows.bat} +0 -0
  71. /package/docs/{api/prompt → prompt}/Claude_code.md +0 -0
  72. /package/docs/{api/prompt → prompt}/Kilo.md +0 -0
  73. /package/docs/{api/prompt → prompt}/Kilo_Hermes.md +0 -0
  74. /package/docs/{api/prompt → prompt}/Minimax4.md +0 -0
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod';
2
+ export declare const streamAgentOutputSchema: z.ZodObject<{
3
+ agentName: z.ZodString;
4
+ runner: z.ZodOptional<z.ZodEnum<{
5
+ claude: "claude";
6
+ gemini: "gemini";
7
+ kilo: "kilo";
8
+ qwencli: "qwencli";
9
+ hermes: "hermes";
10
+ openclaw: "openclaw";
11
+ cline: "cline";
12
+ opencode: "opencode";
13
+ }>>;
14
+ sinceTimestamp: z.ZodOptional<z.ZodNumber>;
15
+ config: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strip>;
17
+ export declare function streamAgentOutputTool(args: z.infer<typeof streamAgentOutputSchema>): Promise<{
18
+ content: {
19
+ type: "text";
20
+ text: string;
21
+ }[];
22
+ isError?: undefined;
23
+ } | {
24
+ content: {
25
+ type: "text";
26
+ text: string;
27
+ }[];
28
+ isError: boolean;
29
+ }>;
30
+ //# sourceMappingURL=stream_agent_output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream_agent_output.d.ts","sourceRoot":"","sources":["../../src/tools/stream_agent_output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;iBAWlC,CAAC;AAEH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC;;;;;;;;;;;;GAiCxF"}
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ import { getProcessStatus } from '../lib/processRegistry.js';
3
+ export const streamAgentOutputSchema = z.object({
4
+ agentName: z.string().describe('Nom de l agent'),
5
+ runner: z
6
+ .enum(['claude', 'gemini', 'kilo', 'qwencli', 'openclaw', 'cline', 'opencode', 'hermes'])
7
+ .optional()
8
+ .describe('Type de runner (optionnel, défaut: any)'),
9
+ sinceTimestamp: z
10
+ .number()
11
+ .optional()
12
+ .describe('Ne retourner que la sortie après ce timestamp (ms)'),
13
+ config: z.string().optional().describe('Chemin du fichier de configuration'),
14
+ });
15
+ export async function streamAgentOutputTool(args) {
16
+ const { agentName, runner, sinceTimestamp, config: configPath } = args;
17
+ const entry = await getProcessStatus(agentName, runner, configPath);
18
+ if (!entry) {
19
+ return {
20
+ content: [
21
+ {
22
+ type: 'text',
23
+ text: `Agent "${agentName}" non trouvé dans le registre.`,
24
+ },
25
+ ],
26
+ };
27
+ }
28
+ const isComplete = entry.status === 'done' || entry.status === 'failed' || entry.status === 'orphaned';
29
+ const output = entry.outputBuffer || '';
30
+ if (sinceTimestamp && entry.lastOutputAt && entry.lastOutputAt > sinceTimestamp) {
31
+ // For now, return all output if there was output after the timestamp
32
+ // (per-chunk timestamps not yet implemented)
33
+ }
34
+ return {
35
+ content: [
36
+ {
37
+ type: 'text',
38
+ text: output || '(no output yet)',
39
+ },
40
+ ],
41
+ isError: isComplete && entry.status === 'failed',
42
+ };
43
+ }
44
+ //# sourceMappingURL=stream_agent_output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream_agent_output.js","sourceRoot":"","sources":["../../src/tools/stream_agent_output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAChD,MAAM,EAAE,CAAC;SACN,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;SACxF,QAAQ,EAAE;SACV,QAAQ,CAAC,yCAAyC,CAAC;IACtD,cAAc,EAAE,CAAC;SACd,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,oDAAoD,CAAC;IACjE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;CAC7E,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAA6C;IACvF,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAEvE,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAEpE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,UAAU,SAAS,gCAAgC;iBAC1D;aACF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC;IACvG,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC;IAExC,IAAI,cAAc,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,GAAG,cAAc,EAAE,CAAC;QAChF,qEAAqE;QACrE,6CAA6C;IAC/C,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,MAAM,IAAI,iBAAiB;aAClC;SACF;QACD,OAAO,EAAE,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ;KACjD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod';
2
+ export declare const waitAgentSchema: z.ZodObject<{
3
+ agentName: z.ZodString;
4
+ runner: z.ZodOptional<z.ZodEnum<{
5
+ claude: "claude";
6
+ gemini: "gemini";
7
+ kilo: "kilo";
8
+ qwencli: "qwencli";
9
+ hermes: "hermes";
10
+ openclaw: "openclaw";
11
+ cline: "cline";
12
+ opencode: "opencode";
13
+ }>>;
14
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
15
+ config: z.ZodOptional<z.ZodString>;
16
+ }, z.core.$strip>;
17
+ export declare function waitAgentTool(args: z.infer<typeof waitAgentSchema>): Promise<{
18
+ content: {
19
+ type: "text";
20
+ text: string;
21
+ }[];
22
+ isError: boolean;
23
+ } | {
24
+ content: {
25
+ type: "text";
26
+ text: string;
27
+ }[];
28
+ isError?: undefined;
29
+ }>;
30
+ //# sourceMappingURL=wait_agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait_agent.d.ts","sourceRoot":"","sources":["../../src/tools/wait_agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;iBAY1B,CAAC;AAEH,wBAAsB,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC;;;;;;;;;;;;GA0DxE"}
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ import { getProcessStatus } from '../lib/processRegistry.js';
3
+ export const waitAgentSchema = z.object({
4
+ agentName: z.string().describe('Nom de l agent'),
5
+ runner: z
6
+ .enum(['claude', 'gemini', 'kilo', 'qwencli', 'openclaw', 'cline', 'opencode', 'hermes'])
7
+ .optional()
8
+ .describe('Type de runner (optionnel, défaut: any)'),
9
+ timeoutMs: z
10
+ .number()
11
+ .optional()
12
+ .default(900000)
13
+ .describe('Timeout en ms (défaut: 900000 = 15 min)'),
14
+ config: z.string().optional().describe('Chemin du fichier de configuration'),
15
+ });
16
+ export async function waitAgentTool(args) {
17
+ const { agentName, runner, timeoutMs, config: configPath } = args;
18
+ const start = Date.now();
19
+ const pollInterval = 1000; // 1 second
20
+ while (Date.now() - start < timeoutMs) {
21
+ const entry = await getProcessStatus(agentName, runner, configPath);
22
+ if (!entry) {
23
+ return {
24
+ content: [
25
+ {
26
+ type: 'text',
27
+ text: `Agent "${agentName}" n existe plus dans le registre.`,
28
+ },
29
+ ],
30
+ isError: true,
31
+ };
32
+ }
33
+ if (entry.status === 'done') {
34
+ return {
35
+ content: [
36
+ {
37
+ type: 'text',
38
+ text: entry.outputBuffer || 'Agent terminé avec succès.',
39
+ },
40
+ ],
41
+ };
42
+ }
43
+ if (entry.status === 'failed' || entry.status === 'orphaned') {
44
+ return {
45
+ content: [
46
+ {
47
+ type: 'text',
48
+ text: `Agent terminé avec erreur: ${entry.status}\n\nSortie:\n${entry.outputBuffer || 'N/A'}`,
49
+ },
50
+ ],
51
+ isError: true,
52
+ };
53
+ }
54
+ // Still running — wait before next poll
55
+ await new Promise((r) => setTimeout(r, pollInterval));
56
+ }
57
+ // Timeout reached
58
+ return {
59
+ content: [
60
+ {
61
+ type: 'text',
62
+ text: `Timeout de ${timeoutMs}ms atteint. L'agent est toujours en cours d exécution.`,
63
+ },
64
+ ],
65
+ isError: true,
66
+ };
67
+ }
68
+ //# sourceMappingURL=wait_agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait_agent.js","sourceRoot":"","sources":["../../src/tools/wait_agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAChD,MAAM,EAAE,CAAC;SACN,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;SACxF,QAAQ,EAAE;SACV,QAAQ,CAAC,yCAAyC,CAAC;IACtD,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,yCAAyC,CAAC;IACtD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;CAC7E,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAqC;IACvE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAElE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,WAAW;IAEtC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QAEpE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,UAAU,SAAS,mCAAmC;qBAC7D;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,KAAK,CAAC,YAAY,IAAI,4BAA4B;qBACzD;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC7D,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,8BAA8B,KAAK,CAAC,MAAM,gBAAgB,KAAK,CAAC,YAAY,IAAI,KAAK,EAAE;qBAC9F;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,wCAAwC;QACxC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,kBAAkB;IAClB,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,cAAc,SAAS,wDAAwD;aACtF;SACF;QACD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,311 @@
1
+ # OverMind Async Agent Integration — Process Registry & PID Tracking
2
+
3
+ > **Problème résolu** : Les agents IA sont invoked en async via MCP, mais le seul lien avec le processus fils est le `sessionId` (généré par le runner, opaque pour OverMind). Si le processus parent meurt, le `sessionId` est perdu et le child process devient orphelin.
4
+ >
5
+ > **Solution** : Un **Process Registry** qui stocke le mapping `pid ↔ sessionId ↔ agentName`, persistant dans `sessions.json`, permettant de :
6
+ > - Se rattacher à un agent en cours via son PID
7
+ > - Vérifier si un agent est encore vivant
8
+ > - Tuer un agent par son PID
9
+ > - Streamer output en temps réel
10
+
11
+ ---
12
+
13
+ ## 1. Architecture
14
+
15
+ ```
16
+ ┌──────────────────────────────────────────────────────────────┐
17
+ │ MCP Tool: run_agent() (async, non-blocking) │
18
+ │ │
19
+ │ 1. Spawn child process (claude/kilo/gemini/etc.) │
20
+ │ 2. Register { pid, sessionId, agentName, runner, ts } │
21
+ │ 3. Return immediately with { sessionId, pid } │
22
+ │ → Client can poll / attach to PID │
23
+ │ │
24
+ │ ┌──────────────────┐ ┌──────────────────────────────┐ │
25
+ │ │ Process Registry │◄──│ child.on('data') │ │
26
+ │ │ (sessions.json) │ │ → buffers output │ │
27
+ │ │ │ │ → checks liveliness │ │
28
+ │ │ { pid, sessionId,│ └──────────────────────────────┘ │
29
+ │ │ agentName, │ │
30
+ │ │ runner, status,│ ┌──────────────────────────────┐ │
31
+ │ │ startedAt } │ │ MCP Tool: get_agent_status() │ │
32
+ │ └──────────────────┘ │ → returns live output │ │
33
+ │ │ → pid / alive / output so far │ │
34
+ │ └──────────────────────────────┘ │
35
+ └──────────────────────────────────────────────────────────────┘
36
+ ```
37
+
38
+ ---
39
+
40
+ ## 2. Sessions JSON — Nouveau Format
41
+
42
+ **Avant** (sessions.json) :
43
+ ```json
44
+ {
45
+ "kilo:sniper_analyst": { "id": "sess_abc123", "ts": 1746892800000 }
46
+ }
47
+ ```
48
+
49
+ **Après** (sessions.json + process registry) :
50
+ ```json
51
+ {
52
+ "kilo:sniper_analyst": {
53
+ "id": "sess_abc123",
54
+ "ts": 1746892800000,
55
+ "pid": 12345,
56
+ "status": "running",
57
+ "outputBuffer": ""
58
+ },
59
+ "claude:planner": {
60
+ "id": "sess_def456",
61
+ "ts": 1746892900000,
62
+ "pid": 67890,
63
+ "status": "running",
64
+ "outputBuffer": "Thinking...\n"
65
+ }
66
+ }
67
+ ```
68
+
69
+ Le champ `status` peut être :
70
+ - `running` — processus actif, PID valide
71
+ - `done` — terminé avec succès (garde le last output pour retrieval)
72
+ - `failed` — terminé avec erreur
73
+ - `orphaned` — le parent a crash mais le child tourne encore
74
+
75
+ ---
76
+
77
+ ## 3. Runner Changes — Spawn & Register
78
+
79
+ Chaque runner (Claude, Kilo, Gemini, Hermes, etc.) doit :
80
+
81
+ 1. **Stocker le PID** dès le `spawn()` :
82
+ ```typescript
83
+ const child = spawn(command, args, options);
84
+ // Immediately register
85
+ await registerProcess(child.pid, {
86
+ sessionId: undefined, // filled when runner gives us sessionId
87
+ agentName,
88
+ runner,
89
+ startedAt: Date.now(),
90
+ status: 'running',
91
+ });
92
+ ```
93
+
94
+ 2. **Mettre à jour avec le sessionId** dès qu'il est reçu :
95
+ ```typescript
96
+ child.stdout?.on('data', (d) => {
97
+ const chunk = d.toString();
98
+ outputBuffer += chunk;
99
+ // Si le sessionId arrive pour la première fois
100
+ if (sessionId && !currentSessionId) {
101
+ currentSessionId = sessionId;
102
+ await updateProcessSession(sessionId, child.pid);
103
+ }
104
+ });
105
+ ```
106
+
107
+ 3. **Marquer `done/failed`** à `child.on('close')` :
108
+ ```typescript
109
+ child.on('close', async (code) => {
110
+ await updateProcessStatus(child.pid, code === 0 ? 'done' : 'failed');
111
+ });
112
+ ```
113
+
114
+ 4. **Cleanup à la terminaison** :
115
+ ```typescript
116
+ // Supprimer après 1h ( TTL ) ou sur explicit delete
117
+ await unregisterProcess(pid);
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 4. Nouvelles Fonctions Registry
123
+
124
+ ```typescript
125
+ // ─── Register a new running process ───────────────────────────
126
+ /**
127
+ * Called immediately after spawn(). Records the PID before the sessionId
128
+ * is known (sessionId arrives later from stdout).
129
+ */
130
+ export async function registerProcess(
131
+ pid: number,
132
+ meta: {
133
+ agentName: string;
134
+ runner: string;
135
+ startedAt: number;
136
+ configPath?: string;
137
+ },
138
+ ): Promise<void> { ... }
139
+
140
+ /**
141
+ * Called when the runner emits a sessionId for the first time.
142
+ * Links sessionId ↔ pid in the registry.
143
+ */
144
+ export async function linkSessionToPid(
145
+ sessionId: string,
146
+ pid: number,
147
+ configPath?: string,
148
+ ): Promise<void> { ... }
149
+
150
+ /**
151
+ * Update output buffer for live streaming.
152
+ */
153
+ export async function appendOutput(
154
+ pid: number,
155
+ chunk: string,
156
+ configPath?: string,
157
+ ): Promise<void> { ... }
158
+
159
+ /**
160
+ * Get current status + output buffer for a process.
161
+ */
162
+ export async function getProcessStatus(
163
+ agentName: string,
164
+ runner?: string,
165
+ configPath?: string,
166
+ ): Promise<ProcessStatus | null> { ... }
167
+
168
+ /**
169
+ * Kill a running agent by PID (Windows: taskkill /F /T /PID; Unix: SIGKILL).
170
+ */
171
+ export async function killAgent(
172
+ agentName: string,
173
+ runner?: string,
174
+ configPath?: string,
175
+ ): Promise<boolean> { ... }
176
+
177
+ /**
178
+ * Unregister (cleanup) a process entry.
179
+ */
180
+ export async function unregisterProcess(
181
+ pid: number,
182
+ configPath?: string,
183
+ ): Promise<void> { ... }
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 5. TTL & Cleanup
189
+
190
+ ```typescript
191
+ const PROCESS_TTL_MS = 60 * 60 * 1000; // 1 hour after 'done'/'failed'
192
+ const ORPHAN_CHECK_INTERVAL = 5 * 60 * 1000; // 5 minutes
193
+
194
+ // On startup, scan for:
195
+ // 1. 'running' entries where the PID no longer exists → mark 'orphaned'
196
+ // 2. 'done'/'failed' entries older than PROCESS_TTL_MS → unregister
197
+ ```
198
+
199
+ ---
200
+
201
+ ## 6. Nouveaux Outils MCP
202
+
203
+ ### `get_agent_status`
204
+ ```typescript
205
+ {
206
+ agentName: string;
207
+ runner?: string; // defaults to 'claude' if omitted
208
+ }
209
+ // Returns:
210
+ // { status, pid, outputBuffer, startedAt, sessionId }
211
+ ```
212
+
213
+ ### `stream_agent_output`
214
+ ```typescript
215
+ {
216
+ agentName: string;
217
+ runner?: string;
218
+ sinceTimestamp?: number; // only return output after this ts
219
+ }
220
+ // Returns:
221
+ // { output: string, status, isComplete: boolean }
222
+ ```
223
+
224
+ ### `kill_agent`
225
+ ```typescript
226
+ {
227
+ agentName: string;
228
+ runner?: string;
229
+ }
230
+ // Returns:
231
+ // { killed: boolean, pid: number }
232
+ ```
233
+
234
+ ### `wait_agent`
235
+ ```typescript
236
+ {
237
+ agentName: string;
238
+ runner?: string;
239
+ timeoutMs?: number; // default: 900000 (15 min)
240
+ }
241
+ // Polls until status !== 'running', returns final result
242
+ // Returns:
243
+ // { status, result, exitCode }
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 7. Flux Complet — Async Agent Lifecycle
249
+
250
+ ```
251
+ Client OverMind MCP Runner
252
+ │ │ │
253
+ │ run_agent() │ │
254
+ │─────────────────────────►│ │
255
+ │ │ spawn(child) │
256
+ │ │───────────────────────────►│
257
+ │ │ registerProcess(pid) │
258
+ │ │ Return { sessionId, pid } │
259
+ │ { sessionId, pid } │ │
260
+ │◄──────────────────────────│ │
261
+ │ │ │
262
+ │ get_agent_status() │ │
263
+ │─────────────────────────►│ │
264
+ │ │ getProcessStatus() │
265
+ │ { status, outputBuffer }│ │
266
+ │◄──────────────────────────│ │
267
+ │ │ stdout.on('data') │
268
+ │ │◄──────────────────────────│
269
+ │ │ appendOutput(pid, chunk) │
270
+ │ │ │
271
+ │ stream_agent_output() │ │
272
+ │─────────────────────────►│ │
273
+ │ { output, status } │ │
274
+ │◄──────────────────────────│ │
275
+ │ │ child.on('close') │
276
+ │ │◄──────────────────────────│
277
+ │ │ updateProcessStatus(done) │
278
+ │ │ │
279
+ │ wait_agent() │ │
280
+ │─────────────────────────►│ │
281
+ │ Polls until done │ │
282
+ │ { status, result } │ │
283
+ │◄──────────────────────────│ │
284
+ ```
285
+
286
+ ---
287
+
288
+ ## 8. Backward Compatibility
289
+
290
+ - Les champs existants (`id`, `ts`) dans `sessions.json` ne changent pas
291
+ - `status`, `pid`, `outputBuffer` sont **ajoutés** (optionnels)
292
+ - Le `sessionId` reste le même — les outils existants (`autoResume`) continuent de fonctionner
293
+ - Si `pid` n'existe pas dans une entrée (sessions anciennes), le status est déduit de `ts` :
294
+ - `ts` < 30 jours + pas de `pid` → `done` (legacy)
295
+ - `ts` récent + pas de `pid` → `running` (legacy, mais incertain)
296
+
297
+ ---
298
+
299
+ ## 9. Implémentation Minimale — Checklist
300
+
301
+ - [ ] `src/lib/processRegistry.ts` — nouvelles fonctions (register, link, append, status, kill, unregister)
302
+ - [ ] `src/lib/sessions.ts` — ajout champs `pid`, `status`, `outputBuffer`
303
+ - [ ] Chaque runner (8 fichiers) — ajouter `registerProcess()` après `spawn()`
304
+ - [ ] Chaque runner — ajouter `appendOutput()` dans `stdout.on('data')`
305
+ - [ ] Chaque runner — ajouter `updateProcessStatus()` dans `child.on('close')`
306
+ - [ ] `src/tools/get_agent_status.ts` — nouvel outil MCP
307
+ - [ ] `src/tools/stream_agent_output.ts` — nouvel outil MCP
308
+ - [ ] `src/tools/kill_agent.ts` — nouvel outil MCP
309
+ - [ ] `src/tools/wait_agent.ts` — nouvel outil MCP
310
+ - [ ] `server.ts` — register les 4 nouveaux outils
311
+ - [ ] Tests dans `src/__tests__/processRegistry.test.ts`