@rynfar/meridian 1.43.0 → 1.44.0

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.
@@ -34,7 +34,7 @@ import {
34
34
  } from "./cli-yeazzt32.js";
35
35
  import {
36
36
  checkPluginConfigured
37
- } from "./cli-rtab0qa6.js";
37
+ } from "./cli-je60fevk.js";
38
38
  import {
39
39
  claudeLog,
40
40
  createPlatformCredentialStore,
@@ -43,7 +43,7 @@ import {
43
43
  startBackgroundRefresh,
44
44
  stopBackgroundRefresh,
45
45
  withClaudeLogContext
46
- } from "./cli-7k1fcprd.js";
46
+ } from "./cli-1kbcm3yn.js";
47
47
  import {
48
48
  __commonJS,
49
49
  __esm,
@@ -1242,7 +1242,7 @@ function getFeaturesForAdapter(adapterName) {
1242
1242
  };
1243
1243
  }
1244
1244
  function getAllFeatureConfigs() {
1245
- const adapters = ["opencode", "crush", "forgecode", "pi", "droid", "passthrough"];
1245
+ const adapters = ["opencode", "crush", "forgecode", "pi", "droid", "passthrough", "openai"];
1246
1246
  const result = {};
1247
1247
  for (const name of adapters) {
1248
1248
  result[name] = getFeaturesForAdapter(name);
@@ -1314,6 +1314,9 @@ var init_sdkFeatures = __esm(() => {
1314
1314
  ADAPTER_DEFAULTS = {
1315
1315
  passthrough: {
1316
1316
  codeSystemPrompt: false
1317
+ },
1318
+ openai: {
1319
+ codeSystemPrompt: false
1317
1320
  }
1318
1321
  };
1319
1322
  VALID_CLAUDE_MD_VALUES = new Set(["off", "project", "full"]);
@@ -3889,7 +3892,7 @@ var DEFAULT_PROXY_CONFIG = {
3889
3892
  host: "127.0.0.1",
3890
3893
  debug: (process.env.MERIDIAN_DEBUG ?? process.env.CLAUDE_PROXY_DEBUG) === "1",
3891
3894
  idleTimeoutSeconds: 120,
3892
- silent: false,
3895
+ silent: (process.env.MERIDIAN_SILENT ?? process.env.CLAUDE_PROXY_SILENT) === "1",
3893
3896
  profiles: undefined,
3894
3897
  defaultProfile: undefined,
3895
3898
  version: undefined
@@ -9479,6 +9482,10 @@ ${historyBlock}` : historyBlock;
9479
9482
  result.temperature = body.temperature;
9480
9483
  if (body.top_p !== undefined)
9481
9484
  result.top_p = body.top_p;
9485
+ if (body.reasoning_effort !== undefined)
9486
+ result.reasoning_effort = body.reasoning_effort;
9487
+ if (body.output_config?.effort !== undefined)
9488
+ result.output_config = { effort: body.output_config.effort };
9482
9489
  return result;
9483
9490
  }
9484
9491
  function toFinishReason(stopReason) {
@@ -10740,6 +10747,12 @@ var claudeCodeAdapter = {
10740
10747
  }
10741
10748
  };
10742
10749
 
10750
+ // src/proxy/adapters/openai.ts
10751
+ var openAiAdapter = {
10752
+ ...openCodeAdapter,
10753
+ name: "openai"
10754
+ };
10755
+
10743
10756
  // src/proxy/adapters/detect.ts
10744
10757
  var ADAPTER_MAP = {
10745
10758
  opencode: openCodeAdapter,
@@ -10749,7 +10762,8 @@ var ADAPTER_MAP = {
10749
10762
  pi: piAdapter,
10750
10763
  forgecode: forgeCodeAdapter,
10751
10764
  "claude-code": claudeCodeAdapter,
10752
- claudecode: claudeCodeAdapter
10765
+ claudecode: claudeCodeAdapter,
10766
+ openai: openAiAdapter
10753
10767
  };
10754
10768
  var envDefault = process.env.MERIDIAN_DEFAULT_AGENT || "";
10755
10769
  if (envDefault && !ADAPTER_MAP[envDefault]) {
@@ -16625,6 +16639,12 @@ function buildQueryOptions(ctx) {
16625
16639
  };
16626
16640
  }
16627
16641
 
16642
+ // src/proxy/effort.ts
16643
+ var VALID_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
16644
+ function normalizeEffort(value) {
16645
+ return typeof value === "string" && VALID_EFFORTS.includes(value) ? value : undefined;
16646
+ }
16647
+
16628
16648
  // src/proxy/transforms/registry.ts
16629
16649
  var ADAPTER_TRANSFORMS = {
16630
16650
  opencode: openCodeTransforms,
@@ -16632,7 +16652,8 @@ var ADAPTER_TRANSFORMS = {
16632
16652
  droid: droidTransforms,
16633
16653
  pi: piTransforms,
16634
16654
  forgecode: forgeCodeTransforms,
16635
- passthrough: passthroughTransforms
16655
+ passthrough: passthroughTransforms,
16656
+ openai: openCodeTransforms
16636
16657
  };
16637
16658
  function getAdapterTransforms(adapterName) {
16638
16659
  return ADAPTER_TRANSFORMS[adapterName] ?? [];
@@ -17504,6 +17525,22 @@ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sd
17504
17525
  // src/proxy/server.ts
17505
17526
  var exec2 = promisify2(execCallback);
17506
17527
  var claudeExecutable = "";
17528
+ function credentialStoreForProfile(profile) {
17529
+ if (profile.type !== "claude-max")
17530
+ return;
17531
+ return createPlatformCredentialStore(profile.env.CLAUDE_CONFIG_DIR ? { claudeConfigDir: profile.env.CLAUDE_CONFIG_DIR } : undefined);
17532
+ }
17533
+ async function ensureFreshTokenForProfiles(config) {
17534
+ const profiles = getEffectiveProfiles(config.profiles);
17535
+ if (profiles.length === 0)
17536
+ return;
17537
+ for (const profile of profiles) {
17538
+ const resolved = resolveProfile(config.profiles, config.defaultProfile, profile.id);
17539
+ const store = credentialStoreForProfile(resolved);
17540
+ if (store)
17541
+ await ensureFreshToken(store).catch(() => {});
17542
+ }
17543
+ }
17507
17544
  var MULTIMODAL_TYPES = new Set(["image", "document", "file"]);
17508
17545
  function hasMultimodalContent(content) {
17509
17546
  if (!Array.isArray(content))
@@ -17627,8 +17664,13 @@ function buildFreshPrompt(messages, sanitizeOpts = {}) {
17627
17664
 
17628
17665
  `) || "";
17629
17666
  }
17667
+ var proxyLogSilent = false;
17668
+ function plog(message) {
17669
+ if (!proxyLogSilent)
17670
+ console.error(message);
17671
+ }
17630
17672
  function logUsage(requestId, usage) {
17631
- console.error(`[PROXY] ${requestId} usage: ${formatUsageSummary(usage)}`);
17673
+ plog(`[PROXY] ${requestId} usage: ${formatUsageSummary(usage)}`);
17632
17674
  }
17633
17675
  function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume, isPassthrough) {
17634
17676
  if (!usage || !sdkSessionId)
@@ -17661,7 +17703,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
17661
17703
  if (anomalies.length > 0) {
17662
17704
  const alerts = formatAnomalyAlerts(requestId, anomalies);
17663
17705
  for (const line of alerts) {
17664
- console.error(line);
17706
+ plog(line);
17665
17707
  }
17666
17708
  for (const a of anomalies) {
17667
17709
  diagnosticLog2.log({
@@ -17675,6 +17717,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
17675
17717
  }
17676
17718
  function createProxyServer(config = {}) {
17677
17719
  const finalConfig = { ...DEFAULT_PROXY_CONFIG, ...config };
17720
+ proxyLogSilent = finalConfig.silent;
17678
17721
  const serverVersion = finalConfig.version ?? "unknown";
17679
17722
  restoreActiveProfile(finalConfig.profiles);
17680
17723
  const sessionDiscoveredTools = new Map;
@@ -17782,6 +17825,7 @@ function createProxyServer(config = {}) {
17782
17825
  } = process.env;
17783
17826
  const sdkModelDefaults = resolveSdkModelDefaults();
17784
17827
  const profileEnv = { ...sdkModelDefaults, ...cleanEnv, ...profile.env };
17828
+ const profileCredentialStore = credentialStoreForProfile(profile);
17785
17829
  let systemContext = "";
17786
17830
  if (body.system) {
17787
17831
  if (typeof body.system === "string") {
@@ -17811,15 +17855,15 @@ function createProxyServer(config = {}) {
17811
17855
  const rawBetaHeader = c.req.header("anthropic-beta");
17812
17856
  const betaFilter = filterBetasForProfile(rawBetaHeader, profile.type, getBetaPolicyFromEnv());
17813
17857
  if (betaFilter.stripped.length > 0) {
17814
- console.error(`[PROXY] ${requestMeta.requestId} stripped anthropic-beta(s) for Max profile: ${betaFilter.stripped.join(", ")}`);
17858
+ plog(`[PROXY] ${requestMeta.requestId} stripped anthropic-beta(s) for Max profile: ${betaFilter.stripped.join(", ")}`);
17815
17859
  }
17816
- const effort = effortHeader || body.effort || undefined;
17860
+ const effort = normalizeEffort(effortHeader || body.effort || body.reasoning_effort || body.output_config?.effort);
17817
17861
  let thinking = body.thinking || undefined;
17818
17862
  if (thinkingHeader !== undefined) {
17819
17863
  try {
17820
17864
  thinking = JSON.parse(thinkingHeader);
17821
17865
  } catch (e) {
17822
- console.error(`[PROXY] ${requestMeta.requestId} ignoring malformed x-opencode-thinking header: ${e instanceof Error ? e.message : String(e)}`);
17866
+ plog(`[PROXY] ${requestMeta.requestId} ignoring malformed x-opencode-thinking header: ${e instanceof Error ? e.message : String(e)}`);
17823
17867
  }
17824
17868
  }
17825
17869
  const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
@@ -17834,7 +17878,7 @@ function createProxyServer(config = {}) {
17834
17878
  if (thinkingBetaStripped) {
17835
17879
  thinking = { type: "disabled" };
17836
17880
  if (betaFilter.stripped.length > 0) {
17837
- console.error(`[PROXY] ${requestMeta.requestId} thinking disabled (thinking beta stripped by ${getBetaPolicyFromEnv()} policy)`);
17881
+ plog(`[PROXY] ${requestMeta.requestId} thinking disabled (thinking beta stripped by ${getBetaPolicyFromEnv()} policy)`);
17838
17882
  }
17839
17883
  }
17840
17884
  const parsedBudget = taskBudgetHeader ? Number.parseInt(taskBudgetHeader, 10) : NaN;
@@ -17861,14 +17905,14 @@ function createProxyServer(config = {}) {
17861
17905
  const msgCount = Array.isArray(body.messages) ? body.messages.length : 0;
17862
17906
  const toolCount = body.tools?.length ?? 0;
17863
17907
  const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name}${requestSource ? ` source=${requestSource}` : ""} model=${model} stream=${stream2} tools=${toolCount} 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}`;
17864
- console.error(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
17908
+ plog(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
17865
17909
  diagnosticLog2.session(`${requestLogLine}`, requestMeta.requestId);
17866
17910
  if (lineageResult.type === "diverged" && profileSessionId && !isIndependentSession) {
17867
17911
  const recovery = lookupSessionRecovery(profileSessionId);
17868
17912
  if (recovery) {
17869
17913
  const prevId = recovery.previousClaudeSessionId || recovery.claudeSessionId;
17870
17914
  const recoveryMsg = `${requestMeta.requestId} SESSION RECOVERY: previous conversation available. Run: claude --resume ${prevId}`;
17871
- console.error(`[PROXY] ${recoveryMsg}`);
17915
+ plog(`[PROXY] ${recoveryMsg}`);
17872
17916
  diagnosticLog2.session(recoveryMsg, requestMeta.requestId);
17873
17917
  }
17874
17918
  }
@@ -17964,7 +18008,7 @@ function createProxyServer(config = {}) {
17964
18008
  const cached = sessionToolCache.get(profileSessionId);
17965
18009
  if (cached && cached.length > 0) {
17966
18010
  requestTools = cached;
17967
- console.error(`[PROXY] ${requestMeta.requestId} tools_restored: client sent 0 tools but session had ${cached.length} — reusing cached tools to preserve prompt cache`);
18011
+ plog(`[PROXY] ${requestMeta.requestId} tools_restored: client sent 0 tools but session had ${cached.length} — reusing cached tools to preserve prompt cache`);
17968
18012
  }
17969
18013
  }
17970
18014
  if (passthrough && requestTools.length > 0) {
@@ -17977,7 +18021,7 @@ function createProxyServer(config = {}) {
17977
18021
  if (profileSessionId) {
17978
18022
  sessionMcpCache.set(profileSessionId, { key: toolSetKey, mcp: passthroughMcp });
17979
18023
  if (cachedMcp) {
17980
- console.error(`[PROXY] ${requestMeta.requestId} tools_changed: MCP server recreated (prompt cache likely invalidates)`);
18024
+ plog(`[PROXY] ${requestMeta.requestId} tools_changed: MCP server recreated (prompt cache likely invalidates)`);
17981
18025
  }
17982
18026
  }
17983
18027
  }
@@ -17989,7 +18033,7 @@ function createProxyServer(config = {}) {
17989
18033
  const coreSet = coreNames ? new Set(coreNames.map((n) => n.toLowerCase())) : undefined;
17990
18034
  const deferredToolCount = hasDeferredTools && requestTools.length > 0 ? requestTools.filter((t) => t.defer_loading === true || coreSet && !coreSet.has(String(t.name).toLowerCase())).length : 0;
17991
18035
  if (hasDeferredTools) {
17992
- console.error(`[PROXY] ${requestMeta.requestId} deferred=${deferredToolCount}/${toolCount} tools (core: ${coreNames?.join(",") ?? "none"})`);
18036
+ plog(`[PROXY] ${requestMeta.requestId} deferred=${deferredToolCount}/${toolCount} tools (core: ${coreNames?.join(",") ?? "none"})`);
17993
18037
  }
17994
18038
  const mcpPrefix = `mcp__${adapter.getMcpServerName()}__`;
17995
18039
  const trackFileChanges = !(process.env.MERIDIAN_NO_FILE_CHANGES ?? process.env.CLAUDE_PROXY_NO_FILE_CHANGES) && pipelineCtx.shouldTrackFileChanges;
@@ -18050,7 +18094,9 @@ function createProxyServer(config = {}) {
18050
18094
  const RATE_LIMIT_BASE_DELAY_MS = 1000;
18051
18095
  const response = async function* () {
18052
18096
  let rateLimitRetries = 0;
18053
- await ensureFreshToken().catch(() => {});
18097
+ if (profileCredentialStore) {
18098
+ await ensureFreshToken(profileCredentialStore).catch(() => {});
18099
+ }
18054
18100
  let tokenRefreshed = false;
18055
18101
  let didFreshBaseRetry = false;
18056
18102
  while (true) {
@@ -18114,7 +18160,7 @@ function createProxyServer(config = {}) {
18114
18160
  rollbackUuid: undoRollbackUuid,
18115
18161
  resumeSessionId
18116
18162
  });
18117
- console.error(`[PROXY] Stale session UUID, evicting and retrying as fresh session`);
18163
+ plog(`[PROXY] Stale session UUID, evicting and retrying as fresh session`);
18118
18164
  evictSession(profileSessionId, profileScopedCwd, allMessages);
18119
18165
  sdkUuidMap.length = 0;
18120
18166
  for (let i = 0;i < allMessages.length; i++)
@@ -18170,7 +18216,7 @@ function createProxyServer(config = {}) {
18170
18216
  to: model,
18171
18217
  reason: "extra_usage_required"
18172
18218
  });
18173
- console.error(`[PROXY] ${requestMeta.requestId} extra usage required for [1m], falling back to ${model} (skipping [1m] for 1h)`);
18219
+ plog(`[PROXY] ${requestMeta.requestId} extra usage required for [1m], falling back to ${model} (skipping [1m] for 1h)`);
18174
18220
  continue;
18175
18221
  }
18176
18222
  if (isExtraUsageRequiredError(errMsg) && resumeSessionId && !didFreshBaseRetry) {
@@ -18180,7 +18226,7 @@ function createProxyServer(config = {}) {
18180
18226
  model,
18181
18227
  reason: "extra_usage_required_resume"
18182
18228
  });
18183
- console.error(`[PROXY] ${requestMeta.requestId} extra usage persisted on resumed ${model}, retrying as fresh session`);
18229
+ plog(`[PROXY] ${requestMeta.requestId} extra usage persisted on resumed ${model}, retrying as fresh session`);
18184
18230
  evictSession(profileSessionId, profileScopedCwd, allMessages);
18185
18231
  sdkUuidMap.length = 0;
18186
18232
  for (let i = 0;i < allMessages.length; i++)
@@ -18228,10 +18274,10 @@ function createProxyServer(config = {}) {
18228
18274
  }
18229
18275
  if (isExpiredTokenError(errMsg) && !tokenRefreshed) {
18230
18276
  tokenRefreshed = true;
18231
- const refreshed = await refreshOAuthToken();
18277
+ const refreshed = profileCredentialStore ? await refreshOAuthToken(profileCredentialStore) : false;
18232
18278
  if (refreshed) {
18233
18279
  claudeLog("token_refresh.retrying", { mode: "non_stream" });
18234
- console.error(`[PROXY] ${requestMeta.requestId} OAuth token expired — refreshed, retrying`);
18280
+ plog(`[PROXY] ${requestMeta.requestId} OAuth token expired — refreshed, retrying`);
18235
18281
  continue;
18236
18282
  }
18237
18283
  }
@@ -18245,7 +18291,7 @@ function createProxyServer(config = {}) {
18245
18291
  to: model,
18246
18292
  reason: "rate_limit"
18247
18293
  });
18248
- console.error(`[PROXY] ${requestMeta.requestId} rate-limited on [1m], retrying with ${model}`);
18294
+ plog(`[PROXY] ${requestMeta.requestId} rate-limited on [1m], retrying with ${model}`);
18249
18295
  continue;
18250
18296
  }
18251
18297
  if (rateLimitRetries < MAX_RATE_LIMIT_RETRIES) {
@@ -18258,7 +18304,7 @@ function createProxyServer(config = {}) {
18258
18304
  maxAttempts: MAX_RATE_LIMIT_RETRIES,
18259
18305
  delayMs: delay
18260
18306
  });
18261
- console.error(`[PROXY] ${requestMeta.requestId} rate-limited on ${model}, retry ${rateLimitRetries}/${MAX_RATE_LIMIT_RETRIES} in ${delay}ms`);
18307
+ plog(`[PROXY] ${requestMeta.requestId} rate-limited on ${model}, retry ${rateLimitRetries}/${MAX_RATE_LIMIT_RETRIES} in ${delay}ms`);
18262
18308
  await new Promise((r) => setTimeout(r, delay));
18263
18309
  continue;
18264
18310
  }
@@ -18334,7 +18380,7 @@ function createProxyServer(config = {}) {
18334
18380
  sessionDiscoveredTools.get(sessId).add(t);
18335
18381
  const newNames = [...discoveredTools].join(", ");
18336
18382
  const allNames = [...sessionDiscoveredTools.get(sessId)];
18337
- console.error(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
18383
+ plog(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
18338
18384
  }
18339
18385
  } catch (error) {
18340
18386
  const stderrOutput = stderrLines.join(`
@@ -18508,7 +18554,9 @@ Subprocess stderr: ${stderrOutput}`;
18508
18554
  const RATE_LIMIT_BASE_DELAY_MS = 1000;
18509
18555
  const response = async function* () {
18510
18556
  let rateLimitRetries = 0;
18511
- await ensureFreshToken().catch(() => {});
18557
+ if (profileCredentialStore) {
18558
+ await ensureFreshToken(profileCredentialStore).catch(() => {});
18559
+ }
18512
18560
  let tokenRefreshed = false;
18513
18561
  let didFreshBaseRetry = false;
18514
18562
  while (true) {
@@ -18572,7 +18620,7 @@ Subprocess stderr: ${stderrOutput}`;
18572
18620
  rollbackUuid: undoRollbackUuid,
18573
18621
  resumeSessionId
18574
18622
  });
18575
- console.error(`[PROXY] Stale session UUID, evicting and retrying as fresh session`);
18623
+ plog(`[PROXY] Stale session UUID, evicting and retrying as fresh session`);
18576
18624
  evictSession(profileSessionId, profileScopedCwd, allMessages);
18577
18625
  sdkUuidMap.length = 0;
18578
18626
  for (let i = 0;i < allMessages.length; i++)
@@ -18628,7 +18676,7 @@ Subprocess stderr: ${stderrOutput}`;
18628
18676
  to: model,
18629
18677
  reason: "extra_usage_required"
18630
18678
  });
18631
- console.error(`[PROXY] ${requestMeta.requestId} extra usage required for [1m], falling back to ${model} (skipping [1m] for 1h)`);
18679
+ plog(`[PROXY] ${requestMeta.requestId} extra usage required for [1m], falling back to ${model} (skipping [1m] for 1h)`);
18632
18680
  continue;
18633
18681
  }
18634
18682
  if (isExtraUsageRequiredError(errMsg) && resumeSessionId && !didFreshBaseRetry) {
@@ -18638,7 +18686,7 @@ Subprocess stderr: ${stderrOutput}`;
18638
18686
  model,
18639
18687
  reason: "extra_usage_required_resume"
18640
18688
  });
18641
- console.error(`[PROXY] ${requestMeta.requestId} extra usage persisted on resumed ${model}, retrying as fresh session`);
18689
+ plog(`[PROXY] ${requestMeta.requestId} extra usage persisted on resumed ${model}, retrying as fresh session`);
18642
18690
  evictSession(profileSessionId, profileScopedCwd, allMessages);
18643
18691
  sdkUuidMap.length = 0;
18644
18692
  for (let i = 0;i < allMessages.length; i++)
@@ -18686,10 +18734,10 @@ Subprocess stderr: ${stderrOutput}`;
18686
18734
  }
18687
18735
  if (isExpiredTokenError(errMsg) && !tokenRefreshed) {
18688
18736
  tokenRefreshed = true;
18689
- const refreshed = await refreshOAuthToken();
18737
+ const refreshed = profileCredentialStore ? await refreshOAuthToken(profileCredentialStore) : false;
18690
18738
  if (refreshed) {
18691
18739
  claudeLog("token_refresh.retrying", { mode: "stream" });
18692
- console.error(`[PROXY] ${requestMeta.requestId} OAuth token expired — refreshed, retrying`);
18740
+ plog(`[PROXY] ${requestMeta.requestId} OAuth token expired — refreshed, retrying`);
18693
18741
  continue;
18694
18742
  }
18695
18743
  }
@@ -18703,7 +18751,7 @@ Subprocess stderr: ${stderrOutput}`;
18703
18751
  to: model,
18704
18752
  reason: "rate_limit"
18705
18753
  });
18706
- console.error(`[PROXY] ${requestMeta.requestId} rate-limited on [1m], retrying with ${model}`);
18754
+ plog(`[PROXY] ${requestMeta.requestId} rate-limited on [1m], retrying with ${model}`);
18707
18755
  continue;
18708
18756
  }
18709
18757
  if (rateLimitRetries < MAX_RATE_LIMIT_RETRIES) {
@@ -18716,7 +18764,7 @@ Subprocess stderr: ${stderrOutput}`;
18716
18764
  maxAttempts: MAX_RATE_LIMIT_RETRIES,
18717
18765
  delayMs: delay
18718
18766
  });
18719
- console.error(`[PROXY] ${requestMeta.requestId} rate-limited on ${model}, retry ${rateLimitRetries}/${MAX_RATE_LIMIT_RETRIES} in ${delay}ms`);
18767
+ plog(`[PROXY] ${requestMeta.requestId} rate-limited on ${model}, retry ${rateLimitRetries}/${MAX_RATE_LIMIT_RETRIES} in ${delay}ms`);
18720
18768
  await new Promise((r) => setTimeout(r, delay));
18721
18769
  continue;
18722
18770
  }
@@ -18930,7 +18978,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
18930
18978
  sessionDiscoveredTools.get(sessId).add(t);
18931
18979
  const newNames = [...discoveredTools].join(", ");
18932
18980
  const allNames = [...sessionDiscoveredTools.get(sessId)];
18933
- console.error(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
18981
+ plog(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
18934
18982
  }
18935
18983
  if (currentSessionId && !isIndependentSession) {
18936
18984
  storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
@@ -19449,7 +19497,7 @@ data: ${JSON.stringify({
19449
19497
  setActiveProfile(body.profile);
19450
19498
  clearSessionCache();
19451
19499
  rateLimitStore.clear();
19452
- console.error(`[PROXY] Active profile switched to: ${body.profile} (session + rate-limit caches cleared)`);
19500
+ plog(`[PROXY] Active profile switched to: ${body.profile} (session + rate-limit caches cleared)`);
19453
19501
  return c.json({ success: true, activeProfile: body.profile });
19454
19502
  });
19455
19503
  app.get("/plugins/list", async (c) => {
@@ -19473,7 +19521,7 @@ data: ${JSON.stringify({
19473
19521
  loadedPlugins = await loadPlugins(pluginDir, pluginConfigPath);
19474
19522
  pluginTransforms = getActiveTransforms(loadedPlugins);
19475
19523
  const active = loadedPlugins.filter((p) => p.status === "active").length;
19476
- console.error(`[PROXY] Plugins reloaded: ${active} active`);
19524
+ plog(`[PROXY] Plugins reloaded: ${active} active`);
19477
19525
  return c.json({
19478
19526
  success: true,
19479
19527
  plugins: loadedPlugins.map((p) => ({
@@ -19492,10 +19540,12 @@ data: ${JSON.stringify({
19492
19540
  return c.html(pluginPageHtml);
19493
19541
  });
19494
19542
  app.post("/auth/refresh", async (c) => {
19495
- const success = await refreshOAuthToken();
19543
+ const profile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile, c.req.header("x-meridian-profile") || undefined);
19544
+ const store = credentialStoreForProfile(profile);
19545
+ const success = store ? await refreshOAuthToken(store) : false;
19496
19546
  if (success) {
19497
19547
  rateLimitStore.clear();
19498
- return c.json({ success: true, message: "OAuth token refreshed successfully" });
19548
+ return c.json({ success: true, message: "OAuth token refreshed successfully", profile: profile.id });
19499
19549
  }
19500
19550
  return c.json({ success: false, message: "Token refresh failed. If the problem persists, run 'claude login'." }, 500);
19501
19551
  });
@@ -19505,7 +19555,10 @@ data: ${JSON.stringify({
19505
19555
  if (!anthropicBody) {
19506
19556
  return c.json({ type: "error", error: { type: "invalid_request_error", message: "messages: Field required" } }, 400);
19507
19557
  }
19508
- const internalHeaders = { "Content-Type": "application/json" };
19558
+ const internalHeaders = {
19559
+ "Content-Type": "application/json",
19560
+ "x-meridian-agent": "openai"
19561
+ };
19509
19562
  const xApiKey = c.req.header("x-api-key");
19510
19563
  if (xApiKey)
19511
19564
  internalHeaders["x-api-key"] = xApiKey;
@@ -19526,8 +19579,7 @@ data: ${JSON.stringify({
19526
19579
  const created = Math.floor(Date.now() / 1000);
19527
19580
  const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model : "claude-sonnet-4-6";
19528
19581
  const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
19529
- const adapter = detectAdapter(c);
19530
- const sdkFeatures = getFeaturesForAdapter2(adapter.name);
19582
+ const sdkFeatures = getFeaturesForAdapter2("openai");
19531
19583
  if (!anthropicBody.stream) {
19532
19584
  const anthropicRes = await internalRes.json();
19533
19585
  return c.json(translateAnthropicToOpenAi(anthropicRes, completionId, model, created, {
@@ -19758,7 +19810,7 @@ data: ${JSON.stringify({
19758
19810
  });
19759
19811
  });
19760
19812
  app.all("*", (c) => {
19761
- console.error(`[PROXY] UNHANDLED ${c.req.method} ${c.req.url}`);
19813
+ plog(`[PROXY] UNHANDLED ${c.req.method} ${c.req.url}`);
19762
19814
  return c.json({ error: { type: "not_found", message: `Endpoint not supported: ${c.req.method} ${new URL(c.req.url).pathname}` } }, 404);
19763
19815
  });
19764
19816
  async function initPluginsAsync() {
@@ -19769,19 +19821,34 @@ data: ${JSON.stringify({
19769
19821
  const active = loadedPlugins.filter((p) => p.status === "active").length;
19770
19822
  const disabled = loadedPlugins.filter((p) => p.status === "disabled").length;
19771
19823
  const errored = loadedPlugins.filter((p) => p.status === "error").length;
19772
- console.error(`[PROXY] Plugins loaded: ${active} active, ${disabled} disabled, ${errored} errors`);
19824
+ plog(`[PROXY] Plugins loaded: ${active} active, ${disabled} disabled, ${errored} errors`);
19773
19825
  }
19774
19826
  } catch (err) {
19775
- console.error(`[PROXY] Plugin loading failed: ${err instanceof Error ? err.message : String(err)}`);
19827
+ plog(`[PROXY] Plugin loading failed: ${err instanceof Error ? err.message : String(err)}`);
19776
19828
  }
19777
19829
  }
19778
19830
  return { app, config: finalConfig, initPlugins: initPluginsAsync };
19779
19831
  }
19832
+ var processErrorHandlersInstalled = false;
19833
+ function installProxyProcessErrorHandlers() {
19834
+ if (processErrorHandlersInstalled)
19835
+ return;
19836
+ processErrorHandlersInstalled = true;
19837
+ process.on("uncaughtException", (err) => {
19838
+ console.error(`[PROXY] Uncaught exception (recovered): ${err.message}`);
19839
+ });
19840
+ process.on("unhandledRejection", (reason) => {
19841
+ console.error(`[PROXY] Unhandled rejection (recovered): ${reason instanceof Error ? reason.message : reason}`);
19842
+ });
19843
+ }
19780
19844
  async function startProxyServer(config = {}) {
19781
19845
  claudeExecutable = await resolveClaudeExecutableAsync();
19782
19846
  const { app, config: finalConfig, initPlugins } = createProxyServer(config);
19783
19847
  if (initPlugins)
19784
19848
  await initPlugins();
19849
+ if (finalConfig.installProcessErrorHandlers) {
19850
+ installProxyProcessErrorHandlers();
19851
+ }
19785
19852
  const server = serve({
19786
19853
  fetch: app.fetch,
19787
19854
  port: finalConfig.port,
@@ -19819,6 +19886,13 @@ Or use a different port:`);
19819
19886
  }
19820
19887
  });
19821
19888
  startBackgroundRefresh();
19889
+ const PROFILE_TOKEN_REFRESH_MS = 45000;
19890
+ ensureFreshTokenForProfiles(finalConfig);
19891
+ const profileTokenRefreshInterval = setInterval(() => {
19892
+ ensureFreshTokenForProfiles(finalConfig);
19893
+ }, PROFILE_TOKEN_REFRESH_MS);
19894
+ if (profileTokenRefreshInterval.unref)
19895
+ profileTokenRefreshInterval.unref();
19822
19896
  let authKeepaliveInterval;
19823
19897
  const effectiveProfiles = getEffectiveProfiles(finalConfig.profiles);
19824
19898
  if (effectiveProfiles.length > 0) {
@@ -19840,6 +19914,7 @@ Or use a different port:`);
19840
19914
  server,
19841
19915
  config: finalConfig,
19842
19916
  async close() {
19917
+ clearInterval(profileTokenRefreshInterval);
19843
19918
  if (authKeepaliveInterval)
19844
19919
  clearInterval(authKeepaliveInterval);
19845
19920
  stopBackgroundRefresh();
@@ -19850,4 +19925,4 @@ Or use a different port:`);
19850
19925
  };
19851
19926
  }
19852
19927
 
19853
- export { runTransformHook, runObserveHook, buildPipeline, createRequestContext, computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };
19928
+ export { runTransformHook, runObserveHook, buildPipeline, createRequestContext, computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, installProxyProcessErrorHandlers, startProxyServer };
@@ -3,6 +3,24 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
3
  import { homedir, platform } from "os";
4
4
  import { dirname, join } from "path";
5
5
  import { fileURLToPath } from "url";
6
+ import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser";
7
+
8
+ class UnparseableConfigError extends Error {
9
+ configPath;
10
+ constructor(configPath) {
11
+ super(`Could not parse ${configPath} — it may contain a syntax error.`);
12
+ this.configPath = configPath;
13
+ this.name = "UnparseableConfigError";
14
+ }
15
+ }
16
+ function parseOpencodeConfig(text) {
17
+ const errors = [];
18
+ const parsed = parseJsonc(text, errors, { allowTrailingComma: true });
19
+ if (errors.length > 0 || parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20
+ return null;
21
+ }
22
+ return parsed;
23
+ }
6
24
  function findOpencodeConfigPath() {
7
25
  if (process.env.OPENCODE_CONFIG_DIR) {
8
26
  return join(process.env.OPENCODE_CONFIG_DIR, "opencode.json");
@@ -31,37 +49,37 @@ function checkPluginConfigured(configPath) {
31
49
  const path = configPath ?? findOpencodeConfigPath();
32
50
  if (!existsSync(path))
33
51
  return false;
34
- try {
35
- const raw = readFileSync(path, "utf-8");
36
- const config = JSON.parse(raw);
37
- const plugins = Array.isArray(config.plugin) ? config.plugin : [];
38
- return plugins.some((p) => typeof p === "string" && isMeridianEntry(p));
39
- } catch {
52
+ const config = parseOpencodeConfig(readFileSync(path, "utf-8"));
53
+ if (config === null)
40
54
  return false;
41
- }
55
+ const plugins = Array.isArray(config.plugin) ? config.plugin : [];
56
+ return plugins.some((p) => typeof p === "string" && isMeridianEntry(p));
42
57
  }
43
58
  function runSetup(pluginPath, configPath) {
44
59
  const path = configPath ?? findOpencodeConfigPath();
45
60
  const dir = dirname(path);
46
- let config = {};
47
- let created = false;
48
- if (existsSync(path)) {
49
- try {
50
- config = JSON.parse(readFileSync(path, "utf-8"));
51
- } catch {}
52
- } else {
53
- created = true;
61
+ if (!existsSync(path)) {
54
62
  if (!existsSync(dir))
55
63
  mkdirSync(dir, { recursive: true });
64
+ writeFileSync(path, `${JSON.stringify({ plugin: [pluginPath] }, null, 2)}
65
+ `, "utf-8");
66
+ return { configPath: path, pluginPath, alreadyConfigured: false, removedStale: [], created: true };
67
+ }
68
+ const text = readFileSync(path, "utf-8");
69
+ const config = parseOpencodeConfig(text);
70
+ if (config === null) {
71
+ throw new UnparseableConfigError(path);
56
72
  }
57
73
  const existing = Array.isArray(config.plugin) ? config.plugin.filter((p) => typeof p === "string") : [];
58
74
  const removedStale = existing.filter(isMeridianEntry);
59
75
  const others = existing.filter((p) => !isMeridianEntry(p));
60
76
  const alreadyConfigured = removedStale.some((p) => p === pluginPath);
61
- config.plugin = [...others, pluginPath];
62
- writeFileSync(path, JSON.stringify(config, null, 2) + `
63
- `, "utf-8");
64
- return { configPath: path, pluginPath, alreadyConfigured, removedStale, created };
77
+ const newPlugins = [...others, pluginPath];
78
+ const edits = modify(text, ["plugin"], newPlugins, {
79
+ formattingOptions: { insertSpaces: true, tabSize: 2 }
80
+ });
81
+ writeFileSync(path, applyEdits(text, edits), "utf-8");
82
+ return { configPath: path, pluginPath, alreadyConfigured, removedStale, created: false };
65
83
  }
66
84
 
67
- export { findOpencodeConfigPath, findPluginPath, checkPluginConfigured, runSetup };
85
+ export { UnparseableConfigError, findOpencodeConfigPath, findPluginPath, checkPluginConfigured, runSetup };