Skip to content

Promote next → main — v0.2.0 stable (NERV theme, marketing site, new icon, docs)#14

Merged
ashproto merged 87 commits into
mainfrom
next
Jul 16, 2026
Merged

Promote next → main — v0.2.0 stable (NERV theme, marketing site, new icon, docs)#14
ashproto merged 87 commits into
mainfrom
next

Conversation

@ashproto

Copy link
Copy Markdown
Owner

Promotion of nextmain — the first stable v0.2.0 release and the public launch of the marketing site.

What's being promoted (85 commits since the last promotion):

  • NERV theme — Classic ↔ NERV toggle (Settings → Appearance), 6 accent schemes, full HUD, boot + scanline motion, materialize boot, and the launch-flash (FOUC) fixes.
  • New app icon — hexagon enclosing the tri-color commit graph.
  • Marketing website (website/) — NERV-themed landing page (git-it.app), incl. the OP // THEME panel.
  • Docs — post-ship sweep (README/CLAUDE/DESIGN), site-planning archive, path_setup comment fix.

⚠️ Merging this does two things:

  1. Triggers deploy-pages.yml → publishes the site to git-it.app (DNS + HTTPS already configured ✅).
  2. Triggers release.yml on main → builds/signs/notarizes stable v0.2.0releases/latest (activates the stable updater channel + makes the site's Download button work). next already carries the release.yml path-fix, so the build will succeed.

guard-main-source passes automatically (promotion from this repo's next).

Waiting on: Codex review 👍, and the dependabot vite bump (#13) landing on next first.

🤖 Generated with Claude Code

ashproto and others added 30 commits July 6, 2026 16:07
chore: sync next up to main (README polish)
rewrite_history and check_prerequisites now take a filter_repo_argv prefix
(e.g. ["python3", <bundled script>]) instead of hardcoding
Command::new("git-filter-repo"). Extract a pure build_filter_repo_argv
helper (unit-tested) and drop the brew-install hint from the spawn-error
message. PrerequisiteCheck gains python3/python3_version, and the check now
probes git + python3 + the bundled script.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ommand

Add filter_repo::filter_repo_argv resolving the bundled script (resource dir
in prod, CARGO_MANIFEST_DIR source tree under tauri dev) as
["python3", <abs path>]. Wire it into check_prerequisites and rewrite_history,
ship resources/git-filter-repo/* via bundle.resources, and add an
install_command_line_tools command running xcode-select --install. Includes an
integration test that drives the real bundled script through rewrite_history and
asserts a commit date changed (skips when python3 is absent).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
surface git/python3 as the real prerequisites and drop the brew-install
guidance now that git-filter-repo ships bundled and runs on host python3.

- types.ts: add python3/python3Version to PrerequisiteCheck
- api.ts: bind install_command_line_tools command
- PrereqBanner.svelte: ok = git && python3; replace the brew block with an
  "Install Command Line Tools" button (xcode-select --install) that disables
  while running and shows the returned status; add a no-button diagnostic when
  python3 is present but the bundled script fails to run
- README.md + CLAUDE.md: prerequisites are git + python3 from the Xcode Command
  Line Tools; git-filter-repo is bundled, not a PATH binary

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat: bundle git-filter-repo + one-click prerequisite install
fix(ci): use workspace-root target dir for macos release artifacts
fix(ci): clean up release-run annotations (changelog 413, node20, macos-latest)
feat: git-it.app marketing landing site
fix: current-branch detection when a same-named tag shadows the branch
Implementation design for the user-toggleable NERV theme (Classic/NERV) per
DESIGN.md. Hardened by a 5-lens adversarial review against the codebase:
phased execution (spike -> token theme -> HUD), new font/radius/on-accent/diff
token families, corrected no-FOUC persistence (no $effect), pure laneColor with
store-side palette selection, and reframed acceptance criteria.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…task)

Phase 0 spike -> Phase A token theme (colors/type/shape) -> Phase B HUD.
Exact file/line anchors, code, and green-gate/QA steps per task. Corrects the
spec where code-tracing showed the HEAD ring is already var(--accent) and all
graph colors route through the two store colorFor* methods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ashproto and others added 27 commits July 8, 2026 03:22
Add B3-style corner brackets to .menu (ContextMenu.svelte, covers
.submenu too) in nerv.css, and gated entrance animations for .menu
(140ms fade+scale) and .dialog (180ms fade+scale) in nerv-motion.css.
Three regressions from the motion-polish round, all verified fixed in the
browser (both themes) with the type gate + 288 tests green.

Right-click: `:root[data-theme="nerv"] .menu { position: relative }` out-specified
ContextMenu.svelte's component-scoped `position: fixed`, dropping the popover into
document flow (it landed bottom-right and shoved panels around). Dropped the
override entirely — `fixed`/`absolute` are already positioned, so the corner-bracket
::after anchors fine without it.

Boot: pulseBootReveal ran at themeMode.ts import time, before SvelteKit mounted any
.panel, so it queried zero panels and the cascade never played. Moved the trigger to
+page.svelte's onMount (panels present, pre-first-paint) via a new appState.bootPulse().

Timeline reveal: replaced the clip-path mask (a wipe over the whole graph) with a
genuine per-element draw — every gutter edge stroke-draws via pathLength/dashoffset,
every dot pops, and every commit row fades in, staggered bottom->top and anchored to
the bottom of the visible CONTENT so a short graph doesn't dwell on empty space. The
reveal state machine and its 5 tests are unchanged (only the visual consumer swapped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the fade boot with a NERV "materialize" sequence, per the user's design:
each panel starts as a tiny accent SQUARE, grows FILLED to the panel footprint, the
fill drains to a full rectangular OUTLINE, then the outline retracts into the four
resting corner brackets (the collapse animation reversed, --b 51%->14px). Staggered
per panel; the square's start scale is measured per panel in JS (--boot-sx/--boot-sy)
so it reads as a real square. Fires on app launch, Classic->NERV toggle, and every
repo switch; a power-on scan band sweeps the viewport. On a repo switch the timeline
reveal is delayed (armReveal(780ms)) so the graph draws AFTER its frame settles.

The old fade boot fired at page-load and was imperceptible; this is a deliberate,
staged "console power-on". Boot now also fires on repo switch (it never did before).

Also fix a real layout jank: the loading bar was a flow element, so it shoved all
content down 3px then snapped back on every nav — now a zero-height overlay.

Adversarial multi-lens review (incl. an independent gpt-5.5 pass) fixes folded in:
- defer the repo-switch pulse until after the Svelte flush (commits panel is
  unmounted behind GraphSkeleton mid-load) so it measures a real square, not a sliver;
- scope bracket draw-on to .panel:not(.collapsed) so collapsed panels (rest at
  --b:51%) don't retract to brackets then snap back;
- guard the boot cleanup timer + gate the launch pulse to !inTauri, so overlapping
  pulses (cold Tauri launch, rapid switches) don't tear down data-boot mid-animation;
- suppress the materialize ::before on the frameless GitHub ReviewBar (.gh .panel).

Verified live in-browser (both themes) and via getAnimations timelines: the full
seed->fill->outline->brackets sequence plays on all 5 panels on launch; collapsed
panels hold their 51% outline; Classic byte-identical; motion-off/reduced-motion
static. Gate: check 0 errors, 288 tests (5 reveal tests intact).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…me lands

The materialize square animated in while the panel box and its content were already
visible, so it read as a red overlay on a loaded panel rather than a panel building
itself. Per the user: nothing visible, THEN the red square, THEN the content.

Now each panel starts as literally nothing — the panel's own background + border fade
in only as the ::before fill drains into the outline (nerv-boot-box, ~46-70%), and the
header + body fade+rise in after the frame settles (nerv-boot-content on `.panel > *`,
which excludes the ::before/::after materialize pseudos so the overlay stays visible
while the real content is held at opacity 0). Both `both`-filled so there's no flash of
content before data-boot is set (onMount's tick()->bootPulse drains as a microtask
before first paint). Collapsed panels also fade their 51% outline in with the frame
(nerv-boot-draw-collapsed) instead of showing a static outline during the seed phase.

The repo-switch timeline reveal is pushed to 950ms (was 780) so it draws after the
commits panel's content has faded in (commits is the last-staggered panel).

Verified via WAAPI freeze: at the seed stage every panel is transparent bg + border +
opacity-0 content (only the red square shows); at the content stage the box, brackets
and content are all present. Real launch settles clean. Classic/motion-off unaffected
(same NERV+motion+data-boot gate). Gate: check 0 errors, 288 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On a repo switch the panel content-fade painted the whole commit timeline at rest for
a beat, then nerv-row-in snapped it hidden and redrew it — a visible flash. Root cause
was my previous change delaying `revealing` itself to 950ms (after the content-fade
revealed the body at ~930ms), so the rows rendered at rest first.

Fix: decouple "when the reveal turns on" from "when the draw plays". `revealing` now
arms IMMEDIATELY (rows carry the hidden nerv-row-in from-state from their first paint,
held via `both`, so the timeline is never shown at rest), and instead a base delay
(revealBaseMs, 900ms on a repo switch / 0 on a view switch) is ADDED to every per-row
and per-edge reveal animation-delay so the draw still plays after the frame settles.
The reveal window extends by the same base so the last row doesn't snap.

Threaded revealBaseMs through the store → GraphHistory (revealRowDelay) → GraphGutter
(revealDelay). View-switch path is byte-identical (base 0); the 5 reveal tests still
pass (armReveal's synchronous arm is preserved).

Verified in-browser by simulating a repo switch: the first commit row holds opacity 0
(nerv-row-in) through 850ms — max opacity 0, no rest-flash — then draws 0→1 at
~1000-1400ms. View switch confirmed base 0 (firstRowDelay 144ms, immediate). Gate:
check 0 errors, 288 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…refresh

Two P2 findings from the automated PR review:

1. The op spinner kept pulsing in static NERV. StatusBar's base `.spinner` carries
   `animation: pulse …`; the NERV static override only changed border/background, so
   the Classic pulse leaked through when motion was off or prefers-reduced-motion was
   set (the gated nerv-live-blink lives in nerv-motion.css, motion-on only). Added
   `animation: none` to the static override — the more-specific [data-motion=on] rule
   still re-enables the blink when motion is on.

2. The theme/scheme/motion hydrate paths applied the durable Tauri-store value to the
   DOM but never refreshed the localStorage mirror that themeMode.ts reads before
   paint. If localStorage was dropped/stale (the exact case the store exists to
   survive), every launch kept painting the stale/default theme until async hydration
   ran. Now each hydrate writes the accepted value back to its mirror key.

Gate: check 0 errors, 288 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On launch the wrong app background flashed: with NERV saved the transparent glass
showed for a beat, and with Classic saved a solid dark box showed before the glass.
Root cause is paint order — themeMode.ts/tauriMode.ts run at SPA-bundle eval and the
theme background CSS lives in +page.svelte, but SvelteKit's module scripts are
deferred, so the browser paints the empty app.html shell (with no theme resolved)
first.

Fix: a synchronous inline <script> + critical <style> in app.html's <head>, which run
before the first paint (ahead of the deferred bundle). The script mirrors themeMode.ts
(sets data-theme from the gitit.theme.v1 mirror) and tauriMode.ts (sets data-tauri from
the injected Tauri globals); the style paints the correct first-frame background —
transparent by default so the Tauri window's native vibrancy shows (Classic glass), and
solid #0A0C0F for NERV. The bundle's full theme CSS loads and takes over from there.

The inline NERV rule (0,1,0) outranks the bundle's base html,body rule (0,0,2), so NERV
is solid from the first frame regardless of data-tauri timing; Classic stays transparent
(glass) because data-tauri is now set in <head> before the bundle's base --bg can paint.

Verified in-browser: inline block is present and ordered before the module bundle; NERV
first-paint body bg = rgb(10,12,15) solid; Classic has no data-theme and goes transparent
under data-tauri. Gate: check 0 errors, 288 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… the glass flash

The launch glass flash was a native layer below the webview: the window is
transparent + acrylic from tauri.conf.json, so the NSVisualEffect glass is on
screen from the instant the window is created — before WebKit paints its first
frame. The earlier app.html critical-CSS fix only governs what the webview
draws; it can't touch the native window already showing behind it.

Start the window hidden (visible:false) and reveal it once the webview has
painted the resolved theme background:
- +page.svelte reveals it after a composited frame (double rAF), with a 250ms
  setTimeout fallback since WebKit throttles rAF while the window is ordered-out.
- lib.rs force-shows after 1.2s as a backstop so a JS bundle failure can never
  leave the window permanently invisible. show() is idempotent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…iew timer

The visible:false window was appearing sluggishly on launch: WebKit throttles
JS timers AND rAF while a window is ordered-out, so the frontend's double-rAF +
250ms fallback both fired late — the window only became visible when the Rust
1.2s backstop kicked in.

Move the reveal to Tauri's native on_page_load hook, which fires on the real
page-load lifecycle and is immune to webview visibility throttling. The window
shows as soon as the page finishes loading its painted background. Drop the
frontend timer path entirely; keep the setup() thread only as a backstop for
the case where the page never fires its load event.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…utline

Previously the red materialize square's fill just cross-faded to transparent
(background-color accent→transparent), leaving the border as the outline. Make
it more elegant: after the square grows filled to the panel, a panel-bg
rectangle grows from the centre (animated background-size 0→100%) so the fill's
inner edge opens outward, thinning the red into the border-only outline. The
1.5px border is never covered (background-origin is padding-box) so it survives
as the resting outline that the ::after brackets then take over.

Live-verified in the browser via a WAAPI freeze at successive stages: filled
square → centred hole growing → thin outline frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…olor graph)

Replace the old blue/steel checkmark-graph icon with a NERV-console mark
derived from the website logo: a pointy-top hexagon over the #0A0C0F void with
the three tri-color commit nodes (muted / orange HEAD / green) joined by a bone
connector, a warm-tinted interior, a bright top edge, node glow, and a faint
CRT scanline — on the established 944px squircle with a subtle sheen.

icon-source.svg is now the single vector source of truth; the full asset set
(PNGs, icon.icns, icon.ico) is regenerated from it via `tauri icon`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Migrate the planning artifacts from the standalone git-it-site working repo
(now retired — the site itself already lives in website/) so the landing
page's implementation plan, design spec, and early hero mockup live with the
project. Matches the existing docs/superpowers/{plans,specs} convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… checkout in test

Two P2 findings from the Codex review:

- app.html restored data-theme before first paint but not data-scheme. The
  scheme-gated NERV rules ship in the render-blocking bundle CSS, but data-scheme
  was only set by the deferred themeMode.ts — so a non-orange scheme (phosphor,
  steel, …) painted its first frame on the default orange accent, then flipped: a
  scheme-flavoured launch flash. Mirror gitit.scheme.v1 in the inline head script,
  validated against the same set themeMode.ts uses.

- The same-named-tag regression test set up HEAD with
  `checkout -q --end-of-options next`. The marker is pointless there (the operand
  is a hardcoded literal, not user input) and git checkout rejects it on some
  versions. Dropped it; plain `next` DWIMs to the branch and attaches HEAD, which
  the assertion needs. Not the reviewer's suggested `refs/heads/next` — verified
  that DETACHES HEAD and would break the test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Features list and the vibrancy note predate the theme system; add a
Themes bullet (Settings → Appearance, six accent schemes) and note that the
frosted-glass look is Classic-only, so the README matches what PR #9 ships.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(theme): NERV app theme — Classic ↔ NERV toggle (full HUD)
docs: archive git-it landing-page plan, spec, and hero mockup
Adds a seventh feature panel after OP // REMOTE: a self-referential beat —
the site's own console aesthetic is one of the app's two built-in themes
(Classic native-macOS glass ↔ NERV), with the six accent schemes. Matches the
existing op-panel markup + themed inline-SVG illustration convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n-functional swatches

The OP // THEME panel illustrated the app's Appearance settings statically, so
its toggle and six scheme swatches read as live controls but did nothing. Swap
the toggle for a directional swap glyph (Classic ⇄ NERV — a mark, not a control)
and remove the scheme-swatch row entirely; the copy, feature list, and console
footer still state "six accent schemes." Cropped the SVG viewBox so no empty
space is left, and updated the screen-reader description to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(website): add OP // THEME panel (Classic ↔ NERV showcase)
…line

Post-ship documentation sweep — the README and website were already accurate
(theme, schemes, git+python3 prereqs, license); these were the remaining gaps:

- CLAUDE.md: note src/lib/theme/ (the Classic↔NERV theme system) and the
  website/ marketing site in the architecture map, and add the NERV nerv.css
  `:global()` footgun to the gotchas.
- DESIGN.md: the theming work shipped — drop the future tense, mark the "open
  decisions" resolved (lane palettes, NERV Shiki theme, Classic light/dark), and
  record that the app icon shipped (favicon is still stock SvelteKit).
- README.md: point the Distribution section at docs/RELEASING.md (the CI/CD
  release pipeline + in-app updater), which it never mentioned.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ment

The comment said the Homebrew PATH prepend exists so child processes can find
git-filter-repo — but it's bundled now (run via python3, not resolved on PATH).
The real remaining reason is Homebrew-installed tools like `gh` (the GitHub
screen). Corrected the rationale; behavior unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs: refresh docs for the shipped NERV theme, icon, and release pipeline
Recreates dependabot's grouped bump (#13) on next. Its branch was cut from main
(85 commits behind), and an incremental install ERESOLVE'd on the stale lockfile
(old plugin-svelte 5.x + its vite-plugin-svelte-inspector@4 pin), so the lockfile
was regenerated from scratch. The target versions are mutually compatible —
@sveltejs/kit 2.69 supports plugin-svelte 7 + vite 8, and vitest 4 supports vite 8.

Verified the full gate on the new toolchain:
- npm run check — 511 files, 0 errors
- npm test — 288 passed (vitest 4)
- npm run build — succeeds (vite 8 / Rolldown) + adapter-static

Supersedes #13.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chore(deps-dev): bump vite to 8, plugin-svelte to 7, vitest to 4
@ashproto
ashproto merged commit 88b71a5 into main Jul 16, 2026
10 of 11 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31c5b68a20

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +53 to +54
The bundled <code>git-filter-repo</code> script could not be run. Commit-time editing
is disabled.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Actually disable editing when the bundled tool probe fails

When git and python3 are available but the bundled script probe fails, this banner claims commit-time editing is disabled, but the result remains local to this component. ApplyPanel.svelte still enables “Rewrite history” whenever dates are queued and calls rewriteHistory, so the user can confirm the destructive operation and even create a backup before it inevitably fails. Propagate prerequisite availability to the editing controls or avoid claiming the feature is disabled.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant