@vuau/agent-memory 0.4.1 → 0.5.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/dist/bin/cli.js +48 -5
- package/dist/index.js +29 -122
- package/package.json +2 -1
- package/templates/AGENTS.md +11 -14
- package/templates/CUSTOM.md +18 -0
package/dist/bin/cli.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// bin/cli.ts
|
|
4
|
+
import { existsSync as existsSync3 } from "fs";
|
|
5
|
+
import { join as join3 } from "path";
|
|
6
|
+
|
|
7
|
+
// src/scaffold.ts
|
|
4
8
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
5
9
|
import { join, resolve, dirname } from "path";
|
|
6
10
|
import { fileURLToPath } from "url";
|
|
7
11
|
|
|
8
|
-
// src/
|
|
12
|
+
// src/types.ts
|
|
9
13
|
var AGENTS_DIR = ".agents";
|
|
10
14
|
var SPEC_DIR = ".agents/spec";
|
|
11
15
|
var MEMORY_FILE = ".agents/MEMORY.md";
|
|
12
16
|
var MEMORY_DETAIL_FILE = ".agents/MEMORY-DETAIL.md";
|
|
13
17
|
var TASKS_FILE = ".agents/TASKS.md";
|
|
18
|
+
var CUSTOM_FILE = ".agents/CUSTOM.md";
|
|
14
19
|
var AGENTS_MD = "AGENTS.md";
|
|
15
20
|
|
|
16
|
-
// src/
|
|
21
|
+
// src/scaffold.ts
|
|
17
22
|
function getTemplatesDir() {
|
|
18
23
|
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
19
24
|
const fromSource = resolve(thisDir, "../../templates");
|
|
@@ -54,7 +59,8 @@ function scaffold(projectDir, options = {}) {
|
|
|
54
59
|
const coreFiles = [
|
|
55
60
|
{ target: MEMORY_FILE, template: "MEMORY.md" },
|
|
56
61
|
{ target: MEMORY_DETAIL_FILE, template: "MEMORY-DETAIL.md" },
|
|
57
|
-
{ target: TASKS_FILE, template: "TASKS.md" }
|
|
62
|
+
{ target: TASKS_FILE, template: "TASKS.md" },
|
|
63
|
+
{ target: CUSTOM_FILE, template: "CUSTOM.md" }
|
|
58
64
|
];
|
|
59
65
|
for (const { target, template } of coreFiles) {
|
|
60
66
|
const targetPath = join(projectDir, target);
|
|
@@ -99,14 +105,24 @@ function guessProjectName(dir) {
|
|
|
99
105
|
}
|
|
100
106
|
return dir.split("/").pop() || "Project";
|
|
101
107
|
}
|
|
108
|
+
function updateRouter(projectDir) {
|
|
109
|
+
const targetPath = join(projectDir, AGENTS_MD);
|
|
110
|
+
if (!existsSync(targetPath)) return false;
|
|
111
|
+
const projectName = guessProjectName(projectDir);
|
|
112
|
+
const vars = { PROJECT_NAME: projectName };
|
|
113
|
+
const content = applyVars(readTemplate("AGENTS.md"), vars);
|
|
114
|
+
writeFileSync(targetPath, content);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
102
117
|
|
|
103
|
-
// src/
|
|
118
|
+
// src/doctor.ts
|
|
104
119
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
105
120
|
import { join as join2 } from "path";
|
|
106
121
|
function doctor(projectDir) {
|
|
107
122
|
const issues = [];
|
|
108
123
|
const required = [
|
|
109
124
|
{ file: AGENTS_MD, desc: "Root router file" },
|
|
125
|
+
{ file: CUSTOM_FILE, desc: "Project specific rules" },
|
|
110
126
|
{ file: MEMORY_FILE, desc: "Long-term memory" },
|
|
111
127
|
{ file: TASKS_FILE, desc: "Working memory" }
|
|
112
128
|
];
|
|
@@ -162,6 +178,7 @@ function printUsage() {
|
|
|
162
178
|
|
|
163
179
|
Usage:
|
|
164
180
|
agent-memory init [options] Scaffold .agents/ structure and AGENTS.md
|
|
181
|
+
agent-memory update Update AGENTS.md router to latest version
|
|
165
182
|
agent-memory doctor Validate .agents/ structure
|
|
166
183
|
agent-memory help Show this help
|
|
167
184
|
|
|
@@ -208,6 +225,26 @@ Initializing agent memory in ${cwd}...
|
|
|
208
225
|
console.log(" 3. Agent will read rules and write to .agents/MEMORY.md automatically");
|
|
209
226
|
console.log("");
|
|
210
227
|
}
|
|
228
|
+
async function runUpdate() {
|
|
229
|
+
const cwd = process.cwd();
|
|
230
|
+
const agentsMdPath = join3(cwd, AGENTS_MD);
|
|
231
|
+
if (!existsSync3(agentsMdPath)) {
|
|
232
|
+
console.error("\u2717 AGENTS.md not found. Please run 'agent-memory init' first.");
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
console.log(`
|
|
236
|
+
Updating ${AGENTS_MD} in ${cwd}...
|
|
237
|
+
`);
|
|
238
|
+
const updated = updateRouter(cwd);
|
|
239
|
+
if (updated) {
|
|
240
|
+
console.log(` \u2713 ${AGENTS_MD} updated to the latest template.`);
|
|
241
|
+
console.log(` (Note: Your custom rules in .agents/CUSTOM.md were not affected)`);
|
|
242
|
+
} else {
|
|
243
|
+
console.error("\u2717 Failed to update AGENTS.md");
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
console.log("");
|
|
247
|
+
}
|
|
211
248
|
function runDoctor() {
|
|
212
249
|
const cwd = process.cwd();
|
|
213
250
|
const result = doctor(cwd);
|
|
@@ -234,6 +271,12 @@ switch (command) {
|
|
|
234
271
|
process.exit(1);
|
|
235
272
|
});
|
|
236
273
|
break;
|
|
274
|
+
case "update":
|
|
275
|
+
runUpdate().catch((err) => {
|
|
276
|
+
console.error("Error:", err.message);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
});
|
|
279
|
+
break;
|
|
237
280
|
case "doctor":
|
|
238
281
|
runDoctor();
|
|
239
282
|
break;
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/scaffold.ts
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
3
3
|
import { join, resolve, dirname } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
|
|
6
|
-
// src/
|
|
6
|
+
// src/types.ts
|
|
7
7
|
var AGENTS_DIR = ".agents";
|
|
8
8
|
var SPEC_DIR = ".agents/spec";
|
|
9
9
|
var MEMORY_FILE = ".agents/MEMORY.md";
|
|
10
10
|
var MEMORY_DETAIL_FILE = ".agents/MEMORY-DETAIL.md";
|
|
11
11
|
var TASKS_FILE = ".agents/TASKS.md";
|
|
12
|
+
var CUSTOM_FILE = ".agents/CUSTOM.md";
|
|
12
13
|
var AGENTS_MD = "AGENTS.md";
|
|
13
14
|
|
|
14
|
-
// src/
|
|
15
|
+
// src/scaffold.ts
|
|
15
16
|
function getTemplatesDir() {
|
|
16
17
|
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const fromSource = resolve(thisDir, "../../templates");
|
|
@@ -52,7 +53,8 @@ function scaffold(projectDir, options = {}) {
|
|
|
52
53
|
const coreFiles = [
|
|
53
54
|
{ target: MEMORY_FILE, template: "MEMORY.md" },
|
|
54
55
|
{ target: MEMORY_DETAIL_FILE, template: "MEMORY-DETAIL.md" },
|
|
55
|
-
{ target: TASKS_FILE, template: "TASKS.md" }
|
|
56
|
+
{ target: TASKS_FILE, template: "TASKS.md" },
|
|
57
|
+
{ target: CUSTOM_FILE, template: "CUSTOM.md" }
|
|
56
58
|
];
|
|
57
59
|
for (const { target, template } of coreFiles) {
|
|
58
60
|
const targetPath = join(projectDir, target);
|
|
@@ -97,134 +99,41 @@ function guessProjectName(dir) {
|
|
|
97
99
|
}
|
|
98
100
|
return dir.split("/").pop() || "Project";
|
|
99
101
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
const content = readFileSync2(filePath, "utf-8");
|
|
110
|
-
const category = entry.category || "Decisions";
|
|
111
|
-
const line = `- ${entry.date}: ${entry.content}`;
|
|
112
|
-
const categoryHeader = `## ${category}`;
|
|
113
|
-
const headerIndex = content.indexOf(categoryHeader);
|
|
114
|
-
let updated;
|
|
115
|
-
if (headerIndex === -1) {
|
|
116
|
-
updated = content.trimEnd() + `
|
|
117
|
-
|
|
118
|
-
${categoryHeader}
|
|
119
|
-
${line}
|
|
120
|
-
`;
|
|
121
|
-
} else {
|
|
122
|
-
const afterHeader = headerIndex + categoryHeader.length;
|
|
123
|
-
const nextHeaderIndex = content.indexOf("\n## ", afterHeader);
|
|
124
|
-
const insertAt = nextHeaderIndex === -1 ? content.length : nextHeaderIndex;
|
|
125
|
-
const categoryContent = content.slice(afterHeader, insertAt);
|
|
126
|
-
const lastLineEnd = afterHeader + categoryContent.trimEnd().length;
|
|
127
|
-
updated = content.slice(0, lastLineEnd) + "\n" + line + content.slice(lastLineEnd);
|
|
128
|
-
}
|
|
129
|
-
writeFileSync2(filePath, updated);
|
|
130
|
-
}
|
|
131
|
-
function readMemory(projectDir) {
|
|
132
|
-
const filePath = join2(projectDir, MEMORY_FILE);
|
|
133
|
-
if (!existsSync2(filePath)) return {};
|
|
134
|
-
const content = readFileSync2(filePath, "utf-8");
|
|
135
|
-
const categories = {};
|
|
136
|
-
let currentCategory = "_uncategorized";
|
|
137
|
-
for (const line of content.split("\n")) {
|
|
138
|
-
const headerMatch = line.match(/^## (.+)/);
|
|
139
|
-
if (headerMatch) {
|
|
140
|
-
currentCategory = headerMatch[1];
|
|
141
|
-
categories[currentCategory] = categories[currentCategory] || [];
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
if (line.startsWith("- ") && currentCategory) {
|
|
145
|
-
categories[currentCategory] = categories[currentCategory] || [];
|
|
146
|
-
categories[currentCategory].push(line.slice(2));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return categories;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// src/core/tasks.ts
|
|
153
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
154
|
-
import { join as join3 } from "path";
|
|
155
|
-
function readTasks(projectDir) {
|
|
156
|
-
const filePath = join3(projectDir, TASKS_FILE);
|
|
157
|
-
const result = {
|
|
158
|
-
in_progress: [],
|
|
159
|
-
up_next: [],
|
|
160
|
-
completed: []
|
|
161
|
-
};
|
|
162
|
-
if (!existsSync3(filePath)) return result;
|
|
163
|
-
const content = readFileSync3(filePath, "utf-8");
|
|
164
|
-
let currentSection = null;
|
|
165
|
-
for (const line of content.split("\n")) {
|
|
166
|
-
if (line.startsWith("## In Progress")) {
|
|
167
|
-
currentSection = "in_progress";
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
if (line.startsWith("## Up Next")) {
|
|
171
|
-
currentSection = "up_next";
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
if (line.startsWith("## Completed")) {
|
|
175
|
-
currentSection = "completed";
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
if (currentSection && line.startsWith("- ")) {
|
|
179
|
-
result[currentSection].push(line.slice(2));
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return result;
|
|
183
|
-
}
|
|
184
|
-
function writeTasks(projectDir, tasks) {
|
|
185
|
-
const filePath = join3(projectDir, TASKS_FILE);
|
|
186
|
-
const content = `# Current Tasks
|
|
187
|
-
|
|
188
|
-
Working memory for cross-session continuity. Update before ending a session.
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
## In Progress
|
|
193
|
-
${tasks.in_progress.map((t) => `- ${t}`).join("\n") || ""}
|
|
194
|
-
|
|
195
|
-
## Up Next
|
|
196
|
-
${tasks.up_next.map((t) => `- ${t}`).join("\n") || ""}
|
|
197
|
-
|
|
198
|
-
## Completed
|
|
199
|
-
${tasks.completed.map((t) => `- ${t}`).join("\n") || ""}
|
|
200
|
-
`;
|
|
201
|
-
writeFileSync3(filePath, content);
|
|
102
|
+
function updateRouter(projectDir) {
|
|
103
|
+
const targetPath = join(projectDir, AGENTS_MD);
|
|
104
|
+
if (!existsSync(targetPath)) return false;
|
|
105
|
+
const projectName = guessProjectName(projectDir);
|
|
106
|
+
const vars = { PROJECT_NAME: projectName };
|
|
107
|
+
const content = applyVars(readTemplate("AGENTS.md"), vars);
|
|
108
|
+
writeFileSync(targetPath, content);
|
|
109
|
+
return true;
|
|
202
110
|
}
|
|
203
111
|
|
|
204
|
-
// src/
|
|
205
|
-
import { existsSync as
|
|
206
|
-
import { join as
|
|
112
|
+
// src/doctor.ts
|
|
113
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
114
|
+
import { join as join2 } from "path";
|
|
207
115
|
function doctor(projectDir) {
|
|
208
116
|
const issues = [];
|
|
209
117
|
const required = [
|
|
210
118
|
{ file: AGENTS_MD, desc: "Root router file" },
|
|
119
|
+
{ file: CUSTOM_FILE, desc: "Project specific rules" },
|
|
211
120
|
{ file: MEMORY_FILE, desc: "Long-term memory" },
|
|
212
121
|
{ file: TASKS_FILE, desc: "Working memory" }
|
|
213
122
|
];
|
|
214
123
|
for (const { file, desc } of required) {
|
|
215
|
-
const filePath =
|
|
216
|
-
if (!
|
|
124
|
+
const filePath = join2(projectDir, file);
|
|
125
|
+
if (!existsSync2(filePath)) {
|
|
217
126
|
issues.push({ level: "error", file, message: `Missing ${desc}` });
|
|
218
127
|
}
|
|
219
128
|
}
|
|
220
129
|
for (const dir of [AGENTS_DIR, SPEC_DIR]) {
|
|
221
|
-
if (!
|
|
130
|
+
if (!existsSync2(join2(projectDir, dir))) {
|
|
222
131
|
issues.push({ level: "error", file: dir, message: "Directory missing" });
|
|
223
132
|
}
|
|
224
133
|
}
|
|
225
|
-
const agentsPath =
|
|
226
|
-
if (
|
|
227
|
-
const content =
|
|
134
|
+
const agentsPath = join2(projectDir, AGENTS_MD);
|
|
135
|
+
if (existsSync2(agentsPath)) {
|
|
136
|
+
const content = readFileSync2(agentsPath, "utf-8");
|
|
228
137
|
if (!content.includes(".agents/")) {
|
|
229
138
|
issues.push({
|
|
230
139
|
level: "warning",
|
|
@@ -240,9 +149,9 @@ function doctor(projectDir) {
|
|
|
240
149
|
});
|
|
241
150
|
}
|
|
242
151
|
}
|
|
243
|
-
const memoryPath =
|
|
244
|
-
if (
|
|
245
|
-
const lines =
|
|
152
|
+
const memoryPath = join2(projectDir, MEMORY_FILE);
|
|
153
|
+
if (existsSync2(memoryPath)) {
|
|
154
|
+
const lines = readFileSync2(memoryPath, "utf-8").split("\n").length;
|
|
246
155
|
if (lines > 150) {
|
|
247
156
|
issues.push({
|
|
248
157
|
level: "warning",
|
|
@@ -256,14 +165,12 @@ function doctor(projectDir) {
|
|
|
256
165
|
export {
|
|
257
166
|
AGENTS_DIR,
|
|
258
167
|
AGENTS_MD,
|
|
168
|
+
CUSTOM_FILE,
|
|
259
169
|
MEMORY_DETAIL_FILE,
|
|
260
170
|
MEMORY_FILE,
|
|
261
171
|
SPEC_DIR,
|
|
262
172
|
TASKS_FILE,
|
|
263
|
-
appendMemory,
|
|
264
173
|
doctor,
|
|
265
|
-
readMemory,
|
|
266
|
-
readTasks,
|
|
267
174
|
scaffold,
|
|
268
|
-
|
|
175
|
+
updateRouter
|
|
269
176
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vuau/agent-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Structured AI memory for codebases — scaffolding CLI for OpenCode, Copilot, Cursor, Windsurf",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"prepublishOnly": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@types/node": "^25.6.0",
|
|
24
25
|
"tsup": "^8.0.0",
|
|
25
26
|
"typescript": "^6.0.3"
|
|
26
27
|
},
|
package/templates/AGENTS.md
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
# {{PROJECT_NAME}} - AGENTS
|
|
2
2
|
|
|
3
|
-
Router file for AI agents.
|
|
3
|
+
Router file for AI agents.
|
|
4
|
+
|
|
5
|
+
> **Note**: This file is automatically managed by `@vuau/agent-memory`.
|
|
6
|
+
> Do not add project-specific rules here, as they may be overwritten by `agent-memory update`.
|
|
7
|
+
>
|
|
8
|
+
> 👉 **For project-specific rules, context, and document mapping, see `.agents/CUSTOM.md`**
|
|
4
9
|
|
|
5
10
|
## Priority
|
|
6
11
|
1. User request first.
|
|
7
|
-
2.
|
|
8
|
-
3.
|
|
9
|
-
4.
|
|
10
|
-
|
|
11
|
-
## Documentation Map
|
|
12
|
-
|
|
13
|
-
| Task | Spec File |
|
|
14
|
-
|------|-----------|
|
|
15
|
-
| Past decisions (1-line) | `.agents/MEMORY.md` |
|
|
16
|
-
| Past decisions (full context) | `.agents/MEMORY-DETAIL.md` |
|
|
17
|
-
| Current work in progress | `.agents/TASKS.md` |
|
|
18
|
-
|
|
19
|
-
> Add your own spec files to `.agents/spec/` and reference them here.
|
|
12
|
+
2. The rules in `.agents/CUSTOM.md`.
|
|
13
|
+
3. This `AGENTS.md`.
|
|
14
|
+
4. Spec files in `.agents/spec/`.
|
|
15
|
+
5. If conflict remains, choose smallest safe change and state assumption.
|
|
20
16
|
|
|
21
17
|
## Memory Protocol
|
|
22
18
|
|
|
@@ -41,5 +37,6 @@ Before ending a session with unfinished work, move items to `## In Progress` or
|
|
|
41
37
|
|
|
42
38
|
## Response Style
|
|
43
39
|
- Concise, concrete, implementation-focused.
|
|
40
|
+
- Propose the simplest solution first (KISS & YAGNI) before writing code.
|
|
44
41
|
- If uncertain, say `I don't know`, then give fastest verification step.
|
|
45
42
|
- Do not invent files, APIs, or command outputs.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Project Rules & Document Map
|
|
2
|
+
|
|
3
|
+
This file contains project-specific rules, architectural decisions, and document mappings.
|
|
4
|
+
Feel free to modify this file to suit your project's needs.
|
|
5
|
+
|
|
6
|
+
## Documentation Map
|
|
7
|
+
|
|
8
|
+
| Task | Spec File |
|
|
9
|
+
|------|-----------|
|
|
10
|
+
| Past decisions (1-line) | `.agents/MEMORY.md` |
|
|
11
|
+
| Past decisions (full context) | `.agents/MEMORY-DETAIL.md` |
|
|
12
|
+
| Current work in progress | `.agents/TASKS.md` |
|
|
13
|
+
|
|
14
|
+
> Add your own spec files to `.agents/spec/` and reference them here.
|
|
15
|
+
|
|
16
|
+
## Custom Rules
|
|
17
|
+
|
|
18
|
+
- Add your project-specific rules here.
|