zidane 7.2.4 → 8.0.4

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 (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -6
  3. package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
  4. package/dist/acp-DQDhi2dj.js.map +1 -0
  5. package/dist/acp-cli.d.ts +1 -1
  6. package/dist/acp-cli.js +9 -66
  7. package/dist/acp-cli.js.map +1 -1
  8. package/dist/acp.d.ts +10 -590
  9. package/dist/acp.d.ts.map +1 -1
  10. package/dist/acp.js +3 -3
  11. package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
  12. package/dist/agent-DSLNmBp0.js.map +1 -0
  13. package/dist/agent.d.ts +1 -1
  14. package/dist/agent.js +3 -2
  15. package/dist/aliasing-lVFbm81n.js +217 -0
  16. package/dist/aliasing-lVFbm81n.js.map +1 -0
  17. package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
  18. package/dist/anthropic-CD00LhUP.js.map +1 -0
  19. package/dist/artifacts-CV2hUKnL.js.map +1 -1
  20. package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
  21. package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
  22. package/dist/call-tool-dHlbGOIY.js +70 -0
  23. package/dist/call-tool-dHlbGOIY.js.map +1 -0
  24. package/dist/chat/pure.d.ts +372 -6
  25. package/dist/chat/pure.d.ts.map +1 -1
  26. package/dist/chat/pure.js +35 -244
  27. package/dist/chat/pure.js.map +1 -1
  28. package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
  29. package/dist/chat-JPJJ8uu5.js.map +1 -0
  30. package/dist/chat.d.ts +4 -6
  31. package/dist/chat.js +23 -12
  32. package/dist/cli-shared-C-YCaglL.js +159 -0
  33. package/dist/cli-shared-C-YCaglL.js.map +1 -0
  34. package/dist/client-core-BQSyDALT.d.ts +2115 -0
  35. package/dist/client-core-BQSyDALT.d.ts.map +1 -0
  36. package/dist/codemode-worker.d.ts +1 -0
  37. package/dist/codemode-worker.js +155 -0
  38. package/dist/codemode-worker.js.map +1 -0
  39. package/dist/codemode.d.ts +352 -0
  40. package/dist/codemode.d.ts.map +1 -0
  41. package/dist/codemode.js +5 -0
  42. package/dist/connection-Dr-Js4yZ.d.ts +28 -0
  43. package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
  44. package/dist/connection-loop-gdh22LTI.js +112 -0
  45. package/dist/connection-loop-gdh22LTI.js.map +1 -0
  46. package/dist/context-segments-BHKlagL6.js +1016 -0
  47. package/dist/context-segments-BHKlagL6.js.map +1 -0
  48. package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
  49. package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
  50. package/dist/contexts/daytona.d.ts +19 -8
  51. package/dist/contexts/daytona.d.ts.map +1 -1
  52. package/dist/contexts/daytona.js +1 -440
  53. package/dist/contexts/docker.d.ts +36 -7
  54. package/dist/contexts/docker.d.ts.map +1 -1
  55. package/dist/contexts/docker.js +1 -456
  56. package/dist/contexts/e2b.d.ts +68 -13
  57. package/dist/contexts/e2b.d.ts.map +1 -1
  58. package/dist/contexts/e2b.js +1 -382
  59. package/dist/contexts/sandbox.d.ts +1 -1
  60. package/dist/contexts/sandbox.js +5 -0
  61. package/dist/contexts/sandbox.js.map +1 -1
  62. package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
  63. package/dist/contexts-d7UolYot.js.map +1 -0
  64. package/dist/contexts.d.ts +3 -3
  65. package/dist/contexts.js +1 -1
  66. package/dist/cred-keys-GpBg71cP.js +105 -0
  67. package/dist/cred-keys-GpBg71cP.js.map +1 -0
  68. package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
  69. package/dist/credentials-JttEuRON.js.map +1 -0
  70. package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
  71. package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
  72. package/dist/daemon-cli.d.ts +1 -1
  73. package/dist/daemon-cli.js +3 -2
  74. package/dist/daemon-cli.js.map +1 -1
  75. package/dist/daytona-DG3omipZ.js +513 -0
  76. package/dist/daytona-DG3omipZ.js.map +1 -0
  77. package/dist/defaults-Cx3zvDOV.js +23 -0
  78. package/dist/defaults-Cx3zvDOV.js.map +1 -0
  79. package/dist/dispatcher-BMlu2BmZ.js +4941 -0
  80. package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
  81. package/dist/docker-BZhMMJUp.js +727 -0
  82. package/dist/docker-BZhMMJUp.js.map +1 -0
  83. package/dist/e2b-CEVOdRib.js +480 -0
  84. package/dist/e2b-CEVOdRib.js.map +1 -0
  85. package/dist/edit-utils-EGosADZq.js +234 -0
  86. package/dist/edit-utils-EGosADZq.js.map +1 -0
  87. package/dist/environment-8wsKE2Ln.js +214 -0
  88. package/dist/environment-8wsKE2Ln.js.map +1 -0
  89. package/dist/eval-BNcvle_J.js +1595 -0
  90. package/dist/eval-BNcvle_J.js.map +1 -0
  91. package/dist/eval.d.ts +2 -2
  92. package/dist/eval.js +1 -1489
  93. package/dist/executor-Cx5-8yqi.js +621 -0
  94. package/dist/executor-Cx5-8yqi.js.map +1 -0
  95. package/dist/extension-authoring-DyGGmq9V.js +385 -0
  96. package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
  97. package/dist/extensions.d.ts +2 -2
  98. package/dist/extensions.js +3 -3
  99. package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
  100. package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
  101. package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
  102. package/dist/format-C2NQEVUH.js.map +1 -0
  103. package/dist/format-bytes-C7tfc3Zm.js +55 -0
  104. package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
  105. package/dist/headless-C_rNUuYC.js +960 -0
  106. package/dist/headless-C_rNUuYC.js.map +1 -0
  107. package/dist/headless.d.ts +1 -1
  108. package/dist/headless.js +1 -413
  109. package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
  110. package/dist/history-search-CcYzF8-0.js.map +1 -0
  111. package/dist/history-search-worker.d.ts +1 -1
  112. package/dist/history-search-worker.js +1 -1
  113. package/dist/host-D7NrI03V.js +378 -0
  114. package/dist/host-D7NrI03V.js.map +1 -0
  115. package/dist/host-signals-BcP5QKUD.js +118 -0
  116. package/dist/host-signals-BcP5QKUD.js.map +1 -0
  117. package/dist/identity-CwfO8K-t.js +26 -0
  118. package/dist/identity-CwfO8K-t.js.map +1 -0
  119. package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
  120. package/dist/index-BGe1fQT7.d.ts.map +1 -0
  121. package/dist/index-BVQsIKGn.d.ts +448 -0
  122. package/dist/index-BVQsIKGn.d.ts.map +1 -0
  123. package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
  124. package/dist/index-CHABJd-L.d.ts.map +1 -0
  125. package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
  126. package/dist/index-D6a7qXpg.d.ts.map +1 -0
  127. package/dist/index.d.ts +6 -6
  128. package/dist/index.js +27 -23
  129. package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
  130. package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
  131. package/dist/ipc/remote.d.ts +313 -0
  132. package/dist/ipc/remote.d.ts.map +1 -0
  133. package/dist/ipc/remote.js +4 -0
  134. package/dist/ipc.d.ts +6 -964
  135. package/dist/ipc.js +403 -4
  136. package/dist/ipc.js.map +1 -0
  137. package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
  138. package/dist/isolation-D9L650W5.d.ts.map +1 -0
  139. package/dist/json-rpc--HXQti1E.js +350 -0
  140. package/dist/json-rpc--HXQti1E.js.map +1 -0
  141. package/dist/links-j8rED1sR.js +603 -0
  142. package/dist/links-j8rED1sR.js.map +1 -0
  143. package/dist/local-terminal-D8QThwo_.js +252 -0
  144. package/dist/local-terminal-D8QThwo_.js.map +1 -0
  145. package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
  146. package/dist/logger-Gtqlayx8.js.map +1 -0
  147. package/dist/logs-view-CWG8aUAG.js.map +1 -1
  148. package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
  149. package/dist/mcp-_wecH9Qe.js.map +1 -0
  150. package/dist/mcp.d.ts +2 -2
  151. package/dist/mcp.js +2 -2
  152. package/dist/media-sniff-UKijEaiQ.js.map +1 -1
  153. package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
  154. package/dist/messages-BqiwcD2Q.js.map +1 -0
  155. package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
  156. package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
  157. package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
  158. package/dist/openai-compat-CFrpH7uq.js.map +1 -0
  159. package/dist/orchestration-BCGmB8Ps.js +511 -0
  160. package/dist/orchestration-BCGmB8Ps.js.map +1 -0
  161. package/dist/output/stream-json.d.ts +1 -2
  162. package/dist/output/stream-json.d.ts.map +1 -1
  163. package/dist/output/stream-json.js +1 -1
  164. package/dist/output/terminal.d.ts +1 -2
  165. package/dist/output/terminal.d.ts.map +1 -1
  166. package/dist/output/terminal.js +13 -7
  167. package/dist/output/terminal.js.map +1 -1
  168. package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
  169. package/dist/plugins-DS7mahzZ.js.map +1 -0
  170. package/dist/plugins.d.ts +1 -1
  171. package/dist/plugins.js +1 -2
  172. package/dist/prelude-Cxo4t74B.js +517 -0
  173. package/dist/prelude-Cxo4t74B.js.map +1 -0
  174. package/dist/presets.d.ts +1 -1
  175. package/dist/presets.js +1 -2
  176. package/dist/project-root-B8zADr4o.js +167 -0
  177. package/dist/project-root-B8zADr4o.js.map +1 -0
  178. package/dist/project-user-paths-BSgtrRxl.js +58 -0
  179. package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
  180. package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
  181. package/dist/prompts-DYcvqShf.d.ts.map +1 -0
  182. package/dist/protocol-DnhqqSmE.js +13 -0
  183. package/dist/protocol-DnhqqSmE.js.map +1 -0
  184. package/dist/providers/anthropic.d.ts +2 -2
  185. package/dist/providers/anthropic.js +1 -2
  186. package/dist/providers/arcee.d.ts +1 -1
  187. package/dist/providers/arcee.js +1 -1
  188. package/dist/providers/baseten.d.ts +1 -1
  189. package/dist/providers/baseten.js +1 -1
  190. package/dist/providers/cerebras.d.ts +1 -1
  191. package/dist/providers/cerebras.js +3 -2
  192. package/dist/providers/cerebras.js.map +1 -1
  193. package/dist/providers/local.d.ts +1 -1
  194. package/dist/providers/local.js +1 -1
  195. package/dist/providers/openai-compat.d.ts +1 -1
  196. package/dist/providers/openai-compat.js +1 -2
  197. package/dist/providers/openai.d.ts +1 -1
  198. package/dist/providers/openai.js +15 -12
  199. package/dist/providers/openai.js.map +1 -1
  200. package/dist/providers/openrouter.d.ts +1 -1
  201. package/dist/providers/openrouter.js +3 -2
  202. package/dist/providers/openrouter.js.map +1 -1
  203. package/dist/providers/xai.d.ts +1 -1
  204. package/dist/providers/xai.js +3 -3
  205. package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
  206. package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
  207. package/dist/providers.d.ts +1 -1
  208. package/dist/providers.js +4 -4
  209. package/dist/registry-D6ShBWJU.js +5234 -0
  210. package/dist/registry-D6ShBWJU.js.map +1 -0
  211. package/dist/remote-hosts-BtA_9ZGp.js +97 -0
  212. package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
  213. package/dist/restate.d.ts +2 -3
  214. package/dist/restate.d.ts.map +1 -1
  215. package/dist/restate.js +631 -572
  216. package/dist/restate.js.map +1 -1
  217. package/dist/run-summary-CklLiZ4y.js +288 -0
  218. package/dist/run-summary-CklLiZ4y.js.map +1 -0
  219. package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
  220. package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
  221. package/dist/session/sqlite.d.ts +1 -2
  222. package/dist/session/sqlite.d.ts.map +1 -1
  223. package/dist/session/sqlite.js +1 -616
  224. package/dist/session-factory-BUGY5P40.js +1576 -0
  225. package/dist/session-factory-BUGY5P40.js.map +1 -0
  226. package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
  227. package/dist/session-xh9JXu6i.js.map +1 -0
  228. package/dist/session.d.ts +1 -1
  229. package/dist/session.js +2 -2
  230. package/dist/settings-keys-Ckf29NeM.js +677 -0
  231. package/dist/settings-keys-Ckf29NeM.js.map +1 -0
  232. package/dist/shell-path-Dqaoow2J.js +412 -0
  233. package/dist/shell-path-Dqaoow2J.js.map +1 -0
  234. package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
  235. package/dist/skills-DKqZJm4X.js.map +1 -0
  236. package/dist/skills.d.ts +2 -2
  237. package/dist/skills.js +1 -2
  238. package/dist/source-mPExaUm8.js +381 -0
  239. package/dist/source-mPExaUm8.js.map +1 -0
  240. package/dist/sqlite-DV1DQzN2.js +698 -0
  241. package/dist/sqlite-DV1DQzN2.js.map +1 -0
  242. package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
  243. package/dist/src-BRMYRJib.js.map +1 -0
  244. package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
  245. package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
  246. package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
  247. package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
  248. package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
  249. package/dist/timeout-DEaqslLO.d.ts.map +1 -1
  250. package/dist/todo-edits-Dn251YUP.js +1790 -0
  251. package/dist/todo-edits-Dn251YUP.js.map +1 -0
  252. package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
  253. package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
  254. package/dist/tool-state-Dku6YqAB.js +989 -0
  255. package/dist/tool-state-Dku6YqAB.js.map +1 -0
  256. package/dist/tools/fetch-url.d.ts +1 -2
  257. package/dist/tools/fetch-url.d.ts.map +1 -1
  258. package/dist/tools/fetch-url.js +1 -2
  259. package/dist/tools/prompts.d.ts +1 -1
  260. package/dist/tools/prompts.js +7 -7
  261. package/dist/tools/prompts.js.map +1 -1
  262. package/dist/tools/web-search.d.ts +1 -2
  263. package/dist/tools/web-search.d.ts.map +1 -1
  264. package/dist/tools/web-search.js +2 -2
  265. package/dist/tools/web-search.js.map +1 -1
  266. package/dist/tools-_DnT3AGM.js +578 -0
  267. package/dist/tools-_DnT3AGM.js.map +1 -0
  268. package/dist/tools.d.ts +3 -3
  269. package/dist/tools.js +4 -2
  270. package/dist/tui.d.ts +534 -517
  271. package/dist/tui.d.ts.map +1 -1
  272. package/dist/tui.js +34933 -27242
  273. package/dist/tui.js.map +1 -1
  274. package/dist/turn-operations-B8sokwi5.js +333 -0
  275. package/dist/turn-operations-B8sokwi5.js.map +1 -0
  276. package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
  277. package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
  278. package/dist/types-C7ZFOztE.d.ts +132 -0
  279. package/dist/types-C7ZFOztE.d.ts.map +1 -0
  280. package/dist/types-CH5XpIHw.js +114 -0
  281. package/dist/types-CH5XpIHw.js.map +1 -0
  282. package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
  283. package/dist/types-Cu0ZGDu9.js.map +1 -0
  284. package/dist/types-IqegbJEE.d.ts +624 -0
  285. package/dist/types-IqegbJEE.d.ts.map +1 -0
  286. package/dist/types.d.ts +4 -4
  287. package/dist/types.js +1 -1
  288. package/dist/url-D8HCl65b.js +1259 -0
  289. package/dist/url-D8HCl65b.js.map +1 -0
  290. package/dist/wasm-BVT-j5cl.js +33 -0
  291. package/dist/wasm-BVT-j5cl.js.map +1 -0
  292. package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
  293. package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
  294. package/dist/ws-CIHMvlSh.js +952 -0
  295. package/dist/ws-CIHMvlSh.js.map +1 -0
  296. package/dist/ws-client-N7NxzvQp.js +230 -0
  297. package/dist/ws-client-N7NxzvQp.js.map +1 -0
  298. package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
  299. package/dist/xai-CvJTeLrI.js.map +1 -0
  300. package/dist/xdg-zweed0-t.js +117 -0
  301. package/dist/xdg-zweed0-t.js.map +1 -0
  302. package/docs/ACP.md +52 -0
  303. package/docs/ARCHITECTURE.md +103 -6
  304. package/docs/ARTIFACTS.md +8 -4
  305. package/docs/CHAT.md +165 -14
  306. package/docs/EXECUTION_CONTEXT.md +8 -0
  307. package/docs/EXTENSIONS.md +123 -2
  308. package/docs/HEADLESS.md +2 -0
  309. package/docs/IPC.md +775 -64
  310. package/docs/MACHINES.md +456 -0
  311. package/docs/PANELS.md +3 -0
  312. package/docs/README.md +4 -0
  313. package/docs/RESTATE.md +3 -2
  314. package/docs/RUN_IN_BACKGROUND.md +10 -2
  315. package/docs/SERVER.md +1085 -0
  316. package/docs/SKILL.md +6 -1
  317. package/docs/TERMINAL.md +75 -0
  318. package/docs/TUI.md +65 -14
  319. package/package.json +58 -26
  320. package/scripts/eval.ts +4 -0
  321. package/dist/acp-D-tVyUjw.js.map +0 -1
  322. package/dist/agent-D0zZnGbt.js.map +0 -1
  323. package/dist/anthropic-C2aole0G.js.map +0 -1
  324. package/dist/approvals-DKaJZYlm.js.map +0 -1
  325. package/dist/atomic-write-B7zr1ddF.js.map +0 -1
  326. package/dist/auth-BG2rVKSt.js.map +0 -1
  327. package/dist/completion-core-BRo86R_L.js.map +0 -1
  328. package/dist/contexts/daytona.js.map +0 -1
  329. package/dist/contexts/docker.js.map +0 -1
  330. package/dist/contexts/e2b.js.map +0 -1
  331. package/dist/contexts-CRE9pw07.js.map +0 -1
  332. package/dist/eval.js.map +0 -1
  333. package/dist/format-BF745pLL.js.map +0 -1
  334. package/dist/glob-DluQFSw1.js +0 -270
  335. package/dist/glob-DluQFSw1.js.map +0 -1
  336. package/dist/headless.js.map +0 -1
  337. package/dist/history-search-C4bk1Wz_.js.map +0 -1
  338. package/dist/index-BgN1T3lk.d.ts.map +0 -1
  339. package/dist/index-C37_ppWv.d.ts.map +0 -1
  340. package/dist/index-C6NEd5y_.d.ts.map +0 -1
  341. package/dist/ipc-zVSyo6K1.js +0 -331
  342. package/dist/ipc-zVSyo6K1.js.map +0 -1
  343. package/dist/ipc.d.ts.map +0 -1
  344. package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
  345. package/dist/json-rpc-rSWMUh9b.js +0 -192
  346. package/dist/json-rpc-rSWMUh9b.js.map +0 -1
  347. package/dist/logger--C1VQjwJ.js.map +0 -1
  348. package/dist/mcp-CgNd-f3F.js.map +0 -1
  349. package/dist/messages-2jcOA_5R.js.map +0 -1
  350. package/dist/openai-compat-Dy56weK8.js.map +0 -1
  351. package/dist/output-cap-C9zukcCj.js +0 -100
  352. package/dist/output-cap-C9zukcCj.js.map +0 -1
  353. package/dist/panels-B6gRk4bf.js +0 -789
  354. package/dist/panels-B6gRk4bf.js.map +0 -1
  355. package/dist/plugins-gbI7SBA6.js.map +0 -1
  356. package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
  357. package/dist/run-summary-BU_NgwUT.js +0 -269
  358. package/dist/run-summary-BU_NgwUT.js.map +0 -1
  359. package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
  360. package/dist/session/sqlite.js.map +0 -1
  361. package/dist/session-BqRP1hS7.js.map +0 -1
  362. package/dist/shell-path-h5czzllR.js +0 -1549
  363. package/dist/shell-path-h5czzllR.js.map +0 -1
  364. package/dist/skills-BC3dodWp.js.map +0 -1
  365. package/dist/src-CkNQKFKr.js.map +0 -1
  366. package/dist/todo-edits-UOwgxGKu.js +0 -528
  367. package/dist/todo-edits-UOwgxGKu.js.map +0 -1
  368. package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
  369. package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
  370. package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
  371. package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
  372. package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
  373. package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
  374. package/dist/turn-operations-DrbJlpq9.js.map +0 -1
  375. package/dist/types-CWgENVLY.js.map +0 -1
  376. package/dist/xai-CazjStOK.js.map +0 -1
@@ -1,6 +1,131 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.js";
2
2
  import { t as generatePkce } from "./pkce-t8BcPyEi.js";
3
3
  import { createServer } from "node:http";
4
+ //#region src/chat/oauth-page/server.ts
5
+ const CALLBACK_HOST = process.env.PI_OAUTH_CALLBACK_HOST || "127.0.0.1";
6
+ /** Providers known to honor `callbackServer: false` (zidane's own loopback flows). */
7
+ const REMOTE_CALLBACK = /* @__PURE__ */ new WeakSet();
8
+ /** Mark a provider that binds no listener under `callbackServer: false`; returns it. */
9
+ function honorsRemoteCallback(provider) {
10
+ REMOTE_CALLBACK.add(provider);
11
+ return provider;
12
+ }
13
+ /**
14
+ * Whether a provider can sign in for a client of a remote host without
15
+ * listening on the host's machine: it honors `callbackServer: false`, or it
16
+ * never listens (`usesCallbackServer: false`: paste, device or polling flows).
17
+ * Others (pi-ai's stock providers, a third party's) would bind a loopback
18
+ * port on the server, which the client's browser can't reach.
19
+ */
20
+ function canSignInRemotely(provider) {
21
+ return REMOTE_CALLBACK.has(provider) || provider.usesCallbackServer === false;
22
+ }
23
+ /** Whether a provider should bind its loopback callback listener for these callbacks. */
24
+ function listensForCallback(callbacks) {
25
+ return callbacks.callbackServer !== false;
26
+ }
27
+ function buildRequestHandler(opts, pending) {
28
+ return (req, res) => {
29
+ try {
30
+ const url = new URL(req.url || "", "http://localhost");
31
+ if (url.pathname !== opts.path) {
32
+ respondError(res, 404, opts, "Callback route not found.");
33
+ return;
34
+ }
35
+ const error = url.searchParams.get("error");
36
+ if (error) {
37
+ respondError(res, 400, opts, `${opts.providerName} authentication did not complete.`, `Error: ${error}`);
38
+ return;
39
+ }
40
+ const code = url.searchParams.get("code");
41
+ const state = url.searchParams.get("state");
42
+ if (!code || !state) {
43
+ respondError(res, 400, opts, "Missing code or state parameter.");
44
+ return;
45
+ }
46
+ if (state !== opts.expectedState) {
47
+ respondError(res, 400, opts, "State mismatch.");
48
+ return;
49
+ }
50
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
51
+ res.end(opts.renderPage({
52
+ kind: "success",
53
+ provider: opts.providerName,
54
+ message: opts.successMessage
55
+ }));
56
+ pending.settle({
57
+ code,
58
+ state
59
+ });
60
+ } catch {
61
+ respondError(res, 500, opts, "Internal error while processing the callback.");
62
+ }
63
+ };
64
+ }
65
+ function respondError(res, status, opts, message, details) {
66
+ res.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
67
+ res.end(opts.renderPage({
68
+ kind: "error",
69
+ provider: opts.providerName,
70
+ message,
71
+ details
72
+ }));
73
+ }
74
+ function buildStubHandle(redirectUri, server) {
75
+ return {
76
+ redirectUri,
77
+ waitForCode: async () => null,
78
+ cancelWait: () => {},
79
+ close: () => {
80
+ try {
81
+ server?.close();
82
+ } catch {}
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * Start the loopback HTTP callback server. The returned handle is the
88
+ * caller's contract — they `await waitForCode()`, race it against manual
89
+ * paste, then `close()` in a `finally`.
90
+ */
91
+ async function startCallbackServer(opts) {
92
+ const onListenError = opts.onListenError ?? "reject";
93
+ const redirectUri = `http://localhost:${opts.port}${opts.path}`;
94
+ if (opts.listen === false) return buildStubHandle(redirectUri, null);
95
+ return new Promise((resolve, reject) => {
96
+ let settled = false;
97
+ const pending = { settle: () => {} };
98
+ const waitPromise = new Promise((resolveWait) => {
99
+ pending.settle = (value) => {
100
+ if (settled) return;
101
+ settled = true;
102
+ resolveWait(value);
103
+ };
104
+ });
105
+ const server = createServer(buildRequestHandler(opts, pending));
106
+ server.on("error", (err) => {
107
+ if (onListenError === "resolveWithStub") {
108
+ pending.settle(null);
109
+ resolve(buildStubHandle(redirectUri, server));
110
+ return;
111
+ }
112
+ reject(err);
113
+ });
114
+ server.listen(opts.port, CALLBACK_HOST, () => {
115
+ resolve({
116
+ redirectUri,
117
+ waitForCode: () => waitPromise,
118
+ cancelWait: () => pending.settle(null),
119
+ close: () => {
120
+ try {
121
+ server.close();
122
+ } catch {}
123
+ }
124
+ });
125
+ });
126
+ });
127
+ }
128
+ //#endregion
4
129
  //#region src/chat/oauth-page/xai.ts
5
130
  var xai_exports = /* @__PURE__ */ __exportAll({
6
131
  XAI_OAUTH_PROVIDER_ID: () => XAI_OAUTH_PROVIDER_ID,
@@ -87,6 +212,41 @@ async function discover() {
87
212
  };
88
213
  }
89
214
  /**
215
+ * A remote sign-in (`callbackServer: false`): nothing listens here; the
216
+ * client's loopback catches the redirect and its URL comes back through
217
+ * `onManualCodeInput`. Same redirect URI as the default listener's.
218
+ */
219
+ function remoteCallback(callbacks) {
220
+ return {
221
+ redirectUri: `http://${xaiOAuthCallbackHost()}:${xaiOAuthCallbackPort()}${CALLBACK_PATH}`,
222
+ waitForCallback: async () => {
223
+ if (!callbacks.onManualCodeInput) return {
224
+ error: "no-callback",
225
+ errorDescription: "No way to receive the xAI OAuth callback."
226
+ };
227
+ const input = (await callbacks.onManualCodeInput()).trim();
228
+ try {
229
+ const url = new URL(input);
230
+ const error = url.searchParams.get("error");
231
+ return error ? {
232
+ error,
233
+ ...url.searchParams.get("error_description") ? { errorDescription: url.searchParams.get("error_description") } : {}
234
+ } : {
235
+ ...url.searchParams.get("code") ? { code: url.searchParams.get("code") } : {},
236
+ ...url.searchParams.get("state") ? { state: url.searchParams.get("state") } : {}
237
+ };
238
+ } catch {
239
+ const params = new URLSearchParams(input.includes("=") ? input : `code=${input}`);
240
+ return {
241
+ ...params.get("code") ? { code: params.get("code") } : {},
242
+ ...params.get("state") ? { state: params.get("state") } : {}
243
+ };
244
+ }
245
+ },
246
+ close: () => void 0
247
+ };
248
+ }
249
+ /**
90
250
  * Start the loopback callback server on `127.0.0.1:56121`. Falls back to an
91
251
  * OS-assigned port if 56121 is taken — xAI accepts any loopback port as long
92
252
  * as the `redirect_uri` we send on the authorize URL matches the listener.
@@ -215,7 +375,7 @@ async function loginXai(renderPage, callbacks) {
215
375
  const { verifier, challenge } = await generatePkce();
216
376
  const state = randomToken();
217
377
  const nonce = randomToken();
218
- const server = await startXaiCallbackServer(renderPage);
378
+ const server = listensForCallback(callbacks) ? await startXaiCallbackServer(renderPage) : remoteCallback(callbacks);
219
379
  try {
220
380
  const authUrl = new URL(discovery.authorization_endpoint);
221
381
  authUrl.searchParams.set("response_type", "code");
@@ -281,16 +441,16 @@ async function refreshXaiToken(credentials) {
281
441
  * so the TUI doesn't need to prompt for a manual code paste.
282
442
  */
283
443
  function createXaiOAuthProvider(renderPage) {
284
- return {
444
+ return honorsRemoteCallback({
285
445
  id: XAI_OAUTH_PROVIDER_ID,
286
446
  name: "xAI Grok (SuperGrok / X Premium+)",
287
447
  usesCallbackServer: true,
288
448
  login: (callbacks) => loginXai(renderPage, callbacks),
289
449
  refreshToken: refreshXaiToken,
290
450
  getApiKey: (credentials) => credentials.access
291
- };
451
+ });
292
452
  }
293
453
  //#endregion
294
- export { xai_exports as i, createXaiOAuthProvider as n, xaiBaseUrl as r, XAI_OAUTH_PROVIDER_ID as t };
454
+ export { canSignInRemotely as a, startCallbackServer as c, xai_exports as i, createXaiOAuthProvider as n, honorsRemoteCallback as o, xaiBaseUrl as r, listensForCallback as s, XAI_OAUTH_PROVIDER_ID as t };
295
455
 
296
- //# sourceMappingURL=xai-CazjStOK.js.map
456
+ //# sourceMappingURL=xai-CvJTeLrI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai-CvJTeLrI.js","names":[],"sources":["../src/chat/oauth-page/server.ts","../src/chat/oauth-page/xai.ts"],"sourcesContent":["/**\n * Local HTTP callback server primitive shared by the Anthropic + Codex\n * login flows. Owns three concerns:\n *\n * 1. Bind a loopback listener (configurable port + host via\n * `PI_OAUTH_CALLBACK_HOST`, matching pi-ai's semantics).\n * 2. Parse the redirect query string into `{ code, state }` or surface\n * a structured error.\n * 3. Render the result page through the caller-supplied renderer.\n *\n * Each provider clones the lifecycle wrapper (`waitForCode` / `cancelWait`\n * / `close`) so the higher-level login code reads the same on either\n * side. The only thing the server itself decides is the HTML.\n */\n\nimport type { OAuthLoginCallbacks } from '@earendil-works/pi-ai/oauth'\nimport type { IncomingMessage, Server, ServerResponse } from 'node:http'\nimport type { OAuthCallbackPageRenderer } from './render'\nimport { createServer } from 'node:http'\n\nconst CALLBACK_HOST = process.env.PI_OAUTH_CALLBACK_HOST || '127.0.0.1'\n\nexport interface CallbackServerOptions {\n /** Loopback port. Must match the `redirect_uri` registered with the provider. */\n port: number\n /** Path component of the redirect URI (e.g. `/callback`, `/auth/callback`). */\n path: string\n /**\n * Expected `state` value. The server rejects any callback whose `state`\n * doesn't match, exactly. For Anthropic this is the PKCE verifier; for\n * Codex it's a random 16-byte hex string.\n */\n expectedState: string\n /** Display name passed through to {@link OAuthCallbackPageRenderer}. */\n providerName: string\n /** HTML renderer for both success + error pages. */\n renderPage: OAuthCallbackPageRenderer\n /** Success-page body shown after a clean redirect. */\n successMessage: string\n /**\n * How to react when `server.listen` itself fails (typically `EADDRINUSE`\n * when another instance is mid-flow). `\"reject\"` propagates the error to\n * the awaiting `start` caller; `\"resolveWithStub\"` returns a degraded\n * handle whose `waitForCode` immediately resolves to `null`, so the\n * caller can fall back to manual paste. Anthropic uses `\"reject\"`,\n * Codex uses `\"resolveWithStub\"` to match pi-ai's per-provider behavior.\n */\n onListenError?: 'reject' | 'resolveWithStub'\n /**\n * `false`: bind nothing, return the stub handle (`waitForCode` resolves\n * `null` at once) for {@link redirectUri}. A remote sign-in: the browser\n * redirects to the CLIENT's loopback, and the code comes back through the\n * provider's manual-input path (see {@link ZidaneOAuthLoginCallbacks}).\n */\n listen?: boolean\n}\n\n/**\n * pi-ai's login callbacks plus zidane's `callbackServer: false`: the\n * redirect lands on another machine (a client of a remote host), which\n * forwards the full callback URL through `onManualCodeInput`. zidane's own\n * providers then skip their loopback listener; others ignore the flag.\n */\nexport type ZidaneOAuthLoginCallbacks = OAuthLoginCallbacks & { callbackServer?: false }\n\n/** Providers known to honor `callbackServer: false` (zidane's own loopback flows). */\nconst REMOTE_CALLBACK = new WeakSet<object>()\n\n/** Mark a provider that binds no listener under `callbackServer: false`; returns it. */\nexport function honorsRemoteCallback<T extends object>(provider: T): T {\n REMOTE_CALLBACK.add(provider)\n return provider\n}\n\n/**\n * Whether a provider can sign in for a client of a remote host without\n * listening on the host's machine: it honors `callbackServer: false`, or it\n * never listens (`usesCallbackServer: false`: paste, device or polling flows).\n * Others (pi-ai's stock providers, a third party's) would bind a loopback\n * port on the server, which the client's browser can't reach.\n */\nexport function canSignInRemotely(provider: { usesCallbackServer?: boolean }): boolean {\n return REMOTE_CALLBACK.has(provider) || provider.usesCallbackServer === false\n}\n\n/** Whether a provider should bind its loopback callback listener for these callbacks. */\nexport function listensForCallback(callbacks: OAuthLoginCallbacks): boolean {\n return (callbacks as ZidaneOAuthLoginCallbacks).callbackServer !== false\n}\n\nexport interface CallbackServerHandle {\n /** Fully-qualified redirect URI to advertise to the provider. */\n redirectUri: string\n /**\n * Resolves when the redirect lands (with `{ code, state? }`) or when\n * {@link cancelWait} is invoked (with `null`). Never throws.\n */\n waitForCode: () => Promise<{ code: string, state?: string } | null>\n /** Unblock `waitForCode` early (e.g. manual paste won the race). */\n cancelWait: () => void\n /** Close the listener. Idempotent. */\n close: () => void\n}\n\ninterface PendingResolution {\n settle: (value: { code: string, state?: string } | null) => void\n}\n\nfunction buildRequestHandler(opts: CallbackServerOptions, pending: PendingResolution) {\n return (req: IncomingMessage, res: ServerResponse) => {\n try {\n const url = new URL(req.url || '', 'http://localhost')\n\n if (url.pathname !== opts.path) {\n respondError(res, 404, opts, 'Callback route not found.')\n return\n }\n\n const error = url.searchParams.get('error')\n if (error) {\n respondError(res, 400, opts, `${opts.providerName} authentication did not complete.`, `Error: ${error}`)\n return\n }\n\n const code = url.searchParams.get('code')\n const state = url.searchParams.get('state')\n\n if (!code || !state) {\n respondError(res, 400, opts, 'Missing code or state parameter.')\n return\n }\n\n if (state !== opts.expectedState) {\n respondError(res, 400, opts, 'State mismatch.')\n return\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(opts.renderPage({\n kind: 'success',\n provider: opts.providerName,\n message: opts.successMessage,\n }))\n pending.settle({ code, state })\n }\n catch {\n // We intentionally swallow the actual error here: surfacing a stack\n // to the user's browser would leak internals, and the login flow\n // is about to fall back to manual paste anyway.\n respondError(res, 500, opts, 'Internal error while processing the callback.')\n }\n }\n}\n\nfunction respondError(\n res: ServerResponse,\n status: number,\n opts: CallbackServerOptions,\n message: string,\n details?: string,\n) {\n res.writeHead(status, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(opts.renderPage({\n kind: 'error',\n provider: opts.providerName,\n message,\n details,\n }))\n}\n\nfunction buildStubHandle(redirectUri: string, server: Server | null): CallbackServerHandle {\n return {\n redirectUri,\n waitForCode: async () => null,\n cancelWait: () => {},\n close: () => {\n try { server?.close() }\n catch { /* already closed */ }\n },\n }\n}\n\n/**\n * Start the loopback HTTP callback server. The returned handle is the\n * caller's contract — they `await waitForCode()`, race it against manual\n * paste, then `close()` in a `finally`.\n */\nexport async function startCallbackServer(opts: CallbackServerOptions): Promise<CallbackServerHandle> {\n const onListenError = opts.onListenError ?? 'reject'\n const redirectUri = `http://localhost:${opts.port}${opts.path}`\n if (opts.listen === false)\n return buildStubHandle(redirectUri, null)\n\n return new Promise<CallbackServerHandle>((resolve, reject) => {\n let settled = false\n const pending: PendingResolution = {\n settle: () => {},\n }\n const waitPromise = new Promise<{ code: string, state?: string } | null>((resolveWait) => {\n pending.settle = (value) => {\n if (settled)\n return\n settled = true\n resolveWait(value)\n }\n })\n\n const server = createServer(buildRequestHandler(opts, pending))\n\n server.on('error', (err) => {\n if (onListenError === 'resolveWithStub') {\n pending.settle(null)\n resolve(buildStubHandle(redirectUri, server))\n return\n }\n reject(err)\n })\n\n server.listen(opts.port, CALLBACK_HOST, () => {\n resolve({\n redirectUri,\n waitForCode: () => waitPromise,\n cancelWait: () => pending.settle(null),\n close: () => {\n try { server.close() }\n catch { /* already closed */ }\n },\n })\n })\n })\n}\n","/**\n * xAI Grok OAuth flow (SuperGrok / X Premium+).\n *\n * xAI is **not** built into pi-ai, so — like Cursor — we implement the flow\n * here and register it with pi-ai's OAuth registry (`registerXaiOAuthProvider`)\n * so `getOAuthApiKey('xai-oauth', …)` resolves to it during lazy token refresh.\n *\n * Auth shape: OAuth 2.0 + PKCE with a loopback callback server, against xAI's\n * OIDC issuer (`https://auth.x.ai`). Differs from the Anthropic / Codex flows\n * (which use the shared `startCallbackServer`) on three points, so it gets its\n * own login impl rather than reusing that primitive:\n *\n * 1. The `redirect_uri` must be `http://127.0.0.1:56121/callback` verbatim\n * (xAI matches the registered loopback IP, not `localhost`).\n * 2. Endpoints come from OIDC discovery, not hard-coded constants.\n * 3. Token exchange + refresh are `application/x-www-form-urlencoded`\n * (the Anthropic flow posts JSON).\n *\n * The callback page still routes through {@link OAuthCallbackPageRenderer} so\n * the post-redirect HTML matches the rest of zidane's themed flows.\n *\n * Flow + constants adapted from the public reference implementations\n * (`stnly/pi-grok`, `BlockedPath/pi-xai-oauth`) and the Hermes Agent docs.\n * xAI's OAuth surface is unofficial/undocumented — re-verify the client id,\n * scopes, and callback port if login starts failing.\n */\n\nimport type {\n OAuthCredentials,\n OAuthLoginCallbacks,\n} from '@earendil-works/pi-ai/oauth'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { OAuthProviderInterface } from '../../providers/oauth-registry'\nimport type { OAuthCallbackPageRenderer } from './render'\nimport { createServer } from 'node:http'\nimport { generatePkce } from './pkce'\nimport { honorsRemoteCallback, listensForCallback } from './server'\n\n/** pi-ai / zidane OAuth provider id. Also the credentials-file key. */\nexport const XAI_OAUTH_PROVIDER_ID = 'xai-oauth'\n\nconst DEFAULT_BASE_URL = 'https://api.x.ai/v1'\nconst ISSUER = 'https://auth.x.ai'\nconst DISCOVERY_URL = `${ISSUER}/.well-known/openid-configuration`\n/** Public client id used by the Grok CLI OAuth surface. */\nconst DEFAULT_CLIENT_ID = 'b1a00492-073a-47ea-816f-4c329264a828'\nconst DEFAULT_SCOPE = 'openid profile email offline_access grok-cli:access api:access'\n/** xAI matches the registered loopback IP exactly — `localhost` is rejected. */\nconst DEFAULT_CALLBACK_HOST = '127.0.0.1'\nconst DEFAULT_CALLBACK_PORT = 56121\nconst CALLBACK_PATH = '/callback'\nconst PROVIDER_NAME = 'xAI Grok'\n/** Refresh slightly early so requests don't race expiry. */\nconst REFRESH_SKEW_MS = 120_000\nconst CALLBACK_TIMEOUT_MS = 180_000\n\nfunction xaiOAuthClientId(): string {\n return process.env.PI_XAI_OAUTH_CLIENT_ID || DEFAULT_CLIENT_ID\n}\n\nfunction xaiOAuthScope(): string {\n return process.env.PI_XAI_OAUTH_SCOPE || DEFAULT_SCOPE\n}\n\nfunction xaiOAuthCallbackHost(): string {\n return process.env.PI_XAI_OAUTH_CALLBACK_HOST || DEFAULT_CALLBACK_HOST\n}\n\nfunction xaiOAuthCallbackPort(): number {\n const parsed = Number.parseInt(process.env.PI_XAI_OAUTH_CALLBACK_PORT || String(DEFAULT_CALLBACK_PORT), 10)\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CALLBACK_PORT\n}\n\n/** Resolve the xAI API base URL (env override → default). */\nexport function xaiBaseUrl(): string {\n return (process.env.PI_XAI_BASE_URL || process.env.XAI_BASE_URL || DEFAULT_BASE_URL)\n .replace(/\\/+$/, '')\n}\n\ninterface XaiDiscovery {\n authorization_endpoint: string\n token_endpoint: string\n}\n\n/**\n * xAI OAuth credentials. Extends the base `{ access, refresh, expires }` with\n * the resolved `token_endpoint` so refresh doesn't need a second discovery\n * round-trip, plus the cached discovery doc for validation.\n */\nexport interface XaiOAuthCredentials extends OAuthCredentials {\n tokenEndpoint?: string\n discovery?: XaiDiscovery\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let binary = ''\n for (const b of bytes)\n binary += String.fromCharCode(b)\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction randomToken(byteLength = 16): string {\n return base64Url(crypto.getRandomValues(new Uint8Array(byteLength)))\n}\n\n/**\n * Refuse any OIDC endpoint that isn't HTTPS on an xAI origin.\n *\n * The discovery doc is cached long-term in `credentials.json`. A single MITM\n * during initial login could otherwise pin a malicious `token_endpoint` that\n * receives every subsequent refresh token. Validating scheme + host keeps the\n * endpoint on `x.ai` / `*.x.ai`.\n */\nfunction validateEndpoint(value: string, field: string): string {\n let url: URL\n try {\n url = new URL(value)\n }\n catch {\n throw new Error(`xAI OAuth discovery returned an invalid ${field}: ${value}`)\n }\n if (url.protocol !== 'https:')\n throw new Error(`xAI OAuth ${field} must use HTTPS: ${value}`)\n const host = url.hostname.toLowerCase()\n if (host !== 'x.ai' && !host.endsWith('.x.ai'))\n throw new Error(`Refusing non-xAI OAuth ${field}: ${value}`)\n return url.toString()\n}\n\nasync function discover(): Promise<XaiDiscovery> {\n let response: Response\n try {\n response = await fetch(DISCOVERY_URL, {\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(15_000),\n })\n }\n catch (cause) {\n throw new Error(`xAI OIDC discovery failed: ${cause instanceof Error ? cause.message : String(cause)}`)\n }\n if (!response.ok)\n throw new Error(`xAI OIDC discovery returned ${response.status}`)\n\n const payload = await response.json() as Record<string, unknown>\n return {\n authorization_endpoint: validateEndpoint(String(payload.authorization_endpoint ?? ''), 'authorization_endpoint'),\n token_endpoint: validateEndpoint(String(payload.token_endpoint ?? ''), 'token_endpoint'),\n }\n}\n\ninterface CallbackResult {\n code?: string\n state?: string\n error?: string\n errorDescription?: string\n}\n\ninterface XaiCallbackServer {\n redirectUri: string\n waitForCallback: (timeoutMs: number) => Promise<CallbackResult>\n close: () => void\n}\n\n/**\n * A remote sign-in (`callbackServer: false`): nothing listens here; the\n * client's loopback catches the redirect and its URL comes back through\n * `onManualCodeInput`. Same redirect URI as the default listener's.\n */\nfunction remoteCallback(callbacks: OAuthLoginCallbacks): XaiCallbackServer {\n return {\n redirectUri: `http://${xaiOAuthCallbackHost()}:${xaiOAuthCallbackPort()}${CALLBACK_PATH}`,\n waitForCallback: async () => {\n if (!callbacks.onManualCodeInput)\n return { error: 'no-callback', errorDescription: 'No way to receive the xAI OAuth callback.' }\n const input = (await callbacks.onManualCodeInput()).trim()\n try {\n const url = new URL(input)\n const error = url.searchParams.get('error')\n return error\n ? { error, ...(url.searchParams.get('error_description') ? { errorDescription: url.searchParams.get('error_description')! } : {}) }\n : { ...(url.searchParams.get('code') ? { code: url.searchParams.get('code')! } : {}), ...(url.searchParams.get('state') ? { state: url.searchParams.get('state')! } : {}) }\n }\n catch {\n const params = new URLSearchParams(input.includes('=') ? input : `code=${input}`)\n return { ...(params.get('code') ? { code: params.get('code')! } : {}), ...(params.get('state') ? { state: params.get('state')! } : {}) }\n }\n },\n close: () => undefined,\n }\n}\n\n/**\n * Start the loopback callback server on `127.0.0.1:56121`. Falls back to an\n * OS-assigned port if 56121 is taken — xAI accepts any loopback port as long\n * as the `redirect_uri` we send on the authorize URL matches the listener.\n */\nasync function startXaiCallbackServer(renderPage: OAuthCallbackPageRenderer): Promise<XaiCallbackServer> {\n const callbackHost = xaiOAuthCallbackHost()\n const callbackPort = xaiOAuthCallbackPort()\n let settle: ((value: CallbackResult) => void) | undefined\n let settled = false\n const callbackPromise = new Promise<CallbackResult>((resolve) => {\n settle = (value) => {\n if (settled)\n return\n settled = true\n resolve(value)\n }\n })\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n try {\n // accounts.x.ai may issue a CORS preflight against the loopback listener.\n const origin = req.headers.origin\n if (origin === 'https://accounts.x.ai' || origin === 'https://auth.x.ai') {\n res.setHeader('Access-Control-Allow-Origin', origin)\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type')\n res.setHeader('Access-Control-Allow-Private-Network', 'true')\n res.setHeader('Vary', 'Origin')\n }\n if (req.method === 'OPTIONS') {\n res.statusCode = 204\n res.end()\n return\n }\n\n const url = new URL(req.url ?? '/', `http://${callbackHost}`)\n if (url.pathname !== CALLBACK_PATH) {\n res.statusCode = 404\n res.end('Not found')\n return\n }\n\n const result: CallbackResult = {\n code: url.searchParams.get('code') ?? undefined,\n state: url.searchParams.get('state') ?? undefined,\n error: url.searchParams.get('error') ?? undefined,\n errorDescription: url.searchParams.get('error_description') ?? undefined,\n }\n\n res.statusCode = result.error ? 400 : 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n res.end(renderPage(result.error\n ? {\n kind: 'error',\n provider: PROVIDER_NAME,\n message: `${PROVIDER_NAME} authentication did not complete.`,\n details: result.errorDescription ?? result.error,\n }\n : {\n kind: 'success',\n provider: PROVIDER_NAME,\n message: 'xAI authentication completed. You can close this window.',\n }))\n settle?.(result)\n }\n catch {\n res.statusCode = 500\n res.end('Internal error')\n }\n })\n\n const listen = (port: number) => new Promise<number>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, callbackHost, () => {\n server.removeListener('error', reject)\n const addr = server.address()\n resolve(typeof addr === 'object' && addr ? addr.port : port)\n })\n })\n\n let actualPort: number\n try {\n actualPort = await listen(callbackPort)\n }\n catch {\n actualPort = await listen(0)\n }\n\n return {\n redirectUri: `http://${callbackHost}:${actualPort}${CALLBACK_PATH}`,\n waitForCallback: timeoutMs => Promise.race([\n callbackPromise,\n new Promise<CallbackResult>(resolve =>\n setTimeout(\n resolve,\n timeoutMs,\n { error: 'timeout', errorDescription: 'Timed out waiting for the xAI OAuth callback.' },\n )),\n ]),\n close: () => {\n try { server.close() }\n catch { /* already closed */ }\n },\n }\n}\n\nfunction expiryFromPayload(payload: Record<string, unknown>): number {\n const expiresIn = typeof payload.expires_in === 'number'\n ? payload.expires_in\n : Number(payload.expires_in ?? 3600)\n return Date.now() + expiresIn * 1000 - REFRESH_SKEW_MS\n}\n\nasync function exchangeCode(\n tokenEndpoint: string,\n code: string,\n redirectUri: string,\n verifier: string,\n discovery: XaiDiscovery,\n): Promise<XaiOAuthCredentials> {\n const clientId = xaiOAuthClientId()\n const response = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: clientId,\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n }),\n signal: AbortSignal.timeout(30_000),\n })\n if (!response.ok)\n throw new Error(`xAI token exchange failed: ${response.status} ${await response.text().catch(() => '')}`)\n\n const payload = await response.json() as Record<string, unknown>\n const access = String(payload.access_token ?? '')\n const refresh = String(payload.refresh_token ?? '')\n if (!access)\n throw new Error('xAI token exchange did not return an access_token.')\n if (!refresh)\n throw new Error('xAI token exchange did not return a refresh_token.')\n\n return { access, refresh, expires: expiryFromPayload(payload), tokenEndpoint, discovery }\n}\n\nexport async function loginXai(\n renderPage: OAuthCallbackPageRenderer,\n callbacks: OAuthLoginCallbacks,\n): Promise<XaiOAuthCredentials> {\n const discovery = await discover()\n const { verifier, challenge } = await generatePkce()\n const state = randomToken()\n const nonce = randomToken()\n const server = listensForCallback(callbacks) ? await startXaiCallbackServer(renderPage) : remoteCallback(callbacks)\n\n try {\n const authUrl = new URL(discovery.authorization_endpoint)\n authUrl.searchParams.set('response_type', 'code')\n authUrl.searchParams.set('client_id', xaiOAuthClientId())\n authUrl.searchParams.set('redirect_uri', server.redirectUri)\n authUrl.searchParams.set('scope', xaiOAuthScope())\n authUrl.searchParams.set('code_challenge', challenge)\n authUrl.searchParams.set('code_challenge_method', 'S256')\n authUrl.searchParams.set('state', state)\n authUrl.searchParams.set('nonce', nonce)\n // Opt into xAI's generic OAuth plan tier (SuperGrok / X Premium+).\n authUrl.searchParams.set('plan', 'generic')\n authUrl.searchParams.set('referrer', 'zidane')\n\n callbacks.onAuth({\n url: authUrl.toString(),\n instructions: `Sign in to xAI and approve access. If the browser is on another machine, the callback listener is ${server.redirectUri}.`,\n })\n\n const result = await server.waitForCallback(CALLBACK_TIMEOUT_MS)\n if (result.error)\n throw new Error(result.errorDescription ?? result.error)\n if (result.state !== state)\n throw new Error('xAI OAuth state mismatch (possible CSRF). Retry the login.')\n if (!result.code)\n throw new Error('xAI OAuth callback did not include an authorization code.')\n\n callbacks.onProgress?.('Exchanging authorization code for tokens...')\n return await exchangeCode(discovery.token_endpoint, result.code, server.redirectUri, verifier, discovery)\n }\n finally {\n server.close()\n }\n}\n\nexport async function refreshXaiToken(credentials: OAuthCredentials): Promise<XaiOAuthCredentials> {\n const xai = credentials as XaiOAuthCredentials\n const clientId = xaiOAuthClientId()\n if (!credentials.refresh)\n throw new Error('xAI credentials are missing a refresh token. Log in again.')\n\n const tokenEndpoint = xai.tokenEndpoint\n ?? xai.discovery?.token_endpoint\n ?? (await discover()).token_endpoint\n validateEndpoint(tokenEndpoint, 'token_endpoint')\n\n const response = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: clientId,\n refresh_token: credentials.refresh,\n }),\n signal: AbortSignal.timeout(30_000),\n })\n if (!response.ok)\n throw new Error(`xAI token refresh failed: ${response.status} ${await response.text().catch(() => '')}`)\n\n const payload = await response.json() as Record<string, unknown>\n const access = String(payload.access_token ?? '')\n if (!access)\n throw new Error('xAI token refresh did not return an access_token.')\n\n return {\n ...xai,\n access,\n // xAI may omit a rotated refresh token — keep the existing one.\n refresh: String(payload.refresh_token ?? credentials.refresh),\n expires: expiryFromPayload(payload),\n tokenEndpoint,\n }\n}\n\n/**\n * Build an xAI `OAuthProviderInterface`. Shape matches Anthropic / Codex /\n * Cursor so it drops into `BUILTIN_PROVIDERS` and `src/auth.ts` unchanged.\n *\n * `usesCallbackServer: true` — the loopback flow has a real callback server,\n * so the TUI doesn't need to prompt for a manual code paste.\n */\nexport function createXaiOAuthProvider(renderPage: OAuthCallbackPageRenderer): OAuthProviderInterface {\n // Honors `callbackServer: false`: a remote sign-in binds nothing on this machine.\n return honorsRemoteCallback({\n id: XAI_OAUTH_PROVIDER_ID,\n name: 'xAI Grok (SuperGrok / X Premium+)',\n usesCallbackServer: true,\n login: callbacks => loginXai(renderPage, callbacks),\n refreshToken: refreshXaiToken,\n getApiKey: credentials => credentials.access,\n })\n}\n"],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import { readdirSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { homedir } from "node:os";
4
+ //#region src/chat/xdg.ts
5
+ /**
6
+ * XDG Base Directory resolution for zidane.
7
+ *
8
+ * The user's storage spreads across four logical slots:
9
+ *
10
+ * - **config** — credentials, mcp-credentials, keybindings, config.json,
11
+ * mcps.json, skills (user-editable surface).
12
+ * - **data** — sessions.db (long-lived chat history).
13
+ * - **state** — state.json (per-machine UI bookkeeping: last provider,
14
+ * last model, last agent, settings).
15
+ * - **cache** — persisted tool results, background-task logs,
16
+ * auto-update registry cache (regenerable, safe to wipe).
17
+ *
18
+ * Historically all four collapsed to `~/.zidane/`. This module adds
19
+ * XDG-Base-Directory-aware defaults so a Linux user with no existing
20
+ * `~/.zidane/` lands in the conventional `~/.config/zidane/`,
21
+ * `~/.local/share/zidane/`, `~/.local/state/zidane/`, `~/.cache/zidane/`
22
+ * trio. Existing setups (anyone with a `~/.zidane/` directory or
23
+ * `ZIDANE_STORAGE_DIR` set) keep the single-dir layout unchanged.
24
+ *
25
+ * Resolution flow — applied in this order:
26
+ *
27
+ * 1. Caller passed an explicit `storageDir` (`ChatOptions.storageDir`)
28
+ * OR `ZIDANE_STORAGE_DIR` is set → **legacy-explicit** single-dir
29
+ * layout under `<storageDir>/<prefix>`. The four slots collapse to
30
+ * the same directory.
31
+ * 2. `~/<prefix>/` already holds storage on disk → **legacy-existing**
32
+ * single-dir layout under that directory. Upgrades never silently
33
+ * shift files around. A dir holding only user-authored, home-anchored
34
+ * content (`extensions/`, `skills/`, `mcps.json`, `SYSTEM.md`,
35
+ * `AGENTS.md`, plus macOS's `.DS_Store`) does not count: discovery reads
36
+ * those from `~/<prefix>/` in every mode, and scaffolding one must not
37
+ * flip an XDG install.
38
+ * 3. Any `XDG_*_HOME` env var is set OR `process.platform === 'linux'`
39
+ * → **XDG split**. Each slot lands in its own dir. Per-slot
40
+ * `ZIDANE_{CONFIG,DATA,CACHE,STATE}_DIR` overrides beat the XDG
41
+ * vars for surgical tweaks.
42
+ * 4. Otherwise (macOS/Windows, no XDG signal, no existing dir) →
43
+ * **default** single-dir layout at `~/<prefix>/`. Day-one behavior
44
+ * on these platforms is unchanged.
45
+ *
46
+ * The `userDir` legacy alias always equals `configDir` so existing code
47
+ * that still references `paths.userDir` keeps reading credentials, mcps,
48
+ * etc. from the right place.
49
+ */
50
+ /**
51
+ * Resolve the four storage slots according to the precedence above.
52
+ *
53
+ * Pure aside from one filesystem probe (`readdirSync(home/<prefix>)`,
54
+ * see {@link holdsLegacyStorage}). No directories are created here; the
55
+ * relevant write paths (state store, credentials writer, persist
56
+ * dir) handle their own lazy `mkdirSync` already.
57
+ */
58
+ function resolveStorageDirs(opts = {}) {
59
+ const env = opts.env ?? process.env;
60
+ const home = opts.home ?? homedir();
61
+ const platform = opts.platform ?? process.platform;
62
+ const rawPrefix = opts.prefix ?? ".zidane";
63
+ const prefixBare = rawPrefix.replace(/^\./, "");
64
+ const explicitStorageDir = opts.storageDir ?? env.ZIDANE_STORAGE_DIR;
65
+ if (explicitStorageDir) return single(resolve(explicitStorageDir, rawPrefix), "legacy-explicit");
66
+ const legacyHomeDir = resolve(home, rawPrefix);
67
+ if (holdsLegacyStorage(legacyHomeDir)) return single(legacyHomeDir, "legacy-existing");
68
+ if (platform === "linux" || !!env.XDG_CONFIG_HOME || !!env.XDG_DATA_HOME || !!env.XDG_CACHE_HOME || !!env.XDG_STATE_HOME || !!env.ZIDANE_CONFIG_DIR || !!env.ZIDANE_DATA_DIR || !!env.ZIDANE_STATE_DIR || !!env.ZIDANE_CACHE_DIR) return {
69
+ configDir: env.ZIDANE_CONFIG_DIR ?? resolve(env.XDG_CONFIG_HOME || resolve(home, ".config"), prefixBare),
70
+ dataDir: env.ZIDANE_DATA_DIR ?? resolve(env.XDG_DATA_HOME || resolve(home, ".local", "share"), prefixBare),
71
+ stateDir: env.ZIDANE_STATE_DIR ?? resolve(env.XDG_STATE_HOME || resolve(home, ".local", "state"), prefixBare),
72
+ cacheDir: env.ZIDANE_CACHE_DIR ?? resolve(env.XDG_CACHE_HOME || resolve(home, ".cache"), prefixBare),
73
+ mode: "xdg"
74
+ };
75
+ return single(legacyHomeDir, "default");
76
+ }
77
+ /**
78
+ * Entries discovery reads from `~/<prefix>/` regardless of the storage
79
+ * mode, plus Finder's `.DS_Store`. Creating one (e.g. the create-extension
80
+ * shortcut writing `~/.zidane/extensions/<name>`) must not be mistaken for
81
+ * a legacy install.
82
+ */
83
+ const HOME_ANCHORED_ENTRIES = /* @__PURE__ */ new Set([
84
+ "extensions",
85
+ "skills",
86
+ "mcps.json",
87
+ "SYSTEM.md",
88
+ "AGENTS.md",
89
+ ".DS_Store"
90
+ ]);
91
+ /**
92
+ * True when `dir` exists and holds anything beyond home-anchored authored
93
+ * content. An unreadable dir counts as legacy: staying put beats silently
94
+ * moving a user's storage.
95
+ */
96
+ function holdsLegacyStorage(dir) {
97
+ let entries;
98
+ try {
99
+ entries = readdirSync(dir);
100
+ } catch (err) {
101
+ return err.code !== "ENOENT";
102
+ }
103
+ return entries.some((name) => !HOME_ANCHORED_ENTRIES.has(name));
104
+ }
105
+ function single(base, mode) {
106
+ return {
107
+ configDir: base,
108
+ dataDir: base,
109
+ stateDir: base,
110
+ cacheDir: base,
111
+ mode
112
+ };
113
+ }
114
+ //#endregion
115
+ export { resolveStorageDirs as t };
116
+
117
+ //# sourceMappingURL=xdg-zweed0-t.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xdg-zweed0-t.js","names":[],"sources":["../src/chat/xdg.ts"],"sourcesContent":["/**\n * XDG Base Directory resolution for zidane.\n *\n * The user's storage spreads across four logical slots:\n *\n * - **config** — credentials, mcp-credentials, keybindings, config.json,\n * mcps.json, skills (user-editable surface).\n * - **data** — sessions.db (long-lived chat history).\n * - **state** — state.json (per-machine UI bookkeeping: last provider,\n * last model, last agent, settings).\n * - **cache** — persisted tool results, background-task logs,\n * auto-update registry cache (regenerable, safe to wipe).\n *\n * Historically all four collapsed to `~/.zidane/`. This module adds\n * XDG-Base-Directory-aware defaults so a Linux user with no existing\n * `~/.zidane/` lands in the conventional `~/.config/zidane/`,\n * `~/.local/share/zidane/`, `~/.local/state/zidane/`, `~/.cache/zidane/`\n * trio. Existing setups (anyone with a `~/.zidane/` directory or\n * `ZIDANE_STORAGE_DIR` set) keep the single-dir layout unchanged.\n *\n * Resolution flow — applied in this order:\n *\n * 1. Caller passed an explicit `storageDir` (`ChatOptions.storageDir`)\n * OR `ZIDANE_STORAGE_DIR` is set → **legacy-explicit** single-dir\n * layout under `<storageDir>/<prefix>`. The four slots collapse to\n * the same directory.\n * 2. `~/<prefix>/` already holds storage on disk → **legacy-existing**\n * single-dir layout under that directory. Upgrades never silently\n * shift files around. A dir holding only user-authored, home-anchored\n * content (`extensions/`, `skills/`, `mcps.json`, `SYSTEM.md`,\n * `AGENTS.md`, plus macOS's `.DS_Store`) does not count: discovery reads\n * those from `~/<prefix>/` in every mode, and scaffolding one must not\n * flip an XDG install.\n * 3. Any `XDG_*_HOME` env var is set OR `process.platform === 'linux'`\n * → **XDG split**. Each slot lands in its own dir. Per-slot\n * `ZIDANE_{CONFIG,DATA,CACHE,STATE}_DIR` overrides beat the XDG\n * vars for surgical tweaks.\n * 4. Otherwise (macOS/Windows, no XDG signal, no existing dir) →\n * **default** single-dir layout at `~/<prefix>/`. Day-one behavior\n * on these platforms is unchanged.\n *\n * The `userDir` legacy alias always equals `configDir` so existing code\n * that still references `paths.userDir` keeps reading credentials, mcps,\n * etc. from the right place.\n */\n\nimport { readdirSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { resolve } from 'node:path'\n\n/** The four slot kinds we resolve. Names match the XDG spec. */\nexport type StorageSlot = 'config' | 'data' | 'state' | 'cache'\n\n/** Which resolution branch produced the layout — surfaced for debugging + tests. */\nexport type StorageMode = 'legacy-explicit' | 'legacy-existing' | 'xdg' | 'default'\n\n/**\n * Per-slot directories. In legacy / default modes the four fields all\n * point at the same path; in XDG mode they fan out into their\n * spec-conventional locations.\n *\n * `mode` carries the resolution branch so a host that wants to print\n * a startup banner (\"zidane is using XDG paths\") can detect the\n * layout without re-running the logic.\n */\nexport interface StorageDirs {\n configDir: string\n dataDir: string\n stateDir: string\n cacheDir: string\n mode: StorageMode\n}\n\nexport interface ResolveStorageDirsOptions {\n /** Storage prefix. Leading dot tolerated. Default: `'.zidane'`. */\n prefix?: string\n /**\n * Explicit storage root (`ChatOptions.storageDir`). When set, forces\n * legacy-explicit mode regardless of the platform / XDG signals.\n */\n storageDir?: string\n /** Override `os.homedir()` for tests. */\n home?: string\n /** Override `process.platform` for tests. */\n platform?: NodeJS.Platform\n /** Override `process.env` for tests. */\n env?: Readonly<Record<string, string | undefined>>\n}\n\n/**\n * Resolve the four storage slots according to the precedence above.\n *\n * Pure aside from one filesystem probe (`readdirSync(home/<prefix>)`,\n * see {@link holdsLegacyStorage}). No directories are created here; the\n * relevant write paths (state store, credentials writer, persist\n * dir) handle their own lazy `mkdirSync` already.\n */\nexport function resolveStorageDirs(opts: ResolveStorageDirsOptions = {}): StorageDirs {\n const env = opts.env ?? process.env\n const home = opts.home ?? homedir()\n const platform = opts.platform ?? process.platform\n // Two prefix forms — legacy mode preserves whatever the caller\n // passed (no implicit dot insertion, so `prefix: 'myapp'` lands at\n // `<storageDir>/myapp` not `<storageDir>/.myapp` — matches the\n // pre-XDG behavior tests already rely on). XDG mode uses the de-\n // dotted form (`'.zidane'` → `'zidane'`) because the XDG dir itself\n // is already the dotfile container — `~/.config/.zidane/` would be\n // a double-dot offense.\n const rawPrefix = opts.prefix ?? '.zidane'\n const prefixBare = rawPrefix.replace(/^\\./, '')\n\n // Branch 1 — explicit storage root → legacy-explicit.\n // Host-supplied `storageDir` beats env so SDK callers can pin a\n // location for embedded usage; otherwise `ZIDANE_STORAGE_DIR` wins.\n const explicitStorageDir = opts.storageDir ?? env.ZIDANE_STORAGE_DIR\n if (explicitStorageDir) {\n const base = resolve(explicitStorageDir, rawPrefix)\n return single(base, 'legacy-explicit')\n }\n\n // Branch 2 — `~/<prefix>/` already holds storage → legacy-existing.\n // Detect ANY of the legacy locations the user might have:\n // - `~/.zidane/` (default prefix)\n // - `~/.<prefix>/` (custom prefix)\n // Skipping it for a user with a customized prefix would leak their\n // data into XDG dirs on next launch.\n const legacyHomeDir = resolve(home, rawPrefix)\n if (holdsLegacyStorage(legacyHomeDir))\n return single(legacyHomeDir, 'legacy-existing')\n\n // Branch 3 — XDG signals present → split layout.\n // The signal is generous: Linux always qualifies, any platform\n // where the user has set any `XDG_*_HOME` var opts in (a savvy\n // mac user can put zidane in their XDG hierarchy too), AND any\n // `ZIDANE_{CONFIG,DATA,STATE,CACHE}_DIR` per-slot override also\n // opts in — otherwise a user pinning JUST `ZIDANE_CACHE_DIR` on\n // macOS would have it silently ignored because none of the\n // `XDG_*_HOME` vars are set.\n const hasXdgSignal = platform === 'linux'\n || !!env.XDG_CONFIG_HOME\n || !!env.XDG_DATA_HOME\n || !!env.XDG_CACHE_HOME\n || !!env.XDG_STATE_HOME\n || !!env.ZIDANE_CONFIG_DIR\n || !!env.ZIDANE_DATA_DIR\n || !!env.ZIDANE_STATE_DIR\n || !!env.ZIDANE_CACHE_DIR\n\n if (hasXdgSignal) {\n return {\n configDir: env.ZIDANE_CONFIG_DIR\n ?? resolve(env.XDG_CONFIG_HOME || resolve(home, '.config'), prefixBare),\n dataDir: env.ZIDANE_DATA_DIR\n ?? resolve(env.XDG_DATA_HOME || resolve(home, '.local', 'share'), prefixBare),\n stateDir: env.ZIDANE_STATE_DIR\n ?? resolve(env.XDG_STATE_HOME || resolve(home, '.local', 'state'), prefixBare),\n cacheDir: env.ZIDANE_CACHE_DIR\n ?? resolve(env.XDG_CACHE_HOME || resolve(home, '.cache'), prefixBare),\n mode: 'xdg',\n }\n }\n\n // Branch 4 — default (mac/windows, no XDG signal, no existing dir).\n // Same as the day-one experience: everything under `~/<prefix>/`.\n return single(legacyHomeDir, 'default')\n}\n\n/**\n * Entries discovery reads from `~/<prefix>/` regardless of the storage\n * mode, plus Finder's `.DS_Store`. Creating one (e.g. the create-extension\n * shortcut writing `~/.zidane/extensions/<name>`) must not be mistaken for\n * a legacy install.\n */\nconst HOME_ANCHORED_ENTRIES = new Set(['extensions', 'skills', 'mcps.json', 'SYSTEM.md', 'AGENTS.md', '.DS_Store'])\n\n/**\n * True when `dir` exists and holds anything beyond home-anchored authored\n * content. An unreadable dir counts as legacy: staying put beats silently\n * moving a user's storage.\n */\nfunction holdsLegacyStorage(dir: string): boolean {\n let entries: string[]\n try {\n entries = readdirSync(dir)\n }\n catch (err) {\n return (err as NodeJS.ErrnoException).code !== 'ENOENT'\n }\n return entries.some(name => !HOME_ANCHORED_ENTRIES.has(name))\n}\n\nfunction single(base: string, mode: StorageMode): StorageDirs {\n return {\n configDir: base,\n dataDir: base,\n stateDir: base,\n cacheDir: base,\n mode,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiGA,SAAgB,mBAAmB,OAAkC,CAAC,GAAgB;CACpF,MAAM,MAAM,KAAK,OAAO,QAAQ;CAChC,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAClC,MAAM,WAAW,KAAK,YAAY,QAAQ;CAQ1C,MAAM,YAAY,KAAK,UAAU;CACjC,MAAM,aAAa,UAAU,QAAQ,OAAO,EAAE;CAK9C,MAAM,qBAAqB,KAAK,cAAc,IAAI;CAClD,IAAI,oBAEF,OAAO,OADM,QAAQ,oBAAoB,SACxB,GAAG,iBAAiB;CASvC,MAAM,gBAAgB,QAAQ,MAAM,SAAS;CAC7C,IAAI,mBAAmB,aAAa,GAClC,OAAO,OAAO,eAAe,iBAAiB;CAoBhD,IAVqB,aAAa,WAC7B,CAAC,CAAC,IAAI,mBACN,CAAC,CAAC,IAAI,iBACN,CAAC,CAAC,IAAI,kBACN,CAAC,CAAC,IAAI,kBACN,CAAC,CAAC,IAAI,qBACN,CAAC,CAAC,IAAI,mBACN,CAAC,CAAC,IAAI,oBACN,CAAC,CAAC,IAAI,kBAGT,OAAO;EACL,WAAW,IAAI,qBACV,QAAQ,IAAI,mBAAmB,QAAQ,MAAM,SAAS,GAAG,UAAU;EACxE,SAAS,IAAI,mBACR,QAAQ,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,GAAG,UAAU;EAC9E,UAAU,IAAI,oBACT,QAAQ,IAAI,kBAAkB,QAAQ,MAAM,UAAU,OAAO,GAAG,UAAU;EAC/E,UAAU,IAAI,oBACT,QAAQ,IAAI,kBAAkB,QAAQ,MAAM,QAAQ,GAAG,UAAU;EACtE,MAAM;CACR;CAKF,OAAO,OAAO,eAAe,SAAS;AACxC;;;;;;;AAQA,MAAM,wCAAwB,IAAI,IAAI;CAAC;CAAc;CAAU;CAAa;CAAa;CAAa;AAAW,CAAC;;;;;;AAOlH,SAAS,mBAAmB,KAAsB;CAChD,IAAI;CACJ,IAAI;EACF,UAAU,YAAY,GAAG;CAC3B,SACO,KAAK;EACV,OAAQ,IAA8B,SAAS;CACjD;CACA,OAAO,QAAQ,MAAK,SAAQ,CAAC,sBAAsB,IAAI,IAAI,CAAC;AAC9D;AAEA,SAAS,OAAO,MAAc,MAAgC;CAC5D,OAAO;EACL,WAAW;EACX,SAAS;EACT,UAAU;EACV,UAAU;EACV;CACF;AACF"}
package/docs/ACP.md CHANGED
@@ -235,6 +235,58 @@ process.once('SIGTERM', () => {
235
235
  The subpath also exports `createAcpServer`, JSON-RPC helpers, content mapping
236
236
  helpers, and ACP TypeScript types for custom transports and tests.
237
237
 
238
+ ## Client-Declared Tools
239
+
240
+ A zidane extension to ACP: a client can hand the agent its own tools (editor
241
+ commands, UI queries) and run them in-process. `initialize` advertises support
242
+ as `agentCapabilities._meta.zidane.clientTools: true`. The Vim/Neovim plugin in
243
+ `editors/vim` is built on it.
244
+
245
+ Declare tools in `session/new`, `session/load`, or `session/resume`:
246
+
247
+ ```json
248
+ {
249
+ "cwd": "/repo",
250
+ "mcpServers": [],
251
+ "_meta": {
252
+ "zidane": {
253
+ "clientTools": [
254
+ {
255
+ "name": "vim_exec",
256
+ "description": "Run an Ex command and return its output.",
257
+ "inputSchema": { "type": "object", "properties": { "command": { "type": "string" } }, "required": ["command"] },
258
+ "mutating": true
259
+ }
260
+ ]
261
+ }
262
+ }
263
+ }
264
+ ```
265
+
266
+ When the model calls one, the agent sends a request to the client:
267
+
268
+ ```json
269
+ { "jsonrpc": "2.0", "id": 7, "method": "_zidane/tool_call",
270
+ "params": { "sessionId": "…", "toolCallId": "…", "name": "vim_exec", "input": { "command": "ls" } } }
271
+ ```
272
+
273
+ The client replies `{ "content": "<text>", "isError": false }`. `isError: true`
274
+ fails the tool call with `content` as the message.
275
+
276
+ Rules:
277
+
278
+ - `name` starts with a letter, uses letters, digits, `_` or `-`, is at most 64
279
+ characters, and must not collide with a host tool. Violations fail the
280
+ session request with `-32602`.
281
+ - `mutating` (default `false`) tools always go through
282
+ `session/request_permission` when permissions are enabled, and are hidden
283
+ and blocked in Plan mode. Non-mutating tools stay available in Plan mode.
284
+ - A live session cannot be resumed with a different tool set; omit `_meta` on
285
+ resume to keep the existing one.
286
+ - Prompt cancellation abandons the pending `_zidane/tool_call` and sends a
287
+ `_zidane/tool_call_cancel` notification with `{ sessionId, toolCallId }` so
288
+ the client can stop the work. Clients that run tools synchronously can ignore it.
289
+
238
290
  ## Protocol Coverage
239
291
 
240
292
  The adapter targets ACP protocol version 1. It implements initialization,