@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.
Files changed (175) hide show
  1. package/client/dist/assets/{EmbeddedTerminal-D2BLGWdW.js → EmbeddedTerminal-5QvKe3_a.js} +20 -20
  2. package/client/dist/assets/{abnfDiagram-VRR7QNED-C-W_2Jd4.js → abnfDiagram-VRR7QNED-CXi9HegQ.js} +1 -1
  3. package/client/dist/assets/{arc-CpqwESP5.js → arc-DLh4GiqR.js} +1 -1
  4. package/client/dist/assets/{architectureDiagram-ZJ3FMSHR-DZVZ895V.js → architectureDiagram-ZJ3FMSHR-DUypQ8dQ.js} +1 -1
  5. package/client/dist/assets/{blockDiagram-677ZJIJ3-CCCZiAA7.js → blockDiagram-677ZJIJ3-D2cVMKJG.js} +1 -1
  6. package/client/dist/assets/{c4Diagram-LMCZKHZV-Bg1beZAE.js → c4Diagram-LMCZKHZV-DtruBGJw.js} +1 -1
  7. package/client/dist/assets/channel-C_k-9jsa.js +1 -0
  8. package/client/dist/assets/{chunk-2Q5K7J3B-CoaXSarh.js → chunk-2Q5K7J3B-CAfQkFw2.js} +1 -1
  9. package/client/dist/assets/{chunk-32BRIVSS-CeFXS-CM.js → chunk-32BRIVSS-CPWXoLnQ.js} +1 -1
  10. package/client/dist/assets/{chunk-5VM5RSS4-QyJMVe0m.js → chunk-5VM5RSS4-xVc3oppQ.js} +1 -1
  11. package/client/dist/assets/{chunk-EX3LRPZG-BIOtWVF8.js → chunk-EX3LRPZG-CUpl6fRR.js} +1 -1
  12. package/client/dist/assets/{chunk-JWPE2WC7-Dcq-lWyX.js → chunk-JWPE2WC7-NejUp56x.js} +1 -1
  13. package/client/dist/assets/{chunk-MOJQB5TN-C95323ja.js → chunk-MOJQB5TN-C9-2lLg0.js} +1 -1
  14. package/client/dist/assets/{chunk-RYQCIY6F-C0HPwpWy.js → chunk-RYQCIY6F-BAPtwABy.js} +1 -1
  15. package/client/dist/assets/{chunk-V7JOEXUC-BPrTbZqA.js → chunk-V7JOEXUC-Dwzihw26.js} +1 -1
  16. package/client/dist/assets/{chunk-VR4S4FIN--BCnNoqt.js → chunk-VR4S4FIN-9-iArFJM.js} +1 -1
  17. package/client/dist/assets/{chunk-XXDRQBXY-Dj8vtcXf.js → chunk-XXDRQBXY-DiWHOrqe.js} +1 -1
  18. package/client/dist/assets/classDiagram-OUVF2IWQ-CsEPq9Ac.js +1 -0
  19. package/client/dist/assets/classDiagram-v2-EOCWNBFH-CsEPq9Ac.js +1 -0
  20. package/client/dist/assets/{cose-bilkent-JH36ORCC-y51otZKz.js → cose-bilkent-JH36ORCC-Cp04EOcH.js} +1 -1
  21. package/client/dist/assets/{cynefin-VYW2F7L2-BRfS3cHo.js → cynefin-VYW2F7L2-D--GN1v8.js} +1 -1
  22. package/client/dist/assets/{cynefinDiagram-TSTJHNR4-Dpg2RtfL.js → cynefinDiagram-TSTJHNR4-BGH0o_qp.js} +1 -1
  23. package/client/dist/assets/{dagre-VKFMJZFB-BdZtXgKZ.js → dagre-VKFMJZFB-DSKkIKlj.js} +1 -1
  24. package/client/dist/assets/{diagram-FQU43EPY-K-RCwWxW.js → diagram-FQU43EPY-Cs_C4lb-.js} +1 -1
  25. package/client/dist/assets/{diagram-G47NLZAW-CHNn7F2-.js → diagram-G47NLZAW-oDtAA8O_.js} +1 -1
  26. package/client/dist/assets/{diagram-NH7WQ7WH-B3zu6xib.js → diagram-NH7WQ7WH-BiFMjqSH.js} +1 -1
  27. package/client/dist/assets/{diagram-OA4YK3LP-Wp5ju7L7.js → diagram-OA4YK3LP-Ccs3thCj.js} +1 -1
  28. package/client/dist/assets/{diagram-WEI45ONY-C94GpsRk.js → diagram-WEI45ONY-CdZNqgO3.js} +1 -1
  29. package/client/dist/assets/{ebnfDiagram-CCIWWBDH-DXrTPOrP.js → ebnfDiagram-CCIWWBDH-CapTA0VL.js} +1 -1
  30. package/client/dist/assets/{erDiagram-Q63AITRT-CGejnW0f.js → erDiagram-Q63AITRT-BcRNEP8s.js} +1 -1
  31. package/client/dist/assets/{flowDiagram-23GEKE2U-CFJMM637.js → flowDiagram-23GEKE2U-CJ_zF7e_.js} +1 -1
  32. package/client/dist/assets/{ganttDiagram-NO4QXBWP-DnaH94Su.js → ganttDiagram-NO4QXBWP-CnJdcg9A.js} +1 -1
  33. package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-DT-D0gbn.js → gitGraphDiagram-IHSO6WYX-YTUQ_ELk.js} +1 -1
  34. package/client/dist/assets/index-6nZ1bt0a.css +1 -0
  35. package/client/dist/assets/index-irQhGNpn.js +828 -0
  36. package/client/dist/assets/{infoDiagram-FWYZ7A6U-DW3Ps00w.js → infoDiagram-FWYZ7A6U-CLOP_ZWD.js} +1 -1
  37. package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-DjxjIT3n.js → ishikawaDiagram-FXEZZL3T-aFTIzr7o.js} +1 -1
  38. package/client/dist/assets/{journeyDiagram-5HDEW3XC-DTQRI93Y.js → journeyDiagram-5HDEW3XC-CbPJB4xd.js} +1 -1
  39. package/client/dist/assets/{kanban-definition-HUTT4EX6-BeDvbiEs.js → kanban-definition-HUTT4EX6-BoyhytIS.js} +1 -1
  40. package/client/dist/assets/{linear-B4foxDlh.js → linear-1VXA-uBg.js} +1 -1
  41. package/client/dist/assets/{mermaid.core-c-L4qgSB.js → mermaid.core-D_lO2yK9.js} +4 -4
  42. package/client/dist/assets/{mindmap-definition-LN4V7U3C-dh8v0J8T.js → mindmap-definition-LN4V7U3C-iFK7LXMx.js} +1 -1
  43. package/client/dist/assets/{pegDiagram-2B236MQR-D5vNrtFh.js → pegDiagram-2B236MQR-DNmcmfA-.js} +1 -1
  44. package/client/dist/assets/{pieDiagram-ENE6RG2P-CIjg_6lR.js → pieDiagram-ENE6RG2P-ekx83O5b.js} +1 -1
  45. package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-CF37qWQD.js → quadrantDiagram-ABIIQ3AL-DayyD1l8.js} +1 -1
  46. package/client/dist/assets/{railroadDiagram-RFXS5EU6-x0Hn30Kj.js → railroadDiagram-RFXS5EU6-Bdgz7S6G.js} +1 -1
  47. package/client/dist/assets/{requirementDiagram-TGXJPOKE-BE2QnVbN.js → requirementDiagram-TGXJPOKE-szP3Muld.js} +1 -1
  48. package/client/dist/assets/{sankeyDiagram-HTMAVEWB-CUv6cIlV.js → sankeyDiagram-HTMAVEWB-Ct3rzgUj.js} +1 -1
  49. package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-C3ACj5LS.js → sequenceDiagram-DBY2YBRQ-_69EfmOU.js} +1 -1
  50. package/client/dist/assets/{sizeCapture-X5ZJPWSS-DTMIb5gX.js → sizeCapture-X5ZJPWSS-BSOU06J2.js} +1 -1
  51. package/client/dist/assets/{stateDiagram-2N3HPSRC-DI1Z8P74.js → stateDiagram-2N3HPSRC-HmOmFwQm.js} +1 -1
  52. package/client/dist/assets/stateDiagram-v2-6OUMAXLB-BW8H33dv.js +1 -0
  53. package/client/dist/assets/{swimlanes-5IMT3BWC-CLSr9w29.js → swimlanes-5IMT3BWC-CVg_4oT7.js} +2 -2
  54. package/client/dist/assets/swimlanesDiagram-G3AALYLV-BaRlxcPD.js +8 -0
  55. package/client/dist/assets/{timeline-definition-FHXFAJF6-BTWmUhDh.js → timeline-definition-FHXFAJF6-CBBaDKXm.js} +1 -1
  56. package/client/dist/assets/{vennDiagram-L72KCM5P-Ce1dlLCM.js → vennDiagram-L72KCM5P-CBXiWPMc.js} +1 -1
  57. package/client/dist/assets/{wardleyDiagram-EHGQE667-ClOE-aae.js → wardleyDiagram-EHGQE667-uhBCZoW0.js} +1 -1
  58. package/client/dist/assets/{xychartDiagram-FW5EYKEG-Fa2pqWKw.js → xychartDiagram-FW5EYKEG-xxE_wY5O.js} +1 -1
  59. package/client/dist/index.html +2 -2
  60. package/package.json +68 -68
  61. package/server/dist/core/grade-runner.d.ts +4 -4
  62. package/server/dist/core/grade-runner.d.ts.map +1 -1
  63. package/server/dist/core/grade-runner.js +51 -26
  64. package/server/dist/core/grade-runner.js.map +1 -1
  65. package/server/dist/core/grade-target.d.ts +8 -0
  66. package/server/dist/core/grade-target.d.ts.map +1 -1
  67. package/server/dist/core/grade-target.js +10 -0
  68. package/server/dist/core/grade-target.js.map +1 -1
  69. package/server/dist/core/triage-cli-runner.d.ts.map +1 -1
  70. package/server/dist/core/triage-cli-runner.js +29 -10
  71. package/server/dist/core/triage-cli-runner.js.map +1 -1
  72. package/server/dist/core/uv-runner.d.ts +23 -0
  73. package/server/dist/core/uv-runner.d.ts.map +1 -0
  74. package/server/dist/core/uv-runner.js +39 -0
  75. package/server/dist/core/uv-runner.js.map +1 -0
  76. package/server/dist/external/file/exists-routes.d.ts +7 -0
  77. package/server/dist/external/file/exists-routes.d.ts.map +1 -0
  78. package/server/dist/external/file/exists-routes.js +91 -0
  79. package/server/dist/external/file/exists-routes.js.map +1 -0
  80. package/server/dist/external/org/audit-log.d.ts +27 -0
  81. package/server/dist/external/org/audit-log.d.ts.map +1 -0
  82. package/server/dist/external/org/audit-log.js +92 -0
  83. package/server/dist/external/org/audit-log.js.map +1 -0
  84. package/server/dist/external/org/beat-register.d.ts +15 -22
  85. package/server/dist/external/org/beat-register.d.ts.map +1 -1
  86. package/server/dist/external/org/beat-register.js +37 -32
  87. package/server/dist/external/org/beat-register.js.map +1 -1
  88. package/server/dist/external/org/file-read.d.ts +16 -0
  89. package/server/dist/external/org/file-read.d.ts.map +1 -1
  90. package/server/dist/external/org/file-read.js +86 -46
  91. package/server/dist/external/org/file-read.js.map +1 -1
  92. package/server/dist/external/org/file-write-core.d.ts +18 -0
  93. package/server/dist/external/org/file-write-core.d.ts.map +1 -0
  94. package/server/dist/external/org/file-write-core.js +97 -0
  95. package/server/dist/external/org/file-write-core.js.map +1 -0
  96. package/server/dist/external/org/file-write.d.ts +25 -0
  97. package/server/dist/external/org/file-write.d.ts.map +1 -1
  98. package/server/dist/external/org/file-write.js +82 -132
  99. package/server/dist/external/org/file-write.js.map +1 -1
  100. package/server/dist/external/org/last-run.d.ts +25 -16
  101. package/server/dist/external/org/last-run.d.ts.map +1 -1
  102. package/server/dist/external/org/last-run.js +78 -64
  103. package/server/dist/external/org/last-run.js.map +1 -1
  104. package/server/dist/external/org/lead-doc-read.d.ts +21 -0
  105. package/server/dist/external/org/lead-doc-read.d.ts.map +1 -0
  106. package/server/dist/external/org/lead-doc-read.js +84 -0
  107. package/server/dist/external/org/lead-doc-read.js.map +1 -0
  108. package/server/dist/external/org/mount.d.ts +12 -0
  109. package/server/dist/external/org/mount.d.ts.map +1 -0
  110. package/server/dist/external/org/mount.js +34 -0
  111. package/server/dist/external/org/mount.js.map +1 -0
  112. package/server/dist/external/org/org-chart-lookup.d.ts +13 -0
  113. package/server/dist/external/org/org-chart-lookup.d.ts.map +1 -1
  114. package/server/dist/external/org/org-chart-lookup.js +40 -5
  115. package/server/dist/external/org/org-chart-lookup.js.map +1 -1
  116. package/server/dist/external/org/org-chart.d.ts +21 -12
  117. package/server/dist/external/org/org-chart.d.ts.map +1 -1
  118. package/server/dist/external/org/org-chart.js +50 -32
  119. package/server/dist/external/org/org-chart.js.map +1 -1
  120. package/server/dist/external/org/role-extract.d.ts +8 -0
  121. package/server/dist/external/org/role-extract.d.ts.map +1 -0
  122. package/server/dist/external/org/role-extract.js +72 -0
  123. package/server/dist/external/org/role-extract.js.map +1 -0
  124. package/server/dist/external/org/usage.d.ts +15 -11
  125. package/server/dist/external/org/usage.d.ts.map +1 -1
  126. package/server/dist/external/org/usage.js +64 -54
  127. package/server/dist/external/org/usage.js.map +1 -1
  128. package/server/dist/external/routes.d.ts +1 -1
  129. package/server/dist/external/routes.d.ts.map +1 -1
  130. package/server/dist/external/routes.js +10 -11
  131. package/server/dist/external/routes.js.map +1 -1
  132. package/server/dist/routes/grade.d.ts.map +1 -1
  133. package/server/dist/routes/grade.js +3 -2
  134. package/server/dist/routes/grade.js.map +1 -1
  135. package/server/dist/routes/org-leads-composite.d.ts +21 -0
  136. package/server/dist/routes/org-leads-composite.d.ts.map +1 -0
  137. package/server/dist/routes/org-leads-composite.js +95 -0
  138. package/server/dist/routes/org-leads-composite.js.map +1 -0
  139. package/server/dist/routes/org.d.ts +15 -0
  140. package/server/dist/routes/org.d.ts.map +1 -0
  141. package/server/dist/routes/org.js +198 -0
  142. package/server/dist/routes/org.js.map +1 -0
  143. package/server/dist/terminal/pty-manager.d.ts +9 -0
  144. package/server/dist/terminal/pty-manager.d.ts.map +1 -1
  145. package/server/dist/terminal/pty-manager.js +15 -0
  146. package/server/dist/terminal/pty-manager.js.map +1 -1
  147. package/server/dist/terminal/replay-snapshot.d.ts +10 -1
  148. package/server/dist/terminal/replay-snapshot.d.ts.map +1 -1
  149. package/server/dist/terminal/replay-snapshot.js +36 -1
  150. package/server/dist/terminal/replay-snapshot.js.map +1 -1
  151. package/server/dist/terminal/ws-upgrade-handler.d.ts +17 -1
  152. package/server/dist/terminal/ws-upgrade-handler.d.ts.map +1 -1
  153. package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts +1 -0
  154. package/server/dist/terminal/ws-upgrade-handler.fixtures.d.ts.map +1 -1
  155. package/server/dist/terminal/ws-upgrade-handler.fixtures.js +3 -2
  156. package/server/dist/terminal/ws-upgrade-handler.fixtures.js.map +1 -1
  157. package/server/dist/terminal/ws-upgrade-handler.js +45 -4
  158. package/server/dist/terminal/ws-upgrade-handler.js.map +1 -1
  159. package/server/dist/test/python-spawn-guard-util.d.ts +14 -0
  160. package/server/dist/test/python-spawn-guard-util.d.ts.map +1 -0
  161. package/server/dist/test/python-spawn-guard-util.js +124 -0
  162. package/server/dist/test/python-spawn-guard-util.js.map +1 -0
  163. package/server/dist/types/org.d.ts +115 -0
  164. package/server/dist/types/org.d.ts.map +1 -0
  165. package/server/dist/types/org.js +16 -0
  166. package/server/dist/types/org.js.map +1 -0
  167. package/server/package.json +1 -1
  168. package/client/dist/assets/MarkdownEditorModal-CP5yG9OU.js +0 -212
  169. package/client/dist/assets/channel-BNXbCvDS.js +0 -1
  170. package/client/dist/assets/classDiagram-OUVF2IWQ-w-wCtLx3.js +0 -1
  171. package/client/dist/assets/classDiagram-v2-EOCWNBFH-w-wCtLx3.js +0 -1
  172. package/client/dist/assets/index-CU2QJgvx.js +0 -609
  173. package/client/dist/assets/index-ftvVcUT8.css +0 -1
  174. package/client/dist/assets/stateDiagram-v2-6OUMAXLB-DvwiHlJv.js +0 -1
  175. package/client/dist/assets/swimlanesDiagram-G3AALYLV-JTQZTlZ3.js +0 -8
@@ -10,5 +10,30 @@ export interface OrgFileWriteDeps extends DecisionsLockDeps {
10
10
  /** Injectable for tests; production wires the real `withDecisionsLock`. */
11
11
  withDecisionsLock?: typeof withDecisionsLock;
12
12
  }
13
+ export type OrgFileWriteCoreResult = {
14
+ status: 200;
15
+ body: {
16
+ written: true;
17
+ fingerprint: string;
18
+ size: number;
19
+ };
20
+ } | {
21
+ status: 400 | 403 | 404 | 409 | 413 | 500;
22
+ body: Record<string, unknown>;
23
+ };
24
+ export interface OrgFileWriteParams {
25
+ relpath: string | undefined;
26
+ contentLengthHeader: string | undefined;
27
+ body: string;
28
+ ifMatch: string | undefined;
29
+ }
30
+ /**
31
+ * Pure core — shared by the secret-gated route and the plain-surface proxy.
32
+ * Kind restriction (e.g. "only `charter` may pass through the browser-facing
33
+ * proxy") is the CALLER's job, applied against `resolveOrgAllowlistedTarget`'s
34
+ * `kind` before or after invoking this — this core stays as general as the
35
+ * existing route (all six allowlisted kinds).
36
+ */
37
+ export declare function orgFileWriteCore(deps: OrgFileWriteDeps, params: OrgFileWriteParams): Promise<OrgFileWriteCoreResult>;
13
38
  export declare function registerOrgFileWrite(app: Hono, deps: OrgFileWriteDeps): void;
14
39
  //# sourceMappingURL=file-write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-write.d.ts","sourceRoot":"","sources":["../../../src/external/org/file-write.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAiBjC,OAAO,EACL,iBAAiB,EAEjB,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,QAAkB,CAAC;AAWnD,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,cAAc,IAAI,OAAO,CAAC;QAAC,MAAM,IAAI,OAAO,CAAA;KAAE,CAAC;IAC/E,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;CAC9C;AA2FD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAiF5E"}
1
+ {"version":3,"file":"file-write.d.ts","sourceRoot":"","sources":["../../../src/external/org/file-write.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAOjC,OAAO,EACL,iBAAiB,EAEjB,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAG7B,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,QAAkB,CAAC;AAOnD,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,cAAc,IAAI,OAAO,CAAC;QAAC,MAAM,IAAI,OAAO,CAAA;KAAE,CAAC;IAC/E,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAC;CAC9C;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC3E;IAAE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEjF,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,sBAAsB,CAAC,CA6EjC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAyB5E"}
@@ -42,164 +42,114 @@
42
42
  * 413 body over ORG_WRITE_MAX_BYTES
43
43
  * 500 stat / read / write failure
44
44
  */
45
- import { readFileSync, writeFileSync, renameSync, unlinkSync, existsSync, lstatSync, } from "node:fs";
46
- import { dirname, join } from "node:path";
47
- import { realPathGuard } from "../../core/path-guard.js";
45
+ import { lstatSync } from "node:fs";
48
46
  import { resolveOrgAllowlistedTarget, } from "./_helpers.js";
49
- import { fileFingerprint, unquoteEtag } from "../file/_helpers.js";
50
47
  import { withDecisionsLock, OrgSymlinkEscapeError, } from "./decisions-lock.js";
48
+ import { performWrite } from "./file-write-core.js";
51
49
  /** 2 MiB — org docs are small prose files, same cap as the project markdown write. */
52
50
  export const ORG_WRITE_MAX_BYTES = 2 * 1024 * 1024;
53
51
  const LOCKED_KINDS = new Set([
54
52
  "decision_log",
55
53
  "decisions_proposed",
56
54
  ]);
57
- function performWrite(absoluteTarget, leadsRoot, relpath, body, ifMatch, lstat) {
58
- let lst;
59
- try {
60
- lst = lstat(absoluteTarget);
61
- }
62
- catch (err) {
63
- const code = err?.code;
64
- if (code === "ENOENT") {
65
- return { ok: false, status: 404, body: { error: "not_found", path: relpath } };
66
- }
67
- return {
68
- ok: false,
69
- status: 500,
70
- body: { error: "file_stat_failed", detail: String(err).slice(0, 200) },
71
- };
72
- }
73
- if (lst.isSymbolicLink()) {
74
- return { ok: false, status: 403, body: { error: "symlink_forbidden", path: relpath } };
75
- }
76
- if (!lst.isFile()) {
77
- return { ok: false, status: 400, body: { error: "not_a_file", path: relpath } };
78
- }
79
- const realGuard = realPathGuard(leadsRoot, absoluteTarget);
80
- if (!realGuard.ok) {
81
- return {
82
- ok: false,
83
- status: 400,
84
- body: { error: "path_traversal", detail: realGuard.reason },
85
- };
86
- }
87
- if (!ifMatch) {
88
- return { ok: false, status: 400, body: { error: "precondition_required" } };
55
+ /**
56
+ * Pure core — shared by the secret-gated route and the plain-surface proxy.
57
+ * Kind restriction (e.g. "only `charter` may pass through the browser-facing
58
+ * proxy") is the CALLER's job, applied against `resolveOrgAllowlistedTarget`'s
59
+ * `kind` before or after invoking this — this core stays as general as the
60
+ * existing route (all six allowlisted kinds).
61
+ */
62
+ export async function orgFileWriteCore(deps, params) {
63
+ const { leadsRoot } = deps;
64
+ const lstat = deps.lstatSync ?? ((p) => lstatSync(p));
65
+ const lockFn = deps.withDecisionsLock ?? withDecisionsLock;
66
+ const { relpath, contentLengthHeader, body, ifMatch } = params;
67
+ if (!relpath || relpath.length === 0) {
68
+ return { status: 400, body: { error: "path_required" } };
89
69
  }
90
- let current;
91
- try {
92
- current = readFileSync(absoluteTarget);
70
+ const target = resolveOrgAllowlistedTarget(leadsRoot, relpath);
71
+ if (!target.ok) {
72
+ const status = target.reason === "not_allowlisted" ? 403 : 400;
73
+ const err = target.reason === "traversal" ? "path_traversal" : target.reason;
74
+ return { status, body: { error: err, detail: target.reason } };
93
75
  }
94
- catch (err) {
95
- const code = err?.code;
96
- if (code === "ENOENT") {
97
- return { ok: false, status: 404, body: { error: "not_found", path: relpath } };
98
- }
76
+ const declaredLength = Number(contentLengthHeader ?? "");
77
+ if (Number.isFinite(declaredLength) && declaredLength > ORG_WRITE_MAX_BYTES) {
99
78
  return {
100
- ok: false,
101
- status: 500,
102
- body: { error: "file_read_failed", detail: String(err).slice(0, 200) },
79
+ status: 413,
80
+ body: { error: "payload_too_large", maxBytes: ORG_WRITE_MAX_BYTES, size: declaredLength },
103
81
  };
104
82
  }
105
- const currentFingerprint = fileFingerprint(current);
106
- if (unquoteEtag(ifMatch) !== currentFingerprint) {
83
+ const byteLen = Buffer.byteLength(body, "utf8");
84
+ if (byteLen > ORG_WRITE_MAX_BYTES) {
107
85
  return {
108
- ok: false,
109
- status: 409,
110
- body: { error: "fingerprint_mismatch", currentFingerprint },
86
+ status: 413,
87
+ body: { error: "payload_too_large", maxBytes: ORG_WRITE_MAX_BYTES, size: byteLen },
111
88
  };
112
89
  }
113
- const nextBuf = Buffer.from(body, "utf8");
114
- const tmp = join(dirname(absoluteTarget), `.org-write.tmp-${process.pid}-${Date.now()}`);
115
- try {
116
- writeFileSync(tmp, nextBuf);
117
- renameSync(tmp, absoluteTarget);
118
- }
119
- catch (err) {
90
+ let outcome;
91
+ if (LOCKED_KINDS.has(target.kind)) {
92
+ // Pre-lock existence probe (external-review fix) — must run BEFORE
93
+ // withDecisionsLock, since its own ensureFile() would otherwise
94
+ // auto-vivify decisions-proposed.md first and hide a genuinely
95
+ // missing target from performWrite's existence check.
120
96
  try {
121
- if (existsSync(tmp))
122
- unlinkSync(tmp);
97
+ lstat(target.absolute);
123
98
  }
124
- catch {
125
- /* swallow */
99
+ catch (err) {
100
+ const code = err?.code;
101
+ if (code === "ENOENT") {
102
+ return { status: 404, body: { error: "not_found", path: relpath } };
103
+ }
104
+ return {
105
+ status: 500,
106
+ body: { error: "file_stat_failed", detail: String(err).slice(0, 200) },
107
+ };
108
+ }
109
+ try {
110
+ outcome = await lockFn({ leadsRoot, lstatSync: deps.lstatSync }, () => performWrite(target.absolute, leadsRoot, relpath, body, ifMatch, lstat));
111
+ }
112
+ catch (err) {
113
+ // Doubt-review fix: `withDecisionsLock` symlink-checks BOTH
114
+ // decision_log.md and decisions-proposed.md (whichever one this PUT
115
+ // targets, the OTHER is still checked because it shares the lock) —
116
+ // uncaught, that 403-shaped condition fell through to the generic
117
+ // 500 handler instead of the family's typed symlink_forbidden.
118
+ // ELOCKED is deliberately NOT caught here: it propagates to the
119
+ // caller (either the app-level errorHandler for the gated route, or
120
+ // the new router's own catch, both of which map it to the same
121
+ // retryable 409 every other multi-writer state file uses (CLAUDE.md
122
+ // DO-NOT #6)).
123
+ if (err instanceof OrgSymlinkEscapeError) {
124
+ return { status: 403, body: { error: "symlink_forbidden", path: err.path } };
125
+ }
126
+ throw err;
126
127
  }
127
- return {
128
- ok: false,
129
- status: 500,
130
- body: { error: "write_failed", detail: String(err).slice(0, 200), path: relpath },
131
- };
132
128
  }
133
- return {
134
- ok: true,
135
- status: 200,
136
- body: { written: true, fingerprint: fileFingerprint(nextBuf), size: nextBuf.length },
137
- };
129
+ else {
130
+ outcome = performWrite(target.absolute, leadsRoot, relpath, body, ifMatch, lstat);
131
+ }
132
+ return { status: outcome.status, body: outcome.body };
138
133
  }
139
134
  export function registerOrgFileWrite(app, deps) {
140
- const { leadsRoot } = deps;
141
- const lstat = deps.lstatSync ?? ((p) => lstatSync(p));
142
- const lockFn = deps.withDecisionsLock ?? withDecisionsLock;
143
135
  app.put("/api/external/org/file", async (c) => {
144
136
  const relpath = c.req.query("path");
145
- if (!relpath || relpath.length === 0) {
146
- return c.json({ error: "path_required" }, 400);
147
- }
148
- const target = resolveOrgAllowlistedTarget(leadsRoot, relpath);
149
- if (!target.ok) {
150
- const status = target.reason === "not_allowlisted" ? 403 : 400;
151
- const err = target.reason === "traversal" ? "path_traversal" : target.reason;
152
- return c.json({ error: err, detail: target.reason }, status);
153
- }
154
- const declaredLength = Number(c.req.header("content-length") ?? "");
155
- if (Number.isFinite(declaredLength) && declaredLength > ORG_WRITE_MAX_BYTES) {
137
+ const contentLengthHeader = c.req.header("content-length");
138
+ // Bail before reading the request body when the declared Content-Length
139
+ // alone already exceeds the cap — preserved from the pre-extraction
140
+ // handler so an oversized upload is never buffered into memory just to
141
+ // be rejected.
142
+ const declaredLength = Number(contentLengthHeader ?? "");
143
+ if (relpath && Number.isFinite(declaredLength) && declaredLength > ORG_WRITE_MAX_BYTES) {
156
144
  return c.json({ error: "payload_too_large", maxBytes: ORG_WRITE_MAX_BYTES, size: declaredLength }, 413);
157
145
  }
158
- const body = await c.req.text();
159
- const byteLen = Buffer.byteLength(body, "utf8");
160
- if (byteLen > ORG_WRITE_MAX_BYTES) {
161
- return c.json({ error: "payload_too_large", maxBytes: ORG_WRITE_MAX_BYTES, size: byteLen }, 413);
162
- }
163
- const ifMatch = c.req.header("if-match");
164
- let outcome;
165
- if (LOCKED_KINDS.has(target.kind)) {
166
- // Pre-lock existence probe (external-review fix) — must run BEFORE
167
- // withDecisionsLock, since its own ensureFile() would otherwise
168
- // auto-vivify decisions-proposed.md first and hide a genuinely
169
- // missing target from performWrite's existence check.
170
- try {
171
- lstat(target.absolute);
172
- }
173
- catch (err) {
174
- const code = err?.code;
175
- if (code === "ENOENT") {
176
- return c.json({ error: "not_found", path: relpath }, 404);
177
- }
178
- return c.json({ error: "file_stat_failed", detail: String(err).slice(0, 200) }, 500);
179
- }
180
- try {
181
- outcome = await lockFn({ leadsRoot, lstatSync: deps.lstatSync }, () => performWrite(target.absolute, leadsRoot, relpath, body, ifMatch, lstat));
182
- }
183
- catch (err) {
184
- // Doubt-review fix: `withDecisionsLock` symlink-checks BOTH
185
- // decision_log.md and decisions-proposed.md (whichever one this PUT
186
- // targets, the OTHER is still checked because it shares the lock) —
187
- // uncaught, that 403-shaped condition fell through to the generic
188
- // 500 handler instead of the family's typed symlink_forbidden.
189
- // ELOCKED is deliberately NOT caught here: it propagates to the
190
- // app-level errorHandler (middleware/error-handler.ts), which already
191
- // maps it to the same retryable 409 every other multi-writer state
192
- // file uses (CLAUDE.md DO-NOT #6).
193
- if (err instanceof OrgSymlinkEscapeError) {
194
- return c.json({ error: "symlink_forbidden", path: err.path }, 403);
195
- }
196
- throw err;
197
- }
198
- }
199
- else {
200
- outcome = performWrite(target.absolute, leadsRoot, relpath, body, ifMatch, lstat);
201
- }
202
- return c.json(outcome.body, outcome.status);
146
+ const result = await orgFileWriteCore(deps, {
147
+ relpath,
148
+ contentLengthHeader,
149
+ body: await c.req.text(),
150
+ ifMatch: c.req.header("if-match"),
151
+ });
152
+ return c.json(result.body, result.status);
203
153
  });
204
154
  }
205
155
  //# sourceMappingURL=file-write.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-write.js","sourceRoot":"","sources":["../../../src/external/org/file-write.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-write.js","sourceRoot":"","sources":["../../../src/external/org/file-write.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,7 @@
1
1
  import type { Hono } from "hono";
2
- import { type LeadOrgInfoReason } from "./org-chart-lookup.js";
3
- import { type Staleness } from "./cron.js";
4
- export type CadenceUnresolvedReason = LeadOrgInfoReason | "invalid_cron";
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;AAChF,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAE9E,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG,cAAc,CAAC;AAEzE,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAA;CAAE,GACnC;IACE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD,CAAC;AAcN,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;CAClB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CA0G5E"}
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
- export function registerLastRunRoute(app, deps) {
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
- app.get("/api/external/org/leads/:leadId/last-run", async (c) => {
48
- const leadId = c.req.param("leadId");
49
- if (!LEAD_ID_RE.test(leadId)) {
50
- return c.json({ error: "invalid_lead_id", leadId }, 400);
51
- }
52
- const absolute = path.join(leadsRoot, leadId, "last-run.json");
53
- let lst;
54
- try {
55
- lst = lstat(absolute);
56
- }
57
- catch (err) {
58
- const code = err?.code;
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
- if (!isValidLastRunPayload(parsed)) {
92
- return c.json({ error: "last_run_invalid", leadId }, 502);
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
- const { lastRunAt, sessionId } = parsed;
95
- const nowValue = now();
96
- const orgInfo = readLeadOrgInfo(leadsRoot, leadId);
97
- if (!orgInfo.ok) {
98
- const body = {
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
- return c.json(body, 200);
109
- }
110
- const interval = cronIntervalMs(orgInfo.cron, nowValue);
111
- if (!interval.ok) {
112
- const body = {
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
- return c.json(body, 200);
123
- }
124
- const evaluation = evaluateStaleness(lastRunAt, interval.ms, nowValue);
125
- const body = {
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
- return c.json(body, 200);
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":"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"}
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"}