@rynfar/meridian 1.60.0 → 1.62.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.
Files changed (40) hide show
  1. package/README.md +3 -1
  2. package/dist/{cli-k1djafvr.js → cli-k36dddkm.js} +998 -282
  3. package/dist/cli.js +1 -1
  4. package/dist/{profilePage-naychnb8.js → profilePage-gtazq15d.js} +9 -0
  5. package/dist/proxy/adapters/detect.d.ts.map +1 -1
  6. package/dist/proxy/adapters/jcode.d.ts +13 -0
  7. package/dist/proxy/adapters/jcode.d.ts.map +1 -0
  8. package/dist/proxy/adapters/prime.d.ts +99 -0
  9. package/dist/proxy/adapters/prime.d.ts.map +1 -0
  10. package/dist/proxy/errors.d.ts +14 -0
  11. package/dist/proxy/errors.d.ts.map +1 -1
  12. package/dist/proxy/messages.d.ts +28 -0
  13. package/dist/proxy/messages.d.ts.map +1 -1
  14. package/dist/proxy/oauthUsage.d.ts +34 -1
  15. package/dist/proxy/oauthUsage.d.ts.map +1 -1
  16. package/dist/proxy/openai.d.ts +5 -1
  17. package/dist/proxy/openai.d.ts.map +1 -1
  18. package/dist/proxy/passthroughEarlyStop.d.ts +48 -0
  19. package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
  20. package/dist/proxy/query.d.ts +3 -2
  21. package/dist/proxy/query.d.ts.map +1 -1
  22. package/dist/proxy/sdkFeatures.d.ts.map +1 -1
  23. package/dist/proxy/server.d.ts.map +1 -1
  24. package/dist/proxy/session/cache.d.ts +1 -1
  25. package/dist/proxy/session/cache.d.ts.map +1 -1
  26. package/dist/proxy/session/lineage.d.ts +70 -0
  27. package/dist/proxy/session/lineage.d.ts.map +1 -1
  28. package/dist/proxy/sessionStore.d.ts +5 -1
  29. package/dist/proxy/sessionStore.d.ts.map +1 -1
  30. package/dist/proxy/transform.d.ts +33 -0
  31. package/dist/proxy/transform.d.ts.map +1 -1
  32. package/dist/proxy/transforms/prime.d.ts +3 -0
  33. package/dist/proxy/transforms/prime.d.ts.map +1 -0
  34. package/dist/proxy/transforms/registry.d.ts.map +1 -1
  35. package/dist/proxy/turnOutcome.d.ts +179 -0
  36. package/dist/proxy/turnOutcome.d.ts.map +1 -0
  37. package/dist/server.js +1 -1
  38. package/dist/telemetry/landing.d.ts.map +1 -1
  39. package/dist/telemetry/profilePage.d.ts.map +1 -1
  40. package/package.json +1 -1
@@ -1752,6 +1752,133 @@ var init_sqlite = __esm(() => {
1752
1752
  ];
1753
1753
  });
1754
1754
 
1755
+ // src/proxy/fileChanges.ts
1756
+ function extractFileChange(toolName, toolInput, mcpPrefix) {
1757
+ if (!toolName.startsWith(mcpPrefix))
1758
+ return;
1759
+ const shortName = toolName.slice(mcpPrefix.length);
1760
+ const input = toolInput;
1761
+ if (shortName === "write" && input?.path) {
1762
+ return { operation: "wrote", path: String(input.path) };
1763
+ }
1764
+ if (shortName === "edit" && input?.path) {
1765
+ return { operation: "edited", path: String(input.path) };
1766
+ }
1767
+ return;
1768
+ }
1769
+ function createFileChangeHook(changes, mcpPrefix) {
1770
+ return {
1771
+ matcher: "",
1772
+ hooks: [async (input) => {
1773
+ const change = extractFileChange(input.tool_name, input.tool_input, mcpPrefix);
1774
+ if (change) {
1775
+ changes.push(change);
1776
+ return {};
1777
+ }
1778
+ if (input.tool_name === `${mcpPrefix}bash`) {
1779
+ const toolInput = input.tool_input;
1780
+ if (toolInput?.command) {
1781
+ const bashChanges = extractFileChangesFromBash(String(toolInput.command));
1782
+ changes.push(...bashChanges);
1783
+ }
1784
+ }
1785
+ return {};
1786
+ }]
1787
+ };
1788
+ }
1789
+ function isLikelyFilePath(s) {
1790
+ if (s.length > 4096)
1791
+ return false;
1792
+ if (/[<>$`\\()[\]{}=]/.test(s))
1793
+ return false;
1794
+ if (/^-?\d+$/.test(s))
1795
+ return false;
1796
+ if (s.includes("/"))
1797
+ return true;
1798
+ if (/\.[A-Za-z0-9]{1,16}$/.test(s))
1799
+ return true;
1800
+ return false;
1801
+ }
1802
+ function extractFileChangesFromBash(command) {
1803
+ const changes = [];
1804
+ const seen = new Set;
1805
+ const addChange = (operation, path) => {
1806
+ if (path === "/dev/null" || path === "/dev/stderr" || path === "/dev/stdout")
1807
+ return;
1808
+ if (!path.trim())
1809
+ return;
1810
+ const key = `${operation}:${path}`;
1811
+ if (!seen.has(key)) {
1812
+ seen.add(key);
1813
+ changes.push({ operation, path });
1814
+ }
1815
+ };
1816
+ const redirectRegex = /(?<![0-9=])>{1,2}\s*['"]?([^\s'";&|)]+)['"]?/g;
1817
+ let match2;
1818
+ while ((match2 = redirectRegex.exec(command)) !== null) {
1819
+ if (isLikelyFilePath(match2[1])) {
1820
+ addChange("wrote", match2[1]);
1821
+ }
1822
+ }
1823
+ const teeRegex = /\btee\s+(?:-[a-zA-Z]\s+)*['"]?([^\s'";&|)]+)['"]?/g;
1824
+ while ((match2 = teeRegex.exec(command)) !== null) {
1825
+ addChange("wrote", match2[1]);
1826
+ }
1827
+ const sedRegex = /\bsed\s+(?:-[a-zA-Z]*i[a-zA-Z]*|-i)\b.*?['"]?([^\s'";&|)]+)['"]?\s*$/gm;
1828
+ while ((match2 = sedRegex.exec(command)) !== null) {
1829
+ addChange("edited", match2[1]);
1830
+ }
1831
+ return changes;
1832
+ }
1833
+ function extractFileChangesFromMessages(messages, extractFn) {
1834
+ const changes = [];
1835
+ const executedToolIds = new Set;
1836
+ for (const msg of messages) {
1837
+ if (msg.role !== "user")
1838
+ continue;
1839
+ const content = Array.isArray(msg.content) ? msg.content : [];
1840
+ for (const block of content) {
1841
+ if (block?.type === "tool_result" && block.tool_use_id) {
1842
+ executedToolIds.add(block.tool_use_id);
1843
+ }
1844
+ }
1845
+ }
1846
+ for (const msg of messages) {
1847
+ if (msg.role !== "assistant")
1848
+ continue;
1849
+ const content = Array.isArray(msg.content) ? msg.content : [];
1850
+ for (const block of content) {
1851
+ if (block?.type !== "tool_use")
1852
+ continue;
1853
+ if (!executedToolIds.has(block.id))
1854
+ continue;
1855
+ const blockChanges = extractFn(block.name, block.input);
1856
+ changes.push(...blockChanges);
1857
+ }
1858
+ }
1859
+ return changes;
1860
+ }
1861
+ function formatFileChangeSummary(changes) {
1862
+ if (changes.length === 0)
1863
+ return;
1864
+ const seen = new Set;
1865
+ const unique = [];
1866
+ for (const c of changes) {
1867
+ const key = `${c.operation}:${c.path}`;
1868
+ if (!seen.has(key)) {
1869
+ seen.add(key);
1870
+ unique.push(c);
1871
+ }
1872
+ }
1873
+ const lines = unique.map((c) => `- ${c.operation} ${c.path}`);
1874
+ return `
1875
+
1876
+ Files changed:
1877
+ ${lines.join(`
1878
+ `)}`;
1879
+ }
1880
+ var init_fileChanges = () => {};
1881
+
1755
1882
  // src/proxy/messages.ts
1756
1883
  function stripCacheControlForHashing(obj) {
1757
1884
  if (!obj || typeof obj !== "object")
@@ -1831,6 +1958,13 @@ ${history}
1831
1958
 
1832
1959
  ` + last.text;
1833
1960
  }
1961
+ function framePassthroughContinuation(delta) {
1962
+ if (!delta)
1963
+ return delta;
1964
+ return `${PASSTHROUGH_CONTINUATION_LEAD_IN}
1965
+
1966
+ ${delta}`;
1967
+ }
1834
1968
  function stripNonStandardStreamFields(event) {
1835
1969
  if (event && typeof event === "object") {
1836
1970
  const e = event;
@@ -1886,6 +2020,12 @@ function consolidateMultimodalOntoLastUser(structured) {
1886
2020
  };
1887
2021
  return result;
1888
2022
  }
2023
+ function normalizeTarget(value) {
2024
+ const collapsed = value.replace(/\s+/g, " ").trim();
2025
+ if (!collapsed)
2026
+ return;
2027
+ return collapsed.length > TOOL_TARGET_MAX ? collapsed.slice(0, TOOL_TARGET_MAX - 3) + "..." : collapsed;
2028
+ }
1889
2029
  function summarizeContent(value) {
1890
2030
  if (typeof value !== "string" || value.length === 0)
1891
2031
  return;
@@ -1894,13 +2034,18 @@ function summarizeContent(value) {
1894
2034
  return;
1895
2035
  return collapsed.length > CONTENT_SUMMARY_MAX ? collapsed.slice(0, CONTENT_SUMMARY_MAX) + "..." : collapsed;
1896
2036
  }
2037
+ function editReplacementText(rec) {
2038
+ if (!rec)
2039
+ return;
2040
+ return rec.new_string ?? rec.newString ?? rec.new_text ?? rec.newText;
2041
+ }
1897
2042
  function extractContentSummary(name, input) {
1898
2043
  if (!input || typeof input !== "object")
1899
2044
  return;
1900
2045
  const rec = input;
1901
2046
  switch (name.toLowerCase()) {
1902
2047
  case "edit":
1903
- return summarizeContent(rec.newString ?? rec.new_string);
2048
+ return summarizeContent(editReplacementText(rec));
1904
2049
  case "write":
1905
2050
  return summarizeContent(rec.content);
1906
2051
  case "multiedit": {
@@ -1908,7 +2053,7 @@ function extractContentSummary(name, input) {
1908
2053
  if (!Array.isArray(edits) || edits.length === 0)
1909
2054
  return;
1910
2055
  const first = edits[0];
1911
- const firstSummary = summarizeContent(first?.newString ?? first?.new_string);
2056
+ const firstSummary = summarizeContent(editReplacementText(first));
1912
2057
  if (!firstSummary)
1913
2058
  return;
1914
2059
  return edits.length > 1 ? `${edits.length} edits; first: ${firstSummary}` : firstSummary;
@@ -1931,8 +2076,9 @@ function buildToolUseIndex(messages) {
1931
2076
  for (const key of TOOL_TARGET_KEYS) {
1932
2077
  const v = input[key];
1933
2078
  if (typeof v === "string" && v) {
1934
- target = v.length > 80 ? v.slice(0, 77) + "..." : v;
1935
- break;
2079
+ target = normalizeTarget(v);
2080
+ if (target)
2081
+ break;
1936
2082
  }
1937
2083
  }
1938
2084
  }
@@ -1957,7 +2103,7 @@ function extractSystemText(system) {
1957
2103
  return system.filter((b) => b?.type === "text" && typeof b.text === "string" && b.text).map((b) => b.text).filter((text) => !TRANSPORT_HEADER_BLOCK.test(text)).join(`
1958
2104
  `);
1959
2105
  }
1960
- var HASH_IGNORED_BLOCK_TYPES, HASH_HANDLED_BLOCK_TYPES, HASH_SERIALIZED_BLOCK_TYPES, MULTIMODAL_TYPES, TOOL_TARGET_KEYS, CONTENT_SUMMARY_MAX = 120, TRANSPORT_HEADER_BLOCK;
2106
+ var HASH_IGNORED_BLOCK_TYPES, HASH_HANDLED_BLOCK_TYPES, HASH_SERIALIZED_BLOCK_TYPES, PASSTHROUGH_CONTINUATION_LEAD_IN, MULTIMODAL_TYPES, TOOL_TARGET_KEYS, TOOL_TARGET_MAX = 80, CONTENT_SUMMARY_MAX = 120, TRANSPORT_HEADER_BLOCK;
1961
2107
  var init_messages = __esm(() => {
1962
2108
  HASH_IGNORED_BLOCK_TYPES = new Set(["thinking", "redacted_thinking"]);
1963
2109
  HASH_HANDLED_BLOCK_TYPES = new Set(["text", "tool_use", "tool_result"]);
@@ -1974,138 +2120,12 @@ var init_messages = __esm(() => {
1974
2120
  "tool_search_tool_result",
1975
2121
  "container_upload"
1976
2122
  ]);
2123
+ PASSTHROUGH_CONTINUATION_LEAD_IN = "The tool calls from your previous turn were forwarded to the client, which has now executed them — " + "their results follow. The instruction to end that turn without further text applied to it alone and " + "is now discharged: continue the work and respond.";
1977
2124
  MULTIMODAL_TYPES = new Set(["image", "document", "file"]);
1978
- TOOL_TARGET_KEYS = ["filePath", "file_path", "path", "command", "pattern", "query", "url"];
2125
+ TOOL_TARGET_KEYS = ["filePath", "file_path", "path", "command", "code", "pattern", "query", "url"];
1979
2126
  TRANSPORT_HEADER_BLOCK = /^\s*x-anthropic-[a-z0-9-]*header\s*:/i;
1980
2127
  });
1981
2128
 
1982
- // src/proxy/fileChanges.ts
1983
- function extractFileChange(toolName, toolInput, mcpPrefix) {
1984
- if (!toolName.startsWith(mcpPrefix))
1985
- return;
1986
- const shortName = toolName.slice(mcpPrefix.length);
1987
- const input = toolInput;
1988
- if (shortName === "write" && input?.path) {
1989
- return { operation: "wrote", path: String(input.path) };
1990
- }
1991
- if (shortName === "edit" && input?.path) {
1992
- return { operation: "edited", path: String(input.path) };
1993
- }
1994
- return;
1995
- }
1996
- function createFileChangeHook(changes, mcpPrefix) {
1997
- return {
1998
- matcher: "",
1999
- hooks: [async (input) => {
2000
- const change = extractFileChange(input.tool_name, input.tool_input, mcpPrefix);
2001
- if (change) {
2002
- changes.push(change);
2003
- return {};
2004
- }
2005
- if (input.tool_name === `${mcpPrefix}bash`) {
2006
- const toolInput = input.tool_input;
2007
- if (toolInput?.command) {
2008
- const bashChanges = extractFileChangesFromBash(String(toolInput.command));
2009
- changes.push(...bashChanges);
2010
- }
2011
- }
2012
- return {};
2013
- }]
2014
- };
2015
- }
2016
- function isLikelyFilePath(s) {
2017
- if (s.length > 4096)
2018
- return false;
2019
- if (/[<>$`\\()[\]{}=]/.test(s))
2020
- return false;
2021
- if (/^-?\d+$/.test(s))
2022
- return false;
2023
- if (s.includes("/"))
2024
- return true;
2025
- if (/\.[A-Za-z0-9]{1,16}$/.test(s))
2026
- return true;
2027
- return false;
2028
- }
2029
- function extractFileChangesFromBash(command) {
2030
- const changes = [];
2031
- const seen = new Set;
2032
- const addChange = (operation, path) => {
2033
- if (path === "/dev/null" || path === "/dev/stderr" || path === "/dev/stdout")
2034
- return;
2035
- if (!path.trim())
2036
- return;
2037
- const key = `${operation}:${path}`;
2038
- if (!seen.has(key)) {
2039
- seen.add(key);
2040
- changes.push({ operation, path });
2041
- }
2042
- };
2043
- const redirectRegex = /(?<![0-9=])>{1,2}\s*['"]?([^\s'";&|)]+)['"]?/g;
2044
- let match2;
2045
- while ((match2 = redirectRegex.exec(command)) !== null) {
2046
- if (isLikelyFilePath(match2[1])) {
2047
- addChange("wrote", match2[1]);
2048
- }
2049
- }
2050
- const teeRegex = /\btee\s+(?:-[a-zA-Z]\s+)*['"]?([^\s'";&|)]+)['"]?/g;
2051
- while ((match2 = teeRegex.exec(command)) !== null) {
2052
- addChange("wrote", match2[1]);
2053
- }
2054
- const sedRegex = /\bsed\s+(?:-[a-zA-Z]*i[a-zA-Z]*|-i)\b.*?['"]?([^\s'";&|)]+)['"]?\s*$/gm;
2055
- while ((match2 = sedRegex.exec(command)) !== null) {
2056
- addChange("edited", match2[1]);
2057
- }
2058
- return changes;
2059
- }
2060
- function extractFileChangesFromMessages(messages, extractFn) {
2061
- const changes = [];
2062
- const executedToolIds = new Set;
2063
- for (const msg of messages) {
2064
- if (msg.role !== "user")
2065
- continue;
2066
- const content = Array.isArray(msg.content) ? msg.content : [];
2067
- for (const block of content) {
2068
- if (block?.type === "tool_result" && block.tool_use_id) {
2069
- executedToolIds.add(block.tool_use_id);
2070
- }
2071
- }
2072
- }
2073
- for (const msg of messages) {
2074
- if (msg.role !== "assistant")
2075
- continue;
2076
- const content = Array.isArray(msg.content) ? msg.content : [];
2077
- for (const block of content) {
2078
- if (block?.type !== "tool_use")
2079
- continue;
2080
- if (!executedToolIds.has(block.id))
2081
- continue;
2082
- const blockChanges = extractFn(block.name, block.input);
2083
- changes.push(...blockChanges);
2084
- }
2085
- }
2086
- return changes;
2087
- }
2088
- function formatFileChangeSummary(changes) {
2089
- if (changes.length === 0)
2090
- return;
2091
- const seen = new Set;
2092
- const unique = [];
2093
- for (const c of changes) {
2094
- const key = `${c.operation}:${c.path}`;
2095
- if (!seen.has(key)) {
2096
- seen.add(key);
2097
- unique.push(c);
2098
- }
2099
- }
2100
- const lines = unique.map((c) => `- ${c.operation} ${c.path}`);
2101
- return `
2102
-
2103
- Files changed:
2104
- ${lines.join(`
2105
- `)}`;
2106
- }
2107
- var init_fileChanges = () => {};
2108
-
2109
2129
  // src/proxy/session/fingerprint.ts
2110
2130
  import { createHash } from "crypto";
2111
2131
  function extractClientCwd(body) {
@@ -2151,7 +2171,7 @@ var init_opencode = __esm(() => {
2151
2171
  openCodeTransforms = [
2152
2172
  {
2153
2173
  name: "opencode-core",
2154
- adapters: ["opencode", "openai", "codex"],
2174
+ adapters: ["opencode", "openai", "jcode", "codex"],
2155
2175
  onRequest(ctx) {
2156
2176
  const body = ctx.body;
2157
2177
  const blockedTools = BLOCKED_BUILTIN_TOOLS;
@@ -2325,6 +2345,51 @@ IMPORTANT: When using the task/Task tool, the subagent_type parameter must be on
2325
2345
  };
2326
2346
  });
2327
2347
 
2348
+ // src/proxy/adapters/openai.ts
2349
+ var openAiAdapter;
2350
+ var init_openai = __esm(() => {
2351
+ init_opencode2();
2352
+ openAiAdapter = {
2353
+ ...openCodeAdapter,
2354
+ name: "openai"
2355
+ };
2356
+ });
2357
+
2358
+ // src/proxy/adapters/jcode.ts
2359
+ function normalizeJcodeSessionId(value) {
2360
+ const trimmed = value?.trim();
2361
+ return trimmed && JCODE_SESSION_ID.test(trimmed) ? trimmed : undefined;
2362
+ }
2363
+ function isTextSystemBlock(value) {
2364
+ if (value === null || typeof value !== "object")
2365
+ return false;
2366
+ const part = value;
2367
+ return part.type === "text" && typeof part.text === "string";
2368
+ }
2369
+ function extractJcodeWorkingDirectory(body) {
2370
+ if (body === null || typeof body !== "object")
2371
+ return;
2372
+ const system = body.system;
2373
+ const text = typeof system === "string" ? system : Array.isArray(system) ? system.filter(isTextSystemBlock).map((part) => part.text).join(`
2374
+ `) : "";
2375
+ return text.match(/(?:^|\n)Working directory:[^\S\n]*([^\n]+)/)?.[1]?.trim() || undefined;
2376
+ }
2377
+ var JCODE_SESSION_ID, jcodeAdapter;
2378
+ var init_jcode = __esm(() => {
2379
+ init_openai();
2380
+ JCODE_SESSION_ID = /^[A-Za-z0-9._:-]{1,256}$/;
2381
+ jcodeAdapter = {
2382
+ ...openAiAdapter,
2383
+ name: "jcode",
2384
+ getSessionId(c) {
2385
+ return normalizeJcodeSessionId(c.req.header("x-jcode-session"));
2386
+ },
2387
+ extractWorkingDirectory(body) {
2388
+ return extractJcodeWorkingDirectory(body);
2389
+ }
2390
+ };
2391
+ });
2392
+
2328
2393
  // src/proxy/transforms/droid.ts
2329
2394
  function resolveDroidPassthrough() {
2330
2395
  return resolvePassthrough(false);
@@ -2815,32 +2880,161 @@ function extractPiCwd(body) {
2815
2880
  const match2 = systemText.match(/Current working directory:\s*([^\n]+)/i);
2816
2881
  return match2?.[1]?.trim() || undefined;
2817
2882
  }
2818
- var PI_MCP_SERVER_NAME2 = "pi", PI_ALLOWED_MCP_TOOLS2, piAdapter;
2819
- var init_pi2 = __esm(() => {
2883
+ var PI_MCP_SERVER_NAME2 = "pi", PI_ALLOWED_MCP_TOOLS2, piAdapter;
2884
+ var init_pi2 = __esm(() => {
2885
+ init_fileChanges();
2886
+ init_messages();
2887
+ init_tools();
2888
+ init_env();
2889
+ init_claudecode();
2890
+ init_pi();
2891
+ PI_ALLOWED_MCP_TOOLS2 = [
2892
+ `mcp__${PI_MCP_SERVER_NAME2}__read`,
2893
+ `mcp__${PI_MCP_SERVER_NAME2}__write`,
2894
+ `mcp__${PI_MCP_SERVER_NAME2}__edit`,
2895
+ `mcp__${PI_MCP_SERVER_NAME2}__bash`,
2896
+ `mcp__${PI_MCP_SERVER_NAME2}__glob`,
2897
+ `mcp__${PI_MCP_SERVER_NAME2}__grep`
2898
+ ];
2899
+ piAdapter = {
2900
+ name: "pi",
2901
+ getSessionId(c, body) {
2902
+ return c.req.header("x-session-affinity") ?? extractClaudeCodeSessionId(body);
2903
+ },
2904
+ extractWorkingDirectory(body) {
2905
+ return extractPiCwd(body);
2906
+ },
2907
+ extractClientWorkingDirectory(body) {
2908
+ return extractPiCwd(body);
2909
+ },
2910
+ normalizeContent(content) {
2911
+ return normalizeContent(content);
2912
+ },
2913
+ getBlockedBuiltinTools() {
2914
+ return BLOCKED_BUILTIN_TOOLS;
2915
+ },
2916
+ getAgentIncompatibleTools() {
2917
+ return CLAUDE_CODE_ONLY_TOOLS;
2918
+ },
2919
+ getMcpServerName() {
2920
+ return PI_MCP_SERVER_NAME2;
2921
+ },
2922
+ getAllowedMcpTools() {
2923
+ return PI_ALLOWED_MCP_TOOLS2;
2924
+ },
2925
+ buildSdkAgents(_body, _mcpToolNames) {
2926
+ return {};
2927
+ },
2928
+ supportsThinking() {
2929
+ return true;
2930
+ },
2931
+ buildSdkHooks(_body, _sdkAgents) {
2932
+ return;
2933
+ },
2934
+ buildSystemContextAddendum(_body, _sdkAgents) {
2935
+ return "";
2936
+ },
2937
+ usesPassthrough() {
2938
+ return resolvePassthrough(true);
2939
+ },
2940
+ extractFileChangesFromToolUse(toolName, toolInput) {
2941
+ const input = toolInput;
2942
+ const filePath = input?.filePath ?? input?.file_path ?? input?.path;
2943
+ if (toolName === "write" && filePath) {
2944
+ return [{ operation: "wrote", path: String(filePath) }];
2945
+ }
2946
+ if (toolName === "edit" && filePath) {
2947
+ return [{ operation: "edited", path: String(filePath) }];
2948
+ }
2949
+ if (toolName === "bash" && input?.command) {
2950
+ return extractFileChangesFromBash(String(input.command));
2951
+ }
2952
+ return [];
2953
+ }
2954
+ };
2955
+ });
2956
+
2957
+ // src/proxy/adapters/prime.ts
2958
+ function extractPrimeCwd(body) {
2959
+ let systemText = "";
2960
+ if (typeof body?.system === "string") {
2961
+ systemText = body.system;
2962
+ } else if (Array.isArray(body?.system)) {
2963
+ systemText = body.system.filter((b) => b?.type === "text" && b.text).map((b) => b.text).join(`
2964
+ `);
2965
+ }
2966
+ if (!systemText)
2967
+ return;
2968
+ const match2 = systemText.match(RLM_CWD_LINE) ?? systemText.match(CUSTOM_PROMPT_CWD_LINE);
2969
+ return match2?.[1]?.trim() || undefined;
2970
+ }
2971
+ function extractFileChangesFromIpythonCell(code) {
2972
+ const lines = code.split(`
2973
+ `);
2974
+ const firstMeaningful = lines.find((l) => l.trim().length > 0) ?? "";
2975
+ if (/^[ \t]*%%bash\b/.test(firstMeaningful)) {
2976
+ const bodyStart = lines.indexOf(firstMeaningful) + 1;
2977
+ return extractFileChangesFromBash(lines.slice(bodyStart).join(`
2978
+ `));
2979
+ }
2980
+ const changes = [];
2981
+ for (const line of lines) {
2982
+ const escaped = line.match(SHELL_ESCAPE_LINE);
2983
+ if (escaped?.[1])
2984
+ changes.push(...extractFileChangesFromBash(escaped[1]));
2985
+ }
2986
+ for (const m of code.matchAll(EDIT_SKILL_CALL)) {
2987
+ if (m[2])
2988
+ changes.push({ operation: "edited", path: m[2] });
2989
+ }
2990
+ return changes;
2991
+ }
2992
+ function extractPrimeFileChanges(toolName, toolInput) {
2993
+ const input = toolInput;
2994
+ if (toolName === "ipython" && typeof input?.code === "string") {
2995
+ return extractFileChangesFromIpythonCell(input.code);
2996
+ }
2997
+ const filePath = input?.path ?? input?.file_path ?? input?.filePath;
2998
+ if (toolName === "edit" && filePath) {
2999
+ return [{ operation: "edited", path: String(filePath) }];
3000
+ }
3001
+ if (toolName === "write" && filePath) {
3002
+ return [{ operation: "wrote", path: String(filePath) }];
3003
+ }
3004
+ if (toolName === "bash" && input?.command) {
3005
+ return extractFileChangesFromBash(String(input.command));
3006
+ }
3007
+ return [];
3008
+ }
3009
+ var PRIME_MCP_SERVER_NAME = "prime", PRIME_ALLOWED_MCP_TOOLS, RLM_CWD_LINE, CUSTOM_PROMPT_CWD_LINE, EDIT_SKILL_CALL, SHELL_ESCAPE_LINE, primeAdapter;
3010
+ var init_prime = __esm(() => {
2820
3011
  init_fileChanges();
2821
3012
  init_messages();
2822
3013
  init_tools();
2823
3014
  init_env();
2824
3015
  init_claudecode();
2825
- init_pi();
2826
- PI_ALLOWED_MCP_TOOLS2 = [
2827
- `mcp__${PI_MCP_SERVER_NAME2}__read`,
2828
- `mcp__${PI_MCP_SERVER_NAME2}__write`,
2829
- `mcp__${PI_MCP_SERVER_NAME2}__edit`,
2830
- `mcp__${PI_MCP_SERVER_NAME2}__bash`,
2831
- `mcp__${PI_MCP_SERVER_NAME2}__glob`,
2832
- `mcp__${PI_MCP_SERVER_NAME2}__grep`
3016
+ PRIME_ALLOWED_MCP_TOOLS = [
3017
+ `mcp__${PRIME_MCP_SERVER_NAME}__read`,
3018
+ `mcp__${PRIME_MCP_SERVER_NAME}__write`,
3019
+ `mcp__${PRIME_MCP_SERVER_NAME}__edit`,
3020
+ `mcp__${PRIME_MCP_SERVER_NAME}__bash`,
3021
+ `mcp__${PRIME_MCP_SERVER_NAME}__glob`,
3022
+ `mcp__${PRIME_MCP_SERVER_NAME}__grep`
2833
3023
  ];
2834
- piAdapter = {
2835
- name: "pi",
3024
+ RLM_CWD_LINE = /^Working directory:[ \t]*(.+)$/m;
3025
+ CUSTOM_PROMPT_CWD_LINE = /^Current working directory:[ \t]*(.+)$/m;
3026
+ EDIT_SKILL_CALL = /\bedit\s*\(\s*path\s*=\s*(['"])(.+?)\1/g;
3027
+ SHELL_ESCAPE_LINE = /^[ \t]*!(.+)$/;
3028
+ primeAdapter = {
3029
+ name: "prime",
2836
3030
  getSessionId(c, body) {
2837
3031
  return c.req.header("x-session-affinity") ?? extractClaudeCodeSessionId(body);
2838
3032
  },
2839
3033
  extractWorkingDirectory(body) {
2840
- return extractPiCwd(body);
3034
+ return extractPrimeCwd(body);
2841
3035
  },
2842
3036
  extractClientWorkingDirectory(body) {
2843
- return extractPiCwd(body);
3037
+ return extractPrimeCwd(body);
2844
3038
  },
2845
3039
  normalizeContent(content) {
2846
3040
  return normalizeContent(content);
@@ -2852,10 +3046,10 @@ var init_pi2 = __esm(() => {
2852
3046
  return CLAUDE_CODE_ONLY_TOOLS;
2853
3047
  },
2854
3048
  getMcpServerName() {
2855
- return PI_MCP_SERVER_NAME2;
3049
+ return PRIME_MCP_SERVER_NAME;
2856
3050
  },
2857
3051
  getAllowedMcpTools() {
2858
- return PI_ALLOWED_MCP_TOOLS2;
3052
+ return PRIME_ALLOWED_MCP_TOOLS;
2859
3053
  },
2860
3054
  buildSdkAgents(_body, _mcpToolNames) {
2861
3055
  return {};
@@ -2873,18 +3067,7 @@ var init_pi2 = __esm(() => {
2873
3067
  return resolvePassthrough(true);
2874
3068
  },
2875
3069
  extractFileChangesFromToolUse(toolName, toolInput) {
2876
- const input = toolInput;
2877
- const filePath = input?.filePath ?? input?.file_path ?? input?.path;
2878
- if (toolName === "write" && filePath) {
2879
- return [{ operation: "wrote", path: String(filePath) }];
2880
- }
2881
- if (toolName === "edit" && filePath) {
2882
- return [{ operation: "edited", path: String(filePath) }];
2883
- }
2884
- if (toolName === "bash" && input?.command) {
2885
- return extractFileChangesFromBash(String(input.command));
2886
- }
2887
- return [];
3070
+ return extractPrimeFileChanges(toolName, toolInput);
2888
3071
  }
2889
3072
  };
2890
3073
  });
@@ -3008,16 +3191,6 @@ var init_forgecode2 = __esm(() => {
3008
3191
  };
3009
3192
  });
3010
3193
 
3011
- // src/proxy/adapters/openai.ts
3012
- var openAiAdapter;
3013
- var init_openai = __esm(() => {
3014
- init_opencode2();
3015
- openAiAdapter = {
3016
- ...openCodeAdapter,
3017
- name: "openai"
3018
- };
3019
- });
3020
-
3021
3194
  // src/proxy/adapters/codex.ts
3022
3195
  var codexAdapter;
3023
3196
  var init_codex = __esm(() => {
@@ -3202,6 +3375,9 @@ function detectAdapter(c) {
3202
3375
  return openCodeAdapter;
3203
3376
  }
3204
3377
  const userAgent = c.req.header("user-agent") || "";
3378
+ if (userAgent.startsWith("jcode/") && normalizeJcodeSessionId(c.req.header("x-jcode-session"))) {
3379
+ return jcodeAdapter;
3380
+ }
3205
3381
  if (userAgent.startsWith("opencode/")) {
3206
3382
  return openCodeAdapter;
3207
3383
  }
@@ -3233,9 +3409,11 @@ var init_detect = __esm(() => {
3233
3409
  init_crush2();
3234
3410
  init_passthrough2();
3235
3411
  init_pi2();
3412
+ init_prime();
3236
3413
  init_forgecode2();
3237
3414
  init_claudecode();
3238
3415
  init_openai();
3416
+ init_jcode();
3239
3417
  init_codex();
3240
3418
  init_cherry();
3241
3419
  init_adapterInstances();
@@ -3245,12 +3423,15 @@ var init_detect = __esm(() => {
3245
3423
  crush: crushAdapter,
3246
3424
  passthrough: passthroughAdapter,
3247
3425
  pi: piAdapter,
3426
+ prime: primeAdapter,
3427
+ "prime-agent": primeAdapter,
3248
3428
  forgecode: forgeCodeAdapter,
3249
3429
  "claude-code": claudeCodeAdapter,
3250
3430
  claudecode: claudeCodeAdapter,
3251
3431
  cherry: cherryAdapter,
3252
3432
  cherrystudio: cherryAdapter,
3253
3433
  openai: openAiAdapter,
3434
+ jcode: jcodeAdapter,
3254
3435
  codex: codexAdapter
3255
3436
  };
3256
3437
  envDefault = process.env.MERIDIAN_DEFAULT_AGENT || "";
@@ -3401,9 +3582,15 @@ var init_sdkFeatures = __esm(() => {
3401
3582
  openai: {
3402
3583
  codeSystemPrompt: false
3403
3584
  },
3585
+ jcode: {
3586
+ codeSystemPrompt: false
3587
+ },
3404
3588
  cherry: {
3405
3589
  codeSystemPrompt: false
3406
3590
  },
3591
+ prime: {
3592
+ codeSystemPrompt: false
3593
+ },
3407
3594
  codex: {
3408
3595
  codeSystemPrompt: false
3409
3596
  }
@@ -6294,8 +6481,10 @@ var OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
6294
6481
  var OAUTH_BETA_HEADER = "oauth-2025-04-20";
6295
6482
  var CACHE_TTL_MS_DEFAULT = 30000;
6296
6483
  var STALE_MAX_MS_DEFAULT = 15 * 60000;
6484
+ var RATE_LIMIT_BACKOFF_MS_DEFAULT = 60000;
6297
6485
  var cacheByProfile = new Map;
6298
6486
  var inflightByProfile = new Map;
6487
+ var rateLimitedUntilByProfile = new Map;
6299
6488
  var DEFAULT_KEY = "__default__";
6300
6489
  var WINDOW_TYPES = [
6301
6490
  "five_hour",
@@ -6317,6 +6506,15 @@ function normalizeUtilization(raw2) {
6317
6506
  return null;
6318
6507
  return Math.max(0, raw2 / 100);
6319
6508
  }
6509
+ function parseRetryAfterMs(raw2) {
6510
+ if (!raw2)
6511
+ return null;
6512
+ const seconds = Number(raw2);
6513
+ if (Number.isFinite(seconds))
6514
+ return Math.max(0, seconds * 1000);
6515
+ const retryAt = Date.parse(raw2);
6516
+ return Number.isFinite(retryAt) ? Math.max(0, retryAt - Date.now()) : null;
6517
+ }
6320
6518
  function modelScopedWindowType(limit) {
6321
6519
  if (limit.kind !== "weekly_scoped")
6322
6520
  return null;
@@ -6374,14 +6572,27 @@ async function callAnthropic(token, fetchImpl, signal) {
6374
6572
  },
6375
6573
  signal: signal ?? AbortSignal.timeout(1e4)
6376
6574
  });
6377
- if (!res.ok)
6378
- return { __status: res.status };
6575
+ if (!res.ok) {
6576
+ return {
6577
+ __status: res.status,
6578
+ retryAfterMs: parseRetryAfterMs(res.headers.get("retry-after"))
6579
+ };
6580
+ }
6379
6581
  return await res.json();
6380
6582
  }
6381
6583
  var _testOverride = null;
6382
6584
  async function fetchOAuthUsage(opts) {
6585
+ return (await fetchOAuthUsageResult(opts)).snapshot;
6586
+ }
6587
+ function missingReason(cacheKey2) {
6588
+ const until = rateLimitedUntilByProfile.get(cacheKey2);
6589
+ return until !== undefined && Date.now() < until ? "rate_limited" : "no_token";
6590
+ }
6591
+ async function fetchOAuthUsageResult(opts) {
6383
6592
  if (_testOverride && !opts?.fetchImpl && !opts?.store) {
6384
- return _testOverride(opts);
6593
+ const snapshot = await _testOverride(opts);
6594
+ const error = snapshot ? null : missingReason(opts?.profileId ?? DEFAULT_KEY);
6595
+ return { snapshot, error };
6385
6596
  }
6386
6597
  return fetchOAuthUsageImpl(opts);
6387
6598
  }
@@ -6389,30 +6600,37 @@ async function fetchOAuthUsageImpl(opts) {
6389
6600
  const ttl = opts?.ttlMs ?? CACHE_TTL_MS_DEFAULT;
6390
6601
  const cacheKey2 = opts?.profileId ?? DEFAULT_KEY;
6391
6602
  const fetchImpl = opts?.fetchImpl ?? globalThis.fetch;
6603
+ const staleMaxMs = opts?.staleMaxMs ?? STALE_MAX_MS_DEFAULT;
6604
+ const staleOr = (reason, error) => {
6605
+ const last = cacheByProfile.get(cacheKey2);
6606
+ if (last && Date.now() - last.fetchedAt < staleMaxMs) {
6607
+ claudeLog("oauth_usage.serving_stale", { profile: cacheKey2, reason, ageMs: Date.now() - last.fetchedAt });
6608
+ return { snapshot: { ...last, stale: true }, error: null };
6609
+ }
6610
+ return { snapshot: null, error };
6611
+ };
6392
6612
  if (!opts?.force) {
6393
6613
  const cached = cacheByProfile.get(cacheKey2);
6394
6614
  if (cached && Date.now() - cached.fetchedAt < ttl)
6395
- return cached;
6615
+ return { snapshot: cached, error: null };
6396
6616
  }
6397
6617
  const existing = inflightByProfile.get(cacheKey2);
6398
6618
  if (existing)
6399
6619
  return existing;
6620
+ const rateLimitedUntil = rateLimitedUntilByProfile.get(cacheKey2);
6621
+ if (rateLimitedUntil !== undefined) {
6622
+ if (Date.now() < rateLimitedUntil)
6623
+ return staleOr("rate_limited", "rate_limited");
6624
+ rateLimitedUntilByProfile.delete(cacheKey2);
6625
+ }
6400
6626
  const store = opts?.store ?? createPlatformCredentialStore({ claudeConfigDir: opts?.claudeConfigDir });
6401
- const staleMaxMs = opts?.staleMaxMs ?? STALE_MAX_MS_DEFAULT;
6402
- const staleOr = (reason) => {
6403
- const last = cacheByProfile.get(cacheKey2);
6404
- if (last && Date.now() - last.fetchedAt < staleMaxMs) {
6405
- claudeLog("oauth_usage.serving_stale", { profile: cacheKey2, reason, ageMs: Date.now() - last.fetchedAt });
6406
- return { ...last, stale: true };
6407
- }
6408
- return null;
6409
- };
6627
+ const rateLimitBackoffMs = opts?.rateLimitBackoffMs ?? RATE_LIMIT_BACKOFF_MS_DEFAULT;
6410
6628
  const promise = (async () => {
6411
6629
  try {
6412
6630
  const token = await readAccessToken(store);
6413
6631
  if (!token) {
6414
6632
  claudeLog("oauth_usage.no_token", { profile: cacheKey2 });
6415
- return staleOr("no_token");
6633
+ return staleOr("no_token", "no_token");
6416
6634
  }
6417
6635
  let result = await callAnthropic(token, fetchImpl);
6418
6636
  if ("__status" in result && result.__status === 401) {
@@ -6420,23 +6638,28 @@ async function fetchOAuthUsageImpl(opts) {
6420
6638
  const refreshed = await refreshOAuthToken(store);
6421
6639
  if (!refreshed) {
6422
6640
  claudeLog("oauth_usage.refresh_failed", { profile: cacheKey2 });
6423
- return staleOr("refresh_failed");
6641
+ return staleOr("refresh_failed", "upstream_error");
6424
6642
  }
6425
6643
  const newToken = await readAccessToken(store);
6426
6644
  if (!newToken)
6427
- return staleOr("no_token_after_refresh");
6645
+ return staleOr("no_token_after_refresh", "no_token");
6428
6646
  result = await callAnthropic(newToken, fetchImpl);
6429
6647
  }
6430
6648
  if ("__status" in result) {
6649
+ if (result.__status === 429) {
6650
+ const retryAfterMs = Math.min(Math.max(rateLimitBackoffMs, result.retryAfterMs ?? 0), Math.max(staleMaxMs, rateLimitBackoffMs));
6651
+ rateLimitedUntilByProfile.set(cacheKey2, Date.now() + retryAfterMs);
6652
+ }
6431
6653
  claudeLog("oauth_usage.upstream_error", { profile: cacheKey2, status: result.__status });
6432
- return staleOr(`upstream_${result.__status}`);
6654
+ return staleOr(`upstream_${result.__status}`, result.__status === 429 ? "rate_limited" : "upstream_error");
6433
6655
  }
6656
+ rateLimitedUntilByProfile.delete(cacheKey2);
6434
6657
  const snapshot = buildSnapshot(result);
6435
6658
  cacheByProfile.set(cacheKey2, snapshot);
6436
- return snapshot;
6659
+ return { snapshot, error: null };
6437
6660
  } catch (err) {
6438
6661
  claudeLog("oauth_usage.fetch_failed", { profile: cacheKey2, error: err instanceof Error ? err.message : String(err) });
6439
- return staleOr("exception");
6662
+ return staleOr("exception", "upstream_error");
6440
6663
  } finally {
6441
6664
  inflightByProfile.delete(cacheKey2);
6442
6665
  }
@@ -10715,6 +10938,31 @@ function shouldEarlyStop(tracker) {
10715
10938
  tracker.fired = true;
10716
10939
  return true;
10717
10940
  }
10941
+ function clientAbortDisposition(input) {
10942
+ if (input.isIndependentSession || !input.profileSessionId)
10943
+ return { action: "none" };
10944
+ if (!input.passthrough)
10945
+ return { action: "evict" };
10946
+ if (input.currentSessionId && !input.sawDuplicateToolUse && input.resumeBoundaryUuid) {
10947
+ return { action: "store", resumeUuid: input.resumeBoundaryUuid };
10948
+ }
10949
+ return { action: "evict" };
10950
+ }
10951
+ function resumeBoundaryUuid(message) {
10952
+ const m = message;
10953
+ if (m?.type !== "user")
10954
+ return;
10955
+ if (typeof m.uuid !== "string" || m.uuid.length === 0)
10956
+ return;
10957
+ const content = m.message?.content;
10958
+ if (!Array.isArray(content))
10959
+ return;
10960
+ const hasResult = content.some((block) => {
10961
+ const b = block;
10962
+ return b?.type === "tool_result";
10963
+ });
10964
+ return hasResult ? m.uuid : undefined;
10965
+ }
10718
10966
 
10719
10967
  // src/proxy/envelopeIntegrity.ts
10720
10968
  function checkEmptyToolInputs(contentBlocks, tools) {
@@ -10755,6 +11003,68 @@ function checkUndeliveredToolUses(captured, deliveredIds) {
10755
11003
  return violations;
10756
11004
  }
10757
11005
 
11006
+ // src/proxy/turnOutcome.ts
11007
+ function classifyTurnOutcome(input) {
11008
+ if (input.toolUses > 0)
11009
+ return { kind: "productive" };
11010
+ if (input.textEvents > 0)
11011
+ return { kind: "productive" };
11012
+ return {
11013
+ kind: "silent",
11014
+ reason: input.blocksForwarded > 0 ? "no_actionable_content" : "no_blocks"
11015
+ };
11016
+ }
11017
+ var SILENT_TURN_NUDGE = "Your previous turn produced no visible output — no text and no tool call — so the client received " + "nothing to act on. Any earlier instruction to end your turn without further text applied only to " + "that turn and is now discharged. Answer now, in text, addressing the most recent request and any " + "tool results above it. If a tool call is still required, make it.";
11018
+ function shouldInjectSilentTurn(input) {
11019
+ if (!input.raw)
11020
+ return false;
11021
+ if (input.raw === "1")
11022
+ return true;
11023
+ return Boolean(input.sessionId && input.raw === input.sessionId);
11024
+ }
11025
+ function createRecoveryLifter(allocateBlockIndex) {
11026
+ let blockIndex;
11027
+ return {
11028
+ lift(innerEvent) {
11029
+ const inner = innerEvent;
11030
+ if (!inner)
11031
+ return;
11032
+ if (inner.type === "content_block_start" && inner.content_block?.type === "text") {
11033
+ blockIndex = allocateBlockIndex();
11034
+ return {
11035
+ kind: "block_start",
11036
+ frame: { type: "content_block_start", index: blockIndex, content_block: { type: "text", text: "" } }
11037
+ };
11038
+ }
11039
+ if (inner.type === "content_block_delta" && inner.delta?.type === "text_delta" && blockIndex !== undefined) {
11040
+ const text = inner.delta.text;
11041
+ return {
11042
+ kind: "text_delta",
11043
+ frame: { type: "content_block_delta", index: blockIndex, delta: { type: "text_delta", text } },
11044
+ textChars: typeof text === "string" ? text.length : 0
11045
+ };
11046
+ }
11047
+ if (inner.type === "content_block_stop" && blockIndex !== undefined) {
11048
+ const index = blockIndex;
11049
+ blockIndex = undefined;
11050
+ return { kind: "block_stop", frame: { type: "content_block_stop", index } };
11051
+ }
11052
+ return;
11053
+ }
11054
+ };
11055
+ }
11056
+ function shouldAttemptRecovery(input) {
11057
+ if (!input.enabled)
11058
+ return false;
11059
+ if (input.outcome.kind === "productive")
11060
+ return false;
11061
+ if (input.alreadyAttempted)
11062
+ return false;
11063
+ if (input.clientGone)
11064
+ return false;
11065
+ return Boolean(input.sessionId);
11066
+ }
11067
+
10758
11068
  // src/proxy/server.ts
10759
11069
  init_agentMatch();
10760
11070
 
@@ -11594,7 +11904,14 @@ function profileSection(q,s,pl,h){
11594
11904
  var orderIdx=(pl.profileOrder||[]).indexOf(p.id);
11595
11905
  if(orderIdx>=0)badge+='<span class="pool-chip">#'+(orderIdx+1)+' in pool</span>';
11596
11906
  var exh=(pl.exhausted||[]).filter(function(e){return e.id===p.id})[0];
11597
- if(exh)badge+=' <span class="pool-chip exhausted">exhausted · resets '+resetIn(exh.until)+'</span>';
11907
+ if(exh){
11908
+ // A billing refusal has no reset to wait for — the pool re-probes on the
11909
+ // same timer, but nothing changes until a human fixes the account.
11910
+ // Showing it as 'resets in 9m' promises a recovery that never comes.
11911
+ badge+=exh.reason==='billing_error'
11912
+ ?' <span class="pool-chip exhausted" title="Subscription or payment refused — this does not clear on its own">subscription refused</span>'
11913
+ :' <span class="pool-chip exhausted">exhausted · resets '+resetIn(exh.until)+'</span>';
11914
+ }
11598
11915
  }
11599
11916
  cards+='<div class="profile-card'+(p.isActive?' active':'')+(switchable?' switchable':'')+'"'+(switchable?' data-profile="'+esc(p.id)+'" role="button" tabindex="0"':'')+'>'
11600
11917
  +'<div class="profile-head"><span class="profile-name"><span class="prof-dot"></span>'+esc(p.label||p.id)+' '+badge+'</span>'
@@ -11780,6 +12097,17 @@ function extendedContextHint(model) {
11780
12097
  return advise("MERIDIAN_SONNET_MODEL=sonnet");
11781
12098
  return advise("MERIDIAN_1M_CONTEXT_SUPPORT=0");
11782
12099
  }
12100
+ var BILLING_SIGNALS = [
12101
+ /\b402\b(?!:\d)/,
12102
+ /billing[_ ](?:error|issue|problem|failure)/,
12103
+ /subscription (?:is |has )?(?:inactive|expired|lapsed|cancell?ed|ended|invalid|not active)/,
12104
+ /(?:expired|inactive|lapsed|invalid|no active|cancell?ed) subscription/,
12105
+ /payment (?:method|required|failed|declined|details|info)/,
12106
+ /update your payment/,
12107
+ /(?:out of|draw from|draws from) extra usage/,
12108
+ /insufficient (?:credit|funds|balance)/
12109
+ ];
12110
+ var HIT_YOUR_LIMIT = /hit your (?:[\w-]+ )?limit/;
11783
12111
  function classifyError(errMsg, model) {
11784
12112
  const lower = errMsg.toLowerCase();
11785
12113
  if (lower.includes("oauth token has expired") || lower.includes("not logged in")) {
@@ -11796,7 +12124,7 @@ function classifyError(errMsg, model) {
11796
12124
  message: "Claude authentication expired or invalid. Run 'claude login' in your terminal to re-authenticate, then restart the proxy."
11797
12125
  };
11798
12126
  }
11799
- if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests") || lower.includes("hit your session limit") || lower.includes("usage limit reached")) {
12127
+ if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests") || HIT_YOUR_LIMIT.test(lower) || lower.includes("usage limit reached")) {
11800
12128
  const hint = lower.includes("1m") || lower.includes("context") ? extendedContextHint(model) : "";
11801
12129
  return {
11802
12130
  status: 429,
@@ -11804,7 +12132,7 @@ function classifyError(errMsg, model) {
11804
12132
  message: `Claude Max rate limit reached. Wait a moment and try again.${hint}`
11805
12133
  };
11806
12134
  }
11807
- if (lower.includes("402") || lower.includes("billing") || lower.includes("subscription") || lower.includes("payment")) {
12135
+ if (BILLING_SIGNALS.some((rx) => rx.test(lower))) {
11808
12136
  return {
11809
12137
  status: 402,
11810
12138
  type: "billing_error",
@@ -11889,6 +12217,16 @@ function isRateLimitError(errMsg) {
11889
12217
  const lower = errMsg.toLowerCase();
11890
12218
  return lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests");
11891
12219
  }
12220
+ var ACCOUNT_FAILOVER_ERROR_TYPES = new Set([
12221
+ "rate_limit_error",
12222
+ "billing_error"
12223
+ ]);
12224
+ function isAccountFailoverError(errorType) {
12225
+ return typeof errorType === "string" && ACCOUNT_FAILOVER_ERROR_TYPES.has(errorType);
12226
+ }
12227
+ function isQuotaRefusal(errorType) {
12228
+ return errorType === "rate_limit_error";
12229
+ }
11892
12230
  function isExtraUsageRequiredError(errMsg) {
11893
12231
  const lower = errMsg.toLowerCase();
11894
12232
  return lower.includes("extra usage") && lower.includes("1m") || lower.includes("out of extra usage");
@@ -12279,7 +12617,7 @@ ${c.text}
12279
12617
  return "";
12280
12618
  }).filter(Boolean).join("");
12281
12619
  }
12282
- function translateOpenAiToAnthropic(body) {
12620
+ function translateOpenAiToAnthropic(body, options = {}) {
12283
12621
  const messages = body.messages ?? [];
12284
12622
  if (messages.length === 0)
12285
12623
  return null;
@@ -12371,7 +12709,7 @@ function translateOpenAiToAnthropic(body) {
12371
12709
  let systemPrompt = systemParts.join(`
12372
12710
  `);
12373
12711
  let messagesToSend = turns;
12374
- if (turns.length > 1) {
12712
+ if (turns.length > 1 && !options.preserveConversationHistory) {
12375
12713
  const history = turns.slice(0, -1).map((m) => `${m.role}: ${summarizeAnthropicContent(m.content)}`).join(`
12376
12714
  `);
12377
12715
  const historyBlock = `<conversation_history>
@@ -12666,6 +13004,9 @@ function buildModelList(isMaxSubscription, now = Math.floor(Date.now() / 1000))
12666
13004
  ];
12667
13005
  }
12668
13006
 
13007
+ // src/proxy/server.ts
13008
+ init_jcode();
13009
+
12669
13010
  // src/proxy/openaiResponses.ts
12670
13011
  function itemDiscriminator(item) {
12671
13012
  if (typeof item !== "object" || item === null)
@@ -18858,7 +19199,7 @@ function buildQueryOptions(ctx, abortController) {
18858
19199
  hasDeferredTools,
18859
19200
  resumeSessionId,
18860
19201
  isUndo,
18861
- undoRollbackUuid,
19202
+ resumeSessionAtUuid,
18862
19203
  forkSession,
18863
19204
  sdkHooks,
18864
19205
  blockedTools,
@@ -18929,7 +19270,7 @@ function buildQueryOptions(ctx, abortController) {
18929
19270
  ...Object.keys(sdkAgents).length > 0 ? { agents: sdkAgents } : {},
18930
19271
  ...resumeSessionId ? { resume: resumeSessionId } : {},
18931
19272
  ...isUndo || forkSession ? { forkSession: true } : {},
18932
- ...isUndo && undoRollbackUuid ? { resumeSessionAt: undoRollbackUuid } : {},
19273
+ ...resumeSessionAtUuid ? { resumeSessionAt: resumeSessionAtUuid } : {},
18933
19274
  ...sdkHooks ? { hooks: sdkHooks } : {},
18934
19275
  ...effort ? { effort } : {},
18935
19276
  ...thinking ? { thinking } : {},
@@ -18990,6 +19331,34 @@ init_opencode();
18990
19331
  init_crush();
18991
19332
  init_droid();
18992
19333
  init_pi();
19334
+
19335
+ // src/proxy/transforms/prime.ts
19336
+ init_tools();
19337
+ init_env();
19338
+ init_prime();
19339
+ function resolvePrimePassthrough() {
19340
+ return resolvePassthrough(true);
19341
+ }
19342
+ var primeTransforms = [
19343
+ {
19344
+ name: "prime-core",
19345
+ adapters: ["prime"],
19346
+ onRequest(ctx) {
19347
+ return {
19348
+ ...ctx,
19349
+ blockedTools: BLOCKED_BUILTIN_TOOLS,
19350
+ incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
19351
+ allowedMcpTools: PRIME_ALLOWED_MCP_TOOLS,
19352
+ sdkAgents: {},
19353
+ passthrough: resolvePrimePassthrough(),
19354
+ supportsThinking: true,
19355
+ extractFileChangesFromToolUse: extractPrimeFileChanges
19356
+ };
19357
+ }
19358
+ }
19359
+ ];
19360
+
19361
+ // src/proxy/transforms/registry.ts
18993
19362
  init_forgecode();
18994
19363
  init_passthrough();
18995
19364
 
@@ -19071,11 +19440,13 @@ var ADAPTER_TRANSFORMS = {
19071
19440
  crush: crushTransforms,
19072
19441
  droid: droidTransforms,
19073
19442
  pi: piTransforms,
19443
+ prime: primeTransforms,
19074
19444
  forgecode: forgeCodeTransforms,
19075
19445
  passthrough: passthroughTransforms,
19076
19446
  cherry: cherryTransforms,
19077
19447
  "claude-code": claudeCodeTransforms,
19078
19448
  openai: openCodeTransforms,
19449
+ jcode: openCodeTransforms,
19079
19450
  codex: [...openCodeTransforms, ...codexTransforms]
19080
19451
  };
19081
19452
  function getAdapterTransforms(adapterName) {
@@ -19088,7 +19459,7 @@ import { join as join5, isAbsolute as isAbsolute2, extname } from "path";
19088
19459
  import { pathToFileURL } from "url";
19089
19460
 
19090
19461
  // src/proxy/plugins/validation.ts
19091
- var KNOWN_ADAPTERS = ["opencode", "openai", "crush", "droid", "pi", "forgecode", "passthrough"];
19462
+ var KNOWN_ADAPTERS = ["opencode", "openai", "jcode", "crush", "droid", "pi", "forgecode", "passthrough"];
19092
19463
  var KNOWN_HOOKS = ["onRequest", "onResponse", "onTelemetry", "onSession", "onToolUse", "onToolResult", "onError"];
19093
19464
  function validateTransform(exported) {
19094
19465
  if (exported == null || typeof exported !== "object") {
@@ -19443,11 +19814,66 @@ function computeLineageHash(messages) {
19443
19814
  function hashMessage(message) {
19444
19815
  return createHash2("sha256").update(`${message.role}:${normalizeContent(message.content)}`).digest("hex").slice(0, 32);
19445
19816
  }
19817
+ function describeShape(message) {
19818
+ const normalized = normalizeContent(message.content);
19819
+ return {
19820
+ role: message.role,
19821
+ blocks: Array.isArray(message.content) ? message.content.map((b) => String(b?.type ?? "unknown")).join(",") : typeof message.content === "string" ? "string" : "unknown",
19822
+ bytes: Buffer.byteLength(normalized, "utf8")
19823
+ };
19824
+ }
19825
+ function describeLineageMismatch(cached, messages, precomputedIncomingHashes) {
19826
+ const storedHashes = cached.messageHashes ?? [];
19827
+ const incomingHashes = precomputedIncomingHashes ?? computeMessageHashes(messages);
19828
+ const limit = Math.min(storedHashes.length, incomingHashes.length);
19829
+ let index = -1;
19830
+ for (let i = 0;i < limit; i++) {
19831
+ if (storedHashes[i] !== incomingHashes[i]) {
19832
+ index = i;
19833
+ break;
19834
+ }
19835
+ }
19836
+ const base = {
19837
+ index,
19838
+ storedCount: cached.messageCount,
19839
+ incomingCount: messages.length
19840
+ };
19841
+ if (index < 0)
19842
+ return base;
19843
+ return {
19844
+ ...base,
19845
+ storedDigest: storedHashes[index],
19846
+ incomingDigest: incomingHashes[index],
19847
+ incomingShape: messages[index] ? describeShape(messages[index]) : undefined,
19848
+ previousDigest: index > 0 ? storedHashes[index - 1] : undefined
19849
+ };
19850
+ }
19851
+ function formatLineageMismatch(mismatch) {
19852
+ if (mismatch.index < 0)
19853
+ return;
19854
+ const short = (digest) => digest ? digest.slice(0, 12) : "—";
19855
+ const trailing = mismatch.index === mismatch.storedCount - 1 ? " (trailing message only — the rest of the history matched)" : "";
19856
+ const shape = mismatch.incomingShape ? `${mismatch.incomingShape.role}[${mismatch.incomingShape.blocks}] ${mismatch.incomingShape.bytes}B` : "unknown";
19857
+ return `first mismatch at index ${mismatch.index}${trailing}: ` + `stored=${short(mismatch.storedDigest)} incoming=${short(mismatch.incomingDigest)}, ` + `incoming now ${shape}`;
19858
+ }
19446
19859
  function computeMessageHashes(messages) {
19447
19860
  if (!messages || messages.length === 0)
19448
19861
  return [];
19449
19862
  return messages.map(hashMessage);
19450
19863
  }
19864
+ function hashNormalizedContent(content) {
19865
+ return createHash2("sha256").update(normalizeContent(content)).digest("hex").slice(0, 32);
19866
+ }
19867
+ function hashableContentBlocks(content) {
19868
+ if (!Array.isArray(content))
19869
+ return [content];
19870
+ return content.filter((block) => !HASH_IGNORED_BLOCK_TYPES.has(block?.type));
19871
+ }
19872
+ function computeMessageBlockHashes(messages) {
19873
+ if (!messages || messages.length === 0)
19874
+ return [];
19875
+ return messages.map((message) => hashableContentBlocks(message.content).map((block) => hashNormalizedContent(Array.isArray(message.content) ? [block] : block)));
19876
+ }
19451
19877
  function measurePrefixOverlap(storedHashes, incomingHashes) {
19452
19878
  let overlap = 0;
19453
19879
  const minLen = Math.min(storedHashes.length, incomingHashes.length);
@@ -19530,6 +19956,34 @@ function verifyLineage(cached, messages) {
19530
19956
  suffixOverlap
19531
19957
  };
19532
19958
  }
19959
+ const boundary = cached.messageCount - 1;
19960
+ if (boundary >= 0 && prefixOverlap === boundary && messages.length >= cached.messageCount && cached.messageBlockHashes?.length === cached.messageCount) {
19961
+ const incomingBoundary = messages[boundary];
19962
+ const storedBlocks = cached.messageBlockHashes[boundary];
19963
+ if (incomingBoundary?.role === "user" && storedBlocks && Array.isArray(incomingBoundary.content)) {
19964
+ const incomingBlocks = hashableContentBlocks(incomingBoundary.content);
19965
+ const incomingBlockHashes = incomingBlocks.map((block) => hashNormalizedContent([block]));
19966
+ const preservesStoredBlocks = incomingBlocks.length === incomingBoundary.content.length && incomingBlockHashes.length > storedBlocks.length && storedBlocks.every((hash, index) => incomingBlockHashes[index] === hash);
19967
+ const appendedBlocks = incomingBlocks.slice(storedBlocks.length);
19968
+ const seenToolResultIds = new Set(incomingBlocks.slice(0, storedBlocks.length).filter((block) => block?.type === "tool_result" && typeof block.tool_use_id === "string").map((block) => block.tool_use_id));
19969
+ const hasOnlyNewToolResults = appendedBlocks.every((block) => {
19970
+ if (block?.type !== "tool_result" || typeof block.tool_use_id !== "string")
19971
+ return false;
19972
+ if (seenToolResultIds.has(block.tool_use_id))
19973
+ return false;
19974
+ seenToolResultIds.add(block.tool_use_id);
19975
+ return true;
19976
+ });
19977
+ if (preservesStoredBlocks && hasOnlyNewToolResults) {
19978
+ return {
19979
+ type: "continuation",
19980
+ session: cached,
19981
+ resumeFrom: boundary,
19982
+ resumeContentFrom: storedBlocks.length
19983
+ };
19984
+ }
19985
+ }
19986
+ }
19533
19987
  if (prefixOverlap > 0 && suffixOverlap === 0 && messages.length <= cached.messageCount) {
19534
19988
  let rollbackUuid;
19535
19989
  if (cached.sdkMessageUuids) {
@@ -19543,7 +19997,12 @@ function verifyLineage(cached, messages) {
19543
19997
  return { type: "undo", session: cached, prefixOverlap, rollbackUuid };
19544
19998
  }
19545
19999
  if (prefixOverlap > 0 && messages.length > cached.messageCount) {
19546
- return { type: "diverged", reason: "modified-history", prefixOverlap };
20000
+ return {
20001
+ type: "diverged",
20002
+ reason: "modified-history",
20003
+ prefixOverlap,
20004
+ mismatch: describeLineageMismatch(cached, messages, incomingHashes)
20005
+ };
19547
20006
  }
19548
20007
  return { type: "diverged", reason: "unrelated-history", prefixOverlap };
19549
20008
  }
@@ -19676,7 +20135,7 @@ function lookupSharedSessionByClaudeId(claudeSessionId) {
19676
20135
  }
19677
20136
  return newest;
19678
20137
  }
19679
- function storeSharedSession(key, claudeSessionId, messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage) {
20138
+ function storeSharedSession(key, claudeSessionId, messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage, messageBlockHashes, passthroughResumeUuid) {
19680
20139
  const path3 = getStorePath();
19681
20140
  const lockPath = `${path3}.lock`;
19682
20141
  const hasLock = skipLocking ? false : acquireLock(lockPath);
@@ -19694,7 +20153,9 @@ function storeSharedSession(key, claudeSessionId, messageCount, lineageHash, mes
19694
20153
  messageCount: messageCount ?? existing?.messageCount ?? 0,
19695
20154
  lineageHash: lineageHash ?? existing?.lineageHash,
19696
20155
  messageHashes: messageHashes ?? existing?.messageHashes,
20156
+ messageBlockHashes: messageBlockHashes ?? existing?.messageBlockHashes,
19697
20157
  sdkMessageUuids: sdkMessageUuids ?? existing?.sdkMessageUuids,
20158
+ passthroughResumeUuid: passthroughResumeUuid === undefined ? existing?.passthroughResumeUuid : passthroughResumeUuid ?? undefined,
19698
20159
  contextUsage: contextUsage ?? existing?.contextUsage,
19699
20160
  ...previousClaudeSessionId ? { previousClaudeSessionId } : {}
19700
20161
  };
@@ -19852,7 +20313,11 @@ function touchSession(state) {
19852
20313
  }
19853
20314
  function classifyLineage(state, messages, cacheKey2) {
19854
20315
  const result = verifyLineage(state, messages);
19855
- if (result.type === "compaction") {
20316
+ if (result.type === "continuation" && result.resumeContentFrom !== undefined) {
20317
+ const msg = `Parallel tool-result continuation (key=${cacheKey2.slice(0, 8)}…): resume from message ${result.resumeFrom}, content block ${result.resumeContentFrom}.`;
20318
+ console.error(`[PROXY] ${msg}`);
20319
+ diagnosticLog2.lineage(msg);
20320
+ } else if (result.type === "compaction") {
19856
20321
  const msg = `Compaction detected (key=${cacheKey2.slice(0, 8)}…): suffix overlap ${result.suffixOverlap}/${state.messageCount}, resume from incoming message ${result.resumeFrom}.`;
19857
20322
  console.error(`[PROXY] ${msg}`);
19858
20323
  diagnosticLog2.lineage(msg);
@@ -19861,7 +20326,9 @@ function classifyLineage(state, messages, cacheKey2) {
19861
20326
  console.error(`[PROXY] ${msg}`);
19862
20327
  diagnosticLog2.lineage(msg);
19863
20328
  } else if (result.type === "diverged" && result.reason === "modified-history") {
19864
- const msg = `Stale session detected (key=${cacheKey2.slice(0, 8)}…): prefix overlap ${result.prefixOverlap || 0}/${state.messageCount}, incoming ${messages.length} msgs. Starting fresh replay.`;
20329
+ const detail = result.mismatch ? formatLineageMismatch(result.mismatch) : undefined;
20330
+ const msg = `Stale session detected (key=${cacheKey2.slice(0, 8)}…): prefix overlap ${result.prefixOverlap || 0}/${state.messageCount}, incoming ${messages.length} msgs. Starting fresh replay.` + (detail ? `
20331
+ ${detail}` : "");
19865
20332
  console.error(`[PROXY] ${msg}`);
19866
20333
  diagnosticLog2.lineage(msg);
19867
20334
  }
@@ -19884,7 +20351,9 @@ function lookupSession(sessionId, messages, workingDirectory) {
19884
20351
  messageCount: shared.messageCount || 0,
19885
20352
  lineageHash: shared.lineageHash || "",
19886
20353
  messageHashes: shared.messageHashes,
20354
+ messageBlockHashes: shared.messageBlockHashes,
19887
20355
  sdkMessageUuids: shared.sdkMessageUuids,
20356
+ passthroughResumeUuid: shared.passthroughResumeUuid,
19888
20357
  contextUsage: shared.contextUsage
19889
20358
  };
19890
20359
  const result = classifyLineage(state, messages, sessionId);
@@ -19912,7 +20381,9 @@ function lookupSession(sessionId, messages, workingDirectory) {
19912
20381
  messageCount: shared.messageCount || 0,
19913
20382
  lineageHash: shared.lineageHash || "",
19914
20383
  messageHashes: shared.messageHashes,
20384
+ messageBlockHashes: shared.messageBlockHashes,
19915
20385
  sdkMessageUuids: shared.sdkMessageUuids,
20386
+ passthroughResumeUuid: shared.passthroughResumeUuid,
19916
20387
  contextUsage: shared.contextUsage
19917
20388
  };
19918
20389
  const result = classifyLineage(state, messages, fp);
@@ -19945,24 +20416,29 @@ function getSessionByClaudeId(claudeSessionId) {
19945
20416
  messageCount: shared.messageCount || 0,
19946
20417
  lineageHash: shared.lineageHash || "",
19947
20418
  messageHashes: shared.messageHashes,
20419
+ messageBlockHashes: shared.messageBlockHashes,
19948
20420
  sdkMessageUuids: shared.sdkMessageUuids,
20421
+ passthroughResumeUuid: shared.passthroughResumeUuid,
19949
20422
  contextUsage: shared.contextUsage
19950
20423
  });
19951
20424
  }
19952
20425
  return newest;
19953
20426
  }
19954
- function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sdkMessageUuids, contextUsage) {
20427
+ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sdkMessageUuids, contextUsage, passthroughResumeUuid) {
19955
20428
  if (!claudeSessionId)
19956
20429
  return;
19957
20430
  const lineageHash = computeLineageHash(messages);
19958
20431
  const messageHashes = computeMessageHashes(messages);
20432
+ const messageBlockHashes = computeMessageBlockHashes(messages);
19959
20433
  const state = {
19960
20434
  claudeSessionId,
19961
20435
  lastAccess: Date.now(),
19962
20436
  messageCount: messages?.length || 0,
19963
20437
  lineageHash,
19964
20438
  messageHashes,
20439
+ messageBlockHashes,
19965
20440
  sdkMessageUuids,
20441
+ ...passthroughResumeUuid ? { passthroughResumeUuid } : {},
19966
20442
  ...contextUsage ? { contextUsage } : {}
19967
20443
  };
19968
20444
  if (sessionId)
@@ -19972,14 +20448,14 @@ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sd
19972
20448
  fingerprintCache.set(fp, state);
19973
20449
  const key = sessionId || fp;
19974
20450
  if (key) {
19975
- storeSharedSession(key, claudeSessionId, state.messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage);
20451
+ storeSharedSession(key, claudeSessionId, state.messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage, messageBlockHashes, passthroughResumeUuid ?? null);
19976
20452
  }
19977
20453
  }
19978
20454
 
19979
20455
  // src/proxy/server.ts
19980
20456
  var exec2 = promisify3(execCallback);
19981
20457
  var claudeExecutable = "";
19982
- var UPSTREAM_IDLE_MS = 90000;
20458
+ var UPSTREAM_IDLE_MS = envInt("UPSTREAM_IDLE_MS", 90000);
19983
20459
  function credentialStoreForProfile(profile) {
19984
20460
  if (profile.type !== "claude-max")
19985
20461
  return;
@@ -20266,23 +20742,25 @@ function createProxyServer(config = {}) {
20266
20742
  });
20267
20743
  });
20268
20744
  }
20269
- async function sniffQuotaFailure(res) {
20745
+ async function sniffAccountFailure(res) {
20270
20746
  const contentType = res.headers.get("content-type") ?? "";
20271
20747
  if (!contentType.includes("text/event-stream")) {
20272
- if (res.status === 429) {
20748
+ if (!res.ok) {
20273
20749
  const body = await res.clone().json().catch(() => null);
20274
- if (body?.error?.type === "rate_limit_error")
20275
- return { failed: true, errorPayload: body, response: res };
20750
+ const errorType = body?.error?.type;
20751
+ if (isAccountFailoverError(errorType)) {
20752
+ return { failed: true, errorPayload: body, errorType, response: res };
20753
+ }
20276
20754
  }
20277
- return { failed: false, errorPayload: null, response: res };
20755
+ return { failed: false, errorPayload: null, errorType: null, response: res };
20278
20756
  }
20279
20757
  const reader = res.body?.getReader();
20280
20758
  if (!reader)
20281
- return { failed: false, errorPayload: null, response: res };
20759
+ return { failed: false, errorPayload: null, errorType: null, response: res };
20282
20760
  const decoder = new TextDecoder;
20283
20761
  const consumed = [];
20284
20762
  let text = "";
20285
- let failedPayload = null;
20763
+ let failure = null;
20286
20764
  while (true) {
20287
20765
  const { done, value } = await reader.read();
20288
20766
  if (done)
@@ -20300,16 +20778,17 @@ function createProxyServer(config = {}) {
20300
20778
  `).find((l) => l.startsWith("data: "));
20301
20779
  try {
20302
20780
  const parsed = dataLine ? JSON.parse(dataLine.slice(6)) : null;
20303
- if (parsed?.error?.type === "rate_limit_error") {
20304
- failedPayload = parsed;
20781
+ const parsedType = parsed?.error?.type;
20782
+ if (isAccountFailoverError(parsedType)) {
20783
+ failure = { payload: parsed, type: parsedType };
20305
20784
  }
20306
20785
  } catch {}
20307
20786
  }
20308
20787
  break;
20309
20788
  }
20310
- if (failedPayload) {
20789
+ if (failure) {
20311
20790
  await reader.cancel().catch(() => {});
20312
- return { failed: true, errorPayload: failedPayload, response: res };
20791
+ return { failed: true, errorPayload: failure.payload, errorType: failure.type, response: res };
20313
20792
  }
20314
20793
  const rest = new ReadableStream({
20315
20794
  start(ctrl) {
@@ -20327,33 +20806,40 @@ function createProxyServer(config = {}) {
20327
20806
  reader.cancel(reason).catch(() => {});
20328
20807
  }
20329
20808
  });
20330
- return { failed: false, errorPayload: null, response: new Response(rest, { status: res.status, headers: res.headers }) };
20809
+ return { failed: false, errorPayload: null, errorType: null, response: new Response(rest, { status: res.status, headers: res.headers }) };
20331
20810
  }
20332
20811
  async function dispatchPriority(c, orderedCandidateIds, sessionKey, wantsStream) {
20333
20812
  const bodyBuf = await c.req.arrayBuffer();
20334
20813
  let lastError = null;
20814
+ let lastStatus = 429;
20335
20815
  let previous = null;
20816
+ let previousReason = "rate_limit_error";
20336
20817
  for (const candidate of orderedCandidateIds) {
20337
20818
  const headers = new Headers(c.req.raw.headers);
20338
20819
  headers.set("x-meridian-profile", candidate);
20339
20820
  headers.set("x-meridian-priority-dispatch", "1");
20340
20821
  const inner = await app.fetch(new Request(c.req.url, { method: "POST", headers, body: bodyBuf }));
20341
- const { failed, errorPayload, response } = await sniffQuotaFailure(inner);
20342
- if (!failed) {
20822
+ const sniffed = await sniffAccountFailure(inner);
20823
+ if (!sniffed.failed) {
20343
20824
  if (sessionKey)
20344
20825
  priorityAssignments.set(sessionKey, candidate);
20345
20826
  if (previous) {
20346
- claudeLog("profile.failover", { from: previous, to: candidate, reason: "rate_limit_error", sessionKey });
20347
- plog(`[PROXY] PRIORITY failover ${previous} -> ${candidate}`);
20348
- }
20349
- return response;
20350
- }
20351
- const cooldownUntil = priorityCooldownUntil(candidate, Date.now());
20352
- priorityExhaustion.mark(candidate, cooldownUntil, "rate_limit_error");
20353
- claudeLog("priority.exhausted", { profile: candidate, until: cooldownUntil });
20354
- refinePriorityCooldown(candidate);
20355
- lastError = errorPayload;
20827
+ claudeLog("profile.failover", { from: previous, to: candidate, reason: previousReason, sessionKey });
20828
+ plog(`[PROXY] PRIORITY failover ${previous} -> ${candidate} (${previousReason})`);
20829
+ }
20830
+ return sniffed.response;
20831
+ }
20832
+ const reason = sniffed.errorType;
20833
+ const quotaRefusal = isQuotaRefusal(reason);
20834
+ const cooldownUntil = quotaRefusal ? priorityCooldownUntil(candidate, Date.now()) : Date.now() + PRIORITY_DEFAULT_COOLDOWN_MS;
20835
+ priorityExhaustion.mark(candidate, cooldownUntil, reason);
20836
+ claudeLog("priority.exhausted", { profile: candidate, until: cooldownUntil, reason });
20837
+ if (quotaRefusal)
20838
+ refinePriorityCooldown(candidate);
20839
+ lastError = sniffed.errorPayload;
20840
+ lastStatus = inner.status;
20356
20841
  previous = candidate;
20842
+ previousReason = reason;
20357
20843
  }
20358
20844
  if (wantsStream) {
20359
20845
  return new Response(`event: error
@@ -20364,7 +20850,7 @@ data: ${JSON.stringify(lastError)}
20364
20850
  headers: { "content-type": "text/event-stream; charset=utf-8", "cache-control": "no-cache" }
20365
20851
  });
20366
20852
  }
20367
- return new Response(JSON.stringify(lastError), { status: 429, headers: { "content-type": "application/json" } });
20853
+ return new Response(JSON.stringify(lastError), { status: lastStatus, headers: { "content-type": "application/json" } });
20368
20854
  }
20369
20855
  app.use("/auth/*", requireAuth);
20370
20856
  app.get("/", (c) => {
@@ -20562,12 +21048,34 @@ data: ${JSON.stringify(lastError)}
20562
21048
  if (lineageResult.type === "undo" && adapterBase === "opencode" && !agentSessionId) {
20563
21049
  lineageResult = { type: "diverged", reason: "missing-session-header" };
20564
21050
  }
21051
+ if (pipeline.some((t) => t.onSession)) {
21052
+ const mismatch = lineageResult.type === "diverged" ? lineageResult.mismatch : undefined;
21053
+ runTransformHook(pipeline, "onSession", {
21054
+ adapter: adapterBase,
21055
+ lineage: lineageResult.type,
21056
+ reason: lineageResult.type === "diverged" ? lineageResult.reason : undefined,
21057
+ sessionKey: profileSessionId,
21058
+ storedCount: mismatch?.storedCount,
21059
+ incomingCount: (body.messages || []).length,
21060
+ prefixOverlap: lineageResult.type === "diverged" ? lineageResult.prefixOverlap : undefined,
21061
+ mismatch: mismatch && mismatch.index >= 0 ? {
21062
+ index: mismatch.index,
21063
+ storedDigest: mismatch.storedDigest,
21064
+ incomingDigest: mismatch.incomingDigest,
21065
+ previousDigest: mismatch.previousDigest,
21066
+ incomingShape: mismatch.incomingShape
21067
+ } : undefined
21068
+ }, adapterBase);
21069
+ }
20565
21070
  const isResume = lineageResult.type === "continuation" || lineageResult.type === "compaction";
20566
21071
  const isUndo = lineageResult.type === "undo";
20567
21072
  const cachedSession = lineageResult.type !== "diverged" ? lineageResult.session : undefined;
20568
21073
  const resumeSessionId = cachedSession?.claudeSessionId;
21074
+ const passthrough = adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
20569
21075
  const resumeFrom = lineageResult.type === "continuation" || lineageResult.type === "compaction" ? lineageResult.resumeFrom : undefined;
21076
+ const resumeContentFrom = lineageResult.type === "continuation" ? lineageResult.resumeContentFrom : undefined;
20570
21077
  const undoRollbackUuid = isUndo && lineageResult.type === "undo" ? lineageResult.rollbackUuid : undefined;
21078
+ const passthroughResumeUuid = passthrough && isResume ? cachedSession?.passthroughResumeUuid : undefined;
20571
21079
  const msgSummary = body.messages?.map((m) => {
20572
21080
  const contentTypes = Array.isArray(m.content) ? m.content.map((b) => b.type).join(",") : "string";
20573
21081
  return `${m.role}[${contentTypes}]`;
@@ -20610,7 +21118,16 @@ data: ${JSON.stringify(lastError)}
20610
21118
  if (isUndo && undoRollbackUuid) {
20611
21119
  messagesToConvert = getLastUserMessage(allMessages);
20612
21120
  } else if (isResume) {
20613
- if (resumeFrom !== undefined && resumeFrom < allMessages.length) {
21121
+ if (resumeFrom !== undefined && resumeContentFrom !== undefined && resumeFrom < allMessages.length && Array.isArray(allMessages[resumeFrom]?.content)) {
21122
+ const boundaryMessage = allMessages[resumeFrom];
21123
+ messagesToConvert = [
21124
+ {
21125
+ ...boundaryMessage,
21126
+ content: boundaryMessage.content.slice(resumeContentFrom)
21127
+ },
21128
+ ...allMessages.slice(resumeFrom + 1)
21129
+ ];
21130
+ } else if (resumeFrom !== undefined && resumeFrom < allMessages.length) {
20614
21131
  messagesToConvert = allMessages.slice(resumeFrom);
20615
21132
  } else {
20616
21133
  messagesToConvert = getLastUserMessage(allMessages);
@@ -20659,6 +21176,13 @@ data: ${JSON.stringify(lastError)}
20659
21176
  if (structuredMessages.length > 1) {
20660
21177
  structuredMessages = consolidateMultimodalOntoLastUser(structuredMessages);
20661
21178
  }
21179
+ if (passthroughResumeUuid && structuredMessages.length > 0) {
21180
+ structuredMessages.unshift({
21181
+ type: "user",
21182
+ message: { role: "user", content: PASSTHROUGH_CONTINUATION_LEAD_IN },
21183
+ parent_tool_use_id: null
21184
+ });
21185
+ }
20662
21186
  } else {
20663
21187
  const toolIndex = buildToolUseIndex(allMessages ?? messagesToConvert ?? []);
20664
21188
  const promptTurns = (messagesToConvert ?? []).map((m) => {
@@ -20670,11 +21194,11 @@ data: ${JSON.stringify(lastError)}
20670
21194
  }
20671
21195
  return { role: "user", text: flattenUserContent(m.content, sanitizeOpts, toolIndex) };
20672
21196
  });
20673
- textPrompt = isResume ? promptTurns.map((t) => t.text).filter(Boolean).join(`
21197
+ const resumeDelta = promptTurns.map((t) => t.text).filter(Boolean).join(`
20674
21198
 
20675
- `) || "" : frameReplayTurns(promptTurns);
21199
+ `) || "";
21200
+ textPrompt = isResume ? passthroughResumeUuid ? framePassthroughContinuation(resumeDelta) : resumeDelta : frameReplayTurns(promptTurns);
20676
21201
  }
20677
- const passthrough = adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
20678
21202
  const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : pipelineCtx.settingSources ?? [];
20679
21203
  const capturedToolUses = [];
20680
21204
  const capturedSignatures = new Set;
@@ -20842,6 +21366,7 @@ data: ${JSON.stringify(lastError)}
20842
21366
  claudeLog("upstream.start", { mode: "non_stream", model });
20843
21367
  let lastUsage;
20844
21368
  let lastStopReason;
21369
+ let nextPassthroughResumeUuid;
20845
21370
  try {
20846
21371
  if (!claudeExecutable) {
20847
21372
  claudeExecutable = await resolveClaudeExecutableAsync();
@@ -20878,8 +21403,8 @@ data: ${JSON.stringify(lastError)}
20878
21403
  hasDeferredTools,
20879
21404
  resumeSessionId,
20880
21405
  isUndo,
20881
- undoRollbackUuid,
20882
- forkSession: busySessionFork || undefined,
21406
+ resumeSessionAtUuid: undoRollbackUuid ?? passthroughResumeUuid,
21407
+ forkSession: busySessionFork || Boolean(passthroughResumeUuid) || undefined,
20883
21408
  sdkHooks,
20884
21409
  blockedTools: pipelineCtx.blockedTools,
20885
21410
  incompatibleTools: pipelineCtx.incompatibleTools,
@@ -20962,7 +21487,7 @@ data: ${JSON.stringify(lastError)}
20962
21487
  hasDeferredTools,
20963
21488
  resumeSessionId: undefined,
20964
21489
  isUndo: false,
20965
- undoRollbackUuid: undefined,
21490
+ resumeSessionAtUuid: undefined,
20966
21491
  sdkHooks,
20967
21492
  blockedTools: pipelineCtx.blockedTools,
20968
21493
  incompatibleTools: pipelineCtx.incompatibleTools,
@@ -21031,7 +21556,7 @@ data: ${JSON.stringify(lastError)}
21031
21556
  hasDeferredTools,
21032
21557
  resumeSessionId: undefined,
21033
21558
  isUndo: false,
21034
- undoRollbackUuid: undefined,
21559
+ resumeSessionAtUuid: undefined,
21035
21560
  sdkHooks,
21036
21561
  blockedTools: pipelineCtx.blockedTools,
21037
21562
  incompatibleTools: pipelineCtx.incompatibleTools,
@@ -21112,6 +21637,7 @@ data: ${JSON.stringify(lastError)}
21112
21637
  if (message.type === "assistant") {
21113
21638
  noteAssistantContent(earlyStop, message.message?.content);
21114
21639
  } else if (message.type === "user") {
21640
+ nextPassthroughResumeUuid = resumeBoundaryUuid(message) ?? nextPassthroughResumeUuid;
21115
21641
  noteUserContent(earlyStop, message.message?.content);
21116
21642
  if (shouldEarlyStop(earlyStop)) {
21117
21643
  earlyStopFired = true;
@@ -21351,7 +21877,7 @@ Subprocess stderr: ${stderrOutput}`;
21351
21877
  ]);
21352
21878
  }
21353
21879
  if (currentSessionId && !isIndependentSession && !sawDuplicateToolUse) {
21354
- storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
21880
+ storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage, earlyStopFired ? nextPassthroughResumeUuid : null);
21355
21881
  }
21356
21882
  const responseSessionId = currentSessionId || resumeSessionId || `session_${Date.now()}`;
21357
21883
  return new Response(JSON.stringify({
@@ -21383,6 +21909,7 @@ Subprocess stderr: ${stderrOutput}`;
21383
21909
  let streamEventsSeen = 0;
21384
21910
  let eventsForwarded = 0;
21385
21911
  let textEventsForwarded = 0;
21912
+ let textCharsForwarded = 0;
21386
21913
  let bytesSent = 0;
21387
21914
  let streamClosed = false;
21388
21915
  let awaitingEarlyStopDrain = false;
@@ -21414,7 +21941,30 @@ Subprocess stderr: ${stderrOutput}`;
21414
21941
  let lastUsage;
21415
21942
  let hasStructuredOutput = false;
21416
21943
  let structuredOutput;
21944
+ let nextPassthroughResumeUuid;
21945
+ const silentTurnRecoveryEnabled = env("SILENT_TURN_RECOVERY") !== "0";
21946
+ let silentTurnRecoveryAttempted = false;
21947
+ let silentTurnRecovered = false;
21417
21948
  const streamedToolUseIds = new Set;
21949
+ let pendingTerminalDelta = null;
21950
+ let terminalDeltaSent = false;
21951
+ const sendTerminalDelta = (stopReasonOverride) => {
21952
+ if (terminalDeltaSent)
21953
+ return;
21954
+ const payload = stopReasonOverride ? encoder.encode(`event: message_delta
21955
+ data: ${JSON.stringify({
21956
+ type: "message_delta",
21957
+ delta: { stop_reason: stopReasonOverride, stop_sequence: null },
21958
+ usage: { output_tokens: lastUsage?.output_tokens ?? 0 }
21959
+ })}
21960
+
21961
+ `) : pendingTerminalDelta;
21962
+ if (!payload)
21963
+ return;
21964
+ terminalDeltaSent = true;
21965
+ if (safeEnqueue(payload, "terminal_message_delta"))
21966
+ eventsForwarded += 1;
21967
+ };
21418
21968
  const openClientBlocks = new Set;
21419
21969
  const resolvePendingStore = passthrough && earlyStopEnabled && !isIndependentSession && profileSessionId ? registerPendingStore(profileSessionId) : () => {};
21420
21970
  let pendingEarlyStop = false;
@@ -21430,10 +21980,7 @@ Subprocess stderr: ${stderrOutput}`;
21430
21980
  });
21431
21981
  pendingEarlyStop = false;
21432
21982
  flushOpenClientBlocks("early_stop");
21433
- safeEnqueue(encoder.encode(`event: message_delta
21434
- data: ${JSON.stringify({ type: "message_delta", delta: { stop_reason: "tool_use", stop_sequence: null }, usage: { output_tokens: lastUsage?.output_tokens ?? 0 } })}
21435
-
21436
- `), "early_stop");
21983
+ sendTerminalDelta("tool_use");
21437
21984
  safeEnqueue(encoder.encode(`event: message_stop
21438
21985
  data: ${JSON.stringify({ type: "message_stop" })}
21439
21986
 
@@ -21463,8 +22010,8 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
21463
22010
  }
21464
22011
  openClientBlocks.clear();
21465
22012
  };
22013
+ let currentSessionId;
21466
22014
  try {
21467
- let currentSessionId;
21468
22015
  const MAX_RATE_LIMIT_RETRIES = 2;
21469
22016
  const RATE_LIMIT_BASE_DELAY_MS = 1000;
21470
22017
  const response = async function* () {
@@ -21496,8 +22043,8 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
21496
22043
  hasDeferredTools,
21497
22044
  resumeSessionId,
21498
22045
  isUndo,
21499
- undoRollbackUuid,
21500
- forkSession: busySessionFork || undefined,
22046
+ resumeSessionAtUuid: undoRollbackUuid ?? passthroughResumeUuid,
22047
+ forkSession: busySessionFork || Boolean(passthroughResumeUuid) || undefined,
21501
22048
  sdkHooks,
21502
22049
  blockedTools: pipelineCtx.blockedTools,
21503
22050
  incompatibleTools: pipelineCtx.incompatibleTools,
@@ -21579,7 +22126,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
21579
22126
  hasDeferredTools,
21580
22127
  resumeSessionId: undefined,
21581
22128
  isUndo: false,
21582
- undoRollbackUuid: undefined,
22129
+ resumeSessionAtUuid: undefined,
21583
22130
  sdkHooks,
21584
22131
  blockedTools: pipelineCtx.blockedTools,
21585
22132
  incompatibleTools: pipelineCtx.incompatibleTools,
@@ -21648,7 +22195,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
21648
22195
  hasDeferredTools,
21649
22196
  resumeSessionId: undefined,
21650
22197
  isUndo: false,
21651
- undoRollbackUuid: undefined,
22198
+ resumeSessionAtUuid: undefined,
21652
22199
  sdkHooks,
21653
22200
  blockedTools: pipelineCtx.blockedTools,
21654
22201
  incompatibleTools: pipelineCtx.incompatibleTools,
@@ -21761,6 +22308,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
21761
22308
  if (message.type === "assistant" && message.uuid) {
21762
22309
  sdkUuidMap.push(message.uuid);
21763
22310
  }
22311
+ nextPassthroughResumeUuid = resumeBoundaryUuid(message) ?? nextPassthroughResumeUuid;
21764
22312
  if (earlyStopEnabled) {
21765
22313
  if (message.type === "assistant") {
21766
22314
  noteAssistantContent(earlyStop, message.message?.content);
@@ -21832,10 +22380,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
21832
22380
  if (messageStartEmitted) {
21833
22381
  if (passthrough && streamedToolUseIds.size > 0) {
21834
22382
  flushOpenClientBlocks("turn2_suppression");
21835
- safeEnqueue(encoder.encode(`event: message_delta
21836
- data: ${JSON.stringify({ type: "message_delta", delta: { stop_reason: "tool_use", stop_sequence: null }, usage: { output_tokens: lastUsage?.output_tokens ?? 0 } })}
21837
-
21838
- `), "passthrough_turn2_stop");
22383
+ sendTerminalDelta("tool_use");
21839
22384
  safeEnqueue(encoder.encode(`event: message_stop
21840
22385
  data: ${JSON.stringify({ type: "message_stop" })}
21841
22386
 
@@ -21939,15 +22484,26 @@ data: ${JSON.stringify({
21939
22484
  }
21940
22485
  }
21941
22486
  }
22487
+ if (eventType === "content_block_delta" && event.delta?.type === "text_delta" && shouldInjectSilentTurn({
22488
+ raw: env("DEBUG_FORCE_SILENT_TURN"),
22489
+ sessionId: agentSessionId
22490
+ })) {
22491
+ claudeLog("debug.silent_turn_injected", { sessionId: agentSessionId });
22492
+ continue;
22493
+ }
21942
22494
  stripNonStandardStreamFields(event);
21943
22495
  const payload = encoder.encode(`event: ${eventType}
21944
22496
  data: ${JSON.stringify(event)}
21945
22497
 
21946
22498
  `);
21947
- if (!safeEnqueue(payload, `stream_event:${eventType}`)) {
21948
- break;
22499
+ if (eventType === "message_delta") {
22500
+ pendingTerminalDelta = payload;
22501
+ } else {
22502
+ if (!safeEnqueue(payload, `stream_event:${eventType}`)) {
22503
+ break;
22504
+ }
22505
+ eventsForwarded += 1;
21949
22506
  }
21950
- eventsForwarded += 1;
21951
22507
  if (eventType === "content_block_start") {
21952
22508
  const idx = event.index;
21953
22509
  if (typeof idx === "number")
@@ -21963,6 +22519,7 @@ data: ${JSON.stringify(event)}
21963
22519
  }
21964
22520
  if (passthrough && eventType === "message_delta" && event.delta?.stop_reason === "tool_use" && streamedToolUseIds.size > 0) {
21965
22521
  flushOpenClientBlocks("drain_close");
22522
+ sendTerminalDelta();
21966
22523
  safeEnqueue(encoder.encode(`event: message_stop
21967
22524
  data: ${JSON.stringify({ type: "message_stop" })}
21968
22525
 
@@ -21979,6 +22536,8 @@ data: ${JSON.stringify({ type: "message_stop" })}
21979
22536
  const delta = event.delta;
21980
22537
  if (delta?.type === "text_delta") {
21981
22538
  textEventsForwarded += 1;
22539
+ if (typeof delta.text === "string")
22540
+ textCharsForwarded += delta.text.length;
21982
22541
  }
21983
22542
  }
21984
22543
  }
@@ -22040,6 +22599,7 @@ data: ${JSON.stringify({
22040
22599
  messageStartEmitted = true;
22041
22600
  eventsForwarded += 5;
22042
22601
  textEventsForwarded += 1;
22602
+ textCharsForwarded += text.length;
22043
22603
  }
22044
22604
  if (passthrough) {
22045
22605
  recordEnvelopeViolations(checkUndeliveredToolUses(capturedToolUses, streamedToolUseIds));
@@ -22065,9 +22625,125 @@ data: ${JSON.stringify({
22065
22625
  plog(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
22066
22626
  }
22067
22627
  if (currentSessionId && !isIndependentSession && !sawDuplicateToolUse) {
22068
- storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
22628
+ storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage, earlyStopFired ? nextPassthroughResumeUuid : null);
22069
22629
  }
22070
22630
  resolvePendingStore();
22631
+ const classifyNow = () => classifyTurnOutcome({
22632
+ textEvents: textEventsForwarded,
22633
+ toolUses: streamedToolUseIds.size,
22634
+ blocksForwarded: eventsForwarded
22635
+ });
22636
+ const preRecoveryOutcome = classifyNow();
22637
+ if (!streamClosed && messageStartEmitted && shouldAttemptRecovery({
22638
+ outcome: preRecoveryOutcome,
22639
+ alreadyAttempted: silentTurnRecoveryAttempted,
22640
+ clientGone: streamClosed,
22641
+ sessionId: currentSessionId || resumeSessionId,
22642
+ enabled: silentTurnRecoveryEnabled
22643
+ })) {
22644
+ silentTurnRecoveryAttempted = true;
22645
+ const capturedBeforeRecovery = capturedToolUses.length;
22646
+ claudeLog("response.silent_turn_recovery", {
22647
+ mode: "stream",
22648
+ kind: preRecoveryOutcome.kind,
22649
+ reason: preRecoveryOutcome.kind === "silent" ? preRecoveryOutcome.reason : undefined,
22650
+ sdkSessionId: currentSessionId || resumeSessionId
22651
+ });
22652
+ const recoveryLifter = createRecoveryLifter(() => nextClientBlockIndex++);
22653
+ let recoverySessionId;
22654
+ let recoveryBoundaryUuid;
22655
+ try {
22656
+ for await (const event of guardUpstreamIdle(query(buildQueryOptions({
22657
+ prompt: SILENT_TURN_NUDGE,
22658
+ model,
22659
+ workingDirectory,
22660
+ clientWorkingDirectory,
22661
+ systemContext,
22662
+ claudeExecutable,
22663
+ passthrough,
22664
+ stream: true,
22665
+ sdkAgents,
22666
+ passthroughMcp,
22667
+ cleanEnv: profileEnv,
22668
+ envOverrides,
22669
+ hasDeferredTools,
22670
+ resumeSessionId: currentSessionId || resumeSessionId,
22671
+ isUndo: false,
22672
+ resumeSessionAtUuid: nextPassthroughResumeUuid,
22673
+ forkSession: true,
22674
+ sdkHooks,
22675
+ blockedTools: pipelineCtx.blockedTools,
22676
+ incompatibleTools: pipelineCtx.incompatibleTools,
22677
+ mcpServerName: adapter.getMcpServerName(),
22678
+ allowedMcpTools: pipelineCtx.allowedMcpTools,
22679
+ onStderr,
22680
+ effort,
22681
+ thinking,
22682
+ taskBudget,
22683
+ outputFormat,
22684
+ betas,
22685
+ settingSources,
22686
+ codeSystemPrompt: sdkFeatures.codeSystemPrompt,
22687
+ clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
22688
+ memory: sdkFeatures.memory,
22689
+ dreaming: sdkFeatures.dreaming,
22690
+ sharedMemory: sdkFeatures.sharedMemory,
22691
+ webFetchPreflight: sdkFeatures.webFetchPreflight,
22692
+ claudeAiConnectors: sdkFeatures.claudeAiConnectors,
22693
+ maxBudgetUsd: sdkFeatures.maxBudgetUsd,
22694
+ fallbackModel: sdkFeatures.fallbackModel,
22695
+ sdkDebug: sdkFeatures.sdkDebug,
22696
+ additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
22697
+ advisorModel
22698
+ }, requestAbort.controller)), UPSTREAM_IDLE_MS, (sinceLastMs) => claudeLog("upstream.stalled", { mode: "silent_recovery", model, sinceLastMs }))) {
22699
+ const recoveryMessage = event;
22700
+ if (recoveryMessage.session_id)
22701
+ recoverySessionId = recoveryMessage.session_id;
22702
+ recoveryBoundaryUuid = resumeBoundaryUuid(recoveryMessage) ?? recoveryBoundaryUuid;
22703
+ if (recoveryMessage.type !== "stream_event")
22704
+ continue;
22705
+ const lifted = recoveryLifter.lift(event.event);
22706
+ if (!lifted)
22707
+ continue;
22708
+ safeEnqueue(encoder.encode(`event: ${lifted.frame.type}
22709
+ data: ${JSON.stringify(lifted.frame)}
22710
+
22711
+ `), `silent_recovery_${lifted.kind}`);
22712
+ if (lifted.kind === "block_start") {
22713
+ eventsForwarded += 1;
22714
+ } else if (lifted.kind === "text_delta") {
22715
+ textEventsForwarded += 1;
22716
+ textCharsForwarded += lifted.textChars;
22717
+ silentTurnRecovered = true;
22718
+ }
22719
+ }
22720
+ } catch (recoveryError) {
22721
+ claudeLog("response.silent_turn_recovery_failed", {
22722
+ mode: "stream",
22723
+ error: recoveryError instanceof Error ? recoveryError.message : String(recoveryError)
22724
+ });
22725
+ }
22726
+ if (capturedToolUses.length > capturedBeforeRecovery) {
22727
+ silentTurnRecovered = true;
22728
+ }
22729
+ if (silentTurnRecovered && recoverySessionId && !isIndependentSession && !sawDuplicateToolUse) {
22730
+ currentSessionId = recoverySessionId;
22731
+ nextPassthroughResumeUuid = recoveryBoundaryUuid;
22732
+ sdkUuidMap.length = 0;
22733
+ for (let i = 0;i < allMessages.length; i++)
22734
+ sdkUuidMap.push(null);
22735
+ storeSession(profileSessionId, body.messages || [], recoverySessionId, profileScopedCwd, sdkUuidMap, lastUsage, recoveryBoundaryUuid ?? null);
22736
+ }
22737
+ claudeLog("response.silent_turn_recovery_result", {
22738
+ mode: "stream",
22739
+ recovered: silentTurnRecovered,
22740
+ textEvents: textEventsForwarded,
22741
+ forkedSession: recoverySessionId ?? null
22742
+ });
22743
+ if (silentTurnRecovered && preRecoveryOutcome.kind === "silent") {
22744
+ diagnosticLog2.session(`${requestMeta.requestId} silent_turn reason=${preRecoveryOutcome.reason} ` + `blocks=${eventsForwarded} out=${lastUsage?.output_tokens ?? 0} ` + `recovery=succeeded`, requestMeta.requestId);
22745
+ }
22746
+ }
22071
22747
  if (!streamClosed) {
22072
22748
  const unseenToolUses = capturedToolUses.filter((tu) => !streamedToolUseIds.has(tu.id));
22073
22749
  if (passthrough && unseenToolUses.length > 0 && messageStartEmitted) {
@@ -22099,14 +22775,7 @@ data: ${JSON.stringify({
22099
22775
 
22100
22776
  `), "passthrough_tool_block_stop");
22101
22777
  }
22102
- safeEnqueue(encoder.encode(`event: message_delta
22103
- data: ${JSON.stringify({
22104
- type: "message_delta",
22105
- delta: { stop_reason: "tool_use", stop_sequence: null },
22106
- usage: { output_tokens: 0 }
22107
- })}
22108
-
22109
- `), "passthrough_message_delta");
22778
+ sendTerminalDelta("tool_use");
22110
22779
  }
22111
22780
  if (trackFileChanges && passthrough && pipelineCtx.extractFileChangesFromToolUse) {
22112
22781
  const passthroughChanges = extractFileChangesFromMessages(body.messages || [], pipelineCtx.extractFileChangesFromToolUse);
@@ -22143,6 +22812,7 @@ data: ${JSON.stringify({
22143
22812
  }
22144
22813
  }
22145
22814
  if (messageStartEmitted) {
22815
+ sendTerminalDelta();
22146
22816
  safeEnqueue(encoder.encode(`event: message_stop
22147
22817
  data: {"type":"message_stop"}
22148
22818
 
@@ -22208,13 +22878,18 @@ data: {"type":"message_stop"}
22208
22878
  cacheHitRate: computeCacheHitRate(lastUsage),
22209
22879
  ...envelopeViolations.length > 0 ? { envelopeViolations: [...envelopeViolations] } : {}
22210
22880
  });
22211
- if (textEventsForwarded === 0) {
22212
- claudeLog("response.empty_stream", {
22881
+ const turnOutcome = classifyNow();
22882
+ if (turnOutcome.kind === "silent") {
22883
+ claudeLog("response.silent_turn", {
22213
22884
  model,
22885
+ reason: turnOutcome.reason,
22214
22886
  streamEventsSeen,
22215
22887
  eventsForwarded,
22216
- reason: "no_text_deltas_forwarded"
22888
+ outputTokens: lastUsage?.output_tokens,
22889
+ recovered: silentTurnRecovered,
22890
+ recoveryAttempted: silentTurnRecoveryAttempted
22217
22891
  });
22892
+ diagnosticLog2.session(`${requestMeta.requestId} silent_turn reason=${turnOutcome.reason} ` + `blocks=${eventsForwarded} out=${lastUsage?.output_tokens ?? 0} ` + `recovery=${silentTurnRecoveryAttempted ? silentTurnRecovered ? "succeeded" : "failed" : "off"}`, requestMeta.requestId);
22218
22893
  }
22219
22894
  }
22220
22895
  } catch (error) {
@@ -22227,6 +22902,21 @@ data: {"type":"message_stop"}
22227
22902
  textEventsForwarded,
22228
22903
  durationMs: Date.now() - requestStartAt
22229
22904
  });
22905
+ const disposition = clientAbortDisposition({
22906
+ isIndependentSession,
22907
+ profileSessionId,
22908
+ currentSessionId,
22909
+ sawDuplicateToolUse,
22910
+ resumeBoundaryUuid: nextPassthroughResumeUuid,
22911
+ passthrough
22912
+ });
22913
+ if (disposition.action === "store" && currentSessionId) {
22914
+ storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage, disposition.resumeUuid);
22915
+ } else if (disposition.action === "evict") {
22916
+ evictSession(profileSessionId, profileScopedCwd, body.messages || []);
22917
+ }
22918
+ claudeLog("passthrough.client_abort_settled", { action: disposition.action });
22919
+ resolvePendingStore();
22230
22920
  return;
22231
22921
  }
22232
22922
  resolvePendingStore();
@@ -22380,26 +23070,41 @@ data: {"type":"message_stop"}
22380
23070
  error: streamErr.type
22381
23071
  });
22382
23072
  if (messageStartEmitted) {
23073
+ const errorStopReason = textEventsForwarded > 0 ? "end_turn" : "max_tokens";
23074
+ claudeLog("response.error_envelope", {
23075
+ mode: "stream",
23076
+ stopReason: errorStopReason,
23077
+ textEvents: textEventsForwarded,
23078
+ classified: streamErr.type
23079
+ });
22383
23080
  safeEnqueue(encoder.encode(`event: message_delta
22384
23081
  data: ${JSON.stringify({
22385
23082
  type: "message_delta",
22386
- delta: { stop_reason: "end_turn", stop_sequence: null },
23083
+ delta: { stop_reason: errorStopReason, stop_sequence: null },
22387
23084
  usage: { output_tokens: 0 }
22388
23085
  })}
22389
23086
 
22390
23087
  `), "error_message_delta");
23088
+ safeEnqueue(encoder.encode(`event: error
23089
+ data: ${JSON.stringify({
23090
+ type: "error",
23091
+ error: { type: streamErr.type, message: streamErr.message }
23092
+ })}
23093
+
23094
+ `), "error_event_before_stop");
22391
23095
  safeEnqueue(encoder.encode(`event: message_stop
22392
23096
  data: {"type":"message_stop"}
22393
23097
 
22394
23098
  `), "error_message_stop");
22395
- }
22396
- safeEnqueue(encoder.encode(`event: error
23099
+ } else {
23100
+ safeEnqueue(encoder.encode(`event: error
22397
23101
  data: ${JSON.stringify({
22398
- type: "error",
22399
- error: { type: streamErr.type, message: streamErr.message }
22400
- })}
23102
+ type: "error",
23103
+ error: { type: streamErr.type, message: streamErr.message }
23104
+ })}
22401
23105
 
22402
23106
  `), "error_event");
23107
+ }
22403
23108
  if (!streamClosed) {
22404
23109
  try {
22405
23110
  controller.close();
@@ -22657,7 +23362,7 @@ data: ${JSON.stringify({
22657
23362
  });
22658
23363
  });
22659
23364
  app.get("/profiles", async (c) => {
22660
- const { profilePageHtml } = await import("./profilePage-naychnb8.js");
23365
+ const { profilePageHtml } = await import("./profilePage-gtazq15d.js");
22661
23366
  return c.html(profilePageHtml);
22662
23367
  });
22663
23368
  app.post("/profiles/active", async (c) => {
@@ -22740,14 +23445,25 @@ data: ${JSON.stringify({
22740
23445
  });
22741
23446
  app.post("/v1/chat/completions", async (c) => {
22742
23447
  const rawBody = await c.req.json();
22743
- const anthropicBody = translateOpenAiToAnthropic(rawBody);
23448
+ const userAgent = c.req.header("user-agent") ?? "";
23449
+ const jcodeSessionId = userAgent.startsWith("jcode/") ? normalizeJcodeSessionId(c.req.header("x-jcode-session")) : undefined;
23450
+ const isJcode = jcodeSessionId !== undefined;
23451
+ const adapterName = isJcode ? "jcode" : "openai";
23452
+ const anthropicBody = translateOpenAiToAnthropic(rawBody, {
23453
+ preserveConversationHistory: isJcode
23454
+ });
22744
23455
  if (!anthropicBody) {
22745
23456
  return c.json({ type: "error", error: { type: "invalid_request_error", message: "messages: Field required" } }, 400);
22746
23457
  }
22747
23458
  const internalHeaders = {
22748
23459
  "Content-Type": "application/json",
22749
- "x-meridian-agent": "openai"
23460
+ "x-meridian-agent": adapterName
22750
23461
  };
23462
+ if (jcodeSessionId)
23463
+ internalHeaders["x-jcode-session"] = jcodeSessionId;
23464
+ const requestedProfile = c.req.header("x-meridian-profile");
23465
+ if (requestedProfile)
23466
+ internalHeaders["x-meridian-profile"] = requestedProfile;
22751
23467
  const xApiKey = c.req.header("x-api-key");
22752
23468
  if (xApiKey)
22753
23469
  internalHeaders["x-api-key"] = xApiKey;
@@ -22768,7 +23484,7 @@ data: ${JSON.stringify({
22768
23484
  const created = Math.floor(Date.now() / 1000);
22769
23485
  const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model : CANONICAL_SONNET_MODEL;
22770
23486
  const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
22771
- const sdkFeatures = getFeaturesForAdapter2("openai");
23487
+ const sdkFeatures = getFeaturesForAdapter2(adapterName);
22772
23488
  if (!anthropicBody.stream) {
22773
23489
  const anthropicRes = await internalRes.json();
22774
23490
  return c.json(translateAnthropicToOpenAi(anthropicRes, completionId, model, created, {
@@ -23014,7 +23730,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
23014
23730
  const profilesList = getEffectiveProfiles(finalConfig.profiles);
23015
23731
  const activeId = getActiveProfileId() || finalConfig.defaultProfile || profilesList[0]?.id || null;
23016
23732
  if (profilesList.length === 0) {
23017
- const oauth = await fetchOAuthUsage({});
23733
+ const { snapshot: oauth, error } = await fetchOAuthUsageResult({});
23018
23734
  return c.json({
23019
23735
  profiles: [{
23020
23736
  id: "default",
@@ -23022,7 +23738,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
23022
23738
  windows: oauth?.windows ?? [],
23023
23739
  extraUsage: oauth?.extraUsage ?? null,
23024
23740
  fetchedAt: oauth?.fetchedAt ?? null,
23025
- error: oauth ? null : "no_token"
23741
+ error
23026
23742
  }],
23027
23743
  activeProfile: "default",
23028
23744
  asOf: Date.now()
@@ -23041,7 +23757,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
23041
23757
  error: "not_oauth"
23042
23758
  };
23043
23759
  }
23044
- const oauth = await fetchOAuthUsage({
23760
+ const { snapshot: oauth, error } = await fetchOAuthUsageResult({
23045
23761
  profileId: p.id,
23046
23762
  claudeConfigDir: p.claudeConfigDir
23047
23763
  });
@@ -23052,7 +23768,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
23052
23768
  windows: oauth?.windows ?? [],
23053
23769
  extraUsage: oauth?.extraUsage ?? null,
23054
23770
  fetchedAt: oauth?.fetchedAt ?? null,
23055
- error: oauth ? null : "no_token"
23771
+ error
23056
23772
  };
23057
23773
  }));
23058
23774
  return c.json({