@cnwenf/occ 2.1.290 → 2.1.292

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.218](https://img.shields.io/badge/Tracks-Claude%20Code%202.1.218-blueviolet.svg)](https://docs.anthropic.com/en/docs/claude-code)
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)
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.218`). 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.219` — 2.1.218 fully aligned, 2.1.219 partial per OCC-43 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.218` | Reference implementation |
65
+ | **Capability parity** | Tracks CC `2.1.219` (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.218`**.
160
+ - Tracks Claude Code **`2.1.219` (partial)**.
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.219`:2.1.218 已完全对齐、2.1.219 部分对齐)。代码全开放、可审计、无暗门,数据由你掌控。
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.219`**(2.1.218 完全对齐、2.1.219 部分对齐)。
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.290","BINARY_NAME":"occ","BUILD_TIME":"2026-07-29T17:58:05.806Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
2
+ globalThis.MACRO={"VERSION":"2.1.292","BINARY_NAME":"occ","BUILD_TIME":"2026-08-03T20:56:55.105Z","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;
@@ -57625,6 +57625,7 @@ var init_sandboxTypes = __esm(() => {
57625
57625
  allowedDomains: exports_external.array(exports_external.string()).optional(),
57626
57626
  deniedDomains: exports_external.array(exports_external.string()).optional().describe("Domains to block even when a broader allowedDomains wildcard would otherwise permit them."),
57627
57627
  allowManagedDomainsOnly: exports_external.boolean().optional().describe("When true (and set in managed settings), only allowedDomains and WebFetch(domain:...) allow rules from managed settings are respected. " + "User, project, local, and flag settings domains are ignored. Denied domains are still respected from all sources."),
57628
+ strictAllowlist: exports_external.boolean().optional().describe("When true, the sandbox runtime deterministically denies hosts not in allowedDomains instead of prompting. " + "Enforced for sandboxed commands only \u2014 in-process tools such as WebFetch are not gated by this setting. " + "Only honored from user, managed/policy, or CLI (--settings) settings \u2014 " + "project settings (.claude/settings.json and .claude/settings.local.json) are ignored."),
57628
57629
  allowUnixSockets: exports_external.array(exports_external.string()).optional().describe("macOS only: Unix socket paths to allow. Ignored on Linux (seccomp cannot filter by path)."),
57629
57630
  allowAllUnixSockets: exports_external.boolean().optional().describe("If true, allow all Unix sockets (disables blocking on both platforms)."),
57630
57631
  allowLocalBinding: exports_external.boolean().optional(),
@@ -58237,7 +58238,7 @@ var init_hooks = __esm(() => {
58237
58238
  });
58238
58239
 
58239
58240
  // src/services/mcp/types.ts
58240
- 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;
58241
58242
  var init_types = __esm(() => {
58242
58243
  init_v4();
58243
58244
  ConfigScopeSchema = lazySchema(() => exports_external.enum([
@@ -58274,7 +58275,9 @@ var init_types = __esm(() => {
58274
58275
  headersHelper: exports_external.string().optional(),
58275
58276
  oauth: McpOAuthConfigSchema().optional(),
58276
58277
  alwaysLoad: exports_external.boolean().optional(),
58277
- 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()
58278
58281
  }));
58279
58282
  McpSSEIDEServerConfigSchema = lazySchema(() => exports_external.object({
58280
58283
  type: exports_external.literal("sse-ide"),
@@ -58290,13 +58293,15 @@ var init_types = __esm(() => {
58290
58293
  ideRunningInWindows: exports_external.boolean().optional()
58291
58294
  }));
58292
58295
  McpHTTPServerConfigSchema = lazySchema(() => exports_external.object({
58293
- type: exports_external.literal("http"),
58296
+ type: exports_external.enum(["http", "streamable-http"]).transform(() => "http"),
58294
58297
  url: exports_external.string(),
58295
58298
  headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
58296
58299
  headersHelper: exports_external.string().optional(),
58297
58300
  oauth: McpOAuthConfigSchema().optional(),
58298
58301
  alwaysLoad: exports_external.boolean().optional(),
58299
- 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()
58300
58305
  }));
58301
58306
  McpWebSocketServerConfigSchema = lazySchema(() => exports_external.object({
58302
58307
  type: exports_external.literal("ws"),
@@ -58304,7 +58309,9 @@ var init_types = __esm(() => {
58304
58309
  headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
58305
58310
  headersHelper: exports_external.string().optional(),
58306
58311
  alwaysLoad: exports_external.boolean().optional(),
58307
- 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()
58308
58315
  }));
58309
58316
  McpSdkServerConfigSchema = lazySchema(() => exports_external.object({
58310
58317
  type: exports_external.literal("sdk"),
@@ -58329,6 +58336,18 @@ var init_types = __esm(() => {
58329
58336
  McpJsonConfigSchema = lazySchema(() => exports_external.object({
58330
58337
  mcpServers: exports_external.record(exports_external.string(), McpServerConfigSchema())
58331
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
+ };
58332
58351
  });
58333
58352
 
58334
58353
  // src/utils/plugins/schemas.ts
@@ -201072,6 +201091,7 @@ Usage notes:
201072
201091
  // src/utils/sandbox/sandbox-adapter.ts
201073
201092
  var exports_sandbox_adapter = {};
201074
201093
  __export(exports_sandbox_adapter, {
201094
+ shouldEnforceStrictAllowlist: () => shouldEnforceStrictAllowlist,
201075
201095
  shouldAllowManagedSandboxDomainsOnly: () => shouldAllowManagedSandboxDomainsOnly,
201076
201096
  resolveSandboxFilesystemPath: () => resolveSandboxFilesystemPath,
201077
201097
  resolvePathPatternForSandbox: () => resolvePathPatternForSandbox,
@@ -201119,6 +201139,14 @@ function resolveSandboxFilesystemPath(pattern, source) {
201119
201139
  function shouldAllowManagedSandboxDomainsOnly() {
201120
201140
  return getSettingsForSource("policySettings")?.sandbox?.network?.allowManagedDomainsOnly === true;
201121
201141
  }
201142
+ function shouldEnforceStrictAllowlist() {
201143
+ const honoredSources = [
201144
+ "userSettings",
201145
+ "flagSettings",
201146
+ "policySettings"
201147
+ ];
201148
+ return honoredSources.some((source) => getSettingsForSource(source)?.sandbox?.network?.strictAllowlist === true);
201149
+ }
201122
201150
  function shouldAllowManagedReadPathsOnly() {
201123
201151
  return getSettingsForSource("policySettings")?.sandbox?.filesystem?.allowManagedReadPathsOnly === true;
201124
201152
  }
@@ -201480,6 +201508,10 @@ async function initialize3(sandboxAskCallback) {
201480
201508
  logForDebugging(`[sandbox] Blocked network request to ${hostPattern.host} (allowManagedDomainsOnly)`);
201481
201509
  return false;
201482
201510
  }
201511
+ if (shouldEnforceStrictAllowlist()) {
201512
+ logForDebugging(`[sandbox] Blocked network request to ${hostPattern.host} (strictAllowlist)`);
201513
+ return false;
201514
+ }
201483
201515
  return sandboxAskCallback(hostPattern);
201484
201516
  } : undefined;
201485
201517
  initializationPromise2 = (async () => {
@@ -386578,6 +386610,7 @@ function filterMcpServersByPolicy(configs) {
386578
386610
  }
386579
386611
  function expandEnvVars(config6) {
386580
386612
  const missingVars = [];
386613
+ let urlExpandedToEmpty = false;
386581
386614
  function expandString(str2) {
386582
386615
  const { expanded: expanded2, missingVars: vars } = expandEnvVarsInString(str2);
386583
386616
  missingVars.push(...vars);
@@ -386600,9 +386633,11 @@ function expandEnvVars(config6) {
386600
386633
  case "http":
386601
386634
  case "ws": {
386602
386635
  const remoteConfig = config6;
386636
+ const expandedUrl = expandString(remoteConfig.url);
386637
+ urlExpandedToEmpty = remoteConfig.url.trim() !== "" && expandedUrl.trim() === "";
386603
386638
  expanded = {
386604
386639
  ...remoteConfig,
386605
- url: expandString(remoteConfig.url),
386640
+ url: expandedUrl,
386606
386641
  headers: remoteConfig.headers ? mapValues_default(remoteConfig.headers, expandString) : undefined
386607
386642
  };
386608
386643
  break;
@@ -386620,7 +386655,8 @@ function expandEnvVars(config6) {
386620
386655
  }
386621
386656
  return {
386622
386657
  expanded,
386623
- missingVars: [...new Set(missingVars)]
386658
+ missingVars: [...new Set(missingVars)],
386659
+ urlExpandedToEmpty
386624
386660
  };
386625
386661
  }
386626
386662
  async function addMcpConfig(name3, config6, scope) {
@@ -387095,6 +387131,19 @@ function parseMcpConfig(params) {
387095
387131
  }
387096
387132
  function parseMcpConfigFromFilePath(params) {
387097
387133
  const { filePath, expandVars, scope } = params;
387134
+ const read = readMcpConfigFileContents({ filePath, scope });
387135
+ if (read.errors) {
387136
+ return { config: null, errors: read.errors };
387137
+ }
387138
+ return parseMcpConfig({
387139
+ configObject: read.parsedJson,
387140
+ expandVars,
387141
+ scope,
387142
+ filePath
387143
+ });
387144
+ }
387145
+ function readMcpConfigFileContents(params) {
387146
+ const { filePath, scope } = params;
387098
387147
  const fs17 = getFsImplementation();
387099
387148
  let configContent;
387100
387149
  try {
@@ -387103,7 +387152,6 @@ function parseMcpConfigFromFilePath(params) {
387103
387152
  const code = getErrnoCode(error52);
387104
387153
  if (code === "ENOENT") {
387105
387154
  return {
387106
- config: null,
387107
387155
  errors: [
387108
387156
  {
387109
387157
  file: filePath,
@@ -387120,7 +387168,6 @@ function parseMcpConfigFromFilePath(params) {
387120
387168
  }
387121
387169
  logForDebugging(`MCP config read error for ${filePath} (scope=${scope}): ${error52}`, { level: "error" });
387122
387170
  return {
387123
- config: null,
387124
387171
  errors: [
387125
387172
  {
387126
387173
  file: filePath,
@@ -387139,7 +387186,6 @@ function parseMcpConfigFromFilePath(params) {
387139
387186
  if (!parsedJson) {
387140
387187
  logForDebugging(`MCP config is not valid JSON: ${filePath} (scope=${scope}, length=${configContent.length}, first100=${jsonStringify(configContent.slice(0, 100))})`, { level: "error" });
387141
387188
  return {
387142
- config: null,
387143
387189
  errors: [
387144
387190
  {
387145
387191
  file: filePath,
@@ -387154,8 +387200,145 @@ function parseMcpConfigFromFilePath(params) {
387154
387200
  ]
387155
387201
  };
387156
387202
  }
387157
- return parseMcpConfig({
387158
- configObject: parsedJson,
387203
+ return { parsedJson };
387204
+ }
387205
+ function isReservedMcpServerName(name3) {
387206
+ return isClaudeInChromeMCPServer(name3) || isComputerUseMCPServer(name3) || isReservedClaudeBrowserName(name3) || name3 === "workspace";
387207
+ }
387208
+ function findMcpConfigWhitespaceIssues(config6) {
387209
+ const issues = [];
387210
+ function check3(label, value) {
387211
+ if (value !== value.trim()) {
387212
+ issues.push(label);
387213
+ }
387214
+ }
387215
+ if ("command" in config6) {
387216
+ check3("command", config6.command);
387217
+ }
387218
+ if ("url" in config6) {
387219
+ check3("url", config6.url);
387220
+ }
387221
+ if ("args" in config6 && config6.args) {
387222
+ config6.args.forEach((arg, index2) => check3(`args[${index2}]`, arg));
387223
+ }
387224
+ if ("env" in config6 && config6.env) {
387225
+ for (const [envName, envValue] of Object.entries(config6.env)) {
387226
+ if (envName !== envName.trim()) {
387227
+ issues.push(`env name ${jsonStringify(envName)}`);
387228
+ }
387229
+ check3(`env.${envName}`, envValue);
387230
+ }
387231
+ }
387232
+ if ("headers" in config6 && config6.headers) {
387233
+ for (const [headerName, headerValue] of Object.entries(config6.headers)) {
387234
+ if (headerName !== headerName.trim()) {
387235
+ issues.push(`header name ${jsonStringify(headerName)}`);
387236
+ }
387237
+ check3(`headers.${headerName}`, headerValue);
387238
+ }
387239
+ }
387240
+ return issues;
387241
+ }
387242
+ function parseDynamicMcpConfig(params) {
387243
+ const { configObject, expandVars, scope, filePath } = params;
387244
+ const shapeResult = McpJsonConfigShapeSchema().safeParse(configObject);
387245
+ if (!shapeResult.success) {
387246
+ const foundServersKeyInstead = configObject !== null && typeof configObject === "object" && "servers" in configObject && !("mcpServers" in configObject);
387247
+ return {
387248
+ config: null,
387249
+ errors: shapeResult.error.issues.map((issue2) => ({
387250
+ ...filePath && { file: filePath },
387251
+ path: issue2.path.join("."),
387252
+ message: foundServersKeyInstead ? 'Missing "mcpServers" \u2014 found "servers" instead. Claude Code reads MCP servers from the "mcpServers" key.' : issue2.message,
387253
+ ...foundServersKeyInstead && {
387254
+ suggestion: `Rename the top-level "servers" key to "mcpServers" in ${filePath ?? "your MCP config"}.`
387255
+ },
387256
+ mcpErrorMetadata: {
387257
+ scope,
387258
+ severity: "fatal"
387259
+ }
387260
+ }))
387261
+ };
387262
+ }
387263
+ const errors8 = [];
387264
+ const validatedServers = {};
387265
+ function pushEntryError(serverName, message, suggestion, skipReason) {
387266
+ errors8.push({
387267
+ ...filePath && { file: filePath },
387268
+ path: `mcpServers.${serverName}`,
387269
+ message,
387270
+ ...suggestion && { suggestion },
387271
+ mcpErrorMetadata: {
387272
+ scope,
387273
+ serverName,
387274
+ severity: "warning",
387275
+ ...skipReason && { skipReason }
387276
+ }
387277
+ });
387278
+ }
387279
+ const rawServers = configObject.mcpServers;
387280
+ if (Object.hasOwn(rawServers, "__proto__") && !Object.hasOwn(shapeResult.data.mcpServers, "__proto__")) {
387281
+ 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");
387282
+ }
387283
+ for (const [name3, rawEntry] of Object.entries(shapeResult.data.mcpServers)) {
387284
+ const declaredType = rawEntry && typeof rawEntry === "object" && "type" in rawEntry && typeof rawEntry.type === "string" ? rawEntry.type : "stdio";
387285
+ const schemaGetter = Object.hasOwn(MCP_SERVER_TYPE_SCHEMA_REGISTRY, declaredType) ? MCP_SERVER_TYPE_SCHEMA_REGISTRY[declaredType] : undefined;
387286
+ if (!schemaGetter) {
387287
+ 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");
387288
+ continue;
387289
+ }
387290
+ const entryResult = schemaGetter().safeParse(rawEntry);
387291
+ if (!entryResult.success) {
387292
+ if (rawEntry !== null && typeof rawEntry === "object" && !("type" in rawEntry) && "url" in rawEntry && !("command" in rawEntry)) {
387293
+ 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");
387294
+ continue;
387295
+ }
387296
+ const details = entryResult.error.issues.map((issue2) => {
387297
+ const issueMessage = issue2.message.replace(/^Invalid input: /, "");
387298
+ return `${issue2.path.join(".") || "(root)"}: ${issueMessage}`;
387299
+ }).join("; ");
387300
+ pushEntryError(name3, `Skipped \u2014 invalid MCP server config for "${name3}": ${details}`, undefined, "invalid_config");
387301
+ continue;
387302
+ }
387303
+ const validated = entryResult.data;
387304
+ if (isReservedMcpServerName(name3) && validated.type !== "sdk") {
387305
+ 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");
387306
+ continue;
387307
+ }
387308
+ const whitespaceIssues = findMcpConfigWhitespaceIssues(validated);
387309
+ if (whitespaceIssues.length > 0) {
387310
+ 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);
387311
+ }
387312
+ let serverConfig = validated;
387313
+ if (expandVars) {
387314
+ const { expanded, missingVars, urlExpandedToEmpty } = expandEnvVars(validated);
387315
+ if (missingVars.length > 0) {
387316
+ pushEntryError(name3, `Missing environment variables: ${missingVars.join(", ")}`, `Set the following environment variables: ${missingVars.join(", ")}`, undefined);
387317
+ }
387318
+ serverConfig = expanded;
387319
+ if (urlExpandedToEmpty && "url" in validated) {
387320
+ serverConfig = {
387321
+ ...expanded,
387322
+ configError: `'url' ${jsonStringify(validated.url)} expanded to an empty string. Set the referenced environment variable, or update the server's config and reconnect.`,
387323
+ configErrorReason: "url_invalid"
387324
+ };
387325
+ }
387326
+ }
387327
+ validatedServers[name3] = serverConfig;
387328
+ }
387329
+ return {
387330
+ config: { mcpServers: validatedServers },
387331
+ errors: errors8
387332
+ };
387333
+ }
387334
+ function parseDynamicMcpConfigFromFile(params) {
387335
+ const { filePath, expandVars, scope } = params;
387336
+ const read = readMcpConfigFileContents({ filePath, scope });
387337
+ if (read.errors) {
387338
+ return { config: null, errors: read.errors };
387339
+ }
387340
+ return parseDynamicMcpConfig({
387341
+ configObject: read.parsedJson,
387159
387342
  expandVars,
387160
387343
  scope,
387161
387344
  filePath
@@ -387215,6 +387398,7 @@ var init_config6 = __esm(() => {
387215
387398
  init_memoize();
387216
387399
  init_platform2();
387217
387400
  init_common4();
387401
+ init_common();
387218
387402
  init_config4();
387219
387403
  init_cwd2();
387220
387404
  init_debug();
@@ -578430,10 +578614,15 @@ function getSonnet46Option() {
578430
578614
  descriptionForModel: "Sonnet 4.6 - previous Sonnet version"
578431
578615
  };
578432
578616
  }
578617
+ function shouldUseCustomModelOptions() {
578618
+ const provider5 = getAPIProvider();
578619
+ const isAnthropicOwned = provider5 === "firstParty" || provider5 === "anthropic_aws" || provider5 === "gateway";
578620
+ const isAwsOrGoogleCloud = provider5 === "anthropic_aws";
578621
+ return !isAnthropicOwned || isAwsOrGoogleCloud || !isFirstPartyAnthropicBaseUrl();
578622
+ }
578433
578623
  function getCustomFableOption() {
578434
- const is3P = getAPIProvider() !== "firstParty";
578435
578624
  const customFableModel = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL;
578436
- if (is3P && customFableModel) {
578625
+ if (shouldUseCustomModelOptions() && customFableModel) {
578437
578626
  return {
578438
578627
  value: "fable",
578439
578628
  label: process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME ?? customFableModel,
@@ -578456,9 +578645,8 @@ function getFable5Option() {
578456
578645
  };
578457
578646
  }
578458
578647
  function getCustomSonnetOption() {
578459
- const is3P = getAPIProvider() !== "firstParty";
578460
578648
  const customSonnetModel = process.env.ANTHROPIC_DEFAULT_SONNET_MODEL;
578461
- if (is3P && customSonnetModel) {
578649
+ if (shouldUseCustomModelOptions() && customSonnetModel) {
578462
578650
  const is1m = has1mContext(customSonnetModel);
578463
578651
  return {
578464
578652
  value: "sonnet",
@@ -578469,9 +578657,8 @@ function getCustomSonnetOption() {
578469
578657
  }
578470
578658
  }
578471
578659
  function getCustomOpusOption() {
578472
- const is3P = getAPIProvider() !== "firstParty";
578473
578660
  const customOpusModel = process.env.ANTHROPIC_DEFAULT_OPUS_MODEL;
578474
- if (is3P && customOpusModel) {
578661
+ if (shouldUseCustomModelOptions() && customOpusModel) {
578475
578662
  const is1m = has1mContext(customOpusModel);
578476
578663
  return {
578477
578664
  value: "opus",
@@ -578544,9 +578731,8 @@ function getOpus46_1MOption(fastMode = false) {
578544
578731
  };
578545
578732
  }
578546
578733
  function getCustomHaikuOption() {
578547
- const is3P = getAPIProvider() !== "firstParty";
578548
578734
  const customHaikuModel = process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
578549
- if (is3P && customHaikuModel) {
578735
+ if (shouldUseCustomModelOptions() && customHaikuModel) {
578550
578736
  return {
578551
578737
  value: "haiku",
578552
578738
  label: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME ?? customHaikuModel,
@@ -578663,6 +578849,33 @@ function getModelOptionsBase(fastMode = false) {
578663
578849
  return standardOptions;
578664
578850
  }
578665
578851
  if (getAPIProvider() === "firstParty") {
578852
+ const customOpus2 = getCustomOpusOption();
578853
+ const customSonnet2 = getCustomSonnetOption();
578854
+ const customHaiku2 = getCustomHaikuOption();
578855
+ const customFable = getCustomFableOption();
578856
+ if (customOpus2 || customSonnet2 || customHaiku2 || customFable) {
578857
+ const customOptions = [getDefaultOptionForUser(fastMode)];
578858
+ if (customOpus2 !== undefined) {
578859
+ customOptions.push(customOpus2);
578860
+ } else if (isOpus1mMergeEnabled()) {
578861
+ customOptions.push(getMergedOpus1MOption(fastMode));
578862
+ } else {
578863
+ customOptions.push(getOpus5Option(fastMode));
578864
+ if (checkOpus1mAccess()) {
578865
+ customOptions.push(getOpus5_1MOption(fastMode));
578866
+ }
578867
+ }
578868
+ if (customFable !== undefined) {
578869
+ customOptions.push(customFable);
578870
+ }
578871
+ if (customSonnet2 !== undefined) {
578872
+ customOptions.push(customSonnet2);
578873
+ } else if (checkSonnet1mAccess()) {
578874
+ customOptions.push(getSonnet5_1MOption());
578875
+ }
578876
+ customOptions.push(customHaiku2 ?? getHaiku45Option());
578877
+ return customOptions;
578878
+ }
578666
578879
  const payg1POptions = [getDefaultOptionForUser(fastMode)];
578667
578880
  if (checkSonnet1mAccess()) {
578668
578881
  payg1POptions.push(getSonnet5_1MOption());
@@ -812658,6 +812871,18 @@ var init_xaaIdpCommand = __esm(() => {
812658
812871
  init_settings2();
812659
812872
  });
812660
812873
 
812874
+ // src/services/mcp/skippedMcpServerErrors.ts
812875
+ function recordSkippedMcpServerErrors(errors8) {
812876
+ skippedMcpServerErrors.push(...errors8);
812877
+ }
812878
+ function getSkippedMcpServerErrors() {
812879
+ return skippedMcpServerErrors;
812880
+ }
812881
+ var skippedMcpServerErrors;
812882
+ var init_skippedMcpServerErrors = __esm(() => {
812883
+ skippedMcpServerErrors = [];
812884
+ });
812885
+
812661
812886
  // src/utils/cliArgs.ts
812662
812887
  function eagerParseCliFlag(flagName, argv = process.argv) {
812663
812888
  for (let i6 = 0;i6 < argv.length; i6++) {
@@ -814911,7 +815136,7 @@ class QueryEngine {
814911
815136
  yield buildSystemInitMessage({
814912
815137
  tools,
814913
815138
  mcpClients,
814914
- mcpServerErrors: [],
815139
+ mcpServerErrors: getSkippedMcpServerErrors(),
814915
815140
  model: mainLoopModel,
814916
815141
  permissionMode: initialAppState.toolPermissionContext.mode,
814917
815142
  commands: commands7,
@@ -815458,6 +815683,7 @@ var init_QueryEngine = __esm(() => {
815458
815683
  init_paths();
815459
815684
  init_query2();
815460
815685
  init_errors10();
815686
+ init_skippedMcpServerErrors();
815461
815687
  init_Tool();
815462
815688
  init_SyntheticOutputTool();
815463
815689
  init_pointer();
@@ -823631,13 +823857,14 @@ ${addendum}` : addendum;
823631
823857
  if (mcpConfig && mcpConfig.length > 0) {
823632
823858
  const processedConfigs = mcpConfig.map((config8) => config8.trim()).filter((config8) => config8.length > 0);
823633
823859
  let allConfigs = {};
823634
- const allErrors = [];
823860
+ const fatalErrors = [];
823861
+ const skippedCandidates = [];
823635
823862
  for (const configItem of processedConfigs) {
823636
823863
  let configs = null;
823637
823864
  let errors8 = [];
823638
823865
  const parsedJson = safeParseJSON(configItem);
823639
823866
  if (parsedJson) {
823640
- const result = parseMcpConfig({
823867
+ const result = parseDynamicMcpConfig({
823641
823868
  configObject: parsedJson,
823642
823869
  filePath: "command line",
823643
823870
  expandVars: true,
@@ -823645,35 +823872,48 @@ ${addendum}` : addendum;
823645
823872
  });
823646
823873
  if (result.config) {
823647
823874
  configs = result.config.mcpServers;
823648
- } else {
823649
- errors8 = result.errors;
823650
823875
  }
823876
+ errors8 = result.errors;
823651
823877
  } else {
823652
823878
  const configPath = resolve63(configItem);
823653
- const result = parseMcpConfigFromFilePath({
823879
+ const result = parseDynamicMcpConfigFromFile({
823654
823880
  filePath: configPath,
823655
823881
  expandVars: true,
823656
823882
  scope: "dynamic"
823657
823883
  });
823658
823884
  if (result.config) {
823659
823885
  configs = result.config.mcpServers;
823660
- } else {
823661
- errors8 = result.errors;
823662
823886
  }
823887
+ errors8 = result.errors;
823663
823888
  }
823664
- if (errors8.length > 0) {
823665
- allErrors.push(...errors8);
823666
- } else if (configs) {
823889
+ if (configs) {
823667
823890
  allConfigs = {
823668
823891
  ...allConfigs,
823669
823892
  ...configs
823670
823893
  };
823894
+ if (errors8.length > 0) {
823895
+ logForDebugging(`--mcp-config: ${errors8.length} entry warning(s): ${errors8.map((err2) => `${err2.path ? err2.path + ": " : ""}${err2.message}`).join("; ")}`, {
823896
+ level: "warn"
823897
+ });
823898
+ for (const err2 of errors8) {
823899
+ const metadata = err2.mcpErrorMetadata;
823900
+ if (metadata?.skipReason && metadata.serverName != null) {
823901
+ skippedCandidates.push({
823902
+ name: metadata.serverName,
823903
+ type: metadata.skipReason,
823904
+ message: err2.message
823905
+ });
823906
+ }
823907
+ }
823908
+ }
823909
+ } else {
823910
+ fatalErrors.push(...errors8);
823671
823911
  }
823672
823912
  }
823673
- if (allErrors.length > 0) {
823674
- const formattedErrors = allErrors.map((err2) => `${err2.path ? err2.path + ": " : ""}${err2.message}`).join(`
823913
+ if (fatalErrors.length > 0) {
823914
+ const formattedErrors = fatalErrors.map((err2) => `${err2.path ? err2.path + ": " : ""}${err2.message}`).join(`
823675
823915
  `);
823676
- logForDebugging(`--mcp-config validation failed (${allErrors.length} errors): ${formattedErrors}`, {
823916
+ logForDebugging(`--mcp-config validation failed (${fatalErrors.length} errors): ${formattedErrors}`, {
823677
823917
  level: "error"
823678
823918
  });
823679
823919
  process.stderr.write(`Error: Invalid MCP configuration:
@@ -823681,25 +823921,27 @@ ${formattedErrors}
823681
823921
  `);
823682
823922
  process.exit(1);
823683
823923
  }
823684
- if (Object.keys(allConfigs).length > 0) {
823685
- const nonSdkConfigNames = Object.entries(allConfigs).filter(([, config8]) => config8.type !== "sdk").map(([name3]) => name3);
823686
- let reservedNameError = null;
823687
- if (nonSdkConfigNames.some(isClaudeInChromeMCPServer)) {
823688
- reservedNameError = `Invalid MCP configuration: "${CLAUDE_IN_CHROME_MCP_SERVER_NAME}" is a reserved MCP name.`;
823689
- } else if (feature("CHICAGO_MCP")) {
823690
- const {
823691
- isComputerUseMCPServer: isComputerUseMCPServer3,
823692
- COMPUTER_USE_MCP_SERVER_NAME: COMPUTER_USE_MCP_SERVER_NAME2
823693
- } = await Promise.resolve().then(() => (init_common(), exports_common));
823694
- if (nonSdkConfigNames.some(isComputerUseMCPServer3)) {
823695
- reservedNameError = `Invalid MCP configuration: "${COMPUTER_USE_MCP_SERVER_NAME2}" is a reserved MCP name.`;
823696
- }
823924
+ const skippedByName = new Map;
823925
+ for (const candidate of skippedCandidates) {
823926
+ if (!Object.hasOwn(allConfigs, candidate.name)) {
823927
+ skippedByName.set(candidate.name, candidate);
823697
823928
  }
823698
- if (reservedNameError) {
823699
- process.stderr.write(`Error: ${reservedNameError}
823929
+ }
823930
+ if (skippedByName.size > 0) {
823931
+ const skipped = Array.from(skippedByName.values());
823932
+ recordSkippedMcpServerErrors(skipped);
823933
+ if (process.stderr.isTTY) {
823934
+ const sanitize = (message) => {
823935
+ const stripped = typeof Bun !== "undefined" && typeof Bun.stripANSI === "function" ? Bun.stripANSI(message) : message;
823936
+ return stripped.replace(/[\x00-\x1f\x7f-\x9f]+/g, " ").trim();
823937
+ };
823938
+ process.stderr.write(`Warning: ${skipped.length} ${plural(skipped.length, "MCP server")} skipped due to invalid config:
823939
+ ${skipped.map((err2) => ` - ${sanitize(err2.message)}`).join(`
823940
+ `)}
823700
823941
  `);
823701
- process.exit(1);
823702
823942
  }
823943
+ }
823944
+ if (Object.keys(allConfigs).length > 0) {
823703
823945
  const scopedConfigs = mapValues_default(allConfigs, (config8) => ({
823704
823946
  ...config8,
823705
823947
  scope: "dynamic"
@@ -826138,7 +826380,7 @@ var init_main7 = __esm(() => {
826138
826380
  init_xaaIdpLogin();
826139
826381
  init_tipRegistry();
826140
826382
  init_api4();
826141
- init_common4();
826383
+ init_skippedMcpServerErrors();
826142
826384
  init_cleanupRegistry();
826143
826385
  init_commitAttribution();
826144
826386
  init_concurrentSessions();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnwenf/occ",
3
- "version": "2.1.290",
3
+ "version": "2.1.292",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {