agent-tasks 1.6.0 → 1.6.1

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.
Files changed (91) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +181 -188
  3. package/package.json +84 -84
  4. package/dist/context.d.ts +0 -21
  5. package/dist/context.d.ts.map +0 -1
  6. package/dist/context.js +0 -48
  7. package/dist/context.js.map +0 -1
  8. package/dist/db.d.ts +0 -10
  9. package/dist/db.d.ts.map +0 -1
  10. package/dist/db.js +0 -112
  11. package/dist/db.js.map +0 -1
  12. package/dist/domain/agent-bridge.d.ts +0 -13
  13. package/dist/domain/agent-bridge.d.ts.map +0 -1
  14. package/dist/domain/agent-bridge.js +0 -99
  15. package/dist/domain/agent-bridge.js.map +0 -1
  16. package/dist/domain/approvals.d.ts +0 -19
  17. package/dist/domain/approvals.d.ts.map +0 -1
  18. package/dist/domain/approvals.js +0 -99
  19. package/dist/domain/approvals.js.map +0 -1
  20. package/dist/domain/cleanup.d.ts +0 -28
  21. package/dist/domain/cleanup.d.ts.map +0 -1
  22. package/dist/domain/cleanup.js +0 -68
  23. package/dist/domain/cleanup.js.map +0 -1
  24. package/dist/domain/collaborators.d.ts +0 -15
  25. package/dist/domain/collaborators.d.ts.map +0 -1
  26. package/dist/domain/collaborators.js +0 -72
  27. package/dist/domain/collaborators.js.map +0 -1
  28. package/dist/domain/comments.d.ts +0 -14
  29. package/dist/domain/comments.d.ts.map +0 -1
  30. package/dist/domain/comments.js +0 -66
  31. package/dist/domain/comments.js.map +0 -1
  32. package/dist/domain/events.d.ts +0 -10
  33. package/dist/domain/events.d.ts.map +0 -1
  34. package/dist/domain/events.js +0 -61
  35. package/dist/domain/events.js.map +0 -1
  36. package/dist/domain/rules.d.ts +0 -2
  37. package/dist/domain/rules.d.ts.map +0 -1
  38. package/dist/domain/rules.js +0 -67
  39. package/dist/domain/rules.js.map +0 -1
  40. package/dist/domain/tasks.d.ts +0 -66
  41. package/dist/domain/tasks.d.ts.map +0 -1
  42. package/dist/domain/tasks.js +0 -655
  43. package/dist/domain/tasks.js.map +0 -1
  44. package/dist/domain/validate.d.ts +0 -16
  45. package/dist/domain/validate.d.ts.map +0 -1
  46. package/dist/domain/validate.js +0 -32
  47. package/dist/domain/validate.js.map +0 -1
  48. package/dist/event-bus.d.ts +0 -10
  49. package/dist/event-bus.d.ts.map +0 -1
  50. package/dist/event-bus.js +0 -38
  51. package/dist/event-bus.js.map +0 -1
  52. package/dist/index.d.ts +0 -3
  53. package/dist/index.d.ts.map +0 -1
  54. package/dist/index.js +0 -132
  55. package/dist/index.js.map +0 -1
  56. package/dist/server.d.ts +0 -10
  57. package/dist/server.d.ts.map +0 -1
  58. package/dist/server.js +0 -95
  59. package/dist/server.js.map +0 -1
  60. package/dist/session.d.ts +0 -7
  61. package/dist/session.d.ts.map +0 -1
  62. package/dist/session.js +0 -11
  63. package/dist/session.js.map +0 -1
  64. package/dist/storage/database.d.ts +0 -15
  65. package/dist/storage/database.d.ts.map +0 -1
  66. package/dist/storage/database.js +0 -224
  67. package/dist/storage/database.js.map +0 -1
  68. package/dist/tasks.d.ts +0 -32
  69. package/dist/tasks.d.ts.map +0 -1
  70. package/dist/tasks.js +0 -410
  71. package/dist/tasks.js.map +0 -1
  72. package/dist/transport/mcp.d.ts +0 -6
  73. package/dist/transport/mcp.d.ts.map +0 -1
  74. package/dist/transport/mcp.js +0 -731
  75. package/dist/transport/mcp.js.map +0 -1
  76. package/dist/transport/rest.d.ts +0 -4
  77. package/dist/transport/rest.d.ts.map +0 -1
  78. package/dist/transport/rest.js +0 -534
  79. package/dist/transport/rest.js.map +0 -1
  80. package/dist/transport/ws.d.ts +0 -10
  81. package/dist/transport/ws.d.ts.map +0 -1
  82. package/dist/transport/ws.js +0 -191
  83. package/dist/transport/ws.js.map +0 -1
  84. package/dist/types.d.ts +0 -147
  85. package/dist/types.d.ts.map +0 -1
  86. package/dist/types.js +0 -35
  87. package/dist/types.js.map +0 -1
  88. package/dist/ui/app.js +0 -1973
  89. package/dist/ui/index.html +0 -172
  90. package/dist/ui/morphdom.min.js +0 -1
  91. package/dist/ui/styles.css +0 -2435
@@ -1,731 +0,0 @@
1
- // =============================================================================
2
- // agent-tasks — MCP transport
3
- //
4
- // Maps MCP tool calls to the TaskService. Thin adapter — validation lives
5
- // in the domain layer, not here.
6
- // =============================================================================
7
- import { writeFileSync, mkdirSync } from 'fs';
8
- import { join } from 'path';
9
- import { homedir } from 'os';
10
- import { ValidationError } from '../types.js';
11
- import { generateRules } from '../domain/rules.js';
12
- // ---------------------------------------------------------------------------
13
- // Tool definitions
14
- // ---------------------------------------------------------------------------
15
- export const tools = [
16
- {
17
- name: 'task_create',
18
- description: 'Create a pipeline task with optional stage, priority, and project.',
19
- inputSchema: {
20
- type: 'object',
21
- properties: {
22
- title: { type: 'string', description: 'Task title (max 500 chars)' },
23
- description: { type: 'string', description: 'Detailed instructions (max 50K chars)' },
24
- assign_to: { type: 'string', description: 'Agent name to assign to' },
25
- stage: { type: 'string', description: 'Pipeline stage (default: backlog)' },
26
- priority: {
27
- type: 'number',
28
- description: 'Priority (higher = more important, default: 0)',
29
- },
30
- project: { type: 'string', description: 'Project name for grouping' },
31
- tags: { type: 'array', items: { type: 'string' }, description: 'Tags for categorization' },
32
- parent_id: { type: 'number', description: 'Parent task ID (creates a subtask)' },
33
- },
34
- required: ['title'],
35
- },
36
- },
37
- {
38
- name: 'task_list',
39
- description: 'List tasks with optional filters and pagination.',
40
- inputSchema: {
41
- type: 'object',
42
- properties: {
43
- status: {
44
- type: 'string',
45
- enum: ['pending', 'in_progress', 'completed', 'failed', 'cancelled'],
46
- description: 'Filter by status',
47
- },
48
- assigned_to: { type: 'string', description: 'Filter by assigned agent name' },
49
- stage: { type: 'string', description: 'Filter by pipeline stage' },
50
- project: { type: 'string', description: 'Filter by project' },
51
- collaborator: { type: 'string', description: 'Filter tasks where agent is a collaborator' },
52
- root_only: { type: 'boolean', description: 'Only show top-level tasks (no subtasks)' },
53
- parent_id: { type: 'number', description: 'Filter subtasks of a specific parent' },
54
- limit: { type: 'number', description: 'Max results (default/max: 500)' },
55
- offset: { type: 'number', description: 'Skip first N results (for pagination)' },
56
- },
57
- },
58
- },
59
- {
60
- name: 'task_claim',
61
- description: 'Claim a pending task. Assigns it and advances from backlog to the next stage.',
62
- inputSchema: {
63
- type: 'object',
64
- properties: {
65
- task_id: { type: 'number', description: 'Task ID to claim' },
66
- claimer: {
67
- type: 'string',
68
- description: 'Agent name claiming (uses session name if omitted)',
69
- },
70
- },
71
- required: ['task_id'],
72
- },
73
- },
74
- {
75
- name: 'task_complete',
76
- description: 'Mark a task as completed with a result.',
77
- inputSchema: {
78
- type: 'object',
79
- properties: {
80
- task_id: { type: 'number', description: 'Task ID' },
81
- result: { type: 'string', description: 'Result or output' },
82
- },
83
- required: ['task_id', 'result'],
84
- },
85
- },
86
- {
87
- name: 'task_fail',
88
- description: 'Mark a task as failed with an error message.',
89
- inputSchema: {
90
- type: 'object',
91
- properties: {
92
- task_id: { type: 'number', description: 'Task ID' },
93
- result: { type: 'string', description: 'Error description' },
94
- },
95
- required: ['task_id', 'result'],
96
- },
97
- },
98
- {
99
- name: 'task_cancel',
100
- description: 'Cancel a task — moves it to the cancelled stage.',
101
- inputSchema: {
102
- type: 'object',
103
- properties: {
104
- task_id: { type: 'number', description: 'Task ID' },
105
- reason: { type: 'string', description: 'Why the task was cancelled' },
106
- },
107
- required: ['task_id', 'reason'],
108
- },
109
- },
110
- {
111
- name: 'task_advance',
112
- description: 'Advance a task to the next pipeline stage (or a specific stage). Validates dependencies.',
113
- inputSchema: {
114
- type: 'object',
115
- properties: {
116
- task_id: { type: 'number', description: 'Task ID' },
117
- stage: { type: 'string', description: 'Target stage (omit to advance to next stage)' },
118
- },
119
- required: ['task_id'],
120
- },
121
- },
122
- {
123
- name: 'task_regress',
124
- description: 'Send a task back to an earlier stage (e.g. review rejection).',
125
- inputSchema: {
126
- type: 'object',
127
- properties: {
128
- task_id: { type: 'number', description: 'Task ID' },
129
- stage: { type: 'string', description: 'Target stage to regress to' },
130
- reason: {
131
- type: 'string',
132
- description: 'Reason for regression (stored as artifact)',
133
- },
134
- },
135
- required: ['task_id', 'stage'],
136
- },
137
- },
138
- {
139
- name: 'task_update',
140
- description: 'Update task metadata (title, description, priority, tags, assignment).',
141
- inputSchema: {
142
- type: 'object',
143
- properties: {
144
- task_id: { type: 'number', description: 'Task ID' },
145
- title: { type: 'string', description: 'New title' },
146
- description: { type: 'string', description: 'New description' },
147
- priority: { type: 'number', description: 'New priority' },
148
- project: { type: 'string', description: 'New project' },
149
- tags: { type: 'array', items: { type: 'string' }, description: 'New tags' },
150
- assign_to: {
151
- type: 'string',
152
- description: 'New assignee (empty string to unassign)',
153
- },
154
- },
155
- required: ['task_id'],
156
- },
157
- },
158
- {
159
- name: 'task_next',
160
- description: 'Get the highest-priority unassigned task with all dependencies met. Returns null if none.',
161
- inputSchema: {
162
- type: 'object',
163
- properties: {
164
- project: { type: 'string', description: 'Filter by project' },
165
- stage: { type: 'string', description: 'Filter by stage' },
166
- },
167
- },
168
- },
169
- {
170
- name: 'task_add_dependency',
171
- description: 'Add a relationship between tasks. "blocks" prevents advancement until dependency is done. "related" and "duplicate" are informational only.',
172
- inputSchema: {
173
- type: 'object',
174
- properties: {
175
- task_id: { type: 'number', description: 'Task that depends on another' },
176
- depends_on: {
177
- type: 'number',
178
- description: 'Task that must complete first (for blocks) or related task',
179
- },
180
- relationship: {
181
- type: 'string',
182
- enum: ['blocks', 'related', 'duplicate'],
183
- description: 'Relationship type (default: blocks)',
184
- },
185
- },
186
- required: ['task_id', 'depends_on'],
187
- },
188
- },
189
- {
190
- name: 'task_remove_dependency',
191
- description: 'Remove a dependency between tasks.',
192
- inputSchema: {
193
- type: 'object',
194
- properties: {
195
- task_id: { type: 'number', description: 'Task ID' },
196
- depends_on: { type: 'number', description: 'Dependency to remove' },
197
- },
198
- required: ['task_id', 'depends_on'],
199
- },
200
- },
201
- {
202
- name: 'task_add_artifact',
203
- description: 'Attach a document/artifact to a task (spec, plan, test results, review notes, etc.).',
204
- inputSchema: {
205
- type: 'object',
206
- properties: {
207
- task_id: { type: 'number', description: 'Task ID' },
208
- name: {
209
- type: 'string',
210
- description: 'Artifact name (e.g. "spec", "test-results", "review-notes")',
211
- },
212
- content: {
213
- type: 'string',
214
- description: 'Artifact content (text, markdown, JSON, max 100K)',
215
- },
216
- stage: {
217
- type: 'string',
218
- description: 'Stage to attach to (defaults to task current stage)',
219
- },
220
- },
221
- required: ['task_id', 'name', 'content'],
222
- },
223
- },
224
- {
225
- name: 'task_get_artifacts',
226
- description: 'Get artifacts attached to a task.',
227
- inputSchema: {
228
- type: 'object',
229
- properties: {
230
- task_id: { type: 'number', description: 'Task ID' },
231
- stage: { type: 'string', description: 'Filter by stage' },
232
- },
233
- required: ['task_id'],
234
- },
235
- },
236
- {
237
- name: 'task_pipeline_config',
238
- description: 'Get or set pipeline stages for a project. Call without stages to get current config.',
239
- inputSchema: {
240
- type: 'object',
241
- properties: {
242
- project: {
243
- type: 'string',
244
- description: 'Project name (omit for default pipeline)',
245
- },
246
- stages: {
247
- type: 'array',
248
- items: { type: 'string' },
249
- description: 'Stage names in order (set mode)',
250
- },
251
- },
252
- },
253
- },
254
- {
255
- name: 'task_set_session',
256
- description: 'Set the session identity for this connection (used to track who creates/claims tasks).',
257
- inputSchema: {
258
- type: 'object',
259
- properties: {
260
- id: { type: 'string', description: 'Session ID' },
261
- name: { type: 'string', description: 'Session name' },
262
- },
263
- required: ['id', 'name'],
264
- },
265
- },
266
- {
267
- name: 'task_delete',
268
- description: 'Delete a task and all its artifacts and dependencies (cascading delete).',
269
- inputSchema: {
270
- type: 'object',
271
- properties: {
272
- task_id: { type: 'number', description: 'Task ID to delete' },
273
- },
274
- required: ['task_id'],
275
- },
276
- },
277
- {
278
- name: 'task_comment',
279
- description: 'Add a comment to a task for async discussion between agents.',
280
- inputSchema: {
281
- type: 'object',
282
- properties: {
283
- task_id: { type: 'number', description: 'Task ID' },
284
- content: { type: 'string', description: 'Comment text' },
285
- parent_comment_id: { type: 'number', description: 'Reply to this comment (threading)' },
286
- },
287
- required: ['task_id', 'content'],
288
- },
289
- },
290
- {
291
- name: 'task_get_comments',
292
- description: 'Get comments on a task.',
293
- inputSchema: {
294
- type: 'object',
295
- properties: {
296
- task_id: { type: 'number', description: 'Task ID' },
297
- limit: { type: 'number', description: 'Max comments (default: 100)' },
298
- },
299
- required: ['task_id'],
300
- },
301
- },
302
- {
303
- name: 'task_add_collaborator',
304
- description: 'Add an agent as collaborator on a task (roles: collaborator, reviewer, watcher).',
305
- inputSchema: {
306
- type: 'object',
307
- properties: {
308
- task_id: { type: 'number', description: 'Task ID' },
309
- agent_id: { type: 'string', description: 'Agent name or ID' },
310
- role: {
311
- type: 'string',
312
- enum: ['collaborator', 'reviewer', 'watcher'],
313
- description: 'Role (default: collaborator)',
314
- },
315
- },
316
- required: ['task_id', 'agent_id'],
317
- },
318
- },
319
- {
320
- name: 'task_remove_collaborator',
321
- description: 'Remove a collaborator from a task.',
322
- inputSchema: {
323
- type: 'object',
324
- properties: {
325
- task_id: { type: 'number', description: 'Task ID' },
326
- agent_id: { type: 'string', description: 'Agent name or ID' },
327
- },
328
- required: ['task_id', 'agent_id'],
329
- },
330
- },
331
- {
332
- name: 'task_search',
333
- description: 'Full-text search across task titles and descriptions.',
334
- inputSchema: {
335
- type: 'object',
336
- properties: {
337
- query: { type: 'string', description: 'Search query' },
338
- project: { type: 'string', description: 'Filter by project' },
339
- limit: { type: 'number', description: 'Max results (default: 50)' },
340
- },
341
- required: ['query'],
342
- },
343
- },
344
- {
345
- name: 'task_get_subtasks',
346
- description: 'Get subtasks of a parent task.',
347
- inputSchema: {
348
- type: 'object',
349
- properties: {
350
- task_id: { type: 'number', description: 'Parent task ID' },
351
- },
352
- required: ['task_id'],
353
- },
354
- },
355
- {
356
- name: 'task_request_approval',
357
- description: 'Request approval for a task at a specific stage.',
358
- inputSchema: {
359
- type: 'object',
360
- properties: {
361
- task_id: { type: 'number', description: 'Task ID' },
362
- stage: { type: 'string', description: 'Stage requiring approval (defaults to current)' },
363
- reviewer: { type: 'string', description: 'Specific reviewer to assign' },
364
- },
365
- required: ['task_id'],
366
- },
367
- },
368
- {
369
- name: 'task_approve',
370
- description: 'Approve a pending approval request.',
371
- inputSchema: {
372
- type: 'object',
373
- properties: {
374
- approval_id: { type: 'number', description: 'Approval ID' },
375
- comment: { type: 'string', description: 'Approval comment' },
376
- },
377
- required: ['approval_id'],
378
- },
379
- },
380
- {
381
- name: 'task_reject',
382
- description: 'Reject a pending approval and optionally regress the task.',
383
- inputSchema: {
384
- type: 'object',
385
- properties: {
386
- approval_id: { type: 'number', description: 'Approval ID' },
387
- comment: { type: 'string', description: 'Rejection reason (required)' },
388
- regress_to: { type: 'string', description: 'Stage to regress task to' },
389
- },
390
- required: ['approval_id', 'comment'],
391
- },
392
- },
393
- {
394
- name: 'task_pending_approvals',
395
- description: 'List pending approval requests, optionally filtered by reviewer.',
396
- inputSchema: {
397
- type: 'object',
398
- properties: {
399
- reviewer: { type: 'string', description: 'Filter by reviewer' },
400
- },
401
- },
402
- },
403
- {
404
- name: 'task_review_cycle',
405
- description: 'Review a task: approve (advance to next stage) or reject (regress with reason). Convenience wrapper for the maker-checker pattern.',
406
- inputSchema: {
407
- type: 'object',
408
- properties: {
409
- task_id: { type: 'number', description: 'Task ID to review' },
410
- action: {
411
- type: 'string',
412
- enum: ['approve', 'reject'],
413
- description: 'Approve or reject',
414
- },
415
- reason: { type: 'string', description: 'Rejection reason (required for reject)' },
416
- regress_to: {
417
- type: 'string',
418
- description: 'Stage to regress to on rejection (default: implement)',
419
- },
420
- },
421
- required: ['task_id', 'action'],
422
- },
423
- },
424
- {
425
- name: 'task_expand',
426
- description: 'Break a task into subtasks. Creates subtasks with parent_id pointing to the given task, inheriting project and priority.',
427
- inputSchema: {
428
- type: 'object',
429
- properties: {
430
- task_id: { type: 'number', description: 'Parent task ID to expand' },
431
- subtasks: {
432
- type: 'array',
433
- items: {
434
- type: 'object',
435
- properties: {
436
- title: { type: 'string', description: 'Subtask title' },
437
- description: { type: 'string', description: 'Subtask description' },
438
- priority: {
439
- type: 'number',
440
- description: 'Priority override (inherits from parent if omitted)',
441
- },
442
- },
443
- required: ['title'],
444
- },
445
- description: 'Array of subtasks to create',
446
- },
447
- },
448
- required: ['task_id', 'subtasks'],
449
- },
450
- },
451
- {
452
- name: 'task_cleanup',
453
- description: 'Run data cleanup manually — purges completed/cancelled tasks and stale data older than the retention period.',
454
- inputSchema: {
455
- type: 'object',
456
- properties: {},
457
- },
458
- },
459
- {
460
- name: 'task_generate_rules',
461
- description: 'Generate IDE-specific rule files that instruct agents to use the pipeline. Supports Cursor (.mdc) and Claude Code (CLAUDE.md) formats.',
462
- inputSchema: {
463
- type: 'object',
464
- properties: {
465
- format: {
466
- type: 'string',
467
- enum: ['mdc', 'claude_md'],
468
- description: 'Output format: mdc (Cursor) or claude_md (Claude Code)',
469
- },
470
- project: { type: 'string', description: 'Project name for project-specific rules' },
471
- },
472
- required: ['format'],
473
- },
474
- },
475
- ];
476
- // ---------------------------------------------------------------------------
477
- // Input validation helpers
478
- // ---------------------------------------------------------------------------
479
- function requireString(args, key) {
480
- const val = args[key];
481
- if (typeof val !== 'string' || !val.trim()) {
482
- throw new ValidationError(`"${key}" must be a non-empty string.`);
483
- }
484
- return val;
485
- }
486
- function optString(args, key) {
487
- const val = args[key];
488
- if (val === undefined || val === null)
489
- return undefined;
490
- if (typeof val !== 'string')
491
- throw new ValidationError(`"${key}" must be a string.`);
492
- return val;
493
- }
494
- function requireNumber(args, key) {
495
- const val = args[key];
496
- if (typeof val !== 'number') {
497
- throw new ValidationError(`"${key}" is required and must be a number.`);
498
- }
499
- return val;
500
- }
501
- function optNumber(args, key) {
502
- const val = args[key];
503
- if (val === undefined || val === null)
504
- return undefined;
505
- if (typeof val !== 'number')
506
- throw new ValidationError(`"${key}" must be a number.`);
507
- return val;
508
- }
509
- function optBoolean(args, key) {
510
- const val = args[key];
511
- if (val === undefined || val === null)
512
- return undefined;
513
- if (typeof val !== 'boolean')
514
- throw new ValidationError(`"${key}" must be a boolean.`);
515
- return val;
516
- }
517
- function optStringArray(args, key) {
518
- const val = args[key];
519
- if (val === undefined || val === null)
520
- return undefined;
521
- if (!Array.isArray(val) || !val.every((v) => typeof v === 'string')) {
522
- throw new ValidationError(`"${key}" must be an array of strings.`);
523
- }
524
- return val;
525
- }
526
- export function createToolHandler(ctx) {
527
- let currentSession = null;
528
- function sessionName() {
529
- return currentSession?.name ?? 'system';
530
- }
531
- return function handleTool(name, args) {
532
- switch (name) {
533
- case 'task_set_session': {
534
- const id = requireString(args, 'id');
535
- const sName = requireString(args, 'name');
536
- currentSession = { id, name: sName };
537
- writeSessionFile(id, sName);
538
- return { success: true, id, name: sName };
539
- }
540
- case 'task_create': {
541
- return ctx.tasks.create({
542
- title: requireString(args, 'title'),
543
- description: optString(args, 'description'),
544
- assign_to: optString(args, 'assign_to'),
545
- stage: optString(args, 'stage'),
546
- priority: optNumber(args, 'priority'),
547
- project: optString(args, 'project'),
548
- tags: optStringArray(args, 'tags'),
549
- parent_id: optNumber(args, 'parent_id'),
550
- }, sessionName());
551
- }
552
- case 'task_list': {
553
- return ctx.tasks.list({
554
- status: optString(args, 'status'),
555
- assigned_to: optString(args, 'assigned_to'),
556
- stage: optString(args, 'stage'),
557
- project: optString(args, 'project'),
558
- parent_id: optNumber(args, 'parent_id'),
559
- root_only: optBoolean(args, 'root_only'),
560
- collaborator: optString(args, 'collaborator'),
561
- limit: optNumber(args, 'limit'),
562
- offset: optNumber(args, 'offset'),
563
- });
564
- }
565
- case 'task_claim': {
566
- const claimer = optString(args, 'claimer') ?? sessionName();
567
- return ctx.tasks.claim(requireNumber(args, 'task_id'), claimer);
568
- }
569
- case 'task_complete':
570
- return ctx.tasks.complete(requireNumber(args, 'task_id'), requireString(args, 'result'));
571
- case 'task_fail':
572
- return ctx.tasks.fail(requireNumber(args, 'task_id'), requireString(args, 'result'));
573
- case 'task_cancel':
574
- return ctx.tasks.cancel(requireNumber(args, 'task_id'), requireString(args, 'reason'));
575
- case 'task_advance':
576
- return ctx.tasks.advance(requireNumber(args, 'task_id'), optString(args, 'stage'));
577
- case 'task_regress':
578
- return ctx.tasks.regress(requireNumber(args, 'task_id'), requireString(args, 'stage'), optString(args, 'reason'));
579
- case 'task_update':
580
- return ctx.tasks.update(requireNumber(args, 'task_id'), {
581
- title: optString(args, 'title'),
582
- description: optString(args, 'description'),
583
- priority: optNumber(args, 'priority'),
584
- project: optString(args, 'project'),
585
- tags: optStringArray(args, 'tags'),
586
- assigned_to: optString(args, 'assign_to'),
587
- });
588
- case 'task_next': {
589
- return (ctx.tasks.next(optString(args, 'project'), optString(args, 'stage')) ?? {
590
- message: 'No available tasks.',
591
- });
592
- }
593
- case 'task_add_dependency': {
594
- const relationship = (optString(args, 'relationship') ?? 'blocks');
595
- ctx.tasks.addDependency(requireNumber(args, 'task_id'), requireNumber(args, 'depends_on'), relationship);
596
- return { success: true, task_id: args.task_id, depends_on: args.depends_on, relationship };
597
- }
598
- case 'task_remove_dependency': {
599
- ctx.tasks.removeDependency(requireNumber(args, 'task_id'), requireNumber(args, 'depends_on'));
600
- return { success: true };
601
- }
602
- case 'task_add_artifact': {
603
- return ctx.tasks.addArtifact(requireNumber(args, 'task_id'), requireString(args, 'name'), requireString(args, 'content'), sessionName(), optString(args, 'stage'));
604
- }
605
- case 'task_get_artifacts':
606
- return ctx.tasks.getArtifacts(requireNumber(args, 'task_id'), optString(args, 'stage'));
607
- case 'task_pipeline_config': {
608
- const stages = optStringArray(args, 'stages');
609
- if (stages) {
610
- return ctx.tasks.setPipelineConfig(optString(args, 'project') || 'default', stages);
611
- }
612
- return { stages: ctx.tasks.getPipelineStages(optString(args, 'project')) };
613
- }
614
- case 'task_delete': {
615
- ctx.tasks.delete(requireNumber(args, 'task_id'));
616
- return { success: true };
617
- }
618
- case 'task_comment': {
619
- return ctx.comments.add(requireNumber(args, 'task_id'), sessionName(), requireString(args, 'content'), optNumber(args, 'parent_comment_id'));
620
- }
621
- case 'task_get_comments':
622
- return ctx.comments.list(requireNumber(args, 'task_id'), optNumber(args, 'limit'));
623
- case 'task_add_collaborator': {
624
- return ctx.collaborators.add(requireNumber(args, 'task_id'), requireString(args, 'agent_id'), (optString(args, 'role') ?? 'collaborator'));
625
- }
626
- case 'task_remove_collaborator': {
627
- ctx.collaborators.remove(requireNumber(args, 'task_id'), requireString(args, 'agent_id'));
628
- return { success: true };
629
- }
630
- case 'task_search':
631
- return ctx.tasks.search(requireString(args, 'query'), {
632
- project: optString(args, 'project'),
633
- limit: optNumber(args, 'limit'),
634
- });
635
- case 'task_get_subtasks':
636
- return ctx.tasks.getSubtasks(requireNumber(args, 'task_id'));
637
- case 'task_request_approval': {
638
- const taskId = requireNumber(args, 'task_id');
639
- const task = ctx.tasks.getById(taskId);
640
- if (!task)
641
- throw new ValidationError(`Task ${taskId} not found.`);
642
- const stage = optString(args, 'stage') ?? task.stage;
643
- return ctx.approvals.request(taskId, stage, optString(args, 'reviewer'));
644
- }
645
- case 'task_approve':
646
- return ctx.approvals.approve(requireNumber(args, 'approval_id'), sessionName(), optString(args, 'comment'));
647
- case 'task_reject': {
648
- const approval = ctx.approvals.reject(requireNumber(args, 'approval_id'), sessionName(), requireString(args, 'comment'));
649
- const regressTo = optString(args, 'regress_to');
650
- if (regressTo) {
651
- ctx.tasks.regress(approval.task_id, regressTo, requireString(args, 'comment'));
652
- }
653
- return approval;
654
- }
655
- case 'task_pending_approvals':
656
- return ctx.approvals.getPending(optString(args, 'reviewer'));
657
- case 'task_review_cycle': {
658
- const taskId = requireNumber(args, 'task_id');
659
- const action = requireString(args, 'action');
660
- const task = ctx.tasks.getById(taskId);
661
- if (!task)
662
- throw new ValidationError(`Task ${taskId} not found.`);
663
- if (action === 'approve') {
664
- ctx.tasks.advance(taskId);
665
- return { success: true, action: 'approved', task: ctx.tasks.getById(taskId) };
666
- }
667
- else if (action === 'reject') {
668
- const reason = requireString(args, 'reason');
669
- const regressTo = optString(args, 'regress_to') ?? 'implement';
670
- ctx.tasks.regress(taskId, regressTo, reason);
671
- return { success: true, action: 'rejected', task: ctx.tasks.getById(taskId) };
672
- }
673
- else {
674
- throw new ValidationError(`Invalid action: ${action}. Use "approve" or "reject".`);
675
- }
676
- }
677
- case 'task_expand': {
678
- const parentId = requireNumber(args, 'task_id');
679
- const parent = ctx.tasks.getById(parentId);
680
- if (!parent)
681
- throw new ValidationError(`Task ${parentId} not found.`);
682
- const subtaskDefs = args.subtasks;
683
- if (!Array.isArray(subtaskDefs) || subtaskDefs.length === 0) {
684
- throw new ValidationError('"subtasks" must be a non-empty array.');
685
- }
686
- const created = [];
687
- for (const sub of subtaskDefs) {
688
- if (typeof sub !== 'object' ||
689
- sub === null ||
690
- typeof sub.title !== 'string') {
691
- throw new ValidationError('Each subtask must have a "title" string.');
692
- }
693
- const s = sub;
694
- created.push(ctx.tasks.create({
695
- title: s.title,
696
- description: s.description ?? undefined,
697
- priority: typeof s.priority === 'number' ? s.priority : parent.priority,
698
- project: parent.project ?? undefined,
699
- parent_id: parentId,
700
- }, sessionName()));
701
- }
702
- return created;
703
- }
704
- case 'task_cleanup':
705
- return ctx.cleanup.run();
706
- case 'task_generate_rules': {
707
- const format = requireString(args, 'format');
708
- if (format !== 'mdc' && format !== 'claude_md') {
709
- throw new ValidationError('Format must be "mdc" or "claude_md".');
710
- }
711
- const project = optString(args, 'project');
712
- const stages = ctx.tasks.getPipelineStages(project);
713
- return { rules: generateRules(format, stages, project) };
714
- }
715
- default:
716
- throw new ValidationError(`Unknown tool: ${name}`);
717
- }
718
- };
719
- }
720
- function writeSessionFile(id, name) {
721
- try {
722
- const claudeDir = join(homedir(), '.claude');
723
- mkdirSync(claudeDir, { recursive: true });
724
- const filePath = join(claudeDir, `hub-session.${id}.json`);
725
- writeFileSync(filePath, JSON.stringify({ pid: process.pid, name, id, timestamp: new Date().toISOString() }));
726
- }
727
- catch {
728
- /* non-critical */
729
- }
730
- }
731
- //# sourceMappingURL=mcp.js.map