@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 CHANGED
@@ -1,19 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/core/scaffold.ts
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/core/types.ts
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/core/scaffold.ts
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/core/doctor.ts
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/core/scaffold.ts
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/core/types.ts
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/core/scaffold.ts
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
- // src/core/memory.ts
102
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
103
- import { join as join2 } from "path";
104
- function appendMemory(projectDir, entry) {
105
- const filePath = join2(projectDir, MEMORY_FILE);
106
- if (!existsSync2(filePath)) {
107
- throw new Error(`${MEMORY_FILE} not found. Run 'agent-memory init' first.`);
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/core/doctor.ts
205
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
206
- import { join as join4 } from "path";
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 = join4(projectDir, file);
216
- if (!existsSync4(filePath)) {
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 (!existsSync4(join4(projectDir, dir))) {
130
+ if (!existsSync2(join2(projectDir, dir))) {
222
131
  issues.push({ level: "error", file: dir, message: "Directory missing" });
223
132
  }
224
133
  }
225
- const agentsPath = join4(projectDir, AGENTS_MD);
226
- if (existsSync4(agentsPath)) {
227
- const content = readFileSync4(agentsPath, "utf-8");
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 = join4(projectDir, MEMORY_FILE);
244
- if (existsSync4(memoryPath)) {
245
- const lines = readFileSync4(memoryPath, "utf-8").split("\n").length;
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
- writeTasks
175
+ updateRouter
269
176
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vuau/agent-memory",
3
- "version": "0.4.1",
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
  },
@@ -1,22 +1,18 @@
1
1
  # {{PROJECT_NAME}} - AGENTS
2
2
 
3
- Router file for AI agents. Keep under 150 lines.
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. This `AGENTS.md`.
8
- 3. Spec files in `.agents/spec/`.
9
- 4. If conflict remains, choose smallest safe change and state assumption.
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.