@thehammer/danx-dashboard-mcp 0.1.186 → 0.1.187

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/activity.js +26 -4
  2. package/package.json +2 -2
package/dist/activity.js CHANGED
@@ -22,7 +22,16 @@
22
22
  * and the transcript producer (`createActivityObserver`) keys its row on that file's
23
23
  * basename, `agent-<agent_id>`. Reporting the bare `agent_id` would upsert a SECOND row for
24
24
  * the same sub-agent, so the hook-side key is the same basename: the two producers converge
25
- * on one row. (`transcript_path` cannot supply it: on these events it is the MAIN session's
25
+ * on one row. The hooks docs disagree on whether `agent_id` already carries the `agent-`
26
+ * prefix, so {@link subagentActivityId} normalizes both forms to the one key.
27
+ *
28
+ * KNOWN LIMITS (DX-3284, pinned in `plan-session-activity.test.ts`):
29
+ * - a sub-agent RESUMED after its SubagentStop reports a second start, but the server's
30
+ * first finish wins, so the row stays closed;
31
+ * - a SubagentStop with no `agent_id` (Claude Code's internal agents) is refused below, and
32
+ * the plugin leaves a failure trace. One WITH an id but no recorded start is
33
+ * indistinguishable from a stop that beat its (async) start, so it is recorded as an
34
+ * already-finished row — it never counts as running. (`transcript_path` cannot supply it: on these events it is the MAIN session's
26
35
  * transcript — only `SubagentStop`'s `agent_transcript_path` names the sub-agent's own, and
27
36
  * it is used below to REFUSE a mismatch, never to guess one.)
28
37
  *
@@ -62,9 +71,19 @@ export const ACTIVITY_REQUEST_TIMEOUT_MS = 5_000;
62
71
  /** The hook events this subcommand accepts, exactly as Claude Code names them in `hook_event_name`. */
63
72
  export const ACTIVITY_HOOK_EVENTS = ["SubagentStart", "SubagentStop", "PostToolUse"];
64
73
  const USAGE = `usage: CLAUDE_CODE_SESSION_ID=<session-id> danx-dashboard-mcp ${ACTIVITY_SUBCOMMAND} <${ACTIVITY_HOOK_EVENTS.join("|")}> <event-at ISO-8601 UTC> (the hook's JSON envelope on stdin)`;
65
- /** A sub-agent's transcript file basename — the key `createActivityObserver` reports it under. */
74
+ const SUBAGENT_PREFIX = "agent-";
75
+ /**
76
+ * A sub-agent's transcript file basename — the key `createActivityObserver` reports it under.
77
+ *
78
+ * DX-3284: the hooks documentation shows `agent_id` BOTH ways — SubagentStart's example carries
79
+ * the `agent-` prefix (`agent-abc123`), SubagentStop's does not (`def456`, against the file
80
+ * `agent-def456.jsonl`). The key is `agent-` + the id with ONE leading `agent-` stripped, so both
81
+ * forms converge on the transcript producer's row; keying on the raw id would leave a phantom
82
+ * `agent-agent-<id>` row that no stop ever closes.
83
+ */
66
84
  export function subagentActivityId(agentId) {
67
- return `agent-${agentId}`;
85
+ const bare = agentId.startsWith(SUBAGENT_PREFIX) ? agentId.slice(SUBAGENT_PREFIX.length) : agentId;
86
+ return `${SUBAGENT_PREFIX}${bare}`;
68
87
  }
69
88
  function nonEmptyString(value) {
70
89
  return typeof value === "string" && value !== "";
@@ -107,7 +126,10 @@ export function activityChangeFromHook(event, envelope, eventAtMs) {
107
126
  },
108
127
  };
109
128
  }
110
- if (!nonEmptyString(e.agent_id))
129
+ // A SubagentStop from one of Claude Code's own internal agents carries no `agent_id`: it names
130
+ // no activity, so it is refused here (the plugin leaves a failure trace) and nothing is
131
+ // written — a stop must never invent a row.
132
+ if (!nonEmptyString(e.agent_id) || e.agent_id === SUBAGENT_PREFIX)
111
133
  return { ok: false, reason: "no_agent_id" };
112
134
  const activityId = subagentActivityId(e.agent_id);
113
135
  if (event === "SubagentStop" && e.agent_transcript_path !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/danx-dashboard-mcp",
3
- "version": "0.1.186",
3
+ "version": "0.1.187",
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",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@modelcontextprotocol/sdk": "1.29.0",
34
- "@thehammer/danx-session-telemetry": "0.1.18",
34
+ "@thehammer/danx-session-telemetry": "0.1.19",
35
35
  "zod": "^3.25.76"
36
36
  },
37
37
  "devDependencies": {