@rubytech/create-sitedesk-code 0.1.452 → 0.1.454

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 (138) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-style/dist/index.d.ts +19 -0
  3. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/graph-style/dist/index.js +111 -0
  5. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  6. package/payload/platform/lib/graph-style/src/__tests__/icons.test.ts +63 -0
  7. package/payload/platform/lib/graph-style/src/index.ts +112 -0
  8. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  9. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +6 -4
  10. package/payload/platform/plugins/cloudflare/references/api.md +1 -1
  11. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +1 -1
  12. package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
  13. package/payload/platform/plugins/docs/references/outlook-guide.md +3 -3
  14. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
  15. package/payload/platform/plugins/outlook/PLUGIN.md +3 -3
  16. package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.d.ts +2 -0
  17. package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.d.ts.map +1 -0
  18. package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.js +131 -0
  19. package/payload/platform/plugins/outlook/mcp/dist/__tests__/complete-registration.test.js.map +1 -0
  20. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.d.ts +2 -0
  21. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.d.ts.map +1 -0
  22. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.js +55 -0
  23. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-paged.test.js.map +1 -0
  24. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.d.ts +2 -0
  25. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.d.ts.map +1 -0
  26. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.js +120 -0
  27. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list-paging.test.js.map +1 -0
  28. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.d.ts +2 -0
  29. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.d.ts.map +1 -0
  30. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.js +66 -0
  31. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-search-paging.test.js.map +1 -0
  32. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.d.ts +2 -0
  33. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.d.ts.map +1 -0
  34. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.js +48 -0
  35. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pending-scan.test.js.map +1 -0
  36. package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.d.ts +31 -0
  37. package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.d.ts.map +1 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.js +47 -0
  39. package/payload/platform/plugins/outlook/mcp/dist/auth/complete-registration.js.map +1 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.d.ts +11 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.d.ts.map +1 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.js +31 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/auth/pending-scan.js.map +1 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/index.js +13 -9
  45. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  46. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +19 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
  48. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +14 -0
  49. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
  50. package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.d.ts +2 -0
  51. package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.d.ts.map +1 -0
  52. package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.js +111 -0
  53. package/payload/platform/plugins/outlook/mcp/dist/scripts/complete-registration.js.map +1 -0
  54. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +16 -1
  55. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -1
  56. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +37 -7
  57. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -1
  58. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts +12 -1
  59. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -1
  60. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +16 -12
  61. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -1
  62. package/payload/platform/plugins/outlook/references/auth.md +2 -0
  63. package/payload/platform/plugins/outlook/references/graph-surfaces.md +20 -9
  64. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +7 -7
  65. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
  66. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +3 -3
  67. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  68. package/payload/platform/scripts/lib/__tests__/account-settings-askgate.test.sh +144 -0
  69. package/payload/platform/scripts/lib/account-settings-askgate.sh +98 -0
  70. package/payload/platform/scripts/setup-account.sh +14 -0
  71. package/payload/platform/scripts/smoke-boot-services.sh +1 -0
  72. package/payload/platform/scripts/voice-mirror-audit.sh +70 -0
  73. package/payload/platform/services/claude-session-manager/dist/config.d.ts +5 -0
  74. package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
  75. package/payload/platform/services/claude-session-manager/dist/config.js +7 -1
  76. package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
  77. package/payload/platform/services/claude-session-manager/dist/index.js +72 -6
  78. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  79. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.d.ts +17 -0
  80. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.d.ts.map +1 -1
  81. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.js +14 -0
  82. package/payload/platform/services/claude-session-manager/dist/interactive-wedge.js.map +1 -1
  83. package/payload/platform/services/claude-session-manager/dist/plugin-enum.d.ts +34 -0
  84. package/payload/platform/services/claude-session-manager/dist/plugin-enum.d.ts.map +1 -0
  85. package/payload/platform/services/claude-session-manager/dist/plugin-enum.js +66 -0
  86. package/payload/platform/services/claude-session-manager/dist/plugin-enum.js.map +1 -0
  87. package/payload/premium-plugins/sitedesk/agents/sitedesk--quoter.md +2 -2
  88. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/PLUGIN.md +1 -1
  89. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.d.ts +1 -1
  90. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.d.ts.map +1 -1
  91. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.js +23 -3
  92. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/render-run.js.map +1 -1
  93. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-render.js +1 -1
  94. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/quote-render.js.map +1 -1
  95. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/render-run.test.ts +48 -1
  96. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/render-run.ts +26 -4
  97. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/tools/quote-render.ts +1 -1
  98. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/skills/quotation/references/quote-generation.md +39 -21
  99. package/payload/server/public/assets/{AdminLoginScreens-Bvf4HKmq.js → AdminLoginScreens-5R0A40Is.js} +1 -1
  100. package/payload/server/public/assets/AdminShell-B2HeKInP.js +2 -0
  101. package/payload/server/public/assets/{Checkbox-2SswiICc.js → Checkbox-yjCERU3B.js} +1 -1
  102. package/payload/server/public/assets/{admin-B7GPCzpr.js → admin-BDio0OER.js} +1 -1
  103. package/payload/server/public/assets/{browser-CodHC_MO.js → browser-bSeWXhod.js} +1 -1
  104. package/payload/server/public/assets/{calendar-DH7cyXKF.js → calendar-MNAmsxL3.js} +1 -1
  105. package/payload/server/public/assets/chat-Bq4Uq3Ht.js +1 -0
  106. package/payload/server/public/assets/chevron-left-D5XwUM2x.js +1 -0
  107. package/payload/server/public/assets/data-DY10qHOy.js +1 -0
  108. package/payload/server/public/assets/{graph-BToB78LG.js → graph-DRWRwsUZ.js} +7 -7
  109. package/payload/server/public/assets/graph-labels-Cy7GyGln.js +1 -0
  110. package/payload/server/public/assets/{maximize-2-CEQRv64B.js → maximize-2-BRHW5pKh.js} +1 -1
  111. package/payload/server/public/assets/{operator-Cx8cq2wf.js → operator-Dv2k2JaW.js} +1 -1
  112. package/payload/server/public/assets/{page-TCsQy4eP.js → page-BZRZZcqM.js} +1 -1
  113. package/payload/server/public/assets/{page-D6kzsk18.js → page-CoBzMOIg.js} +2 -2
  114. package/payload/server/public/assets/{public-B61xcmAr.js → public-CirpatD6.js} +1 -1
  115. package/payload/server/public/assets/{rotate-ccw-7_3ol0Z4.js → rotate-ccw-tv1JxnBS.js} +1 -1
  116. package/payload/server/public/assets/{tasks-BY9ajKXf.js → tasks-B8iXIZ3w.js} +1 -1
  117. package/payload/server/public/assets/{time-entry-format-DmNhIJnM.js → time-entry-format-MGC9wMbZ.js} +1 -1
  118. package/payload/server/public/assets/{useCopyFeedback-C5-GOl5l.js → useCopyFeedback-DdwMdpa-.js} +1 -1
  119. package/payload/server/public/assets/{useSelectionMode-UOUVnP9B.js → useSelectionMode-DyoyGg7d.js} +1 -1
  120. package/payload/server/public/assets/useSubAccountSwitcher-CMi8n_8S.css +1 -0
  121. package/payload/server/public/assets/{useVoiceRecorder-BAP3yGxs.js → useVoiceRecorder-BDtJhfh_.js} +1 -1
  122. package/payload/server/public/browser.html +5 -5
  123. package/payload/server/public/calendar.html +6 -6
  124. package/payload/server/public/chat.html +12 -12
  125. package/payload/server/public/data.html +10 -10
  126. package/payload/server/public/graph.html +11 -11
  127. package/payload/server/public/index.html +13 -13
  128. package/payload/server/public/operator.html +14 -14
  129. package/payload/server/public/public.html +12 -12
  130. package/payload/server/public/tasks.html +5 -5
  131. package/payload/server/server.js +219 -22
  132. package/payload/server/public/assets/AdminShell-CaGc8ODG.js +0 -2
  133. package/payload/server/public/assets/chat-BQyPAEMv.js +0 -1
  134. package/payload/server/public/assets/chevron-left-Cmev0R9v.js +0 -1
  135. package/payload/server/public/assets/data-DWxZzMfL.js +0 -1
  136. package/payload/server/public/assets/graph-labels-JRGrstzM.js +0 -1
  137. package/payload/server/public/assets/useSubAccountSwitcher-DgM1ergs.css +0 -1
  138. /package/payload/server/public/assets/{useSubAccountSwitcher-DF6bohQA.js → useSubAccountSwitcher-B_zj_dY-.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-wedge.d.ts","sourceRoot":"","sources":["../src/interactive-wedge.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAMxC,MAAM,WAAW,uBAAuB;IACtC;;uBAEmB;IACnB,MAAM,EAAE,OAAO,CAAA;IACf;;4CAEwC;IACxC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB;;;oDAGgD;IAChD,cAAc,EAAE,MAAM,CAAA;CACvB;AA6CD;iFACiF;AACjF,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9C,uBAAuB,CA2BzB;AAED,qEAAqE;AACrE,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,6EAA6E;IAC7E,UAAU,EAAE,MAAM,yBAAyB,EAAE,CAAA;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CACvD;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;IACZ,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAChD;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,yBAAyB,GAAG,qBAAqB,CA6ClG"}
1
+ {"version":3,"file":"interactive-wedge.d.ts","sourceRoot":"","sources":["../src/interactive-wedge.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAMxC,MAAM,WAAW,uBAAuB;IACtC;;uBAEmB;IACnB,MAAM,EAAE,OAAO,CAAA;IACf;;4CAEwC;IACxC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB;;;oDAGgD;IAChD,cAAc,EAAE,MAAM,CAAA;CACvB;AA6CD;iFACiF;AACjF,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9C,uBAAuB,CA2BzB;AAED,qEAAqE;AACrE,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAkBD;gFACgF;AAChF,MAAM,WAAW,yBAAyB;IACxC;wCACoC;IACpC,aAAa,EAAE,MAAM,MAAM,EAAE,CAAA;IAC7B,2EAA2E;IAC3E,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAA;IAC7C,+EAA+E;IAC/E,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAA;IAChD,mDAAmD;IACnD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAA;CAC1D;AAED;;8EAE8E;AAC9E,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,yBAAyB,GAC9B,yBAAyB,EAAE,CAS7B;AAED,MAAM,WAAW,yBAAyB;IACxC,6EAA6E;IAC7E,UAAU,EAAE,MAAM,yBAAyB,EAAE,CAAA;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CACvD;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;IACZ,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAChD;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,yBAAyB,GAAG,qBAAqB,CA6ClG"}
@@ -100,6 +100,20 @@ export function classifyInteractiveWedge(records) {
100
100
  }
101
101
  return { wedged: true, tool: lastName, pendingInbound };
102
102
  }
103
+ /** Pure. Collects channel-attached sessions from every non-boot project-slug so
104
+ * the wedge watch covers client sub-account sessions, not just the boot
105
+ * account. Ordering follows `otherSlugDirs()` then `sessionIdsForSlug()`. */
106
+ export function collectSubAccountChannelCandidates(deps) {
107
+ const out = [];
108
+ for (const slug of deps.otherSlugDirs()) {
109
+ for (const sessionId of deps.sessionIdsForSlug(slug)) {
110
+ if (!deps.hasChannelMarker(sessionId))
111
+ continue;
112
+ out.push({ sessionId, jsonlPath: deps.jsonlPathFor(slug, sessionId) });
113
+ }
114
+ }
115
+ return out;
116
+ }
103
117
  export function createInteractiveWedgeWatch(deps) {
104
118
  const readTail = deps.readTail ?? ((p) => readJsonlTailRecords(p));
105
119
  let timer = null;
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-wedge.js","sourceRoot":"","sources":["../src/interactive-wedge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interactive-wedge.js","sourceRoot":"","sources":["../src/interactive-wedge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { ToolSurface } from './tool-surface.js';
2
+ export interface CorePluginExpectation {
3
+ /** Plugin directory basename, matching the `mcpServers` key. */
4
+ plugin: string;
5
+ /** Minimum tool count below which the plugin is treated as unhealthy. */
6
+ minTools: number;
7
+ }
8
+ export declare const EXPECTED_CORE_PLUGINS: readonly CorePluginExpectation[];
9
+ export interface PluginEnumLine {
10
+ plugin: string;
11
+ /** The plugin declared an `mcp:` block and reached `mcpServers`. */
12
+ registered: boolean;
13
+ /** Count of `all` canonical tool names that resolve to this plugin. */
14
+ tools: number;
15
+ /** registered AND tools >= minTools. `false` is the failure signal. */
16
+ healthy: boolean;
17
+ }
18
+ /** One line per EXPECTED_CORE_PLUGINS entry, whether or not the plugin is
19
+ * present. Tool count is the number of `surface.all` entries whose canonical
20
+ * name resolves to the plugin's MCP namespace. */
21
+ export declare function enumerateCorePlugins(surface: ToolSurface): PluginEnumLine[];
22
+ export interface DuplicateVoiceTool {
23
+ /** Tool basename (`voice-…`) declared by more than one plugin. */
24
+ tool: string;
25
+ /** Sorted list of plugin namespaces that declare it. */
26
+ plugins: string[];
27
+ }
28
+ /** Detect a `voice-*` tool basename declared under more than one plugin
29
+ * namespace. The enumerator (`tool-surface.ts`) already hard-throws when two
30
+ * plugins collide on the same *directory* name; this catches the distinct
31
+ * case where two *different* plugins each declare a voice tool basename,
32
+ * which produces two non-colliding canonical names. */
33
+ export declare function findDuplicateVoiceTools(surface: ToolSurface): DuplicateVoiceTool[];
34
+ //# sourceMappingURL=plugin-enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-enum.d.ts","sourceRoot":"","sources":["../src/plugin-enum.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGpD,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;CACjB;AAKD,eAAO,MAAM,qBAAqB,EAAE,SAAS,qBAAqB,EAEjE,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,UAAU,EAAE,OAAO,CAAA;IACnB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAA;CACjB;AAQD;;mDAEmD;AACnD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,EAAE,CAS3E;AAED,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED;;;;wDAIwD;AACxD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,kBAAkB,EAAE,CAmBlF"}
@@ -0,0 +1,66 @@
1
+ // Standing core-plugin enumeration for the manager boot. Task 1652 carved
2
+ // voice mirror into a core plugin (present on every brand); its own MCP boot
3
+ // line (`[voice-mirror] boot …`) only fires when the plugin actually boots,
4
+ // so it cannot report the failure mode where the plugin is advertised in the
5
+ // docs but never registered. This module drives the enumerator's output the
6
+ // other way: it iterates an EXPECTED set, so an absent plugin still emits one
7
+ // line (`registered=false tools=0`). Task 1658.
8
+ //
9
+ // Pure and total — never throws, never reads the filesystem. The caller
10
+ // (index.ts) turns each returned record into a `[plugin-enum]` /
11
+ // `[voice-mirror-audit]` log line with the brand slug.
12
+ import { extractServerNameFromQualifiedTool } from './pty-spawner.js';
13
+ // Voice mirror is the one concrete core plugin this task instruments.
14
+ // Generalising the expected set to other plugins is a separate task (see
15
+ // Task 1658 scope boundaries) — this list stays single-entry deliberately.
16
+ export const EXPECTED_CORE_PLUGINS = [
17
+ { plugin: 'voice-mirror', minTools: 5 },
18
+ ];
19
+ /** Tool basename — the segment after the final `__` of a canonical name. */
20
+ function toolBasename(canonical) {
21
+ const idx = canonical.lastIndexOf('__');
22
+ return idx === -1 ? canonical : canonical.slice(idx + 2);
23
+ }
24
+ /** One line per EXPECTED_CORE_PLUGINS entry, whether or not the plugin is
25
+ * present. Tool count is the number of `surface.all` entries whose canonical
26
+ * name resolves to the plugin's MCP namespace. */
27
+ export function enumerateCorePlugins(surface) {
28
+ return EXPECTED_CORE_PLUGINS.map(({ plugin, minTools }) => {
29
+ const registered = surface.mcpServers.has(plugin);
30
+ let tools = 0;
31
+ for (const canonical of surface.all) {
32
+ if (extractServerNameFromQualifiedTool(canonical) === plugin)
33
+ tools += 1;
34
+ }
35
+ return { plugin, registered, tools, healthy: registered && tools >= minTools };
36
+ });
37
+ }
38
+ /** Detect a `voice-*` tool basename declared under more than one plugin
39
+ * namespace. The enumerator (`tool-surface.ts`) already hard-throws when two
40
+ * plugins collide on the same *directory* name; this catches the distinct
41
+ * case where two *different* plugins each declare a voice tool basename,
42
+ * which produces two non-colliding canonical names. */
43
+ export function findDuplicateVoiceTools(surface) {
44
+ const byBasename = new Map();
45
+ for (const canonical of surface.all) {
46
+ const basename = toolBasename(canonical);
47
+ if (!basename.startsWith('voice-'))
48
+ continue;
49
+ const plugin = extractServerNameFromQualifiedTool(canonical);
50
+ if (!plugin)
51
+ continue;
52
+ let plugins = byBasename.get(basename);
53
+ if (!plugins) {
54
+ plugins = new Set();
55
+ byBasename.set(basename, plugins);
56
+ }
57
+ plugins.add(plugin);
58
+ }
59
+ const out = [];
60
+ for (const [tool, plugins] of byBasename) {
61
+ if (plugins.size > 1)
62
+ out.push({ tool, plugins: [...plugins].sort() });
63
+ }
64
+ return out.sort((a, b) => a.tool.localeCompare(b.tool));
65
+ }
66
+ //# sourceMappingURL=plugin-enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-enum.js","sourceRoot":"","sources":["../src/plugin-enum.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6EAA6E;AAC7E,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,gDAAgD;AAChD,EAAE;AACF,wEAAwE;AACxE,iEAAiE;AACjE,uDAAuD;AAGvD,OAAO,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAA;AASrE,sEAAsE;AACtE,yEAAyE;AACzE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAqC;IACrE,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,EAAE;CACxC,CAAA;AAYD,4EAA4E;AAC5E,SAAS,YAAY,CAAC,SAAiB;IACrC,MAAM,GAAG,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED;;mDAEmD;AACnD,MAAM,UAAU,oBAAoB,CAAC,OAAoB;IACvD,OAAO,qBAAqB,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;QACxD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACjD,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YACpC,IAAI,kCAAkC,CAAC,SAAS,CAAC,KAAK,MAAM;gBAAE,KAAK,IAAI,CAAC,CAAA;QAC1E,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAA;IAChF,CAAC,CAAC,CAAA;AACJ,CAAC;AASD;;;;wDAIwD;AACxD,MAAM,UAAU,uBAAuB,CAAC,OAAoB;IAC1D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAA;IACjD,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,CAAC,CAAA;QACxC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAQ;QAC5C,MAAM,MAAM,GAAG,kCAAkC,CAAC,SAAS,CAAC,CAAA;QAC5D,IAAI,CAAC,MAAM;YAAE,SAAQ;QACrB,IAAI,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACtC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;YAC3B,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QACnC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACrB,CAAC;IACD,MAAM,GAAG,GAAyB,EAAE,CAAA;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,UAAU,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACxE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;AACzD,CAAC"}
@@ -3,7 +3,7 @@ name: quoter
3
3
  description: "SiteDesk quoter. Delegate when the operator wants a new priced quote for a job or enquiry — measuring quantities off a supplied drawing (PDF, photo, or scan) when one is given, then capturing or applying their own pricing and quotation method (items, quantity rules, pricing rules, roll-up, documents) to produce the live quote and its A4 PDF. Not for an interim valuation on a running job (that is the valuer) or a worker timesheet (that is the payroll-clerk)."
4
4
  summary: "Your quoter — measures a drawing into quantities, then turns the operator's own pricing method into a live priced quote and its PDF."
5
5
  model: claude-sonnet-5
6
- tools: Skill, Read, Write, Edit, Bash, Glob, Grep, mcp__plugin_browser_browser__browser-navigate, mcp__plugin_browser_browser__browser-pdf-save, mcp__plugin_email_email__email-send
6
+ tools: Skill, Read, Write, Edit, Bash, Glob, Grep, mcp__plugin_sitedesk-job_sitedesk-job__quote-render, mcp__plugin_browser_browser__browser-navigate, mcp__plugin_browser_browser__browser-pdf-save, mcp__plugin_email_email__email-send
7
7
  ---
8
8
 
9
9
  # SiteDesk Quoter
@@ -23,7 +23,7 @@ Load the skill on demand with the `Skill` tool; it carries its own method.
23
23
  | Skill | Sub-plugin | What it does |
24
24
  |-------|------------|--------------|
25
25
  | `takeoff` | `sitedesk-job` | Measure quantities off a supplied drawing (PDF, photo, or scan) into a quantity list of lengths, areas and counts. Reads printed dimensions, works un-dimensioned elements to a stated scale or one known dimension, counts fixtures, and asks you for anything the drawing does not show. Each line is tagged with its basis. It measures; it does not price. You feed the quantities straight into `quotation`. |
26
- | `quotation` | `sitedesk-job` | Capture the operator's own pricing/quotation method (items, quantity rules, pricing rules, roll-up, documents) and apply it to produce a live quote. One skill builds the method and applies it — there is no separate quote-generation surface. It renders the quote to A4 HTML and saves the PDF through the device's Chromium print pipeline, then sends it as an attachment when the operator asks. |
26
+ | `quotation` | `sitedesk-job` | Capture the operator's own pricing/quotation method (items, quantity rules, pricing rules, roll-up, documents) and apply it to produce a live quote. One skill builds the method and applies it — there is no separate quote-generation surface. It renders the client quote through the `quote-render` tool (the deterministic path that runs the operator's persisted render script behind the reconcile, margin-leak and link-liveness gates and files the reconciling HTML), then prints that filed HTML to PDF with `browser-pdf-save`, and sends it as an attachment when the operator asks. |
27
27
 
28
28
  ## Output contract
29
29
 
@@ -85,7 +85,7 @@ existing platform tools.
85
85
  | Tool | Does |
86
86
  |------|------|
87
87
  | `quote-engine-run` | Executes the already-persisted engine (`quoting/engine.mjs`) against a job (`{methodPath, job, mode}` on stdin, figures JSON on stdout), persists them to `quoting/jobs/<jobId>/figures.json`, and returns line prices, group subtotals and total. `mode=verify` returns the per-level reproduction delta. Faults (engine-absent, method-absent, script-error) return zero figures, never a partial total |
88
- | `quote-render` | Runs the persisted render script (`quoting/render.mjs`) to emit the three reconciling **HTML** documents from figures, enforcing the reconcile, margin-leak and link-liveness gates, and files each by scope. On success also writes a durable render receipt at `quoting/jobs/<jobId>/render-receipt.json` — the proof the deterministic path ran, which the admin `quote-render-gate` PreToolUse hook requires before a client-quote PDF may be printed. HTML only; the PDF is produced downstream by the `browser` plugin's `browser-pdf-save`. A failing gate files nothing (and writes no receipt) |
88
+ | `quote-render` | Runs the persisted render script (`quoting/render.mjs`) to emit the three reconciling **HTML** documents from figures, enforcing the reconcile and margin-leak gates always, plus link-liveness only on the opt-in online-acceptance path (a `signUrl` was supplied) — the default quote carries no Sign-Online anchor and a stray one fails closed. Files each by scope. On success also writes a durable render receipt at `quoting/jobs/<jobId>/render-receipt.json` — the proof the deterministic path ran, which the admin `quote-render-gate` PreToolUse hook requires before a client-quote PDF may be printed. HTML only; the PDF is produced downstream by the `browser` plugin's `browser-pdf-save`. A failing gate files nothing (and writes no receipt) |
89
89
  | `takeoff-compute` | Deterministic takeoff geometry over agent-supplied measured inputs (scale to a real dimension, a scaled area from two sides, count roll-up, and a scaled-vs-printed cross-check), returning the tagged quantity list. Reading the drawing and eliciting inputs stay in the `takeoff` skill |
90
90
  | `note-capture` | Records a durable job note. One atomic transaction matches the account-scoped `:Job`, CREATEs a fresh `(:Note {text, author, createdAt})-[:ABOUT]->(:Job)`, and reads the note count back. Append-only (a second note never overwrites the first) and attributed to the requester; a missing job writes nothing and returns an error. The note is visible on the job in `/graph`. Replaces the overwrite-prone `Job.notes` scalar |
91
91
 
@@ -19,7 +19,7 @@ export type RenderResult = {
19
19
  breakdown: boolean;
20
20
  quote: boolean;
21
21
  };
22
- signLink: SignLinkVerdict;
22
+ signLink: SignLinkVerdict | null;
23
23
  } | {
24
24
  ok: false;
25
25
  reason: RenderFault;
@@ -1 +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;AAG/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,CAoGvE"}
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;AAG/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;IAGrE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAClC,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,CAwHvE"}
@@ -63,10 +63,30 @@ export async function runRender(a) {
63
63
  const recQuote = gateReconcile(html.quote, engineTotal);
64
64
  const leakBreakdown = gateMarginLeak(html.breakdown);
65
65
  const leakQuote = gateMarginLeak(html.quote);
66
- const signLink = gateSignLink(html.quote);
66
+ // E-sign is opt-in. The Sign-Online acceptance block and its link-liveness
67
+ // gate apply only when the operator supplied a signUrl for this job. On the
68
+ // default (no-signer) path the client quote must carry no acceptance anchor;
69
+ // a stray one is a dead/placeholder button and fails closed the same way a
70
+ // margin leak does. gateSignLink returns reason "no-anchor" exactly when the
71
+ // marked anchor is absent, so anchor-present is `reason !== "no-anchor"`.
72
+ const esignRequested = typeof a.signUrl === "string" && a.signUrl.length > 0;
73
+ const signVerdict = gateSignLink(html.quote);
74
+ const hasAnchor = signVerdict.reason !== "no-anchor";
75
+ let signOk;
76
+ let signDetail;
77
+ if (esignRequested) {
78
+ signOk = signVerdict.pass;
79
+ signDetail = `quote Sign-Online link ${signVerdict.reason} (href=${signVerdict.href ?? ""})`;
80
+ }
81
+ else {
82
+ signOk = !hasAnchor;
83
+ signDetail = "quote carries a Sign-Online acceptance anchor but no signer was requested (no signUrl) — e-sign is opt-in";
84
+ }
85
+ // The verdict is reported only when a signer was requested; null otherwise.
86
+ const signLink = esignRequested ? signVerdict : null;
67
87
  const internalOk = recInternal.pass;
68
88
  const breakdownOk = recBreakdown.pass && leakBreakdown.pass;
69
- const quoteOk = recQuote.pass && leakQuote.pass && signLink.pass;
89
+ const quoteOk = recQuote.pass && leakQuote.pass && signOk;
70
90
  if (!internalOk || !breakdownOk || !quoteOk) {
71
91
  // Reason names the first failing gate, in document then gate order.
72
92
  let reason;
@@ -93,7 +113,7 @@ export async function runRender(a) {
93
113
  }
94
114
  else {
95
115
  reason = "sign-link";
96
- detail = `quote Sign-Online link ${signLink.reason} (href=${signLink.href ?? ""})`;
116
+ detail = signDetail;
97
117
  }
98
118
  return { ok: false, reason, detail };
99
119
  }
@@ -1 +1 @@
1
- {"version":3,"file":"render-run.js","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render-run.js","sourceRoot":"","sources":["../../src/lib/render-run.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ import { resolveAccountDir } from "../lib/account.js";
11
11
  import { runRender } from "../lib/render-run.js";
12
12
  import { logLine } from "../lib/log.js";
13
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.", {
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 reconcile (displayed total == engine total) and margin-leak (no cost/margin in client docs) always, plus link-liveness only when a signUrl is supplied (online acceptance is opt-in: with signUrl the client quote's Sign-Online href must be absolute https; without it the quote must carry no acceptance anchor). 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
15
  jobId: z.string().describe("Correlation id; figures load from quoting/jobs/<jobId>/figures.json unless figures is supplied inline."),
16
16
  figures: z.record(z.any()).optional().describe("Inline figures (overrides the persisted figures.json) — for fixed-figure render parity."),
17
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."),
@@ -1 +1 @@
1
- {"version":3,"file":"quote-render.js","sourceRoot":"","sources":["../../src/tools/quote-render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quote-render.js","sourceRoot":"","sources":["../../src/tools/quote-render.ts"],"names":[],"mappings":"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"}
@@ -42,6 +42,23 @@ process.stdin.on("end", () => {
42
42
  // is sub-penny → the doc shows the penny total, the engine total is sub-penny
43
43
  const SUBPENNY = GOOD.replace("const t = figures.total;", "const t = figures.total.toFixed(2);");
44
44
  const THROW = `process.stdin.resume(); process.exit(1);`;
45
+ // A conforming render script for the default (no-signer) path: it emits the
46
+ // Sign-Online acceptance anchor only when a signUrl is supplied, and omits it
47
+ // entirely otherwise. e-sign is opt-in.
48
+ const NOSIGNER = `
49
+ let input = "";
50
+ process.stdin.on("data", (d) => (input += d));
51
+ process.stdin.on("end", () => {
52
+ const { figures, signUrl } = JSON.parse(input);
53
+ const t = figures.total;
54
+ const accept = signUrl ? ('<a data-esign-accept href="' + signUrl + '">Sign online</a>') : '';
55
+ process.stdout.write(JSON.stringify({
56
+ internal: '<html><body><td data-internal-only>cost 900</td><p data-quote-total="' + t + '">Total ' + t + '</p></body></html>',
57
+ breakdown: '<html><body><p data-quote-total="' + t + '">Total ' + t + '</p></body></html>',
58
+ quote: '<html><body><p data-quote-total="' + t + '">Total ' + t + '</p>' + accept + '</body></html>',
59
+ }));
60
+ });
61
+ `;
45
62
 
46
63
  let dir: string;
47
64
  const figures = { total: 1250, header: { phone: "44700900000" }, lines: [] };
@@ -57,6 +74,7 @@ beforeAll(() => {
57
74
  writeFileSync(join(dir, "quoting", "render-wrongtotal.mjs"), WRONGTOTAL);
58
75
  writeFileSync(join(dir, "quoting", "render-subpenny.mjs"), SUBPENNY);
59
76
  writeFileSync(join(dir, "quoting", "render-throw.mjs"), THROW);
77
+ writeFileSync(join(dir, "quoting", "render-nosigner.mjs"), NOSIGNER);
60
78
  });
61
79
  afterAll(() => rmSync(dir, { recursive: true, force: true }));
62
80
  const rs = (n: string) => join(dir, "quoting", n);
@@ -67,7 +85,7 @@ describe("runRender — happy path files all three docs to their scopes", () =>
67
85
  expect(r.ok).toBe(true);
68
86
  if (!r.ok) return;
69
87
  expect(r.reconcile).toEqual({ internal: true, breakdown: true, quote: true });
70
- expect(r.signLink.pass).toBe(true);
88
+ expect(r.signLink?.pass).toBe(true);
71
89
  expect(r.docs.internal).toBe(join(dir, "memory/admin/customers/44700900000/quote-job-1-internal.html"));
72
90
  expect(r.docs.breakdown).toBe(join(dir, "memory/users/44700900000/documents/quote-job-1-breakdown.html"));
73
91
  expect(r.docs.quote).toBe(join(dir, "memory/users/44700900000/documents/quote-job-1.html"));
@@ -91,6 +109,35 @@ describe("runRender — happy path files all three docs to their scopes", () =>
91
109
  });
92
110
  });
93
111
 
112
+ describe("runRender — e-sign is opt-in; the sign-link gate applies only when a signer is requested", () => {
113
+ it("files all three docs when no signer is requested and the quote carries no acceptance anchor", async () => {
114
+ const r = await runRender({ accountDir: dir, renderScriptPath: rs("render-nosigner.mjs"), figures, jobId: "job-nosigner" });
115
+ expect(r.ok).toBe(true);
116
+ if (!r.ok) return;
117
+ expect(r.reconcile).toEqual({ internal: true, breakdown: true, quote: true });
118
+ // No signer requested → no sign-link verdict on the result.
119
+ expect(r.signLink).toBeNull();
120
+ expect(existsSync(join(dir, "memory/users/44700900000/documents/quote-job-nosigner.html"))).toBe(true);
121
+ expect(existsSync(receiptPath(dir, "job-nosigner"))).toBe(true);
122
+ });
123
+ it("still enforces the sign-link gate on the opt-in path when a signUrl is supplied", async () => {
124
+ const r = await runRender({ accountDir: dir, renderScriptPath: rs("render-nosigner.mjs"), figures, signUrl, jobId: "job-optin" });
125
+ expect(r.ok).toBe(true);
126
+ if (!r.ok) return;
127
+ expect(r.signLink?.pass).toBe(true);
128
+ expect(r.signLink?.href).toBe(signUrl);
129
+ });
130
+ it("rejects a stray acceptance anchor when no signer was requested (fail-closed, nothing filed)", async () => {
131
+ // GOOD always injects the anchor; with no signUrl that is a stray/placeholder signer.
132
+ const r = await runRender({ accountDir: dir, renderScriptPath: rs("render.mjs"), figures, jobId: "job-stray" });
133
+ expect(r).toMatchObject({ ok: false, reason: "sign-link" });
134
+ if (r.ok) return;
135
+ expect(r.detail).toMatch(/no signer|opt-in/i);
136
+ expect(existsSync(join(dir, "memory/users/44700900000/documents/quote-job-stray.html"))).toBe(false);
137
+ expect(existsSync(receiptPath(dir, "job-stray"))).toBe(false);
138
+ });
139
+ });
140
+
94
141
  describe("runRender — a failing gate is fail-closed and atomic (no doc filed)", () => {
95
142
  it("margin-leak when a client doc carries data-internal-only", async () => {
96
143
  const r = await runRender({ accountDir: dir, renderScriptPath: rs("render-leak.mjs"), figures, signUrl, jobId: "job-leak" });
@@ -28,7 +28,9 @@ export type RenderResult =
28
28
  ok: true;
29
29
  docs: { internal: string; breakdown: string; quote: string };
30
30
  reconcile: { internal: boolean; breakdown: boolean; quote: boolean };
31
- signLink: SignLinkVerdict;
31
+ // The link-liveness verdict, or null when e-sign was not requested for
32
+ // this job (no signUrl) — the default, signer-less quote.
33
+ signLink: SignLinkVerdict | null;
32
34
  }
33
35
  | { ok: false; reason: RenderFault; detail: string };
34
36
 
@@ -90,11 +92,31 @@ export async function runRender(a: RunRenderArgs): Promise<RenderResult> {
90
92
  const recQuote = gateReconcile(html.quote, engineTotal);
91
93
  const leakBreakdown = gateMarginLeak(html.breakdown);
92
94
  const leakQuote = gateMarginLeak(html.quote);
93
- const signLink = gateSignLink(html.quote);
95
+
96
+ // E-sign is opt-in. The Sign-Online acceptance block and its link-liveness
97
+ // gate apply only when the operator supplied a signUrl for this job. On the
98
+ // default (no-signer) path the client quote must carry no acceptance anchor;
99
+ // a stray one is a dead/placeholder button and fails closed the same way a
100
+ // margin leak does. gateSignLink returns reason "no-anchor" exactly when the
101
+ // marked anchor is absent, so anchor-present is `reason !== "no-anchor"`.
102
+ const esignRequested = typeof a.signUrl === "string" && a.signUrl.length > 0;
103
+ const signVerdict = gateSignLink(html.quote);
104
+ const hasAnchor = signVerdict.reason !== "no-anchor";
105
+ let signOk: boolean;
106
+ let signDetail: string;
107
+ if (esignRequested) {
108
+ signOk = signVerdict.pass;
109
+ signDetail = `quote Sign-Online link ${signVerdict.reason} (href=${signVerdict.href ?? ""})`;
110
+ } else {
111
+ signOk = !hasAnchor;
112
+ signDetail = "quote carries a Sign-Online acceptance anchor but no signer was requested (no signUrl) — e-sign is opt-in";
113
+ }
114
+ // The verdict is reported only when a signer was requested; null otherwise.
115
+ const signLink: SignLinkVerdict | null = esignRequested ? signVerdict : null;
94
116
 
95
117
  const internalOk = recInternal.pass;
96
118
  const breakdownOk = recBreakdown.pass && leakBreakdown.pass;
97
- const quoteOk = recQuote.pass && leakQuote.pass && signLink.pass;
119
+ const quoteOk = recQuote.pass && leakQuote.pass && signOk;
98
120
 
99
121
  if (!internalOk || !breakdownOk || !quoteOk) {
100
122
  // Reason names the first failing gate, in document then gate order.
@@ -105,7 +127,7 @@ export async function runRender(a: RunRenderArgs): Promise<RenderResult> {
105
127
  else if (!leakBreakdown.pass) { reason = "margin-leak"; detail = "breakdown carries data-internal-only"; }
106
128
  else if (!recQuote.pass) { reason = "reconcile-fail"; detail = `quote total ${recQuote.shown} != engine ${engineTotal}`; }
107
129
  else if (!leakQuote.pass) { reason = "margin-leak"; detail = "quote carries data-internal-only"; }
108
- else { reason = "sign-link"; detail = `quote Sign-Online link ${signLink.reason} (href=${signLink.href ?? ""})`; }
130
+ else { reason = "sign-link"; detail = signDetail; }
109
131
  return { ok: false, reason, detail };
110
132
  }
111
133
 
@@ -17,7 +17,7 @@ export function registerQuoteRender(server: McpServer): void {
17
17
  lifelineTool(
18
18
  server,
19
19
  "quote-render",
20
- "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.",
20
+ "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 reconcile (displayed total == engine total) and margin-leak (no cost/margin in client docs) always, plus link-liveness only when a signUrl is supplied (online acceptance is opt-in: with signUrl the client quote's Sign-Online href must be absolute https; without it the quote must carry no acceptance anchor). 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.",
21
21
  {
22
22
  jobId: z.string().describe("Correlation id; figures load from quoting/jobs/<jobId>/figures.json unless figures is supplied inline."),
23
23
  figures: z.record(z.any()).optional().describe("Inline figures (overrides the persisted figures.json) — for fixed-figure render parity."),
@@ -49,15 +49,18 @@ whatever the operator's brand or language:
49
49
  tool reconciles it against the engine total;
50
50
  - **`data-internal-only`** on every cost, margin, or internal-rate figure in the internal view, so the
51
51
  tool asserts the two client documents carry none;
52
- - **`data-esign-accept`** on the client quote's Sign-Online anchor (one line, double-quoted `href`), so
53
- the tool asserts the acceptance link is live.
52
+ - **`data-esign-accept`** on the client quote's Sign-Online anchor (one line, double-quoted `href`)
53
+ present **only when the operator opted the quote into online acceptance** so the tool asserts the
54
+ acceptance link is live.
54
55
 
55
56
  `quote-render` enforces three fail-closed gates before it files anything: **reconcile** (each
56
57
  document's `data-quote-total` equals the engine total), **margin-leak** (no `data-internal-only` in the
57
58
  client breakdown or client quote), and **link-liveness** (the client quote's `data-esign-accept` href
58
- is an absolute `https://` URL). If any gate fails the tool files nothing and returns a cause-naming
59
- fault (`reconcile-fail`, `margin-leak`, `sign-link`, `render-absent`, `render-error`). On success it
60
- files each document to its scope (below) and returns the three HTML paths plus the gate verdicts.
59
+ is an absolute `https://` URL). Link-liveness runs **only on the opt-in path** when a `signUrl` was
60
+ passed; on the default, signer-less path the quote must carry no acceptance anchor, and a stray one
61
+ fails closed. If any gate fails the tool files nothing and returns a cause-naming fault
62
+ (`reconcile-fail`, `margin-leak`, `sign-link`, `render-absent`, `render-error`). On success it files
63
+ each document to its scope (below) and returns the three HTML paths plus the gate verdicts.
61
64
 
62
65
  The tool produces **HTML, not PDF**. Print each returned path to PDF with the `browser` plugin as the
63
66
  final step: `browser-navigate` to its `file://` URL, then `browser-pdf-save` to a `.pdf` alongside it,
@@ -80,19 +83,28 @@ expose cost and margin freely. The two client documents **never** surface a cost
80
83
  internal-rate figure. A column or line that shows the price to the client is fine; a figure that
81
84
  reveals what the work cost the operator, or the markup applied, is a leak.
82
85
 
83
- ### The acceptance block is the e-sign gated form
86
+ ### Online acceptance is optional and off by default
84
87
 
85
- The **acceptance block** in the client quote document is not free-form prose it is the signing form
86
- of the `e-sign` skill (`platform/plugins/business-assistant/skills/e-sign/SKILL.md`). That skill owns
87
- how the quote is accepted: the `name` / `email` / intent-and-consent form, the capture to D1, the
88
+ Most quotes carry **no** online-acceptance link. Online signing is an opt-in the operator asks for per
89
+ quote, not a default. **By default the client quote has no acceptance block and no Sign-Online anchor,
90
+ and it renders and ships with none.** The render script emits the acceptance block **only** when a
91
+ `signUrl` is passed to `quote-render`; with no `signUrl` it omits the block entirely. Do not add an
92
+ online-acceptance button to a quote the operator did not ask to be signable — a stray anchor on the
93
+ default path fails the render closed (`sign-link`), because a signer link with no signing page behind
94
+ it is a dead button.
95
+
96
+ The **acceptance block**, when the operator does opt in, is not free-form prose — it is the signing
97
+ form of the `e-sign` skill (`platform/plugins/business-assistant/skills/e-sign/SKILL.md`). That skill
98
+ owns how the quote is accepted: the `name` / `email` / intent-and-consent form, the capture to D1, the
88
99
  stamped acceptance certificate, and the email dispatch. This contract produces the quote document;
89
100
  e-sign turns its acceptance block into a recordable signature. This contract does not restate those
90
101
  mechanics.
91
102
 
92
- **The Sign-Online link must be live before the quote is finalised — deploy first, then inject, then
93
- render.** The acceptance block carries a **Sign-Online anchor** — the button the client taps to reach
94
- the signing page. That page does not exist until e-sign deploys it, so the client quote **cannot be
95
- rendered until the deploy has run**. The order is fixed and load-bearing:
103
+ **When the operator opts into online acceptance, the Sign-Online link must be live before the quote is
104
+ finalised — deploy first, then inject, then render.** The acceptance block carries a **Sign-Online
105
+ anchor** — the button the client taps to reach the signing page. That page does not exist until e-sign
106
+ deploys it, so a **signable** client quote **cannot be rendered until the deploy has run**. The order
107
+ is fixed and load-bearing:
96
108
 
97
109
  1. run **e-sign § 5** to deploy the signing page and take its returned absolute `https://` URL (e-sign
98
110
  § 5 names it as an explicit hand-back);
@@ -104,11 +116,13 @@ rendered until the deploy has run**. The order is fixed and load-bearing:
104
116
 
105
117
  The render script marks that one anchor with the stable attribute `data-esign-accept` so
106
118
  `quote-render`'s link-liveness gate finds it deterministically, whatever the operator's brand,
107
- wording, or language. The gate matches the anchor's opening tag, so the render script emits that
108
- opening tag on a **single line** with a **double-quoted `href`** (the default for these self-contained
109
- documents); a split tag or single-quoted `href` reads as no anchor and fails the gate closed. The
110
- anchor's `href` is **never** a placeholder, a bare `#`, or a `file://`/relative path: it is the
111
- deployed signing URL or the quote does not ship.
119
+ wording, or language. The gate applies **only on the opt-in path** (a `signUrl` was passed); on the
120
+ default path it does not run and the quote must carry no anchor. When it does apply, the gate matches
121
+ the anchor's opening tag, so the render script emits that opening tag on a **single line** with a
122
+ **double-quoted `href`** (the default for these self-contained documents); a split tag or
123
+ single-quoted `href` reads as no anchor and fails the gate closed. The anchor's `href` is **never** a
124
+ placeholder, a bare `#`, or a `file://`/relative path: it is the deployed signing URL or the quote
125
+ does not ship.
112
126
 
113
127
  When the quote is **confidential to a named client**, the acceptance is gated per e-sign § 1a. That
114
128
  section's **same-origin invariant** is load-bearing: the `/api/accept` and `/api/status` capture
@@ -166,9 +180,13 @@ these checks are enforced deterministically at render time, not as a separate ha
166
180
  - **margin-leak.** The client breakdown and client quote must carry no `data-internal-only` marker. A
167
181
  leak files nothing and returns `margin-leak`. The margin boundary is structural, not a matter of
168
182
  remembering to omit a column.
169
- - **link-liveness.** The client quote's `data-esign-accept` href must be an absolute `https://` URL,
170
- not empty, a bare fragment (`#…`), relative, `file://`, `about:`, or any non-https target. A dead
171
- link files nothing and returns `sign-link`, because a dead link emits no other signal.
183
+ - **link-liveness (opt-in only).** This gate runs only when the operator opted the quote into online
184
+ acceptance a `signUrl` was passed. Then the client quote's `data-esign-accept` href must be an
185
+ absolute `https://` URL, not empty, a bare fragment (`#…`), relative, `file://`, `about:`, or any
186
+ non-https target; a dead link files nothing and returns `sign-link`, because a dead link emits no
187
+ other signal. On the default, signer-less path (no `signUrl`) the quote must carry **no** acceptance
188
+ anchor at all; a stray anchor also returns `sign-link` (a signer link with no signing page is a dead
189
+ button).
172
190
 
173
191
  The tool emits one `[quote-render] op=render jobId=… docs=3 internal=… breakdown=… quote=…` line on
174
192
  success and `[quote-render] op=fault jobId=… reason=… detail=…` on any gate failure. On success it also