@vuau/agent-memory 0.4.1 → 0.5.1
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 +26 -86
- package/README.vi.md +31 -89
- package/dist/bin/cli.js +48 -5
- package/dist/index.js +29 -122
- package/package.json +3 -2
- package/templates/AGENTS.md +12 -15
- package/templates/CUSTOM.md +13 -0
- package/templates/MEMORY-DETAIL.md +0 -3
- package/templates/MEMORY.md +0 -3
- package/templates/TASKS.md +1 -4
package/README.md
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
# @vuau/agent-memory
|
|
2
2
|
|
|
3
|
-
Structured AI memory for codebases.
|
|
3
|
+
Structured AI memory for codebases. Works with 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
|
|
|
7
7
|
## Problem
|
|
8
8
|
|
|
9
|
-
AI coding assistants lose context between sessions. They can't remember
|
|
10
|
-
- Architecture decisions you made last week
|
|
11
|
-
- Code patterns specific to your project
|
|
12
|
-
- What task you were working on yesterday
|
|
13
|
-
|
|
14
|
-
**agent-memory** solves this with a simple file-based memory system that any AI can read.
|
|
9
|
+
AI coding assistants lose context between sessions. They can't remember architecture decisions, specific code patterns, or current tasks. **agent-memory** solves this with a simple file-based memory system that any AI can read and update.
|
|
15
10
|
|
|
16
11
|
## Quick Start
|
|
17
12
|
|
|
@@ -23,8 +18,9 @@ npx @vuau/agent-memory init
|
|
|
23
18
|
|
|
24
19
|
```
|
|
25
20
|
/ (Project Root)
|
|
26
|
-
├── AGENTS.md #
|
|
21
|
+
├── AGENTS.md # Fixed router (managed by package)
|
|
27
22
|
└── .agents/
|
|
23
|
+
├── CUSTOM.md # Project-specific rules & spec mapping
|
|
28
24
|
├── MEMORY.md # Long-term memory (decisions, patterns)
|
|
29
25
|
├── TASKS.md # Working memory (current tasks)
|
|
30
26
|
└── spec/ # Detailed specs (on-demand)
|
|
@@ -32,96 +28,40 @@ npx @vuau/agent-memory init
|
|
|
32
28
|
|
|
33
29
|
## How It Works
|
|
34
30
|
|
|
35
|
-
1. **You run `init`** → Creates `AGENTS.md`
|
|
36
|
-
2. **Agent reads rules** →
|
|
37
|
-
3. **Agent works** →
|
|
38
|
-
4. **
|
|
39
|
-
5. **Next session** → Agent reads memory, continues where you left off
|
|
40
|
-
|
|
41
|
-
**No plugin required.** The rules in `AGENTS.md` instruct the agent what to do.
|
|
31
|
+
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
|
+
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 `AGENTS.md` router without losing your custom rules.
|
|
42
35
|
|
|
43
|
-
## CLI
|
|
36
|
+
## CLI Commands
|
|
44
37
|
|
|
45
38
|
```bash
|
|
46
|
-
npx @vuau/agent-memory init
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
--name <n> Project name (default: from package.json)
|
|
51
|
-
|
|
52
|
-
npx @vuau/agent-memory doctor # Validate structure
|
|
53
|
-
npx @vuau/agent-memory help # Show help
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Memory Protocol
|
|
57
|
-
|
|
58
|
-
Agents follow this protocol (defined in config files):
|
|
59
|
-
|
|
60
|
-
```markdown
|
|
61
|
-
## When to write
|
|
62
|
-
- User approves a decision → append to .agents/MEMORY.md
|
|
63
|
-
- Explore codebase/architecture → update .agents/spec/*.md
|
|
64
|
-
- Start/finish a large task → update .agents/TASKS.md
|
|
65
|
-
|
|
66
|
-
## Entry format
|
|
67
|
-
- YYYY-MM-DD: <1-line decision or pattern>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### MEMORY.md Example
|
|
71
|
-
|
|
72
|
-
```markdown
|
|
73
|
-
## Patterns
|
|
74
|
-
- 2026-04-24: State files = 3 layers (interfaces → defaults → variants)
|
|
75
|
-
- 2026-04-24: Dumb components: initialState prop + optional callbacks
|
|
76
|
-
|
|
77
|
-
## Decisions
|
|
78
|
-
- 2026-04-06: Use useMediaQuery over CSS display:none for heavy components
|
|
39
|
+
npx @vuau/agent-memory init # Scaffold .agents/ structure
|
|
40
|
+
npx @vuau/agent-memory update # Update AGENTS.md router to latest version
|
|
41
|
+
npx @vuau/agent-memory doctor # Validate structure integrity
|
|
42
|
+
npx @vuau/agent-memory help # Show help
|
|
79
43
|
```
|
|
80
44
|
|
|
81
45
|
## Architecture
|
|
82
46
|
|
|
83
|
-
###
|
|
84
|
-
|
|
85
|
-
| Layer | File | Purpose |
|
|
86
|
-
|-------|------|---------|
|
|
87
|
-
| Router | AGENTS.md | Rules + pointers (~100 lines) |
|
|
88
|
-
| Memory | .agents/MEMORY.md | Curated decisions (1-line each) |
|
|
89
|
-
| Tasks | .agents/TASKS.md | Current work, next steps |
|
|
90
|
-
| Specs | .agents/spec/*.md | Detailed docs (on-demand) |
|
|
91
|
-
|
|
92
|
-
### Why File-Based?
|
|
93
|
-
|
|
94
|
-
We tested memsearch, qmd, mem0, memories.sh — all failed for various reasons (see [RESEARCH.md](./docs/RESEARCH.md)):
|
|
95
|
-
|
|
96
|
-
- **Context Blindness**: Auto-capture can't link user intent to prior analysis
|
|
97
|
-
- **Context Bloat**: Fallback to transcripts costs 47k+ tokens
|
|
98
|
-
- **Platform issues**: Dependencies don't work on Windows/VM
|
|
99
|
-
|
|
100
|
-
File-based solution:
|
|
101
|
-
- Agent writes when they understand context (quality > automation)
|
|
102
|
-
- Plain markdown (portable, git-versionable, human-readable)
|
|
103
|
-
- No dependencies (works everywhere)
|
|
47
|
+
### The Router Split
|
|
104
48
|
|
|
105
|
-
|
|
49
|
+
- **AGENTS.md**: Core router managed by the package. Do not edit this file directly as it may be overwritten.
|
|
50
|
+
- **.agents/CUSTOM.md**: Your project's home for custom rules, architectural decisions, and documentation mapping.
|
|
106
51
|
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
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
|
-
```
|
|
52
|
+
### Memory Files
|
|
118
53
|
|
|
119
|
-
|
|
54
|
+
| File | Purpose |
|
|
55
|
+
|------|---------|
|
|
56
|
+
| .agents/MEMORY.md | Curated decisions (1-line each) |
|
|
57
|
+
| .agents/TASKS.md | Current work, next steps |
|
|
58
|
+
| .agents/spec/*.md | Detailed technical documentation |
|
|
120
59
|
|
|
121
|
-
##
|
|
60
|
+
## Why File-Based?
|
|
122
61
|
|
|
123
|
-
- **
|
|
124
|
-
- **
|
|
62
|
+
- **Context Precision**: AI writes when they understand context (quality > automation).
|
|
63
|
+
- **Portable**: Plain markdown is portable, git-versionable, and human-readable.
|
|
64
|
+
- **Minimalist**: No dependencies, no background processes, no API keys.
|
|
125
65
|
|
|
126
66
|
## License
|
|
127
67
|
|
package/README.vi.md
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
# @vuau/agent-memory
|
|
2
2
|
|
|
3
|
-
Bộ nhớ AI có cấu trúc cho các codebase.
|
|
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.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**[English →](./README.md)**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Các quyết định kiến trúc bạn đã đưa ra tuần trước
|
|
9
|
-
- Các mẫu thiết kế cụ thể của dự án
|
|
10
|
-
- Task bạn đang làm hôm qua
|
|
7
|
+
## Bài toán
|
|
11
8
|
|
|
12
|
-
**agent-memory** giải quyết bằng hệ thống bộ nhớ đơn giản dựa trên file mà bất kỳ AI nào cũng có thể đọc.
|
|
9
|
+
AI coding assistants mất bối cảnh giữa các phiên làm việc. Họ không thể nhớ các quyết định kiến trúc, các mẫu thiết kế cụ thể, hoặc các task đang làm dở. **agent-memory** giải quyết vấn đề này bằng một hệ thống bộ nhớ đơn giản dựa trên file mà bất kỳ AI nào cũng có thể đọc và cập nhật.
|
|
13
10
|
|
|
14
11
|
## Bắt đầu nhanh
|
|
15
12
|
|
|
@@ -21,105 +18,50 @@ npx @vuau/agent-memory init
|
|
|
21
18
|
|
|
22
19
|
```
|
|
23
20
|
/ (Project Root)
|
|
24
|
-
├── AGENTS.md #
|
|
21
|
+
├── AGENTS.md # Router cố định (quản lý bởi package)
|
|
25
22
|
└── .agents/
|
|
26
|
-
├──
|
|
27
|
-
├──
|
|
28
|
-
|
|
23
|
+
├── CUSTOM.md # Rules riêng của project & mapping tài liệu
|
|
24
|
+
├── MEMORY.md # Bộ nhớ dài hạn (quyết định, patterns)
|
|
25
|
+
├── TASKS.md # Bộ nhớ làm việc (tasks hiện tại)
|
|
26
|
+
└── spec/ # Tài liệu kỹ thuật chi tiết (on-demand)
|
|
29
27
|
```
|
|
30
28
|
|
|
31
29
|
## Cách hoạt động
|
|
32
30
|
|
|
33
|
-
1. **Bạn chạy `init`** → Tạo `AGENTS.md`
|
|
34
|
-
2. **Agent đọc rules** →
|
|
35
|
-
3. **Agent làm việc** →
|
|
36
|
-
4. **
|
|
37
|
-
5. **Phiên tiếp theo** → Agent đọc memory, tiếp tục từ nơi dừng lại
|
|
38
|
-
|
|
39
|
-
**Không cần plugin.** Rules trong `AGENTS.md` hướng dẫn agent phải làm gì.
|
|
31
|
+
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
|
+
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 `AGENTS.md` mới nhất mà không mất các rules tùy chỉnh của bạn.
|
|
40
35
|
|
|
41
|
-
## CLI
|
|
36
|
+
## Các lệnh CLI
|
|
42
37
|
|
|
43
38
|
```bash
|
|
44
|
-
npx @vuau/agent-memory init
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
--name <n> Tên project (mặc định: từ package.json)
|
|
49
|
-
|
|
50
|
-
npx @vuau/agent-memory doctor # Validate structure
|
|
51
|
-
npx @vuau/agent-memory help # Hiện help
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Memory Protocol
|
|
55
|
-
|
|
56
|
-
Agents follow protocol này (defined trong config files):
|
|
57
|
-
|
|
58
|
-
```markdown
|
|
59
|
-
## Khi nào ghi
|
|
60
|
-
- User approves decision → append vào .agents/MEMORY.md
|
|
61
|
-
- Explore codebase/architecture → update .agents/spec/*.md
|
|
62
|
-
- Start/finish large task → update .agents/TASKS.md
|
|
63
|
-
|
|
64
|
-
## Entry format
|
|
65
|
-
- YYYY-MM-DD: <1-line decision hoặc pattern>
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### MEMORY.md Ví dụ
|
|
69
|
-
|
|
70
|
-
```markdown
|
|
71
|
-
## Patterns
|
|
72
|
-
- 2026-04-24: State files = 3 layers (interfaces → defaults → variants)
|
|
73
|
-
- 2026-04-24: Dumb components: initialState prop + optional callbacks
|
|
74
|
-
|
|
75
|
-
## Decisions
|
|
76
|
-
- 2026-04-06: Use useMediaQuery over CSS display:none cho heavy components
|
|
39
|
+
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 doctor # Kiểm tra tính toàn vẹn của cấu trúc
|
|
42
|
+
npx @vuau/agent-memory help # Hiện trợ giúp
|
|
77
43
|
```
|
|
78
44
|
|
|
79
45
|
## Kiến trúc
|
|
80
46
|
|
|
81
|
-
###
|
|
82
|
-
|
|
83
|
-
| Layer | File | Mục đích |
|
|
84
|
-
|-------|------|----------|
|
|
85
|
-
| Router | AGENTS.md | Rules + pointers (~100 dòng) |
|
|
86
|
-
| Memory | .agents/MEMORY.md | Curated decisions (1-line each) |
|
|
87
|
-
| Tasks | .agents/TASKS.md | Current work, next steps |
|
|
88
|
-
| Specs | .agents/spec/*.md | Detailed docs (on-demand) |
|
|
89
|
-
|
|
90
|
-
### Tại sao File-Based?
|
|
91
|
-
|
|
92
|
-
Chúng tôi đã test memsearch, qmd, mem0, memories.sh — tất cả failed vì nhiều lý do (xem [RESEARCH.md](./docs/RESEARCH.md)):
|
|
93
|
-
|
|
94
|
-
- **Context Blindness**: Auto-capture không thể link user intent với prior analysis
|
|
95
|
-
- **Context Bloat**: Fallback sang transcripts tốn 47k+ tokens
|
|
96
|
-
- **Platform issues**: Dependencies không work trên Windows/VM
|
|
47
|
+
### Phân tách Router
|
|
97
48
|
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
- Plain markdown (portable, git-versionable, human-readable)
|
|
101
|
-
- Không dependencies (works everywhere)
|
|
49
|
+
- **AGENTS.md**: Router cốt lõi được quản lý bởi thư viện. Không sửa file này trực tiếp vì nó có thể bị ghi đè khi update.
|
|
50
|
+
- **.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.
|
|
102
51
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
Mặc định, công cụ chỉ scaffold `AGENTS.md`, một chuẩn router file đang phổ biến.
|
|
106
|
-
|
|
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 có thể đơn giản dùng symlink hoặc copy `AGENTS.md`:
|
|
108
|
-
|
|
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
|
-
```
|
|
52
|
+
### Các file bộ nhớ
|
|
116
53
|
|
|
117
|
-
|
|
54
|
+
| File | Mục đích |
|
|
55
|
+
|------|----------|
|
|
56
|
+
| .agents/MEMORY.md | Các quyết định quan trọng (mỗi dòng 1 quyết định) |
|
|
57
|
+
| .agents/TASKS.md | Công việc hiện tại và các bước tiếp theo |
|
|
58
|
+
| .agents/spec/*.md | Tài liệu kỹ thuật chi tiết |
|
|
118
59
|
|
|
119
|
-
##
|
|
60
|
+
## Tại sao dùng File-Based?
|
|
120
61
|
|
|
121
|
-
- **
|
|
122
|
-
- **
|
|
62
|
+
- **Chính xác**: AI chỉ ghi dữ liệu khi đã hiểu rõ bối cảnh (chất lượng > tự động hóa).
|
|
63
|
+
- **Linh hoạt**: Markdown đơn thuần, dễ di chuyển, có thể quản lý bằng Git và con người có thể đọc được.
|
|
64
|
+
- **Tối giản**: Không phụ thuộc bên ngoài, không chạy ngầm, không cần API keys.
|
|
123
65
|
|
|
124
66
|
## License
|
|
125
67
|
|
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.1",
|
|
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
|
},
|
|
@@ -41,4 +42,4 @@
|
|
|
41
42
|
"type": "git",
|
|
42
43
|
"url": "git+https://github.com/vuau/agent-memory.git"
|
|
43
44
|
}
|
|
44
|
-
}
|
|
45
|
+
}
|
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
|
|
|
@@ -40,6 +36,7 @@ Before ending a session with unfinished work, move items to `## In Progress` or
|
|
|
40
36
|
- Do not create additional memory files outside `.agents/`.
|
|
41
37
|
|
|
42
38
|
## Response Style
|
|
43
|
-
-
|
|
39
|
+
- Concrete, implementation-focused, caveman style (minimum words, zero fluff).
|
|
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,13 @@
|
|
|
1
|
+
# Project Rules & Document Map
|
|
2
|
+
|
|
3
|
+
## Documentation Map
|
|
4
|
+
|
|
5
|
+
| Area / Feature | Spec File |
|
|
6
|
+
|----------------|-----------|
|
|
7
|
+
| Example: Database Schema | `.agents/spec/database.md` |
|
|
8
|
+
|
|
9
|
+
> Add your own spec files to `.agents/spec/` and reference them here.
|
|
10
|
+
|
|
11
|
+
## Custom Rules
|
|
12
|
+
|
|
13
|
+
- Add your project-specific rules here.
|
package/templates/MEMORY.md
CHANGED