@nalvietnam/avatar-cli 1.1.4 → 1.1.6
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
CHANGED
|
@@ -641,6 +641,9 @@ function createGithubRemoteFromFolder(input2) {
|
|
|
641
641
|
return urls;
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
// src/lib/create-workspace-remote-via-gh.ts
|
|
645
|
+
import { spawnSync as spawnSync10 } from "child_process";
|
|
646
|
+
|
|
644
647
|
// src/lib/check-gh-cli-auth-status.ts
|
|
645
648
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
646
649
|
function checkGhCliAuthStatus() {
|
|
@@ -776,6 +779,40 @@ async function ensureGitHubReady(remoteUrl) {
|
|
|
776
779
|
}
|
|
777
780
|
}
|
|
778
781
|
|
|
782
|
+
// src/lib/create-workspace-remote-via-gh.ts
|
|
783
|
+
async function createWorkspaceRemoteViaGh(input2) {
|
|
784
|
+
validateRepoName(input2.workspaceName);
|
|
785
|
+
validateRepoVisibility(input2.visibility);
|
|
786
|
+
await ensureGitHubReady();
|
|
787
|
+
const org = input2.org ?? resolveGithubUsernameDefault();
|
|
788
|
+
const fullName = `${org}/${input2.workspaceName}`;
|
|
789
|
+
log.info(`T\u1EA1o GitHub repo cho workspace: ${fullName} (${input2.visibility})...`);
|
|
790
|
+
const r = spawnSync10(
|
|
791
|
+
"gh",
|
|
792
|
+
[
|
|
793
|
+
"repo",
|
|
794
|
+
"create",
|
|
795
|
+
fullName,
|
|
796
|
+
`--${input2.visibility}`,
|
|
797
|
+
"--source",
|
|
798
|
+
input2.workspacePath,
|
|
799
|
+
"--remote",
|
|
800
|
+
"origin",
|
|
801
|
+
"--push"
|
|
802
|
+
],
|
|
803
|
+
{ stdio: "inherit" }
|
|
804
|
+
);
|
|
805
|
+
if (r.status !== 0) {
|
|
806
|
+
throw new Error(
|
|
807
|
+
`T\u1EA1o workspace remote th\u1EA5t b\u1EA1i (exit ${r.status}). Workspace v\u1EABn d\xF9ng \u0111\u01B0\u1EE3c local. Setup remote sau qua: gh repo create ${fullName} --${input2.visibility} --source=. --remote=origin --push`
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
const sshUrl = `git@github.com:${fullName}.git`;
|
|
811
|
+
const httpsUrl = `https://github.com/${fullName}.git`;
|
|
812
|
+
log.success(`Workspace remote: ${sshUrl}`);
|
|
813
|
+
return { sshUrl, httpsUrl };
|
|
814
|
+
}
|
|
815
|
+
|
|
779
816
|
// src/lib/check-folder-has-git.ts
|
|
780
817
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
781
818
|
import { join as join7 } from "path";
|
|
@@ -931,7 +968,7 @@ async function addTeamPackSubmodule(projectRoot, tag) {
|
|
|
931
968
|
C\xE1ch fix:
|
|
932
969
|
1. T\u1EA1o repo: gh repo create <owner>/team-ai-pack --private --add-readme
|
|
933
970
|
2. Ho\u1EB7c override URL: export AVATAR_TEAM_PACK_REPO_URL=<url-repo-c\u1EE7a-b\u1EA1n>
|
|
934
|
-
3. Ho\u1EB7c d\xF9ng flag --skip-team-pack
|
|
971
|
+
3. Ho\u1EB7c d\xF9ng flag --skip-team-pack`
|
|
935
972
|
);
|
|
936
973
|
}
|
|
937
974
|
throw err;
|
|
@@ -995,7 +1032,7 @@ function buildScaffoldVariables(args) {
|
|
|
995
1032
|
|
|
996
1033
|
// src/commands/init.ts
|
|
997
1034
|
function registerInitCommand(program2) {
|
|
998
|
-
program2.command("init").description("Kh\u1EDFi t\u1EA1o Avatar \u2014 3 flow t\u1EF1 nh\u1EADn di\u1EC7n (repo / folder / new)").option("--project-status <val>", "existing-remote | existing-folder | new-project").option("--folder-path <path>", "\u0110\u01B0\u1EDDng d\u1EABn folder hi\u1EC7n c\xF3 (flow existing-folder)").option("--create-remote", "Force t\u1EA1o remote qua gh (flow existing-folder ho\u1EB7c new-project)").option("--repo-visibility <val>", "private (m\u1EB7c \u0111\u1ECBnh) | public").option("--repo-org <name>", "GitHub org/owner cho repo m\u1EDBi").option("--client-repo <url>", "URL git remote (flow existing-remote)").option("--workspace-name <name>", "T\xEAn workspace").option("--workspace-parent <path>", "Th\u01B0 m\u1EE5c cha t\u1EA1o workspace (m\u1EB7c \u0111\u1ECBnh . \u2014 CWD)").option("--pack-version <tag>", "Pin team-ai-pack v\xE0o tag c\u1EE5 th\u1EC3").option("--team-owner <email>", "Email team owner (b\u1ECF qua prompt)").option("--description <text>", "M\xF4 t\u1EA3 1 d\xF2ng c\u1EE7a d\u1EF1 \xE1n").option("--skip-scan", "B\u1ECF qua project-scanner sau scaffold").option("--skip-team-pack", "B\u1ECF qua submodule team-ai-pack (test mode)").option("--force", "B\u1ECF qua prompt khi workspace path \u0111\xE3 t\u1ED3n t\u1EA1i").option("--yes", "Auto-confirm t\u1EA5t c\u1EA3 prompt").option("--mode <mode>", "[DEPRECATED] D\xF9ng --project-status thay th\u1EBF").action(async (opts) => {
|
|
1035
|
+
program2.command("init").description("Kh\u1EDFi t\u1EA1o Avatar \u2014 3 flow t\u1EF1 nh\u1EADn di\u1EC7n (repo / folder / new)").option("--project-status <val>", "existing-remote | existing-folder | new-project").option("--folder-path <path>", "\u0110\u01B0\u1EDDng d\u1EABn folder hi\u1EC7n c\xF3 (flow existing-folder)").option("--create-remote", "Force t\u1EA1o remote qua gh (flow existing-folder ho\u1EB7c new-project)").option("--repo-visibility <val>", "private (m\u1EB7c \u0111\u1ECBnh) | public").option("--repo-org <name>", "GitHub org/owner cho repo m\u1EDBi").option("--client-repo <url>", "URL git remote (flow existing-remote)").option("--workspace-name <name>", "T\xEAn workspace").option("--workspace-parent <path>", "Th\u01B0 m\u1EE5c cha t\u1EA1o workspace (m\u1EB7c \u0111\u1ECBnh . \u2014 CWD)").option("--pack-version <tag>", "Pin team-ai-pack v\xE0o tag c\u1EE5 th\u1EC3").option("--team-owner <email>", "Email team owner (b\u1ECF qua prompt)").option("--description <text>", "M\xF4 t\u1EA3 1 d\xF2ng c\u1EE7a d\u1EF1 \xE1n").option("--skip-scan", "B\u1ECF qua project-scanner sau scaffold").option("--skip-team-pack", "B\u1ECF qua submodule team-ai-pack (test mode)").option("--force", "B\u1ECF qua prompt khi workspace path \u0111\xE3 t\u1ED3n t\u1EA1i").option("--yes", "Auto-confirm t\u1EA5t c\u1EA3 prompt").option("--no-commit", "Skip commit workspace initial state (m\u1EB7c \u0111\u1ECBnh LU\xD4N commit)").option("--workspace-remote", "T\u1EA1o GitHub remote cho workspace root (default: prompt)").option("--mode <mode>", "[DEPRECATED] D\xF9ng --project-status thay th\u1EBF").action(async (opts) => {
|
|
999
1036
|
try {
|
|
1000
1037
|
await runInit(opts);
|
|
1001
1038
|
} catch (err) {
|
|
@@ -1057,6 +1094,10 @@ async function runInitFromExistingRemote(opts, ownerEmail) {
|
|
|
1057
1094
|
description: opts.description ?? `Avatar workspace cho ${remoteUrl}`,
|
|
1058
1095
|
packVersion: opts.packVersion,
|
|
1059
1096
|
autoYes: opts.yes,
|
|
1097
|
+
skipCommit: opts.commit === false,
|
|
1098
|
+
createWorkspaceRemote: opts.workspaceRemote,
|
|
1099
|
+
repoVisibility: opts.repoVisibility,
|
|
1100
|
+
repoOrg: opts.repoOrg,
|
|
1060
1101
|
flow: "existing-remote"
|
|
1061
1102
|
});
|
|
1062
1103
|
}
|
|
@@ -1084,6 +1125,10 @@ async function runInitFromExistingFolder(opts, ownerEmail) {
|
|
|
1084
1125
|
description: opts.description ?? `Avatar workspace cho folder ${folderPath}`,
|
|
1085
1126
|
packVersion: opts.packVersion,
|
|
1086
1127
|
autoYes: opts.yes,
|
|
1128
|
+
skipCommit: opts.commit === false,
|
|
1129
|
+
createWorkspaceRemote: opts.workspaceRemote,
|
|
1130
|
+
repoVisibility: opts.repoVisibility,
|
|
1131
|
+
repoOrg: opts.repoOrg,
|
|
1087
1132
|
flow: "existing-folder"
|
|
1088
1133
|
});
|
|
1089
1134
|
}
|
|
@@ -1134,6 +1179,10 @@ async function runInitFromScratch(opts, ownerEmail) {
|
|
|
1134
1179
|
description: opts.description ?? `D\u1EF1 \xE1n m\u1EDBi: ${projectName}`,
|
|
1135
1180
|
packVersion: pinnedTag,
|
|
1136
1181
|
autoYes: opts.yes,
|
|
1182
|
+
skipCommit: opts.commit === false,
|
|
1183
|
+
createWorkspaceRemote: opts.workspaceRemote,
|
|
1184
|
+
repoVisibility: opts.repoVisibility,
|
|
1185
|
+
repoOrg: opts.repoOrg,
|
|
1137
1186
|
flow: "new-project"
|
|
1138
1187
|
});
|
|
1139
1188
|
} catch (err) {
|
|
@@ -1199,6 +1248,10 @@ async function scaffoldWorkspaceWithSrcSubmodule(args) {
|
|
|
1199
1248
|
description: args.description,
|
|
1200
1249
|
packVersion: pinnedTag,
|
|
1201
1250
|
autoYes: args.autoYes,
|
|
1251
|
+
skipCommit: args.skipCommit,
|
|
1252
|
+
createWorkspaceRemote: args.createWorkspaceRemote,
|
|
1253
|
+
repoVisibility: args.repoVisibility,
|
|
1254
|
+
repoOrg: args.repoOrg,
|
|
1202
1255
|
flow: args.flow
|
|
1203
1256
|
});
|
|
1204
1257
|
} catch (err) {
|
|
@@ -1225,9 +1278,43 @@ async function finalizeWorkspaceScaffold(args) {
|
|
|
1225
1278
|
await installGitHook(join13(args.workspacePath, ".git", "modules", "src"), "pre-push");
|
|
1226
1279
|
log.success("C\xE0i post-merge (workspace) + pre-push (src/)");
|
|
1227
1280
|
await appendAuditEntry("init", `flow=${args.flow},workspace=${args.workspaceName}`);
|
|
1228
|
-
await maybeCommitWorkspace(args.workspacePath, args.
|
|
1281
|
+
await maybeCommitWorkspace(args.workspacePath, args.skipCommit);
|
|
1282
|
+
await maybeCreateWorkspaceRemote(args);
|
|
1229
1283
|
printInitSuccessBox(args.workspacePath, args.flow);
|
|
1230
1284
|
}
|
|
1285
|
+
async function maybeCreateWorkspaceRemote(args) {
|
|
1286
|
+
if (args.skipCommit) {
|
|
1287
|
+
log.dim("Skip workspace remote (ch\u01B0a commit). Setup sau qua: gh repo create ...");
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
let shouldCreate = args.createWorkspaceRemote;
|
|
1291
|
+
if (shouldCreate === void 0) {
|
|
1292
|
+
if (args.autoYes) return;
|
|
1293
|
+
shouldCreate = await confirm({
|
|
1294
|
+
message: "T\u1EA1o remote GitHub cho workspace \u0111\u1EC3 share team? (Avatar state)",
|
|
1295
|
+
default: false
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
if (!shouldCreate) return;
|
|
1299
|
+
const visibility = args.repoVisibility ?? (args.autoYes ? "private" : await select({
|
|
1300
|
+
message: "Workspace visibility?",
|
|
1301
|
+
choices: [
|
|
1302
|
+
{ name: "private (m\u1EB7c \u0111\u1ECBnh, an to\xE0n)", value: "private" },
|
|
1303
|
+
{ name: "public", value: "public" }
|
|
1304
|
+
]
|
|
1305
|
+
}));
|
|
1306
|
+
try {
|
|
1307
|
+
await createWorkspaceRemoteViaGh({
|
|
1308
|
+
workspacePath: args.workspacePath,
|
|
1309
|
+
workspaceName: args.workspaceName,
|
|
1310
|
+
visibility,
|
|
1311
|
+
org: args.repoOrg
|
|
1312
|
+
});
|
|
1313
|
+
} catch (err) {
|
|
1314
|
+
log.warn(err instanceof Error ? err.message : String(err));
|
|
1315
|
+
log.warn("Workspace v\u1EABn s\u1EB5n s\xE0ng local-only. Setup remote sau khi c\u1EA7n.");
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1231
1318
|
async function resolveWorkspacePath(parent, desiredName, force) {
|
|
1232
1319
|
const desired = join13(parent, desiredName);
|
|
1233
1320
|
if (await isEmptyOrMissing(desired)) return desired;
|
|
@@ -1247,9 +1334,11 @@ async function resolveWorkspacePath(parent, desiredName, force) {
|
|
|
1247
1334
|
async function promptTeamOwner(currentUserEmail) {
|
|
1248
1335
|
return await input({ message: "Team owner email:", default: currentUserEmail });
|
|
1249
1336
|
}
|
|
1250
|
-
async function maybeCommitWorkspace(workspacePath,
|
|
1251
|
-
|
|
1252
|
-
|
|
1337
|
+
async function maybeCommitWorkspace(workspacePath, skipCommit) {
|
|
1338
|
+
if (skipCommit) {
|
|
1339
|
+
log.warn("Skip commit (--no-commit). Ch\u1EA1y 'git status' + commit th\u1EE7 c\xF4ng sau.");
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1253
1342
|
const g = git(workspacePath);
|
|
1254
1343
|
await g.add(["CLAUDE.md", ".claude/", ".gitignore", ".gitmodules", "notes/", "scripts/"]);
|
|
1255
1344
|
await g.commit("chore: initialize Avatar workspace");
|
|
@@ -1747,7 +1836,7 @@ async function removeSubmoduleEntry(gitmodulesPath, submodulePath) {
|
|
|
1747
1836
|
}
|
|
1748
1837
|
|
|
1749
1838
|
// src/commands/uninstall.ts
|
|
1750
|
-
var CLI_VERSION = "1.1.
|
|
1839
|
+
var CLI_VERSION = "1.1.6";
|
|
1751
1840
|
function registerUninstallCommand(program2) {
|
|
1752
1841
|
program2.command("uninstall").description("G\u1EE1 Avatar kh\u1ECFi project \u2014 backup t\u1EF1 \u0111\u1ED9ng (M11)").option("--yes", "Skip confirm prompt").option("--no-backup", "Kh\xF4ng t\u1EA1o backup tr\u01B0\u1EDBc khi x\xF3a (nguy hi\u1EC3m)").option("--keep-submodule", "Gi\u1EEF submodule .claude/pack/").option("--keep-hooks", "Gi\u1EEF git hooks post-merge, pre-push").option("--dry-run", "Hi\u1EC3n th\u1ECB danh s\xE1ch s\u1EBD x\xF3a, kh\xF4ng th\u1EF1c thi").action(async (opts) => {
|
|
1753
1842
|
try {
|
|
@@ -1829,7 +1918,7 @@ function printUninstallSuccessBox(backupPath) {
|
|
|
1829
1918
|
}
|
|
1830
1919
|
|
|
1831
1920
|
// src/index.ts
|
|
1832
|
-
var CLI_VERSION2 = "1.1.
|
|
1921
|
+
var CLI_VERSION2 = "1.1.6";
|
|
1833
1922
|
var program = new Command();
|
|
1834
1923
|
program.name("avatar").description("AI harness CLI for NAL Vietnam engineering").version(CLI_VERSION2, "-v, --version", "Hi\u1EC3n th\u1ECB phi\xEAn b\u1EA3n Avatar CLI").addHelpText(
|
|
1835
1924
|
"beforeAll",
|
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/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.4\";\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 { 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 // 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(\"--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 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 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 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 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 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 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.autoYes);\n printInitSuccessBox(args.workspacePath, args.flow);\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, autoYes?: boolean): Promise<void> {\n const wantCommit =\n autoYes ?? (await confirm({ message: \"Commit workspace ngay?\", default: true }));\n if (!wantCommit) return;\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","// 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` +\n \" Cách fix:\\n\" +\n \" 1. Tạo repo: gh repo create <owner>/team-ai-pack --private --add-readme\\n\" +\n \" 2. Hoặc override URL: export AVATAR_TEAM_PACK_REPO_URL=<url-repo-của-bạn>\\n\" +\n \" 3. Hoặc dùng flag --skip-team-pack (sẽ implement trong v1.2)\",\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.4\";\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","platform","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","spawnSync","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/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"]}
|
|
@@ -84,7 +84,7 @@ var COMMANDS = [
|
|
|
84
84
|
{ name: "uninstall", desc: "G\u1EE1 Avatar kh\u1ECFi project + backup" },
|
|
85
85
|
{ name: "help", desc: "Hi\u1EC3n th\u1ECB help cho t\u1EEBng l\u1EC7nh" }
|
|
86
86
|
];
|
|
87
|
-
var CLI_VERSION = "1.1.
|
|
87
|
+
var CLI_VERSION = "1.1.6";
|
|
88
88
|
function printWelcomeScreen() {
|
|
89
89
|
printAvatarBanner({ tagline: `v${CLI_VERSION} \xB7 AI harness CLI for NAL Vietnam` });
|
|
90
90
|
const maxNameWidth = Math.max(...COMMANDS.map((c) => c.name.length));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/print-welcome-screen.ts","../../src/lib/avatar-ascii-banner.ts","../../src/lib/terminal-logger.ts"],"sourcesContent":["// Welcome screen in ra sau `npm install -g` (qua postinstall hook) hoặc khi\n// user gọi `avatar welcome` thủ công. Mục đích: cho user thấy banner + 13\n// commands + next step gợi ý ngay sau khi cài.\nimport boxen from \"boxen\";\nimport { printAvatarBanner } from \"./avatar-ascii-banner.js\";\nimport { chalk } from \"./terminal-logger.js\";\n\ninterface CommandSummary {\n name: string;\n desc: string;\n}\n\n// Danh sách 13 commands user-facing (mcp-run là hidden, bỏ qua).\nconst COMMANDS: CommandSummary[] = [\n { name: \"login\", desc: \"Đăng nhập Google SSO (@nal.vn)\" },\n { name: \"init\", desc: \"Khởi tạo Avatar — 3 flow tự nhận diện\" },\n { name: \"sync\", desc: \"Pull team-ai-pack mới nhất\" },\n { name: \"scan\", desc: \"Project scanner + knowledge proposal\" },\n { name: \"review\", desc: \"Duyệt pending proposals\" },\n { name: \"status\", desc: \"Snapshot project, pack, pending, backup\" },\n { name: \"doctor\", desc: \"Chẩn đoán cài đặt Avatar\" },\n { name: \"restore\", desc: \"Khôi phục .claude/pack/ từ backup\" },\n { name: \"commit\", desc: \"Commit src/ hoặc Avatar state (client mode)\" },\n { name: \"tools\", desc: \"Quản lý system tools + MCP servers\" },\n { name: \"secrets\", desc: \"Quản lý secrets trong OS keychain\" },\n { name: \"uninstall\", desc: \"Gỡ Avatar khỏi project + backup\" },\n { name: \"help\", desc: \"Hiển thị help cho từng lệnh\" },\n];\n\nconst CLI_VERSION = \"1.1.
|
|
1
|
+
{"version":3,"sources":["../../src/lib/print-welcome-screen.ts","../../src/lib/avatar-ascii-banner.ts","../../src/lib/terminal-logger.ts"],"sourcesContent":["// Welcome screen in ra sau `npm install -g` (qua postinstall hook) hoặc khi\n// user gọi `avatar welcome` thủ công. Mục đích: cho user thấy banner + 13\n// commands + next step gợi ý ngay sau khi cài.\nimport boxen from \"boxen\";\nimport { printAvatarBanner } from \"./avatar-ascii-banner.js\";\nimport { chalk } from \"./terminal-logger.js\";\n\ninterface CommandSummary {\n name: string;\n desc: string;\n}\n\n// Danh sách 13 commands user-facing (mcp-run là hidden, bỏ qua).\nconst COMMANDS: CommandSummary[] = [\n { name: \"login\", desc: \"Đăng nhập Google SSO (@nal.vn)\" },\n { name: \"init\", desc: \"Khởi tạo Avatar — 3 flow tự nhận diện\" },\n { name: \"sync\", desc: \"Pull team-ai-pack mới nhất\" },\n { name: \"scan\", desc: \"Project scanner + knowledge proposal\" },\n { name: \"review\", desc: \"Duyệt pending proposals\" },\n { name: \"status\", desc: \"Snapshot project, pack, pending, backup\" },\n { name: \"doctor\", desc: \"Chẩn đoán cài đặt Avatar\" },\n { name: \"restore\", desc: \"Khôi phục .claude/pack/ từ backup\" },\n { name: \"commit\", desc: \"Commit src/ hoặc Avatar state (client mode)\" },\n { name: \"tools\", desc: \"Quản lý system tools + MCP servers\" },\n { name: \"secrets\", desc: \"Quản lý secrets trong OS keychain\" },\n { name: \"uninstall\", desc: \"Gỡ Avatar khỏi project + backup\" },\n { name: \"help\", desc: \"Hiển thị help cho từng lệnh\" },\n];\n\nconst CLI_VERSION = \"1.1.6\";\n\nexport function printWelcomeScreen(): void {\n printAvatarBanner({ tagline: `v${CLI_VERSION} · AI harness CLI for NAL Vietnam` });\n\n // Tính độ rộng max của tên command để align cột.\n const maxNameWidth = Math.max(...COMMANDS.map((c) => c.name.length));\n\n const commandLines = COMMANDS.map((c) => {\n const padded = c.name.padEnd(maxNameWidth);\n return ` ${chalk.cyan(padded)} ${chalk.dim(c.desc)}`;\n }).join(\"\\n\");\n\n const nextSteps = [\n \"\",\n chalk.bold(\"13 lệnh sẵn sàng:\"),\n \"\",\n commandLines,\n \"\",\n chalk.bold(\"Next steps:\"),\n \"\",\n ` ${chalk.green(\"1.\")} ${chalk.cyan(\"avatar login\")} Đăng nhập SSO`,\n ` ${chalk.green(\"2.\")} ${chalk.cyan(\"avatar init\")} Khởi tạo dự án`,\n ` ${chalk.green(\"?.\")} ${chalk.cyan(\"avatar <command> --help\")} Xem chi tiết lệnh`,\n \"\",\n chalk.dim(\"Docs: https://www.npmjs.com/package/@nalvietnam/avatar-cli\"),\n ].join(\"\\n\");\n\n process.stdout.write(\n `${boxen(nextSteps, { padding: 1, borderStyle: \"round\", borderColor: \"magenta\" })}\\n`,\n );\n}\n\n// Caller (bin/postinstall.js) chịu trách nhiệm gọi printWelcomeScreen() —\n// không auto-execute ở đây để tránh in trùng khi module được import từ postinstall.\n","// Avatar ASCII banner — gradient màu cam → tím để in ở các entry point chính:\n// `avatar --version`, `avatar init`, `avatar login`.\n//\n// Style: ANSI Shadow block characters (Unicode box-drawing).\n// Tự fallback sang plain text khi không phải TTY (CI, pipe ra file).\nimport chalk from \"chalk\";\n\n// 6 dòng chính của logo, mỗi dòng giữ độ rộng đồng nhất 50 ký tự để gradient đẹp.\nconst BANNER_LINES: readonly string[] = [\n \" █████╗ ██╗ ██╗ █████╗ ████████╗ █████╗ ██████╗ \",\n \"██╔══██╗██║ ██║██╔══██╗╚══██╔══╝██╔══██╗██╔══██╗\",\n \"███████║██║ ██║███████║ ██║ ███████║██████╔╝\",\n \"██╔══██║╚██╗ ██╔╝██╔══██║ ██║ ██╔══██║██╔══██╗\",\n \"██║ ██║ ╚████╔╝ ██║ ██║ ██║ ██║ ██║██║ ██║\",\n \"╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝\",\n] as const;\n\n// Gradient stops cam → tím (RGB triples). Mỗi dòng nội suy theo % chiều cao.\nconst GRADIENT_STOPS: ReadonlyArray<readonly [number, number, number]> = [\n [217, 79, 30], // cam-cháy (#d94f1e)\n [200, 70, 80], // cam-hồng\n [170, 70, 140], // hồng-tím\n [125, 88, 217], // tím (#7d58d9)\n];\n\n// Nội suy tuyến tính 1 kênh màu giữa 2 stop.\nfunction lerpChannel(a: number, b: number, t: number): number {\n return Math.round(a + (b - a) * t);\n}\n\n// Lấy màu RGB tại vị trí [0,1] trên gradient.\nfunction gradientAt(t: number): readonly [number, number, number] {\n const clamped = Math.max(0, Math.min(1, t));\n const scaled = clamped * (GRADIENT_STOPS.length - 1);\n const lo = Math.floor(scaled);\n const hi = Math.min(GRADIENT_STOPS.length - 1, lo + 1);\n const localT = scaled - lo;\n const a = GRADIENT_STOPS[lo];\n const b = GRADIENT_STOPS[hi];\n return [\n lerpChannel(a[0], b[0], localT),\n lerpChannel(a[1], b[1], localT),\n lerpChannel(a[2], b[2], localT),\n ];\n}\n\n// Build banner string đã tô màu sẵn. Trả empty khi terminal không hỗ trợ màu.\nexport function renderAvatarBanner(opts?: { tagline?: string }): string {\n const isTty = process.stdout.isTTY ?? false;\n const supportsColor = isTty && chalk.level > 0;\n\n // Plain fallback cho CI hoặc pipe.\n if (!supportsColor) {\n return [...BANNER_LINES, ...(opts?.tagline ? [\"\", opts.tagline] : [])].join(\"\\n\");\n }\n\n const colored = BANNER_LINES.map((line, idx) => {\n const t = BANNER_LINES.length === 1 ? 0 : idx / (BANNER_LINES.length - 1);\n const [r, g, b] = gradientAt(t);\n return chalk.rgb(r, g, b).bold(line);\n });\n\n if (opts?.tagline) {\n colored.push(\"\");\n colored.push(chalk.dim(opts.tagline));\n }\n\n return colored.join(\"\\n\");\n}\n\n// Tiện ích: in banner ra stdout với newline phía trước/sau cho thoáng.\nexport function printAvatarBanner(opts?: { tagline?: string }): void {\n process.stdout.write(`\\n${renderAvatarBanner(opts)}\\n\\n`);\n}\n","// Terminal logging helpers — chalk for color, ora for spinners.\n// All Avatar CLI output should funnel through here for consistent UX.\nimport chalk from \"chalk\";\nimport ora, { type Ora } from \"ora\";\n\ntype LogFn = (message: string) => void;\n\nexport const log: {\n info: LogFn;\n success: LogFn;\n warn: LogFn;\n error: LogFn;\n dim: LogFn;\n plain: LogFn;\n} = {\n info: (m) => process.stdout.write(`${chalk.blue(\"ℹ\")} ${m}\\n`),\n success: (m) => process.stdout.write(`${chalk.green(\"✓\")} ${m}\\n`),\n warn: (m) => process.stdout.write(`${chalk.yellow(\"⚠\")} ${m}\\n`),\n error: (m) => process.stderr.write(`${chalk.red(\"✗\")} ${m}\\n`),\n dim: (m) => process.stdout.write(`${chalk.dim(m)}\\n`),\n plain: (m) => process.stdout.write(`${m}\\n`),\n};\n\n// Spinner wrapper — handles non-TTY by degrading to plain output.\nexport function spinner(text: string): Ora {\n return ora({\n text,\n spinner: \"dots\",\n isEnabled: process.stdout.isTTY ?? false,\n }).start();\n}\n\n// Chalk re-export so commands don't all import chalk separately.\nexport { chalk };\n"],"mappings":"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","names":["chalk","chalk"]}
|