* rm git shim
Drops the terminal git/gh PATH wrapper and its settings toggle. Renames the no-marker shell-ready launch config after what it does.
Co-authored-by: Orca <help@stably.ai>
* rm git shim: clear stale state from older installs
Deletes the orphaned wrapper dir and scrubs inherited env/PATH, so a daemon that outlives the upgrade cannot keep seeding it. Drops a now-unread spawn option.
Co-authored-by: Orca <help@stably.ai>
* rm git shim: cover the daemon and headless paths
Scrub after the PATH prepends (they re-read process.env on the sparse daemon env) and run the cleanup above the serve branch so remote hosts get it too. Retry a locked removal; match PATH case-insensitively.
Co-authored-by: Orca <help@stably.ai>
* rm git shim: keep the scrub final
Refuse to re-prepend a legacy entry during agent-teams PATH promotion, which runs after the scrub. Cover the removal guard.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
The build-time repair layer carried overrides that rewrite already-correct CJK
values back to English. Most are inert against today's catalogs but fire on the
next regeneration, so they read as latent regressions rather than policy:
- zh workspace status picker (Play/Flag/Zinc/Rose/Emerald/Amber/Violet/Sky/
Blue/Neutral) and `sheet`/`page` were pinned to English while every sibling
option, and ko/ja/es, stay translated — half a Chinese picker.
- The zh `蓝色的`/`琥珀色`/`中性的` phrase fixes correctly flagged the adjectival
的 form but replaced it with English instead of the bare color noun.
- ja `Play` was pinned to English though the catalog already reads 再生.
- A value-wide zh `Open: '进行中'` mapped every "Open" to "in progress",
including the button that opens an MCP config file. "Open" is a verb (打开)
on buttons and a state (开放) beside 已关闭, so no single mapping fits.
Catalog corrections in the same area:
- The GitHub/PR state picker key override read 진행 중 / 进行中 for ko and zh
while ja already had the correct オープン; now 열림 / 开放, matching 닫힘 /
已关闭 on the sibling entry.
- The terminal cursor-color group is the on-screen cursor, not the Cursor
editor; ja already had カーソル, ko/zh now get 커서/光标 instead of "Cursor".
- Tailwind swatch labels 天空 (the sky) and 锌 (the metal) do not read as
colors; now 天蓝/锌灰, and ja 空 becomes 空色.
- The ko disk-usage heading was pinned to bare "Space" while its own
description says 저장 공간; both now use 저장 공간.
Two policy tests pinned the Play de-localization. They diagnosed the input
correctly — 玩 / 遊ぶ are wrong for a play icon — so the expectations move to
播放 / 再生 rather than English.
Destructive drift (localized -> English on regeneration) drops from 40 to 21
for zh, 6 to 5 for ja, and 5 to 3 for ko. What remains is deliberate: search
qualifiers, path and filename literals, and product names.
The override for SshTargetForm.137e88ce8d held a truncated relay-TTL sentence
ending mid-clause at "최대:", which renders "Timeout after disconnect
(seconds)" — the sibling key 55c56cf2c7 — not its own English source. #12192
only corrected the terminals token inside that wrong sentence. Point it at the
value ko.json already ships, so a catalog repair cannot overwrite the correct
string with the wrong one.
Fixes#12113.
shouldPreserveEnglishValue keyed on the English value, so any key whose source
string equalled a NEVER_TRANSLATE_VALUES entry was forced back to English on
every repair run — agent, commit, repo, terminal and Continue were all on that
list. Measured on a clean checkout: ko 279, ja 461, zh 1180, es 479 values
rewritten, the large majority destroying translator work.
17 generic terms move into locale-generic-ui-terms.mjs, and the brand revert now
skips a term's canonical rendering, so genuinely nonsensical forms (zh 回购,
ja/zh 端子, es Comprometerse) still fire while 터미널/커밋/エージェント survive.
Brand, path, and code tokens are untouched — MD -> 医学博士 and HEAD -> CABEZA
are why that list still earns its keep.
No catalog values change; every file is under config/scripts/.
Co-authored-by: AnddyAgudelo <44873492+AnddyAgudelo@users.noreply.github.com>
Nine ko values said something other than the English source. The riskiest is
SourceControl.6d7f2a47e5 "Discard folder", rendered as 폴더 삭제 ("delete
folder") next to a sibling delete-untracked action. Others: "Only branches Orca
named itself" read as "branches named Orca"; "staged changes" as 단계적
("phased"); "first-party cloud" as the mojibake 1方클라우드; "discard the
deletion" as "the deletion is deleted"; "Stage all changes" as a sentence
meaning "prepare"; and Recipes as 조리법 (cooking recipes).
EphemeralVmsPane.skillTitle is dropped from the PR's test and override — the
key was renamed to cloudVmSkillTitle on main, so the assertion would resolve to
undefined.
Co-authored-by: ShinSungkyu <kxu4583@naver.com>
The shared Automation tour copy was rendered without passing through
translate(), and the overlay surface hardcoded its default Next and Done
labels. Copy is keyed off the step id rather than its position, so inserting a
step ahead of them cannot shift the text onto the wrong step.
Co-authored-by: 5Hyeons <ohs2251@naver.com>
* Allow clearing all agents from AI Vault session history filter
Add "Select all" / "Clear" buttons so users can quickly isolate one agent without unchecking each box individually. Previously, at least one agent had to remain enabled; now users can filter to zero agents and re-enable selectively.
* Address PR #12128 review feedback
- Make Select all / Clear real DropdownMenuItems so Radix roving focus reaches them by keyboard.
- Rename the zero-agent empty state to a neutral "No agents selected" now that zero agents is a valid filter.
- Use 모두 해제 for the Korean Clear label instead of 지우기 (erase).
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* fix(macos): add a Full Disk Access nudge to reduce recurring TCC prompts (#9756)
macOS shows the "Orca wants to access other apps' data"
(kTCCServiceSystemPolicyAppData) prompt and it can keep reappearing. The
reappearing loop is not a fixable app bug: it is TCC identity churn — an
unsigned local rebuild mints a new code identity each build, so macOS treats
each as a new app — and Orca's other-app reads are already gated behind opt-in
settings or explicit user actions.
The durable remedy for the population we can help (release users) is Full Disk
Access, a superset macOS grant that stops these prompts for a stable identity.
Surface it with an ambient, dismissable sidebar card that reuses the existing
developer-permissions IPC. macOS-only; probes FDA status at most once per
renderer session (the probe itself reads protected data, so it must not repeat
on focus/remount); "Open System Settings" opens the Full Disk Access pane;
permanent localStorage dismissal.
* fix(macos): stop the FDA nudge promising macOS will stop asking
The card said Full Disk Access makes "macOS stop asking", but the grant
covers this app while terminals are spawned by the detached PTY daemon
(daemon-init.ts forks execPath with ELECTRON_RUN_AS_NODE + detached:true,
reparented to launchd), which macOS treats as its own TCC identity. A user
who followed the card would grant FDA and still be prompted from terminals.
Scope the claim to reducing prompts and name the terminal caveat.
* fix(macos): drop stale focus refreshes in the FDA nudge
refreshFullDiskAccessStatus() applied whichever getStatus() round-trip
resolved last. Rapid blur/focus puts several in flight, so an earlier
pre-grant 'unknown' landing after a newer 'granted' un-hid the card and
also wrote 'unknown' into the module-level session cache, re-nagging a
user who already has Full Disk Access for the rest of the session. The
adjacent FullDiskAccessSetupPrompt already guards this with a refresh
sequence; mirror it here.
Also unmount React roots in afterEach: clearing document.body left them
mounted, leaking each test's window focus listener into later tests.
* test(macos): unmount the StrictMode FDA nudge root between tests
The afterEach unmount added in 5a0f717 only covers roots created through
renderNudge(). The StrictMode probe test builds its own root, so it was
never unmounted and its component stayed live for the rest of the file.
Today that component has no window focus listener, so nothing breaks; add
a CTA click to it and the same contamination 5a0f717 fixed comes back —
the two tests after it see extra getStatus() calls and fail. Register the
root so the fix covers every mount site.
* fix(macos): attribute the FDA prompts to agent activity, not Orca's own reads
The card said the prompts happen "when this copy of Orca reads protected app
data", but Orca's own reads are small and gated; #9756's trigger is agent
find/grep sweeps into ~/Library/Containers, which macOS bills to Orca because
Orca is the responsible process for every terminal child. Blaming Orca reads
as an accusation and hid why FDA works at all — the grant attaches to Orca
rather than to each churning child binary.
Name agents as the trigger, keep the "reduce" hedge and the terminal caveat,
and drop the "this copy of Orca" dev-build hedge that cost a clause. Assert
the causation wording so it can't silently regress.
* fix(macos): explain the TCC prompts on the settings row, drop the sidebar card
The sidebar nudge added in 344d466b was premised on FDA being reachable
"only inside onboarding". It isn't: Settings > macOS Permissions has had a
full-disk-access row all along (searchable), the Setup Guide hosts the same
prompt from both a settings pane and a re-openable modal, and the sidebar
already links to that modal via the "Onboarding checklist" entry. The card
added a fifth affordance to the same sidebar that already had the fourth,
so it bought prominence rather than access - shown to every macOS user
without FDA, most of whom never hit #9756.
Keep the part that was actually new. The settings row still described the
prompts as something projects and worktrees trigger, which is the same
misattribution the card carried: the reads come from the agents Orca runs,
and macOS names Orca only because it is the responsible process for every
terminal child. It also never mentioned that the grant has to cover Orca
Helper, or that the preserved daemon keeps stale TCC state until restart.
Non-English catalogs get the English string as a placeholder; the bootstrap
translators key their cache on the English value, so a changed string is
re-translated on the next run.
* feat(macos): nudge Full Disk Access only after macOS repeatedly prompts
The FDA hint is only worth showing to users macOS is actually prompting.
tccd emits one AUTHREQ_PROMPTING line per consent dialog it displays,
carrying the service and both identities, so a narrow log-stream predicate
detects the real thing without correlating across lines or guessing whether
a dialog appeared. Verified against a captured dialog: the predicate matched
1 line out of 1436 TCC lines in ~28s, because routine preflight checks - the
overwhelming majority of TCC traffic - do not emit it.
Count dialogs where Orca is the responsible process, persist across launches,
and tell the renderer on the third one. The event separates the accessing
binary from the responsible app, which is the crux of #9756, so the toast can
name the tool that triggered it rather than blaming Orca generically. One
toast per user, with a permanent opt-out; it deep-links to the FDA row in
Settings > macOS Permissions rather than restating the guidance.
macOS-only: the watcher no-ops elsewhere, the web client stubs the API, and
the child is killed on before-quit since log stream ignores a closed stdout.
* test(macos): pin the platform so the TCC watcher tests exercise the darwin path
start() is darwin-gated, so on Linux CI it no-opped and the stream/kill
assertions passed vacuously against a watcher that never spawned. Pin
process.platform per the existing convention (shared/secure-file.test.ts),
and cover the gate itself with an explicit non-darwin case.
* fix(macos): start the TCC watcher from app bootstrap, not the window wiring
attachMainWindowServices is called directly by its own unit test, so wiring
initTccPromptNotice there made `vitest src/main/window/` spawn real `log stream`
children that outlived the run - two orphaned watchers were left behind by a
single test session. Only the IPC handler registration stays there; the spawn
moves to the real app bootstrap in index.ts, which tests never execute.
Verified: running the suite that leaked now leaves the watcher count unchanged.
* fix(macos): clarify repeated permission notice
* fix(macos): keep TCC notice lifecycle safe
* fix(macos): retain pending TCC notice delivery
* fix(macos): acknowledge TCC notice delivery
* fix(macos): release failed TCC notice claims
* fix(macos): retry transient TCC notice display
* fix(macos): contain TCC notice IPC failures
* fix(macos): harden TCC notice renderer lifecycle
* fix(macos): contain TCC notice dismissal failures
* test(macos): satisfy promise executor lint
* fix(macos): detect helper-attributed TCC prompts
* fix(macos): align TCC watcher lifecycle and helper identity
* perf(macos): defer TCC log reader until first paint
* fix(macos): recover deferred TCC watcher startup
* fix(macos): recover TCC watcher from deferred quit
* fix(macos): localize recurring file access notice
* fix(macos): preserve TCC watcher and localized guidance
* fix(macos): avoid duplicate TCC watcher recovery
* fix(macos): wait for locale before TCC notice
* perf(macos): isolate TCC notice subscriptions
---------
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* fix(terminal): make Zellij/TUI OSC 52 clipboard copy work by default
Zellij and other multiplexers copy via OSC 52. Empty Pc is a valid XTerm
default for clipboard, but we rejected it, and the feature defaulted off so
copy silently failed inside Zellij. Accept empty Pc as clipboard, default the
setting on (query still blocked; size capped), and surface Zellij in settings.
Closes#10567
* fix(review): make the OSC 52 default actually reach existing installs
Review fixes for #10588:
- Persistence: profiles saved under the old off default persisted `false`,
which is indistinguishable from a real opt-out, so the default flip never
reached #10567's reporter. Added the repo's one-shot stamp
(terminalAllowOsc52ClipboardDefaultedOnForAllUsers) so unmigrated profiles
flip once and a later opt-out sticks.
- Replay: reattach/cold-restore re-writes recorded PTY bytes through the same
parser, so a stale `\e]52;c;...` silently clobbered the clipboard on every
restart. Gated behind isPaneReplaying via a new resolveOsc52ClipboardGate.
- Blocked toast latches once per renderer session and could be burned by a
pre-hydration read; it now fires only for a real opt-out.
- An empty Pd decoded to '' and, with the gate default-on, silently blanked
the clipboard. Now rejected as invalid.
- Localization: en.json is bundled and the catalog beats the code fallback,
so all three copy changes were inert. Resynced across five locales.
- Corrected the empty-Pc rationale: tmux (not Zellij) emits `\e]52;;<b64>`.
* test(terminal): cover the OSC 52 gate wiring and settings copy
Extracts createOsc52OscHandler so the replay/hydration gate wiring is
covered, not just the pure gate — dropping the isReplaying getter now
fails a test instead of passing silently.
Adds catalog assertions for the two OSC 52 settings strings. Only the
toast key was pinned, so the same inert-copy regression (code fallback
edited, bundled en.json not) could still ship for the settings pane.
* docs(settings): note that the OSC 52 default only covers new profiles
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): migrate the web settings store to the OSC 52 default-on flip
The default-on flip only reached the Electron store. The web/remote client
keeps its own settings in localStorage, so a profile that persisted the old
`false` there stayed opted out — the same bug the Electron migration fixed,
in the second store.
Extract the migration into shared/osc52-clipboard-settings.ts and call it
from both stores. Also coalesce OSC 52 writes onto a microtask so a hostile
chunk of ~15-byte sequences cannot fan out into a million clipboard writes,
and latch the blocked-write toast after it renders rather than before.
* feat(terminal): tell users when the OSC 52 flip overrides their opt-out
The default-on migration cannot distinguish a deliberate opt-out from a
profile that simply never touched the setting — both persisted `false` under
the old default. Flipping everyone is the only way to fix#10567 for existing
installs, but doing it silently reverses a security choice the user made.
Arm a one-shot notice at load when the migration overrides a persisted
`false`, on both settings stores, and show it once the renderer hydrates.
Profiles that never opted out are never notified.
* fix(terminal): clear the OSC 52 notice after it renders, not before
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): keep the web OSC 52 notice armed against an unmigrated host
The host store always projects osc52ClipboardDefaultOnNoticePending, so the
plain spread in the web client's runtime UI merge overwrote an arm raised by
its own localStorage settings migration — flipping the opt-out in silence.
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): stop the OSC 52 notice overclaiming, and cover it
Round-3 review fixes:
- Rename the arming predicate to osc52ClipboardDefaultOnOverridesPersistedOff.
Both stores rewrite the whole settings object on every save, so every profile
saved under the old off default holds `false` — the deliberate-opt-out cohort
is not distinguishable on disk. Name, docs and test names now say so.
- Read settings before the UI snapshot in readLocalWebUIState: getStoredSettings()
arms the notice, so reading first snapshotted a pre-arm state that callers wrote
back, erasing an arm the stamp can never raise again.
- Give the notice toast a stable id; StrictMode re-runs the effect against the
same closure, so the early return cannot catch the second pass.
- Restore guardParserHandler parity in the coalescer microtask.
- Drop the unverified Zellij claim justifying all-selections routing; that routing
predates this branch and PRIMARY routing stays an open question.
- Cover the notice hook (order, single-fire, deep-link), the armed flag reaching
disk and surviving a clear, and pin the notice catalog to its code fallbacks.
Co-authored-by: Orca <help@stably.ai>
* test(terminal): pin OSC 52 setting discovery by product name
The migration notice says to turn it off in Terminal settings, so searching
Zellij/Grok/tmux has to find it. Also note why the OSC 52 write-back clauses
stay despite an unrelated always-true clause in the same condition.
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): consume the OSC 52 notice on close, and cover the guards it relies on
The notice was cleared the moment the toast was enqueued, so a quit inside its
15s window spent the profile's only warning on a launch where nothing was ever
seen — and the settings stamp means it can never re-arm. Clear on
onAutoClose/onDismiss instead, plus explicitly in the action handler, because
sonner's action path deletes the toast without firing onDismiss.
Also closes three coverage gaps a review found:
- ui.set must accept osc52ClipboardDefaultOnNoticePending. The update schema is
strict, so dropping the key rejects the whole call rather than stripping it,
and the renderer only logs that failure — every paired client would re-toast
forever with nothing red.
- the coalescer's try/catch and .catch had no test; the rejection case needs a
plain function because vi.fn tracks settled results and hides the leak.
- pin that every selection kind (including bare `p`) lands in the system
clipboard, so routing PRIMARY separately later is a deliberate break.
Co-authored-by: Orca <help@stably.ai>
* test(web): pin that ui.get arms the OSC 52 notice when it runs the migration
readLocalWebUIState reads settings before the UI blob so the migration's arm is
in place before the snapshot every caller writes back. Seeding localStorage
after install is what makes ui.get the first settings read, and therefore what
makes swapping those two lines fail.
Co-authored-by: Orca <help@stably.ai>
* test(store): cover the OSC 52 notice clear and its hydration
The clear sets local state before persisting so a rejected ui.set cannot leave
the toast re-firing for the rest of the session; losing the persist only re-arms
the notice next launch.
Co-authored-by: Orca <help@stably.ai>
* docs(terminal): state the real residual risk of default-on OSC 52
Three comment corrections from review:
- the safety note claimed exfil was the risk; queries are blocked, so it isn't.
The actual accepted risk is execute-on-paste: decoded text goes to the
clipboard verbatim, newlines included. Filtering here would break multi-line
TUI copies, which is the feature; bracketed paste is where that is handled,
and kitty/Ghostty take the same posture.
- the coalescer bounds a flood per parse yield, not overall.
- the replay gate reads at parse time while queued live bytes are drained
before the guard engages, so a copy racing a reattach is dropped silently.
Co-authored-by: Orca <help@stably.ai>
* test(terminal): close the four OSC 52 gaps a full revert walked through
Mutation testing found four assertions that stayed green against the very
change they were written to pin.
The notice suite passed 8/9 against a complete revert to clear-at-enqueue:
`calls[0][1][callback]?.()` is a silent no-op when the option is absent, and
the call count was already satisfied by the enqueue-clear, so nothing
separated "cleared by this callback" from "cleared earlier". Assert the
option exists and the notice is unspent before invoking it.
The stable toast id was deletable with all 9 green despite the adjacent
comment calling it load-bearing for StrictMode. Pin it.
The blocked toast's latch-after-throw fix was unproven: both orderings pass
when `toast.info` succeeds. Only a throwing first call tells them apart.
Deleting the hook call in App.tsx silenced the desktop notice with every
suite green. Pin it alongside the static Toaster import, since sonner drops
a toast enqueued before any Toaster subscribes and never replays it.
Also retone the coalescer-latch comment, which claimed the reset ordering
was load-bearing on its own; the try/catch reaches the same end, so the
test binds the pair.
All four verified green->red by mutation, then restored.
* test(terminal): cover the OSC 52 notice and its guards
Add tests pinning the static Toaster mount required to prevent notice dropout (#10567), the stable toast ID deduping StrictMode double-invokes, that the notice stays unspent on toast throws, and that flush-latch guards prevent silent consumption across error boundaries.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
The theme picker count row concatenates "Showing {count}" directly with
the " of {{value0}}" fragment. The ko/ja/zh translations dropped the
fragment's leading separator, so the shown and total counts fused
(e.g. Korean rendered "표시 중 3030 중" instead of "표시 중 30/30").
Restore a slash separator for the total-count fragment and the leading
space for the search-match fragment in ko/ja/zh, in both the runtime
catalogs and the key-override sources so catalog regeneration keeps the
repaired values. Add a regression test covering both fragments.
🤖 Generated with Claude Code
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.
Correct Korean locale mistranslations, preserve cross-locale overrides while splitting KO data, and add regression coverage for key-specific localization repairs.