@thehammer/danx-dashboard-mcp 0.1.300 → 0.1.301

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.
Files changed (2) hide show
  1. package/dist/listen.js +16 -9
  2. package/package.json +1 -1
package/dist/listen.js CHANGED
@@ -11,11 +11,10 @@
11
11
  * - `{type:"event", id, text}` — exactly one per event, the moment it arrives.
12
12
  * `text` is what the session reads; an event it cannot read still produces one
13
13
  * (`could not read event …`), never silence. `id` is `null` only for a frame
14
- * that carried no usable id — which includes DX-2885's `nudge` frame
15
- * (`formatNudgeLine`), DX-4340's `pacing` frame (`formatPacingLine`) and
16
- * DX-4342's `resume` frame (`formatResumeLine`): all are advisory, written fresh by the dashboard's own keep-alive tick,
17
- * and never replayed, so they ride this same shape with `id: null` rather
18
- * than growing a THIRD output variant.
14
+ * that carried no usable id. DX-2885's `nudge` frame (`formatNudgeLine`), DX-4340's `pacing` frame (`formatPacingLine`) and
15
+ * DX-4342's `resume` frame (`formatResumeLine`) are advisory and ride this same shape rather than growing a THIRD output
16
+ * variant. DX-5007: the dashboard stores each with an id and replays it until the id is reported, so they carry their id like
17
+ * an activity line (an id-less one, from an older dashboard, carries `id: null`).
19
18
  * - `{type:"stopped", reason, detail}` — once, last. `reason`
20
19
  * is the dashboard's own end reason (`superseded`, `replaced`, `revoked`,
21
20
  * `not_connected`), `refused` (the ticket was not admitted), or
@@ -492,9 +491,10 @@ export async function runListener(options, deps) {
492
491
  return code;
493
492
  }
494
493
  /**
495
- * The shared path of an ADVISORY frame (DX-2885 `nudge`, DX-4340 `pacing`): it carries no usable id (re-derived or written fresh by the
496
- * dashboard's keep-alive tick, never replayed - see `plan-session-stream.ts`'s module doc), so it rides the SAME `{type:"event", id:null, text}`
497
- * shape an ordinary activity line uses. That is what lets the relay (`plan-events-relay.ts`) forward it with no change: it forwards any
494
+ * The shared path of an ADVISORY frame (DX-2885 `nudge`, DX-4340 `pacing`, DX-4342 `resume`): the dashboard stores each with an id (DX-5007,
495
+ * `plan-session-stream.ts`'s module doc), so it is deduplicated and remembered by that id exactly like an activity event: the id is reported as
496
+ * `Last-Event-ID` on reconnect, which is what stops the dashboard replaying a frame this reader already read. It rides the SAME
497
+ * `{type:"event", id, text}` shape an ordinary activity line uses. That is what lets the relay (`plan-events-relay.ts`) forward it with no change: it forwards any
498
498
  * `{type:"event", id, text}` record, keyed only on `type`.
499
499
  *
500
500
  * `origin: null` is DX-2730 D4's exemption: the frame is delivered at once, never held for a digest flush (a nudge exists to interrupt a quiet
@@ -511,10 +511,17 @@ export async function runListener(options, deps) {
511
511
  catch (err) {
512
512
  invalid = `not JSON: ${err.message}`;
513
513
  }
514
+ // `Number(null)` is 0: a frame with no id must never be read as id 0 (see the activity path below).
515
+ const id = message.id === null ? Number.NaN : Number(message.id);
516
+ const knownId = Number.isSafeInteger(id) && id > 0;
517
+ if (knownId && delivered.has(id))
518
+ return null;
514
519
  const text = invalid === null ? format(parsed) : `${LINE_PREFIX} could not read ${what} (${invalid}): ${oneLine(message.data, 300)}`;
515
520
  // DX-4721: an unreadable frame is a fault line, never the frame it failed to be (a malformed `critical` pacing frame is not a stop).
516
521
  const urgent = isUrgent(invalid === null ? sourceOf(parsed) : { source: "fault" });
517
- deps.write({ type: "event", id: null, text, origin: null, urgent, ...(scope === undefined ? {} : { scope }) });
522
+ deps.write({ type: "event", id: knownId ? id : null, text, origin: null, urgent, ...(scope === undefined ? {} : { scope }) });
523
+ if (knownId)
524
+ remember(id);
518
525
  return null;
519
526
  };
520
527
  const handle = (message) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-dashboard-mcp",
3
- "version": "0.1.300",
3
+ "version": "0.1.301",
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, request_permission, attach_file, and danxbot_slack_reply) (DX-3465, PLN-11 R-25).",
5
5
  "license": "MIT",
6
6
  "type": "module",