@rubytech/create-maxy-code 0.1.254 → 0.1.256

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 (357) hide show
  1. package/dist/__tests__/plugin-install.test.js +58 -40
  2. package/dist/index.js +77 -26
  3. package/dist/lib/plugin-install.js +31 -29
  4. package/package.json +1 -1
  5. package/payload/platform/.docs/search-surface-contract.md +58 -0
  6. package/payload/platform/config/brand-registry.json +8 -0
  7. package/payload/platform/config/brand.json +3 -3
  8. package/payload/platform/lib/embed-client/dist/index.d.ts +4 -0
  9. package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -0
  10. package/payload/platform/lib/embed-client/dist/index.js +53 -0
  11. package/payload/platform/lib/embed-client/dist/index.js.map +1 -0
  12. package/payload/platform/lib/embed-client/src/index.ts +53 -0
  13. package/payload/platform/lib/embed-client/tsconfig.json +8 -0
  14. package/payload/platform/lib/graph-search/dist/index.d.ts +27 -6
  15. package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -1
  16. package/payload/platform/lib/graph-search/dist/index.js +19 -1
  17. package/payload/platform/lib/graph-search/dist/index.js.map +1 -1
  18. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +12 -0
  19. package/payload/platform/lib/graph-search/src/index.ts +28 -6
  20. package/payload/platform/lib/graph-write/dist/index.d.ts +25 -0
  21. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  22. package/payload/platform/lib/graph-write/dist/index.js +80 -2
  23. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  24. package/payload/platform/lib/graph-write/src/index.ts +98 -1
  25. package/payload/platform/neo4j/schema.cypher +126 -0
  26. package/payload/platform/package.json +2 -2
  27. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  28. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  29. package/payload/platform/plugins/admin/PLUGIN.md +3 -6
  30. package/payload/platform/plugins/admin/mcp/dist/index.js +14 -60
  31. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  32. package/payload/platform/plugins/admin/skills/insight/SKILL.md +24 -0
  33. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +84 -31
  34. package/payload/platform/plugins/docs/PLUGIN.md +1 -0
  35. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  36. package/payload/platform/plugins/docs/references/deployment.md +18 -5
  37. package/payload/platform/plugins/docs/references/graph.md +2 -0
  38. package/payload/platform/plugins/docs/references/internals.md +12 -1
  39. package/payload/platform/plugins/docs/references/memory-guide.md +4 -0
  40. package/payload/platform/plugins/docs/references/neo4j.md +2 -2
  41. package/payload/platform/plugins/docs/references/platform.md +1 -1
  42. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  43. package/payload/platform/plugins/docs/references/session-retrospective.md +5 -18
  44. package/payload/platform/plugins/docs/references/slides.md +31 -0
  45. package/payload/platform/plugins/docs/references/voice-mirror-guide.md +1 -1
  46. package/payload/platform/plugins/email/PLUGIN.md +2 -2
  47. package/payload/platform/plugins/email/mcp/dist/index.js +8 -0
  48. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  49. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +19 -0
  50. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -0
  51. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +64 -0
  52. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -0
  53. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +4 -0
  54. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
  55. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +1 -0
  56. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
  57. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts +1 -0
  58. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
  59. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +6 -1
  60. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
  61. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts +1 -0
  62. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
  63. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +7 -1
  64. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
  65. package/payload/platform/plugins/email/references/email-reference.md +4 -0
  66. package/payload/platform/plugins/memory/PLUGIN.md +1 -2
  67. package/payload/platform/plugins/memory/mcp/dist/index.js +6 -44
  68. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  69. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts +2 -0
  70. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts.map +1 -0
  71. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js +41 -0
  72. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js.map +1 -0
  73. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts +2 -0
  74. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts.map +1 -0
  75. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js +90 -0
  76. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js.map +1 -0
  77. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts +2 -0
  78. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts.map +1 -0
  79. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js +27 -0
  80. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js.map +1 -0
  81. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts +10 -0
  82. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts.map +1 -0
  83. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js +47 -0
  84. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js.map +1 -0
  85. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +1 -2
  86. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -1
  87. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +5 -28
  88. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -1
  89. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts +2 -0
  90. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts.map +1 -0
  91. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js +20 -0
  92. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js.map +1 -0
  93. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts +2 -0
  94. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts.map +1 -0
  95. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js +67 -0
  96. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js.map +1 -0
  97. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts +2 -0
  98. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts.map +1 -0
  99. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +34 -0
  100. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -0
  101. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts +2 -0
  102. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts.map +1 -0
  103. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js +61 -0
  104. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js.map +1 -0
  105. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +23 -1
  106. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
  107. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts +2 -0
  108. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts.map +1 -0
  109. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js +87 -0
  110. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js.map +1 -0
  111. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +3 -0
  112. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -1
  113. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts +2 -0
  114. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts.map +1 -0
  115. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js +34 -0
  116. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js.map +1 -0
  117. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
  118. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +19 -4
  119. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
  120. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +33 -6
  121. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
  122. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +280 -10
  123. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
  124. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -1
  125. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +76 -37
  126. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -1
  127. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
  128. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +11 -2
  129. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
  130. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +4 -4
  131. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +3 -3
  132. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  133. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +20 -2
  134. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  135. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +6 -3
  136. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
  137. package/payload/platform/plugins/memory/mcp/vitest.config.ts +5 -0
  138. package/payload/platform/plugins/memory/references/schema-base.md +1 -1
  139. package/payload/platform/plugins/memory/references/schema-construction.md +72 -0
  140. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts.map +1 -1
  141. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js +15 -0
  142. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js.map +1 -1
  143. package/payload/platform/plugins/slides/.claude-plugin/plugin.json +8 -0
  144. package/payload/platform/plugins/slides/LICENSE +21 -0
  145. package/payload/platform/plugins/slides/PLUGIN.md +18 -0
  146. package/payload/platform/plugins/slides/PROVENANCE.md +40 -0
  147. package/payload/platform/plugins/slides/commands/add-slide.md +29 -0
  148. package/payload/platform/plugins/slides/commands/slides-claus.md +39 -0
  149. package/payload/platform/plugins/slides/commands/slides-new-component.md +39 -0
  150. package/payload/platform/plugins/slides/commands/slides-outline.md +43 -0
  151. package/payload/platform/plugins/slides/commands/slides-review.md +52 -0
  152. package/payload/platform/plugins/slides/commands/slides-theme.md +64 -0
  153. package/payload/platform/plugins/slides/commands/slides.md +59 -0
  154. package/payload/platform/plugins/slides/skills/deck-system/REFERENCE.md +581 -0
  155. package/payload/platform/plugins/slides/skills/deck-system/SKILL.md +607 -0
  156. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-board.md +426 -0
  157. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-claus.md +185 -0
  158. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-mbb.md +450 -0
  159. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-product-launch.md +579 -0
  160. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sales.md +464 -0
  161. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sequoia.md +489 -0
  162. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING.md +273 -0
  163. package/payload/platform/plugins/slides/skills/deck-system/deck-craft.html +1371 -0
  164. package/payload/platform/plugins/slides/skills/deck-system/deck-solid.html +1667 -0
  165. package/payload/platform/plugins/slides/skills/deck-system/deck.html +1359 -0
  166. package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +1 -1
  167. package/payload/platform/plugins/url-get/PLUGIN.md +26 -21
  168. package/payload/platform/plugins/url-get/mcp/dist/index.js +3 -3
  169. package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -1
  170. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +1 -2
  171. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -1
  172. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +20 -40
  173. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -1
  174. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +4 -0
  175. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -1
  176. package/payload/platform/scripts/identity-forbidden-token-check.mjs +0 -1
  177. package/payload/platform/scripts/setup-account.sh +0 -15
  178. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts +23 -0
  179. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts.map +1 -0
  180. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js +29 -0
  181. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js.map +1 -0
  182. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  183. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -2
  184. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  185. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +5 -0
  186. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  187. package/payload/platform/services/claude-session-manager/dist/http-server.js +32 -2
  188. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  189. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  190. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +8 -1
  191. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  192. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +13 -1
  193. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -1
  194. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +26 -2
  195. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -1
  196. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +2 -2
  197. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  198. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +12 -3
  199. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  200. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +3 -2
  201. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  202. package/payload/platform/templates/agents/admin/IDENTITY.md +2 -2
  203. package/payload/platform/templates/specialists/agents/database-operator.md +3 -7
  204. package/payload/platform/templates/specialists/agents/typed-edge-classifier.md +1 -1
  205. package/payload/premium-plugins/writer-craft/PLUGIN.md +2 -2
  206. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +5 -5
  207. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
  208. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +1 -1
  209. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +1 -1
  210. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts +4 -8
  211. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -1
  212. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js +30 -98
  213. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js.map +1 -1
  214. package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +37 -114
  215. package/payload/premium-plugins/writer-craft/mcp/src/index.ts +5 -5
  216. package/payload/premium-plugins/writer-craft/mcp/src/lib/voice-corpus.ts +1 -1
  217. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-ingest-session-text.ts +29 -106
  218. package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +15 -17
  219. package/payload/server/{chunk-M6A6EZD4.js → chunk-76HRO7NX.js} +16 -2
  220. package/payload/server/maxy-edge.js +1 -1
  221. package/payload/server/public/assets/AdminShell-T-YknnBn.js +1 -0
  222. package/payload/server/public/assets/Checkbox-DmDxpqVv.js +1 -0
  223. package/payload/server/public/assets/admin-COUV-jgt.js +1 -0
  224. package/payload/server/public/assets/{arc-aUiRP9AS.js → arc-B2CweJq3.js} +1 -1
  225. package/payload/server/public/assets/architecture-YZFGNWBL-Dnn6Hc65.js +1 -0
  226. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-c09loTER.js → architectureDiagram-Q4EWVU46-DP2o-MFV.js} +1 -1
  227. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-Cjdeyoq1.js → blockDiagram-DXYQGD6D-DO4mcYDJ.js} +1 -1
  228. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-NY6Wlzo2.js → c4Diagram-AHTNJAMY-Sy1giHbj.js} +1 -1
  229. package/payload/server/public/assets/channel-CEpR_0rE.js +1 -0
  230. package/payload/server/public/assets/{chunk-2KRD3SAO-BK3470lx.js → chunk-2KRD3SAO-CKsCYCsN.js} +1 -1
  231. package/payload/server/public/assets/chunk-336JU56O-C0-P-aUF.js +2 -0
  232. package/payload/server/public/assets/chunk-426QAEUC-DFjEt3Zb.js +1 -0
  233. package/payload/server/public/assets/{chunk-4BX2VUAB-BOvVdJLf.js → chunk-4BX2VUAB-B8bqAmBa.js} +1 -1
  234. package/payload/server/public/assets/{chunk-4TB4RGXK-BXpto3yW.js → chunk-4TB4RGXK-D1k0VSlW.js} +1 -1
  235. package/payload/server/public/assets/{chunk-55IACEB6-BwZyF7vR.js → chunk-55IACEB6-B-p_QNqz.js} +1 -1
  236. package/payload/server/public/assets/{chunk-5FUZZQ4R-C403gCUk.js → chunk-5FUZZQ4R-D6U6tV_j.js} +1 -1
  237. package/payload/server/public/assets/{chunk-5PVQY5BW-CjVzXQEp.js → chunk-5PVQY5BW-CYK76xfs.js} +1 -1
  238. package/payload/server/public/assets/{chunk-67CJDMHE-D5bhMrtY.js → chunk-67CJDMHE-BC9js-lf.js} +1 -1
  239. package/payload/server/public/assets/{chunk-7N4EOEYR-Si7Lgrwc.js → chunk-7N4EOEYR-4j2OqKkv.js} +1 -1
  240. package/payload/server/public/assets/{chunk-AA7GKIK3-DMuHtDqO.js → chunk-AA7GKIK3-Coen-fXN.js} +1 -1
  241. package/payload/server/public/assets/{chunk-BSJP7CBP-L79XKVcb.js → chunk-BSJP7CBP-CAiOBvec.js} +1 -1
  242. package/payload/server/public/assets/{chunk-CIAEETIT-C0O7Upmg.js → chunk-CIAEETIT-AJzzpZVb.js} +1 -1
  243. package/payload/server/public/assets/{chunk-EDXVE4YY-DJcJAsAg.js → chunk-EDXVE4YY-BL4BKozX.js} +1 -1
  244. package/payload/server/public/assets/{chunk-ENJZ2VHE-CFDNvYu1.js → chunk-ENJZ2VHE-mhAFG8UD.js} +1 -1
  245. package/payload/server/public/assets/{chunk-FMBD7UC4-C_E43NFJ.js → chunk-FMBD7UC4-H231gZA_.js} +1 -1
  246. package/payload/server/public/assets/{chunk-FOC6F5B3-D9lWWHAu.js → chunk-FOC6F5B3-Cl3ZZjYG.js} +1 -1
  247. package/payload/server/public/assets/{chunk-ICPOFSXX-ecLOxGhL.js → chunk-ICPOFSXX-DOEzvzJa.js} +2 -2
  248. package/payload/server/public/assets/{chunk-K5T4RW27-DuhsNH4c.js → chunk-K5T4RW27-C_ipbUDD.js} +1 -1
  249. package/payload/server/public/assets/{chunk-KGLVRYIC-B4-A1Abi.js → chunk-KGLVRYIC-CTsDNSCU.js} +1 -1
  250. package/payload/server/public/assets/{chunk-LIHQZDEY-BxqgHRgT.js → chunk-LIHQZDEY-DvSXhkGf.js} +1 -1
  251. package/payload/server/public/assets/{chunk-ORNJ4GCN-DEYQ5WaJ.js → chunk-ORNJ4GCN-p574NOI7.js} +1 -1
  252. package/payload/server/public/assets/{chunk-OYMX7WX6-B7MW66KB.js → chunk-OYMX7WX6-BlEgFM6U.js} +1 -1
  253. package/payload/server/public/assets/chunk-QZHKN3VN-DpF06ZZQ.js +1 -0
  254. package/payload/server/public/assets/{chunk-U2HBQHQK-BMawmsyk.js → chunk-U2HBQHQK-B2bDK0jv.js} +1 -1
  255. package/payload/server/public/assets/{chunk-X2U36JSP-CT6g7pno.js → chunk-X2U36JSP-D69BxKFw.js} +1 -1
  256. package/payload/server/public/assets/{chunk-XPW4576I-CBfZXZDB.js → chunk-XPW4576I-Dm-PcyUi.js} +1 -1
  257. package/payload/server/public/assets/{chunk-YZCP3GAM-xeAluiAH.js → chunk-YZCP3GAM-Be8RnXgx.js} +1 -1
  258. package/payload/server/public/assets/{chunk-ZZ45TVLE-BRN9qUC5.js → chunk-ZZ45TVLE-Ck8PCTa4.js} +1 -1
  259. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CYbXvKLI.js +1 -0
  260. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DEyHzRhq.js +1 -0
  261. package/payload/server/public/assets/clone-y8gexbBy.js +1 -0
  262. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Br2gjtEO.js → cose-bilkent-S5V4N54A-CmkW2Eaj.js} +1 -1
  263. package/payload/server/public/assets/{dagre-DTjePoco.js → dagre-Dqp-ns8F.js} +1 -1
  264. package/payload/server/public/assets/{dagre-KV5264BT-DHBkRke4.js → dagre-KV5264BT-ZgWWXPLc.js} +1 -1
  265. package/payload/server/public/assets/data-gy6QH9c1.js +1 -0
  266. package/payload/server/public/assets/{diagram-5BDNPKRD-BIq1-idL.js → diagram-5BDNPKRD-CTX5-ScM.js} +1 -1
  267. package/payload/server/public/assets/{diagram-G4DWMVQ6-BsIUDzV6.js → diagram-G4DWMVQ6-BovIsO6H.js} +1 -1
  268. package/payload/server/public/assets/{diagram-MMDJMWI5-CgHSri2i.js → diagram-MMDJMWI5-DcETsQy-.js} +1 -1
  269. package/payload/server/public/assets/{diagram-TYMM5635-Ce2Wh9ZX.js → diagram-TYMM5635-yyq6peoZ.js} +1 -1
  270. package/payload/server/public/assets/{erDiagram-SMLLAGMA-BU0Kh6OQ.js → erDiagram-SMLLAGMA-CiNToftB.js} +1 -1
  271. package/payload/server/public/assets/{flatten-Bo6YRmWl.js → flatten-BtFI066E.js} +1 -1
  272. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B0N06MF7.js → flowDiagram-DWJPFMVM-Xnl3SpIM.js} +1 -1
  273. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BVbx4ARZ.js → ganttDiagram-T4ZO3ILL-C1iyWe0f.js} +1 -1
  274. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CNs-LD5i.js +1 -0
  275. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-C-xRJ94t.js → gitGraphDiagram-UUTBAWPF-D97pbMQb.js} +1 -1
  276. package/payload/server/public/assets/graph-labels-cZu4pK16.js +1 -0
  277. package/payload/server/public/assets/{graph-g48ZcA5M.js → graph-qz5tFKqU.js} +3 -3
  278. package/payload/server/public/assets/{graphlib-YmNcoMjY.js → graphlib-Lq8ijgON.js} +1 -1
  279. package/payload/server/public/assets/info-OMHHGYJF-DsTNigSS.js +1 -0
  280. package/payload/server/public/assets/infoDiagram-42DDH7IO-C_OarRTA.js +2 -0
  281. package/payload/server/public/assets/{isEmpty-D6Kr-M1M.js → isEmpty-D6QovjYR.js} +1 -1
  282. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DTrq54yC.js → ishikawaDiagram-UXIWVN3A-B8XBdjJn.js} +1 -1
  283. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-OZZZMrFX.js → journeyDiagram-VCZTEJTY-CZYbiOaQ.js} +1 -1
  284. package/payload/server/public/assets/{kanban-definition-6JOO6SKY--w-IP9pN.js → kanban-definition-6JOO6SKY-B1PybFoh.js} +1 -1
  285. package/payload/server/public/assets/{line-Ckeulv5T.js → line-D-tw3hHp.js} +1 -1
  286. package/payload/server/public/assets/{linear-DOh_6k2k.js → linear-BHhXD3cd.js} +1 -1
  287. package/payload/server/public/assets/{mermaid-parser.core-CVRAxYRD.js → mermaid-parser.core-C9RAnysF.js} +2 -2
  288. package/payload/server/public/assets/{mermaid.core-B-mE18I1.js → mermaid.core-B532LT1r.js} +3 -3
  289. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-Bm8mDicL.js → mindmap-definition-QFDTVHPH-DGlgeeTV.js} +1 -1
  290. package/payload/server/public/assets/{ordinal-BDi6f4xk.js → ordinal-Bl-aM5b9.js} +1 -1
  291. package/payload/server/public/assets/packet-4T2RLAQJ-DGES22b-.js +1 -0
  292. package/payload/server/public/assets/pie-ZZUOXDRM-ChKeDbzt.js +1 -0
  293. package/payload/server/public/assets/{pieDiagram-DEJITSTG-BCmRLgGO.js → pieDiagram-DEJITSTG-DV9FIWko.js} +1 -1
  294. package/payload/server/public/assets/{public-DknO-g9S.js → public-Bu2_Xi0a.js} +5 -5
  295. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CniTIUTm.js → quadrantDiagram-34T5L4WZ-Betwya4l.js} +1 -1
  296. package/payload/server/public/assets/radar-PYXPWWZC-FGG5Fs7N.js +1 -0
  297. package/payload/server/public/assets/{reduce-CGi9ik8i.js → reduce-BD4xUd2c.js} +1 -1
  298. package/payload/server/public/assets/{requirementDiagram-MS252O5E-CoxBSj9M.js → requirementDiagram-MS252O5E-Cq3vODdg.js} +1 -1
  299. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BjS-4jzq.js → sankeyDiagram-XADWPNL6-x8krXWcS.js} +1 -1
  300. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-B9jVOnPR.js → sequenceDiagram-FGHM5R23-i-_uH-Yl.js} +1 -1
  301. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BvOQPzP8.js → stateDiagram-FHFEXIEX-il4KqSgI.js} +1 -1
  302. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B6zNJ6Tv.js +1 -0
  303. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CdfgWLo1.js → timeline-definition-GMOUNBTQ-DATdZkA5.js} +1 -1
  304. package/payload/server/public/assets/treeView-SZITEDCU-VAQQdbtf.js +1 -0
  305. package/payload/server/public/assets/treemap-W4RFUUIX-DKchO3zI.js +1 -0
  306. package/payload/server/public/assets/useSelectionMode-A5KItZ2T.js +13 -0
  307. package/payload/server/public/assets/{brand-D0gNihp7.css → useSelectionMode-C-Ojh7W9.css} +1 -1
  308. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-JCgpIbj-.js → vennDiagram-DHZGUBPP-BJh9tJTt.js} +1 -1
  309. package/payload/server/public/assets/wardley-RL74JXVD-CBGtx0bS.js +1 -0
  310. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Dei3VqHo.js → wardleyDiagram-NUSXRM2D-EMN1Hdfg.js} +1 -1
  311. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DUtIyoIb.js → xychartDiagram-5P7HB3ND-DbUWXa7T.js} +1 -1
  312. package/payload/server/public/data.html +5 -5
  313. package/payload/server/public/graph.html +6 -6
  314. package/payload/server/public/index.html +5 -6
  315. package/payload/server/public/public.html +4 -5
  316. package/payload/server/server.js +525 -39
  317. package/payload/platform/plugins/admin/hooks/__tests__/session-end-retrospective.test.sh +0 -396
  318. package/payload/platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh +0 -239
  319. package/payload/platform/plugins/admin/hooks/session-end-retrospective.sh +0 -214
  320. package/payload/premium-plugins/writer-craft/hooks/__tests__/voice-session-end-text.test.sh +0 -284
  321. package/payload/premium-plugins/writer-craft/hooks/voice-session-end-text.sh +0 -75
  322. package/payload/premium-plugins/writer-craft/mcp/src/cli/ingest-session-text.ts +0 -65
  323. package/payload/server/public/assets/AdminShell-892Jy_rs.js +0 -1
  324. package/payload/server/public/assets/Checkbox-Bc2QzX9b.js +0 -1
  325. package/payload/server/public/assets/admin-D3K13ndi.js +0 -1
  326. package/payload/server/public/assets/architecture-YZFGNWBL--v-pJPNp.js +0 -1
  327. package/payload/server/public/assets/brand-CcN3dELF.js +0 -9
  328. package/payload/server/public/assets/channel-B1IT7to2.js +0 -1
  329. package/payload/server/public/assets/chunk-336JU56O-CdKRCIeE.js +0 -2
  330. package/payload/server/public/assets/chunk-426QAEUC-BybuQ3Ve.js +0 -1
  331. package/payload/server/public/assets/chunk-QZHKN3VN-Bd-GrQM6.js +0 -1
  332. package/payload/server/public/assets/classDiagram-6PBFFD2Q-rjCize6i.js +0 -1
  333. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BORWOUt0.js +0 -1
  334. package/payload/server/public/assets/clone-Csqv5U6T.js +0 -1
  335. package/payload/server/public/assets/data-Br-pdljK.js +0 -1
  336. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CI0s_tqn.js +0 -1
  337. package/payload/server/public/assets/graph-labels-BYH-IPCb.js +0 -1
  338. package/payload/server/public/assets/info-OMHHGYJF-g3gYW7Qm.js +0 -1
  339. package/payload/server/public/assets/infoDiagram-42DDH7IO-Di6oPQ_-.js +0 -2
  340. package/payload/server/public/assets/packet-4T2RLAQJ-CT0TB9HI.js +0 -1
  341. package/payload/server/public/assets/pie-ZZUOXDRM-CXLe7TFF.js +0 -1
  342. package/payload/server/public/assets/radar-PYXPWWZC-DnPLBl-D.js +0 -1
  343. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-v4ND10uR.js +0 -1
  344. package/payload/server/public/assets/treeView-SZITEDCU-C3cb7Xwe.js +0 -1
  345. package/payload/server/public/assets/treemap-W4RFUUIX-Dc7G3Bgm.js +0 -1
  346. package/payload/server/public/assets/useSelectionMode-DwsyptOw.js +0 -5
  347. package/payload/server/public/assets/wardley-RL74JXVD-DtgibWAt.js +0 -1
  348. /package/payload/server/public/assets/{_baseFor-Cam2PbSt.js → _baseFor-Cs8Y-rGh.js} +0 -0
  349. /package/payload/server/public/assets/{array-DYRGGQae.js → array-iHZP4KWJ.js} +0 -0
  350. /package/payload/server/public/assets/{cytoscape.esm-nWsJMTNI.js → cytoscape.esm-BR2GOQ8_.js} +0 -0
  351. /package/payload/server/public/assets/{defaultLocale-Du1XY3Dp.js → defaultLocale-B9aLeOTg.js} +0 -0
  352. /package/payload/server/public/assets/{dist-BzAsli7o.js → dist-DB-VPj_8.js} +0 -0
  353. /package/payload/server/public/assets/{init-B5BXBRcm.js → init-BNFRgqHM.js} +0 -0
  354. /package/payload/server/public/assets/{katex-HOUACuRw.js → katex-B-EfS3nw.js} +0 -0
  355. /package/payload/server/public/assets/{path-CNO468J-.js → path-DmWWdwp7.js} +0 -0
  356. /package/payload/server/public/assets/{rough.esm-DRO6hWPh.js → rough.esm-Ci7Kjt46.js} +0 -0
  357. /package/payload/server/public/assets/{src-CWiyyVfn.js → src-C1jfwBq0.js} +0 -0
@@ -16,14 +16,13 @@
16
16
  * collapsing a failed lookup into the no-data payload.
17
17
  * 9. voice-tag-content validates mode and format enums, requires format,
18
18
  * and returns zero counts on empty nodeIds (with format supplied).
19
- * 11. voice-ingest-session-text: extractOperatorTurns() extracts real turns
19
+ * 11. voice-ingest-session-text: filterOperatorText() keeps real turns
20
20
  * and excludes slash commands, paste blocks, and system reminders.
21
21
  *
22
22
  * Exit code: 0 on pass, 1 on any assertion failure.
23
23
  */
24
24
  import { strict as assert } from "node:assert";
25
- import { readFileSync, writeFileSync, mkdtempSync, rmSync } from "node:fs";
26
- import { tmpdir } from "node:os";
25
+ import { readFileSync } from "node:fs";
27
26
  import { join, dirname } from "node:path";
28
27
  import { fileURLToPath } from "node:url";
29
28
  import { readdirSync } from "node:fs";
@@ -132,8 +131,7 @@ await check("voice-record-feedback exports voiceRecordFeedback function", () =>
132
131
  });
133
132
  await check("voice-ingest-session-text exports required functions", () => {
134
133
  assert.equal(typeof ingestMod.voiceIngestSessionText, "function");
135
- assert.equal(typeof ingestMod.extractOperatorTurns, "function");
136
- assert.equal(typeof ingestMod.extractOperatorText, "function");
134
+ assert.equal(typeof ingestMod.filterOperatorText, "function");
137
135
  });
138
136
 
139
137
  // ---------------------------------------------------------------------------
@@ -294,127 +292,52 @@ await check("voice-tag-content returns zero counts on empty nodeIds (no DB hit)"
294
292
  });
295
293
 
296
294
  // ---------------------------------------------------------------------------
297
- // 7. voice-ingest-session-text: JSONL extraction (no DB required).
295
+ // 7. voice-ingest-session-text: operator-turn filter (no DB required).
298
296
  // ---------------------------------------------------------------------------
299
- console.log("\n-- JSONL extraction --");
297
+ console.log("\n-- operator-turn filter --");
300
298
 
301
- function makeJsonlLine(type, role, content) {
302
- return JSON.stringify({ type, message: { role, content } });
303
- }
304
-
305
- await check("extractOperatorText: real user turn is extracted", () => {
306
- const record = { type: "user", message: { role: "user", content: "Hello world" } };
307
- const result = ingestMod.extractOperatorText(record);
308
- assert.equal(result, "Hello world");
309
- });
310
- await check("extractOperatorText: slash command is excluded", () => {
311
- const record = { type: "user", message: { role: "user", content: "/end" } };
312
- assert.equal(ingestMod.extractOperatorText(record), null);
299
+ await check("filterOperatorText: real turn is kept (and trimmed)", () => {
300
+ assert.equal(ingestMod.filterOperatorText(" Hello world "), "Hello world");
313
301
  });
314
- await check("extractOperatorText: system-reminder is excluded", () => {
315
- const record = {
316
- type: "user",
317
- message: { role: "user", content: "<system-reminder>some injected text</system-reminder>" },
318
- };
319
- assert.equal(ingestMod.extractOperatorText(record), null);
302
+ await check("filterOperatorText: slash command is excluded", () => {
303
+ assert.equal(ingestMod.filterOperatorText("/end"), null);
320
304
  });
321
- await check("extractOperatorText: paste block > 4096 chars is excluded", () => {
322
- const record = {
323
- type: "user",
324
- message: { role: "user", content: "x".repeat(4097) },
325
- };
326
- assert.equal(ingestMod.extractOperatorText(record), null);
305
+ await check("filterOperatorText: system-reminder is excluded", () => {
306
+ assert.equal(
307
+ ingestMod.filterOperatorText("<system-reminder>some injected text</system-reminder>"),
308
+ null,
309
+ );
327
310
  });
328
- await check("extractOperatorText: paste block = 4096 chars is excluded", () => {
329
- const record = {
330
- type: "user",
331
- message: { role: "user", content: "x".repeat(4096) },
332
- };
333
- assert.equal(ingestMod.extractOperatorText(record), null);
311
+ await check("filterOperatorText: empty / whitespace-only is excluded", () => {
312
+ assert.equal(ingestMod.filterOperatorText(" "), null);
334
313
  });
335
- await check("extractOperatorText: paste block = 4095 chars is included", () => {
336
- const body = "x".repeat(4095);
337
- const record = { type: "user", message: { role: "user", content: body } };
338
- assert.equal(ingestMod.extractOperatorText(record), body);
314
+ await check("filterOperatorText: non-string is excluded", () => {
315
+ assert.equal(ingestMod.filterOperatorText(undefined), null);
316
+ assert.equal(ingestMod.filterOperatorText(42), null);
339
317
  });
340
- await check("extractOperatorText: assistant turn is excluded", () => {
341
- const record = { type: "assistant", message: { role: "assistant", content: "Reply" } };
342
- assert.equal(ingestMod.extractOperatorText(record), null);
318
+ await check("filterOperatorText: paste block >= 4096 chars is excluded", () => {
319
+ assert.equal(ingestMod.filterOperatorText("x".repeat(4096)), null);
320
+ assert.equal(ingestMod.filterOperatorText("x".repeat(4097)), null);
343
321
  });
344
- await check("extractOperatorText: tool_result-only content is excluded", () => {
345
- const record = {
346
- type: "user",
347
- message: {
348
- role: "user",
349
- content: [{ type: "tool_result", tool_use_id: "x", content: "ok" }],
350
- },
351
- };
352
- assert.equal(ingestMod.extractOperatorText(record), null);
353
- });
354
- await check("extractOperatorText: content array with text block is extracted", () => {
355
- const record = {
356
- type: "user",
357
- message: {
358
- role: "user",
359
- content: [{ type: "text", text: "Hello from array" }],
360
- },
361
- };
362
- assert.equal(ingestMod.extractOperatorText(record), "Hello from array");
322
+ await check("filterOperatorText: 4095 chars is included", () => {
323
+ const body = "x".repeat(4095);
324
+ assert.equal(ingestMod.filterOperatorText(body), body);
363
325
  });
364
326
 
365
- // Full JSONL fixture: 3 real turns + 2 assistant + 1 slash + 1 system-reminder.
366
- // Expected: extractOperatorTurns returns 3 strings.
327
+ // turns-array semantics: a mixed array filters down to the real turns.
367
328
  await check(
368
- "extractOperatorTurns: fixture with 3 real turns + 4 excluded → 3 results",
369
- async () => {
370
- const tmp = mkdtempSync(join(tmpdir(), "smoke-ingest-"));
371
- const jsonlPath = join(tmp, "session.jsonl");
372
- const lines = [
373
- // 3 real operator turns
374
- makeJsonlLine("user", "user", "First real turn"),
375
- makeJsonlLine("user", "user", "Second real turn"),
376
- makeJsonlLine("user", "user", "Third real turn"),
377
- // 2 assistant turns
378
- makeJsonlLine("assistant", "assistant", "Agent reply 1"),
379
- makeJsonlLine("assistant", "assistant", "Agent reply 2"),
380
- // 1 slash command
381
- makeJsonlLine("user", "user", "/end"),
382
- // 1 system reminder
383
- makeJsonlLine("user", "user", "<system-reminder>injected</system-reminder>"),
329
+ "turns array: 3 real turns + 3 excluded → filterOperatorText keeps 3",
330
+ () => {
331
+ const turns = [
332
+ "First real turn",
333
+ "Second real turn",
334
+ "/end", // slash command
335
+ "<system-reminder>injected</system-reminder>", // harness injection
336
+ "Third real turn",
337
+ " ", // whitespace only
384
338
  ];
385
- writeFileSync(jsonlPath, lines.join("\n") + "\n");
386
- try {
387
- const turns = await ingestMod.extractOperatorTurns(jsonlPath);
388
- assert.equal(turns.length, 3, `expected 3 turns, got ${turns.length}`);
389
- assert.equal(turns[0], "First real turn");
390
- assert.equal(turns[1], "Second real turn");
391
- assert.equal(turns[2], "Third real turn");
392
- } finally {
393
- rmSync(tmp, { recursive: true, force: true });
394
- }
395
- },
396
- );
397
-
398
- // Second-run fixture: same lines written to same path → same 3 turns extracted.
399
- // (Actual dedup happens in the DB via contentHash MERGE; extraction is idempotent.)
400
- await check(
401
- "extractOperatorTurns: re-running same JSONL extracts same turns (dedup is in DB)",
402
- async () => {
403
- const tmp = mkdtempSync(join(tmpdir(), "smoke-ingest-dedup-"));
404
- const jsonlPath = join(tmp, "session.jsonl");
405
- const lines = [
406
- makeJsonlLine("user", "user", "Dedupe turn"),
407
- makeJsonlLine("user", "user", "/skip-cmd"),
408
- ];
409
- writeFileSync(jsonlPath, lines.join("\n") + "\n");
410
- try {
411
- const turns1 = await ingestMod.extractOperatorTurns(jsonlPath);
412
- const turns2 = await ingestMod.extractOperatorTurns(jsonlPath);
413
- assert.deepEqual(turns1, turns2, "idempotent: same JSONL gives same turns");
414
- assert.equal(turns1.length, 1);
415
- } finally {
416
- rmSync(tmp, { recursive: true, force: true });
417
- }
339
+ const kept = turns.map((t) => ingestMod.filterOperatorText(t)).filter((t) => t !== null);
340
+ assert.deepEqual(kept, ["First real turn", "Second real turn", "Third real turn"]);
418
341
  },
419
342
  );
420
343
 
@@ -348,13 +348,13 @@ server.tool(
348
348
 
349
349
  server.tool(
350
350
  "voice-ingest-session-text",
351
- "Ingest operator PTY turns from a Claude Code session JSONL as :Message {format:'text', source:'admin-pty', authorshipMode:'human-only'} corpus nodes. Deduplication via SHA256 contentHash — re-running against the same JSONL is a no-op. Triggers voice-distil-profile {format:'text'} after ingest (cadence guard decides whether distillation runs). Called automatically by the SessionEnd hook; can also be invoked manually.",
351
+ "Write operator turns from the current session as :Message {format:'text', source:'admin-pty', authorshipMode:'human-only'} corpus nodes. The admin agent reads its own operator turns from the live conversation context and passes them as `turns`. Deduplication via SHA256 contentHash — re-running with the same turns is a no-op. Triggers voice-distil-profile {format:'text'} after ingest (cadence guard decides whether distillation runs). Invoked on demand by the voice-mirror skill when the operator asks to capture this session's voice.",
352
352
  {
353
- sessionJsonlPath: z.string().min(1).describe("Absolute path to the Claude Code session JSONL file"),
354
- sessionId: z.string().optional().describe("Session ID for provenance; read from the SessionEnd envelope"),
353
+ turns: z.array(z.string()).describe("Operator turns the agent read from its own session context (one string per operator message). Slash commands, harness injections, and large paste blocks are filtered out by the tool."),
354
+ sessionId: z.string().optional().describe("Session ID for provenance."),
355
355
  userId: z.string().optional().describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
356
356
  },
357
- async ({ sessionJsonlPath, sessionId, userId }) => {
357
+ async ({ turns, sessionId, userId }) => {
358
358
  if (!accountId) return refuseNoAccount("voice-ingest-session-text");
359
359
  const resolvedUserId = userId ?? resolveUserId();
360
360
  if (!resolvedUserId) {
@@ -370,7 +370,7 @@ server.tool(
370
370
  }
371
371
  try {
372
372
  const result = await voiceIngestSessionText({
373
- sessionJsonlPath,
373
+ turns,
374
374
  accountId,
375
375
  userId: resolvedUserId,
376
376
  sessionId,
@@ -19,7 +19,7 @@ export function notTrashed(alias: string): string {
19
19
  *
20
20
  * Imported by `voice-distil-profile` (count + sample walks),
21
21
  * `voice-retrieve-conditioning` (exemplar walk), `voice-tag-content` (tag
22
- * writes), and `voice-ingest-session-text` (SessionEnd ingest). The single
22
+ * writes), and `voice-ingest-session-text` (on-demand session-text ingest). The single
23
23
  * load-bearing filter — when the corpus rules change, this is the only place
24
24
  * to edit.
25
25
  *
@@ -1,34 +1,29 @@
1
1
  /**
2
- * voice-ingest-session-text — extract operator turns from a Claude Code
3
- * session JSONL and write them as :Message {format:'text', source:'admin-pty'}
4
- * corpus nodes.
2
+ * voice-ingest-session-text — write operator turns the agent read from its
3
+ * own session context as :Message {format:'text', source:'admin-pty'} corpus
4
+ * nodes.
5
5
  *
6
- * Called by the SessionEnd hook (via the CLI wrapper) after each admin PTY
7
- * session. Re-running against the same JSONL is a no-op — MERGE on
8
- * (contentHash, accountId) is the deduplication primitive.
6
+ * Invoked on demand by the voice-mirror skill (Task 644): the operator asks to
7
+ * capture this session's voice, the admin agent extracts its own operator
8
+ * turns from the live conversation context, and passes them here as `turns`.
9
+ * Re-running with the same turns is a no-op — MERGE on (contentHash, accountId)
10
+ * is the deduplication primitive.
9
11
  *
10
12
  * After ingest, triggers voice-distil-profile {format:'text'} so the cadence
11
13
  * guard decides whether distillation runs.
12
14
  *
13
- * JSONL record shape expected (Claude Code session format):
14
- * { "type": "user" | "assistant", "message": { "role": "...", "content": ... }, ... }
15
- *
16
- * "Real operator text" extraction rules (excludes):
17
- * - type != "user" or message.role != "user" → not the operator
18
- * - content is tool_result-only → tool reply, not turn
15
+ * "Real operator text" filter (each supplied turn is excluded when):
16
+ * - text is empty after trimming → nothing to ingest
19
17
  * - text starts with "/" → slash command
20
18
  * - text contains "<system-reminder>" → harness injection
21
19
  * - text.length >= 4096 → likely pasted content
22
- * - text is empty after trimming → nothing to ingest
23
20
  */
24
21
  import { createHash } from "node:crypto";
25
- import { createReadStream } from "node:fs";
26
- import { createInterface } from "node:readline";
27
22
  import { getSession } from "../lib/neo4j.js";
28
23
  import { voiceDistilProfile } from "./voice-distil-profile.js";
29
24
 
30
25
  export interface VoiceIngestSessionTextParams {
31
- sessionJsonlPath: string;
26
+ turns: string[];
32
27
  accountId: string;
33
28
  userId: string;
34
29
  sessionId?: string;
@@ -41,109 +36,37 @@ export interface VoiceIngestSessionTextResult {
41
36
  }
42
37
 
43
38
  /**
44
- * Extracts text content from a "real operator" user record.
45
- * Returns null when the record should be skipped.
46
- */
47
- export function extractOperatorText(record: unknown): string | null {
48
- if (!record || typeof record !== "object") return null;
49
- const rec = record as Record<string, unknown>;
50
-
51
- if (rec["type"] !== "user") return null;
52
-
53
- const msg = rec["message"];
54
- if (!msg || typeof msg !== "object") return null;
55
- const message = msg as Record<string, unknown>;
56
- if (message["role"] !== "user") return null;
57
-
58
- const content = message["content"];
59
- let text = "";
60
-
61
- if (typeof content === "string") {
62
- text = content;
63
- } else if (Array.isArray(content)) {
64
- // Must have at least one non-tool_result block to be a real turn.
65
- const nonToolResult = content.filter(
66
- (b) => typeof b === "object" && b !== null && (b as Record<string, unknown>)["type"] !== "tool_result",
67
- );
68
- if (nonToolResult.length === 0) return null;
69
-
70
- // Collect text from all text-type content blocks.
71
- const parts: string[] = [];
72
- for (const block of content) {
73
- if (typeof block !== "object" || block === null) continue;
74
- const b = block as Record<string, unknown>;
75
- if (b["type"] === "text" && typeof b["text"] === "string") {
76
- parts.push(b["text"]);
77
- }
78
- }
79
- text = parts.join("");
80
- } else {
81
- return null;
82
- }
83
-
84
- text = text.trim();
85
- if (text.length === 0) return null;
86
-
87
- // Exclusions.
88
- if (text.startsWith("/")) return null; // slash command
89
- if (text.includes("<system-reminder>")) return null; // harness injection
90
- if (text.length >= 4096) return null; // paste block
91
-
92
- return text;
93
- }
94
-
95
- /**
96
- * Parse a session JSONL file and return all real operator turn texts.
39
+ * Applies the "real operator text" exclusions to a single supplied turn.
40
+ * Returns the trimmed text to ingest, or null when the turn should be skipped.
97
41
  * Exported for testability (no DB required).
98
42
  */
99
- export async function extractOperatorTurns(jsonlPath: string): Promise<string[]> {
100
- const turns: string[] = [];
101
-
102
- const rl = createInterface({
103
- input: createReadStream(jsonlPath, { encoding: "utf-8" }),
104
- crlfDelay: Infinity,
105
- });
106
-
107
- for await (const line of rl) {
108
- const trimmed = line.trim();
109
- if (!trimmed) continue;
110
- let record: unknown;
111
- try {
112
- record = JSON.parse(trimmed);
113
- } catch {
114
- continue;
115
- }
116
- const text = extractOperatorText(record);
117
- if (text !== null) {
118
- turns.push(text);
119
- }
120
- }
121
-
122
- return turns;
43
+ export function filterOperatorText(text: unknown): string | null {
44
+ if (typeof text !== "string") return null;
45
+ const trimmed = text.trim();
46
+ if (trimmed.length === 0) return null;
47
+ if (trimmed.startsWith("/")) return null; // slash command
48
+ if (trimmed.includes("<system-reminder>")) return null; // harness injection
49
+ if (trimmed.length >= 4096) return null; // paste block
50
+ return trimmed;
123
51
  }
124
52
 
125
53
  export async function voiceIngestSessionText(
126
54
  params: VoiceIngestSessionTextParams,
127
55
  ): Promise<VoiceIngestSessionTextResult> {
128
- const { sessionJsonlPath, accountId, userId, sessionId = null } = params;
56
+ const { turns, accountId, userId, sessionId = null } = params;
129
57
 
130
58
  if (!accountId || !userId) {
131
59
  throw new Error("voice-ingest-session-text: accountId and userId required");
132
60
  }
133
- if (!sessionJsonlPath) {
134
- throw new Error("voice-ingest-session-text: sessionJsonlPath required");
61
+ if (!Array.isArray(turns)) {
62
+ throw new Error("voice-ingest-session-text: turns array required");
135
63
  }
136
64
 
137
- // 1. Extract operator turns from the JSONL.
138
- let allTurns: string[];
139
- try {
140
- allTurns = await extractOperatorTurns(sessionJsonlPath);
141
- } catch (err) {
142
- throw new Error(
143
- `voice-ingest-session-text: failed to read JSONL at '${sessionJsonlPath}': ${
144
- err instanceof Error ? err.message : String(err)
145
- }`,
146
- );
65
+ // 1. Apply the operator-text filter to each supplied turn.
66
+ const allTurns: string[] = [];
67
+ for (const turn of turns) {
68
+ const text = filterOperatorText(turn);
69
+ if (text !== null) allTurns.push(text);
147
70
  }
148
71
 
149
72
  if (allTurns.length === 0) {
@@ -15,7 +15,7 @@ The skill is built on five deterministic MCP tools served by the `writer-craft`
15
15
  | `voice-distil-profile` | Walk the operator's `human-only` corpus for a given `format` and produce a `:VoiceProfile {styleCard, generatedAt, corpusSize, feedbackEntries, format}` node. Without a `format`, enumerates all formats present in the corpus and distils each. |
16
16
  | `voice-retrieve-conditioning` | Return `{styleCard, exemplars[]}` for a drafting brief. Requires `brief.format` (one of the six corpus formats). K=5 for short-form, K=15 for long-form. Token-budget bounded. |
17
17
  | `voice-record-feedback` | When the operator edits an agent draft, write a `:VoiceEdit {originalText, editedText, intent, occurredAt, format}-[:FEEDBACK_FOR]->(:VoiceProfile {format})` node. The `intent` field is a Haiku-summarised diff. |
18
- | `voice-ingest-session-text` | (Called by the SessionEnd hook, not directly.) Ingest operator PTY turns from the session transcript as `:Message {format:'text', authorshipMode:'human-only'}` corpus nodes. Deduplicates via `contentHash`. |
18
+ | `voice-ingest-session-text` | Write operator turns from the current session as `:Message {format:'text', authorshipMode:'human-only'}` corpus nodes. The agent reads its own operator turns from context and passes them as `turns`. Deduplicates via `contentHash`. Invoked on demand when the operator asks to capture this session's voice. |
19
19
 
20
20
  ## Surface — admin only, never delegated
21
21
 
@@ -32,6 +32,7 @@ Activate when the operator says any of:
32
32
  - **"Read my writing first" / "draft this in my voice" — when the operator is asking for a hand-written-quality draft, not a generic AI reply.** Drives `voice-retrieve-conditioning`; the calling drafting skill is the actual surface, this skill is the conditioning input.
33
33
  - **"Use my edit as a teaching example" / "remember how I changed that".** Drives `voice-record-feedback`.
34
34
  - **"Review my historical writing and tag it" / "start the backfill".** Drives the interactive backfill flow described below.
35
+ - **"Capture my voice from this chat" / "ingest this session" / "learn how I write from this conversation".** Drives the on-demand session-text capture flow described below.
35
36
 
36
37
  Do **not** activate for:
37
38
 
@@ -45,7 +46,7 @@ Voice profiles are segmented by content format. The closed enum is:
45
46
 
46
47
  | Format | Operator picks for |
47
48
  |--------|--------------------|
48
- | `text` | `:Message` nodes; the SessionEnd hook stamps this automatically on operator PTY turns (the sole hard-coded path — chat turns are unambiguously text and the operator is not in the loop on session end) |
49
+ | `text` | `:Message` nodes; the operator's session turns, captured on demand via `voice-ingest-session-text` when the operator asks to capture this session's voice |
49
50
  | `email` | Email threads stored as `:KnowledgeDocument {source:'email'}` or `:ConversationArchive {source:'email'}` |
50
51
  | `social-post` | `:SocialPost` nodes |
51
52
  | `article` | Long-form `:KnowledgeDocument` the operator considers an article |
@@ -97,18 +98,17 @@ Authorship at conversation granularity is a deliberate UX trade-off: chunks with
97
98
 
98
99
  After each backfill batch, check whether the qualifying corpus (`authorshipMode IN ['human-only', 'human-led-agent-assisted']`) for any format has grown ≥20% since the last `:VoiceProfile.corpusSize` for that format (or ≥1 entry if no profile exists for that format). If yes, offer to run `voice-distil-profile` immediately. The operator can defer; the next scheduled distillation will pick it up.
99
100
 
100
- ## Automatic text-format capture (SessionEnd hook)
101
+ ## On-demand text-format capture (session turns)
101
102
 
102
- Operator PTY turns are automatically ingested into the `text` corpus at the end of every session no operator action required. The `voice-session-end-text.sh` hook fires when Claude Code terminates the PTY session. It reads the JSONL transcript, filters to genuine operator turns (excludes slash commands, system reminders, and large paste blocks), deduplicates via SHA256 content hash, and writes each new turn as a `:Message {format:'text', authorshipMode:'human-only'}` node.
103
+ Operator turns are captured into the `text` corpus on demand — when the operator asks to capture this session's voice, never automatically. There is no SessionEnd hook; the operator is in the loop.
103
104
 
104
- The hook only runs for admin sessions (role=admin, no specialist flag). Accounts without writer-craft installed skip silently — the hook guards on CLI existence.
105
+ When the operator says "capture my voice from this chat" (or similar):
105
106
 
106
- After ingestion the hook triggers an incremental distillation for the `text` format if the corpus grew ≥20% since the last profile.
107
+ 1. Read the operator's own turns from the live conversation context the user messages already in this session.
108
+ 2. Call `voice-ingest-session-text` with those turns as the `turns` array. The tool filters out slash commands, harness injections (`<system-reminder>`), and large paste blocks, deduplicates via SHA256 content hash, and writes each new turn as a `:Message {format:'text', authorshipMode:'human-only'}` node.
109
+ 3. The tool triggers an incremental `text`-format distillation if the corpus grew ≥20% since the last profile.
107
110
 
108
- Observe via:
109
- ```
110
- journalctl -u maxy-code | grep '\[voice-session-end-hook\]'
111
- ```
111
+ This runs only on the admin seat (the tool is admin-allowlisted). Accounts without a voice profile degrade gracefully — capture simply populates the corpus for the first distillation.
112
112
 
113
113
  ## Flow — drafting-time conditioning
114
114
 
@@ -182,7 +182,7 @@ The tool returns `{existingStyleCard, exemplars[], feedbackIntents[], eligible,
182
182
 
183
183
  When `eligible=0` (every named document failed the predicate) surface the `ineligible[]` payload to the operator naming the per-id reason (`node-not-found`, `wrong-account`, `ineligible-authorship-mode`, `trashed`, `ineligible-label`) rather than silently no-op. Most commonly this means the documents are tagged as `agent-only` and need re-tagging via `voice-tag-content` before they can amend a profile.
184
184
 
185
- Amend mode does not apply to the SessionEnd auto-ingest path. Session-text ingest stays on the full-corpus path; amend is operator-initiated only.
185
+ Amend mode does not apply to the on-demand session-text capture path. Session-text ingest stays on the full-corpus path; amend is operator-initiated only.
186
186
 
187
187
  ## Per-operator scope
188
188
 
@@ -199,18 +199,16 @@ One `:VoiceProfile` per `(accountId, userId, format)`. Multi-author accounts (an
199
199
  | `[voice-distil] mode=write userId=<id> format=<format> amended=true amendedFromNodeIds=<count> ...` | Amend-write fired (operator-initiated update persisted). |
200
200
  | `[voice-retrieve] task=<topic> format=<format> styleCardBytes=<n> exemplarCount=<k> tokenBudget=<n>` | Each retrieval. |
201
201
  | `[voice-record-feedback] userId=<id> format=<format> intent="<haiku-summary>" diffBytes=<n>` | Each feedback write. |
202
- | `[voice-session-end-hook] trigger sessionId=<id>` | Hook fires for an eligible session. |
203
- | `[voice-session-end-hook] result=ok sessionId=<id> turns=<n> skipped=<m>` | Successful ingest. |
204
- | `[voice-session-end-hook] trigger-skipped sessionId=<id> reason=<reason>` | Hook guard fired. |
202
+ | `[voice-ingest-session-text] sessionId=<id> adminUser=<id> turns=<n> bytes=<n> skipped=<m>` | On-demand session-text capture. |
205
203
 
206
- **Confirms working:** `[voice-retrieve] exemplarCount≥1` precedes every drafting-skill prompt assembly when the calling skill has not opted out. `[voice-distil]` appears at least once per 30-day window per active format per operator. `[voice-session-end-hook] result=ok` appears after each admin PTY session.
204
+ **Confirms working:** `[voice-retrieve] exemplarCount≥1` precedes every drafting-skill prompt assembly when the calling skill has not opted out. `[voice-distil]` appears at least once per 30-day window per active format per operator. `[voice-ingest-session-text] turns≥1` appears when the operator asks to capture a session's voice.
207
205
 
208
- **Indicates failure:** `[voice-retrieve] exemplarCount=0` with non-empty corpus → similarity index broken; `[voice-distil] error …` → corpus walk or LLM call failed; absence of `[voice-record-feedback]` after an operator-edit-then-send flow → feedback loop is dead; `[voice-session-end-hook] result=err` → CLI or Neo4j issue.
206
+ **Indicates failure:** `[voice-retrieve] exemplarCount=0` with non-empty corpus → similarity index broken; `[voice-distil] error …` → corpus walk or LLM call failed; absence of `[voice-record-feedback]` after an operator-edit-then-send flow → feedback loop is dead.
209
207
 
210
208
  **Diagnostic path:**
211
209
 
212
210
  ```
213
- journalctl -u maxy-code | grep -E '\[voice-(tag|distil|retrieve|record-feedback|session-end-hook)\]'
211
+ journalctl -u maxy-code | grep -E '\[voice-(tag|distil|retrieve|record-feedback|ingest-session-text)\]'
214
212
  ```
215
213
 
216
214
  Filter by `userId=<id>` for per-operator drill-down.
@@ -4107,11 +4107,13 @@ process.on("SIGINT", async () => {
4107
4107
  });
4108
4108
  var OLLAMA_URL = process.env.OLLAMA_URL ?? "http://localhost:11434";
4109
4109
  var EMBED_MODEL = process.env.EMBED_MODEL ?? "nomic-embed-text";
4110
+ var EMBED_INPUT_MAX_CHARS = 8e3;
4110
4111
  async function embed(text) {
4112
+ const input = text.length > EMBED_INPUT_MAX_CHARS ? text.slice(0, EMBED_INPUT_MAX_CHARS) : text;
4111
4113
  const res = await fetch(`${OLLAMA_URL}/api/embed`, {
4112
4114
  method: "POST",
4113
4115
  headers: { "Content-Type": "application/json" },
4114
- body: JSON.stringify({ model: EMBED_MODEL, input: text }),
4116
+ body: JSON.stringify({ model: EMBED_MODEL, input }),
4115
4117
  signal: AbortSignal.timeout(5e3)
4116
4118
  });
4117
4119
  if (!res.ok) {
@@ -4898,6 +4900,17 @@ async function writeAdminUserAndPerson(params) {
4898
4900
  const givenName = firstSpace === -1 ? trimmed : trimmed.slice(0, firstSpace).trim();
4899
4901
  const familyName = firstSpace === -1 ? null : trimmed.slice(firstSpace + 1).trim() || null;
4900
4902
  const now = (/* @__PURE__ */ new Date()).toISOString();
4903
+ let personEmbedding = null;
4904
+ try {
4905
+ personEmbedding = await embed(
4906
+ `[Person] ${[givenName, familyName].filter(Boolean).join(" ")} role: admin-personal`
4907
+ );
4908
+ } catch (err) {
4909
+ process.stderr.write(
4910
+ `[graph-write] warn reason=embed-failed labels=Person agent=admin-bootstrap detail=${err instanceof Error ? err.message : String(err)}
4911
+ `
4912
+ );
4913
+ }
4901
4914
  const session = getSession();
4902
4915
  try {
4903
4916
  const result = await session.run(
@@ -4927,6 +4940,7 @@ async function writeAdminUserAndPerson(params) {
4927
4940
  familyName: $familyName,
4928
4941
  role: 'admin-personal',
4929
4942
  scope: 'admin',
4943
+ embedding: $personEmbedding,
4930
4944
  createdAt: $now
4931
4945
  })
4932
4946
  MERGE (au)-[:OWNS]->(newPerson)
@@ -4934,7 +4948,7 @@ async function writeAdminUserAndPerson(params) {
4934
4948
  }
4935
4949
  RETURN reused, elementId(p) AS personElementId,
4936
4950
  p.givenName AS givenName, p.familyName AS familyName`,
4937
- { userId, fullName: trimmed, accountId, givenName, familyName, now }
4951
+ { userId, fullName: trimmed, accountId, givenName, familyName, now, personEmbedding }
4938
4952
  );
4939
4953
  if (result.records.length === 0) {
4940
4954
  throw new Error("writeAdminUserAndPerson: no record returned");
@@ -14,7 +14,7 @@ import {
14
14
  sanitizeClientCorrId,
15
15
  vncLog,
16
16
  websockifyLog
17
- } from "./chunk-M6A6EZD4.js";
17
+ } from "./chunk-76HRO7NX.js";
18
18
  import "./chunk-HYQNUVGO.js";
19
19
 
20
20
  // server/edge.ts