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 +18 -22
- package/dist/server.js +63 -56
- package/dist/server.js.map +1 -1
- package/package.json +17 -2
- package/dist/transitions.d.ts +0 -32
- package/dist/transitions.js +0 -174
- package/dist/transitions.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# backlog-mcp
|
|
2
2
|
|
|
3
|
-
Minimal task backlog
|
|
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
|
|
22
|
+
## MCP Tool
|
|
23
|
+
|
|
24
|
+
Single unified tool with action parameter:
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
21
|
-
|
|
20
|
+
const ACTIONS = ['list', 'get', 'create', 'update'];
|
|
21
|
+
server.registerTool('backlog', {
|
|
22
|
+
description: 'Manage tasks. Actions: list, get, create, update',
|
|
22
23
|
inputSchema: {
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,CAAC,YAAY,CACjB,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backlog-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Minimal
|
|
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",
|
package/dist/transitions.d.ts
DELETED
|
@@ -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;
|
package/dist/transitions.js
DELETED
|
@@ -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
|
package/dist/transitions.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transitions.js","sourceRoot":"","sources":["../src/transitions.ts"],"names":[],"mappings":"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"}
|