@agentmemory/agentmemory 0.9.30 → 0.9.31
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 +39 -33
- package/AGENTS.md +8 -8
- package/README.md +173 -558
- package/dist/.env.example +39 -33
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +1741 -966
- package/dist/cli.mjs.map +1 -1
- package/dist/compression-recovery-CnhLQC6N.mjs +5912 -0
- package/dist/compression-recovery-CnhLQC6N.mjs.map +1 -0
- package/dist/{connect-B4_ca6BD.mjs → connect-BSLIAMpw.mjs} +874 -267
- package/dist/connect-BSLIAMpw.mjs.map +1 -0
- package/dist/hooks/_capture.d.mts +5 -2
- package/dist/hooks/_capture.d.mts.map +1 -1
- package/dist/hooks/_capture.mjs +55 -19
- 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 +25 -5
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +12 -4
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +12 -4
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +37 -10
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +25 -5
- 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 +47 -16
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +37 -10
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +74 -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 +18 -6
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +13 -5
- 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 +8539 -4203
- 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 +1145 -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-D9GwO0xp.mjs} +535 -434
- package/dist/secret-store-D9GwO0xp.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-DaMtDzt_.mjs} +4087 -3788
- package/dist/src-DaMtDzt_.mjs.map +1 -0
- package/dist/{standalone-DKCdrf1d.mjs → standalone-BlqshyZ5.mjs} +213 -56
- package/dist/standalone-BlqshyZ5.mjs.map +1 -0
- package/dist/standalone.d.mts +1 -1
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +626 -73
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +288 -140
- package/integrations/hermes/README.md +84 -0
- package/integrations/hermes/__init__.py +669 -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 +1450 -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 +33 -0
- package/integrations/omp/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-config/REFERENCE.md +90 -0
- package/integrations/omp/skills/agentmemory-config/SKILL.md +78 -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 +49 -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 +42 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-rest-api/REFERENCE.md +158 -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 +88 -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 +33 -0
- package/integrations/openclaw/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-config/REFERENCE.md +90 -0
- package/integrations/openclaw/skills/agentmemory-config/SKILL.md +78 -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 +49 -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 +42 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/REFERENCE.md +158 -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 +45 -51
- package/integrations/pi/dist/index.mjs +1379 -0
- package/integrations/pi/index.ts +138 -171
- package/integrations/pi/package.json +16 -6
- 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 +33 -0
- package/integrations/pi/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-config/REFERENCE.md +90 -0
- package/integrations/pi/skills/agentmemory-config/SKILL.md +78 -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 +49 -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 +42 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-rest-api/REFERENCE.md +158 -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 +32 -11
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +4 -3
- package/plugin/.devin-plugin/plugin.json +5 -3
- package/plugin/cursor/hooks.json +23 -8
- 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 -2
- package/plugin/scripts/_capture.d.mts.map +1 -1
- package/plugin/scripts/_capture.mjs +55 -19
- package/plugin/scripts/_capture.mjs.map +1 -1
- package/plugin/scripts/cursor/run-detached.d.mts +1 -0
- 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 +37 -6
- package/plugin/scripts/post-commit.mjs +25 -5
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +12 -4
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +12 -4
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +37 -10
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +25 -5
- 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 +47 -16
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +37 -10
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +74 -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 +18 -6
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +13 -5
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +21 -7
- package/plugin/skills/agentmemory-agents/REFERENCE.md +7 -6
- 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 +4 -4
- package/plugin/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-config/REFERENCE.md +12 -15
- package/plugin/skills/agentmemory-config/SKILL.md +7 -3
- package/plugin/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-hooks/SKILL.md +15 -5
- package/plugin/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +4 -4
- package/plugin/skills/agentmemory-mcp-tools/SKILL.md +6 -3
- package/plugin/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +9 -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/dist/viewer/index.html
CHANGED
|
@@ -1521,28 +1521,17 @@
|
|
|
1521
1521
|
var params = new URLSearchParams(window.location.search);
|
|
1522
1522
|
var paramPort = params.get('port');
|
|
1523
1523
|
var locPort = window.location.port;
|
|
1524
|
-
var
|
|
1525
|
-
var REST, WS_URL, WS_DIRECT_URL, wsPort;
|
|
1524
|
+
var REST;
|
|
1526
1525
|
if (paramPort) {
|
|
1527
1526
|
var resolvedPort = parseInt(paramPort) === 3111 ? '3113' : paramPort;
|
|
1528
1527
|
REST = window.location.protocol + '//' + window.location.hostname + ':' + resolvedPort;
|
|
1529
|
-
wsPort = params.get('wsPort') || String(parseInt(resolvedPort) - 1);
|
|
1530
|
-
WS_URL = wsProto + '//' + window.location.hostname + ':' + wsPort;
|
|
1531
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
1532
1528
|
} else if (locPort) {
|
|
1533
1529
|
var resolvedPort = parseInt(locPort) === 3111 ? '3113' : locPort;
|
|
1534
1530
|
REST = window.location.protocol + '//' + window.location.hostname + ':' + resolvedPort;
|
|
1535
|
-
wsPort = params.get('wsPort') || String(parseInt(resolvedPort) - 1);
|
|
1536
|
-
WS_URL = wsProto + '//' + window.location.hostname + ':' + wsPort;
|
|
1537
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
1538
1531
|
} else {
|
|
1539
1532
|
REST = window.location.origin;
|
|
1540
|
-
wsPort = params.get('wsPort');
|
|
1541
|
-
WS_URL = wsPort
|
|
1542
|
-
? wsProto + '//' + window.location.hostname + ':' + wsPort
|
|
1543
|
-
: wsProto + '//' + window.location.host;
|
|
1544
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
1545
1533
|
}
|
|
1534
|
+
var LIVE_EVENTS_URL = REST + '/agentmemory/viewer/events';
|
|
1546
1535
|
|
|
1547
1536
|
var dateEl = document.getElementById('dateline');
|
|
1548
1537
|
if (dateEl) dateEl.textContent = new Date().toLocaleDateString('en-US', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' });
|
|
@@ -1654,9 +1643,9 @@
|
|
|
1654
1643
|
eventLoop: { term: 'Event loop delay', text: 'How far behind the worker is in handling work. Under 20 ms is healthy; a large value means it is busy or blocked.' },
|
|
1655
1644
|
uptime: { term: 'Uptime', text: 'How long the agentmemory worker has been running since it last started.' },
|
|
1656
1645
|
health: { term: 'Health status', text: 'Healthy means everything is normal. Degraded means something needs attention but memory still works. Critical means a core part is failing.' },
|
|
1657
|
-
stateBackend: { term: 'State store', text: 'Where the
|
|
1658
|
-
engineConnection: { term: 'Engine connection', text: 'Whether the agentmemory worker is connected to the iii engine that
|
|
1659
|
-
live: { term: 'Live updates', text: 'The viewer keeps one
|
|
1646
|
+
stateBackend: { term: 'State store', text: 'Where the state worker keeps every record: file (local files on this machine, the default) or redis (a Redis server set by AGENTMEMORY_STATE_BACKEND and AGENTMEMORY_REDIS_URL). ok means a test write and read just succeeded; the number is how long it took.' },
|
|
1647
|
+
engineConnection: { term: 'Engine connection', text: 'Whether the agentmemory worker is connected to the iii engine that routes calls between workers.' },
|
|
1648
|
+
live: { term: 'Live updates', text: 'The viewer keeps one SSE connection open and updates every page the moment data changes. Nothing is refreshed on a timer.' },
|
|
1660
1649
|
flags: { term: 'Feature flags', text: 'Optional features that are on or off in this install. Off features leave some pages empty; each one lists the setting that turns it on.' },
|
|
1661
1650
|
audit: { term: 'Audit log', text: 'A record of every change agentmemory made to stored data: saves, deletes, imports, consolidation runs. Use it to see who changed what and when.' },
|
|
1662
1651
|
workers: { term: 'Workers', text: 'Processes connected to the iii engine. agentmemory runs as one worker.' },
|
|
@@ -1670,20 +1659,19 @@
|
|
|
1670
1659
|
var state = {
|
|
1671
1660
|
activeTab: 'dashboard',
|
|
1672
1661
|
dashboard: { loaded: false },
|
|
1673
|
-
graph: { loaded: false, loading: false, dirty: false, nodeMap: {}, edgeMap: {}, degrees: {}, rev: 0, localDegree: null, localDegreeRev: -1, stats: null, hidden: {}, search: '', searchOpen: false, searchIndex: 0, selectedId: null, detail: null, queryError: null, disabledInfo: null, warning: '', truncated: false, totalNodes: 0, totalEdges: 0, requestSeq: 0, fetches: 0, patches: 0, lastPatchAt: 0, fresh: {}, simStale: false, rebuildResult: '' },
|
|
1662
|
+
graph: { loaded: false, loading: false, dirty: false, nodeMap: {}, edgeMap: {}, degrees: {}, rev: 0, localDegree: null, localDegreeRev: -1, stats: null, hidden: {}, search: '', searchOpen: false, searchIndex: 0, selectedId: null, detail: null, queryError: null, disabledInfo: null, warning: '', truncated: false, totalNodes: 0, totalEdges: 0, requestSeq: 0, searchRequestSeq: 0, resetSeq: 0, generation: undefined, fetches: 0, patches: 0, lastPatchAt: 0, fresh: {}, simStale: false, rebuildResult: '' },
|
|
1674
1663
|
memories: { search: '', typeFilter: '', projectFilter: '', agentFilter: '', selectedId: null, nextCursor: null, loadingMore: false, searchIds: null, searchMode: '', searching: false, query: null, facets: null, checked: {}, editing: null, saving: false, pendingId: null, fetches: {}, diffId: null, error: '' },
|
|
1675
1664
|
sessions: { selectedId: null, autoSelected: false, closed: false, nextCursor: null, loadingMore: false, filters: { q: '', project: '', agent: '', status: '' }, query: null, facets: null, detail: null, pendingObs: null, notice: null, summarizing: '' },
|
|
1676
1665
|
audit: { opFilter: '', selectedIdx: null, from: '', to: '', q: '', query: null, loadingMore: false, exhausted: {}, fresh: {} },
|
|
1677
1666
|
activity: { loaded: false, observations: [], sessionCount: 0, typeFilter: '', fileFilter: '', day: '' },
|
|
1678
1667
|
lessons: { search: '', selectedId: null, projectFilter: '', notice: null, busy: '' },
|
|
1679
|
-
actions: { frontier: [], statusFilter: '', search: '', selectedId: null, notice: null, busy: '' },
|
|
1668
|
+
actions: { frontier: [], statusFilter: '', search: '', selectedId: null, notice: null, busy: '', detailLoading: '', detailAttemptedId: '', detailRequestFailedId: '', loadError: false },
|
|
1680
1669
|
crystals: { search: '', selectedId: null },
|
|
1681
1670
|
profile: { loaded: false, selectedProject: '', data: null, dataProject: '', userPicked: false, notice: null },
|
|
1682
1671
|
health: { error: null, checking: false, consolidating: false, reveal: '' },
|
|
1683
1672
|
replay: { loaded: false, selectedId: '', timeline: null, cursor: 0, playing: false, speed: 1, timer: null, startAt: 0, offsetAt: 0, loadingTimeline: false, loadError: '', importPath: '', importing: false, importOpen: false, importStatus: null },
|
|
1684
1673
|
flagsOpen: false,
|
|
1685
1674
|
freshRows: {},
|
|
1686
|
-
ws: null
|
|
1687
1675
|
};
|
|
1688
1676
|
|
|
1689
1677
|
var store = {
|
|
@@ -1714,7 +1702,7 @@
|
|
|
1714
1702
|
memory: { path: 'memories?latest=true&limit=100&facets=true', key: 'memories' },
|
|
1715
1703
|
session: { path: 'sessions?limit=100&facets=true', key: 'sessions' },
|
|
1716
1704
|
lesson: { path: 'lessons', key: 'lessons' },
|
|
1717
|
-
action: { path: 'actions', key: 'actions' },
|
|
1705
|
+
action: { path: 'actions', key: 'actions', allPages: true },
|
|
1718
1706
|
crystal: { path: 'crystals', key: 'crystals' },
|
|
1719
1707
|
semantic: { path: 'semantic', key: 'facts', fallbackKey: 'semantic' },
|
|
1720
1708
|
procedural: { path: 'procedural', key: 'procedures', fallbackKey: 'procedural' },
|
|
@@ -2314,6 +2302,20 @@
|
|
|
2314
2302
|
store.entities[kind] = bucket;
|
|
2315
2303
|
}
|
|
2316
2304
|
|
|
2305
|
+
async function loadAllPages(spec, apiGet) {
|
|
2306
|
+
var rows = [];
|
|
2307
|
+
var cursor = null;
|
|
2308
|
+
var result;
|
|
2309
|
+
do {
|
|
2310
|
+
var path = spec.path + '?limit=500' + (cursor ? '&cursor=' + encodeURIComponent(cursor) : '');
|
|
2311
|
+
result = await apiGet(path);
|
|
2312
|
+
if (result === null) return null;
|
|
2313
|
+
rows.push.apply(rows, listOr([], result, spec.key, spec.fallbackKey));
|
|
2314
|
+
cursor = result.nextCursor || null;
|
|
2315
|
+
} while (cursor);
|
|
2316
|
+
return Object.assign({}, result, { [spec.key]: rows });
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2317
2319
|
async function ensureLoaded(kind) {
|
|
2318
2320
|
if (store.loaded[kind]) return;
|
|
2319
2321
|
if (store.loading[kind]) return store.loading[kind];
|
|
@@ -2323,8 +2325,16 @@
|
|
|
2323
2325
|
try {
|
|
2324
2326
|
await bootGate;
|
|
2325
2327
|
var seqAtStart = eventSeq;
|
|
2326
|
-
var result
|
|
2327
|
-
if (
|
|
2328
|
+
var result;
|
|
2329
|
+
if (spec.allPages) {
|
|
2330
|
+
result = await loadAllPages(spec, apiGet);
|
|
2331
|
+
} else {
|
|
2332
|
+
result = await apiGet(spec.path);
|
|
2333
|
+
}
|
|
2334
|
+
if (result === null) {
|
|
2335
|
+
if (kind === 'action') state.actions.loadError = true;
|
|
2336
|
+
return;
|
|
2337
|
+
}
|
|
2328
2338
|
replaceBucket(kind, listOr([], result, spec.key, spec.fallbackKey));
|
|
2329
2339
|
if (kind === 'memory') {
|
|
2330
2340
|
state.memories.nextCursor = result.nextCursor || null;
|
|
@@ -2343,6 +2353,9 @@
|
|
|
2343
2353
|
}
|
|
2344
2354
|
replayEventsSince(seqAtStart, kind);
|
|
2345
2355
|
store.loaded[kind] = true;
|
|
2356
|
+
if (kind === 'action') state.actions.loadError = false;
|
|
2357
|
+
} catch {
|
|
2358
|
+
if (kind === 'action') state.actions.loadError = true;
|
|
2346
2359
|
} finally {
|
|
2347
2360
|
store.loading[kind] = null;
|
|
2348
2361
|
}
|
|
@@ -2358,11 +2371,14 @@
|
|
|
2358
2371
|
});
|
|
2359
2372
|
}
|
|
2360
2373
|
|
|
2361
|
-
async function loadSnapshot() {
|
|
2374
|
+
async function loadSnapshot(retried) {
|
|
2375
|
+
var resetSeq = state.graph.resetSeq;
|
|
2362
2376
|
var snap = await apiGet('viewer/snapshot');
|
|
2377
|
+
if (resetSeq !== state.graph.resetSeq) return retried ? false : loadSnapshot(true);
|
|
2363
2378
|
if (!snap) return false;
|
|
2364
2379
|
var graphBefore = store.graph && store.graph.updatedAt;
|
|
2365
2380
|
var reconnect = !!store.snapshotAt;
|
|
2381
|
+
noteGraphGeneration(snap.graph);
|
|
2366
2382
|
applySnapshot(store, snap);
|
|
2367
2383
|
renderFlagsChip();
|
|
2368
2384
|
renderFlagsPanel();
|
|
@@ -2806,8 +2822,54 @@
|
|
|
2806
2822
|
return graphNodeList().filter(function(n) { return !deg[n.id]; }).length;
|
|
2807
2823
|
}
|
|
2808
2824
|
|
|
2825
|
+
function clearGraphView() {
|
|
2826
|
+
var g = state.graph;
|
|
2827
|
+
g.resetSeq++;
|
|
2828
|
+
g.requestSeq++;
|
|
2829
|
+
g.searchRequestSeq++;
|
|
2830
|
+
g.selectedId = null;
|
|
2831
|
+
g.detail = null;
|
|
2832
|
+
g.nodeMap = {};
|
|
2833
|
+
g.edgeMap = {};
|
|
2834
|
+
g.degrees = {};
|
|
2835
|
+
g.fresh = {};
|
|
2836
|
+
g.stats = null;
|
|
2837
|
+
g.totalNodes = 0;
|
|
2838
|
+
g.totalEdges = 0;
|
|
2839
|
+
g.truncated = false;
|
|
2840
|
+
g.loading = false;
|
|
2841
|
+
g.loaded = false;
|
|
2842
|
+
g.dirty = false;
|
|
2843
|
+
g.queryError = null;
|
|
2844
|
+
g.disabledInfo = null;
|
|
2845
|
+
g.warning = '';
|
|
2846
|
+
g.searchOpen = false;
|
|
2847
|
+
g.rev++;
|
|
2848
|
+
g.simStale = true;
|
|
2849
|
+
if (graphReloadTimer) clearTimeout(graphReloadTimer);
|
|
2850
|
+
graphReloadTimer = null;
|
|
2851
|
+
graphSim.hoverId = null;
|
|
2852
|
+
graphSim.drag = null;
|
|
2853
|
+
graphSim.nodes = [];
|
|
2854
|
+
graphSim.byId = {};
|
|
2855
|
+
graphSim.edges = [];
|
|
2856
|
+
graphSim.isolatedBox = null;
|
|
2857
|
+
setRouteEntity('graph', '');
|
|
2858
|
+
renderGraphDetail();
|
|
2859
|
+
requestGraphDraw();
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
function noteGraphGeneration(data) {
|
|
2863
|
+
if (!data) return;
|
|
2864
|
+
var g = state.graph;
|
|
2865
|
+
if (data.reset === true && data.source === 'items') store.graph = null;
|
|
2866
|
+
if (data.reset === true || ('generation' in data && g.generation !== undefined && g.generation !== data.generation)) clearGraphView();
|
|
2867
|
+
if ('generation' in data) g.generation = data.generation;
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2809
2870
|
function setGraphData(result) {
|
|
2810
2871
|
var g = state.graph;
|
|
2872
|
+
if (!(result.nodes || []).length && !result.truncated && !result.totalNodes && (g.selectedId || g.detail || Object.keys(g.nodeMap).length)) clearGraphView();
|
|
2811
2873
|
var nodeMap = {};
|
|
2812
2874
|
var edgeMap = {};
|
|
2813
2875
|
(result.nodes || []).forEach(function(n) { if (n && n.id) nodeMap[n.id] = n; });
|
|
@@ -2841,6 +2903,7 @@
|
|
|
2841
2903
|
g.loading = false;
|
|
2842
2904
|
if (result === null) {
|
|
2843
2905
|
var stats = await api('graph/stats', { readErrorBody: true });
|
|
2906
|
+
if (seq !== g.requestSeq) return;
|
|
2844
2907
|
if (stats && stats.error && stats.flag) {
|
|
2845
2908
|
g.disabledInfo = stats;
|
|
2846
2909
|
g.queryError = null;
|
|
@@ -2865,8 +2928,9 @@
|
|
|
2865
2928
|
|
|
2866
2929
|
function applyGraphDelta(delta) {
|
|
2867
2930
|
var g = state.graph;
|
|
2868
|
-
if (!g.loaded
|
|
2931
|
+
if (!delta || (!g.loaded && !delta.full)) return false;
|
|
2869
2932
|
if (delta.full) {
|
|
2933
|
+
if (!(delta.nodes || []).length && (g.selectedId || g.detail || Object.keys(g.nodeMap).length)) clearGraphView();
|
|
2870
2934
|
var keepNodes = {};
|
|
2871
2935
|
(delta.nodes || []).forEach(function(n) { keepNodes[n.id] = true; });
|
|
2872
2936
|
Object.keys(g.nodeMap).forEach(function(id) { if (!keepNodes[id] && id !== g.selectedId) delete g.nodeMap[id]; });
|
|
@@ -2893,13 +2957,14 @@
|
|
|
2893
2957
|
g.lastPatchAt = Date.now();
|
|
2894
2958
|
Object.keys(touched).forEach(function(id) { g.fresh[id] = Date.now(); });
|
|
2895
2959
|
if (g.selectedId && touched[g.selectedId] && g.detail && g.detail.id === g.selectedId) g.detail.stale = true;
|
|
2960
|
+
g.loaded = true;
|
|
2896
2961
|
return true;
|
|
2897
2962
|
}
|
|
2898
2963
|
|
|
2899
2964
|
function handleGraphChange(data) {
|
|
2900
2965
|
var g = state.graph;
|
|
2901
2966
|
if (!data) return;
|
|
2902
|
-
|
|
2967
|
+
noteGraphGeneration(data);
|
|
2903
2968
|
if (data.source === 'snapshot') {
|
|
2904
2969
|
if (data.delta && applyGraphDelta(data.delta)) {
|
|
2905
2970
|
if (graphSim.canvas && state.activeTab === 'graph') { syncGraphSim(false); requestGraphDraw(); setTimeout(requestGraphDraw, 4200); }
|
|
@@ -2925,10 +2990,10 @@
|
|
|
2925
2990
|
|
|
2926
2991
|
async function fetchGraphDetail(id) {
|
|
2927
2992
|
var g = state.graph;
|
|
2928
|
-
g.detail = { id: id, loading: true, data: null, error: '', stale: false };
|
|
2993
|
+
var detail = g.detail = { id: id, loading: true, data: null, error: '', stale: false };
|
|
2929
2994
|
renderGraphDetail();
|
|
2930
2995
|
var res = await api('graph/node?id=' + encodeURIComponent(id), { readErrorBody: true });
|
|
2931
|
-
if (
|
|
2996
|
+
if (g.detail !== detail) return;
|
|
2932
2997
|
if (!res || res.error) {
|
|
2933
2998
|
g.detail = { id: id, loading: false, data: null, error: res && res.error ? res.error : 'request failed', stale: false };
|
|
2934
2999
|
} else {
|
|
@@ -3671,7 +3736,7 @@
|
|
|
3671
3736
|
html += copyBtn('memory_graph_query { "startNodeId": ' + JSON.stringify(id) + ', "maxDepth": 1 }', 'MCP call').replace('>copy<', '>copy MCP call<');
|
|
3672
3737
|
html += copyBtn(curlGet('graph/node?id=' + encodeURIComponent(id)), 'curl command').replace('>copy<', '>copy curl<');
|
|
3673
3738
|
html += '</div>';
|
|
3674
|
-
if (d && d.stale) html += '<div class="mem-note">This node changed on the
|
|
3739
|
+
if (d && d.stale) html += '<div class="mem-note">This node changed on the SSE feed. <button type="button" class="linkish" data-action="graph-refresh-detail" data-node-id="' + esc(id) + '">Reload sources</button></div>';
|
|
3675
3740
|
|
|
3676
3741
|
var rels = graphDetailRelations(id);
|
|
3677
3742
|
var relTotal = data && typeof data.relationsTotal === 'number' ? Math.max(data.relationsTotal, rels.length) : rels.length;
|
|
@@ -3796,7 +3861,7 @@
|
|
|
3796
3861
|
html += '<div class="empty-step-label" style="margin-top:8px;">Query it from an agent:</div>' + cmdBlock('memory_graph_query { "query": "checkout" }');
|
|
3797
3862
|
html += '</div>';
|
|
3798
3863
|
if (g.rebuildResult) html += '<div class="mem-note">' + esc(g.rebuildResult) + '</div>';
|
|
3799
|
-
html += '<div class="go-live">' + (g.patches ? 'Patched ' + fmtNum(g.patches) + ' time' + (g.patches === 1 ? '' : 's') + ' from the
|
|
3864
|
+
html += '<div class="go-live">' + (g.patches ? 'Patched ' + fmtNum(g.patches) + ' time' + (g.patches === 1 ? '' : 's') + ' from the SSE feed, last ' + relTime(new Date(g.lastPatchAt).toISOString()) + '.' : 'Updates arrive on the SSE feed; nothing refreshes on a timer.') + ' ' + help('live') + '</div>';
|
|
3800
3865
|
html += '</div>';
|
|
3801
3866
|
setViewHtml(host, html);
|
|
3802
3867
|
}
|
|
@@ -4021,9 +4086,11 @@
|
|
|
4021
4086
|
|
|
4022
4087
|
async function searchGraphRemote(q) {
|
|
4023
4088
|
var g = state.graph;
|
|
4089
|
+
var seq = ++g.searchRequestSeq;
|
|
4024
4090
|
var box = document.getElementById('graph-search-results');
|
|
4025
4091
|
if (box) { box.hidden = false; box.innerHTML = '<div class="gs-empty">Searching all nodes…</div>'; }
|
|
4026
4092
|
var res = await apiPost('graph/query', { query: q, limit: 50 });
|
|
4093
|
+
if (seq !== g.searchRequestSeq) return;
|
|
4027
4094
|
if (!res) {
|
|
4028
4095
|
if (box) box.innerHTML = '<div class="gs-empty">The server search failed.</div>';
|
|
4029
4096
|
return;
|
|
@@ -4097,7 +4164,7 @@
|
|
|
4097
4164
|
try {
|
|
4098
4165
|
var result = await apiPost('graph/build', {});
|
|
4099
4166
|
g.rebuildResult = result && result.success
|
|
4100
|
-
? 'Rebuilt from ' + (result.sessions || 0) + ' sessions: ' + (result.nodes || 0) + ' nodes and ' + (result.edges || 0) + ' relations extracted. New ones arrive on the
|
|
4167
|
+
? 'Rebuilt from ' + (result.sessions || 0) + ' sessions: ' + (result.nodes || 0) + ' nodes and ' + (result.edges || 0) + ' relations extracted. New ones arrive on the SSE feed.'
|
|
4101
4168
|
: 'The rebuild failed. Check the server log.';
|
|
4102
4169
|
} finally {
|
|
4103
4170
|
graphRebuilding = false;
|
|
@@ -4505,7 +4572,7 @@
|
|
|
4505
4572
|
var mem = store.entities.memory[id];
|
|
4506
4573
|
if (!mem) {
|
|
4507
4574
|
if (m.pendingId === id) {
|
|
4508
|
-
setViewHtml(panel, '<div class="detail-panel mem-detail"><div class="mem-detail-head"><span>Saving the new version</span>' + memoryCloseBtn() + '</div><div class="mem-note">Saved. Waiting for the new version to arrive on the
|
|
4575
|
+
setViewHtml(panel, '<div class="detail-panel mem-detail"><div class="mem-detail-head"><span>Saving the new version</span>' + memoryCloseBtn() + '</div><div class="mem-note">Saved. Waiting for the new version to arrive on the SSE feed…</div>' + skeleton(4) + '</div>');
|
|
4509
4576
|
return;
|
|
4510
4577
|
}
|
|
4511
4578
|
if (!m.fetches[id]) fetchMemoryVersion(id);
|
|
@@ -6404,7 +6471,7 @@
|
|
|
6404
6471
|
var res = await apiPost('lessons/strengthen', { lessonId: id });
|
|
6405
6472
|
l.busy = '';
|
|
6406
6473
|
l.notice = res && res.success !== false
|
|
6407
|
-
? { id: id, html: 'Recorded one more use. Confidence and uses update here from the
|
|
6474
|
+
? { id: id, html: 'Recorded one more use. Confidence and uses update here from the SSE feed.' }
|
|
6408
6475
|
: { id: id, err: true, html: 'Strengthen failed' + (res && res.error ? ': ' + esc(res.error) : '. Check that agentmemory is running.') };
|
|
6409
6476
|
renderLessons();
|
|
6410
6477
|
}
|
|
@@ -6497,12 +6564,15 @@
|
|
|
6497
6564
|
function renderActions() {
|
|
6498
6565
|
var el = document.getElementById('view-actions');
|
|
6499
6566
|
var a = state.actions;
|
|
6500
|
-
|
|
6567
|
+
var all = entityList('action');
|
|
6568
|
+
if (!store.loaded.action && !all.length) {
|
|
6501
6569
|
listDetailShell(el, 'actions', '');
|
|
6502
|
-
setViewHtml(document.getElementById('actions-list'),
|
|
6570
|
+
setViewHtml(document.getElementById('actions-list'), a.loadError
|
|
6571
|
+
? '<div class="empty-state compact"><div class="empty-title">Could not load actions</div><div class="empty-what">Check that agentmemory is running, then try again.</div><button type="button" class="btn" data-action="action-list-retry">Retry</button></div>'
|
|
6572
|
+
: skeleton(8));
|
|
6573
|
+
renderActionDetail({});
|
|
6503
6574
|
return;
|
|
6504
6575
|
}
|
|
6505
|
-
var all = entityList('action');
|
|
6506
6576
|
var rows = actionRows();
|
|
6507
6577
|
var frontierIds = {};
|
|
6508
6578
|
(a.frontier || []).forEach(function(f) {
|
|
@@ -6560,24 +6630,82 @@
|
|
|
6560
6630
|
html += '</tbody></table></div>';
|
|
6561
6631
|
if (all.length < 8) html += usageCard('action');
|
|
6562
6632
|
}
|
|
6633
|
+
if (a.loadError) {
|
|
6634
|
+
html = '<div class="inline-note"><strong>Could not refresh actions.</strong> Showing previously loaded actions. <button type="button" class="btn" data-action="action-list-retry">Retry</button></div>' + html;
|
|
6635
|
+
}
|
|
6563
6636
|
setViewHtml(document.getElementById('actions-list'), html);
|
|
6637
|
+
renderActionDetail(frontierIds);
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
function renderActionDetail(frontierIds) {
|
|
6641
|
+
var a = state.actions;
|
|
6564
6642
|
var detail = document.getElementById('actions-detail');
|
|
6565
6643
|
var sel = a.selectedId ? store.entities.action[a.selectedId] : null;
|
|
6566
6644
|
if (a.selectedId && !sel) {
|
|
6567
|
-
|
|
6645
|
+
ensureActionById(a.selectedId);
|
|
6646
|
+
var loadingAction = a.detailLoading === a.selectedId;
|
|
6647
|
+
var actionBody = loadingAction ? '<div class="empty-state compact"><div class="empty-title">Loading action…</div></div>' : a.detailRequestFailedId === a.selectedId
|
|
6648
|
+
? '<div class="empty-state compact"><div class="empty-title">Could not load action</div><div class="empty-what">Check that agentmemory is running, then try again.</div><button type="button" class="btn" data-action="action-retry">Retry</button></div>'
|
|
6649
|
+
: emptyState({
|
|
6568
6650
|
compact: true,
|
|
6569
6651
|
icon: '🔍',
|
|
6570
6652
|
title: 'Action not found',
|
|
6571
6653
|
what: 'Action links anywhere in the viewer open this panel by id.',
|
|
6572
6654
|
why: 'No action has the id <code>' + esc(a.selectedId) + '</code>. It was removed, or the link comes from another install.',
|
|
6573
6655
|
steps: [{ label: 'Check from a terminal:', cmd: curlGet('actions/get?actionId=' + encodeURIComponent(a.selectedId)) }]
|
|
6574
|
-
})
|
|
6656
|
+
});
|
|
6657
|
+
setViewHtml(detail, '<div id="action-detail" class="detail-panel mem-detail"><div class="mem-detail-head"><span>Action</span><button type="button" class="icon-btn icon-close" data-action="action-close" aria-label="Close action details">close</button></div>' + actionBody + '</div>');
|
|
6575
6658
|
} else {
|
|
6576
6659
|
setViewHtml(detail, sel ? actionDetailHtml(sel, !!frontierIds[sel.id]) : '');
|
|
6577
6660
|
}
|
|
6578
6661
|
document.getElementById('actions-layout').classList.toggle('has-detail', !!detail.firstElementChild);
|
|
6579
6662
|
}
|
|
6580
6663
|
|
|
6664
|
+
async function ensureActionById(id) {
|
|
6665
|
+
var a = state.actions;
|
|
6666
|
+
if (!id || store.entities.action[id] || a.detailLoading === id || a.detailAttemptedId === id) return;
|
|
6667
|
+
a.detailAttemptedId = id;
|
|
6668
|
+
a.detailLoading = id;
|
|
6669
|
+
try {
|
|
6670
|
+
var result = await apiGet('actions/get?actionId=' + encodeURIComponent(id));
|
|
6671
|
+
if (result && result.success && result.action && result.action.id) {
|
|
6672
|
+
store.entities.action[result.action.id] = result.action;
|
|
6673
|
+
a.detailRequestFailedId = '';
|
|
6674
|
+
renderActions();
|
|
6675
|
+
} else if (result === null) {
|
|
6676
|
+
a.detailRequestFailedId = id;
|
|
6677
|
+
}
|
|
6678
|
+
} catch (_) {
|
|
6679
|
+
a.detailRequestFailedId = id;
|
|
6680
|
+
} finally {
|
|
6681
|
+
if (a.detailLoading === id) {
|
|
6682
|
+
a.detailLoading = '';
|
|
6683
|
+
if (!store.entities.action[id]) renderActions();
|
|
6684
|
+
}
|
|
6685
|
+
}
|
|
6686
|
+
}
|
|
6687
|
+
|
|
6688
|
+
function retryActionById(id) {
|
|
6689
|
+
var a = state.actions;
|
|
6690
|
+
if (a.detailLoading === id) return;
|
|
6691
|
+
a.detailAttemptedId = '';
|
|
6692
|
+
a.detailRequestFailedId = '';
|
|
6693
|
+
return ensureActionById(id);
|
|
6694
|
+
}
|
|
6695
|
+
|
|
6696
|
+
async function retryActionList() {
|
|
6697
|
+
if (store.loading.action) return store.loading.action;
|
|
6698
|
+
state.actions.loadError = false;
|
|
6699
|
+
store.loaded.action = false;
|
|
6700
|
+
renderActions();
|
|
6701
|
+
await ensureLoaded('action');
|
|
6702
|
+
if (state.actions.selectedId && !store.entities.action[state.actions.selectedId]) {
|
|
6703
|
+
state.actions.detailAttemptedId = '';
|
|
6704
|
+
state.actions.detailRequestFailedId = '';
|
|
6705
|
+
}
|
|
6706
|
+
renderActions();
|
|
6707
|
+
}
|
|
6708
|
+
|
|
6581
6709
|
async function setActionStatus(id, status) {
|
|
6582
6710
|
var a = state.actions;
|
|
6583
6711
|
a.busy = id;
|
|
@@ -6585,7 +6713,7 @@
|
|
|
6585
6713
|
var res = await apiPost('actions/update', { actionId: id, status: status });
|
|
6586
6714
|
a.busy = '';
|
|
6587
6715
|
a.notice = res && res.success !== false
|
|
6588
|
-
? { id: id, html: 'Status set to <b>' + esc(status) + '</b>. Ready markers update from the
|
|
6716
|
+
? { id: id, html: 'Status set to <b>' + esc(status) + '</b>. Ready markers update from the SSE feed.' }
|
|
6589
6717
|
: { id: id, err: true, html: 'Update failed' + (res && res.error ? ': ' + esc(res.error) : '. Check that agentmemory is running.') };
|
|
6590
6718
|
renderActions();
|
|
6591
6719
|
}
|
|
@@ -6679,6 +6807,8 @@
|
|
|
6679
6807
|
return true;
|
|
6680
6808
|
}
|
|
6681
6809
|
if (action === 'action-close') { state.actions.selectedId = null; setRouteEntity('actions', ''); renderActions(); return true; }
|
|
6810
|
+
if (action === 'action-retry') { retryActionById(state.actions.selectedId); return true; }
|
|
6811
|
+
if (action === 'action-list-retry') { retryActionList(); return true; }
|
|
6682
6812
|
if (action === 'action-set-status') { setActionStatus(target.getAttribute('data-action-id'), target.getAttribute('data-status')); return true; }
|
|
6683
6813
|
if (action === 'action-clear-filters') { state.actions.search = ''; state.actions.statusFilter = ''; var ai = document.getElementById('actions-search'); if (ai) ai.value = ''; renderActions(); return true; }
|
|
6684
6814
|
if (action === 'activity-type' || action === 'activity-file' || action === 'activity-day' || action === 'activity-clear') { handleActivityAction(action, target); return true; }
|
|
@@ -7079,7 +7209,7 @@
|
|
|
7079
7209
|
}
|
|
7080
7210
|
if (store.lastHealthAt && Date.now() - store.lastHealthAt > HEALTH_STALE_MS) {
|
|
7081
7211
|
var secs = Math.round((Date.now() - store.lastHealthAt) / 1000);
|
|
7082
|
-
return '<div class="hstale" id="health-live-state"><strong>Stale: no health report for ' + secs + 's.</strong> Reports normally arrive every 30 seconds. The
|
|
7212
|
+
return '<div class="hstale" id="health-live-state"><strong>Stale: no health report for ' + secs + 's.</strong> Reports normally arrive every 30 seconds. The SSE feed is connected, but the worker may be busy or unable to publish a health report. The numbers below are from ' + esc(last) + '.' +
|
|
7083
7213
|
'<div style="margin-top:6px;">Fix: wait a minute; if it stays stale, press Re-check now for the full report, check the server log and restart agentmemory.</div></div>';
|
|
7084
7214
|
}
|
|
7085
7215
|
return '';
|
|
@@ -7105,7 +7235,7 @@
|
|
|
7105
7235
|
}
|
|
7106
7236
|
html += '<div class="verdict"><span class="verdict-badge ' + esc(level) + '">' + esc(badgeText) + '</span><div style="min-width:0;flex:1;">' +
|
|
7107
7237
|
'<div class="verdict-text">' + esc(text) + '</div>' +
|
|
7108
|
-
'<div class="verdict-meta">' + (r ? 'Report ' + relTime(r.checkedAt) + ' · ' : '') + 'updates every 30 s over
|
|
7238
|
+
'<div class="verdict-meta">' + (r ? 'Report ' + relTime(r.checkedAt) + ' · ' : '') + 'updates every 30 s over SSE, no refresh needed ' + help('live') + '</div></div></div>';
|
|
7109
7239
|
html += healthStaleHtml(r);
|
|
7110
7240
|
if (state.health.error) html += '<div class="mem-note err" style="margin-top:10px;">' + esc(state.health.error) + '</div>';
|
|
7111
7241
|
if (r && r.problems.length) {
|
|
@@ -7126,13 +7256,12 @@
|
|
|
7126
7256
|
var backend = r && r.service ? r.service.stateBackend : null;
|
|
7127
7257
|
var streamText = conn.state === 'live' ? 'live' : conn.state;
|
|
7128
7258
|
return '<div class="card"><div class="card-title">Engine and connection ' + help('engineConnection') + '</div>' +
|
|
7129
|
-
hrow('Engine connection', esc(snap.connectionState || 'unknown'), 'engineConnection', 'The worker\'s link to the iii engine, which
|
|
7130
|
-
((kv || backend) ? hrow('State store', esc((backend ? backend + (kv ? ' · ' : '') : '') + (kv ? kv.status + (kv.latencyMs !== undefined ? ' · ' + kv.latencyMs + ' ms' : '') + (kv.error ? ' · ' + kv.error : '') : '')), 'stateBackend', backend === 'redis' ? '
|
|
7131
|
-
hrow('Viewer
|
|
7132
|
-
(snap.streamRelay ? hrow('Redis event relay', esc(snap.streamRelay), 'live', snap.streamRelay === 'down' ? 'The engine stopped relaying live events through Redis, usually after Redis restarted. Data is still saved. Restart agentmemory to resume live updates.' : 'A test event sent through Redis every 30 seconds came back to the worker.') : '') +
|
|
7259
|
+
hrow('Engine connection', esc(snap.connectionState || 'unknown'), 'engineConnection', 'The worker\'s link to the iii engine, which routes calls between workers.') +
|
|
7260
|
+
((kv || backend) ? hrow('State store', esc((backend ? backend + (kv ? ' · ' : '') : '') + (kv ? kv.status + (kv.latencyMs !== undefined ? ' · ' + kv.latencyMs + ' ms' : '') + (kv.error ? ' · ' + kv.error : '') : '')), 'stateBackend', backend === 'redis' ? 'The state worker stores records in Redis (AGENTMEMORY_STATE_BACKEND=redis).' : 'The state worker stores records in local files (the default). Set AGENTMEMORY_STATE_BACKEND=redis to use Redis.') : '') +
|
|
7261
|
+
hrow('Viewer feed', esc(streamText), 'live', 'This page\'s own connection. Offline means the numbers here stop changing.') +
|
|
7133
7262
|
hrow('Uptime', esc(formatUptime(snap.uptimeSeconds)), 'uptime') +
|
|
7134
|
-
hrow('Version', esc('v' + (store.version || (r && r.service.version) || '?') + (r ? ' · engine ' + r.service.
|
|
7135
|
-
hrow('Ports', esc('REST ' + (ports.rest || '?') + ' ·
|
|
7263
|
+
hrow('Version', esc('v' + (store.version || (r && r.service.version) || '?') + (r ? ' · engine pinned ' + r.service.enginePinnedVersion : ''))) +
|
|
7264
|
+
hrow('Ports', esc('REST ' + (ports.rest || '?') + ' · viewer ' + (ports.viewer || 'off'))) +
|
|
7136
7265
|
'</div>';
|
|
7137
7266
|
}
|
|
7138
7267
|
|
|
@@ -7168,17 +7297,18 @@
|
|
|
7168
7297
|
'New and removed vectors are written here right away and replayed after a crash, so nothing is embedded twice. Each save empties it.');
|
|
7169
7298
|
}
|
|
7170
7299
|
}
|
|
7171
|
-
html += hrow('Graph', esc(fmtNum(c.graphNodes) + ' nodes · ' + fmtNum(c.graphEdges) + ' edges'), 'graph', store.graph && store.graph.updatedAt ? '
|
|
7300
|
+
html += hrow('Graph', esc(fmtNum(c.graphNodes) + ' nodes · ' + fmtNum(c.graphEdges) + ' edges'), 'graph', store.graph && store.graph.updatedAt ? 'Graph index updated ' + esc(timeAgo(store.graph.updatedAt)) + '.' : '');
|
|
7172
7301
|
if (r && r.graphCompaction) html += graphCompactionRowHtml(r.graphCompaction);
|
|
7173
7302
|
return html + '</div>';
|
|
7174
7303
|
}
|
|
7175
7304
|
|
|
7176
7305
|
function graphCompactionRowHtml(g) {
|
|
7177
7306
|
var where = g.phase === 'snapshot' || g.total === null || g.total === undefined ? (g.phase || 'nodes') : g.phase + ' ' + fmtNum(g.processed || 0) + ' of ' + fmtNum(g.total);
|
|
7178
|
-
var text = g.state === 'off' ? 'off' : g.state === 'pending' ? 'pending' : g.state === 'running' ? 'running, ' + where : g.state === 'failed' ? 'failed at ' + where : 'done';
|
|
7307
|
+
var text = g.state === 'off' ? 'off' : g.state === 'pending' ? 'pending' : g.state === 'deferred' ? 'deferred' : g.state === 'running' ? 'running, ' + where : g.state === 'failed' ? 'failed at ' + where : 'done';
|
|
7179
7308
|
var note = 'A one-time pass that trims each graph node and edge to its newest 32 source observations, so stores from older versions stop slowing graph search.';
|
|
7180
7309
|
if (g.state === 'done') note = fmtNum(g.trimmed || 0) + ' records trimmed, ' + fmtNum(g.idsRemoved || 0) + ' ids removed' + (g.completedAt ? ', finished ' + timeAgo(g.completedAt) : '') + '. It does not run again.';
|
|
7181
7310
|
else if (g.state === 'running') note += ' It runs in the background, resumes after a restart and stops by itself.';
|
|
7311
|
+
else if (g.state === 'deferred') note = 'Compaction is deferred because it reads complete legacy graph scopes. Run it only during explicit maintenance.';
|
|
7182
7312
|
else if (g.state === 'off') note = 'Turned off with AGENTMEMORY_GRAPH_COMPACT_ON_BOOT=false. Run it by hand if graph search is slow:';
|
|
7183
7313
|
else if (g.state === 'failed') note = esc(g.error || 'unknown error') + '. It resumes on the next start. To run it now:';
|
|
7184
7314
|
var cmd = g.state === 'off' || g.state === 'failed' ? cmdBlock(curlPost('graph/compact', {})) : '';
|
|
@@ -7401,7 +7531,7 @@
|
|
|
7401
7531
|
var snap = store.health || {};
|
|
7402
7532
|
var idx = store.indexes || {};
|
|
7403
7533
|
var c = store.counts || {};
|
|
7404
|
-
var html = '<div class="inline-note"><strong>Health</strong> ' + help('health') + ' is the live version of the <a class="empty-link" href="' + esc(REST) + '/agentmemory/status" target="_blank" rel="noopener">/agentmemory/status</a> page: the same checks and verdict, pushed over
|
|
7534
|
+
var html = '<div class="inline-note"><strong>Health</strong> ' + help('health') + ' is the live version of the <a class="empty-link" href="' + esc(REST) + '/agentmemory/status" target="_blank" rel="noopener">/agentmemory/status</a> page: the same checks and verdict, pushed over SSE every 30 seconds. Every problem says what to do. Scroll down for how consolidation works.</div>';
|
|
7405
7535
|
html += healthVerdictHtml(r);
|
|
7406
7536
|
html += '<div class="hgrid">' + engineCardHtml(r, snap) + indexCardHtml(r, idx, c) + captureCardHtml(r) + llmCardHtml(r) + flagsCardHtml(r) + processCardHtml(snap) + recordsCardHtml(c) + '</div>';
|
|
7407
7537
|
html += consolidationPanelHtml(store.consolidationStatus, c);
|
|
@@ -7611,14 +7741,12 @@
|
|
|
7611
7741
|
|
|
7612
7742
|
var wsReconnectTimer = null;
|
|
7613
7743
|
var wsRetries = 0;
|
|
7614
|
-
var directFailed = true;
|
|
7615
|
-
var directFailures = 0;
|
|
7616
7744
|
var wsHasConnected = false;
|
|
7617
7745
|
var wsOpenedAt = null;
|
|
7618
|
-
var DIRECT_FAILURE_THRESHOLD = 2;
|
|
7619
7746
|
var OFFLINE_AFTER_RETRIES = 3;
|
|
7620
7747
|
var HEALTH_STALE_MS = 90000;
|
|
7621
7748
|
var conn = { state: 'connecting', nextRetryAt: 0, lostAt: 0 };
|
|
7749
|
+
var liveAbortController = null;
|
|
7622
7750
|
|
|
7623
7751
|
function reconnectDelay(attempt) {
|
|
7624
7752
|
var n = Math.max(1, attempt || 1);
|
|
@@ -7704,90 +7832,110 @@
|
|
|
7704
7832
|
function reconnectNow() {
|
|
7705
7833
|
if (wsReconnectTimer) clearTimeout(wsReconnectTimer);
|
|
7706
7834
|
wsReconnectTimer = null;
|
|
7707
|
-
directFailures = 0;
|
|
7708
|
-
directFailed = true;
|
|
7709
7835
|
conn.nextRetryAt = 0;
|
|
7710
|
-
|
|
7711
|
-
|
|
7836
|
+
if (liveAbortController) {
|
|
7837
|
+
liveAbortController.abort();
|
|
7838
|
+
liveAbortController = null;
|
|
7839
|
+
}
|
|
7712
7840
|
connectWs();
|
|
7713
7841
|
}
|
|
7714
7842
|
|
|
7715
|
-
|
|
7843
|
+
function parseSseFrame(frame) {
|
|
7844
|
+
var id = '';
|
|
7845
|
+
var type = '';
|
|
7846
|
+
var data = [];
|
|
7847
|
+
frame.split(/\r?\n/).forEach(function(line) {
|
|
7848
|
+
if (!line || line.charAt(0) === ':') return;
|
|
7849
|
+
var colon = line.indexOf(':');
|
|
7850
|
+
var field = colon < 0 ? line : line.slice(0, colon);
|
|
7851
|
+
var value = colon < 0 ? '' : line.slice(colon + 1).replace(/^ /, '');
|
|
7852
|
+
if (field === 'id') id = value;
|
|
7853
|
+
else if (field === 'event') type = value;
|
|
7854
|
+
else if (field === 'data') data.push(value);
|
|
7855
|
+
});
|
|
7856
|
+
if (!type || !data.length) return null;
|
|
7857
|
+
try { return { id: id, type: type, data: JSON.parse(data.join('\n')) }; } catch (_) { return null; }
|
|
7858
|
+
}
|
|
7859
|
+
|
|
7860
|
+
function consumeSseChunk(buffer, chunk) {
|
|
7861
|
+
buffer += chunk;
|
|
7862
|
+
var frames = [];
|
|
7863
|
+
var match;
|
|
7864
|
+
while ((match = /\r?\n\r?\n/.exec(buffer))) {
|
|
7865
|
+
var frame = buffer.slice(0, match.index);
|
|
7866
|
+
buffer = buffer.slice(match.index + match[0].length);
|
|
7867
|
+
var parsed = parseSseFrame(frame);
|
|
7868
|
+
if (parsed) frames.push(parsed);
|
|
7869
|
+
}
|
|
7870
|
+
return { buffer: buffer, frames: frames };
|
|
7871
|
+
}
|
|
7716
7872
|
|
|
7717
|
-
function connectWs() {
|
|
7873
|
+
async function connectWs() {
|
|
7718
7874
|
wsReconnectTimer = null;
|
|
7719
7875
|
conn.nextRetryAt = 0;
|
|
7720
|
-
var
|
|
7721
|
-
|
|
7876
|
+
var controller = new AbortController();
|
|
7877
|
+
liveAbortController = controller;
|
|
7722
7878
|
try {
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
if (ws.readyState === WebSocket.CONNECTING) {
|
|
7731
|
-
try { ws.close(); } catch {}
|
|
7879
|
+
var headers = { 'Cache-Control': 'no-cache', Accept: 'text/event-stream' };
|
|
7880
|
+
var viewerToken = getViewerToken();
|
|
7881
|
+
if (viewerToken) headers.Authorization = 'Bearer ' + viewerToken;
|
|
7882
|
+
var response = await fetch(LIVE_EVENTS_URL, { headers: headers, signal: controller.signal });
|
|
7883
|
+
if (!response.ok || !response.body) {
|
|
7884
|
+
if (response.status === 401) showViewerAuthPrompt();
|
|
7885
|
+
throw new Error('SSE request failed: ' + response.status);
|
|
7732
7886
|
}
|
|
7733
|
-
|
|
7734
|
-
ws.onopen = function() {
|
|
7735
|
-
clearTimeout(connectTimer);
|
|
7736
|
-
if (state.ws !== ws) return;
|
|
7887
|
+
hideViewerAuthPrompt();
|
|
7737
7888
|
wsRetries = 0;
|
|
7738
|
-
if (!ws.__direct) {
|
|
7739
|
-
ws.send(JSON.stringify({
|
|
7740
|
-
type: 'join',
|
|
7741
|
-
data: {
|
|
7742
|
-
subscriptionId: 'viewer-' + Date.now(),
|
|
7743
|
-
streamName: 'mem-live',
|
|
7744
|
-
groupId: 'viewer'
|
|
7745
|
-
}
|
|
7746
|
-
}));
|
|
7747
|
-
}
|
|
7748
7889
|
var firstConnect = !wsHasConnected;
|
|
7749
7890
|
wsHasConnected = true;
|
|
7750
7891
|
wsOpenedAt = Date.now();
|
|
7751
7892
|
setConnection('live');
|
|
7752
7893
|
updateFooter();
|
|
7753
|
-
resyncAfterConnect(firstConnect);
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7894
|
+
await resyncAfterConnect(firstConnect);
|
|
7895
|
+
var reader = response.body.getReader();
|
|
7896
|
+
var decoder = new TextDecoder();
|
|
7897
|
+
var buffer = '';
|
|
7898
|
+
while (true) {
|
|
7899
|
+
var result = await reader.read();
|
|
7900
|
+
if (result.done) break;
|
|
7901
|
+
buffer += decoder.decode(result.value, { stream: true });
|
|
7902
|
+
var parsed = consumeSseChunk(buffer, '');
|
|
7903
|
+
buffer = parsed.buffer;
|
|
7904
|
+
parsed.frames.forEach(function(frame) {
|
|
7905
|
+
store.lastEventAt = Date.now();
|
|
7906
|
+
if (frame.type === 'raw_observation') {
|
|
7907
|
+
var obs = frame.data && frame.data.data && (frame.data.data.observation || frame.data.data);
|
|
7908
|
+
if (looksLikeObservation(obs)) routeWsMessage({ observation: obs, fresh: true });
|
|
7909
|
+
} else if (frame.type === 'compressed_observation') {
|
|
7910
|
+
var compressed = frame.data && frame.data.data && (frame.data.data.observation || frame.data.data);
|
|
7911
|
+
if (looksLikeObservation(compressed)) routeWsMessage({ observation: compressed, fresh: true });
|
|
7912
|
+
} else {
|
|
7913
|
+
handleLiveEvent(frame.type, frame.data && frame.data.data || {});
|
|
7914
|
+
}
|
|
7915
|
+
});
|
|
7760
7916
|
}
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
};
|
|
7771
|
-
ws.onclose = function() {
|
|
7772
|
-
clearTimeout(connectTimer);
|
|
7773
|
-
if (state.ws !== ws) return;
|
|
7774
|
-
wsOpenedAt = null;
|
|
7775
|
-
updateFooter();
|
|
7776
|
-
directFailures += 1;
|
|
7777
|
-
if (directFailures >= DIRECT_FAILURE_THRESHOLD) {
|
|
7778
|
-
directFailed = ws.__direct;
|
|
7779
|
-
directFailures = 0;
|
|
7917
|
+
if (!controller.signal.aborted) throw new Error('SSE stream ended');
|
|
7918
|
+
} catch (err) {
|
|
7919
|
+
if (!controller.signal.aborted) console.warn('[viewer] SSE connection failed:', err);
|
|
7920
|
+
} finally {
|
|
7921
|
+
if (liveAbortController === controller) liveAbortController = null;
|
|
7922
|
+
if (!controller.signal.aborted) {
|
|
7923
|
+
wsOpenedAt = null;
|
|
7924
|
+
updateFooter();
|
|
7925
|
+
scheduleReconnect();
|
|
7780
7926
|
}
|
|
7781
|
-
|
|
7782
|
-
};
|
|
7783
|
-
ws.onerror = function() {
|
|
7784
|
-
if (state.ws !== ws) return;
|
|
7785
|
-
try { ws.close(); } catch {}
|
|
7786
|
-
};
|
|
7787
|
-
state.ws = ws;
|
|
7927
|
+
}
|
|
7788
7928
|
}
|
|
7789
7929
|
|
|
7790
7930
|
var resyncing = null;
|
|
7931
|
+
function resetLoadedKindForReload(kind) {
|
|
7932
|
+
store.loaded[kind] = false;
|
|
7933
|
+
if (kind === 'action') {
|
|
7934
|
+
state.actions.detailAttemptedId = '';
|
|
7935
|
+
state.actions.detailRequestFailedId = '';
|
|
7936
|
+
}
|
|
7937
|
+
}
|
|
7938
|
+
|
|
7791
7939
|
async function resyncAfterConnect(firstConnect) {
|
|
7792
7940
|
openBootGate();
|
|
7793
7941
|
if (resyncing) return resyncing;
|
|
@@ -7795,9 +7943,10 @@
|
|
|
7795
7943
|
resyncing = (async function() {
|
|
7796
7944
|
try {
|
|
7797
7945
|
await loadSnapshot();
|
|
7946
|
+
await loadRecentObservations();
|
|
7798
7947
|
scheduleHealthStaleCheck();
|
|
7799
7948
|
if (!firstConnect || reloadKinds.length) {
|
|
7800
|
-
reloadKinds.forEach(
|
|
7949
|
+
reloadKinds.forEach(resetLoadedKindForReload);
|
|
7801
7950
|
await Promise.all(reloadKinds.map(ensureLoaded));
|
|
7802
7951
|
state.graph.dirty = state.graph.loaded;
|
|
7803
7952
|
state.activity.loaded = false;
|
|
@@ -7814,6 +7963,24 @@
|
|
|
7814
7963
|
}
|
|
7815
7964
|
|
|
7816
7965
|
var LIVE_BUFFER_MAX = 200;
|
|
7966
|
+
var ACTIVITY_SESSIONS = 10;
|
|
7967
|
+
async function loadRecentObservations() {
|
|
7968
|
+
var sessionResult = await apiGet('sessions?limit=' + ACTIVITY_SESSIONS);
|
|
7969
|
+
var sessions = sortByTimeDesc((sessionResult && sessionResult.sessions) || [], ['startedAt']).filter(function(x) { return sessionId(x); }).slice(0, ACTIVITY_SESSIONS);
|
|
7970
|
+
mergeSessionRows(sessions);
|
|
7971
|
+
var results = await Promise.all(sessions.map(function(x) {
|
|
7972
|
+
return apiGet('observations?sessionId=' + encodeURIComponent(sessionId(x)) + '&limit=100');
|
|
7973
|
+
}));
|
|
7974
|
+
var seen = {};
|
|
7975
|
+
results.forEach(function(result) {
|
|
7976
|
+
((result && result.observations) || []).slice(-LIVE_BUFFER_MAX).forEach(function(observation) {
|
|
7977
|
+
if (!observation || !observation.id || seen[observation.id]) return;
|
|
7978
|
+
seen[observation.id] = true;
|
|
7979
|
+
routeWsMessage({ observation: observation });
|
|
7980
|
+
});
|
|
7981
|
+
});
|
|
7982
|
+
}
|
|
7983
|
+
|
|
7817
7984
|
|
|
7818
7985
|
function looksLikeObservation(obj) {
|
|
7819
7986
|
return !!(obj && typeof obj === 'object' && obj.id && obj.timestamp);
|
|
@@ -8055,15 +8222,6 @@
|
|
|
8055
8222
|
if (looksLikeObservation(observation)) {
|
|
8056
8223
|
routeWsMessage({ observation: observation, fresh: true });
|
|
8057
8224
|
}
|
|
8058
|
-
} else if (evt.type === 'sync') {
|
|
8059
|
-
var items = Array.isArray(evt.data) ? evt.data.slice(-LIVE_BUFFER_MAX) : [];
|
|
8060
|
-
items.forEach(function(item) {
|
|
8061
|
-
var payload = item.data || item;
|
|
8062
|
-
observation = payload.observation || payload;
|
|
8063
|
-
if (looksLikeObservation(observation)) {
|
|
8064
|
-
routeWsMessage({ observation: observation });
|
|
8065
|
-
}
|
|
8066
|
-
});
|
|
8067
8225
|
}
|
|
8068
8226
|
}
|
|
8069
8227
|
|
|
@@ -8226,7 +8384,7 @@
|
|
|
8226
8384
|
var sync = document.getElementById('footer-sync');
|
|
8227
8385
|
if (sync) {
|
|
8228
8386
|
var syncText = store.snapshotAt ? 'full sync ' + new Date(store.snapshotAt).toLocaleTimeString() : 'waiting for first sync';
|
|
8229
|
-
if (store.snapshotAt) syncText += wsOpenedAt ? ',
|
|
8387
|
+
if (store.snapshotAt) syncText += wsOpenedAt ? ', live via SSE since ' + new Date(wsOpenedAt).toLocaleTimeString() : ', SSE reconnecting';
|
|
8230
8388
|
sync.textContent = syncText;
|
|
8231
8389
|
}
|
|
8232
8390
|
var fbEl = document.getElementById('footer-feedback');
|
|
@@ -8323,7 +8481,7 @@
|
|
|
8323
8481
|
var modal = document.getElementById('modal');
|
|
8324
8482
|
var overlay = document.getElementById('modal-overlay');
|
|
8325
8483
|
var html = '<h3>How to read this viewer</h3>';
|
|
8326
|
-
html += '<p style="margin-bottom:8px;">Everything on these pages updates live over one
|
|
8484
|
+
html += '<p style="margin-bottom:8px;">Everything on these pages updates live over one SSE connection; nothing refreshes on a timer. Click any <span class="help" style="cursor:default;">?</span> for a short explanation, or use the keys below.</p>';
|
|
8327
8485
|
html += '<div class="kbd-list">' +
|
|
8328
8486
|
'<div><kbd>/</kbd> focus search on this page</div>' +
|
|
8329
8487
|
'<div><kbd>?</kbd> open this help</div>' +
|
|
@@ -8894,16 +9052,7 @@
|
|
|
8894
9052
|
|
|
8895
9053
|
var bootRoute = parseRoute(window.location.hash);
|
|
8896
9054
|
switchTab(bootRoute.tab, { replaceRoute: true, skipRoute: !!bootRoute.obs && !bootRoute.redirect, id: bootRoute.id, obs: bootRoute.obs });
|
|
8897
|
-
(
|
|
8898
|
-
try {
|
|
8899
|
-
var live = await api('livez', { signal: AbortSignal.timeout(5000) });
|
|
8900
|
-
if (live && typeof live.streamsPort === 'number' && live.streamsPort > 0) {
|
|
8901
|
-
WS_URL = wsProto + '//' + window.location.hostname + ':' + live.streamsPort;
|
|
8902
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
8903
|
-
}
|
|
8904
|
-
} catch (_) {}
|
|
8905
|
-
connectWs();
|
|
8906
|
-
})();
|
|
9055
|
+
connectWs();
|
|
8907
9056
|
setTimeout(function() {
|
|
8908
9057
|
if (wsHasConnected) return;
|
|
8909
9058
|
openBootGate();
|
|
@@ -8913,8 +9062,7 @@
|
|
|
8913
9062
|
|
|
8914
9063
|
document.addEventListener('visibilitychange', function() {
|
|
8915
9064
|
if (document.visibilityState !== 'visible') return;
|
|
8916
|
-
|
|
8917
|
-
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) return;
|
|
9065
|
+
if (liveAbortController) return;
|
|
8918
9066
|
wsRetries = 0;
|
|
8919
9067
|
reconnectNow();
|
|
8920
9068
|
});
|