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.
- package/{0sec.js → 0.js} +90 -82
- package/LICENSE +1 -1
- package/README.md +62 -46
- package/chunks/adapt-loop-7I57LXXR.js +18 -0
- package/chunks/{adgraph-JLGA6RYI.js → adgraph-AUDQTBYA.js} +5 -5
- package/chunks/agent/skills/frameworks/entra-id.yaml +2 -2
- package/chunks/agent/skills/techniques/assumption-mining.yaml +2 -2
- package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +2 -2
- package/chunks/agent/skills/techniques/entra-attack-paths.yaml +1 -1
- package/chunks/agent/skills/techniques/kernel-weaponization.yaml +1 -1
- package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +2 -2
- package/chunks/agent/skills/techniques/npm-ecosystem.yaml +1 -1
- package/chunks/agent/skills/techniques/poc-verification.yaml +1 -1
- package/chunks/agent/skills/techniques/seedless-depth-review.yaml +20 -38
- package/chunks/{artifact-scraper-HQ7HLP6V.js → artifact-scraper-PYZ3RU3O.js} +6 -6
- package/chunks/{assumption-mining-5SNIVVDN.js → assumption-mining-MFLF43IR.js} +24 -26
- package/chunks/{chunk-7DQEV5QI.js → chunk-23DG5YKS.js} +4 -4
- package/chunks/{chunk-UR4ELX2Y.js → chunk-2GV4HQKE.js} +340 -703
- package/chunks/{chunk-P6WKNFWX.js → chunk-2OQOQ2FZ.js} +8 -8
- package/chunks/{chunk-5G3ZXFBW.js → chunk-2WNCI664.js} +3 -3
- package/chunks/{chunk-DW5UWPFY.js → chunk-4VGLO2YS.js} +6 -5
- package/chunks/{chunk-KLTNTE2Z.js → chunk-5IBCBQEH.js} +13 -14
- package/chunks/{chunk-N7BOUYEV.js → chunk-5MWAG3FT.js} +14 -14
- package/chunks/{chunk-OEFNRYI2.js → chunk-6GHSR47F.js} +3 -6
- package/chunks/chunk-6YNKRUMC.js +4474 -0
- package/chunks/{chunk-6L26OBWI.js → chunk-76KSBWOQ.js} +255 -35
- package/chunks/chunk-7DEHG7YT.js +2143 -0
- package/chunks/{chunk-AD7WXDH6.js → chunk-7UFUALR2.js} +288 -22
- package/chunks/{chunk-53G27VPS.js → chunk-AZ7L3HFD.js} +7 -2
- package/chunks/{chunk-TSK2AG6J.js → chunk-CAYANSH6.js} +173 -1757
- package/chunks/{chunk-SAFFWQW4.js → chunk-DKSCN2AB.js} +7 -7
- package/chunks/{chunk-2JCCA2JL.js → chunk-DM5C5L5D.js} +3 -3
- package/chunks/{chunk-RWONANDA.js → chunk-DQTNI3KY.js} +5 -5
- package/chunks/{chunk-5JI7L7KV.js → chunk-EGZGZFAH.js} +10036 -12938
- package/chunks/{chunk-6LKRLK2R.js → chunk-FHC2B7LN.js} +3 -3
- package/chunks/{chunk-MYVT64FN.js → chunk-GHWODZMR.js} +2 -2
- package/chunks/{chunk-2RMLOJVB.js → chunk-GVD6SJGH.js} +2 -2
- package/chunks/{chunk-SF4KZ4O3.js → chunk-HLFS6WV2.js} +2 -2
- package/chunks/chunk-HR2TU42B.js +1228 -0
- package/chunks/{chunk-BFRB6HB2.js → chunk-HUNAPTKV.js} +3 -3
- package/chunks/chunk-IO7R7WBM.js +114 -0
- package/chunks/{chunk-WEBMRWEG.js → chunk-IXT64DV5.js} +656 -1868
- package/chunks/{chunk-3MOLBTLS.js → chunk-K2PWUPUI.js} +2 -2
- package/chunks/{chunk-WXQ6BJ6A.js → chunk-LCRTAQN2.js} +7 -7
- package/chunks/{chunk-SVJEDVYK.js → chunk-LPTRPRZR.js} +5 -5
- package/chunks/{chunk-CMKXP5RR.js → chunk-LYUAM3TG.js} +3 -3
- package/chunks/{chunk-BVAZO4WA.js → chunk-MICHDTBK.js} +3 -3
- package/chunks/{chunk-UCYRA73C.js → chunk-OAYUPGF6.js} +4 -4
- package/chunks/{chunk-XM5NLHYU.js → chunk-OWLJYJ5O.js} +14 -14
- package/chunks/{chunk-BKZFDZ23.js → chunk-QCUFBVIZ.js} +3 -3
- package/chunks/chunk-RE5EZDG2.js +5523 -0
- package/chunks/{chunk-ASUR522M.js → chunk-RRD4XXPU.js} +9 -9
- package/chunks/{chunk-AHTBZC3E.js → chunk-RSIUX3RW.js} +4 -4
- package/chunks/{chunk-BZNEY2ZS.js → chunk-SJBCK2EI.js} +15268 -16053
- package/chunks/{chunk-IOL7D5YV.js → chunk-SQCBHFWN.js} +3 -3
- package/chunks/chunk-TH2LW437.js +7829 -0
- package/chunks/{chunk-WVTBZEQO.js → chunk-TM74SSHC.js} +8 -8
- package/chunks/{chunk-U5FLXGHT.js → chunk-TO35Y326.js} +13 -729
- package/chunks/chunk-TRH2PJSN.js +547 -0
- package/chunks/{chunk-YYRBQVFE.js → chunk-TZFIAMWZ.js} +70 -16
- package/chunks/chunk-UELXHK2Y.js +1950 -0
- package/chunks/{chunk-RJWOYEOG.js → chunk-UEX7PFSE.js} +5 -5
- package/chunks/{chunk-VQG4FT5D.js → chunk-UFHN6RIU.js} +2 -2
- package/chunks/{chunk-JQHOLLTD.js → chunk-UU7PQP6N.js} +9 -9
- package/chunks/{chunk-BFR2CDV5.js → chunk-UV5QWZGE.js} +283 -153
- package/chunks/{chunk-WU6AFRAZ.js → chunk-V36HVTUL.js} +12 -12
- package/chunks/{chunk-IR537GON.js → chunk-VCSFCHAJ.js} +2 -2
- package/chunks/{chunk-YLMN3N25.js → chunk-VIT5ALXF.js} +3 -3
- package/chunks/{chunk-BATRQBOR.js → chunk-VMRRNRMR.js} +41 -41
- package/chunks/{chunk-72CISA2D.js → chunk-VNRY6AWF.js} +89 -41
- package/chunks/chunk-W6UWZFKL.js +298 -0
- package/chunks/{chunk-3KPWWJCI.js → chunk-XFCTUKXR.js} +88 -88
- package/chunks/{chunk-GMT2AZKM.js → chunk-YIQSGNAA.js} +897 -130
- package/chunks/codex-models-7TLJSY3L.js +17 -0
- package/chunks/{commands-TBC2F5CE.js → commands-NEI7L3QA.js} +2836 -1424
- package/chunks/corpus-v1.json +2 -2
- package/chunks/data/appsec-archetypes.json +2 -2
- package/chunks/data/chromium-archetypes.json +1 -1
- package/chunks/data/freebsd-archetypes.json +1 -1
- package/chunks/data/kernel-archetypes.json +2 -2
- package/chunks/db-5AP3JB4W.js +16 -0
- package/chunks/{disclose-EKTWSCGW.js → disclose-LDNKAVRH.js} +13 -11
- package/chunks/{dist-4YICS2J2.js → dist-3FNZIBB4.js} +394 -404
- package/chunks/{dist-4MAW5X6L.js → dist-5YHYNLI3.js} +6 -6
- package/chunks/{dist-FMGSR3DW.js → dist-DD4H6HMQ.js} +13 -5
- package/chunks/dist-KEULE5IQ.js +21914 -0
- package/chunks/dist-XZB53PS5.js +53 -0
- package/chunks/eval-runner-43BO2C4T.js +26 -0
- package/chunks/example-manifest.json +2 -2
- package/chunks/{exploit-agent-45YQOHPJ.js → exploit-agent-N4A5ELBK.js} +4 -4
- package/chunks/{exploit-autoclimb-UZGEMGYT.js → exploit-autoclimb-N7P6KIF5.js} +6 -6
- package/chunks/{exploit-climb-SG23KB2G.js → exploit-climb-WNEJUB5W.js} +12 -12
- package/chunks/fix-Z452M4EC.js +26 -0
- package/chunks/{github-issues-MJ6OYOOU.js → github-issues-IGTTWM7V.js} +7 -7
- package/chunks/harness-QJJJVSG4.js +22 -0
- package/chunks/http-conformance-U5F6GKYG.js +11 -0
- package/chunks/http-sender-I5XFFY35.js +10 -0
- package/chunks/hunt-scan-K6D2V3PX.js +36 -0
- package/chunks/{identity-6ZAIIWOR.js → identity-62SVRW4H.js} +5 -5
- package/chunks/{kernel-primitive-7U6CWHXD.js → kernel-primitive-TKUACPKD.js} +6 -6
- package/chunks/{kernel-vm-runner-3JAU4O6J.js → kernel-vm-runner-RAAO2PGT.js} +6 -6
- package/chunks/memsafety-scan-FCPAXIZE.js +16 -0
- package/chunks/{native-loop-RJCJPOUS.js → native-loop-2ZRJENZ3.js} +17 -18
- package/chunks/{npm-detectors-KB5Y5ZFX.js → npm-detectors-Z2ZIQCN4.js} +6 -6
- package/chunks/npm-dynamic-discovery-5J7FT3XM.js +13 -0
- package/chunks/orchestrate-2GWGNTBF.js +58 -0
- package/chunks/{pre-recon-cve-66EB6G4M.js → pre-recon-cve-X2K2P5YQ.js} +4 -4
- package/chunks/prepare-KYHGFWCJ.js +13 -0
- package/chunks/process-N245QIQG.js +12 -0
- package/chunks/{run-D56MPDKY.js → run-U3XU4CTC.js} +11507 -13632
- package/chunks/{runtime-G7YWIO3B.js → runtime-G75TEWQY.js} +10 -11
- package/chunks/runtime-XFWJTBUO.js +12 -0
- package/chunks/{scan-stream-FHI2FYZE.js → scan-stream-BMOCPKQX.js} +7 -7
- package/chunks/scope-WXI46UHJ.js +21 -0
- package/chunks/{session-store-GZ4A4KYT.js → session-store-27L3ZU73.js} +6 -6
- package/chunks/source-files-REHOM44I.js +12 -0
- package/chunks/{specdrift-WCLH6TTQ.js → specdrift-AFS54WEJ.js} +5 -5
- package/chunks/token-KRWP5JYA.js +72 -0
- package/chunks/token-util-DWTL33S3.js +8 -0
- package/chunks/variant-candidates-YWZORZMK.js +13 -0
- package/chunks/{web-recon-prepass-JJGPEOLE.js → web-recon-prepass-YVMFXCIK.js} +9 -9
- package/cli-path-traversal-fixture.js +352 -0
- package/dashboard/assets/bot-Bg1Tp9_d.js +1 -0
- package/dashboard/assets/dist-B_dDCPbu.js +1 -0
- package/dashboard/assets/findings-page-mayGhNx6.js +5 -0
- package/dashboard/assets/format--susmHX7.js +1 -0
- package/dashboard/assets/input-TuVPR3Zl.js +1 -0
- package/dashboard/assets/jsx-runtime-MGseXjj5.js +3 -0
- package/dashboard/assets/live-page-HWWHX99U.js +1 -0
- package/dashboard/assets/meta-tile-ckHo-w7k.js +1 -0
- package/dashboard/assets/operations-BxZ0OoXO.js +10 -0
- package/dashboard/assets/operations-CMFVrXEe.css +2 -0
- package/dashboard/assets/operations-app-D3d35rgo.js +46 -0
- package/dashboard/assets/overview-page-W_4IteEr.js +1 -0
- package/dashboard/assets/page-header-Bw9AJgBV.js +1 -0
- package/dashboard/assets/scans-page-CgzVXHnn.js +1 -0
- package/dashboard/assets/siren-KQj8QAnJ.js +1 -0
- package/dashboard/assets/table-8EDklulN.js +1 -0
- package/dashboard/assets/tabs-CFHPOwg8.js +1 -0
- package/dashboard/index.html +4 -5
- package/node_modules/node-addon-api/LICENSE.md +9 -0
- package/node_modules/node-addon-api/README.md +95 -0
- package/node_modules/node-addon-api/common.gypi +21 -0
- package/node_modules/node-addon-api/except.gypi +25 -0
- package/node_modules/node-addon-api/index.js +14 -0
- package/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
- package/node_modules/node-addon-api/napi-inl.h +7250 -0
- package/node_modules/node-addon-api/napi.h +3463 -0
- package/node_modules/node-addon-api/node_addon_api.gyp +42 -0
- package/node_modules/node-addon-api/node_api.gyp +9 -0
- package/node_modules/node-addon-api/noexcept.gypi +26 -0
- package/node_modules/node-addon-api/nothing.c +0 -0
- package/node_modules/node-addon-api/package-support.json +21 -0
- package/node_modules/node-addon-api/package.json +481 -0
- package/node_modules/node-addon-api/tools/README.md +73 -0
- package/node_modules/node-addon-api/tools/check-napi.js +99 -0
- package/node_modules/node-addon-api/tools/clang-format.js +71 -0
- package/node_modules/node-addon-api/tools/conversion.js +301 -0
- package/node_modules/node-gyp-build/LICENSE +21 -0
- package/node_modules/node-gyp-build/README.md +58 -0
- package/node_modules/node-gyp-build/SECURITY.md +5 -0
- package/node_modules/node-gyp-build/bin.js +84 -0
- package/node_modules/node-gyp-build/build-test.js +19 -0
- package/node_modules/node-gyp-build/index.js +6 -0
- package/node_modules/node-gyp-build/node-gyp-build.js +207 -0
- package/node_modules/node-gyp-build/optional.js +7 -0
- package/node_modules/node-gyp-build/package.json +43 -0
- package/node_modules/tree-sitter/LICENSE +21 -0
- package/node_modules/tree-sitter/README.md +90 -0
- package/node_modules/tree-sitter/binding.gyp +76 -0
- package/node_modules/tree-sitter/index.js +895 -0
- package/node_modules/tree-sitter/package.json +62 -0
- package/node_modules/tree-sitter/prebuilds/darwin-arm64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/prebuilds/darwin-x64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/prebuilds/linux-x64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/prebuilds/win32-x64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/src/addon_data.h +47 -0
- package/node_modules/tree-sitter/src/binding.cc +35 -0
- package/node_modules/tree-sitter/src/conversions.cc +140 -0
- package/node_modules/tree-sitter/src/conversions.h +22 -0
- package/node_modules/tree-sitter/src/language.cc +106 -0
- package/node_modules/tree-sitter/src/language.h +17 -0
- package/node_modules/tree-sitter/src/logger.cc +70 -0
- package/node_modules/tree-sitter/src/logger.h +19 -0
- package/node_modules/tree-sitter/src/lookaheaditerator.cc +122 -0
- package/node_modules/tree-sitter/src/lookaheaditerator.h +33 -0
- package/node_modules/tree-sitter/src/node.cc +1056 -0
- package/node_modules/tree-sitter/src/node.h +30 -0
- package/node_modules/tree-sitter/src/parser.cc +298 -0
- package/node_modules/tree-sitter/src/parser.h +35 -0
- package/node_modules/tree-sitter/src/query.cc +383 -0
- package/node_modules/tree-sitter/src/query.h +39 -0
- package/node_modules/tree-sitter/src/tree.cc +307 -0
- package/node_modules/tree-sitter/src/tree.h +45 -0
- package/node_modules/tree-sitter/src/tree_cursor.cc +213 -0
- package/node_modules/tree-sitter/src/tree_cursor.h +52 -0
- package/node_modules/tree-sitter/tree-sitter.d.ts +211 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/LICENSE +21 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/README.md +21 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/README.md +6 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/include/tree_sitter/api.h +1266 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.c +48 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.h +41 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/array.h +290 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/atomic.h +68 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/clock.h +146 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/error_costs.h +11 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.c +501 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.h +36 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/host.h +21 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.c +221 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.h +299 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/length.h +52 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.c +419 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.h +49 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lib.c +14 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/node.c +774 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.c +2151 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.h +230 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/point.h +62 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/query.c +4134 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reduce_action.h +34 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reusable_node.h +95 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.c +899 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.h +133 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.c +1060 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.h +382 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.c +165 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.h +31 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.c +714 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.h +48 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ICU_SHA +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/LICENSE +414 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/README.md +29 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ptypes.h +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/umachine.h +448 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/urename.h +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf.h +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf16.h +733 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf8.h +881 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode.h +50 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib-symbols.txt +23 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib.c +109 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/wasm-stdlib.h +1294 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.c +1823 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.h +31 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/test/fixtures/grammars/.gitkeep +0 -0
- package/node_modules/tree-sitter-c/LICENSE +21 -0
- package/node_modules/tree-sitter-c/README.md +18 -0
- package/node_modules/tree-sitter-c/binding.gyp +20 -0
- package/node_modules/tree-sitter-c/bindings/node/binding.cc +20 -0
- package/node_modules/tree-sitter-c/bindings/node/index.d.ts +28 -0
- package/node_modules/tree-sitter-c/bindings/node/index.js +7 -0
- package/node_modules/tree-sitter-c/grammar.js +1463 -0
- package/node_modules/tree-sitter-c/package.json +108 -0
- package/node_modules/tree-sitter-c/prebuilds/darwin-arm64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/prebuilds/darwin-x64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/prebuilds/linux-x64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/prebuilds/win32-x64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/queries/highlights.scm +81 -0
- package/node_modules/tree-sitter-c/queries/tags.scm +9 -0
- package/node_modules/tree-sitter-c/src/grammar.json +9682 -0
- package/node_modules/tree-sitter-c/src/node-types.json +4556 -0
- package/node_modules/tree-sitter-c/src/parser.c +113852 -0
- package/node_modules/tree-sitter-c/src/tree_sitter/alloc.h +54 -0
- package/node_modules/tree-sitter-c/src/tree_sitter/array.h +290 -0
- package/node_modules/tree-sitter-c/src/tree_sitter/parser.h +265 -0
- package/package.json +20 -13
- package/vendor/tree-sitter-0.21.1-node24.json +16 -0
- package/vendor/tree-sitter-0.21.1-node24.tgz +0 -0
- package/chunks/adapt-loop-SMH6V4PD.js +0 -18
- package/chunks/appsec-catalog-CBWHGTEL.js +0 -24
- package/chunks/chunk-242TMK6G.js +0 -110
- package/chunks/chunk-57ZENEX2.js +0 -169
- package/chunks/chunk-ADOLI6DT.js +0 -102
- package/chunks/chunk-ATATQACO.js +0 -471
- package/chunks/chunk-C2WXWFBB.js +0 -1070
- package/chunks/chunk-F3WBKITT.js +0 -687
- package/chunks/chunk-H2FFLZNK.js +0 -3
- package/chunks/chunk-LP3HHYQU.js +0 -245
- package/chunks/chunk-QI233I24.js +0 -333
- package/chunks/chunk-RRMJC3ZE.js +0 -105
- package/chunks/chunk-Z5FA2XOX.js +0 -2798
- package/chunks/cost-ledger-NU63MYZM.js +0 -13
- package/chunks/db-KFWOAUUB.js +0 -16
- package/chunks/eval-runner-7ZF472KV.js +0 -27
- package/chunks/fix-IG7LYXH3.js +0 -12
- package/chunks/harness-7ODOLOWU.js +0 -22
- package/chunks/http-conformance-DU66MZIU.js +0 -11
- package/chunks/http-sender-GWH2IYEA.js +0 -10
- package/chunks/hunt-scan-MMKUOETU.js +0 -38
- package/chunks/memsafety-scan-J7SECV5W.js +0 -16
- package/chunks/npm-dynamic-discovery-AHROOZDB.js +0 -13
- package/chunks/orchestrate-OC2VZN2X.js +0 -62
- package/chunks/pipeline-BZK5BLJR.js +0 -14
- package/chunks/prepare-MYY743TK.js +0 -13
- package/chunks/process-LQRCS5OY.js +0 -13
- package/chunks/replay-runner-45G3VU7X.js +0 -39
- package/chunks/runtime-J7PLXZNM.js +0 -12
- package/chunks/scope-BI7BF4ZY.js +0 -18
- package/chunks/source-files-PWRQR6LY.js +0 -12
- package/chunks/variant-candidates-YERCYMPD.js +0 -13
- package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
- package/dashboard/assets/bot-yILPnRgD.js +0 -1
- package/dashboard/assets/chevron-down-BeDJ-Vka.js +0 -1
- package/dashboard/assets/circle-alert-BEnMBMT-.js +0 -1
- package/dashboard/assets/client-DRYsuOGl.js +0 -9
- package/dashboard/assets/copy-Bi5vzoF9.js +0 -1
- package/dashboard/assets/desktop-CXTQonNm.js +0 -32
- package/dashboard/assets/desktop-NOekk4QS.css +0 -1
- package/dashboard/assets/dist-CmX-h7a4.js +0 -1
- package/dashboard/assets/dist-DAwYQmf_.js +0 -45
- package/dashboard/assets/findings-page-CACW9nw2.js +0 -5
- package/dashboard/assets/format-PoISqsES.js +0 -1
- package/dashboard/assets/jsx-runtime-C7oxC63R.js +0 -1
- package/dashboard/assets/live-page-DrgQqQK5.js +0 -1
- package/dashboard/assets/meta-tile-CcskIV_o.js +0 -1
- package/dashboard/assets/operations-BKE8T-vY.css +0 -2
- package/dashboard/assets/operations-D8nUP5_m.js +0 -4
- package/dashboard/assets/operations-app-CQQhG54n.js +0 -2
- package/dashboard/assets/overview-page-DTGS8dPo.js +0 -1
- package/dashboard/assets/page-header-MFVvEtZW.js +0 -1
- package/dashboard/assets/play-Dwo-9xt6.js +0 -1
- package/dashboard/assets/scans-page-ChVtq8Us.js +0 -1
- package/dashboard/assets/search-CiooTLck.js +0 -1
- package/dashboard/assets/siren-CCBwTSuk.js +0 -1
- package/dashboard/assets/table-BYS-nIVA.js +0 -1
- package/dashboard/assets/tabs-DivxbhQy.js +0 -1
- package/dashboard/desktop.html +0 -21
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire as
|
|
3
|
-
const require =
|
|
2
|
+
import { createRequire as __0CreateRequire } from "node:module";
|
|
3
|
+
const require = __0CreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
|
-
VERSION
|
|
6
|
-
|
|
7
|
-
} from "./chunk-6L26OBWI.js";
|
|
5
|
+
VERSION
|
|
6
|
+
} from "./chunk-76KSBWOQ.js";
|
|
8
7
|
|
|
9
8
|
// packages/core/dist/agent/feature-presets.js
|
|
10
9
|
var FP_MOAT_FLAGS = [
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
10
|
+
"ZERO_FEATURE_REACHABILITY_GATE",
|
|
11
|
+
"ZERO_FEATURE_MULTIMODAL",
|
|
12
|
+
"ZERO_FEATURE_PUBLISHABILITY_GATE",
|
|
13
|
+
"ZERO_FEATURE_POV_GATE",
|
|
14
|
+
"ZERO_FEATURE_POC_GEN_STATIC",
|
|
15
|
+
"ZERO_FEATURE_CONSENSUS_VERIFY"
|
|
17
16
|
];
|
|
18
17
|
var FEATURE_PRESETS = Object.freeze({
|
|
19
18
|
"fp-moat": FP_MOAT_FLAGS
|
|
@@ -41,7 +40,7 @@ function applyFeaturePreset(preset, env2 = process.env) {
|
|
|
41
40
|
return { preset, applied, preserved };
|
|
42
41
|
}
|
|
43
42
|
function applyFeaturePresetFromEnv(env2 = process.env) {
|
|
44
|
-
const raw = env2["
|
|
43
|
+
const raw = env2["ZERO_FEATURE_PRESET"];
|
|
45
44
|
if (!raw)
|
|
46
45
|
return void 0;
|
|
47
46
|
const preset = resolveFeaturePreset(raw);
|
|
@@ -63,73 +62,73 @@ var features = {
|
|
|
63
62
|
*
|
|
64
63
|
* Turn count is also a cost PROXY, and cost is already bounded directly by
|
|
65
64
|
* the token budget, so this never was the control that kept spend in check.
|
|
66
|
-
* Enable with `
|
|
65
|
+
* Enable with `ZERO_FEATURE_EARLY_STOP=1` for benchmark or A/B runs where a
|
|
67
66
|
* fixed turn budget per attempt is the point.
|
|
68
67
|
*/
|
|
69
68
|
get earlyStopRetry() {
|
|
70
|
-
return env("
|
|
69
|
+
return env("ZERO_FEATURE_EARLY_STOP", false);
|
|
71
70
|
},
|
|
72
71
|
/** Detect A-A-A and A-B-A-B loop patterns, inject warning */
|
|
73
72
|
get loopDetection() {
|
|
74
|
-
return env("
|
|
73
|
+
return env("ZERO_FEATURE_LOOP_DETECTION", true);
|
|
75
74
|
},
|
|
76
75
|
/** Compress middle messages when context exceeds 30k tokens */
|
|
77
76
|
get contextCompaction() {
|
|
78
|
-
return env("
|
|
77
|
+
return env("ZERO_FEATURE_CONTEXT_COMPACTION", true);
|
|
79
78
|
},
|
|
80
79
|
/**
|
|
81
80
|
* Re-send the opaque, model-bound Responses output item array on the next
|
|
82
81
|
* turn. Default ON; set to 0 only for matched retained-reasoning A/B runs.
|
|
83
82
|
*/
|
|
84
83
|
get retainedReasoning() {
|
|
85
|
-
return env("
|
|
84
|
+
return env("ZERO_FEATURE_RETAINED_REASONING", true);
|
|
86
85
|
},
|
|
87
86
|
/** Exploit script templates in shell prompt (blind SQLi, SSTI, auth chain) */
|
|
88
87
|
get scriptTemplates() {
|
|
89
|
-
return env("
|
|
88
|
+
return env("ZERO_FEATURE_SCRIPT_TEMPLATES", true);
|
|
90
89
|
},
|
|
91
90
|
/** Dynamic vulnerability playbooks injected after recon phase */
|
|
92
91
|
get dynamicPlaybooks() {
|
|
93
|
-
return env("
|
|
92
|
+
return env("ZERO_FEATURE_DYNAMIC_PLAYBOOKS", false);
|
|
94
93
|
},
|
|
95
94
|
/** Just-in-time atomic DO/DON'T rules injected on a matching tool action */
|
|
96
95
|
get ruleInjection() {
|
|
97
|
-
return env("
|
|
96
|
+
return env("ZERO_FEATURE_RULE_INJECTION", false);
|
|
98
97
|
},
|
|
99
98
|
/** Agent writes plan/creds to disk, injected at reflection checkpoints */
|
|
100
99
|
get externalMemory() {
|
|
101
|
-
return env("
|
|
100
|
+
return env("ZERO_FEATURE_EXTERNAL_MEMORY", false);
|
|
102
101
|
},
|
|
103
102
|
/** Inject prior attempt findings when retrying (LLM-summarized progress handoff) */
|
|
104
103
|
get progressHandoff() {
|
|
105
|
-
return env("
|
|
104
|
+
return env("ZERO_FEATURE_PROGRESS_HANDOFF", true);
|
|
106
105
|
},
|
|
107
106
|
/** Allow the agent to search the web for CVE details, docs, and technique references */
|
|
108
107
|
get webSearch() {
|
|
109
|
-
return env("
|
|
108
|
+
return env("ZERO_FEATURE_WEB_SEARCH", false);
|
|
110
109
|
},
|
|
111
110
|
/** Interactive PTY sessions for exploits requiring interactivity (reverse shells, DB clients, SSH) */
|
|
112
111
|
get ptySession() {
|
|
113
|
-
return env("
|
|
112
|
+
return env("ZERO_FEATURE_PTY_SESSION", false);
|
|
114
113
|
},
|
|
115
114
|
/**
|
|
116
115
|
* Persistent, COMPUTE-ONLY Python REPL (`python_exec`, Phase-0). A framed
|
|
117
116
|
* python3 kernel keeps state across calls for payload/parse/crypto/encode
|
|
118
117
|
* work; networking is blocked at the socket source whenever an engagement is
|
|
119
|
-
* active. Default OFF — opt in via
|
|
118
|
+
* active. Default OFF — opt in via ZERO_FEATURE_PYTHON_EXEC=1. Getter so
|
|
120
119
|
* the CLI `--features` flag (set after this module is imported) is honored at
|
|
121
120
|
* tool-dispatch time.
|
|
122
121
|
*/
|
|
123
122
|
get pythonExec() {
|
|
124
|
-
return env("
|
|
123
|
+
return env("ZERO_FEATURE_PYTHON_EXEC", false);
|
|
125
124
|
},
|
|
126
125
|
/**
|
|
127
126
|
* Expose the path-confined `analyze_binary` bridge to 0verse. Default OFF:
|
|
128
127
|
* a model may request a long-running binary analysis only after an operator
|
|
129
|
-
* opts in with
|
|
128
|
+
* opts in with ZERO_FEATURE_ZEROVERSE=1.
|
|
130
129
|
*/
|
|
131
130
|
get zeroverse() {
|
|
132
|
-
return env("
|
|
131
|
+
return env("ZERO_FEATURE_ZEROVERSE", false);
|
|
133
132
|
},
|
|
134
133
|
/**
|
|
135
134
|
* EGATS specialist routing (#557, HPTSA-inspired). When ON, an EGATS branch
|
|
@@ -146,22 +145,22 @@ var features = {
|
|
|
146
145
|
* benchmark harness. Implemented as a getter so the CLI `--features` flag
|
|
147
146
|
* (which sets the env var inside the command action, AFTER this module has
|
|
148
147
|
* been imported) is honored at routing time. Enable via
|
|
149
|
-
*
|
|
148
|
+
* ZERO_FEATURE_SPECIALIST_ROUTING=1.
|
|
150
149
|
*/
|
|
151
150
|
get specialistRouting() {
|
|
152
|
-
return env("
|
|
151
|
+
return env("ZERO_FEATURE_SPECIALIST_ROUTING", false);
|
|
153
152
|
},
|
|
154
153
|
/** Self-consistency voting: run the structured verify pipeline N times and take the majority vote */
|
|
155
154
|
get selfConsistencyVerify() {
|
|
156
|
-
return env("
|
|
155
|
+
return env("ZERO_FEATURE_CONSENSUS_VERIFY", false);
|
|
157
156
|
},
|
|
158
157
|
/** Multi-modal agreement: cross-validate findings against foxguard (Rust pattern scanner) */
|
|
159
158
|
get multiModalAgreement() {
|
|
160
|
-
return env("
|
|
159
|
+
return env("ZERO_FEATURE_MULTIMODAL", false);
|
|
161
160
|
},
|
|
162
161
|
/** Reachability gate: suppress findings whose sink is not reachable from an application entry point */
|
|
163
162
|
get reachabilityGate() {
|
|
164
|
-
return env("
|
|
163
|
+
return env("ZERO_FEATURE_REACHABILITY_GATE", false);
|
|
165
164
|
},
|
|
166
165
|
/**
|
|
167
166
|
* Publishability / in-scope gate (issue #537 / #539). Decides
|
|
@@ -173,14 +172,14 @@ var features = {
|
|
|
173
172
|
*
|
|
174
173
|
* Default OFF: this gate can suppress reproducible findings, so it must be
|
|
175
174
|
* explicitly opted into before any A/B claim. Disable/enable via
|
|
176
|
-
*
|
|
175
|
+
* ZERO_FEATURE_PUBLISHABILITY_GATE.
|
|
177
176
|
*/
|
|
178
177
|
get publishabilityGate() {
|
|
179
|
-
return env("
|
|
178
|
+
return env("ZERO_FEATURE_PUBLISHABILITY_GATE", false);
|
|
180
179
|
},
|
|
181
180
|
/** PoV gate: require a working, executable PoC per finding or downgrade to info */
|
|
182
181
|
get povGate() {
|
|
183
|
-
return env("
|
|
182
|
+
return env("ZERO_FEATURE_POV_GATE", false);
|
|
184
183
|
},
|
|
185
184
|
/**
|
|
186
185
|
* Intra-scan semantic dedupe post-pass (anchored incremental LLM
|
|
@@ -188,10 +187,10 @@ var features = {
|
|
|
188
187
|
* Marks duplicates with a canonical mapping + cluster reason instead of
|
|
189
188
|
* dropping them. Default OFF: it spends an LLM call per ≤50-finding batch
|
|
190
189
|
* after the scan, so it must be explicitly opted into before any A/B
|
|
191
|
-
* claim. Toggle via
|
|
190
|
+
* claim. Toggle via ZERO_FEATURE_SEMANTIC_DEDUPE.
|
|
192
191
|
*/
|
|
193
192
|
get semanticDedupe() {
|
|
194
|
-
return env("
|
|
193
|
+
return env("ZERO_FEATURE_SEMANTIC_DEDUPE", false);
|
|
195
194
|
},
|
|
196
195
|
/**
|
|
197
196
|
* Finding-specific remediation written by the model
|
|
@@ -207,33 +206,17 @@ var features = {
|
|
|
207
206
|
* degrade cost, never correctness.
|
|
208
207
|
*/
|
|
209
208
|
get llmRemediation() {
|
|
210
|
-
return env("
|
|
211
|
-
},
|
|
212
|
-
/**
|
|
213
|
-
* Per-finding impact assessment (`assessImpact`, `triage/impact-assessment.ts`)
|
|
214
|
-
* written by the model: reachability tier, weaponizability, blast radius,
|
|
215
|
-
* business-impact tier. Default OFF — one extra LLM call per non-false-positive
|
|
216
|
-
* finding at report time.
|
|
217
|
-
*
|
|
218
|
-
* When on, the assessment feeds three things it is otherwise absent from:
|
|
219
|
-
* a real CVSS exploitability vector (AV/PR/UI from the reachability tier
|
|
220
|
-
* rather than the AV:N/severity-floor guess), the advisory's Impact +
|
|
221
|
-
* attack-prerequisites section, and the vendor-notification impact line. When
|
|
222
|
-
* off, all three fall back to today's category/severity heuristics — so this
|
|
223
|
-
* flag strictly adds fidelity, never changes the no-assessment output.
|
|
224
|
-
*/
|
|
225
|
-
get impactAssessment() {
|
|
226
|
-
return env("0SEC_FEATURE_IMPACT_ASSESSMENT", false);
|
|
209
|
+
return env("ZERO_FEATURE_LLM_REMEDIATION", false);
|
|
227
210
|
},
|
|
228
211
|
/**
|
|
229
212
|
* Incremental finding ranking post-pass (decimal-insertion between ranked
|
|
230
213
|
* anchors, `triage/incremental-rank.ts`). Orders the report by comparative
|
|
231
214
|
* promise (exploitability × impact × evidence strength). Default OFF: it
|
|
232
215
|
* spends an LLM call per ≤50-finding batch; opt in before any A/B claim.
|
|
233
|
-
* Toggle via
|
|
216
|
+
* Toggle via ZERO_FEATURE_INCREMENTAL_RANK.
|
|
234
217
|
*/
|
|
235
218
|
get incrementalRank() {
|
|
236
|
-
return env("
|
|
219
|
+
return env("ZERO_FEATURE_INCREMENTAL_RANK", false);
|
|
237
220
|
},
|
|
238
221
|
/**
|
|
239
222
|
* Static-finding PoC generation (#666 / EPIC #674 Part A). For findings that
|
|
@@ -247,10 +230,10 @@ var features = {
|
|
|
247
230
|
*
|
|
248
231
|
* Default OFF: it spends LLM + execution budget per static finding and must
|
|
249
232
|
* be explicitly opted into before any A/B claim (A/B-able via the #656
|
|
250
|
-
* harness). Toggle via
|
|
233
|
+
* harness). Toggle via ZERO_FEATURE_POC_GEN_STATIC.
|
|
251
234
|
*/
|
|
252
235
|
get pocGenStatic() {
|
|
253
|
-
return env("
|
|
236
|
+
return env("ZERO_FEATURE_POC_GEN_STATIC", false);
|
|
254
237
|
},
|
|
255
238
|
/**
|
|
256
239
|
* Inline validation / validate-on-save (#554). When ON, the native attack
|
|
@@ -268,10 +251,10 @@ var features = {
|
|
|
268
251
|
* cost_per_flag claim. Implemented as a getter so the CLI `--features` flag
|
|
269
252
|
* (which sets the env var inside the command action, AFTER this module is
|
|
270
253
|
* imported) is honored at loop time. Enable via
|
|
271
|
-
*
|
|
254
|
+
* ZERO_FEATURE_INLINE_VALIDATION=1.
|
|
272
255
|
*/
|
|
273
256
|
get inlineValidation() {
|
|
274
|
-
return env("
|
|
257
|
+
return env("ZERO_FEATURE_INLINE_VALIDATION", false);
|
|
275
258
|
},
|
|
276
259
|
/**
|
|
277
260
|
* WordPress plugin/theme fingerprinter + OSV CVE lookup.
|
|
@@ -286,7 +269,7 @@ var features = {
|
|
|
286
269
|
* still honored at tool-dispatch time.
|
|
287
270
|
*/
|
|
288
271
|
get wpFingerprint() {
|
|
289
|
-
return env("
|
|
272
|
+
return env("ZERO_FEATURE_WP_FINGERPRINT", true);
|
|
290
273
|
},
|
|
291
274
|
/**
|
|
292
275
|
* MongoDB ObjectID forge tool. Exposes the `mongo_objectid` tool to the
|
|
@@ -296,23 +279,23 @@ var features = {
|
|
|
296
279
|
*
|
|
297
280
|
* Default ON — this is a pure-computation utility with no network or
|
|
298
281
|
* filesystem side effects, so there's no reason to gate it off. Disable
|
|
299
|
-
* via
|
|
282
|
+
* via ZERO_FEATURE_MONGO_OBJECTID_FORGE=0 or `--no-mongo-objectid-forge`
|
|
300
283
|
* for ablation. Implemented as a getter so the CLI `--features` flag
|
|
301
284
|
* (which sets the env var inside the command action, AFTER this module
|
|
302
285
|
* has been imported) is still honored at tool-dispatch time. Matches
|
|
303
286
|
* the wpFingerprint pattern above. See packages/core/src/agent/objectid-forge.ts.
|
|
304
287
|
*/
|
|
305
288
|
get mongoObjectIdForge() {
|
|
306
|
-
return env("
|
|
289
|
+
return env("ZERO_FEATURE_MONGO_OBJECTID_FORGE", true);
|
|
307
290
|
},
|
|
308
291
|
/**
|
|
309
|
-
* Live cloud-surface testing (
|
|
292
|
+
* Live cloud-surface testing (0#925). Exposes `cloud_s3_probe` and
|
|
310
293
|
* `cloud_validate_credentials` to the attack agent so it can test S3 buckets
|
|
311
294
|
* for public access + orphaned-bucket takeover and safely validate harvested
|
|
312
295
|
* AWS credentials (read-only). All probes are anonymous or read/verify-only —
|
|
313
296
|
* no writes, no data exfiltration beyond minimal proof.
|
|
314
297
|
*
|
|
315
|
-
* Default OFF (opt-in via
|
|
298
|
+
* Default OFF (opt-in via ZERO_FEATURE_CLOUD_SURFACE=1). Probing a target
|
|
316
299
|
* org's bucket-name space or validating its harvested credentials is recon
|
|
317
300
|
* AGAINST THAT ORG, so it is deny-by-default at two layers: this enablement
|
|
318
301
|
* flag, AND an engagement-scope check in the tool handlers (a configured
|
|
@@ -323,19 +306,7 @@ var features = {
|
|
|
323
306
|
* mongoObjectIdForge pattern above. See packages/core/src/agent/cloud-surface.ts.
|
|
324
307
|
*/
|
|
325
308
|
get cloudSurface() {
|
|
326
|
-
return env("
|
|
327
|
-
},
|
|
328
|
-
/**
|
|
329
|
-
* #978 (ADR-060) — agent fan-out. When ON, the agent gets the `start_scan`
|
|
330
|
-
* tool: it can dispatch CHILD scans (via the same POST /scans the UI uses)
|
|
331
|
-
* that run independently and report up the scan tree — the recursive
|
|
332
|
-
* sub-agent orchestration. Default OFF: fan-out multiplies scans/cost, so it
|
|
333
|
-
* stays opt-in even though the orchestrator enforces budget + a tree-level
|
|
334
|
-
* cap (max children/depth). Enable with 0SEC_FEATURE_AGENT_FANOUT=1.
|
|
335
|
-
* Getter so the CLI `--features` flag is honored at dispatch time.
|
|
336
|
-
*/
|
|
337
|
-
get agentFanout() {
|
|
338
|
-
return env("0SEC_FEATURE_AGENT_FANOUT", false);
|
|
309
|
+
return env("ZERO_FEATURE_CLOUD_SURFACE", false);
|
|
339
310
|
},
|
|
340
311
|
// ── Phase-2 offensive-engine feature flags (dev-live-engine-recovery) ──
|
|
341
312
|
// Each gates a tool that RUNS/BUILDS untrusted code or WEAPONIZES. They are
|
|
@@ -347,21 +318,21 @@ var features = {
|
|
|
347
318
|
/**
|
|
348
319
|
* `memsafety_fuzz` — clones/builds/fuzzes a source tree (sanitizer builds +
|
|
349
320
|
* a fuzz harness), executing attacker-adjacent build scripts and native
|
|
350
|
-
* fuzz targets. Default OFF; opt in via
|
|
321
|
+
* fuzz targets. Default OFF; opt in via ZERO_FEATURE_MEMSAFETY=1. Building
|
|
351
322
|
* and running an untrusted tree is code execution, so it is deny-by-default
|
|
352
323
|
* behind this flag AND an engagement scope.
|
|
353
324
|
*/
|
|
354
325
|
get memsafetyFuzz() {
|
|
355
|
-
return env("
|
|
326
|
+
return env("ZERO_FEATURE_MEMSAFETY", false);
|
|
356
327
|
},
|
|
357
328
|
/**
|
|
358
329
|
* `npm_dynamic_discovery` — installs and RUNS untrusted npm packages under
|
|
359
330
|
* instrumentation to observe malicious install/runtime behaviour. Executing
|
|
360
331
|
* arbitrary package code is the whole point, so it is deny-by-default behind
|
|
361
|
-
* this flag AND an engagement scope. Opt in via
|
|
332
|
+
* this flag AND an engagement scope. Opt in via ZERO_FEATURE_NPM_DISCOVERY=1.
|
|
362
333
|
*/
|
|
363
334
|
get npmDynamicDiscovery() {
|
|
364
|
-
return env("
|
|
335
|
+
return env("ZERO_FEATURE_NPM_DISCOVERY", false);
|
|
365
336
|
},
|
|
366
337
|
/**
|
|
367
338
|
* `weaponize_kernel` — the kernel-exploit weaponization ladder. It only ever
|
|
@@ -369,19 +340,19 @@ var features = {
|
|
|
369
340
|
* present. Highest-caution capability: deny-by-default behind this flag AND
|
|
370
341
|
* an engagement scope AND a runtime artifact-presence check (the handler
|
|
371
342
|
* refuses when the kernel-VM assets are absent). Opt in via
|
|
372
|
-
*
|
|
343
|
+
* ZERO_FEATURE_KERNEL_WEAPONIZE=1.
|
|
373
344
|
*/
|
|
374
345
|
get kernelWeaponize() {
|
|
375
|
-
return env("
|
|
346
|
+
return env("ZERO_FEATURE_KERNEL_WEAPONIZE", false);
|
|
376
347
|
},
|
|
377
348
|
/**
|
|
378
349
|
* `cve_adapt` — adapts a public CVE PoC to the target and RUNS it to confirm
|
|
379
350
|
* exploitability. Running an adapted exploit is code execution against the
|
|
380
351
|
* target, so it is deny-by-default behind this flag AND an engagement scope.
|
|
381
|
-
* Opt in via
|
|
352
|
+
* Opt in via ZERO_FEATURE_CVE_ADAPT=1.
|
|
382
353
|
*/
|
|
383
354
|
get cveAdapt() {
|
|
384
|
-
return env("
|
|
355
|
+
return env("ZERO_FEATURE_CVE_ADAPT", false);
|
|
385
356
|
},
|
|
386
357
|
/**
|
|
387
358
|
* Anti-honeypot flag-shape validator. When the agent calls the `done`
|
|
@@ -392,7 +363,7 @@ var features = {
|
|
|
392
363
|
*
|
|
393
364
|
* Default ON because legitimate flags pass the shape check trivially
|
|
394
365
|
* and the false-positive rate on real flags should be near zero. Turn
|
|
395
|
-
* off via `
|
|
366
|
+
* off via `ZERO_FEATURE_DECOY_DETECTION=0` or the CLI flag
|
|
396
367
|
* `--no-decoy-detection` for ablation/testing.
|
|
397
368
|
*
|
|
398
369
|
* Implemented as a getter so the CLI flag (which flips the env var
|
|
@@ -402,7 +373,7 @@ var features = {
|
|
|
402
373
|
* packages/core/src/agent/flag-validator.ts.
|
|
403
374
|
*/
|
|
404
375
|
get decoyDetection() {
|
|
405
|
-
return env("
|
|
376
|
+
return env("ZERO_FEATURE_DECOY_DETECTION", true);
|
|
406
377
|
},
|
|
407
378
|
// ── Always-on triage filters (default ON, ablatable for A/B testing) ──
|
|
408
379
|
/**
|
|
@@ -411,13 +382,13 @@ var features = {
|
|
|
411
382
|
* sink names and rejects findings that look like "the function did its job".
|
|
412
383
|
*
|
|
413
384
|
* Default ON because that's the existing v0.6.0 behavior. Can be disabled
|
|
414
|
-
* via
|
|
385
|
+
* via ZERO_FEATURE_HOLDING_IT_WRONG=0 to test whether this filter is
|
|
415
386
|
* suppressing real signal — the ceiling-analysis from 2026-04-06 identified
|
|
416
387
|
* this as the strongest candidate for the unexplained XBOW finding-density
|
|
417
388
|
* collapse from 14 → 4 between `features=none` and `features=all`.
|
|
418
389
|
*/
|
|
419
390
|
get holdingItWrong() {
|
|
420
|
-
return env("
|
|
391
|
+
return env("ZERO_FEATURE_HOLDING_IT_WRONG", true);
|
|
421
392
|
},
|
|
422
393
|
/**
|
|
423
394
|
* `evidence_completeness <= 0.5` reject (`packages/core/src/agentic-scanner.ts:591`).
|
|
@@ -425,10 +396,10 @@ var features = {
|
|
|
425
396
|
* gather enough cross-source evidence (request + response + analysis + ...).
|
|
426
397
|
*
|
|
427
398
|
* Default ON because that's the existing v0.6.0 behavior. Can be disabled
|
|
428
|
-
* via
|
|
399
|
+
* via ZERO_FEATURE_EVIDENCE_GATE=0 for ablation.
|
|
429
400
|
*/
|
|
430
401
|
get evidenceGate() {
|
|
431
|
-
return env("
|
|
402
|
+
return env("ZERO_FEATURE_EVIDENCE_GATE", true);
|
|
432
403
|
},
|
|
433
404
|
/**
|
|
434
405
|
* Learned per-finding triage router (`packages/core/src/triage/learned-router.ts`).
|
|
@@ -439,17 +410,17 @@ var features = {
|
|
|
439
410
|
* the scan's slice type (xbow-wb, xbow-bb, npm).
|
|
440
411
|
*
|
|
441
412
|
* Default OFF until the router is validated via A/B testing on xbow-bench
|
|
442
|
-
* and npm-bench. See
|
|
413
|
+
* and npm-bench. See 0#113 for the design doc.
|
|
443
414
|
*/
|
|
444
415
|
get learnedRouter() {
|
|
445
|
-
return env("
|
|
416
|
+
return env("ZERO_FEATURE_LEARNED_ROUTER", false);
|
|
446
417
|
},
|
|
447
418
|
/**
|
|
448
419
|
* Dynamic per-finding triage routing (`packages/core/src/triage/router/`).
|
|
449
420
|
* When enabled, every finding is sent through a `RouterModel` that
|
|
450
421
|
* decides which subset of the 11 triage layers to invoke for that
|
|
451
422
|
* specific finding. v0 ships an explicit-rule router encoded from the
|
|
452
|
-
*
|
|
423
|
+
* 0#72 per-profile ablation; a learned classifier replaces the
|
|
453
424
|
* rules in a follow-up PR without touching the dispatch site.
|
|
454
425
|
*
|
|
455
426
|
* Distinct from `learnedRouter` above: `learnedRouter` is the XGBoost
|
|
@@ -458,25 +429,11 @@ var features = {
|
|
|
458
429
|
* the dispatch router gates which layers run AFTER the TP/FP score
|
|
459
430
|
* model has spoken.
|
|
460
431
|
*
|
|
461
|
-
* Default OFF — opt in via
|
|
462
|
-
*
|
|
432
|
+
* Default OFF — opt in via ZERO_FEATURE_DYNAMIC_TRIAGE=1. See
|
|
433
|
+
* 0#113 for the design doc and 0#67 for the joint paper plan.
|
|
463
434
|
*/
|
|
464
435
|
get dynamicTriageRouting() {
|
|
465
|
-
return env("
|
|
466
|
-
},
|
|
467
|
-
/**
|
|
468
|
-
* Opt-in cloud-sink webhook integration (`packages/core/src/cloud-sink.ts`).
|
|
469
|
-
* When enabled AND the user has set 0SEC_CLOUD_SINK + 0SEC_CLOUD_SCAN_ID,
|
|
470
|
-
* every finding and the final scan report are POSTed to the configured
|
|
471
|
-
* remote endpoint in real time.
|
|
472
|
-
*
|
|
473
|
-
* Default ON so the env-var trio is sufficient to enable streaming, but the
|
|
474
|
-
* flag exists so operators can force-disable the integration in environments
|
|
475
|
-
* where outbound HTTP from the scanner is not desired (e.g. air-gapped CI).
|
|
476
|
-
* Disable via 0SEC_FEATURE_CLOUD_SINK=0.
|
|
477
|
-
*/
|
|
478
|
-
get cloudSink() {
|
|
479
|
-
return env("0SEC_FEATURE_CLOUD_SINK", true);
|
|
436
|
+
return env("ZERO_FEATURE_DYNAMIC_TRIAGE", false);
|
|
480
437
|
},
|
|
481
438
|
/**
|
|
482
439
|
* Pre-recon CVE check (`packages/core/src/pre-recon-cve.ts`).
|
|
@@ -487,10 +444,10 @@ var features = {
|
|
|
487
444
|
* where the agent has source access but no concrete leads.
|
|
488
445
|
*
|
|
489
446
|
* Default ON in white-box mode (no-op in black-box). Disable via
|
|
490
|
-
*
|
|
447
|
+
* ZERO_FEATURE_PRE_RECON_CVE=0 for ablation.
|
|
491
448
|
*/
|
|
492
449
|
get preReconCve() {
|
|
493
|
-
return env("
|
|
450
|
+
return env("ZERO_FEATURE_PRE_RECON_CVE", true);
|
|
494
451
|
},
|
|
495
452
|
/**
|
|
496
453
|
* Deterministic web-recon pre-pass (`packages/core/src/stages/web-recon-prepass.ts`).
|
|
@@ -501,25 +458,25 @@ var features = {
|
|
|
501
458
|
* checks. It EMITS findings directly for what it can prove and injects a
|
|
502
459
|
* "pursue these leads" block into the system prompt for what it can only hint.
|
|
503
460
|
*
|
|
504
|
-
* Default ON (no-op in non-web modes). Gated behind
|
|
461
|
+
* Default ON (no-op in non-web modes). Gated behind ZERO_FEATURE_WEB_RECON
|
|
505
462
|
* so it can be disabled for ablation or offline runs. Implemented as a getter
|
|
506
463
|
* so the CLI `--features` flag (which sets the env var inside the command
|
|
507
464
|
* action, AFTER this module has been imported) is honored at stage time.
|
|
508
465
|
*/
|
|
509
466
|
get webRecon() {
|
|
510
|
-
return env("
|
|
467
|
+
return env("ZERO_FEATURE_WEB_RECON", true);
|
|
511
468
|
},
|
|
512
469
|
/**
|
|
513
470
|
* Best-effort target-history preflight for source review. When a local repo
|
|
514
|
-
* path is known,
|
|
471
|
+
* path is known, 0 infers repository/package/product hints, queries live
|
|
515
472
|
* prior-vulnerability intel, and injects a compact audit-graph summary into
|
|
516
473
|
* the review prompt before the agent starts.
|
|
517
474
|
*
|
|
518
475
|
* Default ON for white-box/source-review modes. Disable via
|
|
519
|
-
*
|
|
476
|
+
* ZERO_FEATURE_TARGET_HISTORY_PRESEED=0 for offline or ablation runs.
|
|
520
477
|
*/
|
|
521
478
|
get targetHistoryPreseed() {
|
|
522
|
-
return env("
|
|
479
|
+
return env("ZERO_FEATURE_TARGET_HISTORY_PRESEED", true);
|
|
523
480
|
},
|
|
524
481
|
/**
|
|
525
482
|
* Preserve credential / exploit-bearing messages verbatim during
|
|
@@ -534,15 +491,15 @@ var features = {
|
|
|
534
491
|
* (a handful of extra messages preserved verbatim in the user
|
|
535
492
|
* compaction-summary block) is small. BoxPwnr-inspired: see
|
|
536
493
|
* `src/boxpwnr/solvers/single_loop_compactation.py` in 0ca/BoxPwnr,
|
|
537
|
-
* and
|
|
494
|
+
* and 0#229 for the design discussion.
|
|
538
495
|
*
|
|
539
496
|
* Implemented as a getter so the CLI `--features` flag — which sets
|
|
540
497
|
* the env var inside the command action AFTER this module is imported
|
|
541
498
|
* — is still honored at compaction time. Disable via
|
|
542
|
-
*
|
|
499
|
+
* ZERO_FEATURE_PRESERVE_CRITICAL_MESSAGES=0 for ablation.
|
|
543
500
|
*/
|
|
544
501
|
get preserveCriticalMessages() {
|
|
545
|
-
return env("
|
|
502
|
+
return env("ZERO_FEATURE_PRESERVE_CRITICAL_MESSAGES", true);
|
|
546
503
|
},
|
|
547
504
|
/**
|
|
548
505
|
* Two-stage budget-warning injection in the agent loop (#408).
|
|
@@ -558,14 +515,14 @@ var features = {
|
|
|
558
515
|
* single short user-message injection at two specific turn boundaries,
|
|
559
516
|
* and the win on long benchmarks (clean handoff instead of stray
|
|
560
517
|
* exploration on the last turn) is well-documented in Strix's
|
|
561
|
-
* implementation. Disable via
|
|
518
|
+
* implementation. Disable via ZERO_FEATURE_BUDGET_WARNINGS=0 for
|
|
562
519
|
* ablation. Implemented as a getter so the CLI `--features` flag —
|
|
563
520
|
* which sets the env var inside the command action AFTER this module
|
|
564
521
|
* is imported — is still honored at injection time (matches the
|
|
565
522
|
* wpFingerprint / preserveCriticalMessages pattern).
|
|
566
523
|
*/
|
|
567
524
|
get budgetWarnings() {
|
|
568
|
-
return env("
|
|
525
|
+
return env("ZERO_FEATURE_BUDGET_WARNINGS", true);
|
|
569
526
|
},
|
|
570
527
|
/**
|
|
571
528
|
* Per-file orchestration for the research and audit stages (#285).
|
|
@@ -579,14 +536,14 @@ var features = {
|
|
|
579
536
|
* Trade-off: total token spend grows roughly N × per-file budget instead
|
|
580
537
|
* of capped at a single session's budget. For a 50-file package, that
|
|
581
538
|
* could be a 5-10× cost increase on research. Disable via
|
|
582
|
-
* `
|
|
539
|
+
* `ZERO_FEATURE_PER_ITEM_ORCHESTRATION=0` to revert to the shared-session
|
|
583
540
|
* behavior — useful for cost-bounded benchmarks.
|
|
584
541
|
*
|
|
585
542
|
* Implemented as a getter so the env var is honored at orchestration time
|
|
586
543
|
* (matches the wpFingerprint / mongoObjectIdForge pattern).
|
|
587
544
|
*/
|
|
588
545
|
get perItemOrchestration() {
|
|
589
|
-
return env("
|
|
546
|
+
return env("ZERO_FEATURE_PER_ITEM_ORCHESTRATION", true);
|
|
590
547
|
},
|
|
591
548
|
/**
|
|
592
549
|
* JIT skill loading (`packages/core/src/agent/skills/`).
|
|
@@ -595,20 +552,21 @@ var features = {
|
|
|
595
552
|
* them into working context mid-scan. Skills replace the monolithic
|
|
596
553
|
* playbook injection with targeted, on-demand knowledge (#410, #457).
|
|
597
554
|
*
|
|
598
|
-
* Default OFF
|
|
555
|
+
* Default OFF unless an assigned cloud methodology manifest opts this run in.
|
|
556
|
+
* An explicit feature flag still takes precedence over that default.
|
|
599
557
|
* Implemented as a getter so the CLI `--features` flag — which sets
|
|
600
558
|
* the env var inside the command action, AFTER this module has been
|
|
601
559
|
* imported — is still honored at tool-dispatch time.
|
|
602
560
|
*/
|
|
603
561
|
get jitSkills() {
|
|
604
|
-
return env("
|
|
562
|
+
return env("ZERO_FEATURE_JIT_SKILLS", Boolean(process.env["ZERO_AUDIT_SKILLS_MANIFEST"]?.trim()));
|
|
605
563
|
},
|
|
606
564
|
/**
|
|
607
565
|
* Execution-journal shadow mode (#494, first additive slice).
|
|
608
566
|
*
|
|
609
567
|
* When ON, the live agent loop ALSO writes append-only journal entries
|
|
610
568
|
* (`tool_call`, `tool_result`, `finding`, `done`) to
|
|
611
|
-
* `~/.
|
|
569
|
+
* `~/.0/runs/<scanId>/journal.jsonl` as it runs — a durable,
|
|
612
570
|
* replayable trace alongside the existing in-memory conversation window.
|
|
613
571
|
* This is strictly additive: the loop continues to drive off its own
|
|
614
572
|
* conversation state, the journal is write-only here, and a failed
|
|
@@ -621,11 +579,11 @@ var features = {
|
|
|
621
579
|
* moat-ablation harness before any A/B claim. Implemented as a getter so
|
|
622
580
|
* the CLI `--features` flag (which sets the env var inside the command
|
|
623
581
|
* action, AFTER this module has been imported) is honored at loop time.
|
|
624
|
-
* Enable via
|
|
582
|
+
* Enable via ZERO_FEATURE_EXECUTION_JOURNAL=1 or `--features
|
|
625
583
|
* execution-journal`.
|
|
626
584
|
*/
|
|
627
585
|
get executionJournal() {
|
|
628
|
-
return env("
|
|
586
|
+
return env("ZERO_FEATURE_EXECUTION_JOURNAL", false);
|
|
629
587
|
},
|
|
630
588
|
/**
|
|
631
589
|
* Execution-journal context routing (#494, slice 2).
|
|
@@ -641,7 +599,7 @@ var features = {
|
|
|
641
599
|
* Independent of `executionJournal` (the shadow-WRITE flag) on purpose so
|
|
642
600
|
* the moat-ablation harness can toggle write and route separately for a
|
|
643
601
|
* clean A/B. Rehydrate is a READER, though, so it only does anything when
|
|
644
|
-
* a journal was written for the run — it reads `~/.
|
|
602
|
+
* a journal was written for the run — it reads `~/.0/runs/<scanId>/
|
|
645
603
|
* journal.jsonl` regardless of how it got there (shadow mode this slice,
|
|
646
604
|
* or specialists in a later slice). When the journal is missing, empty, or
|
|
647
605
|
* corrupt the loop falls back to the existing DB-blob / fresh-prompt
|
|
@@ -654,11 +612,11 @@ var features = {
|
|
|
654
612
|
* must be explicitly opted into before any A/B claim. Implemented as a
|
|
655
613
|
* getter so the CLI `--features` flag (which sets the env var inside the
|
|
656
614
|
* command action, AFTER this module has been imported) is honored at loop
|
|
657
|
-
* time. Enable via
|
|
615
|
+
* time. Enable via ZERO_FEATURE_JOURNAL_REHYDRATE=1 or `--features
|
|
658
616
|
* journal-rehydrate`.
|
|
659
617
|
*/
|
|
660
618
|
get journalRehydrate() {
|
|
661
|
-
return env("
|
|
619
|
+
return env("ZERO_FEATURE_JOURNAL_REHYDRATE", false);
|
|
662
620
|
},
|
|
663
621
|
/**
|
|
664
622
|
* Loot / foothold ledger for opportunistic exploit chaining (#567).
|
|
@@ -678,14 +636,14 @@ var features = {
|
|
|
678
636
|
* tool), matches the `preserveCriticalMessages` rationale — recovering a
|
|
679
637
|
* credential in turn 12 that's needed in turn 38 is a large win on long-tail
|
|
680
638
|
* challenges — and the cost (a short, size-capped block per turn) is small.
|
|
681
|
-
* Disable via
|
|
639
|
+
* Disable via ZERO_FEATURE_LOOT_LEDGER=0 or `--no-loot-ledger` for
|
|
682
640
|
* ablation. Implemented as a getter so the CLI `--features` flag (which sets
|
|
683
641
|
* the env var inside the command action, AFTER this module has been
|
|
684
642
|
* imported) is honored at tool-dispatch / injection time — matches the
|
|
685
643
|
* wpFingerprint / preserveCriticalMessages pattern.
|
|
686
644
|
*/
|
|
687
645
|
get lootLedger() {
|
|
688
|
-
return env("
|
|
646
|
+
return env("ZERO_FEATURE_LOOT_LEDGER", true);
|
|
689
647
|
},
|
|
690
648
|
/**
|
|
691
649
|
* Typed TODO / plan ledger (`packages/core/src/agent/task-ledger.ts`).
|
|
@@ -704,13 +662,13 @@ var features = {
|
|
|
704
662
|
* failure mode of an unused tool is a few hundred wasted schema tokens
|
|
705
663
|
* rather than wrong behavior. Note for whoever publishes benchmark numbers
|
|
706
664
|
* next: this DOES change the default tool list, so re-baseline before
|
|
707
|
-
* quoting a figure across this change. Disable via
|
|
665
|
+
* quoting a figure across this change. Disable via ZERO_FEATURE_AGENT_PLAN=0
|
|
708
666
|
* or `--features no-agent-plan` for ablation. Getter so the CLI `--features`
|
|
709
667
|
* flag (which sets the env var AFTER this module is imported) is honored at
|
|
710
668
|
* tool-dispatch time.
|
|
711
669
|
*/
|
|
712
670
|
get agentPlan() {
|
|
713
|
-
return env("
|
|
671
|
+
return env("ZERO_FEATURE_AGENT_PLAN", false);
|
|
714
672
|
},
|
|
715
673
|
/**
|
|
716
674
|
* Task-drift detection (`packages/core/src/agent/drift.ts`).
|
|
@@ -733,10 +691,10 @@ var features = {
|
|
|
733
691
|
* to a newly-discovered lead is lexically indistinguishable from a derail.
|
|
734
692
|
* Repo convention is explicit that behavior-steering features stay opt-in
|
|
735
693
|
* until A/B'd, and this is squarely one. Enable via
|
|
736
|
-
*
|
|
694
|
+
* ZERO_FEATURE_DRIFT_DETECTION=1 or `--features drift-detection`.
|
|
737
695
|
*/
|
|
738
696
|
get driftDetection() {
|
|
739
|
-
return env("
|
|
697
|
+
return env("ZERO_FEATURE_DRIFT_DETECTION", false);
|
|
740
698
|
},
|
|
741
699
|
/**
|
|
742
700
|
* OAST out-of-band interaction collaborator + oracle (#659).
|
|
@@ -748,12 +706,12 @@ var features = {
|
|
|
748
706
|
* evidence and feeds the loot ledger.
|
|
749
707
|
*
|
|
750
708
|
* Default OFF — the tools are inert without a deployed collaborator. Enable
|
|
751
|
-
* with
|
|
709
|
+
* with ZERO_FEATURE_OAST=1 AND point ZERO_OAST_URL at the self-hosted
|
|
752
710
|
* collaborator server (see packages/core/src/oast/server.ts). Getter (not a
|
|
753
711
|
* const) so the CLI `--features` flag is honored at tool-dispatch time.
|
|
754
712
|
*/
|
|
755
713
|
get oastCollaborator() {
|
|
756
|
-
return env("
|
|
714
|
+
return env("ZERO_FEATURE_OAST", false);
|
|
757
715
|
},
|
|
758
716
|
/**
|
|
759
717
|
* Anthropic prompt caching (`cache_control: {type: "ephemeral"}`) over the
|
|
@@ -776,17 +734,17 @@ var features = {
|
|
|
776
734
|
* never see an Anthropic-shaped field regardless of this flag (see
|
|
777
735
|
* `providerSupportsPromptCache`).
|
|
778
736
|
*
|
|
779
|
-
* Disable via
|
|
737
|
+
* Disable via ZERO_FEATURE_PROMPT_CACHE=0 — worth doing only to isolate a
|
|
780
738
|
* suspected provider-side caching bug, or to measure the uncached baseline.
|
|
781
739
|
* Implemented as a getter so a late env mutation (CLI `--features`, which
|
|
782
740
|
* runs after this module is imported) is honoured at request-build time.
|
|
783
741
|
*/
|
|
784
742
|
get promptCache() {
|
|
785
|
-
return env("
|
|
743
|
+
return env("ZERO_FEATURE_PROMPT_CACHE", true);
|
|
786
744
|
}
|
|
787
745
|
};
|
|
788
746
|
function presetRaisesDefault(key) {
|
|
789
|
-
const raw = process.env["
|
|
747
|
+
const raw = process.env["ZERO_FEATURE_PRESET"];
|
|
790
748
|
if (!raw)
|
|
791
749
|
return false;
|
|
792
750
|
const preset = resolveFeaturePreset(raw);
|
|
@@ -884,7 +842,7 @@ function sanitizeFields(input) {
|
|
|
884
842
|
var LEVEL_RANK = { info: 10, warn: 20, error: 30 };
|
|
885
843
|
var OFF_RANK = Number.POSITIVE_INFINITY;
|
|
886
844
|
function minimumRank() {
|
|
887
|
-
const raw = process.env["
|
|
845
|
+
const raw = process.env["ZERO_DIAG_LEVEL"];
|
|
888
846
|
if (!raw)
|
|
889
847
|
return LEVEL_RANK.info;
|
|
890
848
|
switch (raw.trim().toLowerCase()) {
|
|
@@ -904,9 +862,9 @@ function minimumRank() {
|
|
|
904
862
|
function formatDiagnosticLine(event) {
|
|
905
863
|
const keys = Object.keys(event.fields);
|
|
906
864
|
if (keys.length === 0)
|
|
907
|
-
return `[
|
|
865
|
+
return `[0] ${event.message}`;
|
|
908
866
|
const rendered = keys.map((k) => `${k}=${event.fields[k]}`).join(" ");
|
|
909
|
-
return `[
|
|
867
|
+
return `[0] ${event.message} (${rendered})`;
|
|
910
868
|
}
|
|
911
869
|
var stderrDiagnosticSink = {
|
|
912
870
|
emit(event) {
|
|
@@ -1065,295 +1023,11 @@ function _resetDiagnosticsForTests() {
|
|
|
1065
1023
|
diag.resetForTests();
|
|
1066
1024
|
}
|
|
1067
1025
|
|
|
1068
|
-
// packages/core/dist/cloud/credentials.js
|
|
1069
|
-
import { readFileSync, statSync } from "node:fs";
|
|
1070
|
-
import { join } from "node:path";
|
|
1071
|
-
var DEFAULT_CLOUD_HOST = "https://cloud.0.security";
|
|
1072
|
-
var CloudAuthMissingError = class extends Error {
|
|
1073
|
-
constructor(message) {
|
|
1074
|
-
super(message);
|
|
1075
|
-
this.name = "CloudAuthMissingError";
|
|
1076
|
-
}
|
|
1077
|
-
};
|
|
1078
|
-
var CloudAuthError = class extends Error {
|
|
1079
|
-
status;
|
|
1080
|
-
constructor(message, status) {
|
|
1081
|
-
super(message);
|
|
1082
|
-
this.status = status;
|
|
1083
|
-
this.name = "CloudAuthError";
|
|
1084
|
-
}
|
|
1085
|
-
};
|
|
1086
|
-
function loadCloudCredentials(opts = {}) {
|
|
1087
|
-
const env2 = opts.env ?? process.env;
|
|
1088
|
-
const warn = opts.warn ?? ((m) => process.stderr.write(`${m}
|
|
1089
|
-
`));
|
|
1090
|
-
const envTok = env2["0SEC_CLOUD_TOKEN"]?.trim();
|
|
1091
|
-
if (envTok) {
|
|
1092
|
-
const envHost = normaliseHost(env2["0SEC_CLOUD_HOST"]?.trim() ?? DEFAULT_CLOUD_HOST);
|
|
1093
|
-
return { host: envHost, token: envTok, source: "env" };
|
|
1094
|
-
}
|
|
1095
|
-
const path = join(homeStateDir(opts.homeDir), "cloud.env");
|
|
1096
|
-
let raw;
|
|
1097
|
-
try {
|
|
1098
|
-
raw = readFileSync(path, "utf-8");
|
|
1099
|
-
} catch (err) {
|
|
1100
|
-
const code = err.code;
|
|
1101
|
-
if (code === "ENOENT") {
|
|
1102
|
-
throw new CloudAuthMissingError(`0sec-cloud credentials not found. Run \`0sec auth login\` or set 0SEC_CLOUD_TOKEN in env, or create ${path} (chmod 600) with 0SEC_CLOUD_TOKEN=\u2026 (optionally 0SEC_CLOUD_HOST=\u2026).`);
|
|
1103
|
-
}
|
|
1104
|
-
throw err;
|
|
1105
|
-
}
|
|
1106
|
-
try {
|
|
1107
|
-
const st = statSync(path);
|
|
1108
|
-
const mode = st.mode & 511;
|
|
1109
|
-
if (mode !== 384) {
|
|
1110
|
-
warn(`[0sec cloud] WARNING: ${path} mode is ${mode.toString(8).padStart(3, "0")} (expected 600). Run: chmod 600 ${path}`);
|
|
1111
|
-
}
|
|
1112
|
-
} catch {
|
|
1113
|
-
}
|
|
1114
|
-
const parsed = parseEnvFile(raw);
|
|
1115
|
-
const fileTok = parsed["0SEC_CLOUD_TOKEN"]?.trim();
|
|
1116
|
-
if (!fileTok) {
|
|
1117
|
-
throw new CloudAuthMissingError(`0sec-cloud credentials in ${path} are incomplete: 0SEC_CLOUD_TOKEN is required.`);
|
|
1118
|
-
}
|
|
1119
|
-
const fileHost = normaliseHost(parsed["0SEC_CLOUD_HOST"]?.trim() ?? DEFAULT_CLOUD_HOST);
|
|
1120
|
-
return { host: fileHost, token: fileTok, source: "file" };
|
|
1121
|
-
}
|
|
1122
|
-
function normaliseHost(host) {
|
|
1123
|
-
let h = host;
|
|
1124
|
-
if (!/^https?:\/\//.test(h)) {
|
|
1125
|
-
throw new CloudAuthMissingError(`0SEC_CLOUD_HOST must be an http(s) URL (got ${JSON.stringify(host)}).`);
|
|
1126
|
-
}
|
|
1127
|
-
while (h.endsWith("/"))
|
|
1128
|
-
h = h.slice(0, -1);
|
|
1129
|
-
return h;
|
|
1130
|
-
}
|
|
1131
|
-
function parseEnvFile(raw) {
|
|
1132
|
-
const out = {};
|
|
1133
|
-
const lines = raw.split(/\r?\n/);
|
|
1134
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1135
|
-
const line = lines[i];
|
|
1136
|
-
const trimmed = line.trim();
|
|
1137
|
-
if (trimmed.length === 0)
|
|
1138
|
-
continue;
|
|
1139
|
-
if (trimmed.startsWith("#"))
|
|
1140
|
-
continue;
|
|
1141
|
-
const eq = trimmed.indexOf("=");
|
|
1142
|
-
if (eq <= 0) {
|
|
1143
|
-
throw new CloudAuthMissingError(`Malformed cloud.env at line ${i + 1}: expected KEY=VALUE, got ${JSON.stringify(line)}`);
|
|
1144
|
-
}
|
|
1145
|
-
const key = trimmed.slice(0, eq).trim();
|
|
1146
|
-
const value = trimmed.slice(eq + 1).trim();
|
|
1147
|
-
if (!/^[A-Z0-9_]+$/.test(key)) {
|
|
1148
|
-
throw new CloudAuthMissingError(`Malformed cloud.env at line ${i + 1}: invalid key ${JSON.stringify(key)}`);
|
|
1149
|
-
}
|
|
1150
|
-
out[key] = value;
|
|
1151
|
-
}
|
|
1152
|
-
return out;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
// packages/core/dist/cloud/client.js
|
|
1156
|
-
var CloudError = class extends Error {
|
|
1157
|
-
status;
|
|
1158
|
-
path;
|
|
1159
|
-
code;
|
|
1160
|
-
constructor(message, status, path, code) {
|
|
1161
|
-
super(message);
|
|
1162
|
-
this.status = status;
|
|
1163
|
-
this.path = path;
|
|
1164
|
-
this.code = code;
|
|
1165
|
-
this.name = "CloudError";
|
|
1166
|
-
}
|
|
1167
|
-
};
|
|
1168
|
-
var CloudUnauthorizedError = class extends CloudError {
|
|
1169
|
-
constructor(path) {
|
|
1170
|
-
super(`0sec-cloud auth rejected (HTTP 401) on ${path}. Run \`0sec auth login\` to refresh.`, 401, path);
|
|
1171
|
-
this.name = "CloudUnauthorizedError";
|
|
1172
|
-
}
|
|
1173
|
-
};
|
|
1174
|
-
var CloudForbiddenError = class extends CloudError {
|
|
1175
|
-
constructor(path) {
|
|
1176
|
-
super(`0sec-cloud forbidden (HTTP 403) on ${path}. Token lacks scope for this resource.`, 403, path);
|
|
1177
|
-
this.name = "CloudForbiddenError";
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
var CloudNetworkError = class extends CloudError {
|
|
1181
|
-
constructor(message, path) {
|
|
1182
|
-
super(`0sec-cloud network error on ${path}: ${message}`, void 0, path);
|
|
1183
|
-
this.name = "CloudNetworkError";
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
function healthPath(host) {
|
|
1187
|
-
try {
|
|
1188
|
-
const hostname = new URL(host).hostname.toLowerCase();
|
|
1189
|
-
if (hostname === "cloud.0sec.ai" || hostname === "cloud.0.security") {
|
|
1190
|
-
return "/api/health";
|
|
1191
|
-
}
|
|
1192
|
-
} catch {
|
|
1193
|
-
}
|
|
1194
|
-
return "/health";
|
|
1195
|
-
}
|
|
1196
|
-
var CloudClient = class {
|
|
1197
|
-
host;
|
|
1198
|
-
token;
|
|
1199
|
-
fetchImpl;
|
|
1200
|
-
constructor(opts) {
|
|
1201
|
-
this.host = opts.host;
|
|
1202
|
-
this.token = opts.token;
|
|
1203
|
-
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
1204
|
-
}
|
|
1205
|
-
/**
|
|
1206
|
-
* Verify cloud reachability through its health route. The hosted dashboard
|
|
1207
|
-
* uses `/api/health`; a self-hosted receiver uses `/health`.
|
|
1208
|
-
*/
|
|
1209
|
-
async pingHealth() {
|
|
1210
|
-
return this.getJson(healthPath(this.host));
|
|
1211
|
-
}
|
|
1212
|
-
/**
|
|
1213
|
-
* Fetch the hosted inference model catalog — available models, pricing,
|
|
1214
|
-
* wire API protocol, and context limits. Used at runtime for model
|
|
1215
|
-
* selection and by the hosted provider to determine per-model capabilities.
|
|
1216
|
-
* Returns the raw list response; the caller caches/filters as needed.
|
|
1217
|
-
*/
|
|
1218
|
-
async getInferenceModels() {
|
|
1219
|
-
return this.getJson("/api/inference/v1/models");
|
|
1220
|
-
}
|
|
1221
|
-
/**
|
|
1222
|
-
* Fetch the organization's hosted inference credit availability. The service
|
|
1223
|
-
* calculates the percentage from Autumn's current pool; holds reduce availability.
|
|
1224
|
-
* Older gateways without percentage metadata remain explicitly unavailable.
|
|
1225
|
-
*/
|
|
1226
|
-
async getInferenceAccount() {
|
|
1227
|
-
const account = await this.getJson("/api/inference/account");
|
|
1228
|
-
const credits = account.credits;
|
|
1229
|
-
if (!credits || typeof credits !== "object" || typeof credits.featureId !== "string" || !credits.featureId.trim() || typeof credits.remaining !== "number" || !Number.isFinite(credits.remaining) || credits.remaining < 0 || credits.granted !== null && (typeof credits.granted !== "number" || !Number.isFinite(credits.granted) || credits.granted < 0)) {
|
|
1230
|
-
return { ...account, credits: null };
|
|
1231
|
-
}
|
|
1232
|
-
const remainingPercent = typeof credits.remainingPercent === "number" && Number.isFinite(credits.remainingPercent) && credits.remainingPercent >= 0 && credits.remainingPercent <= 100 && credits.granted !== null && credits.granted > 0 && credits.remaining <= credits.granted ? credits.remainingPercent : null;
|
|
1233
|
-
const nextResetAt = typeof credits.nextResetAt === "number" && Number.isSafeInteger(credits.nextResetAt) && credits.nextResetAt > 0 && credits.nextResetAt <= 864e13 ? credits.nextResetAt : null;
|
|
1234
|
-
return { ...account, credits: {
|
|
1235
|
-
featureId: credits.featureId,
|
|
1236
|
-
granted: credits.granted,
|
|
1237
|
-
remaining: credits.remaining,
|
|
1238
|
-
remainingPercent,
|
|
1239
|
-
nextResetAt
|
|
1240
|
-
} };
|
|
1241
|
-
}
|
|
1242
|
-
/**
|
|
1243
|
-
* Fetch request-level usage metadata for the operator's hosted
|
|
1244
|
-
* inference sessions. Returns lightweight metadata records (model,
|
|
1245
|
-
* tokens, provider, timestamp) — no prompt/response payload.
|
|
1246
|
-
*/
|
|
1247
|
-
async getInferenceUsage() {
|
|
1248
|
-
return this.getJson("/api/inference/usage");
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Generic JSON POST helper with the same error mapping as getJson.
|
|
1252
|
-
* Used by `0sec connect` to enqueue scans and schedules.
|
|
1253
|
-
*/
|
|
1254
|
-
async postJson(path, body) {
|
|
1255
|
-
const url = `${this.host}${path}`;
|
|
1256
|
-
let res;
|
|
1257
|
-
try {
|
|
1258
|
-
res = await this.fetchImpl(url, {
|
|
1259
|
-
method: "POST",
|
|
1260
|
-
headers: { ...this.headers(), "Content-Type": "application/json" },
|
|
1261
|
-
body: JSON.stringify(body)
|
|
1262
|
-
});
|
|
1263
|
-
} catch (err) {
|
|
1264
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1265
|
-
throw new CloudNetworkError(this.scrub(msg), path);
|
|
1266
|
-
}
|
|
1267
|
-
if (!res.ok) {
|
|
1268
|
-
let code;
|
|
1269
|
-
try {
|
|
1270
|
-
const parsed = await res.json();
|
|
1271
|
-
const raw = typeof parsed?.error === "object" ? parsed.error?.code : void 0;
|
|
1272
|
-
if (typeof raw === "string" && raw.length > 0)
|
|
1273
|
-
code = raw;
|
|
1274
|
-
} catch {
|
|
1275
|
-
}
|
|
1276
|
-
this.throwForStatus(res.status, path, code);
|
|
1277
|
-
}
|
|
1278
|
-
return await res.json();
|
|
1279
|
-
}
|
|
1280
|
-
/**
|
|
1281
|
-
* Generic JSON GET helper. Public so future modules (scans, findings)
|
|
1282
|
-
* can reuse the same error mapping without duplicating it. Not exported
|
|
1283
|
-
* past the package boundary — see ./index.ts.
|
|
1284
|
-
*/
|
|
1285
|
-
async getJson(path) {
|
|
1286
|
-
const url = `${this.host}${path}`;
|
|
1287
|
-
let res;
|
|
1288
|
-
try {
|
|
1289
|
-
res = await this.fetchImpl(url, {
|
|
1290
|
-
method: "GET",
|
|
1291
|
-
headers: this.headers()
|
|
1292
|
-
});
|
|
1293
|
-
} catch (err) {
|
|
1294
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1295
|
-
throw new CloudNetworkError(this.scrub(msg), path);
|
|
1296
|
-
}
|
|
1297
|
-
if (!res.ok) {
|
|
1298
|
-
let code;
|
|
1299
|
-
try {
|
|
1300
|
-
const body = await res.json();
|
|
1301
|
-
const raw = body?.error?.code;
|
|
1302
|
-
if (typeof raw === "string" && raw.length > 0)
|
|
1303
|
-
code = raw;
|
|
1304
|
-
} catch {
|
|
1305
|
-
}
|
|
1306
|
-
this.throwForStatus(res.status, path, code);
|
|
1307
|
-
}
|
|
1308
|
-
return await res.json();
|
|
1309
|
-
}
|
|
1310
|
-
/** Throw a typed error for a non-2xx status, carrying the gateway's body `code`. */
|
|
1311
|
-
throwForStatus(status, path, code) {
|
|
1312
|
-
if (status === 401)
|
|
1313
|
-
throw new CloudUnauthorizedError(path);
|
|
1314
|
-
if (status === 403)
|
|
1315
|
-
throw new CloudForbiddenError(path);
|
|
1316
|
-
throw new CloudError(`0sec-cloud request failed (HTTP ${status}${code ? ` ${code}` : ""}) on ${path}.`, status, path, code);
|
|
1317
|
-
}
|
|
1318
|
-
/**
|
|
1319
|
-
* Throw a typed error for non-2xx responses. Public so direct callers
|
|
1320
|
-
* (e.g. an integration test driving raw fetch) can reuse the mapping.
|
|
1321
|
-
*/
|
|
1322
|
-
assertOk(res, path) {
|
|
1323
|
-
if (res.ok)
|
|
1324
|
-
return;
|
|
1325
|
-
if (res.status === 401)
|
|
1326
|
-
throw new CloudUnauthorizedError(path);
|
|
1327
|
-
if (res.status === 403)
|
|
1328
|
-
throw new CloudForbiddenError(path);
|
|
1329
|
-
throw new CloudError(`0sec-cloud request failed (HTTP ${res.status}) on ${path}.`, res.status, path);
|
|
1330
|
-
}
|
|
1331
|
-
// ── internals ──
|
|
1332
|
-
headers() {
|
|
1333
|
-
return {
|
|
1334
|
-
Authorization: `Bearer ${this.token}`,
|
|
1335
|
-
Accept: "application/json",
|
|
1336
|
-
"User-Agent": `0sec-cli/${VERSION}`
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
/**
|
|
1340
|
-
* Strip anything that looks like our own token from a string. The
|
|
1341
|
-
* cloud token may be interpolated into a TLS-layer error message in
|
|
1342
|
-
* exotic failure modes — we redact it to keep the no-leak invariant
|
|
1343
|
-
* local to this module.
|
|
1344
|
-
*/
|
|
1345
|
-
scrub(s) {
|
|
1346
|
-
if (!this.token)
|
|
1347
|
-
return s;
|
|
1348
|
-
return s.split(this.token).join("[REDACTED]");
|
|
1349
|
-
}
|
|
1350
|
-
};
|
|
1351
|
-
|
|
1352
1026
|
// packages/core/dist/runtime/llm-api.js
|
|
1353
|
-
import { randomUUID } from "node:crypto";
|
|
1354
|
-
import { appendFileSync, existsSync, readFileSync
|
|
1027
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
1028
|
+
import { appendFileSync, existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
1355
1029
|
import { homedir } from "node:os";
|
|
1356
|
-
import { join
|
|
1030
|
+
import { join } from "node:path";
|
|
1357
1031
|
|
|
1358
1032
|
// packages/core/dist/runtime/prompt-cache.js
|
|
1359
1033
|
var MAX_CACHE_BREAKPOINTS = 4;
|
|
@@ -1369,7 +1043,7 @@ function providerSupportsPromptCache(provider) {
|
|
|
1369
1043
|
return readExtraCacheProviders().has(provider);
|
|
1370
1044
|
}
|
|
1371
1045
|
function readExtraCacheProviders() {
|
|
1372
|
-
const raw = process.env["
|
|
1046
|
+
const raw = process.env["ZERO_PROMPT_CACHE_EXTRA_PROVIDERS"];
|
|
1373
1047
|
if (!raw)
|
|
1374
1048
|
return /* @__PURE__ */ new Set();
|
|
1375
1049
|
return new Set(raw.split(",").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0));
|
|
@@ -1438,7 +1112,7 @@ function isWireBlockArray(blocks) {
|
|
|
1438
1112
|
}
|
|
1439
1113
|
var azureRegionCache = /* @__PURE__ */ new Map();
|
|
1440
1114
|
async function probeAzureRegion(baseUrl, apiKey, fetchImpl = fetch) {
|
|
1441
|
-
const override = process.env["
|
|
1115
|
+
const override = process.env["ZERO_REGION_OVERRIDE"];
|
|
1442
1116
|
if (override && override.trim().length > 0) {
|
|
1443
1117
|
return override.trim();
|
|
1444
1118
|
}
|
|
@@ -1500,7 +1174,7 @@ function prettyRegion(code) {
|
|
|
1500
1174
|
};
|
|
1501
1175
|
return map[code.toLowerCase()] ?? code;
|
|
1502
1176
|
}
|
|
1503
|
-
var PROVIDER_BANNER_KEY = /* @__PURE__ */ Symbol.for("
|
|
1177
|
+
var PROVIDER_BANNER_KEY = /* @__PURE__ */ Symbol.for("0.core.loggedProviderStartup");
|
|
1504
1178
|
var loggedProviderStartup = (() => {
|
|
1505
1179
|
const g = globalThis;
|
|
1506
1180
|
if (!g[PROVIDER_BANNER_KEY])
|
|
@@ -1508,7 +1182,7 @@ var loggedProviderStartup = (() => {
|
|
|
1508
1182
|
return g[PROVIDER_BANNER_KEY];
|
|
1509
1183
|
})();
|
|
1510
1184
|
function appendNativeTrace(record) {
|
|
1511
|
-
const file = process.env["
|
|
1185
|
+
const file = process.env["ZERO_TRACE_NATIVE_RESPONSES"];
|
|
1512
1186
|
if (!file)
|
|
1513
1187
|
return;
|
|
1514
1188
|
try {
|
|
@@ -1518,7 +1192,7 @@ function appendNativeTrace(record) {
|
|
|
1518
1192
|
}
|
|
1519
1193
|
}
|
|
1520
1194
|
function shouldLogProviderStartup() {
|
|
1521
|
-
return process.env["
|
|
1195
|
+
return process.env["ZERO_SUPPRESS_PROVIDER_STARTUP_LOG"] !== "1";
|
|
1522
1196
|
}
|
|
1523
1197
|
function isRetryableHttpStatus(status) {
|
|
1524
1198
|
return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
|
|
@@ -1528,7 +1202,7 @@ var TRANSIENT_STREAM_ERROR_PATTERNS = [
|
|
|
1528
1202
|
"response stream failed"
|
|
1529
1203
|
];
|
|
1530
1204
|
function llmStreamMaxAttempts() {
|
|
1531
|
-
const raw = process.env["
|
|
1205
|
+
const raw = process.env["ZERO_LLM_STREAM_MAX_ATTEMPTS"];
|
|
1532
1206
|
if (raw == null || raw.trim() === "")
|
|
1533
1207
|
return 3;
|
|
1534
1208
|
const n = Number.parseInt(raw, 10);
|
|
@@ -1575,28 +1249,28 @@ function isRetryableTransportCode(code) {
|
|
|
1575
1249
|
].includes(code);
|
|
1576
1250
|
}
|
|
1577
1251
|
function llmMaxRetries() {
|
|
1578
|
-
const raw = process.env["
|
|
1252
|
+
const raw = process.env["ZERO_LLM_MAX_RETRIES"];
|
|
1579
1253
|
if (raw == null || raw.trim() === "")
|
|
1580
1254
|
return 6;
|
|
1581
1255
|
const n = Number.parseInt(raw, 10);
|
|
1582
1256
|
return Number.isFinite(n) && n >= 0 ? n : 6;
|
|
1583
1257
|
}
|
|
1584
1258
|
function llmMaxRetryWaitMs() {
|
|
1585
|
-
const raw = process.env["
|
|
1259
|
+
const raw = process.env["ZERO_LLM_MAX_RETRY_WAIT_MS"];
|
|
1586
1260
|
if (raw == null || raw.trim() === "")
|
|
1587
1261
|
return 6e4;
|
|
1588
1262
|
const n = Number.parseInt(raw, 10);
|
|
1589
1263
|
return Number.isFinite(n) && n > 0 ? n : 6e4;
|
|
1590
1264
|
}
|
|
1591
1265
|
function llm429MaxRetries() {
|
|
1592
|
-
const raw = process.env["
|
|
1266
|
+
const raw = process.env["ZERO_LLM_429_MAX_RETRIES"] ?? process.env["ZERO_LLM_MAX_RETRIES"];
|
|
1593
1267
|
if (raw == null || raw.trim() === "")
|
|
1594
1268
|
return 12;
|
|
1595
1269
|
const n = Number.parseInt(raw, 10);
|
|
1596
1270
|
return Number.isFinite(n) && n >= 0 ? n : 12;
|
|
1597
1271
|
}
|
|
1598
1272
|
function llm429MaxRetryWaitMs() {
|
|
1599
|
-
const raw = process.env["
|
|
1273
|
+
const raw = process.env["ZERO_LLM_429_MAX_RETRY_WAIT_MS"] ?? process.env["ZERO_LLM_MAX_RETRY_WAIT_MS"];
|
|
1600
1274
|
if (raw == null || raw.trim() === "")
|
|
1601
1275
|
return 3e5;
|
|
1602
1276
|
const n = Number.parseInt(raw, 10);
|
|
@@ -1707,14 +1381,14 @@ function parseUsageLimitReached(body) {
|
|
|
1707
1381
|
return details;
|
|
1708
1382
|
}
|
|
1709
1383
|
function llmStreamIdleTimeoutMs() {
|
|
1710
|
-
const raw = process.env["
|
|
1384
|
+
const raw = process.env["ZERO_LLM_STREAM_IDLE_TIMEOUT_MS"];
|
|
1711
1385
|
if (raw == null || raw.trim() === "")
|
|
1712
1386
|
return 12e4;
|
|
1713
1387
|
const n = Number.parseInt(raw, 10);
|
|
1714
1388
|
return Number.isFinite(n) && n > 0 ? n : 12e4;
|
|
1715
1389
|
}
|
|
1716
1390
|
function llmStreamEventIdleTimeoutMs() {
|
|
1717
|
-
const raw = process.env["
|
|
1391
|
+
const raw = process.env["ZERO_LLM_STREAM_EVENT_IDLE_TIMEOUT_MS"];
|
|
1718
1392
|
if (raw == null || raw.trim() === "")
|
|
1719
1393
|
return 24e4;
|
|
1720
1394
|
const n = Number.parseInt(raw, 10);
|
|
@@ -1864,7 +1538,7 @@ var AZURE_FOUNDRY_DEPLOYMENT_IDS = {
|
|
|
1864
1538
|
"gpt-5.6-terra": true
|
|
1865
1539
|
};
|
|
1866
1540
|
function parseLlmFallbackChain(env2 = process.env) {
|
|
1867
|
-
const raw = env2["
|
|
1541
|
+
const raw = env2["ZERO_LLM_FALLBACK"];
|
|
1868
1542
|
if (!raw || raw.trim().length === 0)
|
|
1869
1543
|
return [];
|
|
1870
1544
|
const entries = [];
|
|
@@ -1881,8 +1555,7 @@ function parseLlmFallbackChain(env2 = process.env) {
|
|
|
1881
1555
|
xai: true,
|
|
1882
1556
|
opencode: true,
|
|
1883
1557
|
copilot: true,
|
|
1884
|
-
google: true
|
|
1885
|
-
hosted: true
|
|
1558
|
+
google: true
|
|
1886
1559
|
};
|
|
1887
1560
|
for (const part of raw.split(",")) {
|
|
1888
1561
|
const trimmed = part.trim();
|
|
@@ -1890,17 +1563,17 @@ function parseLlmFallbackChain(env2 = process.env) {
|
|
|
1890
1563
|
continue;
|
|
1891
1564
|
const colonIdx = trimmed.indexOf(":");
|
|
1892
1565
|
if (colonIdx < 1 || colonIdx === trimmed.length - 1) {
|
|
1893
|
-
diag.warn("fallback_chain_malformed_entry", `
|
|
1566
|
+
diag.warn("fallback_chain_malformed_entry", `ZERO_LLM_FALLBACK: malformed entry "${trimmed}" (expected provider:model)`, { entry: trimmed, expected: "provider:model" });
|
|
1894
1567
|
continue;
|
|
1895
1568
|
}
|
|
1896
1569
|
const provider = trimmed.slice(0, colonIdx);
|
|
1897
1570
|
const model = trimmed.slice(colonIdx + 1).trim();
|
|
1898
1571
|
if (!VALID_PROVIDERS[provider]) {
|
|
1899
|
-
diag.warn("fallback_chain_unknown_provider", `
|
|
1572
|
+
diag.warn("fallback_chain_unknown_provider", `ZERO_LLM_FALLBACK: unknown provider "${provider}" in "${trimmed}"`, { entry: trimmed, provider });
|
|
1900
1573
|
continue;
|
|
1901
1574
|
}
|
|
1902
1575
|
if (!model) {
|
|
1903
|
-
diag.warn("fallback_chain_empty_model", `
|
|
1576
|
+
diag.warn("fallback_chain_empty_model", `ZERO_LLM_FALLBACK: empty model in "${trimmed}"`, { entry: trimmed, provider });
|
|
1904
1577
|
continue;
|
|
1905
1578
|
}
|
|
1906
1579
|
entries.push({ provider, model });
|
|
@@ -1943,7 +1616,7 @@ function resolveFailoverProvider(provider, model, env2 = process.env, apiKey) {
|
|
|
1943
1616
|
return { apiKey: key, baseUrl: env2.ANTHROPIC_BASE_URL ?? "https://api.anthropic.com", wireApi: "chat_completions" };
|
|
1944
1617
|
}
|
|
1945
1618
|
case "chatgpt-codex": {
|
|
1946
|
-
if (!env2["
|
|
1619
|
+
if (!env2["ZERO_CHATGPT_ACCESS_TOKEN"] && !env2["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"] && !readChatGptCodexAuthFile(env2))
|
|
1947
1620
|
return void 0;
|
|
1948
1621
|
return { apiKey: "", baseUrl: CODEX_API_ENDPOINT, wireApi: "responses" };
|
|
1949
1622
|
}
|
|
@@ -1978,39 +1651,21 @@ function resolveFailoverProvider(provider, model, env2 = process.env, apiKey) {
|
|
|
1978
1651
|
return { apiKey: key, baseUrl: env2.OPENCODE_BASE_URL ?? OPENCODE_DEFAULT_BASE_URL, wireApi: opencodeWireApiForModel(model) };
|
|
1979
1652
|
}
|
|
1980
1653
|
case "copilot": {
|
|
1981
|
-
const key = apiKey ?? env2["
|
|
1654
|
+
const key = apiKey ?? env2["ZERO_COPILOT_GITHUB_TOKEN"];
|
|
1982
1655
|
if (!key)
|
|
1983
1656
|
return void 0;
|
|
1984
1657
|
return { apiKey: key, baseUrl: env2.COPILOT_BASE_URL ?? COPILOT_API_BASE, wireApi: "chat_completions" };
|
|
1985
1658
|
}
|
|
1986
1659
|
case "google": {
|
|
1987
|
-
if (!env2["
|
|
1660
|
+
if (!env2["ZERO_GEMINI_ACCESS_TOKEN"] && !env2["ZERO_GEMINI_OAUTH_REFRESH_TOKEN"])
|
|
1988
1661
|
return void 0;
|
|
1989
1662
|
return { apiKey: "", baseUrl: CODE_ASSIST_ENDPOINT, wireApi: "google_generate_content" };
|
|
1990
1663
|
}
|
|
1991
|
-
case "hosted": {
|
|
1992
|
-
try {
|
|
1993
|
-
const creds = loadCloudCredentials({
|
|
1994
|
-
env: env2,
|
|
1995
|
-
warn: () => {
|
|
1996
|
-
}
|
|
1997
|
-
});
|
|
1998
|
-
return {
|
|
1999
|
-
apiKey: creds.token,
|
|
2000
|
-
baseUrl: `${creds.host}/api/inference/v1`,
|
|
2001
|
-
wireApi: "chat_completions"
|
|
2002
|
-
};
|
|
2003
|
-
} catch (err) {
|
|
2004
|
-
if (err instanceof CloudAuthMissingError)
|
|
2005
|
-
return void 0;
|
|
2006
|
-
throw err;
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
1664
|
}
|
|
2010
1665
|
}
|
|
2011
1666
|
var fallbackChainCache;
|
|
2012
1667
|
function getFallbackChain(env2) {
|
|
2013
|
-
const raw = env2["
|
|
1668
|
+
const raw = env2["ZERO_LLM_FALLBACK"];
|
|
2014
1669
|
if (!fallbackChainCache || fallbackChainCache.raw !== raw) {
|
|
2015
1670
|
fallbackChainCache = { raw, entries: parseLlmFallbackChain(env2) };
|
|
2016
1671
|
}
|
|
@@ -2020,7 +1675,7 @@ var ZAI_DEFAULT_BASE_URL = "https://api.z.ai/api/anthropic";
|
|
|
2020
1675
|
var ZAI_DEFAULT_MODEL = "glm-5.3";
|
|
2021
1676
|
var ZAI_DEFAULT_THINKING_BUDGET = 2048;
|
|
2022
1677
|
function zaiThinkingBudget() {
|
|
2023
|
-
const raw = process.env["
|
|
1678
|
+
const raw = process.env["ZERO_ZAI_THINKING_BUDGET"];
|
|
2024
1679
|
if (raw == null || raw.trim().length === 0)
|
|
2025
1680
|
return ZAI_DEFAULT_THINKING_BUDGET;
|
|
2026
1681
|
const n = Number.parseInt(raw, 10);
|
|
@@ -2031,22 +1686,28 @@ var KIMI_DEFAULT_MODEL = "k3";
|
|
|
2031
1686
|
var QWEN_DEFAULT_BASE_URL = "https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1";
|
|
2032
1687
|
var QWEN_DEFAULT_MODEL = "qwen3.8-max";
|
|
2033
1688
|
var CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
|
|
1689
|
+
var CODEX_CLIENT_VERSION = "0.153.0";
|
|
1690
|
+
var CODEX_PROTOCOL_HEADERS = {
|
|
1691
|
+
"OpenAI-Beta": "responses=experimental",
|
|
1692
|
+
originator: "0",
|
|
1693
|
+
version: CODEX_CLIENT_VERSION
|
|
1694
|
+
};
|
|
2034
1695
|
var CODEX_OAUTH_ISSUER = "https://auth.openai.com";
|
|
2035
1696
|
var CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
2036
1697
|
var CODEX_DEFAULT_MODEL = "gpt-5.5";
|
|
2037
1698
|
var LOOP_SERVER_COMPACTION_TOKENS = 15e4;
|
|
2038
|
-
var PROCESS_SESSION_ID = `
|
|
1699
|
+
var PROCESS_SESSION_ID = `0-${Math.random().toString(36).slice(2, 10)}-${Date.now().toString(36)}`;
|
|
2039
1700
|
var chatGptCodexAuthStates = /* @__PURE__ */ new Map();
|
|
2040
1701
|
function codexAuthStateKey(state) {
|
|
2041
1702
|
return JSON.stringify([state.authFilePath, state.accountId, state.refreshToken || state.accessToken]);
|
|
2042
1703
|
}
|
|
2043
1704
|
function readChatGptCodexEnv(env2 = process.env) {
|
|
2044
|
-
const access = env2["
|
|
2045
|
-
const refresh = env2["
|
|
1705
|
+
const access = env2["ZERO_CHATGPT_ACCESS_TOKEN"];
|
|
1706
|
+
const refresh = env2["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"];
|
|
2046
1707
|
if ((!access || access.length === 0) && (!refresh || refresh.length === 0)) {
|
|
2047
1708
|
return void 0;
|
|
2048
1709
|
}
|
|
2049
|
-
const accountId = env2["
|
|
1710
|
+
const accountId = env2["ZERO_CHATGPT_ACCOUNT_ID"];
|
|
2050
1711
|
return {
|
|
2051
1712
|
accessToken: access && access.length > 0 ? access : void 0,
|
|
2052
1713
|
refreshToken: refresh && refresh.length > 0 ? refresh : void 0,
|
|
@@ -2054,13 +1715,13 @@ function readChatGptCodexEnv(env2 = process.env) {
|
|
|
2054
1715
|
};
|
|
2055
1716
|
}
|
|
2056
1717
|
function resolveChatGptCodexAuthPath(env2 = process.env) {
|
|
2057
|
-
return env2["
|
|
1718
|
+
return env2["ZERO_CHATGPT_AUTH_FILE"] ?? join(env2.HOME ?? homedir(), ".codex", "auth.json");
|
|
2058
1719
|
}
|
|
2059
1720
|
function persistChatGptCodexAuthFile(authPath, tokens, usedRefreshToken) {
|
|
2060
1721
|
try {
|
|
2061
1722
|
let existing = {};
|
|
2062
1723
|
try {
|
|
2063
|
-
existing = JSON.parse(
|
|
1724
|
+
existing = JSON.parse(readFileSync(authPath, "utf8"));
|
|
2064
1725
|
} catch {
|
|
2065
1726
|
existing = {};
|
|
2066
1727
|
}
|
|
@@ -2083,7 +1744,7 @@ function persistChatGptCodexAuthFile(authPath, tokens, usedRefreshToken) {
|
|
|
2083
1744
|
`, { mode: 384 });
|
|
2084
1745
|
renameSync(tmp, authPath);
|
|
2085
1746
|
} catch (err) {
|
|
2086
|
-
process.stderr.write(`[
|
|
1747
|
+
process.stderr.write(`[0] warning: could not persist rotated Codex refresh token to ${authPath}: ${err instanceof Error ? err.message : String(err)}
|
|
2087
1748
|
`);
|
|
2088
1749
|
}
|
|
2089
1750
|
}
|
|
@@ -2092,7 +1753,7 @@ function readChatGptCodexAuthFile(env2 = process.env) {
|
|
|
2092
1753
|
if (!existsSync(authPath))
|
|
2093
1754
|
return void 0;
|
|
2094
1755
|
try {
|
|
2095
|
-
const auth = JSON.parse(
|
|
1756
|
+
const auth = JSON.parse(readFileSync(authPath, "utf8"));
|
|
2096
1757
|
const tokens = auth.tokens;
|
|
2097
1758
|
if (!tokens)
|
|
2098
1759
|
return void 0;
|
|
@@ -2119,6 +1780,7 @@ function accessTokenExpiryMs(accessToken) {
|
|
|
2119
1780
|
}
|
|
2120
1781
|
async function refreshChatGptCodexAccessToken(refreshToken) {
|
|
2121
1782
|
const res = await fetch(`${CODEX_OAUTH_ISSUER}/oauth/token`, {
|
|
1783
|
+
signal: AbortSignal.timeout(3e4),
|
|
2122
1784
|
method: "POST",
|
|
2123
1785
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2124
1786
|
body: new URLSearchParams({
|
|
@@ -2170,12 +1832,15 @@ function extractChatGptAccountId(tokens) {
|
|
|
2170
1832
|
}
|
|
2171
1833
|
return void 0;
|
|
2172
1834
|
}
|
|
1835
|
+
async function getChatGptCodexAccessToken(env2 = process.env) {
|
|
1836
|
+
return refreshChatGptCodexAuthState(resolveChatGptCodexAuthState(env2));
|
|
1837
|
+
}
|
|
2173
1838
|
function resolveChatGptCodexAuthState(env2) {
|
|
2174
1839
|
const fromEnvOnly = readChatGptCodexEnv(env2);
|
|
2175
1840
|
const fromFile = fromEnvOnly ? void 0 : readChatGptCodexAuthFile(env2);
|
|
2176
1841
|
const tokens = fromEnvOnly ?? fromFile;
|
|
2177
1842
|
if (!tokens) {
|
|
2178
|
-
throw new Error("ChatGPT Codex auth: neither
|
|
1843
|
+
throw new Error("ChatGPT Codex auth: neither ZERO_CHATGPT_ACCESS_TOKEN nor ZERO_CHATGPT_OAUTH_REFRESH_TOKEN is set. Run `codex login` and either forward the access token via worker-controller (preferred for multi-sandbox dispatch \u2014 avoids the OAuth refresh-token rotation race) or keep a valid ~/.codex/auth.json on this host.");
|
|
2179
1844
|
}
|
|
2180
1845
|
const identity = {
|
|
2181
1846
|
refreshToken: tokens.refreshToken ?? "",
|
|
@@ -2235,8 +1900,8 @@ function geminiAuthStateKey(refreshToken, accessToken) {
|
|
|
2235
1900
|
return JSON.stringify([refreshToken, refreshToken ? void 0 : accessToken]);
|
|
2236
1901
|
}
|
|
2237
1902
|
function readGeminiCodeAssistEnv(env2 = process.env) {
|
|
2238
|
-
const access = env2["
|
|
2239
|
-
const refresh = env2["
|
|
1903
|
+
const access = env2["ZERO_GEMINI_ACCESS_TOKEN"];
|
|
1904
|
+
const refresh = env2["ZERO_GEMINI_OAUTH_REFRESH_TOKEN"];
|
|
2240
1905
|
if ((!access || access.length === 0) && (!refresh || refresh.length === 0))
|
|
2241
1906
|
return void 0;
|
|
2242
1907
|
return {
|
|
@@ -2247,7 +1912,7 @@ function readGeminiCodeAssistEnv(env2 = process.env) {
|
|
|
2247
1912
|
function resolveGeminiCodeAssistAuthState(env2) {
|
|
2248
1913
|
const tokens = readGeminiCodeAssistEnv(env2);
|
|
2249
1914
|
if (!tokens) {
|
|
2250
|
-
throw new Error("Google Gemini Code Assist auth: neither
|
|
1915
|
+
throw new Error("Google Gemini Code Assist auth: neither ZERO_GEMINI_ACCESS_TOKEN nor ZERO_GEMINI_OAUTH_REFRESH_TOKEN is set. Sign in with your Google account (0 connect) or forward a fresh access token.");
|
|
2251
1916
|
}
|
|
2252
1917
|
const key = geminiAuthStateKey(tokens.refreshToken ?? "", tokens.accessToken);
|
|
2253
1918
|
const existing = geminiCodeAssistAuthStates.get(key);
|
|
@@ -2360,7 +2025,7 @@ async function resolveGeminiCodeAssistProject(state, env2, sleep = (ms) => new P
|
|
|
2360
2025
|
return state.inflightProjectResolve;
|
|
2361
2026
|
state.inflightProjectResolve = (async () => {
|
|
2362
2027
|
try {
|
|
2363
|
-
const override = firstNonEmptyEnv(env2, "GOOGLE_CLOUD_PROJECT", "
|
|
2028
|
+
const override = firstNonEmptyEnv(env2, "GOOGLE_CLOUD_PROJECT", "ZERO_GEMINI_PROJECT");
|
|
2364
2029
|
const accessToken = await refreshGeminiCodeAssistAuthState(state);
|
|
2365
2030
|
let load;
|
|
2366
2031
|
try {
|
|
@@ -2372,7 +2037,7 @@ async function resolveGeminiCodeAssistProject(state, env2, sleep = (ms) => new P
|
|
|
2372
2037
|
if (err.securityPolicyViolated) {
|
|
2373
2038
|
if (override)
|
|
2374
2039
|
return override;
|
|
2375
|
-
throw new Error("Google Gemini Code Assist: this account is behind a VPC Service Controls perimeter \u2014 set GOOGLE_CLOUD_PROJECT (or
|
|
2040
|
+
throw new Error("Google Gemini Code Assist: this account is behind a VPC Service Controls perimeter \u2014 set GOOGLE_CLOUD_PROJECT (or ZERO_GEMINI_PROJECT).");
|
|
2376
2041
|
}
|
|
2377
2042
|
throw err;
|
|
2378
2043
|
}
|
|
@@ -2434,7 +2099,7 @@ function parseCodexAzureConfig(env2 = process.env) {
|
|
|
2434
2099
|
if (!existsSync(configPath))
|
|
2435
2100
|
return {};
|
|
2436
2101
|
try {
|
|
2437
|
-
const content =
|
|
2102
|
+
const content = readFileSync(configPath, "utf8");
|
|
2438
2103
|
const azureSectionMatch = content.match(/\[model_providers\.azure\]([\s\S]*?)(?:\n\[|$)/);
|
|
2439
2104
|
const activeProviderMatch = content.match(/^\s*model_provider\s*=\s*"([^"]+)"/m);
|
|
2440
2105
|
const baseUrlMatch = azureSectionMatch?.[1]?.match(/base_url\s*=\s*"([^"]+)"/);
|
|
@@ -2484,13 +2149,13 @@ function providerForModel(model, env2) {
|
|
|
2484
2149
|
return env2.OPENCODE_API_KEY ? "opencode" : void 0;
|
|
2485
2150
|
}
|
|
2486
2151
|
if (m.startsWith("copilot/")) {
|
|
2487
|
-
return env2["
|
|
2152
|
+
return env2["ZERO_COPILOT_GITHUB_TOKEN"] ? "copilot" : void 0;
|
|
2488
2153
|
}
|
|
2489
2154
|
if (m.startsWith("gemini") || m.startsWith("google/")) {
|
|
2490
|
-
return env2["
|
|
2155
|
+
return env2["ZERO_GEMINI_ACCESS_TOKEN"] || env2["ZERO_GEMINI_OAUTH_REFRESH_TOKEN"] ? "google" : void 0;
|
|
2491
2156
|
}
|
|
2492
2157
|
if (/^gpt-|^o[1-4](?:[-_]|$)/.test(m)) {
|
|
2493
|
-
if (env2
|
|
2158
|
+
if (readChatGptCodexEnv(env2) || readChatGptCodexAuthFile(env2))
|
|
2494
2159
|
return "chatgpt-codex";
|
|
2495
2160
|
if (env2.OPENAI_API_KEY)
|
|
2496
2161
|
return "openai";
|
|
@@ -2518,33 +2183,32 @@ var DEFAULT_PROVIDER_MODELS = {
|
|
|
2518
2183
|
xai: XAI_DEFAULT_MODEL,
|
|
2519
2184
|
opencode: OPENCODE_DEFAULT_MODEL,
|
|
2520
2185
|
copilot: COPILOT_DEFAULT_MODEL,
|
|
2521
|
-
google: GEMINI_DEFAULT_MODEL
|
|
2522
|
-
hosted: ""
|
|
2186
|
+
google: GEMINI_DEFAULT_MODEL
|
|
2523
2187
|
};
|
|
2524
2188
|
var AUTO_MODEL_SENTINEL = "auto";
|
|
2525
2189
|
function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
2526
2190
|
if (configProvider !== void 0 && !Object.hasOwn(DEFAULT_PROVIDER_MODELS, configProvider)) {
|
|
2527
2191
|
throw new Error(`RuntimeConfig.provider is unsupported: ${configProvider}`);
|
|
2528
2192
|
}
|
|
2529
|
-
const selectedProviderRaw = configProvider ?? env2["
|
|
2530
|
-
const forcedProviderRaw = env2["
|
|
2193
|
+
const selectedProviderRaw = configProvider ?? env2["ZERO_SELECTED_PROVIDER"]?.trim();
|
|
2194
|
+
const forcedProviderRaw = env2["ZERO_FORCE_PROVIDER"]?.trim() || void 0;
|
|
2531
2195
|
if (selectedProviderRaw && forcedProviderRaw && selectedProviderRaw !== forcedProviderRaw) {
|
|
2532
|
-
throw new Error(`${configProvider !== void 0 ? "RuntimeConfig.provider" : "
|
|
2196
|
+
throw new Error(`${configProvider !== void 0 ? "RuntimeConfig.provider" : "ZERO_SELECTED_PROVIDER"} conflicts with ZERO_FORCE_PROVIDER`);
|
|
2533
2197
|
}
|
|
2534
|
-
const primaryModel = env2["
|
|
2198
|
+
const primaryModel = env2["ZERO_MODEL"]?.trim();
|
|
2535
2199
|
const selectedProviderApplies = configProvider !== void 0 || !preferredModel || !primaryModel || preferredModel === primaryModel;
|
|
2536
2200
|
const pinnedProviderRaw = forcedProviderRaw ?? (selectedProviderApplies ? selectedProviderRaw : void 0);
|
|
2537
2201
|
if (pinnedProviderRaw) {
|
|
2538
|
-
const source = pinnedProviderRaw === forcedProviderRaw ? "
|
|
2202
|
+
const source = pinnedProviderRaw === forcedProviderRaw ? "ZERO_FORCE_PROVIDER" : configProvider !== void 0 ? "RuntimeConfig.provider" : "ZERO_SELECTED_PROVIDER";
|
|
2539
2203
|
if (!Object.hasOwn(DEFAULT_PROVIDER_MODELS, pinnedProviderRaw)) {
|
|
2540
2204
|
throw new Error(`${source} is unsupported: ${pinnedProviderRaw}`);
|
|
2541
2205
|
}
|
|
2542
2206
|
const provider = pinnedProviderRaw;
|
|
2543
|
-
const model = preferredModel ?? env2["
|
|
2544
|
-
if (model === void 0 || model === ""
|
|
2207
|
+
const model = preferredModel ?? env2["ZERO_MODEL"] ?? (configProvider !== void 0 ? DEFAULT_PROVIDER_MODELS[provider] : void 0);
|
|
2208
|
+
if (model === void 0 || model === "") {
|
|
2545
2209
|
throw new Error(`${source} requires an explicit model`);
|
|
2546
2210
|
}
|
|
2547
|
-
if (configApiKey &&
|
|
2211
|
+
if (configApiKey && provider === "chatgpt-codex") {
|
|
2548
2212
|
throw new Error(`${source}=${provider} requires its own authentication, not RuntimeConfig.apiKey`);
|
|
2549
2213
|
}
|
|
2550
2214
|
const resolved = resolveFailoverProvider(provider, model, env2, configApiKey);
|
|
@@ -2650,7 +2314,7 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2650
2314
|
case "copilot":
|
|
2651
2315
|
return {
|
|
2652
2316
|
provider: "copilot",
|
|
2653
|
-
apiKey: env2["
|
|
2317
|
+
apiKey: env2["ZERO_COPILOT_GITHUB_TOKEN"],
|
|
2654
2318
|
baseUrl: env2.COPILOT_BASE_URL ?? COPILOT_API_BASE,
|
|
2655
2319
|
defaultModel: preferredModel ?? COPILOT_DEFAULT_MODEL,
|
|
2656
2320
|
wireApi: "chat_completions"
|
|
@@ -2668,7 +2332,7 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2668
2332
|
provider: "chatgpt-codex",
|
|
2669
2333
|
apiKey: "",
|
|
2670
2334
|
baseUrl: CODEX_API_ENDPOINT,
|
|
2671
|
-
defaultModel: env2["
|
|
2335
|
+
defaultModel: env2["ZERO_MODEL"] ?? CODEX_DEFAULT_MODEL,
|
|
2672
2336
|
wireApi: "responses"
|
|
2673
2337
|
};
|
|
2674
2338
|
case "anthropic":
|
|
@@ -2698,8 +2362,8 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2698
2362
|
default:
|
|
2699
2363
|
break;
|
|
2700
2364
|
}
|
|
2701
|
-
const chatGptAccess = env2["
|
|
2702
|
-
const chatGptRefresh = env2["
|
|
2365
|
+
const chatGptAccess = env2["ZERO_CHATGPT_ACCESS_TOKEN"];
|
|
2366
|
+
const chatGptRefresh = env2["ZERO_CHATGPT_OAUTH_REFRESH_TOKEN"];
|
|
2703
2367
|
const chatGptAuthFile = !chatGptAccess && !chatGptRefresh ? readChatGptCodexAuthFile(env2) : void 0;
|
|
2704
2368
|
if (chatGptAccess && chatGptAccess.length > 0 || chatGptRefresh && chatGptRefresh.length > 0 || !!chatGptAuthFile) {
|
|
2705
2369
|
return {
|
|
@@ -2712,7 +2376,7 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2712
2376
|
// baseUrl is informational only — the runtime hardcodes
|
|
2713
2377
|
// CODEX_API_ENDPOINT for this provider.
|
|
2714
2378
|
baseUrl: CODEX_API_ENDPOINT,
|
|
2715
|
-
defaultModel: env2["
|
|
2379
|
+
defaultModel: env2["ZERO_MODEL"] ?? CODEX_DEFAULT_MODEL,
|
|
2716
2380
|
wireApi: "responses"
|
|
2717
2381
|
};
|
|
2718
2382
|
}
|
|
@@ -2808,7 +2472,7 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2808
2472
|
wireApi: opencodeWireApiForModel(preferredModel)
|
|
2809
2473
|
};
|
|
2810
2474
|
}
|
|
2811
|
-
const copilotToken = env2["
|
|
2475
|
+
const copilotToken = env2["ZERO_COPILOT_GITHUB_TOKEN"];
|
|
2812
2476
|
if (copilotToken) {
|
|
2813
2477
|
return {
|
|
2814
2478
|
provider: "copilot",
|
|
@@ -2818,14 +2482,14 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2818
2482
|
wireApi: "chat_completions"
|
|
2819
2483
|
};
|
|
2820
2484
|
}
|
|
2821
|
-
const geminiAccess = env2["
|
|
2822
|
-
const geminiRefresh = env2["
|
|
2485
|
+
const geminiAccess = env2["ZERO_GEMINI_ACCESS_TOKEN"];
|
|
2486
|
+
const geminiRefresh = env2["ZERO_GEMINI_OAUTH_REFRESH_TOKEN"];
|
|
2823
2487
|
if (geminiAccess && geminiAccess.length > 0 || geminiRefresh && geminiRefresh.length > 0) {
|
|
2824
2488
|
return {
|
|
2825
2489
|
provider: "google",
|
|
2826
2490
|
apiKey: "",
|
|
2827
2491
|
baseUrl: CODE_ASSIST_ENDPOINT,
|
|
2828
|
-
defaultModel: env2["
|
|
2492
|
+
defaultModel: env2["ZERO_MODEL"] ?? GEMINI_DEFAULT_MODEL,
|
|
2829
2493
|
wireApi: "google_generate_content"
|
|
2830
2494
|
};
|
|
2831
2495
|
}
|
|
@@ -2839,21 +2503,6 @@ function detectProvider(configApiKey, preferredModel, env2, configProvider) {
|
|
|
2839
2503
|
wireApi: "chat_completions"
|
|
2840
2504
|
};
|
|
2841
2505
|
}
|
|
2842
|
-
try {
|
|
2843
|
-
const hostedCreds = loadCloudCredentials({
|
|
2844
|
-
env: env2,
|
|
2845
|
-
warn: () => {
|
|
2846
|
-
}
|
|
2847
|
-
});
|
|
2848
|
-
return {
|
|
2849
|
-
provider: "hosted",
|
|
2850
|
-
apiKey: hostedCreds.token,
|
|
2851
|
-
baseUrl: `${hostedCreds.host}/api/inference/v1`,
|
|
2852
|
-
defaultModel: "",
|
|
2853
|
-
wireApi: "chat_completions"
|
|
2854
|
-
};
|
|
2855
|
-
} catch {
|
|
2856
|
-
}
|
|
2857
2506
|
return {
|
|
2858
2507
|
provider: "anthropic",
|
|
2859
2508
|
apiKey: "",
|
|
@@ -2876,27 +2525,23 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
2876
2525
|
apiKey;
|
|
2877
2526
|
baseUrl;
|
|
2878
2527
|
model;
|
|
2528
|
+
pricingModelSource = "";
|
|
2529
|
+
pricingProviderSource;
|
|
2530
|
+
pricingModelKey = "";
|
|
2879
2531
|
wireApi;
|
|
2880
2532
|
reasoningEffort;
|
|
2881
2533
|
azureConfig;
|
|
2882
2534
|
serverCompactionTokens;
|
|
2883
|
-
/** Ordered fallback chain (
|
|
2535
|
+
/** Ordered fallback chain (ZERO_LLM_FALLBACK). Empty = no failover. */
|
|
2884
2536
|
fallbackChain;
|
|
2885
2537
|
/** Index into fallbackChain — which entry to try next. */
|
|
2886
2538
|
fallbackIndex;
|
|
2887
|
-
/** Resolve and validate the hosted model and wire protocol once per runtime. */
|
|
2888
|
-
hostedCatalogPromise = null;
|
|
2889
|
-
/** Catalog ceiling, resolved before hosted inference is submitted. */
|
|
2890
|
-
hostedMaxOutputTokens;
|
|
2891
2539
|
constructor(config, inherited) {
|
|
2892
2540
|
if (inherited) {
|
|
2893
2541
|
const timeout = config.timeout ?? inherited.config.timeout ?? 12e4;
|
|
2894
2542
|
if (!Number.isFinite(timeout) || timeout <= 0) {
|
|
2895
2543
|
throw new Error("Subagent timeout must be a positive finite number");
|
|
2896
2544
|
}
|
|
2897
|
-
if (inherited.provider === "hosted" && inherited.hostedMaxOutputTokens === void 0) {
|
|
2898
|
-
throw new Error("Hosted model catalog must resolve before creating a subagent");
|
|
2899
|
-
}
|
|
2900
2545
|
const model = config.model ?? inherited.model;
|
|
2901
2546
|
const modelChanged = model !== inherited.model;
|
|
2902
2547
|
this.config = {
|
|
@@ -2930,10 +2575,6 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
2930
2575
|
this.geminiAuthState = inherited.geminiAuthState;
|
|
2931
2576
|
this.fallbackChain = [];
|
|
2932
2577
|
this.fallbackIndex = 0;
|
|
2933
|
-
if (!modelChanged) {
|
|
2934
|
-
this.hostedMaxOutputTokens = inherited.hostedMaxOutputTokens;
|
|
2935
|
-
this.hostedCatalogPromise = inherited.hostedCatalogPromise;
|
|
2936
|
-
}
|
|
2937
2578
|
return;
|
|
2938
2579
|
}
|
|
2939
2580
|
this.applyConfiguration(config);
|
|
@@ -2956,7 +2597,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
2956
2597
|
credentials: resolveFailoverProvider(entry.provider, entry.model, this.env)
|
|
2957
2598
|
}));
|
|
2958
2599
|
this.fallbackIndex = 0;
|
|
2959
|
-
const detected = detectProvider(config.apiKey, config.model ?? this.env["
|
|
2600
|
+
const detected = detectProvider(config.apiKey, config.model ?? this.env["ZERO_MODEL"], this.env, config.provider);
|
|
2960
2601
|
this.provider = detected.provider;
|
|
2961
2602
|
this.apiKey = detected.apiKey;
|
|
2962
2603
|
this.baseUrl = detected.baseUrl;
|
|
@@ -2973,9 +2614,9 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
2973
2614
|
this.geminiAuthState = resolveGeminiCodeAssistAuthState(this.env);
|
|
2974
2615
|
}
|
|
2975
2616
|
}
|
|
2976
|
-
this.reasoningEffort = this.env["
|
|
2617
|
+
this.reasoningEffort = this.env["ZERO_REASONING_EFFORT"] ?? detected.reasoningEffort;
|
|
2977
2618
|
this.serverCompactionTokens = config.serverCompactionTokens !== void 0 ? Math.max(1e3, config.serverCompactionTokens) : void 0;
|
|
2978
|
-
const requestedModel = config.model ?? this.env["
|
|
2619
|
+
const requestedModel = config.model ?? this.env["ZERO_MODEL"];
|
|
2979
2620
|
if (requestedModel === "free" && this.provider === "openrouter") {
|
|
2980
2621
|
this.model = FREE_OPENROUTER_MODEL;
|
|
2981
2622
|
} else {
|
|
@@ -2988,16 +2629,51 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
2988
2629
|
this.model = copilotModelId(this.model);
|
|
2989
2630
|
}
|
|
2990
2631
|
this.applyModelWireApi();
|
|
2991
|
-
if (this.apiKey && !this.env["
|
|
2632
|
+
if (this.apiKey && !this.env["ZERO_SKIP_PROVIDER_BANNER"]) {
|
|
2992
2633
|
void logProviderStartup(this.provider, this.providerLabel, this.baseUrl, this.model, this.wireApi, this.apiKey).catch(() => {
|
|
2993
2634
|
});
|
|
2994
2635
|
}
|
|
2995
2636
|
}
|
|
2637
|
+
/** Non-secret identity for preferences scoped to the captured connection. */
|
|
2638
|
+
connectionIdentity() {
|
|
2639
|
+
let identity;
|
|
2640
|
+
if (this.provider === "chatgpt-codex") {
|
|
2641
|
+
const state = this.codexAuthState;
|
|
2642
|
+
if (!state)
|
|
2643
|
+
return void 0;
|
|
2644
|
+
if (state.accountId) {
|
|
2645
|
+
identity = [this.provider, "account", state.accountId];
|
|
2646
|
+
} else {
|
|
2647
|
+
const credential = state.refreshToken || state.accessToken;
|
|
2648
|
+
if (!credential)
|
|
2649
|
+
return void 0;
|
|
2650
|
+
identity = [this.provider, "credential", credential];
|
|
2651
|
+
}
|
|
2652
|
+
} else if (this.provider === "google") {
|
|
2653
|
+
const credential = this.geminiAuthState?.refreshToken || this.geminiAuthState?.accessToken;
|
|
2654
|
+
if (!credential)
|
|
2655
|
+
return void 0;
|
|
2656
|
+
identity = [this.provider, this.baseUrl, credential, firstNonEmptyEnv(this.env, "GOOGLE_CLOUD_PROJECT", "ZERO_GEMINI_PROJECT") ?? ""];
|
|
2657
|
+
} else {
|
|
2658
|
+
if (!this.apiKey)
|
|
2659
|
+
return void 0;
|
|
2660
|
+
identity = [this.provider, this.baseUrl, this.apiKey];
|
|
2661
|
+
}
|
|
2662
|
+
return createHash("sha256").update(JSON.stringify(identity)).digest("hex");
|
|
2663
|
+
}
|
|
2664
|
+
/** Discover models using this runtime's captured account, including after a separate login changes. */
|
|
2665
|
+
async codexModelCatalog(signal) {
|
|
2666
|
+
const state = this.codexAuthState;
|
|
2667
|
+
if (this.provider !== "chatgpt-codex" || !state)
|
|
2668
|
+
throw new Error("No active Codex subscription");
|
|
2669
|
+
const { loadCodexModelCatalog } = await import("./codex-models-7TLJSY3L.js");
|
|
2670
|
+
return loadCodexModelCatalog({ signal, resolveCredentials: () => refreshChatGptCodexAuthState(state) });
|
|
2671
|
+
}
|
|
2996
2672
|
/**
|
|
2997
2673
|
* Mutate the live selection in place so the NEXT turn (the engine reads
|
|
2998
2674
|
* `config.runtime` per turn) and the NEXT `forkForSubagent` pick up the new
|
|
2999
|
-
* model / provider / role map with zero session teardown.
|
|
3000
|
-
*
|
|
2675
|
+
* model / provider / role map with zero session teardown. Undefined fields
|
|
2676
|
+
* preserve the current state, except a provider change resets an omitted model.
|
|
3001
2677
|
*/
|
|
3002
2678
|
reconfigure(sel) {
|
|
3003
2679
|
const providerChanged = sel.provider !== void 0 && sel.provider !== this.provider;
|
|
@@ -3005,14 +2681,12 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3005
2681
|
const merged = {
|
|
3006
2682
|
...this.config,
|
|
3007
2683
|
apiKey: void 0,
|
|
3008
|
-
provider: sel.provider,
|
|
3009
|
-
|
|
2684
|
+
provider: sel.provider ?? this.provider,
|
|
2685
|
+
model: sel.model,
|
|
3010
2686
|
...sel.agentModels !== void 0 ? { agentModels: sel.agentModels } : {},
|
|
3011
2687
|
...sel.singleModel !== void 0 ? { singleModel: sel.singleModel } : {},
|
|
3012
2688
|
...sel.env !== void 0 ? { env: sel.env } : {}
|
|
3013
2689
|
};
|
|
3014
|
-
this.hostedCatalogPromise = null;
|
|
3015
|
-
this.hostedMaxOutputTokens = void 0;
|
|
3016
2690
|
this.applyConfiguration(merged);
|
|
3017
2691
|
return;
|
|
3018
2692
|
}
|
|
@@ -3038,10 +2712,10 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3038
2712
|
}
|
|
3039
2713
|
}
|
|
3040
2714
|
}
|
|
3041
|
-
/**
|
|
2715
|
+
/** Modern OpenAI tool calls use Responses, shared by roots and forks. */
|
|
3042
2716
|
applyModelWireApi() {
|
|
3043
2717
|
const normalizedModel = this.model.toLowerCase();
|
|
3044
|
-
if (this.wireApi === "chat_completions" && (this.provider === "azure" && normalizedModel === "gpt-5.6-sol" || this.provider === "openai" && normalizedModel === "gpt-5.6-luna")) {
|
|
2718
|
+
if (this.wireApi === "chat_completions" && (this.provider === "azure" && normalizedModel === "gpt-5.6-sol" || this.provider === "openai" && (normalizedModel === "gpt-5.6-luna" || /^gpt-(?:[6-9]|\d{2,})(?:[-.]|$)/.test(normalizedModel)))) {
|
|
3045
2719
|
this.wireApi = "responses";
|
|
3046
2720
|
}
|
|
3047
2721
|
}
|
|
@@ -3050,18 +2724,14 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3050
2724
|
* Providers whose credentials are present in THIS runtime's environment
|
|
3051
2725
|
* (`this.env`, never process-global). A provider counts as accessible iff
|
|
3052
2726
|
* `resolveFailoverProvider` — the same auth-presence check the cross-provider
|
|
3053
|
-
* failover chain uses —
|
|
3054
|
-
* (chatgpt-codex OAuth) and cloud-hosted are covered by the identical rule.
|
|
2727
|
+
* failover chain uses — including auth-only providers (chatgpt-codex OAuth).
|
|
3055
2728
|
*/
|
|
3056
2729
|
accessibleProviders() {
|
|
3057
2730
|
const out = [];
|
|
3058
2731
|
for (const provider of Object.keys(DEFAULT_PROVIDER_MODELS)) {
|
|
3059
2732
|
const probeModel = DEFAULT_PROVIDER_MODELS[provider] || "probe";
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
out.push(provider);
|
|
3063
|
-
} catch {
|
|
3064
|
-
}
|
|
2733
|
+
if (resolveFailoverProvider(provider, probeModel, this.env))
|
|
2734
|
+
out.push(provider);
|
|
3065
2735
|
}
|
|
3066
2736
|
return out;
|
|
3067
2737
|
}
|
|
@@ -3098,7 +2768,6 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3098
2768
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
3099
2769
|
throw new Error("Subagent timeout must be a positive finite number");
|
|
3100
2770
|
}
|
|
3101
|
-
await this.ensureHostedModel();
|
|
3102
2771
|
const roleModel = selection?.role !== void 0 && this.config.agentModels && Object.hasOwn(this.config.agentModels, selection.role) ? this.config.agentModels[selection.role] : void 0;
|
|
3103
2772
|
const autoInEffect = roleModel === AUTO_MODEL_SENTINEL || this.config.autoRoute === true && roleModel === void 0;
|
|
3104
2773
|
const configuredModel = roleModel === AUTO_MODEL_SENTINEL ? void 0 : roleModel;
|
|
@@ -3114,45 +2783,15 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3114
2783
|
throw new Error(autoInEffect ? `Subagent model "${selectedModel}" is not reachable: its provider has no configured credentials.` : `Subagent model "${selectedModel}" is not operator-approved. Configure agentModels before selecting it.`);
|
|
3115
2784
|
}
|
|
3116
2785
|
const child = new _LlmApiRuntime({ type: "api", timeout: timeoutMs, model }, this);
|
|
3117
|
-
await child.ensureHostedModel();
|
|
3118
2786
|
return child;
|
|
3119
2787
|
}
|
|
3120
|
-
/** The server catalog is authoritative even when a model was selected explicitly. */
|
|
3121
|
-
async ensureHostedModel() {
|
|
3122
|
-
if (this.provider !== "hosted")
|
|
3123
|
-
return;
|
|
3124
|
-
if (!this.hostedCatalogPromise) {
|
|
3125
|
-
this.hostedCatalogPromise = (async () => {
|
|
3126
|
-
const client = new CloudClient({
|
|
3127
|
-
host: this.baseUrl.replace(/\/api\/inference\/v1$/, ""),
|
|
3128
|
-
token: this.apiKey
|
|
3129
|
-
});
|
|
3130
|
-
const catalog = await client.getInferenceModels();
|
|
3131
|
-
const selected = this.model ? catalog.data.find((model) => model.id === this.model) : catalog.data[0];
|
|
3132
|
-
if (!selected) {
|
|
3133
|
-
throw new Error(this.model ? `Hosted model "${this.model}" is unavailable. Run \`0sec models\` for available models.` : "No hosted models are available. Run `0sec models` to check service availability.");
|
|
3134
|
-
}
|
|
3135
|
-
this.model = selected.id;
|
|
3136
|
-
this.wireApi = selected.wire_api;
|
|
3137
|
-
this.hostedMaxOutputTokens = selected.max_output_tokens;
|
|
3138
|
-
})();
|
|
3139
|
-
}
|
|
3140
|
-
await this.hostedCatalogPromise;
|
|
3141
|
-
}
|
|
3142
2788
|
/**
|
|
3143
2789
|
* A hard dollar ceiling needs a provider-enforced bound on the next response.
|
|
3144
2790
|
* ChatGPT Codex OAuth rejects `max_output_tokens`, so it cannot support that
|
|
3145
2791
|
* contract; callers must fail closed before making a metered comparison call.
|
|
3146
2792
|
*/
|
|
3147
2793
|
get outputTokenLimit() {
|
|
3148
|
-
return this.provider === "chatgpt-codex" ? void 0 :
|
|
3149
|
-
}
|
|
3150
|
-
/** Hosted requests honor both the catalog ceiling and the local hard cap. */
|
|
3151
|
-
get effectiveOutputTokens() {
|
|
3152
|
-
if (this.provider === "hosted" && this.hostedMaxOutputTokens !== void 0) {
|
|
3153
|
-
return Math.min(NATIVE_COMPLETION_TOKEN_LIMIT, this.hostedMaxOutputTokens);
|
|
3154
|
-
}
|
|
3155
|
-
return NATIVE_COMPLETION_TOKEN_LIMIT;
|
|
2794
|
+
return this.provider === "chatgpt-codex" ? void 0 : NATIVE_COMPLETION_TOKEN_LIMIT;
|
|
3156
2795
|
}
|
|
3157
2796
|
/**
|
|
3158
2797
|
* Whether this provider uses OpenAI-compatible chat/completions format.
|
|
@@ -3164,7 +2803,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3164
2803
|
* inert default — it is intentionally unused for these two providers.
|
|
3165
2804
|
*/
|
|
3166
2805
|
get isOpenAICompat() {
|
|
3167
|
-
return this.provider === "openrouter" || this.provider === "openai" || this.provider === "azure" || this.provider === "deepseek" || this.provider === "qwen" || this.provider === "xai" || this.provider === "copilot" || this.provider === "
|
|
2806
|
+
return this.provider === "openrouter" || this.provider === "openai" || this.provider === "azure" || this.provider === "deepseek" || this.provider === "qwen" || this.provider === "xai" || this.provider === "copilot" || this.provider === "opencode" && (this.wireApi === "chat_completions" || this.wireApi === "responses") || // chatgpt-codex always speaks Responses API; treat it as
|
|
3168
2807
|
// OpenAI-compat for body-shape branching purposes (the Responses
|
|
3169
2808
|
// wire-API code paths below already key on `wireApi === "responses"`
|
|
3170
2809
|
// and produce a body codex's backend accepts as-is).
|
|
@@ -3210,13 +2849,25 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3210
2849
|
resolvedModel() {
|
|
3211
2850
|
return this.model;
|
|
3212
2851
|
}
|
|
2852
|
+
/** Price discovered IDs on their actual route without changing the wire model. */
|
|
2853
|
+
resolvedPricingModel() {
|
|
2854
|
+
if (this.provider === "chatgpt-codex" || this.provider === "copilot" || this.provider === "google")
|
|
2855
|
+
return this.model;
|
|
2856
|
+
if (this.pricingModelSource !== this.model || this.pricingProviderSource !== this.provider) {
|
|
2857
|
+
this.pricingModelSource = this.model;
|
|
2858
|
+
this.pricingProviderSource = this.provider;
|
|
2859
|
+
this.pricingModelKey = `${this.provider}/${this.model}`;
|
|
2860
|
+
}
|
|
2861
|
+
return this.pricingModelKey;
|
|
2862
|
+
}
|
|
3213
2863
|
/** Build the appropriate headers for the configured provider. */
|
|
3214
2864
|
buildHeaders() {
|
|
3215
2865
|
if (this.provider === "chatgpt-codex") {
|
|
3216
2866
|
return {
|
|
3217
2867
|
"Content-Type": "application/json",
|
|
3218
|
-
|
|
3219
|
-
"
|
|
2868
|
+
...CODEX_PROTOCOL_HEADERS,
|
|
2869
|
+
"x-codex-routing-hint": `model=${this.model}`,
|
|
2870
|
+
"User-Agent": `0/${VERSION}`
|
|
3220
2871
|
};
|
|
3221
2872
|
}
|
|
3222
2873
|
if (this.isGeminiCodeAssist) {
|
|
@@ -3248,8 +2899,8 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3248
2899
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
3249
2900
|
}
|
|
3250
2901
|
if (this.provider === "openrouter") {
|
|
3251
|
-
headers["HTTP-Referer"] = "https://
|
|
3252
|
-
headers["X-Title"] = "
|
|
2902
|
+
headers["HTTP-Referer"] = "https://0.security";
|
|
2903
|
+
headers["X-Title"] = "0 Security Scanner";
|
|
3253
2904
|
}
|
|
3254
2905
|
return headers;
|
|
3255
2906
|
}
|
|
@@ -3273,7 +2924,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3273
2924
|
* happens.
|
|
3274
2925
|
*
|
|
3275
2926
|
* session_id is process-stable (PROCESS_SESSION_ID, randomised
|
|
3276
|
-
* once at module load). A
|
|
2927
|
+
* once at module load). A @0/cli invocation = one scan = one
|
|
3277
2928
|
* session, so the process-lifetime constant is the right
|
|
3278
2929
|
* granularity. If we ever want per-scan ids inside a long-lived
|
|
3279
2930
|
* controller process, add a setter on the runtime; for now this
|
|
@@ -3427,7 +3078,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3427
3078
|
/**
|
|
3428
3079
|
* Per-turn prompt-cache accounting line, so a run can be shown to actually
|
|
3429
3080
|
* be hitting cache rather than assumed to be. Off unless
|
|
3430
|
-
* `
|
|
3081
|
+
* `ZERO_DEBUG_PROMPT_CACHE` is set — this fires once per agent turn, and an
|
|
3431
3082
|
* unconditional line would interleave with the TUI on every scan.
|
|
3432
3083
|
*
|
|
3433
3084
|
* The same numbers reach the cloud without this flag: `cachedInputTokens`
|
|
@@ -3435,7 +3086,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3435
3086
|
* is the durable, queryable proof. This is the local fast path.
|
|
3436
3087
|
*/
|
|
3437
3088
|
logCacheUsage(usage) {
|
|
3438
|
-
if (!usage || !process.env["
|
|
3089
|
+
if (!usage || !process.env["ZERO_DEBUG_PROMPT_CACHE"])
|
|
3439
3090
|
return;
|
|
3440
3091
|
const read = usage.cachedInputTokens ?? 0;
|
|
3441
3092
|
const write = usage.cacheWriteTokens ?? 0;
|
|
@@ -3478,12 +3129,10 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3478
3129
|
return "GitHub Copilot";
|
|
3479
3130
|
case "google":
|
|
3480
3131
|
return "Google Gemini (Code Assist)";
|
|
3481
|
-
case "hosted":
|
|
3482
|
-
return "0sec Cloud";
|
|
3483
3132
|
}
|
|
3484
3133
|
}
|
|
3485
3134
|
noKeyError() {
|
|
3486
|
-
return "No provider credential found. Set one of:\n env
|
|
3135
|
+
return "No provider credential found. Set one of:\n env ZERO_CHATGPT_OAUTH_REFRESH_TOKEN=... 0 <command> (ChatGPT Codex subscription auth)\n export OPENROUTER_API_KEY=sk-or-... (OpenRouter \u2014 many models, one key)\n export DEEPSEEK_API_KEY=... (DeepSeek \u2014 direct Flash 0731 inference)\n export ANTHROPIC_API_KEY=sk-ant-... (Anthropic \u2014 direct Claude access)\n export AZURE_OPENAI_API_KEY=... (Azure OpenAI \u2014 reuse your Codex Azure provider)\n export OPENAI_API_KEY=sk-... (OpenAI \u2014 direct GPT access)\n export Z_AI_API_KEY=... (Z.ai GLM \u2014 flat-rate Coding Plan, Anthropic-compatible)\n export KIMI_API_KEY=... (Moonshot Kimi K3 \u2014 flat-rate coding, Anthropic-compatible)\n export QWEN_API_KEY=... (Alibaba Qwen \u2014 Token Plan sub, OpenAI-compatible)\n export XAI_API_KEY=... (xAI Grok \u2014 OpenAI-compatible)\n export OPENCODE_API_KEY=... (OpenCode Zen \u2014 multi-wire gateway)\n export ZERO_COPILOT_GITHUB_TOKEN=... (GitHub Copilot \u2014 device-code OAuth token)";
|
|
3487
3136
|
}
|
|
3488
3137
|
getConfigurationDiagnostics() {
|
|
3489
3138
|
if (!this.apiKey && this.provider !== "chatgpt-codex") {
|
|
@@ -3503,7 +3152,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3503
3152
|
};
|
|
3504
3153
|
}
|
|
3505
3154
|
const hasConfiguredBaseUrl = !!(this.env.AZURE_OPENAI_BASE_URL || this.env.OPENAI_BASE_URL || this.azureConfig.baseUrl);
|
|
3506
|
-
const hasConfiguredModel = !!(this.config.model || this.env["
|
|
3155
|
+
const hasConfiguredModel = !!(this.config.model || this.env["ZERO_MODEL"] || this.env.AZURE_OPENAI_MODEL || this.azureConfig.model);
|
|
3507
3156
|
const missing = [];
|
|
3508
3157
|
if (!hasConfiguredBaseUrl) {
|
|
3509
3158
|
missing.push("AZURE_OPENAI_BASE_URL (or [model_providers.azure].base_url in ~/.codex/config.toml)");
|
|
@@ -3519,7 +3168,7 @@ var LlmApiRuntime = class _LlmApiRuntime {
|
|
|
3519
3168
|
reason: "invalid_config",
|
|
3520
3169
|
fatalError: `Azure OpenAI runtime is selected, but the configuration is incomplete.
|
|
3521
3170
|
Missing: ${missing.join("; ")}
|
|
3522
|
-
|
|
3171
|
+
0 will not guess Azure defaults because that can silently route to the wrong endpoint or deployment.`
|
|
3523
3172
|
};
|
|
3524
3173
|
}
|
|
3525
3174
|
return {
|
|
@@ -3537,15 +3186,15 @@ Missing: ${missing.join("; ")}
|
|
|
3537
3186
|
*
|
|
3538
3187
|
* Two 429 classes are handled differently:
|
|
3539
3188
|
* - per-minute rate limit → retry with the wider 429 budget
|
|
3540
|
-
* (
|
|
3189
|
+
* (ZERO_LLM_429_MAX_RETRIES attempts / ZERO_LLM_429_MAX_RETRY_WAIT_MS
|
|
3541
3190
|
* cumulative, defaults 12 / 5min) since the limiter resets every ~60s;
|
|
3542
3191
|
* `Retry-After` / `retry-after-ms` headers are honored up to a 120s cap.
|
|
3543
3192
|
* - plan-quota exhaustion (`usage_limit_reached`, resets in hours/days) →
|
|
3544
|
-
* skips retries and immediately advances `
|
|
3193
|
+
* skips retries and immediately advances `ZERO_LLM_FALLBACK`; if no
|
|
3545
3194
|
* configured fallback has credentials, it throws QuotaExhaustedError.
|
|
3546
3195
|
*
|
|
3547
3196
|
* Other retryable statuses (transient 5xx) keep the generic budget:
|
|
3548
|
-
*
|
|
3197
|
+
* ZERO_LLM_MAX_RETRIES (attempts) and ZERO_LLM_MAX_RETRY_WAIT_MS
|
|
3549
3198
|
* (cumulative backoff). On exhaustion it returns the last still-failing
|
|
3550
3199
|
* Response with its body intact, so the caller's existing `!res.ok` branch
|
|
3551
3200
|
* surfaces the clear "API error <status>" message — a rate-limit never
|
|
@@ -3556,7 +3205,7 @@ Missing: ${missing.join("; ")}
|
|
|
3556
3205
|
* is fixed across attempts.
|
|
3557
3206
|
*/
|
|
3558
3207
|
/**
|
|
3559
|
-
* Try the next fallback provider in the chain (
|
|
3208
|
+
* Try the next fallback provider in the chain (ZERO_LLM_FALLBACK).
|
|
3560
3209
|
* Updates `this.provider`, `this.model`, `this.apiKey`, `this.baseUrl`,
|
|
3561
3210
|
* `this.wireApi` to match the next valid provider. Returns `true` when a
|
|
3562
3211
|
* valid next provider was found and switched to, `false` when the chain is
|
|
@@ -3568,7 +3217,7 @@ Missing: ${missing.join("; ")}
|
|
|
3568
3217
|
this.fallbackIndex++;
|
|
3569
3218
|
const cfg = entry.credentials;
|
|
3570
3219
|
if (!cfg) {
|
|
3571
|
-
diag.warn("failover_provider_skipped", `
|
|
3220
|
+
diag.warn("failover_provider_skipped", `ZERO_LLM_FALLBACK: skipping ${entry.provider} (auth env missing)`, { provider: entry.provider, model: entry.model, cause: "auth-env-missing" });
|
|
3572
3221
|
continue;
|
|
3573
3222
|
}
|
|
3574
3223
|
this.provider = entry.provider;
|
|
@@ -3576,7 +3225,6 @@ Missing: ${missing.join("; ")}
|
|
|
3576
3225
|
this.apiKey = cfg.apiKey;
|
|
3577
3226
|
this.baseUrl = cfg.baseUrl;
|
|
3578
3227
|
this.wireApi = cfg.wireApi;
|
|
3579
|
-
this.hostedCatalogPromise = null;
|
|
3580
3228
|
diag.warn("failover_engaged", `${reason} \u2014 failover to ${entry.provider} (${entry.model})`, { reason, provider: entry.provider, model: entry.model });
|
|
3581
3229
|
return true;
|
|
3582
3230
|
}
|
|
@@ -3590,9 +3238,8 @@ Missing: ${missing.join("; ")}
|
|
|
3590
3238
|
* hammering the limit in lockstep).
|
|
3591
3239
|
*
|
|
3592
3240
|
* The body factory is valid only for the current provider and wire protocol.
|
|
3593
|
-
* A null result signals failover
|
|
3594
|
-
*
|
|
3595
|
-
*
|
|
3241
|
+
* A null result signals failover so the caller rebuilds the complete request
|
|
3242
|
+
* under its existing timeout/cancellation signal.
|
|
3596
3243
|
* Retry + failover caps documented on `retryBackoffMs` / `llm429MaxRetries`.
|
|
3597
3244
|
*
|
|
3598
3245
|
* Headers are re-resolved per attempt (via ensureFreshHeaders → OAuth
|
|
@@ -3613,9 +3260,6 @@ Missing: ${missing.join("; ")}
|
|
|
3613
3260
|
});
|
|
3614
3261
|
} catch (error) {
|
|
3615
3262
|
abort?.throwIfCancelled();
|
|
3616
|
-
if (this.provider === "hosted") {
|
|
3617
|
-
throw new Error("0sec hosted request outcome is unknown. Automatic replay is disabled; check your inference usage before retrying.", { cause: error });
|
|
3618
|
-
}
|
|
3619
3263
|
const cause = error instanceof Error ? error.cause : void 0;
|
|
3620
3264
|
const causeCode = cause && typeof cause === "object" && "code" in cause && typeof cause.code === "string" ? cause.code : "unknown";
|
|
3621
3265
|
const causeHost = cause && typeof cause === "object" && "hostname" in cause && typeof cause.hostname === "string" ? `@${cause.hostname}` : "";
|
|
@@ -3642,13 +3286,6 @@ Missing: ${missing.join("; ")}
|
|
|
3642
3286
|
if (res.ok || !isRetryableHttpStatus(res.status)) {
|
|
3643
3287
|
return res;
|
|
3644
3288
|
}
|
|
3645
|
-
if (this.provider === "hosted" && res.status === 429 && res.headers.get("x-0sec-retry-safe") !== "1") {
|
|
3646
|
-
return res;
|
|
3647
|
-
}
|
|
3648
|
-
if (this.provider === "hosted" && res.status >= 500) {
|
|
3649
|
-
await res.body?.cancel();
|
|
3650
|
-
throw new Error(`0sec hosted request returned HTTP ${res.status}; its outcome may be unknown. Automatic replay is disabled; check your inference usage before retrying.`);
|
|
3651
|
-
}
|
|
3652
3289
|
abort?.throwIfCancelled();
|
|
3653
3290
|
const is429 = res.status === 429;
|
|
3654
3291
|
let bodyText;
|
|
@@ -3739,7 +3376,6 @@ Missing: ${missing.join("; ")}
|
|
|
3739
3376
|
}
|
|
3740
3377
|
// ── Legacy Runtime interface (single-prompt) ──
|
|
3741
3378
|
async execute(prompt, context) {
|
|
3742
|
-
await this.ensureHostedModel();
|
|
3743
3379
|
const start = Date.now();
|
|
3744
3380
|
if (!this.apiKey && this.provider !== "chatgpt-codex" && this.provider !== "google") {
|
|
3745
3381
|
return {
|
|
@@ -3764,7 +3400,7 @@ Missing: ${missing.join("; ")}
|
|
|
3764
3400
|
messages.push({ role: "user", content: prompt });
|
|
3765
3401
|
res = await this.postWithRetry(() => JSON.stringify({
|
|
3766
3402
|
model: this.model,
|
|
3767
|
-
[this.maxTokensParamKey]:
|
|
3403
|
+
[this.maxTokensParamKey]: NATIVE_COMPLETION_TOKEN_LIMIT,
|
|
3768
3404
|
messages,
|
|
3769
3405
|
// See executeNative: explicit reasoning_effort passthrough only.
|
|
3770
3406
|
...this.reasoningEffort ? { reasoning_effort: this.reasoningEffort } : {}
|
|
@@ -3785,7 +3421,7 @@ Missing: ${missing.join("; ")}
|
|
|
3785
3421
|
res = await this.postWithRetry(() => JSON.stringify({
|
|
3786
3422
|
model: this.model,
|
|
3787
3423
|
input,
|
|
3788
|
-
...isCodex ? { store: false } : { max_output_tokens:
|
|
3424
|
+
...isCodex ? { store: false } : { max_output_tokens: NATIVE_COMPLETION_TOKEN_LIMIT }
|
|
3789
3425
|
}), controller.signal);
|
|
3790
3426
|
} else if (this.isGeminiCodeAssist) {
|
|
3791
3427
|
const request = {
|
|
@@ -3812,8 +3448,6 @@ Missing: ${missing.join("; ")}
|
|
|
3812
3448
|
} else {
|
|
3813
3449
|
throw new Error(`execute: provider ${this.provider} is not mapped to a wire`);
|
|
3814
3450
|
}
|
|
3815
|
-
if (!res)
|
|
3816
|
-
await this.ensureHostedModel();
|
|
3817
3451
|
} while (!res);
|
|
3818
3452
|
clearTimeout(timer);
|
|
3819
3453
|
const body = await res.text();
|
|
@@ -3896,14 +3530,7 @@ Missing: ${missing.join("; ")}
|
|
|
3896
3530
|
error: `${this.providerLabel} request cancelled by operator`
|
|
3897
3531
|
};
|
|
3898
3532
|
}
|
|
3899
|
-
/**
|
|
3900
|
-
* Public entry point. Runs {@link executeNativeAttempt} and, ONLY for a
|
|
3901
|
-
* transient empty stream (see {@link shouldRetryNativeStream}), re-issues the
|
|
3902
|
-
* whole request up to {@link llmStreamMaxAttempts} times with a short backoff.
|
|
3903
|
-
* Every other outcome — success, a real API error, a timeout, an operator
|
|
3904
|
-
* cancellation — is returned from the first attempt untouched, preserving the
|
|
3905
|
-
* existing behaviour exactly.
|
|
3906
|
-
*/
|
|
3533
|
+
/** Public entry point. Retries a transient empty stream with bounded backoff. */
|
|
3907
3534
|
async executeNative(system, messages, tools, callbacks, signal) {
|
|
3908
3535
|
const maxAttempts = llmStreamMaxAttempts();
|
|
3909
3536
|
let result;
|
|
@@ -3924,7 +3551,6 @@ Missing: ${missing.join("; ")}
|
|
|
3924
3551
|
return result;
|
|
3925
3552
|
}
|
|
3926
3553
|
async executeNativeAttempt(system, messages, tools, callbacks, signal) {
|
|
3927
|
-
await this.ensureHostedModel();
|
|
3928
3554
|
const start = Date.now();
|
|
3929
3555
|
if (!this.apiKey && this.provider !== "chatgpt-codex" && this.provider !== "google") {
|
|
3930
3556
|
return {
|
|
@@ -3989,7 +3615,7 @@ Missing: ${missing.join("; ")}
|
|
|
3989
3615
|
}
|
|
3990
3616
|
const body = {
|
|
3991
3617
|
model: this.model,
|
|
3992
|
-
[this.maxTokensParamKey]:
|
|
3618
|
+
[this.maxTokensParamKey]: NATIVE_COMPLETION_TOKEN_LIMIT,
|
|
3993
3619
|
messages: chatMessages
|
|
3994
3620
|
};
|
|
3995
3621
|
if (this.reasoningEffort) {
|
|
@@ -4057,7 +3683,7 @@ Missing: ${missing.join("; ")}
|
|
|
4057
3683
|
const body = {
|
|
4058
3684
|
model: this.model,
|
|
4059
3685
|
input,
|
|
4060
|
-
...isCodex ? { store: false, instructions: system } : { max_output_tokens:
|
|
3686
|
+
...isCodex ? { store: false, instructions: system } : { max_output_tokens: NATIVE_COMPLETION_TOKEN_LIMIT },
|
|
4061
3687
|
...reasoningEffort ? {
|
|
4062
3688
|
reasoning: {
|
|
4063
3689
|
effort: reasoningEffort,
|
|
@@ -4116,10 +3742,8 @@ Missing: ${missing.join("; ")}
|
|
|
4116
3742
|
}
|
|
4117
3743
|
}
|
|
4118
3744
|
res = await this.postWithRetry(() => JSON.stringify({ ...body, stream: true, model: this.model }), call.signal, call);
|
|
4119
|
-
if (!res)
|
|
4120
|
-
await this.ensureHostedModel();
|
|
3745
|
+
if (!res)
|
|
4121
3746
|
continue;
|
|
4122
|
-
}
|
|
4123
3747
|
if (!res.ok) {
|
|
4124
3748
|
const responseText2 = await res.text();
|
|
4125
3749
|
clearTimeout(timer);
|
|
@@ -4228,8 +3852,6 @@ Missing: ${missing.join("; ")}
|
|
|
4228
3852
|
} else {
|
|
4229
3853
|
throw new Error(`executeNative: provider ${this.provider} is not mapped to a wire`);
|
|
4230
3854
|
}
|
|
4231
|
-
if (!res)
|
|
4232
|
-
await this.ensureHostedModel();
|
|
4233
3855
|
} while (!res);
|
|
4234
3856
|
const responseText = await res.text();
|
|
4235
3857
|
clearTimeout(timer);
|
|
@@ -4507,9 +4129,14 @@ Missing: ${missing.join("; ")}
|
|
|
4507
4129
|
};
|
|
4508
4130
|
const decoder = new TextDecoder();
|
|
4509
4131
|
let buffer = "";
|
|
4132
|
+
let trailingCR = false;
|
|
4133
|
+
let receivedBytes = 0;
|
|
4134
|
+
let malformedEvents = 0;
|
|
4135
|
+
const eventTypes = /* @__PURE__ */ new Set();
|
|
4136
|
+
const identifier = (value) => typeof value === "string" && /^[A-Za-z0-9_.:-]{1,96}$/.test(value) ? value : null;
|
|
4510
4137
|
let completedResponse = null;
|
|
4511
|
-
let
|
|
4512
|
-
let
|
|
4138
|
+
let streamFailure;
|
|
4139
|
+
let responseUsage;
|
|
4513
4140
|
const streamedOutputItems = [];
|
|
4514
4141
|
let thinkingText = "";
|
|
4515
4142
|
let lastThinkingEmit = 0;
|
|
@@ -4532,7 +4159,7 @@ Missing: ${missing.join("; ")}
|
|
|
4532
4159
|
lastThinkingLength = thinkingText.length;
|
|
4533
4160
|
callbacks.onThinking(thinkingText);
|
|
4534
4161
|
};
|
|
4535
|
-
while (true) {
|
|
4162
|
+
responses: while (true) {
|
|
4536
4163
|
let chunk;
|
|
4537
4164
|
try {
|
|
4538
4165
|
chunk = await readBounded();
|
|
@@ -4565,9 +4192,18 @@ Missing: ${missing.join("; ")}
|
|
|
4565
4192
|
throw err;
|
|
4566
4193
|
}
|
|
4567
4194
|
const { done, value } = chunk;
|
|
4568
|
-
if (done)
|
|
4195
|
+
if (done) {
|
|
4196
|
+
buffer += decoder.decode();
|
|
4569
4197
|
break;
|
|
4570
|
-
|
|
4198
|
+
}
|
|
4199
|
+
receivedBytes += value.byteLength;
|
|
4200
|
+
let decoded = decoder.decode(value, { stream: true });
|
|
4201
|
+
if (decoded) {
|
|
4202
|
+
if (trailingCR && decoded.startsWith("\n"))
|
|
4203
|
+
decoded = decoded.slice(1);
|
|
4204
|
+
trailingCR = decoded.endsWith("\r");
|
|
4205
|
+
buffer += decoded.replace(/\r\n?/g, "\n");
|
|
4206
|
+
}
|
|
4571
4207
|
let boundary = buffer.indexOf("\n\n");
|
|
4572
4208
|
while (boundary >= 0) {
|
|
4573
4209
|
const rawChunk = buffer.slice(0, boundary);
|
|
@@ -4580,24 +4216,42 @@ Missing: ${missing.join("; ")}
|
|
|
4580
4216
|
let event;
|
|
4581
4217
|
try {
|
|
4582
4218
|
event = JSON.parse(payload);
|
|
4219
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) {
|
|
4220
|
+
malformedEvents++;
|
|
4221
|
+
continue;
|
|
4222
|
+
}
|
|
4583
4223
|
} catch {
|
|
4224
|
+
malformedEvents++;
|
|
4584
4225
|
continue;
|
|
4585
4226
|
}
|
|
4586
4227
|
const type = String(event.type ?? "");
|
|
4587
|
-
if (
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4228
|
+
if (eventTypes.size < 32)
|
|
4229
|
+
eventTypes.add(identifier(type) ?? "unrecognized");
|
|
4230
|
+
const terminal = type === "response.completed" || this.provider === "openrouter" && type === "response.done";
|
|
4231
|
+
if (terminal || type === "response.failed" || type === "response.incomplete" || type === "error") {
|
|
4232
|
+
const response = event.response && typeof event.response === "object" && !Array.isArray(event.response) ? event.response : void 0;
|
|
4233
|
+
const usage = response?.usage;
|
|
4234
|
+
if (usage && typeof usage.input_tokens === "number" && Number.isFinite(usage.input_tokens) && usage.input_tokens >= 0 && typeof usage.output_tokens === "number" && Number.isFinite(usage.output_tokens) && usage.output_tokens >= 0) {
|
|
4235
|
+
responseUsage = {
|
|
4236
|
+
inputTokens: usage.input_tokens,
|
|
4237
|
+
outputTokens: usage.output_tokens,
|
|
4238
|
+
...readResponsesCachedTokens(usage)
|
|
4595
4239
|
};
|
|
4596
|
-
callbacks?.onUsage?.(
|
|
4240
|
+
callbacks?.onUsage?.(responseUsage);
|
|
4597
4241
|
}
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4242
|
+
if (!terminal || !response || response.error != null || (type === "response.done" || response.status !== void 0) && response.status !== "completed") {
|
|
4243
|
+
const error = response?.error ?? event.error;
|
|
4244
|
+
const incomplete = response?.incomplete_details;
|
|
4245
|
+
streamFailure = {
|
|
4246
|
+
event: type,
|
|
4247
|
+
status: identifier(response?.status),
|
|
4248
|
+
code: identifier(error?.code ?? event.code),
|
|
4249
|
+
errorType: identifier(error?.type),
|
|
4250
|
+
reason: identifier(incomplete?.reason)
|
|
4251
|
+
};
|
|
4252
|
+
break responses;
|
|
4253
|
+
}
|
|
4254
|
+
completedResponse = response;
|
|
4601
4255
|
continue;
|
|
4602
4256
|
}
|
|
4603
4257
|
if (type === "response.output_text.delta" || this.provider === "openrouter" && type === "response.content_part.delta") {
|
|
@@ -4631,33 +4285,33 @@ Missing: ${missing.join("; ")}
|
|
|
4631
4285
|
}
|
|
4632
4286
|
continue;
|
|
4633
4287
|
}
|
|
4634
|
-
if (type === "response.completed" || type === "response.incomplete" || this.provider === "openrouter" && type === "response.done") {
|
|
4635
|
-
const response = event.response;
|
|
4636
|
-
if (response) {
|
|
4637
|
-
if (this.provider === "openrouter" && (openRouterStreamFailed || response.error != null || (type === "response.done" || response.status !== void 0) && response.status !== "completed")) {
|
|
4638
|
-
openRouterStreamFailed = true;
|
|
4639
|
-
continue;
|
|
4640
|
-
}
|
|
4641
|
-
completedResponse = response;
|
|
4642
|
-
const usage2 = response.usage;
|
|
4643
|
-
if (usage2 && this.provider !== "openrouter") {
|
|
4644
|
-
callbacks?.onUsage?.({
|
|
4645
|
-
inputTokens: Number(usage2.input_tokens ?? 0),
|
|
4646
|
-
outputTokens: Number(usage2.output_tokens ?? 0)
|
|
4647
|
-
});
|
|
4648
|
-
}
|
|
4649
|
-
}
|
|
4650
|
-
}
|
|
4651
4288
|
}
|
|
4652
4289
|
}
|
|
4653
4290
|
emitThinking(true);
|
|
4654
|
-
if (!completedResponse ||
|
|
4291
|
+
if (!completedResponse || streamFailure) {
|
|
4292
|
+
if (streamFailure) {
|
|
4293
|
+
void reader.cancel().catch(() => {
|
|
4294
|
+
});
|
|
4295
|
+
}
|
|
4296
|
+
appendNativeTrace({
|
|
4297
|
+
kind: "native-response-stream-error",
|
|
4298
|
+
provider: this.providerLabel,
|
|
4299
|
+
wireApi: this.wireApi,
|
|
4300
|
+
httpStatus: res.status,
|
|
4301
|
+
eventStreamContentType: /^text\/event-stream(?:\s*;|$)/i.test(res.headers.get("content-type") ?? ""),
|
|
4302
|
+
terminalFailure: streamFailure ?? null,
|
|
4303
|
+
eventTypes: [...eventTypes],
|
|
4304
|
+
receivedBytes,
|
|
4305
|
+
malformedEvents,
|
|
4306
|
+
trailingCharacters: buffer.length,
|
|
4307
|
+
usage: responseUsage ?? null
|
|
4308
|
+
});
|
|
4655
4309
|
return {
|
|
4656
4310
|
content: thinkingText ? [{ type: "text", text: thinkingText }] : [{ type: "text", text: "" }],
|
|
4657
4311
|
stopReason: "error",
|
|
4658
4312
|
durationMs: Date.now() - start,
|
|
4659
|
-
...
|
|
4660
|
-
error: `${this.providerLabel} API error: ${
|
|
4313
|
+
...responseUsage ? { usage: responseUsage } : {},
|
|
4314
|
+
error: `${this.providerLabel} API error: ${streamFailure ? `Responses terminal failure ${JSON.stringify(streamFailure)}` : `stream completed without final response (HTTP ${res.status}; events=${[...eventTypes].join(",") || "none"}; malformed=${malformedEvents}; trailing=${buffer.length})`}`
|
|
4661
4315
|
};
|
|
4662
4316
|
}
|
|
4663
4317
|
appendNativeTrace({
|
|
@@ -4710,21 +4364,10 @@ Missing: ${missing.join("; ")}
|
|
|
4710
4364
|
thinkingText = reasoningSummaries.join("\n");
|
|
4711
4365
|
emitThinking(true);
|
|
4712
4366
|
}
|
|
4713
|
-
const usageRecord = completedResponse.usage;
|
|
4714
|
-
const usage = usageRecord ? {
|
|
4715
|
-
inputTokens: Number(usageRecord.input_tokens ?? 0),
|
|
4716
|
-
outputTokens: Number(usageRecord.output_tokens ?? 0),
|
|
4717
|
-
// Responses `input_tokens` already INCLUDES the cached span (unlike
|
|
4718
|
-
// Anthropic, which subtracts it), so no normalisation is needed —
|
|
4719
|
-
// this is purely so cache behaviour becomes observable. Without it
|
|
4720
|
-
// the Codex cache hit rate is unmeasurable: `prompt-cache.ts`
|
|
4721
|
-
// instruments the Anthropic path only.
|
|
4722
|
-
...readResponsesCachedTokens(usageRecord)
|
|
4723
|
-
} : void 0;
|
|
4724
4367
|
return {
|
|
4725
4368
|
content,
|
|
4726
4369
|
stopReason: content.some((item) => item.type === "tool_use") ? "tool_use" : "end_turn",
|
|
4727
|
-
usage,
|
|
4370
|
+
usage: responseUsage,
|
|
4728
4371
|
durationMs: Date.now() - start,
|
|
4729
4372
|
// `outputItems` is the complete, correctly-ordered response array —
|
|
4730
4373
|
// reasoning items with their `encrypted_content` still attached, each
|
|
@@ -4767,18 +4410,12 @@ export {
|
|
|
4767
4410
|
isDiagnosticsClaimed,
|
|
4768
4411
|
recentDiagnostics,
|
|
4769
4412
|
_resetDiagnosticsForTests,
|
|
4770
|
-
DEFAULT_CLOUD_HOST,
|
|
4771
|
-
CloudAuthMissingError,
|
|
4772
|
-
CloudAuthError,
|
|
4773
|
-
loadCloudCredentials,
|
|
4774
|
-
CloudError,
|
|
4775
|
-
CloudUnauthorizedError,
|
|
4776
|
-
CloudForbiddenError,
|
|
4777
|
-
CloudNetworkError,
|
|
4778
|
-
CloudClient,
|
|
4779
4413
|
QuotaExhaustedError,
|
|
4780
4414
|
OperatorAbortError,
|
|
4781
4415
|
parseUsageLimitReached,
|
|
4416
|
+
CODEX_CLIENT_VERSION,
|
|
4417
|
+
CODEX_PROTOCOL_HEADERS,
|
|
4782
4418
|
LOOP_SERVER_COMPACTION_TOKENS,
|
|
4419
|
+
getChatGptCodexAccessToken,
|
|
4783
4420
|
LlmApiRuntime
|
|
4784
4421
|
};
|