@bounded-systems/mint 0.4.3

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.
@@ -0,0 +1,20 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
16
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
17
+ with:
18
+ node-version: "22"
19
+ - run: npm ci --no-audit --no-fund
20
+ - run: npm test
@@ -0,0 +1,81 @@
1
+ # Reusable release-provenance workflow (workflow_call). A consuming repo calls
2
+ # this on a `v*` tag push (the tag `mint release` cut) with a ~10-line caller;
3
+ # no install, no published package. mint is checked out here and run against the
4
+ # caller's manifest + CHANGELOG, so fixing the tool once + bumping the pin
5
+ # propagates mint's release flow to every repo.
6
+ #
7
+ # # .github/workflows/release.yml in the consumer:
8
+ # name: release
9
+ # on:
10
+ # push:
11
+ # tags: ["v*"]
12
+ # permissions:
13
+ # contents: write
14
+ # id-token: write
15
+ # jobs:
16
+ # release:
17
+ # uses: bounded-systems/mint/.github/workflows/release-provenance.yml@<sha>
18
+ # with:
19
+ # ref: <sha>
20
+ #
21
+ # It emits the deterministic in-toto release Statement (tag → version plan →
22
+ # commit) with `mint attest`, keyless-signs it with cosign (the workflow's OIDC
23
+ # identity — no key material), and attaches the Statement + its Sigstore bundle
24
+ # to the caller's GitHub release. Verify with `cosign verify-blob` (the same
25
+ # bundle @bounded-systems/verify consumes).
26
+ name: release-provenance (reusable)
27
+
28
+ on:
29
+ workflow_call:
30
+ inputs:
31
+ ref:
32
+ description: "mint ref to run from (tag/sha for reproducibility)."
33
+ type: string
34
+ default: main
35
+ node-version:
36
+ description: "Node version for the mint runtime."
37
+ type: string
38
+ default: "22"
39
+
40
+ permissions:
41
+ contents: write # create / upload to the caller's GitHub release
42
+ id-token: write # OIDC — cosign keyless signing
43
+
44
+ jobs:
45
+ release-provenance:
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - name: Checkout caller (at the tag)
49
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
50
+ - name: Checkout mint
51
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
52
+ with:
53
+ repository: bounded-systems/mint
54
+ ref: ${{ inputs.ref }}
55
+ path: .mint
56
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
57
+ with:
58
+ node-version: ${{ inputs.node-version }}
59
+ - name: Install mint deps
60
+ working-directory: .mint
61
+ run: npm ci --no-audit --no-fund
62
+ # Run mint against the CALLER's repo (cwd = caller workspace), so it reads
63
+ # the caller's package.json + CHANGELOG.md + git HEAD.
64
+ - name: Emit the in-toto release Statement
65
+ env:
66
+ MINT_REF: ${{ inputs.ref }}
67
+ run: node .mint/mint.mjs attest --out mint-release.intoto.json
68
+ - name: Install cosign
69
+ uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.7.0
70
+ - name: Keyless-sign the release Statement (cosign, OIDC)
71
+ env:
72
+ COSIGN_EXPERIMENTAL: "1"
73
+ run: cosign sign-blob --yes --bundle mint-release.intoto.sigstore.json mint-release.intoto.json
74
+ - name: Attach provenance to the GitHub release
75
+ env:
76
+ GH_TOKEN: ${{ github.token }}
77
+ run: |
78
+ assets="mint-release.intoto.json mint-release.intoto.sigstore.json"
79
+ # Create the release from the tag annotation, or upload to it if it exists.
80
+ gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-from-tag $assets \
81
+ || gh release upload "$GITHUB_REF_NAME" $assets --clobber
@@ -0,0 +1,125 @@
1
+ name: release
2
+
3
+ # On a vX.Y.Z tag (pushed by `mint release`):
4
+ # release — test, pack, SLSA-attest the tarball, emit + keyless-sign the
5
+ # in-toto release Statement (tag → version plan → commit), publish
6
+ # the GitHub release (notes from the tag annotation mint wrote) with
7
+ # the statement + its Sigstore bundle attached.
8
+ # publish — stage on npm via OIDC trusted publishing (no tokens, ever) and
9
+ # publish to JSR. The npm package is staged, not live: a maintainer
10
+ # must approve it with 2FA before it appears on the registry.
11
+ # See job summary for the stage ID + approval instructions.
12
+ #
13
+ # This workflow covers: npm (staged) + JSR + GitHub release.
14
+ # Out of scope here — triggered separately on the same tag:
15
+ # Nix flakes — flake consumers pin a sha; update PRs are opened by the
16
+ # flake-update bot when the tag lands on the default branch.
17
+ # GHCR images — OCI builds run in their own repo/workflow and reference the
18
+ # published npm tarball or the GitHub release asset.
19
+ # Other deploys — bounded-systems infra workflows consume the GH release event.
20
+ on:
21
+ push:
22
+ tags: ["v*"]
23
+
24
+ permissions:
25
+ contents: write # create the GitHub release
26
+ id-token: write # OIDC — SLSA attestation, cosign keyless, npm/JSR publishing
27
+ attestations: write
28
+
29
+ jobs:
30
+ release:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
34
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
35
+ with:
36
+ node-version: "22"
37
+ - run: npm ci --no-audit --no-fund
38
+ - run: npm test
39
+ - name: Pack the package
40
+ id: pack
41
+ run: echo "tgz=$(npm pack | tail -1)" >> "$GITHUB_OUTPUT"
42
+ - name: Attest build provenance (SLSA)
43
+ uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
44
+ with:
45
+ subject-path: ${{ steps.pack.outputs.tgz }}
46
+ # Release provenance: the deterministic in-toto Statement binding this tag to
47
+ # its version plan + commit. `mint attest` reproduces byte-for-byte what
48
+ # `mint release` wrote locally, now with the CI builder identity filled in.
49
+ - name: Emit the in-toto release Statement
50
+ run: node mint.mjs attest --out mint-release.intoto.json
51
+ - name: Install cosign
52
+ uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.7.0
53
+ # Keyless: no key material — the signature is bound to this workflow's OIDC
54
+ # identity via Fulcio + logged in Rekor. The self-contained --bundle is the
55
+ # same artifact @bounded-systems/verify consumes (cosign verify-blob).
56
+ - name: Keyless-sign the release Statement (cosign, OIDC)
57
+ env:
58
+ COSIGN_EXPERIMENTAL: "1"
59
+ run: cosign sign-blob --yes --bundle mint-release.intoto.sigstore.json mint-release.intoto.json
60
+ - name: Publish GitHub release (notes from the tag annotation)
61
+ env:
62
+ GH_TOKEN: ${{ github.token }}
63
+ run: |
64
+ gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-from-tag \
65
+ "${{ steps.pack.outputs.tgz }}" \
66
+ mint-release.intoto.json \
67
+ mint-release.intoto.sigstore.json
68
+
69
+ publish:
70
+ needs: release
71
+ runs-on: ubuntu-latest
72
+ steps:
73
+ - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
74
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
75
+ with:
76
+ node-version: "24" # npm 11.15.0+ required for staged publishing
77
+ registry-url: "https://registry.npmjs.org"
78
+ - run: npm ci --no-audit --no-fund
79
+ - name: Publish or stage on npm (OIDC trusted publishing — no token)
80
+ id: stage
81
+ continue-on-error: true # JSR is the source of truth; npm failure must not block it
82
+ run: |
83
+ npm install -g npm@latest # ensure npm 11.15.0+ for staged publishing
84
+ echo "npm version: $(npm --version)"
85
+ PKG=$(node -p "require('./package.json').name")
86
+ # npm stage publish requires the package to already exist on the registry.
87
+ # On first publish, fall back to npm publish to seed it; all subsequent
88
+ # releases go through the staged flow (human 2FA approval required).
89
+ if npm view "$PKG" version 2>/dev/null; then
90
+ echo "package exists — using npm stage publish"
91
+ npm stage publish --access public --provenance 2>&1 | tee /tmp/stage-out.txt || true
92
+ else
93
+ echo "first publish — seeding with npm publish (staged publishing requires existing package)"
94
+ npm publish --access public --provenance 2>&1 | tee /tmp/stage-out.txt || true
95
+ fi
96
+ STAGE_OUT=$(cat /tmp/stage-out.txt)
97
+ STAGE_ID=$(echo "$STAGE_OUT" | grep -oE '[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}' | head -1 || true)
98
+ echo "stage_id=${STAGE_ID}" >> "$GITHUB_OUTPUT"
99
+ - name: Surface approval instructions
100
+ env:
101
+ STAGE_ID: ${{ steps.stage.outputs.stage_id }}
102
+ PKG: ${{ github.repository }}
103
+ run: |
104
+ {
105
+ echo "## npm package staged — human approval required"
106
+ echo ""
107
+ echo "The package is in the staging area, **not yet live on the registry**."
108
+ echo "A maintainer must approve it with 2FA before it becomes publicly available."
109
+ echo ""
110
+ if [ -n "$STAGE_ID" ]; then
111
+ echo "**Stage ID:** \`${STAGE_ID}\`"
112
+ echo ""
113
+ echo "**Approve via CLI (2FA required):**"
114
+ echo '```'
115
+ echo "npm stage approve ${STAGE_ID}"
116
+ echo '```'
117
+ else
118
+ echo "> Could not parse stage ID from npm output."
119
+ echo "> Run \`npm stage list @bounded-systems/mint\` to find it."
120
+ fi
121
+ echo ""
122
+ echo "**Or approve on npmjs.com:** open the [Staged Packages](https://www.npmjs.com/settings/~/packages/staged) tab."
123
+ } >> "$GITHUB_STEP_SUMMARY"
124
+ - name: Publish to JSR (OIDC — no token)
125
+ run: npx jsr publish --allow-slow-types
@@ -0,0 +1,48 @@
1
+ # Reusable versioning check (workflow_call). A consuming repo calls this with a
2
+ # ~6-line caller; no install, no published package. mint is checked out here and
3
+ # run against the caller's .release/ intents, so fixing the tool once + bumping
4
+ # the pin propagates to every repo.
5
+ #
6
+ # jobs:
7
+ # version:
8
+ # uses: bounded-systems/mint/.github/workflows/version.yml@<sha>
9
+ #
10
+ # `mint plan` validates every intent (fails closed on a malformed one) and
11
+ # previews the next version + changelog. It exits 0 when there are no intents.
12
+ name: version (reusable)
13
+
14
+ on:
15
+ workflow_call:
16
+ inputs:
17
+ ref:
18
+ description: "mint ref to run from (tag/sha for reproducibility)."
19
+ type: string
20
+ default: main
21
+ dir:
22
+ description: "Caller's intent directory."
23
+ type: string
24
+ default: .release
25
+
26
+ permissions:
27
+ contents: read
28
+
29
+ jobs:
30
+ version-check:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - name: Checkout caller
34
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
35
+ - name: Checkout mint
36
+ uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
37
+ with:
38
+ repository: bounded-systems/mint
39
+ ref: ${{ inputs.ref }}
40
+ path: .mint
41
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
42
+ with:
43
+ node-version: "22"
44
+ - name: Install mint deps
45
+ working-directory: .mint
46
+ run: npm ci --no-audit --no-fund
47
+ - name: mint plan (validate intents + preview next version)
48
+ run: node .mint/mint.mjs plan --dir "${{ github.workspace }}/${{ inputs.dir }}"
@@ -0,0 +1,18 @@
1
+ # Release intents
2
+
3
+ One file per user-facing change, added in the PR that makes the change. `mint`
4
+ collects every `*.md` here (except this README and `_`/`.`-prefixed files),
5
+ resolves the strongest `bump`, and cuts the release deterministically.
6
+
7
+ Format:
8
+
9
+ ```markdown
10
+ ---
11
+ bump: minor # patch | minor | major
12
+ ---
13
+ scan: promote to a verb (CLI + MCP) + shared Zod type contracts
14
+ ```
15
+
16
+ - `mint plan` — preview the next version + changelog entry (pure; pass `--date` to pin it).
17
+ - `mint version` — apply: bump `package.json` + lockfile, prepend `CHANGELOG.md`, consume these intents.
18
+ - `mint release` — cut the `v<version>` tag + emit the in-toto release provenance (keyless-signed in CI). `--dry-run` previews it.
package/CHANGELOG.md ADDED
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ ## 0.4.3 — 2026-06-29
4
+
5
+ ### Patch
6
+
7
+ - seed npm first publish — detect new package and fall back to `npm publish` before staging is available
8
+
9
+ ## 0.4.2 — 2026-06-29
10
+
11
+ ### Patch
12
+
13
+ - retry staged npm publish — trusted publisher updated to allow staging
14
+
15
+ ## 0.4.1 — 2026-06-29
16
+
17
+ ### Patch
18
+
19
+ - fix publish logging — stream npm stage output so errors are visible in CI (was silently swallowed by set -e)
20
+
21
+ ## 0.4.0 — 2026-06-29
22
+
23
+ ### Minor
24
+
25
+ - staged npm publishing — `npm stage publish` replaces direct publish; human 2FA approval gate before the package goes live
26
+
27
+ ## 0.3.1 — 2026-06-29
28
+
29
+ ### Patch
30
+
31
+ - release: JSR publish must not be blocked by the brand-new-npm-package step (continue-on-error)
32
+
33
+ ## 0.3.0 — 2026-06-29
34
+
35
+ ### Minor
36
+
37
+ - mint release: cut the tag + emit a deterministic in-toto release Statement (tag → version plan → commit), keyless-signed in CI (cosign/Sigstore; anchored-chain-shaped); `mint attest` re-emits it; reusable release-provenance.yml workflow_call for consumers
38
+
39
+ ### Patch
40
+
41
+ - publish-prep: make the package cleanly JSR-publishable — `jsr.json` gains the SPDX `license` + a `publish.include` allowlist (tarball = exports + mint.mjs + README + CHANGELOG); `@types/node` dev dependency so the JSR type-checker resolves the `node:` imports. `npx jsr publish --dry-run` and `deno publish --dry-run` both pass.
42
+
43
+ ## 0.2.0 — 2026-06-24
44
+
45
+ ### Minor
46
+
47
+ - mint release verb (signed tag) + SLSA provenance release workflow
48
+
49
+ ## 0.1.0 — 2026-06-24
50
+
51
+ ### Minor
52
+
53
+ - Deterministic plan core (pure intents+version→version+changelog) + Zod intent contract + CLI (plan/version)
54
+ - Reusable version.yml workflow + org adoption scanner (--write rollout)
55
+
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # @bounded-systems/mint
2
+
3
+ Deterministic versioning — **intent files in, signed release out**. A *seam over
4
+ [`semver`](https://github.com/npm/node-semver)*: mint owns the flow (intent
5
+ assembly, changelog, tagging, provenance) and delegates only the version
6
+ arithmetic to the proven core.
7
+
8
+ Built because tagging-by-hand drifts: a manifest left behind its release tags is
9
+ a recurring bug ([string-audit#42](https://github.com/bounded-systems/string-audit/issues/42)).
10
+ mint makes the version a per-PR declaration and the release a single atomic step.
11
+
12
+ ## Principles
13
+
14
+ - **Opinionated** — one canonical release flow, no configurable branching.
15
+ - **Strongly deterministic** — `plan()` is a *pure function* of `(currentVersion, intents, date)`. No commit-history ordering, no `Date.now()`, no randomness. Same intents in → same version + changelog out (sha in → sha out).
16
+ - **Typed end-to-end** — intents and plan validated with Zod; a verbspec CLI/MCP surface mirrors the rest of the stack.
17
+ - **Owned** — delegate only `semver` arithmetic; own assembly, rendering, tagging, and provenance.
18
+
19
+ ## Use
20
+
21
+ Each PR drops an intent in `.release/` (see [`.release/README.md`](.release/README.md)):
22
+
23
+ ```markdown
24
+ ---
25
+ bump: minor
26
+ ---
27
+ scan: promote to a verb (CLI + MCP) + shared Zod type contracts
28
+ ```
29
+
30
+ Then:
31
+
32
+ ```sh
33
+ mint plan # preview: 0.6.1 → 0.7.0 (minor) + the changelog entry
34
+ mint version # apply: bump package.json + lockfile, prepend CHANGELOG.md, consume intents
35
+ mint release # cut the v<version> tag + emit release provenance (CI keyless-signs it)
36
+ ```
37
+
38
+ `mint plan --json` emits the machine-readable plan. `--date YYYY-MM-DD` pins the
39
+ changelog date (the pure core never reads the clock; the CLI injects it).
40
+
41
+ ## Release provenance
42
+
43
+ `mint release` cuts the annotated tag `v<version>` (signed when a git signing key
44
+ is configured) **and** emits a release **provenance record** — an
45
+ [in-toto Statement v1](https://in-toto.io/Statement/v1) binding the three things a
46
+ release is:
47
+
48
+ ```
49
+ tag → version plan → commit
50
+ ```
51
+
52
+ The subject is the tag, anchored to its commit (in-toto `gitCommit` digest); the
53
+ predicate carries the byte-exact changelog entry (the deterministic `plan()`
54
+ output) and its `sha256`. Re-deriving the plan over the same intents reproduces
55
+ that digest — the tag-to-plan link is machine-checkable, offline.
56
+
57
+ The Statement is **deterministic** (`releaseStatement()` is pure, like `plan()`)
58
+ and **keyless-signed in CI**: `release.yml` runs `mint attest`, then
59
+ `cosign sign-blob` binds the signature to the workflow's OIDC identity (Fulcio +
60
+ Rekor — no key material). Locally the Statement is emitted **unsigned**
61
+ (`builder: null`) so the flow degrades gracefully off-CI. This is the same
62
+ Statement / DSSE / keyless-Sigstore shape the bounded-systems sites and
63
+ [`@bounded-systems/verify`](https://github.com/bounded-systems/verify) already
64
+ produce and verify, so a mint release record verifies with the same tooling:
65
+
66
+ ```sh
67
+ cosign verify-blob \
68
+ --bundle mint-release.intoto.sigstore.json \
69
+ --certificate-identity-regexp '^https://github.com/<org>/<repo>/' \
70
+ --certificate-oidc-issuer https://token.actions.githubusercontent.com \
71
+ mint-release.intoto.json
72
+ ```
73
+
74
+ > **anchored-chain:** mint deliberately mirrors
75
+ > [`anchored-chain`](https://github.com/bounded-systems/anchored-chain)'s in-toto
76
+ > constants + Statement/DSSE shape rather than depending on it: anchored-chain's
77
+ > in-toto module is Phase-0 and not yet re-exported from its public surface, is
78
+ > bun/TypeScript with a build step, and its predicate models a *derivation
79
+ > chain*, not a release. mint stays a zero-build node ESM package and can adopt
80
+ > anchored-chain's `Signer`/`Verifier` once that surface lands — the bytes
81
+ > already match.
82
+
83
+ ### Adopt mint's release in CI
84
+
85
+ A consumer repo calls the reusable
86
+ [`release-provenance.yml`](.github/workflows/release-provenance.yml) on its tag
87
+ push (a ~10-line caller — see the header of that workflow):
88
+
89
+ ```yaml
90
+ # .github/workflows/release.yml
91
+ name: release
92
+ on: { push: { tags: ["v*"] } }
93
+ permissions: { contents: write, id-token: write }
94
+ jobs:
95
+ release:
96
+ uses: bounded-systems/mint/.github/workflows/release-provenance.yml@<sha>
97
+ with: { ref: <sha> }
98
+ ```
99
+
100
+ `adoption.mjs --write` drops both this caller and the `version.yml` caller into
101
+ every publishable repo — the path off hand-tagging.
102
+
103
+ ## Publish (npm + JSR)
104
+
105
+ mint ships from `release.yml` on each `v*` tag via **OIDC trusted publishing** —
106
+ no `NPM_TOKEN`, no JSR token, ever. The package manifests are kept in lockstep by
107
+ `mint version` (it bumps `package.json`, `package-lock.json`, **and** `jsr.json`).
108
+
109
+ **npm uses staged publishing** — `npm stage publish` submits the package to a
110
+ staging area rather than making it live immediately. A maintainer must approve it
111
+ with 2FA before it appears on the registry:
112
+
113
+ ```sh
114
+ npm stage approve <stage-id> # CLI, 2FA required
115
+ # or: npmjs.com → Staged Packages tab → Approve
116
+ ```
117
+
118
+ The stage ID is surfaced in the GitHub Actions job summary after each release run.
119
+
120
+ **JSR publishes immediately** on the same tag (no staging concept on JSR).
121
+
122
+ JSR-readiness is verified the same way CI publishes:
123
+
124
+ ```sh
125
+ npx jsr publish --dry-run --allow-slow-types # the path release.yml runs
126
+ deno publish --dry-run --allow-slow-types # equivalent, Deno-native
127
+ ```
128
+
129
+ `jsr.json` carries the SPDX `license` and a `publish.include` allowlist, so the
130
+ published tarball is just the three exports + `mint.mjs`, `README`, `CHANGELOG`
131
+ (no tests, lockfiles, or workflows). `@types/node` is a dev dependency so the
132
+ JSR type-checker resolves mint's `node:` imports.
133
+
134
+ > **One-time JSR link (manual, once):** before the first JSR publish, link the
135
+ > package on [jsr.io](https://jsr.io) — create `@bounded-systems/mint` under the
136
+ > `@bounded-systems` scope and connect it to the `bounded-systems/mint` GitHub
137
+ > repo (Settings → "Link to a GitHub repository"). That GitHub link is what
138
+ > authorizes the keyless OIDC publish; after it, every tagged release publishes
139
+ > with no token.
140
+
141
+ ## Library
142
+
143
+ ```js
144
+ import { plan } from "@bounded-systems/mint";
145
+ import { releaseStatement } from "@bounded-systems/mint/release";
146
+
147
+ plan({
148
+ currentVersion: "0.6.1",
149
+ intents: [{ bump: "minor", summary: "scan: promote to a verb" }],
150
+ date: "2026-06-23",
151
+ }).nextVersion; // "0.7.0"
152
+
153
+ releaseStatement({
154
+ version: "0.7.0",
155
+ tag: "v0.7.0",
156
+ commit: "0123456789abcdef0123456789abcdef01234567",
157
+ date: "2026-06-23",
158
+ changelog: "## 0.7.0 — 2026-06-23\n\n### Minor\n\n- scan: promote to a verb\n",
159
+ producer: "@bounded-systems/mint",
160
+ })._type; // "https://in-toto.io/Statement/v1"
161
+ ```
162
+
163
+ ## Roadmap
164
+
165
+ - [x] Deterministic `plan` core + Zod intent contract
166
+ - [x] `mint plan` / `mint version`
167
+ - [x] `mint release` — signed tag + in-toto release provenance, keyless-signed in CI (cosign/Sigstore; anchored-chain-shaped)
168
+ - [ ] verbspec-typed CLI + MCP surface
169
+ - [x] Reusable `workflow_call` Action (`version.yml` + `release-provenance.yml`)
170
+ - [x] Publish to npm (staged, human 2FA approval gate) + JSR
171
+
172
+ Tracking: [bounded-systems/string-audit#43](https://github.com/bounded-systems/string-audit/issues/43).
173
+
174
+ ## License
175
+
176
+ PolyForm-Noncommercial-1.0.0