@duyquangnvx/create-agent-cli 0.14.0 → 0.15.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/bin.js +126 -52
  3. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## v0.15.0 (2026-10-27)
8
+
9
+ ### Added
10
+
11
+ - A Packaged-skill CLI gives the `skill` row's problem as a Notice before every Command run from an install, Built-in Commands aside: a missing copy or one of another `metadata.version` (with ``run `<run-as> skill install` ``), or a personal copy under `~/.claude/skills`. A file it cannot read gives a Notice that the copy could not be checked, and the Command still runs.
12
+ - `doctor` of a Packaged-skill CLI has an advisory `agents` row: a project root `AGENTS.md` without the CLI's block, or with one `skill install` would rewrite, is a problem whose fix is `<run-as> skill install`; a `CLAUDE.md` without an `@AGENTS.md` line is one with no fix. The agent-cli skill says a CLI need not check either itself.
13
+ - An Error table entry can name a string key of its `details` in `print`, such as `print: "stack"`, which text mode prints between the message and the hint, so a CLI need not repeat it in the message. `--json` and help JSON are unchanged. The agent-cli skill covers it.
14
+
15
+ ### Upgrade from v0.14.0
16
+
17
+ - A Packaged-skill CLI that gives its own Notice of an outdated Skill copy, or has its own `doctor` row for its `AGENTS.md` block, deletes it: the Runtime now gives both.
18
+
7
19
  ## v0.14.0 (2026-10-27)
8
20
 
9
21
  ### Added
package/dist/bin.js CHANGED
@@ -5869,13 +5869,22 @@ function debugTrace(error, format) {
5869
5869
  function errorsOf(error) {
5870
5870
  return error instanceof AggregateError && error.errors.length > 0 ? error.errors.flatMap(errorsOf) : [error];
5871
5871
  }
5872
+ /** The `details` field that `error`'s code declares for text mode to print, when it holds a string. */
5873
+ function printedDetail(error, format) {
5874
+ if (!(error instanceof CliError)) return void 0;
5875
+ const key = format.errors[error.code]?.print;
5876
+ const { details } = error;
5877
+ if (key === void 0 || typeof details !== "object" || details === null) return void 0;
5878
+ const value = Reflect.get(details, key);
5879
+ return typeof value === "string" ? value : void 0;
5880
+ }
5872
5881
  function errorLines(error, format) {
5873
5882
  const fields = fieldsOf$1(error, format);
5874
- const stack = debugTrace(error, format);
5883
+ const blocks = [printedDetail(error, format), debugTrace(error, format)].filter((block) => block !== void 0);
5875
5884
  const { style } = format;
5876
5885
  const label = style.red(format.isBug(error) ? "internal error:" : "error:");
5877
- const trace = stack === void 0 ? "" : `${stack}\n`;
5878
- return `${label} ${fields.message}\n${trace}${style.cyan("hint:")} ${fields.hint}\n`;
5886
+ const between = blocks.map((block) => `${block}\n`).join("");
5887
+ return `${label} ${fields.message}\n${between}${style.cyan("hint:")} ${fields.hint}\n`;
5879
5888
  }
5880
5889
  function formatRuntimeError(error, format) {
5881
5890
  const errors = errorsOf(error);
@@ -7435,6 +7444,87 @@ function dependencyRelease(cli, install, { cwd, root, standing }) {
7435
7444
  };
7436
7445
  }
7437
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
7484
+ };
7485
+ return {
7486
+ path,
7487
+ block,
7488
+ change: existing.includes(markersOf(cli.name).begin) ? "rewrite" : "add"
7489
+ };
7490
+ }
7491
+ async function handEditsAt(root) {
7492
+ const claudeMd = join(root, "CLAUDE.md");
7493
+ const text = await orMissing(readFile(claudeMd, "utf8"));
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) {
7498
+ return {
7499
+ name: "agents",
7500
+ advisory: true,
7501
+ run: async (ctx) => {
7502
+ const root = await projectRootOf(ctx.cwd);
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
+ }
7525
+ };
7526
+ }
7527
+ //#endregion
7438
7528
  //#region ../agent-cli/dist/built-ins/skills.js
7439
7529
  const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
7440
7530
  const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
@@ -7584,6 +7674,22 @@ async function packagedSkillFinding(cli, folder, ctx) {
7584
7674
  skill
7585
7675
  };
7586
7676
  }
7677
+ /** Gives a Packaged skill's `skill` row problem as a Notice, since an agent rarely runs `doctor`. */
7678
+ async function noticeSkillCopy(cli, { builtIn, bin }, ctx) {
7679
+ if (builtIn || bin === void 0 || cli.commands === void 0) return;
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
+ }
7587
7693
  //#endregion
7588
7694
  //#region ../agent-cli/dist/built-ins/doctor-rows.js
7589
7695
  function ok(message) {
@@ -7778,7 +7884,8 @@ function doctorChecks(cli, launch, read) {
7778
7884
  ...toolRows(cli.tools ?? [], cli.commands),
7779
7885
  installRow(cli, launch, survey),
7780
7886
  registryRow(cli, launch, survey),
7781
- skillRow(cli)
7887
+ skillRow(cli),
7888
+ ...packagedFolderOf(cli) === void 0 ? [] : [agentsRow(cli)]
7782
7889
  ];
7783
7890
  }
7784
7891
  //#endregion
@@ -8245,46 +8352,11 @@ async function sameContent(left, right) {
8245
8352
  const [a, b] = await Promise.all([readFile(left), readFile(right)]);
8246
8353
  return a.equals(b);
8247
8354
  }
8248
- /** One paragraph telling every session that the CLI exists, how to run it and which skill to load. */
8249
- function agentsBlock(cli) {
8250
- const { install } = cli;
8251
- const where = install?.mode === "dependency" ? `, and only from a package that has \`${install.package}\` in its dependencies; from anywhere else npx reports the package missing` : "";
8252
- const what = cli.description.replace(/\.$/, "");
8253
- return `\`${cli.name}\`: ${what}. Run it as \`${runAsOf(cli)}\`${where}. Load the \`${cli.name}\` skill before using it.`;
8254
- }
8255
- function markersOf(name) {
8256
- return {
8257
- begin: `<!-- BEGIN:${name} -->`,
8258
- end: `<!-- END:${name} -->`
8259
- };
8260
- }
8261
- /** `text` with the block between its markers, appended when they are missing; nothing else changes. */
8262
- function withBlock(text, block, { begin, end }) {
8263
- const whole = `${begin}\n${block}\n${end}`;
8264
- const start = text.indexOf(begin);
8265
- const stop = start === -1 ? -1 : text.indexOf(end, start);
8266
- if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
8267
- if (text === "") return `${whole}\n`;
8268
- return `${text}${text.endsWith("\n") ? "" : "\n"}\n${whole}\n`;
8269
- }
8270
- function blockChangeOf(existing, block, markers) {
8271
- if (existing === void 0) return "create";
8272
- if (withBlock(existing, block, markers) === existing) return null;
8273
- return existing.includes(markers.begin) ? "rewrite" : "add";
8274
- }
8275
- async function handEditsAt(root) {
8276
- const claudeMd = join(root, "CLAUDE.md");
8277
- const text = await orMissing(readFile(claudeMd, "utf8"));
8278
- if (text === void 0 || text.split(/\r?\n/).some((line) => line.trim() === "@AGENTS.md")) return [];
8279
- return [`add a line \`@AGENTS.md\` to ${claudeMd}, so Claude Code reads AGENTS.md`];
8280
- }
8281
8355
  async function planOf(cli, folder, cwd, packageRoot) {
8282
8356
  const source = join(packageRoot, folder);
8283
8357
  const { root, copy } = await skillCopyOf(cli, cwd);
8284
8358
  const [shipped, present] = await Promise.all([filesIn(source), filesIn(copy)]);
8285
8359
  const differs = await Promise.all(shipped.map(async (file) => present.includes(file) && !await sameContent(join(source, file), join(copy, file))));
8286
- const agentsPath = join(root, "AGENTS.md");
8287
- const block = agentsBlock(cli);
8288
8360
  return {
8289
8361
  source,
8290
8362
  copy,
@@ -8292,11 +8364,7 @@ async function planOf(cli, folder, cwd, packageRoot) {
8292
8364
  replace: shipped.filter((_file, index) => differs[index]),
8293
8365
  remove: present.filter((file) => !shipped.includes(file)),
8294
8366
  sameVersion: (await skillVersionsOf(source, copy)).same,
8295
- agentsMd: {
8296
- path: agentsPath,
8297
- block,
8298
- change: blockChangeOf(await orMissing(readFile(agentsPath, "utf8")), block, markersOf(cli.name))
8299
- },
8367
+ agentsMd: await agentsMdAt(cli, root),
8300
8368
  handEdits: await handEditsAt(root)
8301
8369
  };
8302
8370
  }
@@ -8357,10 +8425,10 @@ function skillInstallCommand(cli, folder) {
8357
8425
  if (plan.sameVersion && plan.remove.length > 0 && !ctx.force) throw editedRemovals(plan, ctx);
8358
8426
  for (const file of [...plan.write, ...plan.replace]) await ctx.files.write(join(plan.copy, file), await readFile(join(plan.source, file)));
8359
8427
  for (const file of plan.remove) await ctx.files.remove(join(plan.copy, file));
8360
- const { path, block, change } = plan.agentsMd;
8428
+ const { path, change } = plan.agentsMd;
8361
8429
  if (change !== null) {
8362
8430
  const existing = await orMissing(readFile(path, "utf8")) ?? "";
8363
- await ctx.files.write(path, withBlock(existing, block, markersOf(cli.name)));
8431
+ await ctx.files.write(path, withBlock(cli, existing));
8364
8432
  }
8365
8433
  return {
8366
8434
  copy: plan.copy,
@@ -8860,7 +8928,10 @@ function agentCli() {
8860
8928
  }
8861
8929
  //#endregion
8862
8930
  //#region ../agent-cli/dist/error-table.js
8863
- /** Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites. */
8931
+ /**
8932
+ * Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites;
8933
+ * `print` must name a string key of the code's `details`.
8934
+ */
8864
8935
  function defineErrors(table) {
8865
8936
  return table;
8866
8937
  }
@@ -9952,7 +10023,10 @@ async function runCommand(cli, routed, options, write, baseFormat) {
9952
10023
  let served = false;
9953
10024
  let settled;
9954
10025
  try {
9955
- const outcome = await control.settle(execute(command, input, ctx, {
10026
+ const outcome = await control.settle(noticeSkillCopy(cli, {
10027
+ builtIn,
10028
+ bin: options.bin
10029
+ }, ctx).then(() => execute(command, input, ctx, {
9956
10030
  dryRun: flags.dryRun,
9957
10031
  confirm: flags.confirm,
9958
10032
  yes: flags.yes,
@@ -9965,7 +10039,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
9965
10039
  },
9966
10040
  files,
9967
10041
  guardOutputs: outputs.guard
9968
- }));
10042
+ })));
9969
10043
  if (served) return {
9970
10044
  result: STOPPED_RESULT,
9971
10045
  finishSideTask
@@ -10148,14 +10222,14 @@ async function runProcess(cli) {
10148
10222
  }
10149
10223
  //#endregion
10150
10224
  //#region package.json
10151
- var version$1 = "0.14.0";
10225
+ var version$1 = "0.15.0";
10152
10226
  var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
10153
10227
  //#endregion
10154
10228
  //#region src/build.ts
10155
10229
  const build = {
10156
- "sha": "f114cf0",
10230
+ "sha": "cd3df50",
10157
10231
  "dirty": false,
10158
- "builtAt": "2026-10-27T02:06:04.000Z"
10232
+ "builtAt": "2026-10-27T04:23:15.000Z"
10159
10233
  };
10160
10234
  //#endregion
10161
10235
  //#region src/fill.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duyquangnvx/create-agent-cli",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -20,7 +20,7 @@
20
20
  "access": "public"
21
21
  },
22
22
  "devDependencies": {
23
- "@duyquangnvx/agent-cli": "0.14.0",
23
+ "@duyquangnvx/agent-cli": "0.15.0",
24
24
  "tsdown": "0.23.0",
25
25
  "zod": "4.6.7"
26
26
  },