@swarmify/agents-mcp 0.2.3 → 0.2.5
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.
- package/README.md +95 -50
- package/dist/agents.d.ts +18 -4
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +137 -9
- package/dist/agents.js.map +1 -1
- package/dist/api.d.ts +14 -15
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +83 -114
- package/dist/api.js.map +1 -1
- package/dist/hello-world.d.ts +1 -0
- package/dist/hello-world.d.ts.map +1 -0
- package/dist/hello-world.js +3 -0
- package/dist/hello-world.js.map +1 -0
- package/dist/hello.d.ts +1 -1
- package/dist/hello.js +1 -1
- package/dist/hello_world.js +1 -1
- package/dist/persistence.d.ts +7 -2
- package/dist/persistence.d.ts.map +1 -1
- package/dist/persistence.js +54 -9
- package/dist/persistence.js.map +1 -1
- package/dist/ralph.js +2 -2
- package/dist/ralph.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +95 -40
- package/dist/server.js.map +1 -1
- package/dist/version.d.ts +27 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +194 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
# @swarmify/agents-mcp
|
|
2
2
|
|
|
3
|
-
Run
|
|
3
|
+
Run Subagents, Swarm or Ralph Wiggums from any MCP client.
|
|
4
4
|
|
|
5
|
-
Spawn CLI agents in parallel so your main agent stays focused. Each subagent runs
|
|
6
|
-
|
|
5
|
+
Spawn CLI agents in parallel so your main agent stays focused. Each subagent runs in its own context and can be polled for progress.
|
|
6
|
+
|
|
7
|
+
Homepage: https://swarmify.co
|
|
8
|
+
NPM: https://www.npmjs.com/package/@swarmify/agents-mcp
|
|
9
|
+
VS Code Extension: https://marketplace.visualstudio.com/items?itemName=swarmify.swarm-ext
|
|
7
10
|
|
|
8
11
|
## Why This Exists
|
|
9
12
|
|
|
10
|
-
MCP adoption is accelerating and the ecosystem is organizing around registries,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
and security concerns. This server gives you a focused, practical building block
|
|
14
|
-
for real-world swarm work.
|
|
13
|
+
MCP adoption is accelerating and the ecosystem is organizing around registries, gateways, and enterprise governance. At the same time, teams are pushing toward multi-agent workflows and running into orchestration reliability, tool overload, and security concerns. This server gives you a focused, practical building block for real-world swarm work.
|
|
14
|
+
|
|
15
|
+
The API surface is intentionally small, closer to iconic commands like `cd`, `ls`, and `git` than a framework. Fewer knobs means less room for an orchestrator to make mistakes.
|
|
15
16
|
|
|
16
17
|
## What You Get
|
|
17
18
|
|
|
18
|
-
- MCP server with `
|
|
19
|
+
- A dead simple MCP server with `Spawn`, `Status`, `Stop`, and `Tasks` tools
|
|
19
20
|
- The `/swarm` command to teach an orchestrator how to distribute work
|
|
20
21
|
- Plan vs edit modes that control file access per agent
|
|
21
22
|
- Local logs and durable processes that survive IDE restarts
|
|
@@ -24,10 +25,13 @@ for real-world swarm work.
|
|
|
24
25
|
|
|
25
26
|
```bash
|
|
26
27
|
# Claude Code
|
|
27
|
-
claude mcp add
|
|
28
|
+
claude mcp add --scope user Swarm -- npx -y @swarmify/agents-mcp
|
|
29
|
+
|
|
30
|
+
# Codex
|
|
31
|
+
codex mcp add swarm -- npx -y @swarmify/agents-mcp@latest
|
|
28
32
|
|
|
29
33
|
# Gemini CLI
|
|
30
|
-
gemini mcp add
|
|
34
|
+
gemini mcp add Swarm -- npx -y @swarmify/agents-mcp
|
|
31
35
|
|
|
32
36
|
# OpenCode (interactive)
|
|
33
37
|
opencode mcp add
|
|
@@ -43,56 +47,54 @@ The server auto-discovers which agent CLIs you have installed.
|
|
|
43
47
|
- Parallelize tasks across Claude, Codex, Gemini, and Cursor
|
|
44
48
|
- Keep long-running loops responsive by offloading work to subagents
|
|
45
49
|
- Integrate with MCP registries and gateways without changing your workflow
|
|
50
|
+
- Run Ralph Wiggum loops inside spawned Claude Code agents when the plugin is installed
|
|
46
51
|
|
|
47
52
|
## Under the Hood
|
|
48
53
|
|
|
49
|
-
Headless CLI agents run as background processes. Output streams to
|
|
50
|
-
`~/.swarmify/agents/{id}/stdout.log`.
|
|
54
|
+
Headless CLI agents run as background processes. Output streams to `~/.swarmify/agents/{id}/stdout.log`.
|
|
51
55
|
|
|
52
56
|
Plan mode is read-only:
|
|
57
|
+
|
|
53
58
|
- Claude: `--permission-mode plan`
|
|
54
59
|
- Codex: sandboxed (no `--full-auto`)
|
|
55
60
|
- Gemini and Cursor: no auto-approve flags
|
|
56
61
|
|
|
57
62
|
Edit mode unlocks writes:
|
|
63
|
+
|
|
58
64
|
- Codex: `--full-auto`
|
|
59
65
|
- Claude: `acceptEdits`
|
|
60
66
|
- Gemini: `--yolo`
|
|
61
67
|
- Cursor: `-f`
|
|
62
68
|
|
|
63
|
-
Agents are detached from the MCP server process. Close your IDE and reopen it,
|
|
64
|
-
then reconnect with `status` and `tasks`.
|
|
69
|
+
Agents are detached from the MCP server process. Close your IDE and reopen it, then reconnect with `Status` and `Tasks`.
|
|
65
70
|
|
|
66
71
|
## Common Questions
|
|
67
72
|
|
|
68
|
-
**"Isn't this overkill for simple tasks
|
|
69
|
-
Yes. For typo fixes or small changes, one agent is fine. But for implementing a complex feature across 20 files, a single agent drowning in context is slower than a focused swarm working in parallel.
|
|
73
|
+
**"Isn't this overkill for simple tasks?**"Yes. For typo fixes or small changes, one agent is fine. But for implementing a complex feature across 20 files, a single agent drowning in context is slower than a focused swarm working in parallel.
|
|
70
74
|
|
|
71
|
-
**"What if agents conflict
|
|
72
|
-
They don't. The orchestrator (via `/swarm` command) assigns each agent specific files—no overlap. For shared files, it runs agents in sequential waves so there's no collision.
|
|
75
|
+
**"What if agents conflict?**"They don't. The orchestrator (via `/swarm` command) assigns each agent specific files—no overlap. For shared files, it runs agents in sequential waves so there's no collision.
|
|
73
76
|
|
|
74
|
-
**"How do I monitor what's happening
|
|
75
|
-
Use the Swarm `status` tool to see what each agent is doing: files changed, commands run, last messages. No black box—full visibility into the swarm.
|
|
77
|
+
**"How do I monitor what's happening?**"Use the Swarm `Status` tool to see what each agent is doing: files changed, commands run, last messages. No black box—full visibility into the swarm.
|
|
76
78
|
|
|
77
79
|
## API Reference
|
|
78
80
|
|
|
79
81
|
### Tools
|
|
80
82
|
|
|
81
83
|
| Tool | Description |
|
|
82
|
-
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `Spawn` | Start an agent on a task. Returns immediately with agent ID. |
|
|
86
|
+
| `Status` | Get agent progress: files changed, commands run, last messages. |
|
|
87
|
+
| `Stop` | Stop one agent or all agents in a task. |
|
|
88
|
+
| `Tasks` | List all tasks with their agents and activity. |
|
|
87
89
|
|
|
88
|
-
###
|
|
90
|
+
### Spawn
|
|
89
91
|
|
|
90
92
|
```
|
|
91
|
-
|
|
93
|
+
Spawn(task_name, agent_type, prompt, mode?, cwd?, effort?)
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
| Parameter | Required | Description |
|
|
95
|
-
|
|
97
|
+
| --- | --- | --- |
|
|
96
98
|
| `task_name` | Yes | Groups related agents (e.g., "auth-feature") |
|
|
97
99
|
| `agent_type` | Yes | `claude`, `codex`, `gemini`, or `cursor` |
|
|
98
100
|
| `prompt` | Yes | The task for the agent |
|
|
@@ -100,54 +102,53 @@ spawn(task_name, agent_type, prompt, mode?, cwd?, effort?)
|
|
|
100
102
|
| `cwd` | No | Working directory for the agent |
|
|
101
103
|
| `effort` | No | `fast`, `default` (implicit), or `detailed` for max-capability models |
|
|
102
104
|
|
|
103
|
-
###
|
|
105
|
+
### Status
|
|
104
106
|
|
|
105
107
|
```
|
|
106
|
-
|
|
108
|
+
Status(task_name, filter?)
|
|
107
109
|
```
|
|
108
110
|
|
|
109
111
|
| Parameter | Required | Description |
|
|
110
|
-
|
|
112
|
+
| --- | --- | --- |
|
|
111
113
|
| `task_name` | Yes | Task to check |
|
|
112
114
|
| `filter` | No | `running` (default), `completed`, `failed`, `stopped`, or `all` |
|
|
113
115
|
|
|
114
|
-
Returns files created/modified/read/deleted, bash commands executed, and last
|
|
115
|
-
messages.
|
|
116
|
+
Returns files created/modified/read/deleted, bash commands executed, and last messages.
|
|
116
117
|
|
|
117
|
-
###
|
|
118
|
+
### Stop
|
|
118
119
|
|
|
119
120
|
```
|
|
120
|
-
|
|
121
|
+
Stop(task_name, agent_id?)
|
|
121
122
|
```
|
|
122
123
|
|
|
123
124
|
Stop all agents in a task, or a specific agent by ID.
|
|
124
125
|
|
|
125
|
-
###
|
|
126
|
+
### Tasks
|
|
126
127
|
|
|
127
128
|
```
|
|
128
|
-
|
|
129
|
+
Tasks(limit?)
|
|
129
130
|
```
|
|
130
131
|
|
|
131
|
-
List all tasks sorted by most recent activity.
|
|
132
|
+
List all tasks sorted by most recent activity. Defaults to 10 tasks when limit is omitted.
|
|
132
133
|
|
|
133
134
|
## Token Optimization
|
|
134
135
|
|
|
135
136
|
This server is designed to minimize token usage for the calling agent:
|
|
136
137
|
|
|
137
138
|
| Optimization | Benefit |
|
|
138
|
-
|
|
139
|
+
| --- | --- |
|
|
139
140
|
| Status defaults to `filter='running'` | Only shows active agents, not completed history |
|
|
140
141
|
| Bash commands truncated to 120 chars | Heredocs collapsed to `cat <<EOF > path` |
|
|
141
142
|
| Last 5 messages only | Not full conversation history |
|
|
142
143
|
| File operations deduplicated | Sets of created/modified/read/deleted paths |
|
|
143
|
-
| Spawn returns immediately | No blocking, poll with
|
|
144
|
+
| Spawn returns immediately | No blocking, poll with Status later |
|
|
144
145
|
|
|
145
146
|
## Supported Agents
|
|
146
147
|
|
|
147
148
|
The server auto-discovers installed CLIs at startup:
|
|
148
149
|
|
|
149
150
|
| Agent | CLI | Best For |
|
|
150
|
-
|
|
151
|
+
| --- | --- | --- |
|
|
151
152
|
| Claude | `claude` | Best for complex research and open-ended exploration |
|
|
152
153
|
| Codex | `codex` | Fast, cheap. Self-contained features |
|
|
153
154
|
| Gemini | `gemini` | Complex multi-system features, architectural changes |
|
|
@@ -156,7 +157,7 @@ The server auto-discovers installed CLIs at startup:
|
|
|
156
157
|
## Modes
|
|
157
158
|
|
|
158
159
|
| Mode | File Access | Auto-loops? | Use Case |
|
|
159
|
-
|
|
160
|
+
| --- | --- | --- | --- |
|
|
160
161
|
| `plan` | Read-only | No | Research, exploration, code review |
|
|
161
162
|
| `edit` | Read + Write | No | Implementation, refactoring, fixes |
|
|
162
163
|
| `ralph` | Full yolo | Yes | Autonomous iteration through RALPH.md tasks |
|
|
@@ -196,16 +197,18 @@ Cover auth endpoints.
|
|
|
196
197
|
```
|
|
197
198
|
|
|
198
199
|
**How it works:**
|
|
200
|
+
|
|
199
201
|
1. Create a `RALPH.md` file in your project directory with tasks
|
|
200
|
-
2. Call `
|
|
202
|
+
2. Call `Spawn(mode='ralph', cwd='./my-project', prompt='Build the auth system')`
|
|
201
203
|
3. MCP spawns ONE agent with full permissions
|
|
202
204
|
4. Agent reads RALPH.md, understands the system, picks tasks logically
|
|
203
205
|
5. For each task: completes work, marks checkbox `## [x]`, adds update
|
|
204
|
-
6. Continues until all tasks checked (or you stop it with `
|
|
206
|
+
6. Continues until all tasks checked (or you stop it with `Stop` tool)
|
|
205
207
|
|
|
206
208
|
**Multiple ralph agents:** You can spawn multiple ralph agents in parallel for different directories or different RALPH.md files. The orchestrator controls this.
|
|
207
209
|
|
|
208
210
|
**Safety:**
|
|
211
|
+
|
|
209
212
|
- Scoped by `cwd` - orchestrator controls blast radius
|
|
210
213
|
- RALPH.md must exist before spawn
|
|
211
214
|
- Warns if used in home/system directories
|
|
@@ -214,18 +217,60 @@ Cover auth endpoints.
|
|
|
214
217
|
## Effort Levels
|
|
215
218
|
|
|
216
219
|
| Level | Models Used |
|
|
217
|
-
|
|
220
|
+
| --- | --- |
|
|
218
221
|
| `fast` | codex: gpt-5.2-codex, claude: claude-haiku-4-5, gemini: gemini-3-flash, cursor: composer-1 |
|
|
219
222
|
| `default` | codex: gpt-5.2-codex, claude: claude-sonnet-4-5, gemini: gemini-3-flash, cursor: composer-1 |
|
|
220
223
|
| `detailed` | codex: gpt-5.1-codex-max, claude: claude-opus-4-5, gemini: gemini-3-pro, cursor: composer-1 |
|
|
221
224
|
|
|
225
|
+
## Config
|
|
226
|
+
|
|
227
|
+
Config lives at `~/.swarmify/config.json`.
|
|
228
|
+
|
|
229
|
+
Example with per-agent swarm selection and effort model overrides:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"agents": {
|
|
234
|
+
"claude": {
|
|
235
|
+
"swarm": true,
|
|
236
|
+
"effort": {
|
|
237
|
+
"models": {
|
|
238
|
+
"fast": "claude-haiku-4-5-20251001",
|
|
239
|
+
"default": "claude-sonnet-4-5",
|
|
240
|
+
"detailed": "claude-opus-4-5"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"codex": { "swarm": true },
|
|
245
|
+
"gemini": { "swarm": true },
|
|
246
|
+
"cursor": { "swarm": false }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Shorthand for a single effort level override:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"agents": {
|
|
256
|
+
"claude": {
|
|
257
|
+
"swarm": true,
|
|
258
|
+
"effort": {
|
|
259
|
+
"level": "fast",
|
|
260
|
+
"model": "claude-haiku-4-5-20251001"
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
222
267
|
## Environment Variables
|
|
223
268
|
|
|
224
269
|
| Variable | Description |
|
|
225
|
-
|
|
226
|
-
| `
|
|
227
|
-
| `
|
|
228
|
-
| `
|
|
270
|
+
| --- | --- |
|
|
271
|
+
| `AGENTS_MCP_DEFAULT_MODE` | Set default mode (`plan` or `edit`) |
|
|
272
|
+
| `AGENTS_MCP_RALPH_FILE` | Task file name for ralph mode (default: `RALPH.md`) |
|
|
273
|
+
| `AGENTS_MCP_DISABLE_RALPH` | Set to `true` or `1` to disable ralph mode |
|
|
229
274
|
|
|
230
275
|
## Storage
|
|
231
276
|
|
package/dist/agents.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { type ModelOverrides } from './persistence.js';
|
|
1
2
|
import { AgentType } from './parsers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compute the Lowest Common Ancestor (LCA) of multiple file paths.
|
|
5
|
+
* Returns the deepest common directory shared by all paths.
|
|
6
|
+
* Returns null if paths is empty or paths have no common ancestor (different roots).
|
|
7
|
+
*/
|
|
8
|
+
export declare function computePathLCA(paths: string[]): string | null;
|
|
2
9
|
export declare enum AgentStatus {
|
|
3
10
|
RUNNING = "running",
|
|
4
11
|
COMPLETED = "completed",
|
|
@@ -8,7 +15,9 @@ export declare enum AgentStatus {
|
|
|
8
15
|
export type { AgentType } from './parsers.js';
|
|
9
16
|
export declare const AGENT_COMMANDS: Record<AgentType, string[]>;
|
|
10
17
|
export type EffortLevel = 'fast' | 'default' | 'detailed';
|
|
11
|
-
export
|
|
18
|
+
export type EffortModelMap = Record<EffortLevel, Record<AgentType, string>>;
|
|
19
|
+
export declare const EFFORT_MODEL_MAP: EffortModelMap;
|
|
20
|
+
export declare function resolveEffortModelMap(base: EffortModelMap, overrides: ModelOverrides | null | undefined): EffortModelMap;
|
|
12
21
|
declare const VALID_MODES: readonly ["plan", "edit", "ralph"];
|
|
13
22
|
type Mode = typeof VALID_MODES[number];
|
|
14
23
|
export declare function resolveMode(requestedMode: string | null | undefined, defaultMode?: Mode): Mode;
|
|
@@ -25,15 +34,17 @@ export declare class AgentProcess {
|
|
|
25
34
|
agentType: AgentType;
|
|
26
35
|
prompt: string;
|
|
27
36
|
cwd: string | null;
|
|
37
|
+
workspaceDir: string | null;
|
|
28
38
|
mode: Mode;
|
|
29
39
|
pid: number | null;
|
|
30
40
|
status: AgentStatus;
|
|
31
41
|
startedAt: Date;
|
|
32
42
|
completedAt: Date | null;
|
|
43
|
+
parentSessionId: string | null;
|
|
33
44
|
private eventsCache;
|
|
34
45
|
private lastReadPos;
|
|
35
46
|
private baseDir;
|
|
36
|
-
constructor(agentId: string, taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode, pid?: number | null, status?: AgentStatus, startedAt?: Date, completedAt?: Date | null, baseDir?: string | null);
|
|
47
|
+
constructor(agentId: string, taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode, pid?: number | null, status?: AgentStatus, startedAt?: Date, completedAt?: Date | null, baseDir?: string | null, parentSessionId?: string | null, workspaceDir?: string | null);
|
|
37
48
|
get isEditMode(): boolean;
|
|
38
49
|
getAgentDir(): Promise<string>;
|
|
39
50
|
getStdoutPath(): Promise<string>;
|
|
@@ -61,12 +72,14 @@ export declare class AgentManager {
|
|
|
61
72
|
private filterByCwd;
|
|
62
73
|
private cleanupAgeDays;
|
|
63
74
|
private defaultMode;
|
|
75
|
+
private effortModelMap;
|
|
64
76
|
private constructorAgentsDir;
|
|
65
|
-
constructor(maxAgents?: number, maxConcurrent?: number, agentsDir?: string | null, defaultMode?: Mode | null, filterByCwd?: string | null, cleanupAgeDays?: number);
|
|
77
|
+
constructor(maxAgents?: number, maxConcurrent?: number, agentsDir?: string | null, defaultMode?: Mode | null, filterByCwd?: string | null, cleanupAgeDays?: number, modelOverrides?: ModelOverrides | null);
|
|
66
78
|
private initialize;
|
|
67
79
|
getDefaultMode(): Mode;
|
|
80
|
+
setModelOverrides(overrides: ModelOverrides | null | undefined): void;
|
|
68
81
|
private loadExistingAgents;
|
|
69
|
-
spawn(taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode | null, effort?: EffortLevel): Promise<AgentProcess>;
|
|
82
|
+
spawn(taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode | null, effort?: EffortLevel, parentSessionId?: string | null, workspaceDir?: string | null): Promise<AgentProcess>;
|
|
70
83
|
private buildCommand;
|
|
71
84
|
private applyEditMode;
|
|
72
85
|
private applyRalphMode;
|
|
@@ -75,6 +88,7 @@ export declare class AgentManager {
|
|
|
75
88
|
listRunning(): Promise<AgentProcess[]>;
|
|
76
89
|
listCompleted(): Promise<AgentProcess[]>;
|
|
77
90
|
listByTask(taskName: string): Promise<AgentProcess[]>;
|
|
91
|
+
listByParentSession(parentSessionId: string): Promise<AgentProcess[]>;
|
|
78
92
|
stopByTask(taskName: string): Promise<{
|
|
79
93
|
stopped: string[];
|
|
80
94
|
alreadyStopped: string[];
|
package/dist/agents.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
|
package/dist/agents.js
CHANGED
|
@@ -5,6 +5,43 @@ import * as os from 'os';
|
|
|
5
5
|
import { randomUUID } from 'crypto';
|
|
6
6
|
import { resolveAgentsDir } from './persistence.js';
|
|
7
7
|
import { normalizeEvents } from './parsers.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compute the Lowest Common Ancestor (LCA) of multiple file paths.
|
|
10
|
+
* Returns the deepest common directory shared by all paths.
|
|
11
|
+
* Returns null if paths is empty or paths have no common ancestor (different roots).
|
|
12
|
+
*/
|
|
13
|
+
export function computePathLCA(paths) {
|
|
14
|
+
const validPaths = paths.filter(p => p && p.trim());
|
|
15
|
+
if (validPaths.length === 0)
|
|
16
|
+
return null;
|
|
17
|
+
if (validPaths.length === 1)
|
|
18
|
+
return validPaths[0];
|
|
19
|
+
// Normalize and split all paths into segments
|
|
20
|
+
const splitPaths = validPaths.map(p => {
|
|
21
|
+
const normalized = path.resolve(p);
|
|
22
|
+
// Split by path separator, filter empty segments
|
|
23
|
+
return normalized.split(path.sep).filter(seg => seg);
|
|
24
|
+
});
|
|
25
|
+
// Find minimum length
|
|
26
|
+
const minLen = Math.min(...splitPaths.map(p => p.length));
|
|
27
|
+
// Find common prefix
|
|
28
|
+
const commonSegments = [];
|
|
29
|
+
for (let i = 0; i < minLen; i++) {
|
|
30
|
+
const segment = splitPaths[0][i];
|
|
31
|
+
const allMatch = splitPaths.every(p => p[i] === segment);
|
|
32
|
+
if (allMatch) {
|
|
33
|
+
commonSegments.push(segment);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (commonSegments.length === 0)
|
|
40
|
+
return null;
|
|
41
|
+
// Reconstruct path (add leading separator for absolute paths)
|
|
42
|
+
const lca = path.sep + commonSegments.join(path.sep);
|
|
43
|
+
return lca;
|
|
44
|
+
}
|
|
8
45
|
export var AgentStatus;
|
|
9
46
|
(function (AgentStatus) {
|
|
10
47
|
AgentStatus["RUNNING"] = "running";
|
|
@@ -43,6 +80,32 @@ export const EFFORT_MODEL_MAP = {
|
|
|
43
80
|
cursor: 'composer-1',
|
|
44
81
|
},
|
|
45
82
|
};
|
|
83
|
+
export function resolveEffortModelMap(base, overrides) {
|
|
84
|
+
const resolved = {
|
|
85
|
+
fast: { ...base.fast },
|
|
86
|
+
default: { ...base.default },
|
|
87
|
+
detailed: { ...base.detailed },
|
|
88
|
+
};
|
|
89
|
+
if (!overrides)
|
|
90
|
+
return resolved;
|
|
91
|
+
for (const [agentType, effortOverrides] of Object.entries(overrides)) {
|
|
92
|
+
if (!effortOverrides)
|
|
93
|
+
continue;
|
|
94
|
+
if (!['codex', 'gemini', 'cursor', 'claude'].includes(agentType))
|
|
95
|
+
continue;
|
|
96
|
+
const typedAgent = agentType;
|
|
97
|
+
for (const level of ['fast', 'default', 'detailed']) {
|
|
98
|
+
const model = effortOverrides[level];
|
|
99
|
+
if (typeof model === 'string') {
|
|
100
|
+
const trimmed = model.trim();
|
|
101
|
+
if (trimmed) {
|
|
102
|
+
resolved[level][typedAgent] = trimmed;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return resolved;
|
|
108
|
+
}
|
|
46
109
|
// Suffix appended to all prompts to ensure agents provide a summary
|
|
47
110
|
const PROMPT_SUFFIX = `
|
|
48
111
|
|
|
@@ -65,7 +128,7 @@ function normalizeModeValue(modeValue) {
|
|
|
65
128
|
return null;
|
|
66
129
|
}
|
|
67
130
|
function defaultModeFromEnv() {
|
|
68
|
-
for (const envVar of ['
|
|
131
|
+
for (const envVar of ['AGENTS_MCP_MODE', 'AGENTS_MCP_DEFAULT_MODE']) {
|
|
69
132
|
const rawValue = process.env[envVar];
|
|
70
133
|
const parsed = normalizeModeValue(rawValue);
|
|
71
134
|
if (parsed) {
|
|
@@ -77,6 +140,49 @@ function defaultModeFromEnv() {
|
|
|
77
140
|
}
|
|
78
141
|
return 'plan';
|
|
79
142
|
}
|
|
143
|
+
function coerceDate(value) {
|
|
144
|
+
if (value === null || value === undefined)
|
|
145
|
+
return null;
|
|
146
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
147
|
+
const ms = value < 1e12 ? value * 1000 : value;
|
|
148
|
+
const date = new Date(ms);
|
|
149
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
150
|
+
}
|
|
151
|
+
if (typeof value === 'string') {
|
|
152
|
+
const trimmed = value.trim();
|
|
153
|
+
if (!trimmed)
|
|
154
|
+
return null;
|
|
155
|
+
const numeric = Number(trimmed);
|
|
156
|
+
if (!Number.isNaN(numeric)) {
|
|
157
|
+
const ms = numeric < 1e12 ? numeric * 1000 : numeric;
|
|
158
|
+
const date = new Date(ms);
|
|
159
|
+
if (!Number.isNaN(date.getTime()))
|
|
160
|
+
return date;
|
|
161
|
+
}
|
|
162
|
+
const date = new Date(trimmed);
|
|
163
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
function extractTimestamp(raw) {
|
|
168
|
+
if (!raw || typeof raw !== 'object')
|
|
169
|
+
return null;
|
|
170
|
+
const candidates = [
|
|
171
|
+
raw.timestamp,
|
|
172
|
+
raw.time,
|
|
173
|
+
raw.created_at,
|
|
174
|
+
raw.createdAt,
|
|
175
|
+
raw.ts,
|
|
176
|
+
raw.started_at,
|
|
177
|
+
raw.startedAt,
|
|
178
|
+
];
|
|
179
|
+
for (const candidate of candidates) {
|
|
180
|
+
const date = coerceDate(candidate);
|
|
181
|
+
if (date)
|
|
182
|
+
return date;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
80
186
|
export function resolveMode(requestedMode, defaultMode = 'plan') {
|
|
81
187
|
const normalizedDefault = normalizeModeValue(defaultMode);
|
|
82
188
|
if (!normalizedDefault) {
|
|
@@ -131,26 +237,30 @@ export class AgentProcess {
|
|
|
131
237
|
agentType;
|
|
132
238
|
prompt;
|
|
133
239
|
cwd;
|
|
240
|
+
workspaceDir;
|
|
134
241
|
mode = 'plan';
|
|
135
242
|
pid = null;
|
|
136
243
|
status = AgentStatus.RUNNING;
|
|
137
244
|
startedAt = new Date();
|
|
138
245
|
completedAt = null;
|
|
246
|
+
parentSessionId = null;
|
|
139
247
|
eventsCache = [];
|
|
140
248
|
lastReadPos = 0;
|
|
141
249
|
baseDir = null;
|
|
142
|
-
constructor(agentId, taskName, agentType, prompt, cwd = null, mode = 'plan', pid = null, status = AgentStatus.RUNNING, startedAt = new Date(), completedAt = null, baseDir = null) {
|
|
250
|
+
constructor(agentId, taskName, agentType, prompt, cwd = null, mode = 'plan', pid = null, status = AgentStatus.RUNNING, startedAt = new Date(), completedAt = null, baseDir = null, parentSessionId = null, workspaceDir = null) {
|
|
143
251
|
this.agentId = agentId;
|
|
144
252
|
this.taskName = taskName;
|
|
145
253
|
this.agentType = agentType;
|
|
146
254
|
this.prompt = prompt;
|
|
147
255
|
this.cwd = cwd;
|
|
256
|
+
this.workspaceDir = workspaceDir;
|
|
148
257
|
this.mode = mode;
|
|
149
258
|
this.pid = pid;
|
|
150
259
|
this.status = status;
|
|
151
260
|
this.startedAt = startedAt;
|
|
152
261
|
this.completedAt = completedAt;
|
|
153
262
|
this.baseDir = baseDir;
|
|
263
|
+
this.parentSessionId = parentSessionId;
|
|
154
264
|
}
|
|
155
265
|
get isEditMode() {
|
|
156
266
|
return this.mode === 'edit';
|
|
@@ -176,6 +286,8 @@ export class AgentProcess {
|
|
|
176
286
|
event_count: this.events.length,
|
|
177
287
|
duration: this.duration(),
|
|
178
288
|
mode: this.mode,
|
|
289
|
+
parent_session_id: this.parentSessionId,
|
|
290
|
+
workspace_dir: this.workspaceDir,
|
|
179
291
|
};
|
|
180
292
|
}
|
|
181
293
|
duration() {
|
|
@@ -225,6 +337,7 @@ export class AgentProcess {
|
|
|
225
337
|
const stats = await fs.stat(stdoutPath).catch(() => null);
|
|
226
338
|
if (!stats)
|
|
227
339
|
return;
|
|
340
|
+
const fallbackTimestamp = (stats.mtime || new Date()).toISOString();
|
|
228
341
|
const fd = await fs.open(stdoutPath, 'r');
|
|
229
342
|
const buffer = Buffer.alloc(1024 * 1024);
|
|
230
343
|
const { bytesRead } = await fd.read(buffer, 0, buffer.length, this.lastReadPos);
|
|
@@ -238,7 +351,9 @@ export class AgentProcess {
|
|
|
238
351
|
try {
|
|
239
352
|
const rawEvent = JSON.parse(line);
|
|
240
353
|
const events = normalizeEvents(this.agentType, rawEvent);
|
|
354
|
+
const resolvedTimestamp = extractTimestamp(rawEvent)?.toISOString() || fallbackTimestamp;
|
|
241
355
|
for (const event of events) {
|
|
356
|
+
event.timestamp = resolvedTimestamp;
|
|
242
357
|
this.eventsCache.push(event);
|
|
243
358
|
if (event.type === 'result' || event.type === 'turn.completed' || event.type === 'thread.completed') {
|
|
244
359
|
if (event.status === 'success' || event.type === 'turn.completed') {
|
|
@@ -256,7 +371,7 @@ export class AgentProcess {
|
|
|
256
371
|
this.eventsCache.push({
|
|
257
372
|
type: 'raw',
|
|
258
373
|
content: line,
|
|
259
|
-
timestamp:
|
|
374
|
+
timestamp: fallbackTimestamp,
|
|
260
375
|
});
|
|
261
376
|
}
|
|
262
377
|
}
|
|
@@ -274,11 +389,13 @@ export class AgentProcess {
|
|
|
274
389
|
agent_type: this.agentType,
|
|
275
390
|
prompt: this.prompt,
|
|
276
391
|
cwd: this.cwd,
|
|
392
|
+
workspace_dir: this.workspaceDir,
|
|
277
393
|
mode: this.mode,
|
|
278
394
|
pid: this.pid,
|
|
279
395
|
status: this.status,
|
|
280
396
|
started_at: this.startedAt.toISOString(),
|
|
281
397
|
completed_at: this.completedAt?.toISOString() || null,
|
|
398
|
+
parent_session_id: this.parentSessionId,
|
|
282
399
|
};
|
|
283
400
|
const metaPath = await this.getMetaPath();
|
|
284
401
|
await fs.writeFile(metaPath, JSON.stringify(meta, null, 2));
|
|
@@ -296,7 +413,7 @@ export class AgentProcess {
|
|
|
296
413
|
try {
|
|
297
414
|
const metaContent = await fs.readFile(metaPath, 'utf-8');
|
|
298
415
|
const meta = JSON.parse(metaContent);
|
|
299
|
-
const agent = new AgentProcess(meta.agent_id, meta.task_name || 'default', meta.agent_type, meta.prompt, meta.cwd || null, meta.mode === 'edit' ? 'edit' : 'plan', meta.pid || null, AgentStatus[meta.status] || AgentStatus.RUNNING, new Date(meta.started_at), meta.completed_at ? new Date(meta.completed_at) : null, baseDir);
|
|
416
|
+
const agent = new AgentProcess(meta.agent_id, meta.task_name || 'default', meta.agent_type, meta.prompt, meta.cwd || null, meta.mode === 'edit' ? 'edit' : 'plan', meta.pid || null, AgentStatus[meta.status] || AgentStatus.RUNNING, new Date(meta.started_at), meta.completed_at ? new Date(meta.completed_at) : null, baseDir, meta.parent_session_id || null, meta.workspace_dir || null);
|
|
300
417
|
return agent;
|
|
301
418
|
}
|
|
302
419
|
catch {
|
|
@@ -321,11 +438,11 @@ export class AgentProcess {
|
|
|
321
438
|
await this.readNewEvents();
|
|
322
439
|
return;
|
|
323
440
|
}
|
|
324
|
-
const fallbackCompletion = this.getLatestEventTime() || this.startedAt || new Date();
|
|
325
441
|
if (this.status === AgentStatus.RUNNING) {
|
|
326
442
|
const exitCode = await this.reapProcess();
|
|
327
443
|
await this.readNewEvents();
|
|
328
444
|
if (this.status === AgentStatus.RUNNING) {
|
|
445
|
+
const fallbackCompletion = this.getLatestEventTime() || this.startedAt || new Date();
|
|
329
446
|
if (exitCode !== null && exitCode !== 0) {
|
|
330
447
|
this.status = AgentStatus.FAILED;
|
|
331
448
|
}
|
|
@@ -336,6 +453,8 @@ export class AgentProcess {
|
|
|
336
453
|
}
|
|
337
454
|
}
|
|
338
455
|
else if (!this.completedAt) {
|
|
456
|
+
await this.readNewEvents();
|
|
457
|
+
const fallbackCompletion = this.getLatestEventTime() || this.startedAt || new Date();
|
|
339
458
|
this.completedAt = fallbackCompletion;
|
|
340
459
|
}
|
|
341
460
|
await this.saveMeta();
|
|
@@ -360,8 +479,9 @@ export class AgentManager {
|
|
|
360
479
|
filterByCwd;
|
|
361
480
|
cleanupAgeDays;
|
|
362
481
|
defaultMode;
|
|
482
|
+
effortModelMap = EFFORT_MODEL_MAP;
|
|
363
483
|
constructorAgentsDir = null;
|
|
364
|
-
constructor(maxAgents = 50, maxConcurrent = 10, agentsDir = null, defaultMode = null, filterByCwd = null, cleanupAgeDays = 7) {
|
|
484
|
+
constructor(maxAgents = 50, maxConcurrent = 10, agentsDir = null, defaultMode = null, filterByCwd = null, cleanupAgeDays = 7, modelOverrides = null) {
|
|
365
485
|
this.maxAgents = maxAgents;
|
|
366
486
|
this.maxConcurrent = maxConcurrent;
|
|
367
487
|
this.constructorAgentsDir = agentsDir;
|
|
@@ -372,6 +492,7 @@ export class AgentManager {
|
|
|
372
492
|
throw new Error(`Invalid default_mode '${defaultMode}'. Use 'plan' or 'edit'.`);
|
|
373
493
|
}
|
|
374
494
|
this.defaultMode = resolvedDefaultMode;
|
|
495
|
+
this.effortModelMap = resolveEffortModelMap(EFFORT_MODEL_MAP, modelOverrides);
|
|
375
496
|
this.initialize();
|
|
376
497
|
}
|
|
377
498
|
async initialize() {
|
|
@@ -382,6 +503,9 @@ export class AgentManager {
|
|
|
382
503
|
getDefaultMode() {
|
|
383
504
|
return this.defaultMode;
|
|
384
505
|
}
|
|
506
|
+
setModelOverrides(overrides) {
|
|
507
|
+
this.effortModelMap = resolveEffortModelMap(EFFORT_MODEL_MAP, overrides);
|
|
508
|
+
}
|
|
385
509
|
async loadExistingAgents() {
|
|
386
510
|
try {
|
|
387
511
|
await fs.access(this.agentsDir);
|
|
@@ -432,11 +556,11 @@ export class AgentManager {
|
|
|
432
556
|
}
|
|
433
557
|
console.error(`Loaded ${loadedCount} agents from disk`);
|
|
434
558
|
}
|
|
435
|
-
async spawn(taskName, agentType, prompt, cwd = null, mode = null, effort = 'default') {
|
|
559
|
+
async spawn(taskName, agentType, prompt, cwd = null, mode = null, effort = 'default', parentSessionId = null, workspaceDir = null) {
|
|
436
560
|
await this.initialize();
|
|
437
561
|
const resolvedMode = resolveMode(mode, this.defaultMode);
|
|
438
562
|
// Resolve model from effort level
|
|
439
|
-
const resolvedModel =
|
|
563
|
+
const resolvedModel = this.effortModelMap[effort][agentType];
|
|
440
564
|
const running = await this.listRunning();
|
|
441
565
|
if (running.length >= this.maxConcurrent) {
|
|
442
566
|
throw new Error(`Maximum concurrent agents (${this.maxConcurrent}) reached. Wait for an agent to complete or stop one first.`);
|
|
@@ -459,7 +583,7 @@ export class AgentManager {
|
|
|
459
583
|
}
|
|
460
584
|
const agentId = randomUUID().substring(0, 8);
|
|
461
585
|
const cmd = this.buildCommand(agentType, prompt, resolvedMode, resolvedModel, resolvedCwd);
|
|
462
|
-
const agent = new AgentProcess(agentId, taskName, agentType, prompt, resolvedCwd, resolvedMode, null, AgentStatus.RUNNING, new Date(), null, this.agentsDir);
|
|
586
|
+
const agent = new AgentProcess(agentId, taskName, agentType, prompt, resolvedCwd, resolvedMode, null, AgentStatus.RUNNING, new Date(), null, this.agentsDir, parentSessionId, workspaceDir);
|
|
463
587
|
const agentDir = await agent.getAgentDir();
|
|
464
588
|
try {
|
|
465
589
|
await fs.mkdir(agentDir, { recursive: true });
|
|
@@ -618,6 +742,10 @@ export class AgentManager {
|
|
|
618
742
|
const all = await this.listAll();
|
|
619
743
|
return all.filter(a => a.taskName === taskName);
|
|
620
744
|
}
|
|
745
|
+
async listByParentSession(parentSessionId) {
|
|
746
|
+
const all = await this.listAll();
|
|
747
|
+
return all.filter(a => a.parentSessionId === parentSessionId);
|
|
748
|
+
}
|
|
621
749
|
async stopByTask(taskName) {
|
|
622
750
|
const agents = await this.listByTask(taskName);
|
|
623
751
|
const stopped = [];
|