@thehammer/danx-dashboard-mcp 0.1.206 → 0.1.208

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.
@@ -18,8 +18,8 @@
18
18
  * project connected a plan, or the plan is archived/deleted, or the record is
19
19
  * stale. The plugin stays silent, as PLN-11 R-10 requires of a project that
20
20
  * never connected a plan.
21
- * - exit 1, reason on stderr: the lookup itself failed (credential, network,
22
- * non-2xx, bad shape). Never silent: the hook prints a could-not-load notice.
21
+ * - exit 1, reasons on stderr: NO candidate answered (credential, network,
22
+ * non-2xx, bad shape, for every one). Never silent: the hook prints a could-not-load notice.
23
23
  *
24
24
  * The credential is the PREDECESSOR's own record's source, resolved through the
25
25
  * same resolver the bridge uses, so the lookup reaches the dashboard that
@@ -112,6 +112,10 @@ resolveFrom = {}) {
112
112
  return 1;
113
113
  }
114
114
  const candidates = findPredecessorCandidates(projectKeyOf(cwd), sessionId, resolveFrom).slice(0, RESTART_NOTICE_MAX_CANDIDATES);
115
+ // One candidate failing (its credential moved, its dashboard is down) must not hide a LATER candidate that
116
+ // would answer: keep going, and report failure only when no candidate answered at all.
117
+ const failures = [];
118
+ let answered = 0;
115
119
  for (const predecessor of candidates) {
116
120
  let options;
117
121
  try {
@@ -119,8 +123,8 @@ resolveFrom = {}) {
119
123
  }
120
124
  catch (err) {
121
125
  const start = err;
122
- process.stderr.write(`${start.reason}: ${start.message}. Fix: ${start.fix}.\n`);
123
- return 1;
126
+ failures.push(`${start.reason}: ${start.message}. Fix: ${start.fix}.`);
127
+ continue;
124
128
  }
125
129
  const output = await fetchRestartNotice({
126
130
  dashboardUrl: options.dashboardUrl,
@@ -129,13 +133,18 @@ resolveFrom = {}) {
129
133
  askingSessionId: sessionId,
130
134
  }, { fetch: (input, init) => fetch(input, init), requestTimeoutMs: RESTART_NOTICE_REQUEST_TIMEOUT_MS });
131
135
  if (!output.ok) {
132
- process.stderr.write(`${output.reason}: could not ask the dashboard what the previous session of this project was working\n`);
133
- return 1;
136
+ failures.push(`${output.reason}: could not ask the dashboard what session ${predecessor.sessionId} was working`);
137
+ continue;
134
138
  }
139
+ answered += 1;
135
140
  if (output.text !== null) {
136
141
  process.stdout.write(output.text);
137
142
  return 0;
138
143
  }
139
144
  }
145
+ if (answered === 0 && failures.length > 0) {
146
+ process.stderr.write(`no candidate answered (${failures.length} of ${candidates.length} failed):\n${failures.join("\n")}\n`);
147
+ return 1;
148
+ }
140
149
  return 0;
141
150
  }
@@ -1,12 +1,13 @@
1
1
  const TERMS_ACCEPTANCE_PATH = "/api/account/terms-acceptance";
2
2
  // Mirrors `termsAcceptUrl("/")` in src/lib/terms-accept-path.ts (a published package cannot import it);
3
3
  // terms-gate.integration.test.ts pins the server's link to the same literal. Only meaningful for an
4
- // operator session: a dispatch's DANXBOT_DASHBOARD_URL is internal, and agent credentials are never terms-gated.
4
+ // operator session: a dispatch's DANXBOT_DASHBOARD_URL is internal, and a dispatch's own agent credential is never terms-gated.
5
5
  const ACCEPT_SCREEN_PATH = "/terms/accept?return=%2F";
6
6
  /** Keep in step with `termsRefusalInstruction` in src/dashboard/route-policy.ts. */
7
- export function haltText(acceptUrl) {
8
- return ("STOP ALL WORK NOW. The dashboard refuses your access until the person you act for accepts the " +
9
- "current Terms of Use.\n\n" +
7
+ export function haltText(acceptUrl, owner) {
8
+ return ("STOP ALL WORK NOW. The dashboard refuses your access until " +
9
+ (owner === undefined ? "the person you act for" : `${owner}, the user you act for,`) +
10
+ " accepts the current Terms of Use.\n\n" +
10
11
  `Give the person this link to accept them: ${acceptUrl}\n\n` +
11
12
  "Do not retry, do not look for another route, and never accept the Terms yourself. " +
12
13
  "A dispatched agent ends with danxbot_complete({status: \"failed\", summary}) naming this link, " +
@@ -22,7 +23,10 @@ export function termsHaltFor(result) {
22
23
  if (typeof body.acceptUrl !== "string") {
23
24
  throw new Error("[danx-dashboard-mcp] a terms_not_accepted refusal carried no acceptUrl");
24
25
  }
25
- return haltText(body.acceptUrl);
26
+ if (typeof body.owner !== "string") {
27
+ throw new Error("[danx-dashboard-mcp] a terms_not_accepted refusal carried no owner");
28
+ }
29
+ return haltText(body.acceptUrl, body.owner);
26
30
  }
27
31
  /** The refusal for a call that would accept the Terms (never an agent's act), or null for any other call. */
28
32
  export function termsAcceptanceCallHalt(args, dashboardUrl) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-dashboard-mcp",
3
- "version": "0.1.206",
3
+ "version": "0.1.208",
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",