@nalvietnam/avatar-cli 1.2.9 → 1.2.10
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
|
@@ -1865,6 +1865,40 @@ async function ensureGitHubReady(remoteUrl) {
|
|
|
1865
1865
|
}
|
|
1866
1866
|
|
|
1867
1867
|
// src/lib/create-workspace-remote-via-gh.ts
|
|
1868
|
+
var CreateWorkspaceRemoteError = class extends Error {
|
|
1869
|
+
reason;
|
|
1870
|
+
fullName;
|
|
1871
|
+
stderr;
|
|
1872
|
+
constructor(reason, fullName, message, stderr) {
|
|
1873
|
+
super(message);
|
|
1874
|
+
this.name = "CreateWorkspaceRemoteError";
|
|
1875
|
+
this.reason = reason;
|
|
1876
|
+
this.fullName = fullName;
|
|
1877
|
+
this.stderr = stderr;
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
function classifyGhCreateError(stderr) {
|
|
1881
|
+
const text = stderr.toLowerCase();
|
|
1882
|
+
if (text.includes("name already exists") || text.includes("already exists on this account") || text.includes("repository already exists")) {
|
|
1883
|
+
return "repo-exists";
|
|
1884
|
+
}
|
|
1885
|
+
if (text.includes("403") || text.includes("permission") || text.includes("not authorized") || text.includes("forbidden")) {
|
|
1886
|
+
return "no-permission";
|
|
1887
|
+
}
|
|
1888
|
+
if (text.includes("invalid") && text.includes("name")) {
|
|
1889
|
+
return "name-invalid";
|
|
1890
|
+
}
|
|
1891
|
+
if (text.includes("could not resolve") || text.includes("network") || text.includes("connection refused")) {
|
|
1892
|
+
return "network";
|
|
1893
|
+
}
|
|
1894
|
+
return "unknown";
|
|
1895
|
+
}
|
|
1896
|
+
function repoExistsOnGitHub(fullName) {
|
|
1897
|
+
const r = spawnSync16("gh", ["repo", "view", fullName, "--json", "name"], {
|
|
1898
|
+
stdio: "ignore"
|
|
1899
|
+
});
|
|
1900
|
+
return r.status === 0;
|
|
1901
|
+
}
|
|
1868
1902
|
function canCreateInNamespace(org, ghUser) {
|
|
1869
1903
|
if (org.toLowerCase() === ghUser.toLowerCase()) return { ok: true };
|
|
1870
1904
|
const r = spawnSync16("gh", ["api", `orgs/${org}/members/${ghUser}`, "--silent"], {
|
|
@@ -1901,6 +1935,13 @@ async function createWorkspaceRemoteViaGh(input5) {
|
|
|
1901
1935
|
throw new Error(`Kh\xF4ng th\u1EC3 t\u1EA1o repo d\u01B0\u1EDBi '${org}/': ${namespaceCheck.reason}`);
|
|
1902
1936
|
}
|
|
1903
1937
|
const fullName = `${org}/${input5.workspaceName}`;
|
|
1938
|
+
if (repoExistsOnGitHub(fullName)) {
|
|
1939
|
+
throw new CreateWorkspaceRemoteError(
|
|
1940
|
+
"repo-exists",
|
|
1941
|
+
fullName,
|
|
1942
|
+
`Repo '${fullName}' \u0111\xE3 t\u1ED3n t\u1EA1i tr\xEAn GitHub. C\xF3 th\u1EC3 b\u1EA1n \u0111\xE3 init workspace n\xE0y tr\u01B0\u1EDBc \u0111\xF3.`
|
|
1943
|
+
);
|
|
1944
|
+
}
|
|
1904
1945
|
log.info(`T\u1EA1o GitHub repo cho workspace: ${fullName} (${input5.visibility})...`);
|
|
1905
1946
|
const r = spawnSync16(
|
|
1906
1947
|
"gh",
|
|
@@ -1915,14 +1956,24 @@ async function createWorkspaceRemoteViaGh(input5) {
|
|
|
1915
1956
|
"origin",
|
|
1916
1957
|
"--push"
|
|
1917
1958
|
],
|
|
1918
|
-
{ stdio: ["
|
|
1959
|
+
{ stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }
|
|
1919
1960
|
);
|
|
1920
1961
|
if (r.status !== 0) {
|
|
1921
1962
|
const stderr = (r.stderr || "").trim();
|
|
1922
|
-
|
|
1963
|
+
const stdout = (r.stdout || "").trim();
|
|
1964
|
+
const combined = [stderr, stdout].filter(Boolean).join("\n");
|
|
1965
|
+
const reason = classifyGhCreateError(combined);
|
|
1966
|
+
if (combined) {
|
|
1967
|
+
process.stderr.write(`
|
|
1968
|
+
${combined}
|
|
1969
|
+
|
|
1923
1970
|
`);
|
|
1924
|
-
|
|
1925
|
-
|
|
1971
|
+
}
|
|
1972
|
+
throw new CreateWorkspaceRemoteError(
|
|
1973
|
+
reason,
|
|
1974
|
+
fullName,
|
|
1975
|
+
`T\u1EA1o workspace remote th\u1EA5t b\u1EA1i (exit ${r.status}): ${reason}.`,
|
|
1976
|
+
combined
|
|
1926
1977
|
);
|
|
1927
1978
|
}
|
|
1928
1979
|
const sshUrl = `git@github.com:${fullName}.git`;
|
|
@@ -1930,6 +1981,25 @@ async function createWorkspaceRemoteViaGh(input5) {
|
|
|
1930
1981
|
log.success(`Workspace remote: ${sshUrl}`);
|
|
1931
1982
|
return { sshUrl, httpsUrl };
|
|
1932
1983
|
}
|
|
1984
|
+
function linkExistingRemoteToWorkspace(args) {
|
|
1985
|
+
const sshUrl = `git@github.com:${args.fullName}.git`;
|
|
1986
|
+
const httpsUrl = `https://github.com/${args.fullName}.git`;
|
|
1987
|
+
const addResult = spawnSync16(
|
|
1988
|
+
"git",
|
|
1989
|
+
["-C", args.workspacePath, "remote", "add", "origin", sshUrl],
|
|
1990
|
+
{
|
|
1991
|
+
encoding: "utf8",
|
|
1992
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1993
|
+
}
|
|
1994
|
+
);
|
|
1995
|
+
if (addResult.status !== 0) {
|
|
1996
|
+
spawnSync16("git", ["-C", args.workspacePath, "remote", "set-url", "origin", sshUrl], {
|
|
1997
|
+
stdio: "ignore"
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
log.success(`Linked existing remote: ${sshUrl}`);
|
|
2001
|
+
return { sshUrl, httpsUrl };
|
|
2002
|
+
}
|
|
1933
2003
|
|
|
1934
2004
|
// src/lib/safe-bootstrap-for-dirty-folder.ts
|
|
1935
2005
|
import { readdirSync } from "fs";
|
|
@@ -2793,6 +2863,44 @@ async function maybeCreateWorkspaceRemote(args) {
|
|
|
2793
2863
|
});
|
|
2794
2864
|
return;
|
|
2795
2865
|
} catch (err) {
|
|
2866
|
+
if (err instanceof CreateWorkspaceRemoteError && err.reason === "repo-exists") {
|
|
2867
|
+
const fullName = err.fullName;
|
|
2868
|
+
const reuseAction = await select7({
|
|
2869
|
+
message: `Repo '${fullName}' \u0111\xE3 t\u1ED3n t\u1EA1i tr\xEAn GitHub. C\xE1ch x\u1EED l\xFD?`,
|
|
2870
|
+
choices: [
|
|
2871
|
+
{
|
|
2872
|
+
name: "D\xF9ng remote \u0111\xE3 c\xF3 (link workspace local v\xE0o repo n\xE0y)",
|
|
2873
|
+
value: "reuse"
|
|
2874
|
+
},
|
|
2875
|
+
{
|
|
2876
|
+
name: "Nh\u1EADp t\xEAn workspace kh\xE1c (t\u1EA1o repo m\u1EDBi)",
|
|
2877
|
+
value: "rename"
|
|
2878
|
+
},
|
|
2879
|
+
{ name: "B\u1ECF qua (workspace local-only)", value: "skip" },
|
|
2880
|
+
{ name: "T\u1EA1m ng\u01B0ng init", value: "abort" }
|
|
2881
|
+
]
|
|
2882
|
+
});
|
|
2883
|
+
if (reuseAction === "abort") {
|
|
2884
|
+
throw new UserAbortedRecoveryError("User abort t\u1EA1i b\u01B0\u1EDBc t\u1EA1o workspace remote.");
|
|
2885
|
+
}
|
|
2886
|
+
if (reuseAction === "skip") {
|
|
2887
|
+
log.warn("Workspace v\u1EABn s\u1EB5n s\xE0ng local-only. Setup remote sau khi c\u1EA7n.");
|
|
2888
|
+
return;
|
|
2889
|
+
}
|
|
2890
|
+
if (reuseAction === "reuse") {
|
|
2891
|
+
linkExistingRemoteToWorkspace({
|
|
2892
|
+
workspacePath: args.workspacePath,
|
|
2893
|
+
fullName
|
|
2894
|
+
});
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2897
|
+
const newName = await input4({
|
|
2898
|
+
message: "T\xEAn workspace m\u1EDBi (s\u1EBD t\u1EA1o repo new):",
|
|
2899
|
+
validate: (v) => v.trim().length > 0 ? true : "T\xEAn kh\xF4ng \u0111\u01B0\u1EE3c r\u1ED7ng"
|
|
2900
|
+
});
|
|
2901
|
+
args.workspaceName = newName.trim();
|
|
2902
|
+
continue;
|
|
2903
|
+
}
|
|
2796
2904
|
const action = await promptRetryOrSkip({
|
|
2797
2905
|
taskName: "T\u1EA1o workspace remote tr\xEAn GitHub",
|
|
2798
2906
|
reason: err instanceof Error ? err.message : String(err),
|
|
@@ -3173,7 +3281,7 @@ async function removeSubmoduleEntry(gitmodulesPath, submodulePath) {
|
|
|
3173
3281
|
}
|
|
3174
3282
|
|
|
3175
3283
|
// src/commands/uninstall.ts
|
|
3176
|
-
var CLI_VERSION = "1.2.
|
|
3284
|
+
var CLI_VERSION = "1.2.10";
|
|
3177
3285
|
function registerUninstallCommand(program2) {
|
|
3178
3286
|
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) => {
|
|
3179
3287
|
try {
|
|
@@ -3255,7 +3363,7 @@ function printUninstallSuccessBox(backupPath) {
|
|
|
3255
3363
|
}
|
|
3256
3364
|
|
|
3257
3365
|
// src/index.ts
|
|
3258
|
-
var CLI_VERSION2 = "1.2.
|
|
3366
|
+
var CLI_VERSION2 = "1.2.10";
|
|
3259
3367
|
var program = new Command();
|
|
3260
3368
|
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(
|
|
3261
3369
|
"beforeAll",
|