@wirecat/cli-template 0.8.0 → 0.10.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 (125) hide show
  1. package/.github/workflows/ci.yml +3 -3
  2. package/.github/workflows/release.yml +63 -0
  3. package/.gitleaks.toml +18 -0
  4. package/AGENTS.md +9 -15
  5. package/CHANGELOG.md +87 -1
  6. package/README.md +4 -3
  7. package/bin/release +5 -3
  8. package/contracts/plan.json +2 -2
  9. package/dist/bin/clidev.js +34 -12
  10. package/dist/bundle/all-profiles-XHC7BG3P.js +24 -0
  11. package/dist/bundle/anthropic-N6B3ZZHQ.js +70 -0
  12. package/dist/bundle/bun-HUJLS7KP.js +169 -0
  13. package/dist/bundle/bun-sqlite-OWFO2TVR.js +69 -0
  14. package/dist/bundle/chunk-222FANS2.js +161 -0
  15. package/dist/bundle/chunk-2CFBHYFA.js +884 -0
  16. package/dist/bundle/chunk-2KQZ24GI.js +82 -0
  17. package/dist/bundle/chunk-2TBVT4SZ.js +31 -0
  18. package/dist/bundle/chunk-437W3Z2M.js +76 -0
  19. package/dist/bundle/chunk-4QRLPOJ7.js +18 -0
  20. package/dist/bundle/chunk-54AJONOM.js +54 -0
  21. package/dist/bundle/chunk-5D4AEUVA.js +24783 -0
  22. package/dist/bundle/chunk-6CBWO7OF.js +73 -0
  23. package/dist/bundle/chunk-75LVQQEK.js +35782 -0
  24. package/dist/bundle/chunk-7RB76E2L.js +264 -0
  25. package/dist/bundle/chunk-7RXBN7HP.js +63 -0
  26. package/dist/bundle/chunk-ABP7FDMJ.js +122 -0
  27. package/dist/bundle/chunk-ADLS6FVG.js +24600 -0
  28. package/dist/bundle/chunk-AP7QKYBG.js +3531 -0
  29. package/dist/bundle/chunk-ASMH7JWZ.js +288 -0
  30. package/dist/bundle/chunk-B4EED2RF.js +100 -0
  31. package/dist/bundle/chunk-B4LM2B6F.js +1900 -0
  32. package/dist/bundle/chunk-BDSDQCV4.js +281 -0
  33. package/dist/bundle/chunk-DFDN6AUB.js +21 -0
  34. package/dist/bundle/chunk-DMCN22H6.js +35 -0
  35. package/dist/bundle/chunk-E42W72PQ.js +151 -0
  36. package/dist/bundle/chunk-EFHLQXG6.js +5104 -0
  37. package/dist/bundle/chunk-FIHDGZIB.js +34352 -0
  38. package/dist/bundle/chunk-FWVKHD2L.js +48 -0
  39. package/dist/bundle/chunk-FXS3X76A.js +193 -0
  40. package/dist/bundle/chunk-HTQTIKWP.js +928 -0
  41. package/dist/bundle/chunk-IJ3IA7EK.js +24 -0
  42. package/dist/bundle/chunk-JEBSORH7.js +3379 -0
  43. package/dist/bundle/chunk-JTTW5ZKF.js +45 -0
  44. package/dist/bundle/chunk-LSEF4QC3.js +3075 -0
  45. package/dist/bundle/chunk-LY7GS2YI.js +58 -0
  46. package/dist/bundle/chunk-MFS52LTZ.js +570 -0
  47. package/dist/bundle/chunk-MNSD5BX2.js +78 -0
  48. package/dist/bundle/chunk-MTGLJCAZ.js +24 -0
  49. package/dist/bundle/chunk-MZVV2JZT.js +744 -0
  50. package/dist/bundle/chunk-NE3NSB5O.js +8341 -0
  51. package/dist/bundle/chunk-NTLPDH76.js +440 -0
  52. package/dist/bundle/chunk-O3PBQVAB.js +447 -0
  53. package/dist/bundle/chunk-O5EHUB2V.js +2 -0
  54. package/dist/bundle/chunk-O5LMDQTO.js +82 -0
  55. package/dist/bundle/chunk-OPJ24VGH.js +1028 -0
  56. package/dist/bundle/chunk-OPPMGPFW.js +164 -0
  57. package/dist/bundle/chunk-QGNNMPUB.js +158 -0
  58. package/dist/bundle/chunk-QVJLOUQB.js +2 -0
  59. package/dist/bundle/chunk-S57AMKLX.js +6848 -0
  60. package/dist/bundle/chunk-TARN7CHN.js +215 -0
  61. package/dist/bundle/chunk-TJLGI3N6.js +1095 -0
  62. package/dist/bundle/chunk-VMTM46FH.js +7532 -0
  63. package/dist/bundle/chunk-W2IDKBNB.js +2315 -0
  64. package/dist/bundle/chunk-XFXBXQBS.js +630 -0
  65. package/dist/bundle/chunk-Y5E2WNWB.js +35 -0
  66. package/dist/bundle/chunk-ZVVMGPBJ.js +50 -0
  67. package/dist/bundle/clidev.js +22 -0
  68. package/dist/bundle/command-contract-PEM3S634.js +29 -0
  69. package/dist/bundle/dist-ESHIQU4M.js +7577 -0
  70. package/dist/bundle/echarts-2QGL2JP5.js +42501 -0
  71. package/dist/bundle/embed-HHAAGHA6.js +35 -0
  72. package/dist/bundle/embedder-W2OGVVYH.js +108 -0
  73. package/dist/bundle/first-run-WCJUDUBU.js +23 -0
  74. package/dist/bundle/first-screen-U4DFUKUC.js +27 -0
  75. package/dist/bundle/instructions-OTZHT6NV.js +9 -0
  76. package/dist/bundle/mcp-OQBZXELQ.js +165 -0
  77. package/dist/bundle/mcp-VVF6J7SQ.js +151 -0
  78. package/dist/bundle/mcp-Y7VCIZ2J.js +78 -0
  79. package/dist/bundle/node-P4E63KXA.js +2340 -0
  80. package/dist/bundle/node-SYD4GX5O.js +176 -0
  81. package/dist/bundle/node-TLZSIHIJ.js +21 -0
  82. package/dist/bundle/node-sqlite-X2DGRFOZ.js +45 -0
  83. package/dist/bundle/oauth-42M34GQ5.js +17 -0
  84. package/dist/bundle/open-SWXRCDLN.js +19 -0
  85. package/dist/bundle/process-KAFGXZ7Q.js +91 -0
  86. package/dist/bundle/program-EHR4G7VN.js +16967 -0
  87. package/dist/bundle/prompt-ZQTMHRGX.js +12 -0
  88. package/dist/bundle/recognize-TTED4SE3.js +190 -0
  89. package/dist/bundle/remote-C37XJ4BP.js +26 -0
  90. package/dist/bundle/rerank-APFZAMQL.js +49 -0
  91. package/dist/bundle/serve-DDPIHDVZ.js +19 -0
  92. package/dist/bundle/server-L5GNG7KC.js +793 -0
  93. package/dist/bundle/server-LKVYA2AE.js +39 -0
  94. package/dist/bundle/state-WWPPHERF.js +33 -0
  95. package/dist/bundle/store-H6UIA4PK.js +120 -0
  96. package/dist/bundle/store-maintenance-command-EYBT64A2.js +40 -0
  97. package/dist/commands/mcp.d.ts.map +1 -1
  98. package/dist/commands/mcp.js +45 -30
  99. package/dist/commands/mcp.js.map +1 -1
  100. package/dist/version.d.ts +1 -1
  101. package/dist/version.d.ts.map +1 -1
  102. package/dist/version.js +1 -1
  103. package/dist/version.js.map +1 -1
  104. package/docs/commands.md +38 -22
  105. package/docs/dev/TESTING.md +14 -3
  106. package/docs/dev/reference-clis.md +17 -9
  107. package/docs/dev/skills/release/SKILL.md +9 -6
  108. package/docs/dev/skills/release/fresh-audit.md +4 -0
  109. package/docs/dev/test-matrix.md +10 -11
  110. package/docs/security.md +4 -0
  111. package/docs/usage.md +7 -6
  112. package/kit/dist/new.js +17 -2
  113. package/package.json +7 -5
  114. package/scripts/audit.sh +5 -3
  115. package/scripts/smoke-bundle.ts +63 -0
  116. package/scripts/test-matrix-untested.ts +4 -10
  117. package/scripts/version-level.test.ts +17 -1
  118. package/scripts/version-level.ts +35 -7
  119. package/skills/clidev-cli/SKILL.md +8 -0
  120. package/src/commands/mcp.ts +54 -33
  121. package/src/mcp-http.test.ts +20 -13
  122. package/src/mcp.test.ts +3 -3
  123. package/src/program.test.ts +8 -2
  124. package/src/roots.test.ts +2 -7
  125. package/src/version.ts +1 -1
@@ -29,13 +29,13 @@ jobs:
29
29
  platform-run: |
30
30
  node dist/bin/clidev.js commands --json >/dev/null
31
31
  node dist/bin/clidev.js doctor --json >/dev/null
32
- # The skeleton keeps no local state of its own; its config file and run records are cli-core's. A CLI that keeps
33
- # its own (a store, a sync cursor, any file it writes) adds a contracts:upgrade script and removes this skip
34
- # (WC-TEST-14).
32
+ # contracts:upgrade needs local state of the CLI's own and a published version to upgrade from (WC-TEST-14).
33
+ # Once a CLI has both, it adds the script and removes this skip; see docs/dev/TESTING.md.
35
34
  skip: |
36
35
  contracts:upgrade
37
36
  checks: |
38
37
  bash scripts/audit.sh
38
+ pnpm smoke:node
39
39
 
40
40
  version:
41
41
  if: github.event_name == 'pull_request'
@@ -189,3 +189,66 @@ jobs:
189
189
  run: |
190
190
  awk -v v="$VERSION" '$0 ~ "^## "v" " {on=1; next} /^## / && on {exit} on' CHANGELOG.md |
191
191
  gh release create "v$VERSION" --title "$VERSION" --notes-file -
192
+
193
+ # The template's own release publishes @wirecat/cli-template, which has no skill on ClawHub.
194
+ # ClawHub's own workflow, pinned: it runs the ClawHub CLI from this commit and needs id-token only to read which
195
+ # commit that is. It publishes the skill only when it changed, as the next patch of ClawHub's own version line.
196
+ clawhub-dry-run:
197
+ needs: build
198
+ if: inputs.dry_run && github.repository != 'WireCatLabs/cli-template'
199
+ permissions:
200
+ contents: read
201
+ id-token: write
202
+ uses: openclaw/clawhub/.github/workflows/skill-publish.yml@52358852d3510f1150756d48e8a72cb8c8e698e0 # main, 2026-10-25
203
+ with:
204
+ skill_path: skills/clidev-cli
205
+ owner: wirecat
206
+ dry_run: true
207
+
208
+ # After the tag, so a ClawHub failure never holds back the npm release. The same CLI commit as the dry run, but run
209
+ # here instead of through ClawHub's workflow, which GitHub cannot let fail: a version stuck pending ClawHub's scan
210
+ # is not counted as the latest, so the next publish picks it again and gets "already exists" (openclaw/clawhub#4046).
211
+ # That one error warns; any other fails. Bump CLAWHUB_SHA together with the dry run's pin.
212
+ clawhub:
213
+ needs: tag
214
+ if: ${{ !inputs.dry_run && github.repository != 'WireCatLabs/cli-template' }}
215
+ runs-on: ubuntu-latest
216
+ permissions:
217
+ contents: read
218
+ env:
219
+ SKILL_PATH: skills/clidev-cli
220
+ CLAWHUB_SLUG: wirecat-clidev
221
+ CLAWHUB_SHA: 52358852d3510f1150756d48e8a72cb8c8e698e0
222
+ CLAWHUB_URL: https://clawhub.ai
223
+ steps:
224
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
225
+ with:
226
+ persist-credentials: false
227
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
228
+ with:
229
+ repository: openclaw/clawhub
230
+ ref: ${{ env.CLAWHUB_SHA }}
231
+ path: clawhub-source
232
+ persist-credentials: false
233
+ - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
234
+ with:
235
+ bun-version: 1.4.4
236
+ - run: bun install --frozen-lockfile
237
+ working-directory: clawhub-source
238
+ - name: publish the skill
239
+ env:
240
+ CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
241
+ CLAWHUB_CONFIG_PATH: ${{ runner.temp }}/clawhub-config.json
242
+ run: |
243
+ (umask 077; jq -n --arg r "$CLAWHUB_URL" --arg t "$CLAWHUB_TOKEN" '{registry: $r, token: $t}' > "$CLAWHUB_CONFIG_PATH")
244
+ status=0
245
+ output=$(bun clawhub-source/packages/clawhub/src/cli.ts --workdir "$GITHUB_WORKSPACE" \
246
+ --site "$CLAWHUB_URL" --registry "$CLAWHUB_URL" skill publish "$SKILL_PATH" --slug "$CLAWHUB_SLUG" --json \
247
+ --owner wirecat --tags latest --source-repo "$GITHUB_REPOSITORY" --source-commit "$GITHUB_SHA" \
248
+ --source-path "$SKILL_PATH" --source-ref "$GITHUB_REF" 2>&1) || status=$?
249
+ echo "$output"
250
+ if [ "$status" -ne 0 ] && grep -q "already exists" <<< "$output"; then
251
+ echo "::warning::ClawHub already has this skill version, still pending its stalled scan — not republished (openclaw/clawhub#4046)"
252
+ exit 0
253
+ fi
254
+ exit "$status"
package/.gitleaks.toml CHANGED
@@ -3,3 +3,21 @@ useDefault = true
3
3
 
4
4
  [allowlist]
5
5
  paths = ['''pnpm-lock\.yaml''']
6
+
7
+ # gitleaks' own rules know Google API keys (AIza…) only. Google calls its OAuth tokens opaque, so these prefixes are
8
+ # the observed format, not a promised one: ya29. in Apigee's sample access token, 1// in the sample refresh token of
9
+ # the web-server OAuth guide.
10
+ [[rules]]
11
+ id = "google-oauth-access-token"
12
+ description = "Google OAuth 2.0 access token"
13
+ regex = '''\b(ya29\.[A-Za-z0-9._-]{20,})'''
14
+ secretGroup = 1
15
+ keywords = ["ya29."]
16
+
17
+ [[rules]]
18
+ id = "google-oauth-refresh-token"
19
+ description = "Google OAuth 2.0 refresh token"
20
+ regex = '''(?:^|[^A-Za-z0-9/])(1//[A-Za-z0-9_-]{30,})'''
21
+ secretGroup = 1
22
+ entropy = 3.5
23
+ keywords = ["1//"]
package/AGENTS.md CHANGED
@@ -6,20 +6,12 @@ file and over every other document in this repository. The handbook ships inside
6
6
  touches (`WC-<AREA>-<n>`) in the commit message and the pull request. The rules of this CLI alone are in
7
7
  [CLAUDE.md](CLAUDE.md).
8
8
 
9
- ## Before building anything
9
+ ## Design
10
10
 
11
- This CLI was made from [cli-template](https://github.com/WireCatLabs/cli-template). Its first task is the design:
12
-
13
- 1. Read [docs/dev/DESIGN.md](docs/dev/DESIGN.md). If the seven answers are not there, ask the owner the
14
- [design interview](docs/dev/skills/design-interview/SKILL.md) and write them down.
15
- 2. Learn from the reference CLI below. Copy its patterns for the provider, the store and the commands; the
16
- template has no sample code on purpose.
17
- 3. Ask the further questions in the interview that the reference CLI does not answer. Build only after the owner
18
- has read `DESIGN.md`.
19
- 4. When the first command reaches the service, rewrite `README.md`, `docs/index.md` and the description in
20
- `skills/clidev-cli/SKILL.md` to say what the tool does and who it is for. Rewrite the MCP server's instructions
21
- in `src/mcp.ts` too: name the kinds of outside text the CLI carries, from the untrusted-text answer in
22
- `DESIGN.md` (WC-MCP-11).
11
+ [docs/dev/DESIGN.md](docs/dev/DESIGN.md) holds the owner's answers to the
12
+ [design interview](docs/dev/skills/design-interview/SKILL.md) and the decisions made since. Read it before changing
13
+ what a command does, and write a new decision there. Learn the patterns for the provider, the store and the commands
14
+ from the reference CLI below; the template has no sample code on purpose.
23
15
 
24
16
  <!-- cli-template:reference-cli:start -->
25
17
  The reference CLI is not chosen yet; see [Reference CLIs](docs/dev/reference-clis.md).
@@ -27,5 +19,7 @@ The reference CLI is not chosen yet; see [Reference CLIs](docs/dev/reference-cli
27
19
 
28
20
  ## Template-owned files
29
21
 
30
- `template.json` names the files `npx @wirecat/cli-template upgrade` keeps in step with the template. Change one of
31
- them here only when this CLI needs to differ; `upgrade` asks before it touches your change.
22
+ This CLI was made from [cli-template](https://github.com/WireCatLabs/cli-template). `template.json` names the files
23
+ `npx @wirecat/cli-template upgrade` keeps in step with the template. Change one of them here only when this CLI needs
24
+ to differ; `upgrade` asks before it touches your change. Text that holds for this CLI alone goes into the pages it
25
+ owns, such as `DESIGN.md`, `CLAUDE.md` and `README.md`, not into a template-owned page.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,93 @@
3
3
  Notable changes to `@wirecat/cli-template`. One section per version, newest first; versions follow
4
4
  [semantic versioning](https://semver.org), so before `1.0.0` the skeleton may still change.
5
5
 
6
- <!-- cspell:words katex smol whatsapp -->
6
+ <!-- cspell:words clawhub gcal katex openclaw smol whatsapp -->
7
+
8
+ ## 0.10.0 — 31.10.2026
9
+
10
+ ### Changed — may break callers
11
+
12
+ - **The skeleton runs on cli-core 0.469.0 and cli-base 0.65.0**; a CLI that pins cli-base moves both pins together.
13
+ A non-messenger CLI no longer offers messenger settings or the `follow-ups` and `link-conversations` skills
14
+ (cli-core 0.468); runs record successes too, under cli-core 0.467's rules. cli-base 0.64 adds `cli-dev bundle`, the
15
+ shared build that ships the bin as an esbuild bundle, and calendar words in the command vocabulary. cli-base 0.65 adds
16
+ the verbs `serve` and `revoke`, and `cli-dev lint` fails on a baseline entry that names them: the skeleton's
17
+ `lint/baseline/unknown-verb.json` (`mcp serve`, `mcp revoke`) is gone, and a CLI made from the template removes the
18
+ same entries. `<cli> upgrade` now restarts the HTTP MCP server that `mcp server start` started, on the new version,
19
+ and names the MCP sessions over stdio that still run the old one (cli-core #2117).
20
+
21
+ ### Added
22
+
23
+ - **A CLI made from the template publishes its skill on ClawHub as `wirecat-<command>` after each release.** `release.yml`
24
+ gets a dry run through ClawHub's pinned workflow and, after the tag, a publish that only warns while ClawHub still holds
25
+ the version pending its scan ([openclaw/clawhub#4046](https://github.com/openclaw/clawhub/issues/4046)); the template's
26
+ own release skips both. The skill names its binary and npm package for OpenClaw (`metadata.openclaw`). It needs the
27
+ `CLAWHUB_TOKEN` secret, which the WireCatLabs organization shares.
28
+ - **`new --category calendar` names gcal-cli as the reference CLI** in `AGENTS.md` and `DESIGN.md`, and the
29
+ Reference CLIs page lists it, instead of "No reference CLI for this category yet". gcal-cli is the WireCat Google
30
+ Calendar CLI. A CLI made before this keeps what it wrote; edit its `AGENTS.md` by hand if you want the link.
31
+ - **`scripts/audit.sh` audits beside gcal-cli too**: it installs `@wirecat/gcal-cli` with the other published CLIs
32
+ and passes its `gcal` bin to `cli-dev audit`.
33
+ - **An agent publishes a release itself.** The release skill and `bin/release` let an agent merge the release pull
34
+ request and run `bin/release`, which publishes from GitHub Actions. `bin/release --local` stays the owner's, for
35
+ the first release.
36
+
37
+ ### Fixed
38
+
39
+ - **The release audit never uses the owner's accounts.** Its prompt now says: no sign-in, every folder moved, the
40
+ keyring hidden with `DBUS_SESSION_BUS_ADDRESS=disabled:`, and no command that writes to a service.
41
+ - **`bin/release` raises the next free version to the level the changelog needs.** When npm already had the version, it
42
+ took the next patch, so a release with `Added` (`0.1.1` taken, `0.1.2` proposed) failed `version:check` and stopped;
43
+ it now proposes `0.2.0`. A generated CLI gets it with the next template update.
44
+ - **A CLI made from the template starts from an esbuild bundle.** `pnpm build` runs `tsc`, then cli-base's
45
+ `cli-dev bundle` ([WC-LAY-10](https://github.com/WireCatLabs/cli-base/blob/main/docs/standards/layout.md)), and the
46
+ bin becomes a loader for `dist/bundle/`: the skeleton's `config show --help` starts in 151 ms instead of 366.
47
+ `scripts/smoke-bundle.ts` runs the bundle under Node (`pnpm smoke:node`, in CI) and Bun (`pnpm smoke:bun`).
48
+
49
+ ## 0.9.0 — 27.10.2026
50
+
51
+ ### Changed — may break callers
52
+
53
+ - **The MCP server is `clidev <profile> mcp serve`; `mcp` alone only shows its commands** (WC-CMD-3). `--http`,
54
+ `--port` and `--public-url` move to `mcp serve`, and `mcp --revoke` is its own command, `mcp revoke`, still refused
55
+ under `CLIDEV_READ_ONLY`. There is no alias: a client set up with `claude mcp add clidev -- clidev personal mcp`
56
+ gets the help and exits 2; set it up again with `… mcp serve`. `mcp server start` runs `mcp serve --http`.
57
+ - **The skeleton runs on cli-core 0.463.0 and cli-base 0.63.0**, the cli-base line cli-core 0.463 accepts; a CLI that
58
+ pins cli-base moves both pins together. `skill show`, `skill status` and `skill install --json` answer in the
59
+ one-thing envelope, `{ item, meta }`, so a script reads their fields under `item`.
60
+ - **`mcp server start` no longer offers `--permission`.** cli-core added it to every CLI and passed it to a server
61
+ that refused it; now it is refused before anything starts. The profile's `permissions` still make the server
62
+ stricter.
63
+
64
+ A CLI made from an older template keeps its own `src/commands/mcp.ts`, since `src/` is a seed: copy the template's
65
+ file, and change `claude mcp add` lines in its docs to end in `mcp serve`.
66
+
67
+ ### Security
68
+
69
+ - **`.gitleaks.toml` catches Google OAuth tokens.** gitleaks' own rules know Google API keys only, so an access token
70
+ (`ya29.…`) or a refresh token (`1//…`) with no keyword beside it went through. Two rules now catch them. A CLI takes
71
+ them with `upgrade`; scan its history once with `gitleaks git` after that, since CI scans all of it.
72
+
73
+ ### Fixed
74
+
75
+ - **A command other than `mcp serve` no longer loads the MCP library.** `src/commands/mcp.ts` imported `portOf` and
76
+ `publicUrlOf` from `@wirecat/cli-core/mcp` at the top, so `--version` and `doctor` loaded the MCP server SDK too
77
+ (WC-LIFE-6). `mcp serve --http` now imports them when it runs.
78
+ - `docs/security.md` says what `mcp serve --http` listens on, what it keeps of each browser login, and that
79
+ `mcp revoke` ends them.
80
+ - **`pnpm audit:commands` prints the CLI's own scorecard lines**, not the last CLI's total, which was zoom-cli's. It
81
+ fails when the scorecard has no line for the CLI. Whether a new finding fails the run did not change.
82
+ - **`AGENTS.md` keeps only what holds for the CLI's whole life.** The one-time first task (interview, reference CLI,
83
+ rewrite the README and the MCP instructions) moved into the `DESIGN.md` that `new` writes, which the CLI owns and
84
+ deletes the section from when it is done. `upgrade` drops the old text from `AGENTS.md`.
85
+ - **`new` writes a `files` list that ships only what the CLI runs from**: `dist`, `skills`, `README.md`,
86
+ `CHANGELOG.md` and `LICENSE`. It copied the template's own list, so a new CLI published its `src/` with tests and
87
+ fakes, `scripts/`, `.github/`, `bin/release`, `config/`, `lint/` and `template.json` (WC-REL-16). `package.json` is
88
+ a seed, so a CLI made before this trims its list by hand; `pnpm smoke` then checks the package still runs.
89
+ - `docs/dev/TESTING.md` and `ci.yml` give both reasons `contracts:upgrade` is skipped: it needs local state of the
90
+ CLI's own and a published version to upgrade from (WC-TEST-14).
91
+ - `docs/dev/reference-clis.md` shows the provider call cli-core has, `store.accounts.registerProvider(entry)`.
92
+ `@wirecat/cli-core/store` exports no `registerProvider` function.
7
93
 
8
94
  ## 0.8.0 — 27.10.2026
9
95
 
package/README.md CHANGED
@@ -33,14 +33,15 @@ such as `personal` in `clidev personal config show`; none is ever assumed. `CLID
33
33
  | `clidev commands --json` | Prints every command as JSON, for agents and scripts |
34
34
  | `clidev personal config show` | Shows each setting and where it came from |
35
35
  | `clidev skill install` | Installs the agent skill for Claude Code, Codex, Gemini CLI and OpenClaw; `--for hermes` for Hermes Agent |
36
- | `clidev personal mcp` | Serves the profile's commands to an AI agent over MCP; `--http` for agents in the browser |
36
+ | `clidev personal mcp serve` | Serves the profile's commands to an AI agent over MCP; `--http` for agents in the browser |
37
37
  | `clidev runs list` | Lists recorded runs, newest first: every command that failed is kept |
38
38
  | `clidev upgrade --check` | Says whether a newer version is on npm |
39
39
 
40
40
  ## For AI agents
41
41
 
42
- `clidev skill show` prints the rules an agent follows with this tool. `clidev personal mcp` serves every command to an
43
- agent, writes included: the profile's permissions decide what runs. See [MCP and permissions](docs/usage.md#agents).
42
+ `clidev skill show` prints the rules an agent follows with this tool. `clidev personal mcp serve` serves every
43
+ command to an agent, writes included: the profile's permissions decide what runs. See
44
+ [MCP and permissions](docs/usage.md#agents).
44
45
 
45
46
  ## Why this template
46
47
 
package/bin/release CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env sh
2
- # Publishes the version in package.json and tags it. Run on a clean `main` that matches origin/main; the owner runs
3
- # it, never an agent. When npm already has that version, or a higher one, it raises it to the next free one through a
4
- # pull request and publishes that (WC-REL-5). Nothing is published until `pnpm release:check` passes.
2
+ # Publishes the version in package.json and tags it. Run on a clean `main` that matches origin/main. An agent may run
3
+ # it without --local; --local is for the owner's first release only. When npm already has that version, or a higher
4
+ # one, it raises it to the next free one through a pull request and publishes that (WC-REL-5). Nothing is published
5
+ # until `pnpm release:check` passes.
5
6
  #
6
7
  # bin/release # publishes from GitHub Actions (.github/workflows/release.yml, npm trusted publishing)
7
8
  # bin/release --local # publishes from this computer: NPM_TOKEN if exported, else the keyring, else `npm login`
@@ -110,6 +111,7 @@ next=$(pnpm exec cli-dev next-version "$version" "$latest" "$versions")
110
111
  if [ "$next" != "$version" ]; then
111
112
  taken=""
112
113
  if published; then taken=1; why="$version is already on npm"; else why="$version is not above npm's latest $latest"; fi
114
+ next=$(node --experimental-strip-types scripts/version-level.ts --next "$next")
113
115
  echo "$why — publishing $next instead"
114
116
  # A version npm already has keeps its changelog section; the unreleased one becomes the new version.
115
117
  node -e 'const fs = require("fs"); const [o, n, taken] = process.argv.slice(1)
@@ -36,7 +36,7 @@
36
36
  },
37
37
  {
38
38
  "id": "missing-explicit-profile",
39
- "args": ["mcp"],
39
+ "args": ["mcp", "serve"],
40
40
  "exit": 2,
41
41
  "stream": "stderr",
42
42
  "kind": "json",
@@ -44,7 +44,7 @@
44
44
  }
45
45
  ],
46
46
  "mcp": {
47
- "args": ["personal", "mcp"],
47
+ "args": ["personal", "mcp", "serve"],
48
48
  "snapshot": "mcp-tools.json"
49
49
  }
50
50
  }
@@ -1,14 +1,36 @@
1
1
  #!/usr/bin/env node
2
- import { enableCompileCache } from "node:module";
3
- import { catchCrashes } from "@wirecat/cli-base";
4
- import { IDENTITY } from "../identity.js";
5
- enableCompileCache();
6
- const stopCatching = catchCrashes({ cli: IDENTITY.command, interactive: process.stdout.isTTY === true });
7
- const { run } = await import("../program.js");
8
- try {
9
- process.exitCode = await run(process.argv.slice(2));
2
+ // cli-dev bundle loader
3
+ import * as module from "node:module"
4
+
5
+ const words = process.argv.slice(2)
6
+ // As the CLI answers it, unless a test records the argv: then the CLI writes the record too.
7
+ if (
8
+ words.length === 1 &&
9
+ (words[0] === "--version" || words[0] === "-V") &&
10
+ !Object.keys(process.env).some((key) => key.endsWith("_TEST_ARGV_LOG"))
11
+ ) {
12
+ process.stdout.write("0.10.0\n")
13
+ } else {
14
+ // Before the bundle compiles: the bundle's own call comes after its chunks.
15
+ module.enableCompileCache()
16
+ const serves = ((words) => {
17
+ const plain = words.filter((word) => !word.startsWith("-"));
18
+ return plain
19
+ .slice(0, 4)
20
+ .some((word, at) => word === "serve" || word === "watch" || (word === "mcp" && plain[at + 1] === undefined));
21
+ })(words)
22
+ if (serves && module.registerHooks) {
23
+ const bundle = new URL("../bundle/", import.meta.url).href
24
+ module.registerHooks({
25
+ resolve: (specifier, context, next) =>
26
+ specifier.startsWith("./") && context.parentURL?.startsWith(bundle)
27
+ ? { url: new URL(specifier, context.parentURL).href, format: "module", shortCircuit: true }
28
+ : next(specifier, context),
29
+ })
30
+ }
31
+ const running = import("../bundle/clidev.js")
32
+ const chunks = ["../bundle/all-profiles-XHC7BG3P.js","../bundle/anthropic-N6B3ZZHQ.js","../bundle/bun-HUJLS7KP.js","../bundle/bun-sqlite-OWFO2TVR.js","../bundle/dist-ESHIQU4M.js","../bundle/echarts-2QGL2JP5.js","../bundle/embed-HHAAGHA6.js","../bundle/embedder-W2OGVVYH.js","../bundle/first-screen-U4DFUKUC.js","../bundle/instructions-OTZHT6NV.js","../bundle/mcp-OQBZXELQ.js","../bundle/mcp-VVF6J7SQ.js","../bundle/mcp-Y7VCIZ2J.js","../bundle/node-P4E63KXA.js","../bundle/node-SYD4GX5O.js","../bundle/node-TLZSIHIJ.js","../bundle/node-sqlite-X2DGRFOZ.js","../bundle/oauth-42M34GQ5.js","../bundle/open-SWXRCDLN.js","../bundle/process-KAFGXZ7Q.js","../bundle/program-EHR4G7VN.js","../bundle/prompt-ZQTMHRGX.js","../bundle/recognize-TTED4SE3.js","../bundle/remote-C37XJ4BP.js","../bundle/rerank-APFZAMQL.js","../bundle/serve-DDPIHDVZ.js","../bundle/server-L5GNG7KC.js","../bundle/server-LKVYA2AE.js","../bundle/state-WWPPHERF.js","../bundle/store-H6UIA4PK.js","../bundle/store-maintenance-command-EYBT64A2.js"]
33
+ // After the server answers its first request, so it starts no later.
34
+ if (serves) setTimeout(() => void Promise.allSettled(chunks.map((chunk) => import(chunk))), 2000).unref()
35
+ await running
10
36
  }
11
- finally {
12
- stopCatching();
13
- }
14
- //# sourceMappingURL=clidev.js.map
@@ -0,0 +1,24 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ CHILD_IDLE_MS,
5
+ allProfilesServer,
6
+ serveAllProfilesOverHttp,
7
+ serveAllProfilesOverStdio,
8
+ withProfile
9
+ } from "./chunk-BDSDQCV4.js";
10
+ import "./chunk-437W3Z2M.js";
11
+ import "./chunk-XFXBXQBS.js";
12
+ import "./chunk-5D4AEUVA.js";
13
+ import "./chunk-NTLPDH76.js";
14
+ import "./chunk-O5EHUB2V.js";
15
+ import "./chunk-EFHLQXG6.js";
16
+ import "./chunk-Y5E2WNWB.js";
17
+ import "./chunk-ZVVMGPBJ.js";
18
+ export {
19
+ CHILD_IDLE_MS,
20
+ allProfilesServer,
21
+ serveAllProfilesOverHttp,
22
+ serveAllProfilesOverStdio,
23
+ withProfile
24
+ };
@@ -0,0 +1,70 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ checkedOptions
5
+ } from "./chunk-2TBVT4SZ.js";
6
+ import {
7
+ messagesFor,
8
+ systemFor
9
+ } from "./chunk-JTTW5ZKF.js";
10
+ import {
11
+ Anthropic
12
+ } from "./chunk-ADLS6FVG.js";
13
+ import {
14
+ array,
15
+ optional,
16
+ strictObject,
17
+ string
18
+ } from "./chunk-EFHLQXG6.js";
19
+ import "./chunk-Y5E2WNWB.js";
20
+ import {
21
+ __name
22
+ } from "./chunk-ZVVMGPBJ.js";
23
+
24
+ // node_modules/.pnpm/@wirecat+cli-core@0.469.0_@wirecat+cli-base@0.65.0_commander@15.0.0_esbuild@0.28.2_type_9d12b0091b773232c527328da5835651/node_modules/@wirecat/cli-core/dist/models/anthropic.js
25
+ var options = strictObject({
26
+ stop_sequences: optional(array(string()))
27
+ });
28
+ var anthropic = {
29
+ images: true,
30
+ baseUrl: "https://api.anthropic.com",
31
+ validate: /* @__PURE__ */ __name((given) => checkedOptions("anthropic", options, given), "validate"),
32
+ complete: /* @__PURE__ */ __name(async (target, request, checked, apiKey, fetcher) => {
33
+ const client = new Anthropic({
34
+ apiKey: apiKey ?? "",
35
+ authToken: null,
36
+ fetch: /* @__PURE__ */ __name((input, init) => fetcher(input, { ...init, redirect: "error" }), "fetch"),
37
+ baseURL: target.baseUrl,
38
+ maxRetries: 0,
39
+ logLevel: "off",
40
+ timeout: 12e4
41
+ });
42
+ const response = await client.messages.stream({
43
+ ...checked,
44
+ model: target.model,
45
+ system: systemFor(request),
46
+ messages: [
47
+ ...messagesFor(request),
48
+ ...request.images === void 0 ? [] : [
49
+ {
50
+ role: "user",
51
+ content: request.images.map((image) => ({
52
+ type: "image",
53
+ source: { type: "base64", media_type: image.mimeType, data: image.data }
54
+ }))
55
+ }
56
+ ]
57
+ ],
58
+ max_tokens: request.maxTokens
59
+ }).finalMessage();
60
+ if (response.stop_reason !== "end_turn")
61
+ throw new Error("incomplete response");
62
+ return {
63
+ text: response.content.filter((block) => block.type === "text").map((block) => block.text).join(""),
64
+ tokens: response.usage.input_tokens + response.usage.output_tokens + (response.usage.cache_creation_input_tokens ?? 0) + (response.usage.cache_read_input_tokens ?? 0)
65
+ };
66
+ }, "complete")
67
+ };
68
+ export {
69
+ anthropic
70
+ };
@@ -0,0 +1,169 @@
1
+ import { createRequire as __bundleRequire } from "node:module";
2
+ const require = __bundleRequire(import.meta.url);
3
+ import {
4
+ DefaultLogger,
5
+ DrizzleQueryError,
6
+ NoopLogger,
7
+ SQLiteAsyncDatabase,
8
+ SQLiteAsyncPreparedQuery,
9
+ SQLiteAsyncSession,
10
+ SQLiteAsyncTransaction,
11
+ SQLiteDialect,
12
+ booleanFromInteger,
13
+ bufferFromBytes,
14
+ castToText,
15
+ dateFromStoredMilliseconds,
16
+ dateFromStoredSeconds,
17
+ entityKind,
18
+ jitCompatCheck,
19
+ refineSqliteCodecs,
20
+ sql
21
+ } from "./chunk-S57AMKLX.js";
22
+ import {
23
+ __name
24
+ } from "./chunk-ZVVMGPBJ.js";
25
+
26
+ // node_modules/.pnpm/@wirecat+cli-core@0.469.0_@wirecat+cli-base@0.65.0_commander@15.0.0_esbuild@0.28.2_type_9d12b0091b773232c527328da5835651/node_modules/@wirecat/cli-core/dist/store/sqlite/drizzle/bun.js
27
+ import { Database } from "bun:sqlite";
28
+ var bunSQLiteCodecs = refineSqliteCodecs({
29
+ "integer:boolean": { normalize: booleanFromInteger },
30
+ "integer:timestamp": { normalize: dateFromStoredSeconds },
31
+ "integer:timestamp_ms": { normalize: dateFromStoredMilliseconds },
32
+ "text:json": { normalize: JSON.parse },
33
+ blob: { normalize: bufferFromBytes },
34
+ "blob:json": {
35
+ cast: castToText,
36
+ normalize: JSON.parse
37
+ },
38
+ "blob:bigint": {
39
+ cast: castToText,
40
+ normalize: BigInt
41
+ },
42
+ numeric: {
43
+ cast: castToText,
44
+ normalize: String
45
+ },
46
+ "numeric:number": { normalize: Number },
47
+ "numeric:bigint": {
48
+ cast: castToText,
49
+ normalize: BigInt
50
+ }
51
+ });
52
+ var SQLiteBunSession = class extends SQLiteAsyncSession {
53
+ static {
54
+ __name(this, "SQLiteBunSession");
55
+ }
56
+ client;
57
+ relations;
58
+ options;
59
+ static [entityKind] = "SQLiteBunSession";
60
+ logger;
61
+ constructor(client, dialect, relations, options = {}) {
62
+ super(dialect, "sync");
63
+ this.client = client;
64
+ this.relations = relations;
65
+ this.options = options;
66
+ this.logger = options.logger ?? new NoopLogger();
67
+ }
68
+ exec(query) {
69
+ this.client.exec(query);
70
+ }
71
+ prepareQuery(query, mode, _prepare, executeMethod, mapper, queryMetadata) {
72
+ let stmt;
73
+ try {
74
+ stmt = this.client.query(query.sql);
75
+ } catch (e) {
76
+ throw new DrizzleQueryError(query.sql, this.options.paramsInErrors ? query.params : void 0, e);
77
+ }
78
+ return new SQLiteAsyncPreparedQuery("sync", executeMethod, {
79
+ all: /* @__PURE__ */ __name((params) => {
80
+ if (mode === "arrays") return stmt.values(...params);
81
+ return stmt.all(...params);
82
+ }, "all"),
83
+ get: /* @__PURE__ */ __name((params) => {
84
+ if (mode === "arrays") return stmt.values(...params)[0];
85
+ return stmt.get(...params);
86
+ }, "get"),
87
+ run: /* @__PURE__ */ __name((params) => {
88
+ return stmt.run(...params);
89
+ }, "run")
90
+ }, query, mapper, mode, this.logger, void 0, queryMetadata, void 0, this.options.paramsInErrors);
91
+ }
92
+ transaction(transaction, config = {}) {
93
+ const tx = new SQLiteBunTransaction("sync", this.dialect, this, this.relations);
94
+ let result;
95
+ const nativeTx = this.client.transaction(() => {
96
+ result = transaction(tx);
97
+ });
98
+ if (config.behavior === "concurrent") throw new Error("Concurrent transactions are not supported by driver");
99
+ nativeTx[config.behavior ?? "deferred"]();
100
+ return result;
101
+ }
102
+ };
103
+ var SQLiteBunTransaction = class SQLiteBunTransaction2 extends SQLiteAsyncTransaction {
104
+ static {
105
+ __name(this, "SQLiteBunTransaction2");
106
+ }
107
+ static [entityKind] = "SQLiteBunTransaction";
108
+ transaction(transaction) {
109
+ const savepointName = `sp${this.nestedIndex}`;
110
+ const tx = new SQLiteBunTransaction2("sync", this.dialect, this.session, this._.relations, this.nestedIndex + 1);
111
+ this.session.run(sql.raw(`savepoint ${savepointName}`));
112
+ try {
113
+ const result = transaction(tx);
114
+ this.session.run(sql.raw(`release savepoint ${savepointName}`));
115
+ return result;
116
+ } catch (err) {
117
+ try {
118
+ this.session.run(sql.raw(`rollback to savepoint ${savepointName}`));
119
+ } catch {
120
+ }
121
+ throw err;
122
+ }
123
+ }
124
+ };
125
+ var SQLiteBunDatabase = class extends SQLiteAsyncDatabase {
126
+ static {
127
+ __name(this, "SQLiteBunDatabase");
128
+ }
129
+ static [entityKind] = "SQLiteBunDatabase";
130
+ };
131
+ function construct(client, config = {}) {
132
+ const dialect = new SQLiteDialect({
133
+ codecs: config.codecs ?? bunSQLiteCodecs,
134
+ useJitMappers: jitCompatCheck(config.jit)
135
+ });
136
+ let logger;
137
+ if (config.logger === true) logger = new DefaultLogger();
138
+ else if (config.logger !== false) logger = config.logger;
139
+ const relations = config.relations ?? {};
140
+ const db = new SQLiteBunDatabase("sync", dialect, new SQLiteBunSession(client, dialect, relations, {
141
+ logger,
142
+ paramsInErrors: config.paramsInErrors
143
+ }), relations);
144
+ db.$client = client;
145
+ return db;
146
+ }
147
+ __name(construct, "construct");
148
+ function drizzle(...params) {
149
+ if (params[0] === void 0 || typeof params[0] === "string") return construct(params[0] === void 0 ? new Database() : new Database(params[0]), params[1]);
150
+ const { connection, client, ...DrizzleSQLiteConfig } = params[0];
151
+ if (client) return construct(client, DrizzleSQLiteConfig);
152
+ if (typeof connection === "object") {
153
+ const { source, ...opts } = connection;
154
+ const options = Object.values(opts).filter((v) => v !== void 0).length ? opts : void 0;
155
+ return construct(new Database(source, options), DrizzleSQLiteConfig);
156
+ }
157
+ return construct(new Database(connection), DrizzleSQLiteConfig);
158
+ }
159
+ __name(drizzle, "drizzle");
160
+ (function(_drizzle) {
161
+ function mock(config) {
162
+ return construct({}, config);
163
+ }
164
+ __name(mock, "mock");
165
+ _drizzle.mock = mock;
166
+ })(drizzle || (drizzle = {}));
167
+ export {
168
+ drizzle
169
+ };