@askexenow/exe-os 0.9.409 → 0.9.411
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/deploy/stack-manifests/v0.9.json +408 -1
- package/dist/.dist-verified.json +3 -3
- package/dist/{active-agent-5AKPW2N7.js → active-agent-3YCLS7GB.js} +4 -4
- package/dist/{active-agent-2AMJC3SC.js → active-agent-MHWQDMML.js} +4 -4
- package/dist/agent-defs-generator-DNXMO34I.js +32 -0
- package/dist/{agentic-ontology-6RS7A7KP.js → agentic-ontology-RA6CMND6.js} +1 -1
- package/dist/{artifact-backup-6O4FNYPS.js → artifact-backup-EETHNFFP.js} +3 -3
- package/dist/{backfill-metadata-6YX6LGPJ.js → backfill-metadata-WYT257VG.js} +7 -7
- package/dist/backup-verify-AG54CYGR.js +62 -0
- package/dist/{behavior-injection-NRXTNROW.js → behavior-injection-G7GAUHGO.js} +10 -10
- package/dist/{behavior-promotion-MW7OQ72V.js → behavior-promotion-I2DIUFUR.js} +9 -9
- package/dist/{behaviors-7AOK44QK.js → behaviors-SKVKPCRW.js} +8 -8
- package/dist/bin/agentic-ontology-backfill.js +8 -8
- package/dist/bin/agentic-reflection-backfill.js +9 -9
- package/dist/bin/agentic-semantic-label.js +8 -8
- package/dist/bin/backfill-conversations.js +7 -7
- package/dist/bin/backfill-responses.js +7 -7
- package/dist/bin/backfill-vectors.js +7 -7
- package/dist/bin/bulk-sync-postgres.js +16 -16
- package/dist/bin/cc-doctor.js +8 -8
- package/dist/bin/cleanup-stale-review-tasks.js +13 -16
- package/dist/bin/cli.js +24 -24
- package/dist/bin/deferred-daemon-restart.js +97 -97
- package/dist/bin/exe-actions.js +1 -1
- package/dist/bin/exe-agent-config.js +3 -3
- package/dist/bin/exe-agent.js +12 -12
- package/dist/bin/exe-assign.js +8 -8
- package/dist/bin/exe-boot.js +35 -38
- package/dist/bin/exe-call.js +9 -9
- package/dist/bin/exe-cloud.js +26 -22
- package/dist/bin/exe-config-dump.js +3 -3
- package/dist/bin/exe-dispatch.js +14 -17
- package/dist/bin/exe-doctor.js +5 -5
- package/dist/bin/exe-export-behaviors.js +12 -12
- package/dist/bin/exe-forget.js +12 -12
- package/dist/bin/exe-gateway.js +9 -9
- package/dist/bin/exe-grant.js +6 -6
- package/dist/bin/exe-healthcheck.js +8 -8
- package/dist/bin/exe-heartbeat.js +19 -22
- package/dist/bin/exe-kill.js +18 -21
- package/dist/bin/exe-launch-agent.js +264 -110
- package/dist/bin/exe-mcp.js +5 -5
- package/dist/bin/exe-memory-reads.js +7 -7
- package/dist/bin/exe-new-employee.js +11 -11
- package/dist/bin/exe-os-mcp-proxy.js +5 -5
- package/dist/bin/exe-pending-messages.js +14 -17
- package/dist/bin/exe-pending-notifications.js +13 -16
- package/dist/bin/exe-pending-reviews.js +14 -17
- package/dist/bin/exe-rename.js +7 -7
- package/dist/bin/exe-review.js +17 -20
- package/dist/bin/exe-search.js +11 -11
- package/dist/bin/exe-session-cleanup.js +18 -21
- package/dist/bin/exe-settings.js +16 -16
- package/dist/bin/exe-start-codex.js +37 -19
- package/dist/bin/exe-start-opencode.js +35 -17
- package/dist/bin/exe-status.js +15 -18
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +5 -5
- package/dist/bin/git-sweep.js +15 -17
- package/dist/bin/graph-backfill.js +8 -8
- package/dist/bin/graph-export.js +8 -8
- package/dist/bin/hooks-cli.js +1 -1
- package/dist/bin/import-history.js +11 -11
- package/dist/bin/install.js +99 -99
- package/dist/bin/intercom-check.js +5 -5
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +5 -5
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/pre-publish.js +1 -1
- package/dist/bin/reconcile-backlog.js +2 -2
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/repair-document-chunks.js +7 -7
- package/dist/bin/scan-tasks.js +14 -17
- package/dist/bin/setup.js +2 -2
- package/dist/bin/shard-migrate.js +8 -8
- package/dist/bin/stack-update.js +4 -4
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{boot-generation-HG6LLZLY.js → boot-generation-RPJVFAQJ.js} +4 -4
- package/dist/{boot-review-sections-STZ5EAIL.js → boot-review-sections-FOPPZTJI.js} +12 -15
- package/dist/{bug-landed-reconciler-EO72HUI2.js → bug-landed-reconciler-FN5KPBRK.js} +6 -6
- package/dist/build-info.json +3 -3
- package/dist/build-manifest.json +997 -987
- package/dist/{capability-cards-C3SMHB2E.js → capability-cards-YQWBEG7A.js} +3 -3
- package/dist/{capacity-monitor-UI553HRL.js → capacity-monitor-7SMEJHYG.js} +14 -17
- package/dist/{catchup-brief-VE2X4HML.js → catchup-brief-IBQ26LEB.js} +21 -23
- package/dist/{chunk-6ZW6BRI4.js → chunk-27NG2NTG.js} +2 -2
- package/dist/{chunk-EIM7OGTD.js → chunk-2BOLFLAU.js} +4 -2
- package/dist/{chunk-DM4VTXM6.js → chunk-2EYVXUGA.js} +4 -4
- package/dist/{chunk-LMF2YC5C.js → chunk-2YFMBXUU.js} +4 -4
- package/dist/{chunk-C426MZMD.js → chunk-2YGBJHC2.js} +3 -3
- package/dist/{chunk-6EY6OFBC.js → chunk-353XF4LU.js} +2 -2
- package/dist/{chunk-VMHZSZQJ.js → chunk-3ARSKDHC.js} +52 -0
- package/dist/{chunk-ZYOIH5NY.js → chunk-3DXAJVXE.js} +6 -6
- package/dist/{chunk-HFSFWMID.js → chunk-3GGMHSY2.js} +3 -3
- package/dist/{chunk-BM467PZN.js → chunk-3N24FV22.js} +1 -1
- package/dist/{chunk-SY53PYLU.js → chunk-47YGEM4N.js} +1 -1
- package/dist/{chunk-NVM3SKJ4.js → chunk-4CN3EE6U.js} +27 -21
- package/dist/{chunk-KIJRAZWR.js → chunk-4J77TCTX.js} +1 -1
- package/dist/{chunk-NHQWPKX7.js → chunk-54STF27U.js} +2 -2
- package/dist/{chunk-Q4GS5VW7.js → chunk-5BWDUUMH.js} +3 -3
- package/dist/{chunk-VYKXRSHU.js → chunk-5ZMNFSHV.js} +1 -1
- package/dist/{chunk-HNGAM3U4.js → chunk-657I6PUF.js} +3 -3
- package/dist/{chunk-OE7TAEOG.js → chunk-6777GNWI.js} +1 -1
- package/dist/{chunk-HYZV25LY.js → chunk-67IVG6CB.js} +1 -11
- package/dist/{chunk-5N34MMKS.js → chunk-6APOLYIZ.js} +43 -3
- package/dist/{chunk-TBYWOHTE.js → chunk-6BD6JYR2.js} +1 -1
- package/dist/{chunk-JJYAETCO.js → chunk-6DMURUBY.js} +4 -4
- package/dist/{chunk-W5XAB2SW.js → chunk-6HJF7IA3.js} +273 -206
- package/dist/{chunk-HRKN3DQE.js → chunk-6J2J3VJS.js} +11 -11
- package/dist/{chunk-XFGS22VE.js → chunk-6PXFF6IV.js} +1 -1
- package/dist/{chunk-RZ23QQCI.js → chunk-7HLAYQRG.js} +4 -4
- package/dist/{chunk-IUBCS6TA.js → chunk-7KPZQ65I.js} +3 -3
- package/dist/{chunk-SYUJCVJG.js → chunk-7PDZBPGW.js} +1 -1
- package/dist/{chunk-VLAENYCN.js → chunk-7SHU5MOD.js} +1 -1
- package/dist/{chunk-6RRPVE5O.js → chunk-A5I2GYVQ.js} +3 -3
- package/dist/{chunk-X4V5ZLNX.js → chunk-A75TAU2I.js} +628 -4
- package/dist/{chunk-SGR4ZQAV.js → chunk-BE3UETW6.js} +3 -3
- package/dist/{chunk-GG73NHZD.js → chunk-BG6RAOCJ.js} +63 -9
- package/dist/{chunk-DMYJVGQM.js → chunk-BIPTWAEO.js} +1 -1
- package/dist/{chunk-B3ISLIKE.js → chunk-BLTXAUP6.js} +2 -2
- package/dist/{chunk-G2M7WQ2M.js → chunk-CBC3JCIF.js} +1 -1
- package/dist/{chunk-FJKUFMNF.js → chunk-CFFSHBQF.js} +1 -1
- package/dist/{chunk-WYNIWJRN.js → chunk-CJ6CS2IH.js} +5 -5
- package/dist/{chunk-7LTAA55U.js → chunk-CRW63CDI.js} +1 -1
- package/dist/{chunk-BHDDDNC6.js → chunk-CWHTUNJX.js} +2 -2
- package/dist/{chunk-FZT4VQP7.js → chunk-D6NZNUVH.js} +1 -1
- package/dist/{chunk-GKPPLIMJ.js → chunk-DHLJZDWI.js} +4 -4
- package/dist/{chunk-JR3GTBV3.js → chunk-DRHTRVDT.js} +1 -1
- package/dist/{chunk-GTRB6DGI.js → chunk-DWRULKB3.js} +2 -2
- package/dist/{chunk-DIKLSAJE.js → chunk-EOWJXCYC.js} +25 -7
- package/dist/{chunk-4W7Y67B5.js → chunk-EWDBWOCX.js} +1 -1
- package/dist/{chunk-EHILXBVT.js → chunk-FPF2PJFK.js} +3 -3
- package/dist/{chunk-BPBEJD7U.js → chunk-FSXMKIDO.js} +1 -1
- package/dist/{chunk-E2Z3F26R.js → chunk-FUDXITKX.js} +1 -1
- package/dist/{chunk-SFGFNJBR.js → chunk-FYV2CTKP.js} +1 -1
- package/dist/{chunk-4M24XCTI.js → chunk-GATAYYAF.js} +53 -7
- package/dist/{chunk-L5CPS34O.js → chunk-GHYHNHDL.js} +1 -1
- package/dist/{chunk-OISOA6NX.js → chunk-GL5ZG72X.js} +1 -1
- package/dist/{chunk-XAGIZVYI.js → chunk-GM4UEZDE.js} +181 -1625
- package/dist/{chunk-4O7OUBEX.js → chunk-GZVFHFO3.js} +27 -140
- package/dist/{chunk-M4N7I2H5.js → chunk-HA6BIZ6L.js} +5 -5
- package/dist/chunk-HDQAVAV6.js +248 -0
- package/dist/{chunk-IPANAGA3.js → chunk-HDV2V25K.js} +1 -1
- package/dist/{chunk-XGPBHKU3.js → chunk-HTFM7ZDD.js} +2 -2
- package/dist/{chunk-KPLMY2GT.js → chunk-HUHR5CKJ.js} +4 -4
- package/dist/{chunk-IPBNHPTE.js → chunk-IC2AONBH.js} +9 -9
- package/dist/{chunk-23XUZHB7.js → chunk-IHAXXDBH.js} +245 -36
- package/dist/{chunk-4S6H2NWS.js → chunk-IPUDXR67.js} +1 -1
- package/dist/{chunk-UXJAW4IQ.js → chunk-J6U4ZR77.js} +2 -2
- package/dist/{chunk-7I6KVKFF.js → chunk-JAIZCE6W.js} +3 -3
- package/dist/{chunk-SA66WRBT.js → chunk-JGBYZTWH.js} +1 -1
- package/dist/{chunk-HRYWB4TO.js → chunk-JJZZXEAN.js} +3 -3
- package/dist/{chunk-IZ24HRDC.js → chunk-JNULO6I5.js} +3 -3
- package/dist/{chunk-YVS77JPW.js → chunk-JTJP4JK7.js} +3 -3
- package/dist/{chunk-BIV4IHED.js → chunk-JW5NUXPN.js} +15 -28
- package/dist/{chunk-NFNM64A7.js → chunk-K2HIXAIF.js} +22 -18
- package/dist/{chunk-F5ZRHLG5.js → chunk-KEDZRQI3.js} +2 -2
- package/dist/{chunk-QPMKVSHU.js → chunk-KN5GAVCG.js} +2 -2
- package/dist/{chunk-3MDUKF3N.js → chunk-L5JFVK5T.js} +5 -4
- package/dist/{chunk-FBZ32BD4.js → chunk-LBSCOP25.js} +1 -1
- package/dist/{chunk-K7DAE2HO.js → chunk-LLZUL7M2.js} +19 -6
- package/dist/{chunk-PCFYNK7V.js → chunk-LQGLGSBY.js} +2 -2
- package/dist/{chunk-APVU4Q5B.js → chunk-LSHUX7P4.js} +16 -16
- package/dist/{chunk-GRAMRMWS.js → chunk-M6AX64J2.js} +2 -2
- package/dist/{chunk-52Z435PH.js → chunk-M6SUJLNP.js} +15 -10
- package/dist/{chunk-GPWXUU3L.js → chunk-MZNLQC6W.js} +1 -1
- package/dist/{chunk-G3ZYXXO7.js → chunk-N7POJZJT.js} +10 -10
- package/dist/{chunk-DE2V7547.js → chunk-NCNT2C2P.js} +2 -2
- package/dist/{chunk-HK7HIDXP.js → chunk-O3BLL6MY.js} +1 -1
- package/dist/{chunk-YLWKWEJJ.js → chunk-O6KQAJCC.js} +3 -3
- package/dist/{chunk-QUK3UDZV.js → chunk-OHHZNNUD.js} +1 -1
- package/dist/{chunk-6JLVCMKH.js → chunk-PDQGR5LZ.js} +1 -1
- package/dist/{chunk-LE3DIA25.js → chunk-PTF5TB6O.js} +3 -3
- package/dist/{chunk-KBHK2WNO.js → chunk-PYXXL7N7.js} +1 -1
- package/dist/{chunk-QK3Z4TKQ.js → chunk-Q6KUBP6R.js} +5 -5
- package/dist/{chunk-NDCW4G55.js → chunk-QJWLQXR7.js} +1 -1
- package/dist/{chunk-ME733Y2F.js → chunk-QOFQY7BJ.js} +37 -9
- package/dist/{chunk-HFXBL7XE.js → chunk-QSW5DHMZ.js} +1 -1
- package/dist/{chunk-OFT5KSBM.js → chunk-QV26G2BF.js} +1 -1
- package/dist/{chunk-LVEMYNYH.js → chunk-RHHEYC6H.js} +3 -3
- package/dist/{chunk-QYIR64RR.js → chunk-RHJOTGEU.js} +1 -1
- package/dist/{chunk-HUMNRJZE.js → chunk-RJIH7JXM.js} +4 -4
- package/dist/{chunk-6TB7UXCA.js → chunk-RMC2A6EE.js} +1 -1
- package/dist/{chunk-XCPD7NGP.js → chunk-RYMXD2NT.js} +1 -1
- package/dist/{chunk-W2VDJKTB.js → chunk-RYYFFCJG.js} +1 -1
- package/dist/{chunk-YUAOQJVV.js → chunk-SINIRUYZ.js} +101 -9
- package/dist/{chunk-R7QZXQPU.js → chunk-SXUABANK.js} +216 -147
- package/dist/{backup-verify-QIAQ63VC.js → chunk-T3AM52YT.js} +411 -90
- package/dist/{chunk-NK4JHJNP.js → chunk-TCBWHLKH.js} +4 -4
- package/dist/{chunk-R6CKQLEA.js → chunk-TS4LSNRI.js} +2 -2
- package/dist/{chunk-4Q7H3TO7.js → chunk-TVWYMOZ4.js} +1 -1
- package/dist/{chunk-TCV3WA5I.js → chunk-VAHQOIQY.js} +1 -1
- package/dist/{chunk-ZEHBSA25.js → chunk-VQQPYI4X.js} +1 -1
- package/dist/{chunk-PZDAPIQL.js → chunk-VS7V5HNO.js} +1 -1
- package/dist/{chunk-7R7KDRKV.js → chunk-W7VKGB42.js} +1 -1
- package/dist/{chunk-M7774YLB.js → chunk-WC44PNZU.js} +1 -1
- package/dist/{chunk-3AL2LO3L.js → chunk-WHUQ44F2.js} +1 -1
- package/dist/{chunk-4RQ62XXK.js → chunk-X2ZHCNNB.js} +5 -5
- package/dist/{chunk-T2PAFWRK.js → chunk-X4FHT6ST.js} +5 -5
- package/dist/{chunk-N3JEYUDV.js → chunk-XC5OASHV.js} +1 -1
- package/dist/{agent-defs-generator-QN3J6FVJ.js → chunk-XDOCXKHW.js} +61 -21
- package/dist/{chunk-OEHZ46WQ.js → chunk-XEAZJXMZ.js} +2 -2
- package/dist/{chunk-DACRR362.js → chunk-XQ7BIVLI.js} +6 -6
- package/dist/{chunk-7P2TDFZL.js → chunk-Z3LGAFMG.js} +1 -1
- package/dist/{chunk-GEQQGN3J.js → chunk-ZJ6AMC4Y.js} +7 -7
- package/dist/{chunk-IURGBN5B.js → chunk-ZZR2WRNW.js} +4 -4
- package/dist/{cleanup-graph-garbage-NKAJSCWZ.js → cleanup-graph-garbage-SYGPMPUM.js} +8 -8
- package/dist/{cli-shutdown-F3DFDCB5.js → cli-shutdown-JI7CASE4.js} +1 -1
- package/dist/{cloud-sync-command-3YBLSMAL.js → cloud-sync-command-ZV3P5FP6.js} +2 -2
- package/dist/{cloud-sync-db-init-JWSPAFKY.js → cloud-sync-db-init-RQIHWKV4.js} +1 -1
- package/dist/{cloud-sync-shutdown-4R6RIO67.js → cloud-sync-shutdown-V2N7VLD3.js} +3 -3
- package/dist/{co-activation-2ZRANV3Q.js → co-activation-SRE6DIRX.js} +3 -3
- package/dist/{co-occurrence-6EELW2L2.js → co-occurrence-F5TMSEQZ.js} +6 -6
- package/dist/{consent-passphrase-TDR263MC.js → consent-passphrase-MWZRHJRC.js} +2 -2
- package/dist/content-extractor-GWF2T7FK.js +13 -0
- package/dist/{conversation-entity-extractor-KUJN3MOH.js → conversation-entity-extractor-XMOUHGMT.js} +3 -3
- package/dist/{crdt-sync-IX43KVQ3.js → crdt-sync-FXEKABM7.js} +4 -4
- package/dist/{crm-webhook-GSCIW6CE.js → crm-webhook-D6IJOPRQ.js} +2 -2
- package/dist/{cto-delegation-gate-ZWD4EFRR.js → cto-delegation-gate-BU3JRCYN.js} +12 -15
- package/dist/{daemon-orchestration-WL6V4QL4.js → daemon-orchestration-K4NKFYXO.js} +19 -21
- package/dist/{destructive-data-guard-JDUJ2ULM.js → destructive-data-guard-3TGAAE7K.js} +77 -23
- package/dist/{doc-graph-extractor-NJ7ZZC2C.js → doc-graph-extractor-TVK2NGAR.js} +6 -6
- package/dist/{documents-O7WYZFFE.js → documents-MDZ4VB5X.js} +8 -8
- package/dist/{dreaming-TUESPDT3.js → dreaming-L24PSS35.js} +17 -20
- package/dist/{employee-boot-brief-UCP6QLN4.js → employee-boot-brief-GQVL3FQC.js} +23 -25
- package/dist/{entity-boost-TK43XT24.js → entity-boost-OMFA5QCG.js} +2 -2
- package/dist/{exe-drift-QD6LUZT2.js → exe-drift-JDDG3OPT.js} +4 -4
- package/dist/{exe-export-QIUNHFSS.js → exe-export-EEGIE3JP.js} +10 -10
- package/dist/{exe-import-3UFOLHEW.js → exe-import-UJNC5Q2L.js} +10 -10
- package/dist/{exe-key-D5NDKGHT.js → exe-key-TYEY4W4E.js} +97 -97
- package/dist/{exe-org-UWDJBOCV.js → exe-org-B3ICTTEV.js} +32 -32
- package/dist/{exe-snapshot-P6SFODEN.js → exe-snapshot-VBFBONYN.js} +20 -23
- package/dist/{fast-db-init-SD7JZSEC.js → fast-db-init-TFRTK6EH.js} +1 -1
- package/dist/{founder-context-QIXDZIJX.js → founder-context-3X4QUWKD.js} +2 -2
- package/dist/{founder-monitor-envelope-TLOC4UYG.js → founder-monitor-envelope-54UNZNY4.js} +4 -4
- package/dist/gateway/index.js +11 -11
- package/dist/{gateway-client-CQTSYJLP.js → gateway-client-OUDO5GGV.js} +1 -1
- package/dist/{git-staleness-JSQTHB4Z.js → git-staleness-73YZ5PGU.js} +3 -3
- package/dist/{global-procedures-T3RKI4QX.js → global-procedures-PYNE2BQG.js} +20 -6
- package/dist/{graph-auto-extract-V75GSTNX.js → graph-auto-extract-PGUMEEQB.js} +6 -6
- package/dist/{graph-query-VAQN2RK3.js → graph-query-7YA3YNKL.js} +1 -1
- package/dist/{graph-rag-GBA5E3QC.js → graph-rag-UWOTK4AQ.js} +3 -3
- package/dist/{hook-integrity-II6QK6Y4.js → hook-integrity-6MNEPT6W.js} +1 -1
- package/dist/{hook-prefetch-5EHPOYY3.js → hook-prefetch-JOF6YZSR.js} +13 -16
- package/dist/hooks/bug-report-worker.js +17 -20
- package/dist/hooks/codex-stop-task-finalizer.js +19 -22
- package/dist/hooks/commit-complete.js +16 -19
- package/dist/hooks/error-recall.js +14 -14
- package/dist/hooks/exe-heartbeat-hook.js +5 -5
- package/dist/hooks/ingest-worker.js +18 -20
- package/dist/hooks/ingest.js +16 -16
- package/dist/hooks/instructions-loaded.js +7 -7
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +6 -6
- package/dist/hooks/post-compact.js +5 -5
- package/dist/hooks/post-tool-combined.js +13 -13
- package/dist/hooks/pre-compact.js +16 -19
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/prompt-submit.js +40 -39
- package/dist/hooks/session-end.js +21 -24
- package/dist/hooks/session-start.js +18 -18
- package/dist/hooks/stop.js +19 -22
- package/dist/hooks/subagent-stop.js +18 -21
- package/dist/hooks/summary-worker.js +20 -23
- package/dist/index.js +25 -28
- package/dist/{installer-XEEZSF3V.js → installer-34XZ7JMW.js} +7 -8
- package/dist/{installer-MPVQ5L22.js → installer-356RMQ2K.js} +7 -8
- package/dist/{installer-ILYC4LI5.js → installer-7TN36Z7T.js} +113 -30
- package/dist/{intercom-queue-QGHAW2KO.js → intercom-queue-ZJ3MNULM.js} +12 -15
- package/dist/lib/backup-verify-worker.js +157 -0
- package/dist/lib/cloud-sync.js +16 -20
- package/dist/lib/consolidation.js +9 -9
- package/dist/lib/crypto.js +3 -3
- package/dist/lib/database.js +3 -3
- package/dist/lib/db-backup.js +7 -3
- package/dist/lib/db-write-worker.js +3 -3
- package/dist/lib/db.js +3 -3
- package/dist/lib/device-registry.js +1 -1
- package/dist/lib/employee-templates.js +7 -7
- package/dist/lib/employees.js +3 -3
- package/dist/lib/error-detector.js +2 -2
- package/dist/lib/exe-daemon.js +89 -87
- package/dist/lib/hybrid-search.js +11 -11
- package/dist/lib/identity.js +5 -3
- package/dist/lib/keychain.js +1 -1
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +13 -16
- package/dist/lib/post-tool-memory.js +16 -18
- package/dist/lib/registry-proxy.js +1 -1
- package/dist/lib/reminders.js +4 -4
- package/dist/lib/schedules.js +8 -8
- package/dist/lib/session-registry.js +5 -5
- package/dist/lib/skill-learning.js +9 -9
- package/dist/lib/store.js +7 -7
- package/dist/lib/task-router.js +4 -4
- package/dist/lib/tasks.js +14 -17
- package/dist/lib/tmux-routing.js +14 -41
- package/dist/lib/token-spend.js +4 -4
- package/dist/lib/ws-client.js +1 -1
- package/dist/{license-gate-CARN6AB6.js → license-gate-4BXUTHLB.js} +3 -3
- package/dist/{license-recheck-7Z3LS6YS.js → license-recheck-QFPUKISQ.js} +1 -1
- package/dist/{license-sync-PUQV3HSZ.js → license-sync-FDEDT4AC.js} +2 -2
- package/dist/mcp/register-tools.js +96 -96
- package/dist/mcp/server.js +96 -96
- package/dist/mcp/tools/complete-reminder.js +5 -5
- package/dist/mcp/tools/create-reminder.js +5 -5
- package/dist/mcp/tools/create-task.js +16 -19
- package/dist/mcp/tools/deactivate-behavior.js +10 -10
- package/dist/mcp/tools/list-reminders.js +5 -5
- package/dist/mcp/tools/list-tasks.js +16 -19
- package/dist/mcp/tools/send-message.js +15 -18
- package/dist/mcp/tools/update-task.js +15 -18
- package/dist/{mcp-http-config-RJKTZPHZ.js → mcp-http-config-GKP5QGAO.js} +5 -5
- package/dist/{mcp-session-identity-HN444A3G.js → mcp-session-identity-JHAGRB7B.js} +12 -15
- package/dist/{memory-cards-AT3QCCWU.js → memory-cards-O377ETAM.js} +8 -8
- package/dist/{memory-graph-extractor-B43UWGV5.js → memory-graph-extractor-4KJCCUOP.js} +7 -7
- package/dist/{memory-maintenance-WDLL3ZX3.js → memory-maintenance-RR5UPRW3.js} +1 -1
- package/dist/{memory-poisoning-defense-TS4WNW4S.js → memory-poisoning-defense-Y5TTKGOP.js} +3 -3
- package/dist/{memory-pressure-watchdog-6YH7S6W7.js → memory-pressure-watchdog-NGXTI4HR.js} +13 -16
- package/dist/{memory-reflection-N6NSYW6S.js → memory-reflection-EXNHRZL7.js} +8 -8
- package/dist/{memory-write-repository-D35RDO62.js → memory-write-repository-S4TX7WQB.js} +1 -1
- package/dist/{monitor-grants-FH4PNYN5.js → monitor-grants-57Q4NL25.js} +3 -3
- package/dist/{monitor-identity-LK5ZCCND.js → monitor-identity-3FQ52SYU.js} +2 -2
- package/dist/{notification-ledger-3WJYJGGS.js → notification-ledger-O6KQYYGK.js} +13 -16
- package/dist/{notifications-T5C2CVB3.js → notifications-6FCQCJ4P.js} +12 -15
- package/dist/{orchestration-events-73VEJT7Q.js → orchestration-events-2Z2BMMA5.js} +4 -4
- package/dist/{orchestrator-3O657734.js → orchestrator-AGOSKPHD.js} +14 -17
- package/dist/{org-brief-session-EGB35QLM.js → org-brief-session-WJHZVXXJ.js} +15 -15
- package/dist/{org-consent-policy-MSVSRI53.js → org-consent-policy-X43UGTHI.js} +5 -5
- package/dist/{org-join-4BK2XJJI.js → org-join-M3UTBMHC.js} +9 -9
- package/dist/{org-key-admin-EUSSGXQ3.js → org-key-admin-AA2DRHB2.js} +11 -11
- package/dist/{org-key-epoch-NMEWDT5L.js → org-key-epoch-Z5UIVUHT.js} +5 -5
- package/dist/{org-key-pin-HUSXGINB.js → org-key-pin-FE6YHEZ3.js} +3 -3
- package/dist/{org-membership-B74IWEM5.js → org-membership-3J2MIGE4.js} +4 -4
- package/dist/{org-partner-config-5FJTJABN.js → org-partner-config-5HATZYG4.js} +8 -8
- package/dist/{org-partner-runtime-GN4GFWI2.js → org-partner-runtime-UI35IHUC.js} +15 -15
- package/dist/{org-row-visibility-PBZ2TSCR.js → org-row-visibility-TRJERVYP.js} +1 -1
- package/dist/{pipeline-router-2IELBSVJ.js → pipeline-router-EKQ6D7ZA.js} +4 -4
- package/dist/{plan-limits-4GXK5PFT.js → plan-limits-3BGHIHX6.js} +6 -6
- package/dist/{platform-procedures-QP3W2NLH.js → platform-procedures-RXW46WNY.js} +1 -1
- package/dist/{pre-tool-use-impl-CY73PRJP.js → pre-tool-use-impl-7BT5TJVM.js} +35 -33
- package/dist/{project-name-337ERIAX.js → project-name-PGJGUEJY.js} +4 -4
- package/dist/{projection-worker-W476IG6V.js → projection-worker-3GEVFPAI.js} +2 -2
- package/dist/{prospective-memory-5INB7NUL.js → prospective-memory-GEN7CN7H.js} +3 -3
- package/dist/{push-notifications-YVOP4KGN.js → push-notifications-QW4BWRC7.js} +13 -16
- package/dist/{reproject-worktree-memories-OGBR3CMO.js → reproject-worktree-memories-DIULBEBD.js} +12 -15
- package/dist/{reranker-W7WCJH6Y.js → reranker-LQ6OPJOI.js} +1 -1
- package/dist/{retrieval-health-R6MGXLTP.js → retrieval-health-XDFYFEOP.js} +1 -1
- package/dist/{review-polling-TKAWVY6G.js → review-polling-ED33YLFT.js} +13 -16
- package/dist/runtime/index.js +20 -23
- package/dist/{session-events-HUCZ7TOR.js → session-events-7IJGTBVH.js} +13 -16
- package/dist/{session-kill-telemetry-RWRWOW4C.js → session-kill-telemetry-RUTEARJ3.js} +13 -16
- package/dist/{session-scope-5CDRHV75.js → session-scope-SSYA64L3.js} +12 -15
- package/dist/{setup-wizard-RBTJAZOP.js → setup-wizard-XD7FZVLJ.js} +2 -2
- package/dist/{shard-manager-LRPAAQA4.js → shard-manager-FH5JZRSE.js} +2 -2
- package/dist/{skill-refinement-MDXKDCY6.js → skill-refinement-UHD4E6GV.js} +4 -4
- package/dist/{skill-retrieval-OWY6MTCX.js → skill-retrieval-F6PAJ3I5.js} +11 -11
- package/dist/{skill-usage-GNV737U5.js → skill-usage-2MBTF7Y4.js} +4 -4
- package/dist/{stack-generate-manifest-S4SBLKBY.js → stack-generate-manifest-SU6OFFY7.js} +4 -4
- package/dist/{stack-promote-U4EZNLOV.js → stack-promote-MJF436JD.js} +4 -4
- package/dist/{stack-release-4VBGOYGK.js → stack-release-S37R57XC.js} +5 -5
- package/dist/{stack-update-C5YKHE7A.js → stack-update-XXDRKGGR.js} +3 -3
- package/dist/{steward-gate-QFPXQBUZ.js → steward-gate-EWG2BHYQ.js} +4 -4
- package/dist/{subagent-brief-injection-GDXO5WNS.js → subagent-brief-injection-YZGSWUEY.js} +25 -27
- package/dist/{support-bug-actions-4XEKXIIO.js → support-bug-actions-RU6WZ3UV.js} +3 -3
- package/dist/{support-inbox-Y7AFCOGM.js → support-inbox-A3S52SPS.js} +12 -12
- package/dist/{task-enforcement-CN3Q4PEH.js → task-enforcement-LVAS55AR.js} +13 -16
- package/dist/{task-request-inbox-AY3C6DND.js → task-request-inbox-2TN4ZUH2.js} +5 -5
- package/dist/{task-scope-AMR3Z3DJ.js → task-scope-NLKUVCP5.js} +12 -15
- package/dist/{tasks-crud-2GHKIZOM.js → tasks-crud-NQDPLHNZ.js} +14 -15
- package/dist/{tasks-notify-Z53446KM.js → tasks-notify-BDM2NEHP.js} +13 -16
- package/dist/{tasks-review-APRNSHMQ.js → tasks-review-3G7CAW2O.js} +12 -15
- package/dist/{telemetry-upload-5XR42SQN.js → telemetry-upload-6DR6AL3V.js} +8 -8
- package/dist/{token-budget-TTNJXI7W.js → token-budget-KNC2WGR7.js} +4 -4
- package/dist/{tool-telemetry-36ST422N.js → tool-telemetry-I3SEU5M5.js} +1 -1
- package/dist/tui/App.js +23 -26
- package/dist/{tui-data-AP5TPUOQ.js → tui-data-KJDWP4CB.js} +16 -19
- package/dist/{update-support-SFTI2PUD.js → update-support-UYDYMHVR.js} +11 -11
- package/dist/{whatsapp-5CXE3JHG.js → whatsapp-5EMPZHF5.js} +2 -2
- package/dist/{wiki-acl-N754BC2W.js → wiki-acl-M7BTQJBZ.js} +1 -1
- package/dist/{work-claims-OAICQBWO.js → work-claims-5CFMZTML.js} +4 -4
- package/dist/{work-state-heartbeat-MTTUGMPU.js → work-state-heartbeat-7IA2DZ2E.js} +1 -1
- package/dist/{workflow-engine-RID3QL2U.js → workflow-engine-S5JOE2YR.js} +2 -2
- package/dist/{worktree-XWVNDBRD.js → worktree-7V4ZMF3D.js} +5 -5
- package/dist/{worktree-sweep-6VEHGH7U.js → worktree-sweep-34MXJ7S6.js} +6 -6
- package/package.json +2 -1
- package/release-notes.json +25 -7
- package/stack.release.json +3 -3
- package/dist/chunk-ESO5JDOT.js +0 -70
- package/dist/chunk-KCRSJ3VU.js +0 -113
- package/dist/content-extractor-OVD7PTSN.js +0 -9
- /package/dist/{chunk-OLMLA377.js → chunk-542FBM5U.js} +0 -0
- /package/dist/{chunk-LDHJX4TZ.js → chunk-6D2O5SAH.js} +0 -0
- /package/dist/{chunk-33PG3KNY.js → chunk-6NRZLVK3.js} +0 -0
- /package/dist/{chunk-CLV7ALXV.js → chunk-CFO47VW4.js} +0 -0
- /package/dist/{chunk-FLO24BNN.js → chunk-EULAP6L6.js} +0 -0
- /package/dist/{chunk-PKM456D2.js → chunk-FYSKQPTE.js} +0 -0
- /package/dist/{chunk-WIDOLS7T.js → chunk-J4B4M5PH.js} +0 -0
- /package/dist/{chunk-YBB43SXC.js → chunk-J635FA7T.js} +0 -0
- /package/dist/{chunk-64UAHPXA.js → chunk-MOBZTIJQ.js} +0 -0
- /package/dist/{chunk-EZQ4W3WW.js → chunk-N45FAI6D.js} +0 -0
- /package/dist/{chunk-OEEHLATI.js → chunk-QDSNEGJE.js} +0 -0
- /package/dist/{chunk-YG4DZZ6J.js → chunk-SKSXROKP.js} +0 -0
- /package/dist/{chunk-FUZHMV7K.js → chunk-YVWXI2HM.js} +0 -0
- /package/dist/{core-memory-WR7I7DIP.js → core-memory-PZEO3OWH.js} +0 -0
- /package/dist/{memory-isolation-4RQJ5RCK.js → memory-isolation-MFNT2ITE.js} +0 -0
- /package/dist/{oauth-server-VBDMZIEV.js → oauth-server-CBGEWD6H.js} +0 -0
- /package/dist/{project-boot-G7T5WHO6.js → project-boot-VESAYDIH.js} +0 -0
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLatestBackup,
|
|
3
3
|
reasonFromBackupName
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SINIRUYZ.js";
|
|
5
5
|
import {
|
|
6
6
|
recordDbOpen
|
|
7
7
|
} from "./chunk-5YEUPUV4.js";
|
|
8
|
-
import "./chunk-YYB5PMTK.js";
|
|
9
|
-
import "./chunk-MMS2HBRT.js";
|
|
10
|
-
import "./chunk-RH4AH3YB.js";
|
|
11
|
-
import "./chunk-HSGBZSCA.js";
|
|
12
|
-
import "./chunk-JKKZGDLP.js";
|
|
13
|
-
import "./chunk-MLKGABMK.js";
|
|
14
8
|
|
|
15
9
|
// src/lib/backup-verify.ts
|
|
16
10
|
import { createClient } from "@libsql/client";
|
|
17
|
-
import { existsSync } from "fs";
|
|
18
|
-
import { copyFile, mkdtemp, rm, writeFile, readFile } from "fs/promises";
|
|
19
|
-
import { createHash } from "crypto";
|
|
11
|
+
import { existsSync, realpathSync } from "fs";
|
|
12
|
+
import { copyFile, mkdtemp, readdir, lstat, rm, writeFile, readFile, rename } from "fs/promises";
|
|
13
|
+
import { createHash, randomBytes } from "crypto";
|
|
20
14
|
import { tmpdir } from "os";
|
|
21
15
|
import path from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
22
17
|
var MANIFEST_SCHEMA_VERSION = 1;
|
|
23
18
|
var DEFAULT_DRIFT_ALLOWANCE = 1e5;
|
|
24
19
|
var BACKUP_OPEN_PROBE_SQL = "SELECT name FROM sqlite_master LIMIT 1";
|
|
@@ -134,15 +129,300 @@ async function runQuickCheckOnArtifact(client) {
|
|
|
134
129
|
return { status: "failed", detail: `quick_check could not run: ${errMsg(err)}` };
|
|
135
130
|
}
|
|
136
131
|
}
|
|
132
|
+
async function runArtifactChecks(client) {
|
|
133
|
+
try {
|
|
134
|
+
await client.execute(BACKUP_OPEN_PROBE_SQL);
|
|
135
|
+
const quickCheck = await runQuickCheckOnArtifact(client);
|
|
136
|
+
if (quickCheck.status !== "ok") {
|
|
137
|
+
return { kind: "unreadable", detail: `the COPIED artifact FAILED PRAGMA quick_check: ${quickCheck.detail}` };
|
|
138
|
+
}
|
|
139
|
+
const schemaTables = await collectSchemaTables(client);
|
|
140
|
+
const tables = await collectCounts(client, schemaTables.map((t) => t.name));
|
|
141
|
+
return { kind: "ok", schemaTables, tables };
|
|
142
|
+
} catch (err) {
|
|
143
|
+
return { kind: "unreadable", detail: `the COPIED artifact could not be read back: ${errMsg(err)}` };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function runVerifyChecks(client) {
|
|
147
|
+
try {
|
|
148
|
+
await client.execute(BACKUP_OPEN_PROBE_SQL);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
return { kind: "open-failed", detail: errMsg(err) };
|
|
151
|
+
}
|
|
152
|
+
const integrity = await runIntegrityCheck(client);
|
|
153
|
+
if (integrity.status !== "ok") {
|
|
154
|
+
return {
|
|
155
|
+
kind: "integrity",
|
|
156
|
+
status: integrity.status,
|
|
157
|
+
quickCheck: integrity.quickCheck,
|
|
158
|
+
cipherIntegrityCheck: integrity.cipherIntegrityCheck
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const schemaTables = await collectSchemaTables(client);
|
|
163
|
+
const tables = await collectCounts(client, schemaTables.map((t) => t.name));
|
|
164
|
+
return {
|
|
165
|
+
kind: "ok",
|
|
166
|
+
quickCheck: integrity.quickCheck,
|
|
167
|
+
cipherIntegrityCheck: integrity.cipherIntegrityCheck,
|
|
168
|
+
schemaTables,
|
|
169
|
+
tables
|
|
170
|
+
};
|
|
171
|
+
} catch (err) {
|
|
172
|
+
return { kind: "error", detail: errMsg(err) };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
var BACKUP_VERIFY_WORKER_TIMEOUT_MS = 20 * 60 * 1e3;
|
|
176
|
+
var BACKUP_VERIFY_WORKER_MISSING_TAG = "[backup-verify] WORKER MISSING \u2014 verification running on main thread";
|
|
177
|
+
var BACKUP_VERIFY_WORKER_REPLY_REJECTED_TAG = "[backup-verify] WORKER REPLY REJECTED \u2014 verdict not-checked";
|
|
178
|
+
function reportBackupVerifyWorkerMissing(context, reason) {
|
|
179
|
+
try {
|
|
180
|
+
process.stderr.write(
|
|
181
|
+
`${BACKUP_VERIFY_WORKER_MISSING_TAG} (${context}): ${reason} \u2014 check tsup entry lib/backup-verify-worker
|
|
182
|
+
`
|
|
183
|
+
);
|
|
184
|
+
} catch {
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function isRecord(v) {
|
|
188
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
189
|
+
}
|
|
190
|
+
function isStrOrNull(v) {
|
|
191
|
+
return v === null || typeof v === "string";
|
|
192
|
+
}
|
|
193
|
+
function tableSetProblem(schemaTables, tables) {
|
|
194
|
+
if (!Array.isArray(schemaTables) || schemaTables.length === 0) return "schemaTables missing or empty";
|
|
195
|
+
const names = /* @__PURE__ */ new Set();
|
|
196
|
+
for (const t of schemaTables) {
|
|
197
|
+
if (!isRecord(t) || typeof t.name !== "string" || !t.name || typeof t.sql !== "string") {
|
|
198
|
+
return "schemaTables entry malformed";
|
|
199
|
+
}
|
|
200
|
+
if (names.has(t.name)) return `schemaTables lists ${t.name} twice`;
|
|
201
|
+
names.add(t.name);
|
|
202
|
+
}
|
|
203
|
+
if (!isRecord(tables)) return "tables missing";
|
|
204
|
+
const keys = Object.keys(tables);
|
|
205
|
+
if (keys.length !== names.size || keys.some((k) => !names.has(k))) return "tables keys do not match schemaTables";
|
|
206
|
+
for (const k of keys) {
|
|
207
|
+
const n = tables[k];
|
|
208
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 0) return `tables.${k} is not a non-negative integer`;
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
function artifactOutcomeProblem(o) {
|
|
213
|
+
if (!isRecord(o)) return "outcome missing";
|
|
214
|
+
if (o.kind === "unreadable") return typeof o.detail === "string" ? null : "unreadable outcome without detail";
|
|
215
|
+
if (o.kind === "ok") return tableSetProblem(o.schemaTables, o.tables);
|
|
216
|
+
return `outcome.kind=${String(o.kind)} is not ok|unreadable`;
|
|
217
|
+
}
|
|
218
|
+
function verifyOutcomeProblem(o) {
|
|
219
|
+
if (!isRecord(o)) return "outcome missing";
|
|
220
|
+
switch (o.kind) {
|
|
221
|
+
case "open-failed":
|
|
222
|
+
case "error":
|
|
223
|
+
return typeof o.detail === "string" ? null : `${o.kind} outcome without detail`;
|
|
224
|
+
case "integrity":
|
|
225
|
+
if (o.status !== "failed" && o.status !== "unreadable") return "integrity outcome with bad status";
|
|
226
|
+
return isStrOrNull(o.quickCheck) && isStrOrNull(o.cipherIntegrityCheck) ? null : "integrity outcome fields malformed";
|
|
227
|
+
case "ok":
|
|
228
|
+
if (typeof o.quickCheck !== "string" || o.quickCheck.toLowerCase() !== "ok") return "ok outcome without quick_check=ok";
|
|
229
|
+
if (o.cipherIntegrityCheck !== null && (typeof o.cipherIntegrityCheck !== "string" || o.cipherIntegrityCheck.toLowerCase() !== "ok")) {
|
|
230
|
+
return "ok outcome with a non-ok cipher_integrity_check";
|
|
231
|
+
}
|
|
232
|
+
return tableSetProblem(o.schemaTables, o.tables);
|
|
233
|
+
default:
|
|
234
|
+
return `outcome.kind=${String(o.kind)} is not a verify outcome`;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function validateBackupVerifyWorkerReply(req, msg) {
|
|
238
|
+
if (!isRecord(msg)) return { ok: false, reason: "reply is not an object" };
|
|
239
|
+
if (typeof msg.op !== "string") return { ok: false, reason: "reply has no op" };
|
|
240
|
+
if (typeof msg.pid !== "number" || !Number.isInteger(msg.pid)) return { ok: false, reason: "reply has no pid" };
|
|
241
|
+
if (msg.op === "error") {
|
|
242
|
+
return typeof msg.error === "string" ? { ok: true, response: msg } : { ok: false, reason: "error reply without an error string" };
|
|
243
|
+
}
|
|
244
|
+
if (msg.op !== req.op) return { ok: false, reason: `worker answered op=${msg.op} for op=${req.op}` };
|
|
245
|
+
let problem;
|
|
246
|
+
if (msg.op === "source") problem = typeof msg.verdict === "string" ? null : "source reply without a verdict string";
|
|
247
|
+
else if (msg.op === "artifact") problem = artifactOutcomeProblem(msg.outcome);
|
|
248
|
+
else if (msg.op === "verify") problem = verifyOutcomeProblem(msg.outcome);
|
|
249
|
+
else problem = `unknown op ${msg.op}`;
|
|
250
|
+
return problem ? { ok: false, reason: problem } : { ok: true, response: msg };
|
|
251
|
+
}
|
|
252
|
+
function backupVerifyOffloadEnabled(env = process.env) {
|
|
253
|
+
const raw = env.EXE_BACKUP_VERIFY_OFFLOAD;
|
|
254
|
+
if (raw === "1") return true;
|
|
255
|
+
if (raw === "0") return false;
|
|
256
|
+
return env.EXE_IS_DAEMON === "1";
|
|
257
|
+
}
|
|
258
|
+
function resolveBackupVerifyWorker(selfUrl, exists = existsSync) {
|
|
259
|
+
let selfDir;
|
|
260
|
+
try {
|
|
261
|
+
selfDir = path.dirname(fileURLToPath(selfUrl));
|
|
262
|
+
} catch {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
for (const candidate of [
|
|
266
|
+
path.join(selfDir, "backup-verify-worker.js"),
|
|
267
|
+
path.join(selfDir, "lib", "backup-verify-worker.js")
|
|
268
|
+
]) {
|
|
269
|
+
if (exists(candidate)) return { path: candidate, execArgv: [] };
|
|
270
|
+
}
|
|
271
|
+
const tsEntry = path.join(selfDir, "backup-verify-worker.ts");
|
|
272
|
+
if (exists(tsEntry)) return { path: tsEntry, execArgv: ["--import", "tsx"] };
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
async function runInBackupVerifyWorker(req, opts = {}) {
|
|
276
|
+
const worker = resolveBackupVerifyWorker(opts.selfUrl ?? import.meta.url);
|
|
277
|
+
if (!worker) return { ok: false, unavailable: true, reason: "backup-verify-worker entry not found" };
|
|
278
|
+
let child;
|
|
279
|
+
try {
|
|
280
|
+
const { fork } = await import("child_process");
|
|
281
|
+
child = fork(worker.path, [], {
|
|
282
|
+
execArgv: worker.execArgv,
|
|
283
|
+
stdio: ["ignore", "ignore", "inherit", "ipc"],
|
|
284
|
+
// EXE_IS_DAEMON cleared: the child must never act as the daemon.
|
|
285
|
+
env: { ...process.env, EXE_IS_DAEMON: "" }
|
|
286
|
+
});
|
|
287
|
+
} catch (err) {
|
|
288
|
+
return { ok: false, unavailable: true, reason: `fork failed: ${errMsg(err)}` };
|
|
289
|
+
}
|
|
290
|
+
return await new Promise((resolve) => {
|
|
291
|
+
let settled = false;
|
|
292
|
+
const finish = (run) => {
|
|
293
|
+
if (settled) return;
|
|
294
|
+
settled = true;
|
|
295
|
+
clearTimeout(timer);
|
|
296
|
+
try {
|
|
297
|
+
child.kill("SIGKILL");
|
|
298
|
+
} catch {
|
|
299
|
+
}
|
|
300
|
+
resolve(run);
|
|
301
|
+
};
|
|
302
|
+
const timeoutMs = opts.timeoutMs ?? BACKUP_VERIFY_WORKER_TIMEOUT_MS;
|
|
303
|
+
const timer = setTimeout(
|
|
304
|
+
() => finish({ ok: false, unavailable: false, reason: `timed out after ${timeoutMs}ms` }),
|
|
305
|
+
timeoutMs
|
|
306
|
+
);
|
|
307
|
+
child.once("error", (err) => {
|
|
308
|
+
finish({ ok: false, unavailable: child.pid === void 0, reason: `worker error: ${errMsg(err)}` });
|
|
309
|
+
});
|
|
310
|
+
child.once("close", (code, signal) => {
|
|
311
|
+
finish({ ok: false, unavailable: false, reason: `worker exited without a result (code=${code}, signal=${signal})` });
|
|
312
|
+
});
|
|
313
|
+
child.on("message", (msg) => {
|
|
314
|
+
if (settled) return;
|
|
315
|
+
const checked = validateBackupVerifyWorkerReply(req, msg);
|
|
316
|
+
if (!checked.ok) {
|
|
317
|
+
try {
|
|
318
|
+
process.stderr.write(`${BACKUP_VERIFY_WORKER_REPLY_REJECTED_TAG} (op=${req.op}): ${checked.reason}
|
|
319
|
+
`);
|
|
320
|
+
} catch {
|
|
321
|
+
}
|
|
322
|
+
finish({ ok: false, unavailable: false, reason: `worker sent a malformed reply: ${checked.reason}` });
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const res = checked.response;
|
|
326
|
+
if (res.op === "error") {
|
|
327
|
+
finish({ ok: false, unavailable: false, reason: `worker error: ${res.error}` });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
finish({ ok: true, response: res });
|
|
331
|
+
});
|
|
332
|
+
try {
|
|
333
|
+
child.send({ ...req, parentPid: process.pid });
|
|
334
|
+
} catch (err) {
|
|
335
|
+
finish({ ok: false, unavailable: false, reason: `could not send the request: ${errMsg(err)}` });
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
var SCRATCH_DIR_PREFIX = "exe-bkmanifest-";
|
|
340
|
+
var SCRATCH_DIR_ORPHAN_AGE_MS = 6 * 60 * 60 * 1e3;
|
|
341
|
+
async function sweepOrphanScratchDirs(base = tmpdir(), opts = {}) {
|
|
342
|
+
const maxAgeMs = opts.maxAgeMs ?? SCRATCH_DIR_ORPHAN_AGE_MS;
|
|
343
|
+
const removed = [];
|
|
344
|
+
const errors = [];
|
|
345
|
+
let entries;
|
|
346
|
+
try {
|
|
347
|
+
entries = await readdir(base);
|
|
348
|
+
} catch (err) {
|
|
349
|
+
errors.push(`could not list ${base}: ${errMsg(err)}`);
|
|
350
|
+
return { removed, errors };
|
|
351
|
+
}
|
|
352
|
+
let realBase;
|
|
353
|
+
try {
|
|
354
|
+
realBase = realpathSync.native(base);
|
|
355
|
+
} catch (err) {
|
|
356
|
+
errors.push(`could not resolve real path of ${base}: ${errMsg(err)}`);
|
|
357
|
+
return { removed, errors };
|
|
358
|
+
}
|
|
359
|
+
const excludeResolved = opts.exclude ? path.resolve(opts.exclude) : null;
|
|
360
|
+
for (const name of entries) {
|
|
361
|
+
if (!name.startsWith(SCRATCH_DIR_PREFIX)) continue;
|
|
362
|
+
const full = path.join(base, name);
|
|
363
|
+
if (excludeResolved && path.resolve(full) === excludeResolved) continue;
|
|
364
|
+
let st;
|
|
365
|
+
try {
|
|
366
|
+
st = await lstat(full);
|
|
367
|
+
} catch (err) {
|
|
368
|
+
errors.push(`could not stat ${full}: ${errMsg(err)}`);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (st.isSymbolicLink()) continue;
|
|
372
|
+
if (!st.isDirectory()) continue;
|
|
373
|
+
const ageMs = Date.now() - st.mtimeMs;
|
|
374
|
+
if (ageMs < maxAgeMs) continue;
|
|
375
|
+
let real;
|
|
376
|
+
try {
|
|
377
|
+
real = realpathSync.native(full);
|
|
378
|
+
} catch (err) {
|
|
379
|
+
errors.push(`could not resolve real path of ${full}: ${errMsg(err)}`);
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (path.dirname(real) !== realBase) {
|
|
383
|
+
errors.push(`refusing to remove ${full}: resolves outside ${realBase}`);
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
await rm(full, { recursive: true, force: true });
|
|
388
|
+
removed.push(full);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
errors.push(`could not remove ${full}: ${errMsg(err)}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return { removed, errors };
|
|
394
|
+
}
|
|
395
|
+
async function writeManifestAtomic(manifestPath, contents) {
|
|
396
|
+
const tmpPath = `${manifestPath}.${process.pid}-${randomBytes(4).toString("hex")}.tmp`;
|
|
397
|
+
try {
|
|
398
|
+
await writeFile(tmpPath, contents, "utf-8");
|
|
399
|
+
await rename(tmpPath, manifestPath);
|
|
400
|
+
} catch (err) {
|
|
401
|
+
try {
|
|
402
|
+
await rm(tmpPath, { force: true });
|
|
403
|
+
} catch {
|
|
404
|
+
}
|
|
405
|
+
throw err;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
137
408
|
async function readBackBackupArtifact(backupPath, dbName, opts = {}) {
|
|
138
409
|
let scratch = null;
|
|
139
410
|
let ownedClient = null;
|
|
411
|
+
let proof = null;
|
|
140
412
|
try {
|
|
141
413
|
let client = opts.client;
|
|
142
414
|
if (!client) {
|
|
415
|
+
try {
|
|
416
|
+
const sweep = await sweepOrphanScratchDirs(tmpdir());
|
|
417
|
+
for (const e of sweep.errors) {
|
|
418
|
+
console.error(`[backup-verify] orphan scratch sweep: ${e}`);
|
|
419
|
+
}
|
|
420
|
+
} catch (err) {
|
|
421
|
+
console.error(`[backup-verify] orphan scratch sweep failed: ${errMsg(err)}`);
|
|
422
|
+
}
|
|
143
423
|
let scratchDb;
|
|
144
424
|
try {
|
|
145
|
-
scratch = await mkdtemp(path.join(tmpdir(),
|
|
425
|
+
scratch = await mkdtemp(path.join(tmpdir(), SCRATCH_DIR_PREFIX));
|
|
146
426
|
scratchDb = path.join(scratch, path.basename(backupPath));
|
|
147
427
|
await copyFile(backupPath, scratchDb);
|
|
148
428
|
} catch (err) {
|
|
@@ -162,36 +442,36 @@ async function readBackBackupArtifact(backupPath, dbName, opts = {}) {
|
|
|
162
442
|
}
|
|
163
443
|
}
|
|
164
444
|
const keyHex = opts.keyHex === void 0 ? await resolveBackupKeyHex() : opts.keyHex;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
445
|
+
const offload = opts.offload ?? backupVerifyOffloadEnabled();
|
|
446
|
+
if (offload) {
|
|
447
|
+
const run = await runInBackupVerifyWorker({ op: "artifact", dbPath: scratchDb, keyHex: keyHex ?? null });
|
|
448
|
+
if (run.ok && run.response.op === "artifact") {
|
|
449
|
+
proof = run.response.outcome;
|
|
450
|
+
} else if (!run.ok && run.unavailable) {
|
|
451
|
+
reportBackupVerifyWorkerMissing("artifact read-back", run.reason);
|
|
452
|
+
} else {
|
|
453
|
+
return {
|
|
454
|
+
artifact: "not-checked",
|
|
455
|
+
manifestWritten: false,
|
|
456
|
+
manifest: null,
|
|
457
|
+
detail: `artifact read-back worker did not complete: ${run.ok ? `unexpected reply op=${run.response.op}` : run.reason}`
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (!proof) {
|
|
462
|
+
ownedClient = createClient(
|
|
463
|
+
keyHex ? { url: `file:${scratchDb}`, encryptionKey: keyHex } : { url: `file:${scratchDb}` }
|
|
464
|
+
);
|
|
465
|
+
recordDbOpen({ dbPath: scratchDb, source: "backup-verify-scratch", writeCapable: true, checkpointTimer: false });
|
|
466
|
+
client = ownedClient;
|
|
183
467
|
}
|
|
184
|
-
const schemaTables = await collectSchemaTables(client);
|
|
185
|
-
schemaHash = computeSchemaHash(schemaTables);
|
|
186
|
-
tables = await collectCounts(client, schemaTables.map((t) => t.name));
|
|
187
|
-
} catch (err) {
|
|
188
|
-
return {
|
|
189
|
-
artifact: "unreadable",
|
|
190
|
-
manifestWritten: false,
|
|
191
|
-
manifest: null,
|
|
192
|
-
detail: `the COPIED artifact could not be read back: ${errMsg(err)}`
|
|
193
|
-
};
|
|
194
468
|
}
|
|
469
|
+
if (!proof) proof = await runArtifactChecks(client);
|
|
470
|
+
if (proof.kind !== "ok") {
|
|
471
|
+
return { artifact: "unreadable", manifestWritten: false, manifest: null, detail: proof.detail };
|
|
472
|
+
}
|
|
473
|
+
const schemaHash = computeSchemaHash(proof.schemaTables);
|
|
474
|
+
const tables = proof.tables;
|
|
195
475
|
const manifest = {
|
|
196
476
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
197
477
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -203,7 +483,7 @@ async function readBackBackupArtifact(backupPath, dbName, opts = {}) {
|
|
|
203
483
|
const rows = Object.values(tables).reduce((n, c) => n + c, 0);
|
|
204
484
|
const readDetail = `artifact read back: ${Object.keys(tables).length} table(s), ${rows} row(s)`;
|
|
205
485
|
try {
|
|
206
|
-
await
|
|
486
|
+
await writeManifestAtomic(manifestPathFor(backupPath), JSON.stringify(manifest, null, 2));
|
|
207
487
|
} catch (err) {
|
|
208
488
|
return {
|
|
209
489
|
artifact: "readable",
|
|
@@ -478,14 +758,50 @@ async function verifyBackup(backupPath, opts = {}) {
|
|
|
478
758
|
}
|
|
479
759
|
}
|
|
480
760
|
}
|
|
481
|
-
let
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
761
|
+
let outcome = null;
|
|
762
|
+
if (opts.offload ?? backupVerifyOffloadEnabled()) {
|
|
763
|
+
const run = await runInBackupVerifyWorker({ op: "verify", dbPath: scratchDb, keyHex: keyHex ?? null });
|
|
764
|
+
if (run.ok && run.response.op === "verify") {
|
|
765
|
+
outcome = run.response.outcome;
|
|
766
|
+
} else if (!run.ok && run.unavailable) {
|
|
767
|
+
reportBackupVerifyWorkerMissing("verifyBackup", run.reason);
|
|
768
|
+
} else {
|
|
769
|
+
res = {
|
|
770
|
+
ok: false,
|
|
771
|
+
backup: name,
|
|
772
|
+
source: "none",
|
|
773
|
+
integrity: "unreadable",
|
|
774
|
+
tables: [],
|
|
775
|
+
reason: "not-checked",
|
|
776
|
+
detail: `verification worker did not complete; nothing was learned about the backup: ${run.ok ? `unexpected reply op=${run.response.op}` : run.reason}`
|
|
777
|
+
};
|
|
778
|
+
if (record) await recordVerdict(res);
|
|
779
|
+
return res;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
if (!outcome) {
|
|
783
|
+
let client = null;
|
|
784
|
+
try {
|
|
785
|
+
client = createClient(
|
|
786
|
+
keyHex ? { url: `file:${scratchDb}`, encryptionKey: keyHex } : { url: `file:${scratchDb}` }
|
|
787
|
+
);
|
|
788
|
+
recordDbOpen({ dbPath: scratchDb, source: "backup-verify-copy", writeCapable: true, checkpointTimer: false });
|
|
789
|
+
} catch (err) {
|
|
790
|
+
outcome = { kind: "open-failed", detail: errMsg(err) };
|
|
791
|
+
}
|
|
792
|
+
if (client) {
|
|
793
|
+
try {
|
|
794
|
+
outcome = await runVerifyChecks(client);
|
|
795
|
+
} finally {
|
|
796
|
+
try {
|
|
797
|
+
client.close?.();
|
|
798
|
+
} catch {
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if (!outcome) throw new Error("verification produced no outcome");
|
|
804
|
+
if (outcome.kind === "open-failed") {
|
|
489
805
|
res = {
|
|
490
806
|
ok: false,
|
|
491
807
|
backup: name,
|
|
@@ -493,48 +809,40 @@ async function verifyBackup(backupPath, opts = {}) {
|
|
|
493
809
|
integrity: "unreadable",
|
|
494
810
|
tables: [],
|
|
495
811
|
reason: "unreadable",
|
|
496
|
-
detail: `cannot read backup with configured key${targetManifest?.keyEpoch ? " (manifest key epoch matched; artifact is unreadable/corrupt)" : ""}: ${
|
|
812
|
+
detail: `cannot read backup with configured key${targetManifest?.keyEpoch ? " (manifest key epoch matched; artifact is unreadable/corrupt)" : ""}: ${outcome.detail}`
|
|
497
813
|
};
|
|
498
814
|
if (record) await recordVerdict(res);
|
|
499
815
|
return res;
|
|
500
816
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
};
|
|
515
|
-
if (record) await recordVerdict(res);
|
|
516
|
-
return res;
|
|
517
|
-
}
|
|
518
|
-
const schemaTables = await collectSchemaTables(client);
|
|
519
|
-
const schemaHash = computeSchemaHash(schemaTables);
|
|
520
|
-
const gotCounts = await collectCounts(client, schemaTables.map((t) => t.name));
|
|
521
|
-
const wantSource = opts.source ?? "auto";
|
|
522
|
-
const manifest = wantSource === "live" ? null : targetManifest;
|
|
523
|
-
if (manifest) {
|
|
524
|
-
res = compareToManifest(name, manifest, schemaHash, gotCounts);
|
|
525
|
-
} else {
|
|
526
|
-
res = await compareToLive(name, gotCounts, opts);
|
|
527
|
-
}
|
|
528
|
-
res.quickCheck = integrity.quickCheck;
|
|
529
|
-
res.cipherIntegrityCheck = integrity.cipherIntegrityCheck;
|
|
530
|
-
if (record) await recordVerdict(res, target);
|
|
817
|
+
if (outcome.kind === "integrity") {
|
|
818
|
+
res = {
|
|
819
|
+
ok: false,
|
|
820
|
+
backup: name,
|
|
821
|
+
source: "none",
|
|
822
|
+
integrity: outcome.status,
|
|
823
|
+
quickCheck: outcome.quickCheck,
|
|
824
|
+
cipherIntegrityCheck: outcome.cipherIntegrityCheck,
|
|
825
|
+
tables: [],
|
|
826
|
+
reason: outcome.status === "unreadable" ? "unreadable" : "integrity",
|
|
827
|
+
detail: `integrity check ${outcome.status}${outcome.quickCheck ? ` (quick_check=${outcome.quickCheck})` : ""}`
|
|
828
|
+
};
|
|
829
|
+
if (record) await recordVerdict(res);
|
|
531
830
|
return res;
|
|
532
|
-
} finally {
|
|
533
|
-
try {
|
|
534
|
-
client.close?.();
|
|
535
|
-
} catch {
|
|
536
|
-
}
|
|
537
831
|
}
|
|
832
|
+
if (outcome.kind === "error") throw new Error(outcome.detail);
|
|
833
|
+
const schemaHash = computeSchemaHash(outcome.schemaTables);
|
|
834
|
+
const gotCounts = outcome.tables;
|
|
835
|
+
const wantSource = opts.source ?? "auto";
|
|
836
|
+
const manifest = wantSource === "live" ? null : targetManifest;
|
|
837
|
+
if (manifest) {
|
|
838
|
+
res = compareToManifest(name, manifest, schemaHash, gotCounts);
|
|
839
|
+
} else {
|
|
840
|
+
res = await compareToLive(name, gotCounts, opts);
|
|
841
|
+
}
|
|
842
|
+
res.quickCheck = outcome.quickCheck;
|
|
843
|
+
res.cipherIntegrityCheck = outcome.cipherIntegrityCheck;
|
|
844
|
+
if (record) await recordVerdict(res, target);
|
|
845
|
+
return res;
|
|
538
846
|
} catch (err) {
|
|
539
847
|
res = {
|
|
540
848
|
ok: false,
|
|
@@ -565,18 +873,31 @@ async function maybeVerifyDailyBackup(backupPath) {
|
|
|
565
873
|
return null;
|
|
566
874
|
}
|
|
567
875
|
}
|
|
876
|
+
|
|
568
877
|
export {
|
|
569
|
-
|
|
878
|
+
manifestWriteEnabled,
|
|
570
879
|
dailyVerifyEnabled,
|
|
571
880
|
describeDailyVerifyPosture,
|
|
572
|
-
isCrashLoopBackup,
|
|
573
881
|
liveHardEnabled,
|
|
882
|
+
isCrashLoopBackup,
|
|
883
|
+
computeKeyEpoch,
|
|
574
884
|
manifestPathFor,
|
|
575
|
-
|
|
576
|
-
|
|
885
|
+
runQuickCheckOnArtifact,
|
|
886
|
+
runArtifactChecks,
|
|
887
|
+
runVerifyChecks,
|
|
888
|
+
BACKUP_VERIFY_WORKER_TIMEOUT_MS,
|
|
889
|
+
BACKUP_VERIFY_WORKER_MISSING_TAG,
|
|
890
|
+
BACKUP_VERIFY_WORKER_REPLY_REJECTED_TAG,
|
|
891
|
+
reportBackupVerifyWorkerMissing,
|
|
892
|
+
validateBackupVerifyWorkerReply,
|
|
893
|
+
backupVerifyOffloadEnabled,
|
|
894
|
+
resolveBackupVerifyWorker,
|
|
895
|
+
runInBackupVerifyWorker,
|
|
896
|
+
sweepOrphanScratchDirs,
|
|
897
|
+
writeManifestAtomic,
|
|
577
898
|
readBackBackupArtifact,
|
|
899
|
+
writeBackupManifest,
|
|
578
900
|
readManifest,
|
|
579
|
-
runQuickCheckOnArtifact,
|
|
580
901
|
verifyBackup,
|
|
581
|
-
|
|
902
|
+
maybeVerifyDailyBackup
|
|
582
903
|
};
|
|
@@ -4,21 +4,21 @@ import {
|
|
|
4
4
|
assertUsableEpoch,
|
|
5
5
|
deriveOrgKeyIdentities,
|
|
6
6
|
describeEpochRemedy
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-A5I2GYVQ.js";
|
|
8
8
|
import {
|
|
9
9
|
InviteError,
|
|
10
10
|
resolveAuth,
|
|
11
11
|
resolveEndpoint
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HA6BIZ6L.js";
|
|
13
13
|
import {
|
|
14
14
|
asOrgBillablePlan
|
|
15
15
|
} from "./chunk-W4H2MZAS.js";
|
|
16
16
|
import {
|
|
17
17
|
orgKeyFingerprintDisplay
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-6PXFF6IV.js";
|
|
19
19
|
import {
|
|
20
20
|
ed25519PrivateKeyFromSeed
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-MZNLQC6W.js";
|
|
22
22
|
|
|
23
23
|
// src/lib/org-key-admin.ts
|
|
24
24
|
import { sign } from "crypto";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getGlobalProceduresBlock
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HDQAVAV6.js";
|
|
4
4
|
import {
|
|
5
5
|
writePlatformReferenceFile
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4CN3EE6U.js";
|
|
7
7
|
|
|
8
8
|
// src/lib/employee-templates.ts
|
|
9
9
|
var BASE_OPERATING_PROCEDURES = `
|
|
@@ -132,7 +132,7 @@ async function verifyOrBlock(hookPath) {
|
|
|
132
132
|
process.stderr.write(`[SECURITY] Hook tamper detected: ${filename} \u2014 ${result.reason}
|
|
133
133
|
`);
|
|
134
134
|
try {
|
|
135
|
-
const { pushNotifyAsync } = await import("./push-notifications-
|
|
135
|
+
const { pushNotifyAsync } = await import("./push-notifications-QW4BWRC7.js");
|
|
136
136
|
pushNotifyAsync({
|
|
137
137
|
event: "security_alert",
|
|
138
138
|
title: "Hook tamper detected",
|