@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-submit.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/prompt-submit.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { basename } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git
|
|
1
|
+
{"version":3,"file":"prompt-submit.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/prompt-submit.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git repository basename → cwd basename.\nexport function resolveProject(cwd?: string): string {\n const explicit = process.env[\"AGENTMEMORY_PROJECT_NAME\"];\n if (explicit && explicit.trim()) return explicit.trim();\n const dir = cwd && cwd.trim() ? cwd : process.cwd();\n try {\n const [top, gitDir, commonDir] = execSync(\n \"git rev-parse --show-toplevel --git-dir --git-common-dir\",\n {\n cwd: dir,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 500,\n },\n )\n .toString()\n .trim()\n .split(/\\r?\\n/);\n if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));\n } catch {}\n return basename(dir);\n}\n\nfunction repositoryRoot(dir: string, top: string, gitDir?: string, commonDir?: string): string {\n if (!gitDir || !commonDir) return top;\n const physical = realpathSync(dir);\n const common = resolve(physical, commonDir);\n if (resolve(physical, gitDir) === common || basename(common) !== \".git\") return top;\n return dirname(common);\n}\n\nexport function hookCwd(data: Record<string, unknown> | null | undefined): string | undefined {\n if (!data || typeof data !== \"object\") return undefined;\n if (typeof data.cwd === \"string\" && data.cwd.trim()) return data.cwd;\n const roots = data.workspace_roots;\n if (Array.isArray(roots)) {\n for (const root of roots) {\n if (typeof root === \"string\" && root.trim()) return root;\n }\n }\n const projectDir =\n process.env[\"DEVIN_PROJECT_DIR\"] || process.env[\"CLAUDE_PROJECT_DIR\"];\n if (projectDir && projectDir.trim()) return projectDir;\n return undefined;\n}\n","#!/usr/bin/env node\nimport { resolveProject, hookCwd } from \"./_project.js\";\nimport { captureObservation, isDrainChild, runDrainChild, withEventId } from \"./_capture.js\";\n\nfunction isSdkChildContext(payload: unknown): boolean {\n if (process.env[\"AGENTMEMORY_SDK_CHILD\"] === \"1\") return true;\n if (!payload || typeof payload !== \"object\") return false;\n return (payload as { entrypoint?: unknown }).entrypoint === \"sdk-ts\";\n}\n\nconst OBSERVE_TIMEOUT_MS = 3000;\nconst EXIT_CAP_MS = 3500;\n\nasync function main() {\n if (isDrainChild()) return runDrainChild();\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(input);\n } catch {\n return;\n }\n\n if (!data || typeof data !== \"object\") return;\n if (isSdkChildContext(data)) return;\n\n const sessionId = ((data.session_id || data.sessionId || data.conversation_id) as string) || \"unknown\";\n\n const cwd = hookCwd(data) || process.cwd();\n\n void captureObservation(\n withEventId(\n {\n hookType: \"prompt_submit\",\n sessionId,\n project: resolveProject(cwd),\n cwd,\n timestamp: new Date().toISOString(),\n data: { prompt: data.prompt ?? data.userPrompt },\n },\n data,\n ),\n OBSERVE_TIMEOUT_MS,\n );\n setTimeout(() => process.exit(0), EXIT_CAP_MS).unref();\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":";;;;;;AAKA,SAAgB,eAAe,KAAsB;CACnD,MAAM,WAAW,QAAQ,IAAI;AAC7B,KAAI,YAAY,SAAS,MAAM,CAAE,QAAO,SAAS,MAAM;CACvD,MAAM,MAAM,OAAO,IAAI,MAAM,GAAG,MAAM,QAAQ,KAAK;AACnD,KAAI;EACF,MAAM,CAAC,KAAK,QAAQ,aAAa,SAC/B,4DACA;GACE,KAAK;GACL,OAAO;IAAC;IAAU;IAAQ;IAAS;GACnC,SAAS;GACV,CACF,CACE,UAAU,CACV,MAAM,CACN,MAAM,QAAQ;AACjB,MAAI,IAAK,QAAO,SAAS,eAAe,KAAK,KAAK,QAAQ,UAAU,CAAC;SAC/D;AACR,QAAO,SAAS,IAAI;;AAGtB,SAAS,eAAe,KAAa,KAAa,QAAiB,WAA4B;AAC7F,KAAI,CAAC,UAAU,CAAC,UAAW,QAAO;CAClC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,SAAS,QAAQ,UAAU,UAAU;AAC3C,KAAI,QAAQ,UAAU,OAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAQ,QAAO;AAChF,QAAO,QAAQ,OAAO;;AAGxB,SAAgB,QAAQ,MAAsE;AAC5F,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO,KAAA;AAC9C,KAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAE,QAAO,KAAK;CACjE,MAAM,QAAQ,KAAK;AACnB,KAAI,MAAM,QAAQ,MAAM;OACjB,MAAM,QAAQ,MACjB,KAAI,OAAO,SAAS,YAAY,KAAK,MAAM,CAAE,QAAO;;CAGxD,MAAM,aACJ,QAAQ,IAAI,wBAAwB,QAAQ,IAAI;AAClD,KAAI,cAAc,WAAW,MAAM,CAAE,QAAO;;;;ACzC9C,SAAS,kBAAkB,SAA2B;AACpD,KAAI,QAAQ,IAAI,6BAA6B,IAAK,QAAO;AACzD,KAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAQ,QAAqC,eAAe;;AAG9D,MAAM,qBAAqB;AAC3B,MAAM,cAAc;AAEpB,eAAe,OAAO;AACpB,KAAI,cAAc,CAAE,QAAO,eAAe;CAC1C,IAAI,QAAQ;AACZ,YAAW,MAAM,SAAS,QAAQ,MAChC,UAAS;CAGX,IAAI;AACJ,KAAI;AACF,SAAO,KAAK,MAAM,MAAM;SAClB;AACN;;AAGF,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,KAAI,kBAAkB,KAAK,CAAE;CAE7B,MAAM,YAAc,KAAK,cAAc,KAAK,aAAa,KAAK,mBAA+B;CAE7F,MAAM,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAK;AAErC,oBACH,YACE;EACE,UAAU;EACV;EACA,SAAS,eAAe,IAAI;EAC5B;EACA,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,MAAM,EAAE,QAAQ,KAAK,UAAU,KAAK,YAAY;EACjD,EACD,KACD,EACD,mBACD;AACD,kBAAiB,QAAQ,KAAK,EAAE,EAAE,YAAY,CAAC,OAAO;;AAGxD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
2
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
3
3
|
import { execSync } from "node:child_process";
|
|
4
|
-
import { basename } from "node:path";
|
|
4
|
+
import { basename, dirname, resolve } from "node:path";
|
|
5
5
|
import { REST_URL, authHeaders, captureObservation, isDrainChild, runDrainChild, withEventId } from "./_capture.mjs";
|
|
6
6
|
//#region src/hooks/_project.ts
|
|
7
7
|
function resolveProject(cwd) {
|
|
@@ -9,7 +9,7 @@ function resolveProject(cwd) {
|
|
|
9
9
|
if (explicit && explicit.trim()) return explicit.trim();
|
|
10
10
|
const dir = cwd && cwd.trim() ? cwd : process.cwd();
|
|
11
11
|
try {
|
|
12
|
-
const top = execSync("git rev-parse --show-toplevel", {
|
|
12
|
+
const [top, gitDir, commonDir] = execSync("git rev-parse --show-toplevel --git-dir --git-common-dir", {
|
|
13
13
|
cwd: dir,
|
|
14
14
|
stdio: [
|
|
15
15
|
"ignore",
|
|
@@ -17,11 +17,18 @@ function resolveProject(cwd) {
|
|
|
17
17
|
"ignore"
|
|
18
18
|
],
|
|
19
19
|
timeout: 500
|
|
20
|
-
}).toString().trim();
|
|
21
|
-
if (top) return basename(top);
|
|
20
|
+
}).toString().trim().split(/\r?\n/);
|
|
21
|
+
if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));
|
|
22
22
|
} catch {}
|
|
23
23
|
return basename(dir);
|
|
24
24
|
}
|
|
25
|
+
function repositoryRoot(dir, top, gitDir, commonDir) {
|
|
26
|
+
if (!gitDir || !commonDir) return top;
|
|
27
|
+
const physical = realpathSync(dir);
|
|
28
|
+
const common = resolve(physical, commonDir);
|
|
29
|
+
if (resolve(physical, gitDir) === common || basename(common) !== ".git") return top;
|
|
30
|
+
return dirname(common);
|
|
31
|
+
}
|
|
25
32
|
function hookCwd(data) {
|
|
26
33
|
if (!data || typeof data !== "object") return void 0;
|
|
27
34
|
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
@@ -39,6 +46,23 @@ function isSdkChildContext(payload) {
|
|
|
39
46
|
if (!payload || typeof payload !== "object") return false;
|
|
40
47
|
return payload.entrypoint === "sdk-ts";
|
|
41
48
|
}
|
|
49
|
+
const HARNESS_TEXT = /^(?:<(?:command-name|command-message|command-args|local-command-stdout|local-command-stderr|local-command-caveat|bash-input|bash-stdout|bash-stderr|task-notification|system-reminder|ci-monitor-event|cross-session-message|scheduled-task)(?=[\s>])|\[Request interrupted)/;
|
|
50
|
+
function isUserTurn(msg) {
|
|
51
|
+
if (msg.isSidechain || msg.isMeta || msg.isCompactSummary) return false;
|
|
52
|
+
return msg.role === "user" || msg.type === "user" || msg.message?.role === "user";
|
|
53
|
+
}
|
|
54
|
+
function promptText(raw) {
|
|
55
|
+
const m = raw.match(/<user_query>\n?([\s\S]*?)\n?<\/user_query>/);
|
|
56
|
+
const text = (m ? m[1] : raw).trim();
|
|
57
|
+
return HARNESS_TEXT.test(text) ? "" : text;
|
|
58
|
+
}
|
|
59
|
+
function turnTexts(content) {
|
|
60
|
+
if (typeof content === "string") return [content];
|
|
61
|
+
if (!Array.isArray(content)) return [];
|
|
62
|
+
const texts = [];
|
|
63
|
+
for (const block of content) if (block?.type === "text" && typeof block.text === "string") texts.push(block.text);
|
|
64
|
+
return texts;
|
|
65
|
+
}
|
|
42
66
|
function extractTranscriptPrompts(data) {
|
|
43
67
|
const path = data.transcript_path;
|
|
44
68
|
if (typeof path !== "string" || !path.endsWith(".jsonl")) return [];
|
|
@@ -61,16 +85,20 @@ function extractTranscriptPrompts(data) {
|
|
|
61
85
|
if (prompts.length >= 50) return prompts;
|
|
62
86
|
const match = msg.content.match(/<USER_REQUEST>\n?([\s\S]*?)\n?<\/USER_REQUEST>/);
|
|
63
87
|
const text = (match ? match[1] : msg.content).trim();
|
|
64
|
-
if (text) prompts.push(text.slice(0, 8e3));
|
|
88
|
+
if (text) prompts.push({ prompt: text.slice(0, 8e3) });
|
|
65
89
|
continue;
|
|
66
90
|
}
|
|
67
|
-
if (msg
|
|
68
|
-
|
|
91
|
+
if (!isUserTurn(msg)) continue;
|
|
92
|
+
const texts = turnTexts(msg.message?.content).map(promptText).filter(Boolean);
|
|
93
|
+
const promptId = typeof msg.promptId === "string" ? msg.promptId : void 0;
|
|
94
|
+
const timestamp = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
|
|
95
|
+
for (const text of promptId ? [texts.join("\n\n")].filter(Boolean) : texts) {
|
|
69
96
|
if (prompts.length >= 50) return prompts;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
97
|
+
prompts.push({
|
|
98
|
+
prompt: text.slice(0, 8e3),
|
|
99
|
+
promptId,
|
|
100
|
+
timestamp
|
|
101
|
+
});
|
|
74
102
|
}
|
|
75
103
|
}
|
|
76
104
|
return prompts;
|
|
@@ -93,17 +121,17 @@ async function main() {
|
|
|
93
121
|
const cwd = hookCwd(data) || process.cwd();
|
|
94
122
|
const project = resolveProject(cwd);
|
|
95
123
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
96
|
-
await Promise.allSettled(transcriptPrompts.map((prompt, index) => captureObservation(withEventId({
|
|
124
|
+
await Promise.allSettled(transcriptPrompts.map(({ prompt, promptId, timestamp: at }, index) => captureObservation(withEventId({
|
|
97
125
|
hookType: "prompt_submit",
|
|
98
126
|
sessionId,
|
|
99
127
|
project,
|
|
100
128
|
cwd,
|
|
101
|
-
timestamp,
|
|
129
|
+
timestamp: at ?? timestamp,
|
|
102
130
|
data: {
|
|
103
131
|
prompt,
|
|
104
132
|
backfill: true
|
|
105
133
|
}
|
|
106
|
-
}, {}, {
|
|
134
|
+
}, promptId ? { prompt_id: promptId } : {}, {
|
|
107
135
|
source: "transcript",
|
|
108
136
|
transcript: data.transcript_path,
|
|
109
137
|
index,
|
|
@@ -113,7 +141,10 @@ async function main() {
|
|
|
113
141
|
fetch(`${REST_URL}/agentmemory/session/end`, {
|
|
114
142
|
method: "POST",
|
|
115
143
|
headers: authHeaders(),
|
|
116
|
-
body: JSON.stringify({
|
|
144
|
+
body: JSON.stringify({
|
|
145
|
+
sessionId,
|
|
146
|
+
final: true
|
|
147
|
+
}),
|
|
117
148
|
signal: AbortSignal.timeout(3e4)
|
|
118
149
|
}).catch(() => {});
|
|
119
150
|
if (process.env["CLAUDE_MEMORY_BRIDGE"] === "true") fetch(`${REST_URL}/agentmemory/claude-bridge/sync`, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-end.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/session-end.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { basename } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git toplevel basename → cwd basename.\nexport function resolveProject(cwd?: string): string {\n const explicit = process.env[\"AGENTMEMORY_PROJECT_NAME\"];\n if (explicit && explicit.trim()) return explicit.trim();\n const dir = cwd && cwd.trim() ? cwd : process.cwd();\n try {\n const top = execSync(\"git rev-parse --show-toplevel\", {\n cwd: dir,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 500,\n })\n .toString()\n .trim();\n if (top) return basename(top);\n } catch {}\n return basename(dir);\n}\n\nexport function hookCwd(data: Record<string, unknown> | null | undefined): string | undefined {\n if (!data || typeof data !== \"object\") return undefined;\n if (typeof data.cwd === \"string\" && data.cwd.trim()) return data.cwd;\n const roots = data.workspace_roots;\n if (Array.isArray(roots)) {\n for (const root of roots) {\n if (typeof root === \"string\" && root.trim()) return root;\n }\n }\n const projectDir =\n process.env[\"DEVIN_PROJECT_DIR\"] || process.env[\"CLAUDE_PROJECT_DIR\"];\n if (projectDir && projectDir.trim()) return projectDir;\n return undefined;\n}\n","#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\nimport { resolveProject, hookCwd } from \"./_project.js\";\nimport { REST_URL, authHeaders, captureObservation, isDrainChild, runDrainChild, withEventId } from \"./_capture.js\";\n\nfunction isSdkChildContext(payload: unknown): boolean {\n if (process.env[\"AGENTMEMORY_SDK_CHILD\"] === \"1\") return true;\n if (!payload || typeof payload !== \"object\") return false;\n return (payload as { entrypoint?: unknown }).entrypoint === \"sdk-ts\";\n}\n\nfunction extractTranscriptPrompts(data: Record<string, unknown>): string[] {\n const path = data.transcript_path;\n if (typeof path !== \"string\" || !path.endsWith(\".jsonl\")) return [];\n let raw: string;\n try {\n raw = readFileSync(path, \"utf-8\");\n } catch {\n return [];\n }\n const prompts: string[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n let msg: {\n role?: string;\n type?: string;\n source?: string;\n content?: unknown;\n message?: { content?: Array<{ type?: string; text?: string }> };\n };\n try {\n msg = JSON.parse(line);\n } catch {\n continue;\n }\n if (msg.type === \"USER_INPUT\" && msg.source === \"USER_EXPLICIT\" && typeof msg.content === \"string\") {\n if (prompts.length >= 50) return prompts;\n const match = msg.content.match(/<USER_REQUEST>\\n?([\\s\\S]*?)\\n?<\\/USER_REQUEST>/);\n const text = (match ? match[1] : msg.content).trim();\n if (text) prompts.push(text.slice(0, 8000));\n continue;\n }\n if (msg.role !== \"user\") continue;\n for (const block of msg.message?.content ?? []) {\n if (prompts.length >= 50) return prompts;\n if (block.type !== \"text\" || typeof block.text !== \"string\") continue;\n const m = block.text.match(/<user_query>\\n?([\\s\\S]*?)\\n?<\\/user_query>/);\n const text = (m ? m[1] : block.text).trim();\n if (text) prompts.push(text.slice(0, 8000));\n }\n }\n return prompts;\n}\n\nasync function main() {\n if (isDrainChild()) return runDrainChild();\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(input);\n } catch {\n return;\n }\n\n if (!data || typeof data !== \"object\") return;\n if (isSdkChildContext(data)) return;\n\n const sessionId = ((data.session_id || data.sessionId || data.conversation_id) as string) || \"unknown\";\n\n const transcriptPrompts = extractTranscriptPrompts(data);\n if (transcriptPrompts.length > 0) {\n const cwd = hookCwd(data) || process.cwd();\n const project = resolveProject(cwd);\n const timestamp = new Date().toISOString();\n await Promise.allSettled(\n transcriptPrompts.map((prompt, index) =>\n captureObservation(\n withEventId(\n { hookType: \"prompt_submit\", sessionId, project, cwd, timestamp, data: { prompt, backfill: true } },\n {},\n { source: \"transcript\", transcript: data.transcript_path, index, prompt },\n { stable: true },\n ),\n 3000,\n ),\n ),\n );\n }\n\n fetch(`${REST_URL}/agentmemory/session/end`, {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({ sessionId }),\n signal: AbortSignal.timeout(30000),\n }).catch(() => {});\n\n if (process.env[\"CLAUDE_MEMORY_BRIDGE\"] === \"true\") {\n fetch(`${REST_URL}/agentmemory/claude-bridge/sync`, {\n method: \"POST\",\n headers: authHeaders(),\n signal: AbortSignal.timeout(30000),\n }).catch(() => {});\n }\n\n setTimeout(() => process.exit(0), 1500).unref();\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-end.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/session-end.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git repository basename → cwd basename.\nexport function resolveProject(cwd?: string): string {\n const explicit = process.env[\"AGENTMEMORY_PROJECT_NAME\"];\n if (explicit && explicit.trim()) return explicit.trim();\n const dir = cwd && cwd.trim() ? cwd : process.cwd();\n try {\n const [top, gitDir, commonDir] = execSync(\n \"git rev-parse --show-toplevel --git-dir --git-common-dir\",\n {\n cwd: dir,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 500,\n },\n )\n .toString()\n .trim()\n .split(/\\r?\\n/);\n if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));\n } catch {}\n return basename(dir);\n}\n\nfunction repositoryRoot(dir: string, top: string, gitDir?: string, commonDir?: string): string {\n if (!gitDir || !commonDir) return top;\n const physical = realpathSync(dir);\n const common = resolve(physical, commonDir);\n if (resolve(physical, gitDir) === common || basename(common) !== \".git\") return top;\n return dirname(common);\n}\n\nexport function hookCwd(data: Record<string, unknown> | null | undefined): string | undefined {\n if (!data || typeof data !== \"object\") return undefined;\n if (typeof data.cwd === \"string\" && data.cwd.trim()) return data.cwd;\n const roots = data.workspace_roots;\n if (Array.isArray(roots)) {\n for (const root of roots) {\n if (typeof root === \"string\" && root.trim()) return root;\n }\n }\n const projectDir =\n process.env[\"DEVIN_PROJECT_DIR\"] || process.env[\"CLAUDE_PROJECT_DIR\"];\n if (projectDir && projectDir.trim()) return projectDir;\n return undefined;\n}\n","#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\nimport { resolveProject, hookCwd } from \"./_project.js\";\nimport { REST_URL, authHeaders, captureObservation, isDrainChild, runDrainChild, withEventId } from \"./_capture.js\";\n\nfunction isSdkChildContext(payload: unknown): boolean {\n if (process.env[\"AGENTMEMORY_SDK_CHILD\"] === \"1\") return true;\n if (!payload || typeof payload !== \"object\") return false;\n return (payload as { entrypoint?: unknown }).entrypoint === \"sdk-ts\";\n}\n\ntype TranscriptBlock = { type?: string; text?: string };\ntype TranscriptLine = {\n role?: string;\n type?: string;\n source?: string;\n content?: unknown;\n isSidechain?: boolean;\n isMeta?: boolean;\n isCompactSummary?: boolean;\n promptId?: string;\n timestamp?: string;\n message?: { role?: string; content?: string | TranscriptBlock[] };\n};\n\ntype TranscriptPrompt = { prompt: string; promptId?: string; timestamp?: string };\n\nconst HARNESS_TEXT =\n /^(?:<(?:command-name|command-message|command-args|local-command-stdout|local-command-stderr|local-command-caveat|bash-input|bash-stdout|bash-stderr|task-notification|system-reminder|ci-monitor-event|cross-session-message|scheduled-task)(?=[\\s>])|\\[Request interrupted)/;\n\nfunction isUserTurn(msg: TranscriptLine): boolean {\n if (msg.isSidechain || msg.isMeta || msg.isCompactSummary) return false;\n return (\n msg.role === \"user\" || msg.type === \"user\" || msg.message?.role === \"user\"\n );\n}\n\nfunction promptText(raw: string): string {\n const m = raw.match(/<user_query>\\n?([\\s\\S]*?)\\n?<\\/user_query>/);\n const text = (m ? m[1] : raw).trim();\n return HARNESS_TEXT.test(text) ? \"\" : text;\n}\n\nfunction turnTexts(content: string | TranscriptBlock[] | undefined): string[] {\n if (typeof content === \"string\") return [content];\n if (!Array.isArray(content)) return [];\n const texts: string[] = [];\n for (const block of content) {\n if (block?.type === \"text\" && typeof block.text === \"string\") {\n texts.push(block.text);\n }\n }\n return texts;\n}\n\nfunction extractTranscriptPrompts(data: Record<string, unknown>): TranscriptPrompt[] {\n const path = data.transcript_path;\n if (typeof path !== \"string\" || !path.endsWith(\".jsonl\")) return [];\n let raw: string;\n try {\n raw = readFileSync(path, \"utf-8\");\n } catch {\n return [];\n }\n const prompts: TranscriptPrompt[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n let msg: TranscriptLine;\n try {\n msg = JSON.parse(line);\n } catch {\n continue;\n }\n if (msg.type === \"USER_INPUT\" && msg.source === \"USER_EXPLICIT\" && typeof msg.content === \"string\") {\n if (prompts.length >= 50) return prompts;\n const match = msg.content.match(/<USER_REQUEST>\\n?([\\s\\S]*?)\\n?<\\/USER_REQUEST>/);\n const text = (match ? match[1] : msg.content).trim();\n if (text) prompts.push({ prompt: text.slice(0, 8000) });\n continue;\n }\n if (!isUserTurn(msg)) continue;\n const texts = turnTexts(msg.message?.content).map(promptText).filter(Boolean);\n const promptId = typeof msg.promptId === \"string\" ? msg.promptId : undefined;\n const timestamp = typeof msg.timestamp === \"string\" ? msg.timestamp : undefined;\n for (const text of promptId ? [texts.join(\"\\n\\n\")].filter(Boolean) : texts) {\n if (prompts.length >= 50) return prompts;\n prompts.push({ prompt: text.slice(0, 8000), promptId, timestamp });\n }\n }\n return prompts;\n}\n\nasync function main() {\n if (isDrainChild()) return runDrainChild();\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(input);\n } catch {\n return;\n }\n\n if (!data || typeof data !== \"object\") return;\n if (isSdkChildContext(data)) return;\n\n const sessionId = ((data.session_id || data.sessionId || data.conversation_id) as string) || \"unknown\";\n\n const transcriptPrompts = extractTranscriptPrompts(data);\n if (transcriptPrompts.length > 0) {\n const cwd = hookCwd(data) || process.cwd();\n const project = resolveProject(cwd);\n const timestamp = new Date().toISOString();\n await Promise.allSettled(\n transcriptPrompts.map(({ prompt, promptId, timestamp: at }, index) =>\n captureObservation(\n withEventId(\n { hookType: \"prompt_submit\", sessionId, project, cwd, timestamp: at ?? timestamp, data: { prompt, backfill: true } },\n promptId ? { prompt_id: promptId } : {},\n { source: \"transcript\", transcript: data.transcript_path, index, prompt },\n { stable: true },\n ),\n 3000,\n ),\n ),\n );\n }\n\n fetch(`${REST_URL}/agentmemory/session/end`, {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({ sessionId, final: true }),\n signal: AbortSignal.timeout(30000),\n }).catch(() => {});\n\n if (process.env[\"CLAUDE_MEMORY_BRIDGE\"] === \"true\") {\n fetch(`${REST_URL}/agentmemory/claude-bridge/sync`, {\n method: \"POST\",\n headers: authHeaders(),\n signal: AbortSignal.timeout(30000),\n }).catch(() => {});\n }\n\n setTimeout(() => process.exit(0), 1500).unref();\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":";;;;;;AAKA,SAAgB,eAAe,KAAsB;CACnD,MAAM,WAAW,QAAQ,IAAI;AAC7B,KAAI,YAAY,SAAS,MAAM,CAAE,QAAO,SAAS,MAAM;CACvD,MAAM,MAAM,OAAO,IAAI,MAAM,GAAG,MAAM,QAAQ,KAAK;AACnD,KAAI;EACF,MAAM,CAAC,KAAK,QAAQ,aAAa,SAC/B,4DACA;GACE,KAAK;GACL,OAAO;IAAC;IAAU;IAAQ;IAAS;GACnC,SAAS;GACV,CACF,CACE,UAAU,CACV,MAAM,CACN,MAAM,QAAQ;AACjB,MAAI,IAAK,QAAO,SAAS,eAAe,KAAK,KAAK,QAAQ,UAAU,CAAC;SAC/D;AACR,QAAO,SAAS,IAAI;;AAGtB,SAAS,eAAe,KAAa,KAAa,QAAiB,WAA4B;AAC7F,KAAI,CAAC,UAAU,CAAC,UAAW,QAAO;CAClC,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,SAAS,QAAQ,UAAU,UAAU;AAC3C,KAAI,QAAQ,UAAU,OAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAQ,QAAO;AAChF,QAAO,QAAQ,OAAO;;AAGxB,SAAgB,QAAQ,MAAsE;AAC5F,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO,KAAA;AAC9C,KAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAE,QAAO,KAAK;CACjE,MAAM,QAAQ,KAAK;AACnB,KAAI,MAAM,QAAQ,MAAM;OACjB,MAAM,QAAQ,MACjB,KAAI,OAAO,SAAS,YAAY,KAAK,MAAM,CAAE,QAAO;;CAGxD,MAAM,aACJ,QAAQ,IAAI,wBAAwB,QAAQ,IAAI;AAClD,KAAI,cAAc,WAAW,MAAM,CAAE,QAAO;;;;ACxC9C,SAAS,kBAAkB,SAA2B;AACpD,KAAI,QAAQ,IAAI,6BAA6B,IAAK,QAAO;AACzD,KAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAQ,QAAqC,eAAe;;AAmB9D,MAAM,eACJ;AAEF,SAAS,WAAW,KAA8B;AAChD,KAAI,IAAI,eAAe,IAAI,UAAU,IAAI,iBAAkB,QAAO;AAClE,QACE,IAAI,SAAS,UAAU,IAAI,SAAS,UAAU,IAAI,SAAS,SAAS;;AAIxE,SAAS,WAAW,KAAqB;CACvC,MAAM,IAAI,IAAI,MAAM,6CAA6C;CACjE,MAAM,QAAQ,IAAI,EAAE,KAAK,KAAK,MAAM;AACpC,QAAO,aAAa,KAAK,KAAK,GAAG,KAAK;;AAGxC,SAAS,UAAU,SAA2D;AAC5E,KAAI,OAAO,YAAY,SAAU,QAAO,CAAC,QAAQ;AACjD,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO,EAAE;CACtC,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,SAAS,QAClB,KAAI,OAAO,SAAS,UAAU,OAAO,MAAM,SAAS,SAClD,OAAM,KAAK,MAAM,KAAK;AAG1B,QAAO;;AAGT,SAAS,yBAAyB,MAAmD;CACnF,MAAM,OAAO,KAAK;AAClB,KAAI,OAAO,SAAS,YAAY,CAAC,KAAK,SAAS,SAAS,CAAE,QAAO,EAAE;CACnE,IAAI;AACJ,KAAI;AACF,QAAM,aAAa,MAAM,QAAQ;SAC3B;AACN,SAAO,EAAE;;CAEX,MAAM,UAA8B,EAAE;AACtC,MAAK,MAAM,QAAQ,IAAI,MAAM,KAAK,EAAE;AAClC,MAAI,CAAC,KAAK,MAAM,CAAE;EAClB,IAAI;AACJ,MAAI;AACF,SAAM,KAAK,MAAM,KAAK;UAChB;AACN;;AAEF,MAAI,IAAI,SAAS,gBAAgB,IAAI,WAAW,mBAAmB,OAAO,IAAI,YAAY,UAAU;AAClG,OAAI,QAAQ,UAAU,GAAI,QAAO;GACjC,MAAM,QAAQ,IAAI,QAAQ,MAAM,iDAAiD;GACjF,MAAM,QAAQ,QAAQ,MAAM,KAAK,IAAI,SAAS,MAAM;AACpD,OAAI,KAAM,SAAQ,KAAK,EAAE,QAAQ,KAAK,MAAM,GAAG,IAAK,EAAE,CAAC;AACvD;;AAEF,MAAI,CAAC,WAAW,IAAI,CAAE;EACtB,MAAM,QAAQ,UAAU,IAAI,SAAS,QAAQ,CAAC,IAAI,WAAW,CAAC,OAAO,QAAQ;EAC7E,MAAM,WAAW,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW,KAAA;EACnE,MAAM,YAAY,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY,KAAA;AACtE,OAAK,MAAM,QAAQ,WAAW,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,OAAO,QAAQ,GAAG,OAAO;AAC1E,OAAI,QAAQ,UAAU,GAAI,QAAO;AACjC,WAAQ,KAAK;IAAE,QAAQ,KAAK,MAAM,GAAG,IAAK;IAAE;IAAU;IAAW,CAAC;;;AAGtE,QAAO;;AAGT,eAAe,OAAO;AACpB,KAAI,cAAc,CAAE,QAAO,eAAe;CAC1C,IAAI,QAAQ;AACZ,YAAW,MAAM,SAAS,QAAQ,MAChC,UAAS;CAGX,IAAI;AACJ,KAAI;AACF,SAAO,KAAK,MAAM,MAAM;SAClB;AACN;;AAGF,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,KAAI,kBAAkB,KAAK,CAAE;CAE7B,MAAM,YAAc,KAAK,cAAc,KAAK,aAAa,KAAK,mBAA+B;CAE7F,MAAM,oBAAoB,yBAAyB,KAAK;AACxD,KAAI,kBAAkB,SAAS,GAAG;EAChC,MAAM,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAK;EAC1C,MAAM,UAAU,eAAe,IAAI;EACnC,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa;AAC1C,QAAM,QAAQ,WACZ,kBAAkB,KAAK,EAAE,QAAQ,UAAU,WAAW,MAAM,UAC1D,mBACE,YACE;GAAE,UAAU;GAAiB;GAAW;GAAS;GAAK,WAAW,MAAM;GAAW,MAAM;IAAE;IAAQ,UAAU;IAAM;GAAE,EACpH,WAAW,EAAE,WAAW,UAAU,GAAG,EAAE,EACvC;GAAE,QAAQ;GAAc,YAAY,KAAK;GAAiB;GAAO;GAAQ,EACzE,EAAE,QAAQ,MAAM,CACjB,EACD,IACD,CACF,CACF;;AAGH,OAAM,GAAG,SAAS,2BAA2B;EAC3C,QAAQ;EACR,SAAS,aAAa;EACtB,MAAM,KAAK,UAAU;GAAE;GAAW,OAAO;GAAM,CAAC;EAChD,QAAQ,YAAY,QAAQ,IAAM;EACnC,CAAC,CAAC,YAAY,GAAG;AAElB,KAAI,QAAQ,IAAI,4BAA4B,OAC1C,OAAM,GAAG,SAAS,kCAAkC;EAClD,QAAQ;EACR,SAAS,aAAa;EACtB,QAAQ,YAAY,QAAQ,IAAM;EACnC,CAAC,CAAC,YAAY,GAAG;AAGpB,kBAAiB,QAAQ,KAAK,EAAE,EAAE,KAAK,CAAC,OAAO;;AAGjD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
2
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { basename, join } from "node:path";
|
|
4
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
6
|
//#region src/secret-store.ts
|
|
7
7
|
const SECRET_KEY = "AGENTMEMORY_SECRET";
|
|
8
8
|
function agentmemoryHomeDir() {
|
|
9
|
-
return join(homedir(), ".agentmemory");
|
|
9
|
+
return process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
|
|
10
10
|
}
|
|
11
11
|
function secretFilePath() {
|
|
12
12
|
return join(agentmemoryHomeDir(), "secret");
|
|
@@ -30,7 +30,7 @@ function unquote(value) {
|
|
|
30
30
|
function readEnvFileSecret() {
|
|
31
31
|
let content;
|
|
32
32
|
try {
|
|
33
|
-
content = readFileSync(join(
|
|
33
|
+
content = readFileSync(process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env"), "utf-8");
|
|
34
34
|
} catch {
|
|
35
35
|
return "";
|
|
36
36
|
}
|
|
@@ -46,13 +46,29 @@ function readEnvFileSecret() {
|
|
|
46
46
|
}
|
|
47
47
|
return found;
|
|
48
48
|
}
|
|
49
|
-
function
|
|
49
|
+
function readSecretFile(path) {
|
|
50
50
|
try {
|
|
51
|
-
return usable(readFileSync(
|
|
51
|
+
return usable(readFileSync(path, "utf-8"));
|
|
52
52
|
} catch {
|
|
53
53
|
return "";
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
function legacyDataDirSecretPaths(env = process.env) {
|
|
57
|
+
const dataDir = env["AGENTMEMORY_DATA_DIR"];
|
|
58
|
+
if (!dataDir) return [];
|
|
59
|
+
const paths = [
|
|
60
|
+
join(dataDir, "secret"),
|
|
61
|
+
join(dataDir, ".hmac"),
|
|
62
|
+
join(dataDir, "..", ".hmac")
|
|
63
|
+
];
|
|
64
|
+
return [...new Set(paths.filter((path) => path !== secretFilePath()))];
|
|
65
|
+
}
|
|
66
|
+
function readStoredSecret(env = process.env) {
|
|
67
|
+
const canonicalPath = canonicalSecretPath();
|
|
68
|
+
const localPath = secretFilePath();
|
|
69
|
+
const legacyPaths = legacyDataDirSecretPaths(env);
|
|
70
|
+
return readSecretFile(canonicalPath) || (localPath === canonicalPath ? "" : readSecretFile(localPath)) || legacyPaths.map(readSecretFile).find(Boolean) || "";
|
|
71
|
+
}
|
|
56
72
|
function isLoopbackUrl(url) {
|
|
57
73
|
let hostname;
|
|
58
74
|
try {
|
|
@@ -66,8 +82,12 @@ function isLoopbackUrl(url) {
|
|
|
66
82
|
function resolveClientSecret(baseUrl, env = process.env) {
|
|
67
83
|
const fromEnv = usable(env[SECRET_KEY]);
|
|
68
84
|
if (fromEnv) return fromEnv;
|
|
85
|
+
if (env.AGENTMEMORY_CREDENTIAL_MODE === "explicit") return "";
|
|
69
86
|
if (!isLoopbackUrl(baseUrl)) return "";
|
|
70
|
-
return readEnvFileSecret() || readStoredSecret();
|
|
87
|
+
return readEnvFileSecret() || readStoredSecret(env);
|
|
88
|
+
}
|
|
89
|
+
function canonicalSecretPath() {
|
|
90
|
+
return join(homedir(), ".agentmemory", "secret");
|
|
71
91
|
}
|
|
72
92
|
//#endregion
|
|
73
93
|
//#region src/hooks/_project.ts
|
|
@@ -76,7 +96,7 @@ function resolveProject(cwd) {
|
|
|
76
96
|
if (explicit && explicit.trim()) return explicit.trim();
|
|
77
97
|
const dir = cwd && cwd.trim() ? cwd : process.cwd();
|
|
78
98
|
try {
|
|
79
|
-
const top = execSync("git rev-parse --show-toplevel", {
|
|
99
|
+
const [top, gitDir, commonDir] = execSync("git rev-parse --show-toplevel --git-dir --git-common-dir", {
|
|
80
100
|
cwd: dir,
|
|
81
101
|
stdio: [
|
|
82
102
|
"ignore",
|
|
@@ -84,11 +104,18 @@ function resolveProject(cwd) {
|
|
|
84
104
|
"ignore"
|
|
85
105
|
],
|
|
86
106
|
timeout: 500
|
|
87
|
-
}).toString().trim();
|
|
88
|
-
if (top) return basename(top);
|
|
107
|
+
}).toString().trim().split(/\r?\n/);
|
|
108
|
+
if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));
|
|
89
109
|
} catch {}
|
|
90
110
|
return basename(dir);
|
|
91
111
|
}
|
|
112
|
+
function repositoryRoot(dir, top, gitDir, commonDir) {
|
|
113
|
+
if (!gitDir || !commonDir) return top;
|
|
114
|
+
const physical = realpathSync(dir);
|
|
115
|
+
const common = resolve(physical, commonDir);
|
|
116
|
+
if (resolve(physical, gitDir) === common || basename(common) !== ".git") return top;
|
|
117
|
+
return dirname(common);
|
|
118
|
+
}
|
|
92
119
|
function hookCwd(data) {
|
|
93
120
|
if (!data || typeof data !== "object") return void 0;
|
|
94
121
|
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-start.mjs","names":[],"sources":["../../src/secret-store.ts","../../src/hooks/_project.ts","../../src/hooks/session-start.ts"],"sourcesContent":["import {\n chmodSync,\n closeSync,\n linkSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeSync,\n} from \"node:fs\";\nimport { randomBytes } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst SECRET_KEY = \"AGENTMEMORY_SECRET\";\n\nexport function agentmemoryHomeDir(): string {\n return join(homedir(), \".agentmemory\");\n}\n\nexport function secretFilePath(): string {\n return join(agentmemoryHomeDir(), \"secret\");\n}\n\nfunction usable(value: string | undefined): string {\n if (typeof value !== \"string\") return \"\";\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n if (trimmed.startsWith(\"${\") && trimmed.endsWith(\"}\")) return \"\";\n return trimmed;\n}\n\nfunction unquote(value: string): string {\n const quote = value[0];\n if ((quote === '\"' || quote === \"'\") && value.length > 1) {\n const close = value.indexOf(quote, 1);\n if (close !== -1) return value.slice(1, close);\n }\n const hash = value.indexOf(\" #\");\n return hash === -1 ? value : value.slice(0, hash).trim();\n}\n\nexport function readEnvFileSecret(): string {\n let content: unknown;\n try {\n content = readFileSync(join(agentmemoryHomeDir(), \".env\"), \"utf-8\");\n } catch {\n return \"\";\n }\n if (typeof content !== \"string\") return \"\";\n let found = \"\";\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"#\")) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).replace(/^export\\s+/, \"\").trim();\n if (key !== SECRET_KEY) continue;\n found = usable(unquote(trimmed.slice(eq + 1).trim()));\n }\n return found;\n}\n\nexport function readStoredSecret(): string {\n try {\n return usable(readFileSync(secretFilePath(), \"utf-8\"));\n } catch {\n return \"\";\n }\n}\n\nexport function explicitSecret(env: NodeJS.ProcessEnv = process.env): string {\n return usable(env[SECRET_KEY]) || readEnvFileSecret();\n}\n\nexport function isLoopbackUrl(url: string): boolean {\n let hostname: string;\n try {\n hostname = new URL(url).hostname.toLowerCase();\n } catch {\n return false;\n }\n const bare = hostname.replace(/^\\[|\\]$/g, \"\");\n return bare === \"localhost\" || bare === \"::1\" || /^127(?:\\.\\d{1,3}){3}$/.test(bare);\n}\n\nexport function resolveClientSecret(\n baseUrl: string,\n env: NodeJS.ProcessEnv = process.env,\n): string {\n const fromEnv = usable(env[SECRET_KEY]);\n if (fromEnv) return fromEnv;\n if (!isLoopbackUrl(baseUrl)) return \"\";\n return readEnvFileSecret() || readStoredSecret();\n}\n\nexport function ensureServerSecret(env: NodeJS.ProcessEnv = process.env): {\n secret: string;\n source: \"env\" | \"file\" | \"generated\";\n} {\n const configured = explicitSecret(env);\n if (configured) return { secret: configured, source: \"env\" };\n const stored = readStoredSecret();\n if (stored) return { secret: stored, source: \"file\" };\n const generated = randomBytes(32).toString(\"hex\");\n const path = secretFilePath();\n mkdirSync(agentmemoryHomeDir(), { recursive: true, mode: 0o700 });\n const staging = `${path}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`;\n const fd = openSync(staging, \"wx\", 0o600);\n try {\n writeSync(fd, `${generated}\\n`);\n } finally {\n closeSync(fd);\n }\n try {\n chmodSync(staging, 0o600);\n linkSync(staging, path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n const raced = readStoredSecret();\n if (!raced) throw err;\n return { secret: raced, source: \"file\" };\n } finally {\n try {\n unlinkSync(staging);\n } catch {}\n }\n return { secret: generated, source: \"generated\" };\n}\n\nexport function bearerHeaders(\n baseUrl: string,\n env: NodeJS.ProcessEnv = process.env,\n): Record<string, string> {\n const secret = resolveClientSecret(baseUrl, env);\n return secret ? { Authorization: `Bearer ${secret}` } : {};\n}\n","import { execSync } from \"node:child_process\";\nimport { basename } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git toplevel basename → cwd basename.\nexport function resolveProject(cwd?: string): string {\n const explicit = process.env[\"AGENTMEMORY_PROJECT_NAME\"];\n if (explicit && explicit.trim()) return explicit.trim();\n const dir = cwd && cwd.trim() ? cwd : process.cwd();\n try {\n const top = execSync(\"git rev-parse --show-toplevel\", {\n cwd: dir,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 500,\n })\n .toString()\n .trim();\n if (top) return basename(top);\n } catch {}\n return basename(dir);\n}\n\nexport function hookCwd(data: Record<string, unknown> | null | undefined): string | undefined {\n if (!data || typeof data !== \"object\") return undefined;\n if (typeof data.cwd === \"string\" && data.cwd.trim()) return data.cwd;\n const roots = data.workspace_roots;\n if (Array.isArray(roots)) {\n for (const root of roots) {\n if (typeof root === \"string\" && root.trim()) return root;\n }\n }\n const projectDir =\n process.env[\"DEVIN_PROJECT_DIR\"] || process.env[\"CLAUDE_PROJECT_DIR\"];\n if (projectDir && projectDir.trim()) return projectDir;\n return undefined;\n}\n","#!/usr/bin/env node\nimport { resolveClientSecret } from \"../secret-store.js\";\nimport { resolveProject, hookCwd } from \"./_project.js\";\n\n// Inlined from ./sdk-guard so each hook bundles to a single self-contained\n// .mjs (matches the pattern used by every other hook entry in tsdown.config).\nfunction isSdkChildContext(payload: unknown): boolean {\n if (process.env[\"AGENTMEMORY_SDK_CHILD\"] === \"1\") return true;\n if (!payload || typeof payload !== \"object\") return false;\n return (payload as { entrypoint?: unknown }).entrypoint === \"sdk-ts\";\n}\n\nconst INJECT_CONTEXT = process.env[\"AGENTMEMORY_INJECT_CONTEXT\"] === \"true\";\n\nconst REST_URL = process.env[\"AGENTMEMORY_URL\"] || \"http://localhost:3111\";\nconst SECRET = resolveClientSecret(REST_URL);\n\nconst INJECT_TIMEOUT_MS = 1500;\nconst REGISTER_TIMEOUT_MS = 800;\n\nfunction authHeaders(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (SECRET) h[\"Authorization\"] = `Bearer ${SECRET}`;\n return h;\n}\n\nfunction isPlainTextHost(): boolean {\n return Boolean(\n process.env[\"FACTORY_PROJECT_DIR\"] || process.env[\"DROID_PLUGIN_ROOT\"],\n );\n}\n\nfunction wantsStructuredOutput(data: Record<string, unknown>): boolean {\n if (process.env[\"DEVIN_PROJECT_DIR\"] || data.prompt_id !== undefined) {\n return true;\n }\n return data.hook_event_name === \"SessionStart\" && !isPlainTextHost();\n}\n\nfunction contextPayload(data: Record<string, unknown>, context: string): string {\n if (process.env[\"COPILOT_PLUGIN_ROOT\"] && !data.hook_event_name) {\n return JSON.stringify({ additionalContext: context });\n }\n if (\n typeof data.cursor_version === \"string\" ||\n data.hook_event_name === \"sessionStart\"\n ) {\n return JSON.stringify({ additional_context: context });\n }\n if (wantsStructuredOutput(data)) {\n return JSON.stringify({\n hookSpecificOutput: {\n hookEventName: \"SessionStart\",\n additionalContext: context,\n },\n });\n }\n return context;\n}\n\nasync function main() {\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(input);\n } catch {\n return;\n }\n\n if (!data || typeof data !== \"object\") return;\n if (isSdkChildContext(data)) return;\n\n const sessionId =\n ((data.session_id || data.sessionId || data.conversation_id) as string) ||\n `ses_${Date.now().toString(36)}`;\n const cwd = hookCwd(data) || process.cwd();\n const project = resolveProject(cwd);\n\n const url = `${REST_URL}/agentmemory/session/start`;\n const init: RequestInit = {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({ sessionId, project, cwd }),\n };\n\n if (!INJECT_CONTEXT) {\n // Pure telemetry path: caller never reads the response, so don't\n // block on it. AbortSignal.timeout caps the wait the event loop\n // gives the pending socket before exit.\n fetch(url, {\n ...init,\n signal: AbortSignal.timeout(REGISTER_TIMEOUT_MS),\n }).catch(() => {});\n return;\n }\n\n try {\n const res = await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(INJECT_TIMEOUT_MS),\n });\n if (res.ok) {\n const result = (await res.json()) as { context?: string };\n if (result.context) {\n process.stdout.write(contextPayload(data, result.context));\n }\n }\n } catch {\n // silently fail -- don't block Claude Code startup\n }\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-start.mjs","names":[],"sources":["../../src/secret-store.ts","../../src/hooks/_project.ts","../../src/hooks/session-start.ts"],"sourcesContent":["import {\n chmodSync,\n closeSync,\n linkSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeSync,\n} from \"node:fs\";\nimport { randomBytes } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst SECRET_KEY = \"AGENTMEMORY_SECRET\";\n\nexport function agentmemoryHomeDir(): string {\n return process.env[\"AGENTMEMORY_DATA_DIR\"] || join(homedir(), \".agentmemory\");\n}\n\nexport function secretFilePath(): string {\n return join(agentmemoryHomeDir(), \"secret\");\n}\n\nfunction usable(value: string | undefined): string {\n if (typeof value !== \"string\") return \"\";\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n if (trimmed.startsWith(\"${\") && trimmed.endsWith(\"}\")) return \"\";\n return trimmed;\n}\n\nfunction unquote(value: string): string {\n const quote = value[0];\n if ((quote === '\"' || quote === \"'\") && value.length > 1) {\n const close = value.indexOf(quote, 1);\n if (close !== -1) return value.slice(1, close);\n }\n const hash = value.indexOf(\" #\");\n return hash === -1 ? value : value.slice(0, hash).trim();\n}\n\nexport function readEnvFileSecret(): string {\n let content: unknown;\n try {\n content = readFileSync(process.env[\"AGENTMEMORY_ENV_FILE\"] || join(homedir(), \".agentmemory\", \".env\"), \"utf-8\");\n } catch {\n return \"\";\n }\n if (typeof content !== \"string\") return \"\";\n let found = \"\";\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"#\")) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).replace(/^export\\s+/, \"\").trim();\n if (key !== SECRET_KEY) continue;\n found = usable(unquote(trimmed.slice(eq + 1).trim()));\n }\n return found;\n}\n\nfunction readSecretFile(path: string): string {\n try {\n return usable(readFileSync(path, \"utf-8\"));\n } catch {\n return \"\";\n }\n}\n\nfunction legacyDataDirSecretPaths(env: NodeJS.ProcessEnv = process.env): string[] {\n const dataDir = env[\"AGENTMEMORY_DATA_DIR\"];\n if (!dataDir) return [];\n const paths = [join(dataDir, \"secret\"), join(dataDir, \".hmac\"), join(dataDir, \"..\", \".hmac\")];\n return [...new Set(paths.filter((path) => path !== secretFilePath()))];\n}\n\nexport function readStoredSecret(env: NodeJS.ProcessEnv = process.env): string {\n const canonicalPath = canonicalSecretPath();\n const localPath = secretFilePath();\n const legacyPaths = legacyDataDirSecretPaths(env);\n return readSecretFile(canonicalPath) ||\n (localPath === canonicalPath ? \"\" : readSecretFile(localPath)) ||\n legacyPaths.map(readSecretFile).find(Boolean) || \"\";\n}\n\nexport function explicitSecret(env: NodeJS.ProcessEnv = process.env): string {\n return usable(env[SECRET_KEY]) || readEnvFileSecret();\n}\n\nexport function isLoopbackUrl(url: string): boolean {\n let hostname: string;\n try {\n hostname = new URL(url).hostname.toLowerCase();\n } catch {\n return false;\n }\n const bare = hostname.replace(/^\\[|\\]$/g, \"\");\n return bare === \"localhost\" || bare === \"::1\" || /^127(?:\\.\\d{1,3}){3}$/.test(bare);\n}\n\nexport function resolveClientSecret(\n baseUrl: string,\n env: NodeJS.ProcessEnv = process.env,\n): string {\n const fromEnv = usable(env[SECRET_KEY]);\n if (fromEnv) return fromEnv;\n if (env.AGENTMEMORY_CREDENTIAL_MODE === \"explicit\") return \"\";\n if (!isLoopbackUrl(baseUrl)) return \"\";\n return readEnvFileSecret() || readStoredSecret(env);\n}\n\nfunction canonicalSecretPath(): string {\n return join(homedir(), \".agentmemory\", \"secret\");\n}\n\nfunction writeSecretFile(path: string, secret: string): void {\n mkdirSync(join(path, \"..\"), { recursive: true, mode: 0o700 });\n const staging = `${path}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`;\n const fd = openSync(staging, \"wx\", 0o600);\n try {\n writeSync(fd, `${secret}\\n`);\n } finally {\n closeSync(fd);\n }\n try {\n chmodSync(staging, 0o600);\n renameSync(staging, path);\n chmodSync(path, 0o600);\n } finally {\n try { unlinkSync(staging); } catch {}\n }\n}\n\nfunction writeSecretIfAbsent(path: string, secret: string): string {\n mkdirSync(join(path, \"..\"), { recursive: true, mode: 0o700 });\n const staging = `${path}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`;\n const fd = openSync(staging, \"wx\", 0o600);\n try {\n writeSync(fd, `${secret}\\n`);\n } finally {\n closeSync(fd);\n }\n try {\n chmodSync(staging, 0o600);\n linkSync(staging, path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n } finally {\n try { unlinkSync(staging); } catch {}\n }\n const stored = readSecretFile(path);\n if (!stored) throw new Error(`Could not read stored API secret at ${path}.`);\n return stored;\n}\n\nexport function ensureServerSecret(env: NodeJS.ProcessEnv = process.env): {\n secret: string;\n source: \"env\" | \"file\" | \"generated\";\n} {\n const configured = explicitSecret(env);\n if (configured) return { secret: configured, source: \"env\" };\n\n const localPath = secretFilePath();\n const canonicalPath = canonicalSecretPath();\n const canonical = localPath === canonicalPath ? \"\" : readSecretFile(canonicalPath);\n if (canonical) {\n if (localPath !== canonicalPath && readSecretFile(localPath) !== canonical) {\n writeSecretFile(localPath, canonical);\n }\n return { secret: canonical, source: \"file\" };\n }\n\n const legacy = readSecretFile(localPath) || legacyDataDirSecretPaths(env).map(readSecretFile).find(Boolean) || \"\";\n const candidate = legacy || randomBytes(32).toString(\"hex\");\n const localSecret = writeSecretIfAbsent(localPath, candidate);\n const secret = localPath === canonicalPath\n ? localSecret\n : writeSecretIfAbsent(canonicalPath, localSecret);\n if (localPath !== canonicalPath && localSecret !== secret) writeSecretFile(localPath, secret);\n return { secret, source: legacy ? \"file\" : \"generated\" };\n}\n\nexport function bearerHeaders(\n baseUrl: string,\n env: NodeJS.ProcessEnv = process.env,\n): Record<string, string> {\n const secret = resolveClientSecret(baseUrl, env);\n return secret ? { Authorization: `Bearer ${secret}` } : {};\n}\n","import { execSync } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git repository basename → cwd basename.\nexport function resolveProject(cwd?: string): string {\n const explicit = process.env[\"AGENTMEMORY_PROJECT_NAME\"];\n if (explicit && explicit.trim()) return explicit.trim();\n const dir = cwd && cwd.trim() ? cwd : process.cwd();\n try {\n const [top, gitDir, commonDir] = execSync(\n \"git rev-parse --show-toplevel --git-dir --git-common-dir\",\n {\n cwd: dir,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 500,\n },\n )\n .toString()\n .trim()\n .split(/\\r?\\n/);\n if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));\n } catch {}\n return basename(dir);\n}\n\nfunction repositoryRoot(dir: string, top: string, gitDir?: string, commonDir?: string): string {\n if (!gitDir || !commonDir) return top;\n const physical = realpathSync(dir);\n const common = resolve(physical, commonDir);\n if (resolve(physical, gitDir) === common || basename(common) !== \".git\") return top;\n return dirname(common);\n}\n\nexport function hookCwd(data: Record<string, unknown> | null | undefined): string | undefined {\n if (!data || typeof data !== \"object\") return undefined;\n if (typeof data.cwd === \"string\" && data.cwd.trim()) return data.cwd;\n const roots = data.workspace_roots;\n if (Array.isArray(roots)) {\n for (const root of roots) {\n if (typeof root === \"string\" && root.trim()) return root;\n }\n }\n const projectDir =\n process.env[\"DEVIN_PROJECT_DIR\"] || process.env[\"CLAUDE_PROJECT_DIR\"];\n if (projectDir && projectDir.trim()) return projectDir;\n return undefined;\n}\n","#!/usr/bin/env node\nimport { resolveClientSecret } from \"../secret-store.js\";\nimport { resolveProject, hookCwd } from \"./_project.js\";\n\n// Inlined from ./sdk-guard so each hook bundles to a single self-contained\n// .mjs (matches the pattern used by every other hook entry in tsdown.config).\nfunction isSdkChildContext(payload: unknown): boolean {\n if (process.env[\"AGENTMEMORY_SDK_CHILD\"] === \"1\") return true;\n if (!payload || typeof payload !== \"object\") return false;\n return (payload as { entrypoint?: unknown }).entrypoint === \"sdk-ts\";\n}\n\nconst INJECT_CONTEXT = process.env[\"AGENTMEMORY_INJECT_CONTEXT\"] === \"true\";\n\nconst REST_URL = process.env[\"AGENTMEMORY_URL\"] || \"http://localhost:3111\";\nconst SECRET = resolveClientSecret(REST_URL);\n\nconst INJECT_TIMEOUT_MS = 1500;\nconst REGISTER_TIMEOUT_MS = 800;\n\nfunction authHeaders(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (SECRET) h[\"Authorization\"] = `Bearer ${SECRET}`;\n return h;\n}\n\nfunction isPlainTextHost(): boolean {\n return Boolean(\n process.env[\"FACTORY_PROJECT_DIR\"] || process.env[\"DROID_PLUGIN_ROOT\"],\n );\n}\n\nfunction wantsStructuredOutput(data: Record<string, unknown>): boolean {\n if (process.env[\"DEVIN_PROJECT_DIR\"] || data.prompt_id !== undefined) {\n return true;\n }\n return data.hook_event_name === \"SessionStart\" && !isPlainTextHost();\n}\n\nfunction contextPayload(data: Record<string, unknown>, context: string): string {\n if (process.env[\"COPILOT_PLUGIN_ROOT\"] && !data.hook_event_name) {\n return JSON.stringify({ additionalContext: context });\n }\n if (\n typeof data.cursor_version === \"string\" ||\n data.hook_event_name === \"sessionStart\"\n ) {\n return JSON.stringify({ additional_context: context });\n }\n if (wantsStructuredOutput(data)) {\n return JSON.stringify({\n hookSpecificOutput: {\n hookEventName: \"SessionStart\",\n additionalContext: context,\n },\n });\n }\n return context;\n}\n\nasync function main() {\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(input);\n } catch {\n return;\n }\n\n if (!data || typeof data !== \"object\") return;\n if (isSdkChildContext(data)) return;\n\n const sessionId =\n ((data.session_id || data.sessionId || data.conversation_id) as string) ||\n `ses_${Date.now().toString(36)}`;\n const cwd = hookCwd(data) || process.cwd();\n const project = resolveProject(cwd);\n\n const url = `${REST_URL}/agentmemory/session/start`;\n const init: RequestInit = {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({ sessionId, project, cwd }),\n };\n\n if (!INJECT_CONTEXT) {\n // Pure telemetry path: caller never reads the response, so don't\n // block on it. AbortSignal.timeout caps the wait the event loop\n // gives the pending socket before exit.\n fetch(url, {\n ...init,\n signal: AbortSignal.timeout(REGISTER_TIMEOUT_MS),\n }).catch(() => {});\n return;\n }\n\n try {\n const res = await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(INJECT_TIMEOUT_MS),\n });\n if (res.ok) {\n const result = (await res.json()) as { context?: string };\n if (result.context) {\n process.stdout.write(contextPayload(data, result.context));\n }\n }\n } catch {\n // silently fail -- don't block Claude Code startup\n }\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":"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"}
|
package/dist/hooks/stop.mjs
CHANGED
|
@@ -1,72 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return join(agentmemoryHomeDir(), "secret");
|
|
12
|
-
}
|
|
13
|
-
function usable(value) {
|
|
14
|
-
if (typeof value !== "string") return "";
|
|
15
|
-
const trimmed = value.trim();
|
|
16
|
-
if (!trimmed) return "";
|
|
17
|
-
if (trimmed.startsWith("${") && trimmed.endsWith("}")) return "";
|
|
18
|
-
return trimmed;
|
|
19
|
-
}
|
|
20
|
-
function unquote(value) {
|
|
21
|
-
const quote = value[0];
|
|
22
|
-
if ((quote === "\"" || quote === "'") && value.length > 1) {
|
|
23
|
-
const close = value.indexOf(quote, 1);
|
|
24
|
-
if (close !== -1) return value.slice(1, close);
|
|
25
|
-
}
|
|
26
|
-
const hash = value.indexOf(" #");
|
|
27
|
-
return hash === -1 ? value : value.slice(0, hash).trim();
|
|
28
|
-
}
|
|
29
|
-
function readEnvFileSecret() {
|
|
30
|
-
let content;
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, resolve } from "node:path";
|
|
5
|
+
import { REST_URL, authHeaders, captureObservation, isDrainChild, runDrainChild, stripPrivateData, withEventId } from "./_capture.mjs";
|
|
6
|
+
//#region src/hooks/_project.ts
|
|
7
|
+
function resolveProject(cwd) {
|
|
8
|
+
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
|
|
9
|
+
if (explicit && explicit.trim()) return explicit.trim();
|
|
10
|
+
const dir = cwd && cwd.trim() ? cwd : process.cwd();
|
|
31
11
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
found = usable(unquote(trimmed.slice(eq + 1).trim()));
|
|
45
|
-
}
|
|
46
|
-
return found;
|
|
12
|
+
const [top, gitDir, commonDir] = execSync("git rev-parse --show-toplevel --git-dir --git-common-dir", {
|
|
13
|
+
cwd: dir,
|
|
14
|
+
stdio: [
|
|
15
|
+
"ignore",
|
|
16
|
+
"pipe",
|
|
17
|
+
"ignore"
|
|
18
|
+
],
|
|
19
|
+
timeout: 500
|
|
20
|
+
}).toString().trim().split(/\r?\n/);
|
|
21
|
+
if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));
|
|
22
|
+
} catch {}
|
|
23
|
+
return basename(dir);
|
|
47
24
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
25
|
+
function repositoryRoot(dir, top, gitDir, commonDir) {
|
|
26
|
+
if (!gitDir || !commonDir) return top;
|
|
27
|
+
const physical = realpathSync(dir);
|
|
28
|
+
const common = resolve(physical, commonDir);
|
|
29
|
+
if (resolve(physical, gitDir) === common || basename(common) !== ".git") return top;
|
|
30
|
+
return dirname(common);
|
|
54
31
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return
|
|
32
|
+
function hookCwd(data) {
|
|
33
|
+
if (!data || typeof data !== "object") return void 0;
|
|
34
|
+
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
35
|
+
const roots = data.workspace_roots;
|
|
36
|
+
if (Array.isArray(roots)) {
|
|
37
|
+
for (const root of roots) if (typeof root === "string" && root.trim()) return root;
|
|
61
38
|
}
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
function resolveClientSecret(baseUrl, env = process.env) {
|
|
66
|
-
const fromEnv = usable(env[SECRET_KEY]);
|
|
67
|
-
if (fromEnv) return fromEnv;
|
|
68
|
-
if (!isLoopbackUrl(baseUrl)) return "";
|
|
69
|
-
return readEnvFileSecret() || readStoredSecret();
|
|
39
|
+
const projectDir = process.env["DEVIN_PROJECT_DIR"] || process.env["CLAUDE_PROJECT_DIR"];
|
|
40
|
+
if (projectDir && projectDir.trim()) return projectDir;
|
|
70
41
|
}
|
|
71
42
|
//#endregion
|
|
72
43
|
//#region src/hooks/stop.ts
|
|
@@ -75,14 +46,24 @@ function isSdkChildContext(payload) {
|
|
|
75
46
|
if (!payload || typeof payload !== "object") return false;
|
|
76
47
|
return payload.entrypoint === "sdk-ts";
|
|
77
48
|
}
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
49
|
+
const OBSERVE_TIMEOUT_MS = 2e3;
|
|
50
|
+
const EXIT_CAP_MS = 3500;
|
|
51
|
+
const END_CAP_MS = 1500;
|
|
52
|
+
const REPLY_MAX_CHARS = 4e3;
|
|
53
|
+
function boundReply(reply) {
|
|
54
|
+
const safe = stripPrivateData(reply);
|
|
55
|
+
if (safe.length <= REPLY_MAX_CHARS) return { text: safe };
|
|
56
|
+
let head = Math.ceil((REPLY_MAX_CHARS - 1) / 2);
|
|
57
|
+
let tail = safe.length - (REPLY_MAX_CHARS - 1 - head);
|
|
58
|
+
if (/[\uD800-\uDBFF]/.test(safe[head - 1])) head--;
|
|
59
|
+
if (/[\uDC00-\uDFFF]/.test(safe[tail])) tail++;
|
|
60
|
+
return {
|
|
61
|
+
text: `${safe.slice(0, head)}\u2026${safe.slice(tail)}`,
|
|
62
|
+
bytes: Buffer.byteLength(safe, "utf8")
|
|
63
|
+
};
|
|
84
64
|
}
|
|
85
65
|
async function main() {
|
|
66
|
+
if (isDrainChild()) return runDrainChild();
|
|
86
67
|
let input = "";
|
|
87
68
|
for await (const chunk of process.stdin) input += chunk;
|
|
88
69
|
let data;
|
|
@@ -94,13 +75,34 @@ async function main() {
|
|
|
94
75
|
if (!data || typeof data !== "object") return;
|
|
95
76
|
if (isSdkChildContext(data)) return;
|
|
96
77
|
const sessionId = data.session_id || data.sessionId || data.conversation_id || "unknown";
|
|
78
|
+
const reply = data.last_assistant_message;
|
|
79
|
+
if (typeof reply === "string" && reply.trim()) {
|
|
80
|
+
const capture = setTimeout(() => process.exit(0), EXIT_CAP_MS).unref();
|
|
81
|
+
const cwd = hookCwd(data) || process.cwd();
|
|
82
|
+
const bounded = boundReply(reply);
|
|
83
|
+
await captureObservation(withEventId({
|
|
84
|
+
hookType: "stop",
|
|
85
|
+
sessionId,
|
|
86
|
+
project: resolveProject(cwd),
|
|
87
|
+
cwd,
|
|
88
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
89
|
+
data: {
|
|
90
|
+
last_assistant_message: bounded.text,
|
|
91
|
+
...bounded.bytes === void 0 ? {} : { last_assistant_message_bytes: bounded.bytes }
|
|
92
|
+
}
|
|
93
|
+
}, {}), OBSERVE_TIMEOUT_MS).catch(() => {});
|
|
94
|
+
clearTimeout(capture);
|
|
95
|
+
}
|
|
96
|
+
setTimeout(() => process.exit(0), END_CAP_MS).unref();
|
|
97
97
|
fetch(`${REST_URL}/agentmemory/session/end`, {
|
|
98
98
|
method: "POST",
|
|
99
99
|
headers: authHeaders(),
|
|
100
|
-
body: JSON.stringify({
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
sessionId,
|
|
102
|
+
final: false
|
|
103
|
+
}),
|
|
101
104
|
signal: AbortSignal.timeout(5e3)
|
|
102
105
|
}).catch(() => {});
|
|
103
|
-
setTimeout(() => process.exit(0), 1500).unref();
|
|
104
106
|
}
|
|
105
107
|
main().catch(() => process.exit(0));
|
|
106
108
|
//#endregion
|
package/dist/hooks/stop.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop.mjs","names":[],"sources":["../../src/
|
|
1
|
+
{"version":3,"file":"stop.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/stop.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\n\n// Resolution order: AGENTMEMORY_PROJECT_NAME env → git repository basename → cwd basename.\nexport function resolveProject(cwd?: string): string {\n const explicit = process.env[\"AGENTMEMORY_PROJECT_NAME\"];\n if (explicit && explicit.trim()) return explicit.trim();\n const dir = cwd && cwd.trim() ? cwd : process.cwd();\n try {\n const [top, gitDir, commonDir] = execSync(\n \"git rev-parse --show-toplevel --git-dir --git-common-dir\",\n {\n cwd: dir,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n timeout: 500,\n },\n )\n .toString()\n .trim()\n .split(/\\r?\\n/);\n if (top) return basename(repositoryRoot(dir, top, gitDir, commonDir));\n } catch {}\n return basename(dir);\n}\n\nfunction repositoryRoot(dir: string, top: string, gitDir?: string, commonDir?: string): string {\n if (!gitDir || !commonDir) return top;\n const physical = realpathSync(dir);\n const common = resolve(physical, commonDir);\n if (resolve(physical, gitDir) === common || basename(common) !== \".git\") return top;\n return dirname(common);\n}\n\nexport function hookCwd(data: Record<string, unknown> | null | undefined): string | undefined {\n if (!data || typeof data !== \"object\") return undefined;\n if (typeof data.cwd === \"string\" && data.cwd.trim()) return data.cwd;\n const roots = data.workspace_roots;\n if (Array.isArray(roots)) {\n for (const root of roots) {\n if (typeof root === \"string\" && root.trim()) return root;\n }\n }\n const projectDir =\n process.env[\"DEVIN_PROJECT_DIR\"] || process.env[\"CLAUDE_PROJECT_DIR\"];\n if (projectDir && projectDir.trim()) return projectDir;\n return undefined;\n}\n","#!/usr/bin/env node\nimport { resolveProject, hookCwd } from \"./_project.js\";\nimport { REST_URL, authHeaders, captureObservation, isDrainChild, runDrainChild, stripPrivateData, withEventId } from \"./_capture.js\";\n\n// Inlined — see src/hooks/sdk-guard.ts for canonical version. Kept local\n// per-hook so tsdown does not emit a shared hashed chunk that would churn\n// the diff on every rebuild.\nfunction isSdkChildContext(payload: unknown): boolean {\n if (process.env[\"AGENTMEMORY_SDK_CHILD\"] === \"1\") return true;\n if (!payload || typeof payload !== \"object\") return false;\n return (payload as { entrypoint?: unknown }).entrypoint === \"sdk-ts\";\n}\n\nconst OBSERVE_TIMEOUT_MS = 2000;\nconst EXIT_CAP_MS = 3500;\nconst END_CAP_MS = 1500;\nconst REPLY_MAX_CHARS = 4000;\n\n// stripPrivateData only matches a closed <private> block, so the whole reply\n// has to be redacted before anything shortens it.\nfunction boundReply(reply: string): { text: string; bytes?: number } {\n const safe = stripPrivateData(reply);\n if (safe.length <= REPLY_MAX_CHARS) return { text: safe };\n let head = Math.ceil((REPLY_MAX_CHARS - 1) / 2);\n let tail = safe.length - (REPLY_MAX_CHARS - 1 - head);\n if (/[\\uD800-\\uDBFF]/.test(safe[head - 1]!)) head--;\n if (/[\\uDC00-\\uDFFF]/.test(safe[tail]!)) tail++;\n return { text: `${safe.slice(0, head)}\\u2026${safe.slice(tail)}`, bytes: Buffer.byteLength(safe, \"utf8\") };\n}\n\nasync function main() {\n if (isDrainChild()) return runDrainChild();\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(input);\n } catch {\n return;\n }\n\n if (!data || typeof data !== \"object\") return;\n if (isSdkChildContext(data)) {\n // Do not summarize from inside a Claude Agent SDK child session;\n // would re-enter agent-sdk provider and loop (see sdk-guard.ts).\n return;\n }\n\n const sessionId = ((data.session_id || data.sessionId || data.conversation_id) as string) || \"unknown\";\n const reply = data.last_assistant_message;\n if (typeof reply === \"string\" && reply.trim()) {\n const capture = setTimeout(() => process.exit(0), EXIT_CAP_MS).unref();\n const cwd = hookCwd(data) || process.cwd();\n const bounded = boundReply(reply);\n const body = {\n hookType: \"stop\",\n sessionId,\n project: resolveProject(cwd),\n cwd,\n timestamp: new Date().toISOString(),\n data: {\n last_assistant_message: bounded.text,\n ...(bounded.bytes === undefined ? {} : { last_assistant_message_bytes: bounded.bytes }),\n },\n };\n await captureObservation(withEventId(body, {}), OBSERVE_TIMEOUT_MS).catch(() => {});\n clearTimeout(capture);\n }\n\n setTimeout(() => process.exit(0), END_CAP_MS).unref();\n fetch(`${REST_URL}/agentmemory/session/end`, {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({ sessionId, final: false }),\n signal: AbortSignal.timeout(5000),\n }).catch(() => {});\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":"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"}
|