@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.
Files changed (206) hide show
  1. package/client/dist/assets/{EmbeddedTerminal-5QvKe3_a.js → EmbeddedTerminal-CqCQUDtp.js} +1 -1
  2. package/client/dist/assets/{abnfDiagram-VRR7QNED-CXi9HegQ.js → abnfDiagram-VRR7QNED-DX2objTP.js} +1 -1
  3. package/client/dist/assets/{arc-DLh4GiqR.js → arc-DQmjbsFU.js} +1 -1
  4. package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DUypQ8dQ.js → architectureDiagram-ZJ3FMSHR-DAvCsPCW.js} +1 -1
  5. package/client/dist/assets/{blockDiagram-677ZJIJ3-D2cVMKJG.js → blockDiagram-677ZJIJ3-DC-dlyYI.js} +1 -1
  6. package/client/dist/assets/{c4Diagram-LMCZKHZV-DtruBGJw.js → c4Diagram-LMCZKHZV-DSlmXfhE.js} +1 -1
  7. package/client/dist/assets/channel-BfmIcrp7.js +1 -0
  8. package/client/dist/assets/{chunk-2Q5K7J3B-CAfQkFw2.js → chunk-2Q5K7J3B-C111EHL6.js} +1 -1
  9. package/client/dist/assets/{chunk-32BRIVSS-CPWXoLnQ.js → chunk-32BRIVSS-DrCYs2XG.js} +1 -1
  10. package/client/dist/assets/{chunk-5VM5RSS4-xVc3oppQ.js → chunk-5VM5RSS4-DIejoaXS.js} +1 -1
  11. package/client/dist/assets/{chunk-EX3LRPZG-CUpl6fRR.js → chunk-EX3LRPZG-CGWNeH2g.js} +1 -1
  12. package/client/dist/assets/{chunk-JWPE2WC7-NejUp56x.js → chunk-JWPE2WC7-CCH0SRFY.js} +1 -1
  13. package/client/dist/assets/{chunk-MOJQB5TN-C9-2lLg0.js → chunk-MOJQB5TN-B3OpZGRv.js} +1 -1
  14. package/client/dist/assets/{chunk-RYQCIY6F-BAPtwABy.js → chunk-RYQCIY6F-BKhdp_8v.js} +1 -1
  15. package/client/dist/assets/{chunk-V7JOEXUC-Dwzihw26.js → chunk-V7JOEXUC-B6Bu8x1y.js} +1 -1
  16. package/client/dist/assets/{chunk-VR4S4FIN-9-iArFJM.js → chunk-VR4S4FIN-OgFi2_iB.js} +1 -1
  17. package/client/dist/assets/{chunk-XXDRQBXY-DiWHOrqe.js → chunk-XXDRQBXY-xyjuuhxl.js} +1 -1
  18. package/client/dist/assets/classDiagram-OUVF2IWQ-HfUQZ6Uc.js +1 -0
  19. package/client/dist/assets/classDiagram-v2-EOCWNBFH-HfUQZ6Uc.js +1 -0
  20. package/client/dist/assets/{cose-bilkent-JH36ORCC-Cp04EOcH.js → cose-bilkent-JH36ORCC-BQIH3SCK.js} +1 -1
  21. package/client/dist/assets/{cynefin-VYW2F7L2-D--GN1v8.js → cynefin-VYW2F7L2-oyLAz8te.js} +1 -1
  22. package/client/dist/assets/{cynefinDiagram-TSTJHNR4-BGH0o_qp.js → cynefinDiagram-TSTJHNR4-DoLCsH0l.js} +1 -1
  23. package/client/dist/assets/{dagre-VKFMJZFB-DSKkIKlj.js → dagre-VKFMJZFB-D7djx1_Y.js} +1 -1
  24. package/client/dist/assets/{diagram-FQU43EPY-Cs_C4lb-.js → diagram-FQU43EPY-DFuYE0Vf.js} +1 -1
  25. package/client/dist/assets/{diagram-G47NLZAW-oDtAA8O_.js → diagram-G47NLZAW-CffCZVXk.js} +1 -1
  26. package/client/dist/assets/{diagram-NH7WQ7WH-BiFMjqSH.js → diagram-NH7WQ7WH-BhrHtUlt.js} +1 -1
  27. package/client/dist/assets/{diagram-OA4YK3LP-Ccs3thCj.js → diagram-OA4YK3LP-CwQPbOn0.js} +1 -1
  28. package/client/dist/assets/{diagram-WEI45ONY-CdZNqgO3.js → diagram-WEI45ONY-abtYnYqH.js} +1 -1
  29. package/client/dist/assets/{ebnfDiagram-CCIWWBDH-CapTA0VL.js → ebnfDiagram-CCIWWBDH-DfV7gT4m.js} +1 -1
  30. package/client/dist/assets/{erDiagram-Q63AITRT-BcRNEP8s.js → erDiagram-Q63AITRT-vtbCprgH.js} +1 -1
  31. package/client/dist/assets/{flowDiagram-23GEKE2U-CJ_zF7e_.js → flowDiagram-23GEKE2U-CVCgcyDF.js} +1 -1
  32. package/client/dist/assets/{ganttDiagram-NO4QXBWP-CnJdcg9A.js → ganttDiagram-NO4QXBWP-BclyOgMb.js} +1 -1
  33. package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-YTUQ_ELk.js → gitGraphDiagram-IHSO6WYX-BXT4rIKj.js} +1 -1
  34. package/client/dist/assets/index-CKU9dY18.css +1 -0
  35. package/client/dist/assets/index-DOMl6atu.js +847 -0
  36. package/client/dist/assets/{infoDiagram-FWYZ7A6U-CLOP_ZWD.js → infoDiagram-FWYZ7A6U-Dr4mN24J.js} +1 -1
  37. package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-aFTIzr7o.js → ishikawaDiagram-FXEZZL3T-BBUFWq5C.js} +1 -1
  38. package/client/dist/assets/{journeyDiagram-5HDEW3XC-CbPJB4xd.js → journeyDiagram-5HDEW3XC-CmclipcQ.js} +1 -1
  39. package/client/dist/assets/{kanban-definition-HUTT4EX6-BoyhytIS.js → kanban-definition-HUTT4EX6-eIzUeZ03.js} +1 -1
  40. package/client/dist/assets/{linear-1VXA-uBg.js → linear-DGiT7uKK.js} +1 -1
  41. package/client/dist/assets/{mermaid.core-D_lO2yK9.js → mermaid.core-BcLNGbxW.js} +4 -4
  42. package/client/dist/assets/{mindmap-definition-LN4V7U3C-iFK7LXMx.js → mindmap-definition-LN4V7U3C-C4ANnNiP.js} +1 -1
  43. package/client/dist/assets/{pegDiagram-2B236MQR-DNmcmfA-.js → pegDiagram-2B236MQR-DnMeh3Yh.js} +1 -1
  44. package/client/dist/assets/{pieDiagram-ENE6RG2P-ekx83O5b.js → pieDiagram-ENE6RG2P-CKV_rkhF.js} +1 -1
  45. package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-DayyD1l8.js → quadrantDiagram-ABIIQ3AL-BuUsGwHh.js} +1 -1
  46. package/client/dist/assets/{railroadDiagram-RFXS5EU6-Bdgz7S6G.js → railroadDiagram-RFXS5EU6-BwwdKnFL.js} +1 -1
  47. package/client/dist/assets/{requirementDiagram-TGXJPOKE-szP3Muld.js → requirementDiagram-TGXJPOKE-CpQZouJV.js} +1 -1
  48. package/client/dist/assets/{sankeyDiagram-HTMAVEWB-Ct3rzgUj.js → sankeyDiagram-HTMAVEWB-4fnDUNVa.js} +1 -1
  49. package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-_69EfmOU.js → sequenceDiagram-DBY2YBRQ-BOcaWlM0.js} +1 -1
  50. package/client/dist/assets/{sizeCapture-X5ZJPWSS-BSOU06J2.js → sizeCapture-X5ZJPWSS-_pv-9R0c.js} +1 -1
  51. package/client/dist/assets/{stateDiagram-2N3HPSRC-HmOmFwQm.js → stateDiagram-2N3HPSRC-CFwCOonY.js} +1 -1
  52. package/client/dist/assets/stateDiagram-v2-6OUMAXLB-srkiu3Ib.js +1 -0
  53. package/client/dist/assets/{swimlanes-5IMT3BWC-CVg_4oT7.js → swimlanes-5IMT3BWC-DFa2tzxu.js} +2 -2
  54. package/client/dist/assets/swimlanesDiagram-G3AALYLV-Dq-0K9Zm.js +8 -0
  55. package/client/dist/assets/{timeline-definition-FHXFAJF6-CBBaDKXm.js → timeline-definition-FHXFAJF6-rhGYElgn.js} +1 -1
  56. package/client/dist/assets/{vennDiagram-L72KCM5P-CBXiWPMc.js → vennDiagram-L72KCM5P-BoGjRxyA.js} +1 -1
  57. package/client/dist/assets/{wardleyDiagram-EHGQE667-uhBCZoW0.js → wardleyDiagram-EHGQE667-D-IGv5bH.js} +1 -1
  58. package/client/dist/assets/{xychartDiagram-FW5EYKEG-xxE_wY5O.js → xychartDiagram-FW5EYKEG-D9PFTCfm.js} +1 -1
  59. package/client/dist/index.html +27 -27
  60. package/lib/claude-cli.mjs +173 -173
  61. package/lib/preflight.mjs +252 -252
  62. package/lib/probe-path.mjs +84 -84
  63. package/lib/probes.mjs +10 -4
  64. package/lib/server.mjs +506 -369
  65. package/lib/util.mjs +157 -157
  66. package/lib/win32-spawn.mjs +253 -253
  67. package/package.json +68 -68
  68. package/scripts/deploy-procs.mjs +208 -208
  69. package/scripts/deploy-swap.mjs +276 -276
  70. package/scripts/kill-targets.js +140 -140
  71. package/scripts/repair-claude-json.mjs +295 -295
  72. package/server/dist/config/default-actions.json +90 -90
  73. package/server/dist/core/mission-context/association.d.ts +46 -0
  74. package/server/dist/core/mission-context/association.d.ts.map +1 -1
  75. package/server/dist/core/mission-context/association.js +69 -0
  76. package/server/dist/core/mission-context/association.js.map +1 -1
  77. package/server/dist/core/mission-context/resolver-iterate.d.ts +6 -0
  78. package/server/dist/core/mission-context/resolver-iterate.d.ts.map +1 -0
  79. package/server/dist/core/mission-context/resolver-iterate.js +202 -0
  80. package/server/dist/core/mission-context/resolver-iterate.js.map +1 -0
  81. package/server/dist/core/mission-context/resolver-parts.d.ts +20 -0
  82. package/server/dist/core/mission-context/resolver-parts.d.ts.map +1 -1
  83. package/server/dist/core/mission-context/resolver-parts.js +92 -0
  84. package/server/dist/core/mission-context/resolver-parts.js.map +1 -1
  85. package/server/dist/core/mission-context/resolver.d.ts +1 -1
  86. package/server/dist/core/mission-context/resolver.d.ts.map +1 -1
  87. package/server/dist/core/mission-context/resolver.js +17 -199
  88. package/server/dist/core/mission-context/resolver.js.map +1 -1
  89. package/server/dist/core/mission-context/run-id-recovery.d.ts +21 -5
  90. package/server/dist/core/mission-context/run-id-recovery.d.ts.map +1 -1
  91. package/server/dist/core/mission-context/run-id-recovery.js +32 -5
  92. package/server/dist/core/mission-context/run-id-recovery.js.map +1 -1
  93. package/server/dist/core/mission-context/scenario.d.ts +18 -11
  94. package/server/dist/core/mission-context/scenario.d.ts.map +1 -1
  95. package/server/dist/core/mission-context/scenario.js +40 -3
  96. package/server/dist/core/mission-context/scenario.js.map +1 -1
  97. package/server/dist/core/path-guard.d.ts +1 -1
  98. package/server/dist/core/path-guard.d.ts.map +1 -1
  99. package/server/dist/core/path-guard.js +9 -2
  100. package/server/dist/core/path-guard.js.map +1 -1
  101. package/server/dist/core/sdk-sessions-merge.d.ts +19 -0
  102. package/server/dist/core/sdk-sessions-merge.d.ts.map +1 -1
  103. package/server/dist/core/sdk-sessions-merge.js +19 -5
  104. package/server/dist/core/sdk-sessions-merge.js.map +1 -1
  105. package/server/dist/core/sdk-sessions-refresh.d.ts +50 -0
  106. package/server/dist/core/sdk-sessions-refresh.d.ts.map +1 -0
  107. package/server/dist/core/sdk-sessions-refresh.js +69 -0
  108. package/server/dist/core/sdk-sessions-refresh.js.map +1 -0
  109. package/server/dist/core/sdk-sessions-store.d.ts +2 -0
  110. package/server/dist/core/sdk-sessions-store.d.ts.map +1 -1
  111. package/server/dist/core/sdk-sessions-store.js +7 -9
  112. package/server/dist/core/sdk-sessions-store.js.map +1 -1
  113. package/server/dist/core/shipslog-docs-reader.d.ts +4 -0
  114. package/server/dist/core/shipslog-docs-reader.d.ts.map +1 -0
  115. package/server/dist/core/shipslog-docs-reader.js +181 -0
  116. package/server/dist/core/shipslog-docs-reader.js.map +1 -0
  117. package/server/dist/core/shipslog-docs-types.d.ts +15 -0
  118. package/server/dist/core/shipslog-docs-types.d.ts.map +1 -0
  119. package/server/dist/core/shipslog-docs-types.js +14 -0
  120. package/server/dist/core/shipslog-docs-types.js.map +1 -0
  121. package/server/dist/core/shipwright-plugin-version-reader.d.ts +15 -0
  122. package/server/dist/core/shipwright-plugin-version-reader.d.ts.map +1 -0
  123. package/server/dist/core/shipwright-plugin-version-reader.js +49 -0
  124. package/server/dist/core/shipwright-plugin-version-reader.js.map +1 -0
  125. package/server/dist/external/design-review/serve.js +27 -27
  126. package/server/dist/external/inbox/_derive.d.ts +2 -25
  127. package/server/dist/external/inbox/_derive.d.ts.map +1 -1
  128. package/server/dist/external/inbox/_derive.js.map +1 -1
  129. package/server/dist/external/inbox/_lead.d.ts +23 -0
  130. package/server/dist/external/inbox/_lead.d.ts.map +1 -0
  131. package/server/dist/external/inbox/_lead.js +83 -0
  132. package/server/dist/external/inbox/_lead.js.map +1 -0
  133. package/server/dist/external/inbox/_types.d.ts +32 -0
  134. package/server/dist/external/inbox/_types.d.ts.map +1 -0
  135. package/server/dist/external/inbox/_types.js +10 -0
  136. package/server/dist/external/inbox/_types.js.map +1 -0
  137. package/server/dist/external/inbox/routes.d.ts.map +1 -1
  138. package/server/dist/external/inbox/routes.js +29 -1
  139. package/server/dist/external/inbox/routes.js.map +1 -1
  140. package/server/dist/external/launch/claim-holder-gate.d.ts +42 -0
  141. package/server/dist/external/launch/claim-holder-gate.d.ts.map +1 -0
  142. package/server/dist/external/launch/claim-holder-gate.js +87 -0
  143. package/server/dist/external/launch/claim-holder-gate.js.map +1 -0
  144. package/server/dist/external/launch/routes.d.ts.map +1 -1
  145. package/server/dist/external/launch/routes.js +23 -19
  146. package/server/dist/external/launch/routes.js.map +1 -1
  147. package/server/dist/external/mission-context/association-write.d.ts +22 -0
  148. package/server/dist/external/mission-context/association-write.d.ts.map +1 -0
  149. package/server/dist/external/mission-context/association-write.js +90 -0
  150. package/server/dist/external/mission-context/association-write.js.map +1 -0
  151. package/server/dist/external/mission-context/routes.d.ts.map +1 -1
  152. package/server/dist/external/mission-context/routes.js +18 -31
  153. package/server/dist/external/mission-context/routes.js.map +1 -1
  154. package/server/dist/external/org/lead-question-threads.d.ts +46 -0
  155. package/server/dist/external/org/lead-question-threads.d.ts.map +1 -0
  156. package/server/dist/external/org/lead-question-threads.js +132 -0
  157. package/server/dist/external/org/lead-question-threads.js.map +1 -0
  158. package/server/dist/external/org/mount.d.ts +3 -0
  159. package/server/dist/external/org/mount.d.ts.map +1 -1
  160. package/server/dist/external/org/mount.js +2 -1
  161. package/server/dist/external/org/mount.js.map +1 -1
  162. package/server/dist/external/org/usage.d.ts.map +1 -1
  163. package/server/dist/external/org/usage.js +20 -2
  164. package/server/dist/external/org/usage.js.map +1 -1
  165. package/server/dist/external/routes.d.ts.map +1 -1
  166. package/server/dist/external/routes.js +10 -13
  167. package/server/dist/external/routes.js.map +1 -1
  168. package/server/dist/external/shipslog-docs/routes.d.ts +10 -0
  169. package/server/dist/external/shipslog-docs/routes.d.ts.map +1 -0
  170. package/server/dist/external/shipslog-docs/routes.js +41 -0
  171. package/server/dist/external/shipslog-docs/routes.js.map +1 -0
  172. package/server/dist/routes/diagnostics.d.ts +12 -0
  173. package/server/dist/routes/diagnostics.d.ts.map +1 -1
  174. package/server/dist/routes/diagnostics.js +4 -1
  175. package/server/dist/routes/diagnostics.js.map +1 -1
  176. package/server/dist/routes/org-threads-composite.d.ts +24 -0
  177. package/server/dist/routes/org-threads-composite.d.ts.map +1 -0
  178. package/server/dist/routes/org-threads-composite.js +51 -0
  179. package/server/dist/routes/org-threads-composite.js.map +1 -0
  180. package/server/dist/routes/org.d.ts +5 -0
  181. package/server/dist/routes/org.d.ts.map +1 -1
  182. package/server/dist/routes/org.js +13 -0
  183. package/server/dist/routes/org.js.map +1 -1
  184. package/server/dist/terminal/pty-manager.d.ts +23 -1
  185. package/server/dist/terminal/pty-manager.d.ts.map +1 -1
  186. package/server/dist/terminal/pty-manager.js +22 -3
  187. package/server/dist/terminal/pty-manager.js.map +1 -1
  188. package/server/dist/terminal/pty-write-chunker.d.ts +109 -0
  189. package/server/dist/terminal/pty-write-chunker.d.ts.map +1 -0
  190. package/server/dist/terminal/pty-write-chunker.js +234 -0
  191. package/server/dist/terminal/pty-write-chunker.js.map +1 -0
  192. package/server/dist/types/org.d.ts +19 -0
  193. package/server/dist/types/org.d.ts.map +1 -1
  194. package/server/package.json +1 -1
  195. package/server/profiles/PROFILE_SCHEMA_VERSION +1 -1
  196. package/server/profiles/README.md +27 -27
  197. package/server/profiles/python-plugin-monorepo.json +35 -35
  198. package/server/profiles/supabase-nextjs.json +253 -253
  199. package/server/profiles/vite-hono.json +92 -92
  200. package/client/dist/assets/channel-C_k-9jsa.js +0 -1
  201. package/client/dist/assets/classDiagram-OUVF2IWQ-CsEPq9Ac.js +0 -1
  202. package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsEPq9Ac.js +0 -1
  203. package/client/dist/assets/index-6nZ1bt0a.css +0 -1
  204. package/client/dist/assets/index-irQhGNpn.js +0 -828
  205. package/client/dist/assets/stateDiagram-v2-6OUMAXLB-BW8H33dv.js +0 -1
  206. package/client/dist/assets/swimlanesDiagram-G3AALYLV-BaRlxcPD.js +0 -8
@@ -1,84 +1,84 @@
1
- /**
2
- * probe-path.mjs — where the prerequisite probe LOOKS for a binary.
3
- *
4
- * Split out of preflight.mjs (iterate-2026-08-22): the "augment the lookup PATH
5
- * and resolve a bare name to an absolute executable" concern is cohesive and
6
- * independently testable, and keeping it here holds preflight.mjs under the
7
- * 300-line ceiling. preflight.mjs owns the VERDICT; this module owns the LOOKUP.
8
- */
9
-
10
- import { accessSync, constants as fsConstants, statSync } from "node:fs";
11
- import path from "node:path";
12
-
13
- /**
14
- * Return a copy of `baseEnv` whose PATH also contains the well-known user-level
15
- * bin dirs that the uv and Claude Code installers write to.
16
- *
17
- * WHY (Mac cold-start, iterate-2026-08-22): those installers drop their binary
18
- * in `~/.local/bin` (and Homebrew in `/opt/homebrew/bin` | `/usr/local/bin`) and
19
- * only APPEND that dir to the shell rc. The npx process that runs this
20
- * bootstrapper still carries the PATH captured before the install, so a
21
- * `shell: false` probe reported a perfectly-installed uv/claude as ABSENT until
22
- * the user opened a fresh terminal. Augmenting the lookup PATH lets the probe
23
- * find a just-installed tool without the restart.
24
- *
25
- * The extra dirs are APPENDED, never prepended — an explicitly-configured tool
26
- * on the real PATH always wins; `~/.local/bin` is only a fallback. Bare-name,
27
- * PATH-only: no cwd is ever added, so the win32-spawn security posture holds.
28
- *
29
- * Windows subtlety: `process.env` is case-insensitive but a plain object is not,
30
- * so we collapse every `path`-cased key into a single canonical `PATH` — never
31
- * hand spawn both a stale `Path` and an augmented `PATH`.
32
- *
33
- * @param {NodeJS.Platform} platform
34
- * @param {string} homedir
35
- * @param {Record<string, string | undefined>} [baseEnv]
36
- * @returns {Record<string, string>}
37
- */
38
- export function probeEnv(platform, homedir, baseEnv = {}) {
39
- const sep = platform === "win32" ? ";" : ":";
40
- const extra =
41
- platform === "win32"
42
- ? [path.win32.join(homedir, ".local", "bin")]
43
- : [path.posix.join(homedir, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"];
44
-
45
- const out = {};
46
- let current = "";
47
- for (const [k, v] of Object.entries(baseEnv)) {
48
- if (k.toLowerCase() === "path") {
49
- if (v != null) current = v;
50
- continue; // drop every path-cased key; a single PATH is re-added below
51
- }
52
- if (v != null) out[k] = v;
53
- }
54
- const merged = current ? current.split(sep).filter(Boolean) : [];
55
- for (const d of extra) if (!merged.includes(d)) merged.push(d);
56
- out.PATH = merged.join(sep);
57
- return out;
58
- }
59
-
60
- /**
61
- * Resolve a bare command name to an absolute executable path by scanning the
62
- * (already augmented) PATH — POSIX only. Node's own bare-name lookup does not
63
- * reliably honour `options.env.PATH`, so we resolve the absolute path ourselves
64
- * and spawn THAT, making the augmented PATH actually take effect. PATH-only,
65
- * never cwd. Returns the bare name unchanged when nothing resolves (spawn then
66
- * yields the same ENOENT → `ok:false` verdict as before).
67
- * @param {string} name @param {Record<string,string|undefined>} env
68
- */
69
- export function resolvePosixBin(name, env) {
70
- if (name.includes("/")) return name; // already a path
71
- for (const dir of (env.PATH ?? "").split(":")) {
72
- if (!dir) continue;
73
- const cand = path.posix.join(dir, name);
74
- try {
75
- if (statSync(cand).isFile()) {
76
- accessSync(cand, fsConstants.X_OK);
77
- return cand;
78
- }
79
- } catch {
80
- // not a usable executable here — keep searching
81
- }
82
- }
83
- return name;
84
- }
1
+ /**
2
+ * probe-path.mjs — where the prerequisite probe LOOKS for a binary.
3
+ *
4
+ * Split out of preflight.mjs (iterate-2026-08-22): the "augment the lookup PATH
5
+ * and resolve a bare name to an absolute executable" concern is cohesive and
6
+ * independently testable, and keeping it here holds preflight.mjs under the
7
+ * 300-line ceiling. preflight.mjs owns the VERDICT; this module owns the LOOKUP.
8
+ */
9
+
10
+ import { accessSync, constants as fsConstants, statSync } from "node:fs";
11
+ import path from "node:path";
12
+
13
+ /**
14
+ * Return a copy of `baseEnv` whose PATH also contains the well-known user-level
15
+ * bin dirs that the uv and Claude Code installers write to.
16
+ *
17
+ * WHY (Mac cold-start, iterate-2026-08-22): those installers drop their binary
18
+ * in `~/.local/bin` (and Homebrew in `/opt/homebrew/bin` | `/usr/local/bin`) and
19
+ * only APPEND that dir to the shell rc. The npx process that runs this
20
+ * bootstrapper still carries the PATH captured before the install, so a
21
+ * `shell: false` probe reported a perfectly-installed uv/claude as ABSENT until
22
+ * the user opened a fresh terminal. Augmenting the lookup PATH lets the probe
23
+ * find a just-installed tool without the restart.
24
+ *
25
+ * The extra dirs are APPENDED, never prepended — an explicitly-configured tool
26
+ * on the real PATH always wins; `~/.local/bin` is only a fallback. Bare-name,
27
+ * PATH-only: no cwd is ever added, so the win32-spawn security posture holds.
28
+ *
29
+ * Windows subtlety: `process.env` is case-insensitive but a plain object is not,
30
+ * so we collapse every `path`-cased key into a single canonical `PATH` — never
31
+ * hand spawn both a stale `Path` and an augmented `PATH`.
32
+ *
33
+ * @param {NodeJS.Platform} platform
34
+ * @param {string} homedir
35
+ * @param {Record<string, string | undefined>} [baseEnv]
36
+ * @returns {Record<string, string>}
37
+ */
38
+ export function probeEnv(platform, homedir, baseEnv = {}) {
39
+ const sep = platform === "win32" ? ";" : ":";
40
+ const extra =
41
+ platform === "win32"
42
+ ? [path.win32.join(homedir, ".local", "bin")]
43
+ : [path.posix.join(homedir, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"];
44
+
45
+ const out = {};
46
+ let current = "";
47
+ for (const [k, v] of Object.entries(baseEnv)) {
48
+ if (k.toLowerCase() === "path") {
49
+ if (v != null) current = v;
50
+ continue; // drop every path-cased key; a single PATH is re-added below
51
+ }
52
+ if (v != null) out[k] = v;
53
+ }
54
+ const merged = current ? current.split(sep).filter(Boolean) : [];
55
+ for (const d of extra) if (!merged.includes(d)) merged.push(d);
56
+ out.PATH = merged.join(sep);
57
+ return out;
58
+ }
59
+
60
+ /**
61
+ * Resolve a bare command name to an absolute executable path by scanning the
62
+ * (already augmented) PATH — POSIX only. Node's own bare-name lookup does not
63
+ * reliably honour `options.env.PATH`, so we resolve the absolute path ourselves
64
+ * and spawn THAT, making the augmented PATH actually take effect. PATH-only,
65
+ * never cwd. Returns the bare name unchanged when nothing resolves (spawn then
66
+ * yields the same ENOENT → `ok:false` verdict as before).
67
+ * @param {string} name @param {Record<string,string|undefined>} env
68
+ */
69
+ export function resolvePosixBin(name, env) {
70
+ if (name.includes("/")) return name; // already a path
71
+ for (const dir of (env.PATH ?? "").split(":")) {
72
+ if (!dir) continue;
73
+ const cand = path.posix.join(dir, name);
74
+ try {
75
+ if (statSync(cand).isFile()) {
76
+ accessSync(cand, fsConstants.X_OK);
77
+ return cand;
78
+ }
79
+ } catch {
80
+ // not a usable executable here — keep searching
81
+ }
82
+ }
83
+ return name;
84
+ }
package/lib/probes.mjs CHANGED
@@ -9,10 +9,16 @@
9
9
  import net from "node:net";
10
10
 
11
11
  /**
12
- * TCP-connect to 127.0.0.1:port. `connected` → the port is OCCUPIED (by
13
- * anything); ECONNREFUSED → FREE. A connect timeout is treated as free (a
14
- * filtered localhost port does not occur in practice; erring toward free avoids
15
- * a false-foreign that would block boot on a genuinely open port).
12
+ * TCP-connect to `host`:`port` (loopback by default; server.mjs's
13
+ * `resolveProbeHost` passes a profile-derived address, e.g. a tailscale IP,
14
+ * under SHIPWRIGHT_NETWORK_PROFILE=tailscale — webui#415). `connected` → the
15
+ * port is OCCUPIED (by anything); ECONNREFUSED → FREE. A connect timeout is
16
+ * treated as free (a filtered loopback port does not occur in practice;
17
+ * erring toward free avoids a false-foreign that would block boot on a
18
+ * genuinely open port). That heuristic is weaker for a non-loopback `host`: a
19
+ * blackholed/unreachable tailnet interface times out the same way a genuinely
20
+ * free port does, so it also reads as free — a known, accepted gap, not this
21
+ * function's concern to close (server.mjs owns which host to pass).
16
22
  * @returns {Promise<boolean>} occupied
17
23
  */
18
24
  export function tcpOccupied(port, { host = "127.0.0.1", timeoutMs = 1500 } = {}) {