@leo000001/claude-code-mcp 2.4.3 → 2.4.8

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/CHANGELOG.md CHANGED
@@ -8,6 +8,8 @@
8
8
 
9
9
  ### Improvements
10
10
 
11
+ - Upgrade `@anthropic-ai/claude-agent-sdk` to `^0.2.49` and align MCP-facing schemas with the current SDK surface.
12
+ - Permission mode enum now follows SDK 0.2.49 (`default`, `acceptEdits`, `bypassPermissions`, `plan`, `dontAsk`; `delegate` removed).
11
13
  - Session cleanup now marks timed-out running/waiting sessions as `cancelled` for consistent status semantics.
12
14
  - `SessionManager.destroy()` now clears in-memory session/runtime maps after aborting active runs, so post-destroy reads are no longer stale.
13
15
  - Event buffer eviction now uses batch compaction (instead of repeated `findIndex` + `splice`) and `readEvents` now uses binary search for cursor start.
@@ -15,9 +17,13 @@
15
17
  - Runtime tool-discovery updates now notify both tools and resources (internal-tools resource change notification).
16
18
  - Enrich compatibility resources with package version, disk-resume diagnostics, and runtime limits.
17
19
  - Remove deprecated `claude_code` parameter aliases: top-level `sessionInitTimeoutMs` and `advanced.effort` / `advanced.thinking`.
20
+ - Add support for SDK `promptSuggestions` option passthrough and expose `promptSuggestions` in `advanced`/`diskResumeConfig`.
21
+ - Query consumer now maps additional SDK stream messages (`system/task_started`, `rate_limit`, `prompt_suggestion`) to progress events.
18
22
 
19
23
  ### Documentation
20
24
 
25
+ - Restructure documentation architecture: `AGENTS.md` is now execution-first, while `docs/DESIGN.md` is the single detailed source for interface/mapping semantics.
26
+ - Add explicit doc-governance rules, upgrade submission template, and document DoD to reduce AGENTS/DESIGN duplication regression.
21
27
  - Align README/DESIGN/AGENTS with current defaults and behavior (timeout clamp, advanced parameter count, lifecycle semantics).
22
28
  - Clarify package positioning as CLI-first and remove stale guidance that implied a public programmatic API surface.
23
29
  - Update CONTRIBUTING with local environment requirements (Node/npm and Windows Git Bash notes).
package/README.md CHANGED
@@ -117,7 +117,7 @@ Start a new Claude Code session. The agent autonomously performs coding tasks: r
117
117
  | `advanced` | object | No | Advanced/low-frequency parameters (see below) |
118
118
 
119
119
  <details>
120
- <summary><code>advanced</code> object parameters (20 low-frequency parameters)</summary>
120
+ <summary><code>advanced</code> object parameters (21 low-frequency parameters)</summary>
121
121
 
122
122
  | Parameter | Type | Description |
123
123
  | ------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -136,6 +136,7 @@ Start a new Claude Code session. The agent autonomously performs coding tasks: r
136
136
  | `advanced.fallbackModel` | string | Fallback model if the primary model fails or is unavailable. Default: none |
137
137
  | `advanced.enableFileCheckpointing` | boolean | Enable file checkpointing to track file changes during the session. Default: `false` |
138
138
  | `advanced.includePartialMessages` | boolean | When true, includes intermediate streaming messages in the response. Useful for real-time progress monitoring. Default: false |
139
+ | `advanced.promptSuggestions` | boolean | When true, emits post-turn prompt suggestion events (`prompt_suggestion`). Default: `false` |
139
140
  | `advanced.strictMcpConfig` | boolean | Enforce strict validation of MCP server configurations. Default: `false` |
140
141
  | `advanced.settingSources` | string[] | Which filesystem settings to load. Defaults to `["user", "project", "local"]` (loads all settings and CLAUDE.md). Pass `[]` for SDK isolation mode |
141
142
  | `advanced.debug` | boolean | Enable debug mode for verbose logging. Default: `false` |
@@ -177,7 +178,7 @@ Continue an existing session by sending a follow-up message. The agent retains f
177
178
  | `diskResumeConfig` | object | No | Disk resume parameters (see below). Used when `CLAUDE_CODE_MCP_ALLOW_DISK_RESUME=1` and in-memory session is missing |
178
179
 
179
180
  <details>
180
- <summary><code>diskResumeConfig</code> object parameters (28 disk-resume-only parameters)</summary>
181
+ <summary><code>diskResumeConfig</code> object parameters (31 disk-resume-only parameters)</summary>
181
182
 
182
183
  | Parameter | Type | Description |
183
184
  | --------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------- |
@@ -185,6 +186,7 @@ Continue an existing session by sending a follow-up message. The agent retains f
185
186
  | `diskResumeConfig.cwd` | string | Working directory. Required for disk resume. |
186
187
  | `diskResumeConfig.allowedTools` | string[] | Auto-approved tool names (see `claude_code`). Default: `[]` |
187
188
  | `diskResumeConfig.disallowedTools` | string[] | Forbidden tool names (see `claude_code`). Default: `[]` |
189
+ | `diskResumeConfig.strictAllowedTools` | boolean | Enforce strict allow-list behavior for `allowedTools`. Default: `false` |
188
190
  | `diskResumeConfig.tools` | string[] \| object | Base tool set (see `claude_code`). Default: SDK/Claude Code default |
189
191
  | `diskResumeConfig.persistSession` | boolean | Persist session history to disk. Default: `true` |
190
192
  | `diskResumeConfig.maxTurns` | number | Maximum number of agent reasoning steps. Default: SDK/Claude Code default |
@@ -205,6 +207,7 @@ Continue an existing session by sending a follow-up message. The agent retains f
205
207
  | `diskResumeConfig.fallbackModel` | string | Fallback model. Default: none |
206
208
  | `diskResumeConfig.enableFileCheckpointing` | boolean | Enable file checkpointing. Default: `false` |
207
209
  | `diskResumeConfig.includePartialMessages` | boolean | Include intermediate streaming messages. Default: `false` |
210
+ | `diskResumeConfig.promptSuggestions` | boolean | Emit post-turn prompt suggestion events (`prompt_suggestion`). Default: `false` |
208
211
  | `diskResumeConfig.strictMcpConfig` | boolean | Strict MCP config validation. Default: `false` |
209
212
  | `diskResumeConfig.settingSources` | string[] | Which filesystem settings to load. Default: `["user", "project", "local"]` |
210
213
  | `diskResumeConfig.debug` | boolean | Debug mode. Default: `false` |
package/dist/index.js CHANGED
@@ -232,6 +232,7 @@ var SessionManager = class _SessionManager {
232
232
  fallbackModel: params.fallbackModel,
233
233
  enableFileCheckpointing: params.enableFileCheckpointing,
234
234
  includePartialMessages: params.includePartialMessages,
235
+ promptSuggestions: params.promptSuggestions,
235
236
  strictMcpConfig: params.strictMcpConfig,
236
237
  settingSources: params.settingSources,
237
238
  debug: params.debug,
@@ -328,7 +329,9 @@ var SessionManager = class _SessionManager {
328
329
  if (info.status === "waiting_permission") {
329
330
  this.finishAllPending(
330
331
  sessionId,
331
- { behavior: "deny", message: opts?.reason ?? "Session interrupted", interrupt: true },
332
+ // Similar to cancel(), avoid emitting interrupt=true while the query stream is
333
+ // being torn down to reduce SDK-level write/teardown races on stdio clients.
334
+ { behavior: "deny", message: opts?.reason ?? "Session interrupted", interrupt: false },
332
335
  "interrupt"
333
336
  );
334
337
  }
@@ -1236,6 +1239,26 @@ function messageToEvent(msg) {
1236
1239
  }
1237
1240
  };
1238
1241
  }
1242
+ if (msg.type === "system" && msg.subtype === "task_started") {
1243
+ return {
1244
+ type: "progress",
1245
+ data: {
1246
+ type: "task_started",
1247
+ task_id: msg.task_id,
1248
+ tool_use_id: msg.tool_use_id,
1249
+ description: msg.description,
1250
+ task_type: msg.task_type
1251
+ }
1252
+ };
1253
+ }
1254
+ if (msg.type === "rate_limit" || msg.type === "prompt_suggestion") {
1255
+ const rest = { ...msg };
1256
+ delete rest.type;
1257
+ return {
1258
+ type: "progress",
1259
+ data: { type: msg.type, ...rest }
1260
+ };
1261
+ }
1239
1262
  return null;
1240
1263
  }
1241
1264
  function consumeQuery(params) {
@@ -1401,6 +1424,7 @@ function consumeQuery(params) {
1401
1424
  let retryCount = 0;
1402
1425
  let currentStream = activeQuery;
1403
1426
  while (true) {
1427
+ let streamReceivedResult = false;
1404
1428
  try {
1405
1429
  for await (const message of currentStream) {
1406
1430
  if (isSystemInitMessage(message)) {
@@ -1441,6 +1465,7 @@ function consumeQuery(params) {
1441
1465
  continue;
1442
1466
  }
1443
1467
  if (message.type === "result") {
1468
+ streamReceivedResult = true;
1444
1469
  const sessionId2 = message.session_id ?? await getSessionId();
1445
1470
  const agentResult = sdkResultToAgentResult(message);
1446
1471
  const current = params.sessionManager.get(sessionId2);
@@ -1483,7 +1508,7 @@ function consumeQuery(params) {
1483
1508
  queryInterrupt: void 0
1484
1509
  });
1485
1510
  }
1486
- return;
1511
+ continue;
1487
1512
  }
1488
1513
  const sessionId = message.session_id ?? await getSessionId();
1489
1514
  const event = messageToEvent(message);
@@ -1501,7 +1526,7 @@ function consumeQuery(params) {
1501
1526
  `Error [${"INTERNAL" /* INTERNAL */}]: query stream ended before receiving session init.`
1502
1527
  )
1503
1528
  );
1504
- } else if (activeSessionId) {
1529
+ } else if (activeSessionId && !streamReceivedResult) {
1505
1530
  const sessionId = activeSessionId;
1506
1531
  const current = params.sessionManager.get(sessionId);
1507
1532
  if (current && current.status !== "cancelled") {
@@ -1548,6 +1573,9 @@ function consumeQuery(params) {
1548
1573
  );
1549
1574
  return;
1550
1575
  }
1576
+ if (streamReceivedResult) {
1577
+ return;
1578
+ }
1551
1579
  if (!activeSessionId) return;
1552
1580
  const sessionId = activeSessionId;
1553
1581
  if (errClass === "transient" && retryCount < MAX_TRANSIENT_RETRIES) {
@@ -1712,6 +1740,7 @@ function buildOptions(src) {
1712
1740
  opts.enableFileCheckpointing = src.enableFileCheckpointing;
1713
1741
  if (src.includePartialMessages !== void 0)
1714
1742
  opts.includePartialMessages = src.includePartialMessages;
1743
+ if (src.promptSuggestions !== void 0) opts.promptSuggestions = src.promptSuggestions;
1715
1744
  if (src.strictMcpConfig !== void 0) opts.strictMcpConfig = src.strictMcpConfig;
1716
1745
  if (src.settingSources !== void 0) opts.settingSources = src.settingSources;
1717
1746
  else opts.settingSources = DEFAULT_SETTING_SOURCES;
@@ -1750,6 +1779,7 @@ function toSessionCreateParams(input) {
1750
1779
  fallbackModel: src.fallbackModel,
1751
1780
  enableFileCheckpointing: src.enableFileCheckpointing,
1752
1781
  includePartialMessages: src.includePartialMessages,
1782
+ promptSuggestions: src.promptSuggestions,
1753
1783
  strictMcpConfig: src.strictMcpConfig,
1754
1784
  settingSources: src.settingSources ?? DEFAULT_SETTING_SOURCES,
1755
1785
  debug: src.debug,
@@ -2466,11 +2496,14 @@ function detectPathCompatibilityWarnings(session) {
2466
2496
  }
2467
2497
  return warnings;
2468
2498
  }
2469
- function isPosixHomePath(value) {
2470
- return /^\/home\/[^/\s]+(?:\/|$)/.test(value);
2499
+ function isSuspiciousPosixAbsolutePathOnWindows(value) {
2500
+ if (!value.startsWith("/") || value.startsWith("//")) return false;
2501
+ return /^\/home\/[^/\s]+(?:\/|$)/.test(value) || /^\/(?:mnt\/)?[a-zA-Z](?:\/|$)/.test(value) || /^\/(tmp|var|etc|opt|usr|bin|sbin)(?:\/|$)/.test(value);
2471
2502
  }
2472
- function extractPosixHomePath(value) {
2473
- const match = value.match(/\/home\/[^/\s"'`]+(?:\/[^\s"'`]*)?/);
2503
+ function extractSuspiciousPosixAbsolutePath(value) {
2504
+ const match = value.match(
2505
+ /\/(?:home\/[^/\s"'`]+(?:\/[^\s"'`]*)?|(?:mnt\/)?[a-zA-Z](?:\/[^\s"'`]*)?|(?:tmp|var|etc|opt|usr|bin|sbin)(?:\/[^\s"'`]*)?)/
2506
+ );
2474
2507
  return match?.[0];
2475
2508
  }
2476
2509
  function detectPendingPermissionPathWarnings(pending, session) {
@@ -2499,13 +2532,13 @@ function detectPendingPermissionPathWarnings(pending, session) {
2499
2532
  }
2500
2533
  const command = req.input.command;
2501
2534
  if (typeof command === "string") {
2502
- const embeddedPath = extractPosixHomePath(command);
2535
+ const embeddedPath = extractSuspiciousPosixAbsolutePath(command);
2503
2536
  if (embeddedPath) candidates.push(embeddedPath);
2504
2537
  }
2505
- const badPath = candidates.find((p) => isPosixHomePath(p));
2538
+ const badPath = candidates.find((p) => isSuspiciousPosixAbsolutePathOnWindows(p));
2506
2539
  if (!badPath) continue;
2507
2540
  warnings.push(
2508
- `Permission request '${req.requestId}' uses POSIX home path '${badPath}' on Windows. Prefer an absolute Windows path${cwdHint} to avoid out-of-bounds permission prompts.`
2541
+ `Permission request '${req.requestId}' uses POSIX absolute path '${badPath}' on Windows. Prefer an absolute Windows path${cwdHint} to avoid out-of-bounds permission prompts.`
2509
2542
  );
2510
2543
  }
2511
2544
  return warnings;
@@ -3562,7 +3595,7 @@ function registerResources(server, deps) {
3562
3595
  }
3563
3596
 
3564
3597
  // src/server.ts
3565
- var SERVER_VERSION = true ? "2.4.3" : "0.0.0-dev";
3598
+ var SERVER_VERSION = true ? "2.4.8" : "0.0.0-dev";
3566
3599
  function createServerContext(serverCwd) {
3567
3600
  const sessionManager = new SessionManager();
3568
3601
  const server = new McpServer(
@@ -3652,6 +3685,7 @@ function createServerContext(serverCwd) {
3652
3685
  fallbackModel: z.string().optional().describe("Default: none"),
3653
3686
  enableFileCheckpointing: z.boolean().optional().describe("Default: false"),
3654
3687
  includePartialMessages: z.boolean().optional().describe("Default: false"),
3688
+ promptSuggestions: z.boolean().optional().describe("Default: false"),
3655
3689
  strictMcpConfig: z.boolean().optional().describe("Default: false"),
3656
3690
  settingSources: z.array(z.enum(["user", "project", "local"])).optional().describe("Default: ['user','project','local']. []=isolation"),
3657
3691
  debug: z.boolean().optional().describe("Default: false"),
@@ -4000,7 +4034,8 @@ var BENIGN_MESSAGE_PATTERNS = [
4000
4034
  "write after end",
4001
4035
  "stream was destroyed",
4002
4036
  "cannot call write after a stream was destroyed",
4003
- "the pipe is being closed"
4037
+ "the pipe is being closed",
4038
+ "query closed before response received"
4004
4039
  ];
4005
4040
  function isBenignRuntimeError(error) {
4006
4041
  if (!(error instanceof Error)) return false;
@@ -4012,6 +4047,15 @@ function isBenignRuntimeError(error) {
4012
4047
  return BENIGN_MESSAGE_PATTERNS.some((pattern) => message.includes(pattern));
4013
4048
  }
4014
4049
 
4050
+ // src/utils/stdin-shutdown.ts
4051
+ function decideStdinShutdown(params) {
4052
+ if (!params.stdinUnavailable) return "clear";
4053
+ if (params.isConnected) return "reschedule";
4054
+ if (!params.hasActiveSessions) return "shutdown_now";
4055
+ if (params.elapsedMs >= params.maxWaitMs) return "shutdown_timeout";
4056
+ return "reschedule";
4057
+ }
4058
+
4015
4059
  // src/index.ts
4016
4060
  var STDIN_SHUTDOWN_CHECK_MS = 750;
4017
4061
  var STDIN_SHUTDOWN_MAX_WAIT_MS = process.platform === "win32" ? 15e3 : 1e4;
@@ -4088,19 +4132,26 @@ async function main() {
4088
4132
  const evaluateStdinTermination = () => {
4089
4133
  if (closing || stdinClosedAt === void 0) return;
4090
4134
  const stdinUnavailable = process.stdin.destroyed || process.stdin.readableEnded || !process.stdin.readable;
4091
- if (!stdinUnavailable) {
4135
+ const elapsedMs = Date.now() - stdinClosedAt;
4136
+ const active = hasActiveSessions();
4137
+ const connected = server.isConnected();
4138
+ const decision = decideStdinShutdown({
4139
+ stdinUnavailable,
4140
+ elapsedMs,
4141
+ maxWaitMs: STDIN_SHUTDOWN_MAX_WAIT_MS,
4142
+ hasActiveSessions: active,
4143
+ isConnected: connected
4144
+ });
4145
+ if (decision === "clear") {
4092
4146
  stdinClosedAt = void 0;
4093
4147
  stdinClosedReason = void 0;
4094
4148
  return;
4095
4149
  }
4096
- const elapsedMs = Date.now() - stdinClosedAt;
4097
- const active = hasActiveSessions();
4098
- const connected = server.isConnected();
4099
- if (!active && !connected) {
4150
+ if (decision === "shutdown_now") {
4100
4151
  void shutdown(`stdin_${stdinClosedReason ?? "closed"}`);
4101
4152
  return;
4102
4153
  }
4103
- if (elapsedMs >= STDIN_SHUTDOWN_MAX_WAIT_MS) {
4154
+ if (decision === "shutdown_timeout") {
4104
4155
  void shutdown(`stdin_${stdinClosedReason ?? "closed"}_timeout`);
4105
4156
  return;
4106
4157
  }
@@ -4137,7 +4188,9 @@ async function main() {
4137
4188
  void shutdown("SIGHUP");
4138
4189
  });
4139
4190
  process.on("beforeExit", () => {
4140
- void shutdown("beforeExit");
4191
+ if (!server.isConnected()) {
4192
+ void shutdown("beforeExit");
4193
+ }
4141
4194
  });
4142
4195
  process.on("uncaughtException", handleUnexpectedError);
4143
4196
  process.on("unhandledRejection", handleUnexpectedError);