@escalay/kit 1.7.0 → 1.8.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/README.md
CHANGED
|
@@ -130,5 +130,14 @@ npx skills add escalay/api-kit
|
|
|
130
130
|
| [`api-kit-build`](skills/api-kit-build/SKILL.md) | start a new API, move an app onto the kit, take a newer kit |
|
|
131
131
|
| [`api-kit-feature`](skills/api-kit-feature/SKILL.md) | add a feature folder: schema, repo, routes, handlers, tools, tests |
|
|
132
132
|
| [`api-kit-review`](skills/api-kit-review/SKILL.md) | check an API is agent-ready: the commands to run and what a failure means |
|
|
133
|
+
| [`npm-release`](skills/npm-release/SKILL.md) | set up or run releases of any npm package from GitHub Actions, or find out why one failed |
|
|
134
|
+
|
|
135
|
+
## Releases
|
|
136
|
+
|
|
137
|
+
Merging a pull request is the only manual step. Its title, a Conventional Commit, becomes a line of the release
|
|
138
|
+
notes; merging the release pull request publishes `@escalay/kit` and `create-escalay` to npm from GitHub Actions,
|
|
139
|
+
with provenance and no npm token. How it works, and how to set it up in another repo:
|
|
140
|
+
[docs/releasing.md](docs/releasing.md). `pnpm release:check` says whether a release is ready, and
|
|
141
|
+
`npx shadcn add escalay/api-kit/npm-release` copies the setup into another repo.
|
|
133
142
|
|
|
134
143
|
Working on the kit itself: [AGENTS.md](AGENTS.md). Licence: [MIT](LICENSE).
|
package/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `--web-dir` (relative to `--dir`, remembered in kit.json) puts the browser parts in their own folder, still
|
|
7
7
|
* tracked by the one kit.json (as `@web/<file>`).
|
|
8
8
|
*
|
|
9
|
-
* kit list parts, what they need, which are installed
|
|
9
|
+
* kit list parts, what they need, which are installed; then the root items
|
|
10
10
|
* kit add core guide mcp testing [--dir src/kit] [--web-dir ../web] [--install]
|
|
11
11
|
* kit diff [--dir src/kit] [--patch] per file: unchanged, you edited, kit changed, both
|
|
12
12
|
* kit update [part…] [--dir src/kit] [--force]
|
|
@@ -32,8 +32,12 @@ const KIT = dirname(fileURLToPath(import.meta.url))
|
|
|
32
32
|
const REPO = 'escalay/api-kit'
|
|
33
33
|
const rangeOf = (dependency) => [dependency.slice(0, dependency.lastIndexOf('@')), dependency.slice(dependency.lastIndexOf('@') + 1)]
|
|
34
34
|
/** registry.json is a shadcn registry; a part's requires are its dependencies on this repo, a dependency without a range is a peer. */
|
|
35
|
+
const ITEMS = JSON.parse(readFileSync(join(KIT, 'registry.json'), 'utf8')).items
|
|
36
|
+
/** Root items (`meta.root`) are repo setup the shadcn CLI installs at the repo root: not parts, so `add`, `adopt` and `doctor` never see them. */
|
|
37
|
+
const ROOT_ITEMS = ITEMS.filter((item) => item.meta?.root)
|
|
38
|
+
const shadcnAdd = (name) => `npx shadcn add ${REPO}/${name}`
|
|
35
39
|
const REGISTRY = Object.fromEntries(
|
|
36
|
-
|
|
40
|
+
ITEMS.filter((item) => !item.meta?.root).map((item) => [
|
|
37
41
|
item.name,
|
|
38
42
|
{
|
|
39
43
|
description: item.description,
|
|
@@ -73,6 +77,7 @@ const lockPath = join(dir, 'kit.json')
|
|
|
73
77
|
const withRequired = (wanted) => {
|
|
74
78
|
const all = new Set()
|
|
75
79
|
const visit = (name) => {
|
|
80
|
+
if (ROOT_ITEMS.some((item) => item.name === name)) fail(`"${name}" goes to the repo root, not into ${dirArg}: \`${shadcnAdd(name)}\``)
|
|
76
81
|
if (!REGISTRY[name]) fail(`no module "${name}". Modules: ${Object.keys(REGISTRY).join(', ')}`)
|
|
77
82
|
if (all.has(name)) return
|
|
78
83
|
for (const required of REGISTRY[name].requires ?? []) visit(required)
|
|
@@ -291,6 +296,7 @@ const commands = {
|
|
|
291
296
|
const needs = [...(module.requires ?? []), ...Object.keys(module.dependencies ?? {})]
|
|
292
297
|
console.log(`${installed.has(name) ? '●' : '○'} ${name.padEnd(11)} ${module.description}${needs.length ? `\n ${''.padEnd(11)} needs: ${needs.join(', ')}` : ''}`)
|
|
293
298
|
}
|
|
299
|
+
for (const { name, description } of ROOT_ITEMS) console.log(`◇ ${name.padEnd(11)} ${description}\n ${''.padEnd(11)} at the repo root: ${shadcnAdd(name)}`)
|
|
294
300
|
},
|
|
295
301
|
|
|
296
302
|
add: () => {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
How an npm package gets from a merged pull request to the registry with no manual step. The same setup works in
|
|
4
|
+
any pnpm repo: `npx shadcn add escalay/api-kit/npm-release` copies it (the workflow, the release-please files, the
|
|
5
|
+
check and this page).
|
|
6
|
+
|
|
7
|
+
## How a change becomes a release
|
|
8
|
+
|
|
9
|
+
1. **A pull request with a Conventional Commit title.** CI checks the title, because it becomes the commit.
|
|
10
|
+
2. **Squash and merge.** The title is now one commit on `main`, and one line of the next release notes.
|
|
11
|
+
3. **The release pull request.** `release.yml` runs release-please on every push to `main`. It opens, and keeps
|
|
12
|
+
current, one pull request titled `chore(main): release X.Y.Z`: the version bumps and `CHANGELOG.md`.
|
|
13
|
+
`feat` raises the minor version, `fix` and `perf` the patch, a `!` after the type the major.
|
|
14
|
+
4. **Merge it when you want to release.** That is the only decision a person makes.
|
|
15
|
+
5. **Publish.** The same workflow tags `vX.Y.Z`, drafts the GitHub release, then typechecks and tests the tagged
|
|
16
|
+
commit, packs every public package, publishes each to npm, waits until npm serves them, runs
|
|
17
|
+
`scripts/release-smoke.sh X.Y.Z` when the repo has one, attaches the tarballs and publishes the GitHub release.
|
|
18
|
+
6. **Check.** `pnpm release:check` on `main` says, one line each, whether anything is off.
|
|
19
|
+
|
|
20
|
+
## What the pipeline guarantees
|
|
21
|
+
|
|
22
|
+
- **No npm token exists.** npm trusts this repo's `release.yml` in the `npm` environment (OIDC); nothing to leak
|
|
23
|
+
or rotate.
|
|
24
|
+
- **Provenance.** Every version carries a signed statement of the commit and workflow run that built it.
|
|
25
|
+
- **Tested twice.** The gate runs on the pull request and again on the exact commit that is published.
|
|
26
|
+
- **One version everywhere.** Every public package in the workspace is released together at the manifest's
|
|
27
|
+
version; `workspace:` ranges are written as real versions in the tarballs.
|
|
28
|
+
- **A stranger can install it.** The job fails unless the registry serves each `name@version`, and, with a smoke
|
|
29
|
+
script, unless a fresh install passes.
|
|
30
|
+
- **The GitHub release shows only what shipped.** It stays a draft until npm has the packages, and carries the
|
|
31
|
+
exact tarballs.
|
|
32
|
+
|
|
33
|
+
## One-time setup for a package repo
|
|
34
|
+
|
|
35
|
+
The repo uses pnpm, has `packageManager` in `package.json`, a `.node-version` whose npm is 11.5.1 or newer
|
|
36
|
+
(Node 24), `typecheck` and `test` scripts, and a `repository.url` in every published `package.json` that points
|
|
37
|
+
at the GitHub repo (provenance checks it).
|
|
38
|
+
|
|
39
|
+
1. Copy the setup: `npx shadcn add escalay/api-kit/npm-release`, then add
|
|
40
|
+
`"release:check": "node scripts/release-check.mjs"` to the scripts.
|
|
41
|
+
2. **Publish the first version by hand** (`pnpm publish --access public`). A package must exist on npm before a
|
|
42
|
+
trusted publisher can be added to it.
|
|
43
|
+
3. Write that version into `.release-please-manifest.json` (`{".": "1.0.0"}`). With more than one public
|
|
44
|
+
package, list each other `package.json` under `extra-files` in `release-please-config.json`
|
|
45
|
+
(`{"type": "json", "path": "packages/<name>/package.json", "jsonpath": "$.version"}`).
|
|
46
|
+
4. Trust the workflow, once per package (asks for your npm second factor):
|
|
47
|
+
`npm trust github <package> --file release.yml --repo <owner>/<repo> --env npm --allow-publish`
|
|
48
|
+
5. On GitHub: an environment named `npm` (Settings → Environments; limit it to the `main` branch), and
|
|
49
|
+
Settings → Actions → General → "Allow GitHub Actions to create and approve pull requests".
|
|
50
|
+
6. Branch rules for `main`: pull requests only, squash merging only with the pull request title as the commit
|
|
51
|
+
message, and the CI checks required. A pull request opened by the workflow's own token does not start CI, so
|
|
52
|
+
on the release pull request the required checks never report: merge it as an administrator, or close and
|
|
53
|
+
reopen it to start them. Its commits were all tested on their own pull requests, and the publish job tests again.
|
|
54
|
+
7. `pnpm release:check` until every line is ✓.
|
|
55
|
+
|
|
56
|
+
The workflow file must stay named `release.yml`: the trusted publisher names it.
|
|
57
|
+
|
|
58
|
+
## Titles that read well as release notes
|
|
59
|
+
|
|
60
|
+
The title is read by someone deciding whether to upgrade. Say what changed for them, imperative and lowercase,
|
|
61
|
+
without the ticket, the file or the how.
|
|
62
|
+
|
|
63
|
+
| Good | Bad | Why |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `feat: add cursor pages to boards` | `feat: boards changes` | says nothing |
|
|
66
|
+
| `fix: answer 404 for a board that was deleted` | `fix: bug in handlers.ts` | names a file, not a behaviour |
|
|
67
|
+
| `feat(cli)!: drop the --legacy flag` | `refactor: remove flag` | a breaking change hidden from the notes |
|
|
68
|
+
| `perf: embed a batch in one request` | `feat: performance` | wrong type, no content |
|
|
69
|
+
| `docs: explain how to rotate API keys` | `Update README.md` | not a Conventional Commit; CI refuses it |
|
|
70
|
+
|
|
71
|
+
`feat`, `fix`, `perf`, `docs` and `revert` appear in the notes (as New, Fixed, Faster, Documentation, Reverted).
|
|
72
|
+
`refactor`, `chore`, `test`, `build` and `ci` do not, and release nothing on their own.
|
|
73
|
+
|
|
74
|
+
## When a release fails
|
|
75
|
+
|
|
76
|
+
- **Run the failed jobs again** (Actions → the run → "Re-run failed jobs", not "all jobs": a full re-run finds
|
|
77
|
+
no new release and skips publishing). The publish step skips every `name@version` npm already has.
|
|
78
|
+
- **A version can never be published twice**, even after unpublishing. If a published version is bad, fix it and
|
|
79
|
+
release the next one; `npm deprecate <package>@<version> "<why>"` warns people off the bad one.
|
|
80
|
+
- **"npm still does not serve …" after 20 minutes.** npm can hold a new version back before serving it. The
|
|
81
|
+
package was published; when `npm view <package>@<version>` answers, run the failed jobs again.
|
|
82
|
+
- **`npm publish` answers 404 or "OIDC".** The trusted publisher does not match: `npm trust list <package>` must
|
|
83
|
+
show this repo, `release.yml` and the `npm` environment.
|
|
84
|
+
- **The smoke check fails.** The packages are public and broken for new installs. Fix forward with a `fix:` pull
|
|
85
|
+
request and merge the next release pull request; the GitHub release of the bad version stays a draft.
|
|
86
|
+
- **No release pull request appears.** Only `feat`, `fix`, `perf` and breaking changes raise a version; check the
|
|
87
|
+
repository setting from step 5.
|
|
88
|
+
|
|
89
|
+
## Checking a published package
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm view <package> dist.attestations # the provenance statement's URL and type
|
|
93
|
+
npm audit signatures # in a project that installed it: signatures and attestations verify
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
On npmjs.com the version shows a "Built and signed on GitHub Actions" badge that links to the commit and the
|
|
97
|
+
workflow run. The same tarballs are attached to the GitHub release.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@escalay/kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-ready HTTP APIs as parts an app copies in (shadcn-style): Hono + zod OpenAPI 3.1, HAL links, problem+json, cursors, ETags, API keys, discovery, a generated agent guide with skills, an MCP server over the same routes, vector search by words, picture and likeness, and its headless browser side.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.web.json && tsc --noEmit -p test/workers/tsconfig.json",
|
|
57
57
|
"test": "vitest run",
|
|
58
58
|
"test:starter": "node scripts/starter-check.mjs",
|
|
59
|
+
"release:check": "node scripts/release-check.mjs",
|
|
59
60
|
"kit": "node cli.mjs"
|
|
60
61
|
}
|
|
61
62
|
}
|
package/registry.json
CHANGED
|
@@ -507,6 +507,42 @@
|
|
|
507
507
|
"entry": true,
|
|
508
508
|
"web": true
|
|
509
509
|
}
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
"name": "npm-release",
|
|
513
|
+
"type": "registry:item",
|
|
514
|
+
"title": "npm release",
|
|
515
|
+
"description": "Releases of an npm package with no manual step: release-please keeps a release pull request, merging it publishes every public package from GitHub Actions with npm trusted publishing and provenance, waits until npm serves them and publishes the GitHub release; with a read-only release check and the standard that explains it. For any pnpm repo; its files go to the repo root",
|
|
516
|
+
"files": [
|
|
517
|
+
{
|
|
518
|
+
"path": ".github/workflows/release.yml",
|
|
519
|
+
"type": "registry:file",
|
|
520
|
+
"target": "~/.github/workflows/release.yml"
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
"path": "templates/npm-release/release-please-config.json",
|
|
524
|
+
"type": "registry:file",
|
|
525
|
+
"target": "~/release-please-config.json"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
"path": "templates/npm-release/release-please-manifest.json",
|
|
529
|
+
"type": "registry:file",
|
|
530
|
+
"target": "~/.release-please-manifest.json"
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"path": "scripts/release-check.mjs",
|
|
534
|
+
"type": "registry:file",
|
|
535
|
+
"target": "~/scripts/release-check.mjs"
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"path": "docs/releasing.md",
|
|
539
|
+
"type": "registry:file",
|
|
540
|
+
"target": "~/docs/releasing.md"
|
|
541
|
+
}
|
|
542
|
+
],
|
|
543
|
+
"meta": {
|
|
544
|
+
"root": true
|
|
545
|
+
}
|
|
510
546
|
}
|
|
511
547
|
]
|
|
512
548
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
+
"release-type": "node",
|
|
4
|
+
"include-component-in-tag": false,
|
|
5
|
+
"draft": true,
|
|
6
|
+
"force-tag-creation": true,
|
|
7
|
+
"always-update": true,
|
|
8
|
+
"changelog-sections": [
|
|
9
|
+
{
|
|
10
|
+
"type": "feat",
|
|
11
|
+
"section": "New"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "fix",
|
|
15
|
+
"section": "Fixed"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "perf",
|
|
19
|
+
"section": "Faster"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"type": "docs",
|
|
23
|
+
"section": "Documentation"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"type": "revert",
|
|
27
|
+
"section": "Reverted"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"type": "refactor",
|
|
31
|
+
"section": "Refactored",
|
|
32
|
+
"hidden": true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "chore",
|
|
36
|
+
"section": "Chores",
|
|
37
|
+
"hidden": true
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "test",
|
|
41
|
+
"section": "Tests",
|
|
42
|
+
"hidden": true
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"type": "build",
|
|
46
|
+
"section": "Build",
|
|
47
|
+
"hidden": true
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "ci",
|
|
51
|
+
"section": "CI",
|
|
52
|
+
"hidden": true
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"packages": {
|
|
56
|
+
".": {}
|
|
57
|
+
},
|
|
58
|
+
"pull-request-header": "Merging this pull request releases the version below: it is tagged, published to npm, checked from the registry, and then announced.",
|
|
59
|
+
"pull-request-footer": "Edit nothing here by hand; it is rewritten whenever main changes."
|
|
60
|
+
}
|