opendevbrowser 0.0.28 → 0.0.29
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 +2 -2
- package/dist/accessibility-snapshot-PA6NWNS7.js +39 -0
- package/dist/accessibility-snapshot-PA6NWNS7.js.map +1 -0
- package/dist/active-window-YNYTIPZN.js +37 -0
- package/dist/active-window-YNYTIPZN.js.map +1 -0
- package/dist/annotate-STYHXZYJ.js +205 -0
- package/dist/annotate-STYHXZYJ.js.map +1 -0
- package/dist/artifacts-KJ6RNDO2.js +120 -0
- package/dist/artifacts-KJ6RNDO2.js.map +1 -0
- package/dist/attr-GHFZZ4SA.js +84 -0
- package/dist/attr-GHFZZ4SA.js.map +1 -0
- package/dist/browser/ops-client.d.ts +1 -0
- package/dist/browser/ops-client.d.ts.map +1 -1
- package/dist/canvas-54FBOEGP.js +309 -0
- package/dist/canvas-54FBOEGP.js.map +1 -0
- package/dist/capture-desktop-SNABC24E.js +38 -0
- package/dist/capture-desktop-SNABC24E.js.map +1 -0
- package/dist/capture-window-UJSB5AMP.js +40 -0
- package/dist/capture-window-UJSB5AMP.js.map +1 -0
- package/dist/check-ST5UQ2F5.js +71 -0
- package/dist/check-ST5UQ2F5.js.map +1 -0
- package/dist/checked-IEMWI5CU.js +71 -0
- package/dist/checked-IEMWI5CU.js.map +1 -0
- package/dist/chunk-2CG4SW3E.js +64 -0
- package/dist/chunk-2CG4SW3E.js.map +1 -0
- package/dist/chunk-2SIMIPLY.js +67 -0
- package/dist/chunk-2SIMIPLY.js.map +1 -0
- package/dist/chunk-37VSRUW4.js +141 -0
- package/dist/chunk-37VSRUW4.js.map +1 -0
- package/dist/chunk-5SWZDVOW.js +144 -0
- package/dist/chunk-5SWZDVOW.js.map +1 -0
- package/dist/chunk-6PVZ2ABC.js +429 -0
- package/dist/chunk-6PVZ2ABC.js.map +1 -0
- package/dist/chunk-7GVOUZMQ.js +64 -0
- package/dist/chunk-7GVOUZMQ.js.map +1 -0
- package/dist/chunk-7THCPS52.js +84 -0
- package/dist/chunk-7THCPS52.js.map +1 -0
- package/dist/chunk-ASMHEEKY.js +10 -0
- package/dist/chunk-ASMHEEKY.js.map +1 -0
- package/dist/chunk-DBF5OKH3.js +111 -0
- package/dist/chunk-DBF5OKH3.js.map +1 -0
- package/dist/chunk-DW4TX7MU.js +54 -0
- package/dist/chunk-DW4TX7MU.js.map +1 -0
- package/dist/chunk-IPE7TF2P.js +54 -0
- package/dist/chunk-IPE7TF2P.js.map +1 -0
- package/dist/chunk-IQTJHXZJ.js +126 -0
- package/dist/chunk-IQTJHXZJ.js.map +1 -0
- package/dist/chunk-J47N77VG.js +2969 -0
- package/dist/chunk-J47N77VG.js.map +1 -0
- package/dist/chunk-JZXD6FWR.js +25 -0
- package/dist/chunk-JZXD6FWR.js.map +1 -0
- package/dist/{chunk-QVWOPIZJ.js → chunk-KDSNXS6N.js} +75 -149
- package/dist/chunk-KDSNXS6N.js.map +1 -0
- package/dist/chunk-KZ2IXVQT.js +219 -0
- package/dist/chunk-KZ2IXVQT.js.map +1 -0
- package/dist/chunk-LBPELU7L.js +3649 -0
- package/dist/chunk-LBPELU7L.js.map +1 -0
- package/dist/chunk-MX3NFLCE.js +940 -0
- package/dist/chunk-MX3NFLCE.js.map +1 -0
- package/dist/chunk-N44UXKIB.js +26 -0
- package/dist/chunk-N44UXKIB.js.map +1 -0
- package/dist/chunk-OW5HMYMI.js +19 -0
- package/dist/chunk-OW5HMYMI.js.map +1 -0
- package/dist/chunk-OYNLAZQU.js +838 -0
- package/dist/chunk-OYNLAZQU.js.map +1 -0
- package/dist/chunk-PDPJN2OP.js +17 -0
- package/dist/chunk-PDPJN2OP.js.map +1 -0
- package/dist/chunk-RCZZGGJS.js +226 -0
- package/dist/chunk-RCZZGGJS.js.map +1 -0
- package/dist/chunk-RJNI3BHT.js +1 -0
- package/dist/chunk-RPXWUCQQ.js +112 -0
- package/dist/chunk-RPXWUCQQ.js.map +1 -0
- package/dist/chunk-S5KZQJJI.js +107 -0
- package/dist/chunk-S5KZQJJI.js.map +1 -0
- package/dist/{chunk-T3VVHJTK.js → chunk-S6S2UP6U.js} +1074 -1459
- package/dist/chunk-S6S2UP6U.js.map +1 -0
- package/dist/{chunk-I5ZCOZZV.js → chunk-SXAGSEKZ.js} +1202 -9561
- package/dist/chunk-SXAGSEKZ.js.map +1 -0
- package/dist/chunk-T4GMCW6Z.js +46 -0
- package/dist/chunk-T4GMCW6Z.js.map +1 -0
- package/dist/chunk-WHQZBUNY.js +982 -0
- package/dist/chunk-WHQZBUNY.js.map +1 -0
- package/dist/chunk-WOXBLP7V.js +610 -0
- package/dist/chunk-WOXBLP7V.js.map +1 -0
- package/dist/cli/commands/inspiredesign.d.ts.map +1 -1
- package/dist/cli/commands/macro-resolve.d.ts +4 -1
- package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
- package/dist/cli/commands/product-video.d.ts.map +1 -1
- package/dist/cli/commands/research.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/shopping.d.ts.map +1 -1
- package/dist/cli/commands/workflow-output.d.ts +2 -0
- package/dist/cli/commands/workflow-output.d.ts.map +1 -0
- package/dist/cli/daemon-commands.d.ts.map +1 -1
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/index.js +204 -8123
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/installers/postinstall-skill-sync.js +2 -1
- package/dist/cli/installers/postinstall-skill-sync.js.map +1 -1
- package/dist/cli/remote-relay.d.ts.map +1 -1
- package/dist/click-TENZA3Y6.js +81 -0
- package/dist/click-TENZA3Y6.js.map +1 -0
- package/dist/clone-component-STH5AR6M.js +82 -0
- package/dist/clone-component-STH5AR6M.js.map +1 -0
- package/dist/clone-page-BSTWAPAJ.js +69 -0
- package/dist/clone-page-BSTWAPAJ.js.map +1 -0
- package/dist/close-CEMMAAM7.js +63 -0
- package/dist/close-CEMMAAM7.js.map +1 -0
- package/dist/close-QCWUNRAI.js +63 -0
- package/dist/close-QCWUNRAI.js.map +1 -0
- package/dist/connect-J3RVSEZF.js +107 -0
- package/dist/connect-J3RVSEZF.js.map +1 -0
- package/dist/console-poll-HL7BVIVX.js +76 -0
- package/dist/console-poll-HL7BVIVX.js.map +1 -0
- package/dist/cookie-import-WMUCIIHN.js +177 -0
- package/dist/cookie-import-WMUCIIHN.js.map +1 -0
- package/dist/cookie-list-PB2N4RPH.js +117 -0
- package/dist/cookie-list-PB2N4RPH.js.map +1 -0
- package/dist/daemon-5KSVMGN4.js +194 -0
- package/dist/daemon-5KSVMGN4.js.map +1 -0
- package/dist/daemon-fingerprint.json +1 -1
- package/dist/debug-trace-snapshot-RK7KDXA5.js +136 -0
- package/dist/debug-trace-snapshot-RK7KDXA5.js.map +1 -0
- package/dist/dialog-P6P4U7XE.js +75 -0
- package/dist/dialog-P6P4U7XE.js.map +1 -0
- package/dist/disconnect-32F7IDIP.js +58 -0
- package/dist/disconnect-32F7IDIP.js.map +1 -0
- package/dist/enabled-A6C6ZM2O.js +71 -0
- package/dist/enabled-A6C6ZM2O.js.map +1 -0
- package/dist/extension-extractor-GKWSFHPN.js +11 -0
- package/dist/extension-extractor-GKWSFHPN.js.map +1 -0
- package/dist/global-D6WLWBXA.js +56 -0
- package/dist/global-D6WLWBXA.js.map +1 -0
- package/dist/goto-ULTSABDM.js +98 -0
- package/dist/goto-ULTSABDM.js.map +1 -0
- package/dist/help-EKKKEDL5.js +491 -0
- package/dist/help-EKKKEDL5.js.map +1 -0
- package/dist/hover-UF2ZUMTQ.js +71 -0
- package/dist/hover-UF2ZUMTQ.js.map +1 -0
- package/dist/html-B6TX7GK7.js +84 -0
- package/dist/html-B6TX7GK7.js.map +1 -0
- package/dist/index.js +68 -34
- package/dist/index.js.map +1 -1
- package/dist/inspector-6S5FKUZQ.js +62 -0
- package/dist/inspector-6S5FKUZQ.js.map +1 -0
- package/dist/inspector-audit-ARGEGOS7.js +84 -0
- package/dist/inspector-audit-ARGEGOS7.js.map +1 -0
- package/dist/inspector-plan-CSG5HZOC.js +69 -0
- package/dist/inspector-plan-CSG5HZOC.js.map +1 -0
- package/dist/inspiredesign-7VRMMZN4.js +234 -0
- package/dist/inspiredesign-7VRMMZN4.js.map +1 -0
- package/dist/install-autostart-output-5DOMKCQL.js +41 -0
- package/dist/install-autostart-output-5DOMKCQL.js.map +1 -0
- package/dist/install-autostart-reconciliation-NHKOFYTD.js +73 -0
- package/dist/install-autostart-reconciliation-NHKOFYTD.js.map +1 -0
- package/dist/launch-REYCIR3Z.js +225 -0
- package/dist/launch-REYCIR3Z.js.map +1 -0
- package/dist/list-NPRXRQY2.js +51 -0
- package/dist/list-NPRXRQY2.js.map +1 -0
- package/dist/list-STYD2ZWA.js +54 -0
- package/dist/list-STYD2ZWA.js.map +1 -0
- package/dist/local-HXJLUUNT.js +54 -0
- package/dist/local-HXJLUUNT.js.map +1 -0
- package/dist/macro-resolve-ZIJZ65QI.js +253 -0
- package/dist/macro-resolve-ZIJZ65QI.js.map +1 -0
- package/dist/macros/execute-runtime.d.ts +3 -1
- package/dist/macros/execute-runtime.d.ts.map +1 -1
- package/dist/macros/execute.d.ts +2 -0
- package/dist/macros/execute.d.ts.map +1 -1
- package/dist/native-UPLVQ2SG.js +22 -0
- package/dist/native-UPLVQ2SG.js.map +1 -0
- package/dist/network-poll-HLDOSC72.js +76 -0
- package/dist/network-poll-HLDOSC72.js.map +1 -0
- package/dist/new-HXLLN6UT.js +69 -0
- package/dist/new-HXLLN6UT.js.map +1 -0
- package/dist/onboarding-metadata-7E3KLYSZ.js +27 -0
- package/dist/onboarding-metadata-7E3KLYSZ.js.map +1 -0
- package/dist/open-KDR25LQZ.js +81 -0
- package/dist/open-KDR25LQZ.js.map +1 -0
- package/dist/opendevbrowser.js +68 -34
- package/dist/opendevbrowser.js.map +1 -1
- package/dist/perf-EM6SWFJ6.js +58 -0
- package/dist/perf-EM6SWFJ6.js.map +1 -0
- package/dist/pointer-down-ZYWRZNCH.js +55 -0
- package/dist/pointer-down-ZYWRZNCH.js.map +1 -0
- package/dist/pointer-drag-LVEAVJO4.js +54 -0
- package/dist/pointer-drag-LVEAVJO4.js.map +1 -0
- package/dist/pointer-move-7SRKUS66.js +52 -0
- package/dist/pointer-move-7SRKUS66.js.map +1 -0
- package/dist/pointer-up-KLDBSK37.js +55 -0
- package/dist/pointer-up-KLDBSK37.js.map +1 -0
- package/dist/press-UIIXFTD7.js +83 -0
- package/dist/press-UIIXFTD7.js.map +1 -0
- package/dist/product-video-PYOXJVAI.js +235 -0
- package/dist/product-video-PYOXJVAI.js.map +1 -0
- package/dist/providers/artifacts.d.ts +0 -2
- package/dist/providers/artifacts.d.ts.map +1 -1
- package/dist/providers/blocker.d.ts.map +1 -1
- package/dist/providers/bounded-map.d.ts +2 -0
- package/dist/providers/bounded-map.d.ts.map +1 -0
- package/dist/providers/community/index.d.ts.map +1 -1
- package/dist/providers/constraint.d.ts.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/renderer.d.ts.map +1 -1
- package/dist/providers/research-compiler.d.ts +1 -1
- package/dist/providers/research-compiler.d.ts.map +1 -1
- package/dist/providers/research-executor.d.ts.map +1 -1
- package/dist/providers/runtime-factory.d.ts.map +1 -1
- package/dist/providers/shared/traversal-url.d.ts +3 -0
- package/dist/providers/shared/traversal-url.d.ts.map +1 -1
- package/dist/providers/shopping/index.d.ts.map +1 -1
- package/dist/providers/social/search-quality.d.ts.map +1 -1
- package/dist/providers/workflow-handoff.d.ts +4 -0
- package/dist/providers/workflow-handoff.d.ts.map +1 -1
- package/dist/providers/workflows.d.ts.map +1 -1
- package/dist/{providers-QF2RFB4J.js → providers-4YY2BLXG.js} +19 -14
- package/dist/providers-4YY2BLXG.js.map +1 -0
- package/dist/public-surface/generated-manifest.d.ts +2 -2
- package/dist/public-surface/generated-manifest.d.ts.map +1 -1
- package/dist/public-surface/source.d.ts +2 -2
- package/dist/public-surface/source.d.ts.map +1 -1
- package/dist/relay/protocol.d.ts +3 -1
- package/dist/relay/protocol.d.ts.map +1 -1
- package/dist/relay/relay-server.d.ts +6 -0
- package/dist/relay/relay-server.d.ts.map +1 -1
- package/dist/research-CKXMJ2DK.js +295 -0
- package/dist/research-CKXMJ2DK.js.map +1 -0
- package/dist/review-7HWJPZOD.js +48 -0
- package/dist/review-7HWJPZOD.js.map +1 -0
- package/dist/review-desktop-2IBJHFB5.js +54 -0
- package/dist/review-desktop-2IBJHFB5.js.map +1 -0
- package/dist/rpc-3HGIEJUO.js +159 -0
- package/dist/rpc-3HGIEJUO.js.map +1 -0
- package/dist/run-ADRYI3MS.js +180 -0
- package/dist/run-ADRYI3MS.js.map +1 -0
- package/dist/screencast-start-DTLUHD5H.js +67 -0
- package/dist/screencast-start-DTLUHD5H.js.map +1 -0
- package/dist/screencast-stop-54C5LRSS.js +59 -0
- package/dist/screencast-stop-54C5LRSS.js.map +1 -0
- package/dist/screenshot-HOAKR7P7.js +68 -0
- package/dist/screenshot-HOAKR7P7.js.map +1 -0
- package/dist/scroll-IAOO5COY.js +84 -0
- package/dist/scroll-IAOO5COY.js.map +1 -0
- package/dist/scroll-into-view-RKWSLAPH.js +71 -0
- package/dist/scroll-into-view-RKWSLAPH.js.map +1 -0
- package/dist/select-IGD3T6X4.js +86 -0
- package/dist/select-IGD3T6X4.js.map +1 -0
- package/dist/serve-7X4INUCU.js +498 -0
- package/dist/serve-7X4INUCU.js.map +1 -0
- package/dist/shopping-FC6DRW76.js +273 -0
- package/dist/shopping-FC6DRW76.js.map +1 -0
- package/dist/skill-lifecycle-5UAZGKSN.js +89 -0
- package/dist/skill-lifecycle-5UAZGKSN.js.map +1 -0
- package/dist/skills-NSXDX6YM.js +26 -0
- package/dist/skills-NSXDX6YM.js.map +1 -0
- package/dist/snapshot-X22GG324.js +113 -0
- package/dist/snapshot-X22GG324.js.map +1 -0
- package/dist/status-SP55LMNW.js +132 -0
- package/dist/status-SP55LMNW.js.map +1 -0
- package/dist/status-VH2WXIDG.js +35 -0
- package/dist/status-VH2WXIDG.js.map +1 -0
- package/dist/status-capabilities-YBERLRRA.js +57 -0
- package/dist/status-capabilities-YBERLRRA.js.map +1 -0
- package/dist/text-6TB5WNLI.js +84 -0
- package/dist/text-6TB5WNLI.js.map +1 -0
- package/dist/tools/macro_resolve.d.ts.map +1 -1
- package/dist/type-3UI3TQH3.js +94 -0
- package/dist/type-3UI3TQH3.js.map +1 -0
- package/dist/uncheck-5L3D2D4U.js +71 -0
- package/dist/uncheck-5L3D2D4U.js.map +1 -0
- package/dist/uninstall-KYKGJAX7.js +91 -0
- package/dist/uninstall-KYKGJAX7.js.map +1 -0
- package/dist/update-SMXPYGXS.js +305 -0
- package/dist/update-SMXPYGXS.js.map +1 -0
- package/dist/update-skill-modes-BVX7IVMW.js +38 -0
- package/dist/update-skill-modes-BVX7IVMW.js.map +1 -0
- package/dist/upload-YG4J2EMI.js +56 -0
- package/dist/upload-YG4J2EMI.js.map +1 -0
- package/dist/use-V3LGFP3K.js +63 -0
- package/dist/use-V3LGFP3K.js.map +1 -0
- package/dist/value-3247D57X.js +71 -0
- package/dist/value-3247D57X.js.map +1 -0
- package/dist/visible-A7HEV36U.js +71 -0
- package/dist/visible-A7HEV36U.js.map +1 -0
- package/dist/wait-UZPP4Y4R.js +109 -0
- package/dist/wait-UZPP4Y4R.js.map +1 -0
- package/dist/windows-76TR3AIP.js +37 -0
- package/dist/windows-76TR3AIP.js.map +1 -0
- package/extension/dist/background.js +99 -22
- package/extension/dist/ops/ops-runtime.js +85 -7
- package/extension/dist/ops/ops-session-store.js +3 -0
- package/extension/dist/ops/target-session-coordinator.js +3 -0
- package/extension/dist/services/CDPRouter.js +9 -0
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
- package/skills/opendevbrowser-best-practices/SKILL.md +8 -6
- package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +1 -1
- package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +3 -2
- package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +39 -2
- package/skills/opendevbrowser-research/SKILL.md +64 -12
- package/skills/opendevbrowser-research/artifacts/research-workflows.md +56 -19
- package/skills/opendevbrowser-research/assets/templates/compact.md +31 -5
- package/skills/opendevbrowser-research/assets/templates/context.json +52 -1
- package/skills/opendevbrowser-research/assets/templates/report.md +57 -4
- package/skills/opendevbrowser-research/examples/sample-input.json +1 -1
- package/skills/opendevbrowser-research/examples/sample-output.md +27 -2
- package/skills/opendevbrowser-research/scripts/run-research.sh +2 -6
- package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +115 -1
- package/dist/chunk-I5ZCOZZV.js.map +0 -1
- package/dist/chunk-QVWOPIZJ.js.map +0 -1
- package/dist/chunk-T3VVHJTK.js.map +0 -1
- /package/dist/{providers-QF2RFB4J.js.map → chunk-RJNI3BHT.js.map} +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import "./chunk-RJNI3BHT.js";
|
|
2
|
+
import {
|
|
3
|
+
parseOptionalStringFlag
|
|
4
|
+
} from "./chunk-RPXWUCQQ.js";
|
|
5
|
+
import {
|
|
6
|
+
callDaemon
|
|
7
|
+
} from "./chunk-OYNLAZQU.js";
|
|
8
|
+
import "./chunk-LBPELU7L.js";
|
|
9
|
+
import "./chunk-SXAGSEKZ.js";
|
|
10
|
+
import "./chunk-MX3NFLCE.js";
|
|
11
|
+
import "./chunk-ASMHEEKY.js";
|
|
12
|
+
import {
|
|
13
|
+
createUsageError
|
|
14
|
+
} from "./chunk-IPE7TF2P.js";
|
|
15
|
+
import "./chunk-STGGGVYT.js";
|
|
16
|
+
import "./chunk-3ILXPKSJ.js";
|
|
17
|
+
import "./chunk-TBUCZX4A.js";
|
|
18
|
+
import "./chunk-Y2KL55OG.js";
|
|
19
|
+
import "./chunk-5SWZDVOW.js";
|
|
20
|
+
import "./chunk-S6S2UP6U.js";
|
|
21
|
+
import "./chunk-S5KZQJJI.js";
|
|
22
|
+
import "./chunk-KZ2IXVQT.js";
|
|
23
|
+
import "./chunk-WHQZBUNY.js";
|
|
24
|
+
import "./chunk-FUSXMW3G.js";
|
|
25
|
+
|
|
26
|
+
// src/cli/commands/interact/select.ts
|
|
27
|
+
function parseSelectArgs(rawArgs) {
|
|
28
|
+
const parsed = {};
|
|
29
|
+
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
30
|
+
const arg = rawArgs[i];
|
|
31
|
+
if (arg === "--session-id") {
|
|
32
|
+
const value = rawArgs[i + 1];
|
|
33
|
+
if (!value) throw createUsageError("Missing value for --session-id");
|
|
34
|
+
parsed.sessionId = value;
|
|
35
|
+
i += 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (arg?.startsWith("--session-id=")) {
|
|
39
|
+
parsed.sessionId = arg.split("=", 2)[1];
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (arg === "--ref") {
|
|
43
|
+
const value = rawArgs[i + 1];
|
|
44
|
+
if (!value) throw createUsageError("Missing value for --ref");
|
|
45
|
+
parsed.ref = value;
|
|
46
|
+
i += 1;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (arg?.startsWith("--ref=")) {
|
|
50
|
+
parsed.ref = arg.split("=", 2)[1];
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (arg === "--values") {
|
|
54
|
+
const value = rawArgs[i + 1];
|
|
55
|
+
if (!value) throw createUsageError("Missing value for --values");
|
|
56
|
+
parsed.values = value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
57
|
+
i += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (arg?.startsWith("--values=")) {
|
|
61
|
+
const value = arg.split("=", 2)[1];
|
|
62
|
+
if (!value) throw createUsageError("Missing value for --values");
|
|
63
|
+
parsed.values = value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
69
|
+
async function runSelect(args) {
|
|
70
|
+
const { sessionId, ref, values } = parseSelectArgs(args.rawArgs);
|
|
71
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
72
|
+
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
73
|
+
if (!ref) throw createUsageError("Missing --ref");
|
|
74
|
+
if (!values || values.length === 0) throw createUsageError("Missing --values");
|
|
75
|
+
const result = await callDaemon("interact.select", {
|
|
76
|
+
sessionId,
|
|
77
|
+
ref,
|
|
78
|
+
values,
|
|
79
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
80
|
+
});
|
|
81
|
+
return { success: true, message: "Select complete.", data: result };
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
runSelect
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=select-IGD3T6X4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/interact/select.ts"],"sourcesContent":["import type { ParsedArgs } from \"../../args\";\nimport { callDaemon } from \"../../client\";\nimport { createUsageError } from \"../../errors\";\nimport { parseOptionalStringFlag } from \"../../utils/parse\";\n\nfunction parseSelectArgs(rawArgs: string[]): { sessionId?: string; ref?: string; values?: string[] } {\n const parsed: { sessionId?: string; ref?: string; values?: string[] } = {};\n for (let i = 0; i < rawArgs.length; i += 1) {\n const arg = rawArgs[i];\n if (arg === \"--session-id\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --session-id\");\n parsed.sessionId = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--session-id=\")) {\n parsed.sessionId = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--ref\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --ref\");\n parsed.ref = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--ref=\")) {\n parsed.ref = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--values\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --values\");\n parsed.values = value.split(\",\").map((entry) => entry.trim()).filter(Boolean);\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--values=\")) {\n const value = arg.split(\"=\", 2)[1];\n if (!value) throw createUsageError(\"Missing value for --values\");\n parsed.values = value.split(\",\").map((entry) => entry.trim()).filter(Boolean);\n continue;\n }\n }\n return parsed;\n}\n\nexport async function runSelect(args: ParsedArgs) {\n const { sessionId, ref, values } = parseSelectArgs(args.rawArgs);\n const targetId = parseOptionalStringFlag(args.rawArgs, \"--target-id\");\n if (!sessionId) throw createUsageError(\"Missing --session-id\");\n if (!ref) throw createUsageError(\"Missing --ref\");\n if (!values || values.length === 0) throw createUsageError(\"Missing --values\");\n const result = await callDaemon(\"interact.select\", {\n sessionId,\n ref,\n values,\n ...(typeof targetId === \"string\" ? { targetId } : {})\n });\n return { success: true, message: \"Select complete.\", data: result };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,SAAS,gBAAgB,SAA4E;AACnG,QAAM,SAAkE,CAAC;AACzE,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;AAC1C,UAAM,MAAM,QAAQ,CAAC;AACrB,QAAI,QAAQ,gBAAgB;AAC1B,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,gCAAgC;AACnE,aAAO,YAAY;AACnB,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,aAAO,YAAY,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AACtC;AAAA,IACF;AACA,QAAI,QAAQ,SAAS;AACnB,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,yBAAyB;AAC5D,aAAO,MAAM;AACb,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,aAAO,MAAM,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AAChC;AAAA,IACF;AACA,QAAI,QAAQ,YAAY;AACtB,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,4BAA4B;AAC/D,aAAO,SAAS,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO;AAC5E,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,WAAW,GAAG;AAChC,YAAM,QAAQ,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AACjC,UAAI,CAAC,MAAO,OAAM,iBAAiB,4BAA4B;AAC/D,aAAO,SAAS,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO;AAC5E;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,UAAU,MAAkB;AAChD,QAAM,EAAE,WAAW,KAAK,OAAO,IAAI,gBAAgB,KAAK,OAAO;AAC/D,QAAM,WAAW,wBAAwB,KAAK,SAAS,aAAa;AACpE,MAAI,CAAC,UAAW,OAAM,iBAAiB,sBAAsB;AAC7D,MAAI,CAAC,IAAK,OAAM,iBAAiB,eAAe;AAChD,MAAI,CAAC,UAAU,OAAO,WAAW,EAAG,OAAM,iBAAiB,kBAAkB;AAC7E,QAAM,SAAS,MAAM,WAAW,mBAAmB;AAAA,IACjD;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,OAAO,aAAa,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACrD,CAAC;AACD,SAAO,EAAE,SAAS,MAAM,SAAS,oBAAoB,MAAM,OAAO;AACpE;","names":[]}
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import {
|
|
2
|
+
discoverExtensionId,
|
|
3
|
+
getNativeStatusSnapshot,
|
|
4
|
+
installNativeHost
|
|
5
|
+
} from "./chunk-6PVZ2ABC.js";
|
|
6
|
+
import {
|
|
7
|
+
parseNumberFlag
|
|
8
|
+
} from "./chunk-RPXWUCQQ.js";
|
|
9
|
+
import {
|
|
10
|
+
createDaemonStopHeaders,
|
|
11
|
+
fetchDaemonStatus,
|
|
12
|
+
fetchWithTimeout,
|
|
13
|
+
isCurrentDaemonFingerprint,
|
|
14
|
+
readDaemonMetadata,
|
|
15
|
+
startDaemon
|
|
16
|
+
} from "./chunk-LBPELU7L.js";
|
|
17
|
+
import "./chunk-SXAGSEKZ.js";
|
|
18
|
+
import {
|
|
19
|
+
loadGlobalConfig
|
|
20
|
+
} from "./chunk-MX3NFLCE.js";
|
|
21
|
+
import "./chunk-ASMHEEKY.js";
|
|
22
|
+
import {
|
|
23
|
+
EXIT_DISCONNECTED,
|
|
24
|
+
EXIT_EXECUTION,
|
|
25
|
+
createUsageError
|
|
26
|
+
} from "./chunk-IPE7TF2P.js";
|
|
27
|
+
import "./chunk-STGGGVYT.js";
|
|
28
|
+
import "./chunk-3ILXPKSJ.js";
|
|
29
|
+
import "./chunk-TBUCZX4A.js";
|
|
30
|
+
import "./chunk-Y2KL55OG.js";
|
|
31
|
+
import "./chunk-5SWZDVOW.js";
|
|
32
|
+
import "./chunk-S6S2UP6U.js";
|
|
33
|
+
import "./chunk-S5KZQJJI.js";
|
|
34
|
+
import "./chunk-KZ2IXVQT.js";
|
|
35
|
+
import "./chunk-WHQZBUNY.js";
|
|
36
|
+
import "./chunk-FUSXMW3G.js";
|
|
37
|
+
|
|
38
|
+
// src/cli/commands/serve.ts
|
|
39
|
+
import { spawnSync } from "child_process";
|
|
40
|
+
var daemonHandle = null;
|
|
41
|
+
var PS_MAX_BUFFER = 8 * 1024 * 1024;
|
|
42
|
+
var DAEMON_SHUTDOWN_POLL_ATTEMPTS = 10;
|
|
43
|
+
var DAEMON_SHUTDOWN_POLL_DELAY_MS = 100;
|
|
44
|
+
var DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS = 250;
|
|
45
|
+
var DAEMON_STOP_TIMEOUT_MS = 1e3;
|
|
46
|
+
var PROCESS_TERMINATE_GRACE_MS = 250;
|
|
47
|
+
var MIN_PORT = 1;
|
|
48
|
+
var MAX_PORT = 65535;
|
|
49
|
+
var SERVE_COMMAND_PATTERN = /(?:^|\s)serve(?=\s|$)/;
|
|
50
|
+
var SERVE_PORT_SPLIT_PATTERN = /(?:^|\s)--port\s+(\d+)(?=\s|$)/;
|
|
51
|
+
var SERVE_PORT_EQUALS_PATTERN = /(?:^|\s)--port=(\d+)(?=\s|$)/;
|
|
52
|
+
var SERVE_STOP_PATTERN = /(?:^|\s)--stop(?:\s|$)/;
|
|
53
|
+
var CURRENT_UID = typeof process.getuid === "function" ? process.getuid() : null;
|
|
54
|
+
var CURRENT_EXECUTABLE = process.execPath;
|
|
55
|
+
var CURRENT_CLI_ENTRYPOINT = process.argv[1] ?? "";
|
|
56
|
+
function resolveTokenCandidates(requestedToken, metadataToken, configToken) {
|
|
57
|
+
return Array.from(new Set([requestedToken, metadataToken, configToken].filter((token) => typeof token === "string" && token.trim().length > 0)));
|
|
58
|
+
}
|
|
59
|
+
async function resolveExistingDaemon(port, tokens) {
|
|
60
|
+
for (const token of tokens) {
|
|
61
|
+
const status = await fetchDaemonStatus(port, token);
|
|
62
|
+
if (status?.ok) {
|
|
63
|
+
return { token, status };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
function isPositivePid(value) {
|
|
69
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
70
|
+
}
|
|
71
|
+
function parseServeArgs(rawArgs) {
|
|
72
|
+
const parsed = { stop: false };
|
|
73
|
+
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
74
|
+
const arg = rawArgs[i];
|
|
75
|
+
if (arg === "--stop") {
|
|
76
|
+
parsed.stop = true;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (arg === "--daemon") {
|
|
80
|
+
throw createUsageError("`serve --daemon` is not supported. Use `serve` for foreground mode, `daemon install` for autostart, or `status --daemon` to inspect the daemon.");
|
|
81
|
+
}
|
|
82
|
+
if (arg === "--port") {
|
|
83
|
+
const value = rawArgs[i + 1];
|
|
84
|
+
if (!value) {
|
|
85
|
+
throw createUsageError("Missing value for --port");
|
|
86
|
+
}
|
|
87
|
+
parsed.port = parseNumberFlag(value, "--port", { min: MIN_PORT, max: MAX_PORT });
|
|
88
|
+
i += 1;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (arg?.startsWith("--port=")) {
|
|
92
|
+
const value = arg.split("=", 2)[1];
|
|
93
|
+
if (!value) {
|
|
94
|
+
throw createUsageError("Missing value for --port");
|
|
95
|
+
}
|
|
96
|
+
parsed.port = parseNumberFlag(value, "--port", { min: MIN_PORT, max: MAX_PORT });
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (arg === "--token") {
|
|
100
|
+
const value = rawArgs[i + 1];
|
|
101
|
+
if (!value) {
|
|
102
|
+
throw createUsageError("Missing value for --token");
|
|
103
|
+
}
|
|
104
|
+
parsed.token = value;
|
|
105
|
+
i += 1;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (arg?.startsWith("--token=")) {
|
|
109
|
+
const value = arg.split("=", 2)[1];
|
|
110
|
+
if (!value) {
|
|
111
|
+
throw createUsageError("Missing value for --token");
|
|
112
|
+
}
|
|
113
|
+
parsed.token = value;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return parsed;
|
|
118
|
+
}
|
|
119
|
+
function parseServeProcessSnapshot(line) {
|
|
120
|
+
const trimmed = line.trim();
|
|
121
|
+
if (trimmed.length === 0) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const match = trimmed.match(/^(\d+)(?:\s+(\d+))?\s+(.*)$/);
|
|
125
|
+
if (!match) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const pid = Number.parseInt(match[1] ?? "", 10);
|
|
129
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const rawUid = match[2];
|
|
133
|
+
const parsedUid = typeof rawUid === "string" && rawUid.length > 0 ? Number.parseInt(rawUid, 10) : null;
|
|
134
|
+
const command = (match[3] ?? "").trim();
|
|
135
|
+
if (command.length === 0) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
pid,
|
|
140
|
+
uid: typeof parsedUid === "number" && Number.isInteger(parsedUid) && parsedUid >= 0 ? parsedUid : null,
|
|
141
|
+
command
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function parseServeCommandPort(command) {
|
|
145
|
+
const rawPort = command.match(SERVE_PORT_EQUALS_PATTERN)?.[1] ?? command.match(SERVE_PORT_SPLIT_PATTERN)?.[1];
|
|
146
|
+
if (!rawPort) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const port = Number.parseInt(rawPort, 10);
|
|
150
|
+
return Number.isInteger(port) && port >= MIN_PORT && port <= MAX_PORT ? port : null;
|
|
151
|
+
}
|
|
152
|
+
function listServeProcessSnapshots() {
|
|
153
|
+
const result = spawnSync("ps", ["-axww", "-o", "pid=,uid=,command="], {
|
|
154
|
+
encoding: "utf-8",
|
|
155
|
+
maxBuffer: PS_MAX_BUFFER
|
|
156
|
+
});
|
|
157
|
+
if ((result.status ?? 1) !== 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
return String(result.stdout ?? "").split("\n").map((line) => parseServeProcessSnapshot(line)).filter((snapshot) => snapshot !== null);
|
|
161
|
+
}
|
|
162
|
+
function readServeProcessEntrypoint(command) {
|
|
163
|
+
const tokens = command.trim().split(/\s+/u);
|
|
164
|
+
const executable = tokens[0] ?? "";
|
|
165
|
+
if (executable.length === 0) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return executable === CURRENT_EXECUTABLE ? tokens[1] ?? null : executable;
|
|
169
|
+
}
|
|
170
|
+
function isCurrentEntrypointServeProcess(snapshot) {
|
|
171
|
+
if (CURRENT_UID === null || snapshot.uid === null || snapshot.uid !== CURRENT_UID) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
const entrypoint = readServeProcessEntrypoint(snapshot.command);
|
|
175
|
+
if (!CURRENT_CLI_ENTRYPOINT || entrypoint !== CURRENT_CLI_ENTRYPOINT) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (!SERVE_COMMAND_PATTERN.test(snapshot.command)) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
return !SERVE_STOP_PATTERN.test(snapshot.command);
|
|
182
|
+
}
|
|
183
|
+
function isRequestedPortServeProcess(snapshot, requestedPort) {
|
|
184
|
+
return isCurrentEntrypointServeProcess(snapshot) && parseServeCommandPort(snapshot.command) === requestedPort;
|
|
185
|
+
}
|
|
186
|
+
async function terminateProcess(pid) {
|
|
187
|
+
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid || pid === process.ppid) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
process.kill(pid, "SIGTERM");
|
|
192
|
+
} catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
await new Promise((resolve) => setTimeout(resolve, PROCESS_TERMINATE_GRACE_MS));
|
|
196
|
+
try {
|
|
197
|
+
process.kill(pid, 0);
|
|
198
|
+
} catch {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
process.kill(pid, "SIGKILL");
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
async function cleanupCompetingServeProcesses(requestedPort, keepPid) {
|
|
208
|
+
const candidates = listServeProcessSnapshots().filter((snapshot) => {
|
|
209
|
+
if (!isRequestedPortServeProcess(snapshot, requestedPort)) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
if (snapshot.pid === process.pid || snapshot.pid === process.ppid) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
if (Number.isInteger(keepPid) && snapshot.pid === keepPid) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
return true;
|
|
219
|
+
});
|
|
220
|
+
if (candidates.length === 0) {
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
const clearedPids = [];
|
|
224
|
+
for (const snapshot of candidates) {
|
|
225
|
+
if (await terminateProcess(snapshot.pid)) {
|
|
226
|
+
clearedPids.push(snapshot.pid);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return clearedPids;
|
|
230
|
+
}
|
|
231
|
+
async function terminateServeProcessByPid(pid) {
|
|
232
|
+
if (!isPositivePid(pid)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
const snapshot = listServeProcessSnapshots().find((item) => item.pid === pid);
|
|
236
|
+
return snapshot ? isCurrentEntrypointServeProcess(snapshot) && await terminateProcess(pid) : false;
|
|
237
|
+
}
|
|
238
|
+
function isServeProcessRunningByPid(pid) {
|
|
239
|
+
if (!isPositivePid(pid)) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
return listServeProcessSnapshots().some((item) => {
|
|
243
|
+
return item.pid === pid && isCurrentEntrypointServeProcess(item);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
function buildStaleStopMessage(metadata) {
|
|
247
|
+
const pid = isPositivePid(metadata.pid) ? ` pid=${metadata.pid}` : "";
|
|
248
|
+
return `Daemon rejected stale stop request for 127.0.0.1:${metadata.port}${pid}. Run \`opendevbrowser status --daemon\` to inspect the active daemon, then restart from the current install if needed.`;
|
|
249
|
+
}
|
|
250
|
+
function buildProtectedMismatchMessage(port, status) {
|
|
251
|
+
return `Daemon on 127.0.0.1:${port} pid=${status.pid} is protected by a different opendevbrowser build. Run \`opendevbrowser status --daemon\` to inspect it, then restart from the current install.`;
|
|
252
|
+
}
|
|
253
|
+
async function waitForDaemonShutdown(port, token) {
|
|
254
|
+
for (let attempt = 0; attempt < DAEMON_SHUTDOWN_POLL_ATTEMPTS; attempt += 1) {
|
|
255
|
+
const status = await fetchDaemonStatus(port, token, { timeoutMs: DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS });
|
|
256
|
+
if (!status?.ok) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
await new Promise((resolve) => setTimeout(resolve, DAEMON_SHUTDOWN_POLL_DELAY_MS));
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
async function waitForServeProcessExit(pid) {
|
|
264
|
+
if (!isPositivePid(pid)) {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
for (let attempt = 0; attempt < DAEMON_SHUTDOWN_POLL_ATTEMPTS; attempt += 1) {
|
|
268
|
+
if (!isServeProcessRunningByPid(pid)) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
await new Promise((resolve) => setTimeout(resolve, DAEMON_SHUTDOWN_POLL_DELAY_MS));
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
async function confirmStoppedDaemon(port, token, pid) {
|
|
276
|
+
const statusStopped = await waitForDaemonShutdown(port, token);
|
|
277
|
+
const processStopped = await waitForServeProcessExit(pid);
|
|
278
|
+
return statusStopped && processStopped;
|
|
279
|
+
}
|
|
280
|
+
async function stopMismatchedDaemon(port, daemon) {
|
|
281
|
+
let response;
|
|
282
|
+
try {
|
|
283
|
+
response = await fetchWithTimeout(`http://127.0.0.1:${port}/stop`, {
|
|
284
|
+
method: "POST",
|
|
285
|
+
headers: createDaemonStopHeaders(daemon.token, "serve.upgrade")
|
|
286
|
+
}, DAEMON_STOP_TIMEOUT_MS);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
const status = await fetchDaemonStatus(port, daemon.token, {
|
|
289
|
+
timeoutMs: DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS
|
|
290
|
+
});
|
|
291
|
+
if (!status?.ok) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
295
|
+
return `Failed to stop mismatched daemon on 127.0.0.1:${port}: ${message}.`;
|
|
296
|
+
}
|
|
297
|
+
if (response.status === 409) {
|
|
298
|
+
return buildProtectedMismatchMessage(port, daemon.status);
|
|
299
|
+
}
|
|
300
|
+
if (!response.ok) {
|
|
301
|
+
return `Failed to stop mismatched daemon on 127.0.0.1:${port}: stop returned ${response.status}.`;
|
|
302
|
+
}
|
|
303
|
+
if (await waitForDaemonShutdown(port, daemon.token)) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
if (await terminateServeProcessByPid(daemon.status.pid)) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return `Timed out waiting for mismatched daemon on 127.0.0.1:${port} to stop.`;
|
|
310
|
+
}
|
|
311
|
+
async function prepareExistingDaemon(port, daemon) {
|
|
312
|
+
if (isCurrentDaemonFingerprint(daemon.status.fingerprint)) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
return await stopMismatchedDaemon(port, daemon);
|
|
316
|
+
}
|
|
317
|
+
function buildAlreadyRunningResult(port, status, fallbackRelayPort, clearedCount) {
|
|
318
|
+
const relayPort = status.relay.port ?? fallbackRelayPort;
|
|
319
|
+
const staleNote = clearedCount > 0 ? `
|
|
320
|
+
Cleared ${clearedCount} stale daemon process${clearedCount === 1 ? "" : "es"}.` : "";
|
|
321
|
+
return {
|
|
322
|
+
success: true,
|
|
323
|
+
message: `Daemon already running on 127.0.0.1:${port} (pid=${status.pid}, relay ${relayPort}).${staleNote}`,
|
|
324
|
+
data: {
|
|
325
|
+
port,
|
|
326
|
+
pid: status.pid,
|
|
327
|
+
relayPort,
|
|
328
|
+
alreadyRunning: true,
|
|
329
|
+
staleDaemonsCleared: clearedCount,
|
|
330
|
+
relay: status.relay
|
|
331
|
+
},
|
|
332
|
+
exitCode: null
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
async function runServe(args) {
|
|
336
|
+
const serveArgs = parseServeArgs(args.rawArgs);
|
|
337
|
+
if (serveArgs.stop) {
|
|
338
|
+
const metadata2 = readDaemonMetadata();
|
|
339
|
+
if (!metadata2) {
|
|
340
|
+
if (daemonHandle) {
|
|
341
|
+
await daemonHandle.stop();
|
|
342
|
+
daemonHandle = null;
|
|
343
|
+
return { success: true, message: "Daemon stopped." };
|
|
344
|
+
}
|
|
345
|
+
return { success: false, message: "Daemon not running.", exitCode: EXIT_DISCONNECTED };
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
const response = await fetchWithTimeout(`http://127.0.0.1:${metadata2.port}/stop`, {
|
|
349
|
+
method: "POST",
|
|
350
|
+
headers: createDaemonStopHeaders(metadata2.token, "serve.stop")
|
|
351
|
+
});
|
|
352
|
+
if (response.status === 409) {
|
|
353
|
+
return { success: false, message: buildStaleStopMessage(metadata2), exitCode: EXIT_EXECUTION };
|
|
354
|
+
}
|
|
355
|
+
if (!response.ok) {
|
|
356
|
+
throw new Error(`Stop failed (${response.status})`);
|
|
357
|
+
}
|
|
358
|
+
if (await confirmStoppedDaemon(metadata2.port, metadata2.token, metadata2.pid)) {
|
|
359
|
+
return { success: true, message: "Daemon stopped." };
|
|
360
|
+
}
|
|
361
|
+
if (await terminateServeProcessByPid(metadata2.pid)) {
|
|
362
|
+
return { success: true, message: "Daemon stopped." };
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
success: false,
|
|
366
|
+
message: `Timed out waiting for daemon on 127.0.0.1:${metadata2.port} to stop.`,
|
|
367
|
+
exitCode: EXIT_EXECUTION
|
|
368
|
+
};
|
|
369
|
+
} catch (error) {
|
|
370
|
+
if (await terminateServeProcessByPid(metadata2.pid)) {
|
|
371
|
+
return { success: true, message: "Daemon stopped." };
|
|
372
|
+
}
|
|
373
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
374
|
+
return { success: false, message: `Failed to stop daemon: ${message2}`, exitCode: EXIT_EXECUTION };
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const config = loadGlobalConfig();
|
|
378
|
+
const requestedPort = serveArgs.port ?? config.daemonPort;
|
|
379
|
+
const metadata = readDaemonMetadata();
|
|
380
|
+
const metadataToken = metadata?.port === requestedPort ? metadata.token : void 0;
|
|
381
|
+
const tokenCandidates = resolveTokenCandidates(serveArgs.token, metadataToken, config.daemonToken);
|
|
382
|
+
const existingDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
|
|
383
|
+
const staleDaemonPids = /* @__PURE__ */ new Set();
|
|
384
|
+
const staleCleared = () => staleDaemonPids.size;
|
|
385
|
+
if (existingDaemon) {
|
|
386
|
+
const mismatchMessage = await prepareExistingDaemon(requestedPort, existingDaemon);
|
|
387
|
+
if (mismatchMessage) {
|
|
388
|
+
return { success: false, message: mismatchMessage, exitCode: EXIT_EXECUTION };
|
|
389
|
+
}
|
|
390
|
+
if (isCurrentDaemonFingerprint(existingDaemon.status.fingerprint)) {
|
|
391
|
+
for (const pid of await cleanupCompetingServeProcesses(requestedPort, existingDaemon.status.pid)) {
|
|
392
|
+
staleDaemonPids.add(pid);
|
|
393
|
+
}
|
|
394
|
+
return buildAlreadyRunningResult(requestedPort, existingDaemon.status, config.relayPort, staleCleared());
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
for (const pid of await cleanupCompetingServeProcesses(requestedPort)) {
|
|
398
|
+
staleDaemonPids.add(pid);
|
|
399
|
+
}
|
|
400
|
+
let nativeStatus = getNativeStatusSnapshot();
|
|
401
|
+
let nativeMessage = null;
|
|
402
|
+
if (!nativeStatus.installed || nativeStatus.mismatch) {
|
|
403
|
+
const discovered = discoverExtensionId();
|
|
404
|
+
const extensionId = nativeStatus.expectedExtensionId ?? config.nativeExtensionId ?? discovered.extensionId ?? null;
|
|
405
|
+
const usedDiscovery = nativeStatus.expectedExtensionSource !== "config" && Boolean(extensionId);
|
|
406
|
+
const previousExtensionId = nativeStatus.extensionId;
|
|
407
|
+
if (extensionId) {
|
|
408
|
+
const installResult = installNativeHost(extensionId);
|
|
409
|
+
if (installResult.success) {
|
|
410
|
+
const suffix = usedDiscovery && discovered.matchedBy ? ` (auto-detected by ${discovered.matchedBy})` : "";
|
|
411
|
+
nativeMessage = nativeStatus.mismatch && previousExtensionId ? `Native host reinstalled for extension ${extensionId} (replacing stale ${previousExtensionId}).${suffix}` : `${installResult.message ?? "Native host installed."}${suffix}`;
|
|
412
|
+
nativeStatus = getNativeStatusSnapshot();
|
|
413
|
+
} else {
|
|
414
|
+
nativeMessage = nativeStatus.mismatch ? `Native host reinstall skipped: ${installResult.message ?? "unknown error"}` : `Native host install skipped: ${installResult.message ?? "unknown error"}`;
|
|
415
|
+
}
|
|
416
|
+
} else if (nativeStatus.mismatch && previousExtensionId) {
|
|
417
|
+
nativeMessage = `Native host targets stale extension ${previousExtensionId}, but no current extension id could be resolved for reinstall.`;
|
|
418
|
+
} else {
|
|
419
|
+
nativeMessage = "Native host not installed. Set nativeExtensionId in opendevbrowser.jsonc to auto-install.";
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
let handle = null;
|
|
423
|
+
let startError = null;
|
|
424
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
425
|
+
try {
|
|
426
|
+
handle = await startDaemon({
|
|
427
|
+
port: serveArgs.port,
|
|
428
|
+
token: serveArgs.token,
|
|
429
|
+
config
|
|
430
|
+
});
|
|
431
|
+
startError = null;
|
|
432
|
+
break;
|
|
433
|
+
} catch (error) {
|
|
434
|
+
startError = error;
|
|
435
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
436
|
+
if (!message2.includes("EADDRINUSE") && !message2.includes("in use")) {
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
const runningDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
|
|
440
|
+
if (runningDaemon) {
|
|
441
|
+
const mismatchMessage = await prepareExistingDaemon(requestedPort, runningDaemon);
|
|
442
|
+
if (mismatchMessage) {
|
|
443
|
+
return { success: false, message: mismatchMessage, exitCode: EXIT_EXECUTION };
|
|
444
|
+
}
|
|
445
|
+
if (isCurrentDaemonFingerprint(runningDaemon.status.fingerprint)) {
|
|
446
|
+
return buildAlreadyRunningResult(requestedPort, runningDaemon.status, config.relayPort, staleCleared());
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (attempt === 0) {
|
|
450
|
+
let clearedNewPid = false;
|
|
451
|
+
for (const pid of await cleanupCompetingServeProcesses(requestedPort)) {
|
|
452
|
+
const previousSize = staleDaemonPids.size;
|
|
453
|
+
staleDaemonPids.add(pid);
|
|
454
|
+
if (staleDaemonPids.size > previousSize) {
|
|
455
|
+
clearedNewPid = true;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (clearedNewPid) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (!handle) {
|
|
466
|
+
const message2 = startError instanceof Error ? startError.message : String(startError);
|
|
467
|
+
if (message2.includes("EADDRINUSE") || message2.includes("in use")) {
|
|
468
|
+
return {
|
|
469
|
+
success: false,
|
|
470
|
+
message: `Daemon port ${requestedPort} is already in use by another process. If this is an existing daemon, run \`opendevbrowser status --daemon\` or \`opendevbrowser serve --stop\`.`,
|
|
471
|
+
exitCode: EXIT_EXECUTION
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
success: false,
|
|
476
|
+
message: `Failed to start daemon: ${message2}`,
|
|
477
|
+
exitCode: EXIT_EXECUTION
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
daemonHandle = handle;
|
|
481
|
+
const { state } = handle;
|
|
482
|
+
const baseMessage = `Daemon running on 127.0.0.1:${state.port} (relay ${state.relayPort})`;
|
|
483
|
+
const clearedCount = staleCleared();
|
|
484
|
+
const staleNote = clearedCount > 0 ? `
|
|
485
|
+
Cleared ${clearedCount} stale daemon process${clearedCount === 1 ? "" : "es"}.` : "";
|
|
486
|
+
const message = nativeMessage ? `${baseMessage}
|
|
487
|
+
${nativeMessage}${staleNote}` : `${baseMessage}${staleNote}`;
|
|
488
|
+
return {
|
|
489
|
+
success: true,
|
|
490
|
+
message,
|
|
491
|
+
data: { port: state.port, pid: state.pid, relayPort: state.relayPort, native: nativeStatus, staleDaemonsCleared: clearedCount },
|
|
492
|
+
exitCode: null
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
export {
|
|
496
|
+
runServe
|
|
497
|
+
};
|
|
498
|
+
//# sourceMappingURL=serve-7X4INUCU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/serve.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport type { ParsedArgs } from \"../args\";\nimport {\n createDaemonStopHeaders,\n isCurrentDaemonFingerprint,\n readDaemonMetadata,\n startDaemon\n} from \"../daemon\";\nimport { loadGlobalConfig } from \"../../config\";\nimport { createUsageError, EXIT_DISCONNECTED, EXIT_EXECUTION } from \"../errors\";\nimport { parseNumberFlag } from \"../utils/parse\";\nimport { fetchWithTimeout } from \"../utils/http\";\nimport { discoverExtensionId, getNativeStatusSnapshot, installNativeHost } from \"./native\";\nimport type { DaemonStatusPayload } from \"../daemon-status\";\nimport { fetchDaemonStatus } from \"../daemon-status\";\n\ntype ServeArgs = {\n port?: number;\n token?: string;\n stop: boolean;\n};\n\ntype DaemonHandle = {\n stop: () => Promise<void>;\n};\n\ntype ExistingDaemon = {\n token: string;\n status: DaemonStatusPayload;\n};\n\ntype ServeProcessSnapshot = {\n pid: number;\n uid: number | null;\n command: string;\n};\n\nlet daemonHandle: DaemonHandle | null = null;\nconst PS_MAX_BUFFER = 8 * 1024 * 1024;\nconst DAEMON_SHUTDOWN_POLL_ATTEMPTS = 10;\nconst DAEMON_SHUTDOWN_POLL_DELAY_MS = 100;\nconst DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS = 250;\nconst DAEMON_STOP_TIMEOUT_MS = 1000;\nconst PROCESS_TERMINATE_GRACE_MS = 250;\nconst MIN_PORT = 1;\nconst MAX_PORT = 65535;\nconst SERVE_COMMAND_PATTERN = /(?:^|\\s)serve(?=\\s|$)/;\nconst SERVE_PORT_SPLIT_PATTERN = /(?:^|\\s)--port\\s+(\\d+)(?=\\s|$)/;\nconst SERVE_PORT_EQUALS_PATTERN = /(?:^|\\s)--port=(\\d+)(?=\\s|$)/;\nconst SERVE_STOP_PATTERN = /(?:^|\\s)--stop(?:\\s|$)/;\nconst CURRENT_UID = typeof process.getuid === \"function\" ? process.getuid() : null;\nconst CURRENT_EXECUTABLE = process.execPath;\nconst CURRENT_CLI_ENTRYPOINT = process.argv[1] ?? \"\";\n\nfunction resolveTokenCandidates(\n requestedToken: string | undefined,\n metadataToken: string | undefined,\n configToken: string | undefined\n): string[] {\n return Array.from(new Set([requestedToken, metadataToken, configToken].filter((token): token is string => (\n typeof token === \"string\" && token.trim().length > 0\n ))));\n}\n\nasync function resolveExistingDaemon(\n port: number,\n tokens: string[]\n): Promise<ExistingDaemon | null> {\n for (const token of tokens) {\n const status = await fetchDaemonStatus(port, token);\n if (status?.ok) {\n return { token, status };\n }\n }\n return null;\n}\n\nfunction isPositivePid(value: unknown): value is number {\n return typeof value === \"number\" && Number.isInteger(value) && value > 0;\n}\n\nfunction parseServeArgs(rawArgs: string[]): ServeArgs {\n const parsed: ServeArgs = { stop: false };\n for (let i = 0; i < rawArgs.length; i += 1) {\n const arg = rawArgs[i];\n if (arg === \"--stop\") {\n parsed.stop = true;\n continue;\n }\n if (arg === \"--daemon\") {\n throw createUsageError(\"`serve --daemon` is not supported. Use `serve` for foreground mode, `daemon install` for autostart, or `status --daemon` to inspect the daemon.\");\n }\n if (arg === \"--port\") {\n const value = rawArgs[i + 1];\n if (!value) {\n throw createUsageError(\"Missing value for --port\");\n }\n parsed.port = parseNumberFlag(value, \"--port\", { min: MIN_PORT, max: MAX_PORT });\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--port=\")) {\n const value = arg.split(\"=\", 2)[1];\n if (!value) {\n throw createUsageError(\"Missing value for --port\");\n }\n parsed.port = parseNumberFlag(value, \"--port\", { min: MIN_PORT, max: MAX_PORT });\n continue;\n }\n if (arg === \"--token\") {\n const value = rawArgs[i + 1];\n if (!value) {\n throw createUsageError(\"Missing value for --token\");\n }\n parsed.token = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--token=\")) {\n const value = arg.split(\"=\", 2)[1];\n if (!value) {\n throw createUsageError(\"Missing value for --token\");\n }\n parsed.token = value;\n continue;\n }\n }\n return parsed;\n}\n\nfunction parseServeProcessSnapshot(line: string): ServeProcessSnapshot | null {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n return null;\n }\n const match = trimmed.match(/^(\\d+)(?:\\s+(\\d+))?\\s+(.*)$/);\n if (!match) {\n return null;\n }\n const pid = Number.parseInt(match[1] ?? \"\", 10);\n if (!Number.isInteger(pid) || pid <= 0) {\n return null;\n }\n const rawUid = match[2];\n const parsedUid = typeof rawUid === \"string\" && rawUid.length > 0\n ? Number.parseInt(rawUid, 10)\n : null;\n const command = (match[3] ?? \"\").trim();\n if (command.length === 0) {\n return null;\n }\n return {\n pid,\n uid: typeof parsedUid === \"number\" && Number.isInteger(parsedUid) && parsedUid >= 0 ? parsedUid : null,\n command\n };\n}\n\nfunction parseServeCommandPort(command: string): number | null {\n const rawPort = command.match(SERVE_PORT_EQUALS_PATTERN)?.[1]\n ?? command.match(SERVE_PORT_SPLIT_PATTERN)?.[1];\n if (!rawPort) {\n return null;\n }\n const port = Number.parseInt(rawPort, 10);\n return Number.isInteger(port) && port >= MIN_PORT && port <= MAX_PORT ? port : null;\n}\n\nfunction listServeProcessSnapshots(): ServeProcessSnapshot[] {\n const result = spawnSync(\"ps\", [\"-axww\", \"-o\", \"pid=,uid=,command=\"], {\n encoding: \"utf-8\",\n maxBuffer: PS_MAX_BUFFER\n });\n if ((result.status ?? 1) !== 0) {\n return [];\n }\n return String(result.stdout ?? \"\")\n .split(\"\\n\")\n .map((line) => parseServeProcessSnapshot(line))\n .filter((snapshot): snapshot is ServeProcessSnapshot => snapshot !== null);\n}\n\nfunction readServeProcessEntrypoint(command: string): string | null {\n const tokens = command.trim().split(/\\s+/u);\n const executable = tokens[0] ?? \"\";\n if (executable.length === 0) {\n return null;\n }\n return executable === CURRENT_EXECUTABLE ? (tokens[1] ?? null) : executable;\n}\n\nfunction isCurrentEntrypointServeProcess(snapshot: ServeProcessSnapshot): boolean {\n if (CURRENT_UID === null || snapshot.uid === null || snapshot.uid !== CURRENT_UID) {\n return false;\n }\n const entrypoint = readServeProcessEntrypoint(snapshot.command);\n if (!CURRENT_CLI_ENTRYPOINT || entrypoint !== CURRENT_CLI_ENTRYPOINT) {\n return false;\n }\n if (!SERVE_COMMAND_PATTERN.test(snapshot.command)) {\n return false;\n }\n return !SERVE_STOP_PATTERN.test(snapshot.command);\n}\n\nfunction isRequestedPortServeProcess(snapshot: ServeProcessSnapshot, requestedPort: number): boolean {\n return isCurrentEntrypointServeProcess(snapshot)\n && parseServeCommandPort(snapshot.command) === requestedPort;\n}\n\nasync function terminateProcess(pid: number): Promise<boolean> {\n if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid || pid === process.ppid) {\n return false;\n }\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n return false;\n }\n await new Promise((resolve) => setTimeout(resolve, PROCESS_TERMINATE_GRACE_MS));\n try {\n process.kill(pid, 0);\n } catch {\n return true;\n }\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n // process may have exited after SIGTERM\n }\n return true;\n}\n\nasync function cleanupCompetingServeProcesses(requestedPort: number, keepPid?: number): Promise<number[]> {\n const candidates = listServeProcessSnapshots().filter((snapshot) => {\n if (!isRequestedPortServeProcess(snapshot, requestedPort)) {\n return false;\n }\n if (snapshot.pid === process.pid || snapshot.pid === process.ppid) {\n return false;\n }\n if (Number.isInteger(keepPid) && snapshot.pid === keepPid) {\n return false;\n }\n return true;\n });\n if (candidates.length === 0) {\n return [];\n }\n\n const clearedPids: number[] = [];\n for (const snapshot of candidates) {\n if (await terminateProcess(snapshot.pid)) {\n clearedPids.push(snapshot.pid);\n }\n }\n\n return clearedPids;\n}\n\nasync function terminateServeProcessByPid(pid?: number): Promise<boolean> {\n if (!isPositivePid(pid)) {\n return false;\n }\n const snapshot = listServeProcessSnapshots().find((item) => item.pid === pid);\n return snapshot ? isCurrentEntrypointServeProcess(snapshot) && await terminateProcess(pid) : false;\n}\n\nfunction isServeProcessRunningByPid(pid?: number): boolean {\n if (!isPositivePid(pid)) {\n return false;\n }\n return listServeProcessSnapshots().some((item) => {\n return item.pid === pid && isCurrentEntrypointServeProcess(item);\n });\n}\n\nfunction buildStaleStopMessage(metadata: NonNullable<ReturnType<typeof readDaemonMetadata>>): string {\n const pid = isPositivePid(metadata.pid) ? ` pid=${metadata.pid}` : \"\";\n return `Daemon rejected stale stop request for 127.0.0.1:${metadata.port}${pid}. Run \\`opendevbrowser status --daemon\\` to inspect the active daemon, then restart from the current install if needed.`;\n}\n\nfunction buildProtectedMismatchMessage(port: number, status: DaemonStatusPayload): string {\n return `Daemon on 127.0.0.1:${port} pid=${status.pid} is protected by a different opendevbrowser build. Run \\`opendevbrowser status --daemon\\` to inspect it, then restart from the current install.`;\n}\n\nasync function waitForDaemonShutdown(port: number, token: string): Promise<boolean> {\n for (let attempt = 0; attempt < DAEMON_SHUTDOWN_POLL_ATTEMPTS; attempt += 1) {\n const status = await fetchDaemonStatus(port, token, { timeoutMs: DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS });\n if (!status?.ok) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, DAEMON_SHUTDOWN_POLL_DELAY_MS));\n }\n return false;\n}\n\nasync function waitForServeProcessExit(pid?: number): Promise<boolean> {\n if (!isPositivePid(pid)) {\n return true;\n }\n for (let attempt = 0; attempt < DAEMON_SHUTDOWN_POLL_ATTEMPTS; attempt += 1) {\n if (!isServeProcessRunningByPid(pid)) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, DAEMON_SHUTDOWN_POLL_DELAY_MS));\n }\n return false;\n}\n\nasync function confirmStoppedDaemon(port: number, token: string, pid?: number): Promise<boolean> {\n const statusStopped = await waitForDaemonShutdown(port, token);\n const processStopped = await waitForServeProcessExit(pid);\n return statusStopped && processStopped;\n}\n\nasync function stopMismatchedDaemon(port: number, daemon: ExistingDaemon): Promise<string | null> {\n let response: Response;\n try {\n response = await fetchWithTimeout(`http://127.0.0.1:${port}/stop`, {\n method: \"POST\",\n headers: createDaemonStopHeaders(daemon.token, \"serve.upgrade\")\n }, DAEMON_STOP_TIMEOUT_MS);\n } catch (error) {\n const status = await fetchDaemonStatus(port, daemon.token, {\n timeoutMs: DAEMON_SHUTDOWN_STATUS_TIMEOUT_MS\n });\n if (!status?.ok) {\n return null;\n }\n const message = error instanceof Error ? error.message : String(error);\n return `Failed to stop mismatched daemon on 127.0.0.1:${port}: ${message}.`;\n }\n if (response.status === 409) {\n return buildProtectedMismatchMessage(port, daemon.status);\n }\n if (!response.ok) {\n return `Failed to stop mismatched daemon on 127.0.0.1:${port}: stop returned ${response.status}.`;\n }\n if (await waitForDaemonShutdown(port, daemon.token)) {\n return null;\n }\n if (await terminateServeProcessByPid(daemon.status.pid)) {\n return null;\n }\n return `Timed out waiting for mismatched daemon on 127.0.0.1:${port} to stop.`;\n}\n\nasync function prepareExistingDaemon(port: number, daemon: ExistingDaemon): Promise<string | null> {\n if (isCurrentDaemonFingerprint(daemon.status.fingerprint)) {\n return null;\n }\n return await stopMismatchedDaemon(port, daemon);\n}\n\nfunction buildAlreadyRunningResult(\n port: number,\n status: DaemonStatusPayload,\n fallbackRelayPort: number,\n clearedCount: number\n) {\n const relayPort = status.relay.port ?? fallbackRelayPort;\n const staleNote = clearedCount > 0 ? `\\nCleared ${clearedCount} stale daemon process${clearedCount === 1 ? \"\" : \"es\"}.` : \"\";\n return {\n success: true,\n message: `Daemon already running on 127.0.0.1:${port} (pid=${status.pid}, relay ${relayPort}).${staleNote}`,\n data: {\n port,\n pid: status.pid,\n relayPort,\n alreadyRunning: true,\n staleDaemonsCleared: clearedCount,\n relay: status.relay\n },\n exitCode: null\n };\n}\n\nexport async function runServe(args: ParsedArgs) {\n const serveArgs = parseServeArgs(args.rawArgs);\n\n if (serveArgs.stop) {\n const metadata = readDaemonMetadata();\n if (!metadata) {\n if (daemonHandle) {\n await daemonHandle.stop();\n daemonHandle = null;\n return { success: true, message: \"Daemon stopped.\" };\n }\n return { success: false, message: \"Daemon not running.\", exitCode: EXIT_DISCONNECTED };\n }\n\n try {\n const response = await fetchWithTimeout(`http://127.0.0.1:${metadata.port}/stop`, {\n method: \"POST\",\n headers: createDaemonStopHeaders(metadata.token, \"serve.stop\")\n });\n if (response.status === 409) {\n return { success: false, message: buildStaleStopMessage(metadata), exitCode: EXIT_EXECUTION };\n }\n if (!response.ok) {\n throw new Error(`Stop failed (${response.status})`);\n }\n if (await confirmStoppedDaemon(metadata.port, metadata.token, metadata.pid)) {\n return { success: true, message: \"Daemon stopped.\" };\n }\n if (await terminateServeProcessByPid(metadata.pid)) {\n return { success: true, message: \"Daemon stopped.\" };\n }\n return {\n success: false,\n message: `Timed out waiting for daemon on 127.0.0.1:${metadata.port} to stop.`,\n exitCode: EXIT_EXECUTION\n };\n } catch (error) {\n if (await terminateServeProcessByPid(metadata.pid)) {\n return { success: true, message: \"Daemon stopped.\" };\n }\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, message: `Failed to stop daemon: ${message}`, exitCode: EXIT_EXECUTION };\n }\n }\n\n const config = loadGlobalConfig();\n const requestedPort = serveArgs.port ?? config.daemonPort;\n const metadata = readDaemonMetadata();\n const metadataToken = metadata?.port === requestedPort ? metadata.token : undefined;\n const tokenCandidates = resolveTokenCandidates(serveArgs.token, metadataToken, config.daemonToken);\n const existingDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);\n const staleDaemonPids = new Set<number>();\n const staleCleared = () => staleDaemonPids.size;\n\n if (existingDaemon) {\n const mismatchMessage = await prepareExistingDaemon(requestedPort, existingDaemon);\n if (mismatchMessage) {\n return { success: false, message: mismatchMessage, exitCode: EXIT_EXECUTION };\n }\n if (isCurrentDaemonFingerprint(existingDaemon.status.fingerprint)) {\n for (const pid of await cleanupCompetingServeProcesses(requestedPort, existingDaemon.status.pid)) {\n staleDaemonPids.add(pid);\n }\n return buildAlreadyRunningResult(requestedPort, existingDaemon.status, config.relayPort, staleCleared());\n }\n }\n\n for (const pid of await cleanupCompetingServeProcesses(requestedPort)) {\n staleDaemonPids.add(pid);\n }\n\n let nativeStatus = getNativeStatusSnapshot();\n let nativeMessage: string | null = null;\n if (!nativeStatus.installed || nativeStatus.mismatch) {\n const discovered = discoverExtensionId();\n const extensionId = nativeStatus.expectedExtensionId ?? config.nativeExtensionId ?? discovered.extensionId ?? null;\n const usedDiscovery = nativeStatus.expectedExtensionSource !== \"config\" && Boolean(extensionId);\n const previousExtensionId = nativeStatus.extensionId;\n if (extensionId) {\n const installResult = installNativeHost(extensionId);\n if (installResult.success) {\n const suffix = usedDiscovery && discovered.matchedBy ? ` (auto-detected by ${discovered.matchedBy})` : \"\";\n nativeMessage = nativeStatus.mismatch && previousExtensionId\n ? `Native host reinstalled for extension ${extensionId} (replacing stale ${previousExtensionId}).${suffix}`\n : `${installResult.message ?? \"Native host installed.\"}${suffix}`;\n nativeStatus = getNativeStatusSnapshot();\n } else {\n nativeMessage = nativeStatus.mismatch\n ? `Native host reinstall skipped: ${installResult.message ?? \"unknown error\"}`\n : `Native host install skipped: ${installResult.message ?? \"unknown error\"}`;\n }\n } else if (nativeStatus.mismatch && previousExtensionId) {\n nativeMessage = `Native host targets stale extension ${previousExtensionId}, but no current extension id could be resolved for reinstall.`;\n } else {\n nativeMessage = \"Native host not installed. Set nativeExtensionId in opendevbrowser.jsonc to auto-install.\";\n }\n }\n\n let handle: Awaited<ReturnType<typeof startDaemon>> | null = null;\n let startError: unknown = null;\n for (let attempt = 0; attempt < 2; attempt += 1) {\n try {\n handle = await startDaemon({\n port: serveArgs.port,\n token: serveArgs.token,\n config\n });\n startError = null;\n break;\n } catch (error) {\n startError = error;\n const message = error instanceof Error ? error.message : String(error);\n if (!message.includes(\"EADDRINUSE\") && !message.includes(\"in use\")) {\n break;\n }\n const runningDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);\n if (runningDaemon) {\n const mismatchMessage = await prepareExistingDaemon(requestedPort, runningDaemon);\n if (mismatchMessage) {\n return { success: false, message: mismatchMessage, exitCode: EXIT_EXECUTION };\n }\n if (isCurrentDaemonFingerprint(runningDaemon.status.fingerprint)) {\n return buildAlreadyRunningResult(requestedPort, runningDaemon.status, config.relayPort, staleCleared());\n }\n }\n if (attempt === 0) {\n let clearedNewPid = false;\n for (const pid of await cleanupCompetingServeProcesses(requestedPort)) {\n const previousSize = staleDaemonPids.size;\n staleDaemonPids.add(pid);\n if (staleDaemonPids.size > previousSize) {\n clearedNewPid = true;\n }\n }\n if (clearedNewPid) {\n continue;\n }\n }\n break;\n }\n }\n\n if (!handle) {\n const message = startError instanceof Error ? startError.message : String(startError);\n if (message.includes(\"EADDRINUSE\") || message.includes(\"in use\")) {\n return {\n success: false,\n message: `Daemon port ${requestedPort} is already in use by another process. If this is an existing daemon, run \\`opendevbrowser status --daemon\\` or \\`opendevbrowser serve --stop\\`.`,\n exitCode: EXIT_EXECUTION\n };\n }\n return {\n success: false,\n message: `Failed to start daemon: ${message}`,\n exitCode: EXIT_EXECUTION\n };\n }\n\n daemonHandle = handle;\n const { state } = handle;\n\n const baseMessage = `Daemon running on 127.0.0.1:${state.port} (relay ${state.relayPort})`;\n const clearedCount = staleCleared();\n const staleNote = clearedCount > 0 ? `\\nCleared ${clearedCount} stale daemon process${clearedCount === 1 ? \"\" : \"es\"}.` : \"\";\n const message = nativeMessage\n ? `${baseMessage}\\n${nativeMessage}${staleNote}`\n : `${baseMessage}${staleNote}`;\n\n return {\n success: true,\n message,\n data: { port: state.port, pid: state.pid, relayPort: state.relayPort, native: nativeStatus, staleDaemonsCleared: clearedCount },\n exitCode: null\n };\n}\n"],"mappings":"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","names":["metadata","message"]}
|