@desplega.ai/agent-swarm 1.158.0 → 1.160.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 (378) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
  3. package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
  4. package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
  5. package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
  6. package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
  7. package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
  8. package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
  9. package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
  10. package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
  11. package/dist/boot-seeds-gsetbs5y.js +28 -0
  12. package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
  13. package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
  14. package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
  15. package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
  16. package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
  17. package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
  18. package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
  19. package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
  20. package/dist/cli-0x01kwrd.js +491 -0
  21. package/dist/cli-0xqde53b.js +176 -0
  22. package/dist/cli-10nhj6xq.js +8355 -0
  23. package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
  24. package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
  25. package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
  26. package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
  27. package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
  28. package/dist/cli-3qhyh31j.js +166 -0
  29. package/dist/cli-447dt1h3.js +3828 -0
  30. package/dist/cli-4derpgyk.js +115 -0
  31. package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
  32. package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
  33. package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
  34. package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
  35. package/dist/cli-741yb0xx.js +1027 -0
  36. package/dist/cli-74h9hscv.js +69 -0
  37. package/dist/cli-7cxw8b60.js +14910 -0
  38. package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
  39. package/dist/cli-7kyk9jr3.js +22 -0
  40. package/dist/cli-89s4ngw3.js +183 -0
  41. package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
  42. package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
  43. package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
  44. package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
  45. package/dist/cli-br0qdrnp.js +2150 -0
  46. package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
  47. package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
  48. package/dist/cli-cpvsaqsw.js +333 -0
  49. package/dist/cli-d5czme6m.js +17805 -0
  50. package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
  51. package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
  52. package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
  53. package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
  54. package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
  55. package/dist/cli-gt4hxb8p.js +99 -0
  56. package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
  57. package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
  58. package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
  59. package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
  60. package/dist/cli-kmcpfwn2.js +333856 -0
  61. package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
  62. package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
  63. package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
  64. package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
  65. package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
  66. package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
  67. package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
  68. package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
  69. package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
  70. package/dist/cli-rb9m6rpe.js +4980 -0
  71. package/dist/cli-rykfmgwg.js +102 -0
  72. package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
  73. package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
  74. package/dist/cli-tfky2838.js +756 -0
  75. package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
  76. package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
  77. package/dist/cli-trc24wk2.js +143 -0
  78. package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
  79. package/dist/cli-v7fn5gms.js +1425 -0
  80. package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
  81. package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
  82. package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
  83. package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
  84. package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
  85. package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
  86. package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
  87. package/dist/cli-zpep9q5e.js +491 -0
  88. package/dist/cli.js +41 -32
  89. package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
  90. package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
  91. package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
  92. package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
  93. package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
  94. package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
  95. package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
  96. package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
  97. package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
  98. package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
  99. package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
  100. package/dist/execute-6e7qeyk4.js +1017 -0
  101. package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
  102. package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
  103. package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
  104. package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
  105. package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
  106. package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
  107. package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
  108. package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
  109. package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
  110. package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
  111. package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
  112. package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
  113. package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
  114. package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
  115. package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
  116. package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
  117. package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
  118. package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
  119. package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
  120. package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
  121. package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
  122. package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
  123. package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
  124. package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
  125. package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
  126. package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
  127. package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
  128. package/dist/pricing-refresh-wx0tp7cb.js +39 -0
  129. package/dist/quickjs-r1pq2107.wasm +0 -0
  130. package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
  131. package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
  132. package/dist/runtime-zyssgse0.js +24 -0
  133. package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
  134. package/dist/typesafe-system-one-2ef30pec.js +27 -0
  135. package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
  136. package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
  137. package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
  138. package/openapi.json +1314 -91
  139. package/package.json +12 -11
  140. package/src/be/db/agents.ts +20 -0
  141. package/src/be/db/api-keys.ts +70 -0
  142. package/src/be/db/tasks/human-free.ts +442 -0
  143. package/src/be/db/tasks/read.ts +56 -1
  144. package/src/be/db/tasks/write.ts +107 -11
  145. package/src/be/db.ts +274 -188
  146. package/src/be/harness-model-support.ts +182 -0
  147. package/src/be/human-free-drain.ts +67 -0
  148. package/src/be/memory/providers/sqlite-store.ts +51 -15
  149. package/src/be/migrations/182_task_human_free_flag.sql +63 -0
  150. package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
  151. package/src/be/migrations/184_model_catalog.sql +120 -0
  152. package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
  153. package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
  154. package/src/be/model-catalog-store.ts +644 -0
  155. package/src/be/model-tier-keys.ts +46 -0
  156. package/src/be/model-tier-resolution.ts +534 -0
  157. package/src/be/model-validation.ts +188 -0
  158. package/src/be/models-catalog.ts +61 -7
  159. package/src/be/modelsdev-cache.json +82 -0
  160. package/src/be/modelsdev-cache.ts +2 -0
  161. package/src/be/pricing-refresh.ts +154 -12
  162. package/src/be/scripts/typecheck.ts +15 -0
  163. package/src/be/seed/runner.ts +18 -12
  164. package/src/be/seed/types.ts +1 -0
  165. package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
  166. package/src/be/swarm-config-guard.ts +8 -0
  167. package/src/cli.tsx +10 -0
  168. package/src/commands/claude-managed-setup.ts +3 -1
  169. package/src/commands/codex-login.ts +67 -0
  170. package/src/commands/credential-outcome-report.ts +191 -0
  171. package/src/commands/rate-limit-outcome.ts +34 -4
  172. package/src/commands/runner.ts +357 -186
  173. package/src/commands/seat-mismatch-report.ts +46 -0
  174. package/src/extensions/apply-task-create.ts +27 -1
  175. package/src/extensions/contract-types.generated.ts +1 -1
  176. package/src/heartbeat/heartbeat.ts +79 -17
  177. package/src/heartbeat/templates.ts +2 -2
  178. package/src/http/agents.ts +62 -1
  179. package/src/http/api-keys.ts +140 -2
  180. package/src/http/codex-oauth-keep-warm.ts +3 -5
  181. package/src/http/index.ts +8 -0
  182. package/src/http/memory.ts +12 -5
  183. package/src/http/models-catalog.ts +357 -8
  184. package/src/http/poll.ts +54 -3
  185. package/src/http/schedules.ts +51 -6
  186. package/src/http/script-runs.ts +12 -0
  187. package/src/http/session-data.ts +2 -5
  188. package/src/http/stats.ts +6 -8
  189. package/src/http/status.ts +15 -1
  190. package/src/http/tasks.ts +90 -7
  191. package/src/http/usage-cache.ts +56 -15
  192. package/src/http/workflows.ts +46 -8
  193. package/src/mcp-client/http-client.ts +5 -0
  194. package/src/memory/recall-query.ts +74 -0
  195. package/src/prompts/base-prompt.ts +15 -4
  196. package/src/prompts/session-templates.ts +23 -1
  197. package/src/providers/acp-adapter.ts +1 -0
  198. package/src/providers/claude-adapter.ts +14 -5
  199. package/src/providers/claude-managed-adapter.ts +1 -0
  200. package/src/providers/claude-managed-models.ts +47 -161
  201. package/src/providers/claude-sdk-session.ts +3 -1
  202. package/src/providers/codex-adapter.ts +14 -14
  203. package/src/providers/codex-models.ts +65 -198
  204. package/src/providers/devin-adapter.ts +1 -0
  205. package/src/providers/dsh-adapter.ts +2 -1
  206. package/src/providers/harness-version.ts +83 -7
  207. package/src/providers/opencode-adapter.ts +53 -1
  208. package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
  209. package/src/providers/pi-codemode-runtime.ts +17 -0
  210. package/src/providers/pi-mono-adapter.ts +361 -83
  211. package/src/providers/pi-mono-extension.ts +16 -1
  212. package/src/providers/reasoning-effort.ts +44 -140
  213. package/src/providers/types.ts +8 -0
  214. package/src/rbac/legacy-policy.ts +43 -0
  215. package/src/rbac/permissions.ts +15 -0
  216. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  217. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  218. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  219. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  220. package/src/server.ts +6 -0
  221. package/src/slack/assistant.ts +13 -0
  222. package/src/slack/message-text.ts +56 -2
  223. package/src/slack/render-v2.ts +87 -37
  224. package/src/slack/session-status.ts +541 -0
  225. package/src/slack/thread-buffer.ts +10 -2
  226. package/src/tasks/sibling-awareness.ts +3 -2
  227. package/src/telemetry.ts +5 -4
  228. package/src/templates.d.ts +6 -0
  229. package/src/tests/agents-list-model-display.test.ts +4 -6
  230. package/src/tests/api-key-auth-failure-route.test.ts +142 -0
  231. package/src/tests/api-key-tracking.test.ts +368 -1
  232. package/src/tests/base-prompt.test.ts +43 -2
  233. package/src/tests/claude-adapter.test.ts +68 -0
  234. package/src/tests/claude-managed-adapter.test.ts +12 -18
  235. package/src/tests/codex-adapter.test.ts +2 -1
  236. package/src/tests/codex-auth-failure.test.ts +52 -0
  237. package/src/tests/codex-gpt6-release.test.ts +66 -5
  238. package/src/tests/codex-login.test.ts +116 -0
  239. package/src/tests/context-window.test.ts +7 -5
  240. package/src/tests/credential-exhaustion-policy.test.ts +118 -3
  241. package/src/tests/credential-outcome-report.test.ts +171 -0
  242. package/src/tests/credential-status-api.test.ts +103 -2
  243. package/src/tests/db-extraction-contract.test.ts +1 -0
  244. package/src/tests/db-task-read-contract.test.ts +10 -1
  245. package/src/tests/db-task-write-contract.test.ts +535 -2
  246. package/src/tests/docs-index-footprint.test.js +3 -3
  247. package/src/tests/dokploy-deploy.test.ts +315 -0
  248. package/src/tests/dsh-adapter.test.ts +1 -1
  249. package/src/tests/explicit-model-validation.test.ts +583 -0
  250. package/src/tests/extensions-pre-task.test.ts +73 -0
  251. package/src/tests/fetch-resolved-env.test.ts +46 -0
  252. package/src/tests/hang-watchdog-worker.ts +47 -0
  253. package/src/tests/hang-watchdog.test.ts +45 -0
  254. package/src/tests/hang-watchdog.ts +30 -0
  255. package/src/tests/harness-model-guard.test.ts +123 -0
  256. package/src/tests/harness-model-support.test.ts +374 -0
  257. package/src/tests/harness-version.test.ts +70 -3
  258. package/src/tests/heartbeat-checklist-config.test.ts +71 -0
  259. package/src/tests/heartbeat-checklist.test.ts +4 -2
  260. package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
  261. package/src/tests/http-task-write-ownership.test.ts +172 -0
  262. package/src/tests/human-free-flag.test.ts +279 -0
  263. package/src/tests/human-free-oracle.ts +57 -0
  264. package/src/tests/human-free-reclassify.test.ts +669 -0
  265. package/src/tests/memory-fts-populate.test.ts +139 -0
  266. package/src/tests/memory-http-recall-gating.test.ts +125 -1
  267. package/src/tests/migration-046-budgets.test.ts +3 -3
  268. package/src/tests/model-catalog-migration.test.ts +134 -0
  269. package/src/tests/model-catalog-table.test.ts +249 -0
  270. package/src/tests/model-catalog-write-access.test.ts +387 -0
  271. package/src/tests/model-rate-limit-windows.test.ts +19 -0
  272. package/src/tests/model-tier-resolution.test.ts +611 -0
  273. package/src/tests/models-catalog.test.ts +1 -1
  274. package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
  275. package/src/tests/opencode-adapter.test.ts +157 -2
  276. package/src/tests/package-publish.test.ts +137 -36
  277. package/src/tests/pi-codemode.test.ts +246 -0
  278. package/src/tests/pi-mono-adapter.test.ts +3 -0
  279. package/src/tests/pi-native-mcp.test.ts +193 -0
  280. package/src/tests/pi-tool-exposure.test.ts +374 -0
  281. package/src/tests/preload.ts +3 -0
  282. package/src/tests/pricing-routes.test.ts +2 -2
  283. package/src/tests/prompt-template-session.test.ts +5 -3
  284. package/src/tests/rate-limit-event.test.ts +65 -0
  285. package/src/tests/rate-limit-outcome.test.ts +90 -0
  286. package/src/tests/rbac-engine.test.ts +77 -3
  287. package/src/tests/reasoning-effort.test.ts +109 -0
  288. package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
  289. package/src/tests/runner-key-completion-outcome.test.ts +112 -0
  290. package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
  291. package/src/tests/runner-registration-retry.test.ts +149 -0
  292. package/src/tests/runtime-model-catalog.test.ts +86 -0
  293. package/src/tests/script-connections.test.ts +9 -0
  294. package/src/tests/seat-mismatch-report.test.ts +85 -0
  295. package/src/tests/seed-scripts.test.ts +138 -0
  296. package/src/tests/seed.test.ts +25 -0
  297. package/src/tests/session-costs.test.ts +14 -11
  298. package/src/tests/slack-message-text.test.ts +101 -0
  299. package/src/tests/slack-render-v2.test.ts +96 -0
  300. package/src/tests/slack-session-status.test.ts +626 -0
  301. package/src/tests/slack-thread-buffer-context.test.ts +93 -0
  302. package/src/tests/status.test.ts +29 -0
  303. package/src/tests/steering-promotion.test.ts +51 -0
  304. package/src/tests/store-progress-ownership.test.ts +136 -0
  305. package/src/tests/subscription-plans.test.ts +28 -0
  306. package/src/tests/task-cascade-fail.test.ts +148 -2
  307. package/src/tests/task-citations.test.ts +3 -2
  308. package/src/tests/tool-annotations.test.ts +1 -1
  309. package/src/tests/usage-cache.test.ts +166 -0
  310. package/src/tests/workflow-agent-task.test.ts +30 -0
  311. package/src/tests/workflow-executors.test.ts +5 -2
  312. package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
  313. package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
  314. package/src/tests/workflow-system-one-decision.test.ts +2063 -0
  315. package/src/tests/workflow-triggers-v2.test.ts +320 -0
  316. package/src/tools/model-catalog/index.ts +137 -0
  317. package/src/tools/schedules/create-schedule.ts +17 -2
  318. package/src/tools/schedules/patch-schedule.ts +31 -1
  319. package/src/tools/schedules/update-schedule.ts +31 -1
  320. package/src/tools/send-task.ts +18 -1
  321. package/src/tools/store-progress.ts +49 -4
  322. package/src/tools/task-action.ts +14 -1
  323. package/src/tools/tool-config.ts +3 -1
  324. package/src/tools/workflows/create-workflow.ts +17 -4
  325. package/src/tools/workflows/patch-workflow-node.ts +17 -7
  326. package/src/tools/workflows/patch-workflow.ts +9 -2
  327. package/src/tools/workflows/update-workflow.ts +17 -4
  328. package/src/types.ts +41 -1
  329. package/src/utils/codex-auth-failure.ts +34 -0
  330. package/src/utils/context-window.ts +47 -53
  331. package/src/utils/credentials.ts +72 -30
  332. package/src/utils/error-tracker.ts +80 -0
  333. package/src/utils/harness-cli-version.ts +115 -0
  334. package/src/utils/harness-model-error.ts +33 -0
  335. package/src/utils/model-rate-limit-windows.ts +12 -0
  336. package/src/utils/runtime-model-catalog.ts +152 -0
  337. package/src/utils/spawn-model-guard.ts +43 -0
  338. package/src/utils/subscription-plans.ts +22 -0
  339. package/src/workflows/approval-resolution.ts +39 -0
  340. package/src/workflows/definition.ts +7 -0
  341. package/src/workflows/engine.ts +69 -1
  342. package/src/workflows/executors/agent-task.ts +16 -6
  343. package/src/workflows/executors/base.ts +53 -0
  344. package/src/workflows/executors/human-in-the-loop.ts +8 -8
  345. package/src/workflows/executors/index.ts +1 -0
  346. package/src/workflows/executors/registry.ts +2 -0
  347. package/src/workflows/executors/system-one-decision.ts +1232 -0
  348. package/src/workflows/executors/system-one-providers.ts +301 -0
  349. package/src/workflows/executors/workflow-llm.ts +13 -1
  350. package/src/workflows/model-validation.ts +45 -0
  351. package/src/workflows/patch-definition.ts +5 -0
  352. package/src/workflows/readiness.ts +86 -0
  353. package/src/workflows/recovery.ts +12 -12
  354. package/src/workflows/resume.ts +23 -9
  355. package/src/workflows/triggers.ts +85 -0
  356. package/templates/schedules/daily-blocker-digest/content.md +4 -5
  357. package/templates/skills/agent-browser/SKILL.md +6 -5
  358. package/templates/skills/agent-browser/content.md +6 -5
  359. package/templates/skills/heartbeat-runbook/config.json +1 -1
  360. package/templates/skills/heartbeat-runbook/content.md +2 -2
  361. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  362. package/templates/skills/swarm-scripts/content.md +1 -1
  363. package/templates/skills/workflow-iterate/content.md +82 -1
  364. package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
  365. package/templates/workflows/pr-review-status-sweep/content.md +2 -0
  366. package/dist/boot-seeds-s3q01xj3.js +0 -26
  367. package/dist/claude-sdk-session-t442qz6f.js +0 -39108
  368. package/dist/cli-0xjkj1j7.js +0 -61
  369. package/dist/cli-20cj37vt.js +0 -335561
  370. package/dist/cli-2djtr51b.js +0 -48
  371. package/dist/cli-65hjmev5.js +0 -1141
  372. package/dist/cli-aw1jwp1r.js +0 -14075
  373. package/dist/cli-h967nb6r.js +0 -6603
  374. package/dist/cli-vapyk8sw.js +0 -20
  375. package/dist/cli-ws6rqycm.js +0 -247
  376. package/dist/pricing-refresh-v1cbr9te.js +0 -27
  377. package/src/providers/modelsdev-reasoning.json +0 -6453
  378. package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
@@ -1,355 +1,30 @@
1
1
  import {
2
2
  getValidCodexOAuth,
3
3
  persistCodexOAuth
4
- } from "./cli-vhjwh6cz.js";
4
+ } from "./cli-ygwm91nt.js";
5
5
  import {
6
6
  GITHUB_COPILOT_MODELS,
7
7
  builtinModels,
8
- getEnvApiKey,
9
8
  normalizeRadiusGatewayUrl,
10
9
  registerBundledOAuthFlowLoaders
11
- } from "./cli-aw1jwp1r.js";
10
+ } from "./cli-10nhj6xq.js";
12
11
  import {
13
- init_zod
14
- } from "./cli-sd0mxa3c.js";
12
+ oauthErrorHtml,
13
+ oauthSuccessHtml
14
+ } from "./cli-rykfmgwg.js";
15
15
  import {
16
- exports_external
17
- } from "./cli-w5e1d1vv.js";
16
+ getEnvApiKey
17
+ } from "./cli-trc24wk2.js";
18
18
  import {
19
19
  getProviderEnvValue
20
20
  } from "./cli-btbzvq95.js";
21
21
  import {
22
22
  InMemoryCredentialStore
23
- } from "./cli-mcnhgnn1.js";
23
+ } from "./cli-ykk5jaax.js";
24
24
  import {
25
25
  __require
26
26
  } from "./cli-bc05qbss.js";
27
27
 
28
- // plugin/opencode-plugins/lib/memory-raters.ts
29
- function getMemoryRaterNames() {
30
- return (process.env.MEMORY_RATERS ?? "implicit-citation,explicit-self").split(",").map((name) => name.trim()).filter(Boolean);
31
- }
32
- // src/be/memory/raters/llm.ts
33
- init_zod();
34
-
35
- // src/be/memory/raters/llm-client.ts
36
- var DEFAULT_TIMEOUT_MS = 30000;
37
- var PROMPT_TEMPLATE = `You are scoring the usefulness of one retrieved memory.
38
-
39
- Return ONLY a JSON object with these fields (no prose, no markdown):
40
- {
41
- "score": number, // 0 = misleading/unhelpful, 1 = highly useful
42
- "reasoning": string // 1..500 chars, why
43
- }
44
-
45
- QUERY:
46
- \${query}
47
-
48
- MEMORY:
49
- id: \${memoryId}
50
- name: \${memoryName}
51
- content: \${memoryContent}
52
-
53
- AGENT RESPONSE / SUMMARY:
54
- \${response}
55
-
56
- Score 0..1.`;
57
- var PLACEHOLDER_PREFIX = "$";
58
- var QUERY_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{query}`;
59
- var MEMORY_ID_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryId}`;
60
- var MEMORY_NAME_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryName}`;
61
- var MEMORY_CONTENT_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryContent}`;
62
- var RESPONSE_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{response}`;
63
- function buildPrompt(input) {
64
- return PROMPT_TEMPLATE.replace(QUERY_PLACEHOLDER, input.query).replace(MEMORY_ID_PLACEHOLDER, input.memory.id).replace(MEMORY_NAME_PLACEHOLDER, input.memory.name).replace(MEMORY_CONTENT_PLACEHOLDER, input.memory.content).replace(RESPONSE_PLACEHOLDER, input.response);
65
- }
66
- function parseScoreAndReasoning(raw) {
67
- if (typeof raw !== "string")
68
- return null;
69
- let parsed;
70
- try {
71
- parsed = JSON.parse(raw.trim());
72
- } catch {
73
- return null;
74
- }
75
- if (!parsed || typeof parsed !== "object")
76
- return null;
77
- const obj = parsed;
78
- const score = typeof obj.score === "number" ? obj.score : null;
79
- const reasoning = typeof obj.reasoning === "string" ? obj.reasoning : null;
80
- if (score == null || reasoning == null)
81
- return null;
82
- if (!Number.isFinite(score) || score < 0 || score > 1)
83
- return null;
84
- if (reasoning.length === 0 || reasoning.length > 500)
85
- return null;
86
- return { score, reasoning };
87
- }
88
-
89
- class ClaudeCliLlmRaterClient {
90
- model;
91
- timeoutMs;
92
- constructor(opts = {}) {
93
- this.model = opts.model ?? process.env.MEMORY_LLM_RATER_MODEL ?? "haiku";
94
- this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
95
- }
96
- async rate(input) {
97
- const prompt = buildPrompt(input);
98
- const tmpFile = `/tmp/llm-rater-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`;
99
- let stdout = "";
100
- try {
101
- await Bun.write(tmpFile, prompt);
102
- const proc = Bun.spawn(["bash", "-c", `cat "${tmpFile}" | claude -p --model ${this.model} --output-format json`], {
103
- stdout: "pipe",
104
- stderr: "pipe",
105
- env: { ...process.env, SKIP_SESSION_SUMMARY: "1" }
106
- });
107
- const timeoutId = setTimeout(() => proc.kill(), this.timeoutMs);
108
- stdout = await new Response(proc.stdout).text();
109
- clearTimeout(timeoutId);
110
- } catch (err) {
111
- console.error("[memory-rater:llm] claude -p shell-out failed:", err.message);
112
- return null;
113
- } finally {
114
- try {
115
- await Bun.$`rm -f ${tmpFile}`.quiet();
116
- } catch {}
117
- }
118
- let envelope;
119
- try {
120
- envelope = JSON.parse(stdout);
121
- } catch {
122
- return null;
123
- }
124
- return parseScoreAndReasoning(envelope.result);
125
- }
126
- }
127
-
128
- // src/be/memory/raters/types.ts
129
- var REFERENCES_SOURCE_MAX_LENGTH = 512;
130
- var NUL_CHAR_CODE = 0;
131
- var DEL_CHAR_CODE = 127;
132
- var FIRST_PRINTABLE_ASCII = 32;
133
- function sanitizeReferencesSource(input) {
134
- let stripped = "";
135
- for (let i = 0;i < input.length; i++) {
136
- const code = input.charCodeAt(i);
137
- if (code === NUL_CHAR_CODE)
138
- return null;
139
- if (code < FIRST_PRINTABLE_ASCII || code === DEL_CHAR_CODE) {
140
- continue;
141
- }
142
- stripped += input[i];
143
- }
144
- if (stripped.length === 0)
145
- return null;
146
- return stripped;
147
- }
148
-
149
- // src/be/memory/raters/llm.ts
150
- var LLM_RATER_WEIGHT = 0.8;
151
- var RatingSchema = exports_external.object({
152
- id: exports_external.string().min(1),
153
- score: exports_external.number().min(0).max(1),
154
- reasoning: exports_external.string().min(1).max(500),
155
- referencesSource: exports_external.string().min(1).max(REFERENCES_SOURCE_MAX_LENGTH).optional()
156
- });
157
- var SummaryWithRatingsSchema = exports_external.object({
158
- summary: exports_external.string(),
159
- ratings: exports_external.array(RatingSchema).default([])
160
- });
161
- var BASE_SUMMARIZE_PROMPT = `You are summarizing an AI agent's work session. Extract ONLY high-value learnings.
162
-
163
- DO NOT include:
164
- - Generic descriptions of what was done ("worked on task X")
165
- - Tool calls or file reads
166
- - Routine progress updates
167
-
168
- DO include (if present):
169
- - **Mistakes made and corrections** — what went wrong and what fixed it
170
- - **Discovered patterns** — reusable approaches, APIs, or codebase conventions
171
- - **Codebase knowledge** — important file paths, architecture decisions, gotchas
172
- - **Environment knowledge** — service URLs, config details, tool quirks
173
- - **Failed approaches** — what was tried and didn't work (and why)
174
-
175
- Format as a bulleted list of concrete, reusable facts. If the session was routine with no significant learnings, respond with exactly: "No significant learnings."`;
176
-
177
- class LlmRater {
178
- client;
179
- name = "llm";
180
- constructor(client = new ClaudeCliLlmRaterClient) {
181
- this.client = client;
182
- }
183
- async rate(ctx) {
184
- const enriched = ctx;
185
- if (enriched.retrievedMemoryIds.length === 0)
186
- return [];
187
- const memories = enriched.retrievedMemories;
188
- if (!memories || memories.length === 0)
189
- return [];
190
- const events = [];
191
- for (const memoryId of enriched.retrievedMemoryIds) {
192
- const memory = memories.find((m) => m.id === memoryId);
193
- if (!memory)
194
- continue;
195
- let result;
196
- try {
197
- result = await this.client.rate({
198
- query: enriched.query ?? "",
199
- memory,
200
- response: enriched.response ?? enriched.evidence ?? ""
201
- });
202
- } catch (err) {
203
- console.error(`[memory-rater:llm] client.rate threw for memoryId=${memoryId}:`, err.message);
204
- continue;
205
- }
206
- if (!result)
207
- continue;
208
- events.push({
209
- memoryId,
210
- signal: 2 * result.score - 1,
211
- weight: LLM_RATER_WEIGHT,
212
- source: "",
213
- reasoning: result.reasoning
214
- });
215
- }
216
- return events;
217
- }
218
- }
219
- function buildRatingsFromLlm(ratings, retrievals) {
220
- const allowed = new Set(retrievals.map((r) => r.id));
221
- const events = [];
222
- for (const r of ratings) {
223
- if (!allowed.has(r.id))
224
- continue;
225
- let cleanedReferencesSource;
226
- if (r.referencesSource !== undefined) {
227
- const cleaned = sanitizeReferencesSource(r.referencesSource);
228
- if (cleaned !== null) {
229
- cleanedReferencesSource = cleaned;
230
- }
231
- }
232
- events.push({
233
- memoryId: r.id,
234
- signal: 2 * r.score - 1,
235
- weight: LLM_RATER_WEIGHT,
236
- source: "llm",
237
- reasoning: r.reasoning,
238
- ...cleanedReferencesSource !== undefined ? { referencesSource: cleanedReferencesSource } : {}
239
- });
240
- }
241
- return events;
242
- }
243
- var RETRIEVAL_PROMPT_CONTENT_CAP = 600;
244
- function buildSummaryWithRatingsPrompt(basePrompt, retrievals) {
245
- if (retrievals.length === 0)
246
- return basePrompt;
247
- const memoryBlock = retrievals.map((m, i) => {
248
- const content = m.content.length > RETRIEVAL_PROMPT_CONTENT_CAP ? `${m.content.slice(0, RETRIEVAL_PROMPT_CONTENT_CAP)}…` : m.content;
249
- return `Memory #${i + 1}
250
- id: ${m.id}
251
- name: ${m.name}
252
- content: ${content}`;
253
- }).join(`
254
-
255
- `);
256
- return `${basePrompt}
257
-
258
- CRITICAL: Your entire response MUST be a single JSON object that conforms to the schema below. Do NOT wrap it in triple-backtick fences (no \`\`\`json or \`\`\`), do NOT add a prose preamble, do NOT add trailing commentary. Just the JSON object, nothing else.
259
-
260
- Schema:
261
- {
262
- "summary": string, // your existing summary text
263
- "ratings": [ // one entry per memory you can score
264
- {
265
- "id": string, // memory id, copied from the list below
266
- "score": number, // 0 = misleading/unhelpful, 1 = highly useful
267
- "reasoning": string, // 1..500 chars, why
268
- "referencesSource": string // OPTIONAL — see note below
269
- }
270
- ]
271
- }
272
-
273
- Score ONLY memories present in the list below. Use the exact ids. Omit any you cannot evaluate.
274
-
275
- Optionally for each rating, if the memory clearly references a specific external source (a GitHub PR/issue, a Linear issue, a customer, a Slack thread, an AgentMail thread, etc.), include a \`referencesSource\` string using the convention "<source>:<identifier>" (e.g. "github:owner/repo#N", "linear:KEY-N", "customer:<slug>"). Any prefix is fine — pick what matches the source. Omit the field if no clear external source.
276
-
277
- Memories retrieved during this session:
278
-
279
- ${memoryBlock}`;
280
- }
281
- function isLlmRaterEnabled() {
282
- return getMemoryRaterNames().includes("llm");
283
- }
284
- function dedupeRetrievalsForRater(rows) {
285
- const seenSchedules = new Set;
286
- const out = [];
287
- for (const row of rows) {
288
- const scheduleId = row.scheduleId;
289
- if (typeof scheduleId === "string" && scheduleId.length > 0) {
290
- if (seenSchedules.has(scheduleId))
291
- continue;
292
- seenSchedules.add(scheduleId);
293
- }
294
- out.push(row);
295
- }
296
- return out;
297
- }
298
- async function fetchRetrievalsForTask(opts) {
299
- const fetchFn = opts.fetchImpl ?? fetch;
300
- try {
301
- const url = `${opts.apiUrl}/api/memory/retrievals?taskId=${encodeURIComponent(opts.taskId)}`;
302
- const res = await fetchFn(url, {
303
- headers: {
304
- "X-Agent-ID": opts.agentId,
305
- ...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {}
306
- }
307
- });
308
- if (!res.ok) {
309
- console.error(`[memory-rater:llm] GET /api/memory/retrievals failed: ${res.status} ${res.statusText}`);
310
- return [];
311
- }
312
- const body = await res.json();
313
- return body.results ?? [];
314
- } catch (err) {
315
- console.error("[memory-rater:llm] fetchRetrievalsForTask threw:", err.message);
316
- return [];
317
- }
318
- }
319
- async function postRatings(opts) {
320
- if (opts.events.length === 0)
321
- return { ok: true, status: 0 };
322
- const fetchFn = opts.fetchImpl ?? fetch;
323
- const events = opts.events.map((e) => ({
324
- memoryId: e.memoryId,
325
- signal: e.signal,
326
- weight: e.weight,
327
- source: e.source,
328
- ...e.reasoning !== undefined ? { reasoning: e.reasoning } : {},
329
- ...e.referencesSource !== undefined ? { referencesSource: e.referencesSource } : {},
330
- ...opts.taskId ? { taskId: opts.taskId } : {}
331
- }));
332
- try {
333
- const res = await fetchFn(`${opts.apiUrl}/api/memory/rate`, {
334
- method: "POST",
335
- headers: {
336
- "Content-Type": "application/json",
337
- "X-Agent-ID": opts.agentId,
338
- ...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {}
339
- },
340
- body: JSON.stringify({ events })
341
- });
342
- if (!res.ok) {
343
- const text = await res.text().catch(() => "");
344
- console.error(`[memory-rater:llm] POST /api/memory/rate failed: ${res.status} ${res.statusText} ${text.slice(0, 200)}`);
345
- }
346
- return { ok: res.ok, status: res.status };
347
- } catch (err) {
348
- console.error("[memory-rater:llm] postRatings threw:", err.message);
349
- return { ok: false, status: 0 };
350
- }
351
- }
352
-
353
28
  // src/utils/internal-ai/models.ts
354
29
  var DEFAULT_MODEL = {
355
30
  openrouter: "openrouter/deepseek/deepseek-v4.1-flash",
@@ -368,105 +43,135 @@ function parseModelStr(modelStr) {
368
43
  return [modelStr.slice(0, idx), modelStr.slice(idx + 1)];
369
44
  }
370
45
 
371
- // node_modules/@earendil-works/pi-ai/dist/auth/oauth/oauth-page.js
372
- var LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" aria-hidden="true"><path fill="#fff" fill-rule="evenodd" d="M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z M282.65 282.65 V400 H400 V282.65 Z"/><path fill="#fff" d="M517.36 400 H634.72 V634.72 H517.36 Z"/></svg>`;
373
- function escapeHtml(value) {
374
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
375
- }
376
- function renderPage(options) {
377
- const title = escapeHtml(options.title);
378
- const heading = escapeHtml(options.heading);
379
- const message = escapeHtml(options.message);
380
- const details = options.details ? escapeHtml(options.details) : undefined;
381
- return `<!doctype html>
382
- <html lang="en">
383
- <head>
384
- <meta charset="utf-8" />
385
- <meta name="viewport" content="width=device-width, initial-scale=1" />
386
- <title>${title}</title>
387
- <style>
388
- :root {
389
- --text: #fafafa;
390
- --text-dim: #a1a1aa;
391
- --page-bg: #09090b;
392
- --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
393
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
394
- }
395
- * { box-sizing: border-box; }
396
- html { color-scheme: dark; }
397
- body {
398
- margin: 0;
399
- min-height: 100vh;
400
- display: flex;
401
- align-items: center;
402
- justify-content: center;
403
- padding: 24px;
404
- background: var(--page-bg);
405
- color: var(--text);
406
- font-family: var(--font-sans);
407
- text-align: center;
408
- }
409
- main {
410
- width: 100%;
411
- max-width: 560px;
412
- display: flex;
413
- flex-direction: column;
414
- align-items: center;
415
- justify-content: center;
416
- }
417
- .logo {
418
- width: 72px;
419
- height: 72px;
420
- display: block;
421
- margin-bottom: 24px;
422
- }
423
- h1 {
424
- margin: 0 0 10px;
425
- font-size: 28px;
426
- line-height: 1.15;
427
- font-weight: 650;
428
- color: var(--text);
429
- }
430
- p {
431
- margin: 0;
432
- line-height: 1.7;
433
- color: var(--text-dim);
434
- font-size: 15px;
435
- }
436
- .details {
437
- margin-top: 16px;
438
- font-family: var(--font-mono);
439
- font-size: 13px;
440
- color: var(--text-dim);
441
- white-space: pre-wrap;
442
- word-break: break-word;
443
- }
444
- </style>
445
- </head>
446
- <body>
447
- <main>
448
- <div class="logo">${LOGO_SVG}</div>
449
- <h1>${heading}</h1>
450
- <p>${message}</p>
451
- ${details ? `<div class="details">${details}</div>` : ""}
452
- </main>
453
- </body>
454
- </html>`;
455
- }
456
- function oauthSuccessHtml(message) {
457
- return renderPage({
458
- title: "Authentication successful",
459
- heading: "Authentication successful",
460
- message
46
+ // node_modules/@earendil-works/pi-ai/dist/auth/oauth/callback-server.js
47
+ import { createServer } from "node:http";
48
+ function sendPage(response, status, html) {
49
+ response.writeHead(status, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
50
+ response.end(html);
51
+ }
52
+ async function startOAuthCallbackServer(options) {
53
+ const { providerName, signal } = options;
54
+ if (signal?.aborted)
55
+ throw new Error("Login cancelled");
56
+ let resolveWait = () => {};
57
+ let rejectWait = () => {};
58
+ const waitPromise = new Promise((resolve, reject) => {
59
+ resolveWait = resolve;
60
+ rejectWait = reject;
61
+ });
62
+ waitPromise.catch(() => {
63
+ return;
64
+ });
65
+ let claimed = false;
66
+ let settled = false;
67
+ let timer;
68
+ const onAbort = () => finish({ error: new Error("Login cancelled") });
69
+ const finish = (result) => {
70
+ if (settled)
71
+ return;
72
+ settled = true;
73
+ if (timer)
74
+ clearTimeout(timer);
75
+ signal?.removeEventListener("abort", onAbort);
76
+ if ("error" in result)
77
+ rejectWait(result.error);
78
+ else
79
+ resolveWait(result.value);
80
+ };
81
+ const server = createServer((request, response) => {
82
+ (async () => {
83
+ const url = new URL(request.url ?? "/", "http://localhost");
84
+ if (request.method !== "GET" || url.pathname !== options.path) {
85
+ sendPage(response, 404, oauthErrorHtml("Callback route not found."));
86
+ return;
87
+ }
88
+ if (options.state !== undefined && url.searchParams.get("state") !== options.state) {
89
+ sendPage(response, 400, oauthErrorHtml("State mismatch."));
90
+ return;
91
+ }
92
+ if (claimed || settled) {
93
+ sendPage(response, 409, oauthErrorHtml("This sign-in has already been handled."));
94
+ return;
95
+ }
96
+ const error = url.searchParams.get("error");
97
+ if (error) {
98
+ const description = url.searchParams.get("error_description") ?? error;
99
+ sendPage(response, 400, oauthErrorHtml(`${providerName} authorization failed.`, description));
100
+ finish({ error: new Error(`${providerName} authorization failed: ${description}`) });
101
+ return;
102
+ }
103
+ const code = url.searchParams.get("code");
104
+ if (!code) {
105
+ sendPage(response, 400, oauthErrorHtml("Missing authorization code."));
106
+ return;
107
+ }
108
+ claimed = true;
109
+ try {
110
+ const value = await options.complete(code);
111
+ sendPage(response, 200, oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`));
112
+ finish({ value });
113
+ } catch (error2) {
114
+ const failure = error2 instanceof Error ? error2 : new Error(String(error2));
115
+ sendPage(response, 502, oauthErrorHtml(`${providerName} sign-in failed.`, failure.message));
116
+ finish({ error: failure });
117
+ }
118
+ })();
119
+ });
120
+ await new Promise((resolve, reject) => {
121
+ server.once("error", reject);
122
+ server.listen(options.port, options.host, () => {
123
+ server.off("error", reject);
124
+ resolve();
125
+ });
461
126
  });
127
+ const address = server.address();
128
+ if (!address || typeof address === "string") {
129
+ server.close();
130
+ throw new Error("OAuth callback server did not bind to TCP");
131
+ }
132
+ server.on("error", (error) => finish({ error }));
133
+ signal?.addEventListener("abort", onAbort, { once: true });
134
+ if (options.timeoutMs !== undefined) {
135
+ timer = setTimeout(() => finish({ error: new Error(`${providerName} sign-in timed out`) }), options.timeoutMs);
136
+ }
137
+ const redirectHost = options.redirectHost ?? options.host;
138
+ return {
139
+ redirectUri: `http://${redirectHost.includes(":") ? `[${redirectHost}]` : redirectHost}:${address.port}${options.path}`,
140
+ wait: () => waitPromise,
141
+ cancel: () => {
142
+ if (!claimed)
143
+ finish({ value: undefined });
144
+ },
145
+ close: () => {
146
+ finish({ error: new Error("OAuth callback server closed") });
147
+ server.close();
148
+ }
149
+ };
462
150
  }
463
- function oauthErrorHtml(message, details) {
464
- return renderPage({
465
- title: "Authentication failed",
466
- heading: "Authentication failed",
467
- message,
468
- details
151
+ async function waitForCallbackOrManualInput(interaction, callback, prompt) {
152
+ const manualAbort = new AbortController;
153
+ let manualError;
154
+ const manual = interaction.prompt({ type: "manual_code", ...prompt, signal: manualAbort.signal }).then((input) => {
155
+ callback?.cancel();
156
+ return input;
157
+ }).catch((error) => {
158
+ manualError = error instanceof Error ? error : new Error(String(error));
159
+ callback?.cancel();
160
+ return;
469
161
  });
162
+ try {
163
+ const value = await callback?.wait();
164
+ if (manualError)
165
+ throw manualError;
166
+ if (value !== undefined)
167
+ return { type: "callback", value };
168
+ const input = await manual;
169
+ if (manualError)
170
+ throw manualError;
171
+ return { type: "manual", input: input ?? "" };
172
+ } finally {
173
+ manualAbort.abort();
174
+ }
470
175
  }
471
176
 
472
177
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/pkce.js
@@ -489,8 +194,6 @@ async function generatePKCE() {
489
194
  }
490
195
 
491
196
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/anthropic.js
492
- var nodeApis = null;
493
- var nodeApisPromise = null;
494
197
  var decode = (s) => atob(s);
495
198
  var CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
496
199
  var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
@@ -500,20 +203,6 @@ var CALLBACK_PORT = 53692;
500
203
  var CALLBACK_PATH = "/callback";
501
204
  var REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
502
205
  var SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
503
- async function getNodeApis() {
504
- if (nodeApis)
505
- return nodeApis;
506
- if (!nodeApisPromise) {
507
- if (typeof process === "undefined" || !process.versions?.node && !process.versions?.bun) {
508
- throw new Error("Anthropic OAuth is only available in Node.js environments");
509
- }
510
- nodeApisPromise = import("node:http").then((httpModule) => ({
511
- createServer: httpModule.createServer
512
- }));
513
- }
514
- nodeApis = await nodeApisPromise;
515
- return nodeApis;
516
- }
517
206
  function parseAuthorizationInput(input) {
518
207
  const value = input.trim();
519
208
  if (!value)
@@ -556,68 +245,6 @@ function formatErrorDetails(error) {
556
245
  }
557
246
  return String(error);
558
247
  }
559
- async function startCallbackServer(expectedState) {
560
- const { createServer } = await getNodeApis();
561
- return new Promise((resolve, reject) => {
562
- let settleWait;
563
- const waitForCodePromise = new Promise((resolveWait) => {
564
- let settled = false;
565
- settleWait = (value) => {
566
- if (settled)
567
- return;
568
- settled = true;
569
- resolveWait(value);
570
- };
571
- });
572
- const server = createServer((req, res) => {
573
- try {
574
- const url = new URL(req.url || "", "http://localhost");
575
- if (url.pathname !== CALLBACK_PATH) {
576
- res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
577
- res.end(oauthErrorHtml("Callback route not found."));
578
- return;
579
- }
580
- const code = url.searchParams.get("code");
581
- const state = url.searchParams.get("state");
582
- const error = url.searchParams.get("error");
583
- if (error) {
584
- res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
585
- res.end(oauthErrorHtml("Anthropic authentication did not complete.", `Error: ${error}`));
586
- return;
587
- }
588
- if (!code || !state) {
589
- res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
590
- res.end(oauthErrorHtml("Missing code or state parameter."));
591
- return;
592
- }
593
- if (state !== expectedState) {
594
- res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
595
- res.end(oauthErrorHtml("State mismatch."));
596
- return;
597
- }
598
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
599
- res.end(oauthSuccessHtml("Anthropic authentication completed. You can close this window."));
600
- settleWait?.({ code, state });
601
- } catch {
602
- res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
603
- res.end("Internal error");
604
- }
605
- });
606
- server.on("error", (err) => {
607
- reject(err);
608
- });
609
- server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
610
- resolve({
611
- server,
612
- redirectUri: REDIRECT_URI,
613
- cancelWait: () => {
614
- settleWait?.(null);
615
- },
616
- waitForCode: () => waitForCodePromise
617
- });
618
- });
619
- });
620
- }
621
248
  async function postJson(url, body, signal) {
622
249
  const response = await fetch(url, {
623
250
  method: "POST",
@@ -658,21 +285,22 @@ async function exchangeAuthorizationCode(code, state, verifier, redirectUri, sig
658
285
  type: "oauth",
659
286
  refresh: tokenData.refresh_token,
660
287
  access: tokenData.access_token,
661
- expires: Date.now() + tokenData.expires_in * 1000 - 300000
288
+ expires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000
662
289
  };
663
290
  }
664
291
  async function loginAnthropic(interaction) {
665
292
  const { verifier, challenge } = await generatePKCE();
666
- const server = await startCallbackServer(verifier);
667
- const manualAbort = new AbortController;
668
- const onAbort = () => server.cancelWait();
669
- interaction.signal.addEventListener("abort", onAbort, { once: true });
670
- if (interaction.signal.aborted)
671
- onAbort();
672
- let code;
673
- let state;
674
- let manualInput;
675
- let manualError;
293
+ const callback = await startOAuthCallbackServer({
294
+ providerName: "Anthropic",
295
+ host: CALLBACK_HOST,
296
+ port: CALLBACK_PORT,
297
+ path: CALLBACK_PATH,
298
+ state: verifier,
299
+ complete: async (code) => code,
300
+ signal: interaction.signal
301
+ }).catch(() => {
302
+ return;
303
+ });
676
304
  try {
677
305
  const authParams = new URLSearchParams({
678
306
  code: "true",
@@ -689,53 +317,27 @@ async function loginAnthropic(interaction) {
689
317
  url: `${AUTHORIZE_URL}?${authParams.toString()}`,
690
318
  instructions: "Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."
691
319
  });
692
- const manualPromise = interaction.prompt({
693
- type: "manual_code",
320
+ const result = await waitForCallbackOrManualInput(interaction, callback, {
694
321
  message: "Complete login in your browser, or paste the authorization code / redirect URL here:",
695
- placeholder: REDIRECT_URI,
696
- signal: manualAbort.signal
697
- }).then((input) => {
698
- manualInput = input;
699
- server.cancelWait();
700
- }).catch((error) => {
701
- manualError = error instanceof Error ? error : new Error(String(error));
702
- server.cancelWait();
322
+ placeholder: REDIRECT_URI
703
323
  });
704
- const result = await server.waitForCode();
705
- if (manualError)
706
- throw manualError;
707
- if (result?.code) {
708
- code = result.code;
709
- state = result.state;
710
- } else if (manualInput) {
711
- const parsed = parseAuthorizationInput(manualInput);
324
+ let code;
325
+ let state = verifier;
326
+ if (result.type === "callback") {
327
+ code = result.value;
328
+ } else {
329
+ const parsed = parseAuthorizationInput(result.input);
712
330
  if (parsed.state && parsed.state !== verifier)
713
331
  throw new Error("OAuth state mismatch");
714
332
  code = parsed.code;
715
333
  state = parsed.state ?? verifier;
716
334
  }
717
- if (!code) {
718
- await manualPromise;
719
- if (manualError)
720
- throw manualError;
721
- if (manualInput) {
722
- const parsed = parseAuthorizationInput(manualInput);
723
- if (parsed.state && parsed.state !== verifier)
724
- throw new Error("OAuth state mismatch");
725
- code = parsed.code;
726
- state = parsed.state ?? verifier;
727
- }
728
- }
729
335
  if (!code)
730
336
  throw new Error("Missing authorization code");
731
- if (!state)
732
- throw new Error("Missing OAuth state");
733
337
  interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
734
- return exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
338
+ return await exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
735
339
  } finally {
736
- interaction.signal.removeEventListener("abort", onAbort);
737
- manualAbort.abort();
738
- server.server.close();
340
+ callback?.close();
739
341
  }
740
342
  }
741
343
  async function refreshAnthropicToken(refreshToken, signal) {
@@ -759,7 +361,7 @@ async function refreshAnthropicToken(refreshToken, signal) {
759
361
  type: "oauth",
760
362
  refresh: data.refresh_token,
761
363
  access: data.access_token,
762
- expires: Date.now() + data.expires_in * 1000 - 300000
364
+ expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000
763
365
  };
764
366
  }
765
367
  var anthropicOAuth = {
@@ -1577,22 +1179,258 @@ var metaOAuth = {
1577
1179
  }
1578
1180
  };
1579
1181
 
1182
+ // node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-chatgpt.js
1183
+ import { randomBytes } from "node:crypto";
1184
+ import { createServer as createServer2 } from "node:http";
1185
+ var DYNAMIC_CLIENT_ID = "dynamic_agent_client";
1186
+ var AGENT_NAME_HINT = "Pi";
1187
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1188
+ var AUTHORIZE_URL2 = "https://auth.openai.com/api/accounts/authorize";
1189
+ var TOKEN_URL2 = "https://auth.openai.com/api/accounts/oauth/token";
1190
+ var RESOURCE = "https://api.openai.com/v1";
1191
+ var CALLBACK_HOST2 = getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
1192
+ var CALLBACK_PORT2 = 1455;
1193
+ var CALLBACK_PATH2 = "/auth/callback";
1194
+ var REDIRECT_URI2 = `http://127.0.0.1:${CALLBACK_PORT2}${CALLBACK_PATH2}`;
1195
+ var DIRECT_TOKEN_SCOPE = "chatgpt.tokens.use.direct";
1196
+ var SCOPE = `openid profile email offline_access resource.invoke ${DIRECT_TOKEN_SCOPE}`;
1197
+ var EXPIRY_MARGIN_MS = 3 * 60 * 1000;
1198
+ function randomValue() {
1199
+ return randomBytes(32).toString("base64url");
1200
+ }
1201
+ function authorizationResultFromCallback(url, expectedState) {
1202
+ const code = url.searchParams.get("code");
1203
+ if (!code)
1204
+ throw new Error("Missing authorization code");
1205
+ const state = url.searchParams.get("state");
1206
+ if (!state)
1207
+ throw new Error("Missing OAuth state");
1208
+ if (state !== expectedState)
1209
+ throw new Error("OAuth state mismatch");
1210
+ const clientId = url.searchParams.get("client_id")?.trim();
1211
+ if (!clientId)
1212
+ throw new Error("OpenAI OAuth registration callback did not contain an issued client ID");
1213
+ return { code, clientId };
1214
+ }
1215
+ function authorizationResultFromManualInput(input, expectedState) {
1216
+ let url;
1217
+ try {
1218
+ url = new URL(input.trim());
1219
+ } catch {
1220
+ throw new Error("Paste the full callback URL from the browser");
1221
+ }
1222
+ const expected = new URL(REDIRECT_URI2);
1223
+ if (url.origin !== expected.origin || url.pathname !== expected.pathname) {
1224
+ throw new Error(`The pasted callback URL must start with ${REDIRECT_URI2}`);
1225
+ }
1226
+ const error = url.searchParams.get("error");
1227
+ if (error)
1228
+ throw new Error(`ChatGPT authorization failed: ${error}`);
1229
+ return authorizationResultFromCallback(url, expectedState);
1230
+ }
1231
+ function sendHtml(response, status, body) {
1232
+ response.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
1233
+ response.end(body);
1234
+ }
1235
+ function startCallbackServer(expectedState) {
1236
+ return new Promise((resolve, reject) => {
1237
+ let resolveResult;
1238
+ let rejectResult;
1239
+ const result = new Promise((resolveAuthorization, rejectAuthorization) => {
1240
+ resolveResult = resolveAuthorization;
1241
+ rejectResult = rejectAuthorization;
1242
+ });
1243
+ const server = createServer2((request, response) => {
1244
+ try {
1245
+ const url = new URL(request.url || "", REDIRECT_URI2);
1246
+ if (url.pathname !== CALLBACK_PATH2) {
1247
+ sendHtml(response, 404, oauthErrorHtml("Callback route not found."));
1248
+ return;
1249
+ }
1250
+ const error = url.searchParams.get("error");
1251
+ if (error) {
1252
+ sendHtml(response, 400, oauthErrorHtml("ChatGPT was not connected.", `Error: ${error}`));
1253
+ rejectResult(new Error(`ChatGPT authorization failed: ${error}`));
1254
+ return;
1255
+ }
1256
+ let authorizationResult;
1257
+ try {
1258
+ authorizationResult = authorizationResultFromCallback(url, expectedState);
1259
+ } catch (error2) {
1260
+ const message = error2 instanceof Error ? error2.message : "Invalid callback";
1261
+ sendHtml(response, 400, oauthErrorHtml(message));
1262
+ return;
1263
+ }
1264
+ sendHtml(response, 200, oauthSuccessHtml("ChatGPT authentication completed. You can close this window."));
1265
+ resolveResult(authorizationResult);
1266
+ } catch {
1267
+ sendHtml(response, 500, oauthErrorHtml("Internal error while processing the callback."));
1268
+ }
1269
+ });
1270
+ server.once("error", reject);
1271
+ server.listen(CALLBACK_PORT2, CALLBACK_HOST2, () => {
1272
+ server.removeListener("error", reject);
1273
+ server.on("error", rejectResult);
1274
+ resolve({ server, result });
1275
+ });
1276
+ });
1277
+ }
1278
+ async function requestToken(body, signal) {
1279
+ const response = await fetch(TOKEN_URL2, {
1280
+ method: "POST",
1281
+ headers: {
1282
+ accept: "application/json",
1283
+ "content-type": "application/x-www-form-urlencoded"
1284
+ },
1285
+ body,
1286
+ signal
1287
+ });
1288
+ if (!response.ok) {
1289
+ const responseBody = await response.text().catch(() => "");
1290
+ throw new Error(`OpenAI OAuth token request failed (${response.status}): ${responseBody || response.statusText}`);
1291
+ }
1292
+ const data = await response.json();
1293
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
1294
+ throw new Error("OpenAI OAuth token response must be an object");
1295
+ }
1296
+ return data;
1297
+ }
1298
+ function requireTokenString(value, field) {
1299
+ if (typeof value !== "string" || value.trim().length === 0) {
1300
+ throw new Error(`OpenAI OAuth token response has invalid ${field}`);
1301
+ }
1302
+ return value;
1303
+ }
1304
+ function credentialFromTokenResponse(token, clientId) {
1305
+ const access = requireTokenString(token.access_token, "access_token");
1306
+ const refresh = requireTokenString(token.refresh_token, "refresh_token");
1307
+ const scope = requireTokenString(token.scope, "scope");
1308
+ if (typeof token.expires_in !== "number" || !Number.isFinite(token.expires_in) || token.expires_in <= 0) {
1309
+ throw new Error("OpenAI OAuth token response has invalid expires_in");
1310
+ }
1311
+ const scopes = scope.trim().split(/\s+/).filter(Boolean);
1312
+ if (!scopes.includes(DIRECT_TOKEN_SCOPE)) {
1313
+ throw new Error(`OpenAI OAuth grant did not include ${DIRECT_TOKEN_SCOPE}`);
1314
+ }
1315
+ return {
1316
+ type: "oauth",
1317
+ access,
1318
+ refresh,
1319
+ expires: Date.now() + token.expires_in * 1000 - EXPIRY_MARGIN_MS,
1320
+ clientId,
1321
+ scopes
1322
+ };
1323
+ }
1324
+ async function exchangeAuthorizationCode2(code, verifier, clientId, signal) {
1325
+ const token = await requestToken(new URLSearchParams({
1326
+ grant_type: "authorization_code",
1327
+ client_id: clientId,
1328
+ code,
1329
+ code_verifier: verifier,
1330
+ redirect_uri: REDIRECT_URI2,
1331
+ resource: RESOURCE
1332
+ }), signal);
1333
+ if (typeof token.id_token !== "string" || token.id_token.trim().length === 0) {
1334
+ throw new Error("OpenAI OAuth token response did not contain an ID token");
1335
+ }
1336
+ return credentialFromTokenResponse(token, clientId);
1337
+ }
1338
+ async function refreshAccessToken(credential, signal) {
1339
+ const clientId = credential.clientId;
1340
+ if (typeof clientId !== "string" || clientId.trim().length === 0) {
1341
+ throw new Error("Stored OpenAI OAuth credential does not contain an issued client ID; reconnect ChatGPT");
1342
+ }
1343
+ const token = await requestToken(new URLSearchParams({
1344
+ grant_type: "refresh_token",
1345
+ client_id: clientId,
1346
+ refresh_token: credential.refresh,
1347
+ resource: RESOURCE
1348
+ }), signal);
1349
+ return credentialFromTokenResponse(token, clientId);
1350
+ }
1351
+ function agentHostId(deviceId) {
1352
+ if (!deviceId || !UUID_PATTERN.test(deviceId)) {
1353
+ throw new Error("Sign in with ChatGPT requires a device ID (UUID) for this installation");
1354
+ }
1355
+ return `urn:uuid:${deviceId.toLowerCase()}`;
1356
+ }
1357
+ async function loginOpenAIChatGPT(interaction, options) {
1358
+ const hostId = agentHostId(options?.getDeviceId?.());
1359
+ const { verifier, challenge } = await generatePKCE();
1360
+ const state = randomValue();
1361
+ const nonce = randomValue();
1362
+ let callback;
1363
+ try {
1364
+ callback = await startCallbackServer(state);
1365
+ } catch (error) {
1366
+ interaction.notify({
1367
+ type: "info",
1368
+ message: `Could not listen on ${REDIRECT_URI2}; paste the final redirect URL to continue. ${error instanceof Error ? error.message : String(error)}`
1369
+ });
1370
+ }
1371
+ const authorizationUrl = new URL(AUTHORIZE_URL2);
1372
+ authorizationUrl.search = new URLSearchParams({
1373
+ client_id: DYNAMIC_CLIENT_ID,
1374
+ agent_name_hint: AGENT_NAME_HINT,
1375
+ ext_agent_host_id: hostId,
1376
+ response_type: "code",
1377
+ redirect_uri: REDIRECT_URI2,
1378
+ resource: RESOURCE,
1379
+ scope: SCOPE,
1380
+ state,
1381
+ code_challenge: challenge,
1382
+ code_challenge_method: "S256",
1383
+ nonce
1384
+ }).toString();
1385
+ interaction.notify({
1386
+ type: "auth_url",
1387
+ url: authorizationUrl.toString(),
1388
+ instructions: "Complete sign-in in your browser. If the callback does not complete, paste the final redirect URL here."
1389
+ });
1390
+ const manualAbort = new AbortController;
1391
+ const manualCode = interaction.prompt({
1392
+ type: "manual_code",
1393
+ message: "Complete login in your browser, or paste the final redirect URL here:",
1394
+ placeholder: REDIRECT_URI2,
1395
+ signal: AbortSignal.any([manualAbort.signal, interaction.signal])
1396
+ }).then((input) => authorizationResultFromManualInput(input, state));
1397
+ try {
1398
+ const result = await (callback ? Promise.race([callback.result, manualCode]) : manualCode);
1399
+ interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
1400
+ return await exchangeAuthorizationCode2(result.code, verifier, result.clientId, interaction.signal);
1401
+ } catch (error) {
1402
+ if (interaction.signal.aborted)
1403
+ throw new Error("Login cancelled");
1404
+ throw error;
1405
+ } finally {
1406
+ manualAbort.abort();
1407
+ callback?.server.close();
1408
+ callback?.server.closeAllConnections();
1409
+ }
1410
+ }
1411
+ var openaiChatGPTOAuth = {
1412
+ name: "OpenAI (ChatGPT subscription)",
1413
+ isSubscription: true,
1414
+ loginLabel: "Sign in with ChatGPT",
1415
+ login: loginOpenAIChatGPT,
1416
+ refresh: refreshAccessToken,
1417
+ async toAuth(credential) {
1418
+ return { apiKey: credential.access };
1419
+ }
1420
+ };
1421
+
1580
1422
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js
1581
1423
  var _randomBytes = null;
1582
- var _http = null;
1583
1424
  if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
1584
1425
  import("node:crypto").then((m) => {
1585
1426
  _randomBytes = m.randomBytes;
1586
1427
  });
1587
- import("node:http").then((m) => {
1588
- _http = m;
1589
- });
1590
1428
  }
1591
1429
  var CLIENT_ID5 = "app_EMoamEEZ73f0CkXaXp7hrann";
1592
1430
  var AUTH_BASE_URL = "https://auth.openai.com";
1593
- var AUTHORIZE_URL2 = `${AUTH_BASE_URL}/oauth/authorize`;
1594
- var TOKEN_URL2 = `${AUTH_BASE_URL}/oauth/token`;
1595
- var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
1431
+ var AUTHORIZE_URL3 = `${AUTH_BASE_URL}/oauth/authorize`;
1432
+ var TOKEN_URL3 = `${AUTH_BASE_URL}/oauth/token`;
1433
+ var REDIRECT_URI3 = "http://localhost:1455/auth/callback";
1596
1434
  var DEVICE_USER_CODE_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/usercode`;
1597
1435
  var DEVICE_TOKEN_URL2 = `${AUTH_BASE_URL}/api/accounts/deviceauth/token`;
1598
1436
  var DEVICE_VERIFICATION_URI = `${AUTH_BASE_URL}/codex/device`;
@@ -1600,7 +1438,7 @@ var DEVICE_REDIRECT_URI = `${AUTH_BASE_URL}/deviceauth/callback`;
1600
1438
  var DEVICE_CODE_TIMEOUT_SECONDS2 = 900;
1601
1439
  var OPENAI_CODEX_BROWSER_LOGIN_METHOD = "browser";
1602
1440
  var OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD = "device_code";
1603
- var SCOPE = "openid profile email offline_access";
1441
+ var SCOPE2 = "openid profile email offline_access";
1604
1442
  var JWT_CLAIM_PATH = "https://api.openai.com/auth";
1605
1443
  function getCallbackHost() {
1606
1444
  return getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
@@ -1673,8 +1511,8 @@ async function readTokenResponse(response, operation) {
1673
1511
  expires: Date.now() + json.expires_in * 1000
1674
1512
  };
1675
1513
  }
1676
- async function exchangeAuthorizationCode2(code, verifier, redirectUri, signal) {
1677
- const response = await fetchWithLoginCancellation(TOKEN_URL2, {
1514
+ async function exchangeAuthorizationCode3(code, verifier, redirectUri, signal) {
1515
+ const response = await fetchWithLoginCancellation(TOKEN_URL3, {
1678
1516
  method: "POST",
1679
1517
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
1680
1518
  body: new URLSearchParams({
@@ -1688,10 +1526,10 @@ async function exchangeAuthorizationCode2(code, verifier, redirectUri, signal) {
1688
1526
  });
1689
1527
  return readTokenResponse(response, "exchange");
1690
1528
  }
1691
- async function refreshAccessToken(refreshToken2, signal) {
1529
+ async function refreshAccessToken2(refreshToken2, signal) {
1692
1530
  let response;
1693
1531
  try {
1694
- response = await fetch(TOKEN_URL2, {
1532
+ response = await fetch(TOKEN_URL3, {
1695
1533
  method: "POST",
1696
1534
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
1697
1535
  body: new URLSearchParams({
@@ -1787,11 +1625,11 @@ async function pollOpenAICodexDeviceAuth(device, signal) {
1787
1625
  async function createAuthorizationFlow(originator = "pi") {
1788
1626
  const { verifier, challenge } = await generatePKCE();
1789
1627
  const state = createState();
1790
- const url = new URL(AUTHORIZE_URL2);
1628
+ const url = new URL(AUTHORIZE_URL3);
1791
1629
  url.searchParams.set("response_type", "code");
1792
1630
  url.searchParams.set("client_id", CLIENT_ID5);
1793
- url.searchParams.set("redirect_uri", REDIRECT_URI2);
1794
- url.searchParams.set("scope", SCOPE);
1631
+ url.searchParams.set("redirect_uri", REDIRECT_URI3);
1632
+ url.searchParams.set("scope", SCOPE2);
1795
1633
  url.searchParams.set("code_challenge", challenge);
1796
1634
  url.searchParams.set("code_challenge_method", "S256");
1797
1635
  url.searchParams.set("state", state);
@@ -1800,75 +1638,6 @@ async function createAuthorizationFlow(originator = "pi") {
1800
1638
  url.searchParams.set("originator", originator);
1801
1639
  return { verifier, state, url: url.toString() };
1802
1640
  }
1803
- function startLocalOAuthServer(state) {
1804
- if (!_http) {
1805
- throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
1806
- }
1807
- let settleWait;
1808
- const waitForCodePromise = new Promise((resolve) => {
1809
- let settled = false;
1810
- settleWait = (value) => {
1811
- if (settled)
1812
- return;
1813
- settled = true;
1814
- resolve(value);
1815
- };
1816
- });
1817
- const server = _http.createServer((req, res) => {
1818
- try {
1819
- const url = new URL(req.url || "", "http://localhost");
1820
- if (url.pathname !== "/auth/callback") {
1821
- res.statusCode = 404;
1822
- res.setHeader("Content-Type", "text/html; charset=utf-8");
1823
- res.end(oauthErrorHtml("Callback route not found."));
1824
- return;
1825
- }
1826
- if (url.searchParams.get("state") !== state) {
1827
- res.statusCode = 400;
1828
- res.setHeader("Content-Type", "text/html; charset=utf-8");
1829
- res.end(oauthErrorHtml("State mismatch."));
1830
- return;
1831
- }
1832
- const code = url.searchParams.get("code");
1833
- if (!code) {
1834
- res.statusCode = 400;
1835
- res.setHeader("Content-Type", "text/html; charset=utf-8");
1836
- res.end(oauthErrorHtml("Missing authorization code."));
1837
- return;
1838
- }
1839
- res.statusCode = 200;
1840
- res.setHeader("Content-Type", "text/html; charset=utf-8");
1841
- res.end(oauthSuccessHtml("OpenAI authentication completed. You can close this window."));
1842
- settleWait?.({ code });
1843
- } catch {
1844
- res.statusCode = 500;
1845
- res.setHeader("Content-Type", "text/html; charset=utf-8");
1846
- res.end(oauthErrorHtml("Internal error while processing OAuth callback."));
1847
- }
1848
- });
1849
- return new Promise((resolve) => {
1850
- server.listen(1455, getCallbackHost(), () => {
1851
- resolve({
1852
- close: () => server.close(),
1853
- cancelWait: () => {
1854
- settleWait?.(null);
1855
- },
1856
- waitForCode: () => waitForCodePromise
1857
- });
1858
- }).on("error", (_err) => {
1859
- settleWait?.(null);
1860
- resolve({
1861
- close: () => {
1862
- try {
1863
- server.close();
1864
- } catch {}
1865
- },
1866
- cancelWait: () => {},
1867
- waitForCode: async () => null
1868
- });
1869
- });
1870
- });
1871
- }
1872
1641
  function getAccountId(accessToken) {
1873
1642
  const payload = decodeJwt(accessToken);
1874
1643
  const auth = payload?.[JWT_CLAIM_PATH];
@@ -1889,7 +1658,7 @@ function credentialsFromToken(token) {
1889
1658
  };
1890
1659
  }
1891
1660
  async function exchangeAuthorizationCodeForCredentials(code, verifier, redirectUri, signal) {
1892
- return credentialsFromToken(await exchangeAuthorizationCode2(code, verifier, redirectUri, signal));
1661
+ return credentialsFromToken(await exchangeAuthorizationCode3(code, verifier, redirectUri, signal));
1893
1662
  }
1894
1663
  async function loginOpenAICodexDeviceCode(interaction) {
1895
1664
  const device = await startOpenAICodexDeviceAuth(interaction.signal);
@@ -1905,66 +1674,45 @@ async function loginOpenAICodexDeviceCode(interaction) {
1905
1674
  }
1906
1675
  async function loginOpenAICodex(interaction) {
1907
1676
  const { verifier, state, url } = await createAuthorizationFlow();
1908
- const server = await startLocalOAuthServer(state);
1909
- const manualAbort = new AbortController;
1910
- const onAbort = () => server.cancelWait();
1911
- interaction.signal.addEventListener("abort", onAbort, { once: true });
1912
- if (interaction.signal.aborted)
1913
- onAbort();
1914
- let code;
1915
- let manualCode;
1916
- let manualError;
1677
+ const callback = await startOAuthCallbackServer({
1678
+ providerName: "OpenAI",
1679
+ host: getCallbackHost(),
1680
+ port: 1455,
1681
+ path: "/auth/callback",
1682
+ state,
1683
+ complete: async (code) => code,
1684
+ signal: interaction.signal
1685
+ }).catch(() => {
1686
+ return;
1687
+ });
1917
1688
  interaction.notify({
1918
1689
  type: "auth_url",
1919
1690
  url,
1920
1691
  instructions: "A browser window should open. Complete login to finish."
1921
1692
  });
1922
1693
  try {
1923
- const manualPromise = interaction.prompt({
1924
- type: "manual_code",
1694
+ const result = await waitForCallbackOrManualInput(interaction, callback, {
1925
1695
  message: "Complete login in your browser, or paste the authorization code / redirect URL here:",
1926
- placeholder: REDIRECT_URI2,
1927
- signal: manualAbort.signal
1928
- }).then((input) => {
1929
- manualCode = input;
1930
- server.cancelWait();
1931
- }).catch((error) => {
1932
- manualError = error instanceof Error ? error : new Error(String(error));
1933
- server.cancelWait();
1696
+ placeholder: REDIRECT_URI3
1934
1697
  });
1935
- const result = await server.waitForCode();
1936
- if (manualError)
1937
- throw manualError;
1938
- if (result?.code) {
1939
- code = result.code;
1940
- } else if (manualCode) {
1941
- const parsed = parseAuthorizationInput2(manualCode);
1698
+ let code;
1699
+ if (result.type === "callback") {
1700
+ code = result.value;
1701
+ } else {
1702
+ const parsed = parseAuthorizationInput2(result.input);
1942
1703
  if (parsed.state && parsed.state !== state)
1943
1704
  throw new Error("State mismatch");
1944
1705
  code = parsed.code;
1945
1706
  }
1946
- if (!code) {
1947
- await manualPromise;
1948
- if (manualError)
1949
- throw manualError;
1950
- if (manualCode) {
1951
- const parsed = parseAuthorizationInput2(manualCode);
1952
- if (parsed.state && parsed.state !== state)
1953
- throw new Error("State mismatch");
1954
- code = parsed.code;
1955
- }
1956
- }
1957
1707
  if (!code)
1958
1708
  throw new Error("Missing authorization code");
1959
- return exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI2, interaction.signal);
1709
+ return await exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI3, interaction.signal);
1960
1710
  } finally {
1961
- interaction.signal.removeEventListener("abort", onAbort);
1962
- manualAbort.abort();
1963
- server.close();
1711
+ callback?.close();
1964
1712
  }
1965
1713
  }
1966
1714
  async function refreshOpenAICodexToken(refreshToken2, signal) {
1967
- return credentialsFromToken(await refreshAccessToken(refreshToken2, signal));
1715
+ return credentialsFromToken(await refreshAccessToken2(refreshToken2, signal));
1968
1716
  }
1969
1717
  var openaiCodexOAuth = {
1970
1718
  name: "OpenAI (ChatGPT Plus/Pro)",
@@ -1993,20 +1741,13 @@ var openaiCodexOAuth = {
1993
1741
  };
1994
1742
 
1995
1743
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/openrouter.js
1996
- import { createServer } from "node:http";
1997
- var AUTHORIZE_URL3 = "https://openrouter.ai/auth";
1998
- var TOKEN_URL3 = "https://openrouter.ai/api/v1/auth/keys";
1744
+ var AUTHORIZE_URL4 = "https://openrouter.ai/auth";
1745
+ var TOKEN_URL4 = "https://openrouter.ai/api/v1/auth/keys";
1999
1746
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
2000
1747
  var TOKEN_EXCHANGE_TIMEOUT_MS = 30000;
2001
1748
  function getCallbackHost2() {
2002
1749
  return getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
2003
1750
  }
2004
- function sendHtml(response, status, html) {
2005
- response.statusCode = status;
2006
- response.setHeader("content-type", "text/html; charset=utf-8");
2007
- response.setHeader("cache-control", "no-store");
2008
- response.end(html);
2009
- }
2010
1751
  function parseAuthorizationInput3(input) {
2011
1752
  const value = input.trim();
2012
1753
  if (!value)
@@ -2033,7 +1774,7 @@ function errorDetail2(body) {
2033
1774
  }
2034
1775
  return;
2035
1776
  }
2036
- async function exchangeAuthorizationCode3(code, verifier, signal) {
1777
+ async function exchangeAuthorizationCode4(code, verifier, signal) {
2037
1778
  if (signal.aborted)
2038
1779
  throw new Error("Login cancelled");
2039
1780
  const controller = new AbortController;
@@ -2043,7 +1784,7 @@ async function exchangeAuthorizationCode3(code, verifier, signal) {
2043
1784
  let response;
2044
1785
  let body = {};
2045
1786
  try {
2046
- response = await fetch(TOKEN_URL3, {
1787
+ response = await fetch(TOKEN_URL4, {
2047
1788
  method: "POST",
2048
1789
  headers: { accept: "application/json", "content-type": "application/json" },
2049
1790
  body: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" }),
@@ -2081,153 +1822,45 @@ async function exchangeAuthorizationCode3(code, verifier, signal) {
2081
1822
  expires: Number.MAX_SAFE_INTEGER
2082
1823
  };
2083
1824
  }
2084
- async function startCallbackServer2(callbackPath, verifier, signal) {
2085
- if (signal.aborted)
2086
- throw new Error("Login cancelled");
2087
- const callbackHost = getCallbackHost2();
2088
- let resolveCredential = () => {};
2089
- let rejectCredential = () => {};
2090
- const credential = new Promise((resolve, reject) => {
2091
- resolveCredential = resolve;
2092
- rejectCredential = reject;
2093
- });
2094
- let server;
2095
- let claimed = false;
2096
- let settled = false;
2097
- let timeout;
2098
- let onAbort;
2099
- const close = () => {
2100
- if (timeout)
2101
- clearTimeout(timeout);
2102
- if (onAbort)
2103
- signal.removeEventListener("abort", onAbort);
2104
- server.close();
2105
- };
2106
- const finish = (result) => {
2107
- if (settled)
2108
- return;
2109
- settled = true;
2110
- close();
2111
- if ("credential" in result)
2112
- resolveCredential(result.credential);
2113
- else
2114
- rejectCredential(result.error);
2115
- };
2116
- server = createServer((request, response) => {
2117
- (async () => {
2118
- const requestUrl = new URL(request.url ?? "/", `http://${callbackHost}`);
2119
- if (request.method !== "GET" || requestUrl.pathname !== callbackPath) {
2120
- sendHtml(response, 404, oauthErrorHtml("OAuth callback route not found."));
2121
- return;
2122
- }
2123
- if (claimed || settled) {
2124
- sendHtml(response, 409, oauthErrorHtml("This OAuth callback has already been used."));
2125
- return;
2126
- }
2127
- const oauthError = requestUrl.searchParams.get("error");
2128
- if (oauthError) {
2129
- const description = requestUrl.searchParams.get("error_description") ?? oauthError;
2130
- sendHtml(response, 400, oauthErrorHtml("OpenRouter authorization was denied.", description));
2131
- finish({ error: new Error(`OpenRouter authorization failed: ${description}`) });
2132
- return;
2133
- }
2134
- const code = requestUrl.searchParams.get("code");
2135
- if (!code) {
2136
- sendHtml(response, 400, oauthErrorHtml("OpenRouter returned no authorization code."));
2137
- return;
2138
- }
2139
- claimed = true;
2140
- try {
2141
- const result = await exchangeAuthorizationCode3(code, verifier, signal);
2142
- sendHtml(response, 200, oauthSuccessHtml("Signed in to OpenRouter. You may now close this page."));
2143
- finish({ credential: result });
2144
- } catch (error) {
2145
- const message = error instanceof Error ? error.message : "Unknown token exchange error";
2146
- sendHtml(response, 502, oauthErrorHtml("OpenRouter key exchange failed.", message));
2147
- finish({ error: error instanceof Error ? error : new Error(message) });
2148
- }
2149
- })();
2150
- });
2151
- await new Promise((resolve, reject) => {
2152
- server.once("error", reject);
2153
- server.listen(0, callbackHost, () => {
2154
- server.removeListener("error", reject);
2155
- resolve();
2156
- });
2157
- });
2158
- server.on("error", (error) => finish({ error }));
2159
- onAbort = () => finish({ error: new Error("Login cancelled") });
2160
- signal.addEventListener("abort", onAbort, { once: true });
2161
- if (signal.aborted) {
2162
- close();
2163
- throw new Error("Login cancelled");
2164
- }
2165
- timeout = setTimeout(() => finish({ error: new Error("OpenRouter OAuth login timed out") }), LOGIN_TIMEOUT_MS);
2166
- const address = server.address();
2167
- if (!address || typeof address === "string") {
2168
- close();
2169
- throw new Error("Could not determine the OpenRouter OAuth callback port");
2170
- }
2171
- return {
2172
- callbackUrl: `http://${callbackHost}:${address.port}${callbackPath}`,
2173
- close,
2174
- cancelWait: () => {
2175
- if (!claimed)
2176
- finish({ credential: null });
2177
- },
2178
- waitForCredential: () => credential
2179
- };
2180
- }
2181
1825
  async function loginOpenRouter(interaction) {
2182
1826
  const { verifier, challenge } = await generatePKCE();
2183
- const callbackPath = `/oauth/callback/${crypto.randomUUID()}`;
2184
- const callback = await startCallbackServer2(callbackPath, verifier, interaction.signal);
2185
- const manualAbort = new AbortController;
2186
- let manualInput;
2187
- let manualError;
1827
+ const callback = await startOAuthCallbackServer({
1828
+ providerName: "OpenRouter",
1829
+ host: getCallbackHost2(),
1830
+ port: 0,
1831
+ path: `/oauth/callback/${crypto.randomUUID()}`,
1832
+ complete: (code) => exchangeAuthorizationCode4(code, verifier, interaction.signal),
1833
+ signal: interaction.signal,
1834
+ timeoutMs: LOGIN_TIMEOUT_MS
1835
+ });
2188
1836
  try {
2189
- const authorizeUrl = new URL(AUTHORIZE_URL3);
1837
+ const authorizeUrl = new URL(AUTHORIZE_URL4);
2190
1838
  authorizeUrl.search = new URLSearchParams({
2191
- callback_url: callback.callbackUrl,
1839
+ callback_url: callback.redirectUri,
2192
1840
  code_challenge: challenge,
2193
1841
  code_challenge_method: "S256"
2194
1842
  }).toString();
2195
1843
  interaction.notify({
2196
1844
  type: "progress",
2197
- message: `Listening for OpenRouter OAuth callback on ${callback.callbackUrl}`
1845
+ message: `Listening for OpenRouter OAuth callback on ${callback.redirectUri}`
2198
1846
  });
2199
1847
  interaction.notify({
2200
1848
  type: "auth_url",
2201
1849
  url: authorizeUrl.toString(),
2202
1850
  instructions: "Complete sign-in in your browser. If the browser is on another machine, paste the final redirect URL here."
2203
1851
  });
2204
- const manualPromise = interaction.prompt({
2205
- type: "manual_code",
1852
+ const result = await waitForCallbackOrManualInput(interaction, callback, {
2206
1853
  message: "Complete sign-in in your browser, or paste the authorization code / redirect URL here:",
2207
- placeholder: callback.callbackUrl,
2208
- signal: manualAbort.signal
2209
- }).then((input) => {
2210
- manualInput = input;
2211
- callback.cancelWait();
2212
- }).catch((error) => {
2213
- manualError = error instanceof Error ? error : new Error(String(error));
2214
- callback.cancelWait();
1854
+ placeholder: callback.redirectUri
2215
1855
  });
2216
- const credential = await callback.waitForCredential();
2217
- if (manualError)
2218
- throw manualError;
2219
- if (credential)
2220
- return credential;
2221
- await manualPromise;
2222
- if (manualError)
2223
- throw manualError;
2224
- const code = manualInput ? parseAuthorizationInput3(manualInput) : undefined;
1856
+ if (result.type === "callback")
1857
+ return result.value;
1858
+ const code = parseAuthorizationInput3(result.input);
2225
1859
  if (!code)
2226
1860
  throw new Error("Missing authorization code");
2227
1861
  interaction.notify({ type: "progress", message: "Exchanging authorization code for an API key..." });
2228
- return await exchangeAuthorizationCode3(code, verifier, interaction.signal);
1862
+ return await exchangeAuthorizationCode4(code, verifier, interaction.signal);
2229
1863
  } finally {
2230
- manualAbort.abort();
2231
1864
  callback.close();
2232
1865
  }
2233
1866
  }
@@ -2244,16 +1877,10 @@ var openRouterOAuth = {
2244
1877
  };
2245
1878
 
2246
1879
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js
2247
- var _http2 = null;
2248
- if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
2249
- import("node:http").then((m) => {
2250
- _http2 = m;
2251
- });
2252
- }
2253
- var CALLBACK_HOST2 = "127.0.0.1";
2254
- var CALLBACK_PORT2 = 1456;
2255
- var CALLBACK_PATH2 = "/oauth/callback";
2256
- var REDIRECT_URI3 = `http://${CALLBACK_HOST2}:${CALLBACK_PORT2}${CALLBACK_PATH2}`;
1880
+ var CALLBACK_HOST3 = "127.0.0.1";
1881
+ var CALLBACK_PORT3 = 1456;
1882
+ var CALLBACK_PATH3 = "/oauth/callback";
1883
+ var REDIRECT_URI4 = `http://${CALLBACK_HOST3}:${CALLBACK_PORT3}${CALLBACK_PATH3}`;
2257
1884
  var TOKEN_EXPIRY_SKEW_MS = 60000;
2258
1885
  var LOGIN_METHOD_BROWSER = "browser";
2259
1886
  var LOGIN_METHOD_DEVICE_CODE = "device-code";
@@ -2327,69 +1954,6 @@ async function requestOAuthToken(gateway, body, signal) {
2327
1954
  scope: data.scope
2328
1955
  };
2329
1956
  }
2330
- function startOAuthCallbackServer(expectedState, signal) {
2331
- if (!_http2) {
2332
- throw new Error("Radius OAuth is only available in Node.js environments");
2333
- }
2334
- let settle = () => {};
2335
- let settled = false;
2336
- const wait = new Promise((resolve) => {
2337
- settle = resolve;
2338
- });
2339
- const finish = (code) => {
2340
- if (settled) {
2341
- return;
2342
- }
2343
- settled = true;
2344
- signal.removeEventListener("abort", onAbort);
2345
- settle(code);
2346
- };
2347
- const onAbort = () => finish(null);
2348
- signal.addEventListener("abort", onAbort, { once: true });
2349
- const sendPage = (response, status, html) => {
2350
- response.statusCode = status;
2351
- response.setHeader("content-type", "text/html; charset=utf-8");
2352
- response.end(html);
2353
- };
2354
- const server = _http2.createServer((request, response) => {
2355
- const url = new URL(request.url ?? "/", REDIRECT_URI3);
2356
- if (url.pathname !== CALLBACK_PATH2) {
2357
- sendPage(response, 404, oauthErrorHtml("Callback route not found."));
2358
- return;
2359
- }
2360
- if (url.searchParams.get("state") !== expectedState) {
2361
- sendPage(response, 400, oauthErrorHtml("OAuth state mismatch."));
2362
- return;
2363
- }
2364
- const error = url.searchParams.get("error");
2365
- if (error) {
2366
- sendPage(response, 400, oauthErrorHtml(url.searchParams.get("error_description") ?? error));
2367
- finish(null);
2368
- return;
2369
- }
2370
- const code = url.searchParams.get("code");
2371
- if (!code) {
2372
- sendPage(response, 400, oauthErrorHtml("Missing authorization code."));
2373
- return;
2374
- }
2375
- sendPage(response, 200, oauthSuccessHtml("Signed in to Radius. You may now close this page."));
2376
- finish(code);
2377
- });
2378
- return new Promise((resolve) => {
2379
- server.listen(CALLBACK_PORT2, CALLBACK_HOST2, () => {
2380
- resolve({
2381
- waitForCode: () => wait,
2382
- close: () => {
2383
- finish(null);
2384
- server.close();
2385
- }
2386
- });
2387
- }).once("error", () => {
2388
- finish(null);
2389
- resolve({ waitForCode: async () => null, close: () => {} });
2390
- });
2391
- });
2392
- }
2393
1957
  async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
2394
1958
  const { verifier, challenge } = await generatePKCE();
2395
1959
  const state = crypto.randomUUID();
@@ -2397,37 +1961,41 @@ async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
2397
1961
  authorizeUrl.search = new URLSearchParams({
2398
1962
  response_type: "code",
2399
1963
  client_id: OAUTH_CLIENT_ID,
2400
- redirect_uri: REDIRECT_URI3,
1964
+ redirect_uri: REDIRECT_URI4,
2401
1965
  scope: OAUTH_SCOPE,
2402
1966
  code_challenge: challenge,
2403
1967
  code_challenge_method: "S256",
2404
1968
  handoff: "url",
2405
1969
  state
2406
1970
  }).toString();
2407
- const callbackServer = await startOAuthCallbackServer(state, interaction.signal);
2408
- interaction.notify({ type: "progress", message: `Listening for OAuth callback on ${REDIRECT_URI3}` });
1971
+ const callback = await startOAuthCallbackServer({
1972
+ providerName: "Radius",
1973
+ host: CALLBACK_HOST3,
1974
+ port: CALLBACK_PORT3,
1975
+ path: CALLBACK_PATH3,
1976
+ state,
1977
+ complete: (code) => requestOAuthToken(gateway, new URLSearchParams({
1978
+ grant_type: "authorization_code",
1979
+ client_id: OAUTH_CLIENT_ID,
1980
+ redirect_uri: REDIRECT_URI4,
1981
+ code,
1982
+ code_verifier: verifier
1983
+ }), interaction.signal),
1984
+ signal: interaction.signal
1985
+ });
1986
+ interaction.notify({ type: "progress", message: `Listening for OAuth callback on ${REDIRECT_URI4}` });
2409
1987
  interaction.notify({
2410
1988
  type: "auth_url",
2411
1989
  url: authorizeUrl.toString(),
2412
1990
  instructions: "Continue in your browser."
2413
1991
  });
2414
1992
  try {
2415
- const code = await callbackServer.waitForCode();
2416
- if (!code) {
2417
- if (interaction.signal.aborted) {
2418
- throw new Error("Login cancelled");
2419
- }
1993
+ const credential = await callback.wait();
1994
+ if (!credential)
2420
1995
  throw new Error("OAuth callback did not complete.");
2421
- }
2422
- return await requestOAuthToken(gateway, new URLSearchParams({
2423
- grant_type: "authorization_code",
2424
- client_id: OAUTH_CLIENT_ID,
2425
- redirect_uri: REDIRECT_URI3,
2426
- code,
2427
- code_verifier: verifier
2428
- }), interaction.signal);
1996
+ return credential;
2429
1997
  } finally {
2430
- callbackServer.close();
1998
+ callback.close();
2431
1999
  }
2432
2000
  }
2433
2001
  async function requestDeviceAuthorization(gateway, signal) {
@@ -2719,6 +2287,7 @@ function registerBunOAuthFlows() {
2719
2287
  registerBundledOAuthFlowLoaders({
2720
2288
  anthropic: () => anthropicOAuth,
2721
2289
  openaiCodex: () => openaiCodexOAuth,
2290
+ openaiChatGPT: () => openaiChatGPTOAuth,
2722
2291
  githubCopilot: () => githubCopilotOAuth,
2723
2292
  openrouter: () => openRouterOAuth,
2724
2293
  kimiCoding: () => kimiCodingOAuth,
@@ -2825,4 +2394,4 @@ async function resolveCredential(opts = {}) {
2825
2394
  return null;
2826
2395
  }
2827
2396
 
2828
- export { DEFAULT_MODEL, parseModelStr, resolveCredential, getMemoryRaterNames, REFERENCES_SOURCE_MAX_LENGTH, sanitizeReferencesSource, SummaryWithRatingsSchema, BASE_SUMMARIZE_PROMPT, LlmRater, buildRatingsFromLlm, buildSummaryWithRatingsPrompt, isLlmRaterEnabled, dedupeRetrievalsForRater, fetchRetrievalsForTask, postRatings };
2397
+ export { DEFAULT_MODEL, parseModelStr, resolveCredential };