@agentmemory/agentmemory 0.9.27 → 0.9.29
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 +15 -6
- package/AGENTS.md +7 -7
- package/README.md +292 -164
- package/dist/.env.example +15 -6
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +427 -177
- package/dist/cli.mjs.map +1 -1
- package/dist/{connect-bmZ5eqYN.mjs → connect-Qaeq15TQ.mjs} +717 -65
- package/dist/connect-Qaeq15TQ.mjs.map +1 -0
- package/dist/docker-compose.yml +2 -2
- package/dist/hooks/antigravity-bridge.d.mts +8 -0
- package/dist/hooks/antigravity-bridge.d.mts.map +1 -0
- package/dist/hooks/antigravity-bridge.mjs +114 -0
- package/dist/hooks/antigravity-bridge.mjs.map +1 -0
- package/dist/hooks/notification.mjs +21 -5
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +15 -2
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +16 -4
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +16 -4
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +14 -3
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +3 -2
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +16 -4
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +84 -19
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +24 -5
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +3 -8
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +16 -4
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +16 -4
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +16 -4
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/{image-refs-B5Zf_Djo.mjs → image-refs-BKLmp_sD.mjs} +4 -22
- package/dist/image-refs-BKLmp_sD.mjs.map +1 -0
- package/dist/image-refs-CJgZmb9X.mjs +34 -0
- package/dist/image-refs-CJgZmb9X.mjs.map +1 -0
- package/dist/index.mjs +1681 -911
- package/dist/index.mjs.map +1 -1
- package/dist/{image-store-Gpo2mgM9.mjs → keyed-mutex-DTHtcZrt.mjs} +14 -11
- package/dist/keyed-mutex-DTHtcZrt.mjs.map +1 -0
- package/dist/{logger-yHTcEBAI.mjs → logger-BEB7pCI9.mjs} +1 -1
- package/dist/{logger-yHTcEBAI.mjs.map → logger-BEB7pCI9.mjs.map} +1 -1
- package/dist/schema-BFZhNTF7.mjs +197 -0
- package/dist/schema-BFZhNTF7.mjs.map +1 -0
- package/dist/{src-MOg2zKJs.mjs → src-G7yt8gGm.mjs} +1521 -854
- package/dist/src-G7yt8gGm.mjs.map +1 -0
- package/dist/{standalone-BORXC71-.mjs → standalone-BqNJDJ04.mjs} +30 -16
- package/dist/standalone-BqNJDJ04.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +55 -15
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-D8XVVPbJ.mjs → tools-registry-BV_2bu7z.mjs} +55 -17
- package/dist/tools-registry-BV_2bu7z.mjs.map +1 -0
- package/dist/viewer/favicon.svg +35 -1
- package/dist/viewer/index.html +473 -83
- package/docker-compose.yml +2 -2
- package/integrations/pi/README.md +77 -0
- package/integrations/pi/index.ts +403 -0
- package/integrations/pi/package.json +32 -0
- package/integrations/pi/security.ts +35 -0
- package/package.json +6 -4
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/.devin-plugin/plugin.json +32 -0
- package/plugin/cursor/hooks.json +41 -0
- package/plugin/cursor/mcp.json +12 -0
- package/plugin/hooks/hooks.antigravity.json +43 -0
- package/plugin/hooks/hooks.devin.json +67 -0
- package/plugin/hooks/hooks.droid.json +55 -0
- package/plugin/opencode/README.md +1 -1
- package/plugin/opencode/agentmemory-capture.ts +73 -13
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +2 -2
- package/plugin/scripts/antigravity-bridge.d.mts +8 -0
- package/plugin/scripts/antigravity-bridge.d.mts.map +1 -0
- package/plugin/scripts/antigravity-bridge.mjs +114 -0
- package/plugin/scripts/antigravity-bridge.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +21 -5
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/post-commit.mjs +15 -2
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +16 -4
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +16 -4
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +14 -3
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +3 -2
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +16 -4
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +84 -19
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +24 -5
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +3 -8
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +16 -4
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +16 -4
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +16 -4
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +38 -0
- package/plugin/skills/agentmemory-agents/REFERENCE.md +31 -0
- package/plugin/skills/agentmemory-agents/SKILL.md +34 -0
- package/plugin/skills/agentmemory-architecture/SKILL.md +33 -0
- package/plugin/skills/agentmemory-config/REFERENCE.md +45 -0
- package/plugin/skills/agentmemory-config/SKILL.md +37 -0
- package/plugin/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/plugin/skills/agentmemory-hooks/SKILL.md +39 -0
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/plugin/skills/agentmemory-mcp-tools/SKILL.md +39 -0
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +142 -0
- package/plugin/skills/agentmemory-rest-api/SKILL.md +43 -0
- package/plugin/skills/commit-context/EXAMPLES.md +71 -0
- package/plugin/skills/commit-context/SKILL.md +53 -8
- package/plugin/skills/commit-history/EXAMPLES.md +71 -0
- package/plugin/skills/commit-history/SKILL.md +51 -9
- package/plugin/skills/forget/EXAMPLES.md +75 -0
- package/plugin/skills/forget/SKILL.md +57 -14
- package/plugin/skills/handoff/EXAMPLES.md +56 -0
- package/plugin/skills/handoff/SKILL.md +56 -9
- package/plugin/skills/lesson/SKILL.md +64 -0
- package/plugin/skills/memory-discipline/SKILL.md +57 -0
- package/plugin/skills/recall/EXAMPLES.md +74 -0
- package/plugin/skills/recall/SKILL.md +53 -11
- package/plugin/skills/recap/EXAMPLES.md +60 -0
- package/plugin/skills/recap/SKILL.md +51 -13
- package/plugin/skills/remember/EXAMPLES.md +67 -0
- package/plugin/skills/remember/SKILL.md +58 -17
- package/plugin/skills/session-history/EXAMPLES.md +59 -0
- package/plugin/skills/session-history/SKILL.md +54 -11
- package/plugin/skills/write-agentmemory-skill/SKILL.md +40 -0
- package/dist/connect-bmZ5eqYN.mjs.map +0 -1
- package/dist/image-refs-B5Zf_Djo.mjs.map +0 -1
- package/dist/image-store-Gpo2mgM9.mjs.map +0 -1
- package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
- package/dist/schema-CNiCWzV9.mjs +0 -78
- package/dist/schema-CNiCWzV9.mjs.map +0 -1
- package/dist/src-MOg2zKJs.mjs.map +0 -1
- package/dist/standalone-BORXC71-.mjs.map +0 -1
- package/dist/tools-registry-D8XVVPbJ.mjs.map +0 -1
- package/dist/version-9DNrRyph.mjs +0 -6
- package/dist/version-9DNrRyph.mjs.map +0 -1
- package/plugin/scripts/diagnostics.d.mts +0 -17
- package/plugin/scripts/diagnostics.d.mts.map +0 -1
- package/plugin/scripts/diagnostics.mjs.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"hooks": {
|
|
4
|
+
"sessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/session-start.mjs"
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"beforeSubmitPrompt": [
|
|
10
|
+
{
|
|
11
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/prompt-submit.mjs"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"preToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/pre-tool-use.mjs",
|
|
17
|
+
"matcher": "Shell|Read|Write|Grep"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"postToolUse": [
|
|
21
|
+
{
|
|
22
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/post-tool-use.mjs"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"postToolUseFailure": [
|
|
26
|
+
{
|
|
27
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/post-tool-failure.mjs"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"stop": [
|
|
31
|
+
{
|
|
32
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/stop.mjs"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"sessionEnd": [
|
|
36
|
+
{
|
|
37
|
+
"command": "node ${CURSOR_PLUGIN_ROOT}/plugin/scripts/session-end.mjs"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"agentmemory": {
|
|
3
|
+
"enabled": true,
|
|
4
|
+
"PreInvocation": [
|
|
5
|
+
{
|
|
6
|
+
"type": "command",
|
|
7
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/antigravity-bridge.mjs PreInvocation",
|
|
8
|
+
"timeout": 10
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"PreToolUse": [
|
|
12
|
+
{
|
|
13
|
+
"matcher": "view_file|view_code_item|read_file|edit_file|replace_file_content|write_to_file|create_file|grep_search|codebase_search|find_by_name|list_dir",
|
|
14
|
+
"hooks": [
|
|
15
|
+
{
|
|
16
|
+
"type": "command",
|
|
17
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/antigravity-bridge.mjs PreToolUse",
|
|
18
|
+
"timeout": 10
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"PostToolUse": [
|
|
24
|
+
{
|
|
25
|
+
"matcher": "",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"type": "command",
|
|
29
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/antigravity-bridge.mjs PostToolUse",
|
|
30
|
+
"timeout": 10
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"Stop": [
|
|
36
|
+
{
|
|
37
|
+
"type": "command",
|
|
38
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/antigravity-bridge.mjs Stop",
|
|
39
|
+
"timeout": 10
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-start.mjs\""
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"UserPromptSubmit": [
|
|
14
|
+
{
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/prompt-submit.mjs\""
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"PreToolUse": [
|
|
24
|
+
{
|
|
25
|
+
"matcher": "^(exec|edit|write|read|apply_patch|grep|glob)$",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"type": "command",
|
|
29
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/pre-tool-use.mjs\""
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"PostToolUse": [
|
|
35
|
+
{
|
|
36
|
+
"matcher": "",
|
|
37
|
+
"hooks": [
|
|
38
|
+
{
|
|
39
|
+
"type": "command",
|
|
40
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-use.mjs\""
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"Stop": [
|
|
46
|
+
{
|
|
47
|
+
"matcher": "",
|
|
48
|
+
"hooks": [
|
|
49
|
+
{
|
|
50
|
+
"type": "command",
|
|
51
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/stop.mjs\""
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"SessionEnd": [
|
|
57
|
+
{
|
|
58
|
+
"hooks": [
|
|
59
|
+
{
|
|
60
|
+
"type": "command",
|
|
61
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-end.mjs\""
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-start.mjs\""
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"UserPromptSubmit": [
|
|
14
|
+
{
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/prompt-submit.mjs\""
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"PreToolUse": [
|
|
24
|
+
{
|
|
25
|
+
"matcher": "Edit|Create|Read|Glob|Grep",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"type": "command",
|
|
29
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/pre-tool-use.mjs\""
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"PostToolUse": [
|
|
35
|
+
{
|
|
36
|
+
"hooks": [
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-use.mjs\""
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"SessionEnd": [
|
|
45
|
+
{
|
|
46
|
+
"hooks": [
|
|
47
|
+
{
|
|
48
|
+
"type": "command",
|
|
49
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-end.mjs\""
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<img src="https://img.shields.io/badge/MCP-
|
|
12
|
+
<img src="https://img.shields.io/badge/MCP-54_tools-1f6feb?style=flat-square" alt="54 MCP tools" />
|
|
13
13
|
<img src="https://img.shields.io/badge/Plugin-22_hooks-1f6feb?style=flat-square" alt="22 hooks" />
|
|
14
14
|
<img src="https://img.shields.io/badge/Commands-2_slash-1f6feb?style=flat-square" alt="2 slash commands" />
|
|
15
15
|
<img src="https://img.shields.io/badge/R@5-95.2%25-00875f?style=flat-square" alt="95.2% R@5" />
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { basename } from "node:path";
|
|
2
4
|
|
|
3
5
|
const API = process.env.AGENTMEMORY_URL || "http://localhost:3111";
|
|
4
|
-
|
|
6
|
+
// OpenCode reports tool names in lowercase ("read", "edit", ...); matching is
|
|
7
|
+
// case-insensitive at the call site so a future casing change cannot silently
|
|
8
|
+
// kill file enrichment again.
|
|
9
|
+
const FILE_TOOLS = new Set(["read", "write", "edit", "glob", "grep"]);
|
|
5
10
|
const FILE_KEYS = ["filePath", "file_path", "path", "file", "pattern"];
|
|
6
11
|
const MAX_STASHED_FILES = 20;
|
|
7
12
|
|
|
@@ -47,11 +52,12 @@ async function observe(
|
|
|
47
52
|
hookType: string,
|
|
48
53
|
data: Record<string, unknown>,
|
|
49
54
|
): Promise<void> {
|
|
55
|
+
const proj = projectFor(sessionId);
|
|
50
56
|
await post("/observe", {
|
|
51
57
|
hookType,
|
|
52
58
|
sessionId,
|
|
53
|
-
project:
|
|
54
|
-
cwd:
|
|
59
|
+
project: proj.name,
|
|
60
|
+
cwd: proj.cwd,
|
|
55
61
|
timestamp: new Date().toISOString(),
|
|
56
62
|
data,
|
|
57
63
|
});
|
|
@@ -59,7 +65,46 @@ async function observe(
|
|
|
59
65
|
|
|
60
66
|
let activeSessionId: string | null = null;
|
|
61
67
|
let pendingConfig: Record<string, unknown> | null = null;
|
|
62
|
-
|
|
68
|
+
// Default scope resolved at plugin init (same resolution order as the hooks'
|
|
69
|
+
// resolveProject: env override, git toplevel basename, cwd basename). In a
|
|
70
|
+
// long-lived OpenCode process serving multiple directories these defaults are
|
|
71
|
+
// only a fallback — attribution is per-session via sessionProjects, resolved
|
|
72
|
+
// from each session's own directory at session.created. Module-level-only
|
|
73
|
+
// state recorded home-directory sessions under whatever repo loaded first.
|
|
74
|
+
let defaultProjectName: string | null = null;
|
|
75
|
+
let defaultProjectCwd: string | null = null;
|
|
76
|
+
const sessionProjects = new Map<string, { name: string; cwd: string }>();
|
|
77
|
+
|
|
78
|
+
function projectFor(sessionId: string): { name: string | null; cwd: string | null } {
|
|
79
|
+
const p = sessionProjects.get(sessionId);
|
|
80
|
+
return p ?? { name: defaultProjectName, cwd: defaultProjectCwd };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const projectNameCache = new Map<string, string>();
|
|
84
|
+
|
|
85
|
+
function resolveProjectName(dir: string): string {
|
|
86
|
+
const explicit = process.env.AGENTMEMORY_PROJECT_NAME?.trim();
|
|
87
|
+
if (explicit) return explicit;
|
|
88
|
+
const cached = projectNameCache.get(dir);
|
|
89
|
+
if (cached !== undefined) return cached;
|
|
90
|
+
try {
|
|
91
|
+
const top = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
92
|
+
cwd: dir,
|
|
93
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
94
|
+
encoding: "utf8",
|
|
95
|
+
}).trim();
|
|
96
|
+
if (top) {
|
|
97
|
+
const name = basename(top);
|
|
98
|
+
projectNameCache.set(dir, name);
|
|
99
|
+
return name;
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// not a git repo, fall through
|
|
103
|
+
}
|
|
104
|
+
const fallback = basename(dir) || dir;
|
|
105
|
+
projectNameCache.set(dir, fallback);
|
|
106
|
+
return fallback;
|
|
107
|
+
}
|
|
63
108
|
const stashedFiles = new Map<string, Set<string>>();
|
|
64
109
|
const seenSubtaskIds = new Map<string, Set<string>>();
|
|
65
110
|
const seenToolCallIds = new Map<string, Set<string>>();
|
|
@@ -93,6 +138,7 @@ function pruneSessionMaps(sid: string): void {
|
|
|
93
138
|
stashedFiles.delete(sid);
|
|
94
139
|
seenSubtaskIds.delete(sid);
|
|
95
140
|
seenToolCallIds.delete(sid);
|
|
141
|
+
sessionProjects.delete(sid);
|
|
96
142
|
}
|
|
97
143
|
|
|
98
144
|
function safeSlice(v: unknown, max: number): string {
|
|
@@ -168,7 +214,8 @@ function extractErrorMessage(err: unknown): string {
|
|
|
168
214
|
}
|
|
169
215
|
|
|
170
216
|
export const AgentmemoryCapturePlugin: Plugin = async (ctx) => {
|
|
171
|
-
|
|
217
|
+
defaultProjectCwd = ctx.worktree || ctx.project?.id || process.cwd();
|
|
218
|
+
defaultProjectName = resolveProjectName(defaultProjectCwd);
|
|
172
219
|
|
|
173
220
|
return {
|
|
174
221
|
event: async ({ event }) => {
|
|
@@ -188,13 +235,28 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => {
|
|
|
188
235
|
// and another `session.created` event during the await could
|
|
189
236
|
// rebind it, causing context to be cached against the wrong key.
|
|
190
237
|
const sessionId = activeSessionId;
|
|
238
|
+
// Attribute this session to its own directory when the event
|
|
239
|
+
// carries one; a multi-directory OpenCode process otherwise
|
|
240
|
+
// records every session under whichever repo loaded the plugin.
|
|
241
|
+
const sessionDir =
|
|
242
|
+
typeof info?.directory === "string" && info.directory
|
|
243
|
+
? info.directory
|
|
244
|
+
: defaultProjectCwd;
|
|
245
|
+
let proj: { name: string | null; cwd: string | null };
|
|
246
|
+
if (sessionDir) {
|
|
247
|
+
const entry = { cwd: sessionDir, name: resolveProjectName(sessionDir) };
|
|
248
|
+
sessionProjects.set(sessionId, entry);
|
|
249
|
+
proj = entry;
|
|
250
|
+
} else {
|
|
251
|
+
proj = projectFor(sessionId);
|
|
252
|
+
}
|
|
191
253
|
const startResult = await postJson("/session/start", {
|
|
192
254
|
sessionId,
|
|
193
255
|
title: info?.title ?? null,
|
|
194
256
|
parentID: info?.parentID ?? null,
|
|
195
257
|
version: info?.version ?? null,
|
|
196
|
-
project:
|
|
197
|
-
cwd:
|
|
258
|
+
project: proj.name,
|
|
259
|
+
cwd: proj.cwd,
|
|
198
260
|
});
|
|
199
261
|
// cache the context returned at session/start so the
|
|
200
262
|
// chat.system.transform hook injects it without a second fetch.
|
|
@@ -272,10 +334,8 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => {
|
|
|
272
334
|
post("/crystals/auto", { olderThanDays: 7 }, 30000);
|
|
273
335
|
post("/consolidate-pipeline", { tier: "all", force: true }, 30000);
|
|
274
336
|
if (sid === activeSessionId) activeSessionId = null;
|
|
275
|
-
|
|
337
|
+
pruneSessionMaps(sid);
|
|
276
338
|
startContextCache.delete(sid);
|
|
277
|
-
seenSubtaskIds.delete(sid);
|
|
278
|
-
seenToolCallIds.delete(sid);
|
|
279
339
|
contextInjectedSessions.delete(sid);
|
|
280
340
|
}
|
|
281
341
|
|
|
@@ -581,7 +641,7 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => {
|
|
|
581
641
|
|
|
582
642
|
// ── tool.execute.before ──
|
|
583
643
|
"tool.execute.before": async (input, output) => {
|
|
584
|
-
if (!FILE_TOOLS.has(input.tool)) return;
|
|
644
|
+
if (!FILE_TOOLS.has(String(input.tool ?? "").toLowerCase())) return;
|
|
585
645
|
const sid = input.sessionID || activeSessionId;
|
|
586
646
|
if (!sid) return;
|
|
587
647
|
const args = output.args as Record<string, unknown> | undefined;
|
|
@@ -612,7 +672,7 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => {
|
|
|
612
672
|
if (typeof ctx !== "string" || ctx.length === 0) {
|
|
613
673
|
const result = await postJson("/context", {
|
|
614
674
|
sessionId: sid,
|
|
615
|
-
project:
|
|
675
|
+
project: projectFor(sid).name,
|
|
616
676
|
});
|
|
617
677
|
ctx = (result as any)?.context;
|
|
618
678
|
} else {
|
|
@@ -650,7 +710,7 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => {
|
|
|
650
710
|
|
|
651
711
|
const result = await postJson("/context", {
|
|
652
712
|
sessionId: sid,
|
|
653
|
-
project:
|
|
713
|
+
project: projectFor(sid).name,
|
|
654
714
|
});
|
|
655
715
|
const ctx = (result as any)?.context;
|
|
656
716
|
if (typeof ctx === "string" && ctx.length > 0) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentmemory-capture",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.29",
|
|
4
4
|
"description": "OpenCode plugin for agentmemory — full Claude Code hook parity: session lifecycle (create/idle/status/compacted/update/diff/delete/error), messages & prompts (chat.message, message.updated user+assistant, message.removed), tool lifecycle (ToolPart states with timing), part tracking (subtask, step-finish, reasoning, file, patch, compaction, agent, retry), file enrichment pipeline, permissions, task tracking (w/ priority), commands, config & model tracking. 22 hooks, 2 slash commands.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rohit Ghumare",
|
package/plugin/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentmemory",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"description": "Persistent memory for AI coding agents -- captures tool usage, compresses via LLM, injects context into future sessions. 12 hooks,
|
|
3
|
+
"version": "0.9.29",
|
|
4
|
+
"description": "Persistent memory for AI coding agents -- captures tool usage, compresses via LLM, injects context into future sessions. 12 hooks, 54 MCP tools, 17 skills, real-time viewer.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rohit Ghumare",
|
|
7
7
|
"url": "https://github.com/rohitg00"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/hooks/antigravity-bridge.d.ts
|
|
2
|
+
type Json = Record<string, unknown>;
|
|
3
|
+
declare function normalizePayload(event: string, raw: Json): Json;
|
|
4
|
+
declare function targetsFor(event: string, raw: Json): string[];
|
|
5
|
+
declare function responseFor(event: string): string;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { normalizePayload, responseFor, targetsFor };
|
|
8
|
+
//# sourceMappingURL=antigravity-bridge.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-bridge.d.mts","names":[],"sources":["../../src/hooks/antigravity-bridge.ts"],"mappings":";KAkDK,IAAA,GAAO,MAAA;AAAA,iBA2BI,gBAAA,CAAiB,KAAA,UAAe,GAAA,EAAK,IAAA,GAAO,IAAA;AAAA,iBAsD5C,UAAA,CAAW,KAAA,UAAe,GAAA,EAAK,IAAA;AAAA,iBAwB/B,WAAA,CAAY,KAAA"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
//#region src/hooks/antigravity-bridge.ts
|
|
6
|
+
const SCRIPTS_DIR = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const TOOL_NAME_MAP = {
|
|
8
|
+
view_file: "read",
|
|
9
|
+
view_line_range: "read",
|
|
10
|
+
view_code_item: "read",
|
|
11
|
+
read_file: "read",
|
|
12
|
+
read_url_content: "read",
|
|
13
|
+
edit_file: "edit",
|
|
14
|
+
replace_file_content: "edit",
|
|
15
|
+
propose_code: "edit",
|
|
16
|
+
write_to_file: "write",
|
|
17
|
+
create_file: "write",
|
|
18
|
+
grep_search: "grep",
|
|
19
|
+
codebase_search: "grep",
|
|
20
|
+
find_by_name: "glob",
|
|
21
|
+
list_dir: "glob"
|
|
22
|
+
};
|
|
23
|
+
const ARG_KEY_MAP = {
|
|
24
|
+
AbsolutePath: "file_path",
|
|
25
|
+
TargetFile: "file_path",
|
|
26
|
+
DirectoryPath: "path",
|
|
27
|
+
SearchDirectory: "path",
|
|
28
|
+
Pattern: "pattern",
|
|
29
|
+
Query: "pattern",
|
|
30
|
+
CommandLine: "command"
|
|
31
|
+
};
|
|
32
|
+
function asObject(value) {
|
|
33
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
34
|
+
}
|
|
35
|
+
function firstString(...values) {
|
|
36
|
+
for (const v of values) if (typeof v === "string" && v.length > 0) return v;
|
|
37
|
+
}
|
|
38
|
+
function normalizeToolArgs(args) {
|
|
39
|
+
if (!args) return {};
|
|
40
|
+
const out = { ...args };
|
|
41
|
+
for (const [from, to] of Object.entries(ARG_KEY_MAP)) if (out[to] === void 0 && args[from] !== void 0) out[to] = args[from];
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
function normalizePayload(event, raw) {
|
|
45
|
+
const toolCall = asObject(raw["toolCall"]);
|
|
46
|
+
const workspacePaths = Array.isArray(raw["workspacePaths"]) ? raw["workspacePaths"] : [];
|
|
47
|
+
const sessionId = firstString(raw["conversationId"], raw["session_id"], raw["sessionId"]) ?? "unknown";
|
|
48
|
+
const cwd = firstString(raw["cwd"], workspacePaths[0]) ?? process.cwd();
|
|
49
|
+
const out = {
|
|
50
|
+
...raw,
|
|
51
|
+
session_id: sessionId,
|
|
52
|
+
cwd,
|
|
53
|
+
hook_event_name: event
|
|
54
|
+
};
|
|
55
|
+
const transcriptPath = firstString(raw["transcript_path"], raw["transcriptPath"]);
|
|
56
|
+
if (transcriptPath) out["transcript_path"] = transcriptPath;
|
|
57
|
+
if (toolCall) {
|
|
58
|
+
const args = normalizeToolArgs(asObject(toolCall["args"]) ?? asObject(toolCall["toolArgs"]));
|
|
59
|
+
const rawName = firstString(toolCall["name"], toolCall["toolName"], args["ToolName"], args["toolName"]);
|
|
60
|
+
if (rawName) {
|
|
61
|
+
out["tool_name"] = TOOL_NAME_MAP[rawName] ?? rawName;
|
|
62
|
+
out["native_tool_name"] = rawName;
|
|
63
|
+
}
|
|
64
|
+
out["tool_input"] = args;
|
|
65
|
+
const result = toolCall["result"] ?? raw["toolResult"] ?? raw["result"];
|
|
66
|
+
if (result !== void 0) out["tool_result"] = result;
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function targetsFor(event, raw) {
|
|
71
|
+
switch (event) {
|
|
72
|
+
case "PreInvocation": {
|
|
73
|
+
const n = raw["invocationNum"];
|
|
74
|
+
return typeof n !== "number" || n <= 1 ? ["session-start.mjs", "prompt-submit.mjs"] : ["prompt-submit.mjs"];
|
|
75
|
+
}
|
|
76
|
+
case "PreToolUse": return ["pre-tool-use.mjs"];
|
|
77
|
+
case "PostToolUse": return ["post-tool-use.mjs"];
|
|
78
|
+
case "Stop": return ["stop.mjs", "session-end.mjs"];
|
|
79
|
+
default: return [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function responseFor(event) {
|
|
83
|
+
return event === "PreToolUse" ? "{\"decision\":\"allow\"}" : "{}";
|
|
84
|
+
}
|
|
85
|
+
async function main() {
|
|
86
|
+
const event = process.argv[2];
|
|
87
|
+
if (!event) return;
|
|
88
|
+
let input = "";
|
|
89
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
90
|
+
let raw;
|
|
91
|
+
try {
|
|
92
|
+
raw = JSON.parse(input);
|
|
93
|
+
} catch {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!raw || typeof raw !== "object") return;
|
|
97
|
+
const payload = JSON.stringify(normalizePayload(event, raw));
|
|
98
|
+
for (const script of targetsFor(event, raw)) spawnSync(process.execPath, [join(SCRIPTS_DIR, script)], {
|
|
99
|
+
input: payload,
|
|
100
|
+
stdio: [
|
|
101
|
+
"pipe",
|
|
102
|
+
"ignore",
|
|
103
|
+
"ignore"
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (process.argv[1] !== void 0 && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main().catch(() => {}).finally(() => {
|
|
108
|
+
process.stdout.write(responseFor(process.argv[2] ?? ""));
|
|
109
|
+
process.exit(0);
|
|
110
|
+
});
|
|
111
|
+
//#endregion
|
|
112
|
+
export { normalizePayload, responseFor, targetsFor };
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=antigravity-bridge.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-bridge.mjs","names":[],"sources":["../../src/hooks/antigravity-bridge.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawnSync } from \"node:child_process\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Antigravity CLI (`agy`) bridge — sits in front of the canonical hooks\n// because three parts of agy's contract make them unusable as direct\n// `command` targets: only five events exist (no SessionStart/SessionEnd/\n// UserPromptSubmit, so the lifecycle is synthesized from PreInvocation and\n// Stop); the payload is camelCase and nests tool calls under `toolCall`; and\n// stdout must be a JSON object, which `pre-tool-use.mjs` breaks when\n// AGENTMEMORY_INJECT_CONTEXT=true makes it write raw context text.\n//\n// Invoked as: node antigravity-bridge.mjs <PreInvocation|PreToolUse|PostToolUse|Stop>\n// Sources: antigravity.google/docs/hooks, antigravity.google/docs/cli/using\n\nconst SCRIPTS_DIR = dirname(fileURLToPath(import.meta.url));\n\n// Antigravity inherits Cascade-style tool names. Map them onto the tool\n// vocabulary pre-tool-use.ts / post-tool-use.ts already understand so the\n// existing file-activity heuristics keep working unchanged.\nconst TOOL_NAME_MAP: Record<string, string> = {\n view_file: \"read\",\n view_line_range: \"read\",\n view_code_item: \"read\",\n read_file: \"read\",\n read_url_content: \"read\",\n edit_file: \"edit\",\n replace_file_content: \"edit\",\n propose_code: \"edit\",\n write_to_file: \"write\",\n create_file: \"write\",\n grep_search: \"grep\",\n codebase_search: \"grep\",\n find_by_name: \"glob\",\n list_dir: \"glob\",\n};\n\n// Antigravity tool args are PascalCase; the canonical hooks look for\n// snake_case keys. Only the keys those hooks actually read are mapped.\nconst ARG_KEY_MAP: Record<string, string> = {\n AbsolutePath: \"file_path\",\n TargetFile: \"file_path\",\n DirectoryPath: \"path\",\n SearchDirectory: \"path\",\n Pattern: \"pattern\",\n Query: \"pattern\",\n CommandLine: \"command\",\n};\n\ntype Json = Record<string, unknown>;\n\nfunction asObject(value: unknown): Json | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Json)\n : undefined;\n}\n\nfunction firstString(...values: unknown[]): string | undefined {\n for (const v of values) {\n if (typeof v === \"string\" && v.length > 0) return v;\n }\n return undefined;\n}\n\nfunction normalizeToolArgs(args: Json | undefined): Json {\n if (!args) return {};\n const out: Json = { ...args };\n for (const [from, to] of Object.entries(ARG_KEY_MAP)) {\n if (out[to] === undefined && args[from] !== undefined) out[to] = args[from];\n }\n return out;\n}\n\n// Translate one Antigravity hook payload into the flat, snake_case shape the\n// bundled hooks consume. Unknown fields pass through so future Antigravity\n// additions stay visible to the capture pipeline.\nexport function normalizePayload(event: string, raw: Json): Json {\n const toolCall = asObject(raw[\"toolCall\"]);\n const workspacePaths = Array.isArray(raw[\"workspacePaths\"])\n ? (raw[\"workspacePaths\"] as unknown[])\n : [];\n\n const sessionId =\n firstString(raw[\"conversationId\"], raw[\"session_id\"], raw[\"sessionId\"]) ??\n \"unknown\";\n const cwd =\n firstString(raw[\"cwd\"], workspacePaths[0]) ?? process.cwd();\n\n const out: Json = {\n ...raw,\n session_id: sessionId,\n cwd,\n hook_event_name: event,\n };\n\n const transcriptPath = firstString(\n raw[\"transcript_path\"],\n raw[\"transcriptPath\"],\n );\n if (transcriptPath) out[\"transcript_path\"] = transcriptPath;\n\n if (toolCall) {\n const args = normalizeToolArgs(\n asObject(toolCall[\"args\"]) ?? asObject(toolCall[\"toolArgs\"]),\n );\n const rawName = firstString(\n toolCall[\"name\"],\n toolCall[\"toolName\"],\n args[\"ToolName\"],\n args[\"toolName\"],\n );\n if (rawName) {\n out[\"tool_name\"] = TOOL_NAME_MAP[rawName] ?? rawName;\n // Keep the host-native name so captured observations stay traceable\n // back to the tool Antigravity actually ran.\n out[\"native_tool_name\"] = rawName;\n }\n out[\"tool_input\"] = args;\n const result = toolCall[\"result\"] ?? raw[\"toolResult\"] ?? raw[\"result\"];\n if (result !== undefined) out[\"tool_result\"] = result;\n }\n\n return out;\n}\n\n// Map an Antigravity event to the bundled scripts it should drive.\n// PreInvocation stands in for both SessionStart and UserPromptSubmit: the\n// first invocation of a conversation opens the session, every later one is a\n// fresh user turn. PostInvocation is deliberately unmapped — PostToolUse\n// already captures the work, and firing again would double-record it.\nexport function targetsFor(event: string, raw: Json): string[] {\n switch (event) {\n case \"PreInvocation\": {\n const n = raw[\"invocationNum\"];\n const isFirst = typeof n !== \"number\" || n <= 1;\n return isFirst\n ? [\"session-start.mjs\", \"prompt-submit.mjs\"]\n : [\"prompt-submit.mjs\"];\n }\n case \"PreToolUse\":\n return [\"pre-tool-use.mjs\"];\n case \"PostToolUse\":\n return [\"post-tool-use.mjs\"];\n case \"Stop\":\n return [\"stop.mjs\", \"session-end.mjs\"];\n default:\n return [];\n }\n}\n\n// The stdout contract, per event. agy treats a PreToolUse response without\n// `decision` as a denial, so a bare `{}` there makes it refuse every matched\n// tool call (verified on 1.0.15). No other event carries a permission\n// decision, so they stay on `{}` — sending one would override user settings.\nexport function responseFor(event: string): string {\n return event === \"PreToolUse\" ? '{\"decision\":\"allow\"}' : \"{}\";\n}\n\nasync function main() {\n const event = process.argv[2];\n if (!event) return;\n\n let input = \"\";\n for await (const chunk of process.stdin) {\n input += chunk;\n }\n\n let raw: Json;\n try {\n raw = JSON.parse(input) as Json;\n } catch {\n return;\n }\n if (!raw || typeof raw !== \"object\") return;\n\n const payload = JSON.stringify(normalizePayload(event, raw));\n\n for (const script of targetsFor(event, raw)) {\n // Synchronous so the hook process does not exit before the capture\n // POSTs are issued. Each bundled hook already caps its own fetch\n // timeout, so the worst case here is bounded by those.\n spawnSync(process.execPath, [join(SCRIPTS_DIR, script)], {\n input: payload,\n // Child stdout is discarded on purpose: Antigravity parses this\n // process's stdout as the hook response, and the bundled scripts\n // emit prose when context injection is enabled.\n stdio: [\"pipe\", \"ignore\", \"ignore\"],\n });\n }\n}\n\n// Guarded so the pure helpers above stay importable from tests without the\n// module blocking on stdin. Every other bundled hook is a leaf script and\n// needs no such guard.\nconst invokedDirectly =\n process.argv[1] !== undefined &&\n resolve(process.argv[1]) === fileURLToPath(import.meta.url);\n\nif (invokedDirectly) {\n main()\n .catch(() => {})\n .finally(() => {\n // Always a well-formed, non-blocking response, emitted even when the\n // capture above threw or the payload was unparseable — a hook that\n // writes nothing is as fatal to PreToolUse as one that writes `{}`.\n process.stdout.write(responseFor(process.argv[2] ?? \"\"));\n process.exit(0);\n });\n}\n"],"mappings":"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"}
|
|
@@ -20,6 +20,16 @@ function resolveProject(cwd) {
|
|
|
20
20
|
} catch {}
|
|
21
21
|
return basename(dir);
|
|
22
22
|
}
|
|
23
|
+
function hookCwd(data) {
|
|
24
|
+
if (!data || typeof data !== "object") return void 0;
|
|
25
|
+
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
26
|
+
const roots = data.workspace_roots;
|
|
27
|
+
if (Array.isArray(roots)) {
|
|
28
|
+
for (const root of roots) if (typeof root === "string" && root.trim()) return root;
|
|
29
|
+
}
|
|
30
|
+
const projectDir = process.env["DEVIN_PROJECT_DIR"] || process.env["CLAUDE_PROJECT_DIR"];
|
|
31
|
+
if (projectDir && projectDir.trim()) return projectDir;
|
|
32
|
+
}
|
|
23
33
|
//#endregion
|
|
24
34
|
//#region src/hooks/notification.ts
|
|
25
35
|
function isSdkChildContext(payload) {
|
|
@@ -43,19 +53,25 @@ async function main() {
|
|
|
43
53
|
} catch {
|
|
44
54
|
return;
|
|
45
55
|
}
|
|
56
|
+
if (!data || typeof data !== "object") return;
|
|
46
57
|
if (isSdkChildContext(data)) return;
|
|
47
58
|
const notificationType = data.notification_type ?? data.notificationType;
|
|
48
59
|
if (notificationType !== "permission_prompt") return;
|
|
49
|
-
const rawSessionId =
|
|
50
|
-
|
|
60
|
+
const rawSessionId = [
|
|
61
|
+
data.session_id,
|
|
62
|
+
data.sessionId,
|
|
63
|
+
data.conversation_id
|
|
64
|
+
].find((v) => typeof v === "string" && v.length > 0);
|
|
65
|
+
const sessionId = typeof rawSessionId === "string" ? rawSessionId : "unknown";
|
|
66
|
+
const cwd = hookCwd(data) || process.cwd();
|
|
51
67
|
fetch(`${REST_URL}/agentmemory/observe`, {
|
|
52
68
|
method: "POST",
|
|
53
69
|
headers: authHeaders(),
|
|
54
70
|
body: JSON.stringify({
|
|
55
71
|
hookType: "notification",
|
|
56
72
|
sessionId,
|
|
57
|
-
project: resolveProject(
|
|
58
|
-
cwd
|
|
73
|
+
project: resolveProject(cwd),
|
|
74
|
+
cwd,
|
|
59
75
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
60
76
|
data: {
|
|
61
77
|
notification_type: notificationType,
|
|
@@ -67,7 +83,7 @@ async function main() {
|
|
|
67
83
|
}).catch(() => {});
|
|
68
84
|
setTimeout(() => process.exit(0), 500).unref();
|
|
69
85
|
}
|
|
70
|
-
main();
|
|
86
|
+
main().catch(() => process.exit(0));
|
|
71
87
|
//#endregion
|
|
72
88
|
export {};
|
|
73
89
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/notification.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","#!/usr/bin/env node\nimport { resolveProject } from \"./_project.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 REST_URL = process.env[\"AGENTMEMORY_URL\"] || \"http://localhost:3111\";\nconst SECRET = process.env[\"AGENTMEMORY_SECRET\"] || \"\";\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\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 (isSdkChildContext(data)) return;\n const notificationType = data.notification_type ?? data.notificationType;\n if (notificationType !== \"permission_prompt\") return;\n\n const rawSessionId = data.session_id
|
|
1
|
+
{"version":3,"file":"notification.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/notification.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 { resolveProject, hookCwd } from \"./_project.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 REST_URL = process.env[\"AGENTMEMORY_URL\"] || \"http://localhost:3111\";\nconst SECRET = process.env[\"AGENTMEMORY_SECRET\"] || \"\";\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\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 const notificationType = data.notification_type ?? data.notificationType;\n if (notificationType !== \"permission_prompt\") return;\n\n const rawSessionId = [data.session_id, data.sessionId, data.conversation_id].find(\n (v) => typeof v === \"string\" && v.length > 0,\n );\n const sessionId = typeof rawSessionId === \"string\" ? rawSessionId : \"unknown\";\n\n const cwd = hookCwd(data) || process.cwd();\n\n fetch(`${REST_URL}/agentmemory/observe`, {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({\n hookType: \"notification\",\n sessionId,\n project: resolveProject(cwd),\n cwd,\n timestamp: new Date().toISOString(),\n data: {\n notification_type: notificationType,\n title: data.title,\n message: data.message,\n },\n }),\n signal: AbortSignal.timeout(2000),\n }).catch(() => {});\n setTimeout(() => process.exit(0), 500).unref();\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":";;;;AAIA,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,MAAM,SAAS,iCAAiC;GACpD,KAAK;GACL,OAAO;IAAC;IAAU;IAAQ;IAAS;GACnC,SAAS;GACV,CAAC,CACC,UAAU,CACV,MAAM;AACT,MAAI,IAAK,QAAO,SAAS,IAAI;SACvB;AACR,QAAO,SAAS,IAAI;;AAGtB,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;;;;AC7B9C,SAAS,kBAAkB,SAA2B;AACpD,KAAI,QAAQ,IAAI,6BAA6B,IAAK,QAAO;AACzD,KAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAQ,QAAqC,eAAe;;AAG9D,MAAM,WAAW,QAAQ,IAAI,sBAAsB;AACnD,MAAM,SAAS,QAAQ,IAAI,yBAAyB;AAEpD,SAAS,cAAsC;CAC7C,MAAM,IAA4B,EAAE,gBAAgB,oBAAoB;AACxE,KAAI,OAAQ,GAAE,mBAAmB,UAAU;AAC3C,QAAO;;AAGT,eAAe,OAAO;CACpB,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;CAC7B,MAAM,mBAAmB,KAAK,qBAAqB,KAAK;AACxD,KAAI,qBAAqB,oBAAqB;CAE9C,MAAM,eAAe;EAAC,KAAK;EAAY,KAAK;EAAW,KAAK;EAAgB,CAAC,MAC1E,MAAM,OAAO,MAAM,YAAY,EAAE,SAAS,EAC5C;CACD,MAAM,YAAY,OAAO,iBAAiB,WAAW,eAAe;CAEpE,MAAM,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAK;AAE1C,OAAM,GAAG,SAAS,uBAAuB;EACvC,QAAQ;EACR,SAAS,aAAa;EACtB,MAAM,KAAK,UAAU;GACnB,UAAU;GACV;GACA,SAAS,eAAe,IAAI;GAC5B;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,MAAM;IACJ,mBAAmB;IACnB,OAAO,KAAK;IACZ,SAAS,KAAK;IACf;GACF,CAAC;EACF,QAAQ,YAAY,QAAQ,IAAK;EAClC,CAAC,CAAC,YAAY,GAAG;AAClB,kBAAiB,QAAQ,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO;;AAGhD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|