@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
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
//#region src/state/cjk-segmenter.ts
|
|
4
|
+
const cjkRequire = createRequire(import.meta.url);
|
|
5
|
+
const CJK_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
6
|
+
const KANA_RE = /[\p{Script=Hiragana}\p{Script=Katakana}]/u;
|
|
7
|
+
const HANGUL_RE = /\p{Script=Hangul}/u;
|
|
8
|
+
const CJK_RUN_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+/gu;
|
|
9
|
+
const HANGUL_BLOCK_RE = /[가-]+/g;
|
|
10
|
+
const hintShown = /* @__PURE__ */ new Set();
|
|
11
|
+
function hasCjk(text) {
|
|
12
|
+
return CJK_RE.test(text);
|
|
13
|
+
}
|
|
14
|
+
function showHintOnce(key, message) {
|
|
15
|
+
if (hintShown.has(key)) return;
|
|
16
|
+
hintShown.add(key);
|
|
17
|
+
if (typeof process !== "undefined" && process.stderr?.write) process.stderr.write(`agentmemory: ${message}\n`);
|
|
18
|
+
}
|
|
19
|
+
let jiebaInstance = null;
|
|
20
|
+
let jiebaLoaded = false;
|
|
21
|
+
function getJieba() {
|
|
22
|
+
if (jiebaLoaded) return jiebaInstance;
|
|
23
|
+
jiebaLoaded = true;
|
|
24
|
+
try {
|
|
25
|
+
const mod = cjkRequire("@node-rs/jieba");
|
|
26
|
+
try {
|
|
27
|
+
const dictMod = cjkRequire("@node-rs/jieba/dict");
|
|
28
|
+
jiebaInstance = mod.Jieba.withDict(dictMod.dict);
|
|
29
|
+
} catch {
|
|
30
|
+
jiebaInstance = new mod.Jieba();
|
|
31
|
+
}
|
|
32
|
+
return jiebaInstance;
|
|
33
|
+
} catch {
|
|
34
|
+
showHintOnce("jieba", "install @node-rs/jieba to improve Chinese search; falling back to whole-string tokenization");
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
let jaSegmenterInstance = null;
|
|
39
|
+
let jaSegmenterLoaded = false;
|
|
40
|
+
function getJaSegmenter() {
|
|
41
|
+
if (jaSegmenterLoaded) return jaSegmenterInstance;
|
|
42
|
+
jaSegmenterLoaded = true;
|
|
43
|
+
try {
|
|
44
|
+
jaSegmenterInstance = new (cjkRequire("tiny-segmenter"))();
|
|
45
|
+
return jaSegmenterInstance;
|
|
46
|
+
} catch {
|
|
47
|
+
showHintOnce("tiny-segmenter", "install tiny-segmenter to improve Japanese search; falling back to whole-string tokenization");
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function cleanTokens(tokens) {
|
|
52
|
+
const out = [];
|
|
53
|
+
for (const t of tokens) {
|
|
54
|
+
const trimmed = t.trim();
|
|
55
|
+
if (trimmed) out.push(trimmed);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
function segmentHan(text) {
|
|
60
|
+
const j = getJieba();
|
|
61
|
+
if (!j) return [text];
|
|
62
|
+
try {
|
|
63
|
+
return cleanTokens(j.cut(text, true));
|
|
64
|
+
} catch {
|
|
65
|
+
return [text];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function segmentKana(text) {
|
|
69
|
+
const s = getJaSegmenter();
|
|
70
|
+
if (!s) return [text];
|
|
71
|
+
try {
|
|
72
|
+
return cleanTokens(s.segment(text));
|
|
73
|
+
} catch {
|
|
74
|
+
return [text];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function segmentHangul(text) {
|
|
78
|
+
const out = [];
|
|
79
|
+
for (const m of text.matchAll(HANGUL_BLOCK_RE)) if (m[0]) out.push(m[0]);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
function segmentCjk(text) {
|
|
83
|
+
if (!hasCjk(text)) return [text];
|
|
84
|
+
const out = [];
|
|
85
|
+
let cursor = 0;
|
|
86
|
+
for (const m of text.matchAll(CJK_RUN_RE)) {
|
|
87
|
+
const start = m.index ?? 0;
|
|
88
|
+
const run = m[0];
|
|
89
|
+
const end = start + run.length;
|
|
90
|
+
if (start > cursor) {
|
|
91
|
+
const piece = text.slice(cursor, start).trim();
|
|
92
|
+
if (piece) out.push(piece);
|
|
93
|
+
}
|
|
94
|
+
if (HANGUL_RE.test(run)) out.push(...segmentHangul(run));
|
|
95
|
+
else if (KANA_RE.test(run)) out.push(...segmentKana(run));
|
|
96
|
+
else out.push(...segmentHan(run));
|
|
97
|
+
cursor = end;
|
|
98
|
+
}
|
|
99
|
+
if (cursor < text.length) {
|
|
100
|
+
const trailing = text.slice(cursor).trim();
|
|
101
|
+
if (trailing) out.push(trailing);
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/state/schema.ts
|
|
107
|
+
const KV = {
|
|
108
|
+
sessions: "mem:sessions",
|
|
109
|
+
observations: (sessionId) => `mem:obs:${sessionId}`,
|
|
110
|
+
memories: "mem:memories",
|
|
111
|
+
summaries: "mem:summaries",
|
|
112
|
+
config: "mem:config",
|
|
113
|
+
metrics: "mem:metrics",
|
|
114
|
+
health: "mem:health",
|
|
115
|
+
embeddings: (obsId) => `mem:emb:${obsId}`,
|
|
116
|
+
bm25Index: "mem:index:bm25",
|
|
117
|
+
vectorPendingLog: "mem:index:vec-pending",
|
|
118
|
+
relations: "mem:relations",
|
|
119
|
+
profiles: "mem:profiles",
|
|
120
|
+
claudeBridge: "mem:claude-bridge",
|
|
121
|
+
graphNodes: "mem:graph:nodes",
|
|
122
|
+
graphEdges: "mem:graph:edges",
|
|
123
|
+
graphSnapshot: "mem:graph:snapshot",
|
|
124
|
+
graphNameIndex: "mem:graph:name-index",
|
|
125
|
+
graphEdgeKey: "mem:graph:edge-key",
|
|
126
|
+
graphNodeDegree: "mem:graph:node-degree",
|
|
127
|
+
semantic: "mem:semantic",
|
|
128
|
+
procedural: "mem:procedural",
|
|
129
|
+
teamShared: (teamId) => `mem:team:${teamId}:shared`,
|
|
130
|
+
teamUsers: (teamId, userId) => `mem:team:${teamId}:users:${userId}`,
|
|
131
|
+
teamProfile: (teamId) => `mem:team:${teamId}:profile`,
|
|
132
|
+
audit: "mem:audit",
|
|
133
|
+
auditMonth: (month) => `mem:audit:${month}`,
|
|
134
|
+
auditMonths: "mem:audit:months",
|
|
135
|
+
actions: "mem:actions",
|
|
136
|
+
actionEdges: "mem:action-edges",
|
|
137
|
+
leases: "mem:leases",
|
|
138
|
+
routines: "mem:routines",
|
|
139
|
+
routineRuns: "mem:routine-runs",
|
|
140
|
+
signals: "mem:signals",
|
|
141
|
+
checkpoints: "mem:checkpoints",
|
|
142
|
+
mesh: "mem:mesh",
|
|
143
|
+
sketches: "mem:sketches",
|
|
144
|
+
facets: "mem:facets",
|
|
145
|
+
sentinels: "mem:sentinels",
|
|
146
|
+
crystals: "mem:crystals",
|
|
147
|
+
lessons: "mem:lessons",
|
|
148
|
+
insights: "mem:insights",
|
|
149
|
+
graphEdgeHistory: "mem:graph:edge-history",
|
|
150
|
+
enrichedChunks: (sessionId) => `mem:enriched:${sessionId}`,
|
|
151
|
+
latentEmbeddings: (obsId) => `mem:latent:${obsId}`,
|
|
152
|
+
retentionScores: "mem:retention",
|
|
153
|
+
accessLog: "mem:access",
|
|
154
|
+
imageRefs: "mem:image-refs",
|
|
155
|
+
imageEmbeddings: "mem:image-embeddings",
|
|
156
|
+
slots: "mem:slots",
|
|
157
|
+
globalSlots: "mem:slots:global",
|
|
158
|
+
state: "mem:state",
|
|
159
|
+
commits: "mem:commits",
|
|
160
|
+
recentSearches: "mem:recent-searches",
|
|
161
|
+
projectSessionsIndex: "mem:idx:project-sessions",
|
|
162
|
+
obsSessionIndex: (shard) => `mem:idx:obs:${shard}`,
|
|
163
|
+
captureInbox: "mem:capture:inbox",
|
|
164
|
+
captureEvents: (shard) => `mem:capture:events:${shard}`,
|
|
165
|
+
capturePrompts: "mem:capture:prompts"
|
|
166
|
+
};
|
|
167
|
+
const STREAM = {
|
|
168
|
+
name: "mem-live",
|
|
169
|
+
viewerGroup: "viewer"
|
|
170
|
+
};
|
|
171
|
+
function generateId(prefix) {
|
|
172
|
+
return `${prefix}_${Date.now().toString(36)}_${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
|
|
173
|
+
}
|
|
174
|
+
function fingerprintId(prefix, content) {
|
|
175
|
+
return `${prefix}_${createHash("sha256").update(content).digest("hex").slice(0, 16)}`;
|
|
176
|
+
}
|
|
177
|
+
function jaccardTokens(text) {
|
|
178
|
+
if (!hasCjk(text)) return new Set(text.split(/\s+/).filter((t) => t.length > 2));
|
|
179
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
180
|
+
for (const raw of text.split(/\s+/)) {
|
|
181
|
+
if (!raw) continue;
|
|
182
|
+
if (hasCjk(raw)) {
|
|
183
|
+
for (const seg of segmentCjk(raw)) if (seg) tokens.add(seg);
|
|
184
|
+
const chars = Array.from(raw);
|
|
185
|
+
if (chars.length === 1) tokens.add(chars[0]);
|
|
186
|
+
else for (let i = 0; i < chars.length - 1; i++) tokens.add(chars[i] + chars[i + 1]);
|
|
187
|
+
} else if (raw.length > 2) tokens.add(raw);
|
|
188
|
+
}
|
|
189
|
+
return tokens;
|
|
190
|
+
}
|
|
191
|
+
function jaccardSimilarity(a, b) {
|
|
192
|
+
const na = a.normalize("NFC");
|
|
193
|
+
const nb = b.normalize("NFC");
|
|
194
|
+
const setA = jaccardTokens(na);
|
|
195
|
+
const setB = jaccardTokens(nb);
|
|
196
|
+
if (setA.size === 0 || setB.size === 0) return na.trim().replace(/\s+/g, " ") === nb.trim().replace(/\s+/g, " ") ? 1 : 0;
|
|
197
|
+
let intersection = 0;
|
|
198
|
+
for (const word of setA) if (setB.has(word)) intersection++;
|
|
199
|
+
return intersection / (setA.size + setB.size - intersection);
|
|
200
|
+
}
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/state/keyed-mutex.ts
|
|
203
|
+
const locks = /* @__PURE__ */ new Map();
|
|
204
|
+
function withKeyedLock(key, fn) {
|
|
205
|
+
const next = (locks.get(key) ?? Promise.resolve()).then(fn, fn);
|
|
206
|
+
const cleanup = next.then(() => {}, () => {});
|
|
207
|
+
locks.set(key, cleanup);
|
|
208
|
+
cleanup.then(() => {
|
|
209
|
+
if (locks.get(key) === cleanup) locks.delete(key);
|
|
210
|
+
});
|
|
211
|
+
return next;
|
|
212
|
+
}
|
|
213
|
+
function withKeyedLocks(keys, fn) {
|
|
214
|
+
const ordered = [...new Set(keys)].sort();
|
|
215
|
+
const acquire = (index) => index === ordered.length ? fn() : withKeyedLock(ordered[index], () => acquire(index + 1));
|
|
216
|
+
return acquire(0);
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
export { fingerprintId as a, hasCjk as c, STREAM as i, segmentCjk as l, withKeyedLocks as n, generateId as o, KV as r, jaccardSimilarity as s, withKeyedLock as t };
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=keyed-mutex-DchXsyfP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyed-mutex-DchXsyfP.mjs","names":[],"sources":["../src/state/cjk-segmenter.ts","../src/state/schema.ts","../src/state/keyed-mutex.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nconst cjkRequire = createRequire(import.meta.url);\n\nconst CJK_RE = /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u;\nconst HAN_RE = /\\p{Script=Han}/u;\nconst KANA_RE = /[\\p{Script=Hiragana}\\p{Script=Katakana}]/u;\nconst HANGUL_RE = /\\p{Script=Hangul}/u;\nconst CJK_RUN_RE = /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]+/gu;\nconst HANGUL_BLOCK_RE = /[가-]+/g;\n\ntype Script = \"han\" | \"kana\" | \"hangul\" | \"other\";\n\nconst hintShown = new Set<string>();\n\nexport function hasCjk(text: string): boolean {\n return CJK_RE.test(text);\n}\n\nexport function detectScript(text: string): Script {\n if (HAN_RE.test(text)) return \"han\";\n if (KANA_RE.test(text)) return \"kana\";\n if (HANGUL_RE.test(text)) return \"hangul\";\n return \"other\";\n}\n\nfunction showHintOnce(key: string, message: string): void {\n if (hintShown.has(key)) return;\n hintShown.add(key);\n if (typeof process !== \"undefined\" && process.stderr?.write) {\n process.stderr.write(`agentmemory: ${message}\\n`);\n }\n}\n\ninterface JiebaInstance {\n cut(text: string, hmm?: boolean): string[];\n}\n\nlet jiebaInstance: JiebaInstance | null = null;\nlet jiebaLoaded = false;\n\nfunction getJieba(): JiebaInstance | null {\n if (jiebaLoaded) return jiebaInstance;\n jiebaLoaded = true;\n try {\n const mod = cjkRequire(\"@node-rs/jieba\") as {\n Jieba: {\n new (): JiebaInstance;\n withDict(dict: Uint8Array): JiebaInstance;\n };\n };\n try {\n const dictMod = cjkRequire(\"@node-rs/jieba/dict\") as { dict: Uint8Array };\n jiebaInstance = mod.Jieba.withDict(dictMod.dict);\n } catch {\n jiebaInstance = new mod.Jieba();\n }\n return jiebaInstance;\n } catch {\n showHintOnce(\n \"jieba\",\n \"install @node-rs/jieba to improve Chinese search; falling back to whole-string tokenization\",\n );\n return null;\n }\n}\n\ninterface JaSegmenter {\n segment(text: string): string[];\n}\n\nlet jaSegmenterInstance: JaSegmenter | null = null;\nlet jaSegmenterLoaded = false;\n\nfunction getJaSegmenter(): JaSegmenter | null {\n if (jaSegmenterLoaded) return jaSegmenterInstance;\n jaSegmenterLoaded = true;\n try {\n const Ctor = cjkRequire(\"tiny-segmenter\") as new () => JaSegmenter;\n jaSegmenterInstance = new Ctor();\n return jaSegmenterInstance;\n } catch {\n showHintOnce(\n \"tiny-segmenter\",\n \"install tiny-segmenter to improve Japanese search; falling back to whole-string tokenization\",\n );\n return null;\n }\n}\n\nfunction cleanTokens(tokens: string[]): string[] {\n const out: string[] = [];\n for (const t of tokens) {\n const trimmed = t.trim();\n if (trimmed) out.push(trimmed);\n }\n return out;\n}\n\nfunction segmentHan(text: string): string[] {\n const j = getJieba();\n if (!j) return [text];\n try {\n return cleanTokens(j.cut(text, true));\n } catch {\n return [text];\n }\n}\n\nfunction segmentKana(text: string): string[] {\n const s = getJaSegmenter();\n if (!s) return [text];\n try {\n return cleanTokens(s.segment(text));\n } catch {\n return [text];\n }\n}\n\nfunction segmentHangul(text: string): string[] {\n const out: string[] = [];\n for (const m of text.matchAll(HANGUL_BLOCK_RE)) {\n if (m[0]) out.push(m[0]);\n }\n return out;\n}\n\nexport function segmentCjk(text: string): string[] {\n if (!hasCjk(text)) return [text];\n\n const out: string[] = [];\n let cursor = 0;\n\n for (const m of text.matchAll(CJK_RUN_RE)) {\n const start = m.index ?? 0;\n const run = m[0];\n const end = start + run.length;\n\n if (start > cursor) {\n const piece = text.slice(cursor, start).trim();\n if (piece) out.push(piece);\n }\n\n if (HANGUL_RE.test(run)) {\n out.push(...segmentHangul(run));\n } else if (KANA_RE.test(run)) {\n out.push(...segmentKana(run));\n } else {\n out.push(...segmentHan(run));\n }\n\n cursor = end;\n }\n\n if (cursor < text.length) {\n const trailing = text.slice(cursor).trim();\n if (trailing) out.push(trailing);\n }\n\n return out;\n}\n\nexport function __resetCjkSegmenterStateForTests(): void {\n hintShown.clear();\n jiebaInstance = null;\n jiebaLoaded = false;\n jaSegmenterInstance = null;\n jaSegmenterLoaded = false;\n}\n","import { createHash } from \"node:crypto\";\nimport { hasCjk, segmentCjk } from \"./cjk-segmenter.js\";\n\nexport const KV = {\n sessions: \"mem:sessions\",\n observations: (sessionId: string) => `mem:obs:${sessionId}`,\n memories: \"mem:memories\",\n summaries: \"mem:summaries\",\n config: \"mem:config\",\n metrics: \"mem:metrics\",\n health: \"mem:health\",\n embeddings: (obsId: string) => `mem:emb:${obsId}`,\n bm25Index: \"mem:index:bm25\",\n vectorPendingLog: \"mem:index:vec-pending\",\n relations: \"mem:relations\",\n profiles: \"mem:profiles\",\n claudeBridge: \"mem:claude-bridge\",\n graphNodes: \"mem:graph:nodes\",\n graphEdges: \"mem:graph:edges\",\n graphSnapshot: \"mem:graph:snapshot\",\n graphNameIndex: \"mem:graph:name-index\",\n graphEdgeKey: \"mem:graph:edge-key\",\n graphNodeDegree: \"mem:graph:node-degree\",\n semantic: \"mem:semantic\",\n procedural: \"mem:procedural\",\n teamShared: (teamId: string) => `mem:team:${teamId}:shared`,\n teamUsers: (teamId: string, userId: string) =>\n `mem:team:${teamId}:users:${userId}`,\n teamProfile: (teamId: string) => `mem:team:${teamId}:profile`,\n audit: \"mem:audit\",\n auditMonth: (month: string) => `mem:audit:${month}`,\n auditMonths: \"mem:audit:months\",\n actions: \"mem:actions\",\n actionEdges: \"mem:action-edges\",\n leases: \"mem:leases\",\n routines: \"mem:routines\",\n routineRuns: \"mem:routine-runs\",\n signals: \"mem:signals\",\n checkpoints: \"mem:checkpoints\",\n mesh: \"mem:mesh\",\n sketches: \"mem:sketches\",\n facets: \"mem:facets\",\n sentinels: \"mem:sentinels\",\n crystals: \"mem:crystals\",\n lessons: \"mem:lessons\",\n insights: \"mem:insights\",\n graphEdgeHistory: \"mem:graph:edge-history\",\n enrichedChunks: (sessionId: string) => `mem:enriched:${sessionId}`,\n latentEmbeddings: (obsId: string) => `mem:latent:${obsId}`,\n retentionScores: \"mem:retention\",\n accessLog: \"mem:access\",\n imageRefs: \"mem:image-refs\",\n imageEmbeddings: \"mem:image-embeddings\",\n slots: \"mem:slots\",\n globalSlots: \"mem:slots:global\",\n state: \"mem:state\",\n commits: \"mem:commits\",\n recentSearches: \"mem:recent-searches\",\n projectSessionsIndex: \"mem:idx:project-sessions\",\n obsSessionIndex: (shard: number) => `mem:idx:obs:${shard}`,\n captureInbox: \"mem:capture:inbox\",\n captureEvents: (shard: string) => `mem:capture:events:${shard}`,\n capturePrompts: \"mem:capture:prompts\",\n} as const;\n\nexport const STREAM = {\n name: \"mem-live\",\n viewerGroup: \"viewer\",\n} as const;\n\nexport function generateId(prefix: string): string {\n const ts = Date.now().toString(36);\n const rand = crypto.randomUUID().replace(/-/g, \"\").slice(0, 12);\n return `${prefix}_${ts}_${rand}`;\n}\n\nexport function fingerprintId(prefix: string, content: string): string {\n const hash = createHash(\"sha256\").update(content).digest(\"hex\");\n return `${prefix}_${hash.slice(0, 16)}`;\n}\n\n// CJK/Japanese/Thai text carries no inter-word whitespace, so a plain\n// split(/\\s+/) collapses a whole sentence into one token and the two token\n// sets never overlap — dedup silently stops working. When either input\n// contains CJK we segment the CJK runs (word tokens via the shared\n// segmenter, plus character bigram shingles so near-identical strings still\n// overlap even when the optional segmenter deps fall back to whole-string).\n// ASCII text keeps the original word-level behavior.\nfunction jaccardTokens(text: string): Set<string> {\n if (!hasCjk(text)) {\n return new Set(text.split(/\\s+/).filter((t) => t.length > 2));\n }\n const tokens = new Set<string>();\n for (const raw of text.split(/\\s+/)) {\n if (!raw) continue;\n if (hasCjk(raw)) {\n for (const seg of segmentCjk(raw)) {\n if (seg) tokens.add(seg);\n }\n // Character bigram shingles keep the CJK signal even when the\n // segmenter returns the whole run: overlapping bigrams make\n // near-identical strings match while unrelated ones (\"北京\" vs\n // \"上海\") share none. Never drop short CJK tokens.\n const chars = Array.from(raw);\n if (chars.length === 1) {\n tokens.add(chars[0]);\n } else {\n for (let i = 0; i < chars.length - 1; i++) {\n tokens.add(chars[i] + chars[i + 1]);\n }\n }\n } else if (raw.length > 2) {\n tokens.add(raw);\n }\n }\n return tokens;\n}\n\nexport function jaccardSimilarity(a: string, b: string): number {\n const na = a.normalize(\"NFC\");\n const nb = b.normalize(\"NFC\");\n const setA = jaccardTokens(na);\n const setB = jaccardTokens(nb);\n // An empty token set carries no signal for the overlap metric. Very short\n // ASCII text (\"AI\", \"a b\", \"go\") tokenizes to nothing because words <=2\n // chars are dropped. Fall back to exact normalized equality so re-saving\n // the identical short memory still supersedes, while unrelated short\n // strings (\"AI\" vs \"ML\") correctly score 0. Returning 1 unconditionally\n // here (as an \"both empty\" shortcut once did) would let any short memory\n // falsely supersede another, silently marking a real memory not-latest.\n if (setA.size === 0 || setB.size === 0) {\n return na.trim().replace(/\\s+/g, \" \") === nb.trim().replace(/\\s+/g, \" \")\n ? 1\n : 0;\n }\n let intersection = 0;\n for (const word of setA) {\n if (setB.has(word)) intersection++;\n }\n return intersection / (setA.size + setB.size - intersection);\n}\n","const locks = new Map<string, Promise<void>>();\n\nexport function withKeyedLock<T>(\n key: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const prev = locks.get(key) ?? Promise.resolve();\n const next = prev.then(fn, fn);\n const cleanup = next.then(\n () => {},\n () => {},\n );\n locks.set(key, cleanup);\n cleanup.then(() => {\n if (locks.get(key) === cleanup) locks.delete(key);\n });\n return next;\n}\n\nexport function withKeyedLocks<T>(keys: string[], fn: () => Promise<T>): Promise<T> {\n const ordered = [...new Set(keys)].sort();\n const acquire = (index: number): Promise<T> => index === ordered.length\n ? fn()\n : withKeyedLock(ordered[index], () => acquire(index + 1));\n return acquire(0);\n}\n"],"mappings":"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"}
|