@osovv/vv-opencode 0.1.0 → 0.2.1
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/AGENTS.md +62 -50
- package/README.md +237 -20
- package/dist/commands/doctor.d.ts +1 -7
- package/dist/commands/doctor.js +3 -20
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/guardian.js +1 -1
- package/dist/commands/guardian.js.map +1 -1
- package/dist/commands/install.d.ts +1 -7
- package/dist/commands/install.js +4 -16
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.js +2 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +1 -7
- package/dist/commands/sync.js +4 -15
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/opencode.d.ts +3 -18
- package/dist/lib/opencode.js +39 -111
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/opencode.test.js +23 -6
- package/dist/lib/opencode.test.js.map +1 -1
- package/dist/lib/vvoc-paths.d.ts +6 -0
- package/dist/lib/vvoc-paths.js +25 -0
- package/dist/lib/vvoc-paths.js.map +1 -0
- package/dist/plugins/guardian.js +20 -21
- package/dist/plugins/guardian.js.map +1 -1
- package/dist/plugins/memory-store.d.ts +49 -0
- package/dist/plugins/memory-store.js +452 -0
- package/dist/plugins/memory-store.js.map +1 -0
- package/dist/plugins/memory.d.ts +2 -0
- package/dist/plugins/memory.js +323 -0
- package/dist/plugins/memory.js.map +1 -0
- package/dist/plugins/memory.test.d.ts +1 -0
- package/dist/plugins/memory.test.js +151 -0
- package/dist/plugins/memory.test.js.map +1 -0
- package/docs/development-plan.xml +100 -20
- package/docs/knowledge-graph.xml +30 -6
- package/docs/requirements.xml +30 -19
- package/docs/technology.xml +23 -14
- package/docs/verification-plan.xml +92 -25
- package/package.json +14 -2
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { deleteMemory, getDefaultProjectScopeKey, getDefaultSearchLimit, getDefaultSharedScopeKey, getMemory, listMemories, loadMemoryRuntimeConfig, normalizeReadScopeType, normalizeWriteScopeType, putMemory, resolveBranchScopeKey, searchMemories, updateMemory, } from "./memory-store.js";
|
|
3
|
+
const MEMORY_REVIEW_AGENT = "memory-reviewer";
|
|
4
|
+
const z = tool.schema;
|
|
5
|
+
const MEMORY_SYSTEM_INSTRUCTION = `
|
|
6
|
+
vvoc explicit memory is available in this workspace.
|
|
7
|
+
|
|
8
|
+
- Stored memory is never preloaded into the prompt.
|
|
9
|
+
- When durable user preferences, recurring project facts, or reusable procedures may already exist, consider memory_search, memory_list, or memory_get before guessing.
|
|
10
|
+
- When you discover durable information that should survive across turns or sessions, consider memory_put if your current role and available tools permit it.
|
|
11
|
+
- Do not use memory for transient scratch notes or one-off reasoning.
|
|
12
|
+
`.trim();
|
|
13
|
+
const MEMORY_REVIEW_PROMPT = `
|
|
14
|
+
You review explicit persistent memory managed by vvoc.
|
|
15
|
+
|
|
16
|
+
Rules:
|
|
17
|
+
- Memory is explicit-only. Nothing is automatically loaded into the prompt.
|
|
18
|
+
- Start with memory_list for the relevant scopes.
|
|
19
|
+
- Use memory_get for exact ids.
|
|
20
|
+
- Use memory_search to confirm overlap, duplicates, or scope mistakes.
|
|
21
|
+
- Do not create, update, or delete memory.
|
|
22
|
+
- Produce a report only.
|
|
23
|
+
|
|
24
|
+
Return sections in this order:
|
|
25
|
+
## Keep
|
|
26
|
+
## Update
|
|
27
|
+
## Merge
|
|
28
|
+
## Delete
|
|
29
|
+
## Questions
|
|
30
|
+
## Summary
|
|
31
|
+
`;
|
|
32
|
+
function createMemoryReviewerToolsConfig() {
|
|
33
|
+
return {
|
|
34
|
+
bash: false,
|
|
35
|
+
edit: false,
|
|
36
|
+
write: false,
|
|
37
|
+
read: false,
|
|
38
|
+
list: false,
|
|
39
|
+
glob: false,
|
|
40
|
+
grep: false,
|
|
41
|
+
task: false,
|
|
42
|
+
webfetch: false,
|
|
43
|
+
websearch: false,
|
|
44
|
+
codesearch: false,
|
|
45
|
+
lsp: false,
|
|
46
|
+
skill: false,
|
|
47
|
+
todoread: false,
|
|
48
|
+
todowrite: false,
|
|
49
|
+
memory_search: true,
|
|
50
|
+
memory_get: true,
|
|
51
|
+
memory_list: true,
|
|
52
|
+
memory_put: false,
|
|
53
|
+
memory_update: false,
|
|
54
|
+
memory_delete: false,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function installMemoryReviewerAgent(config) {
|
|
58
|
+
config.agent ??= {};
|
|
59
|
+
config.agent[MEMORY_REVIEW_AGENT] = {
|
|
60
|
+
mode: "subagent",
|
|
61
|
+
description: "Reviews stored vvoc memory and suggests cleanup actions without modifying entries.",
|
|
62
|
+
prompt: MEMORY_REVIEW_PROMPT.trim(),
|
|
63
|
+
steps: 6,
|
|
64
|
+
permission: {
|
|
65
|
+
edit: "deny",
|
|
66
|
+
webfetch: "deny",
|
|
67
|
+
bash: {
|
|
68
|
+
"*": "deny",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
tools: createMemoryReviewerToolsConfig(),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function resolveWriteScope(scopeType, scopeKey, sessionID, directory) {
|
|
75
|
+
const normalizedType = normalizeWriteScopeType(scopeType) ?? "project";
|
|
76
|
+
if (normalizedType === "project") {
|
|
77
|
+
return { scopeType: "project", scopeKey: getDefaultProjectScopeKey() };
|
|
78
|
+
}
|
|
79
|
+
if (normalizedType === "shared") {
|
|
80
|
+
return {
|
|
81
|
+
scopeType: "shared",
|
|
82
|
+
scopeKey: typeof scopeKey === "string" && scopeKey.trim()
|
|
83
|
+
? scopeKey.trim()
|
|
84
|
+
: getDefaultSharedScopeKey(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (normalizedType === "session") {
|
|
88
|
+
return {
|
|
89
|
+
scopeType: "session",
|
|
90
|
+
scopeKey: typeof scopeKey === "string" && scopeKey.trim() ? scopeKey.trim() : sessionID,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
scopeType: "branch",
|
|
95
|
+
scopeKey: typeof scopeKey === "string" && scopeKey.trim()
|
|
96
|
+
? scopeKey.trim()
|
|
97
|
+
: resolveBranchScopeKey(directory),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function getRelevantScopes(sessionID, directory) {
|
|
101
|
+
return [
|
|
102
|
+
resolveWriteScope("session", undefined, sessionID, directory),
|
|
103
|
+
resolveWriteScope("branch", undefined, sessionID, directory),
|
|
104
|
+
resolveWriteScope("project", undefined, sessionID, directory),
|
|
105
|
+
resolveWriteScope("shared", undefined, sessionID, directory),
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
function resolveReadScopes(scopeType, scopeKey, sessionID, directory) {
|
|
109
|
+
const normalizedType = normalizeReadScopeType(scopeType);
|
|
110
|
+
if (!normalizedType) {
|
|
111
|
+
return getRelevantScopes(sessionID, directory);
|
|
112
|
+
}
|
|
113
|
+
if (normalizedType === "all") {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
return [resolveWriteScope(normalizedType, scopeKey, sessionID, directory)];
|
|
117
|
+
}
|
|
118
|
+
function formatMemoryEntry(entry) {
|
|
119
|
+
return `- ${entry.id} [${entry.scope_type}:${entry.scope_key}] [${entry.kind}] ${entry.text}`;
|
|
120
|
+
}
|
|
121
|
+
function formatMemoryEntries(entries) {
|
|
122
|
+
return entries.map(formatMemoryEntry).join("\n");
|
|
123
|
+
}
|
|
124
|
+
function formatMemoryDetails(entry) {
|
|
125
|
+
return JSON.stringify(entry, null, 2);
|
|
126
|
+
}
|
|
127
|
+
function getMemoryMetadataTitle(action, count) {
|
|
128
|
+
if (typeof count === "number") {
|
|
129
|
+
return `${action} (${count})`;
|
|
130
|
+
}
|
|
131
|
+
return action;
|
|
132
|
+
}
|
|
133
|
+
function getMemoryConfigWarningLines(memoryConfig) {
|
|
134
|
+
return memoryConfig.warnings.map((warning) => `- ${warning}`);
|
|
135
|
+
}
|
|
136
|
+
function assertEnabled(memoryConfig) {
|
|
137
|
+
if (!memoryConfig.enabled) {
|
|
138
|
+
throw new Error("vvoc memory is disabled in memory.jsonc");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export const MemoryPlugin = async ({ client, directory }) => {
|
|
142
|
+
const memoryConfig = await loadMemoryRuntimeConfig(directory);
|
|
143
|
+
await client.app.log({
|
|
144
|
+
body: {
|
|
145
|
+
service: "memory",
|
|
146
|
+
level: "info",
|
|
147
|
+
message: "memory plugin initialized",
|
|
148
|
+
extra: {
|
|
149
|
+
enabled: memoryConfig.enabled,
|
|
150
|
+
storageRoot: memoryConfig.storageRoot,
|
|
151
|
+
defaultSearchLimit: memoryConfig.defaultSearchLimit,
|
|
152
|
+
configSources: memoryConfig.sources,
|
|
153
|
+
configWarnings: memoryConfig.warnings,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
if (!memoryConfig.enabled) {
|
|
158
|
+
return {};
|
|
159
|
+
}
|
|
160
|
+
const metadataWarnings = getMemoryConfigWarningLines(memoryConfig);
|
|
161
|
+
return {
|
|
162
|
+
config: async (config) => {
|
|
163
|
+
installMemoryReviewerAgent(config);
|
|
164
|
+
},
|
|
165
|
+
"experimental.chat.system.transform": async (_input, output) => {
|
|
166
|
+
if (!output.system.includes(MEMORY_SYSTEM_INSTRUCTION)) {
|
|
167
|
+
output.system.push(MEMORY_SYSTEM_INSTRUCTION);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
tool: {
|
|
171
|
+
memory_search: tool({
|
|
172
|
+
description: "Search explicit persistent memory stored in .vvoc/memory. Memory is never preloaded into the prompt.",
|
|
173
|
+
args: {
|
|
174
|
+
query: z.string(),
|
|
175
|
+
scopeType: z.enum(["session", "branch", "project", "shared", "all"]).optional(),
|
|
176
|
+
scopeKey: z.string().optional(),
|
|
177
|
+
kind: z.string().optional(),
|
|
178
|
+
limit: z.number().int().positive().optional(),
|
|
179
|
+
},
|
|
180
|
+
async execute(args, context) {
|
|
181
|
+
assertEnabled(memoryConfig);
|
|
182
|
+
const results = await searchMemories(memoryConfig, args.query, {
|
|
183
|
+
scopes: resolveReadScopes(args.scopeType, args.scopeKey, context.sessionID, context.worktree),
|
|
184
|
+
kind: args.kind,
|
|
185
|
+
limit: args.limit ?? getDefaultSearchLimit(memoryConfig),
|
|
186
|
+
});
|
|
187
|
+
context.metadata({
|
|
188
|
+
title: getMemoryMetadataTitle("Memory Search", results.length),
|
|
189
|
+
metadata: { count: results.length },
|
|
190
|
+
});
|
|
191
|
+
if (results.length === 0) {
|
|
192
|
+
return metadataWarnings.length > 0
|
|
193
|
+
? [`No matching memory entries found.`, "", ...metadataWarnings].join("\n")
|
|
194
|
+
: "No matching memory entries found.";
|
|
195
|
+
}
|
|
196
|
+
return metadataWarnings.length > 0
|
|
197
|
+
? [formatMemoryEntries(results), "", "Warnings:", ...metadataWarnings].join("\n")
|
|
198
|
+
: formatMemoryEntries(results);
|
|
199
|
+
},
|
|
200
|
+
}),
|
|
201
|
+
memory_get: tool({
|
|
202
|
+
description: "Load a single explicit memory entry by id from .vvoc/memory.",
|
|
203
|
+
args: {
|
|
204
|
+
id: z.string(),
|
|
205
|
+
},
|
|
206
|
+
async execute(args, context) {
|
|
207
|
+
assertEnabled(memoryConfig);
|
|
208
|
+
const entry = await getMemory(memoryConfig, args.id);
|
|
209
|
+
if (!entry) {
|
|
210
|
+
throw new Error(`Memory not found: ${args.id}`);
|
|
211
|
+
}
|
|
212
|
+
context.metadata({
|
|
213
|
+
title: getMemoryMetadataTitle("Memory Get"),
|
|
214
|
+
metadata: { id: entry.id },
|
|
215
|
+
});
|
|
216
|
+
return formatMemoryDetails(entry);
|
|
217
|
+
},
|
|
218
|
+
}),
|
|
219
|
+
memory_put: tool({
|
|
220
|
+
description: "Create a new explicit memory entry in session, branch, project, or shared scope. Use this deliberately for durable facts, preferences, or procedures.",
|
|
221
|
+
args: {
|
|
222
|
+
text: z.string(),
|
|
223
|
+
kind: z.string().optional(),
|
|
224
|
+
scopeType: z.enum(["session", "branch", "project", "shared"]).optional(),
|
|
225
|
+
scopeKey: z.string().optional(),
|
|
226
|
+
tags: z.array(z.string()).optional(),
|
|
227
|
+
meta: z.record(z.string(), z.unknown()).optional(),
|
|
228
|
+
},
|
|
229
|
+
async execute(args, context) {
|
|
230
|
+
assertEnabled(memoryConfig);
|
|
231
|
+
const scope = resolveWriteScope(args.scopeType, args.scopeKey, context.sessionID, context.worktree);
|
|
232
|
+
const entry = await putMemory(memoryConfig, {
|
|
233
|
+
scope_type: scope.scopeType,
|
|
234
|
+
scope_key: scope.scopeKey,
|
|
235
|
+
kind: args.kind,
|
|
236
|
+
text: args.text,
|
|
237
|
+
tags: args.tags,
|
|
238
|
+
meta: args.meta,
|
|
239
|
+
});
|
|
240
|
+
context.metadata({
|
|
241
|
+
title: getMemoryMetadataTitle("Memory Put"),
|
|
242
|
+
metadata: { id: entry.id, scopeType: entry.scope_type, scopeKey: entry.scope_key },
|
|
243
|
+
});
|
|
244
|
+
return `Stored memory ${entry.id}`;
|
|
245
|
+
},
|
|
246
|
+
}),
|
|
247
|
+
memory_update: tool({
|
|
248
|
+
description: "Update an existing explicit memory entry by id.",
|
|
249
|
+
args: {
|
|
250
|
+
id: z.string(),
|
|
251
|
+
text: z.string().optional(),
|
|
252
|
+
kind: z.string().optional(),
|
|
253
|
+
tags: z.array(z.string()).optional(),
|
|
254
|
+
meta: z.record(z.string(), z.unknown()).optional(),
|
|
255
|
+
},
|
|
256
|
+
async execute(args, context) {
|
|
257
|
+
assertEnabled(memoryConfig);
|
|
258
|
+
if (args.text === undefined &&
|
|
259
|
+
args.kind === undefined &&
|
|
260
|
+
args.tags === undefined &&
|
|
261
|
+
args.meta === undefined) {
|
|
262
|
+
throw new Error("memory_update requires at least one field to change");
|
|
263
|
+
}
|
|
264
|
+
const entry = await updateMemory(memoryConfig, args.id, {
|
|
265
|
+
text: args.text,
|
|
266
|
+
kind: args.kind,
|
|
267
|
+
tags: args.tags,
|
|
268
|
+
meta: args.meta,
|
|
269
|
+
});
|
|
270
|
+
if (!entry) {
|
|
271
|
+
throw new Error(`Memory not found: ${args.id}`);
|
|
272
|
+
}
|
|
273
|
+
context.metadata({
|
|
274
|
+
title: getMemoryMetadataTitle("Memory Update"),
|
|
275
|
+
metadata: { id: entry.id },
|
|
276
|
+
});
|
|
277
|
+
return `Updated memory ${entry.id}`;
|
|
278
|
+
},
|
|
279
|
+
}),
|
|
280
|
+
memory_delete: tool({
|
|
281
|
+
description: "Delete an explicit memory entry by id.",
|
|
282
|
+
args: {
|
|
283
|
+
id: z.string(),
|
|
284
|
+
},
|
|
285
|
+
async execute(args, context) {
|
|
286
|
+
assertEnabled(memoryConfig);
|
|
287
|
+
const entry = await deleteMemory(memoryConfig, args.id);
|
|
288
|
+
if (!entry) {
|
|
289
|
+
throw new Error(`Memory not found: ${args.id}`);
|
|
290
|
+
}
|
|
291
|
+
context.metadata({
|
|
292
|
+
title: getMemoryMetadataTitle("Memory Delete"),
|
|
293
|
+
metadata: { id: entry.id },
|
|
294
|
+
});
|
|
295
|
+
return `Deleted memory ${entry.id}`;
|
|
296
|
+
},
|
|
297
|
+
}),
|
|
298
|
+
memory_list: tool({
|
|
299
|
+
description: "List explicit persistent memory entries across session, branch, project, or shared scopes. Memory is never preloaded into the prompt.",
|
|
300
|
+
args: {
|
|
301
|
+
scopeType: z.enum(["session", "branch", "project", "shared", "all"]).optional(),
|
|
302
|
+
scopeKey: z.string().optional(),
|
|
303
|
+
kind: z.string().optional(),
|
|
304
|
+
limit: z.number().int().positive().optional(),
|
|
305
|
+
},
|
|
306
|
+
async execute(args, context) {
|
|
307
|
+
assertEnabled(memoryConfig);
|
|
308
|
+
const results = await listMemories(memoryConfig, {
|
|
309
|
+
scopes: resolveReadScopes(args.scopeType, args.scopeKey, context.sessionID, context.worktree),
|
|
310
|
+
kind: args.kind,
|
|
311
|
+
limit: args.limit ?? getDefaultSearchLimit(memoryConfig),
|
|
312
|
+
});
|
|
313
|
+
context.metadata({
|
|
314
|
+
title: getMemoryMetadataTitle("Memory List", results.length),
|
|
315
|
+
metadata: { count: results.length },
|
|
316
|
+
});
|
|
317
|
+
return results.length > 0 ? formatMemoryEntries(results) : "No memory entries found.";
|
|
318
|
+
},
|
|
319
|
+
}),
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/plugins/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { MemoryPlugin } from "./memory.js";
|
|
7
|
+
import { deleteMemory, getMemory, listMemories, loadMemoryRuntimeConfig, putMemory, searchMemories, updateMemory, } from "./memory-store.js";
|
|
8
|
+
describe("loadMemoryRuntimeConfig", () => {
|
|
9
|
+
test("uses global and project vvoc config files", async () => {
|
|
10
|
+
const configHome = await mkdtemp(join(tmpdir(), "vvoc-config-home-"));
|
|
11
|
+
const projectDir = await mkdtemp(join(tmpdir(), "vvoc-memory-project-"));
|
|
12
|
+
try {
|
|
13
|
+
await mkdir(join(configHome, "vvoc"), { recursive: true });
|
|
14
|
+
await mkdir(join(projectDir, ".vvoc"), { recursive: true });
|
|
15
|
+
await writeFile(join(configHome, "vvoc", "memory.jsonc"), '{\n "defaultSearchLimit": 4\n}\n', "utf8");
|
|
16
|
+
await writeFile(join(projectDir, ".vvoc", "memory.jsonc"), '{\n "enabled": true,\n "defaultSearchLimit": 2\n}\n', "utf8");
|
|
17
|
+
const previous = process.env.XDG_CONFIG_HOME;
|
|
18
|
+
process.env.XDG_CONFIG_HOME = configHome;
|
|
19
|
+
try {
|
|
20
|
+
const memoryConfig = await loadMemoryRuntimeConfig(projectDir);
|
|
21
|
+
expect(memoryConfig.enabled).toBe(true);
|
|
22
|
+
expect(memoryConfig.defaultSearchLimit).toBe(2);
|
|
23
|
+
expect(memoryConfig.storageRoot).toBe(join(projectDir, ".vvoc", "memory"));
|
|
24
|
+
expect(memoryConfig.sources).toEqual([
|
|
25
|
+
join(configHome, "vvoc", "memory.jsonc"),
|
|
26
|
+
join(projectDir, ".vvoc", "memory.jsonc"),
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
if (previous === undefined) {
|
|
31
|
+
delete process.env.XDG_CONFIG_HOME;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
process.env.XDG_CONFIG_HOME = previous;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
await rm(configHome, { recursive: true, force: true });
|
|
40
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe("memory store", () => {
|
|
45
|
+
test("stores, searches, updates, lists, and deletes scoped memories", async () => {
|
|
46
|
+
const projectDir = await mkdtemp(join(tmpdir(), "vvoc-memory-store-"));
|
|
47
|
+
try {
|
|
48
|
+
const memoryConfig = await loadMemoryRuntimeConfig(projectDir);
|
|
49
|
+
const projectMemory = await putMemory(memoryConfig, {
|
|
50
|
+
scope_type: "project",
|
|
51
|
+
scope_key: "project",
|
|
52
|
+
kind: "preference",
|
|
53
|
+
text: "Prefer explicit memory tools for durable facts.",
|
|
54
|
+
tags: ["memory", "facts"],
|
|
55
|
+
});
|
|
56
|
+
const branchMemory = await putMemory(memoryConfig, {
|
|
57
|
+
scope_type: "branch",
|
|
58
|
+
scope_key: "feature/memory-plugin",
|
|
59
|
+
kind: "procedural",
|
|
60
|
+
text: "Keep branch-specific memory entries short.",
|
|
61
|
+
tags: ["branch", "memory"],
|
|
62
|
+
});
|
|
63
|
+
const sessionMemory = await putMemory(memoryConfig, {
|
|
64
|
+
scope_type: "session",
|
|
65
|
+
scope_key: "session-123",
|
|
66
|
+
kind: "note",
|
|
67
|
+
text: "Investigating explicit memory UX.",
|
|
68
|
+
tags: ["session"],
|
|
69
|
+
});
|
|
70
|
+
const sharedMemory = await putMemory(memoryConfig, {
|
|
71
|
+
scope_type: "shared",
|
|
72
|
+
scope_key: "team",
|
|
73
|
+
kind: "decision",
|
|
74
|
+
text: "Memory stays explicit and never injects stored entries into prompts.",
|
|
75
|
+
tags: ["policy", "memory"],
|
|
76
|
+
});
|
|
77
|
+
expect(existsSync(join(memoryConfig.storageRoot, "project", `${projectMemory.id}.json`))).toBe(true);
|
|
78
|
+
expect(existsSync(join(memoryConfig.storageRoot, "branch", encodeURIComponent("feature/memory-plugin"), `${branchMemory.id}.json`))).toBe(true);
|
|
79
|
+
expect(existsSync(join(memoryConfig.storageRoot, "session", "session-123", `${sessionMemory.id}.json`))).toBe(true);
|
|
80
|
+
expect(existsSync(join(memoryConfig.storageRoot, "shared", "team", `${sharedMemory.id}.json`))).toBe(true);
|
|
81
|
+
const branchResults = await searchMemories(memoryConfig, "branch-specific memory", {
|
|
82
|
+
scopes: [{ scopeType: "branch", scopeKey: "feature/memory-plugin" }],
|
|
83
|
+
limit: 5,
|
|
84
|
+
});
|
|
85
|
+
expect(branchResults[0]?.id).toBe(branchMemory.id);
|
|
86
|
+
const loaded = await getMemory(memoryConfig, projectMemory.id);
|
|
87
|
+
expect(loaded?.text).toBe(projectMemory.text);
|
|
88
|
+
const updated = await updateMemory(memoryConfig, projectMemory.id, {
|
|
89
|
+
text: "Prefer explicit memory tools for durable facts and preferences.",
|
|
90
|
+
tags: ["memory", "facts", "preferences"],
|
|
91
|
+
});
|
|
92
|
+
expect(updated?.text).toContain("preferences");
|
|
93
|
+
const listed = await listMemories(memoryConfig, {
|
|
94
|
+
scopes: [{ scopeType: "shared", scopeKey: "team" }],
|
|
95
|
+
limit: 5,
|
|
96
|
+
});
|
|
97
|
+
expect(listed).toHaveLength(1);
|
|
98
|
+
expect(listed[0]?.id).toBe(sharedMemory.id);
|
|
99
|
+
const deleted = await deleteMemory(memoryConfig, sessionMemory.id);
|
|
100
|
+
expect(deleted?.id).toBe(sessionMemory.id);
|
|
101
|
+
expect(await getMemory(memoryConfig, sessionMemory.id)).toBeNull();
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe("MemoryPlugin", () => {
|
|
109
|
+
test("registers explicit memory tools and reviewer agent", async () => {
|
|
110
|
+
const projectDir = await mkdtemp(join(tmpdir(), "vvoc-memory-plugin-"));
|
|
111
|
+
try {
|
|
112
|
+
const plugin = await MemoryPlugin({
|
|
113
|
+
client: {
|
|
114
|
+
app: {
|
|
115
|
+
log: async () => undefined,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
project: {},
|
|
119
|
+
directory: projectDir,
|
|
120
|
+
worktree: projectDir,
|
|
121
|
+
serverUrl: new URL("http://localhost"),
|
|
122
|
+
$: {},
|
|
123
|
+
});
|
|
124
|
+
expect(plugin.tool).toBeDefined();
|
|
125
|
+
expect(Object.keys(plugin.tool ?? {})).toEqual([
|
|
126
|
+
"memory_search",
|
|
127
|
+
"memory_get",
|
|
128
|
+
"memory_put",
|
|
129
|
+
"memory_update",
|
|
130
|
+
"memory_delete",
|
|
131
|
+
"memory_list",
|
|
132
|
+
]);
|
|
133
|
+
const config = {};
|
|
134
|
+
await plugin.config?.(config);
|
|
135
|
+
expect(config.agent?.["memory-reviewer"]?.mode).toBe("subagent");
|
|
136
|
+
const system = { system: ["base system prompt"] };
|
|
137
|
+
await plugin["experimental.chat.system.transform"]?.({
|
|
138
|
+
sessionID: "session-1",
|
|
139
|
+
model: {},
|
|
140
|
+
}, system);
|
|
141
|
+
expect(system.system).toContain("base system prompt");
|
|
142
|
+
expect(system.system.join("\n\n")).toContain("vvoc explicit memory is available in this workspace.");
|
|
143
|
+
expect(system.system.join("\n\n")).toContain("memory_search, memory_list, or memory_get");
|
|
144
|
+
expect(system.system.join("\n\n")).toContain("memory_put if your current role and available tools permit it");
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await rm(projectDir, { recursive: true, force: true });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=memory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.test.js","sourceRoot":"","sources":["../../src/plugins/memory.test.ts"],"names":[],"mappings":"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"}
|