@rubytech/create-sitedesk-code 0.1.429 → 0.1.431

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 (144) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +69 -3
  3. package/payload/platform/plugins/docs/PLUGIN.md +1 -0
  4. package/payload/platform/plugins/docs/references/internals.md +2 -2
  5. package/payload/platform/plugins/docs/references/workflows.md +61 -0
  6. package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.d.ts +8 -1
  7. package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.d.ts.map +1 -1
  8. package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.js +8 -1
  9. package/payload/platform/plugins/whatsapp/mcp/dist/resolve-read-account.js.map +1 -1
  10. package/payload/platform/plugins/workflows/PLUGIN.md +29 -9
  11. package/payload/platform/plugins/workflows/mcp/dist/index.js +34 -0
  12. package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
  13. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +2 -2
  14. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -1
  15. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -1
  16. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +25 -0
  17. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -1
  18. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +14 -1
  19. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
  20. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +25 -1
  21. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -1
  22. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +79 -15
  23. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
  24. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +2 -0
  25. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -1
  26. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +4 -0
  27. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -1
  28. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts +3 -1
  29. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -1
  30. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +8 -1
  31. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -1
  32. package/payload/platform/plugins/workflows/skills/workflow-manager/SKILL.md +24 -3
  33. package/payload/platform/services/telegram-channel/dist/instructions.js +1 -1
  34. package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
  35. package/payload/platform/services/telegram-channel/dist/notification.d.ts +10 -5
  36. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  37. package/payload/platform/services/telegram-channel/dist/notification.js +9 -6
  38. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  39. package/payload/platform/services/telegram-channel/dist/server.d.ts.map +1 -1
  40. package/payload/platform/services/telegram-channel/dist/server.js +15 -5
  41. package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
  42. package/payload/platform/services/webchat-channel/dist/instructions.js +1 -1
  43. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
  44. package/payload/platform/services/webchat-channel/dist/notification.d.ts +12 -10
  45. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
  46. package/payload/platform/services/webchat-channel/dist/notification.js +12 -11
  47. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
  48. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  49. package/payload/platform/services/webchat-channel/dist/server.js +12 -1
  50. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  51. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +11 -6
  52. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  53. package/payload/platform/services/whatsapp-channel/dist/notification.js +11 -8
  54. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  55. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
  56. package/payload/platform/services/whatsapp-channel/dist/server.js +39 -14
  57. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  58. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +17 -2
  59. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
  60. package/payload/platform/services/whatsapp-channel/dist/targets.js +37 -2
  61. package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
  62. package/payload/premium-plugins/sitedesk/lib/mcp-lifeline/dist/index.d.ts +8 -0
  63. package/payload/premium-plugins/sitedesk/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
  64. package/payload/premium-plugins/sitedesk/lib/mcp-lifeline/dist/index.js +71 -0
  65. package/payload/premium-plugins/sitedesk/lib/mcp-lifeline/dist/index.js.map +1 -0
  66. package/payload/premium-plugins/sitedesk/lib/mcp-lifeline/package.json +7 -0
  67. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/PLUGIN.md +39 -3
  68. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/index.d.ts +2 -0
  69. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/index.d.ts.map +1 -0
  70. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/index.js +32 -0
  71. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/index.js.map +1 -0
  72. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/account.d.ts +10 -0
  73. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/account.d.ts.map +1 -0
  74. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/account.js +21 -0
  75. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/account.js.map +1 -0
  76. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/engine-run.d.ts +24 -0
  77. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/engine-run.d.ts.map +1 -0
  78. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/engine-run.js +59 -0
  79. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/engine-run.js.map +1 -0
  80. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.d.ts +22 -0
  81. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.d.ts.map +1 -0
  82. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.js +40 -0
  83. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/gates.js.map +1 -0
  84. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/geometry.d.ts +47 -0
  85. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/geometry.d.ts.map +1 -0
  86. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/geometry.js +60 -0
  87. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/geometry.js.map +1 -0
  88. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/log.d.ts +7 -0
  89. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/log.d.ts.map +1 -0
  90. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/log.js +9 -0
  91. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/log.js.map +1 -0
  92. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.d.ts +29 -0
  93. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.d.ts.map +1 -0
  94. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.js +113 -0
  95. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.js.map +1 -0
  96. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-engine-run.d.ts +3 -0
  97. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-engine-run.d.ts.map +1 -0
  98. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-engine-run.js +48 -0
  99. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-engine-run.js.map +1 -0
  100. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-render.d.ts +3 -0
  101. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-render.d.ts.map +1 -0
  102. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-render.js +50 -0
  103. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-render.js.map +1 -0
  104. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/takeoff-compute.d.ts +3 -0
  105. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/takeoff-compute.d.ts.map +1 -0
  106. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/takeoff-compute.js +42 -0
  107. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/takeoff-compute.js.map +1 -0
  108. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/package-lock.json +2684 -0
  109. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/package.json +21 -0
  110. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/index.ts +39 -0
  111. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/account.test.ts +49 -0
  112. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/engine-run.test.ts +105 -0
  113. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/gates.test.ts +51 -0
  114. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/geometry.test.ts +83 -0
  115. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/render-run.test.ts +111 -0
  116. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/account.ts +20 -0
  117. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/engine-run.ts +80 -0
  118. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/gates.ts +39 -0
  119. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/geometry.ts +93 -0
  120. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/log.ts +8 -0
  121. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/render-run.ts +125 -0
  122. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/tools/quote-engine-run.ts +66 -0
  123. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/tools/quote-render.ts +66 -0
  124. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/tools/takeoff-compute.ts +51 -0
  125. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/tsconfig.json +20 -0
  126. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quote-engine.md +24 -0
  127. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quote-generation.md +67 -51
  128. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/takeoff/SKILL.md +12 -0
  129. package/payload/server/public/assets/{AdminLoginScreens-C4AZT7cQ.js → AdminLoginScreens-CcW3pAAZ.js} +1 -1
  130. package/payload/server/public/assets/{admin-SaF1F4e-.js → admin-Co3hOTNp.js} +1 -1
  131. package/payload/server/public/assets/{audio-attachment-mime-BBW07eyG.js → audio-attachment-mime-CwYrV1pg.js} +1 -1
  132. package/payload/server/public/assets/{chat-B9Qjt7C9.js → chat-rxbGimwf.js} +1 -1
  133. package/payload/server/public/assets/data-D0YFYP1i.js +1 -0
  134. package/payload/server/public/assets/{operator-CTJjI8te.js → operator-Djv3MdcL.js} +1 -1
  135. package/payload/server/public/assets/{page-JzxyFGle.js → page-Ci27UrJz.js} +5 -5
  136. package/payload/server/public/assets/{page-CbI1wtef.js → page-D1EAVC_9.js} +1 -1
  137. package/payload/server/public/assets/{public-DzeW3_eM.js → public-C6k-fPfx.js} +1 -1
  138. package/payload/server/public/chat.html +3 -3
  139. package/payload/server/public/data.html +3 -3
  140. package/payload/server/public/index.html +4 -4
  141. package/payload/server/public/operator.html +4 -4
  142. package/payload/server/public/public.html +3 -3
  143. package/payload/server/server.js +95 -25
  144. package/payload/server/public/assets/data-BKE6Sa-g.js +0 -1
@@ -0,0 +1,40 @@
1
+ // The three deterministic, fail-closed gates quote-render enforces on the HTML
2
+ // the operator's render script emits. They are structural checks over stable
3
+ // attributes the render script marks — not business content:
4
+ // data-quote-total the displayed grand total (reconcile against the engine)
5
+ // data-internal-only cost/margin-bearing figures (must be absent from client docs)
6
+ // data-esign-accept the client quote's Sign-Online anchor (absolute https only)
7
+ /** The document's displayed grand total (data-quote-total) must equal the
8
+ * engine total. No marker → fail closed (an unverifiable total is not shipped). */
9
+ export function gateReconcile(html, engineTotal) {
10
+ const m = html.match(/data-quote-total="([^"]*)"/i);
11
+ if (!m || m[1].trim() === "")
12
+ return { pass: false };
13
+ const shown = Number(m[1]);
14
+ if (!Number.isFinite(shown))
15
+ return { pass: false };
16
+ return { pass: shown === engineTotal, shown };
17
+ }
18
+ /** A client document carrying a cost/margin marker (data-internal-only) is a
19
+ * leak — the boundary is structural, not a matter of remembering to omit. */
20
+ export function gateMarginLeak(html) {
21
+ return { pass: !/\bdata-internal-only\b/i.test(html) };
22
+ }
23
+ /** The client quote's Sign-Online anchor href must be an absolute https URL —
24
+ * the same verdict ladder the quote-generation link-liveness gate applies. */
25
+ export function gateSignLink(html) {
26
+ const tag = html.match(/<a[^>]*\bdata-esign-accept\b[^>]*>/i)?.[0];
27
+ if (!tag)
28
+ return { pass: false, reason: "no-anchor" };
29
+ const href = tag.match(/href="([^"]*)"/i)?.[1] ?? "";
30
+ if (/^https:\/\//i.test(href))
31
+ return { pass: true, href };
32
+ if (href === "")
33
+ return { pass: false, href, reason: "empty" };
34
+ if (href.startsWith("#"))
35
+ return { pass: false, href, reason: "fragment" };
36
+ if (/^[a-z][a-z0-9+.-]*:/i.test(href))
37
+ return { pass: false, href, reason: "non-https" };
38
+ return { pass: false, href, reason: "relative" };
39
+ }
40
+ //# sourceMappingURL=gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/lib/gates.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,6DAA6D;AAC7D,gFAAgF;AAChF,qFAAqF;AACrF,mFAAmF;AAMnF;oFACoF;AACpF,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,WAAmB;IAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACpD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACpD,OAAO,EAAE,IAAI,EAAE,KAAK,KAAK,WAAW,EAAE,KAAK,EAAE,CAAC;AAChD,CAAC;AAED;8EAC8E;AAC9E,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,EAAE,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;+EAC+E;AAC/E,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnE,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IACtD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3D,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC/D,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC3E,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IACzF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACnD,CAAC"}
@@ -0,0 +1,47 @@
1
+ export type Basis = "printed" | "scaled" | "count" | "operator";
2
+ /** A drawing scale: a stated ratio (1:R → R), or a known-dimension calibration
3
+ * where `actual/measuredRef` is the factor. */
4
+ export type Scale = {
5
+ ratio: number;
6
+ } | {
7
+ measuredRef: number;
8
+ actual: number;
9
+ };
10
+ export interface InLine {
11
+ element: string;
12
+ basis: Basis;
13
+ value?: number;
14
+ unit?: string;
15
+ measured?: number;
16
+ measuredB?: number;
17
+ kind?: "length" | "area";
18
+ count?: number | number[];
19
+ crossCheck?: {
20
+ value: number;
21
+ unit?: string;
22
+ tolerance?: number;
23
+ };
24
+ }
25
+ export interface OutLine {
26
+ element: string;
27
+ quantity: number;
28
+ unit?: string;
29
+ basis: Basis;
30
+ crossCheck?: {
31
+ printed: number;
32
+ delta: number;
33
+ disagree: boolean;
34
+ };
35
+ }
36
+ export interface TakeoffResult {
37
+ lines: OutLine[];
38
+ counts: {
39
+ exact: number;
40
+ scaled: number;
41
+ };
42
+ }
43
+ export declare function computeTakeoff(input: {
44
+ scale?: Scale;
45
+ lines: InLine[];
46
+ }): TakeoffResult;
47
+ //# sourceMappingURL=geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/lib/geometry.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAEhE;gDACgD;AAChD,MAAM,MAAM,KAAK,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;CACpE;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AA0CD,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,aAAa,CAevF"}
@@ -0,0 +1,60 @@
1
+ // Deterministic takeoff geometry. Pure arithmetic over agent-supplied measured
2
+ // inputs — scale to a real dimension, a scaled area from two sides, and a count
3
+ // roll-up — plus a cross-check of a scaled quantity against a printed figure.
4
+ // Reading the drawing and eliciting the inputs is the takeoff skill's job, not
5
+ // this module's. No business content: it multiplies numbers, it prices nothing.
6
+ function scaleFactor(scale, element) {
7
+ if (!scale)
8
+ throw new Error(`takeoff: line "${element}" is scale-derived but no scale was supplied`);
9
+ const factor = "ratio" in scale ? scale.ratio : scale.actual / scale.measuredRef;
10
+ if (!Number.isFinite(factor)) {
11
+ throw new Error(`takeoff: line "${element}" has a degenerate scale (factor=${factor})`);
12
+ }
13
+ return factor;
14
+ }
15
+ function quantityFor(line, scale) {
16
+ switch (line.basis) {
17
+ case "printed":
18
+ case "operator": {
19
+ if (typeof line.value !== "number") {
20
+ throw new Error(`takeoff: line "${line.element}" (${line.basis}) is missing its value`);
21
+ }
22
+ return line.value;
23
+ }
24
+ case "count": {
25
+ if (line.count === undefined) {
26
+ throw new Error(`takeoff: line "${line.element}" (count) is missing its count`);
27
+ }
28
+ return Array.isArray(line.count) ? line.count.reduce((a, b) => a + b, 0) : line.count;
29
+ }
30
+ case "scaled": {
31
+ if (typeof line.measured !== "number") {
32
+ throw new Error(`takeoff: line "${line.element}" (scaled) is missing its measured length`);
33
+ }
34
+ const factor = scaleFactor(scale, line.element);
35
+ if (line.kind === "area") {
36
+ if (typeof line.measuredB !== "number") {
37
+ throw new Error(`takeoff: line "${line.element}" (scaled area) is missing its second side`);
38
+ }
39
+ return line.measured * line.measuredB * factor * factor;
40
+ }
41
+ return line.measured * factor;
42
+ }
43
+ }
44
+ }
45
+ export function computeTakeoff(input) {
46
+ const lines = input.lines.map((line) => {
47
+ const quantity = quantityFor(line, input.scale);
48
+ const out = { element: line.element, quantity, unit: line.unit, basis: line.basis };
49
+ if (line.basis === "scaled" && line.crossCheck) {
50
+ const printed = line.crossCheck.value;
51
+ const delta = quantity - printed;
52
+ const tolerance = line.crossCheck.tolerance ?? 0;
53
+ out.crossCheck = { printed, delta, disagree: Math.abs(delta) > tolerance };
54
+ }
55
+ return out;
56
+ });
57
+ const scaled = lines.filter((l) => l.basis === "scaled").length;
58
+ return { lines, counts: { exact: lines.length - scaled, scaled } };
59
+ }
60
+ //# sourceMappingURL=geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../src/lib/geometry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Emit one structured observability line to stderr. Every tool invocation logs
3
+ * one line here, correlated by `jobId`; journald captures stderr, so the
4
+ * diagnostic path is `journalctl --user | grep -E '\\[quote-engine\\]|...'`.
5
+ */
6
+ export declare function logLine(s: string): void;
7
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/lib/log.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAEvC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Emit one structured observability line to stderr. Every tool invocation logs
3
+ * one line here, correlated by `jobId`; journald captures stderr, so the
4
+ * diagnostic path is `journalctl --user | grep -E '\\[quote-engine\\]|...'`.
5
+ */
6
+ export function logLine(s) {
7
+ process.stderr.write(s + "\n");
8
+ }
9
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/lib/log.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { type SignLinkVerdict } from "./gates.js";
2
+ export type RenderFault = "render-absent" | "render-error" | "reconcile-fail" | "margin-leak" | "sign-link";
3
+ export interface RunRenderArgs {
4
+ accountDir: string;
5
+ renderScriptPath: string;
6
+ figures: Record<string, unknown>;
7
+ signUrl?: string;
8
+ jobId: string;
9
+ }
10
+ export type RenderResult = {
11
+ ok: true;
12
+ docs: {
13
+ internal: string;
14
+ breakdown: string;
15
+ quote: string;
16
+ };
17
+ reconcile: {
18
+ internal: boolean;
19
+ breakdown: boolean;
20
+ quote: boolean;
21
+ };
22
+ signLink: SignLinkVerdict;
23
+ } | {
24
+ ok: false;
25
+ reason: RenderFault;
26
+ detail: string;
27
+ };
28
+ export declare function runRender(a: RunRenderArgs): Promise<RenderResult>;
29
+ //# sourceMappingURL=render-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-run.d.ts","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"AAYA,OAAO,EAA+C,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/F,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,cAAc,GAAG,gBAAgB,GAAG,aAAa,GAAG,WAAW,CAAC;AAE5G,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GACpB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,SAAS,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IACrE,QAAQ,EAAE,eAAe,CAAC;CAC3B,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAIvD,wBAAsB,SAAS,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAyFvE"}
@@ -0,0 +1,113 @@
1
+ // Execute the operator's persisted render script (quoting/render.mjs) to turn
2
+ // figures into the three reconciling HTML documents, then enforce the three
3
+ // deterministic gates and file each doc by its scope. The render script owns
4
+ // brand/layout as its own data; this module templates nothing. HTML only — the
5
+ // PDF is produced downstream by the browser plugin's browser-pdf-save.
6
+ //
7
+ // Fail-closed and atomic: if any gate fails, no document is filed and a
8
+ // cause-naming fault is returned. "Fail loudly and stop", never a partial issue.
9
+ import { spawn } from "node:child_process";
10
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { gateReconcile, gateMarginLeak, gateSignLink } from "./gates.js";
13
+ export async function runRender(a) {
14
+ if (!existsSync(a.renderScriptPath)) {
15
+ return { ok: false, reason: "render-absent", detail: `no render script at ${a.renderScriptPath}` };
16
+ }
17
+ const payload = JSON.stringify({ figures: a.figures, signUrl: a.signUrl ?? null });
18
+ const { code, stdout, stderr } = await new Promise((resolve) => {
19
+ const child = spawn("node", [a.renderScriptPath], { cwd: a.accountDir });
20
+ let out = "";
21
+ let err = "";
22
+ child.stdout.on("data", (d) => (out += d));
23
+ child.stderr.on("data", (d) => (err += d));
24
+ child.on("error", (e) => resolve({ code: -1, stdout: out, stderr: String(e) }));
25
+ child.on("close", (c) => resolve({ code: c, stdout: out, stderr: err }));
26
+ // A script that exits before draining stdin closes the read end mid-write,
27
+ // raising EPIPE. Swallow it: the exit code from `close` carries the fault, so
28
+ // an early exit surfaces as render-error rather than crashing the server.
29
+ child.stdin.on("error", () => { });
30
+ child.stdin.write(payload);
31
+ child.stdin.end();
32
+ });
33
+ if (code !== 0) {
34
+ return { ok: false, reason: "render-error", detail: `render script exited ${code}: ${stderr.trim().slice(0, 400)}` };
35
+ }
36
+ let html;
37
+ try {
38
+ const parsed = JSON.parse(stdout);
39
+ if (typeof parsed.internal !== "string" || typeof parsed.breakdown !== "string" || typeof parsed.quote !== "string") {
40
+ return { ok: false, reason: "render-error", detail: "render output must be { internal, breakdown, quote } HTML strings" };
41
+ }
42
+ html = parsed;
43
+ }
44
+ catch {
45
+ return { ok: false, reason: "render-error", detail: `render stdout was not JSON: ${stdout.trim().slice(0, 200)}` };
46
+ }
47
+ const engineTotal = Number(a.figures.total);
48
+ const phone = a.figures.header?.phone;
49
+ if (!phone) {
50
+ return { ok: false, reason: "render-error", detail: "figures.header.phone is required to file the documents by scope" };
51
+ }
52
+ // The phone is a filing-path segment; reject a separator or traversal so a
53
+ // crafted header cannot escape the customer scope, the same guard account.ts
54
+ // applies to ACCOUNT_ID.
55
+ if (phone.includes("/") || phone.includes("..")) {
56
+ return { ok: false, reason: "render-error", detail: `figures.header.phone contains a path separator or traversal: ${phone}` };
57
+ }
58
+ // Gate every document before filing any, so the log reports each doc's verdict
59
+ // and nothing is written when one fails.
60
+ const recInternal = gateReconcile(html.internal, engineTotal);
61
+ const recBreakdown = gateReconcile(html.breakdown, engineTotal);
62
+ const recQuote = gateReconcile(html.quote, engineTotal);
63
+ const leakBreakdown = gateMarginLeak(html.breakdown);
64
+ const leakQuote = gateMarginLeak(html.quote);
65
+ const signLink = gateSignLink(html.quote);
66
+ const internalOk = recInternal.pass;
67
+ const breakdownOk = recBreakdown.pass && leakBreakdown.pass;
68
+ const quoteOk = recQuote.pass && leakQuote.pass && signLink.pass;
69
+ if (!internalOk || !breakdownOk || !quoteOk) {
70
+ // Reason names the first failing gate, in document then gate order.
71
+ let reason;
72
+ let detail;
73
+ if (!recInternal.pass) {
74
+ reason = "reconcile-fail";
75
+ detail = `internal total ${recInternal.shown} != engine ${engineTotal}`;
76
+ }
77
+ else if (!recBreakdown.pass) {
78
+ reason = "reconcile-fail";
79
+ detail = `breakdown total ${recBreakdown.shown} != engine ${engineTotal}`;
80
+ }
81
+ else if (!leakBreakdown.pass) {
82
+ reason = "margin-leak";
83
+ detail = "breakdown carries data-internal-only";
84
+ }
85
+ else if (!recQuote.pass) {
86
+ reason = "reconcile-fail";
87
+ detail = `quote total ${recQuote.shown} != engine ${engineTotal}`;
88
+ }
89
+ else if (!leakQuote.pass) {
90
+ reason = "margin-leak";
91
+ detail = "quote carries data-internal-only";
92
+ }
93
+ else {
94
+ reason = "sign-link";
95
+ detail = `quote Sign-Online link ${signLink.reason} (href=${signLink.href ?? ""})`;
96
+ }
97
+ return { ok: false, reason, detail };
98
+ }
99
+ const internalPath = join(a.accountDir, "memory/admin/customers", phone, `quote-${a.jobId}-internal.html`);
100
+ const breakdownPath = join(a.accountDir, "memory/users", phone, "documents", `quote-${a.jobId}-breakdown.html`);
101
+ const quotePath = join(a.accountDir, "memory/users", phone, "documents", `quote-${a.jobId}.html`);
102
+ for (const [p, body] of [[internalPath, html.internal], [breakdownPath, html.breakdown], [quotePath, html.quote]]) {
103
+ mkdirSync(dirname(p), { recursive: true });
104
+ writeFileSync(p, body);
105
+ }
106
+ return {
107
+ ok: true,
108
+ docs: { internal: internalPath, breakdown: breakdownPath, quote: quotePath },
109
+ reconcile: { internal: internalOk, breakdown: breakdownOk, quote: quoteOk },
110
+ signLink,
111
+ };
112
+ }
113
+ //# sourceMappingURL=render-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-run.js","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,uEAAuE;AACvE,EAAE;AACF,wEAAwE;AACxE,iFAAiF;AAEjF,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAwB,MAAM,YAAY,CAAC;AAuB/F,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,CAAgB;IAC9C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,uBAAuB,CAAC,CAAC,gBAAgB,EAAE,EAAE,CAAC;IACrG,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC;IACnF,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,OAAO,CAA0D,CAAC,OAAO,EAAE,EAAE;QACtH,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QACzE,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACzE,2EAA2E;QAC3E,8EAA8E;QAC9E,0EAA0E;QAC1E,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAClC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,wBAAwB,IAAI,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IACvH,CAAC;IAED,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAqB,CAAC;QACtD,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACpH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,mEAAmE,EAAE,CAAC;QAC5H,CAAC;QACD,IAAI,GAAG,MAAiB,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,+BAA+B,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IACrH,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAI,CAAC,CAAC,OAAO,CAAC,MAAyC,EAAE,KAAK,CAAC;IAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,iEAAiE,EAAE,CAAC;IAC1H,CAAC;IACD,2EAA2E;IAC3E,6EAA6E;IAC7E,yBAAyB;IACzB,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,gEAAgE,KAAK,EAAE,EAAE,CAAC;IAChI,CAAC;IAED,+EAA+E;IAC/E,yCAAyC;IACzC,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAE1C,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC;IACpC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC;IAEjE,IAAI,CAAC,UAAU,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5C,oEAAoE;QACpE,IAAI,MAAmB,CAAC;QACxB,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YAAC,MAAM,GAAG,gBAAgB,CAAC;YAAC,MAAM,GAAG,kBAAkB,WAAW,CAAC,KAAK,cAAc,WAAW,EAAE,CAAC;QAAC,CAAC;aACzH,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YAAC,MAAM,GAAG,gBAAgB,CAAC;YAAC,MAAM,GAAG,mBAAmB,YAAY,CAAC,KAAK,cAAc,WAAW,EAAE,CAAC;QAAC,CAAC;aACjI,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;YAAC,MAAM,GAAG,aAAa,CAAC;YAAC,MAAM,GAAG,sCAAsC,CAAC;QAAC,CAAC;aACrG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAAC,MAAM,GAAG,gBAAgB,CAAC;YAAC,MAAM,GAAG,eAAe,QAAQ,CAAC,KAAK,cAAc,WAAW,EAAE,CAAC;QAAC,CAAC;aACrH,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YAAC,MAAM,GAAG,aAAa,CAAC;YAAC,MAAM,GAAG,kCAAkC,CAAC;QAAC,CAAC;aAC7F,CAAC;YAAC,MAAM,GAAG,WAAW,CAAC;YAAC,MAAM,GAAG,0BAA0B,QAAQ,CAAC,MAAM,UAAU,QAAQ,CAAC,IAAI,IAAI,EAAE,GAAG,CAAC;QAAC,CAAC;QAClH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,wBAAwB,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,KAAK,gBAAgB,CAAC,CAAC;IAC3G,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC;IAChH,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;IAClG,KAAK,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAU,EAAE,CAAC;QAC3H,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE;QAC5E,SAAS,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE;QAC3E,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerQuoteEngineRun(server: McpServer): void;
3
+ //# sourceMappingURL=quote-engine-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote-engine-run.d.ts","sourceRoot":"","sources":["../../src/tools/quote-engine-run.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoD9D"}
@@ -0,0 +1,48 @@
1
+ // quote-engine-run — execute the operator's persisted pricing engine against a
2
+ // job and return structured figures. Runs the already-persisted engine; never
3
+ // regenerates it, never embeds a rate/catalogue/roll-up. A fault returns a
4
+ // cause-naming error and zero figures — never a partial or guessed total.
5
+ import { z } from "zod";
6
+ import { join } from "node:path";
7
+ import { lifelineTool } from "../../../../../lib/mcp-lifeline/dist/index.js";
8
+ import { resolveAccountDir } from "../lib/account.js";
9
+ import { runEngine, writeFigures } from "../lib/engine-run.js";
10
+ import { logLine } from "../lib/log.js";
11
+ export function registerQuoteEngineRun(server) {
12
+ lifelineTool(server, "quote-engine-run", "Execute the operator's already-persisted pricing engine (quoting/engine.mjs) against a job's quantities and return line prices, group subtotals and total. mode=verify runs the engine against a past job and returns the per-level reproduction delta. Runs the operator's own script; it is not a pricing model and embeds no rate, catalogue or roll-up. Faults (engine-absent, method-absent, script-error) return zero figures.", {
13
+ jobId: z.string().describe("Correlation id; figures persist under quoting/jobs/<jobId>/."),
14
+ job: z.record(z.any()).describe("The job: header + lines. Passed to the engine verbatim; not interpreted here."),
15
+ mode: z.enum(["quote", "verify"]).default("quote").describe("quote = price the job; verify = reproduce a past job and return the delta."),
16
+ enginePath: z.string().default("quoting/engine.mjs").describe("Engine path relative to the account workspace."),
17
+ methodPath: z.string().default("quoting/method.json").describe("Method path relative to the account workspace."),
18
+ }, async (params) => {
19
+ const { jobId, job, mode, enginePath, methodPath } = params;
20
+ const accountId = process.env.ACCOUNT_ID ?? "local";
21
+ const accountDir = resolveAccountDir();
22
+ if (!accountDir) {
23
+ const detail = "ACCOUNT_DIR unset and PLATFORM_ROOT+ACCOUNT_ID unavailable";
24
+ logLine(`[quote-engine] op=fault jobId=${jobId} reason=no-account-context detail=${detail}`);
25
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, reason: "no-account-context", detail }) }], isError: true };
26
+ }
27
+ const absEngine = join(accountDir, enginePath);
28
+ const absMethod = join(accountDir, methodPath);
29
+ const r = await runEngine({ accountDir, enginePath: absEngine, methodPath: absMethod, job, mode });
30
+ if (!r.ok) {
31
+ logLine(`[quote-engine] op=fault jobId=${jobId} reason=${r.reason} detail=${r.detail}`);
32
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, reason: r.reason, detail: r.detail }, null, 2) }], isError: true };
33
+ }
34
+ if (mode === "verify") {
35
+ const deltas = r.figures.deltas ?? [];
36
+ const worst = r.figures.worst ?? 0;
37
+ logLine(`[quote-engine] op=verify jobId=${jobId} accountId=${accountId} worst=${worst} levels=${deltas.length}`);
38
+ return { content: [{ type: "text", text: JSON.stringify({ jobId, deltas, worst }, null, 2) }] };
39
+ }
40
+ const total = r.figures.total;
41
+ const lineCount = Array.isArray(r.figures.lines) ? r.figures.lines.length : 0;
42
+ const reconcile = r.figures.reconcile;
43
+ const figuresPath = writeFigures(accountDir, jobId, r.figures);
44
+ logLine(`[quote-engine] op=run jobId=${jobId} accountId=${accountId} enginePath=${enginePath} methodPath=${methodPath} lines=${lineCount} total=${total}`);
45
+ return { content: [{ type: "text", text: JSON.stringify({ jobId, total, lineCount, reconcile, figuresPath }, null, 2) }] };
46
+ });
47
+ }
48
+ //# sourceMappingURL=quote-engine-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote-engine-run.js","sourceRoot":"","sources":["../../src/tools/quote-engine-run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerQuoteRender(server: McpServer): void;
3
+ //# sourceMappingURL=quote-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote-render.d.ts","sourceRoot":"","sources":["../../src/tools/quote-render.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkD3D"}
@@ -0,0 +1,50 @@
1
+ // quote-render — turn engine figures into the three reconciling HTML documents
2
+ // via the operator's persisted render script, enforcing the reconcile,
3
+ // margin-leak and link-liveness gates, and filing each doc by its scope. HTML
4
+ // only: the PDF is produced downstream by the browser plugin's browser-pdf-save.
5
+ // A gate failure is fail-closed — no document is filed.
6
+ import { z } from "zod";
7
+ import { join } from "node:path";
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { lifelineTool } from "../../../../../lib/mcp-lifeline/dist/index.js";
10
+ import { resolveAccountDir } from "../lib/account.js";
11
+ import { runRender } from "../lib/render-run.js";
12
+ import { logLine } from "../lib/log.js";
13
+ export function registerQuoteRender(server) {
14
+ lifelineTool(server, "quote-render", "Turn engine figures into the three reconciling HTML documents (internal margin view, client breakdown, client quote) via the operator's persisted quoting/render.mjs, enforcing three gates — reconcile (displayed total == engine total), margin-leak (no cost/margin in client docs), link-liveness (the client quote's Sign-Online href is absolute https). Files each doc by scope and returns the HTML paths. HTML only; print the PDFs with the browser plugin's browser-pdf-save. A gate failure files nothing.", {
15
+ jobId: z.string().describe("Correlation id; figures load from quoting/jobs/<jobId>/figures.json unless figures is supplied inline."),
16
+ figures: z.record(z.any()).optional().describe("Inline figures (overrides the persisted figures.json) — for fixed-figure render parity."),
17
+ signUrl: z.string().optional().describe("The deployed e-sign signing URL injected into the client quote's acceptance anchor. Absent or non-https fails the link-liveness gate."),
18
+ renderScriptPath: z.string().default("quoting/render.mjs").describe("Render script path relative to the account workspace."),
19
+ }, async (params) => {
20
+ const { jobId, figures: inlineFigures, signUrl, renderScriptPath } = params;
21
+ const accountDir = resolveAccountDir();
22
+ if (!accountDir) {
23
+ const detail = "ACCOUNT_DIR unset and PLATFORM_ROOT+ACCOUNT_ID unavailable";
24
+ logLine(`[quote-render] op=fault jobId=${jobId} reason=no-account-context detail=${detail}`);
25
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, reason: "no-account-context", detail }) }], isError: true };
26
+ }
27
+ let figures;
28
+ if (inlineFigures) {
29
+ figures = inlineFigures;
30
+ }
31
+ else {
32
+ const figuresPath = join(accountDir, "quoting", "jobs", jobId, "figures.json");
33
+ if (!existsSync(figuresPath)) {
34
+ const detail = `no figures at ${figuresPath} — run quote-engine-run first`;
35
+ logLine(`[quote-render] op=fault jobId=${jobId} reason=figures-absent detail=${detail}`);
36
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, reason: "figures-absent", detail }) }], isError: true };
37
+ }
38
+ figures = JSON.parse(readFileSync(figuresPath, "utf8"));
39
+ }
40
+ const absRender = join(accountDir, renderScriptPath);
41
+ const r = await runRender({ accountDir, renderScriptPath: absRender, figures, signUrl, jobId });
42
+ if (!r.ok) {
43
+ logLine(`[quote-render] op=fault jobId=${jobId} reason=${r.reason} detail=${r.detail}`);
44
+ return { content: [{ type: "text", text: JSON.stringify({ ok: false, reason: r.reason, detail: r.detail }, null, 2) }], isError: true };
45
+ }
46
+ logLine(`[quote-render] op=render jobId=${jobId} docs=3 internal=${r.reconcile.internal} breakdown=${r.reconcile.breakdown} quote=${r.reconcile.quote}`);
47
+ return { content: [{ type: "text", text: JSON.stringify({ jobId, docs: r.docs, reconcile: r.reconcile, signLink: r.signLink }, null, 2) }] };
48
+ });
49
+ }
50
+ //# sourceMappingURL=quote-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote-render.js","sourceRoot":"","sources":["../../src/tools/quote-render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerTakeoffCompute(server: McpServer): void;
3
+ //# sourceMappingURL=takeoff-compute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"takeoff-compute.d.ts","sourceRoot":"","sources":["../../src/tools/takeoff-compute.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwC9D"}
@@ -0,0 +1,42 @@
1
+ // takeoff-compute — deterministic takeoff geometry over agent-supplied measured
2
+ // inputs. Reading the drawing and eliciting inputs stay in the takeoff skill;
3
+ // this tool only does the arithmetic. Carries no business content.
4
+ import { z } from "zod";
5
+ import { lifelineTool } from "../../../../../lib/mcp-lifeline/dist/index.js";
6
+ import { computeTakeoff } from "../lib/geometry.js";
7
+ import { logLine } from "../lib/log.js";
8
+ export function registerTakeoffCompute(server) {
9
+ lifelineTool(server, "takeoff-compute", "Deterministic takeoff geometry: turn agent-supplied measured inputs into a tagged quantity list — scale a measured length to its real dimension, a scaled area from two sides, roll up counts, and cross-check a scaled quantity against a printed figure. Reading the drawing and eliciting the inputs is the takeoff skill; this tool does only the arithmetic and carries no business content.", {
10
+ jobId: z.string().describe("Correlation id for this quote/takeoff."),
11
+ scale: z
12
+ .union([z.object({ ratio: z.number() }), z.object({ measuredRef: z.number(), actual: z.number() })])
13
+ .optional()
14
+ .describe("Drawing scale: {ratio} for 1:R, or {measuredRef, actual} calibration. Required only when a line is scale-derived."),
15
+ lines: z
16
+ .array(z.object({
17
+ element: z.string(),
18
+ basis: z.enum(["printed", "scaled", "count", "operator"]),
19
+ value: z.number().optional(),
20
+ unit: z.string().optional(),
21
+ measured: z.number().optional(),
22
+ measuredB: z.number().optional(),
23
+ kind: z.enum(["length", "area"]).optional(),
24
+ count: z.union([z.number(), z.array(z.number())]).optional(),
25
+ crossCheck: z.object({ value: z.number(), unit: z.string().optional(), tolerance: z.number().optional() }).optional(),
26
+ }))
27
+ .describe("The measured lines to compute."),
28
+ }, async (params) => {
29
+ const { jobId, scale, lines } = params;
30
+ try {
31
+ const r = computeTakeoff({ scale, lines });
32
+ logLine(`[takeoff-compute] op=compute jobId=${jobId} lines=${r.lines.length} exact=${r.counts.exact} scaled=${r.counts.scaled}`);
33
+ return { content: [{ type: "text", text: JSON.stringify({ jobId, ...r }, null, 2) }] };
34
+ }
35
+ catch (err) {
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ logLine(`[takeoff-compute] op=fault jobId=${jobId} detail=${msg}`);
38
+ return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
39
+ }
40
+ });
41
+ }
42
+ //# sourceMappingURL=takeoff-compute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"takeoff-compute.js","sourceRoot":"","sources":["../../src/tools/takeoff-compute.ts"],"names":[],"mappings":"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"}