Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 25f89819dd021ccc071f58f336a006d79d6fb419
parent 1bf60f04b18157b893871f6f4a74b6623ba1cf81
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 26 Sep 2026 18:50:57 -0400

plans: slice P — cut a release from the CLI (one controller; archilyzer release cut/show locally, pnpm ops cut-release through /api/ops/cut-release; the /sites form becomes an adapter); slice N's cookies-mode repeat on main 5/5

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Aplans/cut-release-cli.md | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mplans/release-10.md | 4++--
2 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/plans/cut-release-cli.md b/plans/cut-release-cli.md @@ -0,0 +1,88 @@ +# Cut a release from the CLI (release 10 slice P) + +Written 2026-09-26 (night). Operator: "Are you able to cut releases with the CLI ops? add that ability +if not." Answer today: NO. The only cutter is the `/sites` page's "Release notes" form +(`editor/app/sites/components/CutReleaseForm.tsx` → `editor/app/sites/lib/cutReleaseAction.ts`), and +the runbook's step 0 ("re-cut the release notes first") is a click. Anchors verified on `main` 5f577437. + +## What exists (verified) + +- `common/lib/changelog.ts`: `cutRelease(source, version, dateISO)` (:58-88; semver + date checks, + `## [Unreleased]` → `## [<v>] - <date>`, refuses when nothing is pending), `getLatestReleasedVersion` + (:26), `suggestNextVersion` (:31), `extractUnreleasedSection` (:40), `CutReleaseError`. +- `cutReleaseAction.ts` (the server action, "use server"): form fields `workspace` (editor|export), + `version`, `commit`; the dirty-tree guard (`listDirtyPaths`, `common/lib/git.ts:24` — refuses to + commit when anything but the changelog is dirty), `readFile` → `cutRelease(…, todayISO())` → + `writeFileAtomic` → optional `commitPath(root, relPath, "Release <workspace> <version>")` + (`git.ts:36`), then `revalidatePath("/")`, `/changelog`, `/sites`. Paths: + `getPaths().editorChangelogFile` / `.exportChangelogFile`, `monorepoRoot`. Returns + `{ok:true, version, committed} | {ok:false, error}`. Version strings in `package.json` are never + bumped (all 0.1.0) — the changelog heading IS the version; there are no git tags (0). +- Release commits so far are one-line heading edits: `0e0d8f59 Release editor 0.9.0`, + `31798769 Release export 0.9.0`. +- Two CLIs: `pnpm ops` (`scripts/archilyzer-ops.mjs`, plain node, HTTP-only: `ACTIONS` :88-110 → + `POST /api/ops/<action>` with `Bearer WORKER_TOKEN`, usage :277; tests `archilyzer-ops.test.mjs` + :15-45 pin "an action becomes a POST to its route" and the refused-unknown-action list) and + `archilyzer` (`common/bin/archilyzer.ts`, a table of local tsx verbs over `_cli.ts`; tests + `_cli.test.ts`; e.g. `index`, `compose:site`, `sync tick`, `settings-example`). +- Ops API routes: `editor/app/api/ops/<action>/route.ts` on `ops(request, allowedKeys, handler)` + from `_lib.ts` (worker-token auth, JSON body, `OpsInputError` → 400, `optString/optBool/reqSlug`, + `actionResponse`); `refresh-report/route.ts` is the model for a synchronous (non-job) action. +- e2e: `editor/e2e/cut-release.spec.ts` (:53, :74, :95) drives the form against the fixture's + changelog copies. Ops routes' e2e precedent: grep `api/ops` in `editor/e2e/*.spec.ts`. + +## Decisions (made) + +1. **One writer.** New `common/controller/cutRelease.ts`: `cutReleaseForWorkspace({workspace, + version, commit, date?})` = the body of `cutReleaseAction` verbatim (guard, read, cut, atomic + write, commit), returning `{ok:true, workspace, version, committed, commitSha?, heading} | + {ok:false, workspace, error}`. `version: "next"` resolves through + `suggestNextVersion(getLatestReleasedVersion(source))` (patch bump) — `"next-minor"` bumps the + minor. `cutReleaseAction` becomes a thin FormData adapter over it (keeps `revalidatePath`; the + form's fields, labels and `cut-release.spec.ts` unchanged). `workspace: "all"` (CLI/API only) = + editor then export with the SAME version, two commits in today's message form; stops at the first + failure and reports what was done. +2. **Local verb, the primary path**: `archilyzer release cut <editor|export|all> <version|next|next-minor> + [--commit] [--date YYYY-MM-DD]` in the `archilyzer.ts` table; prints one line per workspace + (`editor: ## [0.10.0] - 2026-09-26 (committed 1a2b3c4d)`), exit 1 on any failure. Plus + `archilyzer release show [editor|export]`: the latest released version, its date, and how many + bullets are pending under `[Unreleased]` — the runbook's step-0 check. Works with NO editor running + (this rollout's step 0 precedes step 1's restart, and the live editor is a pre-brand build). +3. **Ops verb, the remote path**: `pnpm ops cut-release --json '{"workspace":"editor","version":"next", + "commit":true}'` → new `editor/app/api/ops/cut-release/route.ts` (synchronous, `ops()` + + `OpsInputError` for a bad workspace/version, `actionResponse`-style body `{ok, results:[…]}`), + `ACTIONS` + usage gain `cut-release` (usage says what the body takes and that `all` cuts both). + Same controller. Note in usage: the route exists only on an editor running this release or later. +4. No version bump in `package.json`, no git tag (neither is a convention here — say so in the record). +5. `--date` is for a re-cut of an already-dated release only; default today (local time, as the + action does). + +## Implementation (one Opus slice, branch `cli/cut-release`, its own worktree) + +1. Controller + `cutRelease.test.ts` (temp git repo via `git init`/`commit` in a temp dir: cut → + heading + commit message; `next` → patch bump of the latest heading; `next-minor`; nothing pending → + error; dirty tree with `commit: true` → refused naming the file; `all` stops at the first failure + and reports the first as done; `--date` used verbatim; NEVER touches the real repo — every test + passes an explicit root). +2. `cutReleaseAction.ts` → adapter; `cut-release.spec.ts` must pass unchanged. +3. `archilyzer.ts` verbs + `_cli.test.ts` cases (parse, usage listing). +4. `/api/ops/cut-release` + `ACTIONS` + usage + `archilyzer-ops.test.mjs` (+1: the action posts to + its route; the unknown-action list includes it) + one editor e2e in the ops style (POST with the + worker token against the fixture changelogs → 200 with the heading; a bad workspace → 400). +5. Docs: `README.md`/`AGENTS.md` only where they mention cutting a release (grep "Cut release", + "re-cut"); the runbook is the parent's. Record `### Slice P, as shipped — cut a release from the + CLI (2026-09-26)` in `plans/release-10.md` before `## Rollout`; one `[Unreleased]` bullet in + `editor/CHANGELOG.md`. + +## Gates (worktree root) + +tsc; common tests (1,987 baseline on this main → new count); editor unit (85); `pnpm run test:scripts` +(173 + 1 → new count); mcp 269 unchanged; `pnpm --filter editor exec next build`; editor e2e detached + +queued: `cut-release.spec.ts` + the new ops e2e + every spec that greps `api/ops` (list them). +Numbers tool: none. + +## Rollout (parent) + +The runbook's step 0 becomes `pnpm --filter yt-dlp-transcript-common exec tsx bin/archilyzer.ts +release show` then `… release cut all next --commit` (or an explicit version) from the primary, before +step 1's restart. Prove `pnpm ops cut-release` after the restart on a throwaway: `release show` only. diff --git a/plans/release-10.md b/plans/release-10.md @@ -1610,8 +1610,8 @@ every video its confirmation check did not reach; `/jobs` says why a job was can live until the :3001 restart (step 1); then prove: `fetch_clip` `full: true` on `teamrcn/dbnS-cBgStY` (the slice M no-op) → 202 → done with a file under `transcripts/saved-videos/teamrcn/dbnS-cBgStY/`, `transcript.json` mtime unchanged, no `audio.*`, and `data/dbnS-cBgStY/metadata.history.json` with one -entry (its `changed` may be empty). Reviewer's follow-up: run `cookies-mode.spec.ts:241 --repeat-each=5` -on a `main` checkout when the e2e lock is free; if `main` stays green and the branch failed 2 of 4, re-open. +entry (its `changed` may be empty). Reviewer's follow-up DONE: `cookies-mode.spec.ts:241 --repeat-each=5` on merged `main` (5f577437) +→ 5/5 passed in 1.8 min — the branch's 2-of-4 was machine load (7–10 during its run), not slice N. ### Slice M — fetch_clip, merged and proved live (2026-09-26 evening)