Commit Graph
7762 Commits
Author SHA1 Message Date
Brennan Benson 90c8125794 fix(agent-status): canonicalize lifecycle and tool agent ids like inventory ids
Review finding round 15: inventory ids trim at parse but lifecycle/tool
agent_id stayed raw, so a padded stop missed the trimmed roster key and
the row could never drain. All id reads now canonicalize identically.
2026-08-01 10:16:22 -07:00
Brennan Benson b4af7f39f0 fix(agent-status): drop dead-wait cards and canonicalize inventory ids
Review findings round 14: (1) the clearing emission after a wait owner's
death carried the cached tool/interactive card, leaving it actionable on
a resolved pane — the cache resets like the answered-question clear.
(2) Whitespace-padded inventory ids were stored raw yet published
trimmed, so their own stops could never drain them — canonicalize at
parse time.
2026-08-01 10:05:23 -07:00
Brennan Benson e686b3acc0 fix(agent-status): make stop-time inventory processing strictly additive
Review findings round 13 share one root: stop-time inventories are
mutually unordered, so any deletion they drive can be a stale claim
against newer live state. Fold only running valid entries (no deletions;
listed-non-running cleanup stays with turn-serialized lead Stops), reap
only pre-restart restoredFromSnapshot rows on an empty inventory, and
drop the untrackable raw-scan working mint (truncated stays silent).
2026-08-01 09:49:24 -07:00
Brennan Benson fc66ab6eea fix(agent-status): count empty-inventory reaps as removal evidence
Review finding round 12: reaping the last inventory-derived rows emitted
nothing, stranding the previously published working until the sweeper.
The reap is same-source-correlated removal evidence — the authority that
minted those rows now reports empty — so it rides the existing done veto
chain.
2026-08-01 09:37:10 -07:00
Brennan Benson 82dae61562 fix(agent-status): reap only unbacked claims from an empty stop inventory
Review finding round 11: the complete-empty fold cleared live-tracked
rows, so a delayed stale stop's empty list could retire a newer live
start — the uncorrelated-retirement race again. The empty inventory now
reaps only restored/inventory-derived claims not backed by live
lifecycle events.
2026-08-01 09:25:26 -07:00
Brennan Benson d9f485b491 fix(agent-status): keep reused-id parks from clearing waits and drop untrackable ids everywhere
Review findings round 9: (1) a delayed prior-turn stop for a reused
teammate id could park the newer start's working row and ride the wait-
clear into done — the clearing done now fires only when the owner has no
roster row left; a parked owner stays silent (sweeper-bounded card).
(2) Over-length ids no longer consume inventory parser cap slots, so
junk cannot fake truncation and veto a legitimate drain. (3) A waiting-
inducing child event with an untrackable id mints no card at all.
2026-08-01 08:59:01 -07:00
Brennan Benson 759926d6ad fix(agent-status): validate inventory ids and clear identity-owned waits explicitly
Review findings round 8: (1) over-length running inventory ids could
allocate rosters or claim liveness despite being untrackable — the fold
guard and raw liveness scan now require an id the upsert would accept.
(2) Deleting a fresh pane's no-stash wait record left the stale amber
waiting card fresh for the stale sweeper; the wait's own agent id
parking/stopping is an identity-correlated resolution and now emits a
clearing done.
2026-08-01 08:46:37 -07:00
Brennan Benson 1bc62cf4dc fix(agent-status): close the remaining no-lead sticky/phantom paths
Review findings round 7: (1) a child permission wait that is a fresh
pane's first lead record fabricated 'working' from the no-stash clear
fallback when the child died — drop the record instead and let evidence
rules decide. (2) A complete empty stop inventory now clears restored
phantom rows (it is complete by construction; the non-empty additive fold
is unchanged). (3) An uncapped raw scan sees running subagents hidden
past the 32-entry parser cap, so a capped inventory with live work emits
truthful working instead of retaining stale state.
2026-08-01 08:32:54 -07:00
Brennan Benson 8cb32cd86b fix(agent-status): track inventory children additively and fail closed on truncated inventories
Review findings round 6: (1) veto-only left the vetoing child untracked,
so its own later drain was start-less-suppressed and the pane stuck on
working — fold running non-teammate inventory entries additively
(inventoryComplete: false; no reap, so a just-parked unconfirmed teammate
row survives). (2) The agent-task parser caps at 32 entries; a running
child past the cap is invisible, so a truncated inventory now claims
neither done nor working. The raw-array shell/cron veto stays uncapped.
2026-08-01 08:18:53 -07:00
Brennan Benson 3c6c1f80b2 fix(agent-status): let a stop's own inventory veto removal-driven done
Review finding round 5: after a restart the listener can miss a child's
start; another child's stop still lists it running in background_tasks.
A running non-teammate task or live shell/cron now vetoes the no-lead
removal->done into working. Veto only — folding the inventory at stop
time would reap a just-parked teammate row before its TeammateIdle
confirmation arrives.
2026-08-01 08:09:52 -07:00
Brennan Benson 7fd2784cfd fix(agent-status): infer done only from one-shot removals when no lead record exists
Review finding round 4: teammate ids persist across turns, so a delayed
stale SubagentStop parks a live teammate's row and the drain->done
inference retired newer work — PR #11353's uncorrelated-completion race.
With no lead record, only a live working child (working) or a one-shot
row removal (done; duplicate-proof since the row is gone) may speak;
teammate parks and idle-only refreshes stay silent.
2026-08-01 07:58:13 -07:00
Brennan Benson 98943de98b fix(agent-status): resolve identity-matched child drains to done without a lead record
Review finding round 3: rosterChanged let a known-child drain bypass the
no-evidence guard into the unconditional 'working' default — sticky until
the stale sweeper when no lead hook ever arrives. With no lead record the
pane state now follows tracked children: live child -> working, identity-
matched drain/park -> done. Duplicate stale stops stay suppressed.
2026-08-01 07:46:35 -07:00
Brennan Benson 6afef239c4 fix(agent-status): prevalidate subagent ids before allocating a roster
Review finding round 2: upsert silently rejects over-length agent ids after
the caller already allocated, stranding one empty roster per invented pane
key with zero emitted payloads. Export the id validity check and gate both
wire-reachable allocation sites.
2026-08-01 07:32:30 -07:00
Brennan Benson 68a010be98 fix(agent-status): stop retaining empty rosters for unknown-pane lifecycle events
Review finding: the early null return left getOrCreateClaudeSubagentRoster's
empty allocation behind, one per untrusted pane key with no lifecycle bound.
Only SubagentStart may allocate; stop/idle now read the existing roster.
2026-08-01 07:19:03 -07:00
Brennan Benson 01727afae0 fix(agent-status): stop start-less SubagentStop from minting phantom working
Claude compact emits PreCompact -> SubagentStop (never started) ->
SessionStart(compact) -> PostCompact. On a freshly resumed pane with no
cached lead state, the child-driven default minted a sticky empty-prompt
'working' that no Stop ever clears (STA-2915). Emit child-driven status
only on positive evidence: a lead record, a live working child, or an
actual roster change.
2026-08-01 07:07:06 -07:00
Neil 16c5526dfd fix(daemon): cover in-flight sleep in PAM watch (#11921)
* fix(daemon): rebaseline in-flight PAM suspension

* test(activity): await portal readiness commits
2026-08-01 03:35:34 -07:00
Neil 33c14bc716 fix(ssh): fall back to OpenSSH for FIDO2 keys (#11913)
Closes #11645
2026-08-01 03:27:42 -07:00
Neil 1f307afa6d fix(terminal): preserve follow output through streaming refocus (#11915) 2026-08-01 03:26:30 -07:00
Neil 76a2317bc0 fix(persistence): stop blocking backup rotation (#11916)
Use async profile probes and serialize the current-time due decision plus mutations under one async owner so sync flushes and detached writers cannot double-shift or miss the recovery interval. Add syscall, timer-liveness, parity, and held-I/O interleaving coverage.
2026-08-01 03:22:36 -07:00
Neil c79b859758 fix(browser): prevent window.close guest crashes (#11910)
* fix(browser): prevent window.close guest crashes

* fix(browser): guard close before inline scripts

* fix(browser): preserve explicit window close policy
2026-08-01 03:08:11 -07:00
Neil e531e796b2 fix(relay): chunk fs.changed notifications to fit the client frame capacity (#11917)
* fix(relay): chunk fs.changed notifications to fit the client frame capacity

emitRelayWatcherEvents published an entire watcher batch as one
fs.changed notification on the ordinary lane. A batch runs routinely
tens of times over the per-frame producer capacity (12,288 bytes against
a Node <=21 socket, 49,152 against Node >=22), and an over-capacity
frame there is not queued or trimmed -- notify() fails admission and
closes the client, tearing down every in-flight request on that
connection. Regressed in 5f7807497e (#11005).

The emitter now sizes chunks against the tightest capacity across
attached clients, measured in encoded bytes through the same envelope
admission measures, and preserves event order. A single event too large
for an empty envelope cannot be chunked, so the ordinary-lane close
remains its backstop: a silent drop on this lane has no resync contract.

* chore(relay): shorten watcher chunking comments
2026-08-01 02:56:52 -07:00
Neil 3a70078ab9 fix(daemon): prevent PAM rejection restart cascades (#11911)
* fix(daemon): back off transient PAM rejection retirement

* fix(daemon): rebaseline PAM evidence after sleep
2026-08-01 02:36:49 -07:00
Neil edb5607e28 ci: block new root-level entries (#11903)
* ci: guard repository root additions

* fix: clear existing type-aware lint warnings
2026-08-01 01:48:24 -07:00
Brennan Benson 169ec8f08d fix(mobile): refresh folder workspace catalog (#11767) 2026-08-01 01:42:27 -07:00
Brennan Benson c2e3d13efe fix(mobile): focus Kimi terminal input after touch (#11865)
* fix(mobile): focus terminal input after TUI touch

* fix(mobile): defer terminal focus after WebView taps

* fix(mobile): reset deferred terminal focus on route blur
2026-08-01 01:40:55 -07:00
Neil 340faaa839 fix(workspaces): use the emojibase shortcode preset for emoji suggestions (#11888)
Swap the worktree-name emoji picker from emojibase-data's `github` shortcode preset to `emojibase`, which carries both `flag_kr` and `south_korea` style flag names, and drop the hand-maintained `kr` entry that patched around the gap. Filter skin-tone aliases so they neither crowd the suggestion list nor clobber base-emoji branch names.

Search now matches anywhere in the shortcode, ranked exact > prefix > word-start > substring, so `:korea` surfaces both Koreas.

Emoji-derived branch names now prefer spelled-out aliases: flags use country names (japan, germany, south-korea) and cryptic stubs are skipped (thumbsdown over no, victory over v).
2026-08-01 00:40:47 -07:00
Jinjing 96c954f3be chore: remove force-added design docs from docs/ (#11891)
Keep only the durable docs already allowlisted for tracking
(STYLEGUIDE, assets, localized readme, and reference compatibility
guides). Drop feature design notes, plans, and repro artifacts that
were force-added past the existing docs ignore rules.
2026-08-01 00:33:20 -07:00
Jinjing ad1e58d966 chore: declutter top-level repo layout (#11890)
Remove one-off incident docs and committed test-results noise, move
dev/repro/bench tools under tests/tools, and relocate i18next config
into config/ so the GitHub root scrolls to the description faster.
2026-08-01 00:25:35 -07:00
Neil 278a4b28c8 fix(terminal): close async capability review gaps (#11887) 2026-08-01 00:00:12 -07:00
OrcaWinandNeil c8a22ad0a6 fix(terminal): make snapshot capability lookup async (#11881)
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-31 23:38:26 -07:00
NeilandBrennan Benson 6e7ceafd07 perf(mobile): avoid unchanged worktree catalog payloads (#11735)
* perf(mobile): avoid unchanged worktree catalog payloads

* fix(mobile): isolate catalog snapshots by limit

* review: reassert host truth on unchanged polls; content-address snapshots

Client — the `changed` gate meant an unchanged poll skipped setWorktrees /
setLastKnownWorktrees / setCachedWorktrees, so optimistic local edits
(togglePin, handleDeleteWorktree's failure re-add) and the #8498 cache guard
were no longer repaired while the host catalog was stable. The gate bought
nothing: setCachedWorktrees is an in-memory Map write and areWorktreeListsEqual
already ran every poll, so the steady state still short-circuits on array
identity. All wire savings are unaffected. admit() now just returns the
confirmed rows and HostScreen applies them exactly as it did pre-PR.

Also on the client:
- a stale response from a superseded client/host no longer clears the token the
  current client/host just established
- discriminate on `worktrees` rather than on `'unchanged' in response`, so a
  future catalog field named `unchanged` can't reclassify a full response
- useRef over useMemo for the snapshot client; React may discard memoized values
- hoist WORKTREE_PS_FULL_LIMIT so the truncates-at-200 rationale travels with it

Host — replace the per-limit snapshot cache with a content-addressed id (ETag
semantics). Ownership lives in the id, so concurrent clients, differing limits,
and runtime restarts are correct by construction; this drops the LRU, the
eviction policy, the per-runtime WeakMap, and the retention of up to 8 full
catalogs. The remaining cache is a pure memo: because ids derive from content,
dropping or thrashing it costs CPU and nothing else. Keeping the memo also
keeps the measured steady-state cost — hashing every poll instead measured
2.24ms vs 0.75ms for the compare on a 310KB catalog.

Verified: mobile 2784 passed / 3 skipped, src/main/runtime/rpc 1064 passed,
node + mobile typechecks, oxlint, oxfmt, max-lines ratchet.

* fix(runtime): isolate catalog snapshot memo

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-31 23:12:13 -07:00
Brennan Benson 4c03cdff72 fix(mobile): mount host before opening tasks (#11853) 2026-07-31 20:46:51 -07:00
Brennan Benson ed00ab0f34 fix(ssh): restore relay ownership after app restart (#11860) 2026-07-31 20:45:52 -07:00
Jinwoo HongandOrcaWin c09a2ee251 fix(mobile): open resume workspace route reliably (#11876)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-31 20:42:05 -07:00
Brennan Benson 402e49203d fix(codex): keep persistent panes logged in after home routing (#11720) 2026-07-31 18:33:26 -07:00
072133fb27 fix(preflight): route landing banner through the runtime-aware preflight slice (#11390)
* fix(preflight): route landing banner through the runtime-aware preflight slice

Landing called window.api.preflight.check directly, which always probes the
local client. The preflight slice is the only caller that consults
getActiveRuntimeTarget and forwards to preflight.check on the active runtime
environment, so while connected to a remote runtime the landing banner
reported the client machine's git/gh state instead of the server's.

Delegate to refreshPreflightStatus and derive the issue list from
state.preflightStatus. This also drops Landing's duplicate probe: the slice
dedupes concurrent and forced checks, so the mount/focus/poll paths now share
one in-flight request with the rest of the app.

* fix(preflight): refresh landing status across runtime sessions

* test(preflight): cover paired runtime session races

* test: make landing preflight oracle behavioral

* fix(preflight): scope runtime session invalidation

* test(preflight): cover headed runtime switching

* test(preflight): isolate runtime status toast

---------

Co-authored-by: Marty <marty@localhost>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-31 18:01:24 -07:00
OrcaWin 33ad64b1c8 fix(runtime): bound persisted graph hydration (#11832) 2026-07-31 17:56:40 -07:00
Brennan Benson 377b580bab Restyle voice dictation feature tip (#11842)
* Restyle voice dictation feature tip

* Remove workspace name from dictation preview

* Refine voice dictation tip instructions

* Clarify voice dictation setup action

* Fix voice dictation tip keyboard behavior

* Use neutral voice dictation demo prompt
2026-07-31 17:51:03 -07:00
Neil 5738d61fe0 fix(workspaces): guarantee Korean flag kr shortcode (#11858) 2026-07-31 17:33:35 -07:00
Brennan Benson a53c5d3fb0 fix(mobile): stop serving a pre-write host-list snapshot to loads issued after the write (#11458)
* fix(mobile): stop serving a pre-write host-list snapshot to loads issued after the write

removeHost/persistHost await hostListMutation, but the in-flight loadHosts()
de-dupe handed back a pass that started BEFORE the write committed, so a load
issued after removal repainted the removed host card (#8791). Every durable
write now drops the shared pass via host-list-load-sharing.ts so the next
caller reads fresh; concurrent loads with no write between them still share
one Keychain pass.

Also extracts the host action sheet into host-list-action-sheet-actions.ts to
pin closeBeforePress on Edit host + Remove (the freeze half of #8791, already
fixed by #8536).

* fix(mobile): invalidate host loads after token writes

* fix(mobile): protect host token cache from stale reads
2026-07-31 17:26:42 -07:00
fsdwen 1a0a1ce4d0 fix(i18n): correct mistranslation of Grace/grace period in Chinese (#11505) (#11507) 2026-07-31 17:18:36 -07:00
Neil e79304ccca feat(workspaces): add Korean flag shortcode (#11845) 2026-07-31 17:16:49 -07:00
Neil 3c05e03c6f Revert "feat(workspaces): add Slack emoji aliases (#11837)" (#11843)
This reverts commit adc56a71f2.
2026-07-31 17:09:41 -07:00
Neil adc56a71f2 feat(workspaces): add Slack emoji aliases (#11837) 2026-07-31 16:39:38 -07:00
Brennan Benson 9bf05b0a9c Prevent Agent sleep while orchestration dispatch is active (#11808)
* fix(agent-sleep): keep active dispatch workers awake

* fix(agent-sleep): harden background work detection
2026-07-31 16:35:33 -07:00
Neil 676964b099 ci: run only changed e2e specs on pull requests (#11834) 2026-07-31 16:25:13 -07:00
Rod BoevandOrcaWin f56e6ade80 fix(ssh): recover orphaned relay install locks (#9828) (#10207)
* fix(ssh): recover orphaned relay install locks (#9828)

* test(ssh): split staged upload relay specs (#9828)

* fix(ssh): verify staged relay upload namespace

* fix(ssh): bound stale relay stage cleanup

* fix(ssh): complete bounded stage recovery

* fix(ssh): generate valid PowerShell stage scripts

* fix(ssh): make staged upload cancellation safe

* fix(ssh): fence staged relay recovery

* test(ssh): align deploy timeout oracle

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-31 16:17:37 -07:00
OrcaWin 139f756064 Add recursive sleep actions for workspace descendants (#11810) 2026-07-31 16:15:20 -07:00
Brennan Benson e4937956b3 Improve disconnected server recovery copy (#11827) 2026-07-31 16:03:59 -07:00
475f63ea1b fix(remote): scope renderer throttling to paired terminal publication (#11581)
* fix(remote): unthrottle host renderer while serving a paired client

A paired desktop host left in the background could not open or close
agent sessions for its remote/relay client: the action stalled and
eventually failed with the host-side "Timed out waiting for terminal
surface after creation" (10s) error, while an already-live terminal's
keystrokes stayed fast.

Root cause: creating/closing a session routes through the host
renderer's setTimeout-coalesced graph sync to publish the terminal
surface, but the host window runs with Electron background throttling
(the hidden-window default, reaffirmed on macOS). When the window is
backgrounded/occluded, those renderer timers are throttled to a crawl
and the surface publication misses the 10s deadline. Live keystrokes are
unaffected because PTY I/O flows through the main process, never the
renderer.

Keep the authoritative renderer unthrottled while at least one remote
client is connected and restore the throttled power-saving default once
the last one disconnects. Connect/disconnect are driven from the shared
MobileSocketWiring onReady/onClose, so both direct-WS and cloud-relay
clients are covered; headless serve has no window and is a safe no-op.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(remote): tidy renderer-throttle comment and test per review

Address automated review nits on #11581:
- Trim the module-level rationale comment to the non-obvious contract,
  matching the repo's concise-comment guideline.
- Drop the dead `detachedThrottle` variable from the reapply test; the
  detached-target scenario is already covered by the lazy-resolution
  test, so the case now asserts only what it exercises.

No behavior change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(remote): scope paired terminal publication throttling

Keep headed paired terminal creation and close renderer-owned so host inventory, input routing, ACK recovery, and cleanup retain the established lifecycle. Hold a reference-counted background-throttle lease only while the renderer publishes a paired operation, and epoch-fence async resolution so renderer reloads reject before any request or PTY spawn. Preserve headless main ownership and prevent paired clients from falling back to a local terminal.

* test(e2e): verify minimized host terminal repaint

* fix(remote): preserve paired terminal inventory through graph gaps

---------

Co-authored-by: fanyunqian.1 <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-31 16:01:44 -07:00