@duyquangnvx/create-agent-cli 0.7.0 → 0.9.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 +20 -0
- package/README.md +3 -3
- package/dist/bin.js +94 -66
- package/package.json +2 -2
- package/template/CHANGELOG.md +1 -1
- package/template/package.json +1 -1
- package/template/pnpm-workspace.yaml +3 -2
- package/template/skills/{{binName}}/references/setup.md +1 -1
- package/template/test/cli.test.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## v0.9.0 (2026-10-20)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- The Scaffolder's `--skill-hub <git URL>` names the Skill Hub each release commits the new CLI's skill to: it becomes `skill.source` in `defineCli`, `skillHub` in `scripts/release.ts` and the README's skill line. See ADR 0009. It refuses a URL that does not end in `.git` or holds a query or fragment, and with it a name the release cannot put in a hub (`SKILL_NAME_INVALID`).
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Breaking:** `doctor`'s `skill` row and `update`'s `next` install the skill only from a declared `skill.source`, no longer from package.json `repository` at `#release`, a branch `@duyquangnvx/release` 0.4 stops moving. A CLI without `skill.source` still gets `skills update` for an older copy.
|
|
16
|
+
- **Breaking:** the Scaffolder's `--repository` only sets package.json `repository`; the skill line comes from `--skill-hub`. The scaffolded template releases with `@duyquangnvx/release` 0.4.0.
|
|
17
|
+
- **Breaking:** the agent-cli skill installs from the Skill Hub: `npx skills add https://github.com/duyquangnvx/skills.git --skill agent-cli -g`.
|
|
18
|
+
|
|
19
|
+
## v0.8.0 (2026-10-20)
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **Breaking:** `update` shows only the Upgrade steps of a skipped release whose CHANGELOG section lists them under `### Upgrade from v<version>`, under `upgrade steps for <version>:`. A release whose only step is `Nothing to do.` is left out, and one without the heading still shows its whole section under `changes in <version>:`.
|
|
24
|
+
- **Breaking:** each entry of `upgrades` in `update --json` is `{ version, steps }` or `{ version, notes }`.
|
|
25
|
+
- The scaffolded template's CHANGELOG asks each release from the second on to hold `### Upgrade from v<the release below>`, and its setup reference tells the agent to do the steps `update` prints. The agent-cli skill's shipping reference explains the convention.
|
|
26
|
+
|
|
7
27
|
## v0.7.0 (2026-10-20)
|
|
8
28
|
|
|
9
29
|
### Added
|
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
Creates a new Agent CLI repository already wired to [`@duyquangnvx/agent-cli`](https://www.npmjs.com/package/@duyquangnvx/agent-cli):
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
pnpm create @duyquangnvx/agent-cli <name> --description "One line saying what it does" --
|
|
6
|
+
pnpm create @duyquangnvx/agent-cli <name> --description "One line saying what it does" --skill-hub https://github.com/<owner>/skills.git
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
The new repository has an Error table, a port, two example Commands (one writing a file at a cost) and their test, a bundled build that stamps the commit and build time into `--version`, CI, a release script, a CHANGELOG, an `AGENTS.md`, and a skeleton skill for the new CLI whose setup reference installs, checks and updates it, so a user installs the skill first and lets their agent do the rest. `--
|
|
9
|
+
The new repository has an Error table, a port, two example Commands (one writing a file at a cost) and their test, a bundled build that stamps the commit and build time into `--version`, CI, a release script, a CHANGELOG, an `AGENTS.md`, and a skeleton skill for the new CLI whose setup reference installs, checks and updates it, so a user installs the skill first and lets their agent do the rest. `--skill-hub` names the Skill Hub each release commits that skill to and agents install it from. Pass `--dry-run` to see what it would write.
|
|
10
10
|
|
|
11
|
-
See the [repository](https://github.com/duyquangnvx/cli-for-agent) for an overview and the [agent-cli skill](https://github.com/duyquangnvx/cli-for-agent/blob/
|
|
11
|
+
See the [repository](https://github.com/duyquangnvx/cli-for-agent) for an overview and the [agent-cli skill](https://github.com/duyquangnvx/cli-for-agent/blob/main/skills/agent-cli/SKILL.md) for how to build on it.
|
package/dist/bin.js
CHANGED
|
@@ -7049,36 +7049,8 @@ async function globalInstallOf(bin, ctx) {
|
|
|
7049
7049
|
};
|
|
7050
7050
|
}
|
|
7051
7051
|
//#endregion
|
|
7052
|
-
//#region ../agent-cli/dist/manifest.js
|
|
7053
|
-
const link$1 = union([string(), object({ url: string() })]).transform((value) => typeof value === "string" ? value : value.url).optional().catch(void 0);
|
|
7054
|
-
const manifestSchema = object({
|
|
7055
|
-
repository: link$1,
|
|
7056
|
-
bugs: link$1
|
|
7057
|
-
});
|
|
7058
|
-
const NO_MANIFEST = {};
|
|
7059
|
-
function manifestAt(packageRoot) {
|
|
7060
|
-
let manifest;
|
|
7061
|
-
try {
|
|
7062
|
-
manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
7063
|
-
} catch {
|
|
7064
|
-
return NO_MANIFEST;
|
|
7065
|
-
}
|
|
7066
|
-
const parsed = manifestSchema.safeParse(manifest);
|
|
7067
|
-
return parsed.success ? parsed.data : NO_MANIFEST;
|
|
7068
|
-
}
|
|
7069
|
-
//#endregion
|
|
7070
7052
|
//#region ../agent-cli/dist/built-ins/skills.js
|
|
7071
7053
|
const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
|
|
7072
|
-
/** The branch a release moves to the released commit, which holds the skill of that version. */
|
|
7073
|
-
const RELEASE_BRANCH$1 = "release";
|
|
7074
|
-
const SHORTHAND = /^(?:(?:github:)?[\w.-]+\/[\w.-]+|gitlab:[\w.-]+(?:\/[\w.-]+)+)$/;
|
|
7075
|
-
const GIT_URL_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
7076
|
-
"https:",
|
|
7077
|
-
"http:",
|
|
7078
|
-
"ssh:",
|
|
7079
|
-
"git:"
|
|
7080
|
-
]);
|
|
7081
|
-
const SCP_STYLE = /^[\w.-]+@[\w.-]+:[\w./-]+$/;
|
|
7082
7054
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
7083
7055
|
const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
|
|
7084
7056
|
/** The version a SKILL.md's frontmatter `metadata.version` states. */
|
|
@@ -7127,18 +7099,6 @@ async function skillCopies(cliName, version, { cwd, env }) {
|
|
|
7127
7099
|
}
|
|
7128
7100
|
return copies;
|
|
7129
7101
|
}
|
|
7130
|
-
function sourceFromRepository(repository) {
|
|
7131
|
-
if (SHORTHAND.test(repository)) return `${repository}#${RELEASE_BRANCH$1}`;
|
|
7132
|
-
const url = repository.replace(/^git\+/, "");
|
|
7133
|
-
if (!(URL.canParse(url) && GIT_URL_PROTOCOLS.has(new URL(url).protocol)) && !SCP_STYLE.test(url)) return void 0;
|
|
7134
|
-
return `${url.endsWith(".git") ? url : `${url}.git`}#${RELEASE_BRANCH$1}`;
|
|
7135
|
-
}
|
|
7136
|
-
/** What the installer installs the CLI's skill from: the declared source, else the package's repository. */
|
|
7137
|
-
function skillSource({ skill }, packageRoot) {
|
|
7138
|
-
if (skill !== void 0) return skill.source;
|
|
7139
|
-
const { repository } = manifestAt(packageRoot);
|
|
7140
|
-
return repository === void 0 ? void 0 : sourceFromRepository(repository);
|
|
7141
|
-
}
|
|
7142
7102
|
function fixFor(cliName, copies, source) {
|
|
7143
7103
|
const has = (wanted) => copies.some(({ state }) => state === wanted);
|
|
7144
7104
|
const update = `npx -y skills update ${cliName}`;
|
|
@@ -7151,7 +7111,7 @@ async function skillReport(cli, version, ctx) {
|
|
|
7151
7111
|
const copies = await skillCopies(cli.name, version, ctx);
|
|
7152
7112
|
return {
|
|
7153
7113
|
copies,
|
|
7154
|
-
fix: fixFor(cli.name, copies,
|
|
7114
|
+
fix: fixFor(cli.name, copies, cli.skill?.source)
|
|
7155
7115
|
};
|
|
7156
7116
|
}
|
|
7157
7117
|
//#endregion
|
|
@@ -7554,8 +7514,20 @@ var RunControl = class {
|
|
|
7554
7514
|
}
|
|
7555
7515
|
};
|
|
7556
7516
|
//#endregion
|
|
7557
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7517
|
+
//#region ../agent-cli/dist/built-ins/upgrades.js
|
|
7518
|
+
/** A skipped release's Upgrade steps, or its whole section when it lists none. */
|
|
7519
|
+
const upgradeSchema = union([object({
|
|
7520
|
+
version: string(),
|
|
7521
|
+
steps: array(string())
|
|
7522
|
+
}), object({
|
|
7523
|
+
version: string(),
|
|
7524
|
+
notes: string()
|
|
7525
|
+
})]);
|
|
7558
7526
|
const RELEASE_HEADING = /^## v?(\S+)/;
|
|
7527
|
+
const UPGRADE_HEADING = /^### Upgrade from v\S+$/;
|
|
7528
|
+
const HEADING = /^#{1,6} /;
|
|
7529
|
+
const ITEM = /^[-*] /;
|
|
7530
|
+
const NOTHING_TO_DO = /^nothing to do\.?$/i;
|
|
7559
7531
|
function releasesIn(changelog) {
|
|
7560
7532
|
const releases = [];
|
|
7561
7533
|
let current;
|
|
@@ -7570,16 +7542,33 @@ function releasesIn(changelog) {
|
|
|
7570
7542
|
if (current !== void 0) releases.push(current);
|
|
7571
7543
|
} else current?.lines.push(line);
|
|
7572
7544
|
}
|
|
7573
|
-
return releases
|
|
7545
|
+
return releases;
|
|
7546
|
+
}
|
|
7547
|
+
function listedSteps(lines) {
|
|
7548
|
+
const start = lines.findIndex((line) => UPGRADE_HEADING.test(line.trimEnd()));
|
|
7549
|
+
if (start === -1) return [];
|
|
7550
|
+
const end = lines.findIndex((line, i) => i > start && HEADING.test(line));
|
|
7551
|
+
const body = lines.slice(start + 1, end === -1 ? void 0 : end).filter((line) => line.trim() !== "");
|
|
7552
|
+
const starts = body.flatMap((line, i) => ITEM.test(line) ? [i] : []);
|
|
7553
|
+
return starts.map((first, i) => body.slice(first, starts[i + 1]).map((line) => line.trim()).join(" ").replace(ITEM, ""));
|
|
7554
|
+
}
|
|
7555
|
+
function upgradeOf({ version, lines }) {
|
|
7556
|
+
const listed = listedSteps(lines);
|
|
7557
|
+
if (listed.length === 0) return [{
|
|
7574
7558
|
version,
|
|
7575
7559
|
notes: lines.join("\n").trim()
|
|
7576
|
-
}
|
|
7560
|
+
}];
|
|
7561
|
+
const todo = listed.filter((step) => !NOTHING_TO_DO.test(step));
|
|
7562
|
+
return todo.length === 0 ? [] : [{
|
|
7563
|
+
version,
|
|
7564
|
+
steps: todo
|
|
7565
|
+
}];
|
|
7577
7566
|
}
|
|
7578
7567
|
/**
|
|
7579
|
-
* What
|
|
7580
|
-
* `packageDir`; none when the package ships no CHANGELOG.
|
|
7568
|
+
* What each release after `from` up to `to` asks of the operator, oldest first, from the
|
|
7569
|
+
* CHANGELOG.md in `packageDir`; none when the package ships no CHANGELOG.
|
|
7581
7570
|
*/
|
|
7582
|
-
async function
|
|
7571
|
+
async function upgradesOf(packageDir, from, to) {
|
|
7583
7572
|
let changelog;
|
|
7584
7573
|
try {
|
|
7585
7574
|
changelog = await readFile(join(packageDir, "CHANGELOG.md"), "utf8");
|
|
@@ -7587,7 +7576,7 @@ async function upgradeNotes(packageDir, from, to) {
|
|
|
7587
7576
|
if (isMissingFile(error)) return [];
|
|
7588
7577
|
throw error;
|
|
7589
7578
|
}
|
|
7590
|
-
return releasesIn(changelog).filter(({ version }) => compareVersions(version, from) > 0 && compareVersions(version, to) <= 0).sort((a, b) => compareVersions(a.version, b.version));
|
|
7579
|
+
return releasesIn(changelog).filter(({ version }) => compareVersions(version, from) > 0 && compareVersions(version, to) <= 0).sort((a, b) => compareVersions(a.version, b.version)).flatMap(upgradeOf);
|
|
7591
7580
|
}
|
|
7592
7581
|
//#endregion
|
|
7593
7582
|
//#region ../agent-cli/dist/built-ins/update.js
|
|
@@ -7598,18 +7587,18 @@ const updateSchema = object({
|
|
|
7598
7587
|
version: string(),
|
|
7599
7588
|
prefix: string()
|
|
7600
7589
|
}).nullable(),
|
|
7601
|
-
upgrades: array(
|
|
7602
|
-
version: string(),
|
|
7603
|
-
notes: string()
|
|
7604
|
-
})),
|
|
7590
|
+
upgrades: array(upgradeSchema),
|
|
7605
7591
|
next: array(string())
|
|
7606
7592
|
});
|
|
7607
7593
|
function nothingToInstall({ from, latest }) {
|
|
7608
7594
|
return standingOf(from, latest) === "current" ? `already on ${from}, the latest release: nothing to install` : `${from} is newer than the latest release ${latest}: nothing to install`;
|
|
7609
7595
|
}
|
|
7596
|
+
function renderUpgrade(upgrade) {
|
|
7597
|
+
return "steps" in upgrade ? [`\nupgrade steps for ${upgrade.version}:`, ...upgrade.steps.map((step) => `- ${step}`)].join("\n") : `\nchanges in ${upgrade.version}:\n${upgrade.notes}`;
|
|
7598
|
+
}
|
|
7610
7599
|
function renderUpdate(cli, install, update) {
|
|
7611
7600
|
const { installed } = update;
|
|
7612
|
-
const head = installed === null ? [nothingToInstall(update)] : [`installed ${install.package}@${installed.version} with the npm under ${installed.prefix}, replacing ${update.from}`, ...update.upgrades.map(
|
|
7601
|
+
const head = installed === null ? [nothingToInstall(update)] : [`installed ${install.package}@${installed.version} with the npm under ${installed.prefix}, replacing ${update.from}`, ...update.upgrades.map(renderUpgrade)];
|
|
7613
7602
|
const next = update.next.map((command) => `next: ${command}, so the ${cli.name} skill describes ${update.latest}`);
|
|
7614
7603
|
return (next.length === 0 ? head : [
|
|
7615
7604
|
...head,
|
|
@@ -7672,7 +7661,7 @@ function updateCommand(cli, install, { bin, node }) {
|
|
|
7672
7661
|
version: latest,
|
|
7673
7662
|
prefix
|
|
7674
7663
|
},
|
|
7675
|
-
upgrades: await
|
|
7664
|
+
upgrades: await upgradesOf(plan.packageDir, from, latest),
|
|
7676
7665
|
next: await skillNext(cli, latest, ctx)
|
|
7677
7666
|
};
|
|
7678
7667
|
if (ctx.signal.aborted) {
|
|
@@ -8756,6 +8745,18 @@ async function execute(command, input, ctx, { dryRun, confirm, yes, page, invoca
|
|
|
8756
8745
|
}
|
|
8757
8746
|
return outcomeOf(await command.apply(plan, ctx), (data, style) => command.render(data, style));
|
|
8758
8747
|
}
|
|
8748
|
+
const manifestSchema = object({ bugs: union([string(), object({ url: string() })]).transform((value) => typeof value === "string" ? value : value.url).optional().catch(void 0) });
|
|
8749
|
+
const NO_MANIFEST = {};
|
|
8750
|
+
function manifestAt(packageRoot) {
|
|
8751
|
+
let manifest;
|
|
8752
|
+
try {
|
|
8753
|
+
manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
8754
|
+
} catch {
|
|
8755
|
+
return NO_MANIFEST;
|
|
8756
|
+
}
|
|
8757
|
+
const parsed = manifestSchema.safeParse(manifest);
|
|
8758
|
+
return parsed.success ? parsed.data : NO_MANIFEST;
|
|
8759
|
+
}
|
|
8759
8760
|
//#endregion
|
|
8760
8761
|
//#region ../agent-cli/dist/parse-input.js
|
|
8761
8762
|
const NO_INPUT = object({});
|
|
@@ -9408,14 +9409,14 @@ async function runProcess(cli) {
|
|
|
9408
9409
|
}
|
|
9409
9410
|
//#endregion
|
|
9410
9411
|
//#region package.json
|
|
9411
|
-
var version$1 = "0.
|
|
9412
|
+
var version$1 = "0.9.0";
|
|
9412
9413
|
var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
|
|
9413
9414
|
//#endregion
|
|
9414
9415
|
//#region src/build.ts
|
|
9415
9416
|
const build = {
|
|
9416
|
-
"sha": "
|
|
9417
|
+
"sha": "ff9a1b4",
|
|
9417
9418
|
"dirty": false,
|
|
9418
|
-
"builtAt": "2026-10-
|
|
9419
|
+
"builtAt": "2026-10-20T09:52:22.284Z"
|
|
9419
9420
|
};
|
|
9420
9421
|
//#endregion
|
|
9421
9422
|
//#region src/steps.ts
|
|
@@ -9549,8 +9550,17 @@ const version = version$1;
|
|
|
9549
9550
|
//#region src/create.ts
|
|
9550
9551
|
const { defineCommand } = agentCli();
|
|
9551
9552
|
const PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?([a-z0-9][a-z0-9._-]*)$/;
|
|
9552
|
-
const
|
|
9553
|
-
const
|
|
9553
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
9554
|
+
const NO_SKILL_HUB = "<!-- Set `skill.source` in `defineCli` and `skillHub` in `scripts/release.ts` to the git URL of the Skill Hub each release commits the skill to, then put here the `! npx -y skills add` line that `node dist/bin.js doctor` gives as the `skill` row's fix. -->";
|
|
9555
|
+
const SKILL_HUB_ANCHORS = [{
|
|
9556
|
+
file: "src/cli.ts",
|
|
9557
|
+
before: " commands: {",
|
|
9558
|
+
line: (hub) => ` skill: { source: ${JSON.stringify(hub)} },\n`
|
|
9559
|
+
}, {
|
|
9560
|
+
file: "scripts/release.ts",
|
|
9561
|
+
before: " smoke: {",
|
|
9562
|
+
line: (hub) => ` skillHub: ${JSON.stringify(hub)},\n`
|
|
9563
|
+
}];
|
|
9554
9564
|
function errorCode(error) {
|
|
9555
9565
|
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
9556
9566
|
}
|
|
@@ -9563,9 +9573,16 @@ async function isFree(path) {
|
|
|
9563
9573
|
throw error;
|
|
9564
9574
|
}
|
|
9565
9575
|
}
|
|
9566
|
-
function skillInstallLine(
|
|
9567
|
-
|
|
9568
|
-
|
|
9576
|
+
function skillInstallLine(skillHub, binName) {
|
|
9577
|
+
return skillHub === void 0 ? NO_SKILL_HUB : `\`! npx -y skills add ${skillHub} --skill ${binName} -g\``;
|
|
9578
|
+
}
|
|
9579
|
+
async function setSkillHub(root, skillHub) {
|
|
9580
|
+
for (const { file, before, line } of SKILL_HUB_ANCHORS) {
|
|
9581
|
+
const path = join(root, file);
|
|
9582
|
+
const text = await readFile(path, "utf8");
|
|
9583
|
+
if (!text.includes(before)) throw new Error(`the template's ${file} has no \`${before}\` line to put the Skill Hub before`);
|
|
9584
|
+
await writeFile(path, text.replace(before, `${line(skillHub)}${before}`));
|
|
9585
|
+
}
|
|
9569
9586
|
}
|
|
9570
9587
|
const MANIFEST = record(string(), unknown());
|
|
9571
9588
|
async function setRepository(root, repository) {
|
|
@@ -9574,6 +9591,13 @@ async function setRepository(root, repository) {
|
|
|
9574
9591
|
const entries = Object.entries(manifest).flatMap((entry) => entry[0] === "description" ? [entry, ["repository", repository]] : [entry]);
|
|
9575
9592
|
await writeFile(path, `${JSON.stringify(Object.fromEntries(entries), null, 2)}\n`);
|
|
9576
9593
|
}
|
|
9594
|
+
function ensureSkillName(binName) {
|
|
9595
|
+
if (!SKILL_NAME.test(binName)) throw new UsageError({
|
|
9596
|
+
code: "SKILL_NAME_INVALID",
|
|
9597
|
+
message: `${binName} cannot name a skill in a Skill Hub, whose names are lowercase letters, digits and single hyphens`,
|
|
9598
|
+
hint: "choose a name such as my-cli, or leave out --skill-hub"
|
|
9599
|
+
});
|
|
9600
|
+
}
|
|
9577
9601
|
async function ensureFree(path) {
|
|
9578
9602
|
if (!await isFree(path)) throw new UsageError({
|
|
9579
9603
|
code: "TARGET_NOT_EMPTY",
|
|
@@ -9594,10 +9618,12 @@ const create = defineCommand({
|
|
|
9594
9618
|
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
9595
9619
|
install: boolean().default(true).describe("run pnpm install"),
|
|
9596
9620
|
git: boolean().default(true).describe("create a git repository with an initial commit"),
|
|
9597
|
-
repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository
|
|
9621
|
+
repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository"),
|
|
9622
|
+
skillHub: url({ protocol: /^https$/ }).refine((url) => new URL(url).search === "" && new URL(url).hash === "", "must name the hub's repository with no query or fragment").refine((url) => new URL(url).pathname.endsWith(".git"), "must end in .git").optional().describe("the https git URL of the Skill Hub each release commits the CLI's skill to")
|
|
9598
9623
|
}),
|
|
9599
|
-
plan: async ({ name, description, install, git, repository }, ctx) => {
|
|
9624
|
+
plan: async ({ name, description, install, git, repository, skillHub }, ctx) => {
|
|
9600
9625
|
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
9626
|
+
if (skillHub !== void 0) ensureSkillName(binName);
|
|
9601
9627
|
const path = resolve(ctx.cwd, binName);
|
|
9602
9628
|
await ensureFree(path);
|
|
9603
9629
|
const values = {
|
|
@@ -9606,7 +9632,7 @@ const create = defineCommand({
|
|
|
9606
9632
|
description,
|
|
9607
9633
|
debugVariable: debugVariable(binName),
|
|
9608
9634
|
runtimeVersion: version,
|
|
9609
|
-
skillInstall: skillInstallLine(
|
|
9635
|
+
skillInstall: skillInstallLine(skillHub, binName)
|
|
9610
9636
|
};
|
|
9611
9637
|
return {
|
|
9612
9638
|
path,
|
|
@@ -9617,13 +9643,15 @@ const create = defineCommand({
|
|
|
9617
9643
|
git
|
|
9618
9644
|
}),
|
|
9619
9645
|
install,
|
|
9620
|
-
repository
|
|
9646
|
+
repository,
|
|
9647
|
+
skillHub
|
|
9621
9648
|
};
|
|
9622
9649
|
},
|
|
9623
9650
|
apply: async (plan, ctx) => {
|
|
9624
9651
|
await mkdir(plan.path, { recursive: true });
|
|
9625
9652
|
await writeTemplate(plan.path, plan.files, plan.values);
|
|
9626
9653
|
if (plan.repository !== void 0) await setRepository(plan.path, plan.repository);
|
|
9654
|
+
if (plan.skillHub !== void 0) await setSkillHub(plan.path, plan.skillHub);
|
|
9627
9655
|
await runSteps(plan.steps, plan.path, ctx);
|
|
9628
9656
|
return {
|
|
9629
9657
|
path: plan.path,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duyquangnvx/create-agent-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@duyquangnvx/agent-cli": "0.
|
|
22
|
+
"@duyquangnvx/agent-cli": "0.9.0",
|
|
23
23
|
"tsdown": "0.23.0",
|
|
24
24
|
"zod": "4.6.7"
|
|
25
25
|
},
|
package/template/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
What changed in each release of `{{packageName}}`, newest first, in the format of [Keep a Changelog 2.0](https://keepachangelog.com/en/2.0.0/). Each change lands under `## Unreleased` as it merges, grouped under `### Added`, `### Changed`, `### Fixed` or `### Removed`. A breaking change starts with `**Breaking:**` and names what breaks: a Command, a flag, a `--json` field, an exit code or the skill. A release turns `## Unreleased` into `## vX.Y.Z (YYYY-MM-DD)`.
|
|
3
|
+
What changed in each release of `{{packageName}}`, newest first, in the format of [Keep a Changelog 2.0](https://keepachangelog.com/en/2.0.0/). Each change lands under `## Unreleased` as it merges, grouped under `### Added`, `### Changed`, `### Fixed` or `### Removed`. A breaking change starts with `**Breaking:**` and names what breaks: a Command, a flag, a `--json` field, an exit code or the skill. A release turns `## Unreleased` into `## vX.Y.Z (YYYY-MM-DD)`. From the second release on, a release holds `### Upgrade from v<the release below>` listing what someone upgrading must do, or `- Nothing to do.`.
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
package/template/package.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@biomejs/biome": "2.5.15",
|
|
30
30
|
"@duyquangnvx/agent-cli": "{{runtimeVersion}}",
|
|
31
31
|
"@duyquangnvx/harness": "0.3.1",
|
|
32
|
-
"@duyquangnvx/release": "0.
|
|
32
|
+
"@duyquangnvx/release": "0.4.0",
|
|
33
33
|
"@types/node": "^22.19.0",
|
|
34
34
|
"tsdown": "0.23.0",
|
|
35
35
|
"typescript": "7.0.2",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
# A fresh project pins the Runtime release it was created with, which can be younger
|
|
2
|
-
# pnpm's minimum release age.
|
|
1
|
+
# A fresh project pins the Runtime and release versions it was created with, which can be younger
|
|
2
|
+
# than pnpm's minimum release age.
|
|
3
3
|
minimumReleaseAgeExclude:
|
|
4
4
|
- "@duyquangnvx/agent-cli"
|
|
5
|
+
- "@duyquangnvx/release"
|
|
@@ -32,7 +32,7 @@ This installs the CLI. The user has installed this skill already.
|
|
|
32
32
|
## Update
|
|
33
33
|
|
|
34
34
|
1. Run `{{binName}} update --dry-run` to see the version it would install. If it fails to reach the registry, the sandbox refused the host, as [Sandbox](#sandbox) says: go on to the next step.
|
|
35
|
-
2. Ask the user to type `! {{binName}} update`; never run it yourself. It installs the latest release and prints
|
|
35
|
+
2. Ask the user to type `! {{binName}} update`; never run it yourself. It installs the latest release and prints, for each release since the version it replaced, oldest first, the upgrade steps it asks of the user, or its whole notes when it lists none: under `--json`, each entry of `upgrades` holds `steps` or `notes`. Do each step, oldest first, and any the notes give.
|
|
36
36
|
3. Hand the user each line in `next` to type with `!`: they bring this skill to the version `update` installed, or to the latest release when it installed nothing, as `doctor`'s `skill` row would. Load this skill again after, as [Check](#check) says.
|
|
37
37
|
4. Confirm the new version with `{{binName}} --version`.
|
|
38
38
|
|
|
@@ -186,7 +186,7 @@ describe("install lines", () => {
|
|
|
186
186
|
expect(await text("README.md")).toContain(`\`! ${install}\``);
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
-
test.skipIf(
|
|
189
|
+
test.skipIf(cli.skill === undefined)(
|
|
190
190
|
"the README installs the skill with doctor's skill line",
|
|
191
191
|
async () => {
|
|
192
192
|
const { skill } = await doctorFixes();
|