@duyquangnvx/create-agent-cli 0.10.1 → 0.11.1
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/CHANGELOG.md +16 -0
- package/dist/bin.js +307 -53
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## v0.11.1 (2026-10-22)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- The agent-cli skill explains `ctx.secret` and the CLI's `.env`, lists idempotence among what a finished write Command's tests cover (its example `links archive` gains that test), triggers on releasing a CLI and on choosing a Global or a Dependency install, and leaves out Runtime behaviour an author cannot change, such as the stdin stall and how spilled output reads; the `--json` stderr format moves to its testing reference.
|
|
12
|
+
|
|
13
|
+
## v0.11.0 (2026-10-22)
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- A Dependency install, `install: { mode: "dependency", package, lockstep? }`, for a CLI each project pins as a devDependency. It gets no Built-in `update`, so the CLI may define its own. `doctor`'s `install` row checks that the project's own copy runs, and its `registry` row asks npm at the project root, which reads the project's `.npmrc`, for the latest release, giving `pnpm up --latest …` or `npm install …@latest` with the `lockstep` packages.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `doctor`'s `install` and `registry` rows are `skipped` ("not checked: <cli> declares no install") for a CLI that declares no `install`, instead of an `ok` that checked nothing.
|
|
22
|
+
|
|
7
23
|
## v0.10.1 (2026-10-22)
|
|
8
24
|
|
|
9
25
|
### Changed
|
package/dist/bin.js
CHANGED
|
@@ -3206,7 +3206,7 @@ function registry() {
|
|
|
3206
3206
|
return new $ZodRegistry();
|
|
3207
3207
|
}
|
|
3208
3208
|
(_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry());
|
|
3209
|
-
const globalRegistry = globalThis.__zod_globalRegistry;
|
|
3209
|
+
const globalRegistry$1 = globalThis.__zod_globalRegistry;
|
|
3210
3210
|
//#endregion
|
|
3211
3211
|
//#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/api.js
|
|
3212
3212
|
function snapshotChecks(def) {
|
|
@@ -3728,7 +3728,7 @@ function initializeContext(params) {
|
|
|
3728
3728
|
if (target === "draft-7") target = "draft-07";
|
|
3729
3729
|
return {
|
|
3730
3730
|
processors: params.processors ?? {},
|
|
3731
|
-
metadataRegistry: params?.metadata ?? globalRegistry,
|
|
3731
|
+
metadataRegistry: params?.metadata ?? globalRegistry$1,
|
|
3732
3732
|
target,
|
|
3733
3733
|
unrepresentable: params?.unrepresentable ?? "throw",
|
|
3734
3734
|
override: params?.override ?? (() => {}),
|
|
@@ -4855,6 +4855,7 @@ const initializer = (inst, issues) => {
|
|
|
4855
4855
|
}
|
|
4856
4856
|
});
|
|
4857
4857
|
};
|
|
4858
|
+
const ZodError = /*@__PURE__*/ $constructor("ZodError", initializer);
|
|
4858
4859
|
const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, void 0, { Parent: Error });
|
|
4859
4860
|
//#endregion
|
|
4860
4861
|
//#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/parse.js
|
|
@@ -4959,13 +4960,13 @@ const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
|
|
|
4959
4960
|
},
|
|
4960
4961
|
describe(description) {
|
|
4961
4962
|
const cl = this.clone();
|
|
4962
|
-
globalRegistry.add(cl, { description });
|
|
4963
|
+
globalRegistry$1.add(cl, { description });
|
|
4963
4964
|
return cl;
|
|
4964
4965
|
},
|
|
4965
4966
|
meta(...args) {
|
|
4966
|
-
if (args.length === 0) return globalRegistry.get(this);
|
|
4967
|
+
if (args.length === 0) return globalRegistry$1.get(this);
|
|
4967
4968
|
const cl = this.clone();
|
|
4968
|
-
globalRegistry.add(cl, args[0]);
|
|
4969
|
+
globalRegistry$1.add(cl, args[0]);
|
|
4969
4970
|
return cl;
|
|
4970
4971
|
},
|
|
4971
4972
|
isOptional() {
|
|
@@ -5041,7 +5042,7 @@ const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
|
|
|
5041
5042
|
return createToJSONSchemaMethod(this, {})(params);
|
|
5042
5043
|
},
|
|
5043
5044
|
get description() {
|
|
5044
|
-
return globalRegistry.get(this)?.description;
|
|
5045
|
+
return globalRegistry$1.get(this)?.description;
|
|
5045
5046
|
},
|
|
5046
5047
|
get _def() {
|
|
5047
5048
|
return this._zod.def;
|
|
@@ -5882,7 +5883,7 @@ function formatRuntimeError(error, format) {
|
|
|
5882
5883
|
//#region ../agent-cli/dist/stdin.js
|
|
5883
5884
|
const STDIN_META = "stdin";
|
|
5884
5885
|
function isStdinSchema(schema) {
|
|
5885
|
-
return globalRegistry.get(schema)?.[STDIN_META] === true;
|
|
5886
|
+
return globalRegistry$1.get(schema)?.[STDIN_META] === true;
|
|
5886
5887
|
}
|
|
5887
5888
|
function endOfInputKeys(platform) {
|
|
5888
5889
|
return platform === "win32" ? "Ctrl-Z then Enter" : "Ctrl-D";
|
|
@@ -6813,7 +6814,7 @@ function compareVersions(a, b) {
|
|
|
6813
6814
|
return comparePrerelease(left[4], right[4]);
|
|
6814
6815
|
}
|
|
6815
6816
|
/** Where `version` stands against `latest`. */
|
|
6816
|
-
function standingOf(version, latest) {
|
|
6817
|
+
function standingOf$1(version, latest) {
|
|
6817
6818
|
const difference = compareVersions(version, latest);
|
|
6818
6819
|
if (difference < 0) return "behind";
|
|
6819
6820
|
return difference > 0 ? "ahead" : "current";
|
|
@@ -6838,10 +6839,11 @@ const REGISTRY_AUTH = "REGISTRY_AUTH";
|
|
|
6838
6839
|
const INSTALL_FAILED = "INSTALL_FAILED";
|
|
6839
6840
|
const NPM_FAILED = "NPM_FAILED";
|
|
6840
6841
|
const NO_LATEST = "NO_LATEST";
|
|
6841
|
-
function npmContext(cli,
|
|
6842
|
+
function npmContext(cli, registry, ctx, node, cwd) {
|
|
6842
6843
|
return {
|
|
6843
6844
|
cliName: cli.name,
|
|
6844
|
-
|
|
6845
|
+
registry,
|
|
6846
|
+
cwd,
|
|
6845
6847
|
env: ctx.env,
|
|
6846
6848
|
signal: ctx.signal,
|
|
6847
6849
|
node
|
|
@@ -6862,20 +6864,40 @@ const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
|
6862
6864
|
]);
|
|
6863
6865
|
const AUTH_CODES = /* @__PURE__ */ new Set(["E401", "E403"]);
|
|
6864
6866
|
const NPM_CODE = /^npm (?:error|ERR!) code (\S+)$/m;
|
|
6867
|
+
/** The `@scope` of a scoped package name. */
|
|
6868
|
+
function scopeOf(name) {
|
|
6869
|
+
return /^(@[^/]+)\//.exec(name)?.[1];
|
|
6870
|
+
}
|
|
6865
6871
|
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
6866
6872
|
function registryFlags({ package: name, registry }) {
|
|
6867
6873
|
if (registry === NPMJS) return [];
|
|
6868
|
-
const scope =
|
|
6874
|
+
const scope = scopeOf(name);
|
|
6869
6875
|
return [scope === void 0 ? `--registry=${registry}` : `--${scope}:registry=${registry}`];
|
|
6870
6876
|
}
|
|
6877
|
+
/** The registry a Global install declares. */
|
|
6878
|
+
function globalRegistry(install) {
|
|
6879
|
+
const { package: name, registry } = install;
|
|
6880
|
+
return {
|
|
6881
|
+
package: name,
|
|
6882
|
+
label: registry,
|
|
6883
|
+
flags: registryFlags(install),
|
|
6884
|
+
unreachableHint: "check the network or VPN, then run it again",
|
|
6885
|
+
loginHint: `log in to ${registry} (npm login --registry=${registry}) or set its token in ~/.npmrc, then run it again`,
|
|
6886
|
+
missingHint: `check that ${name} is published on ${registry}`
|
|
6887
|
+
};
|
|
6888
|
+
}
|
|
6889
|
+
/** npm for a Global install, run where the CLI was started. */
|
|
6890
|
+
function globalNpm(cli, install, ctx, node) {
|
|
6891
|
+
return npmContext(cli, globalRegistry(install), ctx, node, process.cwd());
|
|
6892
|
+
}
|
|
6871
6893
|
/** The command a person runs to install the CLI globally from its registry. */
|
|
6872
|
-
function installCommandLine(
|
|
6894
|
+
function installCommandLine(registry, version = "latest") {
|
|
6873
6895
|
return [
|
|
6874
6896
|
"npm",
|
|
6875
6897
|
"install",
|
|
6876
6898
|
"--global",
|
|
6877
|
-
`${
|
|
6878
|
-
...
|
|
6899
|
+
`${registry.package}@${version}`,
|
|
6900
|
+
...registry.flags
|
|
6879
6901
|
].join(" ");
|
|
6880
6902
|
}
|
|
6881
6903
|
function npmOf(ctx, windows) {
|
|
@@ -6900,7 +6922,7 @@ function npmOf(ctx, windows) {
|
|
|
6900
6922
|
function spawnNpm(args, ctx, signal) {
|
|
6901
6923
|
const npm = npmOf(ctx, process.platform === "win32");
|
|
6902
6924
|
return spawnChild(npm.path, args, {
|
|
6903
|
-
cwd:
|
|
6925
|
+
cwd: ctx.cwd,
|
|
6904
6926
|
env: npm.env,
|
|
6905
6927
|
signal: signal ?? new AbortController().signal,
|
|
6906
6928
|
detached: signal === null
|
|
@@ -6911,24 +6933,24 @@ function tail$1(stderr) {
|
|
|
6911
6933
|
return lines === "" ? "" : `\n${lines}`;
|
|
6912
6934
|
}
|
|
6913
6935
|
function failureOf(call, answer, ctx) {
|
|
6914
|
-
const { registry, package: name } = ctx.
|
|
6936
|
+
const { label: registry, package: name, loginHint, unreachableHint } = ctx.registry;
|
|
6915
6937
|
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
6916
6938
|
const output = tail$1(answer.stderr);
|
|
6917
6939
|
if (code !== void 0 && NETWORK_CODES.has(code)) return new CliError({
|
|
6918
6940
|
code: REGISTRY_UNREACHABLE,
|
|
6919
6941
|
message: `npm could not reach ${registry} (${code})${output}`,
|
|
6920
|
-
hint:
|
|
6942
|
+
hint: unreachableHint
|
|
6921
6943
|
});
|
|
6922
6944
|
if (code !== void 0 && AUTH_CODES.has(code)) return new CliError({
|
|
6923
6945
|
code: REGISTRY_AUTH,
|
|
6924
6946
|
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
6925
|
-
hint:
|
|
6947
|
+
hint: loginHint
|
|
6926
6948
|
});
|
|
6927
6949
|
if (call === "view" && code === "E404") return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
6928
6950
|
if (call === "install") return new CliError({
|
|
6929
6951
|
code: INSTALL_FAILED,
|
|
6930
6952
|
message: `npm could not install ${name}${code === void 0 ? "" : ` (${code})`}${output}`,
|
|
6931
|
-
hint: `fix what npm reports, then run it again, or install it yourself: ${installCommandLine(ctx.
|
|
6953
|
+
hint: `fix what npm reports, then run it again, or install it yourself: ${installCommandLine(ctx.registry)}`
|
|
6932
6954
|
});
|
|
6933
6955
|
return new CliError({
|
|
6934
6956
|
code: NPM_FAILED,
|
|
@@ -6940,7 +6962,7 @@ function noLatest(ctx, message) {
|
|
|
6940
6962
|
return new CliError({
|
|
6941
6963
|
code: NO_LATEST,
|
|
6942
6964
|
message,
|
|
6943
|
-
hint:
|
|
6965
|
+
hint: ctx.registry.missingHint
|
|
6944
6966
|
});
|
|
6945
6967
|
}
|
|
6946
6968
|
/**
|
|
@@ -6991,18 +7013,18 @@ async function installGlobally(version, ctx) {
|
|
|
6991
7013
|
"--global",
|
|
6992
7014
|
"--no-audit",
|
|
6993
7015
|
"--no-fund",
|
|
6994
|
-
`${ctx.
|
|
6995
|
-
...
|
|
7016
|
+
`${ctx.registry.package}@${version}`,
|
|
7017
|
+
...ctx.registry.flags
|
|
6996
7018
|
], ctx, null);
|
|
6997
7019
|
}
|
|
6998
7020
|
async function latestVersion(ctx) {
|
|
6999
|
-
const { package: name, registry } = ctx.
|
|
7021
|
+
const { package: name, label: registry, flags } = ctx.registry;
|
|
7000
7022
|
const answer = await runNpm("view", [
|
|
7001
7023
|
"view",
|
|
7002
7024
|
`${name}@latest`,
|
|
7003
7025
|
"version",
|
|
7004
7026
|
"--json",
|
|
7005
|
-
...
|
|
7027
|
+
...flags
|
|
7006
7028
|
], ctx);
|
|
7007
7029
|
const version = versionInViewAnswer(answer);
|
|
7008
7030
|
if (version === void 0) throw noLatest(ctx, `npm answered no version for ${name}@latest on ${registry}: ${answer.trim()}`);
|
|
@@ -7019,7 +7041,7 @@ function notGlobal(ctx, message) {
|
|
|
7019
7041
|
return new CliError({
|
|
7020
7042
|
code: NOT_GLOBAL_INSTALL,
|
|
7021
7043
|
message,
|
|
7022
|
-
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.
|
|
7044
|
+
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.registry)}`
|
|
7023
7045
|
});
|
|
7024
7046
|
}
|
|
7025
7047
|
async function realpathOrUndefined(path) {
|
|
@@ -7028,6 +7050,7 @@ async function realpathOrUndefined(path) {
|
|
|
7028
7050
|
throw error;
|
|
7029
7051
|
});
|
|
7030
7052
|
}
|
|
7053
|
+
/** Whether `path` lies strictly inside `dir`. */
|
|
7031
7054
|
function isInside(dir, path) {
|
|
7032
7055
|
const inner = relative(dir, path);
|
|
7033
7056
|
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
@@ -7039,7 +7062,7 @@ function isInside(dir, path) {
|
|
|
7039
7062
|
async function globalInstallOf(bin, ctx) {
|
|
7040
7063
|
if (bin === void 0) throw notGlobal(ctx, `${ctx.cliName} runs from source, not from an npm install`);
|
|
7041
7064
|
const prefix = await globalPrefix(ctx);
|
|
7042
|
-
const packageDir = join(globalModulesDir(prefix), ctx.
|
|
7065
|
+
const packageDir = join(globalModulesDir(prefix), ctx.registry.package);
|
|
7043
7066
|
const installed = await realpathOrUndefined(packageDir);
|
|
7044
7067
|
const here = await realpathOrUndefined(bin) ?? bin;
|
|
7045
7068
|
if (installed === void 0 || !isInside(installed, here)) throw notGlobal(ctx, `${ctx.cliName} runs from ${here}, not from npm's global install at ${packageDir}`);
|
|
@@ -7050,6 +7073,196 @@ async function globalInstallOf(bin, ctx) {
|
|
|
7050
7073
|
};
|
|
7051
7074
|
}
|
|
7052
7075
|
//#endregion
|
|
7076
|
+
//#region ../agent-cli/dist/built-ins/dependency-install.js
|
|
7077
|
+
const MANAGERS = [
|
|
7078
|
+
"pnpm",
|
|
7079
|
+
"npm",
|
|
7080
|
+
"yarn",
|
|
7081
|
+
"bun"
|
|
7082
|
+
];
|
|
7083
|
+
const LOCKFILES = [
|
|
7084
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
7085
|
+
["package-lock.json", "npm"],
|
|
7086
|
+
["yarn.lock", "yarn"],
|
|
7087
|
+
["bun.lock", "bun"],
|
|
7088
|
+
["bun.lockb", "bun"]
|
|
7089
|
+
];
|
|
7090
|
+
const LINES = {
|
|
7091
|
+
pnpm: {
|
|
7092
|
+
upgrade: (packages) => `pnpm up --latest ${packages.join(" ")}`,
|
|
7093
|
+
add: (packages) => `pnpm add -D ${packages.join(" ")}`,
|
|
7094
|
+
reinstall: "pnpm install",
|
|
7095
|
+
exec: (cli) => `pnpm exec ${cli}`
|
|
7096
|
+
},
|
|
7097
|
+
npm: {
|
|
7098
|
+
upgrade: (packages) => `npm install ${packages.map((name) => `${name}@latest`).join(" ")}`,
|
|
7099
|
+
add: (packages) => `npm install -D ${packages.join(" ")}`,
|
|
7100
|
+
reinstall: "npm install",
|
|
7101
|
+
exec: (cli) => `npx ${cli}`
|
|
7102
|
+
}
|
|
7103
|
+
};
|
|
7104
|
+
const manifestSchema$1 = object({ packageManager: string().optional() });
|
|
7105
|
+
const packageSchema = object({ version: string() });
|
|
7106
|
+
/** `dir` and every folder above it, nearest first. */
|
|
7107
|
+
function ancestorsOf(dir) {
|
|
7108
|
+
const parent = dirname(dir);
|
|
7109
|
+
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
7110
|
+
}
|
|
7111
|
+
async function exists(path) {
|
|
7112
|
+
try {
|
|
7113
|
+
await stat(path);
|
|
7114
|
+
return true;
|
|
7115
|
+
} catch (error) {
|
|
7116
|
+
if (isMissingFile(error)) return false;
|
|
7117
|
+
throw error;
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
async function declaredManager(dir) {
|
|
7121
|
+
let text;
|
|
7122
|
+
try {
|
|
7123
|
+
text = await readFile(join(dir, "package.json"), "utf8");
|
|
7124
|
+
} catch (error) {
|
|
7125
|
+
if (isMissingFile(error)) return void 0;
|
|
7126
|
+
throw error;
|
|
7127
|
+
}
|
|
7128
|
+
let manifest;
|
|
7129
|
+
try {
|
|
7130
|
+
manifest = JSON.parse(text);
|
|
7131
|
+
} catch {
|
|
7132
|
+
return;
|
|
7133
|
+
}
|
|
7134
|
+
const name = manifestSchema$1.safeParse(manifest).data?.packageManager?.split("@")[0];
|
|
7135
|
+
return MANAGERS.find((manager) => manager === name);
|
|
7136
|
+
}
|
|
7137
|
+
async function lockfileRootOf(cwd) {
|
|
7138
|
+
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
7139
|
+
dir,
|
|
7140
|
+
manager: await declaredManager(dir) ?? kind
|
|
7141
|
+
};
|
|
7142
|
+
}
|
|
7143
|
+
async function versionIn(manifest) {
|
|
7144
|
+
try {
|
|
7145
|
+
return packageSchema.parse(JSON.parse(await readFile(manifest, "utf8"))).version;
|
|
7146
|
+
} catch (error) {
|
|
7147
|
+
if (error instanceof SyntaxError || error instanceof ZodError) return { reason: messageOf(error) };
|
|
7148
|
+
throw error;
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
async function standingOf(install, bin, cwd) {
|
|
7152
|
+
if (bin === void 0) return { kind: "source" };
|
|
7153
|
+
for (const projectDir of ancestorsOf(cwd)) {
|
|
7154
|
+
const folder = join(projectDir, "node_modules", install.package);
|
|
7155
|
+
const manifest = join(folder, "package.json");
|
|
7156
|
+
if (!await exists(manifest)) continue;
|
|
7157
|
+
const version = await versionIn(manifest);
|
|
7158
|
+
if (typeof version !== "string") return {
|
|
7159
|
+
kind: "unreadable",
|
|
7160
|
+
manifest,
|
|
7161
|
+
...version
|
|
7162
|
+
};
|
|
7163
|
+
const copy = {
|
|
7164
|
+
projectDir,
|
|
7165
|
+
realDir: await realpath(folder),
|
|
7166
|
+
version
|
|
7167
|
+
};
|
|
7168
|
+
if (!copy.realDir.split(sep).includes("node_modules")) return {
|
|
7169
|
+
kind: "linked",
|
|
7170
|
+
copy
|
|
7171
|
+
};
|
|
7172
|
+
const runningFrom = await realpath(bin).catch((error) => {
|
|
7173
|
+
if (isMissingFile(error)) return bin;
|
|
7174
|
+
throw error;
|
|
7175
|
+
});
|
|
7176
|
+
return isInside(copy.realDir, runningFrom) ? {
|
|
7177
|
+
kind: "installed",
|
|
7178
|
+
copy
|
|
7179
|
+
} : {
|
|
7180
|
+
kind: "other",
|
|
7181
|
+
copy,
|
|
7182
|
+
runningFrom
|
|
7183
|
+
};
|
|
7184
|
+
}
|
|
7185
|
+
return { kind: "missing" };
|
|
7186
|
+
}
|
|
7187
|
+
async function surveyDependency(install, bin, cwd) {
|
|
7188
|
+
const [root, standing] = await Promise.all([lockfileRootOf(cwd), standingOf(install, bin, cwd)]);
|
|
7189
|
+
return {
|
|
7190
|
+
cwd,
|
|
7191
|
+
root,
|
|
7192
|
+
standing
|
|
7193
|
+
};
|
|
7194
|
+
}
|
|
7195
|
+
function packagesOf(install) {
|
|
7196
|
+
return [install.package, ...install.lockstep ?? []];
|
|
7197
|
+
}
|
|
7198
|
+
function isUnchecked(standing) {
|
|
7199
|
+
return standing.kind === "source" || standing.kind === "linked";
|
|
7200
|
+
}
|
|
7201
|
+
function skippedFor(cli, install, standing) {
|
|
7202
|
+
return {
|
|
7203
|
+
state: "skipped",
|
|
7204
|
+
message: standing.kind === "source" ? `not checked: ${cli.name} runs from source, not from an install` : `not checked: ${install.package} links to ${standing.copy.realDir}, so the workspace decides its version`
|
|
7205
|
+
};
|
|
7206
|
+
}
|
|
7207
|
+
function problem(message, fix) {
|
|
7208
|
+
return fix === void 0 ? {
|
|
7209
|
+
state: "problem",
|
|
7210
|
+
message
|
|
7211
|
+
} : {
|
|
7212
|
+
state: "problem",
|
|
7213
|
+
message,
|
|
7214
|
+
fix
|
|
7215
|
+
};
|
|
7216
|
+
}
|
|
7217
|
+
/** The `install` row of a Dependency install. */
|
|
7218
|
+
function dependencyInstallFinding(cli, install, { cwd, root, standing }) {
|
|
7219
|
+
const lines = root === void 0 ? void 0 : LINES[root.manager];
|
|
7220
|
+
switch (standing.kind) {
|
|
7221
|
+
case "source":
|
|
7222
|
+
case "linked": return skippedFor(cli, install, standing);
|
|
7223
|
+
case "missing": return problem(`no package at or above ${cwd} depends on ${install.package}`, lines?.add(packagesOf(install)));
|
|
7224
|
+
case "unreadable": return problem(`${standing.manifest} is not a package.json with a version: ${standing.reason}`, lines?.reinstall);
|
|
7225
|
+
case "other": {
|
|
7226
|
+
const { copy, runningFrom } = standing;
|
|
7227
|
+
return problem(`${cli.name} runs from ${runningFrom}, not from this project's ${install.package} ${copy.version} at ${copy.realDir}`, lines?.exec(cli.name));
|
|
7228
|
+
}
|
|
7229
|
+
case "installed": {
|
|
7230
|
+
const { copy } = standing;
|
|
7231
|
+
const where = root === void 0 ? copy.projectDir : `${root.dir} with ${root.manager}`;
|
|
7232
|
+
return {
|
|
7233
|
+
state: "ok",
|
|
7234
|
+
message: `${install.package} ${copy.version}, installed in ${where}`
|
|
7235
|
+
};
|
|
7236
|
+
}
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
7239
|
+
function registryOf({ package: name }, root) {
|
|
7240
|
+
const npmrc = root === void 0 ? "the project's .npmrc" : join(root, ".npmrc");
|
|
7241
|
+
const scope = scopeOf(name);
|
|
7242
|
+
return {
|
|
7243
|
+
package: name,
|
|
7244
|
+
label: `the registry npm uses for ${name}`,
|
|
7245
|
+
flags: [],
|
|
7246
|
+
unreachableHint: scope === void 0 ? "check the network or VPN, then run it again" : `check the network or VPN and the ${scope}:registry that ${npmrc} sets, then run it again`,
|
|
7247
|
+
loginHint: `log in to it (npm login${scope === void 0 ? "" : ` --scope=${scope}`}) or set its token in ${npmrc}, then run it again`,
|
|
7248
|
+
missingHint: scope === void 0 ? `check that ${name} is published on the registry ${npmrc} names` : `check that ${name} is published, and that ${npmrc} maps ${scope} to its registry: ${scope}:registry=<url>`
|
|
7249
|
+
};
|
|
7250
|
+
}
|
|
7251
|
+
function adviceFor(install, root, latest) {
|
|
7252
|
+
const packages = packagesOf(install);
|
|
7253
|
+
const lines = root === void 0 ? void 0 : LINES[root.manager];
|
|
7254
|
+
if (lines !== void 0) return { fix: lines.upgrade(packages) };
|
|
7255
|
+
return { note: `move ${packages.length === 1 ? packages[0] : `${packages.slice(0, -1).join(", ")} and ${packages.at(-1)}`} to ${latest} with ${root?.manager ?? "the project's package manager"}` };
|
|
7256
|
+
}
|
|
7257
|
+
function dependencyRelease(cli, install, { cwd, root, standing }) {
|
|
7258
|
+
if (isUnchecked(standing)) return { skipped: skippedFor(cli, install, standing) };
|
|
7259
|
+
return {
|
|
7260
|
+
registry: registryOf(install, root?.dir),
|
|
7261
|
+
cwd: root?.dir ?? cwd,
|
|
7262
|
+
advise: (latest) => adviceFor(install, root, latest)
|
|
7263
|
+
};
|
|
7264
|
+
}
|
|
7265
|
+
//#endregion
|
|
7053
7266
|
//#region ../agent-cli/dist/built-ins/skills.js
|
|
7054
7267
|
const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
|
|
7055
7268
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
@@ -7083,7 +7296,7 @@ async function copyAt(path, version) {
|
|
|
7083
7296
|
return {
|
|
7084
7297
|
path,
|
|
7085
7298
|
version: stated,
|
|
7086
|
-
state: standingOf(stated, version)
|
|
7299
|
+
state: standingOf$1(stated, version)
|
|
7087
7300
|
};
|
|
7088
7301
|
}
|
|
7089
7302
|
async function skillCopies(cliName, version, { cwd, env }) {
|
|
@@ -7123,6 +7336,12 @@ function ok(message) {
|
|
|
7123
7336
|
message
|
|
7124
7337
|
};
|
|
7125
7338
|
}
|
|
7339
|
+
function noInstall(cli) {
|
|
7340
|
+
return {
|
|
7341
|
+
state: "skipped",
|
|
7342
|
+
message: `not checked: ${cli.name} declares no install`
|
|
7343
|
+
};
|
|
7344
|
+
}
|
|
7126
7345
|
function buildRow(cli) {
|
|
7127
7346
|
return {
|
|
7128
7347
|
name: "build",
|
|
@@ -7189,41 +7408,75 @@ function projectRow({ file }, read) {
|
|
|
7189
7408
|
}
|
|
7190
7409
|
};
|
|
7191
7410
|
}
|
|
7192
|
-
function
|
|
7411
|
+
function surveyOnce(bin) {
|
|
7412
|
+
let survey;
|
|
7413
|
+
return (install, cwd) => {
|
|
7414
|
+
survey ??= surveyDependency(install, bin, cwd);
|
|
7415
|
+
return survey;
|
|
7416
|
+
};
|
|
7417
|
+
}
|
|
7418
|
+
function installRow(cli, { bin, node }, survey) {
|
|
7193
7419
|
return {
|
|
7194
7420
|
name: "install",
|
|
7195
7421
|
advisory: true,
|
|
7196
7422
|
run: async (ctx) => {
|
|
7197
7423
|
const { install } = cli;
|
|
7198
|
-
if (install === void 0) return
|
|
7424
|
+
if (install === void 0) return noInstall(cli);
|
|
7425
|
+
if (install.mode === "dependency") return dependencyInstallFinding(cli, install, await survey(install, ctx.cwd));
|
|
7426
|
+
const npm = globalNpm(cli, install, ctx, node);
|
|
7199
7427
|
try {
|
|
7200
|
-
return ok(`a global npm install under ${(await globalInstallOf(bin,
|
|
7428
|
+
return ok(`a global npm install under ${(await globalInstallOf(bin, npm)).prefix}`);
|
|
7201
7429
|
} catch (error) {
|
|
7202
7430
|
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
7203
7431
|
state: "problem",
|
|
7204
7432
|
message: error.message,
|
|
7205
|
-
fix: installCommandLine(
|
|
7433
|
+
fix: installCommandLine(npm.registry)
|
|
7206
7434
|
};
|
|
7207
7435
|
throw error;
|
|
7208
7436
|
}
|
|
7209
7437
|
}
|
|
7210
7438
|
};
|
|
7211
7439
|
}
|
|
7212
|
-
function
|
|
7440
|
+
async function releaseLookupOf(cli, install, ctx, node, survey) {
|
|
7441
|
+
if (install.mode === "global") {
|
|
7442
|
+
const fix = `${cli.name} update`;
|
|
7443
|
+
return {
|
|
7444
|
+
npm: globalNpm(cli, install, ctx, node),
|
|
7445
|
+
advise: () => ({ fix })
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
const release = dependencyRelease(cli, install, await survey(install, ctx.cwd));
|
|
7449
|
+
if ("skipped" in release) return release;
|
|
7450
|
+
return {
|
|
7451
|
+
npm: npmContext(cli, release.registry, ctx, node, release.cwd),
|
|
7452
|
+
advise: release.advise
|
|
7453
|
+
};
|
|
7454
|
+
}
|
|
7455
|
+
function registryRow(cli, { node }, survey) {
|
|
7213
7456
|
return {
|
|
7214
7457
|
name: "registry",
|
|
7215
7458
|
advisory: true,
|
|
7216
7459
|
run: async (ctx) => {
|
|
7217
7460
|
const { install } = cli;
|
|
7218
|
-
if (install === void 0) return
|
|
7219
|
-
const
|
|
7220
|
-
|
|
7221
|
-
const
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7461
|
+
if (install === void 0) return noInstall(cli);
|
|
7462
|
+
const lookup = await releaseLookupOf(cli, install, ctx, node, survey);
|
|
7463
|
+
if ("skipped" in lookup) return lookup.skipped;
|
|
7464
|
+
const { npm, advise } = lookup;
|
|
7465
|
+
const latest = await latestVersion(npm);
|
|
7466
|
+
const standing = standingOf$1(cli.version, latest);
|
|
7467
|
+
const head = `${npm.registry.label} has ${latest} as latest: this build`;
|
|
7468
|
+
if (standing === "behind") {
|
|
7469
|
+
const message = `${head} (${cli.version}) is older`;
|
|
7470
|
+
const advice = advise(latest);
|
|
7471
|
+
return "fix" in advice ? {
|
|
7472
|
+
state: "problem",
|
|
7473
|
+
message,
|
|
7474
|
+
fix: advice.fix
|
|
7475
|
+
} : {
|
|
7476
|
+
state: "problem",
|
|
7477
|
+
message: `${message}; ${advice.note}`
|
|
7478
|
+
};
|
|
7479
|
+
}
|
|
7227
7480
|
return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
|
|
7228
7481
|
}
|
|
7229
7482
|
};
|
|
@@ -7254,14 +7507,15 @@ function skillRow(cli) {
|
|
|
7254
7507
|
}
|
|
7255
7508
|
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
7256
7509
|
function doctorChecks(cli, launch, read) {
|
|
7510
|
+
const survey = surveyOnce(launch.bin);
|
|
7257
7511
|
return [
|
|
7258
7512
|
buildRow(cli),
|
|
7259
7513
|
nodeRow(cli),
|
|
7260
7514
|
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
7261
7515
|
...cli.doctor ?? [],
|
|
7262
7516
|
...toolRows(cli.tools ?? [], cli.commands),
|
|
7263
|
-
installRow(cli, launch),
|
|
7264
|
-
registryRow(cli, launch
|
|
7517
|
+
installRow(cli, launch, survey),
|
|
7518
|
+
registryRow(cli, launch, survey),
|
|
7265
7519
|
skillRow(cli)
|
|
7266
7520
|
];
|
|
7267
7521
|
}
|
|
@@ -7592,7 +7846,7 @@ const updateSchema = object({
|
|
|
7592
7846
|
next: array(string())
|
|
7593
7847
|
});
|
|
7594
7848
|
function nothingToInstall({ from, latest }) {
|
|
7595
|
-
return standingOf(from, latest) === "current" ? `already on ${from}, the latest release: nothing to install` : `${from} is newer than the latest release ${latest}: nothing to install`;
|
|
7849
|
+
return standingOf$1(from, latest) === "current" ? `already on ${from}, the latest release: nothing to install` : `${from} is newer than the latest release ${latest}: nothing to install`;
|
|
7596
7850
|
}
|
|
7597
7851
|
function renderUpgrade(upgrade) {
|
|
7598
7852
|
return "steps" in upgrade ? [`\nupgrade steps for ${upgrade.version}:`, ...upgrade.steps.map((step) => `- ${step}`)].join("\n") : `\nchanges in ${upgrade.version}:\n${upgrade.notes}`;
|
|
@@ -7633,7 +7887,7 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
7633
7887
|
effect: "write",
|
|
7634
7888
|
output: updateSchema,
|
|
7635
7889
|
plan: async (_input, ctx) => {
|
|
7636
|
-
const npm =
|
|
7890
|
+
const npm = globalNpm(cli, install, ctx, node);
|
|
7637
7891
|
const copy = await globalInstallOf(bin, npm);
|
|
7638
7892
|
return {
|
|
7639
7893
|
package: install.package,
|
|
@@ -7645,7 +7899,7 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
7645
7899
|
},
|
|
7646
7900
|
apply: async (plan, ctx) => {
|
|
7647
7901
|
const { from, latest, prefix } = plan;
|
|
7648
|
-
if (standingOf(from, latest) !== "behind") return {
|
|
7902
|
+
if (standingOf$1(from, latest) !== "behind") return {
|
|
7649
7903
|
from,
|
|
7650
7904
|
latest,
|
|
7651
7905
|
installed: null,
|
|
@@ -7654,7 +7908,7 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
7654
7908
|
};
|
|
7655
7909
|
ctx.signal.throwIfAborted();
|
|
7656
7910
|
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
7657
|
-
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest,
|
|
7911
|
+
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, globalNpm(cli, install, ctx, node)));
|
|
7658
7912
|
const update = {
|
|
7659
7913
|
from,
|
|
7660
7914
|
latest,
|
|
@@ -7672,16 +7926,16 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
7672
7926
|
return update;
|
|
7673
7927
|
},
|
|
7674
7928
|
render: (update) => renderUpdate(cli, install, update),
|
|
7675
|
-
renderPlan: (plan) => standingOf(plan.from, plan.latest) === "behind" ? `would install ${plan.package}@${plan.latest} with the npm under ${plan.prefix}, replacing ${plan.from}` : nothingToInstall(plan)
|
|
7929
|
+
renderPlan: (plan) => standingOf$1(plan.from, plan.latest) === "behind" ? `would install ${plan.package}@${plan.latest} with the npm under ${plan.prefix}, replacing ${plan.from}` : nothingToInstall(plan)
|
|
7676
7930
|
});
|
|
7677
7931
|
}
|
|
7678
7932
|
//#endregion
|
|
7679
7933
|
//#region ../agent-cli/dist/built-ins/commands.js
|
|
7680
|
-
/** The Commands the Runtime adds to a multi-Command CLI: `update` only
|
|
7934
|
+
/** The Commands the Runtime adds to a multi-Command CLI: `update` only for a Global install. */
|
|
7681
7935
|
function builtInCommands(cli, launch) {
|
|
7682
7936
|
return {
|
|
7683
7937
|
doctor: doctorCommand(cli, launch),
|
|
7684
|
-
...cli.install ===
|
|
7938
|
+
...cli.install?.mode === "global" ? { update: updateCommand(cli, cli.install, launch) } : {}
|
|
7685
7939
|
};
|
|
7686
7940
|
}
|
|
7687
7941
|
//#endregion
|
|
@@ -9421,14 +9675,14 @@ async function runProcess(cli) {
|
|
|
9421
9675
|
}
|
|
9422
9676
|
//#endregion
|
|
9423
9677
|
//#region package.json
|
|
9424
|
-
var version$1 = "0.
|
|
9678
|
+
var version$1 = "0.11.1";
|
|
9425
9679
|
var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
|
|
9426
9680
|
//#endregion
|
|
9427
9681
|
//#region src/build.ts
|
|
9428
9682
|
const build = {
|
|
9429
|
-
"sha": "
|
|
9683
|
+
"sha": "92df9c6",
|
|
9430
9684
|
"dirty": false,
|
|
9431
|
-
"builtAt": "2026-10-
|
|
9685
|
+
"builtAt": "2026-10-22T10:48:39.000Z"
|
|
9432
9686
|
};
|
|
9433
9687
|
//#endregion
|
|
9434
9688
|
//#region src/steps.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duyquangnvx/create-agent-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@duyquangnvx/agent-cli": "0.
|
|
22
|
+
"@duyquangnvx/agent-cli": "0.11.1",
|
|
23
23
|
"tsdown": "0.23.0",
|
|
24
24
|
"zod": "4.6.7"
|
|
25
25
|
},
|