@bryanhu/codexly 0.1.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/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/README.zh-CN.md +87 -0
- package/dist/chunk-3OBVX5TN.js +15 -0
- package/dist/chunk-42AR5IS7.js +12543 -0
- package/dist/chunk-K63YBMTG.js +61287 -0
- package/dist/chunk-K6J42667.js +43 -0
- package/dist/chunk-MH54VCZJ.js +5224 -0
- package/dist/chunk-TEPSAXZZ.js +3360 -0
- package/dist/cli.js +889 -0
- package/dist/client/index.js +1010 -0
- package/dist/codex-jsonl-frame-worker.js +120 -0
- package/dist/core/index.js +5 -0
- package/dist/dist-NGSIFQU5.js +252 -0
- package/dist/protocol/index.js +5 -0
- package/dist/providers/codex/index.js +7 -0
- package/dist/server/index.js +9 -0
- package/dist/sqlite-state-worker.js +661 -0
- package/dist/web/.vite/manifest.json +829 -0
- package/dist/web/.vite/manifest.json.br +0 -0
- package/dist/web/.vite/manifest.json.gz +0 -0
- package/dist/web/assets/bash-BiGZg9Om.js +1 -0
- package/dist/web/assets/bash-BiGZg9Om.js.br +0 -0
- package/dist/web/assets/bash-BiGZg9Om.js.gz +0 -0
- package/dist/web/assets/bundle-mjs-rHxsej31.js +1 -0
- package/dist/web/assets/bundle-mjs-rHxsej31.js.br +0 -0
- package/dist/web/assets/bundle-mjs-rHxsej31.js.gz +0 -0
- package/dist/web/assets/button-CG0GNEOD.js +1 -0
- package/dist/web/assets/button-CG0GNEOD.js.br +0 -0
- package/dist/web/assets/button-CG0GNEOD.js.gz +0 -0
- package/dist/web/assets/button-group-D2LfHIjt.js +1 -0
- package/dist/web/assets/button-group-D2LfHIjt.js.br +0 -0
- package/dist/web/assets/button-group-D2LfHIjt.js.gz +0 -0
- package/dist/web/assets/c-DWGmR78Y.js +1 -0
- package/dist/web/assets/c-DWGmR78Y.js.br +1 -0
- package/dist/web/assets/c-DWGmR78Y.js.gz +0 -0
- package/dist/web/assets/c-SSSlmE39.js +1 -0
- package/dist/web/assets/c-SSSlmE39.js.br +0 -0
- package/dist/web/assets/c-SSSlmE39.js.gz +0 -0
- package/dist/web/assets/checkbox-Bvl7MRXT.js +1 -0
- package/dist/web/assets/checkbox-Bvl7MRXT.js.br +0 -0
- package/dist/web/assets/checkbox-Bvl7MRXT.js.gz +0 -0
- package/dist/web/assets/chunk-BO2N2NFS-C72FSBge.js +131 -0
- package/dist/web/assets/chunk-BO2N2NFS-C72FSBge.js.br +0 -0
- package/dist/web/assets/chunk-BO2N2NFS-C72FSBge.js.gz +0 -0
- package/dist/web/assets/code-highlighter-Cm0xdvAd.js +1 -0
- package/dist/web/assets/code-highlighter-Cm0xdvAd.js.br +0 -0
- package/dist/web/assets/code-highlighter-Cm0xdvAd.js.gz +0 -0
- package/dist/web/assets/code-languages-CfwYbccP.js +2 -0
- package/dist/web/assets/code-languages-CfwYbccP.js.br +0 -0
- package/dist/web/assets/code-languages-CfwYbccP.js.gz +0 -0
- package/dist/web/assets/cpp-BcHBJY00.js +1 -0
- package/dist/web/assets/cpp-BcHBJY00.js.br +0 -0
- package/dist/web/assets/cpp-BcHBJY00.js.gz +0 -0
- package/dist/web/assets/cpp-CIkEvbIe.js +1 -0
- package/dist/web/assets/cpp-CIkEvbIe.js.br +0 -0
- package/dist/web/assets/cpp-CIkEvbIe.js.gz +0 -0
- package/dist/web/assets/csharp-oqKa8noW.js +1 -0
- package/dist/web/assets/csharp-oqKa8noW.js.br +0 -0
- package/dist/web/assets/csharp-oqKa8noW.js.gz +0 -0
- package/dist/web/assets/css-CdtkT07m.js +1 -0
- package/dist/web/assets/css-CdtkT07m.js.br +1 -0
- package/dist/web/assets/css-CdtkT07m.js.gz +0 -0
- package/dist/web/assets/css-LbU1hoFO.js +1 -0
- package/dist/web/assets/css-LbU1hoFO.js.br +0 -0
- package/dist/web/assets/css-LbU1hoFO.js.gz +0 -0
- package/dist/web/assets/diff-woXpYk--.js +1 -0
- package/dist/web/assets/diff-woXpYk--.js.br +0 -0
- package/dist/web/assets/diff-woXpYk--.js.gz +0 -0
- package/dist/web/assets/dockerfile-IyjqRm3v.js +1 -0
- package/dist/web/assets/dockerfile-IyjqRm3v.js.br +0 -0
- package/dist/web/assets/dockerfile-IyjqRm3v.js.gz +0 -0
- package/dist/web/assets/dotenv-_5a1GRtc.js +1 -0
- package/dist/web/assets/dotenv-_5a1GRtc.js.br +0 -0
- package/dist/web/assets/dotenv-_5a1GRtc.js.gz +0 -0
- package/dist/web/assets/engine-compile-DQ0HPfe0.js +152 -0
- package/dist/web/assets/engine-compile-DQ0HPfe0.js.br +0 -0
- package/dist/web/assets/engine-compile-DQ0HPfe0.js.gz +0 -0
- package/dist/web/assets/es2015-CIXyxC_2.js +41 -0
- package/dist/web/assets/es2015-CIXyxC_2.js.br +0 -0
- package/dist/web/assets/es2015-CIXyxC_2.js.gz +0 -0
- package/dist/web/assets/file-CEs2ZXvf.js +1 -0
- package/dist/web/assets/file-CEs2ZXvf.js.br +0 -0
- package/dist/web/assets/file-CEs2ZXvf.js.gz +0 -0
- package/dist/web/assets/file-change-D7aZLgtG.js +4 -0
- package/dist/web/assets/file-change-D7aZLgtG.js.br +0 -0
- package/dist/web/assets/file-change-D7aZLgtG.js.gz +0 -0
- package/dist/web/assets/file-review-dialog-CTL5FpHU.js +2 -0
- package/dist/web/assets/file-review-dialog-CTL5FpHU.js.br +0 -0
- package/dist/web/assets/file-review-dialog-CTL5FpHU.js.gz +0 -0
- package/dist/web/assets/file-tree-DRpR7Mu2.js +1 -0
- package/dist/web/assets/file-tree-DRpR7Mu2.js.br +0 -0
- package/dist/web/assets/file-tree-DRpR7Mu2.js.gz +0 -0
- package/dist/web/assets/git-commit-horizontal-CQWH7rsr.js +1 -0
- package/dist/web/assets/git-commit-horizontal-CQWH7rsr.js.br +0 -0
- package/dist/web/assets/git-commit-horizontal-CQWH7rsr.js.gz +0 -0
- package/dist/web/assets/git-history-panel-BsIopLeA.js +2 -0
- package/dist/web/assets/git-history-panel-BsIopLeA.js.br +0 -0
- package/dist/web/assets/git-history-panel-BsIopLeA.js.gz +0 -0
- package/dist/web/assets/github-dark-C-LZuMrd.js +1 -0
- package/dist/web/assets/github-dark-C-LZuMrd.js.br +0 -0
- package/dist/web/assets/github-dark-C-LZuMrd.js.gz +0 -0
- package/dist/web/assets/github-light-EUqPIrTm.js +1 -0
- package/dist/web/assets/github-light-EUqPIrTm.js.br +0 -0
- package/dist/web/assets/github-light-EUqPIrTm.js.gz +0 -0
- package/dist/web/assets/global-settings-dialog-CJA_j2dA.js +1 -0
- package/dist/web/assets/global-settings-dialog-CJA_j2dA.js.br +0 -0
- package/dist/web/assets/global-settings-dialog-CJA_j2dA.js.gz +0 -0
- package/dist/web/assets/go-rLFTqkRN.js +1 -0
- package/dist/web/assets/go-rLFTqkRN.js.br +0 -0
- package/dist/web/assets/go-rLFTqkRN.js.gz +0 -0
- package/dist/web/assets/grammar-cpp-support-CV8oNpIY.js +1 -0
- package/dist/web/assets/grammar-cpp-support-CV8oNpIY.js.br +0 -0
- package/dist/web/assets/grammar-cpp-support-CV8oNpIY.js.gz +0 -0
- package/dist/web/assets/graphql-D5qRqMLb.js +1 -0
- package/dist/web/assets/graphql-D5qRqMLb.js.br +0 -0
- package/dist/web/assets/graphql-D5qRqMLb.js.gz +0 -0
- package/dist/web/assets/graphql-f69H1Mm0.js +1 -0
- package/dist/web/assets/graphql-f69H1Mm0.js.br +0 -0
- package/dist/web/assets/graphql-f69H1Mm0.js.gz +0 -0
- package/dist/web/assets/highlighted-body-OFNGDK62-NQRGdW--.js +1 -0
- package/dist/web/assets/highlighted-body-OFNGDK62-NQRGdW--.js.br +0 -0
- package/dist/web/assets/highlighted-body-OFNGDK62-NQRGdW--.js.gz +0 -0
- package/dist/web/assets/html-BcACZWSP.js +1 -0
- package/dist/web/assets/html-BcACZWSP.js.br +0 -0
- package/dist/web/assets/html-BcACZWSP.js.gz +0 -0
- package/dist/web/assets/html-DDNsd9lV.js +1 -0
- package/dist/web/assets/html-DDNsd9lV.js.br +0 -0
- package/dist/web/assets/html-DDNsd9lV.js.gz +0 -0
- package/dist/web/assets/index-B3NtDmQp.css +2 -0
- package/dist/web/assets/index-B3NtDmQp.css.br +0 -0
- package/dist/web/assets/index-B3NtDmQp.css.gz +0 -0
- package/dist/web/assets/index-C_O4z_mI.js +4 -0
- package/dist/web/assets/index-C_O4z_mI.js.br +0 -0
- package/dist/web/assets/index-C_O4z_mI.js.gz +0 -0
- package/dist/web/assets/ini-B5eOa1yu.js +1 -0
- package/dist/web/assets/ini-B5eOa1yu.js.br +5 -0
- package/dist/web/assets/ini-B5eOa1yu.js.gz +0 -0
- package/dist/web/assets/java-BtIQNnN0.js +1 -0
- package/dist/web/assets/java-BtIQNnN0.js.br +0 -0
- package/dist/web/assets/java-BtIQNnN0.js.gz +0 -0
- package/dist/web/assets/java-DxlWrXwe.js +1 -0
- package/dist/web/assets/java-DxlWrXwe.js.br +1 -0
- package/dist/web/assets/java-DxlWrXwe.js.gz +0 -0
- package/dist/web/assets/javascript-BzbQS41l.js +1 -0
- package/dist/web/assets/javascript-BzbQS41l.js.br +0 -0
- package/dist/web/assets/javascript-BzbQS41l.js.gz +0 -0
- package/dist/web/assets/javascript-Yelw-5ZN.js +1 -0
- package/dist/web/assets/javascript-Yelw-5ZN.js.br +0 -0
- package/dist/web/assets/javascript-Yelw-5ZN.js.gz +0 -0
- package/dist/web/assets/json-B88Oqtu5.js +1 -0
- package/dist/web/assets/json-B88Oqtu5.js.br +0 -0
- package/dist/web/assets/json-B88Oqtu5.js.gz +0 -0
- package/dist/web/assets/json-CaljABEy.js +1 -0
- package/dist/web/assets/json-CaljABEy.js.br +1 -0
- package/dist/web/assets/json-CaljABEy.js.gz +0 -0
- package/dist/web/assets/json5-BR5RXkoi.js +1 -0
- package/dist/web/assets/json5-BR5RXkoi.js.br +0 -0
- package/dist/web/assets/json5-BR5RXkoi.js.gz +0 -0
- package/dist/web/assets/jsonc-CYpm1nAK.js +1 -0
- package/dist/web/assets/jsonc-CYpm1nAK.js.br +0 -0
- package/dist/web/assets/jsonc-CYpm1nAK.js.gz +0 -0
- package/dist/web/assets/jsx-D3KKoC5L.js +1 -0
- package/dist/web/assets/jsx-D3KKoC5L.js.br +0 -0
- package/dist/web/assets/jsx-D3KKoC5L.js.gz +0 -0
- package/dist/web/assets/jsx-hEbJ82HF.js +1 -0
- package/dist/web/assets/jsx-hEbJ82HF.js.br +1 -0
- package/dist/web/assets/jsx-hEbJ82HF.js.gz +0 -0
- package/dist/web/assets/kotlin-DhhofPvG.js +1 -0
- package/dist/web/assets/kotlin-DhhofPvG.js.br +0 -0
- package/dist/web/assets/kotlin-DhhofPvG.js.gz +0 -0
- package/dist/web/assets/lazy-message-response-Cy_8wxLM.js +2 -0
- package/dist/web/assets/lazy-message-response-Cy_8wxLM.js.br +0 -0
- package/dist/web/assets/lazy-message-response-Cy_8wxLM.js.gz +0 -0
- package/dist/web/assets/lib-DrPFkMXk.js +1 -0
- package/dist/web/assets/lib-DrPFkMXk.js.br +0 -0
- package/dist/web/assets/lib-DrPFkMXk.js.gz +0 -0
- package/dist/web/assets/lua-BJObVtAx.js +1 -0
- package/dist/web/assets/lua-BJObVtAx.js.br +0 -0
- package/dist/web/assets/lua-BJObVtAx.js.gz +0 -0
- package/dist/web/assets/lua-DjuecEsk.js +1 -0
- package/dist/web/assets/lua-DjuecEsk.js.br +0 -0
- package/dist/web/assets/lua-DjuecEsk.js.gz +0 -0
- package/dist/web/assets/makefile-Dixweg8N.js +1 -0
- package/dist/web/assets/makefile-Dixweg8N.js.br +0 -0
- package/dist/web/assets/makefile-Dixweg8N.js.gz +0 -0
- package/dist/web/assets/markdown-BYOwaDjH.js +1 -0
- package/dist/web/assets/markdown-BYOwaDjH.js.br +0 -0
- package/dist/web/assets/markdown-BYOwaDjH.js.gz +0 -0
- package/dist/web/assets/mdx-DQZ5AkYe.js +1 -0
- package/dist/web/assets/mdx-DQZ5AkYe.js.br +0 -0
- package/dist/web/assets/mdx-DQZ5AkYe.js.gz +0 -0
- package/dist/web/assets/mermaid-GHXKKRXX-D0CV54MY.js +1 -0
- package/dist/web/assets/mermaid-GHXKKRXX-D0CV54MY.js.br +0 -0
- package/dist/web/assets/mermaid-GHXKKRXX-D0CV54MY.js.gz +0 -0
- package/dist/web/assets/message-response-CBOOkYPm.js +7 -0
- package/dist/web/assets/message-response-CBOOkYPm.js.br +0 -0
- package/dist/web/assets/message-response-CBOOkYPm.js.gz +0 -0
- package/dist/web/assets/patch-diff-viewer-BHcdOhhw.js +1409 -0
- package/dist/web/assets/patch-diff-viewer-BHcdOhhw.js.br +0 -0
- package/dist/web/assets/patch-diff-viewer-BHcdOhhw.js.gz +0 -0
- package/dist/web/assets/perl-Br95gH8g.js +1 -0
- package/dist/web/assets/perl-Br95gH8g.js.br +0 -0
- package/dist/web/assets/perl-Br95gH8g.js.gz +0 -0
- package/dist/web/assets/php-CYrBA5iX.js +1 -0
- package/dist/web/assets/php-CYrBA5iX.js.br +0 -0
- package/dist/web/assets/php-CYrBA5iX.js.gz +0 -0
- package/dist/web/assets/prompt-input-controls-CrypM5HZ.js +1 -0
- package/dist/web/assets/prompt-input-controls-CrypM5HZ.js.br +0 -0
- package/dist/web/assets/prompt-input-controls-CrypM5HZ.js.gz +0 -0
- package/dist/web/assets/prompt-reference-token-Cxx6C-IR.js +1 -0
- package/dist/web/assets/prompt-reference-token-Cxx6C-IR.js.br +0 -0
- package/dist/web/assets/prompt-reference-token-Cxx6C-IR.js.gz +0 -0
- package/dist/web/assets/provider-connection-queries-C40YvSEy.js +1 -0
- package/dist/web/assets/provider-connection-queries-C40YvSEy.js.br +0 -0
- package/dist/web/assets/provider-connection-queries-C40YvSEy.js.gz +0 -0
- package/dist/web/assets/python-gzcpVVnB.js +1 -0
- package/dist/web/assets/python-gzcpVVnB.js.br +0 -0
- package/dist/web/assets/python-gzcpVVnB.js.gz +0 -0
- package/dist/web/assets/react-runtime-CVaUQXZF.js +9 -0
- package/dist/web/assets/react-runtime-CVaUQXZF.js.br +0 -0
- package/dist/web/assets/react-runtime-CVaUQXZF.js.gz +0 -0
- package/dist/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/dist/web/assets/rolldown-runtime-QTnfLwEv.js.br +0 -0
- package/dist/web/assets/rolldown-runtime-QTnfLwEv.js.gz +0 -0
- package/dist/web/assets/ruby-CbXu8Ywv.js +1 -0
- package/dist/web/assets/ruby-CbXu8Ywv.js.br +0 -0
- package/dist/web/assets/ruby-CbXu8Ywv.js.gz +0 -0
- package/dist/web/assets/rust-Cfkwpbl8.js +1 -0
- package/dist/web/assets/rust-Cfkwpbl8.js.br +0 -0
- package/dist/web/assets/rust-Cfkwpbl8.js.gz +0 -0
- package/dist/web/assets/scss-DHtrkMkT.js +1 -0
- package/dist/web/assets/scss-DHtrkMkT.js.br +0 -0
- package/dist/web/assets/scss-DHtrkMkT.js.gz +0 -0
- package/dist/web/assets/shellscript-BiGZg9Om.js +1 -0
- package/dist/web/assets/shellscript-BiGZg9Om.js.br +0 -0
- package/dist/web/assets/shellscript-BiGZg9Om.js.gz +0 -0
- package/dist/web/assets/shellscript-CqHdAlCp.js +1 -0
- package/dist/web/assets/shellscript-CqHdAlCp.js.br +0 -0
- package/dist/web/assets/shellscript-CqHdAlCp.js.gz +0 -0
- package/dist/web/assets/shiki-bundle-DzEBOJSk.js +1 -0
- package/dist/web/assets/shiki-bundle-DzEBOJSk.js.br +0 -0
- package/dist/web/assets/shiki-bundle-DzEBOJSk.js.gz +0 -0
- package/dist/web/assets/sql-0Qcw9ht3.js +1 -0
- package/dist/web/assets/sql-0Qcw9ht3.js.br +0 -0
- package/dist/web/assets/sql-0Qcw9ht3.js.gz +0 -0
- package/dist/web/assets/sql-CP0rg-5b.js +1 -0
- package/dist/web/assets/sql-CP0rg-5b.js.br +0 -0
- package/dist/web/assets/sql-CP0rg-5b.js.gz +0 -0
- package/dist/web/assets/svelte-BUVJxsYv.js +1 -0
- package/dist/web/assets/svelte-BUVJxsYv.js.br +0 -0
- package/dist/web/assets/svelte-BUVJxsYv.js.gz +0 -0
- package/dist/web/assets/swift-DonLKvLd.js +1 -0
- package/dist/web/assets/swift-DonLKvLd.js.br +0 -0
- package/dist/web/assets/swift-DonLKvLd.js.gz +0 -0
- package/dist/web/assets/toml-CcmNWLt0.js +1 -0
- package/dist/web/assets/toml-CcmNWLt0.js.br +0 -0
- package/dist/web/assets/toml-CcmNWLt0.js.gz +0 -0
- package/dist/web/assets/tsx-5f3ulCja.js +1 -0
- package/dist/web/assets/tsx-5f3ulCja.js.br +0 -0
- package/dist/web/assets/tsx-5f3ulCja.js.gz +0 -0
- package/dist/web/assets/tsx-BOvsFOI6.js +1 -0
- package/dist/web/assets/tsx-BOvsFOI6.js.br +0 -0
- package/dist/web/assets/tsx-BOvsFOI6.js.gz +0 -0
- package/dist/web/assets/typescript-Utq2Cl8c.js +1 -0
- package/dist/web/assets/typescript-Utq2Cl8c.js.br +0 -0
- package/dist/web/assets/typescript-Utq2Cl8c.js.gz +0 -0
- package/dist/web/assets/typescript-j_1H8WHN.js +1 -0
- package/dist/web/assets/typescript-j_1H8WHN.js.br +0 -0
- package/dist/web/assets/typescript-j_1H8WHN.js.gz +0 -0
- package/dist/web/assets/vue-BpAUjojh.js +1 -0
- package/dist/web/assets/vue-BpAUjojh.js.br +0 -0
- package/dist/web/assets/vue-BpAUjojh.js.gz +0 -0
- package/dist/web/assets/workbench-inspector-changes-RHaBVG45.js +1 -0
- package/dist/web/assets/workbench-inspector-changes-RHaBVG45.js.br +0 -0
- package/dist/web/assets/workbench-inspector-changes-RHaBVG45.js.gz +0 -0
- package/dist/web/assets/workbench-shell--6Y1cx2L.js +12 -0
- package/dist/web/assets/workbench-shell--6Y1cx2L.js.br +0 -0
- package/dist/web/assets/workbench-shell--6Y1cx2L.js.gz +0 -0
- package/dist/web/assets/xml-CoDIzWF0.js +1 -0
- package/dist/web/assets/xml-CoDIzWF0.js.br +0 -0
- package/dist/web/assets/xml-CoDIzWF0.js.gz +0 -0
- package/dist/web/assets/xml-WY0zc4PG.js +1 -0
- package/dist/web/assets/xml-WY0zc4PG.js.br +0 -0
- package/dist/web/assets/xml-WY0zc4PG.js.gz +0 -0
- package/dist/web/assets/yaml-CxbubiML.js +1 -0
- package/dist/web/assets/yaml-CxbubiML.js.br +0 -0
- package/dist/web/assets/yaml-CxbubiML.js.gz +0 -0
- package/dist/web/assets/yaml-DijMHRDA.js +1 -0
- package/dist/web/assets/yaml-DijMHRDA.js.br +0 -0
- package/dist/web/assets/yaml-DijMHRDA.js.gz +0 -0
- package/dist/web/brand/codexly-logo.svg +34 -0
- package/dist/web/brand/codexly-logo.svg.br +0 -0
- package/dist/web/brand/codexly-logo.svg.gz +0 -0
- package/dist/web/brand/codexly-mark.svg +21 -0
- package/dist/web/brand/codexly-mark.svg.br +0 -0
- package/dist/web/brand/codexly-mark.svg.gz +0 -0
- package/dist/web/favicon.svg +20 -0
- package/dist/web/favicon.svg.br +0 -0
- package/dist/web/favicon.svg.gz +0 -0
- package/dist/web/index.html +25 -0
- package/dist/web/index.html.br +0 -0
- package/dist/web/index.html.gz +0 -0
- package/package.json +85 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,889 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { createCodexlyServer, SqliteStateRepository, normalizeAllowedHost } from './chunk-K63YBMTG.js';
|
|
4
|
+
import './chunk-TEPSAXZZ.js';
|
|
5
|
+
import { startCodexAppServer, locateCodexBinary, createCodexRuntimeProvider, CodexProjectRepository, checkCodexVersion } from './chunk-42AR5IS7.js';
|
|
6
|
+
import './chunk-3OBVX5TN.js';
|
|
7
|
+
import './chunk-MH54VCZJ.js';
|
|
8
|
+
import './chunk-K6J42667.js';
|
|
9
|
+
import { mkdir, lstat, chmod, realpath } from 'fs/promises';
|
|
10
|
+
import { networkInterfaces, homedir } from 'os';
|
|
11
|
+
import { join, win32 } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { spawn, execFile } from 'child_process';
|
|
14
|
+
import { createInterface } from 'readline/promises';
|
|
15
|
+
import { randomBytes } from 'crypto';
|
|
16
|
+
import { isIP } from 'net';
|
|
17
|
+
|
|
18
|
+
createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// package.json
|
|
21
|
+
var package_default = {
|
|
22
|
+
version: "0.1.0"};
|
|
23
|
+
var PACKAGE_NAME = "@bryanhu/codexly";
|
|
24
|
+
var INITIAL_APP_VERSION = "0.1.0";
|
|
25
|
+
var CHANGELOG_URL_PREFIX = "https://raw.githubusercontent.com/BryanHoo/Codexly/v";
|
|
26
|
+
var REGISTRY_TIMEOUT_MS = 1e4;
|
|
27
|
+
var MAX_RELEASE_NOTES_BYTES = 32 * 1024;
|
|
28
|
+
var INSTALL_TIMEOUT_MS = 2 * 6e4;
|
|
29
|
+
var SEMANTIC_VERSION_PATTERN = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-((?:(?:0|[1-9][0-9]*)|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:(?:0|[1-9][0-9]*)|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
|
|
30
|
+
var AppUpdateError = class extends Error {
|
|
31
|
+
constructor(code, message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.code = code;
|
|
34
|
+
this.name = "AppUpdateError";
|
|
35
|
+
}
|
|
36
|
+
code;
|
|
37
|
+
};
|
|
38
|
+
var UnpublishedPackageError = class extends Error {
|
|
39
|
+
};
|
|
40
|
+
function parseSemanticVersion(version) {
|
|
41
|
+
const match = SEMANTIC_VERSION_PATTERN.exec(version);
|
|
42
|
+
if (match === null) return void 0;
|
|
43
|
+
return {
|
|
44
|
+
core: [match[1] ?? "0", match[2] ?? "0", match[3] ?? "0"],
|
|
45
|
+
prerelease: match[4]?.split(".") ?? []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function compareNumericIdentifiers(left, right) {
|
|
49
|
+
if (left.length !== right.length) return left.length - right.length;
|
|
50
|
+
return left === right ? 0 : left < right ? -1 : 1;
|
|
51
|
+
}
|
|
52
|
+
function comparePrerelease(left, right) {
|
|
53
|
+
if (left.length === 0 || right.length === 0) {
|
|
54
|
+
return left.length === right.length ? 0 : left.length === 0 ? 1 : -1;
|
|
55
|
+
}
|
|
56
|
+
for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
|
|
57
|
+
const leftPart = left[index];
|
|
58
|
+
const rightPart = right[index];
|
|
59
|
+
if (leftPart === void 0 || rightPart === void 0) {
|
|
60
|
+
return leftPart === rightPart ? 0 : leftPart === void 0 ? -1 : 1;
|
|
61
|
+
}
|
|
62
|
+
if (leftPart === rightPart) continue;
|
|
63
|
+
const leftIsNumeric = /^\d+$/u.test(leftPart);
|
|
64
|
+
const rightIsNumeric = /^\d+$/u.test(rightPart);
|
|
65
|
+
if (leftIsNumeric && rightIsNumeric) {
|
|
66
|
+
return compareNumericIdentifiers(leftPart, rightPart);
|
|
67
|
+
}
|
|
68
|
+
if (leftIsNumeric) return -1;
|
|
69
|
+
if (rightIsNumeric) return 1;
|
|
70
|
+
return leftPart < rightPart ? -1 : 1;
|
|
71
|
+
}
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
function truncateUtf8(value, maxBytes) {
|
|
75
|
+
const bytes = Buffer.from(value, "utf8");
|
|
76
|
+
if (bytes.byteLength <= maxBytes) return value;
|
|
77
|
+
return new TextDecoder("utf-8", { fatal: false }).decode(bytes.subarray(0, maxBytes)).trimEnd();
|
|
78
|
+
}
|
|
79
|
+
function extractVersionReleaseNotes(changelog, version) {
|
|
80
|
+
const lines = changelog.split(/\r?\n/u);
|
|
81
|
+
const start = lines.findIndex((line) => line.startsWith(`## [${version}]`));
|
|
82
|
+
if (start < 0) return void 0;
|
|
83
|
+
const nextVersionOffset = lines.slice(start + 1).findIndex((line) => /^## \[[^\]]+\]/u.test(line));
|
|
84
|
+
const end = nextVersionOffset < 0 ? lines.length : start + 1 + nextVersionOffset;
|
|
85
|
+
const releaseNotes = lines.slice(start + 1, end).join("\n").trim();
|
|
86
|
+
return releaseNotes === "" ? void 0 : truncateUtf8(releaseNotes, MAX_RELEASE_NOTES_BYTES);
|
|
87
|
+
}
|
|
88
|
+
function resolveNpmInstallInvocation(version, platform = process.platform, execPath = process.execPath) {
|
|
89
|
+
const packageSpec = `${PACKAGE_NAME}@${version}`;
|
|
90
|
+
if (platform !== "win32") {
|
|
91
|
+
return { args: ["install", "--global", packageSpec], command: "npm" };
|
|
92
|
+
}
|
|
93
|
+
const npmCliPath = win32.join(
|
|
94
|
+
win32.dirname(execPath),
|
|
95
|
+
"node_modules",
|
|
96
|
+
"npm",
|
|
97
|
+
"bin",
|
|
98
|
+
"npm-cli.js"
|
|
99
|
+
);
|
|
100
|
+
return {
|
|
101
|
+
args: [npmCliPath, "install", "--global", packageSpec],
|
|
102
|
+
command: execPath
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function isNewerVersion(candidate, current) {
|
|
106
|
+
const candidateVersion = parseSemanticVersion(candidate);
|
|
107
|
+
const currentVersion = parseSemanticVersion(current);
|
|
108
|
+
if (candidateVersion === void 0 || currentVersion === void 0) return false;
|
|
109
|
+
for (let index = 0; index < candidateVersion.core.length; index += 1) {
|
|
110
|
+
const candidatePart = candidateVersion.core[index];
|
|
111
|
+
const currentPart = currentVersion.core[index];
|
|
112
|
+
if (candidatePart === void 0 || currentPart === void 0) return false;
|
|
113
|
+
const difference = compareNumericIdentifiers(candidatePart, currentPart);
|
|
114
|
+
if (difference !== 0) return difference > 0;
|
|
115
|
+
}
|
|
116
|
+
return comparePrerelease(candidateVersion.prerelease, currentVersion.prerelease) > 0;
|
|
117
|
+
}
|
|
118
|
+
async function fetchLatestPackageVersion() {
|
|
119
|
+
const response = await fetch(
|
|
120
|
+
`https://registry.npmjs.org/-/package/${encodeURIComponent(PACKAGE_NAME)}/dist-tags`,
|
|
121
|
+
{
|
|
122
|
+
headers: { accept: "application/json" },
|
|
123
|
+
signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS)
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
if (response.status === 401 || response.status === 404) {
|
|
127
|
+
throw new UnpublishedPackageError("Package has not been published");
|
|
128
|
+
}
|
|
129
|
+
if (!response.ok) throw new Error(`Registry returned ${String(response.status)}`);
|
|
130
|
+
const payload = await response.json();
|
|
131
|
+
if (typeof payload !== "object" || payload === null || !("latest" in payload) || typeof payload.latest !== "string" || parseSemanticVersion(payload.latest) === void 0) {
|
|
132
|
+
throw new Error("Registry returned an invalid latest version");
|
|
133
|
+
}
|
|
134
|
+
return payload.latest;
|
|
135
|
+
}
|
|
136
|
+
async function fetchTaggedChangelog(version) {
|
|
137
|
+
const response = await fetch(`${CHANGELOG_URL_PREFIX}${version}/CHANGELOG.md`, {
|
|
138
|
+
headers: { accept: "text/markdown" },
|
|
139
|
+
signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS)
|
|
140
|
+
});
|
|
141
|
+
if (!response.ok) throw new Error(`GitHub returned ${String(response.status)}`);
|
|
142
|
+
return response.text();
|
|
143
|
+
}
|
|
144
|
+
async function installGlobalPackage(version) {
|
|
145
|
+
const invocation = resolveNpmInstallInvocation(version);
|
|
146
|
+
await new Promise((resolve, reject) => {
|
|
147
|
+
execFile(
|
|
148
|
+
invocation.command,
|
|
149
|
+
invocation.args,
|
|
150
|
+
{ shell: false, timeout: INSTALL_TIMEOUT_MS, windowsHide: true },
|
|
151
|
+
(error) => {
|
|
152
|
+
if (error === null) resolve();
|
|
153
|
+
else reject(new Error("npm install failed", { cause: error }));
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function createAppUpdateService(options) {
|
|
159
|
+
const fetchChangelog = options.fetchChangelog ?? fetchTaggedChangelog;
|
|
160
|
+
const fetchLatestVersion = options.fetchLatestVersion ?? fetchLatestPackageVersion;
|
|
161
|
+
const runNpmInstall = options.runNpmInstall ?? installGlobalPackage;
|
|
162
|
+
let installedVersion;
|
|
163
|
+
const readLatest = async () => {
|
|
164
|
+
try {
|
|
165
|
+
const latestVersion = await fetchLatestVersion();
|
|
166
|
+
if (parseSemanticVersion(latestVersion) === void 0) throw new Error("Invalid version");
|
|
167
|
+
return latestVersion;
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (error instanceof UnpublishedPackageError && options.appVersion === INITIAL_APP_VERSION) {
|
|
170
|
+
return options.appVersion;
|
|
171
|
+
}
|
|
172
|
+
throw new AppUpdateError("UPDATE_CHECK_FAILED", "Failed to check for Codexly updates");
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
async install(version) {
|
|
177
|
+
const latestVersion = await readLatest();
|
|
178
|
+
if (version !== latestVersion || !isNewerVersion(latestVersion, options.appVersion)) {
|
|
179
|
+
throw new AppUpdateError("UPDATE_NOT_AVAILABLE", "The requested update is not available");
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
await runNpmInstall(latestVersion);
|
|
183
|
+
} catch {
|
|
184
|
+
throw new AppUpdateError("UPDATE_INSTALL_FAILED", "Failed to install the Codexly update");
|
|
185
|
+
}
|
|
186
|
+
installedVersion = latestVersion;
|
|
187
|
+
return {
|
|
188
|
+
appVersion: options.appVersion,
|
|
189
|
+
codexVersion: options.codexVersion,
|
|
190
|
+
latestVersion,
|
|
191
|
+
releaseNotes: null,
|
|
192
|
+
status: "restart-required",
|
|
193
|
+
updateAvailable: false
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
async read() {
|
|
197
|
+
let latestVersion;
|
|
198
|
+
try {
|
|
199
|
+
latestVersion = await readLatest();
|
|
200
|
+
} catch {
|
|
201
|
+
return {
|
|
202
|
+
appVersion: options.appVersion,
|
|
203
|
+
codexVersion: options.codexVersion,
|
|
204
|
+
latestVersion: null,
|
|
205
|
+
releaseNotes: null,
|
|
206
|
+
status: "check-failed",
|
|
207
|
+
updateAvailable: false
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (installedVersion === latestVersion) {
|
|
211
|
+
return {
|
|
212
|
+
appVersion: options.appVersion,
|
|
213
|
+
codexVersion: options.codexVersion,
|
|
214
|
+
latestVersion,
|
|
215
|
+
releaseNotes: null,
|
|
216
|
+
status: "restart-required",
|
|
217
|
+
updateAvailable: false
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const updateAvailable = isNewerVersion(latestVersion, options.appVersion);
|
|
221
|
+
let releaseNotes = null;
|
|
222
|
+
if (updateAvailable) {
|
|
223
|
+
try {
|
|
224
|
+
releaseNotes = extractVersionReleaseNotes(await fetchChangelog(latestVersion), latestVersion) ?? null;
|
|
225
|
+
} catch {
|
|
226
|
+
releaseNotes = null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
appVersion: options.appVersion,
|
|
231
|
+
codexVersion: options.codexVersion,
|
|
232
|
+
latestVersion,
|
|
233
|
+
releaseNotes,
|
|
234
|
+
status: updateAvailable ? "available" : "current",
|
|
235
|
+
updateAvailable
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/cli-command-options.ts
|
|
242
|
+
var CLI_HELP = `Usage: codexly [command] [options]
|
|
243
|
+
|
|
244
|
+
Commands:
|
|
245
|
+
start Start the Codexly server and open the Web interface.
|
|
246
|
+
doctor Check whether the local Codexly runtime is ready.
|
|
247
|
+
version Print the installed Codexly version.
|
|
248
|
+
|
|
249
|
+
Start options:
|
|
250
|
+
--port <port> Start from the specified TCP port. Defaults to 3210.
|
|
251
|
+
Automatically increases the port when it is occupied.
|
|
252
|
+
--lan Listen on all network interfaces for trusted LAN access.
|
|
253
|
+
This disables automatic browser opening.
|
|
254
|
+
--lan-password <password> Use a custom strong LAN access password instead of a random one.
|
|
255
|
+
Requires 16-128 characters and all character types. Requires --lan.
|
|
256
|
+
--allowed-host <domain> Allow an exact reverse proxy domain. May be repeated.
|
|
257
|
+
--session-ttl <duration> Set the fixed LAN session lifetime using ms, s, m, h, or d.
|
|
258
|
+
Sessions do not expire when omitted. Requires --lan.
|
|
259
|
+
--codex-bin <path> Use the Codex executable at the specified path.
|
|
260
|
+
--codex-home <path> Use a custom Codex home directory instead of CODEX_HOME
|
|
261
|
+
or the default ~/.codex directory.
|
|
262
|
+
|
|
263
|
+
Doctor options:
|
|
264
|
+
--codex-bin <path> Check the Codex executable at the specified path.
|
|
265
|
+
--codex-home <path> Check the state database in the specified Codex home.
|
|
266
|
+
|
|
267
|
+
Global options:
|
|
268
|
+
-h, --help Display all commands, options, and usage details.
|
|
269
|
+
|
|
270
|
+
Examples:
|
|
271
|
+
codexly
|
|
272
|
+
codexly start --port 4567
|
|
273
|
+
codexly start --lan --lan-password 'Strong-Lan_Pass9!'
|
|
274
|
+
codexly start --allowed-host code.example.com
|
|
275
|
+
codexly start --lan --session-ttl 12h
|
|
276
|
+
codexly doctor --codex-bin /path/to/codex
|
|
277
|
+
codexly version
|
|
278
|
+
|
|
279
|
+
Running codexly without a command is equivalent to codexly start.
|
|
280
|
+
`;
|
|
281
|
+
function parseCommandOptions(args, valueOptions, flagOptions = /* @__PURE__ */ new Set()) {
|
|
282
|
+
const parsed = {};
|
|
283
|
+
const seen = /* @__PURE__ */ new Set();
|
|
284
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
285
|
+
const option = args[index];
|
|
286
|
+
if (!option || !valueOptions.has(option) && !flagOptions.has(option)) {
|
|
287
|
+
throw new Error(`\u672A\u77E5\u9009\u9879: ${option ?? "<empty>"}`);
|
|
288
|
+
}
|
|
289
|
+
const repeatable = option === "--allowed-host";
|
|
290
|
+
if (seen.has(option) && !repeatable) {
|
|
291
|
+
throw new Error(`\u9009\u9879\u91CD\u590D: ${option}`);
|
|
292
|
+
}
|
|
293
|
+
seen.add(option);
|
|
294
|
+
if (flagOptions.has(option)) {
|
|
295
|
+
if (option === "--lan") {
|
|
296
|
+
parsed.lan = true;
|
|
297
|
+
}
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const value = args[index + 1];
|
|
301
|
+
if (!value || value.startsWith("--")) {
|
|
302
|
+
throw new Error(`\u9009\u9879\u7F3A\u5C11\u503C: ${option}`);
|
|
303
|
+
}
|
|
304
|
+
if (option === "--codex-bin") {
|
|
305
|
+
parsed.codexBin = value;
|
|
306
|
+
} else if (option === "--codex-home") {
|
|
307
|
+
parsed.codexHome = value;
|
|
308
|
+
} else if (option === "--lan-password") {
|
|
309
|
+
parsed.lanPassword = value;
|
|
310
|
+
} else if (option === "--allowed-host") {
|
|
311
|
+
parsed.allowedHosts = [...parsed.allowedHosts ?? [], value];
|
|
312
|
+
} else if (option === "--port") {
|
|
313
|
+
if (!/^\d+$/u.test(value)) {
|
|
314
|
+
throw new Error("--port \u5FC5\u987B\u662F 1 \u5230 65535 \u4E4B\u95F4\u7684\u6574\u6570");
|
|
315
|
+
}
|
|
316
|
+
const port = Number(value);
|
|
317
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
318
|
+
throw new Error("--port \u5FC5\u987B\u662F 1 \u5230 65535 \u4E4B\u95F4\u7684\u6574\u6570");
|
|
319
|
+
}
|
|
320
|
+
parsed.port = port;
|
|
321
|
+
} else if (option === "--session-ttl") {
|
|
322
|
+
parsed.sessionTtl = value;
|
|
323
|
+
}
|
|
324
|
+
index += 1;
|
|
325
|
+
}
|
|
326
|
+
return parsed;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/cli-server-listen.ts
|
|
330
|
+
var MAX_TCP_PORT = 65535;
|
|
331
|
+
function isAddressInUseError(error) {
|
|
332
|
+
return error instanceof Error && "code" in error && error.code === "EADDRINUSE";
|
|
333
|
+
}
|
|
334
|
+
async function listenOnAvailablePort(server, host, initialPort) {
|
|
335
|
+
for (let port = initialPort; port <= MAX_TCP_PORT; port += 1) {
|
|
336
|
+
try {
|
|
337
|
+
await server.listen({ host, port });
|
|
338
|
+
return port;
|
|
339
|
+
} catch (error) {
|
|
340
|
+
if (!isAddressInUseError(error) || port === MAX_TCP_PORT) {
|
|
341
|
+
throw error;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
throw new Error(`\u7AEF\u53E3 ${String(initialPort)} \u5230 ${String(MAX_TCP_PORT)} \u5747\u4E0D\u53EF\u7528`);
|
|
346
|
+
}
|
|
347
|
+
var STARTUP_UPDATE_APPLIED_ENV = "CODEXLY_STARTUP_UPDATE_APPLIED";
|
|
348
|
+
function createStartupAppUpdateOperations(appVersion) {
|
|
349
|
+
const service = createAppUpdateService({
|
|
350
|
+
appVersion,
|
|
351
|
+
// 启动前 Codex 尚未运行,此服务只消费版本检查和安装结果。
|
|
352
|
+
codexVersion: "not-started"
|
|
353
|
+
});
|
|
354
|
+
return {
|
|
355
|
+
check: async () => {
|
|
356
|
+
const info = await service.read();
|
|
357
|
+
return {
|
|
358
|
+
latestVersion: info.latestVersion,
|
|
359
|
+
status: info.status === "available" ? "available" : info.status === "check-failed" ? "check-failed" : "current"
|
|
360
|
+
};
|
|
361
|
+
},
|
|
362
|
+
install: async (version) => {
|
|
363
|
+
await service.install(version);
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
async function confirmTerminalAppUpdate(currentVersion, latestVersion) {
|
|
368
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
369
|
+
const terminal = createInterface({ input: process.stdin, output: process.stdout });
|
|
370
|
+
try {
|
|
371
|
+
const answer = await terminal.question(
|
|
372
|
+
`\u53D1\u73B0 Codexly \u65B0\u7248\u672C ${latestVersion}\uFF08\u5F53\u524D ${currentVersion}\uFF09\uFF0C\u662F\u5426\u66F4\u65B0\u540E\u542F\u52A8\uFF1F[y/N] `
|
|
373
|
+
);
|
|
374
|
+
const normalizedAnswer = answer.trim().toLocaleLowerCase();
|
|
375
|
+
return normalizedAnswer === "y" || normalizedAnswer === "yes";
|
|
376
|
+
} finally {
|
|
377
|
+
terminal.close();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async function restartCliAfterUpdate(args) {
|
|
381
|
+
const cliEntry = process.argv[1];
|
|
382
|
+
if (cliEntry === void 0) throw new Error("\u65E0\u6CD5\u786E\u5B9A Codexly CLI \u5165\u53E3");
|
|
383
|
+
return new Promise((resolve, reject) => {
|
|
384
|
+
const child = spawn(process.execPath, [cliEntry, ...args], {
|
|
385
|
+
env: { ...process.env, [STARTUP_UPDATE_APPLIED_ENV]: "1" },
|
|
386
|
+
shell: false,
|
|
387
|
+
stdio: "inherit",
|
|
388
|
+
windowsHide: true
|
|
389
|
+
});
|
|
390
|
+
child.once("error", reject);
|
|
391
|
+
child.once("exit", (code, signal) => {
|
|
392
|
+
if (signal !== null) {
|
|
393
|
+
reject(new Error(`\u66F4\u65B0\u540E\u7684 Codexly \u542F\u52A8\u8FDB\u7A0B\u88AB\u4FE1\u53F7 ${signal} \u7EC8\u6B62`));
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
resolve(code ?? 1);
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
var LAUNCH_CONFIRMATION_MS = 500;
|
|
401
|
+
function browserCommands(url, platform) {
|
|
402
|
+
if (platform === "darwin") {
|
|
403
|
+
return [{ args: [url], executable: "open" }];
|
|
404
|
+
}
|
|
405
|
+
if (platform === "win32") {
|
|
406
|
+
return [{ args: ["/c", "start", "", url], executable: "cmd.exe" }];
|
|
407
|
+
}
|
|
408
|
+
return [
|
|
409
|
+
{ args: [url], executable: "xdg-open" },
|
|
410
|
+
{ args: ["open", url], executable: "gio" },
|
|
411
|
+
{ args: [url], executable: "sensible-browser" }
|
|
412
|
+
];
|
|
413
|
+
}
|
|
414
|
+
function launchBrowserCommand(command) {
|
|
415
|
+
return new Promise((resolveOpen, reject) => {
|
|
416
|
+
const child = spawn(command.executable, [...command.args], {
|
|
417
|
+
detached: true,
|
|
418
|
+
shell: false,
|
|
419
|
+
stdio: "ignore"
|
|
420
|
+
});
|
|
421
|
+
let settled = false;
|
|
422
|
+
let confirmationTimer;
|
|
423
|
+
const settle = (action) => {
|
|
424
|
+
if (settled) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
settled = true;
|
|
428
|
+
if (confirmationTimer !== void 0) {
|
|
429
|
+
clearTimeout(confirmationTimer);
|
|
430
|
+
}
|
|
431
|
+
action();
|
|
432
|
+
};
|
|
433
|
+
child.once("error", (error) => {
|
|
434
|
+
settle(() => {
|
|
435
|
+
reject(error);
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
child.once("spawn", () => {
|
|
439
|
+
confirmationTimer = setTimeout(() => {
|
|
440
|
+
settle(() => {
|
|
441
|
+
child.unref();
|
|
442
|
+
resolveOpen();
|
|
443
|
+
});
|
|
444
|
+
}, LAUNCH_CONFIRMATION_MS);
|
|
445
|
+
});
|
|
446
|
+
child.once("exit", (exitCode, signal) => {
|
|
447
|
+
if (exitCode === 0) {
|
|
448
|
+
settle(resolveOpen);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const reason = signal ? `signal ${signal}` : `code ${String(exitCode)}`;
|
|
452
|
+
settle(() => {
|
|
453
|
+
reject(
|
|
454
|
+
Object.assign(new Error(`${command.executable} exited with ${reason}`), {
|
|
455
|
+
code: "LAUNCHER_EXIT"
|
|
456
|
+
})
|
|
457
|
+
);
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
async function openSystemBrowser(url, options = {}) {
|
|
463
|
+
const platform = options.platform ?? process.platform;
|
|
464
|
+
const commands = browserCommands(url, platform);
|
|
465
|
+
const launch = options.launch ?? launchBrowserCommand;
|
|
466
|
+
let lastLauncherError;
|
|
467
|
+
for (const command of commands) {
|
|
468
|
+
try {
|
|
469
|
+
await launch(command);
|
|
470
|
+
return;
|
|
471
|
+
} catch (error) {
|
|
472
|
+
if (platform !== "linux" && error.code !== "ENOENT") {
|
|
473
|
+
throw error;
|
|
474
|
+
}
|
|
475
|
+
lastLauncherError = error;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
throw new Error("No supported browser launcher is installed", { cause: lastLauncherError });
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/terminal-output.ts
|
|
482
|
+
var ANSI_COLORS = {
|
|
483
|
+
cyan: "\x1B[36m",
|
|
484
|
+
green: "\x1B[32m",
|
|
485
|
+
red: "\x1B[31m",
|
|
486
|
+
reset: "\x1B[0m",
|
|
487
|
+
yellow: "\x1B[33m"
|
|
488
|
+
};
|
|
489
|
+
function createTerminalOutput(stdout, stderr, colorEnabled) {
|
|
490
|
+
const label = (text, color) => colorEnabled ? `${color}[${text}]${ANSI_COLORS.reset}` : `[${text}]`;
|
|
491
|
+
return {
|
|
492
|
+
error: (message) => {
|
|
493
|
+
stderr(`${label("\u9519\u8BEF", ANSI_COLORS.red)} ${message}
|
|
494
|
+
`);
|
|
495
|
+
},
|
|
496
|
+
info: (message) => {
|
|
497
|
+
stdout(`${label("\u4FE1\u606F", ANSI_COLORS.cyan)} ${message}
|
|
498
|
+
`);
|
|
499
|
+
},
|
|
500
|
+
plain: stdout,
|
|
501
|
+
success: (message) => {
|
|
502
|
+
stdout(`${label("\u6210\u529F", ANSI_COLORS.green)} ${message}
|
|
503
|
+
`);
|
|
504
|
+
},
|
|
505
|
+
warning: (message) => {
|
|
506
|
+
stderr(`${label("\u8B66\u544A", ANSI_COLORS.yellow)} ${message}
|
|
507
|
+
`);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
var MIN_LAN_PASSWORD_LENGTH = 16;
|
|
512
|
+
var MAX_LAN_PASSWORD_LENGTH = 128;
|
|
513
|
+
var UNIT_MS = {
|
|
514
|
+
d: 24 * 60 * 60 * 1e3,
|
|
515
|
+
h: 60 * 60 * 1e3,
|
|
516
|
+
m: 6e4,
|
|
517
|
+
ms: 1,
|
|
518
|
+
s: 1e3
|
|
519
|
+
};
|
|
520
|
+
var VIRTUAL_INTERFACE_PATTERN = /^(?:awdl|br|bridge|docker|ham|llw|lo|tap|tun|utun|vboxnet|veth|virbr|wg|zt)(?:\d|[-_.]|$)|(?:openvpn|tailscale|vethernet|virtualbox|vmnet|zerotier)/iu;
|
|
521
|
+
function parseSessionTtl(value) {
|
|
522
|
+
const match = /^(\d+)(ms|[smhd])$/u.exec(value);
|
|
523
|
+
if (match === null) {
|
|
524
|
+
throw new Error("Invalid session TTL; use a positive integer followed by ms, s, m, h, or d");
|
|
525
|
+
}
|
|
526
|
+
const amount = BigInt(match[1] ?? "0");
|
|
527
|
+
const unit = match[2];
|
|
528
|
+
const milliseconds = amount * BigInt(UNIT_MS[unit]);
|
|
529
|
+
if (milliseconds <= 0n || milliseconds > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
530
|
+
throw new Error(
|
|
531
|
+
"Invalid session TTL; duration must be a positive safe integer in milliseconds"
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
return Number(milliseconds);
|
|
535
|
+
}
|
|
536
|
+
function validateLanPassword(value) {
|
|
537
|
+
const hasRequiredStrength = value.length >= MIN_LAN_PASSWORD_LENGTH && value.length <= MAX_LAN_PASSWORD_LENGTH && /[A-Z]/u.test(value) && /[a-z]/u.test(value) && /[0-9]/u.test(value) && /[^A-Za-z0-9]/u.test(value);
|
|
538
|
+
if (!hasRequiredStrength) {
|
|
539
|
+
throw new Error(
|
|
540
|
+
"Invalid LAN password; expected 16 to 128 characters with uppercase, lowercase, number, and symbol"
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function generateLanPairingCode() {
|
|
545
|
+
return randomBytes(16).toString("base64url");
|
|
546
|
+
}
|
|
547
|
+
function isPrivateIpv4(address) {
|
|
548
|
+
if (isIP(address) !== 4) {
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
const [first = -1, second = -1] = address.split(".").map(Number);
|
|
552
|
+
return first === 10 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168;
|
|
553
|
+
}
|
|
554
|
+
function isVirtualNetworkInterface(name) {
|
|
555
|
+
return VIRTUAL_INTERFACE_PATTERN.test(name);
|
|
556
|
+
}
|
|
557
|
+
function listLanAccessUrls(port, interfaces = networkInterfaces()) {
|
|
558
|
+
const addresses = Object.entries(interfaces).filter(([name]) => !isVirtualNetworkInterface(name)).flatMap(([, entries]) => entries ?? []).filter((entry) => entry.family === "IPv4" && !entry.internal && isPrivateIpv4(entry.address)).map((entry) => entry.address);
|
|
559
|
+
return [...new Set(addresses)].sort((left, right) => left.localeCompare(right, "en", { numeric: true })).map((address) => `http://${address}:${String(port)}`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/cli-command.ts
|
|
563
|
+
var startupAppUpdate = createStartupAppUpdateOperations(package_default.version);
|
|
564
|
+
var defaultDependencies = {
|
|
565
|
+
appVersion: package_default.version,
|
|
566
|
+
checkAppUpdate: startupAppUpdate.check,
|
|
567
|
+
checkCodexVersion,
|
|
568
|
+
confirmAppUpdate: confirmTerminalAppUpdate,
|
|
569
|
+
createProjectRepository: ({ client, projection }) => new CodexProjectRepository(client, projection),
|
|
570
|
+
createStateRepository: (databasePath) => SqliteStateRepository.open(databasePath),
|
|
571
|
+
createRuntimeProvider: createCodexRuntimeProvider,
|
|
572
|
+
createServer: async (input) => {
|
|
573
|
+
const server = await createCodexlyServer({
|
|
574
|
+
...input
|
|
575
|
+
});
|
|
576
|
+
return {
|
|
577
|
+
close: () => server.close(),
|
|
578
|
+
listen: (options) => server.listen(options)
|
|
579
|
+
};
|
|
580
|
+
},
|
|
581
|
+
ensureTemporaryWorkspace,
|
|
582
|
+
generateLanPairingCode,
|
|
583
|
+
listLanAccessUrls,
|
|
584
|
+
locateCodexBinary,
|
|
585
|
+
nodeVersion: process.versions.node,
|
|
586
|
+
openBrowser: openSystemBrowser,
|
|
587
|
+
installAppUpdate: startupAppUpdate.install,
|
|
588
|
+
restartAfterUpdate: restartCliAfterUpdate,
|
|
589
|
+
startCodexAppServer,
|
|
590
|
+
webRoot: fileURLToPath(new URL("../dist/web", import.meta.url))
|
|
591
|
+
};
|
|
592
|
+
async function ensureTemporaryWorkspace(path) {
|
|
593
|
+
await mkdir(path, { mode: 448, recursive: true });
|
|
594
|
+
const metadata = await lstat(path);
|
|
595
|
+
if (metadata.isSymbolicLink()) {
|
|
596
|
+
throw new Error("Temporary workspace must not be a symbolic link");
|
|
597
|
+
}
|
|
598
|
+
if (!metadata.isDirectory()) {
|
|
599
|
+
throw new Error("Temporary workspace path must be a directory");
|
|
600
|
+
}
|
|
601
|
+
await chmod(path, 448);
|
|
602
|
+
return realpath(path);
|
|
603
|
+
}
|
|
604
|
+
function assertSupportedNodeVersion(version) {
|
|
605
|
+
const [major = Number.NaN, minor = Number.NaN] = version.split(".").map(Number);
|
|
606
|
+
if (!(major > 22 || major === 22 && minor >= 14)) {
|
|
607
|
+
throw new Error(`\u9700\u8981 Node.js 22.14.0 \u6216\u66F4\u9AD8\u7248\u672C\uFF0C\u5F53\u524D\u7248\u672C\u4E3A ${version}`);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
function resolveCodexHome(options) {
|
|
611
|
+
return options.codexHome ?? process.env["CODEX_HOME"] ?? join(homedir(), ".codex");
|
|
612
|
+
}
|
|
613
|
+
function assertDatabaseDiagnostics(diagnostics) {
|
|
614
|
+
if (!diagnostics.writable) {
|
|
615
|
+
throw new Error("SQLite database is not writable");
|
|
616
|
+
}
|
|
617
|
+
if (diagnostics.migrationVersion < 1) {
|
|
618
|
+
throw new Error("SQLite migrations are not applied");
|
|
619
|
+
}
|
|
620
|
+
if (diagnostics.integrityCheck !== "ok") {
|
|
621
|
+
throw new Error(`SQLite integrity_check failed: ${diagnostics.integrityCheck}`);
|
|
622
|
+
}
|
|
623
|
+
if (diagnostics.journalMode.toLocaleLowerCase() !== "wal") {
|
|
624
|
+
throw new Error(`SQLite journal_mode must be WAL; found ${diagnostics.journalMode}`);
|
|
625
|
+
}
|
|
626
|
+
if (!diagnostics.foreignKeys || diagnostics.synchronous !== "normal" || diagnostics.busyTimeout !== 5e3) {
|
|
627
|
+
throw new Error("SQLite PRAGMA configuration is invalid");
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function createProcessShutdownSignal() {
|
|
631
|
+
const controller = new AbortController();
|
|
632
|
+
const abort = () => {
|
|
633
|
+
controller.abort();
|
|
634
|
+
};
|
|
635
|
+
process.once("SIGINT", abort);
|
|
636
|
+
process.once("SIGTERM", abort);
|
|
637
|
+
return {
|
|
638
|
+
cleanup: () => {
|
|
639
|
+
process.off("SIGINT", abort);
|
|
640
|
+
process.off("SIGTERM", abort);
|
|
641
|
+
},
|
|
642
|
+
signal: controller.signal
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
async function waitForAbort(signal) {
|
|
646
|
+
if (signal.aborted) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
await new Promise((resolve) => {
|
|
650
|
+
signal.addEventListener(
|
|
651
|
+
"abort",
|
|
652
|
+
() => {
|
|
653
|
+
resolve();
|
|
654
|
+
},
|
|
655
|
+
{ once: true }
|
|
656
|
+
);
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
async function runDoctor(args, dependencies, output) {
|
|
660
|
+
const options = parseCommandOptions(args, /* @__PURE__ */ new Set(["--codex-bin", "--codex-home"]));
|
|
661
|
+
assertSupportedNodeVersion(dependencies.nodeVersion);
|
|
662
|
+
output.success(`Node.js ${dependencies.nodeVersion}`);
|
|
663
|
+
const binary = await dependencies.locateCodexBinary(
|
|
664
|
+
options.codexBin ? { explicitPath: options.codexBin } : {}
|
|
665
|
+
);
|
|
666
|
+
const version = await dependencies.checkCodexVersion(binary.path);
|
|
667
|
+
output.success(`Codex ${version.version} (${binary.path})`);
|
|
668
|
+
const codexHome = resolveCodexHome(options);
|
|
669
|
+
const stateRepository = await dependencies.createStateRepository(
|
|
670
|
+
join(codexHome, "codexly", "state.sqlite3")
|
|
671
|
+
);
|
|
672
|
+
try {
|
|
673
|
+
const diagnostics = await stateRepository.diagnose();
|
|
674
|
+
assertDatabaseDiagnostics(diagnostics);
|
|
675
|
+
output.success(`SQLite \u53EF\u5199 (${join(codexHome, "codexly", "state.sqlite3")})`);
|
|
676
|
+
output.success(`SQLite migration ${String(diagnostics.migrationVersion)}`);
|
|
677
|
+
output.success(`SQLite integrity_check ${diagnostics.integrityCheck}`);
|
|
678
|
+
output.success(`SQLite journal_mode ${diagnostics.journalMode}`);
|
|
679
|
+
output.success(
|
|
680
|
+
`SQLite PRAGMA foreign_keys=ON synchronous=NORMAL busy_timeout=${String(diagnostics.busyTimeout)}`
|
|
681
|
+
);
|
|
682
|
+
} finally {
|
|
683
|
+
await stateRepository.close();
|
|
684
|
+
}
|
|
685
|
+
return 0;
|
|
686
|
+
}
|
|
687
|
+
async function runStart(args, dependencies, signal, output) {
|
|
688
|
+
const options = parseCommandOptions(
|
|
689
|
+
args,
|
|
690
|
+
/* @__PURE__ */ new Set([
|
|
691
|
+
"--allowed-host",
|
|
692
|
+
"--codex-bin",
|
|
693
|
+
"--codex-home",
|
|
694
|
+
"--lan-password",
|
|
695
|
+
"--port",
|
|
696
|
+
"--session-ttl"
|
|
697
|
+
]),
|
|
698
|
+
/* @__PURE__ */ new Set(["--lan"])
|
|
699
|
+
);
|
|
700
|
+
if (options.sessionTtl !== void 0 && options.lan !== true) {
|
|
701
|
+
throw new Error("--session-ttl \u53EA\u80FD\u4E0E --lan \u4E00\u8D77\u4F7F\u7528");
|
|
702
|
+
}
|
|
703
|
+
if (options.lanPassword !== void 0 && options.lan !== true) {
|
|
704
|
+
throw new Error("--lan-password \u53EA\u80FD\u4E0E --lan \u4E00\u8D77\u4F7F\u7528");
|
|
705
|
+
}
|
|
706
|
+
if (options.lanPassword !== void 0) {
|
|
707
|
+
validateLanPassword(options.lanPassword);
|
|
708
|
+
}
|
|
709
|
+
const allowedHosts = options.allowedHosts?.map(normalizeAllowedHost);
|
|
710
|
+
const port = options.port ?? 3210;
|
|
711
|
+
const sessionTtlMs = options.sessionTtl ? parseSessionTtl(options.sessionTtl) : void 0;
|
|
712
|
+
const access = options.lan !== true ? void 0 : {
|
|
713
|
+
pairingCode: options.lanPassword ?? dependencies.generateLanPairingCode(),
|
|
714
|
+
...sessionTtlMs === void 0 ? {} : { sessionTtlMs }
|
|
715
|
+
};
|
|
716
|
+
if (process.env[STARTUP_UPDATE_APPLIED_ENV] !== "1") {
|
|
717
|
+
const update = await dependencies.checkAppUpdate();
|
|
718
|
+
if (update.status === "check-failed") {
|
|
719
|
+
output.warning("\u65E0\u6CD5\u68C0\u67E5 Codexly \u66F4\u65B0\uFF0C\u5C06\u7EE7\u7EED\u542F\u52A8\u5F53\u524D\u7248\u672C\u3002");
|
|
720
|
+
} else if (update.status === "available" && update.latestVersion !== null) {
|
|
721
|
+
const shouldUpdate = await dependencies.confirmAppUpdate(
|
|
722
|
+
dependencies.appVersion,
|
|
723
|
+
update.latestVersion
|
|
724
|
+
);
|
|
725
|
+
if (shouldUpdate) {
|
|
726
|
+
output.info(`\u6B63\u5728\u66F4\u65B0 Codexly \u5230 ${update.latestVersion}...`);
|
|
727
|
+
await dependencies.installAppUpdate(update.latestVersion);
|
|
728
|
+
output.success(`Codexly \u5DF2\u66F4\u65B0\u5230 ${update.latestVersion}\uFF0C\u6B63\u5728\u91CD\u65B0\u542F\u52A8\u3002`);
|
|
729
|
+
return dependencies.restartAfterUpdate(["start", ...args]);
|
|
730
|
+
}
|
|
731
|
+
output.info("\u5DF2\u8DF3\u8FC7\u66F4\u65B0\uFF0C\u7EE7\u7EED\u542F\u52A8\u5F53\u524D\u7248\u672C\u3002");
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const ownedShutdown = signal ? null : createProcessShutdownSignal();
|
|
735
|
+
const shutdownSignal = signal ?? ownedShutdown?.signal;
|
|
736
|
+
if (!shutdownSignal) {
|
|
737
|
+
throw new Error("Shutdown signal is unavailable");
|
|
738
|
+
}
|
|
739
|
+
let runtime;
|
|
740
|
+
let server;
|
|
741
|
+
let stateRepository;
|
|
742
|
+
try {
|
|
743
|
+
const codexHome = resolveCodexHome(options);
|
|
744
|
+
const env = {
|
|
745
|
+
...process.env,
|
|
746
|
+
...options.codexHome ? { CODEX_HOME: options.codexHome } : {}
|
|
747
|
+
};
|
|
748
|
+
stateRepository = await dependencies.createStateRepository(
|
|
749
|
+
join(codexHome, "codexly", "state.sqlite3")
|
|
750
|
+
);
|
|
751
|
+
const temporaryWorkspace = await dependencies.ensureTemporaryWorkspace(
|
|
752
|
+
join(codexHome, "codexly", "temporary-workspace")
|
|
753
|
+
);
|
|
754
|
+
runtime = await dependencies.startCodexAppServer({
|
|
755
|
+
appVersion: dependencies.appVersion,
|
|
756
|
+
env,
|
|
757
|
+
...options.codexBin ? { binaryPath: options.codexBin } : {}
|
|
758
|
+
});
|
|
759
|
+
const projectRepository = dependencies.createProjectRepository({
|
|
760
|
+
client: runtime.client,
|
|
761
|
+
projection: stateRepository
|
|
762
|
+
});
|
|
763
|
+
const projectSourceMigration = await stateRepository.readProjectSourceMigration();
|
|
764
|
+
if (!projectSourceMigration.completed) {
|
|
765
|
+
await projectRepository.migrateLegacyProjects({
|
|
766
|
+
recoverUnassigned: projectSourceMigration.recoverUnassigned
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
await projectRepository.synchronize();
|
|
770
|
+
if (!projectSourceMigration.completed) {
|
|
771
|
+
await stateRepository.completeProjectSourceMigration();
|
|
772
|
+
}
|
|
773
|
+
const provider = await dependencies.createRuntimeProvider({
|
|
774
|
+
client: runtime.client
|
|
775
|
+
});
|
|
776
|
+
const appUpdateService = createAppUpdateService({
|
|
777
|
+
appVersion: dependencies.appVersion,
|
|
778
|
+
codexVersion: runtime.version.version
|
|
779
|
+
});
|
|
780
|
+
server = await dependencies.createServer({
|
|
781
|
+
...access === void 0 ? {} : { access },
|
|
782
|
+
...allowedHosts === void 0 ? {} : { allowedHosts },
|
|
783
|
+
projectRepository,
|
|
784
|
+
providerConnectionRepository: stateRepository,
|
|
785
|
+
provider,
|
|
786
|
+
installAppUpdate: appUpdateService.install,
|
|
787
|
+
readAppInfo: appUpdateService.read,
|
|
788
|
+
settingsRepository: stateRepository,
|
|
789
|
+
staticRoot: dependencies.webRoot,
|
|
790
|
+
temporaryWorkspace
|
|
791
|
+
});
|
|
792
|
+
const host = options.lan === true ? "0.0.0.0" : "127.0.0.1";
|
|
793
|
+
const activePort = await listenOnAvailablePort(server, host, port);
|
|
794
|
+
if (activePort !== port) {
|
|
795
|
+
output.warning(`\u7AEF\u53E3 ${String(port)} \u5DF2\u88AB\u5360\u7528\uFF0C\u5DF2\u81EA\u52A8\u5207\u6362\u5230\u7AEF\u53E3 ${String(activePort)}\u3002`);
|
|
796
|
+
}
|
|
797
|
+
output.success("Codexly \u5DF2\u542F\u52A8");
|
|
798
|
+
if (access !== void 0) {
|
|
799
|
+
const urls = dependencies.listLanAccessUrls(activePort);
|
|
800
|
+
output.warning("\u5C40\u57DF\u7F51\u6A21\u5F0F\u4F7F\u7528\u672A\u52A0\u5BC6\u7684 HTTP\uFF0C\u8BF7\u4EC5\u5728\u53EF\u4FE1\u7F51\u7EDC\u4E2D\u4F7F\u7528\u3002");
|
|
801
|
+
if (urls.length === 0) {
|
|
802
|
+
output.warning("\u672A\u627E\u5230\u53EF\u7528\u7684\u5C40\u57DF\u7F51 IPv4 \u5730\u5740\uFF0C\u670D\u52A1\u4ECD\u5728\u8FD0\u884C\u3002");
|
|
803
|
+
} else {
|
|
804
|
+
output.info(`\u5C40\u57DF\u7F51\u8BBF\u95EE\u5730\u5740:
|
|
805
|
+
${urls.map((url) => ` ${url}`).join("\n")}`);
|
|
806
|
+
}
|
|
807
|
+
if (options.lanPassword === void 0) {
|
|
808
|
+
output.info(`\u914D\u5BF9\u7801: ${access.pairingCode}`);
|
|
809
|
+
} else {
|
|
810
|
+
output.info("\u5DF2\u4F7F\u7528\u81EA\u5B9A\u4E49\u8BBF\u95EE\u5BC6\u7801\uFF08\u4E0D\u4F1A\u5728\u7EC8\u7AEF\u56DE\u663E\uFF09\u3002");
|
|
811
|
+
}
|
|
812
|
+
output.info(
|
|
813
|
+
options.sessionTtl === void 0 ? "\u4F1A\u8BDD\u6709\u6548\u671F: \u6C38\u4E0D\u8FC7\u671F\uFF08\u4EC5\u5F53\u524D\u8FDB\u7A0B\uFF09" : `\u4F1A\u8BDD\u6709\u6548\u671F: ${options.sessionTtl}\uFF08\u56FA\u5B9A\u671F\u9650\uFF0C\u4E0D\u81EA\u52A8\u7EED\u671F\uFF09`
|
|
814
|
+
);
|
|
815
|
+
output.info("\u91CD\u542F Codexly \u540E\uFF0C\u5F53\u524D\u914D\u5BF9\u7801\u548C\u6240\u6709\u5C40\u57DF\u7F51\u4F1A\u8BDD\u5C06\u5931\u6548\u3002");
|
|
816
|
+
} else {
|
|
817
|
+
output.info(`\u8BBF\u95EE\u5730\u5740: http://127.0.0.1:${String(activePort)}`);
|
|
818
|
+
}
|
|
819
|
+
if (options.lan !== true) {
|
|
820
|
+
try {
|
|
821
|
+
await dependencies.openBrowser(`http://127.0.0.1:${String(activePort)}`);
|
|
822
|
+
} catch (error) {
|
|
823
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
824
|
+
output.warning(`\u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE\u4E0A\u8FF0\u5730\u5740\u3002\u539F\u56E0: ${message}`);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
const outcome = await Promise.race([
|
|
828
|
+
runtime.waitForExit().then((exit) => ({ exit, type: "process-exit" })),
|
|
829
|
+
waitForAbort(shutdownSignal).then(() => ({ type: "shutdown" }))
|
|
830
|
+
]);
|
|
831
|
+
if (outcome.type === "process-exit") {
|
|
832
|
+
const reason = outcome.exit.signal ? `\u4FE1\u53F7 ${outcome.exit.signal}` : `\u9000\u51FA\u7801 ${String(outcome.exit.code)}`;
|
|
833
|
+
throw new Error(`Codex App Server \u5728 Codexly \u5173\u95ED\u524D\u610F\u5916\u9000\u51FA\uFF0C${reason}`);
|
|
834
|
+
}
|
|
835
|
+
return 0;
|
|
836
|
+
} finally {
|
|
837
|
+
try {
|
|
838
|
+
await server?.close();
|
|
839
|
+
} finally {
|
|
840
|
+
try {
|
|
841
|
+
await stateRepository?.close();
|
|
842
|
+
} finally {
|
|
843
|
+
try {
|
|
844
|
+
await runtime?.close();
|
|
845
|
+
} finally {
|
|
846
|
+
ownedShutdown?.cleanup();
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
async function runCli(argv, options = {}) {
|
|
853
|
+
const dependencies = options.dependencies ?? defaultDependencies;
|
|
854
|
+
const stdout = options.stdout ?? ((message) => process.stdout.write(message));
|
|
855
|
+
const stderr = options.stderr ?? ((message) => process.stderr.write(message));
|
|
856
|
+
const colorEnabled = options.color ?? (process.stdout.isTTY && process.env["NO_COLOR"] === void 0);
|
|
857
|
+
const output = createTerminalOutput(stdout, stderr, colorEnabled);
|
|
858
|
+
const [requestedCommand, ...rawArgs] = argv;
|
|
859
|
+
const command = requestedCommand ?? "start";
|
|
860
|
+
const args = rawArgs[0] === "--" ? rawArgs.slice(1) : rawArgs;
|
|
861
|
+
try {
|
|
862
|
+
if (command === "--help" || command === "-h") {
|
|
863
|
+
output.plain(CLI_HELP);
|
|
864
|
+
return 0;
|
|
865
|
+
}
|
|
866
|
+
if (command === "version") {
|
|
867
|
+
if (args.length > 0) {
|
|
868
|
+
throw new Error(`\u672A\u77E5\u9009\u9879: ${args[0] ?? "<empty>"}`);
|
|
869
|
+
}
|
|
870
|
+
output.plain(`codexly ${dependencies.appVersion}
|
|
871
|
+
`);
|
|
872
|
+
return 0;
|
|
873
|
+
}
|
|
874
|
+
if (command === "doctor") {
|
|
875
|
+
return await runDoctor(args, dependencies, output);
|
|
876
|
+
}
|
|
877
|
+
if (command === "start") {
|
|
878
|
+
return await runStart(args, dependencies, options.signal, output);
|
|
879
|
+
}
|
|
880
|
+
throw new Error(`\u672A\u77E5\u547D\u4EE4: ${command}`);
|
|
881
|
+
} catch (error) {
|
|
882
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
883
|
+
output.error(message);
|
|
884
|
+
return 1;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// src/cli.ts
|
|
889
|
+
process.exitCode = await runCli(process.argv.slice(2));
|