farming-code 2.2.29 → 2.2.32
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/README.md +25 -66
- package/README.zh_cn.md +15 -66
- package/THIRD_PARTY_NOTICES.md +7 -0
- package/backend/acp/{client-services.js → client-services.cjs} +132 -134
- package/backend/acp/packaged-claude-acp.cjs +37 -0
- package/backend/acp/packaged-codex-acp.cjs +37 -0
- package/backend/acp/patch-decisions.cjs +182 -0
- package/backend/acp/permission-security.cjs +131 -0
- package/backend/{acp-checkpoint-store.js → acp-checkpoint-store.cjs} +90 -59
- package/backend/{acp-runtime.js → acp-runtime.cjs} +1219 -1125
- package/backend/acp-session-state.cjs +622 -0
- package/backend/acp-transcript.cjs +525 -0
- package/backend/agent-env.cjs +257 -0
- package/backend/agent-extension-discovery.cjs +452 -0
- package/backend/agent-extension-inventory.cjs +116 -0
- package/backend/agent-json-stream.cjs +283 -0
- package/backend/agent-lifecycle-journal.cjs +185 -0
- package/backend/{agent-manager.js → agent-manager.cjs} +3116 -4275
- package/backend/agent-order-transaction.cjs +85 -0
- package/backend/agent-order.cjs +159 -0
- package/backend/agent-provider-session.cjs +98 -0
- package/backend/agent-runtime-binding.cjs +179 -0
- package/backend/agent-session-history.cjs +1022 -0
- package/backend/agent-session-inventory.cjs +291 -0
- package/backend/async-cache.cjs +104 -0
- package/backend/atomic-json-store.cjs +67 -0
- package/backend/auth.cjs +261 -0
- package/backend/authoritative-inventory-cache.cjs +383 -0
- package/backend/business-health.cjs +68 -0
- package/backend/chat-runtime.cjs +50 -0
- package/backend/claude-settings.cjs +132 -0
- package/backend/cli-agents.cjs +435 -0
- package/backend/codex-context-window.cjs +196 -0
- package/backend/codex-models.cjs +228 -0
- package/backend/codex-session-archive.cjs +82 -0
- package/backend/codex-session-history.cjs +590 -0
- package/backend/{codex-terminal-profile.js → codex-terminal-profile.cjs} +149 -155
- package/backend/codex-transcript-sanitizer.cjs +130 -0
- package/backend/codex-transcript.cjs +2107 -0
- package/backend/command-runner-child.cjs +105 -0
- package/backend/config-manager.cjs +1263 -0
- package/backend/control-api.cjs +439 -0
- package/backend/data/LICENSE.cua +21 -0
- package/backend/executable-discovery.cjs +204 -0
- package/backend/farming-agent-bootstrap.cjs +81 -0
- package/backend/farming-agent-bootstrap.zh_cn.md +6 -2
- package/backend/{farming-app-cli.js → farming-app-cli.cjs} +441 -493
- package/backend/farming-cli.cjs +414 -0
- package/backend/farming-net-pass.cjs +319 -0
- package/backend/farming-net-registry.cjs +123 -0
- package/backend/farming-net-server.cjs +309 -0
- package/backend/farming-session-store.cjs +651 -0
- package/backend/git-worktree-info.cjs +181 -0
- package/backend/haiku-token.cjs +828 -0
- package/backend/index-html.cjs +96 -0
- package/backend/input-parts.cjs +68 -0
- package/backend/input-routing.cjs +40 -0
- package/backend/{local-session-engine.js → local-session-engine.cjs} +276 -282
- package/backend/main-agent-skills.cjs +309 -0
- package/backend/main-page-session.cjs +132 -0
- package/backend/native-pty-controller-generation.cjs +139 -0
- package/backend/{native-pty-host-client.js → native-pty-host-client.cjs} +338 -346
- package/backend/native-pty-host-identity.cjs +125 -0
- package/backend/native-pty-host-path.cjs +68 -0
- package/backend/{native-pty-host.js → native-pty-host.cjs} +480 -569
- package/backend/native-session-engine.cjs +296 -0
- package/backend/network.cjs +57 -0
- package/backend/npm-update-helper.cjs +399 -0
- package/backend/packaged-node-pty.cjs +120 -0
- package/backend/preview-session-manager.cjs +89 -0
- package/backend/provider-adapters.cjs +492 -0
- package/backend/provider-home-configuration.cjs +211 -0
- package/backend/provider-session-id.cjs +79 -0
- package/backend/provider-session-service.cjs +333 -0
- package/backend/qr-share-tickets.cjs +119 -0
- package/backend/resource-broadcast-protocol.cjs +50 -0
- package/backend/review-diff-router.cjs +202 -0
- package/backend/review-diff-service.cjs +1267 -0
- package/backend/review-session-router.cjs +93 -0
- package/backend/review-session-service.cjs +470 -0
- package/backend/review-session-store.cjs +161 -0
- package/backend/review-state-router.cjs +132 -0
- package/backend/review-state-store.cjs +299 -0
- package/backend/run-history-store.cjs +97 -0
- package/backend/runtime-dependency-manager.cjs +893 -0
- package/backend/runtime-executable-invocation.cjs +37 -0
- package/backend/runtime-observation.cjs +96 -0
- package/backend/server-process-identity.cjs +70 -0
- package/backend/server.cjs +3356 -0
- package/backend/session-engine-bridge.cjs +144 -0
- package/backend/session-engine-router.cjs +105 -0
- package/backend/session-engine.cjs +64 -0
- package/backend/session-stream-protocol.cjs +181 -0
- package/backend/shell-busy-integration.cjs +442 -0
- package/backend/slash-command-discovery.cjs +423 -0
- package/backend/storage-layout.cjs +263 -0
- package/backend/system-monitor.cjs +96 -0
- package/backend/terminal-attach-checkpoint.cjs +73 -0
- package/backend/terminal-exit-quiescence.cjs +57 -0
- package/backend/{terminal-reducer-flow-control.js → terminal-reducer-flow-control.cjs} +45 -22
- package/backend/terminal-runtime-cleanup.cjs +99 -0
- package/backend/{terminal-screen-state.js → terminal-screen-state.cjs} +100 -108
- package/backend/{terminal-screen-worker-pool.js → terminal-screen-worker-pool.cjs} +89 -79
- package/backend/{terminal-screen-worker-thread.js → terminal-screen-worker-thread.cjs} +64 -65
- package/backend/terminal-screen-worker.cjs +352 -0
- package/backend/terminal-state-serialization.cjs +147 -0
- package/backend/{terminal-status.js → terminal-status.cjs} +137 -187
- package/backend/theme-manager.cjs +185 -0
- package/backend/update-service.cjs +675 -0
- package/backend/usage-forecast.cjs +95 -0
- package/backend/{usage-history-client.js → usage-history-client.cjs} +144 -94
- package/backend/usage-history-smoke.cjs +85 -0
- package/backend/usage-history-worker.cjs +60 -0
- package/backend/{usage-monitor.js → usage-monitor.cjs} +363 -390
- package/backend/workspace-directory.cjs +239 -0
- package/backend/workspace-discovery.cjs +271 -0
- package/backend/{workspace-file-router.js → workspace-file-router.cjs} +213 -282
- package/backend/{workspace-file-service.js → workspace-file-service.cjs} +1139 -1318
- package/backend/workspace-root-registry.cjs +192 -0
- package/bin/farming +1 -1
- package/config/farming.deploy.env.example +1 -1
- package/config/farming.install.env.example +1 -1
- package/dist/acp/codex-acp-1.1.4.mjs +405 -8
- package/dist/assets/App-BCkdpWB6.css +1 -0
- package/dist/assets/App-CRjKpaGp.js +697 -0
- package/dist/assets/CodeSelect-Ci8sKZPU.js +1 -0
- package/dist/assets/CodeSelect-T2eNzrOc.css +1 -0
- package/dist/assets/{FileEditorMarkdownPreview-Cs9cLv8a.js → FileEditorMarkdownPreview-V06QHlAg.js} +55 -55
- package/dist/assets/FileEditorPane-BX-Wjg9U.js +2 -0
- package/dist/assets/IconGlyphs-YhV7tqd4.js +1 -0
- package/dist/assets/ProjectFilesSection-BDT2_r0o.js +12 -0
- package/dist/assets/ReviewPage-BqAs5sG1.js +3 -0
- package/dist/assets/code-dark-B7eM_9G9.css +1 -0
- package/dist/assets/{cssMode-Bdg5RpcJ.js → cssMode-ADdAlxTO.js} +1 -1
- package/dist/assets/{editor.api2-D74ufkbr.js → editor.api2-BFLAr0YF.js} +162 -162
- package/dist/assets/file-icons-BpeqWkIB.js +1 -0
- package/dist/assets/{freemarker2-DfMDJfnE.js → freemarker2-C90q5jrp.js} +1 -1
- package/dist/assets/{handlebars-BEdPtzMT.js → handlebars-BwUQcEDq.js} +1 -1
- package/dist/assets/{html-B1fPb1QD.js → html-1s3uPKfh.js} +1 -1
- package/dist/assets/{htmlMode-CY2ZjHxH.js → htmlMode-xtKD99de.js} +1 -1
- package/dist/assets/{index-CQNaZc3l.js → index-C8MchCem.js} +3 -3
- package/dist/assets/{javascript-BV2OsWA0.js → javascript-Ph7ijyny.js} +1 -1
- package/dist/assets/{jsonMode-zd07aeuX.js → jsonMode-D-jGAnFH.js} +1 -1
- package/dist/assets/linkComputer-CbGyI_qx.js +1 -0
- package/dist/assets/{liquid-BParI24X.js → liquid-0IamE_cI.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-BzredkoV.js → lspLanguageFeatures-BxnQunWF.js} +1 -1
- package/dist/assets/main-CLKXa6hf.css +1 -0
- package/dist/assets/{mdx-vGzUJN98.js → mdx-DdNmfivn.js} +1 -1
- package/dist/assets/{monaco.contribution-BmaeBQEc.js → monaco.contribution-B43jsUs1.js} +2 -2
- package/dist/assets/{python-CUwdLgsI.js → python-IAt4X5TS.js} +1 -1
- package/dist/assets/{razor-BScebUxU.js → razor-DRkFYW0S.js} +1 -1
- package/dist/assets/review-C8-oPKXk.css +1 -0
- package/dist/assets/{tsMode-DzUAibXK.js → tsMode-_d_4U2gf.js} +1 -1
- package/dist/assets/{typescript-D9EOeM7N.js → typescript-C7zcMq9l.js} +1 -1
- package/dist/assets/{workers-DAiomYZM.js → workers-D0nOyJzf.js} +1 -1
- package/dist/assets/workspace-editor-model-DND_Y-Bj.js +1 -0
- package/dist/assets/workspace-editor-monaco-BPWhgcIB.js +4 -0
- package/dist/assets/workspace-editor-monaco-N641qPjX.js +1 -0
- package/dist/assets/workspace-view-state-k1bTlJ_Z.js +13 -0
- package/dist/assets/{xml-wWl1dhkQ.js → xml-BR-HvxT8.js} +1 -1
- package/dist/assets/{yaml-Dc2WDaOZ.js → yaml-YtFQwh4q.js} +1 -1
- package/dist/index.html +2 -1
- package/extensions/browser/backend/agent-browser-runtime.cjs +1040 -0
- package/extensions/browser/backend/agent-capability.cjs +85 -0
- package/extensions/browser/backend/browser-mcp-server.cjs +655 -0
- package/extensions/browser/backend/browser-resource-manager.cjs +1486 -0
- package/extensions/browser/backend/browser-resource-store.cjs +228 -0
- package/extensions/browser/backend/browser-router.cjs +203 -0
- package/extensions/browser/backend/executable-discovery.cjs +248 -0
- package/extensions/browser/backend/farming-browser-client.cjs +116 -0
- package/extensions/browser/backend/index.cjs +32 -0
- package/extensions/browser/backend/managed-chromium-installer.cjs +833 -0
- package/extensions/browser/bin/farming-browser +16 -7
- package/extensions/computer/backend/agent-capability.cjs +72 -0
- package/extensions/computer/backend/computer-constants.cjs +59 -0
- package/extensions/computer/backend/computer-mcp-server.cjs +182 -0
- package/extensions/computer/backend/computer-resource-manager.cjs +1219 -0
- package/extensions/computer/backend/computer-resource-store.cjs +190 -0
- package/extensions/computer/backend/computer-router.cjs +257 -0
- package/extensions/computer/backend/cua-tools.json +3067 -0
- package/extensions/computer/backend/farming-computer-client.cjs +84 -0
- package/extensions/computer/backend/index.cjs +35 -0
- package/extensions/computer/backend/isolated-browser-provider.cjs +157 -0
- package/extensions/computer/bin/farming-computer +131 -0
- package/frontend/farming-net/app.js +255 -262
- package/frontend/ghostty-loader.js +24 -20
- package/frontend/reading-anchor.js +210 -193
- package/frontend/runtime-paths.js +24 -26
- package/frontend/session-bridge.js +90 -111
- package/frontend/session-modal-bridge.js +184 -302
- package/frontend/skin-bridge.js +20 -23
- package/frontend/skins/crt/app.js +7686 -7901
- package/frontend/skins/crt/effects.js +7 -6
- package/frontend/skins/crt/index.html +6 -6
- package/frontend/skins/crt/styles/markdown.css +4 -4
- package/frontend/terminal-bridge.js +174 -181
- package/frontend/terminal-replay.js +320 -345
- package/frontend/theme-loader.js +55 -71
- package/index.html +1 -0
- package/package.json +64 -37
- package/shared/backend-connection-status.js +38 -69
- package/shared/browser-protocol.js +235 -110
- package/shared/websocket-liveness.js +40 -0
- package/backend/acp/packaged-claude-acp.js +0 -13
- package/backend/acp/packaged-codex-acp.js +0 -13
- package/backend/acp/patch-decisions.js +0 -153
- package/backend/acp/permission-security.js +0 -108
- package/backend/acp-session-state.js +0 -644
- package/backend/acp-transcript.js +0 -512
- package/backend/agent-env.js +0 -250
- package/backend/agent-json-stream.js +0 -268
- package/backend/agent-lifecycle-journal.js +0 -133
- package/backend/agent-memory-report.js +0 -583
- package/backend/agent-order.js +0 -166
- package/backend/agent-provider-session.js +0 -76
- package/backend/agent-runtime-binding.js +0 -174
- package/backend/agent-session-history.js +0 -953
- package/backend/async-cache.js +0 -94
- package/backend/atomic-json-store.js +0 -37
- package/backend/auth.js +0 -251
- package/backend/bundle-update-helper.js +0 -113
- package/backend/chat-runtime.js +0 -28
- package/backend/claude-settings.js +0 -121
- package/backend/cli-agents.js +0 -486
- package/backend/codex-context-window.js +0 -189
- package/backend/codex-models.js +0 -226
- package/backend/codex-rollout-follower.js +0 -326
- package/backend/codex-session-archive.js +0 -65
- package/backend/codex-session-history.js +0 -647
- package/backend/codex-transcript-sanitizer.js +0 -115
- package/backend/codex-transcript.js +0 -2564
- package/backend/command-runner-child.js +0 -67
- package/backend/config-manager.js +0 -1133
- package/backend/control-api.js +0 -455
- package/backend/executable-discovery.js +0 -216
- package/backend/farming-agent-bootstrap.js +0 -49
- package/backend/farming-cli.js +0 -457
- package/backend/farming-net-pass.js +0 -285
- package/backend/farming-net-registry.js +0 -112
- package/backend/farming-net-server.js +0 -298
- package/backend/farming-session-store.js +0 -677
- package/backend/git-worktree-info.js +0 -181
- package/backend/haiku-token.js +0 -772
- package/backend/index-html.js +0 -62
- package/backend/input-parts.js +0 -54
- package/backend/input-routing.js +0 -24
- package/backend/json-cli-runtime.js +0 -275
- package/backend/main-agent-skills.js +0 -305
- package/backend/main-page-session.js +0 -122
- package/backend/native-pty-controller-generation.js +0 -106
- package/backend/native-pty-host-identity.js +0 -86
- package/backend/native-pty-host-path.js +0 -42
- package/backend/native-session-engine.js +0 -268
- package/backend/network.js +0 -23
- package/backend/npm-update-helper.js +0 -374
- package/backend/packaged-node-pty.js +0 -99
- package/backend/preview-session-manager.js +0 -68
- package/backend/provider-adapters.js +0 -399
- package/backend/provider-session-id.js +0 -47
- package/backend/provider-session-service.js +0 -345
- package/backend/qr-share-tickets.js +0 -100
- package/backend/review-diff-router.js +0 -180
- package/backend/review-diff-service.js +0 -1270
- package/backend/review-session-router.js +0 -74
- package/backend/review-session-service.js +0 -446
- package/backend/review-session-store.js +0 -151
- package/backend/review-state-router.js +0 -116
- package/backend/review-state-store.js +0 -286
- package/backend/run-history-store.js +0 -67
- package/backend/runtime-dependency-manager.js +0 -759
- package/backend/runtime-executable-invocation.js +0 -20
- package/backend/runtime-observation.js +0 -81
- package/backend/server-process-identity.js +0 -47
- package/backend/server.js +0 -3267
- package/backend/session-engine-bridge.js +0 -129
- package/backend/session-engine-router.js +0 -66
- package/backend/session-engine.js +0 -39
- package/backend/session-stream-protocol.js +0 -185
- package/backend/shell-busy-integration.js +0 -472
- package/backend/slash-command-discovery.js +0 -433
- package/backend/storage-layout.js +0 -190
- package/backend/system-monitor.js +0 -77
- package/backend/terminal-attach-checkpoint.js +0 -74
- package/backend/terminal-exit-quiescence.js +0 -39
- package/backend/terminal-runtime-cleanup.js +0 -80
- package/backend/terminal-screen-worker.js +0 -337
- package/backend/terminal-state-serialization.js +0 -127
- package/backend/theme-manager.js +0 -163
- package/backend/update-service.js +0 -1545
- package/backend/usage-forecast.js +0 -86
- package/backend/usage-history-scanner.ts +0 -2718
- package/backend/usage-history-smoke.js +0 -64
- package/backend/usage-history-worker.js +0 -34
- package/backend/workspace-directory.js +0 -232
- package/backend/workspace-discovery.js +0 -311
- package/backend/workspace-root-registry.js +0 -166
- package/dist/assets/App-BKNUILuL.css +0 -1
- package/dist/assets/App-Ex2oVVXO.js +0 -693
- package/dist/assets/FileEditorPane-CNtuGjQ3.js +0 -2
- package/dist/assets/IconGlyphs-BClgag6E.js +0 -1
- package/dist/assets/ProjectFilesSection-Cf2BEcAN.js +0 -12
- package/dist/assets/ReviewPage-BRuxFaH5.js +0 -3
- package/dist/assets/code-dark-BEZTQwYZ.css +0 -1
- package/dist/assets/file-icons-BOlcJ0ZF.js +0 -1
- package/dist/assets/main-DK9Sy7-c.css +0 -1
- package/dist/assets/review-BcnwQtJv.css +0 -1
- package/dist/assets/workspace-editor-model-CSGCl21x.js +0 -1
- package/dist/assets/workspace-editor-monaco-CJNwbpCy.js +0 -4
- package/dist/assets/workspace-editor-monaco-CO9w8YV0.js +0 -1
- package/dist/assets/workspace-view-state-BjKPYp0E.js +0 -7
- package/extensions/browser/backend/agent-browser-runtime.js +0 -1041
- package/extensions/browser/backend/agent-capability.js +0 -55
- package/extensions/browser/backend/browser-mcp-server.js +0 -621
- package/extensions/browser/backend/browser-resource-manager.js +0 -1309
- package/extensions/browser/backend/browser-resource-store.js +0 -190
- package/extensions/browser/backend/browser-router.js +0 -133
- package/extensions/browser/backend/executable-discovery.js +0 -224
- package/extensions/browser/backend/farming-browser-client.js +0 -83
- package/extensions/browser/backend/index.js +0 -7
- package/extensions/browser/frontend/BrowserSidebarPortals.tsx +0 -360
- package/extensions/browser/frontend/BrowserViewer.tsx +0 -500
- package/extensions/browser/frontend/browser-resource-state.ts +0 -60
- package/extensions/browser/frontend/browser.css +0 -567
- package/extensions/browser/frontend/types.ts +0 -31
- package/extensions/browser/frontend/useBrowserResources.ts +0 -158
- package/frontend/vendor/ghostty-web/index.d.ts +0 -1842
- package/shared/backend-connection-status.d.ts +0 -37
- package/shared/browser-protocol.d.ts +0 -5
- /package/dist/assets/{api-w2x5QfxB.js → api-ByCV9MEr.js} +0 -0
- /package/dist/assets/{core-vPkV8P_m.js → core-Czwdx12k.js} +0 -0
- /package/dist/assets/{fsharp-DNZNZyEE.js → fsharp-BjPpkoJe.js} +0 -0
- /package/dist/assets/{go-_kPJjNc_.js → go-BkIDmSUP.js} +0 -0
- /package/dist/assets/{graphql-4HCNVt5g.js → graphql-CCJTpqi1.js} +0 -0
- /package/dist/assets/{hcl-C87ymY0o.js → hcl-s4z8lUFg.js} +0 -0
- /package/dist/assets/{ini-BYrrGNTc.js → ini-CyUW1I7Z.js} +0 -0
- /package/dist/assets/{java-B211rJbk.js → java-CFCcGRiM.js} +0 -0
- /package/dist/assets/{julia-DVPsRtBm.js → julia-DQyH_EYb.js} +0 -0
- /package/dist/assets/{kotlin-BYyNerjp.js → kotlin-B8hA5O51.js} +0 -0
- /package/dist/assets/{less-EC9UblGE.js → less-DaVdaas0.js} +0 -0
- /package/dist/assets/{lexon-B1yuUdqW.js → lexon-DLBhPd3y.js} +0 -0
- /package/dist/assets/{lua-Bo6GFzxT.js → lua-gB1c_cif.js} +0 -0
- /package/dist/assets/{m3-C-Y9cBVI.js → m3-C2T3z3gB.js} +0 -0
- /package/dist/assets/{markdown-BHu-wLbe.js → markdown-CKq-Euj1.js} +0 -0
- /package/dist/assets/{mips-Dkds26rX.js → mips-Bcs5qIDX.js} +0 -0
- /package/dist/assets/{msdax-PU4g-8_g.js → msdax-CBP48FHF.js} +0 -0
- /package/dist/assets/{mysql-fPpuGpS7.js → mysql-c7tiPcFj.js} +0 -0
- /package/dist/assets/{objective-c-Wy1e5JUf.js → objective-c-D4BZkeEV.js} +0 -0
- /package/dist/assets/{pascal-BIXwvrqU.js → pascal-CJDZg0MN.js} +0 -0
- /package/dist/assets/{pascaligo-DwR0AtL_.js → pascaligo-Bygi8Ynl.js} +0 -0
- /package/dist/assets/{perl-CGHAl8my.js → perl-aS8bkf7E.js} +0 -0
- /package/dist/assets/{pgsql-B91M73E2.js → pgsql-CzNAYFYl.js} +0 -0
- /package/dist/assets/{php-C70ttrCx.js → php-DOtoEFTT.js} +0 -0
- /package/dist/assets/{pla-BNrXaRh0.js → pla-DugRnao1.js} +0 -0
- /package/dist/assets/{postiats-Dv2IAZR9.js → postiats-DsXwusKh.js} +0 -0
- /package/dist/assets/{powerquery-CkY5Wq7J.js → powerquery-DL3o72oD.js} +0 -0
- /package/dist/assets/{powershell-uGIYLU3C.js → powershell-C1qHekys.js} +0 -0
- /package/dist/assets/{protobuf-CavfmJu-.js → protobuf-DHgsc-cH.js} +0 -0
- /package/dist/assets/{pug-Drqnyitx.js → pug-FZXlE_Iu.js} +0 -0
- /package/dist/assets/{qrcode-7uGsTEmi.js → qrcode-DJDTdjL7.js} +0 -0
- /package/dist/assets/{qsharp-C7yF-Dti.js → qsharp-bLyhI3DT.js} +0 -0
- /package/dist/assets/{r-HXLGP0_-.js → r-DjFGXbAa.js} +0 -0
- /package/dist/assets/{redis-C4y6mf2p.js → redis-DSoZ_V6u.js} +0 -0
- /package/dist/assets/{redshift-DdQrFPrv.js → redshift-CzkdCsrg.js} +0 -0
- /package/dist/assets/{restructuredtext-CBrf2PNj.js → restructuredtext-B_XPrGCQ.js} +0 -0
- /package/dist/assets/{ruby-CVtMoX2B.js → ruby-Cry2RneJ.js} +0 -0
- /package/dist/assets/{rust-Ckq4sbMP.js → rust-CWzdbFq1.js} +0 -0
- /package/dist/assets/{sb-er66OpE3.js → sb-DmofU59h.js} +0 -0
- /package/dist/assets/{scala-BdWZz-hH.js → scala-BUC2l-vN.js} +0 -0
- /package/dist/assets/{scheme-kTV_s2kP.js → scheme-CNIB_72f.js} +0 -0
- /package/dist/assets/{scss-Bymy2VJQ.js → scss-DcL4-NbX.js} +0 -0
- /package/dist/assets/{shell-bwEP1LQ1.js → shell-CgAGvSSA.js} +0 -0
- /package/dist/assets/{solidity-DCddeBgL.js → solidity-DSkt6O_P.js} +0 -0
- /package/dist/assets/{sophia-BMN3AQig.js → sophia--5ytcjDN.js} +0 -0
- /package/dist/assets/{sparql-CSXOLjzi.js → sparql-C1Srr7cD.js} +0 -0
- /package/dist/assets/{sql-COg8ewmK.js → sql-2k_O5fj7.js} +0 -0
- /package/dist/assets/{st-CIaZtBS_.js → st-DCCCPqfz.js} +0 -0
- /package/dist/assets/{swift-DXiOhUHu.js → swift-Dd8mAfOt.js} +0 -0
- /package/dist/assets/{systemverilog-BTDE6Dr2.js → systemverilog-B0-aZYXu.js} +0 -0
- /package/dist/assets/{tcl-B0zy9NvV.js → tcl-CZAZwPVX.js} +0 -0
- /package/dist/assets/{twig-D594l4Z1.js → twig-D-Ag0tdS.js} +0 -0
- /package/dist/assets/{typespec-XKVjaPqo.js → typespec-B7kTFp0Z.js} +0 -0
- /package/dist/assets/{useWorkspaceMenuKeyboard-Bpy_s69Z.js → useWorkspaceMenuKeyboard-uYZpDxhU.js} +0 -0
- /package/dist/assets/{vb-B2wYoKRV.js → vb-20w1JPum.js} +0 -0
- /package/dist/assets/{wgsl-D0Yf2LbK.js → wgsl-CLJfqFt0.js} +0 -0
- /package/dist/assets/{workspace-working-copy-C3FSR3N6.js → workspace-working-copy-Cfz07cOd.js} +0 -0
|
@@ -1,89 +1,141 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
// Generated by scripts/build-backend-runtime.ts. Do not edit.
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var farming_app_cli_exports = {};
|
|
31
|
+
__export(farming_app_cli_exports, {
|
|
32
|
+
NATIVE_PTY_HOST_ARG: () => NATIVE_PTY_HOST_ARG,
|
|
33
|
+
SERVER_MODE_ARG: () => SERVER_MODE_ARG,
|
|
34
|
+
buildCleanEnvExecArgs: () => buildCleanEnvExecArgs,
|
|
35
|
+
buildCleanEnvExecCommand: () => buildCleanEnvExecCommand,
|
|
36
|
+
buildControlEnv: () => buildControlEnv,
|
|
37
|
+
buildServerEnv: () => buildServerEnv,
|
|
38
|
+
childInvocation: () => childInvocation,
|
|
39
|
+
cleanupFailedDaemonStart: () => cleanupFailedDaemonStart,
|
|
40
|
+
computeNodeHeapMb: () => computeNodeHeapMb,
|
|
41
|
+
defaultConfigDir: () => defaultConfigDir,
|
|
42
|
+
findAvailablePort: () => findAvailablePort,
|
|
43
|
+
parseReviewArgs: () => parseReviewArgs,
|
|
44
|
+
parseServerArgs: () => parseServerArgs,
|
|
45
|
+
readServerProcessIdentity: () => import_server_process_identity.readServerProcessIdentity,
|
|
46
|
+
readServerState: () => readServerState,
|
|
47
|
+
resolveReviewTarget: () => resolveReviewTarget,
|
|
48
|
+
reviewUrl: () => reviewUrl,
|
|
49
|
+
run: () => run,
|
|
50
|
+
serverStartStabilityMs: () => serverStartStabilityMs,
|
|
51
|
+
serverStartTimeoutMs: () => serverStartTimeoutMs,
|
|
52
|
+
serverStateFile: () => serverStateFile,
|
|
53
|
+
serverStopTimeoutMs: () => serverStopTimeoutMs,
|
|
54
|
+
splitControlArgs: () => splitControlArgs,
|
|
55
|
+
stopDaemon: () => stopDaemon,
|
|
56
|
+
waitForDaemonStop: () => waitForDaemonStop
|
|
57
|
+
});
|
|
58
|
+
module.exports = __toCommonJS(farming_app_cli_exports);
|
|
59
|
+
var fs = __toESM(require("fs"));
|
|
60
|
+
var http = __toESM(require("http"));
|
|
61
|
+
var net = __toESM(require("net"));
|
|
62
|
+
var os = __toESM(require("os"));
|
|
63
|
+
var path = __toESM(require("path"));
|
|
64
|
+
var import_url = require("url");
|
|
65
|
+
var import_child_process = require("child_process");
|
|
66
|
+
var import_farming_cli = require("./farming-cli.cjs");
|
|
67
|
+
var import_packaged_codex_acp = require("./acp/packaged-codex-acp.cjs");
|
|
68
|
+
var import_packaged_claude_acp = require("./acp/packaged-claude-acp.cjs");
|
|
69
|
+
var import_server_process_identity = require("./server-process-identity.cjs");
|
|
70
|
+
var storageLayout = __toESM(require("./storage-layout.cjs"));
|
|
71
|
+
const packagedProcess = process;
|
|
72
|
+
function errorField(error, field) {
|
|
73
|
+
return error && typeof error === "object" && field in error ? error[field] : void 0;
|
|
74
|
+
}
|
|
75
|
+
function errorString(error, field = "message") {
|
|
76
|
+
const value = errorField(error, field);
|
|
77
|
+
return value ? String(value) : "";
|
|
78
|
+
}
|
|
79
|
+
const SERVER_MODE_ARG = "--farming-server";
|
|
80
|
+
const SERVER_MODE_ENV = "FARMING_RUN_SERVER";
|
|
81
|
+
const NATIVE_PTY_HOST_ARG = "--native-pty-host";
|
|
82
|
+
const USAGE_HISTORY_SMOKE_ARG = "--farming-usage-history-smoke";
|
|
83
|
+
const DEFAULT_PORT = "6694";
|
|
84
|
+
const DEFAULT_BASE_PATH = "/farming";
|
|
85
|
+
const DEFAULT_SERVER_START_TIMEOUT_MS = 3e4;
|
|
86
|
+
const DEFAULT_SERVER_START_STABILITY_MS = 1500;
|
|
87
|
+
const DEFAULT_SERVER_STOP_TIMEOUT_MS = 3e4;
|
|
28
88
|
const SERVER_STOP_POLL_MS = 100;
|
|
29
|
-
const SERVER_COMMANDS = new Set([
|
|
30
|
-
const CONTROL_COMMANDS = new Set([
|
|
31
|
-
const SERVER_BACKED_CONTROL_COMMANDS = new Set([
|
|
32
|
-
|
|
89
|
+
const SERVER_COMMANDS = /* @__PURE__ */ new Set(["start", "serve", "daemon", "stop", "status", "logs", "url", "help"]);
|
|
90
|
+
const CONTROL_COMMANDS = /* @__PURE__ */ new Set(["skills", "capabilities", "list", "spawn", "output", "send", "kill"]);
|
|
91
|
+
const SERVER_BACKED_CONTROL_COMMANDS = /* @__PURE__ */ new Set(["capabilities", "list", "spawn", "output", "send", "kill"]);
|
|
33
92
|
function defaultConfigDir(env = process.env) {
|
|
34
93
|
return storageLayout.farmingConfigDir(env);
|
|
35
94
|
}
|
|
36
|
-
|
|
37
95
|
function normalizeBasePath(basePath) {
|
|
38
|
-
|
|
39
|
-
|
|
96
|
+
const value = String(basePath || "");
|
|
97
|
+
if (!value || value === "/") return "";
|
|
98
|
+
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
40
99
|
}
|
|
41
|
-
|
|
42
|
-
function routePath(basePath, suffix = '') {
|
|
100
|
+
function routePath(basePath, suffix = "") {
|
|
43
101
|
const normalizedBase = normalizeBasePath(basePath);
|
|
44
|
-
const normalizedSuffix = suffix.startsWith(
|
|
102
|
+
const normalizedSuffix = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
45
103
|
return normalizedBase ? `${normalizedBase}${normalizedSuffix}` : normalizedSuffix;
|
|
46
104
|
}
|
|
47
|
-
|
|
48
105
|
function quoteShellArg(arg) {
|
|
49
106
|
return `'${String(arg).replace(/'/g, `'\\''`)}'`;
|
|
50
107
|
}
|
|
51
|
-
|
|
52
108
|
function buildCleanEnvExecCommand(env, command, args = []) {
|
|
53
|
-
const parts = [
|
|
54
|
-
return parts.map(quoteShellArg).join(
|
|
109
|
+
const parts = ["/usr/bin/env", ...buildCleanEnvExecArgs(env, command, args)];
|
|
110
|
+
return parts.map(quoteShellArg).join(" ");
|
|
55
111
|
}
|
|
56
|
-
|
|
57
112
|
function buildCleanEnvExecArgs(env, command, args = []) {
|
|
58
|
-
const parts = [
|
|
113
|
+
const parts = ["-i"];
|
|
59
114
|
Object.entries(env || {}).forEach(([key, value]) => {
|
|
60
115
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) return;
|
|
61
|
-
if (value ===
|
|
116
|
+
if (value === void 0 || value === null) return;
|
|
62
117
|
parts.push(`${key}=${String(value)}`);
|
|
63
118
|
});
|
|
64
119
|
parts.push(command, ...args);
|
|
65
120
|
return parts;
|
|
66
121
|
}
|
|
67
|
-
|
|
68
122
|
function readMemoryLimitBytes() {
|
|
69
123
|
const candidates = [
|
|
70
|
-
|
|
71
|
-
|
|
124
|
+
"/sys/fs/cgroup/memory.max",
|
|
125
|
+
"/sys/fs/cgroup/memory/memory.limit_in_bytes"
|
|
72
126
|
];
|
|
73
127
|
for (const file of candidates) {
|
|
74
128
|
try {
|
|
75
|
-
const raw = fs.readFileSync(file,
|
|
76
|
-
if (raw && raw !==
|
|
129
|
+
const raw = fs.readFileSync(file, "utf8").trim();
|
|
130
|
+
if (raw && raw !== "max") {
|
|
77
131
|
const value = Number(raw);
|
|
78
|
-
if (Number.isFinite(value) && value > 0 && value <
|
|
132
|
+
if (Number.isFinite(value) && value > 0 && value < 9e18) return value;
|
|
79
133
|
}
|
|
80
134
|
} catch {
|
|
81
|
-
// Ignore missing cgroup files on macOS and non-container Linux hosts.
|
|
82
135
|
}
|
|
83
136
|
}
|
|
84
137
|
return os.totalmem();
|
|
85
138
|
}
|
|
86
|
-
|
|
87
139
|
function computeNodeHeapMb() {
|
|
88
140
|
const limitMb = Math.floor(readMemoryLimitBytes() / 1024 / 1024);
|
|
89
141
|
if (!Number.isFinite(limitMb) || limitMb <= 0) return 4096;
|
|
@@ -91,165 +143,146 @@ function computeNodeHeapMb() {
|
|
|
91
143
|
if (limitMb <= 8192) return Math.max(512, limitMb - 1024);
|
|
92
144
|
return Math.max(512, Math.floor(limitMb * 0.9));
|
|
93
145
|
}
|
|
94
|
-
|
|
95
146
|
function appendNodeOption(existing, option) {
|
|
96
|
-
const value = String(existing ||
|
|
147
|
+
const value = String(existing || "").trim();
|
|
97
148
|
return value ? `${value} ${option}` : option;
|
|
98
149
|
}
|
|
99
|
-
|
|
100
150
|
function buildServerEnv(overrides = {}, baseEnv = process.env) {
|
|
101
151
|
const env = { ...baseEnv, ...overrides };
|
|
102
152
|
delete env.PKG_EXECPATH;
|
|
103
|
-
if (!
|
|
153
|
+
if (!packagedProcess.pkg && !env.FARMING_MANAGED_PACKAGE_ROOT) {
|
|
104
154
|
try {
|
|
105
|
-
env.FARMING_MANAGED_PACKAGE_ROOT = fs.realpathSync(path.join(__dirname,
|
|
155
|
+
env.FARMING_MANAGED_PACKAGE_ROOT = fs.realpathSync(path.join(__dirname, ".."));
|
|
106
156
|
} catch {
|
|
107
|
-
// npm update verification will remain unavailable when the package root cannot be proven.
|
|
108
157
|
}
|
|
109
158
|
}
|
|
110
|
-
const cliBinDir =
|
|
159
|
+
const cliBinDir = packagedProcess.pkg ? path.dirname(process.execPath) : path.join(__dirname, "..", "bin");
|
|
111
160
|
env.PORT = String(env.FARMING_PORT || env.PORT || DEFAULT_PORT);
|
|
112
161
|
env.FARMING_BASE_PATH = env.FARMING_BASE_PATH || DEFAULT_BASE_PATH;
|
|
113
162
|
env.FARMING_CONFIG_DIR = env.FARMING_CONFIG_DIR || defaultConfigDir(env);
|
|
114
|
-
if (
|
|
115
|
-
env.FARMING_PACKAGED_RUNTIME =
|
|
163
|
+
if (packagedProcess.pkg || env.FARMING_PACKAGED_RUNTIME === "1") {
|
|
164
|
+
env.FARMING_PACKAGED_RUNTIME = "1";
|
|
116
165
|
} else {
|
|
117
166
|
delete env.FARMING_PACKAGED_RUNTIME;
|
|
118
167
|
}
|
|
119
168
|
env.FARMING_NODE_BIN = env.FARMING_NODE_BIN || process.execPath;
|
|
120
169
|
env.FARMING_CLI_BIN_DIR = env.FARMING_CLI_BIN_DIR || cliBinDir;
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const heapMb = heapSetting === 'auto' ? computeNodeHeapMb() : Number(heapSetting);
|
|
170
|
+
const heapSetting = env.FARMING_NODE_MAX_OLD_SPACE_SIZE || "auto";
|
|
171
|
+
const hasHeapOption = /(?:^|\s)--max-old-space-size(?:=|\s|$)/.test(env.NODE_OPTIONS || "");
|
|
172
|
+
if (!hasHeapOption && !["0", "off", "false", "OFF", "FALSE"].includes(heapSetting)) {
|
|
173
|
+
const heapMb = heapSetting === "auto" ? computeNodeHeapMb() : Number(heapSetting);
|
|
126
174
|
if (Number.isFinite(heapMb) && heapMb > 0) {
|
|
127
175
|
env.NODE_OPTIONS = appendNodeOption(env.NODE_OPTIONS, `--max-old-space-size=${Math.floor(heapMb)}`);
|
|
128
176
|
env.FARMING_EFFECTIVE_NODE_HEAP_MB = String(Math.floor(heapMb));
|
|
129
177
|
}
|
|
130
178
|
}
|
|
131
|
-
|
|
132
179
|
return env;
|
|
133
180
|
}
|
|
134
|
-
|
|
135
181
|
function parseServerArgs(argv) {
|
|
136
182
|
const options = {
|
|
137
|
-
command: argv[0] && SERVER_COMMANDS.has(argv[0]) ? argv[0] :
|
|
183
|
+
command: argv[0] && SERVER_COMMANDS.has(argv[0]) ? argv[0] : "start",
|
|
138
184
|
env: {},
|
|
139
|
-
portExplicit: false
|
|
185
|
+
portExplicit: false
|
|
140
186
|
};
|
|
141
187
|
const rest = options.command === argv[0] ? argv.slice(1) : argv;
|
|
142
|
-
|
|
143
188
|
for (let i = 0; i < rest.length; i++) {
|
|
144
189
|
const arg = rest[i];
|
|
145
190
|
const readValue = (name) => {
|
|
146
191
|
const value = rest[i + 1];
|
|
147
|
-
if (!value || value.startsWith(
|
|
192
|
+
if (!value || value.startsWith("--")) throw new Error(`${name} requires a value`);
|
|
148
193
|
i++;
|
|
149
194
|
return value;
|
|
150
195
|
};
|
|
151
|
-
|
|
152
|
-
if (arg === '--port') {
|
|
196
|
+
if (arg === "--port") {
|
|
153
197
|
options.env.PORT = readValue(arg);
|
|
154
198
|
options.portExplicit = true;
|
|
155
|
-
} else if (arg.startsWith(
|
|
156
|
-
options.env.PORT = arg.slice(
|
|
199
|
+
} else if (arg.startsWith("--port=")) {
|
|
200
|
+
options.env.PORT = arg.slice("--port=".length);
|
|
157
201
|
options.portExplicit = true;
|
|
158
|
-
} else if (arg ===
|
|
202
|
+
} else if (arg === "--base-path") {
|
|
159
203
|
options.env.FARMING_BASE_PATH = readValue(arg);
|
|
160
|
-
} else if (arg.startsWith(
|
|
161
|
-
options.env.FARMING_BASE_PATH = arg.slice(
|
|
162
|
-
} else if (arg ===
|
|
204
|
+
} else if (arg.startsWith("--base-path=")) {
|
|
205
|
+
options.env.FARMING_BASE_PATH = arg.slice("--base-path=".length);
|
|
206
|
+
} else if (arg === "--config-dir") {
|
|
163
207
|
options.env.FARMING_CONFIG_DIR = readValue(arg);
|
|
164
|
-
} else if (arg.startsWith(
|
|
165
|
-
options.env.FARMING_CONFIG_DIR = arg.slice(
|
|
166
|
-
} else if (arg ===
|
|
208
|
+
} else if (arg.startsWith("--config-dir=")) {
|
|
209
|
+
options.env.FARMING_CONFIG_DIR = arg.slice("--config-dir=".length);
|
|
210
|
+
} else if (arg === "--home") {
|
|
167
211
|
options.env.HOME = readValue(arg);
|
|
168
|
-
} else if (arg.startsWith(
|
|
169
|
-
options.env.HOME = arg.slice(
|
|
170
|
-
} else if (arg ===
|
|
171
|
-
options.env.FARMING_DISABLE_AUTH =
|
|
172
|
-
} else if (arg ===
|
|
173
|
-
options.command =
|
|
212
|
+
} else if (arg.startsWith("--home=")) {
|
|
213
|
+
options.env.HOME = arg.slice("--home=".length);
|
|
214
|
+
} else if (arg === "--no-auth") {
|
|
215
|
+
options.env.FARMING_DISABLE_AUTH = "1";
|
|
216
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
217
|
+
options.command = "help";
|
|
174
218
|
} else {
|
|
175
219
|
throw new Error(`Unknown option: ${arg}`);
|
|
176
220
|
}
|
|
177
221
|
}
|
|
178
|
-
|
|
179
222
|
return options;
|
|
180
223
|
}
|
|
181
|
-
|
|
182
224
|
function parseSharedAppOption(arg, rest, index, env) {
|
|
183
225
|
const readValue = (name) => {
|
|
184
226
|
const value = rest[index + 1];
|
|
185
|
-
if (!value || value.startsWith(
|
|
227
|
+
if (!value || value.startsWith("--")) throw new Error(`${name} requires a value`);
|
|
186
228
|
return value;
|
|
187
229
|
};
|
|
188
|
-
|
|
189
|
-
if (arg === '--port') {
|
|
230
|
+
if (arg === "--port") {
|
|
190
231
|
env.PORT = readValue(arg);
|
|
191
232
|
return 2;
|
|
192
233
|
}
|
|
193
|
-
if (arg.startsWith(
|
|
194
|
-
env.PORT = arg.slice(
|
|
234
|
+
if (arg.startsWith("--port=")) {
|
|
235
|
+
env.PORT = arg.slice("--port=".length);
|
|
195
236
|
return 1;
|
|
196
237
|
}
|
|
197
|
-
if (arg ===
|
|
238
|
+
if (arg === "--base-path") {
|
|
198
239
|
env.FARMING_BASE_PATH = readValue(arg);
|
|
199
240
|
return 2;
|
|
200
241
|
}
|
|
201
|
-
if (arg.startsWith(
|
|
202
|
-
env.FARMING_BASE_PATH = arg.slice(
|
|
242
|
+
if (arg.startsWith("--base-path=")) {
|
|
243
|
+
env.FARMING_BASE_PATH = arg.slice("--base-path=".length);
|
|
203
244
|
return 1;
|
|
204
245
|
}
|
|
205
|
-
if (arg ===
|
|
246
|
+
if (arg === "--config-dir") {
|
|
206
247
|
env.FARMING_CONFIG_DIR = readValue(arg);
|
|
207
248
|
return 2;
|
|
208
249
|
}
|
|
209
|
-
if (arg.startsWith(
|
|
210
|
-
env.FARMING_CONFIG_DIR = arg.slice(
|
|
250
|
+
if (arg.startsWith("--config-dir=")) {
|
|
251
|
+
env.FARMING_CONFIG_DIR = arg.slice("--config-dir=".length);
|
|
211
252
|
return 1;
|
|
212
253
|
}
|
|
213
|
-
if (arg ===
|
|
254
|
+
if (arg === "--home") {
|
|
214
255
|
env.HOME = readValue(arg);
|
|
215
256
|
return 2;
|
|
216
257
|
}
|
|
217
|
-
if (arg.startsWith(
|
|
218
|
-
env.HOME = arg.slice(
|
|
258
|
+
if (arg.startsWith("--home=")) {
|
|
259
|
+
env.HOME = arg.slice("--home=".length);
|
|
219
260
|
return 1;
|
|
220
261
|
}
|
|
221
|
-
if (arg ===
|
|
222
|
-
env.FARMING_DISABLE_AUTH =
|
|
262
|
+
if (arg === "--no-auth") {
|
|
263
|
+
env.FARMING_DISABLE_AUTH = "1";
|
|
223
264
|
return 1;
|
|
224
265
|
}
|
|
225
266
|
return 0;
|
|
226
267
|
}
|
|
227
|
-
|
|
228
268
|
function isPortOverrideExplicit(overrides = {}, baseEnv = process.env) {
|
|
229
269
|
return Boolean(
|
|
230
|
-
overrides.PORT
|
|
231
|
-
|| overrides.FARMING_PORT
|
|
232
|
-
|| baseEnv.PORT
|
|
233
|
-
|| baseEnv.FARMING_PORT
|
|
270
|
+
overrides.PORT || overrides.FARMING_PORT || baseEnv.PORT || baseEnv.FARMING_PORT
|
|
234
271
|
);
|
|
235
272
|
}
|
|
236
|
-
|
|
237
273
|
function canListenOnHost(port, host) {
|
|
238
274
|
return new Promise((resolve) => {
|
|
239
275
|
const server = net.createServer();
|
|
240
|
-
server.once(
|
|
241
|
-
server.once(
|
|
276
|
+
server.once("error", () => resolve(false));
|
|
277
|
+
server.once("listening", () => {
|
|
242
278
|
server.close(() => resolve(true));
|
|
243
279
|
});
|
|
244
280
|
server.listen({ host, port });
|
|
245
281
|
});
|
|
246
282
|
}
|
|
247
|
-
|
|
248
283
|
async function canListenOnPort(port) {
|
|
249
|
-
return
|
|
250
|
-
&& (await canListenOnHost(port, '0.0.0.0'));
|
|
284
|
+
return await canListenOnHost(port, "127.0.0.1") && await canListenOnHost(port, "0.0.0.0");
|
|
251
285
|
}
|
|
252
|
-
|
|
253
286
|
async function findAvailablePort(startPort = Number(DEFAULT_PORT), maxAttempts = 50) {
|
|
254
287
|
for (let offset = 0; offset < maxAttempts; offset++) {
|
|
255
288
|
const port = startPort + offset;
|
|
@@ -257,26 +290,22 @@ async function findAvailablePort(startPort = Number(DEFAULT_PORT), maxAttempts =
|
|
|
257
290
|
}
|
|
258
291
|
throw new Error(`No available port found from ${startPort} to ${startPort + maxAttempts - 1}`);
|
|
259
292
|
}
|
|
260
|
-
|
|
261
293
|
async function adaptServerPort(env, parsed) {
|
|
262
294
|
if (parsed.portExplicit || isPortOverrideExplicit(parsed.env, process.env)) return env;
|
|
263
295
|
const port = await findAvailablePort(Number(env.PORT || DEFAULT_PORT));
|
|
264
296
|
if (String(port) !== String(env.PORT)) env.PORT = String(port);
|
|
265
297
|
return env;
|
|
266
298
|
}
|
|
267
|
-
|
|
268
299
|
function splitControlArgs(argv) {
|
|
269
300
|
const command = argv[0];
|
|
270
301
|
const env = {};
|
|
271
302
|
const controlArgs = [command];
|
|
272
|
-
|
|
273
303
|
for (let i = 1; i < argv.length; i++) {
|
|
274
304
|
const arg = argv[i];
|
|
275
|
-
if (arg ===
|
|
305
|
+
if (arg === "--") {
|
|
276
306
|
controlArgs.push(...argv.slice(i));
|
|
277
307
|
break;
|
|
278
308
|
}
|
|
279
|
-
|
|
280
309
|
const consumed = parseSharedAppOption(arg, argv, i, env);
|
|
281
310
|
if (consumed > 0) {
|
|
282
311
|
i += consumed - 1;
|
|
@@ -284,106 +313,95 @@ function splitControlArgs(argv) {
|
|
|
284
313
|
}
|
|
285
314
|
controlArgs.push(arg);
|
|
286
315
|
}
|
|
287
|
-
|
|
288
316
|
return { argv: controlArgs, env };
|
|
289
317
|
}
|
|
290
|
-
|
|
291
318
|
function parseReviewArgs(argv) {
|
|
292
319
|
const options = {
|
|
293
|
-
branch:
|
|
320
|
+
branch: "",
|
|
294
321
|
env: {},
|
|
295
322
|
noOpen: false,
|
|
296
323
|
portExplicit: false,
|
|
297
|
-
positional: []
|
|
324
|
+
positional: []
|
|
298
325
|
};
|
|
299
326
|
for (let index = 0; index < argv.length; index++) {
|
|
300
327
|
const arg = argv[index];
|
|
301
328
|
const readValue = (name) => {
|
|
302
329
|
const value = argv[index + 1];
|
|
303
|
-
if (!value || value.startsWith(
|
|
330
|
+
if (!value || value.startsWith("--")) throw new Error(`${name} requires a value`);
|
|
304
331
|
index++;
|
|
305
332
|
return value;
|
|
306
333
|
};
|
|
307
|
-
if (arg ===
|
|
334
|
+
if (arg === "--branch") {
|
|
308
335
|
options.branch = readValue(arg);
|
|
309
336
|
continue;
|
|
310
337
|
}
|
|
311
|
-
if (arg.startsWith(
|
|
312
|
-
options.branch = arg.slice(
|
|
338
|
+
if (arg.startsWith("--branch=")) {
|
|
339
|
+
options.branch = arg.slice("--branch=".length);
|
|
313
340
|
continue;
|
|
314
341
|
}
|
|
315
|
-
if (arg ===
|
|
342
|
+
if (arg === "--no-open") {
|
|
316
343
|
options.noOpen = true;
|
|
317
344
|
continue;
|
|
318
345
|
}
|
|
319
346
|
const consumed = parseSharedAppOption(arg, argv, index, options.env);
|
|
320
347
|
if (consumed > 0) {
|
|
321
|
-
if (arg ===
|
|
348
|
+
if (arg === "--port" || arg.startsWith("--port=")) options.portExplicit = true;
|
|
322
349
|
index += consumed - 1;
|
|
323
350
|
continue;
|
|
324
351
|
}
|
|
325
|
-
if (arg.startsWith(
|
|
352
|
+
if (arg.startsWith("--")) throw new Error(`Unknown review option: ${arg}`);
|
|
326
353
|
options.positional.push(arg);
|
|
327
354
|
}
|
|
328
355
|
if (options.positional.length !== 3) {
|
|
329
|
-
throw new Error(
|
|
356
|
+
throw new Error("Usage: farming review <git-dir> <old-revision> <new-revision|now> [--branch <branch>]");
|
|
330
357
|
}
|
|
331
358
|
const [gitDir, base, head] = options.positional;
|
|
332
|
-
if (base ===
|
|
359
|
+
if (base === "now") throw new Error("the old revision cannot be now");
|
|
333
360
|
return { ...options, base, gitDir, head };
|
|
334
361
|
}
|
|
335
|
-
|
|
336
362
|
function runGit(root, args) {
|
|
337
363
|
try {
|
|
338
|
-
return execFileSync(
|
|
364
|
+
return (0, import_child_process.execFileSync)("git", ["-C", root, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
339
365
|
} catch (error) {
|
|
340
|
-
const detail = String(error
|
|
341
|
-
throw new Error(detail || `git ${args.join(
|
|
366
|
+
const detail = String(errorField(error, "stderr") || errorString(error) || "").trim();
|
|
367
|
+
throw new Error(detail || `git ${args.join(" ")} failed`, { cause: error });
|
|
342
368
|
}
|
|
343
369
|
}
|
|
344
|
-
|
|
345
370
|
function resolveReviewTarget(parsed) {
|
|
346
371
|
const requestedRoot = path.resolve(parsed.gitDir);
|
|
347
|
-
const root = runGit(requestedRoot, [
|
|
348
|
-
const branch = parsed.branch || runGit(root, [
|
|
349
|
-
runGit(root, [
|
|
372
|
+
const root = runGit(requestedRoot, ["rev-parse", "--show-toplevel"]);
|
|
373
|
+
const branch = parsed.branch || runGit(root, ["symbolic-ref", "--quiet", "--short", "HEAD"]);
|
|
374
|
+
runGit(root, ["rev-parse", "--verify", `${branch}^{commit}`]);
|
|
350
375
|
const resolveRevision = (revision) => {
|
|
351
|
-
if (revision ===
|
|
352
|
-
const branchRelative = revision ===
|
|
353
|
-
|
|
354
|
-
: revision.startsWith('HEAD~') || revision.startsWith('HEAD^')
|
|
355
|
-
? `${branch}${revision.slice('HEAD'.length)}`
|
|
356
|
-
: revision;
|
|
357
|
-
return runGit(root, ['rev-parse', '--verify', `${branchRelative}^{commit}`]);
|
|
376
|
+
if (revision === "now") return "now";
|
|
377
|
+
const branchRelative = revision === "HEAD" ? branch : revision.startsWith("HEAD~") || revision.startsWith("HEAD^") ? `${branch}${revision.slice("HEAD".length)}` : revision;
|
|
378
|
+
return runGit(root, ["rev-parse", "--verify", `${branchRelative}^{commit}`]);
|
|
358
379
|
};
|
|
359
380
|
return {
|
|
360
381
|
base: resolveRevision(parsed.base),
|
|
361
382
|
branch,
|
|
362
383
|
head: resolveRevision(parsed.head),
|
|
363
|
-
root
|
|
384
|
+
root
|
|
364
385
|
};
|
|
365
386
|
}
|
|
366
|
-
|
|
367
387
|
function reviewUrl(env, target) {
|
|
368
|
-
const params = new URLSearchParams({
|
|
388
|
+
const params = new import_url.URLSearchParams({
|
|
369
389
|
base: target.base,
|
|
370
390
|
head: target.head,
|
|
371
|
-
root: target.root
|
|
391
|
+
root: target.root
|
|
372
392
|
});
|
|
373
|
-
const token = [
|
|
374
|
-
if (token) params.set(
|
|
375
|
-
return `${entryUrl(env,
|
|
393
|
+
const token = ["1", "true", "yes", "on"].includes(String(env.FARMING_DISABLE_AUTH || "").toLowerCase()) ? "" : readTokenForEnv(env);
|
|
394
|
+
if (token) params.set("token", token);
|
|
395
|
+
return `${entryUrl(env, "127.0.0.1")}/review?${params.toString()}`;
|
|
376
396
|
}
|
|
377
|
-
|
|
378
397
|
function openBrowser(url) {
|
|
379
|
-
const command = process.platform ===
|
|
380
|
-
const child = spawn(command, [url], { detached: true, stdio:
|
|
398
|
+
const command = process.platform === "darwin" ? "open" : "xdg-open";
|
|
399
|
+
const child = (0, import_child_process.spawn)(command, [url], { detached: true, stdio: "ignore" });
|
|
381
400
|
child.unref();
|
|
382
401
|
}
|
|
383
|
-
|
|
384
402
|
async function runReview(parsed) {
|
|
385
403
|
const target = resolveReviewTarget(parsed);
|
|
386
|
-
const serverParsed = { command:
|
|
404
|
+
const serverParsed = { command: "daemon", env: parsed.env, portExplicit: parsed.portExplicit };
|
|
387
405
|
const code = await startDaemon(serverParsed);
|
|
388
406
|
if (code) return code;
|
|
389
407
|
const env = buildControlEnv(parsed.env);
|
|
@@ -392,7 +410,6 @@ async function runReview(parsed) {
|
|
|
392
410
|
if (!parsed.noOpen) openBrowser(url);
|
|
393
411
|
return 0;
|
|
394
412
|
}
|
|
395
|
-
|
|
396
413
|
function buildControlEnv(overrides = {}, baseEnv = process.env) {
|
|
397
414
|
const env = buildServerEnv(overrides, baseEnv);
|
|
398
415
|
if (!isPortOverrideExplicit(overrides, baseEnv) && !env.FARMING_CONTROL_URL) {
|
|
@@ -400,87 +417,75 @@ function buildControlEnv(overrides = {}, baseEnv = process.env) {
|
|
|
400
417
|
if (state.port) env.PORT = String(state.port);
|
|
401
418
|
if (state.basePath) env.FARMING_BASE_PATH = state.basePath;
|
|
402
419
|
}
|
|
403
|
-
env.FARMING_CONTROL_URL = env.FARMING_CONTROL_URL || entryUrl(env,
|
|
420
|
+
env.FARMING_CONTROL_URL = env.FARMING_CONTROL_URL || entryUrl(env, "127.0.0.1");
|
|
404
421
|
env.FARMING_TOKEN_FILE = env.FARMING_TOKEN_FILE || storageLayout.sessionTokenFile(env.FARMING_CONFIG_DIR);
|
|
405
422
|
return env;
|
|
406
423
|
}
|
|
407
|
-
|
|
408
424
|
async function runServerBackedControlCli(argv) {
|
|
409
425
|
const parsed = splitControlArgs(argv);
|
|
410
426
|
const env = buildControlEnv(parsed.env);
|
|
411
427
|
const forwardedKeys = [
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
428
|
+
"FARMING_CONFIG_DIR",
|
|
429
|
+
"FARMING_CONTROL_URL",
|
|
430
|
+
"FARMING_TOKEN_FILE",
|
|
431
|
+
"FARMING_DISABLE_AUTH",
|
|
432
|
+
"FARMING_BASE_PATH",
|
|
433
|
+
"HOME",
|
|
434
|
+
"PORT"
|
|
419
435
|
];
|
|
420
|
-
const previous = new Map(forwardedKeys.map(key => [key, process.env[key]]));
|
|
421
|
-
|
|
436
|
+
const previous = new Map(forwardedKeys.map((key) => [key, process.env[key]]));
|
|
422
437
|
forwardedKeys.forEach((key) => {
|
|
423
|
-
if (env[key] ===
|
|
438
|
+
if (env[key] === void 0) delete process.env[key];
|
|
424
439
|
else process.env[key] = env[key];
|
|
425
440
|
});
|
|
426
|
-
|
|
427
441
|
try {
|
|
428
|
-
return await
|
|
442
|
+
return await (0, import_farming_cli.run)(parsed.argv);
|
|
429
443
|
} finally {
|
|
430
444
|
forwardedKeys.forEach((key) => {
|
|
431
445
|
const value = previous.get(key);
|
|
432
|
-
if (value ===
|
|
446
|
+
if (value === void 0) delete process.env[key];
|
|
433
447
|
else process.env[key] = value;
|
|
434
448
|
});
|
|
435
449
|
}
|
|
436
450
|
}
|
|
437
|
-
|
|
438
451
|
function childInvocation(env = process.env) {
|
|
439
|
-
if (
|
|
440
|
-
// Spawn env directly so it execs the packaged binary in-place. A shell
|
|
441
|
-
// wrapper may keep its own PID while the listener belongs to a child,
|
|
442
|
-
// making daemon ownership impossible to prove on Linux.
|
|
452
|
+
if (packagedProcess.pkg) {
|
|
443
453
|
return {
|
|
444
|
-
command:
|
|
454
|
+
command: "/usr/bin/env",
|
|
445
455
|
// FARMING_RUN_SERVER selects the embedded server entry. Do not append a
|
|
446
456
|
// sentinel argument: pkg may interpret it as an external script path.
|
|
447
|
-
args: buildCleanEnvExecArgs(env, process.execPath)
|
|
457
|
+
args: buildCleanEnvExecArgs(env, process.execPath)
|
|
448
458
|
};
|
|
449
459
|
}
|
|
450
460
|
const nodePath = env.FARMING_NODE_BIN || process.execPath;
|
|
451
461
|
if (env.FARMING_NODE_LD && env.FARMING_NODE_LIBRARY_PATH) {
|
|
452
462
|
return {
|
|
453
463
|
command: env.FARMING_NODE_LD,
|
|
454
|
-
args: [
|
|
464
|
+
args: ["--library-path", env.FARMING_NODE_LIBRARY_PATH, nodePath, __filename]
|
|
455
465
|
};
|
|
456
466
|
}
|
|
457
467
|
return { command: nodePath, args: [__filename] };
|
|
458
468
|
}
|
|
459
|
-
|
|
460
469
|
function ensureConfigDir(configDir) {
|
|
461
470
|
fs.mkdirSync(configDir, { recursive: true });
|
|
462
471
|
}
|
|
463
|
-
|
|
464
472
|
function pidFile(configDir) {
|
|
465
473
|
return storageLayout.serverPidFile(configDir);
|
|
466
474
|
}
|
|
467
|
-
|
|
468
475
|
function serverStateFile(configDir) {
|
|
469
476
|
return storageLayout.serverStateFile(configDir);
|
|
470
477
|
}
|
|
471
|
-
|
|
472
478
|
function logFile(configDir) {
|
|
473
479
|
return storageLayout.serverLogFile(configDir);
|
|
474
480
|
}
|
|
475
|
-
|
|
476
481
|
function readServerState(configDir) {
|
|
477
482
|
try {
|
|
478
|
-
|
|
483
|
+
const value = JSON.parse(fs.readFileSync(serverStateFile(configDir), "utf8"));
|
|
484
|
+
return value && typeof value === "object" ? value : {};
|
|
479
485
|
} catch {
|
|
480
486
|
return {};
|
|
481
487
|
}
|
|
482
488
|
}
|
|
483
|
-
|
|
484
489
|
function canonicalConfigDir(configDir) {
|
|
485
490
|
try {
|
|
486
491
|
return fs.realpathSync.native(configDir);
|
|
@@ -488,8 +493,7 @@ function canonicalConfigDir(configDir) {
|
|
|
488
493
|
return path.resolve(configDir);
|
|
489
494
|
}
|
|
490
495
|
}
|
|
491
|
-
|
|
492
|
-
function writeServerState(configDir, env, pid, processIdentity, phase = 'running') {
|
|
496
|
+
function writeServerState(configDir, env, pid, processIdentity, phase = "running") {
|
|
493
497
|
const state = {
|
|
494
498
|
pid,
|
|
495
499
|
port: Number(env.PORT || DEFAULT_PORT),
|
|
@@ -497,54 +501,50 @@ function writeServerState(configDir, env, pid, processIdentity, phase = 'running
|
|
|
497
501
|
configDir: canonicalConfigDir(configDir),
|
|
498
502
|
processIdentity,
|
|
499
503
|
phase,
|
|
500
|
-
updatedAt: new Date().toISOString()
|
|
504
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
501
505
|
};
|
|
502
506
|
const target = serverStateFile(configDir);
|
|
503
507
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
504
|
-
fs.writeFileSync(temporary, `${JSON.stringify(state, null, 2)}
|
|
508
|
+
fs.writeFileSync(temporary, `${JSON.stringify(state, null, 2)}
|
|
509
|
+
`, { mode: 384 });
|
|
505
510
|
fs.renameSync(temporary, target);
|
|
506
511
|
}
|
|
507
|
-
|
|
508
512
|
function processLooksLikeFarmingServer(pid) {
|
|
509
|
-
let environment =
|
|
513
|
+
let environment = "";
|
|
510
514
|
try {
|
|
511
|
-
environment = fs.readFileSync(`/proc/${pid}/environ`,
|
|
515
|
+
environment = fs.readFileSync(`/proc/${pid}/environ`, "utf8").replace(/\0/g, " ");
|
|
512
516
|
} catch {
|
|
513
517
|
try {
|
|
514
|
-
environment = execFileSync(
|
|
515
|
-
|
|
516
|
-
[
|
|
517
|
-
{ encoding:
|
|
518
|
+
environment = (0, import_child_process.execFileSync)(
|
|
519
|
+
"/bin/ps",
|
|
520
|
+
["eww", "-p", String(pid), "-o", "command="],
|
|
521
|
+
{ encoding: "utf8", timeout: 1e3, maxBuffer: 1024 * 1024 }
|
|
518
522
|
);
|
|
519
523
|
} catch {
|
|
520
|
-
environment =
|
|
524
|
+
environment = "";
|
|
521
525
|
}
|
|
522
526
|
}
|
|
523
527
|
if (/(?:^|\s)FARMING_RUN_SERVER=1(?:\s|$)/.test(environment)) return true;
|
|
524
528
|
return /(?:^|\s)(?:\S+[/\\])?backend[/\\]server\.js(?:\s|$)/.test(environment);
|
|
525
529
|
}
|
|
526
|
-
|
|
527
530
|
function processHasExactEnvironment(pid, expected) {
|
|
528
531
|
try {
|
|
529
|
-
const entries = fs.readFileSync(`/proc/${pid}/environ`,
|
|
530
|
-
.
|
|
531
|
-
.
|
|
532
|
-
|
|
533
|
-
const separator = entry.indexOf('=');
|
|
534
|
-
return separator < 0 ? [entry, ''] : [entry.slice(0, separator), entry.slice(separator + 1)];
|
|
535
|
-
});
|
|
532
|
+
const entries = fs.readFileSync(`/proc/${pid}/environ`, "utf8").split("\0").filter(Boolean).map((entry) => {
|
|
533
|
+
const separator = entry.indexOf("=");
|
|
534
|
+
return separator < 0 ? [entry, ""] : [entry.slice(0, separator), entry.slice(separator + 1)];
|
|
535
|
+
});
|
|
536
536
|
const environment = new Map(entries);
|
|
537
537
|
return Object.entries(expected).every(([key, value]) => environment.get(key) === String(value));
|
|
538
538
|
} catch {
|
|
539
|
-
if (Object.values(expected).some(value => /\s/.test(String(value)))) return false;
|
|
539
|
+
if (Object.values(expected).some((value) => /\s/.test(String(value)))) return false;
|
|
540
540
|
try {
|
|
541
|
-
const environment = execFileSync(
|
|
542
|
-
|
|
543
|
-
[
|
|
544
|
-
{ encoding:
|
|
541
|
+
const environment = (0, import_child_process.execFileSync)(
|
|
542
|
+
"/bin/ps",
|
|
543
|
+
["eww", "-p", String(pid), "-o", "command="],
|
|
544
|
+
{ encoding: "utf8", timeout: 1e3, maxBuffer: 1024 * 1024 }
|
|
545
545
|
);
|
|
546
546
|
return Object.entries(expected).every(([key, value]) => {
|
|
547
|
-
const escaped = `${key}=${value}`.replace(/[.*+?^${}()|[\]\\]/g,
|
|
547
|
+
const escaped = `${key}=${value}`.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
548
548
|
return new RegExp(`(?:^|\\s)${escaped}(?:\\s|$)`).test(environment);
|
|
549
549
|
});
|
|
550
550
|
} catch {
|
|
@@ -552,80 +552,83 @@ function processHasExactEnvironment(pid, expected) {
|
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
554
|
}
|
|
555
|
-
|
|
556
555
|
function readLegacyServerSettings(configDir, state, pid) {
|
|
557
|
-
const authDisabled = processHasExactEnvironment(pid, { FARMING_DISABLE_AUTH:
|
|
558
|
-
const token = authDisabled ?
|
|
556
|
+
const authDisabled = processHasExactEnvironment(pid, { FARMING_DISABLE_AUTH: "1" });
|
|
557
|
+
const token = authDisabled ? "" : readTokenForEnv({ FARMING_CONFIG_DIR: configDir });
|
|
559
558
|
if (!authDisabled && !token) {
|
|
560
|
-
return Promise.reject(new Error(
|
|
559
|
+
return Promise.reject(new Error("legacy Farming server identity probe requires this config directory token"));
|
|
561
560
|
}
|
|
562
|
-
const requestPath = routePath(state.basePath || DEFAULT_BASE_PATH,
|
|
561
|
+
const requestPath = routePath(state.basePath || DEFAULT_BASE_PATH, "/api/settings");
|
|
563
562
|
return new Promise((resolve, reject) => {
|
|
564
563
|
const req = http.request({
|
|
565
|
-
host:
|
|
564
|
+
host: "127.0.0.1",
|
|
566
565
|
port: Number(state.port),
|
|
567
566
|
path: requestPath,
|
|
568
|
-
method:
|
|
569
|
-
timeout:
|
|
570
|
-
headers: token ? { Cookie: `farming_token=${encodeURIComponent(token)}` } : {}
|
|
571
|
-
}, res => {
|
|
572
|
-
let body =
|
|
573
|
-
res.setEncoding(
|
|
574
|
-
res.on(
|
|
567
|
+
method: "GET",
|
|
568
|
+
timeout: 1e3,
|
|
569
|
+
headers: token ? { Cookie: `farming_token=${encodeURIComponent(token)}` } : {}
|
|
570
|
+
}, (res) => {
|
|
571
|
+
let body = "";
|
|
572
|
+
res.setEncoding("utf8");
|
|
573
|
+
res.on("data", (chunk) => {
|
|
575
574
|
if (body.length <= 64 * 1024) body += chunk;
|
|
576
575
|
});
|
|
577
|
-
res.on(
|
|
576
|
+
res.on("end", () => {
|
|
578
577
|
if (res.statusCode !== 200) {
|
|
579
578
|
reject(new Error(`legacy Farming server identity probe returned HTTP ${res.statusCode || 0}`));
|
|
580
579
|
return;
|
|
581
580
|
}
|
|
582
581
|
try {
|
|
583
582
|
const payload = JSON.parse(body);
|
|
584
|
-
|
|
585
|
-
|
|
583
|
+
const settings = payload && typeof payload === "object" && "settings" in payload ? payload.settings : null;
|
|
584
|
+
if (!settings || typeof settings !== "object") {
|
|
585
|
+
reject(new Error("legacy Farming server identity probe did not return Farming settings"));
|
|
586
586
|
return;
|
|
587
587
|
}
|
|
588
|
-
resolve(
|
|
588
|
+
resolve(settings);
|
|
589
589
|
} catch (error) {
|
|
590
|
-
reject(new Error(
|
|
590
|
+
reject(new Error(
|
|
591
|
+
`legacy Farming server identity probe was invalid: ${errorString(error) || error}`
|
|
592
|
+
));
|
|
591
593
|
}
|
|
592
594
|
});
|
|
593
595
|
});
|
|
594
|
-
req.on(
|
|
595
|
-
req.on(
|
|
596
|
+
req.on("error", reject);
|
|
597
|
+
req.on("timeout", () => req.destroy(new Error("legacy Farming server identity probe timed out")));
|
|
596
598
|
req.end();
|
|
597
599
|
});
|
|
598
600
|
}
|
|
599
|
-
|
|
600
601
|
function processOwnsListeningPort(pid, port) {
|
|
601
602
|
const processId = Number(pid);
|
|
602
603
|
const portNumber = Number(port);
|
|
603
604
|
if (!Number.isSafeInteger(processId) || processId <= 0 || !Number.isInteger(portNumber) || portNumber <= 0) {
|
|
604
605
|
return false;
|
|
605
606
|
}
|
|
606
|
-
if (process.platform ===
|
|
607
|
+
if (process.platform === "linux") {
|
|
607
608
|
try {
|
|
608
|
-
const socketInodes = new Set(
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
609
|
+
const socketInodes = new Set(
|
|
610
|
+
fs.readdirSync(`/proc/${processId}/fd`).flatMap((entry) => {
|
|
611
|
+
try {
|
|
612
|
+
const target = fs.readlinkSync(`/proc/${processId}/fd/${entry}`);
|
|
613
|
+
const match = target.match(/^socket:\[(\d+)\]$/);
|
|
614
|
+
return match ? [match[1]] : [];
|
|
615
|
+
} catch {
|
|
616
|
+
return [];
|
|
617
|
+
}
|
|
618
|
+
})
|
|
619
|
+
);
|
|
620
|
+
const portHex = portNumber.toString(16).toUpperCase().padStart(4, "0");
|
|
621
|
+
for (const table of ["/proc/net/tcp", "/proc/net/tcp6"]) {
|
|
619
622
|
let rows = [];
|
|
620
623
|
try {
|
|
621
|
-
rows = fs.readFileSync(table,
|
|
624
|
+
rows = fs.readFileSync(table, "utf8").trim().split(/\r?\n/).slice(1);
|
|
622
625
|
} catch {
|
|
623
626
|
continue;
|
|
624
627
|
}
|
|
625
|
-
if (rows.some(row => {
|
|
628
|
+
if (rows.some((row) => {
|
|
626
629
|
const fields = row.trim().split(/\s+/);
|
|
627
|
-
const localPort = String(fields[1] ||
|
|
628
|
-
return localPort === portHex && fields[3] ===
|
|
630
|
+
const localPort = String(fields[1] || "").split(":").at(-1);
|
|
631
|
+
return localPort === portHex && fields[3] === "0A" && socketInodes.has(fields[9]);
|
|
629
632
|
})) return true;
|
|
630
633
|
}
|
|
631
634
|
return false;
|
|
@@ -634,63 +637,45 @@ function processOwnsListeningPort(pid, port) {
|
|
|
634
637
|
}
|
|
635
638
|
}
|
|
636
639
|
try {
|
|
637
|
-
const lsof = fs.existsSync(
|
|
638
|
-
const stdout = execFileSync(
|
|
640
|
+
const lsof = fs.existsSync("/usr/sbin/lsof") ? "/usr/sbin/lsof" : "lsof";
|
|
641
|
+
const stdout = (0, import_child_process.execFileSync)(
|
|
639
642
|
lsof,
|
|
640
|
-
[
|
|
641
|
-
{ encoding:
|
|
643
|
+
["-nP", "-a", "-p", String(processId), `-iTCP:${portNumber}`, "-sTCP:LISTEN", "-Fpfn"],
|
|
644
|
+
{ encoding: "utf8", timeout: 1e3, maxBuffer: 64 * 1024 }
|
|
642
645
|
);
|
|
643
|
-
return String(stdout ||
|
|
646
|
+
return String(stdout || "").split(/\r?\n/).some((line) => line.startsWith("n") && line.endsWith(`:${portNumber}`));
|
|
644
647
|
} catch {
|
|
645
648
|
return false;
|
|
646
649
|
}
|
|
647
650
|
}
|
|
648
|
-
|
|
649
651
|
async function assertServerProcessIdentity(configDir, pid, state) {
|
|
650
652
|
const expected = state?.processIdentity;
|
|
651
|
-
if (
|
|
652
|
-
Number(state?.pid) !== pid
|
|
653
|
-
|| canonicalConfigDir(state?.configDir || '') !== canonicalConfigDir(configDir)
|
|
654
|
-
|| !expected
|
|
655
|
-
|| Number(expected.pid) !== pid
|
|
656
|
-
|| !Number.isSafeInteger(Number(expected.processGroupId))
|
|
657
|
-
|| Number(expected.processGroupId) <= 0
|
|
658
|
-
|| !String(expected.startedAt || '').trim()
|
|
659
|
-
) {
|
|
653
|
+
if (Number(state?.pid) !== pid || canonicalConfigDir(typeof state?.configDir === "string" ? state.configDir : "") !== canonicalConfigDir(configDir) || !expected || Number(expected.pid) !== pid || !Number.isSafeInteger(Number(expected.processGroupId)) || Number(expected.processGroupId) <= 0 || !String(expected.startedAt || "").trim()) {
|
|
660
654
|
throw new Error(
|
|
661
|
-
`Refusing to stop Farming PID ${pid}: server control metadata does not contain a matching process identity
|
|
655
|
+
`Refusing to stop Farming PID ${pid}: server control metadata does not contain a matching process identity`
|
|
662
656
|
);
|
|
663
657
|
}
|
|
664
|
-
const current = await readServerProcessIdentity(pid);
|
|
665
|
-
if (!matchingProcessIdentity(expected, current)) {
|
|
658
|
+
const current = await (0, import_server_process_identity.readServerProcessIdentity)(pid);
|
|
659
|
+
if (!current || !(0, import_server_process_identity.matchingProcessIdentity)(expected, current)) {
|
|
666
660
|
throw new Error(
|
|
667
|
-
`Refusing to stop Farming PID ${pid}: the live process identity does not match the server control metadata
|
|
661
|
+
`Refusing to stop Farming PID ${pid}: the live process identity does not match the server control metadata`
|
|
668
662
|
);
|
|
669
663
|
}
|
|
670
|
-
if (state.phase !==
|
|
664
|
+
if (state.phase !== "starting" && !processOwnsListeningPort(pid, Number(state.port))) {
|
|
671
665
|
throw new Error(`Refusing to stop Farming PID ${pid}: the process does not own listening port ${state.port}`);
|
|
672
666
|
}
|
|
673
667
|
return current;
|
|
674
668
|
}
|
|
675
|
-
|
|
676
669
|
async function migrateLegacyServerIdentity(configDir, pid, state) {
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|| Number(state.port) <= 0
|
|
682
|
-
|| Number(state.port) > 65535
|
|
683
|
-
|| !processLooksLikeFarmingServer(pid)
|
|
684
|
-
|| !processHasExactEnvironment(pid, {
|
|
685
|
-
FARMING_CONFIG_DIR: configDir,
|
|
686
|
-
PORT: String(state.port),
|
|
687
|
-
})
|
|
688
|
-
) {
|
|
670
|
+
if (Number(state?.pid) !== pid || canonicalConfigDir(typeof state?.configDir === "string" ? state.configDir : "") !== canonicalConfigDir(configDir) || !Number.isInteger(Number(state?.port)) || Number(state.port) <= 0 || Number(state.port) > 65535 || !processLooksLikeFarmingServer(pid) || !processHasExactEnvironment(pid, {
|
|
671
|
+
FARMING_CONFIG_DIR: configDir,
|
|
672
|
+
PORT: String(state.port)
|
|
673
|
+
})) {
|
|
689
674
|
throw new Error(
|
|
690
|
-
`Refusing to stop Farming PID ${pid}: legacy server control metadata could not prove this process belongs to the config directory
|
|
675
|
+
`Refusing to stop Farming PID ${pid}: legacy server control metadata could not prove this process belongs to the config directory`
|
|
691
676
|
);
|
|
692
677
|
}
|
|
693
|
-
const firstIdentity = await readServerProcessIdentity(pid);
|
|
678
|
+
const firstIdentity = await (0, import_server_process_identity.readServerProcessIdentity)(pid);
|
|
694
679
|
if (!firstIdentity) {
|
|
695
680
|
throw new Error(`Refusing to stop Farming PID ${pid}: the legacy server process identity could not be read`);
|
|
696
681
|
}
|
|
@@ -698,8 +683,8 @@ async function migrateLegacyServerIdentity(configDir, pid, state) {
|
|
|
698
683
|
throw new Error(`Refusing to stop Farming PID ${pid}: the legacy process does not own listening port ${state.port}`);
|
|
699
684
|
}
|
|
700
685
|
await readLegacyServerSettings(configDir, state, pid);
|
|
701
|
-
const stableIdentity = await readServerProcessIdentity(pid);
|
|
702
|
-
if (!matchingProcessIdentity(firstIdentity, stableIdentity) || readPid(configDir) !== pid) {
|
|
686
|
+
const stableIdentity = await (0, import_server_process_identity.readServerProcessIdentity)(pid);
|
|
687
|
+
if (!stableIdentity || !(0, import_server_process_identity.matchingProcessIdentity)(firstIdentity, stableIdentity) || readPid(configDir) !== pid) {
|
|
703
688
|
throw new Error(`Refusing to stop Farming PID ${pid}: the legacy server process identity changed during verification`);
|
|
704
689
|
}
|
|
705
690
|
fs.writeFileSync(serverStateFile(configDir), `${JSON.stringify({
|
|
@@ -707,100 +692,91 @@ async function migrateLegacyServerIdentity(configDir, pid, state) {
|
|
|
707
692
|
pid,
|
|
708
693
|
configDir: canonicalConfigDir(configDir),
|
|
709
694
|
processIdentity: stableIdentity,
|
|
710
|
-
identityMigratedAt: new Date().toISOString()
|
|
711
|
-
}, null, 2)}
|
|
695
|
+
identityMigratedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
696
|
+
}, null, 2)}
|
|
697
|
+
`);
|
|
712
698
|
return stableIdentity;
|
|
713
699
|
}
|
|
714
|
-
|
|
715
700
|
function readPid(configDir) {
|
|
716
701
|
try {
|
|
717
|
-
return Number(fs.readFileSync(pidFile(configDir),
|
|
702
|
+
return Number(fs.readFileSync(pidFile(configDir), "utf8").trim());
|
|
718
703
|
} catch {
|
|
719
704
|
return 0;
|
|
720
705
|
}
|
|
721
706
|
}
|
|
722
|
-
|
|
723
707
|
function isRunning(pid) {
|
|
724
708
|
if (!pid) return false;
|
|
725
709
|
try {
|
|
726
710
|
process.kill(pid, 0);
|
|
727
711
|
return true;
|
|
728
712
|
} catch (error) {
|
|
729
|
-
if (error
|
|
713
|
+
if (errorString(error, "code") === "EPERM" || errorString(error, "code") === "EACCES") {
|
|
714
|
+
return true;
|
|
715
|
+
}
|
|
730
716
|
return false;
|
|
731
717
|
}
|
|
732
718
|
}
|
|
733
|
-
|
|
734
719
|
function tailFile(file, lineCount = 80) {
|
|
735
720
|
try {
|
|
736
|
-
return fs.readFileSync(file,
|
|
721
|
+
return fs.readFileSync(file, "utf8").split(/\r?\n/).slice(-lineCount).join("\n").trim();
|
|
737
722
|
} catch {
|
|
738
|
-
return
|
|
723
|
+
return "";
|
|
739
724
|
}
|
|
740
725
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
const basePath = normalizeBasePath(env.FARMING_BASE_PATH || DEFAULT_BASE_PATH) || '/';
|
|
726
|
+
function entryUrl(env, host = "localhost") {
|
|
727
|
+
const basePath = normalizeBasePath(env.FARMING_BASE_PATH || DEFAULT_BASE_PATH) || "/";
|
|
744
728
|
return `http://${host}:${env.PORT}${basePath}`;
|
|
745
729
|
}
|
|
746
|
-
|
|
747
730
|
function readTokenForEnv(env) {
|
|
748
731
|
const tokenFile = storageLayout.sessionTokenFile(env.FARMING_CONFIG_DIR || defaultConfigDir(env));
|
|
749
732
|
try {
|
|
750
|
-
return fs.readFileSync(tokenFile,
|
|
733
|
+
return fs.readFileSync(tokenFile, "utf8").trim();
|
|
751
734
|
} catch {
|
|
752
|
-
return
|
|
735
|
+
return "";
|
|
753
736
|
}
|
|
754
737
|
}
|
|
755
|
-
|
|
756
738
|
function serverStartTimeoutMs(env) {
|
|
757
739
|
const parsed = Number(env.FARMING_START_TIMEOUT_MS || env.FARMING_SERVER_START_TIMEOUT_MS);
|
|
758
740
|
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
759
741
|
return DEFAULT_SERVER_START_TIMEOUT_MS;
|
|
760
742
|
}
|
|
761
|
-
|
|
762
743
|
function serverStartStabilityMs(env) {
|
|
763
744
|
const parsed = Number(env.FARMING_START_STABILITY_MS || env.FARMING_SERVER_START_STABILITY_MS);
|
|
764
|
-
if (Number.isFinite(parsed) && parsed >= 0) return Math.min(parsed,
|
|
745
|
+
if (Number.isFinite(parsed) && parsed >= 0) return Math.min(parsed, 6e4);
|
|
765
746
|
return DEFAULT_SERVER_START_STABILITY_MS;
|
|
766
747
|
}
|
|
767
|
-
|
|
768
748
|
function serverStopTimeoutMs(env) {
|
|
769
749
|
const parsed = Number(env.FARMING_STOP_TIMEOUT_MS || env.FARMING_SERVER_STOP_TIMEOUT_MS);
|
|
770
|
-
if (Number.isFinite(parsed) && parsed > 0) return Math.min(parsed,
|
|
750
|
+
if (Number.isFinite(parsed) && parsed > 0) return Math.min(parsed, 12e4);
|
|
771
751
|
return DEFAULT_SERVER_STOP_TIMEOUT_MS;
|
|
772
752
|
}
|
|
773
|
-
|
|
774
753
|
async function waitForDaemonStop(pid, port, options = {}) {
|
|
775
754
|
const timeoutMs = options.timeoutMs || DEFAULT_SERVER_STOP_TIMEOUT_MS;
|
|
776
755
|
const processRunning = options.isRunning || isRunning;
|
|
777
756
|
const portAvailable = options.canListenOnPort || canListenOnPort;
|
|
778
757
|
const now = options.now || Date.now;
|
|
779
|
-
const wait = options.wait || (durationMs => new Promise(resolve => setTimeout(resolve, durationMs)));
|
|
758
|
+
const wait = options.wait || ((durationMs) => new Promise((resolve) => setTimeout(resolve, durationMs)));
|
|
780
759
|
const startedAt = now();
|
|
781
760
|
let running = true;
|
|
782
761
|
let released = false;
|
|
783
|
-
|
|
784
762
|
while (true) {
|
|
785
763
|
running = processRunning(pid);
|
|
786
764
|
released = await portAvailable(port);
|
|
787
765
|
if (!running && released) return;
|
|
788
766
|
if (now() - startedAt >= timeoutMs) {
|
|
789
767
|
throw new Error(
|
|
790
|
-
`Farming server PID ${pid} did not stop and release port ${port} within ${timeoutMs}ms`
|
|
791
|
-
+ ` (process ${running ? 'still running' : 'exited'}, port ${released ? 'released' : 'still in use'})`,
|
|
768
|
+
`Farming server PID ${pid} did not stop and release port ${port} within ${timeoutMs}ms (process ${running ? "still running" : "exited"}, port ${released ? "released" : "still in use"})`
|
|
792
769
|
);
|
|
793
770
|
}
|
|
794
771
|
await wait(SERVER_STOP_POLL_MS);
|
|
795
772
|
}
|
|
796
773
|
}
|
|
797
|
-
|
|
798
774
|
function waitForProcessStability(pid, durationMs = DEFAULT_SERVER_START_STABILITY_MS) {
|
|
799
775
|
const startedAt = Date.now();
|
|
800
776
|
return new Promise((resolve, reject) => {
|
|
801
777
|
const tick = () => {
|
|
802
778
|
if (!isRunning(pid)) {
|
|
803
|
-
reject(new Error(
|
|
779
|
+
reject(new Error("server process exited during startup stability check"));
|
|
804
780
|
return;
|
|
805
781
|
}
|
|
806
782
|
const remainingMs = durationMs - (Date.now() - startedAt);
|
|
@@ -813,68 +789,62 @@ function waitForProcessStability(pid, durationMs = DEFAULT_SERVER_START_STABILIT
|
|
|
813
789
|
tick();
|
|
814
790
|
});
|
|
815
791
|
}
|
|
816
|
-
|
|
817
792
|
async function cleanupFailedDaemonStart(configDir, childPid, expectedIdentity = null) {
|
|
818
793
|
if (isRunning(childPid)) {
|
|
819
794
|
const expected = expectedIdentity || readServerState(configDir).processIdentity;
|
|
820
|
-
const current = readServerProcessIdentity(childPid);
|
|
821
|
-
if (!matchingProcessIdentity(expected, current)) {
|
|
795
|
+
const current = (0, import_server_process_identity.readServerProcessIdentity)(childPid);
|
|
796
|
+
if (!(0, import_server_process_identity.matchingProcessIdentity)(expected, current)) {
|
|
822
797
|
throw new Error(`Failed Farming startup left live PID ${childPid} with an unproved identity; refusing to signal it`);
|
|
823
798
|
}
|
|
824
799
|
try {
|
|
825
|
-
process.kill(childPid,
|
|
800
|
+
process.kill(childPid, "SIGKILL");
|
|
826
801
|
} catch (error) {
|
|
827
|
-
if (error
|
|
802
|
+
if (errorString(error, "code") === "EPERM" || errorString(error, "code") === "EACCES") {
|
|
828
803
|
throw new Error(
|
|
829
|
-
`Failed Farming startup left Server PID ${childPid} running because cleanup lacks permission.
|
|
830
|
-
|
|
831
|
-
{ cause: error },
|
|
804
|
+
`Failed Farming startup left Server PID ${childPid} running because cleanup lacks permission. Stop it as the operating-system user that owns the process, then retry.`,
|
|
805
|
+
{ cause: error }
|
|
832
806
|
);
|
|
833
807
|
}
|
|
834
|
-
if (error
|
|
808
|
+
if (errorString(error, "code") !== "ESRCH") throw error;
|
|
835
809
|
}
|
|
836
810
|
const startedAt = Date.now();
|
|
837
|
-
while (matchingProcessIdentity(expected, readServerProcessIdentity(childPid))) {
|
|
838
|
-
if (Date.now() - startedAt >=
|
|
811
|
+
while ((0, import_server_process_identity.matchingProcessIdentity)(expected, (0, import_server_process_identity.readServerProcessIdentity)(childPid))) {
|
|
812
|
+
if (Date.now() - startedAt >= 5e3) {
|
|
839
813
|
throw new Error(`Failed Farming startup left Server PID ${childPid} running after SIGKILL`);
|
|
840
814
|
}
|
|
841
|
-
await new Promise(resolve => setTimeout(resolve, SERVER_STOP_POLL_MS));
|
|
815
|
+
await new Promise((resolve) => setTimeout(resolve, SERVER_STOP_POLL_MS));
|
|
842
816
|
}
|
|
843
817
|
}
|
|
844
818
|
if (readPid(configDir) !== childPid) return;
|
|
845
819
|
fs.rmSync(pidFile(configDir), { force: true });
|
|
846
820
|
fs.rmSync(serverStateFile(configDir), { force: true });
|
|
847
821
|
}
|
|
848
|
-
|
|
849
822
|
function waitForServer(env, timeoutMs = serverStartTimeoutMs(env), childPid = 0) {
|
|
850
823
|
const startedAt = Date.now();
|
|
851
824
|
const port = Number(env.PORT || DEFAULT_PORT);
|
|
852
|
-
const authDisabled = [
|
|
853
|
-
|
|
825
|
+
const authDisabled = ["1", "true", "yes", "on"].includes(String(env.FARMING_DISABLE_AUTH || "").toLowerCase());
|
|
854
826
|
return new Promise((resolve, reject) => {
|
|
855
827
|
const tick = () => {
|
|
856
828
|
if (childPid && !isRunning(childPid)) {
|
|
857
|
-
reject(new Error(
|
|
829
|
+
reject(new Error("server process exited before becoming ready"));
|
|
858
830
|
return;
|
|
859
831
|
}
|
|
860
|
-
const token = authDisabled ?
|
|
832
|
+
const token = authDisabled ? "" : readTokenForEnv(env);
|
|
861
833
|
if (!authDisabled && !token) {
|
|
862
834
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
863
|
-
reject(new Error(
|
|
835
|
+
reject(new Error("server did not create its token file before timeout"));
|
|
864
836
|
return;
|
|
865
837
|
}
|
|
866
838
|
setTimeout(tick, 250);
|
|
867
839
|
return;
|
|
868
840
|
}
|
|
869
|
-
const readyPath = authDisabled
|
|
870
|
-
? routePath(env.FARMING_BASE_PATH || DEFAULT_BASE_PATH, '/api/auth/status')
|
|
871
|
-
: `${routePath(env.FARMING_BASE_PATH || DEFAULT_BASE_PATH, '/')}?token=${encodeURIComponent(token)}`;
|
|
841
|
+
const readyPath = authDisabled ? routePath(env.FARMING_BASE_PATH || DEFAULT_BASE_PATH, "/api/auth/status") : `${routePath(env.FARMING_BASE_PATH || DEFAULT_BASE_PATH, "/")}?token=${encodeURIComponent(token)}`;
|
|
872
842
|
const req = http.request({
|
|
873
|
-
host:
|
|
843
|
+
host: "127.0.0.1",
|
|
874
844
|
port,
|
|
875
845
|
path: readyPath,
|
|
876
|
-
method:
|
|
877
|
-
timeout: 500
|
|
846
|
+
method: "GET",
|
|
847
|
+
timeout: 500
|
|
878
848
|
}, (res) => {
|
|
879
849
|
res.resume();
|
|
880
850
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 400) {
|
|
@@ -887,14 +857,14 @@ function waitForServer(env, timeoutMs = serverStartTimeoutMs(env), childPid = 0)
|
|
|
887
857
|
}
|
|
888
858
|
setTimeout(tick, 250);
|
|
889
859
|
});
|
|
890
|
-
req.on(
|
|
860
|
+
req.on("error", () => {
|
|
891
861
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
892
|
-
reject(new Error(
|
|
862
|
+
reject(new Error("server did not become ready before timeout"));
|
|
893
863
|
return;
|
|
894
864
|
}
|
|
895
865
|
setTimeout(tick, 250);
|
|
896
866
|
});
|
|
897
|
-
req.on(
|
|
867
|
+
req.on("timeout", () => {
|
|
898
868
|
req.destroy();
|
|
899
869
|
});
|
|
900
870
|
req.end();
|
|
@@ -902,100 +872,92 @@ function waitForServer(env, timeoutMs = serverStartTimeoutMs(env), childPid = 0)
|
|
|
902
872
|
tick();
|
|
903
873
|
});
|
|
904
874
|
}
|
|
905
|
-
|
|
906
875
|
async function runServerInCurrentProcess() {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
876
|
+
const env = buildServerEnv();
|
|
877
|
+
process.env = env;
|
|
878
|
+
ensureConfigDir(env.FARMING_CONFIG_DIR);
|
|
879
|
+
fs.writeFileSync(pidFile(env.FARMING_CONFIG_DIR), String(process.pid), { mode: 384 });
|
|
880
|
+
const processIdentity = await (0, import_server_process_identity.readServerProcessIdentity)(process.pid);
|
|
881
|
+
if (!processIdentity) throw new Error("server process identity could not be committed before startup");
|
|
882
|
+
writeServerState(env.FARMING_CONFIG_DIR, env, process.pid, processIdentity, "starting");
|
|
883
|
+
const { startServer } = require("./server.cjs");
|
|
914
884
|
const server = startServer();
|
|
915
|
-
server.once(
|
|
885
|
+
server.once("listening", () => {
|
|
916
886
|
writeServerState(
|
|
917
|
-
|
|
918
|
-
|
|
887
|
+
env.FARMING_CONFIG_DIR,
|
|
888
|
+
env,
|
|
919
889
|
process.pid,
|
|
920
890
|
processIdentity,
|
|
921
|
-
|
|
891
|
+
"running"
|
|
922
892
|
);
|
|
923
|
-
const { pruneRuntimeDependencies } = require(
|
|
893
|
+
const { pruneRuntimeDependencies } = require("./runtime-dependency-manager.cjs");
|
|
924
894
|
void pruneRuntimeDependencies({
|
|
925
|
-
configDir:
|
|
926
|
-
env
|
|
927
|
-
}).catch(error => {
|
|
928
|
-
console.warn(`Startup dependency cache cleanup failed: ${error
|
|
895
|
+
configDir: env.FARMING_CONFIG_DIR,
|
|
896
|
+
env
|
|
897
|
+
}).catch((error) => {
|
|
898
|
+
console.warn(`Startup dependency cache cleanup failed: ${errorString(error) || error}`);
|
|
929
899
|
});
|
|
930
900
|
});
|
|
931
901
|
}
|
|
932
|
-
|
|
933
902
|
function runNativePtyHostInCurrentProcess() {
|
|
934
|
-
const { startNativePtyHostProcess } = require(
|
|
903
|
+
const { startNativePtyHostProcess } = require("./native-pty-host.cjs");
|
|
935
904
|
startNativePtyHostProcess();
|
|
936
905
|
}
|
|
937
|
-
|
|
938
906
|
async function prepareStartupDependencies(env, options = {}) {
|
|
939
|
-
if (
|
|
940
|
-
options.force !== true
|
|
941
|
-
&& (env.FARMING_SKIP_RUNTIME_PREPARE === '1' || env.NODE_ENV === 'test')
|
|
942
|
-
) {
|
|
907
|
+
if (options.force !== true && (env.FARMING_SKIP_RUNTIME_PREPARE === "1" || env.NODE_ENV === "test")) {
|
|
943
908
|
return { skipped: true };
|
|
944
909
|
}
|
|
945
|
-
const { prepareRuntimeDependencies } = require(
|
|
910
|
+
const { prepareRuntimeDependencies } = require("./runtime-dependency-manager.cjs");
|
|
946
911
|
return prepareRuntimeDependencies({
|
|
912
|
+
activate: options.activate,
|
|
947
913
|
configDir: env.FARMING_CONFIG_DIR,
|
|
948
|
-
env
|
|
914
|
+
env
|
|
949
915
|
});
|
|
950
916
|
}
|
|
951
|
-
|
|
952
917
|
async function startForeground(parsed) {
|
|
953
918
|
const env = buildServerEnv(parsed.env);
|
|
954
919
|
await prepareStartupDependencies(env);
|
|
955
920
|
await adaptServerPort(env, parsed);
|
|
956
|
-
env[SERVER_MODE_ENV] =
|
|
921
|
+
env[SERVER_MODE_ENV] = "1";
|
|
957
922
|
ensureConfigDir(env.FARMING_CONFIG_DIR);
|
|
958
923
|
const invocation = childInvocation(env);
|
|
959
|
-
const child = spawn(invocation.command, invocation.args, {
|
|
924
|
+
const child = (0, import_child_process.spawn)(invocation.command, invocation.args, {
|
|
960
925
|
env,
|
|
961
|
-
stdio:
|
|
926
|
+
stdio: "inherit"
|
|
962
927
|
});
|
|
963
|
-
child.on(
|
|
928
|
+
child.on("exit", (code, signal) => {
|
|
964
929
|
if (signal) {
|
|
965
930
|
process.kill(process.pid, signal);
|
|
966
931
|
return;
|
|
967
932
|
}
|
|
968
933
|
process.exit(code || 0);
|
|
969
934
|
});
|
|
970
|
-
child.on(
|
|
935
|
+
child.on("error", (error) => {
|
|
971
936
|
console.error(error.message);
|
|
972
937
|
process.exit(1);
|
|
973
938
|
});
|
|
974
939
|
}
|
|
975
|
-
|
|
976
940
|
async function startDaemon(parsed) {
|
|
977
941
|
const env = await adaptServerPort(buildServerEnv(parsed.env), parsed);
|
|
978
|
-
env[SERVER_MODE_ENV] =
|
|
942
|
+
env[SERVER_MODE_ENV] = "1";
|
|
979
943
|
const configDir = env.FARMING_CONFIG_DIR;
|
|
980
944
|
ensureConfigDir(configDir);
|
|
981
|
-
|
|
982
945
|
const existingPid = readPid(configDir);
|
|
983
946
|
if (isRunning(existingPid)) {
|
|
984
947
|
const state = readServerState(configDir);
|
|
985
948
|
try {
|
|
986
|
-
if (state.processIdentity?.format === SERVER_PROCESS_IDENTITY_FORMAT) {
|
|
949
|
+
if (state.processIdentity?.format === import_server_process_identity.SERVER_PROCESS_IDENTITY_FORMAT) {
|
|
987
950
|
await assertServerProcessIdentity(configDir, existingPid, state);
|
|
988
951
|
} else {
|
|
989
952
|
await migrateLegacyServerIdentity(configDir, existingPid, state);
|
|
990
953
|
}
|
|
991
954
|
} catch (error) {
|
|
992
955
|
console.error(
|
|
993
|
-
`Farming PID ${existingPid} is live, but this config directory does not prove that it owns the Server: `
|
|
994
|
-
+ `${error.message || error}`,
|
|
956
|
+
`Farming PID ${existingPid} is live, but this config directory does not prove that it owns the Server: ${errorString(error) || error}`
|
|
995
957
|
);
|
|
996
958
|
return 1;
|
|
997
959
|
}
|
|
998
|
-
if (state.phase ===
|
|
960
|
+
if (state.phase === "starting") {
|
|
999
961
|
console.warn(`Previous Farming startup (PID ${existingPid}) did not complete; replacing it.`);
|
|
1000
962
|
const stopCode = await stopDaemon({ env });
|
|
1001
963
|
if (stopCode !== 0) return stopCode;
|
|
@@ -1007,69 +969,65 @@ async function startDaemon(parsed) {
|
|
|
1007
969
|
return 0;
|
|
1008
970
|
}
|
|
1009
971
|
}
|
|
1010
|
-
|
|
1011
972
|
await prepareStartupDependencies(env);
|
|
1012
|
-
const out = fs.openSync(logFile(configDir),
|
|
973
|
+
const out = fs.openSync(logFile(configDir), "a");
|
|
1013
974
|
const invocation = childInvocation(env);
|
|
1014
|
-
if (env.FARMING_DEBUG_CLI ===
|
|
975
|
+
if (env.FARMING_DEBUG_CLI === "1") {
|
|
1015
976
|
fs.appendFileSync(logFile(configDir), [
|
|
1016
977
|
`daemon invocation command=${invocation.command}`,
|
|
1017
978
|
`daemon invocation args=${JSON.stringify(invocation.args)}`,
|
|
1018
979
|
`daemon parent argv=${JSON.stringify(process.argv)}`,
|
|
1019
980
|
`daemon parent execPath=${process.execPath}`,
|
|
1020
|
-
`daemon child pkg env=${JSON.stringify(Object.fromEntries(Object.entries(env).filter(([key]) => key.startsWith(
|
|
1021
|
-
|
|
1022
|
-
].join(
|
|
981
|
+
`daemon child pkg env=${JSON.stringify(Object.fromEntries(Object.entries(env).filter(([key]) => key.startsWith("PKG"))))}`,
|
|
982
|
+
""
|
|
983
|
+
].join("\n"));
|
|
1023
984
|
}
|
|
1024
|
-
const child = spawn(invocation.command, invocation.args, {
|
|
985
|
+
const child = (0, import_child_process.spawn)(invocation.command, invocation.args, {
|
|
1025
986
|
detached: true,
|
|
1026
987
|
env,
|
|
1027
|
-
stdio: [
|
|
988
|
+
stdio: ["ignore", out, out]
|
|
1028
989
|
});
|
|
990
|
+
const childPid = child.pid;
|
|
991
|
+
if (!childPid) throw new Error("server process did not report its PID after launch");
|
|
1029
992
|
child.unref();
|
|
1030
|
-
fs.writeFileSync(pidFile(configDir), String(
|
|
1031
|
-
|
|
993
|
+
fs.writeFileSync(pidFile(configDir), String(childPid));
|
|
1032
994
|
let processIdentity = null;
|
|
1033
995
|
try {
|
|
1034
|
-
processIdentity = await
|
|
1035
|
-
if (!processIdentity) throw new Error(
|
|
1036
|
-
writeServerState(configDir, env,
|
|
1037
|
-
await waitForServer(env, serverStartTimeoutMs(env),
|
|
1038
|
-
await waitForProcessStability(
|
|
1039
|
-
await waitForServer(env, Math.min(serverStartTimeoutMs(env),
|
|
1040
|
-
const stableIdentity = await
|
|
1041
|
-
if (
|
|
1042
|
-
|
|
1043
|
-
|| stableIdentity.processGroupId !== processIdentity.processGroupId
|
|
1044
|
-
|| stableIdentity.startedAt !== processIdentity.startedAt
|
|
1045
|
-
) {
|
|
1046
|
-
throw new Error('server process identity changed during startup');
|
|
996
|
+
processIdentity = await (0, import_server_process_identity.readServerProcessIdentity)(childPid);
|
|
997
|
+
if (!processIdentity) throw new Error("server process identity could not be verified after launch");
|
|
998
|
+
writeServerState(configDir, env, childPid, processIdentity, "starting");
|
|
999
|
+
await waitForServer(env, serverStartTimeoutMs(env), childPid);
|
|
1000
|
+
await waitForProcessStability(childPid, serverStartStabilityMs(env));
|
|
1001
|
+
await waitForServer(env, Math.min(serverStartTimeoutMs(env), 5e3), childPid);
|
|
1002
|
+
const stableIdentity = await (0, import_server_process_identity.readServerProcessIdentity)(childPid);
|
|
1003
|
+
if (!stableIdentity || stableIdentity.processGroupId !== processIdentity.processGroupId || stableIdentity.startedAt !== processIdentity.startedAt) {
|
|
1004
|
+
throw new Error("server process identity changed during startup");
|
|
1047
1005
|
}
|
|
1048
|
-
writeServerState(configDir, env,
|
|
1006
|
+
writeServerState(configDir, env, childPid, stableIdentity, "running");
|
|
1049
1007
|
} catch (error) {
|
|
1050
1008
|
try {
|
|
1051
|
-
await cleanupFailedDaemonStart(configDir,
|
|
1009
|
+
await cleanupFailedDaemonStart(configDir, childPid, processIdentity);
|
|
1052
1010
|
} catch (cleanupError) {
|
|
1053
|
-
console.error(
|
|
1011
|
+
console.error(
|
|
1012
|
+
`${errorString(error)}; cleanup failed: ${errorString(cleanupError) || cleanupError}`
|
|
1013
|
+
);
|
|
1054
1014
|
return 1;
|
|
1055
1015
|
}
|
|
1056
|
-
console.error(error
|
|
1057
|
-
const
|
|
1058
|
-
if (
|
|
1016
|
+
console.error(errorString(error));
|
|
1017
|
+
const logs2 = tailFile(logFile(configDir), 80);
|
|
1018
|
+
if (logs2) console.error(logs2);
|
|
1059
1019
|
return 1;
|
|
1060
1020
|
}
|
|
1061
|
-
|
|
1062
|
-
console.log(`Farming started (PID ${child.pid})`);
|
|
1021
|
+
console.log(`Farming started (PID ${childPid})`);
|
|
1063
1022
|
const logs = tailFile(logFile(configDir), 40);
|
|
1064
|
-
const urlLines = logs.split(/\r?\n/).filter(line => /Local:|Network:|Token:|Token style:|Token auth:/.test(line));
|
|
1023
|
+
const urlLines = logs.split(/\r?\n/).filter((line) => /Local:|Network:|Token:|Token style:|Token auth:/.test(line));
|
|
1065
1024
|
if (urlLines.length > 0) {
|
|
1066
|
-
console.log(urlLines.join(
|
|
1025
|
+
console.log(urlLines.join("\n"));
|
|
1067
1026
|
} else {
|
|
1068
1027
|
console.log(entryUrl(env));
|
|
1069
1028
|
}
|
|
1070
1029
|
return 0;
|
|
1071
1030
|
}
|
|
1072
|
-
|
|
1073
1031
|
async function stopDaemon(parsed) {
|
|
1074
1032
|
const env = buildServerEnv(parsed.env);
|
|
1075
1033
|
const configDir = env.FARMING_CONFIG_DIR;
|
|
@@ -1077,27 +1035,26 @@ async function stopDaemon(parsed) {
|
|
|
1077
1035
|
if (!isRunning(pid)) {
|
|
1078
1036
|
fs.rmSync(pidFile(configDir), { force: true });
|
|
1079
1037
|
fs.rmSync(serverStateFile(configDir), { force: true });
|
|
1080
|
-
console.log(
|
|
1038
|
+
console.log("Farming is not running.");
|
|
1081
1039
|
return 0;
|
|
1082
1040
|
}
|
|
1083
1041
|
const state = readServerState(configDir);
|
|
1084
1042
|
const port = Number(state.port || env.PORT || DEFAULT_PORT);
|
|
1085
|
-
if (state.processIdentity?.format === SERVER_PROCESS_IDENTITY_FORMAT) {
|
|
1043
|
+
if (state.processIdentity?.format === import_server_process_identity.SERVER_PROCESS_IDENTITY_FORMAT) {
|
|
1086
1044
|
await assertServerProcessIdentity(configDir, pid, state);
|
|
1087
1045
|
} else {
|
|
1088
1046
|
await migrateLegacyServerIdentity(configDir, pid, state);
|
|
1089
1047
|
}
|
|
1090
1048
|
try {
|
|
1091
|
-
process.kill(pid,
|
|
1049
|
+
process.kill(pid, "SIGKILL");
|
|
1092
1050
|
} catch (error) {
|
|
1093
|
-
if (error
|
|
1051
|
+
if (errorString(error, "code") === "EPERM" || errorString(error, "code") === "EACCES") {
|
|
1094
1052
|
throw new Error(
|
|
1095
|
-
`Farming cannot stop server ${pid} because this command lacks permission.
|
|
1096
|
-
|
|
1097
|
-
{ cause: error },
|
|
1053
|
+
`Farming cannot stop server ${pid} because this command lacks permission. Run it as the operating-system user that owns the process (or as an administrator), then start Farming again.`,
|
|
1054
|
+
{ cause: error }
|
|
1098
1055
|
);
|
|
1099
1056
|
}
|
|
1100
|
-
if (error
|
|
1057
|
+
if (errorString(error, "code") !== "ESRCH") throw error;
|
|
1101
1058
|
}
|
|
1102
1059
|
await waitForDaemonStop(pid, port, { timeoutMs: serverStopTimeoutMs(env) });
|
|
1103
1060
|
if (readPid(configDir) === pid) fs.rmSync(pidFile(configDir), { force: true });
|
|
@@ -1105,30 +1062,28 @@ async function stopDaemon(parsed) {
|
|
|
1105
1062
|
console.log(`Stopped Farming (PID ${pid})`);
|
|
1106
1063
|
return 0;
|
|
1107
1064
|
}
|
|
1108
|
-
|
|
1109
1065
|
async function statusDaemon(parsed) {
|
|
1110
1066
|
const env = buildServerEnv(parsed.env);
|
|
1111
1067
|
const configDir = env.FARMING_CONFIG_DIR;
|
|
1112
1068
|
const pid = readPid(configDir);
|
|
1113
1069
|
if (!isRunning(pid)) {
|
|
1114
|
-
console.log(
|
|
1070
|
+
console.log("Farming is not running.");
|
|
1115
1071
|
return 0;
|
|
1116
1072
|
}
|
|
1117
1073
|
const state = readServerState(configDir);
|
|
1118
1074
|
try {
|
|
1119
|
-
if (state.processIdentity?.format === SERVER_PROCESS_IDENTITY_FORMAT) {
|
|
1075
|
+
if (state.processIdentity?.format === import_server_process_identity.SERVER_PROCESS_IDENTITY_FORMAT) {
|
|
1120
1076
|
await assertServerProcessIdentity(configDir, pid, state);
|
|
1121
1077
|
} else {
|
|
1122
1078
|
await migrateLegacyServerIdentity(configDir, pid, state);
|
|
1123
1079
|
}
|
|
1124
1080
|
} catch (error) {
|
|
1125
1081
|
console.error(
|
|
1126
|
-
`Farming PID ${pid} is live, but this config directory does not prove that it owns the Server: `
|
|
1127
|
-
+ `${error.message || error}`,
|
|
1082
|
+
`Farming PID ${pid} is live, but this config directory does not prove that it owns the Server: ${errorString(error) || error}`
|
|
1128
1083
|
);
|
|
1129
1084
|
return 1;
|
|
1130
1085
|
}
|
|
1131
|
-
if (state.phase ===
|
|
1086
|
+
if (state.phase === "starting") {
|
|
1132
1087
|
console.log(`Farming is starting (PID ${pid}). Run 'farming start' to replace an interrupted startup.`);
|
|
1133
1088
|
return 1;
|
|
1134
1089
|
}
|
|
@@ -1137,14 +1092,12 @@ async function statusDaemon(parsed) {
|
|
|
1137
1092
|
if (logs) console.log(logs);
|
|
1138
1093
|
return 0;
|
|
1139
1094
|
}
|
|
1140
|
-
|
|
1141
1095
|
function showLogs(parsed) {
|
|
1142
1096
|
const env = buildServerEnv(parsed.env);
|
|
1143
1097
|
const logs = tailFile(logFile(env.FARMING_CONFIG_DIR), 120);
|
|
1144
|
-
console.log(logs ||
|
|
1098
|
+
console.log(logs || "No Farming log found.");
|
|
1145
1099
|
return 0;
|
|
1146
1100
|
}
|
|
1147
|
-
|
|
1148
1101
|
function showUrl(parsed) {
|
|
1149
1102
|
const env = buildServerEnv(parsed.env);
|
|
1150
1103
|
if (!parsed.portExplicit && !isPortOverrideExplicit(parsed.env, process.env)) {
|
|
@@ -1155,7 +1108,6 @@ function showUrl(parsed) {
|
|
|
1155
1108
|
console.log(entryUrl(env));
|
|
1156
1109
|
return 0;
|
|
1157
1110
|
}
|
|
1158
|
-
|
|
1159
1111
|
function usage() {
|
|
1160
1112
|
return `Usage:
|
|
1161
1113
|
farming [start] [--port 6694] [--base-path /farming] [--config-dir ~/.farming]
|
|
@@ -1164,127 +1116,123 @@ function usage() {
|
|
|
1164
1116
|
farming stop
|
|
1165
1117
|
farming logs
|
|
1166
1118
|
farming url
|
|
1167
|
-
farming runtime prepare [--config-dir ~/.farming]
|
|
1119
|
+
farming runtime prepare [--config-dir ~/.farming] [--no-activate]
|
|
1168
1120
|
farming review <git-dir> <old-revision> <new-revision|now> [--branch <branch>] [--no-open]
|
|
1169
1121
|
|
|
1170
1122
|
Agent control commands are also available:
|
|
1171
1123
|
farming skills
|
|
1172
1124
|
farming capabilities [--json]
|
|
1173
1125
|
farming browser ...
|
|
1126
|
+
farming computer ...
|
|
1174
1127
|
farming list [--json] [--parent <agentId>]
|
|
1175
1128
|
farming spawn --workspace <repo> -- <command...>
|
|
1176
1129
|
farming output <agentId> [--tail <chars>]
|
|
1177
1130
|
farming send <agentId> <text...>
|
|
1178
1131
|
farming kill <agentId>`;
|
|
1179
1132
|
}
|
|
1180
|
-
|
|
1181
1133
|
async function run(argv = process.argv.slice(2)) {
|
|
1182
|
-
if (process.env.FARMING_DEBUG_CLI ===
|
|
1134
|
+
if (process.env.FARMING_DEBUG_CLI === "1" && argv[0] === "debug-argv") {
|
|
1183
1135
|
console.log(JSON.stringify({
|
|
1184
1136
|
argv: process.argv,
|
|
1185
1137
|
execPath: process.execPath,
|
|
1186
|
-
pkg: Boolean(
|
|
1138
|
+
pkg: Boolean(packagedProcess.pkg)
|
|
1187
1139
|
}, null, 2));
|
|
1188
1140
|
return 0;
|
|
1189
1141
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
await runPackagedCodexAcp();
|
|
1142
|
+
if (argv[0] === import_packaged_codex_acp.PACKAGED_CODEX_ACP_ARG) {
|
|
1143
|
+
await (0, import_packaged_codex_acp.runPackagedCodexAcp)();
|
|
1193
1144
|
return 0;
|
|
1194
1145
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
await runPackagedClaudeAcp();
|
|
1146
|
+
if (argv[0] === import_packaged_claude_acp.PACKAGED_CLAUDE_ACP_ARG) {
|
|
1147
|
+
await (0, import_packaged_claude_acp.runPackagedClaudeAcp)();
|
|
1198
1148
|
return 0;
|
|
1199
1149
|
}
|
|
1200
|
-
|
|
1201
1150
|
if (argv[0] === USAGE_HISTORY_SMOKE_ARG) {
|
|
1202
|
-
const { runUsageHistorySmoke } = require(
|
|
1151
|
+
const { runUsageHistorySmoke } = require("./usage-history-smoke.cjs");
|
|
1203
1152
|
const result = await runUsageHistorySmoke();
|
|
1204
1153
|
console.log(JSON.stringify(result));
|
|
1205
1154
|
return 0;
|
|
1206
1155
|
}
|
|
1207
|
-
|
|
1208
|
-
if (argv[0] === NATIVE_PTY_HOST_ARG || process.env.FARMING_RUN_NATIVE_PTY_HOST === '1') {
|
|
1156
|
+
if (argv[0] === NATIVE_PTY_HOST_ARG || argv.length === 0 && process.env.FARMING_RUN_NATIVE_PTY_HOST === "1") {
|
|
1209
1157
|
runNativePtyHostInCurrentProcess();
|
|
1210
1158
|
return 0;
|
|
1211
1159
|
}
|
|
1212
|
-
|
|
1213
|
-
if (process.env[SERVER_MODE_ENV] === '1' || argv[0] === SERVER_MODE_ARG) {
|
|
1160
|
+
if (argv[0] === SERVER_MODE_ARG || argv.length === 0 && process.env[SERVER_MODE_ENV] === "1") {
|
|
1214
1161
|
await runServerInCurrentProcess();
|
|
1215
1162
|
return 0;
|
|
1216
1163
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
const { run: runBrowserCli } = require('../extensions/browser/bin/farming-browser');
|
|
1164
|
+
if (argv[0] === "browser") {
|
|
1165
|
+
const { run: runBrowserCli } = require("../extensions/browser/bin/farming-browser");
|
|
1220
1166
|
return runBrowserCli(argv.slice(1));
|
|
1221
1167
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1168
|
+
if (argv[0] === "computer") {
|
|
1169
|
+
const { run: runComputerCli } = require("../extensions/computer/bin/farming-computer");
|
|
1170
|
+
return runComputerCli(argv.slice(1));
|
|
1171
|
+
}
|
|
1172
|
+
if (argv[0] === "runtime" && argv[1] === "prepare") {
|
|
1173
|
+
const activate = !argv.slice(2).includes("--no-activate");
|
|
1174
|
+
const parsed2 = parseServerArgs([
|
|
1175
|
+
"start",
|
|
1176
|
+
...argv.slice(2).filter((arg) => arg !== "--no-activate")
|
|
1177
|
+
]);
|
|
1178
|
+
const env = buildServerEnv(parsed2.env);
|
|
1179
|
+
const result = await prepareStartupDependencies(env, { activate, force: true });
|
|
1227
1180
|
console.log(JSON.stringify(result, null, 2));
|
|
1228
1181
|
return 0;
|
|
1229
1182
|
}
|
|
1230
|
-
|
|
1231
1183
|
if (SERVER_BACKED_CONTROL_COMMANDS.has(argv[0])) {
|
|
1232
1184
|
return runServerBackedControlCli(argv);
|
|
1233
1185
|
}
|
|
1234
|
-
|
|
1235
1186
|
if (CONTROL_COMMANDS.has(argv[0])) {
|
|
1236
|
-
return
|
|
1187
|
+
return (0, import_farming_cli.run)(argv);
|
|
1237
1188
|
}
|
|
1238
|
-
|
|
1239
|
-
if (argv[0] === 'review') return runReview(parseReviewArgs(argv.slice(1)));
|
|
1240
|
-
|
|
1189
|
+
if (argv[0] === "review") return runReview(parseReviewArgs(argv.slice(1)));
|
|
1241
1190
|
const parsed = parseServerArgs(argv);
|
|
1242
|
-
if (parsed.command ===
|
|
1191
|
+
if (parsed.command === "help") {
|
|
1243
1192
|
console.log(usage());
|
|
1244
1193
|
return 0;
|
|
1245
1194
|
}
|
|
1246
|
-
if (parsed.command ===
|
|
1247
|
-
if (parsed.command ===
|
|
1248
|
-
if (parsed.command ===
|
|
1249
|
-
if (parsed.command ===
|
|
1250
|
-
if (parsed.command ===
|
|
1195
|
+
if (parsed.command === "daemon") return startDaemon(parsed);
|
|
1196
|
+
if (parsed.command === "stop") return stopDaemon(parsed);
|
|
1197
|
+
if (parsed.command === "status") return statusDaemon(parsed);
|
|
1198
|
+
if (parsed.command === "logs") return showLogs(parsed);
|
|
1199
|
+
if (parsed.command === "url") return showUrl(parsed);
|
|
1251
1200
|
await startForeground(parsed);
|
|
1252
1201
|
return 0;
|
|
1253
1202
|
}
|
|
1254
|
-
|
|
1255
1203
|
if (require.main === module) {
|
|
1256
|
-
run().then(code => {
|
|
1204
|
+
run().then((code) => {
|
|
1257
1205
|
if (code) process.exit(code);
|
|
1258
|
-
}).catch(error => {
|
|
1259
|
-
console.error(error
|
|
1206
|
+
}).catch((error) => {
|
|
1207
|
+
console.error(errorString(error) || error);
|
|
1260
1208
|
process.exit(1);
|
|
1261
1209
|
});
|
|
1262
1210
|
}
|
|
1263
|
-
|
|
1264
|
-
module.exports = {
|
|
1265
|
-
SERVER_MODE_ARG,
|
|
1211
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1212
|
+
0 && (module.exports = {
|
|
1266
1213
|
NATIVE_PTY_HOST_ARG,
|
|
1214
|
+
SERVER_MODE_ARG,
|
|
1267
1215
|
buildCleanEnvExecArgs,
|
|
1268
1216
|
buildCleanEnvExecCommand,
|
|
1269
|
-
childInvocation,
|
|
1270
|
-
cleanupFailedDaemonStart,
|
|
1271
1217
|
buildControlEnv,
|
|
1272
1218
|
buildServerEnv,
|
|
1219
|
+
childInvocation,
|
|
1220
|
+
cleanupFailedDaemonStart,
|
|
1273
1221
|
computeNodeHeapMb,
|
|
1274
1222
|
defaultConfigDir,
|
|
1275
1223
|
findAvailablePort,
|
|
1276
|
-
parseServerArgs,
|
|
1277
1224
|
parseReviewArgs,
|
|
1225
|
+
parseServerArgs,
|
|
1226
|
+
readServerProcessIdentity,
|
|
1227
|
+
readServerState,
|
|
1278
1228
|
resolveReviewTarget,
|
|
1279
1229
|
reviewUrl,
|
|
1280
|
-
|
|
1281
|
-
readServerProcessIdentity,
|
|
1282
|
-
serverStartTimeoutMs,
|
|
1230
|
+
run,
|
|
1283
1231
|
serverStartStabilityMs,
|
|
1232
|
+
serverStartTimeoutMs,
|
|
1233
|
+
serverStateFile,
|
|
1284
1234
|
serverStopTimeoutMs,
|
|
1285
1235
|
splitControlArgs,
|
|
1286
1236
|
stopDaemon,
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
waitForDaemonStop,
|
|
1290
|
-
};
|
|
1237
|
+
waitForDaemonStop
|
|
1238
|
+
});
|