wave-agent-sdk 0.17.0 → 0.17.2
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/builtin/skills/deep-research/SKILL.md +90 -0
- package/builtin/skills/settings/ENV.md +6 -3
- package/dist/agent.d.ts +28 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +128 -34
- package/dist/constants/goalPrompts.d.ts +2 -0
- package/dist/constants/goalPrompts.d.ts.map +1 -0
- package/dist/constants/goalPrompts.js +10 -0
- package/dist/constants/tools.d.ts +1 -0
- package/dist/constants/tools.d.ts.map +1 -1
- package/dist/constants/tools.js +1 -0
- package/dist/managers/aiManager.d.ts +7 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +77 -41
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +10 -2
- package/dist/managers/goalManager.d.ts +43 -0
- package/dist/managers/goalManager.d.ts.map +1 -0
- package/dist/managers/goalManager.js +177 -0
- package/dist/managers/messageManager.d.ts +2 -2
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageQueue.d.ts +10 -0
- package/dist/managers/messageQueue.d.ts.map +1 -1
- package/dist/managers/messageQueue.js +53 -1
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +7 -1
- package/dist/managers/skillManager.d.ts +2 -0
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +19 -9
- package/dist/managers/slashCommandManager.d.ts +6 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +105 -0
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +5 -0
- package/dist/managers/workflowManager.d.ts +65 -0
- package/dist/managers/workflowManager.d.ts.map +1 -0
- package/dist/managers/workflowManager.js +380 -0
- package/dist/prompts/index.d.ts +2 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +3 -3
- package/dist/services/aiService.d.ts +23 -0
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +102 -9
- package/dist/services/configurationService.d.ts +1 -1
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +3 -16
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +4 -0
- package/dist/services/session.d.ts +9 -1
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +28 -1
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +49 -7
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +1 -1
- package/dist/tools/taskManagementTools.d.ts.map +1 -1
- package/dist/tools/taskManagementTools.js +103 -157
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/webFetchTool.d.ts.map +1 -1
- package/dist/tools/webFetchTool.js +0 -9
- package/dist/tools/workflowTool.d.ts +11 -0
- package/dist/tools/workflowTool.d.ts.map +1 -0
- package/dist/tools/workflowTool.js +190 -0
- package/dist/types/agent.d.ts +2 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/commands.d.ts +4 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/config.d.ts +2 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core.d.ts +1 -1
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +2 -0
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/messaging.d.ts +2 -2
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +6 -2
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/types/workflow.d.ts +2 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +1 -0
- package/dist/utils/cacheControlUtils.d.ts +13 -8
- package/dist/utils/cacheControlUtils.d.ts.map +1 -1
- package/dist/utils/cacheControlUtils.js +73 -102
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +7 -0
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +21 -6
- package/dist/utils/messageOperations.d.ts +2 -2
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/notificationXml.d.ts.map +1 -1
- package/dist/workflow/budgetTracker.d.ts +12 -0
- package/dist/workflow/budgetTracker.d.ts.map +1 -0
- package/dist/workflow/budgetTracker.js +30 -0
- package/dist/workflow/concurrencyLimiter.d.ts +14 -0
- package/dist/workflow/concurrencyLimiter.d.ts.map +1 -0
- package/dist/workflow/concurrencyLimiter.js +39 -0
- package/dist/workflow/journal.d.ts +19 -0
- package/dist/workflow/journal.d.ts.map +1 -0
- package/dist/workflow/journal.js +74 -0
- package/dist/workflow/progressReporter.d.ts +21 -0
- package/dist/workflow/progressReporter.d.ts.map +1 -0
- package/dist/workflow/progressReporter.js +118 -0
- package/dist/workflow/runState.d.ts +16 -0
- package/dist/workflow/runState.d.ts.map +1 -0
- package/dist/workflow/runState.js +57 -0
- package/dist/workflow/scriptRuntime.d.ts +35 -0
- package/dist/workflow/scriptRuntime.d.ts.map +1 -0
- package/dist/workflow/scriptRuntime.js +196 -0
- package/dist/workflow/structuredOutput.d.ts +27 -0
- package/dist/workflow/structuredOutput.d.ts.map +1 -0
- package/dist/workflow/structuredOutput.js +106 -0
- package/dist/workflow/types.d.ts +81 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow/types.js +1 -0
- package/dist/workflow/workflowApis.d.ts +46 -0
- package/dist/workflow/workflowApis.d.ts.map +1 -0
- package/dist/workflow/workflowApis.js +280 -0
- package/package.json +1 -1
- package/src/agent.ts +144 -34
- package/src/constants/goalPrompts.ts +10 -0
- package/src/constants/tools.ts +1 -0
- package/src/managers/aiManager.ts +91 -47
- package/src/managers/backgroundTaskManager.ts +16 -4
- package/src/managers/goalManager.ts +232 -0
- package/src/managers/messageManager.ts +2 -2
- package/src/managers/messageQueue.ts +59 -1
- package/src/managers/pluginManager.ts +8 -1
- package/src/managers/skillManager.ts +20 -9
- package/src/managers/slashCommandManager.ts +119 -0
- package/src/managers/toolManager.ts +7 -0
- package/src/managers/workflowManager.ts +491 -0
- package/src/prompts/index.ts +4 -2
- package/src/services/aiService.ts +166 -12
- package/src/services/configurationService.ts +2 -22
- package/src/services/hook.ts +5 -0
- package/src/services/session.ts +42 -2
- package/src/tools/bashTool.ts +64 -9
- package/src/tools/readTool.ts +1 -2
- package/src/tools/taskManagementTools.ts +146 -195
- package/src/tools/types.ts +2 -0
- package/src/tools/webFetchTool.ts +0 -12
- package/src/tools/workflowTool.ts +205 -0
- package/src/types/agent.ts +6 -0
- package/src/types/commands.ts +4 -0
- package/src/types/config.ts +2 -2
- package/src/types/core.ts +3 -3
- package/src/types/hooks.ts +2 -0
- package/src/types/index.ts +1 -0
- package/src/types/messaging.ts +2 -2
- package/src/types/processes.ts +10 -2
- package/src/types/workflow.ts +5 -0
- package/src/utils/cacheControlUtils.ts +106 -131
- package/src/utils/containerSetup.ts +9 -0
- package/src/utils/markdownParser.ts +26 -8
- package/src/utils/messageOperations.ts +2 -2
- package/src/utils/notificationXml.ts +6 -1
- package/src/workflow/budgetTracker.ts +34 -0
- package/src/workflow/concurrencyLimiter.ts +47 -0
- package/src/workflow/journal.ts +95 -0
- package/src/workflow/progressReporter.ts +141 -0
- package/src/workflow/runState.ts +65 -0
- package/src/workflow/scriptRuntime.ts +274 -0
- package/src/workflow/structuredOutput.ts +123 -0
- package/src/workflow/types.ts +95 -0
- package/src/workflow/workflowApis.ts +412 -0
|
@@ -7,6 +7,42 @@ import {
|
|
|
7
7
|
TASK_LIST_TOOL_NAME,
|
|
8
8
|
} from "../constants/tools.js";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Helper to record and commit a reversion snapshot for a task file.
|
|
12
|
+
*/
|
|
13
|
+
async function recordSnapshot(
|
|
14
|
+
context: ToolContext,
|
|
15
|
+
taskManager: { getTaskPath: (id: string) => string },
|
|
16
|
+
taskId: string,
|
|
17
|
+
operation: "create" | "modify" | "delete",
|
|
18
|
+
): Promise<string | undefined> {
|
|
19
|
+
if (!context.reversionManager || !context.messageId) return undefined;
|
|
20
|
+
const snapshotId = await context.reversionManager.recordSnapshot(
|
|
21
|
+
context.messageId,
|
|
22
|
+
taskManager.getTaskPath(taskId),
|
|
23
|
+
operation,
|
|
24
|
+
);
|
|
25
|
+
await context.reversionManager.commitSnapshot(snapshotId);
|
|
26
|
+
return snapshotId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Helper to update a target task's blocks/blockedBy array and record a reversion snapshot.
|
|
31
|
+
*/
|
|
32
|
+
async function updateTaskField(
|
|
33
|
+
context: ToolContext,
|
|
34
|
+
taskManager: {
|
|
35
|
+
getTaskPath: (id: string) => string;
|
|
36
|
+
updateTask: (task: Task) => Promise<void>;
|
|
37
|
+
},
|
|
38
|
+
targetTask: Task,
|
|
39
|
+
field: "blocks" | "blockedBy",
|
|
40
|
+
value: string[],
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
await recordSnapshot(context, taskManager, targetTask.id, "modify");
|
|
43
|
+
await taskManager.updateTask({ ...targetTask, [field]: value });
|
|
44
|
+
}
|
|
45
|
+
|
|
10
46
|
export const taskCreateTool: ToolPlugin = {
|
|
11
47
|
name: TASK_CREATE_TOOL_NAME,
|
|
12
48
|
config: {
|
|
@@ -23,32 +59,13 @@ export const taskCreateTool: ToolPlugin = {
|
|
|
23
59
|
},
|
|
24
60
|
description: {
|
|
25
61
|
type: "string",
|
|
26
|
-
description: "
|
|
27
|
-
},
|
|
28
|
-
status: {
|
|
29
|
-
type: "string",
|
|
30
|
-
enum: ["pending", "in_progress", "completed", "deleted"],
|
|
31
|
-
description: "Initial status of the task. Defaults to 'pending'.",
|
|
62
|
+
description: "What needs to be done",
|
|
32
63
|
},
|
|
33
64
|
activeForm: {
|
|
34
65
|
type: "string",
|
|
35
66
|
description:
|
|
36
67
|
'Present continuous form shown in spinner when in_progress (e.g., "Running tests")',
|
|
37
68
|
},
|
|
38
|
-
owner: {
|
|
39
|
-
type: "string",
|
|
40
|
-
description: "Optional owner of the task.",
|
|
41
|
-
},
|
|
42
|
-
blocks: {
|
|
43
|
-
type: "array",
|
|
44
|
-
items: { type: "string" },
|
|
45
|
-
description: "List of task IDs that this task blocks.",
|
|
46
|
-
},
|
|
47
|
-
blockedBy: {
|
|
48
|
-
type: "array",
|
|
49
|
-
items: { type: "string" },
|
|
50
|
-
description: "List of task IDs that block this task.",
|
|
51
|
-
},
|
|
52
69
|
metadata: {
|
|
53
70
|
type: "object",
|
|
54
71
|
description: "Arbitrary metadata to attach to the task",
|
|
@@ -88,7 +105,7 @@ NOTE that you should not use this tool if there is only one trivial task to do.
|
|
|
88
105
|
## Task Fields
|
|
89
106
|
|
|
90
107
|
- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
|
|
91
|
-
- **description**:
|
|
108
|
+
- **description**: What needs to be done, including context and acceptance criteria
|
|
92
109
|
- **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.
|
|
93
110
|
|
|
94
111
|
**IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative ("Run tests") while activeForm should be present continuous ("Running tests"). All tasks are created with status \`pending\`.
|
|
@@ -102,40 +119,23 @@ NOTE that you should not use this tool if there is only one trivial task to do.
|
|
|
102
119
|
execute: async (args, context: ToolContext): Promise<ToolResult> => {
|
|
103
120
|
const taskManager = context.taskManager;
|
|
104
121
|
|
|
105
|
-
if (args.status === "deleted") {
|
|
106
|
-
return {
|
|
107
|
-
success: true,
|
|
108
|
-
content: `Task creation skipped because status was set to 'deleted'.`,
|
|
109
|
-
shortResult: `Skipped deleted task`,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
122
|
const task: Omit<Task, "id"> = {
|
|
114
123
|
subject: args.subject as string,
|
|
115
124
|
description: args.description as string,
|
|
116
|
-
status:
|
|
125
|
+
status: "pending",
|
|
117
126
|
activeForm: args.activeForm as string,
|
|
118
|
-
owner:
|
|
119
|
-
blocks:
|
|
120
|
-
blockedBy:
|
|
127
|
+
owner: undefined,
|
|
128
|
+
blocks: [],
|
|
129
|
+
blockedBy: [],
|
|
121
130
|
metadata: (args.metadata as Record<string, unknown>) || {},
|
|
122
131
|
};
|
|
123
132
|
|
|
124
133
|
const taskId = await taskManager.createTask(task);
|
|
125
|
-
|
|
126
|
-
if (context.reversionManager && context.messageId) {
|
|
127
|
-
const taskPath = taskManager.getTaskPath(taskId);
|
|
128
|
-
const snapshotId = await context.reversionManager.recordSnapshot(
|
|
129
|
-
context.messageId,
|
|
130
|
-
taskPath,
|
|
131
|
-
"create",
|
|
132
|
-
);
|
|
133
|
-
await context.reversionManager.commitSnapshot(snapshotId);
|
|
134
|
-
}
|
|
134
|
+
await recordSnapshot(context, taskManager, taskId, "create");
|
|
135
135
|
|
|
136
136
|
return {
|
|
137
137
|
success: true,
|
|
138
|
-
content: `Task created
|
|
138
|
+
content: `Task #${taskId} created successfully: ${task.subject}`,
|
|
139
139
|
shortResult: `Created task ${taskId}: ${task.subject}`,
|
|
140
140
|
};
|
|
141
141
|
},
|
|
@@ -189,13 +189,28 @@ Returns full task details:
|
|
|
189
189
|
if (!task) {
|
|
190
190
|
return {
|
|
191
191
|
success: false,
|
|
192
|
-
content: `Task
|
|
192
|
+
content: `Task not found`,
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// Format like Claude Code: structured text instead of raw JSON
|
|
197
|
+
const lines = [
|
|
198
|
+
`Task #${task.id}: ${task.subject}`,
|
|
199
|
+
`Status: ${task.status}`,
|
|
200
|
+
`Description: ${task.description}`,
|
|
201
|
+
];
|
|
202
|
+
if (task.blockedBy.length > 0) {
|
|
203
|
+
lines.push(
|
|
204
|
+
`Blocked by: ${task.blockedBy.map((id) => `#${id}`).join(", ")}`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (task.blocks.length > 0) {
|
|
208
|
+
lines.push(`Blocks: ${task.blocks.map((id) => `#${id}`).join(", ")}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
196
211
|
return {
|
|
197
212
|
success: true,
|
|
198
|
-
content:
|
|
213
|
+
content: lines.join("\n"),
|
|
199
214
|
};
|
|
200
215
|
},
|
|
201
216
|
};
|
|
@@ -339,210 +354,139 @@ Set up task dependencies:
|
|
|
339
354
|
if (!existingTask) {
|
|
340
355
|
return {
|
|
341
356
|
success: false,
|
|
342
|
-
content: `Task
|
|
357
|
+
content: `Task #${taskId} not found`,
|
|
343
358
|
};
|
|
344
359
|
}
|
|
345
360
|
|
|
361
|
+
// Handle deletion — just delete the task file (like Claude Code)
|
|
346
362
|
if (args.status === "deleted") {
|
|
347
|
-
|
|
348
|
-
// For each task in the deleted task's blocks list, remove the deleted task's ID from their blockedBy list.
|
|
349
|
-
for (const targetId of existingTask.blocks) {
|
|
350
|
-
const targetTask = await taskManager.getTask(targetId);
|
|
351
|
-
if (targetTask && targetTask.blockedBy.includes(taskId)) {
|
|
352
|
-
let targetSnapshotId: string | undefined;
|
|
353
|
-
if (context.reversionManager && context.messageId) {
|
|
354
|
-
const targetPath = taskManager.getTaskPath(targetId);
|
|
355
|
-
targetSnapshotId = await context.reversionManager.recordSnapshot(
|
|
356
|
-
context.messageId,
|
|
357
|
-
targetPath,
|
|
358
|
-
"modify",
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
await taskManager.updateTask({
|
|
362
|
-
...targetTask,
|
|
363
|
-
blockedBy: targetTask.blockedBy.filter((id) => id !== taskId),
|
|
364
|
-
});
|
|
365
|
-
if (context.reversionManager && targetSnapshotId) {
|
|
366
|
-
await context.reversionManager.commitSnapshot(targetSnapshotId);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// For each task in the deleted task's blockedBy list, remove the deleted task's ID from their blocks list.
|
|
372
|
-
for (const targetId of existingTask.blockedBy) {
|
|
373
|
-
const targetTask = await taskManager.getTask(targetId);
|
|
374
|
-
if (targetTask && targetTask.blocks.includes(taskId)) {
|
|
375
|
-
let targetSnapshotId: string | undefined;
|
|
376
|
-
if (context.reversionManager && context.messageId) {
|
|
377
|
-
const targetPath = taskManager.getTaskPath(targetId);
|
|
378
|
-
targetSnapshotId = await context.reversionManager.recordSnapshot(
|
|
379
|
-
context.messageId,
|
|
380
|
-
targetPath,
|
|
381
|
-
"modify",
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
await taskManager.updateTask({
|
|
385
|
-
...targetTask,
|
|
386
|
-
blocks: targetTask.blocks.filter((id) => id !== taskId),
|
|
387
|
-
});
|
|
388
|
-
if (context.reversionManager && targetSnapshotId) {
|
|
389
|
-
await context.reversionManager.commitSnapshot(targetSnapshotId);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Record delete snapshot for the task itself
|
|
395
|
-
if (context.reversionManager && context.messageId) {
|
|
396
|
-
const taskPath = taskManager.getTaskPath(taskId);
|
|
397
|
-
const deleteSnapshotId = await context.reversionManager.recordSnapshot(
|
|
398
|
-
context.messageId,
|
|
399
|
-
taskPath,
|
|
400
|
-
"delete",
|
|
401
|
-
);
|
|
402
|
-
await context.reversionManager.commitSnapshot(deleteSnapshotId);
|
|
403
|
-
}
|
|
404
|
-
|
|
363
|
+
await recordSnapshot(context, taskManager, taskId, "delete");
|
|
405
364
|
await taskManager.deleteTask(taskId);
|
|
406
365
|
|
|
407
366
|
return {
|
|
408
367
|
success: true,
|
|
409
|
-
content: `Task #${taskId} deleted
|
|
368
|
+
content: `Task #${taskId} deleted`,
|
|
410
369
|
shortResult: `Deleted task ${taskId}`,
|
|
411
370
|
};
|
|
412
371
|
}
|
|
413
372
|
|
|
414
|
-
|
|
415
|
-
if (context.reversionManager && context.messageId) {
|
|
416
|
-
const taskPath = taskManager.getTaskPath(taskId);
|
|
417
|
-
snapshotId = await context.reversionManager.recordSnapshot(
|
|
418
|
-
context.messageId,
|
|
419
|
-
taskPath,
|
|
420
|
-
"modify",
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
|
|
373
|
+
// Build updates object — only include changed fields
|
|
424
374
|
const updatedFields: string[] = [];
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
375
|
+
const updates: {
|
|
376
|
+
subject?: string;
|
|
377
|
+
description?: string;
|
|
378
|
+
activeForm?: string;
|
|
379
|
+
status?: TaskStatus;
|
|
380
|
+
owner?: string;
|
|
381
|
+
metadata?: Record<string, unknown>;
|
|
382
|
+
} = {};
|
|
429
383
|
|
|
430
384
|
if (args.subject !== undefined && args.subject !== existingTask.subject) {
|
|
431
|
-
|
|
385
|
+
updates.subject = args.subject as string;
|
|
432
386
|
updatedFields.push("subject");
|
|
433
387
|
}
|
|
434
388
|
if (
|
|
435
389
|
args.description !== undefined &&
|
|
436
390
|
args.description !== existingTask.description
|
|
437
391
|
) {
|
|
438
|
-
|
|
392
|
+
updates.description = args.description as string;
|
|
439
393
|
updatedFields.push("description");
|
|
440
394
|
}
|
|
441
|
-
if (args.status !== undefined && args.status !== existingTask.status) {
|
|
442
|
-
updatedTask.status = args.status as TaskStatus;
|
|
443
|
-
updatedFields.push("status");
|
|
444
|
-
}
|
|
445
395
|
if (
|
|
446
396
|
args.activeForm !== undefined &&
|
|
447
397
|
args.activeForm !== existingTask.activeForm
|
|
448
398
|
) {
|
|
449
|
-
|
|
399
|
+
updates.activeForm = args.activeForm as string;
|
|
450
400
|
updatedFields.push("activeForm");
|
|
451
401
|
}
|
|
452
402
|
if (args.owner !== undefined && args.owner !== existingTask.owner) {
|
|
453
|
-
|
|
403
|
+
updates.owner = args.owner as string;
|
|
454
404
|
updatedFields.push("owner");
|
|
455
405
|
}
|
|
406
|
+
if (args.status !== undefined && args.status !== existingTask.status) {
|
|
407
|
+
updates.status = args.status as TaskStatus;
|
|
408
|
+
updatedFields.push("status");
|
|
409
|
+
}
|
|
456
410
|
|
|
411
|
+
// Merge metadata (null values delete keys)
|
|
457
412
|
if (args.metadata !== undefined) {
|
|
458
|
-
const
|
|
413
|
+
const merged = { ...(existingTask.metadata ?? {}) };
|
|
459
414
|
for (const [key, value] of Object.entries(
|
|
460
415
|
args.metadata as Record<string, unknown>,
|
|
461
416
|
)) {
|
|
462
417
|
if (value === null) {
|
|
463
|
-
delete
|
|
418
|
+
delete merged[key];
|
|
464
419
|
} else {
|
|
465
|
-
|
|
420
|
+
merged[key] = value;
|
|
466
421
|
}
|
|
467
422
|
}
|
|
468
|
-
|
|
423
|
+
updates.metadata = merged;
|
|
469
424
|
updatedFields.push("metadata");
|
|
470
425
|
}
|
|
471
426
|
|
|
427
|
+
// Apply basic field updates
|
|
428
|
+
if (Object.keys(updates).length > 0) {
|
|
429
|
+
await recordSnapshot(context, taskManager, taskId, "modify");
|
|
430
|
+
await taskManager.updateTask({ ...existingTask, ...updates });
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Add blocks: update this task's blocks + reciprocal blockedBy on targets
|
|
472
434
|
if (args.addBlocks !== undefined) {
|
|
473
435
|
const blocksToAdd = (args.addBlocks as string[]).filter(
|
|
474
|
-
(id) => !
|
|
436
|
+
(id) => !existingTask.blocks.includes(id),
|
|
475
437
|
);
|
|
476
438
|
if (blocksToAdd.length > 0) {
|
|
477
|
-
|
|
439
|
+
await recordSnapshot(context, taskManager, taskId, "modify");
|
|
440
|
+
await taskManager.updateTask({
|
|
441
|
+
...existingTask,
|
|
442
|
+
...updates,
|
|
443
|
+
blocks: [...existingTask.blocks, ...blocksToAdd],
|
|
444
|
+
});
|
|
478
445
|
updatedFields.push("blocks");
|
|
479
446
|
|
|
480
|
-
// Also update the blockedBy of the target tasks
|
|
481
447
|
for (const targetId of blocksToAdd) {
|
|
482
448
|
const targetTask = await taskManager.getTask(targetId);
|
|
483
449
|
if (targetTask && !targetTask.blockedBy.includes(taskId)) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
await taskManager.updateTask({
|
|
494
|
-
...targetTask,
|
|
495
|
-
blockedBy: [...targetTask.blockedBy, taskId],
|
|
496
|
-
});
|
|
497
|
-
if (context.reversionManager && targetSnapshotId) {
|
|
498
|
-
await context.reversionManager.commitSnapshot(targetSnapshotId);
|
|
499
|
-
}
|
|
450
|
+
await updateTaskField(
|
|
451
|
+
context,
|
|
452
|
+
taskManager,
|
|
453
|
+
targetTask,
|
|
454
|
+
"blockedBy",
|
|
455
|
+
[...targetTask.blockedBy, taskId],
|
|
456
|
+
);
|
|
500
457
|
}
|
|
501
458
|
}
|
|
502
459
|
}
|
|
503
460
|
}
|
|
504
461
|
|
|
462
|
+
// Add blockedBy: update this task's blockedBy + reciprocal blocks on targets
|
|
505
463
|
if (args.addBlockedBy !== undefined) {
|
|
506
464
|
const blockedByToAdd = (args.addBlockedBy as string[]).filter(
|
|
507
|
-
(id) => !
|
|
465
|
+
(id) => !existingTask.blockedBy.includes(id),
|
|
508
466
|
);
|
|
509
467
|
if (blockedByToAdd.length > 0) {
|
|
510
|
-
|
|
468
|
+
await recordSnapshot(context, taskManager, taskId, "modify");
|
|
469
|
+
await taskManager.updateTask({
|
|
470
|
+
...existingTask,
|
|
471
|
+
...updates,
|
|
472
|
+
blockedBy: [...existingTask.blockedBy, ...blockedByToAdd],
|
|
473
|
+
});
|
|
511
474
|
updatedFields.push("blockedBy");
|
|
512
475
|
|
|
513
|
-
// Also update the blocks of the target tasks
|
|
514
476
|
for (const targetId of blockedByToAdd) {
|
|
515
477
|
const targetTask = await taskManager.getTask(targetId);
|
|
516
478
|
if (targetTask && !targetTask.blocks.includes(taskId)) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
context.messageId,
|
|
522
|
-
targetPath,
|
|
523
|
-
"modify",
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
|
-
await taskManager.updateTask({
|
|
527
|
-
...targetTask,
|
|
528
|
-
blocks: [...targetTask.blocks, taskId],
|
|
529
|
-
});
|
|
530
|
-
if (context.reversionManager && targetSnapshotId) {
|
|
531
|
-
await context.reversionManager.commitSnapshot(targetSnapshotId);
|
|
532
|
-
}
|
|
479
|
+
await updateTaskField(context, taskManager, targetTask, "blocks", [
|
|
480
|
+
...targetTask.blocks,
|
|
481
|
+
taskId,
|
|
482
|
+
]);
|
|
533
483
|
}
|
|
534
484
|
}
|
|
535
485
|
}
|
|
536
486
|
}
|
|
537
487
|
|
|
538
|
-
await taskManager.updateTask(updatedTask);
|
|
539
|
-
|
|
540
|
-
if (context.reversionManager && snapshotId) {
|
|
541
|
-
await context.reversionManager.commitSnapshot(snapshotId);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
488
|
let content = `Updated task #${taskId} ${updatedFields.join(", ")}`;
|
|
545
|
-
if (
|
|
489
|
+
if (updates.status === "completed") {
|
|
546
490
|
content += `\n\nTask completed. Call TaskList now to find your next available task or see if your work unblocked others.`;
|
|
547
491
|
}
|
|
548
492
|
|
|
@@ -563,13 +507,7 @@ export const taskListTool: ToolPlugin = {
|
|
|
563
507
|
description: "List all tasks in the task list",
|
|
564
508
|
parameters: {
|
|
565
509
|
type: "object",
|
|
566
|
-
properties: {
|
|
567
|
-
status: {
|
|
568
|
-
type: "string",
|
|
569
|
-
enum: ["pending", "in_progress", "completed", "deleted"],
|
|
570
|
-
description: "Optional filter by status.",
|
|
571
|
-
},
|
|
572
|
-
},
|
|
510
|
+
properties: {},
|
|
573
511
|
},
|
|
574
512
|
},
|
|
575
513
|
},
|
|
@@ -593,26 +531,39 @@ Returns a summary of each task:
|
|
|
593
531
|
- **blockedBy**: List of open task IDs that must be resolved first (tasks with blockedBy cannot be claimed until dependencies resolve)
|
|
594
532
|
|
|
595
533
|
Use TaskGet with a specific task ID to view full details including description and comments.`,
|
|
596
|
-
execute: async (
|
|
534
|
+
execute: async (_args, context: ToolContext): Promise<ToolResult> => {
|
|
597
535
|
const taskManager = context.taskManager;
|
|
598
536
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
537
|
+
// Filter out internal metadata tasks (like Claude Code)
|
|
538
|
+
const allTasks = (await taskManager.listTasks()).filter(
|
|
539
|
+
(t) => !(t.metadata as Record<string, unknown>)?._internal,
|
|
540
|
+
);
|
|
603
541
|
|
|
604
|
-
if (
|
|
542
|
+
if (allTasks.length === 0) {
|
|
605
543
|
return {
|
|
606
544
|
success: true,
|
|
607
|
-
content: "No tasks found
|
|
545
|
+
content: "No tasks found",
|
|
608
546
|
};
|
|
609
547
|
}
|
|
610
548
|
|
|
611
549
|
// Sort by ID numerically
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
550
|
+
allTasks.sort((a, b) => parseInt(a.id, 10) - parseInt(b.id, 10));
|
|
551
|
+
|
|
552
|
+
// Filter resolved blockers from blockedBy
|
|
553
|
+
const completedIds = new Set(
|
|
554
|
+
allTasks.filter((t) => t.status === "completed").map((t) => t.id),
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
const content = allTasks
|
|
558
|
+
.map((t) => {
|
|
559
|
+
const blockedBy = t.blockedBy.filter((id) => !completedIds.has(id));
|
|
560
|
+
const owner = t.owner ? ` (${t.owner})` : "";
|
|
561
|
+
const blocked =
|
|
562
|
+
blockedBy.length > 0
|
|
563
|
+
? ` [blocked by ${blockedBy.map((id) => `#${id}`).join(", ")}]`
|
|
564
|
+
: "";
|
|
565
|
+
return `#${t.id} [${t.status}] ${t.subject}${owner}${blocked}`;
|
|
566
|
+
})
|
|
616
567
|
.join("\n");
|
|
617
568
|
|
|
618
569
|
return {
|
package/src/tools/types.ts
CHANGED
|
@@ -113,4 +113,6 @@ export interface ToolContext {
|
|
|
113
113
|
originalWorkdir?: string;
|
|
114
114
|
/** Merged environment variables (process.env + agent env) for child processes */
|
|
115
115
|
env?: Record<string, string>;
|
|
116
|
+
/** Workflow manager instance for workflow orchestration */
|
|
117
|
+
workflowManager?: import("../managers/workflowManager.js").WorkflowManager;
|
|
116
118
|
}
|
|
@@ -96,9 +96,6 @@ function isPermittedRedirect(
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const GITHUB_URL_ERROR =
|
|
100
|
-
"For GitHub URLs, please use the 'gh' CLI via the Bash tool instead (e.g., 'gh pr view', 'gh issue view', 'gh api').";
|
|
101
|
-
|
|
102
99
|
// --- Tool ---
|
|
103
100
|
|
|
104
101
|
export const webFetchTool: ToolPlugin = {
|
|
@@ -175,15 +172,6 @@ Usage notes:
|
|
|
175
172
|
};
|
|
176
173
|
}
|
|
177
174
|
|
|
178
|
-
// Check for GitHub URLs
|
|
179
|
-
if (url.includes("github.com")) {
|
|
180
|
-
return {
|
|
181
|
-
success: false,
|
|
182
|
-
content: "",
|
|
183
|
-
error: GITHUB_URL_ERROR,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
175
|
try {
|
|
188
176
|
const cached = cache.get(url);
|
|
189
177
|
if (cached) {
|