@desplega.ai/agent-swarm 1.158.0 → 1.159.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 (272) hide show
  1. package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-qhch0n2v.js} +1 -1
  2. package/dist/{actions-p9hz5yat.js → actions-dtsh1mfb.js} +33 -29
  3. package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-f2h06k64.js} +8 -3
  4. package/dist/{app-g26wdcz6.js → app-y1b9srva.js} +10 -9
  5. package/dist/{assistant-wydfqkb3.js → assistant-31hwy5xj.js} +34 -30
  6. package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-0k1mfax5.js} +12 -13
  7. package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-48d2qpkt.js} +11 -11
  8. package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-w0bryhkr.js} +12 -12
  9. package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-t65wbrn7.js} +9 -8
  10. package/dist/{boot-seeds-s3q01xj3.js → boot-seeds-h7c32hvm.js} +12 -11
  11. package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-1t6611ne.js} +26 -21
  12. package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-werp659j.js} +4 -2
  13. package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-y6rdgbc1.js} +11 -2
  14. package/dist/claude-sdk-session-zhkyk8yw.js +29319 -0
  15. package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
  16. package/dist/{cli-wscdvcqz.js → cli-0n2e4x49.js} +1 -1
  17. package/dist/cli-0xqde53b.js +176 -0
  18. package/dist/{cli-xberxa1r.js → cli-10ym38qc.js} +2 -2
  19. package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
  20. package/dist/{cli-rqz8qbw7.js → cli-20035trh.js} +50 -18
  21. package/dist/{cli-k0g1sjzm.js → cli-31nkw3g3.js} +3 -3
  22. package/dist/cli-3gvrr8vj.js +1422 -0
  23. package/dist/{cli-c07r9a2m.js → cli-48527fpw.js} +9 -8
  24. package/dist/{cli-24k806sc.js → cli-4aj25szq.js} +2 -2
  25. package/dist/{cli-7gtvvpbh.js → cli-4tvgz99m.js} +7 -7
  26. package/dist/cli-503ya656.js +455 -0
  27. package/dist/{cli-cw9zck8j.js → cli-5f2hq128.js} +8 -4
  28. package/dist/{cli-s8eet254.js → cli-68bmme5p.js} +11078 -27833
  29. package/dist/{cli-ftfvggzx.js → cli-79aq9cgb.js} +794 -563
  30. package/dist/cli-7cxw8b60.js +14910 -0
  31. package/dist/cli-7kyk9jr3.js +22 -0
  32. package/dist/cli-7zttzetj.js +324 -0
  33. package/dist/{cli-y95wp3tg.js → cli-96qd5psa.js} +1 -1
  34. package/dist/{cli-g8djp6qe.js → cli-9yg65c1j.js} +22 -0
  35. package/dist/{cli-3gmcwfyx.js → cli-ardpzhjm.js} +5 -5
  36. package/dist/{cli-7s3syk22.js → cli-b6thtzac.js} +5 -5
  37. package/dist/{cli-00w2c66p.js → cli-bgv70kym.js} +13 -2
  38. package/dist/{cli-j55n64b6.js → cli-bv0a38v9.js} +163 -44
  39. package/dist/cli-ca2w7zv7.js +115 -0
  40. package/dist/cli-cpvsaqsw.js +333 -0
  41. package/dist/cli-cygyqj3b.js +754 -0
  42. package/dist/{cli-x24pshtq.js → cli-dvjpkkjd.js} +6 -6
  43. package/dist/{cli-5d10vd2m.js → cli-e0ndxhtk.js} +4 -4
  44. package/dist/{cli-4198qc9v.js → cli-e4xnc0qp.js} +15 -3
  45. package/dist/{cli-rjehvrts.js → cli-eg7cdg68.js} +8 -8
  46. package/dist/cli-ejpygnqz.js +3815 -0
  47. package/dist/{cli-fgqxwrpv.js → cli-fjtp3463.js} +1631 -127
  48. package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
  49. package/dist/{cli-47m6dkd3.js → cli-g9df2m37.js} +409 -168
  50. package/dist/cli-gzyh0j0g.js +8455 -0
  51. package/dist/cli-hgqfttfc.js +183 -0
  52. package/dist/cli-hj65wsts.js +17755 -0
  53. package/dist/cli-j9z8mfx3.js +476 -0
  54. package/dist/{cli-aehm1rbq.js → cli-kc3dp84d.js} +1135 -61
  55. package/dist/{cli-h38x0qhg.js → cli-kdnehe0t.js} +4 -3
  56. package/dist/{cli-20cj37vt.js → cli-m4excttz.js} +136 -2216
  57. package/dist/{cli-8qmme6vd.js → cli-mg24hkt4.js} +2 -2
  58. package/dist/{cli-xhaeg2nc.js → cli-mzkqpxee.js} +1 -1
  59. package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
  60. package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
  61. package/dist/{cli-rj19hc34.js → cli-qjxy52w7.js} +1 -1
  62. package/dist/{cli-53sz8gkz.js → cli-qv4jv8bx.js} +1 -1
  63. package/dist/cli-qvnnx4ct.js +1051 -0
  64. package/dist/cli-rb9m6rpe.js +4980 -0
  65. package/dist/{cli-tt9k8r35.js → cli-rfezr056.js} +476 -909
  66. package/dist/{cli-ggm92wcn.js → cli-rgjprct3.js} +1 -0
  67. package/dist/{cli-9httdpyq.js → cli-rrqmqr1s.js} +1 -1
  68. package/dist/cli-rykfmgwg.js +102 -0
  69. package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
  70. package/dist/{cli-68w09sjw.js → cli-vn0qv9cj.js} +25 -88
  71. package/dist/{cli-987hg0aa.js → cli-vwbbaecp.js} +2 -2
  72. package/dist/cli-wd9hz40d.js +69 -0
  73. package/dist/{cli-j57qkrpq.js → cli-wgjx0q33.js} +13 -13
  74. package/dist/cli-xgpf00sk.js +2149 -0
  75. package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
  76. package/dist/{cli-aky8tctm.js → cli-z9x0sh1t.js} +3 -3
  77. package/dist/{cli-1hkrch3k.js → cli-zw65mab6.js} +5 -5
  78. package/dist/cli.js +38 -29
  79. package/dist/cloudflare-workers-ai-system-one-1sg586qv.js +46 -0
  80. package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-jqfqqa21.js} +21 -14
  81. package/dist/{codex-hook-9hptmdhj.js → codex-hook-5eys3dya.js} +2 -2
  82. package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-zd341dsm.js} +21 -14
  83. package/dist/{commands-e3bn0p75.js → commands-vfsysz4s.js} +9 -8
  84. package/dist/{db-03v9kzr2.js → db-s3znhvbn.js} +15 -10
  85. package/dist/{dispatcher-nrmg8yht.js → dispatcher-5xn0c7rf.js} +32 -28
  86. package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-894mgfvs.js} +3 -3
  87. package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
  88. package/dist/execute-71ysgv35.js +965 -0
  89. package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-1nfcdphp.js} +5 -4
  90. package/dist/{google-vertex-809af514.js → google-vertex-1tqcd7b1.js} +5 -4
  91. package/dist/{handlers-aqcedbyb.js → handlers-5w4jwycr.js} +35 -31
  92. package/dist/{hook-7vkskkre.js → hook-853bxrr6.js} +16 -13
  93. package/dist/{hook-ybvmrmhq.js → hook-z0hbxj85.js} +16 -13
  94. package/dist/{http-2eqa8t24.js → http-akc3wy3m.js} +600 -123
  95. package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
  96. package/dist/{index-a3vn96n8.js → index-5sz16ksh.js} +187 -47
  97. package/dist/{index-c6zsv1bd.js → index-bjmjh9h4.js} +11 -11
  98. package/dist/{index-chgdkq36.js → index-cd151qkq.js} +32 -28
  99. package/dist/{index-x71bvq0p.js → index-k661dzzr.js} +33 -29
  100. package/dist/{index-1yks3qcr.js → index-ttpbhnjg.js} +32 -28
  101. package/dist/{keepalive-vtkf5n99.js → keepalive-8p9rpvz5.js} +11 -10
  102. package/dist/{lead-h3sp357x.js → lead-jp69z5h3.js} +49 -45
  103. package/dist/llama-cpp-classify-t2tccams.js +335 -0
  104. package/dist/{maintenance-jzeqtk3q.js → maintenance-fwx4ev0k.js} +12 -12
  105. package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-bhvwqcnk.js} +14 -17
  106. package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-cwcq1ctx.js} +10 -9
  107. package/dist/{onboard-tmsp0qbz.js → onboard-2b4q0t84.js} +6 -5
  108. package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-nekthgks.js} +21 -8
  109. package/dist/{openai-completions-9hjrqbw8.js → openai-completions-hxtzwj0s.js} +8 -11
  110. package/dist/{openai-responses-7b1pn0xt.js → openai-responses-w4r118w7.js} +22 -17
  111. package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-zz7xvjj6.js} +6 -4
  112. package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-b6sqqjgn.js} +4 -6
  113. package/dist/{otel-impl-9mz73q65.js → otel-impl-g8rs4vwr.js} +1 -1
  114. package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
  115. package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-n0me28wt.js} +29 -17
  116. package/dist/pricing-refresh-0v77385v.js +39 -0
  117. package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-krjyazbj.js} +10 -9
  118. package/dist/{render-v2-gryrh9h8.js → render-v2-3wjsp9aw.js} +10 -9
  119. package/dist/runtime-ktjysacx.js +24 -0
  120. package/dist/{setup-q9720bt6.js → setup-yeqryke6.js} +6 -5
  121. package/dist/typesafe-system-one-96960jxp.js +27 -0
  122. package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-dzdeq1sf.js} +21 -13
  123. package/dist/{work-objects-b76x7deb.js → work-objects-3pakpkw0.js} +35 -31
  124. package/dist/{worker-6vrxbv41.js → worker-85testgj.js} +49 -45
  125. package/openapi.json +863 -14
  126. package/package.json +9 -8
  127. package/src/be/db/agents.ts +20 -0
  128. package/src/be/db/tasks/human-free.ts +442 -0
  129. package/src/be/db/tasks/read.ts +56 -1
  130. package/src/be/db/tasks/write.ts +107 -11
  131. package/src/be/db.ts +89 -165
  132. package/src/be/harness-model-support.ts +182 -0
  133. package/src/be/human-free-drain.ts +67 -0
  134. package/src/be/migrations/182_task_human_free_flag.sql +63 -0
  135. package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
  136. package/src/be/migrations/184_model_catalog.sql +120 -0
  137. package/src/be/model-catalog-store.ts +644 -0
  138. package/src/be/model-tier-keys.ts +31 -0
  139. package/src/be/model-tier-resolution.ts +489 -0
  140. package/src/be/model-validation.ts +112 -0
  141. package/src/be/models-catalog.ts +61 -7
  142. package/src/be/modelsdev-cache.json +82 -0
  143. package/src/be/modelsdev-cache.ts +2 -0
  144. package/src/be/pricing-refresh.ts +154 -12
  145. package/src/be/scripts/typecheck.ts +15 -0
  146. package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
  147. package/src/be/swarm-config-guard.ts +6 -0
  148. package/src/cli.tsx +10 -0
  149. package/src/commands/claude-managed-setup.ts +3 -1
  150. package/src/commands/runner.ts +76 -2
  151. package/src/extensions/contract-types.generated.ts +1 -1
  152. package/src/heartbeat/heartbeat.ts +64 -15
  153. package/src/heartbeat/templates.ts +2 -2
  154. package/src/http/agents.ts +49 -1
  155. package/src/http/index.ts +8 -0
  156. package/src/http/models-catalog.ts +357 -8
  157. package/src/http/poll.ts +45 -2
  158. package/src/http/schedules.ts +36 -6
  159. package/src/http/session-data.ts +2 -5
  160. package/src/http/stats.ts +6 -8
  161. package/src/http/tasks.ts +26 -1
  162. package/src/http/usage-cache.ts +56 -15
  163. package/src/http/workflows.ts +35 -8
  164. package/src/prompts/session-templates.ts +1 -0
  165. package/src/providers/claude-managed-models.ts +47 -161
  166. package/src/providers/codex-adapter.ts +4 -4
  167. package/src/providers/codex-models.ts +65 -198
  168. package/src/providers/reasoning-effort.ts +44 -140
  169. package/src/rbac/legacy-policy.ts +25 -0
  170. package/src/rbac/permissions.ts +10 -0
  171. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  172. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  173. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  174. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  175. package/src/server.ts +6 -0
  176. package/src/slack/message-text.ts +56 -2
  177. package/src/slack/thread-buffer.ts +10 -2
  178. package/src/tests/agents-list-model-display.test.ts +4 -6
  179. package/src/tests/base-prompt.test.ts +3 -0
  180. package/src/tests/claude-adapter.test.ts +10 -0
  181. package/src/tests/claude-managed-adapter.test.ts +12 -18
  182. package/src/tests/codex-adapter.test.ts +2 -1
  183. package/src/tests/codex-gpt6-release.test.ts +66 -5
  184. package/src/tests/context-window.test.ts +7 -5
  185. package/src/tests/db-extraction-contract.test.ts +1 -0
  186. package/src/tests/db-task-read-contract.test.ts +5 -1
  187. package/src/tests/db-task-write-contract.test.ts +4 -1
  188. package/src/tests/docs-index-footprint.test.js +3 -3
  189. package/src/tests/explicit-model-validation.test.ts +332 -0
  190. package/src/tests/harness-model-support.test.ts +374 -0
  191. package/src/tests/heartbeat-checklist-config.test.ts +71 -0
  192. package/src/tests/heartbeat-checklist.test.ts +4 -2
  193. package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
  194. package/src/tests/human-free-flag.test.ts +279 -0
  195. package/src/tests/human-free-oracle.ts +57 -0
  196. package/src/tests/human-free-reclassify.test.ts +669 -0
  197. package/src/tests/migration-046-budgets.test.ts +3 -3
  198. package/src/tests/model-catalog-migration.test.ts +134 -0
  199. package/src/tests/model-catalog-table.test.ts +249 -0
  200. package/src/tests/model-catalog-write-access.test.ts +387 -0
  201. package/src/tests/model-tier-resolution.test.ts +519 -0
  202. package/src/tests/models-catalog.test.ts +1 -1
  203. package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
  204. package/src/tests/package-publish.test.ts +137 -36
  205. package/src/tests/pricing-routes.test.ts +2 -2
  206. package/src/tests/rbac-engine.test.ts +42 -2
  207. package/src/tests/reasoning-effort.test.ts +109 -0
  208. package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
  209. package/src/tests/runtime-model-catalog.test.ts +86 -0
  210. package/src/tests/script-connections.test.ts +5 -0
  211. package/src/tests/seed-scripts.test.ts +89 -0
  212. package/src/tests/session-costs.test.ts +14 -11
  213. package/src/tests/slack-message-text.test.ts +101 -0
  214. package/src/tests/slack-thread-buffer-context.test.ts +93 -0
  215. package/src/tests/task-cascade-fail.test.ts +148 -2
  216. package/src/tests/tool-annotations.test.ts +1 -1
  217. package/src/tests/usage-cache.test.ts +166 -0
  218. package/src/tests/workflow-executors.test.ts +5 -2
  219. package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
  220. package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
  221. package/src/tests/workflow-system-one-decision.test.ts +2063 -0
  222. package/src/tools/model-catalog/index.ts +137 -0
  223. package/src/tools/schedules/create-schedule.ts +16 -1
  224. package/src/tools/schedules/patch-schedule.ts +17 -0
  225. package/src/tools/schedules/update-schedule.ts +17 -0
  226. package/src/tools/send-task.ts +14 -0
  227. package/src/tools/task-action.ts +12 -0
  228. package/src/tools/tool-config.ts +3 -1
  229. package/src/tools/workflows/create-workflow.ts +9 -2
  230. package/src/tools/workflows/patch-workflow-node.ts +17 -7
  231. package/src/tools/workflows/patch-workflow.ts +9 -2
  232. package/src/tools/workflows/update-workflow.ts +9 -2
  233. package/src/types.ts +30 -1
  234. package/src/utils/context-window.ts +47 -53
  235. package/src/utils/harness-cli-version.ts +115 -0
  236. package/src/utils/harness-model-error.ts +33 -0
  237. package/src/utils/runtime-model-catalog.ts +137 -0
  238. package/src/workflows/approval-resolution.ts +39 -0
  239. package/src/workflows/definition.ts +7 -0
  240. package/src/workflows/engine.ts +69 -1
  241. package/src/workflows/executors/agent-task.ts +9 -0
  242. package/src/workflows/executors/base.ts +53 -0
  243. package/src/workflows/executors/human-in-the-loop.ts +8 -8
  244. package/src/workflows/executors/index.ts +1 -0
  245. package/src/workflows/executors/registry.ts +2 -0
  246. package/src/workflows/executors/system-one-decision.ts +1232 -0
  247. package/src/workflows/executors/system-one-providers.ts +301 -0
  248. package/src/workflows/executors/workflow-llm.ts +13 -1
  249. package/src/workflows/readiness.ts +86 -0
  250. package/src/workflows/recovery.ts +12 -12
  251. package/src/workflows/resume.ts +23 -9
  252. package/templates/schedules/daily-blocker-digest/content.md +4 -5
  253. package/templates/skills/agent-browser/SKILL.md +6 -5
  254. package/templates/skills/agent-browser/content.md +6 -5
  255. package/templates/skills/heartbeat-runbook/config.json +1 -1
  256. package/templates/skills/heartbeat-runbook/content.md +2 -2
  257. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  258. package/templates/skills/swarm-scripts/content.md +1 -1
  259. package/templates/skills/workflow-iterate/content.md +81 -1
  260. package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
  261. package/templates/workflows/pr-review-status-sweep/content.md +2 -0
  262. package/dist/claude-sdk-session-t442qz6f.js +0 -39108
  263. package/dist/cli-0xjkj1j7.js +0 -61
  264. package/dist/cli-65hjmev5.js +0 -1141
  265. package/dist/cli-aw1jwp1r.js +0 -14075
  266. package/dist/cli-h967nb6r.js +0 -6603
  267. package/dist/cli-vapyk8sw.js +0 -20
  268. package/dist/cli-ws6rqycm.js +0 -247
  269. package/dist/pricing-refresh-v1cbr9te.js +0 -27
  270. package/src/providers/modelsdev-reasoning.json +0 -6453
  271. package/dist/{codex-login-x3jk4etn.js → codex-login-he9vrn90.js} +3 -3
  272. package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
@@ -8,348 +8,21 @@ import {
8
8
  getEnvApiKey,
9
9
  normalizeRadiusGatewayUrl,
10
10
  registerBundledOAuthFlowLoaders
11
- } from "./cli-aw1jwp1r.js";
11
+ } from "./cli-gzyh0j0g.js";
12
12
  import {
13
- init_zod
14
- } from "./cli-sd0mxa3c.js";
15
- import {
16
- exports_external
17
- } from "./cli-w5e1d1vv.js";
13
+ oauthErrorHtml,
14
+ oauthSuccessHtml
15
+ } from "./cli-rykfmgwg.js";
18
16
  import {
19
17
  getProviderEnvValue
20
18
  } from "./cli-btbzvq95.js";
21
19
  import {
22
20
  InMemoryCredentialStore
23
- } from "./cli-mcnhgnn1.js";
21
+ } from "./cli-ykk5jaax.js";
24
22
  import {
25
23
  __require
26
24
  } from "./cli-bc05qbss.js";
27
25
 
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
26
  // src/utils/internal-ai/models.ts
354
27
  var DEFAULT_MODEL = {
355
28
  openrouter: "openrouter/deepseek/deepseek-v4.1-flash",
@@ -368,105 +41,135 @@ function parseModelStr(modelStr) {
368
41
  return [modelStr.slice(0, idx), modelStr.slice(idx + 1)];
369
42
  }
370
43
 
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
44
+ // node_modules/@earendil-works/pi-ai/dist/auth/oauth/callback-server.js
45
+ import { createServer } from "node:http";
46
+ function sendPage(response, status, html) {
47
+ response.writeHead(status, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
48
+ response.end(html);
49
+ }
50
+ async function startOAuthCallbackServer(options) {
51
+ const { providerName, signal } = options;
52
+ if (signal?.aborted)
53
+ throw new Error("Login cancelled");
54
+ let resolveWait = () => {};
55
+ let rejectWait = () => {};
56
+ const waitPromise = new Promise((resolve, reject) => {
57
+ resolveWait = resolve;
58
+ rejectWait = reject;
59
+ });
60
+ waitPromise.catch(() => {
61
+ return;
461
62
  });
63
+ let claimed = false;
64
+ let settled = false;
65
+ let timer;
66
+ const onAbort = () => finish({ error: new Error("Login cancelled") });
67
+ const finish = (result) => {
68
+ if (settled)
69
+ return;
70
+ settled = true;
71
+ if (timer)
72
+ clearTimeout(timer);
73
+ signal?.removeEventListener("abort", onAbort);
74
+ if ("error" in result)
75
+ rejectWait(result.error);
76
+ else
77
+ resolveWait(result.value);
78
+ };
79
+ const server = createServer((request, response) => {
80
+ (async () => {
81
+ const url = new URL(request.url ?? "/", "http://localhost");
82
+ if (request.method !== "GET" || url.pathname !== options.path) {
83
+ sendPage(response, 404, oauthErrorHtml("Callback route not found."));
84
+ return;
85
+ }
86
+ if (options.state !== undefined && url.searchParams.get("state") !== options.state) {
87
+ sendPage(response, 400, oauthErrorHtml("State mismatch."));
88
+ return;
89
+ }
90
+ if (claimed || settled) {
91
+ sendPage(response, 409, oauthErrorHtml("This sign-in has already been handled."));
92
+ return;
93
+ }
94
+ const error = url.searchParams.get("error");
95
+ if (error) {
96
+ const description = url.searchParams.get("error_description") ?? error;
97
+ sendPage(response, 400, oauthErrorHtml(`${providerName} authorization failed.`, description));
98
+ finish({ error: new Error(`${providerName} authorization failed: ${description}`) });
99
+ return;
100
+ }
101
+ const code = url.searchParams.get("code");
102
+ if (!code) {
103
+ sendPage(response, 400, oauthErrorHtml("Missing authorization code."));
104
+ return;
105
+ }
106
+ claimed = true;
107
+ try {
108
+ const value = await options.complete(code);
109
+ sendPage(response, 200, oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`));
110
+ finish({ value });
111
+ } catch (error2) {
112
+ const failure = error2 instanceof Error ? error2 : new Error(String(error2));
113
+ sendPage(response, 502, oauthErrorHtml(`${providerName} sign-in failed.`, failure.message));
114
+ finish({ error: failure });
115
+ }
116
+ })();
117
+ });
118
+ await new Promise((resolve, reject) => {
119
+ server.once("error", reject);
120
+ server.listen(options.port, options.host, () => {
121
+ server.off("error", reject);
122
+ resolve();
123
+ });
124
+ });
125
+ const address = server.address();
126
+ if (!address || typeof address === "string") {
127
+ server.close();
128
+ throw new Error("OAuth callback server did not bind to TCP");
129
+ }
130
+ server.on("error", (error) => finish({ error }));
131
+ signal?.addEventListener("abort", onAbort, { once: true });
132
+ if (options.timeoutMs !== undefined) {
133
+ timer = setTimeout(() => finish({ error: new Error(`${providerName} sign-in timed out`) }), options.timeoutMs);
134
+ }
135
+ const redirectHost = options.redirectHost ?? options.host;
136
+ return {
137
+ redirectUri: `http://${redirectHost.includes(":") ? `[${redirectHost}]` : redirectHost}:${address.port}${options.path}`,
138
+ wait: () => waitPromise,
139
+ cancel: () => {
140
+ if (!claimed)
141
+ finish({ value: undefined });
142
+ },
143
+ close: () => {
144
+ finish({ error: new Error("OAuth callback server closed") });
145
+ server.close();
146
+ }
147
+ };
462
148
  }
463
- function oauthErrorHtml(message, details) {
464
- return renderPage({
465
- title: "Authentication failed",
466
- heading: "Authentication failed",
467
- message,
468
- details
149
+ async function waitForCallbackOrManualInput(interaction, callback, prompt) {
150
+ const manualAbort = new AbortController;
151
+ let manualError;
152
+ const manual = interaction.prompt({ type: "manual_code", ...prompt, signal: manualAbort.signal }).then((input) => {
153
+ callback?.cancel();
154
+ return input;
155
+ }).catch((error) => {
156
+ manualError = error instanceof Error ? error : new Error(String(error));
157
+ callback?.cancel();
158
+ return;
469
159
  });
160
+ try {
161
+ const value = await callback?.wait();
162
+ if (manualError)
163
+ throw manualError;
164
+ if (value !== undefined)
165
+ return { type: "callback", value };
166
+ const input = await manual;
167
+ if (manualError)
168
+ throw manualError;
169
+ return { type: "manual", input: input ?? "" };
170
+ } finally {
171
+ manualAbort.abort();
172
+ }
470
173
  }
471
174
 
472
175
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/pkce.js
@@ -489,8 +192,6 @@ async function generatePKCE() {
489
192
  }
490
193
 
491
194
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/anthropic.js
492
- var nodeApis = null;
493
- var nodeApisPromise = null;
494
195
  var decode = (s) => atob(s);
495
196
  var CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
496
197
  var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
@@ -500,20 +201,6 @@ var CALLBACK_PORT = 53692;
500
201
  var CALLBACK_PATH = "/callback";
501
202
  var REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
502
203
  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
204
  function parseAuthorizationInput(input) {
518
205
  const value = input.trim();
519
206
  if (!value)
@@ -556,68 +243,6 @@ function formatErrorDetails(error) {
556
243
  }
557
244
  return String(error);
558
245
  }
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
246
  async function postJson(url, body, signal) {
622
247
  const response = await fetch(url, {
623
248
  method: "POST",
@@ -658,21 +283,22 @@ async function exchangeAuthorizationCode(code, state, verifier, redirectUri, sig
658
283
  type: "oauth",
659
284
  refresh: tokenData.refresh_token,
660
285
  access: tokenData.access_token,
661
- expires: Date.now() + tokenData.expires_in * 1000 - 300000
286
+ expires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000
662
287
  };
663
288
  }
664
289
  async function loginAnthropic(interaction) {
665
290
  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;
291
+ const callback = await startOAuthCallbackServer({
292
+ providerName: "Anthropic",
293
+ host: CALLBACK_HOST,
294
+ port: CALLBACK_PORT,
295
+ path: CALLBACK_PATH,
296
+ state: verifier,
297
+ complete: async (code) => code,
298
+ signal: interaction.signal
299
+ }).catch(() => {
300
+ return;
301
+ });
676
302
  try {
677
303
  const authParams = new URLSearchParams({
678
304
  code: "true",
@@ -689,53 +315,27 @@ async function loginAnthropic(interaction) {
689
315
  url: `${AUTHORIZE_URL}?${authParams.toString()}`,
690
316
  instructions: "Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."
691
317
  });
692
- const manualPromise = interaction.prompt({
693
- type: "manual_code",
318
+ const result = await waitForCallbackOrManualInput(interaction, callback, {
694
319
  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();
320
+ placeholder: REDIRECT_URI
703
321
  });
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);
322
+ let code;
323
+ let state = verifier;
324
+ if (result.type === "callback") {
325
+ code = result.value;
326
+ } else {
327
+ const parsed = parseAuthorizationInput(result.input);
712
328
  if (parsed.state && parsed.state !== verifier)
713
329
  throw new Error("OAuth state mismatch");
714
330
  code = parsed.code;
715
331
  state = parsed.state ?? verifier;
716
332
  }
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
333
  if (!code)
730
334
  throw new Error("Missing authorization code");
731
- if (!state)
732
- throw new Error("Missing OAuth state");
733
335
  interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
734
- return exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
336
+ return await exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
735
337
  } finally {
736
- interaction.signal.removeEventListener("abort", onAbort);
737
- manualAbort.abort();
738
- server.server.close();
338
+ callback?.close();
739
339
  }
740
340
  }
741
341
  async function refreshAnthropicToken(refreshToken, signal) {
@@ -759,7 +359,7 @@ async function refreshAnthropicToken(refreshToken, signal) {
759
359
  type: "oauth",
760
360
  refresh: data.refresh_token,
761
361
  access: data.access_token,
762
- expires: Date.now() + data.expires_in * 1000 - 300000
362
+ expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000
763
363
  };
764
364
  }
765
365
  var anthropicOAuth = {
@@ -1577,22 +1177,258 @@ var metaOAuth = {
1577
1177
  }
1578
1178
  };
1579
1179
 
1180
+ // node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-chatgpt.js
1181
+ import { randomBytes } from "node:crypto";
1182
+ import { createServer as createServer2 } from "node:http";
1183
+ var DYNAMIC_CLIENT_ID = "dynamic_agent_client";
1184
+ var AGENT_NAME_HINT = "Pi";
1185
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1186
+ var AUTHORIZE_URL2 = "https://auth.openai.com/api/accounts/authorize";
1187
+ var TOKEN_URL2 = "https://auth.openai.com/api/accounts/oauth/token";
1188
+ var RESOURCE = "https://api.openai.com/v1";
1189
+ var CALLBACK_HOST2 = getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
1190
+ var CALLBACK_PORT2 = 1455;
1191
+ var CALLBACK_PATH2 = "/auth/callback";
1192
+ var REDIRECT_URI2 = `http://127.0.0.1:${CALLBACK_PORT2}${CALLBACK_PATH2}`;
1193
+ var DIRECT_TOKEN_SCOPE = "chatgpt.tokens.use.direct";
1194
+ var SCOPE = `openid profile email offline_access resource.invoke ${DIRECT_TOKEN_SCOPE}`;
1195
+ var EXPIRY_MARGIN_MS = 3 * 60 * 1000;
1196
+ function randomValue() {
1197
+ return randomBytes(32).toString("base64url");
1198
+ }
1199
+ function authorizationResultFromCallback(url, expectedState) {
1200
+ const code = url.searchParams.get("code");
1201
+ if (!code)
1202
+ throw new Error("Missing authorization code");
1203
+ const state = url.searchParams.get("state");
1204
+ if (!state)
1205
+ throw new Error("Missing OAuth state");
1206
+ if (state !== expectedState)
1207
+ throw new Error("OAuth state mismatch");
1208
+ const clientId = url.searchParams.get("client_id")?.trim();
1209
+ if (!clientId)
1210
+ throw new Error("OpenAI OAuth registration callback did not contain an issued client ID");
1211
+ return { code, clientId };
1212
+ }
1213
+ function authorizationResultFromManualInput(input, expectedState) {
1214
+ let url;
1215
+ try {
1216
+ url = new URL(input.trim());
1217
+ } catch {
1218
+ throw new Error("Paste the full callback URL from the browser");
1219
+ }
1220
+ const expected = new URL(REDIRECT_URI2);
1221
+ if (url.origin !== expected.origin || url.pathname !== expected.pathname) {
1222
+ throw new Error(`The pasted callback URL must start with ${REDIRECT_URI2}`);
1223
+ }
1224
+ const error = url.searchParams.get("error");
1225
+ if (error)
1226
+ throw new Error(`ChatGPT authorization failed: ${error}`);
1227
+ return authorizationResultFromCallback(url, expectedState);
1228
+ }
1229
+ function sendHtml(response, status, body) {
1230
+ response.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
1231
+ response.end(body);
1232
+ }
1233
+ function startCallbackServer(expectedState) {
1234
+ return new Promise((resolve, reject) => {
1235
+ let resolveResult;
1236
+ let rejectResult;
1237
+ const result = new Promise((resolveAuthorization, rejectAuthorization) => {
1238
+ resolveResult = resolveAuthorization;
1239
+ rejectResult = rejectAuthorization;
1240
+ });
1241
+ const server = createServer2((request, response) => {
1242
+ try {
1243
+ const url = new URL(request.url || "", REDIRECT_URI2);
1244
+ if (url.pathname !== CALLBACK_PATH2) {
1245
+ sendHtml(response, 404, oauthErrorHtml("Callback route not found."));
1246
+ return;
1247
+ }
1248
+ const error = url.searchParams.get("error");
1249
+ if (error) {
1250
+ sendHtml(response, 400, oauthErrorHtml("ChatGPT was not connected.", `Error: ${error}`));
1251
+ rejectResult(new Error(`ChatGPT authorization failed: ${error}`));
1252
+ return;
1253
+ }
1254
+ let authorizationResult;
1255
+ try {
1256
+ authorizationResult = authorizationResultFromCallback(url, expectedState);
1257
+ } catch (error2) {
1258
+ const message = error2 instanceof Error ? error2.message : "Invalid callback";
1259
+ sendHtml(response, 400, oauthErrorHtml(message));
1260
+ return;
1261
+ }
1262
+ sendHtml(response, 200, oauthSuccessHtml("ChatGPT authentication completed. You can close this window."));
1263
+ resolveResult(authorizationResult);
1264
+ } catch {
1265
+ sendHtml(response, 500, oauthErrorHtml("Internal error while processing the callback."));
1266
+ }
1267
+ });
1268
+ server.once("error", reject);
1269
+ server.listen(CALLBACK_PORT2, CALLBACK_HOST2, () => {
1270
+ server.removeListener("error", reject);
1271
+ server.on("error", rejectResult);
1272
+ resolve({ server, result });
1273
+ });
1274
+ });
1275
+ }
1276
+ async function requestToken(body, signal) {
1277
+ const response = await fetch(TOKEN_URL2, {
1278
+ method: "POST",
1279
+ headers: {
1280
+ accept: "application/json",
1281
+ "content-type": "application/x-www-form-urlencoded"
1282
+ },
1283
+ body,
1284
+ signal
1285
+ });
1286
+ if (!response.ok) {
1287
+ const responseBody = await response.text().catch(() => "");
1288
+ throw new Error(`OpenAI OAuth token request failed (${response.status}): ${responseBody || response.statusText}`);
1289
+ }
1290
+ const data = await response.json();
1291
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
1292
+ throw new Error("OpenAI OAuth token response must be an object");
1293
+ }
1294
+ return data;
1295
+ }
1296
+ function requireTokenString(value, field) {
1297
+ if (typeof value !== "string" || value.trim().length === 0) {
1298
+ throw new Error(`OpenAI OAuth token response has invalid ${field}`);
1299
+ }
1300
+ return value;
1301
+ }
1302
+ function credentialFromTokenResponse(token, clientId) {
1303
+ const access = requireTokenString(token.access_token, "access_token");
1304
+ const refresh = requireTokenString(token.refresh_token, "refresh_token");
1305
+ const scope = requireTokenString(token.scope, "scope");
1306
+ if (typeof token.expires_in !== "number" || !Number.isFinite(token.expires_in) || token.expires_in <= 0) {
1307
+ throw new Error("OpenAI OAuth token response has invalid expires_in");
1308
+ }
1309
+ const scopes = scope.trim().split(/\s+/).filter(Boolean);
1310
+ if (!scopes.includes(DIRECT_TOKEN_SCOPE)) {
1311
+ throw new Error(`OpenAI OAuth grant did not include ${DIRECT_TOKEN_SCOPE}`);
1312
+ }
1313
+ return {
1314
+ type: "oauth",
1315
+ access,
1316
+ refresh,
1317
+ expires: Date.now() + token.expires_in * 1000 - EXPIRY_MARGIN_MS,
1318
+ clientId,
1319
+ scopes
1320
+ };
1321
+ }
1322
+ async function exchangeAuthorizationCode2(code, verifier, clientId, signal) {
1323
+ const token = await requestToken(new URLSearchParams({
1324
+ grant_type: "authorization_code",
1325
+ client_id: clientId,
1326
+ code,
1327
+ code_verifier: verifier,
1328
+ redirect_uri: REDIRECT_URI2,
1329
+ resource: RESOURCE
1330
+ }), signal);
1331
+ if (typeof token.id_token !== "string" || token.id_token.trim().length === 0) {
1332
+ throw new Error("OpenAI OAuth token response did not contain an ID token");
1333
+ }
1334
+ return credentialFromTokenResponse(token, clientId);
1335
+ }
1336
+ async function refreshAccessToken(credential, signal) {
1337
+ const clientId = credential.clientId;
1338
+ if (typeof clientId !== "string" || clientId.trim().length === 0) {
1339
+ throw new Error("Stored OpenAI OAuth credential does not contain an issued client ID; reconnect ChatGPT");
1340
+ }
1341
+ const token = await requestToken(new URLSearchParams({
1342
+ grant_type: "refresh_token",
1343
+ client_id: clientId,
1344
+ refresh_token: credential.refresh,
1345
+ resource: RESOURCE
1346
+ }), signal);
1347
+ return credentialFromTokenResponse(token, clientId);
1348
+ }
1349
+ function agentHostId(deviceId) {
1350
+ if (!deviceId || !UUID_PATTERN.test(deviceId)) {
1351
+ throw new Error("Sign in with ChatGPT requires a device ID (UUID) for this installation");
1352
+ }
1353
+ return `urn:uuid:${deviceId.toLowerCase()}`;
1354
+ }
1355
+ async function loginOpenAIChatGPT(interaction, options) {
1356
+ const hostId = agentHostId(options?.getDeviceId?.());
1357
+ const { verifier, challenge } = await generatePKCE();
1358
+ const state = randomValue();
1359
+ const nonce = randomValue();
1360
+ let callback;
1361
+ try {
1362
+ callback = await startCallbackServer(state);
1363
+ } catch (error) {
1364
+ interaction.notify({
1365
+ type: "info",
1366
+ message: `Could not listen on ${REDIRECT_URI2}; paste the final redirect URL to continue. ${error instanceof Error ? error.message : String(error)}`
1367
+ });
1368
+ }
1369
+ const authorizationUrl = new URL(AUTHORIZE_URL2);
1370
+ authorizationUrl.search = new URLSearchParams({
1371
+ client_id: DYNAMIC_CLIENT_ID,
1372
+ agent_name_hint: AGENT_NAME_HINT,
1373
+ ext_agent_host_id: hostId,
1374
+ response_type: "code",
1375
+ redirect_uri: REDIRECT_URI2,
1376
+ resource: RESOURCE,
1377
+ scope: SCOPE,
1378
+ state,
1379
+ code_challenge: challenge,
1380
+ code_challenge_method: "S256",
1381
+ nonce
1382
+ }).toString();
1383
+ interaction.notify({
1384
+ type: "auth_url",
1385
+ url: authorizationUrl.toString(),
1386
+ instructions: "Complete sign-in in your browser. If the callback does not complete, paste the final redirect URL here."
1387
+ });
1388
+ const manualAbort = new AbortController;
1389
+ const manualCode = interaction.prompt({
1390
+ type: "manual_code",
1391
+ message: "Complete login in your browser, or paste the final redirect URL here:",
1392
+ placeholder: REDIRECT_URI2,
1393
+ signal: AbortSignal.any([manualAbort.signal, interaction.signal])
1394
+ }).then((input) => authorizationResultFromManualInput(input, state));
1395
+ try {
1396
+ const result = await (callback ? Promise.race([callback.result, manualCode]) : manualCode);
1397
+ interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
1398
+ return await exchangeAuthorizationCode2(result.code, verifier, result.clientId, interaction.signal);
1399
+ } catch (error) {
1400
+ if (interaction.signal.aborted)
1401
+ throw new Error("Login cancelled");
1402
+ throw error;
1403
+ } finally {
1404
+ manualAbort.abort();
1405
+ callback?.server.close();
1406
+ callback?.server.closeAllConnections();
1407
+ }
1408
+ }
1409
+ var openaiChatGPTOAuth = {
1410
+ name: "OpenAI (ChatGPT subscription)",
1411
+ isSubscription: true,
1412
+ loginLabel: "Sign in with ChatGPT",
1413
+ login: loginOpenAIChatGPT,
1414
+ refresh: refreshAccessToken,
1415
+ async toAuth(credential) {
1416
+ return { apiKey: credential.access };
1417
+ }
1418
+ };
1419
+
1580
1420
  // node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js
1581
1421
  var _randomBytes = null;
1582
- var _http = null;
1583
1422
  if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
1584
1423
  import("node:crypto").then((m) => {
1585
1424
  _randomBytes = m.randomBytes;
1586
1425
  });
1587
- import("node:http").then((m) => {
1588
- _http = m;
1589
- });
1590
1426
  }
1591
1427
  var CLIENT_ID5 = "app_EMoamEEZ73f0CkXaXp7hrann";
1592
1428
  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";
1429
+ var AUTHORIZE_URL3 = `${AUTH_BASE_URL}/oauth/authorize`;
1430
+ var TOKEN_URL3 = `${AUTH_BASE_URL}/oauth/token`;
1431
+ var REDIRECT_URI3 = "http://localhost:1455/auth/callback";
1596
1432
  var DEVICE_USER_CODE_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/usercode`;
1597
1433
  var DEVICE_TOKEN_URL2 = `${AUTH_BASE_URL}/api/accounts/deviceauth/token`;
1598
1434
  var DEVICE_VERIFICATION_URI = `${AUTH_BASE_URL}/codex/device`;
@@ -1600,7 +1436,7 @@ var DEVICE_REDIRECT_URI = `${AUTH_BASE_URL}/deviceauth/callback`;
1600
1436
  var DEVICE_CODE_TIMEOUT_SECONDS2 = 900;
1601
1437
  var OPENAI_CODEX_BROWSER_LOGIN_METHOD = "browser";
1602
1438
  var OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD = "device_code";
1603
- var SCOPE = "openid profile email offline_access";
1439
+ var SCOPE2 = "openid profile email offline_access";
1604
1440
  var JWT_CLAIM_PATH = "https://api.openai.com/auth";
1605
1441
  function getCallbackHost() {
1606
1442
  return getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
@@ -1673,8 +1509,8 @@ async function readTokenResponse(response, operation) {
1673
1509
  expires: Date.now() + json.expires_in * 1000
1674
1510
  };
1675
1511
  }
1676
- async function exchangeAuthorizationCode2(code, verifier, redirectUri, signal) {
1677
- const response = await fetchWithLoginCancellation(TOKEN_URL2, {
1512
+ async function exchangeAuthorizationCode3(code, verifier, redirectUri, signal) {
1513
+ const response = await fetchWithLoginCancellation(TOKEN_URL3, {
1678
1514
  method: "POST",
1679
1515
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
1680
1516
  body: new URLSearchParams({
@@ -1688,10 +1524,10 @@ async function exchangeAuthorizationCode2(code, verifier, redirectUri, signal) {
1688
1524
  });
1689
1525
  return readTokenResponse(response, "exchange");
1690
1526
  }
1691
- async function refreshAccessToken(refreshToken2, signal) {
1527
+ async function refreshAccessToken2(refreshToken2, signal) {
1692
1528
  let response;
1693
1529
  try {
1694
- response = await fetch(TOKEN_URL2, {
1530
+ response = await fetch(TOKEN_URL3, {
1695
1531
  method: "POST",
1696
1532
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
1697
1533
  body: new URLSearchParams({
@@ -1787,11 +1623,11 @@ async function pollOpenAICodexDeviceAuth(device, signal) {
1787
1623
  async function createAuthorizationFlow(originator = "pi") {
1788
1624
  const { verifier, challenge } = await generatePKCE();
1789
1625
  const state = createState();
1790
- const url = new URL(AUTHORIZE_URL2);
1626
+ const url = new URL(AUTHORIZE_URL3);
1791
1627
  url.searchParams.set("response_type", "code");
1792
1628
  url.searchParams.set("client_id", CLIENT_ID5);
1793
- url.searchParams.set("redirect_uri", REDIRECT_URI2);
1794
- url.searchParams.set("scope", SCOPE);
1629
+ url.searchParams.set("redirect_uri", REDIRECT_URI3);
1630
+ url.searchParams.set("scope", SCOPE2);
1795
1631
  url.searchParams.set("code_challenge", challenge);
1796
1632
  url.searchParams.set("code_challenge_method", "S256");
1797
1633
  url.searchParams.set("state", state);
@@ -1800,75 +1636,6 @@ async function createAuthorizationFlow(originator = "pi") {
1800
1636
  url.searchParams.set("originator", originator);
1801
1637
  return { verifier, state, url: url.toString() };
1802
1638
  }
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
1639
  function getAccountId(accessToken) {
1873
1640
  const payload = decodeJwt(accessToken);
1874
1641
  const auth = payload?.[JWT_CLAIM_PATH];
@@ -1889,7 +1656,7 @@ function credentialsFromToken(token) {
1889
1656
  };
1890
1657
  }
1891
1658
  async function exchangeAuthorizationCodeForCredentials(code, verifier, redirectUri, signal) {
1892
- return credentialsFromToken(await exchangeAuthorizationCode2(code, verifier, redirectUri, signal));
1659
+ return credentialsFromToken(await exchangeAuthorizationCode3(code, verifier, redirectUri, signal));
1893
1660
  }
1894
1661
  async function loginOpenAICodexDeviceCode(interaction) {
1895
1662
  const device = await startOpenAICodexDeviceAuth(interaction.signal);
@@ -1905,66 +1672,45 @@ async function loginOpenAICodexDeviceCode(interaction) {
1905
1672
  }
1906
1673
  async function loginOpenAICodex(interaction) {
1907
1674
  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;
1675
+ const callback = await startOAuthCallbackServer({
1676
+ providerName: "OpenAI",
1677
+ host: getCallbackHost(),
1678
+ port: 1455,
1679
+ path: "/auth/callback",
1680
+ state,
1681
+ complete: async (code) => code,
1682
+ signal: interaction.signal
1683
+ }).catch(() => {
1684
+ return;
1685
+ });
1917
1686
  interaction.notify({
1918
1687
  type: "auth_url",
1919
1688
  url,
1920
1689
  instructions: "A browser window should open. Complete login to finish."
1921
1690
  });
1922
1691
  try {
1923
- const manualPromise = interaction.prompt({
1924
- type: "manual_code",
1692
+ const result = await waitForCallbackOrManualInput(interaction, callback, {
1925
1693
  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();
1694
+ placeholder: REDIRECT_URI3
1934
1695
  });
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);
1696
+ let code;
1697
+ if (result.type === "callback") {
1698
+ code = result.value;
1699
+ } else {
1700
+ const parsed = parseAuthorizationInput2(result.input);
1942
1701
  if (parsed.state && parsed.state !== state)
1943
1702
  throw new Error("State mismatch");
1944
1703
  code = parsed.code;
1945
1704
  }
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
1705
  if (!code)
1958
1706
  throw new Error("Missing authorization code");
1959
- return exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI2, interaction.signal);
1707
+ return await exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI3, interaction.signal);
1960
1708
  } finally {
1961
- interaction.signal.removeEventListener("abort", onAbort);
1962
- manualAbort.abort();
1963
- server.close();
1709
+ callback?.close();
1964
1710
  }
1965
1711
  }
1966
1712
  async function refreshOpenAICodexToken(refreshToken2, signal) {
1967
- return credentialsFromToken(await refreshAccessToken(refreshToken2, signal));
1713
+ return credentialsFromToken(await refreshAccessToken2(refreshToken2, signal));
1968
1714
  }
1969
1715
  var openaiCodexOAuth = {
1970
1716
  name: "OpenAI (ChatGPT Plus/Pro)",
@@ -1993,20 +1739,13 @@ var openaiCodexOAuth = {
1993
1739
  };
1994
1740
 
1995
1741
  // 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";
1742
+ var AUTHORIZE_URL4 = "https://openrouter.ai/auth";
1743
+ var TOKEN_URL4 = "https://openrouter.ai/api/v1/auth/keys";
1999
1744
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
2000
1745
  var TOKEN_EXCHANGE_TIMEOUT_MS = 30000;
2001
1746
  function getCallbackHost2() {
2002
1747
  return getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
2003
1748
  }
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
1749
  function parseAuthorizationInput3(input) {
2011
1750
  const value = input.trim();
2012
1751
  if (!value)
@@ -2033,7 +1772,7 @@ function errorDetail2(body) {
2033
1772
  }
2034
1773
  return;
2035
1774
  }
2036
- async function exchangeAuthorizationCode3(code, verifier, signal) {
1775
+ async function exchangeAuthorizationCode4(code, verifier, signal) {
2037
1776
  if (signal.aborted)
2038
1777
  throw new Error("Login cancelled");
2039
1778
  const controller = new AbortController;
@@ -2043,7 +1782,7 @@ async function exchangeAuthorizationCode3(code, verifier, signal) {
2043
1782
  let response;
2044
1783
  let body = {};
2045
1784
  try {
2046
- response = await fetch(TOKEN_URL3, {
1785
+ response = await fetch(TOKEN_URL4, {
2047
1786
  method: "POST",
2048
1787
  headers: { accept: "application/json", "content-type": "application/json" },
2049
1788
  body: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" }),
@@ -2081,153 +1820,45 @@ async function exchangeAuthorizationCode3(code, verifier, signal) {
2081
1820
  expires: Number.MAX_SAFE_INTEGER
2082
1821
  };
2083
1822
  }
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
1823
  async function loginOpenRouter(interaction) {
2182
1824
  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;
1825
+ const callback = await startOAuthCallbackServer({
1826
+ providerName: "OpenRouter",
1827
+ host: getCallbackHost2(),
1828
+ port: 0,
1829
+ path: `/oauth/callback/${crypto.randomUUID()}`,
1830
+ complete: (code) => exchangeAuthorizationCode4(code, verifier, interaction.signal),
1831
+ signal: interaction.signal,
1832
+ timeoutMs: LOGIN_TIMEOUT_MS
1833
+ });
2188
1834
  try {
2189
- const authorizeUrl = new URL(AUTHORIZE_URL3);
1835
+ const authorizeUrl = new URL(AUTHORIZE_URL4);
2190
1836
  authorizeUrl.search = new URLSearchParams({
2191
- callback_url: callback.callbackUrl,
1837
+ callback_url: callback.redirectUri,
2192
1838
  code_challenge: challenge,
2193
1839
  code_challenge_method: "S256"
2194
1840
  }).toString();
2195
1841
  interaction.notify({
2196
1842
  type: "progress",
2197
- message: `Listening for OpenRouter OAuth callback on ${callback.callbackUrl}`
1843
+ message: `Listening for OpenRouter OAuth callback on ${callback.redirectUri}`
2198
1844
  });
2199
1845
  interaction.notify({
2200
1846
  type: "auth_url",
2201
1847
  url: authorizeUrl.toString(),
2202
1848
  instructions: "Complete sign-in in your browser. If the browser is on another machine, paste the final redirect URL here."
2203
1849
  });
2204
- const manualPromise = interaction.prompt({
2205
- type: "manual_code",
1850
+ const result = await waitForCallbackOrManualInput(interaction, callback, {
2206
1851
  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();
1852
+ placeholder: callback.redirectUri
2215
1853
  });
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;
1854
+ if (result.type === "callback")
1855
+ return result.value;
1856
+ const code = parseAuthorizationInput3(result.input);
2225
1857
  if (!code)
2226
1858
  throw new Error("Missing authorization code");
2227
1859
  interaction.notify({ type: "progress", message: "Exchanging authorization code for an API key..." });
2228
- return await exchangeAuthorizationCode3(code, verifier, interaction.signal);
1860
+ return await exchangeAuthorizationCode4(code, verifier, interaction.signal);
2229
1861
  } finally {
2230
- manualAbort.abort();
2231
1862
  callback.close();
2232
1863
  }
2233
1864
  }
@@ -2244,16 +1875,10 @@ var openRouterOAuth = {
2244
1875
  };
2245
1876
 
2246
1877
  // 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}`;
1878
+ var CALLBACK_HOST3 = "127.0.0.1";
1879
+ var CALLBACK_PORT3 = 1456;
1880
+ var CALLBACK_PATH3 = "/oauth/callback";
1881
+ var REDIRECT_URI4 = `http://${CALLBACK_HOST3}:${CALLBACK_PORT3}${CALLBACK_PATH3}`;
2257
1882
  var TOKEN_EXPIRY_SKEW_MS = 60000;
2258
1883
  var LOGIN_METHOD_BROWSER = "browser";
2259
1884
  var LOGIN_METHOD_DEVICE_CODE = "device-code";
@@ -2327,69 +1952,6 @@ async function requestOAuthToken(gateway, body, signal) {
2327
1952
  scope: data.scope
2328
1953
  };
2329
1954
  }
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
1955
  async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
2394
1956
  const { verifier, challenge } = await generatePKCE();
2395
1957
  const state = crypto.randomUUID();
@@ -2397,37 +1959,41 @@ async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
2397
1959
  authorizeUrl.search = new URLSearchParams({
2398
1960
  response_type: "code",
2399
1961
  client_id: OAUTH_CLIENT_ID,
2400
- redirect_uri: REDIRECT_URI3,
1962
+ redirect_uri: REDIRECT_URI4,
2401
1963
  scope: OAUTH_SCOPE,
2402
1964
  code_challenge: challenge,
2403
1965
  code_challenge_method: "S256",
2404
1966
  handoff: "url",
2405
1967
  state
2406
1968
  }).toString();
2407
- const callbackServer = await startOAuthCallbackServer(state, interaction.signal);
2408
- interaction.notify({ type: "progress", message: `Listening for OAuth callback on ${REDIRECT_URI3}` });
1969
+ const callback = await startOAuthCallbackServer({
1970
+ providerName: "Radius",
1971
+ host: CALLBACK_HOST3,
1972
+ port: CALLBACK_PORT3,
1973
+ path: CALLBACK_PATH3,
1974
+ state,
1975
+ complete: (code) => requestOAuthToken(gateway, new URLSearchParams({
1976
+ grant_type: "authorization_code",
1977
+ client_id: OAUTH_CLIENT_ID,
1978
+ redirect_uri: REDIRECT_URI4,
1979
+ code,
1980
+ code_verifier: verifier
1981
+ }), interaction.signal),
1982
+ signal: interaction.signal
1983
+ });
1984
+ interaction.notify({ type: "progress", message: `Listening for OAuth callback on ${REDIRECT_URI4}` });
2409
1985
  interaction.notify({
2410
1986
  type: "auth_url",
2411
1987
  url: authorizeUrl.toString(),
2412
1988
  instructions: "Continue in your browser."
2413
1989
  });
2414
1990
  try {
2415
- const code = await callbackServer.waitForCode();
2416
- if (!code) {
2417
- if (interaction.signal.aborted) {
2418
- throw new Error("Login cancelled");
2419
- }
1991
+ const credential = await callback.wait();
1992
+ if (!credential)
2420
1993
  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);
1994
+ return credential;
2429
1995
  } finally {
2430
- callbackServer.close();
1996
+ callback.close();
2431
1997
  }
2432
1998
  }
2433
1999
  async function requestDeviceAuthorization(gateway, signal) {
@@ -2719,6 +2285,7 @@ function registerBunOAuthFlows() {
2719
2285
  registerBundledOAuthFlowLoaders({
2720
2286
  anthropic: () => anthropicOAuth,
2721
2287
  openaiCodex: () => openaiCodexOAuth,
2288
+ openaiChatGPT: () => openaiChatGPTOAuth,
2722
2289
  githubCopilot: () => githubCopilotOAuth,
2723
2290
  openrouter: () => openRouterOAuth,
2724
2291
  kimiCoding: () => kimiCodingOAuth,
@@ -2825,4 +2392,4 @@ async function resolveCredential(opts = {}) {
2825
2392
  return null;
2826
2393
  }
2827
2394
 
2828
- export { DEFAULT_MODEL, parseModelStr, resolveCredential, getMemoryRaterNames, REFERENCES_SOURCE_MAX_LENGTH, sanitizeReferencesSource, SummaryWithRatingsSchema, BASE_SUMMARIZE_PROMPT, LlmRater, buildRatingsFromLlm, buildSummaryWithRatingsPrompt, isLlmRaterEnabled, dedupeRetrievalsForRater, fetchRetrievalsForTask, postRatings };
2395
+ export { DEFAULT_MODEL, parseModelStr, resolveCredential };