@phuetz/code-buddy 1.0.0 → 1.2.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 (312) hide show
  1. package/README.md +160 -164
  2. package/dist/agent/autonomous/agentic-coding-contract.d.ts +6 -6
  3. package/dist/agent/codebuddy-agent.d.ts +1 -1
  4. package/dist/agent/codebuddy-agent.js +101 -13
  5. package/dist/agent/execution/agent-executor.js +122 -12
  6. package/dist/agent/execution/tool-dependency-graph.js +7 -0
  7. package/dist/agent/execution/tool-hooks.d.ts +6 -0
  8. package/dist/agent/execution/tool-hooks.js +13 -5
  9. package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
  10. package/dist/agent/execution/tool-selection-strategy.js +67 -10
  11. package/dist/agent/extended-thinking.d.ts +8 -0
  12. package/dist/agent/extended-thinking.js +27 -0
  13. package/dist/agent/hermes-browser-backends.js +151 -11
  14. package/dist/agent/hermes-claw-migrate.d.ts +59 -0
  15. package/dist/agent/hermes-claw-migrate.js +427 -26
  16. package/dist/agent/hermes-parity-manifest.js +78 -71
  17. package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
  18. package/dist/agent/hermes-runtime-lifecycle.js +468 -0
  19. package/dist/agent/lesson-auto-proposer.js +10 -0
  20. package/dist/agent/middleware/index.d.ts +1 -0
  21. package/dist/agent/middleware/index.js +1 -0
  22. package/dist/agent/middleware/session-duration.d.ts +36 -0
  23. package/dist/agent/middleware/session-duration.js +78 -0
  24. package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
  25. package/dist/agent/middleware/visual-validation-middleware.js +67 -0
  26. package/dist/agent/model-benchmark.d.ts +77 -0
  27. package/dist/agent/model-benchmark.js +309 -0
  28. package/dist/agent/model-tier.d.ts +14 -0
  29. package/dist/agent/model-tier.js +71 -0
  30. package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
  31. package/dist/agent/multi-agent/multi-agent-system.js +3 -1
  32. package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
  33. package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
  34. package/dist/agent/multi-agent/session-tools.js +22 -5
  35. package/dist/agent/reasoning/mcts.js +20 -6
  36. package/dist/agent/session-end-flush.d.ts +71 -0
  37. package/dist/agent/session-end-flush.js +233 -0
  38. package/dist/agent/streaming/streaming-handler.d.ts +7 -0
  39. package/dist/agent/streaming/streaming-handler.js +8 -1
  40. package/dist/agent/tool-executor.js +1 -0
  41. package/dist/agent/tool-handler.d.ts +5 -0
  42. package/dist/agent/tool-handler.js +130 -4
  43. package/dist/browser-automation/browser-operator-executor.js +15 -0
  44. package/dist/browser-automation/browser-use-runner.d.ts +96 -0
  45. package/dist/browser-automation/browser-use-runner.js +492 -0
  46. package/dist/browser-automation/camofox-runner.d.ts +107 -0
  47. package/dist/browser-automation/camofox-runner.js +287 -0
  48. package/dist/channels/dingtalk/index.js +3 -0
  49. package/dist/channels/discord/client.d.ts +9 -0
  50. package/dist/channels/discord/client.js +12 -0
  51. package/dist/channels/feishu/index.d.ts +167 -1
  52. package/dist/channels/feishu/index.js +432 -7
  53. package/dist/channels/gateway-lifecycle.d.ts +132 -0
  54. package/dist/channels/gateway-lifecycle.js +219 -0
  55. package/dist/channels/google-chat/index.d.ts +5 -1
  56. package/dist/channels/google-chat/index.js +5 -1
  57. package/dist/channels/imessage/index.d.ts +14 -0
  58. package/dist/channels/imessage/index.js +64 -17
  59. package/dist/channels/index.d.ts +4 -0
  60. package/dist/channels/index.js +4 -0
  61. package/dist/channels/irc/index.d.ts +73 -3
  62. package/dist/channels/irc/index.js +446 -11
  63. package/dist/channels/line/index.js +3 -0
  64. package/dist/channels/mattermost/index.d.ts +51 -4
  65. package/dist/channels/mattermost/index.js +303 -20
  66. package/dist/channels/nextcloud-talk/index.d.ts +89 -8
  67. package/dist/channels/nextcloud-talk/index.js +367 -16
  68. package/dist/channels/nostr/index.d.ts +121 -1
  69. package/dist/channels/nostr/index.js +396 -8
  70. package/dist/channels/ntfy/index.js +3 -0
  71. package/dist/channels/qq/index.js +3 -0
  72. package/dist/channels/slash-parity.d.ts +117 -0
  73. package/dist/channels/slash-parity.js +185 -0
  74. package/dist/channels/synology-chat/index.js +3 -0
  75. package/dist/channels/teams/index.d.ts +3 -0
  76. package/dist/channels/teams/index.js +3 -0
  77. package/dist/channels/telegram/client.d.ts +9 -0
  78. package/dist/channels/telegram/client.js +12 -0
  79. package/dist/channels/twilio-voice/index.js +3 -0
  80. package/dist/channels/webchat/index.d.ts +7 -1
  81. package/dist/channels/webchat/index.js +7 -1
  82. package/dist/channels/wecom/index.js +3 -0
  83. package/dist/channels/weixin/index.js +3 -0
  84. package/dist/channels/zalo/index.js +3 -0
  85. package/dist/cli/config-loader.js +1 -1
  86. package/dist/codebuddy/client.d.ts +30 -1
  87. package/dist/codebuddy/client.js +167 -20
  88. package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
  89. package/dist/codebuddy/providers/provider-chatgpt-responses.js +1 -0
  90. package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
  91. package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
  92. package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
  93. package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
  94. package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
  95. package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
  96. package/dist/codebuddy/tool-definitions/index.js +2 -1
  97. package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
  98. package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
  99. package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
  100. package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
  101. package/dist/codebuddy/tools.d.ts +1 -1
  102. package/dist/codebuddy/tools.js +27 -24
  103. package/dist/commands/cli/hermes-commands.js +108 -0
  104. package/dist/commands/cli/native-engine-commands.js +107 -3
  105. package/dist/commands/cli/utility-commands.js +45 -0
  106. package/dist/commands/enhanced-command-handler.js +5 -0
  107. package/dist/commands/goal-cli.d.ts +71 -0
  108. package/dist/commands/goal-cli.js +280 -0
  109. package/dist/commands/handlers/goal-handler.d.ts +34 -0
  110. package/dist/commands/handlers/goal-handler.js +155 -0
  111. package/dist/commands/handlers/index.d.ts +1 -0
  112. package/dist/commands/handlers/index.js +2 -0
  113. package/dist/commands/handlers/infra-handlers.js +36 -0
  114. package/dist/commands/handlers/memory-handlers.js +96 -1
  115. package/dist/commands/headless-slash.d.ts +2 -0
  116. package/dist/commands/headless-slash.js +12 -0
  117. package/dist/commands/llm-provider-resolution.d.ts +5 -3
  118. package/dist/commands/llm-provider-resolution.js +87 -33
  119. package/dist/commands/ollama.d.ts +25 -0
  120. package/dist/commands/ollama.js +100 -0
  121. package/dist/commands/provider.d.ts +5 -0
  122. package/dist/commands/provider.js +106 -55
  123. package/dist/commands/slash/builtin-commands.js +20 -0
  124. package/dist/commands/spec-next.js +2 -1
  125. package/dist/commands/spec-plan.js +5 -16
  126. package/dist/commands/tunnel.d.ts +2 -0
  127. package/dist/commands/tunnel.js +48 -0
  128. package/dist/config/config-resolver.d.ts +2 -1
  129. package/dist/config/config-resolver.js +54 -41
  130. package/dist/config/constants.d.ts +28 -0
  131. package/dist/config/constants.js +7 -0
  132. package/dist/config/env-schema.js +770 -0
  133. package/dist/config/feature-flags.js +7 -0
  134. package/dist/config/model-tools.js +4 -4
  135. package/dist/config/toml-config.d.ts +16 -0
  136. package/dist/config/toml-config.js +3 -0
  137. package/dist/context/context-manager-v2.d.ts +39 -0
  138. package/dist/context/context-manager-v2.js +91 -0
  139. package/dist/daemon/agent-task-executor.js +12 -1
  140. package/dist/daemon/autonomous-daemon.d.ts +1 -1
  141. package/dist/daemon/autonomous-daemon.js +5 -3
  142. package/dist/daemon/autonomous-loop.d.ts +21 -1
  143. package/dist/daemon/autonomous-loop.js +69 -0
  144. package/dist/daemon/colab-goal.d.ts +38 -0
  145. package/dist/daemon/colab-goal.js +81 -0
  146. package/dist/daemon/cron-agent-bridge.d.ts +12 -3
  147. package/dist/daemon/cron-agent-bridge.js +25 -9
  148. package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
  149. package/dist/desktop/codebuddy-engine-adapter.js +257 -80
  150. package/dist/desktop/engine-adapter.d.ts +14 -0
  151. package/dist/desktop-automation/automation-manager.js +16 -0
  152. package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
  153. package/dist/desktop-automation/omniparser-runner.js +115 -0
  154. package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
  155. package/dist/desktop-automation/smart-snapshot.js +72 -5
  156. package/dist/doctor/index.js +40 -23
  157. package/dist/events/types.d.ts +11 -0
  158. package/dist/fleet/colab-store.d.ts +21 -0
  159. package/dist/fleet/colab-store.js +28 -0
  160. package/dist/fleet/peer-session-bridge.d.ts +1 -1
  161. package/dist/fleet/peer-session-bridge.js +243 -2
  162. package/dist/fleet/peer-session-store.d.ts +3 -0
  163. package/dist/fleet/peer-tool-bridge.js +14 -0
  164. package/dist/fleet/privacy-lint.d.ts +8 -0
  165. package/dist/fleet/privacy-lint.js +22 -0
  166. package/dist/goals/goal-decomposer.d.ts +27 -0
  167. package/dist/goals/goal-decomposer.js +293 -0
  168. package/dist/goals/goal-judge-client.d.ts +15 -0
  169. package/dist/goals/goal-judge-client.js +45 -0
  170. package/dist/goals/goal-judge.d.ts +38 -0
  171. package/dist/goals/goal-judge.js +158 -0
  172. package/dist/goals/goal-loop.d.ts +37 -0
  173. package/dist/goals/goal-loop.js +101 -0
  174. package/dist/goals/goal-manager.d.ts +77 -0
  175. package/dist/goals/goal-manager.js +289 -0
  176. package/dist/goals/goal-state.d.ts +99 -0
  177. package/dist/goals/goal-state.js +315 -0
  178. package/dist/goals/goal-store.d.ts +28 -0
  179. package/dist/goals/goal-store.js +87 -0
  180. package/dist/goals/index.d.ts +5 -0
  181. package/dist/goals/index.js +6 -0
  182. package/dist/hooks/use-input-handler.js +36 -1
  183. package/dist/hooks/user-hooks.js +17 -3
  184. package/dist/index.js +506 -25
  185. package/dist/input/text-to-speech.d.ts +2 -6
  186. package/dist/input/text-to-speech.js +2 -27
  187. package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
  188. package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
  189. package/dist/integrations/tailscale.d.ts +13 -0
  190. package/dist/integrations/tailscale.js +87 -34
  191. package/dist/knowledge/workspace-indexer.js +53 -9
  192. package/dist/mcp/client.js +1 -0
  193. package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
  194. package/dist/mcp/mcp-desktop-tools.js +158 -0
  195. package/dist/mcp/mcp-server.js +2 -0
  196. package/dist/memory/enhanced-memory.d.ts +10 -0
  197. package/dist/memory/enhanced-memory.js +33 -2
  198. package/dist/memory/index.d.ts +3 -1
  199. package/dist/memory/index.js +4 -1
  200. package/dist/memory/memory-auto-proposer.d.ts +23 -0
  201. package/dist/memory/memory-auto-proposer.js +308 -0
  202. package/dist/memory/memory-candidate-queue.d.ts +92 -0
  203. package/dist/memory/memory-candidate-queue.js +261 -0
  204. package/dist/memory/persistent-memory.d.ts +45 -2
  205. package/dist/memory/persistent-memory.js +236 -40
  206. package/dist/ml/bayesian-qualifier.d.ts +1 -1
  207. package/dist/ml/bayesian-qualifier.js +35 -2
  208. package/dist/observability/run-store.d.ts +1 -1
  209. package/dist/openclaw/gateway-bridge.js +5 -0
  210. package/dist/plugins/marketplace.d.ts +1 -0
  211. package/dist/plugins/marketplace.js +7 -0
  212. package/dist/prompts/execution-discipline.d.ts +14 -0
  213. package/dist/prompts/execution-discipline.js +29 -0
  214. package/dist/prompts/variation-injector.js +9 -2
  215. package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
  216. package/dist/protocols/acp/acp-agentic-runner.js +115 -18
  217. package/dist/protocols/acp/acp-session-store.d.ts +23 -0
  218. package/dist/protocols/acp/acp-session-store.js +77 -0
  219. package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
  220. package/dist/protocols/acp/acp-stdio-server.js +71 -16
  221. package/dist/providers/active-llm-registry.d.ts +37 -0
  222. package/dist/providers/active-llm-registry.js +186 -0
  223. package/dist/providers/auxiliary-provider.d.ts +25 -0
  224. package/dist/providers/auxiliary-provider.js +192 -0
  225. package/dist/providers/codex-oauth.d.ts +1 -1
  226. package/dist/providers/codex-oauth.js +27 -4
  227. package/dist/providers/index.d.ts +3 -0
  228. package/dist/providers/index.js +4 -0
  229. package/dist/providers/provider-catalog.d.ts +70 -0
  230. package/dist/providers/provider-catalog.js +738 -0
  231. package/dist/providers/provider-fallback.d.ts +35 -0
  232. package/dist/providers/provider-fallback.js +171 -0
  233. package/dist/providers/xai-oauth.d.ts +128 -0
  234. package/dist/providers/xai-oauth.js +735 -0
  235. package/dist/scheduler/cron-scheduler.d.ts +15 -3
  236. package/dist/scheduler/cron-scheduler.js +53 -7
  237. package/dist/scheduler/script-runner.d.ts +2 -0
  238. package/dist/scheduler/script-runner.js +19 -4
  239. package/dist/scheduler/watchdog-handlers.js +7 -20
  240. package/dist/search/usearch-index.js +7 -2
  241. package/dist/security/tool-policy/tool-groups.js +2 -0
  242. package/dist/server/index.js +17 -2
  243. package/dist/server/routes/mobile.d.ts +12 -4
  244. package/dist/server/routes/mobile.js +116 -1
  245. package/dist/server/tls-config.d.ts +35 -0
  246. package/dist/server/tls-config.js +142 -0
  247. package/dist/server/tunnel-manager.d.ts +20 -0
  248. package/dist/server/tunnel-manager.js +58 -0
  249. package/dist/server/websocket/fleet-bridge.d.ts +13 -1
  250. package/dist/server/websocket/fleet-bridge.js +16 -0
  251. package/dist/services/prompt-builder.d.ts +1 -0
  252. package/dist/services/prompt-builder.js +49 -8
  253. package/dist/shared/engine-types.d.ts +15 -1
  254. package/dist/sidecar/sidecar-bridge.d.ts +1 -0
  255. package/dist/sidecar/sidecar-bridge.js +21 -10
  256. package/dist/spec/spec-store.js +8 -1
  257. package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
  258. package/dist/talk-mode/providers/audioreader-tts.js +8 -8
  259. package/dist/templates/project-scaffolding.js +3 -2
  260. package/dist/themes/theme-schema.d.ts +10 -10
  261. package/dist/tools/application-profiles.js +38 -0
  262. package/dist/tools/bash/bash-tool.d.ts +1 -0
  263. package/dist/tools/bash/bash-tool.js +16 -2
  264. package/dist/tools/bash/command-validator.js +3 -0
  265. package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
  266. package/dist/tools/bash/rtk-rewrite.js +100 -0
  267. package/dist/tools/bash/streaming-executor.js +14 -1
  268. package/dist/tools/computer-control-tool.d.ts +16 -1
  269. package/dist/tools/computer-control-tool.js +317 -5
  270. package/dist/tools/document-generator.d.ts +14 -0
  271. package/dist/tools/document-generator.js +79 -0
  272. package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
  273. package/dist/tools/execute-code-rpc-invoker.js +46 -5
  274. package/dist/tools/metadata.js +28 -0
  275. package/dist/tools/office-macro-tool.d.ts +10 -0
  276. package/dist/tools/office-macro-tool.js +93 -0
  277. package/dist/tools/registry/index.d.ts +2 -1
  278. package/dist/tools/registry/index.js +2 -1
  279. package/dist/tools/registry/memory-tools.d.ts +20 -0
  280. package/dist/tools/registry/memory-tools.js +225 -3
  281. package/dist/tools/registry/multimodal-tools.js +2 -2
  282. package/dist/tools/registry/vision-tools.d.ts +33 -0
  283. package/dist/tools/registry/vision-tools.js +308 -6
  284. package/dist/tools/registry/windows-tools.d.ts +2 -0
  285. package/dist/tools/registry/windows-tools.js +47 -0
  286. package/dist/tools/route-peer-tool.js +14 -0
  287. package/dist/tools/screenshot-tool.js +14 -2
  288. package/dist/tools/text-to-speech-tool.d.ts +1 -1
  289. package/dist/tools/text-to-speech-tool.js +2 -12
  290. package/dist/tools/tool-selector.js +3 -59
  291. package/dist/utils/config-validation/schema.d.ts +40 -7
  292. package/dist/utils/config-validation/schema.js +130 -1
  293. package/dist/utils/cost-tracker.js +21 -1
  294. package/dist/utils/disk-guard.d.ts +180 -0
  295. package/dist/utils/disk-guard.js +404 -0
  296. package/dist/utils/interactive-setup.js +35 -2
  297. package/dist/utils/model-utils.js +11 -2
  298. package/dist/utils/output-sanitizer.js +11 -0
  299. package/dist/utils/provider-detector.d.ts +8 -7
  300. package/dist/utils/provider-detector.js +19 -77
  301. package/dist/utils/settings-manager.d.ts +7 -0
  302. package/dist/utils/token-display.d.ts +3 -3
  303. package/dist/utils/token-display.js +22 -4
  304. package/dist/wizard/onboarding.d.ts +39 -0
  305. package/dist/wizard/onboarding.js +433 -21
  306. package/dist/wizard/provider-onboarding.d.ts +8 -23
  307. package/dist/wizard/provider-onboarding.js +39 -158
  308. package/package.json +4 -2
  309. package/dist/plugins/provider-onboarding.d.ts +0 -23
  310. package/dist/plugins/provider-onboarding.js +0 -116
  311. package/dist/utils/kokoro-tts.d.ts +0 -8
  312. package/dist/utils/kokoro-tts.js +0 -67
@@ -30,6 +30,7 @@
30
30
  * backed by client `fs/*` + `session/request_permission`, and MCP passthrough.
31
31
  */
32
32
  import { randomUUID } from 'crypto';
33
+ import { AcpSessionStore } from './acp-session-store.js';
33
34
  export const ACP_PROTOCOL_VERSION = 1;
34
35
  function asString(value) {
35
36
  return typeof value === 'string' && value.length > 0 ? value : undefined;
@@ -56,6 +57,8 @@ export class AcpStdioServer {
56
57
  clientRequestTimeoutMs;
57
58
  sessions = new Map();
58
59
  pendingClientRequests = new Map();
60
+ store;
61
+ storeLoaded = false;
59
62
  clientCapabilities = {};
60
63
  nextClientRequestId = 0;
61
64
  buffer = '';
@@ -68,6 +71,7 @@ export class AcpStdioServer {
68
71
  this.agentInfo = options.agentInfo ?? { name: 'Code Buddy', title: 'Code Buddy', version: '1.0.0' };
69
72
  this.protocolVersion = options.protocolVersion ?? ACP_PROTOCOL_VERSION;
70
73
  this.clientRequestTimeoutMs = options.clientRequestTimeoutMs ?? 120_000;
74
+ this.store = options.store ?? new AcpSessionStore();
71
75
  }
72
76
  start() {
73
77
  if (this.started)
@@ -100,9 +104,45 @@ export class AcpStdioServer {
100
104
  sendUpdate(sessionId, update, options = {}) {
101
105
  if (options.record !== false) {
102
106
  this.sessions.get(sessionId)?.history.push(update);
107
+ void this.persistSession(sessionId);
103
108
  }
104
109
  this.write({ jsonrpc: '2.0', method: 'session/update', params: { sessionId, update } });
105
110
  }
111
+ ensureStoreLoaded() {
112
+ if (this.storeLoaded)
113
+ return;
114
+ this.storeLoaded = true;
115
+ return this.store.listAll().then((loaded) => {
116
+ for (const s of loaded) {
117
+ if (!this.sessions.has(s.sessionId)) {
118
+ this.sessions.set(s.sessionId, {
119
+ cwd: s.cwd,
120
+ active: null,
121
+ history: s.history,
122
+ mcpServers: s.mcpServers,
123
+ title: s.title,
124
+ updatedAt: s.updatedAt,
125
+ });
126
+ }
127
+ }
128
+ }).catch((err) => {
129
+ this.storeLoaded = false;
130
+ throw err;
131
+ });
132
+ }
133
+ async persistSession(sessionId) {
134
+ const s = this.sessions.get(sessionId);
135
+ if (!s)
136
+ return;
137
+ await this.store.save({
138
+ sessionId,
139
+ cwd: s.cwd,
140
+ history: s.history,
141
+ mcpServers: s.mcpServers,
142
+ title: s.title,
143
+ updatedAt: s.updatedAt,
144
+ });
145
+ }
106
146
  requestClient(method, params = {}, options = {}) {
107
147
  const clientCapabilities = options.clientCapabilities ?? this.clientCapabilities;
108
148
  if (!canRequestClientWithCapabilities(method, clientCapabilities)) {
@@ -230,24 +270,32 @@ export class AcpStdioServer {
230
270
  });
231
271
  }
232
272
  }
233
- async dispatch(method, params) {
234
- switch (method) {
235
- case 'initialize':
236
- return this.handleInitialize(params);
237
- case 'session/new':
238
- return this.handleNewSession(params);
239
- case 'session/list':
240
- return this.handleListSessions(params);
241
- case 'session/load':
242
- return this.handleLoadSession(params);
243
- case 'session/prompt':
244
- return this.handlePrompt(params);
245
- default: {
246
- const error = new Error(`Method not found: ${method}`);
247
- error.code = -32601;
248
- throw error;
273
+ dispatch(method, params) {
274
+ const run = () => {
275
+ switch (method) {
276
+ case 'initialize':
277
+ return this.handleInitialize(params);
278
+ case 'session/new':
279
+ return this.handleNewSession(params);
280
+ case 'session/list':
281
+ return this.handleListSessions(params);
282
+ case 'session/load':
283
+ return this.handleLoadSession(params);
284
+ case 'session/prompt':
285
+ return this.handlePrompt(params);
286
+ default: {
287
+ const error = new Error(`Method not found: ${method}`);
288
+ error.code = -32601;
289
+ throw error;
290
+ }
249
291
  }
292
+ };
293
+ if (method.startsWith('session/') && !this.storeLoaded) {
294
+ const p = this.ensureStoreLoaded();
295
+ if (p)
296
+ return p.then(run);
250
297
  }
298
+ return run();
251
299
  }
252
300
  handleInitialize(params) {
253
301
  if (params.protocolVersion !== this.protocolVersion) {
@@ -275,8 +323,10 @@ export class AcpStdioServer {
275
323
  cwd,
276
324
  active: null,
277
325
  history: [],
326
+ mcpServers: params.mcpServers,
278
327
  updatedAt: new Date().toISOString(),
279
328
  });
329
+ void this.persistSession(sessionId);
280
330
  return { sessionId };
281
331
  }
282
332
  handleListSessions(params) {
@@ -317,7 +367,10 @@ export class AcpStdioServer {
317
367
  const cwd = optionalStringParam(params, 'cwd', 'Invalid session/load cwd');
318
368
  if (cwd)
319
369
  session.cwd = cwd;
370
+ if ('mcpServers' in params)
371
+ session.mcpServers = params.mcpServers;
320
372
  session.updatedAt = new Date().toISOString();
373
+ void this.persistSession(sessionId);
321
374
  for (const update of session.history) {
322
375
  this.sendUpdate(sessionId, update, { record: false });
323
376
  }
@@ -349,6 +402,7 @@ export class AcpStdioServer {
349
402
  sessionId,
350
403
  cwd: session.cwd,
351
404
  clientCapabilities,
405
+ mcpServers: session.mcpServers,
352
406
  canRequestClient: (method) => canRequestClientWithCapabilities(method, clientCapabilities),
353
407
  prompt,
354
408
  signal: controller.signal,
@@ -359,6 +413,7 @@ export class AcpStdioServer {
359
413
  sendUpdate: (update) => this.sendUpdate(sessionId, update),
360
414
  });
361
415
  session.updatedAt = new Date().toISOString();
416
+ void this.persistSession(sessionId);
362
417
  return { stopReason: controller.signal.aborted ? 'cancelled' : stopReason };
363
418
  }
364
419
  catch (err) {
@@ -0,0 +1,37 @@
1
+ import { type RuntimeFallbackProvider } from './provider-fallback.js';
2
+ export type FailoverOrderPolicy = 'resilience' | 'free-first' | 'manual';
3
+ export interface ActiveLlm extends RuntimeFallbackProvider {
4
+ /** Local runtime (Ollama / LM Studio) — pushed last under the resilience policy. */
5
+ isLocal: boolean;
6
+ /** Best-effort: cloud-keyed/OAuth providers are assumed reachable; the reactive
7
+ * failover loop is the final arbiter, so this is advisory only. */
8
+ reachable: boolean;
9
+ /** Catalog priority (lower = preferred). */
10
+ priority: number;
11
+ /** Rough $/Mtok input cost for free-first ordering + the `/llm list` display. */
12
+ costInputUsdPerMtok: number;
13
+ }
14
+ export interface ActiveLlmRegistry {
15
+ /** Canonical id of the detected primary (never appears in `fallbacks`). */
16
+ primaryProvider: string | null;
17
+ /** Other active LLMs, ordered by policy — ready for `fallbackProviders`. */
18
+ fallbacks: ActiveLlm[];
19
+ /** Primary + fallbacks, for the `/llm list` surface. */
20
+ all: ActiveLlm[];
21
+ }
22
+ export interface BuildActiveLlmRegistryOptions {
23
+ /** The already-resolved session primary (from the index.ts bootstrap). */
24
+ primary?: {
25
+ provider?: string;
26
+ apiKey?: string;
27
+ baseURL?: string;
28
+ model?: string;
29
+ };
30
+ policy?: FailoverOrderPolicy;
31
+ manualOrder?: string[];
32
+ localOnly?: boolean;
33
+ env?: Record<string, string | undefined>;
34
+ force?: boolean;
35
+ }
36
+ export declare function orderFallbacks(list: ActiveLlm[], policy: FailoverOrderPolicy, manualOrder?: string[]): ActiveLlm[];
37
+ export declare function buildActiveLlmRegistry(opts?: BuildActiveLlmRegistryOptions): Promise<ActiveLlmRegistry>;
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Active-LLM registry — the set of providers/models the user is actually
3
+ * authenticated to (and that are reachable), used to drive auto-failover and
4
+ * "together" (ensemble) execution.
5
+ *
6
+ * This does NOT add new failover logic: it produces a `RuntimeFallbackProvider[]`
7
+ * that drops straight into `CodeBuddyClient`'s existing `fallbackProviders` slot
8
+ * (see `src/codebuddy/client.ts` `chatWithProviderFallback`). It joins existing
9
+ * resolvers — the provider catalog (`resolveProviderFromCatalog`), the ChatGPT /
10
+ * xAI OAuth credential checks, and the env-configured fallback list — rather than
11
+ * reinventing detection. The primary provider is passed in by the caller (the
12
+ * session bootstrap already resolved it) to avoid a circular import on
13
+ * `getDetectedProvider` in `src/index.ts`.
14
+ */
15
+ import { getDirectRuntimeProviderCatalog, findRuntimeProvider, resolveProviderFromCatalog, } from './provider-catalog.js';
16
+ import { resolveRuntimeFallbackProviders, } from './provider-fallback.js';
17
+ import { hasCodexCredentials } from './codex-oauth.js';
18
+ import { logger } from '../utils/logger.js';
19
+ /** Rough input $/Mtok for ordering + display. 0 for local runtimes and
20
+ * subscription-OAuth backends (no per-token metering). */
21
+ const APPROX_COST_USD_PER_MTOK = {
22
+ chatgpt: 0,
23
+ ollama: 0,
24
+ lmstudio: 0,
25
+ 'gemini-cli': 0,
26
+ grok: 0.5,
27
+ gemini: 0.3,
28
+ groq: 0.3,
29
+ mistral: 1,
30
+ anthropic: 3,
31
+ openai: 5,
32
+ };
33
+ function canonicalProviderId(provider) {
34
+ if (!provider)
35
+ return undefined;
36
+ return findRuntimeProvider(provider)?.id ?? provider.trim().toLowerCase();
37
+ }
38
+ /** Local runtimes that actually responded to a probe → their first real
39
+ * installed model (reuses the fleet capability registry's Ollama/LM Studio
40
+ * HTTP probes; `probeOllama` sets `id` to the actual model name). */
41
+ async function getReachableLocalModels(force) {
42
+ const map = new Map();
43
+ try {
44
+ const { getLocalCapabilities } = await import('../fleet/capability-registry.js');
45
+ const caps = await getLocalCapabilities({ force });
46
+ for (const m of caps.models) {
47
+ const id = canonicalProviderId(m.provider);
48
+ if ((id === 'ollama' || id === 'lmstudio') && !map.has(id)) {
49
+ map.set(id, m.id);
50
+ }
51
+ }
52
+ }
53
+ catch {
54
+ /* no local runtimes reachable */
55
+ }
56
+ return map;
57
+ }
58
+ /** Resolve the xAI subscription-login bearer when there's no GROK_API_KEY,
59
+ * mirroring `getDetectedProvider` in src/index.ts. */
60
+ async function resolveXaiOAuthProvider(entry, env) {
61
+ try {
62
+ const { hasXaiCredentials, getValidXaiAccessToken } = await import('./xai-oauth.js');
63
+ if (!hasXaiCredentials())
64
+ return null;
65
+ const token = await getValidXaiAccessToken();
66
+ if (!token)
67
+ return null;
68
+ return {
69
+ provider: 'grok',
70
+ label: entry.label,
71
+ apiMode: entry.apiMode,
72
+ authMode: entry.authMode,
73
+ apiKey: token,
74
+ baseURL: 'https://api.x.ai/v1',
75
+ defaultModel: env.GROK_MODEL || 'grok-4-latest',
76
+ source: 'override',
77
+ };
78
+ }
79
+ catch (err) {
80
+ logger.debug('xAI OAuth resolution skipped in active-llm-registry', {
81
+ error: err instanceof Error ? err.message : String(err),
82
+ });
83
+ return null;
84
+ }
85
+ }
86
+ function toActiveLlm(resolved, entry) {
87
+ const isLocal = (entry?.authMode ?? resolved.authMode) === 'local';
88
+ return {
89
+ ...resolved,
90
+ model: resolved.defaultModel,
91
+ rawSpec: `active:${resolved.provider}`,
92
+ fallbackSource: 'environment',
93
+ isLocal,
94
+ reachable: true,
95
+ priority: entry?.priority ?? 500,
96
+ costInputUsdPerMtok: APPROX_COST_USD_PER_MTOK[resolved.provider] ?? 1,
97
+ };
98
+ }
99
+ export function orderFallbacks(list, policy, manualOrder) {
100
+ const sorted = [...list];
101
+ if (policy === 'free-first') {
102
+ sorted.sort((a, b) => a.costInputUsdPerMtok - b.costInputUsdPerMtok || a.priority - b.priority);
103
+ }
104
+ else if (policy === 'manual' && manualOrder && manualOrder.length > 0) {
105
+ const rank = (p) => {
106
+ const i = manualOrder.findIndex((m) => canonicalProviderId(m) === canonicalProviderId(p.provider));
107
+ return i === -1 ? Number.MAX_SAFE_INTEGER : i;
108
+ };
109
+ sorted.sort((a, b) => rank(a) - rank(b));
110
+ }
111
+ else {
112
+ // resilience (default): capable cloud/subscription first (by catalog
113
+ // priority), local runtimes LAST as a free safety net.
114
+ sorted.sort((a, b) => Number(a.isLocal) - Number(b.isLocal) || a.priority - b.priority);
115
+ }
116
+ return sorted;
117
+ }
118
+ export async function buildActiveLlmRegistry(opts = {}) {
119
+ const env = opts.env ?? process.env;
120
+ const policy = opts.policy ?? 'resilience';
121
+ const hasOAuth = hasCodexCredentials();
122
+ const primaryProvider = canonicalProviderId(opts.primary?.provider) ?? null;
123
+ const catalog = getDirectRuntimeProviderCatalog();
124
+ const reachableLocalModels = await getReachableLocalModels(opts.force);
125
+ const all = [];
126
+ const seen = new Set();
127
+ for (const entry of catalog) {
128
+ let resolved = resolveProviderFromCatalog({
129
+ providerOverride: entry.id,
130
+ env,
131
+ hasChatGptOAuth: hasOAuth,
132
+ requireConfigured: true,
133
+ });
134
+ // xAI subscription login (no GROK_API_KEY) — the catalog can't see the
135
+ // OAuth token, so resolve it directly.
136
+ if (!resolved && entry.id === 'grok') {
137
+ resolved = await resolveXaiOAuthProvider(entry, env);
138
+ }
139
+ if (!resolved)
140
+ continue;
141
+ const isLocal = (entry.authMode ?? resolved.authMode) === 'local';
142
+ if (opts.localOnly && !isLocal)
143
+ continue;
144
+ // The catalog reports a local provider as "configured" even when it isn't
145
+ // running — only keep locals we actually probed as reachable, and use their
146
+ // real installed model (not the catalog default, which may not be pulled).
147
+ if (isLocal) {
148
+ const realModel = reachableLocalModels.get(canonicalProviderId(resolved.provider) ?? '');
149
+ if (!realModel)
150
+ continue;
151
+ resolved = { ...resolved, defaultModel: realModel };
152
+ }
153
+ const key = `${canonicalProviderId(resolved.provider)}:${resolved.baseURL.replace(/\/+$/, '')}`;
154
+ if (seen.has(key))
155
+ continue;
156
+ seen.add(key);
157
+ all.push(toActiveLlm(resolved, entry));
158
+ }
159
+ // Fallbacks = active set minus the primary provider.
160
+ const fallbacks = all.filter((p) => canonicalProviderId(p.provider) !== primaryProvider);
161
+ // Preserve any explicit env-configured fallbacks (CODEBUDDY_FALLBACK_PROVIDERS)
162
+ // — concat + dedupe so setting the env var never regresses.
163
+ for (const f of resolveRuntimeFallbackProviders({
164
+ env,
165
+ hasChatGptOAuth: hasOAuth,
166
+ active: opts.primary,
167
+ })) {
168
+ const key = `${canonicalProviderId(f.provider)}:${f.baseURL.replace(/\/+$/, '')}`;
169
+ if (seen.has(key))
170
+ continue;
171
+ seen.add(key);
172
+ fallbacks.push({
173
+ ...f,
174
+ isLocal: false,
175
+ reachable: true,
176
+ priority: 900,
177
+ costInputUsdPerMtok: APPROX_COST_USD_PER_MTOK[f.provider] ?? 1,
178
+ });
179
+ }
180
+ return {
181
+ primaryProvider,
182
+ fallbacks: orderFallbacks(fallbacks, policy, opts.manualOrder),
183
+ all,
184
+ };
185
+ }
186
+ //# sourceMappingURL=active-llm-registry.js.map
@@ -0,0 +1,25 @@
1
+ import { CodeBuddyClient, type ChatOptions } from '../codebuddy/client.js';
2
+ import { type ResolvedRuntimeProvider } from './provider-catalog.js';
3
+ type EnvLike = Record<string, string | undefined>;
4
+ export type RuntimeAuxiliaryTask = 'vision' | 'browser_vision' | 'web_extract' | 'approval' | 'compression' | 'skills_hub' | 'mcp' | 'triage_specifier' | 'session_title';
5
+ export interface RuntimeAuxiliaryMainProvider extends ResolvedRuntimeProvider {
6
+ model?: string;
7
+ }
8
+ export interface RuntimeAuxiliaryResolveOptions {
9
+ task: RuntimeAuxiliaryTask;
10
+ env?: EnvLike;
11
+ hasChatGptOAuth?: boolean;
12
+ mainProvider?: RuntimeAuxiliaryMainProvider | null;
13
+ defaultTimeoutMs?: number;
14
+ }
15
+ export interface ResolvedRuntimeAuxiliaryProvider extends ResolvedRuntimeProvider {
16
+ task: RuntimeAuxiliaryTask;
17
+ model: string;
18
+ timeoutMs: number;
19
+ providerSetting: string;
20
+ extraBody?: Record<string, unknown>;
21
+ }
22
+ export declare function resolveRuntimeAuxiliaryProvider(options: RuntimeAuxiliaryResolveOptions): ResolvedRuntimeAuxiliaryProvider | null;
23
+ export declare function createAuxiliaryCodeBuddyClient(provider: ResolvedRuntimeAuxiliaryProvider): CodeBuddyClient;
24
+ export declare function createAuxiliaryChatOptions(provider: ResolvedRuntimeAuxiliaryProvider, overrides?: ChatOptions): ChatOptions;
25
+ export {};
@@ -0,0 +1,192 @@
1
+ import { CodeBuddyClient, } from '../codebuddy/client.js';
2
+ import { hasCodexCredentials } from './codex-oauth.js';
3
+ import { findRuntimeProvider, resolveProviderFromCatalog, } from './provider-catalog.js';
4
+ const DEFAULT_AUXILIARY_TIMEOUT_MS = {
5
+ vision: 120_000,
6
+ browser_vision: 120_000,
7
+ web_extract: 360_000,
8
+ approval: 30_000,
9
+ compression: 120_000,
10
+ skills_hub: 30_000,
11
+ mcp: 30_000,
12
+ triage_specifier: 120_000,
13
+ session_title: 30_000,
14
+ };
15
+ const OPENROUTER_VISION_MODEL = 'google/gemini-2.5-flash';
16
+ export function resolveRuntimeAuxiliaryProvider(options) {
17
+ const env = options.env ?? process.env;
18
+ const config = readAuxiliaryEnvConfig(options.task, env);
19
+ const providerSetting = (config.provider || 'auto').trim().toLowerCase();
20
+ const timeoutMs = config.timeoutMs ?? options.defaultTimeoutMs ?? DEFAULT_AUXILIARY_TIMEOUT_MS[options.task];
21
+ const hasOAuth = options.hasChatGptOAuth ?? hasCodexCredentials();
22
+ if (providerSetting === 'main') {
23
+ return resolveFromMainProvider(options, config, timeoutMs, providerSetting);
24
+ }
25
+ if (providerSetting === 'auto') {
26
+ const autoResolved = resolveAutoAuxiliaryProvider(options, config, timeoutMs, hasOAuth);
27
+ if (autoResolved)
28
+ return autoResolved;
29
+ return resolveFromMainProvider(options, config, timeoutMs, providerSetting);
30
+ }
31
+ return resolveSpecificAuxiliaryProvider(options.task, providerSetting, env, config, timeoutMs, hasOAuth);
32
+ }
33
+ export function createAuxiliaryCodeBuddyClient(provider) {
34
+ return new CodeBuddyClient(provider.apiKey, provider.model, provider.baseURL, {
35
+ enableFallbacks: false,
36
+ });
37
+ }
38
+ export function createAuxiliaryChatOptions(provider, overrides = {}) {
39
+ return {
40
+ ...overrides,
41
+ model: overrides.model ?? provider.model,
42
+ timeoutMs: overrides.timeoutMs ?? provider.timeoutMs,
43
+ };
44
+ }
45
+ function resolveAutoAuxiliaryProvider(options, config, timeoutMs, hasOAuth) {
46
+ if ((options.task === 'vision' || options.task === 'browser_vision') && hasEnvValue(options.env ?? process.env, 'OPENROUTER_API_KEY')) {
47
+ return resolveSpecificAuxiliaryProvider(options.task, 'openrouter', options.env ?? process.env, {
48
+ ...config,
49
+ model: config.model || OPENROUTER_VISION_MODEL,
50
+ }, timeoutMs, hasOAuth);
51
+ }
52
+ if (options.mainProvider) {
53
+ return resolveFromMainProvider(options, config, timeoutMs, 'auto');
54
+ }
55
+ const resolved = resolveProviderFromCatalog({
56
+ env: options.env,
57
+ hasChatGptOAuth: hasOAuth,
58
+ requireConfigured: true,
59
+ });
60
+ if (!resolved)
61
+ return null;
62
+ return finalizeAuxiliaryProvider(options.task, resolved, config, timeoutMs, 'auto');
63
+ }
64
+ function resolveFromMainProvider(options, config, timeoutMs, providerSetting) {
65
+ const mainProvider = options.mainProvider;
66
+ if (!mainProvider)
67
+ return null;
68
+ return finalizeAuxiliaryProvider(options.task, mainProvider, config, timeoutMs, providerSetting);
69
+ }
70
+ function resolveSpecificAuxiliaryProvider(task, providerSetting, env, config, timeoutMs, hasOAuth) {
71
+ const entry = findRuntimeProvider(providerSetting);
72
+ if (!entry || entry.runtimeSupport !== 'direct')
73
+ return null;
74
+ const envOverlay = { ...env };
75
+ if (config.apiKey && entry.apiKeyEnvKeys[0]) {
76
+ envOverlay[entry.apiKeyEnvKeys[0]] = config.apiKey;
77
+ }
78
+ if (config.baseURL && entry.baseUrlEnvKeys[0]) {
79
+ envOverlay[entry.baseUrlEnvKeys[0]] = config.baseURL;
80
+ }
81
+ if (config.model && entry.modelEnvKeys[0]) {
82
+ envOverlay[entry.modelEnvKeys[0]] = config.model;
83
+ }
84
+ const resolved = resolveProviderFromCatalog({
85
+ providerOverride: providerSetting,
86
+ env: envOverlay,
87
+ hasChatGptOAuth: hasOAuth,
88
+ requireConfigured: true,
89
+ });
90
+ if (!resolved)
91
+ return null;
92
+ return finalizeAuxiliaryProvider(task, resolved, config, timeoutMs, providerSetting);
93
+ }
94
+ function finalizeAuxiliaryProvider(task, provider, config, timeoutMs, providerSetting) {
95
+ return {
96
+ ...provider,
97
+ apiKey: config.apiKey || provider.apiKey,
98
+ baseURL: (config.baseURL || provider.baseURL).replace(/\/+$/, ''),
99
+ defaultModel: config.model || provider.model || provider.defaultModel,
100
+ task,
101
+ model: config.model || provider.model || provider.defaultModel,
102
+ timeoutMs,
103
+ providerSetting,
104
+ ...(config.extraBody ? { extraBody: config.extraBody } : {}),
105
+ };
106
+ }
107
+ function readAuxiliaryEnvConfig(task, env) {
108
+ const taskKey = task.toUpperCase();
109
+ const provider = readFirstEnv(env, [
110
+ `CODEBUDDY_AUXILIARY_${taskKey}_PROVIDER`,
111
+ `AUXILIARY_${taskKey}_PROVIDER`,
112
+ 'CODEBUDDY_AUXILIARY_PROVIDER',
113
+ 'AUXILIARY_PROVIDER',
114
+ ]);
115
+ const model = readFirstEnv(env, [
116
+ `CODEBUDDY_AUXILIARY_${taskKey}_MODEL`,
117
+ `AUXILIARY_${taskKey}_MODEL`,
118
+ 'CODEBUDDY_AUXILIARY_MODEL',
119
+ 'AUXILIARY_MODEL',
120
+ ]);
121
+ const baseURL = readFirstEnv(env, [
122
+ `CODEBUDDY_AUXILIARY_${taskKey}_BASE_URL`,
123
+ `AUXILIARY_${taskKey}_BASE_URL`,
124
+ 'CODEBUDDY_AUXILIARY_BASE_URL',
125
+ 'AUXILIARY_BASE_URL',
126
+ ]);
127
+ const apiKey = readFirstEnv(env, [
128
+ `CODEBUDDY_AUXILIARY_${taskKey}_API_KEY`,
129
+ `AUXILIARY_${taskKey}_API_KEY`,
130
+ 'CODEBUDDY_AUXILIARY_API_KEY',
131
+ 'AUXILIARY_API_KEY',
132
+ ]);
133
+ const timeoutEntry = readFirstEnvEntry(env, [
134
+ `CODEBUDDY_AUXILIARY_${taskKey}_TIMEOUT_MS`,
135
+ `AUXILIARY_${taskKey}_TIMEOUT_MS`,
136
+ `AUXILIARY_${taskKey}_TIMEOUT`,
137
+ 'CODEBUDDY_AUXILIARY_TIMEOUT_MS',
138
+ 'AUXILIARY_TIMEOUT_MS',
139
+ ]);
140
+ const extraBodyRaw = readFirstEnv(env, [
141
+ `CODEBUDDY_AUXILIARY_${taskKey}_EXTRA_BODY`,
142
+ `AUXILIARY_${taskKey}_EXTRA_BODY`,
143
+ 'CODEBUDDY_AUXILIARY_EXTRA_BODY',
144
+ 'AUXILIARY_EXTRA_BODY',
145
+ ]);
146
+ return {
147
+ ...(provider ? { provider } : {}),
148
+ ...(model ? { model } : {}),
149
+ ...(baseURL ? { baseURL } : {}),
150
+ ...(apiKey ? { apiKey } : {}),
151
+ ...(timeoutEntry ? { timeoutMs: parseTimeoutMs(timeoutEntry.value, timeoutEntry.key.endsWith('_TIMEOUT')) } : {}),
152
+ ...(extraBodyRaw ? { extraBody: parseExtraBody(extraBodyRaw) } : {}),
153
+ };
154
+ }
155
+ function readFirstEnv(env, keys) {
156
+ for (const key of keys) {
157
+ const value = env[key]?.trim();
158
+ if (value)
159
+ return value;
160
+ }
161
+ return undefined;
162
+ }
163
+ function readFirstEnvEntry(env, keys) {
164
+ for (const key of keys) {
165
+ const value = env[key]?.trim();
166
+ if (value)
167
+ return { key, value };
168
+ }
169
+ return undefined;
170
+ }
171
+ function hasEnvValue(env, key) {
172
+ return readFirstEnv(env, [key]) !== undefined;
173
+ }
174
+ function parseTimeoutMs(value, seconds) {
175
+ const numeric = Number(value);
176
+ if (!Number.isFinite(numeric) || numeric <= 0)
177
+ return undefined;
178
+ return Math.round(seconds ? numeric * 1000 : numeric);
179
+ }
180
+ function parseExtraBody(value) {
181
+ try {
182
+ const parsed = JSON.parse(value);
183
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
184
+ return parsed;
185
+ }
186
+ }
187
+ catch {
188
+ return undefined;
189
+ }
190
+ return undefined;
191
+ }
192
+ //# sourceMappingURL=auxiliary-provider.js.map
@@ -109,7 +109,7 @@ declare function bindCallbackServer(ports: number[], handler: http.RequestListen
109
109
  * Returns the parsed `ChatGptAuth` so callers can show the user their
110
110
  * email/plan immediately. Throws on failure / timeout (5 minutes).
111
111
  */
112
- export declare function loginInteractive(): Promise<ChatGptAuth>;
112
+ export declare function loginInteractive(openUrl?: (url: string) => void | Promise<void>): Promise<ChatGptAuth>;
113
113
  /**
114
114
  * Returns the current ChatGptAuth (with claims), refreshing the access
115
115
  * token if `last_refresh` is older than 1 hour. Returns `null` when no
@@ -35,6 +35,9 @@ import { logger } from '../utils/logger.js';
35
35
  const CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
36
36
  /** OAuth issuer — both authorize and token endpoints live under here. */
37
37
  const ISSUER = 'https://auth.openai.com';
38
+ /** Hard ceiling on the token exchange/refresh fetches so a stalled IdP can't
39
+ * hang an inline refresh (runs on the first chat call when tokens are stale). */
40
+ const OAUTH_TOKEN_TIMEOUT_MS = 30_000;
38
41
  /** Primary callback port. Must match OpenAI's allow-list of registered
39
42
  * redirect URIs for the Codex CLI client_id. */
40
43
  const CALLBACK_PORT = 1455;
@@ -189,6 +192,8 @@ async function exchangeCodeForTokens(code, codeVerifier, redirectUri) {
189
192
  method: 'POST',
190
193
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
191
194
  body: params.toString(),
195
+ // Bound the network await so a stalled IdP can't hang the caller indefinitely.
196
+ signal: AbortSignal.timeout(OAUTH_TOKEN_TIMEOUT_MS),
192
197
  });
193
198
  if (!response.ok) {
194
199
  const body = await response.text().catch(() => '');
@@ -208,6 +213,9 @@ async function refreshTokens(refreshToken) {
208
213
  refresh_token: refreshToken,
209
214
  client_id: CLIENT_ID,
210
215
  }),
216
+ // A stale-token refresh runs inline on the first chat call; bound it so a
217
+ // stalled IdP surfaces as a timeout error instead of an indefinite hang.
218
+ signal: AbortSignal.timeout(OAUTH_TOKEN_TIMEOUT_MS),
211
219
  });
212
220
  if (!response.ok) {
213
221
  const body = await response.text().catch(() => '');
@@ -344,7 +352,7 @@ async function bindCallbackServer(ports, handler) {
344
352
  * Returns the parsed `ChatGptAuth` so callers can show the user their
345
353
  * email/plan immediately. Throws on failure / timeout (5 minutes).
346
354
  */
347
- export async function loginInteractive() {
355
+ export function loginInteractive(openUrl) {
348
356
  const pkce = generatePkce();
349
357
  const state = randomState();
350
358
  return new Promise((resolve, reject) => {
@@ -433,9 +441,24 @@ export async function loginInteractive() {
433
441
  }, 5 * 60 * 1000);
434
442
  // Open the browser. If it fails, log the URL so the user can
435
443
  // copy-paste manually.
436
- open(authUrl).catch(() => {
437
- console.error(`Couldn't auto-open the browser. Open this URL manually:\n${authUrl}`);
438
- });
444
+ if (openUrl) {
445
+ try {
446
+ const res = openUrl(authUrl);
447
+ if (res instanceof Promise) {
448
+ res.catch(() => {
449
+ console.error(`Couldn't auto-open the browser. Open this URL manually:\n${authUrl}`);
450
+ });
451
+ }
452
+ }
453
+ catch {
454
+ console.error(`Couldn't auto-open the browser. Open this URL manually:\n${authUrl}`);
455
+ }
456
+ }
457
+ else {
458
+ open(authUrl).catch(() => {
459
+ console.error(`Couldn't auto-open the browser. Open this URL manually:\n${authUrl}`);
460
+ });
461
+ }
439
462
  })
440
463
  .catch(reject);
441
464
  });
@@ -16,6 +16,9 @@ export { ProviderManager, getProviderManager, resetProviderManager, autoConfigur
16
16
  export * from './local-llm-provider.js';
17
17
  export { ADDITIONAL_PROVIDERS, getAdditionalProvider, getProviderForModel, listAvailableProviders, listAllProviders, resolveProviderConfig, } from './additional-providers.js';
18
18
  export type { ProviderConfig as AdditionalProviderConfig } from './additional-providers.js';
19
+ export * from './provider-catalog.js';
20
+ export * from './provider-fallback.js';
21
+ export * from './auxiliary-provider.js';
19
22
  export { ProviderFallbackChain, getFallbackChain, resetFallbackChain, } from './fallback-chain.js';
20
23
  export type { FallbackConfig, ProviderHealth, FallbackChainEvents, } from './fallback-chain.js';
21
24
  export { SmartModelRouter, getSmartRouter, resetSmartRouter, } from './smart-router.js';