@cnwenf/occ 2.1.292 → 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-43 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.219`:2.1.218 已完全对齐、2.1.219 部分对齐)。代码全开放、可审计、无暗门,数据由你掌控。
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.219`**(2.1.218 完全对齐、2.1.219 部分对齐)。
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.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":""};
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;
@@ -359985,9 +359985,7 @@ function collectCommands(node, commands7, varScope) {
359985
359985
  loopVar = child.text;
359986
359986
  } else if (child.type === "do_group") {
359987
359987
  doGroup = child;
359988
- } else if (child.type === "for" || child.type === "in" || child.type === "select" || child.type === ";") {
359989
- continue;
359990
- } 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") {
359991
359989
  const err2 = collectCommandSubstitution(child, commands7, varScope);
359992
359990
  if (err2)
359993
359991
  return err2;
@@ -360174,9 +360172,93 @@ function walkTestExpr(node, argv, innerCommands, varScope) {
360174
360172
  argv.push(node.text);
360175
360173
  return null;
360176
360174
  case "regex":
360177
- 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
+ }
360178
360259
  argv.push(node.text);
360179
360260
  return null;
360261
+ }
360180
360262
  default: {
360181
360263
  const arg = walkArgument(node, innerCommands, varScope);
360182
360264
  if (typeof arg !== "string")
@@ -360618,7 +360700,6 @@ function walkVariableAssignment(node, innerCommands, varScope) {
360618
360700
  name3 = child.text;
360619
360701
  } else if (child.type === "=" || child.type === "+=") {
360620
360702
  isAppend = child.type === "+=";
360621
- continue;
360622
360703
  } else if (child.type === "command_substitution") {
360623
360704
  const err2 = collectCommandSubstitution(child, innerCommands, varScope);
360624
360705
  if (err2)
@@ -360675,7 +360756,7 @@ function walkVariableAssignment(node, innerCommands, varScope) {
360675
360756
  if (!/^[A-Za-z0-9 _+:./=[\]-]*$/.test(value.replace(/\$\{[A-Za-z_][A-Za-z0-9_]*\}/g, ""))) {
360676
360757
  return {
360677
360758
  kind: "too-complex",
360678
- 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`,
360679
360760
  nodeType: "variable_assignment"
360680
360761
  };
360681
360762
  }
@@ -362031,6 +362112,7 @@ var init_killShellTasks = __esm(() => {
362031
362112
  });
362032
362113
 
362033
362114
  // src/tasks/LocalShellTask/LocalShellTask.tsx
362115
+ import { statSync as statSync12 } from "fs";
362034
362116
  import { stat as stat21 } from "fs/promises";
362035
362117
  function looksLikePrompt(tail) {
362036
362118
  const lastLine2 = tail.trimEnd().split(`
@@ -362091,6 +362173,16 @@ The command is likely blocked on an interactive prompt. Kill this task and re-ru
362091
362173
  clearInterval(timer);
362092
362174
  };
362093
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
+ }
362094
362186
  function enqueueShellNotification(taskId, description, status, exitCode, setAppState, toolUseId, kind = "bash", agentId) {
362095
362187
  let shouldEnqueue = false;
362096
362188
  updateTaskState(taskId, setAppState, (task) => {
@@ -362107,12 +362199,15 @@ function enqueueShellNotification(taskId, description, status, exitCode, setAppS
362107
362199
  return;
362108
362200
  }
362109
362201
  abortSpeculation(setAppState);
362202
+ const outputPath = getTaskOutputPath(taskId);
362110
362203
  let summary;
362111
362204
  if (feature("MONITOR_TOOL") && kind === "monitor") {
362112
362205
  switch (status) {
362113
- case "completed":
362114
- summary = `Monitor "${description}" stream ended`;
362206
+ case "completed": {
362207
+ const outputBytes = readMonitorOutputBytes(outputPath);
362208
+ summary = monitorCompletedSummary(description, exitCode, outputBytes);
362115
362209
  break;
362210
+ }
362116
362211
  case "failed":
362117
362212
  summary = `Monitor "${description}" script failed${exitCode !== undefined ? ` (exit ${exitCode})` : ""}`;
362118
362213
  break;
@@ -362133,7 +362228,6 @@ function enqueueShellNotification(taskId, description, status, exitCode, setAppS
362133
362228
  break;
362134
362229
  }
362135
362230
  }
362136
- const outputPath = getTaskOutputPath(taskId);
362137
362231
  const toolUseIdLine = toolUseId ? `
362138
362232
  <${TOOL_USE_ID_TAG}>${toolUseId}</${TOOL_USE_ID_TAG}>` : "";
362139
362233
  const message = `<${TASK_NOTIFICATION_TAG}>
@@ -564823,10 +564917,10 @@ var init_cliui = __esm(() => {
564823
564917
 
564824
564918
  // node_modules/.bun/escalade@3.2.0/node_modules/escalade/sync/index.mjs
564825
564919
  import { dirname as dirname43, resolve as resolve38 } from "path";
564826
- import { readdirSync as readdirSync7, statSync as statSync12 } from "fs";
564920
+ import { readdirSync as readdirSync7, statSync as statSync13 } from "fs";
564827
564921
  function sync_default(start, callback) {
564828
564922
  let dir = resolve38(".", start);
564829
- let tmp, stats = statSync12(dir);
564923
+ let tmp, stats = statSync13(dir);
564830
564924
  if (!stats.isDirectory()) {
564831
564925
  dir = dirname43(dir);
564832
564926
  }
@@ -565853,7 +565947,7 @@ var init_yerror = __esm(() => {
565853
565947
  });
565854
565948
 
565855
565949
  // node_modules/.bun/y18n@5.0.8/node_modules/y18n/build/lib/platform-shims/node.js
565856
- 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";
565857
565951
  import { format as format5 } from "util";
565858
565952
  import { resolve as resolve40 } from "path";
565859
565953
  var node_default2;
@@ -565867,7 +565961,7 @@ var init_node12 = __esm(() => {
565867
565961
  resolve: resolve40,
565868
565962
  exists: (file2) => {
565869
565963
  try {
565870
- return statSync13(file2).isFile();
565964
+ return statSync14(file2).isFile();
565871
565965
  } catch (err2) {
565872
565966
  return false;
565873
565967
  }
@@ -583931,7 +584025,7 @@ __export(exports_workflowDiscovery, {
583931
584025
  USER_WORKFLOWS_DIR: () => USER_WORKFLOWS_DIR,
583932
584026
  PROJECT_WORKFLOWS_DIR: () => PROJECT_WORKFLOWS_DIR
583933
584027
  });
583934
- 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";
583935
584029
  import { homedir as homedir31 } from "os";
583936
584030
  import { join as join109 } from "path";
583937
584031
  function isWorkflowsEnabled() {
@@ -583958,7 +584052,7 @@ function listScripts(dir, source2) {
583958
584052
  continue;
583959
584053
  const full = join109(dir, entry);
583960
584054
  try {
583961
- if (!statSync14(full).isFile())
584055
+ if (!statSync15(full).isFile())
583962
584056
  continue;
583963
584057
  } catch {
583964
584058
  continue;
@@ -583987,7 +584081,7 @@ function resolveWorkflowScript(name3, source2, cwd2 = process.cwd()) {
583987
584081
  const full = join109(dir, `${name3}.js`);
583988
584082
  if (existsSync16(full)) {
583989
584083
  try {
583990
- if (statSync14(full).isFile())
584084
+ if (statSync15(full).isFile())
583991
584085
  return full;
583992
584086
  } catch {}
583993
584087
  }
@@ -639383,7 +639477,7 @@ var init_process2 = () => {};
639383
639477
 
639384
639478
  // src/daemon/lockfile.ts
639385
639479
  import { open as open13, readFile as readFile50, unlink as unlink22, writeFile as writeFile43 } from "fs/promises";
639386
- import { existsSync as existsSync18, statSync as statSync15 } from "fs";
639480
+ import { existsSync as existsSync18, statSync as statSync16 } from "fs";
639387
639481
  import { join as join135 } from "path";
639388
639482
  function getDaemonLockfilePath() {
639389
639483
  return join135(getClaudeConfigHomeDir(), "daemon.lock");
@@ -639528,7 +639622,7 @@ async function displaceHolder() {
639528
639622
  }
639529
639623
  function lockfileMtime() {
639530
639624
  try {
639531
- return statSync15(getDaemonLockfilePath()).mtimeMs;
639625
+ return statSync16(getDaemonLockfilePath()).mtimeMs;
639532
639626
  } catch {
639533
639627
  return null;
639534
639628
  }
@@ -640711,7 +640805,7 @@ __export(exports_supervisor, {
640711
640805
  daemonInstall: () => daemonInstall,
640712
640806
  checkBinaryIdentity: () => checkBinaryIdentity
640713
640807
  });
640714
- import { existsSync as existsSync22, statSync as statSync16 } from "fs";
640808
+ import { existsSync as existsSync22, statSync as statSync17 } from "fs";
640715
640809
  function buildIdentity() {
640716
640810
  return {
640717
640811
  supervisorPid: process.pid,
@@ -640734,7 +640828,7 @@ function checkBinaryIdentity() {
640734
640828
  if (!execPath2 || !existsSync22(execPath2)) {
640735
640829
  return "binary identity unresolvable";
640736
640830
  }
640737
- statSync16(execPath2);
640831
+ statSync17(execPath2);
640738
640832
  } catch {
640739
640833
  return "binary identity unresolvable";
640740
640834
  }
@@ -642700,7 +642794,7 @@ var init_file_index = __esm(() => {
642700
642794
  });
642701
642795
 
642702
642796
  // src/hooks/fileSuggestions.ts
642703
- import { statSync as statSync17 } from "fs";
642797
+ import { statSync as statSync18 } from "fs";
642704
642798
  import * as path35 from "path";
642705
642799
  function getFileIndex() {
642706
642800
  if (!fileIndex) {
@@ -642748,7 +642842,7 @@ function getGitIndexMtime() {
642748
642842
  if (!repoRoot)
642749
642843
  return null;
642750
642844
  try {
642751
- return statSync17(path35.join(repoRoot, ".git", "index")).mtimeMs;
642845
+ return statSync18(path35.join(repoRoot, ".git", "index")).mtimeMs;
642752
642846
  } catch {
642753
642847
  return null;
642754
642848
  }
@@ -700000,7 +700094,7 @@ var init_autocompact2 = __esm(() => {
700000
700094
  });
700001
700095
 
700002
700096
  // src/commands/cd/cdLogic.ts
700003
- import { realpathSync as realpathSync8, statSync as statSync18 } from "fs";
700097
+ import { realpathSync as realpathSync8, statSync as statSync19 } from "fs";
700004
700098
  import { resolve as resolve57 } from "path";
700005
700099
  function resolveDirectoryTarget(target) {
700006
700100
  const resolved = resolve57(target);
@@ -700011,7 +700105,7 @@ function resolveDirectoryTarget(target) {
700011
700105
  return { ok: false, error: `Directory does not exist: ${resolved}` };
700012
700106
  }
700013
700107
  try {
700014
- if (!statSync18(physical).isDirectory()) {
700108
+ if (!statSync19(physical).isDirectory()) {
700015
700109
  return { ok: false, error: `Not a directory: ${resolved}` };
700016
700110
  }
700017
700111
  } catch {
@@ -729276,7 +729370,7 @@ import {
729276
729370
  symlink as symlink5,
729277
729371
  utimes as utimes2
729278
729372
  } from "fs/promises";
729279
- 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";
729280
729374
  import { basename as basename51, dirname as dirname73, join as join166 } from "path";
729281
729375
  function validateWorktreeSlug(slug) {
729282
729376
  if (slug.length > MAX_WORKTREE_SLUG_LENGTH) {
@@ -729323,7 +729417,7 @@ function getLinkedGitWorktreePath() {
729323
729417
  const dotGit = join166(dir, ".git");
729324
729418
  try {
729325
729419
  if (existsSync26(dotGit)) {
729326
- const stats = statSync19(dotGit);
729420
+ const stats = statSync20(dotGit);
729327
729421
  if (stats.isFile()) {
729328
729422
  const content = readFileSync34(dotGit, "utf8").trim();
729329
729423
  if (content.startsWith("gitdir:")) {
@@ -816549,8 +816643,7 @@ function runHeadlessStreaming(structuredIO, mcpClients, commands7, tools, initia
816549
816643
  const mutableMessages = initialMessages;
816550
816644
  let readFileState = extractReadFilesFromMessages(initialMessages, cwd2(), READ_FILE_STATE_CACHE_SIZE);
816551
816645
  const pendingSeeds = createFileStateCacheWithSizeLimit(READ_FILE_STATE_CACHE_SIZE);
816552
- const resumeInterruptedTurnEnv = process.env.CLAUDE_CODE_RESUME_INTERRUPTED_TURN;
816553
- if (turnInterruptionState && turnInterruptionState.kind !== "none" && resumeInterruptedTurnEnv) {
816646
+ if (turnInterruptionState && turnInterruptionState.kind !== "none" && isEnvTruthy(process.env.CLAUDE_CODE_RESUME_INTERRUPTED_TURN)) {
816554
816647
  logForDebugging(`[print.ts] Auto-resuming interrupted turn (kind: ${turnInterruptionState.kind})`);
816555
816648
  removeInterruptedMessage(mutableMessages, turnInterruptionState.message);
816556
816649
  enqueue({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnwenf/occ",
3
- "version": "2.1.292",
3
+ "version": "2.1.293",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {