@svenroth-ai/shipwright 0.24.7-next.0 → 0.26.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-D2BLGWdW.js → EmbeddedTerminal-D3wpPNZP.js} +20 -20
- package/client/dist/assets/{abnfDiagram-VRR7QNED-C-W_2Jd4.js → abnfDiagram-VRR7QNED-BkLIltB3.js} +1 -1
- package/client/dist/assets/{arc-CpqwESP5.js → arc-Sw-Gh0nI.js} +1 -1
- package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DZVZ895V.js → architectureDiagram-ZJ3FMSHR-rdxUi9Ks.js} +1 -1
- package/client/dist/assets/{blockDiagram-677ZJIJ3-CCCZiAA7.js → blockDiagram-677ZJIJ3-Ch_9dj8a.js} +1 -1
- package/client/dist/assets/{c4Diagram-LMCZKHZV-Bg1beZAE.js → c4Diagram-LMCZKHZV-CkFlO65x.js} +1 -1
- package/client/dist/assets/channel-BYPbLjRl.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-CoaXSarh.js → chunk-2Q5K7J3B-CypX83xu.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-CeFXS-CM.js → chunk-32BRIVSS-DxVLYGdl.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-QyJMVe0m.js → chunk-5VM5RSS4-Cxk1evhx.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-BIOtWVF8.js → chunk-EX3LRPZG-n9q5S4yJ.js} +1 -1
- package/client/dist/assets/{chunk-JWPE2WC7-Dcq-lWyX.js → chunk-JWPE2WC7-jeL4xvir.js} +1 -1
- package/client/dist/assets/{chunk-MOJQB5TN-C95323ja.js → chunk-MOJQB5TN-DDSHN0cj.js} +1 -1
- package/client/dist/assets/{chunk-RYQCIY6F-C0HPwpWy.js → chunk-RYQCIY6F-C0bo383g.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-BPrTbZqA.js → chunk-V7JOEXUC-C0jDXXAU.js} +1 -1
- package/client/dist/assets/{chunk-VR4S4FIN--BCnNoqt.js → chunk-VR4S4FIN-h-Rr4Pn2.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-Dj8vtcXf.js → chunk-XXDRQBXY-BexSo0-s.js} +1 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-CsFIeTju.js +1 -0
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsFIeTju.js +1 -0
- package/client/dist/assets/{cose-bilkent-JH36ORCC-y51otZKz.js → cose-bilkent-JH36ORCC-BQXzaioj.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-BRfS3cHo.js → cynefin-VYW2F7L2-BJIofhfe.js} +1 -1
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-Dpg2RtfL.js → cynefinDiagram-TSTJHNR4-DmPqTM1T.js} +1 -1
- package/client/dist/assets/{dagre-VKFMJZFB-BdZtXgKZ.js → dagre-VKFMJZFB-1xljvw6X.js} +1 -1
- package/client/dist/assets/{diagram-FQU43EPY-K-RCwWxW.js → diagram-FQU43EPY-iyL9muCG.js} +1 -1
- package/client/dist/assets/{diagram-G47NLZAW-CHNn7F2-.js → diagram-G47NLZAW-DREp2Th6.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-B3zu6xib.js → diagram-NH7WQ7WH-h0X3Is2S.js} +1 -1
- package/client/dist/assets/{diagram-OA4YK3LP-Wp5ju7L7.js → diagram-OA4YK3LP-Bj8YZRFJ.js} +1 -1
- package/client/dist/assets/{diagram-WEI45ONY-C94GpsRk.js → diagram-WEI45ONY-BZOf805d.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-DXrTPOrP.js → ebnfDiagram-CCIWWBDH-DO5JnXda.js} +1 -1
- package/client/dist/assets/{erDiagram-Q63AITRT-CGejnW0f.js → erDiagram-Q63AITRT-DRgcqg1T.js} +1 -1
- package/client/dist/assets/{flowDiagram-23GEKE2U-CFJMM637.js → flowDiagram-23GEKE2U-C3J9QmrW.js} +1 -1
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-DnaH94Su.js → ganttDiagram-NO4QXBWP-BIEl3Tkm.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-DT-D0gbn.js → gitGraphDiagram-IHSO6WYX-BNF0tFWC.js} +1 -1
- package/client/dist/assets/index-BnTOrFHb.js +829 -0
- package/client/dist/assets/index-CYPc6qxw.css +1 -0
- package/client/dist/assets/{infoDiagram-FWYZ7A6U-DW3Ps00w.js → infoDiagram-FWYZ7A6U-DEyFxiyY.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-DjxjIT3n.js → ishikawaDiagram-FXEZZL3T-B_ehlg3I.js} +1 -1
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-DTQRI93Y.js → journeyDiagram-5HDEW3XC-Dp00FyJS.js} +1 -1
- package/client/dist/assets/{kanban-definition-HUTT4EX6-BeDvbiEs.js → kanban-definition-HUTT4EX6-CTAf16q8.js} +1 -1
- package/client/dist/assets/{linear-B4foxDlh.js → linear-9vNUgmYd.js} +1 -1
- package/client/dist/assets/{mermaid.core-c-L4qgSB.js → mermaid.core-A6tjaEVD.js} +4 -4
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-dh8v0J8T.js → mindmap-definition-LN4V7U3C-DRW3bmCY.js} +1 -1
- package/client/dist/assets/{pegDiagram-2B236MQR-D5vNrtFh.js → pegDiagram-2B236MQR-DJFCjHp2.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-CIjg_6lR.js → pieDiagram-ENE6RG2P-KRd-sGvC.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-CF37qWQD.js → quadrantDiagram-ABIIQ3AL-9TLZE3Hu.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-x0Hn30Kj.js → railroadDiagram-RFXS5EU6-y4tLtjXg.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-BE2QnVbN.js → requirementDiagram-TGXJPOKE-B9EOQDQM.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-CUv6cIlV.js → sankeyDiagram-HTMAVEWB-zfwiDzkT.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-C3ACj5LS.js → sequenceDiagram-DBY2YBRQ-DW1LWepL.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-DTMIb5gX.js → sizeCapture-X5ZJPWSS-BM81Mik0.js} +1 -1
- package/client/dist/assets/{stateDiagram-2N3HPSRC-DI1Z8P74.js → stateDiagram-2N3HPSRC-D0EMIw1w.js} +1 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-B3E4_xxT.js +1 -0
- package/client/dist/assets/{swimlanes-5IMT3BWC-CLSr9w29.js → swimlanes-5IMT3BWC-CKXNCX6M.js} +2 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BegQBqnC.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-BTWmUhDh.js → timeline-definition-FHXFAJF6-ByzIfvL5.js} +1 -1
- package/client/dist/assets/{vennDiagram-L72KCM5P-Ce1dlLCM.js → vennDiagram-L72KCM5P-Xep38xBH.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-EHGQE667-ClOE-aae.js → wardleyDiagram-EHGQE667-DKWDpx6g.js} +1 -1
- package/client/dist/assets/{xychartDiagram-FW5EYKEG-Fa2pqWKw.js → xychartDiagram-FW5EYKEG-BGcwZTnu.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/server.mjs +369 -369
- package/lib/util.mjs +157 -157
- package/lib/win32-spawn.mjs +253 -253
- package/package.json +1 -1
- 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/grade-runner.d.ts +4 -4
- package/server/dist/core/grade-runner.d.ts.map +1 -1
- package/server/dist/core/grade-runner.js +51 -26
- package/server/dist/core/grade-runner.js.map +1 -1
- package/server/dist/core/grade-target.d.ts +8 -0
- package/server/dist/core/grade-target.d.ts.map +1 -1
- package/server/dist/core/grade-target.js +10 -0
- package/server/dist/core/grade-target.js.map +1 -1
- 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/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/triage-cli-runner.d.ts.map +1 -1
- package/server/dist/core/triage-cli-runner.js +29 -10
- package/server/dist/core/triage-cli-runner.js.map +1 -1
- package/server/dist/core/uv-runner.d.ts +23 -0
- package/server/dist/core/uv-runner.d.ts.map +1 -0
- package/server/dist/core/uv-runner.js +39 -0
- package/server/dist/core/uv-runner.js.map +1 -0
- package/server/dist/external/design-review/serve.js +27 -27
- package/server/dist/external/file/exists-routes.d.ts +7 -0
- package/server/dist/external/file/exists-routes.d.ts.map +1 -0
- package/server/dist/external/file/exists-routes.js +91 -0
- package/server/dist/external/file/exists-routes.js.map +1 -0
- 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/audit-log.d.ts +27 -0
- package/server/dist/external/org/audit-log.d.ts.map +1 -0
- package/server/dist/external/org/audit-log.js +92 -0
- package/server/dist/external/org/audit-log.js.map +1 -0
- package/server/dist/external/org/beat-register.d.ts +15 -22
- package/server/dist/external/org/beat-register.d.ts.map +1 -1
- package/server/dist/external/org/beat-register.js +37 -32
- package/server/dist/external/org/beat-register.js.map +1 -1
- package/server/dist/external/org/file-read.d.ts +16 -0
- package/server/dist/external/org/file-read.d.ts.map +1 -1
- package/server/dist/external/org/file-read.js +86 -46
- package/server/dist/external/org/file-read.js.map +1 -1
- package/server/dist/external/org/file-write-core.d.ts +18 -0
- package/server/dist/external/org/file-write-core.d.ts.map +1 -0
- package/server/dist/external/org/file-write-core.js +97 -0
- package/server/dist/external/org/file-write-core.js.map +1 -0
- package/server/dist/external/org/file-write.d.ts +25 -0
- package/server/dist/external/org/file-write.d.ts.map +1 -1
- package/server/dist/external/org/file-write.js +82 -132
- package/server/dist/external/org/file-write.js.map +1 -1
- package/server/dist/external/org/last-run.d.ts +25 -16
- package/server/dist/external/org/last-run.d.ts.map +1 -1
- package/server/dist/external/org/last-run.js +78 -64
- package/server/dist/external/org/last-run.js.map +1 -1
- package/server/dist/external/org/lead-doc-read.d.ts +21 -0
- package/server/dist/external/org/lead-doc-read.d.ts.map +1 -0
- package/server/dist/external/org/lead-doc-read.js +84 -0
- package/server/dist/external/org/lead-doc-read.js.map +1 -0
- package/server/dist/external/org/mount.d.ts +12 -0
- package/server/dist/external/org/mount.d.ts.map +1 -0
- package/server/dist/external/org/mount.js +34 -0
- package/server/dist/external/org/mount.js.map +1 -0
- package/server/dist/external/org/org-chart-lookup.d.ts +13 -0
- package/server/dist/external/org/org-chart-lookup.d.ts.map +1 -1
- package/server/dist/external/org/org-chart-lookup.js +40 -5
- package/server/dist/external/org/org-chart-lookup.js.map +1 -1
- package/server/dist/external/org/org-chart.d.ts +21 -12
- package/server/dist/external/org/org-chart.d.ts.map +1 -1
- package/server/dist/external/org/org-chart.js +50 -32
- package/server/dist/external/org/org-chart.js.map +1 -1
- package/server/dist/external/org/role-extract.d.ts +8 -0
- package/server/dist/external/org/role-extract.d.ts.map +1 -0
- package/server/dist/external/org/role-extract.js +72 -0
- package/server/dist/external/org/role-extract.js.map +1 -0
- package/server/dist/external/org/usage.d.ts +15 -11
- package/server/dist/external/org/usage.d.ts.map +1 -1
- package/server/dist/external/org/usage.js +64 -54
- package/server/dist/external/org/usage.js.map +1 -1
- package/server/dist/external/routes.d.ts +1 -1
- package/server/dist/external/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +19 -17
- 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/grade.d.ts.map +1 -1
- package/server/dist/routes/grade.js +3 -2
- package/server/dist/routes/grade.js.map +1 -1
- package/server/dist/routes/org-leads-composite.d.ts +21 -0
- package/server/dist/routes/org-leads-composite.d.ts.map +1 -0
- package/server/dist/routes/org-leads-composite.js +95 -0
- package/server/dist/routes/org-leads-composite.js.map +1 -0
- package/server/dist/routes/org.d.ts +15 -0
- package/server/dist/routes/org.d.ts.map +1 -0
- package/server/dist/routes/org.js +198 -0
- package/server/dist/routes/org.js.map +1 -0
- package/server/dist/terminal/pty-manager.d.ts +9 -0
- package/server/dist/terminal/pty-manager.d.ts.map +1 -1
- package/server/dist/terminal/pty-manager.js +15 -0
- package/server/dist/terminal/pty-manager.js.map +1 -1
- package/server/dist/terminal/replay-snapshot.d.ts +10 -1
- package/server/dist/terminal/replay-snapshot.d.ts.map +1 -1
- package/server/dist/terminal/replay-snapshot.js +36 -1
- package/server/dist/terminal/replay-snapshot.js.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.d.ts +17 -1
- package/server/dist/terminal/ws-upgrade-handler.d.ts.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts +1 -0
- package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.fixtures.js +3 -2
- package/server/dist/terminal/ws-upgrade-handler.fixtures.js.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.js +45 -4
- package/server/dist/terminal/ws-upgrade-handler.js.map +1 -1
- package/server/dist/test/python-spawn-guard-util.d.ts +14 -0
- package/server/dist/test/python-spawn-guard-util.d.ts.map +1 -0
- package/server/dist/test/python-spawn-guard-util.js +124 -0
- package/server/dist/test/python-spawn-guard-util.js.map +1 -0
- package/server/dist/types/org.d.ts +115 -0
- package/server/dist/types/org.d.ts.map +1 -0
- package/server/dist/types/org.js +16 -0
- package/server/dist/types/org.js.map +1 -0
- 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/MarkdownEditorModal-CP5yG9OU.js +0 -212
- package/client/dist/assets/channel-BNXbCvDS.js +0 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-w-wCtLx3.js +0 -1
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-w-wCtLx3.js +0 -1
- package/client/dist/assets/index-CU2QJgvx.js +0 -609
- package/client/dist/assets/index-ftvVcUT8.css +0 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-DvwiHlJv.js +0 -1
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-JTQZTlZ3.js +0 -8
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* shipslog-docs-reader.ts — pure, fs-backed reader for the Ship's-Log
|
|
3
|
+
* Documents panel (iterate-2026-08-31-shipslog-documents-panel). Curates
|
|
4
|
+
* four groups from a project's own tree — no client input beyond
|
|
5
|
+
* `projectRoot` (already resolved server-side from a trusted project
|
|
6
|
+
* record), so every path here is either a fixed constant or discovered by
|
|
7
|
+
* readdir-ing a fixed directory, never client-supplied.
|
|
8
|
+
*
|
|
9
|
+
* "Requirements" = the ur-spec per PLANNING SECTION (a direct subdirectory
|
|
10
|
+
* of .shipwright/planning/ that is not iterate/adr/campaigns and carries
|
|
11
|
+
* its own spec.md) — distinct from "Iterate" (the flat *.md mini-specs
|
|
12
|
+
* under .shipwright/planning/iterate/), which is a SEPARATE tab in the UI
|
|
13
|
+
* (see ShipsLogSpecsTabs.tsx) precisely because they answer different
|
|
14
|
+
* questions ("what did we commit to" vs. "what changed, run by run").
|
|
15
|
+
*
|
|
16
|
+
* Agent Docs / Compliance are a fixed, curated 5-row list each — a file
|
|
17
|
+
* that doesn't exist on disk is skipped silently (no "unavailable" row);
|
|
18
|
+
* these docs are not guaranteed to exist in every clone/fork.
|
|
19
|
+
*
|
|
20
|
+
* Dates are filesystem mtime, not `git log` — cheap even at 200+ iterate
|
|
21
|
+
* specs, and it's already what mtime reflects for these files.
|
|
22
|
+
*
|
|
23
|
+
* CLAUDE.md rule 10 / ADR-044: every path (even a dynamically-readdir'd
|
|
24
|
+
* one) is re-verified with pathGuard + realPathGuard before it is stat'd
|
|
25
|
+
* or returned — the same discipline external/tree/routes.ts applies to a
|
|
26
|
+
* client-supplied path, as defense in depth even though nothing here is
|
|
27
|
+
* client-controlled. `realpathSync(projectRoot)` is hoisted ONCE per read
|
|
28
|
+
* (path-guard.ts's own documented optimization for a batch caller) rather
|
|
29
|
+
* than re-paid on every one of the ~230 iterate-spec entries.
|
|
30
|
+
*/
|
|
31
|
+
import { readdir, stat } from "node:fs/promises";
|
|
32
|
+
import { realpathSync } from "node:fs";
|
|
33
|
+
import path from "node:path";
|
|
34
|
+
import { pathGuard, realPathGuard } from "./path-guard.js";
|
|
35
|
+
const AGENT_DOCS = [
|
|
36
|
+
{ file: "build_dashboard.md", label: "Dashboard" },
|
|
37
|
+
{ file: "architecture.md", label: "Architecture" },
|
|
38
|
+
{ file: "decision_log.md", label: "Decision Log" },
|
|
39
|
+
{ file: "conventions.md", label: "Conventions" },
|
|
40
|
+
{ file: "design_tokens.md", label: "Design Tokens" },
|
|
41
|
+
];
|
|
42
|
+
const COMPLIANCE_DOCS = [
|
|
43
|
+
{ file: "dashboard.md", label: "Dashboard" },
|
|
44
|
+
{ file: "traceability-matrix.md", label: "Traceability Matrix" },
|
|
45
|
+
{ file: "test-evidence.md", label: "Test Evidence" },
|
|
46
|
+
{ file: "change-history.md", label: "Change History" },
|
|
47
|
+
{ file: "sbom.md", label: "SBOM" },
|
|
48
|
+
];
|
|
49
|
+
const PLANNING_SECTION_EXCLUDES = new Set(["iterate", "adr", "campaigns"]);
|
|
50
|
+
/** "01-adopted" → "01 — Adopted"; no dash → the raw name unchanged. */
|
|
51
|
+
function sectionLabel(dirName) {
|
|
52
|
+
const dash = dirName.indexOf("-");
|
|
53
|
+
if (dash === -1)
|
|
54
|
+
return dirName;
|
|
55
|
+
const num = dirName.slice(0, dash);
|
|
56
|
+
const rest = dirName
|
|
57
|
+
.slice(dash + 1)
|
|
58
|
+
.split("-")
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
61
|
+
.join(" ");
|
|
62
|
+
return rest ? `${num} — ${rest}` : dirName;
|
|
63
|
+
}
|
|
64
|
+
/** Guard + realpath-verify `relPath`; null if it fails the guard, doesn't
|
|
65
|
+
* exist, or escapes the project root via a symlink (skip-silently caller
|
|
66
|
+
* contract — see module doc). */
|
|
67
|
+
function verifiedAbsolute(projectRoot, realRoot, relPath) {
|
|
68
|
+
const guard = pathGuard(projectRoot, relPath);
|
|
69
|
+
if (!guard.ok)
|
|
70
|
+
return null;
|
|
71
|
+
const real = realPathGuard(projectRoot, guard.absolute, realRoot);
|
|
72
|
+
return real.ok ? real.absolute : null;
|
|
73
|
+
}
|
|
74
|
+
async function mtimeIso(absPath) {
|
|
75
|
+
try {
|
|
76
|
+
const s = await stat(absPath);
|
|
77
|
+
return s.mtime.toISOString();
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function curatedRows(projectRoot, realRoot, relDir, files) {
|
|
84
|
+
const rows = [];
|
|
85
|
+
for (const { file, label } of files) {
|
|
86
|
+
const relPath = `${relDir}/${file}`;
|
|
87
|
+
const abs = verifiedAbsolute(projectRoot, realRoot, relPath);
|
|
88
|
+
if (!abs)
|
|
89
|
+
continue; // missing on disk — skip silently, no error row
|
|
90
|
+
const when = await mtimeIso(abs);
|
|
91
|
+
if (when === null)
|
|
92
|
+
continue; // vanished between realpath and stat — skip
|
|
93
|
+
rows.push({ path: relPath, label, when });
|
|
94
|
+
}
|
|
95
|
+
return rows;
|
|
96
|
+
}
|
|
97
|
+
async function readRequirements(projectRoot, realRoot) {
|
|
98
|
+
const planningRel = ".shipwright/planning";
|
|
99
|
+
const guard = pathGuard(projectRoot, planningRel);
|
|
100
|
+
if (!guard.ok)
|
|
101
|
+
return [];
|
|
102
|
+
let entries;
|
|
103
|
+
try {
|
|
104
|
+
entries = await readdir(guard.absolute, { withFileTypes: true });
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
const rows = [];
|
|
110
|
+
for (const d of entries) {
|
|
111
|
+
if (!d.isDirectory() || PLANNING_SECTION_EXCLUDES.has(d.name))
|
|
112
|
+
continue;
|
|
113
|
+
const relPath = `${planningRel}/${d.name}/spec.md`;
|
|
114
|
+
const abs = verifiedAbsolute(projectRoot, realRoot, relPath);
|
|
115
|
+
if (!abs)
|
|
116
|
+
continue; // section without its own spec.md — skip
|
|
117
|
+
const when = await mtimeIso(abs);
|
|
118
|
+
if (when === null)
|
|
119
|
+
continue;
|
|
120
|
+
rows.push({ path: relPath, label: sectionLabel(d.name), when });
|
|
121
|
+
}
|
|
122
|
+
rows.sort((a, b) => a.label.localeCompare(b.label));
|
|
123
|
+
return rows;
|
|
124
|
+
}
|
|
125
|
+
async function readIterateSpecs(projectRoot, realRoot) {
|
|
126
|
+
const relDir = ".shipwright/planning/iterate";
|
|
127
|
+
const guard = pathGuard(projectRoot, relDir);
|
|
128
|
+
if (!guard.ok)
|
|
129
|
+
return [];
|
|
130
|
+
let entries;
|
|
131
|
+
try {
|
|
132
|
+
entries = await readdir(guard.absolute, { withFileTypes: true });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
const rows = [];
|
|
138
|
+
for (const d of entries) {
|
|
139
|
+
// Flat files only (per the panel's Iterate tab spec) — a subdirectory
|
|
140
|
+
// like campaigns/ or a per-run folder is out of scope here.
|
|
141
|
+
if (!d.isFile() || !d.name.endsWith(".md"))
|
|
142
|
+
continue;
|
|
143
|
+
const relPath = `${relDir}/${d.name}`;
|
|
144
|
+
const abs = verifiedAbsolute(projectRoot, realRoot, relPath);
|
|
145
|
+
if (!abs)
|
|
146
|
+
continue;
|
|
147
|
+
const when = await mtimeIso(abs);
|
|
148
|
+
rows.push({ path: relPath, label: d.name, when });
|
|
149
|
+
}
|
|
150
|
+
// Newest first; a row with no readable mtime sorts last rather than
|
|
151
|
+
// fabricating a position it didn't earn.
|
|
152
|
+
rows.sort((a, b) => {
|
|
153
|
+
if (a.when === b.when)
|
|
154
|
+
return a.label.localeCompare(b.label);
|
|
155
|
+
if (a.when === null)
|
|
156
|
+
return 1;
|
|
157
|
+
if (b.when === null)
|
|
158
|
+
return -1;
|
|
159
|
+
return a.when < b.when ? 1 : -1;
|
|
160
|
+
});
|
|
161
|
+
return rows;
|
|
162
|
+
}
|
|
163
|
+
export async function readShipsLogDocs(projectRoot) {
|
|
164
|
+
let realRoot;
|
|
165
|
+
try {
|
|
166
|
+
realRoot = realpathSync(path.resolve(projectRoot));
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Project root itself unreadable — every group degrades to empty
|
|
170
|
+
// rather than throwing (this is a read-only observer, spec AC-honesty).
|
|
171
|
+
return { requirements: [], iterateSpecs: [], agentDocs: [], compliance: [] };
|
|
172
|
+
}
|
|
173
|
+
const [requirements, iterateSpecs, agentDocs, compliance] = await Promise.all([
|
|
174
|
+
readRequirements(projectRoot, realRoot),
|
|
175
|
+
readIterateSpecs(projectRoot, realRoot),
|
|
176
|
+
curatedRows(projectRoot, realRoot, ".shipwright/agent_docs", AGENT_DOCS),
|
|
177
|
+
curatedRows(projectRoot, realRoot, ".shipwright/compliance", COMPLIANCE_DOCS),
|
|
178
|
+
]);
|
|
179
|
+
return { requirements, iterateSpecs, agentDocs, compliance };
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=shipslog-docs-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shipslog-docs-reader.js","sourceRoot":"","sources":["../../src/core/shipslog-docs-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ShipsLogDocRow {
|
|
2
|
+
/** Project-root-relative POSIX path, passed straight to SmartViewerModal. */
|
|
3
|
+
path: string;
|
|
4
|
+
label: string;
|
|
5
|
+
/** ISO mtime, or null when the stat failed after the existence check
|
|
6
|
+
* (a TOCTOU race — treated as "date unknown", never fabricated). */
|
|
7
|
+
when: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface ShipsLogDocsBundle {
|
|
10
|
+
requirements: ShipsLogDocRow[];
|
|
11
|
+
iterateSpecs: ShipsLogDocRow[];
|
|
12
|
+
agentDocs: ShipsLogDocRow[];
|
|
13
|
+
compliance: ShipsLogDocRow[];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=shipslog-docs-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shipslog-docs-types.d.ts","sourceRoot":"","sources":["../../src/core/shipslog-docs-types.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd;yEACqE;IACrE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* shipslog-docs-types.ts — shape contract for the Ship's-Log Documents
|
|
3
|
+
* panel read surface (iterate-2026-08-31-shipslog-documents-panel):
|
|
4
|
+
* curated links to a project's Requirements spec(s) (per planning-section
|
|
5
|
+
* ur-spec, .shipwright/planning/<section>/spec.md), Iterate mini-specs
|
|
6
|
+
* (.shipwright/planning/iterate/*.md), Agent Docs and Compliance docs.
|
|
7
|
+
*
|
|
8
|
+
* Split out (not folded into the reader) to match the run-data-types.ts
|
|
9
|
+
* precedent; verbatim-mirrored client-side in
|
|
10
|
+
* client/src/lib/shipsLogDocsApi.ts (ADR-080 — no cross-package import).
|
|
11
|
+
* Drift guard: server/src/test/shipslog-docs-mirror-sync.test.ts.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=shipslog-docs-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shipslog-docs-types.js","sourceRoot":"","sources":["../../src/core/shipslog-docs-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage-cli-runner.d.ts","sourceRoot":"","sources":["../../src/core/triage-cli-runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"triage-cli-runner.d.ts","sourceRoot":"","sources":["../../src/core/triage-cli-runner.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAiD,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAGjG,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KACnD,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAEnC,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC7B;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,IAAI,GAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,SAAS,GAAG,gBAAgB,CAAM,GAAG,MAAM,GAAG,IAAI,CAW/H;AAED,eAAO,MAAM,qBAAqB,EAAE,cAsBhC,CAAC;AAML,wBAAsB,uBAAuB,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAMxG;AAMD,0FAA0F;AAC1F,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,eAAe,CAAC,CAsC1B"}
|
|
@@ -3,15 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Triage reads remain native TypeScript because they are latency-sensitive and
|
|
5
5
|
* have no mutual-exclusion requirement. Every transition, however, executes
|
|
6
|
-
* the Python CLI so its FileLock owns the
|
|
7
|
-
* schema bootstrap and record-boundary
|
|
6
|
+
* the Python CLI via `uv run --python ">=3.11"` so its FileLock owns the
|
|
7
|
+
* compare-and-swap, residence choice, schema bootstrap and record-boundary
|
|
8
|
+
* handling — in a Python that actually satisfies triage_cli.py's own floor,
|
|
9
|
+
* not whichever of python3/python/py happened to answer `--version` first
|
|
10
|
+
* (the grade.py sibling of this bug; see `uv-runner.ts`). triage_cli.py has
|
|
11
|
+
* no `pyproject.toml` of its own, so this is `--python`, not `--project`
|
|
12
|
+
* (verified: `uv run --python ">=3.11" triage_cli.py --help` exits 0).
|
|
13
|
+
* `--no-project` is load-bearing, not decorative (Stage-3 doubt review,
|
|
14
|
+
* 2026-08-26): without it, `uv run` walks up from the SPAWNING PROCESS's cwd
|
|
15
|
+
* (never from the script's own path) looking for an ambient `pyproject.toml`
|
|
16
|
+
* to activate — a webui deployment nested inside another Python-tooled
|
|
17
|
+
* checkout would otherwise silently run this script against an unrelated
|
|
18
|
+
* project. `--no-project` makes "no ambient project" structural rather than
|
|
19
|
+
* an accident of this repo currently having none. There is deliberately no
|
|
8
20
|
* TypeScript append fallback: an unavailable writer disables the UI instead.
|
|
9
21
|
*/
|
|
10
22
|
import { execFile } from "node:child_process";
|
|
11
23
|
import { existsSync } from "node:fs";
|
|
12
24
|
import os from "node:os";
|
|
13
25
|
import path from "node:path";
|
|
14
|
-
import {
|
|
26
|
+
import { READINESS_REPAIR_COMMAND, shipwrightCacheRoot } from "./readiness-probe.js";
|
|
27
|
+
import { resolveUv } from "./uv-runner.js";
|
|
15
28
|
export const TRIAGE_CLI_TIMEOUT_MS = 30_000;
|
|
16
29
|
/** Resolve the single cache-owned CLI shipped with the Shipwright runtime. */
|
|
17
30
|
export function resolveTriageCliScript(deps = {}) {
|
|
@@ -47,8 +60,9 @@ function unavailable(reason) {
|
|
|
47
60
|
export async function triageWriteAvailability(deps = {}) {
|
|
48
61
|
if (!resolveTriageCliScript(deps))
|
|
49
62
|
return unavailable("The triage write engine isn't installed.");
|
|
50
|
-
if (!(await
|
|
51
|
-
return unavailable("
|
|
63
|
+
if (!(await resolveUv({ run: deps.run, homeDir: deps.homeDir, baseEnv: deps.baseEnv }))) {
|
|
64
|
+
return unavailable("uv isn't installed — triage writes need it to run in a managed Python 3.11+.");
|
|
65
|
+
}
|
|
52
66
|
return { available: true };
|
|
53
67
|
}
|
|
54
68
|
function cleanStderr(stderr) {
|
|
@@ -59,13 +73,18 @@ export async function runTriageCli(input, deps = {}) {
|
|
|
59
73
|
const script = resolveTriageCliScript(deps);
|
|
60
74
|
if (!script)
|
|
61
75
|
return { kind: "engine-unavailable", reason: "The triage write engine isn't installed.", repairCommand: READINESS_REPAIR_COMMAND };
|
|
62
|
-
const
|
|
63
|
-
if (!
|
|
64
|
-
return {
|
|
76
|
+
const uv = await resolveUv({ run: deps.run, homeDir: deps.homeDir, baseEnv: deps.baseEnv });
|
|
77
|
+
if (!uv) {
|
|
78
|
+
return {
|
|
79
|
+
kind: "engine-unavailable",
|
|
80
|
+
reason: "uv isn't installed — triage writes need it to run in a managed Python 3.11+.",
|
|
81
|
+
repairCommand: READINESS_REPAIR_COMMAND,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
65
84
|
const spawn = deps.spawn ?? defaultSpawnTriageCli;
|
|
66
|
-
const result = await spawn(
|
|
85
|
+
const result = await spawn(uv.bin, ["run", "--no-project", "--python", ">=3.11", script, "--project-root", input.projectRoot, input.operation, input.itemId, ...input.args, "--json"], { timeoutMs: deps.timeoutMs ?? TRIAGE_CLI_TIMEOUT_MS, env: uv.env });
|
|
67
86
|
if (result.code === -1) {
|
|
68
|
-
return { kind: "engine-unavailable", reason: "
|
|
87
|
+
return { kind: "engine-unavailable", reason: "uv couldn't start on this machine.", repairCommand: READINESS_REPAIR_COMMAND };
|
|
69
88
|
}
|
|
70
89
|
if (result.code === 3)
|
|
71
90
|
return { kind: "precondition" };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage-cli-runner.js","sourceRoot":"","sources":["../../src/core/triage-cli-runner.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"triage-cli-runner.js","sourceRoot":"","sources":["../../src/core/triage-cli-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type RunFn } from "./readiness-probe-run.js";
|
|
2
|
+
export interface UvResolution {
|
|
3
|
+
/** Absolute path (POSIX) or the bare "uv" (win32 — libuv reads PATH from
|
|
4
|
+
* the child env block, so a literal name plus the augmented `env` resolves
|
|
5
|
+
* it; mirrors `defaultRun`'s own win32/POSIX split). */
|
|
6
|
+
bin: string;
|
|
7
|
+
/** PATH-augmented env to hand to the actual `uv run` spawn. */
|
|
8
|
+
env: NodeJS.ProcessEnv;
|
|
9
|
+
}
|
|
10
|
+
export interface ResolveUvDeps {
|
|
11
|
+
/** `--version` runner used for the presence probe (test seam). */
|
|
12
|
+
run?: RunFn;
|
|
13
|
+
platform?: NodeJS.Platform;
|
|
14
|
+
homeDir?: string;
|
|
15
|
+
/** Base env the augmented PATH is layered onto (defaults to process.env). */
|
|
16
|
+
baseEnv?: NodeJS.ProcessEnv;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Test-run `uv --version`; on success resolve the bin + env a real `uv run`
|
|
20
|
+
* spawn needs. Null means "uv isn't there" — not "python isn't there".
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveUv(deps?: ResolveUvDeps): Promise<UvResolution | null>;
|
|
23
|
+
//# sourceMappingURL=uv-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uv-runner.d.ts","sourceRoot":"","sources":["../../src/core/uv-runner.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B;;6DAEyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAUtF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* uv-runner — resolves `uv` for call sites that must run a plugin-owned Python
|
|
3
|
+
* script IN THE ENGINE'S OWN ENVIRONMENT (grade.py, triage_cli.py), not the
|
|
4
|
+
* server's ambient interpreter (root cause of the ModuleNotFoundError bug:
|
|
5
|
+
* grade-runner / triage-cli-runner used to spawn `resolvePython()`'s raw
|
|
6
|
+
* python3/python/py — whichever answered `--version` first, unversioned and
|
|
7
|
+
* dependency-free — instead of the `uv run`-managed environment both scripts
|
|
8
|
+
* are built for).
|
|
9
|
+
*
|
|
10
|
+
* `resolveUv` test-runs `uv --version` (never assumed present) via the same
|
|
11
|
+
* PATH-augmented probe `readiness-probe-run.ts` uses (`~/.local/bin` etc. —
|
|
12
|
+
* the uv installer only appends that dir to a shell rc, so a server spawned
|
|
13
|
+
* before a fresh install would otherwise ENOENT a real uv), then resolves the
|
|
14
|
+
* actual bin + env a REAL spawn needs — reusing `probeEnv`/`resolvePosixBin`
|
|
15
|
+
* from `readiness-probe-path.ts` rather than re-deriving PATH logic.
|
|
16
|
+
*
|
|
17
|
+
* Returns null when uv is genuinely absent. Callers MUST surface an honest
|
|
18
|
+
* "engine unavailable" in that case — never fall back to a bare system
|
|
19
|
+
* python, which is the exact silent-fallback this module replaces.
|
|
20
|
+
*/
|
|
21
|
+
import os from "node:os";
|
|
22
|
+
import { probeEnv, resolvePosixBin } from "./readiness-probe-path.js";
|
|
23
|
+
import { defaultRun } from "./readiness-probe-run.js";
|
|
24
|
+
/**
|
|
25
|
+
* Test-run `uv --version`; on success resolve the bin + env a real `uv run`
|
|
26
|
+
* spawn needs. Null means "uv isn't there" — not "python isn't there".
|
|
27
|
+
*/
|
|
28
|
+
export async function resolveUv(deps = {}) {
|
|
29
|
+
const run = deps.run ?? defaultRun;
|
|
30
|
+
const probe = await run("uv", ["--version"]);
|
|
31
|
+
if (!probe.ok)
|
|
32
|
+
return null;
|
|
33
|
+
const platform = deps.platform ?? process.platform;
|
|
34
|
+
const homeDir = deps.homeDir ?? os.homedir();
|
|
35
|
+
const env = probeEnv(platform, homeDir, deps.baseEnv ?? process.env);
|
|
36
|
+
const bin = platform === "win32" ? "uv" : resolvePosixBin("uv", env);
|
|
37
|
+
return { bin, env };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=uv-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uv-runner.js","sourceRoot":"","sources":["../../src/core/uv-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,UAAU,EAAc,MAAM,0BAA0B,CAAC;AAoBlE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB,EAAE;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAE3B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACrE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -61,33 +61,33 @@ const SERVE_MIME = Object.freeze({
|
|
|
61
61
|
* markdown to the WebUI host. `write()` captures the blob text and posts it;
|
|
62
62
|
* it must NEVER reject (a throw would drop the viewer into its download
|
|
63
63
|
* fallback). Posts with `targetOrigin === location.origin` (same-origin host). */
|
|
64
|
-
const FEEDBACK_BRIDGE = `<script>
|
|
65
|
-
(function () {
|
|
66
|
-
var HOST_ORIGIN = window.location.origin;
|
|
67
|
-
function post(text) {
|
|
68
|
-
try {
|
|
69
|
-
window.parent.postMessage(
|
|
70
|
-
{ type: "shipwright:design-feedback", markdown: String(text) },
|
|
71
|
-
HOST_ORIGIN
|
|
72
|
-
);
|
|
73
|
-
} catch (e) { /* never let a post error trip the viewer's download fallback */ }
|
|
74
|
-
}
|
|
75
|
-
window.showSaveFilePicker = function () {
|
|
76
|
-
return Promise.resolve({
|
|
77
|
-
createWritable: function () {
|
|
78
|
-
return Promise.resolve({
|
|
79
|
-
write: function (blob) {
|
|
80
|
-
return Promise.resolve(
|
|
81
|
-
blob && typeof blob.text === "function" ? blob.text() : blob
|
|
82
|
-
).then(post, function () { /* swallow */ });
|
|
83
|
-
},
|
|
84
|
-
close: function () { return Promise.resolve(); },
|
|
85
|
-
});
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
})();
|
|
90
|
-
</script>
|
|
64
|
+
const FEEDBACK_BRIDGE = `<script>
|
|
65
|
+
(function () {
|
|
66
|
+
var HOST_ORIGIN = window.location.origin;
|
|
67
|
+
function post(text) {
|
|
68
|
+
try {
|
|
69
|
+
window.parent.postMessage(
|
|
70
|
+
{ type: "shipwright:design-feedback", markdown: String(text) },
|
|
71
|
+
HOST_ORIGIN
|
|
72
|
+
);
|
|
73
|
+
} catch (e) { /* never let a post error trip the viewer's download fallback */ }
|
|
74
|
+
}
|
|
75
|
+
window.showSaveFilePicker = function () {
|
|
76
|
+
return Promise.resolve({
|
|
77
|
+
createWritable: function () {
|
|
78
|
+
return Promise.resolve({
|
|
79
|
+
write: function (blob) {
|
|
80
|
+
return Promise.resolve(
|
|
81
|
+
blob && typeof blob.text === "function" ? blob.text() : blob
|
|
82
|
+
).then(post, function () { /* swallow */ });
|
|
83
|
+
},
|
|
84
|
+
close: function () { return Promise.resolve(); },
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
})();
|
|
90
|
+
</script>
|
|
91
91
|
`;
|
|
92
92
|
/** Insert the bridge before the first <script> (so the override is defined
|
|
93
93
|
* before the viewer script runs), else before </body>, else append. */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { ExternalRouteProjectView } from "../_shared/helpers.js";
|
|
3
|
+
export interface FileExistsRouterDeps {
|
|
4
|
+
getProjectById?: (id: string) => ExternalRouteProjectView | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare function createFileExistsRouter(deps: FileExistsRouterDeps): Hono;
|
|
7
|
+
//# sourceMappingURL=exists-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exists-routes.d.ts","sourceRoot":"","sources":["../../../src/external/file/exists-routes.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAKtE,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,wBAAwB,GAAG,SAAS,CAAC;CACvE;AAwBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,CA4DvE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* external/file/exists-routes.ts — GET
|
|
3
|
+
* /api/external/projects/:projectId/files/exist?paths=a,b,c.
|
|
4
|
+
*
|
|
5
|
+
* Batched, read-only existence check reusing the same `pathGuard` +
|
|
6
|
+
* `realPathGuard` boundary as the file-read route (CLAUDE.md rule 10), but no
|
|
7
|
+
* content is ever read — just `stat`. Feeds the Triage file viewer's
|
|
8
|
+
* link-vs-plain-text decision (iterate-2026-08-30-triage-file-viewer-followups):
|
|
9
|
+
* the caller supplies both the structured `evidencePath` field and
|
|
10
|
+
* regex-extracted free-text mentions, either of which can point at a path
|
|
11
|
+
* that no longer exists or never did — the WHOLE-request 400s stay reserved
|
|
12
|
+
* for a malformed REQUEST (missing project, missing `?paths`, batch cap), but
|
|
13
|
+
* an individual bad path (traversal, absolute, symlink escape, not-a-file,
|
|
14
|
+
* missing) resolves to `false` in the map rather than failing the batch.
|
|
15
|
+
*/
|
|
16
|
+
import { Hono } from "hono";
|
|
17
|
+
import { stat, realpath } from "node:fs/promises";
|
|
18
|
+
import { pathGuard, realPathGuard } from "../../core/path-guard.js";
|
|
19
|
+
/** Hard cap on paths per request — this is a UI convenience batch, not a bulk API. */
|
|
20
|
+
const MAX_PATHS_PER_REQUEST = 50;
|
|
21
|
+
async function pathExists(projectPath, relpath, realProjectRoot) {
|
|
22
|
+
const guard = pathGuard(projectPath, relpath);
|
|
23
|
+
if (!guard.ok)
|
|
24
|
+
return false;
|
|
25
|
+
let st;
|
|
26
|
+
try {
|
|
27
|
+
st = await stat(guard.absolute);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (!st.isFile())
|
|
33
|
+
return false;
|
|
34
|
+
// Same symlink-escape defense as the file-read route: a project-local
|
|
35
|
+
// symlink whose target resolves outside the project root must not be
|
|
36
|
+
// reported as an existing, viewable file.
|
|
37
|
+
return realPathGuard(projectPath, guard.absolute, realProjectRoot).ok;
|
|
38
|
+
}
|
|
39
|
+
export function createFileExistsRouter(deps) {
|
|
40
|
+
const app = new Hono();
|
|
41
|
+
const { getProjectById } = deps;
|
|
42
|
+
app.get("/api/external/projects/:projectId/files/exist", async (c) => {
|
|
43
|
+
const projectId = c.req.param("projectId");
|
|
44
|
+
const project = getProjectById?.(projectId);
|
|
45
|
+
if (!project) {
|
|
46
|
+
return c.json({ error: "project_not_found", projectId }, 404);
|
|
47
|
+
}
|
|
48
|
+
if (!project.path) {
|
|
49
|
+
return c.json({ error: "project_path_unavailable", projectId }, 400);
|
|
50
|
+
}
|
|
51
|
+
const raw = c.req.query("paths");
|
|
52
|
+
if (!raw || raw.length === 0) {
|
|
53
|
+
return c.json({ error: "paths_required" }, 400);
|
|
54
|
+
}
|
|
55
|
+
// Each segment is percent-decoded (client encodes with encodeURIComponent)
|
|
56
|
+
// so a literal comma inside a path can't be mistaken for the delimiter —
|
|
57
|
+
// code-review finding, iterate-2026-08-30-triage-file-viewer-followups.
|
|
58
|
+
// A segment that fails to decode (malformed %-escape) is treated as
|
|
59
|
+
// literal text rather than 400ing the whole batch — it will simply not
|
|
60
|
+
// match a real file and resolve to `false` below.
|
|
61
|
+
const paths = raw
|
|
62
|
+
.split(",")
|
|
63
|
+
.filter((p) => p.length > 0)
|
|
64
|
+
.map((p) => {
|
|
65
|
+
try {
|
|
66
|
+
return decodeURIComponent(p);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return p;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
if (paths.length > MAX_PATHS_PER_REQUEST) {
|
|
73
|
+
return c.json({ error: "too_many_paths", max: MAX_PATHS_PER_REQUEST, received: paths.length }, 400);
|
|
74
|
+
}
|
|
75
|
+
// Resolve the project root's realpath ONCE for the whole batch rather
|
|
76
|
+
// than once per path — up to 50 paths would otherwise each pay a
|
|
77
|
+
// redundant realpathSync(root) inside realPathGuard, doubling the
|
|
78
|
+
// blocking-syscall count for no benefit (doubt-review finding,
|
|
79
|
+
// iterate-2026-08-30-triage-file-viewer-followups). `undefined` on
|
|
80
|
+
// failure falls back to realPathGuard's own per-call resolution, which
|
|
81
|
+
// then fails closed exactly as it did before this change.
|
|
82
|
+
const realProjectRoot = await realpath(project.path).catch(() => undefined);
|
|
83
|
+
const results = await Promise.all(paths.map(async (p) => [p, await pathExists(project.path, p, realProjectRoot)]));
|
|
84
|
+
const exists = {};
|
|
85
|
+
for (const [p, ok] of results)
|
|
86
|
+
exists[p] = ok;
|
|
87
|
+
return c.json({ exists });
|
|
88
|
+
});
|
|
89
|
+
return app;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=exists-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exists-routes.js","sourceRoot":"","sources":["../../../src/external/file/exists-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MissionContextAssociation } from "../../core/mission-context/types.js";
|
|
2
|
+
import type { ExternalTask, SdkSessionsStore } from "../../core/sdk-sessions-store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Persist a resolved association — either the FIRST one for a task, or a
|
|
5
|
+
* confirmed supersession of a stale one. Caller must have already checked
|
|
6
|
+
* `associateRunId` is non-null.
|
|
7
|
+
*
|
|
8
|
+
* `associationAtResolve` is the snapshot `resolveMissionContext` actually
|
|
9
|
+
* decided against (captured by the caller BEFORE its slow async work, e.g.
|
|
10
|
+
* `routes.ts`) — not re-read here. Both write paths compare against it, not
|
|
11
|
+
* a fresh `task.missionContext`: by the time this async function runs, a
|
|
12
|
+
* concurrent poll may already have written a NEWER association, and a fresh
|
|
13
|
+
* read here would silently adopt that as the "expected" value, letting THIS
|
|
14
|
+
* poll's now-stale decision overwrite it with no failure involved (a plain
|
|
15
|
+
* lost-update race, doubt-reviewer HIGH, iterate-2026-08-31-mission-feed-gaps
|
|
16
|
+
* — ELOCKED rollback cannot catch it because nothing fails).
|
|
17
|
+
*/
|
|
18
|
+
export declare function persistMissionAssociation(store: SdkSessionsStore, task: ExternalTask, associationAtResolve: MissionContextAssociation | null, associateRunId: string, associateSource: MissionContextAssociation["source"], now: () => Date, wideWindows: Map<string, {
|
|
19
|
+
seen: string;
|
|
20
|
+
scanned: string;
|
|
21
|
+
}>): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=association-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"association-write.d.ts","sourceRoot":"","sources":["../../../src/external/mission-context/association-write.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEvF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,YAAY,EAClB,oBAAoB,EAAE,yBAAyB,GAAG,IAAI,EACtD,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,yBAAyB,CAAC,QAAQ,CAAC,EACpD,GAAG,EAAE,MAAM,IAAI,EACf,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,OAAO,CAAC,IAAI,CAAC,CA4Df"}
|