@nalvietnam/avatar-cli 1.1.6 → 1.2.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/lib/terminal-logger.ts","../src/lib/not-implemented-stub.ts","../src/commands/commit.ts","../src/commands/doctor.ts","../src/lib/filesystem-helpers.ts","../src/lib/git-operations.ts","../src/lib/project-tree-scaffolder.ts","../src/lib/template-bundle-loader.ts","../src/lib/mustache-template-engine.ts","../src/lib/user-config-store.ts","../src/types/config-schema.ts","../src/commands/init.ts","../src/lib/audit-log-appender.ts","../src/lib/avatar-ascii-banner.ts","../src/lib/execute-gh-repo-create.ts","../src/lib/resolve-github-username-default.ts","../src/lib/validate-repo-name-and-visibility.ts","../src/lib/create-github-remote-from-folder.ts","../src/lib/create-workspace-remote-via-gh.ts","../src/lib/check-gh-cli-auth-status.ts","../src/lib/detect-package-manager.ts","../src/lib/detect-host-platform.ts","../src/lib/install-gh-cli-via-package-manager.ts","../src/lib/setup-git-credential-via-gh.ts","../src/lib/trigger-gh-cli-auth-login.ts","../src/lib/verify-git-remote-accessible.ts","../src/lib/git-auth-and-install-orchestrator.ts","../src/lib/check-folder-has-git.ts","../src/lib/create-initial-git-commit.ts","../src/lib/detect-folder-tech-stack.ts","../src/lib/gitignore-template-loader.ts","../src/lib/write-or-merge-gitignore.ts","../src/lib/git-bootstrap-orchestrator.ts","../src/lib/team-pack-submodule-manager.ts","../src/lib/resolve-team-pack-repo-url.ts","../src/commands/init-conflict-detection-helpers.ts","../src/commands/init-scaffold-variable-builders.ts","../src/commands/login.ts","../src/lib/google-oauth-device-flow.ts","../src/commands/mcp-run.ts","../src/commands/restore.ts","../src/commands/review.ts","../src/commands/scan.ts","../src/commands/secrets.ts","../src/commands/status.ts","../src/lib/pack-backup-manager.ts","../src/commands/sync.ts","../src/commands/tools.ts","../src/commands/uninstall.ts","../src/lib/create-uninstall-backup-snapshot.ts","../src/lib/detect-avatar-project-artifacts.ts","../src/lib/execute-uninstall-deletion.ts"],"sourcesContent":["// Bootstrap: load commander, register all 13 subcommands, parse argv.\n// Each command lives in src/commands/<name>.ts as a function that accepts the\n// commander Command instance and registers itself.\nimport { Command } from \"commander\";\nimport { registerCommitCommand } from \"./commands/commit.js\";\nimport { registerDoctorCommand } from \"./commands/doctor.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerLoginCommand } from \"./commands/login.js\";\nimport { registerMcpRunCommand } from \"./commands/mcp-run.js\";\nimport { registerRestoreCommand } from \"./commands/restore.js\";\nimport { registerReviewCommand } from \"./commands/review.js\";\nimport { registerScanCommand } from \"./commands/scan.js\";\nimport { registerSecretsCommand } from \"./commands/secrets.js\";\nimport { registerStatusCommand } from \"./commands/status.js\";\nimport { registerSyncCommand } from \"./commands/sync.js\";\nimport { registerToolsCommand } from \"./commands/tools.js\";\nimport { registerUninstallCommand } from \"./commands/uninstall.js\";\nimport { printAvatarBanner, renderAvatarBanner } from \"./lib/avatar-ascii-banner.js\";\n\nconst CLI_VERSION = \"1.1.6\";\n\nconst program = new Command();\n\nprogram\n .name(\"avatar\")\n .description(\"AI harness CLI for NAL Vietnam engineering\")\n .version(CLI_VERSION, \"-v, --version\", \"Hiển thị phiên bản Avatar CLI\")\n // Override mặc định của commander để in banner kèm version. Commander cho phép\n // custom output qua configureOutput nhưng cách đơn giản nhất là intercept ở argv.\n .addHelpText(\n \"beforeAll\",\n () =>\n `\\n${renderAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` })}\\n\\n`,\n );\n\n// In banner khi user gọi `avatar -v` / `avatar --version`. Banner đã chứa\n// version trong tagline nên ta short-circuit luôn, không để commander in thêm\n// dòng \"1.0.1\" dư thừa.\nconst isVersionCall = process.argv.includes(\"-v\") || process.argv.includes(\"--version\");\nif (isVersionCall) {\n printAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` });\n process.exit(0);\n}\n\n// Register all commands. Order matches Chapter 09 spec in implementation doc.\nregisterLoginCommand(program);\nregisterInitCommand(program);\nregisterSyncCommand(program);\nregisterScanCommand(program);\nregisterReviewCommand(program);\nregisterStatusCommand(program);\nregisterDoctorCommand(program);\nregisterRestoreCommand(program);\nregisterCommitCommand(program);\nregisterToolsCommand(program);\nregisterSecretsCommand(program);\nregisterMcpRunCommand(program);\nregisterUninstallCommand(program);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n // Top-level error sink. Individual commands should handle their own errors;\n // anything reaching here is unexpected.\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`✗ Lỗi không xử lý được: ${msg}\\n`);\n process.exit(1);\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","// Shared stub action for commands wired into commander but not yet implemented.\n// Prints a consistent message + exit code so users know it's coming.\nimport { chalk } from \"./terminal-logger.js\";\n\nexport function notImplementedYet(commandName: string, milestone?: string): () => void {\n return () => {\n process.stdout.write(\n `${chalk.yellow(\"⏳\")} ${chalk.bold(`avatar ${commandName}`)} — chưa implement ở milestone hiện tại.\\n`,\n );\n if (milestone) {\n process.stdout.write(` Dự kiến: ${chalk.cyan(milestone)}\\n`);\n }\n process.stdout.write(\" Spec đã có trong avatar-cli-implementation_4.html.\\n\");\n process.exit(0);\n };\n}\n","// `avatar commit [--src|--avatar|--both] [-m <msg>] [--push]` — Command 09.\n// Only valid in client/library mode. Splits commits between the client repo\n// (src/) and the Avatar workspace.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerCommitCommand(program: Command): void {\n program\n .command(\"commit\")\n .description(\"Commit code khách (src/) hoặc Avatar state riêng — chỉ client mode (M07)\")\n .option(\"--src\", \"Commit src/ → client remote\")\n .option(\"--avatar\", \"Commit Avatar state → workspace remote\")\n .option(\"--both\", \"Commit cả hai (src trước, avatar sau)\")\n .option(\"-m, --message <msg>\", \"Commit message\")\n .option(\"--push\", \"Tự động push sau khi commit\")\n .action(notImplementedYet(\"commit\", \"Milestone 07\"));\n}\n","import { spawnSync } from \"node:child_process\";\n// `avatar doctor [--fix]` — Command 07 spec.\n// Run a series of health checks and surface ✓/✗ for each. --fix attempts\n// auto-fixes for the ones safe to fix automatically.\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { pathExists } from \"../lib/filesystem-helpers.js\";\nimport { isGitRepo } from \"../lib/git-operations.js\";\nimport { installGitHook } from \"../lib/project-tree-scaffolder.js\";\nimport { chalk, log } from \"../lib/terminal-logger.js\";\nimport { isTokenExpired, readUserConfig } from \"../lib/user-config-store.js\";\n\ninterface CheckResult {\n name: string;\n status: \"ok\" | \"warn\" | \"fail\";\n detail: string;\n fixable: boolean;\n fix?: () => Promise<void>;\n}\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Chẩn đoán cài đặt Avatar: hooks, MCP, login, submodule, ...\")\n .option(\"--fix\", \"Tự động fix các issue có thể fix tự động\")\n .action(async (opts: { fix?: boolean }) => {\n try {\n const checks = await runChecks(process.cwd());\n renderChecks(checks);\n if (opts.fix) await applyFixes(checks);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runChecks(cwd: string): Promise<CheckResult[]> {\n const checks: CheckResult[] = [];\n\n // 1. Node.js version >= 18.17\n const nodeVer = process.versions.node;\n const [major, minor] = nodeVer.split(\".\").map((n) => Number.parseInt(n, 10));\n const nodeOk = (major ?? 0) > 18 || ((major ?? 0) === 18 && (minor ?? 0) >= 17);\n checks.push({\n name: \"Node.js version\",\n status: nodeOk ? \"ok\" : \"fail\",\n detail: `v${nodeVer}${nodeOk ? \"\" : \" (cần >= 18.17)\"}`,\n fixable: false,\n });\n\n // 2. Login.\n const config = await readUserConfig();\n if (!config) {\n checks.push({\n name: \"Login status\",\n status: \"fail\",\n detail: \"Chưa đăng nhập — chạy 'avatar login'\",\n fixable: false,\n });\n } else if (isTokenExpired(config)) {\n checks.push({\n name: \"Login status\",\n status: \"warn\",\n detail: `Token hết hạn (${config.email}) — chạy 'avatar login'`,\n fixable: false,\n });\n } else {\n checks.push({\n name: \"Login status\",\n status: \"ok\",\n detail: `Logged in: ${config.email}`,\n fixable: false,\n });\n }\n\n // 3. Git repo.\n const gitRepo = await isGitRepo(cwd);\n checks.push({\n name: \"Git repository\",\n status: gitRepo ? \"ok\" : \"warn\",\n detail: gitRepo ? cwd : \"Không phải git repo (cần cho 'avatar init')\",\n fixable: false,\n });\n\n // 4. .claude/pack/ submodule.\n const packPath = join(cwd, \".claude\", \"pack\");\n const hasPack = await pathExists(packPath);\n checks.push({\n name: \"team-ai-pack submodule\",\n status: hasPack ? \"ok\" : \"warn\",\n detail: hasPack ? packPath : \"Avatar chưa init — chạy 'avatar init'\",\n fixable: false,\n });\n\n // 5. CLAUDE.md present.\n const claudeMdPath = join(cwd, \"CLAUDE.md\");\n const hasClaudeMd = await pathExists(claudeMdPath);\n checks.push({\n name: \"CLAUDE.md\",\n status: hasClaudeMd ? \"ok\" : \"warn\",\n detail: hasClaudeMd ? \"tồn tại ở project root\" : \"thiếu — chạy 'avatar init'\",\n fixable: false,\n });\n\n // 6. post-merge hook.\n const hookPath = join(cwd, \".git\", \"hooks\", \"post-merge\");\n const hasHook = await pathExists(hookPath);\n if (gitRepo && hasPack) {\n checks.push({\n name: \"Git hook post-merge\",\n status: hasHook ? \"ok\" : \"fail\",\n detail: hasHook ? \"installed\" : \"missing — fixable\",\n fixable: !hasHook,\n fix: hasHook\n ? undefined\n : async () => {\n await installGitHook(join(cwd, \".git\"), \"post-merge\");\n },\n });\n }\n\n // 7. .gitignore has Avatar entries.\n const gitignorePath = join(cwd, \".gitignore\");\n if (gitRepo) {\n let gitignoreOk = false;\n if (await pathExists(gitignorePath)) {\n const content = await fs.readFile(gitignorePath, \"utf8\");\n gitignoreOk = content.includes(\".claude/_pending/\");\n }\n checks.push({\n name: \".gitignore Avatar entries\",\n status: gitignoreOk ? \"ok\" : hasPack ? \"fail\" : \"warn\",\n detail: gitignoreOk ? \"có .claude/_pending/, .claude/_backup/\" : \"thiếu entries\",\n fixable: false,\n });\n }\n\n // 8. Claude Code CLI installed (best-effort `which claude`).\n const which = spawnSync(\"which\", [\"claude\"]);\n const hasClaudeCli = which.status === 0;\n checks.push({\n name: \"Claude Code CLI\",\n status: hasClaudeCli ? \"ok\" : \"warn\",\n detail: hasClaudeCli ? which.stdout.toString().trim() : \"không tìm thấy 'claude' trên PATH\",\n fixable: false,\n });\n\n return checks;\n}\n\nfunction renderChecks(checks: CheckResult[]): void {\n const lines = [chalk.bold(\"Avatar Doctor\"), \"─\".repeat(48)];\n let passed = 0;\n let issues = 0;\n let fixable = 0;\n for (const c of checks) {\n const icon =\n c.status === \"ok\"\n ? chalk.green(\"✓\")\n : c.status === \"warn\"\n ? chalk.yellow(\"⚠\")\n : chalk.red(\"✗\");\n lines.push(`${icon} ${c.name.padEnd(28)} ${chalk.dim(c.detail)}`);\n if (c.status === \"ok\") passed += 1;\n else {\n issues += 1;\n if (c.fixable) fixable += 1;\n }\n }\n lines.push(\"─\".repeat(48));\n lines.push(\n `${passed} checks passed, ${issues} issue${issues === 1 ? \"\" : \"s\"}${fixable > 0 ? ` (${fixable} fixable — chạy 'avatar doctor --fix')` : \"\"}`,\n );\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n\nasync function applyFixes(checks: CheckResult[]): Promise<void> {\n let count = 0;\n for (const c of checks) {\n if (c.fixable && c.fix) {\n try {\n await c.fix();\n log.success(`Fixed: ${c.name}`);\n count += 1;\n } catch (err) {\n log.error(`Failed to fix ${c.name}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\n if (count === 0) log.dim(\"Không có gì để fix tự động.\");\n}\n","// Thin promise-based wrappers around node:fs/promises with the patterns Avatar\n// uses most: ensure-dir, read-text, write-text-atomic, copy-dir-recursive.\n// Atomic write writes to a temp file then renames to avoid corruption if Avatar\n// crashes mid-write.\nimport { constants, promises as fs } from \"node:fs\";\nimport { dirname, join, relative } from \"node:path\";\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await fs.access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDir(path: string): Promise<void> {\n await fs.mkdir(path, { recursive: true });\n}\n\nexport async function readText(path: string): Promise<string> {\n return await fs.readFile(path, \"utf8\");\n}\n\nexport async function readJson<T>(path: string): Promise<T> {\n return JSON.parse(await readText(path)) as T;\n}\n\n// Atomic write: write to temp file then rename. Prevents corruption if process\n// is killed between open() and close(). chmod is applied AFTER rename.\nexport async function writeTextAtomic(path: string, content: string, mode?: number): Promise<void> {\n await ensureDir(dirname(path));\n const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n await fs.writeFile(tmp, content, \"utf8\");\n if (mode !== undefined) {\n await fs.chmod(tmp, mode);\n }\n await fs.rename(tmp, path);\n}\n\nexport async function writeJsonAtomic(path: string, data: unknown, mode?: number): Promise<void> {\n await writeTextAtomic(path, `${JSON.stringify(data, null, 2)}\\n`, mode);\n}\n\n// Recursive copy. excludeNames filters by basename at any depth (e.g. \".git\").\nexport async function copyDirRecursive(\n source: string,\n destination: string,\n excludeNames: string[] = [],\n): Promise<void> {\n await ensureDir(destination);\n const entries = await fs.readdir(source, { withFileTypes: true });\n for (const entry of entries) {\n if (excludeNames.includes(entry.name)) continue;\n const src = join(source, entry.name);\n const dst = join(destination, entry.name);\n if (entry.isDirectory()) {\n await copyDirRecursive(src, dst, excludeNames);\n } else if (entry.isSymbolicLink()) {\n const target = await fs.readlink(src);\n await fs.symlink(target, dst);\n } else {\n await fs.copyFile(src, dst);\n }\n }\n}\n\nexport async function removeRecursive(path: string): Promise<void> {\n await fs.rm(path, { recursive: true, force: true });\n}\n\nexport function relativeFromCwd(path: string): string {\n return relative(process.cwd(), path);\n}\n","import { join } from \"node:path\";\n// Wrapper around simple-git for the operations Avatar uses repeatedly:\n// repo detection, submodule add/update, status, log, tag listing.\n// Centralised so error formatting and cwd handling stays consistent.\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { pathExists } from \"./filesystem-helpers.js\";\n\nexport function git(cwd: string = process.cwd()): SimpleGit {\n return simpleGit({ baseDir: cwd, binary: \"git\" });\n}\n\nexport async function isGitRepo(cwd: string = process.cwd()): Promise<boolean> {\n return await pathExists(join(cwd, \".git\"));\n}\n\nexport async function currentBranch(cwd: string = process.cwd()): Promise<string> {\n const result = await git(cwd).revparse([\"--abbrev-ref\", \"HEAD\"]);\n return result.trim();\n}\n\nexport async function addSubmodule(\n repoUrl: string,\n destPath: string,\n cwd: string = process.cwd(),\n): Promise<void> {\n await git(cwd).subModule([\"add\", repoUrl, destPath]);\n}\n\n// Checkout a tag inside a submodule. Used after `addSubmodule` to pin to a\n// specific team-ai-pack release.\nexport async function checkoutTagInSubmodule(\n submodulePath: string,\n tag: string,\n cwd: string = process.cwd(),\n): Promise<void> {\n const submoduleCwd = join(cwd, submodulePath);\n await git(submoduleCwd).fetch([\"--tags\"]);\n await git(submoduleCwd).checkout(tag);\n}\n\nexport async function listTags(cwd: string = process.cwd()): Promise<string[]> {\n const result = await git(cwd).tags();\n return result.all;\n}\n\nexport async function latestTag(cwd: string = process.cwd()): Promise<string | null> {\n const tags = await listTags(cwd);\n return tags.length > 0 ? (tags[tags.length - 1] ?? null) : null;\n}\n\nexport async function currentCommitSha(cwd: string = process.cwd()): Promise<string> {\n const result = await git(cwd).revparse([\"HEAD\"]);\n return result.trim();\n}\n\nexport async function workingTreeIsDirty(cwd: string = process.cwd()): Promise<boolean> {\n const status = await git(cwd).status();\n return !status.isClean();\n}\n","import { promises as fs } from \"node:fs\";\n// Scaffold the .claude/ directory tree inside a project after submodule add.\n// Used by `avatar init` for all three modes (internal/client/library).\n//\n// Spec source: Chapter 02 (folder map) + Chapter 09 Command 02 BEHAVIOR.\nimport { join } from \"node:path\";\nimport type { InitMode } from \"../types/config-schema.js\";\nimport { ensureDir, pathExists, writeTextAtomic } from \"./filesystem-helpers.js\";\nimport { type TemplateName, loadHook, renderTemplateByName } from \"./template-bundle-loader.js\";\n\n// Top-level paths Avatar will create or overwrite during init.\n// init.ts imports this for conflict detection so the list stays in sync.\n// `.gitmodules` is managed by git submodule add (not direct write), but it\n// gets modified during init so it's listed here for conflict warnings.\nexport const AVATAR_MANAGED_PATHS = [\".claude\", \"CLAUDE.md\", \".gitmodules\"] as const;\n\n// Rename `path` to `{path}.avatar-backup-{ISO timestamp}` if it exists.\n// Returns the backup path if created, null if source didn't exist.\n// Caller logs the backup so the user knows where their original file went.\n//\n// Collision handling: if the timestamped backup name already exists (two\n// backups within the same millisecond, or pre-existing leftover from prior\n// run), appends `-{counter}` until a free name is found. Prevents silent\n// overwrite of a previous backup.\nexport async function backupIfExists(path: string): Promise<string | null> {\n if (!(await pathExists(path))) return null;\n const ts = new Date().toISOString().replace(/[:.]/g, \"-\");\n const basePath = `${path}.avatar-backup-${ts}`;\n let backupPath = basePath;\n let counter = 1;\n while (await pathExists(backupPath)) {\n backupPath = `${basePath}-${counter}`;\n counter++;\n if (counter > 5) {\n throw new Error(`Could not find free backup name for ${path}`);\n }\n }\n await fs.rename(path, backupPath);\n return backupPath;\n}\n\n// Backup-aware atomic write. Used by all scaffolder write functions so user's\n// pre-existing files in `.claude/` are preserved when Avatar re-scaffolds.\n// Returns the backup path if a backup was created, null otherwise.\nasync function writeWithBackup(\n path: string,\n content: string,\n mode?: number,\n): Promise<string | null> {\n const backup = await backupIfExists(path);\n await writeTextAtomic(path, content, mode);\n return backup;\n}\n\n// Subdirectories Avatar creates inside .claude/ on init. `pack/` is added\n// separately by the submodule manager — listed here for reference only.\nconst CLAUDE_SUBDIRS = [\"project\", \"state\", \"_pending\", \"_backup\"] as const;\n\nconst PROJECT_KNOWLEDGE_TEMPLATES: TemplateName[] = [\n \"project/tech-stack.md\",\n \"project/conventions.md\",\n \"project/architecture.md\",\n \"project/domain.md\",\n \"project/gotchas.md\",\n];\n\nexport interface ScaffoldVariables {\n projectName: string;\n projectDescription: string;\n teamOwner: string;\n avatarVersion: string;\n packVersion: string;\n lastScan: string;\n mode: InitMode;\n}\n\n// Create .claude/{project,state,_pending,_backup}/ and a .gitkeep in each\n// so they survive a fresh checkout.\nexport async function createClaudeDirTree(projectRoot: string): Promise<void> {\n const claudeRoot = join(projectRoot, \".claude\");\n await ensureDir(claudeRoot);\n for (const sub of CLAUDE_SUBDIRS) {\n const dir = join(claudeRoot, sub);\n await ensureDir(dir);\n await writeTextAtomic(join(dir, \".gitkeep\"), \"\");\n }\n}\n\n// Render and write all 5 project knowledge files from templates.\n// All start with placeholder content — scanners fill them in later.\n// Returns list of backup paths created for pre-existing user files.\nexport async function writeProjectKnowledgeFiles(\n projectRoot: string,\n vars: ScaffoldVariables,\n): Promise<string[]> {\n const baseVars = {\n ...vars,\n primaryLanguage: \"(chưa scan)\",\n frameworks: \"(chưa scan)\",\n databases: \"(chưa scan)\",\n testStack: \"(chưa scan)\",\n buildStack: \"(chưa scan)\",\n toolVersions: \"(chưa scan)\",\n codeStyle: \"(chưa scan)\",\n namingConvention: \"(chưa scan)\",\n folderStructure: \"(chưa scan)\",\n commitConvention: \"(chưa scan)\",\n linterConfig: \"(chưa scan)\",\n architectureOverview: \"(chưa scan)\",\n moduleLayout: \"(chưa scan)\",\n dataFlow: \"(chưa scan)\",\n externalIntegrations: \"(chưa scan)\",\n deploymentTopology: \"(chưa scan)\",\n domainDescription: \"(chưa scan)\",\n coreEntities: \"(chưa scan)\",\n primaryUseCases: \"(chưa scan)\",\n domainGlossary: \"(chưa scan)\",\n };\n const backups: string[] = [];\n for (const tpl of PROJECT_KNOWLEDGE_TEMPLATES) {\n const content = await renderTemplateByName(tpl, baseVars);\n const relative = tpl.replace(/^project\\//, \"\");\n const outPath = join(projectRoot, \".claude\", \"project\", relative);\n const backup = await writeWithBackup(outPath, content);\n if (backup) backups.push(backup);\n }\n return backups;\n}\n\n// Write root CLAUDE.md from template — this is the entry point Claude Code reads.\n// Returns backup path if a pre-existing CLAUDE.md was renamed.\nexport async function writeRootClaudeMd(\n projectRoot: string,\n vars: ScaffoldVariables,\n): Promise<string | null> {\n const content = await renderTemplateByName(\"CLAUDE.md\", vars);\n return await writeWithBackup(join(projectRoot, \"CLAUDE.md\"), content);\n}\n\n// Write .claude/settings.json from template. Returns backup path if existed.\nexport async function writeProjectSettings(\n projectRoot: string,\n vars: ScaffoldVariables,\n): Promise<string | null> {\n const content = await renderTemplateByName(\"settings.json\", vars);\n return await writeWithBackup(join(projectRoot, \".claude\", \"settings.json\"), content);\n}\n\n// Append Avatar entries to project .gitignore (or create if missing).\n// Idempotent — skips if our marker line already present.\nexport async function appendGitignoreEntries(projectRoot: string): Promise<void> {\n const path = join(projectRoot, \".gitignore\");\n const tpl = await renderTemplateByName(\"gitignore\", {});\n const marker = \"# Avatar — git-ignored entries injected on `avatar init`\";\n\n let existing = \"\";\n if (await pathExists(path)) {\n existing = await fs.readFile(path, \"utf8\");\n if (existing.includes(marker)) return;\n }\n\n const separator = existing.endsWith(\"\\n\") || existing.length === 0 ? \"\" : \"\\n\";\n await writeTextAtomic(path, `${existing}${separator}\\n${tpl}`);\n}\n\n// Install git hooks into <gitDir>/hooks/. `gitDir` lets caller point at\n// src/.git/hooks (client mode pre-push) or workspace .git/hooks (post-merge).\nexport async function installGitHook(\n gitDir: string,\n hookName: \"post-merge\" | \"pre-push\",\n): Promise<void> {\n const content = await loadHook(hookName);\n const hooksDir = join(gitDir, \"hooks\");\n await ensureDir(hooksDir);\n const dest = join(hooksDir, hookName);\n await writeTextAtomic(dest, content, 0o755);\n}\n","// Resolve template files bundled inside the Avatar CLI package. tsup bundles\n// src/ into dist/index.js but does NOT bundle template files — they ship as\n// loose files via package.json `files` field (src/templates, src/hooks).\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { readText } from \"./filesystem-helpers.js\";\nimport { renderTemplate } from \"./mustache-template-engine.js\";\n\n// Templates ship in src/templates/ and src/hooks/ at runtime (see\n// package.json `files` field — both src/templates and src/hooks are included\n// in the npm tarball). Locate them by walking up from this file to the\n// package root (folder containing package.json), then descending to src/.\n//\n// This works identically from dist/index.js (npm-installed) and from\n// src/lib/*.ts (vitest/tsx) without path string sniffing.\nconst HERE = dirname(fileURLToPath(import.meta.url));\nconst PACKAGE_ROOT = findPackageRoot(HERE);\nconst TEMPLATES_ROOT = join(PACKAGE_ROOT, \"src\", \"templates\");\nconst HOOKS_ROOT = join(PACKAGE_ROOT, \"src\", \"hooks\");\n\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n while (true) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) {\n throw new Error(`Cannot locate package root from ${startDir}`);\n }\n dir = parent;\n }\n}\n\nexport type TemplateName =\n | \"CLAUDE.md\"\n | \"settings.json\"\n | \"gitignore\"\n | \"project/tech-stack.md\"\n | \"project/conventions.md\"\n | \"project/architecture.md\"\n | \"project/domain.md\"\n | \"project/gotchas.md\";\n\nexport type HookName = \"post-merge\" | \"pre-push\";\n\nexport async function loadTemplate(name: TemplateName): Promise<string> {\n return await readText(join(TEMPLATES_ROOT, `${name}.tpl`));\n}\n\nexport async function renderTemplateByName(\n name: TemplateName,\n variables: Record<string, string | number | undefined>,\n): Promise<string> {\n const source = await loadTemplate(name);\n return renderTemplate(source, variables);\n}\n\nexport async function loadHook(name: HookName): Promise<string> {\n return await readText(join(HOOKS_ROOT, `${name}.sh.tpl`));\n}\n","// Minimal mustache-style {{variable}} replacement engine. Avoids pulling in\n// full mustache dependency — Avatar templates only need flat variable\n// substitution, no loops or conditionals.\n//\n// Unknown variables left as-is, NOT replaced with empty string. This makes\n// missing variables visible in output for easier debugging.\n\nconst TEMPLATE_PATTERN = /\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\}\\}/g;\n\nexport function renderTemplate(\n source: string,\n variables: Record<string, string | number | undefined>,\n): string {\n return source.replace(TEMPLATE_PATTERN, (match, key: string) => {\n const value = variables[key];\n if (value === undefined) return match;\n return String(value);\n });\n}\n\n// Extract the variable names referenced by a template — useful for\n// scaffolding tests and validating that callers pass every required key.\nexport function extractVariables(source: string): string[] {\n const found = new Set<string>();\n for (const match of source.matchAll(TEMPLATE_PATTERN)) {\n if (match[1]) found.add(match[1]);\n }\n return Array.from(found).sort();\n}\n","// Read/write ~/.avatar/config.json (OAuth credentials) and ~/.avatar/state.json\n// (non-credential user state). Validates with Zod, enforces chmod 600 on config.\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n type UserConfig,\n type UserState,\n userConfigSchema,\n userStateSchema,\n} from \"../types/config-schema.js\";\nimport { ensureDir, pathExists, readJson, writeJsonAtomic } from \"./filesystem-helpers.js\";\n\nexport const AVATAR_HOME = join(homedir(), \".avatar\");\nexport const USER_CONFIG_PATH = join(AVATAR_HOME, \"config.json\");\nexport const USER_STATE_PATH = join(AVATAR_HOME, \"state.json\");\nexport const AUDIT_LOG_PATH = join(AVATAR_HOME, \"audit.log\");\nexport const BACKUPS_DIR = join(AVATAR_HOME, \"backups\");\n\n// chmod 600 — owner-only read/write. Matches spec for credential files.\nconst SECRET_FILE_MODE = 0o600;\n\nexport async function ensureAvatarHome(): Promise<void> {\n await ensureDir(AVATAR_HOME);\n}\n\nexport async function readUserConfig(): Promise<UserConfig | null> {\n if (!(await pathExists(USER_CONFIG_PATH))) return null;\n const raw = await readJson<unknown>(USER_CONFIG_PATH);\n const parsed = userConfigSchema.safeParse(raw);\n if (!parsed.success) return null;\n return parsed.data;\n}\n\nexport async function writeUserConfig(config: UserConfig): Promise<void> {\n await ensureAvatarHome();\n await writeJsonAtomic(USER_CONFIG_PATH, config, SECRET_FILE_MODE);\n}\n\nexport async function clearUserConfig(): Promise<void> {\n if (await pathExists(USER_CONFIG_PATH)) {\n const { promises: fs } = await import(\"node:fs\");\n await fs.unlink(USER_CONFIG_PATH);\n }\n}\n\nexport async function readUserState(): Promise<UserState> {\n if (!(await pathExists(USER_STATE_PATH))) {\n return userStateSchema.parse({});\n }\n const raw = await readJson<unknown>(USER_STATE_PATH);\n const parsed = userStateSchema.safeParse(raw);\n if (!parsed.success) return userStateSchema.parse({});\n return parsed.data;\n}\n\nexport async function writeUserState(state: UserState): Promise<void> {\n await ensureAvatarHome();\n await writeJsonAtomic(USER_STATE_PATH, state);\n}\n\n// Token is considered expired if it would expire in the next 60 seconds.\n// 60s buffer accounts for slow network round-trip on the upcoming request.\nexport function isTokenExpired(config: UserConfig): boolean {\n const expiresAt = Date.parse(config.expires_at);\n return Number.isNaN(expiresAt) || expiresAt - Date.now() < 60_000;\n}\n","// Zod schemas + inferred TypeScript types for all on-disk Avatar config files.\n// Centralised so commands import from one place and validation matches storage.\nimport { z } from \"zod\";\n\n// ~/.avatar/config.json — OAuth credentials after `avatar login`.\n// chmod 600 enforced at write site.\nexport const userConfigSchema = z.object({\n email: z.string().email(),\n name: z.string(),\n access_token: z.string().min(1),\n refresh_token: z.string().min(1),\n expires_at: z.string().datetime(),\n id_token: z.string().min(1),\n});\nexport type UserConfig = z.infer<typeof userConfigSchema>;\n\n// ~/.avatar/state.json — non-credential user state (tool install records,\n// allowed-paths chosen for filesystem MCP, etc).\nexport const userStateSchema = z.object({\n installed_tools: z\n .record(\n z.string(),\n z.object({\n version: z.string().optional(),\n installed_at: z.string().datetime(),\n install_method: z.string(),\n }),\n )\n .default({}),\n tool_inputs: z.record(z.string(), z.unknown()).default({}),\n});\nexport type UserState = z.infer<typeof userStateSchema>;\n\n// .claude/settings.json — per-project Claude Code settings emitted by `avatar init`.\nexport const projectSettingsSchema = z.object({\n allowedTools: z.array(z.string()),\n hooks: z\n .object({\n PostToolUse: z.array(z.unknown()).optional(),\n })\n .partial()\n .optional(),\n env: z.record(z.string(), z.string()).default({}),\n});\nexport type ProjectSettings = z.infer<typeof projectSettingsSchema>;\n\n// Init mode — determines workspace topology (Chapter 02 + Chapter 07 spec).\nexport const initModeSchema = z.enum([\"internal\", \"client\", \"library\"]);\nexport type InitMode = z.infer<typeof initModeSchema>;\n","// `avatar init` — Command 02 spec (v1.1 redesign).\n//\n// Bỏ khái niệm --mode internal/client/library. Thay bằng wizard 3-câu hỏi tự\n// nhận diện tình trạng dự án:\n// 1. Đã có repo git remote (URL có sẵn) → flow=existing-remote\n// 2. Đã có folder code local → flow=existing-folder\n// 3. Dự án mới hoàn toàn → flow=new-project\n//\n// Mọi flow đều scaffold workspace tách biệt (không còn mode internal). Avatar\n// luôn check + tự cài gh CLI nếu thiếu, auto-bootstrap git cho folder chưa\n// init, auto-detect .gitignore theo tech stack.\n\nimport { basename, join, relative, resolve } from \"node:path\";\nimport { confirm, input, select } from \"@inquirer/prompts\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { appendAuditEntry } from \"../lib/audit-log-appender.js\";\nimport { printAvatarBanner } from \"../lib/avatar-ascii-banner.js\";\nimport { checkFolderHasGit } from \"../lib/check-folder-has-git.js\";\nimport { createGithubRemoteFromFolder } from \"../lib/create-github-remote-from-folder.js\";\nimport { createWorkspaceRemoteViaGh } from \"../lib/create-workspace-remote-via-gh.js\";\nimport { ensureDir } from \"../lib/filesystem-helpers.js\";\nimport { ensureGitHubReady } from \"../lib/git-auth-and-install-orchestrator.js\";\nimport { bootstrapGitInFolder } from \"../lib/git-bootstrap-orchestrator.js\";\nimport { git } from \"../lib/git-operations.js\";\nimport {\n appendGitignoreEntries,\n createClaudeDirTree,\n installGitHook,\n writeProjectKnowledgeFiles,\n writeProjectSettings,\n writeRootClaudeMd,\n} from \"../lib/project-tree-scaffolder.js\";\nimport { addTeamPackSubmodule } from \"../lib/team-pack-submodule-manager.js\";\nimport { chalk, log, spinner } from \"../lib/terminal-logger.js\";\nimport { isTokenExpired, readUserConfig } from \"../lib/user-config-store.js\";\nimport type { RepoVisibility } from \"../lib/validate-repo-name-and-visibility.js\";\nimport {\n findAlternativeWorkspaceName,\n isEmptyOrMissing,\n} from \"./init-conflict-detection-helpers.js\";\nimport { buildScaffoldVariables, inferWorkspaceName } from \"./init-scaffold-variable-builders.js\";\n\n// 3 flow values + deprecated legacy \"mode\" alias.\ntype ProjectStatus = \"existing-remote\" | \"existing-folder\" | \"new-project\";\n\ninterface InitOptions {\n // New v1.1 flags\n projectStatus?: ProjectStatus;\n folderPath?: string;\n createRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n // Carried over\n skipScan?: boolean;\n skipTeamPack?: boolean;\n packVersion?: string;\n clientRepo?: string; // reused: URL khi projectStatus=existing-remote\n workspaceName?: string;\n workspaceParent?: string;\n force?: boolean;\n teamOwner?: string;\n description?: string;\n yes?: boolean;\n commit?: boolean; // commander tự set false khi user pass --no-commit\n workspaceRemote?: boolean; // tạo remote cho workspace root (--workspace-remote)\n // Legacy (deprecated)\n mode?: string;\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Khởi tạo Avatar — 3 flow tự nhận diện (repo / folder / new)\")\n .option(\"--project-status <val>\", \"existing-remote | existing-folder | new-project\")\n .option(\"--folder-path <path>\", \"Đường dẫn folder hiện có (flow existing-folder)\")\n .option(\"--create-remote\", \"Force tạo remote qua gh (flow existing-folder hoặc new-project)\")\n .option(\"--repo-visibility <val>\", \"private (mặc định) | public\")\n .option(\"--repo-org <name>\", \"GitHub org/owner cho repo mới\")\n .option(\"--client-repo <url>\", \"URL git remote (flow existing-remote)\")\n .option(\"--workspace-name <name>\", \"Tên workspace\")\n .option(\"--workspace-parent <path>\", \"Thư mục cha tạo workspace (mặc định . — CWD)\")\n .option(\"--pack-version <tag>\", \"Pin team-ai-pack vào tag cụ thể\")\n .option(\"--team-owner <email>\", \"Email team owner (bỏ qua prompt)\")\n .option(\"--description <text>\", \"Mô tả 1 dòng của dự án\")\n .option(\"--skip-scan\", \"Bỏ qua project-scanner sau scaffold\")\n .option(\"--skip-team-pack\", \"Bỏ qua submodule team-ai-pack (test mode)\")\n .option(\"--force\", \"Bỏ qua prompt khi workspace path đã tồn tại\")\n .option(\"--yes\", \"Auto-confirm tất cả prompt\")\n .option(\"--no-commit\", \"Skip commit workspace initial state (mặc định LUÔN commit)\")\n .option(\"--workspace-remote\", \"Tạo GitHub remote cho workspace root (default: prompt)\")\n .option(\"--mode <mode>\", \"[DEPRECATED] Dùng --project-status thay thế\")\n .action(async (opts: InitOptions) => {\n try {\n await runInit(opts);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runInit(opts: InitOptions): Promise<void> {\n if (!opts.yes) printAvatarBanner({ tagline: \"Khởi tạo Avatar trong dự án của bạn\" });\n\n if (opts.mode) {\n log.warn(\"Flag --mode đã deprecated từ v1.1. Dùng --project-status thay thế.\");\n }\n\n const userConfig = await readUserConfig();\n if (!userConfig || isTokenExpired(userConfig)) {\n log.error(\"Chưa đăng nhập hoặc token hết hạn. Chạy 'avatar login' trước.\");\n process.exit(1);\n }\n\n const status = opts.projectStatus ?? (await promptProjectStatus());\n\n switch (status) {\n case \"existing-remote\":\n await runInitFromExistingRemote(opts, userConfig.email);\n break;\n case \"existing-folder\":\n await runInitFromExistingFolder(opts, userConfig.email);\n break;\n case \"new-project\":\n await runInitFromScratch(opts, userConfig.email);\n break;\n }\n}\n\nasync function promptProjectStatus(): Promise<ProjectStatus> {\n return (await select({\n message: \"Tình trạng dự án của bạn?\",\n choices: [\n { name: \"1. Đã có repo git remote (URL có sẵn)\", value: \"existing-remote\" as const },\n { name: \"2. Đã có folder code local\", value: \"existing-folder\" as const },\n { name: \"3. Dự án mới hoàn toàn\", value: \"new-project\" as const },\n ],\n })) as ProjectStatus;\n}\n\n// ─── FLOW 1: EXISTING REMOTE ────────────────────────────────────────────────\nasync function runInitFromExistingRemote(opts: InitOptions, ownerEmail: string): Promise<void> {\n const remoteUrl =\n opts.clientRepo ??\n (await input({\n message: \"URL git của repo:\",\n validate: (v) => (v.length > 0 ? true : \"URL bắt buộc\"),\n }));\n\n await ensureGitHubReady(remoteUrl);\n\n const teamOwner = opts.teamOwner ?? (await promptTeamOwner(ownerEmail));\n const inferredName = inferWorkspaceName(remoteUrl);\n const workspaceName =\n opts.workspaceName ?? (await input({ message: \"Tên workspace:\", default: inferredName }));\n const workspaceParent = resolve(opts.workspaceParent ?? \".\");\n const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);\n\n await scaffoldWorkspaceWithSrcSubmodule({\n workspacePath,\n workspaceName,\n srcRemoteUrl: remoteUrl,\n teamOwner,\n skipTeamPack: opts.skipTeamPack,\n description: opts.description ?? `Avatar workspace cho ${remoteUrl}`,\n packVersion: opts.packVersion,\n autoYes: opts.yes,\n skipCommit: opts.commit === false,\n createWorkspaceRemote: opts.workspaceRemote,\n repoVisibility: opts.repoVisibility,\n repoOrg: opts.repoOrg,\n flow: \"existing-remote\",\n });\n}\n\n// ─── FLOW 2: EXISTING FOLDER ────────────────────────────────────────────────\nasync function runInitFromExistingFolder(opts: InitOptions, ownerEmail: string): Promise<void> {\n const folderPath = resolve(\n opts.folderPath ??\n (await input({\n message: \"Đường dẫn folder hiện có:\",\n validate: (v) => (v.length > 0 ? true : \"Path bắt buộc\"),\n })),\n );\n\n // Bootstrap git nếu chưa có (đồng thời ghi .gitignore Avatar block).\n await bootstrapGitInFolder(folderPath);\n\n // Check remote origin. Có → dùng luôn. Chưa có → hỏi tạo mới (default Có).\n const remoteUrl = await getOrCreateOriginRemote(folderPath, opts);\n\n const teamOwner = opts.teamOwner ?? (await promptTeamOwner(ownerEmail));\n const inferredName = opts.workspaceName ?? `${basename(folderPath)}-avatar-workspace`;\n const workspaceName =\n opts.workspaceName ?? (await input({ message: \"Tên workspace:\", default: inferredName }));\n const workspaceParent = resolve(opts.workspaceParent ?? \".\");\n const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);\n\n await scaffoldWorkspaceWithSrcSubmodule({\n workspacePath,\n workspaceName,\n srcRemoteUrl: remoteUrl ?? folderPath, // fallback local path nếu user từ chối tạo remote\n teamOwner,\n skipTeamPack: opts.skipTeamPack,\n description: opts.description ?? `Avatar workspace cho folder ${folderPath}`,\n packVersion: opts.packVersion,\n autoYes: opts.yes,\n skipCommit: opts.commit === false,\n createWorkspaceRemote: opts.workspaceRemote,\n repoVisibility: opts.repoVisibility,\n repoOrg: opts.repoOrg,\n flow: \"existing-folder\",\n });\n}\n\n// ─── FLOW 3: NEW PROJECT ────────────────────────────────────────────────────\nasync function runInitFromScratch(opts: InitOptions, ownerEmail: string): Promise<void> {\n await ensureGitHubReady();\n\n const projectName =\n opts.workspaceName ??\n (await input({\n message: \"Tên dự án:\",\n validate: (v) => (v.length > 0 ? true : \"Tên bắt buộc\"),\n }));\n const visibility = (opts.repoVisibility ??\n (await select({\n message: \"Visibility?\",\n choices: [\n { name: \"private (mặc định)\", value: \"private\" as const },\n { name: \"public\", value: \"public\" as const },\n ],\n }))) as RepoVisibility;\n\n const teamOwner = opts.teamOwner ?? (await promptTeamOwner(ownerEmail));\n const workspaceParent = resolve(opts.workspaceParent ?? \".\");\n const workspacePath = await resolveWorkspacePath(workspaceParent, projectName, opts.force);\n const srcPath = join(workspacePath, \"src\");\n\n // Tạo workspace dir + src/ rỗng + bootstrap git trong src/.\n await ensureDir(workspacePath);\n await ensureDir(srcPath);\n await bootstrapGitInFolder(srcPath);\n\n // Tạo remote GitHub + push initial commit.\n const urls = createGithubRemoteFromFolder({\n folder: srcPath,\n name: projectName,\n visibility,\n org: opts.repoOrg,\n });\n\n // Workspace setup: init git, submodule add cho src/.\n await git(workspacePath).init();\n const sp = spinner(\n opts.skipTeamPack ? \"Add submodule src/...\" : \"Add submodule src/ + team-ai-pack...\",\n );\n try {\n await git(workspacePath).subModule([\"add\", urls.sshUrl, \"src\"]);\n let pinnedTag = \"HEAD\";\n if (!opts.skipTeamPack) {\n const result = await addTeamPackSubmodule(workspacePath, opts.packVersion);\n pinnedTag = result.pinnedTag ?? \"HEAD\";\n sp.succeed(`Pin team-ai-pack vào ${pinnedTag}`);\n } else {\n sp.succeed(\"Skip team-ai-pack (--skip-team-pack)\");\n }\n await finalizeWorkspaceScaffold({\n workspacePath,\n workspaceName: projectName,\n teamOwner,\n description: opts.description ?? `Dự án mới: ${projectName}`,\n packVersion: pinnedTag,\n autoYes: opts.yes,\n skipCommit: opts.commit === false,\n createWorkspaceRemote: opts.workspaceRemote,\n repoVisibility: opts.repoVisibility,\n repoOrg: opts.repoOrg,\n flow: \"new-project\",\n });\n } catch (err) {\n sp.fail(\"Init workspace thất bại\");\n throw err;\n }\n}\n\n// ─── HELPERS ────────────────────────────────────────────────────────────────\n\n// Check origin remote của folder; nếu chưa có thì hỏi tạo (default Có) → gh repo create.\n// Trả về URL remote nếu có, undefined nếu user từ chối (caller fallback local path).\nasync function getOrCreateOriginRemote(\n folderPath: string,\n opts: InitOptions,\n): Promise<string | undefined> {\n const remotes = await git(folderPath).getRemotes(true);\n const origin = remotes.find((r) => r.name === \"origin\");\n if (origin?.refs.push) {\n log.success(`Folder đã có remote origin: ${origin.refs.push}`);\n return origin.refs.push;\n }\n\n const shouldCreate =\n opts.createRemote ??\n (await confirm({\n message: \"Folder chưa có remote. Tạo GitHub repo ngay để share team?\",\n default: true,\n }));\n if (!shouldCreate) {\n log.warn(\"Tiếp tục với local path. Workspace chỉ chạy được trên máy bạn.\");\n return undefined;\n }\n\n await ensureGitHubReady();\n const visibility = (opts.repoVisibility ??\n (await select({\n message: \"Visibility?\",\n choices: [\n { name: \"private (mặc định)\", value: \"private\" as const },\n { name: \"public\", value: \"public\" as const },\n ],\n }))) as RepoVisibility;\n const repoName = await input({\n message: \"Tên repo:\",\n default: basename(folderPath),\n });\n const urls = createGithubRemoteFromFolder({\n folder: folderPath,\n name: repoName,\n visibility,\n org: opts.repoOrg,\n });\n return urls.sshUrl;\n}\n\n// Scaffold workspace dùng cho flow 1 + flow 2: workspace = parent của src/.\n// src/ là submodule trỏ tới remote URL hoặc local path.\nasync function scaffoldWorkspaceWithSrcSubmodule(args: {\n workspacePath: string;\n workspaceName: string;\n srcRemoteUrl: string;\n teamOwner: string;\n description: string;\n packVersion?: string;\n autoYes?: boolean;\n skipCommit?: boolean;\n createWorkspaceRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n skipTeamPack?: boolean;\n flow: ProjectStatus;\n}): Promise<void> {\n await ensureDir(args.workspacePath);\n await git(args.workspacePath).init();\n\n const sp = spinner(\n args.skipTeamPack ? \"Add submodule src/...\" : \"Add submodule src/ + team-ai-pack...\",\n );\n try {\n await git(args.workspacePath).subModule([\"add\", args.srcRemoteUrl, \"src\"]);\n let pinnedTag = \"HEAD\";\n if (!args.skipTeamPack) {\n const result = await addTeamPackSubmodule(args.workspacePath, args.packVersion);\n pinnedTag = result.pinnedTag ?? \"HEAD\";\n sp.succeed(`Pin team-ai-pack vào ${pinnedTag}`);\n } else {\n sp.succeed(\"Skip team-ai-pack (--skip-team-pack)\");\n }\n\n await finalizeWorkspaceScaffold({\n workspacePath: args.workspacePath,\n workspaceName: args.workspaceName,\n teamOwner: args.teamOwner,\n description: args.description,\n packVersion: pinnedTag,\n autoYes: args.autoYes,\n skipCommit: args.skipCommit,\n createWorkspaceRemote: args.createWorkspaceRemote,\n repoVisibility: args.repoVisibility,\n repoOrg: args.repoOrg,\n flow: args.flow,\n });\n } catch (err) {\n sp.fail(\"Init workspace thất bại\");\n throw err;\n }\n}\n\n// Common scaffold step sau khi src/ + team-ai-pack đã add xong.\nasync function finalizeWorkspaceScaffold(args: {\n workspacePath: string;\n workspaceName: string;\n teamOwner: string;\n description: string;\n packVersion: string;\n autoYes?: boolean;\n skipCommit?: boolean;\n createWorkspaceRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n flow: ProjectStatus;\n}): Promise<void> {\n // Mode \"client\" được dùng trong scaffold-variable builder cũ — giữ giá trị\n // này để compatible với template hiện tại. Sẽ rename trong release sau.\n const vars = buildScaffoldVariables({\n projectName: args.workspaceName,\n projectDescription: args.description,\n teamOwner: args.teamOwner,\n packVersion: args.packVersion,\n mode: \"client\",\n });\n\n await createClaudeDirTree(args.workspacePath);\n await writeProjectKnowledgeFiles(args.workspacePath, vars);\n await writeRootClaudeMd(args.workspacePath, vars);\n await writeProjectSettings(args.workspacePath, vars);\n await appendGitignoreEntries(args.workspacePath);\n await ensureDir(join(args.workspacePath, \"notes\"));\n await ensureDir(join(args.workspacePath, \"scripts\"));\n\n await installGitHook(join(args.workspacePath, \".git\"), \"post-merge\");\n await installGitHook(join(args.workspacePath, \".git\", \"modules\", \"src\"), \"pre-push\");\n log.success(\"Cài post-merge (workspace) + pre-push (src/)\");\n\n await appendAuditEntry(\"init\", `flow=${args.flow},workspace=${args.workspaceName}`);\n await maybeCommitWorkspace(args.workspacePath, args.skipCommit);\n await maybeCreateWorkspaceRemote(args);\n printInitSuccessBox(args.workspacePath, args.flow);\n}\n\n// Hỏi/tạo remote GitHub cho workspace root. Chỉ chạy được khi đã commit\n// (gh repo create --push cần ít nhất 1 commit). Nếu user skip commit hoặc\n// từ chối tạo, workspace local-only — vẫn dùng được nhưng không share team.\nasync function maybeCreateWorkspaceRemote(args: {\n workspacePath: string;\n workspaceName: string;\n autoYes?: boolean;\n skipCommit?: boolean;\n createWorkspaceRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n}): Promise<void> {\n // Skip nếu chưa có commit (gh repo create --push sẽ fail).\n if (args.skipCommit) {\n log.dim(\"Skip workspace remote (chưa commit). Setup sau qua: gh repo create ...\");\n return;\n }\n\n // Resolve từ flag hoặc prompt.\n let shouldCreate = args.createWorkspaceRemote;\n if (shouldCreate === undefined) {\n if (args.autoYes) return; // CI mode: default skip để không hỏi\n shouldCreate = await confirm({\n message: \"Tạo remote GitHub cho workspace để share team? (Avatar state)\",\n default: false,\n });\n }\n if (!shouldCreate) return;\n\n const visibility = ((args.repoVisibility as \"private\" | \"public\" | undefined) ??\n (args.autoYes\n ? \"private\"\n : await select({\n message: \"Workspace visibility?\",\n choices: [\n { name: \"private (mặc định, an toàn)\", value: \"private\" as const },\n { name: \"public\", value: \"public\" as const },\n ],\n }))) as \"private\" | \"public\";\n\n try {\n await createWorkspaceRemoteViaGh({\n workspacePath: args.workspacePath,\n workspaceName: args.workspaceName,\n visibility,\n org: args.repoOrg,\n });\n } catch (err) {\n log.warn(err instanceof Error ? err.message : String(err));\n log.warn(\"Workspace vẫn sẵn sàng local-only. Setup remote sau khi cần.\");\n }\n}\n\n// ─── shared utilities (giữ từ v1.0.1, chỉ đổi signature mode → flow) ───────\n\nexport async function resolveWorkspacePath(\n parent: string,\n desiredName: string,\n force?: boolean,\n): Promise<string> {\n const desired = join(parent, desiredName);\n if (await isEmptyOrMissing(desired)) return desired;\n\n const alternative = await findAlternativeWorkspaceName(parent, desiredName);\n if (!alternative) {\n throw new Error(`Không tìm được workspace path khả dụng trong ${parent}`);\n }\n\n log.warn(`Workspace path \"${desired}\" đã có nội dung.`);\n if (force) {\n log.info(`--force: dùng ${alternative}`);\n return alternative;\n }\n const useAlt = await confirm({ message: `Dùng \"${alternative}\" thay thế?`, default: true });\n if (!useAlt) throw new Error(\"Hủy init. Chạy lại với --workspace-name khác.\");\n return alternative;\n}\n\nasync function promptTeamOwner(currentUserEmail: string): Promise<string> {\n return await input({ message: \"Team owner email:\", default: currentUserEmail });\n}\n\nasync function maybeCommitWorkspace(workspacePath: string, skipCommit?: boolean): Promise<void> {\n // Mặc định LUÔN commit — giữ workspace ở git state hợp lệ (có baseline).\n // User muốn review trước commit thì pass --no-commit để skip.\n if (skipCommit) {\n log.warn(\"Skip commit (--no-commit). Chạy 'git status' + commit thủ công sau.\");\n return;\n }\n const g = git(workspacePath);\n await g.add([\"CLAUDE.md\", \".claude/\", \".gitignore\", \".gitmodules\", \"notes/\", \"scripts/\"]);\n await g.commit(\"chore: initialize Avatar workspace\");\n log.success(\"Đã commit workspace\");\n}\n\nfunction printInitSuccessBox(rootPath: string, flow: ProjectStatus): void {\n const lines: string[] = [\n `${chalk.green(\"✓\")} Workspace sẵn sàng: ${relative(process.cwd(), rootPath) || rootPath}`,\n ` ${chalk.dim(`(flow: ${flow})`)}`,\n \"\",\n ` ${chalk.cyan(`cd ${rootPath}`)}`,\n ` ${chalk.cyan(\"claude\")} Mở Claude Code ở workspace root`,\n \"\",\n ` ${chalk.cyan(\"avatar commit --src\")} Commit code lên remote src`,\n ` ${chalk.cyan(\"avatar commit --avatar\")} Commit Avatar state`,\n ` ${chalk.cyan(\"avatar sync\")} Pull team-ai-pack mới`,\n ` ${chalk.cyan(\"avatar uninstall\")} Gỡ Avatar (giữ code)`,\n ];\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n","// Append-only audit log at ~/.avatar/audit.log. Records sensitive actions\n// (secrets set/rm, tool install/remove) WITHOUT logging secret values.\n// Used by `avatar doctor` to surface recent activity.\nimport { promises as fs } from \"node:fs\";\nimport { AUDIT_LOG_PATH, ensureAvatarHome } from \"./user-config-store.js\";\n\nexport type AuditAction =\n | \"login\"\n | \"login_reset\"\n | \"logout\"\n | \"secret_set\"\n | \"secret_rm\"\n | \"tool_install\"\n | \"tool_remove\"\n | \"init\"\n | \"sync\"\n | \"restore\";\n\nexport interface AuditEntry {\n timestamp: string;\n action: AuditAction;\n detail?: string;\n}\n\nexport async function appendAuditEntry(action: AuditAction, detail?: string): Promise<void> {\n await ensureAvatarHome();\n const entry: AuditEntry = {\n timestamp: new Date().toISOString(),\n action,\n ...(detail ? { detail } : {}),\n };\n const line = `${JSON.stringify(entry)}\\n`;\n await fs.appendFile(AUDIT_LOG_PATH, line, \"utf8\");\n}\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","// Wrapper around `gh repo create <org>/<name> --<vis> --source=<folder>\n// --remote=origin --push`. Stream stdio để user thấy gh prompt nếu có.\nimport { spawnSync } from \"node:child_process\";\nimport type { RepoVisibility } from \"./validate-repo-name-and-visibility.js\";\n\nexport class RepoAlreadyExistsError extends Error {\n constructor(fullName: string) {\n super(`Repo \"${fullName}\" đã tồn tại trên GitHub. Đổi tên hoặc xóa repo cũ.`);\n this.name = \"RepoAlreadyExistsError\";\n }\n}\n\nexport interface ExecuteGhRepoCreateInput {\n folder: string;\n org: string;\n name: string;\n visibility: RepoVisibility;\n}\n\nexport interface ExecuteGhRepoCreateOutput {\n sshUrl: string;\n httpsUrl: string;\n}\n\nexport function executeGhRepoCreate(input: ExecuteGhRepoCreateInput): ExecuteGhRepoCreateOutput {\n const fullName = `${input.org}/${input.name}`;\n const args = [\n \"repo\",\n \"create\",\n fullName,\n `--${input.visibility}`,\n \"--source\",\n input.folder,\n \"--remote\",\n \"origin\",\n \"--push\",\n ];\n const r = spawnSync(\"gh\", args, { stdio: \"inherit\" });\n if (r.status !== 0) {\n // gh thường in \"GraphQL: Name already exists\" cho duplicate. Không parse\n // stdout (vì inherit) — surface generic error, user sẽ thấy stderr của gh.\n if (r.status === 1) {\n throw new RepoAlreadyExistsError(fullName);\n }\n throw new Error(`gh repo create thất bại (exit ${r.status})`);\n }\n return {\n sshUrl: `git@github.com:${fullName}.git`,\n httpsUrl: `https://github.com/${fullName}.git`,\n };\n}\n","// Lấy GitHub login mặc định của user qua `gh api user --jq .login`.\n// Dùng làm default org khi user không truyền --repo-org.\nimport { spawnSync } from \"node:child_process\";\n\nexport function resolveGithubUsernameDefault(): string {\n const r = spawnSync(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n if (r.status !== 0) {\n throw new Error(`Không lấy được GitHub username: ${r.stderr?.trim()}`);\n }\n return r.stdout.trim();\n}\n","// Validate repo name + visibility trước khi gọi `gh repo create`. Fail-fast với\n// thông báo Vietnamese rõ ràng. GitHub repo name spec: alphanumeric, dash,\n// underscore, dot. 1-100 chars.\nconst REPO_NAME_REGEX = /^[a-zA-Z0-9._-]{1,100}$/;\n\nexport type RepoVisibility = \"private\" | \"public\";\n\nexport class InvalidRepoNameError extends Error {\n constructor(name: string) {\n super(\n `Tên repo \"${name}\" không hợp lệ. Chỉ dùng chữ/số/dấu chấm/gạch/underscore, dài 1-100 ký tự.`,\n );\n this.name = \"InvalidRepoNameError\";\n }\n}\n\nexport function validateRepoName(name: string): void {\n if (!REPO_NAME_REGEX.test(name)) {\n throw new InvalidRepoNameError(name);\n }\n}\n\nexport function validateRepoVisibility(v: string): asserts v is RepoVisibility {\n if (v !== \"private\" && v !== \"public\") {\n throw new Error(`Visibility phải là \"private\" hoặc \"public\", nhận: \"${v}\"`);\n }\n}\n","// Orchestrator phase 4: validate input → gọi gh repo create → return URLs.\n// Caller chịu trách nhiệm đảm bảo gh đã auth (gọi ensureGitHubReady trước).\nimport { type ExecuteGhRepoCreateOutput, executeGhRepoCreate } from \"./execute-gh-repo-create.js\";\nimport { resolveGithubUsernameDefault } from \"./resolve-github-username-default.js\";\nimport { log } from \"./terminal-logger.js\";\nimport {\n type RepoVisibility,\n validateRepoName,\n validateRepoVisibility,\n} from \"./validate-repo-name-and-visibility.js\";\n\nexport interface CreateGithubRemoteInput {\n folder: string;\n name: string;\n visibility: RepoVisibility;\n org?: string; // mặc định = GitHub login của user\n}\n\nexport function createGithubRemoteFromFolder(\n input: CreateGithubRemoteInput,\n): ExecuteGhRepoCreateOutput {\n validateRepoName(input.name);\n validateRepoVisibility(input.visibility);\n\n const org = input.org ?? resolveGithubUsernameDefault();\n log.info(`Tạo GitHub repo ${org}/${input.name} (${input.visibility})...`);\n\n const urls = executeGhRepoCreate({\n folder: input.folder,\n org,\n name: input.name,\n visibility: input.visibility,\n });\n\n log.success(`Đã tạo: ${urls.sshUrl}`);\n return urls;\n}\n","// Tạo remote GitHub cho workspace + push initial commit. Khác với\n// create-github-remote-from-folder (dành cho src/): hàm này dành cho workspace\n// root (đã commit Avatar state) và setup tracking branch.\n//\n// Workspace remote là OPTIONAL: chỉ cần khi team muốn share Avatar state\n// (knowledge, hooks, settings) qua git. Workspace local-only vẫn dùng được cho\n// 1 dev cá nhân, nhưng không sync được cross-machine.\nimport { spawnSync } from \"node:child_process\";\nimport { ensureGitHubReady } from \"./git-auth-and-install-orchestrator.js\";\nimport { resolveGithubUsernameDefault } from \"./resolve-github-username-default.js\";\nimport { log } from \"./terminal-logger.js\";\nimport {\n type RepoVisibility,\n validateRepoName,\n validateRepoVisibility,\n} from \"./validate-repo-name-and-visibility.js\";\n\nexport interface CreateWorkspaceRemoteInput {\n workspacePath: string;\n workspaceName: string;\n visibility: RepoVisibility;\n org?: string;\n}\n\nexport interface CreateWorkspaceRemoteOutput {\n sshUrl: string;\n httpsUrl: string;\n}\n\n// Idempotent: nếu workspace đã có remote `origin`, skip. Nếu repo trên GitHub\n// đã tồn tại nhưng workspace chưa có remote, thử add remote + push.\nexport async function createWorkspaceRemoteViaGh(\n input: CreateWorkspaceRemoteInput,\n): Promise<CreateWorkspaceRemoteOutput> {\n validateRepoName(input.workspaceName);\n validateRepoVisibility(input.visibility);\n\n await ensureGitHubReady();\n const org = input.org ?? resolveGithubUsernameDefault();\n\n const fullName = `${org}/${input.workspaceName}`;\n log.info(`Tạo GitHub repo cho workspace: ${fullName} (${input.visibility})...`);\n\n // gh repo create --source=workspace --remote=origin --push tạo repo + add\n // remote `origin` + push branch hiện tại (main). Auto-track origin/main.\n const r = spawnSync(\n \"gh\",\n [\n \"repo\",\n \"create\",\n fullName,\n `--${input.visibility}`,\n \"--source\",\n input.workspacePath,\n \"--remote\",\n \"origin\",\n \"--push\",\n ],\n { stdio: \"inherit\" },\n );\n\n if (r.status !== 0) {\n throw new Error(\n `Tạo workspace remote thất bại (exit ${r.status}). Workspace vẫn dùng được local. Setup remote sau qua: gh repo create ${fullName} --${input.visibility} --source=. --remote=origin --push`,\n );\n }\n\n const sshUrl = `git@github.com:${fullName}.git`;\n const httpsUrl = `https://github.com/${fullName}.git`;\n log.success(`Workspace remote: ${sshUrl}`);\n return { sshUrl, httpsUrl };\n}\n","// Kiểm tra gh CLI đã login chưa. `gh auth status` exit 0 = OK.\n// Không parse stdout vì format thay đổi giữa các bản gh.\nimport { spawnSync } from \"node:child_process\";\n\nexport type GhAuthState = \"not-installed\" | \"not-authenticated\" | \"authenticated\";\n\nexport function checkGhCliAuthStatus(): GhAuthState {\n // Probe binary trước. spawnSync với gh không tồn tại trả ENOENT.\n const r = spawnSync(\"gh\", [\"auth\", \"status\"], { stdio: \"ignore\" });\n if (r.error && (r.error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return \"not-installed\";\n }\n return r.status === 0 ? \"authenticated\" : \"not-authenticated\";\n}\n","// Detect package manager để cài binary hệ thống (gh CLI). Order matters:\n// brew (macOS preferred) → winget (Windows) → apt/dnf/pacman (Linux distros).\n// Returns null nếu không tìm được PM nào — caller phải fail-fast.\nimport { spawnSync } from \"node:child_process\";\nimport { detectHostPlatform } from \"./detect-host-platform.js\";\n\nexport type PackageManager = \"brew\" | \"apt\" | \"dnf\" | \"pacman\" | \"winget\";\n\n// Probe binary có trong PATH không. Dùng `command -v` (POSIX) hoặc `where` (Win).\nfunction hasBinary(name: string): boolean {\n const platform = detectHostPlatform();\n const probe = platform === \"win32\" ? \"where\" : \"command\";\n const args = platform === \"win32\" ? [name] : [\"-v\", name];\n // spawnSync với shell=true để `command -v` (builtin) hoạt động.\n const r = spawnSync(probe, args, {\n shell: platform !== \"win32\",\n stdio: \"ignore\",\n });\n return r.status === 0;\n}\n\n// Trả về PM đầu tiên có sẵn theo thứ tự ưu tiên phù hợp với OS.\nexport function detectPackageManager(): PackageManager | null {\n const platform = detectHostPlatform();\n const candidates: PackageManager[] =\n platform === \"darwin\"\n ? [\"brew\"]\n : platform === \"win32\"\n ? [\"winget\"]\n : platform === \"linux\"\n ? [\"apt\", \"dnf\", \"pacman\"]\n : [];\n for (const pm of candidates) {\n if (hasBinary(pm)) return pm;\n }\n return null;\n}\n","// Wrapper mỏng quanh os.platform() để các module khác switch theo OS dễ hơn\n// và test dễ mock.\nimport { platform } from \"node:os\";\n\nexport type HostPlatform = \"darwin\" | \"linux\" | \"win32\" | \"unsupported\";\n\n// Trả về tên platform chuẩn hoá. Mọi giá trị khác 3 OS chính → \"unsupported\".\nexport function detectHostPlatform(): HostPlatform {\n const p = platform();\n if (p === \"darwin\" || p === \"linux\" || p === \"win32\") return p;\n return \"unsupported\";\n}\n","// Cài `gh` CLI qua package manager đã detect. Stream stdio để user thấy progress.\n// Throws nếu cài fail hoặc PM trả non-zero.\nimport { spawnSync } from \"node:child_process\";\nimport type { PackageManager } from \"./detect-package-manager.js\";\nimport { log } from \"./terminal-logger.js\";\n\n// Map PM → command + args để cài gh. apt/dnf cần sudo; brew/pacman/winget thì không.\nconst INSTALL_COMMANDS: Record<PackageManager, { cmd: string; args: string[] }> = {\n brew: { cmd: \"brew\", args: [\"install\", \"gh\"] },\n apt: { cmd: \"sudo\", args: [\"apt-get\", \"install\", \"-y\", \"gh\"] },\n dnf: { cmd: \"sudo\", args: [\"dnf\", \"install\", \"-y\", \"gh\"] },\n pacman: { cmd: \"sudo\", args: [\"pacman\", \"-S\", \"--noconfirm\", \"github-cli\"] },\n winget: { cmd: \"winget\", args: [\"install\", \"--id\", \"GitHub.cli\", \"-e\", \"--silent\"] },\n};\n\nexport function installGhCliViaPackageManager(pm: PackageManager): void {\n const spec = INSTALL_COMMANDS[pm];\n log.info(`Đang cài gh CLI qua ${pm}...`);\n const r = spawnSync(spec.cmd, spec.args, { stdio: \"inherit\" });\n if (r.status !== 0) {\n throw new Error(`Cài gh CLI thất bại qua ${pm} (exit ${r.status}). Cài tay rồi chạy lại.`);\n }\n log.success(\"Đã cài gh CLI\");\n}\n","// Config git credential helper dùng gh token. Cần thiết để `git ls-remote`,\n// `git clone`, `git push` qua HTTPS hoạt động khi gh đã auth nhưng git chưa\n// biết về token đó. Idempotent — chạy nhiều lần OK.\nimport { spawnSync } from \"node:child_process\";\nimport { log } from \"./terminal-logger.js\";\n\nexport function setupGitCredentialViaGh(): void {\n const r = spawnSync(\"gh\", [\"auth\", \"setup-git\"], { stdio: \"ignore\" });\n if (r.status !== 0) {\n // Không throw — nếu setup-git fail, git operation sau có thể vẫn work\n // (vd user đã có credential helper khác). Chỉ warn.\n log.warn(\"gh auth setup-git fail (non-fatal). Nếu git clone lỗi 128 → chạy thủ công.\");\n return;\n }\n log.dim(\"Git credential helper đã link với gh token.\");\n}\n","// Spawn `gh auth login --hostname github.com --web` interactive.\n// User sẽ thấy device-code prompt và browser tự mở. Block đến khi xong.\nimport { spawnSync } from \"node:child_process\";\nimport { log } from \"./terminal-logger.js\";\n\nexport function triggerGhCliAuthLogin(): void {\n log.info(\"Khởi động đăng nhập GitHub qua gh CLI (browser sẽ mở)...\");\n const r = spawnSync(\n \"gh\",\n [\"auth\", \"login\", \"--hostname\", \"github.com\", \"--web\", \"--git-protocol\", \"ssh\"],\n { stdio: \"inherit\" },\n );\n if (r.status !== 0) {\n throw new Error(`gh auth login thất bại (exit ${r.status}). Thử 'gh auth login' tay.`);\n }\n log.success(\"Đã đăng nhập GitHub\");\n}\n","// Verify một remote URL có accessible không bằng `git ls-remote <url> HEAD`\n// với timeout 5 giây. Tách ra để init flow check sớm — fail-fast nếu URL sai.\nimport { spawnSync } from \"node:child_process\";\n\nconst TIMEOUT_MS = 5_000;\n\nexport class RemoteNotAccessibleError extends Error {\n constructor(url: string, reason: string) {\n super(`Không truy cập được remote ${url}: ${reason}`);\n this.name = \"RemoteNotAccessibleError\";\n }\n}\n\nexport function verifyGitRemoteAccessible(url: string): void {\n const r = spawnSync(\"git\", [\"ls-remote\", \"--exit-code\", url, \"HEAD\"], {\n stdio: \"ignore\",\n timeout: TIMEOUT_MS,\n });\n if (r.status === 0) return;\n // signal=SIGTERM nghĩa là Node.js kill do timeout.\n if (r.signal === \"SIGTERM\") throw new RemoteNotAccessibleError(url, \"timeout 5s\");\n throw new RemoteNotAccessibleError(url, `git ls-remote exit ${r.status}`);\n}\n","// Orchestrator phase 2: đảm bảo gh CLI có và đã auth. Tự cài + tự login nếu cần.\n// Chỉ throws khi không thể tự fix (PM thiếu, login thất bại).\nimport { checkGhCliAuthStatus } from \"./check-gh-cli-auth-status.js\";\nimport { detectPackageManager } from \"./detect-package-manager.js\";\nimport { installGhCliViaPackageManager } from \"./install-gh-cli-via-package-manager.js\";\nimport { setupGitCredentialViaGh } from \"./setup-git-credential-via-gh.js\";\nimport { log } from \"./terminal-logger.js\";\nimport { triggerGhCliAuthLogin } from \"./trigger-gh-cli-auth-login.js\";\nimport { verifyGitRemoteAccessible } from \"./verify-git-remote-accessible.js\";\n\n// Gọi trước mọi flow cần GitHub (init nhánh 1, nhánh 2-create-remote, nhánh 3).\n// remoteUrl optional — nếu truyền sẽ verify access cụ thể.\nexport async function ensureGitHubReady(remoteUrl?: string): Promise<void> {\n let state = checkGhCliAuthStatus();\n\n if (state === \"not-installed\") {\n log.warn(\"gh CLI chưa cài. Avatar sẽ tự cài.\");\n const pm = detectPackageManager();\n if (!pm) {\n throw new Error(\n \"Không phát hiện package manager (brew/apt/dnf/pacman/winget). Cài gh CLI tay rồi chạy lại: https://cli.github.com\",\n );\n }\n installGhCliViaPackageManager(pm);\n state = checkGhCliAuthStatus();\n }\n\n if (state === \"not-authenticated\") {\n log.warn(\"Chưa đăng nhập GitHub.\");\n triggerGhCliAuthLogin();\n state = checkGhCliAuthStatus();\n if (state !== \"authenticated\") {\n throw new Error(\"Sau gh auth login vẫn chưa authenticated. Thử lại.\");\n }\n }\n\n log.success(\"gh CLI sẵn sàng\");\n\n // Đảm bảo git CLI dùng gh token cho HTTPS operations. Idempotent — chạy\n // mỗi lần init OK. Fix lỗi `git ls-remote exit 128` khi gh đã auth nhưng\n // git chưa biết.\n setupGitCredentialViaGh();\n\n if (remoteUrl) {\n verifyGitRemoteAccessible(remoteUrl);\n log.success(`Remote accessible: ${remoteUrl}`);\n }\n}\n","// Kiểm tra folder đã là git repo chưa. Đơn giản: check tồn tại của \".git\"\n// (folder hoặc file gitlink — cả hai đều hợp lệ với submodule).\nimport { existsSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport function checkFolderHasGit(folderPath: string): boolean {\n const gitPath = join(folderPath, \".git\");\n if (!existsSync(gitPath)) return false;\n // .git có thể là directory (repo bình thường) hoặc file (submodule gitlink).\n // Cả 2 đều xem là \"đã có git\".\n const stat = statSync(gitPath);\n return stat.isDirectory() || stat.isFile();\n}\n","// Init git repo trong folder + tạo initial commit. Idempotent: skip nếu đã\n// có commit. Default branch \"main\".\nimport { simpleGit } from \"simple-git\";\n\nconst INITIAL_COMMIT_MESSAGE = \"chore: initial commit\";\n\nexport async function createInitialGitCommit(folderPath: string): Promise<void> {\n const g = simpleGit({ baseDir: folderPath });\n\n // Init nếu chưa có .git.\n const isRepo = await g.checkIsRepo().catch(() => false);\n if (!isRepo) {\n await g.init();\n }\n\n // Đảm bảo branch hiện tại là main (đổi master → main nếu cần).\n // Một số git config user có init.defaultBranch=master.\n try {\n await g.branch([\"-M\", \"main\"]);\n } catch {\n // Repo trống chưa có commit nào — branch -M sẽ fail. Bỏ qua, commit\n // đầu tiên dưới đây sẽ tạo branch main qua HEAD ref.\n }\n\n // Stage all + commit. Nếu không có file (folder rỗng) thì commit empty để\n // submodule add có HEAD reference dùng.\n await g.add(\".\");\n const status = await g.status();\n const hasCommits = (await g.raw([\"rev-list\", \"-n\", \"1\", \"--all\"]).catch(() => \"\")).trim();\n if (hasCommits) return; // Đã có commit, skip.\n\n if (status.files.length === 0) {\n await g.commit(INITIAL_COMMIT_MESSAGE, undefined, { \"--allow-empty\": null });\n } else {\n await g.commit(INITIAL_COMMIT_MESSAGE);\n }\n}\n","// Detect tech stack của folder qua signature file ở root. Trả về tất cả stack\n// match được (folder polyglot là chuyện thường — vd monorepo Node + Python).\n// Nếu không match gì → [\"generic\"].\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport type TechStack = \"node\" | \"python\" | \"go\" | \"rust\" | \"java\" | \"ruby\" | \"generic\";\n\n// Bảng signature: stack → các file đủ điều kiện claim stack đó.\nconst SIGNATURES: Record<Exclude<TechStack, \"generic\">, string[]> = {\n node: [\"package.json\"],\n python: [\"pyproject.toml\", \"requirements.txt\", \"setup.py\", \"Pipfile\"],\n go: [\"go.mod\"],\n rust: [\"Cargo.toml\"],\n java: [\"pom.xml\", \"build.gradle\", \"build.gradle.kts\"],\n ruby: [\"Gemfile\"],\n};\n\nexport function detectFolderTechStack(folderPath: string): TechStack[] {\n const matched: TechStack[] = [];\n for (const [stack, files] of Object.entries(SIGNATURES) as [\n Exclude<TechStack, \"generic\">,\n string[],\n ][]) {\n if (files.some((f) => existsSync(join(folderPath, f)))) {\n matched.push(stack);\n }\n }\n return matched.length > 0 ? matched : [\"generic\"];\n}\n","// Load template gitignore từ src/templates/gitignore/<stack>.txt và compose\n// nội dung tổng hợp cho 1+ stack. Generic luôn được prepend.\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { TechStack } from \"./detect-folder-tech-stack.js\";\n\n// Resolve template dir tương đối với file này, không phải CWD. Khi bundle bằng\n// tsup, file này nằm trong dist/, templates nằm trong src/templates — tsup copy\n// templates qua --publicDir (đã cấu hình trong tsup.config.ts) hoặc resolve\n// qua relative path.\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Thứ tự search: relative tới file build (dist/), fallback dev (src/lib/).\nconst CANDIDATE_DIRS = [\n join(__dirname, \"..\", \"templates\", \"gitignore\"),\n join(__dirname, \"..\", \"..\", \"src\", \"templates\", \"gitignore\"),\n];\n\nconst AVATAR_MARKER_START = \"# === avatar ===\";\nconst AVATAR_MARKER_END = \"# === /avatar ===\";\n\nfunction readTemplate(stack: TechStack): string {\n for (const dir of CANDIDATE_DIRS) {\n try {\n return readFileSync(join(dir, `${stack}.txt`), \"utf8\");\n } catch {\n // continue\n }\n }\n throw new Error(`Không tìm thấy template gitignore cho stack \"${stack}\"`);\n}\n\n// Compose: generic luôn ở đầu, sau đó các stack khác theo thứ tự detect.\n// Wrap trong marker để uninstall biết range gỡ chính xác.\nexport function composeGitignoreContent(stacks: TechStack[]): string {\n const all: TechStack[] = [\"generic\", ...stacks.filter((s) => s !== \"generic\")];\n const sections = all.map((s) => `# --- ${s} ---\\n${readTemplate(s).trim()}`);\n return [AVATAR_MARKER_START, ...sections, AVATAR_MARKER_END, \"\"].join(\"\\n\");\n}\n\nexport { AVATAR_MARKER_START, AVATAR_MARKER_END };\n","// Ghi .gitignore: tạo mới nếu chưa có, merge content nếu đã có. Merge logic\n// dùng marker `# === avatar === ... # === /avatar ===`: replace block đó nếu\n// tồn tại, append nếu chưa.\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { AVATAR_MARKER_END, AVATAR_MARKER_START } from \"./gitignore-template-loader.js\";\n\nexport function writeOrMergeGitignore(folderPath: string, avatarBlock: string): void {\n const path = join(folderPath, \".gitignore\");\n\n if (!existsSync(path)) {\n writeFileSync(path, avatarBlock, \"utf8\");\n return;\n }\n\n const existing = readFileSync(path, \"utf8\");\n const startIdx = existing.indexOf(AVATAR_MARKER_START);\n const endIdx = existing.indexOf(AVATAR_MARKER_END);\n\n // Đã có marker → replace block giữa marker (giữ content trước/sau).\n if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + AVATAR_MARKER_END.length);\n writeFileSync(path, `${before.trimEnd()}\\n\\n${avatarBlock}${after.trimStart()}`, \"utf8\");\n return;\n }\n\n // Chưa có marker → append phía cuối, thêm newline phân cách.\n writeFileSync(path, `${existing.trimEnd()}\\n\\n${avatarBlock}`, \"utf8\");\n}\n","// Orchestrator phase 3: bootstrap git cho folder local. Idempotent — chạy trên\n// folder đã có git sẽ no-op (chỉ ensure .gitignore có Avatar block).\nimport { checkFolderHasGit } from \"./check-folder-has-git.js\";\nimport { createInitialGitCommit } from \"./create-initial-git-commit.js\";\nimport { detectFolderTechStack } from \"./detect-folder-tech-stack.js\";\nimport { composeGitignoreContent } from \"./gitignore-template-loader.js\";\nimport { log } from \"./terminal-logger.js\";\nimport { writeOrMergeGitignore } from \"./write-or-merge-gitignore.js\";\n\nexport async function bootstrapGitInFolder(folderPath: string): Promise<void> {\n const hadGit = checkFolderHasGit(folderPath);\n\n // Auto detect tech stack + write .gitignore với Avatar block.\n const stacks = detectFolderTechStack(folderPath);\n log.info(`Tech stack detected: ${stacks.join(\", \")}`);\n writeOrMergeGitignore(folderPath, composeGitignoreContent(stacks));\n log.success(\".gitignore đã ghi (Avatar block)\");\n\n if (!hadGit) {\n log.info(`Bootstrap git cho ${folderPath}...`);\n await createInitialGitCommit(folderPath);\n log.success(\"Đã git init + initial commit\");\n } else {\n log.dim(\"Folder đã có .git — skip init.\");\n }\n}\n","// Manage the team-ai-pack git submodule lifecycle: add, update, pin-to-tag,\n// changelog extraction. Used by `avatar init` and `avatar sync`.\nimport { join } from \"node:path\";\nimport {\n addSubmodule,\n checkoutTagInSubmodule,\n currentCommitSha,\n latestTag,\n} from \"./git-operations.js\";\nimport { resolveTeamPackRepoUrl } from \"./resolve-team-pack-repo-url.js\";\nimport { log } from \"./terminal-logger.js\";\n\n// Resolve URL động qua resolveTeamPackRepoUrl() — không hardcode. Export getter\n// để legacy code đọc URL được nhưng kết quả phụ thuộc env + gh user hiện tại.\nexport function getTeamPackRepoUrl(): string {\n return resolveTeamPackRepoUrl();\n}\n\n// Backward-compat: snapshot URL lúc load module (v1.0/1.1 đã expose). Sẽ remove\n// ở v2.0.0. New code dùng getTeamPackRepoUrl() để luôn pickup env latest.\nexport const TEAM_PACK_REPO_URL = resolveTeamPackRepoUrl();\nexport const TEAM_PACK_RELATIVE_PATH = \".claude/pack\";\n\n// Add the team-ai-pack submodule into a fresh project and pin it to a tag.\n// If `tag` is omitted, checks out the latest tag in the freshly-cloned submodule.\n// Nếu repo không tồn tại / không access được → throw lỗi rõ ràng kèm gợi ý fix.\nexport async function addTeamPackSubmodule(\n projectRoot: string,\n tag?: string,\n): Promise<{ pinnedTag: string | null }> {\n const url = resolveTeamPackRepoUrl();\n try {\n await addSubmodule(url, TEAM_PACK_RELATIVE_PATH, projectRoot);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"Repository not found\") || msg.includes(\"not found\")) {\n log.error(\n `Repo team-ai-pack không tồn tại: ${url}\\n Cách fix:\\n 1. Tạo repo: gh repo create <owner>/team-ai-pack --private --add-readme\\n 2. Hoặc override URL: export AVATAR_TEAM_PACK_REPO_URL=<url-repo-của-bạn>\\n 3. Hoặc dùng flag --skip-team-pack`,\n );\n }\n throw err;\n }\n\n // Resolve which tag to pin to. If caller passed one, honour it; otherwise\n // ask the just-cloned submodule for its latest tag.\n let target = tag ?? null;\n if (!target) {\n target = await latestTag(join(projectRoot, TEAM_PACK_RELATIVE_PATH));\n }\n\n if (target) {\n await checkoutTagInSubmodule(TEAM_PACK_RELATIVE_PATH, target, projectRoot);\n }\n return { pinnedTag: target };\n}\n\n// Read the current pinned version of the pack submodule. Returns the tag name\n// if HEAD matches a tag, otherwise the short SHA.\nexport async function readPinnedPackVersion(projectRoot: string): Promise<string> {\n const submoduleRoot = join(projectRoot, TEAM_PACK_RELATIVE_PATH);\n const tag = await latestTag(submoduleRoot);\n if (tag) return tag;\n const sha = await currentCommitSha(submoduleRoot);\n return sha.slice(0, 7);\n}\n","// Resolve URL của team-ai-pack submodule. Thứ tự ưu tiên:\n// 1. Env var AVATAR_TEAM_PACK_REPO_URL (explicit override)\n// 2. GitHub login của user đang auth (smart default: <gh-user>/team-ai-pack)\n// 3. Fallback hardcode \"LukeNALS/team-ai-pack\" (legacy v1.0/1.1.0)\n//\n// Cho phép user account khác nhau tự dùng repo riêng mà không cần config.\nimport { resolveGithubUsernameDefault } from \"./resolve-github-username-default.js\";\n\nconst LEGACY_FALLBACK = \"https://github.com/LukeNALS/team-ai-pack.git\";\n\nexport function resolveTeamPackRepoUrl(): string {\n if (process.env.AVATAR_TEAM_PACK_REPO_URL) {\n return process.env.AVATAR_TEAM_PACK_REPO_URL;\n }\n\n try {\n const ghUser = resolveGithubUsernameDefault();\n if (ghUser) return `https://github.com/${ghUser}/team-ai-pack.git`;\n } catch {\n // gh chưa auth — fallback legacy.\n }\n\n return LEGACY_FALLBACK;\n}\n","// Pure helpers for `avatar init` conflict detection and workspace path\n// resolution. Extracted from init.ts so they're unit-testable without\n// triggering inquirer prompts or git operations.\n\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pathExists } from \"../lib/filesystem-helpers.js\";\nimport { AVATAR_MANAGED_PATHS } from \"../lib/project-tree-scaffolder.js\";\n\n// True if path doesn't exist OR is an empty directory (ignoring dotfiles and\n// Windows Thumbs.db noise). Safe to scaffold into. macOS .DS_Store and\n// .localized are already filtered by the dotfile rule.\nexport async function isEmptyOrMissing(path: string): Promise<boolean> {\n if (!(await pathExists(path))) return true;\n try {\n const entries = await readdir(path);\n const meaningful = entries.filter((e) => !e.startsWith(\".\") && e !== \"Thumbs.db\");\n return meaningful.length === 0;\n } catch {\n return false;\n }\n}\n\n// Return Avatar-managed top-level paths that already exist in projectRoot.\n// Caller decides whether to abort, prompt, or auto-backup.\nexport async function detectAvatarConflicts(projectRoot: string): Promise<string[]> {\n const found: string[] = [];\n for (const rel of AVATAR_MANAGED_PATHS) {\n if (await pathExists(join(projectRoot, rel))) found.push(rel);\n }\n return found;\n}\n\n// Find first numbered alternative path (e.g. \"foo-2\", \"foo-3\", ...) under\n// `parent` that is empty or missing. Returns null if exhausted.\n// maxAttempts defaults to 10; if a user has 9+ workspaces with the same\n// base name, something else is wrong.\nexport async function findAlternativeWorkspaceName(\n parent: string,\n desiredName: string,\n maxAttempts = 10,\n): Promise<string | null> {\n for (let i = 2; i < maxAttempts; i++) {\n const candidate = join(parent, `${desiredName}-${i}`);\n if (await isEmptyOrMissing(candidate)) return candidate;\n }\n return null;\n}\n","// Pure transformation helpers used by `avatar init` to derive project names,\n// workspace names from git URLs, and build the ScaffoldVariables struct for\n// template rendering. Extracted from init.ts for testability — no IO,\n// no prompts, no git calls.\n\nimport type { ScaffoldVariables } from \"../lib/project-tree-scaffolder.js\";\nimport type { InitMode } from \"../types/config-schema.js\";\n\nconst AVATAR_CLI_VERSION = \"1.0.1\";\n\n// Last path segment of an absolute project root, used as fallback project\n// name when user doesn't supply one explicitly. Handles trailing slashes.\nexport function projectNameOf(projectRoot: string): string {\n return projectRoot.split(\"/\").filter(Boolean).pop() ?? \"avatar-project\";\n}\n\n// Infer workspace folder name from a git remote URL.\n// \"git@github.com:org/repo.git\" → \"avatar-repo-workspace\"\n// \"https://github.com/org/repo.git\" → \"avatar-repo-workspace\"\n// \"https://github.com/org/repo\" → \"avatar-repo-workspace\"\n// fallback when match fails → \"avatar-client-workspace\"\nexport function inferWorkspaceName(repoUrl: string): string {\n const m = repoUrl.match(/[/:]([^/]+?)(\\.git)?$/);\n const base = m?.[1] ?? \"client\";\n return `avatar-${base}-workspace`;\n}\n\n// Build the template-rendering variable bag. lastScan stamps \"now\" — tests\n// that need a deterministic value should freeze time via vi.useFakeTimers().\nexport function buildScaffoldVariables(args: {\n projectName: string;\n projectDescription: string;\n teamOwner: string;\n packVersion: string;\n mode: InitMode;\n}): ScaffoldVariables {\n return {\n projectName: args.projectName,\n projectDescription: args.projectDescription,\n teamOwner: args.teamOwner,\n avatarVersion: AVATAR_CLI_VERSION,\n packVersion: args.packVersion,\n lastScan: new Date().toISOString(),\n mode: args.mode,\n };\n}\n","import boxen from \"boxen\";\n// `avatar login [--reset]` — Command 01 spec.\n// Implements the user-facing flow: announce verification URL, open browser,\n// poll Google until token returned, validate domain, persist credentials.\nimport type { Command } from \"commander\";\nimport open from \"open\";\nimport { appendAuditEntry } from \"../lib/audit-log-appender.js\";\nimport { printAvatarBanner } from \"../lib/avatar-ascii-banner.js\";\nimport {\n buildUserConfig,\n buildVerificationUrl,\n decodeIdToken,\n pollForToken,\n requestDeviceCode,\n revokeToken,\n verifyHostedDomain,\n} from \"../lib/google-oauth-device-flow.js\";\nimport { chalk, log, spinner } from \"../lib/terminal-logger.js\";\nimport {\n USER_CONFIG_PATH,\n clearUserConfig,\n isTokenExpired,\n readUserConfig,\n writeUserConfig,\n} from \"../lib/user-config-store.js\";\n\nexport function registerLoginCommand(program: Command): void {\n program\n .command(\"login\")\n .description(\"Đăng nhập Google SSO (workspace @nal.vn)\")\n .option(\"--reset\", \"Xóa credential cũ và đăng nhập lại\")\n .action(async (opts: { reset?: boolean }) => {\n try {\n await runLogin(opts);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runLogin(opts: { reset?: boolean }): Promise<void> {\n // Banner trước khi vào device-code flow để user nhận diện thương hiệu.\n printAvatarBanner({ tagline: \"Đăng nhập Google SSO · workspace @nal.vn\" });\n\n // Step 1 of spec: short-circuit if already logged in and token is still good.\n if (opts.reset) {\n await clearUserConfig();\n await appendAuditEntry(\"login_reset\");\n } else {\n const existing = await readUserConfig();\n if (existing && !isTokenExpired(existing)) {\n log.success(`Đã đăng nhập: ${existing.email}`);\n return;\n }\n }\n\n // Step 2: request device + user code.\n const deviceSpinner = spinner(\"Đang yêu cầu device code từ Google...\");\n let deviceCode: Awaited<ReturnType<typeof requestDeviceCode>>;\n try {\n deviceCode = await requestDeviceCode();\n deviceSpinner.succeed(\"Nhận device code\");\n } catch (err) {\n deviceSpinner.fail(\"Không kết nối được Google\");\n throw err;\n }\n\n // Step 3: display instructions to user.\n const verificationUrl = buildVerificationUrl(deviceCode);\n const instructions = [\n `1. Truy cập: ${chalk.cyan(deviceCode.verification_url)}`,\n `2. Nhập code: ${chalk.bold.yellow(deviceCode.user_code)}`,\n \"\",\n `Hoặc Avatar tự mở browser, click ${chalk.green(\"Allow\")}...`,\n ].join(\"\\n\");\n process.stdout.write(`${boxen(instructions, { padding: 1, borderStyle: \"round\" })}\\n`);\n\n // Step 4: open browser. Failure here is non-fatal — user can copy URL manually.\n void open(verificationUrl).catch(() => {\n log.dim(\"(Không mở được browser tự động — copy URL ở trên)\");\n });\n\n // Step 5: poll token endpoint until success or expiry.\n const waitSpinner = spinner(\"Đang chờ xác nhận trong browser...\");\n const intervalMs = deviceCode.interval * 1000;\n const deadline = Date.now() + deviceCode.expires_in * 1000;\n\n let token = null;\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n try {\n token = await pollForToken(deviceCode.device_code);\n if (token) break;\n } catch (err) {\n waitSpinner.fail(\"Xác thực thất bại\");\n throw err;\n }\n }\n if (!token) {\n waitSpinner.fail(\"Hết hạn chờ (5 phút). Chạy lại 'avatar login'.\");\n process.exit(1);\n }\n waitSpinner.succeed(\"Đã nhận token từ Google\");\n\n // Step 6: verify hosted domain. Revoke token if claim is wrong.\n const claims = decodeIdToken(token.id_token);\n try {\n verifyHostedDomain(claims);\n } catch (err) {\n await revokeToken(token.access_token);\n throw err;\n }\n\n // Step 7: persist credentials with chmod 600.\n const userConfig = buildUserConfig(token, claims);\n await writeUserConfig(userConfig);\n await appendAuditEntry(\"login\", userConfig.email);\n\n log.success(`Xác thực thành công: ${userConfig.email}`);\n log.success(`Verify hosted domain: ${claims.hd} ✓`);\n log.success(`Lưu credential vào ${USER_CONFIG_PATH} (chmod 600)`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","// Google OAuth 2.0 Device Authorization Grant (RFC 8628) implementation.\n//\n// Why Device Flow: Avatar is a terminal CLI with no browser redirect URL.\n// The user logs in via google.com/device on a browser and the CLI polls\n// Google for the resulting token.\n//\n// Why the client secret is bundled in source: Device Flow does not treat the\n// secret as a security boundary — the human Allow click in the browser is.\n// Google's TV/Limited Input docs explicitly permit this.\n//\n// To rotate: Google Cloud Console → APIs & Services → Credentials → click the\n// OAuth client → Reset Secret. Replace GOOGLE_CLIENT_SECRET below.\n\nimport type { UserConfig } from \"../types/config-schema.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OAuth client config (hardcoded — see file header for rationale).\n// To regenerate: Google Cloud Console → project \"avatar-cli\" → Clients.\n// Application type must be \"TV and Limited Input devices\".\n// ─────────────────────────────────────────────────────────────────────────────\nexport const GOOGLE_CLIENT_ID =\n \"1014766441755-i4jimivh5rd7vt8phuhmepmt45sovtph.apps.googleusercontent.com\";\nexport const GOOGLE_CLIENT_SECRET = \"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\";\n\n// Restrict to the NAL Workspace domain. Enforced at TWO layers:\n// 1. ?hd=nal.vn appended to the verification URL — Google filters the picker\n// 2. Verify id_token.hd === HOSTED_DOMAIN after token exchange (defense-in-depth)\nexport const HOSTED_DOMAIN = \"nal.vn\";\n\nexport const SCOPES = [\"openid\", \"email\", \"profile\"];\n\nconst DEVICE_CODE_URL = \"https://oauth2.googleapis.com/device/code\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\nconst REVOKE_URL = \"https://oauth2.googleapis.com/revoke\";\n\nexport interface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_url: string;\n expires_in: number;\n interval: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n refresh_token: string;\n id_token: string;\n expires_in: number;\n token_type: string;\n scope: string;\n}\n\nexport interface IdTokenClaims {\n email: string;\n email_verified: boolean;\n name?: string;\n hd?: string;\n exp: number;\n iss: string;\n aud: string;\n}\n\n// ── Step 2 of Command 01 spec: request device + user codes.\nexport async function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const body = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n scope: SCOPES.join(\" \"),\n });\n const res = await fetch(DEVICE_CODE_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Device code request failed (${res.status}): ${text}`);\n }\n return (await res.json()) as DeviceCodeResponse;\n}\n\n// ── Step 5: poll the token endpoint until user authorises or expiry.\n// Returns the token response on success, null while still pending.\n// Throws on hard errors (access_denied, expired_token).\nexport async function pollForToken(deviceCode: string): Promise<TokenResponse | null> {\n const body = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n device_code: deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n });\n const res = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n\n if (res.ok) {\n return (await res.json()) as TokenResponse;\n }\n\n // Google returns 4xx with a JSON {error} field for both pending and fatal states.\n let errorCode = \"\";\n try {\n const data = (await res.json()) as { error?: string };\n errorCode = data.error ?? \"\";\n } catch {\n errorCode = \"\";\n }\n\n if (errorCode === \"authorization_pending\" || errorCode === \"slow_down\") {\n return null;\n }\n if (errorCode === \"access_denied\") {\n throw new Error(\"User từ chối quyền truy cập\");\n }\n if (errorCode === \"expired_token\") {\n throw new Error(\"Hết hạn chờ (5 phút). Chạy lại 'avatar login'.\");\n }\n throw new Error(`OAuth token endpoint trả lỗi: ${errorCode || res.status}`);\n}\n\n// Decode JWT payload WITHOUT verifying signature. Safe here because we receive\n// the token directly from Google over HTTPS — no MITM surface.\nexport function decodeIdToken(idToken: string): IdTokenClaims {\n const parts = idToken.split(\".\");\n if (parts.length !== 3) {\n throw new Error(\"id_token format không hợp lệ\");\n }\n const payload = parts[1];\n if (!payload) throw new Error(\"id_token thiếu payload\");\n // Convert base64url to base64.\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = Buffer.from(base64, \"base64\").toString(\"utf8\");\n return JSON.parse(json) as IdTokenClaims;\n}\n\n// ── Step 6: enforce hosted domain. Reject any non-@nal.vn account.\nexport function verifyHostedDomain(claims: IdTokenClaims): void {\n if (claims.hd !== HOSTED_DOMAIN) {\n throw new Error(\n `Email không thuộc workspace NAL (yêu cầu @${HOSTED_DOMAIN}). Nhận: ${claims.email}`,\n );\n }\n if (!claims.email_verified) {\n throw new Error(\"Email chưa được Google verify\");\n }\n}\n\n// Convert OAuth token response + decoded claims into the on-disk UserConfig shape.\nexport function buildUserConfig(token: TokenResponse, claims: IdTokenClaims): UserConfig {\n const expiresAt = new Date(Date.now() + token.expires_in * 1000).toISOString();\n return {\n email: claims.email,\n name: claims.name ?? claims.email,\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n expires_at: expiresAt,\n id_token: token.id_token,\n };\n}\n\n// Refresh flow: exchange refresh_token for a new access_token. Used by other\n// commands when they detect an expired token (see isTokenExpired).\nexport async function refreshAccessToken(refreshToken: string): Promise<{\n access_token: string;\n expires_in: number;\n id_token?: string;\n}> {\n const body = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n refresh_token: refreshToken,\n grant_type: \"refresh_token\",\n });\n const res = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Refresh token failed (${res.status}): ${text}`);\n }\n return (await res.json()) as { access_token: string; expires_in: number; id_token?: string };\n}\n\n// Revoke a token (used when login is rejected post-hoc, e.g. wrong domain).\nexport async function revokeToken(token: string): Promise<void> {\n const body = new URLSearchParams({ token });\n await fetch(REVOKE_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n }).catch(() => {\n // Best-effort revoke — don't fail the caller if revoke itself errors.\n });\n}\n\n// Build the verification URL with hd hint so Google pre-filters the account picker.\nexport function buildVerificationUrl(response: DeviceCodeResponse): string {\n const url = new URL(response.verification_url);\n url.searchParams.set(\"user_code\", response.user_code);\n url.searchParams.set(\"hd\", HOSTED_DOMAIN);\n return url.toString();\n}\n","// `avatar mcp-run <tool-id>` — hidden command from Chapter 13 roadmap.\n// Wrapper used by ~/.claude.json entries: Avatar injects secrets from keychain\n// then spawns the underlying MCP process with stdio piped to Claude Code.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerMcpRunCommand(program: Command): void {\n program\n .command(\"mcp-run <tool-id>\", { hidden: true })\n .description(\"[internal] Spawn MCP với secrets injected (M09)\")\n .action(notImplementedYet(\"mcp-run\", \"Milestone 09\"));\n}\n","// `avatar restore [--backup <name>] [--list]` — Command 08 spec.\n// Restore .claude/pack/ from a previous backup snapshot.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerRestoreCommand(program: Command): void {\n program\n .command(\"restore\")\n .description(\"Khôi phục .claude/pack/ từ backup (M08)\")\n .option(\"--backup <name>\", \"Tên backup folder trong .claude/_backup/\")\n .option(\"--list\", \"Liệt kê các backup hiện có\")\n .action(notImplementedYet(\"restore\", \"Milestone 08\"));\n}\n","// `avatar review [--accept-all|--reject-all]` — Command 05 spec.\n// Interactive review of .claude/_pending/*.diff.md proposals.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerReviewCommand(program: Command): void {\n program\n .command(\"review\")\n .description(\"Review pending proposals từ avatar scan (M08)\")\n .option(\"--accept-all\", \"Approve mọi pending không hỏi (CI mode)\")\n .option(\"--reject-all\", \"Xóa mọi pending không hỏi\")\n .action(notImplementedYet(\"review\", \"Milestone 08\"));\n}\n","// `avatar scan [--incremental|--full] [--scanners <list>]` — Command 04 spec.\n// Runs 5 project scanners and writes proposals to .claude/_pending/.\n// Implementation deferred — scanner files in src/scanners/ are stubbed.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerScanCommand(program: Command): void {\n program\n .command(\"scan\")\n .description(\"Chạy project scanner và đề xuất knowledge update (M06)\")\n .option(\"--incremental\", \"Chỉ scan các file thay đổi từ commit cuối\")\n .option(\"--full\", \"Scan toàn bộ dự án (default)\")\n .option(\"--scanners <list>\", \"tech-stack,conventions,architecture,domain,git-pattern\")\n .option(\"--quiet\", \"Chạy ngầm, ít output (dùng cho git hook)\")\n .action(notImplementedYet(\"scan\", \"Milestone 06\"));\n}\n","// `avatar secrets {list,set,get,rm,check}` — Command 13 spec.\n// Backed by OS keychain via @napi-rs/keyring. Service prefix: \"avatar\".\n// Audit log entries are written for set/rm; values NEVER logged.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerSecretsCommand(program: Command): void {\n const secrets = program.command(\"secrets\").description(\"Quản lý secrets trong OS keychain (M09)\");\n\n secrets\n .command(\"list\")\n .description(\"Liệt kê secrets đã set (chỉ tên, không value)\")\n .action(notImplementedYet(\"secrets list\", \"Milestone 09\"));\n\n secrets\n .command(\"set <service> <name>\")\n .description(\"Set/update secret (prompt ẩn)\")\n .action(notImplementedYet(\"secrets set\", \"Milestone 09\"));\n\n secrets\n .command(\"get <service> <name>\")\n .description(\"Lấy secret, copy clipboard, auto-xóa sau 30s\")\n .action(notImplementedYet(\"secrets get\", \"Milestone 09\"));\n\n secrets\n .command(\"rm <service> <name>\")\n .description(\"Xóa secret khỏi keychain\")\n .action(notImplementedYet(\"secrets rm\", \"Milestone 09\"));\n\n secrets\n .command(\"check\")\n .description(\"Verify mọi secret required bởi MCP đã enabled\")\n .action(notImplementedYet(\"secrets check\", \"Milestone 09\"));\n}\n","// `avatar status [--json]` — Command 06 spec.\n// Read-only snapshot: project name, CLI version, pack version, pending count,\n// backup count, tech-stack first-line. No mutations.\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { pathExists, readText } from \"../lib/filesystem-helpers.js\";\nimport { isGitRepo } from \"../lib/git-operations.js\";\nimport { listBackups } from \"../lib/pack-backup-manager.js\";\nimport { readPinnedPackVersion } from \"../lib/team-pack-submodule-manager.js\";\nimport { chalk, log } from \"../lib/terminal-logger.js\";\n\nconst AVATAR_CLI_VERSION = \"1.0.1\";\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command(\"status\")\n .description(\"Snapshot tức thì: project, pack version, pending, backup\")\n .option(\"--json\", \"Output JSON cho script\")\n .action(async (opts: { json?: boolean }) => {\n try {\n const snapshot = await gatherStatus(process.cwd());\n if (opts.json) {\n process.stdout.write(`${JSON.stringify(snapshot, null, 2)}\\n`);\n } else {\n renderStatusBox(snapshot);\n }\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\ninterface StatusSnapshot {\n projectName: string;\n cliVersion: string;\n packVersion: string | null;\n pendingCount: number;\n backupCount: number;\n techStackSummary: string;\n hasAvatar: boolean;\n}\n\nasync function gatherStatus(cwd: string): Promise<StatusSnapshot> {\n const projectName = cwd.split(\"/\").filter(Boolean).pop() ?? \"unknown\";\n const claudeRoot = join(cwd, \".claude\");\n const hasAvatar = await pathExists(claudeRoot);\n if (!hasAvatar) {\n return {\n projectName,\n cliVersion: AVATAR_CLI_VERSION,\n packVersion: null,\n pendingCount: 0,\n backupCount: 0,\n techStackSummary: \"(Avatar chưa init)\",\n hasAvatar: false,\n };\n }\n\n const packVersion = (await isGitRepo(join(claudeRoot, \"pack\")))\n ? await readPinnedPackVersion(cwd).catch(() => null)\n : null;\n\n const pendingDir = join(claudeRoot, \"_pending\");\n const pendingCount = (await pathExists(pendingDir))\n ? (await fs.readdir(pendingDir)).filter((n) => n.endsWith(\".diff.md\")).length\n : 0;\n\n const backupCount = (await listBackups(cwd)).length;\n\n const techStackSummary = await readTechStackFirstLine(claudeRoot);\n\n return {\n projectName,\n cliVersion: AVATAR_CLI_VERSION,\n packVersion,\n pendingCount,\n backupCount,\n techStackSummary,\n hasAvatar: true,\n };\n}\n\nasync function readTechStackFirstLine(claudeRoot: string): Promise<string> {\n const techStackPath = join(claudeRoot, \"project\", \"tech-stack.md\");\n if (!(await pathExists(techStackPath))) return \"(no tech-stack.md)\";\n const content = await readText(techStackPath);\n const firstNonHeaderLine = content\n .split(\"\\n\")\n .find((l) => l.trim() && !l.startsWith(\"#\") && !l.startsWith(\">\"));\n return firstNonHeaderLine?.trim() ?? \"(empty)\";\n}\n\nfunction renderStatusBox(s: StatusSnapshot): void {\n const lines = [\n `${chalk.bold(\"Avatar Status\")} · ${chalk.cyan(s.projectName)}`,\n \"─\".repeat(48),\n `${chalk.dim(\"CLI version:\")} ${s.cliVersion}`,\n `${chalk.dim(\"Pack version:\")} ${s.packVersion ?? chalk.yellow(\"not installed\")}`,\n `${chalk.dim(\"Pending changes:\")} ${s.pendingCount}${s.pendingCount > 0 ? chalk.dim(\" (avatar review)\") : \"\"}`,\n `${chalk.dim(\"Backups:\")} ${s.backupCount}`,\n `${chalk.dim(\"Tech stack:\")} ${s.techStackSummary}`,\n ];\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n","import { promises as fs } from \"node:fs\";\n// Backup .claude/pack/ before `avatar sync --force` so user can `avatar restore`\n// if the sync goes wrong. Naming convention: pack-{currentVersion}-{YYYYMMDD-HHmm}.\nimport { join } from \"node:path\";\nimport { copyDirRecursive, ensureDir, pathExists } from \"./filesystem-helpers.js\";\n\nexport const BACKUP_DIR_NAME = \"_backup\";\n\nfunction timestamp(): string {\n const now = new Date();\n const y = now.getFullYear();\n const m = String(now.getMonth() + 1).padStart(2, \"0\");\n const d = String(now.getDate()).padStart(2, \"0\");\n const h = String(now.getHours()).padStart(2, \"0\");\n const min = String(now.getMinutes()).padStart(2, \"0\");\n return `${y}${m}${d}-${h}${min}`;\n}\n\nexport function buildBackupName(currentVersion: string): string {\n // Strip any leading \"v\" so we don't get pack-vv1.2.3 if someone passes \"v1.2.3\".\n const cleanVersion = currentVersion.replace(/^v/, \"\");\n return `pack-v${cleanVersion}-${timestamp()}`;\n}\n\n// Backup .claude/pack/ to .claude/_backup/{name}/, excluding the submodule's\n// own .git directory (we restore content only, not git history).\nexport async function backupPack(projectRoot: string, currentVersion: string): Promise<string> {\n const name = buildBackupName(currentVersion);\n const srcPath = join(projectRoot, \".claude\", \"pack\");\n const dstPath = join(projectRoot, \".claude\", BACKUP_DIR_NAME, name);\n if (!(await pathExists(srcPath))) {\n throw new Error(\"Không tìm thấy .claude/pack/ để backup\");\n }\n await ensureDir(dstPath);\n await copyDirRecursive(srcPath, dstPath, [\".git\"]);\n return name;\n}\n\nexport async function listBackups(projectRoot: string): Promise<string[]> {\n const dir = join(projectRoot, \".claude\", BACKUP_DIR_NAME);\n if (!(await pathExists(dir))) return [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n}\n","// `avatar sync [--force] [--version <tag>] [--dry-run]` — Command 03 spec.\n// Pulls latest team-ai-pack into .claude/pack. Implementation in next milestone.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerSyncCommand(program: Command): void {\n program\n .command(\"sync\")\n .description(\"Pull team-ai-pack mới nhất (M08)\")\n .option(\"--force\", \"Override .claude/pack/, backup trước\")\n .option(\"--version <tag>\", \"Pin vào version cụ thể\")\n .option(\"--dry-run\", \"Hiển thị changes, không apply\")\n .action(notImplementedYet(\"sync\", \"Milestone 08\"));\n}\n","// `avatar tools {list,install,remove}` — Commands 10/11/12 spec (Chapter 12 v4).\n// Lifecycle management for system dependencies (git, gh, node, uv, docker) and\n// MCP servers (gitnexus, context7, serena, github, filesystem, playwright).\n// Registry source: team-ai-pack/tools/registry.yaml.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerToolsCommand(program: Command): void {\n const tools = program.command(\"tools\").description(\"Quản lý system tools + MCP servers (M09)\");\n\n tools\n .command(\"list\")\n .description(\"Liệt kê tool đã cài / còn thiếu\")\n .option(\"--installed\", \"Chỉ liệt kê tool đã cài\")\n .option(\"--missing\", \"Chỉ liệt kê tool còn thiếu\")\n .option(\"--json\", \"Output JSON cho script\")\n .action(notImplementedYet(\"tools list\", \"Milestone 09\"));\n\n tools\n .command(\"install [tool-ids...]\")\n .description(\"Cài tool và đăng ký vào ~/.claude.json\")\n .option(\"--all-recommended\", \"Cài mọi MCP được recommend cho project type\")\n .option(\"--verify\", \"Chạy MCP thử để verify (mất ~30s/tool)\")\n .option(\"--no-secrets\", \"Skip prompt secrets, set sau qua 'avatar secrets'\")\n .action(notImplementedYet(\"tools install\", \"Milestone 09\"));\n\n tools\n .command(\"remove <tool-id>\")\n .description(\"Gỡ tool khỏi ~/.claude.json (optional uninstall binary)\")\n .option(\"--keep-secrets\", \"Không xóa secrets khỏi keychain\")\n .option(\"--keep-binary\", \"Không uninstall npm global binary\")\n .action(notImplementedYet(\"tools remove\", \"Milestone 09\"));\n}\n","// `avatar uninstall` — Command 13 (v1.1).\n// Gỡ Avatar khỏi project + auto-backup vào ~/.avatar/uninstall-backups/.\n// Đối ứng với `avatar init`. Code khách (src/) giữ nguyên.\n\nimport { relative } from \"node:path\";\nimport { confirm } from \"@inquirer/prompts\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { appendAuditEntry } from \"../lib/audit-log-appender.js\";\nimport { createUninstallBackupSnapshot } from \"../lib/create-uninstall-backup-snapshot.js\";\nimport { detectAvatarProjectArtifacts } from \"../lib/detect-avatar-project-artifacts.js\";\nimport { executeUninstallDeletion } from \"../lib/execute-uninstall-deletion.js\";\nimport { chalk, log } from \"../lib/terminal-logger.js\";\n\nconst CLI_VERSION = \"1.1.6\";\n\ninterface UninstallOptions {\n yes?: boolean;\n noBackup?: boolean;\n keepSubmodule?: boolean;\n keepHooks?: boolean;\n dryRun?: boolean;\n}\n\nexport function registerUninstallCommand(program: Command): void {\n program\n .command(\"uninstall\")\n .description(\"Gỡ Avatar khỏi project — backup tự động (M11)\")\n .option(\"--yes\", \"Skip confirm prompt\")\n .option(\"--no-backup\", \"Không tạo backup trước khi xóa (nguy hiểm)\")\n .option(\"--keep-submodule\", \"Giữ submodule .claude/pack/\")\n .option(\"--keep-hooks\", \"Giữ git hooks post-merge, pre-push\")\n .option(\"--dry-run\", \"Hiển thị danh sách sẽ xóa, không thực thi\")\n .action(async (opts: UninstallOptions) => {\n try {\n await runUninstall(opts);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runUninstall(opts: UninstallOptions): Promise<void> {\n const projectRoot = process.cwd();\n const artifacts = detectAvatarProjectArtifacts(projectRoot);\n\n if (!artifacts.hasAnyArtifact) {\n log.info(\"Project chưa cài Avatar — không có gì để gỡ.\");\n return;\n }\n\n // Show summary.\n printUninstallSummary(projectRoot, artifacts, opts);\n\n if (opts.dryRun) {\n log.dim(\"--dry-run: kết thúc, không xóa.\");\n return;\n }\n\n // Confirm.\n if (!opts.yes) {\n const ok = await confirm({\n message: \"Tiếp tục gỡ Avatar?\",\n default: false,\n });\n if (!ok) {\n log.info(\"Đã hủy.\");\n return;\n }\n }\n\n // Backup (trừ khi --no-backup).\n let backupPath: string | null = null;\n if (!opts.noBackup) {\n backupPath = await createUninstallBackupSnapshot(projectRoot, artifacts, CLI_VERSION);\n log.success(`Backup tạo tại: ${backupPath}`);\n }\n\n // Delete artifacts.\n await executeUninstallDeletion(artifacts, {\n keepSubmodule: opts.keepSubmodule,\n keepHooks: opts.keepHooks,\n });\n\n await appendAuditEntry(\"uninstall\", `project=${projectRoot},backup=${backupPath ?? \"skipped\"}`);\n\n printUninstallSuccessBox(backupPath);\n}\n\nfunction printUninstallSummary(\n projectRoot: string,\n artifacts: ReturnType<typeof detectAvatarProjectArtifacts>,\n opts: UninstallOptions,\n): void {\n log.info(`Project: ${projectRoot}`);\n log.plain(\"\");\n log.plain(\"Các artifact sẽ gỡ:\");\n if (artifacts.claudeDir)\n log.plain(` ${chalk.red(\"✗\")} ${relative(projectRoot, artifacts.claudeDir) || \".claude/\"}`);\n if (artifacts.claudeMd) log.plain(` ${chalk.red(\"✗\")} CLAUDE.md`);\n if (artifacts.postMergeHook && !opts.keepHooks) {\n log.plain(` ${chalk.red(\"✗\")} .git/hooks/post-merge`);\n }\n if (artifacts.prePushHook && !opts.keepHooks) {\n log.plain(` ${chalk.red(\"✗\")} .git/modules/src/hooks/pre-push`);\n }\n if (artifacts.gitignorePath) log.plain(` ${chalk.yellow(\"✎\")} .gitignore (gỡ Avatar block)`);\n if (artifacts.gitmodulesPath && !opts.keepSubmodule) {\n log.plain(` ${chalk.yellow(\"✎\")} .gitmodules (gỡ entry .claude/pack)`);\n }\n log.plain(\"\");\n log.plain(\"Không đụng:\");\n log.plain(` ${chalk.green(\"✓\")} src/ (code khách)`);\n log.plain(` ${chalk.green(\"✓\")} Git history`);\n log.plain(` ${chalk.green(\"✓\")} ~/.avatar/config.json (token SSO)`);\n log.plain(` ${chalk.green(\"✓\")} Secrets trong keychain`);\n log.plain(\"\");\n}\n\nfunction printUninstallSuccessBox(backupPath: string | null): void {\n const lines: string[] = [`${chalk.green(\"✓\")} Avatar đã được gỡ khỏi project`];\n if (backupPath) {\n lines.push(\"\");\n lines.push(` ${chalk.dim(\"Backup:\")} ${backupPath}`);\n lines.push(` ${chalk.dim(\"Restore:\")} ${chalk.cyan(`cp -r \"${backupPath}\"/* .`)}`);\n }\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n","// Tạo snapshot backup trước khi uninstall. Folder: ~/.avatar/uninstall-backups/\n// <project-name>-<ts>/ với cấu trúc trong spec doc.\nimport { cp, mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { AvatarProjectArtifacts } from \"./detect-avatar-project-artifacts.js\";\n\nexport interface BackupManifest {\n projectName: string;\n projectPath: string;\n timestamp: string;\n avatarVersion: string;\n artifacts: {\n claudeDir: boolean;\n claudeMd: boolean;\n postMergeHook: boolean;\n prePushHook: boolean;\n };\n}\n\nconst UNINSTALL_BACKUPS_DIR = join(homedir(), \".avatar\", \"uninstall-backups\");\n\nexport async function createUninstallBackupSnapshot(\n projectRoot: string,\n artifacts: AvatarProjectArtifacts,\n avatarVersion: string,\n): Promise<string> {\n const projectName = basename(projectRoot);\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backupDir = join(UNINSTALL_BACKUPS_DIR, `${projectName}-${timestamp}`);\n\n await mkdir(backupDir, { recursive: true, mode: 0o700 });\n\n // Copy .claude/ và CLAUDE.md nếu tồn tại.\n if (artifacts.claudeDir) {\n await cp(artifacts.claudeDir, join(backupDir, \".claude\"), { recursive: true });\n }\n if (artifacts.claudeMd) {\n await cp(artifacts.claudeMd, join(backupDir, \"CLAUDE.md\"));\n }\n\n // Copy hooks sang backup/hooks/.\n if (artifacts.postMergeHook || artifacts.prePushHook) {\n const hooksBackupDir = join(backupDir, \"hooks\");\n await mkdir(hooksBackupDir, { recursive: true });\n if (artifacts.postMergeHook) {\n await cp(artifacts.postMergeHook, join(hooksBackupDir, \"post-merge\"));\n }\n if (artifacts.prePushHook) {\n await cp(artifacts.prePushHook, join(hooksBackupDir, \"pre-push\"));\n }\n }\n\n // Write manifest.\n const manifest: BackupManifest = {\n projectName,\n projectPath: projectRoot,\n timestamp,\n avatarVersion,\n artifacts: {\n claudeDir: !!artifacts.claudeDir,\n claudeMd: !!artifacts.claudeMd,\n postMergeHook: !!artifacts.postMergeHook,\n prePushHook: !!artifacts.prePushHook,\n },\n };\n await writeFile(join(backupDir, \"manifest.json\"), JSON.stringify(manifest, null, 2), \"utf8\");\n\n return backupDir;\n}\n","// Scan project root để liệt kê các file/folder Avatar đã tạo. Output là blueprint\n// cho uninstall: cái gì sẽ xóa + cái gì sẽ edit (gitignore, gitmodules).\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface AvatarProjectArtifacts {\n hasAnyArtifact: boolean;\n claudeDir: string | null; // .claude/\n claudeMd: string | null; // CLAUDE.md\n postMergeHook: string | null; // .git/hooks/post-merge\n prePushHook: string | null; // .git/modules/src/hooks/pre-push\n gitignorePath: string | null; // .gitignore (nếu có Avatar block)\n gitmodulesPath: string | null; // .gitmodules (nếu có submodule .claude/pack)\n notesDir: string | null; // notes/ (workspace mode)\n scriptsDir: string | null; // scripts/ (workspace mode)\n}\n\nfunction existsOrNull(path: string): string | null {\n return existsSync(path) ? path : null;\n}\n\nexport function detectAvatarProjectArtifacts(projectRoot: string): AvatarProjectArtifacts {\n const claudeDir = existsOrNull(join(projectRoot, \".claude\"));\n const claudeMd = existsOrNull(join(projectRoot, \"CLAUDE.md\"));\n const postMergeHook = existsOrNull(join(projectRoot, \".git\", \"hooks\", \"post-merge\"));\n const prePushHook = existsOrNull(\n join(projectRoot, \".git\", \"modules\", \"src\", \"hooks\", \"pre-push\"),\n );\n const gitignorePath = existsOrNull(join(projectRoot, \".gitignore\"));\n const gitmodulesPath = existsOrNull(join(projectRoot, \".gitmodules\"));\n const notesDir = existsOrNull(join(projectRoot, \"notes\"));\n const scriptsDir = existsOrNull(join(projectRoot, \"scripts\"));\n\n const hasAnyArtifact = !!(claudeDir || claudeMd || postMergeHook || prePushHook);\n\n return {\n hasAnyArtifact,\n claudeDir,\n claudeMd,\n postMergeHook,\n prePushHook,\n gitignorePath,\n gitmodulesPath,\n notesDir,\n scriptsDir,\n };\n}\n","// Atomic delete các artifact Avatar khỏi project. Gỡ marker block trong\n// .gitignore, remove submodule entry trong .gitmodules. Không đụng src/ + git\n// history + user config.\nimport { readFile, rm, writeFile } from \"node:fs/promises\";\nimport type { AvatarProjectArtifacts } from \"./detect-avatar-project-artifacts.js\";\nimport { AVATAR_MARKER_END, AVATAR_MARKER_START } from \"./gitignore-template-loader.js\";\n\nexport interface UninstallFlags {\n keepSubmodule?: boolean;\n keepHooks?: boolean;\n}\n\nexport async function executeUninstallDeletion(\n artifacts: AvatarProjectArtifacts,\n flags: UninstallFlags,\n): Promise<void> {\n // Delete .claude/ (trừ khi --keep-submodule muốn giữ pack/ — thực tế cả\n // .claude/ chứa nhiều thứ khác, nên --keep-submodule chỉ giữ pack/).\n if (artifacts.claudeDir) {\n if (flags.keepSubmodule) {\n // Chỉ xóa các file/folder không phải pack/ trong .claude/.\n const { readdir } = await import(\"node:fs/promises\");\n const { join } = await import(\"node:path\");\n const entries = await readdir(artifacts.claudeDir);\n for (const entry of entries) {\n if (entry === \"pack\") continue;\n await rm(join(artifacts.claudeDir, entry), { recursive: true, force: true });\n }\n } else {\n await rm(artifacts.claudeDir, { recursive: true, force: true });\n }\n }\n\n if (artifacts.claudeMd) {\n await rm(artifacts.claudeMd, { force: true });\n }\n\n if (!flags.keepHooks) {\n if (artifacts.postMergeHook) await rm(artifacts.postMergeHook, { force: true });\n if (artifacts.prePushHook) await rm(artifacts.prePushHook, { force: true });\n }\n\n // Strip Avatar block khỏi .gitignore (giữ rest).\n if (artifacts.gitignorePath) {\n await stripAvatarBlockFromGitignore(artifacts.gitignorePath);\n }\n\n // Remove submodule entry .claude/pack khỏi .gitmodules (nếu xóa cả pack).\n if (artifacts.gitmodulesPath && !flags.keepSubmodule) {\n await removeSubmoduleEntry(artifacts.gitmodulesPath, \".claude/pack\");\n }\n\n // Workspace mode có notes/, scripts/. Chỉ xóa nếu rỗng (user có thể đã add file).\n for (const dir of [artifacts.notesDir, artifacts.scriptsDir]) {\n if (!dir) continue;\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(dir);\n if (entries.length === 0) {\n await rm(dir, { recursive: true, force: true });\n }\n }\n}\n\nasync function stripAvatarBlockFromGitignore(path: string): Promise<void> {\n const content = await readFile(path, \"utf8\");\n const startIdx = content.indexOf(AVATAR_MARKER_START);\n const endIdx = content.indexOf(AVATAR_MARKER_END);\n if (startIdx === -1 || endIdx === -1) return;\n\n const before = content.slice(0, startIdx);\n const after = content.slice(endIdx + AVATAR_MARKER_END.length);\n const cleaned = `${before.trimEnd()}\\n${after.trimStart()}`.trim();\n if (cleaned.length === 0) {\n await rm(path, { force: true });\n } else {\n await writeFile(path, `${cleaned}\\n`, \"utf8\");\n }\n}\n\nasync function removeSubmoduleEntry(gitmodulesPath: string, submodulePath: string): Promise<void> {\n const content = await readFile(gitmodulesPath, \"utf8\");\n const lines = content.split(\"\\n\");\n const result: string[] = [];\n let skip = false;\n for (const line of lines) {\n if (line.trim().startsWith(\"[submodule\") && line.includes(submodulePath)) {\n skip = true;\n continue;\n }\n if (skip && line.trim().startsWith(\"[submodule\")) {\n skip = false;\n }\n if (!skip) result.push(line);\n }\n const cleaned = result.join(\"\\n\").trim();\n if (cleaned.length === 0) {\n await rm(gitmodulesPath, { force: true });\n } else {\n await writeFile(gitmodulesPath, `${cleaned}\\n`, \"utf8\");\n }\n}\n"],"mappings":"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","names":["program","fs","join","join","join","join","fs","join","dirname","join","dirname","join","fs","join","relative","join","join","fs","program","join","fs","join","relative","boxen","fs","fs","chalk","spawnSync","input","spawnSync","input","spawnSync","spawnSync","spawnSync","platform","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","input","spawnSync","existsSync","join","simpleGit","existsSync","join","dirname","join","fileURLToPath","existsSync","readFileSync","join","join","existsSync","readFileSync","join","join","join","join","program","join","relative","boxen","boxen","program","boxen","resolve","program","program","program","program","program","fs","join","boxen","fs","join","join","fs","AVATAR_CLI_VERSION","program","join","fs","boxen","program","program","relative","confirm","boxen","homedir","basename","join","existsSync","join","writeFile","readdir","join","writeFile","program","confirm","relative","boxen","CLI_VERSION"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/ai.ts","../src/lib/filesystem-helpers.ts","../src/lib/audit-log-appender.ts","../src/lib/user-config-store.ts","../src/types/config-schema.ts","../src/lib/check-claude-code-subscription-and-quota.ts","../src/lib/terminal-logger.ts","../src/lib/detect-claude-code-installation.ts","../src/lib/detect-host-platform.ts","../src/lib/install-claude-code-via-npm.ts","../src/lib/prompt-ai-provider-choice.ts","../src/lib/setup-llmlite-api-key-and-model.ts","../src/lib/write-claude-settings-json-per-project.ts","../src/lib/run-ai-setup-phase.ts","../src/lib/not-implemented-stub.ts","../src/commands/commit.ts","../src/commands/doctor.ts","../src/lib/git-operations.ts","../src/lib/project-tree-scaffolder.ts","../src/lib/template-bundle-loader.ts","../src/lib/mustache-template-engine.ts","../src/commands/init.ts","../src/lib/avatar-ascii-banner.ts","../src/lib/execute-gh-repo-create.ts","../src/lib/resolve-github-username-default.ts","../src/lib/validate-repo-name-and-visibility.ts","../src/lib/create-github-remote-from-folder.ts","../src/lib/create-workspace-remote-via-gh.ts","../src/lib/check-gh-cli-auth-status.ts","../src/lib/detect-package-manager.ts","../src/lib/install-gh-cli-via-package-manager.ts","../src/lib/setup-git-credential-via-gh.ts","../src/lib/trigger-gh-cli-auth-login.ts","../src/lib/verify-git-remote-accessible.ts","../src/lib/git-auth-and-install-orchestrator.ts","../src/lib/safe-bootstrap-for-dirty-folder.ts","../src/lib/check-folder-has-git.ts","../src/lib/create-initial-git-commit.ts","../src/lib/detect-folder-tech-stack.ts","../src/lib/gitignore-template-loader.ts","../src/lib/write-or-merge-gitignore.ts","../src/lib/team-pack-submodule-manager.ts","../src/lib/resolve-team-pack-repo-url.ts","../src/commands/init-conflict-detection-helpers.ts","../src/commands/init-scaffold-variable-builders.ts","../src/commands/login.ts","../src/lib/google-oauth-device-flow.ts","../src/commands/mcp-run.ts","../src/commands/restore.ts","../src/commands/review.ts","../src/commands/scan.ts","../src/commands/secrets.ts","../src/commands/status.ts","../src/lib/pack-backup-manager.ts","../src/commands/sync.ts","../src/commands/tools.ts","../src/commands/uninstall.ts","../src/lib/create-uninstall-backup-snapshot.ts","../src/lib/detect-avatar-project-artifacts.ts","../src/lib/execute-uninstall-deletion.ts"],"sourcesContent":["// Bootstrap: load commander, register all 14 subcommands, parse argv.\n// Each command lives in src/commands/<name>.ts as a function that accepts the\n// commander Command instance and registers itself.\nimport { Command } from \"commander\";\nimport { registerAiCommand } from \"./commands/ai.js\";\nimport { registerCommitCommand } from \"./commands/commit.js\";\nimport { registerDoctorCommand } from \"./commands/doctor.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerLoginCommand } from \"./commands/login.js\";\nimport { registerMcpRunCommand } from \"./commands/mcp-run.js\";\nimport { registerRestoreCommand } from \"./commands/restore.js\";\nimport { registerReviewCommand } from \"./commands/review.js\";\nimport { registerScanCommand } from \"./commands/scan.js\";\nimport { registerSecretsCommand } from \"./commands/secrets.js\";\nimport { registerStatusCommand } from \"./commands/status.js\";\nimport { registerSyncCommand } from \"./commands/sync.js\";\nimport { registerToolsCommand } from \"./commands/tools.js\";\nimport { registerUninstallCommand } from \"./commands/uninstall.js\";\nimport { printAvatarBanner, renderAvatarBanner } from \"./lib/avatar-ascii-banner.js\";\n\nconst CLI_VERSION = \"1.2.0\";\n\nconst program = new Command();\n\nprogram\n .name(\"avatar\")\n .description(\"AI harness CLI for NAL Vietnam engineering\")\n .version(CLI_VERSION, \"-v, --version\", \"Hiển thị phiên bản Avatar CLI\")\n // Override mặc định của commander để in banner kèm version. Commander cho phép\n // custom output qua configureOutput nhưng cách đơn giản nhất là intercept ở argv.\n .addHelpText(\n \"beforeAll\",\n () =>\n `\\n${renderAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` })}\\n\\n`,\n );\n\n// In banner khi user gọi `avatar -v` / `avatar --version`. Banner đã chứa\n// version trong tagline nên ta short-circuit luôn, không để commander in thêm\n// dòng \"1.0.1\" dư thừa.\nconst isVersionCall = process.argv.includes(\"-v\") || process.argv.includes(\"--version\");\nif (isVersionCall) {\n printAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` });\n process.exit(0);\n}\n\n// Register all commands. Order matches Chapter 09 spec in implementation doc.\nregisterLoginCommand(program);\nregisterInitCommand(program);\nregisterSyncCommand(program);\nregisterScanCommand(program);\nregisterReviewCommand(program);\nregisterStatusCommand(program);\nregisterDoctorCommand(program);\nregisterRestoreCommand(program);\nregisterCommitCommand(program);\nregisterToolsCommand(program);\nregisterSecretsCommand(program);\nregisterMcpRunCommand(program);\nregisterAiCommand(program);\nregisterUninstallCommand(program);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n // Top-level error sink. Individual commands should handle their own errors;\n // anything reaching here is unexpected.\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`✗ Lỗi không xử lý được: ${msg}\\n`);\n process.exit(1);\n});\n","// `avatar ai` — Quản lý AI provider config per-workspace (M12).\n// 4 subcommand:\n// - setup : Wizard re-config (reuse runAiSetupPhase từ phase 07)\n// - status : Show provider/model/baseUrl/token-mask hiện tại\n// - test : Cheap prompt verify provider work\n// - reset : Strip env.ANTHROPIC_* khỏi settings.json (về dùng default subscription)\n//\n// Cần chạy trong workspace dir (có `.claude/`). Nếu không → exit 1 với hint.\nimport { spawnSync } from \"node:child_process\";\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { confirm } from \"@inquirer/prompts\";\nimport type { Command } from \"commander\";\nimport { pathExists, readJson, writeJsonAtomic } from \"../lib/filesystem-helpers.js\";\nimport { runAiSetupPhase } from \"../lib/run-ai-setup-phase.js\";\nimport { maskApiKey } from \"../lib/setup-llmlite-api-key-and-model.js\";\nimport { log } from \"../lib/terminal-logger.js\";\n\n// Check workspace context — current dir phải có .claude/. Nếu không, exit với hint.\nasync function ensureWorkspaceCwd(): Promise<string> {\n const cwd = process.cwd();\n const claudeDir = join(cwd, \".claude\");\n if (!(await pathExists(claudeDir))) {\n log.error(\"Không thấy .claude/ trong thư mục hiện tại. Chạy lệnh này trong workspace Avatar.\");\n process.exit(1);\n }\n return cwd;\n}\n\n// Read settings.json hiện có. Trả {} nếu chưa có file (subscription default state).\nasync function readWorkspaceSettings(workspacePath: string): Promise<Record<string, unknown>> {\n const settingsPath = join(workspacePath, \".claude\", \"settings.json\");\n if (!(await pathExists(settingsPath))) return {};\n try {\n return await readJson<Record<string, unknown>>(settingsPath);\n } catch {\n return {};\n }\n}\n\n// === setup ===\nasync function runAiSetup(): Promise<void> {\n const workspacePath = await ensureWorkspaceCwd();\n await runAiSetupPhase({ workspacePath });\n}\n\n// === status ===\nasync function runAiStatus(): Promise<void> {\n const workspacePath = await ensureWorkspaceCwd();\n const settings = await readWorkspaceSettings(workspacePath);\n const env = (settings.env as Record<string, unknown> | undefined) || {};\n const baseUrl = typeof env.ANTHROPIC_BASE_URL === \"string\" ? env.ANTHROPIC_BASE_URL : undefined;\n const token = typeof env.ANTHROPIC_AUTH_TOKEN === \"string\" ? env.ANTHROPIC_AUTH_TOKEN : undefined;\n const model = typeof settings.model === \"string\" ? settings.model : undefined;\n\n const provider = baseUrl ? \"LLMLite\" : token ? \"Custom\" : \"Subscription (default)\";\n log.info(`Project: ${workspacePath}`);\n log.info(`Provider: ${provider}${baseUrl ? ` (${baseUrl})` : \"\"}`);\n log.info(`Model: ${model ?? \"(default — Claude Code chọn)\"}`);\n log.info(`Token: ${token ? maskApiKey(token) : \"(không set — dùng subscription auth)\"}`);\n}\n\n// === test ===\nasync function runAiTest(): Promise<void> {\n await ensureWorkspaceCwd();\n log.info(\"Calling provider với prompt 'say ok'...\");\n const result = spawnSync(\"claude\", [\"--print\", \"say ok\"], {\n encoding: \"utf8\",\n timeout: 30_000,\n });\n\n if (result.signal === \"SIGTERM\") {\n log.error(\"Timeout sau 30s. Check mạng / endpoint.\");\n process.exit(1);\n }\n if (result.status !== 0) {\n log.error(`Test thất bại (exit ${result.status}).`);\n if (result.stderr) process.stderr.write(`${result.stderr}\\n`);\n process.exit(1);\n }\n log.success(`Response: ${(result.stdout || \"\").trim().slice(0, 200)}`);\n log.success(\"AI provider working\");\n}\n\n// === reset ===\nasync function runAiReset(opts: { yes?: boolean }): Promise<void> {\n const workspacePath = await ensureWorkspaceCwd();\n const settingsPath = join(workspacePath, \".claude\", \"settings.json\");\n const settings = await readWorkspaceSettings(workspacePath);\n\n if (!opts.yes) {\n const ok = await confirm({\n message: \"Xóa AI config (về dùng Claude Code Subscription default)?\",\n default: false,\n });\n if (!ok) {\n log.dim(\"Đã hủy.\");\n return;\n }\n }\n\n // Rebuild settings không có env.ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN.\n const { env: existingEnv, ...rest } = settings as { env?: Record<string, unknown> };\n const reset: Record<string, unknown> = { ...rest };\n if (existingEnv) {\n const { ANTHROPIC_BASE_URL: _b, ANTHROPIC_AUTH_TOKEN: _t, ...envRest } = existingEnv;\n if (Object.keys(envRest).length > 0) {\n reset.env = envRest;\n }\n }\n\n // Nếu sau strip object rỗng → xóa file luôn (clean state).\n if (Object.keys(reset).length === 0) {\n await fs.unlink(settingsPath).catch(() => {});\n log.success(\"Đã xóa .claude/settings.json (clean state)\");\n } else {\n await writeJsonAtomic(settingsPath, reset, 0o600);\n log.success(\"Đã reset env block trong .claude/settings.json\");\n }\n}\n\nexport function registerAiCommand(program: Command): void {\n const ai = program.command(\"ai\").description(\"Quản lý AI provider config (M12)\");\n\n ai.command(\"setup\")\n .description(\"Wizard setup/re-config AI provider cho workspace hiện tại\")\n .action(async () => {\n await runAiSetup();\n });\n\n ai.command(\"status\")\n .description(\"Show AI config hiện tại (mask token)\")\n .action(async () => {\n await runAiStatus();\n });\n\n ai.command(\"test\")\n .description(\"Verify AI provider qua cheap prompt\")\n .action(async () => {\n await runAiTest();\n });\n\n ai.command(\"reset\")\n .description(\"Xóa env.ANTHROPIC_* khỏi settings.json (về Subscription default)\")\n .option(\"--yes\", \"Skip confirm\")\n .action(async (opts: { yes?: boolean }) => {\n await runAiReset(opts);\n });\n}\n","// Thin promise-based wrappers around node:fs/promises with the patterns Avatar\n// uses most: ensure-dir, read-text, write-text-atomic, copy-dir-recursive.\n// Atomic write writes to a temp file then renames to avoid corruption if Avatar\n// crashes mid-write.\nimport { constants, promises as fs } from \"node:fs\";\nimport { dirname, join, relative } from \"node:path\";\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await fs.access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDir(path: string): Promise<void> {\n await fs.mkdir(path, { recursive: true });\n}\n\nexport async function readText(path: string): Promise<string> {\n return await fs.readFile(path, \"utf8\");\n}\n\nexport async function readJson<T>(path: string): Promise<T> {\n return JSON.parse(await readText(path)) as T;\n}\n\n// Atomic write: write to temp file then rename. Prevents corruption if process\n// is killed between open() and close(). chmod is applied AFTER rename.\nexport async function writeTextAtomic(path: string, content: string, mode?: number): Promise<void> {\n await ensureDir(dirname(path));\n const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n await fs.writeFile(tmp, content, \"utf8\");\n if (mode !== undefined) {\n await fs.chmod(tmp, mode);\n }\n await fs.rename(tmp, path);\n}\n\nexport async function writeJsonAtomic(path: string, data: unknown, mode?: number): Promise<void> {\n await writeTextAtomic(path, `${JSON.stringify(data, null, 2)}\\n`, mode);\n}\n\n// Recursive copy. excludeNames filters by basename at any depth (e.g. \".git\").\nexport async function copyDirRecursive(\n source: string,\n destination: string,\n excludeNames: string[] = [],\n): Promise<void> {\n await ensureDir(destination);\n const entries = await fs.readdir(source, { withFileTypes: true });\n for (const entry of entries) {\n if (excludeNames.includes(entry.name)) continue;\n const src = join(source, entry.name);\n const dst = join(destination, entry.name);\n if (entry.isDirectory()) {\n await copyDirRecursive(src, dst, excludeNames);\n } else if (entry.isSymbolicLink()) {\n const target = await fs.readlink(src);\n await fs.symlink(target, dst);\n } else {\n await fs.copyFile(src, dst);\n }\n }\n}\n\nexport async function removeRecursive(path: string): Promise<void> {\n await fs.rm(path, { recursive: true, force: true });\n}\n\nexport function relativeFromCwd(path: string): string {\n return relative(process.cwd(), path);\n}\n","// Append-only audit log at ~/.avatar/audit.log. Records sensitive actions\n// (secrets set/rm, tool install/remove) WITHOUT logging secret values.\n// Used by `avatar doctor` to surface recent activity.\nimport { promises as fs } from \"node:fs\";\nimport { AUDIT_LOG_PATH, ensureAvatarHome } from \"./user-config-store.js\";\n\nexport type AuditAction =\n | \"login\"\n | \"login_reset\"\n | \"logout\"\n | \"secret_set\"\n | \"secret_rm\"\n | \"tool_install\"\n | \"tool_remove\"\n | \"init\"\n | \"sync\"\n | \"restore\";\n\nexport interface AuditEntry {\n timestamp: string;\n action: AuditAction;\n detail?: string;\n}\n\nexport async function appendAuditEntry(action: AuditAction, detail?: string): Promise<void> {\n await ensureAvatarHome();\n const entry: AuditEntry = {\n timestamp: new Date().toISOString(),\n action,\n ...(detail ? { detail } : {}),\n };\n const line = `${JSON.stringify(entry)}\\n`;\n await fs.appendFile(AUDIT_LOG_PATH, line, \"utf8\");\n}\n","// Read/write ~/.avatar/config.json (OAuth credentials) and ~/.avatar/state.json\n// (non-credential user state). Validates with Zod, enforces chmod 600 on config.\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n type UserConfig,\n type UserState,\n userConfigSchema,\n userStateSchema,\n} from \"../types/config-schema.js\";\nimport { ensureDir, pathExists, readJson, writeJsonAtomic } from \"./filesystem-helpers.js\";\n\nexport const AVATAR_HOME = join(homedir(), \".avatar\");\nexport const USER_CONFIG_PATH = join(AVATAR_HOME, \"config.json\");\nexport const USER_STATE_PATH = join(AVATAR_HOME, \"state.json\");\nexport const AUDIT_LOG_PATH = join(AVATAR_HOME, \"audit.log\");\nexport const BACKUPS_DIR = join(AVATAR_HOME, \"backups\");\n\n// chmod 600 — owner-only read/write. Matches spec for credential files.\nconst SECRET_FILE_MODE = 0o600;\n\nexport async function ensureAvatarHome(): Promise<void> {\n await ensureDir(AVATAR_HOME);\n}\n\nexport async function readUserConfig(): Promise<UserConfig | null> {\n if (!(await pathExists(USER_CONFIG_PATH))) return null;\n const raw = await readJson<unknown>(USER_CONFIG_PATH);\n const parsed = userConfigSchema.safeParse(raw);\n if (!parsed.success) return null;\n return parsed.data;\n}\n\nexport async function writeUserConfig(config: UserConfig): Promise<void> {\n await ensureAvatarHome();\n await writeJsonAtomic(USER_CONFIG_PATH, config, SECRET_FILE_MODE);\n}\n\nexport async function clearUserConfig(): Promise<void> {\n if (await pathExists(USER_CONFIG_PATH)) {\n const { promises: fs } = await import(\"node:fs\");\n await fs.unlink(USER_CONFIG_PATH);\n }\n}\n\nexport async function readUserState(): Promise<UserState> {\n if (!(await pathExists(USER_STATE_PATH))) {\n return userStateSchema.parse({});\n }\n const raw = await readJson<unknown>(USER_STATE_PATH);\n const parsed = userStateSchema.safeParse(raw);\n if (!parsed.success) return userStateSchema.parse({});\n return parsed.data;\n}\n\nexport async function writeUserState(state: UserState): Promise<void> {\n await ensureAvatarHome();\n await writeJsonAtomic(USER_STATE_PATH, state);\n}\n\n// Token is considered expired if it would expire in the next 60 seconds.\n// 60s buffer accounts for slow network round-trip on the upcoming request.\nexport function isTokenExpired(config: UserConfig): boolean {\n const expiresAt = Date.parse(config.expires_at);\n return Number.isNaN(expiresAt) || expiresAt - Date.now() < 60_000;\n}\n","// Zod schemas + inferred TypeScript types for all on-disk Avatar config files.\n// Centralised so commands import from one place and validation matches storage.\nimport { z } from \"zod\";\n\n// ~/.avatar/config.json — OAuth credentials after `avatar login`.\n// chmod 600 enforced at write site.\nexport const userConfigSchema = z.object({\n email: z.string().email(),\n name: z.string(),\n access_token: z.string().min(1),\n refresh_token: z.string().min(1),\n expires_at: z.string().datetime(),\n id_token: z.string().min(1),\n});\nexport type UserConfig = z.infer<typeof userConfigSchema>;\n\n// ~/.avatar/state.json — non-credential user state (tool install records,\n// allowed-paths chosen for filesystem MCP, etc).\nexport const userStateSchema = z.object({\n installed_tools: z\n .record(\n z.string(),\n z.object({\n version: z.string().optional(),\n installed_at: z.string().datetime(),\n install_method: z.string(),\n }),\n )\n .default({}),\n tool_inputs: z.record(z.string(), z.unknown()).default({}),\n});\nexport type UserState = z.infer<typeof userStateSchema>;\n\n// .claude/settings.json — per-project Claude Code settings emitted by `avatar init`.\nexport const projectSettingsSchema = z.object({\n allowedTools: z.array(z.string()),\n hooks: z\n .object({\n PostToolUse: z.array(z.unknown()).optional(),\n })\n .partial()\n .optional(),\n env: z.record(z.string(), z.string()).default({}),\n});\nexport type ProjectSettings = z.infer<typeof projectSettingsSchema>;\n\n// Init mode — determines workspace topology (Chapter 02 + Chapter 07 spec).\nexport const initModeSchema = z.enum([\"internal\", \"client\", \"library\"]);\nexport type InitMode = z.infer<typeof initModeSchema>;\n","// Subscription path (Anthropic Pro/Team plan) — 3 step verify:\n// 1) checkClaudeCodeSubscriptionAuth() — `claude auth status` exit code\n// 2) triggerClaudeCodeAuthLogin() — `claude auth login` interactive (browser)\n// 3) verifyClaudeCodeQuota() — cheap prompt detect free-tier no-quota\n// Mục đích phase 03: đảm bảo claude binary có thể chạy thật trước khi ghi settings.\nimport { spawnSync } from \"node:child_process\";\nimport { log } from \"./terminal-logger.js\";\n\nexport type ClaudeCodeAuthState = \"authenticated\" | \"not-authenticated\";\n\nexport interface ClaudeCodeQuotaResult {\n ok: boolean;\n // Reason code chuẩn hóa để caller branch: \"credit_balance_too_low\" | \"insufficient_quota\"\n // | \"invalid_api_key\" | \"rate_limit\" | \"timeout\" | \"unknown\"\n reason?: string;\n // Raw stderr/stdout sample để debug.\n detail?: string;\n}\n\n// Quota verify timeout — claude --print API call thông thường < 5s, để 30s an toàn.\nconst QUOTA_VERIFY_TIMEOUT_MS = 30_000;\n\n// Cheap prompt: max_tokens nhỏ + nội dung tối giản. Cost ~$0.0001 trên Sonnet.\nconst QUOTA_VERIFY_PROMPT = \"ok\";\n\n// Step 1: check `claude auth status` exit code.\nexport function checkClaudeCodeSubscriptionAuth(): ClaudeCodeAuthState {\n const result = spawnSync(\"claude\", [\"auth\", \"status\"], { stdio: \"ignore\" });\n if (result.error || result.status !== 0) return \"not-authenticated\";\n return \"authenticated\";\n}\n\n// Step 2: trigger `claude auth login` interactive — block đến khi user complete trên browser.\n// Throws nếu spawn fail / user cancel (exit non-zero).\nexport function triggerClaudeCodeAuthLogin(): void {\n log.info(\"Khởi động đăng nhập Claude Code (browser sẽ mở)...\");\n const result = spawnSync(\"claude\", [\"auth\", \"login\"], { stdio: \"inherit\" });\n if (result.status !== 0) {\n throw new Error(\n `claude auth login thất bại (exit ${result.status}). Thử 'claude auth login' tay rồi chạy lại.`,\n );\n }\n log.success(\"Đã đăng nhập Claude Code\");\n}\n\n// Map error keyword → reason code chuẩn hóa.\n// Order quan trọng: check specific trước generic.\nfunction classifyQuotaError(combinedOutput: string): string {\n const text = combinedOutput.toLowerCase();\n if (text.includes(\"credit_balance_too_low\") || text.includes(\"credit balance too low\")) {\n return \"credit_balance_too_low\";\n }\n if (text.includes(\"insufficient_quota\") || text.includes(\"insufficient quota\")) {\n return \"insufficient_quota\";\n }\n if (text.includes(\"invalid_api_key\") || text.includes(\"invalid api key\")) {\n return \"invalid_api_key\";\n }\n if (text.includes(\"rate_limit\") || text.includes(\"rate limit\")) {\n return \"rate_limit\";\n }\n return \"unknown\";\n}\n\n// Step 3: verify quota qua cheap prompt. Trả structured result.\n// Không throw — caller cần ok/reason để decide branch (warn + suggest LLMLite).\nexport function verifyClaudeCodeQuota(): ClaudeCodeQuotaResult {\n const result = spawnSync(\"claude\", [\"--print\", QUOTA_VERIFY_PROMPT], {\n encoding: \"utf8\",\n timeout: QUOTA_VERIFY_TIMEOUT_MS,\n });\n\n if (result.signal === \"SIGTERM\") {\n return { ok: false, reason: \"timeout\", detail: \"claude --print > 30s\" };\n }\n\n const stderr = result.stderr || \"\";\n const stdout = result.stdout || \"\";\n\n if (result.status === 0) {\n // Claude trả response — quota OK.\n return { ok: true };\n }\n\n // Exit non-zero — parse stderr để classify.\n const reason = classifyQuotaError(`${stderr}\\n${stdout}`);\n return { ok: false, reason, detail: stderr.slice(0, 500) };\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","// Detect Claude Code CLI (\"claude\" binary) trên PATH + parse SemVer version.\n// Trả structured info để các module sau (install / auth-check) decide flow.\n// Cross-platform: Unix dùng `command -v`, Windows dùng `where`.\nimport { spawnSync } from \"node:child_process\";\nimport { detectHostPlatform } from \"./detect-host-platform.js\";\n\nexport interface ClaudeCodeInstallationInfo {\n installed: boolean;\n version: string | null; // SemVer string khi detect được, vd \"1.2.3\"\n path: string | null; // Absolute path đến binary nếu tìm thấy\n}\n\n// Timeout cho `claude --version` — nếu binary hang thì abort tránh block init.\nconst VERSION_PROBE_TIMEOUT_MS = 5000;\n\n// Regex SemVer chấp nhận extra suffix vd \"1.2.3 (Claude Code)\" hoặc \"claude 1.2.3\".\nconst SEMVER_REGEX = /(\\d+\\.\\d+\\.\\d+)/;\n\n// Probe binary location qua `command -v` (POSIX) hoặc `where` (Windows).\n// Trả về absolute path nếu tìm thấy, null nếu không.\nfunction probeClaudeBinaryPath(): string | null {\n const isWindows = detectHostPlatform() === \"win32\";\n const probeCmd = isWindows ? \"where\" : \"command\";\n const probeArgs = isWindows ? [\"claude\"] : [\"-v\", \"claude\"];\n\n // `command` là shell builtin nên cần shell:true trên POSIX. `where` là exe thật.\n const result = spawnSync(probeCmd, probeArgs, {\n encoding: \"utf8\",\n shell: !isWindows,\n });\n\n if (result.error || result.status !== 0) return null;\n const out = (result.stdout || \"\").trim();\n if (!out) return null;\n // `where` có thể list nhiều dòng — lấy dòng đầu.\n return out.split(/\\r?\\n/)[0].trim();\n}\n\n// Parse `claude --version` output → SemVer. Null nếu không match.\nfunction probeClaudeVersion(): string | null {\n const result = spawnSync(\"claude\", [\"--version\"], {\n encoding: \"utf8\",\n timeout: VERSION_PROBE_TIMEOUT_MS,\n });\n\n if (result.error || result.status !== 0) return null;\n const out = (result.stdout || \"\").trim();\n const match = SEMVER_REGEX.exec(out);\n return match ? match[1] : null;\n}\n\n// Main API: detect Claude Code installation state.\n// Không throw — luôn return structured info để caller branch logic.\nexport function detectClaudeCodeInstallation(): ClaudeCodeInstallationInfo {\n const path = probeClaudeBinaryPath();\n if (!path) {\n return { installed: false, version: null, path: null };\n }\n const version = probeClaudeVersion();\n return { installed: true, version, path };\n}\n","// Wrapper mỏng quanh os.platform() để các module khác switch theo OS dễ hơn\n// và test dễ mock.\nimport { platform } from \"node:os\";\n\nexport type HostPlatform = \"darwin\" | \"linux\" | \"win32\" | \"unsupported\";\n\n// Trả về tên platform chuẩn hoá. Mọi giá trị khác 3 OS chính → \"unsupported\".\nexport function detectHostPlatform(): HostPlatform {\n const p = platform();\n if (p === \"darwin\" || p === \"linux\" || p === \"win32\") return p;\n return \"unsupported\";\n}\n","// Auto-install Claude Code CLI qua `npm install -g @anthropic-ai/claude-code`.\n// Stream stdio để user thấy npm progress. Sau khi cài xong → re-detect verify PATH.\n// Throws InstallClaudeCodeError với hint cụ thể cho EACCES / ENOSPC / generic.\nimport { spawnSync } from \"node:child_process\";\nimport { detectClaudeCodeInstallation } from \"./detect-claude-code-installation.js\";\nimport { log } from \"./terminal-logger.js\";\n\n// 5 phút — npm global install có thể chậm trên mạng yếu (registry resolve + download).\nconst NPM_INSTALL_TIMEOUT_MS = 5 * 60 * 1000;\n\n// Package name chính thức của Anthropic Claude Code CLI.\nconst CLAUDE_CODE_PACKAGE = \"@anthropic-ai/claude-code\";\n\nexport type InstallClaudeCodeReason =\n | \"permission-denied\" // EACCES → cần sudo hoặc fix npm prefix\n | \"disk-full\" // ENOSPC\n | \"timeout\" // > 5 phút\n | \"binary-not-in-path\" // install OK nhưng PATH chưa refresh\n | \"generic\"; // exit non-zero khác\n\nexport class InstallClaudeCodeError extends Error {\n reason: InstallClaudeCodeReason;\n exitCode: number | null;\n constructor(reason: InstallClaudeCodeReason, message: string, exitCode: number | null = null) {\n super(message);\n this.name = \"InstallClaudeCodeError\";\n this.reason = reason;\n this.exitCode = exitCode;\n }\n}\n\n// Phân loại exit từ npm install thành reason cụ thể để caller branch hint.\n// Hint hiển thị qua message, không log trực tiếp ở đây (separation of concerns).\nfunction classifyNpmFailure(exitCode: number | null, stderrSample: string): InstallClaudeCodeError {\n const stderr = stderrSample.toLowerCase();\n if (stderr.includes(\"eacces\") || stderr.includes(\"permission denied\")) {\n return new InstallClaudeCodeError(\n \"permission-denied\",\n `npm install -g cần quyền. Thử: sudo npm install -g ${CLAUDE_CODE_PACKAGE} hoặc fix npm prefix (npm config set prefix ~/.npm-global).`,\n exitCode,\n );\n }\n if (stderr.includes(\"enospc\") || stderr.includes(\"no space\")) {\n return new InstallClaudeCodeError(\n \"disk-full\",\n \"Đĩa đầy. Free disk space rồi thử lại.\",\n exitCode,\n );\n }\n return new InstallClaudeCodeError(\n \"generic\",\n `npm install thất bại (exit ${exitCode ?? \"null\"}). Xem log npm phía trên.`,\n exitCode,\n );\n}\n\n// Main API: cài Claude Code + verify. Throws InstallClaudeCodeError nếu fail.\n// Return version đã detect (luôn non-null nếu success vì re-detect verify SemVer).\nexport function installClaudeCodeViaNpm(): { version: string | null; path: string } {\n log.info(\"Đang cài Claude Code qua npm (có thể mất 1-2 phút)...\");\n\n // Pipe stderr để classify error sau, nhưng inherit stdout cho user thấy progress.\n // Note: stdio mixed array — [stdin, stdout, stderr].\n const result = spawnSync(\"npm\", [\"install\", \"-g\", CLAUDE_CODE_PACKAGE], {\n stdio: [\"inherit\", \"inherit\", \"pipe\"],\n timeout: NPM_INSTALL_TIMEOUT_MS,\n encoding: \"utf8\",\n });\n\n // Timeout case — Node set signal SIGTERM khi timeout.\n if (result.signal === \"SIGTERM\") {\n throw new InstallClaudeCodeError(\n \"timeout\",\n `npm install timeout sau ${NPM_INSTALL_TIMEOUT_MS / 1000}s. Check mạng rồi thử lại.`,\n null,\n );\n }\n\n if (result.status !== 0) {\n // In stderr ra để user thấy lỗi gốc trước khi throw.\n if (result.stderr) process.stderr.write(result.stderr);\n throw classifyNpmFailure(result.status, result.stderr || \"\");\n }\n\n // Re-detect — npm install OK không đồng nghĩa binary đã trong PATH (PATH cache).\n const probe = detectClaudeCodeInstallation();\n if (!probe.installed || !probe.path) {\n throw new InstallClaudeCodeError(\n \"binary-not-in-path\",\n \"npm cài xong nhưng `claude` không trong PATH. Reload shell (source ~/.zshrc) hoặc thêm npm global bin vào PATH.\",\n null,\n );\n }\n\n log.success(`Đã cài Claude Code${probe.version ? ` v${probe.version}` : \"\"} tại ${probe.path}`);\n return { version: probe.version, path: probe.path };\n}\n","// Wizard chọn AI provider cho workspace — hybrid logic:\n// 1) Nếu detect được ~/.claude/settings.json global có ANTHROPIC_BASE_URL + token\n// → hỏi user \"Dùng global hay setup riêng?\"\n// 2) Nếu user setup riêng (hoặc không có global) → hỏi \"Subscription / LLMLite?\"\n// Output: discriminated union — caller branch theo provider tiếp tục phase 03 (sub) hoặc 05 (llmlite).\nimport { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { select } from \"@inquirer/prompts\";\n\nexport type AiProviderChoice = \"use-global\" | \"subscription\" | \"llmlite\";\n\n// Snapshot info global config — KHÔNG return raw token (security).\n// Token presence chỉ check, value không expose ra UI / log / return.\nexport interface GlobalClaudeSettingsInfo {\n exists: boolean;\n hasBaseUrl: boolean;\n baseUrl?: string; // OK expose vì base URL là endpoint public (vd https://llm.nal.vn)\n hasToken: boolean;\n model?: string;\n rawSettings?: Record<string, unknown>; // Để caller (use-global path) copy\n}\n\n// Path mặc định Claude Code đọc settings — không config khác.\nfunction getGlobalSettingsPath(): string {\n return join(homedir(), \".claude\", \"settings.json\");\n}\n\n// Read + validate ~/.claude/settings.json an toàn. Không throw — graceful null-ish.\nexport function detectGlobalClaudeSettings(): GlobalClaudeSettingsInfo {\n const path = getGlobalSettingsPath();\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return { exists: false, hasBaseUrl: false, hasToken: false };\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // JSON corrupted — treat as no global config (an toàn hơn dùng config rác).\n return { exists: true, hasBaseUrl: false, hasToken: false };\n }\n\n const env = (parsed.env as Record<string, unknown> | undefined) || {};\n const baseUrl = typeof env.ANTHROPIC_BASE_URL === \"string\" ? env.ANTHROPIC_BASE_URL : undefined;\n const hasToken =\n typeof env.ANTHROPIC_AUTH_TOKEN === \"string\" && env.ANTHROPIC_AUTH_TOKEN.length > 0;\n const model = typeof parsed.model === \"string\" ? parsed.model : undefined;\n\n return {\n exists: true,\n hasBaseUrl: !!baseUrl,\n baseUrl,\n hasToken,\n model,\n rawSettings: parsed,\n };\n}\n\n// Main wizard. Trả enum choice — caller branch theo phase 03 / 05 / use-global path.\n// `globalInfo` injectable cho test (default = detect thật).\nexport async function promptAiProviderChoice(\n globalInfo: GlobalClaudeSettingsInfo = detectGlobalClaudeSettings(),\n): Promise<AiProviderChoice> {\n // Hybrid path: chỉ offer use-global khi global có ĐỦ baseUrl + token (config full).\n if (globalInfo.exists && globalInfo.hasBaseUrl && globalInfo.hasToken) {\n const choice = (await select({\n message: `Phát hiện AI config global (base URL: ${globalInfo.baseUrl}). Dùng cho project này?`,\n choices: [\n {\n name: \"a. Yes — copy config global vào .claude/settings.json (per-project)\",\n value: \"use-global\" as const,\n },\n {\n name: \"b. No — setup riêng (chọn provider khác)\",\n value: \"setup-fresh\" as const,\n },\n ],\n })) as \"use-global\" | \"setup-fresh\";\n\n if (choice === \"use-global\") return \"use-global\";\n // Fall-through to provider picker.\n }\n\n // Provider picker — 2 path Subscription / LLMLite.\n return (await select({\n message: \"Chọn provider cho AI features:\",\n choices: [\n {\n name: \"1. Claude Code Subscription (dùng quota cá nhân Anthropic)\",\n value: \"subscription\" as const,\n },\n {\n name: \"2. LLMLite API key (llm.nal.vn — NAL cấp)\",\n value: \"llmlite\" as const,\n },\n ],\n })) as \"subscription\" | \"llmlite\";\n}\n","// LLMLite setup wizard — flow:\n// 1) Prompt API key ẩn (password input, không echo)\n// 2) Prompt base URL (default https://llm.nal.vn)\n// 3) Fetch GET /v1/models verify key + lấy danh sách model\n// 4) Smart picker: auto-pick nếu chỉ 1 claude-alias, prompt nếu nhiều, fallback toàn list\n// Output: { apiKey, baseUrl, model } cho phase 06 write settings.json.\nimport { input, password, select } from \"@inquirer/prompts\";\nimport { log } from \"./terminal-logger.js\";\n\nexport interface LLMLiteConfig {\n apiKey: string;\n baseUrl: string;\n model: string;\n}\n\n// Endpoint mặc định NAL host. User có thể override (vd self-hosted dev).\nconst DEFAULT_BASE_URL = \"https://llm.nal.vn\";\n\n// 10s timeout fetch — VN mạng có thể chậm nhưng 10s đủ cho list models (response < 1KB).\nconst FETCH_TIMEOUT_MS = 10_000;\n\n// Trả \"sk-...XXXX\" để log không expose full token nhưng vẫn distinguishable.\nexport function maskApiKey(key: string): string {\n if (key.length <= 8) return \"sk-***\";\n return `${key.slice(0, 3)}...${key.slice(-4)}`;\n}\n\n// Prompt ẩn — `password` không echo input, hiển thị `*`.\nasync function promptApiKeyHidden(): Promise<string> {\n return await password({\n message: \"LLMLite API key (ẩn input):\",\n mask: \"*\",\n validate: (v) => (v.trim().length > 0 ? true : \"API key bắt buộc\"),\n });\n}\n\n// Prompt base URL với default cho user enter-to-accept nhanh.\nasync function promptBaseUrl(defaultUrl: string = DEFAULT_BASE_URL): Promise<string> {\n const value = await input({\n message: \"LLMLite base URL:\",\n default: defaultUrl,\n validate: (v) => (/^https?:\\/\\//.test(v) ? true : \"Phải là URL hợp lệ (http/https)\"),\n });\n // Strip trailing slash để concat /v1/... predictable.\n return value.replace(/\\/+$/, \"\");\n}\n\n// Shape response /v1/models theo OpenAI spec — chỉ trust field `id`.\ninterface ModelsResponse {\n data?: Array<{ id?: unknown }>;\n}\n\n// Fetch danh sách model từ endpoint. Throws có message rõ để caller hiển thị.\nexport async function fetchAvailableModels(baseUrl: string, apiKey: string): Promise<string[]> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(`${baseUrl}/v1/models`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n Accept: \"application/json\",\n },\n signal: controller.signal,\n });\n\n if (res.status === 401 || res.status === 403) {\n throw new Error(`API key invalid (HTTP ${res.status}).`);\n }\n if (res.status === 404) {\n throw new Error(`Endpoint /v1/models không tồn tại trên ${baseUrl}.`);\n }\n if (!res.ok) {\n throw new Error(`Fetch models thất bại (HTTP ${res.status}).`);\n }\n\n const json = (await res.json()) as ModelsResponse;\n const models = (json.data || [])\n .map((m) => (typeof m.id === \"string\" ? m.id : null))\n .filter((id): id is string => id !== null);\n\n if (models.length === 0) {\n throw new Error(\"LLMLite trả về list rỗng. Liên hệ admin NAL.\");\n }\n return models;\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n throw new Error(`Connect ${baseUrl} timeout sau ${FETCH_TIMEOUT_MS / 1000}s.`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\n// Smart picker: auto-pick nếu chỉ 1 claude-alias, prompt nếu nhiều, fallback all.\n// `claude` substring match cover: nal-claude, claude-sonnet-4-5, claude-3-5-sonnet, ...\nexport async function promptModelChoice(models: string[]): Promise<string> {\n const claudeAliases = models.filter((m) => m.toLowerCase().includes(\"claude\"));\n\n if (claudeAliases.length === 1) {\n log.info(`Auto-pick model: ${claudeAliases[0]} (chỉ 1 claude alias trên endpoint)`);\n return claudeAliases[0];\n }\n\n const choiceList = claudeAliases.length > 0 ? claudeAliases : models;\n return await select({\n message: \"Chọn model mặc định cho project:\",\n choices: choiceList.map((m) => ({ name: m, value: m })),\n });\n}\n\n// Main wizard. Orchestrate 4 step.\nexport async function setupLLMLiteApiKeyAndModel(): Promise<LLMLiteConfig> {\n const apiKey = await promptApiKeyHidden();\n const baseUrl = await promptBaseUrl();\n\n log.info(`Verify key (${maskApiKey(apiKey)}) qua ${baseUrl}/v1/models...`);\n const models = await fetchAvailableModels(baseUrl, apiKey);\n log.success(`Endpoint OK — ${models.length} models available`);\n\n const model = await promptModelChoice(models);\n return { apiKey, baseUrl, model };\n}\n","// Ghi <workspace>/.claude/settings.json — schema Claude Code expect.\n// 3 branch input: subscription / llmlite / use-global.\n// Merge-safe: preserve key user thêm thủ công (vd \"theme\", \"permissions\"),\n// chỉ override env.ANTHROPIC_BASE_URL / env.ANTHROPIC_AUTH_TOKEN / model.\n// Atomic write qua tmp-rename + chmod 600 (file chứa secret token).\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { pathExists, readJson, writeJsonAtomic } from \"./filesystem-helpers.js\";\n\n// chmod 600 = owner read/write only. Bắt buộc cho file chứa raw token.\nconst SECRET_FILE_MODE = 0o600;\n\n// 3 branch input — discriminated union để TS narrow chính xác.\nexport type ClaudeSettingsInput =\n | { provider: \"subscription\"; model: string }\n | { provider: \"llmlite\"; apiKey: string; baseUrl: string; model: string }\n | { provider: \"use-global\"; sourceSettings: Record<string, unknown> };\n\n// Shape minimal của Claude Code settings.json — chỉ key Avatar đụng tới.\n// Index signature cho phép user thêm key custom (permissions, theme...) mà không lỗi type.\ninterface ClaudeSettings {\n env?: {\n ANTHROPIC_BASE_URL?: string;\n ANTHROPIC_AUTH_TOKEN?: string;\n [k: string]: unknown;\n };\n model?: string;\n [k: string]: unknown;\n}\n\n// Đường dẫn settings target trong workspace.\nexport function getClaudeSettingsPath(workspacePath: string): string {\n return join(workspacePath, \".claude\", \"settings.json\");\n}\n\n// Đọc settings hiện có nếu file tồn tại. Throw nếu JSON corrupted để caller báo user\n// (an toàn hơn merge với object rỗng — có thể nuốt config user đã có).\nasync function readExistingSettings(path: string): Promise<ClaudeSettings> {\n if (!(await pathExists(path))) return {};\n try {\n return await readJson<ClaudeSettings>(path);\n } catch (err) {\n throw new Error(\n `Không parse được ${path} (JSON lỗi): ${(err as Error).message}. Backup file rồi xóa để Avatar tạo lại.`,\n );\n }\n}\n\n// Subscription path: clear LLMLite env keys (nếu có từ config cũ), set model.\nfunction applySubscription(existing: ClaudeSettings, model: string): ClaudeSettings {\n // Rebuild không có key env mặc định — nếu existing.env còn key non-Avatar thì add lại.\n const { env: existingEnv, ...rest } = existing;\n const merged: ClaudeSettings = { ...rest, model };\n if (existingEnv) {\n const { ANTHROPIC_BASE_URL: _b, ANTHROPIC_AUTH_TOKEN: _t, ...envRest } = existingEnv;\n if (Object.keys(envRest).length > 0) {\n merged.env = envRest as ClaudeSettings[\"env\"];\n }\n }\n return merged;\n}\n\n// LLMLite path: set đủ 3 key (baseUrl + token + model). Preserve env key khác.\nfunction applyLLMLite(\n existing: ClaudeSettings,\n apiKey: string,\n baseUrl: string,\n model: string,\n): ClaudeSettings {\n return {\n ...existing,\n env: {\n ...(existing.env || {}),\n ANTHROPIC_BASE_URL: baseUrl,\n ANTHROPIC_AUTH_TOKEN: apiKey,\n },\n model,\n };\n}\n\n// Use-global path: copy block env + model từ ~/.claude/settings.json, giữ key local khác.\nfunction applyUseGlobal(existing: ClaudeSettings, source: Record<string, unknown>): ClaudeSettings {\n const sourceEnv = (source.env as Record<string, unknown> | undefined) || {};\n const sourceModel = typeof source.model === \"string\" ? source.model : undefined;\n return {\n ...existing,\n env: {\n ...(existing.env || {}),\n ...sourceEnv,\n },\n ...(sourceModel ? { model: sourceModel } : {}),\n };\n}\n\n// Main API. Ghi settings + chmod 600. Throws nếu file corrupted hoặc IO fail.\nexport async function writeClaudeSettings(\n workspacePath: string,\n input: ClaudeSettingsInput,\n): Promise<{ path: string; mode: number }> {\n const path = getClaudeSettingsPath(workspacePath);\n const existing = await readExistingSettings(path);\n\n let merged: ClaudeSettings;\n switch (input.provider) {\n case \"subscription\":\n merged = applySubscription(existing, input.model);\n break;\n case \"llmlite\":\n merged = applyLLMLite(existing, input.apiKey, input.baseUrl, input.model);\n break;\n case \"use-global\":\n merged = applyUseGlobal(existing, input.sourceSettings);\n break;\n }\n\n await writeJsonAtomic(path, merged, SECRET_FILE_MODE);\n\n // Re-chmod sau write — writeJsonAtomic đã apply mode trên tmp, rename giữ mode trên POSIX.\n // Trên Windows chmod no-op, không lỗi.\n try {\n await fs.chmod(path, SECRET_FILE_MODE);\n } catch {\n // Windows hoặc filesystem không support — bỏ qua, không fail flow.\n }\n\n return { path, mode: SECRET_FILE_MODE };\n}\n","// Orchestrator AI Setup — compose phase 01-06 thành 1 flow fail-soft.\n// Gọi sau `maybeCreateWorkspaceRemote` trong `finalizeWorkspaceScaffold`.\n// Try/catch toàn bộ: success → log + audit ok. Fail → log warn + audit failed, KHÔNG throw —\n// workspace vẫn dùng được, user setup AI lại qua `avatar ai setup`.\nimport { appendAuditEntry } from \"./audit-log-appender.js\";\nimport {\n checkClaudeCodeSubscriptionAuth,\n triggerClaudeCodeAuthLogin,\n verifyClaudeCodeQuota,\n} from \"./check-claude-code-subscription-and-quota.js\";\nimport { detectClaudeCodeInstallation } from \"./detect-claude-code-installation.js\";\nimport { installClaudeCodeViaNpm } from \"./install-claude-code-via-npm.js\";\nimport {\n type AiProviderChoice,\n detectGlobalClaudeSettings,\n promptAiProviderChoice,\n} from \"./prompt-ai-provider-choice.js\";\nimport { setupLLMLiteApiKeyAndModel } from \"./setup-llmlite-api-key-and-model.js\";\nimport { log } from \"./terminal-logger.js\";\nimport { writeClaudeSettings } from \"./write-claude-settings-json-per-project.js\";\n\n// Default model alias cho Subscription path — Claude Code expect string vd \"sonnet\".\n// User có thể edit settings.json sau nếu muốn dùng model khác.\nconst SUBSCRIPTION_DEFAULT_MODEL = \"sonnet\";\n\nexport interface AiSetupArgs {\n workspacePath: string;\n // CI / test mode: skip mọi interactive prompt — caller phải đảm bảo không vào path cần input.\n // Hiện tại không dùng vì AI setup interactive — reserve cho future enhancement.\n autoYes?: boolean;\n}\n\nexport type AiSetupResult =\n | { ok: true; provider: AiProviderChoice; model?: string }\n | { ok: false; reason: string; phase?: string };\n\n// Main orchestrator. Fail-soft — không throw.\nexport async function runAiSetupPhase(args: AiSetupArgs): Promise<AiSetupResult> {\n try {\n log.info(\"Setup AI provider cho workspace...\");\n\n // Phase 01: detect Claude Code. Phase 02: install nếu thiếu.\n let info = detectClaudeCodeInstallation();\n if (!info.installed) {\n log.info(\"Chưa có Claude Code — sẽ tự cài qua npm.\");\n installClaudeCodeViaNpm();\n info = detectClaudeCodeInstallation();\n if (!info.installed) {\n throw new Error(\"Cài Claude Code xong nhưng vẫn không detect được binary.\");\n }\n } else {\n log.success(`Claude Code đã có${info.version ? ` v${info.version}` : \"\"}`);\n }\n\n // Phase 04: prompt provider choice (hybrid global detect).\n const globalInfo = detectGlobalClaudeSettings();\n const choice = await promptAiProviderChoice(globalInfo);\n\n // Branch theo choice → call phase 03 hoặc 05 → call phase 06 (write settings).\n switch (choice) {\n case \"subscription\": {\n // Phase 03: auth + quota.\n if (checkClaudeCodeSubscriptionAuth() !== \"authenticated\") {\n triggerClaudeCodeAuthLogin();\n }\n const quota = verifyClaudeCodeQuota();\n if (!quota.ok) {\n await appendAuditEntry(\n \"ai_setup\",\n `provider=subscription,result=no-quota,reason=${quota.reason ?? \"unknown\"}`,\n );\n log.warn(\n `Subscription verify thất bại (${quota.reason ?? \"unknown\"}). Suggest LLMLite hoặc upgrade plan.`,\n );\n return { ok: false, reason: `subscription-${quota.reason ?? \"unknown\"}`, phase: \"quota\" };\n }\n await writeClaudeSettings(args.workspacePath, {\n provider: \"subscription\",\n model: SUBSCRIPTION_DEFAULT_MODEL,\n });\n await appendAuditEntry(\"ai_setup\", \"provider=subscription,result=ok\");\n log.success(`AI ready · Subscription · model=${SUBSCRIPTION_DEFAULT_MODEL}`);\n return { ok: true, provider: \"subscription\", model: SUBSCRIPTION_DEFAULT_MODEL };\n }\n\n case \"llmlite\": {\n // Phase 05: API key + model picker + verify.\n const llmConfig = await setupLLMLiteApiKeyAndModel();\n await writeClaudeSettings(args.workspacePath, {\n provider: \"llmlite\",\n apiKey: llmConfig.apiKey,\n baseUrl: llmConfig.baseUrl,\n model: llmConfig.model,\n });\n await appendAuditEntry(\n \"ai_setup\",\n `provider=llmlite,result=ok,model=${llmConfig.model},base=${llmConfig.baseUrl}`,\n );\n log.success(`AI ready · LLMLite · model=${llmConfig.model} · ${llmConfig.baseUrl}`);\n return { ok: true, provider: \"llmlite\", model: llmConfig.model };\n }\n\n case \"use-global\": {\n if (!globalInfo.rawSettings) {\n throw new Error(\"use-global chọn nhưng không đọc được global settings.\");\n }\n await writeClaudeSettings(args.workspacePath, {\n provider: \"use-global\",\n sourceSettings: globalInfo.rawSettings,\n });\n await appendAuditEntry(\"ai_setup\", \"provider=use-global,result=ok\");\n log.success(`AI ready · Copy từ global config (${globalInfo.baseUrl ?? \"subscription\"})`);\n return { ok: true, provider: \"use-global\", model: globalInfo.model };\n }\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log.warn(`AI setup thất bại: ${message}`);\n log.dim(\"Workspace vẫn sẵn sàng. Setup AI sau qua: avatar ai setup\");\n await appendAuditEntry(\"ai_setup\", `result=failed,error=${message.slice(0, 200)}`);\n return { ok: false, reason: message };\n }\n}\n","// Shared stub action for commands wired into commander but not yet implemented.\n// Prints a consistent message + exit code so users know it's coming.\nimport { chalk } from \"./terminal-logger.js\";\n\nexport function notImplementedYet(commandName: string, milestone?: string): () => void {\n return () => {\n process.stdout.write(\n `${chalk.yellow(\"⏳\")} ${chalk.bold(`avatar ${commandName}`)} — chưa implement ở milestone hiện tại.\\n`,\n );\n if (milestone) {\n process.stdout.write(` Dự kiến: ${chalk.cyan(milestone)}\\n`);\n }\n process.stdout.write(\" Spec đã có trong avatar-cli-implementation_4.html.\\n\");\n process.exit(0);\n };\n}\n","// `avatar commit [--src|--avatar|--both] [-m <msg>] [--push]` — Command 09.\n// Only valid in client/library mode. Splits commits between the client repo\n// (src/) and the Avatar workspace.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerCommitCommand(program: Command): void {\n program\n .command(\"commit\")\n .description(\"Commit code khách (src/) hoặc Avatar state riêng — chỉ client mode (M07)\")\n .option(\"--src\", \"Commit src/ → client remote\")\n .option(\"--avatar\", \"Commit Avatar state → workspace remote\")\n .option(\"--both\", \"Commit cả hai (src trước, avatar sau)\")\n .option(\"-m, --message <msg>\", \"Commit message\")\n .option(\"--push\", \"Tự động push sau khi commit\")\n .action(notImplementedYet(\"commit\", \"Milestone 07\"));\n}\n","import { spawnSync } from \"node:child_process\";\n// `avatar doctor [--fix]` — Command 07 spec.\n// Run a series of health checks and surface ✓/✗ for each. --fix attempts\n// auto-fixes for the ones safe to fix automatically.\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { pathExists } from \"../lib/filesystem-helpers.js\";\nimport { isGitRepo } from \"../lib/git-operations.js\";\nimport { installGitHook } from \"../lib/project-tree-scaffolder.js\";\nimport { chalk, log } from \"../lib/terminal-logger.js\";\nimport { isTokenExpired, readUserConfig } from \"../lib/user-config-store.js\";\n\ninterface CheckResult {\n name: string;\n status: \"ok\" | \"warn\" | \"fail\";\n detail: string;\n fixable: boolean;\n fix?: () => Promise<void>;\n}\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Chẩn đoán cài đặt Avatar: hooks, MCP, login, submodule, ...\")\n .option(\"--fix\", \"Tự động fix các issue có thể fix tự động\")\n .action(async (opts: { fix?: boolean }) => {\n try {\n const checks = await runChecks(process.cwd());\n renderChecks(checks);\n if (opts.fix) await applyFixes(checks);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runChecks(cwd: string): Promise<CheckResult[]> {\n const checks: CheckResult[] = [];\n\n // 1. Node.js version >= 18.17\n const nodeVer = process.versions.node;\n const [major, minor] = nodeVer.split(\".\").map((n) => Number.parseInt(n, 10));\n const nodeOk = (major ?? 0) > 18 || ((major ?? 0) === 18 && (minor ?? 0) >= 17);\n checks.push({\n name: \"Node.js version\",\n status: nodeOk ? \"ok\" : \"fail\",\n detail: `v${nodeVer}${nodeOk ? \"\" : \" (cần >= 18.17)\"}`,\n fixable: false,\n });\n\n // 2. Login.\n const config = await readUserConfig();\n if (!config) {\n checks.push({\n name: \"Login status\",\n status: \"fail\",\n detail: \"Chưa đăng nhập — chạy 'avatar login'\",\n fixable: false,\n });\n } else if (isTokenExpired(config)) {\n checks.push({\n name: \"Login status\",\n status: \"warn\",\n detail: `Token hết hạn (${config.email}) — chạy 'avatar login'`,\n fixable: false,\n });\n } else {\n checks.push({\n name: \"Login status\",\n status: \"ok\",\n detail: `Logged in: ${config.email}`,\n fixable: false,\n });\n }\n\n // 3. Git repo.\n const gitRepo = await isGitRepo(cwd);\n checks.push({\n name: \"Git repository\",\n status: gitRepo ? \"ok\" : \"warn\",\n detail: gitRepo ? cwd : \"Không phải git repo (cần cho 'avatar init')\",\n fixable: false,\n });\n\n // 4. .claude/pack/ submodule.\n const packPath = join(cwd, \".claude\", \"pack\");\n const hasPack = await pathExists(packPath);\n checks.push({\n name: \"team-ai-pack submodule\",\n status: hasPack ? \"ok\" : \"warn\",\n detail: hasPack ? packPath : \"Avatar chưa init — chạy 'avatar init'\",\n fixable: false,\n });\n\n // 5. CLAUDE.md present.\n const claudeMdPath = join(cwd, \"CLAUDE.md\");\n const hasClaudeMd = await pathExists(claudeMdPath);\n checks.push({\n name: \"CLAUDE.md\",\n status: hasClaudeMd ? \"ok\" : \"warn\",\n detail: hasClaudeMd ? \"tồn tại ở project root\" : \"thiếu — chạy 'avatar init'\",\n fixable: false,\n });\n\n // 6. post-merge hook.\n const hookPath = join(cwd, \".git\", \"hooks\", \"post-merge\");\n const hasHook = await pathExists(hookPath);\n if (gitRepo && hasPack) {\n checks.push({\n name: \"Git hook post-merge\",\n status: hasHook ? \"ok\" : \"fail\",\n detail: hasHook ? \"installed\" : \"missing — fixable\",\n fixable: !hasHook,\n fix: hasHook\n ? undefined\n : async () => {\n await installGitHook(join(cwd, \".git\"), \"post-merge\");\n },\n });\n }\n\n // 7. .gitignore has Avatar entries.\n const gitignorePath = join(cwd, \".gitignore\");\n if (gitRepo) {\n let gitignoreOk = false;\n if (await pathExists(gitignorePath)) {\n const content = await fs.readFile(gitignorePath, \"utf8\");\n gitignoreOk = content.includes(\".claude/_pending/\");\n }\n checks.push({\n name: \".gitignore Avatar entries\",\n status: gitignoreOk ? \"ok\" : hasPack ? \"fail\" : \"warn\",\n detail: gitignoreOk ? \"có .claude/_pending/, .claude/_backup/\" : \"thiếu entries\",\n fixable: false,\n });\n }\n\n // 8. Claude Code CLI installed (best-effort `which claude`).\n const which = spawnSync(\"which\", [\"claude\"]);\n const hasClaudeCli = which.status === 0;\n checks.push({\n name: \"Claude Code CLI\",\n status: hasClaudeCli ? \"ok\" : \"warn\",\n detail: hasClaudeCli ? which.stdout.toString().trim() : \"không tìm thấy 'claude' trên PATH\",\n fixable: false,\n });\n\n return checks;\n}\n\nfunction renderChecks(checks: CheckResult[]): void {\n const lines = [chalk.bold(\"Avatar Doctor\"), \"─\".repeat(48)];\n let passed = 0;\n let issues = 0;\n let fixable = 0;\n for (const c of checks) {\n const icon =\n c.status === \"ok\"\n ? chalk.green(\"✓\")\n : c.status === \"warn\"\n ? chalk.yellow(\"⚠\")\n : chalk.red(\"✗\");\n lines.push(`${icon} ${c.name.padEnd(28)} ${chalk.dim(c.detail)}`);\n if (c.status === \"ok\") passed += 1;\n else {\n issues += 1;\n if (c.fixable) fixable += 1;\n }\n }\n lines.push(\"─\".repeat(48));\n lines.push(\n `${passed} checks passed, ${issues} issue${issues === 1 ? \"\" : \"s\"}${fixable > 0 ? ` (${fixable} fixable — chạy 'avatar doctor --fix')` : \"\"}`,\n );\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n\nasync function applyFixes(checks: CheckResult[]): Promise<void> {\n let count = 0;\n for (const c of checks) {\n if (c.fixable && c.fix) {\n try {\n await c.fix();\n log.success(`Fixed: ${c.name}`);\n count += 1;\n } catch (err) {\n log.error(`Failed to fix ${c.name}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\n if (count === 0) log.dim(\"Không có gì để fix tự động.\");\n}\n","import { join } from \"node:path\";\n// Wrapper around simple-git for the operations Avatar uses repeatedly:\n// repo detection, submodule add/update, status, log, tag listing.\n// Centralised so error formatting and cwd handling stays consistent.\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { pathExists } from \"./filesystem-helpers.js\";\n\nexport function git(cwd: string = process.cwd()): SimpleGit {\n return simpleGit({ baseDir: cwd, binary: \"git\" });\n}\n\nexport async function isGitRepo(cwd: string = process.cwd()): Promise<boolean> {\n return await pathExists(join(cwd, \".git\"));\n}\n\nexport async function currentBranch(cwd: string = process.cwd()): Promise<string> {\n const result = await git(cwd).revparse([\"--abbrev-ref\", \"HEAD\"]);\n return result.trim();\n}\n\nexport async function addSubmodule(\n repoUrl: string,\n destPath: string,\n cwd: string = process.cwd(),\n): Promise<void> {\n await git(cwd).subModule([\"add\", repoUrl, destPath]);\n}\n\n// Checkout a tag inside a submodule. Used after `addSubmodule` to pin to a\n// specific team-ai-pack release.\nexport async function checkoutTagInSubmodule(\n submodulePath: string,\n tag: string,\n cwd: string = process.cwd(),\n): Promise<void> {\n const submoduleCwd = join(cwd, submodulePath);\n await git(submoduleCwd).fetch([\"--tags\"]);\n await git(submoduleCwd).checkout(tag);\n}\n\nexport async function listTags(cwd: string = process.cwd()): Promise<string[]> {\n const result = await git(cwd).tags();\n return result.all;\n}\n\nexport async function latestTag(cwd: string = process.cwd()): Promise<string | null> {\n const tags = await listTags(cwd);\n return tags.length > 0 ? (tags[tags.length - 1] ?? null) : null;\n}\n\nexport async function currentCommitSha(cwd: string = process.cwd()): Promise<string> {\n const result = await git(cwd).revparse([\"HEAD\"]);\n return result.trim();\n}\n\nexport async function workingTreeIsDirty(cwd: string = process.cwd()): Promise<boolean> {\n const status = await git(cwd).status();\n return !status.isClean();\n}\n","import { promises as fs } from \"node:fs\";\n// Scaffold the .claude/ directory tree inside a project after submodule add.\n// Used by `avatar init` for all three modes (internal/client/library).\n//\n// Spec source: Chapter 02 (folder map) + Chapter 09 Command 02 BEHAVIOR.\nimport { join } from \"node:path\";\nimport type { InitMode } from \"../types/config-schema.js\";\nimport { ensureDir, pathExists, writeTextAtomic } from \"./filesystem-helpers.js\";\nimport { type TemplateName, loadHook, renderTemplateByName } from \"./template-bundle-loader.js\";\n\n// Top-level paths Avatar will create or overwrite during init.\n// init.ts imports this for conflict detection so the list stays in sync.\n// `.gitmodules` is managed by git submodule add (not direct write), but it\n// gets modified during init so it's listed here for conflict warnings.\nexport const AVATAR_MANAGED_PATHS = [\".claude\", \"CLAUDE.md\", \".gitmodules\"] as const;\n\n// Rename `path` to `{path}.avatar-backup-{ISO timestamp}` if it exists.\n// Returns the backup path if created, null if source didn't exist.\n// Caller logs the backup so the user knows where their original file went.\n//\n// Collision handling: if the timestamped backup name already exists (two\n// backups within the same millisecond, or pre-existing leftover from prior\n// run), appends `-{counter}` until a free name is found. Prevents silent\n// overwrite of a previous backup.\nexport async function backupIfExists(path: string): Promise<string | null> {\n if (!(await pathExists(path))) return null;\n const ts = new Date().toISOString().replace(/[:.]/g, \"-\");\n const basePath = `${path}.avatar-backup-${ts}`;\n let backupPath = basePath;\n let counter = 1;\n while (await pathExists(backupPath)) {\n backupPath = `${basePath}-${counter}`;\n counter++;\n if (counter > 5) {\n throw new Error(`Could not find free backup name for ${path}`);\n }\n }\n await fs.rename(path, backupPath);\n return backupPath;\n}\n\n// Backup-aware atomic write. Used by all scaffolder write functions so user's\n// pre-existing files in `.claude/` are preserved when Avatar re-scaffolds.\n// Returns the backup path if a backup was created, null otherwise.\nasync function writeWithBackup(\n path: string,\n content: string,\n mode?: number,\n): Promise<string | null> {\n const backup = await backupIfExists(path);\n await writeTextAtomic(path, content, mode);\n return backup;\n}\n\n// Subdirectories Avatar creates inside .claude/ on init. `pack/` is added\n// separately by the submodule manager — listed here for reference only.\nconst CLAUDE_SUBDIRS = [\"project\", \"state\", \"_pending\", \"_backup\"] as const;\n\nconst PROJECT_KNOWLEDGE_TEMPLATES: TemplateName[] = [\n \"project/tech-stack.md\",\n \"project/conventions.md\",\n \"project/architecture.md\",\n \"project/domain.md\",\n \"project/gotchas.md\",\n];\n\nexport interface ScaffoldVariables {\n projectName: string;\n projectDescription: string;\n teamOwner: string;\n avatarVersion: string;\n packVersion: string;\n lastScan: string;\n mode: InitMode;\n}\n\n// Create .claude/{project,state,_pending,_backup}/ and a .gitkeep in each\n// so they survive a fresh checkout.\nexport async function createClaudeDirTree(projectRoot: string): Promise<void> {\n const claudeRoot = join(projectRoot, \".claude\");\n await ensureDir(claudeRoot);\n for (const sub of CLAUDE_SUBDIRS) {\n const dir = join(claudeRoot, sub);\n await ensureDir(dir);\n await writeTextAtomic(join(dir, \".gitkeep\"), \"\");\n }\n}\n\n// Render and write all 5 project knowledge files from templates.\n// All start with placeholder content — scanners fill them in later.\n// Returns list of backup paths created for pre-existing user files.\nexport async function writeProjectKnowledgeFiles(\n projectRoot: string,\n vars: ScaffoldVariables,\n): Promise<string[]> {\n const baseVars = {\n ...vars,\n primaryLanguage: \"(chưa scan)\",\n frameworks: \"(chưa scan)\",\n databases: \"(chưa scan)\",\n testStack: \"(chưa scan)\",\n buildStack: \"(chưa scan)\",\n toolVersions: \"(chưa scan)\",\n codeStyle: \"(chưa scan)\",\n namingConvention: \"(chưa scan)\",\n folderStructure: \"(chưa scan)\",\n commitConvention: \"(chưa scan)\",\n linterConfig: \"(chưa scan)\",\n architectureOverview: \"(chưa scan)\",\n moduleLayout: \"(chưa scan)\",\n dataFlow: \"(chưa scan)\",\n externalIntegrations: \"(chưa scan)\",\n deploymentTopology: \"(chưa scan)\",\n domainDescription: \"(chưa scan)\",\n coreEntities: \"(chưa scan)\",\n primaryUseCases: \"(chưa scan)\",\n domainGlossary: \"(chưa scan)\",\n };\n const backups: string[] = [];\n for (const tpl of PROJECT_KNOWLEDGE_TEMPLATES) {\n const content = await renderTemplateByName(tpl, baseVars);\n const relative = tpl.replace(/^project\\//, \"\");\n const outPath = join(projectRoot, \".claude\", \"project\", relative);\n const backup = await writeWithBackup(outPath, content);\n if (backup) backups.push(backup);\n }\n return backups;\n}\n\n// Write root CLAUDE.md from template — this is the entry point Claude Code reads.\n// Returns backup path if a pre-existing CLAUDE.md was renamed.\nexport async function writeRootClaudeMd(\n projectRoot: string,\n vars: ScaffoldVariables,\n): Promise<string | null> {\n const content = await renderTemplateByName(\"CLAUDE.md\", vars);\n return await writeWithBackup(join(projectRoot, \"CLAUDE.md\"), content);\n}\n\n// Write .claude/settings.json from template. Returns backup path if existed.\nexport async function writeProjectSettings(\n projectRoot: string,\n vars: ScaffoldVariables,\n): Promise<string | null> {\n const content = await renderTemplateByName(\"settings.json\", vars);\n return await writeWithBackup(join(projectRoot, \".claude\", \"settings.json\"), content);\n}\n\n// Append Avatar entries to project .gitignore (or create if missing).\n// Idempotent — skips if our marker line already present.\nexport async function appendGitignoreEntries(projectRoot: string): Promise<void> {\n const path = join(projectRoot, \".gitignore\");\n const tpl = await renderTemplateByName(\"gitignore\", {});\n const marker = \"# Avatar — git-ignored entries injected on `avatar init`\";\n\n let existing = \"\";\n if (await pathExists(path)) {\n existing = await fs.readFile(path, \"utf8\");\n if (existing.includes(marker)) return;\n }\n\n const separator = existing.endsWith(\"\\n\") || existing.length === 0 ? \"\" : \"\\n\";\n await writeTextAtomic(path, `${existing}${separator}\\n${tpl}`);\n}\n\n// Install git hooks into <gitDir>/hooks/. `gitDir` lets caller point at\n// src/.git/hooks (client mode pre-push) or workspace .git/hooks (post-merge).\nexport async function installGitHook(\n gitDir: string,\n hookName: \"post-merge\" | \"pre-push\",\n): Promise<void> {\n const content = await loadHook(hookName);\n const hooksDir = join(gitDir, \"hooks\");\n await ensureDir(hooksDir);\n const dest = join(hooksDir, hookName);\n await writeTextAtomic(dest, content, 0o755);\n}\n","// Resolve template files bundled inside the Avatar CLI package. tsup bundles\n// src/ into dist/index.js but does NOT bundle template files — they ship as\n// loose files via package.json `files` field (src/templates, src/hooks).\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { readText } from \"./filesystem-helpers.js\";\nimport { renderTemplate } from \"./mustache-template-engine.js\";\n\n// Templates ship in src/templates/ and src/hooks/ at runtime (see\n// package.json `files` field — both src/templates and src/hooks are included\n// in the npm tarball). Locate them by walking up from this file to the\n// package root (folder containing package.json), then descending to src/.\n//\n// This works identically from dist/index.js (npm-installed) and from\n// src/lib/*.ts (vitest/tsx) without path string sniffing.\nconst HERE = dirname(fileURLToPath(import.meta.url));\nconst PACKAGE_ROOT = findPackageRoot(HERE);\nconst TEMPLATES_ROOT = join(PACKAGE_ROOT, \"src\", \"templates\");\nconst HOOKS_ROOT = join(PACKAGE_ROOT, \"src\", \"hooks\");\n\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n while (true) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) {\n throw new Error(`Cannot locate package root from ${startDir}`);\n }\n dir = parent;\n }\n}\n\nexport type TemplateName =\n | \"CLAUDE.md\"\n | \"settings.json\"\n | \"gitignore\"\n | \"project/tech-stack.md\"\n | \"project/conventions.md\"\n | \"project/architecture.md\"\n | \"project/domain.md\"\n | \"project/gotchas.md\";\n\nexport type HookName = \"post-merge\" | \"pre-push\";\n\nexport async function loadTemplate(name: TemplateName): Promise<string> {\n return await readText(join(TEMPLATES_ROOT, `${name}.tpl`));\n}\n\nexport async function renderTemplateByName(\n name: TemplateName,\n variables: Record<string, string | number | undefined>,\n): Promise<string> {\n const source = await loadTemplate(name);\n return renderTemplate(source, variables);\n}\n\nexport async function loadHook(name: HookName): Promise<string> {\n return await readText(join(HOOKS_ROOT, `${name}.sh.tpl`));\n}\n","// Minimal mustache-style {{variable}} replacement engine. Avoids pulling in\n// full mustache dependency — Avatar templates only need flat variable\n// substitution, no loops or conditionals.\n//\n// Unknown variables left as-is, NOT replaced with empty string. This makes\n// missing variables visible in output for easier debugging.\n\nconst TEMPLATE_PATTERN = /\\{\\{\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\}\\}/g;\n\nexport function renderTemplate(\n source: string,\n variables: Record<string, string | number | undefined>,\n): string {\n return source.replace(TEMPLATE_PATTERN, (match, key: string) => {\n const value = variables[key];\n if (value === undefined) return match;\n return String(value);\n });\n}\n\n// Extract the variable names referenced by a template — useful for\n// scaffolding tests and validating that callers pass every required key.\nexport function extractVariables(source: string): string[] {\n const found = new Set<string>();\n for (const match of source.matchAll(TEMPLATE_PATTERN)) {\n if (match[1]) found.add(match[1]);\n }\n return Array.from(found).sort();\n}\n","// `avatar init` — Command 02 spec (v1.1 redesign).\n//\n// Bỏ khái niệm --mode internal/client/library. Thay bằng wizard 3-câu hỏi tự\n// nhận diện tình trạng dự án:\n// 1. Đã có repo git remote (URL có sẵn) → flow=existing-remote\n// 2. Đã có folder code local → flow=existing-folder\n// 3. Dự án mới hoàn toàn → flow=new-project\n//\n// Mọi flow đều scaffold workspace tách biệt (không còn mode internal). Avatar\n// luôn check + tự cài gh CLI nếu thiếu, auto-bootstrap git cho folder chưa\n// init, auto-detect .gitignore theo tech stack.\n\nimport { basename, join, relative, resolve } from \"node:path\";\nimport { confirm, input, select } from \"@inquirer/prompts\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { appendAuditEntry } from \"../lib/audit-log-appender.js\";\nimport { printAvatarBanner } from \"../lib/avatar-ascii-banner.js\";\nimport { checkFolderHasGit } from \"../lib/check-folder-has-git.js\";\nimport { createGithubRemoteFromFolder } from \"../lib/create-github-remote-from-folder.js\";\nimport { createWorkspaceRemoteViaGh } from \"../lib/create-workspace-remote-via-gh.js\";\nimport { ensureDir } from \"../lib/filesystem-helpers.js\";\nimport { ensureGitHubReady } from \"../lib/git-auth-and-install-orchestrator.js\";\nimport { git } from \"../lib/git-operations.js\";\nimport {\n appendGitignoreEntries,\n createClaudeDirTree,\n installGitHook,\n writeProjectKnowledgeFiles,\n writeProjectSettings,\n writeRootClaudeMd,\n} from \"../lib/project-tree-scaffolder.js\";\nimport { runAiSetupPhase } from \"../lib/run-ai-setup-phase.js\";\nimport {\n type BootstrapStrategy,\n InitAbortedByUserError,\n safeBootstrapGitInFolder,\n} from \"../lib/safe-bootstrap-for-dirty-folder.js\";\nimport { addTeamPackSubmodule } from \"../lib/team-pack-submodule-manager.js\";\nimport { chalk, log, spinner } from \"../lib/terminal-logger.js\";\nimport { isTokenExpired, readUserConfig } from \"../lib/user-config-store.js\";\nimport type { RepoVisibility } from \"../lib/validate-repo-name-and-visibility.js\";\nimport {\n findAlternativeWorkspaceName,\n isEmptyOrMissing,\n} from \"./init-conflict-detection-helpers.js\";\nimport { buildScaffoldVariables, inferWorkspaceName } from \"./init-scaffold-variable-builders.js\";\n\n// 3 flow values + deprecated legacy \"mode\" alias.\ntype ProjectStatus = \"existing-remote\" | \"existing-folder\" | \"new-project\";\n\ninterface InitOptions {\n // New v1.1 flags\n projectStatus?: ProjectStatus;\n folderPath?: string;\n createRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n // Carried over\n skipScan?: boolean;\n skipTeamPack?: boolean;\n packVersion?: string;\n clientRepo?: string; // reused: URL khi projectStatus=existing-remote\n workspaceName?: string;\n workspaceParent?: string;\n force?: boolean;\n teamOwner?: string;\n description?: string;\n yes?: boolean;\n commit?: boolean; // commander tự set false khi user pass --no-commit\n workspaceRemote?: boolean; // tạo remote cho workspace root (--workspace-remote)\n aiSkip?: boolean; // Skip AI setup phase (CI / test mode)\n bootstrapStrategy?: string; // stash | commit-all | skip | branch\n preserveUncommitted?: boolean; // Alias cho --bootstrap-strategy=stash\n // Legacy (deprecated)\n mode?: string;\n}\n\n// Parse 2 flag mới → BootstrapStrategy enum hoặc undefined (no preset → prompt).\n// --preserve-uncommitted override --bootstrap-strategy=other (UX: shortcut win).\nfunction parseBootstrapStrategyOpts(opts: InitOptions): BootstrapStrategy | undefined {\n if (opts.preserveUncommitted) return \"stash\";\n if (!opts.bootstrapStrategy) return undefined;\n const valid: BootstrapStrategy[] = [\"stash\", \"commit-all\", \"skip\", \"branch\"];\n if (valid.includes(opts.bootstrapStrategy as BootstrapStrategy)) {\n return opts.bootstrapStrategy as BootstrapStrategy;\n }\n throw new Error(\n `--bootstrap-strategy không hợp lệ: ${opts.bootstrapStrategy}. Chọn: ${valid.join(\" | \")}`,\n );\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Khởi tạo Avatar — 3 flow tự nhận diện (repo / folder / new)\")\n .option(\"--project-status <val>\", \"existing-remote | existing-folder | new-project\")\n .option(\"--folder-path <path>\", \"Đường dẫn folder hiện có (flow existing-folder)\")\n .option(\"--create-remote\", \"Force tạo remote qua gh (flow existing-folder hoặc new-project)\")\n .option(\"--repo-visibility <val>\", \"private (mặc định) | public\")\n .option(\"--repo-org <name>\", \"GitHub org/owner cho repo mới\")\n .option(\"--client-repo <url>\", \"URL git remote (flow existing-remote)\")\n .option(\"--workspace-name <name>\", \"Tên workspace\")\n .option(\"--workspace-parent <path>\", \"Thư mục cha tạo workspace (mặc định . — CWD)\")\n .option(\"--pack-version <tag>\", \"Pin team-ai-pack vào tag cụ thể\")\n .option(\"--team-owner <email>\", \"Email team owner (bỏ qua prompt)\")\n .option(\"--description <text>\", \"Mô tả 1 dòng của dự án\")\n .option(\"--skip-scan\", \"Bỏ qua project-scanner sau scaffold\")\n .option(\"--skip-team-pack\", \"Bỏ qua submodule team-ai-pack (test mode)\")\n .option(\"--force\", \"Bỏ qua prompt khi workspace path đã tồn tại\")\n .option(\"--yes\", \"Auto-confirm tất cả prompt\")\n .option(\"--no-commit\", \"Skip commit workspace initial state (mặc định LUÔN commit)\")\n .option(\"--workspace-remote\", \"Tạo GitHub remote cho workspace root (default: prompt)\")\n .option(\"--ai-skip\", \"Bỏ qua phase AI setup (CI/test mode — chạy `avatar ai setup` sau)\")\n .option(\n \"--bootstrap-strategy <s>\",\n \"Xử lý folder dirty: stash | commit-all | skip | branch (default: prompt)\",\n )\n .option(\"--preserve-uncommitted\", \"Alias cho --bootstrap-strategy=stash (giữ changes user)\")\n .option(\"--mode <mode>\", \"[DEPRECATED] Dùng --project-status thay thế\")\n .action(async (opts: InitOptions) => {\n try {\n await runInit(opts);\n } catch (err) {\n // Skip strategy → exit 0 với hướng dẫn, không phải error thật.\n if (err instanceof InitAbortedByUserError) {\n log.dim(err.message);\n process.exit(0);\n }\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runInit(opts: InitOptions): Promise<void> {\n if (!opts.yes) printAvatarBanner({ tagline: \"Khởi tạo Avatar trong dự án của bạn\" });\n\n if (opts.mode) {\n log.warn(\"Flag --mode đã deprecated từ v1.1. Dùng --project-status thay thế.\");\n }\n\n const userConfig = await readUserConfig();\n if (!userConfig || isTokenExpired(userConfig)) {\n log.error(\"Chưa đăng nhập hoặc token hết hạn. Chạy 'avatar login' trước.\");\n process.exit(1);\n }\n\n const status = opts.projectStatus ?? (await promptProjectStatus());\n\n switch (status) {\n case \"existing-remote\":\n await runInitFromExistingRemote(opts, userConfig.email);\n break;\n case \"existing-folder\":\n await runInitFromExistingFolder(opts, userConfig.email);\n break;\n case \"new-project\":\n await runInitFromScratch(opts, userConfig.email);\n break;\n }\n}\n\nasync function promptProjectStatus(): Promise<ProjectStatus> {\n return (await select({\n message: \"Tình trạng dự án của bạn?\",\n choices: [\n { name: \"1. Đã có repo git remote (URL có sẵn)\", value: \"existing-remote\" as const },\n { name: \"2. Đã có folder code local\", value: \"existing-folder\" as const },\n { name: \"3. Dự án mới hoàn toàn\", value: \"new-project\" as const },\n ],\n })) as ProjectStatus;\n}\n\n// ─── FLOW 1: EXISTING REMOTE ────────────────────────────────────────────────\nasync function runInitFromExistingRemote(opts: InitOptions, ownerEmail: string): Promise<void> {\n const remoteUrl =\n opts.clientRepo ??\n (await input({\n message: \"URL git của repo:\",\n validate: (v) => (v.length > 0 ? true : \"URL bắt buộc\"),\n }));\n\n await ensureGitHubReady(remoteUrl);\n\n const teamOwner = opts.teamOwner ?? (await promptTeamOwner(ownerEmail));\n const inferredName = inferWorkspaceName(remoteUrl);\n const workspaceName =\n opts.workspaceName ?? (await input({ message: \"Tên workspace:\", default: inferredName }));\n const workspaceParent = resolve(opts.workspaceParent ?? \".\");\n const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);\n\n await scaffoldWorkspaceWithSrcSubmodule({\n workspacePath,\n workspaceName,\n srcRemoteUrl: remoteUrl,\n teamOwner,\n skipTeamPack: opts.skipTeamPack,\n description: opts.description ?? `Avatar workspace cho ${remoteUrl}`,\n packVersion: opts.packVersion,\n autoYes: opts.yes,\n skipCommit: opts.commit === false,\n createWorkspaceRemote: opts.workspaceRemote,\n repoVisibility: opts.repoVisibility,\n repoOrg: opts.repoOrg,\n flow: \"existing-remote\",\n aiSkip: opts.aiSkip,\n });\n}\n\n// ─── FLOW 2: EXISTING FOLDER ────────────────────────────────────────────────\nasync function runInitFromExistingFolder(opts: InitOptions, ownerEmail: string): Promise<void> {\n const folderPath = resolve(\n opts.folderPath ??\n (await input({\n message: \"Đường dẫn folder hiện có:\",\n validate: (v) => (v.length > 0 ? true : \"Path bắt buộc\"),\n })),\n );\n\n // Safe bootstrap: nếu folder dirty → prompt 4 strategy bảo vệ user changes.\n await safeBootstrapGitInFolder(folderPath, {\n presetStrategy: parseBootstrapStrategyOpts(opts),\n autoYes: opts.yes,\n });\n\n // Check remote origin. Có → dùng luôn. Chưa có → hỏi tạo mới (default Có).\n const remoteUrl = await getOrCreateOriginRemote(folderPath, opts);\n\n const teamOwner = opts.teamOwner ?? (await promptTeamOwner(ownerEmail));\n const inferredName = opts.workspaceName ?? `${basename(folderPath)}-avatar-workspace`;\n const workspaceName =\n opts.workspaceName ?? (await input({ message: \"Tên workspace:\", default: inferredName }));\n const workspaceParent = resolve(opts.workspaceParent ?? \".\");\n const workspacePath = await resolveWorkspacePath(workspaceParent, workspaceName, opts.force);\n\n await scaffoldWorkspaceWithSrcSubmodule({\n workspacePath,\n workspaceName,\n srcRemoteUrl: remoteUrl ?? folderPath, // fallback local path nếu user từ chối tạo remote\n teamOwner,\n skipTeamPack: opts.skipTeamPack,\n description: opts.description ?? `Avatar workspace cho folder ${folderPath}`,\n packVersion: opts.packVersion,\n autoYes: opts.yes,\n skipCommit: opts.commit === false,\n createWorkspaceRemote: opts.workspaceRemote,\n repoVisibility: opts.repoVisibility,\n repoOrg: opts.repoOrg,\n flow: \"existing-folder\",\n aiSkip: opts.aiSkip,\n });\n}\n\n// ─── FLOW 3: NEW PROJECT ────────────────────────────────────────────────────\nasync function runInitFromScratch(opts: InitOptions, ownerEmail: string): Promise<void> {\n await ensureGitHubReady();\n\n const projectName =\n opts.workspaceName ??\n (await input({\n message: \"Tên dự án:\",\n validate: (v) => (v.length > 0 ? true : \"Tên bắt buộc\"),\n }));\n const visibility = (opts.repoVisibility ??\n (await select({\n message: \"Visibility?\",\n choices: [\n { name: \"private (mặc định)\", value: \"private\" as const },\n { name: \"public\", value: \"public\" as const },\n ],\n }))) as RepoVisibility;\n\n const teamOwner = opts.teamOwner ?? (await promptTeamOwner(ownerEmail));\n const workspaceParent = resolve(opts.workspaceParent ?? \".\");\n const workspacePath = await resolveWorkspacePath(workspaceParent, projectName, opts.force);\n const srcPath = join(workspacePath, \"src\");\n\n // Tạo workspace dir + src/ rỗng + bootstrap git trong src/.\n // srcPath vừa tạo nên empty → safe bootstrap skip prompt thẳng.\n await ensureDir(workspacePath);\n await ensureDir(srcPath);\n await safeBootstrapGitInFolder(srcPath, { autoYes: true });\n\n // Tạo remote GitHub + push initial commit.\n const urls = createGithubRemoteFromFolder({\n folder: srcPath,\n name: projectName,\n visibility,\n org: opts.repoOrg,\n });\n\n // Workspace setup: init git, submodule add cho src/.\n await git(workspacePath).init();\n const sp = spinner(\n opts.skipTeamPack ? \"Add submodule src/...\" : \"Add submodule src/ + team-ai-pack...\",\n );\n try {\n await git(workspacePath).subModule([\"add\", urls.sshUrl, \"src\"]);\n let pinnedTag = \"HEAD\";\n if (!opts.skipTeamPack) {\n const result = await addTeamPackSubmodule(workspacePath, opts.packVersion);\n pinnedTag = result.pinnedTag ?? \"HEAD\";\n sp.succeed(`Pin team-ai-pack vào ${pinnedTag}`);\n } else {\n sp.succeed(\"Skip team-ai-pack (--skip-team-pack)\");\n }\n await finalizeWorkspaceScaffold({\n workspacePath,\n workspaceName: projectName,\n teamOwner,\n description: opts.description ?? `Dự án mới: ${projectName}`,\n packVersion: pinnedTag,\n autoYes: opts.yes,\n skipCommit: opts.commit === false,\n createWorkspaceRemote: opts.workspaceRemote,\n repoVisibility: opts.repoVisibility,\n repoOrg: opts.repoOrg,\n flow: \"new-project\",\n aiSkip: opts.aiSkip,\n });\n } catch (err) {\n sp.fail(\"Init workspace thất bại\");\n throw err;\n }\n}\n\n// ─── HELPERS ────────────────────────────────────────────────────────────────\n\n// Check origin remote của folder; nếu chưa có thì hỏi tạo (default Có) → gh repo create.\n// Trả về URL remote nếu có, undefined nếu user từ chối (caller fallback local path).\nasync function getOrCreateOriginRemote(\n folderPath: string,\n opts: InitOptions,\n): Promise<string | undefined> {\n const remotes = await git(folderPath).getRemotes(true);\n const origin = remotes.find((r) => r.name === \"origin\");\n if (origin?.refs.push) {\n log.success(`Folder đã có remote origin: ${origin.refs.push}`);\n return origin.refs.push;\n }\n\n const shouldCreate =\n opts.createRemote ??\n (await confirm({\n message: \"Folder chưa có remote. Tạo GitHub repo ngay để share team?\",\n default: true,\n }));\n if (!shouldCreate) {\n log.warn(\"Tiếp tục với local path. Workspace chỉ chạy được trên máy bạn.\");\n return undefined;\n }\n\n await ensureGitHubReady();\n const visibility = (opts.repoVisibility ??\n (await select({\n message: \"Visibility?\",\n choices: [\n { name: \"private (mặc định)\", value: \"private\" as const },\n { name: \"public\", value: \"public\" as const },\n ],\n }))) as RepoVisibility;\n const repoName = await input({\n message: \"Tên repo:\",\n default: basename(folderPath),\n });\n const urls = createGithubRemoteFromFolder({\n folder: folderPath,\n name: repoName,\n visibility,\n org: opts.repoOrg,\n });\n return urls.sshUrl;\n}\n\n// Scaffold workspace dùng cho flow 1 + flow 2: workspace = parent của src/.\n// src/ là submodule trỏ tới remote URL hoặc local path.\nasync function scaffoldWorkspaceWithSrcSubmodule(args: {\n workspacePath: string;\n workspaceName: string;\n srcRemoteUrl: string;\n teamOwner: string;\n description: string;\n packVersion?: string;\n autoYes?: boolean;\n skipCommit?: boolean;\n createWorkspaceRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n skipTeamPack?: boolean;\n flow: ProjectStatus;\n aiSkip?: boolean;\n}): Promise<void> {\n await ensureDir(args.workspacePath);\n await git(args.workspacePath).init();\n\n const sp = spinner(\n args.skipTeamPack ? \"Add submodule src/...\" : \"Add submodule src/ + team-ai-pack...\",\n );\n try {\n await git(args.workspacePath).subModule([\"add\", args.srcRemoteUrl, \"src\"]);\n let pinnedTag = \"HEAD\";\n if (!args.skipTeamPack) {\n const result = await addTeamPackSubmodule(args.workspacePath, args.packVersion);\n pinnedTag = result.pinnedTag ?? \"HEAD\";\n sp.succeed(`Pin team-ai-pack vào ${pinnedTag}`);\n } else {\n sp.succeed(\"Skip team-ai-pack (--skip-team-pack)\");\n }\n\n await finalizeWorkspaceScaffold({\n workspacePath: args.workspacePath,\n workspaceName: args.workspaceName,\n teamOwner: args.teamOwner,\n description: args.description,\n packVersion: pinnedTag,\n autoYes: args.autoYes,\n skipCommit: args.skipCommit,\n createWorkspaceRemote: args.createWorkspaceRemote,\n repoVisibility: args.repoVisibility,\n repoOrg: args.repoOrg,\n flow: args.flow,\n aiSkip: args.aiSkip,\n });\n } catch (err) {\n sp.fail(\"Init workspace thất bại\");\n throw err;\n }\n}\n\n// Common scaffold step sau khi src/ + team-ai-pack đã add xong.\nasync function finalizeWorkspaceScaffold(args: {\n workspacePath: string;\n workspaceName: string;\n teamOwner: string;\n description: string;\n packVersion: string;\n autoYes?: boolean;\n skipCommit?: boolean;\n createWorkspaceRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n flow: ProjectStatus;\n aiSkip?: boolean;\n}): Promise<void> {\n // Mode \"client\" được dùng trong scaffold-variable builder cũ — giữ giá trị\n // này để compatible với template hiện tại. Sẽ rename trong release sau.\n const vars = buildScaffoldVariables({\n projectName: args.workspaceName,\n projectDescription: args.description,\n teamOwner: args.teamOwner,\n packVersion: args.packVersion,\n mode: \"client\",\n });\n\n await createClaudeDirTree(args.workspacePath);\n await writeProjectKnowledgeFiles(args.workspacePath, vars);\n await writeRootClaudeMd(args.workspacePath, vars);\n await writeProjectSettings(args.workspacePath, vars);\n await appendGitignoreEntries(args.workspacePath);\n await ensureDir(join(args.workspacePath, \"notes\"));\n await ensureDir(join(args.workspacePath, \"scripts\"));\n\n await installGitHook(join(args.workspacePath, \".git\"), \"post-merge\");\n await installGitHook(join(args.workspacePath, \".git\", \"modules\", \"src\"), \"pre-push\");\n log.success(\"Cài post-merge (workspace) + pre-push (src/)\");\n\n await appendAuditEntry(\"init\", `flow=${args.flow},workspace=${args.workspaceName}`);\n await maybeCommitWorkspace(args.workspacePath, args.skipCommit);\n await maybeCreateWorkspaceRemote(args);\n\n let aiResult: Awaited<ReturnType<typeof runAiSetupPhase>> | null = null;\n if (args.aiSkip) {\n log.dim(\"Bỏ qua AI setup (--ai-skip). Setup sau qua: avatar ai setup\");\n } else {\n aiResult = await runAiSetupPhase({ workspacePath: args.workspacePath });\n }\n\n printInitSuccessBox(args.workspacePath, args.flow, aiResult);\n}\n\n// Hỏi/tạo remote GitHub cho workspace root. Chỉ chạy được khi đã commit\n// (gh repo create --push cần ít nhất 1 commit). Nếu user skip commit hoặc\n// từ chối tạo, workspace local-only — vẫn dùng được nhưng không share team.\nasync function maybeCreateWorkspaceRemote(args: {\n workspacePath: string;\n workspaceName: string;\n autoYes?: boolean;\n skipCommit?: boolean;\n createWorkspaceRemote?: boolean;\n repoVisibility?: string;\n repoOrg?: string;\n}): Promise<void> {\n // Skip nếu chưa có commit (gh repo create --push sẽ fail).\n if (args.skipCommit) {\n log.dim(\"Skip workspace remote (chưa commit). Setup sau qua: gh repo create ...\");\n return;\n }\n\n // Resolve từ flag hoặc prompt.\n let shouldCreate = args.createWorkspaceRemote;\n if (shouldCreate === undefined) {\n if (args.autoYes) return; // CI mode: default skip để không hỏi\n shouldCreate = await confirm({\n message: \"Tạo remote GitHub cho workspace để share team? (Avatar state)\",\n default: false,\n });\n }\n if (!shouldCreate) return;\n\n const visibility = ((args.repoVisibility as \"private\" | \"public\" | undefined) ??\n (args.autoYes\n ? \"private\"\n : await select({\n message: \"Workspace visibility?\",\n choices: [\n { name: \"private (mặc định, an toàn)\", value: \"private\" as const },\n { name: \"public\", value: \"public\" as const },\n ],\n }))) as \"private\" | \"public\";\n\n try {\n await createWorkspaceRemoteViaGh({\n workspacePath: args.workspacePath,\n workspaceName: args.workspaceName,\n visibility,\n org: args.repoOrg,\n });\n } catch (err) {\n log.warn(err instanceof Error ? err.message : String(err));\n log.warn(\"Workspace vẫn sẵn sàng local-only. Setup remote sau khi cần.\");\n }\n}\n\n// ─── shared utilities (giữ từ v1.0.1, chỉ đổi signature mode → flow) ───────\n\nexport async function resolveWorkspacePath(\n parent: string,\n desiredName: string,\n force?: boolean,\n): Promise<string> {\n const desired = join(parent, desiredName);\n if (await isEmptyOrMissing(desired)) return desired;\n\n const alternative = await findAlternativeWorkspaceName(parent, desiredName);\n if (!alternative) {\n throw new Error(`Không tìm được workspace path khả dụng trong ${parent}`);\n }\n\n log.warn(`Workspace path \"${desired}\" đã có nội dung.`);\n if (force) {\n log.info(`--force: dùng ${alternative}`);\n return alternative;\n }\n const useAlt = await confirm({ message: `Dùng \"${alternative}\" thay thế?`, default: true });\n if (!useAlt) throw new Error(\"Hủy init. Chạy lại với --workspace-name khác.\");\n return alternative;\n}\n\nasync function promptTeamOwner(currentUserEmail: string): Promise<string> {\n return await input({ message: \"Team owner email:\", default: currentUserEmail });\n}\n\nasync function maybeCommitWorkspace(workspacePath: string, skipCommit?: boolean): Promise<void> {\n // Mặc định LUÔN commit — giữ workspace ở git state hợp lệ (có baseline).\n // User muốn review trước commit thì pass --no-commit để skip.\n if (skipCommit) {\n log.warn(\"Skip commit (--no-commit). Chạy 'git status' + commit thủ công sau.\");\n return;\n }\n const g = git(workspacePath);\n await g.add([\"CLAUDE.md\", \".claude/\", \".gitignore\", \".gitmodules\", \"notes/\", \"scripts/\"]);\n await g.commit(\"chore: initialize Avatar workspace\");\n log.success(\"Đã commit workspace\");\n}\n\n// AI status line tùy theo kết quả runAiSetupPhase (hoặc null nếu --ai-skip).\nfunction formatAiStatusLine(aiResult: Awaited<ReturnType<typeof runAiSetupPhase>> | null): string {\n if (aiResult === null) {\n return ` ${chalk.yellow(\"AI:\")} skipped · ${chalk.cyan(\"avatar ai setup\")} để config sau`;\n }\n if (aiResult.ok) {\n const modelPart = aiResult.model ? ` · model=${aiResult.model}` : \"\";\n return ` ${chalk.green(\"AI:\")} ready · ${aiResult.provider}${modelPart}`;\n }\n return ` ${chalk.yellow(\"AI:\")} failed (${aiResult.reason.slice(0, 60)}) · thử ${chalk.cyan(\"avatar ai setup\")}`;\n}\n\nfunction printInitSuccessBox(\n rootPath: string,\n flow: ProjectStatus,\n aiResult: Awaited<ReturnType<typeof runAiSetupPhase>> | null = null,\n): void {\n const lines: string[] = [\n `${chalk.green(\"✓\")} Workspace sẵn sàng: ${relative(process.cwd(), rootPath) || rootPath}`,\n ` ${chalk.dim(`(flow: ${flow})`)}`,\n formatAiStatusLine(aiResult),\n \"\",\n ` ${chalk.cyan(`cd ${rootPath}`)}`,\n ` ${chalk.cyan(\"claude\")} Mở Claude Code ở workspace root`,\n \"\",\n ` ${chalk.cyan(\"avatar commit --src\")} Commit code lên remote src`,\n ` ${chalk.cyan(\"avatar commit --avatar\")} Commit Avatar state`,\n ` ${chalk.cyan(\"avatar sync\")} Pull team-ai-pack mới`,\n ` ${chalk.cyan(\"avatar uninstall\")} Gỡ Avatar (giữ code)`,\n ];\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\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","// Wrapper around `gh repo create <org>/<name> --<vis> --source=<folder>\n// --remote=origin --push`. Stream stdio để user thấy gh prompt nếu có.\nimport { spawnSync } from \"node:child_process\";\nimport type { RepoVisibility } from \"./validate-repo-name-and-visibility.js\";\n\nexport class RepoAlreadyExistsError extends Error {\n constructor(fullName: string) {\n super(`Repo \"${fullName}\" đã tồn tại trên GitHub. Đổi tên hoặc xóa repo cũ.`);\n this.name = \"RepoAlreadyExistsError\";\n }\n}\n\nexport interface ExecuteGhRepoCreateInput {\n folder: string;\n org: string;\n name: string;\n visibility: RepoVisibility;\n}\n\nexport interface ExecuteGhRepoCreateOutput {\n sshUrl: string;\n httpsUrl: string;\n}\n\nexport function executeGhRepoCreate(input: ExecuteGhRepoCreateInput): ExecuteGhRepoCreateOutput {\n const fullName = `${input.org}/${input.name}`;\n const args = [\n \"repo\",\n \"create\",\n fullName,\n `--${input.visibility}`,\n \"--source\",\n input.folder,\n \"--remote\",\n \"origin\",\n \"--push\",\n ];\n const r = spawnSync(\"gh\", args, { stdio: \"inherit\" });\n if (r.status !== 0) {\n // gh thường in \"GraphQL: Name already exists\" cho duplicate. Không parse\n // stdout (vì inherit) — surface generic error, user sẽ thấy stderr của gh.\n if (r.status === 1) {\n throw new RepoAlreadyExistsError(fullName);\n }\n throw new Error(`gh repo create thất bại (exit ${r.status})`);\n }\n return {\n sshUrl: `git@github.com:${fullName}.git`,\n httpsUrl: `https://github.com/${fullName}.git`,\n };\n}\n","// Lấy GitHub login mặc định của user qua `gh api user --jq .login`.\n// Dùng làm default org khi user không truyền --repo-org.\nimport { spawnSync } from \"node:child_process\";\n\nexport function resolveGithubUsernameDefault(): string {\n const r = spawnSync(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n if (r.status !== 0) {\n throw new Error(`Không lấy được GitHub username: ${r.stderr?.trim()}`);\n }\n return r.stdout.trim();\n}\n","// Validate repo name + visibility trước khi gọi `gh repo create`. Fail-fast với\n// thông báo Vietnamese rõ ràng. GitHub repo name spec: alphanumeric, dash,\n// underscore, dot. 1-100 chars.\nconst REPO_NAME_REGEX = /^[a-zA-Z0-9._-]{1,100}$/;\n\nexport type RepoVisibility = \"private\" | \"public\";\n\nexport class InvalidRepoNameError extends Error {\n constructor(name: string) {\n super(\n `Tên repo \"${name}\" không hợp lệ. Chỉ dùng chữ/số/dấu chấm/gạch/underscore, dài 1-100 ký tự.`,\n );\n this.name = \"InvalidRepoNameError\";\n }\n}\n\nexport function validateRepoName(name: string): void {\n if (!REPO_NAME_REGEX.test(name)) {\n throw new InvalidRepoNameError(name);\n }\n}\n\nexport function validateRepoVisibility(v: string): asserts v is RepoVisibility {\n if (v !== \"private\" && v !== \"public\") {\n throw new Error(`Visibility phải là \"private\" hoặc \"public\", nhận: \"${v}\"`);\n }\n}\n","// Orchestrator phase 4: validate input → gọi gh repo create → return URLs.\n// Caller chịu trách nhiệm đảm bảo gh đã auth (gọi ensureGitHubReady trước).\nimport { type ExecuteGhRepoCreateOutput, executeGhRepoCreate } from \"./execute-gh-repo-create.js\";\nimport { resolveGithubUsernameDefault } from \"./resolve-github-username-default.js\";\nimport { log } from \"./terminal-logger.js\";\nimport {\n type RepoVisibility,\n validateRepoName,\n validateRepoVisibility,\n} from \"./validate-repo-name-and-visibility.js\";\n\nexport interface CreateGithubRemoteInput {\n folder: string;\n name: string;\n visibility: RepoVisibility;\n org?: string; // mặc định = GitHub login của user\n}\n\nexport function createGithubRemoteFromFolder(\n input: CreateGithubRemoteInput,\n): ExecuteGhRepoCreateOutput {\n validateRepoName(input.name);\n validateRepoVisibility(input.visibility);\n\n const org = input.org ?? resolveGithubUsernameDefault();\n log.info(`Tạo GitHub repo ${org}/${input.name} (${input.visibility})...`);\n\n const urls = executeGhRepoCreate({\n folder: input.folder,\n org,\n name: input.name,\n visibility: input.visibility,\n });\n\n log.success(`Đã tạo: ${urls.sshUrl}`);\n return urls;\n}\n","// Tạo remote GitHub cho workspace + push initial commit. Khác với\n// create-github-remote-from-folder (dành cho src/): hàm này dành cho workspace\n// root (đã commit Avatar state) và setup tracking branch.\n//\n// Workspace remote là OPTIONAL: chỉ cần khi team muốn share Avatar state\n// (knowledge, hooks, settings) qua git. Workspace local-only vẫn dùng được cho\n// 1 dev cá nhân, nhưng không sync được cross-machine.\nimport { spawnSync } from \"node:child_process\";\nimport { ensureGitHubReady } from \"./git-auth-and-install-orchestrator.js\";\nimport { resolveGithubUsernameDefault } from \"./resolve-github-username-default.js\";\nimport { log } from \"./terminal-logger.js\";\nimport {\n type RepoVisibility,\n validateRepoName,\n validateRepoVisibility,\n} from \"./validate-repo-name-and-visibility.js\";\n\nexport interface CreateWorkspaceRemoteInput {\n workspacePath: string;\n workspaceName: string;\n visibility: RepoVisibility;\n org?: string;\n}\n\nexport interface CreateWorkspaceRemoteOutput {\n sshUrl: string;\n httpsUrl: string;\n}\n\n// Idempotent: nếu workspace đã có remote `origin`, skip. Nếu repo trên GitHub\n// đã tồn tại nhưng workspace chưa có remote, thử add remote + push.\nexport async function createWorkspaceRemoteViaGh(\n input: CreateWorkspaceRemoteInput,\n): Promise<CreateWorkspaceRemoteOutput> {\n validateRepoName(input.workspaceName);\n validateRepoVisibility(input.visibility);\n\n await ensureGitHubReady();\n const org = input.org ?? resolveGithubUsernameDefault();\n\n const fullName = `${org}/${input.workspaceName}`;\n log.info(`Tạo GitHub repo cho workspace: ${fullName} (${input.visibility})...`);\n\n // gh repo create --source=workspace --remote=origin --push tạo repo + add\n // remote `origin` + push branch hiện tại (main). Auto-track origin/main.\n const r = spawnSync(\n \"gh\",\n [\n \"repo\",\n \"create\",\n fullName,\n `--${input.visibility}`,\n \"--source\",\n input.workspacePath,\n \"--remote\",\n \"origin\",\n \"--push\",\n ],\n { stdio: \"inherit\" },\n );\n\n if (r.status !== 0) {\n throw new Error(\n `Tạo workspace remote thất bại (exit ${r.status}). Workspace vẫn dùng được local. Setup remote sau qua: gh repo create ${fullName} --${input.visibility} --source=. --remote=origin --push`,\n );\n }\n\n const sshUrl = `git@github.com:${fullName}.git`;\n const httpsUrl = `https://github.com/${fullName}.git`;\n log.success(`Workspace remote: ${sshUrl}`);\n return { sshUrl, httpsUrl };\n}\n","// Kiểm tra gh CLI đã login chưa. `gh auth status` exit 0 = OK.\n// Không parse stdout vì format thay đổi giữa các bản gh.\nimport { spawnSync } from \"node:child_process\";\n\nexport type GhAuthState = \"not-installed\" | \"not-authenticated\" | \"authenticated\";\n\nexport function checkGhCliAuthStatus(): GhAuthState {\n // Probe binary trước. spawnSync với gh không tồn tại trả ENOENT.\n const r = spawnSync(\"gh\", [\"auth\", \"status\"], { stdio: \"ignore\" });\n if (r.error && (r.error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return \"not-installed\";\n }\n return r.status === 0 ? \"authenticated\" : \"not-authenticated\";\n}\n","// Detect package manager để cài binary hệ thống (gh CLI). Order matters:\n// brew (macOS preferred) → winget (Windows) → apt/dnf/pacman (Linux distros).\n// Returns null nếu không tìm được PM nào — caller phải fail-fast.\nimport { spawnSync } from \"node:child_process\";\nimport { detectHostPlatform } from \"./detect-host-platform.js\";\n\nexport type PackageManager = \"brew\" | \"apt\" | \"dnf\" | \"pacman\" | \"winget\";\n\n// Probe binary có trong PATH không. Dùng `command -v` (POSIX) hoặc `where` (Win).\nfunction hasBinary(name: string): boolean {\n const platform = detectHostPlatform();\n const probe = platform === \"win32\" ? \"where\" : \"command\";\n const args = platform === \"win32\" ? [name] : [\"-v\", name];\n // spawnSync với shell=true để `command -v` (builtin) hoạt động.\n const r = spawnSync(probe, args, {\n shell: platform !== \"win32\",\n stdio: \"ignore\",\n });\n return r.status === 0;\n}\n\n// Trả về PM đầu tiên có sẵn theo thứ tự ưu tiên phù hợp với OS.\nexport function detectPackageManager(): PackageManager | null {\n const platform = detectHostPlatform();\n const candidates: PackageManager[] =\n platform === \"darwin\"\n ? [\"brew\"]\n : platform === \"win32\"\n ? [\"winget\"]\n : platform === \"linux\"\n ? [\"apt\", \"dnf\", \"pacman\"]\n : [];\n for (const pm of candidates) {\n if (hasBinary(pm)) return pm;\n }\n return null;\n}\n","// Cài `gh` CLI qua package manager đã detect. Stream stdio để user thấy progress.\n// Throws nếu cài fail hoặc PM trả non-zero.\nimport { spawnSync } from \"node:child_process\";\nimport type { PackageManager } from \"./detect-package-manager.js\";\nimport { log } from \"./terminal-logger.js\";\n\n// Map PM → command + args để cài gh. apt/dnf cần sudo; brew/pacman/winget thì không.\nconst INSTALL_COMMANDS: Record<PackageManager, { cmd: string; args: string[] }> = {\n brew: { cmd: \"brew\", args: [\"install\", \"gh\"] },\n apt: { cmd: \"sudo\", args: [\"apt-get\", \"install\", \"-y\", \"gh\"] },\n dnf: { cmd: \"sudo\", args: [\"dnf\", \"install\", \"-y\", \"gh\"] },\n pacman: { cmd: \"sudo\", args: [\"pacman\", \"-S\", \"--noconfirm\", \"github-cli\"] },\n winget: { cmd: \"winget\", args: [\"install\", \"--id\", \"GitHub.cli\", \"-e\", \"--silent\"] },\n};\n\nexport function installGhCliViaPackageManager(pm: PackageManager): void {\n const spec = INSTALL_COMMANDS[pm];\n log.info(`Đang cài gh CLI qua ${pm}...`);\n const r = spawnSync(spec.cmd, spec.args, { stdio: \"inherit\" });\n if (r.status !== 0) {\n throw new Error(`Cài gh CLI thất bại qua ${pm} (exit ${r.status}). Cài tay rồi chạy lại.`);\n }\n log.success(\"Đã cài gh CLI\");\n}\n","// Config git credential helper dùng gh token. Cần thiết để `git ls-remote`,\n// `git clone`, `git push` qua HTTPS hoạt động khi gh đã auth nhưng git chưa\n// biết về token đó. Idempotent — chạy nhiều lần OK.\nimport { spawnSync } from \"node:child_process\";\nimport { log } from \"./terminal-logger.js\";\n\nexport function setupGitCredentialViaGh(): void {\n const r = spawnSync(\"gh\", [\"auth\", \"setup-git\"], { stdio: \"ignore\" });\n if (r.status !== 0) {\n // Không throw — nếu setup-git fail, git operation sau có thể vẫn work\n // (vd user đã có credential helper khác). Chỉ warn.\n log.warn(\"gh auth setup-git fail (non-fatal). Nếu git clone lỗi 128 → chạy thủ công.\");\n return;\n }\n log.dim(\"Git credential helper đã link với gh token.\");\n}\n","// Spawn `gh auth login --hostname github.com --web` interactive.\n// User sẽ thấy device-code prompt và browser tự mở. Block đến khi xong.\nimport { spawnSync } from \"node:child_process\";\nimport { log } from \"./terminal-logger.js\";\n\nexport function triggerGhCliAuthLogin(): void {\n log.info(\"Khởi động đăng nhập GitHub qua gh CLI (browser sẽ mở)...\");\n const r = spawnSync(\n \"gh\",\n [\"auth\", \"login\", \"--hostname\", \"github.com\", \"--web\", \"--git-protocol\", \"ssh\"],\n { stdio: \"inherit\" },\n );\n if (r.status !== 0) {\n throw new Error(`gh auth login thất bại (exit ${r.status}). Thử 'gh auth login' tay.`);\n }\n log.success(\"Đã đăng nhập GitHub\");\n}\n","// Verify một remote URL có accessible không bằng `git ls-remote <url> HEAD`\n// với timeout 5 giây. Tách ra để init flow check sớm — fail-fast nếu URL sai.\nimport { spawnSync } from \"node:child_process\";\n\nconst TIMEOUT_MS = 5_000;\n\nexport class RemoteNotAccessibleError extends Error {\n constructor(url: string, reason: string) {\n super(`Không truy cập được remote ${url}: ${reason}`);\n this.name = \"RemoteNotAccessibleError\";\n }\n}\n\nexport function verifyGitRemoteAccessible(url: string): void {\n const r = spawnSync(\"git\", [\"ls-remote\", \"--exit-code\", url, \"HEAD\"], {\n stdio: \"ignore\",\n timeout: TIMEOUT_MS,\n });\n if (r.status === 0) return;\n // signal=SIGTERM nghĩa là Node.js kill do timeout.\n if (r.signal === \"SIGTERM\") throw new RemoteNotAccessibleError(url, \"timeout 5s\");\n throw new RemoteNotAccessibleError(url, `git ls-remote exit ${r.status}`);\n}\n","// Orchestrator phase 2: đảm bảo gh CLI có và đã auth. Tự cài + tự login nếu cần.\n// Chỉ throws khi không thể tự fix (PM thiếu, login thất bại).\nimport { checkGhCliAuthStatus } from \"./check-gh-cli-auth-status.js\";\nimport { detectPackageManager } from \"./detect-package-manager.js\";\nimport { installGhCliViaPackageManager } from \"./install-gh-cli-via-package-manager.js\";\nimport { setupGitCredentialViaGh } from \"./setup-git-credential-via-gh.js\";\nimport { log } from \"./terminal-logger.js\";\nimport { triggerGhCliAuthLogin } from \"./trigger-gh-cli-auth-login.js\";\nimport { verifyGitRemoteAccessible } from \"./verify-git-remote-accessible.js\";\n\n// Gọi trước mọi flow cần GitHub (init nhánh 1, nhánh 2-create-remote, nhánh 3).\n// remoteUrl optional — nếu truyền sẽ verify access cụ thể.\nexport async function ensureGitHubReady(remoteUrl?: string): Promise<void> {\n let state = checkGhCliAuthStatus();\n\n if (state === \"not-installed\") {\n log.warn(\"gh CLI chưa cài. Avatar sẽ tự cài.\");\n const pm = detectPackageManager();\n if (!pm) {\n throw new Error(\n \"Không phát hiện package manager (brew/apt/dnf/pacman/winget). Cài gh CLI tay rồi chạy lại: https://cli.github.com\",\n );\n }\n installGhCliViaPackageManager(pm);\n state = checkGhCliAuthStatus();\n }\n\n if (state === \"not-authenticated\") {\n log.warn(\"Chưa đăng nhập GitHub.\");\n triggerGhCliAuthLogin();\n state = checkGhCliAuthStatus();\n if (state !== \"authenticated\") {\n throw new Error(\"Sau gh auth login vẫn chưa authenticated. Thử lại.\");\n }\n }\n\n log.success(\"gh CLI sẵn sàng\");\n\n // Đảm bảo git CLI dùng gh token cho HTTPS operations. Idempotent — chạy\n // mỗi lần init OK. Fix lỗi `git ls-remote exit 128` khi gh đã auth nhưng\n // git chưa biết.\n setupGitCredentialViaGh();\n\n if (remoteUrl) {\n verifyGitRemoteAccessible(remoteUrl);\n log.success(`Remote accessible: ${remoteUrl}`);\n }\n}\n","// Safe Bootstrap (Tier A) — bảo vệ folder user khỏi mất changes uncommitted khi\n// `avatar init` modify .gitignore + tạo initial commit.\n//\n// Flow:\n// 1. detectFolderGitState() → \"empty\" | \"untracked-only\" | \"clean\" | \"dirty\"\n// 2. empty/clean → bootstrap thẳng (không có rủi ro)\n// 3. dirty/untracked-only → promptBootstrapStrategy() → 4 lựa chọn\n// 4. executeBootstrapWithStrategy() → branch xử lý từng strategy\n//\n// 4 strategies:\n// - stash (DEFAULT highlight): git stash -u → bootstrap → stash pop\n// - commit-all (legacy v1.1.6): git add . && commit, all changes bundled\n// - skip: throw InitAbortedByUserError — user tự commit rồi chạy lại\n// - branch: checkout -b avatar/init → bootstrap → checkout back\n//\n// CLI flags:\n// --bootstrap-strategy <s> : preset, skip prompt\n// --preserve-uncommitted : alias cho --bootstrap-strategy=stash\n// --yes : CI mode → default stash (safest)\nimport { readdirSync } from \"node:fs\";\nimport { select } from \"@inquirer/prompts\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\nimport { appendAuditEntry } from \"./audit-log-appender.js\";\nimport { checkFolderHasGit } from \"./check-folder-has-git.js\";\nimport { createInitialGitCommit } from \"./create-initial-git-commit.js\";\nimport { detectFolderTechStack } from \"./detect-folder-tech-stack.js\";\nimport { composeGitignoreContent } from \"./gitignore-template-loader.js\";\nimport { log } from \"./terminal-logger.js\";\nimport { writeOrMergeGitignore } from \"./write-or-merge-gitignore.js\";\n\nexport type GitState = \"empty\" | \"untracked-only\" | \"clean\" | \"dirty\";\n\nexport type BootstrapStrategy = \"stash\" | \"commit-all\" | \"skip\" | \"branch\";\n\nexport interface SafeBootstrapOptions {\n presetStrategy?: BootstrapStrategy;\n autoYes?: boolean;\n}\n\n// User chọn skip giữa wizard → caller catch để abort init.ts gracefully.\nexport class InitAbortedByUserError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InitAbortedByUserError\";\n }\n}\n\n// === Step 1: detect git state ===\nexport async function detectFolderGitState(folderPath: string): Promise<GitState> {\n const hasGit = checkFolderHasGit(folderPath);\n if (!hasGit) {\n // Filter `.git` (rare gitlink file edge case) + dotfiles không count cho empty check.\n const entries = readdirSync(folderPath).filter((e) => e !== \".git\");\n return entries.length === 0 ? \"empty\" : \"untracked-only\";\n }\n const g = simpleGit({ baseDir: folderPath });\n const status = await g.status();\n return status.isClean() ? \"clean\" : \"dirty\";\n}\n\n// === Step 2: prompt strategy ===\nexport async function promptBootstrapStrategy(\n state: GitState,\n opts: SafeBootstrapOptions,\n): Promise<BootstrapStrategy> {\n // Preset flag → skip prompt hoàn toàn.\n if (opts.presetStrategy) return opts.presetStrategy;\n\n // CI mode (--yes) → safe default. Stash là an toàn nhất (reversible).\n if (opts.autoYes) return \"stash\";\n\n // Empty/clean state không gọi prompt (caller skip). Defensive return.\n if (state === \"empty\" || state === \"clean\") return \"commit-all\";\n\n return (await select({\n message:\n state === \"dirty\"\n ? \"Folder có changes chưa commit. Cách xử lý:\"\n : \"Folder có file chưa version. Cách xử lý:\",\n choices: [\n {\n value: \"stash\" as const,\n name: \"1. Stash changes → bootstrap → restore (KHUYẾN NGHỊ)\",\n },\n {\n value: \"commit-all\" as const,\n name: \"2. Commit toàn bộ vào initial commit (legacy v1.1.6)\",\n },\n {\n value: \"skip\" as const,\n name: \"3. Skip — tôi commit thủ công rồi chạy lại\",\n },\n {\n value: \"branch\" as const,\n name: \"4. Commit vào branch riêng `avatar/init` (main giữ sạch)\",\n },\n ],\n default: \"stash\",\n })) as BootstrapStrategy;\n}\n\n// === Helpers: stash + branch ===\n\n// Stash user changes (kể cả untracked) với name rõ ràng để track. Trả true nếu stash thật sự.\nasync function stashUserChanges(g: SimpleGit, stashName: string): Promise<boolean> {\n const status = await g.status();\n if (status.isClean() && status.not_added.length === 0) return false;\n await g.stash([\"push\", \"--include-untracked\", \"-m\", stashName]);\n log.info(`Stashed changes: ${stashName}`);\n return true;\n}\n\n// Restore stash. Nếu conflict → log warning + leave markers (KHÔNG tự revert).\nasync function restoreStash(g: SimpleGit, stashName: string): Promise<void> {\n try {\n await g.stash([\"pop\"]);\n log.success(`Restored stash: ${stashName}`);\n } catch (err) {\n log.warn(\n \"Restore stash conflict — files có Avatar tạo và stash của user xung đột. Stash giữ tại ref stash@{0}.\",\n );\n log.warn(\"Resolve: git stash show -p stash@{0} → fix conflict → git stash drop\");\n log.dim(`Detail: ${(err as Error).message}`);\n }\n}\n\n// Lấy branch hiện tại (HEAD). Fallback \"main\" nếu detached HEAD.\nasync function getCurrentBranch(g: SimpleGit): Promise<string> {\n try {\n const result = await g.revparse([\"--abbrev-ref\", \"HEAD\"]);\n const branch = result.trim();\n return branch === \"HEAD\" ? \"main\" : branch;\n } catch {\n return \"main\";\n }\n}\n\n// === Step 3: execute strategy ===\nasync function writeAvatarGitignore(folderPath: string): Promise<void> {\n const stacks = detectFolderTechStack(folderPath);\n log.info(`Tech stack: ${stacks.join(\", \")}`);\n writeOrMergeGitignore(folderPath, composeGitignoreContent(stacks));\n log.success(\".gitignore đã ghi (Avatar block)\");\n}\n\nexport async function executeBootstrapWithStrategy(\n folderPath: string,\n strategy: BootstrapStrategy,\n): Promise<void> {\n const g = simpleGit({ baseDir: folderPath });\n\n switch (strategy) {\n case \"skip\":\n throw new InitAbortedByUserError(\n \"Init aborted. Commit thủ công changes hiện tại rồi chạy lại `avatar init`.\",\n );\n\n case \"stash\": {\n const stashName = `avatar-init-backup-${Date.now()}`;\n // Stash cần initial commit để work. Nếu folder chưa có .git hoặc chưa có commit\n // → init + empty commit baseline trước, sau đó mới stash user changes.\n const hadGit = checkFolderHasGit(folderPath);\n if (!hadGit) {\n await g.init();\n await g.branch([\"-M\", \"main\"]).catch(() => undefined);\n }\n const hasCommit = (await g.raw([\"rev-list\", \"-n\", \"1\", \"--all\"]).catch(() => \"\")).trim();\n if (!hasCommit) {\n await g.commit(\"chore: avatar baseline (pre-stash)\", undefined, { \"--allow-empty\": null });\n }\n const stashed = await stashUserChanges(g, stashName);\n try {\n await writeAvatarGitignore(folderPath);\n await createInitialGitCommit(folderPath);\n } finally {\n // Always restore stash dù bootstrap fail giữa chừng.\n if (stashed) await restoreStash(g, stashName);\n }\n break;\n }\n\n case \"commit-all\": {\n // Legacy v1.1.6 behavior — KHÔNG dùng cho default mới nhưng giữ cho backward compat.\n await writeAvatarGitignore(folderPath);\n await createInitialGitCommit(folderPath);\n break;\n }\n\n case \"branch\": {\n // Cần repo trước. Nếu chưa có git thì init + commit baseline ở main đầu tiên.\n const hadGit = checkFolderHasGit(folderPath);\n if (!hadGit) {\n await g.init();\n await g.branch([\"-M\", \"main\"]);\n }\n const originalBranch = await getCurrentBranch(g);\n // checkoutLocalBranch fail nếu branch đã tồn tại — fallback checkout existing.\n try {\n await g.checkoutLocalBranch(\"avatar/init\");\n } catch {\n await g.checkout(\"avatar/init\");\n }\n await writeAvatarGitignore(folderPath);\n await createInitialGitCommit(folderPath);\n // Switch back. Nếu fail (vd no commits ở branch gốc) → ở lại avatar/init.\n try {\n await g.checkout(originalBranch);\n log.info(\n `Avatar init committed ở branch 'avatar/init'. Switch back về '${originalBranch}'. Merge khi sẵn sàng: git merge avatar/init`,\n );\n } catch {\n log.warn(\n `Không switch về '${originalBranch}' được — ở lại branch 'avatar/init'. Switch tay sau.`,\n );\n }\n break;\n }\n }\n}\n\n// === Main orchestrator (thay bootstrapGitInFolder cho dirty/untracked case) ===\nexport async function safeBootstrapGitInFolder(\n folderPath: string,\n opts: SafeBootstrapOptions = {},\n): Promise<void> {\n const state = await detectFolderGitState(folderPath);\n log.info(`Folder state: ${state}`);\n\n // Empty/clean → bootstrap thẳng, không prompt.\n if (state === \"empty\" || state === \"clean\") {\n await writeAvatarGitignore(folderPath);\n if (state === \"empty\") {\n await createInitialGitCommit(folderPath);\n }\n await appendAuditEntry(\"bootstrap\", `state=${state},strategy=auto`);\n return;\n }\n\n // Dirty/untracked → prompt + execute.\n const strategy = await promptBootstrapStrategy(state, opts);\n await executeBootstrapWithStrategy(folderPath, strategy);\n await appendAuditEntry(\"bootstrap\", `state=${state},strategy=${strategy}`);\n}\n","// Kiểm tra folder đã là git repo chưa. Đơn giản: check tồn tại của \".git\"\n// (folder hoặc file gitlink — cả hai đều hợp lệ với submodule).\nimport { existsSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport function checkFolderHasGit(folderPath: string): boolean {\n const gitPath = join(folderPath, \".git\");\n if (!existsSync(gitPath)) return false;\n // .git có thể là directory (repo bình thường) hoặc file (submodule gitlink).\n // Cả 2 đều xem là \"đã có git\".\n const stat = statSync(gitPath);\n return stat.isDirectory() || stat.isFile();\n}\n","// Init git repo trong folder + tạo initial commit. Idempotent: skip nếu đã\n// có commit. Default branch \"main\".\nimport { simpleGit } from \"simple-git\";\n\nconst INITIAL_COMMIT_MESSAGE = \"chore: initial commit\";\n\nexport async function createInitialGitCommit(folderPath: string): Promise<void> {\n const g = simpleGit({ baseDir: folderPath });\n\n // Init nếu chưa có .git.\n const isRepo = await g.checkIsRepo().catch(() => false);\n if (!isRepo) {\n await g.init();\n }\n\n // Đảm bảo branch hiện tại là main (đổi master → main nếu cần).\n // Một số git config user có init.defaultBranch=master.\n try {\n await g.branch([\"-M\", \"main\"]);\n } catch {\n // Repo trống chưa có commit nào — branch -M sẽ fail. Bỏ qua, commit\n // đầu tiên dưới đây sẽ tạo branch main qua HEAD ref.\n }\n\n // Stage all + commit. Nếu không có file (folder rỗng) thì commit empty để\n // submodule add có HEAD reference dùng.\n await g.add(\".\");\n const status = await g.status();\n const hasCommits = (await g.raw([\"rev-list\", \"-n\", \"1\", \"--all\"]).catch(() => \"\")).trim();\n if (hasCommits) return; // Đã có commit, skip.\n\n if (status.files.length === 0) {\n await g.commit(INITIAL_COMMIT_MESSAGE, undefined, { \"--allow-empty\": null });\n } else {\n await g.commit(INITIAL_COMMIT_MESSAGE);\n }\n}\n","// Detect tech stack của folder qua signature file ở root. Trả về tất cả stack\n// match được (folder polyglot là chuyện thường — vd monorepo Node + Python).\n// Nếu không match gì → [\"generic\"].\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport type TechStack = \"node\" | \"python\" | \"go\" | \"rust\" | \"java\" | \"ruby\" | \"generic\";\n\n// Bảng signature: stack → các file đủ điều kiện claim stack đó.\nconst SIGNATURES: Record<Exclude<TechStack, \"generic\">, string[]> = {\n node: [\"package.json\"],\n python: [\"pyproject.toml\", \"requirements.txt\", \"setup.py\", \"Pipfile\"],\n go: [\"go.mod\"],\n rust: [\"Cargo.toml\"],\n java: [\"pom.xml\", \"build.gradle\", \"build.gradle.kts\"],\n ruby: [\"Gemfile\"],\n};\n\nexport function detectFolderTechStack(folderPath: string): TechStack[] {\n const matched: TechStack[] = [];\n for (const [stack, files] of Object.entries(SIGNATURES) as [\n Exclude<TechStack, \"generic\">,\n string[],\n ][]) {\n if (files.some((f) => existsSync(join(folderPath, f)))) {\n matched.push(stack);\n }\n }\n return matched.length > 0 ? matched : [\"generic\"];\n}\n","// Load template gitignore từ src/templates/gitignore/<stack>.txt và compose\n// nội dung tổng hợp cho 1+ stack. Generic luôn được prepend.\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { TechStack } from \"./detect-folder-tech-stack.js\";\n\n// Resolve template dir tương đối với file này, không phải CWD. Khi bundle bằng\n// tsup, file này nằm trong dist/, templates nằm trong src/templates — tsup copy\n// templates qua --publicDir (đã cấu hình trong tsup.config.ts) hoặc resolve\n// qua relative path.\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// Thứ tự search: relative tới file build (dist/), fallback dev (src/lib/).\nconst CANDIDATE_DIRS = [\n join(__dirname, \"..\", \"templates\", \"gitignore\"),\n join(__dirname, \"..\", \"..\", \"src\", \"templates\", \"gitignore\"),\n];\n\nconst AVATAR_MARKER_START = \"# === avatar ===\";\nconst AVATAR_MARKER_END = \"# === /avatar ===\";\n\nfunction readTemplate(stack: TechStack): string {\n for (const dir of CANDIDATE_DIRS) {\n try {\n return readFileSync(join(dir, `${stack}.txt`), \"utf8\");\n } catch {\n // continue\n }\n }\n throw new Error(`Không tìm thấy template gitignore cho stack \"${stack}\"`);\n}\n\n// Compose: generic luôn ở đầu, sau đó các stack khác theo thứ tự detect.\n// Wrap trong marker để uninstall biết range gỡ chính xác.\nexport function composeGitignoreContent(stacks: TechStack[]): string {\n const all: TechStack[] = [\"generic\", ...stacks.filter((s) => s !== \"generic\")];\n const sections = all.map((s) => `# --- ${s} ---\\n${readTemplate(s).trim()}`);\n return [AVATAR_MARKER_START, ...sections, AVATAR_MARKER_END, \"\"].join(\"\\n\");\n}\n\nexport { AVATAR_MARKER_START, AVATAR_MARKER_END };\n","// Ghi .gitignore: tạo mới nếu chưa có, merge content nếu đã có. Merge logic\n// dùng marker `# === avatar === ... # === /avatar ===`: replace block đó nếu\n// tồn tại, append nếu chưa.\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { AVATAR_MARKER_END, AVATAR_MARKER_START } from \"./gitignore-template-loader.js\";\n\nexport function writeOrMergeGitignore(folderPath: string, avatarBlock: string): void {\n const path = join(folderPath, \".gitignore\");\n\n if (!existsSync(path)) {\n writeFileSync(path, avatarBlock, \"utf8\");\n return;\n }\n\n const existing = readFileSync(path, \"utf8\");\n const startIdx = existing.indexOf(AVATAR_MARKER_START);\n const endIdx = existing.indexOf(AVATAR_MARKER_END);\n\n // Đã có marker → replace block giữa marker (giữ content trước/sau).\n if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + AVATAR_MARKER_END.length);\n writeFileSync(path, `${before.trimEnd()}\\n\\n${avatarBlock}${after.trimStart()}`, \"utf8\");\n return;\n }\n\n // Chưa có marker → append phía cuối, thêm newline phân cách.\n writeFileSync(path, `${existing.trimEnd()}\\n\\n${avatarBlock}`, \"utf8\");\n}\n","// Manage the team-ai-pack git submodule lifecycle: add, update, pin-to-tag,\n// changelog extraction. Used by `avatar init` and `avatar sync`.\nimport { join } from \"node:path\";\nimport {\n addSubmodule,\n checkoutTagInSubmodule,\n currentCommitSha,\n latestTag,\n} from \"./git-operations.js\";\nimport { resolveTeamPackRepoUrl } from \"./resolve-team-pack-repo-url.js\";\nimport { log } from \"./terminal-logger.js\";\n\n// Resolve URL động qua resolveTeamPackRepoUrl() — không hardcode. Export getter\n// để legacy code đọc URL được nhưng kết quả phụ thuộc env + gh user hiện tại.\nexport function getTeamPackRepoUrl(): string {\n return resolveTeamPackRepoUrl();\n}\n\n// Backward-compat: snapshot URL lúc load module (v1.0/1.1 đã expose). Sẽ remove\n// ở v2.0.0. New code dùng getTeamPackRepoUrl() để luôn pickup env latest.\nexport const TEAM_PACK_REPO_URL = resolveTeamPackRepoUrl();\nexport const TEAM_PACK_RELATIVE_PATH = \".claude/pack\";\n\n// Add the team-ai-pack submodule into a fresh project and pin it to a tag.\n// If `tag` is omitted, checks out the latest tag in the freshly-cloned submodule.\n// Nếu repo không tồn tại / không access được → throw lỗi rõ ràng kèm gợi ý fix.\nexport async function addTeamPackSubmodule(\n projectRoot: string,\n tag?: string,\n): Promise<{ pinnedTag: string | null }> {\n const url = resolveTeamPackRepoUrl();\n try {\n await addSubmodule(url, TEAM_PACK_RELATIVE_PATH, projectRoot);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"Repository not found\") || msg.includes(\"not found\")) {\n log.error(\n `Repo team-ai-pack không tồn tại: ${url}\\n Cách fix:\\n 1. Tạo repo: gh repo create <owner>/team-ai-pack --private --add-readme\\n 2. Hoặc override URL: export AVATAR_TEAM_PACK_REPO_URL=<url-repo-của-bạn>\\n 3. Hoặc dùng flag --skip-team-pack`,\n );\n }\n throw err;\n }\n\n // Resolve which tag to pin to. If caller passed one, honour it; otherwise\n // ask the just-cloned submodule for its latest tag.\n let target = tag ?? null;\n if (!target) {\n target = await latestTag(join(projectRoot, TEAM_PACK_RELATIVE_PATH));\n }\n\n if (target) {\n await checkoutTagInSubmodule(TEAM_PACK_RELATIVE_PATH, target, projectRoot);\n }\n return { pinnedTag: target };\n}\n\n// Read the current pinned version of the pack submodule. Returns the tag name\n// if HEAD matches a tag, otherwise the short SHA.\nexport async function readPinnedPackVersion(projectRoot: string): Promise<string> {\n const submoduleRoot = join(projectRoot, TEAM_PACK_RELATIVE_PATH);\n const tag = await latestTag(submoduleRoot);\n if (tag) return tag;\n const sha = await currentCommitSha(submoduleRoot);\n return sha.slice(0, 7);\n}\n","// Resolve URL của team-ai-pack submodule. Thứ tự ưu tiên:\n// 1. Env var AVATAR_TEAM_PACK_REPO_URL (explicit override)\n// 2. GitHub login của user đang auth (smart default: <gh-user>/team-ai-pack)\n// 3. Fallback hardcode \"LukeNALS/team-ai-pack\" (legacy v1.0/1.1.0)\n//\n// Cho phép user account khác nhau tự dùng repo riêng mà không cần config.\nimport { resolveGithubUsernameDefault } from \"./resolve-github-username-default.js\";\n\nconst LEGACY_FALLBACK = \"https://github.com/LukeNALS/team-ai-pack.git\";\n\nexport function resolveTeamPackRepoUrl(): string {\n if (process.env.AVATAR_TEAM_PACK_REPO_URL) {\n return process.env.AVATAR_TEAM_PACK_REPO_URL;\n }\n\n try {\n const ghUser = resolveGithubUsernameDefault();\n if (ghUser) return `https://github.com/${ghUser}/team-ai-pack.git`;\n } catch {\n // gh chưa auth — fallback legacy.\n }\n\n return LEGACY_FALLBACK;\n}\n","// Pure helpers for `avatar init` conflict detection and workspace path\n// resolution. Extracted from init.ts so they're unit-testable without\n// triggering inquirer prompts or git operations.\n\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pathExists } from \"../lib/filesystem-helpers.js\";\nimport { AVATAR_MANAGED_PATHS } from \"../lib/project-tree-scaffolder.js\";\n\n// True if path doesn't exist OR is an empty directory (ignoring dotfiles and\n// Windows Thumbs.db noise). Safe to scaffold into. macOS .DS_Store and\n// .localized are already filtered by the dotfile rule.\nexport async function isEmptyOrMissing(path: string): Promise<boolean> {\n if (!(await pathExists(path))) return true;\n try {\n const entries = await readdir(path);\n const meaningful = entries.filter((e) => !e.startsWith(\".\") && e !== \"Thumbs.db\");\n return meaningful.length === 0;\n } catch {\n return false;\n }\n}\n\n// Return Avatar-managed top-level paths that already exist in projectRoot.\n// Caller decides whether to abort, prompt, or auto-backup.\nexport async function detectAvatarConflicts(projectRoot: string): Promise<string[]> {\n const found: string[] = [];\n for (const rel of AVATAR_MANAGED_PATHS) {\n if (await pathExists(join(projectRoot, rel))) found.push(rel);\n }\n return found;\n}\n\n// Find first numbered alternative path (e.g. \"foo-2\", \"foo-3\", ...) under\n// `parent` that is empty or missing. Returns null if exhausted.\n// maxAttempts defaults to 10; if a user has 9+ workspaces with the same\n// base name, something else is wrong.\nexport async function findAlternativeWorkspaceName(\n parent: string,\n desiredName: string,\n maxAttempts = 10,\n): Promise<string | null> {\n for (let i = 2; i < maxAttempts; i++) {\n const candidate = join(parent, `${desiredName}-${i}`);\n if (await isEmptyOrMissing(candidate)) return candidate;\n }\n return null;\n}\n","// Pure transformation helpers used by `avatar init` to derive project names,\n// workspace names from git URLs, and build the ScaffoldVariables struct for\n// template rendering. Extracted from init.ts for testability — no IO,\n// no prompts, no git calls.\n\nimport type { ScaffoldVariables } from \"../lib/project-tree-scaffolder.js\";\nimport type { InitMode } from \"../types/config-schema.js\";\n\nconst AVATAR_CLI_VERSION = \"1.0.1\";\n\n// Last path segment of an absolute project root, used as fallback project\n// name when user doesn't supply one explicitly. Handles trailing slashes.\nexport function projectNameOf(projectRoot: string): string {\n return projectRoot.split(\"/\").filter(Boolean).pop() ?? \"avatar-project\";\n}\n\n// Infer workspace folder name from a git remote URL.\n// \"git@github.com:org/repo.git\" → \"avatar-repo-workspace\"\n// \"https://github.com/org/repo.git\" → \"avatar-repo-workspace\"\n// \"https://github.com/org/repo\" → \"avatar-repo-workspace\"\n// fallback when match fails → \"avatar-client-workspace\"\nexport function inferWorkspaceName(repoUrl: string): string {\n const m = repoUrl.match(/[/:]([^/]+?)(\\.git)?$/);\n const base = m?.[1] ?? \"client\";\n return `avatar-${base}-workspace`;\n}\n\n// Build the template-rendering variable bag. lastScan stamps \"now\" — tests\n// that need a deterministic value should freeze time via vi.useFakeTimers().\nexport function buildScaffoldVariables(args: {\n projectName: string;\n projectDescription: string;\n teamOwner: string;\n packVersion: string;\n mode: InitMode;\n}): ScaffoldVariables {\n return {\n projectName: args.projectName,\n projectDescription: args.projectDescription,\n teamOwner: args.teamOwner,\n avatarVersion: AVATAR_CLI_VERSION,\n packVersion: args.packVersion,\n lastScan: new Date().toISOString(),\n mode: args.mode,\n };\n}\n","import boxen from \"boxen\";\n// `avatar login [--reset]` — Command 01 spec.\n// Implements the user-facing flow: announce verification URL, open browser,\n// poll Google until token returned, validate domain, persist credentials.\nimport type { Command } from \"commander\";\nimport open from \"open\";\nimport { appendAuditEntry } from \"../lib/audit-log-appender.js\";\nimport { printAvatarBanner } from \"../lib/avatar-ascii-banner.js\";\nimport {\n buildUserConfig,\n buildVerificationUrl,\n decodeIdToken,\n pollForToken,\n requestDeviceCode,\n revokeToken,\n verifyHostedDomain,\n} from \"../lib/google-oauth-device-flow.js\";\nimport { chalk, log, spinner } from \"../lib/terminal-logger.js\";\nimport {\n USER_CONFIG_PATH,\n clearUserConfig,\n isTokenExpired,\n readUserConfig,\n writeUserConfig,\n} from \"../lib/user-config-store.js\";\n\nexport function registerLoginCommand(program: Command): void {\n program\n .command(\"login\")\n .description(\"Đăng nhập Google SSO (workspace @nal.vn)\")\n .option(\"--reset\", \"Xóa credential cũ và đăng nhập lại\")\n .action(async (opts: { reset?: boolean }) => {\n try {\n await runLogin(opts);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runLogin(opts: { reset?: boolean }): Promise<void> {\n // Banner trước khi vào device-code flow để user nhận diện thương hiệu.\n printAvatarBanner({ tagline: \"Đăng nhập Google SSO · workspace @nal.vn\" });\n\n // Step 1 of spec: short-circuit if already logged in and token is still good.\n if (opts.reset) {\n await clearUserConfig();\n await appendAuditEntry(\"login_reset\");\n } else {\n const existing = await readUserConfig();\n if (existing && !isTokenExpired(existing)) {\n log.success(`Đã đăng nhập: ${existing.email}`);\n return;\n }\n }\n\n // Step 2: request device + user code.\n const deviceSpinner = spinner(\"Đang yêu cầu device code từ Google...\");\n let deviceCode: Awaited<ReturnType<typeof requestDeviceCode>>;\n try {\n deviceCode = await requestDeviceCode();\n deviceSpinner.succeed(\"Nhận device code\");\n } catch (err) {\n deviceSpinner.fail(\"Không kết nối được Google\");\n throw err;\n }\n\n // Step 3: display instructions to user.\n const verificationUrl = buildVerificationUrl(deviceCode);\n const instructions = [\n `1. Truy cập: ${chalk.cyan(deviceCode.verification_url)}`,\n `2. Nhập code: ${chalk.bold.yellow(deviceCode.user_code)}`,\n \"\",\n `Hoặc Avatar tự mở browser, click ${chalk.green(\"Allow\")}...`,\n ].join(\"\\n\");\n process.stdout.write(`${boxen(instructions, { padding: 1, borderStyle: \"round\" })}\\n`);\n\n // Step 4: open browser. Failure here is non-fatal — user can copy URL manually.\n void open(verificationUrl).catch(() => {\n log.dim(\"(Không mở được browser tự động — copy URL ở trên)\");\n });\n\n // Step 5: poll token endpoint until success or expiry.\n const waitSpinner = spinner(\"Đang chờ xác nhận trong browser...\");\n const intervalMs = deviceCode.interval * 1000;\n const deadline = Date.now() + deviceCode.expires_in * 1000;\n\n let token = null;\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n try {\n token = await pollForToken(deviceCode.device_code);\n if (token) break;\n } catch (err) {\n waitSpinner.fail(\"Xác thực thất bại\");\n throw err;\n }\n }\n if (!token) {\n waitSpinner.fail(\"Hết hạn chờ (5 phút). Chạy lại 'avatar login'.\");\n process.exit(1);\n }\n waitSpinner.succeed(\"Đã nhận token từ Google\");\n\n // Step 6: verify hosted domain. Revoke token if claim is wrong.\n const claims = decodeIdToken(token.id_token);\n try {\n verifyHostedDomain(claims);\n } catch (err) {\n await revokeToken(token.access_token);\n throw err;\n }\n\n // Step 7: persist credentials with chmod 600.\n const userConfig = buildUserConfig(token, claims);\n await writeUserConfig(userConfig);\n await appendAuditEntry(\"login\", userConfig.email);\n\n log.success(`Xác thực thành công: ${userConfig.email}`);\n log.success(`Verify hosted domain: ${claims.hd} ✓`);\n log.success(`Lưu credential vào ${USER_CONFIG_PATH} (chmod 600)`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","// Google OAuth 2.0 Device Authorization Grant (RFC 8628) implementation.\n//\n// Why Device Flow: Avatar is a terminal CLI with no browser redirect URL.\n// The user logs in via google.com/device on a browser and the CLI polls\n// Google for the resulting token.\n//\n// Why the client secret is bundled in source: Device Flow does not treat the\n// secret as a security boundary — the human Allow click in the browser is.\n// Google's TV/Limited Input docs explicitly permit this.\n//\n// To rotate: Google Cloud Console → APIs & Services → Credentials → click the\n// OAuth client → Reset Secret. Replace GOOGLE_CLIENT_SECRET below.\n\nimport type { UserConfig } from \"../types/config-schema.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OAuth client config (hardcoded — see file header for rationale).\n// To regenerate: Google Cloud Console → project \"avatar-cli\" → Clients.\n// Application type must be \"TV and Limited Input devices\".\n// ─────────────────────────────────────────────────────────────────────────────\nexport const GOOGLE_CLIENT_ID =\n \"1014766441755-i4jimivh5rd7vt8phuhmepmt45sovtph.apps.googleusercontent.com\";\nexport const GOOGLE_CLIENT_SECRET = \"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\";\n\n// Restrict to the NAL Workspace domain. Enforced at TWO layers:\n// 1. ?hd=nal.vn appended to the verification URL — Google filters the picker\n// 2. Verify id_token.hd === HOSTED_DOMAIN after token exchange (defense-in-depth)\nexport const HOSTED_DOMAIN = \"nal.vn\";\n\nexport const SCOPES = [\"openid\", \"email\", \"profile\"];\n\nconst DEVICE_CODE_URL = \"https://oauth2.googleapis.com/device/code\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\nconst REVOKE_URL = \"https://oauth2.googleapis.com/revoke\";\n\nexport interface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_url: string;\n expires_in: number;\n interval: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n refresh_token: string;\n id_token: string;\n expires_in: number;\n token_type: string;\n scope: string;\n}\n\nexport interface IdTokenClaims {\n email: string;\n email_verified: boolean;\n name?: string;\n hd?: string;\n exp: number;\n iss: string;\n aud: string;\n}\n\n// ── Step 2 of Command 01 spec: request device + user codes.\nexport async function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const body = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n scope: SCOPES.join(\" \"),\n });\n const res = await fetch(DEVICE_CODE_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Device code request failed (${res.status}): ${text}`);\n }\n return (await res.json()) as DeviceCodeResponse;\n}\n\n// ── Step 5: poll the token endpoint until user authorises or expiry.\n// Returns the token response on success, null while still pending.\n// Throws on hard errors (access_denied, expired_token).\nexport async function pollForToken(deviceCode: string): Promise<TokenResponse | null> {\n const body = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n device_code: deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n });\n const res = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n\n if (res.ok) {\n return (await res.json()) as TokenResponse;\n }\n\n // Google returns 4xx with a JSON {error} field for both pending and fatal states.\n let errorCode = \"\";\n try {\n const data = (await res.json()) as { error?: string };\n errorCode = data.error ?? \"\";\n } catch {\n errorCode = \"\";\n }\n\n if (errorCode === \"authorization_pending\" || errorCode === \"slow_down\") {\n return null;\n }\n if (errorCode === \"access_denied\") {\n throw new Error(\"User từ chối quyền truy cập\");\n }\n if (errorCode === \"expired_token\") {\n throw new Error(\"Hết hạn chờ (5 phút). Chạy lại 'avatar login'.\");\n }\n throw new Error(`OAuth token endpoint trả lỗi: ${errorCode || res.status}`);\n}\n\n// Decode JWT payload WITHOUT verifying signature. Safe here because we receive\n// the token directly from Google over HTTPS — no MITM surface.\nexport function decodeIdToken(idToken: string): IdTokenClaims {\n const parts = idToken.split(\".\");\n if (parts.length !== 3) {\n throw new Error(\"id_token format không hợp lệ\");\n }\n const payload = parts[1];\n if (!payload) throw new Error(\"id_token thiếu payload\");\n // Convert base64url to base64.\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = Buffer.from(base64, \"base64\").toString(\"utf8\");\n return JSON.parse(json) as IdTokenClaims;\n}\n\n// ── Step 6: enforce hosted domain. Reject any non-@nal.vn account.\nexport function verifyHostedDomain(claims: IdTokenClaims): void {\n if (claims.hd !== HOSTED_DOMAIN) {\n throw new Error(\n `Email không thuộc workspace NAL (yêu cầu @${HOSTED_DOMAIN}). Nhận: ${claims.email}`,\n );\n }\n if (!claims.email_verified) {\n throw new Error(\"Email chưa được Google verify\");\n }\n}\n\n// Convert OAuth token response + decoded claims into the on-disk UserConfig shape.\nexport function buildUserConfig(token: TokenResponse, claims: IdTokenClaims): UserConfig {\n const expiresAt = new Date(Date.now() + token.expires_in * 1000).toISOString();\n return {\n email: claims.email,\n name: claims.name ?? claims.email,\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n expires_at: expiresAt,\n id_token: token.id_token,\n };\n}\n\n// Refresh flow: exchange refresh_token for a new access_token. Used by other\n// commands when they detect an expired token (see isTokenExpired).\nexport async function refreshAccessToken(refreshToken: string): Promise<{\n access_token: string;\n expires_in: number;\n id_token?: string;\n}> {\n const body = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n refresh_token: refreshToken,\n grant_type: \"refresh_token\",\n });\n const res = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Refresh token failed (${res.status}): ${text}`);\n }\n return (await res.json()) as { access_token: string; expires_in: number; id_token?: string };\n}\n\n// Revoke a token (used when login is rejected post-hoc, e.g. wrong domain).\nexport async function revokeToken(token: string): Promise<void> {\n const body = new URLSearchParams({ token });\n await fetch(REVOKE_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n }).catch(() => {\n // Best-effort revoke — don't fail the caller if revoke itself errors.\n });\n}\n\n// Build the verification URL with hd hint so Google pre-filters the account picker.\nexport function buildVerificationUrl(response: DeviceCodeResponse): string {\n const url = new URL(response.verification_url);\n url.searchParams.set(\"user_code\", response.user_code);\n url.searchParams.set(\"hd\", HOSTED_DOMAIN);\n return url.toString();\n}\n","// `avatar mcp-run <tool-id>` — hidden command from Chapter 13 roadmap.\n// Wrapper used by ~/.claude.json entries: Avatar injects secrets from keychain\n// then spawns the underlying MCP process with stdio piped to Claude Code.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerMcpRunCommand(program: Command): void {\n program\n .command(\"mcp-run <tool-id>\", { hidden: true })\n .description(\"[internal] Spawn MCP với secrets injected (M09)\")\n .action(notImplementedYet(\"mcp-run\", \"Milestone 09\"));\n}\n","// `avatar restore [--backup <name>] [--list]` — Command 08 spec.\n// Restore .claude/pack/ from a previous backup snapshot.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerRestoreCommand(program: Command): void {\n program\n .command(\"restore\")\n .description(\"Khôi phục .claude/pack/ từ backup (M08)\")\n .option(\"--backup <name>\", \"Tên backup folder trong .claude/_backup/\")\n .option(\"--list\", \"Liệt kê các backup hiện có\")\n .action(notImplementedYet(\"restore\", \"Milestone 08\"));\n}\n","// `avatar review [--accept-all|--reject-all]` — Command 05 spec.\n// Interactive review of .claude/_pending/*.diff.md proposals.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerReviewCommand(program: Command): void {\n program\n .command(\"review\")\n .description(\"Review pending proposals từ avatar scan (M08)\")\n .option(\"--accept-all\", \"Approve mọi pending không hỏi (CI mode)\")\n .option(\"--reject-all\", \"Xóa mọi pending không hỏi\")\n .action(notImplementedYet(\"review\", \"Milestone 08\"));\n}\n","// `avatar scan [--incremental|--full] [--scanners <list>]` — Command 04 spec.\n// Runs 5 project scanners and writes proposals to .claude/_pending/.\n// Implementation deferred — scanner files in src/scanners/ are stubbed.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerScanCommand(program: Command): void {\n program\n .command(\"scan\")\n .description(\"Chạy project scanner và đề xuất knowledge update (M06)\")\n .option(\"--incremental\", \"Chỉ scan các file thay đổi từ commit cuối\")\n .option(\"--full\", \"Scan toàn bộ dự án (default)\")\n .option(\"--scanners <list>\", \"tech-stack,conventions,architecture,domain,git-pattern\")\n .option(\"--quiet\", \"Chạy ngầm, ít output (dùng cho git hook)\")\n .action(notImplementedYet(\"scan\", \"Milestone 06\"));\n}\n","// `avatar secrets {list,set,get,rm,check}` — Command 13 spec.\n// Backed by OS keychain via @napi-rs/keyring. Service prefix: \"avatar\".\n// Audit log entries are written for set/rm; values NEVER logged.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerSecretsCommand(program: Command): void {\n const secrets = program.command(\"secrets\").description(\"Quản lý secrets trong OS keychain (M09)\");\n\n secrets\n .command(\"list\")\n .description(\"Liệt kê secrets đã set (chỉ tên, không value)\")\n .action(notImplementedYet(\"secrets list\", \"Milestone 09\"));\n\n secrets\n .command(\"set <service> <name>\")\n .description(\"Set/update secret (prompt ẩn)\")\n .action(notImplementedYet(\"secrets set\", \"Milestone 09\"));\n\n secrets\n .command(\"get <service> <name>\")\n .description(\"Lấy secret, copy clipboard, auto-xóa sau 30s\")\n .action(notImplementedYet(\"secrets get\", \"Milestone 09\"));\n\n secrets\n .command(\"rm <service> <name>\")\n .description(\"Xóa secret khỏi keychain\")\n .action(notImplementedYet(\"secrets rm\", \"Milestone 09\"));\n\n secrets\n .command(\"check\")\n .description(\"Verify mọi secret required bởi MCP đã enabled\")\n .action(notImplementedYet(\"secrets check\", \"Milestone 09\"));\n}\n","// `avatar status [--json]` — Command 06 spec.\n// Read-only snapshot: project name, CLI version, pack version, pending count,\n// backup count, tech-stack first-line. No mutations.\nimport { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { pathExists, readText } from \"../lib/filesystem-helpers.js\";\nimport { isGitRepo } from \"../lib/git-operations.js\";\nimport { listBackups } from \"../lib/pack-backup-manager.js\";\nimport { readPinnedPackVersion } from \"../lib/team-pack-submodule-manager.js\";\nimport { chalk, log } from \"../lib/terminal-logger.js\";\n\nconst AVATAR_CLI_VERSION = \"1.0.1\";\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command(\"status\")\n .description(\"Snapshot tức thì: project, pack version, pending, backup\")\n .option(\"--json\", \"Output JSON cho script\")\n .action(async (opts: { json?: boolean }) => {\n try {\n const snapshot = await gatherStatus(process.cwd());\n if (opts.json) {\n process.stdout.write(`${JSON.stringify(snapshot, null, 2)}\\n`);\n } else {\n renderStatusBox(snapshot);\n }\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\ninterface StatusSnapshot {\n projectName: string;\n cliVersion: string;\n packVersion: string | null;\n pendingCount: number;\n backupCount: number;\n techStackSummary: string;\n hasAvatar: boolean;\n}\n\nasync function gatherStatus(cwd: string): Promise<StatusSnapshot> {\n const projectName = cwd.split(\"/\").filter(Boolean).pop() ?? \"unknown\";\n const claudeRoot = join(cwd, \".claude\");\n const hasAvatar = await pathExists(claudeRoot);\n if (!hasAvatar) {\n return {\n projectName,\n cliVersion: AVATAR_CLI_VERSION,\n packVersion: null,\n pendingCount: 0,\n backupCount: 0,\n techStackSummary: \"(Avatar chưa init)\",\n hasAvatar: false,\n };\n }\n\n const packVersion = (await isGitRepo(join(claudeRoot, \"pack\")))\n ? await readPinnedPackVersion(cwd).catch(() => null)\n : null;\n\n const pendingDir = join(claudeRoot, \"_pending\");\n const pendingCount = (await pathExists(pendingDir))\n ? (await fs.readdir(pendingDir)).filter((n) => n.endsWith(\".diff.md\")).length\n : 0;\n\n const backupCount = (await listBackups(cwd)).length;\n\n const techStackSummary = await readTechStackFirstLine(claudeRoot);\n\n return {\n projectName,\n cliVersion: AVATAR_CLI_VERSION,\n packVersion,\n pendingCount,\n backupCount,\n techStackSummary,\n hasAvatar: true,\n };\n}\n\nasync function readTechStackFirstLine(claudeRoot: string): Promise<string> {\n const techStackPath = join(claudeRoot, \"project\", \"tech-stack.md\");\n if (!(await pathExists(techStackPath))) return \"(no tech-stack.md)\";\n const content = await readText(techStackPath);\n const firstNonHeaderLine = content\n .split(\"\\n\")\n .find((l) => l.trim() && !l.startsWith(\"#\") && !l.startsWith(\">\"));\n return firstNonHeaderLine?.trim() ?? \"(empty)\";\n}\n\nfunction renderStatusBox(s: StatusSnapshot): void {\n const lines = [\n `${chalk.bold(\"Avatar Status\")} · ${chalk.cyan(s.projectName)}`,\n \"─\".repeat(48),\n `${chalk.dim(\"CLI version:\")} ${s.cliVersion}`,\n `${chalk.dim(\"Pack version:\")} ${s.packVersion ?? chalk.yellow(\"not installed\")}`,\n `${chalk.dim(\"Pending changes:\")} ${s.pendingCount}${s.pendingCount > 0 ? chalk.dim(\" (avatar review)\") : \"\"}`,\n `${chalk.dim(\"Backups:\")} ${s.backupCount}`,\n `${chalk.dim(\"Tech stack:\")} ${s.techStackSummary}`,\n ];\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n","import { promises as fs } from \"node:fs\";\n// Backup .claude/pack/ before `avatar sync --force` so user can `avatar restore`\n// if the sync goes wrong. Naming convention: pack-{currentVersion}-{YYYYMMDD-HHmm}.\nimport { join } from \"node:path\";\nimport { copyDirRecursive, ensureDir, pathExists } from \"./filesystem-helpers.js\";\n\nexport const BACKUP_DIR_NAME = \"_backup\";\n\nfunction timestamp(): string {\n const now = new Date();\n const y = now.getFullYear();\n const m = String(now.getMonth() + 1).padStart(2, \"0\");\n const d = String(now.getDate()).padStart(2, \"0\");\n const h = String(now.getHours()).padStart(2, \"0\");\n const min = String(now.getMinutes()).padStart(2, \"0\");\n return `${y}${m}${d}-${h}${min}`;\n}\n\nexport function buildBackupName(currentVersion: string): string {\n // Strip any leading \"v\" so we don't get pack-vv1.2.3 if someone passes \"v1.2.3\".\n const cleanVersion = currentVersion.replace(/^v/, \"\");\n return `pack-v${cleanVersion}-${timestamp()}`;\n}\n\n// Backup .claude/pack/ to .claude/_backup/{name}/, excluding the submodule's\n// own .git directory (we restore content only, not git history).\nexport async function backupPack(projectRoot: string, currentVersion: string): Promise<string> {\n const name = buildBackupName(currentVersion);\n const srcPath = join(projectRoot, \".claude\", \"pack\");\n const dstPath = join(projectRoot, \".claude\", BACKUP_DIR_NAME, name);\n if (!(await pathExists(srcPath))) {\n throw new Error(\"Không tìm thấy .claude/pack/ để backup\");\n }\n await ensureDir(dstPath);\n await copyDirRecursive(srcPath, dstPath, [\".git\"]);\n return name;\n}\n\nexport async function listBackups(projectRoot: string): Promise<string[]> {\n const dir = join(projectRoot, \".claude\", BACKUP_DIR_NAME);\n if (!(await pathExists(dir))) return [];\n const entries = await fs.readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort()\n .reverse();\n}\n","// `avatar sync [--force] [--version <tag>] [--dry-run]` — Command 03 spec.\n// Pulls latest team-ai-pack into .claude/pack. Implementation in next milestone.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerSyncCommand(program: Command): void {\n program\n .command(\"sync\")\n .description(\"Pull team-ai-pack mới nhất (M08)\")\n .option(\"--force\", \"Override .claude/pack/, backup trước\")\n .option(\"--version <tag>\", \"Pin vào version cụ thể\")\n .option(\"--dry-run\", \"Hiển thị changes, không apply\")\n .action(notImplementedYet(\"sync\", \"Milestone 08\"));\n}\n","// `avatar tools {list,install,remove}` — Commands 10/11/12 spec (Chapter 12 v4).\n// Lifecycle management for system dependencies (git, gh, node, uv, docker) and\n// MCP servers (gitnexus, context7, serena, github, filesystem, playwright).\n// Registry source: team-ai-pack/tools/registry.yaml.\nimport type { Command } from \"commander\";\nimport { notImplementedYet } from \"../lib/not-implemented-stub.js\";\n\nexport function registerToolsCommand(program: Command): void {\n const tools = program.command(\"tools\").description(\"Quản lý system tools + MCP servers (M09)\");\n\n tools\n .command(\"list\")\n .description(\"Liệt kê tool đã cài / còn thiếu\")\n .option(\"--installed\", \"Chỉ liệt kê tool đã cài\")\n .option(\"--missing\", \"Chỉ liệt kê tool còn thiếu\")\n .option(\"--json\", \"Output JSON cho script\")\n .action(notImplementedYet(\"tools list\", \"Milestone 09\"));\n\n tools\n .command(\"install [tool-ids...]\")\n .description(\"Cài tool và đăng ký vào ~/.claude.json\")\n .option(\"--all-recommended\", \"Cài mọi MCP được recommend cho project type\")\n .option(\"--verify\", \"Chạy MCP thử để verify (mất ~30s/tool)\")\n .option(\"--no-secrets\", \"Skip prompt secrets, set sau qua 'avatar secrets'\")\n .action(notImplementedYet(\"tools install\", \"Milestone 09\"));\n\n tools\n .command(\"remove <tool-id>\")\n .description(\"Gỡ tool khỏi ~/.claude.json (optional uninstall binary)\")\n .option(\"--keep-secrets\", \"Không xóa secrets khỏi keychain\")\n .option(\"--keep-binary\", \"Không uninstall npm global binary\")\n .action(notImplementedYet(\"tools remove\", \"Milestone 09\"));\n}\n","// `avatar uninstall` — Command 13 (v1.1).\n// Gỡ Avatar khỏi project + auto-backup vào ~/.avatar/uninstall-backups/.\n// Đối ứng với `avatar init`. Code khách (src/) giữ nguyên.\n\nimport { relative } from \"node:path\";\nimport { confirm } from \"@inquirer/prompts\";\nimport boxen from \"boxen\";\nimport type { Command } from \"commander\";\nimport { appendAuditEntry } from \"../lib/audit-log-appender.js\";\nimport { createUninstallBackupSnapshot } from \"../lib/create-uninstall-backup-snapshot.js\";\nimport { detectAvatarProjectArtifacts } from \"../lib/detect-avatar-project-artifacts.js\";\nimport { executeUninstallDeletion } from \"../lib/execute-uninstall-deletion.js\";\nimport { chalk, log } from \"../lib/terminal-logger.js\";\n\nconst CLI_VERSION = \"1.2.0\";\n\ninterface UninstallOptions {\n yes?: boolean;\n noBackup?: boolean;\n keepSubmodule?: boolean;\n keepHooks?: boolean;\n dryRun?: boolean;\n}\n\nexport function registerUninstallCommand(program: Command): void {\n program\n .command(\"uninstall\")\n .description(\"Gỡ Avatar khỏi project — backup tự động (M11)\")\n .option(\"--yes\", \"Skip confirm prompt\")\n .option(\"--no-backup\", \"Không tạo backup trước khi xóa (nguy hiểm)\")\n .option(\"--keep-submodule\", \"Giữ submodule .claude/pack/\")\n .option(\"--keep-hooks\", \"Giữ git hooks post-merge, pre-push\")\n .option(\"--dry-run\", \"Hiển thị danh sách sẽ xóa, không thực thi\")\n .action(async (opts: UninstallOptions) => {\n try {\n await runUninstall(opts);\n } catch (err) {\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n}\n\nasync function runUninstall(opts: UninstallOptions): Promise<void> {\n const projectRoot = process.cwd();\n const artifacts = detectAvatarProjectArtifacts(projectRoot);\n\n if (!artifacts.hasAnyArtifact) {\n log.info(\"Project chưa cài Avatar — không có gì để gỡ.\");\n return;\n }\n\n // Show summary.\n printUninstallSummary(projectRoot, artifacts, opts);\n\n if (opts.dryRun) {\n log.dim(\"--dry-run: kết thúc, không xóa.\");\n return;\n }\n\n // Confirm.\n if (!opts.yes) {\n const ok = await confirm({\n message: \"Tiếp tục gỡ Avatar?\",\n default: false,\n });\n if (!ok) {\n log.info(\"Đã hủy.\");\n return;\n }\n }\n\n // Backup (trừ khi --no-backup).\n let backupPath: string | null = null;\n if (!opts.noBackup) {\n backupPath = await createUninstallBackupSnapshot(projectRoot, artifacts, CLI_VERSION);\n log.success(`Backup tạo tại: ${backupPath}`);\n }\n\n // Delete artifacts.\n await executeUninstallDeletion(artifacts, {\n keepSubmodule: opts.keepSubmodule,\n keepHooks: opts.keepHooks,\n });\n\n await appendAuditEntry(\"uninstall\", `project=${projectRoot},backup=${backupPath ?? \"skipped\"}`);\n\n printUninstallSuccessBox(backupPath);\n}\n\nfunction printUninstallSummary(\n projectRoot: string,\n artifacts: ReturnType<typeof detectAvatarProjectArtifacts>,\n opts: UninstallOptions,\n): void {\n log.info(`Project: ${projectRoot}`);\n log.plain(\"\");\n log.plain(\"Các artifact sẽ gỡ:\");\n if (artifacts.claudeDir)\n log.plain(` ${chalk.red(\"✗\")} ${relative(projectRoot, artifacts.claudeDir) || \".claude/\"}`);\n if (artifacts.claudeMd) log.plain(` ${chalk.red(\"✗\")} CLAUDE.md`);\n if (artifacts.postMergeHook && !opts.keepHooks) {\n log.plain(` ${chalk.red(\"✗\")} .git/hooks/post-merge`);\n }\n if (artifacts.prePushHook && !opts.keepHooks) {\n log.plain(` ${chalk.red(\"✗\")} .git/modules/src/hooks/pre-push`);\n }\n if (artifacts.gitignorePath) log.plain(` ${chalk.yellow(\"✎\")} .gitignore (gỡ Avatar block)`);\n if (artifacts.gitmodulesPath && !opts.keepSubmodule) {\n log.plain(` ${chalk.yellow(\"✎\")} .gitmodules (gỡ entry .claude/pack)`);\n }\n log.plain(\"\");\n log.plain(\"Không đụng:\");\n log.plain(` ${chalk.green(\"✓\")} src/ (code khách)`);\n log.plain(` ${chalk.green(\"✓\")} Git history`);\n log.plain(` ${chalk.green(\"✓\")} ~/.avatar/config.json (token SSO)`);\n log.plain(` ${chalk.green(\"✓\")} Secrets trong keychain`);\n log.plain(\"\");\n}\n\nfunction printUninstallSuccessBox(backupPath: string | null): void {\n const lines: string[] = [`${chalk.green(\"✓\")} Avatar đã được gỡ khỏi project`];\n if (backupPath) {\n lines.push(\"\");\n lines.push(` ${chalk.dim(\"Backup:\")} ${backupPath}`);\n lines.push(` ${chalk.dim(\"Restore:\")} ${chalk.cyan(`cp -r \"${backupPath}\"/* .`)}`);\n }\n process.stdout.write(`${boxen(lines.join(\"\\n\"), { padding: 1, borderStyle: \"round\" })}\\n`);\n}\n","// Tạo snapshot backup trước khi uninstall. Folder: ~/.avatar/uninstall-backups/\n// <project-name>-<ts>/ với cấu trúc trong spec doc.\nimport { cp, mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { AvatarProjectArtifacts } from \"./detect-avatar-project-artifacts.js\";\n\nexport interface BackupManifest {\n projectName: string;\n projectPath: string;\n timestamp: string;\n avatarVersion: string;\n artifacts: {\n claudeDir: boolean;\n claudeMd: boolean;\n postMergeHook: boolean;\n prePushHook: boolean;\n };\n}\n\nconst UNINSTALL_BACKUPS_DIR = join(homedir(), \".avatar\", \"uninstall-backups\");\n\nexport async function createUninstallBackupSnapshot(\n projectRoot: string,\n artifacts: AvatarProjectArtifacts,\n avatarVersion: string,\n): Promise<string> {\n const projectName = basename(projectRoot);\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backupDir = join(UNINSTALL_BACKUPS_DIR, `${projectName}-${timestamp}`);\n\n await mkdir(backupDir, { recursive: true, mode: 0o700 });\n\n // Copy .claude/ và CLAUDE.md nếu tồn tại.\n if (artifacts.claudeDir) {\n await cp(artifacts.claudeDir, join(backupDir, \".claude\"), { recursive: true });\n }\n if (artifacts.claudeMd) {\n await cp(artifacts.claudeMd, join(backupDir, \"CLAUDE.md\"));\n }\n\n // Copy hooks sang backup/hooks/.\n if (artifacts.postMergeHook || artifacts.prePushHook) {\n const hooksBackupDir = join(backupDir, \"hooks\");\n await mkdir(hooksBackupDir, { recursive: true });\n if (artifacts.postMergeHook) {\n await cp(artifacts.postMergeHook, join(hooksBackupDir, \"post-merge\"));\n }\n if (artifacts.prePushHook) {\n await cp(artifacts.prePushHook, join(hooksBackupDir, \"pre-push\"));\n }\n }\n\n // Write manifest.\n const manifest: BackupManifest = {\n projectName,\n projectPath: projectRoot,\n timestamp,\n avatarVersion,\n artifacts: {\n claudeDir: !!artifacts.claudeDir,\n claudeMd: !!artifacts.claudeMd,\n postMergeHook: !!artifacts.postMergeHook,\n prePushHook: !!artifacts.prePushHook,\n },\n };\n await writeFile(join(backupDir, \"manifest.json\"), JSON.stringify(manifest, null, 2), \"utf8\");\n\n return backupDir;\n}\n","// Scan project root để liệt kê các file/folder Avatar đã tạo. Output là blueprint\n// cho uninstall: cái gì sẽ xóa + cái gì sẽ edit (gitignore, gitmodules).\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface AvatarProjectArtifacts {\n hasAnyArtifact: boolean;\n claudeDir: string | null; // .claude/\n claudeMd: string | null; // CLAUDE.md\n postMergeHook: string | null; // .git/hooks/post-merge\n prePushHook: string | null; // .git/modules/src/hooks/pre-push\n gitignorePath: string | null; // .gitignore (nếu có Avatar block)\n gitmodulesPath: string | null; // .gitmodules (nếu có submodule .claude/pack)\n notesDir: string | null; // notes/ (workspace mode)\n scriptsDir: string | null; // scripts/ (workspace mode)\n}\n\nfunction existsOrNull(path: string): string | null {\n return existsSync(path) ? path : null;\n}\n\nexport function detectAvatarProjectArtifacts(projectRoot: string): AvatarProjectArtifacts {\n const claudeDir = existsOrNull(join(projectRoot, \".claude\"));\n const claudeMd = existsOrNull(join(projectRoot, \"CLAUDE.md\"));\n const postMergeHook = existsOrNull(join(projectRoot, \".git\", \"hooks\", \"post-merge\"));\n const prePushHook = existsOrNull(\n join(projectRoot, \".git\", \"modules\", \"src\", \"hooks\", \"pre-push\"),\n );\n const gitignorePath = existsOrNull(join(projectRoot, \".gitignore\"));\n const gitmodulesPath = existsOrNull(join(projectRoot, \".gitmodules\"));\n const notesDir = existsOrNull(join(projectRoot, \"notes\"));\n const scriptsDir = existsOrNull(join(projectRoot, \"scripts\"));\n\n const hasAnyArtifact = !!(claudeDir || claudeMd || postMergeHook || prePushHook);\n\n return {\n hasAnyArtifact,\n claudeDir,\n claudeMd,\n postMergeHook,\n prePushHook,\n gitignorePath,\n gitmodulesPath,\n notesDir,\n scriptsDir,\n };\n}\n","// Atomic delete các artifact Avatar khỏi project. Gỡ marker block trong\n// .gitignore, remove submodule entry trong .gitmodules. Không đụng src/ + git\n// history + user config.\nimport { readFile, rm, writeFile } from \"node:fs/promises\";\nimport type { AvatarProjectArtifacts } from \"./detect-avatar-project-artifacts.js\";\nimport { AVATAR_MARKER_END, AVATAR_MARKER_START } from \"./gitignore-template-loader.js\";\n\nexport interface UninstallFlags {\n keepSubmodule?: boolean;\n keepHooks?: boolean;\n}\n\nexport async function executeUninstallDeletion(\n artifacts: AvatarProjectArtifacts,\n flags: UninstallFlags,\n): Promise<void> {\n // Delete .claude/ (trừ khi --keep-submodule muốn giữ pack/ — thực tế cả\n // .claude/ chứa nhiều thứ khác, nên --keep-submodule chỉ giữ pack/).\n if (artifacts.claudeDir) {\n if (flags.keepSubmodule) {\n // Chỉ xóa các file/folder không phải pack/ trong .claude/.\n const { readdir } = await import(\"node:fs/promises\");\n const { join } = await import(\"node:path\");\n const entries = await readdir(artifacts.claudeDir);\n for (const entry of entries) {\n if (entry === \"pack\") continue;\n await rm(join(artifacts.claudeDir, entry), { recursive: true, force: true });\n }\n } else {\n await rm(artifacts.claudeDir, { recursive: true, force: true });\n }\n }\n\n if (artifacts.claudeMd) {\n await rm(artifacts.claudeMd, { force: true });\n }\n\n if (!flags.keepHooks) {\n if (artifacts.postMergeHook) await rm(artifacts.postMergeHook, { force: true });\n if (artifacts.prePushHook) await rm(artifacts.prePushHook, { force: true });\n }\n\n // Strip Avatar block khỏi .gitignore (giữ rest).\n if (artifacts.gitignorePath) {\n await stripAvatarBlockFromGitignore(artifacts.gitignorePath);\n }\n\n // Remove submodule entry .claude/pack khỏi .gitmodules (nếu xóa cả pack).\n if (artifacts.gitmodulesPath && !flags.keepSubmodule) {\n await removeSubmoduleEntry(artifacts.gitmodulesPath, \".claude/pack\");\n }\n\n // Workspace mode có notes/, scripts/. Chỉ xóa nếu rỗng (user có thể đã add file).\n for (const dir of [artifacts.notesDir, artifacts.scriptsDir]) {\n if (!dir) continue;\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(dir);\n if (entries.length === 0) {\n await rm(dir, { recursive: true, force: true });\n }\n }\n}\n\nasync function stripAvatarBlockFromGitignore(path: string): Promise<void> {\n const content = await readFile(path, \"utf8\");\n const startIdx = content.indexOf(AVATAR_MARKER_START);\n const endIdx = content.indexOf(AVATAR_MARKER_END);\n if (startIdx === -1 || endIdx === -1) return;\n\n const before = content.slice(0, startIdx);\n const after = content.slice(endIdx + AVATAR_MARKER_END.length);\n const cleaned = `${before.trimEnd()}\\n${after.trimStart()}`.trim();\n if (cleaned.length === 0) {\n await rm(path, { force: true });\n } else {\n await writeFile(path, `${cleaned}\\n`, \"utf8\");\n }\n}\n\nasync function removeSubmoduleEntry(gitmodulesPath: string, submodulePath: string): Promise<void> {\n const content = await readFile(gitmodulesPath, \"utf8\");\n const lines = content.split(\"\\n\");\n const result: string[] = [];\n let skip = false;\n for (const line of lines) {\n if (line.trim().startsWith(\"[submodule\") && line.includes(submodulePath)) {\n skip = true;\n continue;\n }\n if (skip && line.trim().startsWith(\"[submodule\")) {\n skip = false;\n }\n if (!skip) result.push(line);\n }\n const cleaned = result.join(\"\\n\").trim();\n if (cleaned.length === 0) {\n await rm(gitmodulesPath, { force: true });\n } else {\n await writeFile(gitmodulesPath, `${cleaned}\\n`, \"utf8\");\n }\n}\n"],"mappings":"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","names":["spawnSync","fs","join","fs","join","join","fs","fs","spawnSync","spawnSync","spawnSync","spawnSync","homedir","join","select","select","fs","join","SECRET_FILE_MODE","join","input","fs","join","spawnSync","fs","program","program","spawnSync","fs","join","join","join","join","fs","join","dirname","join","dirname","join","fs","join","relative","program","join","fs","spawnSync","join","relative","confirm","input","select","boxen","chalk","spawnSync","input","spawnSync","input","spawnSync","spawnSync","spawnSync","platform","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","input","spawnSync","select","simpleGit","existsSync","join","simpleGit","existsSync","join","readFileSync","dirname","join","fileURLToPath","existsSync","readFileSync","join","join","existsSync","readFileSync","simpleGit","select","join","join","join","join","program","select","input","join","confirm","relative","boxen","boxen","program","boxen","resolve","program","program","program","program","program","fs","join","boxen","fs","join","join","fs","AVATAR_CLI_VERSION","program","join","fs","boxen","program","program","relative","confirm","boxen","homedir","basename","join","existsSync","join","writeFile","readdir","join","writeFile","program","confirm","relative","boxen","CLI_VERSION"]}