@svenroth-ai/shipwright 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/dist/assets/{EmbeddedTerminal-5QvKe3_a.js → EmbeddedTerminal-CqCQUDtp.js} +1 -1
- package/client/dist/assets/{abnfDiagram-VRR7QNED-CXi9HegQ.js → abnfDiagram-VRR7QNED-DX2objTP.js} +1 -1
- package/client/dist/assets/{arc-DLh4GiqR.js → arc-DQmjbsFU.js} +1 -1
- package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DUypQ8dQ.js → architectureDiagram-ZJ3FMSHR-DAvCsPCW.js} +1 -1
- package/client/dist/assets/{blockDiagram-677ZJIJ3-D2cVMKJG.js → blockDiagram-677ZJIJ3-DC-dlyYI.js} +1 -1
- package/client/dist/assets/{c4Diagram-LMCZKHZV-DtruBGJw.js → c4Diagram-LMCZKHZV-DSlmXfhE.js} +1 -1
- package/client/dist/assets/channel-BfmIcrp7.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-CAfQkFw2.js → chunk-2Q5K7J3B-C111EHL6.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-CPWXoLnQ.js → chunk-32BRIVSS-DrCYs2XG.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-xVc3oppQ.js → chunk-5VM5RSS4-DIejoaXS.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-CUpl6fRR.js → chunk-EX3LRPZG-CGWNeH2g.js} +1 -1
- package/client/dist/assets/{chunk-JWPE2WC7-NejUp56x.js → chunk-JWPE2WC7-CCH0SRFY.js} +1 -1
- package/client/dist/assets/{chunk-MOJQB5TN-C9-2lLg0.js → chunk-MOJQB5TN-B3OpZGRv.js} +1 -1
- package/client/dist/assets/{chunk-RYQCIY6F-BAPtwABy.js → chunk-RYQCIY6F-BKhdp_8v.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-Dwzihw26.js → chunk-V7JOEXUC-B6Bu8x1y.js} +1 -1
- package/client/dist/assets/{chunk-VR4S4FIN-9-iArFJM.js → chunk-VR4S4FIN-OgFi2_iB.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-DiWHOrqe.js → chunk-XXDRQBXY-xyjuuhxl.js} +1 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-HfUQZ6Uc.js +1 -0
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-HfUQZ6Uc.js +1 -0
- package/client/dist/assets/{cose-bilkent-JH36ORCC-Cp04EOcH.js → cose-bilkent-JH36ORCC-BQIH3SCK.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-D--GN1v8.js → cynefin-VYW2F7L2-oyLAz8te.js} +1 -1
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-BGH0o_qp.js → cynefinDiagram-TSTJHNR4-DoLCsH0l.js} +1 -1
- package/client/dist/assets/{dagre-VKFMJZFB-DSKkIKlj.js → dagre-VKFMJZFB-D7djx1_Y.js} +1 -1
- package/client/dist/assets/{diagram-FQU43EPY-Cs_C4lb-.js → diagram-FQU43EPY-DFuYE0Vf.js} +1 -1
- package/client/dist/assets/{diagram-G47NLZAW-oDtAA8O_.js → diagram-G47NLZAW-CffCZVXk.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-BiFMjqSH.js → diagram-NH7WQ7WH-BhrHtUlt.js} +1 -1
- package/client/dist/assets/{diagram-OA4YK3LP-Ccs3thCj.js → diagram-OA4YK3LP-CwQPbOn0.js} +1 -1
- package/client/dist/assets/{diagram-WEI45ONY-CdZNqgO3.js → diagram-WEI45ONY-abtYnYqH.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-CapTA0VL.js → ebnfDiagram-CCIWWBDH-DfV7gT4m.js} +1 -1
- package/client/dist/assets/{erDiagram-Q63AITRT-BcRNEP8s.js → erDiagram-Q63AITRT-vtbCprgH.js} +1 -1
- package/client/dist/assets/{flowDiagram-23GEKE2U-CJ_zF7e_.js → flowDiagram-23GEKE2U-CVCgcyDF.js} +1 -1
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-CnJdcg9A.js → ganttDiagram-NO4QXBWP-BclyOgMb.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-YTUQ_ELk.js → gitGraphDiagram-IHSO6WYX-BXT4rIKj.js} +1 -1
- package/client/dist/assets/index-CKU9dY18.css +1 -0
- package/client/dist/assets/index-DOMl6atu.js +847 -0
- package/client/dist/assets/{infoDiagram-FWYZ7A6U-CLOP_ZWD.js → infoDiagram-FWYZ7A6U-Dr4mN24J.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-aFTIzr7o.js → ishikawaDiagram-FXEZZL3T-BBUFWq5C.js} +1 -1
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-CbPJB4xd.js → journeyDiagram-5HDEW3XC-CmclipcQ.js} +1 -1
- package/client/dist/assets/{kanban-definition-HUTT4EX6-BoyhytIS.js → kanban-definition-HUTT4EX6-eIzUeZ03.js} +1 -1
- package/client/dist/assets/{linear-1VXA-uBg.js → linear-DGiT7uKK.js} +1 -1
- package/client/dist/assets/{mermaid.core-D_lO2yK9.js → mermaid.core-BcLNGbxW.js} +4 -4
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-iFK7LXMx.js → mindmap-definition-LN4V7U3C-C4ANnNiP.js} +1 -1
- package/client/dist/assets/{pegDiagram-2B236MQR-DNmcmfA-.js → pegDiagram-2B236MQR-DnMeh3Yh.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-ekx83O5b.js → pieDiagram-ENE6RG2P-CKV_rkhF.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-DayyD1l8.js → quadrantDiagram-ABIIQ3AL-BuUsGwHh.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-Bdgz7S6G.js → railroadDiagram-RFXS5EU6-BwwdKnFL.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-szP3Muld.js → requirementDiagram-TGXJPOKE-CpQZouJV.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-Ct3rzgUj.js → sankeyDiagram-HTMAVEWB-4fnDUNVa.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-_69EfmOU.js → sequenceDiagram-DBY2YBRQ-BOcaWlM0.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-BSOU06J2.js → sizeCapture-X5ZJPWSS-_pv-9R0c.js} +1 -1
- package/client/dist/assets/{stateDiagram-2N3HPSRC-HmOmFwQm.js → stateDiagram-2N3HPSRC-CFwCOonY.js} +1 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-srkiu3Ib.js +1 -0
- package/client/dist/assets/{swimlanes-5IMT3BWC-CVg_4oT7.js → swimlanes-5IMT3BWC-DFa2tzxu.js} +2 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-Dq-0K9Zm.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-CBBaDKXm.js → timeline-definition-FHXFAJF6-rhGYElgn.js} +1 -1
- package/client/dist/assets/{vennDiagram-L72KCM5P-CBXiWPMc.js → vennDiagram-L72KCM5P-BoGjRxyA.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-EHGQE667-uhBCZoW0.js → wardleyDiagram-EHGQE667-D-IGv5bH.js} +1 -1
- package/client/dist/assets/{xychartDiagram-FW5EYKEG-xxE_wY5O.js → xychartDiagram-FW5EYKEG-D9PFTCfm.js} +1 -1
- package/client/dist/index.html +27 -27
- package/lib/claude-cli.mjs +173 -173
- package/lib/preflight.mjs +252 -252
- package/lib/probe-path.mjs +84 -84
- package/lib/probes.mjs +10 -4
- package/lib/server.mjs +506 -369
- package/lib/util.mjs +157 -157
- package/lib/win32-spawn.mjs +253 -253
- package/package.json +68 -68
- package/scripts/deploy-procs.mjs +208 -208
- package/scripts/deploy-swap.mjs +276 -276
- package/scripts/kill-targets.js +140 -140
- package/scripts/repair-claude-json.mjs +295 -295
- package/server/dist/config/default-actions.json +90 -90
- package/server/dist/core/mission-context/association.d.ts +46 -0
- package/server/dist/core/mission-context/association.d.ts.map +1 -1
- package/server/dist/core/mission-context/association.js +69 -0
- package/server/dist/core/mission-context/association.js.map +1 -1
- package/server/dist/core/mission-context/resolver-iterate.d.ts +6 -0
- package/server/dist/core/mission-context/resolver-iterate.d.ts.map +1 -0
- package/server/dist/core/mission-context/resolver-iterate.js +202 -0
- package/server/dist/core/mission-context/resolver-iterate.js.map +1 -0
- package/server/dist/core/mission-context/resolver-parts.d.ts +20 -0
- package/server/dist/core/mission-context/resolver-parts.d.ts.map +1 -1
- package/server/dist/core/mission-context/resolver-parts.js +92 -0
- package/server/dist/core/mission-context/resolver-parts.js.map +1 -1
- package/server/dist/core/mission-context/resolver.d.ts +1 -1
- package/server/dist/core/mission-context/resolver.d.ts.map +1 -1
- package/server/dist/core/mission-context/resolver.js +17 -199
- package/server/dist/core/mission-context/resolver.js.map +1 -1
- package/server/dist/core/mission-context/run-id-recovery.d.ts +21 -5
- package/server/dist/core/mission-context/run-id-recovery.d.ts.map +1 -1
- package/server/dist/core/mission-context/run-id-recovery.js +32 -5
- package/server/dist/core/mission-context/run-id-recovery.js.map +1 -1
- package/server/dist/core/mission-context/scenario.d.ts +18 -11
- package/server/dist/core/mission-context/scenario.d.ts.map +1 -1
- package/server/dist/core/mission-context/scenario.js +40 -3
- package/server/dist/core/mission-context/scenario.js.map +1 -1
- package/server/dist/core/path-guard.d.ts +1 -1
- package/server/dist/core/path-guard.d.ts.map +1 -1
- package/server/dist/core/path-guard.js +9 -2
- package/server/dist/core/path-guard.js.map +1 -1
- package/server/dist/core/sdk-sessions-merge.d.ts +19 -0
- package/server/dist/core/sdk-sessions-merge.d.ts.map +1 -1
- package/server/dist/core/sdk-sessions-merge.js +19 -5
- package/server/dist/core/sdk-sessions-merge.js.map +1 -1
- package/server/dist/core/sdk-sessions-refresh.d.ts +50 -0
- package/server/dist/core/sdk-sessions-refresh.d.ts.map +1 -0
- package/server/dist/core/sdk-sessions-refresh.js +69 -0
- package/server/dist/core/sdk-sessions-refresh.js.map +1 -0
- package/server/dist/core/sdk-sessions-store.d.ts +2 -0
- package/server/dist/core/sdk-sessions-store.d.ts.map +1 -1
- package/server/dist/core/sdk-sessions-store.js +7 -9
- package/server/dist/core/sdk-sessions-store.js.map +1 -1
- package/server/dist/core/shipslog-docs-reader.d.ts +4 -0
- package/server/dist/core/shipslog-docs-reader.d.ts.map +1 -0
- package/server/dist/core/shipslog-docs-reader.js +181 -0
- package/server/dist/core/shipslog-docs-reader.js.map +1 -0
- package/server/dist/core/shipslog-docs-types.d.ts +15 -0
- package/server/dist/core/shipslog-docs-types.d.ts.map +1 -0
- package/server/dist/core/shipslog-docs-types.js +14 -0
- package/server/dist/core/shipslog-docs-types.js.map +1 -0
- package/server/dist/core/shipwright-plugin-version-reader.d.ts +15 -0
- package/server/dist/core/shipwright-plugin-version-reader.d.ts.map +1 -0
- package/server/dist/core/shipwright-plugin-version-reader.js +49 -0
- package/server/dist/core/shipwright-plugin-version-reader.js.map +1 -0
- package/server/dist/external/design-review/serve.js +27 -27
- package/server/dist/external/inbox/_derive.d.ts +2 -25
- package/server/dist/external/inbox/_derive.d.ts.map +1 -1
- package/server/dist/external/inbox/_derive.js.map +1 -1
- package/server/dist/external/inbox/_lead.d.ts +23 -0
- package/server/dist/external/inbox/_lead.d.ts.map +1 -0
- package/server/dist/external/inbox/_lead.js +83 -0
- package/server/dist/external/inbox/_lead.js.map +1 -0
- package/server/dist/external/inbox/_types.d.ts +32 -0
- package/server/dist/external/inbox/_types.d.ts.map +1 -0
- package/server/dist/external/inbox/_types.js +10 -0
- package/server/dist/external/inbox/_types.js.map +1 -0
- package/server/dist/external/inbox/routes.d.ts.map +1 -1
- package/server/dist/external/inbox/routes.js +29 -1
- package/server/dist/external/inbox/routes.js.map +1 -1
- package/server/dist/external/launch/claim-holder-gate.d.ts +42 -0
- package/server/dist/external/launch/claim-holder-gate.d.ts.map +1 -0
- package/server/dist/external/launch/claim-holder-gate.js +87 -0
- package/server/dist/external/launch/claim-holder-gate.js.map +1 -0
- package/server/dist/external/launch/routes.d.ts.map +1 -1
- package/server/dist/external/launch/routes.js +23 -19
- package/server/dist/external/launch/routes.js.map +1 -1
- package/server/dist/external/mission-context/association-write.d.ts +22 -0
- package/server/dist/external/mission-context/association-write.d.ts.map +1 -0
- package/server/dist/external/mission-context/association-write.js +90 -0
- package/server/dist/external/mission-context/association-write.js.map +1 -0
- package/server/dist/external/mission-context/routes.d.ts.map +1 -1
- package/server/dist/external/mission-context/routes.js +18 -31
- package/server/dist/external/mission-context/routes.js.map +1 -1
- package/server/dist/external/org/lead-question-threads.d.ts +46 -0
- package/server/dist/external/org/lead-question-threads.d.ts.map +1 -0
- package/server/dist/external/org/lead-question-threads.js +132 -0
- package/server/dist/external/org/lead-question-threads.js.map +1 -0
- package/server/dist/external/org/mount.d.ts +3 -0
- package/server/dist/external/org/mount.d.ts.map +1 -1
- package/server/dist/external/org/mount.js +2 -1
- package/server/dist/external/org/mount.js.map +1 -1
- package/server/dist/external/org/usage.d.ts.map +1 -1
- package/server/dist/external/org/usage.js +20 -2
- package/server/dist/external/org/usage.js.map +1 -1
- package/server/dist/external/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +10 -13
- package/server/dist/external/routes.js.map +1 -1
- package/server/dist/external/shipslog-docs/routes.d.ts +10 -0
- package/server/dist/external/shipslog-docs/routes.d.ts.map +1 -0
- package/server/dist/external/shipslog-docs/routes.js +41 -0
- package/server/dist/external/shipslog-docs/routes.js.map +1 -0
- package/server/dist/routes/diagnostics.d.ts +12 -0
- package/server/dist/routes/diagnostics.d.ts.map +1 -1
- package/server/dist/routes/diagnostics.js +4 -1
- package/server/dist/routes/diagnostics.js.map +1 -1
- package/server/dist/routes/org-threads-composite.d.ts +24 -0
- package/server/dist/routes/org-threads-composite.d.ts.map +1 -0
- package/server/dist/routes/org-threads-composite.js +51 -0
- package/server/dist/routes/org-threads-composite.js.map +1 -0
- package/server/dist/routes/org.d.ts +5 -0
- package/server/dist/routes/org.d.ts.map +1 -1
- package/server/dist/routes/org.js +13 -0
- package/server/dist/routes/org.js.map +1 -1
- package/server/dist/terminal/pty-manager.d.ts +23 -1
- package/server/dist/terminal/pty-manager.d.ts.map +1 -1
- package/server/dist/terminal/pty-manager.js +22 -3
- package/server/dist/terminal/pty-manager.js.map +1 -1
- package/server/dist/terminal/pty-write-chunker.d.ts +109 -0
- package/server/dist/terminal/pty-write-chunker.d.ts.map +1 -0
- package/server/dist/terminal/pty-write-chunker.js +234 -0
- package/server/dist/terminal/pty-write-chunker.js.map +1 -0
- package/server/dist/types/org.d.ts +19 -0
- package/server/dist/types/org.d.ts.map +1 -1
- package/server/package.json +1 -1
- package/server/profiles/PROFILE_SCHEMA_VERSION +1 -1
- package/server/profiles/README.md +27 -27
- package/server/profiles/python-plugin-monorepo.json +35 -35
- package/server/profiles/supabase-nextjs.json +253 -253
- package/server/profiles/vite-hono.json +92 -92
- package/client/dist/assets/channel-C_k-9jsa.js +0 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-CsEPq9Ac.js +0 -1
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsEPq9Ac.js +0 -1
- package/client/dist/assets/index-6nZ1bt0a.css +0 -1
- package/client/dist/assets/index-irQhGNpn.js +0 -828
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-BW8H33dv.js +0 -1
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BaRlxcPD.js +0 -8
package/scripts/kill-targets.js
CHANGED
|
@@ -1,140 +1,140 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
-
/**
|
|
3
|
-
* Port-selection helper for dev-restart.js.
|
|
4
|
-
*
|
|
5
|
-
* Pure function: no subprocess calls, no filesystem. The kill-scope is
|
|
6
|
-
* exactly the two configured ports (Hono + Vite), each with a default.
|
|
7
|
-
*
|
|
8
|
-
* Worktree-parallel contract: if the operator sets PORT and VITE_PORT for
|
|
9
|
-
* their worktree, this function returns ONLY those ports — nothing
|
|
10
|
-
* hardcoded, nothing leaked from a different worktree's config. The
|
|
11
|
-
* historic VITE_ALT_PORT=5177 hardcode was removed in v0.3.2.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const DEFAULT_HONO_PORT = 3847;
|
|
15
|
-
const DEFAULT_VITE_PORT = 5173;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @param {Record<string,string|undefined>} env
|
|
19
|
-
* @param {string} _platform // reserved for future platform-specific overrides
|
|
20
|
-
* @returns {number[]} deduped, finite, positive kill targets
|
|
21
|
-
*/
|
|
22
|
-
function computeKillTargets(env, _platform) {
|
|
23
|
-
const honoPort = parsePort(env.PORT, DEFAULT_HONO_PORT);
|
|
24
|
-
const vitePort = parsePort(env.VITE_PORT, DEFAULT_VITE_PORT);
|
|
25
|
-
const seen = new Set();
|
|
26
|
-
const out = [];
|
|
27
|
-
for (const p of [honoPort, vitePort]) {
|
|
28
|
-
if (!Number.isFinite(p) || p <= 0) continue;
|
|
29
|
-
if (seen.has(p)) continue;
|
|
30
|
-
seen.add(p);
|
|
31
|
-
out.push(p);
|
|
32
|
-
}
|
|
33
|
-
return out;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function parsePort(raw, fallback) {
|
|
37
|
-
if (raw === undefined || raw === null || raw === '') return fallback;
|
|
38
|
-
const n = parseInt(String(raw), 10);
|
|
39
|
-
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
40
|
-
return n;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Extract the numeric port from a netstat "Local Address" token.
|
|
45
|
-
*
|
|
46
|
-
* Handles IPv4 (`0.0.0.0:5173`, `127.0.0.1:5173`) and IPv6
|
|
47
|
-
* (`[::]:5173`, `[::1]:5173`) — the port is always the run of digits after
|
|
48
|
-
* the LAST colon. Returns null when no numeric port is present.
|
|
49
|
-
*
|
|
50
|
-
* @param {string} addr
|
|
51
|
-
* @returns {number|null}
|
|
52
|
-
*/
|
|
53
|
-
function localAddressPort(addr) {
|
|
54
|
-
if (typeof addr !== 'string') return null;
|
|
55
|
-
const idx = addr.lastIndexOf(':');
|
|
56
|
-
if (idx === -1) return null;
|
|
57
|
-
const portStr = addr.slice(idx + 1);
|
|
58
|
-
if (!/^\d+$/.test(portStr)) return null;
|
|
59
|
-
return Number(portStr);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Structurally parse Windows `netstat -ano -p TCP` output and return the PIDs
|
|
64
|
-
* of processes LISTENING on one of the given ports.
|
|
65
|
-
*
|
|
66
|
-
* Fixes F16 (D11): the prior `netstat … | findstr :<port>` did plain substring
|
|
67
|
-
* matching over the whole line with no state filter, so it also caught
|
|
68
|
-
* (1) ESTABLISHED browser sockets whose FOREIGN address ended `:<port>`, and
|
|
69
|
-
* (2) port-prefix collisions (`:5173` is a substring of `:51730`),
|
|
70
|
-
* and taskkill /F /T'd those unrelated PIDs. This parser requires
|
|
71
|
-
* state === LISTENING AND an EXACT local-address port match.
|
|
72
|
-
*
|
|
73
|
-
* Handles IPv4 AND IPv6: plain `netstat -ano` output labels IPv6 rows proto
|
|
74
|
-
* `TCP` (distinguished by the `[::]` address), and some Windows builds use
|
|
75
|
-
* `TCPv6` — the proto check is `startsWith('TCP')` to cover both. UDP rows
|
|
76
|
-
* (`*:*` foreign, no State column, 4 tokens) fall out via the < 5 / state
|
|
77
|
-
* checks. Feed it `netstat -ano` (NOT `-p TCP`, which drops IPv6 listeners).
|
|
78
|
-
*
|
|
79
|
-
* @param {string} netstatOutput raw stdout of `netstat -ano`
|
|
80
|
-
* @param {number[]} ports kill-target ports (already validated)
|
|
81
|
-
* @returns {string[]} deduped PID strings, in first-seen order
|
|
82
|
-
*/
|
|
83
|
-
function parseWindowsListenerPids(netstatOutput, ports) {
|
|
84
|
-
const wanted = new Set(ports.map(Number));
|
|
85
|
-
const seen = new Set();
|
|
86
|
-
const pids = [];
|
|
87
|
-
for (const rawLine of String(netstatOutput ?? '').split(/\r?\n/)) {
|
|
88
|
-
const cols = rawLine.trim().split(/\s+/);
|
|
89
|
-
// A TCP row is: Proto LocalAddr ForeignAddr State PID
|
|
90
|
-
if (cols.length < 5) continue;
|
|
91
|
-
if (!cols[0].toUpperCase().startsWith('TCP')) continue;
|
|
92
|
-
const state = cols[cols.length - 2].toUpperCase();
|
|
93
|
-
if (state !== 'LISTENING') continue;
|
|
94
|
-
const port = localAddressPort(cols[1]);
|
|
95
|
-
if (port === null || !wanted.has(port)) continue;
|
|
96
|
-
const pid = cols[cols.length - 1];
|
|
97
|
-
if (!/^\d+$/.test(pid)) continue;
|
|
98
|
-
if (seen.has(pid)) continue;
|
|
99
|
-
seen.add(pid);
|
|
100
|
-
pids.push(pid);
|
|
101
|
-
}
|
|
102
|
-
return pids;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Build the POSIX lsof command that lists only LISTENING PIDs on the given
|
|
107
|
-
* ports. The `-sTCP:LISTEN` state filter is the POSIX half of the F16 fix —
|
|
108
|
-
* without it, `lsof -ti tcp:<ports>` returns every socket (incl. the
|
|
109
|
-
* ESTABLISHED browser connections) bound to those ports.
|
|
110
|
-
*
|
|
111
|
-
* Argument ORDER is load-bearing: the address (`tcp:<ports>`) MUST stay bound
|
|
112
|
-
* to `-i`, with `-sTCP:LISTEN` APPENDED AFTER it. If `-sTCP:LISTEN` sat between
|
|
113
|
-
* `-i` and its address, `-i` would be addressless (its argument starts with
|
|
114
|
-
* `-`) → it selects EVERY internet file and `-sTCP:LISTEN` then narrows to ALL
|
|
115
|
-
* listeners machine-wide, killing every listener — the inverse of this fix.
|
|
116
|
-
*
|
|
117
|
-
* The command is run via `execSync` (shell), so — although callers pass ports
|
|
118
|
-
* already validated by computeKillTargets — every port is coerced to a positive
|
|
119
|
-
* integer and non-integers are dropped here too. That keeps the exported helper
|
|
120
|
-
* injection-proof regardless of caller (defense in depth at the boundary). An
|
|
121
|
-
* empty filtered port list returns '' (kill nothing) so a portless
|
|
122
|
-
* `lsof -ti tcp:` (which would select ALL TCP files) can never be built.
|
|
123
|
-
*
|
|
124
|
-
* @param {number[]} ports
|
|
125
|
-
* @returns {string} shell command string for execSync ('' when no valid ports)
|
|
126
|
-
*/
|
|
127
|
-
function buildLsofCommand(ports) {
|
|
128
|
-
const portList = ports
|
|
129
|
-
.map(Number)
|
|
130
|
-
.filter((p) => Number.isInteger(p) && p > 0)
|
|
131
|
-
.join(',');
|
|
132
|
-
if (portList === '') return '';
|
|
133
|
-
return `lsof -ti tcp:${portList} -sTCP:LISTEN`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
module.exports = {
|
|
137
|
-
computeKillTargets,
|
|
138
|
-
parseWindowsListenerPids,
|
|
139
|
-
buildLsofCommand,
|
|
140
|
-
};
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
+
/**
|
|
3
|
+
* Port-selection helper for dev-restart.js.
|
|
4
|
+
*
|
|
5
|
+
* Pure function: no subprocess calls, no filesystem. The kill-scope is
|
|
6
|
+
* exactly the two configured ports (Hono + Vite), each with a default.
|
|
7
|
+
*
|
|
8
|
+
* Worktree-parallel contract: if the operator sets PORT and VITE_PORT for
|
|
9
|
+
* their worktree, this function returns ONLY those ports — nothing
|
|
10
|
+
* hardcoded, nothing leaked from a different worktree's config. The
|
|
11
|
+
* historic VITE_ALT_PORT=5177 hardcode was removed in v0.3.2.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const DEFAULT_HONO_PORT = 3847;
|
|
15
|
+
const DEFAULT_VITE_PORT = 5173;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {Record<string,string|undefined>} env
|
|
19
|
+
* @param {string} _platform // reserved for future platform-specific overrides
|
|
20
|
+
* @returns {number[]} deduped, finite, positive kill targets
|
|
21
|
+
*/
|
|
22
|
+
function computeKillTargets(env, _platform) {
|
|
23
|
+
const honoPort = parsePort(env.PORT, DEFAULT_HONO_PORT);
|
|
24
|
+
const vitePort = parsePort(env.VITE_PORT, DEFAULT_VITE_PORT);
|
|
25
|
+
const seen = new Set();
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const p of [honoPort, vitePort]) {
|
|
28
|
+
if (!Number.isFinite(p) || p <= 0) continue;
|
|
29
|
+
if (seen.has(p)) continue;
|
|
30
|
+
seen.add(p);
|
|
31
|
+
out.push(p);
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parsePort(raw, fallback) {
|
|
37
|
+
if (raw === undefined || raw === null || raw === '') return fallback;
|
|
38
|
+
const n = parseInt(String(raw), 10);
|
|
39
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
40
|
+
return n;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Extract the numeric port from a netstat "Local Address" token.
|
|
45
|
+
*
|
|
46
|
+
* Handles IPv4 (`0.0.0.0:5173`, `127.0.0.1:5173`) and IPv6
|
|
47
|
+
* (`[::]:5173`, `[::1]:5173`) — the port is always the run of digits after
|
|
48
|
+
* the LAST colon. Returns null when no numeric port is present.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} addr
|
|
51
|
+
* @returns {number|null}
|
|
52
|
+
*/
|
|
53
|
+
function localAddressPort(addr) {
|
|
54
|
+
if (typeof addr !== 'string') return null;
|
|
55
|
+
const idx = addr.lastIndexOf(':');
|
|
56
|
+
if (idx === -1) return null;
|
|
57
|
+
const portStr = addr.slice(idx + 1);
|
|
58
|
+
if (!/^\d+$/.test(portStr)) return null;
|
|
59
|
+
return Number(portStr);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Structurally parse Windows `netstat -ano -p TCP` output and return the PIDs
|
|
64
|
+
* of processes LISTENING on one of the given ports.
|
|
65
|
+
*
|
|
66
|
+
* Fixes F16 (D11): the prior `netstat … | findstr :<port>` did plain substring
|
|
67
|
+
* matching over the whole line with no state filter, so it also caught
|
|
68
|
+
* (1) ESTABLISHED browser sockets whose FOREIGN address ended `:<port>`, and
|
|
69
|
+
* (2) port-prefix collisions (`:5173` is a substring of `:51730`),
|
|
70
|
+
* and taskkill /F /T'd those unrelated PIDs. This parser requires
|
|
71
|
+
* state === LISTENING AND an EXACT local-address port match.
|
|
72
|
+
*
|
|
73
|
+
* Handles IPv4 AND IPv6: plain `netstat -ano` output labels IPv6 rows proto
|
|
74
|
+
* `TCP` (distinguished by the `[::]` address), and some Windows builds use
|
|
75
|
+
* `TCPv6` — the proto check is `startsWith('TCP')` to cover both. UDP rows
|
|
76
|
+
* (`*:*` foreign, no State column, 4 tokens) fall out via the < 5 / state
|
|
77
|
+
* checks. Feed it `netstat -ano` (NOT `-p TCP`, which drops IPv6 listeners).
|
|
78
|
+
*
|
|
79
|
+
* @param {string} netstatOutput raw stdout of `netstat -ano`
|
|
80
|
+
* @param {number[]} ports kill-target ports (already validated)
|
|
81
|
+
* @returns {string[]} deduped PID strings, in first-seen order
|
|
82
|
+
*/
|
|
83
|
+
function parseWindowsListenerPids(netstatOutput, ports) {
|
|
84
|
+
const wanted = new Set(ports.map(Number));
|
|
85
|
+
const seen = new Set();
|
|
86
|
+
const pids = [];
|
|
87
|
+
for (const rawLine of String(netstatOutput ?? '').split(/\r?\n/)) {
|
|
88
|
+
const cols = rawLine.trim().split(/\s+/);
|
|
89
|
+
// A TCP row is: Proto LocalAddr ForeignAddr State PID
|
|
90
|
+
if (cols.length < 5) continue;
|
|
91
|
+
if (!cols[0].toUpperCase().startsWith('TCP')) continue;
|
|
92
|
+
const state = cols[cols.length - 2].toUpperCase();
|
|
93
|
+
if (state !== 'LISTENING') continue;
|
|
94
|
+
const port = localAddressPort(cols[1]);
|
|
95
|
+
if (port === null || !wanted.has(port)) continue;
|
|
96
|
+
const pid = cols[cols.length - 1];
|
|
97
|
+
if (!/^\d+$/.test(pid)) continue;
|
|
98
|
+
if (seen.has(pid)) continue;
|
|
99
|
+
seen.add(pid);
|
|
100
|
+
pids.push(pid);
|
|
101
|
+
}
|
|
102
|
+
return pids;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Build the POSIX lsof command that lists only LISTENING PIDs on the given
|
|
107
|
+
* ports. The `-sTCP:LISTEN` state filter is the POSIX half of the F16 fix —
|
|
108
|
+
* without it, `lsof -ti tcp:<ports>` returns every socket (incl. the
|
|
109
|
+
* ESTABLISHED browser connections) bound to those ports.
|
|
110
|
+
*
|
|
111
|
+
* Argument ORDER is load-bearing: the address (`tcp:<ports>`) MUST stay bound
|
|
112
|
+
* to `-i`, with `-sTCP:LISTEN` APPENDED AFTER it. If `-sTCP:LISTEN` sat between
|
|
113
|
+
* `-i` and its address, `-i` would be addressless (its argument starts with
|
|
114
|
+
* `-`) → it selects EVERY internet file and `-sTCP:LISTEN` then narrows to ALL
|
|
115
|
+
* listeners machine-wide, killing every listener — the inverse of this fix.
|
|
116
|
+
*
|
|
117
|
+
* The command is run via `execSync` (shell), so — although callers pass ports
|
|
118
|
+
* already validated by computeKillTargets — every port is coerced to a positive
|
|
119
|
+
* integer and non-integers are dropped here too. That keeps the exported helper
|
|
120
|
+
* injection-proof regardless of caller (defense in depth at the boundary). An
|
|
121
|
+
* empty filtered port list returns '' (kill nothing) so a portless
|
|
122
|
+
* `lsof -ti tcp:` (which would select ALL TCP files) can never be built.
|
|
123
|
+
*
|
|
124
|
+
* @param {number[]} ports
|
|
125
|
+
* @returns {string} shell command string for execSync ('' when no valid ports)
|
|
126
|
+
*/
|
|
127
|
+
function buildLsofCommand(ports) {
|
|
128
|
+
const portList = ports
|
|
129
|
+
.map(Number)
|
|
130
|
+
.filter((p) => Number.isInteger(p) && p > 0)
|
|
131
|
+
.join(',');
|
|
132
|
+
if (portList === '') return '';
|
|
133
|
+
return `lsof -ti tcp:${portList} -sTCP:LISTEN`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
computeKillTargets,
|
|
138
|
+
parseWindowsListenerPids,
|
|
139
|
+
buildLsofCommand,
|
|
140
|
+
};
|