GitStudio 1.0.1 — repair release - #3
Open
antonarnaudov wants to merge 12 commits into
Open
Conversation
The walkthrough advertised features that silently did nothing. Root causes,
all verified against the code:
Pull (the big one)
- SyncOps.pull ran a bare `git pull`. Since git 2.34 that is a HARD ERROR on
divergent branches when the user has no pull.rebase/pull.ff config
('fatal: Need to specify how to reconcile divergent branches'), and we piped
that stderr straight to the user — so Pull looked like GitStudio was
demanding you go configure a rebase. Worse: the pull aborted, so no merge was
attempted, no conflict was created, and the 3-pane merge editor could never
appear. Strategy is now always explicit (respects the user's config, else
merges). Regression test reproduces the fatal and proves the fix.
Merge editor
- Clicking a conflicted file in GitStudio's OWN Changes view opened a plain
2-way diff; the merge editor's only entry points were VS Code's built-in SCM
view and the editor title bar. Conflicts now open the 3-pane editor.
- Auto-open swallowed every error, so a failed open was indistinguishable from
'the feature doesn't work'. It now reports, and offers the plain diff.
Blame (the 'overlapping 3 other extensions' bug)
- The duplicate-blame check tested inspect().defaultValue instead of the
EFFECTIVE value. git.blame.editorDecoration.enabled defaults to false, so the
built-in inline blame — the one that actually overlaps us — was NEVER
detected, while the only branch that could fire silently rewrote the user's
GLOBAL settings to disable the status-bar item, which overlaps nothing.
Now: effective values, GitLens detection, and we never touch another
extension's settings without an explicit click.
- The annotation was never cleared when focus left an editor, so a split view
kept a stale line annotation — which itself looked like duplicate blame.
History ('explore files and linear history does not work at all')
- Per-file history had NO working surface: it was routed through
registerTimelineProvider, a PROPOSED API absent from stable typings, so the
call threw at activation and was swallowed by a catch{}. Added a real
'GitStudio: Show File History' command.
- Line history re-opened its QuickPick ON TOP of the diff it had just opened,
so the diff was hidden behind the picker and it read as 'nothing happened'.
- Every history/blame/merge command silently returned when there was no ACTIVE
text editor — and the walkthrough IS the active tab, so its buttons did
nothing while the step still ticked green. They now resolve the visible file
(and map a gitstudio-rev: revision back to its working-tree file), and say
something when they truly can't.
- isInside() was duplicated 5x with a forward-slash-only boundary that never
matched a Windows '\' fsPath — killing history, blame and merge on Windows
outright. One shared, separator- and case-tolerant implementation now.
Walkthrough
- Rewritten: every button is a command that actually works from the walkthrough
context, real product screenshots replace the wordmark on every step, and the
AI step now points at the real Connect AI panel (zero-key Copilot/Cursor,
OpenAI-compatible, or a local agent CLI) instead of the old Anthropic-only
key prompt. Its old primary button literally started a destructive interactive
rebase.
- media/shots/** now SHIPS in the vsix: walkthrough media loads from inside the
extension (unlike README images), so excluding it would have rendered a
walkthrough of broken image boxes.
- 'cli' was missing from the gitstudio.ai.provider enum, so anyone connecting a
local agent got a red squiggle in settings.json.
Icons
- The macOS dock icon was full-bleed with zero transparent margin, so macOS
scaled it edge-to-edge into the dock slot and it rendered visibly larger than
every neighbouring app. It now carries Apple's ~10% margin (824px art in a
1024 canvas); Windows/Linux/Marketplace stay full-bleed.
- The dock icon theme-swapped to a white tile in light mode, which washed the
mark's violet lanes and commit nodes out. A dock icon is fixed identity — no
real app does that. One dark squircle, which reads on any dock.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'Staging is confusing af' — it was. Root causes: - The STAGED group was display:none when empty, so with nothing staged the word 'Staged' did not exist in the UI. Users saw one flat list of files and never learned the model. It now always renders, with an empty-state hint. - Then Commit failed with literally 'commit failed — unknown error': git exits 1 and prints 'no changes added to commit' on STDOUT, but we only ever read stderr, which is empty. CommitResult now carries stdout, the message says the real reason, and a nothing-staged commit offers 'Stage All & Commit' instead of blaming the user. - Optimistic staging snapped rows back: a partially-staged file (git status 'MM') is in BOTH lists before git even runs, so the pending op was 'satisfied' by the first state push and the row visibly jumped back to Unstaged. A stage is now only satisfied once the path LEAVES the unstaged/merge lists. - Discard sat in the same slot where Unstage sits in the staged group, and hovered brand-purple exactly like the safe +. Muscle memory from one group destroyed work in the other. It now reads as destructive (red). - On a conflicted file, + was labelled 'Stage file'. Staging a conflict means 'I resolved this' — it now says 'Mark as Resolved' with a check. - Double-click on a row fired click twice AND opened the actions menu, so the diff opened twice with a popover over it. Right-click keeps the menu. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tile Removing the light variant was the wrong correction. macOS can't carry appearance variants inside an .icns, so app.dock.setIcon() at runtime is the only way an Electron app adapts — the original intent was right; the light tile was just badly drawn. It reused the dark mark's colours verbatim: light-violet lanes (#C4ADFF) and near-white node cores (#F3EEFF) on a near-white tile. The three corner nodes straddle the cube's edge, so half of each sat on the pale background and simply vanished — 'the white background hides the logo git lines and circles'. Re-tuned for light: deep brand-violet lanes and rings (#6B5BE6/#8B75F5) that carry on BOTH the pale tile and the slate cube, with white cores bounded by those rings. The theme swap is restored, and both tiles now carry Apple's icon margin so neither renders oversized in the dock. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…read Three things, one root cause. The mark punches its commit nodes out with an SVG <mask> so the dots are true HOLES showing the tile through them — that is what gives them a clean dark centre. I regenerated the icons with cairosvg, which SILENTLY IGNORES the mask: the white node cores (#F3EEFF) painted straight over the holes, so every dot grew a white centre. It also quietly regressed the Marketplace icon, which had been correct since 1.0.0. - Rasterize with headless Chrome instead. It honors <mask>. A generator assert now fails loudly if a renderer ever ignores it again (dark node cores must come out dark). - Make the mark read: the cube was only ~56% of the tile, so it scales up, and the merge-Y lanes — the brand's whole signature — go 21 -> 27 wide and brighter (#DCCFFF -> #AB8FFF on dark). Verified at real dock sizes (48-128px), not just at 1024. - Both tiles are generated from ONE parametric source, so dark and light can no longer drift apart. The activity-bar glyph is untouched — it was already right. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Top-bar mark (the app's logo): rebuilt on the activity-bar glyph's recipe — three translucent isometric FACES for a real 3D body (it was a flat wireframe silhouette before), a soft closing silhouette, and the merge-Y as the bold signature with every node punched through by a mask. Painted in the wordmark's violet->magenta gradient, so the glyph and the logotype read as one brand. Dock tile: the lanes and nodes disappeared at real dock size (48-64px), and the light tile was effectively paper (#FBFAFE) so the mark had nothing to sit on. - lanes 27 -> 33, nodes 28 -> 33 (centre 31 -> 37): the merge-Y is the signature and it now survives at 48px. - the light tile is a darker shade of white (#E7E3F3 -> #D2CCE6, lavender-grey) with a stronger cube silhouette, so the cube and the deep-violet lanes have a ground instead of dissolving into a light dock. Judged on the backdrops each tile actually sits on (a pale dock strip and a dark one) at 48/64/96/128 — not at 1024, which is what hid the problem. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…agree) Two things were wrong. 1. The coloured glyph only landed in the app's top bar. The DOCK tile was still the old design — an opaque slate cube with lanes painted on top. 2. Because that cube was opaque and fixed, the light tile had to flip its lane colours to stay readable, so the two tiles read as two different logos. The dock tile is now built on the same activity-bar glyph recipe as the in-app mark: the cube is translucent tints of ONE brand gradient (never a second hue), closed by a gradient silhouette, with the merge-Y bold on top and every commit node punched through as a real hole. Because the body is tints rather than a fixed slate, the SAME mark works on either ground — only the tile changes: - dark tile: the bright end of the wordmark gradient (#C9B6FF -> #D98BFF) - light tile: the deep end (#7C5FF0 -> #B44FE0) on lavender-grey, because the bright gradient washes out on a pale ground Same structure, same hues, same logo — one dark, one light. Judged at 48-128px on the dock strips each tile actually sits on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d light agree)" This reverts commit 960670a.
…the dock One lane weight cannot serve a 180px welcome hero and a 48px dock slot. Thin lanes read as elegant when large and DISAPPEAR when small; thick lanes stay legible when small and look clumsy when large. Chasing one weight for both is why the icon kept ping-ponging between 'too thick' and 'not visible'. So the same mark now ships in two optical weights, and each surface gets the one it needs: DISPLAY (lane 23) — the welcome hero, the Marketplace listing, the README. DOCK (lane 38) — the macOS dock and Windows taskbar, seen at 32-64px. The dock tile also gets a lighter cube body (#8E8CBC/#454373/#63608F) and brighter lanes (#E6DCFF -> #B79EFF): the old slate sank into the dark tile at 48px and the whole mark went muddy. Judged at the size each surface is ACTUALLY seen at — 180/128px for display, 32/48/64px on real dock strips for the dock — which is the step I kept skipping. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reported breakage — 'no branch shown, can't click branches' — is the
Changes view collapsing to its no-repo state. Root cause is structural: the
view read the branch/file lists from vscode.git's live `repo.state`, and any
throw there propagated to doPushState's bare `catch { hasRepo = false }`,
blanking the whole view (no branch pill, empty menu).
Every layer tested clean in isolation (git-service listRefs/status.read against
the real repo; the webview renders the real branch list with zero errors), so
the failure lives in vscode.git's live state on the user's machine — the one
path not reproducible headlessly. Hardened it so the view can't die there:
- resolveState uses vscode.git ONLY once it has a real HEAD branch; during the
attach window (branch not yet computed) or on ANY throw, it falls through to
our own `git status`, which needs no vscode.git and is already proven.
- collectBranches failures no longer sink the state push — keep the last-known
branch list instead of emptying the menu.
- doPushState keeps hasRepo TRUE when a repo is open but a status read hiccups,
so the view stays interactive instead of flipping to onboarding.
- All three failure points now console.error the real reason, so if anything
DOES still fail it names itself in the exthost log / Output → GitStudio.
Also: earlier review-fix batch (Stage-All-&-Commit, clean-tree staged group,
blame→showFileHistory, branch.<name>.rebase, doCommit re-entrancy) and the
dialog hover/tooltip work (visible hover + wrapping tooltips for clipped
names / long commands).
NOT published — marketplace stays on 1.0.0 until this is confirmed live.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'empty branch pill / dead clicks' report reproduces on no machine I can test — the webview renders the real branch list correctly even under the production CSP, git-service listRefs/status.read work against both of the user's repos, and the host logs 'every section wired with no errors'. Because webview console errors never reach the extension-host log, a silent script failure in the real vscode-webview context would be invisible. So the webview now posts back — via the existing bridge — a 'script alive' ping on start, plus any window error and any securitypolicyviolation; the host console.errors them (readable in the exthost log / Output → GitStudio), and logs when 'ready' arrives. One reload will show definitively whether the webview script runs, and if not, why. Tripwire — reverted once the cause is found. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
THE BUG, finally pinned from a screenshot: the pill showed '—' (empty branch) with the composer visible (hasRepo=true). That state is only reachable when resolveState returns branch=undefined WITHOUT throwing — which happens when vscode.git has attached the repo but not yet computed state.HEAD (a race other Git extensions on the same repo, e.g. git-ai, can trigger). branch: head?.name is then undefined, no error fires, and the pill has nothing to show and no branch to click. Fix: doPushState now GUARANTEES the branch. If resolveState yields no branch while a repo is open, it recovers the branch from our own git-service getHead() — which is authoritative and doesn't depend on vscode.git's timing. The pill can no longer be empty on a real repo, whatever vscode.git is doing. Also adds a readable diagnostic trail to Output → GitStudio (log.ts shared sink): webview alive/error/CSP pings, 'ready' receipt, and the exact hasRepo/branch/counts each pushState sends — so any remaining edge names itself instead of failing silently (webview console never reaches a log). NOT published — marketplace stays 1.0.0 until confirmed live. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
1.0.0 shipped a walkthrough advertising features that silently did nothing. This is the repair release.
Root causes fixed
Pull demanded a rebase, and took the merge editor down with it.
SyncOps.pullran a baregit pull, which since git 2.34 is a hard error on divergent branches with nopull.rebase/pull.ffconfig ("Need to specify how to reconcile divergent branches") — surfaced verbatim to the user. Because the pull aborted, no merge was attempted, no conflict was created, and the 3-pane merge editor could never appear. Strategy is now always explicit. Regression test reproduces the fatal against real git and proves the fix.The merge editor was unreachable from GitStudio's own Changes view — a conflicted file opened a plain 2-way diff. Its only entry points were VS Code's built-in SCM view and the editor title bar.
Inline blame stacked on top of other providers. The duplicate check tested
inspect().defaultValueinstead of the effective value;git.blame.editorDecoration.enableddefaults tofalse, so the built-in decoration — the one that actually overlaps — was never detected, while the only branch that could fire silently rewrote the user's global settings to disable the status-bar item (which overlaps nothing). Now: effective values, GitLens detection, ask-don't-assume, and we never write another extension's settings unprompted.File history had no working UI at all — routed exclusively through
registerTimelineProvider, a proposed API absent from stable typings, so the call threw at activation into acatch {}. AddedGitStudio: Show File History. Line history re-opened its QuickPick on top of the diff it had just opened.History/blame/merge commands silently no-op'd with no active editor — and the walkthrough IS the active tab, so its buttons did nothing while the step still ticked green.
Windows: one path helper was duplicated 5× with a
/-only boundary that never matches a\fsPath — history, blame and merge were dead there outright.Staging. The Staged group was
display:nonewhen empty, so users never saw the model; committing with nothing staged then failed with literally "unknown error" (git reports "no changes added to commit" on stdout, we only read stderr). Now: Staged always visible with a hint, a Stage All & Commit offer, no row snap-back on partially-staged files, Discard styled destructive, conflicts say Mark as Resolved.Walkthrough rewritten: every button runs a command that works from the walkthrough, real screenshots as media (now shipped in the vsix), and the AI step points at the real Connect AI panel. Its old merge step's primary button started a destructive interactive rebase.
Icons: macOS dock icon was full-bleed (hence oversized) and theme-swapped to a white tile that washed the mark out. Now: Apple's icon margin, a properly-tuned light tile, and optical sizing — thin lanes for display surfaces, thick lanes for the dock.
Verification
🤖 Generated with Claude Code