Commit Graph
31 Commits
Author SHA1 Message Date
d363c83ae3 fix(worktrees): force-remove clean worktree with initialised submodule (#9096)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: MarkXian <mark-xian@foxmail.com>
2026-07-16 19:15:40 -07:00
6e2a4a824d fix(worktrees): stop surfacing prunable git worktrees as live workspaces (#8409)
* fix(worktrees): stop surfacing prunable git worktrees as live workspaces

A worktree still registered in git but whose directory was deleted
(git's `prunable` state) was enumerated as a normal workspace,
producing repeated pty:spawn DaemonProtocolError / fs:readDir ENOENT
loops and a blank pane.

- Parse the `prunable` porcelain field (Git >= 2.36) in both the main
  and relay worktree-list parsers.
- For Git < 2.36 (no `prunable` field), probe each linked worktree
  path for existence on the fallback line-block path, skipping locked
  registrations to mirror git's own prunable rules.
- Omit prunable worktrees from the detected-workspace enumeration only;
  removal/cleanup flows keep seeing them.
- Extend the real-binary compatibility contract with the 2.36
  `prunable` boundary.

Fixes #8389

Claude-Session: https://claude.ai/code/session_018Rg1Bpq4GGwmz613hq6RSD

* fix(worktrees): pin the prunable/locked porcelain annotations to their real Git 2.31 boundary

The prunable and locked annotations landed in Git 2.31, five releases
before `worktree list -z` (2.36); only -z defines the capability
fallback boundary. Correct the compatibility contract so a future
matrix entry in the 2.31-2.35 range passes, and reword the fallback
comments: on 2.31-2.35 the annotations still parse and the existence
probe is a backstop; only Git <2.31 relies on it outright.

* fix(worktrees): omit prunable registrations from the Space scan

A prunable registration has no directory to size or reclaim, so Space
rendered it as a dead "Missing" row whose checkbox stayed disabled with
no prune/remove affordance (reported on macOS after a reboot cleared
/private/tmp under 16 registrations). Skip prunable entries in the scan,
matching the workspace enumeration; removal flows list worktrees
separately and still see them.

---------

Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-15 15:24:15 -07:00
Brennan Benson 64be819790 fix(runtime): harden watcher and PTY teardown ownership (#8661)
* fix(runtime): retain watcher and PTY teardown ownership

* fix(runtime): restore watchers after interrupted cleanup

* fix(runtime): prevent stale watcher revival

* test(runtime): cover watcher shutdown ownership

* test(daemon): model physical PTY exit

* fix(daemon): keep shutdown terminating when disposal cannot prove exit

A rejecting host.dispose() (unreapable child past its exit deadline) left
the shutdown RPC without its process.nextTick(shutdown) and skipped socket
cleanup in shutdown(), stranding the daemon as an unreachable orphan after
the stale-daemon replacement flow unlinks its socket. Log and continue:
daemon exit reparents the child to init instead of blocking on it.

* fix(runtime): keep local watching alive after an idle-kill deadline miss

An idle child that outlived the exit deadline set shutdownRequested on the
shared desktop supervisor, which has no retire-and-replace path — every
later subscribe rejected supervisor_disposed and the roots were cached
unwatchable, silently ending local file watching for the session. The idle
path owns zero records, so there is no double-watch hazard; the zombie
keeps its capacity reservation until physical exit and the next subscribe
gets a fresh child.

* fix(renderer): resync replayed paired-web file watches

Transparent replay removed the implicit resync the old close-and-rebuild
path provided: a replayed files.watch only reports changes from its own
native setup, so changes during the reconnect gap were silently lost.
Deliver a conservative overflow to consumers once the replayed watch is
ready, matching the overflow-after-interruption contract everywhere else.

* fix(runtime): address teardown review findings

* fix(runtime): retry watches after teardown deadlines

* Fix PTY descendant leaks on forced teardown

* Fix jitter-sensitive terminal lifecycle test
2026-07-15 15:23:35 -07:00
Neil acb35ee649 Fix git submodule path cache retention (#7687) 2026-07-11 01:30:19 -07:00
Neil 533992bdda fix(git): cache unsupported capabilities per host (#8109)
* fix(git): cache unsupported capabilities per host

Old Git worktree, ref-search, and merge-tree fallbacks retried unsupported flags on recurring operations, flooding subprocess traces. Centralize capability probing per native, WSL, and SSH execution host, coalesce concurrent probes, and retry periodically for in-place Git upgrades.

* fix(git): recognize real old-Git merge-tree rejection

* test(git): enforce real binary compatibility matrix

* fix(ci): preserve Git compatibility test ownership

* fix(git): retain supported capability state
2026-07-10 18:19:36 -07:00
Jinwoo HongandOrca 977960ed4a Make Windows workspace deletion reliable and respect Git locks (#7963)
* Handle locked worktree force deletion

Co-authored-by: Orca <help@stably.ai>

* Harden locked worktree removal

* Recover Windows worktree deletion after Git deregisters

* Require force permission for lock overrides

* Respect Git worktree locks during deletion

* Require structural proof before Windows deletion recovery

* Align deletion tests with fail-closed recovery

* Restore deletion test filesystem spies

* Scope remote deletion tests to runtime host

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 17:52:50 -07:00
NeilandOrca 46646d7ff1 chore(lint): upgrade oxlint to 1.71 + enable 7 new rules (autofixed backlog) (#6841)
* chore(lint): upgrade oxlint to 1.71 and enable 7 new rules

Upgrade oxlint 1.67.0 -> 1.71.0 (1.72 was blocked by the repo's 3-day
minimum-release-age supply-chain guard; nothing here needs it). The
bump is a no-op on the existing config.

Enable 3 error rules (backlog autofixed to zero in this commit) and
4 warn rules (surface signal without gating CI):

error (autofixed, behavior-preserving):
- unicorn/prefer-node-protocol        (~1531 sites: bare builtin -> node:)
- typescript/no-import-type-side-effects (~36: all-inline-type -> import type)
- unicorn/no-array-reverse            (19: copy-then-reverse -> toReversed)

warn (real signal, current fires are test-only/correct):
- unicorn/no-array-fill-with-reference-type  (aliasing footgun guard)
- typescript/no-unsafe-function-type         (bans bare Function type)
- unicorn/prefer-array-flat-map              (map().flat() -> flatMap())
- unicorn/prefer-regexp-test                 (.match() in bool ctx -> .test())

mobile/.oxlintrc.json extends root, so it inherits all 7; the autofix
ran from root and covered mobile/ too.

Verification (all green): oxlint 0 errors (root+mobile+aux configs),
oxfmt clean, typecheck (node+cli+web), vitest 22795 passed / 0 failed,
builds (electron-vite + web + cli) succeed. node: rewrites confirmed to
skip embedded SSH/CLI string payloads (AST-only); all toReversed sites
verified to operate on fresh copies or write-once locals.

* chore(lint): bump mobile oxlint to 1.71 so inherited rules parse

mobile/ is a standalone pnpm project pinning its own oxlint@1.67, which
lacks unicorn/no-array-fill-with-reference-type (needs >=1.70). Since
mobile/.oxlintrc.json extends the root config, mobile CI's 'cd mobile &&
oxlint' failed to parse the new rule. Bump mobile to match root (1.71).

Verified in mobile/: oxlint 0 errors, oxfmt --check clean, tsc --noEmit
pass, vitest 978 passed / 0 failed.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-06-29 22:38:29 -07:00
Brennan BensonandOrca 8228155e4d Improve preserved branch cleanup after squash merges (#6014)
Co-authored-by: Orca <help@stably.ai>
2026-06-21 18:48:59 -07:00
0ec3882cb8 Add project Windows runtime selection (#5519)
* Add project Windows runtime selection

* Fix project Windows runtime selection

Co-authored-by: Orca <help@stably.ai>

* fix: preserve WSL shell variables

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <neil@stably.ai>
2026-06-17 16:08:14 -07:00
Brennan BensonandOrca 9885ff9760 Add crash report diagnostic log upload (#2580)
Co-authored-by: Orca <help@stably.ai>
2026-06-16 18:05:15 -07:00
Neil 9ed345ef56 Skip broad fetch for PR SHA worktree bases 2026-06-16 14:57:39 -07:00
Jinjing d21e73301e Refresh cleanup base before forced branch deletion (#4462) 2026-06-02 01:08:11 -07:00
Jinjing 1304d6b630 fix: address review findings (#4325) 2026-05-31 16:03:55 -07:00
Neil 75c9f496f1 perf: bound worktree sparse probes
Cap listWorktrees sparse-checkout filesystem probes at 8 concurrent workers while preserving output ordering and parsed sparse/bare short-circuits.

Risk: low.

Validation:
- pnpm exec vitest run src/main/git/remove-worktree.test.ts src/main/git/worktree-list-paths.test.ts src/main/git/worktree.test.ts
- pnpm run typecheck:node
- pnpm lint
- git diff --check
2026-05-31 06:55:20 -07:00
Neil 8ba451e8dd fix: preserve newline worktree paths
Use porcelain-z worktree parsing with fallback line parsing so newline-containing worktree paths survive local and relay operations. Risk: low.
2026-05-31 01:50:16 -07:00
Jinjing 5dc6947fc6 fix: address review findings (#3866) 2026-05-30 12:45:49 -07:00
Trevin Chow 10f97509ea fix: preserve unmerged branch when removing a worktree (#2927) (#2939)
fix: preserve unmerged branch when removing a worktree (#2927)
2026-05-28 20:19:53 -04:00
Brennan Benson 5287a581a6 Revert "Allow OS metadata during worktree delete preflight" (#2776) 2026-05-24 23:23:31 -07:00
Brennan BensonandOrca fdb63366d3 Allow OS metadata during worktree delete preflight (#2760)
Co-authored-by: Orca <help@stably.ai>
2026-05-24 23:00:40 -07:00
Jinjing d4e9c22f8b Fix worktree creation for selected existing branches (#2543)
* fix: address review findings

* fix: address CI failures
2026-05-21 12:25:32 -07:00
Jinjing 087f1aa9bf fix(worktree): preflight delete before terminal teardown (#2103)
Implement delete preflight checks before PTY teardown across git/runtime/ipc flows.

Design reference: docs/worktree-delete-preflight.md
2026-05-16 13:52:59 -07:00
Jinjing 17aef50c82 fix: handle non-git worktree paths (#1805) 2026-05-13 22:22:51 -07:00
Brennan BensonandOrca 8f3c783767 fix(worktree): create branches with --no-track and auto-setup remote (#1563)
* WIP: Changes before auto-review fixes

Co-authored-by: Orca <help@stably.ai>

* WIP: Changes before auto-review fixes

Co-authored-by: Orca <help@stably.ai>

* fix(worktree): preserve user push.autoSetupRemote, include path in warn

- Probe push.autoSetupRemote with `git config --get` before writing so a
  deliberate user value at any scope (local/global/system) is preserved.
- Include worktree path in the warn log for failed config writes.
- Add test pinning the preserve-existing-value behavior.
- Remove stray 00-review-context.md committed during review tooling.

Co-authored-by: Orca <help@stably.ai>

* WIP: Changes before auto-review fixes

Co-authored-by: Orca <help@stably.ai>

* fix(worktree): narrow config --get error handling, tighten test asserts

Treat only exit code 1 from `git config --get push.autoSetupRemote`
as "key unset". Other read failures (corrupt config, locked file,
parse error) now re-throw to the outer warn handler instead of being
silently treated as unset and overwriting whatever value the user
actually has.

Also: add test for the non-unset read-error path; convert the
"preserves existing value" test from `.some()` predicates to a
full-array `toEqual` matching sibling-test style; explicitly mock
`config --get` (with code: 1) in the sparse-failure rollback test
so it exercises the intended branch instead of the helper's empty-
stdout fallthrough; document in the design notes that
addSparseWorktree's rollback intentionally does not unset
push.autoSetupRemote.

Co-authored-by: Orca <help@stably.ai>

* test(worktree): pin --get-empty-stdout and worktree-add-fail invariants

Why: addWorktree's post-create config probe has two ordering
invariants worth pinning so a future refactor can't silently
regress them: (1) `git config --get` succeeding with empty stdout
still counts as "already set" so we don't overwrite an explicit
empty value, and (2) the entire config block is skipped when
`worktree add` itself rejects.

Co-authored-by: Orca <help@stably.ai>

* WIP: Changes before auto-review fixes

Co-authored-by: Orca <help@stably.ai>

* docs(worktree): cross-ref local↔SSH addWorktree, clarify SSH-host git version, add empty-stdout parity test

JSDoc on local addWorktree now flags the push.autoSetupRemote side
effect; both paths cross-reference each other so the next change keeps
them in lockstep. Relay comment clarifies that the git version that
matters is the SSH host's, not the client's. Adds the missing
empty-stdout-as-already-set parity test on the relay side.

Co-authored-by: Orca <help@stably.ai>

* chore: remove 00-review-context.md from PR

Stray file from local review workflow; should not ship in this PR.

Co-authored-by: Orca <help@stably.ai>

* chore: remove worktree-ssh-no-track-parity.md from PR

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-11 12:46:03 -07:00
Jinwoo HongandOrca 28caefd82c Handle stale SSH repo worktree refreshes (#1508)
Co-authored-by: Orca <help@stably.ai>
2026-05-06 13:01:09 -07:00
Brennan BensonandOrca f2b3b7eaf2 fix(worktree): drop unsupported -z from git worktree list --porcelain (#1470)
Co-authored-by: Orca <help@stably.ai>
2026-05-05 16:49:28 -07:00
bbd77c2449 fix(worktree): restore sparse checkout without per-poll git subprocesses (#1316)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Colin <colin.chambachan@gmail.com>
2026-05-01 13:25:22 -07:00
Jinwoo Hong 000d4dc08b Revert sparse checkout worktree creation (#1290) 2026-04-30 15:47:40 -07:00
79faafcc98 Add sparse checkout worktree creation (#1131)
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-04-30 00:43:00 -07:00
Neil e5890f8e3f Fix stale test mocks after runner migration (#516) 2026-04-11 22:47:30 -07:00
Jinwoo HongandClaude Opus 4.6 f6ec69c969 feat: add WSL support for repos on WSL filesystems (#375)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 21:02:36 -04:00
Jinjing db1bab5a05 fix: delete local branch when removing worktree (#296) 2026-04-04 13:35:36 -07:00