@svenroth-ai/shipwright 0.25.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-5QvKe3_a.js → EmbeddedTerminal-D3wpPNZP.js} +1 -1
- package/client/dist/assets/{abnfDiagram-VRR7QNED-CXi9HegQ.js → abnfDiagram-VRR7QNED-BkLIltB3.js} +1 -1
- package/client/dist/assets/{arc-DLh4GiqR.js → arc-Sw-Gh0nI.js} +1 -1
- package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DUypQ8dQ.js → architectureDiagram-ZJ3FMSHR-rdxUi9Ks.js} +1 -1
- package/client/dist/assets/{blockDiagram-677ZJIJ3-D2cVMKJG.js → blockDiagram-677ZJIJ3-Ch_9dj8a.js} +1 -1
- package/client/dist/assets/{c4Diagram-LMCZKHZV-DtruBGJw.js → c4Diagram-LMCZKHZV-CkFlO65x.js} +1 -1
- package/client/dist/assets/channel-BYPbLjRl.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-CAfQkFw2.js → chunk-2Q5K7J3B-CypX83xu.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-CPWXoLnQ.js → chunk-32BRIVSS-DxVLYGdl.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-xVc3oppQ.js → chunk-5VM5RSS4-Cxk1evhx.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-CUpl6fRR.js → chunk-EX3LRPZG-n9q5S4yJ.js} +1 -1
- package/client/dist/assets/{chunk-JWPE2WC7-NejUp56x.js → chunk-JWPE2WC7-jeL4xvir.js} +1 -1
- package/client/dist/assets/{chunk-MOJQB5TN-C9-2lLg0.js → chunk-MOJQB5TN-DDSHN0cj.js} +1 -1
- package/client/dist/assets/{chunk-RYQCIY6F-BAPtwABy.js → chunk-RYQCIY6F-C0bo383g.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-Dwzihw26.js → chunk-V7JOEXUC-C0jDXXAU.js} +1 -1
- package/client/dist/assets/{chunk-VR4S4FIN-9-iArFJM.js → chunk-VR4S4FIN-h-Rr4Pn2.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-DiWHOrqe.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-Cp04EOcH.js → cose-bilkent-JH36ORCC-BQXzaioj.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-D--GN1v8.js → cynefin-VYW2F7L2-BJIofhfe.js} +1 -1
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-BGH0o_qp.js → cynefinDiagram-TSTJHNR4-DmPqTM1T.js} +1 -1
- package/client/dist/assets/{dagre-VKFMJZFB-DSKkIKlj.js → dagre-VKFMJZFB-1xljvw6X.js} +1 -1
- package/client/dist/assets/{diagram-FQU43EPY-Cs_C4lb-.js → diagram-FQU43EPY-iyL9muCG.js} +1 -1
- package/client/dist/assets/{diagram-G47NLZAW-oDtAA8O_.js → diagram-G47NLZAW-DREp2Th6.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-BiFMjqSH.js → diagram-NH7WQ7WH-h0X3Is2S.js} +1 -1
- package/client/dist/assets/{diagram-OA4YK3LP-Ccs3thCj.js → diagram-OA4YK3LP-Bj8YZRFJ.js} +1 -1
- package/client/dist/assets/{diagram-WEI45ONY-CdZNqgO3.js → diagram-WEI45ONY-BZOf805d.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-CapTA0VL.js → ebnfDiagram-CCIWWBDH-DO5JnXda.js} +1 -1
- package/client/dist/assets/{erDiagram-Q63AITRT-BcRNEP8s.js → erDiagram-Q63AITRT-DRgcqg1T.js} +1 -1
- package/client/dist/assets/{flowDiagram-23GEKE2U-CJ_zF7e_.js → flowDiagram-23GEKE2U-C3J9QmrW.js} +1 -1
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-CnJdcg9A.js → ganttDiagram-NO4QXBWP-BIEl3Tkm.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-YTUQ_ELk.js → gitGraphDiagram-IHSO6WYX-BNF0tFWC.js} +1 -1
- package/client/dist/assets/{index-irQhGNpn.js → index-BnTOrFHb.js} +203 -202
- package/client/dist/assets/index-CYPc6qxw.css +1 -0
- package/client/dist/assets/{infoDiagram-FWYZ7A6U-CLOP_ZWD.js → infoDiagram-FWYZ7A6U-DEyFxiyY.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-aFTIzr7o.js → ishikawaDiagram-FXEZZL3T-B_ehlg3I.js} +1 -1
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-CbPJB4xd.js → journeyDiagram-5HDEW3XC-Dp00FyJS.js} +1 -1
- package/client/dist/assets/{kanban-definition-HUTT4EX6-BoyhytIS.js → kanban-definition-HUTT4EX6-CTAf16q8.js} +1 -1
- package/client/dist/assets/{linear-1VXA-uBg.js → linear-9vNUgmYd.js} +1 -1
- package/client/dist/assets/{mermaid.core-D_lO2yK9.js → mermaid.core-A6tjaEVD.js} +4 -4
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-iFK7LXMx.js → mindmap-definition-LN4V7U3C-DRW3bmCY.js} +1 -1
- package/client/dist/assets/{pegDiagram-2B236MQR-DNmcmfA-.js → pegDiagram-2B236MQR-DJFCjHp2.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-ekx83O5b.js → pieDiagram-ENE6RG2P-KRd-sGvC.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-DayyD1l8.js → quadrantDiagram-ABIIQ3AL-9TLZE3Hu.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-Bdgz7S6G.js → railroadDiagram-RFXS5EU6-y4tLtjXg.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-szP3Muld.js → requirementDiagram-TGXJPOKE-B9EOQDQM.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-Ct3rzgUj.js → sankeyDiagram-HTMAVEWB-zfwiDzkT.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-_69EfmOU.js → sequenceDiagram-DBY2YBRQ-DW1LWepL.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-BSOU06J2.js → sizeCapture-X5ZJPWSS-BM81Mik0.js} +1 -1
- package/client/dist/assets/{stateDiagram-2N3HPSRC-HmOmFwQm.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-CVg_4oT7.js → swimlanes-5IMT3BWC-CKXNCX6M.js} +2 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BegQBqnC.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-CBBaDKXm.js → timeline-definition-FHXFAJF6-ByzIfvL5.js} +1 -1
- package/client/dist/assets/{vennDiagram-L72KCM5P-CBXiWPMc.js → vennDiagram-L72KCM5P-Xep38xBH.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-EHGQE667-uhBCZoW0.js → wardleyDiagram-EHGQE667-DKWDpx6g.js} +1 -1
- package/client/dist/assets/{xychartDiagram-FW5EYKEG-xxE_wY5O.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 +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/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/external/design-review/serve.js +27 -27
- 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/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +9 -6
- 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/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/stateDiagram-v2-6OUMAXLB-BW8H33dv.js +0 -1
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BaRlxcPD.js +0 -8
|
@@ -8,12 +8,15 @@
|
|
|
8
8
|
* 1. custom_actions — a VALIDATED custom-actions project → HIDE the Mission
|
|
9
9
|
* tab entirely (only Files & Terminal).
|
|
10
10
|
* 2. iterate — a VALIDATED `iterate_active` pointer, or the persisted
|
|
11
|
-
* association once that pointer has been pruned
|
|
11
|
+
* association once that pointer has been pruned — UNLESS a corroborated
|
|
12
|
+
* transcript footer (below) names a different, newer run, which
|
|
13
|
+
* supersedes a stale association (iterate-2026-08-31-mission-feed-gaps).
|
|
12
14
|
* 3. pipeline — phaseTaskId + runId (run-config v2 phase_tasks).
|
|
13
15
|
* 4. campaign — a `campaign:<slug>` title AND a real campaign record.
|
|
14
16
|
* 5. iterate — a CORROBORATED `Run-ID` footer in this session's own
|
|
15
|
-
* transcript (run-id-recovery.ts). Last resort
|
|
16
|
-
* below pipeline/campaign — see
|
|
17
|
+
* transcript (run-id-recovery.ts). Last resort when NO association
|
|
18
|
+
* exists, and deliberately ranked below pipeline/campaign — see
|
|
19
|
+
* `recoverTranscriptRunId`.
|
|
17
20
|
* 6. plain — everything else (scenarios 1/4): narration, no rail.
|
|
18
21
|
*
|
|
19
22
|
* Two DECIDED asymmetries, both "fail toward showing the tab":
|
|
@@ -24,6 +27,7 @@
|
|
|
24
27
|
* - A `campaign:` TITLE without a matching record is NOT a campaign. Titles
|
|
25
28
|
* are user-editable; a record is evidence.
|
|
26
29
|
*/
|
|
30
|
+
import { isProvablyNewerRunId } from "./run-id-recovery.js";
|
|
27
31
|
/** The four builtin action ids. Anything else is a user-defined custom action. */
|
|
28
32
|
export const BUILTIN_ACTION_IDS = new Set([
|
|
29
33
|
"new-task",
|
|
@@ -111,6 +115,39 @@ export function detectScenario(inputs) {
|
|
|
111
115
|
// validation is a signal something is wrong, and quietly resolving via a
|
|
112
116
|
// stored id would mask it.
|
|
113
117
|
if (inputs.pointer.status === "absent" && inputs.association?.runId) {
|
|
118
|
+
// Before trusting the stored value, give the transcript one chance to
|
|
119
|
+
// SUPERSEDE it (iterate-2026-08-31-mission-feed-gaps). The association is
|
|
120
|
+
// only ever refreshed by catching a LIVE pointer (rule 2) — a narrow
|
|
121
|
+
// window that only opens while a worktree exists, between setup and
|
|
122
|
+
// Finalize. A task whose Mission tab is not open during that window keeps
|
|
123
|
+
// whatever association it last caught, forever, even after several more
|
|
124
|
+
// iterates finish: production evidence (a `new-plain` task with 9+
|
|
125
|
+
// completed PRs after its one caught association) showed a stale
|
|
126
|
+
// association can outlive the run it names by weeks.
|
|
127
|
+
//
|
|
128
|
+
// `recoverTranscriptRunId` finds the LAST `Run-ID:` footer in the
|
|
129
|
+
// transcript, corroborated against this project's OWN completed-run
|
|
130
|
+
// records (run-id-recovery.ts) — the same evidence rule 5 below trusts
|
|
131
|
+
// enough to identify a run with NO association at all. It is therefore
|
|
132
|
+
// not "quoted text" here either: when it names a DIFFERENT, corroborated,
|
|
133
|
+
// and PROVABLY NEWER run than the one on file (`isProvablyNewerRunId` —
|
|
134
|
+
// same-day or unparseable is not proof, external code review, openai
|
|
135
|
+
// MEDIUM), that is proof a newer run finished. The resolver rate-limits
|
|
136
|
+
// the actual scan per (session, association, transcript-content) so this
|
|
137
|
+
// does not reintroduce the "every poll forever" cost PR #309 removed (see
|
|
138
|
+
// resolver.ts), and the route persists the correction (association.ts
|
|
139
|
+
// `supersedeMissionContext`) so it survives instead of re-proving itself
|
|
140
|
+
// every poll.
|
|
141
|
+
const recovered = inputs.recoverTranscriptRunId?.() ?? null;
|
|
142
|
+
if (recovered && recovered !== inputs.association.runId && isProvablyNewerRunId(recovered, inputs.association.runId)) {
|
|
143
|
+
return {
|
|
144
|
+
scenario: "iterate",
|
|
145
|
+
missionTabVisible: true,
|
|
146
|
+
runId: recovered,
|
|
147
|
+
runIdSource: "transcript",
|
|
148
|
+
pointerInvalidReason: null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
114
151
|
return {
|
|
115
152
|
scenario: "iterate",
|
|
116
153
|
missionTabVisible: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario.js","sourceRoot":"","sources":["../../../src/core/mission-context/scenario.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scenario.js","sourceRoot":"","sources":["../../../src/core/mission-context/scenario.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,5 +36,5 @@ export declare function pathGuard(projectRoot: string, relpath: string): PathGua
|
|
|
36
36
|
* guard.absolute, though in practice fs reads against either produce the
|
|
37
37
|
* same bytes as long as both land under the root).
|
|
38
38
|
*/
|
|
39
|
-
export declare function realPathGuard(projectRoot: string, absoluteInsideRoot: string): PathGuardResult;
|
|
39
|
+
export declare function realPathGuard(projectRoot: string, absoluteInsideRoot: string, precomputedRealRoot?: string): PathGuardResult;
|
|
40
40
|
//# sourceMappingURL=path-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-guard.d.ts","sourceRoot":"","sources":["../../src/core/path-guard.ts"],"names":[],"mappings":"AA0BA,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,gBAAgB,CAAC;AAErB,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CA0E/E;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"path-guard.d.ts","sourceRoot":"","sources":["../../src/core/path-guard.ts"],"names":[],"mappings":"AA0BA,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,gBAAgB,CAAC;AAErB,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CA0E/E;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,EAC1B,mBAAmB,CAAC,EAAE,MAAM,GAC3B,eAAe,CA4CjB"}
|
|
@@ -112,12 +112,19 @@ export function pathGuard(projectRoot, relpath) {
|
|
|
112
112
|
* guard.absolute, though in practice fs reads against either produce the
|
|
113
113
|
* same bytes as long as both land under the root).
|
|
114
114
|
*/
|
|
115
|
-
export function realPathGuard(projectRoot, absoluteInsideRoot) {
|
|
115
|
+
export function realPathGuard(projectRoot, absoluteInsideRoot, precomputedRealRoot) {
|
|
116
116
|
const resolvedRoot = path.resolve(projectRoot);
|
|
117
117
|
let realRoot;
|
|
118
118
|
let realTarget;
|
|
119
119
|
try {
|
|
120
|
-
|
|
120
|
+
// A batch caller resolving many targets against the same project root
|
|
121
|
+
// (e.g. exists-routes.ts) can pass its own once-per-request realpath of
|
|
122
|
+
// that root here, instead of paying a redundant realpathSync(root) on
|
|
123
|
+
// every one of up to N iterations (doubt-review finding,
|
|
124
|
+
// iterate-2026-08-30-triage-file-viewer-followups). Single-path callers
|
|
125
|
+
// are unaffected — the parameter is optional and falls back to the
|
|
126
|
+
// original per-call resolution.
|
|
127
|
+
realRoot = precomputedRealRoot ?? realpathSync(resolvedRoot);
|
|
121
128
|
realTarget = realpathSync(absoluteInsideRoot);
|
|
122
129
|
}
|
|
123
130
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-guard.js","sourceRoot":"","sources":["../../src/core/path-guard.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"path-guard.js","sourceRoot":"","sources":["../../src/core/path-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ShipsLogDocsBundle } from "./shipslog-docs-types.js";
|
|
2
|
+
export type { ShipsLogDocRow, ShipsLogDocsBundle } from "./shipslog-docs-types.js";
|
|
3
|
+
export declare function readShipsLogDocs(projectRoot: string): Promise<ShipsLogDocsBundle>;
|
|
4
|
+
//# sourceMappingURL=shipslog-docs-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shipslog-docs-reader.d.ts","sourceRoot":"","sources":["../../src/core/shipslog-docs-reader.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAkB,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnF,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAyInF,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiBvF"}
|
|
@@ -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"}
|
|
@@ -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,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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* external/mission-context/association-write.ts — the ONE guarded
|
|
3
|
+
* association write (CONTRACT §5), split out of routes.ts (2026-08-31,
|
|
4
|
+
* iterate-2026-08-31-mission-feed-gaps) to stay under the 300-line file-size
|
|
5
|
+
* limit. Pure continuation of the GET handler's persistence step: routes.ts
|
|
6
|
+
* resolves the context and hands the decision here.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent for a first association: the store no-ops when one already
|
|
9
|
+
* exists, so repeated polls perform exactly zero writes after the first.
|
|
10
|
+
* Never a per-GET side-effect.
|
|
11
|
+
*/
|
|
12
|
+
import { revertMissionContext, revertSupersession, setMissionContextOnce, supersedeMissionContext, } from "../../core/mission-context/association.js";
|
|
13
|
+
/**
|
|
14
|
+
* Persist a resolved association — either the FIRST one for a task, or a
|
|
15
|
+
* confirmed supersession of a stale one. Caller must have already checked
|
|
16
|
+
* `associateRunId` is non-null.
|
|
17
|
+
*
|
|
18
|
+
* `associationAtResolve` is the snapshot `resolveMissionContext` actually
|
|
19
|
+
* decided against (captured by the caller BEFORE its slow async work, e.g.
|
|
20
|
+
* `routes.ts`) — not re-read here. Both write paths compare against it, not
|
|
21
|
+
* a fresh `task.missionContext`: by the time this async function runs, a
|
|
22
|
+
* concurrent poll may already have written a NEWER association, and a fresh
|
|
23
|
+
* read here would silently adopt that as the "expected" value, letting THIS
|
|
24
|
+
* poll's now-stale decision overwrite it with no failure involved (a plain
|
|
25
|
+
* lost-update race, doubt-reviewer HIGH, iterate-2026-08-31-mission-feed-gaps
|
|
26
|
+
* — ELOCKED rollback cannot catch it because nothing fails).
|
|
27
|
+
*/
|
|
28
|
+
export async function persistMissionAssociation(store, task, associationAtResolve, associateRunId, associateSource, now, wideWindows) {
|
|
29
|
+
if (!associationAtResolve) {
|
|
30
|
+
const association = {
|
|
31
|
+
kind: "iterate",
|
|
32
|
+
runId: associateRunId,
|
|
33
|
+
observedAt: now().toISOString(),
|
|
34
|
+
source: associateSource,
|
|
35
|
+
};
|
|
36
|
+
if (setMissionContextOnce(store, task.taskId, association)) {
|
|
37
|
+
try {
|
|
38
|
+
await store.persist();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// A lock contention (ELOCKED) or I/O fault must not fail the READ —
|
|
42
|
+
// but the in-memory field MUST be rolled back, or every later poll
|
|
43
|
+
// would see it set, skip the write, and the association would never
|
|
44
|
+
// reach disk (external code review, openai HIGH).
|
|
45
|
+
revertMissionContext(store, task.taskId, association);
|
|
46
|
+
// …and the reach-back must be rolled back WITH it. The marker was
|
|
47
|
+
// recorded before the resolve; leaving it would make every later poll
|
|
48
|
+
// read only the ordinary tail while the task is unidentified again —
|
|
49
|
+
// permanently unreachable for a footer beyond it, which is the very
|
|
50
|
+
// data loss the rollback above exists to prevent, re-entered through
|
|
51
|
+
// the read side (internal code review, MEDIUM).
|
|
52
|
+
wideWindows.delete(task.taskId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (associateSource === "transcript_run_id" && associateRunId !== associationAtResolve.runId) {
|
|
58
|
+
// THE evidence-gated supersession write (association.ts,
|
|
59
|
+
// iterate-2026-08-31-mission-feed-gaps, external code review, openai
|
|
60
|
+
// HIGH). scenario.ts rule 2b has already required a corroborated
|
|
61
|
+
// footer naming a PROVABLY newer run before offering `associateRunId`
|
|
62
|
+
// here — this is the write that makes that correction durable instead
|
|
63
|
+
// of re-proving itself from the transcript on every poll forever.
|
|
64
|
+
const previous = associationAtResolve;
|
|
65
|
+
const association = {
|
|
66
|
+
kind: "iterate",
|
|
67
|
+
runId: associateRunId,
|
|
68
|
+
observedAt: now().toISOString(),
|
|
69
|
+
source: associateSource,
|
|
70
|
+
};
|
|
71
|
+
// Compare-and-set against `previous` (association.ts, external code
|
|
72
|
+
// review openai MEDIUM + doubt-reviewer HIGH): the store's CURRENT value
|
|
73
|
+
// must still equal what this decision was based on, or the write is
|
|
74
|
+
// skipped and the next poll resolves fresh against whatever is now
|
|
75
|
+
// current — never a blind overwrite of a value a faster concurrent poll
|
|
76
|
+
// already corrected further.
|
|
77
|
+
if (supersedeMissionContext(store, task.taskId, association, previous)) {
|
|
78
|
+
try {
|
|
79
|
+
await store.persist();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Same ELOCKED/I-O-fault posture as the first-association rollback
|
|
83
|
+
// above — but there is a PREVIOUS association to restore here, not
|
|
84
|
+
// an empty field to revert to.
|
|
85
|
+
revertSupersession(store, task.taskId, association, previous);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=association-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"association-write.js","sourceRoot":"","sources":["../../../src/external/mission-context/association-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,2CAA2C,CAAC;AAInD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAuB,EACvB,IAAkB,EAClB,oBAAsD,EACtD,cAAsB,EACtB,eAAoD,EACpD,GAAe,EACf,WAA2D;IAE3D,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,MAAM,WAAW,GAA8B;YAC7C,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE;YAC/B,MAAM,EAAE,eAAe;SACxB,CAAC;QACF,IAAI,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,oEAAoE;gBACpE,mEAAmE;gBACnE,oEAAoE;gBACpE,kDAAkD;gBAClD,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBACtD,kEAAkE;gBAClE,sEAAsE;gBACtE,qEAAqE;gBACrE,oEAAoE;gBACpE,qEAAqE;gBACrE,gDAAgD;gBAChD,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,eAAe,KAAK,mBAAmB,IAAI,cAAc,KAAK,oBAAoB,CAAC,KAAK,EAAE,CAAC;QAC7F,yDAAyD;QACzD,qEAAqE;QACrE,iEAAiE;QACjE,sEAAsE;QACtE,sEAAsE;QACtE,kEAAkE;QAClE,MAAM,QAAQ,GAAG,oBAAoB,CAAC;QACtC,MAAM,WAAW,GAA8B;YAC7C,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE;YAC/B,MAAM,EAAE,eAAe;SACxB,CAAC;QACF,oEAAoE;QACpE,yEAAyE;QACzE,oEAAoE;QACpE,mEAAmE;QACnE,wEAAwE;QACxE,6BAA6B;QAC7B,IAAI,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;YACvE,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,mEAAmE;gBACnE,mEAAmE;gBACnE,+BAA+B;gBAC/B,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/external/mission-context/routes.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/external/mission-context/routes.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,wCAAwC,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAGtE,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,mBAAmB,QAAc,CAAC;AAS/C,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,gBAAgB,CAAC;IACxB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,wBAAwB,GAAG,SAAS,CAAC;IACrE;;;;;;;;;;;;OAYG;IACH,kBAAkB,EAAE,CAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,KACd,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,yDAAyD;IACzD,gBAAgB,EAAE,CAChB,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,YAAY,KACf,OAAO,CAAC;QACX,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;QACnC,eAAe,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAC;QACnD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,0EAA0E;QAC1E,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;QACtC,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;KACvC,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,wBAAwB,GAAG,IAAI,CAuK/E"}
|