@thehammer/danx-dashboard-mcp 0.1.23 → 0.1.24
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 +3 -3
- package/dist/index.js +17 -5
- package/package.json +1 -1
package/dist/handlers.js
CHANGED
|
@@ -89,8 +89,8 @@ export async function issueCreate(client, args, defaultBoard) {
|
|
|
89
89
|
body.effort_level = args.effort_level;
|
|
90
90
|
if (args.list_id !== undefined)
|
|
91
91
|
body.list_id = args.list_id;
|
|
92
|
-
if (args.
|
|
93
|
-
body.
|
|
92
|
+
if (args.gate_decisions !== undefined)
|
|
93
|
+
body.gate_decisions = args.gate_decisions;
|
|
94
94
|
if (args.phase_children !== undefined)
|
|
95
95
|
body.phase_children = args.phase_children;
|
|
96
96
|
return client.request({ method: "POST", path: "", body, board });
|
|
@@ -346,7 +346,7 @@ export async function issueRequiresHuman(client, args) {
|
|
|
346
346
|
* POST /api/issues/:id/quality-gates/:gate {required} — the same write the
|
|
347
347
|
* dashboard drawer's Quality Gates tab performs (DX-1181). This is the ONLY
|
|
348
348
|
* post-create path to mark a gate required/not — `issue_create` carries
|
|
349
|
-
* `
|
|
349
|
+
* `gate_decisions` at birth, and `issue_edit` rejects gate keys; without
|
|
350
350
|
* this tool an agent that created a card cannot turn a gate on afterward.
|
|
351
351
|
*
|
|
352
352
|
* `gate` is a registry name (`plan-dependency` | `plan-architecture` |
|
package/dist/index.js
CHANGED
|
@@ -165,7 +165,7 @@ server.tool("issue_get", 'Fetch a single hydrated issue via GET /api/issues/:id.
|
|
|
165
165
|
...boardField,
|
|
166
166
|
}, async (args) => jsonResult(await issueGet(client, args)));
|
|
167
167
|
// ---------------- issue_create ----------------
|
|
168
|
-
server.tool("issue_create", 'Create a fresh card via POST /api/issues. Board-scoped; defaults to the dispatch\'s board. Pass `board` (a qualified id `<repo>:<slug>`) to create the card on another board (forwarded into body.board + ?board=; unknown board → 404). INVARIANT: type=Epic REQUIRES non-empty phase_children[] (epic-with-phases atomicity per DX-575) and the route atomically inserts the epic + every phase in ONE transaction. Non-Epic types REFUSE phase_children[] with 400. Status defaults to Review (no lifecycle timestamps stamped on create). parent_id optional. ac items take {title}; phase children inherit the new epic\'s id as parent_id. Optional list_id PLACES the card directly into a column in ONE call. **Pass EITHER a board_lists id OR the list\'s display NAME (case-insensitive, emoji-tolerant — e.g. a queue name like "⚙️ Fulfillment Queue" or just "Fulfillment Queue") — the server resolves a name to its id.** The card lands DIRECTLY in that column with the matching lifecycle stamped automatically — a `ready`-type queue → ToDo, a `completed` list → Done, etc. **You do NOT need a separate issue_transition(ready) + issue_edit(list_id) afterward — just pass the queue name here and the card is created already in that column.** Omit list_id for the default (Review). NOT valid on type=Epic (Epic status derives from children) → 400. Unknown name/id → 400.
|
|
168
|
+
server.tool("issue_create", 'Create a fresh card via POST /api/issues. Board-scoped; defaults to the dispatch\'s board. Pass `board` (a qualified id `<repo>:<slug>`) to create the card on another board (forwarded into body.board + ?board=; unknown board → 404). INVARIANT: type=Epic REQUIRES non-empty phase_children[] (epic-with-phases atomicity per DX-575) and the route atomically inserts the epic + every phase in ONE transaction. Non-Epic types REFUSE phase_children[] with 400. Status defaults to Review (no lifecycle timestamps stamped on create). parent_id optional. ac items take {title}; phase children inherit the new epic\'s id as parent_id. Optional list_id PLACES the card directly into a column in ONE call. **Pass EITHER a board_lists id OR the list\'s display NAME (case-insensitive, emoji-tolerant — e.g. a queue name like "⚙️ Fulfillment Queue" or just "Fulfillment Queue") — the server resolves a name to its id.** The card lands DIRECTLY in that column with the matching lifecycle stamped automatically — a `ready`-type queue → ToDo, a `completed` list → Done, etc. **You do NOT need a separate issue_transition(ready) + issue_edit(list_id) afterward — just pass the queue name here and the card is created already in that column.** Omit list_id for the default (Review). NOT valid on type=Epic (Epic status derives from children) → 400. Unknown name/id → 400. **gate_decisions is REQUIRED whenever the board has any OPTIONAL quality gate for the card\'s type** (DX-1594): supply one `{gate, enabled, note}` per board-optional gate. The create FAILS CLOSED — a missing decision returns 400 `{error, required_gate_decisions:[...]}` enumerating exactly which gates to answer, so just retry with a decision for each listed gate. `required`/`disabled` board gates take no decision; a board with no optional gates needs no gate_decisions at all.', {
|
|
169
169
|
type: z.enum(ISSUE_TYPES),
|
|
170
170
|
title: z.string().min(1),
|
|
171
171
|
description: z.string(),
|
|
@@ -173,10 +173,14 @@ server.tool("issue_create", 'Create a fresh card via POST /api/issues. Board-sco
|
|
|
173
173
|
ac: z.array(z.object({ title: z.string().min(1) })).optional(),
|
|
174
174
|
effort_level: z.enum(EFFORT_VALUES).nullable().optional(),
|
|
175
175
|
list_id: z.string().min(1).nullable().optional(),
|
|
176
|
-
|
|
177
|
-
.array(z.
|
|
176
|
+
gate_decisions: z
|
|
177
|
+
.array(z.object({
|
|
178
|
+
gate: z.string().min(1),
|
|
179
|
+
enabled: z.boolean(),
|
|
180
|
+
note: z.string(),
|
|
181
|
+
}))
|
|
178
182
|
.optional()
|
|
179
|
-
.describe('
|
|
183
|
+
.describe('REQUIRED fail-closed quality-gate decisions (DX-1594 — replaces required_gates). One {gate, enabled, note} per board-OPTIONAL gate of the card\'s type: `enabled` answers whether the gate runs on this card, `note` records the rationale (persisted as the decision rationale, distinct from the reviewer verdict). The board requirement is TRI-STATE per gate (`board_quality_gate_settings.default_state`): `required` runs always (NO decision — auto-on); `optional` REQUIRES a decision here (unanswered → the create 400s); `disabled` never runs (NO decision). Omit this only on a board with no optional gates; otherwise the 400 body\'s `required_gate_decisions` lists exactly which gates to answer — retry with {enabled, note} for each. A decision naming a non-optional gate is rejected 400.'),
|
|
180
184
|
phase_children: z
|
|
181
185
|
.array(z.object({
|
|
182
186
|
type: z.enum(NON_EPIC_TYPES),
|
|
@@ -184,6 +188,14 @@ server.tool("issue_create", 'Create a fresh card via POST /api/issues. Board-sco
|
|
|
184
188
|
description: z.string(),
|
|
185
189
|
ac: z.array(z.object({ title: z.string().min(1) })).optional(),
|
|
186
190
|
effort_level: z.enum(EFFORT_VALUES).nullable().optional(),
|
|
191
|
+
gate_decisions: z
|
|
192
|
+
.array(z.object({
|
|
193
|
+
gate: z.string().min(1),
|
|
194
|
+
enabled: z.boolean(),
|
|
195
|
+
note: z.string(),
|
|
196
|
+
}))
|
|
197
|
+
.optional()
|
|
198
|
+
.describe("Per-child fail-closed gate decisions — same shape + rule as the root gate_decisions, resolved against THIS child's own type. Required when the child's type has board-optional gates."),
|
|
187
199
|
}))
|
|
188
200
|
.optional(),
|
|
189
201
|
...boardField,
|
|
@@ -295,7 +307,7 @@ server.tool("issue_requires_human", "Set or clear the requires_human dispatch ga
|
|
|
295
307
|
...boardField,
|
|
296
308
|
}, async (args) => jsonResult(await issueRequiresHuman(client, args)));
|
|
297
309
|
// ---------------- issue_quality_gate ----------------
|
|
298
|
-
server.tool("issue_quality_gate", "Toggle a single card's per-card quality-gate `required` flag via POST /api/issues/:id/quality-gates/:gate {required} — the SAME write the dashboard drawer's Quality Gates tab performs (DX-1181). This is the ONLY post-create way to mark a gate required/not-required: `issue_create` carries `
|
|
310
|
+
server.tool("issue_quality_gate", "Toggle a single card's per-card quality-gate `required` flag via POST /api/issues/:id/quality-gates/:gate {required} — the SAME write the dashboard drawer's Quality Gates tab performs (DX-1181). This is the ONLY post-create way to mark a gate required/not-required: `issue_create` carries `gate_decisions` at birth, and `issue_edit` REJECTS gate keys (400 offending_keys) — without this tool a card created without a gate can never have it turned on by an agent. `gate` is a registry name: `plan-dependency` | `plan-architecture` | `plan-tdd` | `code-test-quality` | `code-architecture` | `code-quality` (the PRE/plan- gates run before the work dispatch; the POST/code- gates block issue_transition complete). Unknown gate → 400 (never a silent no-op); a card with no seeded row for a registered gate → 500 (canonical corruption). NOTE board requirement is TRI-STATE per gate (`board_quality_gate_settings.default_state`, the Agents-tab surface), NOT a binary on/off: `required` = gate always runs (this flag irrelevant); `optional` = gate runs WHEN this per-card flag is true (per-card opt-in — `optional` is ENABLED, NOT off); `disabled` = never runs (this flag inert). So flipping `required:true` here LAUNCHES the gate when the board state is `required` OR `optional`; it is inert ONLY when the board state is `disabled`. Do not read `optional` as off. (Source of truth: `isGateEffectivelyRequired` in `src/issues/quality-gates/read.ts`.) Returns the hydrated issue. Board-scoped; pass `board` (`<repo>:<slug>`) to target another board.", {
|
|
299
311
|
id: z.string().min(1),
|
|
300
312
|
gate: z.enum([
|
|
301
313
|
"plan-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.24",
|
|
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",
|