@svenroth-ai/shipwright 0.24.7-next.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/dist/assets/{EmbeddedTerminal-D2BLGWdW.js → EmbeddedTerminal-D3wpPNZP.js} +20 -20
- package/client/dist/assets/{abnfDiagram-VRR7QNED-C-W_2Jd4.js → abnfDiagram-VRR7QNED-BkLIltB3.js} +1 -1
- package/client/dist/assets/{arc-CpqwESP5.js → arc-Sw-Gh0nI.js} +1 -1
- package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DZVZ895V.js → architectureDiagram-ZJ3FMSHR-rdxUi9Ks.js} +1 -1
- package/client/dist/assets/{blockDiagram-677ZJIJ3-CCCZiAA7.js → blockDiagram-677ZJIJ3-Ch_9dj8a.js} +1 -1
- package/client/dist/assets/{c4Diagram-LMCZKHZV-Bg1beZAE.js → c4Diagram-LMCZKHZV-CkFlO65x.js} +1 -1
- package/client/dist/assets/channel-BYPbLjRl.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-CoaXSarh.js → chunk-2Q5K7J3B-CypX83xu.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-CeFXS-CM.js → chunk-32BRIVSS-DxVLYGdl.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-QyJMVe0m.js → chunk-5VM5RSS4-Cxk1evhx.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-BIOtWVF8.js → chunk-EX3LRPZG-n9q5S4yJ.js} +1 -1
- package/client/dist/assets/{chunk-JWPE2WC7-Dcq-lWyX.js → chunk-JWPE2WC7-jeL4xvir.js} +1 -1
- package/client/dist/assets/{chunk-MOJQB5TN-C95323ja.js → chunk-MOJQB5TN-DDSHN0cj.js} +1 -1
- package/client/dist/assets/{chunk-RYQCIY6F-C0HPwpWy.js → chunk-RYQCIY6F-C0bo383g.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-BPrTbZqA.js → chunk-V7JOEXUC-C0jDXXAU.js} +1 -1
- package/client/dist/assets/{chunk-VR4S4FIN--BCnNoqt.js → chunk-VR4S4FIN-h-Rr4Pn2.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-Dj8vtcXf.js → chunk-XXDRQBXY-BexSo0-s.js} +1 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-CsFIeTju.js +1 -0
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsFIeTju.js +1 -0
- package/client/dist/assets/{cose-bilkent-JH36ORCC-y51otZKz.js → cose-bilkent-JH36ORCC-BQXzaioj.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-BRfS3cHo.js → cynefin-VYW2F7L2-BJIofhfe.js} +1 -1
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-Dpg2RtfL.js → cynefinDiagram-TSTJHNR4-DmPqTM1T.js} +1 -1
- package/client/dist/assets/{dagre-VKFMJZFB-BdZtXgKZ.js → dagre-VKFMJZFB-1xljvw6X.js} +1 -1
- package/client/dist/assets/{diagram-FQU43EPY-K-RCwWxW.js → diagram-FQU43EPY-iyL9muCG.js} +1 -1
- package/client/dist/assets/{diagram-G47NLZAW-CHNn7F2-.js → diagram-G47NLZAW-DREp2Th6.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-B3zu6xib.js → diagram-NH7WQ7WH-h0X3Is2S.js} +1 -1
- package/client/dist/assets/{diagram-OA4YK3LP-Wp5ju7L7.js → diagram-OA4YK3LP-Bj8YZRFJ.js} +1 -1
- package/client/dist/assets/{diagram-WEI45ONY-C94GpsRk.js → diagram-WEI45ONY-BZOf805d.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-DXrTPOrP.js → ebnfDiagram-CCIWWBDH-DO5JnXda.js} +1 -1
- package/client/dist/assets/{erDiagram-Q63AITRT-CGejnW0f.js → erDiagram-Q63AITRT-DRgcqg1T.js} +1 -1
- package/client/dist/assets/{flowDiagram-23GEKE2U-CFJMM637.js → flowDiagram-23GEKE2U-C3J9QmrW.js} +1 -1
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-DnaH94Su.js → ganttDiagram-NO4QXBWP-BIEl3Tkm.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-DT-D0gbn.js → gitGraphDiagram-IHSO6WYX-BNF0tFWC.js} +1 -1
- package/client/dist/assets/index-BnTOrFHb.js +829 -0
- package/client/dist/assets/index-CYPc6qxw.css +1 -0
- package/client/dist/assets/{infoDiagram-FWYZ7A6U-DW3Ps00w.js → infoDiagram-FWYZ7A6U-DEyFxiyY.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-DjxjIT3n.js → ishikawaDiagram-FXEZZL3T-B_ehlg3I.js} +1 -1
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-DTQRI93Y.js → journeyDiagram-5HDEW3XC-Dp00FyJS.js} +1 -1
- package/client/dist/assets/{kanban-definition-HUTT4EX6-BeDvbiEs.js → kanban-definition-HUTT4EX6-CTAf16q8.js} +1 -1
- package/client/dist/assets/{linear-B4foxDlh.js → linear-9vNUgmYd.js} +1 -1
- package/client/dist/assets/{mermaid.core-c-L4qgSB.js → mermaid.core-A6tjaEVD.js} +4 -4
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-dh8v0J8T.js → mindmap-definition-LN4V7U3C-DRW3bmCY.js} +1 -1
- package/client/dist/assets/{pegDiagram-2B236MQR-D5vNrtFh.js → pegDiagram-2B236MQR-DJFCjHp2.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-CIjg_6lR.js → pieDiagram-ENE6RG2P-KRd-sGvC.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-CF37qWQD.js → quadrantDiagram-ABIIQ3AL-9TLZE3Hu.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-x0Hn30Kj.js → railroadDiagram-RFXS5EU6-y4tLtjXg.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-BE2QnVbN.js → requirementDiagram-TGXJPOKE-B9EOQDQM.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-CUv6cIlV.js → sankeyDiagram-HTMAVEWB-zfwiDzkT.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-C3ACj5LS.js → sequenceDiagram-DBY2YBRQ-DW1LWepL.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-DTMIb5gX.js → sizeCapture-X5ZJPWSS-BM81Mik0.js} +1 -1
- package/client/dist/assets/{stateDiagram-2N3HPSRC-DI1Z8P74.js → stateDiagram-2N3HPSRC-D0EMIw1w.js} +1 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-B3E4_xxT.js +1 -0
- package/client/dist/assets/{swimlanes-5IMT3BWC-CLSr9w29.js → swimlanes-5IMT3BWC-CKXNCX6M.js} +2 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-BegQBqnC.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-BTWmUhDh.js → timeline-definition-FHXFAJF6-ByzIfvL5.js} +1 -1
- package/client/dist/assets/{vennDiagram-L72KCM5P-Ce1dlLCM.js → vennDiagram-L72KCM5P-Xep38xBH.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-EHGQE667-ClOE-aae.js → wardleyDiagram-EHGQE667-DKWDpx6g.js} +1 -1
- package/client/dist/assets/{xychartDiagram-FW5EYKEG-Fa2pqWKw.js → xychartDiagram-FW5EYKEG-BGcwZTnu.js} +1 -1
- package/client/dist/index.html +27 -27
- package/lib/claude-cli.mjs +173 -173
- package/lib/preflight.mjs +252 -252
- package/lib/probe-path.mjs +84 -84
- package/lib/server.mjs +369 -369
- package/lib/util.mjs +157 -157
- package/lib/win32-spawn.mjs +253 -253
- package/package.json +1 -1
- package/scripts/deploy-procs.mjs +208 -208
- package/scripts/deploy-swap.mjs +276 -276
- package/scripts/kill-targets.js +140 -140
- package/scripts/repair-claude-json.mjs +295 -295
- package/server/dist/config/default-actions.json +90 -90
- package/server/dist/core/grade-runner.d.ts +4 -4
- package/server/dist/core/grade-runner.d.ts.map +1 -1
- package/server/dist/core/grade-runner.js +51 -26
- package/server/dist/core/grade-runner.js.map +1 -1
- package/server/dist/core/grade-target.d.ts +8 -0
- package/server/dist/core/grade-target.d.ts.map +1 -1
- package/server/dist/core/grade-target.js +10 -0
- package/server/dist/core/grade-target.js.map +1 -1
- package/server/dist/core/mission-context/association.d.ts +46 -0
- package/server/dist/core/mission-context/association.d.ts.map +1 -1
- package/server/dist/core/mission-context/association.js +69 -0
- package/server/dist/core/mission-context/association.js.map +1 -1
- package/server/dist/core/mission-context/resolver-iterate.d.ts +6 -0
- package/server/dist/core/mission-context/resolver-iterate.d.ts.map +1 -0
- package/server/dist/core/mission-context/resolver-iterate.js +202 -0
- package/server/dist/core/mission-context/resolver-iterate.js.map +1 -0
- package/server/dist/core/mission-context/resolver-parts.d.ts +20 -0
- package/server/dist/core/mission-context/resolver-parts.d.ts.map +1 -1
- package/server/dist/core/mission-context/resolver-parts.js +92 -0
- package/server/dist/core/mission-context/resolver-parts.js.map +1 -1
- package/server/dist/core/mission-context/resolver.d.ts +1 -1
- package/server/dist/core/mission-context/resolver.d.ts.map +1 -1
- package/server/dist/core/mission-context/resolver.js +17 -199
- package/server/dist/core/mission-context/resolver.js.map +1 -1
- package/server/dist/core/mission-context/run-id-recovery.d.ts +21 -5
- package/server/dist/core/mission-context/run-id-recovery.d.ts.map +1 -1
- package/server/dist/core/mission-context/run-id-recovery.js +32 -5
- package/server/dist/core/mission-context/run-id-recovery.js.map +1 -1
- package/server/dist/core/mission-context/scenario.d.ts +18 -11
- package/server/dist/core/mission-context/scenario.d.ts.map +1 -1
- package/server/dist/core/mission-context/scenario.js +40 -3
- package/server/dist/core/mission-context/scenario.js.map +1 -1
- package/server/dist/core/path-guard.d.ts +1 -1
- package/server/dist/core/path-guard.d.ts.map +1 -1
- package/server/dist/core/path-guard.js +9 -2
- package/server/dist/core/path-guard.js.map +1 -1
- package/server/dist/core/shipslog-docs-reader.d.ts +4 -0
- package/server/dist/core/shipslog-docs-reader.d.ts.map +1 -0
- package/server/dist/core/shipslog-docs-reader.js +181 -0
- package/server/dist/core/shipslog-docs-reader.js.map +1 -0
- package/server/dist/core/shipslog-docs-types.d.ts +15 -0
- package/server/dist/core/shipslog-docs-types.d.ts.map +1 -0
- package/server/dist/core/shipslog-docs-types.js +14 -0
- package/server/dist/core/shipslog-docs-types.js.map +1 -0
- package/server/dist/core/triage-cli-runner.d.ts.map +1 -1
- package/server/dist/core/triage-cli-runner.js +29 -10
- package/server/dist/core/triage-cli-runner.js.map +1 -1
- package/server/dist/core/uv-runner.d.ts +23 -0
- package/server/dist/core/uv-runner.d.ts.map +1 -0
- package/server/dist/core/uv-runner.js +39 -0
- package/server/dist/core/uv-runner.js.map +1 -0
- package/server/dist/external/design-review/serve.js +27 -27
- package/server/dist/external/file/exists-routes.d.ts +7 -0
- package/server/dist/external/file/exists-routes.d.ts.map +1 -0
- package/server/dist/external/file/exists-routes.js +91 -0
- package/server/dist/external/file/exists-routes.js.map +1 -0
- package/server/dist/external/mission-context/association-write.d.ts +22 -0
- package/server/dist/external/mission-context/association-write.d.ts.map +1 -0
- package/server/dist/external/mission-context/association-write.js +90 -0
- package/server/dist/external/mission-context/association-write.js.map +1 -0
- package/server/dist/external/mission-context/routes.d.ts.map +1 -1
- package/server/dist/external/mission-context/routes.js +18 -31
- package/server/dist/external/mission-context/routes.js.map +1 -1
- package/server/dist/external/org/audit-log.d.ts +27 -0
- package/server/dist/external/org/audit-log.d.ts.map +1 -0
- package/server/dist/external/org/audit-log.js +92 -0
- package/server/dist/external/org/audit-log.js.map +1 -0
- package/server/dist/external/org/beat-register.d.ts +15 -22
- package/server/dist/external/org/beat-register.d.ts.map +1 -1
- package/server/dist/external/org/beat-register.js +37 -32
- package/server/dist/external/org/beat-register.js.map +1 -1
- package/server/dist/external/org/file-read.d.ts +16 -0
- package/server/dist/external/org/file-read.d.ts.map +1 -1
- package/server/dist/external/org/file-read.js +86 -46
- package/server/dist/external/org/file-read.js.map +1 -1
- package/server/dist/external/org/file-write-core.d.ts +18 -0
- package/server/dist/external/org/file-write-core.d.ts.map +1 -0
- package/server/dist/external/org/file-write-core.js +97 -0
- package/server/dist/external/org/file-write-core.js.map +1 -0
- package/server/dist/external/org/file-write.d.ts +25 -0
- package/server/dist/external/org/file-write.d.ts.map +1 -1
- package/server/dist/external/org/file-write.js +82 -132
- package/server/dist/external/org/file-write.js.map +1 -1
- package/server/dist/external/org/last-run.d.ts +25 -16
- package/server/dist/external/org/last-run.d.ts.map +1 -1
- package/server/dist/external/org/last-run.js +78 -64
- package/server/dist/external/org/last-run.js.map +1 -1
- package/server/dist/external/org/lead-doc-read.d.ts +21 -0
- package/server/dist/external/org/lead-doc-read.d.ts.map +1 -0
- package/server/dist/external/org/lead-doc-read.js +84 -0
- package/server/dist/external/org/lead-doc-read.js.map +1 -0
- package/server/dist/external/org/mount.d.ts +12 -0
- package/server/dist/external/org/mount.d.ts.map +1 -0
- package/server/dist/external/org/mount.js +34 -0
- package/server/dist/external/org/mount.js.map +1 -0
- package/server/dist/external/org/org-chart-lookup.d.ts +13 -0
- package/server/dist/external/org/org-chart-lookup.d.ts.map +1 -1
- package/server/dist/external/org/org-chart-lookup.js +40 -5
- package/server/dist/external/org/org-chart-lookup.js.map +1 -1
- package/server/dist/external/org/org-chart.d.ts +21 -12
- package/server/dist/external/org/org-chart.d.ts.map +1 -1
- package/server/dist/external/org/org-chart.js +50 -32
- package/server/dist/external/org/org-chart.js.map +1 -1
- package/server/dist/external/org/role-extract.d.ts +8 -0
- package/server/dist/external/org/role-extract.d.ts.map +1 -0
- package/server/dist/external/org/role-extract.js +72 -0
- package/server/dist/external/org/role-extract.js.map +1 -0
- package/server/dist/external/org/usage.d.ts +15 -11
- package/server/dist/external/org/usage.d.ts.map +1 -1
- package/server/dist/external/org/usage.js +64 -54
- package/server/dist/external/org/usage.js.map +1 -1
- package/server/dist/external/routes.d.ts +1 -1
- package/server/dist/external/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +19 -17
- package/server/dist/external/routes.js.map +1 -1
- package/server/dist/external/shipslog-docs/routes.d.ts +10 -0
- package/server/dist/external/shipslog-docs/routes.d.ts.map +1 -0
- package/server/dist/external/shipslog-docs/routes.js +41 -0
- package/server/dist/external/shipslog-docs/routes.js.map +1 -0
- package/server/dist/routes/grade.d.ts.map +1 -1
- package/server/dist/routes/grade.js +3 -2
- package/server/dist/routes/grade.js.map +1 -1
- package/server/dist/routes/org-leads-composite.d.ts +21 -0
- package/server/dist/routes/org-leads-composite.d.ts.map +1 -0
- package/server/dist/routes/org-leads-composite.js +95 -0
- package/server/dist/routes/org-leads-composite.js.map +1 -0
- package/server/dist/routes/org.d.ts +15 -0
- package/server/dist/routes/org.d.ts.map +1 -0
- package/server/dist/routes/org.js +198 -0
- package/server/dist/routes/org.js.map +1 -0
- package/server/dist/terminal/pty-manager.d.ts +9 -0
- package/server/dist/terminal/pty-manager.d.ts.map +1 -1
- package/server/dist/terminal/pty-manager.js +15 -0
- package/server/dist/terminal/pty-manager.js.map +1 -1
- package/server/dist/terminal/replay-snapshot.d.ts +10 -1
- package/server/dist/terminal/replay-snapshot.d.ts.map +1 -1
- package/server/dist/terminal/replay-snapshot.js +36 -1
- package/server/dist/terminal/replay-snapshot.js.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.d.ts +17 -1
- package/server/dist/terminal/ws-upgrade-handler.d.ts.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts +1 -0
- package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.fixtures.js +3 -2
- package/server/dist/terminal/ws-upgrade-handler.fixtures.js.map +1 -1
- package/server/dist/terminal/ws-upgrade-handler.js +45 -4
- package/server/dist/terminal/ws-upgrade-handler.js.map +1 -1
- package/server/dist/test/python-spawn-guard-util.d.ts +14 -0
- package/server/dist/test/python-spawn-guard-util.d.ts.map +1 -0
- package/server/dist/test/python-spawn-guard-util.js +124 -0
- package/server/dist/test/python-spawn-guard-util.js.map +1 -0
- package/server/dist/types/org.d.ts +115 -0
- package/server/dist/types/org.d.ts.map +1 -0
- package/server/dist/types/org.js +16 -0
- package/server/dist/types/org.js.map +1 -0
- package/server/package.json +1 -1
- package/server/profiles/PROFILE_SCHEMA_VERSION +1 -1
- package/server/profiles/README.md +27 -27
- package/server/profiles/python-plugin-monorepo.json +35 -35
- package/server/profiles/supabase-nextjs.json +253 -253
- package/server/profiles/vite-hono.json +92 -92
- package/client/dist/assets/MarkdownEditorModal-CP5yG9OU.js +0 -212
- package/client/dist/assets/channel-BNXbCvDS.js +0 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-w-wCtLx3.js +0 -1
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-w-wCtLx3.js +0 -1
- package/client/dist/assets/index-CU2QJgvx.js +0 -609
- package/client/dist/assets/index-ftvVcUT8.css +0 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-DvwiHlJv.js +0 -1
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-JTQZTlZ3.js +0 -8
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
import type { Hono } from "hono";
|
|
2
|
-
import { type
|
|
3
|
-
import {
|
|
4
|
-
export type CadenceUnresolvedReason
|
|
5
|
-
export type LastRunResponse = {
|
|
6
|
-
leadId: string;
|
|
7
|
-
measured: false;
|
|
8
|
-
} | {
|
|
9
|
-
leadId: string;
|
|
10
|
-
measured: true;
|
|
11
|
-
lastRunAt: string;
|
|
12
|
-
sessionId: string;
|
|
13
|
-
staleness: Staleness | "unknown";
|
|
14
|
-
thresholdMs: number | null;
|
|
15
|
-
cadenceMs: number | null;
|
|
16
|
-
cadenceUnresolvedReason?: CadenceUnresolvedReason;
|
|
17
|
-
};
|
|
2
|
+
import { type LeadOrgInfoResult } from "./org-chart-lookup.js";
|
|
3
|
+
import type { LastRunResponse } from "../../types/org.js";
|
|
4
|
+
export type { CadenceUnresolvedReason, LastRunResponse } from "../../types/org.js";
|
|
18
5
|
export interface LastRunRouteDeps {
|
|
19
6
|
leadsRoot: string;
|
|
20
7
|
/** Injectable for tests; production wires the real lstatSync. */
|
|
@@ -23,6 +10,28 @@ export interface LastRunRouteDeps {
|
|
|
23
10
|
};
|
|
24
11
|
/** Injectable for deterministic boundary tests; production wires `() => new Date()`. */
|
|
25
12
|
now?: () => Date;
|
|
13
|
+
/**
|
|
14
|
+
* Pre-fetched cron/reports_to lookup for this lead — when supplied,
|
|
15
|
+
* `lastRunCore` uses it INSTEAD of calling `readLeadOrgInfo` itself.
|
|
16
|
+
* The composite `/api/org/leads` read passes this (via
|
|
17
|
+
* `readAllLeadOrgInfo`, one chart parse for the whole roster); the
|
|
18
|
+
* single-lead secret-gated route omits it and keeps its own self-
|
|
19
|
+
* contained one-lead read (already O(1), not the N+1 this exists to fix).
|
|
20
|
+
*/
|
|
21
|
+
orgInfo?: LeadOrgInfoResult;
|
|
26
22
|
}
|
|
23
|
+
export type LastRunCoreResult = {
|
|
24
|
+
status: 200;
|
|
25
|
+
body: LastRunResponse;
|
|
26
|
+
} | {
|
|
27
|
+
status: 400 | 403 | 500 | 502;
|
|
28
|
+
body: {
|
|
29
|
+
error: string;
|
|
30
|
+
leadId?: string;
|
|
31
|
+
detail?: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/** Pure core — shared by the secret-gated route and the plain-surface proxy. */
|
|
35
|
+
export declare function lastRunCore(deps: LastRunRouteDeps, leadId: string): LastRunCoreResult;
|
|
27
36
|
export declare function registerLastRunRoute(app: Hono, deps: LastRunRouteDeps): void;
|
|
28
37
|
//# sourceMappingURL=last-run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"last-run.d.ts","sourceRoot":"","sources":["../../../src/external/org/last-run.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAMjC,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"last-run.d.ts","sourceRoot":"","sources":["../../../src/external/org/last-run.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAMjC,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,YAAY,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAcnF,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK;QAAE,cAAc,IAAI,OAAO,CAAA;KAAE,CAAC;IACzD,wFAAwF;IACxF,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GACtC;IAAE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEjG,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,CA2GrF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAK5E"}
|
|
@@ -40,62 +40,67 @@ function isValidLastRunPayload(v) {
|
|
|
40
40
|
typeof u.sessionId === "string" &&
|
|
41
41
|
u.sessionId.length > 0);
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
/** Pure core — shared by the secret-gated route and the plain-surface proxy. */
|
|
44
|
+
export function lastRunCore(deps, leadId) {
|
|
44
45
|
const { leadsRoot } = deps;
|
|
45
46
|
const lstat = deps.lstatSync ?? ((p) => lstatSync(p));
|
|
46
47
|
const now = deps.now ?? (() => new Date());
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (code === "ENOENT") {
|
|
60
|
-
const body = { leadId, measured: false };
|
|
61
|
-
return c.json(body, 200);
|
|
62
|
-
}
|
|
63
|
-
return c.json({ error: "last_run_read_failed", detail: String(err).slice(0, 200) }, 500);
|
|
64
|
-
}
|
|
65
|
-
if (lst.isSymbolicLink()) {
|
|
66
|
-
return c.json({ error: "symlink_forbidden", leadId }, 403);
|
|
67
|
-
}
|
|
68
|
-
const containment = realPathGuard(leadsRoot, absolute);
|
|
69
|
-
if (!containment.ok) {
|
|
70
|
-
return c.json({ error: "path_traversal", detail: containment.reason }, 400);
|
|
71
|
-
}
|
|
72
|
-
let raw;
|
|
73
|
-
try {
|
|
74
|
-
raw = readFileSync(absolute, "utf8");
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
const code = err?.code;
|
|
78
|
-
if (code === "ENOENT") {
|
|
79
|
-
const body = { leadId, measured: false };
|
|
80
|
-
return c.json(body, 200);
|
|
81
|
-
}
|
|
82
|
-
return c.json({ error: "last_run_read_failed", detail: String(err).slice(0, 200) }, 500);
|
|
83
|
-
}
|
|
84
|
-
let parsed;
|
|
85
|
-
try {
|
|
86
|
-
parsed = JSON.parse(raw);
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return c.json({ error: "last_run_invalid", leadId }, 502);
|
|
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, "last-run.json");
|
|
52
|
+
let lst;
|
|
53
|
+
try {
|
|
54
|
+
lst = lstat(absolute);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const code = err?.code;
|
|
58
|
+
if (code === "ENOENT") {
|
|
59
|
+
return { status: 200, body: { leadId, measured: false } };
|
|
90
60
|
}
|
|
91
|
-
|
|
92
|
-
|
|
61
|
+
return {
|
|
62
|
+
status: 500,
|
|
63
|
+
body: { error: "last_run_read_failed", detail: String(err).slice(0, 200) },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (lst.isSymbolicLink()) {
|
|
67
|
+
return { status: 403, body: { error: "symlink_forbidden", leadId } };
|
|
68
|
+
}
|
|
69
|
+
const containment = realPathGuard(leadsRoot, absolute);
|
|
70
|
+
if (!containment.ok) {
|
|
71
|
+
return { status: 400, body: { error: "path_traversal", detail: containment.reason } };
|
|
72
|
+
}
|
|
73
|
+
let raw;
|
|
74
|
+
try {
|
|
75
|
+
raw = readFileSync(absolute, "utf8");
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const code = err?.code;
|
|
79
|
+
if (code === "ENOENT") {
|
|
80
|
+
return { status: 200, body: { leadId, measured: false } };
|
|
93
81
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
82
|
+
return {
|
|
83
|
+
status: 500,
|
|
84
|
+
body: { error: "last_run_read_failed", detail: String(err).slice(0, 200) },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(raw);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return { status: 502, body: { error: "last_run_invalid", leadId } };
|
|
93
|
+
}
|
|
94
|
+
if (!isValidLastRunPayload(parsed)) {
|
|
95
|
+
return { status: 502, body: { error: "last_run_invalid", leadId } };
|
|
96
|
+
}
|
|
97
|
+
const { lastRunAt, sessionId } = parsed;
|
|
98
|
+
const nowValue = now();
|
|
99
|
+
const orgInfo = deps.orgInfo ?? readLeadOrgInfo(leadsRoot, leadId);
|
|
100
|
+
if (!orgInfo.ok) {
|
|
101
|
+
return {
|
|
102
|
+
status: 200,
|
|
103
|
+
body: {
|
|
99
104
|
leadId,
|
|
100
105
|
measured: true,
|
|
101
106
|
lastRunAt,
|
|
@@ -104,12 +109,14 @@ export function registerLastRunRoute(app, deps) {
|
|
|
104
109
|
thresholdMs: null,
|
|
105
110
|
cadenceMs: null,
|
|
106
111
|
cadenceUnresolvedReason: orgInfo.reason,
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const interval = cronIntervalMs(orgInfo.cron, nowValue);
|
|
116
|
+
if (!interval.ok) {
|
|
117
|
+
return {
|
|
118
|
+
status: 200,
|
|
119
|
+
body: {
|
|
113
120
|
leadId,
|
|
114
121
|
measured: true,
|
|
115
122
|
lastRunAt,
|
|
@@ -118,11 +125,13 @@ export function registerLastRunRoute(app, deps) {
|
|
|
118
125
|
thresholdMs: null,
|
|
119
126
|
cadenceMs: null,
|
|
120
127
|
cadenceUnresolvedReason: "invalid_cron",
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const evaluation = evaluateStaleness(lastRunAt, interval.ms, nowValue);
|
|
132
|
+
return {
|
|
133
|
+
status: 200,
|
|
134
|
+
body: {
|
|
126
135
|
leadId,
|
|
127
136
|
measured: true,
|
|
128
137
|
lastRunAt,
|
|
@@ -130,8 +139,13 @@ export function registerLastRunRoute(app, deps) {
|
|
|
130
139
|
staleness: evaluation.staleness,
|
|
131
140
|
thresholdMs: evaluation.thresholdMs,
|
|
132
141
|
cadenceMs: interval.ms,
|
|
133
|
-
}
|
|
134
|
-
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export function registerLastRunRoute(app, deps) {
|
|
146
|
+
app.get("/api/external/org/leads/:leadId/last-run", async (c) => {
|
|
147
|
+
const result = lastRunCore(deps, c.req.param("leadId"));
|
|
148
|
+
return c.json(result.body, result.status);
|
|
135
149
|
});
|
|
136
150
|
}
|
|
137
151
|
//# sourceMappingURL=last-run.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"last-run.js","sourceRoot":"","sources":["../../../src/external/org/last-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAA0B,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"last-run.js","sourceRoot":"","sources":["../../../src/external/org/last-run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { openSync } from "node:fs";
|
|
2
|
+
export type LeadDocReadResult = {
|
|
3
|
+
status: 200;
|
|
4
|
+
kind: "file";
|
|
5
|
+
body: Buffer;
|
|
6
|
+
headers: Record<string, string>;
|
|
7
|
+
} | {
|
|
8
|
+
status: 400 | 403 | 404 | 500;
|
|
9
|
+
kind: "json";
|
|
10
|
+
body: {
|
|
11
|
+
error: string;
|
|
12
|
+
detail?: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export interface LeadDocReadDeps {
|
|
16
|
+
leadsRoot: string;
|
|
17
|
+
openSync?: typeof openSync;
|
|
18
|
+
}
|
|
19
|
+
/** Pure core — reads `<leadsRoot>/<leadId>/learnings.md`. */
|
|
20
|
+
export declare function leadLearningsReadCore(deps: LeadDocReadDeps, leadId: string | undefined): LeadDocReadResult;
|
|
21
|
+
//# sourceMappingURL=lead-doc-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-doc-read.d.ts","sourceRoot":"","sources":["../../../src/external/org/lead-doc-read.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAkD,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAOjG,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5E;IAAE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE9F,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC;CAC5B;AAID,6DAA6D;AAC7D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAsD1G"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* external/org/lead-doc-read.ts — GET-only read for a lead's `learnings.md`.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately NOT part of `_helpers.ts`'s six-target allowlist — that
|
|
5
|
+
* allowlist's own docstring calls it a fixed, shared contract with the
|
|
6
|
+
* secret-gated family (`external/org/routes.ts`), and widening it would
|
|
7
|
+
* change what BOTH families accept. `learnings.md` is a read this iterate's
|
|
8
|
+
* new plain `/api/org/*` surface needs (Docs block, AC-2) that the gated
|
|
9
|
+
* family never exposed and doesn't need to; this module — and the sibling
|
|
10
|
+
* `audit-log.ts` for `audit.jsonl` — exist to add it additively, without
|
|
11
|
+
* touching that stable contract.
|
|
12
|
+
*
|
|
13
|
+
* `leadId` is validated against `LEAD_ID_RE` (same validator every other
|
|
14
|
+
* org route shares — never a second one) and the filename suffix is a
|
|
15
|
+
* hardcoded constant, never client-supplied — so unlike the six-target
|
|
16
|
+
* allowlist's raw `path=` input, there is no string for a traversal
|
|
17
|
+
* sequence to hide in. `pathGuard` runs anyway as defense in depth against
|
|
18
|
+
* a future caller changing that; `realPathGuard` (which needs the target to
|
|
19
|
+
* already exist — see its own docstring) is applied AFTER the open, unlike
|
|
20
|
+
* `file-read.ts`'s ordering, precisely so a genuinely-missing file 404s
|
|
21
|
+
* instead of realpathSync's ENOENT reporting as `path_traversal` first.
|
|
22
|
+
*/
|
|
23
|
+
import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
import { pathGuard, realPathGuard } from "../../core/path-guard.js";
|
|
26
|
+
import { LEAD_ID_RE } from "./_helpers.js";
|
|
27
|
+
import { fileFingerprint } from "../file/_helpers.js";
|
|
28
|
+
const LEARNINGS_FILENAME = "learnings.md";
|
|
29
|
+
/** Pure core — reads `<leadsRoot>/<leadId>/learnings.md`. */
|
|
30
|
+
export function leadLearningsReadCore(deps, leadId) {
|
|
31
|
+
const { leadsRoot } = deps;
|
|
32
|
+
const open = deps.openSync ?? openSync;
|
|
33
|
+
if (!leadId || !LEAD_ID_RE.test(leadId)) {
|
|
34
|
+
return { status: 400, kind: "json", body: { error: "invalid_lead_id" } };
|
|
35
|
+
}
|
|
36
|
+
const guard = pathGuard(leadsRoot, join(leadId, LEARNINGS_FILENAME));
|
|
37
|
+
if (!guard.ok) {
|
|
38
|
+
return { status: 400, kind: "json", body: { error: "path_traversal", detail: guard.reason } };
|
|
39
|
+
}
|
|
40
|
+
let fd;
|
|
41
|
+
try {
|
|
42
|
+
fd = open(guard.absolute, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
const code = err?.code;
|
|
46
|
+
if (code === "ENOENT") {
|
|
47
|
+
return { status: 404, kind: "json", body: { error: "not_found" } };
|
|
48
|
+
}
|
|
49
|
+
if (code === "ELOOP") {
|
|
50
|
+
return { status: 403, kind: "json", body: { error: "symlink_forbidden" } };
|
|
51
|
+
}
|
|
52
|
+
return { status: 500, kind: "json", body: { error: "file_stat_failed", detail: String(err).slice(0, 200) } };
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
if (!fstatSync(fd).isFile()) {
|
|
56
|
+
return { status: 400, kind: "json", body: { error: "not_a_file" } };
|
|
57
|
+
}
|
|
58
|
+
// Existence is now confirmed (the open above succeeded) — realPathGuard's
|
|
59
|
+
// own contract requires exactly this ordering.
|
|
60
|
+
const realGuard = realPathGuard(leadsRoot, guard.absolute);
|
|
61
|
+
if (!realGuard.ok) {
|
|
62
|
+
return { status: 403, kind: "json", body: { error: "symlink_forbidden", detail: realGuard.reason } };
|
|
63
|
+
}
|
|
64
|
+
const body = readFileSync(fd);
|
|
65
|
+
return {
|
|
66
|
+
status: 200,
|
|
67
|
+
kind: "file",
|
|
68
|
+
body,
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "text/markdown; charset=utf-8",
|
|
71
|
+
"X-Content-Type-Options": "nosniff",
|
|
72
|
+
ETag: `"${fileFingerprint(body)}"`,
|
|
73
|
+
"Cache-Control": "private, max-age=0, must-revalidate",
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return { status: 500, kind: "json", body: { error: "file_read_failed", detail: String(err).slice(0, 200) } };
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
closeSync(fd);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=lead-doc-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-doc-read.js","sourceRoot":"","sources":["../../../src/external/org/lead-doc-read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import { type OrgRouterDeps } from "./routes.js";
|
|
3
|
+
export interface MountOrgRoutersDeps {
|
|
4
|
+
honoHost?: string;
|
|
5
|
+
leadsRoot?: string;
|
|
6
|
+
leadsRouteSecret?: string;
|
|
7
|
+
orgLstatSync?: OrgRouterDeps["lstatSync"];
|
|
8
|
+
orgWithDecisionsLock?: OrgRouterDeps["withDecisionsLock"];
|
|
9
|
+
}
|
|
10
|
+
/** FR-04.38 — mounted only when `honoHost` + `leadsRoot` are both provided. */
|
|
11
|
+
export declare function mountOrgRouters(app: Hono, deps: MountOrgRoutersDeps): void;
|
|
12
|
+
//# sourceMappingURL=mount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/external/org/mount.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGlE,MAAM,WAAW,mBAAmB;IAClC,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;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAuB1E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* external/org/mount.ts — composes BOTH the secret-gated `/api/external/org/*`
|
|
3
|
+
* family and the plain-surface `/api/org/*` proxy onto one parent Hono app.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `external/routes.ts` (grandfathered at the 300-line bloat
|
|
6
|
+
* ceiling — CLAUDE.md) purely to avoid ratcheting it; no behavior change.
|
|
7
|
+
* Mounting both from one call site is NOT the "route-mount collision" the
|
|
8
|
+
* iterate spec's Design Notes warn against — that note is about the new
|
|
9
|
+
* router never calling a `registerXRoute` from this family (it doesn't;
|
|
10
|
+
* `routes/org.ts` only imports the extracted pure cores). Which file issues
|
|
11
|
+
* the two `app.route()` calls is unrelated to that guard.
|
|
12
|
+
*/
|
|
13
|
+
import { createOrgRouter } from "./routes.js";
|
|
14
|
+
import { createOrgApiRouter } from "../../routes/org.js";
|
|
15
|
+
/** FR-04.38 — mounted only when `honoHost` + `leadsRoot` are both provided. */
|
|
16
|
+
export function mountOrgRouters(app, deps) {
|
|
17
|
+
const { honoHost, leadsRoot, leadsRouteSecret, orgLstatSync, orgWithDecisionsLock } = deps;
|
|
18
|
+
if (!honoHost || !leadsRoot)
|
|
19
|
+
return;
|
|
20
|
+
app.route("/", createOrgRouter({
|
|
21
|
+
honoHost,
|
|
22
|
+
leadsRoot,
|
|
23
|
+
leadsRouteSecret,
|
|
24
|
+
lstatSync: orgLstatSync,
|
|
25
|
+
withDecisionsLock: orgWithDecisionsLock,
|
|
26
|
+
}));
|
|
27
|
+
app.route("/", createOrgApiRouter({
|
|
28
|
+
honoHost,
|
|
29
|
+
leadsRoot,
|
|
30
|
+
lstatSync: orgLstatSync,
|
|
31
|
+
withDecisionsLock: orgWithDecisionsLock,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=mount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../../../src/external/org/mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,eAAe,EAAsB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAUzD,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,GAAS,EAAE,IAAyB;IAClE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,YAAY,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC;IAC3F,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS;QAAE,OAAO;IAEpC,GAAG,CAAC,KAAK,CACP,GAAG,EACH,eAAe,CAAC;QACd,QAAQ;QACR,SAAS;QACT,gBAAgB;QAChB,SAAS,EAAE,YAAY;QACvB,iBAAiB,EAAE,oBAAoB;KACxC,CAAC,CACH,CAAC;IACF,GAAG,CAAC,KAAK,CACP,GAAG,EACH,kBAAkB,CAAC;QACjB,QAAQ;QACR,SAAS;QACT,SAAS,EAAE,YAAY;QACvB,iBAAiB,EAAE,oBAAoB;KACxC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -13,4 +13,17 @@ export declare function readLeadOrgInfo(leadsRoot: string, leadId: string,
|
|
|
13
13
|
* mocked final-component symlink would produce, without needing a REAL
|
|
14
14
|
* symlink on disk). Defaults to the real `openSync`. */
|
|
15
15
|
openSyncFn?: typeof openSync): LeadOrgInfoResult;
|
|
16
|
+
/**
|
|
17
|
+
* Reads + parses `org-chart.json` ONCE and returns a lookup callback good
|
|
18
|
+
* for every lead in the roster — for a composite, multi-lead read where
|
|
19
|
+
* `readLeadOrgInfo`'s per-call re-open+re-parse would recreate the N+1
|
|
20
|
+
* pattern the composite endpoint exists to avoid.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readAllLeadOrgInfo(leadsRoot: string, openSyncFn?: typeof openSync): {
|
|
23
|
+
ok: true;
|
|
24
|
+
forLead: (leadId: string) => LeadOrgInfoResult;
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
reason: "org_chart_missing" | "org_chart_symlink" | "org_chart_invalid";
|
|
28
|
+
};
|
|
16
29
|
//# sourceMappingURL=org-chart-lookup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"org-chart-lookup.d.ts","sourceRoot":"","sources":["../../../src/external/org/org-chart-lookup.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAkD,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAGjG,MAAM,MAAM,iBAAiB,GACzB,mBAAmB,GACnB,mBAAmB,GACnB,mBAAmB,GACnB,gBAAgB,CAAC;AAErB,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"org-chart-lookup.d.ts","sourceRoot":"","sources":["../../../src/external/org/org-chart-lookup.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAkD,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAGjG,MAAM,MAAM,iBAAiB,GACzB,mBAAmB,GACnB,mBAAmB,GACnB,mBAAmB,GACnB,gBAAgB,CAAC;AAErB,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAiG7C,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM;AACd;;yDAEyD;AACzD,UAAU,GAAE,OAAO,QAAmB,GACrC,iBAAiB,CAInB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,OAAO,QAAmB,GAEpC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,CAAA;CAAE,GAC5D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,GAAG,mBAAmB,CAAA;CAAE,CAIzF"}
|
|
@@ -29,11 +29,20 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { closeSync, constants as fsConstants, fstatSync, openSync, readFileSync } from "node:fs";
|
|
31
31
|
import path from "node:path";
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
|
|
32
|
+
/**
|
|
33
|
+
* The O_NOFOLLOW-open + fstat + JSON.parse steps, isolated from the
|
|
34
|
+
* per-lead lookup below — this is the ONE disk read/parse. Split out so
|
|
35
|
+
* `readAllLeadOrgInfo` can share it across every lead in a single request
|
|
36
|
+
* instead of `readLeadOrgInfo`'s per-lead re-open+re-parse (external-review
|
|
37
|
+
* fix, MEDIUM/spec: `GET /api/org/leads` was re-parsing `org-chart.json`
|
|
38
|
+
* once per lead via this function — see the iterate spec's Design Notes).
|
|
39
|
+
* The composite route also calls `orgChartCore` separately for the roster
|
|
40
|
+
* body, so a request still parses the file AT MOST TWICE, never per-lead —
|
|
41
|
+
* that two-parse ceiling, not a single shared parse, is what this fixes
|
|
42
|
+
* (code-review fix: the design doc previously overclaimed "parses the
|
|
43
|
+
* chart once").
|
|
44
|
+
*/
|
|
45
|
+
function readOrgChartRaw(leadsRoot, openSyncFn) {
|
|
37
46
|
const target = path.join(leadsRoot, "org-chart.json");
|
|
38
47
|
let fd;
|
|
39
48
|
try {
|
|
@@ -72,6 +81,10 @@ openSyncFn = openSync) {
|
|
|
72
81
|
if (typeof parsed !== "object" || parsed === null) {
|
|
73
82
|
return { ok: false, reason: "org_chart_invalid" };
|
|
74
83
|
}
|
|
84
|
+
return { ok: true, parsed };
|
|
85
|
+
}
|
|
86
|
+
/** Looks up ONE lead's `triggers.cron` + `reports_to` in an already-parsed chart. */
|
|
87
|
+
function lookupLeadOrgInfo(parsed, leadId) {
|
|
75
88
|
const leadsField = parsed.leads;
|
|
76
89
|
if (typeof leadsField !== "object" || leadsField === null || Array.isArray(leadsField)) {
|
|
77
90
|
return { ok: false, reason: "org_chart_invalid" };
|
|
@@ -97,4 +110,26 @@ openSyncFn = openSync) {
|
|
|
97
110
|
: null;
|
|
98
111
|
return { ok: true, cron, reportsTo };
|
|
99
112
|
}
|
|
113
|
+
export function readLeadOrgInfo(leadsRoot, leadId,
|
|
114
|
+
/** Test seam for the O_NOFOLLOW open below (e.g. to simulate an ELOOP a
|
|
115
|
+
* mocked final-component symlink would produce, without needing a REAL
|
|
116
|
+
* symlink on disk). Defaults to the real `openSync`. */
|
|
117
|
+
openSyncFn = openSync) {
|
|
118
|
+
const raw = readOrgChartRaw(leadsRoot, openSyncFn);
|
|
119
|
+
if (!raw.ok)
|
|
120
|
+
return raw;
|
|
121
|
+
return lookupLeadOrgInfo(raw.parsed, leadId);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Reads + parses `org-chart.json` ONCE and returns a lookup callback good
|
|
125
|
+
* for every lead in the roster — for a composite, multi-lead read where
|
|
126
|
+
* `readLeadOrgInfo`'s per-call re-open+re-parse would recreate the N+1
|
|
127
|
+
* pattern the composite endpoint exists to avoid.
|
|
128
|
+
*/
|
|
129
|
+
export function readAllLeadOrgInfo(leadsRoot, openSyncFn = openSync) {
|
|
130
|
+
const raw = readOrgChartRaw(leadsRoot, openSyncFn);
|
|
131
|
+
if (!raw.ok)
|
|
132
|
+
return raw;
|
|
133
|
+
return { ok: true, forLead: (leadId) => lookupLeadOrgInfo(raw.parsed, leadId) };
|
|
134
|
+
}
|
|
100
135
|
//# sourceMappingURL=org-chart-lookup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"org-chart-lookup.js","sourceRoot":"","sources":["../../../src/external/org/org-chart-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"org-chart-lookup.js","sourceRoot":"","sources":["../../../src/external/org/org-chart-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,IAAI,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACjG,OAAO,IAAI,MAAM,WAAW,CAAC;AAgB7B;;;;;;;;;;;;GAYG;AACH,SAAS,eAAe,CACtB,SAAiB,EACjB,UAA2B;IAE3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEtD,IAAI,EAAU,CAAC;IACf,IAAI,CAAC;QACH,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACzE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;QAClD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;QACpD,CAAC;QACD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;QACpD,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;QACpD,CAAC;QACD,GAAG,GAAG,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC;AAED,qFAAqF;AACrF,SAAS,iBAAiB,CAAC,MAAe,EAAE,MAAc;IACxD,MAAM,UAAU,GAAI,MAAkC,CAAC,KAAK,CAAC;IAC7D,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACvF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,IAAI,GAAI,UAAsC,CAAC,MAAM,CAAC,CAAC;IAC7D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IACjD,CAAC;IACD,MAAM,UAAU,GAAG,IAA+B,CAAC;IAEnD,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;IACrC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;IACD,MAAM,IAAI,GAAI,QAAoC,CAAC,IAAI,CAAC;IACxD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC;IAC3C,MAAM,SAAS,GACb,YAAY,KAAK,IAAI;QACnB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC;YAC3D,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,IAAI,CAAC;IAEb,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,MAAc;AACd;;yDAEyD;AACzD,aAA8B,QAAQ;IAEtC,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACnD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC;IACxB,OAAO,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAiB,EACjB,aAA8B,QAAQ;IAItC,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACnD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC;IACxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;AAC1F,CAAC"}
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import type { Hono } from "hono";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
name: string;
|
|
5
|
-
reports_to: string | null;
|
|
6
|
-
manages: string[];
|
|
7
|
-
charter_path: string;
|
|
8
|
-
}
|
|
9
|
-
export interface OrgChartView {
|
|
10
|
-
version: number;
|
|
11
|
-
po: string;
|
|
12
|
-
leads: Record<string, OrgChartLeadView>;
|
|
13
|
-
}
|
|
2
|
+
import type { OrgChartView } from "../../types/org.js";
|
|
3
|
+
export type { OrgChartLeadView, OrgChartView } from "../../types/org.js";
|
|
14
4
|
/** Structural-only check — NOT the full leadwright Zod schema. See file header. */
|
|
15
5
|
export declare function parseOrgChart(raw: string): OrgChartView | null;
|
|
16
6
|
export interface OrgChartRouteDeps {
|
|
@@ -21,5 +11,24 @@ export interface OrgChartRouteDeps {
|
|
|
21
11
|
isSymbolicLink(): boolean;
|
|
22
12
|
};
|
|
23
13
|
}
|
|
14
|
+
export type OrgChartCoreResult = {
|
|
15
|
+
status: 200;
|
|
16
|
+
body: OrgChartView;
|
|
17
|
+
} | {
|
|
18
|
+
status: 403 | 404 | 500 | 502;
|
|
19
|
+
body: {
|
|
20
|
+
error: string;
|
|
21
|
+
detail?: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Pure core — no Hono dependency, so both the secret-gated
|
|
26
|
+
* `/api/external/org/org-chart` route AND the plain-surface `/api/org/*`
|
|
27
|
+
* proxy (browser-facing, no secret, see `server/src/routes/org.ts`) share
|
|
28
|
+
* this ONE implementation of the symlink/containment/parse guards
|
|
29
|
+
* (Internal Plan Review fix — the guards previously lived only inside this
|
|
30
|
+
* handler closure and could not have been reused without duplication).
|
|
31
|
+
*/
|
|
32
|
+
export declare function orgChartCore(deps: OrgChartRouteDeps): OrgChartCoreResult;
|
|
24
33
|
export declare function registerOrgChartRoute(app: Hono, deps: OrgChartRouteDeps): void;
|
|
25
34
|
//# sourceMappingURL=org-chart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"org-chart.d.ts","sourceRoot":"","sources":["../../../src/external/org/org-chart.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAIjC,
|
|
1
|
+
{"version":3,"file":"org-chart.d.ts","sourceRoot":"","sources":["../../../src/external/org/org-chart.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAIjC,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEzE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAezE,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA2B9D;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB;0EACsE;IACtE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,cAAc,IAAI,OAAO,CAAA;KAAE,CAAC;CAC7D;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEhF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CA4CxE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAK9E"}
|