openmausbot 0.1.97 → 0.1.99
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/dist/assets/ActivityPanel-CgUgtumZ.js +1 -0
- package/dist/assets/BotSettingsDialog-lJj6oiir.js +7 -0
- package/dist/assets/CloudBackendPicker-C5-_arUz.js +1 -0
- package/dist/assets/ComputerPanel-euJ2CSlH.js +1 -0
- package/dist/assets/DesktopViewer-XCln1Pn_.js +5 -0
- package/dist/assets/InspectorPanel-DKYyQZlo.js +5 -0
- package/dist/assets/KeyboardShortcutsModal-DkkZWZRI.js +1 -0
- package/dist/assets/LocalVmWorkspace-Cwt3_XSx.js +1 -0
- package/dist/assets/MacLocalControl-B28RbdCS.js +1 -0
- package/dist/assets/NewBotDialog-dMWDs5xm.js +2 -0
- package/dist/assets/RemoteAgentSettingsPanel-B5KWXnqH.js +1 -0
- package/dist/assets/RoutinesPage-DOosRYDK.js +1 -0
- package/dist/assets/RoutinesSection-uOfOTfkB.js +1 -0
- package/dist/assets/SettingsModal-BTGkFbj1.js +11 -0
- package/dist/assets/TeamMapPage-DqNdJn96.js +8 -0
- package/dist/assets/TriggersPanel-c6xkG9mi.js +1 -0
- package/dist/assets/VisibilitySection-DD4ffIR5.js +12 -0
- package/dist/assets/WebhooksPanel-Cz17K-_O.js +3 -0
- package/dist/assets/{abnfDiagram-O67JEVCF-k1UCNXb7.js → abnfDiagram-O67JEVCF-CX6tDpkg.js} +1 -1
- package/dist/assets/activity-BAVWO0Zj.js +1 -0
- package/dist/assets/{arc-BUWGa9UU.js → arc-h45-9NFk.js} +1 -1
- package/dist/assets/architectureDiagram-NJMV4G6O-CgLFXbg6.js +36 -0
- package/dist/assets/{blockDiagram-BEXU5L5S-Ag9nLW4H.js → blockDiagram-BEXU5L5S-DGDFFc9M.js} +1 -1
- package/dist/assets/brain-CeCdoTb2.js +1 -0
- package/dist/assets/{c4Diagram-YGBWAQC7-Bh0sjgUa.js → c4Diagram-YGBWAQC7-B9aklAUj.js} +1 -1
- package/dist/assets/channel-TsOXCiPg.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-BFBcIIqu.js → chunk-2Q5K7J3B-BC0KmWsM.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-Dvfpex-f.js → chunk-3FUC2YCW-BbDFHsJ1.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-CMjP2YZW.js → chunk-5VM5RSS4-DtGbsjOM.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-BryoeTc7.js → chunk-GTNCS2PH-VMghMcEl.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-BhfvcchO.js → chunk-GWA4HPMP-BP_JyGWQ.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-bcCVp8rp.js → chunk-JWPE2WC7-CYFyzgAU.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-yKIjIlkQ.js → chunk-NETBCI7D-DBNa_kqm.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-D3Zqbmup.js → chunk-WEXAMYUT-BKEeM7CJ.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-CjVoIMG6.js → chunk-XXDRQBXY-C__m3ZXl.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-mUCWdVyH.js → classDiagram-v2-NBCMYWYE-CBUrTSAX.js} +1 -1
- package/dist/assets/computer-control-NLov352p.js +1 -0
- package/dist/assets/core-6lvx-ypA.js +12 -0
- package/dist/assets/cose-bilkent-JH36ORCC-GRfL-1Vb.js +1 -0
- package/dist/assets/cpp-DddhVWhK.js +1 -0
- package/dist/assets/{cynefin-OW5HDTMX-BpRrxoO4.js → cynefin-OW5HDTMX-LopwGUjm.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-D3VBWCPK.js → cynefinDiagram-VND7K2PF-DSB8ZRNS.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-DxEIACOO.js → dagre-6A5THRUB-DL3Kgdfk.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-BANgZEOS.js → diagram-22UHCM2B-DIxN34BM.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-Cnq7nJir.js → diagram-3UASUU5V-CJnSvXaI.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-4TBDIWnz.js → diagram-ATOU4E4O-C-XF-lO8.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-CD_B39D4.js → diagram-CDSNMT55-Df2yZPi_.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-CzvnFhEC.js → diagram-MLGK6HIB-BBs9oZFs.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-C4w2SNml.js → diagram-MPIPVDR6-CEbK11mM.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-gkUEBm2s.js → ebnfDiagram-ZINNZB2B-BNq6Yv3C.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-B_56X6mw.js → elk-276RUBZZ-CFbQ2bGm.js} +1 -1
- package/dist/assets/engine-javascript-D5Xfc425.js +141 -0
- package/dist/assets/{erDiagram-OPXOYQCR-C_oByoDS.js → erDiagram-OPXOYQCR-Bz8vmjN4.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-CR9xXJkC.js → flowDiagram-KWPJA3E3-cQUfEYrx.js} +1 -1
- package/dist/assets/ganttDiagram-FUAMR5RP-BY8n9tbI.js +292 -0
- package/dist/assets/{gitGraphDiagram-X574FWY7-VJ6-Tp_p.js → gitGraphDiagram-X574FWY7-KduSOMDN.js} +1 -1
- package/dist/assets/image-plus-DNIWU160.js +1 -0
- package/dist/assets/index-C8xb62XS.js +585 -0
- package/dist/assets/index-DbN_Hfjs.css +1 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-2Lu9te4D.js → infoDiagram-VRGFBTTK-xBKgUkpL.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-DR49XY-e.js → ishikawaDiagram-OU5B5YK6-_ei09tAJ.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-ZoR0M305.js → journeyDiagram-ZHPQQLJL-Fp49MkSp.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-DLKHxrO-.js → kanban-definition-PNTS6WVX-CY9lLm7V.js} +1 -1
- package/dist/assets/{linear-BASsfWly.js → linear-D2ai4eM2.js} +1 -1
- package/dist/assets/{mermaid.core-BVidiPkk.js → mermaid.core-DP6qPqu1.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-g_Qx0U5C.js → mindmap-definition-NLK3R4M7-g1ynEw_d.js} +1 -1
- package/dist/assets/module-DCUsy2BQ.js +3 -0
- package/dist/assets/page-visible-BZn8304W.js +1 -0
- package/dist/assets/{pegDiagram-GJSIUBJH-DI9Cjs8w.js → pegDiagram-GJSIUBJH-Bt4ObsZj.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-sRI0Uhr5.js → pieDiagram-5QR66LMP-CeLld8bY.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-CamKTby3.js → quadrantDiagram-O4NWA36T-D4WWZw3x.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-DOLlkbf3.js → railroadDiagram-XR7U4H2S-D95P5NqU.js} +1 -1
- package/dist/assets/remote-desktop-panel-DOIMmT4T.js +1 -0
- package/dist/assets/{requirementDiagram-PLB6GJNP-DrRQ5r97.js → requirementDiagram-PLB6GJNP-D12p3RhR.js} +1 -1
- package/dist/assets/ruby-Ct1eTYOr.js +1 -0
- package/dist/assets/{sankeyDiagram-IPEJSGJF-DGS_lXcX.js → sankeyDiagram-IPEJSGJF-Co26Dwcs.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-CkjWqwtf.js → sequenceDiagram-PO4LG4MO-y5YxaDKt.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-CepRgful.js → sizeCapture-INFHLROL-D49hZ8U5.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-hykr-9RS.js → stateDiagram-v2-GCMORJYK-C0sylr-r.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-CKOHEZbI.js → swimlanes-2SLR337P-DmRWsDIs.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-DzhbBHtd.js +8 -0
- package/dist/assets/table-file.worker-KkMx-SNx.js +10 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-CB8pJ6AC.js → timeline-definition-EJHVYXUP-DVmHYs3w.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-DrclJHdl.js → usecaseDiagram-POWQR4AR-BQ1q0VV6.js} +1 -1
- package/dist/assets/user-B9lohN4n.js +1 -0
- package/dist/assets/{vennDiagram-UO4OBE2U-zS23qjv8.js → vennDiagram-UO4OBE2U-C_cnfST0.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-52jgeKxz.js → wardleyDiagram-VNRHLVJA-Bb3BSu12.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-DSdl9rQ8.js → xychartDiagram-PMCCYNJV-CcwEuuEi.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/cloud-home-start.js +19 -8
- package/dist-server/container-mcp.js +8 -0
- package/dist-server/desktop-entry.mjs +54 -0
- package/dist-server/drivers/agents-proxy.js +30 -12
- package/dist-server/index.js +2745 -1487
- package/dist-server/openmausbot.js +1004 -642
- package/dist-server/pair-cli.js +1004 -642
- package/dist-server/permission-proxy.js +2 -0
- package/dist-server/server/activity.js +2 -0
- package/dist-server/server/atomic.js +70 -2
- package/dist-server/server/checkpoints.js +55 -39
- package/dist-server/server/cloud-home-start.js +3 -3
- package/dist-server/server/config.js +22 -1
- package/dist-server/server/connector-card-text.js +15 -0
- package/dist-server/server/default-model-selection.js +7 -4
- package/dist-server/server/direct-apply.js +20 -0
- package/dist-server/server/drivers/acp/core.js +10 -0
- package/dist-server/server/drivers/acp/grok.js +47 -5
- package/dist-server/server/drivers/agents-call.js +1 -1
- package/dist-server/server/drivers/agents-catalog.js +34 -11
- package/dist-server/server/drivers/agents-proxy.js +1 -0
- package/dist-server/server/drivers/chat-mcp-tools.js +5 -3
- package/dist-server/server/drivers/claude-login-auth.js +1 -1
- package/dist-server/server/drivers/claude.js +35 -11
- package/dist-server/server/drivers/codex-device-auth.js +27 -319
- package/dist-server/server/drivers/codex.js +147 -24
- package/dist-server/server/drivers/device-auth.js +343 -0
- package/dist-server/server/drivers/openai-chat.js +17 -8
- package/dist-server/server/fleet-agent.js +18 -5
- package/dist-server/server/harness/http.js +5 -2
- package/dist-server/server/harness/registry.js +82 -45
- package/dist-server/server/harness-capabilities.js +7 -4
- package/dist-server/server/hosted-models.js +3 -1
- package/dist-server/server/index.js +471 -77
- package/dist-server/server/key-rejections.js +57 -0
- package/dist-server/server/mcp-oauth.js +125 -47
- package/dist-server/server/message-file.js +102 -7
- package/dist-server/server/model-requests.js +55 -4
- package/dist-server/server/permission-proxy.js +4 -0
- package/dist-server/server/profile-requests.js +80 -4
- package/dist-server/server/provider-key-check.js +5 -1
- package/dist-server/server/request-auth.js +2 -1
- package/dist-server/server/room-turn-timeout.js +28 -0
- package/dist-server/server/routes/thread-models.js +36 -0
- package/dist-server/server/routes/undo.js +17 -0
- package/dist-server/server/routine-requests.js +210 -6
- package/dist-server/server/routines.js +2 -2
- package/dist-server/server/setup-mode.js +1 -1
- package/dist-server/server/skill-learn.js +2 -2
- package/dist-server/server/skills.js +33 -2
- package/dist-server/server/store.js +148 -60
- package/dist-server/server/system-prompt.js +1 -1
- package/dist-server/server/team-backup.js +19 -4
- package/dist-server/server/thread-model.js +25 -0
- package/dist-server/server/turn-continuation.js +17 -16
- package/dist-server/server/webhook-ingress.js +8 -3
- package/dist-server/server/webhooks.js +40 -5
- package/dist-server/server/workspace-backup.js +6 -1
- package/dist-server/shared/device-sign-in.js +57 -0
- package/dist-server/shared/team-backup.js +2 -0
- package/dist-server/shared/thread-model.js +13 -0
- package/dist-server/vps-container-mcp.js +8 -0
- package/dist-server/workspace-backup.worker.js +42 -23
- package/package.json +1 -1
- package/skills/create-verification-skill/SKILL.md +9 -8
- package/skills/create-verification-skill/manifest.json +1 -1
- package/dist/assets/DesktopViewer-CPidMCtt.js +0 -5
- package/dist/assets/abap-BdImnpbu.js +0 -1
- package/dist/assets/actionscript-3-B3316cI-.js +0 -1
- package/dist/assets/ada-bCR0ucgS.js +0 -1
- package/dist/assets/ahk-CsyLZFj1.js +0 -1
- package/dist/assets/ahk2-8Zs4aa1G.js +0 -1
- package/dist/assets/andromeeda-C4gqWexZ.js +0 -1
- package/dist/assets/angular-html-DA-rfuFy.js +0 -1
- package/dist/assets/angular-ts-BrjP3tb8.js +0 -1
- package/dist/assets/apache-Pmp26Uib.js +0 -1
- package/dist/assets/apex-DhZFqWV2.js +0 -1
- package/dist/assets/apl-CORt7UWP.js +0 -1
- package/dist/assets/applescript-Co6uUVPk.js +0 -1
- package/dist/assets/ara-BRHolxvo.js +0 -1
- package/dist/assets/architectureDiagram-NJMV4G6O-DiPor3UT.js +0 -36
- package/dist/assets/asciidoc-CSVQ5wI8.js +0 -1
- package/dist/assets/asm-D_Q5rh1f.js +0 -1
- package/dist/assets/astro-HNnZUWAn.js +0 -1
- package/dist/assets/aurora-x-D-2ljcwZ.js +0 -1
- package/dist/assets/awk-DMzUqQB5.js +0 -1
- package/dist/assets/ayu-dark-DYE7WIF3.js +0 -1
- package/dist/assets/ayu-light-BA47KaF1.js +0 -1
- package/dist/assets/ayu-mirage-32ctXXKs.js +0 -1
- package/dist/assets/ballerina-BFfxhgS-.js +0 -1
- package/dist/assets/bat-CickPsom.js +0 -1
- package/dist/assets/beancount-k_qm7-4y.js +0 -1
- package/dist/assets/berry-uYugtg8r.js +0 -1
- package/dist/assets/bibtex-CHM0blh-.js +0 -1
- package/dist/assets/bicep-Bmn6On1c.js +0 -1
- package/dist/assets/bird2-Bx8U0n9b.js +0 -1
- package/dist/assets/blade-2xfisSek.js +0 -1
- package/dist/assets/bsl-DlhNcFeZ.js +0 -1
- package/dist/assets/c3-Dp5svz6Z.js +0 -1
- package/dist/assets/cadence-Bv_4Rxtq.js +0 -1
- package/dist/assets/cairo-KRGpt6FW.js +0 -1
- package/dist/assets/catppuccin-frappe-CZL1YF0i.js +0 -1
- package/dist/assets/catppuccin-latte-DH-8KZSZ.js +0 -1
- package/dist/assets/catppuccin-macchiato-B7yYVSCf.js +0 -1
- package/dist/assets/catppuccin-mocha-Ct7hS0mc.js +0 -1
- package/dist/assets/channel-DR8eD6QW.js +0 -1
- package/dist/assets/chapel-DTp_pixX.js +0 -1
- package/dist/assets/clarity-Dn5IMItf.js +0 -1
- package/dist/assets/clojure-P80f7IUj.js +0 -1
- package/dist/assets/cmake-D1j8_8rp.js +0 -1
- package/dist/assets/cobol-nBiQ_Alo.js +0 -1
- package/dist/assets/codeowners-Bp6g37R7.js +0 -1
- package/dist/assets/codeql-DsOJ9woJ.js +0 -1
- package/dist/assets/coffee-Ch7k5sss.js +0 -1
- package/dist/assets/common-lisp-Cg-RD9OK.js +0 -1
- package/dist/assets/coq-C7JzOVbR.js +0 -1
- package/dist/assets/cose-bilkent-JH36ORCC-BBmR1bbX.js +0 -1
- package/dist/assets/cpp-BMRokrvK.js +0 -1
- package/dist/assets/crystal-DGywbUpC.js +0 -1
- package/dist/assets/csv-fuZLfV_i.js +0 -1
- package/dist/assets/cue-D82EKSYY.js +0 -1
- package/dist/assets/cypher-COkxafJQ.js +0 -1
- package/dist/assets/d-85-TOEBH.js +0 -1
- package/dist/assets/dark-plus-C3mMm8J8.js +0 -1
- package/dist/assets/dax-CEL-wOlO.js +0 -1
- package/dist/assets/desktop-BmXAJ9_W.js +0 -1
- package/dist/assets/dotenv-Da5cRb03.js +0 -1
- package/dist/assets/dracula-BzJJZx-M.js +0 -1
- package/dist/assets/dracula-soft-BXkSAIEj.js +0 -1
- package/dist/assets/dream-maker-BtqSS_iP.js +0 -1
- package/dist/assets/edge-FbVlp4U3.js +0 -1
- package/dist/assets/elixir-CkH2-t6x.js +0 -1
- package/dist/assets/elm-DbKCFpqz.js +0 -1
- package/dist/assets/emacs-lisp-C_m_b--Z.js +0 -1
- package/dist/assets/erb-DXfck5VN.js +0 -1
- package/dist/assets/erlang-DsQrWhSR.js +0 -1
- package/dist/assets/everforest-dark-BgDCqdQA.js +0 -1
- package/dist/assets/everforest-light-C8M2exoo.js +0 -1
- package/dist/assets/fennel-BYunw83y.js +0 -1
- package/dist/assets/fluent-C4IJs8-o.js +0 -1
- package/dist/assets/fortran-fixed-form-CkoXwp7k.js +0 -1
- package/dist/assets/fortran-free-form-BxgE0vQu.js +0 -1
- package/dist/assets/fsharp-CXgrBDvD.js +0 -1
- package/dist/assets/ganttDiagram-FUAMR5RP-gtYBTu0B.js +0 -292
- package/dist/assets/gdresource-TyuKm33G.js +0 -1
- package/dist/assets/gdscript-DqcFQ5yU.js +0 -1
- package/dist/assets/gdshader-DkwncUOv.js +0 -1
- package/dist/assets/genie-D0YGMca9.js +0 -1
- package/dist/assets/gherkin-DyxjwDmM.js +0 -1
- package/dist/assets/git-commit-F4YmCXRG.js +0 -1
- package/dist/assets/git-rebase-r7XF79zn.js +0 -1
- package/dist/assets/github-dark-DHJKELXO.js +0 -1
- package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
- package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
- package/dist/assets/github-light-DAi9KRSo.js +0 -1
- package/dist/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
- package/dist/assets/gleam-BspZqrRM.js +0 -1
- package/dist/assets/glimmer-js-ByusRIyA.js +0 -1
- package/dist/assets/glimmer-ts-BfAWNZQY.js +0 -1
- package/dist/assets/glsl-DplSGwfg.js +0 -1
- package/dist/assets/gn-n2N0HUVH.js +0 -1
- package/dist/assets/gnuplot-DdkO51Og.js +0 -1
- package/dist/assets/groovy-gcz8RCvz.js +0 -1
- package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -1
- package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +0 -1
- package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +0 -1
- package/dist/assets/gruvbox-light-hard-CH1njM8p.js +0 -1
- package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +0 -1
- package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +0 -1
- package/dist/assets/hack-BWmVpMyf.js +0 -1
- package/dist/assets/haml-D5jkg6IW.js +0 -1
- package/dist/assets/handlebars-BpdQsYii.js +0 -1
- package/dist/assets/haskell-Df6bDoY_.js +0 -1
- package/dist/assets/haxe-CfZj7gIn.js +0 -1
- package/dist/assets/hcl-BWvSN4gD.js +0 -1
- package/dist/assets/hjson-D5-asLiD.js +0 -1
- package/dist/assets/hlsl-D3lLCCz7.js +0 -1
- package/dist/assets/horizon-BUw7H-hv.js +0 -1
- package/dist/assets/horizon-bright-CUuTKBJd.js +0 -1
- package/dist/assets/houston-DnULxvSX.js +0 -1
- package/dist/assets/html-derivative-DlHx6ybY.js +0 -1
- package/dist/assets/http-jrhK8wxY.js +0 -1
- package/dist/assets/hurl-irOxFIW8.js +0 -1
- package/dist/assets/hxml-2-FPmUDs.js +0 -1
- package/dist/assets/hy-DFXneXwc.js +0 -1
- package/dist/assets/imba-DGztddWO.js +0 -1
- package/dist/assets/index-Cp4S4NOL.js +0 -153
- package/dist/assets/index-CpaIXRLp.js +0 -614
- package/dist/assets/index-Z81SMsgR.css +0 -1
- package/dist/assets/ini-BEwlwnbL.js +0 -1
- package/dist/assets/jinja-f2NsQr07.js +0 -1
- package/dist/assets/jison-wvAkD_A8.js +0 -1
- package/dist/assets/jsonl-DcaNXYhu.js +0 -1
- package/dist/assets/jsonnet-DFQXde-d.js +0 -1
- package/dist/assets/jssm-C2t-YnRu.js +0 -1
- package/dist/assets/julia-5Bft2YPA.js +0 -1
- package/dist/assets/just-Cwhn7H3k.js +0 -1
- package/dist/assets/kanagawa-dragon-BuwD2xS4.js +0 -1
- package/dist/assets/kanagawa-lotus-C3DzagqV.js +0 -1
- package/dist/assets/kanagawa-wave-DFGoQZhC.js +0 -1
- package/dist/assets/kdl-DV7GczEv.js +0 -1
- package/dist/assets/kusto-wEQ09or8.js +0 -1
- package/dist/assets/laserwave-DUszq2jm.js +0 -1
- package/dist/assets/latex-D5pSuvFb.js +0 -1
- package/dist/assets/lean-BZvkOJ9d.js +0 -1
- package/dist/assets/light-plus-B7mTdjB0.js +0 -1
- package/dist/assets/liquid-C0sCDyMI.js +0 -1
- package/dist/assets/llvm-BZoOZj88.js +0 -1
- package/dist/assets/log-2UxHyX5q.js +0 -1
- package/dist/assets/logo-BtOb2qkB.js +0 -1
- package/dist/assets/luau-BnpPk5vE.js +0 -1
- package/dist/assets/marko-DjSrsDqO.js +0 -1
- package/dist/assets/material-theme-D5KoaKCx.js +0 -1
- package/dist/assets/material-theme-darker-BfHTSMKl.js +0 -1
- package/dist/assets/material-theme-lighter-B0m2ddpp.js +0 -1
- package/dist/assets/material-theme-ocean-CyktbL80.js +0 -1
- package/dist/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
- package/dist/assets/matlab-D7o27uSR.js +0 -1
- package/dist/assets/mdc-D1_yUvq7.js +0 -1
- package/dist/assets/mermaid-CQcHuHx7.js +0 -1
- package/dist/assets/min-dark-CafNBF8u.js +0 -1
- package/dist/assets/min-light-CTRr51gU.js +0 -1
- package/dist/assets/mipsasm-CKIfxQSi.js +0 -1
- package/dist/assets/mojo-DJz3ZmWd.js +0 -1
- package/dist/assets/monokai-BRVnQi9A.js +0 -1
- package/dist/assets/moonbit-CHtswR0a.js +0 -1
- package/dist/assets/move-el3G9tDJ.js +0 -1
- package/dist/assets/narrat-DRg8JJMk.js +0 -1
- package/dist/assets/nextflow-C-mBbutL.js +0 -1
- package/dist/assets/nextflow-groovy-vE_lwT2v.js +0 -1
- package/dist/assets/nginx-BpAMiNFr.js +0 -1
- package/dist/assets/night-owl-C39BiMTA.js +0 -1
- package/dist/assets/night-owl-light-CMTm3GFP.js +0 -1
- package/dist/assets/nim-BIad80T-.js +0 -1
- package/dist/assets/nix-CwoSXNpI.js +0 -1
- package/dist/assets/nord-Ddv68eIx.js +0 -1
- package/dist/assets/nsis-BlV79W_Q.js +0 -1
- package/dist/assets/nushell-D3jzshHO.js +0 -1
- package/dist/assets/objective-c-DXmwc3jG.js +0 -1
- package/dist/assets/objective-cpp-CLxacb5B.js +0 -1
- package/dist/assets/ocaml-C0hk2d4L.js +0 -1
- package/dist/assets/odin-BBf5iR-q.js +0 -1
- package/dist/assets/one-dark-pro-DVMEJ2y_.js +0 -1
- package/dist/assets/one-light-C3Wv6jpd.js +0 -1
- package/dist/assets/openscad-C4EeE6gA.js +0 -1
- package/dist/assets/org-DM6o9KBp.js +0 -1
- package/dist/assets/pascal-D93ZcfNL.js +0 -1
- package/dist/assets/perl-B9cMNwum.js +0 -1
- package/dist/assets/pkl-u5AG7uiY.js +0 -1
- package/dist/assets/plastic-3e1v2bzS.js +0 -1
- package/dist/assets/plsql-ChMvpjG-.js +0 -1
- package/dist/assets/po-BTJTHyun.js +0 -1
- package/dist/assets/poimandres-CS3Unz2-.js +0 -1
- package/dist/assets/polar-C0HS_06l.js +0 -1
- package/dist/assets/postcss-CXtECtnM.js +0 -1
- package/dist/assets/powerquery-CEu0bR-o.js +0 -1
- package/dist/assets/prisma-Vru482bI.js +0 -1
- package/dist/assets/prolog-CbFg5uaA.js +0 -1
- package/dist/assets/pug-DKIMFp6K.js +0 -1
- package/dist/assets/puppet-BMWR74SV.js +0 -1
- package/dist/assets/purescript-CklMAg4u.js +0 -1
- package/dist/assets/qml-3beO22l8.js +0 -1
- package/dist/assets/qmldir-C8lEn-DE.js +0 -1
- package/dist/assets/qss-IeuSbFQv.js +0 -1
- package/dist/assets/racket-BqYA7rlc.js +0 -1
- package/dist/assets/raku-DXvB9xmW.js +0 -1
- package/dist/assets/razor-BjBPvh-w.js +0 -1
- package/dist/assets/rbs-CpoqiR4B.js +0 -1
- package/dist/assets/red-hvxz__6c.js +0 -1
- package/dist/assets/reg-C-SQnVFl.js +0 -1
- package/dist/assets/regexp-CDVJQ6XC.js +0 -1
- package/dist/assets/rel-C3B-1QV4.js +0 -1
- package/dist/assets/riscv-BM1_JUlF.js +0 -1
- package/dist/assets/ron-D8l8udqQ.js +0 -1
- package/dist/assets/rose-pine-5qJOZa0Y.js +0 -1
- package/dist/assets/rose-pine-dawn-zx0QlTCp.js +0 -1
- package/dist/assets/rose-pine-moon-C9pEdX9L.js +0 -1
- package/dist/assets/rosmsg-BJDFO7_C.js +0 -1
- package/dist/assets/rst-bs7f0vWN.js +0 -1
- package/dist/assets/ruby-C0TQ7zu5.js +0 -1
- package/dist/assets/sas-DEy46yEz.js +0 -1
- package/dist/assets/scala-CqE71os6.js +0 -1
- package/dist/assets/scheme-C98Dy4si.js +0 -1
- package/dist/assets/sdbl-DVxCFoDh.js +0 -1
- package/dist/assets/shaderlab-Dg9Lc6iA.js +0 -1
- package/dist/assets/shellsession-BADoaaVG.js +0 -1
- package/dist/assets/slack-dark-BthQWCQV.js +0 -1
- package/dist/assets/slack-ochin-DqwNpetd.js +0 -1
- package/dist/assets/smalltalk-BOQMe2GC.js +0 -1
- package/dist/assets/smithy-cds9vsN8.js +0 -1
- package/dist/assets/snazzy-light-Bw305WKR.js +0 -1
- package/dist/assets/solarized-dark-CpvCGNkr.js +0 -1
- package/dist/assets/solarized-light-Dlz6yCKv.js +0 -1
- package/dist/assets/solidity-DijEV5ha.js +0 -1
- package/dist/assets/soy-8wufbnw4.js +0 -1
- package/dist/assets/sparql-rVzFXLq3.js +0 -1
- package/dist/assets/splunk-BtCnVYZw.js +0 -1
- package/dist/assets/ssh-config-_ykCGR6B.js +0 -1
- package/dist/assets/stata-DI20mbqo.js +0 -1
- package/dist/assets/stylus-BEDo0Tqx.js +0 -1
- package/dist/assets/surrealql-Cjom0U5J.js +0 -1
- package/dist/assets/svelte-Cy7k_4gC.js +0 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-D-8vqZ4-.js +0 -8
- package/dist/assets/synthwave-84-CbfX1IO0.js +0 -1
- package/dist/assets/system-verilog-0hqHdDBg.js +0 -1
- package/dist/assets/systemd-4A_iFExJ.js +0 -1
- package/dist/assets/talonscript-CkByrt1z.js +0 -1
- package/dist/assets/tasl-QIJgUcNo.js +0 -1
- package/dist/assets/tcl-dwOrl1Do.js +0 -1
- package/dist/assets/templ-DhtptRzy.js +0 -1
- package/dist/assets/terraform-BETggiCN.js +0 -1
- package/dist/assets/tex-D96PA37w.js +0 -1
- package/dist/assets/tokyo-night-hegEt444.js +0 -1
- package/dist/assets/ts-tags-D351s5mN.js +0 -1
- package/dist/assets/tsv-B_m7g4N7.js +0 -1
- package/dist/assets/turtle-BsS91CYL.js +0 -1
- package/dist/assets/twig-27uCiNez.js +0 -1
- package/dist/assets/typespec-CAFt9gP4.js +0 -1
- package/dist/assets/typst-BUadGCkm.js +0 -1
- package/dist/assets/v-BGw2Nkan.js +0 -1
- package/dist/assets/vala-CsfeWuGM.js +0 -1
- package/dist/assets/vb-Cu-pLBUe.js +0 -1
- package/dist/assets/verilog-nZwndyjY.js +0 -1
- package/dist/assets/vesper-DRje8inN.js +0 -1
- package/dist/assets/vhdl-CeAyd5Ju.js +0 -1
- package/dist/assets/viml-CJc9bBzg.js +0 -1
- package/dist/assets/vitesse-black-Bkuqu6BP.js +0 -1
- package/dist/assets/vitesse-dark-D0r3Knsf.js +0 -1
- package/dist/assets/vitesse-light-CVO1_9PV.js +0 -1
- package/dist/assets/vue-BqiEGhQt.js +0 -1
- package/dist/assets/vue-html-AaS7Mt5G.js +0 -1
- package/dist/assets/vue-vine-BoDAl6tE.js +0 -1
- package/dist/assets/vyper-CDx5xZoG.js +0 -1
- package/dist/assets/wasm-CG6Dc4jp.js +0 -1
- package/dist/assets/wenyan-BV7otONQ.js +0 -1
- package/dist/assets/wgsl-Dx-B1_4e.js +0 -1
- package/dist/assets/wikitext-BhOHFoWU.js +0 -1
- package/dist/assets/wit-5i3qLPDT.js +0 -1
- package/dist/assets/wolfram-lXgVvXCa.js +0 -1
- package/dist/assets/xsl-CtQFsRM5.js +0 -1
- package/dist/assets/zenscript-DVFEvuxE.js +0 -1
- package/dist/assets/zig-VOosw3JB.js +0 -1
- /package/dist/assets/{shellscript-Yzrsuije.js → bash-Yzrsuije.js} +0 -0
- /package/dist/assets/{docker-BcOcwvcX.js → dockerfile-BcOcwvcX.js} +0 -0
- /package/dist/assets/{make-CHLpvVh8.js → makefile-CHLpvVh8.js} +0 -0
|
@@ -10,7 +10,7 @@ import { codexToolSurfaceArgs } from "./codex-tool-surface.js";
|
|
|
10
10
|
//
|
|
11
11
|
// resumeCursor is the codex thread id; a later turn tries thread/resume
|
|
12
12
|
// and preserves that history or reports a failed resume.
|
|
13
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
13
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
14
14
|
import { createHash } from "node:crypto";
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
import { homedir } from "node:os";
|
|
@@ -23,7 +23,7 @@ import { ChatGptPlanAuthController } from "./chatgpt-plan-auth.js";
|
|
|
23
23
|
import { describeSpawnFailure, execCli, killCliTree, spawnCli } from "../procs.js";
|
|
24
24
|
import { isHarnessOwnedMcpEnvName } from "../mcp-registry.js";
|
|
25
25
|
import { newEventId, newId } from "../contracts.js";
|
|
26
|
-
import { decodeCodexSelection, readCodexModelCatalog, STATIC_CODEX_MODELS } from "./codex-catalog.js";
|
|
26
|
+
import { decodeCodexSelection, OFFICIAL_CODEX_PROVIDER, readCodexModelCatalog, STATIC_CODEX_MODELS } from "./codex-catalog.js";
|
|
27
27
|
import { codexLocalProviderArgs } from "./local-inject.js";
|
|
28
28
|
import { augmentedPath, splitCliString } from "../env-path.js";
|
|
29
29
|
import { classifyError, computeBackoff, interruptibleDelay, RETRY_MAX_ATTEMPTS } from "./retry.js";
|
|
@@ -33,7 +33,8 @@ import { commandSummary, toolDetailPreview } from "../tool-summary.js";
|
|
|
33
33
|
import { codexDeveloperInstructions, syncCodexInstructions } from "./codex-instructions.js";
|
|
34
34
|
import { volatileContextNote, withContextNote } from "./prompt-split.js";
|
|
35
35
|
import { CodexDeviceAuthController } from "./codex-device-auth.js";
|
|
36
|
-
import { codexAccountEmail } from "./codex-identity.js";
|
|
36
|
+
import { codexAccountEmail, codexHome } from "./codex-identity.js";
|
|
37
|
+
import { keyRejected, noteKeyAccepted, noteKeyRejected } from "../key-rejections.js";
|
|
37
38
|
import { classifyResumeFailure, mayReplay, recoveryPromptFor } from "../resume-recovery.js";
|
|
38
39
|
import { extractMcpImages } from "../mcp-tool-images.js";
|
|
39
40
|
import { parseProtocolAskQuestions, questionAnswersById, questionChoices } from "../../shared/ask-question.js";
|
|
@@ -54,6 +55,30 @@ export function codexUserError(value, chatgptPlan) {
|
|
|
54
55
|
}
|
|
55
56
|
return value.slice(0, 400);
|
|
56
57
|
}
|
|
58
|
+
// Codex's own words when OpenAI refuses its stored ChatGPT login (codex-cli
|
|
59
|
+
// 0.160 login/src/auth: workspace routing, token refresh, auth storage).
|
|
60
|
+
const CODEX_SIGN_IN_REFUSED = /workspace routing discovery unauthorized|access token could not be refreshed|authentication session could not be refreshed|ChatGPT login is required|auth data is not available|please (?:log out and )?sign in again/i;
|
|
61
|
+
/** A turn error (TurnError: message, codexErrorInfo) that says Codex's own
|
|
62
|
+
* sign-in was refused: `unauthorized`, a 401 from the model backend, or one
|
|
63
|
+
* of Codex's sign-in messages. A 401 from an MCP server or a tool reaches the
|
|
64
|
+
* model as a tool result, never as a turn error, so it cannot land here. */
|
|
65
|
+
export function codexSignInRefused(error) {
|
|
66
|
+
if (!error || typeof error !== "object")
|
|
67
|
+
return false;
|
|
68
|
+
const { message, codexErrorInfo: info } = error;
|
|
69
|
+
if (info === "unauthorized")
|
|
70
|
+
return true;
|
|
71
|
+
if (info && typeof info === "object" &&
|
|
72
|
+
Object.values(info).some((variant) => variant?.httpStatusCode === 401))
|
|
73
|
+
return true;
|
|
74
|
+
return typeof message === "string" && CODEX_SIGN_IN_REFUSED.test(message);
|
|
75
|
+
}
|
|
76
|
+
export const CODEX_SIGN_IN_EXPIRED = "Codex's ChatGPT sign-in has expired. Sign in again in Settings → Model providers → Codex.";
|
|
77
|
+
/** The plain sentence first, so a peer bot's one-line report keeps it;
|
|
78
|
+
* Codex's own words follow as the detail. */
|
|
79
|
+
export function codexSignInExpired(raw) {
|
|
80
|
+
return `${CODEX_SIGN_IN_EXPIRED} Codex said: ${raw.slice(0, 300)}`;
|
|
81
|
+
}
|
|
57
82
|
class CodexRpcError extends Error {
|
|
58
83
|
code;
|
|
59
84
|
constructor(error) {
|
|
@@ -605,10 +630,47 @@ export const CodexDriver = {
|
|
|
605
630
|
}
|
|
606
631
|
else
|
|
607
632
|
await refreshModels();
|
|
633
|
+
// Codex's own ChatGPT login (not ChatGPT plan, whose tokens OpenMausBot
|
|
634
|
+
// holds, nor Company routing) can be refused by OpenAI while `codex login
|
|
635
|
+
// status` still reports it. A refusal marks it the way a rejected API key
|
|
636
|
+
// is marked (key-rejections.ts): its credential home, plus the stored
|
|
637
|
+
// auth file, so a sign-in made anywhere else starts over. A later turn
|
|
638
|
+
// that succeeds, a new sign-in and sign-out clear it. Only a stored
|
|
639
|
+
// ChatGPT login is marked: an API-key login (`codex login --with-api-key`)
|
|
640
|
+
// cannot be fixed by the ChatGPT sign-in Settings offers.
|
|
641
|
+
const ownLogin = !plan && !config.managed;
|
|
642
|
+
const loginMark = () => {
|
|
643
|
+
const home = ownLogin ? codexHome(childEnv()) : null;
|
|
644
|
+
if (!home)
|
|
645
|
+
return null;
|
|
646
|
+
let stored = "";
|
|
647
|
+
try {
|
|
648
|
+
stored = readFileSync(join(home, "auth.json"), "utf8");
|
|
649
|
+
}
|
|
650
|
+
catch {
|
|
651
|
+
return null; /* keyring, or none */
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
const auth = JSON.parse(stored);
|
|
655
|
+
const chatgpt = typeof auth.auth_mode === "string" ? /chatgpt/i.test(auth.auth_mode) : Boolean(auth.tokens);
|
|
656
|
+
if (!chatgpt)
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
catch {
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
return [`codex-login:${home}`, stored];
|
|
663
|
+
};
|
|
664
|
+
const loginRefused = () => { const mark = loginMark(); if (mark)
|
|
665
|
+
noteKeyRejected(...mark); };
|
|
666
|
+
const loginAccepted = (mark = loginMark()) => { if (mark)
|
|
667
|
+
noteKeyAccepted(...mark); };
|
|
668
|
+
const loginRejected = () => { const mark = loginMark(); return mark !== null && keyRejected(...mark); };
|
|
608
669
|
const authentication = new CodexDeviceAuthController({
|
|
609
670
|
cli: config.cli,
|
|
610
671
|
environment: childEnv,
|
|
611
|
-
|
|
672
|
+
signInRejected: loginRejected,
|
|
673
|
+
onAuthenticated: async () => { loginAccepted(); await refreshModels(); },
|
|
612
674
|
});
|
|
613
675
|
const listeners = new Set();
|
|
614
676
|
const active = new Map();
|
|
@@ -690,6 +752,12 @@ export const CodexDriver = {
|
|
|
690
752
|
// a retry relaunches the whole app-server; the backoff is scaled down in
|
|
691
753
|
// tests so a fake's transient failures don't stall real seconds
|
|
692
754
|
const retryScale = Number(process.env.FAKE_CODEX_RETRY_SCALE ?? "1");
|
|
755
|
+
// Only a turn on the official provider says anything about Codex's
|
|
756
|
+
// ChatGPT login: a custom provider's 401 is its own key's, and its
|
|
757
|
+
// success proves nothing about ChatGPT. No model means the catalog's
|
|
758
|
+
// default, which is provider-qualified when config.toml picks another.
|
|
759
|
+
const chatgptTurn = ownLogin &&
|
|
760
|
+
decodeCodexSelection(turn.model || models.default).modelProvider === OFFICIAL_CODEX_PROVIDER;
|
|
693
761
|
const launchAttempt = async (attempt) => {
|
|
694
762
|
const env = childEnv();
|
|
695
763
|
if (planToken)
|
|
@@ -784,6 +852,13 @@ export const CodexDriver = {
|
|
|
784
852
|
const state = {
|
|
785
853
|
settled: false,
|
|
786
854
|
lastError: "",
|
|
855
|
+
// whether lastError went out marked setup (a sign-in to fix)
|
|
856
|
+
lastErrorSetup: false,
|
|
857
|
+
// an error Codex said it would retry itself (willRetry), kept only
|
|
858
|
+
// to explain a turn that then fails without words of its own
|
|
859
|
+
retryError: "",
|
|
860
|
+
// Codex started recovering its model provider's sign-in this turn
|
|
861
|
+
authRecovery: false,
|
|
787
862
|
lastText: "",
|
|
788
863
|
sawStreamDelta: false,
|
|
789
864
|
// codex reports token usage as a running total for this app-server
|
|
@@ -1122,6 +1197,25 @@ export const CodexDriver = {
|
|
|
1122
1197
|
message: `Codex automatic review ${outcome}${target}. Action did not run. Retry stays ${retryMode}. Select Ask for human approval in approval settings.`,
|
|
1123
1198
|
});
|
|
1124
1199
|
};
|
|
1200
|
+
// The turn's failure, said once. An error notification and the
|
|
1201
|
+
// turn/completed after it usually carry the same words; the second
|
|
1202
|
+
// only speaks again to deliver a sign-in flag the first lacked.
|
|
1203
|
+
// Codex's own refused sign-in reads as one plain sentence and marks
|
|
1204
|
+
// the login, so Settings asks for a new sign-in too.
|
|
1205
|
+
const turnError = (error) => {
|
|
1206
|
+
const raw = String(error.message);
|
|
1207
|
+
const refused = chatgptTurn && loginMark() !== null && (codexSignInRefused(error) ||
|
|
1208
|
+
(state.authRecovery && !/\b403\b|forbidden/i.test(raw) && /\b401\b|unauthorized/i.test(raw)));
|
|
1209
|
+
if (refused)
|
|
1210
|
+
loginRefused();
|
|
1211
|
+
const message = refused ? codexSignInExpired(raw) : codexUserError(raw, plan);
|
|
1212
|
+
const setup = refused || classifyError({ text: message }).reason === "auth";
|
|
1213
|
+
if (message === state.lastError && (state.lastErrorSetup || !setup))
|
|
1214
|
+
return;
|
|
1215
|
+
state.lastError = message;
|
|
1216
|
+
state.lastErrorSetup ||= setup;
|
|
1217
|
+
emit({ ...base(threadId, turnId), type: "runtime.error", message, ...(setup ? { setup: true } : {}) });
|
|
1218
|
+
};
|
|
1125
1219
|
const handleNotification = (msg) => {
|
|
1126
1220
|
const p = msg.params ?? {};
|
|
1127
1221
|
// An app-server also emits notifications for native helper threads.
|
|
@@ -1322,27 +1416,43 @@ export const CodexDriver = {
|
|
|
1322
1416
|
if (reviewWarning && !timedOutReview)
|
|
1323
1417
|
reviewNotice("warning");
|
|
1324
1418
|
const t = p.turn ?? {};
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1419
|
+
if (t.status === "completed") {
|
|
1420
|
+
if (chatgptTurn)
|
|
1421
|
+
loginAccepted();
|
|
1422
|
+
}
|
|
1423
|
+
else if (typeof t.error?.message === "string") {
|
|
1424
|
+
turnError(t.error);
|
|
1425
|
+
}
|
|
1426
|
+
else if (t.status === "failed" && !state.lastError && state.retryError) {
|
|
1427
|
+
// Codex gave up retrying without a final word: its last one
|
|
1428
|
+
turnError({ message: state.retryError });
|
|
1331
1429
|
}
|
|
1332
1430
|
void settle(t.status === "completed", t.status === "completed" ? null :
|
|
1333
|
-
(classifyError({ text:
|
|
1431
|
+
(classifyError({ text: state.lastError }).reason === "provider_safety" ? "provider_safety" : (state.lastError || t.status || "failed")));
|
|
1334
1432
|
break;
|
|
1335
1433
|
}
|
|
1336
|
-
case "error":
|
|
1337
|
-
// shape drift: 0.144 sends {message}, 0.139
|
|
1338
|
-
// {error:{message}} — surface either
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1434
|
+
case "error": {
|
|
1435
|
+
// shape drift: 0.144 sends {message}, 0.139 and 0.160 nest it
|
|
1436
|
+
// under {error:{message, codexErrorInfo}} — surface either
|
|
1437
|
+
// (agentcal armor)
|
|
1438
|
+
const error = p.error && typeof p.error === "object" ? p.error : { message: p.message };
|
|
1439
|
+
if (!error.message)
|
|
1440
|
+
break;
|
|
1441
|
+
// 0.160 reports each of its own reconnects ("Reconnecting...
|
|
1442
|
+
// 1/5") with willRetry: true. Those are not the turn's failure;
|
|
1443
|
+
// the final error, or turn/completed, says how it ended.
|
|
1444
|
+
if (p.willRetry === true) {
|
|
1445
|
+
state.retryError = String(error.message);
|
|
1446
|
+
break;
|
|
1345
1447
|
}
|
|
1448
|
+
turnError(error);
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1451
|
+
case "modelProvider/authRecoveryStarted":
|
|
1452
|
+
state.authRecovery = true;
|
|
1453
|
+
break;
|
|
1454
|
+
case "modelProvider/authRecoveryCompleted":
|
|
1455
|
+
state.authRecovery = false;
|
|
1346
1456
|
break;
|
|
1347
1457
|
}
|
|
1348
1458
|
};
|
|
@@ -1732,8 +1842,10 @@ export const CodexDriver = {
|
|
|
1732
1842
|
}
|
|
1733
1843
|
catch (e) {
|
|
1734
1844
|
const failure = e instanceof Error ? e : { text: String(e) };
|
|
1735
|
-
const
|
|
1736
|
-
const
|
|
1845
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
1846
|
+
const refused = chatgptTurn && loginMark() !== null && codexSignInRefused({ message: raw });
|
|
1847
|
+
const message = refused ? codexSignInExpired(raw) : codexUserError(raw, plan);
|
|
1848
|
+
const needsAuth = refused || /(?:\b401\b|unauthorized|missing bearer|authentication required)/i.test(message);
|
|
1737
1849
|
const verdict = classifyError(failure);
|
|
1738
1850
|
// Three guards hold here: main's abandoned attempt never retries,
|
|
1739
1851
|
// neither does a Company session already recovered once from canonical
|
|
@@ -1767,6 +1879,8 @@ export const CodexDriver = {
|
|
|
1767
1879
|
// abandoned marks an attempt retired by a retry; its late rpc
|
|
1768
1880
|
// timeouts must neither report a spurious error nor relaunch again
|
|
1769
1881
|
if (!state.settled && !abandoned) {
|
|
1882
|
+
if (refused)
|
|
1883
|
+
loginRefused();
|
|
1770
1884
|
emit({
|
|
1771
1885
|
...base(threadId, turnId),
|
|
1772
1886
|
type: "runtime.error",
|
|
@@ -1797,6 +1911,11 @@ export const CodexDriver = {
|
|
|
1797
1911
|
const authenticated = await new Promise((resolve) => {
|
|
1798
1912
|
execCli(config.cli, ["login", "status"], { timeout: 8000, env }, (err, stdout, stderr) => resolve(!err && /^logged in\b/im.test(`${stdout}\n${stderr ?? ""}`)));
|
|
1799
1913
|
});
|
|
1914
|
+
// Signed in as far as the CLI knows, but OpenAI refused it on a real turn.
|
|
1915
|
+
if (authenticated && loginRejected()) {
|
|
1916
|
+
return { state: "available", version, authenticated: false, reason: CODEX_SIGN_IN_EXPIRED,
|
|
1917
|
+
update: await codexReleaseUpdate(version, config.cli), billing: "subscription" };
|
|
1918
|
+
}
|
|
1800
1919
|
// Display identity only, so Settings can say whose ChatGPT account the
|
|
1801
1920
|
// bots run on; the status command above stays the authority on sign-in.
|
|
1802
1921
|
const email = authenticated ? await codexAccountEmail(config.cli, env) : null;
|
|
@@ -1837,8 +1956,12 @@ export const CodexDriver = {
|
|
|
1837
1956
|
},
|
|
1838
1957
|
cancelAuthentication: () => (planAuth ?? authentication).cancel(),
|
|
1839
1958
|
signOut: async () => {
|
|
1840
|
-
if (!planAuth)
|
|
1841
|
-
|
|
1959
|
+
if (!planAuth) {
|
|
1960
|
+
const mark = loginMark();
|
|
1961
|
+
await authentication.signOut();
|
|
1962
|
+
loginAccepted(mark);
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1842
1965
|
planSigningOut = true;
|
|
1843
1966
|
planGeneration++;
|
|
1844
1967
|
try {
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { stripVTControlCharacters } from "node:util";
|
|
6
|
+
import { deviceSignInPrompt } from "../../shared/device-sign-in.js";
|
|
7
|
+
import { killCliTree, spawnCli } from "../procs.js";
|
|
8
|
+
const MAX_OUTPUT = 16_384;
|
|
9
|
+
// Two configured instances can use the same on-disk login. Only the auth
|
|
10
|
+
// operation is exclusive: normal turns are not blocked by this lock.
|
|
11
|
+
const authenticatingHomes = new Set();
|
|
12
|
+
/** The real path of a credential home, so two spellings of one home share
|
|
13
|
+
* one sign-in lock. A missing tail keeps its name under its real parent. */
|
|
14
|
+
export function canonicalPath(path) {
|
|
15
|
+
try {
|
|
16
|
+
return realpathSync(path);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
const parent = dirname(path);
|
|
20
|
+
return parent === path ? path : join(canonicalPath(parent), basename(path));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** A fixed login command, not a remotely accessible terminal. CLI output
|
|
24
|
+
* stays in bounded private memory; only a device page and code are exposed. */
|
|
25
|
+
export class DeviceAuthController {
|
|
26
|
+
flow = null;
|
|
27
|
+
command = null;
|
|
28
|
+
disposed = false;
|
|
29
|
+
spec;
|
|
30
|
+
options;
|
|
31
|
+
constructor(spec, options) {
|
|
32
|
+
this.spec = spec;
|
|
33
|
+
this.options = options;
|
|
34
|
+
}
|
|
35
|
+
/** The credential home the lock is held on, for this environment. */
|
|
36
|
+
home(env, action) {
|
|
37
|
+
const { homeEnv, homeDir, product } = this.spec;
|
|
38
|
+
const home = env.HOME || env.USERPROFILE || homedir();
|
|
39
|
+
const named = env[homeEnv];
|
|
40
|
+
if (!isAbsolute(home) || (named && !isAbsolute(named))) {
|
|
41
|
+
throw new Error(`Use an absolute HOME and ${homeEnv} path for this server's ${product} provider before ${action}.`);
|
|
42
|
+
}
|
|
43
|
+
return { home, homeKey: canonicalPath(resolve(named || join(home, homeDir))) };
|
|
44
|
+
}
|
|
45
|
+
async start() {
|
|
46
|
+
const { product, account, status } = this.spec;
|
|
47
|
+
if (this.disposed)
|
|
48
|
+
throw new Error("This provider was removed. Refresh Settings before signing in.");
|
|
49
|
+
if (this.flow?.status.phase === "waiting") {
|
|
50
|
+
if (this.flow.ready)
|
|
51
|
+
return { ...this.flow.status, phase: "waiting" };
|
|
52
|
+
throw new Error(`A ${account} sign-in is already starting. Please wait for the code.`);
|
|
53
|
+
}
|
|
54
|
+
await this.flow?.stopping;
|
|
55
|
+
if (this.disposed)
|
|
56
|
+
throw new Error("This provider was removed. Refresh Settings before signing in.");
|
|
57
|
+
const env = this.options.environment();
|
|
58
|
+
const { home, homeKey } = this.home(env, "signing in");
|
|
59
|
+
if (authenticatingHomes.has(homeKey)) {
|
|
60
|
+
throw new Error(`A ${account} sign-in is already running for this server account. Finish or cancel it before starting another.`);
|
|
61
|
+
}
|
|
62
|
+
authenticatingHomes.add(homeKey);
|
|
63
|
+
return new Promise((resolveStart, reject) => {
|
|
64
|
+
const flow = {
|
|
65
|
+
status: {
|
|
66
|
+
phase: "waiting", flowId: randomUUID(), authorizationUrl: null,
|
|
67
|
+
expiresAt: new Date(Date.now() + (this.options.lifetimeMs ?? 15 * 60_000)).toISOString(),
|
|
68
|
+
},
|
|
69
|
+
child: null, ready: false, resolve: resolveStart, reject, homeKey,
|
|
70
|
+
startupTimer: setTimeout(() => this.finish(flow, "failed", `${product} did not provide a sign-in code in time. Check the server connection and update ${product}, then try again.`), this.options.startupTimeoutMs ?? 30_000),
|
|
71
|
+
expiryTimer: setTimeout(() => this.finish(flow, "expired", `The ${account} sign-in code expired. Start sign-in again.`), this.options.lifetimeMs ?? 15 * 60_000),
|
|
72
|
+
};
|
|
73
|
+
flow.startupTimer.unref();
|
|
74
|
+
flow.expiryTimer.unref();
|
|
75
|
+
this.flow = flow;
|
|
76
|
+
const login = () => this.run(flow, [...this.spec.loginArgs], env, home, (loginCode, loginOutput) => {
|
|
77
|
+
if (loginCode !== 0 || !flow.ready) {
|
|
78
|
+
this.finish(flow, "failed", this.spec.failure(loginOutput));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// A successful command is not enough: confirm the sign-in the way
|
|
82
|
+
// this client's bots will find it, with the same executable and
|
|
83
|
+
// environment.
|
|
84
|
+
flow.startupTimer = setTimeout(() => this.finish(flow, "failed", `${product} finished sign-in but could not confirm the account. Refresh Settings and try again.`), this.options.startupTimeoutMs ?? 30_000);
|
|
85
|
+
flow.startupTimer.unref();
|
|
86
|
+
this.confirm(flow, env, home, (signedIn) => this.finish(flow, signedIn ? "succeeded" : "failed", `${product} finished sign-in but did not confirm a ${account} account. Refresh Settings and try again.`));
|
|
87
|
+
}, true);
|
|
88
|
+
// Never overwrite a working login just because Connect was clicked
|
|
89
|
+
// twice. One the provider refused is not working, whatever status says.
|
|
90
|
+
if (!status) {
|
|
91
|
+
login();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.run(flow, [...status.args], env, home, (code, output) => {
|
|
95
|
+
const state = status.read(code, output);
|
|
96
|
+
if (state === "signed-in" && !this.options.signInRejected?.())
|
|
97
|
+
this.finish(flow, "succeeded");
|
|
98
|
+
else if (state === "signed-in" || state === "signed-out")
|
|
99
|
+
login();
|
|
100
|
+
else if (state === "other")
|
|
101
|
+
this.finish(flow, "failed", `${product} already has a different sign-in method on this server. Ask the server administrator to review it before changing accounts.`);
|
|
102
|
+
else
|
|
103
|
+
this.finish(flow, "failed", `${product} could not confirm the existing sign-in on this server. Update ${product} and check its login status before trying again.`);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async get(flowId) {
|
|
108
|
+
if (!flowId || this.flow?.status.flowId !== flowId)
|
|
109
|
+
throw new Error("This sign-in is no longer available. Start sign-in again.");
|
|
110
|
+
return { ...this.flow.status };
|
|
111
|
+
}
|
|
112
|
+
async cancel() {
|
|
113
|
+
if (this.flow?.status.phase === "waiting")
|
|
114
|
+
this.finish(this.flow, "cancelled", `${this.spec.account} sign-in cancelled.`);
|
|
115
|
+
await this.flow?.stopping;
|
|
116
|
+
if (this.flow?.terminationFailed)
|
|
117
|
+
throw new Error(this.flow.status.message);
|
|
118
|
+
if (this.command && !await this.stopChild(this.command)) {
|
|
119
|
+
throw new Error(`${this.spec.product} could not be stopped on this server. Ask the server administrator to stop the account command before trying again.`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async dispose() {
|
|
123
|
+
this.disposed = true;
|
|
124
|
+
await this.cancel();
|
|
125
|
+
this.flow = null;
|
|
126
|
+
}
|
|
127
|
+
/** Remove the sign-in the CLI stores for this server account so a
|
|
128
|
+
* different account can connect. A sign-in in progress is never pulled
|
|
129
|
+
* away underneath the browser completing it. */
|
|
130
|
+
async signOut() {
|
|
131
|
+
const { product, account, status, logoutArgs } = this.spec;
|
|
132
|
+
if (!status || !logoutArgs)
|
|
133
|
+
throw new Error(`Signing out of ${account} is not available from here.`);
|
|
134
|
+
if (this.disposed)
|
|
135
|
+
throw new Error("This provider was removed. Refresh Settings before signing out.");
|
|
136
|
+
if (this.flow?.status.phase === "waiting")
|
|
137
|
+
throw new Error(`Finish or cancel the ${account} sign-in in progress before signing out.`);
|
|
138
|
+
await this.flow?.stopping;
|
|
139
|
+
if (this.disposed)
|
|
140
|
+
throw new Error("This provider was removed. Refresh Settings before signing out.");
|
|
141
|
+
const env = this.options.environment();
|
|
142
|
+
const { home, homeKey } = this.home(env, "signing out");
|
|
143
|
+
if (authenticatingHomes.has(homeKey)) {
|
|
144
|
+
throw new Error(`A ${account} sign-in is running for this server account. Finish or cancel it before signing out.`);
|
|
145
|
+
}
|
|
146
|
+
authenticatingHomes.add(homeKey);
|
|
147
|
+
try {
|
|
148
|
+
const before = await this.exec([...status.args], env, home);
|
|
149
|
+
const state = status.read(before.code, before.output);
|
|
150
|
+
if (state === "signed-out")
|
|
151
|
+
return;
|
|
152
|
+
if (state !== "signed-in") {
|
|
153
|
+
throw new Error(`${product} did not confirm a ${account} sign-in. Other authentication methods will not be removed; ask the server administrator to check the account.`);
|
|
154
|
+
}
|
|
155
|
+
const logout = await this.exec([...logoutArgs], env, home);
|
|
156
|
+
if (logout.code !== 0)
|
|
157
|
+
throw new Error(`${product} could not remove the sign-in on this server. Check the server's ${product} installation and try again.`);
|
|
158
|
+
// The command's own report is not enough: confirm with the same status
|
|
159
|
+
// check that decides whether bots may run on this account.
|
|
160
|
+
const after = await this.exec([...status.args], env, home);
|
|
161
|
+
if (status.read(after.code, after.output) !== "signed-out") {
|
|
162
|
+
throw new Error(`${product} still reports a sign-in on this server. Update ${product} and check its login status before trying again.`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
// If the OS cannot stop a command, it may still change credentials.
|
|
167
|
+
// Keep the home reserved until that exact child actually exits.
|
|
168
|
+
const child = this.command;
|
|
169
|
+
if (child && child.exitCode === null && child.signalCode === null) {
|
|
170
|
+
child.once("close", () => authenticatingHomes.delete(homeKey));
|
|
171
|
+
}
|
|
172
|
+
else
|
|
173
|
+
authenticatingHomes.delete(homeKey);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** After a login command succeeded: the status command when the CLI has
|
|
177
|
+
* one, else the stored sign-in a turn checks for. */
|
|
178
|
+
confirm(flow, env, home, done) {
|
|
179
|
+
const status = this.spec.status;
|
|
180
|
+
if (status) {
|
|
181
|
+
this.run(flow, [...status.args], env, home, (code, output) => done(status.read(code, output) === "signed-in"));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
let signedIn = false;
|
|
185
|
+
try {
|
|
186
|
+
signedIn = this.spec.signedIn?.(env) === true;
|
|
187
|
+
}
|
|
188
|
+
catch { /* unreadable: not signed in */ }
|
|
189
|
+
done(signedIn);
|
|
190
|
+
}
|
|
191
|
+
startFailure(error) {
|
|
192
|
+
const { product, install } = this.spec;
|
|
193
|
+
return error.code === "ENOENT"
|
|
194
|
+
? `${product} is not installed on this server. ${install}`
|
|
195
|
+
: `${product} could not start on this server. Check the configured CLI path and its executable permissions.`;
|
|
196
|
+
}
|
|
197
|
+
/** One bounded, non-interactive command. Its output stays here; callers
|
|
198
|
+
* see an exit code and a status-line match, never the text. */
|
|
199
|
+
exec(args, env, cwd) {
|
|
200
|
+
const { product } = this.spec;
|
|
201
|
+
return new Promise((resolveExec, rejectExec) => {
|
|
202
|
+
if (this.disposed) {
|
|
203
|
+
rejectExec(new Error("This provider was removed. Refresh Settings before signing out."));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
let child;
|
|
207
|
+
try {
|
|
208
|
+
child = spawnCli(this.options.cli, args, { env: { ...env, NO_COLOR: "1" }, cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
rejectExec(new Error(`${product} could not start on this server. Install or update the configured ${product} CLI, then try again.`));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
this.command = child;
|
|
215
|
+
child.stdin.end();
|
|
216
|
+
let output = "";
|
|
217
|
+
const receive = (chunk) => {
|
|
218
|
+
if (output.length < MAX_OUTPUT)
|
|
219
|
+
output += chunk.toString("utf8").slice(0, MAX_OUTPUT - output.length);
|
|
220
|
+
};
|
|
221
|
+
child.stdout.on("data", receive);
|
|
222
|
+
child.stderr.on("data", receive);
|
|
223
|
+
// A hung CLI must not hold the credential-home lock forever.
|
|
224
|
+
const timer = setTimeout(() => {
|
|
225
|
+
void this.stopChild(child).catch(() => false).then((stopped) => {
|
|
226
|
+
if (!stopped)
|
|
227
|
+
rejectExec(new Error(`${product} could not be stopped on this server. Ask the server administrator to stop the account command before trying again.`));
|
|
228
|
+
});
|
|
229
|
+
}, this.options.startupTimeoutMs ?? 30_000);
|
|
230
|
+
timer.unref();
|
|
231
|
+
child.once("error", (error) => {
|
|
232
|
+
clearTimeout(timer);
|
|
233
|
+
rejectExec(new Error(this.startFailure(error)));
|
|
234
|
+
});
|
|
235
|
+
child.once("close", (code) => {
|
|
236
|
+
clearTimeout(timer);
|
|
237
|
+
if (this.command === child)
|
|
238
|
+
this.command = null;
|
|
239
|
+
resolveExec({ code, output: stripVTControlCharacters(output) });
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
run(flow, args, env, cwd, done, parsePrompt = false) {
|
|
244
|
+
const { product, provider } = this.spec;
|
|
245
|
+
if (flow.status.phase !== "waiting")
|
|
246
|
+
return;
|
|
247
|
+
let child;
|
|
248
|
+
try {
|
|
249
|
+
child = spawnCli(this.options.cli, args, { env: { ...env, NO_COLOR: "1" }, cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
this.finish(flow, "failed", `${product} could not start on this server. Install or update the configured ${product} CLI, then try again.`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
flow.child = child;
|
|
256
|
+
child.stdin.end();
|
|
257
|
+
let output = "";
|
|
258
|
+
const receive = (chunk) => {
|
|
259
|
+
if (flow.status.phase !== "waiting")
|
|
260
|
+
return;
|
|
261
|
+
if (output.length + chunk.length > MAX_OUTPUT) {
|
|
262
|
+
this.finish(flow, "failed", `${product} returned an unexpected sign-in response. Update the server's ${product} CLI and try again.`);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
output += chunk.toString("utf8");
|
|
266
|
+
const prompt = parsePrompt && !flow.ready ? deviceSignInPrompt(provider, stripVTControlCharacters(output)) : null;
|
|
267
|
+
if (prompt) {
|
|
268
|
+
flow.status = { ...flow.status, ...prompt };
|
|
269
|
+
flow.ready = true;
|
|
270
|
+
clearTimeout(flow.startupTimer);
|
|
271
|
+
flow.resolve({ ...flow.status, phase: "waiting" });
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
child.stdout.on("data", receive);
|
|
275
|
+
child.stderr.on("data", receive);
|
|
276
|
+
child.once("error", (error) => this.finish(flow, "failed", this.startFailure(error)));
|
|
277
|
+
child.once("close", (code) => {
|
|
278
|
+
if (flow.child === child)
|
|
279
|
+
flow.child = null;
|
|
280
|
+
if (flow.status.phase === "waiting")
|
|
281
|
+
done(code, stripVTControlCharacters(output));
|
|
282
|
+
output = "";
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
finish(flow, phase, message) {
|
|
286
|
+
const { product, account } = this.spec;
|
|
287
|
+
if (flow.status.phase !== "waiting")
|
|
288
|
+
return;
|
|
289
|
+
clearTimeout(flow.startupTimer);
|
|
290
|
+
clearTimeout(flow.expiryTimer);
|
|
291
|
+
flow.status = {
|
|
292
|
+
phase, flowId: flow.status.flowId, authorizationUrl: null, expiresAt: null,
|
|
293
|
+
...(phase !== "succeeded" && message ? { message } : {}),
|
|
294
|
+
};
|
|
295
|
+
if (!flow.ready) {
|
|
296
|
+
if (phase === "succeeded")
|
|
297
|
+
flow.resolve({ ...flow.status, phase });
|
|
298
|
+
else
|
|
299
|
+
flow.reject(new Error(message ?? `${account} sign-in did not finish.`));
|
|
300
|
+
}
|
|
301
|
+
flow.stopping = this.stopChild(flow.child).catch(() => false).then((stopped) => {
|
|
302
|
+
const release = () => authenticatingHomes.delete(flow.homeKey);
|
|
303
|
+
if (stopped) {
|
|
304
|
+
release();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
flow.terminationFailed = true;
|
|
308
|
+
flow.status = { ...flow.status, phase: "failed", message: `${product} could not be stopped on this server. Ask the server administrator to stop the login process before trying again.` };
|
|
309
|
+
// Retain the credential-home lock until the OS actually reports exit.
|
|
310
|
+
const child = flow.child;
|
|
311
|
+
if (!child || child.exitCode !== null || child.signalCode !== null)
|
|
312
|
+
release();
|
|
313
|
+
else
|
|
314
|
+
child.once("close", release);
|
|
315
|
+
});
|
|
316
|
+
if (phase === "succeeded")
|
|
317
|
+
void this.options.onAuthenticated?.().catch(() => { });
|
|
318
|
+
}
|
|
319
|
+
async stopChild(child) {
|
|
320
|
+
if (!child || await killCliTree(child, this.options.terminateTimeoutMs ?? 1500))
|
|
321
|
+
return true;
|
|
322
|
+
// A broken CLI may ignore SIGTERM. Do not leave a stale device flow able
|
|
323
|
+
// to write credentials after the user cancelled it.
|
|
324
|
+
if (process.platform !== "win32" && child.pid) {
|
|
325
|
+
try {
|
|
326
|
+
process.kill(-child.pid, "SIGKILL");
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
child.kill("SIGKILL");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else
|
|
333
|
+
child.kill("SIGKILL");
|
|
334
|
+
await new Promise((resolveStop) => {
|
|
335
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
336
|
+
return resolveStop();
|
|
337
|
+
const timer = setTimeout(resolveStop, 1500);
|
|
338
|
+
timer.unref();
|
|
339
|
+
child.once("close", () => { clearTimeout(timer); resolveStop(); });
|
|
340
|
+
});
|
|
341
|
+
return child.exitCode !== null || child.signalCode !== null;
|
|
342
|
+
}
|
|
343
|
+
}
|