Rework Clint frontend updater: manifest-driven updates#648
Merged
Conversation
Replace the linear semver high-water mark with a CI-generated manifest (clint/updates/index.json) as the source of truth for which updates exist and in what order, plus a committed per-project applied-update log (frontend/.clint-applied) as the source of truth for what has been applied. A run pins one immutable SHA, reads the manifest at that SHA, computes pending = manifest - applied-log (set diff), sparse-fetches only the pending folders into a temp dir, applies them in manifest `seq` order as a per-update transaction (recorded on success, scoped restore on failure), and never syncs the updates folder into the working tree. - appliedState.ts: owns the sorted line-list log, gitignored meta sidecar, and an O_EXCL lock; git-history reconcile for a deleted log. - git.ts: resolvePinnedSha + getManifest + addSparsePaths (one pinned clone), listTreeDir drift check; getRemoteFiles pins to the run SHA (fixes content skew); retired working-tree sync of clint/updates. - updateChecker.ts: fetchManifest fails closed; pending via set diff; signals migration when the log is absent. CLI self-update stays semver. - updater.ts: pinned apply loop, requires validation, no-gap prefix picker, per-update recording, one-time migration from the legacy version. - update:index / update:new commands for authoring + manifest generation. - .gitattributes: frontend/.clint-applied merge=union for conflict-free appends. Also fixes three latent bugs: frontend packagePath pointed at a nonexistent file, findAndReplaceInFile dropped plain-string rules, and the changelog reader used the wrong filename casing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Runs on PRs/pushes touching clint/updates or clint/src: builds the CLI, runs `update:index` (which fails on missing update.json/CHANGELOG.md, id != folder, or invalid JSON), then enforces that the committed clint/updates/index.json is current by diffing the regenerated manifest's `updates` array (ignoring the volatile generatedAt timestamp). No bot writes or merge queue required: concurrent PRs that both touch updates resolve as an ordinary index.json merge conflict, fixed by re-running the generator. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
indexGitUrl and updateRef now resolve against a dedicated clint-updates publish branch instead of master, so consumers fetch the manifest and update content from a channel they never carry in their own working tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On pushes to develop that touch clint/updates or frontend, force-updates the clint-updates branch to develop's commit, keeping the channel consumers fetch (manifest + update folders + frontend content) an exact snapshot of develop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrites updates.md to match the new updater: manifest (index.json on the clint-updates channel) + committed applied log (frontend/.clint-applied) instead of a semver version, date-slug update folders, no-gap prefix selection, per-update transactions, and migration for legacy projects. Adds a full "Authoring a frontend change" guide (update:new -> fill update.json/CHANGELOG -> update:index -> PR to develop -> publish to clint-updates), stressing that a frontend change only reaches existing projects when it ships with an update folder, plus idempotent findAndReplace guidance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Documents the new frontend config fields (indexGitUrl, updateRef, appliedStatePath), corrects packagePath to ../frontend/package.json, marks packageGitUrl/version as legacy (migration-only), and replaces the version tracking section with applied-log-based state tracking. Sample config now matches the shipped cli.config.json (master + clint-updates channel). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Guides analyzing a frontend diff and producing update.json (modify + findAndReplace) and CHANGELOG.md, then regenerating the manifest. Encodes the exclude-vs-modify classification, idempotent findAndReplace rules, record-only updates, and the never-hand-edit-index.json rule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New AuthorFlow wraps update:new (scaffold) and update:index (regenerate manifest) so maintainers can author updates from the yarn start menu instead of only via `node dist/cli.js ...`. The argv commands stay for CI/scripting. Docs note both paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The changelog HTML (opened after an update) now splits each update's "Manual intervention" section into a highlighted callout, adds a summary banner at the top linking to every update that needs manual work, and echoes a manual-intervention summary to the terminal. Styling uses inline CSS so it doesn't depend on the purged Tailwind build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuilds the changelog HTML around the Statik brand tokens (Jost, yellow accent, soft card shadow, paper background) with a sticky header, collapsible per-update cards (native <details>), and an index/table-of-contents shown when multiple updates are applied. The index and entry headers flag updates that need manual intervention, and a top alert links straight to each manual section. showChangelog now provides the index/count/manual data. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds components/report.css (yellow accent bar + sticky branded header) to the Clint frontend CSS and switches the index, a11y, HTML, links, CO2, and diff report headers to it, so every report matches the redesigned changelog. Bodies and interactions are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switches the report and changelog headers to a 3-column grid (logo left, title centered, meta right) so the title sits in the middle within the container bounds; long titles ellipsize via a min(0,auto) middle column. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reverts the centered header: logo + title are left-aligned again, and the header inner now uses the shared .container so it shares the body's left/right bounds. Applied to the report chrome and the changelog header. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds reusable report content components (stat toolbar, cards, issue rows, pills, code blocks) to report.css and rebuilds the a11y report around them: stats toolbar, per-URL cards with a chevron toggle, red issue pills, copy button + selector chip, and a dark context block. All interactive hooks (toggle, retest, copy) are preserved. a11y renderer now passes urlCount and totalErrors for the stats. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuilds the remaining report templates on the shared report-* components: - HTML: stats toolbar + per-URL cards with rule/line/column meta - Links: broken/valid pills, broken+ok link rows with status badges - CO2: green/not-green alert banner + non-collapsible metric cards with a rating dot - Diff: cards wrapping the image-compare + diff-map toggle (script preserved) - Index landing: project cards with a grid of pass/fail result tiles Extends report.css with alert, metric, rating, link-row, status, meta-line, diff and result-tile components. html/links/co2 renderers now pass stat totals. All interactive hooks (toggle, retest, copy, image-compare) preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
janhenckens
approved these changes
Jun 22, 2026
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Reworks the Clint frontend updater from a linear semver high-water mark to a manifest-driven, sync-then-execute model, designed by a multi-agent council analysis of the problem.
Why: We fix random frontend issues through PRs, so a single linear
frontend/package.jsonversion no longer fits. String comparison misorders versions, a hotfix can't land before an in-flight refactor, a scalar can't merge across branches, and state was written once at the end (a mid-batch crash left no record).How it works
clint/updates/index.json, CI-generated) is the source of truth for what updates exist and in what order — each entry has an explicitseq(never derived from the folder name),id(date-slug),requires, andlegacyVersion.frontend/.clint-applied, committed, sorted line list withmerge=union) is the source of truth for what this project has applied.pending = manifest − applied-log, sparse-fetches only the pending folders into a temp dir (never into the working tree), applies them inseqorder as per-update transactions (recorded on success, scoped restore on failure), and shows a changelog.versionfield (dry-run + confirm) for projects predating this system.Authoring
clint update:new "<title>"scaffolds a<YYYYMMDD>-<slug>folder +update.json+CHANGELOG.md.clint update:indexgenerates/validatesindex.json(intended to run in CI on merge).Latent bugs fixed along the way
frontend.packagePathpointed at../package.json, which doesn't exist (real file is../frontend/package.json).findAndReplaceInFiledropped every non-/.../grule (the.map()returnedundefined).changelog.mdwhile files areCHANGELOG.md→ blank changelogs.Verification
yarn build-clibuilds clean;tsc --noEmitshows no new errors (only pre-existing.default/html-validate noise the whole codebase has).update:indexandupdate:newexercised end-to-end (including accent/symbol slugging and folder/manifest validation).Follow-ups (need maintainer decisions — not in this PR)
indexGitUrl/updateRefcurrently point atmaster. Recommendation was a dedicated channel + tagged releases. Untilindex.jsonis on the fetched ref, a live frontend check fails closed by design.update:index+ a serialized merge queue soseqstays unique/monotonic.frontend/package.jsonversionleft frozen (migration reads it).🤖 Generated with Claude Code