@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.
@@ -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.14.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.9",
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"