@vuau/agent-memory 0.4.0 → 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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @vuau/agent-memory
2
2
 
3
- Structured AI memory for codebases. Works with GitHub Copilot, Cursor, Windsurf, VS Code, OpenCode, and [25+ other AI coding tools](#supported-tools).
3
+ Structured AI memory for codebases. Uses `AGENTS.md` to work with OpenCode, GitHub Copilot, Cursor, Windsurf, and any AI coding assistant that reads markdown files.
4
4
 
5
5
  **[Tiếng Việt →](./README.vi.md)**
6
6
 
@@ -19,28 +19,26 @@ AI coding assistants lose context between sessions. They can't remember:
19
19
  npx @vuau/agent-memory init
20
20
  ```
21
21
 
22
- That's it. Creates `AGENTS.md` + `.agents/` structure.
23
-
24
22
  ## What It Creates
25
23
 
26
24
  ```
27
25
  / (Project Root)
28
- ├── AGENTS.md # Universal agent instructions
26
+ ├── AGENTS.md # Root agent rules
29
27
  └── .agents/
30
- ├── MEMORY.md # Long-term memory (decisions, patterns)
31
- ├── TASKS.md # Working memory (current tasks)
32
- └── spec/ # Detailed specs (on-demand)
28
+ ├── MEMORY.md # Long-term memory (decisions, patterns)
29
+ ├── TASKS.md # Working memory (current tasks)
30
+ └── spec/ # Detailed specs (on-demand)
33
31
  ```
34
32
 
35
33
  ## How It Works
36
34
 
37
35
  1. **You run `init`** → Creates `AGENTS.md` + `.agents/` structure
38
- 2. **Agent reads AGENTS.md** → Finds documentation map pointing to `.agents/`
36
+ 2. **Agent reads rules** → Finds documentation map pointing to `.agents/`
39
37
  3. **Agent works** → Reads MEMORY.md before implementing, updates TASKS.md
40
38
  4. **You approve decision** → Agent writes 1-line entry to MEMORY.md
41
39
  5. **Next session** → Agent reads memory, continues where you left off
42
40
 
43
- **No plugin required.** The instructions in AGENTS.md tell the agent what to do.
41
+ **No plugin required.** The rules in `AGENTS.md` instruct the agent what to do.
44
42
 
45
43
  ## CLI Options
46
44
 
@@ -48,8 +46,8 @@ That's it. Creates `AGENTS.md` + `.agents/` structure.
48
46
  npx @vuau/agent-memory init [options]
49
47
 
50
48
  Options:
51
- --force Overwrite existing files without asking
52
- --name <n> Project name (default: from package.json)
49
+ --force Overwrite existing files without asking
50
+ --name <n> Project name (default: from package.json)
53
51
 
54
52
  npx @vuau/agent-memory doctor # Validate structure
55
53
  npx @vuau/agent-memory help # Show help
@@ -57,7 +55,7 @@ npx @vuau/agent-memory help # Show help
57
55
 
58
56
  ## Memory Protocol
59
57
 
60
- Agents follow this protocol (defined in AGENTS.md):
58
+ Agents follow this protocol (defined in config files):
61
59
 
62
60
  ```markdown
63
61
  ## When to write
@@ -82,11 +80,11 @@ Agents follow this protocol (defined in AGENTS.md):
82
80
 
83
81
  ## Architecture
84
82
 
85
- ### 3-Layer Design
83
+ ### 4-Layer Design
86
84
 
87
85
  | Layer | File | Purpose |
88
86
  |-------|------|---------|
89
- | Instructions | AGENTS.md | Rules + pointers (~100 lines) |
87
+ | Router | AGENTS.md | Rules + pointers (~100 lines) |
90
88
  | Memory | .agents/MEMORY.md | Curated decisions (1-line each) |
91
89
  | Tasks | .agents/TASKS.md | Current work, next steps |
92
90
  | Specs | .agents/spec/*.md | Detailed docs (on-demand) |
@@ -104,17 +102,21 @@ File-based solution:
104
102
  - Plain markdown (portable, git-versionable, human-readable)
105
103
  - No dependencies (works everywhere)
106
104
 
107
- ## Supported Tools
105
+ ## Cross-IDE Compatibility
106
+
107
+ By default, we only scaffold `AGENTS.md`, which is an emerging standard router file.
108
108
 
109
- AGENTS.md is the universal format, supported by **25+ AI coding tools**:
109
+ If your tool requires a specific file (e.g. Cursor requires `.cursorrules`, GitHub Copilot requires `.github/copilot-instructions.md`), you can simply symlink or copy `AGENTS.md`:
110
110
 
111
- | Category | Tools |
112
- |----------|-------|
113
- | **IDEs** | Cursor, Windsurf, VS Code, Zed, RooCode, Kilo Code |
114
- | **CLI Tools** | OpenCode, Aider, goose, Gemini CLI, Warp, Augment Code |
115
- | **AI Agents** | GitHub Copilot, Codex (OpenAI), Jules (Google), Junie (JetBrains), Devin, Factory, Amp, Phoenix, Semgrep, Ona, UiPath Autopilot |
111
+ ```bash
112
+ # For Cursor
113
+ ln -s AGENTS.md .cursorrules
114
+
115
+ # For GitHub Copilot
116
+ mkdir -p .github && ln -s ../AGENTS.md .github/copilot-instructions.md
117
+ ```
116
118
 
117
- See [agents.md](https://agents.md) for the full list.
119
+ All tools will read from the same underlying `.agents/` memory structure.
118
120
 
119
121
  ## Documentation
120
122
 
package/README.vi.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @vuau/agent-memory
2
2
 
3
- Bộ nhớ AI có cấu trúc cho các codebase. Hoạt động với GitHub Copilot, Cursor, Windsurf, VS Code, OpenCode, và [25+ AI coding tools khác](#supported-tools).
3
+ Bộ nhớ AI có cấu trúc cho các codebase. Sử dụng `AGENTS.md` để hoạt động với OpenCode, GitHub Copilot, Cursor, Windsurf, bất kỳ AI coding assistant nào đọc markdown files.
4
4
 
5
5
  ## Bài toán
6
6
 
@@ -17,28 +17,26 @@ AI coding assistants mất bối cảnh giữa các phiên. Họ không thể nh
17
17
  npx @vuau/agent-memory init
18
18
  ```
19
19
 
20
- Đơn giản vậy thôi. Tạo `AGENTS.md` + `.agents/` structure.
21
-
22
20
  ## Cấu trúc tạo ra
23
21
 
24
22
  ```
25
23
  / (Project Root)
26
- ├── AGENTS.md # Universal agent instructions
24
+ ├── AGENTS.md # Root agent rules
27
25
  └── .agents/
28
- ├── MEMORY.md # Long-term memory (decisions, patterns)
29
- ├── TASKS.md # Working memory (current tasks)
30
- └── spec/ # Detailed specs (on-demand)
26
+ ├── MEMORY.md # Long-term memory (decisions, patterns)
27
+ ├── TASKS.md # Working memory (current tasks)
28
+ └── spec/ # Detailed specs (on-demand)
31
29
  ```
32
30
 
33
31
  ## Cách hoạt động
34
32
 
35
33
  1. **Bạn chạy `init`** → Tạo `AGENTS.md` + `.agents/` structure
36
- 2. **Agent đọc AGENTS.md** → Tìm documentation map trỏ đến `.agents/`
34
+ 2. **Agent đọc rules** → Tìm documentation map trỏ đến `.agents/`
37
35
  3. **Agent làm việc** → Đọc MEMORY.md trước khi implement, update TASKS.md
38
36
  4. **Bạn approve decision** → Agent ghi 1-line entry vào MEMORY.md
39
37
  5. **Phiên tiếp theo** → Agent đọc memory, tiếp tục từ nơi dừng lại
40
38
 
41
- **Không cần plugin.** Instructions trong AGENTS.md hướng dẫn agent phải làm gì.
39
+ **Không cần plugin.** Rules trong `AGENTS.md` hướng dẫn agent phải làm gì.
42
40
 
43
41
  ## CLI Options
44
42
 
@@ -46,8 +44,8 @@ npx @vuau/agent-memory init
46
44
  npx @vuau/agent-memory init [options]
47
45
 
48
46
  Options:
49
- --force Ghi đè files có sẵn mà không hỏi
50
- --name <n> Tên project (mặc định: từ package.json)
47
+ --force Ghi đè files có sẵn mà không hỏi
48
+ --name <n> Tên project (mặc định: từ package.json)
51
49
 
52
50
  npx @vuau/agent-memory doctor # Validate structure
53
51
  npx @vuau/agent-memory help # Hiện help
@@ -55,7 +53,7 @@ npx @vuau/agent-memory help # Hiện help
55
53
 
56
54
  ## Memory Protocol
57
55
 
58
- Agents follow protocol này (defined trong AGENTS.md):
56
+ Agents follow protocol này (defined trong config files):
59
57
 
60
58
  ```markdown
61
59
  ## Khi nào ghi
@@ -80,11 +78,11 @@ Agents follow protocol này (defined trong AGENTS.md):
80
78
 
81
79
  ## Kiến trúc
82
80
 
83
- ### Thiết kế 3-Layer
81
+ ### Thiết kế 4-Layer
84
82
 
85
83
  | Layer | File | Mục đích |
86
84
  |-------|------|----------|
87
- | Instructions | AGENTS.md | Rules + pointers (~100 dòng) |
85
+ | Router | AGENTS.md | Rules + pointers (~100 dòng) |
88
86
  | Memory | .agents/MEMORY.md | Curated decisions (1-line each) |
89
87
  | Tasks | .agents/TASKS.md | Current work, next steps |
90
88
  | Specs | .agents/spec/*.md | Detailed docs (on-demand) |
@@ -102,17 +100,21 @@ File-based solution:
102
100
  - Plain markdown (portable, git-versionable, human-readable)
103
101
  - Không dependencies (works everywhere)
104
102
 
105
- ## Supported Tools
103
+ ## Cross-IDE Compatibility
104
+
105
+ Mặc định, công cụ chỉ scaffold `AGENTS.md`, một chuẩn router file đang phổ biến.
106
106
 
107
- AGENTS.md format universal, được hỗ trợ bởi **25+ AI coding tools**:
107
+ Nếu công cụ của bạn yêu cầu một file cụ thể (vd: Cursor yêu cầu `.cursorrules`, GitHub Copilot yêu cầu `.github/copilot-instructions.md`), bạn thể đơn giản dùng symlink hoặc copy `AGENTS.md`:
108
108
 
109
- | Category | Tools |
110
- |----------|-------|
111
- | **IDEs** | Cursor, Windsurf, VS Code, Zed, RooCode, Kilo Code |
112
- | **CLI Tools** | OpenCode, Aider, goose, Gemini CLI, Warp, Augment Code |
113
- | **AI Agents** | GitHub Copilot, Codex (OpenAI), Jules (Google), Junie (JetBrains), Devin, Factory, Amp, Phoenix, Semgrep, Ona, UiPath Autopilot |
109
+ ```bash
110
+ # Cho Cursor
111
+ ln -s AGENTS.md .cursorrules
112
+
113
+ # Cho GitHub Copilot
114
+ mkdir -p .github && ln -s ../AGENTS.md .github/copilot-instructions.md
115
+ ```
114
116
 
115
- Xem [agents.md](https://agents.md) để danh sách đầy đủ.
117
+ Tất cả các công cụ sẽ cùng đọc chung cấu trúc bộ nhớ bên trong thư mục `.agents/`.
116
118
 
117
119
  ## Tài liệu
118
120
 
package/dist/bin/cli.js CHANGED
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // bin/cli.ts
4
- import * as readline from "readline";
5
4
  import { existsSync as existsSync3 } from "fs";
6
5
  import { join as join3 } from "path";
7
6
 
8
- // src/core/scaffold.ts
7
+ // src/scaffold.ts
9
8
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
10
9
  import { join, resolve, dirname } from "path";
11
10
  import { fileURLToPath } from "url";
12
11
 
13
- // src/core/types.ts
12
+ // src/types.ts
14
13
  var AGENTS_DIR = ".agents";
15
14
  var SPEC_DIR = ".agents/spec";
16
15
  var MEMORY_FILE = ".agents/MEMORY.md";
17
16
  var MEMORY_DETAIL_FILE = ".agents/MEMORY-DETAIL.md";
18
17
  var TASKS_FILE = ".agents/TASKS.md";
18
+ var CUSTOM_FILE = ".agents/CUSTOM.md";
19
19
  var AGENTS_MD = "AGENTS.md";
20
20
 
21
- // src/core/scaffold.ts
21
+ // src/scaffold.ts
22
22
  function getTemplatesDir() {
23
23
  const thisDir = dirname(fileURLToPath(import.meta.url));
24
24
  const fromSource = resolve(thisDir, "../../templates");
@@ -56,17 +56,11 @@ function scaffold(projectDir, options = {}) {
56
56
  mkdirSync(dir, { recursive: true });
57
57
  }
58
58
  }
59
- writeFileIfNeeded(
60
- join(projectDir, AGENTS_MD),
61
- applyVars(readTemplate("AGENTS.md"), vars),
62
- AGENTS_MD,
63
- result,
64
- force
65
- );
66
59
  const coreFiles = [
67
60
  { target: MEMORY_FILE, template: "MEMORY.md" },
68
61
  { target: MEMORY_DETAIL_FILE, template: "MEMORY-DETAIL.md" },
69
- { target: TASKS_FILE, template: "TASKS.md" }
62
+ { target: TASKS_FILE, template: "TASKS.md" },
63
+ { target: CUSTOM_FILE, template: "CUSTOM.md" }
70
64
  ];
71
65
  for (const { target, template } of coreFiles) {
72
66
  const targetPath = join(projectDir, target);
@@ -83,6 +77,13 @@ function scaffold(projectDir, options = {}) {
83
77
  writeFileSync(specKeep, "");
84
78
  result.created.push(`${SPEC_DIR}/.gitkeep`);
85
79
  }
80
+ writeFileIfNeeded(
81
+ join(projectDir, AGENTS_MD),
82
+ applyVars(readTemplate("AGENTS.md"), vars),
83
+ AGENTS_MD,
84
+ result,
85
+ force
86
+ );
86
87
  return result;
87
88
  }
88
89
  function writeFileIfNeeded(targetPath, content, displayName, result, force) {
@@ -104,14 +105,24 @@ function guessProjectName(dir) {
104
105
  }
105
106
  return dir.split("/").pop() || "Project";
106
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
+ }
107
117
 
108
- // src/core/doctor.ts
118
+ // src/doctor.ts
109
119
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
110
120
  import { join as join2 } from "path";
111
121
  function doctor(projectDir) {
112
122
  const issues = [];
113
123
  const required = [
114
- { file: AGENTS_MD, desc: "Root agent instructions" },
124
+ { file: AGENTS_MD, desc: "Root router file" },
125
+ { file: CUSTOM_FILE, desc: "Project specific rules" },
115
126
  { file: MEMORY_FILE, desc: "Long-term memory" },
116
127
  { file: TASKS_FILE, desc: "Working memory" }
117
128
  ];
@@ -140,7 +151,7 @@ function doctor(projectDir) {
140
151
  issues.push({
141
152
  level: "warning",
142
153
  file: AGENTS_MD,
143
- message: "Over 150 lines \u2014 consider keeping it concise"
154
+ message: "Over 150 lines \u2014 consider keeping it concise as a router"
144
155
  });
145
156
  }
146
157
  }
@@ -161,28 +172,13 @@ function doctor(projectDir) {
161
172
  // bin/cli.ts
162
173
  var args = process.argv.slice(2);
163
174
  var command = args[0];
164
- var rl = readline.createInterface({
165
- input: process.stdin,
166
- output: process.stdout
167
- });
168
- function ask(question) {
169
- return new Promise((resolve2) => {
170
- rl.question(question, (answer) => resolve2(answer.trim()));
171
- });
172
- }
173
- function askYesNo(question, defaultYes = true) {
174
- const hint = defaultYes ? "(Y/n)" : "(y/N)";
175
- return ask(`${question} ${hint} `).then((answer) => {
176
- if (!answer) return defaultYes;
177
- return answer.toLowerCase().startsWith("y");
178
- });
179
- }
180
175
  function printUsage() {
181
176
  console.log(`
182
177
  @vuau/agent-memory \u2014 Structured AI memory for codebases
183
178
 
184
179
  Usage:
185
- agent-memory init [options] Scaffold AGENTS.md + .agents/ structure
180
+ agent-memory init [options] Scaffold .agents/ structure and AGENTS.md
181
+ agent-memory update Update AGENTS.md router to latest version
186
182
  agent-memory doctor Validate .agents/ structure
187
183
  agent-memory help Show this help
188
184
 
@@ -191,14 +187,8 @@ Options (init):
191
187
  --name <name> Project name (default: from package.json)
192
188
 
193
189
  Examples:
194
- npx @vuau/agent-memory init # Create AGENTS.md + .agents/
195
- npx @vuau/agent-memory init --force # Overwrite existing files
196
- npx @vuau/agent-memory doctor # Check structure
197
-
198
- AGENTS.md is the universal format supported by 25+ AI coding tools:
199
- GitHub Copilot, Cursor, Windsurf, VS Code, OpenCode, Codex, Jules,
200
- Junie, Gemini CLI, Devin, Aider, goose, Factory, Amp, RooCode,
201
- Zed, Warp, Kilo Code, Phoenix, Semgrep, Ona, UiPath, Augment Code...
190
+ npx @vuau/agent-memory init
191
+ npx @vuau/agent-memory init --force
202
192
  `);
203
193
  }
204
194
  async function runInit() {
@@ -207,31 +197,9 @@ async function runInit() {
207
197
  const nameIdx = args.indexOf("--name");
208
198
  const projectName = nameIdx !== -1 ? args[nameIdx + 1] : void 0;
209
199
  const options = {
210
- projectName
200
+ projectName,
201
+ force
211
202
  };
212
- if (!force) {
213
- const filesToCheck = [
214
- { path: AGENTS_MD, name: "AGENTS.md" },
215
- { path: MEMORY_FILE, name: ".agents/MEMORY.md" },
216
- { path: TASKS_FILE, name: ".agents/TASKS.md" }
217
- ];
218
- const existingFiles = filesToCheck.filter((f) => existsSync3(join3(cwd, f.path)));
219
- if (existingFiles.length > 0) {
220
- console.log("\nExisting files found:");
221
- for (const f of existingFiles) {
222
- console.log(` - ${f.name}`);
223
- }
224
- const overwrite = await askYesNo("\nOverwrite these files?", false);
225
- if (!overwrite) {
226
- console.log("\nAborted. Use --force to overwrite without asking.\n");
227
- rl.close();
228
- return;
229
- }
230
- options.force = true;
231
- }
232
- } else {
233
- options.force = true;
234
- }
235
203
  console.log(`
236
204
  Initializing agent memory in ${cwd}...
237
205
  `);
@@ -247,13 +215,35 @@ Initializing agent memory in ${cwd}...
247
215
  for (const f of result.skipped) {
248
216
  console.log(` - ${f}`);
249
217
  }
218
+ if (!force) {
219
+ console.log("\nTip: Use --force to overwrite existing files.");
220
+ }
250
221
  }
251
222
  console.log("\nNext steps:");
252
223
  console.log(" 1. Edit AGENTS.md \u2014 add project-specific rules");
253
224
  console.log(" 2. Add spec files to .agents/spec/ for detailed documentation");
254
- console.log(" 3. AI agents will read AGENTS.md and write to .agents/ automatically");
225
+ console.log(" 3. Agent will read rules and write to .agents/MEMORY.md automatically");
226
+ console.log("");
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
+ }
255
246
  console.log("");
256
- rl.close();
257
247
  }
258
248
  function runDoctor() {
259
249
  const cwd = process.cwd();
@@ -278,7 +268,12 @@ switch (command) {
278
268
  case "init":
279
269
  runInit().catch((err) => {
280
270
  console.error("Error:", err.message);
281
- rl.close();
271
+ process.exit(1);
272
+ });
273
+ break;
274
+ case "update":
275
+ runUpdate().catch((err) => {
276
+ console.error("Error:", err.message);
282
277
  process.exit(1);
283
278
  });
284
279
  break;
@@ -293,7 +288,6 @@ switch (command) {
293
288
  case void 0:
294
289
  runInit().catch((err) => {
295
290
  console.error("Error:", err.message);
296
- rl.close();
297
291
  process.exit(1);
298
292
  });
299
293
  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");
@@ -49,17 +50,11 @@ function scaffold(projectDir, options = {}) {
49
50
  mkdirSync(dir, { recursive: true });
50
51
  }
51
52
  }
52
- writeFileIfNeeded(
53
- join(projectDir, AGENTS_MD),
54
- applyVars(readTemplate("AGENTS.md"), vars),
55
- AGENTS_MD,
56
- result,
57
- force
58
- );
59
53
  const coreFiles = [
60
54
  { target: MEMORY_FILE, template: "MEMORY.md" },
61
55
  { target: MEMORY_DETAIL_FILE, template: "MEMORY-DETAIL.md" },
62
- { target: TASKS_FILE, template: "TASKS.md" }
56
+ { target: TASKS_FILE, template: "TASKS.md" },
57
+ { target: CUSTOM_FILE, template: "CUSTOM.md" }
63
58
  ];
64
59
  for (const { target, template } of coreFiles) {
65
60
  const targetPath = join(projectDir, target);
@@ -76,6 +71,13 @@ function scaffold(projectDir, options = {}) {
76
71
  writeFileSync(specKeep, "");
77
72
  result.created.push(`${SPEC_DIR}/.gitkeep`);
78
73
  }
74
+ writeFileIfNeeded(
75
+ join(projectDir, AGENTS_MD),
76
+ applyVars(readTemplate("AGENTS.md"), vars),
77
+ AGENTS_MD,
78
+ result,
79
+ force
80
+ );
79
81
  return result;
80
82
  }
81
83
  function writeFileIfNeeded(targetPath, content, displayName, result, force) {
@@ -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
- { file: AGENTS_MD, desc: "Root agent instructions" },
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",
@@ -236,13 +145,13 @@ function doctor(projectDir) {
236
145
  issues.push({
237
146
  level: "warning",
238
147
  file: AGENTS_MD,
239
- message: "Over 150 lines \u2014 consider keeping it concise"
148
+ message: "Over 150 lines \u2014 consider keeping it concise as a router"
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
  };
@@ -168,28 +168,21 @@ This document proposes a generalizable architecture for AI memory across codebas
168
168
 
169
169
  ---
170
170
 
171
- ## IDE Integration Points
171
+ ## Integration Points
172
172
 
173
- ### OpenCode
174
- - Reads: AGENTS.md (via plugin hook)
175
- - Plugin auto-injects: `.agents/MEMORY.md` context on session start
176
- - Plugin reminds: Update TASKS.md on session idle
177
- - Writes: Agent appends to MEMORY.md/TASKS.md/spec/
173
+ By default, we scaffold `AGENTS.md` which acts as the root router for your AI coding assistant. This file contains rules and documentation maps that point to the `.agents/` folder.
178
174
 
179
- ### GitHub Copilot (VSCode)
180
- - Reads: `.github/copilot-instructions.md` (GitHub convention)
181
- - copilot-instructions.md = same router format as AGENTS.md
182
- - Points to `.agents/MEMORY.md` + spec files
183
- - Writes: User includes `@save memory: <decision>` in chat → agent appends
175
+ If your specific AI tool requires a different file name, you can simply symlink the `AGENTS.md` file:
184
176
 
185
- ### Cursor / Windsurf
186
- - Reads: `.cursorrules` / `.windsurfrules` (IDE convention)
187
- - Same router format, points to `.agents/`
188
- - Writes: Agent rules instruct direct append
177
+ ```bash
178
+ # Example: For Cursor
179
+ ln -s AGENTS.md .cursorrules
189
180
 
190
- ### CLI / Non-IDE Workflows
191
- - Humans can read/edit `.agents/` files directly
192
- - No special IDE integration needed
181
+ # Example: For GitHub Copilot
182
+ mkdir -p .github && ln -s ../AGENTS.md .github/copilot-instructions.md
183
+ ```
184
+
185
+ This ensures a single source of truth (`AGENTS.md`) is maintained while providing backward compatibility with any tool.
193
186
 
194
187
  ---
195
188
 
@@ -219,12 +212,12 @@ This document proposes a generalizable architecture for AI memory across codebas
219
212
  - Keep `.memsearch/memory/` as archive (1 year retention)
220
213
  - Delete milvus.db
221
214
 
222
- ### From .github/copilot-instructions.md (monolithic)
215
+ ### From Monolithic Config Files (e.g. .cursorrules)
223
216
 
224
217
  1. **Extract decisions** → `.agents/MEMORY.md`
225
218
  2. **Extract patterns** → `.agents/spec/patterns.md`
226
219
  3. **Extract commands** → `AGENTS.md`
227
- 4. **Keep router** → update `.github/copilot-instructions.md` to point to `.agents/`
220
+ 4. **Keep router** → Create symlink from your old config file to `AGENTS.md`
228
221
 
229
222
  ---
230
223
 
@@ -254,10 +247,8 @@ This document proposes a generalizable architecture for AI memory across codebas
254
247
  ## Tooling Support
255
248
 
256
249
  ### CLI
257
- - ✓ `npx @vuau/agent-memory init` — scaffold structure (interactive or with flags)
258
- - ✓ `npx @vuau/agent-memory init --opencode` — OpenCode only
259
- - ✓ `npx @vuau/agent-memory init --copilot --cursor` — multiple IDEs
260
- - ✓ `npx @vuau/agent-memory init --all` — all IDEs
250
+ - ✓ `npx @vuau/agent-memory init` — scaffold structure (`AGENTS.md` + `.agents/`)
251
+ - ✓ `npx @vuau/agent-memory init --force` — overwrite existing files
261
252
  - ✓ `npx @vuau/agent-memory doctor` — validate structure
262
253
  - Planned: ✗ `report` — generate memory stats, archival suggestions
263
254
 
@@ -168,27 +168,21 @@ Tài liệu này đề xuất kiến trúc khả năng skalabiliti cho AI memory
168
168
 
169
169
  ---
170
170
 
171
- ## IDE Integration Points
171
+ ## Điểm Tích Hợp
172
172
 
173
- ### OpenCode
174
- - Reads: `AGENTS.md` (native)
175
- - Agents follow rules trong AGENTS.md
176
- - Writes: Agent appends đến MEMORY.md/TASKS.md/spec/
173
+ Mặc định, chúng tôi scaffold `AGENTS.md` hoạt động như root router cho AI coding assistant của bạn. File này chứa các rules và documentation maps trỏ đến thư mục `.agents/`.
177
174
 
178
- ### GitHub Copilot (VSCode)
179
- - Reads: `.github/copilot-instructions.md` (GitHub convention)
180
- - copilot-instructions.md = cùng router format với AGENTS.md
181
- - Points đến `.agents/MEMORY.md` + spec files
182
- - Writes: Agent follows rules → appends khi appropriate
175
+ Nếu công cụ AI cụ thể của bạn yêu cầu một tên file khác, bạn có thể dễ dàng dùng symlink file `AGENTS.md`:
183
176
 
184
- ### Cursor / Windsurf
185
- - Reads: `.cursorrules` / `.windsurfrules` (IDE convention)
186
- - Cùng router format, points đến `.agents/`
187
- - Writes: Agent rules instruct direct append
177
+ ```bash
178
+ # dụ: Cho Cursor
179
+ ln -s AGENTS.md .cursorrules
188
180
 
189
- ### CLI / Non-IDE Workflows
190
- - Humans thể read/edit `.agents/` files trực tiếp
191
- - Không cần special IDE integration
181
+ # dụ: Cho GitHub Copilot
182
+ mkdir -p .github && ln -s ../AGENTS.md .github/copilot-instructions.md
183
+ ```
184
+
185
+ Điều này đảm bảo single source of truth (`AGENTS.md`) được duy trì trong khi cung cấp khả năng tương thích ngược với mọi công cụ.
192
186
 
193
187
  ---
194
188
 
@@ -218,12 +212,12 @@ Tài liệu này đề xuất kiến trúc khả năng skalabiliti cho AI memory
218
212
  - Keep `.memsearch/memory/` như archive (1 year retention)
219
213
  - Delete milvus.db
220
214
 
221
- ### Từ .github/copilot-instructions.md (monolithic)
215
+ ### Từ Monolithic Config Files (vd: .cursorrules)
222
216
 
223
217
  1. **Extract decisions** → `.agents/MEMORY.md`
224
218
  2. **Extract patterns** → `.agents/spec/patterns.md`
225
219
  3. **Extract commands** → `AGENTS.md`
226
- 4. **Keep router** → update `.github/copilot-instructions.md` để point đến `.agents/`
220
+ 4. **Keep router** → Tạo symlink từ config file cũ của bạn trỏ tới `AGENTS.md`
227
221
 
228
222
  ---
229
223
 
@@ -253,10 +247,8 @@ Tài liệu này đề xuất kiến trúc khả năng skalabiliti cho AI memory
253
247
  ## Công cụ Support
254
248
 
255
249
  ### CLI
256
- - ✓ `npx @vuau/agent-memory init` — scaffold structure (interactive hoặc với flags)
257
- - ✓ `npx @vuau/agent-memory init --opencode` — chỉ OpenCode
258
- - ✓ `npx @vuau/agent-memory init --copilot --cursor` — nhiều IDEs
259
- - ✓ `npx @vuau/agent-memory init --all` — tất cả IDEs
250
+ - ✓ `npx @vuau/agent-memory init` — scaffold structure (`AGENTS.md` + `.agents/`)
251
+ - ✓ `npx @vuau/agent-memory init --force` — ghi đè files có sẵn
260
252
  - ✓ `npx @vuau/agent-memory doctor` — validate structure
261
253
  - Planned: ✗ `report` — generate memory stats, archival suggestions
262
254
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vuau/agent-memory",
3
- "version": "0.4.0",
4
- "description": "Structured AI memory for codebases — works with GitHub Copilot, Cursor, Windsurf, VS Code, OpenCode, and 25+ AI tools",
3
+ "version": "0.5.0",
4
+ "description": "Structured AI memory for codebases — scaffolding CLI for OpenCode, Copilot, Cursor, Windsurf",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "exports": {
@@ -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.