@duyquangnvx/create-agent-cli 0.14.0 → 0.15.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 +18 -0
- package/dist/bin.js +789 -679
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -5869,13 +5869,22 @@ function debugTrace(error, format) {
|
|
|
5869
5869
|
function errorsOf(error) {
|
|
5870
5870
|
return error instanceof AggregateError && error.errors.length > 0 ? error.errors.flatMap(errorsOf) : [error];
|
|
5871
5871
|
}
|
|
5872
|
+
/** The `details` field that `error`'s code declares for text mode to print, when it holds a string. */
|
|
5873
|
+
function printedDetail(error, format) {
|
|
5874
|
+
if (!(error instanceof CliError)) return void 0;
|
|
5875
|
+
const key = format.errors[error.code]?.print;
|
|
5876
|
+
const { details } = error;
|
|
5877
|
+
if (key === void 0 || typeof details !== "object" || details === null) return void 0;
|
|
5878
|
+
const value = Reflect.get(details, key);
|
|
5879
|
+
return typeof value === "string" ? value : void 0;
|
|
5880
|
+
}
|
|
5872
5881
|
function errorLines(error, format) {
|
|
5873
5882
|
const fields = fieldsOf$1(error, format);
|
|
5874
|
-
const
|
|
5883
|
+
const blocks = [printedDetail(error, format), debugTrace(error, format)].filter((block) => block !== void 0);
|
|
5875
5884
|
const { style } = format;
|
|
5876
5885
|
const label = style.red(format.isBug(error) ? "internal error:" : "error:");
|
|
5877
|
-
const
|
|
5878
|
-
return `${label} ${fields.message}\n${
|
|
5886
|
+
const between = blocks.map((block) => `${block}\n`).join("");
|
|
5887
|
+
return `${label} ${fields.message}\n${between}${style.cyan("hint:")} ${fields.hint}\n`;
|
|
5879
5888
|
}
|
|
5880
5889
|
function formatRuntimeError(error, format) {
|
|
5881
5890
|
const errors = errorsOf(error);
|
|
@@ -6487,15 +6496,6 @@ function isCommand(node) {
|
|
|
6487
6496
|
return typeof node.effect === "string";
|
|
6488
6497
|
}
|
|
6489
6498
|
//#endregion
|
|
6490
|
-
//#region ../agent-cli/dist/run-as.js
|
|
6491
|
-
/**
|
|
6492
|
-
* The Run-as: how every command line the Runtime gives its caller starts. A Dependency install runs
|
|
6493
|
-
* the copy the project pins, so it is `npx -q --no-install <bin>`; otherwise the bare name (ADR 0011).
|
|
6494
|
-
*/
|
|
6495
|
-
function runAsOf(cli) {
|
|
6496
|
-
return cli.install?.mode === "dependency" ? `npx -q --no-install ${cli.name}` : cli.name;
|
|
6497
|
-
}
|
|
6498
|
-
//#endregion
|
|
6499
6499
|
//#region ../agent-cli/dist/project.js
|
|
6500
6500
|
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6501
6501
|
function invalid(path, problem, callerLine, options) {
|
|
@@ -6610,6 +6610,69 @@ function versionLine({ version, build }) {
|
|
|
6610
6610
|
return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
|
|
6611
6611
|
}
|
|
6612
6612
|
//#endregion
|
|
6613
|
+
//#region ../agent-cli/dist/project-root.js
|
|
6614
|
+
const MANAGERS = [
|
|
6615
|
+
"pnpm",
|
|
6616
|
+
"npm",
|
|
6617
|
+
"yarn",
|
|
6618
|
+
"bun"
|
|
6619
|
+
];
|
|
6620
|
+
const LOCKFILES = [
|
|
6621
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
6622
|
+
["package-lock.json", "npm"],
|
|
6623
|
+
["yarn.lock", "yarn"],
|
|
6624
|
+
["bun.lock", "bun"],
|
|
6625
|
+
["bun.lockb", "bun"]
|
|
6626
|
+
];
|
|
6627
|
+
const manifestSchema$1 = object({
|
|
6628
|
+
packageManager: string().optional(),
|
|
6629
|
+
dependencies: record(string(), unknown()).optional(),
|
|
6630
|
+
devDependencies: record(string(), unknown()).optional()
|
|
6631
|
+
});
|
|
6632
|
+
/** `dir` and every folder above it, nearest first. */
|
|
6633
|
+
function ancestorsOf(dir) {
|
|
6634
|
+
const parent = dirname(dir);
|
|
6635
|
+
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
6636
|
+
}
|
|
6637
|
+
async function exists(path) {
|
|
6638
|
+
return await orMissing(stat(path)) !== void 0;
|
|
6639
|
+
}
|
|
6640
|
+
/** Whether `path` lies strictly inside `dir`. */
|
|
6641
|
+
function isInside(dir, path) {
|
|
6642
|
+
const inner = relative(dir, path);
|
|
6643
|
+
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
6644
|
+
}
|
|
6645
|
+
async function manifestIn(dir) {
|
|
6646
|
+
let text;
|
|
6647
|
+
try {
|
|
6648
|
+
text = await readFile(join(dir, "package.json"), "utf8");
|
|
6649
|
+
} catch (error) {
|
|
6650
|
+
if (isMissingFile(error)) return void 0;
|
|
6651
|
+
throw error;
|
|
6652
|
+
}
|
|
6653
|
+
let manifest;
|
|
6654
|
+
try {
|
|
6655
|
+
manifest = JSON.parse(text);
|
|
6656
|
+
} catch {
|
|
6657
|
+
return;
|
|
6658
|
+
}
|
|
6659
|
+
return manifestSchema$1.safeParse(manifest).data;
|
|
6660
|
+
}
|
|
6661
|
+
async function declaredManager(dir) {
|
|
6662
|
+
const name = (await manifestIn(dir))?.packageManager?.split("@")[0];
|
|
6663
|
+
return MANAGERS.find((manager) => manager === name);
|
|
6664
|
+
}
|
|
6665
|
+
async function lockfileRootOf(cwd) {
|
|
6666
|
+
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
6667
|
+
dir,
|
|
6668
|
+
manager: await declaredManager(dir) ?? kind
|
|
6669
|
+
};
|
|
6670
|
+
}
|
|
6671
|
+
/** The package manager's project root: the folder of the nearest lockfile, or `cwd` without one. */
|
|
6672
|
+
async function projectRootOf(cwd) {
|
|
6673
|
+
return (await lockfileRootOf(cwd))?.dir ?? cwd;
|
|
6674
|
+
}
|
|
6675
|
+
//#endregion
|
|
6613
6676
|
//#region ../agent-cli/dist/tail.js
|
|
6614
6677
|
/** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
|
|
6615
6678
|
function lastLines(output, count) {
|
|
@@ -6994,7 +7057,6 @@ function npmContext(cli, registry, ctx, node, cwd) {
|
|
|
6994
7057
|
node
|
|
6995
7058
|
};
|
|
6996
7059
|
}
|
|
6997
|
-
const NPMJS = "https://registry.npmjs.org/";
|
|
6998
7060
|
const STDERR_TAIL_LINES = 10;
|
|
6999
7061
|
const RM_RETRIES = 3;
|
|
7000
7062
|
const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
@@ -7013,28 +7075,6 @@ const NPM_CODE = /^npm (?:error|ERR!) code (\S+)$/m;
|
|
|
7013
7075
|
function scopeOf(name) {
|
|
7014
7076
|
return /^(@[^/]+)\//.exec(name)?.[1];
|
|
7015
7077
|
}
|
|
7016
|
-
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
7017
|
-
function registryFlags({ package: name, registry }) {
|
|
7018
|
-
if (registry === NPMJS) return [];
|
|
7019
|
-
const scope = scopeOf(name);
|
|
7020
|
-
return [scope === void 0 ? `--registry=${registry}` : `--${scope}:registry=${registry}`];
|
|
7021
|
-
}
|
|
7022
|
-
/** The registry a Global install declares. */
|
|
7023
|
-
function globalRegistry(install) {
|
|
7024
|
-
const { package: name, registry } = install;
|
|
7025
|
-
return {
|
|
7026
|
-
package: name,
|
|
7027
|
-
label: registry,
|
|
7028
|
-
flags: registryFlags(install),
|
|
7029
|
-
unreachableHint: "check the network or VPN",
|
|
7030
|
-
loginHint: `log in to ${registry} (\`npm login --registry=${registry}\`) or set its token in ~/.npmrc`,
|
|
7031
|
-
missingHint: `check that ${name} is published on ${registry}`
|
|
7032
|
-
};
|
|
7033
|
-
}
|
|
7034
|
-
/** npm for a Global install, run where the CLI was started. */
|
|
7035
|
-
function globalNpm(cli, install, ctx, node) {
|
|
7036
|
-
return npmContext(cli, globalRegistry(install), ctx, node, process.cwd());
|
|
7037
|
-
}
|
|
7038
7078
|
/** The command a person runs to install the CLI globally from its registry. */
|
|
7039
7079
|
function installCommandLine(registry, version = "latest") {
|
|
7040
7080
|
return [
|
|
@@ -7177,62 +7217,13 @@ async function latestVersion(ctx) {
|
|
|
7177
7217
|
return version;
|
|
7178
7218
|
}
|
|
7179
7219
|
//#endregion
|
|
7180
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
7185
|
-
}
|
|
7186
|
-
function notGlobal(ctx, message) {
|
|
7187
|
-
return new CliError({
|
|
7188
|
-
code: NOT_GLOBAL_INSTALL,
|
|
7189
|
-
message,
|
|
7190
|
-
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.registry)}`
|
|
7191
|
-
});
|
|
7192
|
-
}
|
|
7193
|
-
async function realpathOrUndefined(path) {
|
|
7194
|
-
return realpath(path).catch((error) => {
|
|
7195
|
-
if (isMissingFile(error)) return void 0;
|
|
7196
|
-
throw error;
|
|
7197
|
-
});
|
|
7198
|
-
}
|
|
7199
|
-
/** Whether `path` lies strictly inside `dir`. */
|
|
7200
|
-
function isInside(dir, path) {
|
|
7201
|
-
const inner = relative(dir, path);
|
|
7202
|
-
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
7203
|
-
}
|
|
7204
|
-
/**
|
|
7205
|
-
* The global npm install this copy runs from, found by asking npm for its global prefix.
|
|
7206
|
-
* `bin` is the script that started the CLI; throws `NOT_GLOBAL_INSTALL` when it is not inside that install.
|
|
7207
|
-
*/
|
|
7208
|
-
async function globalInstallOf(bin, ctx) {
|
|
7209
|
-
if (bin === void 0) throw notGlobal(ctx, `${ctx.cliName} runs from source, not from an npm install`);
|
|
7210
|
-
const prefix = await globalPrefix(ctx);
|
|
7211
|
-
const packageDir = join(globalModulesDir(prefix), ctx.registry.package);
|
|
7212
|
-
const installed = await realpathOrUndefined(packageDir);
|
|
7213
|
-
const here = await realpathOrUndefined(bin) ?? bin;
|
|
7214
|
-
if (installed === void 0 || !isInside(installed, here)) throw notGlobal(ctx, `${ctx.cliName} runs from ${here}, not from npm's global install at ${packageDir}`);
|
|
7215
|
-
if ((await lstat(packageDir)).isSymbolicLink()) throw notGlobal(ctx, `${ctx.cliName} runs from a link to ${installed} (npm link), not from an npm install`);
|
|
7216
|
-
return {
|
|
7217
|
-
prefix,
|
|
7218
|
-
packageDir
|
|
7219
|
-
};
|
|
7220
|
+
//#region ../agent-cli/dist/built-ins/install/run-as.js
|
|
7221
|
+
/** The Run-as: the bare name, or `npx -q --no-install <bin>` for a Dependency install (ADR 0011). */
|
|
7222
|
+
function runAsOf({ name, install }) {
|
|
7223
|
+
return install?.mode === "dependency" ? `npx -q --no-install ${name}` : name;
|
|
7220
7224
|
}
|
|
7221
7225
|
//#endregion
|
|
7222
|
-
//#region ../agent-cli/dist/built-ins/dependency
|
|
7223
|
-
const MANAGERS = [
|
|
7224
|
-
"pnpm",
|
|
7225
|
-
"npm",
|
|
7226
|
-
"yarn",
|
|
7227
|
-
"bun"
|
|
7228
|
-
];
|
|
7229
|
-
const LOCKFILES = [
|
|
7230
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
7231
|
-
["package-lock.json", "npm"],
|
|
7232
|
-
["yarn.lock", "yarn"],
|
|
7233
|
-
["bun.lock", "bun"],
|
|
7234
|
-
["bun.lockb", "bun"]
|
|
7235
|
-
];
|
|
7226
|
+
//#region ../agent-cli/dist/built-ins/install/dependency.js
|
|
7236
7227
|
const LINES = {
|
|
7237
7228
|
pnpm: {
|
|
7238
7229
|
upgrade: (packages) => `pnpm up --latest ${packages.join(" ")}`,
|
|
@@ -7245,46 +7236,7 @@ const LINES = {
|
|
|
7245
7236
|
install: "npm install"
|
|
7246
7237
|
}
|
|
7247
7238
|
};
|
|
7248
|
-
const manifestSchema$1 = object({
|
|
7249
|
-
packageManager: string().optional(),
|
|
7250
|
-
dependencies: record(string(), unknown()).optional(),
|
|
7251
|
-
devDependencies: record(string(), unknown()).optional()
|
|
7252
|
-
});
|
|
7253
7239
|
const packageSchema = object({ version: string() });
|
|
7254
|
-
/** `dir` and every folder above it, nearest first. */
|
|
7255
|
-
function ancestorsOf(dir) {
|
|
7256
|
-
const parent = dirname(dir);
|
|
7257
|
-
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
7258
|
-
}
|
|
7259
|
-
async function exists(path) {
|
|
7260
|
-
try {
|
|
7261
|
-
await stat(path);
|
|
7262
|
-
return true;
|
|
7263
|
-
} catch (error) {
|
|
7264
|
-
if (isMissingFile(error)) return false;
|
|
7265
|
-
throw error;
|
|
7266
|
-
}
|
|
7267
|
-
}
|
|
7268
|
-
async function manifestIn(dir) {
|
|
7269
|
-
let text;
|
|
7270
|
-
try {
|
|
7271
|
-
text = await readFile(join(dir, "package.json"), "utf8");
|
|
7272
|
-
} catch (error) {
|
|
7273
|
-
if (isMissingFile(error)) return void 0;
|
|
7274
|
-
throw error;
|
|
7275
|
-
}
|
|
7276
|
-
let manifest;
|
|
7277
|
-
try {
|
|
7278
|
-
manifest = JSON.parse(text);
|
|
7279
|
-
} catch {
|
|
7280
|
-
return;
|
|
7281
|
-
}
|
|
7282
|
-
return manifestSchema$1.safeParse(manifest).data;
|
|
7283
|
-
}
|
|
7284
|
-
async function declaredManager(dir) {
|
|
7285
|
-
const name = (await manifestIn(dir))?.packageManager?.split("@")[0];
|
|
7286
|
-
return MANAGERS.find((manager) => manager === name);
|
|
7287
|
-
}
|
|
7288
7240
|
async function manifestListing(name, cwd, root) {
|
|
7289
7241
|
const dirs = ancestorsOf(cwd);
|
|
7290
7242
|
const top = root === void 0 ? dirs.length : dirs.indexOf(root.dir) + 1;
|
|
@@ -7293,16 +7245,6 @@ async function manifestListing(name, cwd, root) {
|
|
|
7293
7245
|
if (manifest?.dependencies?.[name] !== void 0 || manifest?.devDependencies?.[name] !== void 0) return join(dir, "package.json");
|
|
7294
7246
|
}
|
|
7295
7247
|
}
|
|
7296
|
-
async function lockfileRootOf(cwd) {
|
|
7297
|
-
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
7298
|
-
dir,
|
|
7299
|
-
manager: await declaredManager(dir) ?? kind
|
|
7300
|
-
};
|
|
7301
|
-
}
|
|
7302
|
-
/** The package manager's project root: the folder of the nearest lockfile, or `cwd` without one. */
|
|
7303
|
-
async function projectRootOf(cwd) {
|
|
7304
|
-
return (await lockfileRootOf(cwd))?.dir ?? cwd;
|
|
7305
|
-
}
|
|
7306
7248
|
async function versionIn(manifest) {
|
|
7307
7249
|
try {
|
|
7308
7250
|
return packageSchema.parse(JSON.parse(await readFile(manifest, "utf8"))).version;
|
|
@@ -7332,10 +7274,7 @@ async function standingOf(install, bin, cwd, root) {
|
|
|
7332
7274
|
kind: "linked",
|
|
7333
7275
|
copy
|
|
7334
7276
|
};
|
|
7335
|
-
const runningFrom = await realpath(bin)
|
|
7336
|
-
if (isMissingFile(error)) return bin;
|
|
7337
|
-
throw error;
|
|
7338
|
-
});
|
|
7277
|
+
const runningFrom = await orMissing(realpath(bin)) ?? bin;
|
|
7339
7278
|
return isInside(copy.realDir, runningFrom) ? {
|
|
7340
7279
|
kind: "installed",
|
|
7341
7280
|
copy
|
|
@@ -7386,7 +7325,7 @@ function problem(message, fix) {
|
|
|
7386
7325
|
};
|
|
7387
7326
|
}
|
|
7388
7327
|
/** The `install` row of a Dependency install. */
|
|
7389
|
-
function
|
|
7328
|
+
function installFinding(cli, runAs, install, { cwd, root, standing }) {
|
|
7390
7329
|
const lines = root === void 0 ? void 0 : LINES[root.manager];
|
|
7391
7330
|
switch (standing.kind) {
|
|
7392
7331
|
case "source":
|
|
@@ -7396,7 +7335,7 @@ function dependencyInstallFinding(cli, install, { cwd, root, standing }) {
|
|
|
7396
7335
|
case "unreadable": return problem(`${standing.manifest} is not a package.json with a version: ${standing.reason}`, lines?.install);
|
|
7397
7336
|
case "other": {
|
|
7398
7337
|
const { copy, runningFrom } = standing;
|
|
7399
|
-
return problem(`${cli.name} runs from ${runningFrom}, not from this project's ${install.package} ${copy.version} at ${copy.realDir}`, `${
|
|
7338
|
+
return problem(`${cli.name} runs from ${runningFrom}, not from this project's ${install.package} ${copy.version} at ${copy.realDir}`, `${runAs} doctor`);
|
|
7400
7339
|
}
|
|
7401
7340
|
case "installed": {
|
|
7402
7341
|
const { copy } = standing;
|
|
@@ -7426,16 +7365,37 @@ function adviceFor(install, root, latest) {
|
|
|
7426
7365
|
if (lines !== void 0) return { fix: lines.upgrade(packages) };
|
|
7427
7366
|
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"}` };
|
|
7428
7367
|
}
|
|
7429
|
-
function
|
|
7430
|
-
|
|
7368
|
+
function checkOf$1(cli, install, runAs, { bin, node }) {
|
|
7369
|
+
let survey;
|
|
7370
|
+
const surveyed = (cwd) => {
|
|
7371
|
+
survey ??= surveyDependency(install, bin, cwd);
|
|
7372
|
+
return survey;
|
|
7373
|
+
};
|
|
7374
|
+
return {
|
|
7375
|
+
install: async (ctx) => installFinding(cli, runAs, install, await surveyed(ctx.cwd)),
|
|
7376
|
+
release: async (ctx) => {
|
|
7377
|
+
const { cwd, root, standing } = await surveyed(ctx.cwd);
|
|
7378
|
+
if (isUnchecked(standing)) return { skipped: skippedFor(cli, install, standing) };
|
|
7379
|
+
return {
|
|
7380
|
+
npm: npmContext(cli, registryOf(install, root?.dir), ctx, node, root?.dir ?? cwd),
|
|
7381
|
+
advise: (latest) => adviceFor(install, root, latest)
|
|
7382
|
+
};
|
|
7383
|
+
}
|
|
7384
|
+
};
|
|
7385
|
+
}
|
|
7386
|
+
/** The Install of a CLI each project pins as a dependency, run through npx (ADR 0011). */
|
|
7387
|
+
function dependencyInstall(cli, install) {
|
|
7388
|
+
const runAs = runAsOf(cli);
|
|
7431
7389
|
return {
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7390
|
+
runAs,
|
|
7391
|
+
builtIns: () => ({}),
|
|
7392
|
+
exitClasses: [],
|
|
7393
|
+
agentsCaveat: `and only from a package that has \`${install.package}\` in its dependencies; from anywhere else npx reports the package missing`,
|
|
7394
|
+
check: (launch) => checkOf$1(cli, install, runAs, launch)
|
|
7435
7395
|
};
|
|
7436
7396
|
}
|
|
7437
7397
|
//#endregion
|
|
7438
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7398
|
+
//#region ../agent-cli/dist/built-ins/skill/hub.js
|
|
7439
7399
|
const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
|
|
7440
7400
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
7441
7401
|
const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
|
|
@@ -7493,411 +7453,123 @@ function fixFor(cliName, copies, source) {
|
|
|
7493
7453
|
if (has("unversioned") && add !== void 0) return has("behind") ? `${update} && ${add}` : add;
|
|
7494
7454
|
return has("behind") || has("unversioned") ? update : void 0;
|
|
7495
7455
|
}
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7456
|
+
const SKILL_STATE_NOTES = {
|
|
7457
|
+
current: "the same as this build",
|
|
7458
|
+
behind: "older than this build",
|
|
7459
|
+
ahead: "newer than this build",
|
|
7460
|
+
unversioned: "states no metadata.version",
|
|
7461
|
+
unreadable: "could not be read"
|
|
7462
|
+
};
|
|
7463
|
+
function describeCopy({ path, version, state }) {
|
|
7464
|
+
return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
|
|
7465
|
+
}
|
|
7466
|
+
/** A skill that `npx skills add` installs from `source`, the Skill Hub; with no `source`, no line adds it. */
|
|
7467
|
+
function hubSkill(cli, source) {
|
|
7468
|
+
const findingAt = async (version, ctx) => {
|
|
7469
|
+
const copies = await skillCopies(cli.name, version, ctx);
|
|
7470
|
+
const fix = fixFor(cli.name, copies, source);
|
|
7471
|
+
const message = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
|
|
7472
|
+
return fix === void 0 ? {
|
|
7473
|
+
state: "ok",
|
|
7474
|
+
message
|
|
7475
|
+
} : {
|
|
7476
|
+
state: "ok",
|
|
7477
|
+
message,
|
|
7478
|
+
fix
|
|
7479
|
+
};
|
|
7480
|
+
};
|
|
7499
7481
|
return {
|
|
7500
|
-
|
|
7501
|
-
|
|
7482
|
+
kind: "hub",
|
|
7483
|
+
builtIns: {},
|
|
7484
|
+
rows: [{
|
|
7485
|
+
name: "skill",
|
|
7486
|
+
advisory: true,
|
|
7487
|
+
run: (ctx) => findingAt(cli.version, ctx)
|
|
7488
|
+
}],
|
|
7489
|
+
notice: async () => {},
|
|
7490
|
+
findingAt
|
|
7502
7491
|
};
|
|
7503
7492
|
}
|
|
7504
7493
|
//#endregion
|
|
7505
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7506
|
-
/**
|
|
7507
|
-
function
|
|
7508
|
-
|
|
7494
|
+
//#region ../agent-cli/dist/built-ins/agents-md.js
|
|
7495
|
+
/** One paragraph telling every session that the CLI exists, how to run it and which skill to load. */
|
|
7496
|
+
function agentsBlock(cli, { runAs, agentsCaveat }) {
|
|
7497
|
+
const what = cli.description.replace(/\.$/, "");
|
|
7498
|
+
const run = `Run it as \`${runAs}\`${agentsCaveat === void 0 ? "" : `, ${agentsCaveat}`}`;
|
|
7499
|
+
return `\`${cli.name}\`: ${what}. ${run}. Load the \`${cli.name}\` skill before using it.`;
|
|
7509
7500
|
}
|
|
7510
|
-
|
|
7511
|
-
async function skillCopyOf(cli, cwd) {
|
|
7512
|
-
const root = await projectRootOf(cwd);
|
|
7501
|
+
function markersOf(name) {
|
|
7513
7502
|
return {
|
|
7514
|
-
|
|
7515
|
-
|
|
7503
|
+
begin: `<!-- BEGIN:${name} -->`,
|
|
7504
|
+
end: `<!-- END:${name} -->`
|
|
7516
7505
|
};
|
|
7517
7506
|
}
|
|
7518
|
-
/**
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7507
|
+
/** `text` with the CLI's block between its markers, appended when they are missing; nothing else changes. */
|
|
7508
|
+
function withBlock(cli, install, text) {
|
|
7509
|
+
const { begin, end } = markersOf(cli.name);
|
|
7510
|
+
const whole = `${begin}\n${agentsBlock(cli, install)}\n${end}`;
|
|
7511
|
+
const start = text.indexOf(begin);
|
|
7512
|
+
const stop = start === -1 ? -1 : text.indexOf(end, start);
|
|
7513
|
+
if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
|
|
7514
|
+
if (text === "") return `${whole}\n`;
|
|
7515
|
+
return `${text}${text.endsWith("\n") ? "" : "\n"}\n${whole}\n`;
|
|
7524
7516
|
}
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
const
|
|
7528
|
-
const
|
|
7529
|
-
|
|
7517
|
+
async function agentsMdAt(cli, install, root) {
|
|
7518
|
+
const path = join(root, "AGENTS.md");
|
|
7519
|
+
const existing = await orMissing(readFile(path, "utf8"));
|
|
7520
|
+
const block = agentsBlock(cli, install);
|
|
7521
|
+
if (existing === void 0) return {
|
|
7522
|
+
path,
|
|
7523
|
+
block,
|
|
7524
|
+
change: "create"
|
|
7525
|
+
};
|
|
7526
|
+
if (withBlock(cli, install, existing) === existing) return {
|
|
7527
|
+
path,
|
|
7528
|
+
block,
|
|
7529
|
+
change: null
|
|
7530
|
+
};
|
|
7530
7531
|
return {
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7532
|
+
path,
|
|
7533
|
+
block,
|
|
7534
|
+
change: existing.includes(markersOf(cli.name).begin) ? "rewrite" : "add"
|
|
7534
7535
|
};
|
|
7535
7536
|
}
|
|
7536
|
-
async function
|
|
7537
|
-
const
|
|
7538
|
-
const
|
|
7539
|
-
|
|
7537
|
+
async function handEditsAt(root) {
|
|
7538
|
+
const claudeMd = join(root, "CLAUDE.md");
|
|
7539
|
+
const text = await orMissing(readFile(claudeMd, "utf8"));
|
|
7540
|
+
if (text === void 0 || text.split(/\r?\n/).some((line) => line.trim() === "@AGENTS.md")) return [];
|
|
7541
|
+
return [`add a line \`@AGENTS.md\` to ${claudeMd}, so Claude Code reads AGENTS.md`];
|
|
7540
7542
|
}
|
|
7541
|
-
|
|
7542
|
-
const packagedSkillDetailsSchema = object({
|
|
7543
|
-
copy: string(),
|
|
7544
|
-
copyVersion: string().nullable(),
|
|
7545
|
-
packageVersion: string().nullable(),
|
|
7546
|
-
/** A personal copy, which Claude Code prefers over the project's. */
|
|
7547
|
-
home: string().optional()
|
|
7548
|
-
});
|
|
7549
|
-
function versionLabel(version) {
|
|
7550
|
-
return version ?? "(no metadata.version)";
|
|
7551
|
-
}
|
|
7552
|
-
function compared(name, { copy, copyVersion, packageVersion }, same) {
|
|
7553
|
-
const stated = `${copy} ${versionLabel(copyVersion)}`;
|
|
7554
|
-
return same ? `${stated}, the version ${name} ships` : `${stated} differs from the ${versionLabel(packageVersion)} that ${name} ships`;
|
|
7555
|
-
}
|
|
7556
|
-
/** The `skill` row of a Packaged skill: the project root's copy against the package's, and any under home. */
|
|
7557
|
-
async function packagedSkillFinding(cli, folder, ctx) {
|
|
7558
|
-
const { copy } = await skillCopyOf(cli, ctx.cwd);
|
|
7559
|
-
const versions = await skillVersionsOf(join(ctx.packageRoot, folder), copy);
|
|
7560
|
-
const { packageVersion } = versions;
|
|
7561
|
-
const copyVersion = versions.copyVersion ?? null;
|
|
7562
|
-
const home = await personalCopyOf(cli.name, copy, ctx);
|
|
7563
|
-
const skill = {
|
|
7564
|
-
copy,
|
|
7565
|
-
copyVersion,
|
|
7566
|
-
packageVersion,
|
|
7567
|
-
...home === void 0 ? {} : { home }
|
|
7568
|
-
};
|
|
7569
|
-
const head = versions.copyVersion === void 0 ? `no copy of the ${cli.name} skill at ${copy}` : compared(cli.name, skill, versions.same);
|
|
7570
|
-
const message = home === void 0 ? head : `${head}; remove ${home}: Claude Code prefers a personal skill over the project's`;
|
|
7571
|
-
if (!versions.same) return {
|
|
7572
|
-
state: "problem",
|
|
7573
|
-
message,
|
|
7574
|
-
fix: `${runAsOf(cli)} skill install`,
|
|
7575
|
-
skill
|
|
7576
|
-
};
|
|
7577
|
-
return home === void 0 ? {
|
|
7578
|
-
state: "ok",
|
|
7579
|
-
message,
|
|
7580
|
-
skill
|
|
7581
|
-
} : {
|
|
7582
|
-
state: "problem",
|
|
7583
|
-
message,
|
|
7584
|
-
skill
|
|
7585
|
-
};
|
|
7586
|
-
}
|
|
7587
|
-
//#endregion
|
|
7588
|
-
//#region ../agent-cli/dist/built-ins/doctor-rows.js
|
|
7589
|
-
function ok(message) {
|
|
7590
|
-
return {
|
|
7591
|
-
state: "ok",
|
|
7592
|
-
message
|
|
7593
|
-
};
|
|
7594
|
-
}
|
|
7595
|
-
function noInstall(cli) {
|
|
7596
|
-
return {
|
|
7597
|
-
state: "skipped",
|
|
7598
|
-
message: `not checked: ${cli.name} declares no install`
|
|
7599
|
-
};
|
|
7600
|
-
}
|
|
7601
|
-
function buildRow(cli) {
|
|
7543
|
+
function agentsRow(cli, install) {
|
|
7602
7544
|
return {
|
|
7603
|
-
name: "
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
run: () => {
|
|
7611
|
-
const found = process.versions.node;
|
|
7612
|
-
const range = cli.engines?.node;
|
|
7613
|
-
if (range === void 0) return ok(`Node ${found}; ${cli.name} declares no engines.node to check it against`);
|
|
7614
|
-
const minimum = engineMinimum(range);
|
|
7615
|
-
if (minimum === void 0) return {
|
|
7545
|
+
name: "agents",
|
|
7546
|
+
advisory: true,
|
|
7547
|
+
run: async (ctx) => {
|
|
7548
|
+
const root = await projectRootOf(ctx.cwd);
|
|
7549
|
+
const { path, change } = await agentsMdAt(cli, install, root);
|
|
7550
|
+
const fix = `${install.runAs} skill install`;
|
|
7551
|
+
if (change === "rewrite") return {
|
|
7616
7552
|
state: "problem",
|
|
7617
|
-
message: `${
|
|
7553
|
+
message: `${path} holds a ${cli.name} block other than the one ${fix} writes`,
|
|
7554
|
+
fix
|
|
7618
7555
|
};
|
|
7619
|
-
if (
|
|
7620
|
-
const major = minimum[0];
|
|
7621
|
-
return {
|
|
7556
|
+
if (change !== null) return {
|
|
7622
7557
|
state: "problem",
|
|
7623
|
-
message: `${
|
|
7624
|
-
fix
|
|
7558
|
+
message: `${path} holds no ${cli.name} block, so sessions in this repo do not know ${cli.name}`,
|
|
7559
|
+
fix
|
|
7625
7560
|
};
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
/** A row's thrown error as its problem: a `CliError` with its hint and code, anything else a bug. */
|
|
7630
|
-
function problemOfError(name, error) {
|
|
7631
|
-
if (error instanceof CliError) return {
|
|
7632
|
-
state: "problem",
|
|
7633
|
-
message: `${error.message}; ${error.hint}`,
|
|
7634
|
-
code: error.code
|
|
7635
|
-
};
|
|
7636
|
-
return {
|
|
7637
|
-
state: "problem",
|
|
7638
|
-
message: `the ${name} row hit a bug: ${messageOf(error)}`
|
|
7639
|
-
};
|
|
7640
|
-
}
|
|
7641
|
-
function readProject(projectFile, ctx) {
|
|
7642
|
-
if (projectFile === void 0) return {
|
|
7643
|
-
ok: true,
|
|
7644
|
-
project: void 0
|
|
7645
|
-
};
|
|
7646
|
-
try {
|
|
7647
|
-
return {
|
|
7648
|
-
ok: true,
|
|
7649
|
-
project: projectOf(projectFile, ctx.cwd, {
|
|
7650
|
-
fileError: ctx.fileError,
|
|
7651
|
-
callerLine: ctx.commandLine()
|
|
7652
|
-
})
|
|
7653
|
-
};
|
|
7654
|
-
} catch (error) {
|
|
7655
|
-
return {
|
|
7656
|
-
ok: false,
|
|
7657
|
-
error
|
|
7658
|
-
};
|
|
7659
|
-
}
|
|
7660
|
-
}
|
|
7661
|
-
function projectRow({ file }, read) {
|
|
7662
|
-
return {
|
|
7663
|
-
name: "project",
|
|
7664
|
-
run: (ctx) => {
|
|
7665
|
-
if (!read.ok) return problemOfError("project", read.error);
|
|
7666
|
-
return ok(read.project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(read.project.root, file));
|
|
7667
|
-
}
|
|
7668
|
-
};
|
|
7669
|
-
}
|
|
7670
|
-
function surveyOnce(bin) {
|
|
7671
|
-
let survey;
|
|
7672
|
-
return (install, cwd) => {
|
|
7673
|
-
survey ??= surveyDependency(install, bin, cwd);
|
|
7674
|
-
return survey;
|
|
7675
|
-
};
|
|
7676
|
-
}
|
|
7677
|
-
function installRow(cli, { bin, node }, survey) {
|
|
7678
|
-
return {
|
|
7679
|
-
name: "install",
|
|
7680
|
-
advisory: true,
|
|
7681
|
-
run: async (ctx) => {
|
|
7682
|
-
const { install } = cli;
|
|
7683
|
-
if (install === void 0) return noInstall(cli);
|
|
7684
|
-
if (install.mode === "dependency") return dependencyInstallFinding(cli, install, await survey(install, ctx.cwd));
|
|
7685
|
-
const npm = globalNpm(cli, install, ctx, node);
|
|
7686
|
-
try {
|
|
7687
|
-
return ok(`a global npm install under ${(await globalInstallOf(bin, npm)).prefix}`);
|
|
7688
|
-
} catch (error) {
|
|
7689
|
-
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
7690
|
-
state: "problem",
|
|
7691
|
-
message: error.message,
|
|
7692
|
-
fix: installCommandLine(npm.registry)
|
|
7693
|
-
};
|
|
7694
|
-
throw error;
|
|
7695
|
-
}
|
|
7696
|
-
}
|
|
7697
|
-
};
|
|
7698
|
-
}
|
|
7699
|
-
async function releaseLookupOf(cli, install, ctx, node, survey) {
|
|
7700
|
-
if (install.mode === "global") {
|
|
7701
|
-
const fix = `${cli.name} update`;
|
|
7702
|
-
return {
|
|
7703
|
-
npm: globalNpm(cli, install, ctx, node),
|
|
7704
|
-
advise: () => ({ fix })
|
|
7705
|
-
};
|
|
7706
|
-
}
|
|
7707
|
-
const release = dependencyRelease(cli, install, await survey(install, ctx.cwd));
|
|
7708
|
-
if ("skipped" in release) return release;
|
|
7709
|
-
return {
|
|
7710
|
-
npm: npmContext(cli, release.registry, ctx, node, release.cwd),
|
|
7711
|
-
advise: release.advise
|
|
7712
|
-
};
|
|
7713
|
-
}
|
|
7714
|
-
function registryRow(cli, { node }, survey) {
|
|
7715
|
-
return {
|
|
7716
|
-
name: "registry",
|
|
7717
|
-
advisory: true,
|
|
7718
|
-
run: async (ctx) => {
|
|
7719
|
-
const { install } = cli;
|
|
7720
|
-
if (install === void 0) return noInstall(cli);
|
|
7721
|
-
const lookup = await releaseLookupOf(cli, install, ctx, node, survey);
|
|
7722
|
-
if ("skipped" in lookup) return lookup.skipped;
|
|
7723
|
-
const { npm, advise } = lookup;
|
|
7724
|
-
const latest = await latestVersion(npm);
|
|
7725
|
-
const standing = standingOf$1(cli.version, latest);
|
|
7726
|
-
const head = `${npm.registry.label} has ${latest} as latest: this build`;
|
|
7727
|
-
if (standing === "behind") {
|
|
7728
|
-
const message = `${head} (${cli.version}) is older`;
|
|
7729
|
-
const advice = advise(latest);
|
|
7730
|
-
return "fix" in advice ? {
|
|
7731
|
-
state: "problem",
|
|
7732
|
-
message,
|
|
7733
|
-
fix: advice.fix
|
|
7734
|
-
} : {
|
|
7735
|
-
state: "problem",
|
|
7736
|
-
message: `${message}; ${advice.note}`
|
|
7737
|
-
};
|
|
7738
|
-
}
|
|
7739
|
-
return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
|
|
7740
|
-
}
|
|
7741
|
-
};
|
|
7742
|
-
}
|
|
7743
|
-
const SKILL_STATE_NOTES = {
|
|
7744
|
-
current: "the same as this build",
|
|
7745
|
-
behind: "older than this build",
|
|
7746
|
-
ahead: "newer than this build",
|
|
7747
|
-
unversioned: "states no metadata.version",
|
|
7748
|
-
unreadable: "could not be read"
|
|
7749
|
-
};
|
|
7750
|
-
function describeCopy({ path, version, state }) {
|
|
7751
|
-
return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
|
|
7752
|
-
}
|
|
7753
|
-
function skillRow(cli) {
|
|
7754
|
-
const packaged = packagedFolderOf(cli);
|
|
7755
|
-
return {
|
|
7756
|
-
name: "skill",
|
|
7757
|
-
advisory: true,
|
|
7758
|
-
run: async (ctx) => {
|
|
7759
|
-
if (packaged !== void 0) return packagedSkillFinding(cli, packaged, ctx);
|
|
7760
|
-
const { copies, fix } = await skillReport(cli, cli.version, ctx);
|
|
7761
|
-
const message = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
|
|
7762
|
-
return fix === void 0 ? ok(message) : {
|
|
7561
|
+
const holds = `${path} holds the ${cli.name} block`;
|
|
7562
|
+
const [edit] = await handEditsAt(root);
|
|
7563
|
+
return edit === void 0 ? {
|
|
7763
7564
|
state: "ok",
|
|
7764
|
-
message
|
|
7765
|
-
|
|
7565
|
+
message: holds
|
|
7566
|
+
} : {
|
|
7567
|
+
state: "problem",
|
|
7568
|
+
message: `${holds}; ${edit}`
|
|
7766
7569
|
};
|
|
7767
7570
|
}
|
|
7768
7571
|
};
|
|
7769
7572
|
}
|
|
7770
|
-
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
7771
|
-
function doctorChecks(cli, launch, read) {
|
|
7772
|
-
const survey = surveyOnce(launch.bin);
|
|
7773
|
-
return [
|
|
7774
|
-
buildRow(cli),
|
|
7775
|
-
nodeRow(cli),
|
|
7776
|
-
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
7777
|
-
...cli.doctor ?? [],
|
|
7778
|
-
...toolRows(cli.tools ?? [], cli.commands),
|
|
7779
|
-
installRow(cli, launch, survey),
|
|
7780
|
-
registryRow(cli, launch, survey),
|
|
7781
|
-
skillRow(cli)
|
|
7782
|
-
];
|
|
7783
|
-
}
|
|
7784
|
-
//#endregion
|
|
7785
|
-
//#region ../agent-cli/dist/built-ins/doctor.js
|
|
7786
|
-
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
7787
|
-
const DEFAULT_DEADLINE_MS = 1e4;
|
|
7788
|
-
const MS_PER_SECOND = 1e3;
|
|
7789
|
-
const MIN_LABEL_WIDTH = 8;
|
|
7790
|
-
const reportSchema = object({
|
|
7791
|
-
rows: array(object({
|
|
7792
|
-
check: string(),
|
|
7793
|
-
state: _enum([
|
|
7794
|
-
"ok",
|
|
7795
|
-
"problem",
|
|
7796
|
-
"skipped"
|
|
7797
|
-
]),
|
|
7798
|
-
message: string(),
|
|
7799
|
-
fix: string().optional(),
|
|
7800
|
-
code: string().optional(),
|
|
7801
|
-
skill: packagedSkillDetailsSchema.optional()
|
|
7802
|
-
})),
|
|
7803
|
-
next: array(string())
|
|
7804
|
-
});
|
|
7805
|
-
function problemOf(check, error, { signal, deadline, ms }) {
|
|
7806
|
-
if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
|
|
7807
|
-
state: "problem",
|
|
7808
|
-
message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
|
|
7809
|
-
};
|
|
7810
|
-
return problemOfError(check.name, error);
|
|
7811
|
-
}
|
|
7812
|
-
function rowContext(ctx, signal, read) {
|
|
7813
|
-
return Object.create(ctx, {
|
|
7814
|
-
signal: { value: signal },
|
|
7815
|
-
project: { get: () => {
|
|
7816
|
-
if (!read.ok) throw read.error;
|
|
7817
|
-
return read.project;
|
|
7818
|
-
} }
|
|
7819
|
-
});
|
|
7820
|
-
}
|
|
7821
|
-
async function rowOf(check, ctx, read) {
|
|
7822
|
-
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
7823
|
-
const signal = ctx.deadline(ms);
|
|
7824
|
-
let finding;
|
|
7825
|
-
try {
|
|
7826
|
-
finding = await Promise.race([Promise.resolve().then(() => check.run(rowContext(ctx, signal, read))), untilAborted(signal)]);
|
|
7827
|
-
} catch (error) {
|
|
7828
|
-
if (ctx.signal.aborted) return void 0;
|
|
7829
|
-
finding = !read.ok && error === read.error ? {
|
|
7830
|
-
state: "skipped",
|
|
7831
|
-
message: "the Project file is unusable; the project row says why"
|
|
7832
|
-
} : problemOf(check, error, {
|
|
7833
|
-
signal: ctx.signal,
|
|
7834
|
-
deadline: signal,
|
|
7835
|
-
ms
|
|
7836
|
-
});
|
|
7837
|
-
}
|
|
7838
|
-
return {
|
|
7839
|
-
row: {
|
|
7840
|
-
check: check.name,
|
|
7841
|
-
...finding
|
|
7842
|
-
},
|
|
7843
|
-
advisory: check.advisory === true
|
|
7844
|
-
};
|
|
7845
|
-
}
|
|
7846
|
-
function nextOf(rows) {
|
|
7847
|
-
return [...new Set(rows.flatMap(({ fix }) => fix === void 0 ? [] : [fix]))];
|
|
7848
|
-
}
|
|
7849
|
-
function render({ rows, next }, style) {
|
|
7850
|
-
const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
|
|
7851
|
-
const stateWidth = Math.max(...rows.map(({ state }) => state.length)) + 2;
|
|
7852
|
-
return [...rows.map(({ check, state, message }) => {
|
|
7853
|
-
const label = state === "problem" ? style.red(state) : state;
|
|
7854
|
-
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
7855
|
-
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
7856
|
-
}
|
|
7857
|
-
function failure(cliName, callerLine, problems) {
|
|
7858
|
-
const errors = problems.map(({ check, message, fix, code }) => new CliError({
|
|
7859
|
-
code: code ?? "DOCTOR_PROBLEMS",
|
|
7860
|
-
message: `${cliName} doctor found a problem in ${check}: ${message}`,
|
|
7861
|
-
hint: fix === void 0 ? "the row says what is wrong" : `run \`${fix}\`, then run \`${callerLine}\` again`
|
|
7862
|
-
}));
|
|
7863
|
-
return new AggregateError(errors);
|
|
7864
|
-
}
|
|
7865
|
-
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
7866
|
-
function doctorCommand(cli, launch) {
|
|
7867
|
-
return defineCommand$1({
|
|
7868
|
-
name: "doctor",
|
|
7869
|
-
description: "check the setup and say what fixes each problem",
|
|
7870
|
-
examples: [{
|
|
7871
|
-
command: `${runAsOf(cli)} doctor`,
|
|
7872
|
-
note: "check the setup and list the commands that fix it"
|
|
7873
|
-
}, {
|
|
7874
|
-
command: `${runAsOf(cli)} doctor --json`,
|
|
7875
|
-
note: "get the rows and fixes as data"
|
|
7876
|
-
}],
|
|
7877
|
-
effect: "read",
|
|
7878
|
-
output: reportSchema,
|
|
7879
|
-
run: async (_input, ctx) => {
|
|
7880
|
-
const read = readProject(cli.project, ctx);
|
|
7881
|
-
const checked = (await Promise.all(doctorChecks(cli, launch, read).map((check) => rowOf(check, ctx, read)))).filter((row) => row !== void 0);
|
|
7882
|
-
const rows = checked.map(({ row }) => row);
|
|
7883
|
-
const report = {
|
|
7884
|
-
rows,
|
|
7885
|
-
next: nextOf(rows)
|
|
7886
|
-
};
|
|
7887
|
-
if (ctx.signal.aborted) {
|
|
7888
|
-
ctx.deliver(report);
|
|
7889
|
-
ctx.signal.throwIfAborted();
|
|
7890
|
-
}
|
|
7891
|
-
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
7892
|
-
if (problems.length > 0) {
|
|
7893
|
-
ctx.deliver(report);
|
|
7894
|
-
throw failure(cli.name, ctx.commandLine(), problems);
|
|
7895
|
-
}
|
|
7896
|
-
return report;
|
|
7897
|
-
},
|
|
7898
|
-
render
|
|
7899
|
-
});
|
|
7900
|
-
}
|
|
7901
7573
|
//#endregion
|
|
7902
7574
|
//#region ../agent-cli/dist/agent.js
|
|
7903
7575
|
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
@@ -8230,7 +7902,33 @@ async function probeOutputs({ files, cwd, fileError }, outputs) {
|
|
|
8230
7902
|
}));
|
|
8231
7903
|
}
|
|
8232
7904
|
//#endregion
|
|
8233
|
-
//#region ../agent-cli/dist/built-ins/skill-
|
|
7905
|
+
//#region ../agent-cli/dist/built-ins/skill/install-command.js
|
|
7906
|
+
/** The project root and the Skill copy under it, as `skill install` writes it. */
|
|
7907
|
+
async function skillCopyOf(cli, cwd) {
|
|
7908
|
+
const root = await projectRootOf(cwd);
|
|
7909
|
+
return {
|
|
7910
|
+
root,
|
|
7911
|
+
copy: join(root, ".claude", "skills", cli.name)
|
|
7912
|
+
};
|
|
7913
|
+
}
|
|
7914
|
+
/** Every file under `dir`, relative to it and sorted; none when `dir` is missing. */
|
|
7915
|
+
async function filesIn(dir) {
|
|
7916
|
+
return (await orMissing(readdir(dir, {
|
|
7917
|
+
recursive: true,
|
|
7918
|
+
withFileTypes: true
|
|
7919
|
+
})) ?? []).filter((entry) => entry.isFile()).map((entry) => relative(dir, join(entry.parentPath, entry.name))).sort();
|
|
7920
|
+
}
|
|
7921
|
+
/** The versions of the package's skill in `source` and of its copy in `copy`. */
|
|
7922
|
+
async function skillVersionsOf(source, copy) {
|
|
7923
|
+
const [shipped, installed] = await Promise.all([readFile(join(source, "SKILL.md"), "utf8"), orMissing(readFile(join(copy, "SKILL.md"), "utf8"))]);
|
|
7924
|
+
const packageVersion = skillVersionIn(shipped) ?? null;
|
|
7925
|
+
const copyVersion = installed === void 0 ? void 0 : skillVersionIn(installed) ?? null;
|
|
7926
|
+
return {
|
|
7927
|
+
packageVersion,
|
|
7928
|
+
copyVersion,
|
|
7929
|
+
same: copyVersion === packageVersion
|
|
7930
|
+
};
|
|
7931
|
+
}
|
|
8234
7932
|
const installSchema = object({
|
|
8235
7933
|
copy: string(),
|
|
8236
7934
|
written: array(string()),
|
|
@@ -8245,46 +7943,11 @@ async function sameContent(left, right) {
|
|
|
8245
7943
|
const [a, b] = await Promise.all([readFile(left), readFile(right)]);
|
|
8246
7944
|
return a.equals(b);
|
|
8247
7945
|
}
|
|
8248
|
-
|
|
8249
|
-
function agentsBlock(cli) {
|
|
8250
|
-
const { install } = cli;
|
|
8251
|
-
const where = install?.mode === "dependency" ? `, and only from a package that has \`${install.package}\` in its dependencies; from anywhere else npx reports the package missing` : "";
|
|
8252
|
-
const what = cli.description.replace(/\.$/, "");
|
|
8253
|
-
return `\`${cli.name}\`: ${what}. Run it as \`${runAsOf(cli)}\`${where}. Load the \`${cli.name}\` skill before using it.`;
|
|
8254
|
-
}
|
|
8255
|
-
function markersOf(name) {
|
|
8256
|
-
return {
|
|
8257
|
-
begin: `<!-- BEGIN:${name} -->`,
|
|
8258
|
-
end: `<!-- END:${name} -->`
|
|
8259
|
-
};
|
|
8260
|
-
}
|
|
8261
|
-
/** `text` with the block between its markers, appended when they are missing; nothing else changes. */
|
|
8262
|
-
function withBlock(text, block, { begin, end }) {
|
|
8263
|
-
const whole = `${begin}\n${block}\n${end}`;
|
|
8264
|
-
const start = text.indexOf(begin);
|
|
8265
|
-
const stop = start === -1 ? -1 : text.indexOf(end, start);
|
|
8266
|
-
if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
|
|
8267
|
-
if (text === "") return `${whole}\n`;
|
|
8268
|
-
return `${text}${text.endsWith("\n") ? "" : "\n"}\n${whole}\n`;
|
|
8269
|
-
}
|
|
8270
|
-
function blockChangeOf(existing, block, markers) {
|
|
8271
|
-
if (existing === void 0) return "create";
|
|
8272
|
-
if (withBlock(existing, block, markers) === existing) return null;
|
|
8273
|
-
return existing.includes(markers.begin) ? "rewrite" : "add";
|
|
8274
|
-
}
|
|
8275
|
-
async function handEditsAt(root) {
|
|
8276
|
-
const claudeMd = join(root, "CLAUDE.md");
|
|
8277
|
-
const text = await orMissing(readFile(claudeMd, "utf8"));
|
|
8278
|
-
if (text === void 0 || text.split(/\r?\n/).some((line) => line.trim() === "@AGENTS.md")) return [];
|
|
8279
|
-
return [`add a line \`@AGENTS.md\` to ${claudeMd}, so Claude Code reads AGENTS.md`];
|
|
8280
|
-
}
|
|
8281
|
-
async function planOf(cli, folder, cwd, packageRoot) {
|
|
7946
|
+
async function planOf(cli, folder, install, cwd, packageRoot) {
|
|
8282
7947
|
const source = join(packageRoot, folder);
|
|
8283
7948
|
const { root, copy } = await skillCopyOf(cli, cwd);
|
|
8284
7949
|
const [shipped, present] = await Promise.all([filesIn(source), filesIn(copy)]);
|
|
8285
7950
|
const differs = await Promise.all(shipped.map(async (file) => present.includes(file) && !await sameContent(join(source, file), join(copy, file))));
|
|
8286
|
-
const agentsPath = join(root, "AGENTS.md");
|
|
8287
|
-
const block = agentsBlock(cli);
|
|
8288
7951
|
return {
|
|
8289
7952
|
source,
|
|
8290
7953
|
copy,
|
|
@@ -8292,11 +7955,7 @@ async function planOf(cli, folder, cwd, packageRoot) {
|
|
|
8292
7955
|
replace: shipped.filter((_file, index) => differs[index]),
|
|
8293
7956
|
remove: present.filter((file) => !shipped.includes(file)),
|
|
8294
7957
|
sameVersion: (await skillVersionsOf(source, copy)).same,
|
|
8295
|
-
agentsMd:
|
|
8296
|
-
path: agentsPath,
|
|
8297
|
-
block,
|
|
8298
|
-
change: blockChangeOf(await orMissing(readFile(agentsPath, "utf8")), block, markersOf(cli.name))
|
|
8299
|
-
},
|
|
7958
|
+
agentsMd: await agentsMdAt(cli, install, root),
|
|
8300
7959
|
handEdits: await handEditsAt(root)
|
|
8301
7960
|
};
|
|
8302
7961
|
}
|
|
@@ -8336,8 +7995,8 @@ function editedRemovals(plan, ctx) {
|
|
|
8336
7995
|
});
|
|
8337
7996
|
}
|
|
8338
7997
|
/** The built-in `skill install`, for a CLI whose skill ships in its package. */
|
|
8339
|
-
function skillInstallCommand(cli, folder) {
|
|
8340
|
-
const runAs =
|
|
7998
|
+
function skillInstallCommand(cli, folder, install) {
|
|
7999
|
+
const { runAs } = install;
|
|
8341
8000
|
return defineCommand$1({
|
|
8342
8001
|
name: "install",
|
|
8343
8002
|
description: "copy this CLI's skill into the project and write its AGENTS.md block",
|
|
@@ -8351,16 +8010,16 @@ function skillInstallCommand(cli, folder) {
|
|
|
8351
8010
|
effect: "write",
|
|
8352
8011
|
output: installSchema,
|
|
8353
8012
|
force: "replace or remove hand-edited files of a skill copy at the package's version",
|
|
8354
|
-
plan: (_input, ctx) => planOf(cli, folder, ctx.cwd, ctx.packageRoot),
|
|
8013
|
+
plan: (_input, ctx) => planOf(cli, folder, install, ctx.cwd, ctx.packageRoot),
|
|
8355
8014
|
outputs: (plan) => plan.sameVersion ? [...plan.write, ...plan.replace].map((file) => join(plan.copy, file)) : [],
|
|
8356
8015
|
apply: async (plan, ctx) => {
|
|
8357
8016
|
if (plan.sameVersion && plan.remove.length > 0 && !ctx.force) throw editedRemovals(plan, ctx);
|
|
8358
8017
|
for (const file of [...plan.write, ...plan.replace]) await ctx.files.write(join(plan.copy, file), await readFile(join(plan.source, file)));
|
|
8359
8018
|
for (const file of plan.remove) await ctx.files.remove(join(plan.copy, file));
|
|
8360
|
-
const { path,
|
|
8019
|
+
const { path, change } = plan.agentsMd;
|
|
8361
8020
|
if (change !== null) {
|
|
8362
8021
|
const existing = await orMissing(readFile(path, "utf8")) ?? "";
|
|
8363
|
-
await ctx.files.write(path, withBlock(
|
|
8022
|
+
await ctx.files.write(path, withBlock(cli, install, existing));
|
|
8364
8023
|
}
|
|
8365
8024
|
return {
|
|
8366
8025
|
copy: plan.copy,
|
|
@@ -8378,6 +8037,93 @@ function skillInstallCommand(cli, folder) {
|
|
|
8378
8037
|
});
|
|
8379
8038
|
}
|
|
8380
8039
|
//#endregion
|
|
8040
|
+
//#region ../agent-cli/dist/built-ins/skill/packaged.js
|
|
8041
|
+
async function personalCopyOf(name, copy, ctx) {
|
|
8042
|
+
const home = join(homeOf(ctx.env), ".claude", "skills", name);
|
|
8043
|
+
const real = await orMissing(realpath(home));
|
|
8044
|
+
return real === void 0 || real === await orMissing(realpath(copy)) ? void 0 : home;
|
|
8045
|
+
}
|
|
8046
|
+
/** What the `skill` row of a Packaged skill carries under `--json` beside its message. */
|
|
8047
|
+
const packagedSkillDetailsSchema = object({
|
|
8048
|
+
copy: string(),
|
|
8049
|
+
copyVersion: string().nullable(),
|
|
8050
|
+
packageVersion: string().nullable(),
|
|
8051
|
+
/** A personal copy, which Claude Code prefers over the project's. */
|
|
8052
|
+
home: string().optional()
|
|
8053
|
+
});
|
|
8054
|
+
function versionLabel(version) {
|
|
8055
|
+
return version ?? "(no metadata.version)";
|
|
8056
|
+
}
|
|
8057
|
+
function compared(name, { copy, copyVersion, packageVersion }, same) {
|
|
8058
|
+
const stated = `${copy} ${versionLabel(copyVersion)}`;
|
|
8059
|
+
return same ? `${stated}, the version ${name} ships` : `${stated} differs from the ${versionLabel(packageVersion)} that ${name} ships`;
|
|
8060
|
+
}
|
|
8061
|
+
/** The project root's copy against the package's, and any under home. */
|
|
8062
|
+
async function findingOf(cli, folder, install, ctx) {
|
|
8063
|
+
const { copy } = await skillCopyOf(cli, ctx.cwd);
|
|
8064
|
+
const versions = await skillVersionsOf(join(ctx.packageRoot, folder), copy);
|
|
8065
|
+
const { packageVersion } = versions;
|
|
8066
|
+
const copyVersion = versions.copyVersion ?? null;
|
|
8067
|
+
const home = await personalCopyOf(cli.name, copy, ctx);
|
|
8068
|
+
const skill = {
|
|
8069
|
+
copy,
|
|
8070
|
+
copyVersion,
|
|
8071
|
+
packageVersion,
|
|
8072
|
+
...home === void 0 ? {} : { home }
|
|
8073
|
+
};
|
|
8074
|
+
const head = versions.copyVersion === void 0 ? `no copy of the ${cli.name} skill at ${copy}` : compared(cli.name, skill, versions.same);
|
|
8075
|
+
const message = home === void 0 ? head : `${head}; remove ${home}: Claude Code prefers a personal skill over the project's`;
|
|
8076
|
+
if (!versions.same) return {
|
|
8077
|
+
state: "problem",
|
|
8078
|
+
message,
|
|
8079
|
+
fix: `${install.runAs} skill install`,
|
|
8080
|
+
skill
|
|
8081
|
+
};
|
|
8082
|
+
return home === void 0 ? {
|
|
8083
|
+
state: "ok",
|
|
8084
|
+
message,
|
|
8085
|
+
skill
|
|
8086
|
+
} : {
|
|
8087
|
+
state: "problem",
|
|
8088
|
+
message,
|
|
8089
|
+
skill
|
|
8090
|
+
};
|
|
8091
|
+
}
|
|
8092
|
+
async function notice(cli, folder, install, { builtIn, bin }, ctx) {
|
|
8093
|
+
if (builtIn || bin === void 0 || cli.commands === void 0) return;
|
|
8094
|
+
let finding;
|
|
8095
|
+
try {
|
|
8096
|
+
finding = await findingOf(cli, folder, install, ctx);
|
|
8097
|
+
} catch (error) {
|
|
8098
|
+
if (errnoOf(error) === void 0) throw error;
|
|
8099
|
+
ctx.notice(`could not check the ${cli.name} skill: ${messageOf(error)}`);
|
|
8100
|
+
return;
|
|
8101
|
+
}
|
|
8102
|
+
if (finding.state !== "problem") return;
|
|
8103
|
+
ctx.notice(finding.fix === void 0 ? finding.message : `${finding.message}; run \`${finding.fix}\``);
|
|
8104
|
+
}
|
|
8105
|
+
/** A skill shipped in the package at `folder`, which `skill install` copies to the project root. */
|
|
8106
|
+
function packagedSkill(cli, folder, install) {
|
|
8107
|
+
return {
|
|
8108
|
+
kind: "packaged",
|
|
8109
|
+
builtIns: { skill: { install: skillInstallCommand(cli, folder, install) } },
|
|
8110
|
+
rows: [{
|
|
8111
|
+
name: "skill",
|
|
8112
|
+
advisory: true,
|
|
8113
|
+
run: (ctx) => findingOf(cli, folder, install, ctx)
|
|
8114
|
+
}, agentsRow(cli, install)],
|
|
8115
|
+
notice: (launch, ctx) => notice(cli, folder, install, launch, ctx),
|
|
8116
|
+
findingAt: (_version, ctx) => findingOf(cli, folder, install, ctx)
|
|
8117
|
+
};
|
|
8118
|
+
}
|
|
8119
|
+
//#endregion
|
|
8120
|
+
//#region ../agent-cli/dist/built-ins/skill/skill.js
|
|
8121
|
+
/** A Packaged skill, or else a Skill Hub's, also for a CLI that declares no `skill`. */
|
|
8122
|
+
function skillOf(cli, install) {
|
|
8123
|
+
const { skill } = cli;
|
|
8124
|
+
return skill !== void 0 && "packaged" in skill ? packagedSkill(cli, skill.packaged, install) : hubSkill(cli, skill?.source);
|
|
8125
|
+
}
|
|
8126
|
+
//#endregion
|
|
8381
8127
|
//#region ../agent-cli/dist/interrupts.js
|
|
8382
8128
|
const INTERRUPTED = "INTERRUPTED";
|
|
8383
8129
|
const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
|
|
@@ -8515,6 +8261,59 @@ var RunControl = class {
|
|
|
8515
8261
|
}
|
|
8516
8262
|
};
|
|
8517
8263
|
//#endregion
|
|
8264
|
+
//#region ../agent-cli/dist/built-ins/install/global-npm.js
|
|
8265
|
+
const NOT_GLOBAL_INSTALL = "NOT_GLOBAL_INSTALL";
|
|
8266
|
+
/** Where npm puts global packages under its global prefix. */
|
|
8267
|
+
function globalModulesDir(prefix) {
|
|
8268
|
+
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
8269
|
+
}
|
|
8270
|
+
function notGlobal(ctx, message) {
|
|
8271
|
+
return new CliError({
|
|
8272
|
+
code: NOT_GLOBAL_INSTALL,
|
|
8273
|
+
message,
|
|
8274
|
+
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.registry)}`
|
|
8275
|
+
});
|
|
8276
|
+
}
|
|
8277
|
+
/**
|
|
8278
|
+
* The global npm install this copy runs from, found by asking npm for its global prefix.
|
|
8279
|
+
* `bin` is the script that started the CLI; throws `NOT_GLOBAL_INSTALL` when it is not inside that install.
|
|
8280
|
+
*/
|
|
8281
|
+
async function globalInstallOf(bin, ctx) {
|
|
8282
|
+
if (bin === void 0) throw notGlobal(ctx, `${ctx.cliName} runs from source, not from an npm install`);
|
|
8283
|
+
const prefix = await globalPrefix(ctx);
|
|
8284
|
+
const packageDir = join(globalModulesDir(prefix), ctx.registry.package);
|
|
8285
|
+
const installed = await orMissing(realpath(packageDir));
|
|
8286
|
+
const here = await orMissing(realpath(bin)) ?? bin;
|
|
8287
|
+
if (installed === void 0 || !isInside(installed, here)) throw notGlobal(ctx, `${ctx.cliName} runs from ${here}, not from npm's global install at ${packageDir}`);
|
|
8288
|
+
if ((await lstat(packageDir)).isSymbolicLink()) throw notGlobal(ctx, `${ctx.cliName} runs from a link to ${installed} (npm link), not from an npm install`);
|
|
8289
|
+
return {
|
|
8290
|
+
prefix,
|
|
8291
|
+
packageDir
|
|
8292
|
+
};
|
|
8293
|
+
}
|
|
8294
|
+
const NPMJS = "https://registry.npmjs.org/";
|
|
8295
|
+
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
8296
|
+
function registryFlags({ package: name, registry }) {
|
|
8297
|
+
if (registry === NPMJS) return [];
|
|
8298
|
+
const scope = scopeOf(name);
|
|
8299
|
+
return [scope === void 0 ? `--registry=${registry}` : `--${scope}:registry=${registry}`];
|
|
8300
|
+
}
|
|
8301
|
+
function globalRegistry(install) {
|
|
8302
|
+
const { package: name, registry } = install;
|
|
8303
|
+
return {
|
|
8304
|
+
package: name,
|
|
8305
|
+
label: registry,
|
|
8306
|
+
flags: registryFlags(install),
|
|
8307
|
+
unreachableHint: "check the network or VPN",
|
|
8308
|
+
loginHint: `log in to ${registry} (\`npm login --registry=${registry}\`) or set its token in ~/.npmrc`,
|
|
8309
|
+
missingHint: `check that ${name} is published on ${registry}`
|
|
8310
|
+
};
|
|
8311
|
+
}
|
|
8312
|
+
/** npm for a Global install, run in the working directory. */
|
|
8313
|
+
function globalNpm(cli, install, ctx, node) {
|
|
8314
|
+
return npmContext(cli, globalRegistry(install), ctx, node, ctx.cwd);
|
|
8315
|
+
}
|
|
8316
|
+
//#endregion
|
|
8518
8317
|
//#region ../agent-cli/dist/built-ins/upgrades.js
|
|
8519
8318
|
/** A skipped release's Upgrade steps, or its whole section when it lists none. */
|
|
8520
8319
|
const upgradeSchema = union([object({
|
|
@@ -8565,115 +8364,420 @@ function upgradeOf({ version, lines }) {
|
|
|
8565
8364
|
steps: todo
|
|
8566
8365
|
}];
|
|
8567
8366
|
}
|
|
8568
|
-
/**
|
|
8569
|
-
* What each release after `from` up to `to` asks of the operator, oldest first, from the
|
|
8570
|
-
* CHANGELOG.md in `packageDir`; none when the package ships no CHANGELOG.
|
|
8571
|
-
*/
|
|
8572
|
-
async function upgradesOf(packageDir, from, to) {
|
|
8573
|
-
let changelog;
|
|
8367
|
+
/**
|
|
8368
|
+
* What each release after `from` up to `to` asks of the operator, oldest first, from the
|
|
8369
|
+
* CHANGELOG.md in `packageDir`; none when the package ships no CHANGELOG.
|
|
8370
|
+
*/
|
|
8371
|
+
async function upgradesOf(packageDir, from, to) {
|
|
8372
|
+
let changelog;
|
|
8373
|
+
try {
|
|
8374
|
+
changelog = await readFile(join(packageDir, "CHANGELOG.md"), "utf8");
|
|
8375
|
+
} catch (error) {
|
|
8376
|
+
if (isMissingFile(error)) return [];
|
|
8377
|
+
throw error;
|
|
8378
|
+
}
|
|
8379
|
+
return releasesIn(changelog).filter(({ version }) => compareVersions(version, from) > 0 && compareVersions(version, to) <= 0).sort((a, b) => compareVersions(a.version, b.version)).flatMap(upgradeOf);
|
|
8380
|
+
}
|
|
8381
|
+
//#endregion
|
|
8382
|
+
//#region ../agent-cli/dist/built-ins/update.js
|
|
8383
|
+
const updateSchema = object({
|
|
8384
|
+
from: string(),
|
|
8385
|
+
latest: string(),
|
|
8386
|
+
installed: object({
|
|
8387
|
+
version: string(),
|
|
8388
|
+
prefix: string()
|
|
8389
|
+
}).nullable(),
|
|
8390
|
+
upgrades: array(upgradeSchema),
|
|
8391
|
+
next: array(string())
|
|
8392
|
+
});
|
|
8393
|
+
function nothingToInstall({ from, latest }) {
|
|
8394
|
+
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`;
|
|
8395
|
+
}
|
|
8396
|
+
function renderUpgrade(upgrade) {
|
|
8397
|
+
return "steps" in upgrade ? [`\nupgrade steps for ${upgrade.version}:`, ...upgrade.steps.map((step) => `- ${step}`)].join("\n") : `\nchanges in ${upgrade.version}:\n${upgrade.notes}`;
|
|
8398
|
+
}
|
|
8399
|
+
function renderUpdate(cli, install, update) {
|
|
8400
|
+
const { installed } = update;
|
|
8401
|
+
const head = installed === null ? [nothingToInstall(update)] : [`installed ${install.package}@${installed.version} with the npm under ${installed.prefix}, replacing ${update.from}`, ...update.upgrades.map(renderUpgrade)];
|
|
8402
|
+
const next = update.next.map((command) => `next: ${command}, so the ${cli.name} skill describes ${update.latest}`);
|
|
8403
|
+
return (next.length === 0 ? head : [
|
|
8404
|
+
...head,
|
|
8405
|
+
"",
|
|
8406
|
+
...next
|
|
8407
|
+
]).join("\n");
|
|
8408
|
+
}
|
|
8409
|
+
async function skillNext(skill, latest, ctx) {
|
|
8410
|
+
const { fix } = await skill.findingAt(latest, ctx);
|
|
8411
|
+
return fix === void 0 ? [] : [fix];
|
|
8412
|
+
}
|
|
8413
|
+
function interruptedAfterInstall(plan) {
|
|
8414
|
+
return new CliError({
|
|
8415
|
+
code: INTERRUPTED,
|
|
8416
|
+
message: `interrupted, but ${plan.package}@${plan.latest} had already been installed with the npm under ${plan.prefix}, replacing ${plan.from}`,
|
|
8417
|
+
hint: "nothing to run again: run the commands under next"
|
|
8418
|
+
});
|
|
8419
|
+
}
|
|
8420
|
+
/** The built-in `update`, for a CLI installed globally with npm. */
|
|
8421
|
+
function updateCommand(cli, install, skill, { bin, node }) {
|
|
8422
|
+
return defineCommand$1({
|
|
8423
|
+
name: "update",
|
|
8424
|
+
description: "install the latest version of this CLI from its registry",
|
|
8425
|
+
examples: [{
|
|
8426
|
+
command: `${cli.name} update`,
|
|
8427
|
+
note: "install the latest version and show what changed"
|
|
8428
|
+
}, {
|
|
8429
|
+
command: `${cli.name} update --dry-run`,
|
|
8430
|
+
note: "show the version it would install"
|
|
8431
|
+
}],
|
|
8432
|
+
effect: "write",
|
|
8433
|
+
output: updateSchema,
|
|
8434
|
+
plan: async (_input, ctx) => {
|
|
8435
|
+
const npm = globalNpm(cli, install, ctx, node);
|
|
8436
|
+
const copy = await globalInstallOf(bin, npm);
|
|
8437
|
+
return {
|
|
8438
|
+
package: install.package,
|
|
8439
|
+
from: cli.version,
|
|
8440
|
+
latest: await latestVersion(npm),
|
|
8441
|
+
prefix: copy.prefix,
|
|
8442
|
+
packageDir: copy.packageDir
|
|
8443
|
+
};
|
|
8444
|
+
},
|
|
8445
|
+
apply: async (plan, ctx) => {
|
|
8446
|
+
const { from, latest, prefix } = plan;
|
|
8447
|
+
if (standingOf$1(from, latest) !== "behind") return {
|
|
8448
|
+
from,
|
|
8449
|
+
latest,
|
|
8450
|
+
installed: null,
|
|
8451
|
+
upgrades: [],
|
|
8452
|
+
next: await skillNext(skill, latest, ctx)
|
|
8453
|
+
};
|
|
8454
|
+
ctx.signal.throwIfAborted();
|
|
8455
|
+
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
8456
|
+
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, globalNpm(cli, install, ctx, node)));
|
|
8457
|
+
const update = {
|
|
8458
|
+
from,
|
|
8459
|
+
latest,
|
|
8460
|
+
installed: {
|
|
8461
|
+
version: latest,
|
|
8462
|
+
prefix
|
|
8463
|
+
},
|
|
8464
|
+
upgrades: await upgradesOf(plan.packageDir, from, latest),
|
|
8465
|
+
next: await skillNext(skill, latest, ctx)
|
|
8466
|
+
};
|
|
8467
|
+
if (ctx.signal.aborted) {
|
|
8468
|
+
ctx.deliver(update);
|
|
8469
|
+
throw interruptedAfterInstall(plan);
|
|
8470
|
+
}
|
|
8471
|
+
return update;
|
|
8472
|
+
},
|
|
8473
|
+
render: (update) => renderUpdate(cli, install, update),
|
|
8474
|
+
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)
|
|
8475
|
+
});
|
|
8476
|
+
}
|
|
8477
|
+
//#endregion
|
|
8478
|
+
//#region ../agent-cli/dist/built-ins/install/global.js
|
|
8479
|
+
function checkOf(cli, install, { bin, node }) {
|
|
8480
|
+
return {
|
|
8481
|
+
install: async (ctx) => {
|
|
8482
|
+
const npm = globalNpm(cli, install, ctx, node);
|
|
8483
|
+
try {
|
|
8484
|
+
return {
|
|
8485
|
+
state: "ok",
|
|
8486
|
+
message: `a global npm install under ${(await globalInstallOf(bin, npm)).prefix}`
|
|
8487
|
+
};
|
|
8488
|
+
} catch (error) {
|
|
8489
|
+
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
8490
|
+
state: "problem",
|
|
8491
|
+
message: error.message,
|
|
8492
|
+
fix: installCommandLine(npm.registry)
|
|
8493
|
+
};
|
|
8494
|
+
throw error;
|
|
8495
|
+
}
|
|
8496
|
+
},
|
|
8497
|
+
release: async (ctx) => {
|
|
8498
|
+
const fix = `${cli.name} update`;
|
|
8499
|
+
return {
|
|
8500
|
+
npm: globalNpm(cli, install, ctx, node),
|
|
8501
|
+
advise: () => ({ fix })
|
|
8502
|
+
};
|
|
8503
|
+
}
|
|
8504
|
+
};
|
|
8505
|
+
}
|
|
8506
|
+
/** The Install of a CLI installed once per machine with npm, which `update` replaces. */
|
|
8507
|
+
function globalInstall(cli, install) {
|
|
8508
|
+
const adapter = {
|
|
8509
|
+
runAs: runAsOf(cli),
|
|
8510
|
+
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf(cli, adapter), launch) }),
|
|
8511
|
+
exitClasses: ["source"],
|
|
8512
|
+
agentsCaveat: void 0,
|
|
8513
|
+
check: (launch) => checkOf(cli, install, launch)
|
|
8514
|
+
};
|
|
8515
|
+
return adapter;
|
|
8516
|
+
}
|
|
8517
|
+
//#endregion
|
|
8518
|
+
//#region ../agent-cli/dist/built-ins/install/install.js
|
|
8519
|
+
function noInstall(cli) {
|
|
8520
|
+
const skipped = async () => ({
|
|
8521
|
+
state: "skipped",
|
|
8522
|
+
message: `not checked: ${cli.name} declares no install`
|
|
8523
|
+
});
|
|
8524
|
+
return {
|
|
8525
|
+
runAs: runAsOf(cli),
|
|
8526
|
+
builtIns: () => ({}),
|
|
8527
|
+
exitClasses: [],
|
|
8528
|
+
agentsCaveat: void 0,
|
|
8529
|
+
check: () => ({
|
|
8530
|
+
install: skipped,
|
|
8531
|
+
release: async () => ({ skipped: await skipped() })
|
|
8532
|
+
})
|
|
8533
|
+
};
|
|
8534
|
+
}
|
|
8535
|
+
function installOf(cli) {
|
|
8536
|
+
const { install } = cli;
|
|
8537
|
+
if (install === void 0) return noInstall(cli);
|
|
8538
|
+
return install.mode === "global" ? globalInstall(cli, install) : dependencyInstall(cli, install);
|
|
8539
|
+
}
|
|
8540
|
+
//#endregion
|
|
8541
|
+
//#region ../agent-cli/dist/built-ins/doctor-rows.js
|
|
8542
|
+
function ok(message) {
|
|
8543
|
+
return {
|
|
8544
|
+
state: "ok",
|
|
8545
|
+
message
|
|
8546
|
+
};
|
|
8547
|
+
}
|
|
8548
|
+
function buildRow(cli) {
|
|
8549
|
+
return {
|
|
8550
|
+
name: "build",
|
|
8551
|
+
run: () => ok(versionLine(cli))
|
|
8552
|
+
};
|
|
8553
|
+
}
|
|
8554
|
+
function nodeRow(cli) {
|
|
8555
|
+
return {
|
|
8556
|
+
name: "node",
|
|
8557
|
+
run: () => {
|
|
8558
|
+
const found = process.versions.node;
|
|
8559
|
+
const range = cli.engines?.node;
|
|
8560
|
+
if (range === void 0) return ok(`Node ${found}; ${cli.name} declares no engines.node to check it against`);
|
|
8561
|
+
const minimum = engineMinimum(range);
|
|
8562
|
+
if (minimum === void 0) return {
|
|
8563
|
+
state: "problem",
|
|
8564
|
+
message: `${cli.name} declares engines.node "${range}", which doctor cannot read: only >=X.Y.Z is supported`
|
|
8565
|
+
};
|
|
8566
|
+
if (meetsMinimum(found, minimum)) return ok(`Node ${found} meets ${range}`);
|
|
8567
|
+
const major = minimum[0];
|
|
8568
|
+
return {
|
|
8569
|
+
state: "problem",
|
|
8570
|
+
message: `${cli.name} runs on Node ${found}, older than the ${range} it needs; install Node ${minimum.join(".")} or newer and make it the default`,
|
|
8571
|
+
fix: `nvm install ${major} && nvm alias default ${major}`
|
|
8572
|
+
};
|
|
8573
|
+
}
|
|
8574
|
+
};
|
|
8575
|
+
}
|
|
8576
|
+
/** A row's thrown error as its problem: a `CliError` with its hint and code, anything else a bug. */
|
|
8577
|
+
function problemOfError(name, error) {
|
|
8578
|
+
if (error instanceof CliError) return {
|
|
8579
|
+
state: "problem",
|
|
8580
|
+
message: `${error.message}; ${error.hint}`,
|
|
8581
|
+
code: error.code
|
|
8582
|
+
};
|
|
8583
|
+
return {
|
|
8584
|
+
state: "problem",
|
|
8585
|
+
message: `the ${name} row hit a bug: ${messageOf(error)}`
|
|
8586
|
+
};
|
|
8587
|
+
}
|
|
8588
|
+
function readProject(projectFile, ctx) {
|
|
8589
|
+
if (projectFile === void 0) return {
|
|
8590
|
+
ok: true,
|
|
8591
|
+
project: void 0
|
|
8592
|
+
};
|
|
8574
8593
|
try {
|
|
8575
|
-
|
|
8594
|
+
return {
|
|
8595
|
+
ok: true,
|
|
8596
|
+
project: projectOf(projectFile, ctx.cwd, {
|
|
8597
|
+
fileError: ctx.fileError,
|
|
8598
|
+
callerLine: ctx.commandLine()
|
|
8599
|
+
})
|
|
8600
|
+
};
|
|
8576
8601
|
} catch (error) {
|
|
8577
|
-
|
|
8578
|
-
|
|
8602
|
+
return {
|
|
8603
|
+
ok: false,
|
|
8604
|
+
error
|
|
8605
|
+
};
|
|
8579
8606
|
}
|
|
8580
|
-
|
|
8607
|
+
}
|
|
8608
|
+
function projectRow({ file }, read) {
|
|
8609
|
+
return {
|
|
8610
|
+
name: "project",
|
|
8611
|
+
run: (ctx) => {
|
|
8612
|
+
if (!read.ok) return problemOfError("project", read.error);
|
|
8613
|
+
return ok(read.project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(read.project.root, file));
|
|
8614
|
+
}
|
|
8615
|
+
};
|
|
8616
|
+
}
|
|
8617
|
+
function installRow(check) {
|
|
8618
|
+
return {
|
|
8619
|
+
name: "install",
|
|
8620
|
+
advisory: true,
|
|
8621
|
+
run: check.install
|
|
8622
|
+
};
|
|
8623
|
+
}
|
|
8624
|
+
function registryRow(cli, check) {
|
|
8625
|
+
return {
|
|
8626
|
+
name: "registry",
|
|
8627
|
+
advisory: true,
|
|
8628
|
+
run: async (ctx) => {
|
|
8629
|
+
const lookup = await check.release(ctx);
|
|
8630
|
+
if ("skipped" in lookup) return lookup.skipped;
|
|
8631
|
+
const { npm, advise } = lookup;
|
|
8632
|
+
const latest = await latestVersion(npm);
|
|
8633
|
+
const standing = standingOf$1(cli.version, latest);
|
|
8634
|
+
const head = `${npm.registry.label} has ${latest} as latest: this build`;
|
|
8635
|
+
if (standing === "behind") {
|
|
8636
|
+
const message = `${head} (${cli.version}) is older`;
|
|
8637
|
+
const advice = advise(latest);
|
|
8638
|
+
return "fix" in advice ? {
|
|
8639
|
+
state: "problem",
|
|
8640
|
+
message,
|
|
8641
|
+
fix: advice.fix
|
|
8642
|
+
} : {
|
|
8643
|
+
state: "problem",
|
|
8644
|
+
message: `${message}; ${advice.note}`
|
|
8645
|
+
};
|
|
8646
|
+
}
|
|
8647
|
+
return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
|
|
8648
|
+
}
|
|
8649
|
+
};
|
|
8650
|
+
}
|
|
8651
|
+
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
8652
|
+
function doctorChecks(cli, launch, read) {
|
|
8653
|
+
const install = installOf(cli);
|
|
8654
|
+
const check = install.check(launch);
|
|
8655
|
+
return [
|
|
8656
|
+
buildRow(cli),
|
|
8657
|
+
nodeRow(cli),
|
|
8658
|
+
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
8659
|
+
...cli.doctor ?? [],
|
|
8660
|
+
...toolRows(cli.tools ?? [], cli.commands),
|
|
8661
|
+
installRow(check),
|
|
8662
|
+
registryRow(cli, check),
|
|
8663
|
+
...skillOf(cli, install).rows
|
|
8664
|
+
];
|
|
8581
8665
|
}
|
|
8582
8666
|
//#endregion
|
|
8583
|
-
//#region ../agent-cli/dist/built-ins/
|
|
8584
|
-
const
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8667
|
+
//#region ../agent-cli/dist/built-ins/doctor.js
|
|
8668
|
+
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
8669
|
+
const DEFAULT_DEADLINE_MS = 1e4;
|
|
8670
|
+
const MS_PER_SECOND = 1e3;
|
|
8671
|
+
const MIN_LABEL_WIDTH = 8;
|
|
8672
|
+
const reportSchema = object({
|
|
8673
|
+
rows: array(object({
|
|
8674
|
+
check: string(),
|
|
8675
|
+
state: _enum([
|
|
8676
|
+
"ok",
|
|
8677
|
+
"problem",
|
|
8678
|
+
"skipped"
|
|
8679
|
+
]),
|
|
8680
|
+
message: string(),
|
|
8681
|
+
fix: string().optional(),
|
|
8682
|
+
code: string().optional(),
|
|
8683
|
+
skill: packagedSkillDetailsSchema.optional()
|
|
8684
|
+
})),
|
|
8592
8685
|
next: array(string())
|
|
8593
8686
|
});
|
|
8594
|
-
function
|
|
8595
|
-
|
|
8687
|
+
function problemOf(check, error, { signal, deadline, ms }) {
|
|
8688
|
+
if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
|
|
8689
|
+
state: "problem",
|
|
8690
|
+
message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
|
|
8691
|
+
};
|
|
8692
|
+
return problemOfError(check.name, error);
|
|
8596
8693
|
}
|
|
8597
|
-
function
|
|
8598
|
-
return
|
|
8694
|
+
function rowContext(ctx, signal, read) {
|
|
8695
|
+
return Object.create(ctx, {
|
|
8696
|
+
signal: { value: signal },
|
|
8697
|
+
project: { get: () => {
|
|
8698
|
+
if (!read.ok) throw read.error;
|
|
8699
|
+
return read.project;
|
|
8700
|
+
} }
|
|
8701
|
+
});
|
|
8599
8702
|
}
|
|
8600
|
-
function
|
|
8601
|
-
const
|
|
8602
|
-
const
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8703
|
+
async function rowOf(check, ctx, read) {
|
|
8704
|
+
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
8705
|
+
const signal = ctx.deadline(ms);
|
|
8706
|
+
let finding;
|
|
8707
|
+
try {
|
|
8708
|
+
finding = await Promise.race([Promise.resolve().then(() => check.run(rowContext(ctx, signal, read))), untilAborted(signal)]);
|
|
8709
|
+
} catch (error) {
|
|
8710
|
+
if (ctx.signal.aborted) return void 0;
|
|
8711
|
+
finding = !read.ok && error === read.error ? {
|
|
8712
|
+
state: "skipped",
|
|
8713
|
+
message: "the Project file is unusable; the project row says why"
|
|
8714
|
+
} : problemOf(check, error, {
|
|
8715
|
+
signal: ctx.signal,
|
|
8716
|
+
deadline: signal,
|
|
8717
|
+
ms
|
|
8718
|
+
});
|
|
8719
|
+
}
|
|
8720
|
+
return {
|
|
8721
|
+
row: {
|
|
8722
|
+
check: check.name,
|
|
8723
|
+
...finding
|
|
8724
|
+
},
|
|
8725
|
+
advisory: check.advisory === true
|
|
8726
|
+
};
|
|
8609
8727
|
}
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
const finding = packaged === void 0 ? await skillReport(cli, latest, ctx) : await packagedSkillFinding(cli, packaged, ctx);
|
|
8613
|
-
return "fix" in finding && finding.fix !== void 0 ? [finding.fix] : [];
|
|
8728
|
+
function nextOf(rows) {
|
|
8729
|
+
return [...new Set(rows.flatMap(({ fix }) => fix === void 0 ? [] : [fix]))];
|
|
8614
8730
|
}
|
|
8615
|
-
function
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8731
|
+
function render({ rows, next }, style) {
|
|
8732
|
+
const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
|
|
8733
|
+
const stateWidth = Math.max(...rows.map(({ state }) => state.length)) + 2;
|
|
8734
|
+
return [...rows.map(({ check, state, message }) => {
|
|
8735
|
+
const label = state === "problem" ? style.red(state) : state;
|
|
8736
|
+
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
8737
|
+
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
8621
8738
|
}
|
|
8622
|
-
|
|
8623
|
-
|
|
8739
|
+
function failure(cliName, callerLine, problems) {
|
|
8740
|
+
const errors = problems.map(({ check, message, fix, code }) => new CliError({
|
|
8741
|
+
code: code ?? "DOCTOR_PROBLEMS",
|
|
8742
|
+
message: `${cliName} doctor found a problem in ${check}: ${message}`,
|
|
8743
|
+
hint: fix === void 0 ? "the row says what is wrong" : `run \`${fix}\`, then run \`${callerLine}\` again`
|
|
8744
|
+
}));
|
|
8745
|
+
return new AggregateError(errors);
|
|
8746
|
+
}
|
|
8747
|
+
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
8748
|
+
function doctorCommand(cli, launch) {
|
|
8624
8749
|
return defineCommand$1({
|
|
8625
|
-
name: "
|
|
8626
|
-
description: "
|
|
8750
|
+
name: "doctor",
|
|
8751
|
+
description: "check the setup and say what fixes each problem",
|
|
8627
8752
|
examples: [{
|
|
8628
|
-
command: `${cli
|
|
8629
|
-
note: "
|
|
8753
|
+
command: `${runAsOf(cli)} doctor`,
|
|
8754
|
+
note: "check the setup and list the commands that fix it"
|
|
8630
8755
|
}, {
|
|
8631
|
-
command: `${cli
|
|
8632
|
-
note: "
|
|
8756
|
+
command: `${runAsOf(cli)} doctor --json`,
|
|
8757
|
+
note: "get the rows and fixes as data"
|
|
8633
8758
|
}],
|
|
8634
|
-
effect: "
|
|
8635
|
-
output:
|
|
8636
|
-
|
|
8637
|
-
const
|
|
8638
|
-
const
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
prefix: copy.prefix,
|
|
8644
|
-
packageDir: copy.packageDir
|
|
8645
|
-
};
|
|
8646
|
-
},
|
|
8647
|
-
apply: async (plan, ctx) => {
|
|
8648
|
-
const { from, latest, prefix } = plan;
|
|
8649
|
-
if (standingOf$1(from, latest) !== "behind") return {
|
|
8650
|
-
from,
|
|
8651
|
-
latest,
|
|
8652
|
-
installed: null,
|
|
8653
|
-
upgrades: [],
|
|
8654
|
-
next: await skillNext(cli, latest, ctx)
|
|
8655
|
-
};
|
|
8656
|
-
ctx.signal.throwIfAborted();
|
|
8657
|
-
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
8658
|
-
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, globalNpm(cli, install, ctx, node)));
|
|
8659
|
-
const update = {
|
|
8660
|
-
from,
|
|
8661
|
-
latest,
|
|
8662
|
-
installed: {
|
|
8663
|
-
version: latest,
|
|
8664
|
-
prefix
|
|
8665
|
-
},
|
|
8666
|
-
upgrades: await upgradesOf(plan.packageDir, from, latest),
|
|
8667
|
-
next: await skillNext(cli, latest, ctx)
|
|
8759
|
+
effect: "read",
|
|
8760
|
+
output: reportSchema,
|
|
8761
|
+
run: async (_input, ctx) => {
|
|
8762
|
+
const read = readProject(cli.project, ctx);
|
|
8763
|
+
const checked = (await Promise.all(doctorChecks(cli, launch, read).map((check) => rowOf(check, ctx, read)))).filter((row) => row !== void 0);
|
|
8764
|
+
const rows = checked.map(({ row }) => row);
|
|
8765
|
+
const report = {
|
|
8766
|
+
rows,
|
|
8767
|
+
next: nextOf(rows)
|
|
8668
8768
|
};
|
|
8669
8769
|
if (ctx.signal.aborted) {
|
|
8670
|
-
ctx.deliver(
|
|
8671
|
-
|
|
8770
|
+
ctx.deliver(report);
|
|
8771
|
+
ctx.signal.throwIfAborted();
|
|
8672
8772
|
}
|
|
8673
|
-
|
|
8773
|
+
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
8774
|
+
if (problems.length > 0) {
|
|
8775
|
+
ctx.deliver(report);
|
|
8776
|
+
throw failure(cli.name, ctx.commandLine(), problems);
|
|
8777
|
+
}
|
|
8778
|
+
return report;
|
|
8674
8779
|
},
|
|
8675
|
-
render
|
|
8676
|
-
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)
|
|
8780
|
+
render
|
|
8677
8781
|
});
|
|
8678
8782
|
}
|
|
8679
8783
|
//#endregion
|
|
@@ -8683,11 +8787,11 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
8683
8787
|
* `skill install` only for a Packaged skill.
|
|
8684
8788
|
*/
|
|
8685
8789
|
function builtInCommands(cli, launch) {
|
|
8686
|
-
const
|
|
8790
|
+
const install = installOf(cli);
|
|
8687
8791
|
return {
|
|
8688
8792
|
doctor: doctorCommand(cli, launch),
|
|
8689
|
-
...
|
|
8690
|
-
...
|
|
8793
|
+
...install.builtIns(launch),
|
|
8794
|
+
...skillOf(cli, install).builtIns
|
|
8691
8795
|
};
|
|
8692
8796
|
}
|
|
8693
8797
|
//#endregion
|
|
@@ -8811,7 +8915,7 @@ function reachableExitClasses(cli) {
|
|
|
8811
8915
|
"caller",
|
|
8812
8916
|
"operator",
|
|
8813
8917
|
"wait",
|
|
8814
|
-
...cli.commands
|
|
8918
|
+
...cli.commands === void 0 ? [] : installOf(cli).exitClasses
|
|
8815
8919
|
];
|
|
8816
8920
|
const own = Object.values(cli.errors ?? {}).map((declaration) => declaration.class);
|
|
8817
8921
|
return /* @__PURE__ */ new Set([...runtime, ...own]);
|
|
@@ -8837,7 +8941,7 @@ function checkOwnCodes(cli) {
|
|
|
8837
8941
|
function defineCli$1(cli) {
|
|
8838
8942
|
checkOwnCodes(cli);
|
|
8839
8943
|
if (cli.commands === void 0) {
|
|
8840
|
-
if (
|
|
8944
|
+
if (skillOf(cli, installOf(cli)).kind === "packaged") throw new Error(`${cli.name} declares a Packaged skill, which only a CLI with several Commands can install`);
|
|
8841
8945
|
return cli;
|
|
8842
8946
|
}
|
|
8843
8947
|
const { commands } = cli;
|
|
@@ -8860,7 +8964,10 @@ function agentCli() {
|
|
|
8860
8964
|
}
|
|
8861
8965
|
//#endregion
|
|
8862
8966
|
//#region ../agent-cli/dist/error-table.js
|
|
8863
|
-
/**
|
|
8967
|
+
/**
|
|
8968
|
+
* Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites;
|
|
8969
|
+
* `print` must name a string key of the code's `details`.
|
|
8970
|
+
*/
|
|
8864
8971
|
function defineErrors(table) {
|
|
8865
8972
|
return table;
|
|
8866
8973
|
}
|
|
@@ -9952,7 +10059,10 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9952
10059
|
let served = false;
|
|
9953
10060
|
let settled;
|
|
9954
10061
|
try {
|
|
9955
|
-
const outcome = await control.settle(
|
|
10062
|
+
const outcome = await control.settle(skillOf(cli, installOf(cli)).notice({
|
|
10063
|
+
builtIn,
|
|
10064
|
+
bin: options.bin
|
|
10065
|
+
}, ctx).then(() => execute(command, input, ctx, {
|
|
9956
10066
|
dryRun: flags.dryRun,
|
|
9957
10067
|
confirm: flags.confirm,
|
|
9958
10068
|
yes: flags.yes,
|
|
@@ -9965,7 +10075,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9965
10075
|
},
|
|
9966
10076
|
files,
|
|
9967
10077
|
guardOutputs: outputs.guard
|
|
9968
|
-
}));
|
|
10078
|
+
})));
|
|
9969
10079
|
if (served) return {
|
|
9970
10080
|
result: STOPPED_RESULT,
|
|
9971
10081
|
finishSideTask
|
|
@@ -10148,14 +10258,14 @@ async function runProcess(cli) {
|
|
|
10148
10258
|
}
|
|
10149
10259
|
//#endregion
|
|
10150
10260
|
//#region package.json
|
|
10151
|
-
var version$1 = "0.
|
|
10261
|
+
var version$1 = "0.15.1";
|
|
10152
10262
|
var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
|
|
10153
10263
|
//#endregion
|
|
10154
10264
|
//#region src/build.ts
|
|
10155
10265
|
const build = {
|
|
10156
|
-
"sha": "
|
|
10266
|
+
"sha": "da48f36",
|
|
10157
10267
|
"dirty": false,
|
|
10158
|
-
"builtAt": "2026-10-
|
|
10268
|
+
"builtAt": "2026-10-27T08:31:19.000Z"
|
|
10159
10269
|
};
|
|
10160
10270
|
//#endregion
|
|
10161
10271
|
//#region src/fill.ts
|