@agentmemory/agentmemory 0.9.28 → 0.9.30
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 +98 -28
- package/AGENTS.md +19 -26
- package/README.md +619 -274
- package/dist/.env.example +98 -28
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +1328 -244
- package/dist/cli.mjs.map +1 -1
- package/dist/{connect-JnsJXc68.mjs → connect-B4_ca6BD.mjs} +619 -70
- package/dist/connect-B4_ca6BD.mjs.map +1 -0
- package/dist/docker-compose.yml +42 -16
- package/dist/hooks/_capture.d.mts +22 -0
- package/dist/hooks/_capture.d.mts.map +1 -0
- package/dist/hooks/_capture.mjs +908 -0
- package/dist/hooks/_capture.mjs.map +1 -0
- 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 +123 -0
- package/dist/hooks/antigravity-bridge.mjs.map +1 -0
- package/dist/hooks/notification.mjs +34 -27
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +84 -2
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +71 -26
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +99 -36
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +95 -5
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +72 -2
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +25 -22
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +93 -24
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +101 -6
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +72 -8
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +28 -26
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +29 -26
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +31 -28
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/iii-config.docker.yaml +10 -10
- package/dist/iii-config.yaml +3 -1
- package/dist/{image-refs-BKLmp_sD.mjs → image-refs-BaT-9oMU.mjs} +2 -2
- package/dist/image-refs-BaT-9oMU.mjs.map +1 -0
- package/dist/{image-refs-C2YU7BIm.mjs → image-refs-T_urbwHM.mjs} +3 -3
- package/dist/image-refs-T_urbwHM.mjs.map +1 -0
- package/dist/{keyed-mutex-DTHtcZrt.mjs → image-store-BsN4vyjr.mjs} +2 -14
- package/dist/image-store-BsN4vyjr.mjs.map +1 -0
- package/dist/index.mjs +14021 -6494
- package/dist/index.mjs.map +1 -1
- package/dist/keyed-mutex-DchXsyfP.mjs +221 -0
- package/dist/keyed-mutex-DchXsyfP.mjs.map +1 -0
- package/dist/secret-store-BnY3A50C.mjs +2348 -0
- package/dist/secret-store-BnY3A50C.mjs.map +1 -0
- package/dist/{src-CzgoepGU.mjs → src-Jsq9LCeH.mjs} +7349 -2940
- package/dist/src-Jsq9LCeH.mjs.map +1 -0
- package/dist/{standalone-YsZFFQBM.mjs → standalone-DKCdrf1d.mjs} +62 -24
- package/dist/standalone-DKCdrf1d.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +298 -27
- package/dist/standalone.mjs.map +1 -1
- package/dist/status-IRz7ta8-.mjs +2344 -0
- package/dist/status-IRz7ta8-.mjs.map +1 -0
- package/dist/viewer/favicon.svg +35 -1
- package/dist/viewer/index.html +7428 -2608
- package/docker-compose.yml +42 -16
- package/iii-config.docker.yaml +10 -10
- package/iii-config.yaml +3 -1
- package/integrations/pi/README.md +77 -0
- package/integrations/pi/index.ts +402 -0
- package/integrations/pi/package.json +32 -0
- package/integrations/pi/security.ts +87 -0
- package/package.json +15 -7
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +26 -4
- package/plugin/.devin-plugin/plugin.json +32 -0
- package/plugin/.mcp.codex.json +12 -0
- package/plugin/.mcp.copilot.json +2 -7
- package/plugin/.mcp.json +2 -7
- package/plugin/assets/icon.svg +35 -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.copilot.json +11 -11
- package/plugin/hooks/hooks.devin.json +67 -0
- package/plugin/hooks/hooks.droid.json +55 -0
- package/plugin/opencode/README.md +267 -31
- package/plugin/opencode/agentmemory-capture.ts +644 -15
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +2 -2
- package/plugin/scripts/_capture.d.mts +22 -0
- package/plugin/scripts/_capture.d.mts.map +1 -0
- package/plugin/scripts/_capture.mjs +908 -0
- package/plugin/scripts/_capture.mjs.map +1 -0
- 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 +123 -0
- package/plugin/scripts/antigravity-bridge.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +34 -27
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +378 -0
- package/plugin/scripts/post-commit.mjs +84 -2
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +71 -26
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +99 -36
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +95 -5
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +72 -2
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +25 -22
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +93 -24
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +101 -6
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +72 -8
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +28 -26
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +29 -26
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +31 -28
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +22 -6
- package/plugin/skills/agentmemory-agents/REFERENCE.md +8 -5
- package/plugin/skills/agentmemory-config/REFERENCE.md +52 -1
- package/plugin/skills/agentmemory-config/SKILL.md +44 -7
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +4 -3
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +23 -2
- package/plugin/skills/forget/SKILL.md +4 -1
- package/plugin/skills/handoff/SKILL.md +4 -2
- package/plugin/skills/lesson/SKILL.md +64 -0
- package/plugin/skills/memory-discipline/SKILL.md +65 -0
- package/plugin/skills/recall/SKILL.md +4 -1
- package/plugin/skills/remember/SKILL.md +6 -1
- package/dist/config-ChC9EtgV.mjs +0 -259
- package/dist/config-ChC9EtgV.mjs.map +0 -1
- package/dist/connect-JnsJXc68.mjs.map +0 -1
- package/dist/image-refs-BKLmp_sD.mjs.map +0 -1
- package/dist/image-refs-C2YU7BIm.mjs.map +0 -1
- package/dist/keyed-mutex-DTHtcZrt.mjs.map +0 -1
- package/dist/logger-BEB7pCI9.mjs +0 -43
- package/dist/logger-BEB7pCI9.mjs.map +0 -1
- package/dist/schema-CNiCWzV9.mjs +0 -78
- package/dist/schema-CNiCWzV9.mjs.map +0 -1
- package/dist/src-CzgoepGU.mjs.map +0 -1
- package/dist/standalone-YsZFFQBM.mjs.map +0 -1
- package/dist/tools-registry-D3NEoe5m.mjs +0 -1115
- package/dist/tools-registry-D3NEoe5m.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
package/dist/hooks/stop.mjs
CHANGED
|
@@ -1,4 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
//#region src/secret-store.ts
|
|
6
|
+
const SECRET_KEY = "AGENTMEMORY_SECRET";
|
|
7
|
+
function agentmemoryHomeDir() {
|
|
8
|
+
return join(homedir(), ".agentmemory");
|
|
9
|
+
}
|
|
10
|
+
function secretFilePath() {
|
|
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;
|
|
31
|
+
try {
|
|
32
|
+
content = readFileSync(join(agentmemoryHomeDir(), ".env"), "utf-8");
|
|
33
|
+
} catch {
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
if (typeof content !== "string") return "";
|
|
37
|
+
let found = "";
|
|
38
|
+
for (const line of content.split("\n")) {
|
|
39
|
+
const trimmed = line.trim();
|
|
40
|
+
if (trimmed.startsWith("#")) continue;
|
|
41
|
+
const eq = trimmed.indexOf("=");
|
|
42
|
+
if (eq === -1) continue;
|
|
43
|
+
if (trimmed.slice(0, eq).replace(/^export\s+/, "").trim() !== SECRET_KEY) continue;
|
|
44
|
+
found = usable(unquote(trimmed.slice(eq + 1).trim()));
|
|
45
|
+
}
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
function readStoredSecret() {
|
|
49
|
+
try {
|
|
50
|
+
return usable(readFileSync(secretFilePath(), "utf-8"));
|
|
51
|
+
} catch {
|
|
52
|
+
return "";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isLoopbackUrl(url) {
|
|
56
|
+
let hostname;
|
|
57
|
+
try {
|
|
58
|
+
hostname = new URL(url).hostname.toLowerCase();
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const bare = hostname.replace(/^\[|\]$/g, "");
|
|
63
|
+
return bare === "localhost" || bare === "::1" || /^127(?:\.\d{1,3}){3}$/.test(bare);
|
|
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();
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
2
72
|
//#region src/hooks/stop.ts
|
|
3
73
|
function isSdkChildContext(payload) {
|
|
4
74
|
if (process.env["AGENTMEMORY_SDK_CHILD"] === "1") return true;
|
|
@@ -6,7 +76,7 @@ function isSdkChildContext(payload) {
|
|
|
6
76
|
return payload.entrypoint === "sdk-ts";
|
|
7
77
|
}
|
|
8
78
|
const REST_URL = process.env["AGENTMEMORY_URL"] || "http://localhost:3111";
|
|
9
|
-
const SECRET =
|
|
79
|
+
const SECRET = resolveClientSecret(REST_URL);
|
|
10
80
|
function authHeaders() {
|
|
11
81
|
const h = { "Content-Type": "application/json" };
|
|
12
82
|
if (SECRET) h["Authorization"] = `Bearer ${SECRET}`;
|
|
@@ -23,13 +93,7 @@ async function main() {
|
|
|
23
93
|
}
|
|
24
94
|
if (!data || typeof data !== "object") return;
|
|
25
95
|
if (isSdkChildContext(data)) return;
|
|
26
|
-
const sessionId = data.session_id || data.sessionId || "unknown";
|
|
27
|
-
fetch(`${REST_URL}/agentmemory/summarize`, {
|
|
28
|
-
method: "POST",
|
|
29
|
-
headers: authHeaders(),
|
|
30
|
-
body: JSON.stringify({ sessionId }),
|
|
31
|
-
signal: AbortSignal.timeout(12e4)
|
|
32
|
-
}).catch(() => {});
|
|
96
|
+
const sessionId = data.session_id || data.sessionId || data.conversation_id || "unknown";
|
|
33
97
|
fetch(`${REST_URL}/agentmemory/session/end`, {
|
|
34
98
|
method: "POST",
|
|
35
99
|
headers: authHeaders(),
|
package/dist/hooks/stop.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop.mjs","names":[],"sources":["../../src/hooks/stop.ts"],"sourcesContent":["#!/usr/bin/env node\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 REST_URL = process.env[\"AGENTMEMORY_URL\"] || \"http://localhost:3111\";\nconst SECRET =
|
|
1
|
+
{"version":3,"file":"stop.mjs","names":[],"sources":["../../src/secret-store.ts","../../src/hooks/stop.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","#!/usr/bin/env node\nimport { resolveClientSecret } from \"../secret-store.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 REST_URL = process.env[\"AGENTMEMORY_URL\"] || \"http://localhost:3111\";\nconst SECRET = resolveClientSecret(REST_URL);\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)) {\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\n fetch(`${REST_URL}/agentmemory/session/end`, {\n method: \"POST\",\n headers: authHeaders(),\n body: JSON.stringify({ sessionId }),\n signal: AbortSignal.timeout(5000),\n }).catch(() => {});\n\n setTimeout(() => process.exit(0), 1500).unref();\n}\n\nmain().catch(() => process.exit(0));\n"],"mappings":";;;;;AAcA,MAAM,aAAa;AAEnB,SAAgB,qBAA6B;AAC3C,QAAO,KAAK,SAAS,EAAE,eAAe;;AAGxC,SAAgB,iBAAyB;AACvC,QAAO,KAAK,oBAAoB,EAAE,SAAS;;AAG7C,SAAS,OAAO,OAAmC;AACjD,KAAI,OAAO,UAAU,SAAU,QAAO;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,QAAQ,WAAW,KAAK,IAAI,QAAQ,SAAS,IAAI,CAAE,QAAO;AAC9D,QAAO;;AAGT,SAAS,QAAQ,OAAuB;CACtC,MAAM,QAAQ,MAAM;AACpB,MAAK,UAAU,QAAO,UAAU,QAAQ,MAAM,SAAS,GAAG;EACxD,MAAM,QAAQ,MAAM,QAAQ,OAAO,EAAE;AACrC,MAAI,UAAU,GAAI,QAAO,MAAM,MAAM,GAAG,MAAM;;CAEhD,MAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,QAAO,SAAS,KAAK,QAAQ,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;;AAG1D,SAAgB,oBAA4B;CAC1C,IAAI;AACJ,KAAI;AACF,YAAU,aAAa,KAAK,oBAAoB,EAAE,OAAO,EAAE,QAAQ;SAC7D;AACN,SAAO;;AAET,KAAI,OAAO,YAAY,SAAU,QAAO;CACxC,IAAI,QAAQ;AACZ,MAAK,MAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE;EACtC,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,QAAQ,WAAW,IAAI,CAAE;EAC7B,MAAM,KAAK,QAAQ,QAAQ,IAAI;AAC/B,MAAI,OAAO,GAAI;AAEf,MADY,QAAQ,MAAM,GAAG,GAAG,CAAC,QAAQ,cAAc,GAAG,CAAC,MACpD,KAAK,WAAY;AACxB,UAAQ,OAAO,QAAQ,QAAQ,MAAM,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;;AAEvD,QAAO;;AAGT,SAAgB,mBAA2B;AACzC,KAAI;AACF,SAAO,OAAO,aAAa,gBAAgB,EAAE,QAAQ,CAAC;SAChD;AACN,SAAO;;;AAQX,SAAgB,cAAc,KAAsB;CAClD,IAAI;AACJ,KAAI;AACF,aAAW,IAAI,IAAI,IAAI,CAAC,SAAS,aAAa;SACxC;AACN,SAAO;;CAET,MAAM,OAAO,SAAS,QAAQ,YAAY,GAAG;AAC7C,QAAO,SAAS,eAAe,SAAS,SAAS,wBAAwB,KAAK,KAAK;;AAGrF,SAAgB,oBACd,SACA,MAAyB,QAAQ,KACzB;CACR,MAAM,UAAU,OAAO,IAAI,YAAY;AACvC,KAAI,QAAS,QAAO;AACpB,KAAI,CAAC,cAAc,QAAQ,CAAE,QAAO;AACpC,QAAO,mBAAmB,IAAI,kBAAkB;;;;ACvFlD,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,oBAAoB,SAAS;AAE5C,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,CAGzB;CAGF,MAAM,YAAc,KAAK,cAAc,KAAK,aAAa,KAAK,mBAA+B;AAE7F,OAAM,GAAG,SAAS,2BAA2B;EAC3C,QAAQ;EACR,SAAS,aAAa;EACtB,MAAM,KAAK,UAAU,EAAE,WAAW,CAAC;EACnC,QAAQ,YAAY,QAAQ,IAAK;EAClC,CAAC,CAAC,YAAY,GAAG;AAElB,kBAAiB,QAAQ,KAAK,EAAE,EAAE,KAAK,CAAC,OAAO;;AAGjD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
|
+
import { captureObservation, isDrainChild, runDrainChild, withEventId } from "./_capture.mjs";
|
|
4
5
|
//#region src/hooks/_project.ts
|
|
5
6
|
function resolveProject(cwd) {
|
|
6
7
|
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
|
|
@@ -20,6 +21,16 @@ function resolveProject(cwd) {
|
|
|
20
21
|
} catch {}
|
|
21
22
|
return basename(dir);
|
|
22
23
|
}
|
|
24
|
+
function hookCwd(data) {
|
|
25
|
+
if (!data || typeof data !== "object") return void 0;
|
|
26
|
+
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
27
|
+
const roots = data.workspace_roots;
|
|
28
|
+
if (Array.isArray(roots)) {
|
|
29
|
+
for (const root of roots) if (typeof root === "string" && root.trim()) return root;
|
|
30
|
+
}
|
|
31
|
+
const projectDir = process.env["DEVIN_PROJECT_DIR"] || process.env["CLAUDE_PROJECT_DIR"];
|
|
32
|
+
if (projectDir && projectDir.trim()) return projectDir;
|
|
33
|
+
}
|
|
23
34
|
//#endregion
|
|
24
35
|
//#region src/hooks/subagent-start.ts
|
|
25
36
|
function isSdkChildContext(payload) {
|
|
@@ -27,15 +38,10 @@ function isSdkChildContext(payload) {
|
|
|
27
38
|
if (!payload || typeof payload !== "object") return false;
|
|
28
39
|
return payload.entrypoint === "sdk-ts";
|
|
29
40
|
}
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const TIMEOUT_MS = 800;
|
|
33
|
-
function authHeaders() {
|
|
34
|
-
const h = { "Content-Type": "application/json" };
|
|
35
|
-
if (SECRET) h["Authorization"] = `Bearer ${SECRET}`;
|
|
36
|
-
return h;
|
|
37
|
-
}
|
|
41
|
+
const OBSERVE_TIMEOUT_MS = 800;
|
|
42
|
+
const EXIT_CAP_MS = 1300;
|
|
38
43
|
async function main() {
|
|
44
|
+
if (isDrainChild()) return runDrainChild();
|
|
39
45
|
let input = "";
|
|
40
46
|
for await (const chunk of process.stdin) input += chunk;
|
|
41
47
|
let data;
|
|
@@ -46,26 +52,22 @@ async function main() {
|
|
|
46
52
|
}
|
|
47
53
|
if (!data || typeof data !== "object") return;
|
|
48
54
|
if (isSdkChildContext(data)) return;
|
|
49
|
-
const sessionId = data.session_id || data.sessionId || "unknown";
|
|
55
|
+
const sessionId = data.session_id || data.sessionId || data.conversation_id || "unknown";
|
|
50
56
|
const agentId = data.agent_id || data.agentName;
|
|
51
57
|
const agentType = data.agent_type || data.agentDisplayName || data.agentName;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}),
|
|
66
|
-
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
67
|
-
}).catch(() => {});
|
|
68
|
-
setTimeout(() => process.exit(0), 500).unref();
|
|
58
|
+
const cwd = hookCwd(data) || process.cwd();
|
|
59
|
+
captureObservation(withEventId({
|
|
60
|
+
hookType: "subagent_start",
|
|
61
|
+
sessionId,
|
|
62
|
+
project: resolveProject(cwd),
|
|
63
|
+
cwd,
|
|
64
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65
|
+
data: {
|
|
66
|
+
agent_id: agentId,
|
|
67
|
+
agent_type: agentType
|
|
68
|
+
}
|
|
69
|
+
}, data), OBSERVE_TIMEOUT_MS);
|
|
70
|
+
setTimeout(() => process.exit(0), EXIT_CAP_MS).unref();
|
|
69
71
|
}
|
|
70
72
|
main().catch(() => process.exit(0));
|
|
71
73
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-start.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/subagent-start.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\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
|
|
1
|
+
{"version":3,"file":"subagent-start.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/subagent-start.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\";\nimport { captureObservation, isDrainChild, runDrainChild, withEventId } from \"./_capture.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 OBSERVE_TIMEOUT_MS = 800;\nconst EXIT_CAP_MS = 1300;\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 const agentId = data.agent_id || data.agentName;\n const agentType = data.agent_type || data.agentDisplayName || data.agentName;\n\n const cwd = hookCwd(data) || process.cwd();\n\n void captureObservation(\n withEventId(\n {\n hookType: \"subagent_start\",\n sessionId,\n project: resolveProject(cwd),\n cwd,\n timestamp: new Date().toISOString(),\n data: {\n agent_id: agentId,\n agent_type: agentType,\n },\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":";;;;;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;;;;AC1B9C,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;CAC7F,MAAM,UAAU,KAAK,YAAY,KAAK;CACtC,MAAM,YAAY,KAAK,cAAc,KAAK,oBAAoB,KAAK;CAEnE,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;GACJ,UAAU;GACV,YAAY;GACb;EACF,EACD,KACD,EACD,mBACD;AACD,kBAAiB,QAAQ,KAAK,EAAE,EAAE,YAAY,CAAC,OAAO;;AAGxD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
|
+
import { captureObservation, isDrainChild, runDrainChild, withEventId } from "./_capture.mjs";
|
|
4
5
|
//#region src/hooks/_project.ts
|
|
5
6
|
function resolveProject(cwd) {
|
|
6
7
|
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
|
|
@@ -20,6 +21,16 @@ function resolveProject(cwd) {
|
|
|
20
21
|
} catch {}
|
|
21
22
|
return basename(dir);
|
|
22
23
|
}
|
|
24
|
+
function hookCwd(data) {
|
|
25
|
+
if (!data || typeof data !== "object") return void 0;
|
|
26
|
+
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
27
|
+
const roots = data.workspace_roots;
|
|
28
|
+
if (Array.isArray(roots)) {
|
|
29
|
+
for (const root of roots) if (typeof root === "string" && root.trim()) return root;
|
|
30
|
+
}
|
|
31
|
+
const projectDir = process.env["DEVIN_PROJECT_DIR"] || process.env["CLAUDE_PROJECT_DIR"];
|
|
32
|
+
if (projectDir && projectDir.trim()) return projectDir;
|
|
33
|
+
}
|
|
23
34
|
//#endregion
|
|
24
35
|
//#region src/hooks/subagent-stop.ts
|
|
25
36
|
function isSdkChildContext(payload) {
|
|
@@ -27,14 +38,10 @@ function isSdkChildContext(payload) {
|
|
|
27
38
|
if (!payload || typeof payload !== "object") return false;
|
|
28
39
|
return payload.entrypoint === "sdk-ts";
|
|
29
40
|
}
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
function authHeaders() {
|
|
33
|
-
const h = { "Content-Type": "application/json" };
|
|
34
|
-
if (SECRET) h["Authorization"] = `Bearer ${SECRET}`;
|
|
35
|
-
return h;
|
|
36
|
-
}
|
|
41
|
+
const OBSERVE_TIMEOUT_MS = 2e3;
|
|
42
|
+
const EXIT_CAP_MS = 2500;
|
|
37
43
|
async function main() {
|
|
44
|
+
if (isDrainChild()) return runDrainChild();
|
|
38
45
|
let input = "";
|
|
39
46
|
for await (const chunk of process.stdin) input += chunk;
|
|
40
47
|
let data;
|
|
@@ -45,28 +52,24 @@ async function main() {
|
|
|
45
52
|
}
|
|
46
53
|
if (!data || typeof data !== "object") return;
|
|
47
54
|
if (isSdkChildContext(data)) return;
|
|
48
|
-
const sessionId = data.session_id || data.sessionId || "unknown";
|
|
55
|
+
const sessionId = data.session_id || data.sessionId || data.conversation_id || "unknown";
|
|
49
56
|
const agentId = data.agent_id || data.agentName;
|
|
50
57
|
const agentType = data.agent_type || data.agentDisplayName || data.agentName;
|
|
51
58
|
const lastMsg = typeof data.last_assistant_message === "string" ? data.last_assistant_message.slice(0, 4e3) : "";
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}),
|
|
67
|
-
signal: AbortSignal.timeout(2e3)
|
|
68
|
-
}).catch(() => {});
|
|
69
|
-
setTimeout(() => process.exit(0), 500).unref();
|
|
59
|
+
const cwd = hookCwd(data) || process.cwd();
|
|
60
|
+
captureObservation(withEventId({
|
|
61
|
+
hookType: "subagent_stop",
|
|
62
|
+
sessionId,
|
|
63
|
+
project: resolveProject(cwd),
|
|
64
|
+
cwd,
|
|
65
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
66
|
+
data: {
|
|
67
|
+
agent_id: agentId,
|
|
68
|
+
agent_type: agentType,
|
|
69
|
+
last_message: lastMsg
|
|
70
|
+
}
|
|
71
|
+
}, data), OBSERVE_TIMEOUT_MS);
|
|
72
|
+
setTimeout(() => process.exit(0), EXIT_CAP_MS).unref();
|
|
70
73
|
}
|
|
71
74
|
main().catch(() => process.exit(0));
|
|
72
75
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-stop.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/subagent-stop.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
|
|
1
|
+
{"version":3,"file":"subagent-stop.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/subagent-stop.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\";\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 = 2000;\nconst EXIT_CAP_MS = 2500;\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 const agentId = data.agent_id || data.agentName;\n const agentType = data.agent_type || data.agentDisplayName || data.agentName;\n const lastMsg =\n typeof data.last_assistant_message === \"string\"\n ? data.last_assistant_message.slice(0, 4000)\n : \"\";\n\n const cwd = hookCwd(data) || process.cwd();\n\n void captureObservation(\n withEventId(\n {\n hookType: \"subagent_stop\",\n sessionId,\n project: resolveProject(cwd),\n cwd,\n timestamp: new Date().toISOString(),\n data: {\n agent_id: agentId,\n agent_type: agentType,\n last_message: lastMsg,\n },\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":";;;;;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;;;;AC5B9C,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;CAC7F,MAAM,UAAU,KAAK,YAAY,KAAK;CACtC,MAAM,YAAY,KAAK,cAAc,KAAK,oBAAoB,KAAK;CACnE,MAAM,UACJ,OAAO,KAAK,2BAA2B,WACnC,KAAK,uBAAuB,MAAM,GAAG,IAAK,GAC1C;CAEN,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;GACJ,UAAU;GACV,YAAY;GACZ,cAAc;GACf;EACF,EACD,KACD,EACD,mBACD;AACD,kBAAiB,QAAQ,KAAK,EAAE,EAAE,YAAY,CAAC,OAAO;;AAGxD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
|
+
import { captureObservation, isDrainChild, runDrainChild, withEventId } from "./_capture.mjs";
|
|
4
5
|
//#region src/hooks/_project.ts
|
|
5
6
|
function resolveProject(cwd) {
|
|
6
7
|
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
|
|
@@ -20,6 +21,16 @@ function resolveProject(cwd) {
|
|
|
20
21
|
} catch {}
|
|
21
22
|
return basename(dir);
|
|
22
23
|
}
|
|
24
|
+
function hookCwd(data) {
|
|
25
|
+
if (!data || typeof data !== "object") return void 0;
|
|
26
|
+
if (typeof data.cwd === "string" && data.cwd.trim()) return data.cwd;
|
|
27
|
+
const roots = data.workspace_roots;
|
|
28
|
+
if (Array.isArray(roots)) {
|
|
29
|
+
for (const root of roots) if (typeof root === "string" && root.trim()) return root;
|
|
30
|
+
}
|
|
31
|
+
const projectDir = process.env["DEVIN_PROJECT_DIR"] || process.env["CLAUDE_PROJECT_DIR"];
|
|
32
|
+
if (projectDir && projectDir.trim()) return projectDir;
|
|
33
|
+
}
|
|
23
34
|
//#endregion
|
|
24
35
|
//#region src/hooks/task-completed.ts
|
|
25
36
|
function isSdkChildContext(payload) {
|
|
@@ -27,14 +38,10 @@ function isSdkChildContext(payload) {
|
|
|
27
38
|
if (!payload || typeof payload !== "object") return false;
|
|
28
39
|
return payload.entrypoint === "sdk-ts";
|
|
29
40
|
}
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
function authHeaders() {
|
|
33
|
-
const h = { "Content-Type": "application/json" };
|
|
34
|
-
if (SECRET) h["Authorization"] = `Bearer ${SECRET}`;
|
|
35
|
-
return h;
|
|
36
|
-
}
|
|
41
|
+
const OBSERVE_TIMEOUT_MS = 2e3;
|
|
42
|
+
const EXIT_CAP_MS = 2500;
|
|
37
43
|
async function main() {
|
|
44
|
+
if (isDrainChild()) return runDrainChild();
|
|
38
45
|
let input = "";
|
|
39
46
|
for await (const chunk of process.stdin) input += chunk;
|
|
40
47
|
let data;
|
|
@@ -45,27 +52,23 @@ async function main() {
|
|
|
45
52
|
}
|
|
46
53
|
if (!data || typeof data !== "object") return;
|
|
47
54
|
if (isSdkChildContext(data)) return;
|
|
48
|
-
const sessionId = data.session_id || "unknown";
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}),
|
|
66
|
-
signal: AbortSignal.timeout(2e3)
|
|
67
|
-
}).catch(() => {});
|
|
68
|
-
setTimeout(() => process.exit(0), 500).unref();
|
|
55
|
+
const sessionId = data.session_id || data.sessionId || data.conversation_id || "unknown";
|
|
56
|
+
const cwd = hookCwd(data) || process.cwd();
|
|
57
|
+
captureObservation(withEventId({
|
|
58
|
+
hookType: "task_completed",
|
|
59
|
+
sessionId,
|
|
60
|
+
project: resolveProject(cwd),
|
|
61
|
+
cwd,
|
|
62
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
63
|
+
data: {
|
|
64
|
+
task_id: data.task_id,
|
|
65
|
+
task_subject: data.task_subject,
|
|
66
|
+
task_description: typeof data.task_description === "string" ? data.task_description.slice(0, 2e3) : "",
|
|
67
|
+
teammate_name: data.teammate_name,
|
|
68
|
+
team_name: data.team_name
|
|
69
|
+
}
|
|
70
|
+
}, data), OBSERVE_TIMEOUT_MS);
|
|
71
|
+
setTimeout(() => process.exit(0), EXIT_CAP_MS).unref();
|
|
69
72
|
}
|
|
70
73
|
main().catch(() => process.exit(0));
|
|
71
74
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-completed.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/task-completed.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
|
|
1
|
+
{"version":3,"file":"task-completed.mjs","names":[],"sources":["../../src/hooks/_project.ts","../../src/hooks/task-completed.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\";\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 = 2000;\nconst EXIT_CAP_MS = 2500;\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: \"task_completed\",\n sessionId,\n project: resolveProject(cwd),\n cwd,\n timestamp: new Date().toISOString(),\n data: {\n task_id: data.task_id,\n task_subject: data.task_subject,\n task_description: typeof data.task_description === \"string\"\n ? data.task_description.slice(0, 2000)\n : \"\",\n teammate_name: data.teammate_name,\n team_name: data.team_name,\n },\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":";;;;;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;;;;AC5B9C,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;GACJ,SAAS,KAAK;GACd,cAAc,KAAK;GACnB,kBAAkB,OAAO,KAAK,qBAAqB,WAC/C,KAAK,iBAAiB,MAAM,GAAG,IAAK,GACpC;GACJ,eAAe,KAAK;GACpB,WAAW,KAAK;GACjB;EACF,EACD,KACD,EACD,mBACD;AACD,kBAAiB,QAAQ,KAAK,EAAE,EAAE,YAAY,CAAC,OAAO;;AAGxD,MAAM,CAAC,YAAY,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
workers:
|
|
2
2
|
- name: iii-http
|
|
3
3
|
config:
|
|
4
|
-
port: 3111
|
|
4
|
+
port: ${III_REST_PORT:3111}
|
|
5
5
|
host: 0.0.0.0
|
|
6
6
|
default_timeout: 180000
|
|
7
7
|
cors:
|
|
8
|
-
allowed_origins: ["http://localhost:3111", "http://localhost:3113", "http://127.0.0.1:3111", "http://127.0.0.1:3113"]
|
|
8
|
+
allowed_origins: ["http://localhost:${III_REST_PORT:3111}", "http://localhost:${III_VIEWER_PORT:3113}", "http://127.0.0.1:${III_REST_PORT:3111}", "http://127.0.0.1:${III_VIEWER_PORT:3113}"]
|
|
9
9
|
allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
|
|
10
|
+
- name: iii-worker-manager
|
|
11
|
+
config:
|
|
12
|
+
port: ${III_ENGINE_PORT:49134}
|
|
13
|
+
host: 0.0.0.0
|
|
10
14
|
- name: iii-state
|
|
11
15
|
config:
|
|
12
16
|
adapter:
|
|
13
17
|
name: kv
|
|
14
18
|
config:
|
|
15
19
|
store_method: file_based
|
|
20
|
+
save_interval_ms: ${AGENTMEMORY_STATE_SAVE_INTERVAL_MS:2000}
|
|
16
21
|
file_path: /data/state_store.db
|
|
17
22
|
- name: iii-queue
|
|
18
23
|
config:
|
|
@@ -28,26 +33,21 @@ workers:
|
|
|
28
33
|
name: kv
|
|
29
34
|
- name: iii-stream
|
|
30
35
|
config:
|
|
31
|
-
port: 3112
|
|
36
|
+
port: ${III_STREAM_PORT:3112}
|
|
32
37
|
host: 0.0.0.0
|
|
33
38
|
adapter:
|
|
34
39
|
name: kv
|
|
35
40
|
config:
|
|
36
41
|
store_method: file_based
|
|
42
|
+
save_interval_ms: ${AGENTMEMORY_STATE_SAVE_INTERVAL_MS:2000}
|
|
37
43
|
file_path: /data/stream_store
|
|
38
44
|
- name: iii-observability
|
|
39
45
|
config:
|
|
40
46
|
enabled: true
|
|
41
47
|
service_name: agentmemory
|
|
42
48
|
exporter: memory
|
|
43
|
-
# See iii-config.yaml for the rationale on 0.1 / console-off
|
|
49
|
+
# See iii-config.yaml for the rationale on 0.1 / console-off.
|
|
44
50
|
sampling_ratio: 0.1
|
|
45
51
|
metrics_enabled: true
|
|
46
52
|
logs_enabled: true
|
|
47
53
|
logs_console_output: false
|
|
48
|
-
- name: iii-exec
|
|
49
|
-
config:
|
|
50
|
-
watch:
|
|
51
|
-
- src/**/*.ts
|
|
52
|
-
exec:
|
|
53
|
-
- node dist/index.mjs
|
package/dist/iii-config.yaml
CHANGED
|
@@ -13,6 +13,7 @@ workers:
|
|
|
13
13
|
name: kv
|
|
14
14
|
config:
|
|
15
15
|
store_method: file_based
|
|
16
|
+
save_interval_ms: 2000
|
|
16
17
|
file_path: ./data/state_store.db
|
|
17
18
|
- name: iii-queue
|
|
18
19
|
config:
|
|
@@ -34,6 +35,7 @@ workers:
|
|
|
34
35
|
name: kv
|
|
35
36
|
config:
|
|
36
37
|
store_method: file_based
|
|
38
|
+
save_interval_ms: 2000
|
|
37
39
|
file_path: ./data/stream_store
|
|
38
40
|
- name: iii-observability
|
|
39
41
|
config:
|
|
@@ -45,7 +47,7 @@ workers:
|
|
|
45
47
|
# subscriber lagged" WARN, and that WARN re-enters the same
|
|
46
48
|
# stream the subscriber is failing to drain — a positive
|
|
47
49
|
# feedback loop that wrote 137 GB to daemon.log.new on one user
|
|
48
|
-
# in a few days
|
|
50
|
+
# in a few days.
|
|
49
51
|
sampling_ratio: 0.1
|
|
50
52
|
metrics_enabled: true
|
|
51
53
|
logs_enabled: true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as
|
|
2
|
+
import { i as withKeyedLock, n as touchImage, r as KV, t as deleteImage } from "./index.mjs";
|
|
3
3
|
import { TriggerAction } from "iii-sdk";
|
|
4
4
|
//#region src/functions/image-refs.ts
|
|
5
5
|
async function getImageRefCount(kv, filePath) {
|
|
@@ -31,4 +31,4 @@ async function decrementImageRef(kv, sdk, filePath) {
|
|
|
31
31
|
//#endregion
|
|
32
32
|
export { decrementImageRef, getImageRefCount, incrementImageRef };
|
|
33
33
|
|
|
34
|
-
//# sourceMappingURL=image-refs-
|
|
34
|
+
//# sourceMappingURL=image-refs-BaT-9oMU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-refs-BaT-9oMU.mjs","names":[],"sources":["../src/functions/image-refs.ts"],"sourcesContent":["import { TriggerAction, type IIIClient } from \"iii-sdk\";\nimport { KV } from \"../state/schema.js\";\nimport { StateKV } from \"../state/kv.js\";\nimport { deleteImage, touchImage } from \"../utils/image-store.js\";\nimport { withKeyedLock } from \"../state/keyed-mutex.js\";\n\nexport async function getImageRefCount(kv: StateKV, filePath: string): Promise<number> {\n const count = await kv.get<number>(KV.imageRefs, filePath);\n return count ? Number(count) : 0;\n}\n\nexport async function incrementImageRef(kv: StateKV, filePath: string): Promise<void> {\n return withKeyedLock(`imgRef:${filePath}`, async () => {\n const current = await getImageRefCount(kv, filePath);\n await kv.set(KV.imageRefs, filePath, current + 1);\n await touchImage(filePath);\n });\n}\n\nexport async function decrementImageRef(kv: StateKV, sdk: IIIClient, filePath: string): Promise<void> {\n return withKeyedLock(`imgRef:${filePath}`, async () => {\n const current = await getImageRefCount(kv, filePath);\n if (current <= 1) {\n await kv.delete(KV.imageEmbeddings, filePath);\n await kv.delete(KV.imageRefs, filePath);\n const { deletedBytes } = await deleteImage(filePath);\n if (deletedBytes > 0) {\n sdk.trigger({\n function_id: \"mem::disk-size-delta\",\n payload: { deltaBytes: -deletedBytes },\n action: TriggerAction.Void(),\n });\n }\n } else {\n await kv.set(KV.imageRefs, filePath, current - 1);\n }\n });\n}\n"],"mappings":";;;;AAMA,eAAsB,iBAAiB,IAAa,UAAmC;CACrF,MAAM,QAAQ,MAAM,GAAG,IAAY,GAAG,WAAW,SAAS;AAC1D,QAAO,QAAQ,OAAO,MAAM,GAAG;;AAGjC,eAAsB,kBAAkB,IAAa,UAAiC;AACpF,QAAO,cAAc,UAAU,YAAY,YAAY;EACrD,MAAM,UAAU,MAAM,iBAAiB,IAAI,SAAS;AACpD,QAAM,GAAG,IAAI,GAAG,WAAW,UAAU,UAAU,EAAE;AACjD,QAAM,WAAW,SAAS;GAC1B;;AAGJ,eAAsB,kBAAkB,IAAa,KAAgB,UAAiC;AACpG,QAAO,cAAc,UAAU,YAAY,YAAY;EACrD,MAAM,UAAU,MAAM,iBAAiB,IAAI,SAAS;AACpD,MAAI,WAAW,GAAG;AAChB,SAAM,GAAG,OAAO,GAAG,iBAAiB,SAAS;AAC7C,SAAM,GAAG,OAAO,GAAG,WAAW,SAAS;GACvC,MAAM,EAAE,iBAAiB,MAAM,YAAY,SAAS;AACpD,OAAI,eAAe,EACjB,KAAI,QAAQ;IACV,aAAa;IACb,SAAS,EAAE,YAAY,CAAC,cAAc;IACtC,QAAQ,cAAc,MAAM;IAC7B,CAAC;QAGJ,OAAM,GAAG,IAAI,GAAG,WAAW,UAAU,UAAU,EAAE;GAEnD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { r as KV, t as withKeyedLock } from "./keyed-mutex-DchXsyfP.mjs";
|
|
2
|
+
import { n as deleteImage, o as touchImage } from "./image-store-BsN4vyjr.mjs";
|
|
3
3
|
import { TriggerAction } from "iii-sdk";
|
|
4
4
|
//#region src/functions/image-refs.ts
|
|
5
5
|
async function getImageRefCount(kv, filePath) {
|
|
@@ -31,4 +31,4 @@ async function decrementImageRef(kv, sdk, filePath) {
|
|
|
31
31
|
//#endregion
|
|
32
32
|
export { decrementImageRef, getImageRefCount, incrementImageRef };
|
|
33
33
|
|
|
34
|
-
//# sourceMappingURL=image-refs-
|
|
34
|
+
//# sourceMappingURL=image-refs-T_urbwHM.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-refs-T_urbwHM.mjs","names":[],"sources":["../src/functions/image-refs.ts"],"sourcesContent":["import { TriggerAction, type IIIClient } from \"iii-sdk\";\nimport { KV } from \"../state/schema.js\";\nimport { StateKV } from \"../state/kv.js\";\nimport { deleteImage, touchImage } from \"../utils/image-store.js\";\nimport { withKeyedLock } from \"../state/keyed-mutex.js\";\n\nexport async function getImageRefCount(kv: StateKV, filePath: string): Promise<number> {\n const count = await kv.get<number>(KV.imageRefs, filePath);\n return count ? Number(count) : 0;\n}\n\nexport async function incrementImageRef(kv: StateKV, filePath: string): Promise<void> {\n return withKeyedLock(`imgRef:${filePath}`, async () => {\n const current = await getImageRefCount(kv, filePath);\n await kv.set(KV.imageRefs, filePath, current + 1);\n await touchImage(filePath);\n });\n}\n\nexport async function decrementImageRef(kv: StateKV, sdk: IIIClient, filePath: string): Promise<void> {\n return withKeyedLock(`imgRef:${filePath}`, async () => {\n const current = await getImageRefCount(kv, filePath);\n if (current <= 1) {\n await kv.delete(KV.imageEmbeddings, filePath);\n await kv.delete(KV.imageRefs, filePath);\n const { deletedBytes } = await deleteImage(filePath);\n if (deletedBytes > 0) {\n sdk.trigger({\n function_id: \"mem::disk-size-delta\",\n payload: { deltaBytes: -deletedBytes },\n action: TriggerAction.Void(),\n });\n }\n } else {\n await kv.set(KV.imageRefs, filePath, current - 1);\n }\n });\n}\n"],"mappings":";;;;AAMA,eAAsB,iBAAiB,IAAa,UAAmC;CACrF,MAAM,QAAQ,MAAM,GAAG,IAAY,GAAG,WAAW,SAAS;AAC1D,QAAO,QAAQ,OAAO,MAAM,GAAG;;AAGjC,eAAsB,kBAAkB,IAAa,UAAiC;AACpF,QAAO,cAAc,UAAU,YAAY,YAAY;EACrD,MAAM,UAAU,MAAM,iBAAiB,IAAI,SAAS;AACpD,QAAM,GAAG,IAAI,GAAG,WAAW,UAAU,UAAU,EAAE;AACjD,QAAM,WAAW,SAAS;GAC1B;;AAGJ,eAAsB,kBAAkB,IAAa,KAAgB,UAAiC;AACpG,QAAO,cAAc,UAAU,YAAY,YAAY;EACrD,MAAM,UAAU,MAAM,iBAAiB,IAAI,SAAS;AACpD,MAAI,WAAW,GAAG;AAChB,SAAM,GAAG,OAAO,GAAG,iBAAiB,SAAS;AAC7C,SAAM,GAAG,OAAO,GAAG,WAAW,SAAS;GACvC,MAAM,EAAE,iBAAiB,MAAM,YAAY,SAAS;AACpD,OAAI,eAAe,EACjB,KAAI,QAAQ;IACV,aAAa;IACb,SAAS,EAAE,YAAY,CAAC,cAAc;IACtC,QAAQ,cAAc,MAAM;IAC7B,CAAC;QAGJ,OAAM,GAAG,IAAI,GAAG,WAAW,UAAU,UAAU,EAAE;GAEnD"}
|
|
@@ -71,18 +71,6 @@ async function touchImage(filePath) {
|
|
|
71
71
|
} catch (err) {}
|
|
72
72
|
}
|
|
73
73
|
//#endregion
|
|
74
|
-
|
|
75
|
-
const locks = /* @__PURE__ */ new Map();
|
|
76
|
-
function withKeyedLock(key, fn) {
|
|
77
|
-
const next = (locks.get(key) ?? Promise.resolve()).then(fn, fn);
|
|
78
|
-
const cleanup = next.then(() => {}, () => {});
|
|
79
|
-
locks.set(key, cleanup);
|
|
80
|
-
cleanup.then(() => {
|
|
81
|
-
if (locks.get(key) === cleanup) locks.delete(key);
|
|
82
|
-
});
|
|
83
|
-
return next;
|
|
84
|
-
}
|
|
85
|
-
//#endregion
|
|
86
|
-
export { isManagedImagePath as a, getMaxBytes as i, IMAGES_DIR as n, saveImageToDisk as o, deleteImage as r, touchImage as s, withKeyedLock as t };
|
|
74
|
+
export { saveImageToDisk as a, isManagedImagePath as i, deleteImage as n, touchImage as o, getMaxBytes as r, IMAGES_DIR as t };
|
|
87
75
|
|
|
88
|
-
//# sourceMappingURL=
|
|
76
|
+
//# sourceMappingURL=image-store-BsN4vyjr.mjs.map
|