0sec-cli 0.24.1 → 0.26.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 (246) hide show
  1. package/0.js +67 -62
  2. package/README.md +121 -82
  3. package/chunks/{adapt-loop-L77BWMNE.js → adapt-loop-P4HKONB5.js} +6 -5
  4. package/chunks/{artifact-scraper-BV67RAP5.js → artifact-scraper-IIRJNYKT.js} +4 -3
  5. package/chunks/{assumption-mining-RPVR77A3.js → assumption-mining-YA6VJ2V6.js} +22 -20
  6. package/chunks/{backend-connections-ACIXNYZN.js → backend-connections-64PKYKL7.js} +5 -4
  7. package/chunks/chunk-36J5ZLFE.js +18729 -0
  8. package/chunks/{chunk-ZM6ANQZJ.js → chunk-3MWQNNJU.js} +16180 -34467
  9. package/chunks/{chunk-GV5WXDHY.js → chunk-3VQ5EZKG.js} +11 -9
  10. package/chunks/chunk-5XOYTAOK.js +1546 -0
  11. package/chunks/{chunk-UJE4WOQS.js → chunk-6GV5G6U3.js} +1 -1
  12. package/chunks/{chunk-X2ZMSRTP.js → chunk-6SNOKNCS.js} +333 -3
  13. package/chunks/{chunk-BMDG6T7D.js → chunk-72PU46MS.js} +178 -133
  14. package/chunks/{chunk-KCA35IL3.js → chunk-7PUJI64A.js} +11 -9
  15. package/chunks/chunk-A7G6S5RA.js +90 -0
  16. package/chunks/chunk-ABKUI3QB.js +196 -0
  17. package/chunks/{chunk-5ETI27Q3.js → chunk-AFJ2UMPR.js} +3 -3
  18. package/chunks/{chunk-XA2IBHPB.js → chunk-B7XL6RON.js} +1 -1
  19. package/chunks/{chunk-TVS6WVSK.js → chunk-BM6EYP2D.js} +3 -3
  20. package/chunks/{chunk-7UHAXEOV.js → chunk-D4M5WURF.js} +226 -4
  21. package/chunks/{chunk-K74DRDC5.js → chunk-EHNVP6QB.js} +1 -1
  22. package/chunks/{chunk-I43YYHDU.js → chunk-FBZBJYZS.js} +5 -50
  23. package/chunks/{chunk-GXXX7AGH.js → chunk-GYEYTNHK.js} +144 -14
  24. package/chunks/{chunk-IJ6UPW3H.js → chunk-HS2NQ7K6.js} +393 -58
  25. package/chunks/chunk-HUZ2EC2R.js +196 -0
  26. package/chunks/{chunk-SU4IHQQI.js → chunk-IUUNIJPM.js} +1 -1
  27. package/chunks/chunk-JGDA6EIJ.js +49 -0
  28. package/chunks/{chunk-CJRZSWII.js → chunk-K3PTYN43.js} +3 -3
  29. package/chunks/{chunk-2NBZZFRG.js → chunk-KCABBZHN.js} +8 -10
  30. package/chunks/{chunk-3LPBJMHB.js → chunk-LRD5N2TQ.js} +1 -1
  31. package/chunks/{chunk-SQCBHFWN.js → chunk-LWMEJYCP.js} +2 -2
  32. package/chunks/chunk-MNK373HF.js +57 -0
  33. package/chunks/{chunk-R2XBH476.js → chunk-MOEVVXML.js} +2 -2
  34. package/chunks/{chunk-F2P25DJY.js → chunk-MOGWEHSC.js} +1448 -1050
  35. package/chunks/{chunk-6XMFCVJS.js → chunk-N7YCONYR.js} +1 -1
  36. package/chunks/{chunk-3WUPCZGF.js → chunk-NA3FKCI2.js} +1 -1
  37. package/chunks/{chunk-S2GITRD5.js → chunk-NABVDAAO.js} +2 -2
  38. package/chunks/{chunk-SZDD77KX.js → chunk-NNMOTHKC.js} +6 -10
  39. package/chunks/{chunk-LMP2T4G2.js → chunk-OILVEROI.js} +22 -172
  40. package/chunks/{chunk-YERUDEXT.js → chunk-PAE7ZAV6.js} +2780 -1255
  41. package/chunks/{chunk-NBV4I237.js → chunk-PAMJEXE2.js} +1 -1
  42. package/chunks/{chunk-PJU24AKR.js → chunk-R7VWEY45.js} +337 -257
  43. package/chunks/{chunk-QNRYOJEB.js → chunk-RZZ6VPRY.js} +1 -1
  44. package/chunks/{chunk-WUPN3D37.js → chunk-S4DFH2FJ.js} +26 -1
  45. package/chunks/{chunk-5WAHHZBF.js → chunk-SIR7XW2S.js} +61910 -30777
  46. package/chunks/{chunk-BD7WULFS.js → chunk-SSPP64FF.js} +3 -2
  47. package/chunks/{chunk-BOBIAHKA.js → chunk-STPHTPSD.js} +3 -333
  48. package/chunks/{chunk-Q7JKIKKF.js → chunk-UGCTPKJG.js} +89 -17
  49. package/chunks/{chunk-5PFRE522.js → chunk-ULRLUXSS.js} +1 -1
  50. package/chunks/{chunk-GZA7RGK7.js → chunk-UQS7XCBV.js} +2085 -1093
  51. package/chunks/{chunk-X2IPO5JO.js → chunk-V2KJQVYE.js} +2676 -2959
  52. package/chunks/{chunk-CGBDEST2.js → chunk-VJBEB2K6.js} +1 -1
  53. package/chunks/{chunk-ILRMLA6J.js → chunk-VWE36MUN.js} +1 -1
  54. package/chunks/{chunk-RURJYCWY.js → chunk-WNWDQ2TO.js} +1 -1
  55. package/chunks/{chunk-GTED3FSZ.js → chunk-WPJMA5AK.js} +4 -99
  56. package/chunks/{chunk-5NFIY2SJ.js → chunk-XJ2TBEV7.js} +3 -3
  57. package/chunks/{chunk-PVJUPIQG.js → chunk-XOVYV7TT.js} +6 -6
  58. package/chunks/{chunk-IXT64DV5.js → chunk-XPDJE537.js} +97 -1
  59. package/chunks/{chunk-YKWARO3T.js → chunk-YGYJ2FTH.js} +95 -21
  60. package/chunks/{chunk-JWSOUKFF.js → chunk-YJGPPPUB.js} +66 -21
  61. package/chunks/chunk-YP2DHYNI.js +650 -0
  62. package/chunks/{chunk-RVJVM5L4.js → chunk-Z2VLJEQJ.js} +5 -5
  63. package/chunks/chunk-ZPVSDB63.js +3839 -0
  64. package/chunks/{codex-models-6XVNFRXZ.js → codex-models-CI22KIHY.js} +9 -8
  65. package/chunks/{commands-FRPOFIO4.js → commands-C2WRSCNB.js} +909 -610
  66. package/chunks/dashboard-XO2X2SPD.js +75 -0
  67. package/chunks/{db-BXJNWUYJ.js → db-FU3OIGQK.js} +5 -4
  68. package/chunks/{deep-review-GSJEBLCG.js → deep-review-5AL6QYTK.js} +37 -38
  69. package/chunks/{disclose-OU6Z6GVT.js → disclose-YPV5KIUU.js} +6 -5
  70. package/chunks/{dist-M2X367VW.js → dist-JAZWL3SC.js} +3 -2
  71. package/chunks/{dist-TQMHMSBZ.js → dist-ONIRKDH6.js} +376 -333
  72. package/chunks/{dist-RKLQIXDT.js → dist-QLMPTFT7.js} +4 -3
  73. package/chunks/{dist-7KSYDDSG.js → dist-QXJKD743.js} +5 -2
  74. package/chunks/{dist-LNXGATR2.js → dist-WNAOCQGA.js} +5 -4
  75. package/chunks/eval-runner-D3RUCU3R.js +38 -0
  76. package/chunks/{exploit-agent-Y2P4GFIY.js → exploit-agent-4E4HXKUA.js} +1 -1
  77. package/chunks/{exploit-autoclimb-YRZ3TMS2.js → exploit-autoclimb-5GRXI6VQ.js} +1 -1
  78. package/chunks/{exploit-climb-4LEY4SDW.js → exploit-climb-AHQEJ2I2.js} +4 -3
  79. package/chunks/{fix-RQSIG75B.js → fix-CHD7LXDS.js} +9 -8
  80. package/chunks/{harness-3NVC3DDY.js → harness-E63KDHPG.js} +5 -4
  81. package/chunks/{http-conformance-U5F6GKYG.js → http-conformance-AXMUOE6C.js} +3 -2
  82. package/chunks/hunt-scan-ME2Z4CTC.js +43 -0
  83. package/chunks/{kernel-primitive-T47V3RD3.js → kernel-primitive-S566GXWP.js} +4 -3
  84. package/chunks/{kernel-vm-runner-AEL5E3SV.js → kernel-vm-runner-KREBY4DC.js} +4 -3
  85. package/chunks/{local-engine-ZCW4YC6E.js → local-engine-ZRTZVSSX.js} +7 -6
  86. package/chunks/managed-operation-ZMLLRCCQ.js +59 -0
  87. package/chunks/{memsafety-scan-L2Z7E7TE.js → memsafety-scan-Q2MBZEGJ.js} +1 -2
  88. package/chunks/{native-loop-26X2CHBV.js → native-loop-UV3Z4Z2F.js} +31 -16
  89. package/chunks/operator-services-JOCREEBA.js +79 -0
  90. package/chunks/orchestrate-ZF6ZTSIQ.js +62 -0
  91. package/chunks/{prepare-C3KGMBXT.js → prepare-PLDVGLDX.js} +7 -6
  92. package/chunks/{provider-model-discovery-QGUGL3XW.js → provider-model-discovery-3X6DON3Y.js} +7 -2
  93. package/chunks/{remote-workflow-runtime-DB52SINR.js → remote-workflow-runtime-GOI4TYP5.js} +4 -3
  94. package/chunks/routing-WCQLO5SP.js +61 -0
  95. package/chunks/{runtime-AUBLQUOH.js → runtime-6ZIXFTW5.js} +4 -3
  96. package/chunks/{runtime-U66JNSAY.js → runtime-TVH5ORUK.js} +13 -8
  97. package/chunks/{scan-stream-34F3LTPV.js → scan-stream-HJVTWZ44.js} +6 -4
  98. package/chunks/{scope-HSTG63TQ.js → scope-RCYXVGJR.js} +4 -3
  99. package/chunks/service-plugins-TN6KDX4L.js +63 -0
  100. package/chunks/{session-store-MKAAP3WL.js → session-store-6QR3CVUA.js} +8 -5
  101. package/chunks/{variant-candidates-LG767HWH.js → variant-candidates-SGLKPPHI.js} +9 -8
  102. package/chunks/{web-recon-prepass-NJP6J3E4.js → web-recon-prepass-GO7CTMVQ.js} +7 -6
  103. package/chunks/{workflow-runtime-AR627I26.js → workflow-runtime-CQTDASFA.js} +50 -49
  104. package/dashboard/assets/{abnfDiagram-VCTEODGH-Cq149Jpk.js → abnfDiagram-VCTEODGH-DDZsU70-.js} +1 -1
  105. package/dashboard/assets/{arc-CpP-3TRW.js → arc-iDXNTSL6.js} +1 -1
  106. package/dashboard/assets/architecture-7GRP2DOG-DJcY9RFg.js +1 -0
  107. package/dashboard/assets/architectureDiagram-5GKGNRK7-d0ZuOniQ.js +36 -0
  108. package/dashboard/assets/{blockDiagram-I7D4REHJ-CZYkRRDi.js → blockDiagram-I7D4REHJ-B-EWfMy1.js} +2 -2
  109. package/dashboard/assets/{c4Diagram-7LVT6UL2-CV7Iu3_Z.js → c4Diagram-7LVT6UL2-KcZRuXZC.js} +1 -1
  110. package/dashboard/assets/channel-CeWMIm0w.js +1 -0
  111. package/dashboard/assets/{chunk-4HAMMTFA-PKCyW4m-.js → chunk-4HAMMTFA-DXWulBlo.js} +1 -1
  112. package/dashboard/assets/{chunk-75Z2AOVW-C5MlFTc_.js → chunk-75Z2AOVW-RiLZItrz.js} +1 -1
  113. package/dashboard/assets/chunk-DU6HZSFF-MBcaIyTX.js +127 -0
  114. package/dashboard/assets/{chunk-F27PBJKO-DTAok0qM.js → chunk-F27PBJKO-kLWCBX_W.js} +1 -1
  115. package/dashboard/assets/{chunk-FOHPRMQF-DHwB1DNv.js → chunk-FOHPRMQF-COOliuUh.js} +14 -14
  116. package/dashboard/assets/{chunk-GMAD6QVW-CPsr2F33.js → chunk-GMAD6QVW-BeQeSjpW.js} +7 -7
  117. package/dashboard/assets/{chunk-GVQU2GXP-C2AXGf9A.js → chunk-GVQU2GXP-CjCMlOIB.js} +1 -1
  118. package/dashboard/assets/{chunk-IMKFNOWR-DMG6yD_O.js → chunk-IMKFNOWR-BwNst53D.js} +1 -1
  119. package/dashboard/assets/{chunk-L3NEJ4N5-BSvwdbXx.js → chunk-L3NEJ4N5-CHXWQrkL.js} +1 -1
  120. package/dashboard/assets/{chunk-OSK3NFVY-CfB8V7FU.js → chunk-OSK3NFVY-B2vd19Ed.js} +1 -1
  121. package/dashboard/assets/{chunk-P2QGCYS3-CvmZvq6n.js → chunk-P2QGCYS3-Dk7Fyh6n.js} +1 -1
  122. package/dashboard/assets/{chunk-POPQ4Y6H-D_TvwDxL.js → chunk-POPQ4Y6H-CPAgOvYe.js} +1 -1
  123. package/dashboard/assets/{chunk-PWAF6VOD-Da5GnuOY.js → chunk-PWAF6VOD-BotyfMha.js} +1 -1
  124. package/dashboard/assets/{chunk-SHT3W25Y-CcsMJpR-.js → chunk-SHT3W25Y-Buz5gLRP.js} +1 -1
  125. package/dashboard/assets/{chunk-SVP7TREG-COojjieJ.js → chunk-SVP7TREG-_rpYEZcs.js} +1 -1
  126. package/dashboard/assets/{chunk-TICWLB2K-nBAmJwx6.js → chunk-TICWLB2K-DOJxPoec.js} +2 -2
  127. package/dashboard/assets/{chunk-XXDRQBXY-r5HyhWDv.js → chunk-XXDRQBXY-EXxKJbAs.js} +1 -1
  128. package/dashboard/assets/classDiagram-ZZMXUADV-DV_h1NoS.js +1 -0
  129. package/dashboard/assets/classDiagram-v2-VYDZK3BY-DV_h1NoS.js +1 -0
  130. package/dashboard/assets/common-VLJRx-Jq.js +5 -0
  131. package/dashboard/assets/cose-bilkent-JH36ORCC-B1SVC57o.js +1 -0
  132. package/dashboard/assets/cynefin-OW5HDTMX-BzhRorj4.js +1 -0
  133. package/dashboard/assets/{cynefinDiagram-5FMLGOSQ-xodkuQtW.js → cynefinDiagram-5FMLGOSQ-JXzRmldX.js} +1 -1
  134. package/dashboard/assets/cytoscape.esm-BbBREfsg.js +321 -0
  135. package/dashboard/assets/dagre-D7JM2Yhv.js +1 -0
  136. package/dashboard/assets/dagre-GXQ25YYZ-1LZ-X0-Z.js +4 -0
  137. package/dashboard/assets/{diagram-S7CK7UJ4-DNoTMlCO.js → diagram-S7CK7UJ4-C_-J_LQ4.js} +2 -2
  138. package/dashboard/assets/{diagram-UQ7AKVKN-COccuyew.js → diagram-UQ7AKVKN-CnxL1k8g.js} +1 -1
  139. package/dashboard/assets/{diagram-VSXAHHWV-g6D1tWRb.js → diagram-VSXAHHWV-WzSb3aby.js} +1 -1
  140. package/dashboard/assets/{diagram-VX7I27RA-DhO4eVIC.js → diagram-VX7I27RA-DKhrMInE.js} +1 -1
  141. package/dashboard/assets/{diagram-Z3DM3KII-DeOQFexd.js → diagram-Z3DM3KII-CDhI2WGP.js} +1 -1
  142. package/dashboard/assets/{dist-BQYeOQg3.js → dist-B0bfBMeP.js} +1 -1
  143. package/dashboard/assets/{ebnfDiagram-PWID7BFC-MtkX2feM.js → ebnfDiagram-PWID7BFC-iL5NQ1PE.js} +1 -1
  144. package/dashboard/assets/{erDiagram-RLTQ6QDP-DIWSsoYZ.js → erDiagram-RLTQ6QDP-RK2Voa5O.js} +1 -1
  145. package/dashboard/assets/eventmodeling-NTZA5JFV-WgE7OJBb.js +1 -0
  146. package/dashboard/assets/flowDiagram-HODETNUW-B9YcQ0Aq.js +1 -0
  147. package/dashboard/assets/{ganttDiagram-EL5Y4UJY-DKggkJe0.js → ganttDiagram-EL5Y4UJY-D8CJXHRF.js} +1 -1
  148. package/dashboard/assets/gitGraph-4MIJSDKK-BuZ9Lg04.js +1 -0
  149. package/dashboard/assets/{gitGraphDiagram-WWUBYQGX-r_iR8Qzo.js → gitGraphDiagram-WWUBYQGX-LEJMh54j.js} +1 -1
  150. package/dashboard/assets/info-A6RAGUB7-BL5k3pev.js +1 -0
  151. package/dashboard/assets/{infoDiagram-27XIBGKW-ClQk7UyQ.js → infoDiagram-27XIBGKW-LJvntUnZ.js} +1 -1
  152. package/dashboard/assets/{ishikawaDiagram-5VMMS53U-tR7Vziog.js → ishikawaDiagram-5VMMS53U-BYTYgKCG.js} +2 -2
  153. package/dashboard/assets/{journeyDiagram-3NMN7TZE-Cpb9IqKL.js → journeyDiagram-3NMN7TZE-G25qgQgO.js} +1 -1
  154. package/dashboard/assets/{kanban-definition-UXKFOSKX-BzUuKbA9.js → kanban-definition-UXKFOSKX-Bk3uLl1i.js} +1 -1
  155. package/dashboard/assets/{katex-BdBmVSus.js → katex-nLxf_RlZ.js} +2 -2
  156. package/dashboard/assets/{line-BHY_tSHu.js → line-i4qHBaWO.js} +1 -1
  157. package/dashboard/assets/linear-DmrqRsKG.js +1 -0
  158. package/dashboard/assets/mermaid-parser.core-BxbKr4QF.js +7 -0
  159. package/dashboard/assets/{mermaid.core-D_QsUPU8.js → mermaid.core-Cltee6FS.js} +9 -9
  160. package/dashboard/assets/{mindmap-definition-YA3MSWOX-CtfLTPPJ.js → mindmap-definition-YA3MSWOX-DkzO2JgS.js} +1 -1
  161. package/dashboard/assets/operations-B4_timQX.css +1 -0
  162. package/dashboard/assets/operations-DwppJviL.js +199 -0
  163. package/dashboard/assets/packet-AYTQ26CC-uZQUKnrE.js +1 -0
  164. package/dashboard/assets/{pegDiagram-XKGWAZYB-C1Dclbzj.js → pegDiagram-XKGWAZYB-CrOEi00T.js} +1 -1
  165. package/dashboard/assets/pie-WAS4IAKB-Dn9_tpQT.js +1 -0
  166. package/dashboard/assets/{pieDiagram-E7YTZNPT-Cd7XwYo5.js → pieDiagram-E7YTZNPT-D-niUkzc.js} +1 -1
  167. package/dashboard/assets/{quadrantDiagram-AXDQQJYC-CaS-GQ4X.js → quadrantDiagram-AXDQQJYC-CJOTiG5V.js} +1 -1
  168. package/dashboard/assets/radar-RG4KPBEZ-DIIVz4e8.js +1 -0
  169. package/dashboard/assets/railroad-74A4TZTK-1kiqDEID.js +1 -0
  170. package/dashboard/assets/railroad-abnf-HS5TGJTU-DK6rQPZR.js +1 -0
  171. package/dashboard/assets/railroad-ebnf-LZEXJU2U-C6cOgYW4.js +1 -0
  172. package/dashboard/assets/railroad-peg-WCYAUIDC-CQ3ptKef.js +1 -0
  173. package/dashboard/assets/{railroadDiagram-O6MQD6OU-BeesTrqn.js → railroadDiagram-O6MQD6OU-nEfkpa-m.js} +1 -1
  174. package/dashboard/assets/{requirementDiagram-BXWQKSXE-IjyK0DhW.js → requirementDiagram-BXWQKSXE-CdFMY8tG.js} +1 -1
  175. package/dashboard/assets/{sankeyDiagram-P5KCCOFB-DmIluQqo.js → sankeyDiagram-P5KCCOFB-C0KxrFYv.js} +1 -1
  176. package/dashboard/assets/{sequenceDiagram-WJ2MYXX4-CUp8ZjTc.js → sequenceDiagram-WJ2MYXX4-DeZ5ATiu.js} +2 -2
  177. package/dashboard/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  178. package/dashboard/assets/src-Cg-chcoE.js +1 -0
  179. package/dashboard/assets/{stateDiagram-D77RDMKH-Dy9TQb8P.js → stateDiagram-D77RDMKH-B9MwWL5B.js} +1 -1
  180. package/dashboard/assets/stateDiagram-v2-MP3YSRHH-SucFndhx.js +1 -0
  181. package/dashboard/assets/swimlanes-42K2YHIH-DB--fwQE.js +1 -0
  182. package/dashboard/assets/swimlanesDiagram-VR7AAH4N-BzH-rIaK.js +8 -0
  183. package/dashboard/assets/{timeline-definition-24CTP7MA-BGdXW-iY.js → timeline-definition-24CTP7MA-DLkkTbWb.js} +1 -1
  184. package/dashboard/assets/treeView-Q6P3EWNA-XkZ9rl9H.js +1 -0
  185. package/dashboard/assets/treemap-WGGIJYW6-JCtVKxCE.js +1 -0
  186. package/dashboard/assets/{vennDiagram-4TSXK5OY-DzKWHJsl.js → vennDiagram-4TSXK5OY-DEb-x29Z.js} +1 -1
  187. package/dashboard/assets/wardley-WFR3VGLG-DhI7ROY3.js +1 -0
  188. package/dashboard/assets/{wardleyDiagram-VM6X3IG4-DGsjYmNJ.js → wardleyDiagram-VM6X3IG4-KNckudc5.js} +1 -1
  189. package/dashboard/assets/{xychartDiagram-S5SC5T6Z-C7_T_tWt.js → xychartDiagram-S5SC5T6Z-D4c0ynCk.js} +1 -1
  190. package/dashboard/index.html +13 -2
  191. package/package.json +2 -5
  192. package/worker-assets/demo-target/README.md +7 -3
  193. package/chunks/chunk-2XGBEH53.js +0 -4304
  194. package/chunks/chunk-4ROZFLSR.js +0 -279
  195. package/chunks/chunk-56UTQKXO.js +0 -56
  196. package/chunks/chunk-BPU6M42R.js +0 -77
  197. package/chunks/chunk-H5QURBBK.js +0 -1123
  198. package/chunks/chunk-IIBNQTOK.js +0 -1532
  199. package/chunks/chunk-NJLKFC66.js +0 -4790
  200. package/chunks/chunk-OOMBOLAF.js +0 -295
  201. package/chunks/chunk-VIT5ALXF.js +0 -4054
  202. package/chunks/chunk-VU7V2SDW.js +0 -284
  203. package/chunks/chunk-W624J7NF.js +0 -117
  204. package/chunks/chunk-YSQWZ67M.js +0 -6027
  205. package/chunks/dashboard-5HDSNBAU.js +0 -76
  206. package/chunks/eval-runner-A2DIGVP7.js +0 -31
  207. package/chunks/hunt-scan-W246VWJC.js +0 -40
  208. package/chunks/managed-operation-6R2QPPW5.js +0 -60
  209. package/chunks/orchestrate-OBS37FWQ.js +0 -63
  210. package/chunks/run-MU3MFL2Z.js +0 -28242
  211. package/chunks/service-plugins-5B23PWXC.js +0 -64
  212. package/dashboard/assets/architecture-7GRP2DOG-z5EHYkyH.js +0 -1
  213. package/dashboard/assets/architectureDiagram-5GKGNRK7-ewtXpjR_.js +0 -36
  214. package/dashboard/assets/channel-CuYjfiC5.js +0 -1
  215. package/dashboard/assets/chunk-DU6HZSFF-3M37ulcO.js +0 -127
  216. package/dashboard/assets/classDiagram-ZZMXUADV-DCuOrWUV.js +0 -1
  217. package/dashboard/assets/classDiagram-v2-VYDZK3BY-DCuOrWUV.js +0 -1
  218. package/dashboard/assets/common-C6snVPsk.js +0 -5
  219. package/dashboard/assets/cose-bilkent-JH36ORCC-BLGcaZHk.js +0 -1
  220. package/dashboard/assets/cynefin-OW5HDTMX-DbZMK00I.js +0 -1
  221. package/dashboard/assets/cytoscape.esm-CGd-uY3x.js +0 -321
  222. package/dashboard/assets/dagre-GXQ25YYZ-CRk9qfSG.js +0 -4
  223. package/dashboard/assets/dagre-PrKaheQc.js +0 -1
  224. package/dashboard/assets/eventmodeling-NTZA5JFV-D_3ez4Gv.js +0 -1
  225. package/dashboard/assets/flowDiagram-HODETNUW-D2boyYEd.js +0 -1
  226. package/dashboard/assets/gitGraph-4MIJSDKK-DFOQYwXc.js +0 -1
  227. package/dashboard/assets/info-A6RAGUB7-DeednLoB.js +0 -1
  228. package/dashboard/assets/linear-naZZ1pHk.js +0 -1
  229. package/dashboard/assets/mermaid-parser.core-CPvd4cEx.js +0 -7
  230. package/dashboard/assets/operations-BwCzhVnT.js +0 -130
  231. package/dashboard/assets/operations-QjKT0Hwi.css +0 -1
  232. package/dashboard/assets/packet-AYTQ26CC-DDQbkT9I.js +0 -1
  233. package/dashboard/assets/pie-WAS4IAKB-LpU4ULAs.js +0 -1
  234. package/dashboard/assets/radar-RG4KPBEZ-CcxW3NJm.js +0 -1
  235. package/dashboard/assets/railroad-74A4TZTK-9P5Rl8fP.js +0 -1
  236. package/dashboard/assets/railroad-abnf-HS5TGJTU-CSfpwjna.js +0 -1
  237. package/dashboard/assets/railroad-ebnf-LZEXJU2U-D6R5qzr-.js +0 -1
  238. package/dashboard/assets/railroad-peg-WCYAUIDC-DKEX7ITG.js +0 -1
  239. package/dashboard/assets/sizeCapture-INFHLROL-B0uUizjq.js +0 -1
  240. package/dashboard/assets/src-r61wDjcA.js +0 -1
  241. package/dashboard/assets/stateDiagram-v2-MP3YSRHH-CQb0ZtPr.js +0 -1
  242. package/dashboard/assets/swimlanes-42K2YHIH-CZuDV7V5.js +0 -1
  243. package/dashboard/assets/swimlanesDiagram-VR7AAH4N-BxgWMq8X.js +0 -8
  244. package/dashboard/assets/treeView-Q6P3EWNA-DlRrayjM.js +0 -1
  245. package/dashboard/assets/treemap-WGGIJYW6-C6UqLKfI.js +0 -1
  246. package/dashboard/assets/wardley-WFR3VGLG-thmyHKb0.js +0 -1
@@ -0,0 +1,3839 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0CreateRequire } from "node:module";
3
+ const require = __0CreateRequire(import.meta.url);
4
+ import {
5
+ getRuntimeAvailability
6
+ } from "./chunk-MNK373HF.js";
7
+ import {
8
+ ServicePluginServices,
9
+ consoleExecutionProfile
10
+ } from "./chunk-KCABBZHN.js";
11
+ import {
12
+ accountEnvPatch,
13
+ addAccount,
14
+ connectionConfigEnvPatch,
15
+ credentialEnvPatch,
16
+ defaultWriteLayer,
17
+ getSettingSources,
18
+ getSettings,
19
+ listAccounts,
20
+ loadAccountStore,
21
+ loadConnectionConfigs,
22
+ loadCredentials,
23
+ logoutProvider,
24
+ maybeLoadCodexAuth,
25
+ removeAccount,
26
+ resetSettings,
27
+ saveAccountStore,
28
+ saveConnectionConfig,
29
+ setActiveAccount,
30
+ updateSetting,
31
+ validateConnectionConfig
32
+ } from "./chunk-OILVEROI.js";
33
+ import {
34
+ DEFAULT_SETTINGS,
35
+ PROVIDERS,
36
+ SETTING_DEFS,
37
+ allThemeNames,
38
+ appendFeedback,
39
+ buildSubmitPreview,
40
+ getThemeEntry,
41
+ installedThemeEntries,
42
+ isKnownTheme,
43
+ isOperatorSetting,
44
+ isSafeThemeId,
45
+ providerStates,
46
+ reloadInstalledThemes,
47
+ submitFeedback,
48
+ syncThemeChoices,
49
+ validateTheme,
50
+ writeInstalledTheme
51
+ } from "./chunk-V2KJQVYE.js";
52
+ import {
53
+ DEFAULT_REGISTRY_URL,
54
+ createConsoleRuntime,
55
+ listProjectReviewChecks,
56
+ updateProjectReviewChecks
57
+ } from "./chunk-3MWQNNJU.js";
58
+ import {
59
+ getRuntimeMetadata
60
+ } from "./chunk-VWE36MUN.js";
61
+ import {
62
+ TOOL_DEFINITIONS,
63
+ getToolsForRole
64
+ } from "./chunk-SIR7XW2S.js";
65
+ import {
66
+ CodexCatalogRefreshError
67
+ } from "./chunk-PAMJEXE2.js";
68
+ import {
69
+ LlmApiRuntime
70
+ } from "./chunk-HS2NQ7K6.js";
71
+ import {
72
+ aggregateCapabilities,
73
+ disable,
74
+ isSafePluginId,
75
+ listInstalledPluginIds,
76
+ pluginsRootDir,
77
+ readEnablement,
78
+ readInstalledPlugin,
79
+ writeEnablement
80
+ } from "./chunk-RZZ6VPRY.js";
81
+ import {
82
+ MODEL_PRICING,
83
+ VERSION,
84
+ getRates,
85
+ homeStateDir,
86
+ modelProvider,
87
+ registerModelPricing
88
+ } from "./chunk-GYEYTNHK.js";
89
+
90
+ // packages/cli/src/web/operator-services.ts
91
+ import { execFileSync } from "node:child_process";
92
+ import { realpathSync, statSync } from "node:fs";
93
+ import { basename, resolve as resolve3 } from "node:path";
94
+ import { randomUUID as randomUUID3 } from "node:crypto";
95
+
96
+ // packages/cli/src/tui/chatgpt-plan-store.ts
97
+ import { randomUUID } from "node:crypto";
98
+ import { closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
99
+ import { join } from "node:path";
100
+
101
+ // packages/cli/src/tui/chatgpt-plan-auth.ts
102
+ import { createHash, randomBytes } from "node:crypto";
103
+ import { createServer } from "node:http";
104
+
105
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/buffer_utils.js
106
+ var encoder = new TextEncoder();
107
+ var decoder = new TextDecoder();
108
+ var strictDecoder = new TextDecoder("utf-8", { fatal: true });
109
+ var MAX_INT32 = 2 ** 32;
110
+ function concat(...buffers) {
111
+ const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
112
+ let i = 0;
113
+ for (const buffer of buffers)
114
+ buf.set(buffer, i), i += buffer.length;
115
+ return buf;
116
+ }
117
+ var NON_ASCII = /[^\x00-\x7f]/;
118
+ function encode(string) {
119
+ if (typeof string == "string" && string.length >= 128) {
120
+ if (NON_ASCII.test(string))
121
+ throw new TypeError("non-ASCII string encountered in encode()");
122
+ return encoder.encode(string);
123
+ }
124
+ const bytes = new Uint8Array(string.length);
125
+ for (let i = 0; i < string.length; i++) {
126
+ const code = string.charCodeAt(i);
127
+ if (code > 127)
128
+ throw new TypeError("non-ASCII string encountered in encode()");
129
+ bytes[i] = code;
130
+ }
131
+ return bytes;
132
+ }
133
+ function decodeBase64(encoded, url = false) {
134
+ if (Uint8Array.fromBase64)
135
+ return Uint8Array.fromBase64(encoded, { alphabet: url ? "base64url" : "base64" });
136
+ if (url) {
137
+ if (encoded.includes("+") || encoded.includes("/"))
138
+ throw new TypeError("Invalid base64url");
139
+ encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
140
+ }
141
+ const binary = atob(encoded), bytes = new Uint8Array(binary.length);
142
+ for (let i = 0; i < binary.length; i++)
143
+ bytes[i] = binary.charCodeAt(i);
144
+ return bytes;
145
+ }
146
+
147
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/util/errors.js
148
+ var JOSEError = class extends Error {
149
+ static code = "ERR_JOSE_GENERIC";
150
+ code = "ERR_JOSE_GENERIC";
151
+ constructor(message2, options) {
152
+ super(message2, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);
153
+ }
154
+ };
155
+ var JWTClaimValidationFailed = class extends JOSEError {
156
+ static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
157
+ code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
158
+ claim;
159
+ reason;
160
+ payload;
161
+ constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
162
+ super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
163
+ }
164
+ };
165
+ var JWTExpired = class extends JOSEError {
166
+ static code = "ERR_JWT_EXPIRED";
167
+ code = "ERR_JWT_EXPIRED";
168
+ claim;
169
+ reason;
170
+ payload;
171
+ constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
172
+ super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
173
+ }
174
+ };
175
+ var JOSEAlgNotAllowed = class extends JOSEError {
176
+ static code = "ERR_JOSE_ALG_NOT_ALLOWED";
177
+ code = "ERR_JOSE_ALG_NOT_ALLOWED";
178
+ };
179
+ var JOSENotSupported = class extends JOSEError {
180
+ static code = "ERR_JOSE_NOT_SUPPORTED";
181
+ code = "ERR_JOSE_NOT_SUPPORTED";
182
+ };
183
+ var JWSInvalid = class extends JOSEError {
184
+ static code = "ERR_JWS_INVALID";
185
+ code = "ERR_JWS_INVALID";
186
+ };
187
+ var JWTInvalid = class extends JOSEError {
188
+ static code = "ERR_JWT_INVALID";
189
+ code = "ERR_JWT_INVALID";
190
+ };
191
+ var JWKSInvalid = class extends JOSEError {
192
+ static code = "ERR_JWKS_INVALID";
193
+ code = "ERR_JWKS_INVALID";
194
+ };
195
+ var JWKSNoMatchingKey = class extends JOSEError {
196
+ static code = "ERR_JWKS_NO_MATCHING_KEY";
197
+ code = "ERR_JWKS_NO_MATCHING_KEY";
198
+ constructor(message2 = "no applicable key found in the JSON Web Key Set", options) {
199
+ super(message2, options);
200
+ }
201
+ };
202
+ var JWKSMultipleMatchingKeys = class extends JOSEError {
203
+ [Symbol.asyncIterator] = async function* () {
204
+ };
205
+ static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
206
+ code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
207
+ constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) {
208
+ super(message2, options);
209
+ }
210
+ };
211
+ var JWKSTimeout = class extends JOSEError {
212
+ static code = "ERR_JWKS_TIMEOUT";
213
+ code = "ERR_JWKS_TIMEOUT";
214
+ constructor(message2 = "request timed out", options) {
215
+ super(message2, options);
216
+ }
217
+ };
218
+ var JWSSignatureVerificationFailed = class extends JOSEError {
219
+ static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
220
+ code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
221
+ constructor(message2 = "signature verification failed", options) {
222
+ super(message2, options);
223
+ }
224
+ };
225
+
226
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/util/base64url.js
227
+ var invalid = "The input to be decoded is not correctly encoded.";
228
+ function decode(input) {
229
+ try {
230
+ return decodeBase64(typeof input == "string" ? input : decoder.decode(input), true);
231
+ } catch (cause) {
232
+ throw new TypeError(invalid, { cause });
233
+ }
234
+ }
235
+
236
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/validate.js
237
+ function isObject(input) {
238
+ if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]")
239
+ return false;
240
+ const prototype = Object.getPrototypeOf(input);
241
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
242
+ }
243
+ function isJwkSet(input) {
244
+ return isObject(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject);
245
+ }
246
+ function isDisjoint(...headers) {
247
+ const parameters = /* @__PURE__ */ new Set();
248
+ for (const header of headers)
249
+ if (header)
250
+ for (const parameter of Object.keys(header)) {
251
+ if (parameters.has(parameter))
252
+ return false;
253
+ parameters.add(parameter);
254
+ }
255
+ return true;
256
+ }
257
+ function decodeBase64url(value, label, ErrorClass) {
258
+ try {
259
+ return decode(value);
260
+ } catch {
261
+ throw new ErrorClass(`Failed to base64url decode the ${label}`);
262
+ }
263
+ }
264
+ function encodeBase64url(value, label, ErrorClass) {
265
+ try {
266
+ return encode(value);
267
+ } catch {
268
+ throw new ErrorClass(`The ${label} is not a valid base64url string`);
269
+ }
270
+ }
271
+ function parseJoseHeader(b64, ErrorClass, message2) {
272
+ let parsed;
273
+ try {
274
+ parsed = JSON.parse(strictDecoder.decode(decode(b64)));
275
+ } catch {
276
+ throw new ErrorClass(message2);
277
+ }
278
+ if (!isObject(parsed))
279
+ throw new ErrorClass(message2);
280
+ return parsed;
281
+ }
282
+ var JWS_RECOGNIZED = { __proto__: null, b64: true };
283
+ function validateAlgorithms(option, algorithms) {
284
+ if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != "string")))
285
+ throw new TypeError(`"${option}" option must be an array of strings`);
286
+ return algorithms === void 0 ? void 0 : new Set(algorithms);
287
+ }
288
+ function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
289
+ if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0)
290
+ throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
291
+ if (!protectedHeader || protectedHeader.crit === void 0)
292
+ return [];
293
+ if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != "string" || input.length === 0))
294
+ throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
295
+ const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };
296
+ for (const parameter of protectedHeader.crit) {
297
+ if (!(parameter in recognized))
298
+ throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
299
+ if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0)
300
+ throw new Err(`Extension Header Parameter "${parameter}" is missing`);
301
+ if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0))
302
+ throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
303
+ }
304
+ return protectedHeader.crit;
305
+ }
306
+ function validateB64(protectedHeader, extensions) {
307
+ if (extensions.includes("b64")) {
308
+ const b64 = protectedHeader.b64;
309
+ if (typeof b64 != "boolean")
310
+ throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
311
+ return b64;
312
+ }
313
+ return true;
314
+ }
315
+
316
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/key.js
317
+ var tag = (key) => key[Symbol.toStringTag];
318
+ var jwkMatchesOp = (entry, key, usage) => {
319
+ const { alg } = entry;
320
+ if (key.use !== void 0) {
321
+ const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
322
+ if (key.use !== expected)
323
+ throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
324
+ }
325
+ if (key.alg !== void 0 && key.alg !== alg)
326
+ throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
327
+ if (Array.isArray(key.key_ops)) {
328
+ const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
329
+ if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))
330
+ throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
331
+ }
332
+ };
333
+ async function prepareKey(entry, key, usage) {
334
+ const { alg, secret } = entry, privateKey = usage === "decrypt" || usage === "sign";
335
+ if (secret && key instanceof Uint8Array)
336
+ return key;
337
+ let normalized, keyObject;
338
+ if (isObject(key)) {
339
+ if (normalized = normalizeJwk(key), typeof normalized.kty != "string")
340
+ throw invalidKeyType(alg, key, secret);
341
+ if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (privateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === void 0 && normalized.priv === void 0)))
342
+ throw new TypeError(secret ? 'JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present' : `JSON Web Key for this operation must be a ${privateKey ? "private" : "public"} JWK`);
343
+ if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct")
344
+ return decode(normalized.k);
345
+ if (!Object.isFrozen(key)) {
346
+ const { key_ops } = key;
347
+ Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);
348
+ }
349
+ } else {
350
+ if (!isKeyLike(key))
351
+ throw invalidKeyType(alg, key, secret);
352
+ const expectedType = secret ? "secret" : privateKey ? "private" : "public";
353
+ if (key.type !== expectedType && (secret || ["secret", "public", "private"].includes(key.type)))
354
+ throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
355
+ if (isCryptoKey(key))
356
+ return key;
357
+ if (keyObject = key, keyObject.type === "secret")
358
+ return keyObject.export();
359
+ }
360
+ cache ||= /* @__PURE__ */ new WeakMap();
361
+ const cacheKey = key;
362
+ let cached = cache.get(cacheKey);
363
+ if (cached?.[alg])
364
+ return cached[alg];
365
+ if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == "function") {
366
+ const isPublic = keyObject.type === "public", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({ crv, asymmetricKeyType: keyObject.asymmetricKeyType }) ?? entry.subtle;
367
+ return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);
368
+ }
369
+ return normalized ??= keyObject.export({ format: "jwk" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);
370
+ }
371
+ var cache;
372
+ var nist = {
373
+ __proto__: null,
374
+ prime256v1: "P-256",
375
+ secp384r1: "P-384",
376
+ secp521r1: "P-521"
377
+ };
378
+ var isCryptoKey = (key) => {
379
+ if (key?.[Symbol.toStringTag] === "CryptoKey")
380
+ return true;
381
+ try {
382
+ return key instanceof CryptoKey;
383
+ } catch {
384
+ return false;
385
+ }
386
+ };
387
+ var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
388
+ var isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
389
+ function message(msg, actual, ...types) {
390
+ if (types.length > 2) {
391
+ const last = types.pop();
392
+ msg += `one of type ${types.join(", ")}, or ${last}.`;
393
+ } else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
394
+ return actual == null ? msg += ` Received ${actual}` : typeof actual == "function" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == "object" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;
395
+ }
396
+ function invalidKeyType(alg, actual, secret) {
397
+ const types = ["CryptoKey", "KeyObject", "JSON Web Key"];
398
+ return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
399
+ }
400
+ var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
401
+ function checkUsage(key, usage) {
402
+ if (usage && !key.usages.includes(usage))
403
+ throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
404
+ }
405
+ function checkModulusLength(alg, key) {
406
+ const { modulusLength } = key.algorithm;
407
+ if (typeof modulusLength != "number" || modulusLength < 2048)
408
+ throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
409
+ }
410
+ function checkCryptoKey(key, expected, usage) {
411
+ const algorithm = key.algorithm;
412
+ if (algorithm.name !== expected.name)
413
+ throw unusable(expected.name);
414
+ if (expected.hash && algorithm.hash?.name !== expected.hash)
415
+ throw unusable(expected.hash, "algorithm.hash");
416
+ if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)
417
+ throw unusable(expected.namedCurve, "algorithm.namedCurve");
418
+ if (expected.length !== void 0 && algorithm.length !== expected.length)
419
+ throw unusable(expected.length, "algorithm.length");
420
+ checkUsage(key, usage);
421
+ }
422
+ function snapshotJwk(jwk) {
423
+ return { __proto__: null, ...jwk };
424
+ }
425
+ function normalizeJwk(jwk) {
426
+ const normalized = snapshotJwk(jwk);
427
+ if (normalized.ext !== void 0 && typeof normalized.ext != "boolean")
428
+ throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
429
+ if (normalized.key_ops !== void 0) {
430
+ const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
431
+ if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length)
432
+ throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
433
+ normalized.key_ops = keyOps;
434
+ }
435
+ return normalized;
436
+ }
437
+ async function jwkToKey(entry, jwk, extractable) {
438
+ if (!entry.kty.includes(jwk.kty))
439
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
440
+ const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: extractable ?? jwk.ext };
441
+ return keyData.kty !== "AKP" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey("jwk", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
442
+ }
443
+ async function rawKey(key, expected, usage, extractable = false) {
444
+ return key instanceof Uint8Array && (key = await crypto.subtle.importKey("raw", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;
445
+ }
446
+
447
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/key_descriptor.js
448
+ function table(entries) {
449
+ const out = { __proto__: null };
450
+ for (const alg in entries)
451
+ out[alg] = { ...entries[alg], alg };
452
+ return out;
453
+ }
454
+
455
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jws_algorithms.js
456
+ var sig = [["verify"], ["sign"]];
457
+ function hmac(bits) {
458
+ const subtle = { name: "HMAC", hash: `SHA-${bits}` };
459
+ return { kty: ["oct"], secret: true, subtle, signing: subtle, usages: sig };
460
+ }
461
+ function rsa(bits, saltLength) {
462
+ const subtle = { name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5", hash: `SHA-${bits}` };
463
+ return {
464
+ kty: ["RSA"],
465
+ subtle,
466
+ signing: saltLength ? { ...subtle, saltLength } : subtle,
467
+ usages: sig,
468
+ minRsaBits: 2048
469
+ };
470
+ }
471
+ function ecdsa(crv, bits) {
472
+ return {
473
+ kty: ["EC"],
474
+ crv,
475
+ subtle: { name: "ECDSA", namedCurve: crv },
476
+ signing: { name: "ECDSA", hash: `SHA-${bits}` },
477
+ usages: sig
478
+ };
479
+ }
480
+ function eddsa() {
481
+ const subtle = { name: "Ed25519" };
482
+ return {
483
+ kty: ["OKP"],
484
+ crv: "Ed25519",
485
+ subtle,
486
+ signing: subtle,
487
+ usages: sig
488
+ };
489
+ }
490
+ function mldsa(bits) {
491
+ const subtle = { name: `ML-DSA-${bits}` };
492
+ return {
493
+ kty: ["AKP"],
494
+ subtle,
495
+ signing: subtle,
496
+ usages: sig
497
+ };
498
+ }
499
+ var JWS = table({
500
+ HS256: hmac(256),
501
+ HS384: hmac(384),
502
+ HS512: hmac(512),
503
+ RS256: rsa(256),
504
+ RS384: rsa(384),
505
+ RS512: rsa(512),
506
+ PS256: rsa(256, 32),
507
+ PS384: rsa(384, 48),
508
+ PS512: rsa(512, 64),
509
+ ES256: ecdsa("P-256", 256),
510
+ ES384: ecdsa("P-384", 384),
511
+ ES512: ecdsa("P-521", 512),
512
+ EdDSA: eddsa(),
513
+ Ed25519: eddsa(),
514
+ "ML-DSA-44": mldsa(44),
515
+ "ML-DSA-65": mldsa(65),
516
+ "ML-DSA-87": mldsa(87)
517
+ });
518
+ function jwsAlgorithm(alg) {
519
+ const entry = typeof alg == "string" ? JWS[alg] : void 0;
520
+ if (!entry)
521
+ throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
522
+ return entry;
523
+ }
524
+
525
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jws_verify.js
526
+ function prepareVerify(options) {
527
+ return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
528
+ }
529
+ function parseProtectedHeader(encodedProtected) {
530
+ return encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid");
531
+ }
532
+ function encodeCompactUnencodedPayload(payload) {
533
+ try {
534
+ return encode(payload);
535
+ } catch {
536
+ throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters");
537
+ }
538
+ }
539
+ async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
540
+ const { protected: encodedProtected, header, payload: inputPayload } = jws, parsedProt = parsedProtected ?? parseProtectedHeader(encodedProtected);
541
+ if (!isDisjoint(parsedProt, header))
542
+ throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
543
+ const joseHeader = { ...parsedProt, ...header }, b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader)), { alg } = joseHeader;
544
+ if (typeof alg != "string" || !alg)
545
+ throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
546
+ if (shared[0] && !shared[0].has(alg))
547
+ throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
548
+ if (b64) {
549
+ if (typeof inputPayload != "string")
550
+ throw new JWSInvalid("JWS Payload must be a string");
551
+ } else if (typeof inputPayload != "string" && !(inputPayload instanceof Uint8Array))
552
+ throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
553
+ const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
554
+ let resolvedKey = false;
555
+ typeof key == "function" && (key = await key(parsedProt, jws), resolvedKey = true);
556
+ const entry = jwsAlgorithm(alg), data = concat(encodedProtected !== void 0 ? encode(encodedProtected) : new Uint8Array(), encode("."), typeof signingPayload == "string" ? shared[2] ??= encodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), k = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(k, entry.subtle, "verify");
557
+ entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
558
+ let verified = false;
559
+ try {
560
+ verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
561
+ } catch {
562
+ }
563
+ if (!verified)
564
+ throw new JWSSignatureVerificationFailed();
565
+ const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
566
+ return encodedProtected !== void 0 && (result.protectedHeader = parsedProt), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: k }, b64] : [result, b64];
567
+ }
568
+ async function verifyCompact(jws, shared, key) {
569
+ if (jws instanceof Uint8Array && (jws = decoder.decode(jws)), typeof jws != "string")
570
+ throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
571
+ const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
572
+ if (length !== 3)
573
+ throw new JWSInvalid("Invalid Compact JWS");
574
+ return verifySignature({ payload, protected: protectedHeader, signature }, shared, key, encodeCompactUnencodedPayload);
575
+ }
576
+
577
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jwt_claims_set.js
578
+ var epoch = (date) => Math.floor(date.getTime() / 1e3);
579
+ var multipliers = {
580
+ s: 1,
581
+ m: 60,
582
+ h: 3600,
583
+ d: 86400,
584
+ w: 604800,
585
+ y: 31557600
586
+ };
587
+ var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
588
+ var checkFailed = "check_failed";
589
+ function invalidDuration() {
590
+ throw new TypeError("Invalid time period format");
591
+ }
592
+ function secs(str) {
593
+ typeof str != "string" && invalidDuration();
594
+ const matched = REGEX.exec(str);
595
+ (!matched || matched[4] && matched[1]) && invalidDuration();
596
+ const value = parseFloat(matched[2]), numericDate2 = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
597
+ return Number.isFinite(numericDate2) || invalidDuration(), matched[1] === "-" || matched[4] === "ago" ? -numericDate2 : numericDate2;
598
+ }
599
+ function validateInput(label, input) {
600
+ if (!Number.isFinite(input))
601
+ throw new TypeError(`Invalid ${label} input`);
602
+ return input;
603
+ }
604
+ var normalizeTyp = (value) => {
605
+ const normalized = value.toLowerCase();
606
+ return value.includes("/") ? normalized : `application/${normalized}`;
607
+ };
608
+ var checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : false;
609
+ function validateNumericDate(payload, claim, required = false) {
610
+ const value = payload[claim];
611
+ if (!(value === void 0 && !required)) {
612
+ if (typeof value != "number")
613
+ throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, payload, claim, "invalid");
614
+ return value;
615
+ }
616
+ }
617
+ function unexpectedClaim(payload, claim) {
618
+ throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, payload, claim, checkFailed);
619
+ }
620
+ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
621
+ let payload;
622
+ try {
623
+ payload = JSON.parse(strictDecoder.decode(encodedPayload));
624
+ } catch {
625
+ }
626
+ if (!isObject(payload))
627
+ throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
628
+ const { typ } = options;
629
+ if (typ !== void 0 && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))
630
+ throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", checkFailed);
631
+ const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
632
+ maxTokenAge !== void 0 && presenceCheck.push("iat"), audience !== void 0 && presenceCheck.push("aud"), subject !== void 0 && presenceCheck.push("sub"), issuer !== void 0 && presenceCheck.push("iss");
633
+ for (const claim of new Set(presenceCheck.reverse()))
634
+ if (!Object.hasOwn(payload, claim))
635
+ throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
636
+ issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss) && unexpectedClaim(payload, "iss"), subject !== void 0 && payload.sub !== subject && unexpectedClaim(payload, "sub"), audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(payload, "aud");
637
+ const { clockTolerance } = options;
638
+ let tolerance = 0;
639
+ if (typeof clockTolerance == "string")
640
+ tolerance = secs(clockTolerance);
641
+ else if (clockTolerance !== void 0) {
642
+ if (typeof clockTolerance != "number")
643
+ throw new TypeError("Invalid clockTolerance option type");
644
+ tolerance = clockTolerance;
645
+ }
646
+ validateInput("clockTolerance option", tolerance);
647
+ const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(payload, "iat", maxTokenAge !== void 0), nbf = validateNumericDate(payload, "nbf");
648
+ if (nbf !== void 0 && nbf > now + tolerance)
649
+ throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", checkFailed);
650
+ const exp = validateNumericDate(payload, "exp");
651
+ if (exp !== void 0 && exp <= now - tolerance)
652
+ throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", checkFailed);
653
+ if (maxTokenAge !== void 0) {
654
+ const age = now - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
655
+ if (age - tolerance > max)
656
+ throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", checkFailed);
657
+ if (age < -tolerance)
658
+ throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", checkFailed);
659
+ }
660
+ return payload;
661
+ }
662
+
663
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/jwt/verify.js
664
+ async function jwtVerify(jwt, key, options) {
665
+ const [verified, b64] = await verifyCompact(jwt, prepareVerify(options), key);
666
+ if (!b64)
667
+ throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
668
+ const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
669
+ return { ...verified, payload };
670
+ }
671
+
672
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/jwks/local.js
673
+ function isUsableJWK(jwk, entry, alg, kid) {
674
+ const { kty, key_ops: keyOps, ext, kid: jwkKid, alg: jwkAlg, use, crv } = jwk;
675
+ return (ext === void 0 || typeof ext == "boolean") && (keyOps === void 0 || Array.isArray(keyOps) && keyOps.every((operation, index) => typeof operation == "string" && keyOps.indexOf(operation) === index) && keyOps.includes("verify")) && entry.kty.includes(kty) && (kid === void 0 || typeof kid == "string" && kid === jwkKid) && (jwkAlg === void 0 ? kty !== "AKP" : alg === jwkAlg) && (use === void 0 || use === "sig") && (!entry.crv || crv === entry.crv);
676
+ }
677
+ async function importWithAlgCache(cache2, jwk, entry) {
678
+ const cached = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk), { alg } = entry;
679
+ if (cached[alg] === void 0) {
680
+ const pending = jwkToKey(entry, jwk, true).then((key) => {
681
+ if (key.type !== "public")
682
+ throw new JWKSInvalid("JSON Web Key Set members must be public keys");
683
+ return cached[alg] = key, key;
684
+ }).catch((error) => {
685
+ throw cached[alg] === pending && delete cached[alg], error;
686
+ });
687
+ cached[alg] = pending;
688
+ }
689
+ return cached[alg];
690
+ }
691
+ function createLocalJWKSet(jwks) {
692
+ let snapshot;
693
+ try {
694
+ snapshot = structuredClone(jwks);
695
+ } catch {
696
+ }
697
+ if (!isJwkSet(snapshot))
698
+ throw new JWKSInvalid("JSON Web Key Set malformed");
699
+ const metadata = snapshot.keys.map((jwk) => {
700
+ const normalized = snapshotJwk(jwk);
701
+ return Array.isArray(normalized.key_ops) && (normalized.key_ops = [...normalized.key_ops]), normalized;
702
+ }), cached = /* @__PURE__ */ new WeakMap();
703
+ return Object.defineProperty(async (protectedHeader, token) => {
704
+ const { alg, kid } = { ...protectedHeader, ...token?.header }, entry = typeof alg == "string" ? JWS[alg] : void 0;
705
+ if (!entry || entry.secret)
706
+ throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
707
+ const candidates = snapshot.keys.filter((_, index) => isUsableJWK(metadata[index], entry, alg, kid)), { 0: jwk, length } = candidates;
708
+ if (!length)
709
+ throw new JWKSNoMatchingKey();
710
+ if (length !== 1) {
711
+ const error = new JWKSMultipleMatchingKeys();
712
+ throw error[Symbol.asyncIterator] = async function* () {
713
+ for (const jwk2 of candidates)
714
+ try {
715
+ yield await importWithAlgCache(cached, jwk2, entry);
716
+ } catch {
717
+ }
718
+ }, error;
719
+ }
720
+ return importWithAlgCache(cached, jwk, entry);
721
+ }, "jwks", {
722
+ value: () => structuredClone(snapshot)
723
+ });
724
+ }
725
+
726
+ // node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/jwks/remote.js
727
+ function isCloudflareWorkers() {
728
+ return typeof WebSocketPair < "u" || typeof navigator < "u" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime < "u" && EdgeRuntime === "vercel";
729
+ }
730
+ var USER_AGENT;
731
+ (typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT = "jose/v6.2.12");
732
+ var customFetch = /* @__PURE__ */ Symbol();
733
+ async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
734
+ const response = await fetchImpl(url, {
735
+ method: "GET",
736
+ signal,
737
+ redirect: "manual",
738
+ headers
739
+ }).catch((err) => {
740
+ throw err.name === "TimeoutError" ? new JWKSTimeout() : err;
741
+ });
742
+ if (response.status !== 200)
743
+ throw new JOSEError("Expected 200 OK from the JSON Web Key Set HTTP response");
744
+ try {
745
+ return await response.json();
746
+ } catch {
747
+ throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON");
748
+ }
749
+ }
750
+ var jwksCache = /* @__PURE__ */ Symbol();
751
+ function isFreshFor(timestamp, duration) {
752
+ return Number.isFinite(timestamp) && Date.now() < timestamp + duration;
753
+ }
754
+ function validateDuration(value, fallback, option) {
755
+ if (Number.isNaN(value))
756
+ throw new TypeError(`"${option}" option must not be NaN`);
757
+ return typeof value == "number" ? value : fallback;
758
+ }
759
+ function createRemoteJWKSet(url, options) {
760
+ if (!(url instanceof URL))
761
+ throw new TypeError("url must be an instance of URL");
762
+ const href = new URL(url.href).href, opts = options ?? {}, timeoutOption = opts.timeoutDuration;
763
+ if (typeof timeoutOption == "number" && (!Number.isInteger(timeoutOption) || timeoutOption < 0))
764
+ throw new TypeError('"timeoutDuration" option must be a non-negative integer');
765
+ const timeoutDuration = typeof timeoutOption == "number" ? timeoutOption : 5e3, cooldownDuration = validateDuration(opts.cooldownDuration, 3e4, "cooldownDuration"), cacheMaxAge = validateDuration(opts.cacheMaxAge, 6e5, "cacheMaxAge"), headers = new Headers(opts.headers);
766
+ USER_AGENT && !headers.has("User-Agent") && headers.set("User-Agent", USER_AGENT), headers.has("accept") || headers.set("accept", "application/json, application/jwk-set+json");
767
+ const fetchImpl = opts[customFetch], cache2 = opts[jwksCache];
768
+ let jwksTimestamp, pendingFetch, reloadSequence = 0, appliedSequence = 0, local;
769
+ if (cache2 && typeof cache2 == "object") {
770
+ const { uat, jwks } = cache2;
771
+ isFreshFor(uat, cacheMaxAge) && isJwkSet(jwks) && (jwksTimestamp = uat, local = createLocalJWKSet(jwks));
772
+ }
773
+ const reload = async () => {
774
+ if (pendingFetch && isCloudflareWorkers() && (pendingFetch = void 0), !pendingFetch) {
775
+ const sequence = ++reloadSequence, current = pendingFetch = fetchJwks(href, headers, AbortSignal.timeout(timeoutDuration), fetchImpl).then((json) => {
776
+ const next = createLocalJWKSet(json);
777
+ if (sequence <= appliedSequence)
778
+ return;
779
+ local = next;
780
+ const updatedAt = Date.now();
781
+ cache2 && (cache2.uat = updatedAt, cache2.jwks = json), jwksTimestamp = updatedAt, appliedSequence = sequence;
782
+ }).finally(() => {
783
+ pendingFetch === current && (pendingFetch = void 0);
784
+ });
785
+ }
786
+ await pendingFetch;
787
+ };
788
+ return Object.defineProperties(async (protectedHeader, token) => {
789
+ (!local || !isFreshFor(jwksTimestamp, cacheMaxAge)) && await reload();
790
+ try {
791
+ return await local(protectedHeader, token);
792
+ } catch (err) {
793
+ if (err instanceof JWKSNoMatchingKey && !isFreshFor(jwksTimestamp, cooldownDuration))
794
+ return await reload(), local(protectedHeader, token);
795
+ throw err;
796
+ }
797
+ }, {
798
+ coolingDown: {
799
+ get: () => isFreshFor(jwksTimestamp, cooldownDuration),
800
+ enumerable: true
801
+ },
802
+ fresh: {
803
+ get: () => isFreshFor(jwksTimestamp, cacheMaxAge),
804
+ enumerable: true
805
+ },
806
+ reload: {
807
+ value: reload,
808
+ enumerable: true
809
+ },
810
+ reloading: {
811
+ get: () => !!pendingFetch,
812
+ enumerable: true
813
+ },
814
+ jwks: {
815
+ value: () => local?.jwks(),
816
+ enumerable: true
817
+ }
818
+ });
819
+ }
820
+
821
+ // packages/cli/src/tui/chatgpt-plan-auth.ts
822
+ var SIWC_ISSUER = "https://auth.openai.com";
823
+ var SIWC_RESOURCE = "https://api.openai.com/v1";
824
+ var SIWC_SCOPES = ["openid", "profile", "email", "offline_access", "resource.invoke", "chatgpt.tokens.use.direct"];
825
+ var PATH = "/auth/callback";
826
+ var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
827
+ function credential(value) {
828
+ if (typeof value !== "string" || !value || value.length > 65536 || /[^\x21-\x7e]/.test(value)) throw new Error("The provider returned invalid authentication data.");
829
+ return value;
830
+ }
831
+ async function readSiwcJson(url, init, transport = {}) {
832
+ const signal = init.signal ? AbortSignal.any([init.signal, AbortSignal.timeout(3e4)]) : AbortSignal.timeout(3e4);
833
+ let response;
834
+ try {
835
+ response = await (transport.fetch ?? fetch)(url, { ...init, signal, redirect: "error" });
836
+ } catch {
837
+ throw new Error("ChatGPT sign-in could not reach its authentication service. Retry the connection.");
838
+ }
839
+ if (!response.ok) throw new Error(response.status === 400 || response.status === 401 ? "ChatGPT authentication was rejected. Sign in again." : `ChatGPT authentication is unavailable (HTTP ${response.status}).`);
840
+ const reader = response.body?.getReader();
841
+ if (!reader) throw new Error("ChatGPT returned an empty authentication response.");
842
+ let bytes = 0, raw = "";
843
+ const decoder2 = new TextDecoder("utf-8", { fatal: true });
844
+ try {
845
+ for (; ; ) {
846
+ const chunk = await reader.read();
847
+ if (chunk.done) break;
848
+ bytes += chunk.value.byteLength;
849
+ if (bytes > 1048576) throw new Error("ChatGPT authentication response exceeded its limit.");
850
+ raw += decoder2.decode(chunk.value, { stream: true });
851
+ }
852
+ raw += decoder2.decode();
853
+ try {
854
+ return JSON.parse(raw);
855
+ } catch {
856
+ throw new Error("ChatGPT returned an invalid authentication response.");
857
+ }
858
+ } finally {
859
+ await reader.cancel().catch(() => void 0);
860
+ reader.releaseLock();
861
+ }
862
+ }
863
+ function trustedEndpoint(value) {
864
+ if (typeof value !== "string") throw new Error("ChatGPT authentication configuration is incomplete.");
865
+ const url = new URL(value);
866
+ if (url.origin !== SIWC_ISSUER || url.username || url.password || url.hash || url.search) throw new Error("ChatGPT authentication configuration contains an untrusted endpoint.");
867
+ return url.href;
868
+ }
869
+ async function siwcMetadata(transport, signal) {
870
+ const data = object(await readSiwcJson(`${SIWC_ISSUER}/.well-known/openid-configuration`, { signal }, transport));
871
+ if (data.issuer !== SIWC_ISSUER) throw new Error("ChatGPT authentication issuer did not match.");
872
+ return { token: trustedEndpoint(data.token_endpoint), jwks: trustedEndpoint(data.jwks_uri), revoke: trustedEndpoint(data.revocation_endpoint) };
873
+ }
874
+ async function validateSiwcTokens(value, clientId, metadata, transport, signal, expected) {
875
+ const data = object(value), previous = expected?.previous;
876
+ const idToken = data.id_token === void 0 && previous ? previous.idToken : credential(data.id_token);
877
+ const now = transport.now?.() ?? Date.now();
878
+ let identity;
879
+ if (data.id_token === void 0 && previous && previous.clientId === clientId && previous.issuer === SIWC_ISSUER) {
880
+ identity = { sub: previous.subject, email: previous.email, iat: Math.floor(now / 1e3) };
881
+ } else {
882
+ const keys = object(await readSiwcJson(metadata.jwks, { signal }, transport));
883
+ if (!Array.isArray(keys.keys)) throw new Error("ChatGPT returned invalid signing keys.");
884
+ try {
885
+ identity = (await jwtVerify(idToken, createLocalJWKSet(keys), { issuer: SIWC_ISSUER, audience: clientId, algorithms: ["RS256", "ES256"], currentDate: new Date(now), requiredClaims: ["sub", "iat", "exp"] })).payload;
886
+ } catch {
887
+ throw new Error("ChatGPT identity verification failed. Sign in again.");
888
+ }
889
+ }
890
+ if (typeof identity.sub !== "string" || !identity.sub || typeof identity.iat !== "number" || identity.iat > now / 1e3 + 60 || expected?.nonce !== void 0 && identity.nonce !== expected.nonce || expected?.subject !== void 0 && identity.sub !== expected.subject || identity.azp !== void 0 && identity.azp !== clientId || Array.isArray(identity.aud) && identity.aud.length > 1 && identity.azp !== clientId) throw new Error("ChatGPT identity did not match this sign-in.");
891
+ const scopes = typeof data.scope === "string" ? [...new Set(data.scope.split(/\s+/).filter(Boolean))] : data.scope === void 0 ? expected?.scopes : void 0;
892
+ if (!scopes || !scopes.includes("openid")) throw new Error("ChatGPT did not return the granted identity permissions.");
893
+ const sharing = scopes.includes("chatgpt.tokens.use.direct");
894
+ const accessToken = data.access_token !== void 0 ? credential(data.access_token) : void 0;
895
+ const refreshToken = data.refresh_token !== void 0 ? credential(data.refresh_token) : previous?.refreshToken;
896
+ if (data.token_type !== "Bearer" || sharing && (!accessToken || !refreshToken || !scopes.includes("resource.invoke") || !scopes.includes("offline_access")) || typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in) || data.expires_in <= 0 || data.expires_in > 86400) throw new Error("ChatGPT did not return a usable token grant.");
897
+ const earliest = data.earliest_refresh_at;
898
+ const earliestRefreshAt = typeof earliest === "number" ? earliest * 1e3 : typeof earliest === "string" ? Date.parse(earliest) : void 0;
899
+ if (earliestRefreshAt !== void 0 && !Number.isFinite(earliestRefreshAt)) throw new Error("ChatGPT returned an invalid refresh schedule.");
900
+ const email = typeof identity.email === "string" && identity.email.length <= 320 && !/[\x00-\x1f\x7f]/.test(identity.email) ? identity.email : void 0;
901
+ return { clientId, subject: identity.sub, issuer: SIWC_ISSUER, ...email ? { email } : {}, scopes, idToken, ...accessToken ? { accessToken } : {}, ...refreshToken ? { refreshToken } : {}, expiresAt: now + data.expires_in * 1e3, ...earliestRefreshAt !== void 0 ? { earliestRefreshAt } : {}, status: "connected" };
902
+ }
903
+ async function refreshSiwcProfile(profile, transport = {}, signal, checkpoint) {
904
+ if (!profile.refreshToken || profile.status !== "connected") throw new Error("Sign in with ChatGPT again before continuing.");
905
+ const metadata = await siwcMetadata(transport, signal);
906
+ const value = await readSiwcJson(metadata.token, { method: "POST", signal, headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "refresh_token", client_id: profile.clientId, refresh_token: profile.refreshToken, resource: SIWC_RESOURCE }).toString() }, transport);
907
+ const body = object(value), receipt = {};
908
+ for (const key of ["access_token", "refresh_token", "id_token", "token_type", "expires_in", "scope", "earliest_refresh_at"]) {
909
+ const field = body[key];
910
+ if (field !== void 0) receipt[key] = typeof field === "string" && field.length <= 65536 || typeof field === "number" || typeof field === "boolean" || field === null ? field : null;
911
+ }
912
+ await checkpoint?.(receipt);
913
+ return { id: profile.id, ...await validateSiwcTokens(value, profile.clientId, metadata, transport, signal, { subject: profile.subject, scopes: profile.scopes, previous: profile }) };
914
+ }
915
+ async function loginSiwc(options) {
916
+ if (!/^urn:uuid:[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/.test(options.hostId)) throw new Error("ChatGPT sign-in requires this installation's stable host identity.");
917
+ const abort = new AbortController();
918
+ const signal = options.signal ? AbortSignal.any([options.signal, abort.signal, AbortSignal.timeout(3e5)]) : AbortSignal.any([abort.signal, AbortSignal.timeout(3e5)]);
919
+ const state = randomBytes(32).toString("base64url"), nonce = randomBytes(32).toString("base64url"), verifier = randomBytes(64).toString("base64url");
920
+ let resolveCallback, rejectCallback;
921
+ const callback = new Promise((resolve4, reject) => {
922
+ resolveCallback = resolve4;
923
+ rejectCallback = reject;
924
+ });
925
+ void callback.catch(() => void 0);
926
+ let consumed = false, redirect = "";
927
+ const server = createServer((req, res) => {
928
+ let url;
929
+ try {
930
+ if (!redirect) throw new Error();
931
+ url = new URL(req.url ?? "/", redirect);
932
+ } catch {
933
+ res.writeHead(400);
934
+ res.end("Invalid callback.");
935
+ return;
936
+ }
937
+ if (consumed || req.method !== "GET" || req.headers.host !== new URL(redirect).host || url.origin !== new URL(redirect).origin || url.pathname !== PATH || url.searchParams.getAll("state").length !== 1 || url.searchParams.get("state") !== state) {
938
+ res.writeHead(400, { "Cache-Control": "no-store" });
939
+ res.end("This sign-in callback is not valid.");
940
+ return;
941
+ }
942
+ consumed = true;
943
+ res.writeHead(200, { "Cache-Control": "no-store", "Content-Type": "text/plain; charset=utf-8", "Content-Security-Policy": "default-src 'none'", "Referrer-Policy": "no-referrer" });
944
+ res.end("Return to 0 to finish connecting ChatGPT.");
945
+ resolveCallback(url.searchParams);
946
+ });
947
+ const stopped = () => rejectCallback(new Error("ChatGPT sign-in was cancelled or timed out."));
948
+ signal.addEventListener("abort", stopped, { once: true });
949
+ try {
950
+ signal.throwIfAborted();
951
+ await new Promise((resolve4, reject) => {
952
+ server.once("error", () => reject(new Error("The local sign-in callback could not start.")));
953
+ server.listen(0, "127.0.0.1", resolve4);
954
+ });
955
+ const address = server.address();
956
+ if (!address || typeof address === "string") throw new Error("The local sign-in callback could not start.");
957
+ redirect = `http://127.0.0.1:${address.port}${PATH}`;
958
+ const url = new URL(`${SIWC_ISSUER}/api/accounts/authorize`);
959
+ const previous = options.previous;
960
+ const parameters = { client_id: previous?.clientId ?? "dynamic_agent_client", ...previous ? {} : { agent_name_hint: "0" }, ext_agent_host_id: options.hostId, response_type: "code", redirect_uri: redirect, scope: SIWC_SCOPES.join(" "), resource: SIWC_RESOURCE, state, nonce, code_challenge_method: "S256", code_challenge: createHash("sha256").update(verifier).digest("base64url") };
961
+ for (const [key, value2] of Object.entries(parameters)) url.searchParams.set(key, value2);
962
+ void Promise.resolve().then(() => options.onAuthorize(url.href)).catch(() => rejectCallback(new Error("The browser sign-in could not be opened.")));
963
+ const params = await callback;
964
+ signal.throwIfAborted();
965
+ if (params.has("error")) throw new Error("ChatGPT sign-in was not authorized. No account was changed.");
966
+ const clientId = params.has("client_id") ? credential(params.get("client_id")) : previous?.clientId;
967
+ if (!clientId || clientId === "dynamic_agent_client" || params.getAll("client_id").length > 1 || previous && clientId !== previous.clientId || params.getAll("code").length !== 1) throw new Error("ChatGPT registration did not match this sign-in.");
968
+ const code = credential(params.get("code")), metadata = await siwcMetadata(options, signal);
969
+ const value = await readSiwcJson(metadata.token, { method: "POST", signal, headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", client_id: clientId, code, code_verifier: verifier, redirect_uri: redirect, resource: SIWC_RESOURCE }).toString() }, options);
970
+ return await validateSiwcTokens(value, clientId, metadata, options, signal, { nonce, ...previous ? { subject: previous.subject } : {} });
971
+ } finally {
972
+ abort.abort();
973
+ signal.removeEventListener("abort", stopped);
974
+ server.closeAllConnections();
975
+ await new Promise((resolve4) => {
976
+ if (!server.listening) resolve4();
977
+ else server.close(() => resolve4());
978
+ });
979
+ }
980
+ }
981
+
982
+ // packages/cli/src/tui/chatgpt-plan-store.ts
983
+ function paths(homeDir) {
984
+ const directory = join(homeStateDir(homeDir), "chatgpt-plan");
985
+ return { directory, file: join(directory, "accounts.json"), lock: join(directory, "write.lock") };
986
+ }
987
+ function checkPrivate(path, directory) {
988
+ const stat3 = lstatSync(path);
989
+ if (stat3.isSymbolicLink() || (directory ? !stat3.isDirectory() : !stat3.isFile()) || process.platform !== "win32" && ((stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())) throw new Error("ChatGPT connection storage must be private and owned by this user.");
990
+ }
991
+ function read(homeDir) {
992
+ const { directory, file } = paths(homeDir);
993
+ if (!existsSync(directory)) return void 0;
994
+ checkPrivate(directory, true);
995
+ if (!existsSync(file)) return void 0;
996
+ checkPrivate(file, false);
997
+ if (lstatSync(file).size > 4194304) throw new Error("ChatGPT connection storage exceeded its limit.");
998
+ let data;
999
+ try {
1000
+ data = JSON.parse(readFileSync(file, "utf8"));
1001
+ } catch {
1002
+ throw new Error("ChatGPT connection storage is invalid.");
1003
+ }
1004
+ if (data.version !== 1 || !Number.isSafeInteger(data.revision) || data.revision < 0 || !/^urn:uuid:[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/.test(data.hostId) || !Array.isArray(data.profiles) || data.profiles.length > 100) throw new Error("ChatGPT connection storage is invalid.");
1005
+ const ids = /* @__PURE__ */ new Set();
1006
+ for (const p of data.profiles) {
1007
+ if (!p || typeof p.id !== "string" || ids.has(p.id) || typeof p.subject !== "string" || !p.subject || p.issuer !== SIWC_ISSUER || !["connected", "signed-out", "reauth-required"].includes(p.status) || !Array.isArray(p.scopes) || !p.scopes.every((scope) => typeof scope === "string") || typeof p.expiresAt !== "number" || !Number.isFinite(p.expiresAt) || typeof p.idToken !== "string") throw new Error("ChatGPT connection storage is invalid.");
1008
+ if (p.epoch !== void 0 && (!Number.isSafeInteger(p.epoch) || p.epoch < 0)) throw new Error("ChatGPT connection generation is invalid.");
1009
+ credential(p.clientId);
1010
+ if (p.clientId === "dynamic_agent_client") throw new Error("ChatGPT connection storage has no issued registration.");
1011
+ if (p.accessToken !== void 0) credential(p.accessToken);
1012
+ if (p.refreshToken !== void 0) credential(p.refreshToken);
1013
+ ids.add(p.id);
1014
+ }
1015
+ if (data.activeId !== void 0 && !ids.has(data.activeId)) throw new Error("ChatGPT connection selection is invalid.");
1016
+ return data;
1017
+ }
1018
+ function write(store, homeDir) {
1019
+ const { directory, file } = paths(homeDir);
1020
+ checkPrivate(directory, true);
1021
+ const disk = read(homeDir);
1022
+ if ((disk?.revision ?? 0) !== store.revision) throw new Error("ChatGPT connection storage changed. Retry the operation.");
1023
+ const next = { ...store, revision: store.revision + 1 }, temp = join(directory, `${randomUUID()}.tmp`);
1024
+ const bytes = JSON.stringify(next);
1025
+ if (Buffer.byteLength(bytes) > 4194304) throw new Error("ChatGPT connection storage exceeded its limit.");
1026
+ const fd = openSync(temp, "wx", 384);
1027
+ try {
1028
+ writeFileSync(fd, bytes);
1029
+ fsyncSync(fd);
1030
+ } finally {
1031
+ closeSync(fd);
1032
+ }
1033
+ try {
1034
+ renameSync(temp, file);
1035
+ store.revision = next.revision;
1036
+ if (process.platform !== "win32") {
1037
+ const parent = openSync(directory, "r");
1038
+ try {
1039
+ fsyncSync(parent);
1040
+ } finally {
1041
+ closeSync(parent);
1042
+ }
1043
+ }
1044
+ } finally {
1045
+ if (existsSync(temp)) unlinkSync(temp);
1046
+ }
1047
+ }
1048
+ async function locked(homeDir, operation) {
1049
+ const { directory, lock } = paths(homeDir);
1050
+ mkdirSync(directory, { recursive: true, mode: 448 });
1051
+ checkPrivate(directory, true);
1052
+ let fd;
1053
+ const deadline = Date.now() + 5e3;
1054
+ for (; ; ) {
1055
+ try {
1056
+ fd = openSync(lock, "wx", 384);
1057
+ writeFileSync(fd, String(process.pid));
1058
+ break;
1059
+ } catch (error) {
1060
+ if (error.code !== "EEXIST" || Date.now() >= deadline) throw new Error("ChatGPT connection storage is busy. Close other connection operations and retry; an interrupted operation may require removing its stale lock.");
1061
+ await new Promise((resolve4) => setTimeout(resolve4, 25));
1062
+ }
1063
+ }
1064
+ try {
1065
+ return await operation(read(homeDir) ?? { version: 1, revision: 0, hostId: `urn:uuid:${randomUUID()}`, profiles: [] });
1066
+ } finally {
1067
+ closeSync(fd);
1068
+ unlinkSync(lock);
1069
+ }
1070
+ }
1071
+ function listChatGptPlanProfiles(homeDir) {
1072
+ const store = read(homeDir);
1073
+ return store?.profiles.map((p, index) => ({ id: p.id, label: `${p.email ?? "ChatGPT account"} \xB7 Connection ${index + 1}`, active: store.activeId === p.id, status: p.status, sharing: p.status === "connected" && p.scopes.includes("chatgpt.tokens.use.direct") && p.scopes.includes("resource.invoke") })) ?? [];
1074
+ }
1075
+ async function signInChatGptPlan(options) {
1076
+ const prepared = await locked(options.homeDir, async (store) => {
1077
+ const previous = options.profileId ? store.profiles.find((p) => p.id === options.profileId) : void 0;
1078
+ if (options.profileId && !previous) throw new Error("The selected ChatGPT connection no longer exists.");
1079
+ if (!previous && store.profiles.length >= 100) throw new Error("This host already has 100 ChatGPT registrations. Reconnect an existing connection.");
1080
+ write(store, options.homeDir);
1081
+ return { hostId: store.hostId, previous };
1082
+ });
1083
+ const result = await loginSiwc({ ...options, ...prepared });
1084
+ options.signal?.throwIfAborted();
1085
+ await locked(options.homeDir, async (store) => {
1086
+ options.signal?.throwIfAborted();
1087
+ const existing = options.profileId ? store.profiles.find((p) => p.id === options.profileId) : void 0;
1088
+ if (options.profileId && (!existing || existing.clientId !== result.clientId || existing.subject !== result.subject || (existing.epoch ?? 0) !== (prepared.previous?.epoch ?? 0))) throw new Error("The selected ChatGPT registration changed during sign-in.");
1089
+ const profile = { id: existing?.id ?? randomUUID(), ...result, epoch: (existing?.epoch ?? 0) + 1 };
1090
+ store.profiles = [...store.profiles.filter((p) => p.id !== profile.id), profile];
1091
+ store.activeId = profile.id;
1092
+ write(store, options.homeDir);
1093
+ });
1094
+ }
1095
+ async function selectChatGptPlanProfile(profileId, homeDir) {
1096
+ await locked(homeDir, async (store) => {
1097
+ if (!store.profiles.some((p) => p.id === profileId && p.status === "connected")) throw new Error("Sign in to this ChatGPT connection before selecting it.");
1098
+ store.activeId = profileId;
1099
+ write(store, homeDir);
1100
+ });
1101
+ }
1102
+ function getSiwcConnection(homeDir, profileId, transport = {}) {
1103
+ const current = read(homeDir), selected = profileId ?? current?.activeId, profile = current?.profiles.find((p) => p.id === selected);
1104
+ if (!current || !profile || profile.status !== "connected") throw new Error("Connect your ChatGPT plan in Connections before choosing this provider.");
1105
+ const binding = { accountId: profile.subject, clientId: profile.clientId, hostId: current.hostId };
1106
+ return { ...binding, resolveCredentials: async (signal) => {
1107
+ signal?.throwIfAborted();
1108
+ const result = await locked(homeDir, async (store) => {
1109
+ signal?.throwIfAborted();
1110
+ let p = store.profiles.find((p2) => p2.id === selected);
1111
+ if (!p || p.status !== "connected" || p.subject !== binding.accountId || p.clientId !== binding.clientId || store.hostId !== binding.hostId) throw new Error("This ChatGPT registration is no longer available. Reconnect it.");
1112
+ if (p.pendingRotation !== void 0) {
1113
+ const next = await validateSiwcTokens(p.pendingRotation, p.clientId, await siwcMetadata(transport), transport, void 0, { subject: p.subject, scopes: p.scopes, previous: p });
1114
+ p = { id: p.id, ...next, epoch: p.epoch };
1115
+ store.profiles = store.profiles.map((row) => row.id === p.id ? p : row);
1116
+ write(store, homeDir);
1117
+ }
1118
+ if (!p.scopes.includes("chatgpt.tokens.use.direct") || !p.scopes.includes("resource.invoke")) throw new Error("ChatGPT plan usage is not enabled for this connection. Sign in and grant plan usage, or use an API key.");
1119
+ signal?.throwIfAborted();
1120
+ const now = transport.now?.() ?? Date.now();
1121
+ if (p.expiresAt <= now + 6e4 && (p.earliestRefreshAt === void 0 || p.earliestRefreshAt <= now)) {
1122
+ if (Buffer.byteLength(JSON.stringify(store)) + 1048576 > 4194304) throw new Error("ChatGPT connection storage is full. Sign out of unused connections before refreshing.");
1123
+ const next = await refreshSiwcProfile(p, transport, void 0, async (value) => {
1124
+ p.pendingRotation = value;
1125
+ write(store, homeDir);
1126
+ });
1127
+ p = { ...next, epoch: p.epoch };
1128
+ store.profiles = store.profiles.map((row) => row.id === p.id ? p : row);
1129
+ write(store, homeDir);
1130
+ }
1131
+ if (p.expiresAt <= now || !p.accessToken || !p.scopes.includes("chatgpt.tokens.use.direct") || !p.scopes.includes("resource.invoke")) throw new Error("ChatGPT plan usage is not enabled for this connection. Sign in and grant plan usage, or use an API key.");
1132
+ return { accessToken: p.accessToken, scopes: [...p.scopes] };
1133
+ });
1134
+ signal?.throwIfAborted();
1135
+ return result;
1136
+ } };
1137
+ }
1138
+ async function signOutChatGptPlan(profileId, homeDir, transport = {}) {
1139
+ return locked(homeDir, async (store) => {
1140
+ const p = store.profiles.find((row) => row.id === profileId);
1141
+ if (!p) throw new Error("ChatGPT connection not found.");
1142
+ const pending = p.pendingRotation && typeof p.pendingRotation === "object" ? p.pendingRotation : void 0;
1143
+ let refreshToken = p.refreshToken, unknownRotation = false;
1144
+ if (pending?.refresh_token !== void 0) {
1145
+ try {
1146
+ refreshToken = credential(pending.refresh_token);
1147
+ } catch {
1148
+ unknownRotation = true;
1149
+ }
1150
+ }
1151
+ let revoked = !refreshToken && !unknownRotation;
1152
+ if (refreshToken) {
1153
+ try {
1154
+ const metadata2 = await siwcMetadata(transport);
1155
+ const response = await (transport.fetch ?? fetch)(metadata2.revoke, { method: "POST", redirect: "error", signal: AbortSignal.timeout(15e3), headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ token: refreshToken, token_type_hint: "refresh_token", client_id: p.clientId }).toString() });
1156
+ revoked = response.ok && !unknownRotation;
1157
+ } catch {
1158
+ }
1159
+ }
1160
+ const { accessToken: _access, refreshToken: _refresh, pendingRotation: _pending, ...metadata } = p;
1161
+ store.profiles = store.profiles.map((row) => row.id === p.id ? { ...metadata, epoch: (p.epoch ?? 0) + 1, idToken: "", scopes: [], expiresAt: 0, status: "signed-out" } : row);
1162
+ write(store, homeDir);
1163
+ return { revoked };
1164
+ });
1165
+ }
1166
+
1167
+ // packages/cli/src/tui/model-preference.ts
1168
+ async function createSelectedRuntime(config, allowChatGptPlan = true) {
1169
+ if (config.provider !== "chatgpt-plan") return createConsoleRuntime(config);
1170
+ if (!allowChatGptPlan) throw new Error("Native ChatGPT plan sign-in is available only in a user-controlled local open-source runtime. Use an API key for hosted or shared workspaces.");
1171
+ const connection = config.siwcConnection ?? getSiwcConnection(config.env?.HOME);
1172
+ if (config.model) return createConsoleRuntime({ ...config, siwcConnection: connection });
1173
+ const probe = createConsoleRuntime({ ...config, model: "probe", siwcConnection: connection });
1174
+ const catalog = await probe.availableModelCatalog(AbortSignal.timeout(1e4));
1175
+ if (!catalog.length) throw new Error("This ChatGPT connection returned no models. Check plan sharing in ChatGPT Settings.");
1176
+ probe.reconfigure({ model: catalog[0].id });
1177
+ return probe;
1178
+ }
1179
+ async function createPreferredConsoleRuntime(config, options = {}) {
1180
+ const env = config.env ?? process.env;
1181
+ const envModel = env["ZERO_MODEL"]?.trim();
1182
+ const envProvider = env["ZERO_SELECTED_PROVIDER"]?.trim() || env["ZERO_PROVIDER"]?.trim() || env["ZERO_FORCE_PROVIDER"]?.trim();
1183
+ const inherited = options.inheritedConnectionIdentity !== void 0;
1184
+ const explicitChoice = !inherited && config.model !== void 0 || Boolean(envModel);
1185
+ if (inherited && (envModel || envProvider)) config = { ...config, model: void 0, provider: void 0 };
1186
+ if (config.provider === void 0 && envProvider) config = { ...config, provider: envProvider };
1187
+ let runtime;
1188
+ let retainedModel = false;
1189
+ if (inherited && !envModel && !envProvider) {
1190
+ runtime = await createSelectedRuntime({ ...config, model: void 0 }, options.allowChatGptPlan);
1191
+ if (runtime.connectionIdentity() === options.inheritedConnectionIdentity) {
1192
+ runtime.reconfigure({ model: config.model });
1193
+ retainedModel = config.model !== void 0;
1194
+ }
1195
+ }
1196
+ if (!explicitChoice && !retainedModel) {
1197
+ const saved = getSettings().modelPreference;
1198
+ if (saved && (config.provider === void 0 || config.provider === saved.providerId)) {
1199
+ try {
1200
+ const candidate = await createSelectedRuntime({ ...config, model: saved.model, provider: saved.providerId }, options.allowChatGptPlan);
1201
+ if (candidate.connectionIdentity() === saved.connectionIdentity) {
1202
+ runtime = candidate;
1203
+ retainedModel = true;
1204
+ }
1205
+ } catch {
1206
+ }
1207
+ }
1208
+ }
1209
+ runtime ??= await createSelectedRuntime(config, options.allowChatGptPlan);
1210
+ if (!explicitChoice && runtime.getConfigurationDiagnostics().provider === "chatgpt-codex") {
1211
+ let catalog;
1212
+ try {
1213
+ catalog = await runtime.codexModelCatalog(AbortSignal.timeout(1e4));
1214
+ } catch (error) {
1215
+ options.onDiscoveryError?.(error);
1216
+ if (error instanceof CodexCatalogRefreshError) catalog = error.cachedModels;
1217
+ else if (!retainedModel) throw error;
1218
+ }
1219
+ if (catalog) {
1220
+ if (!catalog.length) throw new Error("This ChatGPT subscription returned no available models.");
1221
+ const currentModel = runtime.resolvedModel();
1222
+ if (!retainedModel || !catalog.some((model) => model.id === currentModel)) {
1223
+ runtime.reconfigure({ model: catalog[0].id });
1224
+ }
1225
+ }
1226
+ }
1227
+ return { runtime, explicitChoice };
1228
+ }
1229
+ function saveAppliedModelPreference(runtime) {
1230
+ const connectionIdentity = runtime.connectionIdentity();
1231
+ if (!connectionIdentity) return false;
1232
+ const preference = {
1233
+ providerId: runtime.getConfigurationDiagnostics().provider,
1234
+ model: runtime.resolvedModel(),
1235
+ connectionIdentity
1236
+ };
1237
+ return updateSetting("modelPreference", preference, { scope: "global" });
1238
+ }
1239
+
1240
+ // packages/cli/src/tui/model-catalog-sync.ts
1241
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
1242
+ import { dirname, join as join2 } from "node:path";
1243
+
1244
+ // packages/cli/src/tui/model-catalog.offline.ts
1245
+ var OFFLINE_MODEL_CATALOG = [
1246
+ // Anthropic
1247
+ { id: "claude-fable-5-1", provider: "anthropic", contextTokens: 1e6, input: 10, output: 50 },
1248
+ { id: "claude-opus-5", provider: "anthropic", contextTokens: 1e6, input: 5, output: 25 },
1249
+ { id: "claude-sonnet-5", provider: "anthropic", contextTokens: 1e6, input: 2, output: 10 },
1250
+ { id: "claude-opus-4-7", provider: "anthropic", contextTokens: 2e5, input: 5, output: 25 },
1251
+ { id: "claude-sonnet-4-6", provider: "anthropic", contextTokens: 1e6, input: 3, output: 15 },
1252
+ { id: "claude-haiku-4-5", provider: "anthropic", contextTokens: 2e5, input: 0.8, output: 4 },
1253
+ // OpenAI
1254
+ // Astra standard short-context rates; >272K input has a separate price tier.
1255
+ { id: "gpt-6-astra", provider: "openai", contextTokens: 105e4, input: 10, output: 50 },
1256
+ { id: "gpt-6.1-sol", provider: "openai", contextTokens: 105e4, input: 2, output: 10 },
1257
+ { id: "gpt-6-sol", provider: "openai", contextTokens: 105e4, input: 2, output: 10 },
1258
+ { id: "gpt-6-luna", provider: "openai", contextTokens: 105e4, input: 0.1, output: 0.5 },
1259
+ { id: "gpt-5.5", provider: "openai", contextTokens: 4e5, input: 5, output: 30 },
1260
+ { id: "gpt-5.6-sol", provider: "openai", contextTokens: 105e4 },
1261
+ { id: "gpt-5.6-terra", provider: "openai", contextTokens: 105e4 },
1262
+ { id: "gpt-5.6-luna", provider: "openai", contextTokens: 105e4 },
1263
+ // Google
1264
+ { id: "gemini-3.8-flash", provider: "google", contextTokens: 1048576, input: 0.75, output: 3.75 },
1265
+ { id: "gemini-3.5-flash-lite", provider: "google", contextTokens: 1048576, input: 0.3, output: 2.5 },
1266
+ { id: "gemini-3.1-pro-preview", provider: "google", contextTokens: 1048576, input: 2, output: 12 },
1267
+ // DeepSeek
1268
+ { id: "deepseek-flash", provider: "deepseek", contextTokens: 1e6, input: 0.3, output: 1.2 },
1269
+ // Meta (hosted)
1270
+ { id: "llama-4-maverick", provider: "meta", contextTokens: 1e6, input: 0.5, output: 0.77 },
1271
+ { id: "llama-4-scout", provider: "meta", contextTokens: 1e7, input: 0.2, output: 0.35 },
1272
+ // Mistral
1273
+ { id: "mistral-large", provider: "mistral", contextTokens: 128e3, input: 2, output: 6 },
1274
+ // Alibaba Qwen
1275
+ { id: "qwen3.8-max", provider: "qwen", contextTokens: 1e6, input: 2, output: 6 },
1276
+ { id: "qwen3.8-flash", provider: "qwen", contextTokens: 1e6, input: 0.15, output: 0.47 },
1277
+ { id: "qwen3.8-max-preview", provider: "qwen", contextTokens: 1e6 },
1278
+ { id: "qwen3.7-max", provider: "qwen", contextTokens: 1e6, input: 2.5, output: 7.5 },
1279
+ { id: "qwen3.7-plus", provider: "qwen", contextTokens: 1e6, input: 0.5, output: 3 },
1280
+ { id: "qwen3.6-plus", provider: "qwen", contextTokens: 1e6, input: 0.5, output: 3 },
1281
+ { id: "qwen3.6-flash", provider: "qwen", contextTokens: 1e6, input: 0.1875, output: 1.125 },
1282
+ // xAI
1283
+ { id: "grok-4.6", provider: "xai", contextTokens: 5e5, input: 2, output: 6 },
1284
+ // Moonshot
1285
+ { id: "k3", provider: "moonshot", contextTokens: 1048576, input: 3, output: 15 },
1286
+ // Z.AI
1287
+ { id: "glm-5.3", provider: "z-ai", contextTokens: 1e6, input: 1.4, output: 4.4 },
1288
+ { id: "glm-5.3-flash", provider: "z-ai", contextTokens: 1e6, input: 0.15, output: 0.5 }
1289
+ ];
1290
+
1291
+ // packages/cli/src/tui/model-catalog-sync.ts
1292
+ var MODELS_DEV_URL = "https://models.dev/api.json";
1293
+ var CATALOG_CACHE_FILENAME = "model-catalog.json";
1294
+ var CATALOG_TTL_MS = 24 * 60 * 60 * 1e3;
1295
+ var FETCH_TIMEOUT_MS = 8e3;
1296
+ var CATALOG_PROVIDER_IDS = {
1297
+ "alibaba-token-plan": "qwen",
1298
+ "kimi-code-plan-cn": "kimi",
1299
+ "github-copilot": "copilot",
1300
+ zai: "z-ai",
1301
+ "cline-pass": "cline"
1302
+ };
1303
+ var METERED_CATALOG_PROVIDERS = {
1304
+ anthropic: true,
1305
+ openai: true,
1306
+ deepseek: true,
1307
+ openrouter: true,
1308
+ xai: true,
1309
+ opencode: true,
1310
+ cline: true
1311
+ };
1312
+ function catalogId(value) {
1313
+ return typeof value === "string" && value.length > 0 && !/[\s\x00-\x1f\x7f-\x9f]/.test(value);
1314
+ }
1315
+ function finiteRate(value) {
1316
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
1317
+ }
1318
+ function contextTokens(value) {
1319
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
1320
+ }
1321
+ function normalizedModel(value) {
1322
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1323
+ const row = value;
1324
+ if (!catalogId(row.id) || !catalogId(row.provider) || row.provider === "chatgpt-codex") return null;
1325
+ const provider2 = Object.hasOwn(CATALOG_PROVIDER_IDS, row.provider) ? CATALOG_PROVIDER_IDS[row.provider] ?? row.provider : row.provider;
1326
+ const model = {
1327
+ id: row.provider === "cline-pass" && !row.id.startsWith("cline-pass/") ? `cline-pass/${row.id}` : row.id,
1328
+ provider: provider2,
1329
+ ...finiteRate(row.input) ? { input: row.input } : {},
1330
+ ...finiteRate(row.output) ? { output: row.output } : {},
1331
+ ...finiteRate(row.cachedInput) ? { cachedInput: row.cachedInput } : {},
1332
+ ...contextTokens(row.contextTokens) ? { contextTokens: row.contextTokens } : {}
1333
+ };
1334
+ if (!(provider2 === "cline" && model.id.startsWith("cline-pass/")) && Object.hasOwn(METERED_CATALOG_PROVIDERS, provider2) && model.input !== void 0 && model.output !== void 0) {
1335
+ const rates = { input: model.input, output: model.output, cachedInput: model.cachedInput };
1336
+ registerModelPricing(`${provider2}/${model.id}`, rates);
1337
+ if (provider2 === modelProvider(model.id)) registerModelPricing(model.id, rates);
1338
+ }
1339
+ return model;
1340
+ }
1341
+ function catalogCachePath(opts = {}) {
1342
+ return opts.cachePath ?? join2(homeStateDir(), CATALOG_CACHE_FILENAME);
1343
+ }
1344
+ function normalizeModelsDev(raw) {
1345
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return [];
1346
+ const out = [];
1347
+ for (const [providerId, providerVal] of Object.entries(raw)) {
1348
+ if (!catalogId(providerId) || typeof providerVal !== "object" || providerVal === null || Array.isArray(providerVal)) continue;
1349
+ const models = providerVal["models"];
1350
+ if (typeof models !== "object" || models === null || Array.isArray(models)) continue;
1351
+ for (const [modelId, modelVal] of Object.entries(models)) {
1352
+ if (!catalogId(modelId) || typeof modelVal !== "object" || modelVal === null || Array.isArray(modelVal)) continue;
1353
+ const m = modelVal;
1354
+ const cost = typeof m["cost"] === "object" && m["cost"] !== null ? m["cost"] : {};
1355
+ const limit = typeof m["limit"] === "object" && m["limit"] !== null ? m["limit"] : {};
1356
+ const entry = normalizedModel({
1357
+ id: modelId,
1358
+ provider: providerId,
1359
+ input: cost["input"],
1360
+ output: cost["output"],
1361
+ cachedInput: cost["cache_read"],
1362
+ contextTokens: limit["context"]
1363
+ });
1364
+ if (entry) out.push(entry);
1365
+ }
1366
+ }
1367
+ return out;
1368
+ }
1369
+ function readCache(path) {
1370
+ try {
1371
+ if (!existsSync2(path)) return null;
1372
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
1373
+ if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.models) || !Number.isFinite(parsed.fetchedAt) || parsed.fetchedAt < 0 || typeof parsed.source !== "string") {
1374
+ return null;
1375
+ }
1376
+ const cache2 = parsed;
1377
+ const models = cache2.models.flatMap((row) => {
1378
+ const model = normalizedModel(row);
1379
+ return model ? [model] : [];
1380
+ });
1381
+ return { fetchedAt: cache2.fetchedAt, source: cache2.source, models };
1382
+ } catch {
1383
+ return null;
1384
+ }
1385
+ }
1386
+ function writeCache(path, cache2) {
1387
+ try {
1388
+ mkdirSync2(dirname(path), { recursive: true });
1389
+ writeFileSync2(path, JSON.stringify(cache2, null, 2), { mode: 384 });
1390
+ } catch {
1391
+ }
1392
+ }
1393
+ function isCacheFresh(cache2, opts = {}) {
1394
+ if (!cache2) return false;
1395
+ const now = (opts.now ?? Date.now)();
1396
+ const ttl = opts.ttlMs ?? CATALOG_TTL_MS;
1397
+ const age = now - cache2.fetchedAt;
1398
+ return Number.isFinite(age) && age >= 0 && age < ttl;
1399
+ }
1400
+ function loadCatalogModels(opts = {}) {
1401
+ const cache2 = readCache(catalogCachePath(opts));
1402
+ if (cache2 && cache2.models.length > 0) return cache2;
1403
+ return { fetchedAt: 0, source: "offline", models: OFFLINE_MODEL_CATALOG };
1404
+ }
1405
+ async function syncModelCatalog(opts = {}) {
1406
+ const path = catalogCachePath(opts);
1407
+ const existing = readCache(path);
1408
+ if (!opts.force && isCacheFresh(existing, opts) && (existing?.models.length ?? 0) > 0) {
1409
+ return existing;
1410
+ }
1411
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
1412
+ if (typeof fetchImpl !== "function") return null;
1413
+ const url = opts.url ?? MODELS_DEV_URL;
1414
+ const controller = new AbortController();
1415
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
1416
+ try {
1417
+ const res = await fetchImpl(url, { signal: controller.signal });
1418
+ if (!res.ok) return null;
1419
+ const json = await res.json();
1420
+ const models = normalizeModelsDev(json);
1421
+ if (models.length === 0) return null;
1422
+ const cache2 = {
1423
+ fetchedAt: (opts.now ?? Date.now)(),
1424
+ source: url,
1425
+ models
1426
+ };
1427
+ writeCache(path, cache2);
1428
+ return cache2;
1429
+ } catch {
1430
+ return null;
1431
+ } finally {
1432
+ clearTimeout(timer);
1433
+ }
1434
+ }
1435
+
1436
+ // packages/cli/src/tui/model-catalog.ts
1437
+ var NON_MODEL_PRICING_KEYS = /* @__PURE__ */ new Set(["default"]);
1438
+ function compareStrings(a, b) {
1439
+ if (a === b) return 0;
1440
+ return a < b ? -1 : 1;
1441
+ }
1442
+ function formatRate(value) {
1443
+ return String(Number(value.toFixed(4)));
1444
+ }
1445
+ function formatModelPrice(input, output) {
1446
+ if (input === 0 && output === 0) return "free";
1447
+ return `$${formatRate(input)}/${formatRate(output)} per M`;
1448
+ }
1449
+ function buildModelCatalog(currentModel) {
1450
+ const models = Object.keys(MODEL_PRICING).filter((id) => !NON_MODEL_PRICING_KEYS.has(id)).map((id) => {
1451
+ const provider2 = modelProvider(id);
1452
+ const rates = getRates(Object.hasOwn(METERED_CATALOG_PROVIDERS, provider2) ? `${provider2}/${id}` : id);
1453
+ return { id, provider: provider2, price: provider2 === "cline" && id.startsWith("cline-pass/") ? "ClinePass plan (access unverified)" : formatModelPrice(rates.input, rates.output) };
1454
+ });
1455
+ return models.sort((a, b) => {
1456
+ if (a.id === currentModel) return b.id === currentModel ? 0 : -1;
1457
+ if (b.id === currentModel) return 1;
1458
+ return compareStrings(a.provider, b.provider) || compareStrings(a.id, b.id);
1459
+ });
1460
+ }
1461
+ var PLAN_PROVIDERS = {
1462
+ kimi: true,
1463
+ qwen: true,
1464
+ "z-ai": true,
1465
+ copilot: true,
1466
+ google: true
1467
+ };
1468
+ function compareCatalogRows(currentModel) {
1469
+ return (a, b) => {
1470
+ if (a.id === currentModel) return b.id === currentModel ? 0 : -1;
1471
+ if (b.id === currentModel) return 1;
1472
+ return compareStrings(a.provider, b.provider) || compareStrings(a.id, b.id);
1473
+ };
1474
+ }
1475
+ function catalogExtras(opts = {}) {
1476
+ const priced = new Set(Object.keys(MODEL_PRICING).map((k) => k.toLowerCase()));
1477
+ const out = [];
1478
+ for (const m of loadCatalogModels(opts).models) {
1479
+ if (priced.has(m.id.toLowerCase()) && m.provider === modelProvider(m.id)) continue;
1480
+ const plan = Object.hasOwn(PLAN_PROVIDERS, m.provider) || m.provider === "cline" && m.id.startsWith("cline-pass/");
1481
+ let price = m.provider === "cline" && plan ? "ClinePass plan (access unverified)" : plan ? "subscription" : "\u2014";
1482
+ if (!plan && m.input !== void 0 && m.output !== void 0) {
1483
+ const rates = Object.hasOwn(METERED_CATALOG_PROVIDERS, m.provider) ? getRates(`${m.provider}/${m.id}`) : { input: m.input, output: m.output };
1484
+ price = formatModelPrice(rates.input, rates.output);
1485
+ }
1486
+ out.push({ id: m.id, provider: m.provider, price });
1487
+ }
1488
+ return out;
1489
+ }
1490
+ function buildFullModelCatalog(currentModel, opts = {}) {
1491
+ const extras = catalogExtras(opts);
1492
+ const priced = buildModelCatalog(currentModel);
1493
+ const models = [...priced, ...extras];
1494
+ if (currentModel && !models.some((model) => model.id === currentModel)) {
1495
+ models.push({ id: currentModel, provider: modelProvider(currentModel), price: "\u2014" });
1496
+ }
1497
+ return models.sort(compareCatalogRows(currentModel));
1498
+ }
1499
+
1500
+ // packages/cli/src/tui/available-models.ts
1501
+ var DISCOVERY_TIMEOUT_MS = 1e4;
1502
+ async function boundedCatalog(operation, callerSignal) {
1503
+ const deadline = new AbortController();
1504
+ const signal = callerSignal ? AbortSignal.any([callerSignal, deadline.signal]) : deadline.signal;
1505
+ const timer = setTimeout(() => deadline.abort(), DISCOVERY_TIMEOUT_MS);
1506
+ let onAbort;
1507
+ try {
1508
+ return await new Promise((resolve4, reject) => {
1509
+ onAbort = () => reject(new Error(deadline.signal.aborted ? "Model discovery timed out. Retry this connection." : "Model discovery cancelled."));
1510
+ signal.addEventListener("abort", onAbort, { once: true });
1511
+ if (signal.aborted) {
1512
+ onAbort();
1513
+ return;
1514
+ }
1515
+ Promise.resolve().then(() => {
1516
+ signal.throwIfAborted();
1517
+ return operation(signal);
1518
+ }).then(resolve4, reject);
1519
+ });
1520
+ } finally {
1521
+ clearTimeout(timer);
1522
+ if (onAbort) signal.removeEventListener("abort", onAbort);
1523
+ }
1524
+ }
1525
+ async function discoverConnectionModels(env, providerIds, signal) {
1526
+ const results = await Promise.all(providerIds.map(async (providerId) => {
1527
+ try {
1528
+ const models = await boundedCatalog(async (discoverySignal) => {
1529
+ const runtime = new LlmApiRuntime({
1530
+ type: "api",
1531
+ timeout: DISCOVERY_TIMEOUT_MS,
1532
+ provider: providerId,
1533
+ model: "probe",
1534
+ ...providerId === "chatgpt-plan" ? { siwcConnection: getSiwcConnection(env.HOME) } : {},
1535
+ env: { ...env, ZERO_SKIP_PROVIDER_BANNER: "1" }
1536
+ });
1537
+ return runtime.availableModelCatalog(discoverySignal);
1538
+ }, signal);
1539
+ return { models: models.map((model) => ({ ...model, provider: providerId })), diagnostics: [] };
1540
+ } catch (error) {
1541
+ let message2 = error instanceof Error ? error.message : "Model discovery failed.";
1542
+ for (const [name, value] of Object.entries(env)) {
1543
+ if (value && /KEY|TOKEN|SECRET|PASSWORD/i.test(name)) message2 = message2.split(value).join("[redacted]");
1544
+ }
1545
+ return { models: [], diagnostics: [{ providerId, message: message2.slice(0, 1e3) }] };
1546
+ }
1547
+ }));
1548
+ return { models: results.flatMap((result) => result.models), diagnostics: results.flatMap((result) => result.diagnostics) };
1549
+ }
1550
+
1551
+ // packages/cli/src/tui/context-window.ts
1552
+ var KNOWN_FAMILY_WINDOWS = [
1553
+ ["gpt-5", 272e3],
1554
+ ["gpt-4.1", 1047576],
1555
+ ["gpt-4o", 128e3],
1556
+ ["o3", 2e5],
1557
+ ["o4", 2e5],
1558
+ ["claude", 2e5],
1559
+ ["glm-5", 2e5],
1560
+ ["glm-4", 128e3],
1561
+ ["gemini-2.5", 1048576],
1562
+ ["gemini-2", 1e6],
1563
+ ["deepseek", 128e3],
1564
+ ["qwen", 128e3]
1565
+ ];
1566
+ function knownFamilyWindow(modelId) {
1567
+ const id = modelId.toLowerCase();
1568
+ let best = null;
1569
+ let bestLen = -1;
1570
+ for (const [prefix, tokens] of KNOWN_FAMILY_WINDOWS) {
1571
+ if (id.startsWith(prefix) && prefix.length > bestLen) {
1572
+ best = tokens;
1573
+ bestLen = prefix.length;
1574
+ }
1575
+ }
1576
+ return best;
1577
+ }
1578
+ function positiveTokens(value) {
1579
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
1580
+ }
1581
+ function sameByokModel(row, identity) {
1582
+ return row.id === identity.modelId && row.provider === identity.providerId;
1583
+ }
1584
+ function resolveContextLimit(identity, opts = {}) {
1585
+ if (!identity.modelId || !identity.providerId) return null;
1586
+ const familyFallback = () => {
1587
+ const family = knownFamilyWindow(identity.modelId);
1588
+ return family === null ? null : { tokens: family, source: "known-family" };
1589
+ };
1590
+ const load = opts.loadModels ?? loadCatalogModels;
1591
+ const cache2 = load(opts.sync ?? {});
1592
+ const row = cache2.models.find((model) => sameByokModel(model, identity));
1593
+ const tokens = row ? positiveTokens(row.contextTokens) : null;
1594
+ if (tokens !== null) {
1595
+ return { tokens, source: cache2.source === "offline" ? "offline-catalog" : "synced-catalog" };
1596
+ }
1597
+ return familyFallback();
1598
+ }
1599
+
1600
+ // packages/cli/src/tui/device-auth.ts
1601
+ import { createHash as createHash2, randomBytes as randomBytes2, randomUUID as randomUUID2 } from "node:crypto";
1602
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
1603
+ import { createServer as createServer2 } from "node:http";
1604
+ import { arch, hostname, platform as platform2, release, version as osVersion } from "node:os";
1605
+ import { join as join3 } from "node:path";
1606
+
1607
+ // packages/cli/src/open-browser.ts
1608
+ import { spawn } from "node:child_process";
1609
+ import { platform } from "node:os";
1610
+ function defaultOpenBrowser(url) {
1611
+ const plat = platform();
1612
+ return new Promise((resolve4, reject) => {
1613
+ const options = { detached: true, stdio: "ignore", shell: false };
1614
+ const child = plat === "darwin" ? spawn("open", [url], options) : plat === "win32" ? spawn("powershell.exe", [
1615
+ "-NoProfile",
1616
+ "-NonInteractive",
1617
+ "-Command",
1618
+ "Start-Process -FilePath $env:OSEC_BROWSER_LOGIN_URL"
1619
+ ], { ...options, env: { ...process.env, OSEC_BROWSER_LOGIN_URL: url } }) : spawn("xdg-open", [url], options);
1620
+ child.once("error", reject);
1621
+ child.once("spawn", () => {
1622
+ child.unref();
1623
+ resolve4();
1624
+ });
1625
+ });
1626
+ }
1627
+
1628
+ // packages/cli/src/tui/text.ts
1629
+ var DEFAULT_ENCODED_RUN_MAX = 140;
1630
+ var ENCODED_RUN_MAX_CAP = 1e6;
1631
+ var ENCODED_PLACEHOLDER = "[encoded payload omitted]";
1632
+ var DEFAULT_ENCODED_SEGMENT = new RegExp(`[A-Za-z0-9+_-]{${DEFAULT_ENCODED_RUN_MAX},}={0,2}`, "g");
1633
+ var DEFAULT_ENCODED_DATA_URI = new RegExp(`(data:[^\\s,]*;base64,)[A-Za-z0-9+/_-]{${DEFAULT_ENCODED_RUN_MAX},}={0,2}`, "gi");
1634
+ function stripTerminalControl(text2) {
1635
+ return text2.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
1636
+ }
1637
+ function replaceLargeEncodedChunks(text2, maxEncodedRun) {
1638
+ const normalized = Number.isFinite(maxEncodedRun) ? Math.trunc(maxEncodedRun) : DEFAULT_ENCODED_RUN_MAX;
1639
+ const minRun = Math.min(Math.max(32, normalized), ENCODED_RUN_MAX_CAP);
1640
+ if (text2.length < minRun) return text2;
1641
+ const segment = minRun === DEFAULT_ENCODED_RUN_MAX ? DEFAULT_ENCODED_SEGMENT : new RegExp(`[A-Za-z0-9+_-]{${minRun},}={0,2}`, "g");
1642
+ const dataUri = minRun === DEFAULT_ENCODED_RUN_MAX ? DEFAULT_ENCODED_DATA_URI : new RegExp(`(data:[^\\s,]*;base64,)[A-Za-z0-9+/_-]{${minRun},}={0,2}`, "gi");
1643
+ return text2.replace(dataUri, `$1${ENCODED_PLACEHOLDER}`).replace(segment, ENCODED_PLACEHOLDER);
1644
+ }
1645
+ function sanitizeTuiText(value, options = {}) {
1646
+ return stripTerminalControl(replaceLargeEncodedChunks(String(value ?? ""), options.maxEncodedRun ?? DEFAULT_ENCODED_RUN_MAX)).replace(/\s+/g, " ").trim();
1647
+ }
1648
+ function sanitizeComposerText(value) {
1649
+ return stripTerminalControl(String(value ?? ""));
1650
+ }
1651
+
1652
+ // packages/cli/src/tui/device-auth.ts
1653
+ var MAX_VISIBLE_LINES = 8;
1654
+ var DEFAULT_INTERVAL_SECONDS = 5;
1655
+ var SLOW_DOWN_INCREMENT_SECONDS = 5;
1656
+ var DEFAULT_EXPIRES_IN_SECONDS = 900;
1657
+ var defaultFetch = (url, init) => globalThis.fetch(url, init);
1658
+ var defaultSleep = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
1659
+ var PKCE_TIMEOUT_SECONDS = 300;
1660
+ var base64url = (buffer) => buffer.toString("base64url");
1661
+ var defaultCreatePkcePair = () => {
1662
+ const verifier = base64url(randomBytes2(32));
1663
+ const challenge = base64url(createHash2("sha256").update(verifier).digest());
1664
+ return { verifier, challenge };
1665
+ };
1666
+ var defaultServerFactory = async ({ onRedirect }) => {
1667
+ let delivered = false;
1668
+ const server = createServer2((req, res) => {
1669
+ const requestUrl = new URL(req.url ?? "/", "http://127.0.0.1");
1670
+ if (requestUrl.pathname !== "/callback") {
1671
+ res.statusCode = 404;
1672
+ res.end("Not found");
1673
+ return;
1674
+ }
1675
+ const code = requestUrl.searchParams.get("code") ?? void 0;
1676
+ const error = requestUrl.searchParams.get("error") ?? void 0;
1677
+ res.statusCode = 200;
1678
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
1679
+ res.end("<!doctype html><meta charset=utf-8><title>0</title><body>Sign-in complete \u2014 you can close this tab and return to 0.</body>");
1680
+ if (delivered) return;
1681
+ delivered = true;
1682
+ onRedirect({ code, error });
1683
+ });
1684
+ await new Promise((resolve4, reject) => {
1685
+ server.once("error", reject);
1686
+ server.listen(0, "127.0.0.1", () => resolve4());
1687
+ });
1688
+ const address = server.address();
1689
+ const port = typeof address === "object" && address !== null ? address.port : 0;
1690
+ return { port, close: () => server.close() };
1691
+ };
1692
+ function providerLabel(providerId) {
1693
+ return PROVIDERS.find((provider2) => provider2.id === providerId)?.label ?? providerId;
1694
+ }
1695
+ function positiveInt(value, fallback) {
1696
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : fallback;
1697
+ }
1698
+ function isPlainObject(value) {
1699
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1700
+ }
1701
+ function startDeviceAuth(config, options) {
1702
+ const env = options.env ?? process.env;
1703
+ const transport = options.fetch ?? defaultFetch;
1704
+ const now = options.now ?? Date.now;
1705
+ const sleep = options.sleep ?? defaultSleep;
1706
+ const openBrowser = options.openBrowser ?? defaultOpenBrowser;
1707
+ const label = providerLabel(config.providerId);
1708
+ const lines = [];
1709
+ let settled = false;
1710
+ let cancelled = false;
1711
+ const controller = new AbortController();
1712
+ let deadlineTimer;
1713
+ const bounded = (work) => new Promise((resolve4, reject) => {
1714
+ const abort = () => {
1715
+ cleanup();
1716
+ reject(controller.signal.reason);
1717
+ };
1718
+ const cleanup = () => controller.signal.removeEventListener("abort", abort);
1719
+ if (controller.signal.aborted) {
1720
+ abort();
1721
+ return;
1722
+ }
1723
+ controller.signal.addEventListener("abort", abort, { once: true });
1724
+ work.then((value) => {
1725
+ cleanup();
1726
+ resolve4(value);
1727
+ }, (error) => {
1728
+ cleanup();
1729
+ reject(error);
1730
+ });
1731
+ });
1732
+ const doFetch = async (url, init) => {
1733
+ controller.signal.throwIfAborted();
1734
+ const response = await bounded(transport(url, { ...init, signal: controller.signal }));
1735
+ return { ...response, ok: response.ok, status: response.status, json: () => bounded(response.json()) };
1736
+ };
1737
+ const armDeadline = (ms) => {
1738
+ if (deadlineTimer !== void 0) clearTimeout(deadlineTimer);
1739
+ deadlineTimer = setTimeout(() => {
1740
+ finish("failed", `${label} sign-in timed out. Start again.`);
1741
+ controller.abort(new Error("Sign-in timed out"));
1742
+ cancelWaiter?.();
1743
+ }, ms);
1744
+ deadlineTimer.unref?.();
1745
+ };
1746
+ const pushLine = (text2) => {
1747
+ const value = sanitizeTuiText(text2);
1748
+ if (value.length === 0) return;
1749
+ lines.push(value);
1750
+ if (lines.length > MAX_VISIBLE_LINES) lines.shift();
1751
+ };
1752
+ const publish = (phase, message2) => {
1753
+ if (settled && phase === "running") return;
1754
+ options.onUpdate({ phase, lines: [...lines], message: message2 });
1755
+ };
1756
+ const finish = (phase, message2) => {
1757
+ if (settled) return;
1758
+ settled = true;
1759
+ if (deadlineTimer !== void 0) clearTimeout(deadlineTimer);
1760
+ publish(phase, message2);
1761
+ };
1762
+ const requestDeviceCode = async (cfg) => {
1763
+ const params = new URLSearchParams({ client_id: cfg.clientId });
1764
+ if (cfg.scopes.length > 0) params.set("scope", cfg.scopes.join(" "));
1765
+ const response = await doFetch(cfg.deviceCodeUrl, {
1766
+ method: "POST",
1767
+ headers: {
1768
+ "Content-Type": "application/x-www-form-urlencoded",
1769
+ Accept: "application/json",
1770
+ ...cfg.buildHeaders?.(options.homeDir)
1771
+ },
1772
+ body: params.toString()
1773
+ });
1774
+ if (!response.ok) {
1775
+ throw new Error(`Device code request failed (HTTP ${response.status}).`);
1776
+ }
1777
+ const parsed = await response.json();
1778
+ if (!isPlainObject(parsed) || typeof parsed.device_code !== "string" || typeof parsed.user_code !== "string") {
1779
+ throw new Error("Device code response was missing a device_code or user_code.");
1780
+ }
1781
+ const verificationUri = typeof parsed.verification_uri === "string" ? parsed.verification_uri : typeof parsed.verification_uri_complete === "string" ? parsed.verification_uri_complete : void 0;
1782
+ if (verificationUri === void 0) {
1783
+ throw new Error("Device code response was missing a verification URL.");
1784
+ }
1785
+ return {
1786
+ device_code: parsed.device_code,
1787
+ user_code: parsed.user_code,
1788
+ verification_uri: verificationUri,
1789
+ verification_uri_complete: typeof parsed.verification_uri_complete === "string" ? parsed.verification_uri_complete : void 0,
1790
+ interval: positiveInt(parsed.interval, DEFAULT_INTERVAL_SECONDS),
1791
+ expires_in: positiveInt(parsed.expires_in, DEFAULT_EXPIRES_IN_SECONDS)
1792
+ };
1793
+ };
1794
+ const pollTokenOnce = async (cfg, deviceCode) => {
1795
+ const body = new URLSearchParams({
1796
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1797
+ device_code: deviceCode,
1798
+ client_id: cfg.clientId
1799
+ }).toString();
1800
+ let response;
1801
+ try {
1802
+ response = await doFetch(cfg.tokenUrl, {
1803
+ method: "POST",
1804
+ headers: {
1805
+ "Content-Type": "application/x-www-form-urlencoded",
1806
+ Accept: "application/json",
1807
+ ...cfg.buildHeaders?.(options.homeDir)
1808
+ },
1809
+ body
1810
+ });
1811
+ } catch (error) {
1812
+ return { kind: "failed", message: error instanceof Error ? error.message : String(error) };
1813
+ }
1814
+ let parsed;
1815
+ try {
1816
+ parsed = await response.json();
1817
+ } catch {
1818
+ return { kind: "failed", message: `Token response was not valid JSON (HTTP ${response.status}).` };
1819
+ }
1820
+ if (response.ok && isPlainObject(parsed) && typeof parsed.access_token === "string") {
1821
+ return { kind: "token", response: parsed };
1822
+ }
1823
+ const oauthError = isPlainObject(parsed) && typeof parsed.error === "string" ? parsed.error : void 0;
1824
+ switch (oauthError) {
1825
+ case "authorization_pending":
1826
+ return { kind: "pending" };
1827
+ case "slow_down":
1828
+ return { kind: "slow_down" };
1829
+ case "expired_token":
1830
+ return { kind: "failed", message: `${label} device sign-in code expired. Start again.` };
1831
+ case "access_denied":
1832
+ return { kind: "failed", message: `${label} device sign-in was denied.` };
1833
+ default:
1834
+ return {
1835
+ kind: "failed",
1836
+ message: oauthError ? `${label} device sign-in failed: ${oauthError}.` : `${label} device sign-in failed (HTTP ${response.status}).`
1837
+ };
1838
+ }
1839
+ };
1840
+ const persist = (record, connectedMessage) => {
1841
+ if (settled || cancelled || controller.signal.aborted) return;
1842
+ const { store } = addAccount(loadAccountStore(options.homeDir), config.providerId, record);
1843
+ if (!saveAccountStore(store, options.homeDir)) {
1844
+ finish("failed", "Sign-in completed, but the private credential account store could not be saved. Try again after restoring access to the local state directory.");
1845
+ return;
1846
+ }
1847
+ const patch = accountEnvPatch(store, env);
1848
+ for (const [key, value] of Object.entries(patch)) env[key] = value;
1849
+ finish("connected", connectedMessage);
1850
+ options.onConnected();
1851
+ };
1852
+ const runDeviceCode = async (cfg) => {
1853
+ publish("running", `Starting ${label} device sign-in\u2026`);
1854
+ let device;
1855
+ try {
1856
+ device = await requestDeviceCode(cfg);
1857
+ } catch (error) {
1858
+ finish("failed", error instanceof Error ? error.message : String(error));
1859
+ return;
1860
+ }
1861
+ if (cancelled) {
1862
+ finish("cancelled", `${label} device sign-in cancelled.`);
1863
+ return;
1864
+ }
1865
+ const openUrl = device.verification_uri_complete ?? device.verification_uri;
1866
+ pushLine(`Enter code: ${device.user_code}`);
1867
+ pushLine(`Visit: ${device.verification_uri}`);
1868
+ publish("running", `Complete the ${label} device sign-in in your browser.`);
1869
+ try {
1870
+ await bounded(Promise.resolve(openBrowser(openUrl)));
1871
+ } catch {
1872
+ pushLine("Could not open a browser automatically; open the URL above.");
1873
+ publish("running", `Complete the ${label} device sign-in in your browser.`);
1874
+ }
1875
+ if (settled) return;
1876
+ let intervalSeconds = device.interval ?? DEFAULT_INTERVAL_SECONDS;
1877
+ const deadline = now() + (device.expires_in ?? DEFAULT_EXPIRES_IN_SECONDS) * 1e3;
1878
+ armDeadline(Math.max(0, deadline - now()));
1879
+ while (!cancelled) {
1880
+ if (options.sleep) await bounded(sleep(intervalSeconds * 1e3));
1881
+ else await bounded(new Promise((resolve4, reject) => {
1882
+ const abort = () => {
1883
+ clearTimeout(timer);
1884
+ reject(controller.signal.reason);
1885
+ };
1886
+ const timer = setTimeout(() => {
1887
+ controller.signal.removeEventListener("abort", abort);
1888
+ resolve4();
1889
+ }, intervalSeconds * 1e3);
1890
+ controller.signal.addEventListener("abort", abort, { once: true });
1891
+ }));
1892
+ if (cancelled) break;
1893
+ if (now() >= deadline) {
1894
+ finish("failed", `${label} device sign-in timed out. Start again.`);
1895
+ return;
1896
+ }
1897
+ const result = await pollTokenOnce(cfg, device.device_code);
1898
+ if (cancelled) break;
1899
+ if (result.kind === "token") {
1900
+ persist(cfg.toAccountRecord(result.response), `${label} connected through device sign-in.`);
1901
+ return;
1902
+ }
1903
+ if (result.kind === "failed") {
1904
+ finish("failed", result.message);
1905
+ return;
1906
+ }
1907
+ if (result.kind === "slow_down") {
1908
+ intervalSeconds += SLOW_DOWN_INCREMENT_SECONDS;
1909
+ }
1910
+ }
1911
+ finish("cancelled", `${label} device sign-in cancelled.`);
1912
+ };
1913
+ const exchangeCode = async (cfg, code, verifier, redirectUri) => {
1914
+ const useForm = cfg.exchangeBodyMode === "form";
1915
+ const headers = useForm ? { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" } : { "Content-Type": "application/json", Accept: "application/json" };
1916
+ const body = useForm ? new URLSearchParams({
1917
+ grant_type: "authorization_code",
1918
+ code,
1919
+ code_verifier: verifier,
1920
+ redirect_uri: redirectUri,
1921
+ ...cfg.clientId !== void 0 ? { client_id: cfg.clientId } : {},
1922
+ ...cfg.clientSecret !== void 0 ? { client_secret: cfg.clientSecret } : {}
1923
+ }).toString() : JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" });
1924
+ let response;
1925
+ try {
1926
+ response = await doFetch(cfg.keysUrl, {
1927
+ method: "POST",
1928
+ headers,
1929
+ body
1930
+ });
1931
+ } catch (error) {
1932
+ return { kind: "failed", message: error instanceof Error ? error.message : String(error) };
1933
+ }
1934
+ let parsed;
1935
+ try {
1936
+ parsed = await response.json();
1937
+ } catch {
1938
+ return { kind: "failed", message: `${label} sign-in exchange was not valid JSON (HTTP ${response.status}).` };
1939
+ }
1940
+ if (!response.ok) {
1941
+ const oauthError = isPlainObject(parsed) && typeof parsed.error === "string" ? parsed.error : void 0;
1942
+ return {
1943
+ kind: "failed",
1944
+ message: oauthError ? `${label} browser sign-in failed: ${oauthError}.` : `${label} browser sign-in failed (HTTP ${response.status}).`
1945
+ };
1946
+ }
1947
+ if (!isPlainObject(parsed)) {
1948
+ return { kind: "failed", message: `${label} sign-in exchange returned an unexpected body.` };
1949
+ }
1950
+ return { kind: "ok", response: parsed };
1951
+ };
1952
+ const runPkceLoopback = async (cfg) => {
1953
+ publish("running", `Starting ${label} browser sign-in\u2026`);
1954
+ const { verifier, challenge } = (options.createPkcePair ?? defaultCreatePkcePair)();
1955
+ const serverFactory = options.serverFactory ?? defaultServerFactory;
1956
+ let resolveOutcome = () => {
1957
+ };
1958
+ const outcomePromise = new Promise((resolve4) => {
1959
+ resolveOutcome = resolve4;
1960
+ });
1961
+ let server;
1962
+ try {
1963
+ server = await serverFactory({
1964
+ onRedirect: (redirect) => resolveOutcome({ type: "redirect", redirect })
1965
+ });
1966
+ } catch (error2) {
1967
+ finish("failed", `${label} browser sign-in could not start a local server: ${error2 instanceof Error ? error2.message : String(error2)}.`);
1968
+ return;
1969
+ }
1970
+ cancelWaiter = () => resolveOutcome({ type: "cancelled" });
1971
+ if (cancelled || settled) {
1972
+ server.close();
1973
+ finish("cancelled", `${label} browser sign-in cancelled.`);
1974
+ return;
1975
+ }
1976
+ const redirectUri = `http://localhost:${server.port}/callback`;
1977
+ const state = base64url(randomBytes2(16)).replace(/[^a-zA-Z0-9]/g, "").slice(0, 32);
1978
+ const authorizeUrl = new URL(cfg.authorizeUrl);
1979
+ authorizeUrl.searchParams.set(cfg.redirectParam ?? "redirect_uri", redirectUri);
1980
+ authorizeUrl.searchParams.set("code_challenge", challenge);
1981
+ authorizeUrl.searchParams.set("code_challenge_method", "S256");
1982
+ if (cfg.clientId !== void 0) authorizeUrl.searchParams.set("client_id", cfg.clientId);
1983
+ if (cfg.scopes.length > 0) authorizeUrl.searchParams.set("scope", cfg.scopes.join(" "));
1984
+ for (const [key, value] of Object.entries(cfg.authorizeParams ?? {})) {
1985
+ authorizeUrl.searchParams.set(key, value);
1986
+ }
1987
+ if (cfg.authorizeParams !== void 0) authorizeUrl.searchParams.set("state", state);
1988
+ const openUrl = authorizeUrl.toString();
1989
+ pushLine(`Sign in at: ${openUrl}`);
1990
+ publish("running", `Complete the ${label} sign-in in your browser.`);
1991
+ try {
1992
+ await bounded(Promise.resolve(openBrowser(openUrl)));
1993
+ } catch {
1994
+ pushLine("Could not open a browser automatically; open the URL above.");
1995
+ publish("running", `Complete the ${label} sign-in in your browser.`);
1996
+ }
1997
+ if (options.sleep) void bounded(sleep(PKCE_TIMEOUT_SECONDS * 1e3)).then(() => {
1998
+ finish("failed", `${label} browser sign-in timed out. Start again.`);
1999
+ controller.abort(new Error("Sign-in timed out"));
2000
+ resolveOutcome({ type: "timeout" });
2001
+ }, () => {
2002
+ });
2003
+ const outcome = await outcomePromise;
2004
+ server.close();
2005
+ if (outcome.type === "cancelled" || cancelled) {
2006
+ finish("cancelled", `${label} browser sign-in cancelled.`);
2007
+ return;
2008
+ }
2009
+ if (outcome.type === "timeout") {
2010
+ finish("failed", `${label} browser sign-in timed out. Start again.`);
2011
+ return;
2012
+ }
2013
+ const { code, error } = outcome.redirect;
2014
+ if (error !== void 0) {
2015
+ finish("failed", `${label} browser sign-in was denied: ${error}.`);
2016
+ return;
2017
+ }
2018
+ if (code === void 0 || code.length === 0) {
2019
+ finish("failed", `${label} browser sign-in did not return an authorization code.`);
2020
+ return;
2021
+ }
2022
+ const result = await exchangeCode(cfg, code, verifier, redirectUri);
2023
+ if (cancelled) {
2024
+ finish("cancelled", `${label} browser sign-in cancelled.`);
2025
+ return;
2026
+ }
2027
+ if (result.kind === "failed") {
2028
+ finish("failed", result.message);
2029
+ return;
2030
+ }
2031
+ let record;
2032
+ try {
2033
+ record = cfg.toAccountRecord(result.response);
2034
+ } catch (error2) {
2035
+ finish("failed", error2 instanceof Error ? error2.message : String(error2));
2036
+ return;
2037
+ }
2038
+ persist(record, `${label} connected through browser sign-in.`);
2039
+ };
2040
+ let cancelWaiter;
2041
+ armDeadline((config.kind === "pkce-loopback" ? PKCE_TIMEOUT_SECONDS : DEFAULT_EXPIRES_IN_SECONDS) * 1e3);
2042
+ void (config.kind === "pkce-loopback" ? runPkceLoopback(config) : runDeviceCode(config)).catch((error) => {
2043
+ finish(cancelled ? "cancelled" : "failed", cancelled ? `${label} sign-in cancelled.` : error instanceof Error ? error.message : "Sign-in failed.");
2044
+ });
2045
+ return {
2046
+ cancel: () => {
2047
+ if (settled || cancelled) return;
2048
+ cancelled = true;
2049
+ finish("cancelled", `${label} sign-in cancelled.`);
2050
+ controller.abort(new Error("Sign-in cancelled"));
2051
+ cancelWaiter?.();
2052
+ }
2053
+ };
2054
+ }
2055
+ var KIMI_DEVICE_ID_FILENAME = "kimi-device-id";
2056
+ function kimiDeviceId(homeDir) {
2057
+ const idPath = join3(homeStateDir(homeDir), KIMI_DEVICE_ID_FILENAME);
2058
+ try {
2059
+ const existing = readFileSync3(idPath, "utf8").trim();
2060
+ if (existing) return existing;
2061
+ } catch {
2062
+ }
2063
+ const deviceId = randomUUID2().replace(/-/g, "");
2064
+ try {
2065
+ mkdirSync3(homeStateDir(homeDir), { recursive: true });
2066
+ writeFileSync3(idPath, `${deviceId}
2067
+ `, { mode: 384 });
2068
+ } catch {
2069
+ }
2070
+ return deviceId;
2071
+ }
2072
+ function sanitizeHeaderValue(value, fallback = "unknown") {
2073
+ const sanitized = value.replace(/[^\x20-\x7E]/g, "").trim();
2074
+ return sanitized || fallback;
2075
+ }
2076
+ function kimiDeviceModel() {
2077
+ const plat = platform2();
2078
+ const label = plat === "darwin" ? "macOS" : plat === "win32" ? "Windows" : plat === "linux" ? "Linux" : plat;
2079
+ return [label, release(), arch()].filter(Boolean).join(" ").trim();
2080
+ }
2081
+ function kimiFingerprintHeaders(homeDir) {
2082
+ return {
2083
+ "User-Agent": "0security",
2084
+ "X-Msh-Platform": "0security",
2085
+ "X-Msh-Version": "0",
2086
+ "X-Msh-Device-Name": sanitizeHeaderValue(hostname()),
2087
+ "X-Msh-Device-Model": sanitizeHeaderValue(kimiDeviceModel()),
2088
+ "X-Msh-Os-Version": sanitizeHeaderValue(osVersion()),
2089
+ "X-Msh-Device-Id": sanitizeHeaderValue(kimiDeviceId(homeDir))
2090
+ };
2091
+ }
2092
+ function createProviderDeviceAuth(env = process.env) {
2093
+ const clientId = (name) => env[name]?.trim() || void 0;
2094
+ return {
2095
+ // Endpoints use the provider protocol; client identity must be registered for 0.
2096
+ ...clientId("ZERO_XAI_OAUTH_CLIENT_ID") ? { xai: {
2097
+ kind: "device-code",
2098
+ providerId: "xai",
2099
+ deviceCodeUrl: "https://auth.x.ai/oauth2/device/code",
2100
+ tokenUrl: "https://auth.x.ai/oauth2/token",
2101
+ clientId: clientId("ZERO_XAI_OAUTH_CLIENT_ID"),
2102
+ scopes: ["openid", "profile", "email", "offline_access", "grok-cli:access", "api:access"],
2103
+ toAccountRecord: buildOAuthRecord
2104
+ } } : {},
2105
+ // Never borrow the official Kimi CLI client identity for a new 0 sign-in.
2106
+ // Opt-in is only for an operator who has registered a client for 0.
2107
+ ...clientId("ZERO_KIMI_OAUTH_CLIENT_ID") ? { kimi: {
2108
+ kind: "device-code",
2109
+ providerId: "kimi",
2110
+ deviceCodeUrl: "https://auth.kimi.com/api/oauth/device_authorization",
2111
+ tokenUrl: "https://auth.kimi.com/api/oauth/token",
2112
+ clientId: clientId("ZERO_KIMI_OAUTH_CLIENT_ID"),
2113
+ scopes: [],
2114
+ buildHeaders: kimiFingerprintHeaders,
2115
+ toAccountRecord: buildOAuthRecord
2116
+ } } : {},
2117
+ // Own GitHub app registration must also be entitled to the Copilot service.
2118
+ ...clientId("ZERO_COPILOT_OAUTH_CLIENT_ID") ? { copilot: {
2119
+ kind: "device-code",
2120
+ providerId: "copilot",
2121
+ deviceCodeUrl: "https://github.com/login/device/code",
2122
+ tokenUrl: "https://github.com/login/oauth/access_token",
2123
+ clientId: clientId("ZERO_COPILOT_OAUTH_CLIENT_ID"),
2124
+ scopes: ["read:user"],
2125
+ toAccountRecord: buildOAuthRecord
2126
+ } } : {},
2127
+ // Matches oh-my-pi rules/auth/openrouter.kdl (fetched 2026-09-14):
2128
+ // https://github.com/can1357/oh-my-pi/blob/main/packages/catalog/src/compat/rules/auth/openrouter.kdl
2129
+ // login "oauth-code" pkce=#true, standard authorize params OFF: open
2130
+ // https://openrouter.ai/auth?callback_url=<loopback>&code_challenge=<c>&code_challenge_method=S256
2131
+ // (CLIENT-ID-LESS — no client_id param), then POST JSON
2132
+ // { code, code_verifier, code_challenge_method: "S256" }
2133
+ // to https://openrouter.ai/api/v1/auth/keys, which PROVISIONS a durable
2134
+ // `sk-or-...` API key. The kdl's `credential { access "key" }` names the
2135
+ // response field `key` (buildOpenRouterKeyRecord). Stored as an api_key record
2136
+ // and written to OPENROUTER_API_KEY (envVars[0]) by accountEnvPatch, which
2137
+ // llm-api already reads — so no llm-api change.
2138
+ openrouter: {
2139
+ kind: "pkce-loopback",
2140
+ providerId: "openrouter",
2141
+ authorizeUrl: "https://openrouter.ai/auth",
2142
+ keysUrl: "https://openrouter.ai/api/v1/auth/keys",
2143
+ redirectParam: "callback_url",
2144
+ scopes: [],
2145
+ toAccountRecord: buildOpenRouterKeyRecord
2146
+ },
2147
+ // Google browser sign-in requires a 0 registration entitled to Code Assist.
2148
+ ...clientId("ZERO_GOOGLE_OAUTH_CLIENT_ID") ? { google: {
2149
+ kind: "pkce-loopback",
2150
+ providerId: "google",
2151
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
2152
+ keysUrl: "https://oauth2.googleapis.com/token",
2153
+ clientId: clientId("ZERO_GOOGLE_OAUTH_CLIENT_ID"),
2154
+ ...env.ZERO_GOOGLE_OAUTH_CLIENT_SECRET ? { clientSecret: env.ZERO_GOOGLE_OAUTH_CLIENT_SECRET } : {},
2155
+ exchangeBodyMode: "form",
2156
+ authorizeParams: { response_type: "code", access_type: "offline", prompt: "consent" },
2157
+ scopes: [
2158
+ "https://www.googleapis.com/auth/cloud-platform",
2159
+ "https://www.googleapis.com/auth/userinfo.email",
2160
+ "https://www.googleapis.com/auth/userinfo.profile"
2161
+ ],
2162
+ toAccountRecord: (tokenResponse) => ({
2163
+ ...buildOAuthRecord(tokenResponse),
2164
+ oauthClient: { clientId: clientId("ZERO_GOOGLE_OAUTH_CLIENT_ID"), ...env.ZERO_GOOGLE_OAUTH_CLIENT_SECRET ? { clientSecret: env.ZERO_GOOGLE_OAUTH_CLIENT_SECRET } : {} }
2165
+ })
2166
+ } } : {}
2167
+ };
2168
+ }
2169
+ var PROVIDER_DEVICE_AUTH = createProviderDeviceAuth();
2170
+ function buildOAuthRecord(tokenResponse) {
2171
+ const tokens = {};
2172
+ if (typeof tokenResponse.access_token === "string") tokens.accessToken = tokenResponse.access_token;
2173
+ if (typeof tokenResponse.refresh_token === "string") tokens.refreshToken = tokenResponse.refresh_token;
2174
+ if (typeof tokenResponse.expires_in === "number" && Number.isFinite(tokenResponse.expires_in)) {
2175
+ tokens.expiresAt = Date.now() + tokenResponse.expires_in * 1e3;
2176
+ }
2177
+ return { kind: "oauth", tokens };
2178
+ }
2179
+ function buildOpenRouterKeyRecord(exchange) {
2180
+ const key = typeof exchange.key === "string" ? exchange.key : void 0;
2181
+ if (key === void 0 || key.length === 0) {
2182
+ throw new Error("OpenRouter sign-in did not return an API key.");
2183
+ }
2184
+ return { kind: "api_key", secret: key };
2185
+ }
2186
+
2187
+ // packages/cli/src/tui/plugin-service.ts
2188
+ import { chmodSync, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "node:fs";
2189
+ import { join as join4 } from "node:path";
2190
+ function coreLoader(injected) {
2191
+ if (typeof injected === "function") return injected;
2192
+ if (injected) return async () => injected;
2193
+ let cached;
2194
+ return () => {
2195
+ if (!cached) cached = import("./dist-ONIRKDH6.js");
2196
+ return cached;
2197
+ };
2198
+ }
2199
+ function defaultApplyTheme(themeId) {
2200
+ try {
2201
+ return updateSetting("theme", themeId) === true;
2202
+ } catch {
2203
+ return false;
2204
+ }
2205
+ }
2206
+ function createPluginService(deps = {}) {
2207
+ const getCore = coreLoader(deps.core);
2208
+ const homeDir = deps.homeDir;
2209
+ const projectPath = deps.projectPath ?? process.cwd();
2210
+ const now = deps.now ?? Date.now;
2211
+ const fetchImpl = deps.fetchImpl ?? fetch;
2212
+ const isTurnActive2 = deps.isTurnActive ?? (() => false);
2213
+ const applyTheme = deps.applyTheme ?? defaultApplyTheme;
2214
+ const reservedToolNames2 = deps.reservedToolNames;
2215
+ const registryUrl = (deps.registryUrl ?? "").trim();
2216
+ const manager = deps.pluginHostManager;
2217
+ let host;
2218
+ const deferred = [];
2219
+ async function core() {
2220
+ return getCore();
2221
+ }
2222
+ function installedViews(c, root, ids) {
2223
+ const views = [];
2224
+ for (const id of ids) {
2225
+ let disc;
2226
+ try {
2227
+ disc = c.readInstalledPlugin(root, id, reservedToolNames2 ? { reservedToolNames: reservedToolNames2 } : void 0);
2228
+ } catch {
2229
+ continue;
2230
+ }
2231
+ if (!disc.ok || !disc.plugin) continue;
2232
+ const manifest = disc.plugin.manifest;
2233
+ views.push({
2234
+ id,
2235
+ version: manifest.version,
2236
+ capabilities: c.aggregateCapabilities(manifest)
2237
+ });
2238
+ }
2239
+ return views;
2240
+ }
2241
+ async function fetchRegistry() {
2242
+ try {
2243
+ const c = await core();
2244
+ const fetched = await c.fetchRegistryIndex(registryUrl, {
2245
+ fetchImpl,
2246
+ verifier: c.unconfiguredVerifier
2247
+ });
2248
+ if (!fetched.ok) return { ok: false, error: fetched.error };
2249
+ return { ok: true, result: fetched.result };
2250
+ } catch (error) {
2251
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
2252
+ }
2253
+ }
2254
+ async function list(activeTheme) {
2255
+ const themes = /* @__PURE__ */ new Set();
2256
+ try {
2257
+ for (const entry of installedThemeEntries(homeDir)) themes.add(entry.name);
2258
+ } catch {
2259
+ }
2260
+ const plugins = /* @__PURE__ */ new Map();
2261
+ try {
2262
+ const c = await core();
2263
+ const root = c.pluginsRootDir(homeDir);
2264
+ const ids = c.listInstalledPluginIds(root);
2265
+ const record = c.readEnablement(projectPath, homeDir);
2266
+ const loadable = new Set(c.loadableIds(c.reconcile(record, installedViews(c, root, ids))));
2267
+ for (const id of ids) {
2268
+ plugins.set(id, loadable.has(id) ? "enabled" : "installed");
2269
+ }
2270
+ } catch {
2271
+ }
2272
+ return { themes, activeTheme, plugins };
2273
+ }
2274
+ function installTheme(item) {
2275
+ if (!isSafeThemeId(item.id)) {
2276
+ return { ok: false, message: `"${item.id}" is not a valid theme id; refused.` };
2277
+ }
2278
+ const theme = item.raw?.manifest?.theme;
2279
+ const palette = theme?.palette;
2280
+ if (!palette || typeof palette !== "object") {
2281
+ return { ok: false, message: `Theme "${item.id}" is missing its palette.` };
2282
+ }
2283
+ if (validateTheme(palette).length > 0) {
2284
+ return { ok: false, message: `Theme "${item.id}" has an invalid palette; refused.` };
2285
+ }
2286
+ const written = writeInstalledTheme(
2287
+ {
2288
+ id: item.id,
2289
+ label: theme.label,
2290
+ description: theme.description,
2291
+ mode: theme.mode,
2292
+ palette
2293
+ },
2294
+ homeDir
2295
+ );
2296
+ if (!written.ok) return { ok: false, message: `Could not install "${item.id}": ${written.error}` };
2297
+ reloadInstalledThemes(homeDir);
2298
+ return {
2299
+ ok: true,
2300
+ message: `Installed theme ${item.id}. Select it to apply.`,
2301
+ state: "installed"
2302
+ };
2303
+ }
2304
+ async function installPlugin(item) {
2305
+ const entry = item.raw;
2306
+ try {
2307
+ const c = await core();
2308
+ if (!c.isSafePluginId(item.id)) {
2309
+ return { ok: false, message: `"${item.id}" is not a valid plugin id; refused.` };
2310
+ }
2311
+ const entryBody = entry.files?.[c.PLUGIN_ENTRY_FILE];
2312
+ if (typeof entryBody !== "string") {
2313
+ return { ok: false, message: `Registry entry is missing its ${c.PLUGIN_ENTRY_FILE}.` };
2314
+ }
2315
+ const root = c.pluginsRootDir(homeDir);
2316
+ if (!c.ensurePluginsRoot(root)) {
2317
+ return { ok: false, message: `Could not create the plugins root at ${root}.` };
2318
+ }
2319
+ const dir = join4(root, item.id);
2320
+ mkdirSync4(dir, { recursive: true, mode: c.PLUGIN_DIR_MODE });
2321
+ chmodSync(dir, c.PLUGIN_DIR_MODE);
2322
+ const manifestPath = join4(dir, c.PLUGIN_MANIFEST_FILE);
2323
+ writeFileSync4(manifestPath, `${JSON.stringify(entry.manifest, null, 2)}
2324
+ `, {
2325
+ mode: c.PLUGIN_FILE_MODE
2326
+ });
2327
+ chmodSync(manifestPath, c.PLUGIN_FILE_MODE);
2328
+ const entryPath = join4(dir, c.PLUGIN_ENTRY_FILE);
2329
+ writeFileSync4(entryPath, entryBody, { mode: c.PLUGIN_FILE_MODE });
2330
+ chmodSync(entryPath, c.PLUGIN_FILE_MODE);
2331
+ return {
2332
+ ok: true,
2333
+ message: `Installed ${item.id}. NOT enabled \u2014 select it again to enable it.`,
2334
+ state: "installed"
2335
+ };
2336
+ } catch (error) {
2337
+ return {
2338
+ ok: false,
2339
+ message: `Could not install "${item.id}": ${error instanceof Error ? error.message : String(error)}`
2340
+ };
2341
+ }
2342
+ }
2343
+ async function install(item) {
2344
+ return item.kind === "theme" ? installTheme(item) : installPlugin(item);
2345
+ }
2346
+ async function enable(item) {
2347
+ if (item.kind !== "plugin") {
2348
+ return { ok: false, message: "Only a plugin can be enabled.", capabilities: [] };
2349
+ }
2350
+ try {
2351
+ const c = await core();
2352
+ if (!c.isSafePluginId(item.id)) {
2353
+ return { ok: false, message: `"${item.id}" is not a valid plugin id; refused.`, capabilities: [] };
2354
+ }
2355
+ const root = c.pluginsRootDir(homeDir);
2356
+ const disc = c.readInstalledPlugin(
2357
+ root,
2358
+ item.id,
2359
+ reservedToolNames2 ? { reservedToolNames: reservedToolNames2 } : void 0
2360
+ );
2361
+ if (!disc.ok || !disc.plugin) {
2362
+ const why = disc.errors?.join("; ") ?? "not installed";
2363
+ return { ok: false, message: `Cannot enable ${item.id}: ${why}. Install it first.`, capabilities: [] };
2364
+ }
2365
+ const manifest = disc.plugin.manifest;
2366
+ const capabilities = c.aggregateCapabilities(manifest);
2367
+ const record = c.readEnablement(projectPath, homeDir);
2368
+ const result = c.enable(record, item.id, {
2369
+ version: manifest.version,
2370
+ capabilities,
2371
+ now: now()
2372
+ });
2373
+ if (!result.ok) {
2374
+ return { ok: false, message: `Cannot enable ${item.id}: ${result.error}`, capabilities: [] };
2375
+ }
2376
+ if (!c.writeEnablement(projectPath, result.record, homeDir)) {
2377
+ return {
2378
+ ok: false,
2379
+ message: `Could not persist the enablement approval for ${item.id}.`,
2380
+ capabilities: []
2381
+ };
2382
+ }
2383
+ const capText = capabilities.length > 0 ? capabilities.join(", ") : "no capabilities";
2384
+ return {
2385
+ ok: true,
2386
+ message: `Enabled ${item.id} for this project (approved: ${capText}). Select it again to run it.`,
2387
+ capabilities,
2388
+ state: "enabled"
2389
+ };
2390
+ } catch (error) {
2391
+ return {
2392
+ ok: false,
2393
+ message: `Could not enable "${item.id}": ${error instanceof Error ? error.message : String(error)}`,
2394
+ capabilities: []
2395
+ };
2396
+ }
2397
+ }
2398
+ async function loadEnabled(c, pluginId) {
2399
+ if (manager) {
2400
+ const result2 = await manager.runPlugin(pluginId);
2401
+ if (result2.ok) {
2402
+ const tools = result2.tools ?? [];
2403
+ const toolText = tools.length > 0 ? `tools: ${tools.join(", ")}` : "no tools";
2404
+ return { ok: true, message: `Loaded ${pluginId} (${toolText}).`, state: "enabled" };
2405
+ }
2406
+ return {
2407
+ ok: false,
2408
+ message: `Could not load ${pluginId}: ${result2.errors?.join("; ") ?? "unknown error"}`
2409
+ };
2410
+ }
2411
+ if (!host) {
2412
+ const root = c.pluginsRootDir(homeDir);
2413
+ const record = c.readEnablement(projectPath, homeDir);
2414
+ const loadable = c.loadableIds(c.reconcile(record, installedViews(c, root, c.listInstalledPluginIds(root))));
2415
+ host = deps.hostFactory ? deps.hostFactory({ homeDir, enabled: loadable, reservedToolNames: reservedToolNames2, coreVersion: deps.coreVersion }) : new c.PluginHost({ homeDir, enabled: loadable, reservedToolNames: reservedToolNames2, coreVersion: deps.coreVersion });
2416
+ }
2417
+ const result = await host.load(pluginId);
2418
+ if (result.ok) {
2419
+ const tools = result.tools ?? [];
2420
+ const toolText = tools.length > 0 ? `tools: ${tools.join(", ")}` : "no tools";
2421
+ return { ok: true, message: `Loaded ${pluginId} (${toolText}).`, state: "enabled" };
2422
+ }
2423
+ return { ok: false, message: `Could not load ${pluginId}: ${result.errors?.join("; ") ?? "unknown error"}` };
2424
+ }
2425
+ async function run(item) {
2426
+ if (item.kind !== "plugin") {
2427
+ return { ok: false, message: "Only a plugin can be run." };
2428
+ }
2429
+ try {
2430
+ const c = await core();
2431
+ const root = c.pluginsRootDir(homeDir);
2432
+ const record = c.readEnablement(projectPath, homeDir);
2433
+ const loadable = new Set(
2434
+ c.loadableIds(c.reconcile(record, installedViews(c, root, c.listInstalledPluginIds(root))))
2435
+ );
2436
+ if (!loadable.has(item.id)) {
2437
+ return {
2438
+ ok: false,
2439
+ message: `${item.id} is not enabled (or its capabilities changed since approval) \u2014 enable it first.`
2440
+ };
2441
+ }
2442
+ if (isTurnActive2()) {
2443
+ if (!deferred.includes(item.id)) deferred.push(item.id);
2444
+ return {
2445
+ ok: false,
2446
+ deferred: true,
2447
+ message: `A turn is in progress; loading ${item.id} is deferred to the next turn boundary.`
2448
+ };
2449
+ }
2450
+ return await loadEnabled(c, item.id);
2451
+ } catch (error) {
2452
+ return { ok: false, message: `Could not run "${item.id}": ${error instanceof Error ? error.message : String(error)}` };
2453
+ }
2454
+ }
2455
+ async function flushDeferred() {
2456
+ if (deferred.length === 0) return [];
2457
+ const ids = deferred.splice(0, deferred.length);
2458
+ const results = [];
2459
+ try {
2460
+ const c = await core();
2461
+ for (const id of ids) results.push(await loadEnabled(c, id));
2462
+ } catch (error) {
2463
+ for (const id of ids) {
2464
+ results.push({
2465
+ ok: false,
2466
+ message: `Could not load ${id}: ${error instanceof Error ? error.message : String(error)}`
2467
+ });
2468
+ }
2469
+ }
2470
+ return results;
2471
+ }
2472
+ async function activateTheme(item) {
2473
+ if (item.kind !== "theme") {
2474
+ return { ok: false, message: "Only a theme can be applied." };
2475
+ }
2476
+ if (!isSafeThemeId(item.id)) {
2477
+ return { ok: false, message: `"${item.id}" is not a valid theme id; refused.` };
2478
+ }
2479
+ try {
2480
+ reloadInstalledThemes(homeDir);
2481
+ } catch {
2482
+ }
2483
+ const applied = applyTheme(item.id);
2484
+ if (!applied) {
2485
+ return { ok: false, message: `Could not apply theme ${item.id}.` };
2486
+ }
2487
+ return { ok: true, message: `Applied theme ${item.id}.`, state: "active" };
2488
+ }
2489
+ return { fetchRegistry, list, install, enable, run, activateTheme, flushDeferred };
2490
+ }
2491
+
2492
+ // packages/cli/src/tui/dialog-select-layout.ts
2493
+ var NO_MATCH = Number.POSITIVE_INFINITY;
2494
+
2495
+ // packages/cli/src/tui/settings-layout.ts
2496
+ var DIALOG_HOST_FOOTER_ROWS = 1;
2497
+ var SETTINGS_DIALOG_HOST_ROWS = DIALOG_HOST_FOOTER_ROWS + 1;
2498
+
2499
+ // packages/cli/src/tui/market-layout.ts
2500
+ function signatureOf(state) {
2501
+ return state === "verified" ? "verified" : "unverified";
2502
+ }
2503
+ function nonEmpty(value) {
2504
+ return typeof value === "string" && value.trim().length > 0;
2505
+ }
2506
+ function pluginDescription(entry) {
2507
+ const tools = Array.isArray(entry.manifest?.tools) ? entry.manifest?.tools ?? [] : [];
2508
+ const named = tools.map((tool) => nonEmpty(tool?.name) ? tool.name.trim() : "").filter(Boolean);
2509
+ if (named.length === 0) return "Tool plugin.";
2510
+ const count = named.length;
2511
+ return `${count} tool${count === 1 ? "" : "s"}: ${named.join(", ")}`;
2512
+ }
2513
+ function buildMarketItems(view) {
2514
+ const items = [];
2515
+ if (!view || typeof view !== "object") return items;
2516
+ for (const entry of view.entries ?? []) {
2517
+ if (!entry || typeof entry.id !== "string" || entry.id.length === 0) continue;
2518
+ const version = typeof entry.version === "string" ? entry.version : "";
2519
+ items.push({
2520
+ kind: "plugin",
2521
+ id: entry.id,
2522
+ name: nonEmpty(entry.manifest?.name) ? entry.manifest.name.trim() : entry.id,
2523
+ version,
2524
+ description: sanitizeTuiText(pluginDescription(entry)),
2525
+ capabilities: Array.isArray(entry.capabilities) ? entry.capabilities.filter((cap) => nonEmpty(cap)) : [],
2526
+ signature: signatureOf(entry.signatureState),
2527
+ raw: entry
2528
+ });
2529
+ }
2530
+ for (const artifact of view.artifacts ?? []) {
2531
+ if (!artifact || artifact.kind !== "theme") continue;
2532
+ if (typeof artifact.id !== "string" || artifact.id.length === 0) continue;
2533
+ const theme = artifact.manifest?.theme;
2534
+ const version = typeof artifact.version === "string" ? artifact.version : "";
2535
+ const name = nonEmpty(theme?.label) ? theme.label.trim() : nonEmpty(artifact.manifest?.name) ? artifact.manifest.name.trim() : artifact.id;
2536
+ items.push({
2537
+ kind: "theme",
2538
+ id: artifact.id,
2539
+ name,
2540
+ version,
2541
+ description: sanitizeTuiText(nonEmpty(theme?.description) ? theme.description : "Colour theme."),
2542
+ capabilities: [],
2543
+ signature: signatureOf(artifact.signatureState),
2544
+ raw: artifact
2545
+ });
2546
+ }
2547
+ return items;
2548
+ }
2549
+
2550
+ // packages/cli/src/tui/session-plugin-host.ts
2551
+ function coreLoader2(injected) {
2552
+ if (typeof injected === "function") return injected;
2553
+ if (injected) return async () => injected;
2554
+ let cached;
2555
+ return () => {
2556
+ if (!cached) cached = import("./dist-ONIRKDH6.js");
2557
+ return cached;
2558
+ };
2559
+ }
2560
+ async function createSessionPluginHostManager(deps = {}) {
2561
+ const getCore = coreLoader2(deps.core);
2562
+ const homeDir = deps.homeDir;
2563
+ const projectPath = deps.projectPath ?? process.cwd();
2564
+ const reservedToolNames2 = deps.reservedToolNames;
2565
+ const coreVersion = deps.coreVersion;
2566
+ const listeners = /* @__PURE__ */ new Set();
2567
+ let host;
2568
+ let loaded = /* @__PURE__ */ new Map();
2569
+ let enabledKey = "";
2570
+ const leases = /* @__PURE__ */ new Map();
2571
+ let disposed = false;
2572
+ let refreshTail = Promise.resolve();
2573
+ function computeLoadable(c) {
2574
+ const root = c.pluginsRootDir(homeDir);
2575
+ const ids = c.listInstalledPluginIds(root);
2576
+ const views = [];
2577
+ for (const id of ids) {
2578
+ let disc;
2579
+ try {
2580
+ disc = c.readInstalledPlugin(
2581
+ root,
2582
+ id,
2583
+ reservedToolNames2 ? { reservedToolNames: reservedToolNames2 } : void 0
2584
+ );
2585
+ } catch {
2586
+ continue;
2587
+ }
2588
+ if (!disc.ok || !disc.plugin) continue;
2589
+ views.push({
2590
+ id,
2591
+ version: disc.plugin.manifest.version,
2592
+ capabilities: c.aggregateCapabilities(disc.plugin.manifest)
2593
+ });
2594
+ }
2595
+ const record = c.readEnablement(projectPath, homeDir);
2596
+ return c.loadableIds(c.reconcile(record, views)).slice().sort();
2597
+ }
2598
+ function buildHost(c, enabled) {
2599
+ return deps.hostFactory ? deps.hostFactory({ homeDir, enabled, reservedToolNames: reservedToolNames2, coreVersion }) : new c.PluginHost({ homeDir, enabled, reservedToolNames: reservedToolNames2, coreVersion });
2600
+ }
2601
+ async function loadAll(into, enabled, into_loaded) {
2602
+ for (const id of enabled) {
2603
+ try {
2604
+ const r = await into.load(id);
2605
+ if (r.ok) into_loaded.set(id, r.tools ?? []);
2606
+ } catch {
2607
+ }
2608
+ }
2609
+ }
2610
+ async function reconstruct(c, enabled, emit) {
2611
+ const next = buildHost(c, enabled);
2612
+ const nextLoaded = /* @__PURE__ */ new Map();
2613
+ await loadAll(next, enabled, nextLoaded);
2614
+ if (disposed) {
2615
+ next.shutdown?.();
2616
+ throw new Error("Marketplace host manager is closed");
2617
+ }
2618
+ const old = host;
2619
+ host = next;
2620
+ loaded = nextLoaded;
2621
+ enabledKey = enabled.slice().sort().join("\n");
2622
+ if (old && !leases.has(old)) {
2623
+ try {
2624
+ old.shutdown?.();
2625
+ } catch {
2626
+ }
2627
+ }
2628
+ if (emit) {
2629
+ const swapped = host;
2630
+ for (const listener of [...listeners]) {
2631
+ try {
2632
+ listener(swapped);
2633
+ } catch {
2634
+ }
2635
+ }
2636
+ }
2637
+ }
2638
+ async function refresh() {
2639
+ if (disposed) throw new Error("Marketplace host manager is closed");
2640
+ const operation = refreshTail.then(async () => {
2641
+ if (disposed) throw new Error("Marketplace host manager is closed");
2642
+ const c = await getCore();
2643
+ if (disposed) throw new Error("Marketplace host manager is closed");
2644
+ const enabled = computeLoadable(c);
2645
+ const key = enabled.join("\n");
2646
+ if (host && key === enabledKey && (!leases.has(host) || enabled.every((id) => loaded.has(id)))) {
2647
+ for (const id of enabled) {
2648
+ if (loaded.has(id)) continue;
2649
+ try {
2650
+ const r = await host.load(id);
2651
+ if (r.ok) loaded.set(id, r.tools ?? []);
2652
+ } catch {
2653
+ }
2654
+ }
2655
+ return;
2656
+ }
2657
+ await reconstruct(
2658
+ c,
2659
+ enabled,
2660
+ /* emit */
2661
+ host !== void 0
2662
+ );
2663
+ });
2664
+ refreshTail = operation.catch(() => {
2665
+ });
2666
+ return operation;
2667
+ }
2668
+ async function runPlugin(pluginId) {
2669
+ await refresh();
2670
+ const tools = loaded.get(pluginId);
2671
+ if (tools) return { ok: true, pluginId, tools };
2672
+ return {
2673
+ ok: false,
2674
+ pluginId,
2675
+ errors: [
2676
+ `plugin "${pluginId}" is not loaded; it may be uninstalled, not enabled, or its capabilities changed since approval`
2677
+ ]
2678
+ };
2679
+ }
2680
+ function onChanged(listener) {
2681
+ listeners.add(listener);
2682
+ return () => listeners.delete(listener);
2683
+ }
2684
+ function current() {
2685
+ if (disposed || !host) throw new Error("Marketplace host manager is closed");
2686
+ return host;
2687
+ }
2688
+ function acquire() {
2689
+ const owned = current();
2690
+ const pinned = host;
2691
+ leases.set(pinned, (leases.get(pinned) ?? 0) + 1);
2692
+ let released = false;
2693
+ return {
2694
+ host: owned,
2695
+ release() {
2696
+ if (released) return;
2697
+ released = true;
2698
+ const count = (leases.get(pinned) ?? 1) - 1;
2699
+ if (count > 0) {
2700
+ leases.set(pinned, count);
2701
+ return;
2702
+ }
2703
+ leases.delete(pinned);
2704
+ if (pinned !== host || disposed) pinned.shutdown?.();
2705
+ }
2706
+ };
2707
+ }
2708
+ function dispose() {
2709
+ if (disposed) return;
2710
+ disposed = true;
2711
+ listeners.clear();
2712
+ const old = host;
2713
+ host = void 0;
2714
+ loaded = /* @__PURE__ */ new Map();
2715
+ enabledKey = "";
2716
+ if (old && !leases.has(old)) {
2717
+ try {
2718
+ old.shutdown?.();
2719
+ } catch {
2720
+ }
2721
+ }
2722
+ }
2723
+ {
2724
+ const c = await getCore();
2725
+ await reconstruct(
2726
+ c,
2727
+ computeLoadable(c),
2728
+ /* emit */
2729
+ false
2730
+ );
2731
+ }
2732
+ return { current, acquire, refresh, runPlugin, onChanged, dispose };
2733
+ }
2734
+
2735
+ // packages/cli/src/web/chatgpt-plan-controller.ts
2736
+ var ChatGptPlanAuthController = class {
2737
+ #options;
2738
+ #abort;
2739
+ #epoch = 0;
2740
+ #status = { phase: "idle", message: "Connect your ChatGPT account.", lines: [], verificationUrl: null, userCode: null, available: true };
2741
+ constructor(options = {}) {
2742
+ this.#options = options;
2743
+ }
2744
+ status() {
2745
+ if (this.#status.phase !== "running" && this.#status.phase !== "failed" && this.#status.phase !== "cancelled") {
2746
+ const active = (this.#options.list ?? listChatGptPlanProfiles)(this.#options.homeDir).find((p) => p.active && p.status === "connected");
2747
+ if (active) return { ...this.#status, phase: "connected", message: active.sharing ? "ChatGPT plan sharing is connected." : "ChatGPT identity is connected. Grant plan usage to use models.", lines: [], verificationUrl: null };
2748
+ }
2749
+ return { ...this.#status, lines: [...this.#status.lines] };
2750
+ }
2751
+ start(profileId) {
2752
+ if (this.#abort) return this.status();
2753
+ const epoch2 = ++this.#epoch, abort = new AbortController();
2754
+ this.#abort = abort;
2755
+ this.#status = { ...this.#status, phase: "running", message: "Starting ChatGPT sign-in.", verificationUrl: null, lines: [] };
2756
+ void Promise.resolve().then(() => {
2757
+ abort.signal.throwIfAborted();
2758
+ return (this.#options.signIn ?? signInChatGptPlan)({
2759
+ homeDir: this.#options.homeDir,
2760
+ profileId,
2761
+ signal: abort.signal,
2762
+ onAuthorize: (value) => {
2763
+ if (epoch2 !== this.#epoch || abort.signal.aborted) return;
2764
+ const url = new URL(value);
2765
+ if (url.protocol !== "https:" || url.hostname !== "auth.openai.com" || url.port || url.username || url.password || url.hash || ["access_token", "refresh_token", "id_token", "id_token_hint", "api_key"].some((key) => url.searchParams.has(key))) throw new Error("Unsafe authorization destination.");
2766
+ this.#status = { ...this.#status, message: "Continue in your browser to connect ChatGPT.", verificationUrl: url.href };
2767
+ }
2768
+ });
2769
+ }).then(() => {
2770
+ if (epoch2 !== this.#epoch || abort.signal.aborted) return;
2771
+ this.#status = { ...this.#status, phase: "connected", verificationUrl: null, message: "ChatGPT sign-in completed." };
2772
+ }, () => {
2773
+ if (epoch2 !== this.#epoch || abort.signal.aborted) return;
2774
+ this.#status = { ...this.#status, phase: "failed", verificationUrl: null, message: "ChatGPT sign-in failed. Retry the connection." };
2775
+ }).finally(() => {
2776
+ if (epoch2 === this.#epoch) this.#abort = void 0;
2777
+ });
2778
+ return this.status();
2779
+ }
2780
+ cancel() {
2781
+ ++this.#epoch;
2782
+ this.#abort?.abort();
2783
+ this.#abort = void 0;
2784
+ this.#status = { ...this.#status, phase: "cancelled", message: "ChatGPT sign-in cancelled.", verificationUrl: null, lines: [] };
2785
+ return this.status();
2786
+ }
2787
+ };
2788
+
2789
+ // packages/cli/src/web/codex-auth-controller.ts
2790
+ import { spawnSync as spawnSync2 } from "node:child_process";
2791
+
2792
+ // packages/cli/src/tui/codex-device-auth.ts
2793
+ import { spawn as spawn2, spawnSync } from "node:child_process";
2794
+ var MAX_VISIBLE_LINES2 = 8;
2795
+ var CODEX_UNAVAILABLE_MESSAGE = "Codex CLI is not available on this console's PATH. Install Codex, or add its directory to PATH and restart 0.";
2796
+ function defaultSpawnCodexDeviceAuth(command, args, options) {
2797
+ const child = spawn2(command, args, {
2798
+ env: options.env,
2799
+ stdio: ["ignore", "pipe", "pipe"]
2800
+ });
2801
+ if (!child.stdout || !child.stderr) {
2802
+ child.kill("SIGTERM");
2803
+ throw new Error("Codex device OAuth did not expose output streams.");
2804
+ }
2805
+ return child;
2806
+ }
2807
+ function defaultProbeCodexExecutable(env) {
2808
+ const result = spawnSync("codex", ["--version"], { env, stdio: "ignore" });
2809
+ return result.error?.code !== "ENOENT";
2810
+ }
2811
+ function isMissingCodexExecutable(error) {
2812
+ return error?.code === "ENOENT";
2813
+ }
2814
+ function startCodexDeviceAuth(options) {
2815
+ const env = options.env ?? process.env;
2816
+ if (!(options.probe ?? defaultProbeCodexExecutable)(env)) {
2817
+ options.onUpdate({
2818
+ phase: "unavailable",
2819
+ lines: [],
2820
+ message: CODEX_UNAVAILABLE_MESSAGE
2821
+ });
2822
+ return { cancel: () => {
2823
+ } };
2824
+ }
2825
+ const launch = options.spawn ?? defaultSpawnCodexDeviceAuth;
2826
+ const openBrowser = options.openBrowser ?? defaultOpenBrowser;
2827
+ const lines = [];
2828
+ let pending = "";
2829
+ let settled = false;
2830
+ let cancelled = false;
2831
+ let browserOpened = false;
2832
+ const publish = (phase, message2) => {
2833
+ options.onUpdate({ phase, lines: [...lines], message: message2 });
2834
+ };
2835
+ const tryOpenBrowser = (text2) => {
2836
+ if (browserOpened) return;
2837
+ const rawUrl = text2.match(/https:\/\/auth\.openai\.com\/codex\/device[^\s\x1b]*/)?.[0];
2838
+ if (!rawUrl) return;
2839
+ const url = rawUrl.replace(/[),.;]+$/, "");
2840
+ browserOpened = true;
2841
+ void Promise.resolve(openBrowser(url)).catch(() => {
2842
+ if (settled) return;
2843
+ lines.push("Could not open a browser automatically; open the URL above.");
2844
+ if (lines.length > MAX_VISIBLE_LINES2) lines.shift();
2845
+ publish("running", "Complete the ChatGPT Codex device sign-in in your browser.");
2846
+ });
2847
+ };
2848
+ const pushOutput = (chunk) => {
2849
+ if (settled) return;
2850
+ const text2 = chunk.toString("utf8");
2851
+ tryOpenBrowser(text2);
2852
+ const raw = `${pending}${text2}`;
2853
+ const parts = raw.split(/\r?\n/);
2854
+ pending = parts.pop() ?? "";
2855
+ for (const line of parts) {
2856
+ const value = sanitizeTuiText(line);
2857
+ if (value.length === 0) continue;
2858
+ lines.push(value);
2859
+ if (lines.length > MAX_VISIBLE_LINES2) lines.shift();
2860
+ tryOpenBrowser(value);
2861
+ }
2862
+ publish("running", "Complete the ChatGPT Codex device sign-in in your browser.");
2863
+ };
2864
+ const finish = (phase, message2) => {
2865
+ if (settled) return;
2866
+ settled = true;
2867
+ if (pending.trim().length > 0) {
2868
+ lines.push(pending.trim());
2869
+ if (lines.length > MAX_VISIBLE_LINES2) lines.shift();
2870
+ }
2871
+ publish(phase, message2);
2872
+ };
2873
+ let child;
2874
+ try {
2875
+ child = launch("codex", ["login", "--device-auth"], { env });
2876
+ } catch (error) {
2877
+ finish(
2878
+ isMissingCodexExecutable(error) ? "unavailable" : "failed",
2879
+ isMissingCodexExecutable(error) ? CODEX_UNAVAILABLE_MESSAGE : error instanceof Error ? error.message : String(error)
2880
+ );
2881
+ return { cancel: () => {
2882
+ } };
2883
+ }
2884
+ child.stdout.on("data", pushOutput);
2885
+ child.stderr.on("data", pushOutput);
2886
+ child.on("error", (error) => {
2887
+ finish(
2888
+ isMissingCodexExecutable(error) ? "unavailable" : "failed",
2889
+ isMissingCodexExecutable(error) ? CODEX_UNAVAILABLE_MESSAGE : error.message
2890
+ );
2891
+ });
2892
+ child.on("close", (code) => {
2893
+ if (settled) return;
2894
+ if (cancelled) {
2895
+ finish("cancelled", "Codex device sign-in cancelled.");
2896
+ return;
2897
+ }
2898
+ if (code !== 0) {
2899
+ finish("failed", `Codex device sign-in exited with code ${code ?? "unknown"}.`);
2900
+ return;
2901
+ }
2902
+ maybeLoadCodexAuth({ env, home: options.homeDir, force: true });
2903
+ if (!env["ZERO_CHATGPT_ACCESS_TOKEN"] && !env["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"]) {
2904
+ finish("failed", "Codex completed without a readable ChatGPT subscription credential.");
2905
+ return;
2906
+ }
2907
+ finish("connected", "ChatGPT Codex subscription connected.");
2908
+ options.onConnected();
2909
+ });
2910
+ publish("running", "Starting ChatGPT Codex device sign-in\u2026");
2911
+ return {
2912
+ cancel: () => {
2913
+ if (settled || cancelled) return;
2914
+ cancelled = true;
2915
+ child.kill("SIGTERM");
2916
+ }
2917
+ };
2918
+ }
2919
+
2920
+ // packages/cli/src/web/codex-auth-controller.ts
2921
+ function webAuthStatus(status, available = true) {
2922
+ const text2 = status.lines.join("\n");
2923
+ const candidate = text2.match(/https:\/\/[^\s<>"\x1b]+/)?.[0]?.replace(/[),.;]+$/, "");
2924
+ let verificationUrl = null;
2925
+ if (candidate) {
2926
+ try {
2927
+ const url = new URL(candidate);
2928
+ const allowedHost = [
2929
+ "auth.openai.com",
2930
+ "x.ai",
2931
+ "kimi.com",
2932
+ "github.com",
2933
+ "openrouter.ai",
2934
+ "accounts.google.com"
2935
+ ].includes(url.hostname) || url.hostname.endsWith(".kimi.com") || url.hostname.endsWith(".x.ai");
2936
+ const containsCredential = ["access_token", "refresh_token", "id_token", "api_key"].some((key) => url.searchParams.has(key));
2937
+ if (!url.username && !url.password && allowedHost && !containsCredential) verificationUrl = url.href;
2938
+ } catch {
2939
+ }
2940
+ }
2941
+ const userCode = text2.match(/\b[A-Z0-9]{4,8}-[A-Z0-9]{4,8}\b/)?.[0] ?? text2.match(/(?:code[:\s]+)([A-Z0-9]{4,12})\b/i)?.[1] ?? null;
2942
+ return { ...status, lines: [...status.lines], verificationUrl, userCode, available };
2943
+ }
2944
+ var CodexAuthController = class {
2945
+ #start;
2946
+ #env;
2947
+ #homeDir;
2948
+ #probe;
2949
+ #status = { phase: "idle", message: "ChatGPT Codex is not connected.", lines: [] };
2950
+ #session = null;
2951
+ constructor(options = {}) {
2952
+ this.#start = options.start ?? startCodexDeviceAuth;
2953
+ this.#env = { ...options.env ?? process.env };
2954
+ this.#homeDir = options.homeDir;
2955
+ this.#probe = options.probe ?? ((env) => {
2956
+ const result = spawnSync2("codex", ["--version"], { env, stdio: "ignore", timeout: 5e3 });
2957
+ return !result.error && result.status === 0;
2958
+ });
2959
+ }
2960
+ status() {
2961
+ if (this.#status.phase === "running") return webAuthStatus(this.#status);
2962
+ const env = { ...this.#env };
2963
+ maybeLoadCodexAuth({ env, home: this.#homeDir, force: true });
2964
+ const connected = Boolean(env.ZERO_CHATGPT_ACCESS_TOKEN?.trim() || env.ZERO_CHATGPT_OAUTH_REFRESH_TOKEN?.trim());
2965
+ const available = this.#probe(env);
2966
+ if (connected) return webAuthStatus({
2967
+ phase: "connected",
2968
+ message: "ChatGPT Codex subscription credentials are configured.",
2969
+ lines: []
2970
+ }, available);
2971
+ if (!available) return webAuthStatus({
2972
+ phase: "unavailable",
2973
+ message: "Official Codex sign-in is unavailable because the Codex executable is not installed or cannot run. You can connect a supported API provider in this browser instead.",
2974
+ lines: []
2975
+ }, false);
2976
+ return webAuthStatus(this.#status, true);
2977
+ }
2978
+ start() {
2979
+ if (this.#status.phase === "running") return this.status();
2980
+ this.#session = this.#start({
2981
+ env: this.#env,
2982
+ homeDir: this.#homeDir,
2983
+ probe: this.#probe,
2984
+ openBrowser: () => void 0,
2985
+ onUpdate: (update) => this.#apply(update),
2986
+ onConnected: () => void 0
2987
+ });
2988
+ return webAuthStatus(this.#status, this.#status.phase !== "unavailable");
2989
+ }
2990
+ cancel() {
2991
+ this.#session?.cancel();
2992
+ return this.status();
2993
+ }
2994
+ #apply(update) {
2995
+ this.#status = {
2996
+ phase: update.phase,
2997
+ message: update.phase === "unavailable" ? "Official Codex browser sign-in is unavailable. Connect a supported API provider in this browser instead." : update.message,
2998
+ lines: [...update.lines]
2999
+ };
3000
+ if (update.phase !== "running") this.#session = null;
3001
+ }
3002
+ };
3003
+
3004
+ // packages/cli/src/web/workspace-directories.ts
3005
+ import { opendir, realpath, stat } from "node:fs/promises";
3006
+ import { homedir } from "node:os";
3007
+ import { dirname as dirname2, join as join5, resolve } from "node:path";
3008
+ var MAX_FOLDERS = 200;
3009
+ var MAX_SCANNED_ENTRIES = 2e3;
3010
+ async function listWorkspaceDirectories(input) {
3011
+ if (input !== void 0 && (typeof input !== "string" || input.length > 4096 || input.includes("\0"))) throw new Error("Enter a valid folder path.");
3012
+ const homePath = await realpath(homedir()).catch(() => resolve(homedir()));
3013
+ let path;
3014
+ try {
3015
+ path = await realpath(typeof input === "string" && input.trim() ? resolve(input.trim()) : homePath);
3016
+ } catch {
3017
+ throw new Error("That folder could not be found on this host.");
3018
+ }
3019
+ if (!(await stat(path)).isDirectory()) throw new Error("Choose a folder rather than a file.");
3020
+ let directory;
3021
+ try {
3022
+ directory = await opendir(path);
3023
+ } catch {
3024
+ throw new Error("This host cannot open that folder. Check its permissions or enter another path.");
3025
+ }
3026
+ const entries = [];
3027
+ let scanned = 0;
3028
+ let truncated = false;
3029
+ for await (const entry of directory) {
3030
+ if (++scanned > MAX_SCANNED_ENTRIES) {
3031
+ truncated = true;
3032
+ break;
3033
+ }
3034
+ if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
3035
+ try {
3036
+ const canonical = await realpath(join5(path, entry.name));
3037
+ if (!(await stat(canonical)).isDirectory()) continue;
3038
+ if (entries.length >= MAX_FOLDERS) {
3039
+ truncated = true;
3040
+ break;
3041
+ }
3042
+ entries.push({ name: entry.name, path: canonical });
3043
+ } catch {
3044
+ }
3045
+ }
3046
+ entries.sort((a, b) => a.name.localeCompare(b.name, void 0, { numeric: true, sensitivity: "base" }));
3047
+ const parent = dirname2(path);
3048
+ return { path, parentPath: parent === path ? null : parent, homePath, entries, truncated };
3049
+ }
3050
+
3051
+ // packages/cli/src/web/workspace-folder-picker.ts
3052
+ import { execFile } from "node:child_process";
3053
+ import { realpath as realpath2, stat as stat2 } from "node:fs/promises";
3054
+ import { resolve as resolve2 } from "node:path";
3055
+ import { promisify } from "node:util";
3056
+ var execute = promisify(execFile);
3057
+ var PICKER_SCRIPT = `on run argv
3058
+ activate
3059
+ try
3060
+ if (count of argv) > 0 then
3061
+ set chosen to choose folder with prompt "Choose the folder where Zero works" default location (POSIX file (item 1 of argv))
3062
+ else
3063
+ set chosen to choose folder with prompt "Choose the folder where Zero works"
3064
+ end if
3065
+ return POSIX path of chosen
3066
+ on error number -128
3067
+ return ""
3068
+ end try
3069
+ end run`;
3070
+ var pickerActive = false;
3071
+ async function chooseWorkspaceFolder(input, dependencies = {}) {
3072
+ if (input !== void 0 && (typeof input !== "string" || input.length > 4096 || input.includes("\0"))) throw new Error("Enter a valid folder path.");
3073
+ if ((dependencies.platform ?? process.platform) !== "darwin") return { supported: false, path: null };
3074
+ if (pickerActive) throw new Error("A folder chooser is already open on this host.");
3075
+ pickerActive = true;
3076
+ try {
3077
+ const args = ["-e", PICKER_SCRIPT];
3078
+ if (typeof input === "string" && input.trim()) {
3079
+ const initial = await realpath2(resolve2(input));
3080
+ if (!(await stat2(initial)).isDirectory()) throw new Error("Choose a folder rather than a file.");
3081
+ args.push(initial);
3082
+ }
3083
+ let stdout;
3084
+ try {
3085
+ ({ stdout } = await (dependencies.run ?? execute)("/usr/bin/osascript", args, { encoding: "utf8", timeout: 12e4, maxBuffer: 16384, windowsHide: true }));
3086
+ } catch {
3087
+ throw new Error("The folder chooser could not complete on this host. Try again or enter a folder path.");
3088
+ }
3089
+ const selected = stdout.replace(/\r?\n$/, "");
3090
+ if (!selected) return { supported: true, path: null };
3091
+ if (selected.length > 4096 || selected.includes("\0")) throw new Error("The folder chooser returned an invalid path.");
3092
+ const path = await realpath2(selected);
3093
+ if (!(await stat2(path)).isDirectory()) throw new Error("The folder chooser did not return an existing folder.");
3094
+ return { supported: true, path };
3095
+ } finally {
3096
+ pickerActive = false;
3097
+ }
3098
+ }
3099
+
3100
+ // packages/cli/src/web/operator-services.ts
3101
+ var MODEL_ROLES = ["discovery", "attack", "verify", "report", "audit", "review"];
3102
+ var reservedToolNames = Object.values(TOOL_DEFINITIONS).map((tool) => tool.name);
3103
+ var runtimeEnvironments = /* @__PURE__ */ new WeakMap();
3104
+ function assertPlanAllowed(providerId, policy) {
3105
+ if (providerId === "chatgpt-plan" && policy.allowChatGptPlan === false) throw new OperatorError(403, "local_only", "Native ChatGPT plan connections are available only in the local open-source application.");
3106
+ }
3107
+ var runtimeContextLimits = /* @__PURE__ */ new WeakMap();
3108
+ var pluginManager;
3109
+ var pluginManagerPromise;
3110
+ var isTurnActive = () => false;
3111
+ var deferredPlugins = /* @__PURE__ */ new Set();
3112
+ async function getWebConsolePluginHostManager() {
3113
+ if (!pluginManagerPromise) {
3114
+ pluginManagerPromise = createSessionPluginHostManager({ reservedToolNames, coreVersion: VERSION }).then((manager2) => {
3115
+ pluginManager = manager2;
3116
+ return manager2;
3117
+ }).catch((error) => {
3118
+ pluginManagerPromise = void 0;
3119
+ throw error;
3120
+ });
3121
+ }
3122
+ const manager = await pluginManagerPromise;
3123
+ await manager.refresh();
3124
+ return manager;
3125
+ }
3126
+ var pluginService = createPluginService({
3127
+ registryUrl: (process.env.ZERO_REGISTRY_URL ?? DEFAULT_REGISTRY_URL).trim(),
3128
+ reservedToolNames,
3129
+ coreVersion: VERSION,
3130
+ isTurnActive: () => isTurnActive(),
3131
+ pluginHostManager: {
3132
+ refresh: async () => {
3133
+ await (await getWebConsolePluginHostManager()).refresh();
3134
+ },
3135
+ runPlugin: async (id) => (await getWebConsolePluginHostManager()).runPlugin(id)
3136
+ }
3137
+ });
3138
+ async function flushWebConsolePlugins() {
3139
+ if (consoleExecutionProfile() === "smolvm" || isTurnActive()) return [];
3140
+ const results = await pluginService.flushDeferred();
3141
+ deferredPlugins.clear();
3142
+ return results;
3143
+ }
3144
+ function webRuntimeEnv() {
3145
+ const env = { ...process.env };
3146
+ Object.assign(env, connectionConfigEnvPatch(env), credentialEnvPatch(loadCredentials(), env), accountEnvPatch(loadAccountStore(), env));
3147
+ maybeLoadCodexAuth({ env });
3148
+ return Object.fromEntries(Object.entries(env).filter((entry) => entry[1] !== void 0));
3149
+ }
3150
+ function publicMessage(error) {
3151
+ let message2 = error instanceof Error ? error.message : String(error);
3152
+ const secrets = /* @__PURE__ */ new Set();
3153
+ for (const provider2 of PROVIDERS) for (const variable of provider2.envVars) {
3154
+ const value = process.env[variable];
3155
+ if (value) secrets.add(value);
3156
+ }
3157
+ for (const accounts of Object.values(loadAccountStore().providers)) for (const record of Object.values(accounts.accounts)) {
3158
+ if (record.kind === "api_key") secrets.add(record.secret);
3159
+ else for (const token of [record.tokens.accessToken, record.tokens.refreshToken]) if (token) secrets.add(token);
3160
+ }
3161
+ const env = { ...process.env };
3162
+ maybeLoadCodexAuth({ env });
3163
+ for (const variable of PROVIDERS.find((provider2) => provider2.id === "chatgpt-codex").envVars) if (env[variable]) secrets.add(env[variable]);
3164
+ for (const secret of secrets) if (secret) message2 = message2.split(secret).join("[redacted]");
3165
+ return message2.replace(/(https?:\/\/)[^\s/@]+:[^\s/@]+@/g, "$1[redacted]@").replace(/([?&](?:api[_-]?key|access_token|refresh_token|id_token|token|secret|password)=)[^&\s"'<>]+/gi, "$1[redacted]").slice(0, 4e3);
3166
+ }
3167
+ function runtimeDiagnostics(runtime) {
3168
+ const diagnostics = runtime.getConfigurationDiagnostics();
3169
+ return {
3170
+ valid: diagnostics.valid,
3171
+ reason: diagnostics.reason ?? null,
3172
+ message: diagnostics.fatalError ? publicMessage(diagnostics.fatalError) : null
3173
+ };
3174
+ }
3175
+ function connectionProbeRuntime(providerId, env) {
3176
+ return new LlmApiRuntime({
3177
+ type: "api",
3178
+ timeout: 3e5,
3179
+ provider: providerId,
3180
+ env,
3181
+ // OpenAI has no default model. Like accessibleProviders(), use an explicit
3182
+ // sentinel solely for auth/transport inspection. Azure must still validate
3183
+ // its real deployment configuration; the probe cannot supply that for it.
3184
+ ...providerId !== "azure" ? { model: "probe" } : {}
3185
+ });
3186
+ }
3187
+ function describeWebConsoleRuntime(runtime) {
3188
+ const providerId = runtime.resolvedProvider?.() ?? "unknown";
3189
+ const model = runtime.resolvedModel?.() ?? "unknown";
3190
+ const api = runtime instanceof LlmApiRuntime ? runtime : void 0;
3191
+ const diagnostics = api ? runtimeDiagnostics(api) : { valid: true, reason: null, message: null };
3192
+ return {
3193
+ providerId,
3194
+ providerLabel: PROVIDERS.find((provider2) => provider2.id === providerId)?.label ?? providerId,
3195
+ model,
3196
+ configured: diagnostics.valid,
3197
+ reasoning: api?.reasoningConfiguration() ?? null,
3198
+ connectionIdentity: api?.connectionIdentity() ?? null,
3199
+ diagnostics,
3200
+ ...runtime.modelSelection?.() ?? { agentModels: {}, singleModel: false, autoRoute: false },
3201
+ contextWindowTokens: (api ? runtimeContextLimits.get(api) : void 0) ?? resolveContextLimit({ modelId: model, providerId })?.tokens ?? null
3202
+ };
3203
+ }
3204
+ function savedWebRuntimeSelection(selection, info) {
3205
+ const { reasoningEffort: selectedEffort, ...stored } = selection;
3206
+ const effort = info ? info.reasoning?.effort : selectedEffort;
3207
+ const reasoning = effort && ["none", "low", "medium", "high", "xhigh", "max"].includes(effort) ? { reasoningEffort: effort } : {};
3208
+ if (!info) return { ...stored, ...reasoning };
3209
+ return {
3210
+ ...stored,
3211
+ providerId: info.providerId,
3212
+ model: info.model,
3213
+ agentModels: info.agentModels,
3214
+ singleModel: info.singleModel,
3215
+ autoRoute: info.autoRoute,
3216
+ ...reasoning
3217
+ };
3218
+ }
3219
+ function validateSelection(selection) {
3220
+ if (selection.providerId !== void 0 && !PROVIDERS.some((provider2) => provider2.id === selection.providerId)) throw new OperatorError(400, "invalid_provider", "Unsupported provider.");
3221
+ for (const value of [selection.model, ...Object.values(selection.agentModels ?? {})]) {
3222
+ if (value !== void 0 && (typeof value !== "string" || !value || value.length > 256 || /[\s\x00-\x1f\x7f]/.test(value))) throw new OperatorError(400, "invalid_model", "Model identifiers must be non-empty and contain no whitespace.");
3223
+ }
3224
+ if (selection.reasoningEffort !== void 0 && !["none", "low", "medium", "high", "xhigh", "max"].includes(selection.reasoningEffort)) throw new OperatorError(400, "invalid_reasoning_effort", "Choose an available thinking effort.");
3225
+ for (const key of Object.keys(selection.agentModels ?? {})) if (!/^[a-z][a-z0-9_-]{0,63}$/.test(key)) throw new OperatorError(400, "invalid_role", "Invalid model role.");
3226
+ }
3227
+ async function validateRuntimeModels(runtime) {
3228
+ const diagnostics = runtime.getConfigurationDiagnostics();
3229
+ if (!diagnostics.valid) throw new OperatorError(409, "provider_not_ready", publicMessage(diagnostics.fatalError ?? "Connect the selected provider first."));
3230
+ if (diagnostics.provider === "chatgpt-codex") {
3231
+ let models;
3232
+ try {
3233
+ models = await runtime.codexModelCatalog(AbortSignal.timeout(1e4));
3234
+ } catch (error) {
3235
+ if (error instanceof CodexCatalogRefreshError) models = [...error.cachedModels];
3236
+ else if (/Codex model discovery failed \(HTTP 401\)/.test(error instanceof Error ? error.message : String(error))) throw new OperatorError(409, "connection_expired", "Your ChatGPT connection has expired or was rejected. Sign in again in Connections, then retry.");
3237
+ else throw error;
3238
+ }
3239
+ const selected = models.find((model) => model.id === runtime.resolvedModel());
3240
+ if (!selected) throw new OperatorError(409, "model_not_available", "The selected model is not available to this ChatGPT account.");
3241
+ if (selected.contextTokens) runtimeContextLimits.set(runtime, selected.contextTokens);
3242
+ for (const model of Object.values(runtime.modelSelection().agentModels)) {
3243
+ if (model !== "auto" && !models.some((entry) => entry.id === model.replace(/^openai\//, ""))) throw new OperatorError(409, "model_not_available", "A role model is not available to this ChatGPT account.");
3244
+ }
3245
+ }
3246
+ if (diagnostics.provider === "chatgpt-plan") {
3247
+ const models = await runtime.availableModelCatalog(AbortSignal.timeout(1e4));
3248
+ if (!models.some((model) => model.id === runtime.resolvedModel())) throw new OperatorError(409, "model_not_available", "This model is not available to the connected ChatGPT plan.");
3249
+ for (const model of Object.values(runtime.modelSelection().agentModels)) {
3250
+ if (model !== "auto" && !models.some((entry) => entry.id === model)) throw new OperatorError(409, "model_not_available", "A role model is not available to the connected ChatGPT plan.");
3251
+ }
3252
+ }
3253
+ for (const role of Object.keys(runtime.modelSelection().agentModels)) {
3254
+ if (runtime.modelSelection().agentModels[role] !== "auto") await runtime.forkForSubagent(12e4, { role });
3255
+ }
3256
+ }
3257
+ async function createWebConsoleRuntime(selection = {}, policy = {}) {
3258
+ validateSelection(selection);
3259
+ assertPlanAllowed(selection.providerId, policy);
3260
+ const env = webRuntimeEnv();
3261
+ if (!selection.providerId) assertPlanAllowed(env.ZERO_SELECTED_PROVIDER || env.ZERO_PROVIDER || env.ZERO_FORCE_PROVIDER, policy);
3262
+ const { runtime } = await createPreferredConsoleRuntime({
3263
+ provider: selection.providerId,
3264
+ model: selection.model,
3265
+ agentModels: selection.agentModels,
3266
+ singleModel: selection.singleModel,
3267
+ autoRoute: selection.autoRoute,
3268
+ env,
3269
+ ...selection.providerId === "chatgpt-plan" ? { siwcConnection: getSiwcConnection(env.HOME) } : {}
3270
+ }, policy);
3271
+ await validateRuntimeModels(runtime);
3272
+ if (selection.reasoningEffort !== void 0) {
3273
+ try {
3274
+ runtime.setReasoningEffort(selection.reasoningEffort);
3275
+ } catch {
3276
+ throw new OperatorError(400, "unsupported_reasoning_effort", "Choose an available thinking effort for this model.");
3277
+ }
3278
+ }
3279
+ runtimeEnvironments.set(runtime, env);
3280
+ if (selection.model !== void 0) saveAppliedModelPreference(runtime);
3281
+ return { runtime, info: describeWebConsoleRuntime(runtime) };
3282
+ }
3283
+ async function reloadWebConsoleRuntimeConnection(runtime, policy = {}) {
3284
+ const providerId = runtime.resolvedProvider();
3285
+ const model = runtime.resolvedModel();
3286
+ assertPlanAllowed(providerId, policy);
3287
+ if (providerId === "chatgpt-plan") {
3288
+ await validateRuntimeModels(runtime);
3289
+ return describeWebConsoleRuntime(runtime);
3290
+ }
3291
+ const effort = runtime.reasoningConfiguration()?.effort;
3292
+ const env = webRuntimeEnv();
3293
+ const { runtime: candidate } = await createPreferredConsoleRuntime({
3294
+ provider: providerId,
3295
+ model,
3296
+ ...runtime.modelSelection(),
3297
+ env
3298
+ }, policy);
3299
+ if (candidate.resolvedProvider() !== providerId || candidate.resolvedModel() !== model) throw new OperatorError(409, "connection_changed", "Reconnect the conversation's selected provider and model first.");
3300
+ await validateRuntimeModels(candidate);
3301
+ if (effort !== void 0) candidate.setReasoningEffort(effort);
3302
+ runtime.refreshConnection(env);
3303
+ runtimeEnvironments.set(runtime, env);
3304
+ const contextTokens2 = runtimeContextLimits.get(candidate);
3305
+ if (contextTokens2) runtimeContextLimits.set(runtime, contextTokens2);
3306
+ else runtimeContextLimits.delete(runtime);
3307
+ return describeWebConsoleRuntime(runtime);
3308
+ }
3309
+ async function applyWebConsoleRuntimeSelection(runtime, selection, policy = {}) {
3310
+ validateSelection(selection);
3311
+ const currentProvider = runtime.resolvedProvider();
3312
+ let providerId = selection.providerId;
3313
+ if (providerId === void 0 && selection.model !== void 0) {
3314
+ const inferred = modelProvider(selection.model);
3315
+ if (inferred !== "unknown" && inferred !== currentProvider && !(["chatgpt-codex", "chatgpt-plan"].includes(currentProvider) && inferred === "openai")) providerId = inferred;
3316
+ }
3317
+ const targetProvider = providerId ?? currentProvider;
3318
+ assertPlanAllowed(targetProvider, policy);
3319
+ let candidate;
3320
+ let planConnection;
3321
+ if (targetProvider !== currentProvider) {
3322
+ const env = webRuntimeEnv();
3323
+ if (targetProvider === "chatgpt-plan") planConnection = getSiwcConnection(env.HOME);
3324
+ const created = await createPreferredConsoleRuntime({
3325
+ provider: targetProvider,
3326
+ model: selection.model,
3327
+ env,
3328
+ ...runtime.modelSelection(),
3329
+ ...selection,
3330
+ ...planConnection ? { siwcConnection: planConnection } : {}
3331
+ }, policy);
3332
+ candidate = created.runtime;
3333
+ await validateRuntimeModels(candidate);
3334
+ runtimeEnvironments.set(candidate, env);
3335
+ } else {
3336
+ candidate = await runtime.forkForSubagent(12e4);
3337
+ candidate.reconfigure({ ...runtime.modelSelection(), ...selection });
3338
+ await validateRuntimeModels(candidate);
3339
+ }
3340
+ if (selection.reasoningEffort !== void 0) {
3341
+ try {
3342
+ candidate.setReasoningEffort(selection.reasoningEffort);
3343
+ } catch {
3344
+ throw new OperatorError(400, "unsupported_reasoning_effort", "Choose an available thinking effort for this model.");
3345
+ }
3346
+ }
3347
+ runtime.reconfigure({
3348
+ model: candidate.resolvedModel(),
3349
+ provider: targetProvider,
3350
+ ...planConnection ? { siwcConnection: planConnection } : {},
3351
+ ...candidate.modelSelection(),
3352
+ ...targetProvider !== currentProvider ? { env: runtimeEnvironments.get(candidate) } : {}
3353
+ });
3354
+ const reasoning = candidate.reasoningConfiguration();
3355
+ if (reasoning) runtime.setReasoningEffort(reasoning.effort);
3356
+ const contextTokens2 = runtimeContextLimits.get(candidate);
3357
+ if (contextTokens2) runtimeContextLimits.set(runtime, contextTokens2);
3358
+ else runtimeContextLimits.delete(runtime);
3359
+ if (selection.model !== void 0) saveAppliedModelPreference(runtime);
3360
+ return describeWebConsoleRuntime(runtime);
3361
+ }
3362
+ var OperatorError = class extends Error {
3363
+ constructor(status, code, message2) {
3364
+ super(message2);
3365
+ this.status = status;
3366
+ this.code = code;
3367
+ }
3368
+ status;
3369
+ code;
3370
+ };
3371
+ function object2(input) {
3372
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new OperatorError(400, "invalid_input", "Expected a JSON object.");
3373
+ return input;
3374
+ }
3375
+ function text(input, name, max = 4096) {
3376
+ if (typeof input !== "string" || !input.trim() || input.length > max || /[\x00]/.test(input)) throw new OperatorError(400, "invalid_input", `Invalid ${name}.`);
3377
+ return input.trim();
3378
+ }
3379
+ function provider(input) {
3380
+ const id = input === "codex" ? "chatgpt-codex" : text(input, "provider", 64);
3381
+ const result = PROVIDERS.find((entry) => entry.id === id);
3382
+ if (!result) throw new OperatorError(404, "unknown_provider", "Provider does not exist.");
3383
+ return result;
3384
+ }
3385
+ function settingsView() {
3386
+ syncThemeChoices();
3387
+ return {
3388
+ settings: getSettings(),
3389
+ sources: getSettingSources(),
3390
+ defaultWriteLayer: defaultWriteLayer(),
3391
+ definitions: SETTING_DEFS.map((def) => ({ ...def, operatorOnly: isOperatorSetting(def.key) }))
3392
+ };
3393
+ }
3394
+ var WebOperatorServices = class {
3395
+ #servicePlugins = new ServicePluginServices();
3396
+ #codex = new CodexAuthController();
3397
+ #plan = new ChatGptPlanAuthController();
3398
+ #allowChatGptPlan;
3399
+ #auth = /* @__PURE__ */ new Map();
3400
+ #catalogRefresh;
3401
+ #registryItems = /* @__PURE__ */ new Map();
3402
+ #registryError = null;
3403
+ #feedback = null;
3404
+ constructor(options = {}) {
3405
+ isTurnActive = options.isTurnActive ?? (() => false);
3406
+ this.#allowChatGptPlan = options.allowChatGptPlan !== false;
3407
+ }
3408
+ #publicAuth(status) {
3409
+ return {
3410
+ ...status,
3411
+ message: publicMessage(status.message),
3412
+ lines: status.lines.map((line) => publicMessage(line))
3413
+ };
3414
+ }
3415
+ #authStatus(id, configured) {
3416
+ if (id === "chatgpt-plan") return this.#plan.status();
3417
+ if (id === "chatgpt-codex") return this.#publicAuth(this.#codex.status());
3418
+ const flow = this.#auth.get(id);
3419
+ if (flow?.status.phase === "running") return { ...flow.status, lines: [...flow.status.lines] };
3420
+ if (configured) return webAuthStatus({ phase: "connected", message: "Credentials are configured. The first request verifies account access.", lines: [] }, Boolean(PROVIDER_DEVICE_AUTH[id]));
3421
+ if (flow && flow.status.phase !== "connected") return { ...flow.status, lines: [...flow.status.lines] };
3422
+ return webAuthStatus({ phase: "idle", message: PROVIDERS.find((p) => p.id === id)?.hint ?? "Not connected.", lines: [] }, Boolean(PROVIDER_DEVICE_AUTH[id]));
3423
+ }
3424
+ #providers() {
3425
+ const env = webRuntimeEnv();
3426
+ const store = loadAccountStore();
3427
+ const configs = loadConnectionConfigs();
3428
+ return PROVIDERS.filter((info) => this.#allowChatGptPlan || info.id !== "chatgpt-plan").map((info) => {
3429
+ if (info.id === "chatgpt-plan") {
3430
+ const profiles = listChatGptPlanProfiles();
3431
+ const active = profiles.find((p) => p.active && p.status === "connected");
3432
+ return {
3433
+ id: info.id,
3434
+ label: info.label,
3435
+ methods: info.methods,
3436
+ configured: Boolean(active),
3437
+ source: active ? "account-store" : null,
3438
+ diagnostics: { valid: Boolean(active?.sharing), reason: active?.sharing ? null : active ? "plan_sharing_required" : "missing_connection", message: active?.sharing ? null : active ? "ChatGPT identity is connected. Grant plan usage to use models." : "Connect your ChatGPT account." },
3439
+ accounts: profiles.map((p) => ({ accountId: p.id, kind: "oauth", active: p.active, label: p.label, status: p.status, sharing: p.sharing })),
3440
+ configuration: {},
3441
+ auth: this.#plan.status()
3442
+ };
3443
+ }
3444
+ let diagnostics = {
3445
+ valid: false,
3446
+ reason: "missing_key",
3447
+ message: "Connect this provider in the browser to configure credentials."
3448
+ };
3449
+ const via = info.envVars.find((key) => Boolean(env[key]?.trim()));
3450
+ const environment = info.envVars.some((key) => Boolean(process.env[key]?.trim()));
3451
+ const accounts = listAccounts(store, info.id).map(({ accountId, record, active }) => ({
3452
+ accountId,
3453
+ kind: record.kind,
3454
+ active,
3455
+ label: record.kind === "oauth" ? record.identity?.email ?? record.identity?.label ?? accountId : accountId
3456
+ }));
3457
+ const configured = Boolean(via);
3458
+ if (configured) {
3459
+ try {
3460
+ diagnostics = runtimeDiagnostics(connectionProbeRuntime(info.id, env));
3461
+ } catch (error) {
3462
+ diagnostics = { valid: false, reason: "invalid_config", message: publicMessage(error) };
3463
+ }
3464
+ }
3465
+ return {
3466
+ id: info.id,
3467
+ label: info.id === "openai" ? "OpenAI / Custom AI Provider" : info.label,
3468
+ methods: info.methods.includes("api-key") && !PROVIDER_DEVICE_AUTH[info.id] ? info.methods.filter((method) => method !== "oauth") : info.methods,
3469
+ configured,
3470
+ source: configured ? environment ? "environment" : store.providers[info.id] ? "account-store" : "codex-file" : null,
3471
+ diagnostics,
3472
+ accounts,
3473
+ configuration: configs[info.id] ?? {},
3474
+ auth: this.#authStatus(info.id, configured)
3475
+ };
3476
+ });
3477
+ }
3478
+ async #models(providerId) {
3479
+ if (providerId !== void 0) providerId = provider(providerId).id;
3480
+ assertPlanAllowed(providerId, { allowChatGptPlan: this.#allowChatGptPlan });
3481
+ const env = webRuntimeEnv();
3482
+ const ids = providerStates(env).filter((state) => state.configured && (!providerId || state.id === providerId)).map((state) => state.id);
3483
+ if (this.#allowChatGptPlan && (!providerId || providerId === "chatgpt-plan") && listChatGptPlanProfiles().some((p) => p.active && p.status === "connected" && p.sharing)) ids.push("chatgpt-plan");
3484
+ if (!this.#catalogRefresh) {
3485
+ this.#catalogRefresh = Promise.resolve().then(() => syncModelCatalog()).catch(() => null).finally(() => {
3486
+ this.#catalogRefresh = void 0;
3487
+ });
3488
+ }
3489
+ const discovered = await discoverConnectionModels(env, ids);
3490
+ const metadata = new Map(buildFullModelCatalog().map((model) => [`${model.provider}/${model.id}`, model]));
3491
+ const rows = discovered.models.map((model) => ({
3492
+ id: model.id,
3493
+ provider: model.provider,
3494
+ price: model.provider === "chatgpt-plan" ? "Shared ChatGPT allowance" : model.provider === "chatgpt-codex" ? "Included in subscription" : model.provider === "cline" && model.id.startsWith("cline-pass/") ? "ClinePass plan (access unverified)" : metadata.get(`${model.provider}/${model.id}`)?.price ?? "Unknown rate",
3495
+ contextWindowTokens: model.contextTokens ?? resolveContextLimit({ modelId: model.id, providerId: model.provider })?.tokens ?? null,
3496
+ source: model.provider !== "chatgpt-plan" && model.source === "catalog" ? "public-catalog" : "account"
3497
+ }));
3498
+ const configuredModel = env.OPENAI_MODEL;
3499
+ if (configuredModel && ids.includes("openai") && !rows.some((row) => row.provider === "openai" && row.id === configuredModel)) {
3500
+ rows.unshift({ id: configuredModel, provider: "openai", price: "Unknown rate", contextWindowTokens: null, source: "account" });
3501
+ }
3502
+ return {
3503
+ models: rows,
3504
+ providerId: providerId ?? null,
3505
+ diagnostics: discovered.diagnostics.map((item) => ({ ...item, message: publicMessage(item.message) })),
3506
+ roles: MODEL_ROLES
3507
+ };
3508
+ }
3509
+ async #connections(input) {
3510
+ const body = object2(input);
3511
+ const info = provider(body.providerId);
3512
+ const action = text(body.action, "connection action", 32);
3513
+ assertPlanAllowed(info.id, { allowChatGptPlan: this.#allowChatGptPlan });
3514
+ if (info.id === "chatgpt-plan") {
3515
+ const id = text(body.accountId, "account ID", 128);
3516
+ if (action === "activate") await selectChatGptPlanProfile(id);
3517
+ else if (action === "disconnect") {
3518
+ this.#plan.cancel();
3519
+ const result = await signOutChatGptPlan(id);
3520
+ return { providers: this.#providers(), revoked: result.revoked, message: result.revoked ? "Signed out locally and provider revocation completed." : "Signed out locally. Provider revocation could not be confirmed; review the connection in ChatGPT Settings." };
3521
+ } else throw new OperatorError(400, "unsupported_auth", "Use native ChatGPT browser sign-in.");
3522
+ return { providers: this.#providers() };
3523
+ }
3524
+ if (action === "configure") {
3525
+ const config = validateConnectionConfig(info.id, {
3526
+ ...body.baseUrl !== void 0 ? { baseUrl: text(body.baseUrl, "API endpoint") } : {},
3527
+ ...body.model !== void 0 ? { model: text(body.model, "deployment model", 256) } : {},
3528
+ ...body.projectId !== void 0 ? { projectId: text(body.projectId, "Google project", 256) } : {}
3529
+ });
3530
+ if (!Object.keys(config).length) throw new OperatorError(400, "empty_configuration", "Choose a supported connection configuration field to update.");
3531
+ saveConnectionConfig(info.id, { ...loadConnectionConfigs()[info.id], ...config });
3532
+ return { providers: this.#providers() };
3533
+ }
3534
+ let store = loadAccountStore();
3535
+ if (action === "connect") {
3536
+ if (!info.methods.includes("api-key")) throw new OperatorError(400, "unsupported_auth", "Use this provider's browser sign-in flow.");
3537
+ const secret = text(body.apiKey, "API key", 16384);
3538
+ if (/[\s\x00-\x1f\x7f]/.test(secret)) throw new OperatorError(400, "invalid_key", "API keys must not contain whitespace or control characters.");
3539
+ const config = validateConnectionConfig(info.id, {
3540
+ ...body.baseUrl !== void 0 ? { baseUrl: text(body.baseUrl, "API endpoint") } : {},
3541
+ ...body.model !== void 0 ? { model: text(body.model, "deployment model", 256) } : {}
3542
+ });
3543
+ if (Object.keys(config).length) saveConnectionConfig(info.id, config);
3544
+ const accountId = body.accountId === void 0 ? void 0 : text(body.accountId, "account ID", 128);
3545
+ if (accountId && ["__proto__", "constructor", "prototype"].includes(accountId)) throw new OperatorError(400, "invalid_account", "Invalid account ID.");
3546
+ store = addAccount(store, info.id, { kind: "api_key", secret }, { accountId, makeActive: true }).store;
3547
+ } else if (action === "disconnect") {
3548
+ if (info.envVars.some((key) => process.env[key]?.trim())) throw new OperatorError(409, "environment_owned", "This connection is supplied by the server environment and cannot be revoked by deleting a saved account.");
3549
+ if (info.id === "chatgpt-codex" && !store.providers[info.id]) throw new OperatorError(409, "official_auth_owned", "The official Codex auth file belongs to Codex. Removing another account here does not revoke that login.");
3550
+ this.#auth.get(info.id)?.session?.cancel();
3551
+ this.#auth.delete(info.id);
3552
+ store = body.accountId === void 0 ? logoutProvider(store, info.id) : removeAccount(store, info.id, text(body.accountId, "account ID", 128));
3553
+ } else if (action === "activate") {
3554
+ const accountId = text(body.accountId, "account ID", 128);
3555
+ if (!store.providers[info.id]?.accounts[accountId]) throw new OperatorError(404, "unknown_account", "Saved account does not exist.");
3556
+ if (info.envVars.some((key) => process.env[key]?.trim())) throw new OperatorError(409, "environment_owned", "The explicit server credential takes precedence over saved accounts.");
3557
+ store = setActiveAccount(store, info.id, accountId);
3558
+ } else throw new OperatorError(400, "invalid_action", "Unsupported connection action.");
3559
+ if (!saveAccountStore(store)) throw new OperatorError(500, "persistence_failed", "Could not save the private credential account store.");
3560
+ return { providers: this.#providers() };
3561
+ }
3562
+ #deviceAuth(id, method, input) {
3563
+ const info = provider(id);
3564
+ assertPlanAllowed(info.id, { allowChatGptPlan: this.#allowChatGptPlan });
3565
+ if (info.id === "chatgpt-plan") {
3566
+ const body = input === void 0 ? {} : object2(input);
3567
+ const profileId = body.profileId === void 0 ? void 0 : text(body.profileId, "profile ID", 128);
3568
+ return { status: method === "DELETE" ? this.#plan.cancel() : this.#plan.start(profileId) };
3569
+ }
3570
+ if (info.id === "chatgpt-codex") return { status: this.#publicAuth(method === "DELETE" ? this.#codex.cancel() : this.#codex.start()) };
3571
+ const config = PROVIDER_DEVICE_AUTH[info.id];
3572
+ if (!config) throw new OperatorError(409, "auth_unavailable", info.hint);
3573
+ const previous = this.#auth.get(info.id);
3574
+ if (method === "DELETE") {
3575
+ previous?.session?.cancel();
3576
+ return { status: previous?.status ?? this.#authStatus(info.id, false) };
3577
+ }
3578
+ if (previous?.status.phase === "running") return { status: previous.status };
3579
+ const flow = { status: webAuthStatus({ phase: "running", message: "Starting browser sign-in.", lines: [] }), session: null, env: { ...process.env } };
3580
+ this.#auth.set(info.id, flow);
3581
+ flow.session = startDeviceAuth(config, {
3582
+ env: flow.env,
3583
+ openBrowser: (url) => {
3584
+ const safe = webAuthStatus({ phase: "running", message: "", lines: [url] });
3585
+ if (safe.verificationUrl) flow.status = { ...flow.status, verificationUrl: safe.verificationUrl };
3586
+ },
3587
+ onUpdate: (update) => {
3588
+ const status = webAuthStatus({ phase: update.phase, message: publicMessage(update.message), lines: update.lines.map((line) => publicMessage(line)) });
3589
+ flow.status = { ...status, verificationUrl: status.verificationUrl ?? flow.status.verificationUrl };
3590
+ if (update.phase !== "running") flow.session = null;
3591
+ },
3592
+ onConnected: () => void 0
3593
+ });
3594
+ return { status: flow.status };
3595
+ }
3596
+ async #plugins() {
3597
+ const registryUrl = (process.env.ZERO_REGISTRY_URL ?? DEFAULT_REGISTRY_URL).trim();
3598
+ let publicRegistryUrl = "";
3599
+ if (registryUrl) {
3600
+ try {
3601
+ const url = new URL(registryUrl);
3602
+ url.username = "";
3603
+ url.password = "";
3604
+ url.search = "";
3605
+ url.hash = "";
3606
+ publicRegistryUrl = url.href;
3607
+ } catch {
3608
+ publicRegistryUrl = "Invalid configured registry URL";
3609
+ }
3610
+ }
3611
+ const fetched = await pluginService.fetchRegistry();
3612
+ this.#registryError = fetched.ok ? null : publicMessage(registryUrl ? fetched.error.split(registryUrl).join(publicRegistryUrl) : fetched.error);
3613
+ this.#registryItems = fetched.ok ? new Map(buildMarketItems(fetched.result).map((item) => [`${item.kind}:${item.id}`, item])) : /* @__PURE__ */ new Map();
3614
+ const installed = await pluginService.list(getSettings().theme);
3615
+ const items = new Map(this.#registryItems);
3616
+ const errors = /* @__PURE__ */ new Map();
3617
+ for (const id of listInstalledPluginIds(pluginsRootDir())) {
3618
+ const discovered = readInstalledPlugin(pluginsRootDir(), id, { reservedToolNames });
3619
+ if (!discovered.ok) {
3620
+ errors.set(id, discovered.errors.join("; "));
3621
+ continue;
3622
+ }
3623
+ const manifest = discovered.plugin.manifest;
3624
+ items.set(`plugin:${id}`, {
3625
+ id,
3626
+ kind: "plugin",
3627
+ name: manifest.name ?? id,
3628
+ version: manifest.version,
3629
+ description: manifest.tools.map((tool) => tool.name).join(", "),
3630
+ capabilities: aggregateCapabilities(manifest),
3631
+ signature: "unverified",
3632
+ raw: void 0
3633
+ });
3634
+ }
3635
+ for (const theme of installedThemeEntries()) {
3636
+ if (!items.has(`theme:${theme.name}`)) items.set(`theme:${theme.name}`, {
3637
+ id: theme.name,
3638
+ kind: "theme",
3639
+ name: theme.label,
3640
+ version: "",
3641
+ description: theme.description,
3642
+ capabilities: [],
3643
+ signature: "unverified",
3644
+ raw: void 0
3645
+ });
3646
+ }
3647
+ const host = pluginManager?.current();
3648
+ const hostStates = host?.status() ?? [];
3649
+ const loadedPluginIds = hostStates.filter((entry) => entry.state === "ready").map((entry) => entry.pluginId);
3650
+ const result = [...items.values()].map(({ raw: _raw, ...item }) => ({
3651
+ ...item,
3652
+ state: item.kind === "theme" ? item.id === installed.activeTheme ? "active" : installed.themes.has(item.id) ? "installed" : "available" : installed.plugins.get(item.id) ?? "available",
3653
+ loaded: loadedPluginIds.includes(item.id),
3654
+ error: errors.get(item.id) ?? (hostStates.some((state) => state.pluginId === item.id && state.state === "unavailable") ? "Plugin is unavailable in the current host." : null)
3655
+ }));
3656
+ for (const [id, error] of errors) if (!result.some((item) => item.id === id && item.kind === "plugin")) result.push({ id, kind: "plugin", name: id, version: "", description: "Installed manifest is invalid.", capabilities: [], signature: "unverified", state: "installed", loaded: false, error });
3657
+ return {
3658
+ registry: { url: publicRegistryUrl, available: fetched.ok, error: this.#registryError },
3659
+ items: result,
3660
+ deferred: [...deferredPlugins],
3661
+ executionProfile: consoleExecutionProfile(),
3662
+ host: { loadedPluginIds, tools: host?.toolDefinitions().map(({ name, description }) => ({ name, description })) ?? [] }
3663
+ };
3664
+ }
3665
+ async #pluginAction(action, input) {
3666
+ if (action === "run" && consoleExecutionProfile() === "smolvm") throw new OperatorError(409, "isolated_execution_required", "Plugins load automatically inside new SmolVM chats. Start a new chat to use an approved plugin.");
3667
+ const body = object2(input);
3668
+ const id = text(body.id, "plugin ID", 64);
3669
+ if (action === "install") {
3670
+ const kind = body.kind === "theme" ? "theme" : "plugin";
3671
+ await this.#plugins();
3672
+ if (this.#registryError) throw new OperatorError(503, "registry_unavailable", this.#registryError);
3673
+ const item2 = this.#registryItems.get(`${kind}:${id}`);
3674
+ if (!item2) throw new OperatorError(404, "unknown_artifact", "The configured registry has no installable artifact with that ID.");
3675
+ const result2 = await pluginService.install(item2);
3676
+ if (!result2.ok) throw new OperatorError(409, "install_failed", result2.message);
3677
+ reloadInstalledThemes();
3678
+ return result2;
3679
+ }
3680
+ if (!isSafePluginId(id)) throw new OperatorError(400, "invalid_plugin", "Invalid plugin ID.");
3681
+ if (action === "disable") {
3682
+ if (!writeEnablement(process.cwd(), disable(readEnablement(process.cwd()), id))) throw new OperatorError(500, "persistence_failed", "Could not save plugin approval removal.");
3683
+ deferredPlugins.delete(id);
3684
+ return { ok: true, message: "Disabled for future sessions. Already leased sessions keep their approved host until cleanup.", state: "installed" };
3685
+ }
3686
+ const discovered = readInstalledPlugin(pluginsRootDir(), id, { reservedToolNames });
3687
+ if (!discovered.ok) throw new OperatorError(409, "invalid_plugin", discovered.errors.join("; "));
3688
+ const manifest = discovered.plugin.manifest;
3689
+ const capabilities = aggregateCapabilities(manifest);
3690
+ const item = { id, kind: "plugin", name: manifest.name ?? id, version: manifest.version, description: "", capabilities, signature: "unverified", raw: void 0 };
3691
+ if (action === "enable") {
3692
+ if (body.approved !== true || body.version !== manifest.version || !Array.isArray(body.capabilities) || body.capabilities.some((entry) => typeof entry !== "string") || JSON.stringify([...new Set(body.capabilities)].sort()) !== JSON.stringify([...capabilities].sort())) throw new OperatorError(409, "approval_required", "Inspect and explicitly approve this installed version and its exact capabilities before enabling.");
3693
+ const result2 = await pluginService.enable(item);
3694
+ if (!result2.ok) throw new OperatorError(409, "enable_failed", result2.message);
3695
+ return consoleExecutionProfile() === "smolvm" ? { ...result2, message: "Approved for new SmolVM chats. Plugin files are copied and loaded automatically inside each new VM." } : result2;
3696
+ }
3697
+ if (action !== "run") throw new OperatorError(404, "unknown_action", "Unsupported plugin action.");
3698
+ const result = await pluginService.run(item);
3699
+ if (result.deferred) deferredPlugins.add(id);
3700
+ else if (!result.ok) throw new OperatorError(409, "run_failed", result.message);
3701
+ return result;
3702
+ }
3703
+ async handle(pathname, method, input, query) {
3704
+ if (!pathname.startsWith("/api/console/")) return null;
3705
+ const path = pathname.slice("/api/console/".length);
3706
+ const servicePluginResult = await this.#servicePlugins.handle(path, method, input);
3707
+ if (servicePluginResult) return servicePluginResult;
3708
+ if (!/^(providers(?:\/[^/]+(?:\/device-auth)?)?|models|connections|settings(?:\/reset)?|themes|plugins(?:\/(?:install|enable|disable|run))?|doctor|tools|project(?:\/(?:directories|choose-directory))?|checks|feedback)$/.test(path)) return null;
3709
+ try {
3710
+ let data;
3711
+ let status = 200;
3712
+ if (path === "providers" && method === "GET") data = { providers: this.#providers(), preference: getSettings().modelPreference };
3713
+ else if (path === "models" && method === "GET") data = await this.#models(query.get("providerId") ?? void 0);
3714
+ else if (path === "connections" && method === "POST") data = await this.#connections(input);
3715
+ else if (/^providers\/[^/]+\/device-auth$/.test(path) && ["POST", "DELETE"].includes(method)) {
3716
+ data = this.#deviceAuth(decodeURIComponent(path.split("/")[1]), method, input);
3717
+ status = method === "POST" ? 202 : 200;
3718
+ } else if (/^providers\/[^/]+$/.test(path) && method === "GET") {
3719
+ const info = provider(decodeURIComponent(path.split("/")[1]));
3720
+ assertPlanAllowed(info.id, { allowChatGptPlan: this.#allowChatGptPlan });
3721
+ const state = this.#providers().find((entry) => entry.id === info.id);
3722
+ data = { provider: state, status: state.auth };
3723
+ } else if (path === "settings" && method === "GET") data = settingsView();
3724
+ else if (path === "settings" && method === "PATCH") {
3725
+ const body = object2(input);
3726
+ const key = text(body.key, "setting", 128);
3727
+ const def = SETTING_DEFS.find((entry) => entry.key === key);
3728
+ const internalBoolean = key === "onboardingCompleted" || key === "diagnosticReportingPrompted";
3729
+ if (!def && !internalBoolean) throw new OperatorError(400, "unknown_setting", "Only declared settings can be changed here. Model preferences are saved by successful runtime selection.");
3730
+ if (body.scope !== void 0 && body.scope !== "global" && body.scope !== "project") throw new OperatorError(400, "invalid_scope", "Settings scope must be global or project.");
3731
+ if (isOperatorSetting(key) && body.scope === "project") throw new OperatorError(400, "operator_global", "Operator consent and execution preferences can only be changed globally.");
3732
+ if (internalBoolean ? typeof body.value !== "boolean" : def.kind === "boolean" ? typeof body.value !== "boolean" : key === "theme" ? !isKnownTheme(body.value) : typeof body.value !== "string" || !def.choices?.includes(body.value)) throw new OperatorError(400, "invalid_value", "The value is not supported by this setting.");
3733
+ const persisted = updateSetting(key, body.value, { scope: body.scope });
3734
+ data = { ...settingsView(), persisted, ...!persisted ? { error: "Settings changed in this process but could not be saved to disk.", code: "persistence_failed" } : {} };
3735
+ if (!persisted) status = 507;
3736
+ } else if (path === "settings/reset" && method === "POST") {
3737
+ const body = object2(input);
3738
+ const keys = body.keys ?? SETTING_DEFS.map((def) => def.key);
3739
+ if (!Array.isArray(keys) || keys.some((key) => typeof key !== "string" || !SETTING_DEFS.some((def) => def.key === key))) throw new OperatorError(400, "invalid_setting", "Reset keys must name declared settings.");
3740
+ const persisted = resetSettings(DEFAULT_SETTINGS, keys);
3741
+ data = { ...settingsView(), persisted, ...!persisted ? { error: "Settings reset in this process but could not be saved to disk.", code: "persistence_failed" } : {} };
3742
+ if (!persisted) status = 507;
3743
+ } else if (path === "themes" && method === "GET") data = { active: getSettings().theme, themes: allThemeNames().map((name) => ({ ...getThemeEntry(name) })) };
3744
+ else if (path === "plugins" && method === "GET") data = await this.#plugins();
3745
+ else if (path.startsWith("plugins/") && method === "POST") data = await this.#pluginAction(path.split("/")[1], input);
3746
+ else if (path === "doctor" && method === "GET") {
3747
+ const providers = this.#providers();
3748
+ const availability = await getRuntimeAvailability();
3749
+ const ready = providers.find((entry) => entry.diagnostics.valid);
3750
+ const settings = getSettings();
3751
+ data = {
3752
+ version: VERSION,
3753
+ runtime: { ...getRuntimeMetadata(), node: process.version, nodeSupported: Number(process.versions.node.split(".")[0]) >= 24 },
3754
+ availability: { ...availability, hasApiKey: Boolean(ready), apiRuntime: ready ? { configured: true, valid: true, providerLabel: ready.label } : { ...availability.apiRuntime, error: availability.apiRuntime.error ? publicMessage(availability.apiRuntime.error) : void 0 } },
3755
+ providers,
3756
+ prerequisites: [{ id: "node", available: Number(process.versions.node.split(".")[0]) >= 24, required: true }, { id: "codex", available: providers.find((entry) => entry.id === "chatgpt-codex").auth.available, required: false }],
3757
+ settings: { onboardingCompleted: settings.onboardingCompleted, analyticsLevel: settings.analyticsLevel, diagnosticReporting: settings.diagnosticReporting, executionProfile: settings.executionProfile }
3758
+ };
3759
+ } else if (path === "tools" && method === "GET") {
3760
+ const roleTools = Object.fromEntries(MODEL_ROLES.map((role) => [role, new Set(getToolsForRole(role, { hasScope: true, webMode: true, hasBrowser: true, allowScanners: true }).map((tool) => tool.name))]));
3761
+ data = { roles: MODEL_ROLES, tools: Object.values(TOOL_DEFINITIONS).map(({ name, description }) => ({ name, description, roles: MODEL_ROLES.filter((role) => roleTools[role].has(name)) })), plugins: pluginManager?.current().toolDefinitions().map(({ name, description }) => ({ name, description })) ?? [] };
3762
+ } else if (path === "project/choose-directory" && method === "POST") {
3763
+ data = await chooseWorkspaceFolder(object2(input).path);
3764
+ } else if (path === "project/directories" && method === "POST") {
3765
+ data = await listWorkspaceDirectories(object2(input).path);
3766
+ } else if (path === "project" && method === "GET") {
3767
+ const projectPath = realpathSync(resolve3(query.get("path") ?? process.cwd()));
3768
+ if (!statSync(projectPath).isDirectory()) throw new OperatorError(400, "invalid_project", "Project path must name a local directory.");
3769
+ const git = { root: null, branch: null, dirty: false, error: null };
3770
+ try {
3771
+ git.root = execFileSync("git", ["--no-optional-locks", "-c", "core.fsmonitor=false", "-C", projectPath, "rev-parse", "--show-toplevel"], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim();
3772
+ git.branch = execFileSync("git", ["--no-optional-locks", "-c", "core.fsmonitor=false", "-C", projectPath, "branch", "--show-current"], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
3773
+ git.dirty = Boolean(execFileSync("git", ["--no-optional-locks", "-c", "core.fsmonitor=false", "-C", projectPath, "status", "--porcelain"], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "ignore"], maxBuffer: 1048576 }).trim());
3774
+ } catch {
3775
+ git.error = "Git metadata is unavailable for this directory.";
3776
+ }
3777
+ data = { path: projectPath, name: basename(projectPath), git };
3778
+ } else if (path === "checks" && method === "GET") data = listProjectReviewChecks(query.get("path") ?? process.cwd());
3779
+ else if (path === "checks" && method === "POST") {
3780
+ const body = object2(input);
3781
+ const mutation = object2(body.mutation);
3782
+ const action = text(mutation.action, "review check action", 32);
3783
+ if (!["propose", "add", "enable", "disable", "set", "remove"].includes(action)) throw new OperatorError(400, "invalid_action", "Unsupported review check action.");
3784
+ if (mutation.approved !== void 0 && typeof mutation.approved !== "boolean") throw new OperatorError(400, "invalid_approval", "Approval must be an explicit boolean.");
3785
+ if (mutation.expectedRevision !== void 0 && (!Number.isSafeInteger(mutation.expectedRevision) || Number(mutation.expectedRevision) < 1)) throw new OperatorError(400, "invalid_revision", "Expected revision must be a positive integer.");
3786
+ data = updateProjectReviewChecks(body.path === void 0 ? process.cwd() : text(body.path, "project path"), mutation);
3787
+ } else if (path === "feedback" && method === "POST") {
3788
+ const body = object2(input);
3789
+ if (body.action === "cancel") {
3790
+ this.#feedback = null;
3791
+ data = { cancelled: true, submitted: false };
3792
+ } else if (body.action === "send") {
3793
+ const staged = this.#feedback;
3794
+ if (!staged || body.previewId !== staged.id) throw new OperatorError(409, "review_required", "Review and confirm the staged feedback before sending.");
3795
+ const result = await submitFeedback(staged.payload, process.env, { expectedPreview: staged.preview });
3796
+ if (!result.ok) throw new OperatorError(409, "submission_failed", result.error ?? "Feedback could not be submitted.");
3797
+ this.#feedback = null;
3798
+ data = { saved: true, submitted: true };
3799
+ } else {
3800
+ if (body.submit !== void 0 && typeof body.submit !== "boolean") throw new OperatorError(400, "invalid_submission", "Submission must be explicitly selected.");
3801
+ const payload = { message: text(body.message, "feedback", 16e3), timestamp: (/* @__PURE__ */ new Date()).toISOString(), version: VERSION };
3802
+ const saved = appendFeedback(payload);
3803
+ if (!saved.ok) throw new OperatorError(500, "persistence_failed", saved.error ?? "Could not save local feedback.");
3804
+ if (body.submit === true) {
3805
+ const preview = buildSubmitPreview(payload);
3806
+ if (!preview) throw new OperatorError(409, "submission_unavailable", "Local feedback was saved, but reporting is opted out or no supported HTTPS destination is available.");
3807
+ const id = randomUUID3();
3808
+ this.#feedback = { id, payload, preview };
3809
+ data = { saved: true, path: saved.path, submitted: false, previewId: id, preview: { ...preview, url: publicMessage(preview.url) } };
3810
+ } else data = { saved: true, path: saved.path, submitted: false };
3811
+ }
3812
+ } else throw new OperatorError(405, "method_not_allowed", "This operation does not support that HTTP method.");
3813
+ return { status, data };
3814
+ } catch (error) {
3815
+ return { status: error instanceof OperatorError ? error.status : 400, data: { error: publicMessage(error), code: error instanceof OperatorError ? error.code : "operation_failed" } };
3816
+ }
3817
+ }
3818
+ dispose() {
3819
+ this.#plan.cancel();
3820
+ this.#codex.cancel();
3821
+ for (const flow of this.#auth.values()) flow.session?.cancel();
3822
+ pluginManager?.dispose();
3823
+ }
3824
+ };
3825
+
3826
+ export {
3827
+ sanitizeComposerText,
3828
+ createSessionPluginHostManager,
3829
+ jwtVerify,
3830
+ createRemoteJWKSet,
3831
+ getWebConsolePluginHostManager,
3832
+ flushWebConsolePlugins,
3833
+ describeWebConsoleRuntime,
3834
+ savedWebRuntimeSelection,
3835
+ createWebConsoleRuntime,
3836
+ reloadWebConsoleRuntimeConnection,
3837
+ applyWebConsoleRuntimeSelection,
3838
+ WebOperatorServices
3839
+ };