@thehammer/danx-dashboard-mcp 0.1.301 → 0.1.303

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.
@@ -1,5 +1,6 @@
1
1
  import { boardStampOf } from "./route-board-scope.js";
2
2
  import { assertVersionFloorSatisfied, MCP_MIN_VERSION_HEADER } from "./version-floor.js";
3
+ import { PLUGIN_BACKGROUND_HEADER } from "./session-options.js";
3
4
  export class DashboardHttpClient {
4
5
  config;
5
6
  fetchImpl;
@@ -17,6 +18,14 @@ export class DashboardHttpClient {
17
18
  setToken(token) {
18
19
  this.config.token = token;
19
20
  }
21
+ /**
22
+ * DX-5076 - the ONE entry for a request this process makes on its own (the listener's health read, the key-permission read, the permission claim
23
+ * poll): it is never the agent acting, so it carries the background mark and ends no agent pause. A call the agent makes (`danxbot_api`, a
24
+ * permission-request create) goes through `request` instead. No call site sets `background` by hand.
25
+ */
26
+ requestOwn(args) {
27
+ return this.request({ ...args, background: true });
28
+ }
20
29
  async request(args) {
21
30
  if (this.config.token === "") {
22
31
  // DX-4390 — a caller reaches here only past the sign-in halt; a bearer-less call is a bug.
@@ -51,7 +60,7 @@ export class DashboardHttpClient {
51
60
  headers["x-danx-session-id"] = this.config.session.id;
52
61
  }
53
62
  if (args.background === true) {
54
- headers["x-danx-plugin-background"] = "1";
63
+ headers[PLUGIN_BACKGROUND_HEADER] = "1";
55
64
  }
56
65
  let bodyString;
57
66
  if (args.body !== undefined) {
package/dist/index.js CHANGED
@@ -217,11 +217,12 @@ function boot() {
217
217
  permissionRequests = new PermissionRequests({
218
218
  access,
219
219
  request: (args) => dashboardClient.request(args),
220
+ requestOwn: (args) => dashboardClient.requestOwn(args),
220
221
  log: (line) => console.error(line),
221
222
  });
222
223
  listenerReminder = createListenerReminder({
223
224
  sessionId: config.session?.id,
224
- fetchHealth: () => dashboardClient.request({ method: "GET", basePath: "", path: "/api/plans", query: { limit: 1 } }),
225
+ fetchHealth: () => dashboardClient.requestOwn({ method: "GET", basePath: "", path: "/api/plans", query: { limit: 1 } }),
225
226
  isPlanConnected: isPlanConnectedOnThisMachine,
226
227
  now: Date.now,
227
228
  logLine: (line) => console.error(line),
@@ -270,7 +271,8 @@ function boot() {
270
271
  async function readKeyPermissions() {
271
272
  if (!access.isSignedIn())
272
273
  return { outcome: "no-key" };
273
- const guarded = await access.guard(() => client.request({ method: "GET", basePath: "", path: "/api/auth/me" }));
274
+ // DX-5076: this process reading its own key's permissions is not the agent acting.
275
+ const guarded = await access.guard(() => client.requestOwn({ method: "GET", basePath: "", path: "/api/auth/me" }));
274
276
  if ("halt" in guarded)
275
277
  return { outcome: "no-key" };
276
278
  const { result } = guarded;
@@ -96,7 +96,7 @@ export class PermissionRequests {
96
96
  let guarded;
97
97
  try {
98
98
  // `guard` runs before EVERY claim (DX-4418): a revoked or signed-out session answers its halt without a request.
99
- guarded = await this.deps.access.guard(() => this.deps.request({ method: "POST", basePath: PERMISSION_REQUESTS_BASE_PATH, path: `/${request.publicId}/claim` }));
99
+ guarded = await this.deps.access.guard(() => this.deps.requestOwn({ method: "POST", basePath: PERMISSION_REQUESTS_BASE_PATH, path: `/${request.publicId}/claim` }));
100
100
  }
101
101
  catch (err) {
102
102
  // An outdated MCP will never get a different answer; any other failure is retried until the request ends.
@@ -40,6 +40,7 @@ export const GET_ROUTE_BOARD_SCOPE = [
40
40
  ["/api/platform/teams", "refuse"],
41
41
  ["/api/reminders", "refuse"],
42
42
  ["/api/repos", "refuse"],
43
+ ["/api/security-incidents", "refuse"],
43
44
  ["/api/self-repair/errors", "refuse"],
44
45
  ["/api/sync-root", "refuse"],
45
46
  ["/api/tasks", "refuse"],
@@ -10,6 +10,8 @@ import { credentialFingerprint, describeCredentialSource, readCredential } from
10
10
  import { readSessionConnection } from "./session-connection.js";
11
11
  import { fixForStop } from "./stop-fixes.js";
12
12
  export const SESSION_ID_HEADER = "x-danx-session-id";
13
+ /** DX-5033 / DX-5076 - marks a request as this process's own background work (not the agent acting): the dashboard ends no agent pause on it. */
14
+ export const PLUGIN_BACKGROUND_HEADER = "x-danx-plugin-background";
13
15
  /** A start this process cannot make, named the way the session will be told about it. */
14
16
  export class SessionStartError extends Error {
15
17
  // `ListenStopReason`, not `string`: a start-time failure is always one of `no_connection_record` / `credential_unavailable`
@@ -10,7 +10,7 @@ import { errorCodeOf } from "./json-body.js";
10
10
  import { boundRequest } from "./request-bound.js";
11
11
  import { keyRevocationOf, keyRevokedHalt } from "./key-revoked-halt.js";
12
12
  import { oneLine } from "./one-line.js";
13
- import { SESSION_ID_HEADER } from "./session-options.js";
13
+ import { PLUGIN_BACKGROUND_HEADER, SESSION_ID_HEADER } from "./session-options.js";
14
14
  import { isClaimState } from "@thehammer/danx-session-telemetry";
15
15
  /**
16
16
  * DX-3912 — the longest heartbeat `reason` the relay sends: one under the dashboard's own
@@ -74,6 +74,8 @@ async function request(options, deps, what, url, init = { method: "GET" }) {
74
74
  Authorization: `Bearer ${options.token}`,
75
75
  Accept: "application/json",
76
76
  [SESSION_ID_HEADER]: options.sessionId,
77
+ // DX-5076: every request this module makes is the relay's own work (ticket mint, inventory read, heartbeat), never the agent acting, so it must not end an agent pause. One marking point, so a new request here cannot forget it.
78
+ [PLUGIN_BACKGROUND_HEADER]: "1",
77
79
  };
78
80
  if (init.body !== undefined)
79
81
  headers["Content-Type"] = "application/json";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-dashboard-mcp",
3
- "version": "0.1.301",
3
+ "version": "0.1.303",
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",