@mrtrinhvn/ag-kit 1.3.2 → 1.4.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 +32 -46
- package/bin/cli.js +69 -198
- package/package.json +1 -1
- package/template/.agent/knowledge/USER.md +4 -0
- package/template/.agent/knowledge/ag-kit-ecosystem.md +168 -0
- package/template/.agent/knowledge/ag-kit-elite.md +6 -3
- package/template/.agent/knowledge/context_isolation.md +16 -0
- package/template/.agent/scripts/_post-commit-hook +8 -0
- package/template/.agent/scripts/brain_builder.py +287 -0
- package/template/.agent/scripts/memory_mcp_server.py +423 -0
- package/template/.agent/scripts/memory_tool.py +367 -0
- package/template/.agent/scripts/receptionist_down.sh +5 -5
- package/template/.agent/scripts/receptionist_up.sh +13 -10
- package/template/.agent/scripts/refresh_brain.sh +21 -0
- package/template/.agent/scripts/repomap.py +32 -3
- package/template/.agent/skills/ag-kit-core/SKILL.md +88 -2
- package/template/.agent/skills/intelligent-routing/SKILL.md +20 -10
- package/template/.agent/skills/telegram-agentic-gateway/SKILL.md +3 -0
- package/template/.agent/skills/telegram-agentic-gateway/templates/start.sh.template +2 -2
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# 🌌 AG-KIT ECOSYSTEM — Định Danh & Bản Đồ Hệ Sinh Thái
|
|
2
|
+
|
|
3
|
+
> **Đây là tài liệu cốt lõi bắt buộc phải đọc khi khởi động bất kỳ project nào thuộc hệ sinh thái ag-kit.**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. AG-KIT LÀ GÌ?
|
|
8
|
+
|
|
9
|
+
**ag-kit (Antigravity Kit)** là một framework tư nhân — bộ tiêu chuẩn vận hành AI Agents — được thiết kế và sở hữu bởi **một cá nhân duy nhất (Owner)**.
|
|
10
|
+
|
|
11
|
+
Nó **KHÔNG phải** một open-source framework cho cộng đồng. Nó là **"bộ não chỉ huy"** giúp Owner vận hành và tự động hóa toàn bộ hệ thống AI của mình trên nhiều dự án.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
ag-kit = Tiêu chuẩn + Công cụ + Bộ nhớ + Quy tắc
|
|
15
|
+
cho mọi AI Agent trong hệ sinh thái của Owner
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. CẤU TRÚC HỆ SINH THÁI
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
/home/tao/Projects/ ← Workspace của Owner
|
|
24
|
+
│
|
|
25
|
+
├── ag-kit/ ← 🌱 TEMPLATE GỐC (đây)
|
|
26
|
+
│ └── template/.agent/ ← Bản mẫu chuẩn cho mọi project mới
|
|
27
|
+
│
|
|
28
|
+
├── ceogravity/ ← 🤖 Orchestrator chính
|
|
29
|
+
│ └── .agent/ ← Clone từ ag-kit, đã tùy chỉnh
|
|
30
|
+
│
|
|
31
|
+
├── chungkhoan/ ← 📈 Trading Engine
|
|
32
|
+
│ └── .agent/
|
|
33
|
+
│
|
|
34
|
+
├── <project-N>/ ← Mọi dự án tương lai
|
|
35
|
+
│ └── .agent/ ← Đều dùng chung chuẩn ag-kit
|
|
36
|
+
│
|
|
37
|
+
└── ~/.config/ag-kit/
|
|
38
|
+
└── projects.json ← 📋 Registry toàn bộ projects
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Nguyên tắc:** Mọi project đều dùng chung **cùng một bộ não** (skills, protocols), nhưng có **dữ liệu riêng biệt** (memory, brain, soul).
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 3. BỘ NHỚ 3 TẦNG (Universal Memory Stack)
|
|
46
|
+
|
|
47
|
+
Mỗi project trong hệ sinh thái có bộ nhớ theo chuẩn ag-kit:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
TẦNG 3 — KNOWLEDGE BASE (.agent/knowledge/*.md)
|
|
51
|
+
Sự thật vĩnh cửu — Git-tracked — AI đọc tự động khi khởi động
|
|
52
|
+
Nội dung: kiến trúc, quy tắc, patterns đã phê duyệt
|
|
53
|
+
|
|
54
|
+
TẦNG 2 — WORKING MEMORY GRAPH (.agent/memory/graph.db)
|
|
55
|
+
Hot nodes (tức thì) → Cold nodes (tổng hợp định kỳ)
|
|
56
|
+
AI truy cập qua: MCP tools (memory_save, memory_search...)
|
|
57
|
+
.gitignore — Local only — Auto GC
|
|
58
|
+
|
|
59
|
+
TẦNG 1 — CODEBASE INDEX (.agent/cache/repomap.json)
|
|
60
|
+
Sơ đồ function/class — Auto-rebuild khi code đổi
|
|
61
|
+
.gitignore — Local only
|
|
62
|
+
|
|
63
|
+
AUTO-BRAIN (.agent/brain/summary.md)
|
|
64
|
+
Tổng hợp từ cả 3 tầng — Auto-rebuild sau git commit
|
|
65
|
+
.gitignore — Local only
|
|
66
|
+
|
|
67
|
+
### Chiến lược "Dual-Model Coordination" (Zero-API-Cost Memory)
|
|
68
|
+
Thay vì dùng LLM khổng lồ (Gemini/Claude) để nhúng Vector, hệ sinh thái `ag-kit` phân cực rõ ràng:
|
|
69
|
+
1. **Ollama Local (nomic-embed-text)**: Tự động chạy ngầm ở dưới để chuyển đổi Text → Toán học (Embedding Vector). Tốc độ mili-giây, tốn 0 đồng API, không kết nối internet.
|
|
70
|
+
2. **LLM Cloud (Gemini/Claude)**: Khai thác kết quả của Vector Search (Semantic) để suy luận và code.
|
|
71
|
+
→ Đây là cốt lõi để làm bộ não "giá rẻ nhưng thông thái".
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 4. CÔNG CỤ CHUẨN (Standard Toolset)
|
|
77
|
+
|
|
78
|
+
Mọi project có sẵn trong `.agent/scripts/`:
|
|
79
|
+
|
|
80
|
+
| Script | Chức năng | Trigger |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `memory_mcp_server.py` | MCP Server: AI gọi memory tools trực tiếp | Antigravity load khi khởi động |
|
|
83
|
+
| `memory_tool.py` | CLI: `save/search/hot/cold/consolidate/gc` | Thủ công hoặc từ scripts |
|
|
84
|
+
| `brain_builder.py` | Tổng hợp 3 tầng → `summary.md` | Auto: git post-commit + session start |
|
|
85
|
+
| `refresh_brain.sh` | Rebuild Tầng 1 (repomap) | Thủ công khi cần |
|
|
86
|
+
| `repomap.py` | Scanner code structure → JSON | Được gọi bởi refresh_brain.sh |
|
|
87
|
+
| `backup_brain.sh` | Backup `brain_v1.json` 7 ngày | Chạy định kỳ |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 5. MCP MEMORY SERVER
|
|
92
|
+
|
|
93
|
+
Mỗi project đăng ký `ag-kit-memory` MCP server vào `~/.gemini/antigravity/mcp_config.json`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"ag-kit-memory": {
|
|
99
|
+
"command": "/usr/bin/python3",
|
|
100
|
+
"args": [
|
|
101
|
+
"<PROJECT_ROOT>/.agent/scripts/memory_mcp_server.py",
|
|
102
|
+
"--db", "<PROJECT_ROOT>/.agent/memory/graph.db"
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**8 tools AI có thể gọi native:**
|
|
110
|
+
- `memory_save` — Ghi hot node ngay lập tức
|
|
111
|
+
- `memory_search` — Tìm kiếm theo keyword (hot + cold)
|
|
112
|
+
- `memory_link` — Tạo edge (quan hệ) giữa 2 nodes
|
|
113
|
+
- `memory_graph` — Xem graph quanh 1 node
|
|
114
|
+
- `memory_hot` — Liệt kê hot (working memory)
|
|
115
|
+
- `memory_cold` — Liệt kê cold (long-term summaries)
|
|
116
|
+
- `memory_consolidate` — Gộp hot → cold (định kỳ hàng tuần)
|
|
117
|
+
- `memory_status` — Thống kê DB
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 6. QUY TRÌNH CROSS-PROJECT (Xem Bộ Não Dự Án Khác)
|
|
122
|
+
|
|
123
|
+
Khi đang làm việc ở Project A và cần hiểu Project B:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
1. Đọc registry: ~/.config/ag-kit/projects.json → tìm brain_path của B
|
|
127
|
+
2. Đọc brain: <B>/.agent/brain/summary.md → hiểu B trong 500 tokens
|
|
128
|
+
3. Nếu cần sâu: Gọi memory_search tại DB của B → semantic context
|
|
129
|
+
4. KHÔNG được: Scan toàn bộ folder B khi chưa đọc summary.md
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 7. LUẬT BẤT BIẾN CỦA HỆ SINH THÁI
|
|
135
|
+
|
|
136
|
+
1. **Không bao giờ ghi dữ liệu nghiệp vụ của Project vào ag-kit core template.**
|
|
137
|
+
2. **Mỗi project có một bộ não (graph.db) riêng — không chia sẻ DB giữa projects.**
|
|
138
|
+
3. **Mọi pattern học được từ project này → phải tổng quát hóa trước khi đưa vào template.**
|
|
139
|
+
4. **`brain_v1.json` và dữ liệu sống KHÔNG bao giờ được push lên Git.**
|
|
140
|
+
5. **Memory MCP server phải được đăng ký cho từng project, trỏ đúng DB path.**
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 8. KHỞI ĐỘNG PROJECT MỚI (Bootstrap Protocol)
|
|
145
|
+
|
|
146
|
+
Khi anh muốn thêm một project mới vào hệ sinh thái:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# 1. Copy template
|
|
150
|
+
cp -r /home/tao/Projects/ag-kit/template/.agent <new-project>/
|
|
151
|
+
|
|
152
|
+
# 2. Đăng ký MCP memory server (thay PROJECT_ROOT)
|
|
153
|
+
# Sửa ~/.gemini/antigravity/mcp_config.json
|
|
154
|
+
|
|
155
|
+
# 3. Chạy brain builder lần đầu
|
|
156
|
+
cd <new-project>
|
|
157
|
+
python3 .agent/scripts/brain_builder.py --update
|
|
158
|
+
|
|
159
|
+
# 4. Cài git hook
|
|
160
|
+
cp .agent/scripts/_post-commit-hook .git/hooks/post-commit
|
|
161
|
+
chmod +x .git/hooks/post-commit
|
|
162
|
+
|
|
163
|
+
# → Project sẵn sàng, có não, có memory, tự động cập nhật
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
*Hệ sinh thái này là tài sản riêng của Owner. Mọi Agent hoạt động trong đây đều phải tôn trọng nguyên tắc biệt lập, không ô nhiễm chéo, và tự cập nhật tri thức liên tục.*
|
|
@@ -14,9 +14,12 @@ This document defines the advanced agentic standards for Antigravity, synthesize
|
|
|
14
14
|
- **CodeAct Paradigm**: Use `codeact-executor` to write and run scripts in `/tmp` to resolve complex diagnostics before applying fixes.
|
|
15
15
|
- **TDD Loop**: Always run tests and fix autonomously using the 8-stage refinement loop.
|
|
16
16
|
|
|
17
|
-
## 4.
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
17
|
+
## 4. Context Containment & Pattern Extraction
|
|
18
|
+
- **Smart Learning**: Bạn được phép học giải pháp từ các dự án khác trong `/home/tao/Projects/` nhưng PHẢI đảm bảo tính tổng quát hóa.
|
|
19
|
+
- **Protocol 3-Bước**: **Quan sát (Bản gốc) -> Lọc bỏ từ khóa riêng (Sanitize) -> Nhân bản chuẩn (Model Pattern)**.
|
|
20
|
+
- **Phân tách Linh hồn & Thể xác**:
|
|
21
|
+
- **Linh hồn (Soul - Local Only):** Các winrate, tên hàm nghiệp vụ lẻ, rulesets riêng biệt.
|
|
22
|
+
- **Kiến trúc (Architecture - Shared):** Các patterns hạ tầng ( Watchdog, Logger, API wrapper). PHẢI ĐƯỢC TỔNG QUÁT HÓA khi đưa vào Template.
|
|
20
23
|
|
|
21
24
|
---
|
|
22
25
|
> *Antigravity Elite: Synthesized Intelligence for High-Precision Development.*
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# 🛡️ Smart Learning & Pattern Extraction
|
|
2
|
+
|
|
3
|
+
As an AI Agent operating within the `ag-kit` framework, you are encouraged to use the entire workspace (`/home/tao/Projects/`) as a **Library of Patterns**, but your current repository remains your **Primary Context**.
|
|
4
|
+
|
|
5
|
+
## 1. The Multi-Project Library
|
|
6
|
+
- **Permission to Observe**: You ARE allowed to look at neighbor projects to research how similar features were implemented.
|
|
7
|
+
- **Extraction over Copying**: Do not blindly copy-paste code containing project-specific terminology (B1/B2, DNSE, etc.). Instead, extract the **Universal Pattern**.
|
|
8
|
+
- **Ask First**: If you find a major architectural solution in project X that you want to bring into project Y, ask the operator: *"I found a relevant pattern in project X, may I generalize and apply it here?"*
|
|
9
|
+
|
|
10
|
+
## 2. Generalization & Sanitization
|
|
11
|
+
- **Strip Context**: Remove all business-specific names, IDs, and logic weights.
|
|
12
|
+
- **Standardize**: Convert the logic into a parameterized, reusable structure.
|
|
13
|
+
- **Protect the Soul**: Keep project-unique data (`brain_v1.json`, specific winrates) strictly within their respective folders.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
*Identity: I am an Antigravity Agent. I learn from the whole ecosystem but I protect the integrity of the local repo.*
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# post-commit hook — Auto-rebuild project brain silently after every commit
|
|
3
|
+
# Install: cp .agent/scripts/_post-commit-hook .git/hooks/post-commit && chmod +x .git/hooks/post-commit
|
|
4
|
+
SCRIPT="$(git rev-parse --show-toplevel)/.agent/scripts/brain_builder.py"
|
|
5
|
+
if [ -f "$SCRIPT" ]; then
|
|
6
|
+
python3 "$SCRIPT" --quick > /dev/null 2>&1 &
|
|
7
|
+
fi
|
|
8
|
+
exit 0
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
brain_builder.py — Auto-Brain Generator (Ag-Kit Standard)
|
|
4
|
+
|
|
5
|
+
Synthesizes a project's brain by reading:
|
|
6
|
+
- Tầng 1: .agent/cache/repomap.json (codebase structure)
|
|
7
|
+
- Tầng 2: .agent/memory/graph.db (working memory, top decisions)
|
|
8
|
+
- Tầng 3: .agent/knowledge/*.md (architecture rules)
|
|
9
|
+
- Project metadata: package.json / .env
|
|
10
|
+
|
|
11
|
+
Output:
|
|
12
|
+
- .agent/brain/summary.md (human+AI readable — primary brain file)
|
|
13
|
+
- .agent/brain/index.json (machine-readable metadata for global registry)
|
|
14
|
+
- ~/.config/ag-kit/projects.json (global registry for cross-project discovery)
|
|
15
|
+
|
|
16
|
+
Auto-triggered by:
|
|
17
|
+
- git post-commit hook
|
|
18
|
+
- receptionist_up.sh (on session start)
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
python3 .agent/scripts/brain_builder.py [--root PROJECT_DIR] [--quick] [--update]
|
|
22
|
+
--quick: only rebuild if source files changed since last brain update
|
|
23
|
+
--update: force rebuild
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import argparse
|
|
27
|
+
import json
|
|
28
|
+
import os
|
|
29
|
+
import re
|
|
30
|
+
import sqlite3
|
|
31
|
+
from datetime import datetime
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
GLOBAL_REGISTRY = Path.home() / ".config" / "ag-kit" / "projects.json"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
def read_file_safe(path: Path, max_chars=8000) -> str:
|
|
40
|
+
try:
|
|
41
|
+
text = path.read_text(encoding="utf-8")
|
|
42
|
+
if len(text) > max_chars:
|
|
43
|
+
text = text[:max_chars] + f"\n\n...[truncated at {max_chars} chars]"
|
|
44
|
+
return text
|
|
45
|
+
except Exception:
|
|
46
|
+
return ""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def read_json_safe(path: Path) -> dict:
|
|
50
|
+
try:
|
|
51
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
52
|
+
except Exception:
|
|
53
|
+
return {}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_project_name(root: Path) -> str:
|
|
57
|
+
pkg = read_json_safe(root / "package.json")
|
|
58
|
+
if pkg.get("name"):
|
|
59
|
+
return pkg["name"]
|
|
60
|
+
return root.name
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_tech_stack(root: Path) -> list[str]:
|
|
64
|
+
stack = []
|
|
65
|
+
if (root / "package.json").exists():
|
|
66
|
+
pkg = read_json_safe(root / "package.json")
|
|
67
|
+
deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
|
|
68
|
+
if "typescript" in deps:
|
|
69
|
+
stack.append("TypeScript")
|
|
70
|
+
if "next" in deps:
|
|
71
|
+
stack.append("Next.js")
|
|
72
|
+
if "react" in deps:
|
|
73
|
+
stack.append("React")
|
|
74
|
+
if "express" in deps:
|
|
75
|
+
stack.append("Express")
|
|
76
|
+
if "fastify" in deps:
|
|
77
|
+
stack.append("Fastify")
|
|
78
|
+
if not stack:
|
|
79
|
+
stack.append("Node.js")
|
|
80
|
+
if (root / "requirements.txt").exists() or (root / "pyproject.toml").exists():
|
|
81
|
+
stack.append("Python")
|
|
82
|
+
if (root / "Cargo.toml").exists():
|
|
83
|
+
stack.append("Rust")
|
|
84
|
+
if (root / "go.mod").exists():
|
|
85
|
+
stack.append("Go")
|
|
86
|
+
return stack or ["Unknown"]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_memory_nodes(root: Path, limit=8) -> list[str]:
|
|
90
|
+
db_path = root / ".agent" / "memory" / "graph.db"
|
|
91
|
+
if not db_path.exists():
|
|
92
|
+
return []
|
|
93
|
+
try:
|
|
94
|
+
conn = sqlite3.connect(str(db_path))
|
|
95
|
+
rows = conn.execute(
|
|
96
|
+
"SELECT content, category FROM nodes ORDER BY energy DESC, updated_at DESC LIMIT ?",
|
|
97
|
+
(limit,)
|
|
98
|
+
).fetchall()
|
|
99
|
+
conn.close()
|
|
100
|
+
return [f"[{r[1]}] {r[0][:120]}" for r in rows]
|
|
101
|
+
except Exception:
|
|
102
|
+
return []
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_knowledge_summary(root: Path) -> str:
|
|
106
|
+
knowledge_dir = root / ".agent" / "knowledge"
|
|
107
|
+
if not knowledge_dir.exists():
|
|
108
|
+
return "_No knowledge files found._"
|
|
109
|
+
parts = []
|
|
110
|
+
for md in sorted(knowledge_dir.glob("*.md"))[:6]:
|
|
111
|
+
content = read_file_safe(md, max_chars=800)
|
|
112
|
+
# Extract first meaningful paragraph
|
|
113
|
+
lines = [l.strip() for l in content.splitlines() if l.strip() and not l.startswith("#")]
|
|
114
|
+
snippet = " ".join(lines[:3])[:300]
|
|
115
|
+
parts.append(f"**{md.stem}**: {snippet}")
|
|
116
|
+
return "\n".join(parts) if parts else "_Empty._"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def get_repomap_summary(root: Path) -> str:
|
|
120
|
+
cache = root / ".agent" / "cache" / "repomap.json"
|
|
121
|
+
if cache.exists():
|
|
122
|
+
data = read_json_safe(cache)
|
|
123
|
+
lines = data.get("lines", [])
|
|
124
|
+
# Return first 40 lines of the map
|
|
125
|
+
return "\n".join(lines[:40]) or "_Empty._"
|
|
126
|
+
# Fallback: try running repomap directly (quick scan, 50 files max)
|
|
127
|
+
repomap_script = root / ".agent" / "scripts" / "repomap.py"
|
|
128
|
+
if repomap_script.exists():
|
|
129
|
+
import subprocess
|
|
130
|
+
try:
|
|
131
|
+
result = subprocess.run(
|
|
132
|
+
["python3", str(repomap_script), str(root), "--max-files", "50"],
|
|
133
|
+
capture_output=True, text=True, timeout=15
|
|
134
|
+
)
|
|
135
|
+
lines = result.stdout.splitlines()[:40]
|
|
136
|
+
return "\n".join(lines) or "_Could not scan._"
|
|
137
|
+
except Exception:
|
|
138
|
+
pass
|
|
139
|
+
return "_RepoMap not available. Run: bash .agent/scripts/refresh_brain.sh_"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_env_ports(root: Path) -> dict:
|
|
143
|
+
env_file = root / ".env"
|
|
144
|
+
ports = {}
|
|
145
|
+
if env_file.exists():
|
|
146
|
+
for line in env_file.read_text().splitlines():
|
|
147
|
+
if "PORT" in line and "=" in line:
|
|
148
|
+
k, _, v = line.partition("=")
|
|
149
|
+
ports[k.strip()] = v.strip().split("#")[0].strip()
|
|
150
|
+
return ports
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def needs_rebuild(root: Path) -> bool:
|
|
154
|
+
"""Check if any source changed since last brain generation."""
|
|
155
|
+
brain_file = root / ".agent" / "brain" / "summary.md"
|
|
156
|
+
if not brain_file.exists():
|
|
157
|
+
return True
|
|
158
|
+
last_build = brain_file.stat().st_mtime
|
|
159
|
+
check_dirs = [
|
|
160
|
+
root / ".agent" / "knowledge",
|
|
161
|
+
root / "src",
|
|
162
|
+
root / "backend",
|
|
163
|
+
]
|
|
164
|
+
for d in check_dirs:
|
|
165
|
+
if not d.exists():
|
|
166
|
+
continue
|
|
167
|
+
for f in d.rglob("*.md"):
|
|
168
|
+
if f.stat().st_mtime > last_build:
|
|
169
|
+
return True
|
|
170
|
+
for f in d.rglob("*.ts"):
|
|
171
|
+
if f.stat().st_mtime > last_build:
|
|
172
|
+
return True
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ─── Core Builder ────────────────────────────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
def build_brain(root: Path) -> tuple[str, dict]:
|
|
179
|
+
name = get_project_name(root)
|
|
180
|
+
stack = get_tech_stack(root)
|
|
181
|
+
ports = get_env_ports(root)
|
|
182
|
+
memory_nodes = get_memory_nodes(root)
|
|
183
|
+
knowledge = get_knowledge_summary(root)
|
|
184
|
+
repomap = get_repomap_summary(root)
|
|
185
|
+
now = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
186
|
+
|
|
187
|
+
port_str = " | ".join(f"{k}={v}" for k, v in ports.items()) if ports else "See .env"
|
|
188
|
+
mem_str = "\n".join(f" - {n}" for n in memory_nodes) if memory_nodes else " _(No decisions recorded yet)_"
|
|
189
|
+
|
|
190
|
+
summary = f"""# 🧠 Project Brain: {name}
|
|
191
|
+
> Auto-generated by ag-kit brain_builder | Last updated: {now}
|
|
192
|
+
> Root: {root}
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 1. Identity (Định danh)
|
|
197
|
+
- **Project**: {name}
|
|
198
|
+
- **Stack**: {', '.join(stack)}
|
|
199
|
+
- **Root**: `{root}`
|
|
200
|
+
- **Ports**: {port_str}
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 2. Codebase Structure (Tầng 1 — Repomap)
|
|
205
|
+
```
|
|
206
|
+
{repomap}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 3. Architecture & Rules (Tầng 3 — Knowledge Base)
|
|
212
|
+
{knowledge}
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 4. Recent Decisions (Tầng 2 — Working Memory)
|
|
217
|
+
{mem_str}
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 5. How to Read This Brain (Cross-Project Usage)
|
|
222
|
+
If you are an AI Agent working in ANOTHER project and need to understand **{name}**:
|
|
223
|
+
1. Read this file — it gives a complete overview in ~500 tokens.
|
|
224
|
+
2. For deeper code context: `vfs {root}/src`
|
|
225
|
+
3. For live memory: `python3 {root}/.agent/scripts/memory_tool.py search <keyword>`
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
_Auto-generated. Do not edit manually — changes will be overwritten on next rebuild._
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
index = {
|
|
232
|
+
"name": name,
|
|
233
|
+
"root": str(root),
|
|
234
|
+
"stack": stack,
|
|
235
|
+
"ports": ports,
|
|
236
|
+
"brain_path": str(root / ".agent" / "brain" / "summary.md"),
|
|
237
|
+
"updated_at": now,
|
|
238
|
+
}
|
|
239
|
+
return summary, index
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def update_global_registry(index: dict):
|
|
243
|
+
GLOBAL_REGISTRY.parent.mkdir(parents=True, exist_ok=True)
|
|
244
|
+
registry = {}
|
|
245
|
+
if GLOBAL_REGISTRY.exists():
|
|
246
|
+
try:
|
|
247
|
+
registry = json.loads(GLOBAL_REGISTRY.read_text())
|
|
248
|
+
except Exception:
|
|
249
|
+
pass
|
|
250
|
+
registry[index["name"]] = index
|
|
251
|
+
GLOBAL_REGISTRY.write_text(json.dumps(registry, indent=2, ensure_ascii=False))
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def write_brain(root: Path, summary: str, index: dict):
|
|
255
|
+
brain_dir = root / ".agent" / "brain"
|
|
256
|
+
brain_dir.mkdir(parents=True, exist_ok=True)
|
|
257
|
+
(brain_dir / "summary.md").write_text(summary, encoding="utf-8")
|
|
258
|
+
(brain_dir / "index.json").write_text(json.dumps(index, indent=2, ensure_ascii=False))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
# ─── Main ────────────────────────────────────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
def main():
|
|
264
|
+
p = argparse.ArgumentParser(description="Ag-Kit Brain Builder — Auto-generate project brain.")
|
|
265
|
+
p.add_argument("--root", default=".", help="Project root directory (default: current dir)")
|
|
266
|
+
p.add_argument("--quick", action="store_true", help="Skip rebuild if no source changes detected")
|
|
267
|
+
p.add_argument("--update", action="store_true", help="Force rebuild (default behavior)")
|
|
268
|
+
args = p.parse_args()
|
|
269
|
+
|
|
270
|
+
root = Path(args.root).resolve()
|
|
271
|
+
|
|
272
|
+
if args.quick and not needs_rebuild(root):
|
|
273
|
+
print(f"⚡ Brain is up-to-date for: {root.name} (use --update to force)")
|
|
274
|
+
return
|
|
275
|
+
|
|
276
|
+
print(f"🧠 Building brain for: {root.name}...")
|
|
277
|
+
summary, index = build_brain(root)
|
|
278
|
+
write_brain(root, summary, index)
|
|
279
|
+
update_global_registry(index)
|
|
280
|
+
|
|
281
|
+
brain_path = root / ".agent" / "brain" / "summary.md"
|
|
282
|
+
print(f"✅ Brain saved: {brain_path}")
|
|
283
|
+
print(f"📋 Global registry updated: {GLOBAL_REGISTRY}")
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
if __name__ == "__main__":
|
|
287
|
+
main()
|