@nalvietnam/avatar-cli 1.4.0 → 1.4.2
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.
|
@@ -84,7 +84,7 @@ var COMMANDS = [
|
|
|
84
84
|
{ name: "uninstall", desc: "G\u1EE1 Avatar kh\u1ECFi project + backup" },
|
|
85
85
|
{ name: "help", desc: "Hi\u1EC3n th\u1ECB help cho t\u1EEBng l\u1EC7nh" }
|
|
86
86
|
];
|
|
87
|
-
var CLI_VERSION = "1.4.
|
|
87
|
+
var CLI_VERSION = "1.4.2";
|
|
88
88
|
function printWelcomeScreen() {
|
|
89
89
|
printAvatarBanner({ tagline: `v${CLI_VERSION} \xB7 AI harness CLI for NAL Vietnam` });
|
|
90
90
|
const maxNameWidth = Math.max(...COMMANDS.map((c) => c.name.length));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/print-welcome-screen.ts","../../src/lib/avatar-ascii-banner.ts","../../src/lib/terminal-logger.ts"],"sourcesContent":["// Welcome screen in ra sau `npm install -g` (qua postinstall hook) hoặc khi\n// user gọi `avatar welcome` thủ công. Mục đích: cho user thấy banner + 13\n// commands + next step gợi ý ngay sau khi cài.\nimport boxen from \"boxen\";\nimport { printAvatarBanner } from \"./avatar-ascii-banner.js\";\nimport { chalk } from \"./terminal-logger.js\";\n\ninterface CommandSummary {\n name: string;\n desc: string;\n}\n\n// Danh sách 13 commands user-facing (mcp-run là hidden, bỏ qua).\nconst COMMANDS: CommandSummary[] = [\n { name: \"login\", desc: \"Đăng nhập Google SSO (@nal.vn)\" },\n { name: \"init\", desc: \"Khởi tạo Avatar — 3 flow tự nhận diện\" },\n { name: \"sync\", desc: \"Pull team-ai-pack mới nhất\" },\n { name: \"scan\", desc: \"Project scanner + knowledge proposal\" },\n { name: \"review\", desc: \"Duyệt pending proposals\" },\n { name: \"status\", desc: \"Snapshot project, pack, pending, backup\" },\n { name: \"doctor\", desc: \"Chẩn đoán cài đặt Avatar\" },\n { name: \"restore\", desc: \"Khôi phục .claude/pack/ từ backup\" },\n { name: \"commit\", desc: \"Commit src/ hoặc Avatar state (client mode)\" },\n { name: \"tools\", desc: \"Quản lý system tools + MCP servers\" },\n { name: \"secrets\", desc: \"Quản lý secrets trong OS keychain\" },\n { name: \"uninstall\", desc: \"Gỡ Avatar khỏi project + backup\" },\n { name: \"help\", desc: \"Hiển thị help cho từng lệnh\" },\n];\n\nconst CLI_VERSION = \"1.4.0\";\n\nexport function printWelcomeScreen(): void {\n printAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` });\n\n // Tính độ rộng max của tên command để align cột.\n const maxNameWidth = Math.max(...COMMANDS.map((c) => c.name.length));\n\n const commandLines = COMMANDS.map((c) => {\n const padded = c.name.padEnd(maxNameWidth);\n return ` ${chalk.cyan(padded)} ${chalk.dim(c.desc)}`;\n }).join(\"\\n\");\n\n const nextSteps = [\n \"\",\n chalk.bold(\"13 lệnh sẵn sàng:\"),\n \"\",\n commandLines,\n \"\",\n chalk.bold(\"Next steps:\"),\n \"\",\n ` ${chalk.green(\"1.\")} ${chalk.cyan(\"avatar login\")} Đăng nhập SSO`,\n ` ${chalk.green(\"2.\")} ${chalk.cyan(\"avatar init\")} Khởi tạo dự án`,\n ` ${chalk.green(\"?.\")} ${chalk.cyan(\"avatar <command> --help\")} Xem chi tiết lệnh`,\n \"\",\n chalk.dim(\"Docs: https://www.npmjs.com/package/@nalvietnam/avatar-cli\"),\n ].join(\"\\n\");\n\n process.stdout.write(\n `${boxen(nextSteps, { padding: 1, borderStyle: \"round\", borderColor: \"magenta\" })}\\n`,\n );\n}\n\n// Caller (bin/postinstall.js) chịu trách nhiệm gọi printWelcomeScreen() —\n// không auto-execute ở đây để tránh in trùng khi module được import từ postinstall.\n","// Avatar ASCII banner — gradient màu cam → tím để in ở các entry point chính:\n// `avatar --version`, `avatar init`, `avatar login`.\n//\n// Style: ANSI Shadow block characters (Unicode box-drawing).\n// Tự fallback sang plain text khi không phải TTY (CI, pipe ra file).\nimport chalk from \"chalk\";\n\n// 6 dòng chính của logo, mỗi dòng giữ độ rộng đồng nhất 50 ký tự để gradient đẹp.\nconst BANNER_LINES: readonly string[] = [\n \" █████╗ ██╗ ██╗ █████╗ ████████╗ █████╗ ██████╗ \",\n \"██╔══██╗██║ ██║██╔══██╗╚══██╔══╝██╔══██╗██╔══██╗\",\n \"███████║██║ ██║███████║ ██║ ███████║██████╔╝\",\n \"██╔══██║╚██╗ ██╔╝██╔══██║ ██║ ██╔══██║██╔══██╗\",\n \"██║ ██║ ╚████╔╝ ██║ ██║ ██║ ██║ ██║██║ ██║\",\n \"╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝\",\n] as const;\n\n// Gradient stops cam → tím (RGB triples). Mỗi dòng nội suy theo % chiều cao.\nconst GRADIENT_STOPS: ReadonlyArray<readonly [number, number, number]> = [\n [217, 79, 30], // cam-cháy (#d94f1e)\n [200, 70, 80], // cam-hồng\n [170, 70, 140], // hồng-tím\n [125, 88, 217], // tím (#7d58d9)\n];\n\n// Nội suy tuyến tính 1 kênh màu giữa 2 stop.\nfunction lerpChannel(a: number, b: number, t: number): number {\n return Math.round(a + (b - a) * t);\n}\n\n// Lấy màu RGB tại vị trí [0,1] trên gradient.\nfunction gradientAt(t: number): readonly [number, number, number] {\n const clamped = Math.max(0, Math.min(1, t));\n const scaled = clamped * (GRADIENT_STOPS.length - 1);\n const lo = Math.floor(scaled);\n const hi = Math.min(GRADIENT_STOPS.length - 1, lo + 1);\n const localT = scaled - lo;\n const a = GRADIENT_STOPS[lo];\n const b = GRADIENT_STOPS[hi];\n return [\n lerpChannel(a[0], b[0], localT),\n lerpChannel(a[1], b[1], localT),\n lerpChannel(a[2], b[2], localT),\n ];\n}\n\n// Build banner string đã tô màu sẵn. Trả empty khi terminal không hỗ trợ màu.\nexport function renderAvatarBanner(opts?: { tagline?: string }): string {\n const isTty = process.stdout.isTTY ?? false;\n const supportsColor = isTty && chalk.level > 0;\n\n // Plain fallback cho CI hoặc pipe.\n if (!supportsColor) {\n return [...BANNER_LINES, ...(opts?.tagline ? [\"\", opts.tagline] : [])].join(\"\\n\");\n }\n\n const colored = BANNER_LINES.map((line, idx) => {\n const t = BANNER_LINES.length === 1 ? 0 : idx / (BANNER_LINES.length - 1);\n const [r, g, b] = gradientAt(t);\n return chalk.rgb(r, g, b).bold(line);\n });\n\n if (opts?.tagline) {\n colored.push(\"\");\n colored.push(chalk.dim(opts.tagline));\n }\n\n return colored.join(\"\\n\");\n}\n\n// Tiện ích: in banner ra stdout với newline phía trước/sau cho thoáng.\nexport function printAvatarBanner(opts?: { tagline?: string }): void {\n process.stdout.write(`\\n${renderAvatarBanner(opts)}\\n\\n`);\n}\n","// Terminal logging helpers — chalk for color, ora for spinners.\n// All Avatar CLI output should funnel through here for consistent UX.\nimport chalk from \"chalk\";\nimport ora, { type Ora } from \"ora\";\n\ntype LogFn = (message: string) => void;\n\nexport const log: {\n info: LogFn;\n success: LogFn;\n warn: LogFn;\n error: LogFn;\n dim: LogFn;\n plain: LogFn;\n} = {\n info: (m) => process.stdout.write(`${chalk.blue(\"ℹ\")} ${m}\\n`),\n success: (m) => process.stdout.write(`${chalk.green(\"✓\")} ${m}\\n`),\n warn: (m) => process.stdout.write(`${chalk.yellow(\"⚠\")} ${m}\\n`),\n error: (m) => process.stderr.write(`${chalk.red(\"✗\")} ${m}\\n`),\n dim: (m) => process.stdout.write(`${chalk.dim(m)}\\n`),\n plain: (m) => process.stdout.write(`${m}\\n`),\n};\n\n// Spinner wrapper — handles non-TTY by degrading to plain output.\nexport function spinner(text: string): Ora {\n return ora({\n text,\n spinner: \"dots\",\n isEnabled: process.stdout.isTTY ?? false,\n }).start();\n}\n\n// Chalk re-export so commands don't all import chalk separately.\nexport { chalk };\n"],"mappings":"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","names":["chalk","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/print-welcome-screen.ts","../../src/lib/avatar-ascii-banner.ts","../../src/lib/terminal-logger.ts"],"sourcesContent":["// Welcome screen in ra sau `npm install -g` (qua postinstall hook) hoặc khi\n// user gọi `avatar welcome` thủ công. Mục đích: cho user thấy banner + 13\n// commands + next step gợi ý ngay sau khi cài.\nimport boxen from \"boxen\";\nimport { printAvatarBanner } from \"./avatar-ascii-banner.js\";\nimport { chalk } from \"./terminal-logger.js\";\n\ninterface CommandSummary {\n name: string;\n desc: string;\n}\n\n// Danh sách 13 commands user-facing (mcp-run là hidden, bỏ qua).\nconst COMMANDS: CommandSummary[] = [\n { name: \"login\", desc: \"Đăng nhập Google SSO (@nal.vn)\" },\n { name: \"init\", desc: \"Khởi tạo Avatar — 3 flow tự nhận diện\" },\n { name: \"sync\", desc: \"Pull team-ai-pack mới nhất\" },\n { name: \"scan\", desc: \"Project scanner + knowledge proposal\" },\n { name: \"review\", desc: \"Duyệt pending proposals\" },\n { name: \"status\", desc: \"Snapshot project, pack, pending, backup\" },\n { name: \"doctor\", desc: \"Chẩn đoán cài đặt Avatar\" },\n { name: \"restore\", desc: \"Khôi phục .claude/pack/ từ backup\" },\n { name: \"commit\", desc: \"Commit src/ hoặc Avatar state (client mode)\" },\n { name: \"tools\", desc: \"Quản lý system tools + MCP servers\" },\n { name: \"secrets\", desc: \"Quản lý secrets trong OS keychain\" },\n { name: \"uninstall\", desc: \"Gỡ Avatar khỏi project + backup\" },\n { name: \"help\", desc: \"Hiển thị help cho từng lệnh\" },\n];\n\nconst CLI_VERSION = \"1.4.2\";\n\nexport function printWelcomeScreen(): void {\n printAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` });\n\n // Tính độ rộng max của tên command để align cột.\n const maxNameWidth = Math.max(...COMMANDS.map((c) => c.name.length));\n\n const commandLines = COMMANDS.map((c) => {\n const padded = c.name.padEnd(maxNameWidth);\n return ` ${chalk.cyan(padded)} ${chalk.dim(c.desc)}`;\n }).join(\"\\n\");\n\n const nextSteps = [\n \"\",\n chalk.bold(\"13 lệnh sẵn sàng:\"),\n \"\",\n commandLines,\n \"\",\n chalk.bold(\"Next steps:\"),\n \"\",\n ` ${chalk.green(\"1.\")} ${chalk.cyan(\"avatar login\")} Đăng nhập SSO`,\n ` ${chalk.green(\"2.\")} ${chalk.cyan(\"avatar init\")} Khởi tạo dự án`,\n ` ${chalk.green(\"?.\")} ${chalk.cyan(\"avatar <command> --help\")} Xem chi tiết lệnh`,\n \"\",\n chalk.dim(\"Docs: https://www.npmjs.com/package/@nalvietnam/avatar-cli\"),\n ].join(\"\\n\");\n\n process.stdout.write(\n `${boxen(nextSteps, { padding: 1, borderStyle: \"round\", borderColor: \"magenta\" })}\\n`,\n );\n}\n\n// Caller (bin/postinstall.js) chịu trách nhiệm gọi printWelcomeScreen() —\n// không auto-execute ở đây để tránh in trùng khi module được import từ postinstall.\n","// Avatar ASCII banner — gradient màu cam → tím để in ở các entry point chính:\n// `avatar --version`, `avatar init`, `avatar login`.\n//\n// Style: ANSI Shadow block characters (Unicode box-drawing).\n// Tự fallback sang plain text khi không phải TTY (CI, pipe ra file).\nimport chalk from \"chalk\";\n\n// 6 dòng chính của logo, mỗi dòng giữ độ rộng đồng nhất 50 ký tự để gradient đẹp.\nconst BANNER_LINES: readonly string[] = [\n \" █████╗ ██╗ ██╗ █████╗ ████████╗ █████╗ ██████╗ \",\n \"██╔══██╗██║ ██║██╔══██╗╚══██╔══╝██╔══██╗██╔══██╗\",\n \"███████║██║ ██║███████║ ██║ ███████║██████╔╝\",\n \"██╔══██║╚██╗ ██╔╝██╔══██║ ██║ ██╔══██║██╔══██╗\",\n \"██║ ██║ ╚████╔╝ ██║ ██║ ██║ ██║ ██║██║ ██║\",\n \"╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝\",\n] as const;\n\n// Gradient stops cam → tím (RGB triples). Mỗi dòng nội suy theo % chiều cao.\nconst GRADIENT_STOPS: ReadonlyArray<readonly [number, number, number]> = [\n [217, 79, 30], // cam-cháy (#d94f1e)\n [200, 70, 80], // cam-hồng\n [170, 70, 140], // hồng-tím\n [125, 88, 217], // tím (#7d58d9)\n];\n\n// Nội suy tuyến tính 1 kênh màu giữa 2 stop.\nfunction lerpChannel(a: number, b: number, t: number): number {\n return Math.round(a + (b - a) * t);\n}\n\n// Lấy màu RGB tại vị trí [0,1] trên gradient.\nfunction gradientAt(t: number): readonly [number, number, number] {\n const clamped = Math.max(0, Math.min(1, t));\n const scaled = clamped * (GRADIENT_STOPS.length - 1);\n const lo = Math.floor(scaled);\n const hi = Math.min(GRADIENT_STOPS.length - 1, lo + 1);\n const localT = scaled - lo;\n const a = GRADIENT_STOPS[lo];\n const b = GRADIENT_STOPS[hi];\n return [\n lerpChannel(a[0], b[0], localT),\n lerpChannel(a[1], b[1], localT),\n lerpChannel(a[2], b[2], localT),\n ];\n}\n\n// Build banner string đã tô màu sẵn. Trả empty khi terminal không hỗ trợ màu.\nexport function renderAvatarBanner(opts?: { tagline?: string }): string {\n const isTty = process.stdout.isTTY ?? false;\n const supportsColor = isTty && chalk.level > 0;\n\n // Plain fallback cho CI hoặc pipe.\n if (!supportsColor) {\n return [...BANNER_LINES, ...(opts?.tagline ? [\"\", opts.tagline] : [])].join(\"\\n\");\n }\n\n const colored = BANNER_LINES.map((line, idx) => {\n const t = BANNER_LINES.length === 1 ? 0 : idx / (BANNER_LINES.length - 1);\n const [r, g, b] = gradientAt(t);\n return chalk.rgb(r, g, b).bold(line);\n });\n\n if (opts?.tagline) {\n colored.push(\"\");\n colored.push(chalk.dim(opts.tagline));\n }\n\n return colored.join(\"\\n\");\n}\n\n// Tiện ích: in banner ra stdout với newline phía trước/sau cho thoáng.\nexport function printAvatarBanner(opts?: { tagline?: string }): void {\n process.stdout.write(`\\n${renderAvatarBanner(opts)}\\n\\n`);\n}\n","// Terminal logging helpers — chalk for color, ora for spinners.\n// All Avatar CLI output should funnel through here for consistent UX.\nimport chalk from \"chalk\";\nimport ora, { type Ora } from \"ora\";\n\ntype LogFn = (message: string) => void;\n\nexport const log: {\n info: LogFn;\n success: LogFn;\n warn: LogFn;\n error: LogFn;\n dim: LogFn;\n plain: LogFn;\n} = {\n info: (m) => process.stdout.write(`${chalk.blue(\"ℹ\")} ${m}\\n`),\n success: (m) => process.stdout.write(`${chalk.green(\"✓\")} ${m}\\n`),\n warn: (m) => process.stdout.write(`${chalk.yellow(\"⚠\")} ${m}\\n`),\n error: (m) => process.stderr.write(`${chalk.red(\"✗\")} ${m}\\n`),\n dim: (m) => process.stdout.write(`${chalk.dim(m)}\\n`),\n plain: (m) => process.stdout.write(`${m}\\n`),\n};\n\n// Spinner wrapper — handles non-TTY by degrading to plain output.\nexport function spinner(text: string): Ora {\n return ora({\n text,\n spinner: \"dots\",\n isEnabled: process.stdout.isTTY ?? false,\n }).start();\n}\n\n// Long-running spinner với elapsed time — update text mỗi giây.\n// Trả về { stop } để caller clear interval + stop spinner đúng cách.\n// Format: \"⠋ <prefix> (1:23)\" — user biết tool alive + chạy bao lâu.\nexport function spinnerWithElapsed(prefix: string): {\n succeed: (text: string) => void;\n fail: (text: string) => void;\n stop: () => void;\n} {\n const startMs = Date.now();\n const sp = spinner(`${prefix} (0:00)`);\n const formatElapsed = (): string => {\n const sec = Math.floor((Date.now() - startMs) / 1000);\n const m = Math.floor(sec / 60);\n const s = sec % 60;\n return `${m}:${String(s).padStart(2, \"0\")}`;\n };\n const interval = setInterval(() => {\n sp.text = `${prefix} (${formatElapsed()})`;\n }, 1000);\n return {\n succeed: (text: string) => {\n clearInterval(interval);\n sp.succeed(`${text} (${formatElapsed()})`);\n },\n fail: (text: string) => {\n clearInterval(interval);\n sp.fail(`${text} (${formatElapsed()})`);\n },\n stop: () => {\n clearInterval(interval);\n sp.stop();\n },\n };\n}\n\n// Chalk re-export so commands don't all import chalk separately.\nexport { chalk };\n"],"mappings":"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","names":["chalk","chalk"]}
|
|
@@ -30,22 +30,30 @@ avatar commit src -m "fix: ..." --push # Commit + push luôn
|
|
|
30
30
|
- ❌ `git commit` raw trong `src/` → bypass Avatar audit, miss hooks validation
|
|
31
31
|
- ❌ `git push` raw — luôn dùng `avatar commit src --push`
|
|
32
32
|
|
|
33
|
-
**Nếu workspace
|
|
33
|
+
**Nếu workspace root (`.claude/`, `CLAUDE.md`, file backup, untracked...) có changes:**
|
|
34
34
|
|
|
35
|
-
Đây là Avatar tự update hoặc bạn lỡ edit. **KHÔNG
|
|
35
|
+
Đây là Avatar tự update hoặc bạn lỡ edit. **Mặc định: ĐỂ NGUYÊN, KHÔNG đụng vào.** Avatar sẽ tự sync khi cần, hoặc admin pull về share cho team.
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
# Discard workspace changes (giữ src/ untouched):
|
|
39
|
-
git restore . # ở workspace root, KHÔNG vào src/
|
|
40
|
-
```
|
|
37
|
+
→ Chỉ commit/push **trong `src/`**, **bỏ qua hoàn toàn** các file ở workspace root khi commit.
|
|
41
38
|
|
|
42
39
|
Nếu bạn cố tình muốn share knowledge cập nhật (vd ADR mới, gotcha mới) → báo team admin qua Slack, admin sẽ sync cho cả team.
|
|
43
40
|
|
|
41
|
+
> ⚠️ **Hướng dẫn dành riêng cho AI assistant (Claude Code agent):**
|
|
42
|
+
>
|
|
43
|
+
> Khi user yêu cầu commit code:
|
|
44
|
+
>
|
|
45
|
+
> 1. **CHỈ stage + commit file trong `src/`**. KHÔNG `git add -A` ở workspace root.
|
|
46
|
+
> 2. **KHÔNG tự ý chạy** `git restore`, `git clean`, `git checkout --`, hoặc bất kỳ lệnh nào xóa/discard workspace root files — kể cả untracked file.
|
|
47
|
+
> 3. Nếu thấy workspace root có changes (`.claude/`, `CLAUDE.md`, file backup, untracked...) → **ignore, để nguyên**. Đó là Avatar state, không phải rác.
|
|
48
|
+
> 4. Sau khi `avatar commit src` xong → **dừng**. Không "dọn dẹp" thêm gì ở root.
|
|
49
|
+
> 5. Nếu user explicit yêu cầu discard workspace changes → hỏi confirm trước (`AskUserQuestion`) rồi mới chạy.
|
|
50
|
+
|
|
44
51
|
**Tại sao strict thế?**
|
|
45
52
|
|
|
46
53
|
- Workspace remote team-shared: 1 member push nhầm → toàn team pull về phải resolve conflict
|
|
47
54
|
- Avatar state có hooks, MCP config, knowledge nhạy cảm — chỉ admin verify trước khi share
|
|
48
55
|
- `git commit` raw không biết 2-repo layout → dễ commit nhầm vào wrong remote
|
|
56
|
+
- AI agent tự discard untracked files = **mất data im lặng** (file backup, ADR draft, gotcha note user đang viết dở)
|
|
49
57
|
|
|
50
58
|
{{gitnexusSection}}
|
|
51
59
|
|
package/package.json
CHANGED
|
@@ -30,22 +30,30 @@ avatar commit src -m "fix: ..." --push # Commit + push luôn
|
|
|
30
30
|
- ❌ `git commit` raw trong `src/` → bypass Avatar audit, miss hooks validation
|
|
31
31
|
- ❌ `git push` raw — luôn dùng `avatar commit src --push`
|
|
32
32
|
|
|
33
|
-
**Nếu workspace
|
|
33
|
+
**Nếu workspace root (`.claude/`, `CLAUDE.md`, file backup, untracked...) có changes:**
|
|
34
34
|
|
|
35
|
-
Đây là Avatar tự update hoặc bạn lỡ edit. **KHÔNG
|
|
35
|
+
Đây là Avatar tự update hoặc bạn lỡ edit. **Mặc định: ĐỂ NGUYÊN, KHÔNG đụng vào.** Avatar sẽ tự sync khi cần, hoặc admin pull về share cho team.
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
# Discard workspace changes (giữ src/ untouched):
|
|
39
|
-
git restore . # ở workspace root, KHÔNG vào src/
|
|
40
|
-
```
|
|
37
|
+
→ Chỉ commit/push **trong `src/`**, **bỏ qua hoàn toàn** các file ở workspace root khi commit.
|
|
41
38
|
|
|
42
39
|
Nếu bạn cố tình muốn share knowledge cập nhật (vd ADR mới, gotcha mới) → báo team admin qua Slack, admin sẽ sync cho cả team.
|
|
43
40
|
|
|
41
|
+
> ⚠️ **Hướng dẫn dành riêng cho AI assistant (Claude Code agent):**
|
|
42
|
+
>
|
|
43
|
+
> Khi user yêu cầu commit code:
|
|
44
|
+
>
|
|
45
|
+
> 1. **CHỈ stage + commit file trong `src/`**. KHÔNG `git add -A` ở workspace root.
|
|
46
|
+
> 2. **KHÔNG tự ý chạy** `git restore`, `git clean`, `git checkout --`, hoặc bất kỳ lệnh nào xóa/discard workspace root files — kể cả untracked file.
|
|
47
|
+
> 3. Nếu thấy workspace root có changes (`.claude/`, `CLAUDE.md`, file backup, untracked...) → **ignore, để nguyên**. Đó là Avatar state, không phải rác.
|
|
48
|
+
> 4. Sau khi `avatar commit src` xong → **dừng**. Không "dọn dẹp" thêm gì ở root.
|
|
49
|
+
> 5. Nếu user explicit yêu cầu discard workspace changes → hỏi confirm trước (`AskUserQuestion`) rồi mới chạy.
|
|
50
|
+
|
|
44
51
|
**Tại sao strict thế?**
|
|
45
52
|
|
|
46
53
|
- Workspace remote team-shared: 1 member push nhầm → toàn team pull về phải resolve conflict
|
|
47
54
|
- Avatar state có hooks, MCP config, knowledge nhạy cảm — chỉ admin verify trước khi share
|
|
48
55
|
- `git commit` raw không biết 2-repo layout → dễ commit nhầm vào wrong remote
|
|
56
|
+
- AI agent tự discard untracked files = **mất data im lặng** (file backup, ADR draft, gotcha note user đang viết dở)
|
|
49
57
|
|
|
50
58
|
{{gitnexusSection}}
|
|
51
59
|
|