@cnwenf/occ 2.1.327 → 2.1.328

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +225 -11
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- globalThis.MACRO={"VERSION":"2.1.327","BINARY_NAME":"occ","BUILD_TIME":"2026-09-09T22:35:02.507Z","FEEDBACK_CHANNEL":"","ISSUES_EXPLAINER":"","NATIVE_PACKAGE_URL":"","PACKAGE_URL":"@cnwenf/occ","VERSION_CHANGELOG":""};
2
+ globalThis.MACRO={"VERSION":"2.1.328","BINARY_NAME":"occ","BUILD_TIME":"2026-09-10T19:48:17.557Z","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;
@@ -60319,6 +60319,102 @@ var init_settings = __esm(() => {
60319
60319
  EMPTY_RESULT = Object.freeze({ settings: {}, errors: [] });
60320
60320
  });
60321
60321
 
60322
+ // src/utils/settings/sanitizeAllowlists.ts
60323
+ function issueDetail(error49) {
60324
+ const issue2 = error49.issues[0];
60325
+ if (issue2 === undefined)
60326
+ return "failed validation";
60327
+ return issue2.path.length > 0 ? `${issue2.path.join(".")}: ${issue2.message}` : issue2.message;
60328
+ }
60329
+ function validateAllowlistEntry(key, entry) {
60330
+ if (key === "allowedChannelPlugins") {
60331
+ if (typeof entry === "string") {
60332
+ const at = entry.indexOf("@");
60333
+ const plugin = entry.slice(0, at);
60334
+ const marketplace = entry.slice(at + 1);
60335
+ if (at > 0 && marketplace.length > 0) {
60336
+ return {
60337
+ ok: true,
60338
+ value: { marketplace, plugin },
60339
+ notice: `"allowedChannelPlugins" entry "${entry}" was accepted; prefer the documented object form {"plugin": "${plugin}", "marketplace": "${marketplace}"}.`
60340
+ };
60341
+ }
60342
+ }
60343
+ const parsed2 = CHANNEL_PLUGIN_ENTRY.safeParse(entry);
60344
+ return parsed2.success ? { ok: true, value: parsed2.data } : { ok: false, detail: issueDetail(parsed2.error) };
60345
+ }
60346
+ const parsed = STRING_ENTRY.safeParse(entry);
60347
+ return parsed.success ? { ok: true, value: parsed.data } : { ok: false, detail: issueDetail(parsed.error) };
60348
+ }
60349
+ function sanitizeSecurityAllowlists(data, filePath) {
60350
+ if (!data || typeof data !== "object")
60351
+ return [];
60352
+ const obj = data;
60353
+ const warnings = [];
60354
+ for (const { key, emptyReason } of ALLOWLIST_SPECS) {
60355
+ if (!(key in obj))
60356
+ continue;
60357
+ const raw = obj[key];
60358
+ if (!Array.isArray(raw)) {
60359
+ obj[key] = [];
60360
+ warnings.push({
60361
+ file: filePath,
60362
+ path: key,
60363
+ message: `"${key}" was present but invalid; enforcing an empty allowlist (${emptyReason}) until it is fixed.`,
60364
+ invalidValue: raw
60365
+ });
60366
+ continue;
60367
+ }
60368
+ const valid = [];
60369
+ for (const [index2, entry] of raw.entries()) {
60370
+ const result = validateAllowlistEntry(key, entry);
60371
+ if (result.ok) {
60372
+ valid.push(result.value);
60373
+ if (result.notice !== undefined) {
60374
+ warnings.push({
60375
+ file: filePath,
60376
+ path: `${key}[${index2}]`,
60377
+ message: result.notice
60378
+ });
60379
+ }
60380
+ } else {
60381
+ warnings.push({
60382
+ file: filePath,
60383
+ path: `${key}[${index2}]`,
60384
+ message: `Invalid entry was ignored: ${result.detail}`,
60385
+ invalidValue: entry
60386
+ });
60387
+ }
60388
+ }
60389
+ if (raw.length > 0 && valid.length === 0) {
60390
+ warnings.push({
60391
+ file: filePath,
60392
+ path: key,
60393
+ message: `Every entry of "${key}" was invalid; enforcing an empty allowlist (${emptyReason}) until it is fixed.`
60394
+ });
60395
+ }
60396
+ obj[key] = valid;
60397
+ }
60398
+ return warnings;
60399
+ }
60400
+ var STRING_ENTRY, CHANNEL_PLUGIN_ENTRY, ALLOWLIST_SPECS;
60401
+ var init_sanitizeAllowlists = __esm(() => {
60402
+ init_v4();
60403
+ STRING_ENTRY = exports_external.string();
60404
+ CHANNEL_PLUGIN_ENTRY = exports_external.object({
60405
+ marketplace: exports_external.string(),
60406
+ plugin: exports_external.string()
60407
+ });
60408
+ ALLOWLIST_SPECS = [
60409
+ { key: "allowedHttpHookUrls", emptyReason: "no HTTP hooks may run" },
60410
+ {
60411
+ key: "httpHookAllowedEnvVars",
60412
+ emptyReason: "no environment variables may be interpolated into HTTP hook headers"
60413
+ },
60414
+ { key: "allowedChannelPlugins", emptyReason: "no channel plugins admitted" }
60415
+ ];
60416
+ });
60417
+
60322
60418
  // src/utils/settings/settings.ts
60323
60419
  var exports_settings = {};
60324
60420
  __export(exports_settings, {
@@ -60455,12 +60551,19 @@ function parseSettingsFileUncached(path9) {
60455
60551
  }
60456
60552
  const data = safeParseJSON(content, false);
60457
60553
  const ruleWarnings = filterInvalidPermissionRules(data, path9);
60554
+ const allowlistWarnings = sanitizeSecurityAllowlists(data, path9);
60458
60555
  const result = SettingsSchema().safeParse(data);
60459
60556
  if (!result.success) {
60460
60557
  const errors3 = formatZodError(result.error, path9);
60461
- return { settings: null, errors: [...ruleWarnings, ...errors3] };
60558
+ return {
60559
+ settings: null,
60560
+ errors: [...ruleWarnings, ...allowlistWarnings, ...errors3]
60561
+ };
60462
60562
  }
60463
- return { settings: result.data, errors: ruleWarnings };
60563
+ return {
60564
+ settings: result.data,
60565
+ errors: [...ruleWarnings, ...allowlistWarnings]
60566
+ };
60464
60567
  } catch (error49) {
60465
60568
  handleFileSystemError(error49, path9);
60466
60569
  return { settings: null, errors: [] };
@@ -61086,6 +61189,7 @@ var init_settings2 = __esm(() => {
61086
61189
  init_managedPath();
61087
61190
  init_settings();
61088
61191
  init_settingsCache();
61192
+ init_sanitizeAllowlists();
61089
61193
  init_types2();
61090
61194
  init_validation2();
61091
61195
  MAX_SETTINGS_FILE_BYTES = 2 * 1024 * 1024;
@@ -266184,6 +266288,9 @@ async function* withRetry(getClient2, operation, options) {
266184
266288
  let persistentAttempt = 0;
266185
266289
  let apiKeyHelperAuthRetries = 0;
266186
266290
  const API_KEY_HELPER_AUTH_RETRY_CAP = 2;
266291
+ let awsAuthRetries = 0;
266292
+ let gcpAuthRetries = 0;
266293
+ const CLOUD_AUTH_RETRY_CAP = 2;
266187
266294
  let mediaStrips = 0;
266188
266295
  const MAX_MEDIA_STRIPS = 20;
266189
266296
  for (let attempt = 1;attempt <= maxRetries + 1; attempt++) {
@@ -266312,6 +266419,25 @@ async function* withRetry(getClient2, operation, options) {
266312
266419
  }
266313
266420
  apiKeyHelperAuthRetries++;
266314
266421
  }
266422
+ const cloudCredentialKind = classifyCloudCredentialError(error52);
266423
+ if (cloudCredentialKind === "AWS" || getAPIProvider() !== "firstParty" && isBedrockAuthError(error52)) {
266424
+ if (awsAuthRetries >= CLOUD_AUTH_RETRY_CAP) {
266425
+ logEvent2("api_request", {
266426
+ reason: "api_request_aws_auth_exhausted"
266427
+ });
266428
+ throw new CannotRetryError(error52, retryContext);
266429
+ }
266430
+ awsAuthRetries++;
266431
+ }
266432
+ if (cloudCredentialKind === "Google Cloud" || getAPIProvider() !== "firstParty" && isVertexAuthError(error52)) {
266433
+ if (gcpAuthRetries >= CLOUD_AUTH_RETRY_CAP) {
266434
+ logEvent2("api_request", {
266435
+ reason: "api_request_gcp_auth_exhausted"
266436
+ });
266437
+ throw new CannotRetryError(error52, retryContext);
266438
+ }
266439
+ gcpAuthRetries++;
266440
+ }
266315
266441
  const handledCloudAuthError = handleAwsCredentialError(error52) || handleGcpCredentialError(error52);
266316
266442
  if (!handledCloudAuthError && (!(error52 instanceof APIError) || !shouldRetry(error52))) {
266317
266443
  throw new CannotRetryError(error52, retryContext);
@@ -266474,6 +266600,34 @@ function getFallbackTriggerReason(error52) {
266474
266600
  function isOAuthTokenRevokedError(error52) {
266475
266601
  return error52 instanceof APIError && error52.status === 403 && (error52.message?.includes("OAuth token has been revoked") ?? false);
266476
266602
  }
266603
+ function findInErrorCauseChain(error52, predicate, maxDepth = 5) {
266604
+ let current = error52;
266605
+ for (let depth = 0;depth < maxDepth; depth++) {
266606
+ if (!(current instanceof Error))
266607
+ return;
266608
+ if (predicate(current))
266609
+ return current;
266610
+ current = current.cause;
266611
+ }
266612
+ return;
266613
+ }
266614
+ function errorChainMessageIncludes(error52, needles) {
266615
+ return findInErrorCauseChain(error52, (e4) => needles.some((needle) => e4.message.includes(needle))) !== undefined;
266616
+ }
266617
+ function isGoogleCloudEnv() {
266618
+ return !!(process.env.CLAUDE_CODE_USE_VERTEX || process.env.CLAUDE_CODE_USE_ANTHROPIC_GOOGLE_CLOUD);
266619
+ }
266620
+ function classifyCloudCredentialError(error52) {
266621
+ if (error52 instanceof APIError && error52.status !== undefined)
266622
+ return null;
266623
+ if (findInErrorCauseChain(error52, (e4) => e4.name === "CredentialsProviderError") !== undefined) {
266624
+ return "AWS";
266625
+ }
266626
+ if (isGoogleCloudEnv() && errorChainMessageIncludes(error52, GOOGLE_CREDENTIAL_CLASSIFIER_MESSAGES)) {
266627
+ return "Google Cloud";
266628
+ }
266629
+ return null;
266630
+ }
266477
266631
  function isBedrockAuthError(error52) {
266478
266632
  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK)) {
266479
266633
  if (isAwsCredentialsProviderError(error52) || error52 instanceof APIError && error52.status === 403) {
@@ -266490,10 +266644,11 @@ function handleAwsCredentialError(error52) {
266490
266644
  return false;
266491
266645
  }
266492
266646
  function isGoogleAuthLibraryCredentialError(error52) {
266493
- if (!(error52 instanceof Error))
266494
- return false;
266495
- const msg = error52.message;
266496
- return msg.includes("Could not load the default credentials") || msg.includes("Could not refresh access token") || msg.includes("invalid_grant");
266647
+ return errorChainMessageIncludes(error52, [
266648
+ ...GOOGLE_CREDENTIAL_CLASSIFIER_MESSAGES,
266649
+ GOOGLE_OAUTH_FAILURE_MESSAGE,
266650
+ GOOGLE_TOKEN_REFRESH_FAILURE_MESSAGE
266651
+ ]);
266497
266652
  }
266498
266653
  function isVertexAuthError(error52) {
266499
266654
  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX)) {
@@ -266593,7 +266748,7 @@ function getRateLimitResetDelayMs(error52) {
266593
266748
  return null;
266594
266749
  return Math.min(delayMs, PERSISTENT_RESET_CAP_MS);
266595
266750
  }
266596
- var abortError = () => new APIUserAbortError, DEFAULT_MAX_RETRIES2 = 10, FLOOR_OUTPUT_TOKENS = 3000, MAX_529_RETRIES = 3, BASE_DELAY_MS = 500, MAX_RETRIES_CLAMP = 15, WATCHDOG_DEFAULT_MAX_RETRIES = 300, maxRetriesClampWarned = false, FOREGROUND_529_RETRY_SOURCES, PERSISTENT_MAX_BACKOFF_MS, PERSISTENT_RESET_CAP_MS, HEARTBEAT_INTERVAL_MS = 30000, CannotRetryError, FallbackTriggeredError, DEFAULT_FAST_MODE_FALLBACK_HOLD_MS, SHORT_RETRY_THRESHOLD_MS, MIN_COOLDOWN_MS;
266751
+ var abortError = () => new APIUserAbortError, DEFAULT_MAX_RETRIES2 = 10, FLOOR_OUTPUT_TOKENS = 3000, MAX_529_RETRIES = 3, BASE_DELAY_MS = 500, MAX_RETRIES_CLAMP = 15, WATCHDOG_DEFAULT_MAX_RETRIES = 300, maxRetriesClampWarned = false, FOREGROUND_529_RETRY_SOURCES, PERSISTENT_MAX_BACKOFF_MS, PERSISTENT_RESET_CAP_MS, HEARTBEAT_INTERVAL_MS = 30000, CannotRetryError, FallbackTriggeredError, GOOGLE_CREDENTIAL_CLASSIFIER_MESSAGES, GOOGLE_OAUTH_FAILURE_MESSAGE = "Failed to acquire Google OAuth credentials.", GOOGLE_TOKEN_REFRESH_FAILURE_MESSAGE = "Could not refresh access token", DEFAULT_FAST_MODE_FALLBACK_HOLD_MS, SHORT_RETRY_THRESHOLD_MS, MIN_COOLDOWN_MS;
266597
266752
  var init_withRetry = __esm(() => {
266598
266753
  init_featureFlags();
266599
266754
  init_sdk();
@@ -266659,6 +266814,12 @@ var init_withRetry = __esm(() => {
266659
266814
  this.name = "FallbackTriggeredError";
266660
266815
  }
266661
266816
  };
266817
+ GOOGLE_CREDENTIAL_CLASSIFIER_MESSAGES = [
266818
+ "Could not load the default credentials",
266819
+ "invalid_grant",
266820
+ "invalid_client",
266821
+ "unauthorized_client"
266822
+ ];
266662
266823
  DEFAULT_FAST_MODE_FALLBACK_HOLD_MS = 30 * 60 * 1000;
266663
266824
  SHORT_RETRY_THRESHOLD_MS = 20 * 1000;
266664
266825
  MIN_COOLDOWN_MS = 10 * 60 * 1000;
@@ -377715,7 +377876,8 @@ function getSimpleSandboxSection() {
377715
377876
  ];
377716
377877
  const items = [
377717
377878
  ...sandboxOverrideItems,
377718
- "For temporary files, always use the `$TMPDIR` environment variable. TMPDIR is automatically set to the correct sandbox-writable directory in sandbox mode. Do NOT use `/tmp` directly - use `$TMPDIR` instead."
377879
+ "For temporary files, always use the `$TMPDIR` environment variable. TMPDIR is automatically set to the correct sandbox-writable directory in sandbox mode. Do NOT use `/tmp` directly - use `$TMPDIR` instead.",
377880
+ "If a clipboard utility such as `pbcopy`, `xclip`, or `wl-copy` fails inside the sandbox and the user wants the text on their clipboard, put the text in a fenced code block in your response and tell them to run `/copy` (it copies from outside the sandbox; when the picker appears they can select just that block), rather than writing a file for them to copy manually."
377719
377881
  ];
377720
377882
  return [
377721
377883
  "",
@@ -383975,6 +384137,8 @@ var init_BashTool = __esm(() => {
383975
384137
  timeout: semanticNumber(exports_external.number().optional()).describe(`Optional timeout in milliseconds (max ${getMaxTimeoutMs()})`),
383976
384138
  description: exports_external.string().optional().describe(`Clear, concise description of what this command does in active voice. Never use words like "complex" or "risk" in the description - just describe what it does.
383977
384139
 
384140
+ Say what the command does in plain words: do not echo the command's text, its flags, or file paths - the user reads this description, often without seeing the command.
384141
+
383978
384142
  For simple commands (git, npm, standard CLI tools), keep it brief (5-10 words):
383979
384143
  - ls \u2192 "List files in current directory"
383980
384144
  - git status \u2192 "Show working tree status"
@@ -475491,7 +475655,7 @@ function deserializeMessagesWithInterruptDetection(serializedMessages) {
475491
475655
  turnInterruptionState = internalState;
475492
475656
  }
475493
475657
  const lastRelevantIdx = filteredMessages.findLastIndex((m5) => m5.type !== "system" && m5.type !== "progress");
475494
- if (lastRelevantIdx !== -1 && filteredMessages[lastRelevantIdx].type === "user") {
475658
+ if (lastRelevantIdx !== -1 && filteredMessages[lastRelevantIdx].type === "user" && !isCompleteLocalCommandTail(filteredMessages, lastRelevantIdx)) {
475495
475659
  filteredMessages.splice(lastRelevantIdx + 1, 0, createAssistantMessage({
475496
475660
  content: NO_RESPONSE_REQUESTED
475497
475661
  }));
@@ -475515,6 +475679,9 @@ function detectTurnInterruption(messages) {
475515
475679
  return { kind: "none" };
475516
475680
  }
475517
475681
  if (lastMessage.type === "user") {
475682
+ if (isCompleteLocalCommandTail(messages, lastMessageIdx)) {
475683
+ return { kind: "none" };
475684
+ }
475518
475685
  if (lastMessage.isMeta || lastMessage.isCompactSummary) {
475519
475686
  return { kind: "none" };
475520
475687
  }
@@ -475554,6 +475721,43 @@ function isTerminalToolResult(result, messages, resultIdx) {
475554
475721
  }
475555
475722
  return false;
475556
475723
  }
475724
+ function classifyLocalCommandKind(message) {
475725
+ const content = message.message?.content;
475726
+ const text2 = Array.isArray(content) ? content.findLast((block) => block?.type === "text")?.text : typeof content === "string" ? content : undefined;
475727
+ if (typeof text2 !== "string")
475728
+ return;
475729
+ return LOCAL_COMMAND_TAG_KINDS.find(([prefix]) => text2.startsWith(prefix))?.[1];
475730
+ }
475731
+ function localCommandBreadcrumbKind(message) {
475732
+ if (message.type !== "user")
475733
+ return;
475734
+ if (message.promptSource !== undefined)
475735
+ return;
475736
+ const kind = classifyLocalCommandKind(message);
475737
+ if (kind === "caveat" && message.isMeta !== true)
475738
+ return;
475739
+ return kind;
475740
+ }
475741
+ function isCompleteLocalCommandTail(messages, idx) {
475742
+ if (localCommandBreadcrumbKind(messages[idx]) === undefined)
475743
+ return false;
475744
+ let seenRecord = false;
475745
+ let allMetaUsers = true;
475746
+ for (let i6 = idx;i6 >= 0; i6--) {
475747
+ const msg = messages[i6];
475748
+ if (msg.type === "system" || msg.type === "progress" || msg.type === "attachment") {
475749
+ continue;
475750
+ }
475751
+ const kind = localCommandBreadcrumbKind(msg);
475752
+ if (kind === "caveat")
475753
+ return true;
475754
+ if (kind === undefined || seenRecord)
475755
+ break;
475756
+ seenRecord = kind === "record";
475757
+ allMetaUsers = allMetaUsers && msg.type === "user" && msg.isMeta === true;
475758
+ }
475759
+ return allMetaUsers;
475760
+ }
475557
475761
  function restoreSkillStateFromMessages(messages) {
475558
475762
  for (const message of messages) {
475559
475763
  if (message.type !== "attachment") {
@@ -475671,11 +475875,12 @@ async function loadConversationForResume(source, sourceJsonlFile) {
475671
475875
  throw error52;
475672
475876
  }
475673
475877
  }
475674
- var BRIEF_TOOL_NAME4, LEGACY_BRIEF_TOOL_NAME2, SEND_USER_FILE_TOOL_NAME3;
475878
+ var BRIEF_TOOL_NAME4, LEGACY_BRIEF_TOOL_NAME2, SEND_USER_FILE_TOOL_NAME3, LOCAL_COMMAND_TAG_KINDS;
475675
475879
  var init_conversationRecovery = __esm(() => {
475676
475880
  init_featureFlags();
475677
475881
  init_cwd2();
475678
475882
  init_state();
475883
+ init_xml();
475679
475884
  init_ids();
475680
475885
  init_permissions();
475681
475886
  init_attachments2();
@@ -475688,6 +475893,12 @@ var init_conversationRecovery = __esm(() => {
475688
475893
  BRIEF_TOOL_NAME4 = feature("KAIROS") || feature("KAIROS_BRIEF") ? (init_prompt(), __toCommonJS(exports_prompt)).BRIEF_TOOL_NAME : null;
475689
475894
  LEGACY_BRIEF_TOOL_NAME2 = feature("KAIROS") || feature("KAIROS_BRIEF") ? (init_prompt(), __toCommonJS(exports_prompt)).LEGACY_BRIEF_TOOL_NAME : null;
475690
475895
  SEND_USER_FILE_TOOL_NAME3 = feature("KAIROS") ? (init_prompt8(), __toCommonJS(exports_prompt2)).SEND_USER_FILE_TOOL_NAME : null;
475896
+ LOCAL_COMMAND_TAG_KINDS = [
475897
+ [`<${COMMAND_NAME_TAG}>`, "record"],
475898
+ [`<${LOCAL_COMMAND_STDOUT_TAG}>`, "output"],
475899
+ [`<${LOCAL_COMMAND_STDERR_TAG}>`, "output"],
475900
+ [`<${LOCAL_COMMAND_CAVEAT_TAG}>`, "caveat"]
475901
+ ];
475691
475902
  });
475692
475903
 
475693
475904
  // src/services/api/filesApi.ts
@@ -612335,6 +612546,9 @@ function getCurrentTimestamp() {
612335
612546
  return new Date().toISOString();
612336
612547
  }
612337
612548
  function validatePathWithinBase(basePath, relativePath) {
612549
+ if (process.platform !== "win32" && relativePath.includes("\\")) {
612550
+ throw new Error(`Path traversal detected: "${relativePath}" would escape the base directory`);
612551
+ }
612338
612552
  const resolvedPath = resolve51(basePath, relativePath);
612339
612553
  const normalizedBase = resolve51(basePath) + sep38;
612340
612554
  if (!resolvedPath.startsWith(normalizedBase) && resolvedPath !== resolve51(basePath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnwenf/occ",
3
- "version": "2.1.327",
3
+ "version": "2.1.328",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {