blun-king-cli 9.0.0 → 9.1.0
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/LIESMICH.txt +32 -13
- package/README.md +39 -20
- package/bin/blun.js +248 -160
- package/bin/core-bootstrap.js +47 -0
- package/bin/king.js +277 -1
- package/bin/launcher-mode.js +15 -3
- package/bin/launcher-runtime.js +293 -0
- package/bin/plugin-bootstrap.js +11 -4
- package/bin/private-paths.js +1577 -10
- package/bin/update-lease.js +399 -0
- package/bin/update-notice.js +1245 -0
- package/blun.mjs +26606 -25239
- package/dist-web/assets/{CodeBlockNode-Bsvp6ZEy.js → CodeBlockNode-CXnTLMNr.js} +1 -1
- package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-ta7hLjia.js → CodeBlockShell.vue_vue_type_style_index_0_lang-CCF8Ntnq.js} +1 -1
- package/dist-web/assets/{DesignSystemView-BmDDe28A.js → DesignSystemView-BbMOu-XO.js} +1 -1
- package/dist-web/assets/{Tooltip-nEEfaYVY.js → Tooltip-CFQEzqC-.js} +1 -1
- package/dist-web/assets/abnfDiagram-N423BO3Z-CsByy-GW.js +1 -0
- package/dist-web/assets/abnfDiagram-N423BO3Z-Z1APZG5m.js +1 -0
- package/dist-web/assets/arc-C-LXCaja.js +1 -0
- package/dist-web/assets/arc-C4VyWloT.js +1 -0
- package/dist-web/assets/architectureDiagram-T3A2C74G-DZq4L18e.js +36 -0
- package/dist-web/assets/architectureDiagram-T3A2C74G-DpddbUcM.js +36 -0
- package/dist-web/assets/blockDiagram-VBNYF7ZC-BV4sIf98.js +132 -0
- package/dist-web/assets/blockDiagram-VBNYF7ZC-BqccOSMr.js +132 -0
- package/dist-web/assets/{c4Diagram-AAUBKEIU-DtzacMnD.js → c4Diagram-5PPSVZJV-0MRkZlgP.js} +1 -1
- package/dist-web/assets/{c4Diagram-AAUBKEIU-D1VdMx8d.js → c4Diagram-5PPSVZJV-OHAcJrTy.js} +1 -1
- package/dist-web/assets/channel-B2VOQOI-.js +1 -0
- package/dist-web/assets/channel-DKjwM05G.js +1 -0
- package/dist-web/assets/{chunk-ND2GUHAM-DJoY9wNJ.js → chunk-2GRJ4B5K-DqJHs8Fw.js} +1 -1
- package/dist-web/assets/{chunk-ND2GUHAM-C4-rwdcv.js → chunk-2GRJ4B5K-oO6nqeLA.js} +1 -1
- package/dist-web/assets/{chunk-QZHKN3VN-C7YGaShq.js → chunk-2Q5K7J3B-B1nCd91o.js} +1 -1
- package/dist-web/assets/{chunk-QZHKN3VN-_Rz9_NuS.js → chunk-2Q5K7J3B-BC0Hsfqy.js} +1 -1
- package/dist-web/assets/chunk-5RXB4S5H-BfZa4yDH.js +231 -0
- package/dist-web/assets/chunk-5RXB4S5H-neG70kZx.js +231 -0
- package/dist-web/assets/{chunk-FMBD7UC4-DlLNDUx6.js → chunk-5VM5RSS4-l7biGqeH.js} +1 -1
- package/dist-web/assets/{chunk-FMBD7UC4-B2zs_Y-d.js → chunk-5VM5RSS4-u00AcpiJ.js} +1 -1
- package/dist-web/assets/chunk-6Q2QTUOP-BO-F11Gs.js +88 -0
- package/dist-web/assets/chunk-6Q2QTUOP-RUVRPBzG.js +88 -0
- package/dist-web/assets/{chunk-727SXJPM-Dn5wkDO_.js → chunk-GF5L2VYU-Ba-86KTd.js} +5 -5
- package/dist-web/assets/{chunk-727SXJPM-Dk2Xa3bA.js → chunk-GF5L2VYU-BtC69fw0.js} +5 -5
- package/dist-web/assets/{chunk-4BX2VUAB-DxZViaHS.js → chunk-JWPE2WC7-DIOubEqr.js} +1 -1
- package/dist-web/assets/{chunk-4BX2VUAB-WqrE2gaw.js → chunk-JWPE2WC7-u8Pcfhwh.js} +1 -1
- package/dist-web/assets/{chunk-2J33WTMH-Dm_s0_4f.js → chunk-KBJHAD2P-DDUeH_Ba.js} +1 -1
- package/dist-web/assets/{chunk-2J33WTMH-w4sdiKFO.js → chunk-KBJHAD2P-DS3BL64y.js} +1 -1
- package/dist-web/assets/chunk-RYQCIY6F-B9gFMVbS.js +1 -0
- package/dist-web/assets/chunk-RYQCIY6F-xg3EO0le.js +1 -0
- package/dist-web/assets/{chunk-55IACEB6-B5dE1-Um.js → chunk-XXDRQBXY-B60H0rRC.js} +1 -1
- package/dist-web/assets/{chunk-55IACEB6-B12zGIFz.js → chunk-XXDRQBXY-Bn1Xz6TQ.js} +1 -1
- package/dist-web/assets/classDiagram-JCYQIIEL-BA1TjAxj.js +1 -0
- package/dist-web/assets/classDiagram-JCYQIIEL-BNU7Qn4k.js +1 -0
- package/dist-web/assets/classDiagram-v2-OCEON4UE-BA1TjAxj.js +1 -0
- package/dist-web/assets/classDiagram-v2-OCEON4UE-BNU7Qn4k.js +1 -0
- package/dist-web/assets/{cose-bilkent-S5V4N54A-Bi19n8m-.js → cose-bilkent-JH36ORCC-4Ybddg08.js} +1 -1
- package/dist-web/assets/{cose-bilkent-S5V4N54A-c8o8NFp5.js → cose-bilkent-JH36ORCC-DqigO3T4.js} +1 -1
- package/dist-web/assets/cynefin-VYW2F7L2-C-EfYT07.js +178 -0
- package/dist-web/assets/cynefin-VYW2F7L2-rpD93tQ-.js +178 -0
- package/dist-web/assets/cynefinDiagram-MW4NZA55-DWZPLJcD.js +62 -0
- package/dist-web/assets/cynefinDiagram-MW4NZA55-DbTqnkVJ.js +62 -0
- package/dist-web/assets/dagre-VZM6K2ZE-DcM8aEVY.js +4 -0
- package/dist-web/assets/dagre-VZM6K2ZE-M_HVNtqP.js +4 -0
- package/dist-web/assets/diagram-7IWD3JNH-DoNximNF.js +30 -0
- package/dist-web/assets/diagram-7IWD3JNH-UymgsBNa.js +30 -0
- package/dist-web/assets/{diagram-KO2AKTUF-CFQs13i5.js → diagram-B4RE2ZJO-BVA2EhnC.js} +3 -3
- package/dist-web/assets/{diagram-KO2AKTUF-agFIuPJW.js → diagram-B4RE2ZJO-BiYu5WPF.js} +3 -3
- package/dist-web/assets/{diagram-LMA3HP47-TMIXizxR.js → diagram-LBJQPF4R-BD3kkgOO.js} +2 -2
- package/dist-web/assets/{diagram-LMA3HP47-He5zlyMt.js → diagram-LBJQPF4R-m3a1Euj3.js} +2 -2
- package/dist-web/assets/diagram-Q27KOJAE-D1mYQ_cI.js +24 -0
- package/dist-web/assets/diagram-Q27KOJAE-hy_T73PK.js +24 -0
- package/dist-web/assets/diagram-UB23O5K3-BWkoQZ4A.js +41 -0
- package/dist-web/assets/diagram-UB23O5K3-BtX8u6HG.js +41 -0
- package/dist-web/assets/ebnfDiagram-BXEA7PRR-BKs9JUHW.js +1 -0
- package/dist-web/assets/ebnfDiagram-BXEA7PRR-CBAnFkRF.js +1 -0
- package/dist-web/assets/erDiagram-JOGREHBK-3vKcWsxm.js +85 -0
- package/dist-web/assets/erDiagram-JOGREHBK-BIpd6dTf.js +85 -0
- package/dist-web/assets/flowDiagram-UKHOOZJN-D9wBbHm2.js +156 -0
- package/dist-web/assets/flowDiagram-UKHOOZJN-Z83i2UWI.js +156 -0
- package/dist-web/assets/ganttDiagram-PKOTCBZU-Cd_dViF-.js +292 -0
- package/dist-web/assets/ganttDiagram-PKOTCBZU-DFrb_S1d.js +292 -0
- package/dist-web/assets/{gitGraphDiagram-PVQCEYII-BSDFfwdY.js → gitGraphDiagram-DS77QQ5N-BiEEtTo7.js} +3 -3
- package/dist-web/assets/{gitGraphDiagram-PVQCEYII-DMbTATyw.js → gitGraphDiagram-DS77QQ5N-Dp3Ar-hi.js} +3 -3
- package/dist-web/assets/{graph-BwjfAU3j.js → graph-CAUpWmoK.js} +1 -1
- package/dist-web/assets/{graph--OzhPTMs.js → graph-DOmOIIwC.js} +1 -1
- package/dist-web/assets/{index-W6VnSrkB.js → index-Ba1OvLjf.js} +2 -2
- package/dist-web/assets/{index-CkVgGDpx.js → index-CiPA8Kex.js} +4 -4
- package/dist-web/assets/{index-BzK4vJBu.js → index-DdEakFJM.js} +1 -1
- package/dist-web/assets/{index10-Czg_oF-W.js → index10-CNr4U-Nw.js} +1 -1
- package/dist-web/assets/{index11-BjzCZuCr.js → index11-Dto_yZNz.js} +1 -1
- package/dist-web/assets/{index5-DlVoNkCD.js → index5-B2PldaO2.js} +1 -1
- package/dist-web/assets/{index6-BxiXA2yo.js → index6-CBdZmmyx.js} +1 -1
- package/dist-web/assets/{index7-BPdza6d1.js → index7-Dz9oCsUF.js} +1 -1
- package/dist-web/assets/{index8-Q_XzGC1Z.js → index8-B6k25jtU.js} +2 -2
- package/dist-web/assets/{infoDiagram-5YYISTIA-2JF3XEdD.js → infoDiagram-6WML65LV-BSa2g04G.js} +1 -1
- package/dist-web/assets/{infoDiagram-5YYISTIA-UrQusrJq.js → infoDiagram-6WML65LV-D4ph2sIH.js} +1 -1
- package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-7RVUL-vB.js → ishikawaDiagram-WSZJBQD7-DjKjbMm9.js} +5 -5
- package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-C5OstRVV.js → ishikawaDiagram-WSZJBQD7-Hm36UOQe.js} +5 -5
- package/dist-web/assets/{journeyDiagram-JHISSGLW-B34fCMu9.js → journeyDiagram-NVQOT4AX-DttHDfPQ.js} +1 -1
- package/dist-web/assets/{journeyDiagram-JHISSGLW-yctdo4bX.js → journeyDiagram-NVQOT4AX-MvWWPNDV.js} +1 -1
- package/dist-web/assets/{kanban-definition-UN3LZRKU-BS4FBZsQ.js → kanban-definition-27J2QSJJ-C5gB-W0d.js} +7 -7
- package/dist-web/assets/{kanban-definition-UN3LZRKU-CxBCv27E.js → kanban-definition-27J2QSJJ-Cu-E_cXA.js} +5 -5
- package/dist-web/assets/layout-CvP6o9AK.js +1 -0
- package/dist-web/assets/layout-D-LzfAck.js +1 -0
- package/dist-web/assets/{linear-3mB6q2-g.js → linear-B3HWgQI2.js} +1 -1
- package/dist-web/assets/{linear-BKCnUo31.js → linear-BRGe4-d6.js} +1 -1
- package/dist-web/assets/map-CWKZqZjr.js +1 -0
- package/dist-web/assets/map-DxJ2ADlA.js +1 -0
- package/dist-web/assets/mermaid.core-D-9Sx1No.js +314 -0
- package/dist-web/assets/mermaidParser.worker-PTFfzpoB.js +318 -0
- package/dist-web/assets/{mindmap-definition-RKZ34NQL-BmJZpjh6.js → mindmap-definition-FAOFIHXS-C4vnms3i.js} +2 -2
- package/dist-web/assets/{mindmap-definition-RKZ34NQL-1mjWUcf6.js → mindmap-definition-FAOFIHXS-Cg_hoVIq.js} +1 -1
- package/dist-web/assets/pegDiagram-VL7TDLO6-B2fFEFUH.js +1 -0
- package/dist-web/assets/pegDiagram-VL7TDLO6-CSX9hitD.js +1 -0
- package/dist-web/assets/pieDiagram-7S7Q4E2Y-0L0mxahZ.js +39 -0
- package/dist-web/assets/pieDiagram-7S7Q4E2Y-C7T0Cmw1.js +39 -0
- package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BmT_qM09.js → quadrantDiagram-CIZ2JOQS-BBy7w4kD.js} +3 -3
- package/dist-web/assets/{quadrantDiagram-W4KKPZXB-C0kPuyNP.js → quadrantDiagram-CIZ2JOQS-U483z0er.js} +3 -3
- package/dist-web/assets/railroadDiagram-AXF67PYL-D80a2_DJ.js +1 -0
- package/dist-web/assets/railroadDiagram-AXF67PYL-DX8y0MzW.js +1 -0
- package/dist-web/assets/{requirementDiagram-4Y6WPE33-C0YP_Amt.js → requirementDiagram-LRYGKXZP-CeyHfq8t.js} +3 -3
- package/dist-web/assets/{requirementDiagram-4Y6WPE33-CZrxH1Y2.js → requirementDiagram-LRYGKXZP-DGD5J_4k.js} +3 -3
- package/dist-web/assets/sankeyDiagram-W5VNT64P-CCISkkrR.js +40 -0
- package/dist-web/assets/sankeyDiagram-W5VNT64P-CT5PdZz2.js +40 -0
- package/dist-web/assets/sequenceDiagram-SI44F4Z6-BeMzHWXI.js +162 -0
- package/dist-web/assets/sequenceDiagram-SI44F4Z6-jQfm2XS7.js +162 -0
- package/dist-web/assets/sizeCapture-X5ZJPWSS-BQsTdtrv.js +1 -0
- package/dist-web/assets/sizeCapture-X5ZJPWSS-lRZsmCoS.js +1 -0
- package/dist-web/assets/stateDiagram-OKZ733FA-ClCgTdUm.js +1 -0
- package/dist-web/assets/stateDiagram-OKZ733FA-Cv59z5YT.js +1 -0
- package/dist-web/assets/stateDiagram-v2-UEYNNEHI-R8jTc--F.js +1 -0
- package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fi_lrTAx.js +1 -0
- package/dist-web/assets/swimlanes-SLNWSIFB-BCdOUN05.js +2 -0
- package/dist-web/assets/swimlanes-SLNWSIFB-Cu5l7SuR.js +1 -0
- package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-BUd_uYK3.js +8 -0
- package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-CalrsgPK.js +8 -0
- package/dist-web/assets/{timeline-definition-PNZ67QCA-DsVZdrZa.js → timeline-definition-Z64GVDOM-CMjnh4bu.js} +4 -4
- package/dist-web/assets/{timeline-definition-PNZ67QCA-DnB6Usl0.js → timeline-definition-Z64GVDOM-DpWutSKa.js} +4 -4
- package/dist-web/assets/vennDiagram-T6HMQDX7-DKJW_8oU.js +34 -0
- package/dist-web/assets/vennDiagram-T6HMQDX7-DVC5JVsc.js +34 -0
- package/dist-web/assets/{vue.runtime.esm-bundler-pgHGheCW.js → vue.runtime.esm-bundler-BwwRtQwQ.js} +1 -1
- package/dist-web/assets/{wardleyDiagram-YWT4CUSO-oBauTCEw.js → wardleyDiagram-T6FBY63Y-BK2mrq7L.js} +3 -3
- package/dist-web/assets/{wardleyDiagram-YWT4CUSO-DCiyDQNB.js → wardleyDiagram-T6FBY63Y-oUvgepFn.js} +3 -3
- package/dist-web/assets/xychartDiagram-ELKLHX3M-DI6n79q0.js +7 -0
- package/dist-web/assets/xychartDiagram-ELKLHX3M-DUJu9F7-.js +7 -0
- package/dist-web/index.html +1 -1
- package/dist-web/vis/index.html.gz +0 -0
- package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/package.json +9 -11
- package/skills/screenshot-lesen/SKILL.md +0 -1
- package/skills/web-lesen/SKILL.md +0 -1
- package/telegram-plugin/dist/bridge.mjs +7 -25
- package/telegram-plugin/dist/mcp-server.mjs +236 -71
- package/dist-web/assets/arc-4xPfymbf.js +0 -1
- package/dist-web/assets/arc-Doj0wRZ0.js +0 -1
- package/dist-web/assets/architectureDiagram-3BPJPVTR-BGih283a.js +0 -36
- package/dist-web/assets/architectureDiagram-3BPJPVTR-CQ09RrbH.js +0 -36
- package/dist-web/assets/blockDiagram-GPEHLZMM-3ShMf1gu.js +0 -132
- package/dist-web/assets/blockDiagram-GPEHLZMM-CAtDjkJt.js +0 -132
- package/dist-web/assets/channel-DNkUo9e6.js +0 -1
- package/dist-web/assets/channel-DcnUTIGB.js +0 -1
- package/dist-web/assets/chunk-AQP2D5EJ-FS8-f8lF.js +0 -231
- package/dist-web/assets/chunk-AQP2D5EJ-UKhb4V4r.js +0 -231
- package/dist-web/assets/classDiagram-4FO5ZUOK-B1ZO8EbE.js +0 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK-xk6cM9Kq.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B1ZO8EbE.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-xk6cM9Kq.js +0 -1
- package/dist-web/assets/dagre-BM42HDAG-CmUO9qKN.js +0 -4
- package/dist-web/assets/dagre-BM42HDAG-DLMfLCoV.js +0 -4
- package/dist-web/assets/diagram-2AECGRRQ-DQTst0OH.js +0 -43
- package/dist-web/assets/diagram-2AECGRRQ-L74iLMqd.js +0 -43
- package/dist-web/assets/diagram-5GNKFQAL-BiBm7CJR.js +0 -10
- package/dist-web/assets/diagram-5GNKFQAL-DoE6q7H1.js +0 -10
- package/dist-web/assets/diagram-OG6HWLK6-BHCt1E0n.js +0 -24
- package/dist-web/assets/diagram-OG6HWLK6-DRyxjFMa.js +0 -24
- package/dist-web/assets/erDiagram-TEJ5UH35-BoDczjGG.js +0 -85
- package/dist-web/assets/erDiagram-TEJ5UH35-yd6SOv_7.js +0 -85
- package/dist-web/assets/flowDiagram-I6XJVG4X-DHoceI7r.js +0 -162
- package/dist-web/assets/flowDiagram-I6XJVG4X-DkYNQv0R.js +0 -162
- package/dist-web/assets/ganttDiagram-6RSMTGT7-Cg1TQBc0.js +0 -292
- package/dist-web/assets/ganttDiagram-6RSMTGT7-Z6klo7KK.js +0 -292
- package/dist-web/assets/layout-C1ojF0zw.js +0 -1
- package/dist-web/assets/layout-SsrduOYp.js +0 -1
- package/dist-web/assets/mermaid.core-D_lKT0dR.js +0 -309
- package/dist-web/assets/mermaidParser.worker-Dx4jPi9z.js +0 -313
- package/dist-web/assets/pieDiagram-4H26LBE5-BU41t2A_.js +0 -30
- package/dist-web/assets/pieDiagram-4H26LBE5-BkwDAvbt.js +0 -30
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-De_o7hDr.js +0 -40
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-Dvuj6bMA.js +0 -40
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-DuCrgPyA.js +0 -162
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-VAxffBe7.js +0 -162
- package/dist-web/assets/stateDiagram-AJRCARHV-CYLupxM7.js +0 -1
- package/dist-web/assets/stateDiagram-AJRCARHV-nDExQydZ.js +0 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BhEc7Thx.js +0 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BzwD_BIl.js +0 -1
- package/dist-web/assets/vennDiagram-CIIHVFJN-BBHQmCFf.js +0 -34
- package/dist-web/assets/vennDiagram-CIIHVFJN-Cfj-K9NW.js +0 -34
- package/dist-web/assets/wardley-L42UT6IY-BJFn8eDD.js +0 -173
- package/dist-web/assets/wardley-L42UT6IY-BSu8-4hg.js +0 -173
- package/dist-web/assets/xychartDiagram-2RQKCTM6-C2iZpl9I.js +0 -7
- package/dist-web/assets/xychartDiagram-2RQKCTM6-Db_VoDBV.js +0 -7
- package/mnemo/access_routes.js +0 -692
- package/mnemo/agent_governance.js +0 -4242
- package/mnemo/agent_mail.js +0 -901
- package/mnemo/bootstrap_auto.js +0 -137
- package/mnemo/brief_coordination.js +0 -226
- package/mnemo/code_read_tools.js +0 -375
- package/mnemo/context_preview_tools.js +0 -603
- package/mnemo/embeddings.js +0 -66
- package/mnemo/external_repo_ops.js +0 -575
- package/mnemo/facts/example-project-rules.json +0 -90
- package/mnemo/facts/example.json +0 -34
- package/mnemo/identity_schema.sql +0 -139
- package/mnemo/journal_schema.js +0 -561
- package/mnemo/loop_doctor_tools.js +0 -661
- package/mnemo/mail_secret_refs.js +0 -150
- package/mnemo/mcp.js +0 -9309
- package/mnemo/memory_consolidation.js +0 -1914
- package/mnemo/memory_health_tools.js +0 -165
- package/mnemo/package.json +0 -79
- package/mnemo/protected_scope_gate.js +0 -627
- package/mnemo/resource_access_control.js +0 -684
- package/mnemo/runtime_governance.js +0 -1256
- package/mnemo/runtime_turn_gate.js +0 -862
- package/mnemo/sandbox.js +0 -143
- package/mnemo/schema.sql +0 -389
- package/mnemo/shared_utils.js +0 -763
- package/mnemo/skills/agent-auto-resume/SKILL.md +0 -56
- package/mnemo/skills/agent_hand/SKILL.md +0 -43
- package/mnemo/skills/agent_hand/run.js +0 -63
- package/mnemo/skills/book_flight/SKILL.md +0 -34
- package/mnemo/skills/external_repo_review/SKILL.md +0 -43
- package/mnemo/skills/external_repo_review/run.js +0 -73
- package/mnemo/skills/pay_invoice/SKILL.md +0 -34
- package/mnemo/team_quality_ops.js +0 -944
- package/mnemo/timeline_report_tools.js +0 -810
- package/mnemo/write_gate_risk.js +0 -80
- package/mnemo/writer_health.js +0 -152
- package/skills/doku-ingestion/SKILL.md +0 -48
- package/skills/doku-ingestion/ingest_docs.py +0 -133
|
@@ -1,1914 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const crypto = require("crypto");
|
|
4
|
-
const {
|
|
5
|
-
cleanScope,
|
|
6
|
-
compactContent,
|
|
7
|
-
freshnessFromAgeDays,
|
|
8
|
-
isoAgeDays,
|
|
9
|
-
jsonSafe,
|
|
10
|
-
normalizeAgentName,
|
|
11
|
-
parseMaybeJson,
|
|
12
|
-
uniqueStrings,
|
|
13
|
-
} = require("./shared_utils");
|
|
14
|
-
|
|
15
|
-
const DEFAULT_SCOPE = "default";
|
|
16
|
-
const PHASES = new Set(["light", "daily", "deep", "rem"]);
|
|
17
|
-
const DREAM_BUCKET_KEYS = ["wrong_made", "right_made", "praise_received", "called_out", "broke_things"];
|
|
18
|
-
|
|
19
|
-
function nowIso() {
|
|
20
|
-
return new Date().toISOString();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function sha(value) {
|
|
24
|
-
return crypto.createHash("sha256").update(String(value)).digest("hex");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function scopeName(scope) {
|
|
28
|
-
return cleanScope(scope || DEFAULT_SCOPE);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function normalizeDepartment(value) {
|
|
32
|
-
return String(value || "")
|
|
33
|
-
.trim()
|
|
34
|
-
.toLowerCase()
|
|
35
|
-
.replace(/[^a-z0-9._-]+/g, "-")
|
|
36
|
-
.replace(/^-+|-+$/g, "") || "general";
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function textOrNull(value, max = 8000) {
|
|
40
|
-
const compact = compactContent(value, max);
|
|
41
|
-
return compact && compact.trim() ? compact : null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function listInput(value) {
|
|
45
|
-
if (Array.isArray(value)) return uniqueStrings(value);
|
|
46
|
-
const parsed = parseMaybeJson(value, null);
|
|
47
|
-
if (Array.isArray(parsed)) return uniqueStrings(parsed);
|
|
48
|
-
return uniqueStrings(String(value || "").split(/[\n,;]+/).map((item) => item.trim()).filter(Boolean));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function clampInt(value, fallback, min, max) {
|
|
52
|
-
const n = parseInt(value, 10);
|
|
53
|
-
if (!Number.isFinite(n)) return fallback;
|
|
54
|
-
return Math.min(Math.max(n, min), max);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function tableExists(db, tableName) {
|
|
58
|
-
try {
|
|
59
|
-
return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type IN ('table','view') AND name=?").get(tableName);
|
|
60
|
-
} catch {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function tableColumns(db, tableName) {
|
|
66
|
-
try {
|
|
67
|
-
return db.prepare(`PRAGMA table_info(${tableName})`).all().map((col) => col.name);
|
|
68
|
-
} catch {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function hasColumn(db, tableName, columnName) {
|
|
74
|
-
return tableColumns(db, tableName).includes(columnName);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function safeJson(value, fallback) {
|
|
78
|
-
if (value === undefined) return JSON.stringify(fallback);
|
|
79
|
-
return jsonSafe(value, 30000) || JSON.stringify(fallback);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function parseJson(value, fallback) {
|
|
83
|
-
return parseMaybeJson(value, fallback);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function ensureMemoryLayerColumn(db) {
|
|
87
|
-
if (!tableExists(db, "memory")) return false;
|
|
88
|
-
const cols = tableColumns(db, "memory");
|
|
89
|
-
if (!cols.includes("layer")) {
|
|
90
|
-
try {
|
|
91
|
-
db.exec("ALTER TABLE memory ADD COLUMN layer TEXT");
|
|
92
|
-
} catch {}
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
db.exec("CREATE INDEX IF NOT EXISTS idx_memory_layer ON memory(layer)");
|
|
96
|
-
db.exec(`
|
|
97
|
-
UPDATE memory SET layer = CASE
|
|
98
|
-
WHEN kind IN ('tool_call','ssh_cmd','web_fetch','skill','skill_run') THEN 'procedural'
|
|
99
|
-
WHEN kind IN ('memory_md','decision','scar','manual','dream','reflection','memory_consolidation','company_fact_set') THEN 'semantic'
|
|
100
|
-
WHEN kind IN ('message','edit') THEN 'episodic'
|
|
101
|
-
ELSE 'episodic'
|
|
102
|
-
END
|
|
103
|
-
WHERE layer IS NULL OR layer = ''
|
|
104
|
-
`);
|
|
105
|
-
} catch {}
|
|
106
|
-
return hasColumn(db, "memory", "layer");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function ensureMemoryConsolidationSchema(db) {
|
|
110
|
-
ensureMemoryLayerColumn(db);
|
|
111
|
-
db.exec(`
|
|
112
|
-
CREATE TABLE IF NOT EXISTS daily_reflection (
|
|
113
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
114
|
-
reflection_date TEXT NOT NULL UNIQUE,
|
|
115
|
-
generated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
116
|
-
events_examined INTEGER NOT NULL DEFAULT 0,
|
|
117
|
-
corrections INTEGER NOT NULL DEFAULT 0,
|
|
118
|
-
praises INTEGER NOT NULL DEFAULT 0,
|
|
119
|
-
trait_diffs_json TEXT,
|
|
120
|
-
belief_diffs_json TEXT,
|
|
121
|
-
summary TEXT,
|
|
122
|
-
next_day_focus TEXT
|
|
123
|
-
);
|
|
124
|
-
CREATE INDEX IF NOT EXISTS idx_reflection_date ON daily_reflection(reflection_date);
|
|
125
|
-
|
|
126
|
-
CREATE TABLE IF NOT EXISTS cycle_event (
|
|
127
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
128
|
-
phase TEXT NOT NULL,
|
|
129
|
-
ran_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
130
|
-
window_from TEXT NOT NULL,
|
|
131
|
-
window_to TEXT NOT NULL,
|
|
132
|
-
inputs_count INTEGER NOT NULL DEFAULT 0,
|
|
133
|
-
promoted_count INTEGER NOT NULL DEFAULT 0,
|
|
134
|
-
summary TEXT,
|
|
135
|
-
delta_json TEXT
|
|
136
|
-
);
|
|
137
|
-
CREATE INDEX IF NOT EXISTS idx_cycle_phase ON cycle_event(phase);
|
|
138
|
-
CREATE INDEX IF NOT EXISTS idx_cycle_ran ON cycle_event(ran_at);
|
|
139
|
-
|
|
140
|
-
CREATE TABLE IF NOT EXISTS memory_consolidation_run (
|
|
141
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
142
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
143
|
-
agent_name TEXT,
|
|
144
|
-
project TEXT,
|
|
145
|
-
phase TEXT NOT NULL,
|
|
146
|
-
source_window_start TEXT NOT NULL,
|
|
147
|
-
source_window_end TEXT NOT NULL,
|
|
148
|
-
source_counts_json TEXT,
|
|
149
|
-
selected_refs_json TEXT,
|
|
150
|
-
summary TEXT NOT NULL,
|
|
151
|
-
promoted_memory_id INTEGER,
|
|
152
|
-
status TEXT NOT NULL DEFAULT 'draft',
|
|
153
|
-
confidence TEXT NOT NULL DEFAULT 'derived',
|
|
154
|
-
review_status TEXT NOT NULL DEFAULT 'draft',
|
|
155
|
-
meta_json TEXT,
|
|
156
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
157
|
-
);
|
|
158
|
-
CREATE INDEX IF NOT EXISTS idx_mem_consolidation_phase ON memory_consolidation_run(phase, created_at DESC);
|
|
159
|
-
CREATE INDEX IF NOT EXISTS idx_mem_consolidation_project ON memory_consolidation_run(project, created_at DESC);
|
|
160
|
-
CREATE INDEX IF NOT EXISTS idx_mem_consolidation_agent ON memory_consolidation_run(agent_name, created_at DESC);
|
|
161
|
-
|
|
162
|
-
CREATE TABLE IF NOT EXISTS department_journal (
|
|
163
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
164
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
165
|
-
department_name TEXT NOT NULL,
|
|
166
|
-
agent_name TEXT,
|
|
167
|
-
project TEXT,
|
|
168
|
-
journal_date TEXT NOT NULL,
|
|
169
|
-
progress TEXT,
|
|
170
|
-
blockers TEXT,
|
|
171
|
-
risks TEXT,
|
|
172
|
-
open_questions TEXT,
|
|
173
|
-
dependencies_json TEXT,
|
|
174
|
-
foreign_scope_requests_json TEXT,
|
|
175
|
-
status TEXT NOT NULL DEFAULT 'open',
|
|
176
|
-
meta_json TEXT,
|
|
177
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
178
|
-
);
|
|
179
|
-
CREATE INDEX IF NOT EXISTS idx_department_journal_dept ON department_journal(scope, department_name, journal_date DESC);
|
|
180
|
-
CREATE INDEX IF NOT EXISTS idx_department_journal_project ON department_journal(project, journal_date DESC);
|
|
181
|
-
CREATE INDEX IF NOT EXISTS idx_department_journal_agent ON department_journal(agent_name, journal_date DESC);
|
|
182
|
-
|
|
183
|
-
CREATE TABLE IF NOT EXISTS agent_sleep_note (
|
|
184
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
185
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
186
|
-
agent_name TEXT NOT NULL,
|
|
187
|
-
project TEXT,
|
|
188
|
-
note_date TEXT NOT NULL,
|
|
189
|
-
learned TEXT,
|
|
190
|
-
uncertainty TEXT,
|
|
191
|
-
recurring_errors TEXT,
|
|
192
|
-
needed_context TEXT,
|
|
193
|
-
improvement_idea TEXT,
|
|
194
|
-
source_ref TEXT,
|
|
195
|
-
status TEXT NOT NULL DEFAULT 'draft',
|
|
196
|
-
meta_json TEXT,
|
|
197
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
198
|
-
);
|
|
199
|
-
CREATE INDEX IF NOT EXISTS idx_agent_sleep_agent ON agent_sleep_note(scope, agent_name, note_date DESC);
|
|
200
|
-
CREATE INDEX IF NOT EXISTS idx_agent_sleep_project ON agent_sleep_note(project, note_date DESC);
|
|
201
|
-
|
|
202
|
-
CREATE TABLE IF NOT EXISTS memory_promotion_proposal (
|
|
203
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
204
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
205
|
-
proposal_kind TEXT NOT NULL,
|
|
206
|
-
title TEXT NOT NULL,
|
|
207
|
-
body TEXT,
|
|
208
|
-
project TEXT,
|
|
209
|
-
department_name TEXT,
|
|
210
|
-
agent_name TEXT,
|
|
211
|
-
source_kind TEXT,
|
|
212
|
-
source_id TEXT,
|
|
213
|
-
evidence_json TEXT,
|
|
214
|
-
status TEXT NOT NULL DEFAULT 'proposed',
|
|
215
|
-
reviewer TEXT,
|
|
216
|
-
review_notes TEXT,
|
|
217
|
-
promoted_ref_kind TEXT,
|
|
218
|
-
promoted_ref_id TEXT,
|
|
219
|
-
meta_json TEXT,
|
|
220
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
221
|
-
decided_at TEXT
|
|
222
|
-
);
|
|
223
|
-
CREATE INDEX IF NOT EXISTS idx_memory_promotion_status ON memory_promotion_proposal(scope, status, created_at DESC);
|
|
224
|
-
CREATE INDEX IF NOT EXISTS idx_memory_promotion_project ON memory_promotion_proposal(project, status, created_at DESC);
|
|
225
|
-
CREATE INDEX IF NOT EXISTS idx_memory_promotion_agent ON memory_promotion_proposal(agent_name, status, created_at DESC);
|
|
226
|
-
|
|
227
|
-
CREATE TABLE IF NOT EXISTS dreammode_run (
|
|
228
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
229
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
230
|
-
agent_name TEXT NOT NULL DEFAULT '',
|
|
231
|
-
project TEXT NOT NULL DEFAULT '',
|
|
232
|
-
dream_date TEXT NOT NULL,
|
|
233
|
-
source_window_start TEXT NOT NULL,
|
|
234
|
-
source_window_end TEXT NOT NULL,
|
|
235
|
-
messages_examined INTEGER NOT NULL DEFAULT 0,
|
|
236
|
-
actions_examined INTEGER NOT NULL DEFAULT 0,
|
|
237
|
-
events_examined INTEGER NOT NULL DEFAULT 0,
|
|
238
|
-
wrong_made_json TEXT,
|
|
239
|
-
right_made_json TEXT,
|
|
240
|
-
praise_received_json TEXT,
|
|
241
|
-
called_out_json TEXT,
|
|
242
|
-
broke_things_json TEXT,
|
|
243
|
-
lessons_json TEXT,
|
|
244
|
-
rem_run_ids_json TEXT,
|
|
245
|
-
summary TEXT NOT NULL,
|
|
246
|
-
brief_id INTEGER,
|
|
247
|
-
status TEXT NOT NULL DEFAULT 'draft',
|
|
248
|
-
meta_json TEXT,
|
|
249
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
250
|
-
UNIQUE(scope, agent_name, project, dream_date)
|
|
251
|
-
);
|
|
252
|
-
CREATE INDEX IF NOT EXISTS idx_dreammode_date ON dreammode_run(scope, dream_date DESC);
|
|
253
|
-
CREATE INDEX IF NOT EXISTS idx_dreammode_project ON dreammode_run(project, dream_date DESC);
|
|
254
|
-
CREATE INDEX IF NOT EXISTS idx_dreammode_agent ON dreammode_run(agent_name, dream_date DESC);
|
|
255
|
-
`);
|
|
256
|
-
try {
|
|
257
|
-
db.exec(`
|
|
258
|
-
CREATE TRIGGER IF NOT EXISTS mnemo_journal_memory_consolidation_ai AFTER INSERT ON memory_consolidation_run BEGIN
|
|
259
|
-
INSERT INTO mnemo_event_journal
|
|
260
|
-
(source, channel, direction, actor, event_kind, ref_kind, ref_id, status, content, payload_json, meta_json, occurred_at)
|
|
261
|
-
VALUES
|
|
262
|
-
('memory_consolidation', NEW.project, 'internal', NEW.agent_name, 'memory_consolidation_insert', 'memory_consolidation_run', CAST(NEW.id AS TEXT), NEW.status, NEW.summary, NEW.selected_refs_json, NEW.meta_json, NEW.created_at);
|
|
263
|
-
END;
|
|
264
|
-
CREATE TRIGGER IF NOT EXISTS mnemo_journal_department_journal_ai AFTER INSERT ON department_journal BEGIN
|
|
265
|
-
INSERT INTO mnemo_event_journal
|
|
266
|
-
(source, channel, direction, actor, event_kind, ref_kind, ref_id, status, content, payload_json, meta_json, occurred_at)
|
|
267
|
-
VALUES
|
|
268
|
-
('department_journal', NEW.project, 'internal', NEW.agent_name, 'department_journal_insert', 'department_journal', CAST(NEW.id AS TEXT), NEW.status, COALESCE(NEW.progress, NEW.blockers, NEW.risks, ''), NEW.dependencies_json, NEW.meta_json, NEW.created_at);
|
|
269
|
-
END;
|
|
270
|
-
CREATE TRIGGER IF NOT EXISTS mnemo_journal_agent_sleep_ai AFTER INSERT ON agent_sleep_note BEGIN
|
|
271
|
-
INSERT INTO mnemo_event_journal
|
|
272
|
-
(source, channel, direction, actor, event_kind, ref_kind, ref_id, status, content, payload_json, meta_json, occurred_at)
|
|
273
|
-
VALUES
|
|
274
|
-
('agent_sleep_note', NEW.project, 'internal', NEW.agent_name, 'agent_sleep_note_insert', 'agent_sleep_note', CAST(NEW.id AS TEXT), NEW.status, COALESCE(NEW.learned, NEW.uncertainty, NEW.recurring_errors, ''), NULL, NEW.meta_json, NEW.created_at);
|
|
275
|
-
END;
|
|
276
|
-
CREATE TRIGGER IF NOT EXISTS mnemo_journal_memory_promotion_ai AFTER INSERT ON memory_promotion_proposal BEGIN
|
|
277
|
-
INSERT INTO mnemo_event_journal
|
|
278
|
-
(source, channel, direction, actor, event_kind, ref_kind, ref_id, status, content, payload_json, meta_json, occurred_at)
|
|
279
|
-
VALUES
|
|
280
|
-
('memory_promotion_proposal', NEW.project, 'internal', NEW.agent_name, 'memory_promotion_proposal_insert', 'memory_promotion_proposal', CAST(NEW.id AS TEXT), NEW.status, NEW.title || CASE WHEN NEW.body IS NULL THEN '' ELSE ': ' || NEW.body END, NEW.evidence_json, NEW.meta_json, NEW.created_at);
|
|
281
|
-
END;
|
|
282
|
-
CREATE TRIGGER IF NOT EXISTS mnemo_journal_dreammode_ai AFTER INSERT ON dreammode_run BEGIN
|
|
283
|
-
INSERT INTO mnemo_event_journal
|
|
284
|
-
(source, channel, direction, actor, event_kind, ref_kind, ref_id, status, content, payload_json, meta_json, occurred_at)
|
|
285
|
-
VALUES
|
|
286
|
-
('dreammode', NEW.project, 'internal', NEW.agent_name, 'dreammode_run_insert', 'dreammode_run', CAST(NEW.id AS TEXT), NEW.status, NEW.summary, NEW.lessons_json, NEW.meta_json, NEW.created_at);
|
|
287
|
-
END;
|
|
288
|
-
`);
|
|
289
|
-
} catch {}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function whereProject(input, column = "topic") {
|
|
293
|
-
const project = String(input.project || "").trim();
|
|
294
|
-
if (!project) return { sql: "", params: [] };
|
|
295
|
-
return { sql: ` AND (COALESCE(${column}, '') = ? OR COALESCE(meta_json, '') LIKE ?)`, params: [project, `%${project}%`] };
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function countTable(db, tableName, whereSql = "", params = []) {
|
|
299
|
-
if (!tableExists(db, tableName)) return 0;
|
|
300
|
-
try {
|
|
301
|
-
return db.prepare(`SELECT COUNT(*) c FROM ${tableName}${whereSql}`).get(...params).c || 0;
|
|
302
|
-
} catch {
|
|
303
|
-
return 0;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
function latestRow(db, tableName, orderCol, whereSql = "", params = []) {
|
|
308
|
-
if (!tableExists(db, tableName)) return null;
|
|
309
|
-
try {
|
|
310
|
-
return db.prepare(`SELECT * FROM ${tableName}${whereSql} ORDER BY ${orderCol} DESC LIMIT 1`).get(...params) || null;
|
|
311
|
-
} catch {
|
|
312
|
-
return null;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function memoryLayerCounts(db, input = {}) {
|
|
317
|
-
if (!tableExists(db, "memory")) return [];
|
|
318
|
-
ensureMemoryLayerColumn(db);
|
|
319
|
-
const days = clampInt(input.days, 7, 1, 3650);
|
|
320
|
-
const since = input.since || new Date(Date.now() - days * 86400000).toISOString();
|
|
321
|
-
const project = whereProject(input, "topic");
|
|
322
|
-
try {
|
|
323
|
-
return db.prepare(`
|
|
324
|
-
SELECT COALESCE(layer, 'episodic') AS layer, kind, COUNT(*) AS count, MAX(occurred_at) AS last_at
|
|
325
|
-
FROM memory
|
|
326
|
-
WHERE occurred_at >= ?${project.sql}
|
|
327
|
-
GROUP BY COALESCE(layer, 'episodic'), kind
|
|
328
|
-
ORDER BY layer, count DESC
|
|
329
|
-
`).all(since, ...project.params);
|
|
330
|
-
} catch {
|
|
331
|
-
return [];
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function sourceCounts(db, input = {}) {
|
|
336
|
-
const days = clampInt(input.days, 7, 1, 3650);
|
|
337
|
-
const since = input.since || new Date(Date.now() - days * 86400000).toISOString();
|
|
338
|
-
const counts = {
|
|
339
|
-
since,
|
|
340
|
-
memory: 0,
|
|
341
|
-
transcript: 0,
|
|
342
|
-
capture_receipt: 0,
|
|
343
|
-
mnemo_event_journal: 0,
|
|
344
|
-
agent_action: 0,
|
|
345
|
-
session_handoff: 0,
|
|
346
|
-
decision_log: 0,
|
|
347
|
-
quality_finding: 0,
|
|
348
|
-
daily_reflection: 0,
|
|
349
|
-
cycle_event: 0,
|
|
350
|
-
runtime_tool_receipt: 0,
|
|
351
|
-
department_journal: 0,
|
|
352
|
-
agent_sleep_note: 0,
|
|
353
|
-
memory_promotion_proposal: 0,
|
|
354
|
-
};
|
|
355
|
-
if (tableExists(db, "memory")) {
|
|
356
|
-
const p = whereProject(input, "topic");
|
|
357
|
-
counts.memory = countTable(db, "memory", ` WHERE occurred_at >= ?${p.sql}`, [since, ...p.params]);
|
|
358
|
-
}
|
|
359
|
-
if (tableExists(db, "transcript")) counts.transcript = countTable(db, "transcript", " WHERE occurred_at >= ?", [since]);
|
|
360
|
-
if (tableExists(db, "capture_receipt")) counts.capture_receipt = countTable(db, "capture_receipt", " WHERE last_seen_at >= ?", [since]);
|
|
361
|
-
if (tableExists(db, "mnemo_event_journal")) counts.mnemo_event_journal = countTable(db, "mnemo_event_journal", " WHERE occurred_at >= ?", [since]);
|
|
362
|
-
if (tableExists(db, "agent_action")) counts.agent_action = countTable(db, "agent_action", " WHERE started_at >= ?", [since]);
|
|
363
|
-
if (tableExists(db, "session_handoff")) counts.session_handoff = countTable(db, "session_handoff", " WHERE created_at >= ?", [since]);
|
|
364
|
-
if (tableExists(db, "decision_log")) counts.decision_log = countTable(db, "decision_log", " WHERE decided_at >= ?", [since]);
|
|
365
|
-
if (tableExists(db, "quality_finding")) counts.quality_finding = countTable(db, "quality_finding", " WHERE created_at >= ?", [since]);
|
|
366
|
-
if (tableExists(db, "daily_reflection")) counts.daily_reflection = countTable(db, "daily_reflection", " WHERE generated_at >= ?", [since]);
|
|
367
|
-
if (tableExists(db, "cycle_event")) counts.cycle_event = countTable(db, "cycle_event", " WHERE ran_at >= ?", [since]);
|
|
368
|
-
if (tableExists(db, "runtime_tool_receipt")) counts.runtime_tool_receipt = countTable(db, "runtime_tool_receipt", " WHERE started_at >= ?", [since]);
|
|
369
|
-
if (tableExists(db, "department_journal")) counts.department_journal = countTable(db, "department_journal", " WHERE created_at >= ?", [since]);
|
|
370
|
-
if (tableExists(db, "agent_sleep_note")) counts.agent_sleep_note = countTable(db, "agent_sleep_note", " WHERE created_at >= ?", [since]);
|
|
371
|
-
if (tableExists(db, "memory_promotion_proposal")) counts.memory_promotion_proposal = countTable(db, "memory_promotion_proposal", " WHERE created_at >= ?", [since]);
|
|
372
|
-
return counts;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function canonicalMemoryModel() {
|
|
376
|
-
return {
|
|
377
|
-
authority: "mnemo",
|
|
378
|
-
rule: "External runtimes may collect or execute, but Mnemo owns durable truth, identity, claims, approvals, evidence, and memory promotion.",
|
|
379
|
-
layers: [
|
|
380
|
-
{ name: "company_ledger", mnemo_sources: ["decision_log", "work_claim", "approval_request", "runtime_tool_receipt", "session_handoff", "quality_finding", "project_rules"], purpose: "official company truth and audit trail" },
|
|
381
|
-
{ name: "department_journal", mnemo_sources: ["department_journal"], purpose: "department-level diary; explains work history but is not official truth until promoted" },
|
|
382
|
-
{ name: "agent_sleep_notes", mnemo_sources: ["agent_sleep_note"], purpose: "personal agent REM notes; never official truth until reviewed" },
|
|
383
|
-
{ name: "session", mnemo_sources: ["transcript", "capture_receipt", "agent_action", "memory:episodic"], purpose: "current conversation, tool steps, raw events" },
|
|
384
|
-
{ name: "daily", mnemo_sources: ["daily_reflection", "memory_consolidation_run:daily"], purpose: "day-level journal and correction/praise signal" },
|
|
385
|
-
{ name: "long_term", mnemo_sources: ["memory:semantic", "decision_log", "scar_event", "company facts"], purpose: "stable rules, decisions, scars, project facts" },
|
|
386
|
-
{ name: "recall", mnemo_sources: ["mem_recall", "mem_recall_layered", "memory_fts", "mnemo_search_fts"], purpose: "searchable retrieval, not a second store" },
|
|
387
|
-
{ name: "rem", mnemo_sources: ["cycle_event", "memory_consolidation_run:rem"], purpose: "background consolidation and pattern extraction" },
|
|
388
|
-
],
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
function latestDailyReflection(db) {
|
|
393
|
-
if (!tableExists(db, "daily_reflection")) return null;
|
|
394
|
-
const cols = tableColumns(db, "daily_reflection");
|
|
395
|
-
const dateCol = cols.includes("reflection_date") ? "reflection_date" : (cols.includes("date") ? "date" : null);
|
|
396
|
-
if (!dateCol) return null;
|
|
397
|
-
try {
|
|
398
|
-
return db.prepare(`SELECT * FROM daily_reflection ORDER BY ${dateCol} DESC, generated_at DESC LIMIT 1`).get() || null;
|
|
399
|
-
} catch {
|
|
400
|
-
return null;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
function latestConsolidationByPhase(db) {
|
|
405
|
-
const out = {};
|
|
406
|
-
if (!tableExists(db, "memory_consolidation_run")) return out;
|
|
407
|
-
for (const phase of PHASES) {
|
|
408
|
-
out[phase] = latestRow(db, "memory_consolidation_run", "created_at", " WHERE phase=?", [phase]);
|
|
409
|
-
}
|
|
410
|
-
return out;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function latestCycleByPhase(db) {
|
|
414
|
-
const out = {};
|
|
415
|
-
if (!tableExists(db, "cycle_event")) return out;
|
|
416
|
-
for (const phase of ["pulse", "settle", "arc"]) {
|
|
417
|
-
out[phase] = latestRow(db, "cycle_event", "ran_at", " WHERE phase=?", [phase]);
|
|
418
|
-
}
|
|
419
|
-
return out;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
function memoryLayerStatus(db, input = {}) {
|
|
423
|
-
ensureMemoryConsolidationSchema(db);
|
|
424
|
-
const days = clampInt(input.days, 7, 1, 3650);
|
|
425
|
-
const counts = sourceCounts(db, input);
|
|
426
|
-
const layers = memoryLayerCounts(db, input);
|
|
427
|
-
const latestDaily = latestDailyReflection(db);
|
|
428
|
-
const consolidation = latestConsolidationByPhase(db);
|
|
429
|
-
const cycles = latestCycleByPhase(db);
|
|
430
|
-
const latestRem = consolidation.rem || cycles.arc || null;
|
|
431
|
-
const warnings = [];
|
|
432
|
-
if (!counts.memory && !counts.transcript && !counts.mnemo_event_journal) warnings.push("no recent raw memory/session events in selected window");
|
|
433
|
-
if (!latestDaily) warnings.push("no daily_reflection row found yet");
|
|
434
|
-
if (!latestRem) warnings.push("no REM/arc consolidation found yet");
|
|
435
|
-
return {
|
|
436
|
-
ok: true,
|
|
437
|
-
checked_at: nowIso(),
|
|
438
|
-
scope: scopeName(input.scope),
|
|
439
|
-
agent_name: input.agent_name ? normalizeAgentName(input.agent_name) : null,
|
|
440
|
-
project: input.project || null,
|
|
441
|
-
days,
|
|
442
|
-
canonical_model: canonicalMemoryModel(),
|
|
443
|
-
source_counts: counts,
|
|
444
|
-
memory_layers: layers,
|
|
445
|
-
latest: {
|
|
446
|
-
daily_reflection: latestDaily,
|
|
447
|
-
consolidation,
|
|
448
|
-
cycle_event: cycles,
|
|
449
|
-
},
|
|
450
|
-
freshness: {
|
|
451
|
-
daily_reflection: freshnessFromAgeDays(isoAgeDays(latestDaily && (latestDaily.generated_at || latestDaily.reflection_date)), 2, 7),
|
|
452
|
-
rem: freshnessFromAgeDays(isoAgeDays(latestRem && (latestRem.created_at || latestRem.ran_at)), 7, 21),
|
|
453
|
-
},
|
|
454
|
-
warnings,
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
function phaseWindowDays(phase, inputDays) {
|
|
459
|
-
if (inputDays) return clampInt(inputDays, 1, 1, 3650);
|
|
460
|
-
if (phase === "light") return 1;
|
|
461
|
-
if (phase === "daily") return 1;
|
|
462
|
-
if (phase === "deep") return 3;
|
|
463
|
-
return 7;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
function memoryRemPlan(db, input = {}) {
|
|
467
|
-
ensureMemoryConsolidationSchema(db);
|
|
468
|
-
const status = memoryLayerStatus(db, input);
|
|
469
|
-
const today = (input.date || new Date().toISOString().slice(0, 10)).slice(0, 10);
|
|
470
|
-
const latest = status.latest.consolidation || {};
|
|
471
|
-
const counts = status.source_counts || {};
|
|
472
|
-
const phases = [];
|
|
473
|
-
const add = (phase, due, reason, run_hint) => phases.push({ phase, due, reason, run_hint });
|
|
474
|
-
const lightAge = isoAgeDays(latest.light && latest.light.created_at);
|
|
475
|
-
const dailyExists = tableExists(db, "daily_reflection")
|
|
476
|
-
? !!db.prepare("SELECT 1 FROM daily_reflection WHERE reflection_date=?").get(today)
|
|
477
|
-
: false;
|
|
478
|
-
const deepAge = isoAgeDays(latest.deep && latest.deep.created_at);
|
|
479
|
-
const remAge = isoAgeDays((latest.rem && latest.rem.created_at) || (status.latest.cycle_event.arc && status.latest.cycle_event.arc.ran_at));
|
|
480
|
-
|
|
481
|
-
add("light", (counts.transcript + counts.agent_action + counts.capture_receipt + counts.mnemo_event_journal) > 0 && (lightAge == null || lightAge >= 1),
|
|
482
|
-
"Collect the current working/session layer into a short reviewable summary.",
|
|
483
|
-
{ tool: "mem_memory_rem_run", args: { phase: "light", days: 1, agent_name: input.agent_name || undefined, project: input.project || undefined } });
|
|
484
|
-
add("daily", !dailyExists,
|
|
485
|
-
`Create or refresh daily reflection for ${today}.`,
|
|
486
|
-
{ tool: "mem_memory_rem_run", args: { phase: "daily", date: today, agent_name: input.agent_name || undefined, project: input.project || undefined } });
|
|
487
|
-
add("deep", (counts.memory + counts.session_handoff + counts.decision_log + counts.quality_finding) > 0 && (deepAge == null || deepAge >= 1),
|
|
488
|
-
"Promote durable decisions, handoffs, scars, and high-signal facts into semantic memory.",
|
|
489
|
-
{ tool: "mem_memory_rem_run", args: { phase: "deep", days: 3, agent_name: input.agent_name || undefined, project: input.project || undefined } });
|
|
490
|
-
add("rem", remAge == null || remAge >= 7,
|
|
491
|
-
"Weekly REM pass: extract cross-day patterns without deleting or overwriting old facts.",
|
|
492
|
-
{ tool: "mem_memory_rem_run", args: { phase: "rem", days: 7, agent_name: input.agent_name || undefined, project: input.project || undefined } });
|
|
493
|
-
|
|
494
|
-
return {
|
|
495
|
-
ok: true,
|
|
496
|
-
generated_at: nowIso(),
|
|
497
|
-
scope: scopeName(input.scope),
|
|
498
|
-
project: input.project || null,
|
|
499
|
-
agent_name: input.agent_name ? normalizeAgentName(input.agent_name) : null,
|
|
500
|
-
canonical_model: canonicalMemoryModel(),
|
|
501
|
-
phases,
|
|
502
|
-
next_due: phases.filter((p) => p.due),
|
|
503
|
-
status,
|
|
504
|
-
rule: "Run phases via Mnemo tools only. Runtimes may feed raw events, but promotion and long-term truth stay in Mnemo.",
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
function getRows(db, tableName, sql, params = []) {
|
|
509
|
-
if (!tableExists(db, tableName)) return [];
|
|
510
|
-
try {
|
|
511
|
-
return db.prepare(sql).all(...params);
|
|
512
|
-
} catch {
|
|
513
|
-
return [];
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
function selectMemoryRows(db, input, since, limit) {
|
|
518
|
-
if (!tableExists(db, "memory")) return [];
|
|
519
|
-
const p = whereProject(input, "topic");
|
|
520
|
-
const agent = input.agent_name ? normalizeAgentName(input.agent_name) : "";
|
|
521
|
-
const where = [`occurred_at >= ?${p.sql}`];
|
|
522
|
-
const params = [since, ...p.params];
|
|
523
|
-
if (agent) {
|
|
524
|
-
where.push("(LOWER(COALESCE(actor,''))=? OR COALESCE(meta_json,'') LIKE ?)");
|
|
525
|
-
params.push(agent, `%${agent}%`);
|
|
526
|
-
}
|
|
527
|
-
params.push(limit);
|
|
528
|
-
return getRows(db, "memory", `
|
|
529
|
-
SELECT 'memory' AS ref_kind, CAST(id AS TEXT) AS ref_id, kind AS subtype, actor, topic, occurred_at AS at,
|
|
530
|
-
importance, substr(text,1,700) AS preview
|
|
531
|
-
FROM memory
|
|
532
|
-
WHERE ${where.join(" AND ")}
|
|
533
|
-
ORDER BY importance DESC, occurred_at DESC
|
|
534
|
-
LIMIT ?
|
|
535
|
-
`, params);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
function selectHandoffRows(db, input, since, limit) {
|
|
539
|
-
if (!tableExists(db, "session_handoff")) return [];
|
|
540
|
-
const where = ["created_at >= ?"];
|
|
541
|
-
const params = [since];
|
|
542
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
543
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
544
|
-
params.push(limit);
|
|
545
|
-
return getRows(db, "session_handoff", `
|
|
546
|
-
SELECT 'session_handoff' AS ref_kind, CAST(id AS TEXT) AS ref_id, 'handoff' AS subtype, agent_name AS actor,
|
|
547
|
-
project AS topic, created_at AS at, 8 AS importance, substr(summary,1,700) AS preview
|
|
548
|
-
FROM session_handoff
|
|
549
|
-
WHERE ${where.join(" AND ")}
|
|
550
|
-
ORDER BY created_at DESC
|
|
551
|
-
LIMIT ?
|
|
552
|
-
`, params);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
function selectDecisionRows(db, input, since, limit) {
|
|
556
|
-
if (!tableExists(db, "decision_log")) return [];
|
|
557
|
-
const where = ["decided_at >= ?"];
|
|
558
|
-
const params = [since];
|
|
559
|
-
if (input.scope) { where.push("scope=?"); params.push(scopeName(input.scope)); }
|
|
560
|
-
if (input.project) { where.push("(body LIKE ? OR title LIKE ? OR files_affected LIKE ? OR entities_affected LIKE ?)"); params.push(`%${input.project}%`, `%${input.project}%`, `%${input.project}%`, `%${input.project}%`); }
|
|
561
|
-
params.push(limit);
|
|
562
|
-
return getRows(db, "decision_log", `
|
|
563
|
-
SELECT 'decision_log' AS ref_kind, CAST(id AS TEXT) AS ref_id, 'decision' AS subtype, decided_by AS actor,
|
|
564
|
-
scope AS topic, decided_at AS at, 9 AS importance, substr(title || ': ' || COALESCE(body,''),1,700) AS preview
|
|
565
|
-
FROM decision_log
|
|
566
|
-
WHERE ${where.join(" AND ")}
|
|
567
|
-
ORDER BY decided_at DESC
|
|
568
|
-
LIMIT ?
|
|
569
|
-
`, params);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
function selectFindingRows(db, input, since, limit) {
|
|
573
|
-
if (!tableExists(db, "quality_finding")) return [];
|
|
574
|
-
const where = ["created_at >= ?"];
|
|
575
|
-
const params = [since];
|
|
576
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
577
|
-
params.push(limit);
|
|
578
|
-
return getRows(db, "quality_finding", `
|
|
579
|
-
SELECT 'quality_finding' AS ref_kind, CAST(id AS TEXT) AS ref_id, category AS subtype, source_agent AS actor,
|
|
580
|
-
project AS topic, created_at AS at,
|
|
581
|
-
CASE severity WHEN 'H' THEN 9 WHEN 'M' THEN 7 ELSE 5 END AS importance,
|
|
582
|
-
substr(title || CASE WHEN actual IS NULL THEN '' ELSE ' actual=' || actual END,1,700) AS preview
|
|
583
|
-
FROM quality_finding
|
|
584
|
-
WHERE ${where.join(" AND ")}
|
|
585
|
-
ORDER BY CASE severity WHEN 'H' THEN 3 WHEN 'M' THEN 2 ELSE 1 END DESC, created_at DESC
|
|
586
|
-
LIMIT ?
|
|
587
|
-
`, params);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
function selectActionRows(db, input, since, limit) {
|
|
591
|
-
if (!tableExists(db, "agent_action")) return [];
|
|
592
|
-
const where = ["started_at >= ?"];
|
|
593
|
-
const params = [since];
|
|
594
|
-
if (input.project) { where.push("topic=?"); params.push(input.project); }
|
|
595
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
596
|
-
params.push(limit);
|
|
597
|
-
return getRows(db, "agent_action", `
|
|
598
|
-
SELECT 'agent_action' AS ref_kind, CAST(id AS TEXT) AS ref_id, COALESCE(action_kind,'action') AS subtype, agent_name AS actor,
|
|
599
|
-
topic, started_at AS at, 5 AS importance,
|
|
600
|
-
substr(COALESCE(action_kind,'action') || ' ' || COALESCE(target,'') || ' status=' || COALESCE(status,''),1,700) AS preview
|
|
601
|
-
FROM agent_action
|
|
602
|
-
WHERE ${where.join(" AND ")}
|
|
603
|
-
ORDER BY started_at DESC
|
|
604
|
-
LIMIT ?
|
|
605
|
-
`, params);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
function selectJournalRows(db, input, since, limit) {
|
|
609
|
-
if (!tableExists(db, "mnemo_event_journal")) return [];
|
|
610
|
-
const where = ["occurred_at >= ?"];
|
|
611
|
-
const params = [since];
|
|
612
|
-
if (input.project) { where.push("(channel=? OR content LIKE ? OR payload_json LIKE ? OR meta_json LIKE ?)"); params.push(input.project, `%${input.project}%`, `%${input.project}%`, `%${input.project}%`); }
|
|
613
|
-
if (input.agent_name) { where.push("LOWER(COALESCE(actor,''))=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
614
|
-
params.push(limit);
|
|
615
|
-
return getRows(db, "mnemo_event_journal", `
|
|
616
|
-
SELECT 'mnemo_event_journal' AS ref_kind, CAST(id AS TEXT) AS ref_id, event_kind AS subtype, actor,
|
|
617
|
-
channel AS topic, occurred_at AS at, 4 AS importance, substr(COALESCE(content,''),1,700) AS preview
|
|
618
|
-
FROM mnemo_event_journal
|
|
619
|
-
WHERE ${where.join(" AND ")}
|
|
620
|
-
ORDER BY occurred_at DESC
|
|
621
|
-
LIMIT ?
|
|
622
|
-
`, params);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
function selectDailyReflection(db, input, since, limit) {
|
|
626
|
-
if (!tableExists(db, "daily_reflection")) return [];
|
|
627
|
-
const cols = tableColumns(db, "daily_reflection");
|
|
628
|
-
const dateCol = cols.includes("reflection_date") ? "reflection_date" : (cols.includes("date") ? "date" : null);
|
|
629
|
-
if (!dateCol) return [];
|
|
630
|
-
return getRows(db, "daily_reflection", `
|
|
631
|
-
SELECT 'daily_reflection' AS ref_kind, CAST(id AS TEXT) AS ref_id, 'daily' AS subtype, 'mnemo' AS actor,
|
|
632
|
-
${dateCol} AS topic, generated_at AS at, 7 AS importance, substr(COALESCE(summary,''),1,700) AS preview
|
|
633
|
-
FROM daily_reflection
|
|
634
|
-
WHERE generated_at >= ?
|
|
635
|
-
ORDER BY ${dateCol} DESC
|
|
636
|
-
LIMIT ?
|
|
637
|
-
`, [since, limit]);
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
function selectDepartmentJournalRows(db, input, since, limit) {
|
|
641
|
-
if (!tableExists(db, "department_journal")) return [];
|
|
642
|
-
const where = ["created_at >= ?"];
|
|
643
|
-
const params = [since];
|
|
644
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
645
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
646
|
-
if (input.department_name) { where.push("department_name=?"); params.push(normalizeDepartment(input.department_name)); }
|
|
647
|
-
params.push(limit);
|
|
648
|
-
return getRows(db, "department_journal", `
|
|
649
|
-
SELECT 'department_journal' AS ref_kind, CAST(id AS TEXT) AS ref_id, department_name AS subtype, agent_name AS actor,
|
|
650
|
-
project AS topic, created_at AS at, 7 AS importance,
|
|
651
|
-
substr('progress=' || COALESCE(progress,'') || ' blockers=' || COALESCE(blockers,'') || ' risks=' || COALESCE(risks,''),1,700) AS preview
|
|
652
|
-
FROM department_journal
|
|
653
|
-
WHERE ${where.join(" AND ")}
|
|
654
|
-
ORDER BY journal_date DESC, created_at DESC
|
|
655
|
-
LIMIT ?
|
|
656
|
-
`, params);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
function selectAgentSleepRows(db, input, since, limit) {
|
|
660
|
-
if (!tableExists(db, "agent_sleep_note")) return [];
|
|
661
|
-
const where = ["created_at >= ?"];
|
|
662
|
-
const params = [since];
|
|
663
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
664
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
665
|
-
params.push(limit);
|
|
666
|
-
return getRows(db, "agent_sleep_note", `
|
|
667
|
-
SELECT 'agent_sleep_note' AS ref_kind, CAST(id AS TEXT) AS ref_id, status AS subtype, agent_name AS actor,
|
|
668
|
-
project AS topic, created_at AS at, 6 AS importance,
|
|
669
|
-
substr('learned=' || COALESCE(learned,'') || ' uncertainty=' || COALESCE(uncertainty,'') || ' recurring=' || COALESCE(recurring_errors,''),1,700) AS preview
|
|
670
|
-
FROM agent_sleep_note
|
|
671
|
-
WHERE ${where.join(" AND ")}
|
|
672
|
-
ORDER BY note_date DESC, created_at DESC
|
|
673
|
-
LIMIT ?
|
|
674
|
-
`, params);
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
function selectPromotionRows(db, input, since, limit) {
|
|
678
|
-
if (!tableExists(db, "memory_promotion_proposal")) return [];
|
|
679
|
-
const where = ["created_at >= ?"];
|
|
680
|
-
const params = [since];
|
|
681
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
682
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
683
|
-
if (input.department_name) { where.push("department_name=?"); params.push(normalizeDepartment(input.department_name)); }
|
|
684
|
-
params.push(limit);
|
|
685
|
-
return getRows(db, "memory_promotion_proposal", `
|
|
686
|
-
SELECT 'memory_promotion_proposal' AS ref_kind, CAST(id AS TEXT) AS ref_id, proposal_kind AS subtype, agent_name AS actor,
|
|
687
|
-
project AS topic, created_at AS at, CASE status WHEN 'proposed' THEN 8 ELSE 6 END AS importance,
|
|
688
|
-
substr(status || ' ' || title || CASE WHEN body IS NULL THEN '' ELSE ': ' || body END,1,700) AS preview
|
|
689
|
-
FROM memory_promotion_proposal
|
|
690
|
-
WHERE ${where.join(" AND ")}
|
|
691
|
-
ORDER BY CASE status WHEN 'proposed' THEN 2 ELSE 1 END DESC, created_at DESC
|
|
692
|
-
LIMIT ?
|
|
693
|
-
`, params);
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
function selectRowsForPhase(db, phase, input = {}) {
|
|
697
|
-
const days = phaseWindowDays(phase, input.days);
|
|
698
|
-
const since = input.since || new Date(Date.now() - days * 86400000).toISOString();
|
|
699
|
-
const limit = clampInt(input.limit, 60, 5, 300);
|
|
700
|
-
let rows = [];
|
|
701
|
-
if (phase === "light") {
|
|
702
|
-
rows = rows.concat(selectActionRows(db, input, since, Math.ceil(limit / 3)));
|
|
703
|
-
rows = rows.concat(selectJournalRows(db, input, since, Math.ceil(limit / 3)));
|
|
704
|
-
rows = rows.concat(selectMemoryRows(db, input, since, Math.ceil(limit / 3)));
|
|
705
|
-
} else if (phase === "daily") {
|
|
706
|
-
rows = rows.concat(selectMemoryRows(db, input, since, Math.ceil(limit / 2)));
|
|
707
|
-
rows = rows.concat(selectHandoffRows(db, input, since, Math.ceil(limit / 4)));
|
|
708
|
-
rows = rows.concat(selectFindingRows(db, input, since, Math.ceil(limit / 4)));
|
|
709
|
-
rows = rows.concat(selectDepartmentJournalRows(db, input, since, Math.ceil(limit / 4)));
|
|
710
|
-
rows = rows.concat(selectAgentSleepRows(db, input, since, Math.ceil(limit / 4)));
|
|
711
|
-
} else if (phase === "deep") {
|
|
712
|
-
rows = rows.concat(selectDecisionRows(db, input, since, Math.ceil(limit / 4)));
|
|
713
|
-
rows = rows.concat(selectHandoffRows(db, input, since, Math.ceil(limit / 4)));
|
|
714
|
-
rows = rows.concat(selectFindingRows(db, input, since, Math.ceil(limit / 4)));
|
|
715
|
-
rows = rows.concat(selectMemoryRows(db, input, since, Math.ceil(limit / 4)));
|
|
716
|
-
rows = rows.concat(selectPromotionRows(db, input, since, Math.ceil(limit / 4)));
|
|
717
|
-
} else {
|
|
718
|
-
rows = rows.concat(selectDailyReflection(db, input, since, Math.ceil(limit / 4)));
|
|
719
|
-
rows = rows.concat(selectDepartmentJournalRows(db, input, since, Math.ceil(limit / 4)));
|
|
720
|
-
rows = rows.concat(selectAgentSleepRows(db, input, since, Math.ceil(limit / 4)));
|
|
721
|
-
rows = rows.concat(selectPromotionRows(db, input, since, Math.ceil(limit / 4)));
|
|
722
|
-
rows = rows.concat(selectDecisionRows(db, input, since, Math.ceil(limit / 4)));
|
|
723
|
-
rows = rows.concat(selectHandoffRows(db, input, since, Math.ceil(limit / 4)));
|
|
724
|
-
rows = rows.concat(selectFindingRows(db, input, since, Math.ceil(limit / 4)));
|
|
725
|
-
rows = rows.concat(selectMemoryRows(db, input, since, Math.ceil(limit / 4)));
|
|
726
|
-
}
|
|
727
|
-
const dedup = [];
|
|
728
|
-
const seen = new Set();
|
|
729
|
-
for (const row of rows) {
|
|
730
|
-
const key = `${row.ref_kind}:${row.ref_id}`;
|
|
731
|
-
if (seen.has(key)) continue;
|
|
732
|
-
seen.add(key);
|
|
733
|
-
dedup.push(row);
|
|
734
|
-
}
|
|
735
|
-
dedup.sort((a, b) => (b.importance - a.importance) || String(b.at || "").localeCompare(String(a.at || "")));
|
|
736
|
-
return { since, until: nowIso(), rows: dedup.slice(0, limit) };
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
function groupRows(rows) {
|
|
740
|
-
const groups = {
|
|
741
|
-
decisions: [],
|
|
742
|
-
handoffs: [],
|
|
743
|
-
findings: [],
|
|
744
|
-
actions: [],
|
|
745
|
-
memories: [],
|
|
746
|
-
reflections: [],
|
|
747
|
-
department_journals: [],
|
|
748
|
-
sleep_notes: [],
|
|
749
|
-
promotions: [],
|
|
750
|
-
events: [],
|
|
751
|
-
};
|
|
752
|
-
for (const row of rows) {
|
|
753
|
-
if (row.ref_kind === "decision_log" || row.subtype === "decision") groups.decisions.push(row);
|
|
754
|
-
else if (row.ref_kind === "session_handoff") groups.handoffs.push(row);
|
|
755
|
-
else if (row.ref_kind === "quality_finding") groups.findings.push(row);
|
|
756
|
-
else if (row.ref_kind === "agent_action") groups.actions.push(row);
|
|
757
|
-
else if (row.ref_kind === "daily_reflection") groups.reflections.push(row);
|
|
758
|
-
else if (row.ref_kind === "department_journal") groups.department_journals.push(row);
|
|
759
|
-
else if (row.ref_kind === "agent_sleep_note") groups.sleep_notes.push(row);
|
|
760
|
-
else if (row.ref_kind === "memory_promotion_proposal") groups.promotions.push(row);
|
|
761
|
-
else if (row.ref_kind === "mnemo_event_journal") groups.events.push(row);
|
|
762
|
-
else groups.memories.push(row);
|
|
763
|
-
}
|
|
764
|
-
return groups;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
function bulletRows(rows, maxRows) {
|
|
768
|
-
return rows.slice(0, maxRows).map((row) => {
|
|
769
|
-
const who = row.actor ? ` ${row.actor}` : "";
|
|
770
|
-
const topic = row.topic ? ` [${row.topic}]` : "";
|
|
771
|
-
return `- ${row.ref_kind}:${row.ref_id}${topic}${who}: ${compactContent(row.preview, 240) || "(empty)"}`;
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
function buildSummary(phase, input, selection, counts) {
|
|
776
|
-
const rows = selection.rows || [];
|
|
777
|
-
const groups = groupRows(rows);
|
|
778
|
-
const lines = [];
|
|
779
|
-
lines.push(`# Memory consolidation: ${phase}`);
|
|
780
|
-
lines.push("");
|
|
781
|
-
lines.push(`Scope: ${scopeName(input.scope)}${input.project ? ` | project: ${input.project}` : ""}${input.agent_name ? ` | agent: ${normalizeAgentName(input.agent_name)}` : ""}`);
|
|
782
|
-
lines.push(`Window: ${selection.since} -> ${selection.until}`);
|
|
783
|
-
lines.push(`Sources examined: memory=${counts.memory || 0}, transcript=${counts.transcript || 0}, actions=${counts.agent_action || 0}, handoffs=${counts.session_handoff || 0}, findings=${counts.quality_finding || 0}, events=${counts.mnemo_event_journal || 0}`);
|
|
784
|
-
lines.push("");
|
|
785
|
-
if (phase === "light") lines.push("Purpose: compress recent working/session events into a reviewable note. This is not canonical truth by itself.");
|
|
786
|
-
if (phase === "daily") lines.push("Purpose: create the day journal layer and surface corrections, blockers, handoffs, and durable decisions.");
|
|
787
|
-
if (phase === "deep") lines.push("Purpose: promote high-signal operational facts into semantic long-term memory candidates.");
|
|
788
|
-
if (phase === "rem") lines.push("Purpose: weekly REM pass over daily/deep material to reveal recurring patterns and weak governance rules.");
|
|
789
|
-
lines.push("");
|
|
790
|
-
const sections = [
|
|
791
|
-
["Decisions", groups.decisions, 6],
|
|
792
|
-
["Handoffs", groups.handoffs, 6],
|
|
793
|
-
["Findings", groups.findings, 6],
|
|
794
|
-
["Department journals", groups.department_journals, 6],
|
|
795
|
-
["Agent sleep notes", groups.sleep_notes, 6],
|
|
796
|
-
["Promotion proposals", groups.promotions, 8],
|
|
797
|
-
["Reflections", groups.reflections, 4],
|
|
798
|
-
["Actions", groups.actions, 6],
|
|
799
|
-
["Memory/events", groups.memories.concat(groups.events), 10],
|
|
800
|
-
];
|
|
801
|
-
for (const [title, values, maxRows] of sections) {
|
|
802
|
-
if (!values.length) continue;
|
|
803
|
-
lines.push(`## ${title}`);
|
|
804
|
-
lines.push(...bulletRows(values, maxRows));
|
|
805
|
-
lines.push("");
|
|
806
|
-
}
|
|
807
|
-
if (rows.length === 0) {
|
|
808
|
-
lines.push("No source rows matched this consolidation window.");
|
|
809
|
-
lines.push("");
|
|
810
|
-
}
|
|
811
|
-
lines.push("Review status: draft. A human or assigned agent may promote concrete lines into project truth, rules, scars, or runbooks.");
|
|
812
|
-
return compactContent(lines.join("\n"), 12000);
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
function runDailyReflection(db, input = {}, selection) {
|
|
816
|
-
const date = (input.date || new Date().toISOString().slice(0, 10)).slice(0, 10);
|
|
817
|
-
const fromTs = date + "T00:00:00Z";
|
|
818
|
-
const toTs = date + "T23:59:59Z";
|
|
819
|
-
const events = tableExists(db, "memory")
|
|
820
|
-
? db.prepare("SELECT actor, text FROM memory WHERE kind='message' AND occurred_at BETWEEN ? AND ? ORDER BY occurred_at ASC").all(fromTs, toTs)
|
|
821
|
-
: [];
|
|
822
|
-
let corrections = 0;
|
|
823
|
-
let praises = 0;
|
|
824
|
-
const correctionPatterns = /\b(nicht so|nein|stop|hor auf|hoer auf|falsch|kein|fantasi|verarscht|kacke|scheisse|scheisse|kaputt|broken)\b/i;
|
|
825
|
-
const praisePatterns = /\b(geil|super|perfekt|top|stark|hammer|well done|great)\b/i;
|
|
826
|
-
const owner = String(process.env.MNEMO_OWNER_NAME || "owner").toLowerCase();
|
|
827
|
-
for (const event of events) {
|
|
828
|
-
const actor = String(event.actor || "").toLowerCase();
|
|
829
|
-
if (actor && actor !== owner && actor !== "owner") continue;
|
|
830
|
-
if (correctionPatterns.test(event.text || "")) corrections++;
|
|
831
|
-
if (praisePatterns.test(event.text || "")) praises++;
|
|
832
|
-
}
|
|
833
|
-
const summary = `${events.length} message rows, ${corrections} corrections, ${praises} praises on ${date}. Consolidation selected ${selection.rows.length} durable source rows.`;
|
|
834
|
-
db.prepare(`
|
|
835
|
-
INSERT INTO daily_reflection (reflection_date, events_examined, corrections, praises, summary, trait_diffs_json, belief_diffs_json)
|
|
836
|
-
VALUES (?,?,?,?,?,?,?)
|
|
837
|
-
ON CONFLICT(reflection_date) DO UPDATE SET
|
|
838
|
-
events_examined=excluded.events_examined,
|
|
839
|
-
corrections=excluded.corrections,
|
|
840
|
-
praises=excluded.praises,
|
|
841
|
-
summary=excluded.summary,
|
|
842
|
-
generated_at=strftime('%Y-%m-%dT%H:%M:%fZ','now')
|
|
843
|
-
`).run(date, events.length, corrections, praises, summary, "{}", "{}");
|
|
844
|
-
return { date, events_examined: events.length, corrections, praises, summary };
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
function foldSignalText(value) {
|
|
848
|
-
return String(value || "")
|
|
849
|
-
.toLowerCase()
|
|
850
|
-
.normalize("NFKD")
|
|
851
|
-
.replace(/[\u0300-\u036f]/g, "")
|
|
852
|
-
.replace(/\u00df/g, "ss");
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
function dreamDateWindow(input = {}) {
|
|
856
|
-
const date = (input.dream_date || input.date || new Date().toISOString().slice(0, 10)).slice(0, 10);
|
|
857
|
-
const since = input.since || `${date}T00:00:00Z`;
|
|
858
|
-
const until = input.until || `${date}T23:59:59Z`;
|
|
859
|
-
return { date, since, until };
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
function selectDreamRows(db, input = {}) {
|
|
863
|
-
const win = dreamDateWindow(input);
|
|
864
|
-
const limit = clampInt(input.limit, 800, 20, 5000);
|
|
865
|
-
const project = String(input.project || "").trim();
|
|
866
|
-
const agent = input.agent_name ? normalizeAgentName(input.agent_name) : "";
|
|
867
|
-
const feedbackActors = uniqueStrings(["owner", "owner-channel", process.env.MNEMO_OWNER_NAME || "owner"]).map(normalizeAgentName);
|
|
868
|
-
const rows = [];
|
|
869
|
-
const pushRows = (values) => {
|
|
870
|
-
for (const row of values || []) {
|
|
871
|
-
rows.push(Object.assign({ status: null }, row));
|
|
872
|
-
if (rows.length >= limit * 2) break;
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
|
|
876
|
-
if (tableExists(db, "memory")) {
|
|
877
|
-
const where = ["occurred_at BETWEEN ? AND ?"];
|
|
878
|
-
const params = [win.since, win.until];
|
|
879
|
-
if (project) {
|
|
880
|
-
where.push("(COALESCE(topic,'')=? OR COALESCE(text,'') LIKE ? OR COALESCE(meta_json,'') LIKE ?)");
|
|
881
|
-
params.push(project, `%${project}%`, `%${project}%`);
|
|
882
|
-
}
|
|
883
|
-
if (agent) {
|
|
884
|
-
const ownerPlaceholders = feedbackActors.map(() => "?").join(",");
|
|
885
|
-
where.push(`(LOWER(COALESCE(actor,''))=? OR LOWER(COALESCE(actor,'')) IN (${ownerPlaceholders}) OR COALESCE(meta_json,'') LIKE ?)`);
|
|
886
|
-
params.push(agent, ...feedbackActors, `%${agent}%`);
|
|
887
|
-
}
|
|
888
|
-
params.push(limit);
|
|
889
|
-
pushRows(getRows(db, "memory", `
|
|
890
|
-
SELECT 'memory' AS ref_kind, CAST(id AS TEXT) AS ref_id, kind AS subtype, actor,
|
|
891
|
-
topic, occurred_at AS at, NULL AS status, importance,
|
|
892
|
-
substr(COALESCE(text,''),1,1200) AS preview
|
|
893
|
-
FROM memory
|
|
894
|
-
WHERE ${where.join(" AND ")}
|
|
895
|
-
ORDER BY occurred_at ASC
|
|
896
|
-
LIMIT ?
|
|
897
|
-
`, params));
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
if (tableExists(db, "mnemo_event_journal")) {
|
|
901
|
-
const where = ["occurred_at BETWEEN ? AND ?"];
|
|
902
|
-
const params = [win.since, win.until];
|
|
903
|
-
if (project) {
|
|
904
|
-
where.push("(COALESCE(channel,'')=? OR COALESCE(content,'') LIKE ? OR COALESCE(payload_json,'') LIKE ? OR COALESCE(meta_json,'') LIKE ?)");
|
|
905
|
-
params.push(project, `%${project}%`, `%${project}%`, `%${project}%`);
|
|
906
|
-
}
|
|
907
|
-
if (agent) {
|
|
908
|
-
const ownerPlaceholders = feedbackActors.map(() => "?").join(",");
|
|
909
|
-
where.push(`(LOWER(COALESCE(actor,''))=? OR LOWER(COALESCE(actor,'')) IN (${ownerPlaceholders}) OR COALESCE(meta_json,'') LIKE ?)`);
|
|
910
|
-
params.push(agent, ...feedbackActors, `%${agent}%`);
|
|
911
|
-
}
|
|
912
|
-
params.push(limit);
|
|
913
|
-
pushRows(getRows(db, "mnemo_event_journal", `
|
|
914
|
-
SELECT 'mnemo_event_journal' AS ref_kind, CAST(id AS TEXT) AS ref_id, event_kind AS subtype, actor,
|
|
915
|
-
channel AS topic, occurred_at AS at, status, 4 AS importance,
|
|
916
|
-
substr(COALESCE(content,'') || ' ' || COALESCE(payload_json,'') || ' ' || COALESCE(meta_json,''),1,1200) AS preview
|
|
917
|
-
FROM mnemo_event_journal
|
|
918
|
-
WHERE ${where.join(" AND ")}
|
|
919
|
-
ORDER BY occurred_at ASC
|
|
920
|
-
LIMIT ?
|
|
921
|
-
`, params));
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
if (tableExists(db, "agent_action")) {
|
|
925
|
-
const where = ["started_at BETWEEN ? AND ?"];
|
|
926
|
-
const params = [win.since, win.until];
|
|
927
|
-
if (project) {
|
|
928
|
-
where.push("(COALESCE(topic,'')=? OR COALESCE(payload_json,'') LIKE ? OR COALESCE(meta_json,'') LIKE ?)");
|
|
929
|
-
params.push(project, `%${project}%`, `%${project}%`);
|
|
930
|
-
}
|
|
931
|
-
if (agent) {
|
|
932
|
-
where.push("LOWER(COALESCE(agent_name,''))=?");
|
|
933
|
-
params.push(agent);
|
|
934
|
-
}
|
|
935
|
-
params.push(limit);
|
|
936
|
-
pushRows(getRows(db, "agent_action", `
|
|
937
|
-
SELECT 'agent_action' AS ref_kind, CAST(id AS TEXT) AS ref_id, action_kind AS subtype, agent_name AS actor,
|
|
938
|
-
topic, started_at AS at, status, 5 AS importance,
|
|
939
|
-
substr(COALESCE(action_kind,'') || ' ' || COALESCE(target,'') || ' status=' || COALESCE(status,'') || ' ' || COALESCE(result_json,'') || ' ' || COALESCE(payload_json,''),1,1200) AS preview
|
|
940
|
-
FROM agent_action
|
|
941
|
-
WHERE ${where.join(" AND ")}
|
|
942
|
-
ORDER BY started_at ASC
|
|
943
|
-
LIMIT ?
|
|
944
|
-
`, params));
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
if (tableExists(db, "quality_finding")) {
|
|
948
|
-
const where = ["created_at BETWEEN ? AND ?"];
|
|
949
|
-
const params = [win.since, win.until];
|
|
950
|
-
const qcols = tableColumns(db, "quality_finding");
|
|
951
|
-
const hasAssigned = qcols.includes("assigned_agent");
|
|
952
|
-
if (project) { where.push("project=?"); params.push(project); }
|
|
953
|
-
if (agent) {
|
|
954
|
-
where.push(hasAssigned ? "(LOWER(COALESCE(source_agent,''))=? OR LOWER(COALESCE(assigned_agent,''))=?)" : "LOWER(COALESCE(source_agent,''))=?");
|
|
955
|
-
params.push(agent);
|
|
956
|
-
if (hasAssigned) params.push(agent);
|
|
957
|
-
}
|
|
958
|
-
params.push(limit);
|
|
959
|
-
const actorExpr = hasAssigned ? "COALESCE(source_agent, assigned_agent)" : "source_agent";
|
|
960
|
-
pushRows(getRows(db, "quality_finding", `
|
|
961
|
-
SELECT 'quality_finding' AS ref_kind, CAST(id AS TEXT) AS ref_id, category AS subtype, ${actorExpr} AS actor,
|
|
962
|
-
project AS topic, created_at AS at, COALESCE(status,'open') AS status, 8 AS importance,
|
|
963
|
-
substr(COALESCE(severity,'') || ' ' || COALESCE(title,'') || ' ' || COALESCE(actual,'') || ' ' || COALESCE(expected,''),1,1200) AS preview
|
|
964
|
-
FROM quality_finding
|
|
965
|
-
WHERE ${where.join(" AND ")}
|
|
966
|
-
ORDER BY created_at ASC
|
|
967
|
-
LIMIT ?
|
|
968
|
-
`, params));
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
const dedup = [];
|
|
972
|
-
const seen = new Set();
|
|
973
|
-
for (const row of rows) {
|
|
974
|
-
const key = `${row.ref_kind}:${row.ref_id}`;
|
|
975
|
-
if (seen.has(key)) continue;
|
|
976
|
-
seen.add(key);
|
|
977
|
-
dedup.push(row);
|
|
978
|
-
}
|
|
979
|
-
dedup.sort((a, b) => String(a.at || "").localeCompare(String(b.at || "")));
|
|
980
|
-
return Object.assign(win, { rows: dedup.slice(0, limit) });
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
function emptyDreamBuckets() {
|
|
984
|
-
const out = {};
|
|
985
|
-
for (const key of DREAM_BUCKET_KEYS) out[key] = { count: 0, examples: [] };
|
|
986
|
-
return out;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
function dreamBucketMatches(row) {
|
|
990
|
-
const text = foldSignalText([row.preview, row.subtype, row.status, row.topic].filter(Boolean).join(" "));
|
|
991
|
-
const matches = [];
|
|
992
|
-
const add = (key, reason) => matches.push({ key, reason });
|
|
993
|
-
|
|
994
|
-
if (/\b(super|perfekt|top|stark|danke|geil|sauber|besser|bestaetigt|bestatigt|demo-bereit|b[aehm]*hm|well done|great)\b/.test(text)) {
|
|
995
|
-
add("praise_received", "human/peer praise or green feedback");
|
|
996
|
-
}
|
|
997
|
-
if (/\b(ok|done|passed|pass|green|grun|gruen|verified|verifiziert|bestaetigt|bestatigt|gefixt|live|closed|acceptance|funktioniert wieder|passt jetzt|smoke grun|tests? grun|0 failed|70 passed)\b/.test(text)) {
|
|
998
|
-
add("right_made", "verified success or completed action");
|
|
999
|
-
}
|
|
1000
|
-
if (/\b(falsch|fehler|bug|blocker|regression|nicht live|nichts geaendert|nichts geandert|geht nicht|funktioniert nicht|ignoriert|vermischt|fallback|404|502|broken|fail|failed|error|rot|kaputt)\b/.test(text)) {
|
|
1001
|
-
add("wrong_made", "failure, bug, or red verification");
|
|
1002
|
-
}
|
|
1003
|
-
if (/\b(stop|hoer auf|hor auf|verdammt|nervt|spam|pennt|lump|kacke|scheiss|scheisse|was machst|du hast|nicht in die gruppe|konsole|heimlich)\b/.test(text)) {
|
|
1004
|
-
add("called_out", "direct correction or frustration signal");
|
|
1005
|
-
}
|
|
1006
|
-
if (/\b(kaputt gemacht|abgeschossen|weg gefegt|weggefegt|server down|production-down|prod down|502|crash|crashed|kill|killed|orphan|stopped|telegram kaputt|deploy.*kaputt|service.*down)\b/.test(text)) {
|
|
1007
|
-
add("broke_things", "incident or caused damage");
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
if (/^(done|ok|success|passed)$/i.test(String(row.status || ""))) {
|
|
1011
|
-
add("right_made", "status indicates completed work");
|
|
1012
|
-
} else if (/^(error|failed|fail|blocked)$/i.test(String(row.status || ""))) {
|
|
1013
|
-
add("wrong_made", "status indicates failure/blocker");
|
|
1014
|
-
}
|
|
1015
|
-
return matches;
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
function addDreamExample(bucket, row, reason) {
|
|
1019
|
-
bucket.count++;
|
|
1020
|
-
if (bucket.examples.length >= 20) return;
|
|
1021
|
-
bucket.examples.push({
|
|
1022
|
-
ref_kind: row.ref_kind,
|
|
1023
|
-
ref_id: row.ref_id,
|
|
1024
|
-
actor: row.actor || null,
|
|
1025
|
-
topic: row.topic || null,
|
|
1026
|
-
at: row.at || null,
|
|
1027
|
-
reason,
|
|
1028
|
-
preview: compactContent(row.preview, 360),
|
|
1029
|
-
});
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
function classifyDreamRows(rows) {
|
|
1033
|
-
const buckets = emptyDreamBuckets();
|
|
1034
|
-
for (const row of rows) {
|
|
1035
|
-
for (const match of dreamBucketMatches(row)) {
|
|
1036
|
-
addDreamExample(buckets[match.key], row, match.reason);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
return buckets;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
function dreamLessons(buckets) {
|
|
1043
|
-
const lessons = [];
|
|
1044
|
-
const firstRef = (key) => {
|
|
1045
|
-
const ex = buckets[key] && buckets[key].examples && buckets[key].examples[0];
|
|
1046
|
-
return ex ? `${ex.ref_kind}:${ex.ref_id}` : null;
|
|
1047
|
-
};
|
|
1048
|
-
if (buckets.broke_things.count > 0) {
|
|
1049
|
-
lessons.push({ type: "stop_doing", text: "Production, Telegram, and deploy incidents need a gate, receipt, and rollback path before more changes.", evidence_ref: firstRef("broke_things") });
|
|
1050
|
-
}
|
|
1051
|
-
if (buckets.called_out.count > 0) {
|
|
1052
|
-
lessons.push({ type: "behavior_adjustment", text: "User frustration is a hard signal: reduce spam, write in the requested channel, and keep status updates short.", evidence_ref: firstRef("called_out") });
|
|
1053
|
-
}
|
|
1054
|
-
if (buckets.wrong_made.count > 0) {
|
|
1055
|
-
lessons.push({ type: "fix_next", text: "Red verifications and repeated bugs become next-day tasks until explicitly closed with evidence.", evidence_ref: firstRef("wrong_made") });
|
|
1056
|
-
}
|
|
1057
|
-
if (buckets.right_made.count > 0) {
|
|
1058
|
-
lessons.push({ type: "keep_doing", text: "Keep the workflows that produced green verification: concrete checks, URLs, exit codes, and direct acceptance evidence.", evidence_ref: firstRef("right_made") });
|
|
1059
|
-
}
|
|
1060
|
-
if (buckets.praise_received.count > 0) {
|
|
1061
|
-
lessons.push({ type: "positive_reinforcement", text: "Praise marks a useful pattern; preserve the exact behavior that led to it.", evidence_ref: firstRef("praise_received") });
|
|
1062
|
-
}
|
|
1063
|
-
if (!lessons.length) {
|
|
1064
|
-
lessons.push({ type: "low_signal", text: "No strong praise/correction/failure signal was detected; keep collecting raw messages and evidence." });
|
|
1065
|
-
}
|
|
1066
|
-
return lessons;
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
function dreamSummary(input, source, buckets, lessons, remRuns) {
|
|
1070
|
-
const labels = {
|
|
1071
|
-
wrong_made: "Falsch gemacht",
|
|
1072
|
-
right_made: "Richtig gemacht",
|
|
1073
|
-
praise_received: "Lob bekommen",
|
|
1074
|
-
called_out: "Angemacht/korrigiert",
|
|
1075
|
-
broke_things: "Scheisse gebaut",
|
|
1076
|
-
};
|
|
1077
|
-
const lines = [];
|
|
1078
|
-
lines.push(`# Dreammode Review: ${source.date}`);
|
|
1079
|
-
lines.push("");
|
|
1080
|
-
lines.push(`Scope: ${scopeName(input.scope)}${input.project ? ` | project: ${input.project}` : ""}${input.agent_name ? ` | agent: ${normalizeAgentName(input.agent_name)}` : ""}`);
|
|
1081
|
-
lines.push(`Window: ${source.since} -> ${source.until}`);
|
|
1082
|
-
lines.push(`Sources examined: ${source.rows.length} rows. REM phases: ${remRuns.map((r) => r.phase + "#" + r.run_id).join(", ") || "none"}.`);
|
|
1083
|
-
lines.push("");
|
|
1084
|
-
for (const key of DREAM_BUCKET_KEYS) {
|
|
1085
|
-
const bucket = buckets[key];
|
|
1086
|
-
lines.push(`## ${labels[key]} (${bucket.count})`);
|
|
1087
|
-
if (!bucket.examples.length) {
|
|
1088
|
-
lines.push("- none detected");
|
|
1089
|
-
} else {
|
|
1090
|
-
for (const ex of bucket.examples.slice(0, 8)) {
|
|
1091
|
-
const who = ex.actor ? ` ${ex.actor}` : "";
|
|
1092
|
-
const topic = ex.topic ? ` [${ex.topic}]` : "";
|
|
1093
|
-
lines.push(`- ${ex.ref_kind}:${ex.ref_id}${topic}${who}: ${compactContent(ex.preview, 220)}`);
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
lines.push("");
|
|
1097
|
-
}
|
|
1098
|
-
lines.push("## Daraus lernen");
|
|
1099
|
-
for (const lesson of lessons) {
|
|
1100
|
-
lines.push(`- ${lesson.type}: ${lesson.text}${lesson.evidence_ref ? ` (${lesson.evidence_ref})` : ""}`);
|
|
1101
|
-
}
|
|
1102
|
-
lines.push("");
|
|
1103
|
-
lines.push("Rule: Dreammode is draft processing. It may propose lessons, but official truth/rules still need explicit promotion or task updates.");
|
|
1104
|
-
return compactContent(lines.join("\n"), 16000);
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
function rowToDreammodeRun(row) {
|
|
1108
|
-
return row ? Object.assign({}, row, {
|
|
1109
|
-
wrong_made: parseJson(row.wrong_made_json, { count: 0, examples: [] }),
|
|
1110
|
-
right_made: parseJson(row.right_made_json, { count: 0, examples: [] }),
|
|
1111
|
-
praise_received: parseJson(row.praise_received_json, { count: 0, examples: [] }),
|
|
1112
|
-
called_out: parseJson(row.called_out_json, { count: 0, examples: [] }),
|
|
1113
|
-
broke_things: parseJson(row.broke_things_json, { count: 0, examples: [] }),
|
|
1114
|
-
lessons: parseJson(row.lessons_json, []),
|
|
1115
|
-
rem_run_ids: parseJson(row.rem_run_ids_json, []),
|
|
1116
|
-
meta: parseJson(row.meta_json, {}),
|
|
1117
|
-
}) : null;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
function dreammodeRun(db, input = {}) {
|
|
1121
|
-
ensureMemoryConsolidationSchema(db);
|
|
1122
|
-
const agent = input.agent_name ? normalizeAgentName(input.agent_name) : "";
|
|
1123
|
-
const project = String(input.project || "").trim();
|
|
1124
|
-
const scope = scopeName(input.scope);
|
|
1125
|
-
const source = selectDreamRows(db, input);
|
|
1126
|
-
const existing = db.prepare("SELECT * FROM dreammode_run WHERE scope=? AND agent_name=? AND project=? AND dream_date=?")
|
|
1127
|
-
.get(scope, agent, project, source.date);
|
|
1128
|
-
if (existing && input.force !== true) {
|
|
1129
|
-
return { ok: true, skipped: true, reason: "dreammode already ran for this agent/project/date", run: rowToDreammodeRun(existing) };
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
const remRuns = [];
|
|
1133
|
-
if (input.run_rem_phases !== false) {
|
|
1134
|
-
const phases = input.phases && Array.isArray(input.phases) ? input.phases : ["light", "daily", "deep", "rem"];
|
|
1135
|
-
for (const phase of phases) {
|
|
1136
|
-
const normalized = String(phase || "").toLowerCase();
|
|
1137
|
-
if (!PHASES.has(normalized)) continue;
|
|
1138
|
-
const result = memoryRemRun(db, {
|
|
1139
|
-
scope,
|
|
1140
|
-
agent_name: agent || undefined,
|
|
1141
|
-
project: project || undefined,
|
|
1142
|
-
phase: normalized,
|
|
1143
|
-
date: source.date,
|
|
1144
|
-
days: normalized === "rem" ? clampInt(input.rem_days, 7, 1, 3650) : undefined,
|
|
1145
|
-
meta: Object.assign({}, input.meta || {}, { dreammode: true, dream_date: source.date }),
|
|
1146
|
-
});
|
|
1147
|
-
if (result && result.ok) remRuns.push({ phase: normalized, run_id: result.run_id, promoted_memory_id: result.promoted_memory_id || null });
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
const buckets = classifyDreamRows(source.rows);
|
|
1152
|
-
const lessons = dreamLessons(buckets);
|
|
1153
|
-
const summary = dreamSummary(input, source, buckets, lessons, remRuns);
|
|
1154
|
-
let briefId = null;
|
|
1155
|
-
const writeBrief = input.write_brief !== false;
|
|
1156
|
-
if (writeBrief && tableExists(db, "agent_brief")) {
|
|
1157
|
-
const coordinator = normalizeAgentName(input.coordinator_agent || input.agent_name || "agent-a");
|
|
1158
|
-
const info = db.prepare("INSERT INTO agent_brief (agent_name, source_agent, content, meta_json) VALUES (?,?,?,?)")
|
|
1159
|
-
.run(coordinator || "agent-a", normalizeAgentName(input.source_agent || "mnemo-dreammode"), summary, safeJson({ kind: "dreammode_review", project: project || null, agent_name: agent || null, dream_date: source.date }, {}));
|
|
1160
|
-
briefId = info.lastInsertRowid;
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
const insertArgs = [
|
|
1164
|
-
scope,
|
|
1165
|
-
agent,
|
|
1166
|
-
project,
|
|
1167
|
-
source.date,
|
|
1168
|
-
source.since,
|
|
1169
|
-
source.until,
|
|
1170
|
-
source.rows.filter((row) => row.ref_kind === "memory").length,
|
|
1171
|
-
source.rows.filter((row) => row.ref_kind === "agent_action").length,
|
|
1172
|
-
source.rows.filter((row) => row.ref_kind === "mnemo_event_journal").length,
|
|
1173
|
-
safeJson(buckets.wrong_made, {}),
|
|
1174
|
-
safeJson(buckets.right_made, {}),
|
|
1175
|
-
safeJson(buckets.praise_received, {}),
|
|
1176
|
-
safeJson(buckets.called_out, {}),
|
|
1177
|
-
safeJson(buckets.broke_things, {}),
|
|
1178
|
-
safeJson(lessons, []),
|
|
1179
|
-
safeJson(remRuns, []),
|
|
1180
|
-
summary,
|
|
1181
|
-
briefId,
|
|
1182
|
-
input.status || "draft",
|
|
1183
|
-
safeJson(Object.assign({}, input.meta || {}, { no_destructive_migration: true, human_style_review: true }), {}),
|
|
1184
|
-
];
|
|
1185
|
-
const info = db.prepare(`
|
|
1186
|
-
INSERT INTO dreammode_run
|
|
1187
|
-
(scope, agent_name, project, dream_date, source_window_start, source_window_end, messages_examined, actions_examined, events_examined,
|
|
1188
|
-
wrong_made_json, right_made_json, praise_received_json, called_out_json, broke_things_json, lessons_json, rem_run_ids_json, summary, brief_id, status, meta_json)
|
|
1189
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
1190
|
-
ON CONFLICT(scope, agent_name, project, dream_date) DO UPDATE SET
|
|
1191
|
-
source_window_start=excluded.source_window_start,
|
|
1192
|
-
source_window_end=excluded.source_window_end,
|
|
1193
|
-
messages_examined=excluded.messages_examined,
|
|
1194
|
-
actions_examined=excluded.actions_examined,
|
|
1195
|
-
events_examined=excluded.events_examined,
|
|
1196
|
-
wrong_made_json=excluded.wrong_made_json,
|
|
1197
|
-
right_made_json=excluded.right_made_json,
|
|
1198
|
-
praise_received_json=excluded.praise_received_json,
|
|
1199
|
-
called_out_json=excluded.called_out_json,
|
|
1200
|
-
broke_things_json=excluded.broke_things_json,
|
|
1201
|
-
lessons_json=excluded.lessons_json,
|
|
1202
|
-
rem_run_ids_json=excluded.rem_run_ids_json,
|
|
1203
|
-
summary=excluded.summary,
|
|
1204
|
-
brief_id=excluded.brief_id,
|
|
1205
|
-
status=excluded.status,
|
|
1206
|
-
meta_json=excluded.meta_json,
|
|
1207
|
-
created_at=strftime('%Y-%m-%dT%H:%M:%fZ','now')
|
|
1208
|
-
`).run(...insertArgs);
|
|
1209
|
-
const row = db.prepare("SELECT * FROM dreammode_run WHERE scope=? AND agent_name=? AND project=? AND dream_date=?").get(scope, agent, project, source.date);
|
|
1210
|
-
return {
|
|
1211
|
-
ok: true,
|
|
1212
|
-
skipped: false,
|
|
1213
|
-
run_id: row ? row.id : info.lastInsertRowid,
|
|
1214
|
-
dream_date: source.date,
|
|
1215
|
-
source_count: source.rows.length,
|
|
1216
|
-
brief_id: briefId,
|
|
1217
|
-
rem_runs: remRuns,
|
|
1218
|
-
buckets,
|
|
1219
|
-
lessons,
|
|
1220
|
-
summary,
|
|
1221
|
-
run: rowToDreammodeRun(row),
|
|
1222
|
-
};
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
function dreammodeStatus(db, input = {}) {
|
|
1226
|
-
ensureMemoryConsolidationSchema(db);
|
|
1227
|
-
const where = ["scope=?"];
|
|
1228
|
-
const params = [scopeName(input.scope)];
|
|
1229
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
1230
|
-
if (input.project !== undefined) { where.push("project=?"); params.push(String(input.project || "").trim()); }
|
|
1231
|
-
if (input.date || input.dream_date) { where.push("dream_date=?"); params.push(String(input.date || input.dream_date).slice(0, 10)); }
|
|
1232
|
-
params.push(clampInt(input.limit, 20, 1, 200));
|
|
1233
|
-
const rows = db.prepare(`
|
|
1234
|
-
SELECT * FROM dreammode_run
|
|
1235
|
-
WHERE ${where.join(" AND ")}
|
|
1236
|
-
ORDER BY dream_date DESC, created_at DESC
|
|
1237
|
-
LIMIT ?
|
|
1238
|
-
`).all(...params).map(rowToDreammodeRun);
|
|
1239
|
-
return { ok: true, count: rows.length, runs: rows };
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
function insertPromotedMemory(db, phase, input, runId, summary, selectedRefs) {
|
|
1243
|
-
if (!tableExists(db, "memory")) return null;
|
|
1244
|
-
const occurred = nowIso();
|
|
1245
|
-
const sourceRef = `memory_consolidation_run:${runId}`;
|
|
1246
|
-
const kind = "memory_consolidation";
|
|
1247
|
-
const actor = normalizeAgentName(input.agent_name || "mnemo");
|
|
1248
|
-
const topic = input.project || "memory_consolidation";
|
|
1249
|
-
const meta = {
|
|
1250
|
-
phase,
|
|
1251
|
-
source_ref: sourceRef,
|
|
1252
|
-
confidence: "derived",
|
|
1253
|
-
review_status: "draft",
|
|
1254
|
-
selected_refs: selectedRefs,
|
|
1255
|
-
canonical_model: canonicalMemoryModel(),
|
|
1256
|
-
};
|
|
1257
|
-
const hash = sha([kind, sourceRef, occurred, summary].join("|"));
|
|
1258
|
-
const hasLayer = ensureMemoryLayerColumn(db);
|
|
1259
|
-
const sql = hasLayer
|
|
1260
|
-
? "INSERT OR IGNORE INTO memory (kind, source, source_ref, occurred_at, actor, topic, importance, layer, text, meta_json, hash) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
|
|
1261
|
-
: "INSERT OR IGNORE INTO memory (kind, source, source_ref, occurred_at, actor, topic, importance, text, meta_json, hash) VALUES (?,?,?,?,?,?,?,?,?,?)";
|
|
1262
|
-
const args = hasLayer
|
|
1263
|
-
? [kind, "mnemo:rem", sourceRef, occurred, actor, topic, phase === "rem" ? 8 : 7, "semantic", summary, safeJson(meta, {}), hash]
|
|
1264
|
-
: [kind, "mnemo:rem", sourceRef, occurred, actor, topic, phase === "rem" ? 8 : 7, summary, safeJson(meta, {}), hash];
|
|
1265
|
-
const info = db.prepare(sql).run(...args);
|
|
1266
|
-
if (info.changes > 0) return info.lastInsertRowid;
|
|
1267
|
-
const row = db.prepare("SELECT id FROM memory WHERE hash=?").get(hash);
|
|
1268
|
-
return row ? row.id : null;
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
function memoryRemRun(db, input = {}) {
|
|
1272
|
-
ensureMemoryConsolidationSchema(db);
|
|
1273
|
-
const phase = String(input.phase || "light").toLowerCase();
|
|
1274
|
-
if (!PHASES.has(phase)) return { error: "phase must be light|daily|deep|rem" };
|
|
1275
|
-
const days = phaseWindowDays(phase, input.days);
|
|
1276
|
-
const selection = selectRowsForPhase(db, phase, Object.assign({}, input, { days }));
|
|
1277
|
-
const counts = sourceCounts(db, Object.assign({}, input, { since: selection.since, days }));
|
|
1278
|
-
const dailyReflection = phase === "daily" ? runDailyReflection(db, input, selection) : null;
|
|
1279
|
-
const selectedRefs = selection.rows.map((row) => ({
|
|
1280
|
-
ref_kind: row.ref_kind,
|
|
1281
|
-
ref_id: row.ref_id,
|
|
1282
|
-
subtype: row.subtype || null,
|
|
1283
|
-
at: row.at || null,
|
|
1284
|
-
importance: row.importance || null,
|
|
1285
|
-
}));
|
|
1286
|
-
const summary = buildSummary(phase, input, selection, counts);
|
|
1287
|
-
const info = db.prepare(`
|
|
1288
|
-
INSERT INTO memory_consolidation_run
|
|
1289
|
-
(scope, agent_name, project, phase, source_window_start, source_window_end, source_counts_json, selected_refs_json, summary, status, confidence, review_status, meta_json)
|
|
1290
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
1291
|
-
`).run(
|
|
1292
|
-
scopeName(input.scope),
|
|
1293
|
-
input.agent_name ? normalizeAgentName(input.agent_name) : null,
|
|
1294
|
-
input.project || null,
|
|
1295
|
-
phase,
|
|
1296
|
-
selection.since,
|
|
1297
|
-
selection.until,
|
|
1298
|
-
safeJson(counts, {}),
|
|
1299
|
-
safeJson(selectedRefs, []),
|
|
1300
|
-
summary,
|
|
1301
|
-
input.status || "draft",
|
|
1302
|
-
input.confidence || "derived",
|
|
1303
|
-
input.review_status || "draft",
|
|
1304
|
-
safeJson(Object.assign({}, input.meta || {}, { daily_reflection: dailyReflection, no_destructive_migration: true }), {})
|
|
1305
|
-
);
|
|
1306
|
-
const runId = info.lastInsertRowid;
|
|
1307
|
-
const promotedMemoryId = input.promote_to_memory === false ? null : insertPromotedMemory(db, phase, input, runId, summary, selectedRefs);
|
|
1308
|
-
if (promotedMemoryId) {
|
|
1309
|
-
db.prepare("UPDATE memory_consolidation_run SET promoted_memory_id=? WHERE id=?").run(promotedMemoryId, runId);
|
|
1310
|
-
}
|
|
1311
|
-
return {
|
|
1312
|
-
ok: true,
|
|
1313
|
-
run_id: runId,
|
|
1314
|
-
phase,
|
|
1315
|
-
status: input.status || "draft",
|
|
1316
|
-
confidence: input.confidence || "derived",
|
|
1317
|
-
review_status: input.review_status || "draft",
|
|
1318
|
-
selected_count: selectedRefs.length,
|
|
1319
|
-
source_counts: counts,
|
|
1320
|
-
promoted_memory_id: promotedMemoryId,
|
|
1321
|
-
daily_reflection: dailyReflection,
|
|
1322
|
-
summary,
|
|
1323
|
-
rule: "Draft consolidation only. Promote concrete facts through the proper Mnemo truth/rules/scar tools.",
|
|
1324
|
-
};
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
function rowToConsolidation(row) {
|
|
1328
|
-
if (!row) return null;
|
|
1329
|
-
return Object.assign({}, row, {
|
|
1330
|
-
source_counts: parseJson(row.source_counts_json, {}),
|
|
1331
|
-
selected_refs: parseJson(row.selected_refs_json, []),
|
|
1332
|
-
meta: parseJson(row.meta_json, {}),
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
function memoryConsolidationList(db, input = {}) {
|
|
1337
|
-
ensureMemoryConsolidationSchema(db);
|
|
1338
|
-
const where = ["scope=?"];
|
|
1339
|
-
const params = [scopeName(input.scope)];
|
|
1340
|
-
if (input.phase) { where.push("phase=?"); params.push(String(input.phase).toLowerCase()); }
|
|
1341
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
1342
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
1343
|
-
if (input.status) { where.push("status=?"); params.push(input.status); }
|
|
1344
|
-
params.push(clampInt(input.limit, 50, 1, 500));
|
|
1345
|
-
const rows = db.prepare(`
|
|
1346
|
-
SELECT * FROM memory_consolidation_run
|
|
1347
|
-
WHERE ${where.join(" AND ")}
|
|
1348
|
-
ORDER BY created_at DESC
|
|
1349
|
-
LIMIT ?
|
|
1350
|
-
`).all(...params).map(rowToConsolidation);
|
|
1351
|
-
return { ok: true, count: rows.length, runs: rows };
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
function rowToDepartmentJournal(row) {
|
|
1355
|
-
if (!row) return null;
|
|
1356
|
-
return Object.assign({}, row, {
|
|
1357
|
-
dependencies: parseJson(row.dependencies_json, []),
|
|
1358
|
-
foreign_scope_requests: parseJson(row.foreign_scope_requests_json, []),
|
|
1359
|
-
meta: parseJson(row.meta_json, {}),
|
|
1360
|
-
});
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
function departmentJournalAdd(db, input = {}) {
|
|
1364
|
-
ensureMemoryConsolidationSchema(db);
|
|
1365
|
-
const department = normalizeDepartment(input.department_name || input.department);
|
|
1366
|
-
const date = (input.journal_date || input.date || new Date().toISOString().slice(0, 10)).slice(0, 10);
|
|
1367
|
-
const agent = input.agent_name ? normalizeAgentName(input.agent_name) : null;
|
|
1368
|
-
const info = db.prepare(`
|
|
1369
|
-
INSERT INTO department_journal
|
|
1370
|
-
(scope, department_name, agent_name, project, journal_date, progress, blockers, risks, open_questions, dependencies_json, foreign_scope_requests_json, status, meta_json)
|
|
1371
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
1372
|
-
`).run(
|
|
1373
|
-
scopeName(input.scope),
|
|
1374
|
-
department,
|
|
1375
|
-
agent,
|
|
1376
|
-
input.project || null,
|
|
1377
|
-
date,
|
|
1378
|
-
textOrNull(input.progress || input.summary),
|
|
1379
|
-
textOrNull(input.blockers),
|
|
1380
|
-
textOrNull(input.risks),
|
|
1381
|
-
textOrNull(input.open_questions),
|
|
1382
|
-
safeJson(listInput(input.dependencies), []),
|
|
1383
|
-
safeJson(listInput(input.foreign_scope_requests || input.access_requests), []),
|
|
1384
|
-
input.status || "open",
|
|
1385
|
-
safeJson(input.meta || {}, {})
|
|
1386
|
-
);
|
|
1387
|
-
return { ok: true, id: info.lastInsertRowid, department_name: department, journal_date: date };
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
function departmentJournalList(db, input = {}) {
|
|
1391
|
-
ensureMemoryConsolidationSchema(db);
|
|
1392
|
-
const where = ["scope=?"];
|
|
1393
|
-
const params = [scopeName(input.scope)];
|
|
1394
|
-
if (input.department_name || input.department) { where.push("department_name=?"); params.push(normalizeDepartment(input.department_name || input.department)); }
|
|
1395
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
1396
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
1397
|
-
if (input.status) { where.push("status=?"); params.push(input.status); }
|
|
1398
|
-
if (input.since) { where.push("created_at>=?"); params.push(input.since); }
|
|
1399
|
-
params.push(clampInt(input.limit, 50, 1, 500));
|
|
1400
|
-
const rows = db.prepare(`
|
|
1401
|
-
SELECT * FROM department_journal
|
|
1402
|
-
WHERE ${where.join(" AND ")}
|
|
1403
|
-
ORDER BY journal_date DESC, created_at DESC
|
|
1404
|
-
LIMIT ?
|
|
1405
|
-
`).all(...params).map(rowToDepartmentJournal);
|
|
1406
|
-
return { ok: true, count: rows.length, journals: rows };
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
|
-
function rowToSleepNote(row) {
|
|
1410
|
-
return row ? Object.assign({}, row, { meta: parseJson(row.meta_json, {}) }) : null;
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
function agentSleepNoteAdd(db, input = {}) {
|
|
1414
|
-
ensureMemoryConsolidationSchema(db);
|
|
1415
|
-
const agent = normalizeAgentName(input.agent_name);
|
|
1416
|
-
if (!agent) return { error: "agent_name required" };
|
|
1417
|
-
const date = (input.note_date || input.date || new Date().toISOString().slice(0, 10)).slice(0, 10);
|
|
1418
|
-
const info = db.prepare(`
|
|
1419
|
-
INSERT INTO agent_sleep_note
|
|
1420
|
-
(scope, agent_name, project, note_date, learned, uncertainty, recurring_errors, needed_context, improvement_idea, source_ref, status, meta_json)
|
|
1421
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
|
1422
|
-
`).run(
|
|
1423
|
-
scopeName(input.scope),
|
|
1424
|
-
agent,
|
|
1425
|
-
input.project || null,
|
|
1426
|
-
date,
|
|
1427
|
-
textOrNull(input.learned),
|
|
1428
|
-
textOrNull(input.uncertainty),
|
|
1429
|
-
textOrNull(input.recurring_errors),
|
|
1430
|
-
textOrNull(input.needed_context),
|
|
1431
|
-
textOrNull(input.improvement_idea),
|
|
1432
|
-
input.source_ref || null,
|
|
1433
|
-
input.status || "draft",
|
|
1434
|
-
safeJson(input.meta || {}, {})
|
|
1435
|
-
);
|
|
1436
|
-
return { ok: true, id: info.lastInsertRowid, agent_name: agent, note_date: date };
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
function agentSleepNoteList(db, input = {}) {
|
|
1440
|
-
ensureMemoryConsolidationSchema(db);
|
|
1441
|
-
const where = ["scope=?"];
|
|
1442
|
-
const params = [scopeName(input.scope)];
|
|
1443
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
1444
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
1445
|
-
if (input.status) { where.push("status=?"); params.push(input.status); }
|
|
1446
|
-
if (input.since) { where.push("created_at>=?"); params.push(input.since); }
|
|
1447
|
-
params.push(clampInt(input.limit, 50, 1, 500));
|
|
1448
|
-
const rows = db.prepare(`
|
|
1449
|
-
SELECT * FROM agent_sleep_note
|
|
1450
|
-
WHERE ${where.join(" AND ")}
|
|
1451
|
-
ORDER BY note_date DESC, created_at DESC
|
|
1452
|
-
LIMIT ?
|
|
1453
|
-
`).all(...params).map(rowToSleepNote);
|
|
1454
|
-
return { ok: true, count: rows.length, notes: rows };
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
function normalizeProposalKind(value) {
|
|
1458
|
-
const kind = String(value || "project_memory").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
1459
|
-
const allowed = new Set(["decision", "rule", "project_memory", "risk", "owner_question", "scar", "runbook"]);
|
|
1460
|
-
return allowed.has(kind) ? kind : "project_memory";
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
function proposalTitle(input = {}) {
|
|
1464
|
-
const explicit = String(input.title || "").trim();
|
|
1465
|
-
if (explicit) return explicit.slice(0, 220);
|
|
1466
|
-
const body = String(input.body || input.summary || input.question || "").replace(/\s+/g, " ").trim();
|
|
1467
|
-
return (body ? body.slice(0, 180) : "Memory promotion proposal");
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
function rowToPromotion(row) {
|
|
1471
|
-
return row ? Object.assign({}, row, {
|
|
1472
|
-
evidence: parseJson(row.evidence_json, []),
|
|
1473
|
-
meta: parseJson(row.meta_json, {}),
|
|
1474
|
-
}) : null;
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
function memoryPromotionPropose(db, input = {}) {
|
|
1478
|
-
ensureMemoryConsolidationSchema(db);
|
|
1479
|
-
const kind = normalizeProposalKind(input.proposal_kind || input.kind);
|
|
1480
|
-
const title = proposalTitle(input);
|
|
1481
|
-
const agent = input.agent_name ? normalizeAgentName(input.agent_name) : null;
|
|
1482
|
-
const info = db.prepare(`
|
|
1483
|
-
INSERT INTO memory_promotion_proposal
|
|
1484
|
-
(scope, proposal_kind, title, body, project, department_name, agent_name, source_kind, source_id, evidence_json, status, meta_json)
|
|
1485
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
|
|
1486
|
-
`).run(
|
|
1487
|
-
scopeName(input.scope),
|
|
1488
|
-
kind,
|
|
1489
|
-
title,
|
|
1490
|
-
textOrNull(input.body || input.summary || input.question),
|
|
1491
|
-
input.project || null,
|
|
1492
|
-
input.department_name ? normalizeDepartment(input.department_name) : null,
|
|
1493
|
-
agent,
|
|
1494
|
-
input.source_kind || null,
|
|
1495
|
-
input.source_id != null ? String(input.source_id) : null,
|
|
1496
|
-
safeJson(Array.isArray(input.evidence) ? input.evidence : [], []),
|
|
1497
|
-
input.status || "proposed",
|
|
1498
|
-
safeJson(input.meta || {}, {})
|
|
1499
|
-
);
|
|
1500
|
-
return { ok: true, id: info.lastInsertRowid, status: input.status || "proposed", proposal_kind: kind, title };
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
function insertPromotionMemory(db, proposal, decidedBy) {
|
|
1504
|
-
if (!tableExists(db, "memory")) return null;
|
|
1505
|
-
const kind = proposal.proposal_kind === "decision" ? "decision" : "manual";
|
|
1506
|
-
const occurred = nowIso();
|
|
1507
|
-
const sourceRef = `memory_promotion_proposal:${proposal.id}`;
|
|
1508
|
-
const text = [
|
|
1509
|
-
`Promotion kind: ${proposal.proposal_kind}`,
|
|
1510
|
-
`Title: ${proposal.title}`,
|
|
1511
|
-
proposal.body ? `Body: ${proposal.body}` : null,
|
|
1512
|
-
`Approved by: ${decidedBy || proposal.reviewer || "unknown"}`,
|
|
1513
|
-
].filter(Boolean).join("\n");
|
|
1514
|
-
const meta = {
|
|
1515
|
-
proposal_id: proposal.id,
|
|
1516
|
-
proposal_kind: proposal.proposal_kind,
|
|
1517
|
-
confidence: "confirmed",
|
|
1518
|
-
review_status: "approved",
|
|
1519
|
-
source_kind: proposal.source_kind,
|
|
1520
|
-
source_id: proposal.source_id,
|
|
1521
|
-
};
|
|
1522
|
-
const hash = sha([kind, sourceRef, occurred, text].join("|"));
|
|
1523
|
-
const hasLayer = ensureMemoryLayerColumn(db);
|
|
1524
|
-
const sql = hasLayer
|
|
1525
|
-
? "INSERT OR IGNORE INTO memory (kind, source, source_ref, occurred_at, actor, topic, importance, layer, text, meta_json, hash) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
|
|
1526
|
-
: "INSERT OR IGNORE INTO memory (kind, source, source_ref, occurred_at, actor, topic, importance, text, meta_json, hash) VALUES (?,?,?,?,?,?,?,?,?,?)";
|
|
1527
|
-
const args = hasLayer
|
|
1528
|
-
? [kind, "mnemo:promotion", sourceRef, occurred, decidedBy || proposal.agent_name || "mnemo", proposal.project || "memory_promotion", 9, "semantic", text, safeJson(meta, {}), hash]
|
|
1529
|
-
: [kind, "mnemo:promotion", sourceRef, occurred, decidedBy || proposal.agent_name || "mnemo", proposal.project || "memory_promotion", 9, text, safeJson(meta, {}), hash];
|
|
1530
|
-
const info = db.prepare(sql).run(...args);
|
|
1531
|
-
return info.changes > 0 ? info.lastInsertRowid : ((db.prepare("SELECT id FROM memory WHERE hash=?").get(hash) || {}).id || null);
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
function insertPromotionDecision(db, proposal, decidedBy) {
|
|
1535
|
-
if (!tableExists(db, "decision_log")) return null;
|
|
1536
|
-
try {
|
|
1537
|
-
const info = db.prepare("INSERT INTO decision_log (scope, title, body, decided_by, agents_involved, entities_affected) VALUES (?,?,?,?,?,?)")
|
|
1538
|
-
.run(proposal.scope || DEFAULT_SCOPE, proposal.title, proposal.body || "", decidedBy || proposal.reviewer || "mnemo", proposal.agent_name || null, proposal.project || null);
|
|
1539
|
-
return info.lastInsertRowid;
|
|
1540
|
-
} catch {
|
|
1541
|
-
return null;
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
function memoryPromotionDecide(db, input = {}) {
|
|
1546
|
-
ensureMemoryConsolidationSchema(db);
|
|
1547
|
-
const id = parseInt(input.id || input.proposal_id, 10);
|
|
1548
|
-
const status = String(input.status || input.decision || "").toLowerCase();
|
|
1549
|
-
const reviewer = normalizeAgentName(input.reviewer || input.decided_by || input.approved_by);
|
|
1550
|
-
if (!id || !reviewer || !["approved", "rejected", "promoted"].includes(status)) {
|
|
1551
|
-
return { error: "id + reviewer + status(approved|rejected|promoted) required" };
|
|
1552
|
-
}
|
|
1553
|
-
const row = db.prepare("SELECT * FROM memory_promotion_proposal WHERE id=?").get(id);
|
|
1554
|
-
if (!row) return { error: "proposal_not_found", id };
|
|
1555
|
-
const proposal = rowToPromotion(row);
|
|
1556
|
-
let promotedRef = { kind: null, id: null };
|
|
1557
|
-
if (status === "promoted" || (status === "approved" && input.promote === true)) {
|
|
1558
|
-
if (proposal.proposal_kind === "decision") {
|
|
1559
|
-
const decisionId = insertPromotionDecision(db, proposal, reviewer);
|
|
1560
|
-
if (decisionId) promotedRef = { kind: "decision_log", id: String(decisionId) };
|
|
1561
|
-
}
|
|
1562
|
-
if (!promotedRef.id) {
|
|
1563
|
-
const memoryId = insertPromotionMemory(db, proposal, reviewer);
|
|
1564
|
-
if (memoryId) promotedRef = { kind: "memory", id: String(memoryId) };
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
db.prepare(`
|
|
1568
|
-
UPDATE memory_promotion_proposal
|
|
1569
|
-
SET status=?, reviewer=?, review_notes=?, promoted_ref_kind=?, promoted_ref_id=?, decided_at=strftime('%Y-%m-%dT%H:%M:%fZ','now'), meta_json=COALESCE(?, meta_json)
|
|
1570
|
-
WHERE id=?
|
|
1571
|
-
`).run(
|
|
1572
|
-
status,
|
|
1573
|
-
reviewer,
|
|
1574
|
-
input.review_notes || input.reason || null,
|
|
1575
|
-
promotedRef.kind,
|
|
1576
|
-
promotedRef.id,
|
|
1577
|
-
input.meta ? safeJson(input.meta, {}) : null,
|
|
1578
|
-
id
|
|
1579
|
-
);
|
|
1580
|
-
return { ok: true, id, status, reviewer, promoted_ref: promotedRef };
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
function memoryPromotionList(db, input = {}) {
|
|
1584
|
-
ensureMemoryConsolidationSchema(db);
|
|
1585
|
-
const where = ["scope=?"];
|
|
1586
|
-
const params = [scopeName(input.scope)];
|
|
1587
|
-
if (input.status) { where.push("status=?"); params.push(input.status); }
|
|
1588
|
-
if (input.proposal_kind || input.kind) { where.push("proposal_kind=?"); params.push(normalizeProposalKind(input.proposal_kind || input.kind)); }
|
|
1589
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
1590
|
-
if (input.department_name) { where.push("department_name=?"); params.push(normalizeDepartment(input.department_name)); }
|
|
1591
|
-
if (input.agent_name) { where.push("agent_name=?"); params.push(normalizeAgentName(input.agent_name)); }
|
|
1592
|
-
params.push(clampInt(input.limit, 50, 1, 500));
|
|
1593
|
-
const rows = db.prepare(`
|
|
1594
|
-
SELECT * FROM memory_promotion_proposal
|
|
1595
|
-
WHERE ${where.join(" AND ")}
|
|
1596
|
-
ORDER BY created_at DESC
|
|
1597
|
-
LIMIT ?
|
|
1598
|
-
`).all(...params).map(rowToPromotion);
|
|
1599
|
-
return { ok: true, count: rows.length, proposals: rows };
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
function activeClaims(db, input = {}, limit = 20) {
|
|
1603
|
-
if (!tableExists(db, "work_claim")) return [];
|
|
1604
|
-
const where = ["status IN ('active','stale')"];
|
|
1605
|
-
const params = [];
|
|
1606
|
-
if (input.project) { where.push("project=?"); params.push(input.project); }
|
|
1607
|
-
params.push(limit);
|
|
1608
|
-
return getRows(db, "work_claim", `
|
|
1609
|
-
SELECT id, project, agent_name, claim_kind, scope_value, scope_key, summary, claimed_at, heartbeat_at, expires_at, status
|
|
1610
|
-
FROM work_claim
|
|
1611
|
-
WHERE ${where.join(" AND ")}
|
|
1612
|
-
ORDER BY CASE status WHEN 'stale' THEN 2 ELSE 1 END DESC, expires_at ASC
|
|
1613
|
-
LIMIT ?
|
|
1614
|
-
`, params);
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
function pendingApprovals(db, input = {}, limit = 20) {
|
|
1618
|
-
if (!tableExists(db, "approval_request")) return [];
|
|
1619
|
-
const where = ["status='pending'"];
|
|
1620
|
-
const params = [];
|
|
1621
|
-
if (input.project) { where.push("(project=? OR project IS NULL)"); params.push(input.project); }
|
|
1622
|
-
params.push(limit);
|
|
1623
|
-
return getRows(db, "approval_request", `
|
|
1624
|
-
SELECT id, project, request_kind, resource_kind, resource_key, permission, requester_agent, owner_agent, reason, requested_at, expires_at, status
|
|
1625
|
-
FROM approval_request
|
|
1626
|
-
WHERE ${where.join(" AND ")}
|
|
1627
|
-
ORDER BY requested_at DESC
|
|
1628
|
-
LIMIT ?
|
|
1629
|
-
`, params);
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
function companyRemBrief(db, input = {}) {
|
|
1633
|
-
ensureMemoryConsolidationSchema(db);
|
|
1634
|
-
const days = clampInt(input.days, 1, 1, 30);
|
|
1635
|
-
const since = input.since || new Date(Date.now() - days * 86400000).toISOString();
|
|
1636
|
-
const journals = departmentJournalList(db, Object.assign({}, input, { since, limit: 30 })).journals || [];
|
|
1637
|
-
const sleepNotes = agentSleepNoteList(db, Object.assign({}, input, { since, limit: 30 })).notes || [];
|
|
1638
|
-
const proposals = memoryPromotionList(db, Object.assign({}, input, { status: "proposed", limit: 50 })).proposals || [];
|
|
1639
|
-
const claims = activeClaims(db, input, 30);
|
|
1640
|
-
const approvals = pendingApprovals(db, input, 30);
|
|
1641
|
-
const status = memoryLayerStatus(db, Object.assign({}, input, { since, days }));
|
|
1642
|
-
const remRuns = memoryConsolidationList(db, Object.assign({}, input, { phase: "rem", limit: 5 })).runs || [];
|
|
1643
|
-
|
|
1644
|
-
const lines = [];
|
|
1645
|
-
lines.push("# Coordinator REM Brief");
|
|
1646
|
-
lines.push("");
|
|
1647
|
-
lines.push(`Window: ${since} -> ${nowIso()}`);
|
|
1648
|
-
if (input.project) lines.push(`Project: ${input.project}`);
|
|
1649
|
-
lines.push("");
|
|
1650
|
-
lines.push("## Situation");
|
|
1651
|
-
lines.push(`- Department journal entries: ${journals.length}`);
|
|
1652
|
-
lines.push(`- Agent sleep notes: ${sleepNotes.length}`);
|
|
1653
|
-
lines.push(`- Promotion proposals needing review: ${proposals.length}`);
|
|
1654
|
-
lines.push(`- Active/stale claims: ${claims.length}`);
|
|
1655
|
-
lines.push(`- Pending approvals: ${approvals.length}`);
|
|
1656
|
-
lines.push(`- Recent REM runs: ${remRuns.length}`);
|
|
1657
|
-
lines.push("");
|
|
1658
|
-
|
|
1659
|
-
const pushRows = (title, rows, formatter, max = 10) => {
|
|
1660
|
-
lines.push(`## ${title}`);
|
|
1661
|
-
if (!rows.length) lines.push("- none");
|
|
1662
|
-
for (const row of rows.slice(0, max)) lines.push(formatter(row));
|
|
1663
|
-
lines.push("");
|
|
1664
|
-
};
|
|
1665
|
-
pushRows("Open Promotion Proposals", proposals, (p) => `- #${p.id} ${p.proposal_kind} ${p.project || ""} ${p.title}`.trim(), 12);
|
|
1666
|
-
pushRows("Pending Approvals", approvals, (a) => `- #${a.id} ${a.requester_agent} requests ${a.permission} on ${a.resource_kind}:${a.resource_key}${a.owner_agent ? ` from ${a.owner_agent}` : ""}`, 12);
|
|
1667
|
-
pushRows("Claims", claims, (c) => `- #${c.id} ${c.status} ${c.agent_name} ${c.claim_kind || "scope"}:${c.scope_value || c.scope_key || c.file_path || ""} until ${c.expires_at || "unknown"}`, 12);
|
|
1668
|
-
pushRows("Department Journals", journals, (j) => `- #${j.id} ${j.department_name}${j.project ? `/${j.project}` : ""}: ${compactContent(j.progress || j.blockers || j.risks || "", 180) || "(empty)"}`, 8);
|
|
1669
|
-
pushRows("Agent Sleep Notes", sleepNotes, (n) => `- #${n.id} ${n.agent_name}${n.project ? `/${n.project}` : ""}: ${compactContent(n.learned || n.uncertainty || n.recurring_errors || "", 180) || "(empty)"}`, 8);
|
|
1670
|
-
lines.push("## Required Coordinator Decisions");
|
|
1671
|
-
if (proposals.length) lines.push("- Review proposed promotions and decide approved/rejected/promoted.");
|
|
1672
|
-
if (approvals.length) lines.push("- Decide pending approvals or route to owners.");
|
|
1673
|
-
if (claims.some((c) => c.status === "stale")) lines.push("- Recover or transfer stale claims.");
|
|
1674
|
-
if (!proposals.length && !approvals.length && !claims.some((c) => c.status === "stale")) lines.push("- none");
|
|
1675
|
-
lines.push("");
|
|
1676
|
-
lines.push("Rule: this brief is management input. It does not promote truth by itself.");
|
|
1677
|
-
|
|
1678
|
-
const markdown = lines.join("\n");
|
|
1679
|
-
let briefId = null;
|
|
1680
|
-
if (input.write_brief === true && tableExists(db, "agent_brief")) {
|
|
1681
|
-
const coordinator = normalizeAgentName(input.coordinator_agent || "agent-a");
|
|
1682
|
-
const info = db.prepare("INSERT INTO agent_brief (agent_name, source_agent, content, meta_json) VALUES (?,?,?,?)")
|
|
1683
|
-
.run(coordinator, normalizeAgentName(input.source_agent || "mnemo-rem"), markdown, safeJson({ kind: "company_rem_brief", project: input.project || null, source_counts: status.source_counts }, {}));
|
|
1684
|
-
briefId = info.lastInsertRowid;
|
|
1685
|
-
}
|
|
1686
|
-
return {
|
|
1687
|
-
ok: true,
|
|
1688
|
-
generated_at: nowIso(),
|
|
1689
|
-
scope: scopeName(input.scope),
|
|
1690
|
-
project: input.project || null,
|
|
1691
|
-
markdown,
|
|
1692
|
-
brief_id: briefId,
|
|
1693
|
-
counts: {
|
|
1694
|
-
journals: journals.length,
|
|
1695
|
-
sleep_notes: sleepNotes.length,
|
|
1696
|
-
proposals: proposals.length,
|
|
1697
|
-
claims: claims.length,
|
|
1698
|
-
approvals: approvals.length,
|
|
1699
|
-
rem_runs: remRuns.length,
|
|
1700
|
-
},
|
|
1701
|
-
proposals,
|
|
1702
|
-
pending_approvals: approvals,
|
|
1703
|
-
active_claims: claims,
|
|
1704
|
-
status,
|
|
1705
|
-
};
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
const MEMORY_CONSOLIDATION_TOOL_DEFS = {
|
|
1709
|
-
mem_memory_layer_status: {
|
|
1710
|
-
description: "Show Mnemo's canonical memory layers: session, daily, long_term, recall, and REM. Use this before adding any runtime gateway-like memory path.",
|
|
1711
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, agent_name: { type: "string" }, project: { type: "string" }, days: { type: "integer", default: 7 }, since: { type: "string" } } },
|
|
1712
|
-
},
|
|
1713
|
-
mem_memory_rem_plan: {
|
|
1714
|
-
description: "Return the next safe Memory/REM consolidation phases and exact Mnemo tool calls. Does not write.",
|
|
1715
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, agent_name: { type: "string" }, project: { type: "string" }, days: { type: "integer" }, date: { type: "string" } } },
|
|
1716
|
-
},
|
|
1717
|
-
mem_memory_rem_run: {
|
|
1718
|
-
description: "Run a deterministic Mnemo memory consolidation pass: light, daily, deep, or rem. Writes a draft run and a semantic memory_consolidation row; never deletes or rewrites old facts.",
|
|
1719
|
-
inputSchema: {
|
|
1720
|
-
type: "object",
|
|
1721
|
-
properties: {
|
|
1722
|
-
scope: { type: "string" },
|
|
1723
|
-
agent_name: { type: "string" },
|
|
1724
|
-
project: { type: "string" },
|
|
1725
|
-
phase: { type: "string", enum: ["light", "daily", "deep", "rem"], default: "light" },
|
|
1726
|
-
days: { type: "integer" },
|
|
1727
|
-
date: { type: "string" },
|
|
1728
|
-
limit: { type: "integer" },
|
|
1729
|
-
status: { type: "string" },
|
|
1730
|
-
confidence: { type: "string" },
|
|
1731
|
-
review_status: { type: "string" },
|
|
1732
|
-
promote_to_memory: { type: "boolean", default: true },
|
|
1733
|
-
meta: { type: "object" },
|
|
1734
|
-
},
|
|
1735
|
-
},
|
|
1736
|
-
},
|
|
1737
|
-
mem_memory_consolidation_list: {
|
|
1738
|
-
description: "List memory consolidation runs with selected source refs, source counts, status, confidence, and promoted memory id.",
|
|
1739
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, agent_name: { type: "string" }, project: { type: "string" }, phase: { type: "string" }, status: { type: "string" }, limit: { type: "integer" } } },
|
|
1740
|
-
},
|
|
1741
|
-
mem_department_journal_add: {
|
|
1742
|
-
description: "Append a department diary entry: progress, blockers, risks, open questions, dependencies, and foreign-scope requests. Not official truth until promoted.",
|
|
1743
|
-
inputSchema: {
|
|
1744
|
-
type: "object",
|
|
1745
|
-
properties: {
|
|
1746
|
-
scope: { type: "string" },
|
|
1747
|
-
department_name: { type: "string" },
|
|
1748
|
-
department: { type: "string" },
|
|
1749
|
-
agent_name: { type: "string" },
|
|
1750
|
-
project: { type: "string" },
|
|
1751
|
-
journal_date: { type: "string" },
|
|
1752
|
-
date: { type: "string" },
|
|
1753
|
-
progress: { type: "string" },
|
|
1754
|
-
summary: { type: "string" },
|
|
1755
|
-
blockers: { type: "string" },
|
|
1756
|
-
risks: { type: "string" },
|
|
1757
|
-
open_questions: { type: "string" },
|
|
1758
|
-
dependencies: { anyOf: [{ type: "array", items: { type: "string" } }, { type: "string" }] },
|
|
1759
|
-
foreign_scope_requests: { anyOf: [{ type: "array", items: { type: "string" } }, { type: "string" }] },
|
|
1760
|
-
access_requests: { anyOf: [{ type: "array", items: { type: "string" } }, { type: "string" }] },
|
|
1761
|
-
status: { type: "string" },
|
|
1762
|
-
meta: { type: "object" },
|
|
1763
|
-
},
|
|
1764
|
-
required: ["department_name"],
|
|
1765
|
-
},
|
|
1766
|
-
},
|
|
1767
|
-
mem_department_journal_list: {
|
|
1768
|
-
description: "List department diary entries for REM, handoff, and coordinator review.",
|
|
1769
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, department_name: { type: "string" }, department: { type: "string" }, agent_name: { type: "string" }, project: { type: "string" }, status: { type: "string" }, since: { type: "string" }, limit: { type: "integer" } } },
|
|
1770
|
-
},
|
|
1771
|
-
mem_agent_sleep_note_add: {
|
|
1772
|
-
description: "Append personal agent REM notes: learned, uncertainty, recurring errors, needed context, and improvement ideas. Not official truth until promoted.",
|
|
1773
|
-
inputSchema: {
|
|
1774
|
-
type: "object",
|
|
1775
|
-
properties: {
|
|
1776
|
-
scope: { type: "string" },
|
|
1777
|
-
agent_name: { type: "string" },
|
|
1778
|
-
project: { type: "string" },
|
|
1779
|
-
note_date: { type: "string" },
|
|
1780
|
-
date: { type: "string" },
|
|
1781
|
-
learned: { type: "string" },
|
|
1782
|
-
uncertainty: { type: "string" },
|
|
1783
|
-
recurring_errors: { type: "string" },
|
|
1784
|
-
needed_context: { type: "string" },
|
|
1785
|
-
improvement_idea: { type: "string" },
|
|
1786
|
-
source_ref: { type: "string" },
|
|
1787
|
-
status: { type: "string" },
|
|
1788
|
-
meta: { type: "object" },
|
|
1789
|
-
},
|
|
1790
|
-
required: ["agent_name"],
|
|
1791
|
-
},
|
|
1792
|
-
},
|
|
1793
|
-
mem_agent_sleep_note_list: {
|
|
1794
|
-
description: "List personal agent REM notes.",
|
|
1795
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, agent_name: { type: "string" }, project: { type: "string" }, status: { type: "string" }, since: { type: "string" }, limit: { type: "integer" } } },
|
|
1796
|
-
},
|
|
1797
|
-
mem_memory_promotion_propose: {
|
|
1798
|
-
description: "Propose a REM finding for official promotion. Creates a review item only; it does not change company truth.",
|
|
1799
|
-
inputSchema: {
|
|
1800
|
-
type: "object",
|
|
1801
|
-
properties: {
|
|
1802
|
-
scope: { type: "string" },
|
|
1803
|
-
proposal_kind: { type: "string", enum: ["decision", "rule", "project_memory", "risk", "owner_question", "scar", "runbook"] },
|
|
1804
|
-
kind: { type: "string" },
|
|
1805
|
-
title: { type: "string" },
|
|
1806
|
-
body: { type: "string" },
|
|
1807
|
-
summary: { type: "string" },
|
|
1808
|
-
question: { type: "string" },
|
|
1809
|
-
project: { type: "string" },
|
|
1810
|
-
department_name: { type: "string" },
|
|
1811
|
-
agent_name: { type: "string" },
|
|
1812
|
-
source_kind: { type: "string" },
|
|
1813
|
-
source_id: { type: "string" },
|
|
1814
|
-
evidence: { type: "array", items: { type: "object" } },
|
|
1815
|
-
status: { type: "string" },
|
|
1816
|
-
meta: { type: "object" },
|
|
1817
|
-
},
|
|
1818
|
-
},
|
|
1819
|
-
},
|
|
1820
|
-
mem_memory_promotion_list: {
|
|
1821
|
-
description: "List REM promotion proposals waiting for coordinator/owner review.",
|
|
1822
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, status: { type: "string" }, proposal_kind: { type: "string" }, kind: { type: "string" }, project: { type: "string" }, department_name: { type: "string" }, agent_name: { type: "string" }, limit: { type: "integer" } } },
|
|
1823
|
-
},
|
|
1824
|
-
mem_memory_promotion_decide: {
|
|
1825
|
-
description: "Approve, reject, or promote a REM promotion proposal. Promotion is an explicit Mnemo API action with reviewer attribution.",
|
|
1826
|
-
inputSchema: {
|
|
1827
|
-
type: "object",
|
|
1828
|
-
properties: {
|
|
1829
|
-
id: { type: "integer" },
|
|
1830
|
-
proposal_id: { type: "integer" },
|
|
1831
|
-
status: { type: "string", enum: ["approved", "rejected", "promoted"] },
|
|
1832
|
-
decision: { type: "string" },
|
|
1833
|
-
reviewer: { type: "string" },
|
|
1834
|
-
decided_by: { type: "string" },
|
|
1835
|
-
approved_by: { type: "string" },
|
|
1836
|
-
review_notes: { type: "string" },
|
|
1837
|
-
reason: { type: "string" },
|
|
1838
|
-
promote: { type: "boolean" },
|
|
1839
|
-
meta: { type: "object" },
|
|
1840
|
-
},
|
|
1841
|
-
required: ["id", "reviewer", "status"],
|
|
1842
|
-
},
|
|
1843
|
-
},
|
|
1844
|
-
mem_company_rem_brief: {
|
|
1845
|
-
description: "Generate a coordinator morning brief from department journals, sleep notes, promotion proposals, active claims, pending approvals, and REM state. Optionally writes an agent_brief.",
|
|
1846
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, project: { type: "string" }, days: { type: "integer", default: 1 }, since: { type: "string" }, write_brief: { type: "boolean" }, coordinator_agent: { type: "string" }, source_agent: { type: "string" } } },
|
|
1847
|
-
},
|
|
1848
|
-
mem_dreammode_run: {
|
|
1849
|
-
description: "Run the nightly human-style Dreammode: classify the day into wrong made, right made, praise received, called out, broke things, and lessons. Also runs REM phases by default. Draft only; no automatic truth promotion.",
|
|
1850
|
-
inputSchema: {
|
|
1851
|
-
type: "object",
|
|
1852
|
-
properties: {
|
|
1853
|
-
scope: { type: "string" },
|
|
1854
|
-
agent_name: { type: "string" },
|
|
1855
|
-
project: { type: "string" },
|
|
1856
|
-
dream_date: { type: "string" },
|
|
1857
|
-
date: { type: "string" },
|
|
1858
|
-
since: { type: "string" },
|
|
1859
|
-
until: { type: "string" },
|
|
1860
|
-
limit: { type: "integer" },
|
|
1861
|
-
force: { type: "boolean" },
|
|
1862
|
-
write_brief: { type: "boolean", default: true },
|
|
1863
|
-
coordinator_agent: { type: "string" },
|
|
1864
|
-
run_rem_phases: { type: "boolean", default: true },
|
|
1865
|
-
phases: { type: "array", items: { type: "string", enum: ["light", "daily", "deep", "rem"] } },
|
|
1866
|
-
rem_days: { type: "integer", default: 7 },
|
|
1867
|
-
status: { type: "string" },
|
|
1868
|
-
meta: { type: "object" },
|
|
1869
|
-
},
|
|
1870
|
-
},
|
|
1871
|
-
},
|
|
1872
|
-
mem_dreammode_status: {
|
|
1873
|
-
description: "List recent Dreammode runs with human-style buckets and lessons.",
|
|
1874
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, agent_name: { type: "string" }, project: { type: "string" }, dream_date: { type: "string" }, date: { type: "string" }, limit: { type: "integer" } } },
|
|
1875
|
-
},
|
|
1876
|
-
};
|
|
1877
|
-
|
|
1878
|
-
function handleMemoryConsolidationTool(db, name, input = {}) {
|
|
1879
|
-
if (name === "mem_memory_layer_status") return { handled: true, result: memoryLayerStatus(db, input || {}) };
|
|
1880
|
-
if (name === "mem_memory_rem_plan") return { handled: true, result: memoryRemPlan(db, input || {}) };
|
|
1881
|
-
if (name === "mem_memory_rem_run") return { handled: true, result: memoryRemRun(db, input || {}) };
|
|
1882
|
-
if (name === "mem_memory_consolidation_list") return { handled: true, result: memoryConsolidationList(db, input || {}) };
|
|
1883
|
-
if (name === "mem_department_journal_add") return { handled: true, result: departmentJournalAdd(db, input || {}) };
|
|
1884
|
-
if (name === "mem_department_journal_list") return { handled: true, result: departmentJournalList(db, input || {}) };
|
|
1885
|
-
if (name === "mem_agent_sleep_note_add") return { handled: true, result: agentSleepNoteAdd(db, input || {}) };
|
|
1886
|
-
if (name === "mem_agent_sleep_note_list") return { handled: true, result: agentSleepNoteList(db, input || {}) };
|
|
1887
|
-
if (name === "mem_memory_promotion_propose") return { handled: true, result: memoryPromotionPropose(db, input || {}) };
|
|
1888
|
-
if (name === "mem_memory_promotion_list") return { handled: true, result: memoryPromotionList(db, input || {}) };
|
|
1889
|
-
if (name === "mem_memory_promotion_decide") return { handled: true, result: memoryPromotionDecide(db, input || {}) };
|
|
1890
|
-
if (name === "mem_company_rem_brief") return { handled: true, result: companyRemBrief(db, input || {}) };
|
|
1891
|
-
if (name === "mem_dreammode_run") return { handled: true, result: dreammodeRun(db, input || {}) };
|
|
1892
|
-
if (name === "mem_dreammode_status") return { handled: true, result: dreammodeStatus(db, input || {}) };
|
|
1893
|
-
return { handled: false };
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
module.exports = {
|
|
1897
|
-
MEMORY_CONSOLIDATION_TOOL_DEFS,
|
|
1898
|
-
ensureMemoryConsolidationSchema,
|
|
1899
|
-
handleMemoryConsolidationTool,
|
|
1900
|
-
memoryLayerStatus,
|
|
1901
|
-
memoryRemPlan,
|
|
1902
|
-
memoryRemRun,
|
|
1903
|
-
memoryConsolidationList,
|
|
1904
|
-
departmentJournalAdd,
|
|
1905
|
-
departmentJournalList,
|
|
1906
|
-
agentSleepNoteAdd,
|
|
1907
|
-
agentSleepNoteList,
|
|
1908
|
-
memoryPromotionPropose,
|
|
1909
|
-
memoryPromotionList,
|
|
1910
|
-
memoryPromotionDecide,
|
|
1911
|
-
companyRemBrief,
|
|
1912
|
-
dreammodeRun,
|
|
1913
|
-
dreammodeStatus,
|
|
1914
|
-
};
|