@finityno/claude-code-acp 0.14.0 → 0.16.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/dist/acp-agent.d.ts +11 -0
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +131 -6
- package/dist/lib.d.ts +5 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +7 -0
- package/dist/mcp-server.d.ts +2 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +14 -1
- package/dist/subagent-tracker.d.ts +102 -2
- package/dist/subagent-tracker.d.ts.map +1 -1
- package/dist/subagent-tracker.js +189 -22
- package/dist/task-manager.d.ts +106 -0
- package/dist/task-manager.d.ts.map +1 -0
- package/dist/task-manager.js +231 -0
- package/dist/task-mcp-tools.d.ts +16 -0
- package/dist/task-mcp-tools.d.ts.map +1 -0
- package/dist/task-mcp-tools.js +256 -0
- package/dist/task-store.d.ts +123 -0
- package/dist/task-store.d.ts.map +1 -0
- package/dist/task-store.js +292 -0
- package/dist/work-item-mcp-tools.d.ts +12 -0
- package/dist/work-item-mcp-tools.d.ts.map +1 -0
- package/dist/work-item-mcp-tools.js +296 -0
- package/package.json +2 -2
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Register MCP tools for work item task management (TaskCreate, TaskGet, TaskUpdate, TaskList)
|
|
4
|
+
* These match Claude Code's internal task system stored in ~/.claude/tasks/
|
|
5
|
+
*/
|
|
6
|
+
export function registerWorkItemMcpTools(server, options) {
|
|
7
|
+
const { taskStore } = options;
|
|
8
|
+
// TaskCreate - Create a new task
|
|
9
|
+
server.registerTool("TaskCreate", {
|
|
10
|
+
title: "Create Task",
|
|
11
|
+
description: `Use this tool to create a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
12
|
+
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
13
|
+
|
|
14
|
+
## When to Use This Tool
|
|
15
|
+
|
|
16
|
+
Use this tool proactively in these scenarios:
|
|
17
|
+
|
|
18
|
+
- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
19
|
+
- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
20
|
+
- User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
21
|
+
- User provides multiple tasks - When users provide a list of things to be done
|
|
22
|
+
- After receiving new instructions - Immediately capture user requirements as tasks
|
|
23
|
+
- When you start working on a task - Mark it as in_progress BEFORE beginning work
|
|
24
|
+
- After completing a task - Mark it as completed
|
|
25
|
+
|
|
26
|
+
## Task Fields
|
|
27
|
+
|
|
28
|
+
- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
|
|
29
|
+
- **description**: Detailed description of what needs to be done, including context and acceptance criteria
|
|
30
|
+
- **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug")
|
|
31
|
+
|
|
32
|
+
**IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative ("Run tests") while activeForm should be present continuous ("Running tests").`,
|
|
33
|
+
inputSchema: {
|
|
34
|
+
subject: z.string().describe("A brief title for the task in imperative form"),
|
|
35
|
+
description: z.string().describe("A detailed description of what needs to be done"),
|
|
36
|
+
activeForm: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Present continuous form shown in spinner when in_progress (e.g., "Running tests")'),
|
|
40
|
+
metadata: z
|
|
41
|
+
.record(z.string(), z.unknown())
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Arbitrary metadata to attach to the task"),
|
|
44
|
+
},
|
|
45
|
+
annotations: {
|
|
46
|
+
title: "Create task",
|
|
47
|
+
readOnlyHint: false,
|
|
48
|
+
},
|
|
49
|
+
}, async (input) => {
|
|
50
|
+
try {
|
|
51
|
+
const task = await taskStore.create({
|
|
52
|
+
subject: input.subject,
|
|
53
|
+
description: input.description,
|
|
54
|
+
activeForm: input.activeForm,
|
|
55
|
+
metadata: input.metadata,
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: `Created task ${task.id}: "${task.subject}"`,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return {
|
|
68
|
+
isError: true,
|
|
69
|
+
content: [{ type: "text", text: `Failed to create task: ${err}` }],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// TaskGet - Get a task by ID
|
|
74
|
+
server.registerTool("TaskGet", {
|
|
75
|
+
title: "Get Task",
|
|
76
|
+
description: `Use this tool to retrieve a task by its ID from the task list.
|
|
77
|
+
|
|
78
|
+
## When to Use This Tool
|
|
79
|
+
|
|
80
|
+
- When you need the full description and context before starting work on a task
|
|
81
|
+
- To understand task dependencies (what it blocks, what blocks it)
|
|
82
|
+
- After being assigned a task, to get complete requirements
|
|
83
|
+
|
|
84
|
+
## Output
|
|
85
|
+
|
|
86
|
+
Returns full task details:
|
|
87
|
+
- **subject**: Task title
|
|
88
|
+
- **description**: Detailed requirements and context
|
|
89
|
+
- **status**: 'pending', 'in_progress', or 'completed'
|
|
90
|
+
- **blocks**: Tasks waiting on this one to complete
|
|
91
|
+
- **blockedBy**: Tasks that must complete before this one can start
|
|
92
|
+
|
|
93
|
+
## Tips
|
|
94
|
+
|
|
95
|
+
- After fetching a task, verify its blockedBy list is empty before beginning work.
|
|
96
|
+
- Use TaskList to see all tasks in summary form.`,
|
|
97
|
+
inputSchema: {
|
|
98
|
+
taskId: z.string().describe("The ID of the task to retrieve"),
|
|
99
|
+
},
|
|
100
|
+
annotations: {
|
|
101
|
+
title: "Get task",
|
|
102
|
+
readOnlyHint: true,
|
|
103
|
+
},
|
|
104
|
+
}, async (input) => {
|
|
105
|
+
try {
|
|
106
|
+
const task = await taskStore.get(input.taskId);
|
|
107
|
+
if (!task) {
|
|
108
|
+
return {
|
|
109
|
+
isError: true,
|
|
110
|
+
content: [{ type: "text", text: `Task not found: ${input.taskId}` }],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: "text",
|
|
117
|
+
text: JSON.stringify(task, null, 2),
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
return {
|
|
124
|
+
isError: true,
|
|
125
|
+
content: [{ type: "text", text: `Failed to get task: ${err}` }],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// TaskUpdate - Update a task
|
|
130
|
+
server.registerTool("TaskUpdate", {
|
|
131
|
+
title: "Update Task",
|
|
132
|
+
description: `Use this tool to update a task in the task list.
|
|
133
|
+
|
|
134
|
+
## When to Use This Tool
|
|
135
|
+
|
|
136
|
+
**Mark tasks as resolved:**
|
|
137
|
+
- When you have completed the work described in a task
|
|
138
|
+
- When a task is no longer needed or has been superseded
|
|
139
|
+
- IMPORTANT: Always mark your assigned tasks as resolved when you finish them
|
|
140
|
+
- After resolving, call TaskList to find your next task
|
|
141
|
+
|
|
142
|
+
**Update task details:**
|
|
143
|
+
- When requirements change or become clearer
|
|
144
|
+
- When establishing dependencies between tasks
|
|
145
|
+
|
|
146
|
+
## Fields You Can Update
|
|
147
|
+
|
|
148
|
+
- **status**: The task status ('pending', 'in_progress', 'completed')
|
|
149
|
+
- **subject**: Change the task title (imperative form, e.g., "Run tests")
|
|
150
|
+
- **description**: Change the task description
|
|
151
|
+
- **activeForm**: Present continuous form shown when in_progress
|
|
152
|
+
- **owner**: Change the task owner (agent name)
|
|
153
|
+
- **metadata**: Merge metadata keys into the task (set a key to null to delete it)
|
|
154
|
+
- **addBlocks**: Mark tasks that cannot start until this one completes
|
|
155
|
+
- **addBlockedBy**: Mark tasks that must complete before this one can start
|
|
156
|
+
|
|
157
|
+
## Status Workflow
|
|
158
|
+
|
|
159
|
+
Status progresses: \`pending\` → \`in_progress\` → \`completed\`
|
|
160
|
+
|
|
161
|
+
## Examples
|
|
162
|
+
|
|
163
|
+
Mark task as in progress when starting work:
|
|
164
|
+
\`\`\`json
|
|
165
|
+
{"taskId": "1", "status": "in_progress"}
|
|
166
|
+
\`\`\`
|
|
167
|
+
|
|
168
|
+
Mark task as completed after finishing work:
|
|
169
|
+
\`\`\`json
|
|
170
|
+
{"taskId": "1", "status": "completed"}
|
|
171
|
+
\`\`\`
|
|
172
|
+
|
|
173
|
+
Set up task dependencies:
|
|
174
|
+
\`\`\`json
|
|
175
|
+
{"taskId": "2", "addBlockedBy": ["1"]}
|
|
176
|
+
\`\`\``,
|
|
177
|
+
inputSchema: {
|
|
178
|
+
taskId: z.string().describe("The ID of the task to update"),
|
|
179
|
+
status: z
|
|
180
|
+
.enum(["pending", "in_progress", "completed"])
|
|
181
|
+
.optional()
|
|
182
|
+
.describe("New status for the task"),
|
|
183
|
+
subject: z.string().optional().describe("New subject for the task"),
|
|
184
|
+
description: z.string().optional().describe("New description for the task"),
|
|
185
|
+
activeForm: z
|
|
186
|
+
.string()
|
|
187
|
+
.optional()
|
|
188
|
+
.describe('Present continuous form shown in spinner when in_progress (e.g., "Running tests")'),
|
|
189
|
+
owner: z.string().optional().describe("New owner for the task"),
|
|
190
|
+
addBlocks: z
|
|
191
|
+
.array(z.string())
|
|
192
|
+
.optional()
|
|
193
|
+
.describe("Task IDs that this task blocks"),
|
|
194
|
+
addBlockedBy: z
|
|
195
|
+
.array(z.string())
|
|
196
|
+
.optional()
|
|
197
|
+
.describe("Task IDs that block this task"),
|
|
198
|
+
metadata: z
|
|
199
|
+
.record(z.string(), z.unknown())
|
|
200
|
+
.optional()
|
|
201
|
+
.describe("Metadata keys to merge into the task. Set a key to null to delete it."),
|
|
202
|
+
},
|
|
203
|
+
annotations: {
|
|
204
|
+
title: "Update task",
|
|
205
|
+
readOnlyHint: false,
|
|
206
|
+
},
|
|
207
|
+
}, async (input) => {
|
|
208
|
+
try {
|
|
209
|
+
const task = await taskStore.update(input.taskId, {
|
|
210
|
+
status: input.status,
|
|
211
|
+
subject: input.subject,
|
|
212
|
+
description: input.description,
|
|
213
|
+
activeForm: input.activeForm,
|
|
214
|
+
owner: input.owner,
|
|
215
|
+
addBlocks: input.addBlocks,
|
|
216
|
+
addBlockedBy: input.addBlockedBy,
|
|
217
|
+
metadata: input.metadata,
|
|
218
|
+
});
|
|
219
|
+
let message = `Updated task ${task.id}: "${task.subject}" (${task.status})`;
|
|
220
|
+
if (task.status === "completed") {
|
|
221
|
+
message +=
|
|
222
|
+
"\n\nTask completed. Call TaskList now to find your next available task or see if your work unblocked others.";
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
content: [{ type: "text", text: message }],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
return {
|
|
230
|
+
isError: true,
|
|
231
|
+
content: [{ type: "text", text: `Failed to update task: ${err}` }],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// TaskList - List all tasks
|
|
236
|
+
server.registerTool("TaskList", {
|
|
237
|
+
title: "List Tasks",
|
|
238
|
+
description: `Use this tool to list all tasks in the task list.
|
|
239
|
+
|
|
240
|
+
## When to Use This Tool
|
|
241
|
+
|
|
242
|
+
- To see what tasks are available to work on (status: 'pending', no owner, not blocked)
|
|
243
|
+
- To check overall progress on the project
|
|
244
|
+
- To find tasks that are blocked and need dependencies resolved
|
|
245
|
+
- Before assigning tasks to teammates, to see what's available
|
|
246
|
+
- After completing a task, to check for newly unblocked work or claim the next available task
|
|
247
|
+
|
|
248
|
+
## Output
|
|
249
|
+
|
|
250
|
+
Returns a summary of each task:
|
|
251
|
+
- **id**: Task identifier (use with TaskGet, TaskUpdate)
|
|
252
|
+
- **subject**: Brief description of the task
|
|
253
|
+
- **status**: 'pending', 'in_progress', or 'completed'
|
|
254
|
+
- **owner**: Agent ID if assigned, empty if available
|
|
255
|
+
- **blockedBy**: List of open task IDs that must be resolved first
|
|
256
|
+
|
|
257
|
+
Use TaskGet with a specific task ID to view full details including description.`,
|
|
258
|
+
inputSchema: {},
|
|
259
|
+
annotations: {
|
|
260
|
+
title: "List tasks",
|
|
261
|
+
readOnlyHint: true,
|
|
262
|
+
},
|
|
263
|
+
}, async () => {
|
|
264
|
+
try {
|
|
265
|
+
const tasks = await taskStore.list();
|
|
266
|
+
const stats = await taskStore.getStats();
|
|
267
|
+
const summary = tasks.map((t) => ({
|
|
268
|
+
id: t.id,
|
|
269
|
+
subject: t.subject,
|
|
270
|
+
status: t.status,
|
|
271
|
+
owner: t.owner,
|
|
272
|
+
blockedBy: t.blockedBy.filter((id) => {
|
|
273
|
+
const blocker = tasks.find((task) => task.id === id);
|
|
274
|
+
return blocker && blocker.status !== "completed";
|
|
275
|
+
}),
|
|
276
|
+
}));
|
|
277
|
+
return {
|
|
278
|
+
content: [
|
|
279
|
+
{
|
|
280
|
+
type: "text",
|
|
281
|
+
text: JSON.stringify({
|
|
282
|
+
stats,
|
|
283
|
+
tasks: summary,
|
|
284
|
+
}, null, 2),
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
return {
|
|
291
|
+
isError: true,
|
|
292
|
+
content: [{ type: "text", text: `Failed to list tasks: ${err}` }],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.16.0",
|
|
7
7
|
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
|
|
8
8
|
"main": "dist/lib.js",
|
|
9
9
|
"types": "dist/lib.d.ts",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"license": "Apache-2.0",
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@agentclientprotocol/sdk": "0.13.0",
|
|
64
|
-
"@anthropic-ai/claude-agent-sdk": "0.2.
|
|
64
|
+
"@anthropic-ai/claude-agent-sdk": "0.2.18",
|
|
65
65
|
"@modelcontextprotocol/sdk": "1.25.2",
|
|
66
66
|
"diff": "8.0.3",
|
|
67
67
|
"minimatch": "10.1.1"
|