0sec-cli 0.24.0 → 0.25.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 (243) hide show
  1. package/0.js +64 -60
  2. package/README.md +121 -82
  3. package/chunks/{adapt-loop-TEJPXWFG.js → adapt-loop-L2PXCD4J.js} +6 -5
  4. package/chunks/{artifact-scraper-AJZ3LOQY.js → artifact-scraper-W3LGLXBM.js} +4 -3
  5. package/chunks/{assumption-mining-EATDC4BB.js → assumption-mining-7IJ6ZWZE.js} +22 -20
  6. package/chunks/{backend-connections-QE4NASAK.js → backend-connections-MYH4QRQG.js} +5 -4
  7. package/chunks/{chunk-RBOMXUYL.js → chunk-27SXCYWH.js} +1 -1
  8. package/chunks/{chunk-E42XEJTK.js → chunk-2J3STRJT.js} +337 -257
  9. package/chunks/chunk-36J5ZLFE.js +18729 -0
  10. package/chunks/chunk-3DF55BWV.js +49 -0
  11. package/chunks/{chunk-GHEBZKUS.js → chunk-3HMO42M2.js} +1426 -321
  12. package/chunks/{chunk-BIJPMYFA.js → chunk-3T5R7P4T.js} +6 -6
  13. package/chunks/{chunk-RD4FKFWR.js → chunk-5H2PXZ7Q.js} +1 -1
  14. package/chunks/chunk-5XOYTAOK.js +1546 -0
  15. package/chunks/{chunk-QEA2VHBD.js → chunk-6TA3CWND.js} +2656 -2960
  16. package/chunks/{chunk-H76JYUPE.js → chunk-76CLUI54.js} +3 -3
  17. package/chunks/{chunk-KCA35IL3.js → chunk-7PUJI64A.js} +11 -9
  18. package/chunks/{chunk-W6IYTSZH.js → chunk-7TIWL6E5.js} +8 -10
  19. package/chunks/chunk-ABKUI3QB.js +196 -0
  20. package/chunks/{chunk-YORL5S5V.js → chunk-ACYZMJHC.js} +1 -1
  21. package/chunks/{chunk-5FHFG5P2.js → chunk-AL32F74R.js} +1 -1
  22. package/chunks/{chunk-J6G73WYF.js → chunk-B5TIXHCO.js} +1 -1
  23. package/chunks/{chunk-G2EJ3R5I.js → chunk-BWUW6ZQR.js} +2052 -1075
  24. package/chunks/{chunk-3XLEDCFX.js → chunk-C6ZMPXN2.js} +5 -50
  25. package/chunks/{chunk-4TUR47H5.js → chunk-D4IBEO2K.js} +1 -1
  26. package/chunks/{chunk-EXTN4SQV.js → chunk-DHNYJ2ML.js} +1 -1
  27. package/chunks/{chunk-Y7KV7WV6.js → chunk-DJGJECBV.js} +93 -20
  28. package/chunks/{chunk-UHUW45S3.js → chunk-DMDWIW3E.js} +5 -5
  29. package/chunks/{chunk-V5I5GAQH.js → chunk-EEP6GBUO.js} +16037 -34417
  30. package/chunks/{chunk-EYBMTELO.js → chunk-EIONVEFN.js} +208 -29
  31. package/chunks/chunk-EQBC2ZWL.js +2481 -0
  32. package/chunks/{chunk-FKGFHLLS.js → chunk-FI2H6HV2.js} +1 -1
  33. package/chunks/{chunk-4YRXIVPZ.js → chunk-FI5YL4R2.js} +3 -3
  34. package/chunks/{chunk-DNV3ZMPX.js → chunk-FOLTHXRH.js} +1 -1
  35. package/chunks/{chunk-ZPFBQ3SD.js → chunk-GOUGG7IQ.js} +3 -3
  36. package/chunks/{chunk-O3ADFN2A.js → chunk-GXSECFUE.js} +1 -1
  37. package/chunks/{chunk-YYOQADBB.js → chunk-HDJSHLRM.js} +3 -2
  38. package/chunks/{chunk-A3EKBUEM.js → chunk-HFUOUT2B.js} +61232 -30665
  39. package/chunks/chunk-HJKJ4NQP.js +196 -0
  40. package/chunks/{chunk-RPTO5FY2.js → chunk-I4VIAQHM.js} +1 -1
  41. package/chunks/{chunk-A6AZZ6XX.js → chunk-ITEMDJAB.js} +3 -3
  42. package/chunks/chunk-ITHDAIRY.js +57 -0
  43. package/chunks/{chunk-TOFIGQ63.js → chunk-JCRQV4FE.js} +2 -2
  44. package/chunks/{chunk-SQCBHFWN.js → chunk-LWMEJYCP.js} +2 -2
  45. package/chunks/{chunk-52AWIBCT.js → chunk-MY44EZKD.js} +1 -1
  46. package/chunks/{chunk-SGILXLR3.js → chunk-NBLKIQCW.js} +226 -4
  47. package/chunks/chunk-NO543ZBU.js +90 -0
  48. package/chunks/{chunk-CIMN2AO6.js → chunk-OFPF26WL.js} +333 -3
  49. package/chunks/{chunk-YERUDEXT.js → chunk-PAE7ZAV6.js} +2780 -1255
  50. package/chunks/{chunk-V4BD7GSP.js → chunk-PMAKX6KP.js} +2 -2
  51. package/chunks/{chunk-62PGWN7Y.js → chunk-RBTJYREN.js} +8 -171
  52. package/chunks/{chunk-IK27KMVV.js → chunk-RFK5F45W.js} +1 -1
  53. package/chunks/{chunk-554D4AYM.js → chunk-S2WCYEK2.js} +4 -99
  54. package/chunks/{chunk-RZR2XXAK.js → chunk-S3B6HFSM.js} +144 -14
  55. package/chunks/{chunk-WUPN3D37.js → chunk-S4DFH2FJ.js} +26 -1
  56. package/chunks/{chunk-TZRHWP7R.js → chunk-SEWZ76MN.js} +77 -13
  57. package/chunks/{chunk-HRBOZBMC.js → chunk-TFKY6D7O.js} +1 -1
  58. package/chunks/{chunk-TOAAYJVN.js → chunk-WK6VUCKK.js} +3 -333
  59. package/chunks/{chunk-IXT64DV5.js → chunk-XPDJE537.js} +97 -1
  60. package/chunks/{chunk-RCHAFSWS.js → chunk-YXTV2FRE.js} +113 -22
  61. package/chunks/{chunk-TTDFBFNZ.js → chunk-YYFODVZG.js} +6 -10
  62. package/chunks/{chunk-3XLFB46W.js → chunk-ZWAWZU6C.js} +30 -13
  63. package/chunks/{chunk-5POT5OYF.js → chunk-ZZV56ACK.js} +11 -9
  64. package/chunks/{codex-models-FQPCWRPC.js → codex-models-KCUIVS3R.js} +9 -8
  65. package/chunks/{commands-I5L3VD2A.js → commands-MPPAADGY.js} +798 -608
  66. package/chunks/dashboard-MN7GZLLX.js +75 -0
  67. package/chunks/{db-P5EIKMLP.js → db-R2AQSESC.js} +5 -4
  68. package/chunks/{deep-review-I7RD5QSS.js → deep-review-Q6BJKEV4.js} +37 -38
  69. package/chunks/{disclose-PFBWESVJ.js → disclose-GGULOW27.js} +6 -5
  70. package/chunks/{dist-AJU25UXA.js → dist-6RNAVFAY.js} +376 -333
  71. package/chunks/{dist-VK2M4HNW.js → dist-DWN7U5OV.js} +5 -2
  72. package/chunks/{dist-M2X367VW.js → dist-JAZWL3SC.js} +3 -2
  73. package/chunks/{dist-3SWWY5FZ.js → dist-OLGNKDB2.js} +4 -3
  74. package/chunks/{dist-LNXGATR2.js → dist-WNAOCQGA.js} +5 -4
  75. package/chunks/eval-runner-WCTTIYN4.js +38 -0
  76. package/chunks/{exploit-agent-A4RTIJ4J.js → exploit-agent-M3KUMZJH.js} +1 -1
  77. package/chunks/{exploit-autoclimb-ABMMBC3M.js → exploit-autoclimb-QTTWC5WM.js} +1 -1
  78. package/chunks/{exploit-climb-BQ2SVU63.js → exploit-climb-E4KDELTN.js} +4 -3
  79. package/chunks/{fix-4YCLHFDT.js → fix-U5FFJD4F.js} +9 -8
  80. package/chunks/{harness-DHWULEIZ.js → harness-FMKIMEH5.js} +5 -4
  81. package/chunks/{http-conformance-U5F6GKYG.js → http-conformance-AXMUOE6C.js} +3 -2
  82. package/chunks/hunt-scan-RYPWRUQD.js +43 -0
  83. package/chunks/{kernel-primitive-SF4NALVR.js → kernel-primitive-CVG2E7MJ.js} +4 -3
  84. package/chunks/{kernel-vm-runner-WEBEZEIC.js → kernel-vm-runner-62KISULQ.js} +4 -3
  85. package/chunks/{local-engine-XUG7XRKM.js → local-engine-WP3I7K7G.js} +7 -6
  86. package/chunks/managed-operation-642WPTLC.js +59 -0
  87. package/chunks/{memsafety-scan-L2Z7E7TE.js → memsafety-scan-Q2MBZEGJ.js} +1 -2
  88. package/chunks/{native-loop-ZNAELJGB.js → native-loop-HC77R5NQ.js} +31 -16
  89. package/chunks/operator-services-E2NONBQS.js +79 -0
  90. package/chunks/orchestrate-Z3DW265M.js +62 -0
  91. package/chunks/{prepare-SODWQN6O.js → prepare-7DTS6RJT.js} +7 -6
  92. package/chunks/{remote-workflow-runtime-XNNGI2PG.js → remote-workflow-runtime-6CEVRZXS.js} +4 -3
  93. package/chunks/routing-ITJZBJIU.js +61 -0
  94. package/chunks/{runtime-MB4GEFBY.js → runtime-PZJ77QES.js} +9 -8
  95. package/chunks/{runtime-HFFRUOPL.js → runtime-W6JNDQRO.js} +4 -3
  96. package/chunks/{scan-stream-GXBJHCDF.js → scan-stream-6VOJTHTR.js} +6 -4
  97. package/chunks/{scope-M7L3CD6X.js → scope-FHXW6EX6.js} +4 -3
  98. package/chunks/service-plugins-CN6Q2NSN.js +63 -0
  99. package/chunks/{session-store-K7I4GLNH.js → session-store-DBBI544Y.js} +8 -5
  100. package/chunks/{variant-candidates-2KSP5EHH.js → variant-candidates-DPR6DJ3N.js} +9 -8
  101. package/chunks/{web-recon-prepass-RAXXTEWH.js → web-recon-prepass-HWDHDQMN.js} +7 -6
  102. package/chunks/{workflow-runtime-V26HIJO3.js → workflow-runtime-PLB32XC3.js} +50 -49
  103. package/dashboard/assets/{abnfDiagram-VCTEODGH-CGCueOp5.js → abnfDiagram-VCTEODGH-6e39CQKz.js} +1 -1
  104. package/dashboard/assets/{arc-BjZaQcCc.js → arc-ClYun86B.js} +1 -1
  105. package/dashboard/assets/architecture-7GRP2DOG-rM-lWo7E.js +1 -0
  106. package/dashboard/assets/architectureDiagram-5GKGNRK7-C9gEGZIU.js +36 -0
  107. package/dashboard/assets/{blockDiagram-I7D4REHJ-C-byT12_.js → blockDiagram-I7D4REHJ-Dgh2n5Lf.js} +2 -2
  108. package/dashboard/assets/{c4Diagram-7LVT6UL2-DoYjz-Uv.js → c4Diagram-7LVT6UL2-CsorW08z.js} +1 -1
  109. package/dashboard/assets/channel-BBlDqIBl.js +1 -0
  110. package/dashboard/assets/{chunk-4HAMMTFA-NBNp2zdt.js → chunk-4HAMMTFA-4_b_LGGQ.js} +1 -1
  111. package/dashboard/assets/{chunk-75Z2AOVW-BHmkuP0B.js → chunk-75Z2AOVW-qzNlKGCp.js} +1 -1
  112. package/dashboard/assets/chunk-DU6HZSFF-SAPICW28.js +127 -0
  113. package/dashboard/assets/{chunk-F27PBJKO-3wwNFUgZ.js → chunk-F27PBJKO-DlLotIQx.js} +1 -1
  114. package/dashboard/assets/{chunk-FOHPRMQF-DHwB1DNv.js → chunk-FOHPRMQF-COOliuUh.js} +14 -14
  115. package/dashboard/assets/{chunk-GMAD6QVW-Btg7huZW.js → chunk-GMAD6QVW-DNnr65Nb.js} +7 -7
  116. package/dashboard/assets/{chunk-GVQU2GXP-ihCURK5O.js → chunk-GVQU2GXP-DTwv0VfU.js} +1 -1
  117. package/dashboard/assets/{chunk-IMKFNOWR-FsXj7slg.js → chunk-IMKFNOWR-B1fk1q_W.js} +1 -1
  118. package/dashboard/assets/{chunk-L3NEJ4N5-DorFIxJY.js → chunk-L3NEJ4N5-ByVjFIox.js} +1 -1
  119. package/dashboard/assets/{chunk-OSK3NFVY-DKun_KfC.js → chunk-OSK3NFVY-DUDCzjbh.js} +1 -1
  120. package/dashboard/assets/{chunk-P2QGCYS3-XGgiU1Bz.js → chunk-P2QGCYS3-D_D5qEso.js} +1 -1
  121. package/dashboard/assets/{chunk-POPQ4Y6H-BTXEnGhJ.js → chunk-POPQ4Y6H-CetM-tVm.js} +1 -1
  122. package/dashboard/assets/{chunk-PWAF6VOD-DYZcGkTL.js → chunk-PWAF6VOD-BcJX4exl.js} +1 -1
  123. package/dashboard/assets/{chunk-SHT3W25Y-C4WQfwf8.js → chunk-SHT3W25Y-BWQql238.js} +1 -1
  124. package/dashboard/assets/{chunk-SVP7TREG-C4nCh0-1.js → chunk-SVP7TREG-BSLOD1JE.js} +1 -1
  125. package/dashboard/assets/{chunk-TICWLB2K-DSB-IiGc.js → chunk-TICWLB2K-DReOl-g_.js} +2 -2
  126. package/dashboard/assets/{chunk-XXDRQBXY-CS6fjUcj.js → chunk-XXDRQBXY-DSdSMeei.js} +1 -1
  127. package/dashboard/assets/classDiagram-ZZMXUADV-CRH2kB8G.js +1 -0
  128. package/dashboard/assets/classDiagram-v2-VYDZK3BY-CRH2kB8G.js +1 -0
  129. package/dashboard/assets/common-CRRsylCH.js +5 -0
  130. package/dashboard/assets/cose-bilkent-JH36ORCC-fg-DIBqt.js +1 -0
  131. package/dashboard/assets/cynefin-OW5HDTMX-XmrbEIFh.js +1 -0
  132. package/dashboard/assets/{cynefinDiagram-5FMLGOSQ-CgDOOY67.js → cynefinDiagram-5FMLGOSQ-CoQ7QEPl.js} +1 -1
  133. package/dashboard/assets/cytoscape.esm-BbBREfsg.js +321 -0
  134. package/dashboard/assets/dagre-D7JM2Yhv.js +1 -0
  135. package/dashboard/assets/dagre-GXQ25YYZ-qtQtsg6c.js +4 -0
  136. package/dashboard/assets/{diagram-S7CK7UJ4-CrKqRXZb.js → diagram-S7CK7UJ4-B_ts4_58.js} +2 -2
  137. package/dashboard/assets/{diagram-UQ7AKVKN-Cu6Es0-v.js → diagram-UQ7AKVKN-DwHbbxFy.js} +1 -1
  138. package/dashboard/assets/{diagram-VSXAHHWV-eK4d8FwS.js → diagram-VSXAHHWV-2Tg_RG89.js} +1 -1
  139. package/dashboard/assets/{diagram-VX7I27RA-bFxeFKOc.js → diagram-VX7I27RA-BFYp-YjF.js} +1 -1
  140. package/dashboard/assets/{diagram-Z3DM3KII-C0ClmnhC.js → diagram-Z3DM3KII-DrPiS4V0.js} +1 -1
  141. package/dashboard/assets/{dist-BZh8Kb3O.js → dist-cbVssBvx.js} +1 -1
  142. package/dashboard/assets/{ebnfDiagram-PWID7BFC-CUqxFPzf.js → ebnfDiagram-PWID7BFC-DCMOZtU2.js} +1 -1
  143. package/dashboard/assets/{erDiagram-RLTQ6QDP-CcYM7pLi.js → erDiagram-RLTQ6QDP-CW4rUJGU.js} +1 -1
  144. package/dashboard/assets/eventmodeling-NTZA5JFV-C2q-Aaav.js +1 -0
  145. package/dashboard/assets/flowDiagram-HODETNUW-3NOabgG3.js +1 -0
  146. package/dashboard/assets/{ganttDiagram-EL5Y4UJY-UmZfbMyD.js → ganttDiagram-EL5Y4UJY-C1AqcwIF.js} +1 -1
  147. package/dashboard/assets/gitGraph-4MIJSDKK-DYR76gtd.js +1 -0
  148. package/dashboard/assets/{gitGraphDiagram-WWUBYQGX-CvzeCxVy.js → gitGraphDiagram-WWUBYQGX-B7hL98CE.js} +1 -1
  149. package/dashboard/assets/info-A6RAGUB7-TXB43LiH.js +1 -0
  150. package/dashboard/assets/{infoDiagram-27XIBGKW-DjkpNtVW.js → infoDiagram-27XIBGKW-Dk5dXmh_.js} +1 -1
  151. package/dashboard/assets/{ishikawaDiagram-5VMMS53U-8FhjJaWT.js → ishikawaDiagram-5VMMS53U-BQDuNMka.js} +2 -2
  152. package/dashboard/assets/{journeyDiagram-3NMN7TZE-DyNJ755f.js → journeyDiagram-3NMN7TZE-DkustddD.js} +1 -1
  153. package/dashboard/assets/{kanban-definition-UXKFOSKX-_jCmtaY1.js → kanban-definition-UXKFOSKX-BW7Ann84.js} +1 -1
  154. package/dashboard/assets/{katex-BdBmVSus.js → katex-nLxf_RlZ.js} +2 -2
  155. package/dashboard/assets/{line-Bf0nxyWf.js → line-DVxcLeru.js} +1 -1
  156. package/dashboard/assets/linear-DOM_l9bO.js +1 -0
  157. package/dashboard/assets/mermaid-parser.core-CKg9fDvJ.js +7 -0
  158. package/dashboard/assets/{mermaid.core-B4yCwiN-.js → mermaid.core-DruW_5-Y.js} +9 -9
  159. package/dashboard/assets/{mindmap-definition-YA3MSWOX-D5DjWyXj.js → mindmap-definition-YA3MSWOX-Di5W5VB3.js} +1 -1
  160. package/dashboard/assets/operations-B-t_k60U.js +194 -0
  161. package/dashboard/assets/operations-D2ZKZFOF.css +1 -0
  162. package/dashboard/assets/packet-AYTQ26CC-BABwqtNu.js +1 -0
  163. package/dashboard/assets/{pegDiagram-XKGWAZYB-Bf6a1vaf.js → pegDiagram-XKGWAZYB-Cx4ABT6q.js} +1 -1
  164. package/dashboard/assets/pie-WAS4IAKB-CNdXyrze.js +1 -0
  165. package/dashboard/assets/{pieDiagram-E7YTZNPT-D0L1qbch.js → pieDiagram-E7YTZNPT-BilfQbIs.js} +1 -1
  166. package/dashboard/assets/{quadrantDiagram-AXDQQJYC-CbFyy2Pe.js → quadrantDiagram-AXDQQJYC-BVmMQHE5.js} +1 -1
  167. package/dashboard/assets/radar-RG4KPBEZ-fKNmDeoK.js +1 -0
  168. package/dashboard/assets/railroad-74A4TZTK-DhcvDCOh.js +1 -0
  169. package/dashboard/assets/railroad-abnf-HS5TGJTU-BTRVAmf0.js +1 -0
  170. package/dashboard/assets/railroad-ebnf-LZEXJU2U-CwS8fgC_.js +1 -0
  171. package/dashboard/assets/railroad-peg-WCYAUIDC-CXuhXlNp.js +1 -0
  172. package/dashboard/assets/{railroadDiagram-O6MQD6OU-t7Gp9g2R.js → railroadDiagram-O6MQD6OU-DnBru-jf.js} +1 -1
  173. package/dashboard/assets/{requirementDiagram-BXWQKSXE-LYmqeBXi.js → requirementDiagram-BXWQKSXE-FwdvUZ7_.js} +1 -1
  174. package/dashboard/assets/{sankeyDiagram-P5KCCOFB-DnpfA_94.js → sankeyDiagram-P5KCCOFB-BQvDORai.js} +1 -1
  175. package/dashboard/assets/{sequenceDiagram-WJ2MYXX4-C8s3pTUE.js → sequenceDiagram-WJ2MYXX4-FWYQLzcY.js} +2 -2
  176. package/dashboard/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  177. package/dashboard/assets/src-BwkPhlcp.js +1 -0
  178. package/dashboard/assets/{stateDiagram-D77RDMKH-BMzm6fK1.js → stateDiagram-D77RDMKH-CjPBd_Sa.js} +1 -1
  179. package/dashboard/assets/stateDiagram-v2-MP3YSRHH-DHmenujm.js +1 -0
  180. package/dashboard/assets/swimlanes-42K2YHIH-SQLNsa4J.js +1 -0
  181. package/dashboard/assets/swimlanesDiagram-VR7AAH4N-D1bH4ETZ.js +8 -0
  182. package/dashboard/assets/{timeline-definition-24CTP7MA-BfLJMVeG.js → timeline-definition-24CTP7MA-BxCf20k1.js} +1 -1
  183. package/dashboard/assets/treeView-Q6P3EWNA-BGLYAyGp.js +1 -0
  184. package/dashboard/assets/treemap-WGGIJYW6-BlzAwncU.js +1 -0
  185. package/dashboard/assets/{vennDiagram-4TSXK5OY-BYJRHEaL.js → vennDiagram-4TSXK5OY-D76RIZLz.js} +1 -1
  186. package/dashboard/assets/wardley-WFR3VGLG-Ba_reiVw.js +1 -0
  187. package/dashboard/assets/{wardleyDiagram-VM6X3IG4-DgPN4nSe.js → wardleyDiagram-VM6X3IG4-Cux4coOD.js} +1 -1
  188. package/dashboard/assets/{xychartDiagram-S5SC5T6Z-BhkAMAOT.js → xychartDiagram-S5SC5T6Z-Ch5mvnlH.js} +1 -1
  189. package/dashboard/index.html +2 -2
  190. package/package.json +2 -5
  191. package/chunks/chunk-AV5BF4V7.js +0 -4304
  192. package/chunks/chunk-CSPF47S3.js +0 -6027
  193. package/chunks/chunk-ESM447R6.js +0 -77
  194. package/chunks/chunk-FEOPHBMY.js +0 -56
  195. package/chunks/chunk-GNR3APR6.js +0 -295
  196. package/chunks/chunk-IIBNQTOK.js +0 -1532
  197. package/chunks/chunk-JSTLXPJS.js +0 -284
  198. package/chunks/chunk-NJLKFC66.js +0 -4790
  199. package/chunks/chunk-O7Q2G2KW.js +0 -117
  200. package/chunks/chunk-VIT5ALXF.js +0 -4054
  201. package/chunks/chunk-YJU7QACE.js +0 -279
  202. package/chunks/dashboard-B2AEGCFM.js +0 -76
  203. package/chunks/eval-runner-XVRX3R2Y.js +0 -31
  204. package/chunks/hunt-scan-DXV5H6YN.js +0 -40
  205. package/chunks/managed-operation-SQFMBWHG.js +0 -60
  206. package/chunks/orchestrate-YHFJXGID.js +0 -63
  207. package/chunks/run-5T4Z3Q2D.js +0 -28242
  208. package/chunks/service-plugins-BGS6QKSZ.js +0 -64
  209. package/dashboard/assets/architecture-7GRP2DOG-hcbO-9zX.js +0 -1
  210. package/dashboard/assets/architectureDiagram-5GKGNRK7-DReOXTSq.js +0 -36
  211. package/dashboard/assets/channel-CUURBnpZ.js +0 -1
  212. package/dashboard/assets/chunk-DU6HZSFF-DgfLNaL2.js +0 -127
  213. package/dashboard/assets/classDiagram-ZZMXUADV-CD1Buc26.js +0 -1
  214. package/dashboard/assets/classDiagram-v2-VYDZK3BY-CD1Buc26.js +0 -1
  215. package/dashboard/assets/common-BMdQBwfR.js +0 -5
  216. package/dashboard/assets/cose-bilkent-JH36ORCC-CUjQHTML.js +0 -1
  217. package/dashboard/assets/cynefin-OW5HDTMX-BC7zCtFq.js +0 -1
  218. package/dashboard/assets/cytoscape.esm-CGd-uY3x.js +0 -321
  219. package/dashboard/assets/dagre-GXQ25YYZ-Dqc8FS9x.js +0 -4
  220. package/dashboard/assets/dagre-PrKaheQc.js +0 -1
  221. package/dashboard/assets/eventmodeling-NTZA5JFV-D8ZNnPkV.js +0 -1
  222. package/dashboard/assets/flowDiagram-HODETNUW-pDb1AYm8.js +0 -1
  223. package/dashboard/assets/gitGraph-4MIJSDKK-mvNUo0ZA.js +0 -1
  224. package/dashboard/assets/info-A6RAGUB7-DChKqZMi.js +0 -1
  225. package/dashboard/assets/linear-Bl6JKbf4.js +0 -1
  226. package/dashboard/assets/mermaid-parser.core-Cc6sgCzs.js +0 -7
  227. package/dashboard/assets/operations-B7JAWOi6.js +0 -130
  228. package/dashboard/assets/operations-QjKT0Hwi.css +0 -1
  229. package/dashboard/assets/packet-AYTQ26CC-bQXLDhQC.js +0 -1
  230. package/dashboard/assets/pie-WAS4IAKB-DfzoABIi.js +0 -1
  231. package/dashboard/assets/radar-RG4KPBEZ-CZ2pyeUT.js +0 -1
  232. package/dashboard/assets/railroad-74A4TZTK-CP4Jazfd.js +0 -1
  233. package/dashboard/assets/railroad-abnf-HS5TGJTU-3MvEiHwD.js +0 -1
  234. package/dashboard/assets/railroad-ebnf-LZEXJU2U-BWto6cXE.js +0 -1
  235. package/dashboard/assets/railroad-peg-WCYAUIDC-DasEjbyf.js +0 -1
  236. package/dashboard/assets/sizeCapture-INFHLROL-B0uUizjq.js +0 -1
  237. package/dashboard/assets/src-CaNUT1AQ.js +0 -1
  238. package/dashboard/assets/stateDiagram-v2-MP3YSRHH-B3REMjpY.js +0 -1
  239. package/dashboard/assets/swimlanes-42K2YHIH-uJE05Tt_.js +0 -1
  240. package/dashboard/assets/swimlanesDiagram-VR7AAH4N-CIaVMZEy.js +0 -8
  241. package/dashboard/assets/treeView-Q6P3EWNA-ZOE2enu2.js +0 -1
  242. package/dashboard/assets/treemap-WGGIJYW6-yIZoPBF5.js +0 -1
  243. package/dashboard/assets/wardley-WFR3VGLG-D5V-jLbB.js +0 -1
@@ -0,0 +1,2481 @@
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-ITHDAIRY.js";
7
+ import {
8
+ ServicePluginServices,
9
+ consoleExecutionProfile
10
+ } from "./chunk-7TIWL6E5.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-RBTJYREN.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-6TA3CWND.js";
52
+ import {
53
+ DEFAULT_REGISTRY_URL,
54
+ createConsoleRuntime,
55
+ listProjectReviewChecks,
56
+ updateProjectReviewChecks
57
+ } from "./chunk-EEP6GBUO.js";
58
+ import {
59
+ getRuntimeMetadata
60
+ } from "./chunk-D4IBEO2K.js";
61
+ import {
62
+ TOOL_DEFINITIONS,
63
+ getToolsForRole
64
+ } from "./chunk-HFUOUT2B.js";
65
+ import {
66
+ CodexCatalogRefreshError
67
+ } from "./chunk-GXSECFUE.js";
68
+ import {
69
+ LlmApiRuntime
70
+ } from "./chunk-EIONVEFN.js";
71
+ import {
72
+ aggregateCapabilities,
73
+ disable,
74
+ isSafePluginId,
75
+ listInstalledPluginIds,
76
+ pluginsRootDir,
77
+ readEnablement,
78
+ readInstalledPlugin,
79
+ writeEnablement
80
+ } from "./chunk-27SXCYWH.js";
81
+ import {
82
+ MODEL_PRICING,
83
+ VERSION,
84
+ getRates,
85
+ homeStateDir,
86
+ modelProvider,
87
+ registerModelPricing
88
+ } from "./chunk-S3B6HFSM.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 } from "node:path";
94
+ import { randomUUID as randomUUID2 } from "node:crypto";
95
+
96
+ // packages/cli/src/tui/model-preference.ts
97
+ async function createPreferredConsoleRuntime(config, options = {}) {
98
+ const env = config.env ?? process.env;
99
+ const envModel = env["ZERO_MODEL"]?.trim();
100
+ const envProvider = env["ZERO_SELECTED_PROVIDER"]?.trim() || env["ZERO_PROVIDER"]?.trim() || env["ZERO_FORCE_PROVIDER"]?.trim();
101
+ const inherited = options.inheritedConnectionIdentity !== void 0;
102
+ const explicitChoice = !inherited && config.model !== void 0 || Boolean(envModel);
103
+ if (inherited && (envModel || envProvider)) config = { ...config, model: void 0, provider: void 0 };
104
+ if (config.provider === void 0 && envProvider) config = { ...config, provider: envProvider };
105
+ let runtime;
106
+ let retainedModel = false;
107
+ if (inherited && !envModel && !envProvider) {
108
+ runtime = createConsoleRuntime({ ...config, model: void 0 });
109
+ if (runtime.connectionIdentity() === options.inheritedConnectionIdentity) {
110
+ runtime.reconfigure({ model: config.model });
111
+ retainedModel = config.model !== void 0;
112
+ }
113
+ }
114
+ if (!explicitChoice && !retainedModel) {
115
+ const saved = getSettings().modelPreference;
116
+ if (saved && (config.provider === void 0 || config.provider === saved.providerId)) {
117
+ try {
118
+ const candidate = createConsoleRuntime({ ...config, model: saved.model, provider: saved.providerId });
119
+ if (candidate.connectionIdentity() === saved.connectionIdentity) {
120
+ runtime = candidate;
121
+ retainedModel = true;
122
+ }
123
+ } catch {
124
+ }
125
+ }
126
+ }
127
+ runtime ??= createConsoleRuntime(config);
128
+ if (!explicitChoice && runtime.getConfigurationDiagnostics().provider === "chatgpt-codex") {
129
+ let catalog;
130
+ try {
131
+ catalog = await runtime.codexModelCatalog(AbortSignal.timeout(1e4));
132
+ } catch (error) {
133
+ options.onDiscoveryError?.(error);
134
+ if (error instanceof CodexCatalogRefreshError) catalog = error.cachedModels;
135
+ else if (!retainedModel) throw error;
136
+ }
137
+ if (catalog) {
138
+ if (!catalog.length) throw new Error("This ChatGPT subscription returned no available models.");
139
+ const currentModel = runtime.resolvedModel();
140
+ if (!retainedModel || !catalog.some((model) => model.id === currentModel)) {
141
+ runtime.reconfigure({ model: catalog[0].id });
142
+ }
143
+ }
144
+ }
145
+ return { runtime, explicitChoice };
146
+ }
147
+ function saveAppliedModelPreference(runtime) {
148
+ const connectionIdentity = runtime.connectionIdentity();
149
+ if (!connectionIdentity) return false;
150
+ const preference = {
151
+ providerId: runtime.getConfigurationDiagnostics().provider,
152
+ model: runtime.resolvedModel(),
153
+ connectionIdentity
154
+ };
155
+ return updateSetting("modelPreference", preference, { scope: "global" });
156
+ }
157
+
158
+ // packages/cli/src/tui/model-catalog-sync.ts
159
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
160
+ import { dirname, join } from "node:path";
161
+
162
+ // packages/cli/src/tui/model-catalog.offline.ts
163
+ var OFFLINE_MODEL_CATALOG = [
164
+ // Anthropic
165
+ { id: "claude-fable-5-1", provider: "anthropic", contextTokens: 1e6, input: 10, output: 50 },
166
+ { id: "claude-opus-5", provider: "anthropic", contextTokens: 1e6, input: 5, output: 25 },
167
+ { id: "claude-sonnet-5", provider: "anthropic", contextTokens: 1e6, input: 2, output: 10 },
168
+ { id: "claude-opus-4-7", provider: "anthropic", contextTokens: 2e5, input: 5, output: 25 },
169
+ { id: "claude-sonnet-4-6", provider: "anthropic", contextTokens: 1e6, input: 3, output: 15 },
170
+ { id: "claude-haiku-4-5", provider: "anthropic", contextTokens: 2e5, input: 0.8, output: 4 },
171
+ // OpenAI
172
+ // Astra standard short-context rates; >272K input has a separate price tier.
173
+ { id: "gpt-6-astra", provider: "openai", contextTokens: 105e4, input: 10, output: 50 },
174
+ { id: "gpt-6.1-sol", provider: "openai", contextTokens: 105e4, input: 2, output: 10 },
175
+ { id: "gpt-6-sol", provider: "openai", contextTokens: 105e4, input: 2, output: 10 },
176
+ { id: "gpt-6-luna", provider: "openai", contextTokens: 105e4, input: 0.1, output: 0.5 },
177
+ { id: "gpt-5.5", provider: "openai", contextTokens: 4e5, input: 5, output: 30 },
178
+ { id: "gpt-5.6-sol", provider: "openai", contextTokens: 105e4 },
179
+ { id: "gpt-5.6-terra", provider: "openai", contextTokens: 105e4 },
180
+ { id: "gpt-5.6-luna", provider: "openai", contextTokens: 105e4 },
181
+ // Google
182
+ { id: "gemini-3.8-flash", provider: "google", contextTokens: 1048576, input: 0.75, output: 3.75 },
183
+ { id: "gemini-3.5-flash-lite", provider: "google", contextTokens: 1048576, input: 0.3, output: 2.5 },
184
+ { id: "gemini-3.1-pro-preview", provider: "google", contextTokens: 1048576, input: 2, output: 12 },
185
+ // DeepSeek
186
+ { id: "deepseek-flash", provider: "deepseek", contextTokens: 1e6, input: 0.3, output: 1.2 },
187
+ // Meta (hosted)
188
+ { id: "llama-4-maverick", provider: "meta", contextTokens: 1e6, input: 0.5, output: 0.77 },
189
+ { id: "llama-4-scout", provider: "meta", contextTokens: 1e7, input: 0.2, output: 0.35 },
190
+ // Mistral
191
+ { id: "mistral-large", provider: "mistral", contextTokens: 128e3, input: 2, output: 6 },
192
+ // Alibaba Qwen
193
+ { id: "qwen3.8-max", provider: "qwen", contextTokens: 1e6, input: 2, output: 6 },
194
+ { id: "qwen3.8-flash", provider: "qwen", contextTokens: 1e6, input: 0.15, output: 0.47 },
195
+ { id: "qwen3.8-max-preview", provider: "qwen", contextTokens: 1e6 },
196
+ { id: "qwen3.7-max", provider: "qwen", contextTokens: 1e6, input: 2.5, output: 7.5 },
197
+ { id: "qwen3.7-plus", provider: "qwen", contextTokens: 1e6, input: 0.5, output: 3 },
198
+ { id: "qwen3.6-plus", provider: "qwen", contextTokens: 1e6, input: 0.5, output: 3 },
199
+ { id: "qwen3.6-flash", provider: "qwen", contextTokens: 1e6, input: 0.1875, output: 1.125 },
200
+ // xAI
201
+ { id: "grok-4.6", provider: "xai", contextTokens: 5e5, input: 2, output: 6 },
202
+ // Moonshot
203
+ { id: "k3", provider: "moonshot", contextTokens: 1048576, input: 3, output: 15 },
204
+ // Z.AI
205
+ { id: "glm-5.3", provider: "z-ai", contextTokens: 1e6, input: 1.4, output: 4.4 },
206
+ { id: "glm-5.3-flash", provider: "z-ai", contextTokens: 1e6, input: 0.15, output: 0.5 }
207
+ ];
208
+
209
+ // packages/cli/src/tui/model-catalog-sync.ts
210
+ var MODELS_DEV_URL = "https://models.dev/api.json";
211
+ var CATALOG_CACHE_FILENAME = "model-catalog.json";
212
+ var CATALOG_TTL_MS = 24 * 60 * 60 * 1e3;
213
+ var FETCH_TIMEOUT_MS = 8e3;
214
+ var CATALOG_PROVIDER_IDS = {
215
+ "alibaba-token-plan": "qwen",
216
+ "kimi-code-plan-cn": "kimi",
217
+ "github-copilot": "copilot",
218
+ zai: "z-ai",
219
+ "cline-pass": "cline"
220
+ };
221
+ var METERED_CATALOG_PROVIDERS = {
222
+ anthropic: true,
223
+ openai: true,
224
+ deepseek: true,
225
+ openrouter: true,
226
+ xai: true,
227
+ opencode: true,
228
+ cline: true
229
+ };
230
+ function catalogId(value) {
231
+ return typeof value === "string" && value.length > 0 && !/[\s\x00-\x1f\x7f-\x9f]/.test(value);
232
+ }
233
+ function finiteRate(value) {
234
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
235
+ }
236
+ function contextTokens(value) {
237
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
238
+ }
239
+ function normalizedModel(value) {
240
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
241
+ const row = value;
242
+ if (!catalogId(row.id) || !catalogId(row.provider) || row.provider === "chatgpt-codex") return null;
243
+ const provider2 = Object.hasOwn(CATALOG_PROVIDER_IDS, row.provider) ? CATALOG_PROVIDER_IDS[row.provider] ?? row.provider : row.provider;
244
+ const model = {
245
+ id: row.provider === "cline-pass" && !row.id.startsWith("cline-pass/") ? `cline-pass/${row.id}` : row.id,
246
+ provider: provider2,
247
+ ...finiteRate(row.input) ? { input: row.input } : {},
248
+ ...finiteRate(row.output) ? { output: row.output } : {},
249
+ ...finiteRate(row.cachedInput) ? { cachedInput: row.cachedInput } : {},
250
+ ...contextTokens(row.contextTokens) ? { contextTokens: row.contextTokens } : {}
251
+ };
252
+ if (!(provider2 === "cline" && model.id.startsWith("cline-pass/")) && Object.hasOwn(METERED_CATALOG_PROVIDERS, provider2) && model.input !== void 0 && model.output !== void 0) {
253
+ const rates = { input: model.input, output: model.output, cachedInput: model.cachedInput };
254
+ registerModelPricing(`${provider2}/${model.id}`, rates);
255
+ if (provider2 === modelProvider(model.id)) registerModelPricing(model.id, rates);
256
+ }
257
+ return model;
258
+ }
259
+ function catalogCachePath(opts = {}) {
260
+ return opts.cachePath ?? join(homeStateDir(), CATALOG_CACHE_FILENAME);
261
+ }
262
+ function normalizeModelsDev(raw) {
263
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return [];
264
+ const out = [];
265
+ for (const [providerId, providerVal] of Object.entries(raw)) {
266
+ if (!catalogId(providerId) || typeof providerVal !== "object" || providerVal === null || Array.isArray(providerVal)) continue;
267
+ const models = providerVal["models"];
268
+ if (typeof models !== "object" || models === null || Array.isArray(models)) continue;
269
+ for (const [modelId, modelVal] of Object.entries(models)) {
270
+ if (!catalogId(modelId) || typeof modelVal !== "object" || modelVal === null || Array.isArray(modelVal)) continue;
271
+ const m = modelVal;
272
+ const cost = typeof m["cost"] === "object" && m["cost"] !== null ? m["cost"] : {};
273
+ const limit = typeof m["limit"] === "object" && m["limit"] !== null ? m["limit"] : {};
274
+ const entry = normalizedModel({
275
+ id: modelId,
276
+ provider: providerId,
277
+ input: cost["input"],
278
+ output: cost["output"],
279
+ cachedInput: cost["cache_read"],
280
+ contextTokens: limit["context"]
281
+ });
282
+ if (entry) out.push(entry);
283
+ }
284
+ }
285
+ return out;
286
+ }
287
+ function readCache(path) {
288
+ try {
289
+ if (!existsSync(path)) return null;
290
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
291
+ if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.models) || !Number.isFinite(parsed.fetchedAt) || parsed.fetchedAt < 0 || typeof parsed.source !== "string") {
292
+ return null;
293
+ }
294
+ const cache = parsed;
295
+ const models = cache.models.flatMap((row) => {
296
+ const model = normalizedModel(row);
297
+ return model ? [model] : [];
298
+ });
299
+ return { fetchedAt: cache.fetchedAt, source: cache.source, models };
300
+ } catch {
301
+ return null;
302
+ }
303
+ }
304
+ function writeCache(path, cache) {
305
+ try {
306
+ mkdirSync(dirname(path), { recursive: true });
307
+ writeFileSync(path, JSON.stringify(cache, null, 2), { mode: 384 });
308
+ } catch {
309
+ }
310
+ }
311
+ function isCacheFresh(cache, opts = {}) {
312
+ if (!cache) return false;
313
+ const now = (opts.now ?? Date.now)();
314
+ const ttl = opts.ttlMs ?? CATALOG_TTL_MS;
315
+ const age = now - cache.fetchedAt;
316
+ return Number.isFinite(age) && age >= 0 && age < ttl;
317
+ }
318
+ function loadCatalogModels(opts = {}) {
319
+ const cache = readCache(catalogCachePath(opts));
320
+ if (cache && cache.models.length > 0) return cache;
321
+ return { fetchedAt: 0, source: "offline", models: OFFLINE_MODEL_CATALOG };
322
+ }
323
+ async function syncModelCatalog(opts = {}) {
324
+ const path = catalogCachePath(opts);
325
+ const existing = readCache(path);
326
+ if (!opts.force && isCacheFresh(existing, opts) && (existing?.models.length ?? 0) > 0) {
327
+ return existing;
328
+ }
329
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
330
+ if (typeof fetchImpl !== "function") return null;
331
+ const url = opts.url ?? MODELS_DEV_URL;
332
+ const controller = new AbortController();
333
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
334
+ try {
335
+ const res = await fetchImpl(url, { signal: controller.signal });
336
+ if (!res.ok) return null;
337
+ const json = await res.json();
338
+ const models = normalizeModelsDev(json);
339
+ if (models.length === 0) return null;
340
+ const cache = {
341
+ fetchedAt: (opts.now ?? Date.now)(),
342
+ source: url,
343
+ models
344
+ };
345
+ writeCache(path, cache);
346
+ return cache;
347
+ } catch {
348
+ return null;
349
+ } finally {
350
+ clearTimeout(timer);
351
+ }
352
+ }
353
+
354
+ // packages/cli/src/tui/model-catalog.ts
355
+ var NON_MODEL_PRICING_KEYS = /* @__PURE__ */ new Set(["default"]);
356
+ function compareStrings(a, b) {
357
+ if (a === b) return 0;
358
+ return a < b ? -1 : 1;
359
+ }
360
+ function formatRate(value) {
361
+ return String(Number(value.toFixed(4)));
362
+ }
363
+ function formatModelPrice(input, output) {
364
+ if (input === 0 && output === 0) return "free";
365
+ return `$${formatRate(input)}/${formatRate(output)} per M`;
366
+ }
367
+ function buildModelCatalog(currentModel) {
368
+ const models = Object.keys(MODEL_PRICING).filter((id) => !NON_MODEL_PRICING_KEYS.has(id)).map((id) => {
369
+ const provider2 = modelProvider(id);
370
+ const rates = getRates(Object.hasOwn(METERED_CATALOG_PROVIDERS, provider2) ? `${provider2}/${id}` : id);
371
+ return { id, provider: provider2, price: provider2 === "cline" && id.startsWith("cline-pass/") ? "ClinePass plan (access unverified)" : formatModelPrice(rates.input, rates.output) };
372
+ });
373
+ return models.sort((a, b) => {
374
+ if (a.id === currentModel) return b.id === currentModel ? 0 : -1;
375
+ if (b.id === currentModel) return 1;
376
+ return compareStrings(a.provider, b.provider) || compareStrings(a.id, b.id);
377
+ });
378
+ }
379
+ var PLAN_PROVIDERS = {
380
+ kimi: true,
381
+ qwen: true,
382
+ "z-ai": true,
383
+ copilot: true,
384
+ google: true
385
+ };
386
+ function compareCatalogRows(currentModel) {
387
+ return (a, b) => {
388
+ if (a.id === currentModel) return b.id === currentModel ? 0 : -1;
389
+ if (b.id === currentModel) return 1;
390
+ return compareStrings(a.provider, b.provider) || compareStrings(a.id, b.id);
391
+ };
392
+ }
393
+ function catalogExtras(opts = {}) {
394
+ const priced = new Set(Object.keys(MODEL_PRICING).map((k) => k.toLowerCase()));
395
+ const out = [];
396
+ for (const m of loadCatalogModels(opts).models) {
397
+ if (priced.has(m.id.toLowerCase()) && m.provider === modelProvider(m.id)) continue;
398
+ const plan = Object.hasOwn(PLAN_PROVIDERS, m.provider) || m.provider === "cline" && m.id.startsWith("cline-pass/");
399
+ let price = m.provider === "cline" && plan ? "ClinePass plan (access unverified)" : plan ? "subscription" : "\u2014";
400
+ if (!plan && m.input !== void 0 && m.output !== void 0) {
401
+ const rates = Object.hasOwn(METERED_CATALOG_PROVIDERS, m.provider) ? getRates(`${m.provider}/${m.id}`) : { input: m.input, output: m.output };
402
+ price = formatModelPrice(rates.input, rates.output);
403
+ }
404
+ out.push({ id: m.id, provider: m.provider, price });
405
+ }
406
+ return out;
407
+ }
408
+ function buildFullModelCatalog(currentModel, opts = {}) {
409
+ const extras = catalogExtras(opts);
410
+ const priced = buildModelCatalog(currentModel);
411
+ const models = [...priced, ...extras];
412
+ if (currentModel && !models.some((model) => model.id === currentModel)) {
413
+ models.push({ id: currentModel, provider: modelProvider(currentModel), price: "\u2014" });
414
+ }
415
+ return models.sort(compareCatalogRows(currentModel));
416
+ }
417
+
418
+ // packages/cli/src/tui/available-models.ts
419
+ async function discoverConnectionModels(env, providerIds, signal) {
420
+ const results = await Promise.all(providerIds.map(async (providerId) => {
421
+ try {
422
+ const runtime = new LlmApiRuntime({
423
+ type: "api",
424
+ timeout: 1e4,
425
+ provider: providerId,
426
+ model: "probe",
427
+ env: { ...env, ZERO_SKIP_PROVIDER_BANNER: "1" }
428
+ });
429
+ const models = await runtime.availableModelCatalog(signal ?? AbortSignal.timeout(1e4));
430
+ return { models: models.map((model) => ({ ...model, provider: providerId })), diagnostics: [] };
431
+ } catch (error) {
432
+ let message = error instanceof Error ? error.message : "Model discovery failed.";
433
+ for (const [name, value] of Object.entries(env)) {
434
+ if (value && /KEY|TOKEN|SECRET|PASSWORD/i.test(name)) message = message.split(value).join("[redacted]");
435
+ }
436
+ return { models: [], diagnostics: [{ providerId, message: message.slice(0, 1e3) }] };
437
+ }
438
+ }));
439
+ return { models: results.flatMap((result) => result.models), diagnostics: results.flatMap((result) => result.diagnostics) };
440
+ }
441
+
442
+ // packages/cli/src/tui/context-window.ts
443
+ var KNOWN_FAMILY_WINDOWS = [
444
+ ["gpt-5", 272e3],
445
+ ["gpt-4.1", 1047576],
446
+ ["gpt-4o", 128e3],
447
+ ["o3", 2e5],
448
+ ["o4", 2e5],
449
+ ["claude", 2e5],
450
+ ["glm-5", 2e5],
451
+ ["glm-4", 128e3],
452
+ ["gemini-2.5", 1048576],
453
+ ["gemini-2", 1e6],
454
+ ["deepseek", 128e3],
455
+ ["qwen", 128e3]
456
+ ];
457
+ function knownFamilyWindow(modelId) {
458
+ const id = modelId.toLowerCase();
459
+ let best = null;
460
+ let bestLen = -1;
461
+ for (const [prefix, tokens] of KNOWN_FAMILY_WINDOWS) {
462
+ if (id.startsWith(prefix) && prefix.length > bestLen) {
463
+ best = tokens;
464
+ bestLen = prefix.length;
465
+ }
466
+ }
467
+ return best;
468
+ }
469
+ function positiveTokens(value) {
470
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
471
+ }
472
+ function sameByokModel(row, identity) {
473
+ return row.id === identity.modelId && row.provider === identity.providerId;
474
+ }
475
+ function resolveContextLimit(identity, opts = {}) {
476
+ if (!identity.modelId || !identity.providerId) return null;
477
+ const familyFallback = () => {
478
+ const family = knownFamilyWindow(identity.modelId);
479
+ return family === null ? null : { tokens: family, source: "known-family" };
480
+ };
481
+ const load = opts.loadModels ?? loadCatalogModels;
482
+ const cache = load(opts.sync ?? {});
483
+ const row = cache.models.find((model) => sameByokModel(model, identity));
484
+ const tokens = row ? positiveTokens(row.contextTokens) : null;
485
+ if (tokens !== null) {
486
+ return { tokens, source: cache.source === "offline" ? "offline-catalog" : "synced-catalog" };
487
+ }
488
+ return familyFallback();
489
+ }
490
+
491
+ // packages/cli/src/tui/device-auth.ts
492
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
493
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
494
+ import { createServer } from "node:http";
495
+ import { arch, hostname, platform as platform2, release, version as osVersion } from "node:os";
496
+ import { join as join2 } from "node:path";
497
+
498
+ // packages/cli/src/open-browser.ts
499
+ import { spawn } from "node:child_process";
500
+ import { platform } from "node:os";
501
+ function defaultOpenBrowser(url) {
502
+ const plat = platform();
503
+ return new Promise((resolve2, reject) => {
504
+ const options = { detached: true, stdio: "ignore", shell: false };
505
+ const child = plat === "darwin" ? spawn("open", [url], options) : plat === "win32" ? spawn("powershell.exe", [
506
+ "-NoProfile",
507
+ "-NonInteractive",
508
+ "-Command",
509
+ "Start-Process -FilePath $env:OSEC_BROWSER_LOGIN_URL"
510
+ ], { ...options, env: { ...process.env, OSEC_BROWSER_LOGIN_URL: url } }) : spawn("xdg-open", [url], options);
511
+ child.once("error", reject);
512
+ child.once("spawn", () => {
513
+ child.unref();
514
+ resolve2();
515
+ });
516
+ });
517
+ }
518
+
519
+ // packages/cli/src/tui/text.ts
520
+ var DEFAULT_ENCODED_RUN_MAX = 140;
521
+ var ENCODED_RUN_MAX_CAP = 1e6;
522
+ var ENCODED_PLACEHOLDER = "[encoded payload omitted]";
523
+ var DEFAULT_ENCODED_SEGMENT = new RegExp(`[A-Za-z0-9+_-]{${DEFAULT_ENCODED_RUN_MAX},}={0,2}`, "g");
524
+ var DEFAULT_ENCODED_DATA_URI = new RegExp(`(data:[^\\s,]*;base64,)[A-Za-z0-9+/_-]{${DEFAULT_ENCODED_RUN_MAX},}={0,2}`, "gi");
525
+ function stripTerminalControl(text2) {
526
+ return text2.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
527
+ }
528
+ function replaceLargeEncodedChunks(text2, maxEncodedRun) {
529
+ const normalized = Number.isFinite(maxEncodedRun) ? Math.trunc(maxEncodedRun) : DEFAULT_ENCODED_RUN_MAX;
530
+ const minRun = Math.min(Math.max(32, normalized), ENCODED_RUN_MAX_CAP);
531
+ if (text2.length < minRun) return text2;
532
+ const segment = minRun === DEFAULT_ENCODED_RUN_MAX ? DEFAULT_ENCODED_SEGMENT : new RegExp(`[A-Za-z0-9+_-]{${minRun},}={0,2}`, "g");
533
+ const dataUri = minRun === DEFAULT_ENCODED_RUN_MAX ? DEFAULT_ENCODED_DATA_URI : new RegExp(`(data:[^\\s,]*;base64,)[A-Za-z0-9+/_-]{${minRun},}={0,2}`, "gi");
534
+ return text2.replace(dataUri, `$1${ENCODED_PLACEHOLDER}`).replace(segment, ENCODED_PLACEHOLDER);
535
+ }
536
+ function sanitizeTuiText(value, options = {}) {
537
+ return stripTerminalControl(replaceLargeEncodedChunks(String(value ?? ""), options.maxEncodedRun ?? DEFAULT_ENCODED_RUN_MAX)).replace(/\s+/g, " ").trim();
538
+ }
539
+ function sanitizeComposerText(value) {
540
+ return stripTerminalControl(String(value ?? ""));
541
+ }
542
+
543
+ // packages/cli/src/tui/device-auth.ts
544
+ var MAX_VISIBLE_LINES = 8;
545
+ var DEFAULT_INTERVAL_SECONDS = 5;
546
+ var SLOW_DOWN_INCREMENT_SECONDS = 5;
547
+ var DEFAULT_EXPIRES_IN_SECONDS = 900;
548
+ var defaultFetch = (url, init) => globalThis.fetch(url, init);
549
+ var defaultSleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
550
+ var PKCE_TIMEOUT_SECONDS = 300;
551
+ var base64url = (buffer) => buffer.toString("base64url");
552
+ var defaultCreatePkcePair = () => {
553
+ const verifier = base64url(randomBytes(32));
554
+ const challenge = base64url(createHash("sha256").update(verifier).digest());
555
+ return { verifier, challenge };
556
+ };
557
+ var defaultServerFactory = async ({ onRedirect }) => {
558
+ let delivered = false;
559
+ const server = createServer((req, res) => {
560
+ const requestUrl = new URL(req.url ?? "/", "http://127.0.0.1");
561
+ if (requestUrl.pathname !== "/callback") {
562
+ res.statusCode = 404;
563
+ res.end("Not found");
564
+ return;
565
+ }
566
+ const code = requestUrl.searchParams.get("code") ?? void 0;
567
+ const error = requestUrl.searchParams.get("error") ?? void 0;
568
+ res.statusCode = 200;
569
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
570
+ 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>");
571
+ if (delivered) return;
572
+ delivered = true;
573
+ onRedirect({ code, error });
574
+ });
575
+ await new Promise((resolve2, reject) => {
576
+ server.once("error", reject);
577
+ server.listen(0, "127.0.0.1", () => resolve2());
578
+ });
579
+ const address = server.address();
580
+ const port = typeof address === "object" && address !== null ? address.port : 0;
581
+ return { port, close: () => server.close() };
582
+ };
583
+ function providerLabel(providerId) {
584
+ return PROVIDERS.find((provider2) => provider2.id === providerId)?.label ?? providerId;
585
+ }
586
+ function positiveInt(value, fallback) {
587
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : fallback;
588
+ }
589
+ function isPlainObject(value) {
590
+ return typeof value === "object" && value !== null && !Array.isArray(value);
591
+ }
592
+ function startDeviceAuth(config, options) {
593
+ const env = options.env ?? process.env;
594
+ const doFetch = options.fetch ?? defaultFetch;
595
+ const now = options.now ?? Date.now;
596
+ const sleep = options.sleep ?? defaultSleep;
597
+ const openBrowser = options.openBrowser ?? defaultOpenBrowser;
598
+ const label = providerLabel(config.providerId);
599
+ const lines = [];
600
+ let settled = false;
601
+ let cancelled = false;
602
+ const pushLine = (text2) => {
603
+ const value = sanitizeTuiText(text2);
604
+ if (value.length === 0) return;
605
+ lines.push(value);
606
+ if (lines.length > MAX_VISIBLE_LINES) lines.shift();
607
+ };
608
+ const publish = (phase, message) => {
609
+ options.onUpdate({ phase, lines: [...lines], message });
610
+ };
611
+ const finish = (phase, message) => {
612
+ if (settled) return;
613
+ settled = true;
614
+ publish(phase, message);
615
+ };
616
+ const requestDeviceCode = async (cfg) => {
617
+ const params = new URLSearchParams({ client_id: cfg.clientId });
618
+ if (cfg.scopes.length > 0) params.set("scope", cfg.scopes.join(" "));
619
+ const response = await doFetch(cfg.deviceCodeUrl, {
620
+ method: "POST",
621
+ headers: {
622
+ "Content-Type": "application/x-www-form-urlencoded",
623
+ Accept: "application/json",
624
+ ...cfg.buildHeaders?.(options.homeDir)
625
+ },
626
+ body: params.toString()
627
+ });
628
+ if (!response.ok) {
629
+ throw new Error(`Device code request failed (HTTP ${response.status}).`);
630
+ }
631
+ const parsed = await response.json();
632
+ if (!isPlainObject(parsed) || typeof parsed.device_code !== "string" || typeof parsed.user_code !== "string") {
633
+ throw new Error("Device code response was missing a device_code or user_code.");
634
+ }
635
+ const verificationUri = typeof parsed.verification_uri === "string" ? parsed.verification_uri : typeof parsed.verification_uri_complete === "string" ? parsed.verification_uri_complete : void 0;
636
+ if (verificationUri === void 0) {
637
+ throw new Error("Device code response was missing a verification URL.");
638
+ }
639
+ return {
640
+ device_code: parsed.device_code,
641
+ user_code: parsed.user_code,
642
+ verification_uri: verificationUri,
643
+ verification_uri_complete: typeof parsed.verification_uri_complete === "string" ? parsed.verification_uri_complete : void 0,
644
+ interval: positiveInt(parsed.interval, DEFAULT_INTERVAL_SECONDS),
645
+ expires_in: positiveInt(parsed.expires_in, DEFAULT_EXPIRES_IN_SECONDS)
646
+ };
647
+ };
648
+ const pollTokenOnce = async (cfg, deviceCode) => {
649
+ const body = new URLSearchParams({
650
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
651
+ device_code: deviceCode,
652
+ client_id: cfg.clientId
653
+ }).toString();
654
+ let response;
655
+ try {
656
+ response = await doFetch(cfg.tokenUrl, {
657
+ method: "POST",
658
+ headers: {
659
+ "Content-Type": "application/x-www-form-urlencoded",
660
+ Accept: "application/json",
661
+ ...cfg.buildHeaders?.(options.homeDir)
662
+ },
663
+ body
664
+ });
665
+ } catch (error) {
666
+ return { kind: "failed", message: error instanceof Error ? error.message : String(error) };
667
+ }
668
+ let parsed;
669
+ try {
670
+ parsed = await response.json();
671
+ } catch {
672
+ return { kind: "failed", message: `Token response was not valid JSON (HTTP ${response.status}).` };
673
+ }
674
+ if (response.ok && isPlainObject(parsed) && typeof parsed.access_token === "string") {
675
+ return { kind: "token", response: parsed };
676
+ }
677
+ const oauthError = isPlainObject(parsed) && typeof parsed.error === "string" ? parsed.error : void 0;
678
+ switch (oauthError) {
679
+ case "authorization_pending":
680
+ return { kind: "pending" };
681
+ case "slow_down":
682
+ return { kind: "slow_down" };
683
+ case "expired_token":
684
+ return { kind: "failed", message: `${label} device sign-in code expired. Start again.` };
685
+ case "access_denied":
686
+ return { kind: "failed", message: `${label} device sign-in was denied.` };
687
+ default:
688
+ return {
689
+ kind: "failed",
690
+ message: oauthError ? `${label} device sign-in failed: ${oauthError}.` : `${label} device sign-in failed (HTTP ${response.status}).`
691
+ };
692
+ }
693
+ };
694
+ const persist = (record, connectedMessage) => {
695
+ const { store } = addAccount(loadAccountStore(options.homeDir), config.providerId, record);
696
+ if (!saveAccountStore(store, options.homeDir)) {
697
+ 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.");
698
+ return;
699
+ }
700
+ const patch = accountEnvPatch(store, env);
701
+ for (const [key, value] of Object.entries(patch)) env[key] = value;
702
+ finish("connected", connectedMessage);
703
+ options.onConnected();
704
+ };
705
+ const runDeviceCode = async (cfg) => {
706
+ publish("running", `Starting ${label} device sign-in\u2026`);
707
+ let device;
708
+ try {
709
+ device = await requestDeviceCode(cfg);
710
+ } catch (error) {
711
+ finish("failed", error instanceof Error ? error.message : String(error));
712
+ return;
713
+ }
714
+ if (cancelled) {
715
+ finish("cancelled", `${label} device sign-in cancelled.`);
716
+ return;
717
+ }
718
+ const openUrl = device.verification_uri_complete ?? device.verification_uri;
719
+ pushLine(`Enter code: ${device.user_code}`);
720
+ pushLine(`Visit: ${device.verification_uri}`);
721
+ publish("running", `Complete the ${label} device sign-in in your browser.`);
722
+ try {
723
+ await openBrowser(openUrl);
724
+ } catch {
725
+ pushLine("Could not open a browser automatically; open the URL above.");
726
+ publish("running", `Complete the ${label} device sign-in in your browser.`);
727
+ }
728
+ let intervalSeconds = device.interval ?? DEFAULT_INTERVAL_SECONDS;
729
+ const deadline = now() + (device.expires_in ?? DEFAULT_EXPIRES_IN_SECONDS) * 1e3;
730
+ while (!cancelled) {
731
+ await sleep(intervalSeconds * 1e3);
732
+ if (cancelled) break;
733
+ if (now() >= deadline) {
734
+ finish("failed", `${label} device sign-in timed out. Start again.`);
735
+ return;
736
+ }
737
+ const result = await pollTokenOnce(cfg, device.device_code);
738
+ if (cancelled) break;
739
+ if (result.kind === "token") {
740
+ persist(cfg.toAccountRecord(result.response), `${label} connected through device sign-in.`);
741
+ return;
742
+ }
743
+ if (result.kind === "failed") {
744
+ finish("failed", result.message);
745
+ return;
746
+ }
747
+ if (result.kind === "slow_down") {
748
+ intervalSeconds += SLOW_DOWN_INCREMENT_SECONDS;
749
+ }
750
+ }
751
+ finish("cancelled", `${label} device sign-in cancelled.`);
752
+ };
753
+ const exchangeCode = async (cfg, code, verifier, redirectUri) => {
754
+ const useForm = cfg.exchangeBodyMode === "form";
755
+ const headers = useForm ? { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" } : { "Content-Type": "application/json", Accept: "application/json" };
756
+ const body = useForm ? new URLSearchParams({
757
+ grant_type: "authorization_code",
758
+ code,
759
+ code_verifier: verifier,
760
+ redirect_uri: redirectUri,
761
+ ...cfg.clientId !== void 0 ? { client_id: cfg.clientId } : {},
762
+ ...cfg.clientSecret !== void 0 ? { client_secret: cfg.clientSecret } : {}
763
+ }).toString() : JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" });
764
+ let response;
765
+ try {
766
+ response = await doFetch(cfg.keysUrl, {
767
+ method: "POST",
768
+ headers,
769
+ body
770
+ });
771
+ } catch (error) {
772
+ return { kind: "failed", message: error instanceof Error ? error.message : String(error) };
773
+ }
774
+ let parsed;
775
+ try {
776
+ parsed = await response.json();
777
+ } catch {
778
+ return { kind: "failed", message: `${label} sign-in exchange was not valid JSON (HTTP ${response.status}).` };
779
+ }
780
+ if (!response.ok) {
781
+ const oauthError = isPlainObject(parsed) && typeof parsed.error === "string" ? parsed.error : void 0;
782
+ return {
783
+ kind: "failed",
784
+ message: oauthError ? `${label} browser sign-in failed: ${oauthError}.` : `${label} browser sign-in failed (HTTP ${response.status}).`
785
+ };
786
+ }
787
+ if (!isPlainObject(parsed)) {
788
+ return { kind: "failed", message: `${label} sign-in exchange returned an unexpected body.` };
789
+ }
790
+ return { kind: "ok", response: parsed };
791
+ };
792
+ const runPkceLoopback = async (cfg) => {
793
+ publish("running", `Starting ${label} browser sign-in\u2026`);
794
+ const { verifier, challenge } = (options.createPkcePair ?? defaultCreatePkcePair)();
795
+ const serverFactory = options.serverFactory ?? defaultServerFactory;
796
+ let resolveOutcome = () => {
797
+ };
798
+ const outcomePromise = new Promise((resolve2) => {
799
+ resolveOutcome = resolve2;
800
+ });
801
+ let server;
802
+ try {
803
+ server = await serverFactory({
804
+ onRedirect: (redirect) => resolveOutcome({ type: "redirect", redirect })
805
+ });
806
+ } catch (error2) {
807
+ finish("failed", `${label} browser sign-in could not start a local server: ${error2 instanceof Error ? error2.message : String(error2)}.`);
808
+ return;
809
+ }
810
+ cancelWaiter = () => resolveOutcome({ type: "cancelled" });
811
+ if (cancelled) {
812
+ server.close();
813
+ finish("cancelled", `${label} browser sign-in cancelled.`);
814
+ return;
815
+ }
816
+ const redirectUri = `http://localhost:${server.port}/callback`;
817
+ const state = base64url(randomBytes(16)).replace(/[^a-zA-Z0-9]/g, "").slice(0, 32);
818
+ const authorizeUrl = new URL(cfg.authorizeUrl);
819
+ authorizeUrl.searchParams.set(cfg.redirectParam ?? "redirect_uri", redirectUri);
820
+ authorizeUrl.searchParams.set("code_challenge", challenge);
821
+ authorizeUrl.searchParams.set("code_challenge_method", "S256");
822
+ if (cfg.clientId !== void 0) authorizeUrl.searchParams.set("client_id", cfg.clientId);
823
+ if (cfg.scopes.length > 0) authorizeUrl.searchParams.set("scope", cfg.scopes.join(" "));
824
+ for (const [key, value] of Object.entries(cfg.authorizeParams ?? {})) {
825
+ authorizeUrl.searchParams.set(key, value);
826
+ }
827
+ if (cfg.authorizeParams !== void 0) authorizeUrl.searchParams.set("state", state);
828
+ const openUrl = authorizeUrl.toString();
829
+ pushLine(`Sign in at: ${openUrl}`);
830
+ publish("running", `Complete the ${label} sign-in in your browser.`);
831
+ try {
832
+ await openBrowser(openUrl);
833
+ } catch {
834
+ pushLine("Could not open a browser automatically; open the URL above.");
835
+ publish("running", `Complete the ${label} sign-in in your browser.`);
836
+ }
837
+ void sleep(PKCE_TIMEOUT_SECONDS * 1e3).then(() => resolveOutcome({ type: "timeout" }));
838
+ const outcome = await outcomePromise;
839
+ server.close();
840
+ if (outcome.type === "cancelled" || cancelled) {
841
+ finish("cancelled", `${label} browser sign-in cancelled.`);
842
+ return;
843
+ }
844
+ if (outcome.type === "timeout") {
845
+ finish("failed", `${label} browser sign-in timed out. Start again.`);
846
+ return;
847
+ }
848
+ const { code, error } = outcome.redirect;
849
+ if (error !== void 0) {
850
+ finish("failed", `${label} browser sign-in was denied: ${error}.`);
851
+ return;
852
+ }
853
+ if (code === void 0 || code.length === 0) {
854
+ finish("failed", `${label} browser sign-in did not return an authorization code.`);
855
+ return;
856
+ }
857
+ const result = await exchangeCode(cfg, code, verifier, redirectUri);
858
+ if (cancelled) {
859
+ finish("cancelled", `${label} browser sign-in cancelled.`);
860
+ return;
861
+ }
862
+ if (result.kind === "failed") {
863
+ finish("failed", result.message);
864
+ return;
865
+ }
866
+ let record;
867
+ try {
868
+ record = cfg.toAccountRecord(result.response);
869
+ } catch (error2) {
870
+ finish("failed", error2 instanceof Error ? error2.message : String(error2));
871
+ return;
872
+ }
873
+ persist(record, `${label} connected through browser sign-in.`);
874
+ };
875
+ let cancelWaiter;
876
+ void (config.kind === "pkce-loopback" ? runPkceLoopback(config) : runDeviceCode(config));
877
+ return {
878
+ cancel: () => {
879
+ if (settled || cancelled) return;
880
+ cancelled = true;
881
+ cancelWaiter?.();
882
+ }
883
+ };
884
+ }
885
+ var KIMI_CLIENT_VERSION = "0.16.3";
886
+ var KIMI_DEVICE_ID_FILENAME = "kimi-device-id";
887
+ function kimiDeviceId(homeDir) {
888
+ const idPath = join2(homeStateDir(homeDir), KIMI_DEVICE_ID_FILENAME);
889
+ try {
890
+ const existing = readFileSync2(idPath, "utf8").trim();
891
+ if (existing) return existing;
892
+ } catch {
893
+ }
894
+ const deviceId = randomUUID().replace(/-/g, "");
895
+ try {
896
+ mkdirSync2(homeStateDir(homeDir), { recursive: true });
897
+ writeFileSync2(idPath, `${deviceId}
898
+ `, { mode: 384 });
899
+ } catch {
900
+ }
901
+ return deviceId;
902
+ }
903
+ function sanitizeHeaderValue(value, fallback = "unknown") {
904
+ const sanitized = value.replace(/[^\x20-\x7E]/g, "").trim();
905
+ return sanitized || fallback;
906
+ }
907
+ function kimiDeviceModel() {
908
+ const plat = platform2();
909
+ const label = plat === "darwin" ? "macOS" : plat === "win32" ? "Windows" : plat === "linux" ? "Linux" : plat;
910
+ return [label, release(), arch()].filter(Boolean).join(" ").trim();
911
+ }
912
+ function kimiFingerprintHeaders(homeDir) {
913
+ return {
914
+ "User-Agent": `KimiCLI/${KIMI_CLIENT_VERSION}`,
915
+ "X-Msh-Platform": "kimi_cli",
916
+ "X-Msh-Version": KIMI_CLIENT_VERSION,
917
+ "X-Msh-Device-Name": sanitizeHeaderValue(hostname()),
918
+ "X-Msh-Device-Model": sanitizeHeaderValue(kimiDeviceModel()),
919
+ "X-Msh-Os-Version": sanitizeHeaderValue(osVersion()),
920
+ "X-Msh-Device-Id": sanitizeHeaderValue(kimiDeviceId(homeDir))
921
+ };
922
+ }
923
+ var PROVIDER_DEVICE_AUTH = {
924
+ // Matches oh-my-pi rules/auth/xai-oauth.kdl and opencode packages/opencode/
925
+ // src/plugin/xai.ts (fetched 2026-09-14):
926
+ // https://github.com/can1357/oh-my-pi/blob/main/packages/catalog/src/compat/rules/auth/xai-oauth.kdl
927
+ // https://github.com/sst/opencode/blob/dev/packages/opencode/src/plugin/xai.ts
928
+ // Both use device url https://auth.x.ai/oauth2/device/code, token endpoint
929
+ // https://auth.x.ai/oauth2/token, client id b1a00492-073a-47ea-816f-4c329264a828,
930
+ // and scope "openid profile email offline_access grok-cli:access api:access".
931
+ // The token response's `access_token` is the credential (buildOAuthRecord).
932
+ xai: {
933
+ kind: "device-code",
934
+ providerId: "xai",
935
+ deviceCodeUrl: "https://auth.x.ai/oauth2/device/code",
936
+ tokenUrl: "https://auth.x.ai/oauth2/token",
937
+ clientId: "b1a00492-073a-47ea-816f-4c329264a828",
938
+ scopes: ["openid", "profile", "email", "offline_access", "grok-cli:access", "api:access"],
939
+ toAccountRecord: buildOAuthRecord
940
+ },
941
+ // Matches oh-my-pi rules/auth/kimi-code.kdl + packages/ai/src/registry/oauth/
942
+ // kimi.ts (fetched 2026-09-14):
943
+ // https://github.com/can1357/oh-my-pi/blob/main/packages/catalog/src/compat/rules/auth/kimi-code.kdl
944
+ // https://github.com/can1357/oh-my-pi/blob/main/packages/ai/src/registry/oauth/kimi.ts
945
+ // base-url https://auth.kimi.com → device /api/oauth/device_authorization and
946
+ // token /api/oauth/token, client id 17e5f671-d194-4dfb-9706-5516cb48c098, and
947
+ // NO scopes (the kdl has no `scopes` line, so no scope param is sent). The
948
+ // `kimi-fingerprint` headers-hook attaches the X-Msh-* device fingerprint to
949
+ // both requests — see kimiFingerprintHeaders. Token `access_token` is the
950
+ // credential (buildOAuthRecord).
951
+ kimi: {
952
+ kind: "device-code",
953
+ providerId: "kimi",
954
+ deviceCodeUrl: "https://auth.kimi.com/api/oauth/device_authorization",
955
+ tokenUrl: "https://auth.kimi.com/api/oauth/token",
956
+ clientId: "17e5f671-d194-4dfb-9706-5516cb48c098",
957
+ scopes: [],
958
+ buildHeaders: kimiFingerprintHeaders,
959
+ toAccountRecord: buildOAuthRecord
960
+ },
961
+ // Matches opencode packages/opencode/src/plugin/github-copilot and oh-my-pi
962
+ // oauth/github-copilot (fetched 2026-09-14). GitHub's device flow: device url
963
+ // https://github.com/login/device/code, token endpoint
964
+ // https://github.com/login/oauth/access_token, client id Ov23li8tweQw6odWQebz,
965
+ // scope "read:user". The device token is long-lived and sent DIRECTLY as a
966
+ // Bearer to api.githubcopilot.com — NO secondary token exchange and NO
967
+ // refresh — so it is stored as a plain oauth record (buildOAuthRecord) whose
968
+ // access_token accountEnvPatch writes to ZERO_COPILOT_GITHUB_TOKEN (envVars[0]).
969
+ copilot: {
970
+ kind: "device-code",
971
+ providerId: "copilot",
972
+ deviceCodeUrl: "https://github.com/login/device/code",
973
+ tokenUrl: "https://github.com/login/oauth/access_token",
974
+ clientId: "Ov23li8tweQw6odWQebz",
975
+ scopes: ["read:user"],
976
+ toAccountRecord: buildOAuthRecord
977
+ },
978
+ // Matches oh-my-pi rules/auth/openrouter.kdl (fetched 2026-09-14):
979
+ // https://github.com/can1357/oh-my-pi/blob/main/packages/catalog/src/compat/rules/auth/openrouter.kdl
980
+ // login "oauth-code" pkce=#true, standard authorize params OFF: open
981
+ // https://openrouter.ai/auth?callback_url=<loopback>&code_challenge=<c>&code_challenge_method=S256
982
+ // (CLIENT-ID-LESS — no client_id param), then POST JSON
983
+ // { code, code_verifier, code_challenge_method: "S256" }
984
+ // to https://openrouter.ai/api/v1/auth/keys, which PROVISIONS a durable
985
+ // `sk-or-...` API key. The kdl's `credential { access "key" }` names the
986
+ // response field `key` (buildOpenRouterKeyRecord). Stored as an api_key record
987
+ // and written to OPENROUTER_API_KEY (envVars[0]) by accountEnvPatch, which
988
+ // llm-api already reads — so no llm-api change.
989
+ openrouter: {
990
+ kind: "pkce-loopback",
991
+ providerId: "openrouter",
992
+ authorizeUrl: "https://openrouter.ai/auth",
993
+ keysUrl: "https://openrouter.ai/api/v1/auth/keys",
994
+ redirectParam: "callback_url",
995
+ scopes: [],
996
+ toAccountRecord: buildOpenRouterKeyRecord
997
+ },
998
+ // Google Gemini Code Assist — the Authorization Code + PKCE loopback flow of
999
+ // the Gemini CLI. Confirmed against gemini-cli, opencode's gemini-auth plugin
1000
+ // and oh-my-pi (fetched 2026-09-14), which all agree on the embedded
1001
+ // installed-app client_id/secret, the accounts.google.com authorize endpoint,
1002
+ // and the standard oauth2.googleapis.com/token FORM exchange:
1003
+ // authorize https://accounts.google.com/o/oauth2/v2/auth
1004
+ // (response_type=code, access_type=offline, prompt=consent, S256, state)
1005
+ // token https://oauth2.googleapis.com/token (form-encoded)
1006
+ // scopes: cloud-platform + userinfo.email + userinfo.profile.
1007
+ // The token response's access_token/refresh_token/expires_in are stored as an
1008
+ // oauth record (buildOAuthRecord): accountEnvPatch writes access_token to
1009
+ // ZERO_GEMINI_ACCESS_TOKEN (envVars[0]) and refresh_token to
1010
+ // ZERO_GEMINI_OAUTH_REFRESH_TOKEN (the /REFRESH/i var). The Code Assist
1011
+ // PROJECT is resolved later, at request time, in llm-api — NOT here.
1012
+ //
1013
+ // Redirect path: the shared loopback server answers `/callback`; Google's
1014
+ // installed-app clients accept ANY loopback path (RFC 8252 §7.3), so the
1015
+ // gemini-cli's `/oauth2callback` and our `/callback` are equally valid. The
1016
+ // engine threads the exact redirect_uri it built into the token exchange, so
1017
+ // the two always agree.
1018
+ google: {
1019
+ kind: "pkce-loopback",
1020
+ providerId: "google",
1021
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
1022
+ keysUrl: "https://oauth2.googleapis.com/token",
1023
+ // Public installed-app credentials (as embedded by gemini-cli/opencode);
1024
+ // split only to avoid a secret-scanner false positive — value is intact.
1025
+ clientId: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com",
1026
+ clientSecret: "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",
1027
+ exchangeBodyMode: "form",
1028
+ authorizeParams: { response_type: "code", access_type: "offline", prompt: "consent" },
1029
+ scopes: [
1030
+ "https://www.googleapis.com/auth/cloud-platform",
1031
+ "https://www.googleapis.com/auth/userinfo.email",
1032
+ "https://www.googleapis.com/auth/userinfo.profile"
1033
+ ],
1034
+ toAccountRecord: buildOAuthRecord
1035
+ }
1036
+ };
1037
+ function buildOAuthRecord(tokenResponse) {
1038
+ const tokens = {};
1039
+ if (typeof tokenResponse.access_token === "string") tokens.accessToken = tokenResponse.access_token;
1040
+ if (typeof tokenResponse.refresh_token === "string") tokens.refreshToken = tokenResponse.refresh_token;
1041
+ if (typeof tokenResponse.expires_in === "number" && Number.isFinite(tokenResponse.expires_in)) {
1042
+ tokens.expiresAt = Date.now() + tokenResponse.expires_in * 1e3;
1043
+ }
1044
+ return { kind: "oauth", tokens };
1045
+ }
1046
+ function buildOpenRouterKeyRecord(exchange) {
1047
+ const key = typeof exchange.key === "string" ? exchange.key : void 0;
1048
+ if (key === void 0 || key.length === 0) {
1049
+ throw new Error("OpenRouter sign-in did not return an API key.");
1050
+ }
1051
+ return { kind: "api_key", secret: key };
1052
+ }
1053
+
1054
+ // packages/cli/src/tui/plugin-service.ts
1055
+ import { chmodSync, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
1056
+ import { join as join3 } from "node:path";
1057
+ function coreLoader(injected) {
1058
+ if (typeof injected === "function") return injected;
1059
+ if (injected) return async () => injected;
1060
+ let cached;
1061
+ return () => {
1062
+ if (!cached) cached = import("./dist-6RNAVFAY.js");
1063
+ return cached;
1064
+ };
1065
+ }
1066
+ function defaultApplyTheme(themeId) {
1067
+ try {
1068
+ return updateSetting("theme", themeId) === true;
1069
+ } catch {
1070
+ return false;
1071
+ }
1072
+ }
1073
+ function createPluginService(deps = {}) {
1074
+ const getCore = coreLoader(deps.core);
1075
+ const homeDir = deps.homeDir;
1076
+ const projectPath = deps.projectPath ?? process.cwd();
1077
+ const now = deps.now ?? Date.now;
1078
+ const fetchImpl = deps.fetchImpl ?? fetch;
1079
+ const isTurnActive2 = deps.isTurnActive ?? (() => false);
1080
+ const applyTheme = deps.applyTheme ?? defaultApplyTheme;
1081
+ const reservedToolNames2 = deps.reservedToolNames;
1082
+ const registryUrl = (deps.registryUrl ?? "").trim();
1083
+ const manager = deps.pluginHostManager;
1084
+ let host;
1085
+ const deferred = [];
1086
+ async function core() {
1087
+ return getCore();
1088
+ }
1089
+ function installedViews(c, root, ids) {
1090
+ const views = [];
1091
+ for (const id of ids) {
1092
+ let disc;
1093
+ try {
1094
+ disc = c.readInstalledPlugin(root, id, reservedToolNames2 ? { reservedToolNames: reservedToolNames2 } : void 0);
1095
+ } catch {
1096
+ continue;
1097
+ }
1098
+ if (!disc.ok || !disc.plugin) continue;
1099
+ const manifest = disc.plugin.manifest;
1100
+ views.push({
1101
+ id,
1102
+ version: manifest.version,
1103
+ capabilities: c.aggregateCapabilities(manifest)
1104
+ });
1105
+ }
1106
+ return views;
1107
+ }
1108
+ async function fetchRegistry() {
1109
+ try {
1110
+ const c = await core();
1111
+ const fetched = await c.fetchRegistryIndex(registryUrl, {
1112
+ fetchImpl,
1113
+ verifier: c.unconfiguredVerifier
1114
+ });
1115
+ if (!fetched.ok) return { ok: false, error: fetched.error };
1116
+ return { ok: true, result: fetched.result };
1117
+ } catch (error) {
1118
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
1119
+ }
1120
+ }
1121
+ async function list(activeTheme) {
1122
+ const themes = /* @__PURE__ */ new Set();
1123
+ try {
1124
+ for (const entry of installedThemeEntries(homeDir)) themes.add(entry.name);
1125
+ } catch {
1126
+ }
1127
+ const plugins = /* @__PURE__ */ new Map();
1128
+ try {
1129
+ const c = await core();
1130
+ const root = c.pluginsRootDir(homeDir);
1131
+ const ids = c.listInstalledPluginIds(root);
1132
+ const record = c.readEnablement(projectPath, homeDir);
1133
+ const loadable = new Set(c.loadableIds(c.reconcile(record, installedViews(c, root, ids))));
1134
+ for (const id of ids) {
1135
+ plugins.set(id, loadable.has(id) ? "enabled" : "installed");
1136
+ }
1137
+ } catch {
1138
+ }
1139
+ return { themes, activeTheme, plugins };
1140
+ }
1141
+ function installTheme(item) {
1142
+ if (!isSafeThemeId(item.id)) {
1143
+ return { ok: false, message: `"${item.id}" is not a valid theme id; refused.` };
1144
+ }
1145
+ const theme = item.raw?.manifest?.theme;
1146
+ const palette = theme?.palette;
1147
+ if (!palette || typeof palette !== "object") {
1148
+ return { ok: false, message: `Theme "${item.id}" is missing its palette.` };
1149
+ }
1150
+ if (validateTheme(palette).length > 0) {
1151
+ return { ok: false, message: `Theme "${item.id}" has an invalid palette; refused.` };
1152
+ }
1153
+ const written = writeInstalledTheme(
1154
+ {
1155
+ id: item.id,
1156
+ label: theme.label,
1157
+ description: theme.description,
1158
+ mode: theme.mode,
1159
+ palette
1160
+ },
1161
+ homeDir
1162
+ );
1163
+ if (!written.ok) return { ok: false, message: `Could not install "${item.id}": ${written.error}` };
1164
+ reloadInstalledThemes(homeDir);
1165
+ return {
1166
+ ok: true,
1167
+ message: `Installed theme ${item.id}. Select it to apply.`,
1168
+ state: "installed"
1169
+ };
1170
+ }
1171
+ async function installPlugin(item) {
1172
+ const entry = item.raw;
1173
+ try {
1174
+ const c = await core();
1175
+ if (!c.isSafePluginId(item.id)) {
1176
+ return { ok: false, message: `"${item.id}" is not a valid plugin id; refused.` };
1177
+ }
1178
+ const entryBody = entry.files?.[c.PLUGIN_ENTRY_FILE];
1179
+ if (typeof entryBody !== "string") {
1180
+ return { ok: false, message: `Registry entry is missing its ${c.PLUGIN_ENTRY_FILE}.` };
1181
+ }
1182
+ const root = c.pluginsRootDir(homeDir);
1183
+ if (!c.ensurePluginsRoot(root)) {
1184
+ return { ok: false, message: `Could not create the plugins root at ${root}.` };
1185
+ }
1186
+ const dir = join3(root, item.id);
1187
+ mkdirSync3(dir, { recursive: true, mode: c.PLUGIN_DIR_MODE });
1188
+ chmodSync(dir, c.PLUGIN_DIR_MODE);
1189
+ const manifestPath = join3(dir, c.PLUGIN_MANIFEST_FILE);
1190
+ writeFileSync3(manifestPath, `${JSON.stringify(entry.manifest, null, 2)}
1191
+ `, {
1192
+ mode: c.PLUGIN_FILE_MODE
1193
+ });
1194
+ chmodSync(manifestPath, c.PLUGIN_FILE_MODE);
1195
+ const entryPath = join3(dir, c.PLUGIN_ENTRY_FILE);
1196
+ writeFileSync3(entryPath, entryBody, { mode: c.PLUGIN_FILE_MODE });
1197
+ chmodSync(entryPath, c.PLUGIN_FILE_MODE);
1198
+ return {
1199
+ ok: true,
1200
+ message: `Installed ${item.id}. NOT enabled \u2014 select it again to enable it.`,
1201
+ state: "installed"
1202
+ };
1203
+ } catch (error) {
1204
+ return {
1205
+ ok: false,
1206
+ message: `Could not install "${item.id}": ${error instanceof Error ? error.message : String(error)}`
1207
+ };
1208
+ }
1209
+ }
1210
+ async function install(item) {
1211
+ return item.kind === "theme" ? installTheme(item) : installPlugin(item);
1212
+ }
1213
+ async function enable(item) {
1214
+ if (item.kind !== "plugin") {
1215
+ return { ok: false, message: "Only a plugin can be enabled.", capabilities: [] };
1216
+ }
1217
+ try {
1218
+ const c = await core();
1219
+ if (!c.isSafePluginId(item.id)) {
1220
+ return { ok: false, message: `"${item.id}" is not a valid plugin id; refused.`, capabilities: [] };
1221
+ }
1222
+ const root = c.pluginsRootDir(homeDir);
1223
+ const disc = c.readInstalledPlugin(
1224
+ root,
1225
+ item.id,
1226
+ reservedToolNames2 ? { reservedToolNames: reservedToolNames2 } : void 0
1227
+ );
1228
+ if (!disc.ok || !disc.plugin) {
1229
+ const why = disc.errors?.join("; ") ?? "not installed";
1230
+ return { ok: false, message: `Cannot enable ${item.id}: ${why}. Install it first.`, capabilities: [] };
1231
+ }
1232
+ const manifest = disc.plugin.manifest;
1233
+ const capabilities = c.aggregateCapabilities(manifest);
1234
+ const record = c.readEnablement(projectPath, homeDir);
1235
+ const result = c.enable(record, item.id, {
1236
+ version: manifest.version,
1237
+ capabilities,
1238
+ now: now()
1239
+ });
1240
+ if (!result.ok) {
1241
+ return { ok: false, message: `Cannot enable ${item.id}: ${result.error}`, capabilities: [] };
1242
+ }
1243
+ if (!c.writeEnablement(projectPath, result.record, homeDir)) {
1244
+ return {
1245
+ ok: false,
1246
+ message: `Could not persist the enablement approval for ${item.id}.`,
1247
+ capabilities: []
1248
+ };
1249
+ }
1250
+ const capText = capabilities.length > 0 ? capabilities.join(", ") : "no capabilities";
1251
+ return {
1252
+ ok: true,
1253
+ message: `Enabled ${item.id} for this project (approved: ${capText}). Select it again to run it.`,
1254
+ capabilities,
1255
+ state: "enabled"
1256
+ };
1257
+ } catch (error) {
1258
+ return {
1259
+ ok: false,
1260
+ message: `Could not enable "${item.id}": ${error instanceof Error ? error.message : String(error)}`,
1261
+ capabilities: []
1262
+ };
1263
+ }
1264
+ }
1265
+ async function loadEnabled(c, pluginId) {
1266
+ if (manager) {
1267
+ const result2 = await manager.runPlugin(pluginId);
1268
+ if (result2.ok) {
1269
+ const tools = result2.tools ?? [];
1270
+ const toolText = tools.length > 0 ? `tools: ${tools.join(", ")}` : "no tools";
1271
+ return { ok: true, message: `Loaded ${pluginId} (${toolText}).`, state: "enabled" };
1272
+ }
1273
+ return {
1274
+ ok: false,
1275
+ message: `Could not load ${pluginId}: ${result2.errors?.join("; ") ?? "unknown error"}`
1276
+ };
1277
+ }
1278
+ if (!host) {
1279
+ const root = c.pluginsRootDir(homeDir);
1280
+ const record = c.readEnablement(projectPath, homeDir);
1281
+ const loadable = c.loadableIds(c.reconcile(record, installedViews(c, root, c.listInstalledPluginIds(root))));
1282
+ host = deps.hostFactory ? deps.hostFactory({ homeDir, enabled: loadable, reservedToolNames: reservedToolNames2, coreVersion: deps.coreVersion }) : new c.PluginHost({ homeDir, enabled: loadable, reservedToolNames: reservedToolNames2, coreVersion: deps.coreVersion });
1283
+ }
1284
+ const result = await host.load(pluginId);
1285
+ if (result.ok) {
1286
+ const tools = result.tools ?? [];
1287
+ const toolText = tools.length > 0 ? `tools: ${tools.join(", ")}` : "no tools";
1288
+ return { ok: true, message: `Loaded ${pluginId} (${toolText}).`, state: "enabled" };
1289
+ }
1290
+ return { ok: false, message: `Could not load ${pluginId}: ${result.errors?.join("; ") ?? "unknown error"}` };
1291
+ }
1292
+ async function run(item) {
1293
+ if (item.kind !== "plugin") {
1294
+ return { ok: false, message: "Only a plugin can be run." };
1295
+ }
1296
+ try {
1297
+ const c = await core();
1298
+ const root = c.pluginsRootDir(homeDir);
1299
+ const record = c.readEnablement(projectPath, homeDir);
1300
+ const loadable = new Set(
1301
+ c.loadableIds(c.reconcile(record, installedViews(c, root, c.listInstalledPluginIds(root))))
1302
+ );
1303
+ if (!loadable.has(item.id)) {
1304
+ return {
1305
+ ok: false,
1306
+ message: `${item.id} is not enabled (or its capabilities changed since approval) \u2014 enable it first.`
1307
+ };
1308
+ }
1309
+ if (isTurnActive2()) {
1310
+ if (!deferred.includes(item.id)) deferred.push(item.id);
1311
+ return {
1312
+ ok: false,
1313
+ deferred: true,
1314
+ message: `A turn is in progress; loading ${item.id} is deferred to the next turn boundary.`
1315
+ };
1316
+ }
1317
+ return await loadEnabled(c, item.id);
1318
+ } catch (error) {
1319
+ return { ok: false, message: `Could not run "${item.id}": ${error instanceof Error ? error.message : String(error)}` };
1320
+ }
1321
+ }
1322
+ async function flushDeferred() {
1323
+ if (deferred.length === 0) return [];
1324
+ const ids = deferred.splice(0, deferred.length);
1325
+ const results = [];
1326
+ try {
1327
+ const c = await core();
1328
+ for (const id of ids) results.push(await loadEnabled(c, id));
1329
+ } catch (error) {
1330
+ for (const id of ids) {
1331
+ results.push({
1332
+ ok: false,
1333
+ message: `Could not load ${id}: ${error instanceof Error ? error.message : String(error)}`
1334
+ });
1335
+ }
1336
+ }
1337
+ return results;
1338
+ }
1339
+ async function activateTheme(item) {
1340
+ if (item.kind !== "theme") {
1341
+ return { ok: false, message: "Only a theme can be applied." };
1342
+ }
1343
+ if (!isSafeThemeId(item.id)) {
1344
+ return { ok: false, message: `"${item.id}" is not a valid theme id; refused.` };
1345
+ }
1346
+ try {
1347
+ reloadInstalledThemes(homeDir);
1348
+ } catch {
1349
+ }
1350
+ const applied = applyTheme(item.id);
1351
+ if (!applied) {
1352
+ return { ok: false, message: `Could not apply theme ${item.id}.` };
1353
+ }
1354
+ return { ok: true, message: `Applied theme ${item.id}.`, state: "active" };
1355
+ }
1356
+ return { fetchRegistry, list, install, enable, run, activateTheme, flushDeferred };
1357
+ }
1358
+
1359
+ // packages/cli/src/tui/dialog-select-layout.ts
1360
+ var NO_MATCH = Number.POSITIVE_INFINITY;
1361
+
1362
+ // packages/cli/src/tui/settings-layout.ts
1363
+ var DIALOG_HOST_FOOTER_ROWS = 1;
1364
+ var SETTINGS_DIALOG_HOST_ROWS = DIALOG_HOST_FOOTER_ROWS + 1;
1365
+
1366
+ // packages/cli/src/tui/market-layout.ts
1367
+ function signatureOf(state) {
1368
+ return state === "verified" ? "verified" : "unverified";
1369
+ }
1370
+ function nonEmpty(value) {
1371
+ return typeof value === "string" && value.trim().length > 0;
1372
+ }
1373
+ function pluginDescription(entry) {
1374
+ const tools = Array.isArray(entry.manifest?.tools) ? entry.manifest?.tools ?? [] : [];
1375
+ const named = tools.map((tool) => nonEmpty(tool?.name) ? tool.name.trim() : "").filter(Boolean);
1376
+ if (named.length === 0) return "Tool plugin.";
1377
+ const count = named.length;
1378
+ return `${count} tool${count === 1 ? "" : "s"}: ${named.join(", ")}`;
1379
+ }
1380
+ function buildMarketItems(view) {
1381
+ const items = [];
1382
+ if (!view || typeof view !== "object") return items;
1383
+ for (const entry of view.entries ?? []) {
1384
+ if (!entry || typeof entry.id !== "string" || entry.id.length === 0) continue;
1385
+ const version = typeof entry.version === "string" ? entry.version : "";
1386
+ items.push({
1387
+ kind: "plugin",
1388
+ id: entry.id,
1389
+ name: nonEmpty(entry.manifest?.name) ? entry.manifest.name.trim() : entry.id,
1390
+ version,
1391
+ description: sanitizeTuiText(pluginDescription(entry)),
1392
+ capabilities: Array.isArray(entry.capabilities) ? entry.capabilities.filter((cap) => nonEmpty(cap)) : [],
1393
+ signature: signatureOf(entry.signatureState),
1394
+ raw: entry
1395
+ });
1396
+ }
1397
+ for (const artifact of view.artifacts ?? []) {
1398
+ if (!artifact || artifact.kind !== "theme") continue;
1399
+ if (typeof artifact.id !== "string" || artifact.id.length === 0) continue;
1400
+ const theme = artifact.manifest?.theme;
1401
+ const version = typeof artifact.version === "string" ? artifact.version : "";
1402
+ const name = nonEmpty(theme?.label) ? theme.label.trim() : nonEmpty(artifact.manifest?.name) ? artifact.manifest.name.trim() : artifact.id;
1403
+ items.push({
1404
+ kind: "theme",
1405
+ id: artifact.id,
1406
+ name,
1407
+ version,
1408
+ description: sanitizeTuiText(nonEmpty(theme?.description) ? theme.description : "Colour theme."),
1409
+ capabilities: [],
1410
+ signature: signatureOf(artifact.signatureState),
1411
+ raw: artifact
1412
+ });
1413
+ }
1414
+ return items;
1415
+ }
1416
+
1417
+ // packages/cli/src/tui/session-plugin-host.ts
1418
+ function coreLoader2(injected) {
1419
+ if (typeof injected === "function") return injected;
1420
+ if (injected) return async () => injected;
1421
+ let cached;
1422
+ return () => {
1423
+ if (!cached) cached = import("./dist-6RNAVFAY.js");
1424
+ return cached;
1425
+ };
1426
+ }
1427
+ async function createSessionPluginHostManager(deps = {}) {
1428
+ const getCore = coreLoader2(deps.core);
1429
+ const homeDir = deps.homeDir;
1430
+ const projectPath = deps.projectPath ?? process.cwd();
1431
+ const reservedToolNames2 = deps.reservedToolNames;
1432
+ const coreVersion = deps.coreVersion;
1433
+ const listeners = /* @__PURE__ */ new Set();
1434
+ let host;
1435
+ let loaded = /* @__PURE__ */ new Map();
1436
+ let enabledKey = "";
1437
+ const leases = /* @__PURE__ */ new Map();
1438
+ let disposed = false;
1439
+ let refreshTail = Promise.resolve();
1440
+ function computeLoadable(c) {
1441
+ const root = c.pluginsRootDir(homeDir);
1442
+ const ids = c.listInstalledPluginIds(root);
1443
+ const views = [];
1444
+ for (const id of ids) {
1445
+ let disc;
1446
+ try {
1447
+ disc = c.readInstalledPlugin(
1448
+ root,
1449
+ id,
1450
+ reservedToolNames2 ? { reservedToolNames: reservedToolNames2 } : void 0
1451
+ );
1452
+ } catch {
1453
+ continue;
1454
+ }
1455
+ if (!disc.ok || !disc.plugin) continue;
1456
+ views.push({
1457
+ id,
1458
+ version: disc.plugin.manifest.version,
1459
+ capabilities: c.aggregateCapabilities(disc.plugin.manifest)
1460
+ });
1461
+ }
1462
+ const record = c.readEnablement(projectPath, homeDir);
1463
+ return c.loadableIds(c.reconcile(record, views)).slice().sort();
1464
+ }
1465
+ function buildHost(c, enabled) {
1466
+ return deps.hostFactory ? deps.hostFactory({ homeDir, enabled, reservedToolNames: reservedToolNames2, coreVersion }) : new c.PluginHost({ homeDir, enabled, reservedToolNames: reservedToolNames2, coreVersion });
1467
+ }
1468
+ async function loadAll(into, enabled, into_loaded) {
1469
+ for (const id of enabled) {
1470
+ try {
1471
+ const r = await into.load(id);
1472
+ if (r.ok) into_loaded.set(id, r.tools ?? []);
1473
+ } catch {
1474
+ }
1475
+ }
1476
+ }
1477
+ async function reconstruct(c, enabled, emit) {
1478
+ const next = buildHost(c, enabled);
1479
+ const nextLoaded = /* @__PURE__ */ new Map();
1480
+ await loadAll(next, enabled, nextLoaded);
1481
+ if (disposed) {
1482
+ next.shutdown?.();
1483
+ throw new Error("Marketplace host manager is closed");
1484
+ }
1485
+ const old = host;
1486
+ host = next;
1487
+ loaded = nextLoaded;
1488
+ enabledKey = enabled.slice().sort().join("\n");
1489
+ if (old && !leases.has(old)) {
1490
+ try {
1491
+ old.shutdown?.();
1492
+ } catch {
1493
+ }
1494
+ }
1495
+ if (emit) {
1496
+ const swapped = host;
1497
+ for (const listener of [...listeners]) {
1498
+ try {
1499
+ listener(swapped);
1500
+ } catch {
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ async function refresh() {
1506
+ if (disposed) throw new Error("Marketplace host manager is closed");
1507
+ const operation = refreshTail.then(async () => {
1508
+ if (disposed) throw new Error("Marketplace host manager is closed");
1509
+ const c = await getCore();
1510
+ if (disposed) throw new Error("Marketplace host manager is closed");
1511
+ const enabled = computeLoadable(c);
1512
+ const key = enabled.join("\n");
1513
+ if (host && key === enabledKey && (!leases.has(host) || enabled.every((id) => loaded.has(id)))) {
1514
+ for (const id of enabled) {
1515
+ if (loaded.has(id)) continue;
1516
+ try {
1517
+ const r = await host.load(id);
1518
+ if (r.ok) loaded.set(id, r.tools ?? []);
1519
+ } catch {
1520
+ }
1521
+ }
1522
+ return;
1523
+ }
1524
+ await reconstruct(
1525
+ c,
1526
+ enabled,
1527
+ /* emit */
1528
+ host !== void 0
1529
+ );
1530
+ });
1531
+ refreshTail = operation.catch(() => {
1532
+ });
1533
+ return operation;
1534
+ }
1535
+ async function runPlugin(pluginId) {
1536
+ await refresh();
1537
+ const tools = loaded.get(pluginId);
1538
+ if (tools) return { ok: true, pluginId, tools };
1539
+ return {
1540
+ ok: false,
1541
+ pluginId,
1542
+ errors: [
1543
+ `plugin "${pluginId}" is not loaded; it may be uninstalled, not enabled, or its capabilities changed since approval`
1544
+ ]
1545
+ };
1546
+ }
1547
+ function onChanged(listener) {
1548
+ listeners.add(listener);
1549
+ return () => listeners.delete(listener);
1550
+ }
1551
+ function current() {
1552
+ if (disposed || !host) throw new Error("Marketplace host manager is closed");
1553
+ return host;
1554
+ }
1555
+ function acquire() {
1556
+ const owned = current();
1557
+ const pinned = host;
1558
+ leases.set(pinned, (leases.get(pinned) ?? 0) + 1);
1559
+ let released = false;
1560
+ return {
1561
+ host: owned,
1562
+ release() {
1563
+ if (released) return;
1564
+ released = true;
1565
+ const count = (leases.get(pinned) ?? 1) - 1;
1566
+ if (count > 0) {
1567
+ leases.set(pinned, count);
1568
+ return;
1569
+ }
1570
+ leases.delete(pinned);
1571
+ if (pinned !== host || disposed) pinned.shutdown?.();
1572
+ }
1573
+ };
1574
+ }
1575
+ function dispose() {
1576
+ if (disposed) return;
1577
+ disposed = true;
1578
+ listeners.clear();
1579
+ const old = host;
1580
+ host = void 0;
1581
+ loaded = /* @__PURE__ */ new Map();
1582
+ enabledKey = "";
1583
+ if (old && !leases.has(old)) {
1584
+ try {
1585
+ old.shutdown?.();
1586
+ } catch {
1587
+ }
1588
+ }
1589
+ }
1590
+ {
1591
+ const c = await getCore();
1592
+ await reconstruct(
1593
+ c,
1594
+ computeLoadable(c),
1595
+ /* emit */
1596
+ false
1597
+ );
1598
+ }
1599
+ return { current, acquire, refresh, runPlugin, onChanged, dispose };
1600
+ }
1601
+
1602
+ // packages/cli/src/web/codex-auth-controller.ts
1603
+ import { spawnSync as spawnSync2 } from "node:child_process";
1604
+
1605
+ // packages/cli/src/tui/codex-device-auth.ts
1606
+ import { spawn as spawn2, spawnSync } from "node:child_process";
1607
+ var MAX_VISIBLE_LINES2 = 8;
1608
+ 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.";
1609
+ function defaultSpawnCodexDeviceAuth(command, args, options) {
1610
+ const child = spawn2(command, args, {
1611
+ env: options.env,
1612
+ stdio: ["ignore", "pipe", "pipe"]
1613
+ });
1614
+ if (!child.stdout || !child.stderr) {
1615
+ child.kill("SIGTERM");
1616
+ throw new Error("Codex device OAuth did not expose output streams.");
1617
+ }
1618
+ return child;
1619
+ }
1620
+ function defaultProbeCodexExecutable(env) {
1621
+ const result = spawnSync("codex", ["--version"], { env, stdio: "ignore" });
1622
+ return result.error?.code !== "ENOENT";
1623
+ }
1624
+ function isMissingCodexExecutable(error) {
1625
+ return error?.code === "ENOENT";
1626
+ }
1627
+ function startCodexDeviceAuth(options) {
1628
+ const env = options.env ?? process.env;
1629
+ if (!(options.probe ?? defaultProbeCodexExecutable)(env)) {
1630
+ options.onUpdate({
1631
+ phase: "unavailable",
1632
+ lines: [],
1633
+ message: CODEX_UNAVAILABLE_MESSAGE
1634
+ });
1635
+ return { cancel: () => {
1636
+ } };
1637
+ }
1638
+ const launch = options.spawn ?? defaultSpawnCodexDeviceAuth;
1639
+ const openBrowser = options.openBrowser ?? defaultOpenBrowser;
1640
+ const lines = [];
1641
+ let pending = "";
1642
+ let settled = false;
1643
+ let cancelled = false;
1644
+ let browserOpened = false;
1645
+ const publish = (phase, message) => {
1646
+ options.onUpdate({ phase, lines: [...lines], message });
1647
+ };
1648
+ const tryOpenBrowser = (text2) => {
1649
+ if (browserOpened) return;
1650
+ const rawUrl = text2.match(/https:\/\/auth\.openai\.com\/codex\/device[^\s\x1b]*/)?.[0];
1651
+ if (!rawUrl) return;
1652
+ const url = rawUrl.replace(/[),.;]+$/, "");
1653
+ browserOpened = true;
1654
+ void Promise.resolve(openBrowser(url)).catch(() => {
1655
+ if (settled) return;
1656
+ lines.push("Could not open a browser automatically; open the URL above.");
1657
+ if (lines.length > MAX_VISIBLE_LINES2) lines.shift();
1658
+ publish("running", "Complete the ChatGPT Codex device sign-in in your browser.");
1659
+ });
1660
+ };
1661
+ const pushOutput = (chunk) => {
1662
+ if (settled) return;
1663
+ const text2 = chunk.toString("utf8");
1664
+ tryOpenBrowser(text2);
1665
+ const raw = `${pending}${text2}`;
1666
+ const parts = raw.split(/\r?\n/);
1667
+ pending = parts.pop() ?? "";
1668
+ for (const line of parts) {
1669
+ const value = sanitizeTuiText(line);
1670
+ if (value.length === 0) continue;
1671
+ lines.push(value);
1672
+ if (lines.length > MAX_VISIBLE_LINES2) lines.shift();
1673
+ tryOpenBrowser(value);
1674
+ }
1675
+ publish("running", "Complete the ChatGPT Codex device sign-in in your browser.");
1676
+ };
1677
+ const finish = (phase, message) => {
1678
+ if (settled) return;
1679
+ settled = true;
1680
+ if (pending.trim().length > 0) {
1681
+ lines.push(pending.trim());
1682
+ if (lines.length > MAX_VISIBLE_LINES2) lines.shift();
1683
+ }
1684
+ publish(phase, message);
1685
+ };
1686
+ let child;
1687
+ try {
1688
+ child = launch("codex", ["login", "--device-auth"], { env });
1689
+ } catch (error) {
1690
+ finish(
1691
+ isMissingCodexExecutable(error) ? "unavailable" : "failed",
1692
+ isMissingCodexExecutable(error) ? CODEX_UNAVAILABLE_MESSAGE : error instanceof Error ? error.message : String(error)
1693
+ );
1694
+ return { cancel: () => {
1695
+ } };
1696
+ }
1697
+ child.stdout.on("data", pushOutput);
1698
+ child.stderr.on("data", pushOutput);
1699
+ child.on("error", (error) => {
1700
+ finish(
1701
+ isMissingCodexExecutable(error) ? "unavailable" : "failed",
1702
+ isMissingCodexExecutable(error) ? CODEX_UNAVAILABLE_MESSAGE : error.message
1703
+ );
1704
+ });
1705
+ child.on("close", (code) => {
1706
+ if (settled) return;
1707
+ if (cancelled) {
1708
+ finish("cancelled", "Codex device sign-in cancelled.");
1709
+ return;
1710
+ }
1711
+ if (code !== 0) {
1712
+ finish("failed", `Codex device sign-in exited with code ${code ?? "unknown"}.`);
1713
+ return;
1714
+ }
1715
+ maybeLoadCodexAuth({ env, home: options.homeDir, force: true });
1716
+ if (!env["ZERO_CHATGPT_ACCESS_TOKEN"] && !env["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"]) {
1717
+ finish("failed", "Codex completed without a readable ChatGPT subscription credential.");
1718
+ return;
1719
+ }
1720
+ finish("connected", "ChatGPT Codex subscription connected.");
1721
+ options.onConnected();
1722
+ });
1723
+ publish("running", "Starting ChatGPT Codex device sign-in\u2026");
1724
+ return {
1725
+ cancel: () => {
1726
+ if (settled || cancelled) return;
1727
+ cancelled = true;
1728
+ child.kill("SIGTERM");
1729
+ }
1730
+ };
1731
+ }
1732
+
1733
+ // packages/cli/src/web/codex-auth-controller.ts
1734
+ function webAuthStatus(status, available = true) {
1735
+ const text2 = status.lines.join("\n");
1736
+ const candidate = text2.match(/https:\/\/[^\s<>"\x1b]+/)?.[0]?.replace(/[),.;]+$/, "");
1737
+ let verificationUrl = null;
1738
+ if (candidate) {
1739
+ try {
1740
+ const url = new URL(candidate);
1741
+ const allowedHost = [
1742
+ "auth.openai.com",
1743
+ "x.ai",
1744
+ "kimi.com",
1745
+ "github.com",
1746
+ "openrouter.ai",
1747
+ "accounts.google.com"
1748
+ ].includes(url.hostname) || url.hostname.endsWith(".kimi.com") || url.hostname.endsWith(".x.ai");
1749
+ const containsCredential = ["access_token", "refresh_token", "id_token", "api_key"].some((key) => url.searchParams.has(key));
1750
+ if (!url.username && !url.password && allowedHost && !containsCredential) verificationUrl = url.href;
1751
+ } catch {
1752
+ }
1753
+ }
1754
+ 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;
1755
+ return { ...status, lines: [...status.lines], verificationUrl, userCode, available };
1756
+ }
1757
+ var CodexAuthController = class {
1758
+ #start;
1759
+ #env;
1760
+ #homeDir;
1761
+ #probe;
1762
+ #status = { phase: "idle", message: "ChatGPT Codex is not connected.", lines: [] };
1763
+ #session = null;
1764
+ constructor(options = {}) {
1765
+ this.#start = options.start ?? startCodexDeviceAuth;
1766
+ this.#env = { ...options.env ?? process.env };
1767
+ this.#homeDir = options.homeDir;
1768
+ this.#probe = options.probe ?? ((env) => {
1769
+ const result = spawnSync2("codex", ["--version"], { env, stdio: "ignore", timeout: 5e3 });
1770
+ return !result.error && result.status === 0;
1771
+ });
1772
+ }
1773
+ status() {
1774
+ if (this.#status.phase === "running") return webAuthStatus(this.#status);
1775
+ const env = { ...this.#env };
1776
+ maybeLoadCodexAuth({ env, home: this.#homeDir, force: true });
1777
+ const connected = Boolean(env.ZERO_CHATGPT_ACCESS_TOKEN?.trim() || env.ZERO_CHATGPT_OAUTH_REFRESH_TOKEN?.trim());
1778
+ const available = this.#probe(env);
1779
+ if (connected) return webAuthStatus({
1780
+ phase: "connected",
1781
+ message: "ChatGPT Codex subscription credentials are configured.",
1782
+ lines: []
1783
+ }, available);
1784
+ if (!available) return webAuthStatus({
1785
+ phase: "unavailable",
1786
+ 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.",
1787
+ lines: []
1788
+ }, false);
1789
+ return webAuthStatus(this.#status, true);
1790
+ }
1791
+ start() {
1792
+ if (this.#status.phase === "running") return this.status();
1793
+ this.#session = this.#start({
1794
+ env: this.#env,
1795
+ homeDir: this.#homeDir,
1796
+ probe: this.#probe,
1797
+ openBrowser: () => void 0,
1798
+ onUpdate: (update) => this.#apply(update),
1799
+ onConnected: () => void 0
1800
+ });
1801
+ return webAuthStatus(this.#status, this.#status.phase !== "unavailable");
1802
+ }
1803
+ cancel() {
1804
+ this.#session?.cancel();
1805
+ return this.status();
1806
+ }
1807
+ #apply(update) {
1808
+ this.#status = {
1809
+ phase: update.phase,
1810
+ message: update.phase === "unavailable" ? "Official Codex browser sign-in is unavailable. Connect a supported API provider in this browser instead." : update.message,
1811
+ lines: [...update.lines]
1812
+ };
1813
+ if (update.phase !== "running") this.#session = null;
1814
+ }
1815
+ };
1816
+
1817
+ // packages/cli/src/web/operator-services.ts
1818
+ var MODEL_ROLES = ["discovery", "attack", "verify", "report", "audit", "review"];
1819
+ var reservedToolNames = Object.values(TOOL_DEFINITIONS).map((tool) => tool.name);
1820
+ var runtimeEnvironments = /* @__PURE__ */ new WeakMap();
1821
+ var runtimeContextLimits = /* @__PURE__ */ new WeakMap();
1822
+ var pluginManager;
1823
+ var pluginManagerPromise;
1824
+ var isTurnActive = () => false;
1825
+ var deferredPlugins = /* @__PURE__ */ new Set();
1826
+ async function getWebConsolePluginHostManager() {
1827
+ if (!pluginManagerPromise) {
1828
+ pluginManagerPromise = createSessionPluginHostManager({ reservedToolNames, coreVersion: VERSION }).then((manager2) => {
1829
+ pluginManager = manager2;
1830
+ return manager2;
1831
+ }).catch((error) => {
1832
+ pluginManagerPromise = void 0;
1833
+ throw error;
1834
+ });
1835
+ }
1836
+ const manager = await pluginManagerPromise;
1837
+ await manager.refresh();
1838
+ return manager;
1839
+ }
1840
+ var pluginService = createPluginService({
1841
+ registryUrl: (process.env.ZERO_REGISTRY_URL ?? DEFAULT_REGISTRY_URL).trim(),
1842
+ reservedToolNames,
1843
+ coreVersion: VERSION,
1844
+ isTurnActive: () => isTurnActive(),
1845
+ pluginHostManager: {
1846
+ refresh: async () => {
1847
+ await (await getWebConsolePluginHostManager()).refresh();
1848
+ },
1849
+ runPlugin: async (id) => (await getWebConsolePluginHostManager()).runPlugin(id)
1850
+ }
1851
+ });
1852
+ async function flushWebConsolePlugins() {
1853
+ if (consoleExecutionProfile() === "smolvm" || isTurnActive()) return [];
1854
+ const results = await pluginService.flushDeferred();
1855
+ deferredPlugins.clear();
1856
+ return results;
1857
+ }
1858
+ function webRuntimeEnv() {
1859
+ const env = { ...process.env };
1860
+ Object.assign(env, connectionConfigEnvPatch(env), credentialEnvPatch(loadCredentials(), env), accountEnvPatch(loadAccountStore(), env));
1861
+ maybeLoadCodexAuth({ env });
1862
+ return Object.fromEntries(Object.entries(env).filter((entry) => entry[1] !== void 0));
1863
+ }
1864
+ function publicMessage(error) {
1865
+ let message = error instanceof Error ? error.message : String(error);
1866
+ const secrets = /* @__PURE__ */ new Set();
1867
+ for (const provider2 of PROVIDERS) for (const variable of provider2.envVars) {
1868
+ const value = process.env[variable];
1869
+ if (value) secrets.add(value);
1870
+ }
1871
+ for (const accounts of Object.values(loadAccountStore().providers)) for (const record of Object.values(accounts.accounts)) {
1872
+ if (record.kind === "api_key") secrets.add(record.secret);
1873
+ else for (const token of [record.tokens.accessToken, record.tokens.refreshToken]) if (token) secrets.add(token);
1874
+ }
1875
+ const env = { ...process.env };
1876
+ maybeLoadCodexAuth({ env });
1877
+ for (const variable of PROVIDERS.find((provider2) => provider2.id === "chatgpt-codex").envVars) if (env[variable]) secrets.add(env[variable]);
1878
+ for (const secret of secrets) if (secret) message = message.split(secret).join("[redacted]");
1879
+ return message.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);
1880
+ }
1881
+ function runtimeDiagnostics(runtime) {
1882
+ const diagnostics = runtime.getConfigurationDiagnostics();
1883
+ return {
1884
+ valid: diagnostics.valid,
1885
+ reason: diagnostics.reason ?? null,
1886
+ message: diagnostics.fatalError ? publicMessage(diagnostics.fatalError) : null
1887
+ };
1888
+ }
1889
+ function connectionProbeRuntime(providerId, env) {
1890
+ return new LlmApiRuntime({
1891
+ type: "api",
1892
+ timeout: 3e5,
1893
+ provider: providerId,
1894
+ env,
1895
+ // OpenAI has no default model. Like accessibleProviders(), use an explicit
1896
+ // sentinel solely for auth/transport inspection. Azure must still validate
1897
+ // its real deployment configuration; the probe cannot supply that for it.
1898
+ ...providerId !== "azure" ? { model: "probe" } : {}
1899
+ });
1900
+ }
1901
+ function describeWebConsoleRuntime(runtime) {
1902
+ const providerId = runtime.resolvedProvider?.() ?? "unknown";
1903
+ const model = runtime.resolvedModel?.() ?? "unknown";
1904
+ const api = runtime instanceof LlmApiRuntime ? runtime : void 0;
1905
+ const diagnostics = api ? runtimeDiagnostics(api) : { valid: true, reason: null, message: null };
1906
+ return {
1907
+ providerId,
1908
+ providerLabel: PROVIDERS.find((provider2) => provider2.id === providerId)?.label ?? providerId,
1909
+ model,
1910
+ configured: diagnostics.valid,
1911
+ reasoning: api?.reasoningConfiguration() ?? null,
1912
+ connectionIdentity: api?.connectionIdentity() ?? null,
1913
+ diagnostics,
1914
+ ...runtime.modelSelection?.() ?? { agentModels: {}, singleModel: false, autoRoute: false },
1915
+ contextWindowTokens: (api ? runtimeContextLimits.get(api) : void 0) ?? resolveContextLimit({ modelId: model, providerId })?.tokens ?? null
1916
+ };
1917
+ }
1918
+ function savedWebRuntimeSelection(selection, info) {
1919
+ const { reasoningEffort: selectedEffort, ...stored } = selection;
1920
+ const effort = info ? info.reasoning?.effort : selectedEffort;
1921
+ const reasoning = effort && ["none", "low", "medium", "high", "xhigh", "max"].includes(effort) ? { reasoningEffort: effort } : {};
1922
+ if (!info) return { ...stored, ...reasoning };
1923
+ return {
1924
+ ...stored,
1925
+ providerId: info.providerId,
1926
+ model: info.model,
1927
+ agentModels: info.agentModels,
1928
+ singleModel: info.singleModel,
1929
+ autoRoute: info.autoRoute,
1930
+ ...reasoning
1931
+ };
1932
+ }
1933
+ function validateSelection(selection) {
1934
+ if (selection.providerId !== void 0 && !PROVIDERS.some((provider2) => provider2.id === selection.providerId)) throw new OperatorError(400, "invalid_provider", "Unsupported provider.");
1935
+ for (const value of [selection.model, ...Object.values(selection.agentModels ?? {})]) {
1936
+ 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.");
1937
+ }
1938
+ 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.");
1939
+ 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.");
1940
+ }
1941
+ async function validateRuntimeModels(runtime) {
1942
+ const diagnostics = runtime.getConfigurationDiagnostics();
1943
+ if (!diagnostics.valid) throw new OperatorError(409, "provider_not_ready", publicMessage(diagnostics.fatalError ?? "Connect the selected provider first."));
1944
+ if (diagnostics.provider === "chatgpt-codex") {
1945
+ let models;
1946
+ try {
1947
+ models = await runtime.codexModelCatalog(AbortSignal.timeout(1e4));
1948
+ } catch (error) {
1949
+ if (error instanceof CodexCatalogRefreshError) models = [...error.cachedModels];
1950
+ 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.");
1951
+ else throw error;
1952
+ }
1953
+ const selected = models.find((model) => model.id === runtime.resolvedModel());
1954
+ if (!selected) throw new OperatorError(409, "model_not_available", "The selected model is not available to this ChatGPT account.");
1955
+ if (selected.contextTokens) runtimeContextLimits.set(runtime, selected.contextTokens);
1956
+ for (const model of Object.values(runtime.modelSelection().agentModels)) {
1957
+ 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.");
1958
+ }
1959
+ }
1960
+ for (const role of Object.keys(runtime.modelSelection().agentModels)) {
1961
+ if (runtime.modelSelection().agentModels[role] !== "auto") await runtime.forkForSubagent(12e4, { role });
1962
+ }
1963
+ }
1964
+ async function createWebConsoleRuntime(selection = {}) {
1965
+ validateSelection(selection);
1966
+ const env = webRuntimeEnv();
1967
+ const { runtime } = await createPreferredConsoleRuntime({
1968
+ provider: selection.providerId,
1969
+ model: selection.model,
1970
+ agentModels: selection.agentModels,
1971
+ singleModel: selection.singleModel,
1972
+ autoRoute: selection.autoRoute,
1973
+ env
1974
+ });
1975
+ await validateRuntimeModels(runtime);
1976
+ if (selection.reasoningEffort !== void 0) {
1977
+ try {
1978
+ runtime.setReasoningEffort(selection.reasoningEffort);
1979
+ } catch {
1980
+ throw new OperatorError(400, "unsupported_reasoning_effort", "Choose an available thinking effort for this model.");
1981
+ }
1982
+ }
1983
+ runtimeEnvironments.set(runtime, env);
1984
+ if (selection.model !== void 0) saveAppliedModelPreference(runtime);
1985
+ return { runtime, info: describeWebConsoleRuntime(runtime) };
1986
+ }
1987
+ async function reloadWebConsoleRuntimeConnection(runtime) {
1988
+ const providerId = runtime.resolvedProvider();
1989
+ const model = runtime.resolvedModel();
1990
+ const effort = runtime.reasoningConfiguration()?.effort;
1991
+ const env = webRuntimeEnv();
1992
+ const { runtime: candidate } = await createPreferredConsoleRuntime({
1993
+ provider: providerId,
1994
+ model,
1995
+ ...runtime.modelSelection(),
1996
+ env
1997
+ });
1998
+ if (candidate.resolvedProvider() !== providerId || candidate.resolvedModel() !== model) throw new OperatorError(409, "connection_changed", "Reconnect the conversation's selected provider and model first.");
1999
+ await validateRuntimeModels(candidate);
2000
+ if (effort !== void 0) candidate.setReasoningEffort(effort);
2001
+ runtime.refreshConnection(env);
2002
+ runtimeEnvironments.set(runtime, env);
2003
+ const contextTokens2 = runtimeContextLimits.get(candidate);
2004
+ if (contextTokens2) runtimeContextLimits.set(runtime, contextTokens2);
2005
+ else runtimeContextLimits.delete(runtime);
2006
+ return describeWebConsoleRuntime(runtime);
2007
+ }
2008
+ async function applyWebConsoleRuntimeSelection(runtime, selection) {
2009
+ validateSelection(selection);
2010
+ const currentProvider = runtime.resolvedProvider();
2011
+ let providerId = selection.providerId;
2012
+ if (providerId === void 0 && selection.model !== void 0) {
2013
+ const inferred = modelProvider(selection.model);
2014
+ if (inferred !== "unknown" && inferred !== currentProvider && !(currentProvider === "chatgpt-codex" && inferred === "openai")) providerId = inferred;
2015
+ }
2016
+ const targetProvider = providerId ?? currentProvider;
2017
+ let candidate;
2018
+ if (targetProvider !== currentProvider) {
2019
+ const env = webRuntimeEnv();
2020
+ const created = await createPreferredConsoleRuntime({
2021
+ provider: targetProvider,
2022
+ model: selection.model,
2023
+ env,
2024
+ ...runtime.modelSelection(),
2025
+ ...selection
2026
+ });
2027
+ candidate = created.runtime;
2028
+ await validateRuntimeModels(candidate);
2029
+ runtimeEnvironments.set(candidate, env);
2030
+ } else {
2031
+ candidate = await runtime.forkForSubagent(12e4);
2032
+ candidate.reconfigure({ ...runtime.modelSelection(), ...selection });
2033
+ await validateRuntimeModels(candidate);
2034
+ }
2035
+ if (selection.reasoningEffort !== void 0) {
2036
+ try {
2037
+ candidate.setReasoningEffort(selection.reasoningEffort);
2038
+ } catch {
2039
+ throw new OperatorError(400, "unsupported_reasoning_effort", "Choose an available thinking effort for this model.");
2040
+ }
2041
+ }
2042
+ runtime.reconfigure({
2043
+ model: candidate.resolvedModel(),
2044
+ provider: targetProvider,
2045
+ ...candidate.modelSelection(),
2046
+ ...targetProvider !== currentProvider ? { env: runtimeEnvironments.get(candidate) } : {}
2047
+ });
2048
+ const reasoning = candidate.reasoningConfiguration();
2049
+ if (reasoning) runtime.setReasoningEffort(reasoning.effort);
2050
+ const contextTokens2 = runtimeContextLimits.get(candidate);
2051
+ if (contextTokens2) runtimeContextLimits.set(runtime, contextTokens2);
2052
+ else runtimeContextLimits.delete(runtime);
2053
+ if (selection.model !== void 0) saveAppliedModelPreference(runtime);
2054
+ return describeWebConsoleRuntime(runtime);
2055
+ }
2056
+ var OperatorError = class extends Error {
2057
+ constructor(status, code, message) {
2058
+ super(message);
2059
+ this.status = status;
2060
+ this.code = code;
2061
+ }
2062
+ status;
2063
+ code;
2064
+ };
2065
+ function object(input) {
2066
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new OperatorError(400, "invalid_input", "Expected a JSON object.");
2067
+ return input;
2068
+ }
2069
+ function text(input, name, max = 4096) {
2070
+ if (typeof input !== "string" || !input.trim() || input.length > max || /[\x00]/.test(input)) throw new OperatorError(400, "invalid_input", `Invalid ${name}.`);
2071
+ return input.trim();
2072
+ }
2073
+ function provider(input) {
2074
+ const id = input === "codex" ? "chatgpt-codex" : text(input, "provider", 64);
2075
+ const result = PROVIDERS.find((entry) => entry.id === id);
2076
+ if (!result) throw new OperatorError(404, "unknown_provider", "Provider does not exist.");
2077
+ return result;
2078
+ }
2079
+ function settingsView() {
2080
+ syncThemeChoices();
2081
+ return {
2082
+ settings: getSettings(),
2083
+ sources: getSettingSources(),
2084
+ defaultWriteLayer: defaultWriteLayer(),
2085
+ definitions: SETTING_DEFS.map((def) => ({ ...def, operatorOnly: isOperatorSetting(def.key) }))
2086
+ };
2087
+ }
2088
+ var WebOperatorServices = class {
2089
+ #servicePlugins = new ServicePluginServices();
2090
+ #codex = new CodexAuthController();
2091
+ #auth = /* @__PURE__ */ new Map();
2092
+ #registryItems = /* @__PURE__ */ new Map();
2093
+ #registryError = null;
2094
+ #feedback = null;
2095
+ constructor(options = {}) {
2096
+ isTurnActive = options.isTurnActive ?? (() => false);
2097
+ }
2098
+ #publicAuth(status) {
2099
+ return {
2100
+ ...status,
2101
+ message: publicMessage(status.message),
2102
+ lines: status.lines.map((line) => publicMessage(line))
2103
+ };
2104
+ }
2105
+ #authStatus(id, configured) {
2106
+ if (id === "chatgpt-codex") return this.#publicAuth(this.#codex.status());
2107
+ const flow = this.#auth.get(id);
2108
+ if (flow?.status.phase === "running") return { ...flow.status, lines: [...flow.status.lines] };
2109
+ if (configured) return webAuthStatus({ phase: "connected", message: "Credentials are configured. The first request verifies account access.", lines: [] }, Boolean(PROVIDER_DEVICE_AUTH[id]));
2110
+ if (flow && flow.status.phase !== "connected") return { ...flow.status, lines: [...flow.status.lines] };
2111
+ return webAuthStatus({ phase: "idle", message: "Not connected.", lines: [] }, Boolean(PROVIDER_DEVICE_AUTH[id]));
2112
+ }
2113
+ #providers() {
2114
+ const env = webRuntimeEnv();
2115
+ const store = loadAccountStore();
2116
+ const configs = loadConnectionConfigs();
2117
+ return PROVIDERS.map((info) => {
2118
+ let diagnostics = {
2119
+ valid: false,
2120
+ reason: "missing_key",
2121
+ message: "Connect this provider in the browser to configure credentials."
2122
+ };
2123
+ const via = info.envVars.find((key) => Boolean(env[key]?.trim()));
2124
+ const environment = info.envVars.some((key) => Boolean(process.env[key]?.trim()));
2125
+ const accounts = listAccounts(store, info.id).map(({ accountId, record, active }) => ({
2126
+ accountId,
2127
+ kind: record.kind,
2128
+ active,
2129
+ label: record.kind === "oauth" ? record.identity?.email ?? record.identity?.label ?? accountId : accountId
2130
+ }));
2131
+ const configured = Boolean(via);
2132
+ if (configured) {
2133
+ try {
2134
+ diagnostics = runtimeDiagnostics(connectionProbeRuntime(info.id, env));
2135
+ } catch (error) {
2136
+ diagnostics = { valid: false, reason: "invalid_config", message: publicMessage(error) };
2137
+ }
2138
+ }
2139
+ return {
2140
+ id: info.id,
2141
+ label: info.id === "openai" ? "OpenAI / Custom AI Provider" : info.label,
2142
+ methods: info.methods,
2143
+ configured,
2144
+ source: configured ? environment ? "environment" : store.providers[info.id] ? "account-store" : "codex-file" : null,
2145
+ diagnostics,
2146
+ accounts,
2147
+ configuration: configs[info.id] ?? {},
2148
+ auth: this.#authStatus(info.id, configured)
2149
+ };
2150
+ });
2151
+ }
2152
+ async #models(providerId) {
2153
+ if (providerId !== void 0) providerId = provider(providerId).id;
2154
+ const env = webRuntimeEnv();
2155
+ const ids = providerStates(env).filter((state) => state.configured && (!providerId || state.id === providerId)).map((state) => state.id);
2156
+ const [discovered] = await Promise.all([discoverConnectionModels(env, ids), syncModelCatalog()]);
2157
+ const metadata = new Map(buildFullModelCatalog().map((model) => [`${model.provider}/${model.id}`, model]));
2158
+ const rows = discovered.models.map((model) => ({
2159
+ id: model.id,
2160
+ provider: model.provider,
2161
+ price: 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",
2162
+ contextWindowTokens: model.contextTokens ?? resolveContextLimit({ modelId: model.id, providerId: model.provider })?.tokens ?? null,
2163
+ source: model.source === "catalog" ? "public-catalog" : "account"
2164
+ }));
2165
+ const configuredModel = env.OPENAI_MODEL;
2166
+ if (configuredModel && ids.includes("openai") && !rows.some((row) => row.provider === "openai" && row.id === configuredModel)) {
2167
+ rows.unshift({ id: configuredModel, provider: "openai", price: "Unknown rate", contextWindowTokens: null, source: "account" });
2168
+ }
2169
+ return {
2170
+ models: rows,
2171
+ providerId: providerId ?? null,
2172
+ diagnostics: discovered.diagnostics.map((item) => ({ ...item, message: publicMessage(item.message) })),
2173
+ roles: MODEL_ROLES
2174
+ };
2175
+ }
2176
+ async #connections(input) {
2177
+ const body = object(input);
2178
+ const info = provider(body.providerId);
2179
+ const action = text(body.action, "connection action", 32);
2180
+ if (action === "configure") {
2181
+ const config = validateConnectionConfig(info.id, {
2182
+ ...body.baseUrl !== void 0 ? { baseUrl: text(body.baseUrl, "API endpoint") } : {},
2183
+ ...body.model !== void 0 ? { model: text(body.model, "deployment model", 256) } : {},
2184
+ ...body.projectId !== void 0 ? { projectId: text(body.projectId, "Google project", 256) } : {}
2185
+ });
2186
+ if (!Object.keys(config).length) throw new OperatorError(400, "empty_configuration", "Choose a supported connection configuration field to update.");
2187
+ saveConnectionConfig(info.id, { ...loadConnectionConfigs()[info.id], ...config });
2188
+ return { providers: this.#providers() };
2189
+ }
2190
+ let store = loadAccountStore();
2191
+ if (action === "connect") {
2192
+ if (!info.methods.includes("api-key")) throw new OperatorError(400, "unsupported_auth", "Use this provider's browser sign-in flow.");
2193
+ const secret = text(body.apiKey, "API key", 16384);
2194
+ if (/[\s\x00-\x1f\x7f]/.test(secret)) throw new OperatorError(400, "invalid_key", "API keys must not contain whitespace or control characters.");
2195
+ const config = validateConnectionConfig(info.id, {
2196
+ ...body.baseUrl !== void 0 ? { baseUrl: text(body.baseUrl, "API endpoint") } : {},
2197
+ ...body.model !== void 0 ? { model: text(body.model, "deployment model", 256) } : {}
2198
+ });
2199
+ if (Object.keys(config).length) saveConnectionConfig(info.id, config);
2200
+ const accountId = body.accountId === void 0 ? void 0 : text(body.accountId, "account ID", 128);
2201
+ if (accountId && ["__proto__", "constructor", "prototype"].includes(accountId)) throw new OperatorError(400, "invalid_account", "Invalid account ID.");
2202
+ store = addAccount(store, info.id, { kind: "api_key", secret }, { accountId, makeActive: true }).store;
2203
+ } else if (action === "disconnect") {
2204
+ 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.");
2205
+ 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.");
2206
+ this.#auth.get(info.id)?.session?.cancel();
2207
+ this.#auth.delete(info.id);
2208
+ store = body.accountId === void 0 ? logoutProvider(store, info.id) : removeAccount(store, info.id, text(body.accountId, "account ID", 128));
2209
+ } else if (action === "activate") {
2210
+ const accountId = text(body.accountId, "account ID", 128);
2211
+ if (!store.providers[info.id]?.accounts[accountId]) throw new OperatorError(404, "unknown_account", "Saved account does not exist.");
2212
+ if (info.envVars.some((key) => process.env[key]?.trim())) throw new OperatorError(409, "environment_owned", "The explicit server credential takes precedence over saved accounts.");
2213
+ store = setActiveAccount(store, info.id, accountId);
2214
+ } else throw new OperatorError(400, "invalid_action", "Unsupported connection action.");
2215
+ if (!saveAccountStore(store)) throw new OperatorError(500, "persistence_failed", "Could not save the private credential account store.");
2216
+ return { providers: this.#providers() };
2217
+ }
2218
+ #deviceAuth(id, method) {
2219
+ const info = provider(id);
2220
+ if (info.id === "chatgpt-codex") return { status: this.#publicAuth(method === "DELETE" ? this.#codex.cancel() : this.#codex.start()) };
2221
+ const config = PROVIDER_DEVICE_AUTH[info.id];
2222
+ if (!config) throw new OperatorError(409, "auth_unavailable", "This provider does not support browser sign-in; connect its API key instead.");
2223
+ const previous = this.#auth.get(info.id);
2224
+ if (method === "DELETE") {
2225
+ previous?.session?.cancel();
2226
+ return { status: previous?.status ?? this.#authStatus(info.id, false) };
2227
+ }
2228
+ if (previous?.status.phase === "running") return { status: previous.status };
2229
+ const flow = { status: webAuthStatus({ phase: "running", message: "Starting browser sign-in.", lines: [] }), session: null, env: { ...process.env } };
2230
+ this.#auth.set(info.id, flow);
2231
+ flow.session = startDeviceAuth(config, {
2232
+ env: flow.env,
2233
+ openBrowser: (url) => {
2234
+ const safe = webAuthStatus({ phase: "running", message: "", lines: [url] });
2235
+ if (safe.verificationUrl) flow.status = { ...flow.status, verificationUrl: safe.verificationUrl };
2236
+ },
2237
+ onUpdate: (update) => {
2238
+ const status = webAuthStatus({ phase: update.phase, message: publicMessage(update.message), lines: update.lines.map((line) => publicMessage(line)) });
2239
+ flow.status = { ...status, verificationUrl: status.verificationUrl ?? flow.status.verificationUrl };
2240
+ if (update.phase !== "running") flow.session = null;
2241
+ },
2242
+ onConnected: () => void 0
2243
+ });
2244
+ return { status: flow.status };
2245
+ }
2246
+ async #plugins() {
2247
+ const registryUrl = (process.env.ZERO_REGISTRY_URL ?? DEFAULT_REGISTRY_URL).trim();
2248
+ let publicRegistryUrl = "";
2249
+ if (registryUrl) {
2250
+ try {
2251
+ const url = new URL(registryUrl);
2252
+ url.username = "";
2253
+ url.password = "";
2254
+ url.search = "";
2255
+ url.hash = "";
2256
+ publicRegistryUrl = url.href;
2257
+ } catch {
2258
+ publicRegistryUrl = "Invalid configured registry URL";
2259
+ }
2260
+ }
2261
+ const fetched = await pluginService.fetchRegistry();
2262
+ this.#registryError = fetched.ok ? null : publicMessage(registryUrl ? fetched.error.split(registryUrl).join(publicRegistryUrl) : fetched.error);
2263
+ this.#registryItems = fetched.ok ? new Map(buildMarketItems(fetched.result).map((item) => [`${item.kind}:${item.id}`, item])) : /* @__PURE__ */ new Map();
2264
+ const installed = await pluginService.list(getSettings().theme);
2265
+ const items = new Map(this.#registryItems);
2266
+ const errors = /* @__PURE__ */ new Map();
2267
+ for (const id of listInstalledPluginIds(pluginsRootDir())) {
2268
+ const discovered = readInstalledPlugin(pluginsRootDir(), id, { reservedToolNames });
2269
+ if (!discovered.ok) {
2270
+ errors.set(id, discovered.errors.join("; "));
2271
+ continue;
2272
+ }
2273
+ const manifest = discovered.plugin.manifest;
2274
+ items.set(`plugin:${id}`, {
2275
+ id,
2276
+ kind: "plugin",
2277
+ name: manifest.name ?? id,
2278
+ version: manifest.version,
2279
+ description: manifest.tools.map((tool) => tool.name).join(", "),
2280
+ capabilities: aggregateCapabilities(manifest),
2281
+ signature: "unverified",
2282
+ raw: void 0
2283
+ });
2284
+ }
2285
+ for (const theme of installedThemeEntries()) {
2286
+ if (!items.has(`theme:${theme.name}`)) items.set(`theme:${theme.name}`, {
2287
+ id: theme.name,
2288
+ kind: "theme",
2289
+ name: theme.label,
2290
+ version: "",
2291
+ description: theme.description,
2292
+ capabilities: [],
2293
+ signature: "unverified",
2294
+ raw: void 0
2295
+ });
2296
+ }
2297
+ const host = pluginManager?.current();
2298
+ const hostStates = host?.status() ?? [];
2299
+ const loadedPluginIds = hostStates.filter((entry) => entry.state === "ready").map((entry) => entry.pluginId);
2300
+ const result = [...items.values()].map(({ raw: _raw, ...item }) => ({
2301
+ ...item,
2302
+ state: item.kind === "theme" ? item.id === installed.activeTheme ? "active" : installed.themes.has(item.id) ? "installed" : "available" : installed.plugins.get(item.id) ?? "available",
2303
+ loaded: loadedPluginIds.includes(item.id),
2304
+ error: errors.get(item.id) ?? (hostStates.some((state) => state.pluginId === item.id && state.state === "unavailable") ? "Plugin is unavailable in the current host." : null)
2305
+ }));
2306
+ 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 });
2307
+ return {
2308
+ registry: { url: publicRegistryUrl, available: fetched.ok, error: this.#registryError },
2309
+ items: result,
2310
+ deferred: [...deferredPlugins],
2311
+ executionProfile: consoleExecutionProfile(),
2312
+ host: { loadedPluginIds, tools: host?.toolDefinitions().map(({ name, description }) => ({ name, description })) ?? [] }
2313
+ };
2314
+ }
2315
+ async #pluginAction(action, input) {
2316
+ 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.");
2317
+ const body = object(input);
2318
+ const id = text(body.id, "plugin ID", 64);
2319
+ if (action === "install") {
2320
+ const kind = body.kind === "theme" ? "theme" : "plugin";
2321
+ await this.#plugins();
2322
+ if (this.#registryError) throw new OperatorError(503, "registry_unavailable", this.#registryError);
2323
+ const item2 = this.#registryItems.get(`${kind}:${id}`);
2324
+ if (!item2) throw new OperatorError(404, "unknown_artifact", "The configured registry has no installable artifact with that ID.");
2325
+ const result2 = await pluginService.install(item2);
2326
+ if (!result2.ok) throw new OperatorError(409, "install_failed", result2.message);
2327
+ reloadInstalledThemes();
2328
+ return result2;
2329
+ }
2330
+ if (!isSafePluginId(id)) throw new OperatorError(400, "invalid_plugin", "Invalid plugin ID.");
2331
+ if (action === "disable") {
2332
+ if (!writeEnablement(process.cwd(), disable(readEnablement(process.cwd()), id))) throw new OperatorError(500, "persistence_failed", "Could not save plugin approval removal.");
2333
+ deferredPlugins.delete(id);
2334
+ return { ok: true, message: "Disabled for future sessions. Already leased sessions keep their approved host until cleanup.", state: "installed" };
2335
+ }
2336
+ const discovered = readInstalledPlugin(pluginsRootDir(), id, { reservedToolNames });
2337
+ if (!discovered.ok) throw new OperatorError(409, "invalid_plugin", discovered.errors.join("; "));
2338
+ const manifest = discovered.plugin.manifest;
2339
+ const capabilities = aggregateCapabilities(manifest);
2340
+ const item = { id, kind: "plugin", name: manifest.name ?? id, version: manifest.version, description: "", capabilities, signature: "unverified", raw: void 0 };
2341
+ if (action === "enable") {
2342
+ 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.");
2343
+ const result2 = await pluginService.enable(item);
2344
+ if (!result2.ok) throw new OperatorError(409, "enable_failed", result2.message);
2345
+ return consoleExecutionProfile() === "smolvm" ? { ...result2, message: "Approved for new SmolVM chats. Plugin files are copied and loaded automatically inside each new VM." } : result2;
2346
+ }
2347
+ if (action !== "run") throw new OperatorError(404, "unknown_action", "Unsupported plugin action.");
2348
+ const result = await pluginService.run(item);
2349
+ if (result.deferred) deferredPlugins.add(id);
2350
+ else if (!result.ok) throw new OperatorError(409, "run_failed", result.message);
2351
+ return result;
2352
+ }
2353
+ async handle(pathname, method, input, query) {
2354
+ if (!pathname.startsWith("/api/console/")) return null;
2355
+ const path = pathname.slice("/api/console/".length);
2356
+ const servicePluginResult = await this.#servicePlugins.handle(path, method, input);
2357
+ if (servicePluginResult) return servicePluginResult;
2358
+ if (!/^(providers(?:\/[^/]+(?:\/device-auth)?)?|models|connections|settings(?:\/reset)?|themes|plugins(?:\/(?:install|enable|disable|run))?|doctor|tools|project|checks|feedback)$/.test(path)) return null;
2359
+ try {
2360
+ let data;
2361
+ let status = 200;
2362
+ if (path === "providers" && method === "GET") data = { providers: this.#providers(), preference: getSettings().modelPreference };
2363
+ else if (path === "models" && method === "GET") data = await this.#models(query.get("providerId") ?? void 0);
2364
+ else if (path === "connections" && method === "POST") data = await this.#connections(input);
2365
+ else if (/^providers\/[^/]+\/device-auth$/.test(path) && ["POST", "DELETE"].includes(method)) {
2366
+ data = this.#deviceAuth(decodeURIComponent(path.split("/")[1]), method);
2367
+ status = method === "POST" ? 202 : 200;
2368
+ } else if (/^providers\/[^/]+$/.test(path) && method === "GET") {
2369
+ const info = provider(decodeURIComponent(path.split("/")[1]));
2370
+ const state = this.#providers().find((entry) => entry.id === info.id);
2371
+ data = { provider: state, status: state.auth };
2372
+ } else if (path === "settings" && method === "GET") data = settingsView();
2373
+ else if (path === "settings" && method === "PATCH") {
2374
+ const body = object(input);
2375
+ const key = text(body.key, "setting", 128);
2376
+ const def = SETTING_DEFS.find((entry) => entry.key === key);
2377
+ const internalBoolean = key === "onboardingCompleted" || key === "diagnosticReportingPrompted";
2378
+ if (!def && !internalBoolean) throw new OperatorError(400, "unknown_setting", "Only declared settings can be changed here. Model preferences are saved by successful runtime selection.");
2379
+ if (body.scope !== void 0 && body.scope !== "global" && body.scope !== "project") throw new OperatorError(400, "invalid_scope", "Settings scope must be global or project.");
2380
+ if (isOperatorSetting(key) && body.scope === "project") throw new OperatorError(400, "operator_global", "Operator consent and execution preferences can only be changed globally.");
2381
+ 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.");
2382
+ const persisted = updateSetting(key, body.value, { scope: body.scope });
2383
+ data = { ...settingsView(), persisted, ...!persisted ? { error: "Settings changed in this process but could not be saved to disk.", code: "persistence_failed" } : {} };
2384
+ if (!persisted) status = 507;
2385
+ } else if (path === "settings/reset" && method === "POST") {
2386
+ const body = object(input);
2387
+ const keys = body.keys ?? SETTING_DEFS.map((def) => def.key);
2388
+ 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.");
2389
+ const persisted = resetSettings(DEFAULT_SETTINGS, keys);
2390
+ data = { ...settingsView(), persisted, ...!persisted ? { error: "Settings reset in this process but could not be saved to disk.", code: "persistence_failed" } : {} };
2391
+ if (!persisted) status = 507;
2392
+ } else if (path === "themes" && method === "GET") data = { active: getSettings().theme, themes: allThemeNames().map((name) => ({ ...getThemeEntry(name) })) };
2393
+ else if (path === "plugins" && method === "GET") data = await this.#plugins();
2394
+ else if (path.startsWith("plugins/") && method === "POST") data = await this.#pluginAction(path.split("/")[1], input);
2395
+ else if (path === "doctor" && method === "GET") {
2396
+ const providers = this.#providers();
2397
+ const availability = await getRuntimeAvailability();
2398
+ const ready = providers.find((entry) => entry.diagnostics.valid);
2399
+ const settings = getSettings();
2400
+ data = {
2401
+ version: VERSION,
2402
+ runtime: { ...getRuntimeMetadata(), node: process.version, nodeSupported: Number(process.versions.node.split(".")[0]) >= 24 },
2403
+ 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 } },
2404
+ providers,
2405
+ 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 }],
2406
+ settings: { onboardingCompleted: settings.onboardingCompleted, analyticsLevel: settings.analyticsLevel, diagnosticReporting: settings.diagnosticReporting, executionProfile: settings.executionProfile }
2407
+ };
2408
+ } else if (path === "tools" && method === "GET") {
2409
+ 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))]));
2410
+ 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 })) ?? [] };
2411
+ } else if (path === "project" && method === "GET") {
2412
+ const projectPath = realpathSync(resolve(query.get("path") ?? process.cwd()));
2413
+ if (!statSync(projectPath).isDirectory()) throw new OperatorError(400, "invalid_project", "Project path must name a local directory.");
2414
+ const git = { root: null, branch: null, dirty: false, error: null };
2415
+ try {
2416
+ 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();
2417
+ 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;
2418
+ 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());
2419
+ } catch {
2420
+ git.error = "Git metadata is unavailable for this directory.";
2421
+ }
2422
+ data = { path: projectPath, name: basename(projectPath), git };
2423
+ } else if (path === "checks" && method === "GET") data = listProjectReviewChecks(query.get("path") ?? process.cwd());
2424
+ else if (path === "checks" && method === "POST") {
2425
+ const body = object(input);
2426
+ const mutation = object(body.mutation);
2427
+ const action = text(mutation.action, "review check action", 32);
2428
+ if (!["propose", "add", "enable", "disable", "set", "remove"].includes(action)) throw new OperatorError(400, "invalid_action", "Unsupported review check action.");
2429
+ if (mutation.approved !== void 0 && typeof mutation.approved !== "boolean") throw new OperatorError(400, "invalid_approval", "Approval must be an explicit boolean.");
2430
+ 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.");
2431
+ data = updateProjectReviewChecks(body.path === void 0 ? process.cwd() : text(body.path, "project path"), mutation);
2432
+ } else if (path === "feedback" && method === "POST") {
2433
+ const body = object(input);
2434
+ if (body.action === "cancel") {
2435
+ this.#feedback = null;
2436
+ data = { cancelled: true, submitted: false };
2437
+ } else if (body.action === "send") {
2438
+ const staged = this.#feedback;
2439
+ if (!staged || body.previewId !== staged.id) throw new OperatorError(409, "review_required", "Review and confirm the staged feedback before sending.");
2440
+ const result = await submitFeedback(staged.payload, process.env, { expectedPreview: staged.preview });
2441
+ if (!result.ok) throw new OperatorError(409, "submission_failed", result.error ?? "Feedback could not be submitted.");
2442
+ this.#feedback = null;
2443
+ data = { saved: true, submitted: true };
2444
+ } else {
2445
+ if (body.submit !== void 0 && typeof body.submit !== "boolean") throw new OperatorError(400, "invalid_submission", "Submission must be explicitly selected.");
2446
+ const payload = { message: text(body.message, "feedback", 16e3), timestamp: (/* @__PURE__ */ new Date()).toISOString(), version: VERSION };
2447
+ const saved = appendFeedback(payload);
2448
+ if (!saved.ok) throw new OperatorError(500, "persistence_failed", saved.error ?? "Could not save local feedback.");
2449
+ if (body.submit === true) {
2450
+ const preview = buildSubmitPreview(payload);
2451
+ if (!preview) throw new OperatorError(409, "submission_unavailable", "Local feedback was saved, but reporting is opted out or no supported HTTPS destination is available.");
2452
+ const id = randomUUID2();
2453
+ this.#feedback = { id, payload, preview };
2454
+ data = { saved: true, path: saved.path, submitted: false, previewId: id, preview: { ...preview, url: publicMessage(preview.url) } };
2455
+ } else data = { saved: true, path: saved.path, submitted: false };
2456
+ }
2457
+ } else throw new OperatorError(405, "method_not_allowed", "This operation does not support that HTTP method.");
2458
+ return { status, data };
2459
+ } catch (error) {
2460
+ return { status: error instanceof OperatorError ? error.status : 400, data: { error: publicMessage(error), code: error instanceof OperatorError ? error.code : "operation_failed" } };
2461
+ }
2462
+ }
2463
+ dispose() {
2464
+ this.#codex.cancel();
2465
+ for (const flow of this.#auth.values()) flow.session?.cancel();
2466
+ pluginManager?.dispose();
2467
+ }
2468
+ };
2469
+
2470
+ export {
2471
+ sanitizeComposerText,
2472
+ createSessionPluginHostManager,
2473
+ getWebConsolePluginHostManager,
2474
+ flushWebConsolePlugins,
2475
+ describeWebConsoleRuntime,
2476
+ savedWebRuntimeSelection,
2477
+ createWebConsoleRuntime,
2478
+ reloadWebConsoleRuntimeConnection,
2479
+ applyWebConsoleRuntimeSelection,
2480
+ WebOperatorServices
2481
+ };