@rubytech/create-maxy-code 0.1.158 → 0.1.161

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 (359) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts +1 -1
  3. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/admin-conversation-purge/dist/index.js +4 -4
  5. package/payload/platform/lib/admin-conversation-purge/dist/index.js.map +1 -1
  6. package/payload/platform/lib/admin-conversation-purge/src/index.ts +5 -5
  7. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +48 -17
  8. package/payload/platform/lib/graph-style/dist/index.js +2 -2
  9. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  10. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +1 -1
  11. package/payload/platform/lib/graph-style/src/index.ts +2 -2
  12. package/payload/platform/lib/graph-trash/dist/index.js +1 -1
  13. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  14. package/payload/platform/lib/graph-trash/src/index.ts +1 -1
  15. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +1 -1
  16. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -1
  17. package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts +3 -3
  18. package/payload/platform/lib/graph-write/dist/conversation-provenance.js +5 -5
  19. package/payload/platform/lib/graph-write/dist/conversation-provenance.js.map +1 -1
  20. package/payload/platform/lib/graph-write/dist/index.js +1 -1
  21. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  22. package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +1 -1
  23. package/payload/platform/lib/graph-write/src/conversation-provenance.ts +8 -8
  24. package/payload/platform/lib/graph-write/src/index.ts +1 -1
  25. package/payload/platform/neo4j/schema.cypher +86 -46
  26. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  27. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  28. package/payload/platform/plugins/admin/PLUGIN.md +8 -4
  29. package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +1 -1
  30. package/payload/platform/plugins/admin/hooks/__tests__/per-turn-graph-pass-gate.test.sh +361 -0
  31. package/payload/platform/plugins/admin/hooks/__tests__/pre-turn-graph-pass.test.sh +13 -13
  32. package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +1 -1
  33. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +2 -2
  34. package/payload/platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh +102 -0
  35. package/payload/platform/plugins/admin/hooks/per-turn-graph-pass-gate.sh +106 -0
  36. package/payload/platform/plugins/admin/hooks/pre-turn-graph-pass.sh +15 -8
  37. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +4 -4
  38. package/payload/platform/plugins/admin/mcp/dist/index.js +65 -24
  39. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  40. package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +1 -1
  41. package/payload/platform/plugins/admin/skills/session-management/SKILL.md +2 -2
  42. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +5 -5
  43. package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +6 -6
  44. package/payload/platform/plugins/business-assistant/references/profiling.md +1 -1
  45. package/payload/platform/plugins/contacts/PLUGIN.md +1 -1
  46. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +2 -2
  47. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
  48. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js +3 -3
  49. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts +1 -1
  50. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js +2 -2
  51. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts +1 -1
  52. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -1
  53. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +4 -4
  54. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -1
  55. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js +10 -10
  56. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js.map +1 -1
  57. package/payload/platform/plugins/docs/references/admin-session.md +6 -6
  58. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  59. package/payload/platform/plugins/docs/references/internals.md +5 -5
  60. package/payload/platform/plugins/docs/references/plugins-guide.md +6 -5
  61. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  62. package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
  63. package/payload/platform/plugins/email/PLUGIN.md +19 -2
  64. package/payload/platform/plugins/email/mcp/dist/index.js +78 -0
  65. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  66. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts +8 -0
  67. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts.map +1 -0
  68. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js +177 -0
  69. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js.map +1 -0
  70. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js +2 -2
  71. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js.map +1 -1
  72. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts +6 -54
  73. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts.map +1 -1
  74. package/payload/platform/plugins/email/mcp/dist/lib/graph.js +12 -300
  75. package/payload/platform/plugins/email/mcp/dist/lib/graph.js.map +1 -1
  76. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +1 -1
  77. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +23 -0
  78. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -0
  79. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js +15 -0
  80. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -0
  81. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts +6 -0
  82. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts.map +1 -0
  83. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js +89 -0
  84. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js.map +1 -0
  85. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts +15 -0
  86. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts.map +1 -0
  87. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +49 -0
  88. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -0
  89. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts +20 -0
  90. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -0
  91. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +91 -0
  92. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -0
  93. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  94. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +32 -52
  95. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  96. package/payload/platform/plugins/email/references/email-reference.md +19 -83
  97. package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +87 -0
  98. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +10 -37
  99. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md +1 -0
  100. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
  101. package/payload/platform/plugins/memory/PLUGIN.md +11 -2
  102. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.mjs +139 -439
  103. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.sh +15 -47
  104. package/payload/platform/plugins/memory/mcp/dist/index.js +197 -58
  105. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  106. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +43 -27
  107. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -1
  108. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts +2 -0
  109. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts.map +1 -0
  110. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js +62 -0
  111. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js.map +1 -0
  112. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +5 -0
  113. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -1
  114. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +1 -1
  115. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -1
  116. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts +42 -25
  117. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts.map +1 -1
  118. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js +23 -17
  119. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js.map +1 -1
  120. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts +3 -0
  121. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts.map +1 -0
  122. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js +61 -0
  123. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js.map +1 -0
  124. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +1 -0
  125. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -1
  126. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +3 -0
  127. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -1
  128. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +1 -1
  129. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -1
  130. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +1 -0
  131. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js.map +1 -1
  132. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js +2 -2
  133. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js.map +1 -1
  134. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts +2 -0
  135. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -1
  136. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +9 -3
  137. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js.map +1 -1
  138. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +3 -3
  139. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -1
  140. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +6 -6
  141. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -1
  142. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts +41 -0
  143. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts.map +1 -0
  144. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js +71 -0
  145. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js.map +1 -0
  146. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts +18 -0
  147. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts.map +1 -0
  148. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js +31 -0
  149. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js.map +1 -0
  150. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +1 -1
  151. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -1
  152. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +2 -2
  153. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +2 -2
  154. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +1 -1
  155. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +1 -1
  156. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts +5 -0
  157. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts.map +1 -1
  158. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +162 -78
  159. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -1
  160. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js +1 -1
  161. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js.map +1 -1
  162. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js +3 -3
  163. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js.map +1 -1
  164. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js +2 -0
  165. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js.map +1 -1
  166. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js +2 -2
  167. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js.map +1 -1
  168. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js +2 -0
  169. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js.map +1 -1
  170. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +6 -0
  171. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +1 -1
  172. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts +2 -0
  173. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts.map +1 -0
  174. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js +141 -0
  175. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js.map +1 -0
  176. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js +8 -8
  177. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js.map +1 -1
  178. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts +2 -0
  179. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts.map +1 -0
  180. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js +86 -0
  181. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js.map +1 -0
  182. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js +2 -2
  183. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js.map +1 -1
  184. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +33 -34
  185. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
  186. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +94 -273
  187. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
  188. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts +43 -0
  189. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts.map +1 -0
  190. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js +96 -0
  191. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js.map +1 -0
  192. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts +1 -1
  193. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts.map +1 -1
  194. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js +2 -2
  195. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js.map +1 -1
  196. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +6 -0
  197. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -0
  198. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +73 -0
  199. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -0
  200. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
  201. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +0 -1
  202. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
  203. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts +2 -2
  204. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -1
  205. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +4 -4
  206. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -1
  207. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts +6 -0
  208. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -1
  209. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +2 -0
  210. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -1
  211. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts +8 -0
  212. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts.map +1 -1
  213. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js +40 -5
  214. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js.map +1 -1
  215. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +8 -1
  216. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts.map +1 -1
  217. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +25 -9
  218. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -1
  219. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts +1 -1
  220. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts.map +1 -1
  221. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js +2 -2
  222. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js.map +1 -1
  223. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +11 -0
  224. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  225. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts +28 -0
  226. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts.map +1 -0
  227. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js +46 -0
  228. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js.map +1 -0
  229. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts +1 -1
  230. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js +1 -1
  231. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +1 -1
  232. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +1 -1
  233. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +2 -2
  234. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +1 -1
  235. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
  236. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +26 -0
  237. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
  238. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +2 -2
  239. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  240. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +1 -1
  241. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
  242. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +11 -11
  243. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
  244. package/payload/platform/plugins/memory/mcp/scripts/backfill-typed-edges.ts +1 -1
  245. package/payload/platform/plugins/memory/mcp/scripts/graph/fixture.cypher +1 -1
  246. package/payload/platform/plugins/memory/mcp/vitest.config.ts +5 -4
  247. package/payload/platform/plugins/memory/references/graph-primitives.md +1 -1
  248. package/payload/platform/plugins/memory/references/schema-base.md +8 -10
  249. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +100 -116
  250. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +74 -24
  251. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +1 -1
  252. package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +1 -1
  253. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +1 -1
  254. package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +8 -0
  255. package/payload/platform/plugins/substack-import/PLUGIN.md +34 -0
  256. package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +182 -0
  257. package/payload/platform/plugins/substack-import/skills/substack-import/references/archive-shape.md +68 -0
  258. package/payload/platform/plugins/substack-import/skills/substack-import/references/attachments.md +72 -0
  259. package/payload/platform/plugins/substack-import/skills/substack-import/references/engagement.md +61 -0
  260. package/payload/platform/plugins/substack-import/skills/substack-import/references/posts.md +80 -0
  261. package/payload/platform/plugins/substack-import/skills/substack-import/references/subscribers.md +74 -0
  262. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
  263. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +2 -2
  264. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  265. package/payload/platform/plugins/work/mcp/dist/index.js +2 -2
  266. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
  267. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js +6 -6
  268. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js.map +1 -1
  269. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts +1 -1
  270. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts.map +1 -1
  271. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js +1 -1
  272. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js.map +1 -1
  273. package/payload/platform/plugins/x-import/references/archive-shape.md +2 -2
  274. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +4 -4
  275. package/payload/platform/scripts/admin-persist-audit.ts +18 -18
  276. package/payload/platform/scripts/identity-forbidden-token-check.mjs +2 -0
  277. package/payload/platform/scripts/seed-neo4j.sh +1 -0
  278. package/payload/platform/services/claude-session-manager/dist/http-server.js +3 -3
  279. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  280. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +3 -3
  281. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +4 -4
  282. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  283. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  284. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +2 -0
  285. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  286. package/payload/platform/templates/specialists/agents/archive-ingest-operator.md +45 -0
  287. package/payload/platform/templates/specialists/agents/database-operator.md +5 -17
  288. package/payload/platform/templates/specialists/agents/librarian.md +1 -1
  289. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  290. package/payload/server/{chunk-AXOL2PPG.js → chunk-3TRIXQSJ.js} +101 -101
  291. package/payload/server/maxy-edge.js +1 -1
  292. package/payload/server/public/assets/{admin-3fLFD5h_.js → admin-Dal5FWaD.js} +2 -2
  293. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Breg9-99.js → architectureDiagram-Q4EWVU46-Do2zYONG.js} +1 -1
  294. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DXf1_673.js → blockDiagram-DXYQGD6D-DpIX_bRu.js} +1 -1
  295. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CSZ36W4-.js → c4Diagram-AHTNJAMY-Cz335ZSY.js} +1 -1
  296. package/payload/server/public/assets/channel-PC4_IjI1.js +1 -0
  297. package/payload/server/public/assets/{chunk-336JU56O-DsrLk2eK.js → chunk-336JU56O-Dmknn3Wo.js} +2 -2
  298. package/payload/server/public/assets/{chunk-426QAEUC-JpNfNf81.js → chunk-426QAEUC-ClfGjizN.js} +1 -1
  299. package/payload/server/public/assets/{chunk-4TB4RGXK-DmClEAD0.js → chunk-4TB4RGXK-BPKctJ5c.js} +1 -1
  300. package/payload/server/public/assets/{chunk-5FUZZQ4R-BI9blW3N.js → chunk-5FUZZQ4R-BWDCO9zw.js} +1 -1
  301. package/payload/server/public/assets/{chunk-5PVQY5BW-BbgttEFO.js → chunk-5PVQY5BW-BE34_Db0.js} +1 -1
  302. package/payload/server/public/assets/{chunk-EDXVE4YY-BX_LCFOx.js → chunk-EDXVE4YY-BysA-_6v.js} +1 -1
  303. package/payload/server/public/assets/{chunk-ENJZ2VHE-Bb7EoD0w.js → chunk-ENJZ2VHE-BMVyMsqA.js} +1 -1
  304. package/payload/server/public/assets/{chunk-ICPOFSXX-DH8uQk-s.js → chunk-ICPOFSXX-C5KRdLV4.js} +1 -1
  305. package/payload/server/public/assets/{chunk-OYMX7WX6-FH5kgXsw.js → chunk-OYMX7WX6-DVZD-AVc.js} +1 -1
  306. package/payload/server/public/assets/{chunk-U2HBQHQK-D_ljlkHr.js → chunk-U2HBQHQK-DYmQdx8x.js} +1 -1
  307. package/payload/server/public/assets/{chunk-X2U36JSP-BX3EmZvm.js → chunk-X2U36JSP-DrZenIl3.js} +1 -1
  308. package/payload/server/public/assets/{chunk-YZCP3GAM-Vu7-E93h.js → chunk-YZCP3GAM-CDuGbvMq.js} +1 -1
  309. package/payload/server/public/assets/{chunk-ZZ45TVLE-CwjhNPX5.js → chunk-ZZ45TVLE-COztbiu5.js} +1 -1
  310. package/payload/server/public/assets/classDiagram-6PBFFD2Q-B_pMa-SX.js +1 -0
  311. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BdBAgF20.js +1 -0
  312. package/payload/server/public/assets/clone-CkNt9L9r.js +1 -0
  313. package/payload/server/public/assets/{dagre-Ce6gsj0C.js → dagre-Cv9Ib2OM.js} +1 -1
  314. package/payload/server/public/assets/{dagre-KV5264BT-BaMGpsoy.js → dagre-KV5264BT-CoEd61KZ.js} +1 -1
  315. package/payload/server/public/assets/{data-BHASh0_Y.js → data-DbSORCl4.js} +1 -1
  316. package/payload/server/public/assets/{diagram-5BDNPKRD-CHEE9rjq.js → diagram-5BDNPKRD-WXNzw3uW.js} +1 -1
  317. package/payload/server/public/assets/{diagram-G4DWMVQ6-C98sZLW1.js → diagram-G4DWMVQ6-C6IuQ2VV.js} +1 -1
  318. package/payload/server/public/assets/{diagram-MMDJMWI5-DNvMGsTZ.js → diagram-MMDJMWI5-CdJdir5A.js} +1 -1
  319. package/payload/server/public/assets/{diagram-TYMM5635-Cdte4IBa.js → diagram-TYMM5635-DxWKQH5T.js} +1 -1
  320. package/payload/server/public/assets/{erDiagram-SMLLAGMA-C9VZsWXK.js → erDiagram-SMLLAGMA-C9fvs33K.js} +1 -1
  321. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-tuP5fzzR.js → flowDiagram-DWJPFMVM-BO7Yrbqv.js} +1 -1
  322. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-SJgRPUwx.js → ganttDiagram-T4ZO3ILL-CQJyWBZq.js} +1 -1
  323. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DU_cI_50.js → gitGraphDiagram-UUTBAWPF-DZfQHrYw.js} +1 -1
  324. package/payload/server/public/assets/{graph-labels-DXlmm1og.js → graph-labels-BBB5jsZk.js} +1 -1
  325. package/payload/server/public/assets/{graph-BhEI09tF.js → graph-ys_joP2o.js} +1 -1
  326. package/payload/server/public/assets/{graphlib-D_nAsvmx.js → graphlib-C40H-Q5E.js} +1 -1
  327. package/payload/server/public/assets/{infoDiagram-42DDH7IO-Cj2Y19m6.js → infoDiagram-42DDH7IO-CakfV5f9.js} +1 -1
  328. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DMc1xq1y.js → ishikawaDiagram-UXIWVN3A-CPuBPyfa.js} +1 -1
  329. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C4CRAQma.js → journeyDiagram-VCZTEJTY-zpZm2Mmo.js} +1 -1
  330. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CTr4AldU.js → kanban-definition-6JOO6SKY-DfJduQCo.js} +1 -1
  331. package/payload/server/public/assets/{line-Btlm_IAl.js → line-BpYQqO5R.js} +1 -1
  332. package/payload/server/public/assets/{mermaid-parser.core-DXFdj_y1.js → mermaid-parser.core-C5Mwi14D.js} +1 -1
  333. package/payload/server/public/assets/{mermaid.core-DFBhoCr5.js → mermaid.core-D8qBtvvT.js} +3 -3
  334. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-r9gVQybo.js → mindmap-definition-QFDTVHPH-Bli9JhIN.js} +1 -1
  335. package/payload/server/public/assets/{page-CDWu1Aft.js → page--bl5Y7ZI.js} +2 -2
  336. package/payload/server/public/assets/page-CwmZ76U7.js +1 -0
  337. package/payload/server/public/assets/{pieDiagram-DEJITSTG-CHKZjSaH.js → pieDiagram-DEJITSTG-MsLXTSLg.js} +1 -1
  338. package/payload/server/public/assets/{public-DyGWgfaZ.js → public-DltgEfA9.js} +2 -2
  339. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CSGR1HJr.js → quadrantDiagram-34T5L4WZ-De1sh2K0.js} +1 -1
  340. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DZ6hX9D6.js → requirementDiagram-MS252O5E-D5Sfg1t_.js} +1 -1
  341. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DbZBKh0m.js → sankeyDiagram-XADWPNL6-DHA3LIbv.js} +1 -1
  342. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BHHpb8dt.js → sequenceDiagram-FGHM5R23-BE_QlG1B.js} +1 -1
  343. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DQ1jiLB4.js → stateDiagram-FHFEXIEX-NIwp3F4u.js} +1 -1
  344. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-pfk2F6st.js +1 -0
  345. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BlGiEU7p.js → timeline-definition-GMOUNBTQ-CPE9jyDF.js} +1 -1
  346. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DmEH-hsB.js → vennDiagram-DHZGUBPP-CKfoyYmH.js} +1 -1
  347. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-C7KJJ40d.js → wardleyDiagram-NUSXRM2D-B9yJek-o.js} +1 -1
  348. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-JDnusCaa.js → xychartDiagram-5P7HB3ND-DuCcSLqX.js} +1 -1
  349. package/payload/server/public/data.html +3 -3
  350. package/payload/server/public/graph.html +3 -3
  351. package/payload/server/public/index.html +4 -4
  352. package/payload/server/public/public.html +1 -1
  353. package/payload/server/server.js +133 -133
  354. package/payload/server/public/assets/channel-BmZnt3PP.js +0 -1
  355. package/payload/server/public/assets/classDiagram-6PBFFD2Q-kmMLFUpV.js +0 -1
  356. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BV7Ae8ct.js +0 -1
  357. package/payload/server/public/assets/clone-B5eqoN9I.js +0 -1
  358. package/payload/server/public/assets/page-cyvshX4Z.js +0 -1
  359. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CByT2RzF.js +0 -1
@@ -1,43 +1,29 @@
1
1
  #!/usr/bin/env bash
2
2
  # =============================================================================
3
- # conversation-archive-ingest.sh — single deterministic Bash entry for
4
- # conversation-archive ingestion
5
- # env-only identity, progress-file path on stdout).
3
+ # conversation-archive-ingest.sh — Bash wrapper around the
4
+ # conversation-archive prepare helper (Task 435).
6
5
  #
7
- # Source-agnostic: WhatsApp `_chat.txt`, Telegram, Signal, LinkedIn DMs, Zoom
8
- # transcript, meeting minutes, iMessage, Slack every source flows through
9
- # the same pipeline with `--source` selecting the normaliser.
10
- #
11
- # Pipeline: normalise (per source) bind canonical sender set
12
- # derive conversationIdentity look up prior :ConversationArchive (delta
13
- # cursor) → sessionize delta at gap-hours boundary → for each session: classify
14
- # via Haiku (mode='chat') + memory-ingest immediately (per-session checkpoint).
6
+ # Post-Task-435 contract: the wrapper validates env (ACCOUNT_ID, USER_ID,
7
+ # NEO4J_URI, NEO4J_PASSWORD) and argv, then exec's the .mjs which runs the
8
+ # deterministic pipeline (normalise verify participants → derive
9
+ # conversationIdentity → look up prior archive cursor → slice delta →
10
+ # sessionize emit JSON). Classify + memory-ingest move into the dispatched
11
+ # specialist's per-turn work (driven by SKILL.md).
15
12
  #
16
13
  # Usage:
17
14
  # bash conversation-archive-ingest.sh <archive-path>
18
- # --source <whatsapp|telegram|signal|linkedin-messages|zoom-transcript|meeting-minutes|imessage|slack|other>
15
+ # --source <whatsapp|telegram|signal|linkedin-messages|zoom-transcript|meeting-minutes|imessage|slack|x-dm|other>
19
16
  # --participant-person-ids <csv>
20
17
  # --scope <admin|public>
21
- # [--rebuild] (opt-in destructive rebuild)
18
+ # [--rebuild]
22
19
  # [--timezone <iana-zone>]
23
- # [--date-format <DD/MM/YY|MM/DD/YY|DD/MM/YYYY|MM/DD/YYYY>] (whatsapp only)
24
- # [--session-id <id>]
25
- #
26
- # Sessions split deterministically at 8h gap (fixed code constant).
27
- # `--session-gap-hours` is REMOVED; passing it FAILs at phase=argv.
20
+ # [--date-format <DD/MM/YY|MM/DD/YY|DD/MM/YYYY|MM/DD/YYYY>]
28
21
  #
29
- # Identity: `ACCOUNT_ID` + `USER_ID` come from the caller's env
30
- # (plumbed by `spawn-env.ts` into every Bash subprocess). The owner :AdminUser
31
- # elementId is derived from (accountId, userId) inside the bin via Cypher.
32
- # `--account-id` and `--owner-element-id` flags are GONE — env-only identity
33
- # is doctrine. `--participant-person-ids` carries the operator-confirmed
34
- # non-owner set.
22
+ # Identity: ACCOUNT_ID + USER_ID come from the caller's env (plumbed by
23
+ # spawn-env.ts). Owner :AdminUser elementId is derived inside the .mjs.
35
24
  #
36
- # Exit 0 + JSON summary on stdout on success.
25
+ # Exit 0 + one JSON line on stdout on success.
37
26
  # Exit !0 + one [conversation-archive] FAIL line on stderr on failure.
38
- # Stdout (always, before exec node): `[conversation-archive] progress-file=<absolute-path>`
39
- # Mid-run progress: line-by-line writes to that progress-file (fsync per line);
40
- # the agent's heartbeat polls it via `tail -n <N> <path>` every 30 s.
41
27
  # =============================================================================
42
28
 
43
29
  set -euo pipefail
@@ -56,10 +42,6 @@ if [ ! -f "$INGEST_MJS" ]; then
56
42
  arg_fail "conversation-archive-ingest.mjs not found at $INGEST_MJS — run from a built install"
57
43
  fi
58
44
 
59
- # Identity is env-only. The mjs LOUD-FAILs on missing/malformed
60
- # values, but we mirror the cheap accountId presence check here so the
61
- # progress-file path can be computed and emitted before exec node — without
62
- # accountId, the path is undefined.
63
45
  if [ -z "${ACCOUNT_ID:-}" ]; then
64
46
  arg_fail "ACCOUNT_ID env missing — bin must be invoked under an authenticated agent context (set by spawn-env.ts)"
65
47
  fi
@@ -74,7 +56,6 @@ HAS_PARTICIPANTS=0
74
56
  PARTICIPANTS_VAL=""
75
57
  HAS_SCOPE=0
76
58
  SCOPE_VAL=""
77
- SESSION_ID_VAL=""
78
59
 
79
60
  ARGS=("$@")
80
61
  i=0
@@ -84,7 +65,6 @@ while [ $i -lt ${#ARGS[@]} ]; do
84
65
  --source) HAS_SOURCE=1; SOURCE_VAL="${ARGS[$((i + 1))]:-}"; i=$((i + 2)); continue ;;
85
66
  --participant-person-ids) HAS_PARTICIPANTS=1; PARTICIPANTS_VAL="${ARGS[$((i + 1))]:-}"; i=$((i + 2)); continue ;;
86
67
  --scope) HAS_SCOPE=1; SCOPE_VAL="${ARGS[$((i + 1))]:-}"; i=$((i + 2)); continue ;;
87
- --session-id) SESSION_ID_VAL="${ARGS[$((i + 1))]:-}"; i=$((i + 2)); continue ;;
88
68
  --rebuild) i=$((i + 1)); continue ;;
89
69
  --session-gap-hours) arg_fail "--session-gap-hours is no longer supported; gap is fixed at 8h. Use --rebuild on the prior export bytes if you need to re-classify." ;;
90
70
  --timezone|--date-format) i=$((i + 2)); continue ;;
@@ -98,7 +78,7 @@ while [ $i -lt ${#ARGS[@]} ]; do
98
78
  done
99
79
 
100
80
  [ -n "$ARCHIVE" ] || arg_fail "missing positional <archive>"
101
- [ "$HAS_SOURCE" -eq 1 ] && [ -n "$SOURCE_VAL" ] || arg_fail "missing --source (whatsapp|telegram|signal|linkedin-messages|zoom-transcript|meeting-minutes|imessage|slack|other)"
81
+ [ "$HAS_SOURCE" -eq 1 ] && [ -n "$SOURCE_VAL" ] || arg_fail "missing --source (whatsapp|telegram|signal|linkedin-messages|zoom-transcript|meeting-minutes|imessage|slack|x-dm|other)"
102
82
  [ "$HAS_PARTICIPANTS" -eq 1 ] && [ -n "$PARTICIPANTS_VAL" ] || arg_fail "missing --participant-person-ids (csv of operator-confirmed :Person/:AdminUser elementIds, owner excluded)"
103
83
  [ "$HAS_SCOPE" -eq 1 ] && [ -n "$SCOPE_VAL" ] || arg_fail "missing --scope (or empty value)"
104
84
  case "$SCOPE_VAL" in
@@ -123,16 +103,4 @@ fi
123
103
  export NEO4J_USER="${NEO4J_USER:-neo4j}"
124
104
  export MAXY_PLATFORM_ROOT="$PLATFORM_ROOT"
125
105
 
126
- # Progress-file path must match the path the mjs opens (deterministic from
127
- # (ACCOUNT_ID, sessionId)). When the operator omits --session-id, the mjs
128
- # mints one — the wrapper passes through the same value via env so both
129
- # sides converge on one path.
130
- if [ -z "$SESSION_ID_VAL" ]; then
131
- SESSION_ID_VAL="conversation-archive:${SOURCE_VAL}:$(date +%s%N)"
132
- ARGS+=(--session-id "$SESSION_ID_VAL")
133
- fi
134
- INSTALL_DIR="$(cd "$PLATFORM_ROOT/.." && pwd)"
135
- PROGRESS_FILE="$INSTALL_DIR/data/accounts/$ACCOUNT_ID/logs/conversation-archive-$SESSION_ID_VAL.log"
136
- echo "[conversation-archive] progress-file=$PROGRESS_FILE"
137
-
138
106
  exec node "$INGEST_MJS" "${ARGS[@]}"
@@ -12,6 +12,8 @@ import { buildLiveSchemaSource, defaultSchemaCypherPath, } from "./lib/live-sche
12
12
  import { memoryReindex } from "./tools/memory-reindex.js";
13
13
  import { memoryIngestExtract } from "./tools/memory-ingest-extract.js";
14
14
  import { memoryIngest } from "./tools/memory-ingest.js";
15
+ import { CONVERSATION_SOURCES } from "./lib/conversation-normalisers/types.js";
16
+ import { kdClassify } from "./tools/kd-classify.js";
15
17
  import { memoryArchiveWrite } from "./tools/memory-archive-write.js";
16
18
  import { obsidianVaultImport, } from "./tools/obsidian-vault-import.js";
17
19
  // whatsapp-export-{parse,preview,insight-write} deleted. Conversation
@@ -25,6 +27,7 @@ import { memoryIngestWeb } from "./tools/memory-ingest-web.js";
25
27
  import { memoryUpdate } from "./tools/memory-update.js";
26
28
  import { memoryDelete } from "./tools/memory-delete.js";
27
29
  import { memoryFindCandidates } from "./tools/memory-find-candidates.js";
30
+ import { memoryNodeExists, ALLOWED_LABELS as MEMORY_NODE_EXISTS_LABELS } from "./tools/memory-node-exists.js";
28
31
  import { memoryRestore } from "./tools/memory-restore.js";
29
32
  import { memoryEmptyTrash } from "./tools/memory-empty-trash.js";
30
33
  import { memoryListAttachments } from "./tools/memory-list-attachments.js";
@@ -39,7 +42,8 @@ import { graphPruneDenylistAdd } from "./tools/graph-prune-denylist-add.js";
39
42
  import { graphPruneDenylistList } from "./tools/graph-prune-denylist-list.js";
40
43
  import { graphPruneDenylistRemove } from "./tools/graph-prune-denylist-remove.js";
41
44
  import { conversationMemoryExpunge } from "./tools/conversation-memory-expunge.js";
42
- import { conversationArchiveDeriveInsights, } from "./tools/conversation-archive-derive-insights.js";
45
+ import { conversationArchiveDeriveInsights, PROPOSAL_KINDS, } from "./tools/conversation-archive-derive-insights.js";
46
+ import { conversationArchiveListChunks } from "./tools/conversation-archive-list-chunks.js";
43
47
  import { conversationArchiveEnrichRejection } from "./tools/conversation-archive-enrich-rejection.js";
44
48
  import { fetchImageAsContent } from "./tools/image-fetch.js";
45
49
  import { memoryTypedEdgePass } from "./tools/memory-typed-edge-pass.js";
@@ -295,16 +299,12 @@ eagerTool(server, "memory-search", "Search the knowledge graph using semantic ve
295
299
  }
296
300
  });
297
301
  // ---------------------------------------------------------------------------
298
- // conversation-archive Phase 2: chunk-anchored insight derivation.
299
- // Read-only tool. Walks the :Section chunks of one named conversation
300
- // archive (`:ConversationArchive` keyed on `conversationIdentity` — Task
301
- // 397) in pages and asks Haiku (via OAuth) for the high-confidence claims.
302
- // Returns operator-facing proposals with the cypher needed to wire them;
303
- // the conversation-archive-enrich skill drives the per-row operator gate.
304
- // The tool itself NEVER writes; idempotency lives on the MERGE-key shape
305
- // (chunkElementId, kind, contentHash) encoded in each proposal's mergeCypher.
302
+ // conversation-archive Phase 2 chunk page reader (Task 433).
303
+ // Returns one page of :Section chunk bodies for the named :ConversationArchive
304
+ // so the conversation-archive-enrich skill can drive the dispatched
305
+ // specialist to read each chunk and emit claims in-turn. Read-only.
306
306
  // ---------------------------------------------------------------------------
307
- server.tool("conversation-archive-derive-insights", "Walk the :Section chunks of one named :ConversationArchive (conversation-archive walker) and emit high-confidence claim proposals (mention, task, preference, observed-relationship). Read-only: the caller drives a per-row operator gate; this tool never writes. Paginates via chunkOffset + chunkLimit (default 5). Operator-triggered, never automatic.", {
307
+ server.tool("conversation-archive-list-chunks", "Page through the :Section chunks of one named :ConversationArchive and return each chunk's elementId, ordered index, summary, and full body. The conversation-archive-enrich skill calls this per page, then prompts the dispatched specialist to read each chunk's body in-turn and emit claims; the skill hands those claims back to `conversation-archive-derive-insights` for per-kind cypher emission. Read-only.", {
308
308
  archiveElementId: z
309
309
  .string()
310
310
  .describe("elementId of the :ConversationArchive parent (Task 397 — keyed on conversationIdentity) the operator named (required)."),
@@ -313,23 +313,100 @@ server.tool("conversation-archive-derive-insights", "Walk the :Section chunks of
313
313
  .int()
314
314
  .nonnegative()
315
315
  .optional()
316
- .describe("Zero-based chunk offset. Default 0. Increase per page."),
316
+ .describe("Zero-based chunk offset. Default 0. Advance by chunkLimit per page."),
317
317
  chunkLimit: z
318
318
  .number()
319
319
  .int()
320
320
  .positive()
321
321
  .max(20)
322
322
  .optional()
323
- .describe("Chunks per page (1..20). Default 5 — small pages keep MCP calls under SDK timeout windows."),
323
+ .describe("Chunks per page (1..20). Default 5."),
324
324
  }, async ({ archiveElementId, chunkOffset, chunkLimit }) => {
325
325
  if (!accountId)
326
- return refuseNoAccount("conversation-archive-derive-insights");
326
+ return refuseNoAccount("conversation-archive-list-chunks");
327
327
  try {
328
- const result = await conversationArchiveDeriveInsights({
328
+ const result = await conversationArchiveListChunks({
329
329
  accountId,
330
330
  archiveElementId,
331
331
  chunkOffset,
332
332
  chunkLimit,
333
+ });
334
+ const header = `archiveElementId=${result.archiveElementId} title=${JSON.stringify(result.archiveTitle ?? "")} totalChunks=${result.totalChunks} walked=${result.walkedFrom}..${result.walkedTo} chunks=${result.chunks.length} chunksRemaining=${result.chunksRemaining}`;
335
+ const chunkBlocks = result.chunks
336
+ .map((c) => [
337
+ `Chunk ${c.index + 1}/${result.totalChunks}:`,
338
+ ` elementId=${c.elementId}`,
339
+ ` summary=${JSON.stringify(c.summary)}`,
340
+ ` body=${JSON.stringify(c.body)}`,
341
+ ].join("\n"))
342
+ .join("\n\n");
343
+ return {
344
+ content: [
345
+ {
346
+ type: "text",
347
+ text: result.chunks.length === 0
348
+ ? `${header}\n(no chunks at this offset)`
349
+ : `${header}\n\n${chunkBlocks}`,
350
+ },
351
+ ],
352
+ };
353
+ }
354
+ catch (err) {
355
+ const msg = err instanceof Error ? err.message : String(err);
356
+ return {
357
+ content: [{ type: "text", text: msg }],
358
+ isError: true,
359
+ };
360
+ }
361
+ });
362
+ process.stderr.write("[memory-mcp] registered tool=conversation-archive-list-chunks\n");
363
+ // ---------------------------------------------------------------------------
364
+ // conversation-archive Phase 2: per-chunk claim → cypher proposal emitter.
365
+ // Task 433: accepts the agent-produced `claims` array for one chunk (read
366
+ // from `conversation-archive-list-chunks`) and returns operator-facing
367
+ // proposals carrying the per-kind mergeCypher. Rejection sidecar filter is
368
+ // applied here. The tool itself NEVER writes; idempotency lives on the
369
+ // MERGE-key (chunkElementId, kind, contentHash) baked into each mergeCypher.
370
+ // ---------------------------------------------------------------------------
371
+ const claimSchema = z.object({
372
+ kind: z.enum([...PROPOSAL_KINDS]).describe("One of: mention, task, preference, observed-relationship."),
373
+ evidenceSnippet: z
374
+ .string()
375
+ .describe("Near-verbatim quote from the chunk body (≤80 chars enforced server-side)."),
376
+ subject: z
377
+ .string()
378
+ .nullable()
379
+ .optional()
380
+ .describe("Display name of the primary entity. Required for mention + observed-relationship."),
381
+ object: z
382
+ .string()
383
+ .nullable()
384
+ .optional()
385
+ .describe("Display name of the related entity. Required for observed-relationship only."),
386
+ payload: z
387
+ .record(z.string(), z.unknown())
388
+ .optional()
389
+ .describe("Kind-specific structured fields (taskTitle/taskDueHint for task; preferenceCategory/preferenceKey/preferenceValue for preference; relationshipType for observed-relationship)."),
390
+ });
391
+ server.tool("conversation-archive-derive-insights", "Convert one chunk's agent-produced claims into operator-facing claim proposals (mention, task, preference, observed-relationship). The conversation-archive-enrich skill reads chunk bodies via `conversation-archive-list-chunks`, drives the dispatched specialist to emit claims in-turn, and passes them here for per-kind cypher emission. Applies the durable rejection sidecar so already-triaged claims do not re-surface. Read-only: the per-row operator gate runs in the skill, this tool never writes.", {
392
+ archiveElementId: z
393
+ .string()
394
+ .describe("elementId of the :ConversationArchive parent (Task 397 — keyed on conversationIdentity) the operator named (required)."),
395
+ chunkElementId: z
396
+ .string()
397
+ .describe("elementId of the single :Section chunk the agent just read (required)."),
398
+ claims: z
399
+ .array(claimSchema)
400
+ .describe("Claims the dispatched specialist emitted in-turn from the chunk body. Zero is valid — pass [] to record an empty-chunk pass."),
401
+ }, async ({ archiveElementId, chunkElementId, claims }) => {
402
+ if (!accountId)
403
+ return refuseNoAccount("conversation-archive-derive-insights");
404
+ try {
405
+ const result = await conversationArchiveDeriveInsights({
406
+ accountId,
407
+ archiveElementId,
408
+ chunkElementId,
409
+ claims: claims,
333
410
  sessionId: resolveSessionId(),
334
411
  });
335
412
  const proposalLines = result.proposals
@@ -349,13 +426,13 @@ server.tool("conversation-archive-derive-insights", "Walk the :Section chunks of
349
426
  ].join("\n");
350
427
  })
351
428
  .join("\n\n");
352
- const header = `archiveElementId=${result.archiveElementId} title=${JSON.stringify(result.archiveTitle ?? "")} totalChunks=${result.totalChunks} walked=${result.walkedFrom}..${result.walkedTo} proposals=${result.proposals.length} proposalsRemaining=${result.proposalsRemaining} emptyChunks=${result.emptyChunkElementIds.length}`;
429
+ const header = `archiveElementId=${result.archiveElementId} chunkElementId=${result.chunkElementId} proposals=${result.proposals.length} rejectionsFiltered=${result.rejectionsFiltered} invalidClaims=${result.invalidClaims}`;
353
430
  return {
354
431
  content: [
355
432
  {
356
433
  type: "text",
357
434
  text: result.proposals.length === 0
358
- ? `${header}\n(no high-confidence claims in this page; advance chunkOffset to walk further)`
435
+ ? `${header}\n(no proposals from this chunk's claims)`
359
436
  : `${header}\n\n${proposalLines}`,
360
437
  },
361
438
  ],
@@ -676,7 +753,7 @@ if (!readOnly) {
676
753
  keywords,
677
754
  sourceWorkflow,
678
755
  occurredAt,
679
- conversationNodeId: process.env.CONVERSATION_NODE_ID,
756
+ conversationNodeId: process.env.SESSION_NODE_ID,
680
757
  });
681
758
  const status = result.created
682
759
  ? `Report created`
@@ -888,20 +965,29 @@ if (!readOnly) {
888
965
  };
889
966
  }
890
967
  });
891
- server.tool("memory-ingest", "Write a classified document into the graph as typed nodes anchored to the document subject. " +
892
- "Requires a prior memory-ingest-extract call for the text cache; the typed-section JSON in the `sections` argument is produced by the dispatched specialist in-turn from the loaded ontology. " +
968
+ server.tool("memory-ingest", "Write a classified document or conversation-archive session into the graph as typed nodes anchored to a subject. " +
969
+ "Two mutually-exclusive parent paths exactly one MUST be set: " +
970
+ "(1) **Document path** — set `attachmentId` (requires a prior memory-ingest-extract call for the text cache). MERGEs under `:KnowledgeDocument` keyed on attachmentId. The typed-section JSON in `sections` is produced by the dispatched specialist in-turn from the loaded ontology. " +
971
+ "(2) **Conversation-archive path** — set `conversationIdentity` along with the conversation-document fields (`source`, `archiveSha256`, `archiveSourceFile`, `participantElementIds`, `lastIngestedMessageHash`, `lastIngestedMessageAt`, optionally `archiveTitle` and `cleanupPriorChunks`). MERGEs under `:ConversationArchive` keyed on conversationIdentity. The specialist invokes this once per session prepared by `conversation-archive-ingest.sh`, advancing the cursor atomically with each session's chunks. " +
893
972
  "Each section becomes either a typed graph node (Position, Service, Credential, etc.) anchored to the named " +
894
- "subject via the natural ontology edge plus a (KnowledgeDocument)-[:REFERENCES]->(typed) link, or — for " +
895
- "UNMAPPED sections — a generic :Section node hanging off the document via HAS_SECTION (legacy fallback). " +
896
- "Re-ingesting with the same attachmentId replaces the document's typed and untyped children safe to call " +
897
- "on already-ingested documents. Shared related entities (Organizations, Persons referenced by typed nodes) " +
973
+ "subject via the natural ontology edge plus a (parent)-[:REFERENCES]->(typed) link, or — for " +
974
+ "UNMAPPED sections — a generic :Section node hanging off the parent via HAS_SECTION (legacy fallback). " +
975
+ "Document re-ingest replaces the document's typed and untyped children (same attachmentId). Conversation-archive re-ingest is delta-append: prior chunks are never touched unless `cleanupPriorChunks=true` is set (only legitimate on the FIRST session of a `--rebuild` run). " +
976
+ "Shared related entities (Organizations, Persons referenced by typed nodes) " +
898
977
  "are MERGEd by identifying property and never deleted on re-ingest.", {
899
- attachmentId: z.string().describe("UUID of the file attachment — must match a prior memory-ingest-extract call"),
900
- documentSummary: z.string().describe("Classifier-produced summary of the entire document (1-3 sentences)"),
901
- anchorNodeId: z.string().describe("Element ID of the anchor node (UserProfile/LocalBusiness/Person/Organization). The document subject " +
902
- "the operator confirmed during the document-ingest skill's first step."),
903
- anchorLabel: z.string().describe("Primary label of the anchor node (e.g. 'UserProfile', 'LocalBusiness'). Used in the per-section MATCH " +
904
- "for anchor-edge creation."),
978
+ attachmentId: z.string().optional().describe("UUID of the file attachment — must match a prior memory-ingest-extract call. Document path only — mutually exclusive with conversationIdentity."),
979
+ conversationIdentity: z.string().optional().describe("sha256(accountId + ':' + sortedParticipantElementIds.join(',')) produced by `conversation-archive-ingest.sh`. Conversation-archive path only — mutually exclusive with attachmentId."),
980
+ source: z.enum(CONVERSATION_SOURCES).optional().describe("Conversation source enum. Required on the conversation-archive path."),
981
+ archiveSha256: z.string().optional().describe("sha256 of the export bytes. Required on the conversation-archive path; stamped on every :Section chunk so cleanup-by-archiveSha256 is exact."),
982
+ archiveSourceFile: z.string().optional().describe("Basename of the source file (e.g. `_chat.txt`). Required on the conversation-archive path."),
983
+ participantElementIds: z.array(z.string()).optional().describe("Owner + operator-confirmed participants (elementIds). Required on the conversation-archive path. Owner is included first; :PARTICIPANT_IN edges land for every entry. Order is irrelevant for conversationIdentity, which is derived from a sorted set."),
984
+ lastIngestedMessageHash: z.string().optional().describe("sha256 of the last message in THIS session. Required on the conversation-archive path; written to :ConversationArchive.lastIngestedMessageHash atomically with this session's chunks for delta-append on the next ingest."),
985
+ lastIngestedMessageAt: z.string().optional().describe("ISO timestamp of the last message in THIS session. Required on the conversation-archive path; written to :ConversationArchive.lastIngestedMessageAt."),
986
+ archiveTitle: z.string().optional().describe("Stable archive title (`<source> · <owner> ↔ <others> · <YYYY-MM-DD>→<YYYY-MM-DD>`) computed by `conversation-archive-ingest.sh`. Written ON CREATE and COALESCE-on-MATCH so the UI label is stable across re-ingests. Conversation-archive path only."),
987
+ cleanupPriorChunks: z.boolean().optional().describe("When true, the writer deletes prior chunks for the matching archiveSha256 before MERGE. Set this ONLY on the FIRST session of a `--rebuild` run; subsequent sessions in the same run MUST set it false or the writer drops chunks the earlier sessions just wrote. Defaults to false."),
988
+ documentSummary: z.string().describe("Classifier-produced summary (1-3 sentences) for the document path. On the conversation-archive path, pass the stable `archiveTitle` so the parent's summary matches the title."),
989
+ anchorNodeId: z.string().describe("Element ID of the anchor node. Document path: the operator-confirmed document subject (UserProfile/LocalBusiness/Person/Organization). Conversation-archive path: the owner :AdminUser elementId (or :Person for a third-party archive)."),
990
+ anchorLabel: z.string().describe("Primary label of the anchor node (e.g. 'UserProfile', 'LocalBusiness', 'AdminUser'). Used in the per-section MATCH for anchor-edge creation."),
905
991
  sections: z.array(z.object({
906
992
  kind: z.string().describe("Section kind from the closed enumeration (Position/Education/Chapter/Parties/.../Other), or a standalone-node kind like 'Project'."),
907
993
  title: z.string(),
@@ -945,13 +1031,22 @@ if (!readOnly) {
945
1031
  documentKeywords: z.array(z.string()).optional().describe("Classifier-extracted topic keywords."),
946
1032
  userKeywords: z.array(z.string()).optional().describe("Keywords explicitly provided by the user. Merged additively with documentKeywords."),
947
1033
  sessionId: z.string().optional().describe("Session UUID for provenance stamping. Optional override; the server falls back to the SESSION_ID env var set by the admin agent at MCP spawn. The agent only needs to pass this when calling outside the normal admin-session context."),
948
- }, async ({ attachmentId, documentSummary, anchorNodeId, anchorLabel, sections, documentEdges, orphanCandidates, scope, sourceUrl, sourceType, documentKeywords, userKeywords, sessionId: sessionIdOverride }) => {
1034
+ }, async ({ attachmentId, conversationIdentity, source, archiveSha256, archiveSourceFile, participantElementIds, lastIngestedMessageHash, lastIngestedMessageAt, archiveTitle, cleanupPriorChunks, documentSummary, anchorNodeId, anchorLabel, sections, documentEdges, orphanCandidates, scope, sourceUrl, sourceType, documentKeywords, userKeywords, sessionId: sessionIdOverride }) => {
949
1035
  if (!accountId)
950
1036
  return refuseNoAccount("memory-ingest");
951
1037
  try {
952
1038
  const result = await memoryIngest({
953
1039
  accountId,
954
1040
  attachmentId,
1041
+ conversationIdentity,
1042
+ source,
1043
+ archiveSha256,
1044
+ archiveSourceFile,
1045
+ participantElementIds,
1046
+ lastIngestedMessageHash,
1047
+ lastIngestedMessageAt,
1048
+ archiveTitle,
1049
+ cleanupPriorChunks,
955
1050
  documentSummary,
956
1051
  anchorNodeId,
957
1052
  anchorLabel,
@@ -978,6 +1073,7 @@ if (!readOnly) {
978
1073
  orphanCandidates: result.orphanCandidates,
979
1074
  documentSummary: result.documentSummary,
980
1075
  keywords: result.keywords,
1076
+ cleanedPriorChunks: result.cleanedPriorChunks,
981
1077
  }),
982
1078
  }],
983
1079
  };
@@ -992,6 +1088,25 @@ if (!readOnly) {
992
1088
  };
993
1089
  }
994
1090
  });
1091
+ eagerTool(server, "kd-classify", "Operator-solicited reclassify for any :KnowledgeDocument that carries a `body` property (today: email-thread KDs; future: any thread-shaped source). Reads the KD by attachmentId, decides via a body-growth gate (proceed iff body grew ≥25% since the last classify, or first-ever classify), stages the body to a temp file under $ACCOUNT_DIR/tmp/, and returns a dispatch envelope the admin agent hands to the `librarian` specialist. Librarian runs the document-ingest skill against the temp file; memory-ingest MERGEs by attachmentId, replacing any prior :Section children, and stamps lastClassifiedAt + lastClassifiedBodyLength on the KD so the next gate call has a baseline. Bodyless attachment KDs (PDFs etc.) are not supported here — they have no growth signal.", {
1092
+ attachmentId: z.string().describe("attachmentId of the :KnowledgeDocument to classify. For email threads, this is sha256(`email:<accountId>:<rootMessageId>`); use the email-classify tool when you only have the root Message-ID."),
1093
+ }, async ({ attachmentId }) => {
1094
+ if (!accountId)
1095
+ return refuseNoAccount("kd-classify");
1096
+ try {
1097
+ const text = await kdClassify({ accountId, attachmentId });
1098
+ return { content: [{ type: "text", text }] };
1099
+ }
1100
+ catch (err) {
1101
+ return {
1102
+ content: [{
1103
+ type: "text",
1104
+ text: `kd-classify failed: ${err instanceof Error ? err.message : String(err)}`,
1105
+ }],
1106
+ isError: true,
1107
+ };
1108
+ }
1109
+ });
995
1110
  eagerTool(server, "memory-archive-write", "Bulk-archive write surface for flat datasets. " +
996
1111
  "Writes typed entities + natural edges in 500-row UNWIND batches. The Cypher body is fixed " +
997
1112
  "server-side per `archiveType`; the agent supplies parsed rows + the discriminant, never " +
@@ -1211,7 +1326,7 @@ if (!readOnly) {
1211
1326
  "",
1212
1327
  ...result.items.map((i) => {
1213
1328
  const preview = i.firstUserMsgPreview ? ` userPreview=${JSON.stringify(i.firstUserMsgPreview)}` : "";
1214
- return `- elementId=${i.elementId} conversationId=${i.conversationId ?? "null"} assistantMsgs=${i.assistantMsgCount} realUserMsgs=${i.realUserMsgCount}${preview}`;
1329
+ return `- elementId=${i.elementId} sessionId=${i.sessionId ?? "null"} assistantMsgs=${i.assistantMsgCount} realUserMsgs=${i.realUserMsgCount}${preview}`;
1215
1330
  }),
1216
1331
  ];
1217
1332
  return { content: [{ type: "text", text: lines.join("\n") }] };
@@ -1223,6 +1338,30 @@ if (!readOnly) {
1223
1338
  };
1224
1339
  }
1225
1340
  });
1341
+ server.tool("memory-node-exists", "Deterministic label-existence check for installer-seeded singleton roots. " +
1342
+ "Returns { exists, elementId, labels } for a single label/accountId lookup, " +
1343
+ "bypassing the memory-search ranking stack so an installer-seeded node with " +
1344
+ "empty content properties (e.g. a freshly seeded :LocalBusiness with no name yet) " +
1345
+ "is still reported as exists=true. Allow-list of labels is fixed: LocalBusiness, " +
1346
+ "AdminUser, UserProfile, Person. Refuses any other label — use memory-search for " +
1347
+ "ranked discovery on general labels. Use this before any branch that claims a " +
1348
+ "singleton root is missing.", {
1349
+ label: z.enum(MEMORY_NODE_EXISTS_LABELS).describe("Installer-seeded singleton label. One of: LocalBusiness, AdminUser, UserProfile, Person."),
1350
+ }, async ({ label }) => {
1351
+ if (!accountId)
1352
+ return refuseNoAccount("memory-node-exists");
1353
+ try {
1354
+ const result = await memoryNodeExists({ accountId, label });
1355
+ const payload = JSON.stringify(result);
1356
+ return { content: [{ type: "text", text: payload }] };
1357
+ }
1358
+ catch (err) {
1359
+ return {
1360
+ content: [{ type: "text", text: `memory-node-exists failed: ${err instanceof Error ? err.message : String(err)}` }],
1361
+ isError: true,
1362
+ };
1363
+ }
1364
+ });
1226
1365
  server.tool("memory-delete", "Soft-delete a single graph node by elementId. Adds the :Trashed label, preserves relationships, " +
1227
1366
  "and excludes the node from memory-search and any read filtered via notTrashed. For KnowledgeDocument, " +
1228
1367
  "cascades to linked Section and Chunk children. For Conversation, cascades to attached :PART_OF Messages " +
@@ -1473,7 +1612,7 @@ if (!readOnly) {
1473
1612
  }
1474
1613
  /** Format conversation header line with activity timestamps. Shared across metadata and inline modes. */
1475
1614
  function formatConversationHeader(opts) {
1476
- const label = opts.name ? `"${opts.name}"` : opts.conversationId.slice(0, 8) + "…";
1615
+ const label = opts.name ? `"${opts.name}"` : opts.sessionId.slice(0, 8) + "…";
1477
1616
  const agentInfo = opts.agentSlug ? `${opts.agentType}/${opts.agentSlug}` : opts.agentType;
1478
1617
  const createdStr = shortIso(opts.createdAt) || "(no timestamp)";
1479
1618
  const updatedStr = shortIso(opts.updatedAt);
@@ -1492,12 +1631,12 @@ if (!readOnly) {
1492
1631
  return `${label} [${agentInfo}] · created ${createdStr} · active ${updatedStr}${agoStr} — ${opts.messageCount} messages`;
1493
1632
  }
1494
1633
  server.tool("conversation-list", "List conversations or retrieve messages from a specific conversation. " +
1495
- "Without conversationId: lists all conversations with message counts, ordered by most recent activity (updatedAt DESC). " +
1634
+ "Without sessionId: lists all conversations with message counts, ordered by most recent activity (updatedAt DESC). " +
1496
1635
  "Headers show both creation time and last activity time; when they differ, the conversation was resumed. " +
1497
- "With conversationId: returns all messages in that conversation chronologically with per-message timestamps. " +
1636
+ "With sessionId: returns all messages in that conversation chronologically with per-message timestamps. " +
1498
1637
  "With includeMessages: returns conversations with their timestamped messages inline (useful for batch review). " +
1499
1638
  "The since filter matches against activity time (updatedAt), not creation time.", {
1500
- conversationId: z
1639
+ sessionId: z
1501
1640
  .string()
1502
1641
  .optional()
1503
1642
  .describe("If provided, returns messages for this conversation. If omitted, lists all conversations."),
@@ -1521,20 +1660,20 @@ if (!readOnly) {
1521
1660
  .number()
1522
1661
  .optional()
1523
1662
  .describe("Maximum results (default 50 for conversations, 200 for messages)"),
1524
- }, async ({ conversationId, agentType, agentSlug, since, includeMessages, limit }) => {
1663
+ }, async ({ sessionId, agentType, agentSlug, since, includeMessages, limit }) => {
1525
1664
  if (!accountId)
1526
1665
  return refuseNoAccount("conversation-list");
1527
1666
  const startTime = Date.now();
1528
1667
  const dbSession = getSession();
1529
1668
  try {
1530
- if (conversationId) {
1669
+ if (sessionId) {
1531
1670
  // Messages mode — chronological listing for a specific conversation
1532
1671
  const messageLimit = limit ?? 200;
1533
- const result = await dbSession.run(`MATCH (m:Message)-[:PART_OF]->(c:Conversation {conversationId: $conversationId, accountId: $accountId})
1672
+ const result = await dbSession.run(`MATCH (m:Message)-[:PART_OF]->(c:Conversation {sessionId: $sessionId, accountId: $accountId})
1534
1673
  WHERE ${notTrashed("m")} AND ${notTrashed("c")}
1535
1674
  RETURN m.role AS role, m.content AS content, m.createdAt AS createdAt
1536
1675
  ORDER BY m.createdAt ASC
1537
- LIMIT $limit`, { conversationId, accountId, limit: int(messageLimit) });
1676
+ LIMIT $limit`, { sessionId, accountId, limit: int(messageLimit) });
1538
1677
  if (result.records.length === 0) {
1539
1678
  return {
1540
1679
  content: [{ type: "text", text: "No messages found for this conversation." }],
@@ -1546,7 +1685,7 @@ if (!readOnly) {
1546
1685
  const ts = shortIso(String(r.get("createdAt") ?? ""));
1547
1686
  return ts ? `[${role} ${ts}]\n ${content}` : `[${role}]\n ${content}`;
1548
1687
  });
1549
- process.stderr.write(`[conversation-list] [${accountId}] mode=messages conversationId=${conversationId.slice(0, 8)}… count=${result.records.length} (${Date.now() - startTime}ms)\n`);
1688
+ process.stderr.write(`[conversation-list] [${accountId}] mode=messages sessionId=${sessionId.slice(0, 8)}… count=${result.records.length} (${Date.now() - startTime}ms)\n`);
1550
1689
  return {
1551
1690
  content: [{ type: "text", text: formatted.join("\n---\n") }],
1552
1691
  };
@@ -1579,7 +1718,7 @@ if (!readOnly) {
1579
1718
  OPTIONAL MATCH (m:Message)-[:PART_OF]->(c) WHERE ${trashedMsgFilter}
1580
1719
  WITH c, m ORDER BY m.createdAt ASC
1581
1720
  WITH c, collect({role: m.role, content: m.content, createdAt: m.createdAt})[0..${msgLimit}] AS messages
1582
- RETURN c.conversationId AS conversationId,
1721
+ RETURN c.sessionId AS sessionId,
1583
1722
  c.agentType AS agentType,
1584
1723
  c.agentSlug AS agentSlug,
1585
1724
  c.name AS name,
@@ -1594,11 +1733,11 @@ if (!readOnly) {
1594
1733
  };
1595
1734
  }
1596
1735
  const formatted = result.records.map((r) => {
1597
- const id = String(r.get("conversationId") ?? "");
1736
+ const id = String(r.get("sessionId") ?? "");
1598
1737
  const msgCount = Number(r.get("messageCount") ?? 0);
1599
1738
  const header = formatConversationHeader({
1600
1739
  name: r.get("name"),
1601
- conversationId: id,
1740
+ sessionId: id,
1602
1741
  agentType: String(r.get("agentType") ?? ""),
1603
1742
  agentSlug: r.get("agentSlug"),
1604
1743
  createdAt: String(r.get("createdAt") ?? ""),
@@ -1634,7 +1773,7 @@ if (!readOnly) {
1634
1773
  ${whereStr ? whereStr + " AND " : "WHERE "}${trashedConvFilter}
1635
1774
  WITH c ORDER BY c.updatedAt DESC LIMIT $limit
1636
1775
  OPTIONAL MATCH (m:Message)-[:PART_OF]->(c) WHERE ${trashedMsgFilter}
1637
- RETURN c.conversationId AS conversationId,
1776
+ RETURN c.sessionId AS sessionId,
1638
1777
  c.agentType AS agentType,
1639
1778
  c.agentSlug AS agentSlug,
1640
1779
  c.name AS name,
@@ -1648,13 +1787,13 @@ if (!readOnly) {
1648
1787
  };
1649
1788
  }
1650
1789
  const formatted = result.records.map((r) => {
1651
- const id = String(r.get("conversationId") ?? "");
1790
+ const id = String(r.get("sessionId") ?? "");
1652
1791
  const msgCount = typeof r.get("messageCount") === "number"
1653
1792
  ? r.get("messageCount")
1654
1793
  : Number(r.get("messageCount"));
1655
1794
  return formatConversationHeader({
1656
1795
  name: r.get("name"),
1657
- conversationId: id,
1796
+ sessionId: id,
1658
1797
  agentType: String(r.get("agentType") ?? ""),
1659
1798
  agentSlug: r.get("agentSlug"),
1660
1799
  createdAt: String(r.get("createdAt") ?? ""),
@@ -1691,7 +1830,7 @@ if (!readOnly) {
1691
1830
  .describe("How the preference was observed. Defaults to 'behavioural'."),
1692
1831
  mode: z.enum(["reinforce", "update", "contradict", "merge"]).optional()
1693
1832
  .describe("Update mode. Defaults to 'reinforce'."),
1694
- conversationId: z.string().optional()
1833
+ sessionId: z.string().optional()
1695
1834
  .describe("Conversation ID for evidence linking"),
1696
1835
  profileFields: z.record(z.string(), z.unknown()).optional()
1697
1836
  .describe("Top-level UserProfile fields to update (e.g. timezone, locale, role)"),
@@ -1702,7 +1841,7 @@ if (!readOnly) {
1702
1841
  .describe("Operator-identity fields written to the OWNS-bound Person. Use canonical `telephone` (NOT `phone` — that is the schema synonym, not the canonical name). Tool throws if the AdminUser-OWNS-Person edge is missing rather than silently no-op."),
1703
1842
  mergeSourceIds: z.array(z.string()).optional()
1704
1843
  .describe("For mode 'merge': preferenceIds of sources to combine into this preference"),
1705
- }, async ({ category, key, value, source, mode, conversationId, profileFields, personFields, mergeSourceIds }) => {
1844
+ }, async ({ category, key, value, source, mode, sessionId, profileFields, personFields, mergeSourceIds }) => {
1706
1845
  if (!accountId)
1707
1846
  return refuseNoAccount("profile-update");
1708
1847
  try {
@@ -1717,7 +1856,7 @@ if (!readOnly) {
1717
1856
  value,
1718
1857
  source,
1719
1858
  mode,
1720
- conversationId,
1859
+ sessionId,
1721
1860
  profileFields: profileFields,
1722
1861
  personFields,
1723
1862
  mergeSourceIds,
@@ -1901,15 +2040,15 @@ if (!readOnly) {
1901
2040
  "(Message nodes) is immutable history and is never modified — only the derived :Memory payload that " +
1902
2041
  "memory-search would otherwise re-surface. Use when a single conversation polluted memory with claims " +
1903
2042
  "that should not propagate (e.g. wrong-account hostnames, fabricated identifiers).", {
1904
- conversationId: z.string().min(1).describe("The Conversation node's conversationId to scope the expunge to."),
2043
+ sessionId: z.string().min(1).describe("The Conversation node's sessionId to scope the expunge to."),
1905
2044
  pattern: z.string().min(1).describe("The substring to scrub from string properties on linked :Memory nodes."),
1906
- }, async ({ conversationId, pattern }) => {
2045
+ }, async ({ sessionId, pattern }) => {
1907
2046
  if (!accountId)
1908
2047
  return refuseNoAccount("conversation-memory-expunge");
1909
2048
  try {
1910
- const result = await conversationMemoryExpunge({ accountId, conversationId, pattern });
2049
+ const result = await conversationMemoryExpunge({ accountId, sessionId, pattern });
1911
2050
  const lines = [
1912
- `Expunged "${result.pattern}" from conversation ${result.conversationId.slice(0, 8)}…`,
2051
+ `Expunged "${result.pattern}" from conversation ${result.sessionId.slice(0, 8)}…`,
1913
2052
  `:Memory nodes scanned: ${result.nodesScanned}`,
1914
2053
  `Properties nulled: ${result.propertiesNulled}`,
1915
2054
  ];
@@ -1967,7 +2106,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
1967
2106
  try {
1968
2107
  const conversationSessionId = resolveSessionId();
1969
2108
  const sessionClause = conversationSessionId
1970
- ? "AND node.conversationId = $sessionId"
2109
+ ? "AND node.sessionId = $sessionId"
1971
2110
  : "";
1972
2111
  const result = await dbSession.run(`CALL db.index.vector.queryNodes('message_embedding', $limit, $embedding)
1973
2112
  YIELD node, score
@@ -1979,7 +2118,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
1979
2118
  RETURN node.messageId AS messageId,
1980
2119
  node.role AS role,
1981
2120
  node.content AS content,
1982
- node.conversationId AS conversationId,
2121
+ node.sessionId AS sessionId,
1983
2122
  c.name AS sessionName,
1984
2123
  node.createdAt AS createdAt,
1985
2124
  score
@@ -2000,7 +2139,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
2000
2139
  const content = r.get("content");
2001
2140
  const score = typeof r.get("score") === "number" ? r.get("score") : Number(r.get("score"));
2002
2141
  const createdAt = String(r.get("createdAt"));
2003
- const convId = r.get("conversationId");
2142
+ const convId = r.get("sessionId");
2004
2143
  const sessionName = r.get("sessionName");
2005
2144
  const convPrefix = convId ? convId.slice(0, 8) : "unknown";
2006
2145
  const convLabel = sessionName
@@ -2010,7 +2149,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
2010
2149
  });
2011
2150
  // Diagnostic: log when admin search results span multiple conversations
2012
2151
  const distinctConvIds = new Set(result.records
2013
- .map((r) => r.get("conversationId"))
2152
+ .map((r) => r.get("sessionId"))
2014
2153
  .filter(Boolean));
2015
2154
  if (distinctConvIds.size > 1) {
2016
2155
  const prefixes = [...distinctConvIds].map((id) => id.slice(0, 8));
@@ -2082,7 +2221,7 @@ server.tool("image-fetch", [
2082
2221
  // bypassing this tool.
2083
2222
  server.tool("memory-typed-edge-pass", "Run the typed-edge auto-extraction pass over prose-bearing nodes this account wrote since sinceIso. Reads Message/Page/Meeting/Email/Idea/Note/Post/Report nodes, batches them, asks Haiku for typed-edge proposals against the closed allowlist (ATTENDED, WORKS_AT, INVESTED_IN, FOUNDED, ADVISES, MENTIONS, AUTHORED, ATTACHED_TO, REFERENCES), validates each proposal inline, and MERGEs accepted edges with createdBy provenance. Returns the counters (nodes, proposed, accepted, rejected, failed, ms) for the caller to hand back to admin's session-retrospective-mark-complete.", {
2084
2223
  sinceIso: z.string().describe("ISO timestamp lower bound. Prose nodes with updatedAt >= sinceIso are processed."),
2085
- conversationId: z.string().optional().describe("Conversation id stamped onto the createdBy provenance of MERGEd edges. Defaults to CONVERSATION_ID env if absent."),
2224
+ sessionId: z.string().optional().describe("Conversation id stamped onto the createdBy provenance of MERGEd edges. Defaults to SESSION_ID env if absent."),
2086
2225
  }, async (args) => {
2087
2226
  if (!accountId)
2088
2227
  return refuseNoAccount("memory-typed-edge-pass");