@thehammer/danx-dashboard-mcp 0.1.209 → 0.1.211
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 +1 -1
- package/dist/index.js +1 -2
- package/dist/listen.js +45 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ There is no dedicated `resource_fields` tool (removed DX-3465 — it was a thin
|
|
|
29
29
|
|
|
30
30
|
A dedicated tool survives only for something about the agent itself, never a card/plan operation: `plan_connect` (binds the session to a plan; the event-bridge hook keys on it) and the per-dispatch worker callbacks (`danxbot_complete`, `danxbot_slack_reply`, `danxbot_slack_post_update`, `load_template_app`/`save_template_app`, `quality_gate_complete`, `link_thread_to_issue`, `attach_file`, the `slack_recovery_*` trio, `danxbot_set_evaluator_summary`) — see `src/lifecycle.ts`. The live list is always `tool-defs.json` in this package, regenerated by `npm run gen-tool-defs` — read it rather than trusting a list copied into prose.
|
|
31
31
|
|
|
32
|
-
Card and plan reads/writes go through `danxbot_api` against the issue/plan route families documented in `GET /api/openapi` (via `danxbot_api_spec`) — `POST /api/issues`, `GET /api/issues/:id` (or `/batch` for many at once, DX-2727), `PATCH /api/issues/:id/edit`, `POST /api/issues/:id/transition`, the problems/solutions/dependencies/comments/quality-gates/retro sub-resource routes, and the equivalent `/api/plans/*` family (`GET /api/plans/:planId` — cheap scalars by default, `fields` opts into `cards`/`records`/`architecture`/`
|
|
32
|
+
Card and plan reads/writes go through `danxbot_api` against the issue/plan route families documented in `GET /api/openapi` (via `danxbot_api_spec`) — `POST /api/issues`, `GET /api/issues/:id` (or `/batch` for many at once, DX-2727), `PATCH /api/issues/:id/edit`, `POST /api/issues/:id/transition`, the problems/solutions/dependencies/comments/quality-gates/retro sub-resource routes, and the equivalent `/api/plans/*` family (`GET /api/plans/:planId` — cheap scalars by default, `fields` opts into `cards`/`records`/`architecture`/`session_history`/`worker_dispatches`; `GET /api/plans` for the list, with an optional `status` filter over the same computed `complete`/`awaiting-session`/`building`/`planning` value `GET /api/plans/:planId` always returns ungated).
|
|
33
33
|
|
|
34
34
|
## `bridge` — a working session's event stream client
|
|
35
35
|
|
package/dist/index.js
CHANGED
|
@@ -249,8 +249,7 @@ EXACT current shape of the one(s) you picked, before calling them through \`danx
|
|
|
249
249
|
schema, required permission, and every documented error envelope. Never guess a field name or a route path.
|
|
250
250
|
|
|
251
251
|
ALWAYS PASS \`fields\`. The default response for a list/get route is minimal — scalars only, no relations, no
|
|
252
|
-
heavy text. Every resource that supports it takes a \`fields\` query param (a field tree
|
|
253
|
-
an older route) that opts into exactly what you need. Passing nothing and then being surprised a field is
|
|
252
|
+
heavy text. Every resource that supports it takes a \`fields\` query param (a JSON field tree) that opts into exactly what you need. Passing nothing and then being surprised a field is
|
|
254
253
|
missing is a caller bug, not a server one — check the spec for the resource's own field vocabulary.
|
|
255
254
|
|
|
256
255
|
THE STALE-HASH RULE. A write that touches contested text (a card's title/description/checklists, a plan
|
package/dist/listen.js
CHANGED
|
@@ -323,6 +323,32 @@ export function formatNudgeLine(event) {
|
|
|
323
323
|
"Work these cards; any you cannot work, update to its true state: open a problem, add depends_on or " +
|
|
324
324
|
"conflict_on, block it with the real reason, or rollback_pickup.");
|
|
325
325
|
}
|
|
326
|
+
/** Why a reminder cannot be read, or `null` when it can. */
|
|
327
|
+
export function invalidReminderReason(value) {
|
|
328
|
+
if (!isRecord(value))
|
|
329
|
+
return "the reminder is not an object";
|
|
330
|
+
if (value.kind !== "policy_reminder")
|
|
331
|
+
return "kind is not policy_reminder";
|
|
332
|
+
if (typeof value.text !== "string" || value.text.trim() === "")
|
|
333
|
+
return "text is not a non-empty string";
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* The label every reminder carries, so the session can never read one as the operator speaking
|
|
338
|
+
* (DX-2955: "labelled unmistakably as automated system reminders, never phrased as the operator").
|
|
339
|
+
*/
|
|
340
|
+
export const REMINDER_LABEL = "AUTOMATED SYSTEM REMINDER from the danxbot dashboard monitor (not from the operator):";
|
|
341
|
+
/**
|
|
342
|
+
* The text of a reminder: the label, then the reminder as the dashboard wrote it. Unlike an
|
|
343
|
+
* activity line the body keeps its line breaks, because a reminder with something off is the
|
|
344
|
+
* numbered checklist plus what is off. Throws, naming the fault, on a malformed reminder.
|
|
345
|
+
*/
|
|
346
|
+
export function formatReminderLine(event) {
|
|
347
|
+
const invalid = invalidReminderReason(event);
|
|
348
|
+
if (invalid !== null)
|
|
349
|
+
throw new Error(`malformed reminder event: ${invalid}`);
|
|
350
|
+
return `${LINE_PREFIX} ${REMINDER_LABEL}\n${event.text.trim()}`;
|
|
351
|
+
}
|
|
326
352
|
/**
|
|
327
353
|
* Incremental SSE parser. Comment lines (keep-alives, the connect marker) and
|
|
328
354
|
* field-less blocks produce no message, which is what keeps them out of the output.
|
|
@@ -463,6 +489,25 @@ export async function runListener(options, deps) {
|
|
|
463
489
|
deps.write({ type: "event", id: null, text, origin: null });
|
|
464
490
|
return null;
|
|
465
491
|
}
|
|
492
|
+
if (message.event === "reminder") {
|
|
493
|
+
// DX-2955 - like a nudge: no usable id, never replayed, never deduplicated, and
|
|
494
|
+
// `origin: null` so `bridge.ts` delivers it immediately instead of folding it
|
|
495
|
+
// into a digest (the generic null-origin exemption in `routeEvent`).
|
|
496
|
+
let parsed;
|
|
497
|
+
let invalid;
|
|
498
|
+
try {
|
|
499
|
+
parsed = JSON.parse(message.data);
|
|
500
|
+
invalid = invalidReminderReason(parsed);
|
|
501
|
+
}
|
|
502
|
+
catch (err) {
|
|
503
|
+
invalid = `not JSON: ${err.message}`;
|
|
504
|
+
}
|
|
505
|
+
const text = invalid === null
|
|
506
|
+
? formatReminderLine(parsed)
|
|
507
|
+
: `${LINE_PREFIX} could not read reminder (${invalid}): ${oneLine(message.data, 300)}`;
|
|
508
|
+
deps.write({ type: "event", id: null, text, origin: null });
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
466
511
|
if (message.event !== "activity")
|
|
467
512
|
return null;
|
|
468
513
|
// `Number(null)` is 0, so a frame with no id must never be read as event 0: that id
|
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.211",
|
|
4
4
|
"description": "Stdio MCP server fronting danxbot's dashboard API for agents (operator sessions and dispatched workers alike): the generic danxbot_api/danxbot_api_list/danxbot_api_spec tools reach any route the caller's credential may call, plus dedicated agent-specific tools (plan_connect, danxbot_complete, and other per-dispatch lifecycle callbacks) (DX-3465, PLN-11 R-25).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|