@vuau/agent-memory 0.5.5 → 0.6.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 +12 -7
- package/README.vi.md +12 -7
- package/dist/bin/cli.js +101 -40
- package/dist/index.js +96 -34
- package/package.json +2 -2
- package/templates/AGENTS.md +4 -1
- package/templates/CLAUDE.md +14 -0
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, and any AI coding assistant that reads markdown files.
|
|
3
|
+
Structured AI memory for codebases. Works with GitHub Copilot, Cursor, Windsurf, Claude Code, OpenCode, and any AI coding assistant that reads markdown files.
|
|
4
4
|
|
|
5
5
|
**[Tiếng Việt →](./README.vi.md)**
|
|
6
6
|
|
|
@@ -18,7 +18,8 @@ npx @vuau/agent-memory init
|
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
/ (Project Root)
|
|
21
|
-
├── AGENTS.md #
|
|
21
|
+
├── AGENTS.md # Copilot, Cursor, Windsurf, OpenCode …
|
|
22
|
+
├── CLAUDE.md # Claude Code (symlink → AGENTS.md on macOS/Linux)
|
|
22
23
|
└── .agents/
|
|
23
24
|
├── CUSTOM.md # Project-specific rules & spec mapping
|
|
24
25
|
├── MEMORY.md # Long-term memory (decisions, patterns)
|
|
@@ -29,15 +30,15 @@ npx @vuau/agent-memory init
|
|
|
29
30
|
## How It Works
|
|
30
31
|
|
|
31
32
|
1. **You run `init`** → Creates the structure. `AGENTS.md` points to `.agents/CUSTOM.md`.
|
|
32
|
-
2. **Agent reads rules** → Follows the priority: CUSTOM.md > AGENTS.md > spec files.
|
|
33
|
+
2. **Agent reads rules** → Follows the priority: CUSTOM.md > AGENTS/CLAUDE.md > spec files.
|
|
33
34
|
3. **Agent works** → Updates MEMORY.md for decisions and TASKS.md for progress.
|
|
34
|
-
4. **Update package** → Run `agent-memory update` to get the latest
|
|
35
|
+
4. **Update package** → Run `agent-memory update` to get the latest router files without losing your custom rules.
|
|
35
36
|
|
|
36
37
|
## CLI Commands
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
40
|
npx @vuau/agent-memory init # Scaffold .agents/ structure
|
|
40
|
-
npx @vuau/agent-memory update # Update AGENTS.md
|
|
41
|
+
npx @vuau/agent-memory update # Update router files (AGENTS.md, CLAUDE.md) to latest version
|
|
41
42
|
npx @vuau/agent-memory doctor # Validate structure integrity
|
|
42
43
|
npx @vuau/agent-memory help # Show help
|
|
43
44
|
```
|
|
@@ -46,8 +47,12 @@ npx @vuau/agent-memory help # Show help
|
|
|
46
47
|
|
|
47
48
|
### The Router Split
|
|
48
49
|
|
|
49
|
-
-
|
|
50
|
-
|
|
50
|
+
- **`AGENTS.md`** — For GitHub Copilot, Cursor, Windsurf, OpenCode, and general AI coding assistants.
|
|
51
|
+
Read by: Copilot (`.github/copilot-instructions.md` instructions point here), Cursor (`@AGENTS.md`), Windsurf (`.windsurfrules` references).
|
|
52
|
+
- **`CLAUDE.md`** — For Claude Code exclusively.
|
|
53
|
+
On macOS/Linux it's a **symlink to `AGENTS.md`** so content is always in sync.
|
|
54
|
+
On Windows it's a **hook file** that tells Claude Code to read `AGENTS.md`.
|
|
55
|
+
- **`.agents/CUSTOM.md`** — Your project's home for custom rules, architectural decisions, and documentation mapping.
|
|
51
56
|
|
|
52
57
|
### Memory Files
|
|
53
58
|
|
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, và bất kỳ AI coding assistant nào đọc markdown files.
|
|
3
|
+
Bộ nhớ AI có cấu trúc cho các codebase. Hoạt động với GitHub Copilot, Cursor, Windsurf, Claude Code, OpenCode, và bất kỳ AI coding assistant nào đọc markdown files.
|
|
4
4
|
|
|
5
5
|
**[English →](./README.md)**
|
|
6
6
|
|
|
@@ -18,7 +18,8 @@ npx @vuau/agent-memory init
|
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
/ (Project Root)
|
|
21
|
-
├── AGENTS.md #
|
|
21
|
+
├── AGENTS.md # Copilot, Cursor, Windsurf, OpenCode …
|
|
22
|
+
├── CLAUDE.md # Claude Code (symlink → AGENTS.md trên macOS/Linux)
|
|
22
23
|
└── .agents/
|
|
23
24
|
├── CUSTOM.md # Rules riêng của project & mapping tài liệu
|
|
24
25
|
├── MEMORY.md # Bộ nhớ dài hạn (quyết định, patterns)
|
|
@@ -29,15 +30,15 @@ npx @vuau/agent-memory init
|
|
|
29
30
|
## Cách hoạt động
|
|
30
31
|
|
|
31
32
|
1. **Bạn chạy `init`** → Tạo cấu trúc thư mục. `AGENTS.md` sẽ trỏ đến `.agents/CUSTOM.md`.
|
|
32
|
-
2. **Agent đọc rules** → Tuân theo ưu tiên: CUSTOM.md > AGENTS.md > spec files.
|
|
33
|
+
2. **Agent đọc rules** → Tuân theo ưu tiên: CUSTOM.md > AGENTS/CLAUDE.md > spec files.
|
|
33
34
|
3. **Agent làm việc** → Cập nhật MEMORY.md cho các quyết định và TASKS.md cho tiến độ công việc.
|
|
34
|
-
4. **Cập nhật package** → Chạy `agent-memory update` để nhận router
|
|
35
|
+
4. **Cập nhật package** → Chạy `agent-memory update` để nhận các router files mới nhất mà không mất rules tùy chỉnh của bạn.
|
|
35
36
|
|
|
36
37
|
## Các lệnh CLI
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
40
|
npx @vuau/agent-memory init # Khởi tạo cấu trúc .agents/
|
|
40
|
-
npx @vuau/agent-memory update # Cập nhật router AGENTS.md lên bản mới nhất
|
|
41
|
+
npx @vuau/agent-memory update # Cập nhật router files (AGENTS.md, CLAUDE.md) lên bản mới nhất
|
|
41
42
|
npx @vuau/agent-memory doctor # Kiểm tra tính toàn vẹn của cấu trúc
|
|
42
43
|
npx @vuau/agent-memory help # Hiện trợ giúp
|
|
43
44
|
```
|
|
@@ -46,8 +47,12 @@ npx @vuau/agent-memory help # Hiện trợ giúp
|
|
|
46
47
|
|
|
47
48
|
### Phân tách Router
|
|
48
49
|
|
|
49
|
-
-
|
|
50
|
-
|
|
50
|
+
- **`AGENTS.md`** — Dành cho GitHub Copilot, Cursor, Windsurf, OpenCode, và các AI coding assistants thông thường.
|
|
51
|
+
Cách đọc: Copilot (chỉ định trong `.github/copilot-instructions.md`), Cursor (`@AGENTS.md`), Windsurf (tham chiếu trong `.windsurfrules`).
|
|
52
|
+
- **`CLAUDE.md`** — Riêng cho Claude Code.
|
|
53
|
+
Trên macOS/Linux: **symlink đến `AGENTS.md`** để luôn đồng bộ.
|
|
54
|
+
Trên Windows: **hook file** yêu cầu Claude Code đọc `AGENTS.md`.
|
|
55
|
+
- **`.agents/CUSTOM.md`** — Nơi dành riêng cho dự án của bạn để viết custom rules, quyết định kiến trúc và mapping tài liệu.
|
|
51
56
|
|
|
52
57
|
### Các file bộ nhớ
|
|
53
58
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -5,9 +5,10 @@ import { existsSync as existsSync3 } from "fs";
|
|
|
5
5
|
import { join as join3 } from "path";
|
|
6
6
|
|
|
7
7
|
// src/scaffold.ts
|
|
8
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
8
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, symlinkSync, lstatSync, unlinkSync } from "fs";
|
|
9
9
|
import { join, resolve, dirname } from "path";
|
|
10
10
|
import { fileURLToPath } from "url";
|
|
11
|
+
import { platform } from "os";
|
|
11
12
|
|
|
12
13
|
// src/types.ts
|
|
13
14
|
var AGENTS_DIR = ".agents";
|
|
@@ -17,6 +18,7 @@ var MEMORY_DETAIL_FILE = ".agents/MEMORY-DETAIL.md";
|
|
|
17
18
|
var TASKS_FILE = ".agents/TASKS.md";
|
|
18
19
|
var CUSTOM_FILE = ".agents/CUSTOM.md";
|
|
19
20
|
var AGENTS_MD = "AGENTS.md";
|
|
21
|
+
var CLAUDE_MD = "CLAUDE.md";
|
|
20
22
|
|
|
21
23
|
// src/scaffold.ts
|
|
22
24
|
function getTemplatesDir() {
|
|
@@ -93,6 +95,7 @@ function scaffold(projectDir, options = {}) {
|
|
|
93
95
|
result,
|
|
94
96
|
force
|
|
95
97
|
);
|
|
98
|
+
writeClaudeMd(projectDir, vars, result, force);
|
|
96
99
|
return result;
|
|
97
100
|
}
|
|
98
101
|
function writeFileIfNeeded(targetPath, content, displayName, result, force) {
|
|
@@ -114,26 +117,67 @@ function guessProjectName(dir) {
|
|
|
114
117
|
}
|
|
115
118
|
return dir.split("/").pop() || "Project";
|
|
116
119
|
}
|
|
120
|
+
var IS_WIN = platform() === "win32";
|
|
121
|
+
function writeClaudeMd(projectDir, vars, result, force) {
|
|
122
|
+
const targetPath = join(projectDir, CLAUDE_MD);
|
|
123
|
+
if (IS_WIN) {
|
|
124
|
+
writeFileIfNeeded(
|
|
125
|
+
targetPath,
|
|
126
|
+
applyVars(readTemplate("CLAUDE.md"), vars),
|
|
127
|
+
CLAUDE_MD,
|
|
128
|
+
result,
|
|
129
|
+
force
|
|
130
|
+
);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const linkTarget = AGENTS_MD;
|
|
134
|
+
if (existsSync(targetPath)) {
|
|
135
|
+
if (!force) {
|
|
136
|
+
result.skipped.push(CLAUDE_MD);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
unlinkSync(targetPath);
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
symlinkSync(linkTarget, targetPath);
|
|
143
|
+
result.created.push(`${CLAUDE_MD} \u2192 ${AGENTS_MD}`);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
writeFileSync(targetPath, applyVars(readTemplate("CLAUDE.md"), vars));
|
|
146
|
+
result.created.push(`${CLAUDE_MD} (symlink failed, wrote file)`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
117
149
|
function updateRouter(projectDir) {
|
|
118
|
-
const targetPath = join(projectDir, AGENTS_MD);
|
|
119
|
-
if (!existsSync(targetPath)) return false;
|
|
120
150
|
const projectName = guessProjectName(projectDir);
|
|
121
151
|
const vars = { PROJECT_NAME: projectName };
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
152
|
+
const agentsPath = join(projectDir, AGENTS_MD);
|
|
153
|
+
if (!existsSync(agentsPath)) return false;
|
|
154
|
+
writeFileSync(agentsPath, applyVars(readTemplate("AGENTS.md"), vars));
|
|
155
|
+
const claudePath = join(projectDir, CLAUDE_MD);
|
|
156
|
+
if (IS_WIN) {
|
|
157
|
+
writeFileSync(claudePath, applyVars(readTemplate("CLAUDE.md"), vars));
|
|
158
|
+
} else {
|
|
159
|
+
let needsRecreate = false;
|
|
160
|
+
if (!existsSync(claudePath)) {
|
|
161
|
+
needsRecreate = true;
|
|
162
|
+
} else {
|
|
163
|
+
try {
|
|
164
|
+
const stat = lstatSync(claudePath);
|
|
165
|
+
if (!stat.isSymbolicLink()) {
|
|
166
|
+
needsRecreate = true;
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
needsRecreate = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (needsRecreate) {
|
|
173
|
+
try {
|
|
174
|
+
if (existsSync(claudePath)) unlinkSync(claudePath);
|
|
175
|
+
symlinkSync(AGENTS_MD, claudePath);
|
|
176
|
+
} catch {
|
|
177
|
+
writeFileSync(claudePath, applyVars(readTemplate("CLAUDE.md"), vars));
|
|
178
|
+
}
|
|
134
179
|
}
|
|
135
180
|
}
|
|
136
|
-
writeFileSync(targetPath, content);
|
|
137
181
|
const managedSpecs = [
|
|
138
182
|
{ target: `${SPEC_DIR}/coding-principles.md`, template: "spec/coding-principles.md" }
|
|
139
183
|
];
|
|
@@ -147,12 +191,14 @@ ${customContent}
|
|
|
147
191
|
}
|
|
148
192
|
|
|
149
193
|
// src/doctor.ts
|
|
150
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
194
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, lstatSync as lstatSync2 } from "fs";
|
|
151
195
|
import { join as join2 } from "path";
|
|
196
|
+
import { platform as platform2 } from "os";
|
|
152
197
|
function doctor(projectDir) {
|
|
153
198
|
const issues = [];
|
|
154
199
|
const required = [
|
|
155
|
-
{ file: AGENTS_MD, desc: "Root router file" },
|
|
200
|
+
{ file: AGENTS_MD, desc: "Root router file (OpenCode)" },
|
|
201
|
+
{ file: CLAUDE_MD, desc: "Root router file (Claude Code)" },
|
|
156
202
|
{ file: CUSTOM_FILE, desc: "Project specific rules" },
|
|
157
203
|
{ file: MEMORY_FILE, desc: "Long-term memory" },
|
|
158
204
|
{ file: TASKS_FILE, desc: "Working memory" },
|
|
@@ -169,22 +215,37 @@ function doctor(projectDir) {
|
|
|
169
215
|
issues.push({ level: "error", file: dir, message: "Directory missing" });
|
|
170
216
|
}
|
|
171
217
|
}
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
218
|
+
const routerFiles = [AGENTS_MD, CLAUDE_MD];
|
|
219
|
+
for (const rf of routerFiles) {
|
|
220
|
+
const rfPath = join2(projectDir, rf);
|
|
221
|
+
if (existsSync2(rfPath)) {
|
|
222
|
+
if (rf === CLAUDE_MD && platform2() !== "win32") {
|
|
223
|
+
try {
|
|
224
|
+
if (!lstatSync2(rfPath).isSymbolicLink()) {
|
|
225
|
+
issues.push({
|
|
226
|
+
level: "warning",
|
|
227
|
+
file: CLAUDE_MD,
|
|
228
|
+
message: "Plain file \u2014 should be a symlink to AGENTS.md. Run 'agent-memory update' to fix"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const content = readFileSync2(rfPath, "utf-8");
|
|
235
|
+
if (!content.includes(".agents/")) {
|
|
236
|
+
issues.push({
|
|
237
|
+
level: "warning",
|
|
238
|
+
file: rf,
|
|
239
|
+
message: "No references to .agents/ \u2014 agents may not find memory files"
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (content.split("\n").length > 150) {
|
|
243
|
+
issues.push({
|
|
244
|
+
level: "warning",
|
|
245
|
+
file: rf,
|
|
246
|
+
message: "Over 150 lines \u2014 consider keeping it concise as a router"
|
|
247
|
+
});
|
|
248
|
+
}
|
|
188
249
|
}
|
|
189
250
|
}
|
|
190
251
|
const memoryPath = join2(projectDir, MEMORY_FILE);
|
|
@@ -209,8 +270,8 @@ function printUsage() {
|
|
|
209
270
|
@vuau/agent-memory \u2014 Structured AI memory for codebases
|
|
210
271
|
|
|
211
272
|
Usage:
|
|
212
|
-
agent-memory init [options] Scaffold .agents/ structure and
|
|
213
|
-
agent-memory update Update
|
|
273
|
+
agent-memory init [options] Scaffold .agents/ structure, AGENTS.md and CLAUDE.md
|
|
274
|
+
agent-memory update Update router files to latest version
|
|
214
275
|
agent-memory doctor Validate .agents/ structure
|
|
215
276
|
agent-memory help Show this help
|
|
216
277
|
|
|
@@ -252,7 +313,7 @@ Initializing agent memory in ${cwd}...
|
|
|
252
313
|
}
|
|
253
314
|
}
|
|
254
315
|
console.log("\nNext steps:");
|
|
255
|
-
console.log(" 1. Edit AGENTS.md
|
|
316
|
+
console.log(" 1. Edit AGENTS.md (OpenCode) / CLAUDE.md (Claude Code) with project-specific rules");
|
|
256
317
|
console.log(" 2. Add spec files to .agents/spec/ for detailed documentation");
|
|
257
318
|
console.log(" 3. Agent will read rules and write to .agents/MEMORY.md automatically");
|
|
258
319
|
console.log("");
|
|
@@ -265,14 +326,14 @@ async function runUpdate() {
|
|
|
265
326
|
process.exit(1);
|
|
266
327
|
}
|
|
267
328
|
console.log(`
|
|
268
|
-
Updating ${AGENTS_MD} in ${cwd}...
|
|
329
|
+
Updating ${AGENTS_MD} / ${CLAUDE_MD} in ${cwd}...
|
|
269
330
|
`);
|
|
270
331
|
const updated = updateRouter(cwd);
|
|
271
332
|
if (updated) {
|
|
272
|
-
console.log(` \u2713 ${AGENTS_MD} updated to the latest template.`);
|
|
333
|
+
console.log(` \u2713 ${AGENTS_MD} and ${CLAUDE_MD} updated to the latest template.`);
|
|
273
334
|
console.log(` (Note: Your custom rules in .agents/CUSTOM.md were not affected)`);
|
|
274
335
|
} else {
|
|
275
|
-
console.error("\u2717 Failed to update
|
|
336
|
+
console.error("\u2717 Failed to update router files");
|
|
276
337
|
process.exit(1);
|
|
277
338
|
}
|
|
278
339
|
console.log("");
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// src/scaffold.ts
|
|
2
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, symlinkSync, lstatSync, unlinkSync } from "fs";
|
|
3
3
|
import { join, resolve, dirname } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
+
import { platform } from "os";
|
|
5
6
|
|
|
6
7
|
// src/types.ts
|
|
7
8
|
var AGENTS_DIR = ".agents";
|
|
@@ -11,6 +12,7 @@ var MEMORY_DETAIL_FILE = ".agents/MEMORY-DETAIL.md";
|
|
|
11
12
|
var TASKS_FILE = ".agents/TASKS.md";
|
|
12
13
|
var CUSTOM_FILE = ".agents/CUSTOM.md";
|
|
13
14
|
var AGENTS_MD = "AGENTS.md";
|
|
15
|
+
var CLAUDE_MD = "CLAUDE.md";
|
|
14
16
|
|
|
15
17
|
// src/scaffold.ts
|
|
16
18
|
function getTemplatesDir() {
|
|
@@ -87,6 +89,7 @@ function scaffold(projectDir, options = {}) {
|
|
|
87
89
|
result,
|
|
88
90
|
force
|
|
89
91
|
);
|
|
92
|
+
writeClaudeMd(projectDir, vars, result, force);
|
|
90
93
|
return result;
|
|
91
94
|
}
|
|
92
95
|
function writeFileIfNeeded(targetPath, content, displayName, result, force) {
|
|
@@ -108,26 +111,67 @@ function guessProjectName(dir) {
|
|
|
108
111
|
}
|
|
109
112
|
return dir.split("/").pop() || "Project";
|
|
110
113
|
}
|
|
114
|
+
var IS_WIN = platform() === "win32";
|
|
115
|
+
function writeClaudeMd(projectDir, vars, result, force) {
|
|
116
|
+
const targetPath = join(projectDir, CLAUDE_MD);
|
|
117
|
+
if (IS_WIN) {
|
|
118
|
+
writeFileIfNeeded(
|
|
119
|
+
targetPath,
|
|
120
|
+
applyVars(readTemplate("CLAUDE.md"), vars),
|
|
121
|
+
CLAUDE_MD,
|
|
122
|
+
result,
|
|
123
|
+
force
|
|
124
|
+
);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const linkTarget = AGENTS_MD;
|
|
128
|
+
if (existsSync(targetPath)) {
|
|
129
|
+
if (!force) {
|
|
130
|
+
result.skipped.push(CLAUDE_MD);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
unlinkSync(targetPath);
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
symlinkSync(linkTarget, targetPath);
|
|
137
|
+
result.created.push(`${CLAUDE_MD} \u2192 ${AGENTS_MD}`);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
writeFileSync(targetPath, applyVars(readTemplate("CLAUDE.md"), vars));
|
|
140
|
+
result.created.push(`${CLAUDE_MD} (symlink failed, wrote file)`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
111
143
|
function updateRouter(projectDir) {
|
|
112
|
-
const targetPath = join(projectDir, AGENTS_MD);
|
|
113
|
-
if (!existsSync(targetPath)) return false;
|
|
114
144
|
const projectName = guessProjectName(projectDir);
|
|
115
145
|
const vars = { PROJECT_NAME: projectName };
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
const agentsPath = join(projectDir, AGENTS_MD);
|
|
147
|
+
if (!existsSync(agentsPath)) return false;
|
|
148
|
+
writeFileSync(agentsPath, applyVars(readTemplate("AGENTS.md"), vars));
|
|
149
|
+
const claudePath = join(projectDir, CLAUDE_MD);
|
|
150
|
+
if (IS_WIN) {
|
|
151
|
+
writeFileSync(claudePath, applyVars(readTemplate("CLAUDE.md"), vars));
|
|
152
|
+
} else {
|
|
153
|
+
let needsRecreate = false;
|
|
154
|
+
if (!existsSync(claudePath)) {
|
|
155
|
+
needsRecreate = true;
|
|
156
|
+
} else {
|
|
157
|
+
try {
|
|
158
|
+
const stat = lstatSync(claudePath);
|
|
159
|
+
if (!stat.isSymbolicLink()) {
|
|
160
|
+
needsRecreate = true;
|
|
161
|
+
}
|
|
162
|
+
} catch {
|
|
163
|
+
needsRecreate = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (needsRecreate) {
|
|
167
|
+
try {
|
|
168
|
+
if (existsSync(claudePath)) unlinkSync(claudePath);
|
|
169
|
+
symlinkSync(AGENTS_MD, claudePath);
|
|
170
|
+
} catch {
|
|
171
|
+
writeFileSync(claudePath, applyVars(readTemplate("CLAUDE.md"), vars));
|
|
172
|
+
}
|
|
128
173
|
}
|
|
129
174
|
}
|
|
130
|
-
writeFileSync(targetPath, content);
|
|
131
175
|
const managedSpecs = [
|
|
132
176
|
{ target: `${SPEC_DIR}/coding-principles.md`, template: "spec/coding-principles.md" }
|
|
133
177
|
];
|
|
@@ -141,12 +185,14 @@ ${customContent}
|
|
|
141
185
|
}
|
|
142
186
|
|
|
143
187
|
// src/doctor.ts
|
|
144
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
188
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, lstatSync as lstatSync2 } from "fs";
|
|
145
189
|
import { join as join2 } from "path";
|
|
190
|
+
import { platform as platform2 } from "os";
|
|
146
191
|
function doctor(projectDir) {
|
|
147
192
|
const issues = [];
|
|
148
193
|
const required = [
|
|
149
|
-
{ file: AGENTS_MD, desc: "Root router file" },
|
|
194
|
+
{ file: AGENTS_MD, desc: "Root router file (OpenCode)" },
|
|
195
|
+
{ file: CLAUDE_MD, desc: "Root router file (Claude Code)" },
|
|
150
196
|
{ file: CUSTOM_FILE, desc: "Project specific rules" },
|
|
151
197
|
{ file: MEMORY_FILE, desc: "Long-term memory" },
|
|
152
198
|
{ file: TASKS_FILE, desc: "Working memory" },
|
|
@@ -163,22 +209,37 @@ function doctor(projectDir) {
|
|
|
163
209
|
issues.push({ level: "error", file: dir, message: "Directory missing" });
|
|
164
210
|
}
|
|
165
211
|
}
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
212
|
+
const routerFiles = [AGENTS_MD, CLAUDE_MD];
|
|
213
|
+
for (const rf of routerFiles) {
|
|
214
|
+
const rfPath = join2(projectDir, rf);
|
|
215
|
+
if (existsSync2(rfPath)) {
|
|
216
|
+
if (rf === CLAUDE_MD && platform2() !== "win32") {
|
|
217
|
+
try {
|
|
218
|
+
if (!lstatSync2(rfPath).isSymbolicLink()) {
|
|
219
|
+
issues.push({
|
|
220
|
+
level: "warning",
|
|
221
|
+
file: CLAUDE_MD,
|
|
222
|
+
message: "Plain file \u2014 should be a symlink to AGENTS.md. Run 'agent-memory update' to fix"
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const content = readFileSync2(rfPath, "utf-8");
|
|
229
|
+
if (!content.includes(".agents/")) {
|
|
230
|
+
issues.push({
|
|
231
|
+
level: "warning",
|
|
232
|
+
file: rf,
|
|
233
|
+
message: "No references to .agents/ \u2014 agents may not find memory files"
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (content.split("\n").length > 150) {
|
|
237
|
+
issues.push({
|
|
238
|
+
level: "warning",
|
|
239
|
+
file: rf,
|
|
240
|
+
message: "Over 150 lines \u2014 consider keeping it concise as a router"
|
|
241
|
+
});
|
|
242
|
+
}
|
|
182
243
|
}
|
|
183
244
|
}
|
|
184
245
|
const memoryPath = join2(projectDir, MEMORY_FILE);
|
|
@@ -197,6 +258,7 @@ function doctor(projectDir) {
|
|
|
197
258
|
export {
|
|
198
259
|
AGENTS_DIR,
|
|
199
260
|
AGENTS_MD,
|
|
261
|
+
CLAUDE_MD,
|
|
200
262
|
CUSTOM_FILE,
|
|
201
263
|
MEMORY_DETAIL_FILE,
|
|
202
264
|
MEMORY_FILE,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vuau/agent-memory",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Structured AI memory for codebases — scaffolding CLI for OpenCode, Copilot, Cursor, Windsurf",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Structured AI memory for codebases — scaffolding CLI for OpenCode, Copilot, Cursor, Windsurf, Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"exports": {
|
package/templates/AGENTS.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# {{PROJECT_NAME}} - AGENTS
|
|
2
2
|
|
|
3
|
-
Router file for AI
|
|
3
|
+
Router file for AI coding assistants: OpenCode, GitHub Copilot, Cursor, Windsurf, and others.
|
|
4
4
|
|
|
5
5
|
> **Note**: This file is automatically managed by `@vuau/agent-memory`.
|
|
6
6
|
> Do not add project-specific rules here, as they may be overwritten by `agent-memory update`.
|
|
7
7
|
>
|
|
8
8
|
> 👉 **For project-specific rules, context, and document mapping, see `.agents/CUSTOM.md`**
|
|
9
|
+
>
|
|
10
|
+
> 💡 **Claude Code users**: Install `@vuau/agent-memory` and run `init` to auto-generate `CLAUDE.md` —
|
|
11
|
+
> a companion file that references this `AGENTS.md` so you get the same rules.
|
|
9
12
|
|
|
10
13
|
## Priority
|
|
11
14
|
1. User request first.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# {{PROJECT_NAME}} - CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Router file for Claude Code.
|
|
4
|
+
|
|
5
|
+
> **Note**: This file is auto-generated by `@vuau/agent-memory`.
|
|
6
|
+
> Do not edit directly.
|
|
7
|
+
>
|
|
8
|
+
> 👉 **All project rules live in `AGENTS.md`** — you MUST read that file for context and instructions.
|
|
9
|
+
|
|
10
|
+
## Rules
|
|
11
|
+
|
|
12
|
+
All project rules, memory protocol, and response style are defined in **[AGENTS.md](./AGENTS.md)**.
|
|
13
|
+
|
|
14
|
+
Read `AGENTS.md` before making any changes.
|