Skip to content

feat(git): auto-fetch open repositories on a timer (DAN-89) - #153

Merged
danielss-dev merged 5 commits into
mainfrom
developements/auto-fetch-timer-22cf
Oct 19, 2026
Merged

danielss-dev merged 5 commits into
mainfrom
developements/auto-fetch-timer-22cf

Conversation

@danielss-dev

@danielss-dev danielss-dev commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

https://linear.app/daniels-dev/issue/DAN-89

Default interval

Daniels chose 10 minutes. That is the shipped default, not a placeholder. The single constant is DEFAULT_AUTO_FETCH_INTERVAL_MIN in ui/src/lib/autoFetch.ts. Settings → Git still offers Off, 5 min, 10 min, and 30 min, and each open repository can opt out.

What Daniels should check live

Open two repositories. From another machine, push a commit to one remote. Wait one 10-minute interval. The behind-count for that branch should update, and a notice should appear (N new commits on origin/<branch>). The other repository fetches a few seconds later. Confirm a background fetch never flashes a console window on Windows. A remote with no saved credential should fail once, quietly, and then wait instead of prompting every tick.

Proof

  • Scheduler interval, no second concurrent fetch for the same repo, and skip while a manual fetch/pull is running: ui/src/lib/autoFetch.test.ts (fires at the interval…, does not start a second fetch…, never runs two fetches…).
  • One tick after a push to a bare remote updates the behind-count and the new-commit count the notice uses; HEAD, porcelain status, git ls-files -s, git write-tree, and file bytes stay the same: background_fetch_one_tick_reports_new_commits_without_touching_worktree. Notice text: does not spawn a fetch until the interval, then surfaces a new-commit notice once.
  • Auth-required remote, no cached credential, no prompt, one quiet failure, then backoff: background_fetch_auth_failure_does_not_prompt (HTTP 401 plus a credential helper that would block) and records one quiet auth failure and does not spawn again until backoff ends.
  • Setting Off spawns no background fetch: spawns no background fetch when the setting is off and spawns nothing when the interval is off… (wakeAt is null, the fetch spy is never called).
  • Windows console: background fetch goes through prepare_git_command → crate::git_command() → CREATE_NO_WINDOW (background_fetch_command_uses_hidden_git_and_cannot_prompt). On Windows, console_probe::hidden_console_child_has_no_window re-executes the test binary and checks GetConsoleWindow() is null.
  • Local: cargo clippy -p strand-core -p strand-tauri -p strand-ops -p strand-headless -p strand-azdo-protocol -p strand-azdo -- -D warnings passed; pnpm --filter ./ui exec tsc --noEmit passed; pnpm --filter ./ui test (auto-fetch and settings) passed; cargo test -p strand-core --lib background_fetch passed (4 tests).
  • CI on https://github.com/danielss-dev/strand/actions/runs/39228389030 is green: Frontend (tsc + vitest), Rust (test + clippy) on ubuntu-22.04 and macos-latest, Azure DevOps Server helper (Windows), and Native agent review (Windows).

Fetch only. No auto-pull, no fetch of closed recent repos, no OS notification.

Review fixes

  • Background fetch keeps the user's core.sshCommand / GIT_SSH_COMMAND / GIT_SSH. It only forces ssh -o BatchMode=yes when no ssh command is set.
  • Background fetch passes -c core.askPass=, so a configured askpass helper can't prompt.
  • The manual-op skip follows the repository the op started on, not the tab that is active when the tick runs.
  • After a fetch, the refresh goes through the store's coalesced refreshUpstream. That refreshes meta per tab, and refs through refreshRefs when the repo is active.
  • A fetch that printed nothing and brought no commits writes no activity entry.
  • The 10-minute default wording (autoFetch.ts:6) is unchanged, pending confirmation.
  • Tests:
    • Rust: background_fetch_keeps_the_users_core_ssh_command, plus askPass assertions.
    • UI: autoFetchIsNoop, and a store test for refreshUpstream.
  • Round 2:
    • Tests now cover the busy-repo skip: a busy non-active repo is skipped while the active one fetches, a tab switch mid-op keeps the skip, and the op ending clears it. They run through the extracted manualOpPath / isManualBusyRepo (no behaviour change).
    • The background-fetch command tests run in a fresh temp repo, with the ssh probe blind to GIT_SSH_COMMAND, GIT_SSH and global/system config.

Merge order 157 → 153 → 155 → 154 → 156 → 158: no later PR in the stack touches these files, so none needs adapting for this one.

Open in Web Open in Cursor 

cursoragent and others added 5 commits October 19, 2026 16:14
Settings → Git offers Off, 5, 10, or 30 minutes. Daniels chose 10 minutes
as the default. Background fetch is fetch-only, staggered across open
repositories, and fails quietly when credentials are missing. DAN-89.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
GetConsoleWindow returns *mut c_void on the current windows-sys, so the
CREATE_NO_WINDOW probe compared a pointer with an integer and failed to
compile on Windows CI.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
… fetch (DAN-89)

GIT_SSH_COMMAND outranks core.sshCommand, so forcing BatchMode
unconditionally dropped a user's custom key or ssh. Only force it when
no ssh command is configured. Pass -c core.askPass= so a configured
askpass helper cannot prompt from a background tick.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
…vity rows (DAN-89)

- The manual-op skip now follows the repository the op started on, not
  whichever tab is active when the tick runs.
- Refresh after a background fetch goes through the store's coalesced
  refreshUpstream (meta per tab, refs through refreshRefs when active).
- A successful fetch that printed nothing and brought no commits writes
  no activity entry.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
- Extract manualOpPath / isManualBusyRepo (no behaviour change) and test
  that a busy non-active repo is skipped while the active one fetches,
  that a tab switch mid-op keeps the skip, and that op end clears it.
- The background-fetch command tests run in a fresh temp repo with the
  ssh probe blind to GIT_SSH_COMMAND, GIT_SSH and global/system config,
  so a developer's own ssh setup can't fail them.

Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
@danielss-dev
danielss-dev marked this pull request as ready for review October 19, 2026 14:16
@danielss-dev
danielss-dev force-pushed the developements/auto-fetch-timer-22cf branch from 8795d50 to 7ab82c0 Compare October 19, 2026 14:16
@danielss-dev
danielss-dev merged commit 512ca65 into main Oct 19, 2026
10 of 11 checks passed
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.

3 participants