@thehammer/danx-dashboard-mcp 0.1.120 → 0.1.121
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 +54 -6
- package/dist/index.js +53 -7
- package/package.json +1 -1
package/dist/handlers.js
CHANGED
|
@@ -679,12 +679,13 @@ export async function issueProblem(client, args) {
|
|
|
679
679
|
}
|
|
680
680
|
}
|
|
681
681
|
/**
|
|
682
|
-
* One problem's candidate solutions
|
|
683
|
-
* `/api/issues/:id/problems/:pid/solutions[/:sid]`
|
|
684
|
-
* like `issue_checklist`. A missing required arg for the
|
|
685
|
-
* this boundary (no round-trip); the server's
|
|
686
|
-
* (`stale_solution` with the current row, a
|
|
687
|
-
* problem, editing a chosen option, a
|
|
682
|
+
* One problem's candidate solutions, AND (DX-3310) one solution's individual
|
|
683
|
+
* procedure steps, via `/api/issues/:id/problems/:pid/solutions[/:sid][/steps[/:stepId]]`
|
|
684
|
+
* — action-dispatched like `issue_checklist`. A missing required arg for the
|
|
685
|
+
* chosen action throws at this boundary (no round-trip); the server's
|
|
686
|
+
* refusal envelopes (`stale_solution`/`stale_step` with the current row, a
|
|
687
|
+
* second recommendation on the same problem, editing a chosen option, a
|
|
688
|
+
* solution/step id from the wrong scope → 404, nesting past depth 3 → 400)
|
|
688
689
|
* pass through verbatim.
|
|
689
690
|
*
|
|
690
691
|
* There is deliberately NO answer action, on this tool or any other. Answering
|
|
@@ -708,11 +709,22 @@ export async function issueSolution(client, args) {
|
|
|
708
709
|
case "add": {
|
|
709
710
|
// DX-2735: the POST carries the CHECKED title, not a re-read of args.title.
|
|
710
711
|
const title = need.string(args.title, "title");
|
|
712
|
+
// DX-3310 — omitted `steps` on add means "no steps", not "leave
|
|
713
|
+
// untouched" (there is nothing yet to leave untouched on a brand new
|
|
714
|
+
// solution) — sent through only when the caller actually supplied it,
|
|
715
|
+
// so an existing add-only caller that never heard of `steps` keeps
|
|
716
|
+
// creating exactly what it always created.
|
|
717
|
+
if (args.steps !== undefined)
|
|
718
|
+
content.steps = args.steps;
|
|
711
719
|
return client.request({ method: "POST", path: base, body: { ...content, title }, board });
|
|
712
720
|
}
|
|
713
721
|
case "edit": {
|
|
714
722
|
const solutionId = need.id(args.solution_id, "solution_id");
|
|
715
723
|
const baseHash = need.string(args.base_hash, "base_hash");
|
|
724
|
+
// DX-3310 — omitted keeps the stored steps untouched; an explicit
|
|
725
|
+
// (including empty) array replaces them via the server's diff.
|
|
726
|
+
if (args.steps !== undefined)
|
|
727
|
+
content.steps = args.steps;
|
|
716
728
|
return client.request({
|
|
717
729
|
method: "PATCH",
|
|
718
730
|
path: `${base}/${solutionId}`,
|
|
@@ -730,6 +742,42 @@ export async function issueSolution(client, args) {
|
|
|
730
742
|
board,
|
|
731
743
|
});
|
|
732
744
|
}
|
|
745
|
+
// DX-3310 (AC 35250) — granular single-step CUD, so changing one step
|
|
746
|
+
// never requires resending the whole `steps` tree.
|
|
747
|
+
case "add_step": {
|
|
748
|
+
const solutionId = need.id(args.solution_id, "solution_id");
|
|
749
|
+
const title = need.string(args.title, "title");
|
|
750
|
+
const body = { title };
|
|
751
|
+
if (args.description !== undefined)
|
|
752
|
+
body.description = args.description;
|
|
753
|
+
if (args.parent_step_id !== undefined)
|
|
754
|
+
body.parent_step_id = args.parent_step_id;
|
|
755
|
+
if (args.position !== undefined)
|
|
756
|
+
body.position = args.position;
|
|
757
|
+
return client.request({ method: "POST", path: `${base}/${solutionId}/steps`, body, board });
|
|
758
|
+
}
|
|
759
|
+
case "edit_step": {
|
|
760
|
+
const solutionId = need.id(args.solution_id, "solution_id");
|
|
761
|
+
const stepId = need.id(args.step_id, "step_id");
|
|
762
|
+
const baseHash = need.string(args.base_hash, "base_hash");
|
|
763
|
+
const body = { base_hash: baseHash };
|
|
764
|
+
if (args.title !== undefined)
|
|
765
|
+
body.title = args.title;
|
|
766
|
+
if (args.description !== undefined)
|
|
767
|
+
body.description = args.description;
|
|
768
|
+
return client.request({ method: "PATCH", path: `${base}/${solutionId}/steps/${stepId}`, body, board });
|
|
769
|
+
}
|
|
770
|
+
case "remove_step": {
|
|
771
|
+
const solutionId = need.id(args.solution_id, "solution_id");
|
|
772
|
+
const stepId = need.id(args.step_id, "step_id");
|
|
773
|
+
const baseHash = need.string(args.base_hash, "base_hash");
|
|
774
|
+
return client.request({
|
|
775
|
+
method: "DELETE",
|
|
776
|
+
path: `${base}/${solutionId}/steps/${stepId}`,
|
|
777
|
+
body: { base_hash: baseHash },
|
|
778
|
+
board,
|
|
779
|
+
});
|
|
780
|
+
}
|
|
733
781
|
}
|
|
734
782
|
}
|
|
735
783
|
/**
|
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* - issue_comment POST/PATCH/DELETE /api/issues/:id/comments[/:cid]
|
|
21
21
|
* - issue_checklist POST/PATCH/DELETE /api/issues/:id/checklists[/:cid[/items[/:iid]]]
|
|
22
22
|
* - issue_problem GET/POST/PATCH/DELETE /api/issues/:id/problems[/:pid] (DX-2735)
|
|
23
|
-
* - issue_solution POST/PATCH/DELETE /api/issues/:id/problems/:pid/solutions[/:sid] (DX-2735)
|
|
23
|
+
* - issue_solution POST/PATCH/DELETE /api/issues/:id/problems/:pid/solutions[/:sid][/steps[/:stepId]] (DX-2735, steps DX-3310)
|
|
24
24
|
* - issue_dependency POST/DELETE /api/issues/:id/dependencies[/:did]
|
|
25
25
|
* - issue_retire_branch POST /api/issues/:id/card-branch-retire (DX-2845)
|
|
26
26
|
* - issue_quality_gate POST /api/issues/:id/quality-gates/:gate
|
|
@@ -678,15 +678,61 @@ strictTool("issue_problem", "A card's PROBLEMS via /api/issues/:id/problems[/:pi
|
|
|
678
678
|
.describe("add only; fields as issue_solution add"),
|
|
679
679
|
...boardField,
|
|
680
680
|
}, async (args) => jsonResult(await issueProblem(client, args)));
|
|
681
|
-
|
|
682
|
-
|
|
681
|
+
const STEP_INPUT = z.lazy(() => z
|
|
682
|
+
.object({
|
|
683
|
+
id: z
|
|
684
|
+
.number()
|
|
685
|
+
.int()
|
|
686
|
+
.positive()
|
|
687
|
+
.optional()
|
|
688
|
+
.describe("present → this node IS an existing step (matched on this id); absent → new, or matched by (parent, ordinal, title)"),
|
|
689
|
+
title: z.string().min(1),
|
|
690
|
+
description: z.string().nullable().optional().describe("markdown detail, or null/omitted for none"),
|
|
691
|
+
steps: z.array(STEP_INPUT).optional().describe("this step's own children, nested — refused past 3 levels total"),
|
|
692
|
+
})
|
|
693
|
+
.strict());
|
|
694
|
+
strictTool("issue_solution", "One problem's options via /api/issues/:id/problems/:pid/solutions[/:sid], AND (DX-3310) one solution's individual " +
|
|
695
|
+
"procedure steps via .../solutions/:sid/steps[/:stepId]; `problem_id` is REQUIRED (from issue_problem list/add; " +
|
|
696
|
+
"another problem's solution id → 404). add {title, body?, pro?, con?, recommended?, steps?}: title names the " +
|
|
697
|
+
"option/route, body is its markdown detail, pro/con the case for and against, `steps` is its WHOLE procedure " +
|
|
698
|
+
"authored in one call — an ordered array of {title, description?, steps?}, nestable to 3 levels (a 4th is refused " +
|
|
699
|
+
"400 naming the offending step and the limit); edit :sid {base_hash, ...only the changed fields, steps?}: `steps` " +
|
|
700
|
+
"omitted leaves the stored procedure untouched, an explicit array (including []) DIFFS against it — send back an " +
|
|
701
|
+
"existing step's `id` (read from the card) to keep it (even while retitling/reordering it) and omit `id` for a " +
|
|
702
|
+
"genuinely new step; any existing step you don't include gets removed. NEVER resend the whole tree just to fix " +
|
|
703
|
+
"one word — see add_step/edit_step/remove_step below. remove :sid {base_hash}. A stale base_hash → 409 " +
|
|
704
|
+
"`stale_solution` with currentHash + currentSolution: merge, then retry. At most ONE live recommended per " +
|
|
705
|
+
"problem: a second → 409 naming `recommended_solution_id`. A chosen option cannot be edited (409 — add a new " +
|
|
706
|
+
"one) but can be removed.\n\n" +
|
|
707
|
+
"Granular single-step actions — change ONE step without resending the tree: add_step {solution_id, title, " +
|
|
708
|
+
"description?, parent_step_id?, position?} — parent_step_id omitted/null = top-level; position is 1-indexed " +
|
|
709
|
+
"among the parent's current live children, omitted = append; nesting past depth 3 → 400. edit_step " +
|
|
710
|
+
"{solution_id, step_id, base_hash, title?, description?} — never moves a step (no parent_step_id/position here). " +
|
|
711
|
+
"remove_step {solution_id, step_id, base_hash} — soft-deletes it AND its own live children. A stale base_hash on " +
|
|
712
|
+
"a step → 409 `stale_step` with currentHash + currentStep (carrying its real derived `label`).", {
|
|
683
713
|
id: z.string().min(1),
|
|
684
|
-
action: z.enum(["add", "edit", "remove"]),
|
|
714
|
+
action: z.enum(["add", "edit", "remove", "add_step", "edit_step", "remove_step"]),
|
|
685
715
|
problem_id: z.number().int().positive(),
|
|
686
|
-
solution_id: z.number().int().positive().optional().describe("edit/remove"),
|
|
687
|
-
base_hash: z.string().min(1).optional().describe("content_hash last read; edit/remove"),
|
|
688
|
-
title: z.string().min(1).optional().describe("add"),
|
|
716
|
+
solution_id: z.number().int().positive().optional().describe("edit/remove/add_step/edit_step/remove_step"),
|
|
717
|
+
base_hash: z.string().min(1).optional().describe("content_hash last read; edit/remove/edit_step/remove_step"),
|
|
718
|
+
title: z.string().min(1).optional().describe("add; also add_step/edit_step"),
|
|
689
719
|
...SOLUTION_FIELDS,
|
|
720
|
+
steps: z.array(STEP_INPUT).optional().describe("add/edit only — see this tool's own description"),
|
|
721
|
+
description: z.string().nullable().optional().describe("add_step/edit_step; markdown detail, or null/omitted for none"),
|
|
722
|
+
step_id: z.number().int().positive().optional().describe("edit_step/remove_step"),
|
|
723
|
+
parent_step_id: z
|
|
724
|
+
.number()
|
|
725
|
+
.int()
|
|
726
|
+
.positive()
|
|
727
|
+
.nullable()
|
|
728
|
+
.optional()
|
|
729
|
+
.describe("add_step only; omitted/null = top-level step"),
|
|
730
|
+
position: z
|
|
731
|
+
.number()
|
|
732
|
+
.int()
|
|
733
|
+
.positive()
|
|
734
|
+
.optional()
|
|
735
|
+
.describe("add_step only; 1-indexed among the parent's current live children, omitted = append"),
|
|
690
736
|
...boardField,
|
|
691
737
|
}, async (args) => jsonResult(await issueSolution(client, args)));
|
|
692
738
|
// ---------------- issue_dependency ----------------
|
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.121",
|
|
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",
|