@rubytech/create-sitedesk-code 0.1.446 → 0.1.447

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 (224) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  3. package/payload/platform/lib/graph-style/dist/index.js +6 -0
  4. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  5. package/payload/platform/lib/graph-style/src/index.ts +7 -0
  6. package/payload/platform/neo4j/schema.cypher +32 -1
  7. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  8. package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +1 -0
  9. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +42 -5
  10. package/payload/platform/plugins/docs/references/calendar-booking.md +18 -1
  11. package/payload/platform/plugins/docs/references/claudeai-connectors.md +15 -0
  12. package/payload/platform/plugins/docs/references/outlook-guide.md +8 -3
  13. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +4 -4
  14. package/payload/platform/plugins/memory/references/schema-construction.md +7 -2
  15. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
  16. package/payload/platform/plugins/outlook/PLUGIN.md +23 -5
  17. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.d.ts +2 -0
  18. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.d.ts.map +1 -0
  19. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js +70 -0
  20. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js.map +1 -0
  21. package/payload/platform/plugins/outlook/mcp/dist/__tests__/html-to-text.test.d.ts +2 -0
  22. package/payload/platform/plugins/outlook/mcp/dist/__tests__/html-to-text.test.d.ts.map +1 -0
  23. package/payload/platform/plugins/outlook/mcp/dist/__tests__/html-to-text.test.js +22 -0
  24. package/payload/platform/plugins/outlook/mcp/dist/__tests__/html-to-text.test.js.map +1 -0
  25. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-delete.test.d.ts +2 -0
  26. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-delete.test.d.ts.map +1 -0
  27. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-delete.test.js +60 -0
  28. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-delete.test.js.map +1 -0
  29. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-fetch-body.test.d.ts +2 -0
  30. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-fetch-body.test.d.ts.map +1 -0
  31. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-fetch-body.test.js +80 -0
  32. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-fetch-body.test.js.map +1 -0
  33. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-otp-extract.test.d.ts +2 -0
  34. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-otp-extract.test.d.ts.map +1 -0
  35. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-otp-extract.test.js +90 -0
  36. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-otp-extract.test.js.map +1 -0
  37. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-reply.test.d.ts +2 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-reply.test.d.ts.map +1 -0
  39. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-reply.test.js +194 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-reply.test.js.map +1 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/__tests__/otp.test.d.ts +2 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/__tests__/otp.test.d.ts.map +1 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/__tests__/otp.test.js +16 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/__tests__/otp.test.js.map +1 -0
  45. package/payload/platform/plugins/outlook/mcp/dist/__tests__/outbound-attachments.test.d.ts +2 -0
  46. package/payload/platform/plugins/outlook/mcp/dist/__tests__/outbound-attachments.test.d.ts.map +1 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/__tests__/outbound-attachments.test.js +103 -0
  48. package/payload/platform/plugins/outlook/mcp/dist/__tests__/outbound-attachments.test.js.map +1 -0
  49. package/payload/platform/plugins/outlook/mcp/dist/index.js +88 -0
  50. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  51. package/payload/platform/plugins/outlook/mcp/dist/lib/html-to-text.d.ts +9 -0
  52. package/payload/platform/plugins/outlook/mcp/dist/lib/html-to-text.d.ts.map +1 -0
  53. package/payload/platform/plugins/outlook/mcp/dist/lib/html-to-text.js +24 -0
  54. package/payload/platform/plugins/outlook/mcp/dist/lib/html-to-text.js.map +1 -0
  55. package/payload/platform/plugins/outlook/mcp/dist/lib/otp.d.ts +2 -0
  56. package/payload/platform/plugins/outlook/mcp/dist/lib/otp.d.ts.map +1 -0
  57. package/payload/platform/plugins/outlook/mcp/dist/lib/otp.js +49 -0
  58. package/payload/platform/plugins/outlook/mcp/dist/lib/otp.js.map +1 -0
  59. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts +58 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts.map +1 -0
  61. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js +127 -0
  62. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js.map +1 -0
  63. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.d.ts +28 -0
  64. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.d.ts.map +1 -0
  65. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.js +54 -0
  66. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.js.map +1 -0
  67. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts +21 -0
  68. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts.map +1 -0
  69. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js +38 -0
  70. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js.map +1 -0
  71. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-delete.d.ts +14 -0
  72. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-delete.d.ts.map +1 -0
  73. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-delete.js +39 -0
  74. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-delete.js.map +1 -0
  75. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts +23 -0
  76. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts.map +1 -0
  77. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js +44 -0
  78. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js.map +1 -0
  79. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-otp-extract.d.ts +22 -0
  80. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-otp-extract.d.ts.map +1 -0
  81. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-otp-extract.js +90 -0
  82. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-otp-extract.js.map +1 -0
  83. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts +27 -0
  84. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -0
  85. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +75 -0
  86. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js.map +1 -0
  87. package/payload/platform/plugins/outlook/references/graph-surfaces.md +57 -1
  88. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +15 -4
  89. package/payload/platform/plugins/scheduling/PLUGIN.md +15 -0
  90. package/payload/platform/plugins/scheduling/mcp/dist/index.js +29 -1
  91. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  92. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +53 -1
  93. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -1
  94. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +21 -0
  95. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
  96. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +80 -0
  97. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
  98. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts +4 -0
  99. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts.map +1 -1
  100. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +68 -1
  101. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
  102. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-connector-busy-sync.test.d.ts +2 -0
  103. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-connector-busy-sync.test.d.ts.map +1 -0
  104. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-connector-busy-sync.test.js +75 -0
  105. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-connector-busy-sync.test.js.map +1 -0
  106. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.d.ts +31 -0
  107. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.d.ts.map +1 -0
  108. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.js +41 -0
  109. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-connector-busy-sync.js.map +1 -0
  110. package/payload/platform/plugins/voice-mirror/.claude-plugin/plugin.json +21 -0
  111. package/payload/platform/plugins/voice-mirror/PLUGIN.md +72 -0
  112. package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/index.js +193 -0
  113. package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/package.json +3 -0
  114. package/payload/platform/plugins/voice-mirror/mcp/dist/index.d.ts +3 -0
  115. package/payload/platform/plugins/voice-mirror/mcp/dist/index.d.ts.map +1 -0
  116. package/payload/platform/plugins/voice-mirror/mcp/dist/index.js +403 -0
  117. package/payload/platform/plugins/voice-mirror/mcp/dist/index.js.map +1 -0
  118. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/neo4j.d.ts +14 -0
  119. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/neo4j.d.ts.map +1 -0
  120. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/neo4j.js +47 -0
  121. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/neo4j.js.map +1 -0
  122. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.d.ts +117 -0
  123. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.d.ts.map +1 -0
  124. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.js +138 -0
  125. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.js.map +1 -0
  126. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts +90 -0
  127. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -0
  128. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +609 -0
  129. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -0
  130. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.d.ts +19 -0
  131. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -0
  132. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.js +124 -0
  133. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-ingest-session-text.js.map +1 -0
  134. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.d.ts +38 -0
  135. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -0
  136. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.js +93 -0
  137. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-record-feedback.js.map +1 -0
  138. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.d.ts +61 -0
  139. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -0
  140. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js +171 -0
  141. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -0
  142. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.d.ts +35 -0
  143. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.d.ts.map +1 -0
  144. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.js +127 -0
  145. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-tag-content.js.map +1 -0
  146. package/payload/platform/plugins/voice-mirror/mcp/package-lock.json +1327 -0
  147. package/payload/platform/plugins/voice-mirror/mcp/package.json +19 -0
  148. package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +420 -0
  149. package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +241 -0
  150. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  151. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +12 -0
  152. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  153. package/payload/platform/services/claude-session-manager/dist/http-server.js +1 -1
  154. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  155. package/payload/platform/templates/agents/admin/AGENTS.md +1 -1
  156. package/payload/platform/templates/specialists/agents/content-producer.md +1 -1
  157. package/payload/platform/templates/specialists/agents/personal-assistant.md +6 -2
  158. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/PLUGIN.md +15 -9
  159. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/index.js +2 -0
  160. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/index.js.map +1 -1
  161. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/neo4j.d.ts +5 -0
  162. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/neo4j.d.ts.map +1 -0
  163. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/neo4j.js +41 -0
  164. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/lib/neo4j.js.map +1 -0
  165. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/note-capture.d.ts +25 -0
  166. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/note-capture.d.ts.map +1 -0
  167. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/note-capture.js +114 -0
  168. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/dist/tools/note-capture.js.map +1 -0
  169. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/package-lock.json +137 -0
  170. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/package.json +1 -0
  171. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/index.ts +2 -0
  172. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/__tests__/note-capture.test.ts +55 -0
  173. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/lib/neo4j.ts +51 -0
  174. package/payload/premium-plugins/sitedesk/plugins/sitedesk-job/mcp/src/tools/note-capture.ts +153 -0
  175. package/payload/server/public/assets/{AdminLoginScreens-D9L-CuWi.js → AdminLoginScreens-Bvf4HKmq.js} +1 -1
  176. package/payload/server/public/assets/AdminShell-CaGc8ODG.js +2 -0
  177. package/payload/server/public/assets/{Checkbox-CFdt8ljo.js → Checkbox-2SswiICc.js} +1 -1
  178. package/payload/server/public/assets/admin-B7GPCzpr.js +1 -0
  179. package/payload/server/public/assets/browser-CodHC_MO.js +1 -0
  180. package/payload/server/public/assets/calendar-DH7cyXKF.js +1 -0
  181. package/payload/server/public/assets/chat-BQyPAEMv.js +1 -0
  182. package/payload/server/public/assets/chevron-left-Cmev0R9v.js +1 -0
  183. package/payload/server/public/assets/data-DWxZzMfL.js +1 -0
  184. package/payload/server/public/assets/{graph-DrE7KupQ.js → graph-BToB78LG.js} +2 -2
  185. package/payload/server/public/assets/graph-labels-JRGrstzM.js +1 -0
  186. package/payload/server/public/assets/maximize-2-CEQRv64B.js +1 -0
  187. package/payload/server/public/assets/operator-Cx8cq2wf.js +1 -0
  188. package/payload/server/public/assets/page-D6kzsk18.js +32 -0
  189. package/payload/server/public/assets/page-TCsQy4eP.js +1 -0
  190. package/payload/server/public/assets/public-B61xcmAr.js +1 -0
  191. package/payload/server/public/assets/{rotate-ccw-Cqp4oqHV.js → rotate-ccw-7_3ol0Z4.js} +1 -1
  192. package/payload/server/public/assets/{tasks-bQKOhMga.js → tasks-BY9ajKXf.js} +1 -1
  193. package/payload/server/public/assets/{time-entry-format-BIL4ZaDK.js → time-entry-format-DmNhIJnM.js} +1 -1
  194. package/payload/server/public/assets/useCopyFeedback-C5-GOl5l.js +1 -0
  195. package/payload/server/public/assets/useSelectionMode-UOUVnP9B.js +1 -0
  196. package/payload/server/public/assets/{useSubAccountSwitcher-CVHKTSst.css → useSubAccountSwitcher-DgM1ergs.css} +1 -1
  197. package/payload/server/public/assets/useVoiceRecorder-BAP3yGxs.js +2 -0
  198. package/payload/server/public/browser.html +5 -5
  199. package/payload/server/public/calendar.html +6 -6
  200. package/payload/server/public/chat.html +12 -12
  201. package/payload/server/public/data.html +10 -10
  202. package/payload/server/public/graph.html +11 -11
  203. package/payload/server/public/index.html +13 -13
  204. package/payload/server/public/operator.html +14 -14
  205. package/payload/server/public/public.html +12 -12
  206. package/payload/server/public/tasks.html +5 -5
  207. package/payload/server/server.js +349 -171
  208. package/payload/server/public/assets/AdminShell-DSQrvZXq.js +0 -2
  209. package/payload/server/public/assets/admin-Ch4n-G0j.js +0 -1
  210. package/payload/server/public/assets/browser-B2AIxiuk.js +0 -1
  211. package/payload/server/public/assets/calendar-BvItH3B0.js +0 -1
  212. package/payload/server/public/assets/chat-eQFMaX9y.js +0 -1
  213. package/payload/server/public/assets/chevron-left-D2AnCEyE.js +0 -1
  214. package/payload/server/public/assets/data-BzOmbHoe.js +0 -1
  215. package/payload/server/public/assets/file-download-CK9j_Jx2.js +0 -1
  216. package/payload/server/public/assets/graph-labels-CwEtvIRV.js +0 -1
  217. package/payload/server/public/assets/maximize-2-CuzEom3K.js +0 -1
  218. package/payload/server/public/assets/operator-DlboYPPu.js +0 -1
  219. package/payload/server/public/assets/page-BuWH5gNK.js +0 -1
  220. package/payload/server/public/assets/page-Co9E8U5x.js +0 -32
  221. package/payload/server/public/assets/public-DtFpPMTG.js +0 -1
  222. package/payload/server/public/assets/useCopyFeedback-rB8QuqyH.js +0 -1
  223. package/payload/server/public/assets/useVoiceRecorder-Ctny8qWx.js +0 -2
  224. /package/payload/server/public/assets/{useSubAccountSwitcher-CHEt_m6q.js → useSubAccountSwitcher-DF6bohQA.js} +0 -0
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@maxy/voice-mirror-mcp",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "smoke": "node scripts/smoke.mjs"
10
+ },
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "^1.12.1",
13
+ "neo4j-driver": "^5.28.1"
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^5.7.0",
17
+ "@types/node": "^22.0.0"
18
+ }
19
+ }
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Boot + shape smoke test for the voice-mirror MCP server.
4
+ *
5
+ * Verifies without a live Neo4j connection:
6
+ * 1. Cypher forbidden-pattern gate (Task 458 fold-in): no NULLS LAST /
7
+ * NULLS FIRST / RETURNING patterns in the Cypher emitted by tool sources.
8
+ * 2. Every compiled tool module loads without throwing.
9
+ * 3. Every exported handler is a function with the expected name.
10
+ * 4. AUTHORSHIP_MODES enum covers the five spec-required values.
11
+ * 5. TAGGABLE_PRIMARY_LABELS covers the three content labels.
12
+ * 6. FORMAT_VALUES covers the six writing-format values (Task 462).
13
+ * 7. voiceCorpusWhereWithFormat() appends the format predicate;
14
+ * voiceCorpusWhereWithFormatAndAuthor() also appends the author predicate,
15
+ * and ORG_USER_ID / profileUserIdForScope map scope→userId (Task 676).
16
+ * * 8. voice-retrieve-conditioning discriminates error from no-data (Task 493):
17
+ * status:"error" on blank identity and on a forced lookup throw, never
18
+ * collapsing a failed lookup into the no-data payload. Personal scope
19
+ * requires the caller's userId; org scope is account-wide and resolves
20
+ * identity from accountId alone, so a blank userId must not trip the
21
+ * missing-identity guard for org scope (Task 975).
22
+ * 9. voice-tag-content validates mode and format enums, requires format,
23
+ * returns zero counts on empty nodeIds, and requires voiceAuthor when
24
+ * there are nodes to tag; resolveVoiceAuthor defaults to the operator
25
+ * (Task 676).
26
+ * 11. voice-ingest-session-text: filterOperatorText() keeps real turns
27
+ * and excludes slash commands, paste blocks, and system reminders.
28
+ *
29
+ * Exit code: 0 on pass, 1 on any assertion failure.
30
+ */
31
+ import { strict as assert } from "node:assert";
32
+ import { readFileSync } from "node:fs";
33
+ import { join, dirname } from "node:path";
34
+ import { fileURLToPath } from "node:url";
35
+ import { readdirSync } from "node:fs";
36
+
37
+ const __dirname = dirname(fileURLToPath(import.meta.url));
38
+ const TOOLS_SRC = join(__dirname, "../src/tools");
39
+ const LIB_SRC = join(__dirname, "../src/lib");
40
+
41
+ const errors = [];
42
+ function check(name, fn) {
43
+ try {
44
+ const result = fn();
45
+ if (result && typeof result.then === "function") {
46
+ return result.then(
47
+ () => console.log(` ok ${name}`),
48
+ (err) => {
49
+ errors.push({ name, err });
50
+ console.error(` FAIL ${name}: ${err.message}`);
51
+ },
52
+ );
53
+ }
54
+ console.log(` ok ${name}`);
55
+ } catch (err) {
56
+ errors.push({ name, err });
57
+ console.error(` FAIL ${name}: ${err.message}`);
58
+ }
59
+ }
60
+
61
+ console.log("[voice-mirror smoke] starting");
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // 1. Cypher forbidden-pattern gate (Task 458).
65
+ // No NULLS LAST / NULLS FIRST / RETURNING in tool source files.
66
+ // These patterns are Postgres-isms; neo4j-driver silently ignores or
67
+ // errors on them. The gate runs on .ts source files so it catches issues
68
+ // before compilation.
69
+ // ---------------------------------------------------------------------------
70
+ console.log("\n-- Cypher gate --");
71
+ const FORBIDDEN_PATTERNS = [/NULLS\s+LAST/i, /NULLS\s+FIRST/i, /\bRETURNING\b/];
72
+
73
+ function scanFile(filePath) {
74
+ const content = readFileSync(filePath, "utf-8");
75
+ const hits = [];
76
+ for (const pat of FORBIDDEN_PATTERNS) {
77
+ if (pat.test(content)) hits.push(pat.toString());
78
+ }
79
+ return hits;
80
+ }
81
+
82
+ function scanDir(dirPath) {
83
+ const allHits = {};
84
+ for (const entry of readdirSync(dirPath)) {
85
+ if (!entry.endsWith(".ts")) continue;
86
+ const filePath = join(dirPath, entry);
87
+ const hits = scanFile(filePath);
88
+ if (hits.length > 0) allHits[filePath] = hits;
89
+ }
90
+ return allHits;
91
+ }
92
+
93
+ await check("no forbidden Cypher patterns in tool sources", () => {
94
+ const toolHits = scanDir(TOOLS_SRC);
95
+ const libHits = scanDir(LIB_SRC);
96
+ const allHits = { ...toolHits, ...libHits };
97
+ const fileList = Object.keys(allHits);
98
+ assert.equal(
99
+ fileList.length,
100
+ 0,
101
+ `Forbidden Cypher patterns found:\n${fileList.map((f) => ` ${f}: ${allHits[f].join(", ")}`).join("\n")}`,
102
+ );
103
+ });
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // 2. Module load + export shape checks.
107
+ // ---------------------------------------------------------------------------
108
+ console.log("\n-- Module shapes --");
109
+ const tagMod = await import("../dist/tools/voice-tag-content.js");
110
+ const distilMod = await import("../dist/tools/voice-distil-profile.js");
111
+ const retrieveMod = await import("../dist/tools/voice-retrieve-conditioning.js");
112
+ const feedbackMod = await import("../dist/tools/voice-record-feedback.js");
113
+ const ingestMod = await import("../dist/tools/voice-ingest-session-text.js");
114
+ const corpusMod = await import("../dist/lib/voice-corpus.js");
115
+
116
+ await check("voice-tag-content exports voiceTagContent function", () => {
117
+ assert.equal(typeof tagMod.voiceTagContent, "function");
118
+ });
119
+ await check("voice-tag-content exports AUTHORSHIP_MODES set of 5", () => {
120
+ const expected = [
121
+ "human-only",
122
+ "human-led-agent-assisted",
123
+ "agent-led-human-reviewed",
124
+ "agent-only",
125
+ "unknown",
126
+ ];
127
+ assert.equal(tagMod.AUTHORSHIP_MODES.size, 5);
128
+ for (const m of expected) assert.ok(tagMod.AUTHORSHIP_MODES.has(m), `missing ${m}`);
129
+ });
130
+ await check("voice-distil-profile exports voiceDistilProfile function", () => {
131
+ assert.equal(typeof distilMod.voiceDistilProfile, "function");
132
+ });
133
+ await check("voice-retrieve-conditioning exports voiceRetrieveConditioning function", () => {
134
+ assert.equal(typeof retrieveMod.voiceRetrieveConditioning, "function");
135
+ });
136
+ await check("voice-record-feedback exports voiceRecordFeedback function", () => {
137
+ assert.equal(typeof feedbackMod.voiceRecordFeedback, "function");
138
+ });
139
+ await check("voice-ingest-session-text exports required functions", () => {
140
+ assert.equal(typeof ingestMod.voiceIngestSessionText, "function");
141
+ assert.equal(typeof ingestMod.filterOperatorText, "function");
142
+ });
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // 3. voice-corpus exports — format axis (Task 462).
146
+ // ---------------------------------------------------------------------------
147
+ console.log("\n-- voice-corpus format exports --");
148
+ await check("VOICE_CORPUS_WHERE is non-empty string with both predicates", () => {
149
+ assert.equal(typeof corpusMod.VOICE_CORPUS_WHERE, "string");
150
+ assert.ok(corpusMod.VOICE_CORPUS_WHERE.includes("authorshipMode IN"));
151
+ assert.ok(corpusMod.VOICE_CORPUS_WHERE.includes("human-only"));
152
+ assert.ok(corpusMod.VOICE_CORPUS_WHERE.includes("Section"));
153
+ });
154
+ await check("TAGGABLE_PRIMARY_LABELS covers the three content labels", () => {
155
+ const labels = [...corpusMod.TAGGABLE_PRIMARY_LABELS];
156
+ assert.deepEqual(labels.sort(), ["KnowledgeDocument", "Message", "SocialPost"]);
157
+ });
158
+ await check("FORMAT_VALUES covers all six writing formats", () => {
159
+ const expected = ["text", "email", "social-post", "article", "marketing-copy", "note"];
160
+ const actual = [...corpusMod.FORMAT_VALUES].sort();
161
+ assert.deepEqual(actual.sort(), expected.sort());
162
+ });
163
+ await check("voiceCorpusWhereWithFormat appends format predicate", () => {
164
+ const result = corpusMod.voiceCorpusWhereWithFormat("email");
165
+ assert.ok(typeof result === "string");
166
+ assert.ok(result.includes(corpusMod.VOICE_CORPUS_WHERE));
167
+ assert.ok(result.includes("n.format = $format"));
168
+ assert.ok(result.includes("email") || result.includes("$format"));
169
+ });
170
+ await check("voiceCorpusWhereWithFormatAndAuthor appends format + author predicates", () => {
171
+ const result = corpusMod.voiceCorpusWhereWithFormatAndAuthor("article");
172
+ assert.ok(result.includes(corpusMod.VOICE_CORPUS_WHERE));
173
+ assert.ok(result.includes("n.format = $format"));
174
+ assert.ok(result.includes("n.voiceAuthor = $voiceAuthor"));
175
+ });
176
+ await check("ORG_USER_ID sentinel + profileUserIdForScope map scope→userId", () => {
177
+ assert.equal(corpusMod.ORG_USER_ID, "__org__");
178
+ assert.equal(corpusMod.profileUserIdForScope("org", "ua"), "__org__");
179
+ assert.equal(corpusMod.profileUserIdForScope("personal", "ua"), "ua");
180
+ });
181
+
182
+ // ---------------------------------------------------------------------------
183
+ // 4. deriveFormat is gone (Task 471) — format is operator-supplied editorial.
184
+ // ---------------------------------------------------------------------------
185
+ console.log("\n-- format is operator-supplied --");
186
+ await check("deriveFormat export is removed from voice-corpus", () => {
187
+ assert.equal(corpusMod.deriveFormat, undefined);
188
+ });
189
+
190
+ // ---------------------------------------------------------------------------
191
+ // 5. Error-vs-no-data discrimination for voice-retrieve-conditioning (Task 493).
192
+ // Blank identity and a forced lookup failure must both return status:"error",
193
+ // distinct from the genuine no-data state — so the drafting agent never
194
+ // reports "no profile exists" when the lookup actually errored.
195
+ // ---------------------------------------------------------------------------
196
+ console.log("\n-- error-vs-no-data discrimination --");
197
+ await check(
198
+ "voice-retrieve-conditioning returns status:error on missing accountId",
199
+ async () => {
200
+ const result = await retrieveMod.voiceRetrieveConditioning({
201
+ accountId: "",
202
+ userId: "u",
203
+ brief: { format: "text", length: "short" },
204
+ });
205
+ assert.equal(result.status, "error");
206
+ assert.equal(result.styleCard, null);
207
+ assert.deepEqual(result.exemplars, []);
208
+ },
209
+ );
210
+ await check(
211
+ "voice-retrieve-conditioning returns status:error on missing userId (personal scope)",
212
+ async () => {
213
+ // Default scope is personal, which genuinely needs the caller's userId.
214
+ const result = await retrieveMod.voiceRetrieveConditioning({
215
+ accountId: "acc",
216
+ userId: "",
217
+ brief: { format: "email", length: "long" },
218
+ });
219
+ assert.equal(result.status, "error");
220
+ assert.equal(result.error, "missing accountId/userId");
221
+ assert.equal(result.styleCard, null);
222
+ assert.deepEqual(result.exemplars, []);
223
+ },
224
+ );
225
+ await check(
226
+ "voice-retrieve-conditioning org scope does not require a userId",
227
+ async () => {
228
+ // org scope is account-wide (keyed on ORG_USER_ID + accountId) and never
229
+ // reads a userId, so a blank userId must NOT trip the missing-identity
230
+ // guard. Force the Neo4j lookup to fail so the guard's absence is provable:
231
+ // the call reaches the lookup and returns the connection error, never
232
+ // "missing accountId/userId". Save/restore the env + reset the singleton.
233
+ const { closeDriver } = await import("../dist/lib/neo4j.js");
234
+ const savedUri = process.env.NEO4J_URI;
235
+ try {
236
+ process.env.NEO4J_URI = "";
237
+ await closeDriver();
238
+ const result = await retrieveMod.voiceRetrieveConditioning({
239
+ accountId: "acc",
240
+ userId: "",
241
+ brief: { format: "article", length: "long", scope: "org" },
242
+ });
243
+ assert.equal(result.status, "error");
244
+ assert.notEqual(
245
+ result.error,
246
+ "missing accountId/userId",
247
+ "org scope must not trip the missing-identity guard on a blank userId",
248
+ );
249
+ } finally {
250
+ if (savedUri === undefined) delete process.env.NEO4J_URI;
251
+ else process.env.NEO4J_URI = savedUri;
252
+ await closeDriver();
253
+ }
254
+ },
255
+ );
256
+ await check(
257
+ "voice-retrieve-conditioning returns status:error (not no-data) when the lookup throws",
258
+ async () => {
259
+ // Force the Neo4j call to fail: an empty NEO4J_URI makes getSession()
260
+ // throw inside the try block. Save/restore the env and reset the driver
261
+ // singleton so neither this check nor later checks inherit the empty URI.
262
+ const { closeDriver } = await import("../dist/lib/neo4j.js");
263
+ const savedUri = process.env.NEO4J_URI;
264
+ try {
265
+ process.env.NEO4J_URI = "";
266
+ await closeDriver();
267
+ const result = await retrieveMod.voiceRetrieveConditioning({
268
+ accountId: "acc",
269
+ userId: "user",
270
+ brief: { format: "text", length: "short" },
271
+ });
272
+ assert.equal(result.status, "error");
273
+ assert.notEqual(result.status, "no-data");
274
+ assert.equal(result.styleCard, null);
275
+ assert.deepEqual(result.exemplars, []);
276
+ } finally {
277
+ if (savedUri === undefined) delete process.env.NEO4J_URI;
278
+ else process.env.NEO4J_URI = savedUri;
279
+ await closeDriver();
280
+ }
281
+ },
282
+ );
283
+
284
+ // ---------------------------------------------------------------------------
285
+ // 6. voice-tag-content enum validation.
286
+ // ---------------------------------------------------------------------------
287
+ console.log("\n-- voice-tag-content validation --");
288
+ await check("voice-tag-content rejects an invalid mode", async () => {
289
+ await assert.rejects(
290
+ () =>
291
+ tagMod.voiceTagContent({
292
+ nodeIds: ["x"],
293
+ mode: "not-a-mode",
294
+ accountId: "acc",
295
+ format: "text",
296
+ }),
297
+ /invalid authorshipMode/,
298
+ );
299
+ });
300
+ await check("voice-tag-content rejects an invalid format", async () => {
301
+ await assert.rejects(
302
+ () =>
303
+ tagMod.voiceTagContent({
304
+ nodeIds: ["x"],
305
+ mode: "human-only",
306
+ accountId: "acc",
307
+ format: "bad-format",
308
+ }),
309
+ /invalid format/,
310
+ );
311
+ });
312
+ await check("voice-tag-content rejects empty accountId", async () => {
313
+ await assert.rejects(
314
+ () =>
315
+ tagMod.voiceTagContent({
316
+ nodeIds: ["x"],
317
+ mode: "human-only",
318
+ accountId: "",
319
+ format: "text",
320
+ }),
321
+ /accountId is required/,
322
+ );
323
+ });
324
+ await check("voice-tag-content rejects missing format", async () => {
325
+ await assert.rejects(
326
+ () =>
327
+ tagMod.voiceTagContent({
328
+ nodeIds: ["x"],
329
+ mode: "human-only",
330
+ accountId: "acc",
331
+ }),
332
+ /format is required/,
333
+ );
334
+ });
335
+ await check("voice-tag-content returns zero counts on empty nodeIds (no DB hit)", async () => {
336
+ const result = await tagMod.voiceTagContent({
337
+ nodeIds: [],
338
+ mode: "human-only",
339
+ accountId: "acc",
340
+ format: "text",
341
+ });
342
+ assert.deepEqual(result, { updated: 0, skipped: 0, skippedReasons: {} });
343
+ });
344
+ await check("voice-tag-content requires voiceAuthor when there are nodes to tag", async () => {
345
+ await assert.rejects(
346
+ () =>
347
+ tagMod.voiceTagContent({
348
+ nodeIds: ["x"],
349
+ mode: "human-only",
350
+ accountId: "acc",
351
+ format: "text",
352
+ }),
353
+ /voiceAuthor is required/,
354
+ );
355
+ });
356
+ await check("resolveVoiceAuthor: explicit author wins, omitted defaults to operator, neither throws", () => {
357
+ assert.equal(tagMod.resolveVoiceAuthor("B", "ua"), "B");
358
+ assert.equal(tagMod.resolveVoiceAuthor(undefined, "ua"), "ua");
359
+ assert.equal(tagMod.resolveVoiceAuthor(" ", "ua"), "ua");
360
+ assert.throws(() => tagMod.resolveVoiceAuthor(undefined, null));
361
+ });
362
+
363
+ // ---------------------------------------------------------------------------
364
+ // 7. voice-ingest-session-text: operator-turn filter (no DB required).
365
+ // ---------------------------------------------------------------------------
366
+ console.log("\n-- operator-turn filter --");
367
+
368
+ await check("filterOperatorText: real turn is kept (and trimmed)", () => {
369
+ assert.equal(ingestMod.filterOperatorText(" Hello world "), "Hello world");
370
+ });
371
+ await check("filterOperatorText: slash command is excluded", () => {
372
+ assert.equal(ingestMod.filterOperatorText("/end"), null);
373
+ });
374
+ await check("filterOperatorText: system-reminder is excluded", () => {
375
+ assert.equal(
376
+ ingestMod.filterOperatorText("<system-reminder>some injected text</system-reminder>"),
377
+ null,
378
+ );
379
+ });
380
+ await check("filterOperatorText: empty / whitespace-only is excluded", () => {
381
+ assert.equal(ingestMod.filterOperatorText(" "), null);
382
+ });
383
+ await check("filterOperatorText: non-string is excluded", () => {
384
+ assert.equal(ingestMod.filterOperatorText(undefined), null);
385
+ assert.equal(ingestMod.filterOperatorText(42), null);
386
+ });
387
+ await check("filterOperatorText: paste block >= 4096 chars is excluded", () => {
388
+ assert.equal(ingestMod.filterOperatorText("x".repeat(4096)), null);
389
+ assert.equal(ingestMod.filterOperatorText("x".repeat(4097)), null);
390
+ });
391
+ await check("filterOperatorText: 4095 chars is included", () => {
392
+ const body = "x".repeat(4095);
393
+ assert.equal(ingestMod.filterOperatorText(body), body);
394
+ });
395
+
396
+ // turns-array semantics: a mixed array filters down to the real turns.
397
+ await check(
398
+ "turns array: 3 real turns + 3 excluded → filterOperatorText keeps 3",
399
+ () => {
400
+ const turns = [
401
+ "First real turn",
402
+ "Second real turn",
403
+ "/end", // slash command
404
+ "<system-reminder>injected</system-reminder>", // harness injection
405
+ "Third real turn",
406
+ " ", // whitespace only
407
+ ];
408
+ const kept = turns.map((t) => ingestMod.filterOperatorText(t)).filter((t) => t !== null);
409
+ assert.deepEqual(kept, ["First real turn", "Second real turn", "Third real turn"]);
410
+ },
411
+ );
412
+
413
+ // ---------------------------------------------------------------------------
414
+ // Final summary.
415
+ // ---------------------------------------------------------------------------
416
+ if (errors.length > 0) {
417
+ console.error(`\n[voice-mirror smoke] FAILED — ${errors.length} assertion(s)`);
418
+ process.exit(1);
419
+ }
420
+ console.log("\n[voice-mirror smoke] all passed");