@duyquangnvx/create-agent-cli 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/bin.js +756 -725
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -6496,15 +6496,6 @@ function isCommand(node) {
|
|
|
6496
6496
|
return typeof node.effect === "string";
|
|
6497
6497
|
}
|
|
6498
6498
|
//#endregion
|
|
6499
|
-
//#region ../agent-cli/dist/run-as.js
|
|
6500
|
-
/**
|
|
6501
|
-
* The Run-as: how every command line the Runtime gives its caller starts. A Dependency install runs
|
|
6502
|
-
* the copy the project pins, so it is `npx -q --no-install <bin>`; otherwise the bare name (ADR 0011).
|
|
6503
|
-
*/
|
|
6504
|
-
function runAsOf(cli) {
|
|
6505
|
-
return cli.install?.mode === "dependency" ? `npx -q --no-install ${cli.name}` : cli.name;
|
|
6506
|
-
}
|
|
6507
|
-
//#endregion
|
|
6508
6499
|
//#region ../agent-cli/dist/project.js
|
|
6509
6500
|
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6510
6501
|
function invalid(path, problem, callerLine, options) {
|
|
@@ -6619,6 +6610,69 @@ function versionLine({ version, build }) {
|
|
|
6619
6610
|
return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
|
|
6620
6611
|
}
|
|
6621
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
|
|
6622
6676
|
//#region ../agent-cli/dist/tail.js
|
|
6623
6677
|
/** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
|
|
6624
6678
|
function lastLines(output, count) {
|
|
@@ -7003,7 +7057,6 @@ function npmContext(cli, registry, ctx, node, cwd) {
|
|
|
7003
7057
|
node
|
|
7004
7058
|
};
|
|
7005
7059
|
}
|
|
7006
|
-
const NPMJS = "https://registry.npmjs.org/";
|
|
7007
7060
|
const STDERR_TAIL_LINES = 10;
|
|
7008
7061
|
const RM_RETRIES = 3;
|
|
7009
7062
|
const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
@@ -7022,28 +7075,6 @@ const NPM_CODE = /^npm (?:error|ERR!) code (\S+)$/m;
|
|
|
7022
7075
|
function scopeOf(name) {
|
|
7023
7076
|
return /^(@[^/]+)\//.exec(name)?.[1];
|
|
7024
7077
|
}
|
|
7025
|
-
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
7026
|
-
function registryFlags({ package: name, registry }) {
|
|
7027
|
-
if (registry === NPMJS) return [];
|
|
7028
|
-
const scope = scopeOf(name);
|
|
7029
|
-
return [scope === void 0 ? `--registry=${registry}` : `--${scope}:registry=${registry}`];
|
|
7030
|
-
}
|
|
7031
|
-
/** The registry a Global install declares. */
|
|
7032
|
-
function globalRegistry(install) {
|
|
7033
|
-
const { package: name, registry } = install;
|
|
7034
|
-
return {
|
|
7035
|
-
package: name,
|
|
7036
|
-
label: registry,
|
|
7037
|
-
flags: registryFlags(install),
|
|
7038
|
-
unreachableHint: "check the network or VPN",
|
|
7039
|
-
loginHint: `log in to ${registry} (\`npm login --registry=${registry}\`) or set its token in ~/.npmrc`,
|
|
7040
|
-
missingHint: `check that ${name} is published on ${registry}`
|
|
7041
|
-
};
|
|
7042
|
-
}
|
|
7043
|
-
/** npm for a Global install, run where the CLI was started. */
|
|
7044
|
-
function globalNpm(cli, install, ctx, node) {
|
|
7045
|
-
return npmContext(cli, globalRegistry(install), ctx, node, process.cwd());
|
|
7046
|
-
}
|
|
7047
7078
|
/** The command a person runs to install the CLI globally from its registry. */
|
|
7048
7079
|
function installCommandLine(registry, version = "latest") {
|
|
7049
7080
|
return [
|
|
@@ -7186,62 +7217,13 @@ async function latestVersion(ctx) {
|
|
|
7186
7217
|
return version;
|
|
7187
7218
|
}
|
|
7188
7219
|
//#endregion
|
|
7189
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
7194
|
-
}
|
|
7195
|
-
function notGlobal(ctx, message) {
|
|
7196
|
-
return new CliError({
|
|
7197
|
-
code: NOT_GLOBAL_INSTALL,
|
|
7198
|
-
message,
|
|
7199
|
-
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.registry)}`
|
|
7200
|
-
});
|
|
7201
|
-
}
|
|
7202
|
-
async function realpathOrUndefined(path) {
|
|
7203
|
-
return realpath(path).catch((error) => {
|
|
7204
|
-
if (isMissingFile(error)) return void 0;
|
|
7205
|
-
throw error;
|
|
7206
|
-
});
|
|
7207
|
-
}
|
|
7208
|
-
/** Whether `path` lies strictly inside `dir`. */
|
|
7209
|
-
function isInside(dir, path) {
|
|
7210
|
-
const inner = relative(dir, path);
|
|
7211
|
-
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
7212
|
-
}
|
|
7213
|
-
/**
|
|
7214
|
-
* The global npm install this copy runs from, found by asking npm for its global prefix.
|
|
7215
|
-
* `bin` is the script that started the CLI; throws `NOT_GLOBAL_INSTALL` when it is not inside that install.
|
|
7216
|
-
*/
|
|
7217
|
-
async function globalInstallOf(bin, ctx) {
|
|
7218
|
-
if (bin === void 0) throw notGlobal(ctx, `${ctx.cliName} runs from source, not from an npm install`);
|
|
7219
|
-
const prefix = await globalPrefix(ctx);
|
|
7220
|
-
const packageDir = join(globalModulesDir(prefix), ctx.registry.package);
|
|
7221
|
-
const installed = await realpathOrUndefined(packageDir);
|
|
7222
|
-
const here = await realpathOrUndefined(bin) ?? bin;
|
|
7223
|
-
if (installed === void 0 || !isInside(installed, here)) throw notGlobal(ctx, `${ctx.cliName} runs from ${here}, not from npm's global install at ${packageDir}`);
|
|
7224
|
-
if ((await lstat(packageDir)).isSymbolicLink()) throw notGlobal(ctx, `${ctx.cliName} runs from a link to ${installed} (npm link), not from an npm install`);
|
|
7225
|
-
return {
|
|
7226
|
-
prefix,
|
|
7227
|
-
packageDir
|
|
7228
|
-
};
|
|
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;
|
|
7229
7224
|
}
|
|
7230
7225
|
//#endregion
|
|
7231
|
-
//#region ../agent-cli/dist/built-ins/dependency
|
|
7232
|
-
const MANAGERS = [
|
|
7233
|
-
"pnpm",
|
|
7234
|
-
"npm",
|
|
7235
|
-
"yarn",
|
|
7236
|
-
"bun"
|
|
7237
|
-
];
|
|
7238
|
-
const LOCKFILES = [
|
|
7239
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
7240
|
-
["package-lock.json", "npm"],
|
|
7241
|
-
["yarn.lock", "yarn"],
|
|
7242
|
-
["bun.lock", "bun"],
|
|
7243
|
-
["bun.lockb", "bun"]
|
|
7244
|
-
];
|
|
7226
|
+
//#region ../agent-cli/dist/built-ins/install/dependency.js
|
|
7245
7227
|
const LINES = {
|
|
7246
7228
|
pnpm: {
|
|
7247
7229
|
upgrade: (packages) => `pnpm up --latest ${packages.join(" ")}`,
|
|
@@ -7254,46 +7236,7 @@ const LINES = {
|
|
|
7254
7236
|
install: "npm install"
|
|
7255
7237
|
}
|
|
7256
7238
|
};
|
|
7257
|
-
const manifestSchema$1 = object({
|
|
7258
|
-
packageManager: string().optional(),
|
|
7259
|
-
dependencies: record(string(), unknown()).optional(),
|
|
7260
|
-
devDependencies: record(string(), unknown()).optional()
|
|
7261
|
-
});
|
|
7262
7239
|
const packageSchema = object({ version: string() });
|
|
7263
|
-
/** `dir` and every folder above it, nearest first. */
|
|
7264
|
-
function ancestorsOf(dir) {
|
|
7265
|
-
const parent = dirname(dir);
|
|
7266
|
-
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
7267
|
-
}
|
|
7268
|
-
async function exists(path) {
|
|
7269
|
-
try {
|
|
7270
|
-
await stat(path);
|
|
7271
|
-
return true;
|
|
7272
|
-
} catch (error) {
|
|
7273
|
-
if (isMissingFile(error)) return false;
|
|
7274
|
-
throw error;
|
|
7275
|
-
}
|
|
7276
|
-
}
|
|
7277
|
-
async function manifestIn(dir) {
|
|
7278
|
-
let text;
|
|
7279
|
-
try {
|
|
7280
|
-
text = await readFile(join(dir, "package.json"), "utf8");
|
|
7281
|
-
} catch (error) {
|
|
7282
|
-
if (isMissingFile(error)) return void 0;
|
|
7283
|
-
throw error;
|
|
7284
|
-
}
|
|
7285
|
-
let manifest;
|
|
7286
|
-
try {
|
|
7287
|
-
manifest = JSON.parse(text);
|
|
7288
|
-
} catch {
|
|
7289
|
-
return;
|
|
7290
|
-
}
|
|
7291
|
-
return manifestSchema$1.safeParse(manifest).data;
|
|
7292
|
-
}
|
|
7293
|
-
async function declaredManager(dir) {
|
|
7294
|
-
const name = (await manifestIn(dir))?.packageManager?.split("@")[0];
|
|
7295
|
-
return MANAGERS.find((manager) => manager === name);
|
|
7296
|
-
}
|
|
7297
7240
|
async function manifestListing(name, cwd, root) {
|
|
7298
7241
|
const dirs = ancestorsOf(cwd);
|
|
7299
7242
|
const top = root === void 0 ? dirs.length : dirs.indexOf(root.dir) + 1;
|
|
@@ -7302,16 +7245,6 @@ async function manifestListing(name, cwd, root) {
|
|
|
7302
7245
|
if (manifest?.dependencies?.[name] !== void 0 || manifest?.devDependencies?.[name] !== void 0) return join(dir, "package.json");
|
|
7303
7246
|
}
|
|
7304
7247
|
}
|
|
7305
|
-
async function lockfileRootOf(cwd) {
|
|
7306
|
-
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
7307
|
-
dir,
|
|
7308
|
-
manager: await declaredManager(dir) ?? kind
|
|
7309
|
-
};
|
|
7310
|
-
}
|
|
7311
|
-
/** The package manager's project root: the folder of the nearest lockfile, or `cwd` without one. */
|
|
7312
|
-
async function projectRootOf(cwd) {
|
|
7313
|
-
return (await lockfileRootOf(cwd))?.dir ?? cwd;
|
|
7314
|
-
}
|
|
7315
7248
|
async function versionIn(manifest) {
|
|
7316
7249
|
try {
|
|
7317
7250
|
return packageSchema.parse(JSON.parse(await readFile(manifest, "utf8"))).version;
|
|
@@ -7341,10 +7274,7 @@ async function standingOf(install, bin, cwd, root) {
|
|
|
7341
7274
|
kind: "linked",
|
|
7342
7275
|
copy
|
|
7343
7276
|
};
|
|
7344
|
-
const runningFrom = await realpath(bin)
|
|
7345
|
-
if (isMissingFile(error)) return bin;
|
|
7346
|
-
throw error;
|
|
7347
|
-
});
|
|
7277
|
+
const runningFrom = await orMissing(realpath(bin)) ?? bin;
|
|
7348
7278
|
return isInside(copy.realDir, runningFrom) ? {
|
|
7349
7279
|
kind: "installed",
|
|
7350
7280
|
copy
|
|
@@ -7395,7 +7325,7 @@ function problem(message, fix) {
|
|
|
7395
7325
|
};
|
|
7396
7326
|
}
|
|
7397
7327
|
/** The `install` row of a Dependency install. */
|
|
7398
|
-
function
|
|
7328
|
+
function installFinding(cli, runAs, install, { cwd, root, standing }) {
|
|
7399
7329
|
const lines = root === void 0 ? void 0 : LINES[root.manager];
|
|
7400
7330
|
switch (standing.kind) {
|
|
7401
7331
|
case "source":
|
|
@@ -7405,7 +7335,7 @@ function dependencyInstallFinding(cli, install, { cwd, root, standing }) {
|
|
|
7405
7335
|
case "unreadable": return problem(`${standing.manifest} is not a package.json with a version: ${standing.reason}`, lines?.install);
|
|
7406
7336
|
case "other": {
|
|
7407
7337
|
const { copy, runningFrom } = standing;
|
|
7408
|
-
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`);
|
|
7409
7339
|
}
|
|
7410
7340
|
case "installed": {
|
|
7411
7341
|
const { copy } = standing;
|
|
@@ -7435,97 +7365,36 @@ function adviceFor(install, root, latest) {
|
|
|
7435
7365
|
if (lines !== void 0) return { fix: lines.upgrade(packages) };
|
|
7436
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"}` };
|
|
7437
7367
|
}
|
|
7438
|
-
function
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
advise: (latest) => adviceFor(install, root, latest)
|
|
7444
|
-
};
|
|
7445
|
-
}
|
|
7446
|
-
//#endregion
|
|
7447
|
-
//#region ../agent-cli/dist/built-ins/agents-md.js
|
|
7448
|
-
/** One paragraph telling every session that the CLI exists, how to run it and which skill to load. */
|
|
7449
|
-
function agentsBlock(cli) {
|
|
7450
|
-
const { install } = cli;
|
|
7451
|
-
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` : "";
|
|
7452
|
-
const what = cli.description.replace(/\.$/, "");
|
|
7453
|
-
return `\`${cli.name}\`: ${what}. Run it as \`${runAsOf(cli)}\`${where}. Load the \`${cli.name}\` skill before using it.`;
|
|
7454
|
-
}
|
|
7455
|
-
function markersOf(name) {
|
|
7456
|
-
return {
|
|
7457
|
-
begin: `<!-- BEGIN:${name} -->`,
|
|
7458
|
-
end: `<!-- END:${name} -->`
|
|
7459
|
-
};
|
|
7460
|
-
}
|
|
7461
|
-
/** `text` with the CLI's block between its markers, appended when they are missing; nothing else changes. */
|
|
7462
|
-
function withBlock(cli, text) {
|
|
7463
|
-
const { begin, end } = markersOf(cli.name);
|
|
7464
|
-
const whole = `${begin}\n${agentsBlock(cli)}\n${end}`;
|
|
7465
|
-
const start = text.indexOf(begin);
|
|
7466
|
-
const stop = start === -1 ? -1 : text.indexOf(end, start);
|
|
7467
|
-
if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
|
|
7468
|
-
if (text === "") return `${whole}\n`;
|
|
7469
|
-
return `${text}${text.endsWith("\n") ? "" : "\n"}\n${whole}\n`;
|
|
7470
|
-
}
|
|
7471
|
-
async function agentsMdAt(cli, root) {
|
|
7472
|
-
const path = join(root, "AGENTS.md");
|
|
7473
|
-
const existing = await orMissing(readFile(path, "utf8"));
|
|
7474
|
-
const block = agentsBlock(cli);
|
|
7475
|
-
if (existing === void 0) return {
|
|
7476
|
-
path,
|
|
7477
|
-
block,
|
|
7478
|
-
change: "create"
|
|
7479
|
-
};
|
|
7480
|
-
if (withBlock(cli, existing) === existing) return {
|
|
7481
|
-
path,
|
|
7482
|
-
block,
|
|
7483
|
-
change: null
|
|
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;
|
|
7484
7373
|
};
|
|
7485
7374
|
return {
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
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
|
+
}
|
|
7489
7384
|
};
|
|
7490
7385
|
}
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
const
|
|
7494
|
-
if (text === void 0 || text.split(/\r?\n/).some((line) => line.trim() === "@AGENTS.md")) return [];
|
|
7495
|
-
return [`add a line \`@AGENTS.md\` to ${claudeMd}, so Claude Code reads AGENTS.md`];
|
|
7496
|
-
}
|
|
7497
|
-
function agentsRow(cli) {
|
|
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);
|
|
7498
7389
|
return {
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
const { path, change } = await agentsMdAt(cli, root);
|
|
7504
|
-
const fix = `${runAsOf(cli)} skill install`;
|
|
7505
|
-
if (change === "rewrite") return {
|
|
7506
|
-
state: "problem",
|
|
7507
|
-
message: `${path} holds a ${cli.name} block other than the one ${fix} writes`,
|
|
7508
|
-
fix
|
|
7509
|
-
};
|
|
7510
|
-
if (change !== null) return {
|
|
7511
|
-
state: "problem",
|
|
7512
|
-
message: `${path} holds no ${cli.name} block, so sessions in this repo do not know ${cli.name}`,
|
|
7513
|
-
fix
|
|
7514
|
-
};
|
|
7515
|
-
const holds = `${path} holds the ${cli.name} block`;
|
|
7516
|
-
const [edit] = await handEditsAt(root);
|
|
7517
|
-
return edit === void 0 ? {
|
|
7518
|
-
state: "ok",
|
|
7519
|
-
message: holds
|
|
7520
|
-
} : {
|
|
7521
|
-
state: "problem",
|
|
7522
|
-
message: `${holds}; ${edit}`
|
|
7523
|
-
};
|
|
7524
|
-
}
|
|
7390
|
+
runAs,
|
|
7391
|
+
builtIns: () => ({}),
|
|
7392
|
+
exitClasses: [],
|
|
7393
|
+
check: (launch) => checkOf$1(cli, install, runAs, launch)
|
|
7525
7394
|
};
|
|
7526
7395
|
}
|
|
7527
7396
|
//#endregion
|
|
7528
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7397
|
+
//#region ../agent-cli/dist/built-ins/skill/hub.js
|
|
7529
7398
|
const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
|
|
7530
7399
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
7531
7400
|
const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
|
|
@@ -7583,479 +7452,168 @@ function fixFor(cliName, copies, source) {
|
|
|
7583
7452
|
if (has("unversioned") && add !== void 0) return has("behind") ? `${update} && ${add}` : add;
|
|
7584
7453
|
return has("behind") || has("unversioned") ? update : void 0;
|
|
7585
7454
|
}
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7455
|
+
const SKILL_STATE_NOTES = {
|
|
7456
|
+
current: "the same as this build",
|
|
7457
|
+
behind: "older than this build",
|
|
7458
|
+
ahead: "newer than this build",
|
|
7459
|
+
unversioned: "states no metadata.version",
|
|
7460
|
+
unreadable: "could not be read"
|
|
7461
|
+
};
|
|
7462
|
+
function describeCopy({ path, version, state }) {
|
|
7463
|
+
return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
|
|
7593
7464
|
}
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
}
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7465
|
+
/** A skill that `npx skills add` installs from `source`, the Skill Hub; with no `source`, no line adds it. */
|
|
7466
|
+
function hubSkill(cli, source) {
|
|
7467
|
+
const findingAt = async (version, ctx) => {
|
|
7468
|
+
const copies = await skillCopies(cli.name, version, ctx);
|
|
7469
|
+
const fix = fixFor(cli.name, copies, source);
|
|
7470
|
+
const message = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
|
|
7471
|
+
return fix === void 0 ? {
|
|
7472
|
+
state: "ok",
|
|
7473
|
+
message
|
|
7474
|
+
} : {
|
|
7475
|
+
state: "ok",
|
|
7476
|
+
message,
|
|
7477
|
+
fix
|
|
7478
|
+
};
|
|
7479
|
+
};
|
|
7603
7480
|
return {
|
|
7604
|
-
|
|
7605
|
-
|
|
7481
|
+
kind: "hub",
|
|
7482
|
+
builtIns: {},
|
|
7483
|
+
rows: [{
|
|
7484
|
+
name: "skill",
|
|
7485
|
+
advisory: true,
|
|
7486
|
+
run: (ctx) => findingAt(cli.version, ctx)
|
|
7487
|
+
}],
|
|
7488
|
+
notice: async () => {},
|
|
7489
|
+
findingAt
|
|
7606
7490
|
};
|
|
7607
7491
|
}
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
recursive: true,
|
|
7612
|
-
withFileTypes: true
|
|
7613
|
-
})) ?? []).filter((entry) => entry.isFile()).map((entry) => relative(dir, join(entry.parentPath, entry.name))).sort();
|
|
7614
|
-
}
|
|
7615
|
-
/** The versions of the package's skill in `source` and of its copy in `copy`. */
|
|
7616
|
-
async function skillVersionsOf(source, copy) {
|
|
7617
|
-
const [shipped, installed] = await Promise.all([readFile(join(source, "SKILL.md"), "utf8"), orMissing(readFile(join(copy, "SKILL.md"), "utf8"))]);
|
|
7618
|
-
const packageVersion = skillVersionIn(shipped) ?? null;
|
|
7619
|
-
const copyVersion = installed === void 0 ? void 0 : skillVersionIn(installed) ?? null;
|
|
7492
|
+
//#endregion
|
|
7493
|
+
//#region ../agent-cli/dist/built-ins/agents-md.js
|
|
7494
|
+
function markersOf(name) {
|
|
7620
7495
|
return {
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
same: copyVersion === packageVersion
|
|
7496
|
+
begin: `<!-- BEGIN:${name} -->`,
|
|
7497
|
+
end: `<!-- END:${name} -->`
|
|
7624
7498
|
};
|
|
7625
7499
|
}
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
const
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
packageVersion: string().nullable(),
|
|
7636
|
-
/** A personal copy, which Claude Code prefers over the project's. */
|
|
7637
|
-
home: string().optional()
|
|
7638
|
-
});
|
|
7639
|
-
function versionLabel(version) {
|
|
7640
|
-
return version ?? "(no metadata.version)";
|
|
7641
|
-
}
|
|
7642
|
-
function compared(name, { copy, copyVersion, packageVersion }, same) {
|
|
7643
|
-
const stated = `${copy} ${versionLabel(copyVersion)}`;
|
|
7644
|
-
return same ? `${stated}, the version ${name} ships` : `${stated} differs from the ${versionLabel(packageVersion)} that ${name} ships`;
|
|
7500
|
+
/** `text` with the CLI's block between its markers, appended when they are missing; nothing else changes. */
|
|
7501
|
+
function withBlock({ name, text: block }, text) {
|
|
7502
|
+
const { begin, end } = markersOf(name);
|
|
7503
|
+
const whole = `${begin}\n${block}\n${end}`;
|
|
7504
|
+
const start = text.indexOf(begin);
|
|
7505
|
+
const stop = start === -1 ? -1 : text.indexOf(end, start);
|
|
7506
|
+
if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
|
|
7507
|
+
if (text === "") return `${whole}\n`;
|
|
7508
|
+
return `${text}${text.endsWith("\n") ? "" : "\n"}\n${whole}\n`;
|
|
7645
7509
|
}
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
const
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
const skill = {
|
|
7654
|
-
copy,
|
|
7655
|
-
copyVersion,
|
|
7656
|
-
packageVersion,
|
|
7657
|
-
...home === void 0 ? {} : { home }
|
|
7658
|
-
};
|
|
7659
|
-
const head = versions.copyVersion === void 0 ? `no copy of the ${cli.name} skill at ${copy}` : compared(cli.name, skill, versions.same);
|
|
7660
|
-
const message = home === void 0 ? head : `${head}; remove ${home}: Claude Code prefers a personal skill over the project's`;
|
|
7661
|
-
if (!versions.same) return {
|
|
7662
|
-
state: "problem",
|
|
7663
|
-
message,
|
|
7664
|
-
fix: `${runAsOf(cli)} skill install`,
|
|
7665
|
-
skill
|
|
7666
|
-
};
|
|
7667
|
-
return home === void 0 ? {
|
|
7668
|
-
state: "ok",
|
|
7669
|
-
message,
|
|
7670
|
-
skill
|
|
7671
|
-
} : {
|
|
7672
|
-
state: "problem",
|
|
7673
|
-
message,
|
|
7674
|
-
skill
|
|
7510
|
+
async function agentsMdAt(agents, root) {
|
|
7511
|
+
const path = join(root, "AGENTS.md");
|
|
7512
|
+
const existing = await orMissing(readFile(path, "utf8"));
|
|
7513
|
+
if (existing === void 0) return {
|
|
7514
|
+
path,
|
|
7515
|
+
agents,
|
|
7516
|
+
change: "create"
|
|
7675
7517
|
};
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
const folder = packagedFolderOf(cli);
|
|
7681
|
-
if (folder === void 0) return;
|
|
7682
|
-
let finding;
|
|
7683
|
-
try {
|
|
7684
|
-
finding = await packagedSkillFinding(cli, folder, ctx);
|
|
7685
|
-
} catch (error) {
|
|
7686
|
-
if (errnoOf(error) === void 0) throw error;
|
|
7687
|
-
ctx.notice(`could not check the ${cli.name} skill: ${messageOf(error)}`);
|
|
7688
|
-
return;
|
|
7689
|
-
}
|
|
7690
|
-
if (finding.state !== "problem") return;
|
|
7691
|
-
ctx.notice(finding.fix === void 0 ? finding.message : `${finding.message}; run \`${finding.fix}\``);
|
|
7692
|
-
}
|
|
7693
|
-
//#endregion
|
|
7694
|
-
//#region ../agent-cli/dist/built-ins/doctor-rows.js
|
|
7695
|
-
function ok(message) {
|
|
7696
|
-
return {
|
|
7697
|
-
state: "ok",
|
|
7698
|
-
message
|
|
7518
|
+
if (withBlock(agents, existing) === existing) return {
|
|
7519
|
+
path,
|
|
7520
|
+
agents,
|
|
7521
|
+
change: null
|
|
7699
7522
|
};
|
|
7700
|
-
}
|
|
7701
|
-
function noInstall(cli) {
|
|
7702
7523
|
return {
|
|
7703
|
-
|
|
7704
|
-
|
|
7524
|
+
path,
|
|
7525
|
+
agents,
|
|
7526
|
+
change: existing.includes(markersOf(agents.name).begin) ? "rewrite" : "add"
|
|
7705
7527
|
};
|
|
7706
7528
|
}
|
|
7707
|
-
function
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
};
|
|
7529
|
+
async function handEditsAt(root) {
|
|
7530
|
+
const claudeMd = join(root, "CLAUDE.md");
|
|
7531
|
+
const text = await orMissing(readFile(claudeMd, "utf8"));
|
|
7532
|
+
if (text === void 0 || text.split(/\r?\n/).some((line) => line.trim() === "@AGENTS.md")) return [];
|
|
7533
|
+
return [`add a line \`@AGENTS.md\` to ${claudeMd}, so Claude Code reads AGENTS.md`];
|
|
7712
7534
|
}
|
|
7713
|
-
function
|
|
7535
|
+
function agentsRow(agents, install) {
|
|
7536
|
+
const { name } = agents;
|
|
7714
7537
|
return {
|
|
7715
|
-
name: "
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
const
|
|
7719
|
-
|
|
7720
|
-
const
|
|
7721
|
-
if (
|
|
7538
|
+
name: "agents",
|
|
7539
|
+
advisory: true,
|
|
7540
|
+
run: async (ctx) => {
|
|
7541
|
+
const root = await projectRootOf(ctx.cwd);
|
|
7542
|
+
const { path, change } = await agentsMdAt(agents, root);
|
|
7543
|
+
const fix = `${install.runAs} skill install`;
|
|
7544
|
+
if (change === "rewrite") return {
|
|
7722
7545
|
state: "problem",
|
|
7723
|
-
message: `${
|
|
7546
|
+
message: `${path} holds a ${name} block other than the one ${fix} writes`,
|
|
7547
|
+
fix
|
|
7724
7548
|
};
|
|
7725
|
-
if (
|
|
7726
|
-
const major = minimum[0];
|
|
7727
|
-
return {
|
|
7549
|
+
if (change !== null) return {
|
|
7728
7550
|
state: "problem",
|
|
7729
|
-
message: `${
|
|
7730
|
-
fix
|
|
7551
|
+
message: `${path} holds no ${name} block, so sessions in this repo do not know ${name}`,
|
|
7552
|
+
fix
|
|
7553
|
+
};
|
|
7554
|
+
const holds = `${path} holds the ${name} block`;
|
|
7555
|
+
const [edit] = await handEditsAt(root);
|
|
7556
|
+
return edit === void 0 ? {
|
|
7557
|
+
state: "ok",
|
|
7558
|
+
message: holds
|
|
7559
|
+
} : {
|
|
7560
|
+
state: "problem",
|
|
7561
|
+
message: `${holds}; ${edit}`
|
|
7731
7562
|
};
|
|
7732
7563
|
}
|
|
7733
7564
|
};
|
|
7734
7565
|
}
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7566
|
+
//#endregion
|
|
7567
|
+
//#region ../agent-cli/dist/agent.js
|
|
7568
|
+
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7569
|
+
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7570
|
+
const equals = (name, value) => (env) => env[name] === value;
|
|
7571
|
+
const MARKERS = [
|
|
7572
|
+
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
7573
|
+
equals("AGENT", "amp"),
|
|
7574
|
+
isSet("CODEX_SANDBOX"),
|
|
7575
|
+
isSet("CODEX_CI"),
|
|
7576
|
+
isSet("CODEX_THREAD_ID"),
|
|
7577
|
+
isSet("GEMINI_CLI"),
|
|
7578
|
+
isSet("COPILOT_CLI"),
|
|
7579
|
+
isSet("OPENCODE"),
|
|
7580
|
+
isSet("ANTIGRAVITY_AGENT"),
|
|
7581
|
+
isSet("AUGMENT_AGENT"),
|
|
7582
|
+
isSet("REPL_ID"),
|
|
7583
|
+
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
7584
|
+
isSet("CLAUDECODE"),
|
|
7585
|
+
isSet("CLAUDE_CODE"),
|
|
7586
|
+
isSet("CURSOR_TRACE_ID"),
|
|
7587
|
+
isSet("CURSOR_AGENT"),
|
|
7588
|
+
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
7589
|
+
equals("TERM_PROGRAM", "kiro"),
|
|
7590
|
+
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
7591
|
+
isSet("GOOSE_PROVIDER")
|
|
7592
|
+
];
|
|
7593
|
+
/**
|
|
7594
|
+
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
7595
|
+
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
7596
|
+
*/
|
|
7597
|
+
function isAgent(env) {
|
|
7598
|
+
return MARKERS.some((marker) => marker(env));
|
|
7766
7599
|
}
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7600
|
+
//#endregion
|
|
7601
|
+
//#region ../agent-cli/dist/errno.js
|
|
7602
|
+
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
7603
|
+
const DISK_FULL = "DISK_FULL";
|
|
7604
|
+
const NOT_FOUND = "NOT_FOUND";
|
|
7605
|
+
const ALREADY_EXISTS = "ALREADY_EXISTS";
|
|
7606
|
+
const NOT_A_FILE = "NOT_A_FILE";
|
|
7607
|
+
function permissionHint({ path, access, callerLine, env, platform }) {
|
|
7608
|
+
if (platform === "win32") return `a program may hold ${path} open: close it, then run \`${callerLine}\` again`;
|
|
7609
|
+
if (!isAgent(env)) return `check the permissions of ${path} and its folder`;
|
|
7610
|
+
return `your sandbox may block it: ask your user to run \`! ${callerLine}\`, or ${access === "read" ? `to allow reading ${path} in the sandbox` : `to allow ${path} in the sandbox's write list`}`;
|
|
7775
7611
|
}
|
|
7776
|
-
function
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
};
|
|
7782
|
-
}
|
|
7783
|
-
function installRow(cli, { bin, node }, survey) {
|
|
7784
|
-
return {
|
|
7785
|
-
name: "install",
|
|
7786
|
-
advisory: true,
|
|
7787
|
-
run: async (ctx) => {
|
|
7788
|
-
const { install } = cli;
|
|
7789
|
-
if (install === void 0) return noInstall(cli);
|
|
7790
|
-
if (install.mode === "dependency") return dependencyInstallFinding(cli, install, await survey(install, ctx.cwd));
|
|
7791
|
-
const npm = globalNpm(cli, install, ctx, node);
|
|
7792
|
-
try {
|
|
7793
|
-
return ok(`a global npm install under ${(await globalInstallOf(bin, npm)).prefix}`);
|
|
7794
|
-
} catch (error) {
|
|
7795
|
-
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
7796
|
-
state: "problem",
|
|
7797
|
-
message: error.message,
|
|
7798
|
-
fix: installCommandLine(npm.registry)
|
|
7799
|
-
};
|
|
7800
|
-
throw error;
|
|
7801
|
-
}
|
|
7802
|
-
}
|
|
7803
|
-
};
|
|
7804
|
-
}
|
|
7805
|
-
async function releaseLookupOf(cli, install, ctx, node, survey) {
|
|
7806
|
-
if (install.mode === "global") {
|
|
7807
|
-
const fix = `${cli.name} update`;
|
|
7808
|
-
return {
|
|
7809
|
-
npm: globalNpm(cli, install, ctx, node),
|
|
7810
|
-
advise: () => ({ fix })
|
|
7811
|
-
};
|
|
7812
|
-
}
|
|
7813
|
-
const release = dependencyRelease(cli, install, await survey(install, ctx.cwd));
|
|
7814
|
-
if ("skipped" in release) return release;
|
|
7815
|
-
return {
|
|
7816
|
-
npm: npmContext(cli, release.registry, ctx, node, release.cwd),
|
|
7817
|
-
advise: release.advise
|
|
7818
|
-
};
|
|
7819
|
-
}
|
|
7820
|
-
function registryRow(cli, { node }, survey) {
|
|
7821
|
-
return {
|
|
7822
|
-
name: "registry",
|
|
7823
|
-
advisory: true,
|
|
7824
|
-
run: async (ctx) => {
|
|
7825
|
-
const { install } = cli;
|
|
7826
|
-
if (install === void 0) return noInstall(cli);
|
|
7827
|
-
const lookup = await releaseLookupOf(cli, install, ctx, node, survey);
|
|
7828
|
-
if ("skipped" in lookup) return lookup.skipped;
|
|
7829
|
-
const { npm, advise } = lookup;
|
|
7830
|
-
const latest = await latestVersion(npm);
|
|
7831
|
-
const standing = standingOf$1(cli.version, latest);
|
|
7832
|
-
const head = `${npm.registry.label} has ${latest} as latest: this build`;
|
|
7833
|
-
if (standing === "behind") {
|
|
7834
|
-
const message = `${head} (${cli.version}) is older`;
|
|
7835
|
-
const advice = advise(latest);
|
|
7836
|
-
return "fix" in advice ? {
|
|
7837
|
-
state: "problem",
|
|
7838
|
-
message,
|
|
7839
|
-
fix: advice.fix
|
|
7840
|
-
} : {
|
|
7841
|
-
state: "problem",
|
|
7842
|
-
message: `${message}; ${advice.note}`
|
|
7843
|
-
};
|
|
7844
|
-
}
|
|
7845
|
-
return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
|
|
7846
|
-
}
|
|
7847
|
-
};
|
|
7848
|
-
}
|
|
7849
|
-
const SKILL_STATE_NOTES = {
|
|
7850
|
-
current: "the same as this build",
|
|
7851
|
-
behind: "older than this build",
|
|
7852
|
-
ahead: "newer than this build",
|
|
7853
|
-
unversioned: "states no metadata.version",
|
|
7854
|
-
unreadable: "could not be read"
|
|
7855
|
-
};
|
|
7856
|
-
function describeCopy({ path, version, state }) {
|
|
7857
|
-
return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
|
|
7858
|
-
}
|
|
7859
|
-
function skillRow(cli) {
|
|
7860
|
-
const packaged = packagedFolderOf(cli);
|
|
7861
|
-
return {
|
|
7862
|
-
name: "skill",
|
|
7863
|
-
advisory: true,
|
|
7864
|
-
run: async (ctx) => {
|
|
7865
|
-
if (packaged !== void 0) return packagedSkillFinding(cli, packaged, ctx);
|
|
7866
|
-
const { copies, fix } = await skillReport(cli, cli.version, ctx);
|
|
7867
|
-
const message = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
|
|
7868
|
-
return fix === void 0 ? ok(message) : {
|
|
7869
|
-
state: "ok",
|
|
7870
|
-
message,
|
|
7871
|
-
fix
|
|
7872
|
-
};
|
|
7873
|
-
}
|
|
7874
|
-
};
|
|
7875
|
-
}
|
|
7876
|
-
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
7877
|
-
function doctorChecks(cli, launch, read) {
|
|
7878
|
-
const survey = surveyOnce(launch.bin);
|
|
7879
|
-
return [
|
|
7880
|
-
buildRow(cli),
|
|
7881
|
-
nodeRow(cli),
|
|
7882
|
-
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
7883
|
-
...cli.doctor ?? [],
|
|
7884
|
-
...toolRows(cli.tools ?? [], cli.commands),
|
|
7885
|
-
installRow(cli, launch, survey),
|
|
7886
|
-
registryRow(cli, launch, survey),
|
|
7887
|
-
skillRow(cli),
|
|
7888
|
-
...packagedFolderOf(cli) === void 0 ? [] : [agentsRow(cli)]
|
|
7889
|
-
];
|
|
7890
|
-
}
|
|
7891
|
-
//#endregion
|
|
7892
|
-
//#region ../agent-cli/dist/built-ins/doctor.js
|
|
7893
|
-
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
7894
|
-
const DEFAULT_DEADLINE_MS = 1e4;
|
|
7895
|
-
const MS_PER_SECOND = 1e3;
|
|
7896
|
-
const MIN_LABEL_WIDTH = 8;
|
|
7897
|
-
const reportSchema = object({
|
|
7898
|
-
rows: array(object({
|
|
7899
|
-
check: string(),
|
|
7900
|
-
state: _enum([
|
|
7901
|
-
"ok",
|
|
7902
|
-
"problem",
|
|
7903
|
-
"skipped"
|
|
7904
|
-
]),
|
|
7905
|
-
message: string(),
|
|
7906
|
-
fix: string().optional(),
|
|
7907
|
-
code: string().optional(),
|
|
7908
|
-
skill: packagedSkillDetailsSchema.optional()
|
|
7909
|
-
})),
|
|
7910
|
-
next: array(string())
|
|
7911
|
-
});
|
|
7912
|
-
function problemOf(check, error, { signal, deadline, ms }) {
|
|
7913
|
-
if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
|
|
7914
|
-
state: "problem",
|
|
7915
|
-
message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
|
|
7916
|
-
};
|
|
7917
|
-
return problemOfError(check.name, error);
|
|
7918
|
-
}
|
|
7919
|
-
function rowContext(ctx, signal, read) {
|
|
7920
|
-
return Object.create(ctx, {
|
|
7921
|
-
signal: { value: signal },
|
|
7922
|
-
project: { get: () => {
|
|
7923
|
-
if (!read.ok) throw read.error;
|
|
7924
|
-
return read.project;
|
|
7925
|
-
} }
|
|
7926
|
-
});
|
|
7927
|
-
}
|
|
7928
|
-
async function rowOf(check, ctx, read) {
|
|
7929
|
-
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
7930
|
-
const signal = ctx.deadline(ms);
|
|
7931
|
-
let finding;
|
|
7932
|
-
try {
|
|
7933
|
-
finding = await Promise.race([Promise.resolve().then(() => check.run(rowContext(ctx, signal, read))), untilAborted(signal)]);
|
|
7934
|
-
} catch (error) {
|
|
7935
|
-
if (ctx.signal.aborted) return void 0;
|
|
7936
|
-
finding = !read.ok && error === read.error ? {
|
|
7937
|
-
state: "skipped",
|
|
7938
|
-
message: "the Project file is unusable; the project row says why"
|
|
7939
|
-
} : problemOf(check, error, {
|
|
7940
|
-
signal: ctx.signal,
|
|
7941
|
-
deadline: signal,
|
|
7942
|
-
ms
|
|
7943
|
-
});
|
|
7944
|
-
}
|
|
7945
|
-
return {
|
|
7946
|
-
row: {
|
|
7947
|
-
check: check.name,
|
|
7948
|
-
...finding
|
|
7949
|
-
},
|
|
7950
|
-
advisory: check.advisory === true
|
|
7951
|
-
};
|
|
7952
|
-
}
|
|
7953
|
-
function nextOf(rows) {
|
|
7954
|
-
return [...new Set(rows.flatMap(({ fix }) => fix === void 0 ? [] : [fix]))];
|
|
7955
|
-
}
|
|
7956
|
-
function render({ rows, next }, style) {
|
|
7957
|
-
const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
|
|
7958
|
-
const stateWidth = Math.max(...rows.map(({ state }) => state.length)) + 2;
|
|
7959
|
-
return [...rows.map(({ check, state, message }) => {
|
|
7960
|
-
const label = state === "problem" ? style.red(state) : state;
|
|
7961
|
-
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
7962
|
-
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
7963
|
-
}
|
|
7964
|
-
function failure(cliName, callerLine, problems) {
|
|
7965
|
-
const errors = problems.map(({ check, message, fix, code }) => new CliError({
|
|
7966
|
-
code: code ?? "DOCTOR_PROBLEMS",
|
|
7967
|
-
message: `${cliName} doctor found a problem in ${check}: ${message}`,
|
|
7968
|
-
hint: fix === void 0 ? "the row says what is wrong" : `run \`${fix}\`, then run \`${callerLine}\` again`
|
|
7969
|
-
}));
|
|
7970
|
-
return new AggregateError(errors);
|
|
7971
|
-
}
|
|
7972
|
-
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
7973
|
-
function doctorCommand(cli, launch) {
|
|
7974
|
-
return defineCommand$1({
|
|
7975
|
-
name: "doctor",
|
|
7976
|
-
description: "check the setup and say what fixes each problem",
|
|
7977
|
-
examples: [{
|
|
7978
|
-
command: `${runAsOf(cli)} doctor`,
|
|
7979
|
-
note: "check the setup and list the commands that fix it"
|
|
7980
|
-
}, {
|
|
7981
|
-
command: `${runAsOf(cli)} doctor --json`,
|
|
7982
|
-
note: "get the rows and fixes as data"
|
|
7983
|
-
}],
|
|
7984
|
-
effect: "read",
|
|
7985
|
-
output: reportSchema,
|
|
7986
|
-
run: async (_input, ctx) => {
|
|
7987
|
-
const read = readProject(cli.project, ctx);
|
|
7988
|
-
const checked = (await Promise.all(doctorChecks(cli, launch, read).map((check) => rowOf(check, ctx, read)))).filter((row) => row !== void 0);
|
|
7989
|
-
const rows = checked.map(({ row }) => row);
|
|
7990
|
-
const report = {
|
|
7991
|
-
rows,
|
|
7992
|
-
next: nextOf(rows)
|
|
7993
|
-
};
|
|
7994
|
-
if (ctx.signal.aborted) {
|
|
7995
|
-
ctx.deliver(report);
|
|
7996
|
-
ctx.signal.throwIfAborted();
|
|
7997
|
-
}
|
|
7998
|
-
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
7999
|
-
if (problems.length > 0) {
|
|
8000
|
-
ctx.deliver(report);
|
|
8001
|
-
throw failure(cli.name, ctx.commandLine(), problems);
|
|
8002
|
-
}
|
|
8003
|
-
return report;
|
|
8004
|
-
},
|
|
8005
|
-
render
|
|
8006
|
-
});
|
|
8007
|
-
}
|
|
8008
|
-
//#endregion
|
|
8009
|
-
//#region ../agent-cli/dist/agent.js
|
|
8010
|
-
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
8011
|
-
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
8012
|
-
const equals = (name, value) => (env) => env[name] === value;
|
|
8013
|
-
const MARKERS = [
|
|
8014
|
-
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
8015
|
-
equals("AGENT", "amp"),
|
|
8016
|
-
isSet("CODEX_SANDBOX"),
|
|
8017
|
-
isSet("CODEX_CI"),
|
|
8018
|
-
isSet("CODEX_THREAD_ID"),
|
|
8019
|
-
isSet("GEMINI_CLI"),
|
|
8020
|
-
isSet("COPILOT_CLI"),
|
|
8021
|
-
isSet("OPENCODE"),
|
|
8022
|
-
isSet("ANTIGRAVITY_AGENT"),
|
|
8023
|
-
isSet("AUGMENT_AGENT"),
|
|
8024
|
-
isSet("REPL_ID"),
|
|
8025
|
-
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
8026
|
-
isSet("CLAUDECODE"),
|
|
8027
|
-
isSet("CLAUDE_CODE"),
|
|
8028
|
-
isSet("CURSOR_TRACE_ID"),
|
|
8029
|
-
isSet("CURSOR_AGENT"),
|
|
8030
|
-
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
8031
|
-
equals("TERM_PROGRAM", "kiro"),
|
|
8032
|
-
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
8033
|
-
isSet("GOOSE_PROVIDER")
|
|
8034
|
-
];
|
|
8035
|
-
/**
|
|
8036
|
-
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
8037
|
-
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
8038
|
-
*/
|
|
8039
|
-
function isAgent(env) {
|
|
8040
|
-
return MARKERS.some((marker) => marker(env));
|
|
8041
|
-
}
|
|
8042
|
-
//#endregion
|
|
8043
|
-
//#region ../agent-cli/dist/errno.js
|
|
8044
|
-
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
8045
|
-
const DISK_FULL = "DISK_FULL";
|
|
8046
|
-
const NOT_FOUND = "NOT_FOUND";
|
|
8047
|
-
const ALREADY_EXISTS = "ALREADY_EXISTS";
|
|
8048
|
-
const NOT_A_FILE = "NOT_A_FILE";
|
|
8049
|
-
function permissionHint({ path, access, callerLine, env, platform }) {
|
|
8050
|
-
if (platform === "win32") return `a program may hold ${path} open: close it, then run \`${callerLine}\` again`;
|
|
8051
|
-
if (!isAgent(env)) return `check the permissions of ${path} and its folder`;
|
|
8052
|
-
return `your sandbox may block it: ask your user to run \`! ${callerLine}\`, or ${access === "read" ? `to allow reading ${path} in the sandbox` : `to allow ${path} in the sandbox's write list`}`;
|
|
8053
|
-
}
|
|
8054
|
-
function fileErrorOf(scope) {
|
|
8055
|
-
return (error, at) => classifyErrno(error, {
|
|
8056
|
-
...at,
|
|
8057
|
-
...scope
|
|
8058
|
-
});
|
|
7612
|
+
function fileErrorOf(scope) {
|
|
7613
|
+
return (error, at) => classifyErrno(error, {
|
|
7614
|
+
...at,
|
|
7615
|
+
...scope
|
|
7616
|
+
});
|
|
8059
7617
|
}
|
|
8060
7618
|
function classifyErrno(error, context) {
|
|
8061
7619
|
const { path } = context;
|
|
@@ -8337,26 +7895,52 @@ async function probeOutputs({ files, cwd, fileError }, outputs) {
|
|
|
8337
7895
|
}));
|
|
8338
7896
|
}
|
|
8339
7897
|
//#endregion
|
|
8340
|
-
//#region ../agent-cli/dist/built-ins/skill-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
}
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
const [shipped,
|
|
8359
|
-
const
|
|
7898
|
+
//#region ../agent-cli/dist/built-ins/skill/install-command.js
|
|
7899
|
+
/** The project root and the Skill copy under it, as `skill install` writes it. */
|
|
7900
|
+
async function skillCopyOf(cli, cwd) {
|
|
7901
|
+
const root = await projectRootOf(cwd);
|
|
7902
|
+
return {
|
|
7903
|
+
root,
|
|
7904
|
+
copy: join(root, ".claude", "skills", cli.name)
|
|
7905
|
+
};
|
|
7906
|
+
}
|
|
7907
|
+
/** Every file under `dir`, relative to it and sorted; none when `dir` is missing. */
|
|
7908
|
+
async function filesIn(dir) {
|
|
7909
|
+
return (await orMissing(readdir(dir, {
|
|
7910
|
+
recursive: true,
|
|
7911
|
+
withFileTypes: true
|
|
7912
|
+
})) ?? []).filter((entry) => entry.isFile()).map((entry) => relative(dir, join(entry.parentPath, entry.name))).sort();
|
|
7913
|
+
}
|
|
7914
|
+
/** The versions of the package's skill in `source` and of its copy in `copy`. */
|
|
7915
|
+
async function skillVersionsOf(source, copy) {
|
|
7916
|
+
const [shipped, installed] = await Promise.all([readFile(join(source, "SKILL.md"), "utf8"), orMissing(readFile(join(copy, "SKILL.md"), "utf8"))]);
|
|
7917
|
+
const packageVersion = skillVersionIn(shipped) ?? null;
|
|
7918
|
+
const copyVersion = installed === void 0 ? void 0 : skillVersionIn(installed) ?? null;
|
|
7919
|
+
return {
|
|
7920
|
+
packageVersion,
|
|
7921
|
+
copyVersion,
|
|
7922
|
+
same: copyVersion === packageVersion
|
|
7923
|
+
};
|
|
7924
|
+
}
|
|
7925
|
+
const installSchema = object({
|
|
7926
|
+
copy: string(),
|
|
7927
|
+
written: array(string()),
|
|
7928
|
+
removed: array(string()),
|
|
7929
|
+
agentsMd: object({
|
|
7930
|
+
path: string(),
|
|
7931
|
+
changed: boolean()
|
|
7932
|
+
}).nullable(),
|
|
7933
|
+
handEdits: array(string())
|
|
7934
|
+
});
|
|
7935
|
+
async function sameContent(left, right) {
|
|
7936
|
+
const [a, b] = await Promise.all([readFile(left), readFile(right)]);
|
|
7937
|
+
return a.equals(b);
|
|
7938
|
+
}
|
|
7939
|
+
async function planOf(cli, folder, agents, cwd, packageRoot) {
|
|
7940
|
+
const source = join(packageRoot, folder);
|
|
7941
|
+
const { root, copy } = await skillCopyOf(cli, cwd);
|
|
7942
|
+
const [shipped, present] = await Promise.all([filesIn(source), filesIn(copy)]);
|
|
7943
|
+
const differs = await Promise.all(shipped.map(async (file) => present.includes(file) && !await sameContent(join(source, file), join(copy, file))));
|
|
8360
7944
|
return {
|
|
8361
7945
|
source,
|
|
8362
7946
|
copy,
|
|
@@ -8364,8 +7948,8 @@ async function planOf(cli, folder, cwd, packageRoot) {
|
|
|
8364
7948
|
replace: shipped.filter((_file, index) => differs[index]),
|
|
8365
7949
|
remove: present.filter((file) => !shipped.includes(file)),
|
|
8366
7950
|
sameVersion: (await skillVersionsOf(source, copy)).same,
|
|
8367
|
-
agentsMd: await agentsMdAt(
|
|
8368
|
-
handEdits: await handEditsAt(root)
|
|
7951
|
+
agentsMd: agents === void 0 ? null : await agentsMdAt(agents, root),
|
|
7952
|
+
handEdits: agents === void 0 ? [] : await handEditsAt(root)
|
|
8369
7953
|
};
|
|
8370
7954
|
}
|
|
8371
7955
|
const BLOCK_VERBS = {
|
|
@@ -8379,11 +7963,11 @@ function renderPlan(cli, plan) {
|
|
|
8379
7963
|
...plan.replace.map((file) => ` replace ${file}`),
|
|
8380
7964
|
...plan.remove.map((file) => ` remove ${file}`)
|
|
8381
7965
|
];
|
|
8382
|
-
const {
|
|
7966
|
+
const { agentsMd } = plan;
|
|
8383
7967
|
return [
|
|
8384
7968
|
files.length === 0 ? `the ${cli.name} skill at ${plan.copy} already matches the package` : `would copy the ${cli.name} skill to ${plan.copy}:`,
|
|
8385
7969
|
...files,
|
|
8386
|
-
change === null ? `${path} already holds the ${cli.name} block` : `would ${BLOCK_VERBS[change]} ${path}:\n${
|
|
7970
|
+
...agentsMd === null ? [] : [agentsMd.change === null ? `${agentsMd.path} already holds the ${cli.name} block` : `would ${BLOCK_VERBS[agentsMd.change]} ${agentsMd.path}:\n${agentsMd.agents.text}`],
|
|
8387
7971
|
...plan.handEdits.map((edit) => `by hand: ${edit}`)
|
|
8388
7972
|
].join("\n");
|
|
8389
7973
|
}
|
|
@@ -8391,7 +7975,7 @@ function renderInstalled(cli, data) {
|
|
|
8391
7975
|
const { written, removed, agentsMd } = data;
|
|
8392
7976
|
return [
|
|
8393
7977
|
written.length + removed.length === 0 ? `the ${cli.name} skill at ${data.copy} already matches the package` : `copied the ${cli.name} skill to ${data.copy}: wrote ${written.length} files, removed ${removed.length}`,
|
|
8394
|
-
agentsMd.changed ? `wrote the ${cli.name} block in ${agentsMd.path}` : `${agentsMd.path} already holds the ${cli.name} block
|
|
7978
|
+
...agentsMd === null ? [] : [agentsMd.changed ? `wrote the ${cli.name} block in ${agentsMd.path}` : `${agentsMd.path} already holds the ${cli.name} block`],
|
|
8395
7979
|
...data.handEdits.map((edit) => `by hand: ${edit}`)
|
|
8396
7980
|
].join("\n");
|
|
8397
7981
|
}
|
|
@@ -8404,11 +7988,11 @@ function editedRemovals(plan, ctx) {
|
|
|
8404
7988
|
});
|
|
8405
7989
|
}
|
|
8406
7990
|
/** The built-in `skill install`, for a CLI whose skill ships in its package. */
|
|
8407
|
-
function skillInstallCommand(cli, folder) {
|
|
8408
|
-
const runAs =
|
|
7991
|
+
function skillInstallCommand(cli, folder, install, agents) {
|
|
7992
|
+
const { runAs } = install;
|
|
8409
7993
|
return defineCommand$1({
|
|
8410
7994
|
name: "install",
|
|
8411
|
-
description: "copy this CLI's skill into the project and write its AGENTS.md block",
|
|
7995
|
+
description: agents === void 0 ? "copy this CLI's skill into the project" : "copy this CLI's skill into the project and write its AGENTS.md block",
|
|
8412
7996
|
examples: [{
|
|
8413
7997
|
command: `${runAs} skill install`,
|
|
8414
7998
|
note: "install the skill this version ships"
|
|
@@ -8419,24 +8003,24 @@ function skillInstallCommand(cli, folder) {
|
|
|
8419
8003
|
effect: "write",
|
|
8420
8004
|
output: installSchema,
|
|
8421
8005
|
force: "replace or remove hand-edited files of a skill copy at the package's version",
|
|
8422
|
-
plan: (_input, ctx) => planOf(cli, folder, ctx.cwd, ctx.packageRoot),
|
|
8006
|
+
plan: (_input, ctx) => planOf(cli, folder, agents, ctx.cwd, ctx.packageRoot),
|
|
8423
8007
|
outputs: (plan) => plan.sameVersion ? [...plan.write, ...plan.replace].map((file) => join(plan.copy, file)) : [],
|
|
8424
8008
|
apply: async (plan, ctx) => {
|
|
8425
8009
|
if (plan.sameVersion && plan.remove.length > 0 && !ctx.force) throw editedRemovals(plan, ctx);
|
|
8426
8010
|
for (const file of [...plan.write, ...plan.replace]) await ctx.files.write(join(plan.copy, file), await readFile(join(plan.source, file)));
|
|
8427
8011
|
for (const file of plan.remove) await ctx.files.remove(join(plan.copy, file));
|
|
8428
|
-
const {
|
|
8429
|
-
if (change !== null) {
|
|
8430
|
-
const existing = await orMissing(readFile(path, "utf8")) ?? "";
|
|
8431
|
-
await ctx.files.write(path, withBlock(
|
|
8012
|
+
const { agentsMd } = plan;
|
|
8013
|
+
if (agentsMd !== null && agentsMd.change !== null) {
|
|
8014
|
+
const existing = await orMissing(readFile(agentsMd.path, "utf8")) ?? "";
|
|
8015
|
+
await ctx.files.write(agentsMd.path, withBlock(agentsMd.agents, existing));
|
|
8432
8016
|
}
|
|
8433
8017
|
return {
|
|
8434
8018
|
copy: plan.copy,
|
|
8435
8019
|
written: [...plan.write, ...plan.replace].sort(),
|
|
8436
8020
|
removed: [...plan.remove],
|
|
8437
|
-
agentsMd: {
|
|
8438
|
-
path,
|
|
8439
|
-
changed: change !== null
|
|
8021
|
+
agentsMd: agentsMd === null ? null : {
|
|
8022
|
+
path: agentsMd.path,
|
|
8023
|
+
changed: agentsMd.change !== null
|
|
8440
8024
|
},
|
|
8441
8025
|
handEdits: [...plan.handEdits]
|
|
8442
8026
|
};
|
|
@@ -8446,6 +8030,97 @@ function skillInstallCommand(cli, folder) {
|
|
|
8446
8030
|
});
|
|
8447
8031
|
}
|
|
8448
8032
|
//#endregion
|
|
8033
|
+
//#region ../agent-cli/dist/built-ins/skill/packaged.js
|
|
8034
|
+
async function personalCopyOf(name, copy, ctx) {
|
|
8035
|
+
const home = join(homeOf(ctx.env), ".claude", "skills", name);
|
|
8036
|
+
const real = await orMissing(realpath(home));
|
|
8037
|
+
return real === void 0 || real === await orMissing(realpath(copy)) ? void 0 : home;
|
|
8038
|
+
}
|
|
8039
|
+
/** What the `skill` row of a Packaged skill carries under `--json` beside its message. */
|
|
8040
|
+
const packagedSkillDetailsSchema = object({
|
|
8041
|
+
copy: string(),
|
|
8042
|
+
copyVersion: string().nullable(),
|
|
8043
|
+
packageVersion: string().nullable(),
|
|
8044
|
+
/** A personal copy, which Claude Code prefers over the project's. */
|
|
8045
|
+
home: string().optional()
|
|
8046
|
+
});
|
|
8047
|
+
function versionLabel(version) {
|
|
8048
|
+
return version ?? "(no metadata.version)";
|
|
8049
|
+
}
|
|
8050
|
+
function compared(name, { copy, copyVersion, packageVersion }, same) {
|
|
8051
|
+
const stated = `${copy} ${versionLabel(copyVersion)}`;
|
|
8052
|
+
return same ? `${stated}, the version ${name} ships` : `${stated} differs from the ${versionLabel(packageVersion)} that ${name} ships`;
|
|
8053
|
+
}
|
|
8054
|
+
/** The project root's copy against the package's, and any under home. */
|
|
8055
|
+
async function findingOf(cli, folder, install, ctx) {
|
|
8056
|
+
const { copy } = await skillCopyOf(cli, ctx.cwd);
|
|
8057
|
+
const versions = await skillVersionsOf(join(ctx.packageRoot, folder), copy);
|
|
8058
|
+
const { packageVersion } = versions;
|
|
8059
|
+
const copyVersion = versions.copyVersion ?? null;
|
|
8060
|
+
const home = await personalCopyOf(cli.name, copy, ctx);
|
|
8061
|
+
const skill = {
|
|
8062
|
+
copy,
|
|
8063
|
+
copyVersion,
|
|
8064
|
+
packageVersion,
|
|
8065
|
+
...home === void 0 ? {} : { home }
|
|
8066
|
+
};
|
|
8067
|
+
const head = versions.copyVersion === void 0 ? `no copy of the ${cli.name} skill at ${copy}` : compared(cli.name, skill, versions.same);
|
|
8068
|
+
const message = home === void 0 ? head : `${head}; remove ${home}: Claude Code prefers a personal skill over the project's`;
|
|
8069
|
+
if (!versions.same) return {
|
|
8070
|
+
state: "problem",
|
|
8071
|
+
message,
|
|
8072
|
+
fix: `${install.runAs} skill install`,
|
|
8073
|
+
skill
|
|
8074
|
+
};
|
|
8075
|
+
return home === void 0 ? {
|
|
8076
|
+
state: "ok",
|
|
8077
|
+
message,
|
|
8078
|
+
skill
|
|
8079
|
+
} : {
|
|
8080
|
+
state: "problem",
|
|
8081
|
+
message,
|
|
8082
|
+
skill
|
|
8083
|
+
};
|
|
8084
|
+
}
|
|
8085
|
+
async function notice(cli, folder, install, { builtIn, bin }, ctx) {
|
|
8086
|
+
if (builtIn || bin === void 0 || cli.commands === void 0) return;
|
|
8087
|
+
let finding;
|
|
8088
|
+
try {
|
|
8089
|
+
finding = await findingOf(cli, folder, install, ctx);
|
|
8090
|
+
} catch (error) {
|
|
8091
|
+
if (errnoOf(error) === void 0) throw error;
|
|
8092
|
+
ctx.notice(`could not check the ${cli.name} skill: ${messageOf(error)}`);
|
|
8093
|
+
return;
|
|
8094
|
+
}
|
|
8095
|
+
if (finding.state !== "problem") return;
|
|
8096
|
+
ctx.notice(finding.fix === void 0 ? finding.message : `${finding.message}; run \`${finding.fix}\``);
|
|
8097
|
+
}
|
|
8098
|
+
/** A skill shipped in the package at `packaged`, which `skill install` copies to the project root. */
|
|
8099
|
+
function packagedSkill(cli, { packaged: folder, agents: text }, install) {
|
|
8100
|
+
const agents = text === void 0 ? void 0 : {
|
|
8101
|
+
name: cli.name,
|
|
8102
|
+
text
|
|
8103
|
+
};
|
|
8104
|
+
return {
|
|
8105
|
+
kind: "packaged",
|
|
8106
|
+
builtIns: { skill: { install: skillInstallCommand(cli, folder, install, agents) } },
|
|
8107
|
+
rows: [{
|
|
8108
|
+
name: "skill",
|
|
8109
|
+
advisory: true,
|
|
8110
|
+
run: (ctx) => findingOf(cli, folder, install, ctx)
|
|
8111
|
+
}, ...agents === void 0 ? [] : [agentsRow(agents, install)]],
|
|
8112
|
+
notice: (launch, ctx) => notice(cli, folder, install, launch, ctx),
|
|
8113
|
+
findingAt: (_version, ctx) => findingOf(cli, folder, install, ctx)
|
|
8114
|
+
};
|
|
8115
|
+
}
|
|
8116
|
+
//#endregion
|
|
8117
|
+
//#region ../agent-cli/dist/built-ins/skill/skill.js
|
|
8118
|
+
/** A Packaged skill, or else a Skill Hub's, also for a CLI that declares no `skill`. */
|
|
8119
|
+
function skillOf(cli, install) {
|
|
8120
|
+
const { skill } = cli;
|
|
8121
|
+
return skill !== void 0 && "packaged" in skill ? packagedSkill(cli, skill, install) : hubSkill(cli, skill?.source);
|
|
8122
|
+
}
|
|
8123
|
+
//#endregion
|
|
8449
8124
|
//#region ../agent-cli/dist/interrupts.js
|
|
8450
8125
|
const INTERRUPTED = "INTERRUPTED";
|
|
8451
8126
|
const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
|
|
@@ -8583,6 +8258,59 @@ var RunControl = class {
|
|
|
8583
8258
|
}
|
|
8584
8259
|
};
|
|
8585
8260
|
//#endregion
|
|
8261
|
+
//#region ../agent-cli/dist/built-ins/install/global-npm.js
|
|
8262
|
+
const NOT_GLOBAL_INSTALL = "NOT_GLOBAL_INSTALL";
|
|
8263
|
+
/** Where npm puts global packages under its global prefix. */
|
|
8264
|
+
function globalModulesDir(prefix) {
|
|
8265
|
+
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
8266
|
+
}
|
|
8267
|
+
function notGlobal(ctx, message) {
|
|
8268
|
+
return new CliError({
|
|
8269
|
+
code: NOT_GLOBAL_INSTALL,
|
|
8270
|
+
message,
|
|
8271
|
+
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.registry)}`
|
|
8272
|
+
});
|
|
8273
|
+
}
|
|
8274
|
+
/**
|
|
8275
|
+
* The global npm install this copy runs from, found by asking npm for its global prefix.
|
|
8276
|
+
* `bin` is the script that started the CLI; throws `NOT_GLOBAL_INSTALL` when it is not inside that install.
|
|
8277
|
+
*/
|
|
8278
|
+
async function globalInstallOf(bin, ctx) {
|
|
8279
|
+
if (bin === void 0) throw notGlobal(ctx, `${ctx.cliName} runs from source, not from an npm install`);
|
|
8280
|
+
const prefix = await globalPrefix(ctx);
|
|
8281
|
+
const packageDir = join(globalModulesDir(prefix), ctx.registry.package);
|
|
8282
|
+
const installed = await orMissing(realpath(packageDir));
|
|
8283
|
+
const here = await orMissing(realpath(bin)) ?? bin;
|
|
8284
|
+
if (installed === void 0 || !isInside(installed, here)) throw notGlobal(ctx, `${ctx.cliName} runs from ${here}, not from npm's global install at ${packageDir}`);
|
|
8285
|
+
if ((await lstat(packageDir)).isSymbolicLink()) throw notGlobal(ctx, `${ctx.cliName} runs from a link to ${installed} (npm link), not from an npm install`);
|
|
8286
|
+
return {
|
|
8287
|
+
prefix,
|
|
8288
|
+
packageDir
|
|
8289
|
+
};
|
|
8290
|
+
}
|
|
8291
|
+
const NPMJS = "https://registry.npmjs.org/";
|
|
8292
|
+
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
8293
|
+
function registryFlags({ package: name, registry }) {
|
|
8294
|
+
if (registry === NPMJS) return [];
|
|
8295
|
+
const scope = scopeOf(name);
|
|
8296
|
+
return [scope === void 0 ? `--registry=${registry}` : `--${scope}:registry=${registry}`];
|
|
8297
|
+
}
|
|
8298
|
+
function globalRegistry(install) {
|
|
8299
|
+
const { package: name, registry } = install;
|
|
8300
|
+
return {
|
|
8301
|
+
package: name,
|
|
8302
|
+
label: registry,
|
|
8303
|
+
flags: registryFlags(install),
|
|
8304
|
+
unreachableHint: "check the network or VPN",
|
|
8305
|
+
loginHint: `log in to ${registry} (\`npm login --registry=${registry}\`) or set its token in ~/.npmrc`,
|
|
8306
|
+
missingHint: `check that ${name} is published on ${registry}`
|
|
8307
|
+
};
|
|
8308
|
+
}
|
|
8309
|
+
/** npm for a Global install, run in the working directory. */
|
|
8310
|
+
function globalNpm(cli, install, ctx, node) {
|
|
8311
|
+
return npmContext(cli, globalRegistry(install), ctx, node, ctx.cwd);
|
|
8312
|
+
}
|
|
8313
|
+
//#endregion
|
|
8586
8314
|
//#region ../agent-cli/dist/built-ins/upgrades.js
|
|
8587
8315
|
/** A skipped release's Upgrade steps, or its whole section when it lists none. */
|
|
8588
8316
|
const upgradeSchema = union([object({
|
|
@@ -8675,10 +8403,9 @@ function renderUpdate(cli, install, update) {
|
|
|
8675
8403
|
...next
|
|
8676
8404
|
]).join("\n");
|
|
8677
8405
|
}
|
|
8678
|
-
async function skillNext(
|
|
8679
|
-
const
|
|
8680
|
-
|
|
8681
|
-
return "fix" in finding && finding.fix !== void 0 ? [finding.fix] : [];
|
|
8406
|
+
async function skillNext(skill, latest, ctx) {
|
|
8407
|
+
const { fix } = await skill.findingAt(latest, ctx);
|
|
8408
|
+
return fix === void 0 ? [] : [fix];
|
|
8682
8409
|
}
|
|
8683
8410
|
function interruptedAfterInstall(plan) {
|
|
8684
8411
|
return new CliError({
|
|
@@ -8688,7 +8415,7 @@ function interruptedAfterInstall(plan) {
|
|
|
8688
8415
|
});
|
|
8689
8416
|
}
|
|
8690
8417
|
/** The built-in `update`, for a CLI installed globally with npm. */
|
|
8691
|
-
function updateCommand(cli, install, { bin, node }) {
|
|
8418
|
+
function updateCommand(cli, install, skill, { bin, node }) {
|
|
8692
8419
|
return defineCommand$1({
|
|
8693
8420
|
name: "update",
|
|
8694
8421
|
description: "install the latest version of this CLI from its registry",
|
|
@@ -8719,7 +8446,7 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
8719
8446
|
latest,
|
|
8720
8447
|
installed: null,
|
|
8721
8448
|
upgrades: [],
|
|
8722
|
-
next: await skillNext(
|
|
8449
|
+
next: await skillNext(skill, latest, ctx)
|
|
8723
8450
|
};
|
|
8724
8451
|
ctx.signal.throwIfAborted();
|
|
8725
8452
|
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
@@ -8732,7 +8459,7 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
8732
8459
|
prefix
|
|
8733
8460
|
},
|
|
8734
8461
|
upgrades: await upgradesOf(plan.packageDir, from, latest),
|
|
8735
|
-
next: await skillNext(
|
|
8462
|
+
next: await skillNext(skill, latest, ctx)
|
|
8736
8463
|
};
|
|
8737
8464
|
if (ctx.signal.aborted) {
|
|
8738
8465
|
ctx.deliver(update);
|
|
@@ -8745,17 +8472,321 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
8745
8472
|
});
|
|
8746
8473
|
}
|
|
8747
8474
|
//#endregion
|
|
8475
|
+
//#region ../agent-cli/dist/built-ins/install/global.js
|
|
8476
|
+
function checkOf(cli, install, { bin, node }) {
|
|
8477
|
+
return {
|
|
8478
|
+
install: async (ctx) => {
|
|
8479
|
+
const npm = globalNpm(cli, install, ctx, node);
|
|
8480
|
+
try {
|
|
8481
|
+
return {
|
|
8482
|
+
state: "ok",
|
|
8483
|
+
message: `a global npm install under ${(await globalInstallOf(bin, npm)).prefix}`
|
|
8484
|
+
};
|
|
8485
|
+
} catch (error) {
|
|
8486
|
+
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
8487
|
+
state: "problem",
|
|
8488
|
+
message: error.message,
|
|
8489
|
+
fix: installCommandLine(npm.registry)
|
|
8490
|
+
};
|
|
8491
|
+
throw error;
|
|
8492
|
+
}
|
|
8493
|
+
},
|
|
8494
|
+
release: async (ctx) => {
|
|
8495
|
+
const fix = `${cli.name} update`;
|
|
8496
|
+
return {
|
|
8497
|
+
npm: globalNpm(cli, install, ctx, node),
|
|
8498
|
+
advise: () => ({ fix })
|
|
8499
|
+
};
|
|
8500
|
+
}
|
|
8501
|
+
};
|
|
8502
|
+
}
|
|
8503
|
+
/** The Install of a CLI installed once per machine with npm, which `update` replaces. */
|
|
8504
|
+
function globalInstall(cli, install) {
|
|
8505
|
+
const adapter = {
|
|
8506
|
+
runAs: runAsOf(cli),
|
|
8507
|
+
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf(cli, adapter), launch) }),
|
|
8508
|
+
exitClasses: ["source"],
|
|
8509
|
+
check: (launch) => checkOf(cli, install, launch)
|
|
8510
|
+
};
|
|
8511
|
+
return adapter;
|
|
8512
|
+
}
|
|
8513
|
+
//#endregion
|
|
8514
|
+
//#region ../agent-cli/dist/built-ins/install/install.js
|
|
8515
|
+
function noInstall(cli) {
|
|
8516
|
+
const skipped = async () => ({
|
|
8517
|
+
state: "skipped",
|
|
8518
|
+
message: `not checked: ${cli.name} declares no install`
|
|
8519
|
+
});
|
|
8520
|
+
return {
|
|
8521
|
+
runAs: runAsOf(cli),
|
|
8522
|
+
builtIns: () => ({}),
|
|
8523
|
+
exitClasses: [],
|
|
8524
|
+
check: () => ({
|
|
8525
|
+
install: skipped,
|
|
8526
|
+
release: async () => ({ skipped: await skipped() })
|
|
8527
|
+
})
|
|
8528
|
+
};
|
|
8529
|
+
}
|
|
8530
|
+
function installOf(cli) {
|
|
8531
|
+
const { install } = cli;
|
|
8532
|
+
if (install === void 0) return noInstall(cli);
|
|
8533
|
+
return install.mode === "global" ? globalInstall(cli, install) : dependencyInstall(cli, install);
|
|
8534
|
+
}
|
|
8535
|
+
//#endregion
|
|
8536
|
+
//#region ../agent-cli/dist/built-ins/doctor-rows.js
|
|
8537
|
+
function ok(message) {
|
|
8538
|
+
return {
|
|
8539
|
+
state: "ok",
|
|
8540
|
+
message
|
|
8541
|
+
};
|
|
8542
|
+
}
|
|
8543
|
+
function buildRow(cli) {
|
|
8544
|
+
return {
|
|
8545
|
+
name: "build",
|
|
8546
|
+
run: () => ok(versionLine(cli))
|
|
8547
|
+
};
|
|
8548
|
+
}
|
|
8549
|
+
function nodeRow(cli) {
|
|
8550
|
+
return {
|
|
8551
|
+
name: "node",
|
|
8552
|
+
run: () => {
|
|
8553
|
+
const found = process.versions.node;
|
|
8554
|
+
const range = cli.engines?.node;
|
|
8555
|
+
if (range === void 0) return ok(`Node ${found}; ${cli.name} declares no engines.node to check it against`);
|
|
8556
|
+
const minimum = engineMinimum(range);
|
|
8557
|
+
if (minimum === void 0) return {
|
|
8558
|
+
state: "problem",
|
|
8559
|
+
message: `${cli.name} declares engines.node "${range}", which doctor cannot read: only >=X.Y.Z is supported`
|
|
8560
|
+
};
|
|
8561
|
+
if (meetsMinimum(found, minimum)) return ok(`Node ${found} meets ${range}`);
|
|
8562
|
+
const major = minimum[0];
|
|
8563
|
+
return {
|
|
8564
|
+
state: "problem",
|
|
8565
|
+
message: `${cli.name} runs on Node ${found}, older than the ${range} it needs; install Node ${minimum.join(".")} or newer and make it the default`,
|
|
8566
|
+
fix: `nvm install ${major} && nvm alias default ${major}`
|
|
8567
|
+
};
|
|
8568
|
+
}
|
|
8569
|
+
};
|
|
8570
|
+
}
|
|
8571
|
+
/** A row's thrown error as its problem: a `CliError` with its hint and code, anything else a bug. */
|
|
8572
|
+
function problemOfError(name, error) {
|
|
8573
|
+
if (error instanceof CliError) return {
|
|
8574
|
+
state: "problem",
|
|
8575
|
+
message: `${error.message}; ${error.hint}`,
|
|
8576
|
+
code: error.code
|
|
8577
|
+
};
|
|
8578
|
+
return {
|
|
8579
|
+
state: "problem",
|
|
8580
|
+
message: `the ${name} row hit a bug: ${messageOf(error)}`
|
|
8581
|
+
};
|
|
8582
|
+
}
|
|
8583
|
+
function readProject(projectFile, ctx) {
|
|
8584
|
+
if (projectFile === void 0) return {
|
|
8585
|
+
ok: true,
|
|
8586
|
+
project: void 0
|
|
8587
|
+
};
|
|
8588
|
+
try {
|
|
8589
|
+
return {
|
|
8590
|
+
ok: true,
|
|
8591
|
+
project: projectOf(projectFile, ctx.cwd, {
|
|
8592
|
+
fileError: ctx.fileError,
|
|
8593
|
+
callerLine: ctx.commandLine()
|
|
8594
|
+
})
|
|
8595
|
+
};
|
|
8596
|
+
} catch (error) {
|
|
8597
|
+
return {
|
|
8598
|
+
ok: false,
|
|
8599
|
+
error
|
|
8600
|
+
};
|
|
8601
|
+
}
|
|
8602
|
+
}
|
|
8603
|
+
function projectRow({ file }, read) {
|
|
8604
|
+
return {
|
|
8605
|
+
name: "project",
|
|
8606
|
+
run: (ctx) => {
|
|
8607
|
+
if (!read.ok) return problemOfError("project", read.error);
|
|
8608
|
+
return ok(read.project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(read.project.root, file));
|
|
8609
|
+
}
|
|
8610
|
+
};
|
|
8611
|
+
}
|
|
8612
|
+
function installRow(check) {
|
|
8613
|
+
return {
|
|
8614
|
+
name: "install",
|
|
8615
|
+
advisory: true,
|
|
8616
|
+
run: check.install
|
|
8617
|
+
};
|
|
8618
|
+
}
|
|
8619
|
+
function registryRow(cli, check) {
|
|
8620
|
+
return {
|
|
8621
|
+
name: "registry",
|
|
8622
|
+
advisory: true,
|
|
8623
|
+
run: async (ctx) => {
|
|
8624
|
+
const lookup = await check.release(ctx);
|
|
8625
|
+
if ("skipped" in lookup) return lookup.skipped;
|
|
8626
|
+
const { npm, advise } = lookup;
|
|
8627
|
+
const latest = await latestVersion(npm);
|
|
8628
|
+
const standing = standingOf$1(cli.version, latest);
|
|
8629
|
+
const head = `${npm.registry.label} has ${latest} as latest: this build`;
|
|
8630
|
+
if (standing === "behind") {
|
|
8631
|
+
const message = `${head} (${cli.version}) is older`;
|
|
8632
|
+
const advice = advise(latest);
|
|
8633
|
+
return "fix" in advice ? {
|
|
8634
|
+
state: "problem",
|
|
8635
|
+
message,
|
|
8636
|
+
fix: advice.fix
|
|
8637
|
+
} : {
|
|
8638
|
+
state: "problem",
|
|
8639
|
+
message: `${message}; ${advice.note}`
|
|
8640
|
+
};
|
|
8641
|
+
}
|
|
8642
|
+
return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
|
|
8643
|
+
}
|
|
8644
|
+
};
|
|
8645
|
+
}
|
|
8646
|
+
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
8647
|
+
function doctorChecks(cli, launch, read) {
|
|
8648
|
+
const install = installOf(cli);
|
|
8649
|
+
const check = install.check(launch);
|
|
8650
|
+
return [
|
|
8651
|
+
buildRow(cli),
|
|
8652
|
+
nodeRow(cli),
|
|
8653
|
+
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
8654
|
+
...cli.doctor ?? [],
|
|
8655
|
+
...toolRows(cli.tools ?? [], cli.commands),
|
|
8656
|
+
installRow(check),
|
|
8657
|
+
registryRow(cli, check),
|
|
8658
|
+
...skillOf(cli, install).rows
|
|
8659
|
+
];
|
|
8660
|
+
}
|
|
8661
|
+
//#endregion
|
|
8662
|
+
//#region ../agent-cli/dist/built-ins/doctor.js
|
|
8663
|
+
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
8664
|
+
const DEFAULT_DEADLINE_MS = 1e4;
|
|
8665
|
+
const MS_PER_SECOND = 1e3;
|
|
8666
|
+
const MIN_LABEL_WIDTH = 8;
|
|
8667
|
+
const reportSchema = object({
|
|
8668
|
+
rows: array(object({
|
|
8669
|
+
check: string(),
|
|
8670
|
+
state: _enum([
|
|
8671
|
+
"ok",
|
|
8672
|
+
"problem",
|
|
8673
|
+
"skipped"
|
|
8674
|
+
]),
|
|
8675
|
+
message: string(),
|
|
8676
|
+
fix: string().optional(),
|
|
8677
|
+
code: string().optional(),
|
|
8678
|
+
skill: packagedSkillDetailsSchema.optional()
|
|
8679
|
+
})),
|
|
8680
|
+
next: array(string())
|
|
8681
|
+
});
|
|
8682
|
+
function problemOf(check, error, { signal, deadline, ms }) {
|
|
8683
|
+
if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
|
|
8684
|
+
state: "problem",
|
|
8685
|
+
message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
|
|
8686
|
+
};
|
|
8687
|
+
return problemOfError(check.name, error);
|
|
8688
|
+
}
|
|
8689
|
+
function rowContext(ctx, signal, read) {
|
|
8690
|
+
return Object.create(ctx, {
|
|
8691
|
+
signal: { value: signal },
|
|
8692
|
+
project: { get: () => {
|
|
8693
|
+
if (!read.ok) throw read.error;
|
|
8694
|
+
return read.project;
|
|
8695
|
+
} }
|
|
8696
|
+
});
|
|
8697
|
+
}
|
|
8698
|
+
async function rowOf(check, ctx, read) {
|
|
8699
|
+
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
8700
|
+
const signal = ctx.deadline(ms);
|
|
8701
|
+
let finding;
|
|
8702
|
+
try {
|
|
8703
|
+
finding = await Promise.race([Promise.resolve().then(() => check.run(rowContext(ctx, signal, read))), untilAborted(signal)]);
|
|
8704
|
+
} catch (error) {
|
|
8705
|
+
if (ctx.signal.aborted) return void 0;
|
|
8706
|
+
finding = !read.ok && error === read.error ? {
|
|
8707
|
+
state: "skipped",
|
|
8708
|
+
message: "the Project file is unusable; the project row says why"
|
|
8709
|
+
} : problemOf(check, error, {
|
|
8710
|
+
signal: ctx.signal,
|
|
8711
|
+
deadline: signal,
|
|
8712
|
+
ms
|
|
8713
|
+
});
|
|
8714
|
+
}
|
|
8715
|
+
return {
|
|
8716
|
+
row: {
|
|
8717
|
+
check: check.name,
|
|
8718
|
+
...finding
|
|
8719
|
+
},
|
|
8720
|
+
advisory: check.advisory === true
|
|
8721
|
+
};
|
|
8722
|
+
}
|
|
8723
|
+
function nextOf(rows) {
|
|
8724
|
+
return [...new Set(rows.flatMap(({ fix }) => fix === void 0 ? [] : [fix]))];
|
|
8725
|
+
}
|
|
8726
|
+
function render({ rows, next }, style) {
|
|
8727
|
+
const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
|
|
8728
|
+
const stateWidth = Math.max(...rows.map(({ state }) => state.length)) + 2;
|
|
8729
|
+
return [...rows.map(({ check, state, message }) => {
|
|
8730
|
+
const label = state === "problem" ? style.red(state) : state;
|
|
8731
|
+
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
8732
|
+
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
8733
|
+
}
|
|
8734
|
+
function failure(cliName, callerLine, problems) {
|
|
8735
|
+
const errors = problems.map(({ check, message, fix, code }) => new CliError({
|
|
8736
|
+
code: code ?? "DOCTOR_PROBLEMS",
|
|
8737
|
+
message: `${cliName} doctor found a problem in ${check}: ${message}`,
|
|
8738
|
+
hint: fix === void 0 ? "the row says what is wrong" : `run \`${fix}\`, then run \`${callerLine}\` again`
|
|
8739
|
+
}));
|
|
8740
|
+
return new AggregateError(errors);
|
|
8741
|
+
}
|
|
8742
|
+
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
8743
|
+
function doctorCommand(cli, launch) {
|
|
8744
|
+
return defineCommand$1({
|
|
8745
|
+
name: "doctor",
|
|
8746
|
+
description: "check the setup and say what fixes each problem",
|
|
8747
|
+
examples: [{
|
|
8748
|
+
command: `${runAsOf(cli)} doctor`,
|
|
8749
|
+
note: "check the setup and list the commands that fix it"
|
|
8750
|
+
}, {
|
|
8751
|
+
command: `${runAsOf(cli)} doctor --json`,
|
|
8752
|
+
note: "get the rows and fixes as data"
|
|
8753
|
+
}],
|
|
8754
|
+
effect: "read",
|
|
8755
|
+
output: reportSchema,
|
|
8756
|
+
run: async (_input, ctx) => {
|
|
8757
|
+
const read = readProject(cli.project, ctx);
|
|
8758
|
+
const checked = (await Promise.all(doctorChecks(cli, launch, read).map((check) => rowOf(check, ctx, read)))).filter((row) => row !== void 0);
|
|
8759
|
+
const rows = checked.map(({ row }) => row);
|
|
8760
|
+
const report = {
|
|
8761
|
+
rows,
|
|
8762
|
+
next: nextOf(rows)
|
|
8763
|
+
};
|
|
8764
|
+
if (ctx.signal.aborted) {
|
|
8765
|
+
ctx.deliver(report);
|
|
8766
|
+
ctx.signal.throwIfAborted();
|
|
8767
|
+
}
|
|
8768
|
+
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
8769
|
+
if (problems.length > 0) {
|
|
8770
|
+
ctx.deliver(report);
|
|
8771
|
+
throw failure(cli.name, ctx.commandLine(), problems);
|
|
8772
|
+
}
|
|
8773
|
+
return report;
|
|
8774
|
+
},
|
|
8775
|
+
render
|
|
8776
|
+
});
|
|
8777
|
+
}
|
|
8778
|
+
//#endregion
|
|
8748
8779
|
//#region ../agent-cli/dist/built-ins/commands.js
|
|
8749
8780
|
/**
|
|
8750
8781
|
* The Commands the Runtime adds to a multi-Command CLI: `update` only for a Global install, and
|
|
8751
8782
|
* `skill install` only for a Packaged skill.
|
|
8752
8783
|
*/
|
|
8753
8784
|
function builtInCommands(cli, launch) {
|
|
8754
|
-
const
|
|
8785
|
+
const install = installOf(cli);
|
|
8755
8786
|
return {
|
|
8756
8787
|
doctor: doctorCommand(cli, launch),
|
|
8757
|
-
...
|
|
8758
|
-
...
|
|
8788
|
+
...install.builtIns(launch),
|
|
8789
|
+
...skillOf(cli, install).builtIns
|
|
8759
8790
|
};
|
|
8760
8791
|
}
|
|
8761
8792
|
//#endregion
|
|
@@ -8879,7 +8910,7 @@ function reachableExitClasses(cli) {
|
|
|
8879
8910
|
"caller",
|
|
8880
8911
|
"operator",
|
|
8881
8912
|
"wait",
|
|
8882
|
-
...cli.commands
|
|
8913
|
+
...cli.commands === void 0 ? [] : installOf(cli).exitClasses
|
|
8883
8914
|
];
|
|
8884
8915
|
const own = Object.values(cli.errors ?? {}).map((declaration) => declaration.class);
|
|
8885
8916
|
return /* @__PURE__ */ new Set([...runtime, ...own]);
|
|
@@ -8905,7 +8936,7 @@ function checkOwnCodes(cli) {
|
|
|
8905
8936
|
function defineCli$1(cli) {
|
|
8906
8937
|
checkOwnCodes(cli);
|
|
8907
8938
|
if (cli.commands === void 0) {
|
|
8908
|
-
if (
|
|
8939
|
+
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`);
|
|
8909
8940
|
return cli;
|
|
8910
8941
|
}
|
|
8911
8942
|
const { commands } = cli;
|
|
@@ -10023,7 +10054,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10023
10054
|
let served = false;
|
|
10024
10055
|
let settled;
|
|
10025
10056
|
try {
|
|
10026
|
-
const outcome = await control.settle(
|
|
10057
|
+
const outcome = await control.settle(skillOf(cli, installOf(cli)).notice({
|
|
10027
10058
|
builtIn,
|
|
10028
10059
|
bin: options.bin
|
|
10029
10060
|
}, ctx).then(() => execute(command, input, ctx, {
|
|
@@ -10222,14 +10253,14 @@ async function runProcess(cli) {
|
|
|
10222
10253
|
}
|
|
10223
10254
|
//#endregion
|
|
10224
10255
|
//#region package.json
|
|
10225
|
-
var version$1 = "0.
|
|
10256
|
+
var version$1 = "0.16.0";
|
|
10226
10257
|
var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
|
|
10227
10258
|
//#endregion
|
|
10228
10259
|
//#region src/build.ts
|
|
10229
10260
|
const build = {
|
|
10230
|
-
"sha": "
|
|
10261
|
+
"sha": "648fa57",
|
|
10231
10262
|
"dirty": false,
|
|
10232
|
-
"builtAt": "2026-10-
|
|
10263
|
+
"builtAt": "2026-10-27T10:21:48.000Z"
|
|
10233
10264
|
};
|
|
10234
10265
|
//#endregion
|
|
10235
10266
|
//#region src/fill.ts
|