---
name: publish
description: Publish a monorepo package to all its supported registries by bumping version, building, and creating a GitHub release
argument-hint: "[package] [patch|minor|major]"
---
Publish a package from this monorepo via GitHub release. The publish workflow always publishes to **all supported registries** for the package (see table below) — there is no way to select individual registries.
Arguments are optional and positional — any can be omitted:
- `package`: `mcp-wallet-signer`, `browser-evm-signer`, or `browser-tron-signer`
- `bump`: `patch`, `minor`, or `major`
Note: `wallet-signer-core` is an internal-only monorepo package — it's inlined into both chain packages by dnt, so no consumer would install it directly from npm. Don't publish it.
## Inferring missing arguments
When arguments are omitted, infer them from context:
1. **Package**: Run `git diff HEAD~3 --stat -- packages/` to find which package(s) changed recently. If exactly one, use it. If ambiguous, ask the user.
2. **Bump**: Recommend based on the diff (see step 2 below). Ask for confirmation.
## Package details
| Package | Dir | Version field in `deno.jsonc` | npm name | JSR name | Supported registries |
|---|---|---|---|---|---|
| mcp-wallet-signer | `packages/mcp-wallet-signer` | `npm.version` | `mcp-wallet-signer` | — | npm |
| browser-evm-signer | `packages/browser-evm-signer` | top-level `version` | `browser-evm-signer` | `@nikicat/browser-evm-signer` | npm, jsr |
| browser-tron-signer | `packages/browser-tron-signer` | top-level `version` | `browser-tron-signer` | `@nikicat/browser-tron-signer` | npm, jsr |
### First publish of a new package
New npm packages need a one-time manual bootstrap before the GitHub-Actions OIDC flow works. For the very first publish of a new package:
1. Build locally: `cd packages/
&& deno task build:npm`
2. From the user's shell: `cd packages//npm && npm login && npm publish --provenance --access public` (interactive — user runs)
3. JSR (if applicable): `cd packages/ && deno publish --allow-dirty`
4. Tag the commit and push, but **skip creating a GitHub release** for this initial version — the publish workflow would otherwise fire on `release: created` and fail because the version is already on the registry.
5. **Authorize the GitHub workflow on each registry — do this immediately, even though the next release may be weeks away:**
- **npm Trusted Publisher** (https://www.npmjs.com/package/<npm-name>/access → "Trusted Publishers"): add provider `GitHub Actions`, owner `nikicat`, repo `mcp-wallet-signer`, workflow `publish.yml`, environment blank.
Without this, the workflow's `npm publish --provenance` fails with `ENEEDAUTH` — `secrets.NPM_TOKEN` is unset in this repo on purpose; the workflow relies entirely on OIDC.
- **JSR linked repo** (https://jsr.io/<jsr-name>/settings → "GitHub repository"): set to `nikicat/mcp-wallet-signer`.
Without this, `deno publish --allow-dirty` fails with `actorNotAuthorized`. Authorization is per-package — granting it for one package does **not** carry over to a sibling under the same scope.
6. The next version bump (≥ 0.x.y+1) goes through the normal workflow flow below.
### Bumping the chain-pkg dep range in `mcp-wallet-signer`
The MCP build remaps each chain-pkg `mod.ts` import to an npm dependency with a fixed version range — see `packages/mcp-wallet-signer/scripts/build-npm.ts`, in `mappings`. For pre-1.0 versions, **`^0.1.0` only matches `>=0.1.0 <0.2.0`**, so a chain minor bump (0.1.x → 0.2.0) leaves the MCP package pinned to the old major-zero band and `npx mcp-wallet-signer` keeps installing the stale version.
When publishing `mcp-wallet-signer` after a chain package's minor bump, also bump the range to the new band (e.g. `^0.1.0` → `^0.2.0`) and verify the built `npm/package.json` carries it before tagging:
```
grep -E '"browser-(evm|tron)-signer"' packages/mcp-wallet-signer/npm/package.json
```
## Tag format
Tags use the monorepo convention: `@` (e.g., `mcp-wallet-signer@0.4.1`, `browser-evm-signer@0.1.4`). The publish workflow parses the package name from the tag.
## Steps
### 1. Select package
Resolve package from arguments or inference (see above).
### 2. Detect existing state and determine version
Before doing any work, check what's already been done so the skill can resume a partial publish:
1. Read the current version from the package's `deno.jsonc` (see table above for which field).
2. Find the latest **released** tag: `git tag -l '@*' --sort=-v:refname | head -1`.
3. Check whether a tag for the current version already exists: `git tag -l '@'`.
4. Check whether a GitHub release already exists: `gh release view @ 2>&1`.
5. Check whether the package is already published:
- npm: `npm view version`
- JSR (if applicable): `deno info jsr:@`
Based on this state, determine the resume point:
| Tag exists? | Release exists? | Published? | Action |
|---|---|---|---|
| No | — | — | Need to bump version, tag, and publish (full flow from step 3) |
| Yes (local only) | No | No | Push tag, then continue from step 5 (CI) |
| Yes (remote) | No | No | Continue from step 5 (CI) |
| Yes (remote) | Yes | No | Continue from step 7 (wait for publish workflow) |
| Yes (remote) | Yes | Yes | Already fully published — inform user and stop |
**If a full flow is needed (no tag for current version):**
1. Run `git log ..HEAD --oneline -- packages/` to get commits since the last release.
2. If there are no commits, inform the user there's nothing new to publish and stop.
3. Recommend a bump type based on the commits:
- **patch**: bug fixes, formatting, docs, dependency bumps, CI changes
- **minor**: new features, new API surface, new tools/commands
- **major**: breaking changes to public API, removed exports, changed behavior
4. Show the user: the commit list, your recommended bump type with reasoning, and the resulting version. Ask for confirmation.
### 3. Build the npm package (smoke test)
Skip this step if resuming past it.
Run from the package directory:
```
cd packages/ && deno task build:npm
```
Verify the build succeeds before continuing.
### 4. Commit, tag, and push
Skip steps that are already done (e.g., if tag already exists, don't re-create it).
1. Bump the version in `packages//deno.jsonc`.
2. **If publishing `mcp-wallet-signer`**: also bump both `version` fields in the root `server.json` (top-level and `packages[0].version`).
3. Stage and commit changed files with message: `Bump version to `
4. Create a git tag: `@`
5. Push commit and tag: `git push && git push --tags`
**Important**: Always verify the tag is on the remote before proceeding. If the tag exists locally but not on the remote, push it with `git push --tags`.
### 5. Wait for CI checks
Wait for the CI workflow to pass on the pushed commit using `gh run watch $(gh run list --workflow=ci.yml --limit=1 --json databaseId --jq '.[0].databaseId')` with a timeout of 5 minutes.
If CI fails, show the logs with `gh run view --log-failed` and **stop** — do not create a release with failing checks.
### 6. Create GitHub release
Run:
```
gh release create @ --title "@" --generate-notes
```
This triggers the `publish.yml` GitHub Actions workflow which parses the package name from the tag, builds, and publishes to all supported registries:
- **npm job**: always runs — builds with `deno task build:npm` and publishes with `npm publish --provenance`
- **jsr job**: runs only for packages with `jsr: true` in the workflow (currently `browser-evm-signer`, `browser-tron-signer`)
### 7. Wait for publish workflow
Get the run ID from `gh run list --workflow=publish.yml --limit=1` and watch it with `gh run watch `. Use a timeout of 5 minutes.
If the workflow fails:
1. Show the logs with `gh run view --log-failed`.
2. Common failure modes — diagnose before retrying:
- `npm error code ENEEDAUTH` → trusted publisher missing on npm for this package. See "First publish of a new package" step 5 — same fix applies to a package that was bootstrapped manually but never wired up for CI.
- `error: ... actorNotAuthorized` from `deno publish` → JSR repo authorization missing for this package.
3. Once the underlying auth/setup is fixed (ask the user to do this), resume the same run instead of cutting a new tag: `gh run rerun --failed`. The GitHub release is already created, so a fresh push won't re-trigger anything.
### 8. Verify published packages
Check all supported registries for the package:
- **npm**: Run `npm view version` and confirm the output matches ``.
- **JSR** (if package supports it): Do **not** use `deno info jsr:@` from inside the workspace — Deno resolves the JSR specifier to the local workspace member and reports the in-tree source, so the check always "passes" regardless of what's actually on the registry. Hit JSR's meta API directly instead:
```
curl -s "https://jsr.io//meta.json" | python3 -c "import sys, json; print(list(json.load(sys.stdin).get('versions', {}).keys()))"
```
Confirm `` appears in the list.
- If any check fails, warn the user.