@rubytech/create-maxy-code 0.1.316 → 0.1.318
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 +2 -2
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +0 -20
- package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-eager/dist/index.js +2 -1
- package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-eager/src/index.ts +3 -1
- package/payload/platform/lib/mcp-lifeline/dist/index.d.ts +8 -0
- package/payload/platform/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/mcp-lifeline/dist/index.js +71 -0
- package/payload/platform/lib/mcp-lifeline/dist/index.js.map +1 -0
- package/payload/platform/lib/mcp-lifeline/package.json +7 -0
- package/payload/platform/lib/mcp-lifeline/src/__tests__/lifeline.test.ts +146 -0
- package/payload/platform/lib/mcp-lifeline/src/index.ts +78 -0
- package/payload/platform/lib/mcp-lifeline/tsconfig.json +9 -0
- package/payload/platform/lib/mcp-lifeline/vitest.config.ts +9 -0
- package/payload/platform/lib/models/dist/index.d.ts +8 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +20 -1
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +22 -0
- package/payload/platform/package.json +5 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +11 -10
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +19 -10
- package/payload/platform/plugins/docs/references/admin-ui.md +4 -2
- package/payload/platform/plugins/docs/references/internals.md +14 -7
- package/payload/platform/plugins/memory/mcp/dist/index.js +32 -31
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +8 -7
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js +12 -11
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/replicate/mcp/dist/index.js +4 -3
- package/payload/platform/plugins/replicate/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +11 -10
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/__tests__/check-no-raw-mcp-registrations.test.sh +57 -0
- package/payload/platform/scripts/check-no-raw-mcp-registrations.mjs +70 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +57 -9
- 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 +5 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +3 -12
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +9 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +5 -0
- 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 +15 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts +8 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts.map +1 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js +71 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js.map +1 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/package.json +7 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +6 -5
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +6 -5
- package/payload/server/{chunk-Q7EWROVN.js → chunk-NCRJQEZ3.js} +0 -101
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminLoginScreens-CrdmA3KA.js +1 -0
- package/payload/server/public/assets/AdminShell-0meAFBva.js +1 -0
- package/payload/server/public/assets/Checkbox-DXisJRUK.js +1 -0
- package/payload/server/public/assets/OperatorConversations-DBy2G8q3.js +9 -0
- package/payload/server/public/assets/OperatorConversations-DvRXfq3q.css +1 -0
- package/payload/server/public/assets/admin-DX5lZxWt.js +1 -0
- package/payload/server/public/assets/{arc-J2g2u5Xv.js → arc-CxLB9WCE.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DN-MYxff.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CN0BXxpE.js → architectureDiagram-Q4EWVU46-D-EdJPSY.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-HX-8wF2p.js → blockDiagram-DXYQGD6D-CXx9RgCm.js} +1 -1
- package/payload/server/public/assets/browser-Bxx8w8BA.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-wIuarKF5.js → c4Diagram-AHTNJAMY-RFBXEe0B.js} +1 -1
- package/payload/server/public/assets/channel-y27xl53N.js +1 -0
- package/payload/server/public/assets/chat-CT9YrNtI.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-Buz7egJZ.js → chunk-2KRD3SAO-DBqAFwK9.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-_JcFXJqc.js → chunk-336JU56O-DdnFEz6R.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-D8Iwaegm.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-DUR5Dg3M.js → chunk-4BX2VUAB-cnw-3Gbs.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BRIqQ9st.js → chunk-4TB4RGXK-BnqJ0bDc.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-CezTHWXL.js → chunk-55IACEB6-BwyHvvzo.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DHYUPzF1.js → chunk-5FUZZQ4R-DXA9U02I.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BVn4_fI5.js → chunk-5PVQY5BW-D78bZ_8D.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-BBLA8Mbi.js → chunk-67CJDMHE-CtE_Mgv7.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-CdWfEI5c.js → chunk-7N4EOEYR-CUZDaySl.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-tS11knCR.js → chunk-AA7GKIK3-CYQ3jO4X.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-GEu1OOZ6.js → chunk-BSJP7CBP-BbA_HyTR.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DKrNbbp_.js → chunk-CIAEETIT-D7_YqRhG.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B0InXNyr.js → chunk-EDXVE4YY-B23LrtSw.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CO7lkHdm.js → chunk-ENJZ2VHE-D3fTHYKN.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-CMj74lWo.js → chunk-FMBD7UC4-DFAA2tyh.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-CLnKQoXw.js → chunk-FOC6F5B3-BF4IHvlI.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-CdiEKIaz.js → chunk-ICPOFSXX-DBUGemHy.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-B6LA3fiv.js → chunk-K5T4RW27-rMMs08Eh.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-DrhRrb8Q.js → chunk-KGLVRYIC-BD2r8R2G.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-DVQukevB.js → chunk-LIHQZDEY-D4sYTTwM.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-ZMLkoDhP.js → chunk-ORNJ4GCN-CAs_uFzb.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C0dJkynG.js → chunk-OYMX7WX6-Fkp-2ORc.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-qHqDpwz3.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BQ9BPIFZ.js → chunk-U2HBQHQK-D_pxZh25.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CAonGMOd.js → chunk-X2U36JSP-CeVmvvRf.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-D5C_WNlk.js → chunk-XPW4576I-iWP54fKp.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Ecdvzekb.js → chunk-YZCP3GAM-CNtbWJNN.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BsFZd1cN.js → chunk-ZZ45TVLE-BmlFjU_9.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DgVoYWhO.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C0WNP3uN.js +1 -0
- package/payload/server/public/assets/clone-D50F_pvg.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-DBWHaIwm.js → cose-bilkent-S5V4N54A-C7YmF1Pg.js} +1 -1
- package/payload/server/public/assets/{dagre-Dr7ZJYeS.js → dagre-BAmiDDtR.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-oIJddk7m.js → dagre-KV5264BT-Ca3ESJhc.js} +1 -1
- package/payload/server/public/assets/data-B9NtsXgF.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-CEVxqOZ4.js → diagram-5BDNPKRD-BgT1ORf2.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BovF7Rjx.js → diagram-G4DWMVQ6-BTaUIiem.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-BhrF8zoF.js → diagram-MMDJMWI5-Bdb2g6Uo.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-DCUYwxtR.js → diagram-TYMM5635-CkLGC0zZ.js} +1 -1
- package/payload/server/public/assets/{dist-DSsFp0Qd.js → dist-Bkbhs3jw.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BS2-HdCg.js → erDiagram-SMLLAGMA-D_sj4DMg.js} +1 -1
- package/payload/server/public/assets/{flatten-BZMXCpLh.js → flatten-E2Sr0FeD.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BzSFLoea.js → flowDiagram-DWJPFMVM-iLERoZTe.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-1-3QU7mT.js → ganttDiagram-T4ZO3ILL-D60hjMBy.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-D-L2yzYf.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-fTrJ35Wk.js → gitGraphDiagram-UUTBAWPF-Di0XM6fi.js} +1 -1
- package/payload/server/public/assets/{graph-BZNc3EXa.js → graph-B59N222f.js} +3 -3
- package/payload/server/public/assets/graph-labels-70w-1ov0.js +1 -0
- package/payload/server/public/assets/{graphlib-rlEzI2qD.js → graphlib-C8fUP7uV.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BQn6jndO.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-BwMdbiXg.js +2 -0
- package/payload/server/public/assets/{isEmpty-DaYIrHay.js → isEmpty-CLz-UprQ.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-0eU_UtlT.js → ishikawaDiagram-UXIWVN3A-CwgI4B5Z.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BKLeZohp.js → journeyDiagram-VCZTEJTY-CxBu-tze.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dq72xyaN.js → kanban-definition-6JOO6SKY-D2qlheA5.js} +1 -1
- package/payload/server/public/assets/{line-LQhmDT8k.js → line-Bdod7uzQ.js} +1 -1
- package/payload/server/public/assets/{linear-BGotDbGs.js → linear-BiVe6QzC.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-DoLdho1V.js → mermaid-parser.core-xZN7hC6M.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-C1RRyHGm.js → mermaid.core-D0IylAac.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-vUVVVyV1.js → mindmap-definition-QFDTVHPH-J_Szhwf1.js} +1 -1
- package/payload/server/public/assets/operator-DpRAhwQN.js +1 -0
- package/payload/server/public/assets/{ordinal-BqEhkPyh.js → ordinal-5RtyPJVt.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-DmkQBx4h.js +1 -0
- package/payload/server/public/assets/page-Ehjc9b9V.js +30 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-DDnxYUBm.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-B9Pl6Qhc.js → pieDiagram-DEJITSTG-CV5DxUVx.js} +1 -1
- package/payload/server/public/assets/public-BcqXGSaE.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Drn9T81A.js → quadrantDiagram-34T5L4WZ-BsFMVizF.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-7H4k0ChM.js +1 -0
- package/payload/server/public/assets/{reduce-T2IuntYP.js → reduce-B3Mw_0s1.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-C0PAItJm.js → requirementDiagram-MS252O5E-C5eRRvGc.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BR42Mtwd.js → sankeyDiagram-XADWPNL6-CJYv5gpw.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-c2lR9UOS.js → sequenceDiagram-FGHM5R23-B25563_2.js} +1 -1
- package/payload/server/public/assets/{src-DXUM2BJo.js → src-BKOAoFQc.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BcHhtqsZ.js → stateDiagram-FHFEXIEX-BLyNJYOA.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BSVuxZxz.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Ax32c10H.js → timeline-definition-GMOUNBTQ-D-HgOM6Q.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BLXWTQtW.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-DiePDF5d.js +1 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BxePewPq.js → vennDiagram-DHZGUBPP-Cw1JElYp.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-OSUWK5LN.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DmJwZ2f5.js → wardleyDiagram-NUSXRM2D-BqMWzEko.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-YjHomudv.js → xychartDiagram-5P7HB3ND-DBp71TLT.js} +1 -1
- package/payload/server/public/browser.html +5 -8
- package/payload/server/public/chat.html +8 -12
- package/payload/server/public/data.html +5 -7
- package/payload/server/public/graph.html +7 -10
- package/payload/server/public/index.html +8 -11
- package/payload/server/public/operator.html +10 -14
- package/payload/server/public/public.html +8 -10
- package/payload/server/server.js +276 -219
- package/payload/server/public/assets/AccessGate-bu988Xo-.js +0 -1
- package/payload/server/public/assets/AdminLoginScreens-BCYaOOuk.js +0 -1
- package/payload/server/public/assets/AdminShell-DSjJ4Biu.js +0 -1
- package/payload/server/public/assets/Checkbox-B4Dbvjls.js +0 -1
- package/payload/server/public/assets/OperatorConversations-XsXP7-P-.js +0 -1
- package/payload/server/public/assets/OperatorConversations-qc_xy7Az.css +0 -1
- package/payload/server/public/assets/admin-m0797WGA.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-C6nkAxzW.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-Jm4KJ4YC.js +0 -30
- package/payload/server/public/assets/brand-D8LClgr_.js +0 -9
- package/payload/server/public/assets/brand-DvttVeGB.css +0 -1
- package/payload/server/public/assets/browser-CBjNMPsz.js +0 -1
- package/payload/server/public/assets/channel-Q39xIXyT.js +0 -1
- package/payload/server/public/assets/chat-Sg-RGuV6.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CCYjp9C2.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BNBxnHZh.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BShusfby.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D4ivPLFF.js +0 -1
- package/payload/server/public/assets/clone-CjEM8LwB.js +0 -1
- package/payload/server/public/assets/data-CEqE4BDw.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-Btp3PwZh.js +0 -1
- package/payload/server/public/assets/graph-labels-Bj5yM9bI.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-CPt2y6_L.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CpXNTMgd.js +0 -2
- package/payload/server/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/payload/server/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/payload/server/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/payload/server/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/payload/server/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/payload/server/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/payload/server/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/payload/server/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-300-normal-AOSWdb_s.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-300-normal-FGBQ0wlI.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-400-normal-BFBkh4jY.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-400-normal-gRTjlS2D.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-500-normal-B66TYsaK.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-500-normal-DFwuUcdu.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-300-normal-CFtw49Zd.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-300-normal-DRMzurxT.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-400-normal-DYA1XoQK.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-400-normal-svq1FPys.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-500-normal-BNHmvKvI.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-500-normal-CZruMFou.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-300-normal-CsrIkm-V.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-300-normal-D3VHEe81.woff2 +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-400-normal-BekUZro8.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-400-normal-DdKr49mV.woff2 +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-500-normal-BEAbKU8A.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-500-normal-CL6a8tp2.woff2 +0 -0
- package/payload/server/public/assets/operator-Bph7mx87.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Cwc-j_AI.js +0 -1
- package/payload/server/public/assets/page-CtWCeXdg.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BZ9fjD1_.js +0 -1
- package/payload/server/public/assets/public-gxHCJCs3.js +0 -6
- package/payload/server/public/assets/public-next-C3clISGQ.js +0 -1
- package/payload/server/public/assets/public-vnj7OhQj.css +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BNz5Rt9V.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BUQ_F4eP.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-DcVCQgp1.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Bm12mwGd.js +0 -1
- package/payload/server/public/assets/useSelectionMode-BMn70cch.js +0 -5
- package/payload/server/public/assets/wardley-RL74JXVD-47Z3ymtK.js +0 -1
- package/payload/server/public/public-next.html +0 -25
- /package/payload/server/public/assets/{_baseFor-Y5mTRiRv.js → _baseFor-DVaNaTfF.js} +0 -0
- /package/payload/server/public/assets/{admin-types-D2qTXuCg.js → admin-types-CJrGd46U.js} +0 -0
- /package/payload/server/public/assets/{array-BwJyW1Dp.js → array-8_H1156C.js} +0 -0
- /package/payload/server/public/assets/{chunk-CAM3fms7.js → chunk-Pqm5yXtL.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-D95TtHqz.js → cytoscape.esm-h10p_6j-.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-kiwRz9Au.js → defaultLocale-pD7tFa1r.js} +0 -0
- /package/payload/server/public/assets/{init-CKZirZ49.js → init-CwJ4b81e.js} +0 -0
- /package/payload/server/public/assets/{katex-8mXVa4k3.js → katex-DJPjIBAI.js} +0 -0
- /package/payload/server/public/assets/{path-B0d9ncVi.js → path-CK8wrAxY.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-C5gCWwwF.js → preload-helper-Bf_JiD2A.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-BWqoIFNR.js → rough.esm-Dwml_la6.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:cf1810647052f471dbe16bc2ab5b2704ff25b43d06fc4246471c3b963302965c
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -2320,10 +2320,12 @@ either is a regression.
|
|
|
2320
2320
|
|
|
2321
2321
|
**`/chat` empty-state greeting panel.** While the admin webchat has no conversation JSONL yet (`GET /api/webchat/session` → `projectDir:null`), `app/chat/page.tsx` renders a "What's up next, {givenName}?" greeting (given name = first whitespace token of the admin session's `userName`) above two read-only lists from `GET /api/webchat/greeting` (`server/routes/webchat-greeting.ts`, `requireAdminSession`-gated, `accountId`-scoped): the next 5 upcoming `:Event` rows (`eventStatus IN ['scheduled','due']`, future `COALESCE(nextRun, startDate)`, soonest first) and the outstanding `:Task` rows (`status IN ['pending','active','running']`, 5 shown + `+N more`). Read failure returns HTTP 200 `{ ok: false }` and the page shows the headline alone — the panel never blocks the composer. A third section, **Your specialists**, shows the account's installed roster — every `*.md` under `data/accounts/<accountId>/specialists/agents/`, core and `--`-prefixed premium files alike — shown by frontmatter `name` + `summary` (fallback `description`), empty dir → "No specialists installed". The roster read (`app/lib/claude-agent/specialist-roster.ts`) is isolated from the graph fallback: malformed files are skipped (`op=specialist-skipped file=<name> reason=<…>`), a whole-roster failure degrades to `specialists: []` inside the `ok: true` payload (`op=specialists-read-failed`). Logs: `[webchat:greeting] op=read account=<id8> events=<n> tasks=<n> specialists=<n> ms=<n>` / `op=read-failed reason=…`; client warns `[admin-ui] greeting-unavailable …`. The full webchat architecture lives in `.docs/admin-webchat-native-channel.md`.
|
|
2322
2322
|
|
|
2323
|
-
**`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx
|
|
2323
|
+
**`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx`, `app/chat/__tests__/transcript-render.test.tsx`). **Day-divider:** both renderers insert a centered `.day-divider` row between two consecutive timeline items on different local calendar days (label `Today`/`Yesterday`, else `Sat 14 Jun 2026`), so a thread spanning midnight is never an ambiguous run of HH:MM; the first dated item gets a leading divider, a null/unparseable `ts` marks no boundary, dividers are computed over the filtered `visibleItems`, and in `/chat` a day crossover flushes any open tool/think run first so a collapsed run never spans it. Per-bubble HH:MM stamps are unchanged. Shared helpers `dayKey`/`dayLabel`/`itemTs`/`DayDivider` live in `app/whatsapp/Transcript.tsx`.
|
|
2324
2324
|
|
|
2325
2325
|
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
|
|
2326
2326
|
|
|
2327
|
+
**Public visitor surface.** The public-host root (`GET /`), the `/:slug` agent routes, and the admin-host `/public` / `/public-chat` previews all serve one shell, `public.html` → [`app/public-entry.tsx`](../../../ui/app/public-entry.tsx) → `PublicChat`. `PublicChat` reuses `useSession` purely as the magic-link gatekeeper — it drives `AccessGate`, resolves the agent slug from the path, and handles `?token=` verification; once the grant is satisfied it mounts `ChatSurface variant="public"`, whose transcript reads the visitor-scoped, **delivered-only** stream `GET /api/public-reader/stream` ([`server/routes/public-reader.ts`](../../../ui/server/routes/public-reader.ts)) — the visitor sees the agent's delivered prose, never the tool/tool-result/directive bytes the legacy `/api/chat` SSE render exposed. Branding is resolved client-side by `useSession`, so the server hands back the bare shell with no per-agent HTML injection. There is exactly one public client surface and it is 1:1 visitor↔agent: the earlier `?surface=next` A/B handle is retired, group messaging is retired (not a supported product surface), and a former `/g/<slug>` group URL now serves the same 1:1 shell — a stale bookmark gets the 1:1 chat, never a broken render.
|
|
2328
|
+
|
|
2327
2329
|
### Graph
|
|
2328
2330
|
|
|
2329
2331
|
| Mount | Purpose |
|
|
@@ -2569,7 +2571,7 @@ authoritative. This section names the surfaces and what backs each.
|
|
|
2569
2571
|
| Nav rows (Chat / People / Agents / Projects / Tasks / Artefacts) | People, Agents, Tasks open the artefact-pane Graph filtered to the matching label. Chat selects the active conversation. Artefacts swaps the list to editable documents. | `graph-search.ts`, `graph-subgraph.ts`, `sidebar-artefacts.ts` |
|
|
2570
2572
|
| Sessions list (Active / Archived / All) | Live row store driven by SSE; manual reconcile button on the segmented control re-fetches the full id set. Every listed row carries two launch actions: the claude.ai/code resume (`ExternalLink`) and a chat-launch (`MessageSquare`) that opens `/chat?session=<full sessionId>` — the admin webchat pointed at that exact session; sending there resumes a stopped session with the webchat channel bound to that id (see `admin-webchat-native-channel.md`, "Session-targeted mode"). At the ≤720 px drawer breakpoint each row stacks into two lines — dot + title + id/stamp, then the action icons — with a divider between rows and actions at full opacity (the desktop hover-gated 0.5 opacity never resolves on touch). Below a 400 px list width each row's action icons collapse to a single `MoreHorizontal` ellipsis trigger; its popover menu lists the same actions as the inline icons but labels them with concise verbs (`Resume in claude.ai/code`, `Open in webchat`, `Stop`, `Archive` / `Unarchive`, `Rename`, `Delete`, `Re-seat`) rather than the inline icon buttons' verbose per-session aria-labels — the inline buttons keep those verbose labels because an icon-only control needs the full descriptive accessible name. **Re-seat:** Re-seat is a member action of the one `SessionRowActions` cluster, not a separate sibling control — wide it is the sliders icon inline with the other icons (sharing the cluster geometry and alignment); collapsed it is the `Re-seat` menu item, which expands the model/mode/effort form inline inside the overflow menu. The form (`SessionReseatControl`) forks the session via `/api/admin/session-reseat` and navigates to the fork (the same fork mechanism `/chat`'s pickers drive); its model picker defaults to the row's current model (a `model` field on each row, read from the JSONL tail), and mode and effort each carry a "Keep" option that omits the field. The overflow menu and the Re-seat form render through a `document.body` portal, fixed-positioned from the trigger's rect (right-aligned, flipped above the trigger when there is no room below), so neither is clipped by `.side-list`'s `overflow-y:auto`; Escape, a pointerdown outside the trigger/popover, and any scroll or resize dismiss them. | `/claude-sessions/events`, `/claude-sessions`, `/session-reseat` |
|
|
2571
2573
|
| Channel reader nav rows (WhatsApp / Telegram) | One conditional nav row **per interactive channel that has ≥1 admin session**. Each row carries its brand glyph (WhatsApp `#25D366`, Telegram `#229ED9`); a channel with no admin session shows no row, and no install ever shows an always-empty "No conversations" row. The channel list loads **once on sidebar mount** (the per-channel counts must be known before the nav renders), so a failed load shows one muted, non-clickable line instead of channel rows. Clicking a channel row lists that channel's admin conversations; each conversation row shows a **display name** resolved by precedence `operatorName ?? whatsappName ?? senderId ?? title`: the bound `Person givenName familyName` when a `senderId`→`userId` binding exists, else the persisted WhatsApp display name (`pushName`, read from the latest `:Message:WhatsAppMessage.senderName`), else the raw `senderId`, else the agent title; the agent session title is the hover tooltip only. Under the name each row shows a **last-message-time breadcrumb** (`conv-timestamp`, same markup as the Sessions rows) formatted from the row's `lastMessageAt` (the last parseable turn's `ts`); a session with no parseable turn shows no time, never "Invalid Date". **Re-seat:** each channel conversation row carries a `SessionRowActions` cluster whose sole action is Re-seat (the row is a `conv-with-actions` shell whose open click moved onto an inner button so the cluster can sit beside it), so a WhatsApp/Telegram session's model/mode/effort is re-seatable from the dashboard exactly like a webchat row — wide it is the inline sliders icon, and below the 400 px width it folds into the `…` overflow menu identically to the Sessions rows; the channel reader row carries the same `model` field for the picker default. A click on a conversation **opens its transcript on the home surface**: on `/` it selects in place, and from any other route (`/graph`, `/data`, `/browser`) it navigates to `/?wa=<sessionId>&projectDir=<dir>`, which the root shell hydrates on mount (then strips the query so a later refresh does not re-pin a closed conversation). Server logs `[wa-reader] op=operator-name-fallback senderId=… source=whatsapp-pushname` when the pushName fallback fires and `[wa-reader] op=conversations count=<n> withTimestamp=<m>` per list build; the client logs `[admin-ui] wa-open route=… via=<in-place\|navigate> …` and `[admin-ui] wa-hydrate route=/ …`. | `/whatsapp-reader/conversations` |
|
|
2572
|
-
| Channel transcript (`<Transcript>`) | Reads one session's JSONL over SSE (`/whatsapp-reader/stream`) and renders both sides plus tool calls — the turns claude.ai/code hides because channel inbound is stamped `isMeta`. Every turn shows its time-of-day (HH:MM from the turn's `ts`; a null/unparseable `ts` shows no time, never "Invalid Date"). `tool-call`/`tool-result` turns render as **collapsed cards** (chevron + label + time, default collapsed, expandable per card; one card's state never affects another) so the human↔agent text is not buried in JSON; the three conversation kinds always render in full. The thread **follows the tail**: it opens at the newest turn and pins to the bottom on each live append **only while the operator is already within 32 px of the bottom** — a scroll up suppresses the jump so reading history is never yanked. While the operator is scrolled up a **jump-to-bottom control** (`.wa-jump`, bottom-right of the viewport) appears; clicking it scrolls to the newest turn and re-arms follow-tail, and it hides again at the bottom. The thread scrolls inside its grid cell (header/sidebar/footer fixed). The stream sends a 20 s heartbeat so an idle Cloudflare tunnel does not idle-drop, tags each frame with a byte-offset `id:`, and resumes from the client's `Last-Event-ID` on reconnect (no duplicate backlog); the client clears the "Stream disconnected" banner on reopen and latches it only on a terminal CLOSED state. The thread also interleaves a collapsed `⚙ directive injected (N B)` row per turn, sorted by timestamp just before the turn it informed; expanding one fetches the exact stored `prompt-optimiser-directive` bytes for that turn. The entries are listed by `GET /whatsapp-reader/directives?sessionId=` and the bytes served by `GET /whatsapp-reader/directive?sessionId=&name=`, both admin-gated and account-scoped; a missing store degrades to no rows. | `/whatsapp-reader/stream`, `/whatsapp-reader/directives`, `/whatsapp-reader/directive` |
|
|
2574
|
+
| Channel transcript (`<Transcript>`) | Reads one session's JSONL over SSE (`/whatsapp-reader/stream`) and renders both sides plus tool calls — the turns claude.ai/code hides because channel inbound is stamped `isMeta`. Every turn shows its time-of-day (HH:MM from the turn's `ts`; a null/unparseable `ts` shows no time, never "Invalid Date"). `tool-call`/`tool-result` turns render as **collapsed cards** (chevron + label + time, default collapsed, expandable per card; one card's state never affects another) so the human↔agent text is not buried in JSON; the three conversation kinds always render in full. The thread **follows the tail**: it opens at the newest turn and pins to the bottom on each live append **only while the operator is already within 32 px of the bottom** — a scroll up suppresses the jump so reading history is never yanked. While the operator is scrolled up a **jump-to-bottom control** (`.wa-jump`, bottom-right of the viewport) appears; clicking it scrolls to the newest turn and re-arms follow-tail, and it hides again at the bottom. The thread scrolls inside its grid cell (header/sidebar/footer fixed). The stream sends a 20 s heartbeat so an idle Cloudflare tunnel does not idle-drop, tags each frame with a byte-offset `id:`, and resumes from the client's `Last-Event-ID` on reconnect (no duplicate backlog); the client clears the "Stream disconnected" banner on reopen and latches it only on a terminal CLOSED state. The thread also interleaves a collapsed `⚙ directive injected (N B)` row per turn, sorted by timestamp just before the turn it informed; expanding one fetches the exact stored `prompt-optimiser-directive` bytes for that turn. The entries are listed by `GET /whatsapp-reader/directives?sessionId=` and the bytes served by `GET /whatsapp-reader/directive?sessionId=&name=`, both admin-gated and account-scoped; a missing store degrades to no rows. A centered day-divider row (`.day-divider`) marks each local calendar-day crossover between consecutive turns so a thread spanning midnight is unambiguous. | `/whatsapp-reader/stream`, `/whatsapp-reader/directives`, `/whatsapp-reader/directive` |
|
|
2573
2575
|
| Conversations row hover actions | Inline rename, archive, delete, JSONL view / download per row. The historical `.conversations-modal` CSS block exists in `globals.css` but is no longer mounted from any TSX — Sidebar.tsx now owns every per-row affordance directly. | `claude-sessions.ts` |
|
|
2574
2576
|
| Artefacts list | Lists every `:FileArtifact` under this account's tree (`relativePath STARTS WITH 'accounts/'`, all file types, excluding the `uploads/<id>/` subtree) plus this account's IDENTITY / SOUL / KNOWLEDGE / specialist templates. Click downloads the row's backing file (`downloadPath` → `GET /api/admin/files/download`) so the operator opens it in their local app; rows whose file is outside `DATA_ROOT` (bundled-fallback templates) show a "can't be downloaded" pill. The in-app artefact pane is dead pending removal. | `sidebar-artefacts.ts`, `files.ts` |
|
|
2575
2577
|
| System-stats widget | CPU / RAM widget at the foot of the sidebar. | `system-stats.ts` (see above) |
|
|
@@ -3241,15 +3243,22 @@ The admin agent runs via Claude Code CLI, which manages its own system prompt as
|
|
|
3241
3243
|
|
|
3242
3244
|
This is assembled as a `<previous-context>` block in the system prompt on each admin turn.
|
|
3243
3245
|
|
|
3244
|
-
### Public-agent memory context
|
|
3246
|
+
### Public-agent memory context
|
|
3245
3247
|
|
|
3246
3248
|
Public agents historically had their memory context injected by a server-side bridge
|
|
3247
3249
|
(`fetchMemoryContext`) that spawned the memory MCP server with `ALLOWED_SCOPES=public,shared`
|
|
3248
|
-
and ran a `memory-search` on the agent's behalf. That bridge
|
|
3249
|
-
are
|
|
3250
|
-
server-side proxy runs a public-scope memory
|
|
3251
|
-
path ranked against was retired alongside it.
|
|
3252
|
-
|
|
3250
|
+
and ran a `memory-search` on the agent's behalf. That bridge was removed: public agents
|
|
3251
|
+
are toolless (`buildPublicDeny` denies `mcp__memory__*`), so neither the agent nor a
|
|
3252
|
+
server-side proxy runs a public-scope memory search, and the public-scope fulltext index that
|
|
3253
|
+
path ranked against was retired alongside it.
|
|
3254
|
+
|
|
3255
|
+
A gated visitor's per-visitor memory still reaches their next conversation, without any tool
|
|
3256
|
+
and without reopening the ringfence. The session-end reviewer writes per-visitor slice nodes
|
|
3257
|
+
(`{sliceToken, scope:'user'}`); at the next gated spawn the UI process fetches that visitor's
|
|
3258
|
+
own `scope:'user'` slice nodes (a slice-pinned read, not a public-scope search), renders them
|
|
3259
|
+
to a `<previous-context>` block, and threads it through the public spawn body so the manager
|
|
3260
|
+
appends it to the agent's system prompt. Only the visitor's own slice is read; open-mode
|
|
3261
|
+
visitors, admins, and first visits inject nothing.
|
|
3253
3262
|
|
|
3254
3263
|
---
|
|
3255
3264
|
|
|
@@ -3317,7 +3326,7 @@ The Claude Code SDK marks every MCP tool as **deferred** by default. The model c
|
|
|
3317
3326
|
|
|
3318
3327
|
The SDK's per-tool override is `_meta["anthropic/alwaysLoad"]: true` on each MCP tool's `tools/list` entry. Two surfaces apply it:
|
|
3319
3328
|
|
|
3320
|
-
1. **In-process plugins.** Every admin-eager tool is registered via `eagerTool(server, name, description, inputSchema, handler)` from `platform/lib/mcp-eager/` instead of `server.tool(...)`. The helper calls `server.registerTool` with the `_meta` flag set.
|
|
3329
|
+
1. **In-process plugins.** Every admin-eager tool is registered via `eagerTool(server, name, description, inputSchema, handler)` from `platform/lib/mcp-eager/` instead of `server.tool(...)`. The helper calls `server.registerTool` with the `_meta` flag set. Both `eagerTool` and the non-eager `lifelineTool` (from `platform/lib/mcp-lifeline/`) wrap the handler with `wrapWithLifeline`, which emits a structured `op=request`/`op=result` log pair per call including a holdings census — see `.docs/mcp-helper-observability.md` "Tool-call lifeline".
|
|
3321
3330
|
2. **Upstream graph proxy.** The upstream Python `mcp-neo4j-cypher` server has no `_meta` channel, so `platform/lib/graph-mcp/src/index.ts` intercepts every `tools/list` response on the wire and injects `_meta["anthropic/alwaysLoad"]: true` into each tool entry. The `[graph-mcp] tools/list eager-flagged count=<N>` stderr line confirms the injection fired.
|
|
3322
3331
|
|
|
3323
3332
|
**Curation rule.** Every MCP tool the admin agent calls routinely should be eager — registered via `eagerTool` (or arriving through the graph-mcp interceptor). Whether a tool is eager is decided at its registration site in the plugin's MCP `index.ts` (`eagerTool` vs `server.tool`); there is no separate allow-list constant. Admin-skill / specialist / public-agent tools that stay on `server.tool()` pay the ToolSearch tax only when their caller invokes them. The admin tool surface (`toolSurface.admin`, the `adminAllowlist: true` set) is the intended eager set; a routinely-called admin tool left on `server.tool()` is a gap to fix at the registration site.
|
|
@@ -55,10 +55,12 @@ either is a regression.
|
|
|
55
55
|
|
|
56
56
|
**`/chat` empty-state greeting panel.** While the admin webchat has no conversation JSONL yet (`GET /api/webchat/session` → `projectDir:null`), `app/chat/page.tsx` renders a "What's up next, {givenName}?" greeting (given name = first whitespace token of the admin session's `userName`) above two read-only lists from `GET /api/webchat/greeting` (`server/routes/webchat-greeting.ts`, `requireAdminSession`-gated, `accountId`-scoped): the next 5 upcoming `:Event` rows (`eventStatus IN ['scheduled','due']`, future `COALESCE(nextRun, startDate)`, soonest first) and the outstanding `:Task` rows (`status IN ['pending','active','running']`, 5 shown + `+N more`). Read failure returns HTTP 200 `{ ok: false }` and the page shows the headline alone — the panel never blocks the composer. A third section, **Your specialists**, shows the account's installed roster — every `*.md` under `data/accounts/<accountId>/specialists/agents/`, core and `--`-prefixed premium files alike — shown by frontmatter `name` + `summary` (fallback `description`), empty dir → "No specialists installed". The roster read (`app/lib/claude-agent/specialist-roster.ts`) is isolated from the graph fallback: malformed files are skipped (`op=specialist-skipped file=<name> reason=<…>`), a whole-roster failure degrades to `specialists: []` inside the `ok: true` payload (`op=specialists-read-failed`). Logs: `[webchat:greeting] op=read account=<id8> events=<n> tasks=<n> specialists=<n> ms=<n>` / `op=read-failed reason=…`; client warns `[admin-ui] greeting-unavailable …`. The full webchat architecture lives in `.docs/admin-webchat-native-channel.md`.
|
|
57
57
|
|
|
58
|
-
**`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx
|
|
58
|
+
**`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx`, `app/chat/__tests__/transcript-render.test.tsx`). **Day-divider:** both renderers insert a centered `.day-divider` row between two consecutive timeline items on different local calendar days (label `Today`/`Yesterday`, else `Sat 14 Jun 2026`), so a thread spanning midnight is never an ambiguous run of HH:MM; the first dated item gets a leading divider, a null/unparseable `ts` marks no boundary, dividers are computed over the filtered `visibleItems`, and in `/chat` a day crossover flushes any open tool/think run first so a collapsed run never spans it. Per-bubble HH:MM stamps are unchanged. Shared helpers `dayKey`/`dayLabel`/`itemTs`/`DayDivider` live in `app/whatsapp/Transcript.tsx`.
|
|
59
59
|
|
|
60
60
|
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
|
|
61
61
|
|
|
62
|
+
**Public visitor surface.** The public-host root (`GET /`), the `/:slug` agent routes, and the admin-host `/public` / `/public-chat` previews all serve one shell, `public.html` → [`app/public-entry.tsx`](../../../ui/app/public-entry.tsx) → `PublicChat`. `PublicChat` reuses `useSession` purely as the magic-link gatekeeper — it drives `AccessGate`, resolves the agent slug from the path, and handles `?token=` verification; once the grant is satisfied it mounts `ChatSurface variant="public"`, whose transcript reads the visitor-scoped, **delivered-only** stream `GET /api/public-reader/stream` ([`server/routes/public-reader.ts`](../../../ui/server/routes/public-reader.ts)) — the visitor sees the agent's delivered prose, never the tool/tool-result/directive bytes the legacy `/api/chat` SSE render exposed. Branding is resolved client-side by `useSession`, so the server hands back the bare shell with no per-agent HTML injection. There is exactly one public client surface and it is 1:1 visitor↔agent: the earlier `?surface=next` A/B handle is retired, group messaging is retired (not a supported product surface), and a former `/g/<slug>` group URL now serves the same 1:1 shell — a stale bookmark gets the 1:1 chat, never a broken render.
|
|
63
|
+
|
|
62
64
|
### Graph
|
|
63
65
|
|
|
64
66
|
| Mount | Purpose |
|
|
@@ -304,7 +306,7 @@ authoritative. This section names the surfaces and what backs each.
|
|
|
304
306
|
| Nav rows (Chat / People / Agents / Projects / Tasks / Artefacts) | People, Agents, Tasks open the artefact-pane Graph filtered to the matching label. Chat selects the active conversation. Artefacts swaps the list to editable documents. | `graph-search.ts`, `graph-subgraph.ts`, `sidebar-artefacts.ts` |
|
|
305
307
|
| Sessions list (Active / Archived / All) | Live row store driven by SSE; manual reconcile button on the segmented control re-fetches the full id set. Every listed row carries two launch actions: the claude.ai/code resume (`ExternalLink`) and a chat-launch (`MessageSquare`) that opens `/chat?session=<full sessionId>` — the admin webchat pointed at that exact session; sending there resumes a stopped session with the webchat channel bound to that id (see `admin-webchat-native-channel.md`, "Session-targeted mode"). At the ≤720 px drawer breakpoint each row stacks into two lines — dot + title + id/stamp, then the action icons — with a divider between rows and actions at full opacity (the desktop hover-gated 0.5 opacity never resolves on touch). Below a 400 px list width each row's action icons collapse to a single `MoreHorizontal` ellipsis trigger; its popover menu lists the same actions as the inline icons but labels them with concise verbs (`Resume in claude.ai/code`, `Open in webchat`, `Stop`, `Archive` / `Unarchive`, `Rename`, `Delete`, `Re-seat`) rather than the inline icon buttons' verbose per-session aria-labels — the inline buttons keep those verbose labels because an icon-only control needs the full descriptive accessible name. **Re-seat:** Re-seat is a member action of the one `SessionRowActions` cluster, not a separate sibling control — wide it is the sliders icon inline with the other icons (sharing the cluster geometry and alignment); collapsed it is the `Re-seat` menu item, which expands the model/mode/effort form inline inside the overflow menu. The form (`SessionReseatControl`) forks the session via `/api/admin/session-reseat` and navigates to the fork (the same fork mechanism `/chat`'s pickers drive); its model picker defaults to the row's current model (a `model` field on each row, read from the JSONL tail), and mode and effort each carry a "Keep" option that omits the field. The overflow menu and the Re-seat form render through a `document.body` portal, fixed-positioned from the trigger's rect (right-aligned, flipped above the trigger when there is no room below), so neither is clipped by `.side-list`'s `overflow-y:auto`; Escape, a pointerdown outside the trigger/popover, and any scroll or resize dismiss them. | `/claude-sessions/events`, `/claude-sessions`, `/session-reseat` |
|
|
306
308
|
| Channel reader nav rows (WhatsApp / Telegram) | One conditional nav row **per interactive channel that has ≥1 admin session**. Each row carries its brand glyph (WhatsApp `#25D366`, Telegram `#229ED9`); a channel with no admin session shows no row, and no install ever shows an always-empty "No conversations" row. The channel list loads **once on sidebar mount** (the per-channel counts must be known before the nav renders), so a failed load shows one muted, non-clickable line instead of channel rows. Clicking a channel row lists that channel's admin conversations; each conversation row shows a **display name** resolved by precedence `operatorName ?? whatsappName ?? senderId ?? title`: the bound `Person givenName familyName` when a `senderId`→`userId` binding exists, else the persisted WhatsApp display name (`pushName`, read from the latest `:Message:WhatsAppMessage.senderName`), else the raw `senderId`, else the agent title; the agent session title is the hover tooltip only. Under the name each row shows a **last-message-time breadcrumb** (`conv-timestamp`, same markup as the Sessions rows) formatted from the row's `lastMessageAt` (the last parseable turn's `ts`); a session with no parseable turn shows no time, never "Invalid Date". **Re-seat:** each channel conversation row carries a `SessionRowActions` cluster whose sole action is Re-seat (the row is a `conv-with-actions` shell whose open click moved onto an inner button so the cluster can sit beside it), so a WhatsApp/Telegram session's model/mode/effort is re-seatable from the dashboard exactly like a webchat row — wide it is the inline sliders icon, and below the 400 px width it folds into the `…` overflow menu identically to the Sessions rows; the channel reader row carries the same `model` field for the picker default. A click on a conversation **opens its transcript on the home surface**: on `/` it selects in place, and from any other route (`/graph`, `/data`, `/browser`) it navigates to `/?wa=<sessionId>&projectDir=<dir>`, which the root shell hydrates on mount (then strips the query so a later refresh does not re-pin a closed conversation). Server logs `[wa-reader] op=operator-name-fallback senderId=… source=whatsapp-pushname` when the pushName fallback fires and `[wa-reader] op=conversations count=<n> withTimestamp=<m>` per list build; the client logs `[admin-ui] wa-open route=… via=<in-place\|navigate> …` and `[admin-ui] wa-hydrate route=/ …`. | `/whatsapp-reader/conversations` |
|
|
307
|
-
| Channel transcript (`<Transcript>`) | Reads one session's JSONL over SSE (`/whatsapp-reader/stream`) and renders both sides plus tool calls — the turns claude.ai/code hides because channel inbound is stamped `isMeta`. Every turn shows its time-of-day (HH:MM from the turn's `ts`; a null/unparseable `ts` shows no time, never "Invalid Date"). `tool-call`/`tool-result` turns render as **collapsed cards** (chevron + label + time, default collapsed, expandable per card; one card's state never affects another) so the human↔agent text is not buried in JSON; the three conversation kinds always render in full. The thread **follows the tail**: it opens at the newest turn and pins to the bottom on each live append **only while the operator is already within 32 px of the bottom** — a scroll up suppresses the jump so reading history is never yanked. While the operator is scrolled up a **jump-to-bottom control** (`.wa-jump`, bottom-right of the viewport) appears; clicking it scrolls to the newest turn and re-arms follow-tail, and it hides again at the bottom. The thread scrolls inside its grid cell (header/sidebar/footer fixed). The stream sends a 20 s heartbeat so an idle Cloudflare tunnel does not idle-drop, tags each frame with a byte-offset `id:`, and resumes from the client's `Last-Event-ID` on reconnect (no duplicate backlog); the client clears the "Stream disconnected" banner on reopen and latches it only on a terminal CLOSED state. The thread also interleaves a collapsed `⚙ directive injected (N B)` row per turn, sorted by timestamp just before the turn it informed; expanding one fetches the exact stored `prompt-optimiser-directive` bytes for that turn. The entries are listed by `GET /whatsapp-reader/directives?sessionId=` and the bytes served by `GET /whatsapp-reader/directive?sessionId=&name=`, both admin-gated and account-scoped; a missing store degrades to no rows. | `/whatsapp-reader/stream`, `/whatsapp-reader/directives`, `/whatsapp-reader/directive` |
|
|
309
|
+
| Channel transcript (`<Transcript>`) | Reads one session's JSONL over SSE (`/whatsapp-reader/stream`) and renders both sides plus tool calls — the turns claude.ai/code hides because channel inbound is stamped `isMeta`. Every turn shows its time-of-day (HH:MM from the turn's `ts`; a null/unparseable `ts` shows no time, never "Invalid Date"). `tool-call`/`tool-result` turns render as **collapsed cards** (chevron + label + time, default collapsed, expandable per card; one card's state never affects another) so the human↔agent text is not buried in JSON; the three conversation kinds always render in full. The thread **follows the tail**: it opens at the newest turn and pins to the bottom on each live append **only while the operator is already within 32 px of the bottom** — a scroll up suppresses the jump so reading history is never yanked. While the operator is scrolled up a **jump-to-bottom control** (`.wa-jump`, bottom-right of the viewport) appears; clicking it scrolls to the newest turn and re-arms follow-tail, and it hides again at the bottom. The thread scrolls inside its grid cell (header/sidebar/footer fixed). The stream sends a 20 s heartbeat so an idle Cloudflare tunnel does not idle-drop, tags each frame with a byte-offset `id:`, and resumes from the client's `Last-Event-ID` on reconnect (no duplicate backlog); the client clears the "Stream disconnected" banner on reopen and latches it only on a terminal CLOSED state. The thread also interleaves a collapsed `⚙ directive injected (N B)` row per turn, sorted by timestamp just before the turn it informed; expanding one fetches the exact stored `prompt-optimiser-directive` bytes for that turn. The entries are listed by `GET /whatsapp-reader/directives?sessionId=` and the bytes served by `GET /whatsapp-reader/directive?sessionId=&name=`, both admin-gated and account-scoped; a missing store degrades to no rows. A centered day-divider row (`.day-divider`) marks each local calendar-day crossover between consecutive turns so a thread spanning midnight is unambiguous. | `/whatsapp-reader/stream`, `/whatsapp-reader/directives`, `/whatsapp-reader/directive` |
|
|
308
310
|
| Conversations row hover actions | Inline rename, archive, delete, JSONL view / download per row. The historical `.conversations-modal` CSS block exists in `globals.css` but is no longer mounted from any TSX — Sidebar.tsx now owns every per-row affordance directly. | `claude-sessions.ts` |
|
|
309
311
|
| Artefacts list | Lists every `:FileArtifact` under this account's tree (`relativePath STARTS WITH 'accounts/'`, all file types, excluding the `uploads/<id>/` subtree) plus this account's IDENTITY / SOUL / KNOWLEDGE / specialist templates. Click downloads the row's backing file (`downloadPath` → `GET /api/admin/files/download`) so the operator opens it in their local app; rows whose file is outside `DATA_ROOT` (bundled-fallback templates) show a "can't be downloaded" pill. The in-app artefact pane is dead pending removal. | `sidebar-artefacts.ts`, `files.ts` |
|
|
310
312
|
| System-stats widget | CPU / RAM widget at the foot of the sidebar. | `system-stats.ts` (see above) |
|
|
@@ -373,15 +373,22 @@ The admin agent runs via Claude Code CLI, which manages its own system prompt as
|
|
|
373
373
|
|
|
374
374
|
This is assembled as a `<previous-context>` block in the system prompt on each admin turn.
|
|
375
375
|
|
|
376
|
-
### Public-agent memory context
|
|
376
|
+
### Public-agent memory context
|
|
377
377
|
|
|
378
378
|
Public agents historically had their memory context injected by a server-side bridge
|
|
379
379
|
(`fetchMemoryContext`) that spawned the memory MCP server with `ALLOWED_SCOPES=public,shared`
|
|
380
|
-
and ran a `memory-search` on the agent's behalf. That bridge
|
|
381
|
-
are
|
|
382
|
-
server-side proxy runs a public-scope memory
|
|
383
|
-
path ranked against was retired alongside it.
|
|
384
|
-
|
|
380
|
+
and ran a `memory-search` on the agent's behalf. That bridge was removed: public agents
|
|
381
|
+
are toolless (`buildPublicDeny` denies `mcp__memory__*`), so neither the agent nor a
|
|
382
|
+
server-side proxy runs a public-scope memory search, and the public-scope fulltext index that
|
|
383
|
+
path ranked against was retired alongside it.
|
|
384
|
+
|
|
385
|
+
A gated visitor's per-visitor memory still reaches their next conversation, without any tool
|
|
386
|
+
and without reopening the ringfence. The session-end reviewer writes per-visitor slice nodes
|
|
387
|
+
(`{sliceToken, scope:'user'}`); at the next gated spawn the UI process fetches that visitor's
|
|
388
|
+
own `scope:'user'` slice nodes (a slice-pinned read, not a public-scope search), renders them
|
|
389
|
+
to a `<previous-context>` block, and threads it through the public spawn body so the manager
|
|
390
|
+
appends it to the agent's system prompt. Only the visitor's own slice is read; open-mode
|
|
391
|
+
visitors, admins, and first visits inject nothing.
|
|
385
392
|
|
|
386
393
|
---
|
|
387
394
|
|
|
@@ -449,7 +456,7 @@ The Claude Code SDK marks every MCP tool as **deferred** by default. The model c
|
|
|
449
456
|
|
|
450
457
|
The SDK's per-tool override is `_meta["anthropic/alwaysLoad"]: true` on each MCP tool's `tools/list` entry. Two surfaces apply it:
|
|
451
458
|
|
|
452
|
-
1. **In-process plugins.** Every admin-eager tool is registered via `eagerTool(server, name, description, inputSchema, handler)` from `platform/lib/mcp-eager/` instead of `server.tool(...)`. The helper calls `server.registerTool` with the `_meta` flag set.
|
|
459
|
+
1. **In-process plugins.** Every admin-eager tool is registered via `eagerTool(server, name, description, inputSchema, handler)` from `platform/lib/mcp-eager/` instead of `server.tool(...)`. The helper calls `server.registerTool` with the `_meta` flag set. Both `eagerTool` and the non-eager `lifelineTool` (from `platform/lib/mcp-lifeline/`) wrap the handler with `wrapWithLifeline`, which emits a structured `op=request`/`op=result` log pair per call including a holdings census — see `.docs/mcp-helper-observability.md` "Tool-call lifeline".
|
|
453
460
|
2. **Upstream graph proxy.** The upstream Python `mcp-neo4j-cypher` server has no `_meta` channel, so `platform/lib/graph-mcp/src/index.ts` intercepts every `tools/list` response on the wire and injects `_meta["anthropic/alwaysLoad"]: true` into each tool entry. The `[graph-mcp] tools/list eager-flagged count=<N>` stderr line confirms the injection fired.
|
|
454
461
|
|
|
455
462
|
**Curation rule.** Every MCP tool the admin agent calls routinely should be eager — registered via `eagerTool` (or arriving through the graph-mcp interceptor). Whether a tool is eager is decided at its registration site in the plugin's MCP `index.ts` (`eagerTool` vs `server.tool`); there is no separate allow-list constant. Admin-skill / specialist / public-agent tools that stay on `server.tool()` pay the ToolSearch tax only when their caller invokes them. The admin tool surface (`toolSurface.admin`, the `adminAllowlist: true` set) is the intended eager set; a routinely-called admin tool left on `server.tool()` is a gap to fix at the registration site.
|
|
@@ -59,6 +59,7 @@ import { memoryCompiledTruthHistory } from "./tools/memory-compiled-truth-histor
|
|
|
59
59
|
import { getSession, closeDriver } from "./lib/neo4j.js";
|
|
60
60
|
import { embed } from "./lib/embeddings.js";
|
|
61
61
|
import { notTrashed } from "../../../../lib/graph-trash/dist/index.js";
|
|
62
|
+
import { lifelineTool } from "../../../../lib/mcp-lifeline/dist/index.js";
|
|
62
63
|
const server = new McpServer({
|
|
63
64
|
name: "maxy-memory",
|
|
64
65
|
version: "0.1.0",
|
|
@@ -406,7 +407,7 @@ eagerTool(server, "memory-lookup-by-name", "Deterministic by-name entity lookup.
|
|
|
406
407
|
// so the conversation-archive-enrich skill can drive the dispatched
|
|
407
408
|
// specialist to read each chunk and emit claims in-turn. Read-only.
|
|
408
409
|
// ---------------------------------------------------------------------------
|
|
409
|
-
server
|
|
410
|
+
lifelineTool(server, "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.", {
|
|
410
411
|
archiveElementId: z
|
|
411
412
|
.string()
|
|
412
413
|
.describe("elementId of the :ConversationArchive parent (Task 397 — keyed on conversationIdentity) the operator named (required)."),
|
|
@@ -490,7 +491,7 @@ const claimSchema = z.object({
|
|
|
490
491
|
.optional()
|
|
491
492
|
.describe("Kind-specific structured fields (taskTitle/taskDueHint for task; preferenceCategory/preferenceKey/preferenceValue for preference; relationshipType for observed-relationship)."),
|
|
492
493
|
});
|
|
493
|
-
server
|
|
494
|
+
lifelineTool(server, "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.", {
|
|
494
495
|
archiveElementId: z
|
|
495
496
|
.string()
|
|
496
497
|
.describe("elementId of the :ConversationArchive parent (Task 397 — keyed on conversationIdentity) the operator named (required)."),
|
|
@@ -565,7 +566,7 @@ process.stderr.write("[memory-mcp] registered tool=conversation-archive-derive-i
|
|
|
565
566
|
// undo — drop matching line via atomic-rename (called after a `wire`
|
|
566
567
|
// so a later wire of a once-rejected key cleans up its rejection).
|
|
567
568
|
// ---------------------------------------------------------------------------
|
|
568
|
-
server
|
|
569
|
+
lifelineTool(server, "conversation-archive-enrich-rejection", "Record or undo a per-row rejection from conversation-archive-enrich. Writes a sidecar JSONL keyed on (chunkElementId, kind, contentHash). Call with mode='record' on operator `reject`; call with mode='undo' after a successful `wire` so a later wire of a once-rejected key clears its rejection. Idempotent: duplicate records are no-ops.", {
|
|
569
570
|
archiveElementId: z
|
|
570
571
|
.string()
|
|
571
572
|
.describe("elementId of the conversation-document parent (carried on each line for diagnostics)."),
|
|
@@ -888,7 +889,7 @@ if (!readOnly) {
|
|
|
888
889
|
};
|
|
889
890
|
}
|
|
890
891
|
});
|
|
891
|
-
server
|
|
892
|
+
lifelineTool(server, "memory-update-by-name", "Update an existing node addressed by (label, name, accountId) instead of elementId. Use this as a repair surface when memory-search cannot return an elementId for a node you know exists by name — typically an ingest-created :Organization the search route is failing to surface. Resolves the unique node matching the tuple, then delegates to memory-update (embedding refresh, write gates, compiled-truth refusal, and provenance stamping all carry over). Rejects loudly on zero matches (the row does not exist) and on two-or-more matches (ambiguous — the rejection lists candidate elementIds so you can pick one and call memory-update directly). Trashed nodes are excluded from the lookup. For one-off updates where you already have the elementId from a successful memory-search, prefer memory-update — this tool is the fallback when search hides the node.", {
|
|
892
893
|
label: z.string().describe("The single label to MATCH on (e.g. 'Organization', 'Person', 'Project'). Must be exactly the label carried by the target node — the tool does not iterate label variants."),
|
|
893
894
|
name: z.string().describe("The exact `name` property of the target node (case-sensitive). Forbidden-property rules still apply downstream — if the label rejects `name`, use memory-update with the correct identifier instead."),
|
|
894
895
|
properties: z
|
|
@@ -930,7 +931,7 @@ if (!readOnly) {
|
|
|
930
931
|
};
|
|
931
932
|
}
|
|
932
933
|
});
|
|
933
|
-
server
|
|
934
|
+
lifelineTool(server, "memory-update", "Update properties on an existing node in the knowledge graph. Finds the node by element ID, verifies account ownership, sets the provided properties, and recomputes the embedding. To refresh `compiledTruth` / `compiledTruthPublic` on :Person / :Organization / :Concept / :Project / :LocalBusiness, dispatch the `compiled-truth-rewriter` specialist via the Task tool — admin sends the nodeId plus any `operatorHint` / `publicOperatorHint`; the specialist reads the node + 90-day timeline, computes the new summary, and writes it back via memory-update. Direct writes to compiled-truth properties via this tool are refused unless the caller is the compiled-truth-rewriter specialist (gated by MAXY_SPECIALIST env). When you only have the node's name (typically because memory-search couldn't return it), use memory-update-by-name instead.", {
|
|
934
935
|
nodeId: z.string().describe("Element ID of the node to update (from memory-search results)"),
|
|
935
936
|
properties: z
|
|
936
937
|
.record(z.string(), z.unknown())
|
|
@@ -970,7 +971,7 @@ if (!readOnly) {
|
|
|
970
971
|
};
|
|
971
972
|
}
|
|
972
973
|
});
|
|
973
|
-
server
|
|
974
|
+
lifelineTool(server, "memory-edge", "Create or delete a typed directed edge between two nodes that already exist in the knowledge graph. Both nodes must belong to the same account. Use action='create' to MERGE the edge (idempotent — returns {created:false} if it already exists) or action='delete' to remove it (returns {deleted:false} if already absent). relationshipType is uppercase-coerced; types starting with underscore are reserved and rejected. Properties are stamped on the edge on CREATE only.", {
|
|
974
975
|
action: z.enum(["create", "delete"]).describe("'create' MERGEs the edge (idempotent); 'delete' removes it (no-op if absent)."),
|
|
975
976
|
fromId: z.string().describe("elementId of the source node (from memory-search results)."),
|
|
976
977
|
toId: z.string().describe("elementId of the target node (from memory-search results)."),
|
|
@@ -1127,7 +1128,7 @@ if (!readOnly) {
|
|
|
1127
1128
|
};
|
|
1128
1129
|
}
|
|
1129
1130
|
});
|
|
1130
|
-
server
|
|
1131
|
+
lifelineTool(server, "memory-ingest-extract", "Extract text from an uploaded file and cache it server-side for memory-ingest. " +
|
|
1131
1132
|
"Supports PDF (via pdftotext), plain text, and markdown. " +
|
|
1132
1133
|
"Rejects CSV (structured data — use memory-write instead) and images (metadata-only). " +
|
|
1133
1134
|
"Returns file metadata + a short preview; the full text lives in the in-process cache keyed by attachmentId. " +
|
|
@@ -1158,7 +1159,7 @@ if (!readOnly) {
|
|
|
1158
1159
|
};
|
|
1159
1160
|
}
|
|
1160
1161
|
});
|
|
1161
|
-
server
|
|
1162
|
+
lifelineTool(server, "memory-ingest", "Write a classified document or conversation-archive session into the graph as typed nodes anchored to a subject. " +
|
|
1162
1163
|
"Two mutually-exclusive parent paths — exactly one MUST be set: " +
|
|
1163
1164
|
"(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. " +
|
|
1164
1165
|
"(2) **Conversation-archive path** — set `conversationIdentity` along with the conversation-document fields (`source`, `archiveSha256`, `archiveSourceFile`, `participantElementIds`, `lastIngestedMessageHash`, `lastIngestedMessageAt`, `sessionIndex`, 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. `:Section.body` is server-sliced from the per-session turnText tempfile the bin wrote at `turnTextCachePath(conversationIdentity, archiveSha256, sessionIndex)` — the specialist emits offsets, never body text (server-sliced via per-session tempfile). " +
|
|
@@ -1453,7 +1454,7 @@ if (!readOnly) {
|
|
|
1453
1454
|
// `memory/bin/conversation-archive-ingest.{mjs,sh}`. Phase-2 insight
|
|
1454
1455
|
// derivation will operate on conversation-document :Section chunks regardless of
|
|
1455
1456
|
// source.
|
|
1456
|
-
server
|
|
1457
|
+
lifelineTool(server, "memory-ingest-web", "Adapter for web-content ingestion. Accepts a URL, its pre-fetched readable content " +
|
|
1457
1458
|
"(the agent calls WebFetch first, then passes the text here), and the page's editorial title parsed from " +
|
|
1458
1459
|
"the HTML `<title>` / `og:title`. Writes the content to a temp file and delegates to memory-ingest-extract — " +
|
|
1459
1460
|
"caching the text under a freshly-generated attachmentId. The dispatched specialist then produces typed-section " +
|
|
@@ -1505,7 +1506,7 @@ if (!readOnly) {
|
|
|
1505
1506
|
};
|
|
1506
1507
|
}
|
|
1507
1508
|
});
|
|
1508
|
-
server
|
|
1509
|
+
lifelineTool(server, "memory-find-candidates", "Deterministic bulk-delete selector for Conversation nodes. Returns a structured list of candidates " +
|
|
1509
1510
|
"matching a fixed-name filter ('empty' = zero :PART_OF messages; 'single-assistant' = exactly one " +
|
|
1510
1511
|
"assistant-role message) and an opaque filterToken. Pair with memory-delete(filterToken=…) — the server " +
|
|
1511
1512
|
"re-runs the same predicate per elementId before trashing, so a stale or forged token never deletes. " +
|
|
@@ -1549,7 +1550,7 @@ if (!readOnly) {
|
|
|
1549
1550
|
};
|
|
1550
1551
|
}
|
|
1551
1552
|
});
|
|
1552
|
-
server
|
|
1553
|
+
lifelineTool(server, "memory-node-exists", "Deterministic label-existence check for installer-seeded singleton roots. " +
|
|
1553
1554
|
"Returns { exists, elementId, labels } for a single label/accountId lookup, " +
|
|
1554
1555
|
"bypassing the memory-search ranking stack so an installer-seeded node with " +
|
|
1555
1556
|
"empty content properties (e.g. a freshly seeded :LocalBusiness with no name yet) " +
|
|
@@ -1573,7 +1574,7 @@ if (!readOnly) {
|
|
|
1573
1574
|
};
|
|
1574
1575
|
}
|
|
1575
1576
|
});
|
|
1576
|
-
server
|
|
1577
|
+
lifelineTool(server, "memory-delete", "Soft-delete a single graph node by elementId. Adds the :Trashed label, preserves relationships, " +
|
|
1577
1578
|
"and excludes the node from memory-search and any read filtered via notTrashed. For KnowledgeDocument, " +
|
|
1578
1579
|
"cascades to linked Section and Chunk children. For Conversation, cascades to attached :PART_OF Messages " +
|
|
1579
1580
|
". Hard removal happens later via memory-empty-trash after the grace period (default 30 days). " +
|
|
@@ -1608,7 +1609,7 @@ if (!readOnly) {
|
|
|
1608
1609
|
};
|
|
1609
1610
|
}
|
|
1610
1611
|
});
|
|
1611
|
-
server
|
|
1612
|
+
lifelineTool(server, "memory-restore", "Undo memory-delete on a single graph node by elementId. Removes the :Trashed label and restores " +
|
|
1612
1613
|
"snapshotted unique-key properties. For KnowledgeDocument, walks HAS_SECTION/HAS_CHUNK edges to bring " +
|
|
1613
1614
|
"trashed children back too. Fails loudly when an active node already holds a unique slot the trashed " +
|
|
1614
1615
|
"node needs back (e.g. a fresh LocalBusiness was created while the old one was in trash) — " +
|
|
@@ -1636,7 +1637,7 @@ if (!readOnly) {
|
|
|
1636
1637
|
};
|
|
1637
1638
|
}
|
|
1638
1639
|
});
|
|
1639
|
-
server
|
|
1640
|
+
lifelineTool(server, "memory-empty-trash", "Hard-delete trashed nodes whose trashedAt is older than the grace period (default 30 days). " +
|
|
1640
1641
|
"For KnowledgeDocument candidates, also removes the on-disk attachment directory. Use dryRun=true " +
|
|
1641
1642
|
"to preview candidates without mutating — the absence of [trash:emptied] log lines after a " +
|
|
1642
1643
|
"[trash:empty-run] dryRun=true line is the correct-behaviour signal. Optional labels filter " +
|
|
@@ -1668,7 +1669,7 @@ if (!readOnly) {
|
|
|
1668
1669
|
};
|
|
1669
1670
|
}
|
|
1670
1671
|
});
|
|
1671
|
-
server
|
|
1672
|
+
lifelineTool(server, "memory-list-attachments", "List stored file attachments for this account with their ingestion status. " +
|
|
1672
1673
|
"Returns original filenames, sizes, upload dates, and whether each file has been ingested " +
|
|
1673
1674
|
"into the knowledge graph. Does not include web-ingested documents (those have no file on disk).", {}, async () => {
|
|
1674
1675
|
if (!accountId)
|
|
@@ -1706,7 +1707,7 @@ if (!readOnly) {
|
|
|
1706
1707
|
};
|
|
1707
1708
|
}
|
|
1708
1709
|
});
|
|
1709
|
-
server
|
|
1710
|
+
lifelineTool(server, "memory-read-attachment", "Read the content of a stored attachment from disk. Returns the full text for text/markdown files, " +
|
|
1710
1711
|
"extracted text for PDFs (via pdftotext), and metadata + HTTP URL for images. " +
|
|
1711
1712
|
"Use this to show the user what's in a file or to prepare content for editing.", {
|
|
1712
1713
|
attachmentId: z.string().describe("UUID of the attachment to read"),
|
|
@@ -1731,7 +1732,7 @@ if (!readOnly) {
|
|
|
1731
1732
|
};
|
|
1732
1733
|
}
|
|
1733
1734
|
});
|
|
1734
|
-
server
|
|
1735
|
+
lifelineTool(server, "memory-edit-attachment", "Edit a stored text/markdown attachment in place. Replaces the file content on disk, updates the " +
|
|
1735
1736
|
"metadata timestamp, and re-extracts the file for chunking (populating the extract cache). " +
|
|
1736
1737
|
"After this call, use memory-ingest with updated summaries to sync the knowledge graph. " +
|
|
1737
1738
|
"Only text/plain and text/markdown files are editable — PDFs and images are rejected.", {
|
|
@@ -1760,7 +1761,7 @@ if (!readOnly) {
|
|
|
1760
1761
|
};
|
|
1761
1762
|
}
|
|
1762
1763
|
});
|
|
1763
|
-
server
|
|
1764
|
+
lifelineTool(server, "memory-rename-attachment", "Rename a stored attachment. Updates the filename in the .meta.json sidecar and the " +
|
|
1764
1765
|
"KnowledgeDocument name in Neo4j (if the file has been ingested). The file on disk " +
|
|
1765
1766
|
"is not renamed — it uses UUID-based naming. Only the human-readable metadata changes.", {
|
|
1766
1767
|
attachmentId: z.string().describe("UUID of the attachment to rename"),
|
|
@@ -1841,7 +1842,7 @@ if (!readOnly) {
|
|
|
1841
1842
|
const agoStr = ago ? ` (${ago})` : "";
|
|
1842
1843
|
return `${label} [${agentInfo}] · created ${createdStr} · active ${updatedStr}${agoStr} — ${opts.messageCount} messages`;
|
|
1843
1844
|
}
|
|
1844
|
-
server
|
|
1845
|
+
lifelineTool(server, "conversation-list", "List conversations or retrieve messages from a specific conversation. " +
|
|
1845
1846
|
"Without sessionId: lists all conversations with message counts, ordered by most recent activity (updatedAt DESC). " +
|
|
1846
1847
|
"Headers show both creation time and last activity time; when they differ, the conversation was resumed. " +
|
|
1847
1848
|
"With sessionId: returns all messages in that conversation chronologically with per-message timestamps. " +
|
|
@@ -2032,7 +2033,7 @@ if (!readOnly) {
|
|
|
2032
2033
|
await dbSession.close();
|
|
2033
2034
|
}
|
|
2034
2035
|
});
|
|
2035
|
-
server
|
|
2036
|
+
lifelineTool(server, "profile-update", "Create, update, or reinforce a user preference; set top-level UserProfile fields (timezone, locale, givenName, role, expertise) via profileFields; AND set operator-identity fields (email, telephone) on the operator's personal-profile Person via personFields. Person is the canonical operator-identity store; UserProfile carries preferences and behavioural state only. Supports modes: reinforce (re-observed, boost confidence), update (value changed), contradict (value contradicts prior), merge (combine overlapping preferences).", {
|
|
2036
2037
|
category: z.enum(["communication", "scheduling", "decision", "workflow", "content", "interaction"])
|
|
2037
2038
|
.describe("Preference category"),
|
|
2038
2039
|
key: z.string().describe("Preference identifier (e.g. 'response_length', 'meeting_time')"),
|
|
@@ -2089,7 +2090,7 @@ if (!readOnly) {
|
|
|
2089
2090
|
};
|
|
2090
2091
|
}
|
|
2091
2092
|
});
|
|
2092
|
-
server
|
|
2093
|
+
lifelineTool(server, "profile-delete", "Soft-delete a specific user preference (marks :Trashed, restorable via memory-restore within the grace period; permanently removed later by memory-empty-trash). Use when the owner says 'forget that' or 'don't remember X'. Idempotent — succeeds even if the preference doesn't exist.", {
|
|
2093
2094
|
category: z.enum(["communication", "scheduling", "decision", "workflow", "content", "interaction"])
|
|
2094
2095
|
.describe("Preference category"),
|
|
2095
2096
|
key: z.string().describe("Preference key to delete"),
|
|
@@ -2122,7 +2123,7 @@ if (!readOnly) {
|
|
|
2122
2123
|
});
|
|
2123
2124
|
// profile-read contains owner PII (name, role, timezone, preferences) —
|
|
2124
2125
|
// admin-only, not exposed to the public agent.
|
|
2125
|
-
server
|
|
2126
|
+
lifelineTool(server, "profile-read", "Read the business owner's profile and preferences. Returns preferences grouped by category (communication, scheduling, decisions, workflow, content, interaction). " +
|
|
2126
2127
|
"With detail=true: includes per-preference confidence scores, evidence trail (which conversations the preference was observed in), source (explicit vs behavioural), and summary statistics. " +
|
|
2127
2128
|
"Use detail=true when the owner asks 'what do you know about me?' or when reviewing memory accuracy.", {
|
|
2128
2129
|
detail: z.boolean().optional().describe("When true, returns per-preference confidence, source, evidence trail, and memory statistics. " +
|
|
@@ -2158,7 +2159,7 @@ if (!readOnly) {
|
|
|
2158
2159
|
// :Idea nodes filtered by r.createdByAgent='database-operator'. The
|
|
2159
2160
|
// admin agent uses this to answer "what has the brain captured today?"
|
|
2160
2161
|
// without touching cypher. Task 439.
|
|
2161
|
-
server
|
|
2162
|
+
lifelineTool(server, "memory-brain-capture-recent", "Read the most recent per-turn graph-pass writes for this account: entity mentions extracted from operator messages, and original-thinking :Idea nodes. " +
|
|
2162
2163
|
"Default window is the last 24 hours. " +
|
|
2163
2164
|
"Use this when the operator asks 'what has the brain captured today?', 'show me recent mentions of X', or 'what ideas did I leave on the table this week?'.", {
|
|
2164
2165
|
windowHours: z.number().int().optional().describe("Hours back from now. Default 24. Capped at 720 (30 days)."),
|
|
@@ -2192,7 +2193,7 @@ if (!readOnly) {
|
|
|
2192
2193
|
// replaces the removed graph-prune autonomous rule engine whose
|
|
2193
2194
|
// orphan-delete rule wiped 19 nodes on 2026-04-20.
|
|
2194
2195
|
// -------------------------------------------------------------------------
|
|
2195
|
-
server
|
|
2196
|
+
lifelineTool(server, "graph-prune-denylist-add", "Add one or more strings to the operator-curated deny-list. The list is a stored signal — no cron, no " +
|
|
2196
2197
|
"autonomous sweep. The admin agent reads the list and decides per case whether to null a property " +
|
|
2197
2198
|
"via memory-update, remove a node via memory-delete, or scrub a conversation's :Memory via " +
|
|
2198
2199
|
"conversation-memory-expunge. Use to record poisonous substrings (retired domain names, wrong " +
|
|
@@ -2221,7 +2222,7 @@ if (!readOnly) {
|
|
|
2221
2222
|
};
|
|
2222
2223
|
}
|
|
2223
2224
|
});
|
|
2224
|
-
server
|
|
2225
|
+
lifelineTool(server, "graph-prune-denylist-remove", "Remove one or more strings from the operator-curated deny-list. Entries no longer serve as signal " +
|
|
2225
2226
|
"for the admin agent. Any property values previously nulled via manual memory-update calls are not " +
|
|
2226
2227
|
"restored — audit entries on each affected node remain for forensic review.", {
|
|
2227
2228
|
values: z.array(z.string().min(1)).min(1).describe("Substring values to remove (must match exactly as previously added)."),
|
|
@@ -2246,7 +2247,7 @@ if (!readOnly) {
|
|
|
2246
2247
|
};
|
|
2247
2248
|
}
|
|
2248
2249
|
});
|
|
2249
|
-
server
|
|
2250
|
+
lifelineTool(server, "conversation-memory-expunge", "Remove deny-listable content from a specific conversation's :Memory nodes by manually-supplied " +
|
|
2250
2251
|
"substring pattern. Targets :Memory nodes linked to the named Conversation; nulls every string property " +
|
|
2251
2252
|
"whose value contains the pattern, with an audit entry on each affected node. The conversation transcript " +
|
|
2252
2253
|
"(Message nodes) is immutable history and is never modified — only the derived :Memory payload that " +
|
|
@@ -2281,7 +2282,7 @@ if (!readOnly) {
|
|
|
2281
2282
|
});
|
|
2282
2283
|
}
|
|
2283
2284
|
// graph-prune-denylist-list and conversation-search are read-only — available regardless of readOnly mode.
|
|
2284
|
-
server
|
|
2285
|
+
lifelineTool(server, "graph-prune-denylist-list", "List the current operator-curated deny-list values used by the daily graph-prune cron. " +
|
|
2285
2286
|
"Returns the substring values, the timestamp of the last edit, and the total count.", {}, () => {
|
|
2286
2287
|
if (!accountId)
|
|
2287
2288
|
return refuseNoAccount("graph-prune-denylist-list");
|
|
@@ -2393,7 +2394,7 @@ eagerTool(server, "conversation-search", "Search conversation history using sema
|
|
|
2393
2394
|
// Specialist tool, not in ADMIN_CORE_TOOLS — registered via server.tool, not
|
|
2394
2395
|
// eagerTool (deferred-by-default ToolSearch tax is acceptable because the
|
|
2395
2396
|
// curator is the only routine caller).
|
|
2396
|
-
server
|
|
2397
|
+
lifelineTool(server, "image-fetch", [
|
|
2397
2398
|
"Fetch a remote image URL and return its bytes as an inline image content block the model can see.",
|
|
2398
2399
|
"Guards: http/https only, content-type must start with image/, 10 MB byte cap, 30 s timeout.",
|
|
2399
2400
|
"Returns one text block summarising the fetch plus one image block on success; one text block with isError on failure.",
|
|
@@ -2431,7 +2432,7 @@ server.tool("image-fetch", [
|
|
|
2431
2432
|
// (admin Task-spawns it during an on-demand `/insight` pass); NOT in
|
|
2432
2433
|
// `ADMIN_CORE_TOOLS`. Backfill is via the CLI under `scripts/backfill-typed-edges.ts`,
|
|
2433
2434
|
// bypassing this tool.
|
|
2434
|
-
server
|
|
2435
|
+
lifelineTool(server, "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 for its insight-pass summary.", {
|
|
2435
2436
|
sinceIso: z.string().describe("ISO timestamp lower bound. Prose nodes with updatedAt >= sinceIso are processed."),
|
|
2436
2437
|
sessionId: z.string().optional().describe("Conversation id stamped onto the createdBy provenance of MERGEd edges. Defaults to SESSION_ID env if absent."),
|
|
2437
2438
|
}, async (args) => {
|
|
@@ -2470,7 +2471,7 @@ server.tool("memory-typed-edge-pass", "Run the typed-edge auto-extraction pass o
|
|
|
2470
2471
|
// ===================================================================
|
|
2471
2472
|
// Report MCP tools (Task 332) are registered earlier in this file.
|
|
2472
2473
|
// Dream-run calls the same writer in-process for the per-run :Report.
|
|
2473
|
-
server
|
|
2474
|
+
lifelineTool(server, "memory-dream-run", "Operator-initiated dream-cycle: graph-hygiene sweep across seven phases " +
|
|
2474
2475
|
"(orphan detection, stale compiled-truth, edges to :Trashed targets, citation audit on :TimelineEvent, " +
|
|
2475
2476
|
"prune compiled-truth revisions, materialise :BACKLINKS edges, tag normalisation). " +
|
|
2476
2477
|
"Writes a :Report node at the end. Failure of any phase logs and continues. " +
|
|
@@ -2493,7 +2494,7 @@ server.tool("memory-dream-run", "Operator-initiated dream-cycle: graph-hygiene s
|
|
|
2493
2494
|
};
|
|
2494
2495
|
}
|
|
2495
2496
|
});
|
|
2496
|
-
server
|
|
2497
|
+
lifelineTool(server, "memory-review-queue", "Read-only summary of the dream-cycle's review queues (:OrphanCandidate, :CitationProposal). " +
|
|
2497
2498
|
"Returns per-queue counts and a small sample so the operator can see whether to triage.", {
|
|
2498
2499
|
sampleSize: z.number().int().positive().optional().describe("Sample rows per queue. Default 5, max 25."),
|
|
2499
2500
|
}, async ({ sampleSize }) => {
|