Skip to content

Prevent monitor status TCC prompts in Git-Same 3.2.0 - #21

Open
manuelgruber wants to merge 21 commits into
mainfrom
C/TCC
Open

manuelgruber wants to merge 21 commits into
mainfrom
C/TCC

Conversation

@manuelgruber

@manuelgruber manuelgruber commented Jul 18, 2026

Copy link
Copy Markdown
Member

This adds host-facing atomic status mirroring through IpcConfig, migrates legacy status symlinks safely, and keeps mirror failures non-fatal while primary writes still fail normally, preventing macOS cross-app access prompts in the Tauri host.

It adds a backward-compatible optional monitor_version field to FinderStatus, reports app/monitor build skew, and automatically restarts an already-installed stale monitor after upgrades so status recovers without manual intervention.

It also bumps Git-Same to 3.2.0 and refreshes in-range Cargo and pnpm dependencies.

Validation passed with cargo fmt --all -- --check, cargo test --workspace, and pnpm --dir crates/git-same-app/ui check.

Summary by Sourcery

Add host-facing status mirroring and monitor version tracking to avoid macOS TCC prompts and handle monitor/app skew while bumping Git-Same to 3.2.0.

New Features:

  • Introduce host-facing status mirroring via IpcConfig so the monitor writes status.json both to the app-group container and to the host config directory.
  • Expose a host-specific IPC configuration (HostIpc) and use it across app commands and status streaming to read status from the host directory instead of the app-group container.
  • Add an optional monitor_version field to FinderStatus and surface monitor/app build skew in requirement checks and UI types.

Bug Fixes:

  • Avoid macOS TCC prompts by preventing the non-sandboxed Tauri host from following status.json symlinks into the app-group container and by mirroring a real file into the host directory.
  • Treat corrupt or missing status.json files as stale status snapshots rather than hard errors, and ensure legacy status symlinks are safely removed or replaced.
  • Ensure monitor status writes remain atomic while allowing mirror write failures to be non-fatal.

Enhancements:

  • Refine legacy symlink handling so only the socket is symlinked and status.json is mirrored as a real file, with tests for migration behavior.
  • Refactor status writer construction through IpcConfig::status_writer to encapsulate platform-specific mirroring, and use a shared StatusFileWriter in the monitor socket handler.
  • Improve requirement messaging with better guidance for stale status and version skew, and add upgrade-time auto-restart of an already-installed monitor when legacy status symlinks are detected.
  • Filter filesystem watch events to only react to final status.json changes and avoid duplicate status-updated emissions.

Build:

  • Cap the time crate below 0.3.52 to work around an upstream cookie/time compatibility issue.
  • Bump workspace, app UI, and Badges extension versions to 3.2.0 and refresh selected JS dependencies (e.g., @lucide/svelte, @tauri-apps/cli, vite).

Documentation:

  • Document the IPC layout, host-facing status path, and rationale for avoiding cross-app container access in comments across IPC, commands, and status streaming modules.

Tests:

  • Add tests for status mirroring, symlink removal, legacy symlink behavior, corrupt status handling, and host/legacy IPC path consistency.
  • Extend monitor requirement tests to cover monitor_version stamping and version skew reporting.
  • Add tests for status watcher event filtering to distinguish status.json from its temporary files.

Summary by CodeRabbit

  • New Features
    • Added monitor version reporting to detect and surface app–monitor mismatches.
    • Enhanced macOS status synchronization with a host-facing status mirror.
    • Added clearer status-refresh controls and animated progress feedback in the dashboard.
  • Bug Fixes
    • Improved handling of legacy status-file symlinks and corrupted status data.
    • Reduced unnecessary updates by responding only to relevant status changes.
    • Improved recovery by restarting the installed monitor when legacy symlinks are detected.
  • Release
    • Updated the application and workspace version to 3.2.0.

Monitor identity and Full Disk Access gate (added 2026-09-09)

  • The monitor LaunchAgent now runs Git-Same.app/Contents/MacOS/git-same-app monitor --foreground (headless monitor mode in the app binary) instead of Contents/Helpers/git-same. macOS TCC attributes a launchd-spawned process to its bundle only through the bundle's own executable, so this is what lets a single Full Disk Access grant for Git-Same cover the monitor. The app re-renders an installed agent that still points at the helper, and the cask renders the new path.
  • The "Full Disk Access" requirement is now a real probe (opening the user TCC database, which never prompts) instead of the "zero repos" heuristic. The monitor stamps its own answer into status.json as full_disk_access; the app reports host and monitor answers.
  • New enable_finder_extension / disable_finder_extension commands set the pluginkit election in-app. Enabling is refused until Full Disk Access is granted. The badge checklist is reordered (monitor, FDA, installed, enable badges), the banner asks for FDA before offering the extension, permissions re-probe on window focus, and a lagging monitor is restarted once after the grant lands.
  • Shared monitor shim pieces (Options::from_config, default_shutdown_signal) moved into git-same-core; usage strings added to the bundle Info.plist; dead Banner.svelte removed.
  • Test env guards in core and the app now assert config isolation so tests can never register temp workspaces in the developer's real config.
  • CI fixes: portable EPERM test, beta-only double_must_use allow, and the audit job runs on current stable.

Note for release testing: macOS applies a new FDA grant only to processes started afterwards, so after granting it quit and reopen the app; the app restarts the monitor itself.

Merge readiness (updated 2026-09-21)

S1 is green on 01bb2b9 across every job for the first time on this branch: run 35655452798. That includes the four Test legs, Code Coverage, Security Audit, and the Build and Tauri App Debug Build jobs, which earlier runs skipped because the test matrix gated them.

Four commits were added after the rebase to get there:

  • eaf1dc4 Gate macOS-only items so clippy passes off macOS. use std::process::Command and the render_for_app plist helper were reachable only from macOS- and unix-gated code, so -D warnings failed the ubuntu and windows legs while macOS stayed green.
  • 643ab4e Derive the plist path in the cask install test from source::app_main_executable instead of a slash literal, so the string comparison matches the platform separator on Windows.
  • 12ada56 Rewrite the section 8 acceptance matrix in toolkit/packaging/release-checklist.md for the app-identity agent, with new rows for the pre-3.2 agent re-render, build skew after an app upgrade, the Full Disk Access gate in both directions, and a moved or deleted bundle.
  • 01bb2b9 Bump vitest to 4.1.11, clearing the three open Dependabot alerts (the advisory and its transitive @vitest/mocker). Dev dependency only.

The time < 0.3.52 cap noted above was dropped earlier in the branch; the lockfile now resolves time 0.3.55 with cookie 0.18.2.

Still outstanding after merge: tag 3.2.0, run S2 / S3 / S4, and work section 8 of the release checklist on a disposable macOS account, which is the only way to verify that one Full Disk Access grant reaches the monitor.

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Version 3.2.0 adds host-facing status mirroring, monitor version metadata, IPC configuration injection, filtered status watching, symlink migration handling, monitor/app version-skew detection, and guarded TUI status refreshes.

Changes

Host IPC and monitor synchronization

Layer / File(s) Summary
Release and compatibility contracts
Cargo.toml, crates/git-same-app/Cargo.toml, crates/git-same-app/tauri.conf.json, crates/git-same-app/ui/package.json, crates/git-same-cli/Cargo.toml, macos/GitSameBadges/Info.plist
Package versions are updated to 3.2.0. Frontend tooling versions are updated. The CLI version is aligned. The time crate is constrained below 0.3.52.
Monitor version status contract
crates/git-same-core/src/types/finder_status.rs, crates/git-same-core/src/types/finder_status_tests.rs, crates/git-same-app/ui/src/lib/types.ts
FinderStatus records an optional monitor version. Older JSON remains readable. The UI type exposes the field.
Host status mirroring and symlink migration
crates/git-same-core/src/ipc/*
IpcConfig resolves the host status path. StatusFileWriter writes primary and mirror files atomically. macOS migration retains only the finder.sock symlink.
Monitor writer propagation
crates/git-same-core/src/monitor/*
The monitor passes a configured StatusFileWriter through socket handlers for status writes and reads.
App host IPC and status watcher
crates/git-same-app/src/main.rs, crates/git-same-app/src/commands.rs, crates/git-same-app/src/status_stream.rs, crates/git-same-app/src/status_stream_tests.rs
Tauri stores resolved host IPC state. Startup can restart an installed monitor after legacy symlink detection. The watcher filters events to relevant status files.
Requirement checks and snapshot recovery
crates/git-same-app/src/commands.rs, crates/git-same-app/src/commands_tests.rs
Requirement checks detect monitor/app version skew. Snapshot reads remove legacy symlinks and handle invalid JSON as stale absent status.

TUI status refresh control

Layer / File(s) Summary
Guarded status refresh
crates/git-same-cli/src/tui/backend.rs, crates/git-same-cli/src/tui/backend_tests.rs
Status refresh starts only with a workspace and without an active refresh or sync operation.
Refresh and sync lifecycle
crates/git-same-cli/src/tui/handler.rs, crates/git-same-cli/src/tui/handler_tests.rs, crates/git-same-cli/src/tui/screens/dashboard.rs, crates/git-same-cli/src/tui/screens/dashboard_tests.rs
Dashboard refreshes use the shared guard. Sync blocks during refresh. Sync completion starts one guarded refresh. Status results clear status operations without replacing active sync state.
Refresh rendering and spinner
crates/git-same-cli/src/tui/widgets/*, crates/git-same-cli/src/tui/screens/dashboard.rs, crates/git-same-cli/src/tui/screens/dashboard_tests.rs
The dashboard displays an animated spinner while status refresh is active. Shared spinner frames wrap by tick count.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Monitor
  participant StatusFileWriter
  participant HostStatusPath
  participant StatusWatcher
  participant TauriApp
  Monitor->>StatusFileWriter: write FinderStatus
  StatusFileWriter->>HostStatusPath: atomically write status.json
  HostStatusPath->>StatusWatcher: notify status.json event
  StatusWatcher->>TauriApp: emit status-updated snapshot
  TauriApp->>HostStatusPath: read status snapshot
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: preventing monitor status TCC prompts in Git-Same 3.2.0. This matches the host-facing status mirroring objective.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch C/TCC

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the status trail,
Mirrors write without a fail.
Versions match or warnings start,
Symlinks leave the host-side chart.
“Three-point-two!” hops every part.

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds host-facing status mirroring and monitor version reporting to keep the macOS app and monitor in sync without triggering TCC prompts, refactors IPC/status handling to be safer and more robust in the presence of legacy symlinks and corrupt files, wires the Tauri host to read from the mirrored host path, and bumps the project to the 3.2.0 release line with dependency and test updates.

File-Level Changes

Change Details Files
Introduce atomic primary+mirror status writing and safe legacy symlink handling in the IPC layer.
  • Extend StatusFileWriter to support optional mirror paths and delegate atomic writes to a shared write_atomic helper that overwrites any existing symlink with a real file.
  • Treat mirror write failures as non-fatal warnings while keeping primary-path failures hard errors.
  • Add remove_symlink_if_present utility to safely unlink legacy status.json symlinks without following them, and add targeted tests for mirror behavior and symlink migration.
  • Refine macOS ensure_legacy_symlinks so only finder.sock is symlinked and expose ensure_legacy_symlinks_in for testability, with tests ensuring status.json is no longer symlinked.
crates/git-same-core/src/ipc/status_file.rs
crates/git-same-core/src/ipc/status_file_tests.rs
Route the Tauri host and status watcher through a host-facing IPC config and improve monitor lifecycle handling.
  • Introduce HostIpc state in the app to resolve IpcConfig::host_status_path once at setup and inject it into Tauri commands instead of recomputing default_path.
  • Update check_requirements, read_status, start_sync, and app_requirement_checks to use the injected HostIpc/IpcConfig and to incorporate monitor version skew into requirement messaging and suggestions.
  • Change read_status_snapshot_with to remove any legacy status.json symlink, treat missing/corrupt status as stale snapshots instead of errors, and simplify liveness/staleness computation to a single read.
  • Add restart_monitor_if_installed and call it on startup when a leftover host status symlink is detected, restarting only already-installed monitors to pick up new builds without implicit installation.
crates/git-same-app/src/commands.rs
crates/git-same-app/src/main.rs
crates/git-same-app/src/commands_tests.rs
Make the status watcher host-path aware and reduce redundant snapshot reads from temporary files.
  • Change spawn_watcher to accept an IpcConfig (host-facing) instead of resolving default_path internally, and use read_status_snapshot_with(ipc) for snapshot emission.
  • Introduce event_touches_status_file to filter notify events so only status.json (and pathless rescan events) trigger snapshot reads, skipping status.json.tmp noise.
  • Add unit tests for event_touches_status_file to verify filtering of temp files, final files, mixed-path events, and pathless events.
crates/git-same-app/src/status_stream.rs
crates/git-same-app/src/status_stream_tests.rs
Expose host-facing IPC configuration and status mirroring policy via IpcConfig, and adapt the monitor to reuse a shared StatusFileWriter.
  • Export remove_symlink_if_present from the ipc module and add IpcConfig::host_status_path as the canonical host-facing dir, ensuring it matches legacy_default_path.
  • Add IpcConfig::status_writer that, on macOS when pointing at the app-group container, returns a StatusFileWriter that also mirrors into the host dir; custom dirs and non-macOS remain mirrorless.
  • Update monitor run loop and socket handler to construct a single StatusFileWriter from IpcConfig::status_writer and pass/cloned it into connection handlers, updating status_response to use the writer instead of raw paths.
  • Add tests ensuring host_status_path equals legacy_default_path and that status_writer mirrors only for the group container, with no mirrors for custom dirs.
crates/git-same-core/src/ipc/mod.rs
crates/git-same-core/src/ipc/mod_tests.rs
crates/git-same-core/src/monitor/run.rs
crates/git-same-core/src/monitor/socket_handler.rs
crates/git-same-core/src/monitor/socket_handler_tests.rs
Add monitor build version stamping to FinderStatus and surface app/monitor version skew in checks and UI types.
  • Extend FinderStatus with an optional monitor_version field stamped from env!("CARGO_PKG_VERSION") in FinderStatus::new, and ensure legacy files without the field deserialize with None.
  • Update TypeScript FinderStatus interface to include optional monitor_version to keep the UI schema in sync.
  • Add monitor_version_mismatch helper and pass app_version into monitor_requirement_message/suggestion so they can flag and message version skew when the monitor reports a different build.
  • Add tests for monitor_version stamping/legacy deserialization and for the new version-skew requirement messaging behaviors.
crates/git-same-core/src/types/finder_status.rs
crates/git-same-core/src/types/finder_status_tests.rs
crates/git-same-app/ui/src/lib/types.ts
crates/git-same-app/src/commands_tests.rs
Update versions and build tooling for the 3.2.0 release and pin time to avoid a tauri-cookie incompatibility.
  • Bump workspace, app UI, CLI, and macOS extension versions from 3.1.0 to 3.2.0 and align git-same-cli's git-same-core dependency version constraint.
  • Refresh selected frontend dependencies in the app UI package.json (lucide, tauri CLI, vite) and update the pnpm lockfile accordingly.
  • Add an explicit time = ">=0.3, <0.3.52" dependency to git-same-app with a comment explaining the tauri/cookie incompatibility and intent to remove once fixed.
Cargo.toml
crates/git-same-cli/Cargo.toml
crates/git-same-app/ui/package.json
crates/git-same-app/ui/pnpm-lock.yaml
macos/GitSameBadges/Info.plist
crates/git-same-app/Cargo.toml
crates/git-same-app/tauri.conf.json
Cargo.lock

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@manuelgruber
manuelgruber marked this pull request as ready for review July 18, 2026 08:06
Copilot AI review requested due to automatic review settings July 18, 2026 08:06

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/git-same-app/src/commands.rs`:
- Around line 1013-1026: Update the Monitor requirement’s passed condition in
the checks construction to also require monitor_version_mismatch to be false.
Preserve the existing running-agent and fresh-snapshot checks, while ensuring a
running, fresh monitor with a mismatched version is marked as failed.

In `@crates/git-same-core/src/ipc/status_file.rs`:
- Around line 117-129: Update remove_symlink_if_present to distinguish
symlink_metadata errors: return Ok(false) only for ErrorKind::NotFound, and
propagate all other inspection errors as AppError::path failures. Preserve the
existing symlink removal behavior and error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cbc0eccc-5949-45b2-81ab-179756176bec

📥 Commits

Reviewing files that changed from the base of the PR and between bab0c0b and 9edcf79.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • crates/git-same-app/ui/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • Cargo.toml
  • crates/git-same-app/Cargo.toml
  • crates/git-same-app/src/commands.rs
  • crates/git-same-app/src/commands_tests.rs
  • crates/git-same-app/src/main.rs
  • crates/git-same-app/src/status_stream.rs
  • crates/git-same-app/src/status_stream_tests.rs
  • crates/git-same-app/tauri.conf.json
  • crates/git-same-app/ui/package.json
  • crates/git-same-app/ui/src/lib/types.ts
  • crates/git-same-cli/Cargo.toml
  • crates/git-same-core/src/ipc/mod.rs
  • crates/git-same-core/src/ipc/mod_tests.rs
  • crates/git-same-core/src/ipc/status_file.rs
  • crates/git-same-core/src/ipc/status_file_tests.rs
  • crates/git-same-core/src/monitor/run.rs
  • crates/git-same-core/src/monitor/socket_handler.rs
  • crates/git-same-core/src/monitor/socket_handler_tests.rs
  • crates/git-same-core/src/types/finder_status.rs
  • crates/git-same-core/src/types/finder_status_tests.rs
  • macos/GitSameBadges/Info.plist

Comment thread crates/git-same-app/src/commands.rs
Comment thread crates/git-same-core/src/ipc/status_file.rs

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 23 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread crates/git-same-core/src/ipc/status_file.rs
Comment thread crates/git-same-core/src/ipc/status_file_tests.rs Outdated
Comment thread crates/git-same-core/src/ipc/mod_tests.rs
Comment thread crates/git-same-app/src/commands.rs Outdated
Comment thread crates/git-same-core/src/ipc/status_file.rs Outdated
Comment thread crates/git-same-app/Cargo.toml Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 11:05

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 10 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread crates/git-same-cli/src/tui/widgets/spinner.rs

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 12 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="crates/git-same-cli/src/tui/handler.rs">

<violation number="1" location="crates/git-same-cli/src/tui/handler.rs:138">
P2: The dashboard can show pre-sync repository statuses until the refresh interval expires when an older status scan is still running as sync completes: this guarded call is skipped while `app.status_loading` is true, and that older result is then treated as the fresh post-sync snapshot. A post-sync refresh should be queued and started after the in-flight scan finishes, or otherwise forced after sync completion.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread crates/git-same-cli/src/tui/handler.rs

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 32 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread crates/git-same-core/src/monitor/run.rs
Comment thread crates/git-same-app/ui/src/stores/status.ts
Comment thread crates/git-same-app/ui/src/stores/status.ts
Comment thread crates/git-same-app/ui/src/stores/status.ts Outdated
Comment thread crates/git-same-app/src/commands.rs
@codecov

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

The non-sandboxed Tauri host read status.json from the App Group
container, so macOS fired "Git-Same would like to access data from
other apps" up to five times on launch and after each sync.

The monitor now mirrors a real status.json into ~/.config/git-same/
finder/ (StatusFileWriter::new_with_mirrors) in addition to the
container, and the host reads only that host-home copy via a shared
tauri::State<HostIpc> resolved once at startup. ensure_legacy_symlinks
no longer symlinks status.json (only finder.sock), and the host unlinks
any leftover status.json symlink before reading so it never follows a
link into the container during the upgrade window.

The FinderSync extension, the socket, and all entitlements are
unchanged, so no Apple re-sign or macOS-26 re-test is required.
time 0.3.52 changed its sealed Parsable::parse trait method from one argument to two (added defaults: Option<Parsed>). cookie 0.18.1, pulled in transitively via tauri, calls the one-argument form and fails to compile against time >= 0.3.52. No fixed cookie release exists (0.18.1 is the latest and tauri pins cookie 0.18), so cap time below 0.3.52 in the git-same-app manifest and re-pin the lockfile to the latest compatible time 0.3.51. Remove the cap once cookie ships a fix.
Updates 6 crates.io packages (clap_complete, console, indicatif,
inotify-sys, libredox, tauri) and 3 npm packages (@lucide/svelte,
@tauri-apps/cli, vite) to their latest semver-compatible releases.
The time <0.3.52 cap in git-same-app/Cargo.toml stays in place since
tauri's transitive cookie 0.18.1 still hasn't shipped a fix.
Address findings from an xhigh code review of the status-mirror change:

- Gate the Windows-hostile suffix assert in the IPC test so S1 CI passes.
- Make status mirror writes best-effort (warn, not error) so an unwritable
  host dir cannot crash-loop the monitor under launchd.
- Add core remove_symlink_if_present (NotFound-tolerant), reuse it from the
  host, and drop the duplicated app-side helper and its synthetic test.
- Move the mirror policy into IpcConfig::status_writer so a custom IpcConfig
  can never clobber the real user's host status.json.
- Drop the false state-guard clones in the Tauri handlers, single-parse the
  status snapshot, and filter watcher events to status.json.
- Correct the ipc module docs to describe the mirror design.
Add monitor_version to FinderStatus, stamped in FinderStatus::new with the
building crate's CARGO_PKG_VERSION, so each status records the monitor build
that wrote it. The Tauri Monitor requirement check compares it against the
app's own version and, when a readable status reports a different build,
tells the user to restart the monitor. Informational only: it does not flip
the check to failed, and the stale hint still takes priority when no status
is readable. Old status files without the field parse as None.
After an app upgrade the previously installed monitor keeps running the old
build (launchd KeepAlive keeps the process alive; nothing restarts it). The
old monitor only symlinks the host status.json into the container and never
writes the mirror the new host reads, so the host deletes the leftover
symlink and then shows stale/absent status until a manual restart.

On startup, detect that leftover symlink (a reliable signal an old monitor is
running) via symlink_metadata, which does not follow the link into the
app-group container, and best-effort restart the installed monitor on a
background thread so the on-disk build takes over and starts mirroring. Skip
when no LaunchAgent is installed so a monitor is never created implicitly.
This complements the stale-status guidance text by making the common upgrade
case self-heal without user action.
Make the app's Monitor requirement fail its pass check on a build-version
skew via a new monitor_requirement_passed helper, so the row no longer
shows a green check while its message and suggestion say to restart the
monitor.

Log the status watcher's watcher-error and snapshot-read-error paths
instead of swallowing them, so a stale dashboard leaves a diagnostic
trail.

Propagate non-NotFound symlink_metadata failures from
remove_symlink_if_present so read_status_snapshot_with aborts rather than
dereferencing a path it could not inspect, preserving the TCC-safety
guarantee.
Run status scans as guarded background work, recover legacy Status states, refresh requirements, and show animated feedback. Add regression coverage for manual, automatic, and post-sync refresh paths.
Route the monitor LaunchAgent through Git-Same.app's main executable
(headless `git-same-app monitor`) so one Full Disk Access grant covers
both the app and the monitor. The helper at Contents/Helpers/git-same
was a separate, path-based TCC identity that the grant never reached,
so the monitor kept prompting for Desktop, Documents, Downloads, and
volume access no matter what the user granted.

Replace the "zero repos" Full Disk Access heuristic with a real probe
(opening the user TCC database; silent, never prompts). The monitor
stamps its own answer into status.json, the app reports host and
monitor answers, and enable_finder_extension refuses to set the
pluginkit election until the gate passes. The badge checklist now runs
monitor, FDA, installed, enable; permissions re-probe on window focus;
a lagging monitor is restarted once after the grant lands; the app
re-renders an installed agent that still execs the helper.

Shared monitor shim pieces (Options::from_config, the shutdown signal)
move into git-same-core so the CLI and app use the same code. The cask
renders the new agent path, the bundle Info.plist gains usage strings,
and the dead Banner.svelte is removed.
Core and app test env guards now fail fast if Config::default_path()
resolves outside the temp home, so a broken override can no longer
register temp workspaces in the developer's real
~/.config/git-same/config.toml. The ten stale my-ws entries found
there were historical; the current tree does not reproduce them.
Make the EPERM probe test portable (raw OS error 1 is not
PermissionDenied on Windows), allow clippy's beta-only double_must_use
on the async_trait Provider trait, and run the Security Audit job on
current stable because cargo-audit's dependency graph (kstring 2.0.4)
outgrew the pinned 1.93.1 toolchain. Also correct the LaunchAgent
migration comment to the 3.2 release.
Address the unresolved review threads on PR #21, re-verified against the
rebased tree.

TUI: DiscoveryError no longer tears down an in-flight operation. Per-org
discovery failures are non-fatal in the provider, so resetting to Idle
dropped the guards that keep a status refresh, and a second concurrent
sync, from starting mid-run. Also clear status_loading on OperationError
and stop recording a short-circuited Status run as a sync.

IPC: move aside a directory left at the host status.json path. The mirror
write fails EISDIR forever otherwise, and a mirror failure is only a
warning, so the monitor ran with host status permanently absent.

App: withhold the host-probe fallback in the Full Disk Access gate when a
fresh monitor reports no answer and the agent is not app-owned, since the
grant does not reach a CLI-owned helper. Broaden startup recovery beyond
the leftover symlink, which the first status read erases. Expose a
guarded restart the UI can use without implicitly installing a service.

UI: kickMonitorIfLagging now skips monitors it cannot restart, clears its
latch on failure so transient launchctl errors retry, and re-reads Full
Disk Access on success so the badge action unlocks immediately.

Deps: drop the time cap. cookie 0.18.2 no longer calls Parsable::parse,
so the 0.3.52 incompatibility no longer applies.

Tests: assert the mirror entries are real files rather than symlinks, add
a crate-wide env lock so the IPC path readers cannot race the config
tests that swap HOME, and de-duplicate the TUI spinner onto one table.
@manuelgruber

Copy link
Copy Markdown
Member Author

Two findings raised in local review (not GitHub threads), recorded here for the trail. Both relate to commit 087b51a.

monitor/run.rs initial status write is fatal while other writes log and continue — already fixed upstream, no change needed.

The bare status_writer.write(&initial_status)? is gone. run.rs:208-215 now logs and returns Ok(()) under launchd so KeepAlive cannot crash-loop, while a foreground CLI run still returns Err. That asymmetry is deliberate and correct. The stated trigger was also not reachable: mirror failures are swallowed inside StatusFileWriter::write (status_file.rs:61-69), so only a primary write failure ever reached the ?.

commands.rs: nothing restarts the monitor on app launch — partly stale, but a real residual gap, now fixed.

The premise is stale: main.rs has restarted an installed monitor at launch since 9edcf79, and it already used the guarded restart_monitor_if_installed.

The residual gap was the trigger. It keyed on a leftover symlink at the host status path, but read_status_snapshot_with unlinks that on the first read (commands.rs:1436), and the status watcher performs one within moments of launch. So from the second launch onwards there was no evidence left to find, and with an old monitor still running the host status stayed absent indefinitely.

monitor_needs_startup_recovery now accepts a second signal: an installed service that is running and has completed a scan, while the host mirror is absent or stale. Requiring a completed scan (MonitorAgentStatus::last_scan, populated only when facts.scan_complete) is what keeps this from restarting a healthy monitor that simply has not finished its first pass.

The recovery also moved off a raw std::thread::spawn onto run_monitor_operation, so it serializes with ensure_monitor_on_startup instead of racing it, and its result reaches the UI as a monitor-agent-updated event.

The app-identity commit left `use std::process::Command` and the
`render_for_app` plist test helper reachable only from macOS- and
unix-gated code, so `-D warnings` failed the ubuntu and windows S1
legs while macOS stayed green. Spell the one bare `Command` call site
out in full and drop the import, and gate `render_for_app` plus its
`source` import with `#[cfg(unix)]` to match their only caller.

Verified with a containerized Linux `cargo +stable clippy --workspace
--all-targets --all-features -- -D warnings`, which is the exact S1
command and cannot be run natively on macOS.
The cask install test compared the rendered LaunchAgent against
`app.join("Contents/MacOS/git-same-app")`, a slash literal, while the
plist carries the three-join form that renders as backslashes on
Windows, so the only failing test of the S1 windows leg was a
separator mismatch rather than a behaviour difference. Build the
expectation with `source::app_main_executable` so the assertion keeps
its meaning on every platform instead of being gated off.
Section 8 still described the pre-3.2 helper model, so the release
gate never checked the behaviour this version exists to deliver. The
LaunchAgent now execs the bundle's own main executable in place, which
is what makes one Full Disk Access grant cover the monitor, so the
matrix gains rows for the pre-3.2 agent re-render, build skew after an
app upgrade, the Full Disk Access gate in both directions, and a moved
or deleted bundle. Rows that still assume a copied helper are reworded
for CLI owners, where that copy and its separate TCC identity remain.

Also record the two hand-maintained versions (ui/package.json and
tauri.conf.json) in section 1, which no CI job gates.
All three open alerts are the same advisory: vitest >= 2.1.0 < 4.1.11
flagged against package.json and pnpm-lock.yaml, plus its transitive
@vitest/mocker. The bump crosses a major, so it was verified rather
than assumed: installed with the pinned pnpm 11.0.9 in a container,
then svelte-check (0 errors), the 31 unit tests, and vite build all
pass, and a second `--frozen-lockfile` install reproduces it exactly
as CI does.

The lockfile shrinks because vitest 3 carried its own vite 7 and
vite-node, while vitest 4 reuses the vite 8 already pinned here. Only
the vitest entry moves in package.json. Dev dependency only: nothing
in a shipped artifact changes.
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.

2 participants