@agentmemory/agentmemory 0.9.30 → 0.9.32
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/.env.example +57 -48
- package/AGENTS.md +8 -8
- package/README.md +256 -819
- package/dist/.env.example +57 -48
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +2257 -1027
- package/dist/cli.mjs.map +1 -1
- package/dist/compression-recovery-CZh63Jmz.mjs +5997 -0
- package/dist/compression-recovery-CZh63Jmz.mjs.map +1 -0
- package/dist/{connect-B4_ca6BD.mjs → connect-BX3njQ3Y.mjs} +897 -276
- package/dist/connect-BX3njQ3Y.mjs.map +1 -0
- package/dist/hooks/_capture.d.mts +5 -1
- package/dist/hooks/_capture.d.mts.map +1 -1
- package/dist/hooks/_capture.mjs +141 -26
- package/dist/hooks/_capture.mjs.map +1 -1
- package/dist/hooks/notification.mjs +20 -6
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +83 -10
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +19 -6
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +19 -6
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +104 -22
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +83 -10
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +12 -4
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +59 -17
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +95 -15
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +75 -72
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +13 -5
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +32 -10
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +21 -6
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/{image-refs-T_urbwHM.mjs → image-refs-Cyta4Lf9.mjs} +2 -2
- package/dist/{image-refs-T_urbwHM.mjs.map → image-refs-Cyta4Lf9.mjs.map} +1 -1
- package/dist/index.mjs +16390 -11530
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/dsh.d.mts +55 -0
- package/dist/integrations/dsh.d.mts.map +1 -0
- package/dist/integrations/dsh.mjs +1172 -0
- package/dist/integrations/dsh.mjs.map +1 -0
- package/dist/{keyed-mutex-DchXsyfP.mjs → keyed-mutex-DCUh7PG-.mjs} +58 -9
- package/dist/keyed-mutex-DCUh7PG-.mjs.map +1 -0
- package/dist/{secret-store-BnY3A50C.mjs → secret-store-iYXRcrO8.mjs} +717 -474
- package/dist/secret-store-iYXRcrO8.mjs.map +1 -0
- package/dist/session-arguments-zxsbbd8y.mjs +113 -0
- package/dist/session-arguments-zxsbbd8y.mjs.map +1 -0
- package/dist/{src-Jsq9LCeH.mjs → src-C23nMpda.mjs} +5263 -4667
- package/dist/src-C23nMpda.mjs.map +1 -0
- package/dist/{standalone-DKCdrf1d.mjs → standalone-BYo5USDb.mjs} +379 -63
- package/dist/standalone-BYo5USDb.mjs.map +1 -0
- package/dist/standalone.d.mts +1 -1
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +864 -81
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +337 -168
- package/integrations/hermes/README.md +94 -0
- package/integrations/hermes/__init__.py +670 -0
- package/integrations/hermes/plugin.yaml +27 -0
- package/integrations/omp/LICENSE +190 -0
- package/integrations/omp/README.md +76 -0
- package/integrations/omp/capture.ts +1 -0
- package/integrations/omp/dist/index.mjs +1477 -0
- package/integrations/omp/index.ts +488 -0
- package/integrations/omp/package.json +13 -0
- package/integrations/omp/security.ts +67 -0
- package/integrations/omp/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/omp/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/omp/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/omp/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/omp/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/omp/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/omp/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/omp/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/omp/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/omp/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/omp/skills/commit-context/SKILL.md +64 -0
- package/integrations/omp/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/omp/skills/commit-history/SKILL.md +62 -0
- package/integrations/omp/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/forget/EXAMPLES.md +40 -0
- package/integrations/omp/skills/forget/SKILL.md +73 -0
- package/integrations/omp/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/omp/skills/handoff/SKILL.md +75 -0
- package/integrations/omp/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/lesson/SKILL.md +64 -0
- package/integrations/omp/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/omp/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/recall/EXAMPLES.md +74 -0
- package/integrations/omp/skills/recall/SKILL.md +74 -0
- package/integrations/omp/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/recap/EXAMPLES.md +62 -0
- package/integrations/omp/skills/recap/SKILL.md +68 -0
- package/integrations/omp/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/remember/EXAMPLES.md +67 -0
- package/integrations/omp/skills/remember/SKILL.md +66 -0
- package/integrations/omp/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/omp/skills/session-history/SKILL.md +67 -0
- package/integrations/omp/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/omp/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/LICENSE +190 -0
- package/integrations/openclaw/README.md +98 -0
- package/integrations/openclaw/openclaw.plugin.json +71 -0
- package/integrations/openclaw/package.json +38 -0
- package/integrations/openclaw/plugin.mjs +425 -0
- package/integrations/openclaw/plugin.yaml +26 -0
- package/integrations/openclaw/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/openclaw/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/openclaw/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/openclaw/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/openclaw/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/openclaw/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/openclaw/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/openclaw/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/openclaw/skills/commit-context/SKILL.md +64 -0
- package/integrations/openclaw/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/openclaw/skills/commit-history/SKILL.md +62 -0
- package/integrations/openclaw/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/forget/EXAMPLES.md +40 -0
- package/integrations/openclaw/skills/forget/SKILL.md +73 -0
- package/integrations/openclaw/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/openclaw/skills/handoff/SKILL.md +75 -0
- package/integrations/openclaw/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/lesson/SKILL.md +64 -0
- package/integrations/openclaw/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/openclaw/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/recall/EXAMPLES.md +74 -0
- package/integrations/openclaw/skills/recall/SKILL.md +74 -0
- package/integrations/openclaw/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/recap/EXAMPLES.md +62 -0
- package/integrations/openclaw/skills/recap/SKILL.md +68 -0
- package/integrations/openclaw/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/remember/EXAMPLES.md +67 -0
- package/integrations/openclaw/skills/remember/SKILL.md +66 -0
- package/integrations/openclaw/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/openclaw/skills/session-history/SKILL.md +67 -0
- package/integrations/openclaw/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/openclaw/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/LICENSE +190 -0
- package/integrations/pi/README.md +46 -51
- package/integrations/pi/dist/index.mjs +1460 -0
- package/integrations/pi/index.ts +192 -175
- package/integrations/pi/package.json +17 -7
- package/integrations/pi/security.ts +6 -26
- package/integrations/pi/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/pi/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/pi/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/pi/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/pi/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/pi/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/pi/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/pi/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/pi/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/pi/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/pi/skills/commit-context/SKILL.md +64 -0
- package/integrations/pi/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/pi/skills/commit-history/SKILL.md +62 -0
- package/integrations/pi/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/forget/EXAMPLES.md +40 -0
- package/integrations/pi/skills/forget/SKILL.md +73 -0
- package/integrations/pi/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/pi/skills/handoff/SKILL.md +75 -0
- package/integrations/pi/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/lesson/SKILL.md +64 -0
- package/integrations/pi/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/pi/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/recall/EXAMPLES.md +74 -0
- package/integrations/pi/skills/recall/SKILL.md +74 -0
- package/integrations/pi/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/recap/EXAMPLES.md +62 -0
- package/integrations/pi/skills/recap/SKILL.md +68 -0
- package/integrations/pi/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/remember/EXAMPLES.md +67 -0
- package/integrations/pi/skills/remember/SKILL.md +66 -0
- package/integrations/pi/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/pi/skills/session-history/SKILL.md +67 -0
- package/integrations/pi/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/pi/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/package.json +33 -11
- package/plugin/.claude-plugin/plugin.json +16 -3
- package/plugin/.codex-plugin/plugin.json +4 -3
- package/plugin/.devin-plugin/plugin.json +6 -5
- package/plugin/.mcp.json +5 -1
- package/plugin/README.md +71 -0
- package/plugin/cursor/hooks.json +23 -8
- package/plugin/hooks/hooks.json +24 -12
- package/plugin/hooks.json +67 -0
- package/plugin/opencode/README.md +1 -1
- package/plugin/opencode/agentmemory-capture.ts +25 -11
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +1 -1
- package/plugin/scripts/_capture.d.mts +5 -1
- package/plugin/scripts/_capture.d.mts.map +1 -1
- package/plugin/scripts/_capture.mjs +141 -26
- package/plugin/scripts/_capture.mjs.map +1 -1
- package/plugin/scripts/cursor/run-detached.mjs +786 -0
- package/plugin/scripts/cursor/run-detached.mjs.map +1 -0
- package/plugin/scripts/cursor/run-hook.d.mts +1 -0
- package/plugin/scripts/cursor/run-hook.mjs +704 -0
- package/plugin/scripts/cursor/run-hook.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +20 -6
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +61 -11
- package/plugin/scripts/post-tool-failure.mjs +19 -6
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +19 -6
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +104 -22
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +83 -10
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +12 -4
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +59 -17
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +95 -15
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +75 -72
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +13 -5
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +32 -10
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +21 -6
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +21 -7
- package/plugin/skills/agentmemory-agents/REFERENCE.md +8 -7
- package/plugin/skills/agentmemory-agents/SKILL.md +19 -5
- package/plugin/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-architecture/SKILL.md +8 -4
- package/plugin/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-config/REFERENCE.md +13 -15
- package/plugin/skills/agentmemory-config/SKILL.md +34 -10
- package/plugin/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-hooks/SKILL.md +31 -10
- package/plugin/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +5 -5
- package/plugin/skills/agentmemory-mcp-tools/SKILL.md +16 -3
- package/plugin/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +10 -1
- package/plugin/skills/agentmemory-rest-api/SKILL.md +12 -6
- package/plugin/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/commit-context/SKILL.md +1 -1
- package/plugin/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/commit-history/SKILL.md +1 -1
- package/plugin/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/forget/EXAMPLES.md +19 -54
- package/plugin/skills/forget/SKILL.md +16 -12
- package/plugin/skills/forget/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/handoff/EXAMPLES.md +5 -4
- package/plugin/skills/handoff/SKILL.md +10 -5
- package/plugin/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/lesson/SKILL.md +1 -1
- package/plugin/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/memory-discipline/SKILL.md +1 -1
- package/plugin/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/recall/SKILL.md +18 -7
- package/plugin/skills/recall/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/recap/EXAMPLES.md +5 -3
- package/plugin/skills/recap/SKILL.md +11 -6
- package/plugin/skills/recap/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/remember/EXAMPLES.md +3 -3
- package/plugin/skills/remember/SKILL.md +1 -1
- package/plugin/skills/remember/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/session-history/EXAMPLES.md +2 -2
- package/plugin/skills/session-history/SKILL.md +10 -4
- package/plugin/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/write-agentmemory-skill/SKILL.md +2 -1
- package/plugin/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/dist/connect-B4_ca6BD.mjs.map +0 -1
- package/dist/docker-compose.yml +0 -73
- package/dist/iii-config.docker.yaml +0 -53
- package/dist/iii-config.yaml +0 -63
- package/dist/keyed-mutex-DchXsyfP.mjs.map +0 -1
- package/dist/secret-store-BnY3A50C.mjs.map +0 -1
- package/dist/src-Jsq9LCeH.mjs.map +0 -1
- package/dist/standalone-DKCdrf1d.mjs.map +0 -1
- package/dist/status-IRz7ta8-.mjs +0 -2344
- package/dist/status-IRz7ta8-.mjs.map +0 -1
- package/docker-compose.yml +0 -73
- package/iii-config.docker.yaml +0 -53
- package/iii-config.yaml +0 -63
- package/plugin/scripts/post-commit.mjs +0 -184
- package/plugin/scripts/post-commit.mjs.map +0 -1
- /package/plugin/scripts/{post-commit.d.mts → cursor/run-detached.d.mts} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"status-IRz7ta8-.mjs","names":[],"sources":["../src/runtime-paths.ts","../src/shutdown.ts","../src/cli-data-dir.ts","../src/functions/privacy.ts","../src/capture/spool.ts","../src/prompts/graph-extraction.ts","../src/functions/graph.ts","../src/functions/graph-compact-boot.ts","../src/functions/status.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\ninterface RuntimeMetadataPathOptions {\n env?: NodeJS.ProcessEnv;\n home?: string;\n}\n\nexport function runtimeMetadataPath(\n name: string,\n options: RuntimeMetadataPathOptions = {},\n): string {\n const env = options.env ?? process.env;\n const home = options.home ?? homedir();\n const baseDir = env[\"AGENTMEMORY_RUNTIME_DIR\"]\n ? resolve(env[\"AGENTMEMORY_RUNTIME_DIR\"])\n : join(home, \".agentmemory\");\n return join(baseDir, name);\n}\n","export const SHUTDOWN_FLUSH_TIMEOUT_MS = 4000;\nexport const SHUTDOWN_HARD_EXIT_MS = 8000;\n\nexport async function settleWithin(\n work: Promise<unknown>,\n ms: number,\n): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const expiry = new Promise<boolean>((resolve) => {\n timer = setTimeout(() => resolve(false), ms);\n });\n try {\n return await Promise.race([work.then(() => true), expiry]);\n } finally {\n clearTimeout(timer);\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { homedir, platform } from \"node:os\";\n\nexport type DataDirSource = \"flag\" | \"env\" | \"default\";\n\nexport type ResolvedDataDir = {\n dataDir: string;\n source: DataDirSource;\n relocatedFrom?: string;\n};\n\ntype ResolveDataDirOptions = {\n args?: string[];\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n home?: string;\n platform?: NodeJS.Platform;\n};\n\nfunction argValue(args: string[], name: string): string | undefined {\n const equals = `${name}=`;\n const inline = args.find((arg) => arg.startsWith(equals));\n if (inline) return inline.slice(equals.length);\n\n const idx = args.indexOf(name);\n if (idx !== -1) return args[idx + 1];\n return undefined;\n}\n\nfunction expandHome(pathValue: string, home: string): string {\n if (pathValue === \"~\") return home;\n if (pathValue.startsWith(\"~/\") || pathValue.startsWith(\"~\\\\\")) {\n return join(home, pathValue.slice(2));\n }\n return pathValue;\n}\n\nfunction absoluteDataDir(pathValue: string, cwd: string, home: string): string {\n const expanded = expandHome(pathValue, home);\n return isAbsolute(expanded) ? expanded : resolve(cwd, expanded);\n}\n\nfunction platformDefaultDataDir(\n env: NodeJS.ProcessEnv,\n home: string,\n nodePlatform: NodeJS.Platform,\n useXdg = true,\n): string {\n if (nodePlatform === \"darwin\") {\n return join(home, \"Library\", \"Application Support\", \"agentmemory\");\n }\n if (nodePlatform === \"win32\") {\n const appData = env[\"APPDATA\"];\n return appData\n ? join(appData, \"agentmemory\")\n : join(home, \".agentmemory\");\n }\n const xdgDataHome = env[\"XDG_DATA_HOME\"];\n if (useXdg && xdgDataHome && isAbsolute(xdgDataHome)) {\n return join(xdgDataHome, \"agentmemory\");\n }\n return join(home, \".local\", \"share\", \"agentmemory\");\n}\n\nfunction nearestGitParent(pathValue: string): string | undefined {\n let current = pathValue;\n while (true) {\n if (existsSync(join(current, \".git\"))) return current;\n const parent = dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n}\n\nfunction isWithin(parent: string, child: string): boolean {\n const pathFromParent = relative(parent, child);\n return (\n pathFromParent === \"\" ||\n (pathFromParent !== \"..\" &&\n !pathFromParent.startsWith(`..${sep}`) &&\n !isAbsolute(pathFromParent))\n );\n}\n\nexport function resolveDataDir(options: ResolveDataDirOptions = {}): ResolvedDataDir {\n const args = options.args ?? process.argv.slice(2);\n const env = options.env ?? process.env;\n const cwd = options.cwd ?? process.cwd();\n const home = options.home ?? homedir();\n const nodePlatform = options.platform ?? platform();\n const parsedInstance = parseInt(argValue(args, \"--instance\") ?? \"0\", 10);\n const instance =\n parsedInstance > 0 && parsedInstance <= 50 ? parsedInstance : 0;\n const forInstance = (dataDir: string) =>\n instance ? join(dataDir, `instance-${instance}`) : dataDir;\n\n const flagValue = argValue(args, \"--data-dir\");\n if (flagValue) {\n return {\n dataDir: forInstance(absoluteDataDir(flagValue, cwd, home)),\n source: \"flag\",\n };\n }\n\n const envValue = env[\"AGENTMEMORY_DATA_DIR\"];\n if (envValue) {\n return {\n dataDir: forInstance(absoluteDataDir(envValue, cwd, home)),\n source: \"env\",\n };\n }\n\n const legacyDir = resolve(cwd, \"data\");\n const hasLegacyStore =\n existsSync(join(legacyDir, \"state_store.db\")) ||\n existsSync(join(legacyDir, \"iii-config.yaml\"));\n if (instance === 0 && hasLegacyStore) {\n return { dataDir: legacyDir, source: \"default\" };\n }\n\n const defaultDir = platformDefaultDataDir(env, home, nodePlatform);\n const gitParent = nearestGitParent(cwd);\n if (gitParent && isWithin(gitParent, defaultDir)) {\n const relocated = platformDefaultDataDir(env, home, nodePlatform, false);\n if (relocated !== defaultDir) {\n return {\n dataDir: forInstance(relocated),\n source: \"default\",\n relocatedFrom: defaultDir,\n };\n }\n }\n\n return {\n dataDir: forInstance(defaultDir),\n source: \"default\",\n };\n}\n","import type { IIIClient } from \"iii-sdk\";\n\nconst PRIVATE_TAG_RE = /<private>[\\s\\S]*?<\\/private>/gi;\n\nconst SECRET_PATTERN_SOURCES = [\n /(?:api[_-]?key|secret|token|password|credential|auth)[\\s]*[=:]\\s*[\"']?[A-Za-z0-9_\\-/.+]{20,}[\"']?/gi,\n /Bearer\\s+[A-Za-z0-9._\\-+/=]{20,}/gi,\n /sk-proj-[A-Za-z0-9\\-_]{20,}/g,\n /(?:sk|pk|rk|ak)-[A-Za-z0-9][A-Za-z0-9\\-_]{19,}/g,\n /sk-ant-[A-Za-z0-9\\-_]{20,}/g,\n /gh[pus]_[A-Za-z0-9]{36,}/g,\n /github_pat_[A-Za-z0-9_]{22,}/g,\n /xoxb-[A-Za-z0-9\\-]+/g,\n /AKIA[0-9A-Z]{16}/g,\n /AIza[A-Za-z0-9\\-_]{35}/g,\n /eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g,\n /npm_[A-Za-z0-9]{36}/g,\n /glpat-[A-Za-z0-9\\-_]{20,}/g,\n /dop_v1_[A-Za-z0-9]{64}/g,\n];\n\nconst PRIVATE_KEY_BLOCK_RE =\n /-----BEGIN [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----[\\s\\S]*?(?:-----END [A-Z0-9 ]*PRIVATE KEY(?: BLOCK)?-----|$)/g;\n\nconst URL_CREDENTIALS_RE =\n /\\b([a-z][a-z0-9+.-]*:\\/\\/)[^\\s/?#@:\"'<>]*:[^\\s/?#@\"'<>]+@/gi;\n\nexport function stripPrivateData(input: string): string {\n let result = input.replace(PRIVATE_TAG_RE, \"[REDACTED]\");\n result = result.replace(new RegExp(PRIVATE_KEY_BLOCK_RE.source, PRIVATE_KEY_BLOCK_RE.flags), \"[REDACTED_SECRET]\");\n result = result.replace(new RegExp(URL_CREDENTIALS_RE.source, URL_CREDENTIALS_RE.flags), \"$1[REDACTED_SECRET]@\");\n for (const source of SECRET_PATTERN_SOURCES) {\n const pattern = new RegExp(source.source, source.flags);\n result = result.replace(pattern, \"[REDACTED_SECRET]\");\n }\n return result;\n}\n\nexport function scrubRecord<T>(value: T): T {\n if (typeof value === \"string\") return stripPrivateData(value) as T;\n if (Array.isArray(value)) return value.map((item) => scrubRecord(item)) as T;\n if (value !== null && typeof value === \"object\") {\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n out[key] = scrubRecord(item);\n }\n return out as T;\n }\n return value;\n}\n\nexport const SCRUBBED_WRITE_FUNCTIONS: ReadonlySet<string> = new Set([\n \"mem::remember\",\n \"mem::evolve\",\n \"mem::slot-create\",\n \"mem::slot-append\",\n \"mem::slot-replace\",\n \"mem::lesson-save\",\n \"mem::action-create\",\n \"mem::action-update\",\n \"mem::sketch-create\",\n \"mem::sketch-add\",\n \"mem::import\",\n \"mem::mesh-receive\",\n \"mem::team-share\",\n \"mem::signal-send\",\n \"mem::routine-create\",\n \"mem::checkpoint-create\",\n \"mem::checkpoint-resolve\",\n \"mem::sentinel-create\",\n \"mem::sentinel-trigger\",\n \"mem::core-add\",\n \"mem::facet-tag\",\n]);\n\ntype RegisterFunction = (id: string, handler: unknown, ...rest: unknown[]) => unknown;\n\nexport function withWriteScrubbing<T extends object>(sdk: T): T {\n return new Proxy(sdk, {\n get(target, prop) {\n const value = Reflect.get(target, prop, target);\n if (typeof value !== \"function\") return value;\n if (prop !== \"registerFunction\") return value.bind(target);\n const register = value as RegisterFunction;\n return (id: string, handler: unknown, ...rest: unknown[]) => {\n if (!SCRUBBED_WRITE_FUNCTIONS.has(id) || typeof handler !== \"function\") {\n return register.call(target, id, handler, ...rest);\n }\n const original = handler as (data: unknown, ...args: unknown[]) => unknown;\n const scrubbed = (data: unknown, ...args: unknown[]) => original(scrubRecord(data), ...args);\n return register.call(target, id, scrubbed, ...rest);\n };\n },\n });\n}\n\nexport function registerPrivacyFunction(sdk: IIIClient): void {\n sdk.registerFunction(\"mem::privacy\", \n async (data: { input?: unknown } | undefined) => {\n if (!data || typeof data.input !== \"string\") {\n return { output: \"\", error: \"invalid input: expected string field 'input'\" };\n }\n return { output: stripPrivateData(data.input) };\n },\n );\n}\n","import {\n chmodSync,\n closeSync,\n existsSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n utimesSync,\n writeFileSync,\n writeSync,\n} from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { resolveDataDir } from \"../cli-data-dir.js\";\nimport { stripPrivateData } from \"../functions/privacy.js\";\n\nexport interface SpoolRecord {\n v: 1;\n eventId: string;\n spooledAt: string;\n reason: string;\n attempts: number;\n body: Record<string, unknown>;\n bootId?: string;\n}\n\nexport interface SentMark {\n bootId: string;\n durableAfterMs: number;\n}\n\nexport interface SentReconcile {\n released: number;\n requeued: number;\n}\n\nexport interface SpoolPolicy {\n enabled: boolean;\n maxBytes: number;\n maxAgeMs: number;\n maxRecordBytes: number;\n}\n\nexport interface SpoolStats {\n spooled: number;\n dropped: number;\n droppedBytes: number;\n expired: number;\n delivered: number;\n duplicates: number;\n rejected: number;\n lastSpooledAt?: string;\n lastSpoolReason?: string;\n lastDropAt?: string;\n lastDropReason?: string;\n lastDrainAt?: string;\n lastDrainDelivered?: number;\n lastDrainDuplicates?: number;\n lastDrainRejected?: number;\n lastDrainRemaining?: number;\n lastDrainError?: string;\n}\n\nexport interface SpoolPaths {\n dir: string;\n name: string;\n file: string;\n lock: string;\n drainLock: string;\n stats: string;\n}\n\nexport interface SpoolSummary {\n enabled: boolean;\n path: string;\n records: number;\n bytes: number;\n oldestAt: string | null;\n retained: number;\n retainedBytes: number;\n maxBytes: number;\n maxAgeHours: number;\n stats: SpoolStats;\n}\n\nexport type SendOutcome = \"delivered\" | \"duplicate\" | \"rejected\" | \"retry\";\n\nexport interface DrainResult {\n claimed: number;\n delivered: number;\n duplicates: number;\n rejected: number;\n expired: number;\n corrupt: number;\n remaining: number;\n error?: string;\n skipped?: \"locked\" | \"empty\" | \"disabled\";\n}\n\nconst DEFAULT_MAX_BYTES = 5 * 1024 * 1024;\nconst MIN_MAX_BYTES = 64 * 1024;\nconst DEFAULT_MAX_AGE_HOURS = 168;\nconst LOCK_STALE_MS = 10_000;\nconst DRAIN_LOCK_STALE_MS = 120_000;\nconst ORPHAN_CLAIM_MS = 120_000;\nconst LOCK_WAIT_MS = 500;\nconst IMAGE_PLACEHOLDER = \"[image dropped from capture spool]\";\nconst BOOT_ID_RE = /^[A-Za-z0-9]{8,64}$/;\nconst SENT_FILE_RE = /^([A-Za-z0-9]{8,64})-(\\d+)\\.jsonl$/;\nconst SENT_BUCKET_MS = 1000;\nconst MAX_DURABLE_AFTER_MS = 10 * 60_000;\n\nfunction emptyStats(): SpoolStats {\n return { spooled: 0, dropped: 0, droppedBytes: 0, expired: 0, delivered: 0, duplicates: 0, rejected: 0 };\n}\n\nfunction positiveInt(raw: string | undefined, fallback: number): number {\n if (!raw || !/^\\d+$/.test(raw.trim())) return fallback;\n const n = parseInt(raw.trim(), 10);\n return n > 0 ? n : fallback;\n}\n\nexport function spoolPolicy(env: NodeJS.ProcessEnv = process.env): SpoolPolicy {\n const maxBytes = Math.max(MIN_MAX_BYTES, positiveInt(env[\"AGENTMEMORY_CAPTURE_SPOOL_MAX_BYTES\"], DEFAULT_MAX_BYTES));\n const maxAgeHours = positiveInt(env[\"AGENTMEMORY_CAPTURE_SPOOL_MAX_AGE_HOURS\"], DEFAULT_MAX_AGE_HOURS);\n return {\n enabled: env[\"AGENTMEMORY_CAPTURE_SPOOL\"] !== \"false\",\n maxBytes,\n maxAgeMs: maxAgeHours * 3600_000,\n maxRecordBytes: Math.min(256 * 1024, Math.floor(maxBytes / 4)),\n };\n}\n\nexport function spoolDir(env: NodeJS.ProcessEnv = process.env): string {\n const explicit = env[\"AGENTMEMORY_CAPTURE_SPOOL_DIR\"];\n if (explicit && explicit.trim()) return resolve(explicit.trim());\n return join(resolveDataDir({ args: [], env }).dataDir, \"capture-spool\");\n}\n\nconst LOOPBACK = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\", \"0.0.0.0\"]);\n\nexport function spoolTargetName(url: string): string {\n try {\n const u = new URL(url);\n const host = LOOPBACK.has(u.hostname) ? \"local\" : u.hostname.toLowerCase().replace(/[^a-z0-9.-]/g, \"_\");\n const port = u.port || (u.protocol === \"https:\" ? \"443\" : \"80\");\n return `${host}-${port}`;\n } catch {\n return \"local-3111\";\n }\n}\n\nexport function spoolPaths(url: string, dir: string = spoolDir()): SpoolPaths {\n const name = spoolTargetName(url);\n return {\n dir,\n name,\n file: join(dir, `${name}.jsonl`),\n lock: join(dir, `${name}.lock`),\n drainLock: join(dir, `${name}.drain.lock`),\n stats: join(dir, `${name}.stats.json`),\n };\n}\n\nfunction ensureDir(dir: string): void {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n try {\n chmodSync(dir, 0o700);\n } catch {}\n}\n\nfunction sleepSync(ms: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\nfunction tryLock(path: string, staleMs: number): boolean {\n try {\n const fd = openSync(path, \"wx\", 0o600);\n writeSync(fd, `${process.pid}\\n`);\n closeSync(fd);\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") return false;\n try {\n if (Date.now() - statSync(path).mtimeMs > staleMs) unlinkSync(path);\n } catch {}\n return false;\n }\n}\n\nfunction releaseLock(path: string): void {\n try {\n unlinkSync(path);\n } catch {}\n}\n\nfunction withLock<T>(path: string, fn: (locked: boolean) => T, waitMs = LOCK_WAIT_MS): T {\n const deadline = Date.now() + waitMs;\n let locked = tryLock(path, LOCK_STALE_MS);\n while (!locked && Date.now() < deadline) {\n sleepSync(5);\n locked = tryLock(path, LOCK_STALE_MS);\n }\n try {\n return fn(locked);\n } finally {\n if (locked) releaseLock(path);\n }\n}\n\nexport function readSpoolStats(paths: SpoolPaths): SpoolStats {\n try {\n const parsed = JSON.parse(readFileSync(paths.stats, \"utf-8\")) as Partial<SpoolStats>;\n return { ...emptyStats(), ...parsed };\n } catch {\n return emptyStats();\n }\n}\n\nfunction writeStats(paths: SpoolPaths, patch: (stats: SpoolStats) => void): void {\n try {\n const stats = readSpoolStats(paths);\n patch(stats);\n const tmp = `${paths.stats}.${process.pid}.tmp`;\n writeFileSync(tmp, JSON.stringify(stats), { mode: 0o600 });\n renameSync(tmp, paths.stats);\n } catch {}\n}\n\nfunction fileSize(path: string): number {\n try {\n return statSync(path).size;\n } catch {\n return 0;\n }\n}\n\nfunction sanitizeBody(body: Record<string, unknown>): Record<string, unknown> {\n try {\n return JSON.parse(stripPrivateData(JSON.stringify(body))) as Record<string, unknown>;\n } catch {\n return body;\n }\n}\n\nfunction withoutImage(body: Record<string, unknown>): Record<string, unknown> {\n const data = body[\"data\"];\n if (!data || typeof data !== \"object\" || Array.isArray(data)) return body;\n const d = data as Record<string, unknown>;\n if (d[\"image_data\"] === undefined) return body;\n return { ...body, data: { ...d, image_data: IMAGE_PLACEHOLDER } };\n}\n\nfunction parseLines(text: string): { records: SpoolRecord[]; corrupt: number } {\n const records: SpoolRecord[] = [];\n let corrupt = 0;\n for (const line of text.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const rec = JSON.parse(line) as SpoolRecord;\n if (rec && typeof rec.eventId === \"string\" && rec.body && typeof rec.body === \"object\") records.push(rec);\n else corrupt++;\n } catch {\n corrupt++;\n }\n }\n return { records, corrupt };\n}\n\nfunction isExpired(rec: SpoolRecord, policy: SpoolPolicy, now: number): boolean {\n const at = Date.parse(rec.spooledAt);\n return Number.isFinite(at) && now - at > policy.maxAgeMs;\n}\n\nfunction serialize(records: SpoolRecord[]): string {\n return records.map((r) => JSON.stringify(r)).join(\"\\n\") + (records.length ? \"\\n\" : \"\");\n}\n\nfunction rewriteLocked(paths: SpoolPaths, records: SpoolRecord[]): void {\n const tmp = `${paths.file}.${process.pid}.tmp`;\n const fd = openSync(tmp, \"w\", 0o600);\n try {\n writeSync(fd, serialize(records));\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n renameSync(tmp, paths.file);\n}\n\nfunction pruneExpiredLocked(paths: SpoolPaths, policy: SpoolPolicy): number {\n if (!existsSync(paths.file)) return 0;\n const { records } = parseLines(readFileSync(paths.file, \"utf-8\"));\n const now = Date.now();\n const kept = records.filter((r) => !isExpired(r, policy, now));\n const expired = records.length - kept.length;\n if (expired > 0) rewriteLocked(paths, kept);\n return expired;\n}\n\nexport interface AppendResult {\n spooled: boolean;\n dropped?: \"disabled\" | \"too-large\" | \"full\" | \"error\";\n}\n\nexport function appendSpool(\n url: string,\n eventId: string,\n body: Record<string, unknown>,\n reason: string,\n options: { policy?: SpoolPolicy; dir?: string; attempts?: number } = {},\n): AppendResult {\n const policy = options.policy ?? spoolPolicy();\n if (!policy.enabled) return { spooled: false, dropped: \"disabled\" };\n const paths = spoolPaths(url, options.dir);\n const note = (dropReason: NonNullable<AppendResult[\"dropped\"]>, bytes: number) => {\n writeStats(paths, (s) => {\n s.dropped++;\n s.droppedBytes += bytes;\n s.lastDropAt = new Date().toISOString();\n s.lastDropReason = dropReason;\n });\n return { spooled: false, dropped: dropReason } as AppendResult;\n };\n try {\n ensureDir(paths.dir);\n const record: SpoolRecord = {\n v: 1,\n eventId,\n spooledAt: new Date().toISOString(),\n reason,\n attempts: options.attempts ?? 0,\n body: sanitizeBody(body),\n };\n let line = JSON.stringify(record) + \"\\n\";\n if (Buffer.byteLength(line) > policy.maxRecordBytes) {\n record.body = withoutImage(record.body);\n line = JSON.stringify(record) + \"\\n\";\n }\n const bytes = Buffer.byteLength(line);\n if (bytes > policy.maxRecordBytes) return note(\"too-large\", bytes);\n return withLock(paths.lock, (locked) => {\n let expired = 0;\n if (locked && fileSize(paths.file) + bytes > policy.maxBytes) expired = pruneExpiredLocked(paths, policy);\n const over = fileSize(paths.file) + sentBytes(paths) + bytes - policy.maxBytes;\n if (locked && over > 0) evictSent(paths, over);\n if (fileSize(paths.file) + sentBytes(paths) + bytes > policy.maxBytes) {\n if (expired) writeStats(paths, (s) => void (s.expired += expired));\n return note(\"full\", bytes);\n }\n const fd = openSync(paths.file, \"a\", 0o600);\n try {\n writeSync(fd, line);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n writeStats(paths, (s) => {\n s.spooled++;\n s.expired += expired;\n s.lastSpooledAt = record.spooledAt;\n s.lastSpoolReason = reason;\n });\n return { spooled: true } as AppendResult;\n });\n } catch {\n return { spooled: false, dropped: \"error\" };\n }\n}\n\ninterface SentSegment {\n file: string;\n bootId: string;\n dueAt: number;\n bytes: number;\n}\n\nfunction listSent(paths: SpoolPaths): SentSegment[] {\n const segments: SentSegment[] = [];\n let entries: string[];\n try {\n entries = readdirSync(paths.dir);\n } catch {\n return segments;\n }\n const prefix = `${paths.name}.sent-`;\n for (const entry of entries) {\n if (!entry.startsWith(prefix)) continue;\n const match = entry.slice(prefix.length).match(SENT_FILE_RE);\n if (!match) continue;\n const file = join(paths.dir, entry);\n segments.push({ file, bootId: match[1]!, dueAt: Number(match[2]), bytes: fileSize(file) });\n }\n return segments;\n}\n\nfunction sentBytes(paths: SpoolPaths): number {\n return listSent(paths).reduce((n, s) => n + s.bytes, 0);\n}\n\nfunction evictSent(paths: SpoolPaths, need: number): void {\n let freed = 0;\n for (const seg of listSent(paths).sort((a, b) => a.dueAt - b.dueAt)) {\n if (freed >= need) return;\n try {\n unlinkSync(seg.file);\n freed += seg.bytes;\n } catch {}\n }\n}\n\nexport function parseSentMark(body: unknown): SentMark | null {\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return null;\n const bootId = (body as Record<string, unknown>)[\"bootId\"];\n const after = (body as Record<string, unknown>)[\"durableAfterMs\"];\n if (typeof bootId !== \"string\" || !BOOT_ID_RE.test(bootId)) return null;\n if (typeof after !== \"number\" || !Number.isFinite(after) || after < 0) return null;\n return { bootId, durableAfterMs: Math.min(Math.ceil(after), MAX_DURABLE_AFTER_MS) };\n}\n\nexport function retainSent(\n url: string,\n eventId: string,\n body: Record<string, unknown>,\n mark: SentMark,\n options: { policy?: SpoolPolicy; dir?: string; now?: number } = {},\n): boolean {\n const policy = options.policy ?? spoolPolicy();\n if (!policy.enabled || !BOOT_ID_RE.test(mark.bootId)) return false;\n const paths = spoolPaths(url, options.dir);\n const now = options.now ?? Date.now();\n try {\n ensureDir(paths.dir);\n const record: SpoolRecord = {\n v: 1,\n eventId,\n spooledAt: new Date(now).toISOString(),\n reason: \"sent\",\n attempts: 0,\n body: sanitizeBody(body),\n bootId: mark.bootId,\n };\n let line = JSON.stringify(record) + \"\\n\";\n if (Buffer.byteLength(line) > policy.maxRecordBytes) {\n record.body = withoutImage(record.body);\n line = JSON.stringify(record) + \"\\n\";\n }\n const bytes = Buffer.byteLength(line);\n if (bytes > policy.maxRecordBytes) return false;\n const dueAt = Math.ceil((now + mark.durableAfterMs) / SENT_BUCKET_MS) * SENT_BUCKET_MS;\n const file = join(paths.dir, `${paths.name}.sent-${mark.bootId}-${dueAt}.jsonl`);\n return withLock(paths.lock, () => {\n if (fileSize(paths.file) + sentBytes(paths) + bytes > policy.maxBytes) return false;\n const fd = openSync(file, \"a\", 0o600);\n try {\n writeSync(fd, line);\n } finally {\n closeSync(fd);\n }\n return true;\n });\n } catch {\n return false;\n }\n}\n\nexport function reconcileSent(\n url: string,\n bootId: string,\n options: { policy?: SpoolPolicy; dir?: string; now?: number } = {},\n): SentReconcile {\n const result: SentReconcile = { released: 0, requeued: 0 };\n const policy = options.policy ?? spoolPolicy();\n if (!policy.enabled) return result;\n const paths = spoolPaths(url, options.dir);\n const now = options.now ?? Date.now();\n for (const seg of listSent(paths)) {\n if (seg.bootId === bootId) {\n if (seg.dueAt > now) continue;\n try {\n unlinkSync(seg.file);\n result.released++;\n } catch {}\n continue;\n }\n const target = join(paths.dir, `${paths.name}.draining-${process.pid}-${now}-${result.requeued}.jsonl`);\n try {\n renameSync(seg.file, target);\n } catch {\n continue;\n }\n try {\n utimesSync(target, 0, 0);\n } catch {}\n result.requeued++;\n }\n return result;\n}\n\nfunction claimFiles(paths: SpoolPaths): string[] {\n const claimed: string[] = [];\n try {\n const prefix = `${paths.name}.draining-`;\n for (const entry of readdirSync(paths.dir)) {\n if (!entry.startsWith(prefix) || !entry.endsWith(\".jsonl\")) continue;\n const full = join(paths.dir, entry);\n try {\n if (Date.now() - statSync(full).mtimeMs > ORPHAN_CLAIM_MS) claimed.push(full);\n } catch {}\n }\n } catch {}\n if (fileSize(paths.file) > 0) {\n const target = join(paths.dir, `${paths.name}.draining-${process.pid}-${Date.now()}.jsonl`);\n withLock(paths.lock, (locked) => {\n if (!locked) return;\n try {\n renameSync(paths.file, target);\n claimed.push(target);\n } catch {}\n });\n }\n return claimed;\n}\n\nfunction requeueLocked(paths: SpoolPaths, leftover: SpoolRecord[]): void {\n if (leftover.length === 0) return;\n const existing = existsSync(paths.file) ? parseLines(readFileSync(paths.file, \"utf-8\")).records : [];\n rewriteLocked(paths, [...leftover, ...existing]);\n}\n\nfunction requeueUnlocked(paths: SpoolPaths, leftover: SpoolRecord[]): void {\n if (leftover.length === 0) return;\n const target = join(paths.dir, `${paths.name}.draining-${process.pid}-${Date.now()}-requeue.jsonl`);\n const fd = openSync(target, \"wx\", 0o600);\n try {\n writeSync(fd, serialize(leftover));\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n try {\n utimesSync(target, 0, 0);\n } catch {}\n}\n\nexport function spoolHasRecords(url: string, dir?: string): boolean {\n return fileSize(spoolPaths(url, dir).file) > 0;\n}\n\nexport function drainInProgress(url: string, dir?: string): boolean {\n const paths = spoolPaths(url, dir);\n try {\n return Date.now() - statSync(paths.drainLock).mtimeMs < DRAIN_LOCK_STALE_MS;\n } catch {\n return false;\n }\n}\n\nexport async function drainSpool(\n url: string,\n send: (record: SpoolRecord) => Promise<SendOutcome>,\n options: { policy?: SpoolPolicy; dir?: string; maxRecords?: number; deadlineMs?: number } = {},\n): Promise<DrainResult> {\n const policy = options.policy ?? spoolPolicy();\n const result: DrainResult = { claimed: 0, delivered: 0, duplicates: 0, rejected: 0, expired: 0, corrupt: 0, remaining: 0 };\n const paths = spoolPaths(url, options.dir);\n if (!existsSync(paths.dir)) return { ...result, skipped: \"empty\" };\n try {\n ensureDir(paths.dir);\n } catch {}\n if (!tryLock(paths.drainLock, DRAIN_LOCK_STALE_MS)) return { ...result, skipped: \"locked\" };\n try {\n const files = claimFiles(paths);\n if (files.length === 0) return { ...result, skipped: \"empty\" };\n const records: SpoolRecord[] = [];\n for (const file of files) {\n try {\n const parsed = parseLines(readFileSync(file, \"utf-8\"));\n records.push(...parsed.records);\n result.corrupt += parsed.corrupt;\n } catch {}\n }\n result.claimed = records.length;\n const seen = new Set<string>();\n const now = Date.now();\n const deadline = options.deadlineMs ? now + options.deadlineMs : Number.POSITIVE_INFINITY;\n const maxRecords = options.maxRecords ?? Number.POSITIVE_INFINITY;\n const leftover: SpoolRecord[] = [];\n let stopped = false;\n let processed = 0;\n for (const rec of records) {\n if (seen.has(rec.eventId)) {\n result.duplicates++;\n continue;\n }\n seen.add(rec.eventId);\n if (isExpired(rec, policy, now)) {\n result.expired++;\n continue;\n }\n if (stopped || processed >= maxRecords || Date.now() > deadline) {\n leftover.push(rec);\n continue;\n }\n processed++;\n let outcome: SendOutcome;\n try {\n outcome = await send(rec);\n } catch (err) {\n outcome = \"retry\";\n result.error = err instanceof Error ? err.message : String(err);\n }\n if (outcome === \"delivered\") result.delivered++;\n else if (outcome === \"duplicate\") result.duplicates++;\n else if (outcome === \"rejected\") result.rejected++;\n else {\n stopped = true;\n leftover.push({ ...rec, attempts: (rec.attempts ?? 0) + 1 });\n }\n }\n result.remaining = leftover.length;\n withLock(paths.lock, (locked) => (locked ? requeueLocked(paths, leftover) : requeueUnlocked(paths, leftover)), 2000);\n for (const file of files) {\n try {\n unlinkSync(file);\n } catch {}\n }\n writeStats(paths, (s) => {\n s.delivered += result.delivered;\n s.duplicates += result.duplicates;\n s.rejected += result.rejected;\n s.expired += result.expired;\n s.lastDrainAt = new Date().toISOString();\n s.lastDrainDelivered = result.delivered;\n s.lastDrainDuplicates = result.duplicates;\n s.lastDrainRejected = result.rejected;\n s.lastDrainRemaining = result.remaining;\n if (result.error) s.lastDrainError = result.error;\n else delete s.lastDrainError;\n });\n return result;\n } finally {\n releaseLock(paths.drainLock);\n }\n}\n\nexport function spoolSummary(url: string, options: { policy?: SpoolPolicy; dir?: string } = {}): SpoolSummary {\n const policy = options.policy ?? spoolPolicy();\n const paths = spoolPaths(url, options.dir);\n let records = 0;\n let bytes = 0;\n let oldestAt: string | null = null;\n const files: string[] = [];\n if (existsSync(paths.file)) files.push(paths.file);\n try {\n for (const entry of readdirSync(paths.dir)) {\n if (entry.startsWith(`${paths.name}.draining-`) && entry.endsWith(\".jsonl\")) files.push(join(paths.dir, entry));\n }\n } catch {}\n for (const file of files) {\n try {\n const text = readFileSync(file, \"utf-8\");\n bytes += Buffer.byteLength(text);\n for (const rec of parseLines(text).records) {\n records++;\n if (!oldestAt || rec.spooledAt < oldestAt) oldestAt = rec.spooledAt;\n }\n } catch {}\n }\n let retained = 0;\n let retainedBytes = 0;\n for (const seg of listSent(paths)) {\n try {\n const text = readFileSync(seg.file, \"utf-8\");\n retainedBytes += Buffer.byteLength(text);\n retained += parseLines(text).records.length;\n } catch {}\n }\n return {\n enabled: policy.enabled,\n path: paths.file,\n records,\n bytes,\n oldestAt,\n retained,\n retainedBytes,\n maxBytes: policy.maxBytes,\n maxAgeHours: Math.round(policy.maxAgeMs / 3600_000),\n stats: readSpoolStats(paths),\n };\n}\n","export const GRAPH_EXTRACTION_SYSTEM = `You are a knowledge graph extraction engine. Given a compressed observation from a coding session, extract entities and relationships.\n\nOutput format (XML):\n<entities>\n <entity type=\"file|function|concept|error|decision|pattern|library|person\" name=\"exact name\">\n <property key=\"key\">value</property>\n </entity>\n</entities>\n<relationships>\n <relationship type=\"uses|imports|modifies|causes|fixes|depends_on|related_to\" source=\"entity name\" target=\"entity name\" weight=\"0.1-1.0\"/>\n</relationships>\n\nRules:\n- Extract concrete entities only (real file paths, function names, library names)\n- Use the most specific type available\n- Weight relationships by how strong/direct the connection is\n- If no entities found, output empty tags`;\n\nexport function buildGraphExtractionPrompt(\n observations: Array<{\n title: string;\n narrative: string;\n concepts: string[];\n files: string[];\n type: string;\n }>,\n): string {\n const items = observations\n .map(\n (o, i) =>\n `[${i + 1}] Type: ${o.type}\\nTitle: ${o.title}\\nNarrative: ${o.narrative}\\nConcepts: ${(o.concepts ?? []).join(\", \")}\\nFiles: ${(o.files ?? []).join(\", \")}`,\n )\n .join(\"\\n\\n\");\n // Some local models default to a hidden reasoning pass that consumes\n // most of the token budget before any output. The suffix is their\n // documented soft switch to skip it; other models ignore the token.\n const noThink = process.env.AGENTMEMORY_LLM_NOTHINK === \"1\" ? \"\\n/no_think\" : \"\";\n return `Extract entities and relationships from these observations:\\n\\n${items}${noThink}`;\n}\n","import type { IIIClient } from \"iii-sdk\";\nimport type {\n GraphNode,\n GraphEdge,\n GraphQueryResult,\n GraphSnapshot,\n CompressedObservation,\n MemoryProvider,\n} from \"../types.js\";\nimport { KV, generateId } from \"../state/schema.js\";\nimport type { StateKV } from \"../state/kv.js\";\nimport { withKeyedLock } from \"../state/keyed-mutex.js\";\nimport {\n GRAPH_EXTRACTION_SYSTEM,\n buildGraphExtractionPrompt,\n} from \"../prompts/graph-extraction.js\";\nimport { isGraphExtractionEnabled } from \"../config.js\";\nimport { recordAudit, safeAudit } from \"./audit.js\";\nimport { logger } from \"../logger.js\";\nimport { scrubRecord } from \"./privacy.js\";\n\nconst DEFAULT_GRAPH_QUERY_LIMIT = 500;\nconst MAX_GRAPH_QUERY_LIMIT = 5000;\n\nconst SNAPSHOT_TOP_NODES = DEFAULT_GRAPH_QUERY_LIMIT;\nconst SNAPSHOT_KEY = \"current\";\n\n// `state::list` over a 75K-node scope can exceed the iii invocation\n// timeout. The query handler races the enumeration against this budget\n// and falls back to the snapshot (or a warning envelope) when the live\n// path is too slow. 6000ms leaves headroom under the default 8s engine\n// invocation deadline.\nconst LIVE_ENUMERATION_BUDGET_MS = 6000;\n\nfunction withTimeout<T>(p: Promise<T>, ms: number, label: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const t = setTimeout(\n () => reject(new Error(`${label}: exceeded ${ms}ms budget`)),\n ms,\n );\n p.then(\n (v) => {\n clearTimeout(t);\n resolve(v);\n },\n (err) => {\n clearTimeout(t);\n reject(err);\n },\n );\n });\n}\n\nfunction emptySnapshot(): GraphSnapshot {\n return {\n version: 1,\n topNodes: [],\n topEdges: [],\n topDegrees: {},\n stats: {\n totalNodes: 0,\n totalEdges: 0,\n nodesByType: {},\n edgesByType: {},\n },\n updatedAt: new Date(0).toISOString(),\n dirty: true,\n };\n}\n\nasync function readSnapshot(kv: StateKV): Promise<GraphSnapshot | null> {\n try {\n const snap = await kv.get<GraphSnapshot>(KV.graphSnapshot, SNAPSHOT_KEY);\n if (snap && typeof snap === \"object\" && snap.version === 1) {\n return snap;\n }\n return null;\n } catch (err) {\n logger.warn(\"Graph snapshot read failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n}\n\nasync function readSnapshotStrict(kv: StateKV): Promise<GraphSnapshot | null> {\n let raw: unknown;\n try {\n raw = await kv.get<unknown>(KV.graphSnapshot, SNAPSHOT_KEY);\n } catch (err) {\n logger.warn(\"Graph snapshot read failed, retrying once\", {\n error: err instanceof Error ? err.message : String(err),\n });\n raw = await kv.get<unknown>(KV.graphSnapshot, SNAPSHOT_KEY);\n }\n if (raw === null || raw === undefined) return null;\n if (typeof raw === \"object\" && (raw as { version?: unknown }).version === 1) {\n return raw as GraphSnapshot;\n }\n throw new Error(\n `Graph snapshot has unknown schema version: ${JSON.stringify(\n (raw as { version?: unknown }).version,\n )}`,\n );\n}\n\nfunction buildSnapshotFromArrays(\n nodes: GraphNode[],\n edges: GraphEdge[],\n): GraphSnapshot {\n const liveNodes = nodes.filter((n) => !n.stale);\n const liveEdges = edges.filter((e) => !e.stale);\n // Build the global degree map once so we can both rank by it AND\n // snapshot the per-top-node values into topDegrees for synchronous\n // re-sort after incremental edge writes.\n const degree = new Map<string, number>();\n for (const e of liveEdges) {\n degree.set(e.sourceNodeId, (degree.get(e.sourceNodeId) ?? 0) + 1);\n degree.set(e.targetNodeId, (degree.get(e.targetNodeId) ?? 0) + 1);\n }\n const ranked = [...liveNodes]\n .sort((a, b) => (degree.get(b.id) ?? 0) - (degree.get(a.id) ?? 0))\n .slice(0, SNAPSHOT_TOP_NODES);\n const rankedIds = new Set(ranked.map((n) => n.id));\n const topEdges = liveEdges.filter(\n (e) => rankedIds.has(e.sourceNodeId) && rankedIds.has(e.targetNodeId),\n );\n const topDegrees: Record<string, number> = {};\n for (const n of ranked) {\n topDegrees[n.id] = degree.get(n.id) ?? 0;\n }\n const nodesByType: Record<string, number> = {};\n for (const n of liveNodes) {\n nodesByType[n.type] = (nodesByType[n.type] || 0) + 1;\n }\n const edgesByType: Record<string, number> = {};\n for (const e of liveEdges) {\n edgesByType[e.type] = (edgesByType[e.type] || 0) + 1;\n }\n return {\n version: 1,\n topNodes: ranked,\n topEdges,\n topDegrees,\n stats: {\n totalNodes: liveNodes.length,\n totalEdges: liveEdges.length,\n nodesByType,\n edgesByType,\n },\n updatedAt: new Date().toISOString(),\n dirty: false,\n };\n}\n\nfunction paginateFromSnapshot(\n snap: GraphSnapshot,\n filterType: string | undefined,\n limit: number,\n offset: number,\n): GraphQueryResult {\n const filteredNodes = filterType\n ? snap.topNodes.filter((n) => n.type === filterType)\n : snap.topNodes;\n const totalRaw = filterType\n ? snap.stats.nodesByType[filterType] ?? 0\n : snap.stats.totalNodes;\n const total = Math.max(totalRaw, filteredNodes.length);\n const pageNodes = filteredNodes.slice(offset, offset + limit);\n const pageIds = new Set(pageNodes.map((n) => n.id));\n const pageEdges = snap.topEdges.filter(\n (e) => pageIds.has(e.sourceNodeId) && pageIds.has(e.targetNodeId),\n );\n const degrees: Record<string, number> = {};\n for (const n of pageNodes) {\n const d = snap.topDegrees?.[n.id];\n if (typeof d === \"number\") degrees[n.id] = d;\n }\n return {\n nodes: pageNodes,\n edges: pageEdges,\n depth: 0,\n totalNodes: total,\n totalEdges: snap.stats.totalEdges,\n truncated: total > pageNodes.length,\n limit,\n offset,\n fromSnapshot: true,\n degrees,\n };\n}\n\nconst REBUILD_SAFE_NODE_CEILING = 25000;\n\nfunction nameIndexKey(type: string, name: string): string {\n return `${type}|${name}`;\n}\n\nfunction edgeIndexKey(\n sourceNodeId: string,\n targetNodeId: string,\n type: string,\n): string {\n return `${sourceNodeId}|${targetNodeId}|${type}`;\n}\n\n// Mutates `snap` to apply a +1 (or -1) degree delta for nodeId,\n// maintaining the top-N ranking. Returns the new degree. Reads /\n// writes the per-node degree counter via targeted kv.get/set so we\n// never enumerate. Top-N membership flips when:\n// - node's new degree > current min in topNodes AND it's not in\n// topNodes (promote, evict tail if topNodes is full)\n// - node IS in topNodes and its position needs resorting (re-sort\n// topNodes in place)\nasync function applyDegreeDelta(\n kv: StateKV,\n snap: GraphSnapshot,\n nodeId: string,\n delta: number,\n): Promise<number> {\n const prev = (await kv.get<number>(KV.graphNodeDegree, nodeId)) ?? 0;\n const next = Math.max(0, prev + delta);\n await kv.set(KV.graphNodeDegree, nodeId, next);\n\n const inTop = snap.topNodes.findIndex((n) => n.id === nodeId);\n if (inTop !== -1) {\n // Cache the new degree in topDegrees so the comparator runs\n // synchronously over numbers, not async kv.get calls. Re-sort\n // descending by degree.\n snap.topDegrees[nodeId] = next;\n snap.topNodes.sort(\n (a, b) =>\n (snap.topDegrees[b.id] ?? 0) - (snap.topDegrees[a.id] ?? 0),\n );\n return next;\n }\n\n if (snap.topNodes.length < SNAPSHOT_TOP_NODES) {\n // Capacity available — fetch + promote.\n const node = await kv.get<GraphNode>(KV.graphNodes, nodeId);\n if (node && !node.stale) {\n snap.topNodes.push(node);\n snap.topDegrees[node.id] = next;\n snap.topNodes.sort(\n (a, b) =>\n (snap.topDegrees[b.id] ?? 0) - (snap.topDegrees[a.id] ?? 0),\n );\n }\n return next;\n }\n\n // topNodes is full; the cutoff is the tail's cached degree.\n const tailEntry = snap.topNodes[snap.topNodes.length - 1];\n if (!tailEntry) return next;\n const tailDegree = snap.topDegrees[tailEntry.id] ?? 0;\n if (next > tailDegree) {\n const node = await kv.get<GraphNode>(KV.graphNodes, nodeId);\n if (node && !node.stale) {\n const evicted = snap.topNodes.pop();\n if (evicted) delete snap.topDegrees[evicted.id];\n snap.topNodes.push(node);\n snap.topDegrees[node.id] = next;\n snap.topNodes.sort(\n (a, b) =>\n (snap.topDegrees[b.id] ?? 0) - (snap.topDegrees[a.id] ?? 0),\n );\n }\n }\n return next;\n}\n\nfunction snapshotPushEdgeIfBothInTop(\n snap: GraphSnapshot,\n edge: GraphEdge,\n): void {\n const topIds = new Set(snap.topNodes.map((n) => n.id));\n if (topIds.has(edge.sourceNodeId) && topIds.has(edge.targetNodeId)) {\n // Dedupe in case the same edge gets pushed twice.\n if (!snap.topEdges.find((e) => e.id === edge.id)) {\n snap.topEdges.push(edge);\n }\n }\n}\n\nexport const MAX_GRAPH_SOURCE_OBSERVATIONS = 32;\n\nexport function boundSources(existing: string[], incoming: string[]): string[] {\n const merged = new Set(existing);\n for (const id of incoming) {\n merged.delete(id);\n merged.add(id);\n }\n return [...merged].slice(-MAX_GRAPH_SOURCE_OBSERVATIONS);\n}\n\nexport function boundRecordSources<R extends object>(record: R): R {\n const sources = (record as { sourceObservationIds?: unknown } | null)?.sourceObservationIds;\n if (!Array.isArray(sources) || sources.length <= MAX_GRAPH_SOURCE_OBSERVATIONS) return record;\n return { ...record, sourceObservationIds: boundSources([], sources as string[]) };\n}\n\nfunction mergeNode(\n existing: GraphNode,\n incoming: GraphNode,\n capturedAt: string,\n): GraphNode {\n return {\n ...existing,\n sourceObservationIds: boundSources(\n existing.sourceObservationIds ?? [],\n incoming.sourceObservationIds ?? [],\n ),\n properties: { ...existing.properties, ...incoming.properties },\n updatedAt: capturedAt,\n };\n}\n\nfunction mergeEdge(existing: GraphEdge, incoming: GraphEdge): GraphEdge {\n return {\n ...existing,\n sourceObservationIds: boundSources(\n existing.sourceObservationIds ?? [],\n incoming.sourceObservationIds ?? [],\n ),\n };\n}\n\nfunction resolvePagination(\n rawLimit: number | undefined,\n rawOffset: number | undefined,\n): { limit: number; offset: number } {\n const requested = typeof rawLimit === \"number\" && Number.isFinite(rawLimit)\n ? Math.floor(rawLimit)\n : DEFAULT_GRAPH_QUERY_LIMIT;\n const limit = Math.max(1, Math.min(requested, MAX_GRAPH_QUERY_LIMIT));\n const offset = Math.max(\n 0,\n typeof rawOffset === \"number\" && Number.isFinite(rawOffset)\n ? Math.floor(rawOffset)\n : 0,\n );\n return { limit, offset };\n}\n\nfunction paginate(\n nodes: GraphNode[],\n allEdges: GraphEdge[],\n depth: number,\n limit: number,\n offset: number,\n): GraphQueryResult {\n const totalNodes = nodes.length;\n const pageNodes = nodes.slice(offset, offset + limit);\n const pageNodeIds = new Set(pageNodes.map((n) => n.id));\n // Edges restricted to the page so the response payload scales with\n // `limit`, not with the global edge count. An edge is included only\n // when BOTH endpoints land in the page — half-edges to nodes outside\n // the page would render as dangling links in the viewer.\n const pageEdges = allEdges.filter(\n (e) => pageNodeIds.has(e.sourceNodeId) && pageNodeIds.has(e.targetNodeId),\n );\n // Total edges (for the same node universe). Counted unbounded so the\n // viewer can show \"showing X of Y\" without re-querying.\n const universeIds = new Set(nodes.map((n) => n.id));\n const totalEdges = allEdges.reduce(\n (count, e) =>\n universeIds.has(e.sourceNodeId) && universeIds.has(e.targetNodeId)\n ? count + 1\n : count,\n 0,\n );\n return {\n nodes: pageNodes,\n edges: pageEdges,\n depth,\n totalNodes,\n totalEdges,\n truncated: totalNodes > pageNodes.length,\n limit,\n offset,\n };\n}\n\nfunction parseAttrs(raw: string): Record<string, string> {\n const attrs: Record<string, string> = {};\n const attrRegex = /([A-Za-z_][\\w:-]*)=\"([^\"]*)\"/g;\n let m;\n while ((m = attrRegex.exec(raw)) !== null) {\n attrs[m[1]] = m[2];\n }\n return attrs;\n}\n\nfunction parseGraphXml(\n xml: string,\n observationIds: string[],\n): {\n nodes: GraphNode[];\n edges: GraphEdge[];\n} {\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n const now = new Date().toISOString();\n\n const entitySelfClose = /<entity\\b([^>]*?)\\/>/g;\n const entityWithBody = /<entity\\b([^>]*[^/])>([\\s\\S]*?)<\\/entity>/g;\n\n const addEntity = (rawAttrs: string, propsBlock = \"\"): void => {\n const attrs = parseAttrs(rawAttrs);\n const type = attrs[\"type\"] as GraphNode[\"type\"] | undefined;\n const name = attrs[\"name\"];\n if (!type || !name) return;\n const properties: Record<string, string> = {};\n const propRegex = /<property\\s+key=\"([^\"]+)\">([^<]*)<\\/property>/g;\n let propMatch;\n while ((propMatch = propRegex.exec(propsBlock)) !== null) {\n properties[propMatch[1]] = propMatch[2];\n }\n nodes.push({\n id: generateId(\"gn\"),\n type,\n name,\n properties,\n sourceObservationIds: observationIds,\n createdAt: now,\n });\n };\n\n let match;\n while ((match = entitySelfClose.exec(xml)) !== null) {\n addEntity(match[1]);\n }\n while ((match = entityWithBody.exec(xml)) !== null) {\n addEntity(match[1], match[2]);\n }\n\n const relRegex = /<relationship\\b([^>]*?)\\/>/g;\n while ((match = relRegex.exec(xml)) !== null) {\n const attrs = parseAttrs(match[1]);\n const type = attrs[\"type\"] as GraphEdge[\"type\"] | undefined;\n const sourceName = attrs[\"source\"];\n const targetName = attrs[\"target\"];\n if (!type || !sourceName || !targetName) continue;\n const parsedWeight = parseFloat(attrs[\"weight\"] ?? \"\");\n const weight = Number.isFinite(parsedWeight) ? parsedWeight : 0.5;\n\n const sourceNode = nodes.find((n) => n.name === sourceName);\n const targetNode = nodes.find((n) => n.name === targetName);\n if (!sourceNode || !targetNode) continue;\n edges.push({\n id: generateId(\"ge\"),\n type,\n sourceNodeId: sourceNode.id,\n targetNodeId: targetNode.id,\n weight: Math.max(0, Math.min(1, weight)),\n sourceObservationIds: observationIds,\n createdAt: now,\n });\n }\n\n return { nodes, edges };\n}\n\nconst HEURISTIC_EDGE_WEIGHT = 0.4;\nconst MAX_HEURISTIC_EDGES_PER_OBS = 12;\n\nexport function extractGraphHeuristics(\n observations: CompressedObservation[],\n): { nodes: GraphNode[]; edges: GraphEdge[] } {\n const now = new Date().toISOString();\n const nodes: GraphNode[] = [];\n const nodeByKey = new Map<string, GraphNode>();\n const edges: GraphEdge[] = [];\n const edgeByPair = new Map<string, GraphEdge>();\n\n const nodeFor = (\n type: GraphNode[\"type\"],\n name: string,\n obsId: string,\n ): GraphNode | null => {\n const trimmed = name.trim();\n if (!trimmed) return null;\n const key = `${type}\u0000${trimmed.toLowerCase()}`;\n let node = nodeByKey.get(key);\n if (!node) {\n node = {\n id: generateId(\"gn\"),\n type,\n name: trimmed,\n properties: {},\n sourceObservationIds: [obsId],\n createdAt: now,\n };\n nodeByKey.set(key, node);\n nodes.push(node);\n } else if (!node.sourceObservationIds.includes(obsId)) {\n node.sourceObservationIds.push(obsId);\n }\n return node;\n };\n\n for (const obs of observations) {\n let budget = MAX_HEURISTIC_EDGES_PER_OBS;\n const link = (a: GraphNode | null, b: GraphNode | null): void => {\n if (!a || !b || a.id === b.id) return;\n const pair = a.id < b.id ? `${a.id}|${b.id}` : `${b.id}|${a.id}`;\n const existing = edgeByPair.get(pair);\n if (existing) {\n if (!existing.sourceObservationIds.includes(obs.id)) {\n existing.sourceObservationIds.push(obs.id);\n }\n return;\n }\n if (budget <= 0) return;\n budget -= 1;\n const edge: GraphEdge = {\n id: generateId(\"ge\"),\n type: \"related_to\",\n sourceNodeId: a.id,\n targetNodeId: b.id,\n weight: HEURISTIC_EDGE_WEIGHT,\n sourceObservationIds: [obs.id],\n createdAt: now,\n };\n edgeByPair.set(pair, edge);\n edges.push(edge);\n };\n\n const fileNodes = (obs.files ?? []).map((f) =>\n nodeFor(\"file\", f, obs.id),\n );\n const conceptNodes = (obs.concepts ?? []).map((c) =>\n nodeFor(\"concept\", c, obs.id),\n );\n\n for (const concept of conceptNodes) {\n for (const file of fileNodes) link(concept, file);\n }\n for (let i = 0; i + 1 < conceptNodes.length; i++) {\n link(conceptNodes[i], conceptNodes[i + 1]);\n }\n for (let i = 0; i + 1 < fileNodes.length; i++) {\n link(fileNodes[i], fileNodes[i + 1]);\n }\n }\n\n return { nodes, edges };\n}\n\nexport async function persistGraphDelta(\n kv: StateKV,\n rawNodes: GraphNode[],\n rawEdges: GraphEdge[],\n): Promise<{ newNodeCount: number; newEdgeCount: number }> {\n const nodes = rawNodes.map((node) => scrubRecord(node));\n const edges = rawEdges.map((edge) => scrubRecord(edge));\n return withKeyedLock(\"graph:persist\", async () => {\n const snap = (await readSnapshotStrict(kv)) ?? emptySnapshot();\n const capturedAt = new Date().toISOString();\n let newNodeCount = 0;\n let newEdgeCount = 0;\n // Merge-only batches mutate cached topNodes/topEdges entries without\n // changing the counts; track that separately so the snapshot still persists.\n let snapMutated = false;\n const newEdgesForTopCheck: GraphEdge[] = [];\n // When a freshly-minted node merges into an existing row via the name\n // index, edges in the same batch still reference the fresh id. Remap edge\n // endpoints to the persisted ids so edges never dangle and re-runs hit the\n // same edge-index key instead of duplicating.\n const idRemap = new Map<string, string>();\n\n for (const node of nodes) {\n const indexKey = nameIndexKey(node.type, node.name);\n const existingId = await kv.get<string>(KV.graphNameIndex, indexKey);\n\n let existing: GraphNode | null = null;\n if (existingId) {\n existing = await kv.get<GraphNode>(KV.graphNodes, existingId);\n if (\n existing &&\n snap.resetAt &&\n typeof existing.createdAt === \"string\" &&\n existing.createdAt < snap.resetAt\n ) {\n existing = null;\n }\n }\n\n if (existing) {\n idRemap.set(node.id, existing.id);\n const merged = mergeNode(existing, node, capturedAt);\n await kv.set(KV.graphNodes, existing.id, merged);\n // Update topNodes entry if present so a stale clone isn't\n // returned from the snapshot fast path.\n const topIdx = snap.topNodes.findIndex((n) => n.id === existing!.id);\n if (topIdx !== -1) {\n snap.topNodes[topIdx] = merged;\n snapMutated = true;\n }\n } else {\n node.sourceObservationIds = boundSources([], node.sourceObservationIds ?? []);\n await kv.set(KV.graphNodes, node.id, node);\n await kv.set(KV.graphNameIndex, indexKey, node.id);\n await kv.set(KV.graphNodeDegree, node.id, 0);\n snap.stats.totalNodes += 1;\n snap.stats.nodesByType[node.type] =\n (snap.stats.nodesByType[node.type] ?? 0) + 1;\n newNodeCount += 1;\n if (snap.topNodes.length < SNAPSHOT_TOP_NODES) {\n // Degree 0 still beats an empty slot — sit at the tail\n // until edges arrive and promote.\n snap.topNodes.push(node);\n snap.topDegrees[node.id] = 0;\n }\n }\n }\n\n for (const rawEdge of edges) {\n const edge: GraphEdge = {\n ...rawEdge,\n sourceNodeId: idRemap.get(rawEdge.sourceNodeId) ?? rawEdge.sourceNodeId,\n targetNodeId: idRemap.get(rawEdge.targetNodeId) ?? rawEdge.targetNodeId,\n };\n const eKey = edgeIndexKey(edge.sourceNodeId, edge.targetNodeId, edge.type);\n const existingId = await kv.get<string>(KV.graphEdgeKey, eKey);\n\n let existing: GraphEdge | null = null;\n if (existingId) {\n existing = await kv.get<GraphEdge>(KV.graphEdges, existingId);\n if (\n existing &&\n snap.resetAt &&\n typeof existing.createdAt === \"string\" &&\n existing.createdAt < snap.resetAt\n ) {\n existing = null;\n }\n }\n\n if (existing) {\n const merged = mergeEdge(existing, edge);\n await kv.set(KV.graphEdges, existing.id, merged);\n // Replace cached topEdges entry too if present.\n const topIdx = snap.topEdges.findIndex((e) => e.id === existing!.id);\n if (topIdx !== -1) {\n snap.topEdges[topIdx] = merged;\n snapMutated = true;\n }\n } else {\n edge.sourceObservationIds = boundSources([], edge.sourceObservationIds ?? []);\n await kv.set(KV.graphEdges, edge.id, edge);\n await kv.set(KV.graphEdgeKey, eKey, edge.id);\n snap.stats.totalEdges += 1;\n snap.stats.edgesByType[edge.type] =\n (snap.stats.edgesByType[edge.type] ?? 0) + 1;\n newEdgeCount += 1;\n await applyDegreeDelta(kv, snap, edge.sourceNodeId, +1);\n await applyDegreeDelta(kv, snap, edge.targetNodeId, +1);\n newEdgesForTopCheck.push(edge);\n }\n }\n\n // Push newly-added edges into snapshot.topEdges if both\n // endpoints are in the top-N (post-degree-delta). Done after\n // all degree updates so the topIds set is stable.\n for (const edge of newEdgesForTopCheck) {\n snapshotPushEdgeIfBothInTop(snap, edge);\n }\n\n if (newNodeCount > 0 || newEdgeCount > 0 || snapMutated) {\n snap.updatedAt = capturedAt;\n snap.dirty = false;\n await kv.set(KV.graphSnapshot, SNAPSHOT_KEY, snap);\n }\n\n return { newNodeCount, newEdgeCount };\n });\n}\n\nexport interface GraphCompactResult {\n nodesScanned: number;\n nodesTrimmed: number;\n edgesScanned: number;\n edgesTrimmed: number;\n historyScanned: number;\n historyTrimmed: number;\n idsRemoved: number;\n snapshotTrimmed: boolean;\n total?: number;\n nextOffset: number | null;\n}\n\nexport type GraphCompactScope = \"nodes\" | \"edges\" | \"history\" | \"snapshot\";\n\nexport interface GraphCompactOptions {\n scope?: GraphCompactScope;\n offset?: number;\n limit?: number;\n dryRun?: boolean;\n}\n\nexport const COMPACT_SCOPES: readonly GraphCompactScope[] = [\"nodes\", \"edges\", \"history\", \"snapshot\"];\n\nexport async function compactGraphProvenance(\n kv: StateKV,\n opts: GraphCompactOptions = {},\n): Promise<GraphCompactResult> {\n const { scope } = opts;\n if (scope !== undefined && !COMPACT_SCOPES.includes(scope)) {\n throw new Error(`unknown compact scope: ${String(scope)}`);\n }\n const offset = opts.offset ?? 0;\n const dryRun = opts.dryRun === true;\n const limit = opts.limit ?? Number.POSITIVE_INFINITY;\n if (!Number.isInteger(offset) || offset < 0) {\n throw new Error(`compact offset must be a non-negative integer: ${String(opts.offset)}`);\n }\n if (!(limit === Number.POSITIVE_INFINITY || (Number.isInteger(limit) && limit > 0))) {\n throw new Error(`compact limit must be a positive integer: ${String(opts.limit)}`);\n }\n\n const result: GraphCompactResult = {\n nodesScanned: 0,\n nodesTrimmed: 0,\n edgesScanned: 0,\n edgesTrimmed: 0,\n historyScanned: 0,\n historyTrimmed: 0,\n idsRemoved: 0,\n snapshotTrimmed: false,\n nextOffset: null,\n };\n\n const trimScope = async <R extends { sourceObservationIds: string[] }>(\n listIds: () => Promise<unknown[]>,\n recordScope: string,\n ): Promise<{ scanned: number; trimmed: number }> => {\n const allIds = [...new Set(await listIds())]\n .filter((id): id is string => typeof id === \"string\")\n .sort();\n const end = Math.min(allIds.length, offset + limit);\n result.total = allIds.length;\n result.nextOffset = end < allIds.length ? end : null;\n let scanned = 0;\n let trimmed = 0;\n for (const id of allIds.slice(offset, end)) {\n await withKeyedLock(\"graph:persist\", async () => {\n const record = await kv.get<R>(recordScope, id);\n if (!record) return;\n scanned += 1;\n const sources = record.sourceObservationIds ?? [];\n if (sources.length <= MAX_GRAPH_SOURCE_OBSERVATIONS) return;\n const bounded = boundSources([], sources);\n result.idsRemoved += sources.length - bounded.length;\n if (!dryRun) await kv.set(recordScope, id, { ...record, sourceObservationIds: bounded });\n trimmed += 1;\n });\n }\n return { scanned, trimmed };\n };\n\n const trimSnapshot = () =>\n withKeyedLock(\"graph:persist\", async () => {\n const snap = await readSnapshot(kv);\n if (!snap) return;\n const trimList = <R extends { sourceObservationIds: string[] }>(list: R[]) =>\n list.map((r) => {\n const sources = r.sourceObservationIds ?? [];\n if (sources.length <= MAX_GRAPH_SOURCE_OBSERVATIONS) return r;\n result.snapshotTrimmed = true;\n return { ...r, sourceObservationIds: boundSources([], sources) };\n });\n const topNodes = trimList(snap.topNodes);\n const topEdges = trimList(snap.topEdges);\n if (result.snapshotTrimmed && !dryRun) {\n await kv.set(KV.graphSnapshot, SNAPSHOT_KEY, { ...snap, topNodes, topEdges });\n }\n });\n\n if (scope === undefined || scope === \"nodes\") {\n const n = await trimScope<GraphNode>(() => kv.list<string>(KV.graphNameIndex), KV.graphNodes);\n result.nodesScanned = n.scanned;\n result.nodesTrimmed = n.trimmed;\n }\n if (scope === undefined || scope === \"edges\") {\n const e = await trimScope<GraphEdge>(() => kv.list<string>(KV.graphEdgeKey), KV.graphEdges);\n result.edgesScanned = e.scanned;\n result.edgesTrimmed = e.trimmed;\n }\n if (scope === undefined || scope === \"history\") {\n const h = await trimScope<GraphEdge>(\n async () => (await kv.list<GraphEdge>(KV.graphEdgeHistory)).map((r) => r?.id),\n KV.graphEdgeHistory,\n );\n result.historyScanned = h.scanned;\n result.historyTrimmed = h.trimmed;\n }\n if (scope === undefined || scope === \"snapshot\") {\n await trimSnapshot();\n }\n if (scope === undefined) {\n delete result.total;\n result.nextOffset = null;\n }\n return result;\n}\n\nexport function registerGraphFunction(\n sdk: IIIClient,\n kv: StateKV,\n provider: MemoryProvider,\n): void {\n sdk.registerFunction(\"mem::graph-extract\",\n async (data: { observations: CompressedObservation[] }) => {\n if (!data.observations || data.observations.length === 0) {\n return { success: false, error: \"No observations provided\" };\n }\n\n const obsIds = data.observations.map((o) => o.id);\n\n let nodes: GraphNode[] = [];\n let edges: GraphEdge[] = [];\n try {\n const heuristic = extractGraphHeuristics(data.observations);\n nodes = heuristic.nodes;\n edges = heuristic.edges;\n } catch (err) {\n logger.warn(\"heuristic graph extraction failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n const llmEnabled =\n isGraphExtractionEnabled() && !provider.name.includes(\"noop\");\n let llmError: string | undefined;\n if (llmEnabled) {\n const prompt = buildGraphExtractionPrompt(\n data.observations.map((o) => ({\n title: o.title,\n narrative: o.narrative,\n concepts: o.concepts,\n files: o.files,\n type: o.type,\n })),\n );\n try {\n const response = await provider.compress(\n GRAPH_EXTRACTION_SYSTEM,\n prompt,\n );\n const parsed = parseGraphXml(response, obsIds);\n nodes = nodes.concat(parsed.nodes);\n edges = edges.concat(parsed.edges);\n } catch (err) {\n llmError = err instanceof Error ? err.message : String(err);\n logger.error(\"LLM graph extraction failed\", { error: llmError });\n }\n }\n\n if (nodes.length === 0 && edges.length === 0) {\n return llmError\n ? { success: false, error: llmError }\n : { success: true, nodesAdded: 0, edgesAdded: 0 };\n }\n\n try {\n const { newNodeCount, newEdgeCount } = await persistGraphDelta(\n kv,\n nodes,\n edges,\n );\n\n await recordAudit(kv, \"observe\", \"mem::graph-extract\", obsIds, {\n nodesExtracted: nodes.length,\n edgesExtracted: edges.length,\n });\n\n logger.info(\"Graph extraction complete\", {\n nodes: nodes.length,\n edges: edges.length,\n newNodes: newNodeCount,\n newEdges: newEdgeCount,\n llm: llmEnabled && !llmError,\n });\n return {\n success: true,\n nodesAdded: nodes.length,\n edgesAdded: edges.length,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\"Graph extraction failed\", { error: msg });\n return { success: false, error: msg };\n }\n },\n );\n\n sdk.registerFunction(\"mem::graph-query\",\n async (data: {\n startNodeId?: string;\n nodeType?: string;\n maxDepth?: number;\n query?: string;\n limit?: number;\n offset?: number;\n }): Promise<GraphQueryResult> => {\n const maxDepth = Math.min(data.maxDepth || 3, 5);\n const { limit, offset } = resolvePagination(data.limit, data.offset);\n\n const noWalk = !data.query && !data.startNodeId;\n if (noWalk) {\n const snap = await readSnapshot(kv);\n if (snap && snap.stats.totalNodes > 0) {\n return paginateFromSnapshot(snap, data.nodeType, limit, offset);\n }\n return {\n nodes: [],\n edges: [],\n depth: 0,\n totalNodes: 0,\n totalEdges: 0,\n truncated: false,\n limit,\n offset,\n warning:\n \"No graph snapshot available. Either no graph has been \" +\n \"extracted yet, or you are on a legacy corpus from an older \" +\n \"agentmemory build. Run POST /agentmemory/graph/snapshot-rebuild \" +\n \"(safe up to ~25K nodes) or POST /agentmemory/graph/reset to \" +\n \"wipe and let future extracts repopulate.\",\n };\n }\n\n // Query / startNodeId paths still need broader access. Race the\n // live enumeration against a wall-clock budget so a long\n // kv.list doesn't block the worker indefinitely. On timeout the\n // caller gets a snapshot-backed approximation instead of a 500.\n let allNodes: GraphNode[];\n let allEdges: GraphEdge[];\n try {\n const [rawNodes, rawEdges] = await withTimeout(\n Promise.all([\n kv.list<GraphNode>(KV.graphNodes),\n kv.list<GraphEdge>(KV.graphEdges),\n ]),\n LIVE_ENUMERATION_BUDGET_MS,\n \"graph-query enumeration\",\n );\n allNodes = rawNodes.filter((n) => !n.stale);\n allEdges = rawEdges.filter((e) => !e.stale);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.warn(\"Graph query enumeration timed out, using snapshot\", {\n error: msg,\n });\n const snap = await readSnapshot(kv);\n if (snap) {\n return {\n ...paginateFromSnapshot(snap, data.nodeType, limit, offset),\n warning:\n \"Live graph enumeration exceeded budget. Query / \" +\n \"startNodeId paths degrade on >25K-node corpora until a \" +\n \"per-node edge index lands. Result reflects top-degree \" +\n \"snapshot, not the requested walk.\",\n };\n }\n return {\n nodes: [],\n edges: [],\n depth: 0,\n totalNodes: 0,\n totalEdges: 0,\n truncated: false,\n limit,\n offset,\n warning:\n \"Graph enumeration exceeded budget and no snapshot is available.\",\n };\n }\n\n if (data.query) {\n const lower = data.query.toLowerCase();\n const matchingNodes = allNodes.filter(\n (n) =>\n n.name.toLowerCase().includes(lower) ||\n Object.values(n.properties).some(\n (v) => typeof v === \"string\" && v.toLowerCase().includes(lower),\n ),\n );\n return paginate(matchingNodes, allEdges, 0, limit, offset);\n }\n\n if (data.startNodeId) {\n const visited = new Set<string>();\n const visitedEdges = new Set<string>();\n const resultNodes: GraphNode[] = [];\n const resultEdges: GraphEdge[] = [];\n const queue: Array<{ nodeId: string; depth: number }> = [\n { nodeId: data.startNodeId, depth: 0 },\n ];\n\n while (queue.length > 0) {\n const { nodeId, depth } = queue.shift()!;\n if (visited.has(nodeId) || depth > maxDepth) continue;\n visited.add(nodeId);\n\n const node = allNodes.find((n) => n.id === nodeId);\n if (node) {\n if (!data.nodeType || node.type === data.nodeType) {\n resultNodes.push(node);\n }\n }\n\n const neighborEdges = allEdges.filter(\n (e) => e.sourceNodeId === nodeId || e.targetNodeId === nodeId,\n );\n for (const edge of neighborEdges) {\n if (!visitedEdges.has(edge.id)) {\n visitedEdges.add(edge.id);\n resultEdges.push(edge);\n }\n const nextId =\n edge.sourceNodeId === nodeId\n ? edge.targetNodeId\n : edge.sourceNodeId;\n if (!visited.has(nextId)) {\n queue.push({ nodeId: nextId, depth: depth + 1 });\n }\n }\n }\n\n return paginate(resultNodes, resultEdges, maxDepth, limit, offset);\n }\n\n // Unreachable — noWalk branch handles the rest.\n return paginate([], [], 0, limit, offset);\n },\n );\n\n sdk.registerFunction(\"mem::graph-stats\", async () => {\n const snap = await readSnapshot(kv);\n if (snap) {\n return {\n ...snap.stats,\n fromSnapshot: true,\n updatedAt: snap.updatedAt,\n ...(snap.dirty\n ? {\n warning:\n \"Snapshot is marked dirty (write was in-flight when read). \" +\n \"Counts are eventually consistent.\",\n }\n : {}),\n };\n }\n return {\n totalNodes: 0,\n totalEdges: 0,\n nodesByType: {},\n edgesByType: {},\n fromSnapshot: false,\n warning:\n \"No graph snapshot available. Run POST /agentmemory/graph/snapshot-rebuild \" +\n \"(safe up to ~25K nodes) or POST /agentmemory/graph/reset to wipe \" +\n \"and let future extracts repopulate.\",\n };\n });\n\n sdk.registerFunction(\n \"mem::graph-snapshot-rebuild\",\n async (data?: { force?: boolean }) => {\n const started = Date.now();\n const forceRebuild = data?.force === true;\n try {\n const existing = await readSnapshot(kv);\n if (!existing && !forceRebuild) {\n logger.warn(\"Graph snapshot rebuild refused: no prior snapshot\", {\n hint: \"legacy corpus or empty store\",\n });\n return {\n success: false,\n legacyCorpus: true,\n error:\n \"No prior snapshot found. Rebuild would call kv.list on \" +\n \"KV.graphNodes/Edges, which heartbeat-crashes the worker \" +\n \"on corpora past the iii state response budget (~25K nodes). \" +\n \"Either (a) call POST /agentmemory/graph/reset to drop into \" +\n \"incremental-only mode and rebuild from new extracts, or \" +\n \"(b) re-send with `force: true` if you're certain the \" +\n \"corpus is small.\",\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.warn(\"Graph snapshot pre-flight read failed\", { error: msg });\n // Fall through; the user passed force=true or the snapshot\n // read itself failed (separate problem).\n }\n\n try {\n const outcome = await withKeyedLock(\"graph:persist\", async () => {\n const [nodes, edges] = await withTimeout(\n Promise.all([\n kv.list<GraphNode>(KV.graphNodes),\n kv.list<GraphEdge>(KV.graphEdges),\n ]),\n LIVE_ENUMERATION_BUDGET_MS,\n \"graph-snapshot-rebuild enumeration\",\n );\n\n if (nodes.length > REBUILD_SAFE_NODE_CEILING) {\n return { tooLargeNodeCount: nodes.length };\n }\n\n const liveNodes = nodes.filter((n) => !n.stale);\n const liveEdges = edges.filter((e) => !e.stale);\n const degree = new Map<string, number>();\n for (const e of liveEdges) {\n degree.set(e.sourceNodeId, (degree.get(e.sourceNodeId) ?? 0) + 1);\n degree.set(e.targetNodeId, (degree.get(e.targetNodeId) ?? 0) + 1);\n }\n const BATCH_SIZE = 100;\n for (let i = 0; i < liveNodes.length; i += BATCH_SIZE) {\n const batch = liveNodes.slice(i, i + BATCH_SIZE);\n await Promise.all(\n batch.flatMap((n) => [\n kv.set(KV.graphNameIndex, nameIndexKey(n.type, n.name), n.id),\n kv.set(KV.graphNodeDegree, n.id, degree.get(n.id) ?? 0),\n ]),\n );\n }\n for (let i = 0; i < liveEdges.length; i += BATCH_SIZE) {\n const batch = liveEdges.slice(i, i + BATCH_SIZE);\n await Promise.all(\n batch.map((e) =>\n kv.set(\n KV.graphEdgeKey,\n edgeIndexKey(e.sourceNodeId, e.targetNodeId, e.type),\n e.id,\n ),\n ),\n );\n }\n\n const rebuilt = buildSnapshotFromArrays(nodes, edges);\n await kv.set(KV.graphSnapshot, SNAPSHOT_KEY, rebuilt);\n return { snap: rebuilt };\n });\n\n if (\"tooLargeNodeCount\" in outcome) {\n const totalNodes = outcome.tooLargeNodeCount;\n logger.warn(\"Graph snapshot rebuild aborted: corpus too large\", {\n totalNodes,\n ceiling: REBUILD_SAFE_NODE_CEILING,\n });\n return {\n success: false,\n tooLarge: true,\n totalNodes,\n ceiling: REBUILD_SAFE_NODE_CEILING,\n error:\n `Corpus has ${totalNodes} graph nodes; safe-rebuild ceiling ` +\n `is ${REBUILD_SAFE_NODE_CEILING}. Run POST /agentmemory/graph/reset ` +\n `to wipe and let future extracts rebuild incrementally.`,\n };\n }\n\n const { snap } = outcome;\n const tookMs = Date.now() - started;\n logger.info(\"Graph snapshot rebuilt\", {\n totalNodes: snap.stats.totalNodes,\n totalEdges: snap.stats.totalEdges,\n topNodes: snap.topNodes.length,\n topEdges: snap.topEdges.length,\n tookMs,\n });\n return {\n success: true,\n ...snap.stats,\n topNodes: snap.topNodes.length,\n topEdges: snap.topEdges.length,\n updatedAt: snap.updatedAt,\n tookMs,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\"Graph snapshot rebuild failed\", { error: msg });\n return { success: false, error: msg };\n }\n });\n\n sdk.registerFunction(\"mem::graph-compact\", async (data?: GraphCompactOptions) => {\n const started = Date.now();\n try {\n const result = await compactGraphProvenance(kv, data ?? {});\n const tookMs = Date.now() - started;\n logger.info(\"Graph provenance compacted\", { ...result, tookMs });\n if (result.idsRemoved > 0) {\n await safeAudit(kv, \"graph_compact\", \"mem::graph-compact\", [], {\n scope: data?.scope ?? \"all\",\n offset: data?.offset,\n limit: data?.limit,\n nodesTrimmed: result.nodesTrimmed,\n edgesTrimmed: result.edgesTrimmed,\n historyTrimmed: result.historyTrimmed,\n idsRemoved: result.idsRemoved,\n snapshotTrimmed: result.snapshotTrimmed,\n });\n }\n return { success: true, ...result, tookMs };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\"Graph provenance compaction failed\", { error: msg });\n return { success: false, error: msg };\n }\n });\n\n sdk.registerFunction(\"mem::graph-reset\", async () => {\n const started = Date.now();\n // Stamp resetAt=now on the empty snapshot. Future\n // mem::graph-extract calls compare each name-index lookup's\n // existing node `createdAt` against this timestamp; anything\n // older counts as an orphan and is dropped from the merge path,\n // forcing extract to write a fresh row instead of reconnecting\n // to a pre-reset entry.\n const resetSnapshot: GraphSnapshot = {\n ...emptySnapshot(),\n resetAt: new Date().toISOString(),\n };\n await withKeyedLock(\"graph:persist\", () =>\n kv.set(KV.graphSnapshot, SNAPSHOT_KEY, resetSnapshot),\n );\n const counts: Record<string, number> = {\n [KV.graphSnapshot]: 1,\n };\n const tookMs = Date.now() - started;\n logger.info(\"Graph state reset\", { counts, tookMs });\n return { success: true, cleared: counts, tookMs };\n });\n}\n","import type { StateKV } from \"../state/kv.js\";\nimport { KV } from \"../state/schema.js\";\nimport {\n MAX_GRAPH_SOURCE_OBSERVATIONS,\n compactGraphProvenance,\n type GraphCompactResult,\n type GraphCompactScope,\n} from \"./graph.js\";\nimport { safeAudit } from \"./audit.js\";\n\nexport const GRAPH_COMPACT_BOOT_VERSION = 1;\nexport const GRAPH_COMPACT_BOOT_KEY = `graph-compact-on-boot:v${GRAPH_COMPACT_BOOT_VERSION}`;\nexport const GRAPH_COMPACT_BOOT_FUNCTION_ID = \"mem::graph-compact-on-boot\";\nexport const GRAPH_COMPACT_BOOT_DELAY_MS = 3000;\n\nconst SLICED_SCOPES = [\"nodes\", \"edges\", \"history\"] as const;\ntype SlicedScope = (typeof SLICED_SCOPES)[number];\ntype BootPhase = SlicedScope | \"snapshot\";\n\nexport interface GraphCompactBootProgress {\n version: number;\n cap: number;\n status: \"running\" | \"done\" | \"failed\";\n phase: BootPhase;\n offset: number;\n phaseTotal: number | null;\n scanned: number;\n trimmed: number;\n idsRemoved: number;\n pending?: GraphCompactBootSlicePlan;\n startedAt: string;\n updatedAt: string;\n completedAt?: string;\n error?: string;\n}\n\nexport interface GraphCompactBootSlicePlan {\n phase: BootPhase;\n offset: number;\n scanned: number;\n trimmed: number;\n idsRemoved: number;\n nextOffset: number | null;\n total: number | null;\n}\n\nexport type GraphCompactBootState = \"off\" | \"pending\" | \"running\" | \"done\" | \"failed\";\n\nexport interface GraphCompactBootStatus {\n state: GraphCompactBootState;\n phase?: BootPhase;\n processed?: number;\n total?: number | null;\n scanned?: number;\n trimmed?: number;\n idsRemoved?: number;\n startedAt?: string;\n completedAt?: string;\n error?: string;\n}\n\nexport interface GraphCompactBootOptions {\n sliceSize?: number;\n pauseMs?: number;\n maxAttempts?: number;\n retryDelayMs?: number;\n log?: (msg: string) => void;\n warn?: (msg: string) => void;\n sleep?: (ms: number) => Promise<void>;\n now?: () => Date;\n}\n\nconst DEFAULT_SLICE_SIZE = 100;\nconst DEFAULT_PAUSE_MS = 200;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_RETRY_DELAY_MS = 2000;\n\nlet current: GraphCompactBootStatus = { state: \"pending\" };\nlet running: Promise<GraphCompactBootStatus> | null = null;\n\nexport function getGraphCompactBootStatus(): GraphCompactBootStatus {\n return { ...current };\n}\n\nexport function setGraphCompactBootDisabled(): void {\n current = { state: \"off\" };\n}\n\nexport function resetGraphCompactBootStatus(): void {\n current = { state: \"pending\" };\n running = null;\n}\n\nfunction statusFrom(p: GraphCompactBootProgress): GraphCompactBootStatus {\n return {\n state: p.status,\n phase: p.phase,\n processed: p.offset,\n total: p.phaseTotal,\n scanned: p.scanned,\n trimmed: p.trimmed,\n idsRemoved: p.idsRemoved,\n startedAt: p.startedAt,\n completedAt: p.completedAt,\n error: p.error,\n };\n}\n\nfunction isResumable(p: GraphCompactBootProgress | null): p is GraphCompactBootProgress {\n return (\n !!p &&\n p.version === GRAPH_COMPACT_BOOT_VERSION &&\n p.cap === MAX_GRAPH_SOURCE_OBSERVATIONS &&\n (p.phase === \"snapshot\" || (SLICED_SCOPES as readonly string[]).includes(p.phase)) &&\n Number.isInteger(p.offset) &&\n p.offset >= 0\n );\n}\n\nfunction storedPlan(p: GraphCompactBootProgress, phase: BootPhase): GraphCompactBootSlicePlan | null {\n const plan = p.pending;\n if (!plan || plan.phase !== phase || plan.offset !== p.offset) return null;\n const counts = [plan.scanned, plan.trimmed, plan.idsRemoved];\n return counts.every((n) => Number.isInteger(n) && n >= 0) ? plan : null;\n}\n\nfunction scannedOf(scope: SlicedScope, r: GraphCompactResult): [number, number] {\n if (scope === \"nodes\") return [r.nodesScanned, r.nodesTrimmed];\n if (scope === \"edges\") return [r.edgesScanned, r.edgesTrimmed];\n return [r.historyScanned, r.historyTrimmed];\n}\n\nexport function describeGraphCompactBoot(s: GraphCompactBootStatus): string {\n if (s.state === \"off\") return \"off (AGENTMEMORY_GRAPH_COMPACT_ON_BOOT=false)\";\n if (s.state === \"pending\") return \"pending\";\n const where =\n s.phase === \"snapshot\" || s.total === null || s.total === undefined\n ? `${s.phase ?? \"nodes\"}`\n : `${s.phase} ${s.processed ?? 0} of ${s.total}`;\n if (s.state === \"running\") return `running, ${where}`;\n if (s.state === \"failed\") return `failed at ${where}: ${s.error ?? \"unknown error\"}`;\n return `done, ${s.trimmed ?? 0} records trimmed, ${s.idsRemoved ?? 0} ids removed`;\n}\n\nexport function runGraphCompactOnBoot(\n kv: StateKV,\n opts: GraphCompactBootOptions = {},\n): Promise<GraphCompactBootStatus> {\n if (running) return running;\n running = runOnce(kv, opts).finally(() => {\n running = null;\n });\n return running;\n}\n\nasync function runOnce(kv: StateKV, opts: GraphCompactBootOptions): Promise<GraphCompactBootStatus> {\n const sliceSize = opts.sliceSize ?? DEFAULT_SLICE_SIZE;\n const pauseMs = opts.pauseMs ?? DEFAULT_PAUSE_MS;\n const maxAttempts = Math.max(1, opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n const retryDelayMs = opts.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n const log = opts.log ?? (() => {});\n const warn = opts.warn ?? log;\n const sleep = opts.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));\n const now = opts.now ?? (() => new Date());\n\n const attempt = async <T>(fn: () => Promise<T>): Promise<T> => {\n let lastErr: unknown;\n for (let i = 1; i <= maxAttempts; i++) {\n try {\n return await fn();\n } catch (err) {\n lastErr = err;\n if (i < maxAttempts) await sleep(retryDelayMs * i);\n }\n }\n throw lastErr;\n };\n\n let progress: GraphCompactBootProgress | null = null;\n const save = async () => {\n if (!progress) return;\n progress.updatedAt = now().toISOString();\n current = statusFrom(progress);\n await attempt(() => kv.set(KV.config, GRAPH_COMPACT_BOOT_KEY, progress));\n };\n\n try {\n const stored = await attempt(() => kv.get<GraphCompactBootProgress>(KV.config, GRAPH_COMPACT_BOOT_KEY));\n if (isResumable(stored) && stored.status === \"done\") {\n current = statusFrom(stored);\n return getGraphCompactBootStatus();\n }\n const startedAt = now().toISOString();\n if (isResumable(stored)) {\n progress = { ...stored, status: \"running\", error: undefined };\n log(`Graph provenance compaction: resuming in the background at ${progress.phase} ${progress.offset}`);\n } else {\n progress = {\n version: GRAPH_COMPACT_BOOT_VERSION,\n cap: MAX_GRAPH_SOURCE_OBSERVATIONS,\n status: \"running\",\n phase: \"nodes\",\n offset: 0,\n phaseTotal: null,\n scanned: 0,\n trimmed: 0,\n idsRemoved: 0,\n startedAt,\n updatedAt: startedAt,\n };\n log(`Graph provenance compaction: started in the background (cap ${MAX_GRAPH_SOURCE_OBSERVATIONS} ids per record)`);\n }\n await save();\n\n const p = progress;\n for (const scope of SLICED_SCOPES) {\n if (p.phase === \"snapshot\") break;\n if (SLICED_SCOPES.indexOf(p.phase) > SLICED_SCOPES.indexOf(scope)) continue;\n p.phase = scope;\n let phaseTrimmed = 0;\n let phaseScanned = 0;\n for (;;) {\n const slice = { scope: scope as GraphCompactScope, offset: p.offset, limit: sliceSize };\n let plan = storedPlan(p, scope);\n if (!plan) {\n const r = await attempt(() => compactGraphProvenance(kv, { ...slice, dryRun: true }));\n const [scanned, trimmed] = scannedOf(scope, r);\n plan = {\n phase: scope,\n offset: p.offset,\n scanned,\n trimmed,\n idsRemoved: r.idsRemoved,\n nextOffset: r.nextOffset,\n total: r.total ?? null,\n };\n if (plan.trimmed > 0) {\n p.pending = plan;\n await save();\n }\n }\n if (plan.trimmed > 0) await attempt(() => compactGraphProvenance(kv, slice));\n phaseScanned += plan.scanned;\n phaseTrimmed += plan.trimmed;\n p.scanned += plan.scanned;\n p.trimmed += plan.trimmed;\n p.idsRemoved += plan.idsRemoved;\n p.pending = undefined;\n p.phaseTotal = plan.total;\n p.offset = plan.nextOffset ?? p.phaseTotal ?? p.offset;\n await save();\n if (plan.nextOffset === null) break;\n if (pauseMs > 0) await sleep(pauseMs);\n }\n log(`Graph provenance compaction: ${scope} done (${phaseScanned} checked, ${phaseTrimmed} trimmed)`);\n const next = SLICED_SCOPES[SLICED_SCOPES.indexOf(scope) + 1];\n p.phase = next ?? \"snapshot\";\n p.offset = 0;\n p.phaseTotal = null;\n await save();\n }\n\n let snapPlan = storedPlan(p, \"snapshot\");\n if (!snapPlan) {\n const dry = await attempt(() => compactGraphProvenance(kv, { scope: \"snapshot\", dryRun: true }));\n snapPlan = {\n phase: \"snapshot\",\n offset: p.offset,\n scanned: 0,\n trimmed: dry.snapshotTrimmed ? 1 : 0,\n idsRemoved: 0,\n nextOffset: null,\n total: null,\n };\n if (snapPlan.trimmed > 0) {\n p.pending = snapPlan;\n await save();\n }\n }\n if (snapPlan.trimmed > 0) await attempt(() => compactGraphProvenance(kv, { scope: \"snapshot\" }));\n const snapshotTrimmed = snapPlan.trimmed > 0;\n p.trimmed += snapPlan.trimmed;\n p.pending = undefined;\n p.status = \"done\";\n p.completedAt = now().toISOString();\n await save();\n if (p.idsRemoved > 0) {\n await safeAudit(kv, \"graph_compact\", GRAPH_COMPACT_BOOT_FUNCTION_ID, [], {\n trigger: \"boot\",\n recordsTrimmed: p.trimmed,\n idsRemoved: p.idsRemoved,\n snapshotTrimmed,\n });\n }\n log(\n `Graph provenance compaction: done (${p.scanned} records checked, ${p.trimmed} trimmed, ${p.idsRemoved} ids removed)`,\n );\n return getGraphCompactBootStatus();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (progress) {\n progress.status = \"failed\";\n progress.error = msg;\n current = statusFrom(progress);\n try {\n await kv.set(KV.config, GRAPH_COMPACT_BOOT_KEY, { ...progress, updatedAt: now().toISOString() });\n } catch {}\n } else {\n current = { state: \"failed\", error: msg };\n }\n warn(\n `Graph provenance compaction failed (${describeGraphCompactBoot(current)}). It resumes on the next start; to run it now, POST /agentmemory/graph/compact.`,\n );\n return getGraphCompactBootStatus();\n }\n}\n","import type { IndexLegStatus, IndexPersistenceStatus } from \"../state/index-persistence.js\";\nimport type { VectorBackfillState } from \"./search.js\";\nimport { describeGraphCompactBoot, type GraphCompactBootStatus } from \"./graph-compact-boot.js\";\nimport type { CaptureStatus } from \"./capture.js\";\n\nexport type StatusLevel = \"ok\" | \"info\" | \"warn\" | \"error\";\n\nexport interface StatusProblem {\n level: Exclude<StatusLevel, \"ok\">;\n code: string;\n message: string;\n fix?: string;\n}\n\nexport interface FunctionMetricInput {\n functionId: string;\n totalCalls: number;\n successCount: number;\n failureCount: number;\n avgLatencyMs: number;\n}\n\nexport interface StatusFlag {\n key: string;\n label: string;\n enabled: boolean;\n needsLlm: boolean;\n enableHow: string;\n}\n\nexport interface GraphStatsInput {\n totalNodes?: number;\n totalEdges?: number;\n fromSnapshot?: boolean;\n updatedAt?: string;\n dirty?: boolean;\n warning?: string;\n}\n\nexport interface StatusInputs {\n now: Date;\n version: string;\n engineVersion: string;\n uptimeSeconds: number;\n stateBackend: \"file\" | \"redis\";\n ports: { rest: number | null; streams: number | null; viewer: number | null };\n health: {\n status?: string;\n alerts?: string[];\n notes?: string[];\n connectionState?: string;\n memory?: { heapUsed: number; heapTotal: number; heapLimit?: number; rss: number };\n eventLoopLagMs?: number;\n cpuPercent?: number;\n } | null;\n circuitBreaker: { state?: string; failures?: number } | null;\n functionMetrics: FunctionMetricInput[];\n provider: string;\n embeddingProvider: string;\n flags: StatusFlag[];\n index: {\n bm25Documents: number;\n vectorDocuments: number | null;\n observationsIndexed: number;\n memoriesIndexed?: number;\n lessonsIndexed?: number;\n missingObservations: number | null;\n sessions: number | null;\n bm25Incomplete: boolean;\n keywordRebuildRunning?: boolean;\n pendingVectorBackfill: number;\n vectorBackfillState?: VectorBackfillState;\n };\n graph: GraphStatsInput | null;\n graphExtractionEnabled: boolean;\n graphCompaction?: GraphCompactBootStatus | null;\n auditLegacy: { status: string; sizeBytes?: number } | null;\n indexPersistence?: IndexPersistenceStatus | null;\n stateStore?: { ok: boolean; latencyMs?: number } | null;\n capture?: CaptureStatus | null;\n observeDedup?: ObserveDedupStatus | null;\n}\n\nexport interface ObserveDedupStatus {\n skippedSinceStart: number;\n windowSeconds: number;\n}\n\nexport interface IndexBreakdown {\n observations: number;\n memories: number;\n lessons: number;\n}\n\nexport interface StatusReport {\n status: StatusLevel;\n headline: string;\n checkedAt: string;\n service: {\n version: string;\n engineVersion: string;\n uptimeSeconds: number;\n stateBackend: StatusInputs[\"stateBackend\"];\n stateStore: { ok: boolean; latencyMs?: number } | null;\n ports: StatusInputs[\"ports\"];\n };\n health: StatusInputs[\"health\"];\n provider: {\n llm: string;\n embeddings: string;\n circuitBreaker: StatusInputs[\"circuitBreaker\"];\n offWithoutLlm: string[];\n };\n index: StatusInputs[\"index\"] & { breakdown: IndexBreakdown | null };\n indexPersistence: IndexPersistenceStatus | null;\n graph: (GraphStatsInput & { ageSeconds: number | null; extractionEnabled: boolean }) | null;\n graphCompaction: GraphCompactBootStatus | null;\n capture: CaptureStatus | null;\n observeDedup: ObserveDedupStatus | null;\n functions: Array<FunctionMetricInput & { failureRate: number; offWithoutLlm: boolean }>;\n flags: Array<StatusFlag & { inactiveReason?: string }>;\n problems: StatusProblem[];\n}\n\nconst FAILURE_RATE_THRESHOLD = 0.2;\nconst FAILURE_MIN_CALLS = 5;\nconst GRAPH_SNAPSHOT_STALE_SECONDS = 24 * 60 * 60;\nconst LEVEL_RANK: Record<StatusLevel, number> = { ok: 0, info: 1, warn: 2, error: 3 };\n\nconst FUNCTION_FIXES: Record<string, string> = {\n \"mem::summarize\":\n \"Summaries come from your LLM provider. Check the provider key, model name and rate limits in ~/.agentmemory/.env, then look for provider errors in the server log.\",\n \"mem::compress\":\n \"Compression calls your LLM provider. Check the provider key and model, or set AGENTMEMORY_AUTO_COMPRESS=false to use zero-LLM compression.\",\n \"mem::graph-extract\":\n \"Graph extraction calls your LLM provider. Check the provider key and model, or set GRAPH_EXTRACTION_ENABLED=false.\",\n};\n\nexport const LLM_KEY_FIX =\n \"Add one LLM provider key (for example ANTHROPIC_API_KEY or OPENAI_API_KEY) to ~/.agentmemory/.env and restart.\";\n\nexport const OFF_WITHOUT_LLM = [\n \"session summaries\",\n \"consolidation into semantic facts and procedures\",\n \"typed graph extraction\",\n \"LLM observation compression\",\n \"skill extraction from finished sessions\",\n];\n\nexport const BM25_EXPLAINER =\n \"The keyword index holds observations, memories and lessons, so its total is larger than the observation count.\";\n\nexport function describeHealthAlert(slug: string): { level: \"warn\" | \"error\"; message: string; fix: string } {\n let m: RegExpExecArray | null;\n if ((m = /^memory_(warn|critical)_(\\d+)%_rss(\\d+)mb$/.exec(slug))) {\n return {\n level: m[1] === \"critical\" ? \"error\" : \"warn\",\n message: `Memory ${m[1] === \"critical\" ? \"critically high\" : \"high\"}: ${m[2]}% of the heap limit in use, process memory ${m[3]} MB.`,\n fix: \"Restart agentmemory to release memory. If it climbs back, raise the limit with NODE_OPTIONS=--max-old-space-size=4096.\",\n };\n }\n if ((m = /^cpu_(warn|critical)_(\\d+)%$/.exec(slug))) {\n return {\n level: m[1] === \"critical\" ? \"error\" : \"warn\",\n message: `CPU ${m[1] === \"critical\" ? \"critically high\" : \"high\"}: ${m[2]}%.`,\n fix: \"Usually a burst of observations or a rebuild. If it stays high with no agent running, check the server log for a loop.\",\n };\n }\n if ((m = /^event_loop_lag_(warn|critical)_(\\d+)ms$/.exec(slug))) {\n return {\n level: m[1] === \"critical\" ? \"error\" : \"warn\",\n message: `The worker is ${m[2]} ms behind on its work (event loop delay), so requests answer slowly.`,\n fix: \"It usually clears after an import or index rebuild finishes. If it persists, restart agentmemory.\",\n };\n }\n if (slug === \"stream_relay_down\") {\n return {\n level: \"warn\",\n message: \"Live updates are not reaching the viewer: the engine stopped relaying stream events, which happens after Redis restarts or drops the connection. Data is still saved.\",\n fix: \"Restart agentmemory (npx @agentmemory/agentmemory stop, then start) so the engine subscribes to Redis again, then reload the viewer.\",\n };\n }\n if (slug === \"connection_reconnecting\") {\n return {\n level: \"warn\",\n message: \"The connection to the iii engine dropped and is reconnecting.\",\n fix: \"Wait a few seconds. If it does not recover, check that the engine is running with npx @agentmemory/agentmemory status.\",\n };\n }\n if ((m = /^connection_(.+)$/.exec(slug))) {\n return {\n level: \"error\",\n message: `The connection to the iii engine is ${m[1]}, so nothing can be stored or searched.`,\n fix: \"Restart agentmemory. Run npx @agentmemory/agentmemory doctor if the engine does not start.\",\n };\n }\n return { level: \"warn\", message: slug, fix: \"Look for this alert in the server log.\" };\n}\n\nexport function isOffWithoutLlm(functionId: string, providerKind: string): boolean {\n return providerKind === \"noop\" && functionId in FUNCTION_FIXES;\n}\n\nexport function markLlmFunctions<T extends { functionId: string }>(\n metrics: T[],\n providerKind: string,\n): Array<T & { offWithoutLlm: boolean }> {\n return metrics.map((m) => ({ ...m, offWithoutLlm: isOffWithoutLlm(m.functionId, providerKind) }));\n}\n\nfunction secondsBetween(later: Date, earlierIso: string | undefined): number | null {\n if (!earlierIso) return null;\n const earlier = Date.parse(earlierIso);\n if (Number.isNaN(earlier)) return null;\n return Math.max(0, Math.round((later.getTime() - earlier) / 1000));\n}\n\nfunction describeBackfillState(state: VectorBackfillState): string {\n if (state === \"waiting-for-opt-in\") return \"paused, waiting for opt-in\";\n if (state === \"paused\") return \"paused, retried on the next start\";\n return state;\n}\n\nfunction vectorBackfillFix(state: VectorBackfillState | undefined): string {\n if (state === \"waiting-for-opt-in\") {\n return \"Backfill is paused. Set AGENTMEMORY_VECTOR_BACKFILL=all and restart to opt in. This calls the embedding provider and is capped per boot by AGENTMEMORY_VECTOR_BACKFILL_MAX.\";\n }\n if (state === \"running\") {\n return \"Backfill is running in the background in batches of AGENTMEMORY_VECTOR_BACKFILL_MAX with a short pause between batches. If agentmemory stops first, it continues on the next start. Check the server log for embedding provider errors if progress stops.\";\n }\n if (state === \"paused\") {\n return \"Backfill stopped because the embedding provider did not return vectors. Search still works by keyword. Check the embedding provider key and the server log; the remaining documents are retried on the next start.\";\n }\n return \"Backfill is not running. Check the server log and embedding provider configuration. A full backfill requires AGENTMEMORY_VECTOR_BACKFILL=all and a restart, and can consume embedding provider tokens.\";\n}\n\nexport function evaluateStatus(input: StatusInputs): StatusReport {\n const problems: StatusProblem[] = [];\n\n if (!input.health) {\n problems.push({\n level: \"info\",\n code: \"health-check-unavailable\",\n message: \"The health monitor has no snapshot yet or did not answer in time, so its state was not checked.\",\n fix: \"The monitor writes a snapshot every 30 seconds after start. Wait a minute; if this stays, check the server log.\",\n });\n }\n const healthStatus = input.health?.status;\n const alerts = input.health?.alerts ?? [];\n if (alerts.length === 0 && healthStatus === \"critical\") {\n problems.push({\n level: \"error\",\n code: \"health-critical\",\n message: \"The health monitor reports a critical state.\",\n fix: \"Check the server log, then restart agentmemory.\",\n });\n } else if (alerts.length === 0 && healthStatus === \"degraded\") {\n problems.push({\n level: \"warn\",\n code: \"health-degraded\",\n message: \"The health monitor reports a degraded state.\",\n fix: \"Check the server log for the cause.\",\n });\n }\n const described = alerts.map(describeHealthAlert);\n if (healthStatus !== \"critical\") for (const d of described) d.level = \"warn\";\n else if (described.length && !described.some((d) => d.level === \"error\")) described[0].level = \"error\";\n for (const d of described) {\n problems.push({ level: d.level, code: \"health-alert\", message: d.message, fix: d.fix });\n }\n\n if (input.circuitBreaker?.state === \"open\") {\n problems.push({\n level: \"error\",\n code: \"provider-circuit-open\",\n message: `LLM provider calls are paused after ${input.circuitBreaker.failures ?? 0} consecutive failures.`,\n fix: \"Check the provider key and model in ~/.agentmemory/.env. Calls resume automatically once the provider answers again.\",\n });\n }\n\n if (input.provider === \"noop\") {\n problems.push({\n level: \"info\",\n code: \"no-llm-provider\",\n message: \"No LLM provider is configured, so summaries, consolidation and graph extraction stay off. Search still works.\",\n fix: LLM_KEY_FIX,\n });\n }\n\n const noLlm = input.provider === \"noop\";\n const functions = markLlmFunctions(input.functionMetrics, input.provider).map((m) => ({\n ...m,\n failureRate: m.totalCalls > 0 ? m.failureCount / m.totalCalls : 0,\n }));\n for (const fn of functions) {\n if (fn.offWithoutLlm) continue;\n if (fn.totalCalls < FAILURE_MIN_CALLS || fn.failureRate < FAILURE_RATE_THRESHOLD) continue;\n problems.push({\n level: \"warn\",\n code: \"function-failing\",\n message: `${fn.functionId} failed ${fn.failureCount} of ${fn.totalCalls} calls (${Math.round(fn.failureRate * 100)}%).`,\n fix: FUNCTION_FIXES[fn.functionId] ?? \"Look for this function id in the server log to see the error.\",\n });\n }\n\n const missingObservations = input.index.missingObservations;\n if (!input.index.keywordRebuildRunning && missingObservations !== null && missingObservations > 0) {\n problems.push({\n level: \"warn\",\n code: \"index-missing-observations\",\n message: `${missingObservations} stored observations are not in the search index, so search cannot find them.`,\n fix: \"Restart agentmemory: the boot reconcile re-indexes observations missing from the snapshot.\",\n });\n }\n if (input.index.keywordRebuildRunning) {\n problems.push({\n level: \"info\",\n code: \"keyword-index-rebuilding\",\n message: \"The keyword index is still rebuilding from stored data, so the check for observations missing from search waits until it finishes.\",\n fix: \"No action needed. The check runs on the next health update after the rebuild.\",\n });\n } else if (missingObservations === null) {\n problems.push({\n level: \"info\",\n code: \"index-check-unavailable\",\n message: \"The session store did not answer in time, so the search index was not checked for missing observations.\",\n fix: \"The check runs again on the next health update. If it keeps timing out, the store is overloaded: check the server log.\",\n });\n }\n\n if (input.index.bm25Incomplete) {\n problems.push({\n level: \"error\",\n code: \"bm25-rebuild-incomplete\",\n message: \"The keyword index could not load every session at boot, so some observations are missing from search until the next successful rebuild.\",\n fix: \"Check the server log for the session listing failure. Restarting or the next cold-start search retries automatically.\",\n });\n }\n\n if (input.index.pendingVectorBackfill > 0) {\n problems.push({\n level: \"info\",\n code: \"index-vector-backfill-pending\",\n message: `${input.index.pendingVectorBackfill} documents are waiting for a vector embedding.`,\n fix: vectorBackfillFix(input.index.vectorBackfillState),\n });\n }\n\n const persistence = input.indexPersistence ?? null;\n const vectorLeg = persistence?.vector ?? null;\n if (persistence && vectorLeg) {\n if (vectorLeg.lastError) {\n problems.push({\n level: \"error\",\n code: \"index-save-failing\",\n message: `The vector index could not be saved: ${vectorLeg.lastError}. Search keeps working from memory, but vectors added since the last save are lost on restart.`,\n fix: \"Check the server log for the failing state write. The next save retries automatically.\",\n });\n }\n const dirtyAge = secondsBetween(input.now, vectorLeg.dirtySince ?? undefined);\n if (!vectorLeg.lastError && dirtyAge !== null && dirtyAge * 1000 > 2 * persistence.saveIntervalMs) {\n problems.push({\n level: \"warn\",\n code: \"index-save-stale\",\n message: `The vector index has unsaved changes from ${formatDuration(dirtyAge)} ago.`,\n fix: \"After the first checkpoint, saves are batched by AGENTMEMORY_INDEX_SAVE_INTERVAL_MS. Check the server log for save errors or a save that never finishes.\",\n });\n }\n }\n if (persistence?.pendingLogError) {\n problems.push({\n level: \"warn\",\n code: \"index-pending-log-failing\",\n message: `New vectors could not be written to the pending vector log: ${persistence.pendingLogError}. They are still kept by the next index save, but a crash before then means they are embedded again at the next start.`,\n fix: \"Check the server log for the failing state write. Each new vector retries the log write.\",\n });\n }\n if (persistence?.vectorCountShortfall) {\n const { expected, loaded } = persistence.vectorCountShortfall;\n problems.push({\n level: \"warn\",\n code: \"index-vector-count-shortfall\",\n message: `Only ${loaded} of ${expected} vectors loaded from the last save.`,\n fix: vectorBackfillFix(input.index.vectorBackfillState),\n });\n }\n\n let graph: StatusReport[\"graph\"] = null;\n if (input.graph) {\n const ageSeconds = secondsBetween(input.now, input.graph.updatedAt);\n graph = { ...input.graph, ageSeconds, extractionEnabled: input.graphExtractionEnabled };\n if (input.graphExtractionEnabled && !input.graph.fromSnapshot) {\n problems.push({\n level: \"warn\",\n code: \"graph-no-snapshot\",\n message: \"Graph extraction is on but no graph snapshot exists, so graph counts read as zero.\",\n fix: \"Use Rebuild Graph in the viewer, or POST /agentmemory/graph/snapshot-rebuild.\",\n });\n } else if (input.graph.fromSnapshot && ageSeconds !== null && ageSeconds > GRAPH_SNAPSHOT_STALE_SECONDS) {\n const age = ageSeconds >= 2 * 86400 ? `${Math.floor(ageSeconds / 86400)} days` : `${Math.round(ageSeconds / 3600)} hours`;\n problems.push({\n level: \"info\",\n code: \"graph-snapshot-stale\",\n message: `The graph snapshot is ${age} old, so dashboard graph counts can lag the live graph.`,\n fix: \"POST /agentmemory/graph/snapshot-rebuild refreshes it.\",\n });\n }\n if (input.graph.dirty) {\n problems.push({\n level: \"info\",\n code: \"graph-snapshot-dirty\",\n message: \"The graph snapshot was read while a write was in flight; counts are eventually consistent.\",\n fix: \"No action needed: the next graph write settles the counts.\",\n });\n }\n }\n\n const compaction = input.graphCompaction ?? null;\n if (compaction?.state === \"running\") {\n problems.push({\n level: \"info\",\n code: \"graph-compaction-running\",\n message: `Oversized graph provenance is being trimmed in the background (${describeGraphCompactBoot(compaction)}). Search and capture keep working.`,\n fix: \"No action needed. It runs once, resumes after a restart and stops by itself. AGENTMEMORY_GRAPH_COMPACT_ON_BOOT=false turns it off.\",\n });\n } else if (compaction?.state === \"failed\") {\n problems.push({\n level: \"warn\",\n code: \"graph-compaction-failed\",\n message: `The one-time graph provenance compaction stopped: ${compaction.error ?? \"unknown error\"}. Graph search can stay slow until it finishes.`,\n fix: `It resumes on the next start. To run it now: ${graphCompactCommand(input.ports.rest)}`,\n });\n }\n\n if (input.auditLegacy?.status === \"too-large\" || input.auditLegacy?.status === \"unreadable\") {\n const size = input.auditLegacy.sizeBytes;\n const sizeText = typeof size === \"number\" ? ` (${Math.round(size / (1024 * 1024))} MiB)` : \"\";\n problems.push({\n level: \"info\",\n code: \"audit-legacy-frozen\",\n message: `An older audit log${sizeText} was left in place instead of being migrated into monthly scopes, so it is no longer rewritten but its rows do not show up in audit queries.`,\n fix:\n input.stateBackend === \"redis\"\n ? \"Safe to ignore. To remove it, run redis-cli -u \\\"$AGENTMEMORY_REDIS_URL\\\" DEL state:mem:audit, then restart agentmemory.\"\n : \"Safe to ignore. To remove it, stop agentmemory, delete mem%3Aaudit.bin from the state store directory, then start it again.\",\n });\n }\n\n if (input.capture === null) {\n problems.push({\n level: \"info\",\n code: \"capture-check-unavailable\",\n message: \"The capture inbox did not answer in time, so capture was not checked.\",\n fix: \"The check runs again on the next status request. If it keeps timing out, the state store is overloaded: check the server log.\",\n });\n }\n problems.push(...captureProblems(input.capture ?? null, input.now, input.ports.rest));\n\n if (input.stateStore && !input.stateStore.ok) {\n problems.push({\n level: \"error\",\n code: \"state-store-unreachable\",\n message:\n input.stateBackend === \"redis\"\n ? \"The state store is not answering: the engine cannot reach Redis, so nothing is being saved or read.\"\n : \"The state store is not answering: the engine did not complete a state read in time, so nothing is being saved or read.\",\n fix:\n input.stateBackend === \"redis\"\n ? \"Check that Redis is running and reachable at AGENTMEMORY_REDIS_URL (redis-cli -u \\\"$AGENTMEMORY_REDIS_URL\\\" ping should answer PONG). Once Redis is back, restart agentmemory: the engine does not resume the live viewer stream after a Redis restart.\"\n : \"Check the server log for engine errors, then restart agentmemory.\",\n });\n }\n\n const status = problems.reduce<StatusLevel>(\n (worst, p) => (LEVEL_RANK[p.level] > LEVEL_RANK[worst] ? p.level : worst),\n \"ok\",\n );\n\n return {\n status,\n headline: statusHeadline(status, problems),\n checkedAt: input.now.toISOString(),\n service: {\n version: input.version,\n engineVersion: input.engineVersion,\n uptimeSeconds: input.uptimeSeconds,\n stateBackend: input.stateBackend,\n stateStore: input.stateStore ?? null,\n ports: input.ports,\n },\n health: input.health,\n provider: {\n llm: input.provider,\n embeddings: input.embeddingProvider,\n circuitBreaker: input.circuitBreaker,\n offWithoutLlm: noLlm ? OFF_WITHOUT_LLM : [],\n },\n index: { ...input.index, breakdown: indexBreakdown(input.index) },\n indexPersistence: persistence,\n graph,\n graphCompaction: compaction,\n capture: input.capture ?? null,\n observeDedup: input.observeDedup ?? null,\n functions,\n flags: input.flags.map((flag) =>\n flag.enabled && flag.needsLlm && noLlm\n ? { ...flag, inactiveReason: \"needs an LLM provider, none is configured\" }\n : flag,\n ),\n problems,\n };\n}\n\nconst RECENT_DROP_MS = 24 * 60 * 60 * 1000;\n\nexport const CURL_AUTH_HEADER = '-H \"Authorization: Bearer ${AGENTMEMORY_SECRET:-$(cat ~/.agentmemory/secret)}\"';\n\nexport function captureRestBase(restPort: number | null): string {\n return `http://localhost:${restPort ?? 3111}/agentmemory`;\n}\n\nfunction captureProblems(capture: CaptureStatus | null, now: Date, restPort: number | null): StatusProblem[] {\n if (!capture) return [];\n const problems: StatusProblem[] = [];\n const base = captureRestBase(restPort);\n const inbox = capture.inbox;\n if (inbox && inbox.dead > 0) {\n problems.push({\n level: \"warn\",\n code: \"capture-dead-letters\",\n message: `${plural(inbox.dead, \"captured observation\")} could not be stored after ${plural(capture.policy.maxAttempts, \"attempt\")} and ${inbox.dead === 1 ? \"is parked as a dead letter\" : \"are parked as dead letters\"}${inbox.lastError ? `: ${inbox.lastError}` : \".\"}`,\n fix: `List them with curl -s ${CURL_AUTH_HEADER} '${base}/capture?status=dead'. After fixing the cause, retry them with curl -X POST ${base}/capture/retry ${CURL_AUTH_HEADER} -H \"Content-Type: application/json\" -d '{\"all\":true}'.`,\n });\n }\n if (inbox && inbox.retrying + inbox.pending > 0) {\n problems.push({\n level: \"info\",\n code: \"capture-retrying\",\n message: `${plural(inbox.retrying + inbox.pending, \"accepted observation\")} ${inbox.retrying + inbox.pending === 1 ? \"is\" : \"are\"} waiting to be stored${inbox.lastError ? ` after a failure: ${inbox.lastError}` : \"\"}.`,\n fix: `No action needed: the server retries every ${Math.round(capture.policy.retryIntervalMs / 1000)} s with backoff, up to ${capture.policy.maxAttempts} attempts, and again after a restart.`,\n });\n }\n const waiting = capture.spool.reduce((n, s) => n + s.records, 0);\n if (waiting > 0) {\n problems.push({\n level: \"info\",\n code: \"capture-spool-waiting\",\n message: `${plural(waiting, \"observation\")} captured while the server was unreachable ${waiting === 1 ? \"is\" : \"are\"} waiting in the local capture spool.`,\n fix: `They are sent on the next hook call and at every start. To send them now: npx @agentmemory/agentmemory capture --drain, or curl -X POST ${base}/capture/drain ${CURL_AUTH_HEADER}.`,\n });\n }\n let dropped = 0;\n let latest: { at: number; reason: string; maxBytes: number; maxAgeHours: number } | null = null;\n for (const spool of capture.spool) {\n dropped += spool.stats.dropped;\n const lastDrop = spool.stats.lastDropAt ? Date.parse(spool.stats.lastDropAt) : NaN;\n if (Number.isFinite(lastDrop) && (!latest || lastDrop > latest.at)) {\n latest = { at: lastDrop, reason: spool.stats.lastDropReason ?? \"unknown\", maxBytes: spool.maxBytes, maxAgeHours: spool.maxAgeHours };\n }\n }\n if (latest && now.getTime() - latest.at < RECENT_DROP_MS) {\n problems.push({\n level: \"warn\",\n code: \"capture-spool-dropped\",\n message: `The local capture spool dropped ${plural(dropped, \"observation\")} in total (latest reason: ${latest.reason}), so those tool calls are not in memory.`,\n fix: `The spool holds at most ${Math.round(latest.maxBytes / 1024)} KiB for ${latest.maxAgeHours} hours. Raise AGENTMEMORY_CAPTURE_SPOOL_MAX_BYTES, keep agentmemory running while agents work, or check that AGENTMEMORY_CAPTURE_SPOOL is not false.`,\n });\n }\n return problems;\n}\n\nfunction statusHeadline(status: StatusLevel, problems: StatusProblem[]): string {\n if (status === \"ok\") return \"Every check passed. Capture, search and the stream are working.\";\n if (status === \"info\") {\n return `Working normally. ${plural(problems.length, \"note\")} below about features that are off or checks that did not run.`;\n }\n const worst = problems.find((p) => p.level === status) ?? problems[0];\n const rest = problems.length - 1;\n const lead = status === \"error\" ? \"Not working correctly\" : \"Working, but needs attention\";\n return `${lead}: ${worst.message}${rest > 0 ? ` (${plural(rest, \"more item\")} below.)` : \"\"}`;\n}\n\nfunction indexBreakdown(idx: StatusInputs[\"index\"]): IndexBreakdown | null {\n if (idx.memoriesIndexed === undefined && idx.lessonsIndexed === undefined) return null;\n const lessons = idx.lessonsIndexed ?? 0;\n return {\n observations: Math.max(0, idx.observationsIndexed - lessons),\n memories: idx.memoriesIndexed ?? 0,\n lessons,\n };\n}\n\nfunction plural(count: number, word: string): string {\n return `${count} ${word}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction documentBreakdown(idx: StatusReport[\"index\"]): string {\n const b = idx.breakdown;\n if (!b) return String(idx.bm25Documents);\n const parts = [\n plural(b.observations, \"observation\"),\n `${b.memories} ${b.memories === 1 ? \"memory\" : \"memories\"}`,\n plural(b.lessons, \"lesson\"),\n ];\n return `${idx.bm25Documents} (${parts.join(\", \")})`;\n}\n\nfunction flagState(flag: StatusReport[\"flags\"][number]): string {\n if (!flag.enabled) return \"off\";\n if (flag.inactiveReason) return `on, inactive: ${flag.inactiveReason}`;\n return \"on\";\n}\n\nfunction flagHowTo(flag: StatusReport[\"flags\"][number]): string {\n if (!flag.enabled) return flag.enableHow;\n if (flag.inactiveReason) return LLM_KEY_FIX;\n return `Set ${flag.key}=false and restart to turn it off.`;\n}\n\nfunction processHealth(report: StatusReport): string {\n const status = report.health?.status;\n if (!status) return \"no data yet\";\n if (status === \"healthy\" && report.status !== \"ok\") {\n return \"healthy (memory, CPU and engine checks only; the badge at the top covers every problem on this page)\";\n }\n return status;\n}\n\nfunction escapeHtml(value: unknown): string {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction formatDuration(seconds: number | null): string {\n if (seconds === null) return \"unknown\";\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n if (hours < 48) return `${hours}h ${minutes % 60}m`;\n return `${Math.floor(hours / 24)}d`;\n}\n\nfunction row(label: string, value: string): string {\n return `<tr><th>${escapeHtml(label)}</th><td>${value}</td></tr>`;\n}\n\nfunction legSummary(report: StatusReport, leg: IndexLegStatus): string {\n if (leg.lastError) return `failing: ${leg.lastError}`;\n const saved = leg.lastSavedAt ? `saved ${formatDuration(secondsBetween(new Date(report.checkedAt), leg.lastSavedAt))} ago` : \"not saved since start\";\n return leg.dirtySince ? `${saved}, unsaved changes pending` : saved;\n}\n\nconst PENDING_LOG_EXPLAINER =\n \"Every new or removed vector is also written right away to this small log. After a crash or force-kill it is replayed at start, so vectors are not lost and nothing is embedded twice. Each index save empties it.\";\n\nfunction indexPersistenceRows(report: StatusReport): string {\n const persistence = report.indexPersistence;\n if (!persistence) return \"\";\n let rows = row(\"BM25 index\", \"rebuilt from stored content at boot\");\n if (persistence.vector) {\n rows += row(\"Vector save\", escapeHtml(legSummary(report, persistence.vector)));\n rows += row(\n \"Vector storage\",\n escapeHtml(`${plural(persistence.buckets, \"bucket\")}, ${plural(persistence.pendingChanges, \"unsaved change\")}`),\n );\n if (persistence.pendingLog !== undefined) {\n rows += row(\n \"Pending vector log\",\n escapeHtml(plural(persistence.pendingLog, \"vector change\")) +\n `<p class=\"note\">${escapeHtml(PENDING_LOG_EXPLAINER)}</p>`,\n );\n }\n }\n return rows;\n}\n\nexport function describeCaptureSpool(capture: CaptureStatus): string {\n const records = capture.spool.reduce((n, s) => n + s.records, 0);\n const bytes = capture.spool.reduce((n, s) => n + s.bytes, 0);\n if (!capture.spool.some((s) => s.enabled)) return \"off (AGENTMEMORY_CAPTURE_SPOOL=false)\";\n const retained = capture.spool.reduce((n, s) => n + (s.retained ?? 0), 0);\n const held = retained > 0 ? `, ${retained} sent and kept until saved` : \"\";\n return records === 0 ? `empty${held}` : `${plural(records, \"observation\")} waiting, ${Math.ceil(bytes / 1024)} KiB${held}`;\n}\n\nfunction captureRows(report: StatusReport): string {\n const capture = report.capture;\n if (!capture) return row(\"Capture\", \"not reported\");\n const inbox = capture.inbox;\n const since = capture.sinceStart;\n let rows = row(\n \"Inbox\",\n escapeHtml(inbox ? `${inbox.pending} pending · ${inbox.retrying} retrying · ${inbox.dead} dead letters` : \"not checked\") +\n '<p class=\"note\">Every accepted observation is written here first and removed once it is stored, so a failure or restart retries it instead of losing it.</p>',\n );\n rows += row(\n \"Since start\",\n escapeHtml(`${since.accepted} accepted · ${since.completed} stored · ${since.duplicates} duplicates skipped · ${since.recovered} recovered by retry · ${since.deadLettered} dead`),\n );\n rows += row(\n \"Local spool\",\n escapeHtml(describeCaptureSpool(capture)) +\n `<p class=\"note\">Hooks write here when the server is unreachable, and keep each accepted observation here until the server has saved it to disk. ${escapeHtml(capture.spool.map((s) => s.path).join(\", \"))}</p>`,\n );\n const drained = capture.spool.map((s) => s.stats.lastDrainAt).filter(Boolean).sort().pop();\n if (drained) rows += row(\"Last spool drain\", escapeHtml(`${formatDuration(secondsBetween(new Date(report.checkedAt), drained))} ago`));\n rows += row(\n \"Duplicate protection\",\n escapeHtml(`event ids kept ${capture.policy.dedupRetentionHours} h, retries up to ${plural(capture.policy.maxAttempts, \"attempt\")}`),\n );\n return rows;\n}\n\nfunction mb(bytes: number): string {\n return `${Math.round(bytes / (1024 * 1024))} MB`;\n}\n\nfunction processRows(report: StatusReport): string {\n const h = report.health;\n let rows = row(\"Process health\", escapeHtml(processHealth(report)));\n if (h?.memory) {\n const limit = h.memory.heapLimit || h.memory.heapTotal;\n const pct = limit > 0 ? Math.round((h.memory.heapUsed / limit) * 100) : 0;\n rows += row(\n \"Heap\",\n escapeHtml(`${mb(h.memory.heapUsed)} of ${mb(limit)} (${pct}%)`) +\n '<p class=\"note\">JavaScript memory in use against the most it may grow to. Only a concern above 80% while RSS is also over 512 MB.</p>',\n );\n rows += row(\n \"RSS\",\n escapeHtml(mb(h.memory.rss)) + '<p class=\"note\">Everything the process holds from the operating system, including code and buffers.</p>',\n );\n }\n if (typeof h?.eventLoopLagMs === \"number\") {\n rows += row(\n \"Event loop delay\",\n escapeHtml(`${h.eventLoopLagMs.toFixed(1)} ms`) +\n '<p class=\"note\">How far behind the worker is. Under 100 ms is fine; above that requests answer slowly.</p>',\n );\n }\n return rows;\n}\n\nexport function renderStatusHtml(\n report: StatusReport,\n styleNonce: string,\n options: { viewerUrl?: string } = {},\n): string {\n const viewerUrl = options.viewerUrl ?? \"/agentmemory/viewer#health\";\n const problems = report.problems.length\n ? report.problems\n .map(\n (p) =>\n `<li class=\"p ${p.level}\"><span class=\"lvl\">${p.level}</span><div><p>${escapeHtml(p.message)}</p>` +\n (p.fix ? `<p class=\"fix\">${escapeHtml(p.fix)}</p>` : \"\") +\n `</div></li>`,\n )\n .join(\"\")\n : `<li class=\"p ok\"><span class=\"lvl\">ok</span><div><p>No problems found.</p></div></li>`;\n\n const functions = report.functions.length\n ? report.functions\n .slice()\n .sort((a, b) => b.totalCalls - a.totalCalls)\n .map(\n (f) =>\n `<tr${!f.offWithoutLlm && f.failureRate >= FAILURE_RATE_THRESHOLD && f.totalCalls >= FAILURE_MIN_CALLS ? ' class=\"bad\"' : \"\"}>` +\n `<td>${escapeHtml(f.functionId)}</td><td>${f.totalCalls}</td><td>${f.offWithoutLlm ? \"-\" : f.failureCount}</td>` +\n `<td>${f.offWithoutLlm ? \"off, no LLM provider\" : `${Math.round(f.failureRate * 100)}%`}</td><td>${Math.round(f.avgLatencyMs)} ms</td></tr>`,\n )\n .join(\"\")\n : `<tr><td colspan=\"5\">No function calls recorded yet.</td></tr>`;\n\n const flags = report.flags\n .map(\n (f) =>\n `<tr><td>${escapeHtml(f.label)}</td><td><code>${escapeHtml(f.key)}</code></td><td${f.inactiveReason ? ' class=\"warn\"' : \"\"}>${escapeHtml(flagState(f))}</td>` +\n `<td>${escapeHtml(flagHowTo(f))}</td></tr>`,\n )\n .join(\"\");\n\n const idx = report.index;\n const graph = report.graph;\n const ports = report.service.ports;\n\n return `<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>agentmemory status</title>\n<style nonce=\"${escapeHtml(styleNonce)}\">\n:root{--bg:#F9F9F7;--bg-alt:#F0F0EC;--ink:#111111;--ink-muted:#666666;--line:#D4D4CF;--rule:#111111;--ok:#2D6A4F;--info:#1D4E89;--warn:#B8860B;--error:#CC0000;--font-display:'Playfair Display',Georgia,'Times New Roman',serif;--font-body:'Lora',Georgia,serif;--font-ui:'Inter',-apple-system,system-ui,sans-serif;--font-mono:'JetBrains Mono','SF Mono','Fira Code',ui-monospace,monospace}\n@media (prefers-color-scheme:dark){:root{--bg:#121316;--bg-alt:#1a1c20;--ink:#eef0f3;--ink-muted:#94979d;--line:#26282c;--rule:#c9cbd1;--ok:#4ade80;--info:#93c5fd;--warn:#fbbf24;--error:#f2555a}}\n*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.55 var(--font-body)}\nmain{max-width:960px;margin:0 auto;padding:32px 16px 64px}\nheader{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;border-bottom:3px double var(--rule);padding-bottom:12px;margin-bottom:24px}\nh1{font:700 26px/1.2 var(--font-display);margin:0}h2{font:600 11px/1.4 var(--font-ui);letter-spacing:.12em;text-transform:uppercase;color:var(--ink-muted);margin:32px 0 8px;padding-bottom:4px;border-bottom:1px solid var(--rule)}\n.badge{font:700 11px/1.4 var(--font-ui);text-transform:uppercase;letter-spacing:.08em;padding:2px 8px;border:1.5px solid currentColor}\n.ok{color:var(--ok)}.info{color:var(--info)}.warn{color:var(--warn)}.error{color:var(--error)}\n.meta{color:var(--ink-muted);font:12px/1.4 var(--font-ui);margin-left:auto}\nul.problems{list-style:none;padding:0;margin:0}\nli.p{display:grid;grid-template-columns:64px 1fr;gap:12px;padding:12px 0;border-bottom:1px solid var(--line)}\nli.p p{margin:0;color:var(--ink)}li.p .fix{color:var(--ink-muted);margin-top:4px;font-size:13px}\n.lvl{font:700 11px/1.4 var(--font-ui);text-transform:uppercase;letter-spacing:.08em;padding-top:2px}\ntable{width:100%;border-collapse:collapse;font:13px/1.5 var(--font-ui)}th,td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--line);vertical-align:top;overflow-wrap:anywhere}\nth{color:var(--ink-muted);font-weight:500;width:220px}\ntable.list th{width:auto;font-size:11px;text-transform:uppercase;letter-spacing:.06em;overflow-wrap:normal}table.list td{overflow-wrap:break-word}table.list td code{overflow-wrap:break-word;word-break:normal}tr.bad td{color:var(--error)}\ntr:nth-child(even) td{background:var(--bg-alt)}\ncode{font:12px var(--font-mono);overflow-wrap:anywhere}\n.lead{font:600 16px/1.45 var(--font-body);margin:0 0 8px}.live{font:13px/1.5 var(--font-ui);color:var(--ink-muted);margin:0 0 8px}\n.note{margin:2px 0 0;color:var(--ink-muted);font-size:12px}\na{color:inherit}\n@media (max-width:640px){th{width:110px}table.list{table-layout:fixed}table.list th,table.list td{padding:6px 4px;font-size:12px}}\n</style></head><body><main>\n<header><h1>agentmemory</h1><span class=\"badge ${report.status}\">${report.status}</span>\n<span class=\"meta\">v${escapeHtml(report.service.version)} · engine ${escapeHtml(report.service.engineVersion)} · checked ${escapeHtml(report.checkedAt)} · <a href=\"?format=json\">json</a></span></header>\n<p class=\"lead ${report.status}\">${escapeHtml(report.headline)}</p>\n<p class=\"live\">A snapshot from when this page loaded. <a href=\"${escapeHtml(viewerUrl)}\">Open the live version in the viewer →</a> From a terminal: <code>curl -s ${escapeHtml(CURL_AUTH_HEADER)} ${ports.rest ? `http://localhost:${escapeHtml(ports.rest)}` : \"\"}/agentmemory/status</code> returns this report as JSON.</p>\n<h2>Problems</h2><ul class=\"problems\">${problems}</ul>\n<h2>Engine and connection</h2><table>\n${row(\"Engine connection\", escapeHtml(report.health?.connectionState ?? \"unknown\"))}\n${row(\"Uptime\", escapeHtml(formatDuration(report.service.uptimeSeconds)))}\n${row(\"State backend\", escapeHtml(report.service.stateBackend))}\n${row(\"REST port\", escapeHtml(ports.rest ?? \"unknown\"))}\n${row(\"Streams port\", escapeHtml(ports.streams ?? \"unknown\"))}\n${row(\"Viewer port\", escapeHtml(ports.viewer ?? \"not running\"))}\n</table>\n<h2>LLM and embeddings</h2><table>\n${row(\"LLM\", escapeHtml(report.provider.llm === \"noop\" ? \"none configured\" : report.provider.llm))}\n${report.provider.offWithoutLlm.length ? row(\"Off without an LLM\", escapeHtml(report.provider.offWithoutLlm.join(\", \")) + `<p class=\"note\">${escapeHtml(LLM_KEY_FIX)}</p>`) : \"\"}\n${row(\"Embeddings\", escapeHtml(report.provider.embeddings === \"none\" ? \"none (keyword search only)\" : report.provider.embeddings))}\n${row(\"Circuit breaker\", escapeHtml(report.provider.circuitBreaker ? `${report.provider.circuitBreaker.state ?? \"unknown\"} (${report.provider.circuitBreaker.failures ?? 0} failures)` : \"not in use\"))}\n</table>\n<h2>Search index</h2><table>\n${row(\"Keyword index (BM25)\", escapeHtml(documentBreakdown(idx)) + `<p class=\"note\">${escapeHtml(BM25_EXPLAINER)}</p>`)}\n${row(\"Vector documents\", escapeHtml(idx.vectorDocuments ?? \"vector search off\"))}\n${row(\"Observations searchable\", escapeHtml(idx.breakdown ? idx.breakdown.observations : idx.observationsIndexed))}\n${row(\"Missing from index\", escapeHtml(idx.missingObservations ?? \"not checked\"))}\n${row(\"Sessions\", escapeHtml(idx.sessions ?? \"unknown\"))}\n${row(\"Keyword index rebuild\", idx.bm25Incomplete ? '<span class=\"warn\">incomplete</span>' : \"complete\")}\n${row(\"Pending vector backfill\", escapeHtml(idx.pendingVectorBackfill))}\n${idx.vectorBackfillState ? row(\"Vector backfill\", escapeHtml(describeBackfillState(idx.vectorBackfillState))) : \"\"}\n${indexPersistenceRows(report)}\n</table>\n<h2>Capture</h2><table>\n${captureRows(report)}\n${report.observeDedup ? row(\"Repeats skipped\", escapeHtml(`${report.observeDedup.skippedSinceStart} since start`) + `<p class=\"note\">${escapeHtml(`A tool call with the same input and the same output as one stored in the last ${formatDuration(report.observeDedup.windowSeconds)} is skipped when the hook sends no event id.`)}</p>`) : \"\"}\n</table>\n<h2>Knowledge graph</h2><table>\n${graph\n ? row(\"Extraction\", graph.extractionEnabled ? \"on\" : \"off\") +\n row(\"Nodes / edges\", escapeHtml(`${graph.totalNodes ?? 0} / ${graph.totalEdges ?? 0}`)) +\n row(\"Snapshot age\", escapeHtml(graph.fromSnapshot ? formatDuration(graph.ageSeconds) : \"no snapshot\"))\n : row(\"Graph\", \"unavailable\")}\n${report.graphCompaction ? row(\"Provenance compaction\", escapeHtml(describeGraphCompactBoot(report.graphCompaction))) : \"\"}\n</table>\n<h2>Features</h2><table class=\"list\"><tr><th>Feature</th><th>Setting</th><th>State</th><th>How to change</th></tr>${flags}</table>\n<h2>Process</h2><table>\n${processRows(report)}\n</table>\n<h2>Functions</h2><table class=\"list\"><tr><th>Function</th><th>Calls</th><th>Failed</th><th>Failure rate</th><th>Avg latency</th></tr>${functions}</table>\n<h2>More</h2><p>Environment checks (keys, engine binary, stale pid files) run on your machine with <code>npx @agentmemory/agentmemory doctor</code>. JSON: <code>GET /agentmemory/status</code> with <code>Accept: application/json</code>, or add <code>?format=json</code>.</p>\n</main></body></html>`;\n}\n\nexport function graphCompactCommand(restPort: number | null): string {\n return `curl -X POST http://localhost:${restPort ?? 3111}/agentmemory/graph/compact ${CURL_AUTH_HEADER} -H \"Content-Type: application/json\" -d '{}'`;\n}\n\nexport const UNINDEXED_SCAN_REUSE_MS = 30_000;\n\nexport function singleFlight<T>(\n run: () => Promise<T>,\n reuseMs: number,\n now: () => number = Date.now,\n): () => Promise<T> {\n let current: { promise: Promise<T>; settledAt: number | null } | null = null;\n return () => {\n if (current && (current.settledAt === null || now() - current.settledAt < reuseMs)) {\n return current.promise;\n }\n const entry: { promise: Promise<T>; settledAt: number | null } = { promise: run(), settledAt: null };\n entry.promise.then(\n () => {\n entry.settledAt = now();\n },\n () => {\n if (current === entry) current = null;\n },\n );\n current = entry;\n return entry.promise;\n };\n}\n\nexport function prefersHtml(accept: string | undefined, format: string | undefined): boolean {\n if (format === \"json\") return false;\n if (format === \"html\") return true;\n if (!accept) return false;\n return /\\btext\\/html\\b/.test(accept);\n}\n"],"mappings":"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"}
|
package/docker-compose.yml
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
services:
|
|
2
|
-
# One-shot init container: docker creates named volumes root:root mode
|
|
3
|
-
# 755, but the iii-engine image is distroless and runs as UID 65532
|
|
4
|
-
# with no `chown` of its own. Without this, /data is unwritable, the
|
|
5
|
-
# engine silently buffers in RAM, and state evaporates on every
|
|
6
|
-
# restart — the exact symptom v0.9.7's working-directory fix set out
|
|
7
|
-
# to solve. Runs once at compose-up and exits.
|
|
8
|
-
iii-init:
|
|
9
|
-
image: busybox:1.36
|
|
10
|
-
user: "0:0"
|
|
11
|
-
environment:
|
|
12
|
-
AGENTMEMORY_DOCKER_UID: "${AGENTMEMORY_DOCKER_UID:-65532}"
|
|
13
|
-
AGENTMEMORY_DOCKER_GID: "${AGENTMEMORY_DOCKER_GID:-65532}"
|
|
14
|
-
AGENTMEMORY_DOCKER_SKIP_CHOWN: "${AGENTMEMORY_DOCKER_SKIP_CHOWN:-0}"
|
|
15
|
-
volumes:
|
|
16
|
-
- "${AGENTMEMORY_DATA_DIR:-iii-data}:/data"
|
|
17
|
-
entrypoint: ["sh", "-c", "if [ \"$${AGENTMEMORY_DOCKER_SKIP_CHOWN}\" = \"1\" ]; then exit 0; fi; chown -R $${AGENTMEMORY_DOCKER_UID}:$${AGENTMEMORY_DOCKER_GID} /data && chmod 755 /data"]
|
|
18
|
-
restart: "no"
|
|
19
|
-
|
|
20
|
-
iii-engine:
|
|
21
|
-
# Pinned to the same release as agentmemory's iii-sdk dependency
|
|
22
|
-
# (package.json). The worker speaks this engine's wire protocol, so
|
|
23
|
-
# bump the image tag and the SDK together, never one of them alone.
|
|
24
|
-
# 0.22.x is the last line before 0.23 removes the config.yaml worker
|
|
25
|
-
# lifecycle; it keeps HTTP routes owned by the reconnecting worker.
|
|
26
|
-
#
|
|
27
|
-
# Override per-shell or via .env file:
|
|
28
|
-
# AGENTMEMORY_III_VERSION=0.22.1 docker compose up
|
|
29
|
-
image: iiidev/iii:${AGENTMEMORY_III_VERSION:-0.22.1}
|
|
30
|
-
user: "${AGENTMEMORY_DOCKER_UID:-65532}:${AGENTMEMORY_DOCKER_GID:-65532}"
|
|
31
|
-
depends_on:
|
|
32
|
-
iii-init:
|
|
33
|
-
condition: service_completed_successfully
|
|
34
|
-
command: ["--config", "/app/config.yaml", "--no-update-check"]
|
|
35
|
-
environment:
|
|
36
|
-
III_TELEMETRY_ENABLED: "${III_TELEMETRY_ENABLED:-false}"
|
|
37
|
-
III_REST_PORT: "${III_REST_PORT:-3111}"
|
|
38
|
-
III_STREAM_PORT: "${III_STREAM_PORT:-3112}"
|
|
39
|
-
III_VIEWER_PORT: "${III_VIEWER_PORT:-3113}"
|
|
40
|
-
III_ENGINE_PORT: "${III_ENGINE_PORT:-49134}"
|
|
41
|
-
AGENTMEMORY_REDIS_URL: "${AGENTMEMORY_REDIS_URL:-}"
|
|
42
|
-
AGENTMEMORY_STATE_SAVE_INTERVAL_MS: "${AGENTMEMORY_STATE_SAVE_INTERVAL_MS:-2000}"
|
|
43
|
-
MALLOC_ARENA_MAX: "${MALLOC_ARENA_MAX:-2}"
|
|
44
|
-
ulimits:
|
|
45
|
-
nofile:
|
|
46
|
-
soft: 10240
|
|
47
|
-
hard: 10240
|
|
48
|
-
ports:
|
|
49
|
-
- "127.0.0.1:${III_ENGINE_PORT:-49134}:${III_ENGINE_PORT:-49134}"
|
|
50
|
-
- "127.0.0.1:${III_REST_PORT:-3111}:${III_REST_PORT:-3111}"
|
|
51
|
-
- "127.0.0.1:${III_STREAM_PORT:-3112}:${III_STREAM_PORT:-3112}"
|
|
52
|
-
- "127.0.0.1:${AGENTMEMORY_METRICS_PORT:-9464}:9464"
|
|
53
|
-
volumes:
|
|
54
|
-
- "${AGENTMEMORY_DATA_DIR:-iii-data}:/data"
|
|
55
|
-
- ./iii-config.docker.yaml:/app/config.yaml:ro
|
|
56
|
-
# The engine persists each builtin worker's seeded config block under
|
|
57
|
-
# config/ next to its config file (/app/config in the image) on first
|
|
58
|
-
# boot and treats that copy as the source of truth afterwards. Keeping
|
|
59
|
-
# it on a tmpfs means every container start re-seeds from config.yaml
|
|
60
|
-
# and the III_* env vars, the same behavior the native CLI path has.
|
|
61
|
-
- type: tmpfs
|
|
62
|
-
target: /app/config
|
|
63
|
-
tmpfs:
|
|
64
|
-
mode: 01777
|
|
65
|
-
restart: unless-stopped
|
|
66
|
-
logging:
|
|
67
|
-
driver: json-file
|
|
68
|
-
options:
|
|
69
|
-
max-size: "10m"
|
|
70
|
-
max-file: "3"
|
|
71
|
-
|
|
72
|
-
volumes:
|
|
73
|
-
iii-data:
|
package/iii-config.docker.yaml
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
workers:
|
|
2
|
-
- name: iii-http
|
|
3
|
-
config:
|
|
4
|
-
port: ${III_REST_PORT:3111}
|
|
5
|
-
host: 0.0.0.0
|
|
6
|
-
default_timeout: 180000
|
|
7
|
-
cors:
|
|
8
|
-
allowed_origins: ["http://localhost:${III_REST_PORT:3111}", "http://localhost:${III_VIEWER_PORT:3113}", "http://127.0.0.1:${III_REST_PORT:3111}", "http://127.0.0.1:${III_VIEWER_PORT:3113}"]
|
|
9
|
-
allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
|
|
10
|
-
- name: iii-worker-manager
|
|
11
|
-
config:
|
|
12
|
-
port: ${III_ENGINE_PORT:49134}
|
|
13
|
-
host: 0.0.0.0
|
|
14
|
-
- name: iii-state
|
|
15
|
-
config:
|
|
16
|
-
adapter:
|
|
17
|
-
name: kv
|
|
18
|
-
config:
|
|
19
|
-
store_method: file_based
|
|
20
|
-
save_interval_ms: ${AGENTMEMORY_STATE_SAVE_INTERVAL_MS:2000}
|
|
21
|
-
file_path: /data/state_store.db
|
|
22
|
-
- name: iii-queue
|
|
23
|
-
config:
|
|
24
|
-
adapter:
|
|
25
|
-
name: builtin
|
|
26
|
-
- name: iii-pubsub
|
|
27
|
-
config:
|
|
28
|
-
adapter:
|
|
29
|
-
name: local
|
|
30
|
-
- name: iii-cron
|
|
31
|
-
config:
|
|
32
|
-
adapter:
|
|
33
|
-
name: kv
|
|
34
|
-
- name: iii-stream
|
|
35
|
-
config:
|
|
36
|
-
port: ${III_STREAM_PORT:3112}
|
|
37
|
-
host: 0.0.0.0
|
|
38
|
-
adapter:
|
|
39
|
-
name: kv
|
|
40
|
-
config:
|
|
41
|
-
store_method: file_based
|
|
42
|
-
save_interval_ms: ${AGENTMEMORY_STATE_SAVE_INTERVAL_MS:2000}
|
|
43
|
-
file_path: /data/stream_store
|
|
44
|
-
- name: iii-observability
|
|
45
|
-
config:
|
|
46
|
-
enabled: true
|
|
47
|
-
service_name: agentmemory
|
|
48
|
-
exporter: memory
|
|
49
|
-
# See iii-config.yaml for the rationale on 0.1 / console-off.
|
|
50
|
-
sampling_ratio: 0.1
|
|
51
|
-
metrics_enabled: true
|
|
52
|
-
logs_enabled: true
|
|
53
|
-
logs_console_output: false
|