* Reflow and edit hard-wrapped prose within single paragraph blocks
Instead of splitting consecutive markdown source lines into multiple visual paragraph nodes during document initialization, preserve them as a single paragraph containing literal newlines.
- Use `white-space: normal` CSS to reflow soft breaks naturally.
- Introduce `deleteAdjacentEmptyParagraph` to handle Backspace/Delete without converting soft newlines to hard break elements.
- Update the cut handler to delete only a visual line on Cmd+X within hard-wrapped paragraphs.
- Avoid split-pane/sync phantom dirty states caused by structural block splitting.
* Document why normalizeEmptyListItems is used for paragraph reflow
Add comments to clarify that normalizeEmptyListItems preserves
hard-wrapped paragraphs as single paragraphs, allowing them to
reflow via CSS instead of being split on load or external sync.
* fix(ai-vault): scan sessions by execution host
* fix(ai-vault): route history resume by host
* test(e2e): cover SSH AI Vault history
* Generalize remote session scanning for all AI Vault agents
Replace the Codex-only remote SSH session history scanner with a
unified scanner supporting all registered agents. This ensures remote
transcripts for Claude, Gemini, Devin, Droid, and others are scanned
and listed alongside local history.
- Propagate host metadata (host ID and platform) to scanned sessions
- Scope remote actions by host, disabling local OS path actions on
remote session logs
- Resolve ambiguous project/worktree matching for overlapping paths
by verifying matching host setup IDs
- Update tests and E2E specs to validate multi-agent remote scanning
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* Harden rate-limit PTY cwd and abort background usage probes on stop
Resolve a runaway CPU incident where background Claude rate-limit usage
probes could inherit a root working directory (such as `/` or `C:\`) and
index the entire disk.
- Force hidden Claude and Codex usage PTYs to spawn inside a small,
dedicated directory under user data or temp.
- Thread AbortSignal through rate-limit fetchers to immediately kill
and reap in-flight PTY processes when RateLimitService stops.
- Harden daemon and local PTY defaults to reject root-like working
directories for automated agent startups.
* Consolidate PTY path safety checks to prevent runaway CPU
Centralize `isRootLikePath` into a dedicated PTY path safety module
to prevent terminal launches and hidden usage probes from executing
in filesystem or drive roots, avoiding unbounded file discovery.
- Centralize path validation supporting POSIX, Windows, and UNC roots.
- Fail loudly if no safe default working directory is available.
- Enforce bounded directories for hidden usage PTYs and WSL probes.
- Check for aborted signals during rate-limit CLI repairs.
* Gate agent startup on the effective PTY cwd after default fallback
Co-authored-by: Orca <help@stably.ai>
* test(repos): verify origin/HEAD target in SSH base-ref tests
Co-authored-by: Orca <help@stably.ai>
* Pin HOME to assert exact default PTY cwd in spawn test
Pin `process.env.HOME` in the fallback test for LocalPtyProvider to
assert the exact resolved candidate rather than just checking that it is
non-root-like. This catches potential regressions where an unintended
home directory is picked, and uses a try/finally block to safely restore
the environment afterwards.
---------
Co-authored-by: Orca <help@stably.ai>
Older folder-based workspaces are tracked by `activeWorkspaceKey`
rather than the legacy `activeWorktreeId`. Deriving the active sidebar
workspace ID from the workspace key enables the "Reveal active
workspace" action to work correctly for both types of workspaces.
* fix(worktrees): fall back from stale default base refs (#7312)
* docs(worktrees): explain base fallback policy
* fix(worktrees): harden stale base fallback edge cases
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* Warn about and manage repository overrides for AI action recipes
This improves the user experience around overriding global AI action recipe
defaults with repository-specific settings:
- In global settings, display a note if repositories override a recipe,
with a shortcut to review those repository settings.
- In the agent launch dialog, show a warning if the repo overrides the
global default and default the save target to the repo.
- In repository settings, support saving and discarding recipe overrides
on a per-action basis.
* Memoize repo filtering and override summaries in recipe defaults
Avoid re-filtering all repositories and re-computing override summaries
on every keystroke in sibling textareas.
Also use an exhaustive switch check for override field labels, and add
a test verifying the overflow note indicator when overrides exceed the
visible limit.
buildWorktreePurgeState is the bulk worktree-removal reducer reached by the
authoritative-scan reconcile (CLI `git worktree remove`, another Orca window,
SSH), remove-project, and the hydration stale-purge. Unlike the single in-app
removeWorktree path — which runs shutdownWorktreeTerminals /
dropAgentStatusByWorktree / clearPaneForegroundAgentByWorktree — it never ran
terminal teardown, so it left every pane-scoped map untouched:
agentStatusByPaneKey, agentLaunchConfigByPaneKey, acknowledgedAgentsByPaneKey,
paneForegroundAgentByPaneKey, sleepingAgentSessionsByPaneKey,
unreadTerminalPanes, unreadAgentCompletionPanes, lastTerminalInputAtByPaneKey
(all keyed by `${tabId}:${leafId}`) and unreadTerminalTabs (keyed by tabId).
Result: one orphaned entry per agent pane of every externally-removed worktree,
retained for the whole renderer session (monotonic growth), plus a phantom +1
on the unread dock badge. This is a direct parallel to leaks the maintainers
already fixed in this same function (browserAnnotationsByPageId, editorCursorLine
— each carrying a 'the bulk reconcile path missed them' comment).
Fix: evict these maps by tab-id / `${tabId}:` prefix in the reducer, matching
the in-app teardown. retainedAgentsByPaneKey and runtimeAgentOrchestrationByPaneKey
are intentionally left out — both self-heal (pruneRetainedAgents on a
worktreesByRepo change; the runtime map is replaced wholesale each sync).
Leak-regression test drives purgeWorktreeTerminalState and asserts every map is
emptied for the removed worktree while a sibling worktree's state is preserved.
Reverting the fix fails both cases.
Co-authored-by: Orca <help@stably.ai>
* perf(windows): dedupe per-pane process-table scans in agent inspection
Windows agent foreground-process inspection forks a whole-process-table
PowerShell/CIM scan per pane on the same 750ms/2000ms cadence the POSIX path
uses. The POSIX side routes through getProcessTableSnapshot (500ms TTL + single
in-flight, #6288/#6667), collapsing N concurrent panes to ~2 scans/sec. The
Windows path (queryWindowsProcessDescendants) had no such dedup: K concurrent
agent panes forked K powershell.exe cold-starts, each enumerating the ENTIRE
process table then filtering per-pid in JS — ~10-40x heavier than `ps` (a
powershell cold start is ~150-400ms CPU + tens of MB RSS). The degraded/local
PTY provider path calls it with no per-pane throttle at all. This is the
Windows analogue of the idle-CPU churn #6288 fixed for POSIX.
Generalize the existing createProcessTableSnapshotReader factory to be generic
over its scan result (default T = string, so the POSIX path and its test are
byte-identical) and add a Windows singleton reader that caches parsed
WindowsProcessRow[]. queryWindowsProcessDescendants now reads the shared
snapshot and runs its own descendant walk; runWindowsProcessRows throws on total
enumeration failure so the miss is not cached and the prior null-fallback
contract (callers fall through to node-pty's name) is preserved.
Windows scan-volume regression test (mirrors the POSIX #6288 guard) drives
PANE_COUNT concurrent panes over the cadence window and asserts powershell.exe
spawns are bounded by ticks, not pane count, while every pane still resolves its
descendant. Reverting the dedup fails both cases. POSIX snapshot + volume tests
unchanged and green; node/web/cli typecheck clean.
Co-authored-by: Orca <help@stably.ai>
* test: reset windows process-rows snapshot between agent-foreground cases
The new module-level Windows rows reader caches for 500ms with real
Date.now(), so one case's mocked process table was served to the next
case's assertions (7 CI failures in agent-foreground-process.test.ts).
Mirror the suite's existing POSIX resetProcessTableSnapshotForTests()
with the Windows reset in beforeEach.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
Translate various remaining English strings in Spanish, Japanese, Korean,
and Chinese locale files to provide better localized terminology for
common UI actions, settings descriptions, and toast messages.
Register-PSRepository -Default failed inside the legacy nuget.exe provider
with "Missing option value for: '-source'" on the hosted windows-2022 image,
leaving PSGallery unregistered so the subsequent Set-PSRepository threw
"No repository with the name 'PSGallery'".
Prefer Microsoft.PowerShell.PSResourceGet (bundled with PowerShell 7.4+),
which has PSGallery registered by default and avoids that code path; fall
back to PowerShellGet with an explicit NuGet-provider bootstrap only when
PSResourceGet is unavailable.
Co-authored-by: Orca <help@stably.ai>
* Use official OpenCode SVG icon instead of remote favicon
Replaces the remote favicon loading for OpenCode with a local SVG icon.
This avoids flaky external network requests and ensures the icon renders
properly across light and dark themes using theme-aware currentColor.
* Update OpenCodeIcon SVG geometry to use official 512 canvas
Update the OpenCode icon geometry and viewBox to use the official
512x512 canvas sourced from the opencode.ai favicon. Using a square
viewBox matches sibling glyphs.
- Resolve true work item identity (issue vs. PR) using the URL path to
override stale or incorrect cached payload types.
- Prevent invalid PR start point resolution when launching an issue
misclassified as a PR.
- Validate and reject mismatched URL types in the worktree metadata
dialog fields to avoid incorrect associations.
* Fix missing space in import-cookies "From <browser>" menu labels
The Import Cookies dropdown rendered browser entries as "FromGoogle Chrome"
and "FromSafari" — JSX collapses whitespace between the adjacent
{translate(…, 'From')}{browser.label} expressions.
Switch both settings menus to the 'From {{value0}}' interpolation pattern
already used by the other import-cookies menus, so the label is a single
translatable unit and renders with the correct space. Interpolation also lets
each locale position the browser name correctly: ja/ko use postpositions
("から"/"에서") that belong after the name, which the old concatenation placed
before it. Localized the new key in es/ja/ko/zh to match the existing catalog
style. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix browser use import source label
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Keep PetOverlay runtime keyframes out of localization so translated locales cannot invalidate sprite or bob animations.\n\nAlso adds regression coverage for translated-locale keyframe CSS and removes the stale generated locale entries.
Store POSIX mode bits in secure-file hardening cache entries so permission drift is detected even when ctime granularity is coarse.
Also clears inherited HISTFILE in the local PTY test harness for hermetic WSL history assertions, and adds a deterministic coarse-ctime regression test for directory and credential-file mode drift.
* feat(ghostty): import adjust-cell-height and dual-value window paddings
Two Ghostty config forms previously landed in unsupportedKeys:
- adjust-cell-height percentages (e.g. "35%") now map to
terminalLineHeight (1.35), the direct xterm equivalent. Pixel values
are still rejected because they depend on the rendered cell height.
- window-padding-x/y "top,bottom" / "left,right" pairs now import as
the rounded average, preserving the total padding along the axis.
parseStrictInt moves to numeric-config-values.ts alongside the new
pair parser to keep mapper.ts under the max-lines budget.
* fix(ghostty): tighten import edge cases
Co-authored-by: Orca <help@stably.ai>
* fix(settings): sentence-case account runtime copy
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* feat(ghostty): resolve theme references during config import
`theme = <name>` is how most Ghostty configs pick their colors, but the
importer treated the key as unsupported and silently dropped the entire
palette. Resolve the referenced theme file and merge its colors as
defaults, mirroring Ghostty's own precedence:
- Search user themes first (XDG, then the native macOS dir), then the
bundled themes inside the Ghostty install, and parse the file with the
existing parseGhosttyConfig (theme files are plain config subsets).
- Explicit config keys win over theme values; config palette entries are
appended after the theme's so per-index overrides apply naturally.
- Only color-bearing keys may flow from a theme into the import, a theme
file cannot smuggle font/window settings past the user's config.
- Theme names containing path separators are rejected (no traversal),
files over 256 KB are ignored, and light:/dark: pairs plus unresolvable
names surface as annotated unsupportedKeys instead of vanishing.
* fix(ghostty): align theme resolution with Ghostty lookup
Co-authored-by: Orca <help@stably.ai>
* test: stabilize ghostty import CI coverage
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* chore(i18n): refine Spanish locale copy
Why:
Improve the Spanish UI copy so developer-facing terms stay natural and technically accurate.
Changes:
- Keep core dev terms such as PR, worktree, branch, and runtime consistent.
- Preserve locale key parity and placeholder compatibility with English.
* chore(i18n): localize new Spanish strings
* chore(i18n): use rama for branch in Spanish
* chore(i18n): clarify Spanish repository copy
* fix(i18n): correct Spanish locale defects found in review
Post-review polish on the Spanish copy pass:
- Restore dropped/altered meaning: 'repo color' (was 'en el repositorio'),
'uploaded' (was 'sincronizado'), 'is behind {ref}' (was '{ref} atrás',
which rendered the ref name as a quantity).
- Translate leftover English over prior correct strings: 'Review from'->
'Revisión de', 'Agents'->'Agentes', 'workspace'->'espacio de trabajo',
'clone'->'clon', 'Skill de Agent'->'Skill de agente'.
- Grammar/register: 'para commit'->'para hacer commit' (x3), 'desde issue'->
'desde el issue' (x4), 'Cuando tanto...y'->'Cuando ambos...', unify tú in
the sidebar-tint description, 'obligatorio'->'obligatorias' (agrees with
approvals), 'desbloquear'->'descongelar' for 'unfreeze', de-Spanglish the
local-folder-drop message.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Bare repo-backed terminal creates now reuse Settings agent defaults for exact agent commands while preserving raw commands, disabled agents, and already-managed launches.
Validation:
- PR Checks / verify passed
- Local runtime tests, typecheck, lint, CLI build, and Electron CLI/runtime smoke passed
* fix(terminal): pass Ctrl+Arrow to PSReadLine on local Windows ConPTY
On local Windows shells (PowerShell/cmd via PSReadLine) Ctrl+Left/Right
printed a stray "b"/"f" instead of moving by word. The terminal shortcut
policy translated Ctrl+Arrow to \eb/\ef (readline's Alt+b/Alt+f word-nav
bytes), but PSReadLine binds Escape to RevertLine and has no Alt+b/Alt+f
binding, so it consumed the ESC and self-inserted the bare letter.
PSReadLine already binds Ctrl+Left/Right to word-nav natively, so the
translation was breaking a working default.
Gate the translation so genuine local native Windows ConPTY panes fall
through to xterm's native \e[1;5D/\e[1;5C, while Linux and remote/WSL/SSH
readline shells keep the \eb/\ef translation. Reuses isLocalNativeWindowsConpty
(the same execution-host heuristic as the Kitty-keyboard fix) so SSH/WSL
panes on a Windows client are correctly excluded. Adds policy coverage for
the ConPTY-passthrough and SSH/WSL-still-translates paths.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(terminal): use live session for Windows Ctrl+Arrow
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Seed WSL Codex runtime config through the fresh-mirror preparation
The WSL runtime home seed copied config.toml verbatim, so relative
path-valued settings (model_instructions_file etc.) resolved against the
runtime home inside the distro and aborted Codex config load with
'os error 2' -- the same failure class #7157 fixed for host runtime and
managed account homes. Seed now applies the shared fresh-mirror
preparation (deprecated codex_hooks normalization + relative-path rewrite
anchored to the Linux-side source home + system hook-trust strip).
Also fixes CRLF configs skipping deprecated codex_hooks normalization:
the feature-section header regexes did not tolerate the trailing \r.
Co-authored-by: Orca <help@stably.ai>
* Extract prepareWslRuntimeSeedConfig and pin UNC->Linux anchor in tests
The e2e seed test's mocked WSL home is a plain local path, so the
parseWslUncPath linuxPath branch was never exercised. Extract the seed
preparation as a pure exported function and cover both UNC spellings
(wsl.localhost and wsl$) with hardcoded literals.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
The SSH reconnect dialog was auto-opened at render time for any active/restored
worktree whose SSH target was disconnected, blocking the entire UI even when the
user was working elsewhere. On app restart the previously-active worktree is
restored without a click, so the modal stole focus app-wide over unrelated work.
The disconnected state is now surfaced only through the non-blocking affordances
that already existed — the worktree card chip, the status-bar Connect action, and
the pane-scoped terminal reconnect overlay. The blocking dialog opens only on
deliberate focus (clicking the worktree card), and even then it is suppressed when
the active view is a terminal, since that pane already shows the in-context
reconnect overlay and a second prompt would just duplicate it.
Fixes#7314
Refines 291 Simplified Chinese (zh-CN) strings for terminology consistency and clarity. Rebased onto main with full en/es/ja/ko key + interpolation parity; fixed placeholder parity on 4 keys and 9 reviewed translation-quality issues.
Co-authored-by: linyunlong <yunlonglin1995@gmail.com>
* perf: overlap sidebar-scope loads with worktree scan at startup (#7225)
Continues the renderer-chain parallelization proposed in #7225 (proposal 2),
on top of the merged #7266:
- Run project-groups → folder-workspaces concurrently with the per-repo
`git worktree list` fan-out. Neither reads the repos store nor worktrees,
so a slow remote host's 15s scope RPCs no longer queue ahead of the scan.
- Raise worktree refresh concurrency 5 → 8 so multi-core machines run fewer
sequential scan batches, still bounded so one moment can't launch every
git probe at once.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Test overlapping sidebar scope loads and worktree hydration at startup
Verify that sidebar scope loads and worktree hydration operations run
concurrently before session hydration. This protects against regressions
in startup performance under the perf/startup-lag optimization.
Additionally, document the rationale for the worktree refresh
concurrency limit in the worktrees slice.
* Clarify worktree refresh concurrency comment
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Resolve terminal CWD and worktree paths to their canonical form using
realpath before validating containment. This blocks symlink escape
routes for local terminal spawns, returning the default workspace
directory if a requested path attempts to escape the worktree.
- Local terminal paths are canonicalized using native realpath logic
- WSL UNC paths and SSH/remote terminals skip canonicalization
- Floating terminal startup directories bypass containment checks
- Missing or unresolvable workspace directories default safely
* fix(automations): start scheduler in headless serve mode
* Trigger initial catch-up check for headless scheduled automations
Headless serve never receives a renderer-ready IPC, which previously
prevented the initial catch-up pass of due scheduled automations from
running on startup. Checking for the presence of a headless dispatcher
allows starting the evaluation pass immediately.
Additionally, refactor the corresponding test to use fake timers for
better reliability and deterministic assertions.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Creating a workspace hard-failed with "Could not refresh base ref …"
whenever the pre-create git fetch of a remote-tracking base (e.g.
origin/main) failed — offline, transient, or (common on Linux GUI) the
Electron process lacking SSH_AUTH_SOCK so `ssh -o BatchMode=yes` cannot
auth. This blocked creation even when a perfectly usable local
origin/main already existed and `git worktree add` from it would succeed.
Regression introduced by #2310 (5c93579e40), which replaced the prior
best-effort fetch + post-create reconcile with a hard network gate.
Fix: at all three create sites (local runtime, local IPC, SSH), only
throw when the refresh failed AND no usable local base ref exists;
otherwise create from the local ref (a possibly stale but valid base).
Also: move the SSH local-ref probe after session.registerRoot so relays
that gate generic git.exec don't false-negative and defeat the fallback.
Co-authored-by: Orca <help@stably.ai>
* fix: address pr-bug-scan validated finding from #6952
throwNodeNotFound() now re-raises AbortError when the shared signal is aborted, so a signal-cancelled node probe no longer launders into 'Node.js not found'; sequential fallback runs.
* fix(ssh): make session-limited (MaxSessions=1) relay deploys actually succeed
Review of #7180 verified the parent fallback end-to-end against a real
MaxSessions=1 sshd and found the connect still failed. Four gaps, in order
of discovery:
- isSshSessionLimitError missed stock OpenSSH, which refuses session
channels over MaxSessions with SSH2_OPEN_CONNECT_FAILED (2) and 'open
failed' — reason 4 never matched, so the fallback never triggered.
- execCommand settled aborted commands before the channel finished
closing, so the sequential fallback reissued execs while sshd still
counted the old session.
- SshConnection.waitForSshCallback rejected aborts mid-channel-open
immediately, leaking a confirmed-late channel that held the only
session slot; it now settles after the late channel closes (bounded)
and drains its streams so ssh2 emits 'close'.
- Session channel opens now retry transient session-limit refusals
(sshd frees the slot only after processing our close-ack, which the
next open can beat by microseconds), and the remote orca CLI shim
install is non-fatal like the managed-hook install — after the relay
bridge occupies the sole session slot, raw-connection extras must
degrade instead of failing the connection.
Verified live against Docker sshd (OpenSSH 9.2, MaxSessions=1): fresh
deploy (upload + native deps + launch), reconnect cycles, and a PTY
round-trip all succeed; unrestricted-sshd regression run also passes.
Co-authored-by: Orca <help@stably.ai>
* Handle ssh execution aborts immediately during retry backoff or hangs
- Cancel the session-limit retry delay immediately if the operation is
aborted during backoff.
- Limit the wait time to a 5-second grace period when aborted during a
channel open that is hung and never invokes its callback, rather than
waiting for the full connection timeout.
---------
Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
The release-blocking `terminal rendering golden mac` job was failing ~40%
of Cut Release runs with `Expected e2e repo to be loaded`, leaving the RC
stuck as a draft (publish-release depends on this job).
Root cause: the sharedPage fixture did a single-shot fetchRepos() + find()
+ throw. window.api.repos.add() fires a repos:changed echo that triggers a
concurrent fetchRepos() in the renderer; the store's reposFetchGeneration
guard then drops the fixture's own awaited fetch result, leaving `repos`
briefly stale, so find() returns undefined and throws. The repo lands a few
ms later (the failure screenshot's sidebar actually shows it).
Wrap the repo load in expect.poll (matching the seeded-worktree poll right
below it) so it retries fetchRepos until the repo lands, then runs the
idempotent updateRepo. Also harden the single-shot hasWebgl/cursorHidden
diagnostics reads in the golden spec: WebGL reattaches asynchronously after
a worktree switch, so poll those eventually-consistent fields until they
settle before the golden asserts. Regression detection is preserved: a real
WebGL/cursor regression times out the poll and still fails the test; the
geometry/wrap/overpaint golden checks stay single-shot.
- Prevent the "Stage All" button from being enabled when only nested
submodule worktree changes are present.
- Remove the disabled stage button on submodule worktree-only rows,
replacing it with an explanatory tooltip.
- Fix WSL terminal environment assertion in daemon PTY tests to allow
inherited agent-hook environment variables.
* Fix notes send targets for manual agents
* Split agent title merging into manual and launch-agent paths
Separate the merging logic for terminal titles depending on whether the
tab has a launch agent or is a manually started CLI.
- Launch-agent tabs carry an owner bit, allowing their live titles to
promote a stale status row on the same pane.
- Manually started agents have no owner bit, so they only ever add a
row and must not override existing status evidence.
- Remove the temporary TitleHintAgentTarget type and the need to strip
metadata when pushing targets.