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,627 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const DEFAULT_SCOPE = "default";
|
|
4
|
-
const DEFAULT_TTL_MINUTES = 240;
|
|
5
|
-
|
|
6
|
-
function cleanScope(scope) {
|
|
7
|
-
return String(scope || DEFAULT_SCOPE).toLowerCase().replace(/[^a-z0-9_-]/g, "") || DEFAULT_SCOPE;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function normalizeAgentName(name) {
|
|
11
|
-
return String(name || "").trim().toLowerCase();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function normalizeClaimKind(value) {
|
|
15
|
-
const kind = String(value || "")
|
|
16
|
-
.trim()
|
|
17
|
-
.toLowerCase()
|
|
18
|
-
.replace(/[^a-z0-9]+/g, "_")
|
|
19
|
-
.replace(/^_+|_+$/g, "");
|
|
20
|
-
return kind || "scope";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function normalizeScopeKey(value) {
|
|
24
|
-
return String(value || "")
|
|
25
|
-
.trim()
|
|
26
|
-
.toLowerCase()
|
|
27
|
-
.replace(/[^a-z0-9]+/g, " ")
|
|
28
|
-
.trim();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function claimScopeKey(claimKind, scopeValue) {
|
|
32
|
-
return normalizeClaimKind(claimKind) + ":" + normalizeScopeKey(scopeValue);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function parseJson(value, fallback) {
|
|
36
|
-
if (value == null || value === "") return fallback;
|
|
37
|
-
if (typeof value !== "string") return value;
|
|
38
|
-
try { return JSON.parse(value); } catch { return fallback; }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function uniqueStrings(values) {
|
|
42
|
-
const out = [];
|
|
43
|
-
const seen = new Set();
|
|
44
|
-
for (const value of Array.isArray(values) ? values : []) {
|
|
45
|
-
const item = String(value || "").trim();
|
|
46
|
-
const key = item.toLowerCase();
|
|
47
|
-
if (!item || seen.has(key)) continue;
|
|
48
|
-
seen.add(key);
|
|
49
|
-
out.push(item);
|
|
50
|
-
}
|
|
51
|
-
return out;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function envOwner(envName, fallback) {
|
|
55
|
-
return normalizeAgentName(process.env[envName] || fallback || "");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function defaultProtectedScopeRules() {
|
|
59
|
-
return [
|
|
60
|
-
{
|
|
61
|
-
rule_key: "auth_login",
|
|
62
|
-
label: "Account, auth, login, session",
|
|
63
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_AUTH", "agent-a"),
|
|
64
|
-
risk_class: "live-risk",
|
|
65
|
-
claim_scope_value: "auth login",
|
|
66
|
-
patterns: [
|
|
67
|
-
"account.example", "/auth", " auth", "login", "logout", "session", "cookie",
|
|
68
|
-
"jwt", "oauth", "2fa", "mfa", "password reset", "whoami", "signin", "signup",
|
|
69
|
-
"google/callback", "github/callback"
|
|
70
|
-
],
|
|
71
|
-
required_evidence: ["login smoke test", "whoami/session check", "redirect check"]
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
rule_key: "account_settings_popup",
|
|
75
|
-
label: "Global account settings popup and user shell",
|
|
76
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_ACCOUNT_UI", "agent-a"),
|
|
77
|
-
risk_class: "normal-fix",
|
|
78
|
-
claim_scope_value: "account settings popup",
|
|
79
|
-
patterns: [
|
|
80
|
-
"settings popup", "account popup", "account settings", "global settings",
|
|
81
|
-
"personalization", "theme setting", "language preference", "brand_lang_pref",
|
|
82
|
-
"brand_locale", "sidebar account", "account menu", "mini popup", "user shell"
|
|
83
|
-
],
|
|
84
|
-
required_evidence: ["desktop popup smoke test", "light/dark setting check", "language setting check"]
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
rule_key: "billing_checkout",
|
|
88
|
-
label: "Billing, pricing, Stripe, VAT and checkout",
|
|
89
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_BILLING", "agent-a"),
|
|
90
|
-
risk_class: "billing-risk",
|
|
91
|
-
claim_scope_value: "billing checkout",
|
|
92
|
-
patterns: [
|
|
93
|
-
"billing", "invoice", "subscription", "stripe", "vatcheck", "vatcheckapi",
|
|
94
|
-
" vat", "checkout", "price", "pricing", "tier", "plan"
|
|
95
|
-
],
|
|
96
|
-
required_evidence: ["test checkout or mocked billing check", "VAT validation check"]
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
rule_key: "production_infra",
|
|
100
|
-
label: "Production infra, nginx, PM2, SSH and deploy",
|
|
101
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_INFRA", "agent-a"),
|
|
102
|
-
risk_class: "production",
|
|
103
|
-
claim_scope_value: "production infra",
|
|
104
|
-
patterns: [
|
|
105
|
-
"nginx", "vhost", "pm2", "systemctl", "restart", "deploy", "ssh ",
|
|
106
|
-
"server", "65er", "176er", "live system", "production"
|
|
107
|
-
],
|
|
108
|
-
required_evidence: ["health check", "pm2/nginx status or curl evidence"]
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
rule_key: "protected_final_artifacts",
|
|
112
|
-
label: "Locked final pages and no-touch artifacts",
|
|
113
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_DESIGN_LOCKS", "agent-c"),
|
|
114
|
-
risk_class: "live-risk",
|
|
115
|
-
claim_scope_value: "protected final artifacts",
|
|
116
|
-
patterns: [
|
|
117
|
-
"pitch/cold-email-pitch-v14.html", "artifact_lock", "locked final",
|
|
118
|
-
"no-touch", "do not touch", "nicht mehr angefasst"
|
|
119
|
-
],
|
|
120
|
-
required_evidence: ["explicit owner approval", "artifact lock override reference"]
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
rule_key: "portal_design_system",
|
|
124
|
-
label: "Portal dashboard skeleton and shared design system",
|
|
125
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_DESIGN", "agent-c"),
|
|
126
|
-
risk_class: "normal-fix",
|
|
127
|
-
claim_scope_value: "portal design system",
|
|
128
|
-
patterns: [
|
|
129
|
-
"dashboard skeleton", "sidebar width", "sidebar color", "body color",
|
|
130
|
-
"logo size", "shared design", "design system", "glassmorphism", "portal shell"
|
|
131
|
-
],
|
|
132
|
-
required_evidence: ["desktop screenshot or browser check", "mobile/responsive check when relevant"]
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
rule_key: "chat_runtime",
|
|
136
|
-
label: "Chat runtime, chat UI, skills and chat memory layer",
|
|
137
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_CHAT", "agent-b"),
|
|
138
|
-
risk_class: "normal-fix",
|
|
139
|
-
claim_scope_value: "chat runtime",
|
|
140
|
-
patterns: [
|
|
141
|
-
"chat.example", "/api/chat", "chat runtime", "chat login", "chat session",
|
|
142
|
-
"chat sidebar", "examplecorp-memory", "examplecorp-skills", "skills"
|
|
143
|
-
],
|
|
144
|
-
required_evidence: ["chat login smoke test", "chat API 200/401 check"]
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
rule_key: "portal_translations",
|
|
148
|
-
label: "Portal translations and language content",
|
|
149
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_TRANSLATIONS", "frida"),
|
|
150
|
-
risk_class: "normal-fix",
|
|
151
|
-
claim_scope_value: "portal translations",
|
|
152
|
-
patterns: [
|
|
153
|
-
"translation", "translations", "locale messages", "i18n", "language switcher",
|
|
154
|
-
"header footer translation", "unterseiten", "all languages", "107 languages"
|
|
155
|
-
],
|
|
156
|
-
required_evidence: ["English smoke check", "Swedish smoke check", "missing-key check"]
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
rule_key: "coordination_rules",
|
|
160
|
-
label: "Agent coordination, briefs, rules and Mnemo gates",
|
|
161
|
-
owner_agent: envOwner("MNEMO_SCOPE_OWNER_COORDINATION", "agent-a"),
|
|
162
|
-
risk_class: "coordination",
|
|
163
|
-
claim_scope_value: "coordination rules",
|
|
164
|
-
patterns: [
|
|
165
|
-
"agent coordination", "brief", "handoff", "work claim", "protected scope",
|
|
166
|
-
"mnemo gate", "mnemo plugin", "agent passport", "duplicate work", "mission control"
|
|
167
|
-
],
|
|
168
|
-
required_evidence: ["local smoke test", "documented example call"]
|
|
169
|
-
}
|
|
170
|
-
];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function ensureProtectedScopeSchema(db) {
|
|
174
|
-
db.exec(`
|
|
175
|
-
CREATE TABLE IF NOT EXISTS protected_scope_rule (
|
|
176
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
177
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
178
|
-
project TEXT,
|
|
179
|
-
rule_key TEXT NOT NULL,
|
|
180
|
-
label TEXT NOT NULL,
|
|
181
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
182
|
-
owner_agent TEXT,
|
|
183
|
-
required_approval_by TEXT,
|
|
184
|
-
risk_class TEXT NOT NULL DEFAULT 'normal-fix',
|
|
185
|
-
match_kind TEXT NOT NULL DEFAULT 'any',
|
|
186
|
-
patterns_json TEXT NOT NULL DEFAULT '[]',
|
|
187
|
-
required_claims_json TEXT NOT NULL DEFAULT '[]',
|
|
188
|
-
required_evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
189
|
-
notes TEXT,
|
|
190
|
-
source_kind TEXT NOT NULL DEFAULT 'manual',
|
|
191
|
-
meta_json TEXT,
|
|
192
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
193
|
-
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
194
|
-
UNIQUE(scope, rule_key)
|
|
195
|
-
);
|
|
196
|
-
CREATE INDEX IF NOT EXISTS idx_protected_scope_status ON protected_scope_rule(scope, status, rule_key);
|
|
197
|
-
CREATE INDEX IF NOT EXISTS idx_protected_scope_project ON protected_scope_rule(project, status);
|
|
198
|
-
CREATE INDEX IF NOT EXISTS idx_protected_scope_owner ON protected_scope_rule(owner_agent, status);
|
|
199
|
-
`);
|
|
200
|
-
const cols = db.prepare("PRAGMA table_info(protected_scope_rule)").all().map((c) => c.name);
|
|
201
|
-
const missing = (name) => !cols.includes(name);
|
|
202
|
-
if (missing("required_approval_by")) db.exec("ALTER TABLE protected_scope_rule ADD COLUMN required_approval_by TEXT");
|
|
203
|
-
if (missing("source_kind")) db.exec("ALTER TABLE protected_scope_rule ADD COLUMN source_kind TEXT NOT NULL DEFAULT 'manual'");
|
|
204
|
-
if (missing("meta_json")) db.exec("ALTER TABLE protected_scope_rule ADD COLUMN meta_json TEXT");
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function ensureWorkClaimSchemaForLookup(db) {
|
|
208
|
-
db.exec(`
|
|
209
|
-
CREATE TABLE IF NOT EXISTS work_claim (
|
|
210
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
211
|
-
project TEXT NOT NULL,
|
|
212
|
-
file_path TEXT NOT NULL,
|
|
213
|
-
agent_name TEXT NOT NULL,
|
|
214
|
-
summary TEXT,
|
|
215
|
-
claim_kind TEXT NOT NULL DEFAULT 'file',
|
|
216
|
-
scope_value TEXT,
|
|
217
|
-
scope_key TEXT,
|
|
218
|
-
claimed_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
219
|
-
heartbeat_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
220
|
-
stale_after_sec INTEGER NOT NULL DEFAULT 1800,
|
|
221
|
-
expires_at TEXT NOT NULL,
|
|
222
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
223
|
-
released_at TEXT,
|
|
224
|
-
takeover_count INTEGER NOT NULL DEFAULT 0,
|
|
225
|
-
meta_json TEXT
|
|
226
|
-
);
|
|
227
|
-
CREATE INDEX IF NOT EXISTS idx_work_claim_scope_active ON work_claim(project, scope_key, status, expires_at);
|
|
228
|
-
CREATE INDEX IF NOT EXISTS idx_work_claim_agent_status ON work_claim(agent_name, status, claimed_at DESC);
|
|
229
|
-
CREATE INDEX IF NOT EXISTS idx_work_claim_kind_status ON work_claim(claim_kind, status, claimed_at DESC);
|
|
230
|
-
`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function ensureOverrideSchemaForLookup(db) {
|
|
234
|
-
db.exec(`
|
|
235
|
-
CREATE TABLE IF NOT EXISTS override_log (
|
|
236
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
237
|
-
scope TEXT NOT NULL DEFAULT 'default',
|
|
238
|
-
project TEXT,
|
|
239
|
-
system_name TEXT,
|
|
240
|
-
agent_name TEXT,
|
|
241
|
-
gate_kind TEXT NOT NULL,
|
|
242
|
-
reason TEXT NOT NULL,
|
|
243
|
-
approved_by TEXT,
|
|
244
|
-
starts_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
245
|
-
expires_at TEXT,
|
|
246
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
247
|
-
notes TEXT,
|
|
248
|
-
meta_json TEXT,
|
|
249
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
250
|
-
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
251
|
-
);
|
|
252
|
-
CREATE INDEX IF NOT EXISTS idx_override_scope_status ON override_log(scope, status, starts_at DESC);
|
|
253
|
-
CREATE INDEX IF NOT EXISTS idx_override_project_gate ON override_log(project, gate_kind, status);
|
|
254
|
-
`);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function seedDefaultProtectedScopes(db, options = {}) {
|
|
258
|
-
ensureProtectedScopeSchema(db);
|
|
259
|
-
if (process.env.MNEMO_PROTECTED_SCOPE_SEED_DEFAULTS === "0" && !options.force) {
|
|
260
|
-
return { ok: true, skipped: "disabled", count: 0, scope: cleanScope(options.scope) };
|
|
261
|
-
}
|
|
262
|
-
const scope = cleanScope(options.scope || process.env.MNEMO_DEFAULT_SCOPE || DEFAULT_SCOPE);
|
|
263
|
-
const rules = Array.isArray(options.rules) && options.rules.length ? options.rules : defaultProtectedScopeRules();
|
|
264
|
-
const insert = db.prepare(`
|
|
265
|
-
INSERT OR IGNORE INTO protected_scope_rule
|
|
266
|
-
(scope, project, rule_key, label, status, owner_agent, required_approval_by, risk_class, match_kind, patterns_json, required_claims_json, required_evidence_json, notes, source_kind, meta_json)
|
|
267
|
-
VALUES
|
|
268
|
-
(?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?, 'default', ?)
|
|
269
|
-
`);
|
|
270
|
-
const update = db.prepare(`
|
|
271
|
-
UPDATE protected_scope_rule
|
|
272
|
-
SET label=?,
|
|
273
|
-
risk_class=?,
|
|
274
|
-
match_kind=?,
|
|
275
|
-
patterns_json=?,
|
|
276
|
-
required_claims_json=?,
|
|
277
|
-
required_evidence_json=?,
|
|
278
|
-
notes=?,
|
|
279
|
-
meta_json=?,
|
|
280
|
-
updated_at=strftime('%Y-%m-%dT%H:%M:%fZ','now')
|
|
281
|
-
WHERE scope=? AND rule_key=? AND source_kind='default'
|
|
282
|
-
`);
|
|
283
|
-
const txn = db.transaction(() => {
|
|
284
|
-
for (const rule of rules) {
|
|
285
|
-
const requiredClaims = rule.required_claims || [{
|
|
286
|
-
claim_kind: "protected_scope",
|
|
287
|
-
scope_value: rule.claim_scope_value || rule.rule_key
|
|
288
|
-
}];
|
|
289
|
-
const meta = Object.assign({}, rule.meta || {}, { seeded_by: "protected_scope_gate" });
|
|
290
|
-
insert.run(
|
|
291
|
-
scope,
|
|
292
|
-
rule.project || null,
|
|
293
|
-
rule.rule_key,
|
|
294
|
-
rule.label,
|
|
295
|
-
rule.owner_agent || null,
|
|
296
|
-
rule.required_approval_by || null,
|
|
297
|
-
rule.risk_class || "normal-fix",
|
|
298
|
-
rule.match_kind || "any",
|
|
299
|
-
JSON.stringify(uniqueStrings(rule.patterns || [])),
|
|
300
|
-
JSON.stringify(requiredClaims),
|
|
301
|
-
JSON.stringify(uniqueStrings(rule.required_evidence || [])),
|
|
302
|
-
rule.notes || null,
|
|
303
|
-
JSON.stringify(meta)
|
|
304
|
-
);
|
|
305
|
-
update.run(
|
|
306
|
-
rule.label,
|
|
307
|
-
rule.risk_class || "normal-fix",
|
|
308
|
-
rule.match_kind || "any",
|
|
309
|
-
JSON.stringify(uniqueStrings(rule.patterns || [])),
|
|
310
|
-
JSON.stringify(requiredClaims),
|
|
311
|
-
JSON.stringify(uniqueStrings(rule.required_evidence || [])),
|
|
312
|
-
rule.notes || null,
|
|
313
|
-
JSON.stringify(meta),
|
|
314
|
-
scope,
|
|
315
|
-
rule.rule_key
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
txn();
|
|
320
|
-
return { ok: true, scope, count: rules.length };
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function protectedScopeRuleRow(row) {
|
|
324
|
-
return Object.assign({}, row, {
|
|
325
|
-
patterns: parseJson(row.patterns_json, []),
|
|
326
|
-
required_claims: parseJson(row.required_claims_json, []),
|
|
327
|
-
required_evidence: parseJson(row.required_evidence_json, []),
|
|
328
|
-
meta: parseJson(row.meta_json, {})
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function listProtectedScopeRules(db, input = {}) {
|
|
333
|
-
ensureProtectedScopeSchema(db);
|
|
334
|
-
seedDefaultProtectedScopes(db, { scope: input.scope });
|
|
335
|
-
const where = ["scope=?"];
|
|
336
|
-
const params = [cleanScope(input.scope || process.env.MNEMO_DEFAULT_SCOPE || DEFAULT_SCOPE)];
|
|
337
|
-
if (input.project) {
|
|
338
|
-
where.push("(project=? OR project IS NULL)");
|
|
339
|
-
params.push(input.project);
|
|
340
|
-
}
|
|
341
|
-
if (input.rule_key) {
|
|
342
|
-
where.push("rule_key=?");
|
|
343
|
-
params.push(input.rule_key);
|
|
344
|
-
}
|
|
345
|
-
if (input.owner_agent) {
|
|
346
|
-
where.push("owner_agent=?");
|
|
347
|
-
params.push(normalizeAgentName(input.owner_agent));
|
|
348
|
-
}
|
|
349
|
-
if (input.status) {
|
|
350
|
-
where.push("status=?");
|
|
351
|
-
params.push(input.status);
|
|
352
|
-
} else {
|
|
353
|
-
where.push("status!='deleted'");
|
|
354
|
-
}
|
|
355
|
-
params.push(Math.min(Math.max(parseInt(input.limit || 100, 10) || 100, 1), 500));
|
|
356
|
-
const rows = db.prepare("SELECT * FROM protected_scope_rule WHERE " + where.join(" AND ") + " ORDER BY rule_key LIMIT ?").all(...params).map(protectedScopeRuleRow);
|
|
357
|
-
return { ok: true, count: rows.length, rules: rows };
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function buildHaystack(input = {}) {
|
|
361
|
-
const parts = [];
|
|
362
|
-
for (const key of ["task", "summary", "action_type", "environment", "tool_name"]) {
|
|
363
|
-
if (input[key]) parts.push(String(input[key]));
|
|
364
|
-
}
|
|
365
|
-
for (const key of ["files", "urls", "routes", "domains", "system_names", "topics", "commands"]) {
|
|
366
|
-
const values = Array.isArray(input[key]) ? input[key] : [];
|
|
367
|
-
for (const value of values) parts.push(String(value || ""));
|
|
368
|
-
}
|
|
369
|
-
return parts.join("\n").replace(/\\/g, "/").toLowerCase();
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function patternMatches(pattern, haystack) {
|
|
373
|
-
const raw = String(pattern || "").trim();
|
|
374
|
-
if (!raw) return false;
|
|
375
|
-
if (raw.startsWith("re:")) {
|
|
376
|
-
try { return new RegExp(raw.slice(3), "i").test(haystack); } catch { return false; }
|
|
377
|
-
}
|
|
378
|
-
return haystack.includes(raw.toLowerCase());
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function ruleMatches(rule, haystack) {
|
|
382
|
-
const patterns = parseJson(rule.patterns_json, []);
|
|
383
|
-
if (!patterns.length) return false;
|
|
384
|
-
const matches = patterns.filter((pattern) => patternMatches(pattern, haystack));
|
|
385
|
-
if (String(rule.match_kind || "any").toLowerCase() === "all") {
|
|
386
|
-
return matches.length === patterns.length ? matches : [];
|
|
387
|
-
}
|
|
388
|
-
return matches;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function isReadLikeText(text) {
|
|
392
|
-
const trimmed = String(text || "").trim().toLowerCase();
|
|
393
|
-
return /^(get-content|select-string|rg\b|grep\b|cat\b|type\b|dir\b|ls\b|git status\b|git diff\b|git show\b|npm test\b|node --check\b)/.test(trimmed);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
function isWriteLike(input = {}, haystack = "") {
|
|
397
|
-
if (process.env.MNEMO_PROTECTED_SCOPE_STRICT_READ === "1") return true;
|
|
398
|
-
const action = String(input.action_type || "").toLowerCase();
|
|
399
|
-
if (["code_edit", "deploy", "external_comm", "write", "delete", "move"].includes(action)) return true;
|
|
400
|
-
if (action === "code_read" || action === "read") return false;
|
|
401
|
-
if (isReadLikeText(input.task) || isReadLikeText(input.summary)) return false;
|
|
402
|
-
return /\b(apply_patch|set-content|new-item|remove-item|move-item|copy-item|git push|pm2 restart|pm2 reload|systemctl|nginx -s|rsync|scp|deploy)\b/i.test(haystack);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function activeClaimRows(db, input = {}) {
|
|
406
|
-
ensureWorkClaimSchemaForLookup(db);
|
|
407
|
-
const project = input.project || "unknown";
|
|
408
|
-
const key = claimScopeKey(input.claim_kind, input.scope_value);
|
|
409
|
-
const agent = normalizeAgentName(input.agent_name);
|
|
410
|
-
if (!agent || !key.includes(":")) return [];
|
|
411
|
-
const rows = db.prepare(
|
|
412
|
-
"SELECT * FROM work_claim " +
|
|
413
|
-
"WHERE scope_key=? AND agent_name=? AND status='active' AND expires_at >= strftime('%Y-%m-%dT%H:%M:%fZ','now') " +
|
|
414
|
-
"AND (project=? OR project='*' OR project='unknown' OR ?='unknown') " +
|
|
415
|
-
"ORDER BY expires_at DESC LIMIT 10"
|
|
416
|
-
).all(key, agent, project, project);
|
|
417
|
-
return rows.map((row) => Object.assign({}, row, { meta: parseJson(row.meta_json, {}) }));
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function activeOverrideRows(db, input = {}) {
|
|
421
|
-
ensureOverrideSchemaForLookup(db);
|
|
422
|
-
const scope = cleanScope(input.scope || process.env.MNEMO_DEFAULT_SCOPE || DEFAULT_SCOPE);
|
|
423
|
-
const project = input.project || null;
|
|
424
|
-
const agent = normalizeAgentName(input.agent_name);
|
|
425
|
-
const ruleKey = String(input.rule_key || "").trim();
|
|
426
|
-
const gateKinds = uniqueStrings(["protected_scope", ruleKey ? "protected_scope:" + ruleKey : "", ruleKey]).filter(Boolean);
|
|
427
|
-
const placeholders = gateKinds.map(() => "?").join(",");
|
|
428
|
-
const rows = db.prepare(
|
|
429
|
-
"SELECT * FROM override_log WHERE scope=? AND status='active' " +
|
|
430
|
-
"AND gate_kind IN (" + placeholders + ") " +
|
|
431
|
-
"AND starts_at <= strftime('%Y-%m-%dT%H:%M:%fZ','now') " +
|
|
432
|
-
"AND (expires_at IS NULL OR expires_at >= strftime('%Y-%m-%dT%H:%M:%fZ','now')) " +
|
|
433
|
-
"AND (project IS NULL OR project=? OR ? IS NULL) " +
|
|
434
|
-
"AND (agent_name IS NULL OR agent_name=? OR ?='') " +
|
|
435
|
-
"ORDER BY starts_at DESC LIMIT 20"
|
|
436
|
-
).all(scope, ...gateKinds, project, project, agent, agent);
|
|
437
|
-
return rows.map((row) => Object.assign({}, row, { meta: parseJson(row.meta_json, {}) }));
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
function validateProtectedScopeOverride(db, input = {}) {
|
|
441
|
-
const gateKind = String(input.gate_kind || "").trim().toLowerCase();
|
|
442
|
-
if (!gateKind.startsWith("protected_scope")) {
|
|
443
|
-
return { ok: true, protected_scope: false };
|
|
444
|
-
}
|
|
445
|
-
ensureProtectedScopeSchema(db);
|
|
446
|
-
seedDefaultProtectedScopes(db, { scope: input.scope });
|
|
447
|
-
const scope = cleanScope(input.scope || process.env.MNEMO_DEFAULT_SCOPE || DEFAULT_SCOPE);
|
|
448
|
-
const meta = input.meta && typeof input.meta === "object" ? input.meta : parseJson(input.meta_json, {});
|
|
449
|
-
const suffix = gateKind.includes(":") ? gateKind.split(":").slice(1).join(":") : "";
|
|
450
|
-
const ruleKey = String(input.rule_key || meta.rule_key || suffix || "").trim();
|
|
451
|
-
if (!ruleKey) {
|
|
452
|
-
return {
|
|
453
|
-
ok: false,
|
|
454
|
-
protected_scope: true,
|
|
455
|
-
error: "protected_scope_rule_key_required",
|
|
456
|
-
hint: "Protected-scope overrides must name the exact rule: gate_kind='protected_scope:<rule_key>' and approved_by=<assigned owner>."
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
const row = db.prepare("SELECT * FROM protected_scope_rule WHERE scope=? AND rule_key=? AND status='active'").get(scope, ruleKey);
|
|
460
|
-
if (!row) {
|
|
461
|
-
return {
|
|
462
|
-
ok: false,
|
|
463
|
-
protected_scope: true,
|
|
464
|
-
error: "protected_scope_rule_not_found",
|
|
465
|
-
rule_key: ruleKey,
|
|
466
|
-
hint: "Run mem_protected_scope_list and use an existing active rule_key."
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
const owner = normalizeAgentName(row.required_approval_by || row.owner_agent);
|
|
470
|
-
const approvedBy = normalizeAgentName(input.approved_by);
|
|
471
|
-
if (!owner) {
|
|
472
|
-
return {
|
|
473
|
-
ok: false,
|
|
474
|
-
protected_scope: true,
|
|
475
|
-
error: "protected_scope_owner_missing",
|
|
476
|
-
rule_key: ruleKey,
|
|
477
|
-
hint: "Set owner_agent or required_approval_by on the protected scope before overrides are allowed."
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
if (!approvedBy || approvedBy !== owner) {
|
|
481
|
-
return {
|
|
482
|
-
ok: false,
|
|
483
|
-
protected_scope: true,
|
|
484
|
-
error: "protected_scope_owner_approval_required",
|
|
485
|
-
rule_key: ruleKey,
|
|
486
|
-
label: row.label,
|
|
487
|
-
required_approved_by: owner,
|
|
488
|
-
provided_approved_by: approvedBy || null,
|
|
489
|
-
hint: "Only the assigned protected-scope owner can approve this exception."
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
return {
|
|
493
|
-
ok: true,
|
|
494
|
-
protected_scope: true,
|
|
495
|
-
rule_key: ruleKey,
|
|
496
|
-
label: row.label,
|
|
497
|
-
approved_by: approvedBy,
|
|
498
|
-
owner_agent: owner
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function protectedScopeCheck(db, input = {}) {
|
|
503
|
-
ensureProtectedScopeSchema(db);
|
|
504
|
-
seedDefaultProtectedScopes(db, { scope: input.scope });
|
|
505
|
-
const scope = cleanScope(input.scope || process.env.MNEMO_DEFAULT_SCOPE || DEFAULT_SCOPE);
|
|
506
|
-
const project = input.project || null;
|
|
507
|
-
const agent = normalizeAgentName(input.agent_name);
|
|
508
|
-
const haystack = buildHaystack(input);
|
|
509
|
-
const writeLike = isWriteLike(input, haystack);
|
|
510
|
-
const rows = db.prepare("SELECT * FROM protected_scope_rule WHERE scope=? AND status='active' AND (project IS NULL OR project=?) ORDER BY rule_key").all(scope, project);
|
|
511
|
-
const matched = [];
|
|
512
|
-
const blockers = [];
|
|
513
|
-
const warnings = [];
|
|
514
|
-
const instructions = [];
|
|
515
|
-
for (const row of rows) {
|
|
516
|
-
const patternHits = ruleMatches(row, haystack);
|
|
517
|
-
if (!patternHits.length) continue;
|
|
518
|
-
const rule = protectedScopeRuleRow(row);
|
|
519
|
-
const requiredClaims = Array.isArray(rule.required_claims) && rule.required_claims.length
|
|
520
|
-
? rule.required_claims
|
|
521
|
-
: [{ claim_kind: "protected_scope", scope_value: rule.rule_key }];
|
|
522
|
-
const claims = requiredClaims.flatMap((claim) => activeClaimRows(db, {
|
|
523
|
-
project: project || "unknown",
|
|
524
|
-
agent_name: agent,
|
|
525
|
-
claim_kind: claim.claim_kind || "protected_scope",
|
|
526
|
-
scope_value: claim.scope_value || rule.rule_key
|
|
527
|
-
}));
|
|
528
|
-
const overrides = activeOverrideRows(db, {
|
|
529
|
-
scope,
|
|
530
|
-
project,
|
|
531
|
-
agent_name: agent,
|
|
532
|
-
rule_key: rule.rule_key
|
|
533
|
-
});
|
|
534
|
-
const owner = normalizeAgentName(rule.owner_agent);
|
|
535
|
-
const ownerOk = !owner || owner === agent;
|
|
536
|
-
const hasClaim = claims.length > 0;
|
|
537
|
-
const hasOverride = overrides.length > 0;
|
|
538
|
-
matched.push(Object.assign({}, rule, {
|
|
539
|
-
matched_patterns: patternHits,
|
|
540
|
-
active_claims: claims,
|
|
541
|
-
active_overrides: overrides,
|
|
542
|
-
owner_ok: ownerOk,
|
|
543
|
-
claim_ok: hasClaim,
|
|
544
|
-
override_ok: hasOverride
|
|
545
|
-
}));
|
|
546
|
-
if (!writeLike) {
|
|
547
|
-
warnings.push("protected scope matched read/prep context: " + rule.label + "; write/deploy will require owner/claim gate.");
|
|
548
|
-
continue;
|
|
549
|
-
}
|
|
550
|
-
if (!hasOverride && !ownerOk) {
|
|
551
|
-
blockers.push("protected scope \"" + rule.label + "\" is owned by " + owner + "; " + (agent || "this agent") + " needs explicit handoff or mem_override_log before write/deploy.");
|
|
552
|
-
}
|
|
553
|
-
if (!hasOverride && !hasClaim) {
|
|
554
|
-
const claim = requiredClaims[0] || { claim_kind: "protected_scope", scope_value: rule.rule_key };
|
|
555
|
-
const claimKind = claim.claim_kind || "protected_scope";
|
|
556
|
-
const scopeValue = claim.scope_value || rule.rule_key;
|
|
557
|
-
blockers.push("protected scope \"" + rule.label + "\" requires an active claim before write/deploy.");
|
|
558
|
-
instructions.push("Claim first: mem_work_claim({ project: \"" + (project || "unknown") + "\", agent_name: \"" + (agent || "<agent>") + "\", claim_kind: \"" + claimKind + "\", scope_value: \"" + scopeValue + "\", summary: \"<task>\", ttl_minutes: " + DEFAULT_TTL_MINUTES + " })");
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
const status = blockers.length ? "block" : (warnings.length ? "warn" : "ok");
|
|
562
|
-
return {
|
|
563
|
-
ok: !blockers.length,
|
|
564
|
-
status,
|
|
565
|
-
scope,
|
|
566
|
-
project,
|
|
567
|
-
agent_name: agent,
|
|
568
|
-
write_like: writeLike,
|
|
569
|
-
matched_count: matched.length,
|
|
570
|
-
matched_rules: matched,
|
|
571
|
-
blockers,
|
|
572
|
-
warnings,
|
|
573
|
-
instructions,
|
|
574
|
-
hint: blockers.length ? "Resolve protected-scope blockers before editing, deploying, or changing shared behavior." : "Protected-scope gate passed."
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
const PROTECTED_SCOPE_TOOL_DEFS = {
|
|
579
|
-
mem_protected_scope_seed: {
|
|
580
|
-
description: "Seed the default protected-scope rules into the current Mnemo scope.",
|
|
581
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, force: { type: "boolean" } } }
|
|
582
|
-
},
|
|
583
|
-
mem_protected_scope_list: {
|
|
584
|
-
description: "List active protected-scope rules. These are hard gates checked by mem_agent_preflight.",
|
|
585
|
-
inputSchema: { type: "object", properties: { scope: { type: "string" }, project: { type: "string" }, rule_key: { type: "string" }, owner_agent: { type: "string" }, status: { type: "string" }, limit: { type: "integer" } } }
|
|
586
|
-
},
|
|
587
|
-
mem_protected_scope_check: {
|
|
588
|
-
description: "Check whether a task/files/routes touch protected scopes and whether owner, claim, or override gates are satisfied.",
|
|
589
|
-
inputSchema: {
|
|
590
|
-
type: "object",
|
|
591
|
-
properties: {
|
|
592
|
-
agent_name: { type: "string" },
|
|
593
|
-
project: { type: "string" },
|
|
594
|
-
task: { type: "string" },
|
|
595
|
-
summary: { type: "string" },
|
|
596
|
-
files: { type: "array", items: { type: "string" } },
|
|
597
|
-
urls: { type: "array", items: { type: "string" } },
|
|
598
|
-
routes: { type: "array", items: { type: "string" } },
|
|
599
|
-
domains: { type: "array", items: { type: "string" } },
|
|
600
|
-
system_names: { type: "array", items: { type: "string" } },
|
|
601
|
-
topics: { type: "array", items: { type: "string" } },
|
|
602
|
-
commands: { type: "array", items: { type: "string" } },
|
|
603
|
-
action_type: { type: "string" },
|
|
604
|
-
scope: { type: "string" }
|
|
605
|
-
},
|
|
606
|
-
required: ["agent_name"]
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
function handleProtectedScopeTool(db, name, input = {}) {
|
|
612
|
-
if (name === "mem_protected_scope_seed") return { handled: true, result: seedDefaultProtectedScopes(db, input || {}) };
|
|
613
|
-
if (name === "mem_protected_scope_list") return { handled: true, result: listProtectedScopeRules(db, input || {}) };
|
|
614
|
-
if (name === "mem_protected_scope_check") return { handled: true, result: protectedScopeCheck(db, input || {}) };
|
|
615
|
-
return { handled: false };
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
module.exports = {
|
|
619
|
-
PROTECTED_SCOPE_TOOL_DEFS,
|
|
620
|
-
ensureProtectedScopeSchema,
|
|
621
|
-
seedDefaultProtectedScopes,
|
|
622
|
-
listProtectedScopeRules,
|
|
623
|
-
protectedScopeCheck,
|
|
624
|
-
validateProtectedScopeOverride,
|
|
625
|
-
handleProtectedScopeTool,
|
|
626
|
-
claimScopeKey
|
|
627
|
-
};
|