@wirecat/cli-template 0.9.0 → 0.11.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/.github/workflows/ci.yml +18 -0
- package/.github/workflows/release.yml +63 -0
- package/CHANGELOG.md +72 -1
- package/CLAUDE.md +1 -3
- package/bin/release +5 -3
- package/contracts/help.snap +2 -0
- package/dist/bin/clidev.js +34 -12
- package/dist/bundle/all-profiles-MJ6XSFOO.js +24 -0
- package/dist/bundle/anthropic-W5UKBZUB.js +70 -0
- package/dist/bundle/app-server-EZ46JAHB.js +217 -0
- package/dist/bundle/bun-HB6O2TTT.js +169 -0
- package/dist/bundle/bun-sqlite-KBXOW2ES.js +69 -0
- package/dist/bundle/chunk-2B5U4Z5H.js +100 -0
- package/dist/bundle/chunk-35KYY65W.js +122 -0
- package/dist/bundle/chunk-4LURWBVV.js +752 -0
- package/dist/bundle/chunk-5D4AEUVA.js +24783 -0
- package/dist/bundle/chunk-7IXL4UFK.js +158 -0
- package/dist/bundle/chunk-ADLS6FVG.js +24600 -0
- package/dist/bundle/chunk-AK257OMS.js +8353 -0
- package/dist/bundle/chunk-CXQXVKUY.js +24 -0
- package/dist/bundle/chunk-DFDN6AUB.js +21 -0
- package/dist/bundle/chunk-E42W72PQ.js +151 -0
- package/dist/bundle/chunk-EFHLQXG6.js +5104 -0
- package/dist/bundle/chunk-EGRB55FF.js +264 -0
- package/dist/bundle/chunk-ERGB4NJA.js +53 -0
- package/dist/bundle/chunk-ERKR3VJ5.js +1146 -0
- package/dist/bundle/chunk-FDBINRWA.js +884 -0
- package/dist/bundle/chunk-FZZIU4B7.js +34514 -0
- package/dist/bundle/chunk-GOO67PDU.js +2 -0
- package/dist/bundle/chunk-HDY5X3WQ.js +281 -0
- package/dist/bundle/chunk-HTQTIKWP.js +928 -0
- package/dist/bundle/chunk-IBBN7Z3A.js +630 -0
- package/dist/bundle/chunk-IDWW4TU2.js +18 -0
- package/dist/bundle/chunk-IGHEW777.js +164 -0
- package/dist/bundle/chunk-IN3FVRPK.js +76 -0
- package/dist/bundle/chunk-JAOGZMKQ.js +48 -0
- package/dist/bundle/chunk-JHO2LL2J.js +459 -0
- package/dist/bundle/chunk-JRK73FOW.js +78 -0
- package/dist/bundle/chunk-KAREKBUZ.js +24 -0
- package/dist/bundle/chunk-KJTNT4SW.js +82 -0
- package/dist/bundle/chunk-L5WWMP5M.js +1904 -0
- package/dist/bundle/chunk-MFS52LTZ.js +570 -0
- package/dist/bundle/chunk-MJRSEUKG.js +442 -0
- package/dist/bundle/chunk-MUSYGFCY.js +3556 -0
- package/dist/bundle/chunk-N2Z3MCOF.js +779 -0
- package/dist/bundle/chunk-NOVLCHDV.js +45 -0
- package/dist/bundle/chunk-O3UXNU3S.js +54 -0
- package/dist/bundle/chunk-O5EHUB2V.js +2 -0
- package/dist/bundle/chunk-OV6PHTAY.js +36226 -0
- package/dist/bundle/chunk-PBN4RBHS.js +2315 -0
- package/dist/bundle/chunk-PDGXMKJS.js +31 -0
- package/dist/bundle/chunk-PJOVK7PG.js +191 -0
- package/dist/bundle/chunk-QBP7OMN5.js +58 -0
- package/dist/bundle/chunk-QJ6XW4DM.js +7556 -0
- package/dist/bundle/chunk-QKWRL4OD.js +1028 -0
- package/dist/bundle/chunk-RUKDZEID.js +73 -0
- package/dist/bundle/chunk-SVDF6NJF.js +215 -0
- package/dist/bundle/chunk-TAYOKLGF.js +193 -0
- package/dist/bundle/chunk-TGB5F7NC.js +288 -0
- package/dist/bundle/chunk-V3ZTQ24B.js +161 -0
- package/dist/bundle/chunk-VLNKTMV7.js +3103 -0
- package/dist/bundle/chunk-VYSUKHKL.js +63 -0
- package/dist/bundle/chunk-Y5E2WNWB.js +35 -0
- package/dist/bundle/chunk-YJNUDHJD.js +3390 -0
- package/dist/bundle/chunk-Z7MSIRSQ.js +6848 -0
- package/dist/bundle/chunk-ZLY6GUAS.js +82 -0
- package/dist/bundle/chunk-ZVVMGPBJ.js +50 -0
- package/dist/bundle/clidev.js +22 -0
- package/dist/bundle/command-contract-75VJ36U4.js +29 -0
- package/dist/bundle/decode-AMXUVKNY.js +158 -0
- package/dist/bundle/dist-ESHIQU4M.js +7577 -0
- package/dist/bundle/echarts-GJDMQ2AQ.js +42501 -0
- package/dist/bundle/embed-L4CRZ2XQ.js +35 -0
- package/dist/bundle/embedder-IBGV4M2K.js +108 -0
- package/dist/bundle/first-run-VTKC2IBV.js +23 -0
- package/dist/bundle/first-screen-X5IJKBSU.js +27 -0
- package/dist/bundle/instructions-YJECS4KN.js +11 -0
- package/dist/bundle/mcp-G6XP2IRO.js +151 -0
- package/dist/bundle/mcp-OQBZXELQ.js +165 -0
- package/dist/bundle/mcp-RDZGYPSY.js +78 -0
- package/dist/bundle/node-NQG4EVZR.js +176 -0
- package/dist/bundle/node-P4E63KXA.js +2340 -0
- package/dist/bundle/node-TLZSIHIJ.js +21 -0
- package/dist/bundle/node-sqlite-BR7F3BLB.js +61 -0
- package/dist/bundle/oauth-J7UAWNIK.js +17 -0
- package/dist/bundle/open-BR47R5UE.js +19 -0
- package/dist/bundle/process-66I7RDPJ.js +91 -0
- package/dist/bundle/program-K6347XBZ.js +17279 -0
- package/dist/bundle/prompt-NE5JJ7UP.js +12 -0
- package/dist/bundle/recognize-GC3YFVIA.js +21 -0
- package/dist/bundle/remote-QELOMKQM.js +26 -0
- package/dist/bundle/rerank-BH6TZ2SP.js +49 -0
- package/dist/bundle/serve-WWLRNDT2.js +19 -0
- package/dist/bundle/server-DE6NLNUF.js +52 -0
- package/dist/bundle/server-ZPSQKOAH.js +39 -0
- package/dist/bundle/state-2BEGXAMO.js +33 -0
- package/dist/bundle/store-AH6WZMCF.js +120 -0
- package/dist/bundle/store-maintenance-command-PBXX3IEV.js +40 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/commands.md +9 -13
- package/docs/dev/TESTING.md +10 -0
- package/docs/dev/reference-clis.md +7 -5
- package/docs/dev/skills/release/SKILL.md +15 -8
- package/docs/dev/skills/release/fresh-audit.md +4 -0
- package/docs/dev/test-matrix.md +1 -1
- package/kit/dist/new.js +1 -0
- package/package.json +8 -5
- package/scripts/audit.sh +14 -3
- package/scripts/smoke-bundle.ts +64 -0
- package/scripts/smoke.ts +18 -0
- package/scripts/test-matrix-untested.ts +1 -1
- package/scripts/version-level.test.ts +17 -1
- package/scripts/version-level.ts +35 -7
- package/skills/clidev-cli/SKILL.md +8 -0
- package/src/version.ts +1 -1
- package/lint/baseline/unknown-verb.json +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-template",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Start a new WireCat CLI: a working skeleton on cli-base and cli-core, copied by new and kept current by upgrade",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Viacheslav Ptsarev",
|
|
@@ -50,18 +50,20 @@
|
|
|
50
50
|
"gitignore"
|
|
51
51
|
],
|
|
52
52
|
"scripts": {
|
|
53
|
-
"build": "tsc --build --force && pnpm kit:build",
|
|
53
|
+
"build": "tsc --build --force && cli-dev bundle --bin dist/bin/clidev.js && pnpm kit:build",
|
|
54
54
|
"typecheck": "tsc --build --force --emitDeclarationOnly && tsc -p tsconfig.test.json && tsc -p tsconfig.scripts.json && pnpm kit:typecheck",
|
|
55
55
|
"lint": "biome check .",
|
|
56
56
|
"lint:fix": "biome check --write .",
|
|
57
57
|
"test": "vitest run",
|
|
58
58
|
"test:coverage": "vitest run --coverage",
|
|
59
|
+
"test:slow": "vitest run --reporter=json --outputFile=coverage/tests.json >/dev/null; cli-dev slow-tests",
|
|
59
60
|
"test:matrix": "vitest run >/dev/null && pnpm build >/dev/null && pnpm test:matrix:check",
|
|
60
61
|
"test:matrix:check": "cli-dev test-matrix --program scripts/command-program.ts --untested scripts/test-matrix-untested.ts --name clidev --check && git diff --exit-code -- docs/dev/test-matrix.md",
|
|
61
62
|
"generate": "pnpm build && node --experimental-strip-types scripts/commands.ts",
|
|
62
63
|
"generate:check": "pnpm build && node --experimental-strip-types scripts/commands.ts --check",
|
|
63
64
|
"smoke": "node --experimental-strip-types scripts/smoke.ts",
|
|
64
|
-
"smoke:bun": "bun scripts/smoke.ts",
|
|
65
|
+
"smoke:bun": "bun scripts/smoke.ts && bun scripts/smoke-bundle.ts",
|
|
66
|
+
"smoke:node": "node --experimental-strip-types scripts/smoke-bundle.ts",
|
|
65
67
|
"package:check": "pnpm smoke",
|
|
66
68
|
"docs:check": "cli-dev docs-check --rules scripts/docs-rules.ts --pages && pnpm docs:spell && rumdl check --config config/wirecat/rumdl.toml README.md SECURITY.md CHANGELOG.md CLAUDE.md AGENTS.md docs/*.md docs/dev/*.md && pnpm docs:lint && pnpm kit:docs",
|
|
67
69
|
"docs:lint": "markdownlint-cli2",
|
|
@@ -84,8 +86,8 @@
|
|
|
84
86
|
},
|
|
85
87
|
"dependencies": {
|
|
86
88
|
"@modelcontextprotocol/server": "2.4.0",
|
|
87
|
-
"@wirecat/cli-base": "0.
|
|
88
|
-
"@wirecat/cli-core": "0.
|
|
89
|
+
"@wirecat/cli-base": "0.65.0",
|
|
90
|
+
"@wirecat/cli-core": "0.495.0",
|
|
89
91
|
"commander": "15.0.0"
|
|
90
92
|
},
|
|
91
93
|
"devDependencies": {
|
|
@@ -98,6 +100,7 @@
|
|
|
98
100
|
"@vitest/coverage-v8": "5.0.5",
|
|
99
101
|
"@wirecat/cli-testing": "0.5.3",
|
|
100
102
|
"cspell": "10.4.0",
|
|
103
|
+
"esbuild": "0.28.2",
|
|
101
104
|
"lefthook": "2.2.2",
|
|
102
105
|
"markdownlint-cli2": "0.24.0",
|
|
103
106
|
"rumdl": "0.3.0",
|
package/scripts/audit.sh
CHANGED
|
@@ -8,18 +8,29 @@ command=$(node --input-type=module -e "import('$root/dist/identity.js').then((m)
|
|
|
8
8
|
scratch=$(mktemp -d)
|
|
9
9
|
trap 'rm -rf "$scratch"' EXIT
|
|
10
10
|
# A CLI that starts may move the store under HOME; every CLI run here gets a throwaway one.
|
|
11
|
+
# Moved folders do not hide the keyring: it is reached over D-Bus.
|
|
11
12
|
export HOME="$scratch/home" MESSAGING_STORE="$scratch/store" WIRECAT_STATE_DIR="$scratch/state"
|
|
13
|
+
export DBUS_SESSION_BUS_ADDRESS=disabled:
|
|
12
14
|
mkdir -p "$HOME"
|
|
13
15
|
npm install -g --prefix "$scratch/prefix" --ignore-scripts --no-audit --no-fund --loglevel error \
|
|
14
|
-
@wirecat/tg-cli @wirecat/max-cli @wirecat/whatsapp-cli @wirecat/cli-memo @wirecat/drive-cli @wirecat/zoom-cli
|
|
16
|
+
@wirecat/tg-cli @wirecat/max-cli @wirecat/whatsapp-cli @wirecat/cli-memo @wirecat/drive-cli @wirecat/zoom-cli \
|
|
17
|
+
@wirecat/gcal-cli
|
|
15
18
|
bin="$scratch/prefix/bin"
|
|
16
19
|
others=()
|
|
17
20
|
# A groups file replaces cli-base's PARITY_GROUPS. The template keeps one because it is in no group of cli-base's.
|
|
18
21
|
[ -f "$root/config/parity-groups.json" ] && others+=(--groups "$root/config/parity-groups.json")
|
|
19
|
-
for cli in tg max wa memo drive zm; do
|
|
22
|
+
for cli in tg max wa memo drive zm gcal; do
|
|
20
23
|
[ "$cli" = "$command" ] || others+=(--cli "$bin/$cli")
|
|
21
24
|
done
|
|
25
|
+
# This CLI's entity schemas and error reasons, from its own `commands info`, so same-entity-schema and
|
|
26
|
+
# same-error-reason measure it. shared-command-contract needs `--complete`, which wants cli-core's doctor contract.
|
|
27
|
+
node "$root/dist/bin/$command.js" commands info --json >"$scratch/info.json"
|
|
28
|
+
node -e 'const info = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"))
|
|
29
|
+
require("fs").writeFileSync(process.argv[2], JSON.stringify(info.schemas))
|
|
30
|
+
require("fs").writeFileSync(process.argv[3], JSON.stringify(info.reasons))' \
|
|
31
|
+
"$scratch/info.json" "$scratch/schemas.json" "$scratch/reasons.json"
|
|
22
32
|
"$root/node_modules/.bin/cli-dev" audit --cli "$root/dist/bin/$command.js" "${others[@]}" --for "$command" \
|
|
23
|
-
--lint "$command=$root/lint"
|
|
33
|
+
--lint "$command=$root/lint" --schemas "$command=$scratch/schemas.json" --reasons "$command=$scratch/reasons.json" \
|
|
34
|
+
>"$scratch/scorecard.txt" || { cat "$scratch/scorecard.txt"; exit 1; }
|
|
24
35
|
awk -v cli="$command" 'NR == 1 || $1 == cli' "$scratch/scorecard.txt"
|
|
25
36
|
grep -q "^$command *total " "$scratch/scorecard.txt" || { echo "audit: no scorecard row for $command" >&2; exit 1; }
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The published bin is a loader for `dist/bundle/` (cli-base's `cli-dev bundle`, WC-LAY-10). This runs it, with
|
|
3
|
+
* directories of its own, under Node (`pnpm smoke:node`) and Bun (`pnpm smoke:bun`): the vitest suite runs against
|
|
4
|
+
* `src/`, so this is the proof the bundle a user installs works.
|
|
5
|
+
*
|
|
6
|
+
* pnpm build && pnpm smoke:node
|
|
7
|
+
*/
|
|
8
|
+
import { spawnSync } from "node:child_process"
|
|
9
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"
|
|
10
|
+
import { tmpdir } from "node:os"
|
|
11
|
+
import { join } from "node:path"
|
|
12
|
+
|
|
13
|
+
const COMMAND = "clidev"
|
|
14
|
+
const PREFIX = "CLIDEV"
|
|
15
|
+
|
|
16
|
+
const runtime = "Bun" in globalThis ? "bun" : "node"
|
|
17
|
+
const failures: string[] = []
|
|
18
|
+
const check = (what: string, condition: boolean) => {
|
|
19
|
+
if (!condition) failures.push(what)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Overridden directories also move the keyring entry, so nothing here reads the owner's accounts or store.
|
|
23
|
+
const isolated = mkdtempSync(join(tmpdir(), `${COMMAND}-bundle-smoke-`))
|
|
24
|
+
const run = (args: string[], env: Record<string, string> = {}) =>
|
|
25
|
+
spawnSync(process.execPath, [`dist/bin/${COMMAND}.js`, ...args], {
|
|
26
|
+
encoding: "utf8",
|
|
27
|
+
env: {
|
|
28
|
+
...process.env,
|
|
29
|
+
[`${PREFIX}_CONFIG_DIR`]: join(isolated, "config"),
|
|
30
|
+
[`${PREFIX}_STATE_DIR`]: join(isolated, "state"),
|
|
31
|
+
[`${PREFIX}_CACHE_DIR`]: join(isolated, "cache"),
|
|
32
|
+
[`${PREFIX}_NO_UPDATE_CHECK`]: "1",
|
|
33
|
+
MESSAGING_STORE: join(isolated, "store.db"),
|
|
34
|
+
DBUS_SESSION_BUS_ADDRESS: "disabled:",
|
|
35
|
+
...env,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const loader = readFileSync(`dist/bin/${COMMAND}.js`, "utf8")
|
|
40
|
+
check("the bin starts the bundle", loader.includes(`import("../bundle/${COMMAND}.js")`))
|
|
41
|
+
const preloaded = [...loader.matchAll(/"\.\.\/bundle\/([^"]+)"/g)].map(([, chunk]) => chunk ?? "")
|
|
42
|
+
check(
|
|
43
|
+
"a server preloads only chunks the bundle has",
|
|
44
|
+
preloaded.length > 1 && preloaded.every((chunk) => existsSync(join("dist/bundle", chunk))),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const version = run(["--version"])
|
|
48
|
+
check("--version prints a version and nothing else", /^\d+\.\d+\.\d+\n$/.test(version.stdout) && version.stderr === "")
|
|
49
|
+
const recorded = run(["--version"], { [`${PREFIX}_TEST_ARGV_LOG`]: join(isolated, "argv.jsonl") })
|
|
50
|
+
check("the loader's --version is the bundle's", recorded.stdout === version.stdout)
|
|
51
|
+
check("--help names the command", run(["--help"]).stdout.includes(`Usage: ${COMMAND}`))
|
|
52
|
+
check("skill show prints the SKILL.md the package ships", run(["skill", "show"]).stdout.startsWith("---"))
|
|
53
|
+
check(
|
|
54
|
+
"doctor finds the document readers",
|
|
55
|
+
run(["doctor", "--json"]).stdout.includes('"files":{"checked":true,"ok":true'),
|
|
56
|
+
)
|
|
57
|
+
rmSync(isolated, { recursive: true, force: true })
|
|
58
|
+
|
|
59
|
+
if (failures.length > 0) {
|
|
60
|
+
console.error(`${COMMAND} bundle smoke FAILED under ${runtime}:`)
|
|
61
|
+
for (const failure of failures) console.error(` - ${failure}`)
|
|
62
|
+
process.exit(1)
|
|
63
|
+
}
|
|
64
|
+
console.log(`${COMMAND} bundle smoke passed under ${runtime}`)
|
package/scripts/smoke.ts
CHANGED
|
@@ -24,6 +24,23 @@ const shipped = files
|
|
|
24
24
|
.map((entry) => entry.replace(/^\//, ""))
|
|
25
25
|
.map((entry) => (statSync(join(root, entry), { throwIfNoEntry: false })?.isDirectory() ? `${entry}/` : entry))
|
|
26
26
|
assert.deepEqual(packContents(root, ["package.json", ...shipped], "package.json and the paths in its files list")(), [])
|
|
27
|
+
// WC-REL-16. The template's own package ships the skeleton's sources, since `new` copies them.
|
|
28
|
+
const FORBIDDEN = [
|
|
29
|
+
"src",
|
|
30
|
+
"scripts",
|
|
31
|
+
".github",
|
|
32
|
+
"bin/release",
|
|
33
|
+
"config",
|
|
34
|
+
"lint",
|
|
35
|
+
"contracts",
|
|
36
|
+
"docs/dev",
|
|
37
|
+
"template.json",
|
|
38
|
+
]
|
|
39
|
+
const overlaps = (entry: string, path: string) =>
|
|
40
|
+
entry === path || entry.startsWith(`${path}/`) || path.startsWith(`${entry}/`)
|
|
41
|
+
const forbidden = shipped.flatMap((entry) => FORBIDDEN.filter((path) => overlaps(entry.replace(/\/$/, ""), path)))
|
|
42
|
+
if (name !== "@wirecat/cli-template")
|
|
43
|
+
assert.deepEqual(forbidden, [], "package.json's files ships paths WC-REL-16 forbids")
|
|
27
44
|
const temp = mkdtempSync(join(tmpdir(), "clidev-package-"))
|
|
28
45
|
try {
|
|
29
46
|
const userConfig = join(temp, "npm-user-config")
|
|
@@ -48,6 +65,7 @@ try {
|
|
|
48
65
|
...process.env,
|
|
49
66
|
NODE_OPTIONS: "",
|
|
50
67
|
HOME: temp,
|
|
68
|
+
DBUS_SESSION_BUS_ADDRESS: "disabled:",
|
|
51
69
|
CLIDEV_CONFIG_DIR: join(temp, "config"),
|
|
52
70
|
CLIDEV_STATE_DIR: join(temp, "state"),
|
|
53
71
|
CLIDEV_CACHE_DIR: join(temp, "cache"),
|
|
@@ -29,6 +29,6 @@ export const UNTESTED: { command: string; option?: string; reason: string }[] =
|
|
|
29
29
|
{
|
|
30
30
|
command: "mcp server stop",
|
|
31
31
|
reason:
|
|
32
|
-
"
|
|
32
|
+
"stops the detached server that `mcp server start` wrote a pid file for; cli-core tests mcpServerCommand, and no live scenario starts a server to stop",
|
|
33
33
|
},
|
|
34
34
|
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect, it } from "vitest"
|
|
2
|
-
import { versionLevelProblem } from "./version-level.js"
|
|
2
|
+
import { nextVersion, versionLevelProblem } from "./version-level.js"
|
|
3
3
|
|
|
4
4
|
const changelog = (version: string, headings: string[], previous = "0.1.8") =>
|
|
5
5
|
[`## ${version} — 26.10.2026`, ...headings.flatMap((h) => [`### ${h}`, "- x"]), `## ${previous} — 25.10.2026`].join(
|
|
@@ -28,3 +28,19 @@ it("refuses a patch release that adds something", () => {
|
|
|
28
28
|
it("checks nothing while the top section is Unreleased", () => {
|
|
29
29
|
expect(versionLevelProblem("## Unreleased\n\n### Removed\n\n- x\n\n## 0.1.8 — 25.10.2026\n")).toBeUndefined()
|
|
30
30
|
})
|
|
31
|
+
|
|
32
|
+
const unreleased = (headings: string[], previous = "0.1.1") =>
|
|
33
|
+
["## Unreleased", ...headings.flatMap((h) => [`### ${h}`, "- x"]), `## ${previous} — 29.10.2026`].join("\n")
|
|
34
|
+
|
|
35
|
+
it.each([
|
|
36
|
+
[["Fixed"], "0.1.2", "0.1.2"],
|
|
37
|
+
[["Added"], "0.1.2", "0.2.0"],
|
|
38
|
+
[["Removed"], "0.1.2", "0.2.0"],
|
|
39
|
+
[["Added"], "0.3.1", "0.3.1"],
|
|
40
|
+
])("raises the next free number for %j from %s to %s", (headings, next, expected) => {
|
|
41
|
+
expect(nextVersion(unreleased(headings), next)).toBe(expected)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it("raises a 1.x release that may break callers to the next major", () => {
|
|
45
|
+
expect(nextVersion(unreleased(["Changed — may break callers"], "1.4.2"), "1.4.3")).toBe("2.0.0")
|
|
46
|
+
})
|
package/scripts/version-level.ts
CHANGED
|
@@ -21,13 +21,35 @@ const needed = (version: string, section: string): Level => {
|
|
|
21
21
|
return /^### Added$/m.test(section) ? "minor" : "patch"
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
const raise = (from: string, level: Level) => {
|
|
25
|
+
const [a = 0, b = 0, c = 0] = parse(from)
|
|
26
|
+
if (level === "major") return `${a + 1}.0.0`
|
|
27
|
+
return level === "minor" ? `${a}.${b + 1}.0` : `${a}.${b}.${c + 1}`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const later = (x: string, y: string) => {
|
|
31
|
+
const [a, b] = [parse(x), parse(y)]
|
|
32
|
+
const i = a.findIndex((n, k) => n !== b[k])
|
|
33
|
+
return i === -1 || (a[i] ?? 0) > (b[i] ?? 0) ? x : y
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const sections = (changelog: string) => {
|
|
37
|
+
const [top, below] = [...changelog.matchAll(/^## (\S+).*$/gm)]
|
|
38
|
+
if (!top || !below?.[1]) return undefined
|
|
39
|
+
return { version: top[1], previous: below[1], section: changelog.slice(top.index, below.index) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The next free number on npm is a patch; the top section may need a minor or major over the version below it.
|
|
43
|
+
export const nextVersion = (changelog: string, next: string): string => {
|
|
44
|
+
const parts = sections(changelog)
|
|
45
|
+
if (!parts) return next
|
|
46
|
+
return later(next, raise(parts.previous, needed(next, parts.section)))
|
|
47
|
+
}
|
|
48
|
+
|
|
24
49
|
export const versionLevelProblem = (changelog: string): string | undefined => {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const version =
|
|
28
|
-
const previous = below?.[1]
|
|
29
|
-
if (!top || !below || !version || !previous || !/^\d+\.\d+\.\d+$/.test(version)) return undefined
|
|
30
|
-
const section = changelog.slice(top.index, below.index)
|
|
50
|
+
const parts = sections(changelog)
|
|
51
|
+
if (!parts?.version || !/^\d+\.\d+\.\d+$/.test(parts.version)) return undefined
|
|
52
|
+
const { version, previous, section } = parts
|
|
31
53
|
const want = needed(version, section)
|
|
32
54
|
const got = raised(previous, version)
|
|
33
55
|
if (LEVELS.indexOf(got) >= LEVELS.indexOf(want)) return undefined
|
|
@@ -35,7 +57,13 @@ export const versionLevelProblem = (changelog: string): string | undefined => {
|
|
|
35
57
|
}
|
|
36
58
|
|
|
37
59
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
38
|
-
const
|
|
60
|
+
const changelog = readFileSync(resolve(import.meta.dirname, "../CHANGELOG.md"), "utf8")
|
|
61
|
+
const [flag, next] = process.argv.slice(2)
|
|
62
|
+
if (flag === "--next" && next) {
|
|
63
|
+
console.log(nextVersion(changelog, next))
|
|
64
|
+
process.exit(0)
|
|
65
|
+
}
|
|
66
|
+
const problem = versionLevelProblem(changelog)
|
|
39
67
|
if (problem) {
|
|
40
68
|
console.error(`${problem} (docs/dev/skills/release/SKILL.md, step 6)`)
|
|
41
69
|
process.exit(1)
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clidev-cli
|
|
3
3
|
description: Use clidev, a WireCat CLI started from cli-template, from an agent — find a command, run it with the owner's profile, read JSON answers. Use when a task needs clidev. It does not connect to a service yet.
|
|
4
|
+
metadata:
|
|
5
|
+
openclaw:
|
|
6
|
+
requires:
|
|
7
|
+
bins: [clidev]
|
|
8
|
+
install:
|
|
9
|
+
- kind: node
|
|
10
|
+
package: "@wirecat/clidev-cli"
|
|
11
|
+
bins: [clidev]
|
|
4
12
|
---
|
|
5
13
|
|
|
6
14
|
# clidev
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.11.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
["mcp revoke", "mcp serve"]
|