feat(SYNC): team presence — teammates' worktrees in the sidebar via git-ref sync#214
Open
btucker wants to merge 19 commits into
Open
feat(SYNC): team presence — teammates' worktrees in the sidebar via git-ref sync#214btucker wants to merge 19 commits into
btucker wants to merge 19 commits into
Conversation
… history search over WebRTC) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…JSON Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace `state: String` in `PresenceDocument.Worktree` with a nested `State` enum (`running`/`idle`); update `build()` and tests to use the typed cases instead of raw string literals. - Rephrase the SYNC-1.1 `@Test` title to avoid escaped double-quotes, which caused `generate-specs.py` to emit a dangling backslash and truncate the sentence in SPECS.md. - Add `/// Format version` doc comment on `version`, and one-line `///` comments on `user`, `email`, and `updatedAt` matching WorktreeEntry style. - Regenerate SPECS.md; `--check` passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds PresenceIdentity with slug derivation (lowercase + non-alphanumeric runs → hyphen) and async load() that probes git config user.name/user.email; throws IdentityError.missingEmail when email is absent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… over origin Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extends fetchDecodesAllPeerDocs to push a non-JSON commit to refs/graftty/presence/legacy-tool from cloneB before fetching, confirming fetchAll mirrors the ref but skips it during decode and returns only the valid doc. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the N+1 subprocess loop (for-each-ref + per-ref git show) in fetchAll with a single `git for-each-ref --format=%(refname)%09%(contents)` call. Extract the namespace string into `refPrefix` and derive refName, the fetch refspec, and the for-each-ref pattern from it. Add a comment on the best-effort local delete in `delete`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…and observable store Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ublish-on-change test - Log a debug-level message when identityProvider fails so a missing git config user.email is greppable in Console instead of silently disabling sync for the repo. - Add isTicking reentrancy guard (MainActor-isolated, race-free) so a hung git subprocess cannot stack a second tick's git work on the same refs; the next ticker fire retries cleanly. - Add 6th test: publish fires immediately on worktree-set change without waiting for the heartbeat interval. - Soften start() doc comment: uses the same ticker-injection seam as WorktreeStatsStore, does not implement stop(). - Hoist tickNow = now() and per-doc slug computation to avoid repeated calls inside the hot path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add block comment explaining why the suite has no @SPEC ID (behavioral specs live on SYNC-1.x/2.x/3.x unit suites; duplication is prohibited). Annotate @mainactor and local git-config rationale inline. Replace ben@btucker.net with ben@example.com so fixtures use no real addresses. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ring toggle
Renders teammates' worktrees as read-only ambient rows inside each repo's
sidebar section (dim person icon, dimmed branch, italic running hint, owner
badge — no buttons/drag/menu/selection per the ambient-cue design rule).
Adds an opt-in repo context-menu toggle ("Share/Stop Sharing Worktrees with
Team", git-tracked repos only). Enabling pulses the presence ticker for an
immediate publish/fetch; disabling deletes our presence ref from origin
(SYNC-2.3, best-effort).
Adds the minimal Task-8 seam: TeamPresenceSyncStore + teamPresenceTicker on
AppServices, threaded into MainWindow/SidebarView.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rt delete failures - RemoteWorktreeRow: append ", running" to accessibilityLabel when presence.state == .running so the only dynamic cue on the row is exposed to VoiceOver. - MainWindow: add import os + static presenceLogger (Logger subsystem/category matching TeamPresenceSync); restructure toggleTeamSharing's disable branch from nested try? calls into a single do/catch that logs a debug message when identity load or ref delete fails. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ave/pulse, store change-guards Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eave A @mainactor TeamPresenceSync.tick(repos:) could interleave with leave(repoPath:) at its await suspension points (publisher/fetcher subprocess calls). If leave ran while tick was suspended after passing the presenceSharingEnabled guard, the resumed tick wrote the stale fetch result back via store.update — repopulating rows the user just removed until the next 60s tick. Track repos whose leave() ran mid-tick in a MainActor-serialized pendingLeaves set; the resumed tick skips the lastPublished and store writes for those repos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Summary
Phase 1 of the team worktree sharing design (spec, plan): teammates' worktrees appear in the sidebar alongside your own, synced through the repo's existing git remote — zero new infrastructure.
refs/graftty/presence/<slug>onorigin. The JSON rides in the commit message of an empty-tree commit (no working-tree writes, no stdin plumbing); slug derives fromgit config user.email.SYNC-4.1); disabling deletes your ref from origin and clears local state immediately (race-guarded against in-flight ticks).Specs
SYNC-1.1..1.3(document/slug),SYNC-2.1..2.3(ref publish/fetch/delete),SYNC-3.1..3.4(service tick: opt-in gate, own-doc exclusion, heartbeat, staleness),SYNC-4.1(persisted flag),SYNC-5.1(sidebar rendering, inventory). SPECS.md regenerated;generate-specs.py --checkclean.Test plan
git ls-remote origin 'refs/graftty/presence/*'; second clone with differentuser.emailpublishes → dimmed row appears within ~60s; disable → ref deleted, rows gone.Phase 2+ (consent-gated live view/control, history search) builds on this per the design doc.
🤖 Generated with Claude Code