@cnwenf/occ 2.1.291 → 2.1.293

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm version](https://img.shields.io/npm/v/@cnwenf/occ.svg)](https://www.npmjs.com/package/@cnwenf/occ)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
7
7
  [![Runtime: Bun](https://img.shields.io/badge/Runtime-Bun-%23000000.svg)](https://bun.sh/)
8
- [![Tracks: Claude Code 2.1.219](https://img.shields.io/badge/Tracks-Claude%20Code%202.1.219-blueviolet.svg)](https://docs.anthropic.com/en/docs/claude-code)
8
+ [![Tracks: Claude Code 2.1.221](https://img.shields.io/badge/Tracks-Claude%20Code%202.1.221-blueviolet.svg)](https://docs.anthropic.com/en/docs/claude-code)
9
9
 
10
10
  [简体中文](./README.zh-CN.md) · **English**
11
11
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  ## What is OCC
15
15
 
16
- **Open C Code (OCC)** is an open-source coding agent. Its capabilities are aligned with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (currently tracking `2.1.219` — 2.1.218 fully aligned, 2.1.219 partial per OCC-39 gap report). The code is fully open, auditable, backdoor-free, and your data stays under your control.
16
+ **Open C Code (OCC)** is an open-source coding agent. Its capabilities are aligned with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (currently tracking `2.1.221` — 2.1.218 fully aligned, 2.1.219 + 2.1.221 partial per OCC-44 gap report). The code is fully open, auditable, backdoor-free, and your data stays under your control.
17
17
 
18
18
  If you worry that a closed-source CLI might hide backdoors, or that your code and credentials are uploaded to unauditable services, OCC is for you: all source is open and unobfuscated, the build is reproducible from source, and API credentials are sent only to endpoints you configure.
19
19
 
@@ -62,7 +62,7 @@ Requires a valid Anthropic API Key (or AWS Bedrock / Google Vertex / Azure Found
62
62
  | **Auditability** | Line-by-line reviewable | No |
63
63
  | **Telemetry** | Minimal (analytics stubbed) | Standard |
64
64
  | **Data sovereignty** | Credentials stay on your machine; requests only to endpoints you configure | Anthropic endpoints |
65
- | **Capability parity** | Tracks CC `2.1.219` (partial) | Reference implementation |
65
+ | **Capability parity** | Tracks CC `2.1.221` (partial) | Reference implementation |
66
66
  | **Providers** | Anthropic Direct, Bedrock, Vertex, Azure | Anthropic, Bedrock, Vertex |
67
67
  | **Cost** | Free & open-source (MIT) | Subscription |
68
68
  | **Build** | Reproducible from source | N/A |
@@ -157,7 +157,7 @@ For architecture, entry/bootstrap, tool system, UI layer, and module-status deta
157
157
 
158
158
  ## Status
159
159
 
160
- - Tracks Claude Code **`2.1.219` (partial)**.
160
+ - Tracks Claude Code **`2.1.221` (partial)** (2.1.218 fully aligned; 2.1.219 + 2.1.221 partial — see `docs/upstream-version-gap-occ44.md`).
161
161
  - Published to npm as [`@cnwenf/occ`](https://www.npmjs.com/package/@cnwenf/occ).
162
162
  - Many modules are intentionally stubbed or feature-flagged off — see "Disabled / stubbed" above.
163
163
 
package/README.zh-CN.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ## 这是什么
10
10
 
11
- **Open C Code(OCC)** 是一个开源的编码智能体。能力与 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) 对齐(当前跟踪 `2.1.218`)。代码全开放、可审计、无暗门,数据由你掌控。
11
+ **Open C Code(OCC)** 是一个开源的编码智能体。能力与 [Claude Code](https://docs.anthropic.com/en/docs/claude-code) 对齐(当前跟踪 `2.1.221`:2.1.218 已完全对齐、2.1.219 与 2.1.221 部分对齐)。代码全开放、可审计、无暗门,数据由你掌控。
12
12
 
13
13
  如果你担心闭源 CLI 可能植入后门、担心代码与凭据被上传到不可审计的服务,OCC 就是为你准备的:全部源码开放、无混淆,构建产物可由源码复现,API 凭据只发往你自己配置的端点。
14
14
 
@@ -21,7 +21,7 @@
21
21
 
22
22
  ## 现状
23
23
 
24
- - 跟踪 Claude Code **`2.1.218`**。
24
+ - 跟踪 Claude Code **`2.1.221`**(2.1.218 完全对齐、2.1.219 与 2.1.221 部分对齐)。
25
25
  - 代码库有约 1300 个不阻塞的 `tsc` 类型错误(大量松散的 `unknown`/`never`/`{}` 类型),**不影响 Bun 运行时执行**。门槛是 Biome lint,不是 `tsc`。
26
26
  - 所有内部 feature flag(`feature(...)`)已被 polyfill 为 `false` —— 内部功能(COORDINATOR_MODE、KAIROS、PROACTIVE 等)全部关闭。
27
27
  - 已发布到 npm:[`@cnwenf/occ`](https://www.npmjs.com/package/@cnwenf/occ)。
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- globalThis.MACRO={"VERSION":"2.1.291","BINARY_NAME":"occ","BUILD_TIME":"2026-07-30T17:31:04.907Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
2
+ globalThis.MACRO={"VERSION":"2.1.293","BINARY_NAME":"occ","BUILD_TIME":"2026-08-04T22:30:21.732Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
3
3
  // @bun
4
4
  var __create = Object.create;
5
5
  var __getProtoOf = Object.getPrototypeOf;
@@ -58238,7 +58238,7 @@ var init_hooks = __esm(() => {
58238
58238
  });
58239
58239
 
58240
58240
  // src/services/mcp/types.ts
58241
- var ConfigScopeSchema, TransportSchema, McpStdioServerConfigSchema, McpXaaConfigSchema, McpOAuthConfigSchema, McpSSEServerConfigSchema, McpSSEIDEServerConfigSchema, McpWebSocketIDEServerConfigSchema, McpHTTPServerConfigSchema, McpWebSocketServerConfigSchema, McpSdkServerConfigSchema, McpClaudeAIProxyServerConfigSchema, McpServerConfigSchema, McpJsonConfigSchema;
58241
+ var ConfigScopeSchema, TransportSchema, McpStdioServerConfigSchema, McpXaaConfigSchema, McpOAuthConfigSchema, McpSSEServerConfigSchema, McpSSEIDEServerConfigSchema, McpWebSocketIDEServerConfigSchema, McpHTTPServerConfigSchema, McpWebSocketServerConfigSchema, McpSdkServerConfigSchema, McpClaudeAIProxyServerConfigSchema, McpServerConfigSchema, McpJsonConfigSchema, McpJsonConfigShapeSchema, MCP_SERVER_TYPE_SCHEMA_REGISTRY;
58242
58242
  var init_types = __esm(() => {
58243
58243
  init_v4();
58244
58244
  ConfigScopeSchema = lazySchema(() => exports_external.enum([
@@ -58275,7 +58275,9 @@ var init_types = __esm(() => {
58275
58275
  headersHelper: exports_external.string().optional(),
58276
58276
  oauth: McpOAuthConfigSchema().optional(),
58277
58277
  alwaysLoad: exports_external.boolean().optional(),
58278
- request_timeout_ms: exports_external.number().int().positive().optional()
58278
+ request_timeout_ms: exports_external.number().int().positive().optional(),
58279
+ configError: exports_external.string().optional(),
58280
+ configErrorReason: exports_external.string().optional()
58279
58281
  }));
58280
58282
  McpSSEIDEServerConfigSchema = lazySchema(() => exports_external.object({
58281
58283
  type: exports_external.literal("sse-ide"),
@@ -58291,13 +58293,15 @@ var init_types = __esm(() => {
58291
58293
  ideRunningInWindows: exports_external.boolean().optional()
58292
58294
  }));
58293
58295
  McpHTTPServerConfigSchema = lazySchema(() => exports_external.object({
58294
- type: exports_external.literal("http"),
58296
+ type: exports_external.enum(["http", "streamable-http"]).transform(() => "http"),
58295
58297
  url: exports_external.string(),
58296
58298
  headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
58297
58299
  headersHelper: exports_external.string().optional(),
58298
58300
  oauth: McpOAuthConfigSchema().optional(),
58299
58301
  alwaysLoad: exports_external.boolean().optional(),
58300
- request_timeout_ms: exports_external.number().int().positive().optional()
58302
+ request_timeout_ms: exports_external.number().int().positive().optional(),
58303
+ configError: exports_external.string().optional(),
58304
+ configErrorReason: exports_external.string().optional()
58301
58305
  }));
58302
58306
  McpWebSocketServerConfigSchema = lazySchema(() => exports_external.object({
58303
58307
  type: exports_external.literal("ws"),
@@ -58305,7 +58309,9 @@ var init_types = __esm(() => {
58305
58309
  headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
58306
58310
  headersHelper: exports_external.string().optional(),
58307
58311
  alwaysLoad: exports_external.boolean().optional(),
58308
- request_timeout_ms: exports_external.number().int().positive().optional()
58312
+ request_timeout_ms: exports_external.number().int().positive().optional(),
58313
+ configError: exports_external.string().optional(),
58314
+ configErrorReason: exports_external.string().optional()
58309
58315
  }));
58310
58316
  McpSdkServerConfigSchema = lazySchema(() => exports_external.object({
58311
58317
  type: exports_external.literal("sdk"),
@@ -58330,6 +58336,18 @@ var init_types = __esm(() => {
58330
58336
  McpJsonConfigSchema = lazySchema(() => exports_external.object({
58331
58337
  mcpServers: exports_external.record(exports_external.string(), McpServerConfigSchema())
58332
58338
  }));
58339
+ McpJsonConfigShapeSchema = lazySchema(() => exports_external.object({
58340
+ mcpServers: exports_external.record(exports_external.string(), exports_external.unknown())
58341
+ }));
58342
+ MCP_SERVER_TYPE_SCHEMA_REGISTRY = {
58343
+ stdio: McpStdioServerConfigSchema,
58344
+ sse: McpSSEServerConfigSchema,
58345
+ http: McpHTTPServerConfigSchema,
58346
+ "streamable-http": McpHTTPServerConfigSchema,
58347
+ ws: McpWebSocketServerConfigSchema,
58348
+ sdk: McpSdkServerConfigSchema,
58349
+ "claudeai-proxy": McpClaudeAIProxyServerConfigSchema
58350
+ };
58333
58351
  });
58334
58352
 
58335
58353
  // src/utils/plugins/schemas.ts
@@ -359967,9 +359985,7 @@ function collectCommands(node, commands7, varScope) {
359967
359985
  loopVar = child.text;
359968
359986
  } else if (child.type === "do_group") {
359969
359987
  doGroup = child;
359970
- } else if (child.type === "for" || child.type === "in" || child.type === "select" || child.type === ";") {
359971
- continue;
359972
- } else if (child.type === "command_substitution") {
359988
+ } else if (child.type === "for" || child.type === "in" || child.type === "select" || child.type === ";") {} else if (child.type === "command_substitution") {
359973
359989
  const err2 = collectCommandSubstitution(child, commands7, varScope);
359974
359990
  if (err2)
359975
359991
  return err2;
@@ -360156,9 +360172,93 @@ function walkTestExpr(node, argv, innerCommands, varScope) {
360156
360172
  argv.push(node.text);
360157
360173
  return null;
360158
360174
  case "regex":
360159
- case "extglob_pattern":
360175
+ case "extglob_pattern": {
360176
+ if (/\$[({[\w#?!*@$'"+~^=-]|`|[<>]\(/.test(node.text)) {
360177
+ return {
360178
+ kind: "too-complex",
360179
+ reason: `[[ ]] ${node.type} contains expansion / command / process substitution`,
360180
+ nodeType: node.type
360181
+ };
360182
+ }
360183
+ if (node.type === "extglob_pattern") {
360184
+ const text2 = node.text;
360185
+ let i6 = 0;
360186
+ while (i6 < text2.length) {
360187
+ if (text2[i6] === "\\" && i6 + 1 < text2.length) {
360188
+ i6 += 2;
360189
+ continue;
360190
+ }
360191
+ if (text2[i6] === "&") {
360192
+ return {
360193
+ kind: "too-complex",
360194
+ reason: "[[ ]] pattern contains unquoted & (zsh splits the word at & at any depth)"
360195
+ };
360196
+ }
360197
+ i6++;
360198
+ }
360199
+ }
360200
+ if (node.type === "regex") {
360201
+ const text2 = node.text;
360202
+ let parenDepth = 0;
360203
+ let i6 = 0;
360204
+ while (i6 < text2.length) {
360205
+ const ch2 = text2[i6];
360206
+ if (ch2 === "\\" && i6 + 1 < text2.length) {
360207
+ i6 += 2;
360208
+ continue;
360209
+ }
360210
+ if (parenDepth === 0 && ch2 === "|" && text2[i6 + 1] === ch2) {
360211
+ return {
360212
+ kind: "too-complex",
360213
+ reason: "[[ ]] regex contains glued || (zsh splits it as a cond operator)",
360214
+ nodeType: node.type
360215
+ };
360216
+ }
360217
+ if (ch2 === "&") {
360218
+ return {
360219
+ kind: "too-complex",
360220
+ reason: "[[ ]] regex contains unquoted & (zsh splits the word at & at any depth)",
360221
+ nodeType: node.type
360222
+ };
360223
+ }
360224
+ if (ch2 === '"' || ch2 === "'") {
360225
+ const quote2 = ch2;
360226
+ i6++;
360227
+ while (i6 < text2.length && text2[i6] !== quote2) {
360228
+ if (quote2 === '"' && text2[i6] === "\\" && i6 + 1 < text2.length) {
360229
+ i6++;
360230
+ }
360231
+ i6++;
360232
+ }
360233
+ if (i6 < text2.length)
360234
+ i6++;
360235
+ continue;
360236
+ }
360237
+ if (ch2 === "(") {
360238
+ parenDepth++;
360239
+ } else if (ch2 === ")") {
360240
+ parenDepth--;
360241
+ if (parenDepth < 0) {
360242
+ return {
360243
+ kind: "too-complex",
360244
+ reason: "[[ ]] regex has unbalanced parentheses (parser desync)",
360245
+ nodeType: node.type
360246
+ };
360247
+ }
360248
+ }
360249
+ i6++;
360250
+ }
360251
+ if (parenDepth !== 0) {
360252
+ return {
360253
+ kind: "too-complex",
360254
+ reason: "[[ ]] regex has unbalanced parentheses (parser desync)",
360255
+ nodeType: node.type
360256
+ };
360257
+ }
360258
+ }
360160
360259
  argv.push(node.text);
360161
360260
  return null;
360261
+ }
360162
360262
  default: {
360163
360263
  const arg = walkArgument(node, innerCommands, varScope);
360164
360264
  if (typeof arg !== "string")
@@ -360600,7 +360700,6 @@ function walkVariableAssignment(node, innerCommands, varScope) {
360600
360700
  name3 = child.text;
360601
360701
  } else if (child.type === "=" || child.type === "+=") {
360602
360702
  isAppend = child.type === "+=";
360603
- continue;
360604
360703
  } else if (child.type === "command_substitution") {
360605
360704
  const err2 = collectCommandSubstitution(child, innerCommands, varScope);
360606
360705
  if (err2)
@@ -360657,7 +360756,7 @@ function walkVariableAssignment(node, innerCommands, varScope) {
360657
360756
  if (!/^[A-Za-z0-9 _+:./=[\]-]*$/.test(value.replace(/\$\{[A-Za-z_][A-Za-z0-9_]*\}/g, ""))) {
360658
360757
  return {
360659
360758
  kind: "too-complex",
360660
- reason: "PS4 value outside safe charset \u2014 only ${VAR} refs and [A-Za-z0-9 _+:.=/[]-] allowed",
360759
+ reason: `PS4 value outside safe charset \u2014 only \${VAR} refs and [A-Za-z0-9 _+:.=/[]-] allowed`,
360661
360760
  nodeType: "variable_assignment"
360662
360761
  };
360663
360762
  }
@@ -362013,6 +362112,7 @@ var init_killShellTasks = __esm(() => {
362013
362112
  });
362014
362113
 
362015
362114
  // src/tasks/LocalShellTask/LocalShellTask.tsx
362115
+ import { statSync as statSync12 } from "fs";
362016
362116
  import { stat as stat21 } from "fs/promises";
362017
362117
  function looksLikePrompt(tail) {
362018
362118
  const lastLine2 = tail.trimEnd().split(`
@@ -362073,6 +362173,16 @@ The command is likely blocked on an interactive prompt. Kill this task and re-ru
362073
362173
  clearInterval(timer);
362074
362174
  };
362075
362175
  }
362176
+ function monitorCompletedSummary(description, exitCode, outputBytes) {
362177
+ return outputBytes === 0 ? `Monitor "${description}" ended without producing output${exitCode !== undefined ? ` (exit ${exitCode})` : ""}` : `Monitor "${description}" stream ended`;
362178
+ }
362179
+ function readMonitorOutputBytes(outputPath) {
362180
+ try {
362181
+ return statSync12(outputPath).size;
362182
+ } catch (e4) {
362183
+ return e4.code === "ENOENT" ? 0 : undefined;
362184
+ }
362185
+ }
362076
362186
  function enqueueShellNotification(taskId, description, status, exitCode, setAppState, toolUseId, kind = "bash", agentId) {
362077
362187
  let shouldEnqueue = false;
362078
362188
  updateTaskState(taskId, setAppState, (task) => {
@@ -362089,12 +362199,15 @@ function enqueueShellNotification(taskId, description, status, exitCode, setAppS
362089
362199
  return;
362090
362200
  }
362091
362201
  abortSpeculation(setAppState);
362202
+ const outputPath = getTaskOutputPath(taskId);
362092
362203
  let summary;
362093
362204
  if (feature("MONITOR_TOOL") && kind === "monitor") {
362094
362205
  switch (status) {
362095
- case "completed":
362096
- summary = `Monitor "${description}" stream ended`;
362206
+ case "completed": {
362207
+ const outputBytes = readMonitorOutputBytes(outputPath);
362208
+ summary = monitorCompletedSummary(description, exitCode, outputBytes);
362097
362209
  break;
362210
+ }
362098
362211
  case "failed":
362099
362212
  summary = `Monitor "${description}" script failed${exitCode !== undefined ? ` (exit ${exitCode})` : ""}`;
362100
362213
  break;
@@ -362115,7 +362228,6 @@ function enqueueShellNotification(taskId, description, status, exitCode, setAppS
362115
362228
  break;
362116
362229
  }
362117
362230
  }
362118
- const outputPath = getTaskOutputPath(taskId);
362119
362231
  const toolUseIdLine = toolUseId ? `
362120
362232
  <${TOOL_USE_ID_TAG}>${toolUseId}</${TOOL_USE_ID_TAG}>` : "";
362121
362233
  const message = `<${TASK_NOTIFICATION_TAG}>
@@ -386592,6 +386704,7 @@ function filterMcpServersByPolicy(configs) {
386592
386704
  }
386593
386705
  function expandEnvVars(config6) {
386594
386706
  const missingVars = [];
386707
+ let urlExpandedToEmpty = false;
386595
386708
  function expandString(str2) {
386596
386709
  const { expanded: expanded2, missingVars: vars } = expandEnvVarsInString(str2);
386597
386710
  missingVars.push(...vars);
@@ -386614,9 +386727,11 @@ function expandEnvVars(config6) {
386614
386727
  case "http":
386615
386728
  case "ws": {
386616
386729
  const remoteConfig = config6;
386730
+ const expandedUrl = expandString(remoteConfig.url);
386731
+ urlExpandedToEmpty = remoteConfig.url.trim() !== "" && expandedUrl.trim() === "";
386617
386732
  expanded = {
386618
386733
  ...remoteConfig,
386619
- url: expandString(remoteConfig.url),
386734
+ url: expandedUrl,
386620
386735
  headers: remoteConfig.headers ? mapValues_default(remoteConfig.headers, expandString) : undefined
386621
386736
  };
386622
386737
  break;
@@ -386634,7 +386749,8 @@ function expandEnvVars(config6) {
386634
386749
  }
386635
386750
  return {
386636
386751
  expanded,
386637
- missingVars: [...new Set(missingVars)]
386752
+ missingVars: [...new Set(missingVars)],
386753
+ urlExpandedToEmpty
386638
386754
  };
386639
386755
  }
386640
386756
  async function addMcpConfig(name3, config6, scope) {
@@ -387109,6 +387225,19 @@ function parseMcpConfig(params) {
387109
387225
  }
387110
387226
  function parseMcpConfigFromFilePath(params) {
387111
387227
  const { filePath, expandVars, scope } = params;
387228
+ const read = readMcpConfigFileContents({ filePath, scope });
387229
+ if (read.errors) {
387230
+ return { config: null, errors: read.errors };
387231
+ }
387232
+ return parseMcpConfig({
387233
+ configObject: read.parsedJson,
387234
+ expandVars,
387235
+ scope,
387236
+ filePath
387237
+ });
387238
+ }
387239
+ function readMcpConfigFileContents(params) {
387240
+ const { filePath, scope } = params;
387112
387241
  const fs17 = getFsImplementation();
387113
387242
  let configContent;
387114
387243
  try {
@@ -387117,7 +387246,6 @@ function parseMcpConfigFromFilePath(params) {
387117
387246
  const code = getErrnoCode(error52);
387118
387247
  if (code === "ENOENT") {
387119
387248
  return {
387120
- config: null,
387121
387249
  errors: [
387122
387250
  {
387123
387251
  file: filePath,
@@ -387134,7 +387262,6 @@ function parseMcpConfigFromFilePath(params) {
387134
387262
  }
387135
387263
  logForDebugging(`MCP config read error for ${filePath} (scope=${scope}): ${error52}`, { level: "error" });
387136
387264
  return {
387137
- config: null,
387138
387265
  errors: [
387139
387266
  {
387140
387267
  file: filePath,
@@ -387153,7 +387280,6 @@ function parseMcpConfigFromFilePath(params) {
387153
387280
  if (!parsedJson) {
387154
387281
  logForDebugging(`MCP config is not valid JSON: ${filePath} (scope=${scope}, length=${configContent.length}, first100=${jsonStringify(configContent.slice(0, 100))})`, { level: "error" });
387155
387282
  return {
387156
- config: null,
387157
387283
  errors: [
387158
387284
  {
387159
387285
  file: filePath,
@@ -387168,8 +387294,145 @@ function parseMcpConfigFromFilePath(params) {
387168
387294
  ]
387169
387295
  };
387170
387296
  }
387171
- return parseMcpConfig({
387172
- configObject: parsedJson,
387297
+ return { parsedJson };
387298
+ }
387299
+ function isReservedMcpServerName(name3) {
387300
+ return isClaudeInChromeMCPServer(name3) || isComputerUseMCPServer(name3) || isReservedClaudeBrowserName(name3) || name3 === "workspace";
387301
+ }
387302
+ function findMcpConfigWhitespaceIssues(config6) {
387303
+ const issues = [];
387304
+ function check3(label, value) {
387305
+ if (value !== value.trim()) {
387306
+ issues.push(label);
387307
+ }
387308
+ }
387309
+ if ("command" in config6) {
387310
+ check3("command", config6.command);
387311
+ }
387312
+ if ("url" in config6) {
387313
+ check3("url", config6.url);
387314
+ }
387315
+ if ("args" in config6 && config6.args) {
387316
+ config6.args.forEach((arg, index2) => check3(`args[${index2}]`, arg));
387317
+ }
387318
+ if ("env" in config6 && config6.env) {
387319
+ for (const [envName, envValue] of Object.entries(config6.env)) {
387320
+ if (envName !== envName.trim()) {
387321
+ issues.push(`env name ${jsonStringify(envName)}`);
387322
+ }
387323
+ check3(`env.${envName}`, envValue);
387324
+ }
387325
+ }
387326
+ if ("headers" in config6 && config6.headers) {
387327
+ for (const [headerName, headerValue] of Object.entries(config6.headers)) {
387328
+ if (headerName !== headerName.trim()) {
387329
+ issues.push(`header name ${jsonStringify(headerName)}`);
387330
+ }
387331
+ check3(`headers.${headerName}`, headerValue);
387332
+ }
387333
+ }
387334
+ return issues;
387335
+ }
387336
+ function parseDynamicMcpConfig(params) {
387337
+ const { configObject, expandVars, scope, filePath } = params;
387338
+ const shapeResult = McpJsonConfigShapeSchema().safeParse(configObject);
387339
+ if (!shapeResult.success) {
387340
+ const foundServersKeyInstead = configObject !== null && typeof configObject === "object" && "servers" in configObject && !("mcpServers" in configObject);
387341
+ return {
387342
+ config: null,
387343
+ errors: shapeResult.error.issues.map((issue2) => ({
387344
+ ...filePath && { file: filePath },
387345
+ path: issue2.path.join("."),
387346
+ message: foundServersKeyInstead ? 'Missing "mcpServers" \u2014 found "servers" instead. Claude Code reads MCP servers from the "mcpServers" key.' : issue2.message,
387347
+ ...foundServersKeyInstead && {
387348
+ suggestion: `Rename the top-level "servers" key to "mcpServers" in ${filePath ?? "your MCP config"}.`
387349
+ },
387350
+ mcpErrorMetadata: {
387351
+ scope,
387352
+ severity: "fatal"
387353
+ }
387354
+ }))
387355
+ };
387356
+ }
387357
+ const errors8 = [];
387358
+ const validatedServers = {};
387359
+ function pushEntryError(serverName, message, suggestion, skipReason) {
387360
+ errors8.push({
387361
+ ...filePath && { file: filePath },
387362
+ path: `mcpServers.${serverName}`,
387363
+ message,
387364
+ ...suggestion && { suggestion },
387365
+ mcpErrorMetadata: {
387366
+ scope,
387367
+ serverName,
387368
+ severity: "warning",
387369
+ ...skipReason && { skipReason }
387370
+ }
387371
+ });
387372
+ }
387373
+ const rawServers = configObject.mcpServers;
387374
+ if (Object.hasOwn(rawServers, "__proto__") && !Object.hasOwn(shapeResult.data.mcpServers, "__proto__")) {
387375
+ pushEntryError("__proto__", '"__proto__" is a reserved MCP server name and was not loaded', 'Rename this server in your MCP config \u2014 "__proto__" cannot be used as a server name', "reserved_name");
387376
+ }
387377
+ for (const [name3, rawEntry] of Object.entries(shapeResult.data.mcpServers)) {
387378
+ const declaredType = rawEntry && typeof rawEntry === "object" && "type" in rawEntry && typeof rawEntry.type === "string" ? rawEntry.type : "stdio";
387379
+ const schemaGetter = Object.hasOwn(MCP_SERVER_TYPE_SCHEMA_REGISTRY, declaredType) ? MCP_SERVER_TYPE_SCHEMA_REGISTRY[declaredType] : undefined;
387380
+ if (!schemaGetter) {
387381
+ pushEntryError(name3, `Skipped \u2014 unknown MCP server type "${declaredType}" for server "${name3}"`, "Valid types are: stdio, sse, http (or streamable-http), ws, sdk", "unknown_type");
387382
+ continue;
387383
+ }
387384
+ const entryResult = schemaGetter().safeParse(rawEntry);
387385
+ if (!entryResult.success) {
387386
+ if (rawEntry !== null && typeof rawEntry === "object" && !("type" in rawEntry) && "url" in rawEntry && !("command" in rawEntry)) {
387387
+ pushEntryError(name3, `Skipped \u2014 MCP server "${name3}" has a "url" but no "type"; add "type": "http" (or "sse" / "ws") to this entry`, undefined, "url_missing_type");
387388
+ continue;
387389
+ }
387390
+ const details = entryResult.error.issues.map((issue2) => {
387391
+ const issueMessage = issue2.message.replace(/^Invalid input: /, "");
387392
+ return `${issue2.path.join(".") || "(root)"}: ${issueMessage}`;
387393
+ }).join("; ");
387394
+ pushEntryError(name3, `Skipped \u2014 invalid MCP server config for "${name3}": ${details}`, undefined, "invalid_config");
387395
+ continue;
387396
+ }
387397
+ const validated = entryResult.data;
387398
+ if (isReservedMcpServerName(name3) && validated.type !== "sdk") {
387399
+ pushEntryError(name3, `"${name3}" is a reserved MCP server name and was not loaded`, `Rename this server in your MCP config \u2014 "${name3}" is reserved for internal use`, "reserved_name");
387400
+ continue;
387401
+ }
387402
+ const whitespaceIssues = findMcpConfigWhitespaceIssues(validated);
387403
+ if (whitespaceIssues.length > 0) {
387404
+ pushEntryError(name3, `Leading or trailing whitespace in: ${whitespaceIssues.join(", ")}`, `Remove the whitespace from these values in the "${name3}" entry \u2014 they are used exactly as written`, undefined);
387405
+ }
387406
+ let serverConfig = validated;
387407
+ if (expandVars) {
387408
+ const { expanded, missingVars, urlExpandedToEmpty } = expandEnvVars(validated);
387409
+ if (missingVars.length > 0) {
387410
+ pushEntryError(name3, `Missing environment variables: ${missingVars.join(", ")}`, `Set the following environment variables: ${missingVars.join(", ")}`, undefined);
387411
+ }
387412
+ serverConfig = expanded;
387413
+ if (urlExpandedToEmpty && "url" in validated) {
387414
+ serverConfig = {
387415
+ ...expanded,
387416
+ configError: `'url' ${jsonStringify(validated.url)} expanded to an empty string. Set the referenced environment variable, or update the server's config and reconnect.`,
387417
+ configErrorReason: "url_invalid"
387418
+ };
387419
+ }
387420
+ }
387421
+ validatedServers[name3] = serverConfig;
387422
+ }
387423
+ return {
387424
+ config: { mcpServers: validatedServers },
387425
+ errors: errors8
387426
+ };
387427
+ }
387428
+ function parseDynamicMcpConfigFromFile(params) {
387429
+ const { filePath, expandVars, scope } = params;
387430
+ const read = readMcpConfigFileContents({ filePath, scope });
387431
+ if (read.errors) {
387432
+ return { config: null, errors: read.errors };
387433
+ }
387434
+ return parseDynamicMcpConfig({
387435
+ configObject: read.parsedJson,
387173
387436
  expandVars,
387174
387437
  scope,
387175
387438
  filePath
@@ -387229,6 +387492,7 @@ var init_config6 = __esm(() => {
387229
387492
  init_memoize();
387230
387493
  init_platform2();
387231
387494
  init_common4();
387495
+ init_common();
387232
387496
  init_config4();
387233
387497
  init_cwd2();
387234
387498
  init_debug();
@@ -564653,10 +564917,10 @@ var init_cliui = __esm(() => {
564653
564917
 
564654
564918
  // node_modules/.bun/escalade@3.2.0/node_modules/escalade/sync/index.mjs
564655
564919
  import { dirname as dirname43, resolve as resolve38 } from "path";
564656
- import { readdirSync as readdirSync7, statSync as statSync12 } from "fs";
564920
+ import { readdirSync as readdirSync7, statSync as statSync13 } from "fs";
564657
564921
  function sync_default(start, callback) {
564658
564922
  let dir = resolve38(".", start);
564659
- let tmp, stats = statSync12(dir);
564923
+ let tmp, stats = statSync13(dir);
564660
564924
  if (!stats.isDirectory()) {
564661
564925
  dir = dirname43(dir);
564662
564926
  }
@@ -565683,7 +565947,7 @@ var init_yerror = __esm(() => {
565683
565947
  });
565684
565948
 
565685
565949
  // node_modules/.bun/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js
565686
- import { readFileSync as readFileSync23, statSync as statSync13, writeFile as writeFile28 } from "fs";
565950
+ import { readFileSync as readFileSync23, statSync as statSync14, writeFile as writeFile28 } from "fs";
565687
565951
  import { format as format5 } from "util";
565688
565952
  import { resolve as resolve40 } from "path";
565689
565953
  var node_default2;
@@ -565697,7 +565961,7 @@ var init_node12 = __esm(() => {
565697
565961
  resolve: resolve40,
565698
565962
  exists: (file2) => {
565699
565963
  try {
565700
- return statSync13(file2).isFile();
565964
+ return statSync14(file2).isFile();
565701
565965
  } catch (err2) {
565702
565966
  return false;
565703
565967
  }
@@ -578444,10 +578708,15 @@ function getSonnet46Option() {
578444
578708
  descriptionForModel: "Sonnet 4.6 - previous Sonnet version"
578445
578709
  };
578446
578710
  }
578711
+ function shouldUseCustomModelOptions() {
578712
+ const provider5 = getAPIProvider();
578713
+ const isAnthropicOwned = provider5 === "firstParty" || provider5 === "anthropic_aws" || provider5 === "gateway";
578714
+ const isAwsOrGoogleCloud = provider5 === "anthropic_aws";
578715
+ return !isAnthropicOwned || isAwsOrGoogleCloud || !isFirstPartyAnthropicBaseUrl();
578716
+ }
578447
578717
  function getCustomFableOption() {
578448
- const is3P = getAPIProvider() !== "firstParty";
578449
578718
  const customFableModel = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL;
578450
- if (is3P && customFableModel) {
578719
+ if (shouldUseCustomModelOptions() && customFableModel) {
578451
578720
  return {
578452
578721
  value: "fable",
578453
578722
  label: process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME ?? customFableModel,
@@ -578470,9 +578739,8 @@ function getFable5Option() {
578470
578739
  };
578471
578740
  }
578472
578741
  function getCustomSonnetOption() {
578473
- const is3P = getAPIProvider() !== "firstParty";
578474
578742
  const customSonnetModel = process.env.ANTHROPIC_DEFAULT_SONNET_MODEL;
578475
- if (is3P && customSonnetModel) {
578743
+ if (shouldUseCustomModelOptions() && customSonnetModel) {
578476
578744
  const is1m = has1mContext(customSonnetModel);
578477
578745
  return {
578478
578746
  value: "sonnet",
@@ -578483,9 +578751,8 @@ function getCustomSonnetOption() {
578483
578751
  }
578484
578752
  }
578485
578753
  function getCustomOpusOption() {
578486
- const is3P = getAPIProvider() !== "firstParty";
578487
578754
  const customOpusModel = process.env.ANTHROPIC_DEFAULT_OPUS_MODEL;
578488
- if (is3P && customOpusModel) {
578755
+ if (shouldUseCustomModelOptions() && customOpusModel) {
578489
578756
  const is1m = has1mContext(customOpusModel);
578490
578757
  return {
578491
578758
  value: "opus",
@@ -578558,9 +578825,8 @@ function getOpus46_1MOption(fastMode = false) {
578558
578825
  };
578559
578826
  }
578560
578827
  function getCustomHaikuOption() {
578561
- const is3P = getAPIProvider() !== "firstParty";
578562
578828
  const customHaikuModel = process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
578563
- if (is3P && customHaikuModel) {
578829
+ if (shouldUseCustomModelOptions() && customHaikuModel) {
578564
578830
  return {
578565
578831
  value: "haiku",
578566
578832
  label: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME ?? customHaikuModel,
@@ -578677,6 +578943,33 @@ function getModelOptionsBase(fastMode = false) {
578677
578943
  return standardOptions;
578678
578944
  }
578679
578945
  if (getAPIProvider() === "firstParty") {
578946
+ const customOpus2 = getCustomOpusOption();
578947
+ const customSonnet2 = getCustomSonnetOption();
578948
+ const customHaiku2 = getCustomHaikuOption();
578949
+ const customFable = getCustomFableOption();
578950
+ if (customOpus2 || customSonnet2 || customHaiku2 || customFable) {
578951
+ const customOptions = [getDefaultOptionForUser(fastMode)];
578952
+ if (customOpus2 !== undefined) {
578953
+ customOptions.push(customOpus2);
578954
+ } else if (isOpus1mMergeEnabled()) {
578955
+ customOptions.push(getMergedOpus1MOption(fastMode));
578956
+ } else {
578957
+ customOptions.push(getOpus5Option(fastMode));
578958
+ if (checkOpus1mAccess()) {
578959
+ customOptions.push(getOpus5_1MOption(fastMode));
578960
+ }
578961
+ }
578962
+ if (customFable !== undefined) {
578963
+ customOptions.push(customFable);
578964
+ }
578965
+ if (customSonnet2 !== undefined) {
578966
+ customOptions.push(customSonnet2);
578967
+ } else if (checkSonnet1mAccess()) {
578968
+ customOptions.push(getSonnet5_1MOption());
578969
+ }
578970
+ customOptions.push(customHaiku2 ?? getHaiku45Option());
578971
+ return customOptions;
578972
+ }
578680
578973
  const payg1POptions = [getDefaultOptionForUser(fastMode)];
578681
578974
  if (checkSonnet1mAccess()) {
578682
578975
  payg1POptions.push(getSonnet5_1MOption());
@@ -583732,7 +584025,7 @@ __export(exports_workflowDiscovery, {
583732
584025
  USER_WORKFLOWS_DIR: () => USER_WORKFLOWS_DIR,
583733
584026
  PROJECT_WORKFLOWS_DIR: () => PROJECT_WORKFLOWS_DIR
583734
584027
  });
583735
- import { existsSync as existsSync16, readdirSync as readdirSync8, statSync as statSync14 } from "fs";
584028
+ import { existsSync as existsSync16, readdirSync as readdirSync8, statSync as statSync15 } from "fs";
583736
584029
  import { homedir as homedir31 } from "os";
583737
584030
  import { join as join109 } from "path";
583738
584031
  function isWorkflowsEnabled() {
@@ -583759,7 +584052,7 @@ function listScripts(dir, source2) {
583759
584052
  continue;
583760
584053
  const full = join109(dir, entry);
583761
584054
  try {
583762
- if (!statSync14(full).isFile())
584055
+ if (!statSync15(full).isFile())
583763
584056
  continue;
583764
584057
  } catch {
583765
584058
  continue;
@@ -583788,7 +584081,7 @@ function resolveWorkflowScript(name3, source2, cwd2 = process.cwd()) {
583788
584081
  const full = join109(dir, `${name3}.js`);
583789
584082
  if (existsSync16(full)) {
583790
584083
  try {
583791
- if (statSync14(full).isFile())
584084
+ if (statSync15(full).isFile())
583792
584085
  return full;
583793
584086
  } catch {}
583794
584087
  }
@@ -639184,7 +639477,7 @@ var init_process2 = () => {};
639184
639477
 
639185
639478
  // src/daemon/lockfile.ts
639186
639479
  import { open as open13, readFile as readFile50, unlink as unlink22, writeFile as writeFile43 } from "fs/promises";
639187
- import { existsSync as existsSync18, statSync as statSync15 } from "fs";
639480
+ import { existsSync as existsSync18, statSync as statSync16 } from "fs";
639188
639481
  import { join as join135 } from "path";
639189
639482
  function getDaemonLockfilePath() {
639190
639483
  return join135(getClaudeConfigHomeDir(), "daemon.lock");
@@ -639329,7 +639622,7 @@ async function displaceHolder() {
639329
639622
  }
639330
639623
  function lockfileMtime() {
639331
639624
  try {
639332
- return statSync15(getDaemonLockfilePath()).mtimeMs;
639625
+ return statSync16(getDaemonLockfilePath()).mtimeMs;
639333
639626
  } catch {
639334
639627
  return null;
639335
639628
  }
@@ -640512,7 +640805,7 @@ __export(exports_supervisor, {
640512
640805
  daemonInstall: () => daemonInstall,
640513
640806
  checkBinaryIdentity: () => checkBinaryIdentity
640514
640807
  });
640515
- import { existsSync as existsSync22, statSync as statSync16 } from "fs";
640808
+ import { existsSync as existsSync22, statSync as statSync17 } from "fs";
640516
640809
  function buildIdentity() {
640517
640810
  return {
640518
640811
  supervisorPid: process.pid,
@@ -640535,7 +640828,7 @@ function checkBinaryIdentity() {
640535
640828
  if (!execPath2 || !existsSync22(execPath2)) {
640536
640829
  return "binary identity unresolvable";
640537
640830
  }
640538
- statSync16(execPath2);
640831
+ statSync17(execPath2);
640539
640832
  } catch {
640540
640833
  return "binary identity unresolvable";
640541
640834
  }
@@ -642501,7 +642794,7 @@ var init_file_index = __esm(() => {
642501
642794
  });
642502
642795
 
642503
642796
  // src/hooks/fileSuggestions.ts
642504
- import { statSync as statSync17 } from "fs";
642797
+ import { statSync as statSync18 } from "fs";
642505
642798
  import * as path35 from "path";
642506
642799
  function getFileIndex() {
642507
642800
  if (!fileIndex) {
@@ -642549,7 +642842,7 @@ function getGitIndexMtime() {
642549
642842
  if (!repoRoot)
642550
642843
  return null;
642551
642844
  try {
642552
- return statSync17(path35.join(repoRoot, ".git", "index")).mtimeMs;
642845
+ return statSync18(path35.join(repoRoot, ".git", "index")).mtimeMs;
642553
642846
  } catch {
642554
642847
  return null;
642555
642848
  }
@@ -699801,7 +700094,7 @@ var init_autocompact2 = __esm(() => {
699801
700094
  });
699802
700095
 
699803
700096
  // src/commands/cd/cdLogic.ts
699804
- import { realpathSync as realpathSync8, statSync as statSync18 } from "fs";
700097
+ import { realpathSync as realpathSync8, statSync as statSync19 } from "fs";
699805
700098
  import { resolve as resolve57 } from "path";
699806
700099
  function resolveDirectoryTarget(target) {
699807
700100
  const resolved = resolve57(target);
@@ -699812,7 +700105,7 @@ function resolveDirectoryTarget(target) {
699812
700105
  return { ok: false, error: `Directory does not exist: ${resolved}` };
699813
700106
  }
699814
700107
  try {
699815
- if (!statSync18(physical).isDirectory()) {
700108
+ if (!statSync19(physical).isDirectory()) {
699816
700109
  return { ok: false, error: `Not a directory: ${resolved}` };
699817
700110
  }
699818
700111
  } catch {
@@ -729077,7 +729370,7 @@ import {
729077
729370
  symlink as symlink5,
729078
729371
  utimes as utimes2
729079
729372
  } from "fs/promises";
729080
- import { existsSync as existsSync26, readFileSync as readFileSync34, statSync as statSync19 } from "fs";
729373
+ import { existsSync as existsSync26, readFileSync as readFileSync34, statSync as statSync20 } from "fs";
729081
729374
  import { basename as basename51, dirname as dirname73, join as join166 } from "path";
729082
729375
  function validateWorktreeSlug(slug) {
729083
729376
  if (slug.length > MAX_WORKTREE_SLUG_LENGTH) {
@@ -729124,7 +729417,7 @@ function getLinkedGitWorktreePath() {
729124
729417
  const dotGit = join166(dir, ".git");
729125
729418
  try {
729126
729419
  if (existsSync26(dotGit)) {
729127
- const stats = statSync19(dotGit);
729420
+ const stats = statSync20(dotGit);
729128
729421
  if (stats.isFile()) {
729129
729422
  const content = readFileSync34(dotGit, "utf8").trim();
729130
729423
  if (content.startsWith("gitdir:")) {
@@ -812672,6 +812965,18 @@ var init_xaaIdpCommand = __esm(() => {
812672
812965
  init_settings2();
812673
812966
  });
812674
812967
 
812968
+ // src/services/mcp/skippedMcpServerErrors.ts
812969
+ function recordSkippedMcpServerErrors(errors8) {
812970
+ skippedMcpServerErrors.push(...errors8);
812971
+ }
812972
+ function getSkippedMcpServerErrors() {
812973
+ return skippedMcpServerErrors;
812974
+ }
812975
+ var skippedMcpServerErrors;
812976
+ var init_skippedMcpServerErrors = __esm(() => {
812977
+ skippedMcpServerErrors = [];
812978
+ });
812979
+
812675
812980
  // src/utils/cliArgs.ts
812676
812981
  function eagerParseCliFlag(flagName, argv = process.argv) {
812677
812982
  for (let i6 = 0;i6 < argv.length; i6++) {
@@ -814925,7 +815230,7 @@ class QueryEngine {
814925
815230
  yield buildSystemInitMessage({
814926
815231
  tools,
814927
815232
  mcpClients,
814928
- mcpServerErrors: [],
815233
+ mcpServerErrors: getSkippedMcpServerErrors(),
814929
815234
  model: mainLoopModel,
814930
815235
  permissionMode: initialAppState.toolPermissionContext.mode,
814931
815236
  commands: commands7,
@@ -815472,6 +815777,7 @@ var init_QueryEngine = __esm(() => {
815472
815777
  init_paths();
815473
815778
  init_query2();
815474
815779
  init_errors10();
815780
+ init_skippedMcpServerErrors();
815475
815781
  init_Tool();
815476
815782
  init_SyntheticOutputTool();
815477
815783
  init_pointer();
@@ -816337,8 +816643,7 @@ function runHeadlessStreaming(structuredIO, mcpClients, commands7, tools, initia
816337
816643
  const mutableMessages = initialMessages;
816338
816644
  let readFileState = extractReadFilesFromMessages(initialMessages, cwd2(), READ_FILE_STATE_CACHE_SIZE);
816339
816645
  const pendingSeeds = createFileStateCacheWithSizeLimit(READ_FILE_STATE_CACHE_SIZE);
816340
- const resumeInterruptedTurnEnv = process.env.CLAUDE_CODE_RESUME_INTERRUPTED_TURN;
816341
- if (turnInterruptionState && turnInterruptionState.kind !== "none" && resumeInterruptedTurnEnv) {
816646
+ if (turnInterruptionState && turnInterruptionState.kind !== "none" && isEnvTruthy(process.env.CLAUDE_CODE_RESUME_INTERRUPTED_TURN)) {
816342
816647
  logForDebugging(`[print.ts] Auto-resuming interrupted turn (kind: ${turnInterruptionState.kind})`);
816343
816648
  removeInterruptedMessage(mutableMessages, turnInterruptionState.message);
816344
816649
  enqueue({
@@ -823645,13 +823950,14 @@ ${addendum}` : addendum;
823645
823950
  if (mcpConfig && mcpConfig.length > 0) {
823646
823951
  const processedConfigs = mcpConfig.map((config8) => config8.trim()).filter((config8) => config8.length > 0);
823647
823952
  let allConfigs = {};
823648
- const allErrors = [];
823953
+ const fatalErrors = [];
823954
+ const skippedCandidates = [];
823649
823955
  for (const configItem of processedConfigs) {
823650
823956
  let configs = null;
823651
823957
  let errors8 = [];
823652
823958
  const parsedJson = safeParseJSON(configItem);
823653
823959
  if (parsedJson) {
823654
- const result = parseMcpConfig({
823960
+ const result = parseDynamicMcpConfig({
823655
823961
  configObject: parsedJson,
823656
823962
  filePath: "command line",
823657
823963
  expandVars: true,
@@ -823659,35 +823965,48 @@ ${addendum}` : addendum;
823659
823965
  });
823660
823966
  if (result.config) {
823661
823967
  configs = result.config.mcpServers;
823662
- } else {
823663
- errors8 = result.errors;
823664
823968
  }
823969
+ errors8 = result.errors;
823665
823970
  } else {
823666
823971
  const configPath = resolve63(configItem);
823667
- const result = parseMcpConfigFromFilePath({
823972
+ const result = parseDynamicMcpConfigFromFile({
823668
823973
  filePath: configPath,
823669
823974
  expandVars: true,
823670
823975
  scope: "dynamic"
823671
823976
  });
823672
823977
  if (result.config) {
823673
823978
  configs = result.config.mcpServers;
823674
- } else {
823675
- errors8 = result.errors;
823676
823979
  }
823980
+ errors8 = result.errors;
823677
823981
  }
823678
- if (errors8.length > 0) {
823679
- allErrors.push(...errors8);
823680
- } else if (configs) {
823982
+ if (configs) {
823681
823983
  allConfigs = {
823682
823984
  ...allConfigs,
823683
823985
  ...configs
823684
823986
  };
823987
+ if (errors8.length > 0) {
823988
+ logForDebugging(`--mcp-config: ${errors8.length} entry warning(s): ${errors8.map((err2) => `${err2.path ? err2.path + ": " : ""}${err2.message}`).join("; ")}`, {
823989
+ level: "warn"
823990
+ });
823991
+ for (const err2 of errors8) {
823992
+ const metadata = err2.mcpErrorMetadata;
823993
+ if (metadata?.skipReason && metadata.serverName != null) {
823994
+ skippedCandidates.push({
823995
+ name: metadata.serverName,
823996
+ type: metadata.skipReason,
823997
+ message: err2.message
823998
+ });
823999
+ }
824000
+ }
824001
+ }
824002
+ } else {
824003
+ fatalErrors.push(...errors8);
823685
824004
  }
823686
824005
  }
823687
- if (allErrors.length > 0) {
823688
- const formattedErrors = allErrors.map((err2) => `${err2.path ? err2.path + ": " : ""}${err2.message}`).join(`
824006
+ if (fatalErrors.length > 0) {
824007
+ const formattedErrors = fatalErrors.map((err2) => `${err2.path ? err2.path + ": " : ""}${err2.message}`).join(`
823689
824008
  `);
823690
- logForDebugging(`--mcp-config validation failed (${allErrors.length} errors): ${formattedErrors}`, {
824009
+ logForDebugging(`--mcp-config validation failed (${fatalErrors.length} errors): ${formattedErrors}`, {
823691
824010
  level: "error"
823692
824011
  });
823693
824012
  process.stderr.write(`Error: Invalid MCP configuration:
@@ -823695,25 +824014,27 @@ ${formattedErrors}
823695
824014
  `);
823696
824015
  process.exit(1);
823697
824016
  }
823698
- if (Object.keys(allConfigs).length > 0) {
823699
- const nonSdkConfigNames = Object.entries(allConfigs).filter(([, config8]) => config8.type !== "sdk").map(([name3]) => name3);
823700
- let reservedNameError = null;
823701
- if (nonSdkConfigNames.some(isClaudeInChromeMCPServer)) {
823702
- reservedNameError = `Invalid MCP configuration: "${CLAUDE_IN_CHROME_MCP_SERVER_NAME}" is a reserved MCP name.`;
823703
- } else if (feature("CHICAGO_MCP")) {
823704
- const {
823705
- isComputerUseMCPServer: isComputerUseMCPServer3,
823706
- COMPUTER_USE_MCP_SERVER_NAME: COMPUTER_USE_MCP_SERVER_NAME2
823707
- } = await Promise.resolve().then(() => (init_common(), exports_common));
823708
- if (nonSdkConfigNames.some(isComputerUseMCPServer3)) {
823709
- reservedNameError = `Invalid MCP configuration: "${COMPUTER_USE_MCP_SERVER_NAME2}" is a reserved MCP name.`;
823710
- }
824017
+ const skippedByName = new Map;
824018
+ for (const candidate of skippedCandidates) {
824019
+ if (!Object.hasOwn(allConfigs, candidate.name)) {
824020
+ skippedByName.set(candidate.name, candidate);
823711
824021
  }
823712
- if (reservedNameError) {
823713
- process.stderr.write(`Error: ${reservedNameError}
824022
+ }
824023
+ if (skippedByName.size > 0) {
824024
+ const skipped = Array.from(skippedByName.values());
824025
+ recordSkippedMcpServerErrors(skipped);
824026
+ if (process.stderr.isTTY) {
824027
+ const sanitize = (message) => {
824028
+ const stripped = typeof Bun !== "undefined" && typeof Bun.stripANSI === "function" ? Bun.stripANSI(message) : message;
824029
+ return stripped.replace(/[\x00-\x1f\x7f-\x9f]+/g, " ").trim();
824030
+ };
824031
+ process.stderr.write(`Warning: ${skipped.length} ${plural(skipped.length, "MCP server")} skipped due to invalid config:
824032
+ ${skipped.map((err2) => ` - ${sanitize(err2.message)}`).join(`
824033
+ `)}
823714
824034
  `);
823715
- process.exit(1);
823716
824035
  }
824036
+ }
824037
+ if (Object.keys(allConfigs).length > 0) {
823717
824038
  const scopedConfigs = mapValues_default(allConfigs, (config8) => ({
823718
824039
  ...config8,
823719
824040
  scope: "dynamic"
@@ -826152,7 +826473,7 @@ var init_main7 = __esm(() => {
826152
826473
  init_xaaIdpLogin();
826153
826474
  init_tipRegistry();
826154
826475
  init_api4();
826155
- init_common4();
826476
+ init_skippedMcpServerErrors();
826156
826477
  init_cleanupRegistry();
826157
826478
  init_commitAttribution();
826158
826479
  init_concurrentSessions();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnwenf/occ",
3
- "version": "2.1.291",
3
+ "version": "2.1.293",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {