@thehammer/danx-dashboard-mcp 0.1.18 → 0.1.19
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/dist/handlers.js +105 -0
- package/dist/index.js +27 -1
- package/package.json +1 -1
package/dist/handlers.js
CHANGED
|
@@ -205,6 +205,111 @@ export async function issueDependency(client, args) {
|
|
|
205
205
|
board,
|
|
206
206
|
});
|
|
207
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* DX-1362 — targeted checklist CUD. Action-dispatched onto the
|
|
210
|
+
* `/api/issues/:id/checklists[/:cid[/items[/:iid]]]` route family so an agent
|
|
211
|
+
* mutates ONE checklist or item without the wholesale `issue_edit({checklists})`
|
|
212
|
+
* replace (which silently drops any omitted checklist + churns every item id).
|
|
213
|
+
* A missing required arg for the chosen action throws at this boundary (no
|
|
214
|
+
* round-trip). The dashboard's structured error envelope passes through verbatim.
|
|
215
|
+
*/
|
|
216
|
+
export async function issueChecklist(client, args) {
|
|
217
|
+
const idEnc = encodeURIComponent(args.id);
|
|
218
|
+
const board = args.board;
|
|
219
|
+
switch (args.action) {
|
|
220
|
+
case "add_list": {
|
|
221
|
+
if (typeof args.name !== "string") {
|
|
222
|
+
throw new Error("issue_checklist action=add_list requires name");
|
|
223
|
+
}
|
|
224
|
+
const body = { name: args.name };
|
|
225
|
+
if (args.items !== undefined)
|
|
226
|
+
body.items = args.items;
|
|
227
|
+
return client.request({
|
|
228
|
+
method: "POST",
|
|
229
|
+
path: `/${idEnc}/checklists`,
|
|
230
|
+
body,
|
|
231
|
+
board,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
case "update_list": {
|
|
235
|
+
if (args.checklist_id === undefined) {
|
|
236
|
+
throw new Error("issue_checklist action=update_list requires checklist_id");
|
|
237
|
+
}
|
|
238
|
+
if (typeof args.name !== "string") {
|
|
239
|
+
throw new Error("issue_checklist action=update_list requires name");
|
|
240
|
+
}
|
|
241
|
+
return client.request({
|
|
242
|
+
method: "PATCH",
|
|
243
|
+
path: `/${idEnc}/checklists/${args.checklist_id}`,
|
|
244
|
+
body: { name: args.name },
|
|
245
|
+
board,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
case "remove_list": {
|
|
249
|
+
if (args.checklist_id === undefined) {
|
|
250
|
+
throw new Error("issue_checklist action=remove_list requires checklist_id");
|
|
251
|
+
}
|
|
252
|
+
return client.request({
|
|
253
|
+
method: "DELETE",
|
|
254
|
+
path: `/${idEnc}/checklists/${args.checklist_id}`,
|
|
255
|
+
board,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
case "add_item": {
|
|
259
|
+
if (args.checklist_id === undefined) {
|
|
260
|
+
throw new Error("issue_checklist action=add_item requires checklist_id");
|
|
261
|
+
}
|
|
262
|
+
if (typeof args.label !== "string") {
|
|
263
|
+
throw new Error("issue_checklist action=add_item requires label");
|
|
264
|
+
}
|
|
265
|
+
const body = { label: args.label };
|
|
266
|
+
if (args.detail !== undefined)
|
|
267
|
+
body.detail = args.detail;
|
|
268
|
+
if (args.status !== undefined)
|
|
269
|
+
body.status = args.status;
|
|
270
|
+
return client.request({
|
|
271
|
+
method: "POST",
|
|
272
|
+
path: `/${idEnc}/checklists/${args.checklist_id}/items`,
|
|
273
|
+
body,
|
|
274
|
+
board,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
case "update_item": {
|
|
278
|
+
if (args.checklist_id === undefined) {
|
|
279
|
+
throw new Error("issue_checklist action=update_item requires checklist_id");
|
|
280
|
+
}
|
|
281
|
+
if (args.item_id === undefined) {
|
|
282
|
+
throw new Error("issue_checklist action=update_item requires item_id");
|
|
283
|
+
}
|
|
284
|
+
const body = {};
|
|
285
|
+
if (args.label !== undefined)
|
|
286
|
+
body.label = args.label;
|
|
287
|
+
if (args.detail !== undefined)
|
|
288
|
+
body.detail = args.detail;
|
|
289
|
+
if (args.status !== undefined)
|
|
290
|
+
body.status = args.status;
|
|
291
|
+
return client.request({
|
|
292
|
+
method: "PATCH",
|
|
293
|
+
path: `/${idEnc}/checklists/${args.checklist_id}/items/${args.item_id}`,
|
|
294
|
+
body,
|
|
295
|
+
board,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
case "remove_item": {
|
|
299
|
+
if (args.checklist_id === undefined) {
|
|
300
|
+
throw new Error("issue_checklist action=remove_item requires checklist_id");
|
|
301
|
+
}
|
|
302
|
+
if (args.item_id === undefined) {
|
|
303
|
+
throw new Error("issue_checklist action=remove_item requires item_id");
|
|
304
|
+
}
|
|
305
|
+
return client.request({
|
|
306
|
+
method: "DELETE",
|
|
307
|
+
path: `/${idEnc}/checklists/${args.checklist_id}/items/${args.item_id}`,
|
|
308
|
+
board,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
208
313
|
export async function issueRequiresHuman(client, args) {
|
|
209
314
|
const idEnc = encodeURIComponent(args.id);
|
|
210
315
|
const board = args.board;
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* - issue_transition POST /api/issues/:id/transition
|
|
19
19
|
* - issue_triage POST /api/issues/:id/triage
|
|
20
20
|
* - issue_comment POST/PATCH/DELETE /api/issues/:id/comments[/:cid]
|
|
21
|
+
* - issue_checklist POST/PATCH/DELETE /api/issues/:id/checklists[/:cid[/items[/:iid]]]
|
|
21
22
|
* - issue_dependency POST/DELETE /api/issues/:id/dependencies[/:did]
|
|
22
23
|
* - issue_requires_human POST/DELETE /api/issues/:id/requires-human
|
|
23
24
|
* - issue_retro PUT /api/issues/:id/retro
|
|
@@ -50,7 +51,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
50
51
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
51
52
|
import { z } from "zod";
|
|
52
53
|
import { DashboardHttpClient } from "./http-client.js";
|
|
53
|
-
import { issueAttach, issueComment, issueCreate, issueDependency, issueEdit, issueGet, issueList, issueRequiresHuman, issueRetro, issueTransition, issueTriage, } from "./handlers.js";
|
|
54
|
+
import { issueAttach, issueChecklist, issueComment, issueCreate, issueDependency, issueEdit, issueGet, issueList, issueRequiresHuman, issueRetro, issueTransition, issueTriage, } from "./handlers.js";
|
|
54
55
|
function readEnvOrDie(name) {
|
|
55
56
|
const v = process.env[name];
|
|
56
57
|
if (typeof v !== "string" || v === "") {
|
|
@@ -229,6 +230,31 @@ server.tool("issue_comment", "Comment CRUD via /api/issues/:id/comments[/:cid].
|
|
|
229
230
|
text: z.string().min(1).optional(),
|
|
230
231
|
...boardField,
|
|
231
232
|
}, async (args) => jsonResult(await issueComment(client, args)));
|
|
233
|
+
// ---------------- issue_checklist ----------------
|
|
234
|
+
const CHECKLIST_ITEM_INPUT = z.object({
|
|
235
|
+
label: z.string().min(1),
|
|
236
|
+
detail: z.string().optional(),
|
|
237
|
+
status: z.enum(CHECKLIST_ITEM_STATUSES).optional(),
|
|
238
|
+
});
|
|
239
|
+
server.tool("issue_checklist", "Targeted checklist CUD via /api/issues/:id/checklists[/:cid[/items[/:iid]]] (DX-1362). Mutates ONE checklist or item WITHOUT the wholesale `issue_edit({checklists})` replace — use this for the common case (flip an item's status, add/rename a checklist, add/edit/remove an item); the wholesale path silently DROPS any checklist you omit and churns every item id (orphaning its Trello mirror), so prefer this for single-item changes. Action-dispatched: add_list (POST :id/checklists {name, items?}) — create a named checklist, optionally with initial items; update_list (PATCH :id/checklists/:cid {name}) — rename; remove_list (DELETE :id/checklists/:cid) — soft-delete the checklist (audit trail preserved); add_item (POST :id/checklists/:cid/items {label, detail?, status?}) — append an item (status defaults `incomplete`); update_item (PATCH :id/checklists/:cid/items/:iid {label?, detail?, status?}) — change ONLY the fields you pass, in place (the item keeps its id + Trello linkage; at least one field required); remove_item (DELETE :id/checklists/:cid/items/:iid) — soft-delete one item. 4-state status: incomplete|failing|passing|cancelled (terminal = passing|cancelled). checklist_id is required for every action except add_list; item_id for update_item/remove_item. Each returns the {ok,status,body} envelope; unknown card/checklist/item → 404, invalid status → 400. ADDITIVE — the wholesale `issue_edit({checklists})` path stays for bulk authoring.", {
|
|
240
|
+
id: z.string().min(1),
|
|
241
|
+
action: z.enum([
|
|
242
|
+
"add_list",
|
|
243
|
+
"update_list",
|
|
244
|
+
"remove_list",
|
|
245
|
+
"add_item",
|
|
246
|
+
"update_item",
|
|
247
|
+
"remove_item",
|
|
248
|
+
]),
|
|
249
|
+
checklist_id: z.number().int().positive().optional(),
|
|
250
|
+
item_id: z.number().int().positive().optional(),
|
|
251
|
+
name: z.string().min(1).optional(),
|
|
252
|
+
items: z.array(CHECKLIST_ITEM_INPUT).optional(),
|
|
253
|
+
label: z.string().min(1).optional(),
|
|
254
|
+
detail: z.string().optional(),
|
|
255
|
+
status: z.enum(CHECKLIST_ITEM_STATUSES).optional(),
|
|
256
|
+
...boardField,
|
|
257
|
+
}, async (args) => jsonResult(await issueChecklist(client, args)));
|
|
232
258
|
// ---------------- issue_dependency ----------------
|
|
233
259
|
server.tool("issue_dependency", "Dependency CRUD via /api/issues/:id/dependencies[/:did]. action=add → POST {kind, target_id, reason} where kind ∈ {depends_on, conflict_on}. depends_on adds are CYCLE-CHECKED (BFS from target back to source — 409 if loop). Idempotent: re-adding a live triple returns the existing id. Self-loops refuse 409. action=remove → DELETE /:did. The server REQUIRES the literal reason=\"recorded_in_error\" on removal (encodes \"removal means NOT related, never satisfied\") — this MCP boundary hardcodes it, so callers do not pass reason on remove.", {
|
|
234
260
|
id: z.string().min(1),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thehammer/danx-dashboard-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Stdio MCP server wrapping danxbot's dashboard /api/issues/* normalized DB-backed HTTP routes for dispatched agents (DX-704 Phase 2).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|