@duyquangnvx/create-agent-cli 0.21.0 → 0.23.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
CHANGED
|
@@ -4,6 +4,24 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## v0.23.0 (2026-11-03)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- A Global install of a CLI with several Commands runs a Release check: at most once a day a run asks the Install registry, in a detached process, for the latest release, and later runs give the Notice ``<cli> X.Y.Z is out, this is A.B.C; run `<cli> update` `` while the CLI is behind. No run waits on it. `CI`, or `<NAME>_NO_RELEASE_CHECK=1` for one CLI, turns it off; it keeps its answer in `$XDG_CACHE_HOME/<name>/release-check.json`, by default under `~/.cache`.
|
|
12
|
+
|
|
13
|
+
## v0.22.0 (2026-11-02)
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- The hint of `UNKNOWN_OPTION`, `UNKNOWN_COMMAND` and `INVALID_INPUT` names each Skill copy whose `metadata.version` differs from the build's, for a Skill Hub or a Packaged skill, and says to run `doctor` to update it. A CLI's skill can drop its line on a flag or Command it names that the CLI does not know.
|
|
18
|
+
- The scaffolded setup reference of a Global install says what to do when the user installed the CLI but the shell finds none, under nvm. A CLI's skill can drop its own `command not found` row.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `REGISTRY_AUTH` from npm's `E403` under a Coding agent hints that the agent's sandbox may refuse the registry: the user types `!` and runs it again, or allows the registry in the sandbox's network list, and logs in only if it fails outside the sandbox too. `update`, the install and `doctor`'s `registry` row all give it. A CLI's skill can drop its row saying that `REGISTRY_AUTH` is no refused login, and its `INTERNAL` row too: that hint already names `<NAME>_DEBUG=1`.
|
|
23
|
+
- The scaffolded skill drops what the agent sees anyway: `SKILL.md` loses its When to use section, which belongs in the description, its paragraph on `--json`, `--dry-run` and `--confirm`, and its description of the error format; the setup reference's Check no longer describes `doctor`'s rows. The shipping guide says a skill line earns its place only when no `--help`, output, hint or `doctor` row says it.
|
|
24
|
+
|
|
7
25
|
## v0.21.0 (2026-10-29)
|
|
8
26
|
|
|
9
27
|
### Added
|
package/dist/bin.js
CHANGED
|
@@ -5959,8 +5959,12 @@ async function orMissing(pending) {
|
|
|
5959
5959
|
function isNothingThere(error) {
|
|
5960
5960
|
return isMissingFile(error) || errnoOf(error) === "ENOTDIR";
|
|
5961
5961
|
}
|
|
5962
|
+
/** The CLI's own environment variable, such as `TOOL_DEBUG` for `cliVariable("tool", "DEBUG")`. */
|
|
5963
|
+
function cliVariable(cliName, suffix) {
|
|
5964
|
+
return `${cliName.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_${suffix}`;
|
|
5965
|
+
}
|
|
5962
5966
|
function debugVariable(cliName) {
|
|
5963
|
-
return
|
|
5967
|
+
return cliVariable(cliName, "DEBUG");
|
|
5964
5968
|
}
|
|
5965
5969
|
function messageOf(error) {
|
|
5966
5970
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -7081,9 +7085,9 @@ function secretRows(secrets, commands) {
|
|
|
7081
7085
|
/** The bundler's stamp, absent when the CLI runs unbundled. Read per call, so a test can define it. */
|
|
7082
7086
|
function buildStamp() {
|
|
7083
7087
|
return {
|
|
7084
|
-
"sha": "
|
|
7088
|
+
"sha": "71583a7",
|
|
7085
7089
|
"dirty": false,
|
|
7086
|
-
"builtAt": "2026-
|
|
7090
|
+
"builtAt": "2026-11-03T06:40:47.000Z"
|
|
7087
7091
|
};
|
|
7088
7092
|
}
|
|
7089
7093
|
/** The first line of `--version`: the version, and the commit and time of a stamped build. */
|
|
@@ -7092,6 +7096,40 @@ function versionLine({ version }) {
|
|
|
7092
7096
|
return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
|
|
7093
7097
|
}
|
|
7094
7098
|
//#endregion
|
|
7099
|
+
//#region ../agent-cli/dist/context/agent.js
|
|
7100
|
+
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7101
|
+
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7102
|
+
const equals = (name, value) => (env) => env[name] === value;
|
|
7103
|
+
const MARKERS = [
|
|
7104
|
+
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
7105
|
+
equals("AGENT", "amp"),
|
|
7106
|
+
isSet("CODEX_SANDBOX"),
|
|
7107
|
+
isSet("CODEX_CI"),
|
|
7108
|
+
isSet("CODEX_THREAD_ID"),
|
|
7109
|
+
isSet("GEMINI_CLI"),
|
|
7110
|
+
isSet("COPILOT_CLI"),
|
|
7111
|
+
isSet("OPENCODE"),
|
|
7112
|
+
isSet("ANTIGRAVITY_AGENT"),
|
|
7113
|
+
isSet("AUGMENT_AGENT"),
|
|
7114
|
+
isSet("REPL_ID"),
|
|
7115
|
+
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
7116
|
+
isSet("CLAUDECODE"),
|
|
7117
|
+
isSet("CLAUDE_CODE"),
|
|
7118
|
+
isSet("CURSOR_TRACE_ID"),
|
|
7119
|
+
isSet("CURSOR_AGENT"),
|
|
7120
|
+
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
7121
|
+
equals("TERM_PROGRAM", "kiro"),
|
|
7122
|
+
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
7123
|
+
isSet("GOOSE_PROVIDER")
|
|
7124
|
+
];
|
|
7125
|
+
/**
|
|
7126
|
+
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
7127
|
+
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
7128
|
+
*/
|
|
7129
|
+
function isAgent(env) {
|
|
7130
|
+
return MARKERS.some((marker) => marker(env));
|
|
7131
|
+
}
|
|
7132
|
+
//#endregion
|
|
7095
7133
|
//#region ../agent-cli/dist/built-ins/semver.js
|
|
7096
7134
|
const VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
7097
7135
|
const ENGINE = /^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?$/;
|
|
@@ -7231,8 +7269,14 @@ function tail$1(stderr) {
|
|
|
7231
7269
|
const lines = lastLines(stderr, STDERR_TAIL_LINES);
|
|
7232
7270
|
return lines === "" ? "" : `\n${lines}`;
|
|
7233
7271
|
}
|
|
7272
|
+
function authHint(code, ctx) {
|
|
7273
|
+
const { label: registry, loginHint } = ctx.registry;
|
|
7274
|
+
const login = `${loginHint}, then ${RUN_AGAIN}`;
|
|
7275
|
+
if (code !== "E403" || !isAgent(ctx.env)) return login;
|
|
7276
|
+
return `a Coding agent's sandbox may refuse ${registry} with a 403: ask your user to type ! and ${RUN_AGAIN}, or to allow ${registry} in the sandbox's network list; if it fails outside the sandbox too, ${login}`;
|
|
7277
|
+
}
|
|
7234
7278
|
function failureOf(call, answer, ctx) {
|
|
7235
|
-
const { label: registry, package: name,
|
|
7279
|
+
const { label: registry, package: name, unreachableHint } = ctx.registry;
|
|
7236
7280
|
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
7237
7281
|
const output = tail$1(answer.stderr);
|
|
7238
7282
|
const next = [ctx.rerun];
|
|
@@ -7245,7 +7289,7 @@ function failureOf(call, answer, ctx) {
|
|
|
7245
7289
|
if (code !== void 0 && AUTH_CODES.has(code)) return new CliError({
|
|
7246
7290
|
code: REGISTRY_AUTH,
|
|
7247
7291
|
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
7248
|
-
hint:
|
|
7292
|
+
hint: authHint(code, ctx),
|
|
7249
7293
|
next
|
|
7250
7294
|
});
|
|
7251
7295
|
if (call === "view" && code === "E404") return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
@@ -7321,15 +7365,18 @@ async function installGlobally(version, ctx) {
|
|
|
7321
7365
|
...ctx.registry.flags
|
|
7322
7366
|
], ctx, null);
|
|
7323
7367
|
}
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
const answer = await runNpm("view", [
|
|
7368
|
+
function latestViewArgs({ package: name, flags }) {
|
|
7369
|
+
return [
|
|
7327
7370
|
"view",
|
|
7328
7371
|
`${name}@latest`,
|
|
7329
7372
|
"version",
|
|
7330
7373
|
"--json",
|
|
7331
7374
|
...flags
|
|
7332
|
-
]
|
|
7375
|
+
];
|
|
7376
|
+
}
|
|
7377
|
+
async function latestVersion(ctx) {
|
|
7378
|
+
const { package: name, label: registry } = ctx.registry;
|
|
7379
|
+
const answer = await runNpm("view", latestViewArgs(ctx.registry), ctx);
|
|
7333
7380
|
const version = versionInViewAnswer(answer);
|
|
7334
7381
|
if (version === void 0) throw noLatest(ctx, `npm answered no version for ${name}@latest on ${registry}: ${answer.trim()}`);
|
|
7335
7382
|
return version;
|
|
@@ -7571,7 +7618,8 @@ function dependencyInstall(cli, install) {
|
|
|
7571
7618
|
runAs,
|
|
7572
7619
|
builtIns: () => ({}),
|
|
7573
7620
|
exitClasses: [],
|
|
7574
|
-
check: (launch) => checkOf$1(cli, install, runAs, launch)
|
|
7621
|
+
check: (launch) => checkOf$1(cli, install, runAs, launch),
|
|
7622
|
+
notice: async () => {}
|
|
7575
7623
|
};
|
|
7576
7624
|
}
|
|
7577
7625
|
//#endregion
|
|
@@ -7669,6 +7717,7 @@ function hubSkill(cli, from) {
|
|
|
7669
7717
|
run: async (ctx) => findingOf(await skillCopies(cli.name, cli.version, ctx))
|
|
7670
7718
|
}],
|
|
7671
7719
|
notice: async () => {},
|
|
7720
|
+
differing: async (place) => (await skillCopies(cli.name, cli.version, place)).filter(({ state }) => state !== "current" && state !== "unreadable").map(describeCopy),
|
|
7672
7721
|
nextAt: async (version, ctx) => {
|
|
7673
7722
|
const copies = await skillCopies(cli.name, version, ctx);
|
|
7674
7723
|
const fix = fixFor(cli.name, copies, from);
|
|
@@ -7751,40 +7800,6 @@ function agentsRow(agents, install) {
|
|
|
7751
7800
|
};
|
|
7752
7801
|
}
|
|
7753
7802
|
//#endregion
|
|
7754
|
-
//#region ../agent-cli/dist/context/agent.js
|
|
7755
|
-
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7756
|
-
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7757
|
-
const equals = (name, value) => (env) => env[name] === value;
|
|
7758
|
-
const MARKERS = [
|
|
7759
|
-
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
7760
|
-
equals("AGENT", "amp"),
|
|
7761
|
-
isSet("CODEX_SANDBOX"),
|
|
7762
|
-
isSet("CODEX_CI"),
|
|
7763
|
-
isSet("CODEX_THREAD_ID"),
|
|
7764
|
-
isSet("GEMINI_CLI"),
|
|
7765
|
-
isSet("COPILOT_CLI"),
|
|
7766
|
-
isSet("OPENCODE"),
|
|
7767
|
-
isSet("ANTIGRAVITY_AGENT"),
|
|
7768
|
-
isSet("AUGMENT_AGENT"),
|
|
7769
|
-
isSet("REPL_ID"),
|
|
7770
|
-
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
7771
|
-
isSet("CLAUDECODE"),
|
|
7772
|
-
isSet("CLAUDE_CODE"),
|
|
7773
|
-
isSet("CURSOR_TRACE_ID"),
|
|
7774
|
-
isSet("CURSOR_AGENT"),
|
|
7775
|
-
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
7776
|
-
equals("TERM_PROGRAM", "kiro"),
|
|
7777
|
-
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
7778
|
-
isSet("GOOSE_PROVIDER")
|
|
7779
|
-
];
|
|
7780
|
-
/**
|
|
7781
|
-
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
7782
|
-
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
7783
|
-
*/
|
|
7784
|
-
function isAgent(env) {
|
|
7785
|
-
return MARKERS.some((marker) => marker(env));
|
|
7786
|
-
}
|
|
7787
|
-
//#endregion
|
|
7788
7803
|
//#region ../agent-cli/dist/context/errno.js
|
|
7789
7804
|
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
7790
7805
|
const DISK_FULL = "DISK_FULL";
|
|
@@ -8305,6 +8320,15 @@ function packagedSkill(cli, { packaged: folder, agents: text }, install) {
|
|
|
8305
8320
|
run: (ctx) => findingOf(cli, folder, install, ctx)
|
|
8306
8321
|
}, ...agents === void 0 ? [] : [agentsRow(agents, install)]],
|
|
8307
8322
|
notice: (launch, ctx) => notice(cli, folder, install, launch, ctx),
|
|
8323
|
+
differing: async ({ cwd, packageRoot }) => {
|
|
8324
|
+
const { copy } = await skillCopyOf(cli, cwd);
|
|
8325
|
+
const { copyVersion, packageVersion, same } = await skillVersionsOf(join(packageRoot, folder), copy);
|
|
8326
|
+
return copyVersion === void 0 || same ? [] : [compared(cli.name, {
|
|
8327
|
+
copy,
|
|
8328
|
+
copyVersion,
|
|
8329
|
+
packageVersion
|
|
8330
|
+
}, false)];
|
|
8331
|
+
},
|
|
8308
8332
|
nextAt: async (_version, ctx) => {
|
|
8309
8333
|
const { fix } = await findingOf(cli, folder, install, ctx);
|
|
8310
8334
|
return fix === void 0 ? [] : [fix];
|
|
@@ -8672,6 +8696,127 @@ function updateCommand(cli, install, skill, { bin, node }) {
|
|
|
8672
8696
|
});
|
|
8673
8697
|
}
|
|
8674
8698
|
//#endregion
|
|
8699
|
+
//#region ../agent-cli/dist/built-ins/install/release-check.js
|
|
8700
|
+
const CHECK_INTERVAL_MS = 864e5;
|
|
8701
|
+
const checkSchema = object({
|
|
8702
|
+
checkedAt: number(),
|
|
8703
|
+
latest: string().optional(),
|
|
8704
|
+
error: string().optional()
|
|
8705
|
+
});
|
|
8706
|
+
const CHECK_SCRIPT = `
|
|
8707
|
+
const { spawnSync } = require("node:child_process");
|
|
8708
|
+
const { mkdtempSync, renameSync, rmSync, writeFileSync } = require("node:fs");
|
|
8709
|
+
const { tmpdir } = require("node:os");
|
|
8710
|
+
const { join } = require("node:path");
|
|
8711
|
+
const [file, checkedAt, previous, npm, ...args] = process.argv.slice(1);
|
|
8712
|
+
const windows = process.platform === "win32";
|
|
8713
|
+
const cache = mkdtempSync(join(tmpdir(), "release-check-"));
|
|
8714
|
+
const write = (check) => {
|
|
8715
|
+
const temp = file + "." + process.pid + ".tmp";
|
|
8716
|
+
writeFileSync(temp, JSON.stringify({ checkedAt: Number(checkedAt), ...check }));
|
|
8717
|
+
renameSync(temp, file);
|
|
8718
|
+
};
|
|
8719
|
+
const latestOf = (stdout) => {
|
|
8720
|
+
try {
|
|
8721
|
+
const parsed = JSON.parse(stdout);
|
|
8722
|
+
const latest = Array.isArray(parsed) ? parsed.at(-1) : parsed;
|
|
8723
|
+
return typeof latest === "string" && /^\\d+\\.\\d+\\.\\d+/.test(latest) ? latest : undefined;
|
|
8724
|
+
} catch {
|
|
8725
|
+
return undefined;
|
|
8726
|
+
}
|
|
8727
|
+
};
|
|
8728
|
+
try {
|
|
8729
|
+
const answer = spawnSync(windows ? '"' + npm + '"' : npm, args, {
|
|
8730
|
+
encoding: "utf8",
|
|
8731
|
+
shell: windows,
|
|
8732
|
+
windowsHide: true,
|
|
8733
|
+
env: { ...process.env, npm_config_cache: join(cache, "cache"), npm_config_logs_max: "0" },
|
|
8734
|
+
});
|
|
8735
|
+
const latest = answer.status === 0 ? latestOf(answer.stdout) : undefined;
|
|
8736
|
+
if (latest !== undefined) {
|
|
8737
|
+
write({ latest });
|
|
8738
|
+
} else {
|
|
8739
|
+
const said = (answer.stderr || "").trim().split(/\\r?\\n/).slice(0, 5).join("; ");
|
|
8740
|
+
const error = answer.error ? answer.error.message : said || "npm answered " + answer.stdout.trim();
|
|
8741
|
+
write({ latest: previous || undefined, error });
|
|
8742
|
+
}
|
|
8743
|
+
} finally {
|
|
8744
|
+
rmSync(cache, { recursive: true, force: true });
|
|
8745
|
+
}
|
|
8746
|
+
`;
|
|
8747
|
+
function isOff(cliName, env) {
|
|
8748
|
+
return Boolean(env[cliVariable(cliName, "NO_RELEASE_CHECK")] || env.CI);
|
|
8749
|
+
}
|
|
8750
|
+
function cacheFileOf(cliName, env) {
|
|
8751
|
+
const cache = env.XDG_CACHE_HOME || join(env.HOME || env.USERPROFILE || homedir(), ".cache");
|
|
8752
|
+
return join(cache, cliName, "release-check.json");
|
|
8753
|
+
}
|
|
8754
|
+
function parsedCheck(text) {
|
|
8755
|
+
try {
|
|
8756
|
+
return checkSchema.safeParse(JSON.parse(text)).data;
|
|
8757
|
+
} catch {
|
|
8758
|
+
return;
|
|
8759
|
+
}
|
|
8760
|
+
}
|
|
8761
|
+
async function lastCheck(file) {
|
|
8762
|
+
const text = await orMissing(readFile(file, "utf8"));
|
|
8763
|
+
return text === void 0 ? void 0 : parsedCheck(text);
|
|
8764
|
+
}
|
|
8765
|
+
async function writeCheck(file, check) {
|
|
8766
|
+
await mkdir(dirname(file), { recursive: true });
|
|
8767
|
+
const temp = tempPathOf(file);
|
|
8768
|
+
await writeFile(temp, JSON.stringify(check));
|
|
8769
|
+
await rename(temp, file);
|
|
8770
|
+
}
|
|
8771
|
+
async function startCheck(cli, install, file, last, { node }, ctx) {
|
|
8772
|
+
const checkedAt = ctx.clock.now();
|
|
8773
|
+
const previous = last?.latest ?? "";
|
|
8774
|
+
await writeCheck(file, {
|
|
8775
|
+
checkedAt,
|
|
8776
|
+
latest: last?.latest
|
|
8777
|
+
});
|
|
8778
|
+
const npm = globalNpm(cli, install, ctx, node);
|
|
8779
|
+
const { path, env } = npmOf(npm, process.platform === "win32");
|
|
8780
|
+
await ctx.spawnDetached(process.execPath, [
|
|
8781
|
+
"-e",
|
|
8782
|
+
CHECK_SCRIPT,
|
|
8783
|
+
file,
|
|
8784
|
+
String(checkedAt),
|
|
8785
|
+
previous,
|
|
8786
|
+
path,
|
|
8787
|
+
...latestViewArgs(npm.registry)
|
|
8788
|
+
], { env });
|
|
8789
|
+
}
|
|
8790
|
+
function debugLine(cli, ctx, text) {
|
|
8791
|
+
if (isDebug({
|
|
8792
|
+
env: ctx.env,
|
|
8793
|
+
cliName: cli.name
|
|
8794
|
+
})) ctx.progress(`release check failed: ${text}`);
|
|
8795
|
+
}
|
|
8796
|
+
/**
|
|
8797
|
+
* Tells the caller of a newer release that an earlier Release check found, and starts the next
|
|
8798
|
+
* check once the last is a day old.
|
|
8799
|
+
*/
|
|
8800
|
+
async function releaseCheck(cli, install, runAs, launch, ctx) {
|
|
8801
|
+
if (launch.builtIn || launch.bin === void 0 || cli.commands === void 0) return;
|
|
8802
|
+
if (isOff(cli.name, ctx.env)) return;
|
|
8803
|
+
try {
|
|
8804
|
+
await checkAndTell(cli, install, runAs, launch, ctx);
|
|
8805
|
+
} catch (error) {
|
|
8806
|
+
if (errnoOf(error) === void 0 && !(error instanceof CliError)) throw error;
|
|
8807
|
+
debugLine(cli, ctx, messageOf(error));
|
|
8808
|
+
}
|
|
8809
|
+
}
|
|
8810
|
+
async function checkAndTell(cli, install, runAs, launch, ctx) {
|
|
8811
|
+
const file = cacheFileOf(cli.name, ctx.env);
|
|
8812
|
+
const last = await lastCheck(file);
|
|
8813
|
+
if (last?.error !== void 0) debugLine(cli, ctx, last.error);
|
|
8814
|
+
if (last === void 0 || ctx.clock.now() - last.checkedAt >= CHECK_INTERVAL_MS) await startCheck(cli, install, file, last, launch, ctx);
|
|
8815
|
+
const latest = last?.latest;
|
|
8816
|
+
if (latest === void 0 || !isVersion(latest) || compareVersions(latest, cli.version) <= 0) return;
|
|
8817
|
+
ctx.notice(`${cli.name} ${latest} is out, this is ${cli.version}; run \`${runAs} update\``);
|
|
8818
|
+
}
|
|
8819
|
+
//#endregion
|
|
8675
8820
|
//#region ../agent-cli/dist/built-ins/install/global.js
|
|
8676
8821
|
function checkOf(cli, install, { bin, node }) {
|
|
8677
8822
|
return {
|
|
@@ -8706,12 +8851,14 @@ function globalInstall(cli, install) {
|
|
|
8706
8851
|
runAs: runAsOf(cli),
|
|
8707
8852
|
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf$1(cli, adapter), launch) }),
|
|
8708
8853
|
exitClasses: ["source"],
|
|
8709
|
-
check: (launch) => checkOf(cli, install, launch)
|
|
8854
|
+
check: (launch) => checkOf(cli, install, launch),
|
|
8855
|
+
notice: (launch, ctx) => releaseCheck(cli, install, adapter.runAs, launch, ctx)
|
|
8710
8856
|
};
|
|
8711
8857
|
return adapter;
|
|
8712
8858
|
}
|
|
8713
8859
|
//#endregion
|
|
8714
8860
|
//#region ../agent-cli/dist/built-ins/install/install.js
|
|
8861
|
+
const noNotice = async () => {};
|
|
8715
8862
|
function noInstall(cli) {
|
|
8716
8863
|
const skipped = async () => ({
|
|
8717
8864
|
state: "skipped",
|
|
@@ -8724,7 +8871,8 @@ function noInstall(cli) {
|
|
|
8724
8871
|
check: () => ({
|
|
8725
8872
|
install: skipped,
|
|
8726
8873
|
release: async () => ({ skipped: await skipped() })
|
|
8727
|
-
})
|
|
8874
|
+
}),
|
|
8875
|
+
notice: noNotice
|
|
8728
8876
|
};
|
|
8729
8877
|
}
|
|
8730
8878
|
function installOf(cli) {
|
|
@@ -9356,6 +9504,30 @@ function startSideTask(sideTask, runWith, { clock, failed }) {
|
|
|
9356
9504
|
};
|
|
9357
9505
|
}
|
|
9358
9506
|
//#endregion
|
|
9507
|
+
//#region ../agent-cli/dist/built-ins/skill/usage-hint.js
|
|
9508
|
+
const SKILL_USAGE_CODES = /* @__PURE__ */ new Set([
|
|
9509
|
+
UNKNOWN_OPTION,
|
|
9510
|
+
UNKNOWN_COMMAND,
|
|
9511
|
+
INVALID_INPUT
|
|
9512
|
+
]);
|
|
9513
|
+
/** A usage error whose hint names each Skill copy that differs from this build, since one may have named the input. */
|
|
9514
|
+
async function withDifferingSkill(error, cli, place, runAs) {
|
|
9515
|
+
if (!(error instanceof UsageError) || !SKILL_USAGE_CODES.has(error.code)) return error;
|
|
9516
|
+
let differing;
|
|
9517
|
+
try {
|
|
9518
|
+
differing = await skillOf$1(cli, installOf(cli)).differing(place);
|
|
9519
|
+
} catch (lookup) {
|
|
9520
|
+
if (errnoOf(lookup) === void 0) throw lookup;
|
|
9521
|
+
return error;
|
|
9522
|
+
}
|
|
9523
|
+
if (differing.length === 0) return error;
|
|
9524
|
+
return new UsageError({
|
|
9525
|
+
code: error.code,
|
|
9526
|
+
message: error.message,
|
|
9527
|
+
hint: `${error.hint}; the ${cli.name} skill may name what this build does not know: ${differing.join("; ")}; run \`${runAs} doctor\` to see how to update it`
|
|
9528
|
+
});
|
|
9529
|
+
}
|
|
9530
|
+
//#endregion
|
|
9359
9531
|
//#region ../agent-cli/dist/command-line/suggest.js
|
|
9360
9532
|
const MAX_DISTANCE = 3;
|
|
9361
9533
|
const MIN_SIMILARITY = .4;
|
|
@@ -11066,7 +11238,11 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
11066
11238
|
});
|
|
11067
11239
|
});
|
|
11068
11240
|
} catch (error) {
|
|
11069
|
-
return failed(error,
|
|
11241
|
+
return failed(await withDifferingSkill(error, cli, {
|
|
11242
|
+
cwd,
|
|
11243
|
+
env,
|
|
11244
|
+
packageRoot
|
|
11245
|
+
}, invocation.runAs), noSideTask);
|
|
11070
11246
|
}
|
|
11071
11247
|
const { input, flags } = parsed;
|
|
11072
11248
|
resumed = command.deadline?.resume(input, rerunOf);
|
|
@@ -11134,9 +11310,10 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
11134
11310
|
let served = false;
|
|
11135
11311
|
let settled;
|
|
11136
11312
|
try {
|
|
11137
|
-
const outcome = await control.settle(
|
|
11313
|
+
const outcome = await control.settle(noticesOf(cli, {
|
|
11138
11314
|
builtIn,
|
|
11139
|
-
bin: options.bin
|
|
11315
|
+
bin: options.bin,
|
|
11316
|
+
node: options.node
|
|
11140
11317
|
}, ctx).then(() => execute(command, input, ctx, {
|
|
11141
11318
|
dryRun: flags.dryRun,
|
|
11142
11319
|
confirm: flags.confirm,
|
|
@@ -11196,6 +11373,11 @@ function once(build) {
|
|
|
11196
11373
|
throw outcome.error;
|
|
11197
11374
|
};
|
|
11198
11375
|
}
|
|
11376
|
+
async function noticesOf(cli, launch, ctx) {
|
|
11377
|
+
const install = installOf(cli);
|
|
11378
|
+
await skillOf$1(cli, install).notice(launch, ctx);
|
|
11379
|
+
await install.notice(launch, ctx);
|
|
11380
|
+
}
|
|
11199
11381
|
//#endregion
|
|
11200
11382
|
//#region ../agent-cli/dist/style.js
|
|
11201
11383
|
function colourEnabled(env, stdoutIsTTY) {
|
|
@@ -11278,10 +11460,16 @@ async function routeAndRun(cli, argv, options, write, stopNotice) {
|
|
|
11278
11460
|
...format,
|
|
11279
11461
|
json: routed.json
|
|
11280
11462
|
}));
|
|
11281
|
-
case "usage error":
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11463
|
+
case "usage error": {
|
|
11464
|
+
const place = {
|
|
11465
|
+
...options,
|
|
11466
|
+
packageRoot: packageRootOf(options.bin, options.cwd)
|
|
11467
|
+
};
|
|
11468
|
+
return ranAlone(errorResult(await withDifferingSkill(routed.error, cli, place, runAs), {
|
|
11469
|
+
...misused(routed.node),
|
|
11470
|
+
json: routed.json
|
|
11471
|
+
}));
|
|
11472
|
+
}
|
|
11285
11473
|
case "command": return whileStopping(options.signal, stopNotice === void 0 ? void 0 : () => write.stderr(stopLine(stopNotice, routed.json)), () => runCommand(cli, routed, options, write, misused(routed.spec)));
|
|
11286
11474
|
}
|
|
11287
11475
|
}
|
|
@@ -11344,7 +11532,7 @@ async function runProcess(cli) {
|
|
|
11344
11532
|
//#region package.json
|
|
11345
11533
|
var package_default = {
|
|
11346
11534
|
name: "@duyquangnvx/create-agent-cli",
|
|
11347
|
-
version: "0.
|
|
11535
|
+
version: "0.23.0",
|
|
11348
11536
|
description: "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
11349
11537
|
type: "module",
|
|
11350
11538
|
engines: { "node": ">=22.12.0" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duyquangnvx/create-agent-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@duyquangnvx/agent-cli": "0.
|
|
24
|
+
"@duyquangnvx/agent-cli": "0.23.0",
|
|
25
25
|
"tsdown": "0.23.0",
|
|
26
26
|
"zod": "4.6.7"
|
|
27
27
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
This installs the CLI. The user has installed this skill already.
|
|
2
2
|
|
|
3
|
-
1. Run `node --version` and compare it with the range `npm view {{packageName}} engines.node` prints, which `doctor`'s `node` row also checks once the CLI is installed. Under nvm every Node version has its own global packages, so {{binName}} lands under the Node this shell runs. If that Node is too old, or is not the one the user's terminal runs, tell the user and let them choose before going on.
|
|
3
|
+
1. Run `node --version` and compare it with the range `npm view {{packageName}} engines.node` prints, which `doctor`'s `node` row also checks once the CLI is installed. Under nvm every Node version has its own global packages, so {{binName}} lands under the Node this shell runs. If that Node is too old, or is not the one the user's terminal runs, tell the user and let them choose before going on. That is also why a {{binName}} the user installed can be missing from this shell: ask which Node their terminal runs before installing again.
|
|
4
4
|
2. Hand the user the install line to type, as [Sandbox](#sandbox) says:
|
|
5
5
|
|
|
6
6
|
`! npm install --global {{packageName}}@latest`
|
|
@@ -7,7 +7,7 @@ metadata:
|
|
|
7
7
|
version: "0.0.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
<!-- A skeleton to rewrite around {{binName}}'s real Commands. Leave flags out: `--help` is generated from the code and stays in sync with it, this file does not. -->
|
|
10
|
+
<!-- A skeleton to rewrite around {{binName}}'s real Commands. A line earns its place only when no `--help`, output, hint or `doctor` row tells the agent the same thing: write down what costs it turns to work out, such as a convention, a reason, a trap, or a step that needs the user's consent. Leave flags out: `--help` is generated from the code and stays in sync with it, this file does not. What {{binName}} is for, and the nearby tasks it is not for, go in the description, which the agent always sees. -->
|
|
11
11
|
|
|
12
12
|
# {{binName}}
|
|
13
13
|
|
|
@@ -19,13 +19,6 @@ metadata:
|
|
|
19
19
|
|
|
20
20
|
The line above should show 0.0.0, the version this skill describes. If it says {{binName}} is not installed or shows another version, read [setup](references/setup.md) before anything else.
|
|
21
21
|
|
|
22
|
-
## When to use
|
|
23
|
-
|
|
24
|
-
<!-- The tasks {{binName}} is for, and the nearby tasks it is not for. -->
|
|
25
|
-
|
|
26
|
-
- Greeting someone by name.
|
|
27
|
-
- Writing a greeting card to a file, in English for free or in another language at a cost.
|
|
28
|
-
|
|
29
22
|
## Workflows
|
|
30
23
|
|
|
31
24
|
<!-- Each main task as steps naming the Commands it runs, in order. Move a long workflow to a file under references/ and link it. -->
|
|
@@ -43,11 +36,9 @@ The line above should show 0.0.0, the version this skill describes. If it says {
|
|
|
43
36
|
|
|
44
37
|
To put a message under the greeting, pass `-` after the name and pipe the message in with a heredoc, so its quotes and newlines reach the card intact.
|
|
45
38
|
|
|
46
|
-
Pass `--json` whenever you parse the output: stdout then holds only the data. A Command that changes something takes `--dry-run`, which prints its Plan, the files it writes and its cost, and changes nothing: run it first when unsure. A destructive Command also needs `--confirm=<target>`, and its error's Next step gives the exact command.
|
|
47
|
-
|
|
48
39
|
## Recovering from errors
|
|
49
40
|
|
|
50
|
-
|
|
41
|
+
Do what the error's hint says, except for a code below:
|
|
51
42
|
|
|
52
43
|
| Code | What to do |
|
|
53
44
|
|---|---|
|
|
@@ -8,11 +8,9 @@ Work through a section in order and stop at a step that fails. Ask the user to d
|
|
|
8
8
|
|
|
9
9
|
## Check
|
|
10
10
|
|
|
11
|
-
Run `{{runAs}} doctor --json
|
|
11
|
+
Run `{{runAs}} doctor --json`, which changes nothing. Hand the user each line of its `next` to type with `!`, in order, then run `doctor` again.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
- `next` lists every fix in order. Hand the user each one to type with `!`, then run `doctor` again.
|
|
15
|
-
- {{skillCheck}} If the session does not show it, ask the user to type `/reload-skills`, and failing that to restart Claude Code.
|
|
13
|
+
{{skillCheck}} If the session does not show it, ask the user to type `/reload-skills`, and failing that to restart Claude Code.
|
|
16
14
|
|
|
17
15
|
`{{runAs}} --version` names on its second line the `CHANGELOG.md` installed with the CLI. When the user asks what changed, read it from the top, newest first, down to the version in question.
|
|
18
16
|
|