kanbango 3.3.0 → 3.5.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/.ai/lessons.jsonl +1 -0
- package/.ai/retro/last-run.json +1 -1
- package/.ait-quality.yml +25 -0
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +32 -4
- package/README.md +2 -2
- package/agent-playbook.js +12 -6
- package/bin/kanban.js +49 -14
- package/fenced-text.js +62 -0
- package/index.html +1305 -1168
- package/kanban.js +107 -82
- package/mcp-server.js +89 -144
- package/package.json +3 -2
- package/tests/run.js +4 -1
- package/.opencode/plans/action-error-recipe.md +0 -121
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Action error recipe (implement)
|
|
2
|
-
|
|
3
|
-
Status: approved (user said go). Plan mode blocked code edits — switch to **build** and apply.
|
|
4
|
-
|
|
5
|
-
## Goal
|
|
6
|
-
Missing/empty/unknown `action` on `kanban_manage` / `kanban_gui`: **message** is a full retry recipe (Valid + Example JSON + sent keys).
|
|
7
|
-
|
|
8
|
-
## Files
|
|
9
|
-
1. `mcp-server.js` — replace `requireToolAction`; add helpers; unknown-action defaults
|
|
10
|
-
2. `tests/mcp-server.test.js` — assert recipe content
|
|
11
|
-
3. `CHANGELOG.md` — one-line unreleased note
|
|
12
|
-
|
|
13
|
-
## mcp-server.js
|
|
14
|
-
|
|
15
|
-
Replace current `requireToolAction` block (after `GUI_ACTIONS`) with:
|
|
16
|
-
|
|
17
|
-
```js
|
|
18
|
-
const ACTION_EXAMPLES = {
|
|
19
|
-
kanban_manage: '{"action":"create","title":"Ship image","col":"planned"}',
|
|
20
|
-
kanban_gui: '{"action":"status"}'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
function receivedKeys(args) {
|
|
24
|
-
return Object.keys(args && typeof args === 'object' ? args : {});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function actionRecipeMessage(toolName, allowed, opts = {}) {
|
|
28
|
-
const keys = opts.received_keys || [];
|
|
29
|
-
const example = ACTION_EXAMPLES[toolName] || `{"action":"${allowed[0]}"}`;
|
|
30
|
-
const lines = [];
|
|
31
|
-
if (opts.kind === 'unknown') {
|
|
32
|
-
lines.push(`Unknown action "${opts.action}" on ${toolName}.`);
|
|
33
|
-
} else {
|
|
34
|
-
lines.push(`Missing required top-level field "action" on ${toolName}.`);
|
|
35
|
-
}
|
|
36
|
-
lines.push('Pass action next to other args (not nested under params).');
|
|
37
|
-
lines.push(`Valid: ${allowed.join(', ')}.`);
|
|
38
|
-
lines.push(`Example: ${example}`);
|
|
39
|
-
lines.push(keys.length > 0 ? `You sent keys: ${keys.join(', ')}` : 'You sent keys: (none)');
|
|
40
|
-
return lines.join(' ');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function actionRecipeHint() {
|
|
44
|
-
return [
|
|
45
|
-
'Retry the same tool with top-level action set to one Valid value.',
|
|
46
|
-
'Common mistake: omitting action, or putting it under params (jira/gitlab style) — kanban uses top-level action.'
|
|
47
|
-
].join(' ');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function requireToolAction(args, allowed, toolName) {
|
|
51
|
-
const action = args && args.action;
|
|
52
|
-
const keys = receivedKeys(args);
|
|
53
|
-
if (action === undefined || action === null || action === '') {
|
|
54
|
-
throw kanban.createKanbanError(
|
|
55
|
-
'MISSING_REQUIRED_FIELD',
|
|
56
|
-
actionRecipeMessage(toolName, allowed, {
|
|
57
|
-
kind: 'missing',
|
|
58
|
-
received_keys: keys,
|
|
59
|
-
action: action === undefined ? null : action
|
|
60
|
-
}),
|
|
61
|
-
actionRecipeHint(),
|
|
62
|
-
{
|
|
63
|
-
field: 'action',
|
|
64
|
-
tool: toolName,
|
|
65
|
-
received_keys: keys,
|
|
66
|
-
allowed_actions: allowed,
|
|
67
|
-
action: action === undefined ? null : action
|
|
68
|
-
},
|
|
69
|
-
false,
|
|
70
|
-
400
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
return action;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function unknownToolAction(action, args, allowed, toolName) {
|
|
77
|
-
const keys = receivedKeys(args);
|
|
78
|
-
return invalidRequest(
|
|
79
|
-
actionRecipeMessage(toolName, allowed, { kind: 'unknown', action, received_keys: keys }),
|
|
80
|
-
actionRecipeHint(),
|
|
81
|
-
{
|
|
82
|
-
field: 'action',
|
|
83
|
-
tool: toolName,
|
|
84
|
-
action,
|
|
85
|
-
received_keys: keys,
|
|
86
|
-
allowed_actions: allowed
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Manage default: `throw unknownToolAction(action, args, MANAGE_ACTIONS, 'kanban_manage');`
|
|
93
|
-
GUI default: `throw unknownToolAction(action, args, GUI_ACTIONS, 'kanban_gui');`
|
|
94
|
-
|
|
95
|
-
## tests/mcp-server.test.js
|
|
96
|
-
|
|
97
|
-
Assert on missing/empty/unknown/gui:
|
|
98
|
-
- message includes `Missing required top-level field "action"` (or `Unknown action "nope"`)
|
|
99
|
-
- `Valid:` + key actions + `Example:` + `"action":`
|
|
100
|
-
- sent keys line
|
|
101
|
-
- `details.allowed_actions`
|
|
102
|
-
- no `undefined` in message
|
|
103
|
-
- codes unchanged: MISSING_REQUIRED_FIELD / VALIDATION_ERROR
|
|
104
|
-
|
|
105
|
-
## CHANGELOG
|
|
106
|
-
|
|
107
|
-
```md
|
|
108
|
-
### Fixed
|
|
109
|
-
- MCP `kanban_manage` / `kanban_gui`: missing/empty/unknown `action` errors put a full retry recipe in `message` (Valid list + Example JSON + sent keys); missing/empty use `MISSING_REQUIRED_FIELD` instead of `Unknown action: undefined`
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Verify
|
|
113
|
-
```bash
|
|
114
|
-
node tests/mcp-server.test.js
|
|
115
|
-
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"kanban_manage","arguments":{"title":"x"}}}' | node mcp-server.js
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## Acceptance
|
|
119
|
-
- [ ] Missing action message is copy-paste retry recipe
|
|
120
|
-
- [ ] Unknown action same clarity
|
|
121
|
-
- [ ] Tests green
|