@svenroth-ai/shipwright 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/dist/assets/{EmbeddedTerminal-5QvKe3_a.js → EmbeddedTerminal-CqCQUDtp.js} +1 -1
- package/client/dist/assets/{abnfDiagram-VRR7QNED-CXi9HegQ.js → abnfDiagram-VRR7QNED-DX2objTP.js} +1 -1
- package/client/dist/assets/{arc-DLh4GiqR.js → arc-DQmjbsFU.js} +1 -1
- package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DUypQ8dQ.js → architectureDiagram-ZJ3FMSHR-DAvCsPCW.js} +1 -1
- package/client/dist/assets/{blockDiagram-677ZJIJ3-D2cVMKJG.js → blockDiagram-677ZJIJ3-DC-dlyYI.js} +1 -1
- package/client/dist/assets/{c4Diagram-LMCZKHZV-DtruBGJw.js → c4Diagram-LMCZKHZV-DSlmXfhE.js} +1 -1
- package/client/dist/assets/channel-BfmIcrp7.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-CAfQkFw2.js → chunk-2Q5K7J3B-C111EHL6.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-CPWXoLnQ.js → chunk-32BRIVSS-DrCYs2XG.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-xVc3oppQ.js → chunk-5VM5RSS4-DIejoaXS.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-CUpl6fRR.js → chunk-EX3LRPZG-CGWNeH2g.js} +1 -1
- package/client/dist/assets/{chunk-JWPE2WC7-NejUp56x.js → chunk-JWPE2WC7-CCH0SRFY.js} +1 -1
- package/client/dist/assets/{chunk-MOJQB5TN-C9-2lLg0.js → chunk-MOJQB5TN-B3OpZGRv.js} +1 -1
- package/client/dist/assets/{chunk-RYQCIY6F-BAPtwABy.js → chunk-RYQCIY6F-BKhdp_8v.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-Dwzihw26.js → chunk-V7JOEXUC-B6Bu8x1y.js} +1 -1
- package/client/dist/assets/{chunk-VR4S4FIN-9-iArFJM.js → chunk-VR4S4FIN-OgFi2_iB.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-DiWHOrqe.js → chunk-XXDRQBXY-xyjuuhxl.js} +1 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-HfUQZ6Uc.js +1 -0
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-HfUQZ6Uc.js +1 -0
- package/client/dist/assets/{cose-bilkent-JH36ORCC-Cp04EOcH.js → cose-bilkent-JH36ORCC-BQIH3SCK.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-D--GN1v8.js → cynefin-VYW2F7L2-oyLAz8te.js} +1 -1
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-BGH0o_qp.js → cynefinDiagram-TSTJHNR4-DoLCsH0l.js} +1 -1
- package/client/dist/assets/{dagre-VKFMJZFB-DSKkIKlj.js → dagre-VKFMJZFB-D7djx1_Y.js} +1 -1
- package/client/dist/assets/{diagram-FQU43EPY-Cs_C4lb-.js → diagram-FQU43EPY-DFuYE0Vf.js} +1 -1
- package/client/dist/assets/{diagram-G47NLZAW-oDtAA8O_.js → diagram-G47NLZAW-CffCZVXk.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-BiFMjqSH.js → diagram-NH7WQ7WH-BhrHtUlt.js} +1 -1
- package/client/dist/assets/{diagram-OA4YK3LP-Ccs3thCj.js → diagram-OA4YK3LP-CwQPbOn0.js} +1 -1
- package/client/dist/assets/{diagram-WEI45ONY-CdZNqgO3.js → diagram-WEI45ONY-abtYnYqH.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-CapTA0VL.js → ebnfDiagram-CCIWWBDH-DfV7gT4m.js} +1 -1
- package/client/dist/assets/{erDiagram-Q63AITRT-BcRNEP8s.js → erDiagram-Q63AITRT-vtbCprgH.js} +1 -1
- package/client/dist/assets/{flowDiagram-23GEKE2U-CJ_zF7e_.js → flowDiagram-23GEKE2U-CVCgcyDF.js} +1 -1
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-CnJdcg9A.js → ganttDiagram-NO4QXBWP-BclyOgMb.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-YTUQ_ELk.js → gitGraphDiagram-IHSO6WYX-BXT4rIKj.js} +1 -1
- package/client/dist/assets/index-CKU9dY18.css +1 -0
- package/client/dist/assets/index-DOMl6atu.js +847 -0
- package/client/dist/assets/{infoDiagram-FWYZ7A6U-CLOP_ZWD.js → infoDiagram-FWYZ7A6U-Dr4mN24J.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-aFTIzr7o.js → ishikawaDiagram-FXEZZL3T-BBUFWq5C.js} +1 -1
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-CbPJB4xd.js → journeyDiagram-5HDEW3XC-CmclipcQ.js} +1 -1
- package/client/dist/assets/{kanban-definition-HUTT4EX6-BoyhytIS.js → kanban-definition-HUTT4EX6-eIzUeZ03.js} +1 -1
- package/client/dist/assets/{linear-1VXA-uBg.js → linear-DGiT7uKK.js} +1 -1
- package/client/dist/assets/{mermaid.core-D_lO2yK9.js → mermaid.core-BcLNGbxW.js} +4 -4
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-iFK7LXMx.js → mindmap-definition-LN4V7U3C-C4ANnNiP.js} +1 -1
- package/client/dist/assets/{pegDiagram-2B236MQR-DNmcmfA-.js → pegDiagram-2B236MQR-DnMeh3Yh.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-ekx83O5b.js → pieDiagram-ENE6RG2P-CKV_rkhF.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-DayyD1l8.js → quadrantDiagram-ABIIQ3AL-BuUsGwHh.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-Bdgz7S6G.js → railroadDiagram-RFXS5EU6-BwwdKnFL.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-szP3Muld.js → requirementDiagram-TGXJPOKE-CpQZouJV.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-Ct3rzgUj.js → sankeyDiagram-HTMAVEWB-4fnDUNVa.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-_69EfmOU.js → sequenceDiagram-DBY2YBRQ-BOcaWlM0.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-BSOU06J2.js → sizeCapture-X5ZJPWSS-_pv-9R0c.js} +1 -1
- package/client/dist/assets/{stateDiagram-2N3HPSRC-HmOmFwQm.js → stateDiagram-2N3HPSRC-CFwCOonY.js} +1 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-srkiu3Ib.js +1 -0
- package/client/dist/assets/{swimlanes-5IMT3BWC-CVg_4oT7.js → swimlanes-5IMT3BWC-DFa2tzxu.js} +2 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-Dq-0K9Zm.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-CBBaDKXm.js → timeline-definition-FHXFAJF6-rhGYElgn.js} +1 -1
- package/client/dist/assets/{vennDiagram-L72KCM5P-CBXiWPMc.js → vennDiagram-L72KCM5P-BoGjRxyA.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-EHGQE667-uhBCZoW0.js → wardleyDiagram-EHGQE667-D-IGv5bH.js} +1 -1
- package/client/dist/assets/{xychartDiagram-FW5EYKEG-xxE_wY5O.js → xychartDiagram-FW5EYKEG-D9PFTCfm.js} +1 -1
- package/client/dist/index.html +27 -27
- package/lib/claude-cli.mjs +173 -173
- package/lib/preflight.mjs +252 -252
- package/lib/probe-path.mjs +84 -84
- package/lib/probes.mjs +10 -4
- package/lib/server.mjs +506 -369
- package/lib/util.mjs +157 -157
- package/lib/win32-spawn.mjs +253 -253
- package/package.json +68 -68
- package/scripts/deploy-procs.mjs +208 -208
- package/scripts/deploy-swap.mjs +276 -276
- package/scripts/kill-targets.js +140 -140
- package/scripts/repair-claude-json.mjs +295 -295
- package/server/dist/config/default-actions.json +90 -90
- package/server/dist/core/mission-context/association.d.ts +46 -0
- package/server/dist/core/mission-context/association.d.ts.map +1 -1
- package/server/dist/core/mission-context/association.js +69 -0
- package/server/dist/core/mission-context/association.js.map +1 -1
- package/server/dist/core/mission-context/resolver-iterate.d.ts +6 -0
- package/server/dist/core/mission-context/resolver-iterate.d.ts.map +1 -0
- package/server/dist/core/mission-context/resolver-iterate.js +202 -0
- package/server/dist/core/mission-context/resolver-iterate.js.map +1 -0
- package/server/dist/core/mission-context/resolver-parts.d.ts +20 -0
- package/server/dist/core/mission-context/resolver-parts.d.ts.map +1 -1
- package/server/dist/core/mission-context/resolver-parts.js +92 -0
- package/server/dist/core/mission-context/resolver-parts.js.map +1 -1
- package/server/dist/core/mission-context/resolver.d.ts +1 -1
- package/server/dist/core/mission-context/resolver.d.ts.map +1 -1
- package/server/dist/core/mission-context/resolver.js +17 -199
- package/server/dist/core/mission-context/resolver.js.map +1 -1
- package/server/dist/core/mission-context/run-id-recovery.d.ts +21 -5
- package/server/dist/core/mission-context/run-id-recovery.d.ts.map +1 -1
- package/server/dist/core/mission-context/run-id-recovery.js +32 -5
- package/server/dist/core/mission-context/run-id-recovery.js.map +1 -1
- package/server/dist/core/mission-context/scenario.d.ts +18 -11
- package/server/dist/core/mission-context/scenario.d.ts.map +1 -1
- package/server/dist/core/mission-context/scenario.js +40 -3
- package/server/dist/core/mission-context/scenario.js.map +1 -1
- package/server/dist/core/path-guard.d.ts +1 -1
- package/server/dist/core/path-guard.d.ts.map +1 -1
- package/server/dist/core/path-guard.js +9 -2
- package/server/dist/core/path-guard.js.map +1 -1
- package/server/dist/core/sdk-sessions-merge.d.ts +19 -0
- package/server/dist/core/sdk-sessions-merge.d.ts.map +1 -1
- package/server/dist/core/sdk-sessions-merge.js +19 -5
- package/server/dist/core/sdk-sessions-merge.js.map +1 -1
- package/server/dist/core/sdk-sessions-refresh.d.ts +50 -0
- package/server/dist/core/sdk-sessions-refresh.d.ts.map +1 -0
- package/server/dist/core/sdk-sessions-refresh.js +69 -0
- package/server/dist/core/sdk-sessions-refresh.js.map +1 -0
- package/server/dist/core/sdk-sessions-store.d.ts +2 -0
- package/server/dist/core/sdk-sessions-store.d.ts.map +1 -1
- package/server/dist/core/sdk-sessions-store.js +7 -9
- package/server/dist/core/sdk-sessions-store.js.map +1 -1
- package/server/dist/core/shipslog-docs-reader.d.ts +4 -0
- package/server/dist/core/shipslog-docs-reader.d.ts.map +1 -0
- package/server/dist/core/shipslog-docs-reader.js +181 -0
- package/server/dist/core/shipslog-docs-reader.js.map +1 -0
- package/server/dist/core/shipslog-docs-types.d.ts +15 -0
- package/server/dist/core/shipslog-docs-types.d.ts.map +1 -0
- package/server/dist/core/shipslog-docs-types.js +14 -0
- package/server/dist/core/shipslog-docs-types.js.map +1 -0
- package/server/dist/core/shipwright-plugin-version-reader.d.ts +15 -0
- package/server/dist/core/shipwright-plugin-version-reader.d.ts.map +1 -0
- package/server/dist/core/shipwright-plugin-version-reader.js +49 -0
- package/server/dist/core/shipwright-plugin-version-reader.js.map +1 -0
- package/server/dist/external/design-review/serve.js +27 -27
- package/server/dist/external/inbox/_derive.d.ts +2 -25
- package/server/dist/external/inbox/_derive.d.ts.map +1 -1
- package/server/dist/external/inbox/_derive.js.map +1 -1
- package/server/dist/external/inbox/_lead.d.ts +23 -0
- package/server/dist/external/inbox/_lead.d.ts.map +1 -0
- package/server/dist/external/inbox/_lead.js +83 -0
- package/server/dist/external/inbox/_lead.js.map +1 -0
- package/server/dist/external/inbox/_types.d.ts +32 -0
- package/server/dist/external/inbox/_types.d.ts.map +1 -0
- package/server/dist/external/inbox/_types.js +10 -0
- package/server/dist/external/inbox/_types.js.map +1 -0
- package/server/dist/external/inbox/routes.d.ts.map +1 -1
- package/server/dist/external/inbox/routes.js +29 -1
- package/server/dist/external/inbox/routes.js.map +1 -1
- package/server/dist/external/launch/claim-holder-gate.d.ts +42 -0
- package/server/dist/external/launch/claim-holder-gate.d.ts.map +1 -0
- package/server/dist/external/launch/claim-holder-gate.js +87 -0
- package/server/dist/external/launch/claim-holder-gate.js.map +1 -0
- package/server/dist/external/launch/routes.d.ts.map +1 -1
- package/server/dist/external/launch/routes.js +23 -19
- package/server/dist/external/launch/routes.js.map +1 -1
- package/server/dist/external/mission-context/association-write.d.ts +22 -0
- package/server/dist/external/mission-context/association-write.d.ts.map +1 -0
- package/server/dist/external/mission-context/association-write.js +90 -0
- package/server/dist/external/mission-context/association-write.js.map +1 -0
- package/server/dist/external/mission-context/routes.d.ts.map +1 -1
- package/server/dist/external/mission-context/routes.js +18 -31
- package/server/dist/external/mission-context/routes.js.map +1 -1
- package/server/dist/external/org/lead-question-threads.d.ts +46 -0
- package/server/dist/external/org/lead-question-threads.d.ts.map +1 -0
- package/server/dist/external/org/lead-question-threads.js +132 -0
- package/server/dist/external/org/lead-question-threads.js.map +1 -0
- package/server/dist/external/org/mount.d.ts +3 -0
- package/server/dist/external/org/mount.d.ts.map +1 -1
- package/server/dist/external/org/mount.js +2 -1
- package/server/dist/external/org/mount.js.map +1 -1
- package/server/dist/external/org/usage.d.ts.map +1 -1
- package/server/dist/external/org/usage.js +20 -2
- package/server/dist/external/org/usage.js.map +1 -1
- package/server/dist/external/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +10 -13
- package/server/dist/external/routes.js.map +1 -1
- package/server/dist/external/shipslog-docs/routes.d.ts +10 -0
- package/server/dist/external/shipslog-docs/routes.d.ts.map +1 -0
- package/server/dist/external/shipslog-docs/routes.js +41 -0
- package/server/dist/external/shipslog-docs/routes.js.map +1 -0
- package/server/dist/routes/diagnostics.d.ts +12 -0
- package/server/dist/routes/diagnostics.d.ts.map +1 -1
- package/server/dist/routes/diagnostics.js +4 -1
- package/server/dist/routes/diagnostics.js.map +1 -1
- package/server/dist/routes/org-threads-composite.d.ts +24 -0
- package/server/dist/routes/org-threads-composite.d.ts.map +1 -0
- package/server/dist/routes/org-threads-composite.js +51 -0
- package/server/dist/routes/org-threads-composite.js.map +1 -0
- package/server/dist/routes/org.d.ts +5 -0
- package/server/dist/routes/org.d.ts.map +1 -1
- package/server/dist/routes/org.js +13 -0
- package/server/dist/routes/org.js.map +1 -1
- package/server/dist/terminal/pty-manager.d.ts +23 -1
- package/server/dist/terminal/pty-manager.d.ts.map +1 -1
- package/server/dist/terminal/pty-manager.js +22 -3
- package/server/dist/terminal/pty-manager.js.map +1 -1
- package/server/dist/terminal/pty-write-chunker.d.ts +109 -0
- package/server/dist/terminal/pty-write-chunker.d.ts.map +1 -0
- package/server/dist/terminal/pty-write-chunker.js +234 -0
- package/server/dist/terminal/pty-write-chunker.js.map +1 -0
- package/server/dist/types/org.d.ts +19 -0
- package/server/dist/types/org.d.ts.map +1 -1
- package/server/package.json +1 -1
- package/server/profiles/PROFILE_SCHEMA_VERSION +1 -1
- package/server/profiles/README.md +27 -27
- package/server/profiles/python-plugin-monorepo.json +35 -35
- package/server/profiles/supabase-nextjs.json +253 -253
- package/server/profiles/vite-hono.json +92 -92
- package/client/dist/assets/channel-C_k-9jsa.js +0 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-CsEPq9Ac.js +0 -1
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsEPq9Ac.js +0 -1
- package/client/dist/assets/index-6nZ1bt0a.css +0 -1
- package/client/dist/assets/index-irQhGNpn.js +0 -828
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-BW8H33dv.js +0 -1
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BaRlxcPD.js +0 -8
|
@@ -7,10 +7,13 @@
|
|
|
7
7
|
* `detectAwaitingUserQuestion`.
|
|
8
8
|
* - `terminal_prompt` — a waiting picker visible in the LIVE headless
|
|
9
9
|
* mirror but not (yet) journaled to the JSONL.
|
|
10
|
+
* - `lead_question` — a leadwright follow-up WRITTEN onto the task's
|
|
11
|
+
* `description` (FR-04.19), not derived from a JSONL/terminal read
|
|
12
|
+
* — see `./_lead.ts`.
|
|
10
13
|
*
|
|
11
14
|
* Precedence: ask_tool > terminal_prompt > text_question. terminal_prompt
|
|
12
15
|
* is a post-pass over the JSONL-derived set so the mtime-keyed cache
|
|
13
|
-
* stays byte-identical.
|
|
16
|
+
* stays byte-identical. `lead_question` is independent of that precedence.
|
|
14
17
|
*
|
|
15
18
|
* Phase A4 hot-path: per-session derive cache + negative-result cache
|
|
16
19
|
* — see `./_cache.ts`. JSONL cold-path + terminal_prompt post-pass live
|
|
@@ -19,6 +22,7 @@
|
|
|
19
22
|
import { Hono } from "hono";
|
|
20
23
|
import { inboxDeriveCache } from "./_cache.js";
|
|
21
24
|
import { deriveInboxFromJsonl, appendTerminalPrompts } from "./_derive.js";
|
|
25
|
+
import { appendLeadQuestions, extractLeadQuestionBody, LEAD_QUESTION_DISMISS_PREFIX, } from "./_lead.js";
|
|
22
26
|
export function createInboxRouter(deps) {
|
|
23
27
|
const app = new Hono();
|
|
24
28
|
const { store, watcher, ptyManager } = deps;
|
|
@@ -28,6 +32,7 @@ export function createInboxRouter(deps) {
|
|
|
28
32
|
watcher,
|
|
29
33
|
});
|
|
30
34
|
appendTerminalPrompts(entries, { store, ptyManager });
|
|
35
|
+
appendLeadQuestions(entries, { store });
|
|
31
36
|
if (storeDirty)
|
|
32
37
|
await store.persist();
|
|
33
38
|
return c.json({ items: entries });
|
|
@@ -52,6 +57,29 @@ export function createInboxRouter(deps) {
|
|
|
52
57
|
await store.persist();
|
|
53
58
|
return c.json({ ok: true, taskId: task.taskId });
|
|
54
59
|
}
|
|
60
|
+
// lead_question dismiss — the id is `lq-<taskId>`, not a JSONL toolUseId
|
|
61
|
+
// (a written kind has no toolUseId at all). Reuses `dismissedToolUseIds`
|
|
62
|
+
// as a generic dismissed-id set rather than adding a parallel field.
|
|
63
|
+
if (toolUseId.startsWith(LEAD_QUESTION_DISMISS_PREFIX)) {
|
|
64
|
+
const taskId = toolUseId.slice(LEAD_QUESTION_DISMISS_PREFIX.length);
|
|
65
|
+
const task = store.get(taskId);
|
|
66
|
+
if (task &&
|
|
67
|
+
extractLeadQuestionBody(task.description) !== null &&
|
|
68
|
+
!task.inbox.dismissedToolUseIds.includes(toolUseId)) {
|
|
69
|
+
store.patch(task.taskId, {
|
|
70
|
+
inbox: {
|
|
71
|
+
pendingToolUseIds: task.inbox.pendingToolUseIds,
|
|
72
|
+
dismissedToolUseIds: [
|
|
73
|
+
...task.inbox.dismissedToolUseIds,
|
|
74
|
+
toolUseId,
|
|
75
|
+
],
|
|
76
|
+
lastProcessedByteOffset: task.inbox.lastProcessedByteOffset,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
await store.persist();
|
|
80
|
+
return c.json({ ok: true, taskId: task.taskId });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
55
83
|
return c.json({ ok: false, error: "toolUseId not found in any pending set" }, 404);
|
|
56
84
|
});
|
|
57
85
|
return app;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/external/inbox/routes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/external/inbox/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ExternalTask } from "../../core/sdk-sessions-store.js";
|
|
2
|
+
/**
|
|
3
|
+
* How long a claim stays launch-eligible after `claimedAt`. §10.9 left the
|
|
4
|
+
* VALUE unfixed ("a named limit"), justified only against one criterion: a
|
|
5
|
+
* holder who restarts LATE must still succeed, never be locked out (AC
|
|
6
|
+
* FR-04.22) — the fix for a stale token is re-claiming, not an indefinite
|
|
7
|
+
* grant. 24h is generous enough to survive a sleeping laptop, a slow beat,
|
|
8
|
+
* or an overnight gap between claim and restart, while still bounding how
|
|
9
|
+
* long an abandoned claim stays replayable.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CLAIM_LAUNCH_WINDOW_MS: number;
|
|
12
|
+
/**
|
|
13
|
+
* Doubt-review finding (iterate-2026-09-03-claim-holder-launch): `withinWindow`
|
|
14
|
+
* originally only bounded the claim's age from ABOVE, so a well-formed but
|
|
15
|
+
* FUTURE-dated `claimedAt` (clock skew between the webui host and the daemon
|
|
16
|
+
* host, or a daemon bug) made `Date.now() - claimedAtMs` negative — always
|
|
17
|
+
* `<= CLAIM_LAUNCH_WINDOW_MS`, reading as "very fresh" instead of being
|
|
18
|
+
* rejected. `sdk-sessions-validate.ts` does no date-sanity check on
|
|
19
|
+
* `claimedAt`, so this module is the only place that can catch it. A small
|
|
20
|
+
* tolerance (rather than rejecting any future timestamp outright) survives
|
|
21
|
+
* ordinary clock drift between two processes' wall clocks without reopening
|
|
22
|
+
* the gap: anything beyond it is refused as not-within-window, same as an
|
|
23
|
+
* expired claim.
|
|
24
|
+
*/
|
|
25
|
+
export declare const CLAIM_CLOCK_SKEW_TOLERANCE_MS: number;
|
|
26
|
+
export type ClaimGateResult = {
|
|
27
|
+
allowed: true;
|
|
28
|
+
} | {
|
|
29
|
+
allowed: false;
|
|
30
|
+
error: Record<string, unknown>;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Decide whether a launch request may proceed against a (possibly) claimed
|
|
34
|
+
* task. Returns `{ allowed: true }` when there is no active claim, or when
|
|
35
|
+
* `bodyClaimToken` matches the task's current `claimToken` AND the claim is
|
|
36
|
+
* within the launch window. Otherwise refuses with the `task_claimed`
|
|
37
|
+
* envelope — `claimExpired: true` distinguishes "right token, too old" from
|
|
38
|
+
* a foreign/absent token (trap: an expired claim must read differently from
|
|
39
|
+
* someone else's).
|
|
40
|
+
*/
|
|
41
|
+
export declare function checkClaimHolderGate(task: ExternalTask, bodyClaimToken: string | undefined): ClaimGateResult;
|
|
42
|
+
//# sourceMappingURL=claim-holder-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claim-holder-gate.d.ts","sourceRoot":"","sources":["../../../src/external/launch/claim-holder-gate.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAErE;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,6BAA6B,QAAgB,CAAC;AAE3D,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEvD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,eAAe,CAqCjB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* external/launch/claim-holder-gate.ts — FR-04.22 / V5 (leadwright
|
|
3
|
+
* spec/lead-model-spec.md §5.2 + §10.9, PO decision 2026-08-16).
|
|
4
|
+
*
|
|
5
|
+
* The launch route refuses everyone while `claimToken` is set — EXCEPT the
|
|
6
|
+
* claim holder, who must be able to (re)launch (AC FR-04.22). `task` passed
|
|
7
|
+
* in here MUST already be the freshly-disk-read row (see
|
|
8
|
+
* SdkSessionsStore.refreshRowFromDisk in ../../core/sdk-sessions-store.ts) —
|
|
9
|
+
* this module makes no disk access itself and trusts the caller's freshness.
|
|
10
|
+
*
|
|
11
|
+
* §10.9 decided variant (a) plus a time window: the exception accepts the
|
|
12
|
+
* caller presenting the CURRENT claimToken, and additionally requires
|
|
13
|
+
* `claimedAt` to be no older than CLAIM_LAUNCH_WINDOW_MS. Explicitly
|
|
14
|
+
* rejected: making the token single-use (valid only while `launchedAt` is
|
|
15
|
+
* unset) — that breaks AC FR-04.22's "a restart by the holder succeeds".
|
|
16
|
+
*
|
|
17
|
+
* Named residual risk (§8, §10.9): both sides run as the same local user
|
|
18
|
+
* with sdk-sessions.json readable, so this defends against a MISTAKE (a
|
|
19
|
+
* stale browser tab racing a daemon claim), not a local attacker — a
|
|
20
|
+
* process on the same machine under the same user can read the token
|
|
21
|
+
* directly. The window only shrinks that exposure; it does not close it.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* How long a claim stays launch-eligible after `claimedAt`. §10.9 left the
|
|
25
|
+
* VALUE unfixed ("a named limit"), justified only against one criterion: a
|
|
26
|
+
* holder who restarts LATE must still succeed, never be locked out (AC
|
|
27
|
+
* FR-04.22) — the fix for a stale token is re-claiming, not an indefinite
|
|
28
|
+
* grant. 24h is generous enough to survive a sleeping laptop, a slow beat,
|
|
29
|
+
* or an overnight gap between claim and restart, while still bounding how
|
|
30
|
+
* long an abandoned claim stays replayable.
|
|
31
|
+
*/
|
|
32
|
+
export const CLAIM_LAUNCH_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
33
|
+
/**
|
|
34
|
+
* Doubt-review finding (iterate-2026-09-03-claim-holder-launch): `withinWindow`
|
|
35
|
+
* originally only bounded the claim's age from ABOVE, so a well-formed but
|
|
36
|
+
* FUTURE-dated `claimedAt` (clock skew between the webui host and the daemon
|
|
37
|
+
* host, or a daemon bug) made `Date.now() - claimedAtMs` negative — always
|
|
38
|
+
* `<= CLAIM_LAUNCH_WINDOW_MS`, reading as "very fresh" instead of being
|
|
39
|
+
* rejected. `sdk-sessions-validate.ts` does no date-sanity check on
|
|
40
|
+
* `claimedAt`, so this module is the only place that can catch it. A small
|
|
41
|
+
* tolerance (rather than rejecting any future timestamp outright) survives
|
|
42
|
+
* ordinary clock drift between two processes' wall clocks without reopening
|
|
43
|
+
* the gap: anything beyond it is refused as not-within-window, same as an
|
|
44
|
+
* expired claim.
|
|
45
|
+
*/
|
|
46
|
+
export const CLAIM_CLOCK_SKEW_TOLERANCE_MS = 5 * 60 * 1000;
|
|
47
|
+
/**
|
|
48
|
+
* Decide whether a launch request may proceed against a (possibly) claimed
|
|
49
|
+
* task. Returns `{ allowed: true }` when there is no active claim, or when
|
|
50
|
+
* `bodyClaimToken` matches the task's current `claimToken` AND the claim is
|
|
51
|
+
* within the launch window. Otherwise refuses with the `task_claimed`
|
|
52
|
+
* envelope — `claimExpired: true` distinguishes "right token, too old" from
|
|
53
|
+
* a foreign/absent token (trap: an expired claim must read differently from
|
|
54
|
+
* someone else's).
|
|
55
|
+
*/
|
|
56
|
+
export function checkClaimHolderGate(task, bodyClaimToken) {
|
|
57
|
+
if (typeof task.claimToken !== "string" || task.claimToken.length === 0) {
|
|
58
|
+
return { allowed: true };
|
|
59
|
+
}
|
|
60
|
+
const tokenMatches = bodyClaimToken !== undefined && bodyClaimToken === task.claimToken;
|
|
61
|
+
const claimedAtMs = task.claimedAt ? Date.parse(task.claimedAt) : NaN;
|
|
62
|
+
const age = Date.now() - claimedAtMs;
|
|
63
|
+
const withinWindow = Number.isFinite(claimedAtMs) &&
|
|
64
|
+
age >= -CLAIM_CLOCK_SKEW_TOLERANCE_MS &&
|
|
65
|
+
age <= CLAIM_LAUNCH_WINDOW_MS;
|
|
66
|
+
if (tokenMatches && withinWindow) {
|
|
67
|
+
return { allowed: true };
|
|
68
|
+
}
|
|
69
|
+
console.warn(JSON.stringify({
|
|
70
|
+
level: "warn",
|
|
71
|
+
message: "task_claimed: launch refused while claimToken is set",
|
|
72
|
+
taskId: task.taskId,
|
|
73
|
+
claimedBy: task.claimedBy,
|
|
74
|
+
claimedAt: task.claimedAt,
|
|
75
|
+
claimPid: task.claimPid,
|
|
76
|
+
reason: tokenMatches ? "claim_expired" : "foreign_claim",
|
|
77
|
+
}));
|
|
78
|
+
const error = {
|
|
79
|
+
error: "task_claimed",
|
|
80
|
+
claimedBy: task.claimedBy,
|
|
81
|
+
claimedAt: task.claimedAt,
|
|
82
|
+
};
|
|
83
|
+
if (tokenMatches)
|
|
84
|
+
error.claimExpired = true;
|
|
85
|
+
return { allowed: false, error };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=claim-holder-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claim-holder-gate.js","sourceRoot":"","sources":["../../../src/external/launch/claim-holder-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAM3D;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAkB,EAClB,cAAkC;IAElC,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,MAAM,YAAY,GAChB,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,CAAC,UAAU,CAAC;IACrE,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACtE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC;IACrC,MAAM,YAAY,GAChB,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC5B,GAAG,IAAI,CAAC,6BAA6B;QACrC,GAAG,IAAI,sBAAsB,CAAC;IAEhC,IAAI,YAAY,IAAI,YAAY,EAAE,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,IAAI,CACV,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,sDAAsD;QAC/D,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe;KACzD,CAAC,CACH,CAAC;IAEF,MAAM,KAAK,GAA4B;QACrC,KAAK,EAAE,cAAc;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;IACF,IAAI,YAAY;QAAE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;IAC5C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/external/launch/routes.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAEjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/external/launch/routes.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAEjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AActE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,gBAAgB,CAAC;IACxB,UAAU,EAAE;QAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC7C,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,wBAAwB,GAAG,SAAS,CAAC;IACtE,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvE;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAwN/D"}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import { Hono } from "hono";
|
|
21
21
|
import { withLiveSession } from "../_shared/helpers.js";
|
|
22
22
|
import { parseLaunchBody, applyPhaseTaskBranch, applyCampaignBranch, applyCampaignStepBranch, applyMasterRunBranch, applyActionSubstitutionBranch, applyLegacyFallbackBranch, } from "./_helpers.js";
|
|
23
|
+
import { checkClaimHolderGate } from "./claim-holder-gate.js";
|
|
23
24
|
export function createLaunchRouter(deps) {
|
|
24
25
|
const app = new Hono();
|
|
25
26
|
const { store, ptyManager, getProjectById, runConfigReader, jsonlExistsOnDisk } = deps;
|
|
@@ -28,7 +29,7 @@ export function createLaunchRouter(deps) {
|
|
|
28
29
|
const body = rawBody && typeof rawBody === "object" && !Array.isArray(rawBody)
|
|
29
30
|
? rawBody
|
|
30
31
|
: {};
|
|
31
|
-
|
|
32
|
+
let task = store.get(c.req.param("id"));
|
|
32
33
|
if (!task)
|
|
33
34
|
return c.json({ error: "Task not found" }, 404);
|
|
34
35
|
// Section 03 (iterate 3) — O20 idempotency guard. Reject re-launch on
|
|
@@ -39,24 +40,27 @@ export function createLaunchRouter(deps) {
|
|
|
39
40
|
return c.json({ error: "launch_invalid_state", state: task.state }, 409);
|
|
40
41
|
}
|
|
41
42
|
// iterate-2026-05-14 lead-foundation-task-schema (leadwright Phase 1).
|
|
42
|
-
// While a task is claimed the
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
// While a task is claimed the launch route MUST step aside for anyone
|
|
44
|
+
// but the claim HOLDER (FR-04.22/V5, iterate-2026-09-03-claim-holder-launch)
|
|
45
|
+
// — so a stranger and the daemon don't fight over the same session
|
|
46
|
+
// (stale SQLite lock, interleaved JSONL, double-running shells), while
|
|
47
|
+
// the holder itself can still (re)launch. External review HIGH-2: only
|
|
48
|
+
// `claimToken` triggers the 409.
|
|
49
|
+
//
|
|
50
|
+
// The in-memory row can be STALE — `load()` runs once at server boot
|
|
51
|
+
// (index.ts), so a foreign claim written to disk by the leadwright
|
|
52
|
+
// daemon only reaches this process's memory via its OWN persist(). A
|
|
53
|
+
// webui that has persisted nothing since the claim was written would
|
|
54
|
+
// otherwise see no claim at all (the normal case for an idle daemon
|
|
55
|
+
// with no browser open). Refresh this one row from disk first — never
|
|
56
|
+
// re-run `load()` (a guarded no-op after the first call).
|
|
57
|
+
const freshTask = await store.refreshRowFromDisk(task.taskId);
|
|
58
|
+
if (freshTask)
|
|
59
|
+
task = freshTask;
|
|
60
|
+
const bodyClaimToken = typeof body.claimToken === "string" ? body.claimToken : undefined;
|
|
61
|
+
const claimGate = checkClaimHolderGate(task, bodyClaimToken);
|
|
62
|
+
if (!claimGate.allowed) {
|
|
63
|
+
return c.json(claimGate.error, 409);
|
|
60
64
|
}
|
|
61
65
|
// Parse + apply once-set-always-used (v0.4.1 fallback contract).
|
|
62
66
|
const parseResult = parseLaunchBody(body, task);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/external/launch/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAQ5B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,6BAA6B,EAC7B,yBAAyB,GAE1B,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/external/launch/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"}
|
|
@@ -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"}
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { Hono } from "hono";
|
|
22
22
|
import { parseDocId } from "../../core/mission-context/doc-ids.js";
|
|
23
|
-
import { revertMissionContext, setMissionContextOnce, } from "../../core/mission-context/association.js";
|
|
24
23
|
import { resolveMissionContext, readDocumentBody, } from "../../core/mission-context/resolver.js";
|
|
25
24
|
import { readAllowedRoots } from "../../core/mission-context/worktree-roots.js";
|
|
26
25
|
import { samePath } from "../../core/mission-context/pointer.js";
|
|
26
|
+
import { persistMissionAssociation } from "./association-write.js";
|
|
27
27
|
/** Bounded tail of the transcript — enough for a `pr-link`, never the whole file. */
|
|
28
28
|
export const TRANSCRIPT_TAIL_BYTES = 512 * 1024;
|
|
29
29
|
/**
|
|
@@ -129,6 +129,17 @@ export function createMissionContextRouter(deps) {
|
|
|
129
129
|
scanned: wide ? read.revision : (window?.scanned ?? ""),
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
|
+
// Snapshotted ONCE, here — the exact value `resolveMissionContext` bases
|
|
133
|
+
// `associateRunId`/`associateSource` on. The write below must compare
|
|
134
|
+
// against THIS reference, not a fresh re-read of `task.missionContext` at
|
|
135
|
+
// write time: the resolve that follows does slow async work (git calls in
|
|
136
|
+
// resolver-iterate.ts), during which a concurrent poll (multi-tab, or the
|
|
137
|
+
// next ~1s tick landing first) can legitimately write a NEWER association
|
|
138
|
+
// — re-reading late would then "expect" that newer value and let this
|
|
139
|
+
// poll's now-stale decision overwrite it (doubt-reviewer HIGH,
|
|
140
|
+
// iterate-2026-08-31-mission-feed-gaps: a lost-update/TOCTOU race with no
|
|
141
|
+
// failure involved, so ELOCKED rollback never catches it).
|
|
142
|
+
const associationAtResolve = task.missionContext ?? null;
|
|
132
143
|
const { context, associateRunId, associateSource } = await resolveMissionContext({
|
|
133
144
|
taskId: task.taskId,
|
|
134
145
|
sessionUuid: task.sessionUuid,
|
|
@@ -140,38 +151,14 @@ export function createMissionContextRouter(deps) {
|
|
|
140
151
|
taskTerminal: task.state === "done" || task.state === "launch_failed",
|
|
141
152
|
// Server-held, server-written — this is what keeps a FINALIZED iterate
|
|
142
153
|
// resolvable after its `iterate_active` pointer was pruned.
|
|
143
|
-
association:
|
|
154
|
+
association: associationAtResolve,
|
|
144
155
|
...facts,
|
|
145
156
|
}, deps.resolveDeps);
|
|
146
|
-
// THE one guarded association write (CONTRACT §5)
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
if (associateRunId
|
|
150
|
-
|
|
151
|
-
kind: "iterate",
|
|
152
|
-
runId: associateRunId,
|
|
153
|
-
observedAt: now().toISOString(),
|
|
154
|
-
source: associateSource,
|
|
155
|
-
};
|
|
156
|
-
if (setMissionContextOnce(store, task.taskId, association)) {
|
|
157
|
-
try {
|
|
158
|
-
await store.persist();
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
// A lock contention (ELOCKED) or I/O fault must not fail the READ —
|
|
162
|
-
// but the in-memory field MUST be rolled back, or every later poll
|
|
163
|
-
// would see it set, skip the write, and the association would never
|
|
164
|
-
// reach disk (external code review, openai HIGH).
|
|
165
|
-
revertMissionContext(store, task.taskId, association);
|
|
166
|
-
// …and the reach-back must be rolled back WITH it. The marker was
|
|
167
|
-
// recorded before the resolve; leaving it would make every later poll
|
|
168
|
-
// read only the ordinary tail while the task is unidentified again —
|
|
169
|
-
// permanently unreachable for a footer beyond it, which is the very
|
|
170
|
-
// data loss the rollback above exists to prevent, re-entered through
|
|
171
|
-
// the read side (internal code review, MEDIUM).
|
|
172
|
-
wideWindows.delete(task.taskId);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
157
|
+
// THE one guarded association write (CONTRACT §5) — first association or
|
|
158
|
+
// a confirmed supersession, both idempotent. Split out to
|
|
159
|
+
// association-write.ts to stay under the file-size limit.
|
|
160
|
+
if (associateRunId) {
|
|
161
|
+
await persistMissionAssociation(store, task, associationAtResolve, associateRunId, associateSource, now, wideWindows);
|
|
175
162
|
}
|
|
176
163
|
return c.json({ status: "ok", context });
|
|
177
164
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/external/mission-context/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/external/mission-context/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface LeadQuestionRoundMirror {
|
|
2
|
+
round: number;
|
|
3
|
+
questionType: string;
|
|
4
|
+
question: string;
|
|
5
|
+
askedAt: string;
|
|
6
|
+
answer?: {
|
|
7
|
+
text: string;
|
|
8
|
+
answeredAt: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface LeadQuestionThreadMirror {
|
|
12
|
+
taskId: string;
|
|
13
|
+
dedupKey: string;
|
|
14
|
+
rounds: LeadQuestionRoundMirror[];
|
|
15
|
+
}
|
|
16
|
+
interface LeadQuestionThreadsFileMirror {
|
|
17
|
+
version: number;
|
|
18
|
+
threads: Record<string, LeadQuestionThreadMirror>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Structural-only parse. `null` on anything that isn't a well-formed,
|
|
22
|
+
* KNOWN-version threads file — every such case reads as "no threads" to
|
|
23
|
+
* every caller (see file header).
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseLeadQuestionThreadsFile(raw: string): LeadQuestionThreadsFileMirror | null;
|
|
26
|
+
export interface LeadQuestionThreadsRouteDeps {
|
|
27
|
+
leadsRoot: string;
|
|
28
|
+
/** Injectable for tests; production wires the real lstatSync. */
|
|
29
|
+
lstatSync?: (p: string) => {
|
|
30
|
+
isSymbolicLink(): boolean;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export type LeadQuestionThreadsReadResult = {
|
|
34
|
+
ok: true;
|
|
35
|
+
threads: Record<string, LeadQuestionThreadMirror>;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Pure core. Always succeeds with a (possibly empty) threads map — a
|
|
41
|
+
* missing/symlinked/unreadable/invalid/unknown-version file degrades to
|
|
42
|
+
* `{ ok: false }`, which callers treat identically to "no threads yet".
|
|
43
|
+
*/
|
|
44
|
+
export declare function readLeadQuestionThreadsCore(deps: LeadQuestionThreadsRouteDeps, leadId: string): LeadQuestionThreadsReadResult;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=lead-question-threads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-question-threads.d.ts","sourceRoot":"","sources":["../../../src/external/org/lead-question-threads.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,EAAE,CAAC;CACnC;AAED,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;CACnD;AAkCD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,6BAA6B,GAAG,IAAI,CA4B9F;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK;QAAE,cAAc,IAAI,OAAO,CAAA;KAAE,CAAC;CAC1D;AAED,MAAM,MAAM,6BAA6B,GACrC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;CAAE,GAC/D;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC;AAElB;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,4BAA4B,EAClC,MAAM,EAAE,MAAM,GACb,6BAA6B,CAiC/B"}
|