@rynfar/meridian 1.24.1 → 1.25.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.
@@ -1,19 +1,15 @@
1
- import { createRequire } from "node:module";
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
1
+ import {
2
+ checkPluginConfigured
3
+ } from "./cli-rtab0qa6.js";
4
+ import {
5
+ claudeLog,
6
+ refreshOAuthToken,
7
+ withClaudeLogContext
8
+ } from "./cli-m9pfb7h9.js";
9
+ import {
10
+ __export,
11
+ __require
12
+ } from "./cli-a05ws7rb.js";
17
13
 
18
14
  // node_modules/hono/dist/compose.js
19
15
  var compose = (middleware, onError, onNotFound) => {
@@ -2179,68 +2175,6 @@ var DEFAULT_PROXY_CONFIG = {
2179
2175
  silent: false
2180
2176
  };
2181
2177
 
2182
- // src/logger.ts
2183
- import { AsyncLocalStorage } from "node:async_hooks";
2184
- var contextStore = new AsyncLocalStorage;
2185
- var shouldLog = () => process.env["OPENCODE_CLAUDE_PROVIDER_DEBUG"];
2186
- var shouldLogStreamDebug = () => process.env["OPENCODE_CLAUDE_PROVIDER_STREAM_DEBUG"];
2187
- var isVerboseStreamEvent = (event) => {
2188
- return event.startsWith("stream.") || event === "response.empty_stream";
2189
- };
2190
- var REDACTED_KEYS = new Set([
2191
- "authorization",
2192
- "cookie",
2193
- "x-api-key",
2194
- "apiKey",
2195
- "apikey",
2196
- "prompt",
2197
- "messages",
2198
- "content"
2199
- ]);
2200
- var sanitize = (value) => {
2201
- if (value === null || value === undefined)
2202
- return value;
2203
- if (typeof value === "string") {
2204
- if (value.length > 512) {
2205
- return `${value.slice(0, 512)}... [truncated=${value.length}]`;
2206
- }
2207
- return value;
2208
- }
2209
- if (Array.isArray(value)) {
2210
- return value.map(sanitize);
2211
- }
2212
- if (typeof value === "object") {
2213
- const out = {};
2214
- for (const [k, v] of Object.entries(value)) {
2215
- if (REDACTED_KEYS.has(k)) {
2216
- if (typeof v === "string") {
2217
- out[k] = `[redacted len=${v.length}]`;
2218
- } else if (Array.isArray(v)) {
2219
- out[k] = `[redacted array len=${v.length}]`;
2220
- } else {
2221
- out[k] = "[redacted]";
2222
- }
2223
- } else {
2224
- out[k] = sanitize(v);
2225
- }
2226
- }
2227
- return out;
2228
- }
2229
- return value;
2230
- };
2231
- var withClaudeLogContext = (context, fn) => {
2232
- return contextStore.run(context, fn);
2233
- };
2234
- var claudeLog = (event, extra) => {
2235
- if (!shouldLog())
2236
- return;
2237
- if (isVerboseStreamEvent(event) && !shouldLogStreamDebug())
2238
- return;
2239
- const context = contextStore.getStore() || {};
2240
- const payload = sanitize({ ts: new Date().toISOString(), event, ...context, ...extra || {} });
2241
- console.debug(`[opencode-claude-code-provider] ${JSON.stringify(payload)}`);
2242
- };
2243
-
2244
2178
  // src/proxy/server.ts
2245
2179
  import { exec as execCallback2 } from "child_process";
2246
2180
  import { promisify as promisify3 } from "util";
@@ -6455,6 +6389,11 @@ class DiagnosticLogStore {
6455
6389
  }
6456
6390
  }
6457
6391
  var diagnosticLog = new DiagnosticLogStore;
6392
+ // src/telemetry/routes.ts
6393
+ import { existsSync, readFileSync } from "node:fs";
6394
+ import { resolve, dirname } from "node:path";
6395
+ import { fileURLToPath } from "node:url";
6396
+
6458
6397
  // src/telemetry/dashboard.ts
6459
6398
  var dashboardHtml = `<!DOCTYPE html>
6460
6399
  <html lang="en">
@@ -6462,6 +6401,7 @@ var dashboardHtml = `<!DOCTYPE html>
6462
6401
  <meta charset="utf-8">
6463
6402
  <meta name="viewport" content="width=device-width, initial-scale=1">
6464
6403
  <title>Meridian — Telemetry</title>
6404
+ <link rel="icon" type="image/svg+xml" href="/telemetry/icon.svg">
6465
6405
  <style>
6466
6406
  :root {
6467
6407
  --bg: #0d1117; --surface: #161b22; --border: #30363d;
@@ -6783,11 +6723,21 @@ timer = setInterval(refresh, 5000);
6783
6723
  </html>`;
6784
6724
 
6785
6725
  // src/telemetry/routes.ts
6726
+ var _iconPath = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "assets", "icon.svg");
6727
+ var _iconSvg = existsSync(_iconPath) ? readFileSync(_iconPath, "utf-8") : null;
6786
6728
  function createTelemetryRoutes() {
6787
6729
  const routes = new Hono2;
6788
6730
  routes.get("/", (c) => {
6789
6731
  return c.html(dashboardHtml);
6790
6732
  });
6733
+ routes.get("/icon.svg", (c) => {
6734
+ if (!_iconSvg)
6735
+ return c.notFound();
6736
+ return c.body(_iconSvg, 200, {
6737
+ "Content-Type": "image/svg+xml",
6738
+ "Cache-Control": "public, max-age=3600"
6739
+ });
6740
+ });
6791
6741
  routes.get("/requests", (c) => {
6792
6742
  const limit = Number.parseInt(c.req.query("limit") || "50", 10);
6793
6743
  const since = c.req.query("since") ? Number.parseInt(c.req.query("since"), 10) : undefined;
@@ -6940,6 +6890,13 @@ refresh();setInterval(refresh,10000);
6940
6890
  // src/proxy/errors.ts
6941
6891
  function classifyError(errMsg) {
6942
6892
  const lower = errMsg.toLowerCase();
6893
+ if (lower.includes("oauth token has expired") || lower.includes("not logged in")) {
6894
+ return {
6895
+ status: 401,
6896
+ type: "authentication_error",
6897
+ message: "Claude OAuth token has expired and could not be refreshed automatically. Run 'claude login' in your terminal to re-authenticate."
6898
+ };
6899
+ }
6943
6900
  if (lower.includes("401") || lower.includes("authentication") || lower.includes("invalid auth") || lower.includes("credentials")) {
6944
6901
  return {
6945
6902
  status: 401,
@@ -6948,10 +6905,11 @@ function classifyError(errMsg) {
6948
6905
  };
6949
6906
  }
6950
6907
  if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests")) {
6908
+ const hint = lower.includes("1m") || lower.includes("context") ? " If you're frequently hitting this, set MERIDIAN_SONNET_MODEL=sonnet to use the 200k model instead." : "";
6951
6909
  return {
6952
6910
  status: 429,
6953
6911
  type: "rate_limit_error",
6954
- message: "Claude Max rate limit reached. Wait a moment and try again."
6912
+ message: `Claude Max rate limit reached. Wait a moment and try again.${hint}`
6955
6913
  };
6956
6914
  }
6957
6915
  if (lower.includes("402") || lower.includes("billing") || lower.includes("subscription") || lower.includes("payment")) {
@@ -7014,6 +6972,10 @@ function classifyError(errMsg) {
7014
6972
  message: errMsg || "Unknown error"
7015
6973
  };
7016
6974
  }
6975
+ function isExpiredTokenError(errMsg) {
6976
+ const lower = errMsg.toLowerCase();
6977
+ return lower.includes("oauth token has expired") || lower.includes("not logged in");
6978
+ }
7017
6979
  function isStaleSessionError(error) {
7018
6980
  if (!(error instanceof Error))
7019
6981
  return false;
@@ -7023,12 +6985,16 @@ function isRateLimitError(errMsg) {
7023
6985
  const lower = errMsg.toLowerCase();
7024
6986
  return lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests");
7025
6987
  }
6988
+ function isExtraUsageRequiredError(errMsg) {
6989
+ const lower = errMsg.toLowerCase();
6990
+ return lower.includes("extra usage") && lower.includes("1m");
6991
+ }
7026
6992
 
7027
6993
  // src/proxy/models.ts
7028
6994
  import { exec as execCallback } from "child_process";
7029
- import { existsSync } from "fs";
7030
- import { fileURLToPath } from "url";
7031
- import { join, dirname } from "path";
6995
+ import { existsSync as existsSync2 } from "fs";
6996
+ import { fileURLToPath as fileURLToPath2 } from "url";
6997
+ import { join, dirname as dirname2 } from "path";
7032
6998
  import { promisify } from "util";
7033
6999
  var exec = promisify(execCallback);
7034
7000
  var AUTH_STATUS_CACHE_TTL_MS = 60000;
@@ -7043,19 +7009,35 @@ function supports1mContext(model) {
7043
7009
  return false;
7044
7010
  return true;
7045
7011
  }
7046
- function mapModelToClaudeModel(model, subscriptionType) {
7012
+ function mapModelToClaudeModel(model, subscriptionType, agentMode) {
7047
7013
  if (model.includes("haiku"))
7048
7014
  return "haiku";
7049
7015
  const use1m = supports1mContext(model);
7050
- if (model.includes("opus"))
7051
- return use1m ? "opus[1m]" : "opus";
7016
+ const isSubagent = agentMode === "subagent";
7017
+ if (model.includes("opus")) {
7018
+ if (use1m && !isSubagent && !isExtendedContextKnownUnavailable())
7019
+ return "opus[1m]";
7020
+ return "opus";
7021
+ }
7052
7022
  const sonnetOverride = process.env.MERIDIAN_SONNET_MODEL ?? process.env.CLAUDE_PROXY_SONNET_MODEL;
7053
7023
  if (sonnetOverride === "sonnet" || sonnetOverride === "sonnet[1m]")
7054
7024
  return sonnetOverride;
7055
7025
  if (!use1m)
7056
7026
  return "sonnet";
7027
+ if (isSubagent)
7028
+ return "sonnet";
7029
+ if (isExtendedContextKnownUnavailable())
7030
+ return "sonnet";
7057
7031
  return subscriptionType === "max" ? "sonnet[1m]" : "sonnet";
7058
7032
  }
7033
+ var EXTRA_USAGE_RETRY_MS = 60 * 60 * 1000;
7034
+ var extraUsageUnavailableAt = 0;
7035
+ function recordExtendedContextUnavailable() {
7036
+ extraUsageUnavailableAt = Date.now();
7037
+ }
7038
+ function isExtendedContextKnownUnavailable() {
7039
+ return extraUsageUnavailableAt > 0 && Date.now() - extraUsageUnavailableAt < EXTRA_USAGE_RETRY_MS;
7040
+ }
7059
7041
  function stripExtendedContext(model) {
7060
7042
  if (model === "opus[1m]")
7061
7043
  return "opus";
@@ -7106,9 +7088,9 @@ async function resolveClaudeExecutableAsync() {
7106
7088
  const runningUnderBun = typeof process.versions.bun !== "undefined";
7107
7089
  if (runningUnderBun) {
7108
7090
  try {
7109
- const sdkPath = fileURLToPath(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
7110
- const sdkCliJs = join(dirname(sdkPath), "cli.js");
7111
- if (existsSync(sdkCliJs)) {
7091
+ const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
7092
+ const sdkCliJs = join(dirname2(sdkPath), "cli.js");
7093
+ if (existsSync2(sdkCliJs)) {
7112
7094
  cachedClaudePath = sdkCliJs;
7113
7095
  return sdkCliJs;
7114
7096
  }
@@ -7117,16 +7099,16 @@ async function resolveClaudeExecutableAsync() {
7117
7099
  try {
7118
7100
  const { stdout } = await exec("which claude");
7119
7101
  const claudePath = stdout.trim();
7120
- if (claudePath && existsSync(claudePath)) {
7102
+ if (claudePath && existsSync2(claudePath)) {
7121
7103
  cachedClaudePath = claudePath;
7122
7104
  return claudePath;
7123
7105
  }
7124
7106
  } catch {}
7125
7107
  if (!runningUnderBun) {
7126
7108
  try {
7127
- const sdkPath = fileURLToPath(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
7128
- const sdkCliJs = join(dirname(sdkPath), "cli.js");
7129
- if (existsSync(sdkCliJs)) {
7109
+ const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
7110
+ const sdkCliJs = join(dirname2(sdkPath), "cli.js");
7111
+ if (existsSync2(sdkCliJs)) {
7130
7112
  cachedClaudePath = sdkCliJs;
7131
7113
  return sdkCliJs;
7132
7114
  }
@@ -7218,6 +7200,17 @@ function createFileChangeHook(changes, mcpPrefix) {
7218
7200
  }]
7219
7201
  };
7220
7202
  }
7203
+ function isLikelyFilePath(s) {
7204
+ if (/[()[\]]/.test(s))
7205
+ return false;
7206
+ if (/^-?\d+$/.test(s))
7207
+ return false;
7208
+ if (/^[{}]$/.test(s))
7209
+ return false;
7210
+ if (!/[\w/.]/.test(s))
7211
+ return false;
7212
+ return true;
7213
+ }
7221
7214
  function extractFileChangesFromBash(command) {
7222
7215
  const changes = [];
7223
7216
  const seen = new Set;
@@ -7232,10 +7225,12 @@ function extractFileChangesFromBash(command) {
7232
7225
  changes.push({ operation, path });
7233
7226
  }
7234
7227
  };
7235
- const redirectRegex = /(?<![0-9])>{1,2}\s*['"]?([^\s'";&|)]+)['"]?/g;
7228
+ const redirectRegex = /(?<![0-9=])>{1,2}\s*['"]?([^\s'";&|)]+)['"]?/g;
7236
7229
  let match2;
7237
7230
  while ((match2 = redirectRegex.exec(command)) !== null) {
7238
- addChange("wrote", match2[1]);
7231
+ if (isLikelyFilePath(match2[1])) {
7232
+ addChange("wrote", match2[1]);
7233
+ }
7239
7234
  }
7240
7235
  const teeRegex = /\btee\s+(?:-[a-zA-Z]\s+)*['"]?([^\s'";&|)]+)['"]?/g;
7241
7236
  while ((match2 = teeRegex.exec(command)) !== null) {
@@ -9203,7 +9198,7 @@ minimatch.escape = escape;
9203
9198
  minimatch.unescape = unescape;
9204
9199
 
9205
9200
  // node_modules/glob/dist/esm/glob.js
9206
- import { fileURLToPath as fileURLToPath3 } from "node:url";
9201
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
9207
9202
 
9208
9203
  // node_modules/lru-cache/dist/esm/index.js
9209
9204
  var defaultPerf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
@@ -10366,7 +10361,7 @@ class LRUCache {
10366
10361
 
10367
10362
  // node_modules/path-scurry/dist/esm/index.js
10368
10363
  import { posix, win32 } from "node:path";
10369
- import { fileURLToPath as fileURLToPath2 } from "node:url";
10364
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
10370
10365
  import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSync as rps } from "fs";
10371
10366
  import * as actualFS from "node:fs";
10372
10367
  import { lstat, readdir, readlink, realpath } from "node:fs/promises";
@@ -10913,10 +10908,10 @@ class Minipass extends EventEmitter {
10913
10908
  return this[ENCODING] ? buf.join("") : Buffer.concat(buf, buf.dataLength);
10914
10909
  }
10915
10910
  async promise() {
10916
- return new Promise((resolve, reject) => {
10911
+ return new Promise((resolve2, reject) => {
10917
10912
  this.on(DESTROYED, () => reject(new Error("stream destroyed")));
10918
10913
  this.on("error", (er) => reject(er));
10919
- this.on("end", () => resolve());
10914
+ this.on("end", () => resolve2());
10920
10915
  });
10921
10916
  }
10922
10917
  [Symbol.asyncIterator]() {
@@ -10935,7 +10930,7 @@ class Minipass extends EventEmitter {
10935
10930
  return Promise.resolve({ done: false, value: res });
10936
10931
  if (this[EOF])
10937
10932
  return stop();
10938
- let resolve;
10933
+ let resolve2;
10939
10934
  let reject;
10940
10935
  const onerr = (er) => {
10941
10936
  this.off("data", ondata);
@@ -10949,19 +10944,19 @@ class Minipass extends EventEmitter {
10949
10944
  this.off("end", onend);
10950
10945
  this.off(DESTROYED, ondestroy);
10951
10946
  this.pause();
10952
- resolve({ value, done: !!this[EOF] });
10947
+ resolve2({ value, done: !!this[EOF] });
10953
10948
  };
10954
10949
  const onend = () => {
10955
10950
  this.off("error", onerr);
10956
10951
  this.off("data", ondata);
10957
10952
  this.off(DESTROYED, ondestroy);
10958
10953
  stop();
10959
- resolve({ done: true, value: undefined });
10954
+ resolve2({ done: true, value: undefined });
10960
10955
  };
10961
10956
  const ondestroy = () => onerr(new Error("stream destroyed"));
10962
10957
  return new Promise((res2, rej) => {
10963
10958
  reject = rej;
10964
- resolve = res2;
10959
+ resolve2 = res2;
10965
10960
  this.once(DESTROYED, ondestroy);
10966
10961
  this.once("error", onerr);
10967
10962
  this.once("end", onend);
@@ -11661,8 +11656,8 @@ class PathBase {
11661
11656
  if (this.#asyncReaddirInFlight) {
11662
11657
  await this.#asyncReaddirInFlight;
11663
11658
  } else {
11664
- let resolve = () => {};
11665
- this.#asyncReaddirInFlight = new Promise((res) => resolve = res);
11659
+ let resolve2 = () => {};
11660
+ this.#asyncReaddirInFlight = new Promise((res) => resolve2 = res);
11666
11661
  try {
11667
11662
  for (const e of await this.#fs.promises.readdir(fullpath, {
11668
11663
  withFileTypes: true
@@ -11675,7 +11670,7 @@ class PathBase {
11675
11670
  children.provisional = 0;
11676
11671
  }
11677
11672
  this.#asyncReaddirInFlight = undefined;
11678
- resolve();
11673
+ resolve2();
11679
11674
  }
11680
11675
  return children.slice(0, children.provisional);
11681
11676
  }
@@ -11821,7 +11816,7 @@ class PathScurryBase {
11821
11816
  constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS } = {}) {
11822
11817
  this.#fs = fsFromOption(fs);
11823
11818
  if (cwd instanceof URL || cwd.startsWith("file://")) {
11824
- cwd = fileURLToPath2(cwd);
11819
+ cwd = fileURLToPath3(cwd);
11825
11820
  }
11826
11821
  const cwdPath = pathImpl.resolve(cwd);
11827
11822
  this.roots = Object.create(null);
@@ -13125,7 +13120,7 @@ class Glob {
13125
13120
  if (!opts.cwd) {
13126
13121
  this.cwd = "";
13127
13122
  } else if (opts.cwd instanceof URL || opts.cwd.startsWith("file://")) {
13128
- opts.cwd = fileURLToPath3(opts.cwd);
13123
+ opts.cwd = fileURLToPath4(opts.cwd);
13129
13124
  }
13130
13125
  this.cwd = opts.cwd || "";
13131
13126
  this.root = opts.root;
@@ -13679,10 +13674,10 @@ class LRUMap {
13679
13674
  // src/proxy/sessionStore.ts
13680
13675
  import {
13681
13676
  closeSync,
13682
- existsSync as existsSync2,
13677
+ existsSync as existsSync3,
13683
13678
  mkdirSync,
13684
13679
  openSync,
13685
- readFileSync,
13680
+ readFileSync as readFileSync2,
13686
13681
  renameSync,
13687
13682
  statSync,
13688
13683
  unlinkSync,
@@ -13737,7 +13732,7 @@ var sessionDirOverride = null;
13737
13732
  var skipLocking = false;
13738
13733
  function getStorePath() {
13739
13734
  const dir = sessionDirOverride || process.env.MERIDIAN_SESSION_DIR || process.env.CLAUDE_PROXY_SESSION_DIR || getDefaultCacheDir();
13740
- if (!existsSync2(dir)) {
13735
+ if (!existsSync3(dir)) {
13741
13736
  mkdirSync(dir, { recursive: true });
13742
13737
  }
13743
13738
  return join2(dir, "sessions.json");
@@ -13745,9 +13740,9 @@ function getStorePath() {
13745
13740
  function getDefaultCacheDir() {
13746
13741
  const newDir = join2(homedir(), ".cache", "meridian");
13747
13742
  const oldDir = join2(homedir(), ".cache", "opencode-claude-max-proxy");
13748
- if (existsSync2(newDir))
13743
+ if (existsSync3(newDir))
13749
13744
  return newDir;
13750
- if (existsSync2(oldDir)) {
13745
+ if (existsSync3(oldDir)) {
13751
13746
  try {
13752
13747
  const { symlinkSync } = __require("fs");
13753
13748
  symlinkSync(oldDir, newDir);
@@ -13760,10 +13755,10 @@ function getDefaultCacheDir() {
13760
13755
  }
13761
13756
  function readStore() {
13762
13757
  const path3 = getStorePath();
13763
- if (!existsSync2(path3))
13758
+ if (!existsSync3(path3))
13764
13759
  return {};
13765
13760
  try {
13766
- const data = readFileSync(path3, "utf-8");
13761
+ const data = readFileSync2(path3, "utf-8");
13767
13762
  return JSON.parse(data);
13768
13763
  } catch (e) {
13769
13764
  console.error("[sessionStore] read failed:", e.message);
@@ -14112,8 +14107,8 @@ function createProxyServer(config = {}) {
14112
14107
  activeSessions++;
14113
14108
  return;
14114
14109
  }
14115
- return new Promise((resolve2) => {
14116
- sessionQueue.push({ resolve: resolve2 });
14110
+ return new Promise((resolve3) => {
14111
+ sessionQueue.push({ resolve: resolve3 });
14117
14112
  });
14118
14113
  }
14119
14114
  function releaseSession() {
@@ -14149,11 +14144,15 @@ function createProxyServer(config = {}) {
14149
14144
  return textPrompt;
14150
14145
  };
14151
14146
  const body = await c.req.json();
14147
+ if (!Array.isArray(body.messages)) {
14148
+ return c.json({ type: "error", error: { type: "invalid_request_error", message: "messages: Field required" } }, 400);
14149
+ }
14152
14150
  const authStatus = await getClaudeAuthStatusAsync();
14153
- let model = mapModelToClaudeModel(body.model || "sonnet", authStatus?.subscriptionType);
14151
+ const agentMode = c.req.header("x-opencode-agent-mode") ?? null;
14152
+ let model = mapModelToClaudeModel(body.model || "sonnet", authStatus?.subscriptionType, agentMode);
14154
14153
  const adapter = detectAdapter(c);
14155
14154
  const adapterStreamPref = adapter.prefersStreaming?.(body);
14156
- const stream2 = adapterStreamPref !== undefined ? adapterStreamPref : body.stream ?? true;
14155
+ const stream2 = adapterStreamPref !== undefined ? adapterStreamPref : body.stream ?? false;
14157
14156
  const workingDirectory = (process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR) || adapter.extractWorkingDirectory(body) || process.cwd();
14158
14157
  const {
14159
14158
  CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS,
@@ -14184,7 +14183,7 @@ function createProxyServer(config = {}) {
14184
14183
  }).join(" → ");
14185
14184
  const lineageType = lineageResult.type === "diverged" && !cachedSession ? "new" : lineageResult.type;
14186
14185
  const msgCount = Array.isArray(body.messages) ? body.messages.length : 0;
14187
- const requestLogLine = `${requestMeta.requestId} model=${model} stream=${stream2} tools=${body.tools?.length ?? 0} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
14186
+ const requestLogLine = `${requestMeta.requestId} model=${model} stream=${stream2} tools=${body.tools?.length ?? 0} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
14188
14187
  console.error(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
14189
14188
  diagnosticLog.session(`${requestLogLine}`, requestMeta.requestId);
14190
14189
  claudeLog("request.received", {
@@ -14352,6 +14351,7 @@ function createProxyServer(config = {}) {
14352
14351
  const RATE_LIMIT_BASE_DELAY_MS = 1000;
14353
14352
  const response = async function* () {
14354
14353
  let rateLimitRetries = 0;
14354
+ let tokenRefreshed = false;
14355
14355
  while (true) {
14356
14356
  let didYieldContent = false;
14357
14357
  try {
@@ -14373,7 +14373,7 @@ function createProxyServer(config = {}) {
14373
14373
  adapter,
14374
14374
  onStderr
14375
14375
  }))) {
14376
- if (event.type === "assistant") {
14376
+ if (event.type === "assistant" && !event.error) {
14377
14377
  didYieldContent = true;
14378
14378
  }
14379
14379
  yield event;
@@ -14414,6 +14414,28 @@ function createProxyServer(config = {}) {
14414
14414
  }));
14415
14415
  return;
14416
14416
  }
14417
+ if (isExtraUsageRequiredError(errMsg) && hasExtendedContext(model)) {
14418
+ const from = model;
14419
+ model = stripExtendedContext(model);
14420
+ recordExtendedContextUnavailable();
14421
+ claudeLog("upstream.context_fallback", {
14422
+ mode: "non_stream",
14423
+ from,
14424
+ to: model,
14425
+ reason: "extra_usage_required"
14426
+ });
14427
+ console.error(`[PROXY] ${requestMeta.requestId} extra usage required for [1m], falling back to ${model} (skipping [1m] for 1h)`);
14428
+ continue;
14429
+ }
14430
+ if (isExpiredTokenError(errMsg) && !tokenRefreshed) {
14431
+ tokenRefreshed = true;
14432
+ const refreshed = await refreshOAuthToken();
14433
+ if (refreshed) {
14434
+ claudeLog("token_refresh.retrying", { mode: "non_stream" });
14435
+ console.error(`[PROXY] ${requestMeta.requestId} OAuth token expired — refreshed, retrying`);
14436
+ continue;
14437
+ }
14438
+ }
14417
14439
  if (isRateLimitError(errMsg)) {
14418
14440
  if (hasExtendedContext(model)) {
14419
14441
  const from = model;
@@ -14622,6 +14644,7 @@ Subprocess stderr: ${stderrOutput}`;
14622
14644
  const RATE_LIMIT_BASE_DELAY_MS = 1000;
14623
14645
  const response = async function* () {
14624
14646
  let rateLimitRetries = 0;
14647
+ let tokenRefreshed = false;
14625
14648
  while (true) {
14626
14649
  let didYieldClientEvent = false;
14627
14650
  try {
@@ -14684,6 +14707,28 @@ Subprocess stderr: ${stderrOutput}`;
14684
14707
  }));
14685
14708
  return;
14686
14709
  }
14710
+ if (isExtraUsageRequiredError(errMsg) && hasExtendedContext(model)) {
14711
+ const from = model;
14712
+ model = stripExtendedContext(model);
14713
+ recordExtendedContextUnavailable();
14714
+ claudeLog("upstream.context_fallback", {
14715
+ mode: "stream",
14716
+ from,
14717
+ to: model,
14718
+ reason: "extra_usage_required"
14719
+ });
14720
+ console.error(`[PROXY] ${requestMeta.requestId} extra usage required for [1m], falling back to ${model} (skipping [1m] for 1h)`);
14721
+ continue;
14722
+ }
14723
+ if (isExpiredTokenError(errMsg) && !tokenRefreshed) {
14724
+ tokenRefreshed = true;
14725
+ const refreshed = await refreshOAuthToken();
14726
+ if (refreshed) {
14727
+ claudeLog("token_refresh.retrying", { mode: "stream" });
14728
+ console.error(`[PROXY] ${requestMeta.requestId} OAuth token expired — refreshed, retrying`);
14729
+ continue;
14730
+ }
14731
+ }
14687
14732
  if (isRateLimitError(errMsg)) {
14688
14733
  if (hasExtendedContext(model)) {
14689
14734
  const from = model;
@@ -15117,7 +15162,8 @@ data: ${JSON.stringify({
15117
15162
  email: auth.email,
15118
15163
  subscriptionType: auth.subscriptionType
15119
15164
  },
15120
- mode: process.env.MERIDIAN_PASSTHROUGH ?? process.env.CLAUDE_PROXY_PASSTHROUGH ? "passthrough" : "internal"
15165
+ mode: process.env.MERIDIAN_PASSTHROUGH ?? process.env.CLAUDE_PROXY_PASSTHROUGH ? "passthrough" : "internal",
15166
+ plugin: { opencode: checkPluginConfigured() ? "configured" : "not-configured" }
15121
15167
  });
15122
15168
  } catch {
15123
15169
  return c.json({
@@ -15127,6 +15173,13 @@ data: ${JSON.stringify({
15127
15173
  });
15128
15174
  }
15129
15175
  });
15176
+ app.post("/auth/refresh", async (c) => {
15177
+ const success = await refreshOAuthToken();
15178
+ if (success) {
15179
+ return c.json({ success: true, message: "OAuth token refreshed successfully" });
15180
+ }
15181
+ return c.json({ success: false, message: "Token refresh failed. If the problem persists, run 'claude login'." }, 500);
15182
+ });
15130
15183
  app.all("*", (c) => {
15131
15184
  console.error(`[PROXY] UNHANDLED ${c.req.method} ${c.req.url}`);
15132
15185
  return c.json({ error: { type: "not_found", message: `Endpoint not supported: ${c.req.method} ${new URL(c.req.url).pathname}` } }, 404);
@@ -15170,11 +15223,11 @@ Or use a different port:`);
15170
15223
  server,
15171
15224
  config: finalConfig,
15172
15225
  async close() {
15173
- await new Promise((resolve2, reject) => {
15174
- server.close((err) => err ? reject(err) : resolve2());
15226
+ await new Promise((resolve3, reject) => {
15227
+ server.close((err) => err ? reject(err) : resolve3());
15175
15228
  });
15176
15229
  }
15177
15230
  };
15178
15231
  }
15179
15232
 
15180
- export { __require, computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };
15233
+ export { computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };