@vuau/agent-memory 0.1.0 → 0.2.0
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/README.md +9 -0
- package/dist/bin/cli.js +346 -0
- package/dist/index.js +444 -0
- package/package.json +14 -8
- package/bin/cli.ts +0 -111
- package/index.ts +0 -11
- package/src/core/doctor.ts +0 -86
- package/src/core/index.ts +0 -5
- package/src/core/memory.ts +0 -86
- package/src/core/scaffold.ts +0 -124
- package/src/core/tasks.ts +0 -77
- package/src/core/types.ts +0 -30
- package/src/opencode/plugin.ts +0 -97
package/README.md
CHANGED
|
@@ -82,9 +82,18 @@ npx @vuau/agent-memory init
|
|
|
82
82
|
npx @vuau/agent-memory init --force # Overwrite existing files
|
|
83
83
|
npx @vuau/agent-memory init --name "My App" # Custom project name
|
|
84
84
|
npx @vuau/agent-memory init --no-copilot # Skip copilot-instructions.md
|
|
85
|
+
npx @vuau/agent-memory init --opencode # Wire up OpenCode plugin
|
|
85
86
|
npx @vuau/agent-memory doctor # Validate structure
|
|
86
87
|
```
|
|
87
88
|
|
|
89
|
+
#### `--opencode` flag
|
|
90
|
+
|
|
91
|
+
Wires up the OpenCode plugin automatically:
|
|
92
|
+
- Creates/updates `.opencode/package.json` with `@vuau/agent-memory` dependency
|
|
93
|
+
- Creates/updates `opencode.json` with `"plugin": ["@vuau/agent-memory"]`
|
|
94
|
+
|
|
95
|
+
After running, restart OpenCode to activate the plugin.
|
|
96
|
+
|
|
88
97
|
## How It Works
|
|
89
98
|
|
|
90
99
|
### For AI Agents
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/core/scaffold.ts
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
5
|
+
import { join, resolve, dirname } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
// src/core/types.ts
|
|
9
|
+
var AGENTS_DIR = ".agents";
|
|
10
|
+
var SPEC_DIR = ".agents/spec";
|
|
11
|
+
var MEMORY_FILE = ".agents/MEMORY.md";
|
|
12
|
+
var TASKS_FILE = ".agents/TASKS.md";
|
|
13
|
+
var AGENTS_MD = "AGENTS.md";
|
|
14
|
+
var COPILOT_INSTRUCTIONS = ".github/copilot-instructions.md";
|
|
15
|
+
|
|
16
|
+
// src/core/scaffold.ts
|
|
17
|
+
function getTemplatesDir() {
|
|
18
|
+
try {
|
|
19
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const candidate = resolve(thisDir, "../../templates");
|
|
21
|
+
if (existsSync(candidate)) return candidate;
|
|
22
|
+
} catch {
|
|
23
|
+
}
|
|
24
|
+
const candidate2 = resolve(__dirname, "../../templates");
|
|
25
|
+
if (existsSync(candidate2)) return candidate2;
|
|
26
|
+
throw new Error("Cannot locate templates directory");
|
|
27
|
+
}
|
|
28
|
+
var TEMPLATES_DIR = getTemplatesDir();
|
|
29
|
+
function readTemplate(name) {
|
|
30
|
+
const templatePath = join(TEMPLATES_DIR, name);
|
|
31
|
+
return readFileSync(templatePath, "utf-8");
|
|
32
|
+
}
|
|
33
|
+
function applyVars(content, vars) {
|
|
34
|
+
let result = content;
|
|
35
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
36
|
+
result = result.replaceAll(`{{${key}}}`, value);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function scaffold(projectDir, config = {}, force = false) {
|
|
41
|
+
const result = { created: [], skipped: [] };
|
|
42
|
+
const projectName = config.projectName || guessProjectName(projectDir);
|
|
43
|
+
const vars = { PROJECT_NAME: projectName };
|
|
44
|
+
const dirs = [
|
|
45
|
+
join(projectDir, AGENTS_DIR),
|
|
46
|
+
join(projectDir, SPEC_DIR)
|
|
47
|
+
];
|
|
48
|
+
if (config.copilotInstructions !== false) {
|
|
49
|
+
dirs.push(join(projectDir, ".github"));
|
|
50
|
+
}
|
|
51
|
+
for (const dir of dirs) {
|
|
52
|
+
if (!existsSync(dir)) {
|
|
53
|
+
mkdirSync(dir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const files = [
|
|
57
|
+
{ target: AGENTS_MD, template: "AGENTS.md" },
|
|
58
|
+
{ target: MEMORY_FILE, template: "MEMORY.md" },
|
|
59
|
+
{ target: TASKS_FILE, template: "TASKS.md" }
|
|
60
|
+
];
|
|
61
|
+
if (config.copilotInstructions !== false) {
|
|
62
|
+
files.push({
|
|
63
|
+
target: COPILOT_INSTRUCTIONS,
|
|
64
|
+
template: "copilot-instructions.md"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
for (const { target, template } of files) {
|
|
68
|
+
const targetPath = join(projectDir, target);
|
|
69
|
+
if (existsSync(targetPath) && !force) {
|
|
70
|
+
result.skipped.push(target);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const content = applyVars(readTemplate(template), vars);
|
|
74
|
+
writeFileSync(targetPath, content);
|
|
75
|
+
result.created.push(target);
|
|
76
|
+
}
|
|
77
|
+
const specKeep = join(projectDir, SPEC_DIR, ".gitkeep");
|
|
78
|
+
if (!existsSync(specKeep)) {
|
|
79
|
+
writeFileSync(specKeep, "");
|
|
80
|
+
result.created.push(`${SPEC_DIR}/.gitkeep`);
|
|
81
|
+
}
|
|
82
|
+
if (config.opencode) {
|
|
83
|
+
scaffoldOpenCode(projectDir, result, force);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
function scaffoldOpenCode(projectDir, result, force) {
|
|
88
|
+
const PACKAGE_NAME = "@vuau/agent-memory";
|
|
89
|
+
const opencodePkgPath = join(projectDir, ".opencode", "package.json");
|
|
90
|
+
const opencodeDir = join(projectDir, ".opencode");
|
|
91
|
+
if (!existsSync(opencodeDir)) {
|
|
92
|
+
mkdirSync(opencodeDir, { recursive: true });
|
|
93
|
+
}
|
|
94
|
+
if (!existsSync(opencodePkgPath)) {
|
|
95
|
+
writeFileSync(
|
|
96
|
+
opencodePkgPath,
|
|
97
|
+
JSON.stringify({ dependencies: { [PACKAGE_NAME]: "latest" } }, null, 2) + "\n"
|
|
98
|
+
);
|
|
99
|
+
result.created.push(".opencode/package.json");
|
|
100
|
+
} else {
|
|
101
|
+
const pkg = JSON.parse(readFileSync(opencodePkgPath, "utf-8"));
|
|
102
|
+
const deps = pkg.dependencies || {};
|
|
103
|
+
if (!deps[PACKAGE_NAME] || force) {
|
|
104
|
+
deps[PACKAGE_NAME] = "latest";
|
|
105
|
+
pkg.dependencies = deps;
|
|
106
|
+
writeFileSync(opencodePkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
107
|
+
if (!deps[PACKAGE_NAME]) {
|
|
108
|
+
result.created.push(".opencode/package.json");
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
result.skipped.push(".opencode/package.json");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const opencodeJsonPath = join(projectDir, "opencode.json");
|
|
115
|
+
if (!existsSync(opencodeJsonPath)) {
|
|
116
|
+
writeFileSync(
|
|
117
|
+
opencodeJsonPath,
|
|
118
|
+
JSON.stringify({ plugin: [PACKAGE_NAME] }, null, 2) + "\n"
|
|
119
|
+
);
|
|
120
|
+
result.created.push("opencode.json");
|
|
121
|
+
} else {
|
|
122
|
+
const config = JSON.parse(readFileSync(opencodeJsonPath, "utf-8"));
|
|
123
|
+
const plugins = config.plugin || [];
|
|
124
|
+
if (!plugins.includes(PACKAGE_NAME)) {
|
|
125
|
+
config.plugin = [...plugins, PACKAGE_NAME];
|
|
126
|
+
writeFileSync(opencodeJsonPath, JSON.stringify(config, null, 2) + "\n");
|
|
127
|
+
result.created.push("opencode.json (merged plugin)");
|
|
128
|
+
} else {
|
|
129
|
+
result.skipped.push("opencode.json");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function guessProjectName(dir) {
|
|
134
|
+
const pkgPath = join(dir, "package.json");
|
|
135
|
+
if (existsSync(pkgPath)) {
|
|
136
|
+
try {
|
|
137
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
138
|
+
if (pkg.name) return pkg.name;
|
|
139
|
+
} catch {
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return dir.split("/").pop() || "Project";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/core/doctor.ts
|
|
146
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
147
|
+
import { join as join2 } from "path";
|
|
148
|
+
function doctor(projectDir) {
|
|
149
|
+
const issues = [];
|
|
150
|
+
const required = [
|
|
151
|
+
{ file: AGENTS_MD, desc: "Root router file" },
|
|
152
|
+
{ file: MEMORY_FILE, desc: "Long-term memory" },
|
|
153
|
+
{ file: TASKS_FILE, desc: "Working memory" }
|
|
154
|
+
];
|
|
155
|
+
for (const { file, desc } of required) {
|
|
156
|
+
const filePath = join2(projectDir, file);
|
|
157
|
+
if (!existsSync2(filePath)) {
|
|
158
|
+
issues.push({ level: "error", file, message: `Missing ${desc}` });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
for (const dir of [AGENTS_DIR, SPEC_DIR]) {
|
|
162
|
+
if (!existsSync2(join2(projectDir, dir))) {
|
|
163
|
+
issues.push({ level: "error", file: dir, message: "Directory missing" });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const copilotPath = join2(projectDir, COPILOT_INSTRUCTIONS);
|
|
167
|
+
if (!existsSync2(copilotPath)) {
|
|
168
|
+
issues.push({
|
|
169
|
+
level: "warning",
|
|
170
|
+
file: COPILOT_INSTRUCTIONS,
|
|
171
|
+
message: "Copilot instructions missing \u2014 VSCode/GitHub Copilot won't have context"
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const agentsPath = join2(projectDir, AGENTS_MD);
|
|
175
|
+
if (existsSync2(agentsPath)) {
|
|
176
|
+
const content = readFileSync2(agentsPath, "utf-8");
|
|
177
|
+
if (!content.includes(".agents/")) {
|
|
178
|
+
issues.push({
|
|
179
|
+
level: "warning",
|
|
180
|
+
file: AGENTS_MD,
|
|
181
|
+
message: "No references to .agents/ \u2014 agents may not find memory files"
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (content.split("\n").length > 150) {
|
|
185
|
+
issues.push({
|
|
186
|
+
level: "warning",
|
|
187
|
+
file: AGENTS_MD,
|
|
188
|
+
message: "Over 150 lines \u2014 consider keeping it concise as a router"
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const memoryPath = join2(projectDir, MEMORY_FILE);
|
|
193
|
+
if (existsSync2(memoryPath)) {
|
|
194
|
+
const lines = readFileSync2(memoryPath, "utf-8").split("\n").length;
|
|
195
|
+
if (lines > 150) {
|
|
196
|
+
issues.push({
|
|
197
|
+
level: "warning",
|
|
198
|
+
file: MEMORY_FILE,
|
|
199
|
+
message: `${lines} lines \u2014 consider compressing or archiving old entries`
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const opencodePkgPath = join2(projectDir, ".opencode", "package.json");
|
|
204
|
+
const opencodeJsonPath = join2(projectDir, "opencode.json");
|
|
205
|
+
const opencodeExists = existsSync2(join2(projectDir, ".opencode"));
|
|
206
|
+
if (opencodeExists) {
|
|
207
|
+
if (!existsSync2(opencodePkgPath)) {
|
|
208
|
+
issues.push({
|
|
209
|
+
level: "warning",
|
|
210
|
+
file: ".opencode/package.json",
|
|
211
|
+
message: "Missing \u2014 run 'agent-memory init --opencode' to wire up the plugin"
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
try {
|
|
215
|
+
const pkg = JSON.parse(readFileSync2(opencodePkgPath, "utf-8"));
|
|
216
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
217
|
+
if (!deps["@vuau/agent-memory"]) {
|
|
218
|
+
issues.push({
|
|
219
|
+
level: "warning",
|
|
220
|
+
file: ".opencode/package.json",
|
|
221
|
+
message: "@vuau/agent-memory not in dependencies \u2014 run 'agent-memory init --opencode'"
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
} catch {
|
|
225
|
+
issues.push({ level: "warning", file: ".opencode/package.json", message: "Invalid JSON" });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (!existsSync2(opencodeJsonPath)) {
|
|
229
|
+
issues.push({
|
|
230
|
+
level: "warning",
|
|
231
|
+
file: "opencode.json",
|
|
232
|
+
message: "Missing \u2014 run 'agent-memory init --opencode' to wire up the plugin"
|
|
233
|
+
});
|
|
234
|
+
} else {
|
|
235
|
+
try {
|
|
236
|
+
const config = JSON.parse(readFileSync2(opencodeJsonPath, "utf-8"));
|
|
237
|
+
const plugins = config.plugin || [];
|
|
238
|
+
if (!plugins.includes("@vuau/agent-memory")) {
|
|
239
|
+
issues.push({
|
|
240
|
+
level: "warning",
|
|
241
|
+
file: "opencode.json",
|
|
242
|
+
message: "@vuau/agent-memory not in plugin array \u2014 run 'agent-memory init --opencode'"
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
} catch {
|
|
246
|
+
issues.push({ level: "warning", file: "opencode.json", message: "Invalid JSON" });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return { ok: issues.filter((i) => i.level === "error").length === 0, issues };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// bin/cli.ts
|
|
254
|
+
var args = process.argv.slice(2);
|
|
255
|
+
var command = args[0];
|
|
256
|
+
function printUsage() {
|
|
257
|
+
console.log(`
|
|
258
|
+
@vuau/agent-memory \u2014 Structured AI memory for codebases
|
|
259
|
+
|
|
260
|
+
Usage:
|
|
261
|
+
agent-memory init [options] Scaffold .agents/ structure
|
|
262
|
+
agent-memory doctor Validate .agents/ structure
|
|
263
|
+
agent-memory help Show this help
|
|
264
|
+
|
|
265
|
+
Options (init):
|
|
266
|
+
--force Overwrite existing files
|
|
267
|
+
--name <name> Project name (default: from package.json)
|
|
268
|
+
--no-copilot Skip .github/copilot-instructions.md
|
|
269
|
+
--opencode Wire up OpenCode plugin (.opencode/package.json + opencode.json)
|
|
270
|
+
`);
|
|
271
|
+
}
|
|
272
|
+
function runInit() {
|
|
273
|
+
const force = args.includes("--force");
|
|
274
|
+
const noCopilot = args.includes("--no-copilot");
|
|
275
|
+
const opencode = args.includes("--opencode");
|
|
276
|
+
const nameIdx = args.indexOf("--name");
|
|
277
|
+
const projectName = nameIdx !== -1 ? args[nameIdx + 1] : void 0;
|
|
278
|
+
const cwd = process.cwd();
|
|
279
|
+
console.log(`Initializing agent memory in ${cwd}...`);
|
|
280
|
+
const result = scaffold(cwd, {
|
|
281
|
+
projectName,
|
|
282
|
+
copilotInstructions: !noCopilot,
|
|
283
|
+
opencode
|
|
284
|
+
}, force);
|
|
285
|
+
if (result.created.length > 0) {
|
|
286
|
+
console.log("\nCreated:");
|
|
287
|
+
for (const f of result.created) {
|
|
288
|
+
console.log(` \u2713 ${f}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (result.skipped.length > 0) {
|
|
292
|
+
console.log("\nSkipped (already exist):");
|
|
293
|
+
for (const f of result.skipped) {
|
|
294
|
+
console.log(` - ${f}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (result.created.length === 0 && result.skipped.length > 0) {
|
|
298
|
+
console.log("\nAll files already exist. Use --force to overwrite.");
|
|
299
|
+
}
|
|
300
|
+
console.log("\nNext steps:");
|
|
301
|
+
console.log(" 1. Edit AGENTS.md \u2014 add your project-specific rules");
|
|
302
|
+
console.log(" 2. Add spec files to .agents/spec/ for detailed documentation");
|
|
303
|
+
if (opencode) {
|
|
304
|
+
console.log(" 3. Restart OpenCode to activate the plugin");
|
|
305
|
+
} else {
|
|
306
|
+
console.log(" 3. For OpenCode: run with --opencode flag to wire up the plugin");
|
|
307
|
+
}
|
|
308
|
+
console.log("");
|
|
309
|
+
}
|
|
310
|
+
function runDoctor() {
|
|
311
|
+
const cwd = process.cwd();
|
|
312
|
+
const result = doctor(cwd);
|
|
313
|
+
if (result.issues.length === 0) {
|
|
314
|
+
console.log("\u2713 All checks passed!");
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
for (const issue of result.issues) {
|
|
318
|
+
const icon = issue.level === "error" ? "\u2717" : issue.level === "warning" ? "\u26A0" : "\u2139";
|
|
319
|
+
console.log(` ${icon} [${issue.level}] ${issue.file}: ${issue.message}`);
|
|
320
|
+
}
|
|
321
|
+
console.log("");
|
|
322
|
+
if (result.ok) {
|
|
323
|
+
console.log("\u26A0 Passed with warnings. Run 'agent-memory init' to fix missing files.");
|
|
324
|
+
} else {
|
|
325
|
+
console.log("\u2717 Failed. Run 'agent-memory init' to create missing files.");
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
switch (command) {
|
|
330
|
+
case "init":
|
|
331
|
+
runInit();
|
|
332
|
+
break;
|
|
333
|
+
case "doctor":
|
|
334
|
+
runDoctor();
|
|
335
|
+
break;
|
|
336
|
+
case "help":
|
|
337
|
+
case "--help":
|
|
338
|
+
case "-h":
|
|
339
|
+
case void 0:
|
|
340
|
+
printUsage();
|
|
341
|
+
break;
|
|
342
|
+
default:
|
|
343
|
+
console.error(`Unknown command: ${command}`);
|
|
344
|
+
printUsage();
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|