dispatch-agents 0.4.0 → 0.5.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.
- package/README.md +35 -0
- package/dist/cli.js +33 -11
- package/dist/mcp.js +263 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -49,6 +49,41 @@ npm link
|
|
|
49
49
|
- `git` — for worktree management
|
|
50
50
|
- iTerm2 (recommended) — for native tab integration via `tmux -CC`
|
|
51
51
|
|
|
52
|
+
## MCP Server
|
|
53
|
+
|
|
54
|
+
Dispatch includes an MCP server so Claude Code can orchestrate agents directly — no shell commands needed.
|
|
55
|
+
|
|
56
|
+
### Setup
|
|
57
|
+
|
|
58
|
+
After installing dispatch, register the MCP server with Claude Code:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
claude mcp add --scope user dispatch node $(which dispatch-mcp)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This exposes 6 tools to Claude Code:
|
|
65
|
+
|
|
66
|
+
| Tool | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `dispatch_run` | Launch an agent with a prompt (inline text, not a file) |
|
|
69
|
+
| `dispatch_list` | List all running agents with status |
|
|
70
|
+
| `dispatch_stop` | Stop a running agent |
|
|
71
|
+
| `dispatch_resume` | Resume a stopped agent |
|
|
72
|
+
| `dispatch_cleanup` | Remove worktrees and optionally branches |
|
|
73
|
+
| `dispatch_logs` | Get recent output from an agent |
|
|
74
|
+
|
|
75
|
+
### How it works
|
|
76
|
+
|
|
77
|
+
The MCP server wraps the dispatch CLI over stdio using the [Model Context Protocol](https://modelcontextprotocol.io). When Claude Code calls `dispatch_run`, the server writes the prompt to a temp file, runs `dispatch run --prompt-file <file>`, and cleans up. Interactive agents open iTerm tabs; headless agents run in the background.
|
|
78
|
+
|
|
79
|
+
### Working directory
|
|
80
|
+
|
|
81
|
+
By default the MCP server uses the directory Claude Code is running in. To override, set `DISPATCH_CWD`:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
claude mcp add --scope user dispatch -e DISPATCH_CWD=/path/to/repo node $(which dispatch-mcp)
|
|
85
|
+
```
|
|
86
|
+
|
|
52
87
|
## Usage
|
|
53
88
|
|
|
54
89
|
### Launch an agent
|
package/dist/cli.js
CHANGED
|
@@ -211,6 +211,8 @@ function ensureSession() {
|
|
|
211
211
|
execSync(
|
|
212
212
|
`tmux new-session -d -s "${DISPATCH_SESSION}" -n "dispatch"`
|
|
213
213
|
);
|
|
214
|
+
execSync(`tmux set -t "${DISPATCH_SESSION}" -g mouse on`);
|
|
215
|
+
execSync(`tmux set -t "${DISPATCH_SESSION}" -g history-limit 50000`);
|
|
214
216
|
execSync(
|
|
215
217
|
`tmux send-keys -t "${DISPATCH_SESSION}:dispatch" "# Dispatch control window" Enter`
|
|
216
218
|
);
|
|
@@ -419,6 +421,9 @@ function tailFile(path) {
|
|
|
419
421
|
|
|
420
422
|
// src/commands.ts
|
|
421
423
|
var TICKET_RE = /^[A-Z]+-[0-9]+$/;
|
|
424
|
+
function slugify(text) {
|
|
425
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
|
|
426
|
+
}
|
|
422
427
|
function buildClaudeCmd(prompt, mode, wtPath, config, extraArgs) {
|
|
423
428
|
let cmd = "claude";
|
|
424
429
|
if (mode === "headless") cmd += " -p";
|
|
@@ -433,7 +438,7 @@ function buildClaudeCmd(prompt, mode, wtPath, config, extraArgs) {
|
|
|
433
438
|
if (mode === "headless") {
|
|
434
439
|
const promptFile = join3(wtPath, ".dispatch-prompt.txt");
|
|
435
440
|
writeFileSync2(promptFile, prompt);
|
|
436
|
-
cmd += `
|
|
441
|
+
cmd += ` < '${promptFile}'`;
|
|
437
442
|
}
|
|
438
443
|
return cmd;
|
|
439
444
|
}
|
|
@@ -442,9 +447,9 @@ async function launchAgent(input, headless, extraArgs, skipWorktree, promptFileA
|
|
|
442
447
|
let prompt;
|
|
443
448
|
let branch;
|
|
444
449
|
if (TICKET_RE.test(input)) {
|
|
445
|
-
id = input;
|
|
446
|
-
branch = input.toLowerCase();
|
|
447
450
|
const ticket = await fetchLinearTicket(input);
|
|
451
|
+
id = `${input.toLowerCase()}-${slugify(ticket.title)}`;
|
|
452
|
+
branch = id;
|
|
448
453
|
if (ticket.description) {
|
|
449
454
|
prompt = `Linear ticket ${input}: ${ticket.title}
|
|
450
455
|
|
|
@@ -455,14 +460,13 @@ Work on this ticket. Create commits as you go. When done, push the branch.`;
|
|
|
455
460
|
prompt = `Work on ticket ${input}: ${ticket.title}. Create commits as you go. When done, push the branch.`;
|
|
456
461
|
}
|
|
457
462
|
} else {
|
|
458
|
-
|
|
459
|
-
id = `task-${suffix}`;
|
|
463
|
+
id = slugify(input) || `task-${String(Date.now()).slice(-6)}`;
|
|
460
464
|
branch = id;
|
|
461
465
|
prompt = input;
|
|
462
466
|
}
|
|
463
467
|
if (nameOverride) {
|
|
464
|
-
id = nameOverride;
|
|
465
|
-
branch =
|
|
468
|
+
id = slugify(nameOverride) || nameOverride;
|
|
469
|
+
branch = id;
|
|
466
470
|
}
|
|
467
471
|
if (promptFileArg) {
|
|
468
472
|
if (!existsSync2(promptFileArg)) {
|
|
@@ -474,6 +478,15 @@ Work on this ticket. Create commits as you go. When done, push the branch.`;
|
|
|
474
478
|
}
|
|
475
479
|
const { readFileSync: readFileSync4 } = await import("fs");
|
|
476
480
|
prompt = readFileSync4(promptFileArg, "utf-8");
|
|
481
|
+
if (!nameOverride && !TICKET_RE.test(input)) {
|
|
482
|
+
const firstLine = prompt.split("\n").find((l) => l.trim().length > 0) || "";
|
|
483
|
+
const clean = firstLine.replace(/^#+\s*/, "");
|
|
484
|
+
const derived = slugify(clean);
|
|
485
|
+
if (derived) {
|
|
486
|
+
id = derived;
|
|
487
|
+
branch = id;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
477
490
|
}
|
|
478
491
|
if (windowExists(id)) {
|
|
479
492
|
log.error(`Agent '${id}' is already running. Use 'dispatch stop ${id}' first.`);
|
|
@@ -526,6 +539,7 @@ async function cmdRun(args, config) {
|
|
|
526
539
|
let extraArgs = "";
|
|
527
540
|
let skipWorktree = false;
|
|
528
541
|
let nameOverride = "";
|
|
542
|
+
let noAttach = false;
|
|
529
543
|
let i = 0;
|
|
530
544
|
while (i < args.length) {
|
|
531
545
|
const arg = args[i];
|
|
@@ -562,6 +576,10 @@ async function cmdRun(args, config) {
|
|
|
562
576
|
skipWorktree = true;
|
|
563
577
|
i++;
|
|
564
578
|
break;
|
|
579
|
+
case "--no-attach":
|
|
580
|
+
noAttach = true;
|
|
581
|
+
i++;
|
|
582
|
+
break;
|
|
565
583
|
case "--name":
|
|
566
584
|
case "-n":
|
|
567
585
|
nameOverride = args[++i];
|
|
@@ -589,6 +607,9 @@ async function cmdRun(args, config) {
|
|
|
589
607
|
console.log(" dispatch run HEY-837 --base main # branch off main");
|
|
590
608
|
process.exit(1);
|
|
591
609
|
}
|
|
610
|
+
if (inputs.length === 0 && promptFile) {
|
|
611
|
+
inputs.push("prompt-file");
|
|
612
|
+
}
|
|
592
613
|
ensureTmux();
|
|
593
614
|
if (inputs.length > 1) {
|
|
594
615
|
log.info(`Batch launching ${inputs.length} agents...`);
|
|
@@ -598,7 +619,7 @@ async function cmdRun(args, config) {
|
|
|
598
619
|
await launchAgent(input, headless, extraArgs, skipWorktree, promptFile, nameOverride, config);
|
|
599
620
|
}
|
|
600
621
|
console.log();
|
|
601
|
-
if (!headless && inputs.length === 1) {
|
|
622
|
+
if (!headless && inputs.length === 1 && !noAttach) {
|
|
602
623
|
log.info("Attaching to tmux session...");
|
|
603
624
|
log.dim(" Detach with: Ctrl-B then D");
|
|
604
625
|
console.log();
|
|
@@ -687,10 +708,11 @@ function cmdStop(args) {
|
|
|
687
708
|
function cmdResume(args, config) {
|
|
688
709
|
const id = args[0];
|
|
689
710
|
if (!id) {
|
|
690
|
-
log.error("Usage: dispatch resume <agent-id> [--headless]");
|
|
711
|
+
log.error("Usage: dispatch resume <agent-id> [--headless] [--no-attach]");
|
|
691
712
|
process.exit(1);
|
|
692
713
|
}
|
|
693
714
|
const headless = args.includes("--headless") || args.includes("-H");
|
|
715
|
+
const noAttach = args.includes("--no-attach");
|
|
694
716
|
ensureTmux();
|
|
695
717
|
const wtPath = worktreePath(id, config);
|
|
696
718
|
if (!existsSync2(wtPath)) {
|
|
@@ -709,7 +731,7 @@ function cmdResume(args, config) {
|
|
|
709
731
|
`tmux send-keys -t "${tmuxTarget(id)}" "unset CLAUDECODE && claude --continue ${modelFlag}" Enter`
|
|
710
732
|
);
|
|
711
733
|
log.ok(`Resumed agent: ${id} (interactive)`);
|
|
712
|
-
tmuxAttach();
|
|
734
|
+
if (!noAttach) tmuxAttach();
|
|
713
735
|
} else {
|
|
714
736
|
const resumePrompt = "Continue working on the task.";
|
|
715
737
|
const claudeCmd = buildClaudeCmd(
|
|
@@ -858,7 +880,7 @@ function cmdSetup() {
|
|
|
858
880
|
}
|
|
859
881
|
|
|
860
882
|
// src/cli.ts
|
|
861
|
-
var VERSION = "0.4.
|
|
883
|
+
var VERSION = "0.4.1";
|
|
862
884
|
function help() {
|
|
863
885
|
console.log(`dispatch \u2014 Launch Claude Code agents in isolated git worktrees
|
|
864
886
|
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/mcp.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
ListToolsRequestSchema
|
|
9
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { execSync } from "child_process";
|
|
11
|
+
import {
|
|
12
|
+
writeFileSync,
|
|
13
|
+
unlinkSync,
|
|
14
|
+
readFileSync,
|
|
15
|
+
existsSync
|
|
16
|
+
} from "fs";
|
|
17
|
+
import { tmpdir } from "os";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
import { randomBytes } from "crypto";
|
|
20
|
+
function stripAnsi(str) {
|
|
21
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "").replace(/\x1b\][^\x07]*\x07/g, "");
|
|
22
|
+
}
|
|
23
|
+
function dispatch(args) {
|
|
24
|
+
const cwd = process.env.DISPATCH_CWD || process.cwd();
|
|
25
|
+
try {
|
|
26
|
+
const output = execSync(`dispatch ${args}`, {
|
|
27
|
+
encoding: "utf-8",
|
|
28
|
+
cwd,
|
|
29
|
+
timeout: 12e4,
|
|
30
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
31
|
+
});
|
|
32
|
+
return stripAnsi(output).trim();
|
|
33
|
+
} catch (e) {
|
|
34
|
+
const out = [e.stdout, e.stderr, e.message].filter(Boolean).join("\n");
|
|
35
|
+
return stripAnsi(out).trim();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function makeTempPrompt(prompt) {
|
|
39
|
+
const name = `dispatch-mcp-${randomBytes(4).toString("hex")}.md`;
|
|
40
|
+
const path = join(tmpdir(), name);
|
|
41
|
+
writeFileSync(path, prompt);
|
|
42
|
+
return path;
|
|
43
|
+
}
|
|
44
|
+
var server = new Server(
|
|
45
|
+
{ name: "dispatch", version: "0.1.0" },
|
|
46
|
+
{ capabilities: { tools: {} } }
|
|
47
|
+
);
|
|
48
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
49
|
+
tools: [
|
|
50
|
+
{
|
|
51
|
+
name: "dispatch_run",
|
|
52
|
+
description: "Launch a Claude Code agent in an isolated git worktree. Pass the full task prompt inline. Returns agent ID and branch name.",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: {
|
|
56
|
+
prompt: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "Full task description/prompt for the agent"
|
|
59
|
+
},
|
|
60
|
+
ticket: {
|
|
61
|
+
type: "string",
|
|
62
|
+
description: "Linear ticket ID (e.g. HEY-907). Fetches title + description if LINEAR_API_KEY is set."
|
|
63
|
+
},
|
|
64
|
+
name: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Agent name and branch name (kebab-case). Defaults to ticket ID or derived from prompt."
|
|
67
|
+
},
|
|
68
|
+
headless: {
|
|
69
|
+
type: "boolean",
|
|
70
|
+
description: "Run in background (fire-and-forget). Default: false (interactive)."
|
|
71
|
+
},
|
|
72
|
+
model: {
|
|
73
|
+
type: "string",
|
|
74
|
+
description: "Claude model: sonnet, opus, haiku"
|
|
75
|
+
},
|
|
76
|
+
base_branch: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Branch to create worktree from. Default: dev."
|
|
79
|
+
},
|
|
80
|
+
max_turns: {
|
|
81
|
+
type: "number",
|
|
82
|
+
description: "Max agentic turns (headless only)"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
required: ["prompt"]
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "dispatch_list",
|
|
90
|
+
description: "List all running dispatch agents with their status (running/idle/exited).",
|
|
91
|
+
inputSchema: { type: "object", properties: {} }
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "dispatch_stop",
|
|
95
|
+
description: "Stop a running dispatch agent. Worktree and branch are preserved.",
|
|
96
|
+
inputSchema: {
|
|
97
|
+
type: "object",
|
|
98
|
+
properties: {
|
|
99
|
+
agent_id: { type: "string", description: "Agent ID to stop" }
|
|
100
|
+
},
|
|
101
|
+
required: ["agent_id"]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "dispatch_resume",
|
|
106
|
+
description: "Resume a previously stopped agent. Picks up where it left off.",
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: "object",
|
|
109
|
+
properties: {
|
|
110
|
+
agent_id: {
|
|
111
|
+
type: "string",
|
|
112
|
+
description: "Agent ID to resume"
|
|
113
|
+
},
|
|
114
|
+
headless: {
|
|
115
|
+
type: "boolean",
|
|
116
|
+
description: "Resume in headless mode"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
required: ["agent_id"]
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "dispatch_cleanup",
|
|
124
|
+
description: "Remove an agent's worktree and optionally its branch.",
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: "object",
|
|
127
|
+
properties: {
|
|
128
|
+
agent_id: {
|
|
129
|
+
type: "string",
|
|
130
|
+
description: "Agent ID to clean up. Omit and set all=true for all agents."
|
|
131
|
+
},
|
|
132
|
+
all: {
|
|
133
|
+
type: "boolean",
|
|
134
|
+
description: "Clean up all worktrees"
|
|
135
|
+
},
|
|
136
|
+
delete_branch: {
|
|
137
|
+
type: "boolean",
|
|
138
|
+
description: "Also delete the git branch"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "dispatch_logs",
|
|
145
|
+
description: "Get recent output from a dispatch agent (log file or tmux capture).",
|
|
146
|
+
inputSchema: {
|
|
147
|
+
type: "object",
|
|
148
|
+
properties: {
|
|
149
|
+
agent_id: { type: "string", description: "Agent ID" },
|
|
150
|
+
lines: {
|
|
151
|
+
type: "number",
|
|
152
|
+
description: "Number of lines to return. Default: 50."
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
required: ["agent_id"]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}));
|
|
160
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
161
|
+
const { name, arguments: args = {} } = request.params;
|
|
162
|
+
switch (name) {
|
|
163
|
+
case "dispatch_run": {
|
|
164
|
+
const {
|
|
165
|
+
prompt,
|
|
166
|
+
ticket,
|
|
167
|
+
name: agentName,
|
|
168
|
+
headless,
|
|
169
|
+
model,
|
|
170
|
+
base_branch,
|
|
171
|
+
max_turns
|
|
172
|
+
} = args;
|
|
173
|
+
const tmpFile = makeTempPrompt(prompt);
|
|
174
|
+
try {
|
|
175
|
+
const parts = ["run"];
|
|
176
|
+
parts.push(ticket || "prompt-file");
|
|
177
|
+
parts.push(`--prompt-file "${tmpFile}"`);
|
|
178
|
+
if (agentName) parts.push(`--name "${agentName}"`);
|
|
179
|
+
if (headless) parts.push("--headless");
|
|
180
|
+
if (model) parts.push(`--model ${model}`);
|
|
181
|
+
if (base_branch) parts.push(`--base ${base_branch}`);
|
|
182
|
+
if (max_turns) parts.push(`--max-turns ${max_turns}`);
|
|
183
|
+
if (headless) parts.push("--no-attach");
|
|
184
|
+
const output = dispatch(parts.join(" "));
|
|
185
|
+
return { content: [{ type: "text", text: output }] };
|
|
186
|
+
} finally {
|
|
187
|
+
try {
|
|
188
|
+
unlinkSync(tmpFile);
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
case "dispatch_list": {
|
|
194
|
+
const output = dispatch("list");
|
|
195
|
+
return {
|
|
196
|
+
content: [{ type: "text", text: output || "No agents running." }]
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
case "dispatch_stop": {
|
|
200
|
+
const { agent_id } = args;
|
|
201
|
+
const output = dispatch(`stop ${agent_id}`);
|
|
202
|
+
return { content: [{ type: "text", text: output }] };
|
|
203
|
+
}
|
|
204
|
+
case "dispatch_resume": {
|
|
205
|
+
const { agent_id, headless } = args;
|
|
206
|
+
const flags = headless ? "--headless" : "";
|
|
207
|
+
const output = dispatch(
|
|
208
|
+
`resume ${agent_id} ${flags} --no-attach`.trim()
|
|
209
|
+
);
|
|
210
|
+
return { content: [{ type: "text", text: output }] };
|
|
211
|
+
}
|
|
212
|
+
case "dispatch_cleanup": {
|
|
213
|
+
const { agent_id, all, delete_branch } = args;
|
|
214
|
+
const parts = ["cleanup"];
|
|
215
|
+
if (all) parts.push("--all");
|
|
216
|
+
else if (agent_id) parts.push(agent_id);
|
|
217
|
+
if (delete_branch) parts.push("--delete-branch");
|
|
218
|
+
const output = dispatch(parts.join(" "));
|
|
219
|
+
return { content: [{ type: "text", text: output }] };
|
|
220
|
+
}
|
|
221
|
+
case "dispatch_logs": {
|
|
222
|
+
const { agent_id, lines = 50 } = args;
|
|
223
|
+
const cwd = process.env.DISPATCH_CWD || process.cwd();
|
|
224
|
+
const logPath = join(cwd, ".worktrees", agent_id, ".dispatch.log");
|
|
225
|
+
if (existsSync(logPath)) {
|
|
226
|
+
const content = readFileSync(logPath, "utf-8");
|
|
227
|
+
const logLines = content.split("\n");
|
|
228
|
+
const lastLines = logLines.slice(-lines).join("\n");
|
|
229
|
+
return {
|
|
230
|
+
content: [{ type: "text", text: stripAnsi(lastLines) }]
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
const output = execSync(
|
|
235
|
+
`tmux capture-pane -t "dispatch:${agent_id}" -p -S -${lines}`,
|
|
236
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
237
|
+
);
|
|
238
|
+
return {
|
|
239
|
+
content: [{ type: "text", text: stripAnsi(output).trim() }]
|
|
240
|
+
};
|
|
241
|
+
} catch {
|
|
242
|
+
return {
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: "text",
|
|
246
|
+
text: `Agent '${agent_id}' not found or no output available.`
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
default:
|
|
253
|
+
return {
|
|
254
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
255
|
+
isError: true
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
async function main() {
|
|
260
|
+
const transport = new StdioServerTransport();
|
|
261
|
+
await server.connect(transport);
|
|
262
|
+
}
|
|
263
|
+
main().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dispatch-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Orchestrate Claude Code agents in git worktrees",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"dispatch": "./dist/cli.js"
|
|
7
|
+
"dispatch": "./dist/cli.js",
|
|
8
|
+
"dispatch-mcp": "./dist/mcp.js"
|
|
8
9
|
},
|
|
9
10
|
"scripts": {
|
|
10
11
|
"build": "tsup",
|
|
@@ -26,6 +27,9 @@
|
|
|
26
27
|
"type": "git",
|
|
27
28
|
"url": "https://github.com/paperMoose/dispatch.git"
|
|
28
29
|
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
32
|
+
},
|
|
29
33
|
"devDependencies": {
|
|
30
34
|
"tsup": "^8.0.0",
|
|
31
35
|
"tsx": "^4.0.0",
|