Commit graph

1,003 commits

Author SHA1 Message Date
f9a99056fe
fix(release): release notes come from the CHANGELOG, not the tag message
Same-day correction to ee2259f. That commit followed the order literally --
"use the tag's own message" -- and the result was an llm-security v8.0.0
release page reading "llm-security v8.0.0" and nothing else.

The defect is structural, not a typo: --create-tag mints -m "<name>
v<version>", so the tag message is mechanical EXACTLY where this helper made
the tag. The tag message is a good source only for tags written by hand.

The right source was already proven on the instance: llm-security v7.8.3's
release body is byte-for-byte its CHANGELOG `## [7.8.3]` section. So the
CHANGELOG is the org's established source, not a new invention -- and all 10
backfilled repos ship one (measured, 10/10).

- extractChangelogSection / releaseBodyFrom: pure, tested. Priority is
  CHANGELOG section -> tag message -> empty, and the source is REPORTED so a
  run says where the text came from rather than implying it wrote it.
- Three heading dialects are live and all three are covered: `## [6.0.0] -
  date`, `## [0.2.0] -- date` (em-dash), `## v1.0 (date)`, and voyage's
  `## v5.10.1 -- date -- trailing prose`. The version token matches exactly,
  so 0.1.0-pre is not 0.1.0 and 1.1.0 is not 1.10.0. An empty section (the
  standing `## [Unreleased]`) returns null so the caller falls through
  instead of publishing a blank body.
- backfill gains --repair for the backlog the first cut created. It PATCHes
  a PUBLISHED page, so the bar is strictly more informative, never merely
  different: no CHANGELOG section means no update, and a hand-written body at
  least as long as the section is left alone. Measured: that rule is what
  protects portfolio-optimiser v1.1.0 (4750 hand-written chars vs 3704).

Dry-run over the org: 14 release objects would gain real notes, e.g.
llm-security v8.0.0 19 chars -> 10530, config-audit v6.0.0 19 -> 27309.

18 new tests, written red first. Suite 211/211; check-versions 12/12 OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:41:18 +02:00
ee2259f63f
feat(release): file the Forgejo release object as part of a release
A pushed git tag is filed by Forgejo under /tags; only an explicit release
object appears under /releases. release-plugin.mjs only ever made a tag, so
every plugin's public releases page sat a version behind the ref the catalog
pinned -- llm-security showed v7.8.3 against a v8.0.0 tag.

Measured 2026-09-18 against the instance API: 24 repos in org `open`, 21 with
at least one tag, 11 of those 21 with no release object for their newest tag.
That reproduces the order's own independently-measured list exactly.

- parseForgejoRepo / planForgejoRelease / ensureForgejoRelease: pure, tested.
  The release body is the tag's own message VERBATIM or empty -- never
  generated prose. Read via %(contents:subject)+%(contents:body), never
  %(contents), which drags the SSH signature block into the notes.
- The step fires only on a run that PUBLISHES (--create-tag --write, or
  --push): filing a release object is itself a publish and must not ride
  along on a local --write past the operator's one-shot push token.
- Synchronous (curl via execFileSync), like check-versions.mjs's
  checkHomepage: runRelease is called without an await and its return value
  becomes the exit code, so an async step would let a rejected POST surface
  after the run had already exited 0 and called the release complete.
- 429 and the 502/503/504 family are retried with backoff, never swallowed.
  An unthrottled sweep drew 17 HTTP 429s and the first version of that sweep
  read every one as an empty list -- "verified nothing" was indistinguishable
  from "verified everything, all clean".
- The token reaches curl through a 0600 header file, never argv.

scripts/backfill-forgejo-releases.mjs covers the backlog and retries the one
step, reusing the same planner and API shell so the two cannot drift. Only
the newest tag is considered. Documented exception: ktg-plugin-marketplace
pre-polyrepo-archive, an archive marker, not a release; the register is keyed
by repo AND tag so that repo's next real release is still backfilled.

Tests written red first: 20 new (12 release path, 8 backfill), and the two
real-git integration tests were probed known-negative -- breaking the wiring
turns 68/0 into 66/2. Suite 193/193; check-versions 12/12 OK.

The backfill of the 10 outstanding release objects is NOT done: it was denied
in-session as a public-surface write and is the operator's call.

Order: 20260917T235642Z-730962924-from-from-ai-to-chitta

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:23:52 +02:00
328e92feb9
chore(catalog): bump claude-design v0.1.0 -> v0.2.0
claude-design v0.2.0 — release. Catalog ref now pins the v0.2.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-18 01:48:51 +02:00
cf34fce291
fix(catalog): claude-design referanse-tallene 13 -> 14
Phase 9 la til 05-critique-iterate.md, saa foundation-referansene gikk fra
fem til seks. Maalt ved f596c83: 14 filer under references/ - seks foundation
(00-05) + aatte per-preset. Badgen leser references-14.

To steder, fordi stat-linja ellers ville motsi prosaen to linjer over:
  :217 prosa       five foundation -> six foundation   (ugatet)
  :220 stat-linje  13 -> 14 reference files            (gatet)

Prosaen var korrekt for v0.1.0. Ugatede tall rotner naar ref-en flytter seg.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 01:48:30 +02:00
6b915777af
chore(catalog): bump repo-mailbox v0.34.0 -> v0.35.0
repo-mailbox v0.35.0 — release. Catalog ref now pins the v0.35.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-18 01:40:01 +02:00
4e3d2c76bd
fix(catalog): stat-linja for repo-mailbox 927 -> 978
Pluginens badge leser selftest_checks-978 ved 0.35.0 (fem suiter:
coord 257 + board 478 + route 73 + orders 116 + guard 54 = 978).
Katalogen sa 927. Badgen er kilden; katalogen rettes til den.

Ett tall paa README.md:235; resten av raden er urort.

Ordre 20260917T221924Z-6958712598-from-repo-mailbox, steg 2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 01:36:47 +02:00
bf1d913c21 docs(catalog): rett signatur-påstanden — git tag -a er SSH-signert, ikke usignert
CLAUDE.md sa at probe-taggen fra 2026-08-17 «came out unsigned all the same
(0 PGP blocks)». Det var en defekt i MÅLINGEN: ~/.gitconfig setter
gpg.format=ssh, så signaturen er en SSH-signatur og PGP-telling leser 0 på en
fullt signert tagg.

Re-målt i ferskt temp-repo: `git tag -a` gir 0 BEGIN PGP, 1 BEGIN SSH
SIGNATURE. Live-taggen llm-security v8.0.0 bærer samme SSH-signatur.

Forgejo viser likevel «ingen kjent nøkkel for denne signaturen» fordi
signeringsnøkkelen ikke er registrert som verifiseringsnøkkel på kontoen —
taggen er signert, men ingenting oppstrøms kan sjekke den. Signering er
dessuten ortogonalt til TAG-ANNOTATED: det er `-a` som gjør taggen til et
ekte tag-objekt, ikke signaturen.

Verifiseringsloven ansikt 4, i denne filas egne notater.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 01:15:52 +02:00
e6e4cf9d66 chore(catalog): bump llm-security v7.8.3 -> v8.0.0
llm-security v8.0.0 — release. Catalog ref now pins the v8.0.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-18 01:10:03 +02:00
5a893e3bfd fix(catalog): bryt stat-linje-vranglåsen mellom de to pre-flightene
Q3e innførte en pre-flight som leser den NYE ref-ens badger, mens applyRelease'
pre-flight leser den PINNEDE ref-en. De krevde motsatte verdier av samme
stat-linje, og den pinnede ref-en flyttes først av nettopp den skrivingen som
blokkeres — så ingen release som endrer et badget tall kunne fullføres. Målt på
to levende ordrer (repo-mailbox 0.35.0, llm-security 8.0.0).

Verre enn en blokk: --create-tag er med vilje ugatet på den katalog-brede
pre-flighten, så et ekte løp ville MINTET OG PUSHET taggen og deretter blokkert
— en publisert tag mot en katalog som aldri kan bumpes.

Fiks: preflightErrors tar navnet på pluginen som slippes og ser bort fra DENS
stat-funn. Ingenting blir uverifisert — (a) validerer stat-linja mot målet før
noe røres, og post-write-gaten validerer den mot den nå-pinnede nye ref-en. Kun
vinduet der den pinnede ref-en er kjent stale hoppes over.

Vakten er smal i tre ledd: kun den pluginen som slippes, kun funn med
kind='stat' (diskriminator i check-versions.mjs, aldri prosa-match), og en
ERROR uten ERROR-funn blir aldri frikjent. Hengende ref, badge-avvik, feil
README-etikett og død homepage blokkerer som før.

Valgt denne framfor å la applyRelease skrive stat-linja selv, fordi den ville
måttet innføre en maskinpolicy for badge-løse akser — og de er ved dokumentert
org-beslutning et menneskelig skjønn.

Iron Law: 5 nye tester, 2 røde før fiksen. 172/172 grønne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 01:05:39 +02:00
b5b0e2b88e fix(catalog): release-plugin.mjs stat-line pre-flight + no raw stacktrace on post-write fail
Q3e (order 20260913T051659Z-717911204-from-.claude), after Q3d. Live incident 13.09
(operator's own run): `release-plugin.mjs repo-mailbox --version 0.34.0 --create-tag
--write --commit --push` tagged+pushed v0.34.0, wrote the catalog ref + README label,
then crashed with a raw Node stacktrace because check-versions found the catalog's own
stat line stale against the plugin's NEW badge (868 vs 927). Neither --commit nor
--push of the catalog ran; the push token was correctly consumed (Q3c). Operator fixed
the line and committed/pushed manually.

D1 — the ordinary pre-flight (applyRelease -> check-versions) only ever inspects the
OLD ref, so a stat-line drift the release itself is about to expose slipped straight
through it into a pushed tag + a written, uncommitted catalog. New `preflightStatMismatches`
compares the catalog's stat line against what the release is about to make current (the
target ref's badge if that tag already exists, else the plugin's worktree README — exactly
what --create-tag is about to tag), BEFORE any tag or write. Extracted the shared
mismatch logic into check-versions.mjs as `statMismatchFindings` (pure refactor,
classifyPlugin's own behavior unchanged) so both the post-hoc gate and this pre-release
check use one rule.

D2 — the post-write confirmation was a bare execFileSync, which throws on a non-zero
exit. `reportPostWriteCheck` catches any failure (a real ERROR, or the subprocess
dying) and reports exactly what is done (tag pushed y/n, files written) and what
remains (commit/push), returning an exit code instead of an unhandled exception.

No version bump, no tag, no push, no CLAUDE.md wording this session.

Verification:
- node --test scripts/release-plugin.test.mjs: 41/41 (Q3d) -> 50/50 (9 new: 3
  preflightStatMismatches unit + 2 real-git D1 integration + 3 reportPostWriteCheck
  unit + 1 real-git D2 integration)
- node --test scripts/*.test.mjs: 158/158 (Q3d) -> 167/167
- node scripts/check-versions.mjs: 0 ERROR (1 known WARN: claude-design, unrelated)
- Mutation evidence (D1): commented out the new pre-flight call in runRelease ->
  exactly the new "D1 (Q3e, real git)" test went red (49 pass, 1 fail), all others
  stayed green; restored -> 50/50 again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 06:48:48 +02:00
19908a88b7 fix(catalog): test-vouch main()'s finally, orphan-tag cleanup, precise CLAUDE.md wording
Order 20260912T222008Z-8793921535-from-.claude (Q3d), follow-up to the PM
re-measurement of Q3c (dd278ca).

R1 — the run-scoped push-token consumption was only test-vouched at the
runRelease() level; D3's own test called consume() a second time in the TEST
BODY ("mirrors main()'s own finally") and asserted on that call, never on
anything main() itself did. A PM agent deleted the `finally` line in main()
in a copy and every existing test stayed green (39/39) while the real CLI,
run end-to-end, pushed the tag, hit NOOP, and left the token behind.

Added a test that runs the actual CLI entry point as a real subprocess
(main() calls process.exit(), so it cannot run in-process without killing
the test runner) against an isolated plugin repo, a local bare "remote",
and its own HOME — the same scenario the PM agent used (tag pushed, then a
NOOP branch that is not the run's final line). Mutation proof: removed the
`finally` line -> new test went RED (40 pass, 1 fail) while D3 stayed GREEN,
confirming D3 does not cover this path -> restored -> GREEN.

Sub-fix required to make the new test possible on this machine: macOS's
os.tmpdir() resolves through /var/folders, a symlink to /private/var/folders.
release-plugin.mjs's self-invocation guard compares the literal argv[1] path
against import.meta.url (which Node resolves through symlinks), so a script
run from the unresolved path never satisfies the guard and main() silently
never executes (exit 0, zero output). makeTempRoot() now returns the
realpath of the created temp dir.

S (side finding) — a tag push that fails after the local `git tag -a`
succeeded left an orphan local tag behind; a retry then failed on git's own
"tag already exists" (exit 128) instead of going through the idempotent
tag-absent path --create-tag already relies on. Chose: delete the local tag
when its push fails (option a) rather than detect-and-explain the orphan
state (option b) — it reuses the existing idempotency property instead of
adding a second one. Red-first: new test failed (orphan tag survived) ->
wrapped the push in try/catch, `git tag -d` on failure, rethrow -> GREEN.

R2 — CLAUDE.md said "a failed push leaves the token intact for the retry",
which is imprecise: with --create-tag --write --commit --push, if the tag
push succeeds and the catalog push then fails, the token IS consumed
(main()'s finally fires because pushGate.pushed was already set true by the
earlier successful push) even though the run overall "failed". Corrected to
state the actual rule: the token survives only when the run makes zero
successful pushes. The usage-block comment at the top of release-plugin.mjs
does not carry the same imprecise claim, so it needed no change.

Verification:
- node --test scripts/release-plugin.test.mjs: 39 -> 41/41 (R1, S added)
- node --test scripts/*.test.mjs: 156 -> 158/158
- node scripts/check-versions.mjs: 0 ERROR (1 known WARN: claude-design;
  repo-mailbox now OK — externally re-tagged since Q3c, untouched here)
- git tag -l: unchanged (12 tags, no new ones — no tag/push/bump this session)
- mutation proof for R1: finally line removed -> RED (D3 stayed green) -> restored -> GREEN
- mutation proof for S: recorded in scripts/release-plugin.test.mjs history above (red-first)

Not done (out of scope, deliberately): no version bump, no tag, no push;
no files touched outside scripts/release-plugin.mjs, scripts/release-plugin.test.mjs, CLAUDE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 07:19:36 +02:00
bc0bc0da61 release(repo-mailbox): v0.34.0 - catalog ref, README label, selftest stat 868->927 2026-09-13 07:17:33 +02:00
dd278ca70e fix(catalog): release-plugin.mjs consumes the push token on ANY exit after a push
Q3c (RETTELSE av Q3b `5bc6c4e`, ordre 20260912T220453Z-5021715764-from-.claude,
etter PM-re-måling på frossen klone 13.09 00:04). TDD: to nye røde tester skrevet
først (kjørt mot 5bc6c4e — SyntaxError: `runRelease` fantes ikke, se
release-plugin.test.mjs sin `Q3c fix` header for detaljer), deretter fiksen.

D3 (regresjon i Q3b) — `pushGate.consume()` sto nederst i main(), etter fire
tidligere process.exit()-kall (BLOCKED, NOOP, dry-run, rød pre-flight) som en
kjøring kan treffe ETTER at en tag-push allerede har lyktes. Live-verifisert
FØR fiksen (node -e med try/finally rundt process.exit(1)): finally kjører IKKE
når process.exit() kalles inne i try — Node terminerer før stack-avvikling.
Derfor holder ikke et enkelt try/finally rundt den gamle main()-kroppen.

Fiksen: `main()`s gren-logikk er flyttet til en eksportert `runRelease()` som
returnerer en exit-kode i stedet for å kalle process.exit() noe sted etter at en
push kan ha skjedd. `main()` kaller process.exit() nøyaktig ÉN gang, etter en
`finally` som kjører `if (pushGate.pushed) pushGate.consume()`. `pushGate` fikk
et nytt `pushed`-felt, satt til true rett etter hver vellykkede `git push`
(tag-push og katalog-push). Dette er det eneste stedet igjen å resonnere om
konsum — færrest utgangsstier, som ordren ba om.

S1 (svakhet i D2-testen fra Q3b) — den gamle testen satte `tagCreated` fra
`auth.authorised` i TESTEN SELV og asserterte på egen variabel; den beviste
ingenting om den faktiske main()-stien. Nye tester kjører `runRelease` mot
ekte midlertidige git-repoer (ingen mocket git):
- S1: uten token → `git tag -l` uendret, exit ≠ 0, `pushGate.pushed === false`.
  Mutasjonsbevis: flyttet `git tag -a` over token-sjekken → testen ble RØD →
  gjenopprettet original rekkefølge → GRØNN igjen.
- D3: med token, tag mangler men katalogen pinner allerede versjonen (NOOP-
  scenario) → ekte tag mintes+pushes til et lokalt bare-remote, run returnerer
  0, `pushGate.pushed === true`, tokenet er FYSISK BORTE etter — reproduserer
  PM-agentens live-probe (tag pushet, NOOP, token fortsatt der FØR fiksen).

Ordrens D1/D2-krav fra Q3b står uendret (delt token, sjekk før `git tag -a`) —
ikke rørt av denne fiksen, kun konsum-tidspunktet.

Verifisering (kommandoer kjørt, tall gjengitt her):
- `node --test scripts/release-plugin.test.mjs` → 39/39, 0 fail (opp fra 37).
- `node --test scripts/*.test.mjs` → 156/156, 0 fail (opp fra 154).
- `node scripts/check-versions.mjs` → 0 ERROR, 2 kjente WARN (claude-design,
  repo-mailbox — urørt, utenfor scope).
- Re-kjørt etter `git add` — uendret.

Kun `scripts/release-plugin.mjs` og `scripts/release-plugin.test.mjs` rørt.
Ingen versjonsbump, ingen tag, ingen push (forbudt i ordren). CLAUDE.md-
ordlyden («consumed after the push actually succeeds») er nå sann på alle
utgangsstier og krevde ingen endring.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 00:12:17 +02:00
5bc6c4ecbd fix(catalog): release-plugin.mjs shares one push token across a whole run
Q3b (order 20260912T213049Z-5772222747) corrects two measured defects in
Q3's ea9bf7a: pushWithToken checked-and-consumed per call, so a single
`--create-tag --write --commit --push` run spent the operator's one-shot
token on the tag push and always saw blocked:true on the catalog push
right after (D1). And `git tag -a` ran before any token check at all, so
a blocked run left a local annotated tag behind, breaking the retry with
"tag already exists" (D2).

createPushGate replaces the per-push check-and-consume with a run-scoped
gate: ensure() checks the token once and every later call in the same run
reuses that result, consume() fires once after the run's last successful
push. main() calls ensure() before the tag write (not just before the
push) and consume() once at the end. pushWithToken is now a single-push
convenience wrapper over the same gate — its existing tests stay green
unmodified.

Red-first: `createPushGate` did not exist on ea9bf7a (import error),
proving both new tests were red before the fix. After:
node --test scripts/release-plugin.test.mjs -> 37/37 (35 + 2 new)
node --test scripts/*.test.mjs -> 154/154
node scripts/check-versions.mjs -> 0 ERROR (2 known WARN: claude-design, repo-mailbox)
Live D2 check: `release-plugin.mjs repo-mailbox --create-tag --write`
without a token -> BLOCKED, exit 1, no local tag created.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 23:57:07 +02:00
ea9bf7ab02 fix(catalog): release-plugin.mjs requires the push-approval token before it pushes
pre-push-gate.sh is a text-matching PreToolUse hook and cannot see a `git push`
issued via execFileSync inside this script's own process — pinned as GAP in the
gate's header, with this script named as the concrete case (a plugin tag left the
machine unseen, 2026-09-12). --create-tag --write and --push now each require the
same one-shot push-approval token the gate checks, and consume it themselves after
a push succeeds, since post-push-consume.sh never fires for a call the gate never
saw. Tag-push and catalog-push share one token — one publish from the operator's
perspective. Red-first: 9 new tests (26 -> 35 in release-plugin.test.mjs, 0 fail
before implementation existed as an import error, 152/152 across the suite after).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 23:20:54 +02:00
80c25faaf5 chore(catalog): bump ms-ai-architect v1.17.0 -> v1.18.0
ms-ai-architect v1.18.0 — release. Catalog ref now pins the v1.18.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-12 21:29:06 +02:00
a829c2cb19 docs(catalog): re-measure repo-mailbox selftest-checks axis at v0.33.1
Order 20260905T044601Z-6057725482-from-catalog. Two provenance findings
before editing:
- CLAUDE.md itself never contained "529" — that was README.md's stat
  line, already fixed 09-04 to 868. The order named the wrong file for
  that number; CLAUDE.md's only selftest-checks passage is the dated
  2026-08-02 correction saga at v0.20.2 (398).
- "663" (STATE.md's NESTE shorthand for this task) appears nowhere in
  the tracked history of CLAUDE.md, README.md, or STATE.md — no known
  provenance, do not propagate it further.

Appended a dated re-measurement to the existing historical passage
(the v0.20.2/398 record stays untouched) rather than overwriting it:
verified pinned ref is v0.33.1 (marketplace.json), badge is
selftest_checks-868 (git show v0.33.1:README.md), catalog stat line
already agrees. Noted repo-mailbox's own per-script counts still only
sum to 792 against the 868 badge — the same ungated-prose pattern the
paragraph exists to document.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3PxDA5mgFb9R6fabekh6S
2026-09-05 06:52:41 +02:00
4d6a8ebf1c chore(catalog): bump repo-mailbox v0.33.0 -> v0.33.1
repo-mailbox v0.33.1 — release. Catalog ref now pins the v0.33.1 tag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 06:43:12 +02:00
ca19723bcb docs(catalog): document the update path - autoUpdate is off by default
`claude plugin marketplace add` records no `autoUpdate` key, and Claude Code
only defaults it on for Anthropic's own catalogs. A release published here
therefore never reaches an already-registered machine on its own.

Adds a "Staying up to date" section after Install with the manual commands
(`claude plugin marketplace update`, `claude plugin update`) and a paste-ready
`extraKnownMarketplaces` settings block that turns auto-update on.

Measured on Claude Code 2.1.260 in an isolated CLAUDE_CONFIG_DIR profile:
- `marketplace add` writes {source:{source,url}} with no autoUpdate
- `autoUpdate: true` in extraKnownMarketplaces propagates to
  plugins/known_marketplaces.json on next start
- negative control: `false` propagates too, so the probe discriminates

One place only; the 12 plugin READMEs are untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 18:42:21 +02:00
538af61925 chore(catalog): bump repo-mailbox v0.32.1 -> v0.33.0
Also correct the repo-mailbox stat line: catalog said 529 selftest
checks, plugin's own badge at v0.33.0 says 868 (check-versions.mjs
caught the drift as an ERROR before this commit).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 15:54:35 +02:00
a033835f30 chore(catalog): bump repo-mailbox v0.32.0 -> v0.32.1
repo-mailbox v0.32.1 — release. Catalog ref now pins the v0.32.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-04 07:55:57 +02:00
bb693454ab fix(catalog): remove retired push-window rule from release output
The "weekday 20-23" push window is retired; the release helper still
told the operator to observe it at the exact moment it pushed. Two
lines, one file — ordre 20260818T145115Z-1170729223-from-voyage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nUcNMXucyztssywSaHnoq
2026-09-03 20:44:33 +02:00
ad9723078c chore(catalog): bump repo-mailbox v0.31.0 -> v0.32.0
repo-mailbox v0.32.0 — release. Catalog ref now pins the v0.32.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-03 20:43:28 +02:00
647a061682 chore(catalog): bump voyage v5.10.0 -> v5.10.1
voyage v5.10.1 — release. Catalog ref now pins the v5.10.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-03 20:43:16 +02:00
47779d3b2b chore(catalog): bump repo-mailbox v0.30.0 -> v0.31.0
repo-mailbox v0.31.0 — release. Catalog ref now pins the v0.31.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-29 17:55:11 +02:00
5503c670f4 chore(catalog): bump repo-mailbox v0.29.0 -> v0.30.0
repo-mailbox v0.30.0 — release. Catalog ref now pins the v0.30.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-27 11:34:11 +02:00
0b0bf24137 fix(catalog): release gate can no longer be green without measuring anything
check-versions.mjs reported "12 SKIP, exit 0" on a fresh clone with no
sibling plugin repos — a run that verified nothing was indistinguishable
from a clean run. Any SKIP now fails the gate by default (--allow-skip
opts in explicitly), and the summary always reports "verified N/M".

Also adds a homepage-resolves check on plugin.json (dead-link ERROR,
verified live against voyage's stale pre-polyrepo URL); the field stays
optional since 11 of 12 plugins don't carry it yet.

gateOutcome is split out as a pure function so both directions (all-SKIP
fails, fully-verified-clean still passes) are unit-tested without needing
a real sibling-repo layout on disk.
2026-08-26 11:22:09 +02:00
4509bb6096 chore(catalog): bump repo-mailbox v0.28.0 -> v0.29.0
repo-mailbox v0.29.0 — release. Catalog ref now pins the v0.29.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-23 19:07:28 +02:00
d8b05bafe2 docs(catalog): add llms.txt (D2b)
One deterministic entry point for an AI agent already in the repo — H1,
one-line summary, and the exact install command quoted verbatim from
README.md's first code block. Not for crawler/search-engine discovery
(measured: GPTBot/ClaudeBot/PerplexityBot/Google-Extended read HTML
directly and skip /llms.txt in practice).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VtzotkDWXkjYpqqBnotKHN
2026-08-21 11:23:46 +02:00
55121d6680 chore(catalog): bump repo-mailbox v0.27.0 -> v0.28.0
repo-mailbox v0.28.0 — release. Catalog ref now pins the v0.28.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-20 23:08:22 +02:00
998cd5741a chore(catalog): bump config-audit v5.13.0 -> v6.0.0
config-audit v6.0.0 — release. Catalog ref now pins the v6.0.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-18 20:58:23 +02:00
9126adb4c9 chore(catalog): bump voyage v5.9.1 -> v5.10.0
voyage v5.10.0 — release. Catalog ref now pins the v5.10.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-18 16:49:26 +02:00
077ca732a7 chore(catalog): bump repo-mailbox v0.25.0 -> v0.27.0
repo-mailbox v0.27.0 — release. Catalog ref now pins the v0.27.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-17 21:59:13 +02:00
91fc0e6195 docs(catalog): record that the TAG-ANNOTATED acceptance is inert
Follow-up measurement to acdd606. The ERROR this repo carries is not an
unmade decision -- it is a made decision the checker structurally cannot see.

repo-standard's register already lists v7.7.2 under
tags_lightweight_accepted["ktg-plugin-marketplace"] (register/repos.json:231),
accepted 2026-08-14, with the rationale recorded at :211-223: monorepo-era
llm-security tag, pre-split, no install path consumes it. But
checkTagIntegrity judges the newest tag at :711 BEFORE reading the register at
:719, and applies `accepted` only to tags.slice(0, -1). The entry is therefore
inert.

Measured, not reasoned: importing repo-standard's own exported
checkTagIntegrity with its real register and `git for-each-ref refs/tags/v*`
returns exactly two findings for this repo -- [ERROR] TAG-ANNOTATED on v7.7.2,
and [OK] TAG-ANNOTATED-ACCEPTED covering the other 7 lightweight tags. No
TAG-ANNOTATED-HISTORY WARN: tag history here is fully claimed already.

That is the "we decided this" / "nobody looked" collapse the register was
built to prevent, reappearing one level up. Fix belongs in repo-standard;
reported to them and to .claude, not patched from here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FLwHvGkH2kV4XLjUHorhLu
2026-08-17 13:46:06 +02:00
acdd6060bd docs(catalog): record annotated-tag policy at the hand-tagging drift site
repo-standard's org-wide run flagged TAG-ANNOTATED (ERROR) on this repo: the
newest tag (v7.7.2) is lightweight, and the catalog pins plugins by tag, so a
movable tag is a movable pin.

Measured before writing, and the order's premise did not survive it:
release-plugin.mjs is NOT the reproduction site. It has used `git tag -a`
since 9b1838f, and the published surface agrees -- `git ls-remote --tags` on
repo-mailbox returns refs/tags/v0.25.0 (tag object a9b5eb8) AND the peeled
v0.25.0^{} (95ac710), which a lightweight tag does not have. The script tags
plugin repos; it never tags the catalog. The catalog's own tags are cut by
hand, and that is where nothing enforces anything.

Forward-only: the published lightweight tags stay. The only remedy for a
published tag is `git tag -a -f`, which force-moves a ref others may have
fetched -- the same traceless move the finding warns about. Consequence
recorded rather than hidden: TAG-ANNOTATED stays ERROR until a new annotated
tag sorts above v7.7.2 under compareTags, because tags_lightweight_accepted
reaches history only and cannot excuse the newest tag.

Probe pair run locally and deleted: `git tag -a` -> objecttype `tag`,
`git update-ref refs/tags/x` -> `commit`. Control that the measurement
discriminates on real tags: pre-polyrepo-archive is `tag`, v7.7.2 is `commit`.

Also noted: ~/.gitconfig has tag.gpgsign=true, which makes a bare `git tag`
fail rather than cut a lightweight one -- but the probe's -a tag came out
unsigned, so that is an accident, not the enforcement.

check-versions before and after: 12 plugins, 11 OK, 1 WARN, 0 ERROR
(unchanged -- the WARN is repo-mailbox 0.26.0, a separate order).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FLwHvGkH2kV4XLjUHorhLu
2026-08-17 13:35:01 +02:00
01161f092f chore(catalog): release repo-mailbox v0.25.0
Completes the two-repo release: v0.25.0 was tagged + pushed in the plugin
repo, and the catalog ref moves v0.24.0 -> v0.25.0. Before this, plugin.json
said 0.25.0 while the catalog still pinned v0.24.0 — a public unreleased bump
(check-versions WARN), leaving `board.sh --dispatch` written but uninstallable.

Stat line mirrored to the plugin's own badges at v0.25.0 (release-plugin.mjs
bumps ref + label but not stats, so the post-write gate ERRORed on both axes):
skills 3 -> 4 and selftest checks 433 -> 529. Both measured with
check-versions' own extractStatBadges/extractCatalogStats against
`git show v0.25.0:README.md`, with config-audit as a known-positive control;
skills=4 cross-checked against skills/*/SKILL.md at the tag. The new
`dispatch` bullet keeps the block's one-bullet-per-skill pattern intact.

check-versions: 12 OK, 0 WARN, 0 ERROR (was 11 OK, 1 WARN).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A4uewAg3byV6Z3TuaQfR7G
2026-08-16 21:41:55 +02:00
c475182761 docs(catalog): add SECURITY.md
Publishes a vulnerability disclosure policy at the repo root, per the
AAA+ program's C-axis (trust) sweep. Contact address and response
timeline per operator decision; supported-versions section reflects
that the catalog has no versioned release cycle and updates directly
on main.
2026-08-16 21:14:34 +02:00
564385b198 docs(catalog): mark repo-standard checks-count discrepancy resolved
v0.11.2's own CHANGELOG shows the plugin removed its stale prose counts
rather than correcting them, making its README table (20 rows, verified
unchanged since v0.11.1) canonical — the catalog's README already reads
"20 checks" in both places. No further ask to repo-standard needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBKjXtfgyV1YsFxbLcPpMs
2026-08-15 18:29:29 +02:00
2c12e7c060 chore(catalog): bump repo-mailbox v0.23.0 -> v0.24.0
repo-mailbox v0.24.0 — release. Catalog ref now pins the v0.24.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 22:24:58 +02:00
3f5afeeb99 docs(catalog): correct repo-standard stat mirror — 20 checks, 245 tests
repo-standard removed both numbers from its own README prose to stop an
ungated figure going stale again, and gave a corrected unit for checks
(check-table rows, not exported functions). Self-measured at the pinned
v0.11.2 tag per the catalog's own badge-less-axis convention: checks =
table rows (README.md:68-87, 20 — their own grep recipe overcounts by
hitting a second table in the file), tests = `node --test` (245/245).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPstjCdfFm5dUWFC3pFTNE
2026-08-14 20:32:29 +02:00
be6e80f7bc chore(catalog): bump repo-standard v0.11.1 -> v0.11.2
repo-standard v0.11.2 — release. Catalog ref now pins the v0.11.2 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 20:19:38 +02:00
9c0738cbeb chore(catalog): bump repo-mailbox v0.22.0 -> v0.23.0
Post-write gate caught the selftest-check stat line stale again (412 -> 433,
read from the plugin's own badge at v0.23.0). Tag minted+pushed on bf11cbf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RQPdPvk1pnB1MNdsvUanFD
2026-08-14 19:48:50 +02:00
c741adaaa8 chore(catalog): bump repo-mailbox v0.21.0 -> v0.22.0
Tag v0.22.0 created and pushed to repo-mailbox. Also corrects the
catalog's stale selftest-check count for repo-mailbox (402 -> 412)
to match the plugin's own badge, caught by the post-write gate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QugnZfg8Jpi7tHNmoT7Uqp
2026-08-13 21:18:18 +02:00
aff807c101 docs(catalog): re-measure badge coverage at every pinned ref — 24 gated, 18 ungated
The 2026-08-04 count (27 gated / 15 ungated across 7 plugins) was correct and is
not overturned: re-running the measurement against catalog commit c7fbbd3
reproduces it exactly. Coverage fell to 24/18 across 8 because three axes lost
their badge when a ref moved — okr v1.8.2 -> v1.10.0 dropped agents-7 and
hooks-3, graceful-handoff v3.1.0 -> v3.2.1 dropped tests-30. 27 - 3 = 24.

All 18 ungated values are now measured at their refs in the same pass rather
than inherited: 16 exact, 1 correct-but-split (voyage's 6 commands + 1 helper is
the plugin's own split, 7 files), 1 defect (repo-standard states 170 tests,
measures 243 — the catalog faithfully mirrors the plugin's own stale README, so
the fix belongs in repo-standard first). repo-standard's checks axis stays open:
catalog bullet says twelve, stat line says 14, plugin README says twelve,
measurement finds 19 exported check functions — ask, do not guess.

Coverage is now read by importing check-versions.mjs's own extractStatBadges and
extractCatalogStats rather than a second parser that could drift from the gate.

Also records two measurement defects found in the pass itself: git ls-tree quotes
non-ASCII paths, which silently dropped okr's two Norwegian-named commands and
read as a defect in okr; and a zsh loop whose set -- did not word-split reported
13/13 MATCH by comparing empty strings.

No ref, tag or stat line was touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011wF4LZtSrfBFZr2h5ZPVHu
2026-08-13 21:06:55 +02:00
e17229fb78 docs(catalog): count prompt-hook entries on the badge-less hooks axis
The counting rule said "hook COMMAND entries". It was calibrated against
plugins that predate prompt-hooks, so it was never a ruling on them. A prompt
entry fires on the same event and does the same job, so it counts.

Re-measured every pinned ref before rewriting the rule, since restating an old
measurement in new words is itself a claim: every plugin that badges hooks and
ships a hooks.json has entries equal to command-entries, so the two phrasings
agree across the whole badged set. okr is the only plugin with a non-command
entry, and it does not badge the axis.

Also records which plugins badge the agents axis and which two do not, so a
future session does not treat an unmeasured number as gated or a gated one as
unmeasured.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141o7P9gFCDxURKyc2cW7mc
2026-08-13 20:40:00 +02:00
d0d5d70208 docs(catalog): show the test command in a fenced block
A visitor could see that this repository has tests but not how to run them.
Adds a Tests section naming the command, and states that the migration test
files under docs/ are an archive rather than part of the suite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0141o7P9gFCDxURKyc2cW7mc
2026-08-13 20:25:20 +02:00
a51add7b59 chore(catalog): bump repo-standard v0.11.0 -> v0.11.1
repo-standard v0.11.1 — release. Catalog ref now pins the v0.11.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-13 10:54:45 +02:00
069f7e0e92 chore(catalog): bump repo-standard v0.10.1 -> v0.11.0
repo-standard v0.11.0 — release. Catalog ref now pins the v0.11.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-13 10:52:17 +02:00
a7dff0fcc2 chore(catalog): bump repo-standard v0.10.0 -> v0.10.1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwZeAZ8cHmGZofM9dryuT9
2026-08-12 23:28:45 +02:00
65764bae95 chore(catalog): bump repo-standard v0.9.0 -> v0.10.0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwZeAZ8cHmGZofM9dryuT9
2026-08-12 23:22:24 +02:00