@thehammer/danx-dashboard-mcp 0.1.172 → 0.1.173
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/background-work.js +34 -12
- package/dist/listen.js +8 -1
- package/package.json +1 -1
package/dist/background-work.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `danx-dashboard-mcp background-work <count|clear>` — the ONE-SHOT client of
|
|
2
|
+
* `danx-dashboard-mcp background-work <count|clear> <event-at>` — the ONE-SHOT client of
|
|
3
3
|
* `PUT /api/plan-sessions/me/background-work` (DX-3367).
|
|
4
4
|
*
|
|
5
5
|
* WHO RUNS IT. The danxbot Claude Code plugin's `Stop` / `SubagentStop` /
|
|
@@ -29,10 +29,15 @@
|
|
|
29
29
|
* no-op — `{"ok":false,"reason":"no_connection_record"}` — the plugin
|
|
30
30
|
* hook simply does not forward anything further in this case, exactly
|
|
31
31
|
* what "no-op when the session isn't plan-connected" means in practice;
|
|
32
|
-
* - on success, `{"ok":true,"count":<number|null>}`
|
|
33
|
-
*
|
|
34
|
-
* `
|
|
35
|
-
*
|
|
32
|
+
* - on success, `{"ok":true,"count":<number|null>,"applied":<boolean>}`
|
|
33
|
+
* echoes the SUBMITTED `count`; `applied` is the server's answer to
|
|
34
|
+
* whether it was stored (DX-3676: `false` for an out-of-order report
|
|
35
|
+
* older than the one already on file — the caller must not treat it as
|
|
36
|
+
* the dashboard's current count);
|
|
37
|
+
* - DX-3676 — `<event-at>` is the ISO-8601 UTC time the reporting HOOK
|
|
38
|
+
* fired, captured by the caller, never this process's own clock: the
|
|
39
|
+
* hooks are async and can finish out of order, and the server orders
|
|
40
|
+
* reports by this time;
|
|
36
41
|
* - human-readable diagnostics go to stderr only, never stdout.
|
|
37
42
|
*
|
|
38
43
|
* THE CREDENTIAL — the SAME resolver `bridge` and `plan-state` use, via
|
|
@@ -56,7 +61,7 @@ export const BACKGROUND_WORK_SUBCOMMAND = "background-work";
|
|
|
56
61
|
export const BACKGROUND_WORK_PATH = "/api/plan-sessions/me/background-work";
|
|
57
62
|
/** How long this one-shot call may take before it counts as a timeout. */
|
|
58
63
|
export const BACKGROUND_WORK_REQUEST_TIMEOUT_MS = 5_000;
|
|
59
|
-
const USAGE = `usage: CLAUDE_CODE_SESSION_ID=<session-id> danx-dashboard-mcp ${BACKGROUND_WORK_SUBCOMMAND} <non-negative-integer|clear>`;
|
|
64
|
+
const USAGE = `usage: CLAUDE_CODE_SESSION_ID=<session-id> danx-dashboard-mcp ${BACKGROUND_WORK_SUBCOMMAND} <non-negative-integer|clear> <event-at ISO-8601 UTC>`;
|
|
60
65
|
/**
|
|
61
66
|
* Parse the ONE positional argument: `clear`, or a non-negative integer
|
|
62
67
|
* string. Anything else is a usage error — never guessed or floored.
|
|
@@ -68,6 +73,15 @@ export function parseCountArg(raw) {
|
|
|
68
73
|
return { error: `count must be "clear" or a non-negative integer, got "${raw}"` };
|
|
69
74
|
return Number.parseInt(raw, 10);
|
|
70
75
|
}
|
|
76
|
+
/** DX-3676 — an ISO-8601 UTC instant, as `Date#toISOString` writes it (the server accepts exactly this). */
|
|
77
|
+
const ISO_UTC_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/;
|
|
78
|
+
/** Parse the event-time argument (DX-3676). Never substituted with this process's clock. */
|
|
79
|
+
export function parseEventAtArg(raw) {
|
|
80
|
+
if (!ISO_UTC_INSTANT.test(raw) || Number.isNaN(Date.parse(raw))) {
|
|
81
|
+
return { error: `event-at must be an ISO-8601 UTC timestamp (e.g. 2026-09-30T00:00:00.000Z), got "${raw}"` };
|
|
82
|
+
}
|
|
83
|
+
return raw;
|
|
84
|
+
}
|
|
71
85
|
/**
|
|
72
86
|
* One authenticated PUT, with a hard timeout, classified into the output
|
|
73
87
|
* shape this subcommand always prints — never a throw, never a non-2xx
|
|
@@ -81,8 +95,8 @@ export function parseCountArg(raw) {
|
|
|
81
95
|
* (no `409 session_not_connected` equivalent), so status alone decides
|
|
82
96
|
* whether a body read is even attempted.
|
|
83
97
|
*/
|
|
84
|
-
export async function putBackgroundWork(options,
|
|
85
|
-
const sent = await sendSessionRequest(options, BACKGROUND_WORK_PATH, { method: "PUT", body: JSON.stringify({ count }) }, deps);
|
|
98
|
+
export async function putBackgroundWork(options, report, deps) {
|
|
99
|
+
const sent = await sendSessionRequest(options, BACKGROUND_WORK_PATH, { method: "PUT", body: JSON.stringify({ count: report.count, eventAt: report.eventAt }) }, deps);
|
|
86
100
|
if ("reason" in sent)
|
|
87
101
|
return sent;
|
|
88
102
|
const { status, text } = sent;
|
|
@@ -99,10 +113,12 @@ export async function putBackgroundWork(options, count, deps) {
|
|
|
99
113
|
if (typeof body !== "object" ||
|
|
100
114
|
body === null ||
|
|
101
115
|
!("count" in body) ||
|
|
102
|
-
(body.count !== null && typeof body.count !== "number")
|
|
116
|
+
(body.count !== null && typeof body.count !== "number") ||
|
|
117
|
+
typeof body.applied !== "boolean") {
|
|
103
118
|
return { ok: false, reason: "bad_response" };
|
|
104
119
|
}
|
|
105
|
-
|
|
120
|
+
const shaped = body;
|
|
121
|
+
return { ok: true, count: shaped.count, applied: shaped.applied };
|
|
106
122
|
}
|
|
107
123
|
/** The bin's `background-work` subcommand, wired to the real process. Always resolves to exit code 0. */
|
|
108
124
|
export async function runBackgroundWorkCommand(argv, env = process.env,
|
|
@@ -111,7 +127,7 @@ resolveFrom = {}) {
|
|
|
111
127
|
const write = (output) => {
|
|
112
128
|
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
113
129
|
};
|
|
114
|
-
if (argv.length !==
|
|
130
|
+
if (argv.length !== 2) {
|
|
115
131
|
write({ ok: false, reason: "usage" });
|
|
116
132
|
process.stderr.write(`${USAGE}\n`);
|
|
117
133
|
return 0;
|
|
@@ -123,6 +139,12 @@ resolveFrom = {}) {
|
|
|
123
139
|
return 0;
|
|
124
140
|
}
|
|
125
141
|
const count = parsed;
|
|
142
|
+
const eventAt = parseEventAtArg(argv[1]);
|
|
143
|
+
if (typeof eventAt === "object") {
|
|
144
|
+
write({ ok: false, reason: "usage" });
|
|
145
|
+
process.stderr.write(`${eventAt.error}\n${USAGE}\n`);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
126
148
|
const resolved = await resolveSessionOptions(env, resolveFrom, USAGE);
|
|
127
149
|
if (!resolved.ok) {
|
|
128
150
|
// A session that never `plan_connect`-ed has no connection record — this
|
|
@@ -132,7 +154,7 @@ resolveFrom = {}) {
|
|
|
132
154
|
process.stderr.write(`${resolved.detail}\n`);
|
|
133
155
|
return 0;
|
|
134
156
|
}
|
|
135
|
-
const output = await putBackgroundWork(resolved.options, count, {
|
|
157
|
+
const output = await putBackgroundWork(resolved.options, { count, eventAt }, {
|
|
136
158
|
fetch: (input, init) => fetch(input, init),
|
|
137
159
|
requestTimeoutMs: BACKGROUND_WORK_REQUEST_TIMEOUT_MS,
|
|
138
160
|
});
|
package/dist/listen.js
CHANGED
|
@@ -284,6 +284,11 @@ function cardList(cards) {
|
|
|
284
284
|
* this signal cannot support. See `evaluateIdleNudge`'s own doc comment
|
|
285
285
|
* (`src/issues/db/session-idle-nudge.ts`) for why a sub-agent-awareness
|
|
286
286
|
* special case was rejected instead of this wording fix.
|
|
287
|
+
*
|
|
288
|
+
* DX-3676 — every named card clears every dispatch gate, so if the session
|
|
289
|
+
* still cannot work one, the card's recorded state is wrong (DX-3400 sat in
|
|
290
|
+
* ToDo with its real blocker only in a comment). The line therefore ends by
|
|
291
|
+
* naming each state-correcting move, which is also what stops the nudge.
|
|
287
292
|
*/
|
|
288
293
|
export function formatNudgeLine(event) {
|
|
289
294
|
const invalid = invalidNudgeReason(event);
|
|
@@ -294,7 +299,9 @@ export function formatNudgeLine(event) {
|
|
|
294
299
|
parts.push(`startable: ${cardList(event.startable)}`);
|
|
295
300
|
if (event.held.length > 0)
|
|
296
301
|
parts.push(`held: ${cardList(event.held)}`);
|
|
297
|
-
return oneLine(`${LINE_PREFIX} this session has not made an MCP call in ${event.idleMinutes}m — ${parts.join("; ")}`
|
|
302
|
+
return oneLine(`${LINE_PREFIX} this session has not made an MCP call in ${event.idleMinutes}m — ${parts.join("; ")}. ` +
|
|
303
|
+
"Work these cards; any you cannot work, update to its true state: open a problem, add depends_on or " +
|
|
304
|
+
"conflict_on, block it with the real reason, or rollback_pickup.");
|
|
298
305
|
}
|
|
299
306
|
/**
|
|
300
307
|
* Incremental SSE parser. Comment lines (keep-alives, the connect marker) and
|
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.173",
|
|
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",
|