0sec-cli 0.18.0 → 0.22.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 (329) hide show
  1. package/{0sec.js → 0.js} +90 -82
  2. package/LICENSE +1 -1
  3. package/README.md +62 -46
  4. package/chunks/adapt-loop-7I57LXXR.js +18 -0
  5. package/chunks/{adgraph-JLGA6RYI.js → adgraph-AUDQTBYA.js} +5 -5
  6. package/chunks/agent/skills/frameworks/entra-id.yaml +2 -2
  7. package/chunks/agent/skills/techniques/assumption-mining.yaml +2 -2
  8. package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +2 -2
  9. package/chunks/agent/skills/techniques/entra-attack-paths.yaml +1 -1
  10. package/chunks/agent/skills/techniques/kernel-weaponization.yaml +1 -1
  11. package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +2 -2
  12. package/chunks/agent/skills/techniques/npm-ecosystem.yaml +1 -1
  13. package/chunks/agent/skills/techniques/poc-verification.yaml +1 -1
  14. package/chunks/agent/skills/techniques/seedless-depth-review.yaml +20 -38
  15. package/chunks/{artifact-scraper-HQ7HLP6V.js → artifact-scraper-PYZ3RU3O.js} +6 -6
  16. package/chunks/{assumption-mining-5SNIVVDN.js → assumption-mining-MFLF43IR.js} +24 -26
  17. package/chunks/{chunk-7DQEV5QI.js → chunk-23DG5YKS.js} +4 -4
  18. package/chunks/{chunk-UR4ELX2Y.js → chunk-2GV4HQKE.js} +340 -703
  19. package/chunks/{chunk-P6WKNFWX.js → chunk-2OQOQ2FZ.js} +8 -8
  20. package/chunks/{chunk-5G3ZXFBW.js → chunk-2WNCI664.js} +3 -3
  21. package/chunks/{chunk-DW5UWPFY.js → chunk-4VGLO2YS.js} +6 -5
  22. package/chunks/{chunk-KLTNTE2Z.js → chunk-5IBCBQEH.js} +13 -14
  23. package/chunks/{chunk-N7BOUYEV.js → chunk-5MWAG3FT.js} +14 -14
  24. package/chunks/{chunk-OEFNRYI2.js → chunk-6GHSR47F.js} +3 -6
  25. package/chunks/chunk-6YNKRUMC.js +4474 -0
  26. package/chunks/{chunk-6L26OBWI.js → chunk-76KSBWOQ.js} +255 -35
  27. package/chunks/chunk-7DEHG7YT.js +2143 -0
  28. package/chunks/{chunk-AD7WXDH6.js → chunk-7UFUALR2.js} +288 -22
  29. package/chunks/{chunk-53G27VPS.js → chunk-AZ7L3HFD.js} +7 -2
  30. package/chunks/{chunk-TSK2AG6J.js → chunk-CAYANSH6.js} +173 -1757
  31. package/chunks/{chunk-SAFFWQW4.js → chunk-DKSCN2AB.js} +7 -7
  32. package/chunks/{chunk-2JCCA2JL.js → chunk-DM5C5L5D.js} +3 -3
  33. package/chunks/{chunk-RWONANDA.js → chunk-DQTNI3KY.js} +5 -5
  34. package/chunks/{chunk-5JI7L7KV.js → chunk-EGZGZFAH.js} +10036 -12938
  35. package/chunks/{chunk-6LKRLK2R.js → chunk-FHC2B7LN.js} +3 -3
  36. package/chunks/{chunk-MYVT64FN.js → chunk-GHWODZMR.js} +2 -2
  37. package/chunks/{chunk-2RMLOJVB.js → chunk-GVD6SJGH.js} +2 -2
  38. package/chunks/{chunk-SF4KZ4O3.js → chunk-HLFS6WV2.js} +2 -2
  39. package/chunks/chunk-HR2TU42B.js +1228 -0
  40. package/chunks/{chunk-BFRB6HB2.js → chunk-HUNAPTKV.js} +3 -3
  41. package/chunks/chunk-IO7R7WBM.js +114 -0
  42. package/chunks/{chunk-WEBMRWEG.js → chunk-IXT64DV5.js} +656 -1868
  43. package/chunks/{chunk-3MOLBTLS.js → chunk-K2PWUPUI.js} +2 -2
  44. package/chunks/{chunk-WXQ6BJ6A.js → chunk-LCRTAQN2.js} +7 -7
  45. package/chunks/{chunk-SVJEDVYK.js → chunk-LPTRPRZR.js} +5 -5
  46. package/chunks/{chunk-CMKXP5RR.js → chunk-LYUAM3TG.js} +3 -3
  47. package/chunks/{chunk-BVAZO4WA.js → chunk-MICHDTBK.js} +3 -3
  48. package/chunks/{chunk-UCYRA73C.js → chunk-OAYUPGF6.js} +4 -4
  49. package/chunks/{chunk-XM5NLHYU.js → chunk-OWLJYJ5O.js} +14 -14
  50. package/chunks/{chunk-BKZFDZ23.js → chunk-QCUFBVIZ.js} +3 -3
  51. package/chunks/chunk-RE5EZDG2.js +5523 -0
  52. package/chunks/{chunk-ASUR522M.js → chunk-RRD4XXPU.js} +9 -9
  53. package/chunks/{chunk-AHTBZC3E.js → chunk-RSIUX3RW.js} +4 -4
  54. package/chunks/{chunk-BZNEY2ZS.js → chunk-SJBCK2EI.js} +15268 -16053
  55. package/chunks/{chunk-IOL7D5YV.js → chunk-SQCBHFWN.js} +3 -3
  56. package/chunks/chunk-TH2LW437.js +7829 -0
  57. package/chunks/{chunk-WVTBZEQO.js → chunk-TM74SSHC.js} +8 -8
  58. package/chunks/{chunk-U5FLXGHT.js → chunk-TO35Y326.js} +13 -729
  59. package/chunks/chunk-TRH2PJSN.js +547 -0
  60. package/chunks/{chunk-YYRBQVFE.js → chunk-TZFIAMWZ.js} +70 -16
  61. package/chunks/chunk-UELXHK2Y.js +1950 -0
  62. package/chunks/{chunk-RJWOYEOG.js → chunk-UEX7PFSE.js} +5 -5
  63. package/chunks/{chunk-VQG4FT5D.js → chunk-UFHN6RIU.js} +2 -2
  64. package/chunks/{chunk-JQHOLLTD.js → chunk-UU7PQP6N.js} +9 -9
  65. package/chunks/{chunk-BFR2CDV5.js → chunk-UV5QWZGE.js} +283 -153
  66. package/chunks/{chunk-WU6AFRAZ.js → chunk-V36HVTUL.js} +12 -12
  67. package/chunks/{chunk-IR537GON.js → chunk-VCSFCHAJ.js} +2 -2
  68. package/chunks/{chunk-YLMN3N25.js → chunk-VIT5ALXF.js} +3 -3
  69. package/chunks/{chunk-BATRQBOR.js → chunk-VMRRNRMR.js} +41 -41
  70. package/chunks/{chunk-72CISA2D.js → chunk-VNRY6AWF.js} +89 -41
  71. package/chunks/chunk-W6UWZFKL.js +298 -0
  72. package/chunks/{chunk-3KPWWJCI.js → chunk-XFCTUKXR.js} +88 -88
  73. package/chunks/{chunk-GMT2AZKM.js → chunk-YIQSGNAA.js} +897 -130
  74. package/chunks/codex-models-7TLJSY3L.js +17 -0
  75. package/chunks/{commands-TBC2F5CE.js → commands-NEI7L3QA.js} +2836 -1424
  76. package/chunks/corpus-v1.json +2 -2
  77. package/chunks/data/appsec-archetypes.json +2 -2
  78. package/chunks/data/chromium-archetypes.json +1 -1
  79. package/chunks/data/freebsd-archetypes.json +1 -1
  80. package/chunks/data/kernel-archetypes.json +2 -2
  81. package/chunks/db-5AP3JB4W.js +16 -0
  82. package/chunks/{disclose-EKTWSCGW.js → disclose-LDNKAVRH.js} +13 -11
  83. package/chunks/{dist-4YICS2J2.js → dist-3FNZIBB4.js} +394 -404
  84. package/chunks/{dist-4MAW5X6L.js → dist-5YHYNLI3.js} +6 -6
  85. package/chunks/{dist-FMGSR3DW.js → dist-DD4H6HMQ.js} +13 -5
  86. package/chunks/dist-KEULE5IQ.js +21914 -0
  87. package/chunks/dist-XZB53PS5.js +53 -0
  88. package/chunks/eval-runner-43BO2C4T.js +26 -0
  89. package/chunks/example-manifest.json +2 -2
  90. package/chunks/{exploit-agent-45YQOHPJ.js → exploit-agent-N4A5ELBK.js} +4 -4
  91. package/chunks/{exploit-autoclimb-UZGEMGYT.js → exploit-autoclimb-N7P6KIF5.js} +6 -6
  92. package/chunks/{exploit-climb-SG23KB2G.js → exploit-climb-WNEJUB5W.js} +12 -12
  93. package/chunks/fix-Z452M4EC.js +26 -0
  94. package/chunks/{github-issues-MJ6OYOOU.js → github-issues-IGTTWM7V.js} +7 -7
  95. package/chunks/harness-QJJJVSG4.js +22 -0
  96. package/chunks/http-conformance-U5F6GKYG.js +11 -0
  97. package/chunks/http-sender-I5XFFY35.js +10 -0
  98. package/chunks/hunt-scan-K6D2V3PX.js +36 -0
  99. package/chunks/{identity-6ZAIIWOR.js → identity-62SVRW4H.js} +5 -5
  100. package/chunks/{kernel-primitive-7U6CWHXD.js → kernel-primitive-TKUACPKD.js} +6 -6
  101. package/chunks/{kernel-vm-runner-3JAU4O6J.js → kernel-vm-runner-RAAO2PGT.js} +6 -6
  102. package/chunks/memsafety-scan-FCPAXIZE.js +16 -0
  103. package/chunks/{native-loop-RJCJPOUS.js → native-loop-2ZRJENZ3.js} +17 -18
  104. package/chunks/{npm-detectors-KB5Y5ZFX.js → npm-detectors-Z2ZIQCN4.js} +6 -6
  105. package/chunks/npm-dynamic-discovery-5J7FT3XM.js +13 -0
  106. package/chunks/orchestrate-2GWGNTBF.js +58 -0
  107. package/chunks/{pre-recon-cve-66EB6G4M.js → pre-recon-cve-X2K2P5YQ.js} +4 -4
  108. package/chunks/prepare-KYHGFWCJ.js +13 -0
  109. package/chunks/process-N245QIQG.js +12 -0
  110. package/chunks/{run-D56MPDKY.js → run-U3XU4CTC.js} +11507 -13632
  111. package/chunks/{runtime-G7YWIO3B.js → runtime-G75TEWQY.js} +10 -11
  112. package/chunks/runtime-XFWJTBUO.js +12 -0
  113. package/chunks/{scan-stream-FHI2FYZE.js → scan-stream-BMOCPKQX.js} +7 -7
  114. package/chunks/scope-WXI46UHJ.js +21 -0
  115. package/chunks/{session-store-GZ4A4KYT.js → session-store-27L3ZU73.js} +6 -6
  116. package/chunks/source-files-REHOM44I.js +12 -0
  117. package/chunks/{specdrift-WCLH6TTQ.js → specdrift-AFS54WEJ.js} +5 -5
  118. package/chunks/token-KRWP5JYA.js +72 -0
  119. package/chunks/token-util-DWTL33S3.js +8 -0
  120. package/chunks/variant-candidates-YWZORZMK.js +13 -0
  121. package/chunks/{web-recon-prepass-JJGPEOLE.js → web-recon-prepass-YVMFXCIK.js} +9 -9
  122. package/cli-path-traversal-fixture.js +352 -0
  123. package/dashboard/assets/bot-Bg1Tp9_d.js +1 -0
  124. package/dashboard/assets/dist-B_dDCPbu.js +1 -0
  125. package/dashboard/assets/findings-page-mayGhNx6.js +5 -0
  126. package/dashboard/assets/format--susmHX7.js +1 -0
  127. package/dashboard/assets/input-TuVPR3Zl.js +1 -0
  128. package/dashboard/assets/jsx-runtime-MGseXjj5.js +3 -0
  129. package/dashboard/assets/live-page-HWWHX99U.js +1 -0
  130. package/dashboard/assets/meta-tile-ckHo-w7k.js +1 -0
  131. package/dashboard/assets/operations-BxZ0OoXO.js +10 -0
  132. package/dashboard/assets/operations-CMFVrXEe.css +2 -0
  133. package/dashboard/assets/operations-app-D3d35rgo.js +46 -0
  134. package/dashboard/assets/overview-page-W_4IteEr.js +1 -0
  135. package/dashboard/assets/page-header-Bw9AJgBV.js +1 -0
  136. package/dashboard/assets/scans-page-CgzVXHnn.js +1 -0
  137. package/dashboard/assets/siren-KQj8QAnJ.js +1 -0
  138. package/dashboard/assets/table-8EDklulN.js +1 -0
  139. package/dashboard/assets/tabs-CFHPOwg8.js +1 -0
  140. package/dashboard/index.html +4 -5
  141. package/node_modules/node-addon-api/LICENSE.md +9 -0
  142. package/node_modules/node-addon-api/README.md +95 -0
  143. package/node_modules/node-addon-api/common.gypi +21 -0
  144. package/node_modules/node-addon-api/except.gypi +25 -0
  145. package/node_modules/node-addon-api/index.js +14 -0
  146. package/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  147. package/node_modules/node-addon-api/napi-inl.h +7250 -0
  148. package/node_modules/node-addon-api/napi.h +3463 -0
  149. package/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  150. package/node_modules/node-addon-api/node_api.gyp +9 -0
  151. package/node_modules/node-addon-api/noexcept.gypi +26 -0
  152. package/node_modules/node-addon-api/nothing.c +0 -0
  153. package/node_modules/node-addon-api/package-support.json +21 -0
  154. package/node_modules/node-addon-api/package.json +481 -0
  155. package/node_modules/node-addon-api/tools/README.md +73 -0
  156. package/node_modules/node-addon-api/tools/check-napi.js +99 -0
  157. package/node_modules/node-addon-api/tools/clang-format.js +71 -0
  158. package/node_modules/node-addon-api/tools/conversion.js +301 -0
  159. package/node_modules/node-gyp-build/LICENSE +21 -0
  160. package/node_modules/node-gyp-build/README.md +58 -0
  161. package/node_modules/node-gyp-build/SECURITY.md +5 -0
  162. package/node_modules/node-gyp-build/bin.js +84 -0
  163. package/node_modules/node-gyp-build/build-test.js +19 -0
  164. package/node_modules/node-gyp-build/index.js +6 -0
  165. package/node_modules/node-gyp-build/node-gyp-build.js +207 -0
  166. package/node_modules/node-gyp-build/optional.js +7 -0
  167. package/node_modules/node-gyp-build/package.json +43 -0
  168. package/node_modules/tree-sitter/LICENSE +21 -0
  169. package/node_modules/tree-sitter/README.md +90 -0
  170. package/node_modules/tree-sitter/binding.gyp +76 -0
  171. package/node_modules/tree-sitter/index.js +895 -0
  172. package/node_modules/tree-sitter/package.json +62 -0
  173. package/node_modules/tree-sitter/prebuilds/darwin-arm64/tree-sitter.node +0 -0
  174. package/node_modules/tree-sitter/prebuilds/darwin-x64/tree-sitter.node +0 -0
  175. package/node_modules/tree-sitter/prebuilds/linux-x64/tree-sitter.node +0 -0
  176. package/node_modules/tree-sitter/prebuilds/win32-x64/tree-sitter.node +0 -0
  177. package/node_modules/tree-sitter/src/addon_data.h +47 -0
  178. package/node_modules/tree-sitter/src/binding.cc +35 -0
  179. package/node_modules/tree-sitter/src/conversions.cc +140 -0
  180. package/node_modules/tree-sitter/src/conversions.h +22 -0
  181. package/node_modules/tree-sitter/src/language.cc +106 -0
  182. package/node_modules/tree-sitter/src/language.h +17 -0
  183. package/node_modules/tree-sitter/src/logger.cc +70 -0
  184. package/node_modules/tree-sitter/src/logger.h +19 -0
  185. package/node_modules/tree-sitter/src/lookaheaditerator.cc +122 -0
  186. package/node_modules/tree-sitter/src/lookaheaditerator.h +33 -0
  187. package/node_modules/tree-sitter/src/node.cc +1056 -0
  188. package/node_modules/tree-sitter/src/node.h +30 -0
  189. package/node_modules/tree-sitter/src/parser.cc +298 -0
  190. package/node_modules/tree-sitter/src/parser.h +35 -0
  191. package/node_modules/tree-sitter/src/query.cc +383 -0
  192. package/node_modules/tree-sitter/src/query.h +39 -0
  193. package/node_modules/tree-sitter/src/tree.cc +307 -0
  194. package/node_modules/tree-sitter/src/tree.h +45 -0
  195. package/node_modules/tree-sitter/src/tree_cursor.cc +213 -0
  196. package/node_modules/tree-sitter/src/tree_cursor.h +52 -0
  197. package/node_modules/tree-sitter/tree-sitter.d.ts +211 -0
  198. package/node_modules/tree-sitter/vendor/tree-sitter/LICENSE +21 -0
  199. package/node_modules/tree-sitter/vendor/tree-sitter/README.md +21 -0
  200. package/node_modules/tree-sitter/vendor/tree-sitter/lib/README.md +6 -0
  201. package/node_modules/tree-sitter/vendor/tree-sitter/lib/include/tree_sitter/api.h +1266 -0
  202. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.c +48 -0
  203. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.h +41 -0
  204. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/array.h +290 -0
  205. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/atomic.h +68 -0
  206. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/clock.h +146 -0
  207. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/error_costs.h +11 -0
  208. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.c +501 -0
  209. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.h +36 -0
  210. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/host.h +21 -0
  211. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.c +221 -0
  212. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.h +299 -0
  213. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/length.h +52 -0
  214. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.c +419 -0
  215. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.h +49 -0
  216. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lib.c +14 -0
  217. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/node.c +774 -0
  218. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.c +2151 -0
  219. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.h +230 -0
  220. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/point.h +62 -0
  221. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/query.c +4134 -0
  222. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reduce_action.h +34 -0
  223. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reusable_node.h +95 -0
  224. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.c +899 -0
  225. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.h +133 -0
  226. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.c +1060 -0
  227. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.h +382 -0
  228. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.c +165 -0
  229. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.h +31 -0
  230. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.c +714 -0
  231. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.h +48 -0
  232. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ICU_SHA +1 -0
  233. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/LICENSE +414 -0
  234. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/README.md +29 -0
  235. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ptypes.h +1 -0
  236. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/umachine.h +448 -0
  237. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/urename.h +1 -0
  238. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf.h +1 -0
  239. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf16.h +733 -0
  240. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf8.h +881 -0
  241. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode.h +50 -0
  242. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib-symbols.txt +23 -0
  243. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib.c +109 -0
  244. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/wasm-stdlib.h +1294 -0
  245. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.c +1823 -0
  246. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.h +31 -0
  247. package/node_modules/tree-sitter/vendor/tree-sitter/test/fixtures/grammars/.gitkeep +0 -0
  248. package/node_modules/tree-sitter-c/LICENSE +21 -0
  249. package/node_modules/tree-sitter-c/README.md +18 -0
  250. package/node_modules/tree-sitter-c/binding.gyp +20 -0
  251. package/node_modules/tree-sitter-c/bindings/node/binding.cc +20 -0
  252. package/node_modules/tree-sitter-c/bindings/node/index.d.ts +28 -0
  253. package/node_modules/tree-sitter-c/bindings/node/index.js +7 -0
  254. package/node_modules/tree-sitter-c/grammar.js +1463 -0
  255. package/node_modules/tree-sitter-c/package.json +108 -0
  256. package/node_modules/tree-sitter-c/prebuilds/darwin-arm64/tree-sitter-c.node +0 -0
  257. package/node_modules/tree-sitter-c/prebuilds/darwin-x64/tree-sitter-c.node +0 -0
  258. package/node_modules/tree-sitter-c/prebuilds/linux-x64/tree-sitter-c.node +0 -0
  259. package/node_modules/tree-sitter-c/prebuilds/win32-x64/tree-sitter-c.node +0 -0
  260. package/node_modules/tree-sitter-c/queries/highlights.scm +81 -0
  261. package/node_modules/tree-sitter-c/queries/tags.scm +9 -0
  262. package/node_modules/tree-sitter-c/src/grammar.json +9682 -0
  263. package/node_modules/tree-sitter-c/src/node-types.json +4556 -0
  264. package/node_modules/tree-sitter-c/src/parser.c +113852 -0
  265. package/node_modules/tree-sitter-c/src/tree_sitter/alloc.h +54 -0
  266. package/node_modules/tree-sitter-c/src/tree_sitter/array.h +290 -0
  267. package/node_modules/tree-sitter-c/src/tree_sitter/parser.h +265 -0
  268. package/package.json +20 -13
  269. package/vendor/tree-sitter-0.21.1-node24.json +16 -0
  270. package/vendor/tree-sitter-0.21.1-node24.tgz +0 -0
  271. package/chunks/adapt-loop-SMH6V4PD.js +0 -18
  272. package/chunks/appsec-catalog-CBWHGTEL.js +0 -24
  273. package/chunks/chunk-242TMK6G.js +0 -110
  274. package/chunks/chunk-57ZENEX2.js +0 -169
  275. package/chunks/chunk-ADOLI6DT.js +0 -102
  276. package/chunks/chunk-ATATQACO.js +0 -471
  277. package/chunks/chunk-C2WXWFBB.js +0 -1070
  278. package/chunks/chunk-F3WBKITT.js +0 -687
  279. package/chunks/chunk-H2FFLZNK.js +0 -3
  280. package/chunks/chunk-LP3HHYQU.js +0 -245
  281. package/chunks/chunk-QI233I24.js +0 -333
  282. package/chunks/chunk-RRMJC3ZE.js +0 -105
  283. package/chunks/chunk-Z5FA2XOX.js +0 -2798
  284. package/chunks/cost-ledger-NU63MYZM.js +0 -13
  285. package/chunks/db-KFWOAUUB.js +0 -16
  286. package/chunks/eval-runner-7ZF472KV.js +0 -27
  287. package/chunks/fix-IG7LYXH3.js +0 -12
  288. package/chunks/harness-7ODOLOWU.js +0 -22
  289. package/chunks/http-conformance-DU66MZIU.js +0 -11
  290. package/chunks/http-sender-GWH2IYEA.js +0 -10
  291. package/chunks/hunt-scan-MMKUOETU.js +0 -38
  292. package/chunks/memsafety-scan-J7SECV5W.js +0 -16
  293. package/chunks/npm-dynamic-discovery-AHROOZDB.js +0 -13
  294. package/chunks/orchestrate-OC2VZN2X.js +0 -62
  295. package/chunks/pipeline-BZK5BLJR.js +0 -14
  296. package/chunks/prepare-MYY743TK.js +0 -13
  297. package/chunks/process-LQRCS5OY.js +0 -13
  298. package/chunks/replay-runner-45G3VU7X.js +0 -39
  299. package/chunks/runtime-J7PLXZNM.js +0 -12
  300. package/chunks/scope-BI7BF4ZY.js +0 -18
  301. package/chunks/source-files-PWRQR6LY.js +0 -12
  302. package/chunks/variant-candidates-YERCYMPD.js +0 -13
  303. package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
  304. package/dashboard/assets/bot-yILPnRgD.js +0 -1
  305. package/dashboard/assets/chevron-down-BeDJ-Vka.js +0 -1
  306. package/dashboard/assets/circle-alert-BEnMBMT-.js +0 -1
  307. package/dashboard/assets/client-DRYsuOGl.js +0 -9
  308. package/dashboard/assets/copy-Bi5vzoF9.js +0 -1
  309. package/dashboard/assets/desktop-CXTQonNm.js +0 -32
  310. package/dashboard/assets/desktop-NOekk4QS.css +0 -1
  311. package/dashboard/assets/dist-CmX-h7a4.js +0 -1
  312. package/dashboard/assets/dist-DAwYQmf_.js +0 -45
  313. package/dashboard/assets/findings-page-CACW9nw2.js +0 -5
  314. package/dashboard/assets/format-PoISqsES.js +0 -1
  315. package/dashboard/assets/jsx-runtime-C7oxC63R.js +0 -1
  316. package/dashboard/assets/live-page-DrgQqQK5.js +0 -1
  317. package/dashboard/assets/meta-tile-CcskIV_o.js +0 -1
  318. package/dashboard/assets/operations-BKE8T-vY.css +0 -2
  319. package/dashboard/assets/operations-D8nUP5_m.js +0 -4
  320. package/dashboard/assets/operations-app-CQQhG54n.js +0 -2
  321. package/dashboard/assets/overview-page-DTGS8dPo.js +0 -1
  322. package/dashboard/assets/page-header-MFVvEtZW.js +0 -1
  323. package/dashboard/assets/play-Dwo-9xt6.js +0 -1
  324. package/dashboard/assets/scans-page-ChVtq8Us.js +0 -1
  325. package/dashboard/assets/search-CiooTLck.js +0 -1
  326. package/dashboard/assets/siren-CCBwTSuk.js +0 -1
  327. package/dashboard/assets/table-BYS-nIVA.js +0 -1
  328. package/dashboard/assets/tabs-DivxbhQy.js +0 -1
  329. package/dashboard/desktop.html +0 -21
@@ -1,68 +1,45 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire as __0secCreateRequire } from "node:module";
3
- const require = __0secCreateRequire(import.meta.url);
2
+ import { createRequire as __0CreateRequire } from "node:module";
3
+ const require = __0CreateRequire(import.meta.url);
4
4
  import {
5
5
  isValidSessionId,
6
6
  listSessions,
7
7
  loadSession
8
- } from "./chunk-BVAZO4WA.js";
8
+ } from "./chunk-MICHDTBK.js";
9
9
  import {
10
- consolePresentationOutput,
11
10
  getSettings,
12
11
  maybeLoadCodexAuth
13
- } from "./chunk-GMT2AZKM.js";
12
+ } from "./chunk-YIQSGNAA.js";
14
13
  import {
15
- captureObservation,
14
+ createConsoleJevRuntime,
16
15
  createConsoleSession,
17
- createEvolvedFinder,
18
16
  inspectLensRegistry,
19
17
  lastGreen,
20
18
  loadLedger,
21
19
  loadManifest,
22
20
  makeFinderLensProbe,
23
21
  retireArchetype,
24
- runLensSynthesisLoop
25
- } from "./chunk-5JI7L7KV.js";
22
+ runLensSynthesisLoop,
23
+ toToolContextJevRuntime
24
+ } from "./chunk-EGZGZFAH.js";
26
25
  import {
27
26
  source_default
28
- } from "./chunk-SF4KZ4O3.js";
29
- import {
30
- stampDeploymentContext
31
- } from "./chunk-BFR2CDV5.js";
27
+ } from "./chunk-HLFS6WV2.js";
32
28
  import {
33
29
  harvestMissesFromLedgerEntry,
34
- loadEvolutionConfigFile,
35
30
  mergeHarvestedMisses
36
- } from "./chunk-BZNEY2ZS.js";
31
+ } from "./chunk-SJBCK2EI.js";
32
+ import {
33
+ eventBus
34
+ } from "./chunk-RE5EZDG2.js";
37
35
  import {
38
36
  listOsecRunDatabasePaths,
39
37
  osecDB,
40
- resolveOsecDbPath,
41
- resolveOsecRunStorage,
42
- writeOsecRunReport
43
- } from "./chunk-72CISA2D.js";
44
- import {
45
- loadAppsecFinderLenses
46
- } from "./chunk-QI233I24.js";
47
- import {
48
- ScanCostLedger
49
- } from "./chunk-242TMK6G.js";
38
+ resolveOsecDbPath
39
+ } from "./chunk-VNRY6AWF.js";
50
40
  import {
51
41
  redactSensitiveHeaders
52
- } from "./chunk-WEBMRWEG.js";
53
- import {
54
- CloudAuthMissingError,
55
- CloudClient,
56
- CloudError,
57
- CloudForbiddenError,
58
- CloudNetworkError,
59
- CloudUnauthorizedError,
60
- DEFAULT_CLOUD_HOST,
61
- loadCloudCredentials
62
- } from "./chunk-UR4ELX2Y.js";
63
- import {
64
- eventBus
65
- } from "./chunk-ADOLI6DT.js";
42
+ } from "./chunk-UELXHK2Y.js";
66
43
  import {
67
44
  SEVERITY_RANK,
68
45
  VERSION,
@@ -71,14 +48,13 @@ import {
71
48
  createScanReportDocument,
72
49
  findingSchema,
73
50
  formatZodError,
74
- homeStateDir,
75
51
  severityRank
76
- } from "./chunk-6L26OBWI.js";
52
+ } from "./chunk-76KSBWOQ.js";
77
53
 
78
54
  // packages/cli/src/utils.ts
79
55
  import { gzipSync } from "zlib";
80
56
  async function getRuntimeAvailability() {
81
- const { detectAvailableRuntimes, LlmApiRuntime } = await import("./dist-4YICS2J2.js");
57
+ const { detectAvailableRuntimes, LlmApiRuntime } = await import("./dist-3FNZIBB4.js");
82
58
  const apiRuntimeDiagnostics = new LlmApiRuntime({ type: "api", timeout: 5e3 }).getConfigurationDiagnostics();
83
59
  const hasApiKey = apiRuntimeDiagnostics.valid;
84
60
  const availableRuntimes = [...await detectAvailableRuntimes()];
@@ -110,1094 +86,14 @@ async function checkRuntimeAvailability(runtime) {
110
86
  } else {
111
87
  console.log(source_default.yellow(" Warning: No API key or local agent runtime detected. AI analysis will be skipped."));
112
88
  }
113
- console.log(source_default.gray(" Provider credentials: 0SEC_CHATGPT_ACCESS_TOKEN | 0SEC_CHATGPT_OAUTH_REFRESH_TOKEN, OPENROUTER_API_KEY, ANTHROPIC_API_KEY, AZURE_OPENAI_API_KEY, OPENAI_API_KEY"));
89
+ console.log(source_default.gray(" Provider credentials: ZERO_CHATGPT_ACCESS_TOKEN | ZERO_CHATGPT_OAUTH_REFRESH_TOKEN, OPENROUTER_API_KEY, ANTHROPIC_API_KEY, AZURE_OPENAI_API_KEY, OPENAI_API_KEY"));
114
90
  console.log("");
115
91
  }
116
92
  function buildShareUrl(report) {
117
93
  const json = JSON.stringify(report);
118
94
  const compressed = gzipSync(Buffer.from(json, "utf-8"));
119
95
  const b64 = compressed.toString("base64url");
120
- return `https://0sec.ai/r#${b64}`;
121
- }
122
-
123
- // packages/cli/src/commands/hunt.ts
124
- import { readFileSync, writeFileSync } from "node:fs";
125
- import { resolve } from "node:path";
126
- function leadToCandidateFinding(finding, bugClass, seedRef, candidatePath) {
127
- const evidence = finding.evidence ?? {};
128
- const provenance = `Variant-hunt LEAD (bug class: ${bugClass}; seed: ${seedRef}). Surfaced by the recency hunt and gated by the adversarial skeptic \u2014 a HYPOTHESIS, not a confirmed bug. Verify the real sink + upstream-fix status (novelty) before any disclosure.`;
129
- if (candidatePath) stampDeploymentContext(finding, candidatePath);
130
- return {
131
- ...finding,
132
- // LEADS are never confirmed/sendable: force candidate status so the cloud
133
- // ingests them as verify candidates, never as confirmed findings.
134
- status: "discovered",
135
- templateId: "recency-hunt-lead",
136
- evidence: {
137
- request: evidence.request ?? "",
138
- response: evidence.response ?? "",
139
- analysis: evidence.analysis ? `${evidence.analysis}
140
-
141
- ${provenance}` : provenance
142
- }
143
- };
144
- }
145
- function parsePositive(flag, raw, dflt) {
146
- if (raw === void 0) return dflt;
147
- const n = parseInt(raw, 10);
148
- if (!Number.isFinite(n) || n <= 0) throw new Error(`invalid ${flag} '${raw}' (expected positive integer)`);
149
- return n;
150
- }
151
- var IMPACT_CEILINGS = ["dos-only", "info-leak", "oob-write", "uaf-control"];
152
- function parseCeiling(raw) {
153
- const v = raw.trim();
154
- if (!IMPACT_CEILINGS.includes(v)) {
155
- throw new Error(`invalid --prove-min-ceiling '${raw}' (expected one of: ${IMPACT_CEILINGS.join(", ")})`);
156
- }
157
- return v;
158
- }
159
- function parseNonNegative(flag, raw, dflt) {
160
- if (raw === void 0) return dflt;
161
- const n = parseInt(raw, 10);
162
- if (!Number.isFinite(n) || n < 0) throw new Error(`invalid ${flag} '${raw}' (expected non-negative integer)`);
163
- return n;
164
- }
165
- function parseEnvBestOfN(raw) {
166
- if (raw === void 0 || raw.trim() === "") return void 0;
167
- const n = Number.parseInt(raw, 10);
168
- return Number.isFinite(n) && n > 1 ? n : void 0;
169
- }
170
- function parseEnvPositiveInt(raw) {
171
- if (raw === void 0 || raw.trim() === "") return void 0;
172
- const n = Number.parseInt(raw, 10);
173
- return Number.isFinite(n) && n > 0 ? n : void 0;
174
- }
175
- async function runHunt(opts) {
176
- const {
177
- generateVariantCandidates,
178
- runHuntScan,
179
- makeSkepticVerifier,
180
- loadKnownNegativesFromEnv,
181
- buildInvariantHuntContext,
182
- buildGraphSliceHuntContext,
183
- localMirrors,
184
- syncLoreMirror,
185
- makeLloreJudge,
186
- makeHuntProveStage,
187
- prepare,
188
- getCloudSinkConfig,
189
- postFinding
190
- } = await import("./dist-4YICS2J2.js");
191
- const log = opts.log ?? (() => {
192
- });
193
- const runtime = opts.runtime ?? "api";
194
- const seedDiff = readFileSync(resolve(opts.seedPath), "utf8");
195
- const prepared = await prepare(opts.sourceRoot, "source-code", { ...opts.timeoutMs ? { timeout: opts.timeoutMs } : {} }, (e) => {
196
- if (e.message) log(`[hunt:source] ${e.message}`);
197
- });
198
- const sourceRoot = resolve(prepared.resolvedTarget);
199
- const noveltyRoot = opts.novelty?.rootDir ?? process.env["0SEC_LORE_MIRROR_ROOT"] ?? "/root/lore-mirror";
200
- const noveltyLists = opts.novelty?.lists ?? (process.env["0SEC_LORE_LISTS"] ?? "linux-media").split(",").map((s) => s.trim()).filter(Boolean);
201
- const noveltyRecentEpochs = opts.novelty?.recentEpochs ?? 1;
202
- const noveltyWarnings = [];
203
- const sinkCfg = getCloudSinkConfig();
204
- const savedCloudSink = process.env["0SEC_CLOUD_SINK"];
205
- if (sinkCfg) delete process.env["0SEC_CLOUD_SINK"];
206
- try {
207
- let noveltyMirrors = [];
208
- if (opts.novelty && noveltyLists.length > 0) {
209
- try {
210
- noveltyMirrors = opts.novelty.sync ? await syncLoreMirror({
211
- rootDir: noveltyRoot,
212
- lists: noveltyLists,
213
- recentEpochs: noveltyRecentEpochs,
214
- log
215
- }) : localMirrors(noveltyRoot, noveltyLists);
216
- } catch (err) {
217
- const reason = err instanceof Error ? err.message : String(err);
218
- noveltyWarnings.push(`hunt: novelty sync failed: ${reason.slice(0, 160)}`);
219
- log(`[hunt] ${noveltyWarnings[noveltyWarnings.length - 1]}`);
220
- }
221
- }
222
- if (opts.novelty && noveltyMirrors.length === 0) {
223
- const message = `novelty requested but no lore mirrors found under ${noveltyRoot} for ${noveltyLists.join(",") || "(no lists)"}`;
224
- return {
225
- exitCode: 3,
226
- result: {
227
- mode: "hunt",
228
- seed: opts.ref ?? opts.seedPath,
229
- candidates: 0,
230
- novelty: { enabled: true, required: true, mirrors: [] },
231
- warnings: [...noveltyWarnings, `hunt: ${message}; aborting fail-closed`],
232
- note: "Discovery did not run because requested novelty evidence was unavailable."
233
- }
234
- };
235
- }
236
- const skipCandidates = opts.skipCandidates ?? 0;
237
- const maxCandidates = opts.maxCandidates ?? 40;
238
- const reachableOnly = opts.reachableOnly ?? process.env.HUNT_REACHABLE_ONLY === "1";
239
- const reachablePrefer = opts.reachablePrefer ?? (opts.methodology ? true : process.env.HUNT_REACHABLE_PREFER === "1");
240
- let invariantCtx = null;
241
- const invariantWarnings = [];
242
- if (opts.invariant) {
243
- try {
244
- invariantCtx = await buildInvariantHuntContext({ sourceRoot, seedDiff, runtime, log });
245
- if (!invariantCtx) {
246
- invariantWarnings.push("hunt: --invariant set but no subsystem scope/files derivable from the seed \u2014 continuing without invariant context");
247
- log(`[hunt] ${invariantWarnings[invariantWarnings.length - 1]}`);
248
- }
249
- } catch (err) {
250
- const reason = err instanceof Error ? err.message : String(err);
251
- invariantWarnings.push(`hunt: invariant-model stage failed, continuing without it: ${reason.slice(0, 160)}`);
252
- log(`[hunt] ${invariantWarnings[invariantWarnings.length - 1]}`);
253
- }
254
- }
255
- let graphSliceCtx = null;
256
- const graphSliceWarnings = [];
257
- if (opts.graphSlice) {
258
- try {
259
- graphSliceCtx = buildGraphSliceHuntContext({
260
- sourceRoot,
261
- seedDiff,
262
- ...opts.cpgPath ? { cpgPath: opts.cpgPath } : {},
263
- log,
264
- ...opts.opsHarvestSourceFiles !== void 0 ? { opsHarvestSourceFiles: opts.opsHarvestSourceFiles } : {},
265
- ...opts.graphSliceHops !== void 0 ? { hops: opts.graphSliceHops } : {}
266
- });
267
- if (!graphSliceCtx) {
268
- graphSliceWarnings.push("hunt: --graph-slice set but no CPG/scope/slice derivable \u2014 continuing with the flat-text finder");
269
- log(`[hunt] ${graphSliceWarnings[graphSliceWarnings.length - 1]}`);
270
- }
271
- } catch (err) {
272
- const reason = err instanceof Error ? err.message : String(err);
273
- graphSliceWarnings.push(`hunt: graph-slice stage failed, continuing without it: ${reason.slice(0, 160)}`);
274
- log(`[hunt] ${graphSliceWarnings[graphSliceWarnings.length - 1]}`);
275
- }
276
- }
277
- const plan = await generateVariantCandidates({
278
- sourceRoot,
279
- fix: { diff: seedDiff, reference: opts.ref ?? opts.seedPath },
280
- runtime,
281
- maxCandidates: skipCandidates + maxCandidates,
282
- ...opts.models ? { models: opts.models } : {},
283
- ...reachableOnly ? { reachableOnly } : {},
284
- ...reachablePrefer ? { reachablePrefer } : {},
285
- log
286
- });
287
- const selectedCandidates = plan.candidates.slice(skipCandidates, skipCandidates + maxCandidates);
288
- if (selectedCandidates.length === 0) {
289
- return {
290
- exitCode: 2,
291
- result: {
292
- mode: "hunt",
293
- seed: opts.ref ?? opts.seedPath,
294
- bug_class: plan.brief.bugClass,
295
- grep_patterns: plan.grepPatterns,
296
- candidates: 0,
297
- skipped_candidates: Math.min(skipCandidates, plan.candidates.length),
298
- warnings: [...noveltyWarnings, ...plan.warnings],
299
- note: plan.candidates.length === 0 ? "no candidate sites generated \u2014 seed too narrow or surface already clean" : "no candidate sites left after --skip-candidates"
300
- }
301
- };
302
- }
303
- const candidates = selectedCandidates.map((c) => ({ ...c, path: `${sourceRoot}/${c.path}` }));
304
- const attemptsPerCandidate = opts.attemptsPerCandidate ?? parseEnvBestOfN(process.env.HUNT_BEST_OF_N) ?? (opts.methodology ? 4 : void 0);
305
- const judgeTopK = opts.judgeTopK ?? parseEnvPositiveInt(process.env.HUNT_JUDGE_TOP_K) ?? (opts.methodology ? 2 : void 0);
306
- const judgeModel = opts.judgeModel ?? process.env.HUNT_JUDGE_MODEL;
307
- const baseBrief = opts.methodology ? {
308
- ...plan.brief,
309
- pattern: `${plan.brief.pattern}
310
-
311
- METHODOLOGY LENSES: map the full object lifecycle across handlers, callbacks, error/teardown paths and concurrent sessions; trace buffer/page provenance across zero-copy and in-place subsystem boundaries; look for a fix applied to one sibling path but bypassed by another. Refute capability, configuration and state-machine reachability before claiming impact. Treat source reasoning as a hypothesis until a sanitizer-backed reproducer proves it.`
312
- } : plan.brief;
313
- let huntPattern = baseBrief.pattern;
314
- if (invariantCtx) huntPattern = `${huntPattern}
315
-
316
- ${invariantCtx.promptBlock}`;
317
- if (graphSliceCtx) huntPattern = `${huntPattern}
318
-
319
- ${graphSliceCtx.promptBlock}`;
320
- const huntBrief = huntPattern === baseBrief.pattern ? baseBrief : { ...baseBrief, pattern: huntPattern };
321
- const res = await runHuntScan({
322
- sourceRoot,
323
- candidates,
324
- brief: huntBrief,
325
- runtime,
326
- concurrency: opts.concurrency ?? 4,
327
- ...opts.models ? { models: opts.models } : {},
328
- ...attemptsPerCandidate ? { attemptsPerCandidate } : {},
329
- ...judgeTopK ? { judgeTopK } : {},
330
- ...judgeModel ? { judgeModel } : {},
331
- // The skeptic is handed `models[0]` — i.e. by default the refute pass runs
332
- // on the SAME MODEL that found the bug, which is the correlated-error
333
- // problem in #661. `finderModels` lets the cross-family selector avoid
334
- // every family in the finder fan-out (not just the first) and swap the
335
- // refuter to a different family when one is configured; when only one
336
- // provider is configured it passes through to exactly this model. `log`
337
- // makes that decision visible in the run log instead of implicit.
338
- ...opts.verify === false ? {} : {
339
- verify: makeSkepticVerifier({
340
- sourceRoot,
341
- runtime,
342
- ...opts.models?.[0] ? { model: opts.models[0] } : {},
343
- ...opts.models && opts.models.length > 0 ? { finderModels: opts.models } : {},
344
- negatives: loadKnownNegativesFromEnv(),
345
- log
346
- })
347
- },
348
- // PROVE stage (#1119) — the terminal gate. Only wired on --exploitability,
349
- // because it boots REAL QEMU per confirmed finding. runHuntScan itself
350
- // ignores it (with a warning) when `verify` is absent, so --no-verify
351
- // --exploitability degrades safely instead of booting anything.
352
- ...opts.exploitability ? {
353
- exploitability: makeHuntProveStage({
354
- // Cheap VM-free pre-filter: never spend a QEMU slot on a dos-only bug.
355
- escalation: opts.proveMinCeiling ? { minCeiling: opts.proveMinCeiling } : {},
356
- onVerdict: (f, _c, v) => log(
357
- `[hunt:prove] ${f.title}: maxObserved=${v.maxObservedClass} upgraded=${v.upgraded} reachesPrivesc=${v.reachesPrivesc} proven=${v.provenExploitability}`
358
- ),
359
- onEscalation: (f, _c, v) => log(`[hunt:prove] ${f.title}: impact ceiling ${v.ceiling} (${v.basis}, conf ${v.confidence})`),
360
- log
361
- })
362
- } : {},
363
- ...opts.novelty && noveltyMirrors.length > 0 ? {
364
- novelty: {
365
- mirrors: noveltyMirrors,
366
- ...opts.novelty.model ? { judge: makeLloreJudge({ model: opts.novelty.model }) } : {}
367
- }
368
- } : {},
369
- log
370
- });
371
- const gated = opts.verify !== false;
372
- const leads = gated ? res.confirmed : res.findings;
373
- let ingested = 0;
374
- if (sinkCfg) {
375
- const seedRef = opts.ref ?? opts.seedPath;
376
- const pathForId = /* @__PURE__ */ new Map();
377
- for (const rec of res.records) pathForId.set(rec.finding.id, rec.candidatePath);
378
- for (const lead of leads) {
379
- const candidatePath = pathForId.get(lead.id);
380
- await postFinding(leadToCandidateFinding(lead, plan.brief.bugClass, seedRef, candidatePath), sinkCfg);
381
- ingested++;
382
- }
383
- log(`[hunt] posted ${ingested} lead(s) to the cloud-sink as candidate findings`);
384
- }
385
- return {
386
- exitCode: leads.length > 0 ? 0 : 1,
387
- result: {
388
- mode: "hunt",
389
- seed: opts.ref ?? opts.seedPath,
390
- bug_class: plan.brief.bugClass,
391
- source: sourceRoot,
392
- candidate_sites: selectedCandidates.map((c) => c.path),
393
- skipped_candidates: skipCandidates,
394
- scanned: res.scanned,
395
- findings: res.findings.length,
396
- confirmed: gated ? res.confirmed.length : null,
397
- novelty: opts.novelty ? {
398
- enabled: true,
399
- required: true,
400
- root: noveltyRoot,
401
- lists: noveltyLists,
402
- mirrors: noveltyMirrors.map((m) => ({ list: m.list, epoch: m.epoch, dir: m.dir })),
403
- duplicates: res.duplicates.map((d) => ({
404
- title: d.finding.title,
405
- matches: d.novelty.duplicates
406
- }))
407
- } : { enabled: false },
408
- leads: leads.map((f) => ({
409
- title: f.title,
410
- severity: f.severity,
411
- analysis: f.evidence.analysis ?? ""
412
- })),
413
- dropped: res.dropped.map((d) => ({
414
- title: d.finding.title,
415
- severity: d.finding.severity,
416
- candidatePath: d.candidatePath,
417
- lensId: d.lensId,
418
- dropReason: d.dropReason,
419
- detail: d.detail
420
- })),
421
- invariant: invariantCtx ? {
422
- enabled: true,
423
- subsystem: invariantCtx.subsystem,
424
- model_path: invariantCtx.modelPath,
425
- model_loaded: invariantCtx.modelLoaded,
426
- objects: invariantCtx.model.objects.length,
427
- violations: invariantCtx.violations.length
428
- } : { enabled: false },
429
- graph_slice: graphSliceCtx ? {
430
- enabled: true,
431
- subsystem: graphSliceCtx.subsystem,
432
- cpg_path: graphSliceCtx.cpgPath,
433
- target_functions: graphSliceCtx.targetFunctions,
434
- resolved_targets: graphSliceCtx.resolvedTargets,
435
- ops_edges: graphSliceCtx.opsEdges,
436
- functions: graphSliceCtx.stats.functions,
437
- files: graphSliceCtx.stats.files.length,
438
- call_edges: graphSliceCtx.stats.callEdges,
439
- slice_chars: graphSliceCtx.stats.chars
440
- } : { enabled: false },
441
- ingested: sinkCfg ? ingested : null,
442
- gated,
443
- methodology: opts.methodology === true,
444
- warnings: [...invariantWarnings, ...graphSliceWarnings, ...noveltyWarnings, ...plan.warnings, ...res.warnings].slice(0, 10),
445
- note: opts.novelty ? "LEADS, not confirmed 0-days. Novelty-duplicate leads were dropped when lore mirrors matched; still verify the real sink before disclosure." : "LEADS, not confirmed 0-days. Verify the real sink + upstream-fix (novelty) before disclosure."
446
- }
447
- };
448
- } finally {
449
- if (savedCloudSink !== void 0) process.env["0SEC_CLOUD_SINK"] = savedCloudSink;
450
- prepared.cleanup();
451
- }
452
- }
453
- async function huntAction(opts) {
454
- if (!opts.source) throw new Error("missing required flag: --source <kernel/src tree>");
455
- if (!opts.seed) throw new Error("missing required flag: --seed <fix diff/patch to hunt variants of>");
456
- const outcome = await runHunt({
457
- sourceRoot: opts.source,
458
- seedPath: opts.seed,
459
- ...opts.ref ? { ref: opts.ref } : {},
460
- concurrency: parsePositive("--concurrency", opts.concurrency, 4),
461
- skipCandidates: parseNonNegative("--skip-candidates", opts.skipCandidates, 0),
462
- ...opts.models ? { models: opts.models.split(",").map((s) => s.trim()).filter(Boolean) } : {},
463
- ...opts.reachableOnly ? { reachableOnly: true } : {},
464
- ...opts.reachablePrefer ? { reachablePrefer: true } : {},
465
- verify: opts.verify,
466
- ...opts.novelty || opts.noveltyRequired || opts.methodology ? {
467
- novelty: {
468
- ...opts.noveltyRoot ? { rootDir: opts.noveltyRoot } : {},
469
- ...opts.noveltyLists ? { lists: opts.noveltyLists.split(",").map((s) => s.trim()).filter(Boolean) } : {},
470
- recentEpochs: parsePositive("--novelty-recent-epochs", opts.noveltyRecentEpochs, 1),
471
- sync: opts.noveltySync === true || opts.methodology === true,
472
- ...opts.noveltyModel ? { model: opts.noveltyModel } : {},
473
- required: opts.noveltyRequired === true || opts.methodology === true
474
- }
475
- } : {},
476
- methodology: opts.methodology === true,
477
- invariant: opts.invariant === true,
478
- graphSlice: opts.graphSlice === true,
479
- ...opts.cpg ? { cpgPath: opts.cpg } : {},
480
- ...opts.opsHarvest !== void 0 ? {
481
- opsHarvestSourceFiles: opts.opsHarvest.split(",").map((path) => path.trim()).filter(Boolean)
482
- } : {},
483
- ...opts.graphSliceHops ? { graphSliceHops: parsePositive("--graph-slice-hops", opts.graphSliceHops, 3) } : {},
484
- exploitability: opts.exploitability === true,
485
- ...opts.proveMinCeiling ? { proveMinCeiling: parseCeiling(opts.proveMinCeiling) } : {},
486
- ...opts.runtime ? { runtime: opts.runtime } : {},
487
- timeoutMs: parsePositive("--timeout", opts.timeout, 6e5),
488
- log: (m) => process.stderr.write(m + "\n")
489
- });
490
- const json = JSON.stringify(outcome.result, null, 2);
491
- if (opts.output) writeFileSync(resolve(opts.output), json + "\n", "utf8");
492
- else process.stdout.write(json + "\n");
493
- process.exitCode = outcome.exitCode;
494
- }
495
- function registerHuntCommand(program) {
496
- program.command("hunt").description(
497
- "Hunt a bug CLASS across a source tree, seeded by a proven fix: generate variant candidate sites from the fix, fan finders out over them, and gate each finding through an adversarial skeptic. Emits LEADS to verify (not confirmed 0-days). Exit 0=lead(s), 1=none, 2=no candidates, 3=error."
498
- ).requiredOption("--source <path>", "Source tree to hunt in (e.g. a linux checkout)").requiredOption("--seed <path>", "Fix diff / .patch whose bug class to hunt variants of").option("--ref <name>", "Provenance label for the seed (e.g. the CVE / commit)").option("--concurrency <N>", "Max finders in flight (default 4)").option("--max-candidates <N>", "Cap candidate sites hunted (default 40)").option("--skip-candidates <N>", "Skip the first N ranked candidate sites before hunting (default 0)").option("--models <a,b>", "Comma-separated finder models for diversity (default: provider default)").option("--reachable-only", "Restrict candidates to paths built + zero-cap reachable on the kernelCTF COS target (default: HUNT_REACHABLE_ONLY env)").option("--reachable-prefer", "Sort kernelCTF-reachable candidates first, without dropping any (default: HUNT_REACHABLE_PREFER env)").option("--no-verify", "Skip the skeptic gate (emit all raw findings \u2014 triage only, never disclosure)").option("--novelty", "Require lore.kernel.org duplicate suppression; abort before discovery when evidence is unavailable").option("--novelty-root <path>", "Lore mirror root (default: 0SEC_LORE_MIRROR_ROOT or /root/lore-mirror)").option("--novelty-lists <a,b>", "Comma-separated lore lists to search (default: 0SEC_LORE_LISTS or linux-media)").option("--novelty-recent-epochs <N>", "Newest public-inbox epochs to sync per list when --novelty-sync is set (default 1)").option("--novelty-sync", "Clone/fetch lore mirrors before running the novelty gate").option("--novelty-model <model>", "Optional model override for the lore duplicate judge").option("--novelty-required", "Legacy alias; --novelty already aborts when evidence is unavailable").option("--methodology", "Use the kernel-LPE methodology preset: lifecycle/provenance lenses, best-of-4, top-2 skeptic gate, reachable-first").option("--invariant", "Engine A: build (or load) the seed-touched subsystem's stored invariant model and inject its rules + deterministic violation hypotheses into every finder prompt").option("--graph-slice", "Load the seed-touched subsystem's pre-exported Joern CPG and inject a compact interprocedural reachability slice around the fix site into every finder prompt (needs scripts/provision-cpg.sh; fail-open to flat-text)").option("--cpg <path>", "Explicit CPG graphson JSON path for --graph-slice (default: <source>/.0sec/cpg/<subsystem>.json)").option(
499
- "--ops-harvest <paths>",
500
- "[--graph-slice] Comma-separated repo-relative C files to harvest static ops-struct initializers from; overrides a precomputed .ops.json"
501
- ).option(
502
- "--graph-slice-hops <N>",
503
- "[--graph-slice] Call-graph radius around the seed functions (default 3; use 8 for the exp527 known answer)"
504
- ).option(
505
- "--exploitability",
506
- "PROVE stage: after the skeptic+prover gate, run the execution-verified exploitability oracle on each confirmed finding (GREBE diversify + SCAVY differential). BOOTS REAL QEMU VMs \u2014 requires staged kernel-VM artifacts and is ignored under --no-verify. Never rejects a finding; it stamps a proven verdict and gates the weaponize budget."
507
- ).option(
508
- "--prove-min-ceiling <ceiling>",
509
- "[--exploitability] Minimum assessed impact ceiling worth a VM slot: dos-only|info-leak|oob-write|uaf-control (default info-leak \u2014 filters out dos-only before QEMU is touched)"
510
- ).option("--output <path>", "Write the hunt result JSON to this path instead of stdout").option("--runtime <mode>", "Engine runtime (default api)").option("--timeout <ms>", "Accepted cloud agent timeout budget in milliseconds", "600000").action(async (opts) => {
511
- try {
512
- await huntAction(opts);
513
- } catch (err) {
514
- const reason = err instanceof Error ? err.message : String(err);
515
- const json = JSON.stringify({ mode: "hunt", error: reason }, null, 2);
516
- if (opts.output) {
517
- try {
518
- writeFileSync(resolve(opts.output), json + "\n", "utf8");
519
- } catch {
520
- process.stderr.write(json + "\n");
521
- }
522
- } else process.stdout.write(json + "\n");
523
- process.exitCode = 3;
524
- }
525
- });
526
- }
527
-
528
- // packages/cli/src/commands/deep-review.ts
529
- import { readFileSync as readFileSync2, realpathSync, statSync } from "node:fs";
530
- import { resolve as resolve2, join, sep, relative } from "node:path";
531
- import { createHash, randomUUID } from "node:crypto";
532
- var DEEP_REVIEW_FILE_CAP = 5e3;
533
- var DEFAULT_MAX_CANDIDATES = 8;
534
- function defaultMaxCandidates() {
535
- const raw = process.env["0SEC_DEEP_REVIEW_MAX_CANDIDATES"];
536
- if (!raw) return DEFAULT_MAX_CANDIDATES;
537
- const n = Number.parseInt(raw, 10);
538
- return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_CANDIDATES;
539
- }
540
- function scaleMaxCandidates(fileCount) {
541
- if (fileCount > 2e3) return 20;
542
- if (fileCount > 500) return 16;
543
- if (fileCount > 200) return 12;
544
- return DEFAULT_MAX_CANDIDATES;
545
- }
546
- var DEFAULT_ATTEMPTS = 1;
547
- function defaultAttempts() {
548
- const raw = process.env["0SEC_DEEP_REVIEW_ATTEMPTS"];
549
- if (!raw) return DEFAULT_ATTEMPTS;
550
- const n = Number.parseInt(raw, 10);
551
- return Number.isFinite(n) && n > 0 ? n : DEFAULT_ATTEMPTS;
552
- }
553
- function defaultModels() {
554
- const raw = process.env["0SEC_DEEP_REVIEW_MODELS"];
555
- if (!raw) return void 0;
556
- const models = raw.split(",").map((s) => s.trim()).filter(Boolean);
557
- return models.length > 0 ? models : void 0;
558
- }
559
- var DEFAULT_CONCURRENCY = 8;
560
- var genericFinderLenses = [
561
- {
562
- id: "memory-safety",
563
- challengeHint: "Hunt MEMORY-SAFETY bugs only: out-of-bounds read/write, use-after-free, double-free, uninitialized read, integer overflow feeding an allocation or index, and unchecked length/size arithmetic before a copy. Cite the exact unguarded sink (file:line) and the attacker-controlled path that reaches it."
564
- },
565
- {
566
- id: "input-validation",
567
- challengeHint: "Hunt INPUT-VALIDATION and injection bugs only: untrusted input reaching a dangerous sink without validation \u2014 command/SQL/path/template injection, unsafe deserialization, SSRF, unchecked redirects, or a parser that trusts attacker-supplied structure. Trace the taint from the entry point to the sink."
568
- },
569
- {
570
- id: "auth-logic",
571
- challengeHint: "Hunt AUTHZ / LOGIC bugs only: a missing or wrong permission/ownership check, a broken state machine, a TOCTOU race, an off-by-one or boundary error in a security-relevant decision, or a check that can be bypassed. Prove the guard is absent or mis-scoped, not merely that the keywords appear."
572
- },
573
- {
574
- id: "secrets-crypto",
575
- challengeHint: "Hunt SECRETS / CRYPTO misuse only: hardcoded credentials, a weak/predictable RNG used for security, a broken or misused cryptographic primitive (ECB, static IV/nonce, missing MAC verification, non-constant-time compare), or a signature/token check that can be forged or replayed. Cite the exact misuse."
576
- },
577
- {
578
- id: "cross-component",
579
- challengeHint: "Hunt CROSS-COMPONENT bugs only: a bug whose exploit path spans two or more subsystems touching DIFFERENT trust boundaries \u2014 e.g. an API layer that passes unvalidated user input to a kernel driver, a storage layer whose consistency assumptions are violated by a separate async path, or a UX component whose state bleeds into an auth decision in a sibling module. Trace the path ACROSS the boundary and prove the attacker can reach BOTH sides. Ignore bugs fully contained within a single component."
580
- }
581
- ];
582
- function lensSetDigest(lenses) {
583
- return createHash("sha256").update(JSON.stringify(lenses.map(({ id, challengeHint }) => ({ id, challengeHint })))).digest("hex");
584
- }
585
- function createDefaultFinderLenses() {
586
- return [...genericFinderLenses, ...loadAppsecFinderLenses()];
587
- }
588
- var defaultFinderLenses = createDefaultFinderLenses();
589
- var defaultVerifyLenses = [
590
- {
591
- id: "reachability",
592
- challengeHint: "REACHABILITY: is the vulnerable code actually reachable by an attacker from a real entry point (exported/public API, request handler, CLI, parser) with no gate it cannot pass? Trace the concrete path from the entry to the sink. If the path is dead code, disabled, or privileged-only, refute it."
593
- },
594
- {
595
- id: "completeness",
596
- challengeHint: "COMPLETENESS: is the 'missing' check actually enforced elsewhere on the path \u2014 a validation earlier in the flow, a guard in the only caller, a wrapper that sanitizes first? Read the whole call path and the full file/module. If the guard is present AND correctly scoped, refute it; keep it only if genuinely absent or mis-scoped."
597
- },
598
- {
599
- id: "novelty-known-issue",
600
- challengeHint: "NOVELTY / KNOWN-GUARD: is the standard guard for this class present and correct (a framework escaper, a safe API, a bounds check, a working auth middleware)? Is this a well-known already-mitigated pattern in this codebase or its dependencies? If a correct standard guard covers it, refute it."
601
- },
602
- {
603
- id: "scope",
604
- challengeHint: "SCOPE / IMPACT: does exploiting this actually corrupt memory, leak secrets, escalate privilege, execute code, or move value / break a security invariant? A cosmetic missing check with no real impact is info/low, not a high-severity finding \u2014 refute it as such."
605
- },
606
- {
607
- id: "deployment-context",
608
- challengeHint: "DEPLOYMENT CONTEXT: is this finding's vulnerable code path actually deployed to a production runtime, or is it restricted to development, test, or build-only surfaces? \n\nYour job is to examine the finding's evidence AND your own reading of the candidate source to decide: can an attacker reach this code from a production entry point? \n\n- If the code is in a test file, a dev-only config (seeds, .dev.vars, dev-server), or build scaffolding (webpack, CI, vendored deps) with NO trust-boundary crossing from prod, refute it as dev/test/build-only.\n- If you find a trust-boundary bypass \u2014 a prod-routed entry point that reaches this code despite it being in a dev/test/build file \u2014 DO NOT refute; the finding is valid per the HackerOne rule.\n- If you are UNCERTAIN (the evidence is ambiguous or you cannot assess the deployment topology), ABSTAIN by returning an error. Never falsely refute a finding with weak evidence.\nPRIORITY: the mechanical path heuristic (file path classification) is the DETERMINISTIC FLOOR and overrides this lens on conflict. If the heuristic already tagged the finding as dev_only/test_only/build_only, the severity cap has already been applied \u2014 this lens exists to catch cases the heuristic misses (ambiguous paths, model-extracted evidence, cross-boundary reachability)."
609
- }
610
- ];
611
- function selectProfileLenses(profile, sets, defaultFinderSnapshot = defaultFinderLenses) {
612
- switch ((profile ?? "").trim().toLowerCase()) {
613
- case "evm-onchain":
614
- return { finderLenses: sets.evmFinderLenses, verifyLenses: sets.evmVerifyLenses, matchedProfile: "evm-onchain" };
615
- case "solana-onchain":
616
- return { finderLenses: sets.solanaFinderLenses, verifyLenses: sets.solanaVerifyLenses, matchedProfile: "solana-onchain" };
617
- case "cardano-onchain":
618
- return { finderLenses: sets.cardanoFinderLenses, verifyLenses: sets.cardanoVerifyLenses, matchedProfile: "cardano-onchain" };
619
- case "cairo-onchain":
620
- return { finderLenses: sets.cairoFinderLenses, verifyLenses: sets.cairoVerifyLenses, matchedProfile: "cairo-onchain" };
621
- case "move-onchain":
622
- return { finderLenses: sets.moveFinderLenses, verifyLenses: sets.moveVerifyLenses, matchedProfile: "move-onchain" };
623
- default:
624
- return { finderLenses: defaultFinderSnapshot, verifyLenses: defaultVerifyLenses, matchedProfile: "default" };
625
- }
626
- }
627
- var NATIVE_SOURCE_EXTS = /* @__PURE__ */ new Set([
628
- "c",
629
- "h",
630
- "cc",
631
- "cpp",
632
- "cxx",
633
- "hpp",
634
- "hh",
635
- "hxx",
636
- "rs"
637
- ]);
638
- var MANAGED_WEB_EXTS = /* @__PURE__ */ new Set([
639
- "cs",
640
- "csproj",
641
- "sln",
642
- "vbproj",
643
- "fsproj",
644
- // .NET / C#
645
- "ts",
646
- "tsx",
647
- "js",
648
- "jsx",
649
- "mjs",
650
- "cjs",
651
- "vue",
652
- "svelte",
653
- // JS/TS front+back
654
- "java",
655
- "kt",
656
- "kts",
657
- "scala",
658
- // JVM
659
- "py",
660
- "rb",
661
- "php",
662
- "go",
663
- // scripting / Go
664
- "html",
665
- "htm",
666
- "cshtml",
667
- "razor",
668
- "aspx",
669
- "jsp"
670
- // web templates
671
- ]);
672
- function fileExt(path) {
673
- const base = path.split(/[/\\]+/).pop() ?? path;
674
- const dot = base.lastIndexOf(".");
675
- return dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
676
- }
677
- function detectStack(files) {
678
- let native = 0;
679
- let managed = 0;
680
- for (const f of files) {
681
- const ext = fileExt(f);
682
- if (NATIVE_SOURCE_EXTS.has(ext)) native++;
683
- else if (MANAGED_WEB_EXTS.has(ext)) managed++;
684
- }
685
- if (native === 0 && managed === 0) return "unknown";
686
- if (native === 0) return "managed-web";
687
- if (managed === 0) return "native";
688
- return "mixed";
689
- }
690
- var MEMORY_SAFETY_LENS_ID = "memory-safety";
691
- function selectDefaultFinderLensesForStack(files, defaultFinder) {
692
- if (detectStack(files) === "managed-web") {
693
- return defaultFinder.filter((l) => l.id !== MEMORY_SAFETY_LENS_ID);
694
- }
695
- return defaultFinder;
696
- }
697
- var EVM_EXCLUDE_DIR_SEGMENTS = /* @__PURE__ */ new Set([
698
- "test",
699
- "tests",
700
- "mock",
701
- "mocks",
702
- "script",
703
- "scripts",
704
- // Foundry deploy scripts
705
- "lib",
706
- // Foundry vendored deps (forge-std / openzeppelin / solmate …)
707
- "node_modules"
708
- // Hardhat/JS vendored deps (also skipped by the core walker)
709
- ]);
710
- function isNonProtocolEvmPath(absPath, scopeRoot) {
711
- const rel = relative(scopeRoot, absPath);
712
- if (rel === "" || rel.startsWith("..")) return false;
713
- const segments = rel.split(/[/\\]+/).filter(Boolean);
714
- if (segments.length === 0) return false;
715
- for (let i = 0; i < segments.length - 1; i++) {
716
- if (EVM_EXCLUDE_DIR_SEGMENTS.has(segments[i].toLowerCase())) return true;
717
- }
718
- const fileName = segments[segments.length - 1].toLowerCase();
719
- if (fileName.endsWith(".t.sol")) return true;
720
- if (fileName.includes(".test.") || fileName.includes(".spec.")) return true;
721
- return false;
722
- }
723
- function topLevelModule(absPath, scopeRoot) {
724
- const rel = relative(scopeRoot, absPath);
725
- if (rel === "" || rel.startsWith("..")) return ".";
726
- const segments = rel.split(/[/\\]+/).filter(Boolean);
727
- return segments.length > 1 ? segments[0] : ".";
728
- }
729
- function selectCandidatesModuleSpread(entries, scopeRoot, maxCandidates) {
730
- const cmp = (a, b) => b.size - a.size || a.p.localeCompare(b.p);
731
- const byModule = /* @__PURE__ */ new Map();
732
- for (const e of entries) {
733
- const key = topLevelModule(e.p, scopeRoot);
734
- let group = byModule.get(key);
735
- if (!group) byModule.set(key, group = []);
736
- group.push(e);
737
- }
738
- const groups = [...byModule.values()];
739
- for (const g of groups) g.sort(cmp);
740
- groups.sort((a, b) => cmp(a[0], b[0]));
741
- const cap = Math.max(1, maxCandidates);
742
- const out = [];
743
- for (let round = 0; out.length < cap; round++) {
744
- let advanced = false;
745
- for (const g of groups) {
746
- if (round >= g.length) continue;
747
- out.push(g[round].p);
748
- advanced = true;
749
- if (out.length >= cap) break;
750
- }
751
- if (!advanced) break;
752
- }
753
- return out;
754
- }
755
- function enumerateDeepReviewCandidates(scopeRoot, helpers, opts) {
756
- const fileCap = opts.fileCap ?? DEEP_REVIEW_FILE_CAP;
757
- const exclude = opts.exclude ?? (() => false);
758
- const fileSize = helpers.fileSize ?? ((p) => {
759
- try {
760
- return statSync(p).size;
761
- } catch {
762
- return 0;
763
- }
764
- });
765
- const totalFiles = helpers.countScopeFilesUpTo(scopeRoot, fileCap);
766
- const overCap = totalFiles > fileCap;
767
- const files = helpers.collectScopeFiles(scopeRoot, { maxFiles: fileCap });
768
- const entries = files.filter((p) => !exclude(p)).map((p) => ({ p, size: fileSize(p) }));
769
- const candidates = selectCandidatesModuleSpread(entries, scopeRoot, opts.maxCandidates);
770
- return { candidates, totalFiles, overCap };
771
- }
772
- async function runDeepReview(opts) {
773
- const defaultFinderSnapshot = createDefaultFinderLenses();
774
- const evolvedFinder = opts.evolutionConfig ? await createEvolvedFinder(opts.evolutionConfig, `deep-review-${randomUUID()}`) : void 0;
775
- const {
776
- runHuntScan,
777
- makeMultiLensVerifier,
778
- prepare,
779
- collectScopeFiles,
780
- countScopeFilesUpTo,
781
- getCloudSinkConfig,
782
- postFinding,
783
- evmFinderLenses,
784
- evmVerifyLenses,
785
- solanaFinderLenses,
786
- solanaVerifyLenses,
787
- cardanoFinderLenses,
788
- cardanoVerifyLenses,
789
- cairoFinderLenses,
790
- cairoVerifyLenses,
791
- moveFinderLenses,
792
- moveVerifyLenses
793
- } = await import("./dist-4YICS2J2.js");
794
- const costLedger = new ScanCostLedger();
795
- const scanStartedAt = Date.now();
796
- const log = opts.log ?? (() => {
797
- });
798
- const runtime = opts.runtime ?? "api";
799
- const explicitMaxCandidates = opts.maxCandidates;
800
- const hasEnvMaxOverride = !!process.env["0SEC_DEEP_REVIEW_MAX_CANDIDATES"];
801
- const baseMaxCandidates = explicitMaxCandidates ?? defaultMaxCandidates();
802
- if (evolvedFinder && opts.models?.length) throw new Error("--models selects native finders and cannot be combined with --evolution-config");
803
- const models = evolvedFinder ? ["evolved-source"] : opts.models ?? defaultModels();
804
- const attemptsPerCandidate = opts.attemptsPerCandidate ?? defaultAttempts();
805
- const prepared = await prepare(opts.target, "source-code", { ...opts.timeoutMs ? { timeout: opts.timeoutMs } : {} }, (e) => {
806
- if (e.message) log(`[deep-review:source] ${e.message}`);
807
- });
808
- const sourceRoot = resolve2(prepared.resolvedTarget);
809
- let scopeRoot = sourceRoot;
810
- if (opts.subsystem && opts.subsystem.trim() !== "") {
811
- const scoped = resolve2(join(sourceRoot, opts.subsystem));
812
- if (scoped !== sourceRoot && !scoped.startsWith(sourceRoot + sep)) {
813
- prepared.cleanup();
814
- throw new Error(`--subsystem '${opts.subsystem}' escapes the source tree`);
815
- }
816
- try {
817
- const realRoot = realpathSync(sourceRoot);
818
- const realScoped = realpathSync(scoped);
819
- if (realScoped !== realRoot && !realScoped.startsWith(realRoot + sep)) {
820
- throw new Error(`--subsystem '${opts.subsystem}' escapes the source tree`);
821
- }
822
- scopeRoot = scoped;
823
- } catch (error) {
824
- prepared.cleanup();
825
- throw error;
826
- }
827
- }
828
- const sinkCfg = getCloudSinkConfig();
829
- const savedCloudSink = process.env["0SEC_CLOUD_SINK"];
830
- if (sinkCfg) delete process.env["0SEC_CLOUD_SINK"];
831
- try {
832
- const isEvmProfile = (opts.profile ?? "").trim().toLowerCase() === "evm-onchain";
833
- const totalFiles = countScopeFilesUpTo(scopeRoot, DEEP_REVIEW_FILE_CAP);
834
- const maxCandidates = explicitMaxCandidates ?? (hasEnvMaxOverride ? baseMaxCandidates : scaleMaxCandidates(totalFiles));
835
- const overCap = totalFiles > DEEP_REVIEW_FILE_CAP;
836
- if (explicitMaxCandidates === void 0 && maxCandidates !== baseMaxCandidates) {
837
- log(`[deep-review] auto-scaled candidate cap from ${baseMaxCandidates} to ${maxCandidates} (${totalFiles} scope files)`);
838
- }
839
- let lanes = null;
840
- let allocateAcrossLanes;
841
- if (opts.useThreatModel) {
842
- const threatModule = await import("./dist-4YICS2J2.js");
843
- allocateAcrossLanes = threatModule.allocateCandidatesAcrossLanes;
844
- const rtType = runtime !== "auto" ? runtime : "api";
845
- const plannerRuntime = threatModule.createRuntime({
846
- type: rtType,
847
- timeout: opts.timeoutMs ?? 6e5,
848
- model: models?.[0]
849
- });
850
- lanes = await threatModule.runThreatModelPlanner(sourceRoot, plannerRuntime, log);
851
- if (!lanes || lanes.length === 0) {
852
- log("[threat-model] no lanes produced \u2014 continuing with default selection");
853
- } else {
854
- log(`[threat-model] planner returned ${lanes.length} lane(s) \u2014 will allocate candidates across boundaries`);
855
- }
856
- }
857
- if (overCap) {
858
- return {
859
- exitCode: 2,
860
- result: {
861
- mode: "deep_review",
862
- source: sourceRoot,
863
- subsystem: opts.subsystem ?? null,
864
- scope_files: totalFiles,
865
- note: `scope exceeds the ${DEEP_REVIEW_FILE_CAP}-file review cap \u2014 narrow it with --subsystem <path> to a specific directory.`
866
- }
867
- };
868
- }
869
- const { candidates: initialCandidates } = enumerateDeepReviewCandidates(
870
- scopeRoot,
871
- { collectScopeFiles, countScopeFilesUpTo },
872
- {
873
- maxCandidates,
874
- fileCap: DEEP_REVIEW_FILE_CAP,
875
- ...isEvmProfile ? { exclude: (p) => isNonProtocolEvmPath(p, scopeRoot) } : {}
876
- }
877
- );
878
- const candidatePaths = initialCandidates.slice();
879
- if (lanes && lanes.length > 0 && allocateAcrossLanes) {
880
- const allFiles = collectScopeFiles(scopeRoot, { maxFiles: DEEP_REVIEW_FILE_CAP });
881
- const exclude = isEvmProfile ? (p) => isNonProtocolEvmPath(p, scopeRoot) : () => false;
882
- const entries = allFiles.filter((p) => !exclude(p)).map((p) => {
883
- try {
884
- return { p, size: statSync(p).size };
885
- } catch {
886
- return { p, size: 0 };
887
- }
888
- });
889
- const laneCandidates = allocateAcrossLanes(entries, lanes, scopeRoot, maxCandidates, log);
890
- if (laneCandidates.length > 0) {
891
- const prevModules = new Set(initialCandidates.map((p) => relative(scopeRoot, p).split(/[/\\]+/)[0]));
892
- const laneModules = new Set(laneCandidates.map((p) => relative(scopeRoot, p).split(/[/\\]+/)[0]));
893
- log(`[deep-review] threat-model re-allocated ${initialCandidates.length} \u2192 ${laneCandidates.length} candidate(s); modules ${prevModules.size} \u2192 ${laneModules.size}`);
894
- candidatePaths.length = 0;
895
- candidatePaths.push(...laneCandidates);
896
- }
897
- }
898
- if (candidatePaths.length === 0) {
899
- return {
900
- exitCode: 2,
901
- result: {
902
- mode: "deep_review",
903
- source: sourceRoot,
904
- subsystem: opts.subsystem ?? null,
905
- scope_files: totalFiles,
906
- candidates: 0,
907
- note: "no reviewable source files found under the scope (empty tree or all filtered)."
908
- }
909
- };
910
- }
911
- const { finderLenses: selectedFinderLenses, verifyLenses, matchedProfile } = selectProfileLenses(opts.profile, {
912
- evmFinderLenses,
913
- evmVerifyLenses,
914
- solanaFinderLenses,
915
- solanaVerifyLenses,
916
- cardanoFinderLenses,
917
- cardanoVerifyLenses,
918
- cairoFinderLenses,
919
- cairoVerifyLenses,
920
- moveFinderLenses,
921
- moveVerifyLenses
922
- }, defaultFinderSnapshot);
923
- const finderLenses = matchedProfile === "default" ? selectDefaultFinderLensesForStack(candidatePaths, selectedFinderLenses) : selectedFinderLenses;
924
- const lensDigest = lensSetDigest(finderLenses);
925
- const scanId = randomUUID();
926
- let sourceRevisionDigest = null;
927
- let sourceFingerprintWarning;
928
- try {
929
- const files = [...candidatePaths].sort().map((path) => ({
930
- path: relative(sourceRoot, path),
931
- digest: createHash("sha256").update(readFileSync2(path)).digest("hex")
932
- }));
933
- sourceRevisionDigest = `sha256:${createHash("sha256").update(JSON.stringify(files)).digest("hex")}`;
934
- } catch (error) {
935
- sourceFingerprintWarning = `learning feedback skipped: reviewed inputs could not be fingerprinted (${error instanceof Error ? error.message : String(error)})`;
936
- log(`[deep-review] ${sourceFingerprintWarning}`);
937
- }
938
- log(
939
- `[deep-review] ${candidatePaths.length} candidate file(s) (of ${totalFiles}${overCap ? "+" : ""}) \xD7 ${finderLenses.length} finder-lens(es); verify quorum over ${verifyLenses.length} lens(es); profile=${matchedProfile}; lens-snapshot=${lensDigest.slice(0, 12)}`
940
- );
941
- const verify = makeMultiLensVerifier(verifyLenses, {
942
- sourceRoot,
943
- runtime,
944
- ...!evolvedFinder && models?.[0] ? { model: models[0] } : {},
945
- // Every verify lens is a refute pass on `models[0]` — the same model the
946
- // finders ran on. Passing the full finder set lets the cross-family
947
- // selector move the refutation off ALL finder families when a second
948
- // provider is configured (#661), and `log` records what it decided —
949
- // including "it could not", which is the case worth knowing about.
950
- ...opts.costCeilingUsd !== void 0 ? { costCeilingUsd: opts.costCeilingUsd } : {},
951
- costLedger,
952
- ...!evolvedFinder && models && models.length > 0 ? { finderModels: models } : {},
953
- ...opts.quorum ? { quorum: opts.quorum } : {},
954
- log
955
- });
956
- const postedIds = /* @__PURE__ */ new Set();
957
- let ingested = 0;
958
- const provenance = `deep_review (${matchedProfile} lenses)`;
959
- const postLead = async (lead) => {
960
- if (!sinkCfg || postedIds.has(lead.id)) return;
961
- postedIds.add(lead.id);
962
- await postFinding(leadToCandidateFinding(lead, `deep-review:${matchedProfile}`, provenance), sinkCfg);
963
- ingested++;
964
- };
965
- const res = await runHuntScan({
966
- sourceRoot,
967
- candidates: candidatePaths.map((path) => ({ path })),
968
- lenses: finderLenses,
969
- runtime,
970
- ...evolvedFinder ? { finder: (input) => evolvedFinder.find(sourceRoot, input) } : {},
971
- concurrency: opts.concurrency ?? DEFAULT_CONCURRENCY,
972
- ...opts.costCeilingUsd !== void 0 ? { costCeilingUsd: opts.costCeilingUsd } : {},
973
- costLedger,
974
- attemptsPerCandidate,
975
- ...models ? { models } : {},
976
- verify,
977
- ...sinkCfg ? { onConfirmed: postLead } : {},
978
- log
979
- });
980
- const leads = res.confirmed;
981
- if (sourceFingerprintWarning) res.warnings.push(sourceFingerprintWarning);
982
- if (sourceRevisionDigest) {
983
- try {
984
- for (const gap of res.incompleteCoverage ?? []) {
985
- captureObservation({
986
- classHint: gap.lensId || "generic-finder-timeout",
987
- sinkPattern: "",
988
- exampleFileLine: gap.file,
989
- whyMissed: `finder ${gap.reason}; budget ${gap.budgetMs}ms`,
990
- source: "incomplete-coverage",
991
- scanId,
992
- sourceRevisionDigest,
993
- consent: false,
994
- detectorLensId: gap.lensId || void 0,
995
- detectorLensVersionDigest: gap.lensVersionDigest
996
- });
997
- }
998
- for (const dropped of res.dropped ?? []) {
999
- if (dropped.dropReason === "verify_refuted" || dropped.dropReason === "novelty_duplicate" || dropped.dropReason === "judge_truncation" || dropped.dropReason === "late_resolution") continue;
1000
- captureObservation({
1001
- classHint: dropped.lensId || "unknown-lens",
1002
- sinkPattern: "",
1003
- exampleFileLine: dropped.candidatePath,
1004
- whyMissed: `dropped: ${dropped.dropReason}`,
1005
- source: "incomplete-coverage",
1006
- scanId,
1007
- sourceRevisionDigest,
1008
- consent: false,
1009
- detectorLensId: dropped.lensId || void 0,
1010
- detectorLensVersionDigest: dropped.lensVersionDigest
1011
- });
1012
- }
1013
- } catch (error) {
1014
- const warning = `learning feedback was not persisted: ${error instanceof Error ? error.message : String(error)}`;
1015
- res.warnings.push(warning);
1016
- log(`[deep-review] ${warning}`);
1017
- }
1018
- }
1019
- if (sinkCfg) {
1020
- for (const lead of leads) await postLead(lead);
1021
- log(`[deep-review] posted ${ingested} lead(s) to the cloud-sink as candidate findings (incremental)`);
1022
- }
1023
- const sweptNothing = res.scanned > 0 && typeof res.finderCompleted === "number" && res.finderCompleted === 0;
1024
- const cost = costLedger.costBreakdown();
1025
- eventBus.emit("scan_completed", {
1026
- exit_reason: sweptNothing ? "failed" : res.costCeilingExceeded ? "cost_exceeded" : "completed",
1027
- findings: res.findings.length,
1028
- findings_count: res.findings.length,
1029
- duration_ms: Date.now() - scanStartedAt,
1030
- summary: res.costCeilingExceeded ? `Deep review stopped at the $${opts.costCeilingUsd?.toFixed(2) ?? "configured"} cost ceiling.` : `Deep review completed: ${res.scanned} finder runs, ${res.findings.length} findings, ${leads.length} leads.`,
1031
- ...cost ? { cost_usd: cost.costUsd, cost_breakdown: cost.breakdown } : {}
1032
- });
1033
- if (sweptNothing) {
1034
- return {
1035
- exitCode: 3,
1036
- result: {
1037
- mode: "deep_review",
1038
- profile: matchedProfile,
1039
- scan_id: scanId,
1040
- source_revision_digest: sourceRevisionDigest,
1041
- lens_snapshot_digest: lensDigest,
1042
- ...evolvedFinder ? { evolution_version_id: evolvedFinder.versionId, evolution_compute_cost_usd: evolvedFinder.computeCostUsd } : {},
1043
- source: sourceRoot,
1044
- subsystem: opts.subsystem ?? null,
1045
- scope_files: totalFiles,
1046
- candidates: candidatePaths.length,
1047
- scanned: res.scanned,
1048
- finder_completed: res.finderCompleted,
1049
- finder_timed_out: res.finderTimedOut ?? null,
1050
- finder_errored: res.finderErrored ?? null,
1051
- error: `every finder run failed (0 of ${res.scanned} completed) \u2014 no coverage was produced; treating as a backend/LLM failure, not a clean 0-finding result.`,
1052
- warnings: res.warnings.slice(0, 10)
1053
- }
1054
- };
1055
- }
1056
- const completedAt = /* @__PURE__ */ new Date();
1057
- const candidateFindings = leads.map((lead) => ({
1058
- ...lead,
1059
- status: "discovered"
1060
- }));
1061
- const report = {
1062
- target: opts.target,
1063
- scanDepth: "deep",
1064
- startedAt: new Date(scanStartedAt).toISOString(),
1065
- completedAt: completedAt.toISOString(),
1066
- durationMs: completedAt.getTime() - scanStartedAt,
1067
- summary: {
1068
- totalAttacks: res.scanned,
1069
- totalFindings: candidateFindings.length,
1070
- critical: candidateFindings.filter((finding) => finding.severity === "critical").length,
1071
- high: candidateFindings.filter((finding) => finding.severity === "high").length,
1072
- medium: candidateFindings.filter((finding) => finding.severity === "medium").length,
1073
- low: candidateFindings.filter((finding) => finding.severity === "low").length,
1074
- info: candidateFindings.filter((finding) => finding.severity === "info").length
1075
- },
1076
- findings: candidateFindings,
1077
- warnings: res.warnings.slice(0, 10).map((message) => ({
1078
- stage: "attack",
1079
- message
1080
- })),
1081
- ...res.costCeilingExceeded ? { costCeilingExceeded: true, exitReason: "cost_ceiling_exceeded" } : {}
1082
- };
1083
- return {
1084
- exitCode: 0,
1085
- report,
1086
- result: {
1087
- mode: "deep_review",
1088
- profile: matchedProfile,
1089
- scan_id: scanId,
1090
- source_revision_digest: sourceRevisionDigest,
1091
- source: sourceRoot,
1092
- subsystem: opts.subsystem ?? null,
1093
- scope_files: totalFiles,
1094
- lens_snapshot_digest: lensDigest,
1095
- ...evolvedFinder ? { evolution_version_id: evolvedFinder.versionId, evolution_compute_cost_usd: evolvedFinder.computeCostUsd } : {},
1096
- candidates: candidatePaths.length,
1097
- finder_lenses: finderLenses.map((l) => l.id),
1098
- verify_lenses: verifyLenses.map((l) => l.id),
1099
- scanned: res.scanned,
1100
- findings: res.findings.length,
1101
- confirmed: leads.length,
1102
- leads: leads.map((f) => ({
1103
- title: f.title,
1104
- severity: f.severity,
1105
- analysis: f.evidence.analysis ?? ""
1106
- })),
1107
- dropped: res.dropped.map((d) => ({
1108
- title: d.finding.title,
1109
- severity: d.finding.severity,
1110
- candidatePath: d.candidatePath,
1111
- lensId: d.lensId,
1112
- dropReason: d.dropReason,
1113
- detail: d.detail
1114
- })),
1115
- ingested: sinkCfg ? ingested : null,
1116
- warnings: res.warnings.slice(0, 10),
1117
- note: "LEADS, not confirmed bugs. Each survived the multi-lens refute quorum; verify the real sink + impact before disclosure."
1118
- }
1119
- };
1120
- } catch (error) {
1121
- const cost = costLedger.costBreakdown();
1122
- eventBus.emit("scan_completed", {
1123
- exit_reason: "failed",
1124
- findings: 0,
1125
- findings_count: 0,
1126
- duration_ms: Date.now() - scanStartedAt,
1127
- summary: `Deep review failed: ${error instanceof Error ? error.message : String(error)}`,
1128
- ...cost ? { cost_usd: cost.costUsd, cost_breakdown: cost.breakdown } : {}
1129
- });
1130
- throw error;
1131
- } finally {
1132
- if (savedCloudSink !== void 0) process.env["0SEC_CLOUD_SINK"] = savedCloudSink;
1133
- prepared.cleanup();
1134
- }
1135
- }
1136
- function parsePositive2(flag, raw, dflt) {
1137
- if (raw === void 0) return dflt;
1138
- const n = parseInt(raw, 10);
1139
- if (!Number.isFinite(n) || n <= 0) throw new Error(`invalid ${flag} '${raw}' (expected positive integer)`);
1140
- return n;
1141
- }
1142
- async function deepReviewAction(target, opts) {
1143
- if (!target || target.trim() === "") throw new Error("missing required argument: <target> (source tree path or git URL)");
1144
- const ceilingSource = opts.costCeiling ?? process.env["0SEC_COST_CEILING_USD"];
1145
- let costCeilingUsd;
1146
- if (ceilingSource !== void 0 && ceilingSource !== "") {
1147
- const parsed = Number(ceilingSource);
1148
- if (!Number.isFinite(parsed) || parsed <= 0) {
1149
- throw new Error(`invalid --cost-ceiling '${ceilingSource}' (expected positive USD amount)`);
1150
- }
1151
- costCeilingUsd = parsed;
1152
- }
1153
- const { writeFileSync: writeFileSync3 } = await import("node:fs");
1154
- const outcome = await runDeepReview({
1155
- target,
1156
- ...costCeilingUsd !== void 0 ? { costCeilingUsd } : {},
1157
- ...opts.profile ? { profile: opts.profile } : {},
1158
- ...opts.subsystem ? { subsystem: opts.subsystem } : {},
1159
- // Flag > env > single provider-default model. Only pass `models` when the
1160
- // flag is set; otherwise let runDeepReview resolve $0SEC_DEEP_REVIEW_MODELS.
1161
- ...opts.models ? { models: opts.models.split(",").map((s) => s.trim()).filter(Boolean) } : {},
1162
- ...opts.attempts ? { attemptsPerCandidate: parsePositive2("--attempts", opts.attempts, defaultAttempts()) } : {},
1163
- concurrency: parsePositive2("--concurrency", opts.concurrency, DEFAULT_CONCURRENCY),
1164
- maxCandidates: parsePositive2("--max-candidates", opts.maxCandidates, defaultMaxCandidates()),
1165
- ...opts.quorum ? { quorum: parsePositive2("--quorum", opts.quorum, 1) } : {},
1166
- ...opts.threatModel ? { useThreatModel: true } : {},
1167
- ...opts.runtime ? { runtime: opts.runtime } : {},
1168
- ...opts.evolutionConfig ? { evolutionConfig: loadEvolutionConfigFile(opts.evolutionConfig) } : {},
1169
- timeoutMs: parsePositive2("--timeout", opts.timeout, 6e5),
1170
- log: (m) => process.stderr.write(m + "\n")
1171
- });
1172
- if (outcome.report) {
1173
- const storage = resolveOsecRunStorage();
1174
- writeOsecRunReport(storage, outcome.report);
1175
- }
1176
- const json = JSON.stringify(outcome.result, null, 2);
1177
- if (opts.output) writeFileSync3(resolve2(opts.output), json + "\n", "utf8");
1178
- else process.stdout.write(json + "\n");
1179
- process.exitCode = outcome.exitCode;
1180
- }
1181
- function registerDeepReviewCommand(program) {
1182
- program.command("deep-review").description(
1183
- "Seedless DEPTH review of a source tree: enumerate candidate files, re-hunt each through the profile's specialized finder lenses, and gate survivors through the multi-lens verify quorum. Emits LEADS to verify (not confirmed bugs). Exit 0=sweep completed (with or without leads), 2=skipped (no files / over the review cap), 3=error (bad flags / unreadable target / all finders failed)."
1184
- ).argument("<target>", "Source tree to review (a local path or a git URL)").option("--profile <p>", "Lens profile: evm-onchain | solana-onchain | cardano-onchain | cairo-onchain | move-onchain (else a generic default lens set)").option("--subsystem <path>", "Narrow the review scope to a subdirectory (respects the 5000-file review cap)").option("--evolution-config <path>", "Use the active source finder with private local execution receipts").option("--models <a,b>", "Comma-separated finder models for diversity (default: single provider model, or $0SEC_DEEP_REVIEW_MODELS)").option("--attempts <N>", `Finder attempts per candidate\xD7lens\xD7model, best-of-N (default ${DEFAULT_ATTEMPTS}, or $0SEC_DEEP_REVIEW_ATTEMPTS)`).option("--concurrency <N>", `Max finders in flight (default ${DEFAULT_CONCURRENCY})`).option("--cost-ceiling <usd>", "Hard scan-wide USD ceiling. Overrides $0SEC_COST_CEILING_USD.").option("--max-candidates <N>", `Cap candidate files hunted, largest-first (default ${DEFAULT_MAX_CANDIDATES}, or $0SEC_DEEP_REVIEW_MAX_CANDIDATES)`).option("--threat-model", "Enable pre-selection threat-model planner pass (trust-boundary lanes); default OFF").option("--quorum <N>", "Multi-lens verify quorum (default: majority of the verify-lens count)").option("--format <fmt>", "Output format (json)", "json").option("--output <path>", "Write the result JSON to this path instead of stdout").option("--runtime <mode>", "Engine runtime (default api)").option("--timeout <ms>", "Cloud agent timeout budget in milliseconds", "600000").action(async (target, opts) => {
1185
- try {
1186
- await deepReviewAction(target, opts);
1187
- } catch (err) {
1188
- const reason = err instanceof Error ? err.message : String(err);
1189
- const json = JSON.stringify({ mode: "deep_review", error: reason }, null, 2);
1190
- if (opts.output) {
1191
- const { writeFileSync: writeFileSync3 } = await import("node:fs");
1192
- try {
1193
- writeFileSync3(resolve2(opts.output), json + "\n", "utf8");
1194
- } catch {
1195
- process.stderr.write(json + "\n");
1196
- }
1197
- } else process.stdout.write(json + "\n");
1198
- process.exitCode = 3;
1199
- }
1200
- });
96
+ return `https://0.security/r#${b64}`;
1201
97
  }
1202
98
 
1203
99
  // packages/cli/src/finding-handoff.ts
@@ -1285,7 +181,7 @@ function shellQuote(value) {
1285
181
  }
1286
182
  function buildFindingConsoleCommand(finding, dbPath, intent = "investigate") {
1287
183
  const args = [
1288
- "0sec console",
184
+ "0 console",
1289
185
  "--finding",
1290
186
  shellQuote(finding.id),
1291
187
  "--finding-intent",
@@ -1296,7 +192,7 @@ function buildFindingConsoleCommand(finding, dbPath, intent = "investigate") {
1296
192
  }
1297
193
 
1298
194
  // packages/cli/src/finding-focus.ts
1299
- import { resolve as resolve3 } from "node:path";
195
+ import { resolve } from "node:path";
1300
196
  import { existsSync } from "node:fs";
1301
197
  function parseJson(value) {
1302
198
  if (value == null) return void 0;
@@ -1308,11 +204,11 @@ function parseJson(value) {
1308
204
  }
1309
205
  }
1310
206
  function databasePaths(dbPath) {
1311
- if (dbPath?.trim()) return [resolve3(dbPath)];
207
+ if (dbPath?.trim()) return [resolve(dbPath)];
1312
208
  return [...new Set([
1313
209
  ...listOsecRunDatabasePaths(),
1314
210
  resolveOsecDbPath()
1315
- ].map((path) => resolve3(path)))];
211
+ ].map((path) => resolve(path)))];
1316
212
  }
1317
213
  function findingFromRow(row, reviewFields) {
1318
214
  const id = typeof row.id === "string" ? row.id : "";
@@ -1408,9 +304,9 @@ function loadFindingFocus(id, options = {}) {
1408
304
  }
1409
305
 
1410
306
  // packages/cli/src/commands/lens-synth.ts
1411
- import { createHash as createHash2 } from "node:crypto";
1412
- import { readFileSync as readFileSync3 } from "node:fs";
1413
- import { resolve as resolve4 } from "node:path";
307
+ import { createHash } from "node:crypto";
308
+ import { readFileSync } from "node:fs";
309
+ import { resolve as resolve2 } from "node:path";
1414
310
  function isRecord(value) {
1415
311
  return typeof value === "object" && value !== null && !Array.isArray(value);
1416
312
  }
@@ -1466,10 +362,10 @@ function parseMissInputFile(raw) {
1466
362
  return { misses, corpus };
1467
363
  }
1468
364
  async function harvestBenchMisses(fromBench, manifestPath) {
1469
- const ledger = await loadLedger(resolve4(fromBench));
365
+ const ledger = await loadLedger(resolve2(fromBench));
1470
366
  const entry = lastGreen(ledger) ?? ledger.entries[ledger.entries.length - 1];
1471
367
  if (!entry) throw new Error(`--from-bench: ledger ${fromBench} has no entries to harvest`);
1472
- const manifest = await loadManifest(resolve4(manifestPath));
368
+ const manifest = await loadManifest(resolve2(manifestPath));
1473
369
  const result = harvestMissesFromLedgerEntry(entry, manifest);
1474
370
  return { misses: result.misses, result };
1475
371
  }
@@ -1487,7 +383,7 @@ async function runLensSynthesisInput(input, opts, deps = {}) {
1487
383
  ...deps.model ? { model: deps.model } : {},
1488
384
  ...opts.model ? { modelId: opts.model } : {},
1489
385
  probe,
1490
- ...opts.registry ? { registryPath: resolve4(opts.registry) } : {},
386
+ ...opts.registry ? { registryPath: resolve2(opts.registry) } : {},
1491
387
  maxRegistrations: opts.maxRegister ?? 1,
1492
388
  dryRun: !opts.promote,
1493
389
  trials,
@@ -1496,7 +392,7 @@ async function runLensSynthesisInput(input, opts, deps = {}) {
1496
392
  });
1497
393
  }
1498
394
  async function runLensSynthCommand(opts, deps = {}) {
1499
- const raw = JSON.parse(readFileSync3(resolve4(opts.missInput), "utf8"));
395
+ const raw = JSON.parse(readFileSync(resolve2(opts.missInput), "utf8"));
1500
396
  let input = parseMissInputFile(raw);
1501
397
  if (opts.fromBench) {
1502
398
  if (!opts.manifest) throw new Error("--from-bench requires --manifest");
@@ -1507,7 +403,7 @@ async function runLensSynthCommand(opts, deps = {}) {
1507
403
  return runLensSynthesisInput(input, opts, deps);
1508
404
  }
1509
405
  async function watchLensSynthCommand(opts, deps = {}) {
1510
- const inputPath = resolve4(opts.missInput);
406
+ const inputPath = resolve2(opts.missInput);
1511
407
  const log = deps.log ?? (() => {
1512
408
  });
1513
409
  const requestedInterval = opts.pollIntervalMs ?? 2e3;
@@ -1516,8 +412,8 @@ async function watchLensSynthCommand(opts, deps = {}) {
1516
412
  let previousRevision;
1517
413
  while (!deps.signal?.aborted) {
1518
414
  try {
1519
- const bytes = readFileSync3(inputPath);
1520
- const revision = createHash2("sha256").update(bytes).digest("hex");
415
+ const bytes = readFileSync(inputPath);
416
+ const revision = createHash("sha256").update(bytes).digest("hex");
1521
417
  if (revision !== previousRevision) {
1522
418
  previousRevision = revision;
1523
419
  const input = parseMissInputFile(JSON.parse(bytes.toString("utf8")));
@@ -1584,9 +480,9 @@ function formatLensRegistryStatus(status) {
1584
480
  return lines.join("\n");
1585
481
  }
1586
482
  function registerLensSynthCommand(program) {
1587
- program.command("lens-synth").description("Evolve appsec finder coverage from curated misses; promotion is corpus-gated and active reviews stay pinned").option("--miss-input <path>", "curated miss-input JSON ({ misses, corpus })").option("--registry <path>", "durable overlay path (default: ~/.0sec/lenses/appsec-archetypes.json)").option("--max-register <n>", "cap promoted champions per input revision", (value) => Number.parseInt(value, 10)).option("-m, --model <id>", "synthesis model override").option("--promote", "persist a validated champion to the durable overlay", false).option("--trials <n>", "repeated validation trials (2\u201310; default 2)", Number).option("--from-bench <ledger>", "harvest the champion's false-negatives from a benchmark ledger into the curated misses (requires --manifest)").option("--manifest <path>", "bench manifest path (ground-truth vuln class + sink); required with --from-bench").option("--watch", "poll the miss-input and process each new content revision", false).option("--poll-interval <ms>", "watch polling interval (minimum 100ms)", "2000").option("--status", "show the active durable overlay and promotion ledger", false).option("--rollback <lens-id>", "retire one previously promoted overlay lens").option("--json", "print machine-readable output", false).action(async (opts) => {
483
+ program.command("lens-synth").description("Evolve appsec finder coverage from curated misses; promotion is corpus-gated and active reviews stay pinned").option("--miss-input <path>", "curated miss-input JSON ({ misses, corpus })").option("--registry <path>", "durable overlay path (default: ~/.0/lenses/appsec-archetypes.json)").option("--max-register <n>", "cap promoted champions per input revision", (value) => Number.parseInt(value, 10)).option("-m, --model <id>", "synthesis model override").option("--promote", "persist a validated champion to the durable overlay", false).option("--trials <n>", "repeated validation trials (2\u201310; default 2)", Number).option("--from-bench <ledger>", "harvest the champion's false-negatives from a benchmark ledger into the curated misses (requires --manifest)").option("--manifest <path>", "bench manifest path (ground-truth vuln class + sink); required with --from-bench").option("--watch", "poll the miss-input and process each new content revision", false).option("--poll-interval <ms>", "watch polling interval (minimum 100ms)", "2000").option("--status", "show the active durable overlay and promotion ledger", false).option("--rollback <lens-id>", "retire one previously promoted overlay lens").option("--json", "print machine-readable output", false).action(async (opts) => {
1588
484
  try {
1589
- const registry = opts.registry ? resolve4(opts.registry) : void 0;
485
+ const registry = opts.registry ? resolve2(opts.registry) : void 0;
1590
486
  if (opts.status && opts.rollback) throw new Error("--status and --rollback cannot be combined");
1591
487
  if (opts.status) {
1592
488
  const status = inspectLensRegistry(registry);
@@ -1625,7 +521,7 @@ function registerLensSynthCommand(program) {
1625
521
  promote: Boolean(opts.promote),
1626
522
  trials: trialCount(opts.trials),
1627
523
  ...opts.fromBench ? { fromBench: String(opts.fromBench) } : {},
1628
- ...opts.manifest ? { manifest: resolve4(String(opts.manifest)) } : {}
524
+ ...opts.manifest ? { manifest: resolve2(String(opts.manifest)) } : {}
1629
525
  };
1630
526
  const printResult = (result) => {
1631
527
  process.stdout.write(
@@ -1669,388 +565,12 @@ function registerLensSynthCommand(program) {
1669
565
  });
1670
566
  }
1671
567
 
1672
- // packages/cli/src/commands/auth.ts
1673
- import { spawn } from "node:child_process";
1674
- import { mkdirSync, writeFileSync as writeFileSync2, chmodSync, unlinkSync, existsSync as existsSync2 } from "node:fs";
1675
- import { homedir, platform } from "node:os";
1676
- import { join as join2 } from "node:path";
1677
- import { randomBytes } from "node:crypto";
1678
- import { setTimeout as delay } from "node:timers/promises";
1679
- var EXIT_OK = 0;
1680
- var EXIT_USER_ERROR = 1;
1681
- var EXIT_AUTH = 2;
1682
- var EXIT_NET = 3;
1683
- function registerAuthCommand(program) {
1684
- const auth = program.command("auth").description("0sec-cloud authentication");
1685
- auth.command("login").description("Log in to 0sec-cloud (opens browser; --token to paste directly)").option("--host <url>", `Cloud host (default ${DEFAULT_CLOUD_HOST})`).option("--token <value>", "Skip the browser flow and persist this token directly").action(async (opts) => {
1686
- await runLogin(opts);
1687
- });
1688
- auth.command("logout").description("Delete ~/.0sec/cloud.env").action(() => {
1689
- runLogout({});
1690
- });
1691
- auth.command("status").description("Verify 0sec-cloud credentials against /health").action(async () => {
1692
- await runStatus({});
1693
- });
1694
- }
1695
- async function hostedBrowserLoginFlow(opts = {}) {
1696
- const host = normaliseHostArg(opts.host ?? DEFAULT_CLOUD_HOST);
1697
- if (host === null) {
1698
- return { ok: false, error: "Cloud host must be an http(s) URL without credentials, query or fragment." };
1699
- }
1700
- const attempts = opts.pollAttempts ?? 150;
1701
- const intervalMs = opts.pollIntervalMs ?? 2e3;
1702
- if (!Number.isSafeInteger(attempts) || attempts <= 0 || !Number.isFinite(intervalMs) || intervalMs < 0) {
1703
- return { ok: false, error: "Invalid sign-in polling budget." };
1704
- }
1705
- const cancelled = () => {
1706
- opts.onStatus?.("cancelled", "Sign-in cancelled.");
1707
- return { ok: false, error: "Sign-in cancelled.", recoverable: true, cancelled: true };
1708
- };
1709
- if (opts.signal?.aborted) return cancelled();
1710
- const deadline = new AbortController();
1711
- const timer = setTimeout(() => deadline.abort(), 3e5);
1712
- const signal = opts.signal ? AbortSignal.any([opts.signal, deadline.signal]) : deadline.signal;
1713
- const session = randomBytes(9).toString("base64url").slice(0, 12);
1714
- const loginUrl = `${host}/cli-auth?session=${session}`;
1715
- const pollUrl = `${host}/cli-auth/sessions/${session}`;
1716
- const timedOut = () => {
1717
- opts.onStatus?.("timeout", "Sign-in timed out. Try again.");
1718
- return { ok: false, error: "Sign-in timed out. Try again.", recoverable: true };
1719
- };
1720
- try {
1721
- opts.onStatus?.("opening", "Opening browser for 0sec Cloud sign-in.", loginUrl);
1722
- signal.throwIfAborted();
1723
- try {
1724
- await awaitLoginStep(Promise.resolve().then(() => {
1725
- signal.throwIfAborted();
1726
- return (opts.openBrowser ?? defaultOpenBrowser)(loginUrl);
1727
- }), signal);
1728
- } catch {
1729
- signal.throwIfAborted();
1730
- opts.onStatus?.("opener-failed", "Could not open a browser. Open this sign-in URL manually.", loginUrl);
1731
- }
1732
- const fetcher = opts.fetchImpl ?? fetch;
1733
- for (let i = 0; i < attempts; i++) {
1734
- signal.throwIfAborted();
1735
- opts.onStatus?.("polling", "Waiting for browser sign-in.", loginUrl);
1736
- signal.throwIfAborted();
1737
- await awaitLoginStep(
1738
- opts.sleep ? opts.sleep(intervalMs) : delay(intervalMs, void 0, { signal }),
1739
- signal
1740
- );
1741
- signal.throwIfAborted();
1742
- const request = new AbortController();
1743
- const requestTimer = setTimeout(() => request.abort(), 1e4);
1744
- const requestSignal = AbortSignal.any([signal, request.signal]);
1745
- try {
1746
- let res;
1747
- try {
1748
- res = await awaitLoginStep(fetcher(pollUrl, {
1749
- method: "GET",
1750
- headers: { Accept: "application/json" },
1751
- signal: requestSignal,
1752
- redirect: "error"
1753
- }), requestSignal);
1754
- } catch {
1755
- signal.throwIfAborted();
1756
- continue;
1757
- }
1758
- signal.throwIfAborted();
1759
- if (res.status === 200) {
1760
- let body;
1761
- try {
1762
- body = await awaitLoginStep(res.json(), requestSignal);
1763
- } catch {
1764
- signal.throwIfAborted();
1765
- if (requestSignal.aborted) continue;
1766
- return { ok: false, error: "Login response was not valid JSON." };
1767
- }
1768
- signal.throwIfAborted();
1769
- const rawStatus = body && typeof body === "object" ? body.status : void 0;
1770
- const status = sessionStatus(body);
1771
- const token = extractToken(body);
1772
- if (token) {
1773
- if (rawStatus !== void 0 && status !== "ready") {
1774
- return { ok: false, error: "Login returned credentials before the session was ready." };
1775
- }
1776
- try {
1777
- persistCredentials(host, token, opts.homeDir);
1778
- } catch {
1779
- return { ok: false, error: "Could not save 0sec Cloud credentials." };
1780
- }
1781
- opts.onStatus?.("ready", "Signed in to 0sec Cloud.");
1782
- return { ok: true, host };
1783
- }
1784
- if (status === "pending") continue;
1785
- if (status === "expired") return { ok: false, error: "Sign-in request expired. Try again.", recoverable: true };
1786
- return { ok: false, error: "Login response did not contain valid credentials." };
1787
- }
1788
- if ([202, 204, 404].includes(res.status)) continue;
1789
- if (res.status === 410) return { ok: false, error: "Sign-in request expired. Try again.", recoverable: true };
1790
- return {
1791
- ok: false,
1792
- error: `0sec Cloud sign-in unavailable (HTTP ${res.status}). Use your own provider or try again later.`,
1793
- recoverable: res.status === 429 || res.status >= 500
1794
- };
1795
- } finally {
1796
- clearTimeout(requestTimer);
1797
- request.abort();
1798
- }
1799
- }
1800
- return timedOut();
1801
- } catch (error) {
1802
- if (opts.signal?.aborted) return cancelled();
1803
- if (deadline.signal.aborted) return timedOut();
1804
- throw error;
1805
- } finally {
1806
- clearTimeout(timer);
1807
- }
1808
- }
1809
- async function awaitLoginStep(operation, signal) {
1810
- return new Promise((resolve6, reject) => {
1811
- const onAbort = () => {
1812
- signal.removeEventListener("abort", onAbort);
1813
- reject(signal.reason);
1814
- };
1815
- operation.then(
1816
- (value) => {
1817
- signal.removeEventListener("abort", onAbort);
1818
- resolve6(value);
1819
- },
1820
- (error) => {
1821
- signal.removeEventListener("abort", onAbort);
1822
- reject(error);
1823
- }
1824
- );
1825
- if (signal.aborted) onAbort();
1826
- else signal.addEventListener("abort", onAbort, { once: true });
1827
- });
1828
- }
1829
- async function runLogin(opts) {
1830
- const host = normaliseHostArg(opts.host ?? DEFAULT_CLOUD_HOST);
1831
- if (host === null) {
1832
- consolePresentationOutput.stderr(source_default.red("Error: Cloud host must be an http(s) URL without credentials, query or fragment."), "auth.login.host-error");
1833
- process.exitCode = EXIT_USER_ERROR;
1834
- return;
1835
- }
1836
- if (opts.token !== void 0) {
1837
- const tok = opts.token.trim();
1838
- if (!validCloudToken(tok)) {
1839
- consolePresentationOutput.stderr(source_default.red("Error: --token must be a nonempty credential without whitespace."), "auth.login.token-empty");
1840
- process.exitCode = EXIT_USER_ERROR;
1841
- return;
1842
- }
1843
- try {
1844
- persistCredentials(host, tok, opts.homeDir);
1845
- } catch {
1846
- consolePresentationOutput.stderr(source_default.red("Could not save 0sec Cloud credentials."), "auth.login.save-error");
1847
- process.exitCode = EXIT_USER_ERROR;
1848
- return;
1849
- }
1850
- consolePresentationOutput.stdout(`Logged in (host=${host})`, "auth.login.logged-in");
1851
- process.exitCode = EXIT_OK;
1852
- return;
1853
- }
1854
- const result = await hostedBrowserLoginFlow({
1855
- host,
1856
- pollAttempts: opts.pollAttempts,
1857
- pollIntervalMs: opts.pollIntervalMs,
1858
- openBrowser: opts.openBrowser,
1859
- fetchImpl: opts.fetchImpl,
1860
- homeDir: opts.homeDir,
1861
- sleep: opts.sleep,
1862
- onStatus: (phase, msg, url) => {
1863
- if (phase === "opening") {
1864
- consolePresentationOutput.stdout(source_default.dim("Opening browser..."), "auth.login.opening");
1865
- if (url) consolePresentationOutput.stdout(source_default.dim(` ${url}`), "auth.login.url");
1866
- consolePresentationOutput.stdout("", "auth.login.empty-line");
1867
- consolePresentationOutput.stdout(source_default.dim("Complete sign-in in the opened browser, then return here."), "auth.login.browser-hint");
1868
- consolePresentationOutput.stdout("", "auth.login.empty-line");
1869
- }
1870
- if (phase === "opener-failed") {
1871
- consolePresentationOutput.stderr(source_default.yellow(msg), "auth.login.browser-error");
1872
- }
1873
- }
1874
- });
1875
- if (result.ok) {
1876
- consolePresentationOutput.stdout(`Logged in (host=${result.host})`, "auth.login.logged-in");
1877
- process.exitCode = EXIT_OK;
1878
- } else {
1879
- consolePresentationOutput.stderr(source_default.red(result.error), "auth.login.error");
1880
- process.exitCode = result.recoverable ? EXIT_NET : EXIT_USER_ERROR;
1881
- }
1882
- }
1883
- function runLogout(opts) {
1884
- const home = opts.homeDir ?? homedir();
1885
- const osecPath = join2(homeStateDir(opts.homeDir), "cloud.env");
1886
- const cloudCredsPath = join2(home, ".0cloud", "credentials.json");
1887
- let deletedAny = false;
1888
- try {
1889
- unlinkSync(osecPath);
1890
- deletedAny = true;
1891
- } catch (err) {
1892
- const code = err.code;
1893
- if (code !== "ENOENT") {
1894
- consolePresentationOutput.stderr(source_default.red(`Could not delete ${osecPath}: ${err instanceof Error ? err.message : String(err)}`), "auth.logout.delete-error");
1895
- process.exitCode = EXIT_USER_ERROR;
1896
- return;
1897
- }
1898
- }
1899
- try {
1900
- unlinkSync(cloudCredsPath);
1901
- deletedAny = true;
1902
- } catch (err) {
1903
- const code = err.code;
1904
- if (code !== "ENOENT") {
1905
- consolePresentationOutput.stderr(source_default.red(`Could not delete ${cloudCredsPath}: ${err instanceof Error ? err.message : String(err)}`), "auth.logout.delete-error");
1906
- process.exitCode = EXIT_USER_ERROR;
1907
- return;
1908
- }
1909
- }
1910
- if (deletedAny) {
1911
- consolePresentationOutput.stdout("Logged out", "auth.logout.deleted");
1912
- } else {
1913
- consolePresentationOutput.stdout("Logged out (no credentials file was present)", "auth.logout.not-found");
1914
- }
1915
- process.exitCode = EXIT_OK;
1916
- }
1917
- async function runStatus(opts) {
1918
- let creds;
1919
- try {
1920
- const c = loadCloudCredentials();
1921
- creds = { host: c.host, token: c.token };
1922
- } catch (err) {
1923
- if (err instanceof CloudAuthMissingError) {
1924
- consolePresentationOutput.stderr(source_default.red(err.message), "auth.status.auth-missing");
1925
- process.exitCode = EXIT_AUTH;
1926
- return;
1927
- }
1928
- consolePresentationOutput.stderr(source_default.red(err instanceof Error ? err.message : String(err)), "auth.status.load-error");
1929
- process.exitCode = EXIT_AUTH;
1930
- return;
1931
- }
1932
- const client = new CloudClient({ ...creds, fetchImpl: opts.fetchImpl });
1933
- try {
1934
- await client.pingHealth();
1935
- consolePresentationOutput.stdout(`OK (host=${creds.host})`, "auth.status.ok");
1936
- process.exitCode = EXIT_OK;
1937
- } catch (err) {
1938
- handleStatusError(err);
1939
- }
1940
- }
1941
- function handleStatusError(err) {
1942
- if (err instanceof CloudUnauthorizedError) {
1943
- consolePresentationOutput.stderr("FAIL (HTTP 401)", "auth.status.unauthorized");
1944
- process.exitCode = EXIT_AUTH;
1945
- return;
1946
- }
1947
- if (err instanceof CloudForbiddenError) {
1948
- consolePresentationOutput.stderr(source_default.red(`FAIL (HTTP 403) \u2014 status: ${err.message}`), "auth.status.forbidden");
1949
- process.exitCode = EXIT_AUTH;
1950
- return;
1951
- }
1952
- if (err instanceof CloudNetworkError) {
1953
- consolePresentationOutput.stderr(source_default.red(`FAIL (network) \u2014 status: ${err.message}`), "auth.status.network-error");
1954
- process.exitCode = EXIT_NET;
1955
- return;
1956
- }
1957
- if (err instanceof CloudError) {
1958
- consolePresentationOutput.stderr(source_default.red(`FAIL (HTTP ${err.status ?? "?"}) \u2014 status`), "auth.status.cloud-error");
1959
- process.exitCode = EXIT_USER_ERROR;
1960
- return;
1961
- }
1962
- consolePresentationOutput.stderr(source_default.red(`FAIL \u2014 status: ${err instanceof Error ? err.message : String(err)}`), "auth.status.error");
1963
- process.exitCode = EXIT_USER_ERROR;
1964
- }
1965
- function normaliseHostArg(host) {
1966
- if (!host?.trim()) return null;
1967
- try {
1968
- const url = new URL(host.trim());
1969
- if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) return null;
1970
- return url.href.replace(/\/+$/, "");
1971
- } catch {
1972
- return null;
1973
- }
1974
- }
1975
- function persistCredentials(host, token, homeDirOverride) {
1976
- if (!validCloudToken(token)) throw new Error("Invalid Cloud credential");
1977
- const home = homeDirOverride ?? homedir();
1978
- const dir = homeStateDir(homeDirOverride);
1979
- mkdirSync(dir, { recursive: true, mode: 448 });
1980
- const path = join2(dir, "cloud.env");
1981
- const body = `# 0sec-cloud credentials. Managed by \`0sec auth\`.
1982
- # DO NOT commit this file or share its contents.
1983
- 0SEC_CLOUD_HOST=${host}
1984
- 0SEC_CLOUD_TOKEN=${token}
1985
- `;
1986
- writeFileSync2(path, body, { mode: 384 });
1987
- chmodSync(path, 384);
1988
- if (!existsSync2(path)) {
1989
- return;
1990
- }
1991
- try {
1992
- const cloudDir = join2(home, ".0cloud");
1993
- mkdirSync(cloudDir, { recursive: true });
1994
- const cloudCredsPath = join2(cloudDir, "credentials.json");
1995
- const trimmedHost = host.replace(/\/+$/, "");
1996
- const apiEndpoint = trimmedHost.endsWith("/api") ? trimmedHost : `${trimmedHost}/api`;
1997
- const cloudCreds = JSON.stringify(
1998
- {
1999
- token,
2000
- orgId: "",
2001
- endpoint: apiEndpoint,
2002
- dashboardUrl: host,
2003
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
2004
- },
2005
- null,
2006
- 2
2007
- ) + "\n";
2008
- writeFileSync2(cloudCredsPath, cloudCreds, { mode: 384 });
2009
- chmodSync(cloudCredsPath, 384);
2010
- } catch {
2011
- }
2012
- }
2013
- function sessionStatus(body) {
2014
- if (!body || typeof body !== "object") return void 0;
2015
- const status = body.status;
2016
- return status === "pending" || status === "ready" || status === "expired" ? status : void 0;
2017
- }
2018
- function validCloudToken(value) {
2019
- return typeof value === "string" && value.trim().length > 0 && !/[\s\x00-\x1f\x7f]/.test(value.trim());
2020
- }
2021
- function extractToken(body) {
2022
- if (!body || typeof body !== "object") return null;
2023
- const obj = body;
2024
- const candidates = [obj.token, obj.access_token];
2025
- for (const c of candidates) {
2026
- if (validCloudToken(c)) return c.trim();
2027
- }
2028
- return null;
2029
- }
2030
- function defaultOpenBrowser(url) {
2031
- const plat = platform();
2032
- return new Promise((resolve6, reject) => {
2033
- const options = { detached: true, stdio: "ignore", shell: false };
2034
- const child = plat === "darwin" ? spawn("open", [url], options) : plat === "win32" ? spawn("powershell.exe", [
2035
- "-NoProfile",
2036
- "-NonInteractive",
2037
- "-Command",
2038
- "Start-Process -FilePath $env:OSEC_BROWSER_LOGIN_URL"
2039
- ], { ...options, env: { ...process.env, OSEC_BROWSER_LOGIN_URL: url } }) : spawn("xdg-open", [url], options);
2040
- child.once("error", reject);
2041
- child.once("spawn", () => {
2042
- child.unref();
2043
- resolve6();
2044
- });
2045
- });
2046
- }
2047
-
2048
568
  // packages/cli/src/commands/run.ts
2049
569
  import { writeFile } from "node:fs/promises";
2050
- import { join as join3, resolve as resolve5 } from "node:path";
570
+ import { join, resolve as resolve3 } from "node:path";
2051
571
  import { tmpdir } from "node:os";
2052
572
  import { execFile } from "node:child_process";
2053
- import { existsSync as existsSync3 } from "node:fs";
573
+ import { existsSync as existsSync2 } from "node:fs";
2054
574
  import { fileURLToPath } from "node:url";
2055
575
 
2056
576
  // packages/cli/src/formatters/terminal.ts
@@ -2177,7 +697,7 @@ var EVIDENCE_BLOCK_LIMIT = 4e3;
2177
697
  var POC_STEP_LIMIT = 20;
2178
698
  function formatMarkdown(report) {
2179
699
  const lines = [];
2180
- lines.push("# 0sec Scan Report");
700
+ lines.push("# 0 Scan Report");
2181
701
  lines.push("");
2182
702
  lines.push(`| Field | Value |`);
2183
703
  lines.push(`|-------|-------|`);
@@ -2434,7 +954,7 @@ function formatHtml(report) {
2434
954
  <head>
2435
955
  <meta charset="UTF-8">
2436
956
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
2437
- <title>0sec Report \u2014 ${escapeHtml(report.target)}</title>
957
+ <title>0 Report \u2014 ${escapeHtml(report.target)}</title>
2438
958
  <style>
2439
959
  * { margin: 0; padding: 0; box-sizing: border-box; }
2440
960
  body {
@@ -2698,7 +1218,7 @@ function formatHtml(report) {
2698
1218
  <div class="header">
2699
1219
  <div class="header-top">
2700
1220
  <div>
2701
- <div class="brand">0SEC</div>
1221
+ <div class="brand">ZERO</div>
2702
1222
  <div class="brand-sub">Security Scan Report</div>
2703
1223
  </div>
2704
1224
  <div class="risk-badge" style="background:${risk.color};color:#fff">${risk.label} RISK</div>
@@ -2739,7 +1259,7 @@ function formatHtml(report) {
2739
1259
  </div>
2740
1260
 
2741
1261
  <div class="footer">
2742
- Generated by 0sec &middot; ${escapeHtml((/* @__PURE__ */ new Date()).toISOString())}
1262
+ Generated by 0 &middot; ${escapeHtml((/* @__PURE__ */ new Date()).toISOString())}
2743
1263
  </div>
2744
1264
  </body>
2745
1265
  </html>`;
@@ -2875,9 +1395,9 @@ function formatSarif(report) {
2875
1395
  {
2876
1396
  tool: {
2877
1397
  driver: {
2878
- name: "0sec",
1398
+ name: "0",
2879
1399
  version: VERSION,
2880
- informationUri: "https://github.com/0sec-labs/0sec",
1400
+ informationUri: "https://github.com/0sec-labs/0",
2881
1401
  rules: Array.from(rulesMap.values())
2882
1402
  }
2883
1403
  },
@@ -2953,13 +1473,13 @@ function truncate(text, maxLen) {
2953
1473
  async function generatePdfReport(report, outputPath) {
2954
1474
  const require_ = createRequire(import.meta.url);
2955
1475
  const PDFDocument = require_("pdfkit");
2956
- return new Promise((resolve6, reject) => {
1476
+ return new Promise((resolve4, reject) => {
2957
1477
  const doc = new PDFDocument({
2958
1478
  size: "LETTER",
2959
1479
  margins: { top: PAGE_MARGIN, bottom: PAGE_MARGIN, left: PAGE_MARGIN, right: PAGE_MARGIN },
2960
1480
  info: {
2961
- Title: `0sec Pentest Report - ${report.target}`,
2962
- Author: "0sec",
1481
+ Title: `0 Pentest Report - ${report.target}`,
1482
+ Author: "0",
2963
1483
  Subject: "Automated Penetration Test Report",
2964
1484
  CreationDate: /* @__PURE__ */ new Date()
2965
1485
  },
@@ -2967,7 +1487,7 @@ async function generatePdfReport(report, outputPath) {
2967
1487
  });
2968
1488
  const stream = createWriteStream(outputPath);
2969
1489
  stream.on("error", reject);
2970
- stream.on("finish", resolve6);
1490
+ stream.on("finish", resolve4);
2971
1491
  doc.pipe(stream);
2972
1492
  renderCoverPage(doc, report);
2973
1493
  renderExecutiveSummary(doc, report);
@@ -2980,7 +1500,7 @@ async function generatePdfReport(report, outputPath) {
2980
1500
  }
2981
1501
  function renderCoverPage(doc, report) {
2982
1502
  doc.rect(0, 0, 612, 792).fill(COLORS.primary);
2983
- doc.fontSize(48).font("Helvetica-Bold").fillColor(COLORS.accent).text("0sec", PAGE_MARGIN, 200, { align: "center" });
1503
+ doc.fontSize(48).font("Helvetica-Bold").fillColor(COLORS.accent).text("0", PAGE_MARGIN, 200, { align: "center" });
2984
1504
  doc.fontSize(14).font("Helvetica").fillColor(COLORS.white).text("Automated Penetration Test Report", PAGE_MARGIN, 260, { align: "center" });
2985
1505
  doc.moveTo(200, 300).lineTo(412, 300).strokeColor(COLORS.accent).lineWidth(2).stroke();
2986
1506
  doc.fontSize(18).font("Helvetica-Bold").fillColor(COLORS.white).text(report.target, PAGE_MARGIN, 330, { align: "center" });
@@ -3107,7 +1627,7 @@ function renderMethodology(doc, report) {
3107
1627
  doc.addPage();
3108
1628
  sectionTitle(doc, "Methodology");
3109
1629
  doc.fontSize(10).font("Helvetica").fillColor(COLORS.text).text(
3110
- "This report was generated by 0sec, a fully autonomous agentic pentesting framework. The tool uses AI-driven attack generation and multi-agent consensus verification to identify security vulnerabilities.",
1630
+ "This report was generated by 0, a fully autonomous agentic pentesting framework. The tool uses AI-driven attack generation and multi-agent consensus verification to identify security vulnerabilities.",
3111
1631
  PAGE_MARGIN,
3112
1632
  doc.y + 10,
3113
1633
  { width: CONTENT_WIDTH }
@@ -3184,7 +1704,7 @@ function renderFooters(doc) {
3184
1704
  doc.switchToPage(i);
3185
1705
  if (i === 0) continue;
3186
1706
  doc.fontSize(8).font("Helvetica").fillColor(COLORS.textLight).text(
3187
- `0sec Pentest Report | Page ${i + 1} of ${pageCount} | CONFIDENTIAL`,
1707
+ `0 Pentest Report | Page ${i + 1} of ${pageCount} | CONFIDENTIAL`,
3188
1708
  PAGE_MARGIN,
3189
1709
  760,
3190
1710
  { width: CONTENT_WIDTH, align: "center" }
@@ -3194,7 +1714,7 @@ function renderFooters(doc) {
3194
1714
 
3195
1715
  // packages/cli/src/formatters/replay.ts
3196
1716
  function sleep(ms) {
3197
- return new Promise((resolve6) => setTimeout(resolve6, ms));
1717
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
3198
1718
  }
3199
1719
  function stripAnsi(s) {
3200
1720
  return s.replace(/\x1b\[[0-9;]*m/g, "");
@@ -3383,7 +1903,7 @@ function buildReplayLines(data) {
3383
1903
  const duration = data.durationMs < 1e3 ? `${data.durationMs}ms` : `${(data.durationMs / 1e3).toFixed(1)}s`;
3384
1904
  lines.push({
3385
1905
  text: boxRow(
3386
- source_default.white(`Completed in ${duration}`) + source_default.dim(" \u2192 ") + source_default.gray("./0sec-report.json")
1906
+ source_default.white(`Completed in ${duration}`) + source_default.dim(" \u2192 ") + source_default.gray("./0-report.json")
3387
1907
  ),
3388
1908
  delay: MED
3389
1909
  });
@@ -3394,7 +1914,7 @@ async function renderReplay(data) {
3394
1914
  const lines = buildReplayLines(data);
3395
1915
  process.stdout.write("\n");
3396
1916
  process.stdout.write(
3397
- source_default.red.bold(" \u25C6 0sec") + source_default.gray(" attack replay") + "\n"
1917
+ source_default.red.bold(" \u25C6 0") + source_default.gray(" attack replay") + "\n"
3398
1918
  );
3399
1919
  process.stdout.write(
3400
1920
  source_default.dim(" " + "\u2500".repeat(BOX_WIDTH + 1)) + "\n"
@@ -3619,8 +2139,8 @@ var coreModulePromise = null;
3619
2139
  async function loadCoreModule() {
3620
2140
  if (!coreModulePromise) {
3621
2141
  const srcUrl = new URL("../../../core/src/index.ts", import.meta.url);
3622
- const srcExists = process.versions.bun && existsSync3(fileURLToPath(srcUrl));
3623
- coreModulePromise = srcExists ? import(srcUrl.href) : import("./dist-4YICS2J2.js");
2142
+ const srcExists = process.versions.bun && existsSync2(fileURLToPath(srcUrl));
2143
+ coreModulePromise = srcExists ? import(srcUrl.href) : import("./dist-3FNZIBB4.js");
3624
2144
  }
3625
2145
  return coreModulePromise;
3626
2146
  }
@@ -3664,16 +2184,8 @@ function getTargetType(report, opts) {
3664
2184
  return report?.targetType ?? opts.targetType;
3665
2185
  }
3666
2186
  function emitResultLine(payload) {
3667
- if (process.env["0SEC_EMIT_RESULT_LINE"] !== "1" && !process.env["0SEC_CLOUD_SINK"]) return;
3668
- console.log(`0SEC_RESULT=${JSON.stringify(payload)}`);
3669
- }
3670
- function getCloudFinalSinkConfig() {
3671
- if (process.env["0SEC_FEATURE_CLOUD_SINK"] === "0") return null;
3672
- const sinkUrl = process.env["0SEC_CLOUD_SINK"]?.trim();
3673
- const scanId = process.env["0SEC_CLOUD_SCAN_ID"]?.trim();
3674
- if (!sinkUrl || !scanId) return null;
3675
- const token = process.env["0SEC_CLOUD_TOKEN"]?.trim() || void 0;
3676
- return { sinkUrl, scanId, token };
2187
+ if (process.env["ZERO_EMIT_RESULT_LINE"] !== "1") return;
2188
+ console.log(`ZERO_RESULT=${JSON.stringify(payload)}`);
3677
2189
  }
3678
2190
  function isCostBreakdownEntry(value) {
3679
2191
  if (!value || typeof value !== "object") return false;
@@ -3746,55 +2258,6 @@ function printCrossValidatedLeads(summary) {
3746
2258
  console.log(source_default.gray(` +${summary.moreCount} more`));
3747
2259
  }
3748
2260
  }
3749
- async function postFinalResultToCloud(report) {
3750
- const config = getCloudFinalSinkConfig();
3751
- if (!config) return;
3752
- const url = `${config.sinkUrl.replace(/\/+$/, "")}/scans/${encodeURIComponent(config.scanId)}/findings`;
3753
- const headers = {
3754
- "Content-Type": "application/json",
3755
- "X-0sec-Scan-Id": config.scanId
3756
- };
3757
- if (config.token) headers.Authorization = `Bearer ${config.token}`;
3758
- try {
3759
- const res = await fetch(url, {
3760
- method: "POST",
3761
- headers,
3762
- body: JSON.stringify({ report, final: true })
3763
- });
3764
- if (!res.ok) {
3765
- const text = await res.text().catch(() => "");
3766
- process.stderr.write(
3767
- `[0sec cloud-sink] report POST ${url} returned ${res.status}: ${text.slice(0, 200)}
3768
- `
3769
- );
3770
- }
3771
- } catch (err) {
3772
- const msg = err instanceof Error ? err.message : String(err);
3773
- process.stderr.write(`[0sec cloud-sink] report POST ${url} failed: ${msg}
3774
- `);
3775
- }
3776
- }
3777
- function skippedLensReviewReport(target, message) {
3778
- const now = (/* @__PURE__ */ new Date()).toISOString();
3779
- return {
3780
- target,
3781
- scanDepth: "deep",
3782
- startedAt: now,
3783
- completedAt: now,
3784
- durationMs: 0,
3785
- summary: {
3786
- totalAttacks: 0,
3787
- totalFindings: 0,
3788
- critical: 0,
3789
- high: 0,
3790
- medium: 0,
3791
- low: 0,
3792
- info: 0
3793
- },
3794
- findings: [],
3795
- warnings: [{ stage: "attack", message }]
3796
- };
3797
- }
3798
2261
  async function runUnified(opts) {
3799
2262
  const { target, depth, format, runtime, timeout } = opts;
3800
2263
  const core = await loadCoreModule();
@@ -3804,7 +2267,7 @@ async function runUnified(opts) {
3804
2267
  console.error(source_default.red("--branch-from requires --resume <run-id>"));
3805
2268
  process.exit(2);
3806
2269
  }
3807
- const { branchJournal } = await import("./dist-4YICS2J2.js");
2270
+ const { branchJournal } = await import("./dist-3FNZIBB4.js");
3808
2271
  const result = branchJournal({
3809
2272
  runId: effectiveResumeScanId,
3810
2273
  fromEntry: opts.branchFromEntry
@@ -3840,7 +2303,7 @@ async function runUnified(opts) {
3840
2303
  console.error(source_default.red(`Unknown runtime '${runtime}'. Valid: ${validRuntimes.join(", ")}`));
3841
2304
  process.exit(2);
3842
2305
  }
3843
- const directCodexProviderConfigured = runtime === "codex" && (!!process.env["0SEC_CHATGPT_ACCESS_TOKEN"]?.trim() || !!process.env["0SEC_CHATGPT_OAUTH_REFRESH_TOKEN"]?.trim());
2306
+ const directCodexProviderConfigured = runtime === "codex" && (!!process.env["ZERO_CHATGPT_ACCESS_TOKEN"]?.trim() || !!process.env["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"]?.trim());
3844
2307
  if (runtime !== "api" && runtime !== "auto" && !directCodexProviderConfigured) {
3845
2308
  const rt = core.createRuntime({ type: runtime, timeout });
3846
2309
  const available = await rt.isAvailable();
@@ -3859,9 +2322,9 @@ async function runUnified(opts) {
3859
2322
  if (opts.sessionUiFactory) {
3860
2323
  inkUI = await opts.sessionUiFactory({ target, depth, mode });
3861
2324
  } else {
3862
- const { isBunRuntime } = await import("./runtime-J7PLXZNM.js");
2325
+ const { isBunRuntime } = await import("./runtime-XFWJTBUO.js");
3863
2326
  if (isBunRuntime()) {
3864
- const { createOpenTuiSession } = await import("./run-D56MPDKY.js");
2327
+ const { createOpenTuiSession } = await import("./run-U3XU4CTC.js");
3865
2328
  const availability = await getRuntimeAvailability();
3866
2329
  inkUI = await createOpenTuiSession({
3867
2330
  target,
@@ -3875,7 +2338,7 @@ async function runUnified(opts) {
3875
2338
  model: opts.model
3876
2339
  });
3877
2340
  } else {
3878
- const { renderScanStream } = await import("./scan-stream-FHI2FYZE.js");
2341
+ const { renderScanStream } = await import("./scan-stream-BMOCPKQX.js");
3879
2342
  inkUI = renderScanStream({ version: VERSION, target, depth, mode });
3880
2343
  }
3881
2344
  }
@@ -3883,44 +2346,8 @@ async function runUnified(opts) {
3883
2346
  getPendingUserMessages = inkUI.getPendingUserMessages;
3884
2347
  }
3885
2348
  try {
3886
- let runnerExitCode = 0;
3887
2349
  let report;
3888
- if (opts.targetType === "source-code" && opts.reviewStrategy === "lenses") {
3889
- eventHandler({
3890
- type: "stage:start",
3891
- stage: "source-analysis",
3892
- message: "capturing the validated finder-lens snapshot"
3893
- });
3894
- const outcome = await runDeepReview({
3895
- target,
3896
- profile: opts.reviewProfile,
3897
- subsystem: opts.subsystem,
3898
- models: opts.model ? [opts.model] : void 0,
3899
- runtime,
3900
- timeoutMs: timeout,
3901
- costCeilingUsd: opts.costCeilingUsd,
3902
- log: (message) => eventHandler({
3903
- type: "stage:start",
3904
- stage: "attack",
3905
- message
3906
- })
3907
- });
3908
- runnerExitCode = outcome.exitCode;
3909
- const lensReport = outcome.report ?? skippedLensReviewReport(
3910
- target,
3911
- typeof outcome.result === "object" && outcome.result !== null && "note" in outcome.result ? String(outcome.result.note) : `lens review ended with exit code ${outcome.exitCode}`
3912
- );
3913
- report = lensReport;
3914
- writeOsecRunReport(
3915
- resolveOsecRunStorage({ ...opts.dbPath ? { dbPath: opts.dbPath } : {} }),
3916
- lensReport
3917
- );
3918
- eventHandler({
3919
- type: "stage:end",
3920
- stage: "attack",
3921
- message: outcome.exitCode === 0 ? "validated finder-lens review completed" : `validated finder-lens review ended with exit code ${outcome.exitCode}`
3922
- });
3923
- } else if (opts.targetType === "url" || opts.targetType === "web-app") {
2350
+ if (opts.targetType === "url" || opts.targetType === "web-app") {
3924
2351
  report = await core.agenticScan({
3925
2352
  config: {
3926
2353
  target,
@@ -3986,16 +2413,13 @@ async function runUnified(opts) {
3986
2413
  }
3987
2414
  const reportAny = report;
3988
2415
  const canonicalReport = toScanReport(report);
3989
- if (opts.targetType !== "url" && opts.targetType !== "web-app") {
3990
- await postFinalResultToCloud(reportAny);
3991
- }
3992
2416
  if (inkUI) {
3993
2417
  inkUI.setReport(report);
3994
2418
  await inkUI.waitForExit();
3995
2419
  } else {
3996
2420
  if (format === "html" || format === "pdf") {
3997
2421
  const extension = format === "pdf" ? "pdf" : "html";
3998
- const filePath = opts.reportPath ? resolve5(opts.reportPath) : join3(tmpdir(), `0sec-report-${Date.now()}.${extension}`);
2422
+ const filePath = opts.reportPath ? resolve3(opts.reportPath) : join(tmpdir(), `0-report-${Date.now()}.${extension}`);
3999
2423
  if (format === "pdf") {
4000
2424
  await generatePdfReport(toScanReport(reportAny), filePath);
4001
2425
  } else {
@@ -4015,7 +2439,7 @@ async function runUnified(opts) {
4015
2439
  console.log("");
4016
2440
  console.log(source_default.gray(" --tui post-scan view is no longer bundled in the npm package."));
4017
2441
  console.log(source_default.gray(" Install the standalone binary for the full OpenTUI experience:"));
4018
- console.log(source_default.gray(" curl -fsSL https://raw.githubusercontent.com/0sec-labs/0sec/main/install.sh | bash"));
2442
+ console.log(source_default.gray(" curl -fsSL https://raw.githubusercontent.com/0sec-labs/0/main/install.sh | bash"));
4019
2443
  console.log("");
4020
2444
  }
4021
2445
  if (crossValidatedLeads) {
@@ -4025,14 +2449,14 @@ async function runUnified(opts) {
4025
2449
  printCostSummary(scanCompletedCost);
4026
2450
  }
4027
2451
  unsubscribeCost();
4028
- let exitCode = runnerExitCode;
2452
+ let exitCode = 0;
4029
2453
  const estimatedCostUsd = getEstimatedCost(reportAny);
4030
2454
  const usage = getUsage(reportAny);
4031
2455
  if (opts.emit === "pr") {
4032
2456
  const findings = report.findings ?? [];
4033
2457
  const core2 = await loadCoreModule();
4034
- const repoRoot = opts.targetType === "source-code" && existsSync3(target) ? resolve5(target) : process.cwd();
4035
- const outDir = opts.emitOutDir ?? join3(tmpdir(), `0sec-emit-${Date.now()}`);
2458
+ const repoRoot = opts.targetType === "source-code" && existsSync2(target) ? resolve3(target) : process.cwd();
2459
+ const outDir = opts.emitOutDir ?? join(tmpdir(), `0-emit-${Date.now()}`);
4036
2460
  console.log(source_default.blue(`[emit pr] ${findings.length} finding(s); repo=${repoRoot} base=${opts.emitPrBase ?? "main"}${opts.emitPrDryRun ? " (dry-run)" : ""}`));
4037
2461
  const emitReport = await core2.emitFindingsAsPRs(findings, {
4038
2462
  repoRoot,
@@ -4063,7 +2487,7 @@ async function runUnified(opts) {
4063
2487
  if (findings.length === 0) {
4064
2488
  console.log(source_default.yellow("No findings to export."));
4065
2489
  } else {
4066
- const { exportToGitHubIssues } = await import("./github-issues-MJ6OYOOU.js");
2490
+ const { exportToGitHubIssues } = await import("./github-issues-IGTTWM7V.js");
4067
2491
  console.log(source_default.blue(`Exporting ${findings.length} finding(s) to GitHub Issues on ${repo}...`));
4068
2492
  const result = await exportToGitHubIssues(findings, repo);
4069
2493
  console.log(
@@ -4071,7 +2495,7 @@ async function runUnified(opts) {
4071
2495
  );
4072
2496
  }
4073
2497
  }
4074
- const ceilingRaw = process.env["0SEC_COST_CEILING_USD"]?.trim();
2498
+ const ceilingRaw = process.env["ZERO_COST_CEILING_USD"]?.trim();
4075
2499
  if (ceilingRaw) {
4076
2500
  const ceiling = Number(ceilingRaw);
4077
2501
  if (Number.isFinite(ceiling) && estimatedCostUsd !== void 0 && estimatedCostUsd > ceiling) {
@@ -4143,13 +2567,18 @@ var DEFAULT_ENCODED_RUN_MAX = 140;
4143
2567
  var ENCODED_RUN_MAX_CAP = 1e6;
4144
2568
  var ELLIPSIS = "...";
4145
2569
  var ENCODED_PLACEHOLDER = "[encoded payload omitted]";
2570
+ var DEFAULT_ENCODED_SEGMENT = new RegExp(`[A-Za-z0-9+_-]{${DEFAULT_ENCODED_RUN_MAX},}={0,2}`, "g");
2571
+ var DEFAULT_ENCODED_DATA_URI = new RegExp(`(data:[^\\s,]*;base64,)[A-Za-z0-9+/_-]{${DEFAULT_ENCODED_RUN_MAX},}={0,2}`, "gi");
4146
2572
  function stripTerminalControl(text) {
4147
2573
  return text.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
4148
2574
  }
4149
2575
  function replaceLargeEncodedChunks(text, maxEncodedRun) {
4150
2576
  const normalized = Number.isFinite(maxEncodedRun) ? Math.trunc(maxEncodedRun) : DEFAULT_ENCODED_RUN_MAX;
4151
2577
  const minRun = Math.min(Math.max(32, normalized), ENCODED_RUN_MAX_CAP);
4152
- return text.replace(new RegExp(`[A-Za-z0-9+/_-]{${minRun},}={0,2}`, "g"), ENCODED_PLACEHOLDER);
2578
+ if (text.length < minRun) return text;
2579
+ const segment = minRun === DEFAULT_ENCODED_RUN_MAX ? DEFAULT_ENCODED_SEGMENT : new RegExp(`[A-Za-z0-9+_-]{${minRun},}={0,2}`, "g");
2580
+ const dataUri = minRun === DEFAULT_ENCODED_RUN_MAX ? DEFAULT_ENCODED_DATA_URI : new RegExp(`(data:[^\\s,]*;base64,)[A-Za-z0-9+/_-]{${minRun},}={0,2}`, "gi");
2581
+ return text.replace(dataUri, `$1${ENCODED_PLACEHOLDER}`).replace(segment, ENCODED_PLACEHOLDER);
4153
2582
  }
4154
2583
  function sanitizeTuiText(value, options = {}) {
4155
2584
  return stripTerminalControl(replaceLargeEncodedChunks(String(value ?? ""), options.maxEncodedRun ?? DEFAULT_ENCODED_RUN_MAX)).replace(/\s+/g, " ").trim();
@@ -4287,20 +2716,6 @@ var SLASH_COMMANDS = [
4287
2716
  category: "info",
4288
2717
  description: "List available tools"
4289
2718
  },
4290
- {
4291
- name: "agents",
4292
- aliases: [],
4293
- category: "info",
4294
- description: "List available agents",
4295
- tuiOnly: true
4296
- },
4297
- {
4298
- name: "harness",
4299
- aliases: [],
4300
- category: "navigation",
4301
- description: "Live harness: views, commands, settings, rollback and workspace trust",
4302
- tuiOnly: true
4303
- },
4304
2719
  {
4305
2720
  name: "new-chat",
4306
2721
  aliases: ["new"],
@@ -4308,13 +2723,6 @@ var SLASH_COMMANDS = [
4308
2723
  description: "Create an independent audit using the staged model and connection",
4309
2724
  tuiOnly: true
4310
2725
  },
4311
- {
4312
- name: "audits",
4313
- aliases: [],
4314
- category: "navigation",
4315
- description: "Switch between live audits without stopping their work",
4316
- tuiOnly: true
4317
- },
4318
2726
  {
4319
2727
  name: "onboard",
4320
2728
  aliases: [],
@@ -4322,14 +2730,6 @@ var SLASH_COMMANDS = [
4322
2730
  description: "Reopen guided setup without replacing the current audit",
4323
2731
  tuiOnly: true
4324
2732
  },
4325
- {
4326
- name: "stop",
4327
- aliases: [],
4328
- category: "session",
4329
- description: "Stop this audit's work or one owned worker and its descendants",
4330
- usage: "/stop audit | /stop worker <exact name or id>",
4331
- tuiOnly: true
4332
- },
4333
2733
  // ── session ─────────────────────────────────────────────────────────────
4334
2734
  {
4335
2735
  name: "clear",
@@ -4344,13 +2744,6 @@ var SLASH_COMMANDS = [
4344
2744
  description: "Browse previous scan runs and their results",
4345
2745
  tuiOnly: true
4346
2746
  },
4347
- {
4348
- name: "transcript",
4349
- aliases: ["review"],
4350
- category: "session",
4351
- description: "Show this conversation, including tool details",
4352
- tuiOnly: true
4353
- },
4354
2747
  {
4355
2748
  name: "findings",
4356
2749
  aliases: ["finds"],
@@ -4359,11 +2752,11 @@ var SLASH_COMMANDS = [
4359
2752
  tuiOnly: true
4360
2753
  },
4361
2754
  {
4362
- name: "finding",
4363
- aliases: ["finding-detail"],
2755
+ name: "fix",
2756
+ aliases: [],
4364
2757
  category: "session",
4365
- description: "Open one finding in full detail to read and act on it",
4366
- usage: "/finding [id]",
2758
+ description: "Generate a verified local source fix; review before explicitly publishing a draft PR",
2759
+ usage: "/fix [finding-id] | /fix publish <finding-id> | /fix cancel",
4367
2760
  tuiOnly: true
4368
2761
  },
4369
2762
  {
@@ -4383,33 +2776,11 @@ var SLASH_COMMANDS = [
4383
2776
  tuiOnly: true
4384
2777
  },
4385
2778
  {
4386
- name: "replay",
4387
- aliases: [],
4388
- category: "session",
4389
- description: "Replay a previous turn or session",
4390
- tuiOnly: true
4391
- },
4392
- // ── mode ────────────────────────────────────────────────────────────────
4393
- {
4394
- name: "mode",
2779
+ name: "sessions",
4395
2780
  aliases: [],
4396
- category: "mode",
4397
- description: "Set Standard (approve actions), Co-pilot (in scope), YOLO (public-network autonomy), or Recon (passive)",
4398
- usage: "/mode [standard|copilot|yolo|recon]"
4399
- },
4400
- {
4401
- name: "resume",
4402
- aliases: ["sessions"],
4403
2781
  category: "session",
4404
- description: "Find and resume saved conversations",
4405
- usage: "/resume"
4406
- },
4407
- {
4408
- name: "providers",
4409
- aliases: [],
4410
- category: "system",
4411
- description: "Connection: 0sec Cloud, API keys, or provider subscriptions",
4412
- usage: "/providers",
2782
+ description: "Switch open sessions or resume saved conversations",
2783
+ usage: "/sessions",
4413
2784
  tuiOnly: true
4414
2785
  },
4415
2786
  {
@@ -4423,7 +2794,7 @@ var SLASH_COMMANDS = [
4423
2794
  name: "feedback",
4424
2795
  aliases: [],
4425
2796
  category: "system",
4426
- description: "Record feedback about 0sec to a local file you control, with optional HTTPS submission",
2797
+ description: "Record feedback about 0 to a local file you control, with optional HTTPS submission",
4427
2798
  usage: "/feedback <message> | /feedback submit <message> | /feedback send | /feedback cancel"
4428
2799
  },
4429
2800
  {
@@ -4452,7 +2823,7 @@ var SLASH_COMMANDS = [
4452
2823
  {
4453
2824
  name: "model",
4454
2825
  aliases: ["models"],
4455
- category: "mode",
2826
+ category: "session",
4456
2827
  description: "Show or select a model (TUI: applies to New chat)",
4457
2828
  usage: "/model [id]"
4458
2829
  },
@@ -4478,13 +2849,6 @@ var SLASH_COMMANDS = [
4478
2849
  description: "View active and recent operations",
4479
2850
  tuiOnly: true
4480
2851
  },
4481
- {
4482
- name: "herd",
4483
- aliases: ["workers"],
4484
- category: "navigation",
4485
- description: "Inspect the active harness worker herd",
4486
- tuiOnly: true
4487
- },
4488
2852
  {
4489
2853
  name: "comms",
4490
2854
  aliases: ["messages"],
@@ -4501,9 +2865,9 @@ var SLASH_COMMANDS = [
4501
2865
  },
4502
2866
  {
4503
2867
  name: "connect",
4504
- aliases: ["login", "auth"],
2868
+ aliases: [],
4505
2869
  category: "navigation",
4506
- description: "Connect to 0sec Cloud, or use your own API key or provider subscription",
2870
+ description: "Connect your API key or provider subscription",
4507
2871
  usage: "/connect",
4508
2872
  tuiOnly: true
4509
2873
  },
@@ -4605,7 +2969,7 @@ function filterCommands(query) {
4605
2969
  }
4606
2970
 
4607
2971
  // packages/cli/src/console-session.ts
4608
- import { randomUUID as randomUUID2 } from "node:crypto";
2972
+ import { randomUUID } from "node:crypto";
4609
2973
 
4610
2974
  // packages/cli/src/conversation-history.ts
4611
2975
  var MAX_PAGE_CHARS = 16e3;
@@ -4677,10 +3041,10 @@ function createConversationHistory(options = {}) {
4677
3041
 
4678
3042
  // packages/cli/src/dev-engine-updates.ts
4679
3043
  import { execFile as execFile2 } from "node:child_process";
4680
- import { createHash as createHash3 } from "node:crypto";
4681
- import { appendFileSync, readFileSync as readFileSync4, readdirSync, realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
3044
+ import { createHash as createHash2 } from "node:crypto";
3045
+ import { appendFileSync, readFileSync as readFileSync2, readdirSync, realpathSync, statSync } from "node:fs";
4682
3046
  import { mkdir, mkdtemp, rm } from "node:fs/promises";
4683
- import { isAbsolute, join as join4, relative as relative2, sep as sep2 } from "node:path";
3047
+ import { isAbsolute, join as join2, relative, sep } from "node:path";
4684
3048
  import { pathToFileURL } from "node:url";
4685
3049
  import { isDeepStrictEqual, promisify } from "node:util";
4686
3050
  var execute = promisify(execFile2);
@@ -4708,12 +3072,12 @@ function assertSessionContract(session) {
4708
3072
  }
4709
3073
  }
4710
3074
  function sourceDigest(root) {
4711
- const hash = createHash3("sha256");
3075
+ const hash = createHash2("sha256");
4712
3076
  const visit = (directory) => {
4713
3077
  const entries = readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
4714
3078
  for (const entry of entries) {
4715
3079
  if (entry.name.startsWith(".") || Object.hasOwn(ignoredSourceNames, entry.name)) continue;
4716
- const path = join4(directory, entry.name);
3080
+ const path = join2(directory, entry.name);
4717
3081
  if (entry.isDirectory()) {
4718
3082
  visit(path);
4719
3083
  continue;
@@ -4721,23 +3085,23 @@ function sourceDigest(root) {
4721
3085
  if (!entry.isFile() && !entry.isSymbolicLink() || /\.(test|spec)\.[cm]?[jt]sx?$/.test(entry.name) || entry.name.endsWith(".d.ts")) continue;
4722
3086
  let readable = path;
4723
3087
  if (entry.isSymbolicLink()) {
4724
- readable = realpathSync2(path);
4725
- const target = relative2(root, readable);
4726
- if (target === ".." || target.startsWith(`..${sep2}`) || isAbsolute(target) || !statSync2(readable).isFile()) {
3088
+ readable = realpathSync(path);
3089
+ const target = relative(root, readable);
3090
+ if (target === ".." || target.startsWith(`..${sep}`) || isAbsolute(target) || !statSync(readable).isFile()) {
4727
3091
  throw new Error(`Source links must resolve to files inside the core source tree: ${path}`);
4728
3092
  }
4729
3093
  }
4730
- hash.update(relative2(root, path)).update("\0").update(readFileSync4(readable)).update("\0");
3094
+ hash.update(relative(root, path)).update("\0").update(readFileSync2(readable)).update("\0");
4731
3095
  }
4732
3096
  };
4733
3097
  visit(root);
4734
3098
  return hash.digest("hex");
4735
3099
  }
4736
3100
  function withDevEngineUpdates(initial, config, closeStore) {
4737
- const requestedRoot = process.env["0SEC_DEV_SOURCE_ROOT"];
4738
- const root = requestedRoot ? realpathSync2(requestedRoot) : void 0;
4739
- if (root && JSON.parse(readFileSync4(join4(root, "packages/core/package.json"), "utf8")).name !== "@0sec/core") {
4740
- throw new Error("0SEC_DEV_SOURCE_ROOT must identify a 0sec development checkout");
3101
+ const requestedRoot = process.env["ZERO_DEV_SOURCE_ROOT"];
3102
+ const root = requestedRoot ? realpathSync(requestedRoot) : void 0;
3103
+ if (root && JSON.parse(readFileSync2(join2(root, "packages/core/package.json"), "utf8")).name !== "@0/core") {
3104
+ throw new Error("ZERO_DEV_SOURCE_ROOT must identify a 0 development checkout");
4741
3105
  }
4742
3106
  let current = initial;
4743
3107
  let activeDigest;
@@ -4763,15 +3127,15 @@ function withDevEngineUpdates(initial, config, closeStore) {
4763
3127
  let committed = false;
4764
3128
  let pendingHarnessSnapshot;
4765
3129
  try {
4766
- const source = join4(root, "packages/core/src");
3130
+ const source = join2(root, "packages/core/src");
4767
3131
  const digest = sourceDigest(source);
4768
3132
  if (digest === activeDigest || digest === rejectedDigest) return;
4769
3133
  rejectedDigest = digest;
4770
3134
  notify("Building changed development engine source; the current session remains active until handoff.");
4771
- const generationRoot = join4(root, "packages/core/.0sec/dev-engines");
3135
+ const generationRoot = join2(root, "packages/core/.0/dev-engines");
4772
3136
  await mkdir(generationRoot, { recursive: true, mode: 448 });
4773
- directory = await mkdtemp(join4(generationRoot, "generation-"));
4774
- const result = await execute(process.execPath, [join4(root, "scripts/build-dev-engine.mjs"), source, directory], {
3137
+ directory = await mkdtemp(join2(generationRoot, "generation-"));
3138
+ const result = await execute(process.execPath, [join2(root, "scripts/build-dev-engine.mjs"), source, directory], {
4775
3139
  cwd: root,
4776
3140
  timeout: 12e4,
4777
3141
  maxBuffer: 2 * 1024 * 1024,
@@ -4801,7 +3165,7 @@ function withDevEngineUpdates(initial, config, closeStore) {
4801
3165
  if (!isDeepStrictEqual(comparableCheckpoint(candidate.exportCheckpoint()), comparableCheckpoint(checkpoint))) {
4802
3166
  throw new Error("Candidate engine did not preserve the session checkpoint");
4803
3167
  }
4804
- const candidateBus = await import(pathToFileURL(join4(directory, "runtime/events/bus.js")).href);
3168
+ const candidateBus = await import(pathToFileURL(join2(directory, "runtime/events/bus.js")).href);
4805
3169
  signal?.throwIfAborted();
4806
3170
  if (closingStarted || !getSettings().allowDevSourceUpdates) throw new Error("Development engine update cancelled before handoff");
4807
3171
  if (!isDeepStrictEqual(current.exportCheckpoint(), checkpoint)) throw new Error("Session changed during candidate preparation; keeping the current engine");
@@ -4879,7 +3243,7 @@ function withDevEngineUpdates(initial, config, closeStore) {
4879
3243
  };
4880
3244
  const devlog = (o) => {
4881
3245
  try {
4882
- appendFileSync(process.env["0SEC_TUI_LOG"] ?? "/tmp/0sec-tui.log", JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), kind: "dev-engine", ...o }) + "\n");
3246
+ appendFileSync(process.env["ZERO_TUI_LOG"] ?? "/tmp/0-tui.log", JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), kind: "dev-engine", ...o }) + "\n");
4883
3247
  } catch {
4884
3248
  }
4885
3249
  };
@@ -4946,9 +3310,25 @@ function withDevEngineUpdates(initial, config, closeStore) {
4946
3310
  }
4947
3311
 
4948
3312
  // packages/cli/src/console-session.ts
3313
+ var CONSOLE_JEV_FEATURES = /* @__PURE__ */ new Set([
3314
+ "browser",
3315
+ "memory",
3316
+ "dedupe",
3317
+ "redteam",
3318
+ "kernel",
3319
+ "crash",
3320
+ "radar",
3321
+ "foxguard"
3322
+ ]);
3323
+ function consoleJevRuntimeFromEnvironment() {
3324
+ const features = [...new Set(
3325
+ (process.env["ZERO_JEV_FEATURES"] ?? "").split(",").map((feature) => feature.trim()).filter((feature) => CONSOLE_JEV_FEATURES.has(feature))
3326
+ )];
3327
+ return toToolContextJevRuntime(createConsoleJevRuntime({ provider: "direct", features }));
3328
+ }
4949
3329
  function createLocalConsoleSession(config, dbPath) {
4950
3330
  const db = new osecDB(dbPath);
4951
- const scanId = config.scanId ?? `console-${randomUUID2()}`;
3331
+ const scanId = config.scanId ?? `console-${randomUUID()}`;
4952
3332
  let ownsScan = false;
4953
3333
  try {
4954
3334
  if (!db.getScan(scanId)) {
@@ -4964,7 +3344,8 @@ function createLocalConsoleSession(config, dbPath) {
4964
3344
  ...config,
4965
3345
  scanId,
4966
3346
  db,
4967
- conversationHistory: config.conversationHistory ?? createConversationHistory()
3347
+ conversationHistory: config.conversationHistory ?? createConversationHistory(),
3348
+ jevRuntime: config.jevRuntime ?? consoleJevRuntimeFromEnvironment()
4968
3349
  };
4969
3350
  const session = createConsoleSession(engineConfig);
4970
3351
  return withDevEngineUpdates(session, engineConfig, (completed) => {
@@ -4986,6 +3367,29 @@ function createLocalConsoleSession(config, dbPath) {
4986
3367
 
4987
3368
  // packages/cli/src/tui/codex-device-auth.ts
4988
3369
  import { spawn as spawn2 } from "node:child_process";
3370
+
3371
+ // packages/cli/src/open-browser.ts
3372
+ import { spawn } from "node:child_process";
3373
+ import { platform } from "node:os";
3374
+ function defaultOpenBrowser(url) {
3375
+ const plat = platform();
3376
+ return new Promise((resolve4, reject) => {
3377
+ const options = { detached: true, stdio: "ignore", shell: false };
3378
+ const child = plat === "darwin" ? spawn("open", [url], options) : plat === "win32" ? spawn("powershell.exe", [
3379
+ "-NoProfile",
3380
+ "-NonInteractive",
3381
+ "-Command",
3382
+ "Start-Process -FilePath $env:OSEC_BROWSER_LOGIN_URL"
3383
+ ], { ...options, env: { ...process.env, OSEC_BROWSER_LOGIN_URL: url } }) : spawn("xdg-open", [url], options);
3384
+ child.once("error", reject);
3385
+ child.once("spawn", () => {
3386
+ child.unref();
3387
+ resolve4();
3388
+ });
3389
+ });
3390
+ }
3391
+
3392
+ // packages/cli/src/tui/codex-device-auth.ts
4989
3393
  var MAX_VISIBLE_LINES = 8;
4990
3394
  function defaultSpawnCodexDeviceAuth(command, args, options) {
4991
3395
  const child = spawn2(command, args, {
@@ -5001,22 +3405,39 @@ function defaultSpawnCodexDeviceAuth(command, args, options) {
5001
3405
  function startCodexDeviceAuth(options) {
5002
3406
  const env = options.env ?? process.env;
5003
3407
  const launch = options.spawn ?? defaultSpawnCodexDeviceAuth;
3408
+ const openBrowser = options.openBrowser ?? defaultOpenBrowser;
5004
3409
  const lines = [];
5005
3410
  let pending = "";
5006
3411
  let settled = false;
5007
3412
  let cancelled = false;
3413
+ let browserOpened = false;
5008
3414
  const publish = (phase, message) => {
5009
3415
  options.onUpdate({ phase, lines: [...lines], message });
5010
3416
  };
3417
+ const tryOpenBrowser = (text) => {
3418
+ if (browserOpened) return;
3419
+ const rawUrl = text.match(/https:\/\/auth\.openai\.com\/codex\/device[^\s\x1b]*/)?.[0];
3420
+ if (!rawUrl) return;
3421
+ const url = rawUrl.replace(/[),.;]+$/, "");
3422
+ browserOpened = true;
3423
+ void Promise.resolve(openBrowser(url)).catch(() => {
3424
+ lines.push("Could not open a browser automatically; open the URL above.");
3425
+ if (lines.length > MAX_VISIBLE_LINES) lines.shift();
3426
+ publish("running", "Complete the ChatGPT Codex device sign-in in your browser.");
3427
+ });
3428
+ };
5011
3429
  const pushOutput = (chunk) => {
5012
- const normalized = sanitizeTuiText(`${pending}${chunk.toString("utf8")}`);
5013
- const parts = normalized.split("\n");
3430
+ const text = chunk.toString("utf8");
3431
+ tryOpenBrowser(text);
3432
+ const raw = `${pending}${text}`;
3433
+ const parts = raw.split(/\r?\n/);
5014
3434
  pending = parts.pop() ?? "";
5015
3435
  for (const line of parts) {
5016
- const value = line.trim();
3436
+ const value = sanitizeTuiText(line);
5017
3437
  if (value.length === 0) continue;
5018
3438
  lines.push(value);
5019
3439
  if (lines.length > MAX_VISIBLE_LINES) lines.shift();
3440
+ tryOpenBrowser(value);
5020
3441
  }
5021
3442
  publish("running", "Complete the ChatGPT Codex device sign-in in your browser.");
5022
3443
  };
@@ -5052,7 +3473,7 @@ function startCodexDeviceAuth(options) {
5052
3473
  return;
5053
3474
  }
5054
3475
  maybeLoadCodexAuth({ env, home: options.homeDir, force: true });
5055
- if (!env["0SEC_CHATGPT_ACCESS_TOKEN"] && !env["0SEC_CHATGPT_OAUTH_REFRESH_TOKEN"]) {
3476
+ if (!env["ZERO_CHATGPT_ACCESS_TOKEN"] && !env["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"]) {
5056
3477
  finish("failed", "Codex completed without a readable ChatGPT subscription credential.");
5057
3478
  return;
5058
3479
  }
@@ -5077,8 +3498,6 @@ export {
5077
3498
  TIMELINE_FORMATS,
5078
3499
  isTimelineFormat,
5079
3500
  formatTimeline,
5080
- registerHuntCommand,
5081
- registerDeepReviewCommand,
5082
3501
  resolveFindingChatIntent,
5083
3502
  buildFindingChatPrompt,
5084
3503
  buildFindingConsoleCommand,
@@ -5099,10 +3518,7 @@ export {
5099
3518
  watchLensSynthCommand,
5100
3519
  registerLensSynthCommand,
5101
3520
  createLocalConsoleSession,
5102
- startCodexDeviceAuth,
5103
- registerAuthCommand,
5104
- hostedBrowserLoginFlow,
5105
- runLogin,
5106
3521
  defaultOpenBrowser,
3522
+ startCodexDeviceAuth,
5107
3523
  runUnified
5108
3524
  };