backlog-mcp 0.1.0 → 0.2.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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # backlog-mcp
2
2
 
3
- Minimal task backlog as an MCP server. Records state, doesn't enforce workflow.
3
+ Minimal task backlog MCP server for Claude and AI agents.
4
+
5
+ > **Quick start**: Tell your LLM: `Add backlog-mcp to .mcp.json and use it to track tasks`
4
6
 
5
7
  ## Task Schema
6
8
 
@@ -17,14 +19,18 @@ Minimal task backlog as an MCP server. Records state, doesn't enforce workflow.
17
19
  }
18
20
  ```
19
21
 
20
- ## MCP Tools
22
+ ## MCP Tool
23
+
24
+ Single unified tool with action parameter:
21
25
 
22
- | Tool | Description |
23
- |------|-------------|
24
- | `backlog_list` | List tasks. Filter by status. Use `summary=true` for counts. |
25
- | `backlog_get` | Get task by ID |
26
- | `backlog_create` | Create task |
27
- | `backlog_update` | Update any field (title, description, status, blocked_reason, evidence) |
26
+ ```
27
+ backlog action="list" # List all tasks
28
+ backlog action="list" summary=true # Get counts by status
29
+ backlog action="list" status=["open"] # Filter by status
30
+ backlog action="get" id="TASK-0001" # Get task details
31
+ backlog action="create" title="Fix bug" # Create task
32
+ backlog action="update" id="TASK-0001" set_status="done" # Update task
33
+ ```
28
34
 
29
35
  ## Installation
30
36
 
@@ -50,22 +56,12 @@ npm install && npm run build
50
56
  npm start
51
57
  ```
52
58
 
53
- Claude Desktop config:
54
-
55
- ```json
56
- {
57
- "mcpServers": {
58
- "backlog": {
59
- "command": "node",
60
- "args": ["/path/to/backlog-mcp/dist/server.js"]
61
- }
62
- }
63
- }
64
- ```
65
-
66
59
  ## Storage
67
60
 
68
- Single file: `data/backlog.json` (atomic writes via temp + rename)
61
+ - Default: `data/backlog.json` (local to project)
62
+ - Global: Set `BACKLOG_DATA_DIR=~/.backlog` for cross-project persistence
63
+ - Completed/cancelled tasks auto-archive to `archive.json`
64
+ - Atomic writes via temp + rename
69
65
 
70
66
  ## License
71
67
 
package/dist/server.js CHANGED
@@ -17,65 +17,72 @@ const storageOptions = {
17
17
  // ============================================================================
18
18
  // Tools
19
19
  // ============================================================================
20
- server.registerTool('backlog_list', {
21
- description: 'List tasks, optionally filtered by status. Use summary=true for counts.',
20
+ const ACTIONS = ['list', 'get', 'create', 'update'];
21
+ server.registerTool('backlog', {
22
+ description: 'Manage tasks. Actions: list, get, create, update',
22
23
  inputSchema: {
23
- status: z.array(z.enum(STATUSES)).optional().describe('Filter by status'),
24
- summary: z.boolean().optional().describe('Return counts instead of list'),
24
+ action: z.enum(ACTIONS).describe('Action to perform'),
25
+ // list options
26
+ status: z.array(z.enum(STATUSES)).optional().describe('Filter by status (list)'),
27
+ summary: z.boolean().optional().describe('Return counts instead of list (list)'),
28
+ // get/update options
29
+ id: z.string().optional().describe('Task ID (get, update)'),
30
+ // create/update options
31
+ title: z.string().optional().describe('Task title (create, update)'),
32
+ description: z.string().optional().describe('Task description (create, update)'),
33
+ // update-only options
34
+ set_status: z.enum(STATUSES).optional().describe('New status (update)'),
35
+ blocked_reason: z.string().optional().describe('Reason for blocked status (update)'),
36
+ evidence: z.array(z.string()).optional().describe('Evidence of completion (update)'),
25
37
  },
26
- }, async ({ status, summary }) => {
27
- const tasks = listTasks(status ? { status } : undefined, storageOptions);
28
- if (summary) {
29
- const counts = getTaskCounts(storageOptions);
30
- return { content: [{ type: 'text', text: JSON.stringify(counts, null, 2) }] };
38
+ }, async ({ action, status, summary, id, title, description, set_status, blocked_reason, evidence }) => {
39
+ switch (action) {
40
+ case 'list': {
41
+ const tasks = listTasks(status ? { status } : undefined, storageOptions);
42
+ if (summary) {
43
+ const counts = getTaskCounts(storageOptions);
44
+ return { content: [{ type: 'text', text: JSON.stringify(counts, null, 2) }] };
45
+ }
46
+ const list = tasks.map((t) => ({ id: t.id, title: t.title, status: t.status }));
47
+ return { content: [{ type: 'text', text: JSON.stringify(list, null, 2) }] };
48
+ }
49
+ case 'get': {
50
+ if (!id) {
51
+ return { content: [{ type: 'text', text: 'Missing required: id' }], isError: true };
52
+ }
53
+ const task = getTask(id, storageOptions);
54
+ if (!task) {
55
+ return { content: [{ type: 'text', text: `Not found: ${id}` }], isError: true };
56
+ }
57
+ return { content: [{ type: 'text', text: JSON.stringify(task, null, 2) }] };
58
+ }
59
+ case 'create': {
60
+ if (!title) {
61
+ return { content: [{ type: 'text', text: 'Missing required: title' }], isError: true };
62
+ }
63
+ const backlog = loadBacklog(storageOptions);
64
+ const task = createTask({ title, description }, backlog.tasks);
65
+ addTask(task, storageOptions);
66
+ return { content: [{ type: 'text', text: `Created ${task.id}` }] };
67
+ }
68
+ case 'update': {
69
+ if (!id) {
70
+ return { content: [{ type: 'text', text: 'Missing required: id' }], isError: true };
71
+ }
72
+ const task = getTask(id, storageOptions);
73
+ if (!task) {
74
+ return { content: [{ type: 'text', text: `Not found: ${id}` }], isError: true };
75
+ }
76
+ const updates = { title, description, status: set_status, blocked_reason, evidence };
77
+ const updated = {
78
+ ...task,
79
+ ...Object.fromEntries(Object.entries(updates).filter(([_, v]) => v !== undefined)),
80
+ updated_at: new Date().toISOString(),
81
+ };
82
+ saveTask(updated, storageOptions);
83
+ return { content: [{ type: 'text', text: `Updated ${id}` }] };
84
+ }
31
85
  }
32
- const list = tasks.map((t) => ({ id: t.id, title: t.title, status: t.status }));
33
- return { content: [{ type: 'text', text: JSON.stringify(list, null, 2) }] };
34
- });
35
- server.registerTool('backlog_get', {
36
- description: 'Get a task by ID',
37
- inputSchema: { id: z.string().describe('Task ID') },
38
- }, async ({ id }) => {
39
- const task = getTask(id, storageOptions);
40
- if (!task) {
41
- return { content: [{ type: 'text', text: `Not found: ${id}` }], isError: true };
42
- }
43
- return { content: [{ type: 'text', text: JSON.stringify(task, null, 2) }] };
44
- });
45
- server.registerTool('backlog_create', {
46
- description: 'Create a new task',
47
- inputSchema: {
48
- title: z.string().describe('Task title'),
49
- description: z.string().optional().describe('Task description'),
50
- },
51
- }, async ({ title, description }) => {
52
- const backlog = loadBacklog(storageOptions);
53
- const task = createTask({ title, description }, backlog.tasks);
54
- addTask(task, storageOptions);
55
- return { content: [{ type: 'text', text: `Created ${task.id}` }] };
56
- });
57
- server.registerTool('backlog_update', {
58
- description: 'Update a task (any field)',
59
- inputSchema: {
60
- id: z.string().describe('Task ID'),
61
- title: z.string().optional(),
62
- description: z.string().optional(),
63
- status: z.enum(STATUSES).optional(),
64
- blocked_reason: z.string().optional(),
65
- evidence: z.array(z.string()).optional(),
66
- },
67
- }, async ({ id, ...updates }) => {
68
- const task = getTask(id, storageOptions);
69
- if (!task) {
70
- return { content: [{ type: 'text', text: `Not found: ${id}` }], isError: true };
71
- }
72
- const updated = {
73
- ...task,
74
- ...Object.fromEntries(Object.entries(updates).filter(([_, v]) => v !== undefined)),
75
- updated_at: new Date().toISOString(),
76
- };
77
- saveTask(updated, storageOptions);
78
- return { content: [{ type: 'text', text: `Updated ${id}` }] };
79
86
  });
80
87
  // ============================================================================
81
88
  // Main
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAuB,MAAM,cAAc,CAAC;AAEtH,+EAA+E;AAC/E,SAAS;AACT,+EAA+E;AAE/E,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,cAAc,GAAmB;IACrC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,MAAM;CAChD,CAAC;AAEF,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAE7D,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;IACE,WAAW,EAAE,kDAAkD;IAC/D,WAAW,EAAE;QACX,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACrD,eAAe;QACf,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAChF,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;QAChF,qBAAqB;QACrB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC3D,wBAAwB;QACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QACpE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QAChF,sBAAsB;QACtB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACvE,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QACpF,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KACrF;CACF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,EAAE,EAAE;IAClG,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YACzE,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,MAAM,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;gBAC7C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACzF,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAChF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACvF,CAAC;QAED,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC/F,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3F,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACvF,CAAC;QAED,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAClG,CAAC;YACD,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;YAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,WAAW,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAED,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC/F,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3F,CAAC;YACD,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC;YACrF,MAAM,OAAO,GAAS;gBACpB,GAAG,IAAI;gBACP,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;gBAClF,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,CAAC;YACF,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAClC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QACzE,CAAC;IACH,CAAC;AACH,CAAC,CACF,CAAC;AAEF,+EAA+E;AAC/E,OAAO;AACP,+EAA+E;AAE/E,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,22 @@
1
1
  {
2
2
  "name": "backlog-mcp",
3
- "version": "0.1.0",
4
- "description": "Minimal, boring, correct core for persistent backlog state",
3
+ "version": "0.2.0",
4
+ "description": "Minimal task backlog MCP server for Claude and AI agents",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "claude",
9
+ "anthropic",
10
+ "ai",
11
+ "llm",
12
+ "backlog",
13
+ "task-management",
14
+ "claude-code"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/gkoreli/backlog-mcp.git"
19
+ },
5
20
  "type": "module",
6
21
  "main": "dist/index.js",
7
22
  "types": "dist/index.d.ts",
@@ -1,32 +0,0 @@
1
- import type { Task, Status, Blocked, Dod, Evidence, ValidationError } from './schema.js';
2
- export declare const TERMINAL_STATUSES: readonly Status[];
3
- export interface TransitionToBlocked {
4
- to: 'blocked';
5
- blocked: Blocked;
6
- }
7
- export interface TransitionToVerifying {
8
- to: 'verifying';
9
- dod: Dod;
10
- evidence: Evidence;
11
- }
12
- export interface TransitionToDone {
13
- to: 'done';
14
- }
15
- export interface TransitionToInProgress {
16
- to: 'in_progress';
17
- }
18
- export interface TransitionToCancelled {
19
- to: 'cancelled';
20
- }
21
- export type TransitionInput = TransitionToBlocked | TransitionToVerifying | TransitionToDone | TransitionToInProgress | TransitionToCancelled;
22
- export type TransitionResult = {
23
- ok: true;
24
- task: Task;
25
- } | {
26
- ok: false;
27
- errors: ValidationError[];
28
- };
29
- export declare function canTransition(from: Status, to: Status): boolean;
30
- export declare function getAllowedTransitions(from: Status): readonly Status[];
31
- export declare function isTerminal(status: Status): boolean;
32
- export declare function transition(task: Task, input: TransitionInput): TransitionResult;
@@ -1,174 +0,0 @@
1
- // ============================================================================
2
- // Constants
3
- // ============================================================================
4
- export const TERMINAL_STATUSES = ['done', 'cancelled'];
5
- /**
6
- * State machine transitions:
7
- *
8
- * open ──────► in_progress ──────► verifying ──────► done
9
- * │ │ │
10
- * │ │ ├─► in_progress (rejected)
11
- * │ │ │
12
- * │ │ └─► cancelled
13
- * │ │
14
- * │ ├────────────────► blocked
15
- * │ │ │
16
- * │ │ ├─► in_progress
17
- * │ │ │
18
- * │ │ └─► cancelled
19
- * │ │
20
- * │ └────────────────► cancelled
21
- * │
22
- * └────────────────────────────────► cancelled
23
- */
24
- const ALLOWED_TRANSITIONS = {
25
- open: ['in_progress', 'cancelled'],
26
- in_progress: ['blocked', 'verifying', 'cancelled'],
27
- blocked: ['in_progress', 'cancelled'],
28
- verifying: ['done', 'in_progress', 'cancelled'],
29
- done: [],
30
- cancelled: [],
31
- };
32
- // ============================================================================
33
- // Helpers
34
- // ============================================================================
35
- function isNonEmptyString(value) {
36
- return typeof value === 'string' && value.trim().length > 0;
37
- }
38
- function isNonEmptyStringArray(value) {
39
- return Array.isArray(value) && value.length > 0 && value.every(isNonEmptyString);
40
- }
41
- // ============================================================================
42
- // Query Functions
43
- // ============================================================================
44
- export function canTransition(from, to) {
45
- return ALLOWED_TRANSITIONS[from].includes(to);
46
- }
47
- export function getAllowedTransitions(from) {
48
- return ALLOWED_TRANSITIONS[from];
49
- }
50
- export function isTerminal(status) {
51
- return TERMINAL_STATUSES.includes(status);
52
- }
53
- // ============================================================================
54
- // Transition Validators
55
- // ============================================================================
56
- function validateBlockedInput(input, errors) {
57
- if (!input.blocked || typeof input.blocked !== 'object') {
58
- errors.push({ field: 'blocked', message: 'required for transition to blocked' });
59
- return;
60
- }
61
- if (!isNonEmptyString(input.blocked.reason)) {
62
- errors.push({ field: 'blocked.reason', message: 'must be a non-empty string' });
63
- }
64
- if (input.blocked.dependency !== undefined && typeof input.blocked.dependency !== 'string') {
65
- errors.push({ field: 'blocked.dependency', message: 'must be a string if present' });
66
- }
67
- }
68
- function validateVerifyingInput(input, errors) {
69
- // Validate dod
70
- if (!input.dod || typeof input.dod !== 'object') {
71
- errors.push({ field: 'dod', message: 'required for transition to verifying' });
72
- }
73
- else if (!isNonEmptyStringArray(input.dod.checklist)) {
74
- errors.push({ field: 'dod.checklist', message: 'must be a non-empty array of non-empty strings' });
75
- }
76
- // Validate evidence
77
- if (!input.evidence || typeof input.evidence !== 'object') {
78
- errors.push({ field: 'evidence', message: 'required for transition to verifying' });
79
- return;
80
- }
81
- if (!isNonEmptyStringArray(input.evidence.artifacts)) {
82
- errors.push({ field: 'evidence.artifacts', message: 'must have at least 1 non-empty artifact' });
83
- }
84
- if (input.evidence.commands !== undefined) {
85
- if (!Array.isArray(input.evidence.commands)) {
86
- errors.push({ field: 'evidence.commands', message: 'must be an array if present' });
87
- }
88
- else if (!input.evidence.commands.every((c) => typeof c === 'string')) {
89
- errors.push({ field: 'evidence.commands', message: 'all items must be strings' });
90
- }
91
- }
92
- if (input.evidence.notes !== undefined && typeof input.evidence.notes !== 'string') {
93
- errors.push({ field: 'evidence.notes', message: 'must be a string if present' });
94
- }
95
- }
96
- function validateDoneTransition(task, errors) {
97
- // Structural verification: task must already have dod and evidence from verifying state
98
- if (!task.dod || !Array.isArray(task.dod.checklist) || task.dod.checklist.length === 0) {
99
- errors.push({ field: 'dod.checklist', message: 'must be non-empty to complete verification' });
100
- }
101
- if (!task.evidence || !Array.isArray(task.evidence.artifacts) || task.evidence.artifacts.length === 0) {
102
- errors.push({ field: 'evidence.artifacts', message: 'must have at least 1 artifact to complete verification' });
103
- }
104
- }
105
- // ============================================================================
106
- // Transition Function
107
- // ============================================================================
108
- export function transition(task, input) {
109
- const errors = [];
110
- const from = task.status;
111
- const to = input.to;
112
- // Check if transition is allowed by state machine
113
- if (!canTransition(from, to)) {
114
- const allowed = getAllowedTransitions(from);
115
- const allowedStr = allowed.length > 0 ? allowed.join(', ') : 'none (terminal state)';
116
- errors.push({
117
- field: 'status',
118
- message: `cannot transition from '${from}' to '${to}'. Allowed: ${allowedStr}`,
119
- });
120
- return { ok: false, errors };
121
- }
122
- // Validate transition-specific requirements
123
- switch (input.to) {
124
- case 'blocked':
125
- validateBlockedInput(input, errors);
126
- break;
127
- case 'verifying':
128
- validateVerifyingInput(input, errors);
129
- break;
130
- case 'done':
131
- validateDoneTransition(task, errors);
132
- break;
133
- }
134
- if (errors.length > 0) {
135
- return { ok: false, errors };
136
- }
137
- // Build the updated task
138
- const now = new Date().toISOString();
139
- const updatedTask = {
140
- ...task,
141
- status: to,
142
- updated_at: now,
143
- };
144
- // Apply transition-specific changes
145
- switch (input.to) {
146
- case 'blocked':
147
- updatedTask.blocked = input.blocked;
148
- break;
149
- case 'verifying':
150
- updatedTask.dod = input.dod;
151
- updatedTask.evidence = input.evidence;
152
- updatedTask.blocked = null;
153
- break;
154
- case 'done':
155
- // No changes needed - dod and evidence already set from verifying
156
- updatedTask.blocked = null;
157
- break;
158
- case 'in_progress':
159
- if (from === 'blocked') {
160
- // Clear blocked field when unblocking
161
- updatedTask.blocked = null;
162
- }
163
- else if (from === 'verifying') {
164
- // Rejection: clear evidence, keep dod for retry
165
- updatedTask.evidence = undefined;
166
- }
167
- break;
168
- case 'cancelled':
169
- updatedTask.blocked = null;
170
- break;
171
- }
172
- return { ok: true, task: updatedTask };
173
- }
174
- //# sourceMappingURL=transitions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transitions.js","sourceRoot":"","sources":["../src/transitions.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,CAAC,MAAM,iBAAiB,GAAsB,CAAC,MAAM,EAAE,WAAW,CAAU,CAAC;AAEnF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,mBAAmB,GAAsC;IAC7D,IAAI,EAAE,CAAC,aAAa,EAAE,WAAW,CAAC;IAClC,WAAW,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,CAAC;IAClD,OAAO,EAAE,CAAC,aAAa,EAAE,WAAW,CAAC;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC;IAC/C,IAAI,EAAE,EAAE;IACR,SAAS,EAAE,EAAE;CACL,CAAC;AA4CX,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc;IAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;AACnF,CAAC;AAED,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,EAAU;IACpD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E,SAAS,oBAAoB,CAAC,KAA0B,EAAE,MAAyB;IACjF,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC3F,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;IACvF,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,KAA4B,EAAE,MAAyB;IACrF,eAAe;IACf,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAC;IACjF,CAAC;SAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,gDAAgD,EAAE,CAAC,CAAC;IACrG,CAAC;IAED,oBAAoB;IACpB,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAC;QACpF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;QACtF,CAAC;aAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YACxE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACnF,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;IACnF,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAU,EAAE,MAAyB;IACnE,wFAAwF;IACxF,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvF,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,4CAA4C,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtG,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,wDAAwD,EAAE,CAAC,CAAC;IAClH,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E,MAAM,UAAU,UAAU,CAAC,IAAU,EAAE,KAAsB;IAC3D,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;IACzB,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;IAEpB,kDAAkD;IAClD,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC;QACrF,MAAM,CAAC,IAAI,CAAC;YACV,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,2BAA2B,IAAI,SAAS,EAAE,eAAe,UAAU,EAAE;SAC/E,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,4CAA4C;IAC5C,QAAQ,KAAK,CAAC,EAAE,EAAE,CAAC;QACjB,KAAK,SAAS;YACZ,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACpC,MAAM;QACR,KAAK,WAAW;YACd,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACtC,MAAM;QACR,KAAK,MAAM;YACT,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACrC,MAAM;IACV,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,yBAAyB;IACzB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,WAAW,GAAS;QACxB,GAAG,IAAI;QACP,MAAM,EAAE,EAAE;QACV,UAAU,EAAE,GAAG;KAChB,CAAC;IAEF,oCAAoC;IACpC,QAAQ,KAAK,CAAC,EAAE,EAAE,CAAC;QACjB,KAAK,SAAS;YACZ,WAAW,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;YACpC,MAAM;QAER,KAAK,WAAW;YACd,WAAW,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;YAC5B,WAAW,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YACtC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,MAAM;QAER,KAAK,MAAM;YACT,kEAAkE;YAClE,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,MAAM;QAER,KAAK,aAAa;YAChB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,sCAAsC;gBACtC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC7B,CAAC;iBAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBAChC,gDAAgD;gBAChD,WAAW,CAAC,QAAQ,GAAG,SAAS,CAAC;YACnC,CAAC;YACD,MAAM;QAER,KAAK,WAAW;YACd,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;YAC3B,MAAM;IACV,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AACzC,CAAC"}