@xtruder/opencode-claude-max-plugin 0.1.17 → 0.2.2

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/build/index.js CHANGED
@@ -1,10 +1,213 @@
1
+ // src/usage.ts
2
+ import {
3
+ closeSync,
4
+ constants as fsConstants,
5
+ mkdirSync,
6
+ openSync,
7
+ readFileSync as readFileSync2,
8
+ renameSync,
9
+ unlinkSync,
10
+ writeFileSync
11
+ } from "node:fs";
12
+ import { homedir as homedir2 } from "node:os";
13
+ import { join as join2 } from "node:path";
14
+
15
+ // src/credentials.ts
16
+ import { existsSync, readFileSync } from "node:fs";
17
+ import { execSync } from "node:child_process";
18
+ import { homedir } from "node:os";
19
+ import { join } from "node:path";
20
+ var CREDENTIAL_CACHE_TTL_MS = 30000;
21
+ var EXPIRY_BUFFER_MS = 60000;
22
+ var cachedCreds = null;
23
+ var cachedAt = 0;
24
+ var cachedPath;
25
+ function getCredentialsPath() {
26
+ return join(homedir(), ".claude", ".credentials.json");
27
+ }
28
+ function readClaudeCredentials(path) {
29
+ const credPath = path ?? getCredentialsPath();
30
+ if (!existsSync(credPath))
31
+ return null;
32
+ try {
33
+ const raw = readFileSync(credPath, "utf-8");
34
+ const parsed = JSON.parse(raw);
35
+ if (!parsed.claudeAiOauth?.accessToken)
36
+ return null;
37
+ return parsed.claudeAiOauth;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+ function isExpired(creds) {
43
+ return Date.now() > creds.expiresAt - EXPIRY_BUFFER_MS;
44
+ }
45
+ function refreshViaCli() {
46
+ const maxAttempts = 2;
47
+ for (let i = 0;i < maxAttempts; i++) {
48
+ try {
49
+ execSync("claude -p . --model haiku", {
50
+ timeout: 60000,
51
+ encoding: "utf-8",
52
+ env: { ...process.env, TERM: "dumb" },
53
+ stdio: "ignore"
54
+ });
55
+ return true;
56
+ } catch {}
57
+ }
58
+ return false;
59
+ }
60
+ function refreshIfNeeded(path) {
61
+ const creds = readClaudeCredentials(path);
62
+ if (!creds)
63
+ return null;
64
+ if (!isExpired(creds))
65
+ return creds;
66
+ console.warn("[anthropic-sdk-provider] OAuth token near expiry, refreshing via Claude CLI...");
67
+ const refreshed = refreshViaCli();
68
+ if (!refreshed) {
69
+ console.warn("[anthropic-sdk-provider] CLI refresh failed. Token may be expired.");
70
+ return creds;
71
+ }
72
+ const fresh = readClaudeCredentials(path);
73
+ if (fresh && !isExpired(fresh)) {
74
+ console.warn("[anthropic-sdk-provider] Token refreshed successfully.");
75
+ return fresh;
76
+ }
77
+ return fresh ?? creds;
78
+ }
79
+ function getCachedCredentials(path) {
80
+ const now = Date.now();
81
+ const resolvedPath = path ?? cachedPath;
82
+ if (cachedCreds && now - cachedAt < CREDENTIAL_CACHE_TTL_MS && !isExpired(cachedCreds)) {
83
+ return cachedCreds;
84
+ }
85
+ const fresh = refreshIfNeeded(resolvedPath);
86
+ if (fresh) {
87
+ cachedCreds = fresh;
88
+ cachedAt = now;
89
+ cachedPath = resolvedPath;
90
+ } else {
91
+ cachedCreds = null;
92
+ }
93
+ return cachedCreds;
94
+ }
95
+
96
+ // src/usage.ts
97
+ var cachedUsage = {};
98
+ var XDG_STATE = process.env.XDG_STATE_HOME || join2(homedir2(), ".local", "state");
99
+ var USAGE_CACHE_DIR = join2(XDG_STATE, "opencode");
100
+ var USAGE_CACHE_FILE = join2(USAGE_CACHE_DIR, "usage-cache.json");
101
+ function emptyCache() {
102
+ return { api: null, headers: null, updatedAt: 0, apiFetchedAt: 0, apiRateLimitUntil: 0 };
103
+ }
104
+ var USAGE_LOCK_FILE = USAGE_CACHE_FILE + ".lock";
105
+ var USAGE_TMP_FILE = USAGE_CACHE_FILE + ".tmp";
106
+ var LOCK_STALE_MS = 5000;
107
+ function acquireLock() {
108
+ try {
109
+ mkdirSync(USAGE_CACHE_DIR, { recursive: true });
110
+ const fd = openSync(USAGE_LOCK_FILE, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY);
111
+ writeFileSync(fd, `${process.pid}
112
+ ${Date.now()}`);
113
+ closeSync(fd);
114
+ return true;
115
+ } catch (err) {
116
+ if (err?.code !== "EEXIST")
117
+ return false;
118
+ try {
119
+ const text = readFileSync2(USAGE_LOCK_FILE, "utf-8");
120
+ const ts = parseInt(text.split(`
121
+ `)[1] ?? "0");
122
+ if (Date.now() - ts > LOCK_STALE_MS) {
123
+ unlinkSync(USAGE_LOCK_FILE);
124
+ return acquireLock();
125
+ }
126
+ } catch {
127
+ try {
128
+ unlinkSync(USAGE_LOCK_FILE);
129
+ } catch {}
130
+ return acquireLock();
131
+ }
132
+ return false;
133
+ }
134
+ }
135
+ function releaseLock() {
136
+ try {
137
+ unlinkSync(USAGE_LOCK_FILE);
138
+ } catch {}
139
+ }
140
+ function readUsageCache() {
141
+ try {
142
+ const text = readFileSync2(USAGE_CACHE_FILE, "utf-8");
143
+ const data = JSON.parse(text);
144
+ if (data && typeof data.updatedAt === "number")
145
+ return data;
146
+ } catch {}
147
+ return emptyCache();
148
+ }
149
+ function writeUsageCache(update) {
150
+ if (!acquireLock())
151
+ return;
152
+ try {
153
+ const existing = readUsageCache();
154
+ const merged = {
155
+ ...existing,
156
+ ...update,
157
+ updatedAt: Date.now()
158
+ };
159
+ mkdirSync(USAGE_CACHE_DIR, { recursive: true });
160
+ writeFileSync(USAGE_TMP_FILE, JSON.stringify(merged));
161
+ renameSync(USAGE_TMP_FILE, USAGE_CACHE_FILE);
162
+ } catch {
163
+ try {
164
+ unlinkSync(USAGE_TMP_FILE);
165
+ } catch {}
166
+ } finally {
167
+ releaseLock();
168
+ }
169
+ }
170
+ function persistCachedUsage() {
171
+ if (cachedUsage.fiveHourUtil == null && cachedUsage.sevenDayUtil == null)
172
+ return;
173
+ writeUsageCache({ headers: { ...cachedUsage } });
174
+ }
175
+ var API_TTL_MS = 5 * 60000;
176
+
177
+ // src/cch.ts
178
+ import xxhashInit from "xxhash-wasm";
179
+ var CCH_SEED = 0x6e52736ac806831en;
180
+ var CCH_PLACEHOLDER = "cch=00000";
181
+ var CCH_MASK = 0xfffffn;
182
+ var hasherPromise = null;
183
+ function getHasher() {
184
+ if (!hasherPromise) {
185
+ hasherPromise = xxhashInit();
186
+ }
187
+ return hasherPromise;
188
+ }
189
+ async function computeCch(body) {
190
+ const hasher = await getHasher();
191
+ const hash = hasher.h64Raw(new TextEncoder().encode(body), CCH_SEED);
192
+ return (hash & CCH_MASK).toString(16).padStart(5, "0");
193
+ }
194
+ function replaceCchPlaceholder(body, cch) {
195
+ return body.replace(CCH_PLACEHOLDER, `cch=${cch}`);
196
+ }
197
+ function hasCchPlaceholder(body) {
198
+ return body.includes(CCH_PLACEHOLDER);
199
+ }
200
+
1
201
  // src/index.ts
2
202
  import Anthropic from "@anthropic-ai/sdk";
3
203
 
204
+ // src/model.ts
205
+ import { APIError, RateLimitError } from "@anthropic-ai/sdk";
206
+
4
207
  // src/tool-names.ts
5
- import { readFileSync, existsSync } from "node:fs";
6
- import { join } from "node:path";
7
- import { homedir } from "node:os";
208
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
209
+ import { homedir as homedir3 } from "node:os";
210
+ import { join as join3 } from "node:path";
8
211
  var BUILTIN_OPENCODE_TO_CLAUDE = {
9
212
  task: "Agent",
10
213
  question: "AskUserQuestion",
@@ -36,15 +239,15 @@ var mcpServerNames = null;
36
239
  function detectMcpServers() {
37
240
  const servers = new Set;
38
241
  const paths = [
39
- join(process.cwd(), ".opencode", "opencode.json"),
40
- join(homedir(), ".config", "opencode", "opencode.json"),
41
- join(homedir(), ".config", "opencode", "opencode.jsonc")
242
+ join3(process.cwd(), ".opencode", "opencode.json"),
243
+ join3(homedir3(), ".config", "opencode", "opencode.json"),
244
+ join3(homedir3(), ".config", "opencode", "opencode.jsonc")
42
245
  ];
43
246
  for (const p of paths) {
44
247
  try {
45
- if (!existsSync(p))
248
+ if (!existsSync2(p))
46
249
  continue;
47
- let raw = readFileSync(p, "utf-8");
250
+ let raw = readFileSync3(p, "utf-8");
48
251
  raw = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
49
252
  const config = JSON.parse(raw);
50
253
  if (config.mcp && typeof config.mcp === "object") {
@@ -130,6 +333,50 @@ function rewriteToolNamesInText(text) {
130
333
  return result;
131
334
  }
132
335
 
336
+ // src/tools.ts
337
+ function cleanSchema(schema) {
338
+ const cleaned = {};
339
+ for (const [key, value] of Object.entries(schema)) {
340
+ if (key === "custom")
341
+ continue;
342
+ if (value && typeof value === "object" && !Array.isArray(value)) {
343
+ cleaned[key] = cleanSchema(value);
344
+ } else {
345
+ cleaned[key] = value;
346
+ }
347
+ }
348
+ if (cleaned.properties && !cleaned.type) {
349
+ cleaned.type = "object";
350
+ }
351
+ return cleaned;
352
+ }
353
+ function convertTools(tools) {
354
+ if (!tools || tools.length === 0)
355
+ return;
356
+ return tools.filter((t) => t.type === "function").map((tool) => ({
357
+ name: toClaudeToolName(tool.name),
358
+ description: tool.description ?? "",
359
+ input_schema: cleanSchema(tool.inputSchema)
360
+ }));
361
+ }
362
+ function convertToolChoice(toolChoice) {
363
+ if (!toolChoice)
364
+ return;
365
+ switch (toolChoice.type) {
366
+ case "auto":
367
+ return { type: "auto" };
368
+ case "required":
369
+ return { type: "any" };
370
+ case "none":
371
+ return;
372
+ case "tool":
373
+ return { type: "tool", name: toClaudeToolName(toolChoice.toolName) };
374
+ }
375
+ }
376
+
377
+ // src/model.ts
378
+ import { createHash, randomBytes } from "node:crypto";
379
+
133
380
  // src/prompt.ts
134
381
  function convertPrompt(prompt) {
135
382
  const systemParts = [];
@@ -272,235 +519,6 @@ function formatToolResultContent(output) {
272
519
  }
273
520
  }
274
521
 
275
- // src/usage-cache.ts
276
- var cachedUsage = {};
277
-
278
- // src/credentials.ts
279
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "node:fs";
280
- import { execSync } from "node:child_process";
281
- import { join as join2 } from "node:path";
282
- import { homedir as homedir2 } from "node:os";
283
- var CREDENTIAL_CACHE_TTL_MS = 30000;
284
- var EXPIRY_BUFFER_MS = 60000;
285
- var cachedCreds = null;
286
- var cachedAt = 0;
287
- var cachedPath;
288
- function getCredentialsPath() {
289
- return join2(homedir2(), ".claude", ".credentials.json");
290
- }
291
- function readClaudeCredentials(path) {
292
- const credPath = path ?? getCredentialsPath();
293
- if (!existsSync2(credPath))
294
- return null;
295
- try {
296
- const raw = readFileSync2(credPath, "utf-8");
297
- const parsed = JSON.parse(raw);
298
- if (!parsed.claudeAiOauth?.accessToken)
299
- return null;
300
- return parsed.claudeAiOauth;
301
- } catch {
302
- return null;
303
- }
304
- }
305
- function isExpired(creds) {
306
- return Date.now() > creds.expiresAt - EXPIRY_BUFFER_MS;
307
- }
308
- function refreshViaCli() {
309
- const maxAttempts = 2;
310
- for (let i = 0;i < maxAttempts; i++) {
311
- try {
312
- execSync("claude -p . --model haiku", {
313
- timeout: 60000,
314
- encoding: "utf-8",
315
- env: { ...process.env, TERM: "dumb" },
316
- stdio: "ignore"
317
- });
318
- return true;
319
- } catch {}
320
- }
321
- return false;
322
- }
323
- function refreshIfNeeded(path) {
324
- const creds = readClaudeCredentials(path);
325
- if (!creds)
326
- return null;
327
- if (!isExpired(creds))
328
- return creds;
329
- console.warn("[anthropic-sdk-provider] OAuth token near expiry, refreshing via Claude CLI...");
330
- const refreshed = refreshViaCli();
331
- if (!refreshed) {
332
- console.warn("[anthropic-sdk-provider] CLI refresh failed. Token may be expired.");
333
- return creds;
334
- }
335
- const fresh = readClaudeCredentials(path);
336
- if (fresh && !isExpired(fresh)) {
337
- console.warn("[anthropic-sdk-provider] Token refreshed successfully.");
338
- return fresh;
339
- }
340
- return fresh ?? creds;
341
- }
342
- function getCachedCredentials(path) {
343
- const now = Date.now();
344
- const resolvedPath = path ?? cachedPath;
345
- if (cachedCreds && now - cachedAt < CREDENTIAL_CACHE_TTL_MS && !isExpired(cachedCreds)) {
346
- return cachedCreds;
347
- }
348
- const fresh = refreshIfNeeded(resolvedPath);
349
- if (fresh) {
350
- cachedCreds = fresh;
351
- cachedAt = now;
352
- cachedPath = resolvedPath;
353
- } else {
354
- cachedCreds = null;
355
- }
356
- return cachedCreds;
357
- }
358
-
359
- // src/usage.ts
360
- var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
361
- async function fetchUsage(credentialsPath) {
362
- const creds = readClaudeCredentials(credentialsPath);
363
- if (!creds)
364
- return null;
365
- if (isExpired(creds))
366
- return null;
367
- const resp = await fetch(USAGE_URL, {
368
- headers: {
369
- authorization: `Bearer ${creds.accessToken}`,
370
- "anthropic-beta": "claude-code-20250219,oauth-2025-04-20",
371
- "content-type": "application/json",
372
- "user-agent": "claude-cli/2.1.81 (external, sdk-cli)",
373
- "x-app": "cli"
374
- }
375
- });
376
- if (!resp.ok) {
377
- const body = await resp.text().catch(() => "");
378
- const msg = body.includes("message") ? JSON.parse(body)?.error?.message ?? body : `HTTP ${resp.status}`;
379
- throw new Error(`Usage API error: ${msg}`);
380
- }
381
- return resp.json();
382
- }
383
- function progressBar(utilization, width = 50) {
384
- const filled = Math.round(utilization / 100 * width);
385
- const bar = "█".repeat(filled) + " ".repeat(width - filled);
386
- return bar;
387
- }
388
- function formatReset(resetsAt) {
389
- if (!resetsAt)
390
- return "";
391
- const reset = new Date(resetsAt);
392
- const now = new Date;
393
- const diffMs = reset.getTime() - now.getTime();
394
- if (diffMs <= 0)
395
- return "Reset now";
396
- const diffMin = Math.floor(diffMs / 60000);
397
- const diffHour = Math.floor(diffMin / 60);
398
- const timeStr = reset.toLocaleTimeString("en-US", {
399
- hour: "numeric",
400
- minute: "2-digit",
401
- timeZoneName: "short"
402
- });
403
- const dateStr = reset.toLocaleDateString("en-US", {
404
- month: "short",
405
- day: "numeric"
406
- });
407
- if (diffHour < 24) {
408
- return `Resets ${timeStr}`;
409
- }
410
- return `Resets ${dateStr}, ${timeStr}`;
411
- }
412
- function formatUsage(data) {
413
- const lines = [];
414
- if (data.five_hour) {
415
- const pct = Math.round(data.five_hour.utilization);
416
- lines.push(" Current session");
417
- lines.push(` ${progressBar(pct)} ${pct}% used`);
418
- lines.push(` ${formatReset(data.five_hour.resets_at)}`);
419
- lines.push("");
420
- }
421
- if (data.seven_day) {
422
- const pct = Math.round(data.seven_day.utilization);
423
- lines.push(" Current week (all models)");
424
- lines.push(` ${progressBar(pct)} ${pct}% used`);
425
- lines.push(` ${formatReset(data.seven_day.resets_at)}`);
426
- lines.push("");
427
- }
428
- if (data.seven_day_sonnet) {
429
- const pct = Math.round(data.seven_day_sonnet.utilization);
430
- lines.push(" Current week (Sonnet only)");
431
- lines.push(` ${progressBar(pct)} ${pct}% used`);
432
- if (data.seven_day_sonnet.resets_at) {
433
- lines.push(` ${formatReset(data.seven_day_sonnet.resets_at)}`);
434
- }
435
- lines.push("");
436
- }
437
- if (data.seven_day_opus) {
438
- const pct = Math.round(data.seven_day_opus.utilization);
439
- lines.push(" Current week (Opus only)");
440
- lines.push(` ${progressBar(pct)} ${pct}% used`);
441
- if (data.seven_day_opus.resets_at) {
442
- lines.push(` ${formatReset(data.seven_day_opus.resets_at)}`);
443
- }
444
- lines.push("");
445
- }
446
- if (data.extra_usage) {
447
- if (data.extra_usage.is_enabled) {
448
- const pct = Math.round(data.extra_usage.utilization ?? 0);
449
- lines.push(" Extra usage");
450
- lines.push(` ${progressBar(pct)} ${pct}% used`);
451
- if (data.extra_usage.monthly_limit != null) {
452
- lines.push(` $${data.extra_usage.used_credits?.toFixed(2) ?? "0.00"} / $${data.extra_usage.monthly_limit.toFixed(2)}`);
453
- }
454
- } else {
455
- lines.push(" Extra usage: disabled");
456
- }
457
- lines.push("");
458
- }
459
- return lines.join(`
460
- `);
461
- }
462
-
463
- // src/tools.ts
464
- function cleanSchema(schema) {
465
- const cleaned = {};
466
- for (const [key, value] of Object.entries(schema)) {
467
- if (key === "custom")
468
- continue;
469
- if (value && typeof value === "object" && !Array.isArray(value)) {
470
- cleaned[key] = cleanSchema(value);
471
- } else {
472
- cleaned[key] = value;
473
- }
474
- }
475
- if (cleaned.properties && !cleaned.type) {
476
- cleaned.type = "object";
477
- }
478
- return cleaned;
479
- }
480
- function convertTools(tools) {
481
- if (!tools || tools.length === 0)
482
- return;
483
- return tools.filter((t) => t.type === "function").map((tool) => ({
484
- name: toClaudeToolName(tool.name),
485
- description: tool.description ?? "",
486
- input_schema: cleanSchema(tool.inputSchema)
487
- }));
488
- }
489
- function convertToolChoice(toolChoice) {
490
- if (!toolChoice)
491
- return;
492
- switch (toolChoice.type) {
493
- case "auto":
494
- return { type: "auto" };
495
- case "required":
496
- return { type: "any" };
497
- case "none":
498
- return;
499
- case "tool":
500
- return { type: "tool", name: toClaudeToolName(toolChoice.toolName) };
501
- }
502
- }
503
-
504
522
  // src/stream.ts
505
523
  var idCounter = 0;
506
524
  function generateId() {
@@ -681,8 +699,6 @@ function processEvent(event, blockStates, modelId) {
681
699
  }
682
700
 
683
701
  // src/model.ts
684
- import { randomBytes, createHash } from "node:crypto";
685
- import { APIError, RateLimitError } from "@anthropic-ai/sdk";
686
702
  function handleApiError(error) {
687
703
  if (error instanceof RateLimitError || error instanceof APIError && error.status === 429) {
688
704
  const h = error.headers;
@@ -732,74 +748,6 @@ function buildMetadata() {
732
748
  user_id: JSON.stringify({ device_id: DEVICE_ID })
733
749
  };
734
750
  }
735
- function isUsageCommand(prompt) {
736
- for (let i = prompt.length - 1;i >= 0; i--) {
737
- const msg = prompt[i];
738
- if (msg.role !== "user")
739
- continue;
740
- const text = msg.content.filter((p) => p.type === "text").map((p) => p.text).join("").trim();
741
- return /^\/usage(\s|$)/i.test(text);
742
- }
743
- return false;
744
- }
745
- function formatReset2(epoch) {
746
- if (!epoch)
747
- return "";
748
- const reset = new Date(epoch * 1000);
749
- const now = new Date;
750
- const diffMs = reset.getTime() - now.getTime();
751
- if (diffMs <= 0)
752
- return "Reset now";
753
- const timeStr = reset.toLocaleTimeString("en-US", {
754
- hour: "numeric",
755
- minute: "2-digit",
756
- timeZoneName: "short"
757
- });
758
- const dateStr = reset.toLocaleDateString("en-US", { month: "short", day: "numeric" });
759
- return diffMs < 86400000 ? `Resets ${timeStr}` : `Resets ${dateStr}, ${timeStr}`;
760
- }
761
- var bar = (pct, width = 50) => "█".repeat(Math.round(pct / 100 * width)) + " ".repeat(width - Math.round(pct / 100 * width));
762
- function formatCachedUsage(usage) {
763
- const lines = [];
764
- const h5 = Math.round((usage.fiveHourUtil ?? 0) * 100);
765
- lines.push(" Current session");
766
- lines.push(` ${bar(h5)} ${h5}% used`);
767
- if (usage.fiveHourReset)
768
- lines.push(` ${formatReset2(usage.fiveHourReset)}`);
769
- lines.push("");
770
- const d7 = Math.round((usage.sevenDayUtil ?? 0) * 100);
771
- lines.push(" Current week");
772
- lines.push(` ${bar(d7)} ${d7}% used`);
773
- if (usage.sevenDayReset)
774
- lines.push(` ${formatReset2(usage.sevenDayReset)}`);
775
- lines.push("");
776
- if (usage.overageStatus === "rejected") {
777
- lines.push(" Extra usage: disabled");
778
- } else if (usage.overageStatus) {
779
- lines.push(` Extra usage: ${usage.overageStatus}`);
780
- }
781
- return lines.join(`
782
- `);
783
- }
784
- async function handleUsageCommand() {
785
- if (cachedUsage.timestamp) {
786
- throw new Error(`Claude Subscription Usage
787
- ` + "─".repeat(52) + `
788
- ` + formatCachedUsage(cachedUsage));
789
- }
790
- try {
791
- const data = await fetchUsage();
792
- if (data) {
793
- throw new Error(`Claude Subscription Usage
794
- ` + "─".repeat(52) + `
795
- ` + formatUsage(data));
796
- }
797
- } catch (e) {
798
- if (e.message?.startsWith("Claude Subscription Usage"))
799
- throw e;
800
- }
801
- throw new Error("No usage data available. Send a message first, then try /usage again.");
802
- }
803
751
 
804
752
  class AnthropicSDKModel {
805
753
  client;
@@ -940,8 +888,6 @@ class AnthropicSDKModel {
940
888
  return { params, warnings };
941
889
  }
942
890
  async doGenerate(options) {
943
- if (isUsageCommand(options.prompt))
944
- await handleUsageCommand();
945
891
  const { params, warnings } = this.buildParams(options);
946
892
  if (!options.maxOutputTokens && params.max_tokens > 4096) {
947
893
  params.max_tokens = 4096;
@@ -1014,8 +960,6 @@ class AnthropicSDKModel {
1014
960
  };
1015
961
  }
1016
962
  async doStream(options) {
1017
- if (isUsageCommand(options.prompt))
1018
- await handleUsageCommand();
1019
963
  const { params, warnings } = this.buildParams(options);
1020
964
  let anthropicStream;
1021
965
  try {
@@ -1078,30 +1022,6 @@ class AnthropicSDKModel {
1078
1022
  }
1079
1023
  }
1080
1024
 
1081
- // src/cch.ts
1082
- import xxhashInit from "xxhash-wasm";
1083
- var CCH_SEED = 0x6e52736ac806831en;
1084
- var CCH_PLACEHOLDER = "cch=00000";
1085
- var CCH_MASK = 0xfffffn;
1086
- var hasherPromise = null;
1087
- function getHasher() {
1088
- if (!hasherPromise) {
1089
- hasherPromise = xxhashInit();
1090
- }
1091
- return hasherPromise;
1092
- }
1093
- async function computeCch(body) {
1094
- const hasher = await getHasher();
1095
- const hash = hasher.h64Raw(new TextEncoder().encode(body), CCH_SEED);
1096
- return (hash & CCH_MASK).toString(16).padStart(5, "0");
1097
- }
1098
- function replaceCchPlaceholder(body, cch) {
1099
- return body.replace(CCH_PLACEHOLDER, `cch=${cch}`);
1100
- }
1101
- function hasCchPlaceholder(body) {
1102
- return body.includes(CCH_PLACEHOLDER);
1103
- }
1104
-
1105
1025
  // src/index.ts
1106
1026
  var CLAUDE_CODE_VERSION = "2.1.81";
1107
1027
  var OAUTH_BETAS = [
@@ -1230,7 +1150,7 @@ function createAnthropicSDK(options = {}) {
1230
1150
  cachedUsage.fiveHourReset = parseInt(resp.headers.get("anthropic-ratelimit-unified-5h-reset") ?? "0");
1231
1151
  cachedUsage.sevenDayReset = parseInt(resp.headers.get("anthropic-ratelimit-unified-7d-reset") ?? "0");
1232
1152
  cachedUsage.overageStatus = resp.headers.get("anthropic-ratelimit-unified-overage-status") ?? undefined;
1233
- cachedUsage.timestamp = Date.now();
1153
+ persistCachedUsage();
1234
1154
  }
1235
1155
  if (resp.status === 429) {
1236
1156
  const unifiedStatus = resp.headers.get("anthropic-ratelimit-unified-status") ?? "";
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAI1B,6BAA6B,EAC7B,2BAA2B,EAE5B,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAA;AAU9C,KAAK,gBAAgB,GAAG,6BAA6B,CAAA;AACrD,KAAK,cAAc,GAAG,2BAA2B,CAAA;AAwLjD,qBAAa,iBAAkB,YAAW,eAAe;IAQrD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IATjB,QAAQ,CAAC,oBAAoB,EAAG,IAAI,CAAS;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAK;gBAGnD,OAAO,EAAE,MAAM,EACP,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAe;IAMlC,OAAO,CAAC,WAAW;IA2Lb,UAAU,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuF1E,QAAQ,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,cAAc,CAAC;CA6E7E"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAG1B,6BAA6B,EAE7B,2BAA2B,EAE5B,MAAM,kBAAkB,CAAA;AAIzB,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAA;AAI9C,KAAK,gBAAgB,GAAG,6BAA6B,CAAA;AACrD,KAAK,cAAc,GAAG,2BAA2B,CAAA;AAkGjD,qBAAa,iBAAkB,YAAW,eAAe;IAQrD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IATjB,QAAQ,CAAC,oBAAoB,EAAG,IAAI,CAAS;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAK;gBAGnD,OAAO,EAAE,MAAM,EACP,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAe;IAMlC,OAAO,CAAC,WAAW;IA2Lb,UAAU,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsF1E,QAAQ,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,cAAc,CAAC;CA4E7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAA0B,MAAM,kBAAkB,CAAA;AACrF,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAA;AAG9C,KAAK,gBAAgB,GAAG,SAAS,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzE,KAAK,oBAAoB,GAAG,SAAS,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAA;AAEnE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,oBAAoB,CAAA;IAC5B,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAiC5E"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACrF,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAA;AAG9C,KAAK,gBAAgB,GAAG,SAAS,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzE,KAAK,oBAAoB,GAAG,SAAS,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAA;AAEnE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,oBAAoB,CAAA;IAC5B,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAiC5E"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Server-side plugin entry point (V1 plugin format).
3
+ *
4
+ * This module re-exports the server plugin in the format expected by
5
+ * OpenCode's V1 plugin loader: `default export { id, server }`.
6
+ *
7
+ * The `./server` export in package.json points here.
8
+ */
9
+ import type { PluginModule } from "@opencode-ai/plugin";
10
+ declare const plugin: PluginModule & {
11
+ id: string;
12
+ };
13
+ export default plugin;
14
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAU,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAO/D,QAAA,MAAM,MAAM,EAAE,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAGxC,CAAA;AAED,eAAe,MAAM,CAAA"}