From 36c3ecb9be6fc331a3d25392eeaad14242e15e9f Mon Sep 17 00:00:00 2001 From: Cristhofer Pincetti Date: Wed, 2 Sep 2026 10:51:51 -0400 Subject: [PATCH] docs: add AGENTS.md with release-loop and catalog-extraction guardrails Also add @types/bun so editors type-resolve bun:test/import.meta.main in scripts and tests that the CI tsconfig gate intentionally excludes. --- AGENTS.md | 35 +++++++++++++++++++++++++++++++++++ bun.lock | 5 +++++ package.json | 1 + 3 files changed, 41 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f9bc319 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,35 @@ +# AGENTS.md + +OpenCode provider plugin (`@brainervirus/opencode-commandcode`). Ships a **bundled** model catalog (`models.json`) extracted from the minified `command-code` npm CLI. CI does the extracting — never hand-edit `models.json`, `manifest.json`, or `_version.txt`. + +Layout: `src/` = runtime plugin + catalog engine (product, release-gated). `scripts/` = CI tooling (not published, not release-gated). `tests/unit/` = the only suite `bun run check` runs. + +## Commands + +- `bun run check` — the CI gate: `oxlint --deny-warnings` + `oxfmt --check` + `bun test tests/unit/` + `tsc --noEmit`. Run before every PR. +- Single file: `bun test tests/unit/catalog.test.ts` +- Refresh catalog locally (writes `models.json`, `_version.txt`, `manifest.json`): `bun run sync -- --remote` + +## Release rules — read before committing + +On 2026-09-02 this repo published **42 accidental npm versions** (0.7.5→0.7.46) from an infinite loop. The rules below exist to prevent that. Do not relax them. + +- Releases are path-gated (`scripts/analyze-release-scope.ts`): a commit counts only if it touches a product path — `plugin.ts`, `index.ts`, `models.json`, `manifest.json`, `_version.txt`, or `src/`. CI/docs/tests/scripts-only merges never release. +- Only **`fix|feat|perf`** commit subjects can cut a release. **`chore` never releases — not even `chore(scope)`.** The post-release automation commits `chore(release): sync manifests to vX` touching `package.json` + `manifest.json` (both product paths): making any `chore` releasable turns each release into the trigger for the next one — release → sync PR → merge → release → … +- The intended release path for catalog updates is the automation's `fix(catalog): sync command-code@X` commit (patch). Do not rename it to `chore(catalog)`. +- `package.json` / `manifest.json` version fields are written by automation only; don't bump them in feature PRs. + +## Catalog extraction (`src/catalog.ts`) — fragile by design + +- It slices balanced `{…}` spans around the anchor `SONNET_4_6:{id:"claude-sonnet-4-6"` and evals them with string bindings collected from the 12k chars before the anchor (`extractStringBindings`). +- Minified identifier names are **not stable** across `command-code` releases. 1.40.x introduced `$`-prefixed vars (`$R="vercel-ai-gateway"`); `\b` regex boundaries never fire before `$` (not a word char) — use `(?.tgz`, bundle is `dist/cli.mjs`), eval candidates manually with the same context, and surface the real ReferenceError (usually a missing binding, e.g. `$R is not defined`). +- Every extraction fix ships with a regression test in `tests/unit/catalog.test.ts` whose fixture mirrors the new minified shape. `isModelCatalog` requires ≥2 model entries — single-model fixtures fail. + +## CI automation + +- `catalog-sync.yml`: every 6h + manual dispatch. Extracts `command-code@latest`, opens a `fix(catalog)` PR (branch `chore/catalog-sync`) that auto-merges when the five `check *` jobs pass. On extraction failure it opens/updates a **catalog-break issue** — labels `catalog-break` and `automation` must exist on the repo (recreate with `gh label create` if missing). +- `release.yml`: semantic-release on every push to `main` (npm publish + tag + GitHub Release), then opens the `chore(release): sync manifests` PR which also auto-merges. +- `main` is protected (5 required checks). Never push to `main` — open a PR and let auto-merge handle it. +- `workflow_dispatch` always runs a workflow from **`main`**, never a PR head. Dispatching does not test your branch. +- Secrets: `NPMJS` (npm **Automation** token, mapped to `NPM_TOKEN`/`NODE_AUTH_TOKEN` — a login token fails with `EOTP`), `RELEASE_SYNC_TOKEN` (PAT; PRs opened with `GITHUB_TOKEN` do not trigger CI runs on their branch). diff --git a/bun.lock b/bun.lock index c31902a..739045a 100644 --- a/bun.lock +++ b/bun.lock @@ -9,6 +9,7 @@ "@semantic-release/github": "12.0.9", "@semantic-release/npm": "13.1.5", "@semantic-release/release-notes-generator": "14.1.1", + "@types/bun": "1.4.0", "@types/node": "^25.9.1", "ai": "6.0.191", "oxfmt": "0.63.0", @@ -170,6 +171,8 @@ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@types/bun": ["@types/bun@1.4.0", "", { "dependencies": { "bun-types": "1.4.0" } }, "sha512-K+lZULY23vRgK/CfTjFIV+tyifaNdSMlPh9j+6mQ/cLfpOznLyAuzgV/JQysyECpkBQLVMSyvjlr2fBUSA9wFQ=="], + "@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="], "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], @@ -202,6 +205,8 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "bun-types": ["bun-types@1.4.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-iIKw23BspnQQYd3prITOBxeUsxBHnwzX6YJfGMuNOZzeNcMmVqzIIVGRm1l69ogaPQmb4wB6BN8mA5bE9YuC5Q=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], diff --git a/package.json b/package.json index 69509c4..13d6532 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@semantic-release/github": "12.0.9", "@semantic-release/npm": "13.1.5", "@semantic-release/release-notes-generator": "14.1.1", + "@types/bun": "1.4.0", "@types/node": "^25.9.1", "ai": "6.0.191", "oxfmt": "0.63.0",