Commit graph

1,033 commits

Author SHA1 Message Date
0231c2fb6e
docs(migration): replace links to now-private repos with placeholders
repo-standard 7a20866 (LINK-PRIVATE) flagged two historical links that a
stranger can no longer open: brief.md:150 (open/linkedin-studio, an example
entry shape) and RUNBOOK.md:51 (open/graceful-handoff). The brief example
now uses <plugin>, matching the open/<plugin> layout above it; the runbook
command keeps the repo name with an <org> placeholder and a historical note.
Engine on the catalog: WARN -> OK. check-public-links: 0 hits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 09:29:08 +01:00
8e1c43cd97
docs(catalog): match README opening to forge description; annotate private runbook link
README.md:3 now equals the forge description byte for byte (repo-standard
README-DESC demands equality). RUNBOOK.md:51 is a historical step pointing
at open/graceful-handoff, which has left open/ (anon 404); annotated in
place rather than rewritten. Both from org-ops census 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 17:26:49 +01:00
62b46f79a4
fix(release): quote $HOME, not ~, in the push-approval token command
`~` inside double quotes is not expanded, so the documented command's
touch targeted a literal ./~/... path and failed; the token never reached
$HOME and the gate kept refusing. Comment-only in release-plugin.mjs
(the script's own error message already printed the right path); the same
line in CLAUDE.md is fixed too. Reported by voyage (release drill 08.10).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 17:26:48 +01:00
8ee416ed34
chore(catalog): bump voyage v6.4.0 -> v6.5.0
voyage v6.5.0 — release. Catalog ref now pins the v6.5.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-18 20:46:06 +02:00
c123d161e7
chore(catalog): bump voyage v6.3.1 -> v6.4.0
voyage v6.4.0 — release. Catalog ref now pins the v6.4.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-17 00:25:10 +02:00
1343cb310d
chore(catalog): bump voyage v6.3.0 -> v6.3.1
voyage v6.3.1 — release. Catalog ref now pins the v6.3.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-11 18:05:59 +02:00
19530d003e
chore(catalog): bump voyage v6.2.0 -> v6.3.0
voyage v6.3.0 — release. Catalog ref now pins the v6.3.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-11 08:33:09 +02:00
c7dac529e4
chore(catalog): bump voyage v6.1.1 -> v6.2.0
voyage v6.2.0 — release. Catalog ref now pins the v6.2.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-08 20:53:33 +02:00
4549500217
chore(catalog): keep only Voyage in the open catalog
Operator decision 2026-10-06: until further notice only Voyage stays in
the open/ organisation; repositories and plugins are added back when
they are good enough. The eight other plugins move to the operator's
private marketplace. Manifest, README and PUBLIC_REPOS changed in the
same commit, as the public-link gate requires.

check-public-links: 0 hits; check-versions, check-retired-refs,
check-nav-golden, check-okf-parity exit 0; 233 of 233 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:23:34 +02:00
c5d90b5cc2
chore(catalog): remove llm-security and config-audit from the catalog
Both plugins move to the operator's private marketplace (decision
2026-10-06): their threat and Claude Code knowledge is out of date and
they will not be developed further in the open. Removed from the
manifest, the README and PUBLIC_REPOS in the same commit, as the
public-link gate requires. The catalog now lists 9 plugins.

check-public-links: 0 hits; check-versions, check-retired-refs,
check-nav-golden exit 0 before and after; 233 of 233 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 09:29:47 +02:00
c4af905f89
chore(catalog): bump voyage v6.1.0 -> v6.1.1
voyage v6.1.1 — release. Catalog ref now pins the v6.1.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-05 18:43:31 +02:00
910c19834d
chore(catalog): bump voyage v6.0.0 -> v6.1.0
voyage v6.1.0 — release. Catalog ref now pins the v6.1.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-05 12:43:32 +02:00
b072d63a08
chore(catalog): bump voyage v5.11.1 -> v6.0.0
voyage 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-10-02 19:54:26 +02:00
a98cb503ad
chore(catalog): bump repo-mailbox v0.36.1 -> v0.37.0
repo-mailbox v0.37.0 — release. Catalog ref now pins the v0.37.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-27 13:40:02 +02:00
b595747321
chore(catalog): correct repo-mailbox stat line (1006 -> 1187 selftest checks)
Catalog stat line was stale against repo-mailbox main (deb3707, 0.37.0):
badge reads selftest_checks-1187, catalog said 1006. Hooks/skills/CLI
scripts already matched (1/4/8) so only the selftest count changes.
This unblocks scripts/release-plugin.mjs repo-mailbox --create-tag,
whose pre-flight compares the catalog line against the target
version's README (tag missing, falls back to worktree = 1187).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 13:35:40 +02:00
859b6add13
chore(catalog): bump repo-mailbox v0.36.0 -> v0.36.1
repo-mailbox v0.36.1 — release. Catalog ref now pins the v0.36.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 17:07:10 +02:00
d1fb0a4956
chore(catalog): bump ms-ai-architect v1.18.1 -> v1.18.2
ms-ai-architect v1.18.2 — release. Catalog ref now pins the v1.18.2 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 17:02:39 +02:00
b5be3c7fdc
chore(catalog): bump ms-ai-architect v1.18.0 -> v1.18.1
ms-ai-architect v1.18.1 — release. Catalog ref now pins the v1.18.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 14:25:33 +02:00
d0bc696da3
chore(catalog): remove plugins that are no longer published
Remove claude-design from the marketplace manifest and its catalog
README entry, and remove the playground-design-system entry from the
README. The catalog now lists 11 plugins.

Add scripts/check-public-links.mjs: fails when README.md or the
manifest links to an open/<name> repository missing from a tracked
PUBLIC_REPOS list. Chosen over the local retired-terms list because
that gate scans every tracked file, and historical docs plus
CONVENTIONS.md (which keep naming these repos on purpose) would hold
it red; a live visibility check could not be red before the repos
change visibility. Red on 5ba4a7a (6 hits), green after (0 of 36).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:18:19 +02:00
5ba4a7a735
chore(catalog): bump okr v1.10.0 -> v1.10.1
okr v1.10.1 — release. Catalog ref now pins the v1.10.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 13:58:08 +02:00
6f5a7c0a71
chore(catalog): bump voyage v5.11.0 -> v5.11.1
voyage v5.11.1 — release. Catalog ref now pins the v5.11.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 13:47:56 +02:00
fdee2f110c
chore(catalog): bump repo-mailbox v0.35.0 -> v0.36.0
repo-mailbox v0.36.0 — release. Catalog ref now pins the v0.36.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 13:47:38 +02:00
59784410a2
docs(catalog): repo-mailbox stat line 978 -> 1006 selftest checks
Mirrors repo-mailbox's own badge (selftest_checks-1006 at 4fd1955, the
0.36.0 release commit). release-plugin.mjs refused the 0.36.0 dry-run on
the stale stat line before tagging; it now passes that pre-flight and
stops only at the not-yet-minted v0.36.0 tag.

check-versions shows 1 ERROR on repo-mailbox until the release moves the
ref: the gate reads the badge at the pinned v0.35.0 (978). That finding
is kind=stat for the plugin being released, which preflightErrors()
exempts - measured: preflightErrors(gate, 'repo-mailbox') -> [].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 13:47:32 +02:00
4ecc6e2b6a
chore(scripts): remove dead references to a retired repository
Two comments in build-rollup-register.{mjs,test.mjs} used a since-deleted
repository as the example of a nested same-name git repo. Replaced with the
invented `example-repo/example-repo`; the test fixture (`outer/outer`) and
what it proves are unchanged.

Adds scripts/check-retired-refs.mjs (+ test): fails when a tracked text
file names a retired term in its content or path. The term list is
local-only (scripts/retired-terms.local.md, ignored via *.local.md) and
never tracked; a missing or empty list reports NOT CHECKED (exit 2), and
the repo-level test skips with that reason instead of passing silently.
Named exemption list, empty. Chosen *.local.md because the existing ignore
rule already covers it, so .gitignore is untouched.

Red on 69fb250 (112 files, 2 hits, exit 1) -> green (114 files, 0 hits).
Suite 217 -> 227 tests, 211 -> 221 pass; the same 6 check-okf-parity
failures before and after, caused by the worktree path breaking its
sibling-repo lookup (9/9 green in the main checkout). check-versions:
12/12 OK, 0 ERROR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 13:47:32 +02:00
74c27d0e8e
chore(catalog): bump llm-security v8.1.2 -> v8.1.3
llm-security v8.1.3 — release. Catalog ref now pins the v8.1.3 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 12:37:41 +02:00
08aca9512f
chore(catalog): bump voyage v5.10.1 -> v5.11.0
voyage v5.11.0 — release. Catalog ref now pins the v5.11.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 12:33:50 +02:00
69fb25037c
chore(catalog): bump llm-security v8.1.1 -> v8.1.2
llm-security v8.1.2 — release. Catalog ref now pins the v8.1.2 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 08:18:03 +02:00
2794e2fca8
chore(catalog): bump llm-security v8.1.0 -> v8.1.1
llm-security v8.1.1 — release. Catalog ref now pins the v8.1.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-22 21:16:48 +02:00
bb43a20376
fix(release): NOOP no longer drops a pending commit/push, token scope documented accurately
Three defects in release-plugin.mjs measured live by llm-security S4 during the
v8.1.0 release (order 20260922T185613Z-5930828122-from-.claude):

1. The header/token comments claimed the tag-push and catalog-push "share ONE
   token" without qualifying the scope, which read as spanning a whole release
   however many separate invocations it took. The push-approval token is
   actually scoped to ONE script invocation (createPushGate consumes it as
   soon as that run's first push succeeds) — chosen over making the token
   survive across separate processes, since a persisted cross-invocation
   authorisation is exactly the kind of standing grant the one-shot design
   exists to avoid. Comments and the operator-facing BLOCKED message now say
   this, and recommend the combined `--create-tag --write --commit --push`
   as the one-token-one-release path.

2. `--write --commit` run after an earlier `--write`-only invocation reported
   NOOP and committed nothing: a fresh process re-reads marketplace.json off
   disk, sees the target ref already written (but uncommitted) by the prior
   run, and planRelease — which has no git access — cannot tell that apart
   from an already-released catalog.

3. NOOP returned before ever checking --push, so a pending write could also
   never be pushed by a follow-up invocation.

Fixed by pendingCatalogChanges(), which checks the working tree for the
plugin's catalog files; a NOOP verdict with --commit requested against a
dirty tree now finishes the release (commit, push, Forgejo release object)
via a shared finishPublish() instead of silently reporting "nothing to do".
A genuinely clean NOOP is unchanged (still exits early, still never touches
the push gate).

Also isolates release-plugin.test.mjs's temp git fixtures from the
machine-global pre-push hook (installed today, order 20260918T004628Z, live
during this session) via a repo-local core.hooksPath override — those tests
exercise this script's own token/NOOP/push logic, not that unrelated global
CHANGELOG policy, and R-FJ1 specifically needs the tag-message fallback path
a real CHANGELOG.md would short-circuit.

TDD: BUG 2 and BUG 3 were written RED against the unmodified script (real
git temp repos, two-invocation traces reproducing the measured scenario)
before the fix; full suite 217/217, check-versions 0 ERROR (1 pre-existing
WARN on llm-security's in-flight, unrelated v8.1.1 bump).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:13:07 +02:00
1fd3743f46
chore(catalog): bump llm-security v8.0.0 -> v8.1.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-22 20:38:02 +02:00
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