opencode-anthropic-fix 0.1.0 → 0.1.1

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 (3) hide show
  1. package/README.md +1 -1
  2. package/index.mjs +33 -48
  3. package/package.json +2 -3
package/README.md CHANGED
@@ -44,7 +44,7 @@ The [original plugin](https://github.com/anomalyco/opencode-anthropic-auth) prov
44
44
  - **Configurable strategies** — sticky, round-robin, or hybrid account selection
45
45
  - **Claude Code signature emulation** — full HTTP header, system prompt, beta flag, and metadata mimicry derived from Claude Code's open source code. System prompt cache scoping follows the real CC's three-path `splitSysPromptPrefix()` architecture (boundary/global/org) with exact marker detection and scope-aware `cache_control` generation
46
46
  - **OAuth endpoint fingerprint parity** — matches the real CLI's bundled axios 1.13.6 HTTP client signature (`Accept`, `User-Agent`, `Content-Type`) on all OAuth token endpoint calls, required since 2026-03-21 server-side enforcement
47
- - **Billing header fingerprint parity** — `cc_version` suffix uses the real CLI's 3-char fingerprint hash (SHA-256 of salt + first user message chars + version), `cch` is computed via xxHash64 attestation matching the Bun binary (omitted on bedrock/anthropicAws/mantle), system prompt is sanitized to match Claude Code's pattern validation, and `X-Claude-Code-Session-Id` header is sent on all requests
47
+ - **Billing header fingerprint parity** — `cc_version` suffix uses the real CLI's 3-char fingerprint hash (SHA-256 of salt + first user message chars + version), `cch=00000` is a static placeholder (xxHash64 attestation was removed in Claude Code v2.1.97), system prompt is sanitized to match Claude Code's pattern validation, and `X-Claude-Code-Session-Id` header is sent on all requests
48
48
  - **Adaptive thinking for Opus/Sonnet 4.6** — automatically normalizes thinking to `{type: "adaptive"}` for supported models, with `effort-2025-11-24` beta
49
49
  - **Upstream-aligned auto betas** — 13+ always-on betas matching Claude Code 2.1.92 (`redact-thinking-2026-02-12` available as opt-in to preserve thinking block visibility)
50
50
  - **1M context limit override** — patches `model.limit.context` so OpenCode compacts at the right threshold while `models.dev` catches up
package/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { stdin, stdout } from "node:process";
3
3
  import { randomBytes, randomUUID, createHash as createHashCrypto } from "node:crypto";
4
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
5
  import { join, resolve, basename } from "node:path";
6
- import xxhashInit from "xxhash-wasm";
6
+ // xxhash-wasm import removed: CCH attestation was removed in CC v2.1.97
7
7
  import { AccountManager } from "./lib/accounts.mjs";
8
8
  import { authorize as oauthAuthorize, exchange as oauthExchange, refreshToken } from "./lib/oauth.mjs";
9
9
  import { loadConfig, loadConfigFresh, saveConfig, CLIENT_ID, getConfigDir } from "./lib/config.mjs";
@@ -2815,8 +2815,9 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
2815
2815
  _adaptiveOverride,
2816
2816
  _tokenEconomy,
2817
2817
  );
2818
- // Compute cch attestation: xxHash64 of body with seed, replaces "00000"
2819
- const finalBody = typeof body === "string" ? await computeAndReplaceCch(body) : body;
2818
+ // v2.1.97: cch=00000 is now static (xxHash64 attestation removed).
2819
+ // Send body as-is without cch replacement.
2820
+ const finalBody = body;
2820
2821
 
2821
2822
  // Execute the request
2822
2823
  let response;
@@ -4957,17 +4958,18 @@ process.once("beforeExit", _beforeExitHandler);
4957
4958
  // Request building helpers (extracted from original fetch interceptor)
4958
4959
  // ---------------------------------------------------------------------------
4959
4960
 
4960
- const FALLBACK_CLAUDE_CLI_VERSION = "2.1.96";
4961
+ const FALLBACK_CLAUDE_CLI_VERSION = "2.1.97";
4961
4962
  const CLAUDE_CODE_NPM_LATEST_URL = "https://registry.npmjs.org/@anthropic-ai/claude-code/latest";
4962
- const CLAUDE_CODE_BUILD_TIME = "2026-04-08T03:13:25Z";
4963
+ const CLAUDE_CODE_BUILD_TIME = "2026-04-08T20:46:46Z";
4963
4964
 
4964
- // The @anthropic-ai/sdk version bundled with Claude Code v2.1.96.
4965
+ // The @anthropic-ai/sdk version bundled with Claude Code v2.1.97.
4965
4966
  // This is distinct from the CLI version and goes in X-Stainless-Package-Version.
4966
- // Verified by extracting VERSION="0.208.0" from the bundled cli.js of all versions .80-.96.
4967
+ // Verified by extracting VERSION="0.208.0" from the bundled cli.js of all versions .80-.97.
4967
4968
  const ANTHROPIC_SDK_VERSION = "0.208.0";
4968
4969
 
4969
4970
  // Map of CLI version → bundled SDK version (update when CLI version changes)
4970
4971
  const CLI_TO_SDK_VERSION = new Map([
4972
+ ["2.1.97", "0.208.0"],
4971
4973
  ["2.1.96", "0.208.0"],
4972
4974
  ["2.1.95", "0.208.0"],
4973
4975
  ["2.1.94", "0.208.0"],
@@ -4998,31 +5000,11 @@ function getSdkVersion(cliVersion) {
4998
5000
  const BILLING_HASH_SALT = "59cf53e54c78";
4999
5001
  const BILLING_HASH_INDICES = [4, 7, 20];
5000
5002
 
5001
- // cch attestation: xxHash64 of the full serialized body with seed, masked to 20 bits.
5002
- // Seed is static per CC version, extracted from Bun's compiled Zig layer.
5003
- // See: https://a10k.co/b/reverse-engineering-claude-code-cch.html
5004
- const CCH_SEED = 0x6e52736ac806831en; // BigInt changes per CC version
5005
-
5006
- /** @type {null | ((buf: Uint8Array, seed: bigint) => bigint)} */
5007
- let _xxh64Raw = null;
5008
- const _xxhashReady = xxhashInit().then((h) => {
5009
- _xxh64Raw = h.h64Raw;
5010
- });
5011
-
5012
- /**
5013
- * Compute the cch attestation hash for a serialized request body.
5014
- * @param {string} bodyWithPlaceholder - JSON body containing "cch=00000"
5015
- * @returns {Promise<string>} The body with "cch=00000" replaced by the computed hash
5016
- */
5017
- async function computeAndReplaceCch(bodyWithPlaceholder) {
5018
- if (!bodyWithPlaceholder.includes("cch=00000")) return bodyWithPlaceholder;
5019
- await _xxhashReady;
5020
- if (!_xxh64Raw) return bodyWithPlaceholder;
5021
- const bodyBytes = Buffer.from(bodyWithPlaceholder, "utf-8");
5022
- const hash = _xxh64Raw(bodyBytes, CCH_SEED);
5023
- const cch = (hash & 0xfffffn).toString(16).padStart(5, "0");
5024
- return bodyWithPlaceholder.replace("cch=00000", `cch=${cch}`);
5025
- }
5003
+ // cch attestation: REMOVED in v2.1.97.
5004
+ // Previously (v2.1.96), CC computed xxHash64 of the serialized body and replaced
5005
+ // "cch=00000" with the 20-bit masked hash. In v2.1.97, the xxHash64 computation
5006
+ // was completely removed — "cch=00000" is now sent as a static placeholder.
5007
+ // Sending a computed cch value would now be detected as non-genuine.
5026
5008
 
5027
5009
  /**
5028
5010
  * Compute the billing cache hash (cch) matching Claude Code's NP1() function.
@@ -5250,24 +5232,23 @@ const BEDROCK_UNSUPPORTED_BETAS = new Set([
5250
5232
  "interleaved-thinking-2025-05-14",
5251
5233
  "context-1m-2025-08-07",
5252
5234
  "tool-search-tool-2025-10-19",
5253
- "code-execution-2025-08-25",
5254
- "files-api-2025-04-14",
5255
- "fine-grained-tool-streaming-2025-05-14",
5256
5235
  ]);
5257
5236
  const EXPERIMENTAL_BETA_FLAGS = new Set([
5258
5237
  "adaptive-thinking-2026-01-28",
5259
5238
  "advanced-tool-use-2025-11-20",
5239
+ "advisor-tool-2026-03-01",
5260
5240
  "afk-mode-2026-01-31",
5261
5241
  "code-execution-2025-08-25",
5242
+ "compact-2026-01-12",
5262
5243
  "context-1m-2025-08-07",
5263
5244
  "context-management-2025-06-27",
5264
5245
  "fast-mode-2026-02-01",
5265
5246
  "files-api-2025-04-14",
5266
- "fine-grained-tool-streaming-2025-05-14",
5267
5247
  "interleaved-thinking-2025-05-14",
5268
5248
  "prompt-caching-scope-2026-01-05",
5269
5249
  "redact-thinking-2026-02-12",
5270
5250
  "structured-outputs-2025-12-15",
5251
+ "task-budgets-2026-03-13",
5271
5252
  "tool-search-tool-2025-10-19",
5272
5253
  "web-search-2025-03-05",
5273
5254
  ]);
@@ -5498,12 +5479,17 @@ function isAdaptiveThinkingModel(model) {
5498
5479
 
5499
5480
  /**
5500
5481
  * Check if a model is eligible for 1M context (can receive context-1m beta).
5501
- * This includes models with explicit "1m" in the name AND Opus 4.6.
5482
+ * Real CC v2.1.97 U01(): claude-sonnet-4* || opus-4-6 are eligible.
5483
+ * Also matches explicit "1m" in the name (e.g. "claude-opus-4-6[1m]").
5502
5484
  * @param {string} model
5503
5485
  * @returns {boolean}
5504
5486
  */
5505
5487
  function isEligibleFor1MContext(model) {
5506
- return /(^|[-_ ])1m($|[-_ ])|context[-_]?1m/i.test(model) || isOpus46Model(model);
5488
+ if (!model) return false;
5489
+ // Explicit 1m suffix/tag in model name
5490
+ if (/(^|[-_ ])1m($|[-_ ])|context[-_]?1m|\[1m\]/i.test(model)) return true;
5491
+ // CC v2.1.97 U01: claude-sonnet-4* (any Sonnet 4.x) or opus-4-6
5492
+ return /claude-sonnet-4|sonnet[._-]4/i.test(model) || isOpus46Model(model);
5507
5493
  }
5508
5494
 
5509
5495
  /**
@@ -5664,13 +5650,13 @@ function buildRequestMetadata(input) {
5664
5650
 
5665
5651
  /**
5666
5652
  * Build the billing header block for Claude Code system prompt injection.
5667
- * Claude Code v2.1.96: cc_version includes 3-char fingerprint hash (not model ID).
5668
- * cch is a static "00000" placeholder for Bun native client attestation.
5653
+ * Claude Code v2.1.97: cc_version includes 3-char fingerprint hash (not model ID).
5654
+ * cch is a static "00000" placeholder (xxHash64 attestation removed in v2.1.97).
5669
5655
  *
5670
5656
  * Real CC (system.ts:78): version = `${MACRO.VERSION}.${fingerprint}`
5671
- * Real CC (system.ts:82): cch = feature('NATIVE_CLIENT_ATTESTATION') ? ' cch=00000;' : ''
5657
+ * Real CC (system.ts:82): cch = ' cch=00000;' (static, no longer computed)
5672
5658
  *
5673
- * @param {string} version - CLI version (e.g., "2.1.96")
5659
+ * @param {string} version - CLI version (e.g., "2.1.97")
5674
5660
  * @param {string} [firstUserMessage] - First user message text for fingerprint computation
5675
5661
  * @param {string} [provider] - API provider ("anthropic" | "bedrock" | "vertex" | "foundry" | "anthropicAws" | "mantle")
5676
5662
  * @returns {string}
@@ -5686,10 +5672,8 @@ function buildAnthropicBillingHeader(version, firstUserMessage, provider) {
5686
5672
  // the hash from "000" chars (indices 4,7,20 all missing → fallback "0").
5687
5673
  const fingerprint = computeBillingCacheHash(firstUserMessage || "", version);
5688
5674
  const ccVersion = `${version}.${fingerprint}`;
5689
- // cch: The server may use the PRESENCE of cch as a CC identification signal.
5690
- // Real CC sends cch=00000 placeholder which Bun's Zig stack overwrites.
5691
- // For non-Bun runtimes: send cch=00000 so the server recognizes this as CC.
5692
- // The server should skip attestation verification for all-zeros cch.
5675
+ // cch: v2.1.97 sends static "cch=00000" xxHash64 attestation was removed.
5676
+ // The server uses the PRESENCE of cch=00000 as a CC identification signal.
5693
5677
  const cchDisabled = provider === "bedrock" || provider === "anthropicAws" || provider === "mantle";
5694
5678
  const cchPart = cchDisabled ? "" : " cch=00000;";
5695
5679
  // Build workload part (upstream concatenates directly, no regex replace)
@@ -6689,9 +6673,10 @@ function transformRequestBody(body, signature, runtime, betaHeader, config) {
6689
6673
  }
6690
6674
  }
6691
6675
 
6692
- // Fast mode: inject speed parameter for supported models
6676
+ // Fast mode: inject speed parameter for Opus 4.6 only (v2.1.97 restriction).
6677
+ // Real CC v2.1.97 xJ() checks: model.includes("opus-4-6") — Sonnet is NOT eligible.
6693
6678
  const fastModeEnabled = signature.fastMode && !isFalsyEnv(process.env.OPENCODE_ANTHROPIC_DISABLE_FAST_MODE);
6694
- if (fastModeEnabled && parsed.model && (isOpus46Model(parsed.model) || isSonnet46Model(parsed.model))) {
6679
+ if (fastModeEnabled && parsed.model && isOpus46Model(parsed.model)) {
6695
6680
  parsed.speed = "fast";
6696
6681
  }
6697
6682
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-anthropic-fix",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "GPL-3.0-or-later",
5
5
  "main": "./index.mjs",
6
6
  "files": [
@@ -43,7 +43,6 @@
43
43
  "vitest": "^4.0.18"
44
44
  },
45
45
  "dependencies": {
46
- "@openauthjs/openauth": "^0.4.3",
47
- "xxhash-wasm": "^1.1.0"
46
+ "@openauthjs/openauth": "^0.4.3"
48
47
  }
49
48
  }