@rubytech/create-maxy-code 0.1.294 → 0.1.296
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/lib/models/dist/index.d.ts +1 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +4 -2
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +3 -1
- package/payload/platform/neo4j/schema.cypher +10 -2
- package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-compliance.test.sh +27 -0
- package/payload/platform/plugins/admin/hooks/prompt-optimiser-compliance.sh +24 -5
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +22 -4
- package/payload/platform/plugins/docs/references/admin-ui.md +19 -2
- package/payload/platform/plugins/docs/references/platform.md +2 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.js +214 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.js +113 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-write-path-task802.test.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts +52 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js +90 -4
- package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/vitest.config.ts +3 -0
- package/payload/platform/plugins/memory/references/schema-base.md +6 -2
- package/payload/platform/plugins/memory/references/schema-construction.md +8 -6
- package/payload/platform/plugins/memory/references/schema-estate-agent.md +1 -1
- package/payload/platform/scripts/smoke-boot-services.sh +1 -1
- 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 +23 -3
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
- 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 +14 -0
- 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 +7 -4
- 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 +7 -4
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts +3 -0
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js +28 -0
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +10 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +15 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/account.json +1 -1
- package/payload/platform/templates/specialists/agents/data-manager.md +27 -0
- package/payload/server/public/assets/AdminShell-DDieHnzi.js +1 -0
- package/payload/server/public/assets/{Checkbox-DxOCnNT7.js → Checkbox-DTrIyIFP.js} +1 -1
- package/payload/server/public/assets/{Transcript-BIhFafaZ.js → Transcript-C3aDVJ-n.js} +1 -1
- package/payload/server/public/assets/{admin-CGjBmQRF.js → admin-DVdyV-Q6.js} +1 -1
- package/payload/server/public/assets/{arc-CL2g6wtE.js → arc-DmR-LPIx.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-CjF2k79a.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-B6pI_4kf.js → architectureDiagram-Q4EWVU46-DR9W0q1P.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-DGEfApkA.js +1 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-OTjX8onE.js → blockDiagram-DXYQGD6D-C3uwaI7p.js} +1 -1
- package/payload/server/public/assets/{browser-Bf0v--kb.js → browser-DrJReVEG.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-d3BJbhwh.js → c4Diagram-AHTNJAMY-C8hmUDdd.js} +1 -1
- package/payload/server/public/assets/channel-drVqp11B.js +1 -0
- package/payload/server/public/assets/chat-rJYaCD6C.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-CjdgBkCI.js → chunk-2KRD3SAO-BYqpHDvA.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-77Kuo1_M.js → chunk-336JU56O-BRCubMCb.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-BNINkVsL.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-CJ-bacvW.js → chunk-4BX2VUAB-BeDVr5Tb.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-C7oTm4E0.js → chunk-4TB4RGXK-DSMj_AZh.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BGVu8gHm.js → chunk-55IACEB6-DB18cH4S.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-BBHRG4DD.js → chunk-5FUZZQ4R-6DNGaUkf.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BbxYk0vN.js → chunk-5PVQY5BW-DPhkkS4p.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-DCXRVLld.js → chunk-67CJDMHE-Ca9KwdQm.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-Cb8gnv2L.js → chunk-7N4EOEYR-BDpzHOmv.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-BDKd8RHS.js → chunk-AA7GKIK3-DXo9fZho.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-C-a5U7hf.js → chunk-BSJP7CBP-CTqmM6qI.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C2s4AWWp.js → chunk-CIAEETIT-NufEId2j.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-C_NxZc3q.js → chunk-EDXVE4YY-BjWSqn7_.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CP-iwXd0.js → chunk-ENJZ2VHE-BX1ZnU4A.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-Cb04mvB7.js → chunk-FMBD7UC4-_4wtKsfc.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-B1tHdg5H.js → chunk-FOC6F5B3-565zaYb3.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BlGsRet_.js → chunk-ICPOFSXX-DvYSWH7x.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-I1-reqf9.js → chunk-K5T4RW27-CTZnA5fq.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-Dz5VoWZh.js → chunk-KGLVRYIC-CeuKp7uR.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-CJVhgo59.js → chunk-LIHQZDEY-DXkzlh3_.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-B236VjaQ.js → chunk-ORNJ4GCN-DcZUCmgM.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-CqSmIaQf.js → chunk-OYMX7WX6-7_m3mEOK.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CBWmDBHe.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CeMKC3D0.js → chunk-U2HBQHQK-Bl1a895I.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DK30THxZ.js → chunk-X2U36JSP-WkSpBPYx.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-DVW18Ukl.js → chunk-XPW4576I-CnU6DVpC.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DxfWX7Ap.js → chunk-YZCP3GAM-DpWRmPUo.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BEQSVm39.js → chunk-ZZ45TVLE-D9Dgmeso.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Dplkw_pj.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-sJXv1Ihp.js +1 -0
- package/payload/server/public/assets/clone-Q_B6oO0c.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BcEd1xsZ.js → cose-bilkent-S5V4N54A-C04wkJr7.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BBzAnJNh.js → dagre-KV5264BT-DPq3dcLH.js} +1 -1
- package/payload/server/public/assets/{dagre-Ch3nCevh.js → dagre-PrVfCcSt.js} +1 -1
- package/payload/server/public/assets/data-CYyR2m_B.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BG13t9mu.js → diagram-5BDNPKRD-DoszElKb.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DYh2zRvB.js → diagram-G4DWMVQ6-BRuqosix.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-CNMjDPoP.js → diagram-MMDJMWI5-CpigG1d_.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-BAb8gFOW.js → diagram-TYMM5635-BS0eYiq9.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-Dy4ADi6A.js → erDiagram-SMLLAGMA-VEQyXCFl.js} +1 -1
- package/payload/server/public/assets/file-download-C3pBZjt9.js +1 -0
- package/payload/server/public/assets/{flatten-E2Sr0FeD.js → flatten-DeFkSYLU.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DSMf9IO0.js → flowDiagram-DWJPFMVM-2NYMfqHX.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DRj0wip6.js → ganttDiagram-T4ZO3ILL-AAAa2sqE.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DsUTwRUb.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-D5s87wIr.js → gitGraphDiagram-UUTBAWPF-d8NUAIz5.js} +1 -1
- package/payload/server/public/assets/graph-Bx9_2qbJ.js +51 -0
- package/payload/server/public/assets/{graph-labels-DsXyfwKP.js → graph-labels-Cc1nU1_f.js} +1 -1
- package/payload/server/public/assets/{graphlib-DBueCu-j.js → graphlib-DUlqr2mr.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BV9FyUXQ.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-D4dh4-0g.js +2 -0
- package/payload/server/public/assets/{isEmpty-CLz-UprQ.js → isEmpty-Bn-Se8yT.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BoMwv4cD.js → ishikawaDiagram-UXIWVN3A-DPTmm2IE.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BkKxK7iC.js → journeyDiagram-VCZTEJTY-B85vjqkE.js} +1 -1
- package/payload/server/public/assets/jsx-runtime-D3PZpOAF.css +1 -0
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BSrkzXlb.js → kanban-definition-6JOO6SKY-C2Lfb5Xh.js} +1 -1
- package/payload/server/public/assets/{line-CMDTDopn.js → line-CODKFpwO.js} +1 -1
- package/payload/server/public/assets/{linear-CKifLODy.js → linear-CgbkJiu6.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CEH6m0Lv.js → mermaid-parser.core-DYdFZnXH.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-DyAGyaJG.js → mermaid.core-Bamjzahu.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DLZa0d69.js → mindmap-definition-QFDTVHPH-CLK90bKJ.js} +1 -1
- package/payload/server/public/assets/{ordinal-5RtyPJVt.js → ordinal-C-EimP2j.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-SXjQ83Vr.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-q7TXebDD.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-zTOJvniq.js → pieDiagram-DEJITSTG-DEsnxhqP.js} +1 -1
- package/payload/server/public/assets/public-BFMu-jux.js +35 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CHzDGI4U.js → quadrantDiagram-34T5L4WZ-uIP9V2jZ.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-CXKUHVMS.js +1 -0
- package/payload/server/public/assets/{reduce-B3Mw_0s1.js → reduce-B0wq8DtH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CrrYBRTT.js → requirementDiagram-MS252O5E-CVS6t5tv.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-EEi77dbS.js → sankeyDiagram-XADWPNL6-BIsmtyZA.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BNeO1Hdg.js → sequenceDiagram-FGHM5R23-Cu8TfQiW.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-9Zyf6fFj.js → stateDiagram-FHFEXIEX-ax4vYGft.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BRv1By5g.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DRCVn4rg.js → timeline-definition-GMOUNBTQ-3l7ojkMA.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWuFgUeJ.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-gKO4rbgo.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-CVoG6qb0.js → useSelectionMode-C_EBRd2k.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CNaA1Bcg.js → vennDiagram-DHZGUBPP-C_sv0qMD.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-hDEw8pJN.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-9BoBW3Oo.js → wardleyDiagram-NUSXRM2D-C7u4IHMB.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CAXyPTsj.js → xychartDiagram-5P7HB3ND-A-uLXr1a.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +8 -9
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -9
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +6 -6
- package/payload/server/server.js +558 -275
- package/payload/server/public/assets/AdminShell-t3IuI7JZ.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DLCnSHk9.js +0 -1
- package/payload/server/public/assets/channel-BEqls8-f.js +0 -1
- package/payload/server/public/assets/chat-DJ3nvES3.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-TEFdhIy5.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CcHV2DdO.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CtuzQYGd.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CnyF9bus.js +0 -1
- package/payload/server/public/assets/clone-HKYySpjZ.js +0 -1
- package/payload/server/public/assets/data-BNqGUTEs.js +0 -1
- package/payload/server/public/assets/file-download-BUeQHzJD.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DOHzO_KB.js +0 -1
- package/payload/server/public/assets/graph-C4FX88ML.js +0 -51
- package/payload/server/public/assets/info-OMHHGYJF-CgstATO5.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO--6bwMJZM.js +0 -2
- package/payload/server/public/assets/jsx-runtime-61OZ_8PV.css +0 -1
- package/payload/server/public/assets/mic-BXINsrwF.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BRSJpaWt.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-B5VBvTzX.js +0 -1
- package/payload/server/public/assets/public-Cya9ie76.js +0 -35
- package/payload/server/public/assets/radar-PYXPWWZC-CWBqEfap.js +0 -1
- package/payload/server/public/assets/sliders-horizontal-CUmlgKbR.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-PeqMIgxs.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-D8zjIvCq.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DQW69zQK.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-CDTm6Cdu.js +0 -1
- /package/payload/server/public/assets/{_baseFor-DVaNaTfF.js → _baseFor-BV-TyLWt.js} +0 -0
- /package/payload/server/public/assets/{array-8_H1156C.js → array-lqrvkwy7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-h10p_6j-.js → cytoscape.esm-SmEOayFS.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-pD7tFa1r.js → defaultLocale-Dl3Sud5K.js} +0 -0
- /package/payload/server/public/assets/{dist-DHQbMi0P.js → dist-Pgmncqde.js} +0 -0
- /package/payload/server/public/assets/{init-CwJ4b81e.js → init-BukMwkmL.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-GpAtq6d8.js → jsx-runtime-5auA0FEj.js} +0 -0
- /package/payload/server/public/assets/{katex-DJPjIBAI.js → katex-jl-BtNZi.js} +0 -0
- /package/payload/server/public/assets/{path-CK8wrAxY.js → path-DPTRcLku.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-Dwml_la6.js → rough.esm-VLpapkIG.js} +0 -0
- /package/payload/server/public/assets/{src-CglFLxOI.js → src-CozP7LCe.js} +0 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAChD,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKvD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
// Templates, docs, and skills reference these values as strings;
|
|
4
4
|
// all TypeScript consumers import from here.
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.MODEL_CONTEXT_WINDOW = exports.HAIKU_MODEL = exports.SONNET_MODEL = exports.OPUS_MODEL = void 0;
|
|
6
|
+
exports.MODEL_CONTEXT_WINDOW = exports.HAIKU_MODEL = exports.SONNET_MODEL = exports.OPUS_MODEL = exports.FABLE_MODEL = void 0;
|
|
7
7
|
exports.contextWindow = contextWindow;
|
|
8
|
-
// Opus
|
|
8
|
+
// Fable and Opus default to the 1M-context variant ([1m] is Claude Code's
|
|
9
9
|
// context-extension suffix, valid in settings.json "model" and agent
|
|
10
10
|
// frontmatter); Sonnet/Haiku stay on the standard 200k window.
|
|
11
|
+
exports.FABLE_MODEL = "claude-fable-5[1m]";
|
|
11
12
|
exports.OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
12
13
|
exports.SONNET_MODEL = "claude-sonnet-4-6";
|
|
13
14
|
exports.HAIKU_MODEL = "claude-haiku-4-5";
|
|
14
15
|
exports.MODEL_CONTEXT_WINDOW = {
|
|
16
|
+
[exports.FABLE_MODEL]: 1_000_000,
|
|
15
17
|
[exports.OPUS_MODEL]: 1_000_000,
|
|
16
18
|
[exports.SONNET_MODEL]: 200_000,
|
|
17
19
|
[exports.HAIKU_MODEL]: 200_000,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,iEAAiE;AACjE,6CAA6C;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,iEAAiE;AACjE,6CAA6C;;;AAkB7C,sCAEC;AAlBD,0EAA0E;AAC1E,qEAAqE;AACrE,+DAA+D;AAClD,QAAA,WAAW,GAAG,oBAAoB,CAAC;AACnC,QAAA,UAAU,GAAG,qBAAqB,CAAC;AACnC,QAAA,YAAY,GAAG,mBAAmB,CAAC;AACnC,QAAA,WAAW,GAAG,kBAAkB,CAAC;AAEjC,QAAA,oBAAoB,GAA2B;IAC1D,CAAC,mBAAW,CAAC,EAAE,SAAS;IACxB,CAAC,kBAAU,CAAC,EAAE,SAAS;IACvB,CAAC,oBAAY,CAAC,EAAE,OAAO;IACvB,CAAC,mBAAW,CAAC,EAAE,OAAO;CACvB,CAAC;AAEF,wEAAwE;AACxE,SAAgB,aAAa,CAAC,KAAa;IACzC,OAAO,4BAAoB,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC;AAChD,CAAC"}
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// Templates, docs, and skills reference these values as strings;
|
|
3
3
|
// all TypeScript consumers import from here.
|
|
4
4
|
|
|
5
|
-
// Opus
|
|
5
|
+
// Fable and Opus default to the 1M-context variant ([1m] is Claude Code's
|
|
6
6
|
// context-extension suffix, valid in settings.json "model" and agent
|
|
7
7
|
// frontmatter); Sonnet/Haiku stay on the standard 200k window.
|
|
8
|
+
export const FABLE_MODEL = "claude-fable-5[1m]";
|
|
8
9
|
export const OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
9
10
|
export const SONNET_MODEL = "claude-sonnet-4-6";
|
|
10
11
|
export const HAIKU_MODEL = "claude-haiku-4-5";
|
|
11
12
|
|
|
12
13
|
export const MODEL_CONTEXT_WINDOW: Record<string, number> = {
|
|
14
|
+
[FABLE_MODEL]: 1_000_000,
|
|
13
15
|
[OPUS_MODEL]: 1_000_000,
|
|
14
16
|
[SONNET_MODEL]: 200_000,
|
|
15
17
|
[HAIKU_MODEL]: 200_000,
|
|
@@ -1409,8 +1409,16 @@ OPTIONS {
|
|
|
1409
1409
|
}
|
|
1410
1410
|
};
|
|
1411
1411
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1412
|
+
// Task 802 renamed the key property invoiceNumber -> confirmationNumber
|
|
1413
|
+
// (Schema.org canonical). The constraint gets a NEW name because
|
|
1414
|
+
// CREATE ... IF NOT EXISTS matches by constraint name: re-using the old
|
|
1415
|
+
// name would silently skip creation on databases seeded before the rename,
|
|
1416
|
+
// leaving the key unprotected. The old-name DROP retires the stale
|
|
1417
|
+
// invoiceNumber constraint on those databases; both statements are
|
|
1418
|
+
// idempotent on fresh installs.
|
|
1419
|
+
DROP CONSTRAINT inbound_invoice_account_supplier_num_unique IF EXISTS;
|
|
1420
|
+
CREATE CONSTRAINT inbound_invoice_account_supplier_confirmation_unique IF NOT EXISTS
|
|
1421
|
+
FOR (ii:InboundInvoice) REQUIRE (ii.accountId, ii.supplier, ii.confirmationNumber) IS UNIQUE;
|
|
1414
1422
|
|
|
1415
1423
|
CREATE INDEX inbound_invoice_account IF NOT EXISTS
|
|
1416
1424
|
FOR (ii:InboundInvoice) ON (ii.accountId);
|
|
@@ -45,6 +45,17 @@ ASSISTANT_REPLY='{"type":"assistant","message":{"role":"assistant","content":[{"
|
|
|
45
45
|
ASSISTANT_REPLYDOC='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"mcp__whatsapp-channel__reply-document","input":{}}]}}'
|
|
46
46
|
ASSISTANT_SKILLLOAD='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"mcp__admin__skill-load","input":{}}]}}'
|
|
47
47
|
ASSISTANT_TASK='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Task","input":{}}]}}'
|
|
48
|
+
ASSISTANT_BASH='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Bash","input":{}}]}}'
|
|
49
|
+
ASSISTANT_WRITE='{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","name":"Write","input":{}}]}}'
|
|
50
|
+
# Task 805 — a production-shape reframe turn: channel-wrapped, isMeta, carrying
|
|
51
|
+
# the composeAdminContent ## Context / ## Instruction sections. No directive
|
|
52
|
+
# marker row accompanies it (the directive hook suppresses itself on channel
|
|
53
|
+
# turns, Task 753), so the reframe itself must count as directive-equivalent.
|
|
54
|
+
CHANNEL_REFRAME='{"type":"user","isMeta":true,"message":{"role":"user","content":"<channel source=\"whatsapp-channel\">## Context\nplease draft the works order PDF for order 926\n\n## Instruction\nChoose the installed specialist that owns this request and dispatch it with the Agent tool.</channel>"}}'
|
|
55
|
+
# Same shape, one-word Context payload — the trivial filter must read the
|
|
56
|
+
# payload, not the wrapper (the always-present instruction text would otherwise
|
|
57
|
+
# make every reframed turn look non-trivial).
|
|
58
|
+
CHANNEL_REFRAME_TRIVIAL='{"type":"user","isMeta":true,"message":{"role":"user","content":"<channel source=\"whatsapp-channel\">## Context\nyes\n\n## Instruction\nChoose the installed specialist that owns this request and dispatch it with the Agent tool.</channel>"}}'
|
|
48
59
|
|
|
49
60
|
assert_flagged() {
|
|
50
61
|
local name="$1" t="$2" out
|
|
@@ -147,6 +158,22 @@ assert_not_flagged "route then isMeta injections -> not flagged (slice not trunc
|
|
|
147
158
|
assert_not_flagged "slash prompt then isMeta skill body -> not flagged" \
|
|
148
159
|
"$(mk_transcript '{"type":"user","message":{"role":"user","content":"/insight"}}' "$DIRECTIVE_ATTACH" "$ASSISTANT_TEXT" "$META_SKILL")"
|
|
149
160
|
|
|
161
|
+
# 16. Task 805 — reframed channel turn, no marker row, inline authoring tools
|
|
162
|
+
# (the e48c2a5e freestyle shape) -> flagged. The reframe IS the directive.
|
|
163
|
+
assert_flagged "reframe turn + inline authoring, no marker -> flagged" \
|
|
164
|
+
"$(mk_transcript "$CHANNEL_REFRAME" "$ASSISTANT_REPLY" "$ASSISTANT_BASH" "$ASSISTANT_WRITE")"
|
|
165
|
+
# 17. Same reframed turn with an Agent dispatch -> not flagged.
|
|
166
|
+
assert_not_flagged "reframe turn + Agent dispatch -> not flagged" \
|
|
167
|
+
"$(mk_transcript "$CHANNEL_REFRAME" "$ASSISTANT_REPLY" "$ASSISTANT_AGENT")"
|
|
168
|
+
# 18. Reframed turn whose Context payload is one word -> trivial, not flagged,
|
|
169
|
+
# even though the wrapper text is long.
|
|
170
|
+
assert_not_flagged "reframe turn with one-word Context payload -> not flagged (trivial)" \
|
|
171
|
+
"$(mk_transcript "$CHANNEL_REFRAME_TRIVIAL" "$ASSISTANT_TEXT")"
|
|
172
|
+
# 19. Channel-wrapped NON-reframe turn (no ## Instruction section — webchat
|
|
173
|
+
# today, Task 776) with no marker -> not directive-equivalent, not flagged.
|
|
174
|
+
assert_not_flagged "channel-wrapped non-reframe turn, no marker -> not flagged" \
|
|
175
|
+
"$(mk_transcript "$CHANNEL_PROMPT" "$ASSISTANT_TEXT")"
|
|
176
|
+
|
|
150
177
|
# 11. Fail-open: missing transcript_path -> exit 0, no output.
|
|
151
178
|
fo_out=$(printf '{"session_id":"x"}' | bash "$HOOK" 2>&1); fo_exit=$?
|
|
152
179
|
if [[ "$fo_exit" -eq 0 && -z "$fo_out" ]]; then
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
# slice (robust to CC-version differences in how the
|
|
12
12
|
# UserPromptSubmit additionalContext is recorded: a
|
|
13
13
|
# type:"attachment"/hook_success on 2.1.x, a
|
|
14
|
-
# type:"hook_additional_context" on the Pi)
|
|
14
|
+
# type:"hook_additional_context" on the Pi), OR the prompt is
|
|
15
|
+
# a <channel>-wrapped reframe turn (## Context/## Instruction
|
|
16
|
+
# sections, Task 805) — the directive hook suppresses itself
|
|
17
|
+
# on channel turns, so the reframe is directive-equivalent.
|
|
15
18
|
# route taken = the turn contains a tool_use that is a genuine route:
|
|
16
19
|
# Agent/Task dispatch, native Skill, or a *__skill-load MCP
|
|
17
20
|
# tool. ToolSearch (a schema load) and the channel transport
|
|
@@ -126,23 +129,39 @@ if boundary is None:
|
|
|
126
129
|
|
|
127
130
|
slice_rows = rows[boundary:]
|
|
128
131
|
|
|
129
|
-
# Strip a leading <channel ...>...</channel> wrapper to reach the inner prompt
|
|
130
|
-
#
|
|
132
|
+
# Strip a leading <channel ...>...</channel> wrapper to reach the inner prompt
|
|
133
|
+
# (WhatsApp/native-channel prompts arrive wrapped).
|
|
131
134
|
inner = prompt_text
|
|
135
|
+
is_channel = False
|
|
132
136
|
if inner.startswith("<channel"):
|
|
133
137
|
end = inner.find(">")
|
|
134
138
|
close = inner.rfind("</channel>")
|
|
135
139
|
if end != -1 and close != -1 and close > end:
|
|
136
140
|
inner = inner[end + 1:close].strip()
|
|
141
|
+
is_channel = True
|
|
142
|
+
|
|
143
|
+
# Task 805 — a channel-wrapped reframe turn (the ## Context / ## Instruction
|
|
144
|
+
# sections of composeAdminContent) is directive-equivalent: the directive hook suppresses
|
|
145
|
+
# itself on channel turns (Task 753), so the reframe is the only routing
|
|
146
|
+
# instruction the turn carries, and the marker check alone left every channel
|
|
147
|
+
# turn unevaluated. A channel-wrapped turn WITHOUT the reframe (webchat today,
|
|
148
|
+
# Task 776) is not directive-equivalent. For the trivial check the prompt is the
|
|
149
|
+
# Context payload, not the wrapper — the always-present instruction text would
|
|
150
|
+
# otherwise make a one-word confirmation look non-trivial.
|
|
151
|
+
is_reframe = is_channel and inner.startswith("## Context\n") and "\n## Instruction\n" in inner
|
|
152
|
+
if is_reframe:
|
|
153
|
+
head, _, _rest = inner.partition("\n## Instruction\n")
|
|
154
|
+
inner = head[len("## Context"):].strip()
|
|
137
155
|
|
|
138
156
|
# Trivial-turn filter.
|
|
139
157
|
is_slash = inner.startswith("/")
|
|
140
158
|
tokens = inner.split()
|
|
141
159
|
is_one_word = len(tokens) <= 1
|
|
142
160
|
|
|
143
|
-
# Directive fired = marker present anywhere in the slice (any record shape)
|
|
161
|
+
# Directive fired = marker present anywhere in the slice (any record shape) OR
|
|
162
|
+
# the prompt is a channel-wrapped reframe turn (Task 805).
|
|
144
163
|
marker = "PROMPT-OPTIMISER DIRECTIVE"
|
|
145
|
-
directive_fired = any(marker in json.dumps(r, ensure_ascii=False) for r in slice_rows)
|
|
164
|
+
directive_fired = is_reframe or any(marker in json.dumps(r, ensure_ascii=False) for r in slice_rows)
|
|
146
165
|
|
|
147
166
|
# Route taken = an assistant tool_use that is a genuine route: specialist
|
|
148
167
|
# dispatch (Agent/Task) or skill load (native Skill, or the *__skill-load MCP
|
|
@@ -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:c39a9e28304fa49a4afee3aabc0507872065d868994c9ab14d56b2576f4ce636
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -153,7 +153,7 @@ Plugins are installed and managed through conversation. You can add marketplace
|
|
|
153
153
|
|
|
154
154
|
## Roles
|
|
155
155
|
|
|
156
|
-
Maxy ships
|
|
156
|
+
Maxy ships thirteen roles it can dispatch for specific tasks — like members of your team. You don't need to configure or manage them — Maxy decides when to use each role and handles everything automatically. You may see activity like "Dispatching personal-assistant..." in the chat timeline when this happens.
|
|
157
157
|
|
|
158
158
|
The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask Maxy to call `capabilities-here`.
|
|
159
159
|
|
|
@@ -164,6 +164,7 @@ The catalogue below is what the platform ships. It is not evidence of what is in
|
|
|
164
164
|
| Coding Assistant | Runs shell commands, drives git repositories, and reads or edits code on your behalf — the specialist you reach for when the work belongs in a developer terminal. |
|
|
165
165
|
| Compiled Truth Rewriter | Recomputes a node's compiledTruth (and public twin where applicable) from its 90-day timeline plus optional operator hints. |
|
|
166
166
|
| Content Producer | Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip. |
|
|
167
|
+
| Data Manager | Keeps the account data directory organised consistently with the graph ontology, pairing every file move with a database-operator reference update. |
|
|
167
168
|
| Database Operator | Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it. |
|
|
168
169
|
| Librarian | Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph. |
|
|
169
170
|
| Personal Assistant | Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. |
|
|
@@ -2280,7 +2281,9 @@ Task 500 — **admin session management moved entirely to claude's own interface
|
|
|
2280
2281
|
|
|
2281
2282
|
**Row title resolution.** Both the sidebar (`/sidebar-sessions`) and the manager's own row payload resolve a row's title in the same order: operator rename → Claude Code `ai-title` → first non-CLI user message → 8-char sessionId prefix. The operator-rename tier is the on-disk `<accountDir>/session-titles.json` (the manager's `UserTitleStore`), keyed by the CC sessionId — the sidebar reads that same file, so a write to the store lights up both surfaces with one write.
|
|
2282
2283
|
|
|
2283
|
-
**Task 785 — `/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. Logs: `[webchat:greeting] op=read account=<id8> events=<n> tasks=<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`.
|
|
2284
|
+
**Task 785 — `/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. **Task 792** adds a third section, **Your specialists**: 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`.
|
|
2285
|
+
|
|
2286
|
+
**Task 799 — `/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 with only the message text (no label, no per-turn time); all agent output renders as plain prose (the reply-document filename line stays, as prose); 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` unmodified, `app/chat/__tests__/transcript-render.test.tsx` new).
|
|
2284
2287
|
|
|
2285
2288
|
**Task 624 — 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 bridge (`dispatchOnce` → `managerSpawn`) to the manager `POST /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.
|
|
2286
2289
|
|
|
@@ -2331,6 +2334,21 @@ snapping back to the data root; the hash never reaches the server and `/data`
|
|
|
2331
2334
|
has no client router, so the channel is isolated. `path=` is cleared at the
|
|
2332
2335
|
root for a clean URL.
|
|
2333
2336
|
|
|
2337
|
+
**`/data` search — locate-in-files link and clear button (Task 791).** Every
|
|
2338
|
+
search hit is a `:FileArtifact` backed by a physical file, so each result card
|
|
2339
|
+
whose `relativePath` is a non-empty string carries a **locate link** (folder
|
|
2340
|
+
icon + containing folder; root-level files show `data`). Clicking it clears the
|
|
2341
|
+
active search (query, results, error, chip) and navigates the file browser to
|
|
2342
|
+
that folder via the same `path` state + `#path=` hash contract above, so the
|
|
2343
|
+
file appears among its siblings and a reload restores the place. The link is a
|
|
2344
|
+
sibling of the clickable card, so it never triggers the row's download. Hits
|
|
2345
|
+
without a usable `relativePath` render no link; one
|
|
2346
|
+
`console.warn('[data-search] op=locate-link-missing nodeId=…')` per result set
|
|
2347
|
+
surfaces the index gap, and each click logs
|
|
2348
|
+
`[data-search] op=locate nodeId=… folder=…`. The search bar shows an **× clear
|
|
2349
|
+
button** while it holds text — clicking empties the input, clears results
|
|
2350
|
+
(restoring the file-browser body), and refocuses the input.
|
|
2351
|
+
|
|
2334
2352
|
### Browser / device-browser
|
|
2335
2353
|
|
|
2336
2354
|
| Mount | Purpose |
|
|
@@ -2444,7 +2462,7 @@ authoritative. This section names the surfaces and what backs each.
|
|
|
2444
2462
|
| `+ New session` button | Opens `NewSessionModal`, which POSTs `{channel, permissionMode, model, initialMessage}` to `/api/admin/claude-sessions`. | `claude-sessions.ts` |
|
|
2445
2463
|
| Mode trigger | Per-`(accountId, userId)` `SpawnPreference` for `permissionMode` and `model`; persists across reload, tab, device. | `session-defaults.ts` |
|
|
2446
2464
|
| 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` |
|
|
2447
|
-
| Sessions list (Active / Archived / All) | Live row store driven by SSE; manual reconcile button on the segmented control re-fetches the full id set. | `/claude-sessions/events`, `/claude-sessions` |
|
|
2465
|
+
| 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 resumable row (not `resumable === false` public rows) carries two launch actions (Task 800): 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). | `/claude-sessions/events`, `/claude-sessions` |
|
|
2448
2466
|
| Channel reader nav rows (WhatsApp / Telegram) | One conditional nav row **per interactive channel that has ≥1 admin session** (Task 738). 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` (Task 747): 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". 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` |
|
|
2449
2467
|
| 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 (Task 747). 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 (Task 746), 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` |
|
|
2450
2468
|
| 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` |
|
|
@@ -53,7 +53,9 @@ Task 500 — **admin session management moved entirely to claude's own interface
|
|
|
53
53
|
|
|
54
54
|
**Row title resolution.** Both the sidebar (`/sidebar-sessions`) and the manager's own row payload resolve a row's title in the same order: operator rename → Claude Code `ai-title` → first non-CLI user message → 8-char sessionId prefix. The operator-rename tier is the on-disk `<accountDir>/session-titles.json` (the manager's `UserTitleStore`), keyed by the CC sessionId — the sidebar reads that same file, so a write to the store lights up both surfaces with one write.
|
|
55
55
|
|
|
56
|
-
**Task 785 — `/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. Logs: `[webchat:greeting] op=read account=<id8> events=<n> tasks=<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`.
|
|
56
|
+
**Task 785 — `/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. **Task 792** adds a third section, **Your specialists**: 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
|
+
|
|
58
|
+
**Task 799 — `/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 with only the message text (no label, no per-turn time); all agent output renders as plain prose (the reply-document filename line stays, as prose); 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` unmodified, `app/chat/__tests__/transcript-render.test.tsx` new).
|
|
57
59
|
|
|
58
60
|
**Task 624 — 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 bridge (`dispatchOnce` → `managerSpawn`) to the manager `POST /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.
|
|
59
61
|
|
|
@@ -104,6 +106,21 @@ snapping back to the data root; the hash never reaches the server and `/data`
|
|
|
104
106
|
has no client router, so the channel is isolated. `path=` is cleared at the
|
|
105
107
|
root for a clean URL.
|
|
106
108
|
|
|
109
|
+
**`/data` search — locate-in-files link and clear button (Task 791).** Every
|
|
110
|
+
search hit is a `:FileArtifact` backed by a physical file, so each result card
|
|
111
|
+
whose `relativePath` is a non-empty string carries a **locate link** (folder
|
|
112
|
+
icon + containing folder; root-level files show `data`). Clicking it clears the
|
|
113
|
+
active search (query, results, error, chip) and navigates the file browser to
|
|
114
|
+
that folder via the same `path` state + `#path=` hash contract above, so the
|
|
115
|
+
file appears among its siblings and a reload restores the place. The link is a
|
|
116
|
+
sibling of the clickable card, so it never triggers the row's download. Hits
|
|
117
|
+
without a usable `relativePath` render no link; one
|
|
118
|
+
`console.warn('[data-search] op=locate-link-missing nodeId=…')` per result set
|
|
119
|
+
surfaces the index gap, and each click logs
|
|
120
|
+
`[data-search] op=locate nodeId=… folder=…`. The search bar shows an **× clear
|
|
121
|
+
button** while it holds text — clicking empties the input, clears results
|
|
122
|
+
(restoring the file-browser body), and refocuses the input.
|
|
123
|
+
|
|
107
124
|
### Browser / device-browser
|
|
108
125
|
|
|
109
126
|
| Mount | Purpose |
|
|
@@ -217,7 +234,7 @@ authoritative. This section names the surfaces and what backs each.
|
|
|
217
234
|
| `+ New session` button | Opens `NewSessionModal`, which POSTs `{channel, permissionMode, model, initialMessage}` to `/api/admin/claude-sessions`. | `claude-sessions.ts` |
|
|
218
235
|
| Mode trigger | Per-`(accountId, userId)` `SpawnPreference` for `permissionMode` and `model`; persists across reload, tab, device. | `session-defaults.ts` |
|
|
219
236
|
| 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` |
|
|
220
|
-
| Sessions list (Active / Archived / All) | Live row store driven by SSE; manual reconcile button on the segmented control re-fetches the full id set. | `/claude-sessions/events`, `/claude-sessions` |
|
|
237
|
+
| 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 resumable row (not `resumable === false` public rows) carries two launch actions (Task 800): 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). | `/claude-sessions/events`, `/claude-sessions` |
|
|
221
238
|
| Channel reader nav rows (WhatsApp / Telegram) | One conditional nav row **per interactive channel that has ≥1 admin session** (Task 738). 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` (Task 747): 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". 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` |
|
|
222
239
|
| 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 (Task 747). 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 (Task 746), 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` |
|
|
223
240
|
| 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` |
|
|
@@ -39,7 +39,7 @@ Plugins are installed and managed through conversation. You can add marketplace
|
|
|
39
39
|
|
|
40
40
|
## Roles
|
|
41
41
|
|
|
42
|
-
{{productName}} ships
|
|
42
|
+
{{productName}} ships thirteen roles it can dispatch for specific tasks — like members of your team. You don't need to configure or manage them — {{productName}} decides when to use each role and handles everything automatically. You may see activity like "Dispatching personal-assistant..." in the chat timeline when this happens.
|
|
43
43
|
|
|
44
44
|
The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask {{productName}} to call `capabilities-here`.
|
|
45
45
|
|
|
@@ -50,6 +50,7 @@ The catalogue below is what the platform ships. It is not evidence of what is in
|
|
|
50
50
|
| Coding Assistant | Runs shell commands, drives git repositories, and reads or edits code on your behalf — the specialist you reach for when the work belongs in a developer terminal. |
|
|
51
51
|
| Compiled Truth Rewriter | Recomputes a node's compiledTruth (and public twin where applicable) from its 90-day timeline plus optional operator hints. |
|
|
52
52
|
| Content Producer | Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip. |
|
|
53
|
+
| Data Manager | Keeps the account data directory organised consistently with the graph ontology, pairing every file move with a database-operator reference update. |
|
|
53
54
|
| Database Operator | Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it. |
|
|
54
55
|
| Librarian | Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph. |
|
|
55
56
|
| Personal Assistant | Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-doc-contradictions.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/schema-doc-contradictions.test.ts"],"names":[],"mappings":""}
|
package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { test, expect, vi } from "vitest";
|
|
2
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { loadSchema, detectContradictions } from "../schema-loader.js";
|
|
6
|
+
const expectEqual = (actual, wanted) => expect(actual).toBe(wanted);
|
|
7
|
+
const expectDeepEqual = (actual, wanted) => expect(actual).toEqual(wanted);
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Task 802 — schema docs must never prescribe a property name that the
|
|
10
|
+
// loaded synonym (wrongToCorrect) map bans in the same scope. A label whose
|
|
11
|
+
// required cell contains a banned token is structurally unwritable: the
|
|
12
|
+
// banned name trips the synonym rejection, the canonical name trips the
|
|
13
|
+
// missing-required check.
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const BASE_WITH_AMOUNT_BAN = `# Base
|
|
16
|
+
|
|
17
|
+
## Property Naming Rules
|
|
18
|
+
|
|
19
|
+
| Correct | Wrong |
|
|
20
|
+
|---------|-------|
|
|
21
|
+
| \`totalPaymentDue\` | \`amount\`, \`total\` |
|
|
22
|
+
| \`postalCode\` | \`postcode\` |
|
|
23
|
+
`;
|
|
24
|
+
function writeFixtureDir(files) {
|
|
25
|
+
const dir = mkdtempSync(join(tmpdir(), "schema-contradictions-"));
|
|
26
|
+
for (const [name, content] of Object.entries(files)) {
|
|
27
|
+
writeFileSync(join(dir, name), content, "utf-8");
|
|
28
|
+
}
|
|
29
|
+
return dir;
|
|
30
|
+
}
|
|
31
|
+
test("detectContradictions: required token banned by base file is reported", () => {
|
|
32
|
+
const dir = writeFixtureDir({
|
|
33
|
+
"schema-base.md": BASE_WITH_AMOUNT_BAN,
|
|
34
|
+
"schema-vert.md": `# Vert
|
|
35
|
+
|
|
36
|
+
## Node Types
|
|
37
|
+
|
|
38
|
+
| Entity | Neo4j Label | Required Properties |
|
|
39
|
+
|--------|-------------|---------------------|
|
|
40
|
+
| Foo | \`Foo\` | \`accountId\`, \`amount\`, \`status\` |
|
|
41
|
+
`,
|
|
42
|
+
});
|
|
43
|
+
const schema = loadSchema({ referencesDir: dir });
|
|
44
|
+
const hits = detectContradictions(schema);
|
|
45
|
+
expectEqual(hits.length, 1);
|
|
46
|
+
expectDeepEqual(hits[0], {
|
|
47
|
+
file: "schema-vert.md",
|
|
48
|
+
label: "Foo",
|
|
49
|
+
property: "amount",
|
|
50
|
+
correct: "totalPaymentDue",
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
test("detectContradictions: clean required cell yields no contradictions", () => {
|
|
54
|
+
const dir = writeFixtureDir({
|
|
55
|
+
"schema-base.md": BASE_WITH_AMOUNT_BAN,
|
|
56
|
+
"schema-vert.md": `# Vert
|
|
57
|
+
|
|
58
|
+
## Node Types
|
|
59
|
+
|
|
60
|
+
| Entity | Neo4j Label | Required Properties |
|
|
61
|
+
|--------|-------------|---------------------|
|
|
62
|
+
| Foo | \`Foo\` | \`accountId\`, \`totalPaymentDue\`, \`status\` |
|
|
63
|
+
`,
|
|
64
|
+
});
|
|
65
|
+
const hits = detectContradictions(loadSchema({ referencesDir: dir }));
|
|
66
|
+
expectDeepEqual(hits, []);
|
|
67
|
+
});
|
|
68
|
+
test("detectContradictions: documented-canonical bullet banned by base is reported with heading label", () => {
|
|
69
|
+
const dir = writeFixtureDir({
|
|
70
|
+
"schema-base.md": BASE_WITH_AMOUNT_BAN,
|
|
71
|
+
"schema-vert.md": `# Vert
|
|
72
|
+
|
|
73
|
+
## Node Types
|
|
74
|
+
|
|
75
|
+
| Entity | Neo4j Label | Required Properties |
|
|
76
|
+
|--------|-------------|---------------------|
|
|
77
|
+
| Bar | \`Bar\` | \`accountId\` |
|
|
78
|
+
|
|
79
|
+
### Bar — full property set
|
|
80
|
+
|
|
81
|
+
- \`slug\` — URL-safe identifier
|
|
82
|
+
- \`postcode\` — UK postcode
|
|
83
|
+
- \`town\`
|
|
84
|
+
`,
|
|
85
|
+
});
|
|
86
|
+
const hits = detectContradictions(loadSchema({ referencesDir: dir }));
|
|
87
|
+
expectEqual(hits.length, 1);
|
|
88
|
+
expectDeepEqual(hits[0], {
|
|
89
|
+
file: "schema-vert.md",
|
|
90
|
+
label: "Bar",
|
|
91
|
+
property: "postcode",
|
|
92
|
+
correct: "postalCode",
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
test("detectContradictions: vertical-file ban only applies to labels in the same file", () => {
|
|
96
|
+
const vertTable = (label) => `# Vert
|
|
97
|
+
|
|
98
|
+
## Node Types
|
|
99
|
+
|
|
100
|
+
| Entity | Neo4j Label | Required Properties |
|
|
101
|
+
|--------|-------------|---------------------|
|
|
102
|
+
| ${label} | \`${label}\` | \`accountId\`, \`widgetCount\` |
|
|
103
|
+
`;
|
|
104
|
+
const banTable = `
|
|
105
|
+
## Property Naming Rules
|
|
106
|
+
|
|
107
|
+
| Correct | Wrong |
|
|
108
|
+
|---------|-------|
|
|
109
|
+
| \`numberOfItems\` | \`widgetCount\` |
|
|
110
|
+
`;
|
|
111
|
+
// Ban declared in schema-aaa.md; schema-bbb.md requires the banned token.
|
|
112
|
+
// Out of scope (different vertical) -> not a contradiction.
|
|
113
|
+
const crossDir = writeFixtureDir({
|
|
114
|
+
"schema-base.md": "# Base\n",
|
|
115
|
+
"schema-aaa.md": `# A\n${banTable}`,
|
|
116
|
+
"schema-bbb.md": vertTable("Bee"),
|
|
117
|
+
});
|
|
118
|
+
expectDeepEqual(detectContradictions(loadSchema({ referencesDir: crossDir })), []);
|
|
119
|
+
// Same file declares the ban AND requires the banned token -> contradiction.
|
|
120
|
+
const sameDir = writeFixtureDir({
|
|
121
|
+
"schema-base.md": "# Base\n",
|
|
122
|
+
"schema-aaa.md": `${vertTable("Aye")}\n${banTable}`,
|
|
123
|
+
});
|
|
124
|
+
const hits = detectContradictions(loadSchema({ referencesDir: sameDir }));
|
|
125
|
+
expectEqual(hits.length, 1);
|
|
126
|
+
expectEqual(hits[0].label, "Aye");
|
|
127
|
+
expectEqual(hits[0].property, "widgetCount");
|
|
128
|
+
});
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Boot standing check: loadSchema() emits one structured stderr line per
|
|
131
|
+
// contradiction at every MCP boot, so a drifted or field-edited schema file
|
|
132
|
+
// is visible in the memory plugin's stderr log without any write attempted.
|
|
133
|
+
// It logs only — MCP module init must never throw.
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
test("loadSchema: emits op=contradiction line per hit at boot, none when clean", () => {
|
|
136
|
+
const contradictingDir = writeFixtureDir({
|
|
137
|
+
"schema-base.md": BASE_WITH_AMOUNT_BAN,
|
|
138
|
+
"schema-vert.md": `# Vert
|
|
139
|
+
|
|
140
|
+
## Node Types
|
|
141
|
+
|
|
142
|
+
| Entity | Neo4j Label | Required Properties |
|
|
143
|
+
|--------|-------------|---------------------|
|
|
144
|
+
| Foo | \`Foo\` | \`accountId\`, \`amount\` |
|
|
145
|
+
`,
|
|
146
|
+
});
|
|
147
|
+
const spy = vi
|
|
148
|
+
.spyOn(process.stderr, "write")
|
|
149
|
+
.mockImplementation(() => true);
|
|
150
|
+
try {
|
|
151
|
+
loadSchema({ referencesDir: contradictingDir });
|
|
152
|
+
const lines = spy.mock.calls
|
|
153
|
+
.map((c) => String(c[0]))
|
|
154
|
+
.filter((l) => l.includes("op=contradiction"));
|
|
155
|
+
expectDeepEqual(lines, [
|
|
156
|
+
"[schema-loader] op=contradiction file=schema-vert.md label=Foo property=amount correct=totalPaymentDue\n",
|
|
157
|
+
]);
|
|
158
|
+
spy.mockClear();
|
|
159
|
+
const cleanDir = writeFixtureDir({
|
|
160
|
+
"schema-base.md": BASE_WITH_AMOUNT_BAN,
|
|
161
|
+
"schema-vert.md": `# Vert
|
|
162
|
+
|
|
163
|
+
## Node Types
|
|
164
|
+
|
|
165
|
+
| Entity | Neo4j Label | Required Properties |
|
|
166
|
+
|--------|-------------|---------------------|
|
|
167
|
+
| Foo | \`Foo\` | \`accountId\`, \`totalPaymentDue\` |
|
|
168
|
+
`,
|
|
169
|
+
});
|
|
170
|
+
loadSchema({ referencesDir: cleanDir });
|
|
171
|
+
const cleanLines = spy.mock.calls
|
|
172
|
+
.map((c) => String(c[0]))
|
|
173
|
+
.filter((l) => l.includes("op=contradiction"));
|
|
174
|
+
expectDeepEqual(cleanLines, []);
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
spy.mockRestore();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// The gate: the shipped schema files must carry zero contradictions. The
|
|
182
|
+
// failure message lists every offending file/label/property so the fix is
|
|
183
|
+
// a doc edit away.
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
test("gate: shipped schema files carry no required-vs-banned contradictions", () => {
|
|
186
|
+
const hits = detectContradictions(loadSchema());
|
|
187
|
+
const rendered = hits
|
|
188
|
+
.map((h) => `${h.file} ${h.label}.${h.property} (use ${h.correct})`)
|
|
189
|
+
.join("\n");
|
|
190
|
+
expect(hits, `schema docs prescribe banned property names:\n${rendered}`)
|
|
191
|
+
.toEqual([]);
|
|
192
|
+
});
|
|
193
|
+
test("detectContradictions: qualified '(on ...)' wrong tokens are not bans", () => {
|
|
194
|
+
const dir = writeFixtureDir({
|
|
195
|
+
"schema-base.md": `# Base
|
|
196
|
+
|
|
197
|
+
## Property Naming Rules
|
|
198
|
+
|
|
199
|
+
| Correct | Wrong |
|
|
200
|
+
|---------|-------|
|
|
201
|
+
| \`postalCode\` | \`postcode\` (on PostalAddress nodes) |
|
|
202
|
+
`,
|
|
203
|
+
"schema-vert.md": `# Vert
|
|
204
|
+
|
|
205
|
+
## Node Types
|
|
206
|
+
|
|
207
|
+
| Entity | Neo4j Label | Required Properties |
|
|
208
|
+
|--------|-------------|---------------------|
|
|
209
|
+
| Foo | \`Foo\` | \`accountId\`, \`postcode\` |
|
|
210
|
+
`,
|
|
211
|
+
});
|
|
212
|
+
expectDeepEqual(detectContradictions(loadSchema({ referencesDir: dir })), []);
|
|
213
|
+
});
|
|
214
|
+
//# sourceMappingURL=schema-doc-contradictions.test.js.map
|
package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-doc-contradictions.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-doc-contradictions.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/schema-doc-contradictions.test.ts"],"names":[],"mappings":"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"}
|