You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Local repos: display the checked-out branch, drop the branch axis (#110)
* feat(source): drop the branch axis for local repos
A local source scans whatever is checked out on disk, so a stored branch
is a lie: it must not namespace the cache, the URL, or recents. Add
identityBranch(src, branch) as the single "does this source carry a
branch" rule (undefined for local, branch for remote) and route sourceKey,
CURRENT_SOURCE, the deep-link URL, the fetch/overlay, and recents dedupe
through it.
- Recents now key + dedupe a local path by src alone, so switching its
checkout no longer spawns a second row, and the row shows no @Branch
identity pill.
- The header branch pill still shows the live checked-out branch: it falls
back to manifest.repo.branch via resolveBranch/SOURCE_INFO (display only).
Backend already populates repo.branch from HEAD for every scan, so no
change there.
Closes#92
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(source): normalize local branch at the commit boundary only
Follow-up to the local-branch-axis work: the "local has no branch" rule
was being re-decided on every read (sourceKey, recents dedupe, the active
match all called identityBranch(...) ?? ''). Collapse it to one boundary.
- Add sourceIdentity(src, branch): the canonical identity string, one place
the src\0branch join + empty-branch coercion lives. sourceKey hashes it;
recents dedupe and the active match compare it.
- identityBranch now applies only at the commit boundary (loadSource +
setCurrentSource), so CURRENT_SOURCE and every stored recent are already
branch-less for local. sourceIdentity trusts that and does a plain join —
no per-read source-kind switch.
- Bump the recents localStorage slot to recents.v2. Pre-v2 local entries
stored a checkout branch; dropping the slot once is cheaper than migrating
an MRU list, and it removes the only stale-data case the read guard existed
for.
- RecentsList matches active rows against CURRENT_SOURCE (the canonical
applied source) instead of SOURCE_INFO (which exposes the manifest's live
checkout for display). Post-v2 a recent's branch equals CURRENT_SOURCE's on
both kinds, so the match is exact; a local row no longer needs the display
branch normalized away. Drop the now-redundant !isLocal pill guard.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(source): share sameSourceIdentity for the active-row match
The recents-dedupe predicate was private and RecentsList re-spelled the
same identity comparison inline. Export it as sameSourceIdentity (it takes
any two {src, branch?} refs, not just recents) and use it in the active-row
match, so pushRecent, removeRecent, and isActive all go through one "are
these the same source?" check. sourceIdentity (the string) still backs the
React key.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(source): move pure source-identity helpers to utils/sources
sourceKey (+ djb2), sourceIdentity, and sameSourceIdentity are pure
functions on a source's (src, branch) identity with no signal dependency,
so they belong beside their siblings identityBranch/resolveBranch in
utils/sources, not in the stateful store. state/stores/source keeps the
signals, the recents mutations, and the URL effect built on them.
RecentsList now imports the two identity helpers from utils instead of
reaching into the store for pure logic; excludes + useManifestSource import
sourceKey from utils. Unit tests for the moved functions live in
tests/utils/sources.test.ts (mirroring the new home), with focused
sourceIdentity/sameSourceIdentity coverage added.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
0 commit comments