@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.
- 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-search/src/__tests__/fulltext-coverage.test.ts +48 -17
- 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 +86 -46
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- 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/archive-ingest-surface-gate.sh +2 -2
- 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/business-profile/SKILL.md +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 +6 -5
- 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 +19 -2
- package/payload/platform/plugins/email/mcp/dist/index.js +78 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts +8 -0
- package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js +177 -0
- package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js.map +1 -0
- 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.d.ts +6 -54
- package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/graph.js +12 -300
- 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-classify.d.ts +6 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js +89 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-classify.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 +91 -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/linkedin-import/skills/linkedin-import/SKILL.md +10 -37
- package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md +1 -0
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +11 -2
- package/payload/platform/plugins/memory/bin/conversation-archive-ingest.mjs +139 -439
- package/payload/platform/plugins/memory/bin/conversation-archive-ingest.sh +15 -47
- package/payload/platform/plugins/memory/mcp/dist/index.js +197 -58
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +43 -27
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js +62 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +5 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts +42 -25
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js +23 -17
- package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js +61 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.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/conversation-pipeline/derive-keys.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +9 -3
- package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.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/kd-classify-gate.d.ts +41 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js +71 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts +18 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js +31 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js.map +1 -0
- 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-archive-derive-insights.test.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +162 -78
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js.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__/conversation-normalisers-source-agnosticism.test.js +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.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-compiled-truth-history.test.js +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +6 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js +141 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js.map +1 -0
- 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-empty-trash-reserved-label.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js +86 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js.map +1 -0
- 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-archive-derive-insights.d.ts +33 -34
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +94 -273
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts +43 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js +96 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js.map +1 -0
- 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/kd-classify.d.ts +6 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +73 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +0 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.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-compiled-truth-history.d.ts +6 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts +8 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js +40 -5
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +8 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +25 -9
- 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-ingest.js +11 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts +28 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js +46 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js.map +1 -0
- 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-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +26 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.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/mcp/vitest.config.ts +5 -4
- package/payload/platform/plugins/memory/references/graph-primitives.md +1 -1
- package/payload/platform/plugins/memory/references/schema-base.md +8 -10
- package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +100 -116
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +74 -24
- package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +1 -1
- package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +1 -1
- package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +1 -1
- package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/substack-import/PLUGIN.md +34 -0
- package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +182 -0
- package/payload/platform/plugins/substack-import/skills/substack-import/references/archive-shape.md +68 -0
- package/payload/platform/plugins/substack-import/skills/substack-import/references/attachments.md +72 -0
- package/payload/platform/plugins/substack-import/skills/substack-import/references/engagement.md +61 -0
- package/payload/platform/plugins/substack-import/skills/substack-import/references/posts.md +80 -0
- package/payload/platform/plugins/substack-import/skills/substack-import/references/subscribers.md +74 -0
- 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 +4 -4
- 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/archive-ingest-operator.md +45 -0
- package/payload/platform/templates/specialists/agents/database-operator.md +5 -17
- package/payload/platform/templates/specialists/agents/librarian.md +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
|
@@ -1,43 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# =============================================================================
|
|
3
|
-
# conversation-archive-ingest.sh —
|
|
4
|
-
# conversation-archive
|
|
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
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
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]
|
|
18
|
+
# [--rebuild]
|
|
22
19
|
# [--timezone <iana-zone>]
|
|
23
|
-
# [--date-format <DD/MM/YY|MM/DD/YY|DD/MM/YYYY|MM/DD/YYYY>]
|
|
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:
|
|
30
|
-
#
|
|
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
|
|
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
|
|
299
|
-
//
|
|
300
|
-
// archive
|
|
301
|
-
//
|
|
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-
|
|
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.
|
|
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
|
|
323
|
+
.describe("Chunks per page (1..20). Default 5."),
|
|
324
324
|
}, async ({ archiveElementId, chunkOffset, chunkLimit }) => {
|
|
325
325
|
if (!accountId)
|
|
326
|
-
return refuseNoAccount("conversation-archive-
|
|
326
|
+
return refuseNoAccount("conversation-archive-list-chunks");
|
|
327
327
|
try {
|
|
328
|
-
const result = await
|
|
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}
|
|
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
|
|
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.
|
|
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
|
|
892
|
-
"
|
|
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 (
|
|
895
|
-
"UNMAPPED sections — a generic :Section node hanging off the
|
|
896
|
-
"
|
|
897
|
-
"
|
|
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
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
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}
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ({
|
|
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 (
|
|
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 {
|
|
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`, {
|
|
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
|
|
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.
|
|
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("
|
|
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
|
-
|
|
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.
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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 ({
|
|
2045
|
+
}, async ({ sessionId, pattern }) => {
|
|
1907
2046
|
if (!accountId)
|
|
1908
2047
|
return refuseNoAccount("conversation-memory-expunge");
|
|
1909
2048
|
try {
|
|
1910
|
-
const result = await conversationMemoryExpunge({ accountId,
|
|
2049
|
+
const result = await conversationMemoryExpunge({ accountId, sessionId, pattern });
|
|
1911
2050
|
const lines = [
|
|
1912
|
-
`Expunged "${result.pattern}" from conversation ${result.
|
|
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.
|
|
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.
|
|
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("
|
|
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("
|
|
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
|
-
|
|
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");
|