0sec-cli 0.22.4 → 0.24.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 (208) hide show
  1. package/0.js +73 -68
  2. package/README.md +95 -61
  3. package/chunks/{adapt-loop-3CCOWE43.js → adapt-loop-TEJPXWFG.js} +4 -4
  4. package/chunks/{artifact-scraper-Z4UUIOH3.js → artifact-scraper-AJZ3LOQY.js} +2 -2
  5. package/chunks/{assumption-mining-2UAKQB6V.js → assumption-mining-EATDC4BB.js} +18 -18
  6. package/chunks/backend-connections-QE4NASAK.js +23 -0
  7. package/chunks/chunk-3XLEDCFX.js +566 -0
  8. package/chunks/{chunk-BGX53365.js → chunk-3XLFB46W.js} +5 -3
  9. package/chunks/{chunk-IXAHQICR.js → chunk-4TUR47H5.js} +8 -3
  10. package/chunks/{chunk-5WAJGLCW.js → chunk-4YRXIVPZ.js} +3 -3
  11. package/chunks/{chunk-4ZYYX5GY.js → chunk-52AWIBCT.js} +1 -1
  12. package/chunks/{chunk-TO35Y326.js → chunk-554D4AYM.js} +5 -2
  13. package/chunks/{chunk-GQ3DGHWE.js → chunk-5FHFG5P2.js} +174 -710
  14. package/chunks/chunk-5POT5OYF.js +733 -0
  15. package/chunks/chunk-62PGWN7Y.js +700 -0
  16. package/chunks/{chunk-H6Q2QAIY.js → chunk-A3EKBUEM.js} +1424 -859
  17. package/chunks/{chunk-6WQDXWQC.js → chunk-A6AZZ6XX.js} +2 -2
  18. package/chunks/{chunk-6YZE552K.js → chunk-AV5BF4V7.js} +1281 -2580
  19. package/chunks/{chunk-2WWAPKAW.js → chunk-BIJPMYFA.js} +6 -6
  20. package/chunks/{chunk-SCWWLABR.js → chunk-CIMN2AO6.js} +1 -1
  21. package/chunks/{chunk-H4DH7COV.js → chunk-CSPF47S3.js} +30 -20
  22. package/chunks/{chunk-RCRTSKQN.js → chunk-DNV3ZMPX.js} +1 -1
  23. package/chunks/{chunk-GVY3S5E5.js → chunk-E42XEJTK.js} +2 -2
  24. package/chunks/{chunk-VDOWARMJ.js → chunk-ESM447R6.js} +15 -1
  25. package/chunks/{chunk-WBRGXCU2.js → chunk-EXTN4SQV.js} +1 -1
  26. package/chunks/{chunk-QVIRWJ45.js → chunk-EYBMTELO.js} +108 -24
  27. package/chunks/chunk-FEOPHBMY.js +56 -0
  28. package/chunks/{chunk-IHPTOTLL.js → chunk-FKGFHLLS.js} +1 -1
  29. package/chunks/chunk-G2EJ3R5I.js +5198 -0
  30. package/chunks/chunk-GHEBZKUS.js +5417 -0
  31. package/chunks/chunk-GNR3APR6.js +295 -0
  32. package/chunks/{chunk-ELI3BVIK.js → chunk-H76JYUPE.js} +3 -3
  33. package/chunks/{chunk-E74LXQFY.js → chunk-HRBOZBMC.js} +1 -1
  34. package/chunks/{chunk-TM74SSHC.js → chunk-IIBNQTOK.js} +3 -2
  35. package/chunks/{chunk-UELXHK2Y.js → chunk-IK27KMVV.js} +16 -5
  36. package/chunks/{chunk-WHUAUFSX.js → chunk-J6G73WYF.js} +1 -1
  37. package/chunks/chunk-JSTLXPJS.js +284 -0
  38. package/chunks/{chunk-G2BE2FC7.js → chunk-O3ADFN2A.js} +1 -1
  39. package/chunks/chunk-O7Q2G2KW.js +117 -0
  40. package/chunks/{chunk-XODDLNBI.js → chunk-QEA2VHBD.js} +284 -33
  41. package/chunks/{chunk-C6JPA32H.js → chunk-RBOMXUYL.js} +3 -111
  42. package/chunks/{chunk-L2CCO4KE.js → chunk-RCHAFSWS.js} +838 -39
  43. package/chunks/{chunk-3BPX75OR.js → chunk-RD4FKFWR.js} +1 -1
  44. package/chunks/{chunk-DPUXXMJW.js → chunk-RPTO5FY2.js} +1 -1
  45. package/chunks/{chunk-6KFB6AYN.js → chunk-RZR2XXAK.js} +531 -17
  46. package/chunks/chunk-SGILXLR3.js +289 -0
  47. package/chunks/{chunk-E3OOBVOK.js → chunk-TOAAYJVN.js} +2 -2
  48. package/chunks/chunk-TOFIGQ63.js +83 -0
  49. package/chunks/{chunk-QWK4R3DB.js → chunk-TTDFBFNZ.js} +6 -6
  50. package/chunks/chunk-TZRHWP7R.js +736 -0
  51. package/chunks/chunk-UHUW45S3.js +164 -0
  52. package/chunks/{chunk-5JNTMWPK.js → chunk-V4BD7GSP.js} +2 -2
  53. package/chunks/{chunk-OAS5SAVZ.js → chunk-V5I5GAQH.js} +3226 -1683
  54. package/chunks/{chunk-PS5E7LUQ.js → chunk-W6IYTSZH.js} +79 -9
  55. package/chunks/{chunk-RTBZ36BD.js → chunk-WUPN3D37.js} +22 -248
  56. package/chunks/{chunk-CF3MNS3O.js → chunk-Y7KV7WV6.js} +2 -2
  57. package/chunks/{chunk-2OQOQ2FZ.js → chunk-YERUDEXT.js} +763 -688
  58. package/chunks/{chunk-CPCHLL6A.js → chunk-YJU7QACE.js} +1 -1
  59. package/chunks/{chunk-YED25PA4.js → chunk-YORL5S5V.js} +1 -1
  60. package/chunks/{chunk-YAZARMJY.js → chunk-YYOQADBB.js} +4 -3
  61. package/chunks/chunk-ZPFBQ3SD.js +127 -0
  62. package/chunks/{codex-models-Z43V3427.js → codex-models-FQPCWRPC.js} +7 -7
  63. package/chunks/{commands-EUGF4FUZ.js → commands-I5L3VD2A.js} +6187 -12196
  64. package/chunks/dashboard-B2AEGCFM.js +76 -0
  65. package/chunks/{db-NVAW4WWR.js → db-P5EIKMLP.js} +3 -3
  66. package/chunks/deep-review-I7RD5QSS.js +82 -0
  67. package/chunks/{disclose-LDNKAVRH.js → disclose-PFBWESVJ.js} +4 -2
  68. package/chunks/{dist-7RUOKPRJ.js → dist-3SWWY5FZ.js} +18 -2
  69. package/chunks/{dist-27BNG6WD.js → dist-AJU25UXA.js} +112 -63
  70. package/chunks/{dist-NG2HT5XU.js → dist-VK2M4HNW.js} +85 -1
  71. package/chunks/eval-runner-XVRX3R2Y.js +31 -0
  72. package/chunks/{exploit-agent-FCCR2HYX.js → exploit-agent-A4RTIJ4J.js} +1 -1
  73. package/chunks/{exploit-autoclimb-X5ZS5FAO.js → exploit-autoclimb-ABMMBC3M.js} +1 -1
  74. package/chunks/{exploit-climb-3JHGEO36.js → exploit-climb-BQ2SVU63.js} +2 -2
  75. package/chunks/{fix-NSNPU33B.js → fix-4YCLHFDT.js} +7 -7
  76. package/chunks/{harness-KXQOVIDQ.js → harness-DHWULEIZ.js} +3 -3
  77. package/chunks/{hunt-scan-ELTKGKC4.js → hunt-scan-DXV5H6YN.js} +16 -16
  78. package/chunks/{kernel-primitive-MT7YZSIG.js → kernel-primitive-SF4NALVR.js} +2 -2
  79. package/chunks/{kernel-vm-runner-YFRHYC6G.js → kernel-vm-runner-WEBEZEIC.js} +2 -2
  80. package/chunks/local-engine-XUG7XRKM.js +21 -0
  81. package/chunks/managed-operation-SQFMBWHG.js +60 -0
  82. package/chunks/{memsafety-scan-FCPAXIZE.js → memsafety-scan-L2Z7E7TE.js} +2 -2
  83. package/chunks/{native-loop-OFJDRHPI.js → native-loop-ZNAELJGB.js} +14 -13
  84. package/chunks/orchestrate-YHFJXGID.js +63 -0
  85. package/chunks/{prepare-72GWTRVI.js → prepare-SODWQN6O.js} +5 -5
  86. package/chunks/provider-model-discovery-QGUGL3XW.js +277 -0
  87. package/chunks/remote-workflow-runtime-XNNGI2PG.js +12 -0
  88. package/chunks/{run-WTJCZZHV.js → run-5T4Z3Q2D.js} +924 -327
  89. package/chunks/{runtime-LCJ4XSKE.js → runtime-HFFRUOPL.js} +4 -2
  90. package/chunks/{runtime-FCKOUB7V.js → runtime-MB4GEFBY.js} +7 -7
  91. package/chunks/{scan-stream-GT6GKQ3U.js → scan-stream-GXBJHCDF.js} +3 -2
  92. package/chunks/{scope-E5QZUOOH.js → scope-M7L3CD6X.js} +2 -2
  93. package/chunks/service-plugins-BGS6QKSZ.js +64 -0
  94. package/chunks/{session-store-H3Q7KCYG.js → session-store-K7I4GLNH.js} +2 -2
  95. package/chunks/{variant-candidates-SZKDCOLK.js → variant-candidates-2KSP5EHH.js} +7 -7
  96. package/chunks/{web-recon-prepass-IO3GXQMW.js → web-recon-prepass-RAXXTEWH.js} +5 -5
  97. package/chunks/workflow-runtime-V26HIJO3.js +178 -0
  98. package/dashboard/assets/abnfDiagram-VCTEODGH-CGCueOp5.js +1 -0
  99. package/dashboard/assets/arc-BjZaQcCc.js +1 -0
  100. package/dashboard/assets/architecture-7GRP2DOG-hcbO-9zX.js +1 -0
  101. package/dashboard/assets/architectureDiagram-5GKGNRK7-DReOXTSq.js +36 -0
  102. package/dashboard/assets/array-BifhSqXX.js +1 -0
  103. package/dashboard/assets/blockDiagram-I7D4REHJ-C-byT12_.js +129 -0
  104. package/dashboard/assets/c4Diagram-7LVT6UL2-DoYjz-Uv.js +38 -0
  105. package/dashboard/assets/channel-CUURBnpZ.js +1 -0
  106. package/dashboard/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  107. package/dashboard/assets/chunk-4HAMMTFA-NBNp2zdt.js +62 -0
  108. package/dashboard/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  109. package/dashboard/assets/chunk-75Z2AOVW-BHmkuP0B.js +2 -0
  110. package/dashboard/assets/chunk-DU6HZSFF-DgfLNaL2.js +127 -0
  111. package/dashboard/assets/chunk-F27PBJKO-3wwNFUgZ.js +1 -0
  112. package/dashboard/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
  113. package/dashboard/assets/chunk-GMAD6QVW-Btg7huZW.js +72 -0
  114. package/dashboard/assets/chunk-GVQU2GXP-ihCURK5O.js +1 -0
  115. package/dashboard/assets/chunk-IMKFNOWR-FsXj7slg.js +231 -0
  116. package/dashboard/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  117. package/dashboard/assets/chunk-L3NEJ4N5-DorFIxJY.js +1 -0
  118. package/dashboard/assets/chunk-OSK3NFVY-DKun_KfC.js +10 -0
  119. package/dashboard/assets/chunk-P2QGCYS3-XGgiU1Bz.js +1 -0
  120. package/dashboard/assets/chunk-POPQ4Y6H-BTXEnGhJ.js +1 -0
  121. package/dashboard/assets/chunk-PWAF6VOD-DYZcGkTL.js +1 -0
  122. package/dashboard/assets/chunk-SHT3W25Y-C4WQfwf8.js +168 -0
  123. package/dashboard/assets/chunk-SVP7TREG-C4nCh0-1.js +88 -0
  124. package/dashboard/assets/chunk-TICWLB2K-DSB-IiGc.js +206 -0
  125. package/dashboard/assets/chunk-XXDRQBXY-CS6fjUcj.js +1 -0
  126. package/dashboard/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  127. package/dashboard/assets/classDiagram-ZZMXUADV-CD1Buc26.js +1 -0
  128. package/dashboard/assets/classDiagram-v2-VYDZK3BY-CD1Buc26.js +1 -0
  129. package/dashboard/assets/common-BMdQBwfR.js +5 -0
  130. package/dashboard/assets/cose-bilkent-JH36ORCC-CUjQHTML.js +1 -0
  131. package/dashboard/assets/cynefin-OW5HDTMX-BC7zCtFq.js +1 -0
  132. package/dashboard/assets/cynefinDiagram-5FMLGOSQ-CgDOOY67.js +62 -0
  133. package/dashboard/assets/cytoscape.esm-CGd-uY3x.js +321 -0
  134. package/dashboard/assets/dagre-GXQ25YYZ-Dqc8FS9x.js +4 -0
  135. package/dashboard/assets/dagre-PrKaheQc.js +1 -0
  136. package/dashboard/assets/defaultLocale-BFoDCU3G.js +1 -0
  137. package/dashboard/assets/diagram-S7CK7UJ4-CrKqRXZb.js +30 -0
  138. package/dashboard/assets/diagram-UQ7AKVKN-Cu6Es0-v.js +41 -0
  139. package/dashboard/assets/diagram-VSXAHHWV-eK4d8FwS.js +3 -0
  140. package/dashboard/assets/diagram-VX7I27RA-bFxeFKOc.js +24 -0
  141. package/dashboard/assets/diagram-Z3DM3KII-C0ClmnhC.js +24 -0
  142. package/dashboard/assets/dist-BZh8Kb3O.js +1 -0
  143. package/dashboard/assets/ebnfDiagram-PWID7BFC-CUqxFPzf.js +1 -0
  144. package/dashboard/assets/erDiagram-RLTQ6QDP-CcYM7pLi.js +99 -0
  145. package/dashboard/assets/eventmodeling-NTZA5JFV-D8ZNnPkV.js +1 -0
  146. package/dashboard/assets/flowDiagram-HODETNUW-pDb1AYm8.js +1 -0
  147. package/dashboard/assets/ganttDiagram-EL5Y4UJY-UmZfbMyD.js +292 -0
  148. package/dashboard/assets/gitGraph-4MIJSDKK-mvNUo0ZA.js +1 -0
  149. package/dashboard/assets/gitGraphDiagram-WWUBYQGX-CvzeCxVy.js +106 -0
  150. package/dashboard/assets/graphlib-DS17s2tU.js +1 -0
  151. package/dashboard/assets/info-A6RAGUB7-DChKqZMi.js +1 -0
  152. package/dashboard/assets/infoDiagram-27XIBGKW-DjkpNtVW.js +2 -0
  153. package/dashboard/assets/init-C-OQMol4.js +1 -0
  154. package/dashboard/assets/ishikawaDiagram-5VMMS53U-8FhjJaWT.js +70 -0
  155. package/dashboard/assets/journeyDiagram-3NMN7TZE-DyNJ755f.js +139 -0
  156. package/dashboard/assets/kanban-definition-UXKFOSKX-_jCmtaY1.js +89 -0
  157. package/dashboard/assets/katex-BdBmVSus.js +257 -0
  158. package/dashboard/assets/line-Bf0nxyWf.js +1 -0
  159. package/dashboard/assets/linear-Bl6JKbf4.js +1 -0
  160. package/dashboard/assets/mermaid-parser.core-Cc6sgCzs.js +7 -0
  161. package/dashboard/assets/mermaid.core-B4yCwiN-.js +44 -0
  162. package/dashboard/assets/mindmap-definition-YA3MSWOX-D5DjWyXj.js +96 -0
  163. package/dashboard/assets/operations-B7JAWOi6.js +130 -0
  164. package/dashboard/assets/operations-QjKT0Hwi.css +1 -0
  165. package/dashboard/assets/ordinal-BDEzSJ7C.js +1 -0
  166. package/dashboard/assets/packet-AYTQ26CC-bQXLDhQC.js +1 -0
  167. package/dashboard/assets/path-fybaL0A-.js +1 -0
  168. package/dashboard/assets/pegDiagram-XKGWAZYB-Bf6a1vaf.js +1 -0
  169. package/dashboard/assets/pie-WAS4IAKB-DfzoABIi.js +1 -0
  170. package/dashboard/assets/pieDiagram-E7YTZNPT-D0L1qbch.js +39 -0
  171. package/dashboard/assets/quadrantDiagram-AXDQQJYC-CbFyy2Pe.js +7 -0
  172. package/dashboard/assets/radar-RG4KPBEZ-CZ2pyeUT.js +1 -0
  173. package/dashboard/assets/railroad-74A4TZTK-CP4Jazfd.js +1 -0
  174. package/dashboard/assets/railroad-abnf-HS5TGJTU-3MvEiHwD.js +1 -0
  175. package/dashboard/assets/railroad-ebnf-LZEXJU2U-BWto6cXE.js +1 -0
  176. package/dashboard/assets/railroad-peg-WCYAUIDC-DasEjbyf.js +1 -0
  177. package/dashboard/assets/railroadDiagram-O6MQD6OU-t7Gp9g2R.js +1 -0
  178. package/dashboard/assets/requirementDiagram-BXWQKSXE-LYmqeBXi.js +84 -0
  179. package/dashboard/assets/rough.esm-Dy-Kn_BL.js +1 -0
  180. package/dashboard/assets/sankeyDiagram-P5KCCOFB-DnpfA_94.js +40 -0
  181. package/dashboard/assets/sequenceDiagram-WJ2MYXX4-C8s3pTUE.js +162 -0
  182. package/dashboard/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  183. package/dashboard/assets/src-CaNUT1AQ.js +1 -0
  184. package/dashboard/assets/stateDiagram-D77RDMKH-BMzm6fK1.js +1 -0
  185. package/dashboard/assets/stateDiagram-v2-MP3YSRHH-B3REMjpY.js +1 -0
  186. package/dashboard/assets/swimlanes-42K2YHIH-uJE05Tt_.js +1 -0
  187. package/dashboard/assets/swimlanesDiagram-VR7AAH4N-CIaVMZEy.js +8 -0
  188. package/dashboard/assets/timeline-definition-24CTP7MA-BfLJMVeG.js +120 -0
  189. package/dashboard/assets/treeView-Q6P3EWNA-ZOE2enu2.js +1 -0
  190. package/dashboard/assets/treemap-WGGIJYW6-yIZoPBF5.js +1 -0
  191. package/dashboard/assets/vennDiagram-4TSXK5OY-BYJRHEaL.js +34 -0
  192. package/dashboard/assets/wardley-WFR3VGLG-D5V-jLbB.js +1 -0
  193. package/dashboard/assets/wardleyDiagram-VM6X3IG4-DgPN4nSe.js +78 -0
  194. package/dashboard/assets/xychartDiagram-S5SC5T6Z-BhkAMAOT.js +7 -0
  195. package/dashboard/index.html +3 -3
  196. package/package.json +3 -2
  197. package/worker-assets/demo-target/README.md +15 -0
  198. package/worker-assets/demo-target/include/decoder.h +27 -0
  199. package/worker-assets/demo-target/patched-decoder.c +40 -0
  200. package/worker-assets/demo-target/src/decoder.c +50 -0
  201. package/worker-assets/demo-target/witness-65537x1.bin +0 -0
  202. package/chunks/chunk-FFHRANYC.js +0 -547
  203. package/chunks/eval-runner-6Q3H52SP.js +0 -30
  204. package/chunks/orchestrate-DRZ2SVCP.js +0 -62
  205. package/chunks/service-plugins-MSK2EQP6.js +0 -62
  206. package/dashboard/assets/operations-BvB5Qpmk.css +0 -1
  207. package/dashboard/assets/operations-D8Ii01SV.js +0 -114
  208. package/dashboard/assets/zero-peek-Dzm3MT3X.png +0 -0
@@ -1,55 +1,56 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __0CreateRequire } from "node:module";
3
3
  const require = __0CreateRequire(import.meta.url);
4
+ import {
5
+ runLensSynthesisInput,
6
+ watchLensSynthCommand
7
+ } from "./chunk-JSTLXPJS.js";
8
+ import {
9
+ compareFindingRowsByBusinessPriority,
10
+ cycleChoice,
11
+ describeEventPayload,
12
+ describeFindingsFilters,
13
+ findingFromRow,
14
+ findingRowPriority,
15
+ formatDuration,
16
+ isNativeRuntime,
17
+ parseSummary
18
+ } from "./chunk-O7Q2G2KW.js";
4
19
  import {
5
20
  DIALOG_HOST_FOOTER_ROWS,
6
21
  FIX_USAGE,
7
22
  PROVIDER_DEVICE_AUTH,
8
23
  SETTINGS_DIALOG_HOST_ROWS,
9
24
  actionForRow,
10
- activateModelConnectAction,
11
- agentRosterLines,
12
- buildContextWindowIndex,
13
25
  buildDialogRows,
14
26
  buildFindingChatPrompt,
15
27
  buildFullModelCatalog,
16
28
  buildMarketItems,
17
29
  buildMarketRows,
18
- buildModelRows,
30
+ buildModelCatalog,
19
31
  buildSettingsRows,
20
- catalogContextKey,
21
32
  clampDialogSelection,
22
33
  clampSelection,
23
34
  clipMarketDetailLines,
24
- clipModelDetailLines,
25
35
  computeDialogPanel,
26
36
  computeDialogScreenLayout,
27
37
  computeKvSplit,
28
38
  computeListWindow,
29
39
  computeMarketLayout,
30
- computeModelDialogLayout,
31
40
  computeSettingsLayout,
32
- configuredProviderLabels,
33
41
  confirmPrompt,
34
- contextWindowFor,
35
42
  createLocalConsoleSession,
36
43
  createPluginService,
37
44
  createPreferredConsoleRuntime,
38
45
  createSessionPluginHostManager,
39
- credentialEnvPatch,
40
- credentialSummary,
41
- cycleChoice,
42
46
  cycleSetting,
43
- describeEventPayload,
44
- describeFindingsFilters,
45
47
  describeFixStatus,
46
- dialogContentWidth,
47
48
  dialogDisplayIndex,
48
49
  dialogRowColumns,
49
50
  dialogWindow,
51
+ discoverConnectionModels,
50
52
  exportChatConversation,
51
53
  filterDialogItems,
52
- findingFromRow,
53
54
  findingSourcePath,
54
55
  firstEnabled,
55
56
  fitHint,
@@ -60,51 +61,29 @@ import {
60
61
  fixInputEligibility,
61
62
  fixPublicationLines,
62
63
  fixResultLines,
63
- formatDuration,
64
- getSymbols,
65
- groupFindings,
66
64
  isFilterKey,
67
65
  isFilterKey2,
68
- isFilterKey3,
69
- isModelConnectAction,
70
- isNativeRuntime,
71
66
  isSettingModified,
72
67
  keyGlyph,
73
- loadAccountStore,
74
68
  loadCatalogModels,
75
- loadCredentials,
76
69
  loadFindingFocus,
77
70
  marketDetailLines,
78
71
  marketDialogItems,
79
72
  marketDialogMeta,
80
73
  marketEmptyLines,
81
74
  marketFooterHint,
82
- modelConnectActionItem,
83
- modelConnectDetailLines,
84
- modelDetailLines,
85
- modelDialogCount,
86
- modelDialogHint,
87
- modelDialogTitle,
88
- modelFooterHint,
89
- modelResultCount,
90
- modelTargetLine,
91
75
  moveDialogSelection,
92
76
  moveSelection,
93
77
  paneTitleColumns,
94
- parseSummary,
95
78
  rankDialogItem,
96
- reachableModelCatalog,
97
- redactSecret,
98
79
  reduceWorkerTelemetry,
99
80
  resetAllSettings,
100
81
  resetSetting,
101
82
  resolveContextLimit,
102
- runLensSynthesisInput,
103
83
  runUnified,
104
84
  sanitizeComposerText,
105
85
  sanitizeTuiText,
106
86
  saveAppliedModelPreference,
107
- saveCredentials,
108
87
  scopeModelCatalog,
109
88
  selectConversationContext,
110
89
  settingValue,
@@ -117,21 +96,13 @@ import {
117
96
  stateTag,
118
97
  syncModelCatalog,
119
98
  titleColumns,
120
- watchLensSynthCommand,
121
99
  wrapCells,
122
100
  wrapText
123
- } from "./chunk-6YZE552K.js";
101
+ } from "./chunk-AV5BF4V7.js";
124
102
  import {
125
103
  buildShareUrl,
126
104
  getRuntimeAvailability
127
- } from "./chunk-GQ3DGHWE.js";
128
- import {
129
- consoleExecutionProfile,
130
- loadServicePluginConnections
131
- } from "./chunk-PS5E7LUQ.js";
132
- import {
133
- getRuntimeMetadata
134
- } from "./chunk-IXAHQICR.js";
105
+ } from "./chunk-3XLEDCFX.js";
135
106
  import {
136
107
  deleteSession,
137
108
  listSessions,
@@ -139,7 +110,11 @@ import {
139
110
  pruneSessions,
140
111
  relativeAge,
141
112
  saveSession
142
- } from "./chunk-BGX53365.js";
113
+ } from "./chunk-3XLFB46W.js";
114
+ import {
115
+ consoleExecutionProfile,
116
+ loadServicePluginConnections
117
+ } from "./chunk-W6IYTSZH.js";
143
118
  import {
144
119
  reportHerdrActivity,
145
120
  reportHerdrCompaction,
@@ -149,23 +124,36 @@ import {
149
124
  reportHerdrSession,
150
125
  reportHerdrSessionClose,
151
126
  reportHerdrTarget,
152
- reportOperatorGate
153
- } from "./chunk-VDOWARMJ.js";
127
+ reportOperatorGate,
128
+ savedConnectionEnvPatch
129
+ } from "./chunk-ESM447R6.js";
130
+ import {
131
+ SHIMMER_TEXT_INTERVAL_MS,
132
+ UI_ANIMATION_INTERVAL_MS,
133
+ resumeProcessPresentationStreamBridge,
134
+ shimmerText,
135
+ spinnerGlyph,
136
+ suspendProcessPresentationStreamBridge
137
+ } from "./chunk-GNR3APR6.js";
154
138
  import {
155
139
  createPresentationEmitter,
140
+ presentationEventBus
141
+ } from "./chunk-FEOPHBMY.js";
142
+ import {
156
143
  getAnalyticsSetupDraft,
157
144
  getSettings,
158
- presentationEventBus,
145
+ loadAccountStore,
146
+ loadCredentials,
159
147
  previewSetting,
148
+ redactSecret,
160
149
  reloadSettings,
161
150
  resetSettings,
162
151
  resolveEngagement,
163
- resumeProcessPresentationStreamBridge,
152
+ saveCredentials,
164
153
  subscribeSettings,
165
- suspendProcessPresentationStreamBridge,
166
154
  updateSetting,
167
155
  useSettings
168
- } from "./chunk-FFHRANYC.js";
156
+ } from "./chunk-62PGWN7Y.js";
169
157
  import "./chunk-HLFS6WV2.js";
170
158
  import {
171
159
  KEYBINDINGS,
@@ -196,7 +184,7 @@ import {
196
184
  severityToneFor,
197
185
  submissionBlockedReason,
198
186
  submitFeedback
199
- } from "./chunk-XODDLNBI.js";
187
+ } from "./chunk-QEA2VHBD.js";
200
188
  import {
201
189
  DEFAULT_REGISTRY_URL,
202
190
  appendStageAction,
@@ -207,38 +195,45 @@ import {
207
195
  markProcessed,
208
196
  normalizeStageAction,
209
197
  normalizeStageEndDetail,
210
- parseImpactAssessment,
211
198
  parseMcpConfig,
212
199
  releaseClaim,
213
200
  releaseStaleClaims
214
- } from "./chunk-OAS5SAVZ.js";
215
- import "./chunk-E3OOBVOK.js";
201
+ } from "./chunk-V5I5GAQH.js";
202
+ import "./chunk-5FHFG5P2.js";
203
+ import "./chunk-4YRXIVPZ.js";
204
+ import "./chunk-TOAAYJVN.js";
205
+ import {
206
+ getRuntimeMetadata
207
+ } from "./chunk-4TUR47H5.js";
208
+ import "./chunk-GVD6SJGH.js";
216
209
  import "./chunk-QCUFBVIZ.js";
217
- import "./chunk-5JNTMWPK.js";
218
- import "./chunk-TM74SSHC.js";
210
+ import "./chunk-V4BD7GSP.js";
211
+ import "./chunk-IIBNQTOK.js";
219
212
  import "./chunk-2WNCI664.js";
220
213
  import "./chunk-23DG5YKS.js";
221
214
  import "./chunk-DQTNI3KY.js";
222
- import "./chunk-IHPTOTLL.js";
223
- import "./chunk-DPUXXMJW.js";
224
- import "./chunk-5WAJGLCW.js";
225
- import "./chunk-E74LXQFY.js";
215
+ import "./chunk-FKGFHLLS.js";
216
+ import "./chunk-RPTO5FY2.js";
217
+ import "./chunk-E42XEJTK.js";
218
+ import "./chunk-HRBOZBMC.js";
226
219
  import "./chunk-AZ7L3HFD.js";
227
- import "./chunk-ELI3BVIK.js";
228
- import "./chunk-H4DH7COV.js";
220
+ import "./chunk-H76JYUPE.js";
221
+ import "./chunk-CSPF47S3.js";
229
222
  import {
230
223
  TOOL_DEFINITIONS,
231
224
  agentTaskLabel,
232
225
  getWorkspaceHarnessTrust,
233
226
  renderInboundMessage,
234
227
  sendOperatorMessage
235
- } from "./chunk-H6Q2QAIY.js";
228
+ } from "./chunk-A3EKBUEM.js";
229
+ import "./chunk-YORL5S5V.js";
236
230
  import "./chunk-K2PWUPUI.js";
237
- import "./chunk-SCWWLABR.js";
238
- import "./chunk-2OQOQ2FZ.js";
231
+ import "./chunk-CIMN2AO6.js";
232
+ import "./chunk-YERUDEXT.js";
239
233
  import "./chunk-UEX7PFSE.js";
240
- import "./chunk-YED25PA4.js";
241
- import "./chunk-RCRTSKQN.js";
234
+ import "./chunk-YJU7QACE.js";
235
+ import "./chunk-YYOQADBB.js";
236
+ import "./chunk-DNV3ZMPX.js";
242
237
  import {
243
238
  loadSourceFixProjectInputs,
244
239
  planSourceFixPublication,
@@ -246,58 +241,58 @@ import {
246
241
  resolveSourceFixRepository,
247
242
  runSourceFix,
248
243
  saveSourceFixProjectInputs
249
- } from "./chunk-6WQDXWQC.js";
250
- import "./chunk-CF3MNS3O.js";
244
+ } from "./chunk-A6AZZ6XX.js";
245
+ import "./chunk-Y7KV7WV6.js";
251
246
  import "./chunk-SQCBHFWN.js";
252
- import "./chunk-GVD6SJGH.js";
253
247
  import {
254
248
  createRuntime
255
- } from "./chunk-WBRGXCU2.js";
249
+ } from "./chunk-EXTN4SQV.js";
256
250
  import "./chunk-O6KPVYOI.js";
257
251
  import "./chunk-FHC2B7LN.js";
258
252
  import "./chunk-DKSCN2AB.js";
259
253
  import "./chunk-UFHN6RIU.js";
260
- import "./chunk-L2CCO4KE.js";
261
- import "./chunk-TO35Y326.js";
254
+ import "./chunk-RCHAFSWS.js";
255
+ import "./chunk-554D4AYM.js";
262
256
  import "./chunk-IXT64DV5.js";
263
- import "./chunk-3BPX75OR.js";
264
- import "./chunk-GVY3S5E5.js";
265
- import "./chunk-CPCHLL6A.js";
266
- import "./chunk-YAZARMJY.js";
257
+ import "./chunk-RD4FKFWR.js";
267
258
  import "./chunk-NJLKFC66.js";
268
259
  import {
269
260
  CodexCatalogRefreshError,
270
261
  loadCodexModelCatalog
271
- } from "./chunk-G2BE2FC7.js";
262
+ } from "./chunk-O3ADFN2A.js";
272
263
  import {
273
264
  claimDiagnostics
274
- } from "./chunk-QVIRWJ45.js";
275
- import "./chunk-2WWAPKAW.js";
265
+ } from "./chunk-EYBMTELO.js";
266
+ import "./chunk-BIJPMYFA.js";
267
+ import {
268
+ eventBus
269
+ } from "./chunk-52AWIBCT.js";
276
270
  import "./chunk-RS4MAN3Q.js";
277
271
  import {
278
272
  redactSensitiveHeaders,
279
273
  renderCvssSection,
280
274
  renderPlatformReport
281
- } from "./chunk-UELXHK2Y.js";
282
- import {
283
- eventBus
284
- } from "./chunk-4ZYYX5GY.js";
275
+ } from "./chunk-IK27KMVV.js";
285
276
  import {
286
277
  ScopePolicy
287
- } from "./chunk-C6JPA32H.js";
278
+ } from "./chunk-RBOMXUYL.js";
288
279
  import "./chunk-5IBCBQEH.js";
289
280
  import {
290
281
  DEFAULT_AUTONOMY_MODE,
282
+ ImpactAssessmentSchema,
291
283
  MODEL_PRICING,
292
284
  SLASH_COMMANDS,
293
285
  VERSION,
286
+ compareFindingsByBusinessPriority,
294
287
  createPresentationEvent,
295
288
  createTranscriptDocument,
296
289
  filterCommands,
297
290
  findCommand,
291
+ getFindingPriority,
298
292
  homeStateDir,
293
+ isHeuristicImpactAssessment,
299
294
  modelProvider
300
- } from "./chunk-6KFB6AYN.js";
295
+ } from "./chunk-RZR2XXAK.js";
301
296
  import "./chunk-VIT5ALXF.js";
302
297
  import {
303
298
  __commonJS,
@@ -645,6 +640,272 @@ function useMouseSupport() {
645
640
  // packages/cli/src/tui/shell-frame.tsx
646
641
  import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, useState as useState5 } from "react";
647
642
 
643
+ // packages/cli/src/tui/symbols.ts
644
+ var UNICODE = {
645
+ check: "\u2713",
646
+ cross: "\u2717",
647
+ warning: "\u26A0",
648
+ info: "\u2139",
649
+ running: "\u25B8",
650
+ parked: "\u25CC",
651
+ stopped: "\u25A0",
652
+ queued: "\xB7",
653
+ bulletFilled: "\u25CF",
654
+ bulletHollow: "\u25CB",
655
+ bulletActive: "\u25C9",
656
+ radioOn: "(\u25CF)",
657
+ radioOff: "( )",
658
+ checkboxOn: "[\u2713]",
659
+ checkboxOff: "[ ]",
660
+ rowMarker: "\u203A",
661
+ caretOpen: "\u25BE",
662
+ caretClosed: "\u25B8",
663
+ foldMore: "\u25B8",
664
+ treeBranch: "\u21B3",
665
+ roleGlyph: "\u258C",
666
+ meterFilled: "\u25B0",
667
+ meterEmpty: "\u25B1",
668
+ iconNew: "+",
669
+ iconOps: "\u25A6",
670
+ iconDoctor: "\u271A",
671
+ iconHistory: "\u25F7",
672
+ iconFindings: "\u25C7",
673
+ iconReplay: "\u25B7",
674
+ iconSettings: "*",
675
+ iconHarness: "\u2318",
676
+ iconAgents: "\u2659",
677
+ iconAudits: "\u25A3",
678
+ iconMarket: "\u229E",
679
+ iconConnect: "\u2197",
680
+ iconOnboard: "\u2726",
681
+ iconModels: "\u25C8",
682
+ iconUsage: "\u25A5",
683
+ iconShortcuts: "=",
684
+ fieldFolderOpen: "\u25A6",
685
+ fieldFolder: "\u25A5",
686
+ fieldStatus: "\u25CF",
687
+ fieldTags: "\u25C8",
688
+ fieldInfo: "\u25D0",
689
+ fieldFile: "\u25A4",
690
+ fieldEye: "\u2726",
691
+ fieldGavel: "\u271A",
692
+ fieldDiamond: "\u25C7",
693
+ fieldLink: "\u2197",
694
+ fieldContext: "\u25EB",
695
+ fieldInput: "\u2193",
696
+ fieldOutput: "\u2191",
697
+ fieldReason: "\u2726",
698
+ fieldCost: "$",
699
+ fieldModel: "\u25C8",
700
+ fieldHost: "=",
701
+ fieldCwd: "\u2302",
702
+ fieldBranch: "\u2442",
703
+ fieldDirty: "\xB1",
704
+ fieldTokens: "\u2195",
705
+ fieldPlan: "\u25A3",
706
+ fieldSearch: "\u2315",
707
+ fieldProtected: "\u2298",
708
+ fieldEffort: "\u2726",
709
+ fieldMode: "\u25D0"
710
+ };
711
+ var NERD = {
712
+ check: "\uF00C",
713
+ // nf-fa-check
714
+ cross: "\uF00D",
715
+ // nf-fa-times
716
+ warning: "\uF071",
717
+ // nf-fa-warning
718
+ info: "\uF05A",
719
+ // nf-fa-info-circle
720
+ running: "\uF04B",
721
+ // nf-fa-play
722
+ parked: "\uF04C",
723
+ // nf-fa-pause
724
+ stopped: "\uF04D",
725
+ // nf-fa-stop
726
+ queued: "\uF111",
727
+ // nf-fa-circle
728
+ bulletFilled: "\uF111",
729
+ // nf-fa-circle
730
+ bulletHollow: "\uF10C",
731
+ // nf-fa-circle-o
732
+ bulletActive: "\uF192",
733
+ // nf-fa-dot-circle-o
734
+ radioOn: "(\uF192)",
735
+ radioOff: "( )",
736
+ checkboxOn: "[\uF14A]",
737
+ // nf-fa-check-square
738
+ checkboxOff: "[\uF0C8]",
739
+ // nf-fa-square
740
+ rowMarker: "\uF054",
741
+ // nf-fa-chevron-right
742
+ caretOpen: "\uF078",
743
+ // nf-fa-chevron-down
744
+ caretClosed: "\uF054",
745
+ // nf-fa-chevron-right
746
+ foldMore: "\uF142",
747
+ // nf-fa-ellipsis-v
748
+ treeBranch: "\uF148",
749
+ // nf-fa-level-up (corner)
750
+ roleGlyph: "\u258C",
751
+ meterFilled: "\u25B0",
752
+ meterEmpty: "\u25B1",
753
+ iconNew: "\uF067",
754
+ // nf-fa-plus
755
+ iconOps: "\uF0E4",
756
+ // nf-fa-dashboard
757
+ iconDoctor: "\uF0F0",
758
+ // nf-fa-user-md
759
+ iconHistory: "\uF017",
760
+ // nf-fa-clock-o
761
+ iconFindings: "\uF0EB",
762
+ // nf-fa-lightbulb-o
763
+ iconReplay: "\uF04B",
764
+ // nf-fa-play
765
+ iconSettings: "\uF013",
766
+ // nf-fa-cog
767
+ iconHarness: "\uF085",
768
+ // nf-fa-cogs
769
+ iconAgents: "\uF0C0",
770
+ // nf-fa-users
771
+ iconAudits: "\uF0CA",
772
+ // nf-fa-list-ul
773
+ iconMarket: "\uF07A",
774
+ // nf-fa-shopping-cart
775
+ iconConnect: "\uF0C1",
776
+ // nf-fa-link
777
+ iconOnboard: "\uF005",
778
+ // nf-fa-star
779
+ iconModels: "\uF0E7",
780
+ // nf-fa-bolt
781
+ iconUsage: "\uF080",
782
+ // nf-fa-bar-chart
783
+ iconShortcuts: "\uF11C",
784
+ // nf-fa-keyboard-o
785
+ fieldFolderOpen: "\uF07C",
786
+ // nf-fa-folder-open
787
+ fieldFolder: "\uF07B",
788
+ // nf-fa-folder
789
+ fieldStatus: "\uF111",
790
+ // nf-fa-circle
791
+ fieldTags: "\uF0AE",
792
+ // nf-fa-tasks (tags family)
793
+ fieldInfo: "\uF05A",
794
+ // nf-fa-info-circle
795
+ fieldFile: "\uF15C",
796
+ // nf-fa-file-text
797
+ fieldEye: "\uF06E",
798
+ // nf-fa-eye
799
+ fieldGavel: "\uF0E3",
800
+ // nf-fa-gavel
801
+ fieldDiamond: "\uF0C4",
802
+ // nf-fa-scissors (diamond family)
803
+ fieldLink: "\uF0C1",
804
+ // nf-fa-link
805
+ fieldContext: "\uF0DB",
806
+ // nf-fa-columns
807
+ fieldInput: "\uF063",
808
+ // nf-fa-arrow-down
809
+ fieldOutput: "\uF062",
810
+ // nf-fa-arrow-up
811
+ fieldReason: "\uF0EB",
812
+ // nf-fa-lightbulb-o
813
+ fieldCost: "\uF155",
814
+ // nf-fa-dollar
815
+ fieldModel: "\uF0E7",
816
+ // nf-fa-bolt
817
+ fieldHost: "\uF085",
818
+ // nf-fa-cogs
819
+ fieldCwd: "\uF015",
820
+ // nf-fa-home
821
+ fieldBranch: "\uF126",
822
+ // nf-fa-code-fork
823
+ fieldDirty: "\uF069",
824
+ // nf-fa-asterisk
825
+ fieldTokens: "\uF0EC",
826
+ // nf-fa-exchange
827
+ fieldPlan: "\uF0CA",
828
+ // nf-fa-list-ul
829
+ fieldSearch: "\uF002",
830
+ // nf-fa-search
831
+ fieldProtected: "\uF023",
832
+ // nf-fa-lock
833
+ fieldEffort: "\uF0E7",
834
+ // nf-fa-bolt
835
+ fieldMode: "\uF042"
836
+ // nf-fa-adjust
837
+ };
838
+ var ASCII = {
839
+ check: "+",
840
+ cross: "x",
841
+ warning: "!",
842
+ info: "i",
843
+ running: ">",
844
+ parked: "=",
845
+ stopped: "#",
846
+ queued: ".",
847
+ bulletFilled: "*",
848
+ bulletHollow: "o",
849
+ bulletActive: "@",
850
+ radioOn: "(*)",
851
+ radioOff: "( )",
852
+ checkboxOn: "[x]",
853
+ checkboxOff: "[ ]",
854
+ rowMarker: ">",
855
+ caretOpen: "v",
856
+ caretClosed: ">",
857
+ foldMore: "+",
858
+ treeBranch: "\\",
859
+ roleGlyph: "|",
860
+ meterFilled: "#",
861
+ meterEmpty: "-",
862
+ iconNew: "+",
863
+ iconOps: "#",
864
+ iconDoctor: "+",
865
+ iconHistory: "h",
866
+ iconFindings: "*",
867
+ iconReplay: ">",
868
+ iconSettings: "%",
869
+ iconHarness: "&",
870
+ iconAgents: "&",
871
+ iconAudits: "#",
872
+ iconMarket: "#",
873
+ iconConnect: ">",
874
+ iconOnboard: "*",
875
+ iconModels: "#",
876
+ iconUsage: "#",
877
+ iconShortcuts: "=",
878
+ fieldFolderOpen: "#",
879
+ fieldFolder: "#",
880
+ fieldStatus: "*",
881
+ fieldTags: "#",
882
+ fieldInfo: "i",
883
+ fieldFile: "=",
884
+ fieldEye: "*",
885
+ fieldGavel: "+",
886
+ fieldDiamond: "<",
887
+ fieldLink: ">",
888
+ fieldContext: "#",
889
+ fieldInput: "v",
890
+ fieldOutput: "^",
891
+ fieldReason: "*",
892
+ fieldCost: "$",
893
+ fieldModel: "#",
894
+ fieldHost: "=",
895
+ fieldCwd: "~",
896
+ fieldBranch: "Y",
897
+ fieldDirty: "*",
898
+ fieldTokens: "=",
899
+ fieldPlan: "#",
900
+ fieldSearch: "/",
901
+ fieldProtected: "!",
902
+ fieldEffort: "*",
903
+ fieldMode: "%"
904
+ };
905
+ function getSymbols(preset) {
906
+ return preset === "nerd" ? NERD : preset === "ascii" ? ASCII : UNICODE;
907
+ }
908
+
648
909
  // packages/cli/src/tui/symbol-context.ts
649
910
  var cache = /* @__PURE__ */ new Map();
650
911
  function tableFor(preset) {
@@ -797,16 +1058,16 @@ function allocateColumns({
797
1058
  };
798
1059
  }
799
1060
  function fitCells(value, width, { align = "left", fit, maxEncodedRun } = {}) {
800
- const cells8 = toCells(width);
801
- if (cells8 <= 0) return "";
802
- const text = fitTuiText(value ?? "", cells8, { mode: fit, maxEncodedRun });
803
- if (text.length >= cells8) return text.slice(0, cells8);
804
- if (align === "right") return text.padStart(cells8, " ");
1061
+ const cells9 = toCells(width);
1062
+ if (cells9 <= 0) return "";
1063
+ const text = fitTuiText(value ?? "", cells9, { mode: fit, maxEncodedRun });
1064
+ if (text.length >= cells9) return text.slice(0, cells9);
1065
+ if (align === "right") return text.padStart(cells9, " ");
805
1066
  if (align === "center") {
806
- const left = Math.floor((cells8 - text.length) / 2);
807
- return `${" ".repeat(left)}${text}`.padEnd(cells8, " ");
1067
+ const left = Math.floor((cells9 - text.length) / 2);
1068
+ return `${" ".repeat(left)}${text}`.padEnd(cells9, " ");
808
1069
  }
809
- return text.padEnd(cells8, " ");
1070
+ return text.padEnd(cells9, " ");
810
1071
  }
811
1072
  function Cells({
812
1073
  width,
@@ -819,12 +1080,12 @@ function Cells({
819
1080
  maxEncodedRun,
820
1081
  onMouseDown
821
1082
  }) {
822
- const cells8 = toCells(width);
823
- if (cells8 <= 0) return null;
1083
+ const cells9 = toCells(width);
1084
+ if (cells9 <= 0) return null;
824
1085
  return /* @__PURE__ */ jsx(
825
1086
  "text",
826
1087
  {
827
- width: cells8,
1088
+ width: cells9,
828
1089
  flexShrink: 0,
829
1090
  flexGrow: 0,
830
1091
  wrapMode: "none",
@@ -832,7 +1093,7 @@ function Cells({
832
1093
  bg,
833
1094
  attributes,
834
1095
  onMouseDown,
835
- children: fitCells(children, cells8, { align, fit, maxEncodedRun })
1096
+ children: fitCells(children, cells9, { align, fit, maxEncodedRun })
836
1097
  }
837
1098
  );
838
1099
  }
@@ -1085,7 +1346,7 @@ function dialogTotalRows(items) {
1085
1346
  return count;
1086
1347
  }
1087
1348
  function wrapDialogLines(value, width, fg) {
1088
- const cells8 = Math.max(1, Math.trunc(width));
1349
+ const cells9 = Math.max(1, Math.trunc(width));
1089
1350
  const words = String(value ?? "").split(/\s+/).filter(Boolean);
1090
1351
  const out = [];
1091
1352
  let line4 = "";
@@ -1097,14 +1358,14 @@ function wrapDialogLines(value, width, fg) {
1097
1358
  };
1098
1359
  for (const word of words) {
1099
1360
  let rest = word;
1100
- while (rest.length > cells8) {
1361
+ while (rest.length > cells9) {
1101
1362
  flush();
1102
- out.push({ text: rest.slice(0, cells8), fg });
1103
- rest = rest.slice(cells8);
1363
+ out.push({ text: rest.slice(0, cells9), fg });
1364
+ rest = rest.slice(cells9);
1104
1365
  }
1105
1366
  if (rest.length === 0) continue;
1106
1367
  if (line4.length === 0) line4 = rest;
1107
- else if (line4.length + 1 + rest.length <= cells8) line4 = `${line4} ${rest}`;
1368
+ else if (line4.length + 1 + rest.length <= cells9) line4 = `${line4} ${rest}`;
1108
1369
  else {
1109
1370
  flush();
1110
1371
  line4 = rest;
@@ -1956,76 +2217,6 @@ function frameAt(kind, elapsedMs, opts = {}) {
1956
2217
  return frame;
1957
2218
  }
1958
2219
 
1959
- // packages/cli/src/tui/animations.ts
1960
- var UI_ANIMATION_INTERVAL_MS = 70;
1961
- function clamp(x, lo, hi) {
1962
- if (!Number.isFinite(x)) return lo;
1963
- return x < lo ? lo : x > hi ? hi : x;
1964
- }
1965
- function clamp01(x) {
1966
- return clamp(x, 0, 1);
1967
- }
1968
- function smoothstep(t) {
1969
- const x = clamp01(t);
1970
- return x * x * (3 - 2 * x);
1971
- }
1972
- function safeFrame(frame) {
1973
- if (!Number.isFinite(frame)) return 0;
1974
- const t = Math.trunc(frame);
1975
- return t < 0 ? 0 : t;
1976
- }
1977
- var SPINNER_PERIOD = 8;
1978
- var TOAST_ENTER_FRAMES = 6;
1979
- var TOAST_HOLD_FRAMES = 28;
1980
- var TOAST_EXIT_FRAMES = 6;
1981
- var TOAST_TOTAL_FRAMES = TOAST_ENTER_FRAMES + TOAST_HOLD_FRAMES + TOAST_EXIT_FRAMES;
1982
- var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827"];
1983
- function spinnerFrame(frame, opts = {}) {
1984
- if (opts.reduceMotion) return 0;
1985
- return safeFrame(frame) % SPINNER_PERIOD;
1986
- }
1987
- function spinnerGlyph(frame, opts = {}) {
1988
- return SPINNER_FRAMES[spinnerFrame(frame, opts)] ?? SPINNER_FRAMES[0];
1989
- }
1990
- var SHIMMER_TEXT_TAIL = 5;
1991
- var SHIMMER_TEXT_INTERVAL_MS = 80;
1992
- var SHIMMER_TEXT_REST_GAP = 6;
1993
- function shimmerTail(opts) {
1994
- const t = opts?.tail;
1995
- if (t === void 0 || !Number.isFinite(t)) return SHIMMER_TEXT_TAIL;
1996
- return Math.max(1, Math.trunc(t));
1997
- }
1998
- function shimmerRestGap(opts) {
1999
- const g = opts?.restGap;
2000
- if (g === void 0 || !Number.isFinite(g)) return SHIMMER_TEXT_REST_GAP;
2001
- return Math.max(0, Math.trunc(g));
2002
- }
2003
- function shimmerLength(length) {
2004
- if (!Number.isFinite(length)) return 0;
2005
- const n = Math.trunc(length);
2006
- return n < 0 ? 0 : n;
2007
- }
2008
- function shimmerText(length, frame, opts) {
2009
- const len = shimmerLength(length);
2010
- if (len <= 0) return [];
2011
- const out = new Array(len).fill(0);
2012
- if (opts?.reduceMotion) return out;
2013
- const tail = shimmerTail(opts);
2014
- const rest = shimmerRestGap(opts);
2015
- const period = len + 2 * tail + rest;
2016
- const sweep = len + 2 * tail;
2017
- const idx = (safeFrame(frame) % period + period) % period;
2018
- if (idx >= sweep) return out;
2019
- const head = idx - tail;
2020
- for (let offset = -tail; offset <= tail; offset += 1) {
2021
- const col = head + offset;
2022
- if (col < 0 || col >= len) continue;
2023
- const intensity = 1 - smoothstep(Math.abs(offset) / tail);
2024
- if (intensity > out[col]) out[col] = intensity;
2025
- }
2026
- return out;
2027
- }
2028
-
2029
2220
  // packages/cli/src/tui/chat/shimmer.tsx
2030
2221
  import { jsx as jsx7 } from "@opentui/react/jsx-runtime";
2031
2222
  var GRAPHEMES = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -3349,7 +3540,7 @@ function matchListItem(line4) {
3349
3540
  }
3350
3541
  function splitTableCells(line4) {
3351
3542
  const trimmed = line4.trim();
3352
- const cells8 = [];
3543
+ const cells9 = [];
3353
3544
  let current = "";
3354
3545
  for (let j = 0; j < trimmed.length; j += 1) {
3355
3546
  const ch = trimmed[j];
@@ -3359,24 +3550,24 @@ function splitTableCells(line4) {
3359
3550
  continue;
3360
3551
  }
3361
3552
  if (ch === "|") {
3362
- cells8.push(current);
3553
+ cells9.push(current);
3363
3554
  current = "";
3364
3555
  continue;
3365
3556
  }
3366
3557
  current += ch;
3367
3558
  }
3368
- cells8.push(current);
3369
- if (cells8.length > 1 && cells8[0].trim() === "") cells8.shift();
3370
- if (cells8.length > 1 && cells8[cells8.length - 1].trim() === "") cells8.pop();
3371
- return cells8.map((cell) => cell.trim());
3559
+ cells9.push(current);
3560
+ if (cells9.length > 1 && cells9[0].trim() === "") cells9.shift();
3561
+ if (cells9.length > 1 && cells9[cells9.length - 1].trim() === "") cells9.pop();
3562
+ return cells9.map((cell) => cell.trim());
3372
3563
  }
3373
3564
  function matchTableDelimiter(line4) {
3374
3565
  if (leadingSpaces(line4) > 3) return null;
3375
3566
  if (!line4.includes("-") || !line4.includes("|")) return null;
3376
- const cells8 = splitTableCells(line4);
3377
- if (cells8.length === 0) return null;
3567
+ const cells9 = splitTableCells(line4);
3568
+ if (cells9.length === 0) return null;
3378
3569
  const align = [];
3379
- for (const cell of cells8) {
3570
+ for (const cell of cells9) {
3380
3571
  if (!/^:?-+:?$/.test(cell)) return null;
3381
3572
  const left = cell.startsWith(":");
3382
3573
  const right = cell.endsWith(":");
@@ -3483,8 +3674,8 @@ function parseMarkdownBlocks(source) {
3483
3674
  i += 1;
3484
3675
  }
3485
3676
  const cols = Math.max(header.length, align.length);
3486
- const fit = (cells8) => {
3487
- const out = cells8.slice(0, cols);
3677
+ const fit = (cells9) => {
3678
+ const out = cells9.slice(0, cols);
3488
3679
  while (out.length < cols) out.push("");
3489
3680
  return out;
3490
3681
  };
@@ -3587,7 +3778,7 @@ function wrapBlock(block, width) {
3587
3778
  return { kind: "paragraph", lines: wrapSpans(joinLines(block.lines), width) };
3588
3779
  case "table": {
3589
3780
  const widths = tableColumnWidths(block.header, block.rows, width);
3590
- const clip2 = (cells8) => cells8.map((cell, c) => truncateSpans(cell, widths[c] ?? 1));
3781
+ const clip2 = (cells9) => cells9.map((cell, c) => truncateSpans(cell, widths[c] ?? 1));
3591
3782
  return {
3592
3783
  kind: "table",
3593
3784
  align: block.align,
@@ -4074,8 +4265,8 @@ function previewTranscriptText(source, maxChars = MAX_TRANSCRIPT_PREVIEW_CHARS)
4074
4265
  var MAX_REVIEW_CHARS = 32e3;
4075
4266
  var MAX_REVIEW_LINE_CHARS = 8e3;
4076
4267
  function reviewRule(width) {
4077
- const cells8 = Number.isFinite(width) ? Math.floor(width) : 0;
4078
- return "\u2500".repeat(Math.max(3, Math.min(cells8, 80)));
4268
+ const cells9 = Number.isFinite(width) ? Math.floor(width) : 0;
4269
+ return "\u2500".repeat(Math.max(3, Math.min(cells9, 80)));
4079
4270
  }
4080
4271
  var GUTTER = {
4081
4272
  speaker: "\u258C",
@@ -5078,7 +5269,7 @@ function SessionScreen({ state, onExit, shell, queueUserMessage }) {
5078
5269
  /* @__PURE__ */ jsx13("text", { fg: stage.status === "running" ? theme.PRIMARY : stage.status === "done" ? theme.SUCCESS : stage.status === "error" ? theme.ERROR : theme.MUTED, children: fitTuiText(`${stage.label} \xB7 ${stage.status}`, sidebarTextWidth) }),
5079
5270
  stage.detail ? /* @__PURE__ */ jsx13("text", { fg: theme.TEXT, wrapMode: "word", children: fitTuiText(stage.detail, sidebarTextWidth) }) : stage.status === "pending" ? /* @__PURE__ */ jsx13("text", { fg: theme.MUTED, children: fitTuiText("waiting", sidebarTextWidth) }) : null
5080
5271
  ] }, stage.id)) }) }),
5081
- /* @__PURE__ */ jsx13(PanelSection, { title: "Findings", contentWidth: sidebarTextWidth, tone: totalFindings > 0 ? theme.WARNING : theme.BORDER, children: /* @__PURE__ */ jsx13("box", { flexDirection: "column", minWidth: 0, children: state.stages.flatMap((stage) => stage.findings).length === 0 ? /* @__PURE__ */ jsx13("text", { fg: theme.TEXT, children: fitTuiText("No findings yet.", sidebarTextWidth) }) : state.stages.flatMap((stage) => stage.findings).slice(0, SESSION_MAX_SIDEBAR_FINDINGS).map((finding, index) => /* @__PURE__ */ jsx13("text", { fg: severityToneFor(theme, finding.severity), children: fitTuiText(`${finding.severity} \xB7 ${finding.title}`, sidebarTextWidth) }, `${finding.title}-${index}`)) }) }),
5272
+ /* @__PURE__ */ jsx13(PanelSection, { title: "Findings", contentWidth: sidebarTextWidth, tone: totalFindings > 0 ? theme.WARNING : theme.BORDER, children: /* @__PURE__ */ jsx13("box", { flexDirection: "column", minWidth: 0, children: state.stages.flatMap((stage) => stage.findings).length === 0 ? /* @__PURE__ */ jsx13("text", { fg: theme.TEXT, children: fitTuiText("No findings yet.", sidebarTextWidth) }) : state.stages.flatMap((stage) => stage.findings).sort(compareFindingsByBusinessPriority).slice(0, SESSION_MAX_SIDEBAR_FINDINGS).map((finding, index) => /* @__PURE__ */ jsx13("text", { fg: getFindingPriority(finding).assessed ? theme.TEXT : theme.MUTED, children: fitTuiText(`${getFindingPriority(finding).label} \xB7 ${finding.title} \xB7 technical ${finding.severity}`, sidebarTextWidth) }, `${finding.title}-${index}`)) }) }),
5082
5273
  summary ? /* @__PURE__ */ jsx13(PanelSection, { title: "Report", contentWidth: sidebarTextWidth, tone: summary.critical > 0 || summary.high > 0 ? theme.ERROR : theme.SUCCESS, children: /* @__PURE__ */ jsxs8("box", { flexDirection: "column", minWidth: 0, children: [
5083
5274
  /* @__PURE__ */ jsxs8("box", { flexDirection: "row", width: "100%", minWidth: 0, children: [
5084
5275
  /* @__PURE__ */ jsx13("text", { flexShrink: 0, fg: summary.critical > 0 ? theme.ERROR : theme.TEXT, children: "critical " }),
@@ -5407,13 +5598,26 @@ function formatGoal(goal) {
5407
5598
  return goal === "known-vulnerabilities" ? "known vulnerabilities" : goal === "unknown-vulnerabilities" ? "unknown vulnerabilities" : "misconfigurations";
5408
5599
  }
5409
5600
  function formatExecutionMode(mode) {
5410
- return mode === "sequential" ? "sequential (calmer)" : "parallel (faster)";
5601
+ return mode === "sequential" ? "sequential (calmer)" : "parallel (overlapping)";
5411
5602
  }
5412
5603
  function cycleNumber(items, current, delta) {
5413
5604
  const index = items.indexOf(current);
5414
5605
  const next = index < 0 ? 0 : (index + delta + items.length) % items.length;
5415
5606
  return items[next];
5416
5607
  }
5608
+ function scanGoalExplanation(kind, goal) {
5609
+ const scope = kind === "web" ? "live surface" : kind === "package" ? "package" : "source";
5610
+ if (goal === "unknown-vulnerabilities") return `Investigate ${scope} behavior beyond known patterns. Unknown vulnerabilities are an objective, not a promised result.`;
5611
+ if (goal === "known-vulnerabilities") return `Check the selected ${scope} for known vulnerability patterns and evidence that they apply.`;
5612
+ return `Check the selected ${scope} for exposed or unsafe configuration.`;
5613
+ }
5614
+ function scanDepthExplanation(goal) {
5615
+ return goal === "unknown-vulnerabilities" ? "Deep is suggested for broader investigation and reproduction; it takes more effort. Your selected limits still apply." : "Default is suggested for focused checks and reproduction without the effort of a deep investigation.";
5616
+ }
5617
+ var SCAN_RUNS_HELP = "Start with 1 run. Extra runs repeat the selected scope; each run can already use subagents. All runs share the same limits.";
5618
+ var SCAN_MODE_HELP = "Sequential is suggested for lower concurrency. Parallel overlaps runs and may finish sooner, but can consume the shared budget sooner.";
5619
+ var SCAN_TIME_HELP = "Wall-clock limit for the whole plan, including concurrent runs. Reaching it cancels work; unfinished checks remain incomplete.";
5620
+ var SCAN_COST_HELP = "Estimated USD limit shared by every run and subagent. In-flight requests can exceed it before usage is reported. Unknown cost is not zero; this is not a guaranteed provider charge ceiling.";
5417
5621
 
5418
5622
  // packages/cli/src/tui/home-screen.tsx
5419
5623
  import { jsx as jsx14, jsxs as jsxs9 } from "@opentui/react/jsx-runtime";
@@ -5476,7 +5680,7 @@ function HomeScreen({
5476
5680
  }
5477
5681
  if (!confirming) {
5478
5682
  setConfirming(true);
5479
- setNotice("Press Enter again to start.");
5683
+ setNotice("In-flight cost may exceed the shared estimate. Enter confirms; Esc cancels.");
5480
5684
  return;
5481
5685
  }
5482
5686
  setNotice(null);
@@ -5508,14 +5712,14 @@ function HomeScreen({
5508
5712
  help: "URL \xB7 path \xB7 source: \xB7 npm: \xB7 pypi: \xB7 cargo: \xB7 oci:",
5509
5713
  editable: true
5510
5714
  },
5511
- { key: "goal", label: "Goal", value: formatGoal(goal) },
5715
+ { key: "goal", label: "Goal", value: formatGoal(goal), help: scanGoalExplanation(targetKind, goal) },
5512
5716
  { key: "runtime", label: "Provider", value: runtime },
5513
- { key: "depth", label: "Depth", value: depth },
5514
- { key: "runs", label: "Runs", value: String(runCount) },
5515
- { key: "mode", label: "Mode", value: formatExecutionMode(executionMode) },
5516
- { key: "time", label: "Time cap", value: formatTimeCap(timeCapMs) },
5517
- { key: "cost", label: "Cost cap", value: `$${costCapUsd}` }
5518
- ], [costCapUsd, depth, executionMode, goal, inputValue, runCount, runtime, timeCapMs]);
5717
+ { key: "depth", label: "Depth", value: depth, help: scanDepthExplanation(goal) },
5718
+ { key: "runs", label: "Runs", value: String(runCount), help: SCAN_RUNS_HELP },
5719
+ { key: "mode", label: "Mode", value: formatExecutionMode(executionMode), help: SCAN_MODE_HELP },
5720
+ { key: "time", label: "Time cap", value: formatTimeCap(timeCapMs), help: SCAN_TIME_HELP },
5721
+ { key: "cost", label: "Cost limit (estimated)", value: `$${costCapUsd}`, help: SCAN_COST_HELP }
5722
+ ], [costCapUsd, depth, executionMode, goal, inputValue, runCount, runtime, targetKind, timeCapMs]);
5519
5723
  const adjustFocusedOption = (delta) => {
5520
5724
  const field = fields[focusIndex]?.key;
5521
5725
  setConfirming(false);
@@ -5662,7 +5866,7 @@ function HomeScreen({
5662
5866
  lines.push({ text: "" });
5663
5867
  lines.push(...wrapDialogLines(planText, inner, planTone));
5664
5868
  lines.push({ text: "" });
5665
- lines.push(...wrapDialogLines(`Suggested: ${formatGoal(recommendedGoal)} \xB7 ${recommendedDepth} \xB7 ${formatTimeCap(recommendedTime)} \xB7 $5`, inner, theme.MUTED));
5869
+ lines.push(...wrapDialogLines(`Suggested: ${formatGoal(recommendedGoal)} \xB7 ${recommendedDepth} \xB7 ${formatTimeCap(recommendedTime)} \xB7 1 run \xB7 sequential \xB7 $5 estimated`, inner, theme.MUTED));
5666
5870
  const help = fields[focusIndex]?.help;
5667
5871
  if (help) lines.push(...wrapDialogLines(help, inner, theme.MUTED));
5668
5872
  if (evolutionStatus) lines.push(...wrapDialogLines(evolutionStatus.message, inner, theme.MUTED));
@@ -5734,7 +5938,7 @@ function OpsScreen({ dbPath, refreshMs, onExit, shell }) {
5734
5938
  let alive = true;
5735
5939
  const refresh = async () => {
5736
5940
  try {
5737
- const { osecDB } = await import("./dist-7RUOKPRJ.js");
5941
+ const { osecDB } = await import("./dist-3SWWY5FZ.js");
5738
5942
  const db = new osecDB(dbPath);
5739
5943
  try {
5740
5944
  const scans = db.listScans(12);
@@ -6299,7 +6503,7 @@ function HistoryScreen({ dbPath, limit, onResolve, onExit, shell }) {
6299
6503
  let alive = true;
6300
6504
  const load = async () => {
6301
6505
  try {
6302
- const { osecDB } = await import("./dist-7RUOKPRJ.js");
6506
+ const { osecDB } = await import("./dist-3SWWY5FZ.js");
6303
6507
  const db = new osecDB(dbPath);
6304
6508
  try {
6305
6509
  const rows = db.listScans(limit);
@@ -6666,7 +6870,7 @@ function cells(value, fallback = 0) {
6666
6870
  const truncated = Math.trunc(raw);
6667
6871
  return truncated > 0 ? truncated : 0;
6668
6872
  }
6669
- function clamp2(value, low, high) {
6873
+ function clamp(value, low, high) {
6670
6874
  if (high < low) return low;
6671
6875
  return Math.min(Math.max(value, low), high);
6672
6876
  }
@@ -6723,10 +6927,17 @@ function findingCvssLine(finding, injected) {
6723
6927
  return EM_DASH;
6724
6928
  }
6725
6929
  function findingImpactLines(finding) {
6726
- const assessment = finding.impactAssessment ? parseImpactAssessment(JSON.stringify(finding.impactAssessment)) : null;
6727
- if (!assessment) return ["Not assessed."];
6930
+ const parsed = ImpactAssessmentSchema.safeParse(finding.impactAssessment);
6931
+ const priority = getFindingPriority(finding);
6932
+ if (!priority.assessed) return [
6933
+ "Not assessed.",
6934
+ ...parsed.success && isHeuristicImpactAssessment(parsed.data) ? ["Heuristic baseline; business consequences have not been established."] : [],
6935
+ priority.rationale
6936
+ ];
6937
+ if (!parsed.success) return ["Not assessed.", priority.rationale];
6938
+ const assessment = parsed.data;
6728
6939
  return [
6729
- "Model's estimate \u2014 not reproduction proof.",
6940
+ assessment.assessment_source === "model" ? "Model's estimate \u2014 not reproduction proof." : assessment.assessment_source === "provided" ? "Provided assessment \u2014 not reproduction proof." : "Assessment source not recorded \u2014 not reproduction proof.",
6730
6941
  `Business impact: ${assessment.business_impact}`,
6731
6942
  `Reachability: ${assessment.reachability_tier}`,
6732
6943
  `Blast radius: ${assessment.blast_radius}`,
@@ -6768,6 +6979,13 @@ function buildFindingRows(finding, innerWidth, options = {}) {
6768
6979
  const icon = findingRowIcons(options.symbols ?? DEFAULT_SYMBOLS2);
6769
6980
  const rows = [];
6770
6981
  pushWrapped(rows, findingText(finding.title || EM_DASH), width, "title");
6982
+ const priority = getFindingPriority(finding);
6983
+ rows.push({
6984
+ kind: "kv",
6985
+ label: `${icon.status} Business priority`,
6986
+ value: priority.label,
6987
+ tone: priority.label === "Urgent" || priority.label === "High" ? "error" : priority.label === "Moderate" ? "warn" : "muted"
6988
+ });
6771
6989
  rows.push({
6772
6990
  kind: "kv",
6773
6991
  label: `${icon.status} Severity`,
@@ -6793,7 +7011,7 @@ function buildFindingRows(finding, innerWidth, options = {}) {
6793
7011
  rows.push({
6794
7012
  kind: "kv",
6795
7013
  label: `${icon.confid} Confidence`,
6796
- value: typeof finding.confidence === "number" && Number.isFinite(finding.confidence) ? `${Math.round(clamp2(finding.confidence, 0, 1) * 100)}%` : EM_DASH,
7014
+ value: typeof finding.confidence === "number" && Number.isFinite(finding.confidence) ? `${Math.round(clamp(finding.confidence, 0, 1) * 100)}%` : EM_DASH,
6797
7015
  tone: "text"
6798
7016
  });
6799
7017
  pushWrapped(rows, `${icon.location} Location: ${findingLocation(finding) ?? EM_DASH}`, width, "text");
@@ -6911,7 +7129,7 @@ function computeScrollWindow({ total, offset, visible }) {
6911
7129
  return { start: 0, end: 0, count: 0, total: rowCount, hasAbove: rowCount > 0, hasBelow: false };
6912
7130
  }
6913
7131
  const maxStart = Math.max(0, rowCount - capacity);
6914
- const start = clamp2(cells(offset), 0, maxStart);
7132
+ const start = clamp(cells(offset), 0, maxStart);
6915
7133
  const end = Math.min(rowCount, start + capacity);
6916
7134
  return {
6917
7135
  start,
@@ -7034,20 +7252,16 @@ function findingDetailFooterHint({
7034
7252
 
7035
7253
  // packages/cli/src/tui/findings-screen.tsx
7036
7254
  import { jsx as jsx19, jsxs as jsxs13 } from "@opentui/react/jsx-runtime";
7037
- var FINDING_SEVERITY_ORDER = ["critical", "high", "medium", "low", "info"];
7038
- function findingSeverityRank(severity) {
7039
- const index = FINDING_SEVERITY_ORDER.indexOf(String(severity).toLowerCase());
7040
- return index < 0 ? FINDING_SEVERITY_ORDER.length : index;
7041
- }
7042
- function findingSeverityHeading(severity) {
7043
- const value = String(severity).trim();
7044
- return value.length === 0 ? "unrated" : value.toUpperCase();
7045
- }
7046
7255
  function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7047
7256
  const theme = useTheme();
7257
+ const priorityTone = (row) => {
7258
+ const priority = findingRowPriority(row);
7259
+ return priority.assessed ? severityToneFor(theme, { Urgent: "critical", High: "high", Moderate: "medium", Low: "low" }[priority.label]) : theme.MUTED;
7260
+ };
7048
7261
  const { mouseSupport } = useSettings();
7049
7262
  const contextMenu = useContextMenu();
7050
7263
  const [rows, setRows] = useState15([]);
7264
+ const [families, setFamilies] = useState15([]);
7051
7265
  const [error, setError] = useState15(null);
7052
7266
  const [index, setIndex] = useState15(0);
7053
7267
  const [reloadNonce, setReloadNonce] = useState15(0);
@@ -7076,19 +7290,28 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7076
7290
  let alive = true;
7077
7291
  const load = async () => {
7078
7292
  try {
7079
- const { osecDB } = await import("./dist-7RUOKPRJ.js");
7293
+ const { osecDB } = await import("./dist-3SWWY5FZ.js");
7080
7294
  const db = new osecDB(options.dbPath);
7081
7295
  try {
7082
- const findings = db.listFindings({
7296
+ const filters = {
7083
7297
  scanId: options.scan,
7084
7298
  severity: options.severity,
7085
7299
  category: options.category,
7086
7300
  status: options.status,
7087
7301
  triageStatus: options.triage,
7088
- limit: options.all ? options.limit : 1e3
7089
- });
7302
+ limit: Math.min(options.limit, 5e3)
7303
+ };
7304
+ const groups2 = options.all ? [] : db.listFindingFamiliesByBusinessPriority(filters);
7305
+ const findings = options.all ? db.listFindingsByBusinessPriority(filters) : groups2.map((group) => group.latest);
7090
7306
  if (!alive) return;
7091
7307
  setRows(findings);
7308
+ setFamilies(groups2.map((group) => ({
7309
+ fingerprint: group.key,
7310
+ latest: group.latest,
7311
+ count: group.count,
7312
+ scans: group.scanCount
7313
+ })));
7314
+ if (options.limit > 5e3) setNotice("Showing the top 5000 findings by business priority.");
7092
7315
  applyIndex(0);
7093
7316
  setError(null);
7094
7317
  } finally {
@@ -7104,7 +7327,7 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7104
7327
  alive = false;
7105
7328
  };
7106
7329
  }, [options, reloadNonce]);
7107
- const groups = useMemo10(() => groupFindings(rows).slice(0, options.limit), [rows, options.limit]);
7330
+ const groups = families;
7108
7331
  const items = options.all ? rows.slice(0, options.limit) : groups;
7109
7332
  const itemCount = items.length;
7110
7333
  const findingsItems = useMemo10(() => {
@@ -7113,12 +7336,12 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7113
7336
  if (visible.length === 0) {
7114
7337
  return [{ id: "finding:none", label: "No findings found.", category: "Findings", disabled: true }];
7115
7338
  }
7116
- return [...visible].sort((a, b) => findingSeverityRank(a.severity) - findingSeverityRank(b.severity)).map((row) => ({
7339
+ return [...visible].sort(compareFindingRowsByBusinessPriority).map((row) => ({
7117
7340
  id: `row:${row.id}`,
7118
7341
  label: row.title,
7119
- description: `${row.category} \xB7 ${row.status}${row.triageStatus && row.triageStatus !== "new" ? ` \xB7 ${row.triageStatus}` : ""}`,
7120
- category: findingSeverityHeading(row.severity),
7121
- tone: severityToneFor(theme, row.severity),
7342
+ description: `Technical severity: ${row.severity} \xB7 ${row.category} \xB7 ${row.status}${row.triageStatus && row.triageStatus !== "new" ? ` \xB7 ${row.triageStatus}` : ""}`,
7343
+ category: findingRowPriority(row).label,
7344
+ tone: priorityTone(row),
7122
7345
  // The gutter dot marks a family whose triage decision is in effect;
7123
7346
  // an untriaged row carries none.
7124
7347
  current: (row.triageStatus ?? "new") !== "new"
@@ -7127,13 +7350,13 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7127
7350
  if (groups.length === 0) {
7128
7351
  return [{ id: "finding:none", label: "No findings found.", category: "Findings", disabled: true }];
7129
7352
  }
7130
- return [...groups].sort((a, b) => findingSeverityRank(a.latest.severity) - findingSeverityRank(b.latest.severity)).map((group) => ({
7353
+ return [...groups].sort((a, b) => compareFindingRowsByBusinessPriority(a.latest, b.latest)).map((group) => ({
7131
7354
  id: `group:${group.fingerprint}`,
7132
7355
  label: group.latest.title,
7133
- description: `${group.latest.category} \xB7 ${group.latest.status}${group.latest.triageStatus && group.latest.triageStatus !== "new" ? ` \xB7 ${group.latest.triageStatus}` : ""}`,
7356
+ description: `Technical severity: ${group.latest.severity} \xB7 ${group.latest.category} \xB7 ${group.latest.status}${group.latest.triageStatus && group.latest.triageStatus !== "new" ? ` \xB7 ${group.latest.triageStatus}` : ""}`,
7134
7357
  meta: group.count > 1 ? `${group.count}\xD7` : "",
7135
- category: findingSeverityHeading(group.latest.severity),
7136
- tone: severityToneFor(theme, group.latest.severity),
7358
+ category: findingRowPriority(group.latest).label,
7359
+ tone: priorityTone(group.latest),
7137
7360
  current: (group.latest.triageStatus ?? "new") !== "new"
7138
7361
  }));
7139
7362
  }, [options.all, options.limit, rows, groups, theme]);
@@ -7250,7 +7473,7 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7250
7473
  setError(null);
7251
7474
  setNotice(`Marking ${triageStatus}\u2026`);
7252
7475
  try {
7253
- const { osecDB } = await import("./dist-7RUOKPRJ.js");
7476
+ const { osecDB } = await import("./dist-3SWWY5FZ.js");
7254
7477
  const db = new osecDB(options.dbPath);
7255
7478
  try {
7256
7479
  db.updateFindingTriageByFingerprint(selectedRow2.fingerprint, triageStatus);
@@ -7287,7 +7510,8 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7287
7510
  const copyFinding = (row) => {
7288
7511
  const text = [
7289
7512
  row.title,
7290
- `${row.severity} \xB7 ${row.status} \xB7 ${row.triageStatus ?? "new"}`,
7513
+ `Business priority: ${findingRowPriority(row).label}`,
7514
+ `Technical severity: ${row.severity} \xB7 ${row.status} \xB7 ${row.triageStatus ?? "new"}`,
7291
7515
  "",
7292
7516
  row.description,
7293
7517
  "",
@@ -7413,12 +7637,13 @@ function FindingsScreen({ options, onExit, shell, onSourceFix }) {
7413
7637
  const push2 = (value, fg) => {
7414
7638
  lines.push(...wrapDialogLines(sanitizeTuiText(value), inner, fg));
7415
7639
  };
7416
- lines.push({ text: options.all ? "FINDING" : "FAMILY", fg: row ? severityToneFor(theme, row.severity) : theme.PRIMARY });
7640
+ lines.push({ text: options.all ? "FINDING" : "FAMILY", fg: theme.PRIMARY });
7417
7641
  if (!row) {
7418
7642
  push2("No finding selected", theme.MUTED);
7419
7643
  } else {
7420
7644
  push2(row.title, theme.TEXT);
7421
- push2(`${row.severity} \xB7 ${row.status} \xB7 ${row.triageStatus ?? "new"}`, severityToneFor(theme, row.severity));
7645
+ push2(`Business priority: ${findingRowPriority(row).label}`, theme.PRIMARY);
7646
+ push2(`Technical severity: ${row.severity} \xB7 ${row.status} \xB7 ${row.triageStatus ?? "new"}`, theme.MUTED);
7422
7647
  if (group) push2(`seen ${group.count}\xD7 in ${group.scans} scan${group.scans === 1 ? "" : "s"}`, theme.MUTED);
7423
7648
  push2(`id ${row.id}`, theme.MUTED);
7424
7649
  if (row.triageNote) push2(row.triageNote, theme.ACCENT);
@@ -7549,7 +7774,7 @@ function ReplayScreen({ dbPath, scanId, onExit, shell }) {
7549
7774
  let alive = true;
7550
7775
  const load = async () => {
7551
7776
  try {
7552
- const { osecDB } = await import("./dist-7RUOKPRJ.js");
7777
+ const { osecDB } = await import("./dist-3SWWY5FZ.js");
7553
7778
  const db = new osecDB(dbPath);
7554
7779
  try {
7555
7780
  let selected = scanId ? db.getScan(scanId) : void 0;
@@ -9634,6 +9859,9 @@ function connectionRecoveryForError(error) {
9634
9859
  detail
9635
9860
  };
9636
9861
  }
9862
+ if (/\bcline(?:pass)?\b|cline_api_key/i.test(detail)) {
9863
+ return { providerId: "cline", title: "Cline credentials need attention", detail };
9864
+ }
9637
9865
  if (/anthropic|claude/i.test(detail)) {
9638
9866
  return {
9639
9867
  providerId: "anthropic",
@@ -10983,10 +11211,10 @@ function progressOf(frame, count) {
10983
11211
  if (count <= 1) return 1;
10984
11212
  return frame / (count - 1);
10985
11213
  }
10986
- function clamp012(x) {
11214
+ function clamp01(x) {
10987
11215
  return x < 0 ? 0 : x > 1 ? 1 : x;
10988
11216
  }
10989
- function smoothstep2(t) {
11217
+ function smoothstep(t) {
10990
11218
  if (t <= 0) return 0;
10991
11219
  if (t >= 1) return 1;
10992
11220
  return t * t * (3 - 2 * t);
@@ -11014,7 +11242,7 @@ function rgbHex(r, g, b) {
11014
11242
  return `#${channelHex(r)}${channelHex(g)}${channelHex(b)}`;
11015
11243
  }
11016
11244
  function greyHex(l) {
11017
- const v = clamp012(l) * 255;
11245
+ const v = clamp01(l) * 255;
11018
11246
  return rgbHex(v, v, v);
11019
11247
  }
11020
11248
  function hslToHex(h, s, l) {
@@ -11101,7 +11329,7 @@ function fadeFrame(grid, frame, width) {
11101
11329
  const cy = (rows - 1) / 2;
11102
11330
  const maxDist = Math.hypot(Math.max(cx, width - 1 - cx), Math.max(cy, rows - 1 - cy)) || 1;
11103
11331
  const SPREAD = 0.6;
11104
- const progress = smoothstep2(progressOf(frame, FRAME_COUNTS.fade));
11332
+ const progress = smoothstep(progressOf(frame, FRAME_COUNTS.fade));
11105
11333
  for (let r = 0; r < rows; r += 1) {
11106
11334
  for (let c = 0; c < width; c += 1) {
11107
11335
  const ch = out[r][c].ch;
@@ -11110,10 +11338,10 @@ function fadeFrame(grid, frame, width) {
11110
11338
  const local = progress * (1 + SPREAD) - dist * SPREAD;
11111
11339
  let tone;
11112
11340
  if (local < 1 / 3 - EPS) {
11113
- const t = clamp012(local / (1 / 3));
11341
+ const t = clamp01(local / (1 / 3));
11114
11342
  tone = hslToHex(0, 0.72, 0.14 + t * 0.24);
11115
11343
  } else if (local < 2 / 3 - EPS) {
11116
- const t = clamp012((local - 1 / 3) / (1 / 3));
11344
+ const t = clamp01((local - 1 / 3) / (1 / 3));
11117
11345
  tone = hslToHex(4, 0.78, 0.42 + t * 0.2);
11118
11346
  } else {
11119
11347
  tone = finalTone(ch);
@@ -11133,7 +11361,7 @@ function typeinFrame(grid, frame, width) {
11133
11361
  }
11134
11362
  const total = order.length;
11135
11363
  if (total === 0) return out;
11136
- const progress = smoothstep2(progressOf(frame, FRAME_COUNTS.typein));
11364
+ const progress = smoothstep(progressOf(frame, FRAME_COUNTS.typein));
11137
11365
  const revealed = Math.round(progress * total);
11138
11366
  const GLOW = progress < 1 - EPS ? 3 : 0;
11139
11367
  for (let i = 0; i < revealed; i += 1) {
@@ -11147,7 +11375,7 @@ function typeinFrame(grid, frame, width) {
11147
11375
  function sweepFrame(grid, frame, width) {
11148
11376
  const out = blankFrame(grid, width);
11149
11377
  const BAR = 2;
11150
- const lead = smoothstep2(progressOf(frame, FRAME_COUNTS.sweep)) * (width + BAR);
11378
+ const lead = smoothstep(progressOf(frame, FRAME_COUNTS.sweep)) * (width + BAR);
11151
11379
  for (let r = 0; r < grid.length; r += 1) {
11152
11380
  for (let c = 0; c < width; c += 1) {
11153
11381
  const ch = out[r][c].ch;
@@ -11163,7 +11391,7 @@ function sweepFrame(grid, frame, width) {
11163
11391
  }
11164
11392
  function glitchFrame(grid, frame, width) {
11165
11393
  const out = blankFrame(grid, width);
11166
- const progress = smoothstep2(progressOf(frame, FRAME_COUNTS.glitch));
11394
+ const progress = smoothstep(progressOf(frame, FRAME_COUNTS.glitch));
11167
11395
  for (let r = 0; r < grid.length; r += 1) {
11168
11396
  for (let c = 0; c < width; c += 1) {
11169
11397
  const ch = out[r][c].ch;
@@ -11184,12 +11412,12 @@ function glitchFrame(grid, frame, width) {
11184
11412
  function matrixFrame(grid, frame, width) {
11185
11413
  const out = blankFrame(grid, width);
11186
11414
  const rows = grid.length;
11187
- const progress = smoothstep2(progressOf(frame, FRAME_COUNTS.matrix));
11415
+ const progress = smoothstep(progressOf(frame, FRAME_COUNTS.matrix));
11188
11416
  const TRAIL = MATRIX_REDS.length - 1;
11189
11417
  const DELAY = 0.55;
11190
11418
  for (let c = 0; c < width; c += 1) {
11191
11419
  const delay = hash3(c, 0, 7) % 1e3 / 1e3 * DELAY;
11192
- const cp = clamp012(progress * (1 + DELAY) - delay);
11420
+ const cp = clamp01(progress * (1 + DELAY) - delay);
11193
11421
  const front = cp * (rows + TRAIL);
11194
11422
  for (let r = 0; r < rows; r += 1) {
11195
11423
  const ch = out[r][c].ch;
@@ -11207,7 +11435,7 @@ function matrixFrame(grid, frame, width) {
11207
11435
  function waveFrame(grid, frame, width) {
11208
11436
  const out = blankFrame(grid, width);
11209
11437
  const rows = grid.length;
11210
- const progress = smoothstep2(progressOf(frame, FRAME_COUNTS.wave));
11438
+ const progress = smoothstep(progressOf(frame, FRAME_COUNTS.wave));
11211
11439
  const AMP = 2.2;
11212
11440
  const CREST = WAVE_REDS.length;
11213
11441
  const K = 2 * Math.PI / Math.max(1, rows);
@@ -11229,7 +11457,7 @@ function waveFrame(grid, frame, width) {
11229
11457
  }
11230
11458
  function neonFrame(grid, frame, width) {
11231
11459
  const out = blankFrame(grid, width);
11232
- const progress = smoothstep2(progressOf(frame, FRAME_COUNTS.neon));
11460
+ const progress = smoothstep(progressOf(frame, FRAME_COUNTS.neon));
11233
11461
  for (let r = 0; r < grid.length; r += 1) {
11234
11462
  for (let c = 0; c < width; c += 1) {
11235
11463
  const ch = out[r][c].ch;
@@ -11676,14 +11904,14 @@ var DEFAULT_TOAST_ENVELOPE = {
11676
11904
  holdMs: 1500,
11677
11905
  exitMs: 180
11678
11906
  };
11679
- function clamp013(t) {
11907
+ function clamp012(t) {
11680
11908
  if (!Number.isFinite(t)) return 0;
11681
11909
  if (t <= 0) return 0;
11682
11910
  if (t >= 1) return 1;
11683
11911
  return t;
11684
11912
  }
11685
11913
  var smoothstepRamp = (t) => {
11686
- const x = clamp013(t);
11914
+ const x = clamp012(t);
11687
11915
  return x * x * (3 - 2 * x);
11688
11916
  };
11689
11917
  var HIDDEN_FRAME = {
@@ -12066,11 +12294,11 @@ function formatMessageAge(ts, now) {
12066
12294
  function boundBodyLines(body, width, options = {}) {
12067
12295
  const cap = options.expanded ? options.expandedLines ?? BODY_LINES_EXPANDED : options.collapsedLines ?? BODY_LINES_COLLAPSED;
12068
12296
  const limit = Math.max(1, Math.trunc(cap));
12069
- const cells8 = Math.max(1, Math.trunc(Number.isFinite(width) ? width : 0));
12297
+ const cells9 = Math.max(1, Math.trunc(Number.isFinite(width) ? width : 0));
12070
12298
  const wrapped = [];
12071
12299
  for (const paragraph2 of body.split("\n")) {
12072
12300
  if (!paragraph2.trim()) continue;
12073
- for (const line4 of wrapText(paragraph2, cells8)) {
12301
+ for (const line4 of wrapText(paragraph2, cells9)) {
12074
12302
  if (line4.trim()) wrapped.push(line4);
12075
12303
  }
12076
12304
  }
@@ -12759,9 +12987,9 @@ function renderMarkdownBlocks(blocks, key, theme, tone) {
12759
12987
  if (block.kind === "table") {
12760
12988
  const { widths } = block;
12761
12989
  const rule = (lc, mc, rc) => lc + widths.map((w) => "\u2500".repeat(Math.max(1, w) + 2)).join(mc) + rc;
12762
- const renderRow = (cells8, rowKey, header) => /* @__PURE__ */ jsxs18("box", { flexDirection: "row", flexShrink: 0, minWidth: 0, children: [
12990
+ const renderRow = (cells9, rowKey, header) => /* @__PURE__ */ jsxs18("box", { flexDirection: "row", flexShrink: 0, minWidth: 0, children: [
12763
12991
  /* @__PURE__ */ jsx24("text", { flexShrink: 0, fg: BORDER, children: "\u2502 " }),
12764
- cells8.map((cell, c) => {
12992
+ cells9.map((cell, c) => {
12765
12993
  const w = widths[c] ?? 1;
12766
12994
  const disp = cell.reduce((n, s) => n + Array.from(s.text).length, 0);
12767
12995
  const pad = Math.max(0, w - disp);
@@ -13297,13 +13525,13 @@ var TODO_STRIKE_REVEAL_MS = 640;
13297
13525
  var TODO_STRIKE_TOTAL_MS = TODO_STRIKE_HOLD_MS + TODO_STRIKE_REVEAL_MS;
13298
13526
  var TODO_CLEAR_DELAY_MS = 6e3;
13299
13527
  var TODO_STRIKE_FRAME_MS = 60;
13300
- function clamp014(value) {
13528
+ function clamp013(value) {
13301
13529
  return value < 0 ? 0 : value > 1 ? 1 : value;
13302
13530
  }
13303
13531
  function strikeReveal(elapsed, holdMs, revealMs) {
13304
13532
  if (elapsed <= holdMs) return 0;
13305
13533
  if (revealMs <= 0) return 1;
13306
- return clamp014((elapsed - holdMs) / revealMs);
13534
+ return clamp013((elapsed - holdMs) / revealMs);
13307
13535
  }
13308
13536
  function selectEphemeralTodos(todos, options) {
13309
13537
  const { now, completedAt } = options;
@@ -14688,13 +14916,13 @@ function renderComposerRow(line4, textColor, chipColor) {
14688
14916
  if (last < line4.length) parts.push(/* @__PURE__ */ jsx29("span", { fg: textColor, children: line4.slice(last) }, key++));
14689
14917
  return parts;
14690
14918
  }
14691
- function truncateGhostText(text, cells8) {
14692
- if (cells8 <= 0 || text.length === 0) return "";
14919
+ function truncateGhostText(text, cells9) {
14920
+ if (cells9 <= 0 || text.length === 0) return "";
14693
14921
  let out = "";
14694
14922
  let used = 0;
14695
14923
  for (const { segment } of GRAPHEMES3.segment(text)) {
14696
14924
  const w = stringWidth(segment);
14697
- if (used + w > cells8) break;
14925
+ if (used + w > cells9) break;
14698
14926
  out += segment;
14699
14927
  used += w;
14700
14928
  }
@@ -14728,10 +14956,10 @@ function wrapComposerInput(text, width) {
14728
14956
  continue;
14729
14957
  }
14730
14958
  for (const { segment } of GRAPHEMES3.segment(tok)) {
14731
- const cells8 = stringWidth(segment);
14732
- if (rowW + cells8 > w && row) pushRow();
14959
+ const cells9 = stringWidth(segment);
14960
+ if (rowW + cells9 > w && row) pushRow();
14733
14961
  row += segment;
14734
- rowW += cells8;
14962
+ rowW += cells9;
14735
14963
  }
14736
14964
  }
14737
14965
  pushRow();
@@ -14902,13 +15130,13 @@ function wrapWorkText(value, width, maxLines) {
14902
15130
  }
14903
15131
  const lastLine = lines.length + 1 === maxLines;
14904
15132
  const limit = lastLine ? width - 1 : width;
14905
- let cells8 = 0;
15133
+ let cells9 = 0;
14906
15134
  let end = 0;
14907
15135
  let breakAt = 0;
14908
15136
  for (const { segment, index } of workTextSegments.segment(rest)) {
14909
15137
  const segmentWidth = stringWidth(segment);
14910
- if (cells8 + segmentWidth > limit) break;
14911
- cells8 += segmentWidth;
15138
+ if (cells9 + segmentWidth > limit) break;
15139
+ cells9 += segmentWidth;
14912
15140
  end = index + segment.length;
14913
15141
  if (segment === " ") breakAt = index;
14914
15142
  }
@@ -15271,7 +15499,7 @@ function cells3(value, fallback = 0) {
15271
15499
  const truncated = Math.trunc(raw);
15272
15500
  return truncated > 0 ? truncated : 0;
15273
15501
  }
15274
- function clamp3(value, low, high) {
15502
+ function clamp2(value, low, high) {
15275
15503
  if (high < low) return low;
15276
15504
  return Math.min(Math.max(value, low), high);
15277
15505
  }
@@ -15393,7 +15621,7 @@ function commsFleetStatLine(row, now) {
15393
15621
  function clampFleetSelection(count, current) {
15394
15622
  const total = cells3(count);
15395
15623
  if (total === 0) return -1;
15396
- return clamp3(Math.trunc(Number.isFinite(current) ? current : 0), 0, total - 1);
15624
+ return clamp2(Math.trunc(Number.isFinite(current) ? current : 0), 0, total - 1);
15397
15625
  }
15398
15626
  function moveFleetSelection(count, current, delta) {
15399
15627
  const total = cells3(count);
@@ -17038,7 +17266,7 @@ ${preview.warnings.join("\n")}` : "") + "\n\n/feedback send to submit \xB7 /feed
17038
17266
  const buildSession = useCallback4(async (opts = {}) => {
17039
17267
  if (closingRef.current || stoppingAuditRef.current) throw new Error("This audit is stopping.");
17040
17268
  const buildEpoch = ++sessionBuildEpoch.current;
17041
- const env = { ...process.env, ...credentialEnvPatch(loadCredentials(), process.env) };
17269
+ const env = { ...process.env, ...savedConnectionEnvPatch(process.env) };
17042
17270
  const { runtime, explicitChoice } = await createPreferredConsoleRuntime({
17043
17271
  model: (opts.providerId !== void 0 ? opts.model : opts.model ?? options?.model) || void 0,
17044
17272
  provider: opts.providerId ?? options?.providerId,
@@ -17234,7 +17462,7 @@ ${preview.warnings.join("\n")}` : "") + "\n\n/feedback send to submit \xB7 /feed
17234
17462
  const applyRuntimeSelection = useCallback4((sel) => {
17235
17463
  const runtime = runtimeRef.current;
17236
17464
  if (!runtime) return;
17237
- const env = { ...process.env, ...credentialEnvPatch(loadCredentials(), process.env) };
17465
+ const env = { ...process.env, ...savedConnectionEnvPatch(process.env) };
17238
17466
  const currentProvider = runtime.getConfigurationDiagnostics().provider;
17239
17467
  let targetProvider = sel.providerId;
17240
17468
  if (targetProvider === void 0 && sel.model !== void 0) {
@@ -18053,7 +18281,13 @@ ${preview.warnings.join("\n")}` : "") + "\n\n/feedback send to submit \xB7 /feed
18053
18281
  `test command ${testCommand}`,
18054
18282
  "Working on isolated copies; your checkout is untouched. /fix cancel stops it."
18055
18283
  ]);
18056
- const runtime = createRuntime({ type: "api", timeout: 6e5, model: modelId ?? void 0, provider: options?.providerId });
18284
+ const runtime = createRuntime({
18285
+ type: "api",
18286
+ timeout: 6e5,
18287
+ model: modelId ?? void 0,
18288
+ provider: options?.providerId,
18289
+ env: Object.fromEntries(Object.entries({ ...process.env, ...savedConnectionEnvPatch(process.env) }).filter((entry) => entry[1] !== void 0))
18290
+ });
18057
18291
  if (!isNativeRuntime(runtime) || !await runtime.isAvailable()) throw new Error("selected API runtime is unavailable; connect a provider first");
18058
18292
  const result = await runSourceFix({
18059
18293
  repoRoot,
@@ -21101,7 +21335,7 @@ function connectFooterHint(mode, hasFilter = false, canContinue = false) {
21101
21335
  hasFilter ? "Esc clear" : "Esc back"
21102
21336
  ].join(" \xB7 ");
21103
21337
  }
21104
- function isFilterKey4(sequence) {
21338
+ function isFilterKey3(sequence) {
21105
21339
  if (typeof sequence !== "string" || sequence.length !== 1) return false;
21106
21340
  const code = sequence.charCodeAt(0);
21107
21341
  return code >= 32 && code !== 127;
@@ -23076,6 +23310,348 @@ function HarnessLifecycle({ children, host, busy, workspaceRoot }) {
23076
23310
  import { useEffect as useEffect22, useMemo as useMemo18, useRef as useRef21, useState as useState25 } from "react";
23077
23311
  import { useKeyboard as useKeyboard18, usePaste as usePaste4 } from "@opentui/react";
23078
23312
  import { decodePasteBytes as decodePasteBytes4, TextAttributes as TextAttributes20 } from "@opentui/core";
23313
+
23314
+ // packages/cli/src/tui/model-layout.ts
23315
+ var DEFAULT_SYMBOLS4 = getSymbols("unicode");
23316
+ function cells6(value, fallback = 0) {
23317
+ const raw = typeof value === "number" && Number.isFinite(value) ? value : fallback;
23318
+ const truncated = Math.trunc(raw);
23319
+ return truncated > 0 ? truncated : 0;
23320
+ }
23321
+ function titleCase(id) {
23322
+ return sanitizeTuiText(id).split(/[-_\s]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
23323
+ }
23324
+ function providerGroupFor(id, states) {
23325
+ const state = states.find((candidate) => candidate.id === id);
23326
+ if (!state) {
23327
+ return {
23328
+ id,
23329
+ label: titleCase(id) || id,
23330
+ credential: "unmapped",
23331
+ envVars: []
23332
+ };
23333
+ }
23334
+ return {
23335
+ id: state.id,
23336
+ label: state.label,
23337
+ credential: state.configured ? "ready" : "missing",
23338
+ via: state.via,
23339
+ hint: state.hint,
23340
+ fileSource: state.fileSource,
23341
+ envVars: state.envVars
23342
+ };
23343
+ }
23344
+ function configuredProviderLabels(states) {
23345
+ return states.filter((state) => state.configured).map((state) => state.label);
23346
+ }
23347
+ function credentialSummary(states) {
23348
+ const labels = configuredProviderLabels(states);
23349
+ if (labels.length === 0) {
23350
+ return "No provider connected \xB7 /connect to add one";
23351
+ }
23352
+ return `Connected: ${labels.join(", ")}`;
23353
+ }
23354
+ function compareStrings2(a, b) {
23355
+ if (a === b) return 0;
23356
+ return a < b ? -1 : 1;
23357
+ }
23358
+ var PROVIDER_ORDER = new Map(PROVIDERS.map((info, index) => [info.id, index]));
23359
+ function groupRank(group, activeProvider) {
23360
+ if (activeProvider !== void 0 && group.id === activeProvider) return 0;
23361
+ switch (group.credential) {
23362
+ case "ready":
23363
+ return 1;
23364
+ case "missing":
23365
+ return 2;
23366
+ default:
23367
+ return 3;
23368
+ }
23369
+ }
23370
+ function buildModelRows({
23371
+ catalog = buildModelCatalog(),
23372
+ states = providerStates({}),
23373
+ filter = "",
23374
+ activeModel,
23375
+ activeProvider: selectedProvider
23376
+ } = {}) {
23377
+ const terms = sanitizeTuiText(filter).toLowerCase().split(" ").filter(Boolean);
23378
+ const groups = /* @__PURE__ */ new Map();
23379
+ const byProvider = /* @__PURE__ */ new Map();
23380
+ for (const model of catalog) {
23381
+ if (!model || typeof model.id !== "string" || model.id.length === 0) continue;
23382
+ const providerId = typeof model.provider === "string" && model.provider.length > 0 ? model.provider : "unknown";
23383
+ let group = groups.get(providerId);
23384
+ if (!group) {
23385
+ group = providerGroupFor(providerId, states);
23386
+ groups.set(providerId, group);
23387
+ }
23388
+ const haystack2 = `${model.id} ${group.id} ${group.label} ${model.price}`.toLowerCase();
23389
+ if (terms.length > 0 && !terms.every((term) => haystack2.includes(term))) continue;
23390
+ const bucket = byProvider.get(providerId);
23391
+ if (bucket) bucket.push(model);
23392
+ else byProvider.set(providerId, [model]);
23393
+ }
23394
+ const activeProvider = selectedProvider ?? [...byProvider.entries()].find(
23395
+ ([, models]) => models.some((model) => model.id === activeModel)
23396
+ )?.[0];
23397
+ const order = [...byProvider.keys()].sort((a, b) => {
23398
+ const left = groups.get(a);
23399
+ const right = groups.get(b);
23400
+ if (!left || !right) return compareStrings2(a, b);
23401
+ return groupRank(left, activeProvider) - groupRank(right, activeProvider) || (PROVIDER_ORDER.get(a) ?? Number.MAX_SAFE_INTEGER) - (PROVIDER_ORDER.get(b) ?? Number.MAX_SAFE_INTEGER) || compareStrings2(a, b);
23402
+ });
23403
+ const rows = [];
23404
+ for (const providerId of order) {
23405
+ const group = groups.get(providerId);
23406
+ const models = byProvider.get(providerId);
23407
+ if (!group || !models || models.length === 0) continue;
23408
+ const sorted = [...models].sort((a, b) => {
23409
+ if (a.id === activeModel) return b.id === activeModel ? 0 : -1;
23410
+ if (b.id === activeModel) return 1;
23411
+ return compareStrings2(a.id, b.id);
23412
+ });
23413
+ rows.push({ kind: "heading", group, count: sorted.length });
23414
+ for (const model of sorted) {
23415
+ rows.push({ kind: "model", group, model, active: model.id === activeModel && providerId === activeProvider });
23416
+ }
23417
+ }
23418
+ return rows;
23419
+ }
23420
+ var MODEL_CONNECT_ACTION_ID = "\0model-connect";
23421
+ function modelConnectActionItem() {
23422
+ return {
23423
+ id: MODEL_CONNECT_ACTION_ID,
23424
+ label: "Connect another provider\u2026",
23425
+ description: "Open Connections",
23426
+ category: "Connections"
23427
+ };
23428
+ }
23429
+ function isModelConnectAction(item) {
23430
+ return item.id === MODEL_CONNECT_ACTION_ID;
23431
+ }
23432
+ function activateModelConnectAction(item, onConnect) {
23433
+ if (!isModelConnectAction(item)) return false;
23434
+ onConnect?.();
23435
+ return true;
23436
+ }
23437
+ function modelResultCount(items) {
23438
+ return items.reduce((count, item) => count + (isModelConnectAction(item) ? 0 : 1), 0);
23439
+ }
23440
+ function modelConnectDetailLines(width) {
23441
+ const limit = cells6(width);
23442
+ if (limit === 0) return [];
23443
+ return wrapCells("Add a provider in Connections.", limit).map((text) => ({ text, tone: "accent" }));
23444
+ }
23445
+ function catalogContextKey(provider, id) {
23446
+ return `${provider}\0${id}`;
23447
+ }
23448
+ function buildContextWindowIndex(models) {
23449
+ const index = /* @__PURE__ */ new Map();
23450
+ const conflicted = /* @__PURE__ */ new Set();
23451
+ for (const model of models) {
23452
+ if (typeof model?.id !== "string" || model.id.length === 0) continue;
23453
+ if (typeof model.provider !== "string" || model.provider.length === 0) continue;
23454
+ const tokens = model.contextTokens;
23455
+ if (typeof tokens !== "number" || !Number.isFinite(tokens) || tokens <= 0) continue;
23456
+ const key = catalogContextKey(model.provider, model.id);
23457
+ if (conflicted.has(key)) continue;
23458
+ const seen = index.get(key);
23459
+ if (seen !== void 0 && seen !== Math.trunc(tokens)) {
23460
+ index.delete(key);
23461
+ conflicted.add(key);
23462
+ continue;
23463
+ }
23464
+ index.set(key, Math.trunc(tokens));
23465
+ }
23466
+ return index;
23467
+ }
23468
+ function contextWindowFor(index, provider, id) {
23469
+ if (typeof provider !== "string" || provider.length === 0) return null;
23470
+ if (typeof id !== "string" || id.length === 0) return null;
23471
+ return index.get(catalogContextKey(provider, id)) ?? null;
23472
+ }
23473
+ function formatContextTokens(value) {
23474
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return "unknown";
23475
+ const tokens = Math.trunc(value);
23476
+ if (tokens >= 1e6 && tokens % 1e6 === 0) return `${tokens / 1e6}M tokens`;
23477
+ if (tokens >= 1e3 && tokens % 1e3 === 0) return `${tokens / 1e3}K tokens`;
23478
+ return `${tokens} tokens`;
23479
+ }
23480
+ function modelPriceText(price) {
23481
+ const text = sanitizeTuiText(price ?? "");
23482
+ if (text.length === 0 || text === "\u2014" || text === "-") return "not published";
23483
+ return text;
23484
+ }
23485
+ function modelDetailLines({ row, configured = [], compact = false, contextTokens }, width, symbols = DEFAULT_SYMBOLS4) {
23486
+ const limit = cells6(width);
23487
+ if (!row || limit <= 0) return [];
23488
+ const ICON_PROVIDER = symbols.fieldHost;
23489
+ const ICON_PRICE = symbols.fieldCost;
23490
+ const ICON_CONTEXT = symbols.fieldContext;
23491
+ const lines = [];
23492
+ const push2 = (value, tone) => {
23493
+ for (const text of wrapCells(value, limit)) lines.push({ text, tone });
23494
+ };
23495
+ const separate = () => {
23496
+ if (!compact) lines.push({ text: "", tone: "blank" });
23497
+ };
23498
+ const group = row.group;
23499
+ if (row.kind === "heading") {
23500
+ push2(group.label, "title");
23501
+ separate();
23502
+ push2(`${row.count} model${row.count === 1 ? "" : "s"}`, "text");
23503
+ } else {
23504
+ push2(row.model.id, "title");
23505
+ separate();
23506
+ push2(`${ICON_PROVIDER} Provider: ${group.label}`, "text");
23507
+ const priceText = modelPriceText(row.model.price);
23508
+ push2(`${ICON_PRICE} Price: ${priceText}`, priceText === "not published" ? "muted" : "text");
23509
+ const contextText = formatContextTokens(contextTokens);
23510
+ push2(`${ICON_CONTEXT} Context: ${contextText}`, contextText === "unknown" ? "muted" : "text");
23511
+ if (row.active) push2("In use", "accent");
23512
+ else push2("Enter to use", "accent");
23513
+ }
23514
+ separate();
23515
+ switch (group.credential) {
23516
+ case "ready":
23517
+ push2(`Connected via ${group.via ?? "the environment"}`, "ok");
23518
+ break;
23519
+ case "missing":
23520
+ push2("Not connected \xB7 /connect to set up", "warn");
23521
+ if (group.envVars.length > 0) push2(`Reads: ${group.envVars.join(", ")}`, "muted");
23522
+ if (group.hint) push2(`Setup: ${group.hint}`, "muted");
23523
+ if (group.fileSource) {
23524
+ push2(`Also reads ${group.fileSource} (not checked).`, "muted");
23525
+ }
23526
+ if (configured.length > 0) push2(`Connected: ${configured.join(", ")}`, "muted");
23527
+ break;
23528
+ default:
23529
+ push2("No direct access. Use a gateway like OpenRouter or OpenCode Zen.", "muted");
23530
+ break;
23531
+ }
23532
+ return lines;
23533
+ }
23534
+ function clipModelDetailLines(lines, rows, width = 0) {
23535
+ const limit = cells6(rows);
23536
+ if (limit <= 0) return [];
23537
+ if (lines.length <= limit) return [...lines];
23538
+ const kept = lines.slice(0, limit);
23539
+ const last = kept[limit - 1];
23540
+ const room = cells6(width);
23541
+ if (room >= 8 && last && last.text.length > 0) {
23542
+ const head = last.text.slice(0, Math.max(0, room - 4)).trimEnd();
23543
+ kept[limit - 1] = { text: `${head} ...`, tone: last.tone };
23544
+ } else {
23545
+ kept[limit - 1] = { text: "...", tone: "muted" };
23546
+ }
23547
+ return kept;
23548
+ }
23549
+ var MODEL_DIALOG_HOST_CHROME_ROWS = 2;
23550
+ function dialogContentWidth(width, inDialog = false) {
23551
+ return Math.max(0, cells6(width) - (inDialog ? 0 : 4));
23552
+ }
23553
+ var MAX_META_ROWS = 8;
23554
+ var META_BODY_FLOOR = 6;
23555
+ var STACKED_MIN_WIDTH = 24;
23556
+ var STACKED_MIN_LIST_ROWS = 6;
23557
+ var STACKED_MAX_ROWS = 8;
23558
+ function computeModelDialogLayout({
23559
+ width,
23560
+ height,
23561
+ totalRows,
23562
+ inDialog = false,
23563
+ compact = false,
23564
+ hostChromeRows,
23565
+ metaLineCount
23566
+ }) {
23567
+ const surfaceWidth = cells6(width);
23568
+ const surfaceHeight = cells6(height);
23569
+ const contentWidth = dialogContentWidth(surfaceWidth, inDialog);
23570
+ const chrome = inDialog ? cells6(hostChromeRows ?? MODEL_DIALOG_HOST_CHROME_ROWS) : shellChromeRows(surfaceWidth);
23571
+ const available = Math.max(0, surfaceHeight - chrome);
23572
+ const titleRows = available >= 5 ? 1 : 0;
23573
+ const statusRows = available >= 4 ? 1 : 0;
23574
+ const desiredMeta = cells6(metaLineCount ?? 2);
23575
+ const metaCeiling = available >= 10 ? MAX_META_ROWS : available >= 8 ? 1 : 0;
23576
+ const metaBudget = Math.max(0, available - titleRows - statusRows - META_BODY_FLOOR);
23577
+ const metaRows = Math.min(desiredMeta, metaCeiling, metaBudget);
23578
+ const bodyRows = Math.max(0, available - titleRows - statusRows - metaRows);
23579
+ const panelFor = (rows) => computeDialogPanel({
23580
+ width: contentWidth,
23581
+ height: surfaceHeight,
23582
+ size: "large",
23583
+ totalRows,
23584
+ withDetail: !compact,
23585
+ bodyRows: rows
23586
+ });
23587
+ let panel = panelFor(bodyRows);
23588
+ let stackedRows = 0;
23589
+ if (!compact && !panel.showDetail && contentWidth >= STACKED_MIN_WIDTH && bodyRows >= STACKED_MIN_LIST_ROWS + 3) {
23590
+ stackedRows = Math.min(STACKED_MAX_ROWS, bodyRows - STACKED_MIN_LIST_ROWS);
23591
+ panel = panelFor(bodyRows - stackedRows);
23592
+ }
23593
+ return { contentWidth, titleRows, metaRows, statusRows, bodyRows, stackedRows, panel };
23594
+ }
23595
+ function modelDialogTitle({ scope }) {
23596
+ return scope === "unknown" ? "Select model \xB7 not connected" : "Select model";
23597
+ }
23598
+ function modelDialogCount(matched, refreshing) {
23599
+ const count = cells6(matched);
23600
+ return `${count} model${count === 1 ? "" : "s"}${refreshing ? " \xB7 loading" : ""}`;
23601
+ }
23602
+ function modelDialogHint({ scope, role = null, hasFilter = false, canReload = false }) {
23603
+ void scope;
23604
+ void canReload;
23605
+ return [
23606
+ "[\u23CE] apply",
23607
+ "[\u2303\u2190\u2192] target",
23608
+ "[\u2303S] single model",
23609
+ role !== null ? "[\u2303\u232B] inherit" : void 0,
23610
+ hasFilter ? "[esc] clear" : "[esc] back"
23611
+ ].filter((part) => part !== void 0).join(" \xB7 ");
23612
+ }
23613
+ function modelTargetLine(role, activeModel, assigned, symbols = DEFAULT_SYMBOLS4, singleModel = false) {
23614
+ const target = role === null ? "parent" : sanitizeTuiText(role);
23615
+ const model = sanitizeTuiText(activeModel ?? "");
23616
+ const value = model.length > 0 ? model : "not selected";
23617
+ const inherits = role !== null && !assigned ? " (inherits parent)" : "";
23618
+ const inert = singleModel && role !== null ? " \xB7 ignored (single model on)" : "";
23619
+ return `${symbols.fieldModel} Target: ${target} \u2192 ${value}${inherits}${inert}`;
23620
+ }
23621
+ function agentRosterToken(role, parentModel, agentModels, focused) {
23622
+ let token;
23623
+ if (role === null) {
23624
+ const model = sanitizeTuiText(parentModel ?? "");
23625
+ token = `parent \u2192 ${model.length > 0 ? model : "not selected"}`;
23626
+ } else {
23627
+ const assigned = agentModels[role];
23628
+ token = assigned !== void 0 ? `${sanitizeTuiText(role)} \u2192 ${sanitizeTuiText(assigned)}` : `${sanitizeTuiText(role)} \u2192 inherits parent`;
23629
+ }
23630
+ return focused ? `[${token}]` : token;
23631
+ }
23632
+ function agentRosterLines({ roles, parentModel, agentModels = {}, activeRole, singleModel = false }, width, _symbols = DEFAULT_SYMBOLS4) {
23633
+ const limit = cells6(width);
23634
+ if (limit <= 0 || roles.length === 0) return [];
23635
+ const tokens = roles.map((role) => agentRosterToken(role, parentModel, agentModels, role === activeRole));
23636
+ const header = singleModel ? "Agents (ignored, single model on): " : "Agents: ";
23637
+ const lines = [];
23638
+ wrapCells(`${header}${tokens.join(" ")}`, limit).forEach((text, index) => {
23639
+ lines.push({ text, tone: index === 0 && singleModel ? "warn" : "muted" });
23640
+ });
23641
+ return lines;
23642
+ }
23643
+ function modelFooterHint(mode, hasFilter = false) {
23644
+ return [
23645
+ "[\u23CE] select",
23646
+ "[\u21E5] curated/all",
23647
+ mode === "filter" || hasFilter ? "[esc] clear" : "[esc] back"
23648
+ ].join(" \xB7 ");
23649
+ }
23650
+ function isFilterKey4(sequence) {
23651
+ return typeof sequence === "string" && sequence.length > 0 && !/[\x00-\x1f\x7f-\x9f]/.test(sequence);
23652
+ }
23653
+
23654
+ // packages/cli/src/tui/model-screen.tsx
23079
23655
  import { Fragment as Fragment16, jsx as jsx44, jsxs as jsxs36 } from "@opentui/react/jsx-runtime";
23080
23656
  var PAGE_STEP3 = 5;
23081
23657
  var MODEL_ROLES = ["discovery", "attack", "verify", "report", "audit", "review"];
@@ -23138,7 +23714,7 @@ function ModelScreen({
23138
23714
  const [reload, setReload] = useState25(0);
23139
23715
  const env = useMemo18(() => suppliedEnv ?? {
23140
23716
  ...process.env,
23141
- ...credentialEnvPatch(loadCredentials(), process.env)
23717
+ ...savedConnectionEnvPatch(process.env)
23142
23718
  }, [suppliedEnv, reload]);
23143
23719
  const scope = "byok";
23144
23720
  const rolesLive = onAgentModelsChange !== void 0;
@@ -23161,6 +23737,9 @@ function ModelScreen({
23161
23737
  const loadCodex = providerId === "chatgpt-codex" || credentialStates.some((state) => state.id === "chatgpt-codex" && state.configured);
23162
23738
  const source = useMemo18(() => ({ providerId, env, reload, codexCatalog }), [providerId, env, reload, codexCatalog]);
23163
23739
  const [codexState, setCodexState] = useState25(null);
23740
+ const [connectionState, setConnectionState] = useState25(null);
23741
+ const connectionModels = connectionState?.source === source ? connectionState.result.models : [];
23742
+ const connectionDiagnostics = connectionState?.source === source ? connectionState.result.diagnostics : [];
23164
23743
  const codexModels = codexState?.source === source ? codexState.models : null;
23165
23744
  const codexFailed = codexState?.source === source && codexState.failed;
23166
23745
  const states = useMemo18(() => credentialStates.map((state) => state.id === "chatgpt-codex" && codexModels !== null ? { ...state, configured: true } : state), [credentialStates, codexModels]);
@@ -23185,6 +23764,9 @@ function ModelScreen({
23185
23764
  }
23186
23765
  ));
23187
23766
  }
23767
+ tasks.push(discoverConnectionModels(env, credentialStates.filter((state) => state.configured && state.id !== "chatgpt-codex").map((state) => state.id), controller.signal).then((result) => {
23768
+ if (alive) setConnectionState({ source, result });
23769
+ }));
23188
23770
  tasks.push(
23189
23771
  syncModelCatalog({ force: reload > 0 }).then((updated) => {
23190
23772
  if (!alive) return;
@@ -23212,12 +23794,16 @@ function ModelScreen({
23212
23794
  );
23213
23795
  const scopeCatalog = (query, all) => {
23214
23796
  const scoped = scopeModelCatalog(catalog, { showAll: all, filter: query, currentModel: activeModel });
23215
- const catalogRows = [
23216
- ...scoped.filter((model) => model.provider !== "chatgpt-codex"),
23797
+ const metadata = new Map(catalog.map((model) => [`${model.provider}/${model.id}`, model]));
23798
+ const scopedIds = new Set(scoped.map((model) => `${model.provider}/${model.id}`));
23799
+ return [
23800
+ ...connectionModels.filter((model) => !metadata.has(`${model.provider}/${model.id}`) || scopedIds.has(`${model.provider}/${model.id}`)).map((model) => ({
23801
+ id: model.id,
23802
+ provider: model.provider,
23803
+ price: model.provider === "cline" && model.id.startsWith("cline-pass/") ? "Pass \xB7 access unverified" : metadata.get(`${model.provider}/${model.id}`)?.price ?? "\u2014"
23804
+ })),
23217
23805
  ...(codexModels ?? []).map((model) => ({ id: model.id, provider: "chatgpt-codex", price: "subscription" }))
23218
- ];
23219
- const codexModelIds = new Set((codexModels ?? []).map((model) => model.id));
23220
- return reachableModelCatalog(catalogRows, states, { env, providerId, codexModelIds }).filter((model) => role === null || model.provider === providerId);
23806
+ ].filter((model) => role === null || model.provider === providerId);
23221
23807
  };
23222
23808
  const scopedCatalog = scopeCatalog(filter, showAll);
23223
23809
  const modelRows = useMemo18(
@@ -23250,7 +23836,15 @@ function ModelScreen({
23250
23836
  () => providerId && activeModel ? catalogContextKey(providerId, activeModel) : items.find((item) => item.row?.active)?.id ?? items[0]?.id
23251
23837
  );
23252
23838
  const selectedIdRef = useRef21(selectedId);
23253
- const selectionIndex = (visible, selection = selectedIdRef.current) => clampDialogSelection(visible, visible.findIndex((item) => item.id === selection));
23839
+ const selectionTouchedRef = useRef21(false);
23840
+ const selectionIndex = (visible, selection = selectedIdRef.current) => {
23841
+ if (!selectionTouchedRef.current) {
23842
+ const initial = visible.findIndex((item) => item.row?.active);
23843
+ const firstModel = visible.findIndex((item) => item.row !== void 0);
23844
+ if (initial >= 0 || firstModel >= 0) return clampDialogSelection(visible, initial >= 0 ? initial : firstModel);
23845
+ }
23846
+ return clampDialogSelection(visible, visible.findIndex((item) => item.id === selection));
23847
+ };
23254
23848
  const cursor = selectionIndex(items, selectedId);
23255
23849
  const metaContentWidth = dialogContentWidth(width, inDialog);
23256
23850
  const metaLines = [];
@@ -23281,7 +23875,8 @@ function ModelScreen({
23281
23875
  const visibleMetaLines = metaLines.slice(0, layout.metaRows);
23282
23876
  const mode = filter ? "filter" : "browse";
23283
23877
  const baseStatusText = credentialSummary(states);
23284
- const catalogStatus = publicFailed ? "Catalog offline \xB7 showing cached models \xB7 Ctrl+R retry" : baseStatusText;
23878
+ const discoveryStatus = connectionDiagnostics.length ? `${connectionDiagnostics.map((item) => item.providerId).join(", ")} models unavailable \xB7 Ctrl+R retry` : baseStatusText;
23879
+ const catalogStatus = publicFailed ? `Pricing offline \xB7 ${discoveryStatus}` : discoveryStatus;
23285
23880
  const statusText = !loadCodex ? catalogStatus : `${codexFailed ? `Codex models unavailable${codexModels ? " \xB7 showing cached" : ""} \xB7 Ctrl+R retry` : codexModels === null ? "Loading Codex models\u2026" : `${codexModels.length} Codex models`} \xB7 ${catalogStatus}`;
23286
23881
  const currentItems = () => {
23287
23882
  const byok = filterRef.current === filter && showAllRef.current === showAll ? byokItems : modelDialogItems(buildModelRows({
@@ -23295,6 +23890,7 @@ function ModelScreen({
23295
23890
  };
23296
23891
  const highlight = (index, visible = currentItems()) => {
23297
23892
  const item = visible[clampDialogSelection(visible, index)];
23893
+ selectionTouchedRef.current = true;
23298
23894
  selectedIdRef.current = item?.id;
23299
23895
  setSelectedId(item?.id);
23300
23896
  };
@@ -23418,7 +24014,7 @@ function ModelScreen({
23418
24014
  setQuery((current) => Array.from(current).slice(0, -1).join(""));
23419
24015
  return;
23420
24016
  }
23421
- if (isFilterKey2(seq)) {
24017
+ if (isFilterKey4(seq)) {
23422
24018
  setQuery((current) => current === "" && seq === "/" ? "" : current + seq);
23423
24019
  }
23424
24020
  });
@@ -23485,7 +24081,7 @@ function ModelScreen({
23485
24081
  renderDetail,
23486
24082
  onActivateRow: (index) => highlight(index, items),
23487
24083
  onScroll: move2,
23488
- emptyText: showAll || filter.trim() ? "No matches. Ctrl+U clears search." : "No connected models. Tab shows all, or connect a provider."
24084
+ emptyText: filter.trim() ? "No matches. Ctrl+U clears search." : "No discovered models. Ctrl+R retries, or connect a provider."
23489
24085
  }
23490
24086
  ),
23491
24087
  stackedRows > 0 && items[cursor] ? /* @__PURE__ */ jsx44("box", { width: contentWidth, height: stackedRows, flexDirection: "column", flexShrink: 0, minWidth: 0, children: renderDetail(items[cursor], { width: contentWidth, height: stackedRows }) }) : null,
@@ -23508,8 +24104,8 @@ import { useKeyboard as useKeyboard19, usePaste as usePaste5 } from "@opentui/re
23508
24104
  import { decodePasteBytes as decodePasteBytes5, TextAttributes as TextAttributes21 } from "@opentui/core";
23509
24105
 
23510
24106
  // packages/cli/src/tui/resume-layout.ts
23511
- var DEFAULT_SYMBOLS4 = getSymbols("unicode");
23512
- function cells6(value, fallback = 0) {
24107
+ var DEFAULT_SYMBOLS5 = getSymbols("unicode");
24108
+ function cells7(value, fallback = 0) {
23513
24109
  const raw = typeof value === "number" && Number.isFinite(value) ? value : fallback;
23514
24110
  const truncated = Math.trunc(raw);
23515
24111
  return truncated > 0 ? truncated : 0;
@@ -23531,7 +24127,7 @@ function sessionMeta(session, now) {
23531
24127
  const parts = [];
23532
24128
  const age = relativeAge(session.savedAt, now);
23533
24129
  if (age.length > 0) parts.push(age);
23534
- const count = cells6(session.messageCount);
24130
+ const count = cells7(session.messageCount);
23535
24131
  parts.push(`${count} msg${count === 1 ? "" : "s"}`);
23536
24132
  const model = sanitizeTuiText(session.model ?? "");
23537
24133
  if (model.length > 0) parts.push(model);
@@ -23546,7 +24142,7 @@ function resumeItems({
23546
24142
  now,
23547
24143
  filter = "",
23548
24144
  protectedSessionIds,
23549
- symbols = DEFAULT_SYMBOLS4
24145
+ symbols = DEFAULT_SYMBOLS5
23550
24146
  }) {
23551
24147
  const terms = sanitizeTuiText(filter).toLowerCase().split(" ").filter(Boolean);
23552
24148
  const matches = (text) => {
@@ -23604,8 +24200,8 @@ function formatSavedAt(savedAt) {
23604
24200
  const time = `${pad2(date.getUTCHours())}:${pad2(date.getUTCMinutes())}`;
23605
24201
  return `${day} ${time} UTC`;
23606
24202
  }
23607
- function resumeDetailLines({ session, liveSession, now, compact = false, isProtected = false }, width, symbols = DEFAULT_SYMBOLS4) {
23608
- const limit = cells6(width);
24203
+ function resumeDetailLines({ session, liveSession, now, compact = false, isProtected = false }, width, symbols = DEFAULT_SYMBOLS5) {
24204
+ const limit = cells7(width);
23609
24205
  if (!session && !liveSession || limit <= 0) return [];
23610
24206
  const ICON_PROTECTED = symbols.fieldProtected;
23611
24207
  const lines = [];
@@ -23645,7 +24241,7 @@ function resumeDetailLines({ session, liveSession, now, compact = false, isProte
23645
24241
  );
23646
24242
  }
23647
24243
  separate();
23648
- const count = cells6(session.messageCount);
24244
+ const count = cells7(session.messageCount);
23649
24245
  push2(`Messages: ${count}`, "muted");
23650
24246
  const model = sanitizeTuiText(session.model ?? "");
23651
24247
  if (model.length > 0) push2(`Model: ${model}`, "muted");
@@ -23663,12 +24259,12 @@ function resumeDetailLines({ session, liveSession, now, compact = false, isProte
23663
24259
  return lines;
23664
24260
  }
23665
24261
  function clipResumeDetailLines(lines, rows, width = 0) {
23666
- const limit = cells6(rows);
24262
+ const limit = cells7(rows);
23667
24263
  if (limit <= 0) return [];
23668
24264
  if (lines.length <= limit) return [...lines];
23669
24265
  const kept = lines.slice(0, limit);
23670
24266
  const last = kept[limit - 1];
23671
- const room = cells6(width);
24267
+ const room = cells7(width);
23672
24268
  if (room >= 8 && last && last.text.length > 0) {
23673
24269
  const head = last.text.slice(0, Math.max(0, room - 4)).trimEnd();
23674
24270
  kept[limit - 1] = { text: `${head} ...`, tone: last.tone };
@@ -23677,9 +24273,9 @@ function clipResumeDetailLines(lines, rows, width = 0) {
23677
24273
  }
23678
24274
  return kept;
23679
24275
  }
23680
- var STACKED_MIN_WIDTH = 24;
23681
- var STACKED_MIN_LIST_ROWS = 6;
23682
- var STACKED_MAX_ROWS = 8;
24276
+ var STACKED_MIN_WIDTH2 = 24;
24277
+ var STACKED_MIN_LIST_ROWS2 = 6;
24278
+ var STACKED_MAX_ROWS2 = 8;
23683
24279
  function computeResumeDialogLayout({
23684
24280
  width,
23685
24281
  height,
@@ -23688,8 +24284,8 @@ function computeResumeDialogLayout({
23688
24284
  hasStatus = false,
23689
24285
  hasActions = false
23690
24286
  }) {
23691
- const surfaceWidth = cells6(width);
23692
- const surfaceHeight = cells6(height);
24287
+ const surfaceWidth = cells7(width);
24288
+ const surfaceHeight = cells7(height);
23693
24289
  const contentWidth = Math.max(0, surfaceWidth - (inDialog ? 0 : 4));
23694
24290
  const available = Math.max(0, surfaceHeight - (inDialog ? 0 : shellChromeRows(surfaceWidth)));
23695
24291
  const footerRows = available >= 3 ? 1 : 0;
@@ -23707,24 +24303,24 @@ function computeResumeDialogLayout({
23707
24303
  });
23708
24304
  let panel = panelFor(bodyRows);
23709
24305
  let stackedRows = 0;
23710
- if (!panel.showDetail && contentWidth >= STACKED_MIN_WIDTH && bodyRows >= STACKED_MIN_LIST_ROWS + 3) {
23711
- stackedRows = Math.min(STACKED_MAX_ROWS, bodyRows - STACKED_MIN_LIST_ROWS);
24306
+ if (!panel.showDetail && contentWidth >= STACKED_MIN_WIDTH2 && bodyRows >= STACKED_MIN_LIST_ROWS2 + 3) {
24307
+ stackedRows = Math.min(STACKED_MAX_ROWS2, bodyRows - STACKED_MIN_LIST_ROWS2);
23712
24308
  panel = panelFor(bodyRows - stackedRows);
23713
24309
  }
23714
24310
  return { contentWidth, titleRows, statusRows, footerRows, actionRows, bodyRows, stackedRows, panel };
23715
24311
  }
23716
- function resumeDialogTitle(scope, scoped, symbols = DEFAULT_SYMBOLS4) {
24312
+ function resumeDialogTitle(scope, scoped, symbols = DEFAULT_SYMBOLS5) {
23717
24313
  const head = `${operatorIcon("resume", symbols)} ${operatorTitle("resume")}`;
23718
24314
  if (!scoped) return head;
23719
24315
  return `${head} \xB7 ${scope === "project" ? "this project" : "all projects"}`;
23720
24316
  }
23721
- function resumeDialogCount(matched, protectedCount = 0, symbols = DEFAULT_SYMBOLS4) {
23722
- const count = cells6(matched);
23723
- const locked = cells6(protectedCount);
24317
+ function resumeDialogCount(matched, protectedCount = 0, symbols = DEFAULT_SYMBOLS5) {
24318
+ const count = cells7(matched);
24319
+ const locked = cells7(protectedCount);
23724
24320
  const head = `${count} session${count === 1 ? "" : "s"}`;
23725
24321
  return locked > 0 ? `${head} \xB7 ${symbols.fieldProtected} ${locked} live` : head;
23726
24322
  }
23727
- function resumeFooterHint(mode, hasFilter = false, hasSessions = true, scope = "project", sessionCount, highlightProtected = false, symbols = DEFAULT_SYMBOLS4) {
24323
+ function resumeFooterHint(mode, hasFilter = false, hasSessions = true, scope = "project", sessionCount, highlightProtected = false, symbols = DEFAULT_SYMBOLS5) {
23728
24324
  const ICON_PROTECTED = symbols.fieldProtected;
23729
24325
  void sessionCount;
23730
24326
  switch (mode) {
@@ -24398,7 +24994,7 @@ function MarketScreen({
24398
24994
  setQuery(filterRef.current.slice(0, -1));
24399
24995
  return;
24400
24996
  }
24401
- if (isFilterKey3(seq)) setQuery(filterRef.current + seq);
24997
+ if (isFilterKey2(seq)) setQuery(filterRef.current + seq);
24402
24998
  return;
24403
24999
  }
24404
25000
  if (key.name === "escape") {
@@ -24418,7 +25014,7 @@ function MarketScreen({
24418
25014
  setQuery("");
24419
25015
  return;
24420
25016
  }
24421
- if (isFilterKey3(seq)) {
25017
+ if (isFilterKey2(seq)) {
24422
25018
  applyMode("filter");
24423
25019
  setQuery(seq);
24424
25020
  }
@@ -24865,7 +25461,7 @@ function ConnectScreen({ frame, onBack, onSkip, onExit, recovery, onConnected, e
24865
25461
  setQuery(filterRef.current.slice(0, -1));
24866
25462
  return;
24867
25463
  }
24868
- if (isFilterKey4(seq)) setQuery(filterRef.current + seq);
25464
+ if (isFilterKey3(seq)) setQuery(filterRef.current + seq);
24869
25465
  return;
24870
25466
  }
24871
25467
  if (key.name === "backspace") {
@@ -24877,7 +25473,7 @@ function ConnectScreen({ frame, onBack, onSkip, onExit, recovery, onConnected, e
24877
25473
  setQuery("");
24878
25474
  return;
24879
25475
  }
24880
- if (isFilterKey4(seq)) {
25476
+ if (isFilterKey3(seq)) {
24881
25477
  setFilterMode(true);
24882
25478
  setQuery(seq);
24883
25479
  }
@@ -25101,8 +25697,8 @@ import { TextAttributes as TextAttributes24 } from "@opentui/core";
25101
25697
  import { useKeyboard as useKeyboard22 } from "@opentui/react";
25102
25698
 
25103
25699
  // packages/cli/src/tui/usage-layout.ts
25104
- var DEFAULT_SYMBOLS5 = getSymbols("unicode");
25105
- function cells7(value, fallback = 0) {
25700
+ var DEFAULT_SYMBOLS6 = getSymbols("unicode");
25701
+ function cells8(value, fallback = 0) {
25106
25702
  const raw = typeof value === "number" && Number.isFinite(value) ? value : fallback;
25107
25703
  const truncated = Math.trunc(raw);
25108
25704
  return truncated > 0 ? truncated : 0;
@@ -25210,7 +25806,7 @@ function usageIcons(symbols) {
25210
25806
  // warning
25211
25807
  };
25212
25808
  }
25213
- function buildUsageReport(snapshot = {}, symbols = DEFAULT_SYMBOLS5) {
25809
+ function buildUsageReport(snapshot = {}, symbols = DEFAULT_SYMBOLS6) {
25214
25810
  const icon = usageIcons(symbols);
25215
25811
  const rows = [];
25216
25812
  const heading = (label2) => rows.push({ kind: "heading", label: label2, tone: "title" });
@@ -25285,8 +25881,8 @@ function buildUsageReport(snapshot = {}, symbols = DEFAULT_SYMBOLS5) {
25285
25881
  }
25286
25882
  return rows;
25287
25883
  }
25288
- function usageMeterBar(fraction, cellCount2, symbols = DEFAULT_SYMBOLS5) {
25289
- const width = cells7(cellCount2);
25884
+ function usageMeterBar(fraction, cellCount2, symbols = DEFAULT_SYMBOLS6) {
25885
+ const width = cells8(cellCount2);
25290
25886
  if (width <= 0) return "";
25291
25887
  const clamped = Number.isFinite(fraction) ? Math.max(0, Math.min(1, fraction)) : 0;
25292
25888
  const filled = Math.max(0, Math.min(width, Math.round(clamped * width)));
@@ -25305,8 +25901,8 @@ function borderChrome3(bordered) {
25305
25901
  return bordered ? { horizontal: 4, vertical: 2 } : { horizontal: 0, vertical: 0 };
25306
25902
  }
25307
25903
  function makePane4(width, height, chromeH, chromeV) {
25308
- const outerWidth = cells7(width);
25309
- const outerHeight = cells7(height);
25904
+ const outerWidth = cells8(width);
25905
+ const outerHeight = cells8(height);
25310
25906
  if (outerWidth <= chromeH || outerHeight <= chromeV) {
25311
25907
  return { width: 0, innerWidth: 0, height: 0, bodyRows: 0 };
25312
25908
  }
@@ -25326,7 +25922,7 @@ function computeKvLayout(innerWidth) {
25326
25922
  });
25327
25923
  }
25328
25924
  function computeMeterLayout(innerWidth) {
25329
- const width = cells7(innerWidth);
25925
+ const width = cells8(innerWidth);
25330
25926
  if (width <= 0) return { width: 0, barCells: 0, gap: 0, captionWidth: 0 };
25331
25927
  const barCells = width >= METER_MIN_ROOM ? Math.min(METER_MAX_CELLS, Math.floor(width * METER_WIDTH_SHARE)) : 0;
25332
25928
  const gap = barCells > 0 && width > barCells ? 1 : 0;
@@ -25340,11 +25936,11 @@ function computeUsageLayout({
25340
25936
  hostRows,
25341
25937
  hostPaddingX
25342
25938
  }) {
25343
- const terminalWidth = cells7(width);
25344
- const padding = hostPaddingX === void 0 ? 2 : cells7(hostPaddingX);
25345
- const chromeRows = hostRows === void 0 ? shellChromeRows(terminalWidth) : cells7(hostRows);
25939
+ const terminalWidth = cells8(width);
25940
+ const padding = hostPaddingX === void 0 ? 2 : cells8(hostPaddingX);
25941
+ const chromeRows = hostRows === void 0 ? shellChromeRows(terminalWidth) : cells8(hostRows);
25346
25942
  const contentWidth = Math.max(0, terminalWidth - padding * 2);
25347
- const bodyRows = Math.max(0, cells7(height) - chromeRows - cells7(headerRows));
25943
+ const bodyRows = Math.max(0, cells8(height) - chromeRows - cells8(headerRows));
25348
25944
  const bordered = bodyRows >= BORDERED_MIN_ROWS4 && contentWidth >= BORDERED_MIN_WIDTH3;
25349
25945
  const chrome = borderChrome3(bordered);
25350
25946
  const pane = makePane4(contentWidth, bodyRows, chrome.horizontal, chrome.vertical);
@@ -25359,7 +25955,7 @@ function computeUsageLayout({
25359
25955
  };
25360
25956
  }
25361
25957
  function clipUsageRows(rows, visible) {
25362
- const limit = cells7(visible);
25958
+ const limit = cells8(visible);
25363
25959
  if (limit <= 0) return [];
25364
25960
  if (rows.length <= limit) return [...rows];
25365
25961
  const kept = rows.slice(0, limit);
@@ -25824,10 +26420,10 @@ function createSessionCloseGate() {
25824
26420
 
25825
26421
  // packages/cli/src/tui/session-state.ts
25826
26422
  function upsertFinding(findings, finding) {
25827
- const exists = findings.some(
25828
- (item) => item.severity.toLowerCase() === finding.severity.toLowerCase() && item.title === finding.title
25829
- );
25830
- return exists ? findings : [...findings, finding];
26423
+ const matches = (item) => item.severity.toLowerCase() === finding.severity.toLowerCase() && item.title === finding.title;
26424
+ if (!findings.some(matches)) return [...findings, finding];
26425
+ if (!finding.impactAssessment) return findings;
26426
+ return findings.map((item) => matches(item) ? { ...item, impactAssessment: finding.impactAssessment } : item);
25831
26427
  }
25832
26428
  function parseSavedFinding(action) {
25833
26429
  const match = /^save_finding:\s*\[([^\]]+)\]\s+(.+)$/i.exec(action.trim());
@@ -26084,11 +26680,12 @@ function applySessionEvent(state, event) {
26084
26680
  if (event.type === "finding") {
26085
26681
  const running = next.stages.find((stage) => stage.status === "running") ?? next.stages.find((stage) => stage.id === "attack");
26086
26682
  const severity = event.data?.severity ?? "info";
26683
+ const impact = ImpactAssessmentSchema.safeParse(event.data?.impactAssessment);
26087
26684
  const title = cleanDisplayText(msg.replace(/^\[[\w]+\]\s*/g, "").trim() || "Finding from AI analysis", 200);
26088
26685
  if (running) {
26089
26686
  next.stages = updateStage(next.stages, running.id, (stage) => ({
26090
26687
  ...stage,
26091
- findings: upsertFinding(stage.findings, { severity, title })
26688
+ findings: upsertFinding(stage.findings, { severity, title, ...impact.success ? { impactAssessment: impact.data } : {} })
26092
26689
  }));
26093
26690
  }
26094
26691
  next.transcript.push(transcriptItem("finding", `[${severity}] ${title}`, { stage: running?.id, tone: severity === "critical" || severity === "high" ? "error" : severity === "medium" ? "warning" : "info" }));