@rubytech/create-maxy-code 0.1.158 → 0.1.159
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.
- package/package.json +1 -1
- package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts +1 -1
- package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admin-conversation-purge/dist/index.js +4 -4
- package/payload/platform/lib/admin-conversation-purge/dist/index.js.map +1 -1
- package/payload/platform/lib/admin-conversation-purge/src/index.ts +5 -5
- package/payload/platform/lib/graph-style/dist/index.js +2 -2
- package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +1 -1
- package/payload/platform/lib/graph-style/src/index.ts +2 -2
- package/payload/platform/lib/graph-trash/dist/index.js +1 -1
- package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-trash/src/index.ts +1 -1
- package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +1 -1
- package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -1
- package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts +3 -3
- package/payload/platform/lib/graph-write/dist/conversation-provenance.js +5 -5
- package/payload/platform/lib/graph-write/dist/conversation-provenance.js.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +1 -1
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +1 -1
- package/payload/platform/lib/graph-write/src/conversation-provenance.ts +8 -8
- package/payload/platform/lib/graph-write/src/index.ts +1 -1
- package/payload/platform/neo4j/schema.cypher +30 -13
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +8 -4
- package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/per-turn-graph-pass-gate.test.sh +361 -0
- package/payload/platform/plugins/admin/hooks/__tests__/pre-turn-graph-pass.test.sh +13 -13
- package/payload/platform/plugins/admin/hooks/__tests__/turn-completed-graph-write.test.sh +1 -1
- package/payload/platform/plugins/admin/hooks/lib/admin-graph-pass-common.sh +102 -0
- package/payload/platform/plugins/admin/hooks/per-turn-graph-pass-gate.sh +106 -0
- package/payload/platform/plugins/admin/hooks/pre-turn-graph-pass.sh +15 -8
- package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +4 -4
- package/payload/platform/plugins/admin/mcp/dist/index.js +65 -24
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/session-management/SKILL.md +2 -2
- package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +5 -5
- package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +6 -6
- package/payload/platform/plugins/business-assistant/references/profiling.md +1 -1
- package/payload/platform/plugins/contacts/PLUGIN.md +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +2 -2
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js +3 -3
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js +2 -2
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +4 -4
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js +10 -10
- package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js.map +1 -1
- package/payload/platform/plugins/docs/references/admin-session.md +6 -6
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/internals.md +5 -5
- package/payload/platform/plugins/docs/references/plugins-guide.md +3 -3
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/email/PLUGIN.md +15 -2
- package/payload/platform/plugins/email/mcp/dist/index.js +53 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/embedding.js +2 -2
- package/payload/platform/plugins/email/mcp/dist/lib/embedding.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/graph.js +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/graph.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +23 -0
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js +15 -0
- package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts +15 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +49 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts +20 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +86 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +32 -52
- package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +19 -83
- package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +87 -0
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +29 -29
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +3 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +6 -6
- package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +2 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js +3 -3
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js +8 -8
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +4 -4
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +8 -8
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +11 -11
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/scripts/backfill-typed-edges.ts +1 -1
- package/payload/platform/plugins/memory/mcp/scripts/graph/fixture.cypher +1 -1
- package/payload/platform/plugins/memory/references/graph-primitives.md +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +4 -4
- package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +1 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +2 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/index.js +2 -2
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/project-create.js +6 -6
- package/payload/platform/plugins/work/mcp/dist/tools/project-create.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.js +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/session-list.js.map +1 -1
- package/payload/platform/plugins/x-import/references/archive-shape.md +2 -2
- package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +3 -3
- package/payload/platform/scripts/admin-persist-audit.ts +18 -18
- package/payload/platform/scripts/identity-forbidden-token-check.mjs +2 -0
- package/payload/platform/scripts/seed-neo4j.sh +1 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js +3 -3
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +3 -3
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +4 -4
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-AXOL2PPG.js → chunk-3TRIXQSJ.js} +101 -101
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{admin-3fLFD5h_.js → admin-Dal5FWaD.js} +2 -2
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Breg9-99.js → architectureDiagram-Q4EWVU46-Do2zYONG.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DXf1_673.js → blockDiagram-DXYQGD6D-DpIX_bRu.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CSZ36W4-.js → c4Diagram-AHTNJAMY-Cz335ZSY.js} +1 -1
- package/payload/server/public/assets/channel-PC4_IjI1.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-DsrLk2eK.js → chunk-336JU56O-Dmknn3Wo.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-JpNfNf81.js → chunk-426QAEUC-ClfGjizN.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-DmClEAD0.js → chunk-4TB4RGXK-BPKctJ5c.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-BI9blW3N.js → chunk-5FUZZQ4R-BWDCO9zw.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BbgttEFO.js → chunk-5PVQY5BW-BE34_Db0.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-BX_LCFOx.js → chunk-EDXVE4YY-BysA-_6v.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Bb7EoD0w.js → chunk-ENJZ2VHE-BMVyMsqA.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DH8uQk-s.js → chunk-ICPOFSXX-C5KRdLV4.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-FH5kgXsw.js → chunk-OYMX7WX6-DVZD-AVc.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-D_ljlkHr.js → chunk-U2HBQHQK-DYmQdx8x.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-BX3EmZvm.js → chunk-X2U36JSP-DrZenIl3.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Vu7-E93h.js → chunk-YZCP3GAM-CDuGbvMq.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-CwjhNPX5.js → chunk-ZZ45TVLE-COztbiu5.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-B_pMa-SX.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BdBAgF20.js +1 -0
- package/payload/server/public/assets/clone-CkNt9L9r.js +1 -0
- package/payload/server/public/assets/{dagre-Ce6gsj0C.js → dagre-Cv9Ib2OM.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BaMGpsoy.js → dagre-KV5264BT-CoEd61KZ.js} +1 -1
- package/payload/server/public/assets/{data-BHASh0_Y.js → data-DbSORCl4.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-CHEE9rjq.js → diagram-5BDNPKRD-WXNzw3uW.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-C98sZLW1.js → diagram-G4DWMVQ6-C6IuQ2VV.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DNvMGsTZ.js → diagram-MMDJMWI5-CdJdir5A.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Cdte4IBa.js → diagram-TYMM5635-DxWKQH5T.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-C9VZsWXK.js → erDiagram-SMLLAGMA-C9fvs33K.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-tuP5fzzR.js → flowDiagram-DWJPFMVM-BO7Yrbqv.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-SJgRPUwx.js → ganttDiagram-T4ZO3ILL-CQJyWBZq.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DU_cI_50.js → gitGraphDiagram-UUTBAWPF-DZfQHrYw.js} +1 -1
- package/payload/server/public/assets/{graph-labels-DXlmm1og.js → graph-labels-BBB5jsZk.js} +1 -1
- package/payload/server/public/assets/{graph-BhEI09tF.js → graph-ys_joP2o.js} +1 -1
- package/payload/server/public/assets/{graphlib-D_nAsvmx.js → graphlib-C40H-Q5E.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-Cj2Y19m6.js → infoDiagram-42DDH7IO-CakfV5f9.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DMc1xq1y.js → ishikawaDiagram-UXIWVN3A-CPuBPyfa.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C4CRAQma.js → journeyDiagram-VCZTEJTY-zpZm2Mmo.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CTr4AldU.js → kanban-definition-6JOO6SKY-DfJduQCo.js} +1 -1
- package/payload/server/public/assets/{line-Btlm_IAl.js → line-BpYQqO5R.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-DXFdj_y1.js → mermaid-parser.core-C5Mwi14D.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-DFBhoCr5.js → mermaid.core-D8qBtvvT.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-r9gVQybo.js → mindmap-definition-QFDTVHPH-Bli9JhIN.js} +1 -1
- package/payload/server/public/assets/{page-CDWu1Aft.js → page--bl5Y7ZI.js} +2 -2
- package/payload/server/public/assets/page-CwmZ76U7.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CHKZjSaH.js → pieDiagram-DEJITSTG-MsLXTSLg.js} +1 -1
- package/payload/server/public/assets/{public-DyGWgfaZ.js → public-DltgEfA9.js} +2 -2
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CSGR1HJr.js → quadrantDiagram-34T5L4WZ-De1sh2K0.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DZ6hX9D6.js → requirementDiagram-MS252O5E-D5Sfg1t_.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DbZBKh0m.js → sankeyDiagram-XADWPNL6-DHA3LIbv.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BHHpb8dt.js → sequenceDiagram-FGHM5R23-BE_QlG1B.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DQ1jiLB4.js → stateDiagram-FHFEXIEX-NIwp3F4u.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-pfk2F6st.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BlGiEU7p.js → timeline-definition-GMOUNBTQ-CPE9jyDF.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DmEH-hsB.js → vennDiagram-DHZGUBPP-CKfoyYmH.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-C7KJJ40d.js → wardleyDiagram-NUSXRM2D-B9yJek-o.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-JDnusCaa.js → xychartDiagram-5P7HB3ND-DuCcSLqX.js} +1 -1
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/public/public.html +1 -1
- package/payload/server/server.js +133 -133
- package/payload/server/public/assets/channel-BmZnt3PP.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-kmMLFUpV.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BV7Ae8ct.js +0 -1
- package/payload/server/public/assets/clone-B5eqoN9I.js +0 -1
- package/payload/server/public/assets/page-cyvshX4Z.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CByT2RzF.js +0 -1
|
@@ -54,7 +54,7 @@ The tool accepts the `messageId` of the email being replied to (visible in `emai
|
|
|
54
54
|
- **Reply to sender:** Default behaviour — replies to the original sender only.
|
|
55
55
|
- **Reply all:** Set `replyAll: true` to include all original recipients (TO + CC). The agent's own address is automatically excluded from the recipient list.
|
|
56
56
|
- **Threading:** The reply appears in the same conversation thread in Gmail, Apple Mail, Outlook, and other RFC 2822-compliant clients.
|
|
57
|
-
- **Prerequisite:** The original email must exist in the graph (
|
|
57
|
+
- **Prerequisite:** The original email must exist in the graph (ingested via the operator-initiated `email-ingest` flow). If the message hasn't been ingested yet, the tool returns a clear error.
|
|
58
58
|
|
|
59
59
|
Use `email-reply` when responding to a received email. Use `email-send` for new outbound messages.
|
|
60
60
|
|
|
@@ -71,26 +71,28 @@ When `agentAddress` is not set or matches the auth email, all tools behave as be
|
|
|
71
71
|
|
|
72
72
|
## Email Persistence
|
|
73
73
|
|
|
74
|
-
Emails
|
|
74
|
+
Emails enter the graph as `:KnowledgeDocument {source:'email'}` thread documents via the **operator-initiated ingestion flow** (see `skills/email-ingest/SKILL.md`). There is no background poll, cron, or auto-classifier — new messages are written only when the operator says "check my emails" and approves each one.
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
- **Deduplication:** Each email is identified by its Message-ID header. Re-polling the same messages does not create duplicates, even if the agent's email address changes between poll cycles. A composite unique constraint on `(messageId, accountId)` provides database-level enforcement.
|
|
78
|
-
- **Semantic search:** Stored emails are vector-indexed (subject + body preview), enabling natural-language search over email history via `email-graph-query`.
|
|
79
|
-
- **Isolation:** Each agent sees only emails addressed to its own bound email address, even when sharing a catchall mailbox.
|
|
76
|
+
The two ingestion tools:
|
|
80
77
|
|
|
81
|
-
|
|
78
|
+
- **`email-fetch`** — lists new IMAP messages since the stored high-water mark (`lastFetchedUid` on the `:EmailAccount` node). Returns sender, subject, date, Message-ID, UID, and a body preview. Writes nothing to the graph; stages the batch in-memory for the follow-up `email-ingest` call.
|
|
79
|
+
- **`email-ingest`** — takes a `decisions` array (`messageId` + `ingest` or `discard` per message). Writes only the `ingest` subset to the graph, advances `lastFetchedUid` to the batch's max UID, and consumes the staged batch. Refuses if any pending Message-ID lacks a decision.
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
Properties of the persistence layer:
|
|
84
82
|
|
|
85
|
-
- **
|
|
86
|
-
- **
|
|
87
|
-
- **
|
|
83
|
+
- **Operator-initiated only.** No `setInterval`, cron, or systemd timer ever invokes `email-fetch`. The operator drives every cycle.
|
|
84
|
+
- **Deduplication:** Each message is identified by Message-ID. Re-ingesting the same message MERGEs without duplicating; a composite unique constraint on `(messageId, accountId)` provides database-level enforcement.
|
|
85
|
+
- **Alias filtering:** Only emails addressed TO the agent's `agentAddress` are listed and ingested.
|
|
86
|
+
- **Semantic search:** Ingested threads are vector-indexed (subject + body preview), enabling natural-language search via `email-graph-query`.
|
|
87
|
+
- **Isolation:** Each agent sees only emails addressed to its own bound email address, even when sharing a catchall mailbox.
|
|
88
88
|
|
|
89
|
-
##
|
|
89
|
+
## Email Threading
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Ingested messages are linked into conversation threads as one `:KnowledgeDocument {source:'email'}` per thread, with `:Person` `FROM`/`TO`/`CC` edges. Threading is resolved by `In-Reply-To`/`References` headers at ingest time.
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
- **Out-of-order arrival:** If a reply is ingested before its parent, the reply lives in its own thread until the parent is ingested, at which point future ingests fold them together via the shared root.
|
|
94
|
+
- **Thread context:** `email-read` and `email-search` include `Thread-Depth` (number of hops to the thread root) and `Thread-ID` (emailId of the root message) for any message already in the graph. Root emails (no parent) have no thread fields.
|
|
95
|
+
- **Scope:** Thread linkage never crosses account boundaries — parent lookups are always scoped to the same `accountId`.
|
|
94
96
|
|
|
95
97
|
### Agent-Email Binding
|
|
96
98
|
|
|
@@ -112,31 +114,9 @@ When the user asks about stored emails, email history, or email recall — use `
|
|
|
112
114
|
|
|
113
115
|
## Inbound Email Screening
|
|
114
116
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### Verdicts
|
|
118
|
-
|
|
119
|
-
| Verdict | Stored? | Embedding? | Auto-respond? | Graph query? |
|
|
120
|
-
|---------|---------|------------|---------------|--------------|
|
|
121
|
-
| `clean` | Yes | Yes | Yes | Yes |
|
|
122
|
-
| `suspicious` | Yes (with `screeningReason`) | Yes | No | Yes |
|
|
123
|
-
| `discarded` | Yes (with `screeningReason`) | No | No | No (list mode) |
|
|
124
|
-
|
|
125
|
-
- **clean** — legitimate personal or business correspondence
|
|
126
|
-
- **suspicious** — phishing indicators (urgency + credential requests, mismatched sender), prompt injection patterns, or classification failure (safe default)
|
|
127
|
-
- **discarded** — obvious spam, marketing bulk mail, auto-generated notifications with no actionable content
|
|
128
|
-
|
|
129
|
-
### Prompt injection flag
|
|
117
|
+
There is no automated screener. The operator screens by eye during the `email-ingest` skill flow: `email-fetch` lists the new messages with sender, subject, and a body preview; the operator picks which ones to ingest and which to discard. A `screening` property of `clean` is stamped on every operator-approved row as a provenance marker (operator-approved), and discarded messages never enter the graph.
|
|
130
118
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
### Failure handling
|
|
134
|
-
|
|
135
|
-
If the Haiku API is unavailable (network, rate limit, auth failure), the email defaults to `suspicious`. The entire fetch batch is never blocked — each email is classified independently. API key absence causes all emails in the batch to default to `suspicious`.
|
|
136
|
-
|
|
137
|
-
### Logs
|
|
138
|
-
|
|
139
|
-
Classification verdicts are logged to `{accountDir}/logs/email-fetch.log` with per-email detail (fromAddress, verdict, reason, promptInjectionRisk) and batch summaries.
|
|
119
|
+
The previous Haiku classifier was removed in Task 424; the auto-respond binary that depended on it was removed alongside the screener. Both are intentionally absent — the doctrine is that every LLM-bearing pipeline is operator-initiated.
|
|
140
120
|
|
|
141
121
|
## Security
|
|
142
122
|
|
|
@@ -144,51 +124,7 @@ Classification verdicts are logged to `{accountDir}/logs/email-fetch.log` with p
|
|
|
144
124
|
- IMAP and SMTP connections require TLS or STARTTLS — plaintext is rejected
|
|
145
125
|
- Only the agent's own dedicated account is accessed — never the user's personal email
|
|
146
126
|
- Email nodes have `scope: "admin"` — never visible to public agents
|
|
147
|
-
- Inbound
|
|
148
|
-
|
|
149
|
-
## Auto-Respond
|
|
150
|
-
|
|
151
|
-
When enabled, a public agent replies to incoming emails. The auto-respond binary lives at `email/mcp/dist/scripts/email-auto-respond.js` and, like the fetcher, is **not currently scheduled on any install** — see `maxy-code-prd.md` §Scheduled tasks for the canonical dispatch destination. Until that landing, auto-respond only runs when an operator invokes the script manually.
|
|
152
|
-
|
|
153
|
-
### Setup
|
|
154
|
-
|
|
155
|
-
To enable auto-respond, call `email-auto-respond-config` with `enabled: true`. The tool requires an `agentSlug`. When called without a slug, the tool returns available public agents — present these as a numbered list in plain chat so the admin can choose which agent handles responses, then call the tool again with the selected slug.
|
|
156
|
-
|
|
157
|
-
### Configuration
|
|
158
|
-
|
|
159
|
-
- `enabled` — `true` to enable, `false` to disable
|
|
160
|
-
- `agentSlug` — slug of the public agent that responds (required when enabling)
|
|
161
|
-
- `pollIntervalMinutes` — how often to check for new emails (default: 5, range: 1–60)
|
|
162
|
-
- `hourlyLimit` — maximum auto-replies per clock hour UTC (default: 20, range: 1–1000)
|
|
163
|
-
- `dailyLimit` — maximum auto-replies per calendar day UTC (default: 100, range: 1–10000)
|
|
164
|
-
|
|
165
|
-
### Behaviour
|
|
166
|
-
|
|
167
|
-
- Once the dispatcher is wired (see above), each account's poll is skipped if the configured interval hasn't elapsed since the last poll. The interval gate is enforced inside `email-auto-respond.js`, so the same skip logic applies whether the script is fired by the dispatcher or manually by an operator.
|
|
168
|
-
- Only emails addressed TO the agent's email address are processed (alias filtering applies).
|
|
169
|
-
- Auto-replies, mailing list messages, and emails from the agent's own address are automatically skipped (RFC 3834 loop prevention).
|
|
170
|
-
- Outgoing replies include `In-Reply-To` and `References` headers for correct threading, and `Auto-Submitted: auto-replied` to prevent loops with other auto-responders.
|
|
171
|
-
- Every reply includes a deterministic AI disclosure footer ("This reply was generated by an AI assistant.") appended after the agent's response. This is a regulatory requirement (EU AI Act Article 50) and is not dependent on the LLM including disclosure in its generated text.
|
|
172
|
-
- The subject line carries a single `Re:` prefix (no doubling).
|
|
173
|
-
|
|
174
|
-
### Rate Limiting
|
|
175
|
-
|
|
176
|
-
Per-account send caps prevent runaway auto-replies from spam waves, mailing list explosions, or deliberate attacks. Two independent limits:
|
|
177
|
-
|
|
178
|
-
- **Hourly limit** (default 20) — resets at each UTC clock-hour boundary
|
|
179
|
-
- **Daily limit** (default 100) — resets at midnight UTC
|
|
180
|
-
|
|
181
|
-
When either limit is reached, remaining emails in the poll cycle are skipped (not replied to). Auto-respond is **not** disabled — counters reset naturally at the next boundary. A medium-priority admin Task is created to notify the admin.
|
|
182
|
-
|
|
183
|
-
Within a single poll cycle, only one auto-reply is sent per unique sender address. This prevents reply storms when an automated sender delivers multiple messages. Sender deduplication is case-insensitive.
|
|
184
|
-
|
|
185
|
-
### Circuit Breaker
|
|
186
|
-
|
|
187
|
-
After 3 consecutive failures (IMAP errors, API failures, SMTP rejections), auto-respond is automatically disabled and a high-priority Task is created for the admin. The admin sees this task at the start of their next session and can re-enable auto-respond after resolving the issue.
|
|
188
|
-
|
|
189
|
-
### Disabling
|
|
190
|
-
|
|
191
|
-
Call `email-auto-respond-config` with `enabled: false`. This clears the agent assignment and resets the failure counter.
|
|
127
|
+
- Inbound messages enter the graph only when the operator approves them by eye via `email-ingest`
|
|
192
128
|
|
|
193
129
|
## OTP Integration
|
|
194
130
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: email-ingest
|
|
3
|
+
description: "Operator-initiated email ingestion. Activate when the operator asks to check, triage, or pull in new email ('check my emails', 'any new mail?', 'pull in the latest emails', 'what came in overnight'). Drives a list → summarise → ask → ingest loop using the email-fetch and email-ingest tools. Human-in-the-loop: nothing enters the graph without an explicit operator decision per message."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Email ingestion
|
|
7
|
+
|
|
8
|
+
Operator-initiated, human-in-the-loop ingestion of the agent's IMAP inbox into the graph. New messages enter the knowledge graph **only** when the operator says so, and only the ones they pick. There is no background poll, no automatic classifier, no silent writes.
|
|
9
|
+
|
|
10
|
+
## When to activate
|
|
11
|
+
|
|
12
|
+
Activate when the operator wants to bring new email into the agent's memory. Typical phrasings:
|
|
13
|
+
|
|
14
|
+
- "Check my emails."
|
|
15
|
+
- "Any new mail?"
|
|
16
|
+
- "Pull in the latest emails."
|
|
17
|
+
- "What came in overnight?"
|
|
18
|
+
|
|
19
|
+
Do **not** activate for:
|
|
20
|
+
|
|
21
|
+
- Searching, reading, or recalling email already in the inbox or the graph — those are `email-search`, `email-read`, `email-graph-query`.
|
|
22
|
+
- Drafting or sending — that's `email-composition`.
|
|
23
|
+
- Setup, status, or OTP extraction — those are direct tool calls.
|
|
24
|
+
|
|
25
|
+
## Flow
|
|
26
|
+
|
|
27
|
+
### 1. List
|
|
28
|
+
|
|
29
|
+
Call `email-fetch`. It pulls new messages since the stored high-water mark (or a `since_uid` if the operator asked for a wider window) and stages them in-memory for the follow-up ingest. **It writes nothing to the graph.**
|
|
30
|
+
|
|
31
|
+
If `email-fetch` returns "No new messages", say that and stop. There is nothing to ingest.
|
|
32
|
+
|
|
33
|
+
### 2. Summarise
|
|
34
|
+
|
|
35
|
+
Present the listed messages to the operator as a numbered or per-`Message-ID` summary. For each, surface:
|
|
36
|
+
|
|
37
|
+
- Sender (name + address).
|
|
38
|
+
- Subject.
|
|
39
|
+
- A one-line gist drawn from the body preview (not the full preview — keep it tight).
|
|
40
|
+
- A suggested disposition where the message is obviously one or the other (e.g., "newsletter — looks like discard", "thread reply from a known correspondent — looks like ingest"). The suggestion is a hint, never an action; the operator decides.
|
|
41
|
+
|
|
42
|
+
Do not classify suspicious vs clean — there is no screener. If a message looks like phishing, surface that observation in plain English so the operator can discard it by eye.
|
|
43
|
+
|
|
44
|
+
### 3. Ask
|
|
45
|
+
|
|
46
|
+
Ask the operator to confirm a disposition for **every** message in the list. Either:
|
|
47
|
+
|
|
48
|
+
- A blanket call ("ingest all", "discard everything"), which you turn into the per-message map.
|
|
49
|
+
- An explicit per-message choice ("ingest 1, 2, 4; discard 3").
|
|
50
|
+
|
|
51
|
+
If the operator answers ambiguously ("the work ones"), restate the messages you think they mean and confirm before proceeding. Never guess.
|
|
52
|
+
|
|
53
|
+
### 4. Ingest
|
|
54
|
+
|
|
55
|
+
Call `email-ingest` with a `decisions` array containing one entry per Message-ID returned by `email-fetch`. The tool refuses if any pending Message-ID is missing a decision — that's the safeguard against silent drops, not an error to retry around. If it refuses, go back to the operator and ask about the missing ones.
|
|
56
|
+
|
|
57
|
+
On success the tool returns a one-line summary (ingested / discarded / thread counts) and advances the inbox high-water mark.
|
|
58
|
+
|
|
59
|
+
### 5. Confirm
|
|
60
|
+
|
|
61
|
+
Echo the tool's summary back to the operator in one sentence. If they want to draft a reply to anything that was just ingested, hand off to `email-composition`.
|
|
62
|
+
|
|
63
|
+
## Edge cases
|
|
64
|
+
|
|
65
|
+
| Situation | Behaviour |
|
|
66
|
+
|-----------|-----------|
|
|
67
|
+
| `email-fetch` returns zero new messages | Tell the operator and stop. Do not call `email-ingest`. |
|
|
68
|
+
| A listed message has no `Message-ID` header | Surface it by UID and ask the operator how to handle it. `email-ingest` cannot apply a per-message decision to it, so either widen the search or skip it explicitly. |
|
|
69
|
+
| Operator wants to ingest some now and review the rest later | Refuse cleanly. The high-water mark advances on every successful ingest, so a partial decision would silently drop the rest. Ask them to commit one way or the other on every message, or to wait. |
|
|
70
|
+
| Operator abandons mid-flow | Do not call `email-ingest`. The staged batch stays in memory until the next `email-fetch` overwrites it; the high-water mark does not move. |
|
|
71
|
+
| `email-fetch` errors (IMAP down, auth failure) | Surface the error verbatim. Do not retry silently. |
|
|
72
|
+
|
|
73
|
+
## Out of scope
|
|
74
|
+
|
|
75
|
+
- **Automatic re-screening or LLM classification.** The screener was removed; the operator is the screener now.
|
|
76
|
+
- **Scheduled or recurring ingestion.** There is no cron, no interval, no background trigger. The operator initiates every cycle.
|
|
77
|
+
- **Per-thread or per-sender allowlists.** Each message gets a fresh decision.
|
|
78
|
+
- **Other channels.** WhatsApp and the public web have their own ingestion paths.
|
|
79
|
+
|
|
80
|
+
## Observability
|
|
81
|
+
|
|
82
|
+
Each tool emits a single tagged log line:
|
|
83
|
+
|
|
84
|
+
- `[email-fetch] tag=email-fetch listed=<n> sinceUid=<uid>` — one per list call.
|
|
85
|
+
- `[email-ingest] tag=email-ingest ingested=<n> discarded=<m>` — one per ingest call.
|
|
86
|
+
|
|
87
|
+
A complete cycle is greppable as the pair `email-fetch` → `email-ingest` for the same session.
|
|
@@ -160,7 +160,7 @@ Writes targeting `:Person`, `:UserProfile`, `:AdminUser`, `:Organization`, `:Loc
|
|
|
160
160
|
|
|
161
161
|
- **Workflow path — `producedByTaskId`.** `memory-write` accepts an optional `producedByTaskId` parameter. When set, the platform composes an inbound `:PRODUCED` edge from that `:Task` node into the write's `relationships` array before the write runs. The Task and the new node must share the same `accountId`; mismatch is rejected loud. The typical pattern: call `work-create` at the start of an autonomous flow (onboarding skill, cloudflare tunnel-login) with `kind` and `raisedDuringConversationKey`; capture the returned `taskId`; pass it as `producedByTaskId` on every subsequent `memory-write` for one of the gated labels.
|
|
162
162
|
|
|
163
|
-
- **Direct-ask path — `
|
|
163
|
+
- **Direct-ask path — `SESSION_NODE_ID` env-stamp.** When `producedByTaskId` is not provided (typical of direct admin asks like "add Anneke as person"), `memory-write` falls back to the `SESSION_NODE_ID` env var. The admin server stamps it at PTY spawn time on both admin sessions and on the specialist subagent spawns the admin dispatches (Task 382 — listing-curator, content-producer, database-operator and friends inherit the same anchor). The value is the `sessionId` UUID of the active `:AdminConversation`; the wrapper's `injectConversationProvenance` MATCHes `(c:Conversation {sessionId, accountId})` so account isolation is enforced inside the natural key — a cross-account stamp returns zero rows and never injects. Autonomous spawns with no parent conversation (cron, scheduled-task) legitimately have no env-stamp; those must thread `producedByTaskId` via `work-create` instead. The env-stamp is invisible to the agent (no schema field changes); the LLM never decides whether to use it.
|
|
164
164
|
|
|
165
165
|
## Graph Hygiene
|
|
166
166
|
|
|
@@ -676,7 +676,7 @@ if (!readOnly) {
|
|
|
676
676
|
keywords,
|
|
677
677
|
sourceWorkflow,
|
|
678
678
|
occurredAt,
|
|
679
|
-
conversationNodeId: process.env.
|
|
679
|
+
conversationNodeId: process.env.SESSION_NODE_ID,
|
|
680
680
|
});
|
|
681
681
|
const status = result.created
|
|
682
682
|
? `Report created`
|
|
@@ -1211,7 +1211,7 @@ if (!readOnly) {
|
|
|
1211
1211
|
"",
|
|
1212
1212
|
...result.items.map((i) => {
|
|
1213
1213
|
const preview = i.firstUserMsgPreview ? ` userPreview=${JSON.stringify(i.firstUserMsgPreview)}` : "";
|
|
1214
|
-
return `- elementId=${i.elementId}
|
|
1214
|
+
return `- elementId=${i.elementId} sessionId=${i.sessionId ?? "null"} assistantMsgs=${i.assistantMsgCount} realUserMsgs=${i.realUserMsgCount}${preview}`;
|
|
1215
1215
|
}),
|
|
1216
1216
|
];
|
|
1217
1217
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
@@ -1473,7 +1473,7 @@ if (!readOnly) {
|
|
|
1473
1473
|
}
|
|
1474
1474
|
/** Format conversation header line with activity timestamps. Shared across metadata and inline modes. */
|
|
1475
1475
|
function formatConversationHeader(opts) {
|
|
1476
|
-
const label = opts.name ? `"${opts.name}"` : opts.
|
|
1476
|
+
const label = opts.name ? `"${opts.name}"` : opts.sessionId.slice(0, 8) + "…";
|
|
1477
1477
|
const agentInfo = opts.agentSlug ? `${opts.agentType}/${opts.agentSlug}` : opts.agentType;
|
|
1478
1478
|
const createdStr = shortIso(opts.createdAt) || "(no timestamp)";
|
|
1479
1479
|
const updatedStr = shortIso(opts.updatedAt);
|
|
@@ -1492,12 +1492,12 @@ if (!readOnly) {
|
|
|
1492
1492
|
return `${label} [${agentInfo}] · created ${createdStr} · active ${updatedStr}${agoStr} — ${opts.messageCount} messages`;
|
|
1493
1493
|
}
|
|
1494
1494
|
server.tool("conversation-list", "List conversations or retrieve messages from a specific conversation. " +
|
|
1495
|
-
"Without
|
|
1495
|
+
"Without sessionId: lists all conversations with message counts, ordered by most recent activity (updatedAt DESC). " +
|
|
1496
1496
|
"Headers show both creation time and last activity time; when they differ, the conversation was resumed. " +
|
|
1497
|
-
"With
|
|
1497
|
+
"With sessionId: returns all messages in that conversation chronologically with per-message timestamps. " +
|
|
1498
1498
|
"With includeMessages: returns conversations with their timestamped messages inline (useful for batch review). " +
|
|
1499
1499
|
"The since filter matches against activity time (updatedAt), not creation time.", {
|
|
1500
|
-
|
|
1500
|
+
sessionId: z
|
|
1501
1501
|
.string()
|
|
1502
1502
|
.optional()
|
|
1503
1503
|
.describe("If provided, returns messages for this conversation. If omitted, lists all conversations."),
|
|
@@ -1521,20 +1521,20 @@ if (!readOnly) {
|
|
|
1521
1521
|
.number()
|
|
1522
1522
|
.optional()
|
|
1523
1523
|
.describe("Maximum results (default 50 for conversations, 200 for messages)"),
|
|
1524
|
-
}, async ({
|
|
1524
|
+
}, async ({ sessionId, agentType, agentSlug, since, includeMessages, limit }) => {
|
|
1525
1525
|
if (!accountId)
|
|
1526
1526
|
return refuseNoAccount("conversation-list");
|
|
1527
1527
|
const startTime = Date.now();
|
|
1528
1528
|
const dbSession = getSession();
|
|
1529
1529
|
try {
|
|
1530
|
-
if (
|
|
1530
|
+
if (sessionId) {
|
|
1531
1531
|
// Messages mode — chronological listing for a specific conversation
|
|
1532
1532
|
const messageLimit = limit ?? 200;
|
|
1533
|
-
const result = await dbSession.run(`MATCH (m:Message)-[:PART_OF]->(c:Conversation {
|
|
1533
|
+
const result = await dbSession.run(`MATCH (m:Message)-[:PART_OF]->(c:Conversation {sessionId: $sessionId, accountId: $accountId})
|
|
1534
1534
|
WHERE ${notTrashed("m")} AND ${notTrashed("c")}
|
|
1535
1535
|
RETURN m.role AS role, m.content AS content, m.createdAt AS createdAt
|
|
1536
1536
|
ORDER BY m.createdAt ASC
|
|
1537
|
-
LIMIT $limit`, {
|
|
1537
|
+
LIMIT $limit`, { sessionId, accountId, limit: int(messageLimit) });
|
|
1538
1538
|
if (result.records.length === 0) {
|
|
1539
1539
|
return {
|
|
1540
1540
|
content: [{ type: "text", text: "No messages found for this conversation." }],
|
|
@@ -1546,7 +1546,7 @@ if (!readOnly) {
|
|
|
1546
1546
|
const ts = shortIso(String(r.get("createdAt") ?? ""));
|
|
1547
1547
|
return ts ? `[${role} ${ts}]\n ${content}` : `[${role}]\n ${content}`;
|
|
1548
1548
|
});
|
|
1549
|
-
process.stderr.write(`[conversation-list] [${accountId}] mode=messages
|
|
1549
|
+
process.stderr.write(`[conversation-list] [${accountId}] mode=messages sessionId=${sessionId.slice(0, 8)}… count=${result.records.length} (${Date.now() - startTime}ms)\n`);
|
|
1550
1550
|
return {
|
|
1551
1551
|
content: [{ type: "text", text: formatted.join("\n---\n") }],
|
|
1552
1552
|
};
|
|
@@ -1579,7 +1579,7 @@ if (!readOnly) {
|
|
|
1579
1579
|
OPTIONAL MATCH (m:Message)-[:PART_OF]->(c) WHERE ${trashedMsgFilter}
|
|
1580
1580
|
WITH c, m ORDER BY m.createdAt ASC
|
|
1581
1581
|
WITH c, collect({role: m.role, content: m.content, createdAt: m.createdAt})[0..${msgLimit}] AS messages
|
|
1582
|
-
RETURN c.
|
|
1582
|
+
RETURN c.sessionId AS sessionId,
|
|
1583
1583
|
c.agentType AS agentType,
|
|
1584
1584
|
c.agentSlug AS agentSlug,
|
|
1585
1585
|
c.name AS name,
|
|
@@ -1594,11 +1594,11 @@ if (!readOnly) {
|
|
|
1594
1594
|
};
|
|
1595
1595
|
}
|
|
1596
1596
|
const formatted = result.records.map((r) => {
|
|
1597
|
-
const id = String(r.get("
|
|
1597
|
+
const id = String(r.get("sessionId") ?? "");
|
|
1598
1598
|
const msgCount = Number(r.get("messageCount") ?? 0);
|
|
1599
1599
|
const header = formatConversationHeader({
|
|
1600
1600
|
name: r.get("name"),
|
|
1601
|
-
|
|
1601
|
+
sessionId: id,
|
|
1602
1602
|
agentType: String(r.get("agentType") ?? ""),
|
|
1603
1603
|
agentSlug: r.get("agentSlug"),
|
|
1604
1604
|
createdAt: String(r.get("createdAt") ?? ""),
|
|
@@ -1634,7 +1634,7 @@ if (!readOnly) {
|
|
|
1634
1634
|
${whereStr ? whereStr + " AND " : "WHERE "}${trashedConvFilter}
|
|
1635
1635
|
WITH c ORDER BY c.updatedAt DESC LIMIT $limit
|
|
1636
1636
|
OPTIONAL MATCH (m:Message)-[:PART_OF]->(c) WHERE ${trashedMsgFilter}
|
|
1637
|
-
RETURN c.
|
|
1637
|
+
RETURN c.sessionId AS sessionId,
|
|
1638
1638
|
c.agentType AS agentType,
|
|
1639
1639
|
c.agentSlug AS agentSlug,
|
|
1640
1640
|
c.name AS name,
|
|
@@ -1648,13 +1648,13 @@ if (!readOnly) {
|
|
|
1648
1648
|
};
|
|
1649
1649
|
}
|
|
1650
1650
|
const formatted = result.records.map((r) => {
|
|
1651
|
-
const id = String(r.get("
|
|
1651
|
+
const id = String(r.get("sessionId") ?? "");
|
|
1652
1652
|
const msgCount = typeof r.get("messageCount") === "number"
|
|
1653
1653
|
? r.get("messageCount")
|
|
1654
1654
|
: Number(r.get("messageCount"));
|
|
1655
1655
|
return formatConversationHeader({
|
|
1656
1656
|
name: r.get("name"),
|
|
1657
|
-
|
|
1657
|
+
sessionId: id,
|
|
1658
1658
|
agentType: String(r.get("agentType") ?? ""),
|
|
1659
1659
|
agentSlug: r.get("agentSlug"),
|
|
1660
1660
|
createdAt: String(r.get("createdAt") ?? ""),
|
|
@@ -1691,7 +1691,7 @@ if (!readOnly) {
|
|
|
1691
1691
|
.describe("How the preference was observed. Defaults to 'behavioural'."),
|
|
1692
1692
|
mode: z.enum(["reinforce", "update", "contradict", "merge"]).optional()
|
|
1693
1693
|
.describe("Update mode. Defaults to 'reinforce'."),
|
|
1694
|
-
|
|
1694
|
+
sessionId: z.string().optional()
|
|
1695
1695
|
.describe("Conversation ID for evidence linking"),
|
|
1696
1696
|
profileFields: z.record(z.string(), z.unknown()).optional()
|
|
1697
1697
|
.describe("Top-level UserProfile fields to update (e.g. timezone, locale, role)"),
|
|
@@ -1702,7 +1702,7 @@ if (!readOnly) {
|
|
|
1702
1702
|
.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
1703
|
mergeSourceIds: z.array(z.string()).optional()
|
|
1704
1704
|
.describe("For mode 'merge': preferenceIds of sources to combine into this preference"),
|
|
1705
|
-
}, async ({ category, key, value, source, mode,
|
|
1705
|
+
}, async ({ category, key, value, source, mode, sessionId, profileFields, personFields, mergeSourceIds }) => {
|
|
1706
1706
|
if (!accountId)
|
|
1707
1707
|
return refuseNoAccount("profile-update");
|
|
1708
1708
|
try {
|
|
@@ -1717,7 +1717,7 @@ if (!readOnly) {
|
|
|
1717
1717
|
value,
|
|
1718
1718
|
source,
|
|
1719
1719
|
mode,
|
|
1720
|
-
|
|
1720
|
+
sessionId,
|
|
1721
1721
|
profileFields: profileFields,
|
|
1722
1722
|
personFields,
|
|
1723
1723
|
mergeSourceIds,
|
|
@@ -1901,15 +1901,15 @@ if (!readOnly) {
|
|
|
1901
1901
|
"(Message nodes) is immutable history and is never modified — only the derived :Memory payload that " +
|
|
1902
1902
|
"memory-search would otherwise re-surface. Use when a single conversation polluted memory with claims " +
|
|
1903
1903
|
"that should not propagate (e.g. wrong-account hostnames, fabricated identifiers).", {
|
|
1904
|
-
|
|
1904
|
+
sessionId: z.string().min(1).describe("The Conversation node's sessionId to scope the expunge to."),
|
|
1905
1905
|
pattern: z.string().min(1).describe("The substring to scrub from string properties on linked :Memory nodes."),
|
|
1906
|
-
}, async ({
|
|
1906
|
+
}, async ({ sessionId, pattern }) => {
|
|
1907
1907
|
if (!accountId)
|
|
1908
1908
|
return refuseNoAccount("conversation-memory-expunge");
|
|
1909
1909
|
try {
|
|
1910
|
-
const result = await conversationMemoryExpunge({ accountId,
|
|
1910
|
+
const result = await conversationMemoryExpunge({ accountId, sessionId, pattern });
|
|
1911
1911
|
const lines = [
|
|
1912
|
-
`Expunged "${result.pattern}" from conversation ${result.
|
|
1912
|
+
`Expunged "${result.pattern}" from conversation ${result.sessionId.slice(0, 8)}…`,
|
|
1913
1913
|
`:Memory nodes scanned: ${result.nodesScanned}`,
|
|
1914
1914
|
`Properties nulled: ${result.propertiesNulled}`,
|
|
1915
1915
|
];
|
|
@@ -1967,7 +1967,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
|
|
|
1967
1967
|
try {
|
|
1968
1968
|
const conversationSessionId = resolveSessionId();
|
|
1969
1969
|
const sessionClause = conversationSessionId
|
|
1970
|
-
? "AND node.
|
|
1970
|
+
? "AND node.sessionId = $sessionId"
|
|
1971
1971
|
: "";
|
|
1972
1972
|
const result = await dbSession.run(`CALL db.index.vector.queryNodes('message_embedding', $limit, $embedding)
|
|
1973
1973
|
YIELD node, score
|
|
@@ -1979,7 +1979,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
|
|
|
1979
1979
|
RETURN node.messageId AS messageId,
|
|
1980
1980
|
node.role AS role,
|
|
1981
1981
|
node.content AS content,
|
|
1982
|
-
node.
|
|
1982
|
+
node.sessionId AS sessionId,
|
|
1983
1983
|
c.name AS sessionName,
|
|
1984
1984
|
node.createdAt AS createdAt,
|
|
1985
1985
|
score
|
|
@@ -2000,7 +2000,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
|
|
|
2000
2000
|
const content = r.get("content");
|
|
2001
2001
|
const score = typeof r.get("score") === "number" ? r.get("score") : Number(r.get("score"));
|
|
2002
2002
|
const createdAt = String(r.get("createdAt"));
|
|
2003
|
-
const convId = r.get("
|
|
2003
|
+
const convId = r.get("sessionId");
|
|
2004
2004
|
const sessionName = r.get("sessionName");
|
|
2005
2005
|
const convPrefix = convId ? convId.slice(0, 8) : "unknown";
|
|
2006
2006
|
const convLabel = sessionName
|
|
@@ -2010,7 +2010,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
|
|
|
2010
2010
|
});
|
|
2011
2011
|
// Diagnostic: log when admin search results span multiple conversations
|
|
2012
2012
|
const distinctConvIds = new Set(result.records
|
|
2013
|
-
.map((r) => r.get("
|
|
2013
|
+
.map((r) => r.get("sessionId"))
|
|
2014
2014
|
.filter(Boolean));
|
|
2015
2015
|
if (distinctConvIds.size > 1) {
|
|
2016
2016
|
const prefixes = [...distinctConvIds].map((id) => id.slice(0, 8));
|
|
@@ -2082,7 +2082,7 @@ server.tool("image-fetch", [
|
|
|
2082
2082
|
// bypassing this tool.
|
|
2083
2083
|
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
2084
|
sinceIso: z.string().describe("ISO timestamp lower bound. Prose nodes with updatedAt >= sinceIso are processed."),
|
|
2085
|
-
|
|
2085
|
+
sessionId: z.string().optional().describe("Conversation id stamped onto the createdBy provenance of MERGEd edges. Defaults to SESSION_ID env if absent."),
|
|
2086
2086
|
}, async (args) => {
|
|
2087
2087
|
if (!accountId)
|
|
2088
2088
|
return refuseNoAccount("memory-typed-edge-pass");
|