@svenroth-ai/shipwright 0.24.7-next.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/dist/assets/{EmbeddedTerminal-D2BLGWdW.js → EmbeddedTerminal-5QvKe3_a.js} +20 -20
- package/client/dist/assets/{abnfDiagram-VRR7QNED-C-W_2Jd4.js → abnfDiagram-VRR7QNED-CXi9HegQ.js} +1 -1
- package/client/dist/assets/{arc-CpqwESP5.js → arc-DLh4GiqR.js} +1 -1
- package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DZVZ895V.js → architectureDiagram-ZJ3FMSHR-DUypQ8dQ.js} +1 -1
- package/client/dist/assets/{blockDiagram-677ZJIJ3-CCCZiAA7.js → blockDiagram-677ZJIJ3-D2cVMKJG.js} +1 -1
- package/client/dist/assets/{c4Diagram-LMCZKHZV-Bg1beZAE.js → c4Diagram-LMCZKHZV-DtruBGJw.js} +1 -1
- package/client/dist/assets/channel-C_k-9jsa.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-CoaXSarh.js → chunk-2Q5K7J3B-CAfQkFw2.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-CeFXS-CM.js → chunk-32BRIVSS-CPWXoLnQ.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-QyJMVe0m.js → chunk-5VM5RSS4-xVc3oppQ.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-BIOtWVF8.js → chunk-EX3LRPZG-CUpl6fRR.js} +1 -1
- package/client/dist/assets/{chunk-JWPE2WC7-Dcq-lWyX.js → chunk-JWPE2WC7-NejUp56x.js} +1 -1
- package/client/dist/assets/{chunk-MOJQB5TN-C95323ja.js → chunk-MOJQB5TN-C9-2lLg0.js} +1 -1
- package/client/dist/assets/{chunk-RYQCIY6F-C0HPwpWy.js → chunk-RYQCIY6F-BAPtwABy.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-BPrTbZqA.js → chunk-V7JOEXUC-Dwzihw26.js} +1 -1
- package/client/dist/assets/{chunk-VR4S4FIN--BCnNoqt.js → chunk-VR4S4FIN-9-iArFJM.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-Dj8vtcXf.js → chunk-XXDRQBXY-DiWHOrqe.js} +1 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-CsEPq9Ac.js +1 -0
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsEPq9Ac.js +1 -0
- package/client/dist/assets/{cose-bilkent-JH36ORCC-y51otZKz.js → cose-bilkent-JH36ORCC-Cp04EOcH.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-BRfS3cHo.js → cynefin-VYW2F7L2-D--GN1v8.js} +1 -1
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-Dpg2RtfL.js → cynefinDiagram-TSTJHNR4-BGH0o_qp.js} +1 -1
- package/client/dist/assets/{dagre-VKFMJZFB-BdZtXgKZ.js → dagre-VKFMJZFB-DSKkIKlj.js} +1 -1
- package/client/dist/assets/{diagram-FQU43EPY-K-RCwWxW.js → diagram-FQU43EPY-Cs_C4lb-.js} +1 -1
- package/client/dist/assets/{diagram-G47NLZAW-CHNn7F2-.js → diagram-G47NLZAW-oDtAA8O_.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-B3zu6xib.js → diagram-NH7WQ7WH-BiFMjqSH.js} +1 -1
- package/client/dist/assets/{diagram-OA4YK3LP-Wp5ju7L7.js → diagram-OA4YK3LP-Ccs3thCj.js} +1 -1
- package/client/dist/assets/{diagram-WEI45ONY-C94GpsRk.js → diagram-WEI45ONY-CdZNqgO3.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-DXrTPOrP.js → ebnfDiagram-CCIWWBDH-CapTA0VL.js} +1 -1
- package/client/dist/assets/{erDiagram-Q63AITRT-CGejnW0f.js → erDiagram-Q63AITRT-BcRNEP8s.js} +1 -1
- package/client/dist/assets/{flowDiagram-23GEKE2U-CFJMM637.js → flowDiagram-23GEKE2U-CJ_zF7e_.js} +1 -1
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-DnaH94Su.js → ganttDiagram-NO4QXBWP-CnJdcg9A.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-DT-D0gbn.js → gitGraphDiagram-IHSO6WYX-YTUQ_ELk.js} +1 -1
- package/client/dist/assets/index-6nZ1bt0a.css +1 -0
- package/client/dist/assets/index-irQhGNpn.js +828 -0
- package/client/dist/assets/{infoDiagram-FWYZ7A6U-DW3Ps00w.js → infoDiagram-FWYZ7A6U-CLOP_ZWD.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-DjxjIT3n.js → ishikawaDiagram-FXEZZL3T-aFTIzr7o.js} +1 -1
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-DTQRI93Y.js → journeyDiagram-5HDEW3XC-CbPJB4xd.js} +1 -1
- package/client/dist/assets/{kanban-definition-HUTT4EX6-BeDvbiEs.js → kanban-definition-HUTT4EX6-BoyhytIS.js} +1 -1
- package/client/dist/assets/{linear-B4foxDlh.js → linear-1VXA-uBg.js} +1 -1
- package/client/dist/assets/{mermaid.core-c-L4qgSB.js → mermaid.core-D_lO2yK9.js} +4 -4
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-dh8v0J8T.js → mindmap-definition-LN4V7U3C-iFK7LXMx.js} +1 -1
- package/client/dist/assets/{pegDiagram-2B236MQR-D5vNrtFh.js → pegDiagram-2B236MQR-DNmcmfA-.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-CIjg_6lR.js → pieDiagram-ENE6RG2P-ekx83O5b.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-CF37qWQD.js → quadrantDiagram-ABIIQ3AL-DayyD1l8.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-x0Hn30Kj.js → railroadDiagram-RFXS5EU6-Bdgz7S6G.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-BE2QnVbN.js → requirementDiagram-TGXJPOKE-szP3Muld.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-CUv6cIlV.js → sankeyDiagram-HTMAVEWB-Ct3rzgUj.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-C3ACj5LS.js → sequenceDiagram-DBY2YBRQ-_69EfmOU.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-DTMIb5gX.js → sizeCapture-X5ZJPWSS-BSOU06J2.js} +1 -1
- package/client/dist/assets/{stateDiagram-2N3HPSRC-DI1Z8P74.js → stateDiagram-2N3HPSRC-HmOmFwQm.js} +1 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-BW8H33dv.js +1 -0
- package/client/dist/assets/{swimlanes-5IMT3BWC-CLSr9w29.js → swimlanes-5IMT3BWC-CVg_4oT7.js} +2 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BaRlxcPD.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-BTWmUhDh.js → timeline-definition-FHXFAJF6-CBBaDKXm.js} +1 -1
- package/client/dist/assets/{vennDiagram-L72KCM5P-Ce1dlLCM.js → vennDiagram-L72KCM5P-CBXiWPMc.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-EHGQE667-ClOE-aae.js → wardleyDiagram-EHGQE667-uhBCZoW0.js} +1 -1
- package/client/dist/assets/{xychartDiagram-FW5EYKEG-Fa2pqWKw.js → xychartDiagram-FW5EYKEG-xxE_wY5O.js} +1 -1
- package/client/dist/index.html +2 -2
- package/package.json +68 -68
- package/server/dist/core/grade-runner.d.ts +4 -4
- package/server/dist/core/grade-runner.d.ts.map +1 -1
- package/server/dist/core/grade-runner.js +51 -26
- package/server/dist/core/grade-runner.js.map +1 -1
- package/server/dist/core/grade-target.d.ts +8 -0
- package/server/dist/core/grade-target.d.ts.map +1 -1
- package/server/dist/core/grade-target.js +10 -0
- package/server/dist/core/grade-target.js.map +1 -1
- package/server/dist/core/triage-cli-runner.d.ts.map +1 -1
- package/server/dist/core/triage-cli-runner.js +29 -10
- package/server/dist/core/triage-cli-runner.js.map +1 -1
- package/server/dist/core/uv-runner.d.ts +23 -0
- package/server/dist/core/uv-runner.d.ts.map +1 -0
- package/server/dist/core/uv-runner.js +39 -0
- package/server/dist/core/uv-runner.js.map +1 -0
- package/server/dist/external/file/exists-routes.d.ts +7 -0
- package/server/dist/external/file/exists-routes.d.ts.map +1 -0
- package/server/dist/external/file/exists-routes.js +91 -0
- package/server/dist/external/file/exists-routes.js.map +1 -0
- package/server/dist/external/org/audit-log.d.ts +27 -0
- package/server/dist/external/org/audit-log.d.ts.map +1 -0
- package/server/dist/external/org/audit-log.js +92 -0
- package/server/dist/external/org/audit-log.js.map +1 -0
- package/server/dist/external/org/beat-register.d.ts +15 -22
- package/server/dist/external/org/beat-register.d.ts.map +1 -1
- package/server/dist/external/org/beat-register.js +37 -32
- package/server/dist/external/org/beat-register.js.map +1 -1
- package/server/dist/external/org/file-read.d.ts +16 -0
- package/server/dist/external/org/file-read.d.ts.map +1 -1
- package/server/dist/external/org/file-read.js +86 -46
- package/server/dist/external/org/file-read.js.map +1 -1
- package/server/dist/external/org/file-write-core.d.ts +18 -0
- package/server/dist/external/org/file-write-core.d.ts.map +1 -0
- package/server/dist/external/org/file-write-core.js +97 -0
- package/server/dist/external/org/file-write-core.js.map +1 -0
- package/server/dist/external/org/file-write.d.ts +25 -0
- package/server/dist/external/org/file-write.d.ts.map +1 -1
- package/server/dist/external/org/file-write.js +82 -132
- package/server/dist/external/org/file-write.js.map +1 -1
- package/server/dist/external/org/last-run.d.ts +25 -16
- package/server/dist/external/org/last-run.d.ts.map +1 -1
- package/server/dist/external/org/last-run.js +78 -64
- package/server/dist/external/org/last-run.js.map +1 -1
- package/server/dist/external/org/lead-doc-read.d.ts +21 -0
- package/server/dist/external/org/lead-doc-read.d.ts.map +1 -0
- package/server/dist/external/org/lead-doc-read.js +84 -0
- package/server/dist/external/org/lead-doc-read.js.map +1 -0
- package/server/dist/external/org/mount.d.ts +12 -0
- package/server/dist/external/org/mount.d.ts.map +1 -0
- package/server/dist/external/org/mount.js +34 -0
- package/server/dist/external/org/mount.js.map +1 -0
- package/server/dist/external/org/org-chart-lookup.d.ts +13 -0
- package/server/dist/external/org/org-chart-lookup.d.ts.map +1 -1
- package/server/dist/external/org/org-chart-lookup.js +40 -5
- package/server/dist/external/org/org-chart-lookup.js.map +1 -1
- package/server/dist/external/org/org-chart.d.ts +21 -12
- package/server/dist/external/org/org-chart.d.ts.map +1 -1
- package/server/dist/external/org/org-chart.js +50 -32
- package/server/dist/external/org/org-chart.js.map +1 -1
- package/server/dist/external/org/role-extract.d.ts +8 -0
- package/server/dist/external/org/role-extract.d.ts.map +1 -0
- package/server/dist/external/org/role-extract.js +72 -0
- package/server/dist/external/org/role-extract.js.map +1 -0
- package/server/dist/external/org/usage.d.ts +15 -11
- package/server/dist/external/org/usage.d.ts.map +1 -1
- package/server/dist/external/org/usage.js +64 -54
- package/server/dist/external/org/usage.js.map +1 -1
- package/server/dist/external/routes.d.ts +1 -1
- package/server/dist/external/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +10 -11
- package/server/dist/external/routes.js.map +1 -1
- package/server/dist/routes/grade.d.ts.map +1 -1
- package/server/dist/routes/grade.js +3 -2
- package/server/dist/routes/grade.js.map +1 -1
- package/server/dist/routes/org-leads-composite.d.ts +21 -0
- package/server/dist/routes/org-leads-composite.d.ts.map +1 -0
- package/server/dist/routes/org-leads-composite.js +95 -0
- package/server/dist/routes/org-leads-composite.js.map +1 -0
- package/server/dist/routes/org.d.ts +15 -0
- package/server/dist/routes/org.d.ts.map +1 -0
- package/server/dist/routes/org.js +198 -0
- package/server/dist/routes/org.js.map +1 -0
- package/server/dist/terminal/pty-manager.d.ts +9 -0
- package/server/dist/terminal/pty-manager.d.ts.map +1 -1
- package/server/dist/terminal/pty-manager.js +15 -0
- package/server/dist/terminal/pty-manager.js.map +1 -1
- package/server/dist/terminal/replay-snapshot.d.ts +10 -1
- package/server/dist/terminal/replay-snapshot.d.ts.map +1 -1
- package/server/dist/terminal/replay-snapshot.js +36 -1
- package/server/dist/terminal/replay-snapshot.js.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.d.ts +17 -1
- package/server/dist/terminal/ws-upgrade-handler.d.ts.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts +1 -0
- package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.fixtures.js +3 -2
- package/server/dist/terminal/ws-upgrade-handler.fixtures.js.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.js +45 -4
- package/server/dist/terminal/ws-upgrade-handler.js.map +1 -1
- package/server/dist/test/python-spawn-guard-util.d.ts +14 -0
- package/server/dist/test/python-spawn-guard-util.d.ts.map +1 -0
- package/server/dist/test/python-spawn-guard-util.js +124 -0
- package/server/dist/test/python-spawn-guard-util.js.map +1 -0
- package/server/dist/types/org.d.ts +115 -0
- package/server/dist/types/org.d.ts.map +1 -0
- package/server/dist/types/org.js +16 -0
- package/server/dist/types/org.js.map +1 -0
- package/server/package.json +1 -1
- package/client/dist/assets/MarkdownEditorModal-CP5yG9OU.js +0 -212
- package/client/dist/assets/channel-BNXbCvDS.js +0 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-w-wCtLx3.js +0 -1
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-w-wCtLx3.js +0 -1
- package/client/dist/assets/index-CU2QJgvx.js +0 -609
- package/client/dist/assets/index-ftvVcUT8.css +0 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-DvwiHlJv.js +0 -1
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-JTQZTlZ3.js +0 -8
|
@@ -41,70 +41,80 @@ function isValidUsagePayload(v) {
|
|
|
41
41
|
typeof u.asOf === "string" &&
|
|
42
42
|
u.asOf.length > 0);
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
/** Pure core — shared by the secret-gated route and the plain-surface proxy. */
|
|
45
|
+
export function usageCore(deps, leadId) {
|
|
45
46
|
const { leadsRoot } = deps;
|
|
46
47
|
const lstat = deps.lstatSync ?? ((p) => lstatSync(p));
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (code === "ENOENT") {
|
|
63
|
-
const body = { leadId, measured: false };
|
|
64
|
-
return c.json(body, 200);
|
|
65
|
-
}
|
|
66
|
-
return c.json({ error: "usage_read_failed", detail: String(err).slice(0, 200) }, 500);
|
|
67
|
-
}
|
|
68
|
-
if (lst.isSymbolicLink()) {
|
|
69
|
-
return c.json({ error: "symlink_forbidden", leadId }, 403);
|
|
70
|
-
}
|
|
71
|
-
// Parent-directory symlink escape (e.g. the lead directory itself is a
|
|
72
|
-
// junction pointing outside leadsRoot) — checked BEFORE reading.
|
|
73
|
-
const containment = realPathGuard(leadsRoot, absolute);
|
|
74
|
-
if (!containment.ok) {
|
|
75
|
-
return c.json({ error: "path_traversal", detail: containment.reason }, 400);
|
|
76
|
-
}
|
|
77
|
-
let raw;
|
|
78
|
-
try {
|
|
79
|
-
raw = readFileSync(absolute, "utf8");
|
|
80
|
-
}
|
|
81
|
-
catch (err) {
|
|
82
|
-
const code = err?.code;
|
|
83
|
-
if (code === "ENOENT") {
|
|
84
|
-
const body = { leadId, measured: false };
|
|
85
|
-
return c.json(body, 200);
|
|
86
|
-
}
|
|
87
|
-
return c.json({ error: "usage_read_failed", detail: String(err).slice(0, 200) }, 500);
|
|
48
|
+
if (!LEAD_ID_RE.test(leadId)) {
|
|
49
|
+
return { status: 400, body: { error: "invalid_lead_id", leadId } };
|
|
50
|
+
}
|
|
51
|
+
const absolute = path.join(leadsRoot, leadId, "usage.json");
|
|
52
|
+
// Existence + symlink check BEFORE any read — a missing lead directory
|
|
53
|
+
// (steady state pre-producer) is `measured: false`, not an error; a
|
|
54
|
+
// symlinked final component is rejected before it is ever opened.
|
|
55
|
+
let lst;
|
|
56
|
+
try {
|
|
57
|
+
lst = lstat(absolute);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const code = err?.code;
|
|
61
|
+
if (code === "ENOENT") {
|
|
62
|
+
return { status: 200, body: { leadId, measured: false } };
|
|
88
63
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
64
|
+
return {
|
|
65
|
+
status: 500,
|
|
66
|
+
body: { error: "usage_read_failed", detail: String(err).slice(0, 200) },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (lst.isSymbolicLink()) {
|
|
70
|
+
return { status: 403, body: { error: "symlink_forbidden", leadId } };
|
|
71
|
+
}
|
|
72
|
+
// Parent-directory symlink escape (e.g. the lead directory itself is a
|
|
73
|
+
// junction pointing outside leadsRoot) — checked BEFORE reading.
|
|
74
|
+
const containment = realPathGuard(leadsRoot, absolute);
|
|
75
|
+
if (!containment.ok) {
|
|
76
|
+
return { status: 400, body: { error: "path_traversal", detail: containment.reason } };
|
|
77
|
+
}
|
|
78
|
+
let raw;
|
|
79
|
+
try {
|
|
80
|
+
raw = readFileSync(absolute, "utf8");
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
const code = err?.code;
|
|
84
|
+
if (code === "ENOENT") {
|
|
85
|
+
return { status: 200, body: { leadId, measured: false } };
|
|
98
86
|
}
|
|
99
|
-
|
|
87
|
+
return {
|
|
88
|
+
status: 500,
|
|
89
|
+
body: { error: "usage_read_failed", detail: String(err).slice(0, 200) },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(raw);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return { status: 502, body: { error: "usage_invalid", leadId } };
|
|
98
|
+
}
|
|
99
|
+
if (!isValidUsagePayload(parsed)) {
|
|
100
|
+
return { status: 502, body: { error: "usage_invalid", leadId } };
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
status: 200,
|
|
104
|
+
body: {
|
|
100
105
|
leadId,
|
|
101
106
|
measured: true,
|
|
102
107
|
costUsd: parsed.costUsd,
|
|
103
108
|
runCount: parsed.runCount,
|
|
104
109
|
windowDays: parsed.windowDays,
|
|
105
110
|
asOf: parsed.asOf,
|
|
106
|
-
}
|
|
107
|
-
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function registerUsageRoute(app, deps) {
|
|
115
|
+
app.get("/api/external/org/leads/:leadId/usage", async (c) => {
|
|
116
|
+
const result = usageCore(deps, c.req.param("leadId"));
|
|
117
|
+
return c.json(result.body, result.status);
|
|
108
118
|
});
|
|
109
119
|
}
|
|
110
120
|
//# sourceMappingURL=usage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/external/org/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,+BAA+B,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/external/org/usage.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { type RunConfigReadResult } from "../core/run-config-reader.js";
|
|
|
4
4
|
import type { ComplianceReadResult } from "../core/compliance-reader.js";
|
|
5
5
|
import { SessionWatcher } from "../core/session-watcher.js";
|
|
6
6
|
import { SdkSessionsStore } from "../core/sdk-sessions-store.js";
|
|
7
|
-
import {
|
|
7
|
+
import type { OrgRouterDeps } from "./org/routes.js";
|
|
8
8
|
export { FILE_MAX_BYTES, MIME_BY_EXTENSION, sanitizeContentDispositionFilename, } from "./file/_helpers.js";
|
|
9
9
|
export { clearInboxDeriveCache } from "./inbox/_cache.js";
|
|
10
10
|
export type { ExternalRouteProjectView } from "./_shared/helpers.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/external/routes.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,KAAK,cAAc,EACpB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAmBjE,OAAO,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/external/routes.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,KAAK,cAAc,EACpB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAmBjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AASrD,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,kCAAkC,GACnC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,wBAAwB,GAAG,SAAS,CAAC;IACtE;;;;OAIG;IACH,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACvC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,cAAc,GAAG,IAAI,CAAC;IAC7D;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACtE;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACxE;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D;;;;;;;;;;OAUG;IACH,UAAU,EAAE;QACV,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7B;;;;WAIG;QACH,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5C;;;;;;WAMG;QACH,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;KAClD,CAAC;IACF;;mEAE+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C,oBAAoB,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;CAC3D,8EAsJA"}
|
|
@@ -48,7 +48,7 @@ import { createTasksRouter } from "./tasks/routes.js";
|
|
|
48
48
|
import { createLaunchRouter } from "./launch/routes.js";
|
|
49
49
|
import { createPrStatusRouter } from "./pr-status/routes.js";
|
|
50
50
|
import { createDesignReviewRouter } from "./design-review/routes.js";
|
|
51
|
-
import {
|
|
51
|
+
import { mountOrgRouters } from "./org/mount.js";
|
|
52
52
|
// Back-compat re-exports — 14+ sibling test files + downstream consumers
|
|
53
53
|
// import these from `./routes.js` directly. Sources of truth post-C2:
|
|
54
54
|
// - ./file/_helpers.ts (FILE_MAX_BYTES, MIME_BY_EXTENSION,
|
|
@@ -147,16 +147,15 @@ export function createExternalRoutes(args) {
|
|
|
147
147
|
// shell:false (iterate-2026-05-30-pr-card-status). Stateless; uses the
|
|
148
148
|
// default gh runner + in-memory TTL cache from core/pr-status.ts.
|
|
149
149
|
app.route("/", createPrStatusRouter());
|
|
150
|
-
// FR-04.38 —
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
150
|
+
// FR-04.38 — secret-gated `/api/external/org/*` + plain `/api/org/*` proxy
|
|
151
|
+
// (see org/mount.ts for why both are composed from one call site).
|
|
152
|
+
mountOrgRouters(app, {
|
|
153
|
+
honoHost,
|
|
154
|
+
leadsRoot,
|
|
155
|
+
leadsRouteSecret,
|
|
156
|
+
orgLstatSync,
|
|
157
|
+
orgWithDecisionsLock,
|
|
158
|
+
});
|
|
160
159
|
return app;
|
|
161
160
|
}
|
|
162
161
|
//# sourceMappingURL=routes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/external/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EACL,aAAa,IAAI,oBAAoB,GAEtC,MAAM,8BAA8B,CAAC;AAKtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/external/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grade.d.ts","sourceRoot":"","sources":["../../src/routes/grade.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grade.d.ts","sourceRoot":"","sources":["../../src/routes/grade.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAMtE,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE;IACvC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/F,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,8EAqBA"}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* POST /api/wizard/grade — the read-only Grade door route (A09b, FR-01.53).
|
|
3
3
|
*
|
|
4
4
|
* Runs `shipwright-grade`'s `grade.py <target> --format json` via
|
|
5
|
-
* `core/grade-runner.ts` (shell:false,
|
|
6
|
-
* and returns the plugin's real `ReportModel` — or an
|
|
5
|
+
* `core/grade-runner.ts` (shell:false, `uv run --project <plugin-root>`,
|
|
6
|
+
* validated target) and returns the plugin's real `ReportModel` — or an
|
|
7
|
+
* HONEST degraded state.
|
|
7
8
|
* Grade registers NO project and writes NOTHING (a bare grade is read-only);
|
|
8
9
|
* this is a pure observer route, so it is POST only for a request body, never a
|
|
9
10
|
* mutation.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grade.js","sourceRoot":"","sources":["../../src/routes/grade.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"grade.js","sourceRoot":"","sources":["../../src/routes/grade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,QAAQ,EAAqB,MAAM,yBAAyB,CAAC;AAEtE,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAKjC;IACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,IAAI,EAAE,QAAQ,IAAI,QAAQ,CAAC;IAEvC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACxC,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,gCAAgC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3F,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QACxD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7D,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACtE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LeadRosterEntry, OrgChartLeadView } from "../types/org.js";
|
|
2
|
+
import { type OrgFileReadDeps } from "../external/org/file-read.js";
|
|
3
|
+
import type { LeadOrgInfoResult } from "../external/org/org-chart-lookup.js";
|
|
4
|
+
export interface LeadRosterBuildDeps {
|
|
5
|
+
leadsRoot: string;
|
|
6
|
+
/** Shared shape across usage/last-run/beat-register — all three route
|
|
7
|
+
* deps declare the same `(p) => { isSymbolicLink() }` test seam. */
|
|
8
|
+
lstatSync?: (p: string) => {
|
|
9
|
+
isSymbolicLink(): boolean;
|
|
10
|
+
};
|
|
11
|
+
openSync?: OrgFileReadDeps["openSync"];
|
|
12
|
+
now?: () => Date;
|
|
13
|
+
}
|
|
14
|
+
export declare function buildLeadRosterEntry(deps: LeadRosterBuildDeps, leadId: string, lead: OrgChartLeadView,
|
|
15
|
+
/**
|
|
16
|
+
* `org-chart.json` cron/reports_to lookup for THIS lead, resolved ONCE
|
|
17
|
+
* for the whole roster by the caller (`readAllLeadOrgInfo`) — see the
|
|
18
|
+
* iterate spec's "parses the chart once" composite-read requirement.
|
|
19
|
+
*/
|
|
20
|
+
orgInfo: LeadOrgInfoResult): LeadRosterEntry;
|
|
21
|
+
//# sourceMappingURL=org-leads-composite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-leads-composite.d.ts","sourceRoot":"","sources":["../../src/routes/org-leads-composite.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAIV,eAAe,EACf,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAI7E,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB;yEACqE;IACrE,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK;QAAE,cAAc,IAAI,OAAO,CAAA;KAAE,CAAC;IACzD,QAAQ,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACvC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AA8DD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,mBAAmB,EACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB;AACtB;;;;GAIG;AACH,OAAO,EAAE,iBAAiB,GACzB,eAAe,CAYjB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* routes/org-leads-composite.ts — builds the `GET /api/org/leads` response
|
|
3
|
+
* body: one composite roster read over the whole `org-chart.json`, not an
|
|
4
|
+
* N+1 fan-out (iterate spec Design Notes, "One composite endpoint").
|
|
5
|
+
*
|
|
6
|
+
* Composes four already-extracted pure cores per lead (usage, last-run,
|
|
7
|
+
* beat-register health, charter.md read) plus the new `role-extract.ts`
|
|
8
|
+
* text rule. A per-figure read failure degrades that figure to its own
|
|
9
|
+
* `measured: false` / `not-measured` shape — it never fails the whole
|
|
10
|
+
* roster response, and it never fabricates a value.
|
|
11
|
+
*/
|
|
12
|
+
import { usageCore } from "../external/org/usage.js";
|
|
13
|
+
import { lastRunCore } from "../external/org/last-run.js";
|
|
14
|
+
import { beatRegisterHealthCore } from "../external/org/beat-register.js";
|
|
15
|
+
import { orgFileReadCore } from "../external/org/file-read.js";
|
|
16
|
+
import { cronIntervalMs } from "../external/org/cron.js";
|
|
17
|
+
import { extractRoleSentence } from "../external/org/role-extract.js";
|
|
18
|
+
function formatCadence(ms) {
|
|
19
|
+
const minutes = ms / 60_000;
|
|
20
|
+
if (minutes < 60) {
|
|
21
|
+
const n = Math.max(1, Math.round(minutes));
|
|
22
|
+
return `every ${n} min`;
|
|
23
|
+
}
|
|
24
|
+
const hours = minutes / 60;
|
|
25
|
+
if (hours < 24) {
|
|
26
|
+
const n = Math.max(1, Math.round(hours));
|
|
27
|
+
return `every ${n} hr${n === 1 ? "" : "s"}`;
|
|
28
|
+
}
|
|
29
|
+
const days = hours / 24;
|
|
30
|
+
const n = Math.max(1, Math.round(days));
|
|
31
|
+
return `every ${n} day${n === 1 ? "" : "s"}`;
|
|
32
|
+
}
|
|
33
|
+
function buildCadence(orgInfo, now) {
|
|
34
|
+
if (!orgInfo.ok)
|
|
35
|
+
return { measured: false };
|
|
36
|
+
const interval = cronIntervalMs(orgInfo.cron, now);
|
|
37
|
+
if (!interval.ok)
|
|
38
|
+
return { measured: false };
|
|
39
|
+
return { measured: true, text: formatCadence(interval.ms), cron: orgInfo.cron };
|
|
40
|
+
}
|
|
41
|
+
function buildNow(deps, leadId, orgInfo) {
|
|
42
|
+
const health = beatRegisterHealthCore({ leadsRoot: deps.leadsRoot, lstatSync: deps.lstatSync }, leadId);
|
|
43
|
+
if (health.status !== 200)
|
|
44
|
+
return { state: "not-measured" };
|
|
45
|
+
if (health.body.status === "fault") {
|
|
46
|
+
return { state: "needs-attention", reason: "duplicate-session" };
|
|
47
|
+
}
|
|
48
|
+
if (health.body.status === "open") {
|
|
49
|
+
return { state: "running" };
|
|
50
|
+
}
|
|
51
|
+
// status === "clear" — Resting; text sourced from last-run. `orgInfo` was
|
|
52
|
+
// already resolved once for the whole composite request (see
|
|
53
|
+
// `buildLeadRosterEntry`) — passed through so `lastRunCore` doesn't
|
|
54
|
+
// re-parse `org-chart.json` per lead.
|
|
55
|
+
const lastRun = lastRunCore({ leadsRoot: deps.leadsRoot, lstatSync: deps.lstatSync, orgInfo }, leadId);
|
|
56
|
+
if (lastRun.status !== 200)
|
|
57
|
+
return { state: "not-measured" };
|
|
58
|
+
if (lastRun.body.measured === false) {
|
|
59
|
+
return { state: "resting", lastRun: { measured: false } };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
state: "resting",
|
|
63
|
+
lastRun: { measured: true, lastRunAt: lastRun.body.lastRunAt },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function buildRole(deps, leadId) {
|
|
67
|
+
const result = orgFileReadCore({ leadsRoot: deps.leadsRoot, openSync: deps.openSync }, `${leadId}/charter.md`);
|
|
68
|
+
if (result.status !== 200 || result.kind !== "file")
|
|
69
|
+
return { measured: false };
|
|
70
|
+
return extractRoleSentence(result.body.toString("utf8"));
|
|
71
|
+
}
|
|
72
|
+
function buildUsage(deps, leadId) {
|
|
73
|
+
const result = usageCore({ leadsRoot: deps.leadsRoot, lstatSync: deps.lstatSync }, leadId);
|
|
74
|
+
return result.status === 200 ? result.body : { leadId, measured: false };
|
|
75
|
+
}
|
|
76
|
+
export function buildLeadRosterEntry(deps, leadId, lead,
|
|
77
|
+
/**
|
|
78
|
+
* `org-chart.json` cron/reports_to lookup for THIS lead, resolved ONCE
|
|
79
|
+
* for the whole roster by the caller (`readAllLeadOrgInfo`) — see the
|
|
80
|
+
* iterate spec's "parses the chart once" composite-read requirement.
|
|
81
|
+
*/
|
|
82
|
+
orgInfo) {
|
|
83
|
+
const now = deps.now ?? (() => new Date());
|
|
84
|
+
return {
|
|
85
|
+
leadId,
|
|
86
|
+
domain: lead.domain,
|
|
87
|
+
name: lead.name,
|
|
88
|
+
reportsTo: lead.reports_to,
|
|
89
|
+
role: buildRole(deps, leadId),
|
|
90
|
+
now: buildNow(deps, leadId, orgInfo),
|
|
91
|
+
cadence: buildCadence(orgInfo, now()),
|
|
92
|
+
usage: buildUsage(deps, leadId),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=org-leads-composite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-leads-composite.js","sourceRoot":"","sources":["../../src/routes/org-leads-composite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { type OrgFileReadDeps } from "../external/org/file-read.js";
|
|
3
|
+
import { type OrgFileWriteDeps } from "../external/org/file-write.js";
|
|
4
|
+
export interface OrgApiRouterDeps {
|
|
5
|
+
leadsRoot: string;
|
|
6
|
+
/** The application's resolved bind host — passed through, never re-derived. */
|
|
7
|
+
honoHost: string;
|
|
8
|
+
/** Widest shared shape — file-write's core additionally needs `isFile()`. */
|
|
9
|
+
lstatSync?: OrgFileWriteDeps["lstatSync"];
|
|
10
|
+
openSync?: OrgFileReadDeps["openSync"];
|
|
11
|
+
withDecisionsLock?: OrgFileWriteDeps["withDecisionsLock"];
|
|
12
|
+
now?: () => Date;
|
|
13
|
+
}
|
|
14
|
+
export declare function createOrgApiRouter(deps: OrgApiRouterDeps): Hono;
|
|
15
|
+
//# sourceMappingURL=org.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org.d.ts","sourceRoot":"","sources":["../../src/routes/org.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAK1C,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAMxF,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACvC,iBAAiB,CAAC,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;IAC1D,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAgL/D"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* routes/org.ts — the plain-surface `/api/org/*` proxy (iterate spec Design
|
|
3
|
+
* Notes, "Server-side proxy route"). Browser-facing mirror of
|
|
4
|
+
* `external/org/routes.ts`'s secret-gated family, sharing its extracted
|
|
5
|
+
* pure cores directly (no HTTP, no `registerXRoute` call — see "No
|
|
6
|
+
* route-mount collision").
|
|
7
|
+
*
|
|
8
|
+
* Only the shared-secret gate is dropped (the browser is a first-party
|
|
9
|
+
* caller of its own server); the host allowlist (`isAllowedOrgRouteHost`,
|
|
10
|
+
* FR-04.38 Auflage 1, a PO-decided control independent of the secret) is
|
|
11
|
+
* retained here as its own middleware, unchanged.
|
|
12
|
+
*
|
|
13
|
+
* Endpoints:
|
|
14
|
+
* GET /api/org/org-chart — wraps `orgChartCore` verbatim.
|
|
15
|
+
* GET /api/org/leads — composite roster (see
|
|
16
|
+
* `org-leads-composite.ts`).
|
|
17
|
+
* GET /api/org/file?path=<relpath> — read-only, the SAME six-kind
|
|
18
|
+
* allowlist the gated route's GET uses (`resolveOrgAllowlistedTarget`);
|
|
19
|
+
* unrestricted by kind, unlike the PUT below — a read carries none of
|
|
20
|
+
* the unlocked-write risk AC-10 guards against. Backs the
|
|
21
|
+
* shared-documents block (org-chart.json's sibling docs: conventions.md,
|
|
22
|
+
* principal.md, decision_log.md) and the charter.md fresh-load-before-
|
|
23
|
+
* edit round trip (`orgMarkdownFileApi.ts`).
|
|
24
|
+
* PUT /api/org/leads/:leadId/charter — the ONLY browser write this
|
|
25
|
+
* iterate; refuses (403) anything that would resolve to a non-`charter`
|
|
26
|
+
* kind (AC-10) — in particular `decision_log.md` /
|
|
27
|
+
* `decisions-proposed.md`, which stay lock-guarded on the existing
|
|
28
|
+
* gated route only.
|
|
29
|
+
*/
|
|
30
|
+
import { Hono } from "hono";
|
|
31
|
+
import { isAllowedOrgRouteHost, resolveOrgAllowlistedTarget, LEAD_ID_RE } from "../external/org/_helpers.js";
|
|
32
|
+
import { orgChartCore } from "../external/org/org-chart.js";
|
|
33
|
+
import { readAllLeadOrgInfo } from "../external/org/org-chart-lookup.js";
|
|
34
|
+
import { orgFileReadCore } from "../external/org/file-read.js";
|
|
35
|
+
import { orgFileWriteCore } from "../external/org/file-write.js";
|
|
36
|
+
import { buildLeadRosterEntry } from "./org-leads-composite.js";
|
|
37
|
+
import { leadLearningsReadCore } from "../external/org/lead-doc-read.js";
|
|
38
|
+
import { auditLogCore } from "../external/org/audit-log.js";
|
|
39
|
+
export function createOrgApiRouter(deps) {
|
|
40
|
+
const app = new Hono();
|
|
41
|
+
const { leadsRoot, honoHost } = deps;
|
|
42
|
+
app.use("/api/org/*", async (c, next) => {
|
|
43
|
+
if (!isAllowedOrgRouteHost(honoHost)) {
|
|
44
|
+
return c.json({ error: "host_not_allowed" }, 403);
|
|
45
|
+
}
|
|
46
|
+
await next();
|
|
47
|
+
});
|
|
48
|
+
app.get("/api/org/org-chart", async (c) => {
|
|
49
|
+
const result = orgChartCore({ leadsRoot, lstatSync: deps.lstatSync });
|
|
50
|
+
return c.json(result.body, result.status);
|
|
51
|
+
});
|
|
52
|
+
app.get("/api/org/leads", async (c) => {
|
|
53
|
+
const chart = orgChartCore({ leadsRoot, lstatSync: deps.lstatSync });
|
|
54
|
+
if (chart.status !== 200) {
|
|
55
|
+
return c.json(chart.body, chart.status);
|
|
56
|
+
}
|
|
57
|
+
const buildDeps = {
|
|
58
|
+
leadsRoot,
|
|
59
|
+
lstatSync: deps.lstatSync,
|
|
60
|
+
openSync: deps.openSync,
|
|
61
|
+
now: deps.now,
|
|
62
|
+
};
|
|
63
|
+
// Code-review fix (doc accuracy): this handler still parses
|
|
64
|
+
// org-chart.json TWICE per request — once above via `orgChartCore` for
|
|
65
|
+
// the roster body (full-validates every lead, all-or-nothing), once
|
|
66
|
+
// here via `readAllLeadOrgInfo` for the per-lead cron/reports_to lookup
|
|
67
|
+
// (tolerant of a broken lead elsewhere in the file — see
|
|
68
|
+
// org-chart-lookup.ts's header for why that can't be the same parse).
|
|
69
|
+
// What the N+1 fix actually buys (iterate spec Design Notes, "One
|
|
70
|
+
// composite endpoint, not N+1") is AT MOST TWO parses per request,
|
|
71
|
+
// never one per lead — `forLead` below is an in-memory lookup over the
|
|
72
|
+
// one parse done here, not a re-read.
|
|
73
|
+
const orgInfoResult = readAllLeadOrgInfo(leadsRoot);
|
|
74
|
+
const orgInfoFor = (leadId) => orgInfoResult.ok ? orgInfoResult.forLead(leadId) : orgInfoResult;
|
|
75
|
+
const leads = Object.entries(chart.body.leads).map(([leadId, lead]) => buildLeadRosterEntry(buildDeps, leadId, lead, orgInfoFor(leadId)));
|
|
76
|
+
const body = { leads };
|
|
77
|
+
return c.json(body, 200);
|
|
78
|
+
});
|
|
79
|
+
app.get("/api/org/file", async (c) => {
|
|
80
|
+
const result = orgFileReadCore({ leadsRoot, openSync: deps.openSync }, c.req.query("path"));
|
|
81
|
+
if (result.kind === "json") {
|
|
82
|
+
return c.json(result.body, result.status);
|
|
83
|
+
}
|
|
84
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
85
|
+
c.header(key, value);
|
|
86
|
+
}
|
|
87
|
+
return c.body(new Uint8Array(result.body), result.status);
|
|
88
|
+
});
|
|
89
|
+
// Code-review fix (LOW, consistency): the charter PUT route below refuses
|
|
90
|
+
// an unregistered leadId (the HIGH external-review fix); these two GET
|
|
91
|
+
// routes previously only shape-checked the leadId and never checked chart
|
|
92
|
+
// membership, so a stale/decommissioned lead directory left on disk would
|
|
93
|
+
// still serve through the browser-facing proxy. Same posture, both verbs.
|
|
94
|
+
//
|
|
95
|
+
// Doubt-review fix (HIGH, security): a shape-invalid RAW leadId must be
|
|
96
|
+
// REJECTED here, never deferred to a downstream core's own check. That
|
|
97
|
+
// deferral was safe for the two GET routes (their cores re-validate the
|
|
98
|
+
// SAME raw string), but not for the PUT charter route below:
|
|
99
|
+
// `resolveOrgAllowlistedTarget` derives its OWN, more lenient "leadId" by
|
|
100
|
+
// slicing the path.resolve()-normalized absolute path, and Hono decodes a
|
|
101
|
+
// `%2f` in the route param (but not in path segmentation) — so a raw
|
|
102
|
+
// leadId of `"ghost-lead/"` (from the URL `ghost-lead%2f`) normalizes to
|
|
103
|
+
// the clean, registered `"acme-lead"`-shaped target while `LEAD_ID_RE`
|
|
104
|
+
// (correctly) rejects the RAW string with its trailing slash. Deferring
|
|
105
|
+
// on that rejection let the write proceed with NO chart-membership check
|
|
106
|
+
// at all. `LEAD_ID_RE` matches only `[a-z0-9][a-z0-9-]*` — no `/` or `.`
|
|
107
|
+
// — so a raw string that passes it can never diverge from its own
|
|
108
|
+
// path-normalized form; rejecting here closes the whole class, not just
|
|
109
|
+
// the one PoC. Same 400 `invalid_lead_id` shape the GET routes' cores
|
|
110
|
+
// already used, so their existing 400 contract is unchanged.
|
|
111
|
+
function requireChartLead(c, leadId) {
|
|
112
|
+
if (!LEAD_ID_RE.test(leadId)) {
|
|
113
|
+
return { ok: false, response: c.json({ error: "invalid_lead_id" }, 400) };
|
|
114
|
+
}
|
|
115
|
+
const chart = orgChartCore({ leadsRoot, lstatSync: deps.lstatSync });
|
|
116
|
+
if (chart.status !== 200) {
|
|
117
|
+
return { ok: false, response: c.json(chart.body, chart.status) };
|
|
118
|
+
}
|
|
119
|
+
if (!Object.hasOwn(chart.body.leads, leadId)) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
response: c.json({ error: "unknown_lead", detail: "leadId is not a chart entry" }, 403),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return { ok: true };
|
|
126
|
+
}
|
|
127
|
+
app.get("/api/org/leads/:leadId/learnings", async (c) => {
|
|
128
|
+
const leadId = c.req.param("leadId");
|
|
129
|
+
const gate = requireChartLead(c, leadId);
|
|
130
|
+
if (!gate.ok)
|
|
131
|
+
return gate.response;
|
|
132
|
+
const leadDeps = { leadsRoot, openSync: deps.openSync };
|
|
133
|
+
const result = leadLearningsReadCore(leadDeps, leadId);
|
|
134
|
+
if (result.kind === "json") {
|
|
135
|
+
return c.json(result.body, result.status);
|
|
136
|
+
}
|
|
137
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
138
|
+
c.header(key, value);
|
|
139
|
+
}
|
|
140
|
+
return c.body(new Uint8Array(result.body), result.status);
|
|
141
|
+
});
|
|
142
|
+
app.get("/api/org/leads/:leadId/audit", async (c) => {
|
|
143
|
+
const leadId = c.req.param("leadId");
|
|
144
|
+
const gate = requireChartLead(c, leadId);
|
|
145
|
+
if (!gate.ok)
|
|
146
|
+
return gate.response;
|
|
147
|
+
const auditDeps = { leadsRoot, openSync: deps.openSync };
|
|
148
|
+
const beforeRaw = c.req.query("before");
|
|
149
|
+
const limitRaw = c.req.query("limit");
|
|
150
|
+
const result = auditLogCore(auditDeps, {
|
|
151
|
+
leadId,
|
|
152
|
+
before: beforeRaw !== undefined ? Number(beforeRaw) : undefined,
|
|
153
|
+
limit: limitRaw !== undefined ? Number(limitRaw) : undefined,
|
|
154
|
+
});
|
|
155
|
+
return c.json(result.body, result.status);
|
|
156
|
+
});
|
|
157
|
+
app.put("/api/org/leads/:leadId/charter", async (c) => {
|
|
158
|
+
const leadId = c.req.param("leadId");
|
|
159
|
+
const relpath = `${leadId}/charter.md`;
|
|
160
|
+
// AC-10: only a `charter` kind may pass through this browser-facing
|
|
161
|
+
// proxy — every other allowlisted kind (decision_log,
|
|
162
|
+
// decisions_proposed, conventions, principal, agents) is refused here,
|
|
163
|
+
// before ever reaching the write core.
|
|
164
|
+
const target = resolveOrgAllowlistedTarget(leadsRoot, relpath);
|
|
165
|
+
if (!target.ok) {
|
|
166
|
+
const status = target.reason === "not_allowlisted" ? 403 : 400;
|
|
167
|
+
const err = target.reason === "traversal" ? "path_traversal" : target.reason;
|
|
168
|
+
return c.json({ error: err, detail: target.reason }, status);
|
|
169
|
+
}
|
|
170
|
+
if (target.kind !== "charter") {
|
|
171
|
+
return c.json({ error: "not_allowlisted", detail: "only charter.md is writable here" }, 403);
|
|
172
|
+
}
|
|
173
|
+
// External-review fix (HIGH, security): the checks above only prove
|
|
174
|
+
// `leadId` is kebab-case-shaped and that its `charter.md` sits inside
|
|
175
|
+
// `leadsRoot` — they never confirm `leadId` is an actual chart entry.
|
|
176
|
+
// Any syntactically valid, never-registered lead id could otherwise
|
|
177
|
+
// have a charter.md written (and later read back through the same
|
|
178
|
+
// allowlist) with no corresponding org-chart.json entry. Require the
|
|
179
|
+
// lead to be a real roster member before the write proceeds.
|
|
180
|
+
const gate = requireChartLead(c, leadId);
|
|
181
|
+
if (!gate.ok)
|
|
182
|
+
return gate.response;
|
|
183
|
+
const writeDeps = {
|
|
184
|
+
leadsRoot,
|
|
185
|
+
lstatSync: deps.lstatSync,
|
|
186
|
+
withDecisionsLock: deps.withDecisionsLock,
|
|
187
|
+
};
|
|
188
|
+
const result = await orgFileWriteCore(writeDeps, {
|
|
189
|
+
relpath,
|
|
190
|
+
contentLengthHeader: c.req.header("content-length"),
|
|
191
|
+
body: await c.req.text(),
|
|
192
|
+
ifMatch: c.req.header("if-match"),
|
|
193
|
+
});
|
|
194
|
+
return c.json(result.body, result.status);
|
|
195
|
+
});
|
|
196
|
+
return app;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=org.js.map
|