mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
b024043feb58c97ec99c7f1817fdc6b3f20ccf83
14118
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b024043feb |
refactor(tabs): delete unused copy-tab and merge-group store actions (#28836)
* refactor(tabs): delete unused copy-tab and merge-group store actions copyUnifiedTabToGroup and mergeGroupIntoSibling had no callers outside the store and its tests. Tests that used the copy action as a setup step now create the duplicate tab directly, the same call the action made. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(tabs): follow the split-ratio file rename in the layout-writer baseline Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2de7381204 |
fix(relay): supersede a reserve seat from the feed once a later, newer join shows (#28716)
* test(relay): check invariant 4 (one demotion winner) in the step-5 simulation Every demotion now names its winner (the newer booking, or the row). The model flags a director that names a different winner for a divergence another already named, and a host whose two seats are each demoted for the other. A fault where directors break level ties by their own cell order shows the check fires. Violations are capped per invariant so one flood cannot hide another class. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * test(relay): bound unseen duplicates by the silence close and assert all invariants on contested ties A reserve seat the booking director's map had not seen (joined, then half-open within a poll) is never superseded and has no lease to re-check, so it lasts until the cell's control silence close (75 s + one 15 s ping). Invariant 3 now uses that bound for such seats, and the level-divergence config asserts every invariant. Stale maps now judge a divergence another director already demoted, so the config's "contested" counter (divergences judged by two or more directors) is the case invariant 4 guards. The silence-close constant now matches production (90 s, not 100 s). Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * test(relay): raise the floor on map-judged demotes and count only level contests A reconcile whose map has not seen another director's demotion still demotes in production, which raises its epoch floor; the model now does too. The contested counter counts only same-epoch pairs, the only ones invariant 4 can split. The keep-this-seat rule is one helper. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * refactor(relay): name the simulation's fault-kept seat check for the fault Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): supersede a reserve seat from the feed once a later, newer join shows A half-open seat the booking director's map had not yet seen was never demoted and held its cell until the 75 s control silence close. Directors now demote it once both joins are in the map; the simulation holds invariant 3 at the supersede bound for it. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): outrank only past cell clock skew, reuse demoteSeat, keep invariant 3's loose clock running Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * refactor(relay): share the outrank rule with the simulation, pin the skew boundary Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count only confirmed level demotions and every second judgment, and bound duplicates by placement records alone Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): a drained seat keeps its drain grace under a demote, and the feed reports each seat once Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * refactor(relay): name the outranked-report bound and the reconcile backstop Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f |
||
|
|
6f929849eb |
fix(mobile): workspace list host badge, "workspaces" wording, and search keyboard on the page (#28824)
* fix(mobile): workspace list host badge, wording, and search keyboard on the page - Host badge no longer shrinks to "m…"; the branch/path text gives up the space. - Search placeholder, accessibility label, and empty states say "workspaces". - The page's workspace list no longer closes the keyboard on each narrowing keystroke: react-native-web dismisses on-drag on every scroll event, including the offset clamp. * fix(mobile): let the row path take only the leftover space instead of pinning the host badge A non-shrinking badge overflowed narrow, indented rows; a zero-basis path keeps a short host name whole and still lets the badge shrink when the row is genuinely too narrow. * fix(mobile): reword the row path's layout comment * refactor(mobile): inline the page's keyboard dismiss choice and use flex: 1 for the row path Drop the platform split and its react-native-web test: an inline Platform.OS check states the same choice where it is used. flex: 1 renders identically to flexBasis 0 + flexGrow 1. |
||
|
|
941a0f2a8a |
fix(opencode): refuse a picked OpenCode model in any \\wsl$ repo (#28236)
OpenCode in a \\wsl$ repo runs in WSL whatever the project's setting, and Orca can't verify a model there yet, so picking one is refused, as it already is for a project set to WSL, instead of being checked on Windows. |
||
|
|
d40fbdba91 |
feat(native-chat): Share a chat visual from the chat (#28479)
* fix(files): never write through a dangling symlink A path that doesn't exist yet was authorized by walking up to the nearest existing folder. A dangling symlink fails realpath with ENOENT, so the walk stepped over it and approved the link's own path; the write then followed the link and created its target outside the allowed folders. The walk now continues from the link's target, and returns that real destination. * refactor(native-chat): rename the chat visuals folder to the chat scratch folder The per-chat folder agents write into is the chat's scratch space, not only a visuals folder. Its root becomes <state>/chat-scratch/<hash> (the hash is unchanged) and the agent variable becomes ORCA_CHAT_SCRATCH_DIR. The old ORCA_CHAT_VISUALS_DIR is never set and is still stripped from what every agent child inherits, Pi included. The visuals skill names the new variable and says the folder is temporary. * test(native-chat): keep the delivery test to the rename The launch parity snapshot already pins that every agent drops the pre-rename variable. * fix(files): refuse any dangling symlink in the missing-path walk Following a dangling link by hand resolved relative targets against the lexical parent, not the link's real folder: through a folder link the walk could loop forever or authorize the wrong file. Refuse instead: realpath can't say where a dangling link leads, but a write would follow it. * feat(runtime-files): the host serves a chat's scratch folder as a file root File commands accept `path:<this host's chat-scratch root>/<32 hex>` and resolve it only when it names this host's own folder, at the file-commands seam so the selector never reaches chat placement. They authorize against the project roots plus the chat-scratch root, refuse files.open/openDiff for the folder, and agentSession.readVisual's ok results carry the file's absolute path so a client can build the selector. * test(runtime-files): name the readVisual helper's parameter type * test(files): drop the loop case that duplicated the dangling-link refusal * test(runtime-files): run the readVisual RPC test, which opens a real SQLite store, under Node * test(runtime-files): put the same-suffix folder inside the authorized root so only the selector refuses it * refactor(native-chat): open a chat visual like any file "Open in new tab" on an inline chat visual now opens the visual's file the way any HTML file of the chat's workspace opens: a file:// browser tab for a local chat (its overflow menu gains "Open source file"), the document preview for a paired-host chat (with its existing source action and Share). Edits save on the chat's host through the exact path: selector the host serves, and a matching editor save re-reads the inline copy freshly. The read-only chat-visual tab is removed. * feat(native-chat): share a chat visual from the chat The inline visual's toolbar gains Share beside Open. It publishes under the file's own key on the chat's host, the key the opened preview and editor use, so every surface updates one link. The published text comes from a fresh read begun after the click; a failed read publishes nothing and says the visual couldn't be read. The toolbar stays shown while Share's popover is open. * fix(native-chat): a visual read without a path is a malformed reply A visual's path is always on the current host's readVisual answer, so the inline Open needs no branch for a missing one. Also prune the deleted chat-visual tab action from the layout-writer baseline. * test(native-chat): give visual read replies their path without longer lines * fix(native-chat): address a scratch file by its folder only outside every workspace A workspace that contains the host's state folder keeps its own address, so explorer drops, folder creation and renames inside it stay on one root. Document preview Share reads a runtime grant's own selector and root directly instead of passing the selector off as a workspace id. * fix(native-chat): show a chat visual's Share whenever it shows Every read now carries the visual's path, so Share no longer waits on one; its key comes from the path the click's fresh read returns. * test(runtime-files): wait for the stores to close before removing the state folder |
||
|
|
8f83f6b076 |
feat(wsl-mover): pause a moving project's terminals through Sleep and prove they exited (D1b-5d) (#28820)
* feat(wsl-mover): pause a moving project's terminals through Sleep and prove they exited (D1b-5d) * fix(wsl-mover): gate again under the fence, swap journal phases atomically, keep sessions frozen through commit (D1b-5d) * test(wsl-mover): the fence e2e walks the journal one phase at a time, as a move writes it (D1b-5d) |
||
|
|
5976c4628d |
fix(new-tab): Enter on a visited site's name opens the site, not a file (#28804)
* Rank browser history above fuzzy file matches in the omnibox Scattered-character fuzzy file matches are weak evidence, so a remembered page should appear above them. Exact and literal file matches and typed URLs still rank above history. Adds a test for typing a host like linear.app, which should rank the page above unrelated fuzzy files. * Anchor omnibox history on the typed URL instead of demoting fuzzy files The real bug: after visiting https://linear.app/, typing `linear.app` made Enter open an unrelated file. The history row removes the typed-URL row it duplicates, but was then placed below every file match, so the page lost the top slot the URL row had. History now sits with the typed URL row (in its slot when it replaced it). Queries with no typed URL keep the old rule: below every file match. This replaces the previous commit's rule of ranking history above "fuzzy" files. That label covers every non-exact match for queries with a slash, a dot suffix or a space, so a code-host page whose title holds the file path took Enter away from local rows for path queries (or left nothing selected when pasted). It also left `localhost` broken when a file name contained it. |
||
|
|
657a47c25c |
fix(pty): report agent start failures the same way from every launch path (#28724)
* feat(telemetry): count agent start failures from the host too The host spawn path (CLI, phone, orchestration workers, headless automations, worktree startup) now records agent_error when starting an agent fails, as the window path already did. Removes C5a's TEMPORARY recordsAgentError input; the host already threads each launch's telemetry, so failures get real kinds. * fix(telemetry): count a claimed start that several requests joined once Concurrent resumes of one agent session join one claimed start. When it fails, every joined request ran the host catch and recorded agent_error, so one failed start counted once per request. Only the request that ran the start records it now; the others still clean up. * fix(telemetry): only skip agent_error for a request that joined another start The host marked a request as joined before calling ensure, so a claim that refused the request on its own (conflict, capacity, unreachable owner) recorded no agent_error. ensure now reports the join itself, right before awaiting the other request's start. * chore: re-run CI after main's localization fix (#28810) |
||
|
|
d09605ee8e |
ci: run the Electron browser probes serially, out of the unit shards (#28799)
The three popup compatibility probes ran in the parallel unit shards and timed out at their 14s in-process deadline when other files starved the runner. Move them into the package job's serial Electron lifecycle step, and stop the six probes already in that step from also running in the shards. Claude-Session: p2-headless |
||
|
|
68b186e2aa |
fix(relay): end the restart-safe quiet at the drain's pace window, not a window after it (#28677)
* fix(relay): end the restart-safe quiet at the drain's pace window, not a window after it A paced drain tells its last host when the window ends, so the restart-safe wait has to see an empty runtime reaching past that point. It counted a full window of quiet samples from the first empty one instead, and the runtime only empties as the window ends, so every same-cap cell waited the window twice: about 25 minutes per Asia cell at 1200 s on 2026-10-13, and 5 minutes per 300 s cell. The window is now measured from the verifier's own start, which runs after the cell accepted the drain and so ends no earlier than the cell's own window. A pass still needs two consecutive restart-safe samples, the last taken at or after that end, and any non-zero runtime counter or open migration still restarts the count. Progress lines report paceWindowRemainingMs in place of the old sample target. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): drop the same-cap drain timeout's double-wait allowance and stale quiet wording The drain step's timeout added the window's excess over 300000 only because restart-safe used to wait a second window after the cell emptied, so it is now the 15-minute migration lease plus the window for every pace (35 minutes at 1200000, unchanged at 300000 and below). Docs, workflow comments and the shadow gate's settledAfterSeconds note now describe the window-end rule. The always-quiet test starts its clock late, so a window measured from zero fails it, and the overlapping late-control test is folded away. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * docs(relay): state the restart-safe window-end rule exactly Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * docs(relay): the slowest restart-safe wait is now 35 minutes Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f |
||
|
|
17959a90f7 |
feat(relay): measure each host hello's pre-auth time on the cell (#28695)
* feat(relay): measure each host hello's pre-auth time on the cell Adds preAuthLatencyMs to the per-cell orca_relay_runtime_metrics line: per admit path (db, reserve) and outcome (admitted, refused), a count plus p50/p95/p99/max for the window. Each sample runs from the cell accepting the host control WebSocket to the hello being admitted (proof verified) or refused. Samples are kept in a bounded reservoir, shared with the control round-trip metric. No behaviour, wire, or flag change. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count abandoned hellos and publish mergeable pre-auth buckets - Record a third outcome, abandoned, for a host that hangs up before a decision or before the cell acts on one, so the slowest hellos no longer drop out of the window. - Add non-cumulative bucket counts per group (bounds 50..5000 ms and +Inf, 450 exact) so the share at or under 450 ms sums exactly across windows and cells. - Split refusals that end before an admission check answers into a beforeCheck path. - One refuse() closure per phase records the metric, and the path is passed to settle. - Drop the half-used LatencyReservoir type; the shared reservoir function stays. - Replace test casts with a typed accessor or SAFETY comments. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * docs(relay): note pre-auth path labels for late throws and the combined role Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f |
||
|
|
8dfaeea572 |
Resume in New Native Chat for Pi (#28080)
* feat(chat): Resume in New Native Chat for Pi terminal conversations A Pi conversation started in the terminal now offers "Resume in New Native Chat" in its Session History row menu and its tab's right-click menu, like the other chat agents: a new Pi chat takes it over, showing its history and continuing it. Pi joins the shared adoption path. Its import finds the session file Session History lists under the row id, and reads it with OMP's decoder, since OMP kept Pi's session format. A Pi chat's handle names its session file, so the import says so and create mints the adopted handle from the found file; the committed-create replay compares through the registration's row id, and the adopted link id is kept to the link-id alphabet. A Pi chat forks a conversation recorded in another folder instead of resuming it, so the workspace rule covers Pi too. * fix(pi): preserve adopted session identity and active history * Fix saved Pi adoption history and summary content * test: keep only the tests that pin user-visible behavior |
||
|
|
b0308f24ef |
feat(wsl-mover): refuse edits to a project a WSL move is taking (D1b-5c-2) (#28761)
* feat(wsl-mover): refuse edits to a project a WSL move is taking, and drop its background bookkeeping quietly (D1b-5c-2) * fix(wsl-mover): hide only local rows of a moved project; the host's own row keeps its id (D1b-5c-2) * fix(wsl-mover): refuse a user's unread toggle, fence branch deletes, host setups and issue commands; settings unfreeze once the host owns a repo (D1b-5c-2) * test(wsl-mover): the fence e2e refuses edits to moving projects and drops their bookkeeping quietly (D1b-5c-2) * refactor(wsl-mover): name the update type the fence inspects (D1b-5c-2) * test(wsl-mover): run the fence tests that open a real store in the Node runtime (D1b-5c-2) * fix(wsl-mover): a host setup's own repo stays frozen once the host owns it; e2e pins the quiet drop (D1b-5c-2) |
||
|
|
872012f42c |
fix(i18n): drop catalog strings left behind by the automation removal (#28810)
The automation removal deleted the screens but kept their strings in every locale catalog. With no call site left, the boot-bundle catalog check counts them as required and fails on main. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7eb6c45f96 |
refactor(native-chat): open a chat visual like any file (#28437)
* fix(files): never write through a dangling symlink A path that doesn't exist yet was authorized by walking up to the nearest existing folder. A dangling symlink fails realpath with ENOENT, so the walk stepped over it and approved the link's own path; the write then followed the link and created its target outside the allowed folders. The walk now continues from the link's target, and returns that real destination. * refactor(native-chat): rename the chat visuals folder to the chat scratch folder The per-chat folder agents write into is the chat's scratch space, not only a visuals folder. Its root becomes <state>/chat-scratch/<hash> (the hash is unchanged) and the agent variable becomes ORCA_CHAT_SCRATCH_DIR. The old ORCA_CHAT_VISUALS_DIR is never set and is still stripped from what every agent child inherits, Pi included. The visuals skill names the new variable and says the folder is temporary. * test(native-chat): keep the delivery test to the rename The launch parity snapshot already pins that every agent drops the pre-rename variable. * fix(files): refuse any dangling symlink in the missing-path walk Following a dangling link by hand resolved relative targets against the lexical parent, not the link's real folder: through a folder link the walk could loop forever or authorize the wrong file. Refuse instead: realpath can't say where a dangling link leads, but a write would follow it. * feat(runtime-files): the host serves a chat's scratch folder as a file root File commands accept `path:<this host's chat-scratch root>/<32 hex>` and resolve it only when it names this host's own folder, at the file-commands seam so the selector never reaches chat placement. They authorize against the project roots plus the chat-scratch root, refuse files.open/openDiff for the folder, and agentSession.readVisual's ok results carry the file's absolute path so a client can build the selector. * test(runtime-files): name the readVisual helper's parameter type * test(files): drop the loop case that duplicated the dangling-link refusal * test(runtime-files): run the readVisual RPC test, which opens a real SQLite store, under Node * test(runtime-files): put the same-suffix folder inside the authorized root so only the selector refuses it * refactor(native-chat): open a chat visual like any file "Open in new tab" on an inline chat visual now opens the visual's file the way any HTML file of the chat's workspace opens: a file:// browser tab for a local chat (its overflow menu gains "Open source file"), the document preview for a paired-host chat (with its existing source action and Share). Edits save on the chat's host through the exact path: selector the host serves, and a matching editor save re-reads the inline copy freshly. The read-only chat-visual tab is removed. * fix(native-chat): a visual read without a path is a malformed reply A visual's path is always on the current host's readVisual answer, so the inline Open needs no branch for a missing one. Also prune the deleted chat-visual tab action from the layout-writer baseline. * test(native-chat): give visual read replies their path without longer lines * fix(native-chat): address a scratch file by its folder only outside every workspace A workspace that contains the host's state folder keeps its own address, so explorer drops, folder creation and renames inside it stay on one root. Document preview Share reads a runtime grant's own selector and root directly instead of passing the selector off as a workspace id. * test(runtime-files): wait for the stores to close before removing the state folder |
||
|
|
fd4a802b3c |
Native chat: record which agent run wrote each journal item (1/5, rebuild of #26867) (#28092)
* feat(native-chat): record which agent run wrote each journal item Each journal item row, subagent roster entry and background-task entry now records ownerFence: the lease fence of the agent run whose output produced it. Optional, persisted, no row version bump and no migration. The journal's itemFence() returns it, so the turn-verdict rules and per-run provider activity read the producing run rather than the writer's fence. * test(native-chat): fewer provenance tests: fold reopen and unstated-owner checks into the main case Drops the epoch-replacement case (Part 2 rewind test reads the same values through the same rebuild) and the corrupt-value case (no version writes one). * test(native-chat): an unstamped roster entry from an older build reads as its row provenance Moved here from Part 4 so it sits beside stampJournalEntryProvenance. * test(native-chat): build the older-build roster row inline, after main removed its body helper Main #27947 writes one row per subagent and deleted journal-subagent-group-body; a roster row from an older build is still what this case reads. * refactor(native-chat): provenance is per item only; drop per-entry stamping Main's #27947 writes one saved row per subagent, and each background task already has its own row, so an item's own ownerFence names the run of every entry a producer still writes. Per-entry stamps inside a row mattered only for the shared roster rows saved before #27947, and no run writes into those any more, so the row's own provenance settles them correctly. Removes the entry stamping, the optional ownerFence on roster entries and background tasks, and their tests. * fix(native-chat): an item's provenance is set when it is created; revisions keep it A newer run's provider can revise an item an older run created: Pi's start and an ACP session/load both report context usage onto the newest saved turn. Restamping that turn with the newer run let the newer run's exit settle the older run's unverifiable turn as interrupted. Only creation states an owner now, as main's itemFences rule did. * test(native-chat): keep the provenance test below the production lines it covers |
||
|
|
33b85580b4 |
fix(terminal): name the fix that applies when --shell is refused (#28235)
A refusal names a \\wsl$ working directory first, since no runtime setting can move it out of WSL, and names Settings > Project Runtime when the runtime comes from the global default. |
||
|
|
dfafde6a7f |
test(cross-version): pin the ephemeral-key and source-fence downgrade tests to v1.4.224 (#28803)
v1.4.225 ships both capabilities, so the newest release no longer models an old host. Pin each to the last release without its capability, as the other downgrade tests in the suite already do. |
||
|
|
8644ade7fc |
Remove Hermes automation support (#28519)
* Remove external cron history from the automation UI * Simplify the automation editor * Remove Hermes cron discovery and management |
||
|
|
52d9dd2fd7 |
Keep CI failure excerpts bounded and strip malformed ANSI controls linearly (#28671)
* Bound and sanitize CI failure excerpts with linear ANSI stripping * Fix excerpt regression checks and reduce bounded marker overhead * Require signal proof for benchmark timeouts and load consumer fixtures portably * Validate benchmark timeout framing and run required cases with a pinned CI baseline * Strip dense generic ANSI escapes with bounded forward scanning * Use the standard UTF8 encoder for byte-cap test oracles * Gate CI log performance suites behind a dedicated job The wall-clock performance suites run about 1k child workloads up to 63 MiB, so they were sharing runners with unit tests and could fail on noise. They now run only in their own `check_log_performance` job, opted in with `ORCA_CHECK_LOG_PERF=1`. - Remove the pinned-baseline checkout and `ORCA_CHECK_LOG_BASELINE_DIR`. The baseline comparison is now a manual step that reads the pinned ref from local Git history. - Run the current-implementation checks with `compareBaseline: false`, which skips baseline builds and audits. * Inline check-log fixture and drop dedicated perf CI job - Replace the captured failure-log JSON with a synthetic log built by `createCheckLogFixture()`, so no scraped job output or provenance metadata is kept in the repo. - Remove the `check_log_performance` CI job. The log performance suites now run only when `ORCA_CHECK_LOG_PERF=1` is set, as a manual benchmark. - Update the benchmark scripts and tests to use the new fixture helper and drop the `fixturePath` parameter. |
||
|
|
ff1285a936 |
fix(terminal): judge an agent's --shell against the runtime it runs in (#28234)
* fix(terminal): judge an agent's --shell against the runtime it runs in `orca terminal create --shell` for an agent is now judged only against the runtime that agent runs in, not also against the project's saved runtime. So --shell wsl.exe for an agent in a \\wsl$ repo (saved as Windows host, or with no setting) runs instead of being refused. * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main * chore(ci): re-run checks against current main |
||
|
|
98dc5495d5 |
refactor(pty): one failure cleanup and agent_error for both terminal spawn paths (#28613)
* test(pty): pin a failed provider start on both spawn lanes Characterizes main before the two execute steps merge: the error is rethrown, the pre-spawn hidden mark, pending registration, worktree spawn gate, cached size and pane reservation are all undone, and only the window lane records agent_error. * refactor(pty): one failure cleanup and agent_error for both spawn lanes The window (pty:spawn) and the host (runtime controller) each undid a failed execute step with their own copy of the same cleanup: provisional execution context, early-exit fence, pending registration, cached size and provider state for a minted session id. Both now call failPtySpawnExecute, which also records agent_error in one place. recordsAgentError is TEMPORARY: host starts still record none, as on main, until C5a-2 removes the input. The window's extra hidden-mark rollback in this catch duplicated its outer catch, which still runs, and is gone. * chore: re-run CI against current main |
||
|
|
1ead9c2734 |
fix(terminal): store the Terminal shell setting trimmed so agent tabs start like plain tabs (#28635)
* fix(terminal): store the Terminal shell setting trimmed The Settings field only stripped leading spaces and a hand-edited settings file loaded as-is, so a trailing space reached agent tabs, the CLI and other host-planned launches, while plain terminal tabs trimmed it in their own reader. Trim the setting when the field loses focus and when settings load (whitespace-only becomes unset), and drop the plain-tab reader's now-redundant trim. * fix(terminal): trim the shell setting at the settings write too A keystroke write could still store a padded shell, and Escape closes Settings without a blur, so a plain tab could launch the padded value once its own trim was gone. Trim at the settings write boundary (shared with load, like the machine name), and keep the typed text in a local draft while the field is focused. * fix(settings): drop the shell field's draft when the field unmounts The draft lived on the whole Terminal pane, so a field removed without a blur (another window switching to System shell, or the settings search hiding it) left a stale draft that showed later instead of the saved shell. Move it into a small input component so it is discarded with the field. |
||
|
|
b85597cbfa |
fix(serve): restore a remote server's browser tabs after it restarts (#28166)
* feat(serve): keep browser tabs across an orca serve restart A host with no window now saves the browser tabs it opens in the same shape a desktop window saves its own, and restores them the same way: listed at once with their last address, each page started when a client first opens or drives it. A closed tab is forgotten; a page that ends with the process is not a close. * test(e2e): the server's published strip now holds its saved browser tab * fix(serve): save browser addresses cheaply, open once, restore by page id Review fixes: a page's address is written onto its saved records without reloading the layout, and only on committed navigations; reopening a saved page writes nothing; a command naming only the page finds the workspace that saved it; a refused save no longer throws from a page event or a close. The browser-tab map is renamed to say it lists saved tabs too. * fix(serve): list, switch and close saved browser tabs from commands that name no page or worktree * fix(serve): a tab list does not start saved pages; only a command acting on a page does * fix(serve): a pageless command starts the browser tab the layout shows, not the first saved one A host now records the browser tab a window would show: the one it just opened, and the one a tab switch picks. With nothing running, a command that names no page starts that tab; when the layout shows none it starts nothing and reports no browser tab open. * fix(serve): report the saved active browser tab as current Claude-Session: p2-headless * chore(ratchet): count the serve browser-tab save as a main-process layout writer Claude-Session: p2-headless * fix(serve): use the window's active browser tab rule, one scope, one active row Claude-Session: p2-headless * fix(browser): pick the active tab among tabs this host can start A desktop document page or a remote page recorded as active no longer leaves a pageless command with no tab. Adds a test for the first-saved-worktree scope. Claude-Session: p2-headless * refactor(browser): restore saved serve tabs through the page wake point Saved serve browser tabs now start where a window would mount them: the two existing wake helpers ask one host hook before messaging a window. The offscreen backend reports opened and moved pages, so the command layer no longer threads save, list, select or close hooks. No worktree named and no page running reports no tab, as a window does. Claude-Session: p2-headless * fix(browser): only page creation opens a saved serve tab A navigation now only updates an existing saved tab, so a late load after a close cannot re-add it; a restored page sends no open, so its saved title stays. Claude-Session: p2-headless * refactor(browser): drop the restore mark the open/navigate split made redundant Claude-Session: p2-headless * refactor(browser): save serve tabs from the create command, list unstarted ones as tab rows The create command saves the tab (it holds the group), so the backend reports only navigations. Unstarted saved tabs are tab-info rows the existing listings take as-is, the restore dedupe map goes (a created page registers before createTab returns), and one lookup gives a page's unified tab id. Claude-Session: p2-headless * fix(browser): opening a serve browser tab no longer records it as active Which tab shows is a view's choice; after a restart the active tab is the one a window recorded, else the first. Claude-Session: p2-headless * fix(browser): give the composed browser command owners the saved-tab host member Completes the forward merge of main's browser command split (#27576). Claude-Session: p2-headless |
||
|
|
3e25fe70f6 |
fix(unread): a pane is read when it is on screen; closing a waiting tab clears its dot (#28637)
* test(unread): characterize today's workspace and pane unread transitions Pins, against the real store, what every unread trigger does today: the workspace flag per host row, the three tab/pane marker maps, persistence calls and payloads, lastActivityAt and sortEpoch bumps, the Dock count and the floating launcher dot. Events are replayed through one driver file so a later rewiring of who writes the state changes only the driver, never these expectations. * refactor(unread): one workspace-attention module owns every unread transition Every write to the workspace unread flag and the tab/pane/completion markers now goes through src/renderer/src/store/slices/workspace-attention: store operations named by the triggering event (bell, agent attention, pane input, viewed-agent auto-ack, manual mark read/unread) and pure transitions folded into other slices' set() calls (activation, tab activation, close, sleep, hibernate, retire, rekey, reconcile, mirror removal, purge, acknowledge). Behaviour, storage, readers, persistence and wire format are unchanged; the characterization suites pass without edits to their expectations. * refactor(unread): review fixes for the workspace-attention module - Ratchets: moved terminal-tab-attention baseline entries to terminal-tab-appearance; split the characterization setup/observables into an exempt fixture so the driver holds only events. - Removed the test-only writer seam; mocked-store tests assert the event they fire. - The slice owns the experimental pane gate for completions too; groupAttentionEnabled is gone from the attention request and write. - Collapsed marker removals to removeTabsAttention / removePanesAttention / removeCompletionAttention / removeTabMarkers / movePaneAttention; tab activation uses omitRecordKeys. - Mark read/unread is passed in like other store actions; readers of the workspace dot go through isWorkspaceUnread. * feat(unread): on screen means read; the workspace flag follows its markers While Orca's window is visible and focused, the tabs on screen (active tab of the active workspace, plus an open floating panel) are read: every tab, pane and completion marker of each. One scan (the auto-ack hook, now startViewedAttentionScan) replaces the keydown, pointerdown, tab activation, group focus, workspace activation and auto-ack marker clears. After a read, close, sleep, hibernate, retire or purge that removed a marker, a workspace's flag is cleared once no tab or completion marker remains on a live tab; a marker-less flag (Mark as unread, restart, another client) is read when its workspace comes on screen. Mark as read removes every marker in the workspace. Reads and removals dismiss the affected panes' OS notifications in one IPC call. * fix(unread): a bell or completion already on screen leaves no marker or flag write Marking now asks the scan's own on-screen rule (isTabOnScreen: the window is visible and focused and the tab is a scan target), so an on-screen bell no longer persists the flag true then false. A completion in any split pane of the tab on screen is viewed, matching the read. A superseded turn's completion-marker removal settles the flag and dismisses like other removals. * fix(unread): read the screen across hosts, groups and non-agent views; mark only for an absent user - Arriving at a workspace in its own view settles its flag even when it shows an editor, browser or nothing; Settings and other views read nothing. - A bell or completion on screen skips marking only when the user is confirmed present under the scan's own presence gate (input, or main reporting the desktop active within the shared away threshold); otherwise it marks and the gated scan reads it when the user returns. - The active workspace's host is part of the screen, so switching same-id folder rows between hosts is an arrival on the new host. - Removal settles lower every same-id folder row and persist each host. - Opening and closing the floating panel both rescan. - Every visible tab group's active tab is on screen, not only the focused one. - One pane-key parser, one marker-tab enumeration, one removal wrapper (settleAttentionRemovedBy), one remove-and-dismiss; the hook is now useReadOnScreenAttention over on-screen-attention-scan.ts, and terminal keystrokes reach presence through a capture-phase window keydown. * fix(unread): presence only from renderer input; host-exact folder flags; subjectless completions follow the screen - Main's 'not away' answers only the scan that asked; presence is stamped only by trusted input (wheel included), so it can't outlive the threshold. - isWorkspaceViewed uses the on-screen rule (workspace view showing, focused window, user present), so a subjectless completion marks under Settings or while away. - Folder flag writes resolve the row's host like updateFolderWorkspace does (project-group fallback), so the row flipped and the owner persisted match. - A runtime host purge dismisses but doesn't settle flags of surviving rows. - DESKTOP_AWAY_SECONDS is the shared threshold's neutral name. * test(unread): folder flag persists name the row's host * test(unread): drop casts from the folder persistence seeds * fix(unread): point the reliability gate and e2e fixture at the renamed on-screen hook * refactor(unread): drop reshapes the follow-up deletes; keep the flag functions module-internal Reverts the reconcile/mirror/activation/focus/group call sites and the isWorkspaceUnread selector to main, removes removeTabMarkers, removeCompletionAttention and the activation read helpers, and drives tests through public attention actions. * test(unread): read the Dock badge flag down by putting its tab on screen * fix(unread): keep the on-input read action removed after merging main |
||
|
|
c51a85ec65 |
Shorten worker sub-dispatch instructions (#28565)
* Allow workers to dispatch one level of sub-workers by default The default nested worker depth was 1, so a coordinator's workers were refused on their first dispatch. Raising it to 2 lets one generation of sub-workers run without changing any settings. The depth constant, the global settings default, and the affected tests now share that value, so they stay in step. - Set NESTED_WORKER_MAX_DEPTH_DEFAULT and the settings default to 2. - Pin the cap-1 refusal test to an explicit cap of 1, and point the depth-2 test at the default constant. - Update the resolver and settings pane tests to expect 2 when unset. * Keep worker depth at 1 and shorten sub-dispatch instructions |
||
|
|
38255300d9 |
fix(worktrees): never delete a folder git no longer tracks (#25075)
* fix(worktrees): a retried or resumed delete only removes the folder it started deleting
A failed worktree delete stays listed for a retry, and an interrupted one is
finished at the next start. Both later deletes force-deleted whatever was at
the recorded path, proven only by "git does not list it and it has no .git",
so an ordinary folder the user put at that path since was deleted with its
files, with no click needed in the startup case (STA-9338).
An accepted removal now records the checkout directory's identity (device,
inode, creation time) in its durable record. A retry, a startup finish, and
the in-slot check before the force-delete refuse any folder at the path that
is not that directory. Startup no longer rebuilds a missing .git for a
registered checkout unless the folder is the recorded one. Records without an
identity (older builds, or no creation time) are only finished through Git's
own checks and never force-deleted.
* fix(worktrees): identify the accepted checkout by inode and a real creation time only
The device number changes when an external volume is attached again, so a
genuine leftover read as a different folder. Windows reports a missing
creation time as a negative number rather than 0, which slipped past the
guard.
* refactor(worktrees): every background removal states the checkout identity it accepted
A new acceptance site that forgot the identity used to compile and silently
write records no retry or resume could ever finish. The resume tests also
assert the identity was read, so their refusals can't pass as unrecorded.
* fix(worktrees): a delete that leaves the user's folder in place also ends the workspace
When Orca decided the folder at a failed or interrupted delete's path was not
the one it started deleting, it dropped the removal record but kept the
workspace's metadata. That metadata still says Orca created a checkout there,
and with no record left, the next Delete of the same workspace (a runtime
Delete from mobile, the CLI or a paired client, or a second desktop Delete on a
row not yet refreshed) went to the cleanup that deletes an Orca-created folder
Git no longer lists, and removed the user's folder after all.
Now, when a removal ends without deleting while Git does not list the path (a
listing ends a failed delete, or a retry, resume or first delete fails with no
leftover to show), the host runs a finished delete's bookkeeping: metadata,
terminal history, caches and change events. The folder and the branch are left
alone, and nothing is ended while Git still lists the path.
* test(worktrees): cover the in-slot folder check when Git cannot remove a registered checkout
Reverting that check left every test green: only the unregistered branch's
check had a test where the folder changes during the delete-slot wait.
* fix(worktrees): a resumed or retried Git delete checks the folder inside the delete slot
The check that the folder at the path is still the one Orca accepted ran
before the watcher gate and the delete-slot wait, which can last minutes behind
other large deletes. A folder restored there meanwhile with a copy of the
checkout's .git file passes Git's own validation, so `git worktree remove
--force` deleted it. The resume and retry now repeat the check inside the slot,
right before Git deletes, as the non-Git branch already did; the refusal skips
the Windows recovery that could otherwise finish the delete itself. A normal
first delete is unchanged.
* test(worktrees): assert the second desktop Delete refuses the user's folder
The handler result is untyped, so the previous catch-all did not typecheck; the
assertion now names the refusal the Delete gets once the workspace has ended.
* test(worktrees): the desktop Delete test's stand-in host ends the workspace without a cast
* fix(worktrees): a listing asks Git before dropping a failed delete, and ends its workspace in the same step
* fix(worktrees): a failed delete Git cannot be asked about stays failed for the next listing to decide
* test(worktrees): the failed-delete record test states that Git still registers the checkout
* fix(worktrees): a restart keeps a failed delete whose checkout is gone, so the first listing ends its workspace
* fix(worktrees): a folder Orca cannot read keeps its failed delete and is never deleted
* fix(worktrees): a failed delete leaves the disk only after its workspace's end is saved
* fix(worktrees): a runtime Delete of a failed delete's row is told when Orca left the folder in place
* test(worktrees): the desktop Delete test's stand-in host returns nothing
* fix(worktrees): a Delete of a failed delete's leftover whose .git Orca cannot read says so
* Revert "fix(worktrees): a runtime Delete of a failed delete's row is told when Orca left the folder in place"
This reverts commit
|
||
|
|
81ed8c0feb |
feat(runtime-files): the host serves a chat's scratch folder as a file root (#28397)
* fix(files): never write through a dangling symlink A path that doesn't exist yet was authorized by walking up to the nearest existing folder. A dangling symlink fails realpath with ENOENT, so the walk stepped over it and approved the link's own path; the write then followed the link and created its target outside the allowed folders. The walk now continues from the link's target, and returns that real destination. * refactor(native-chat): rename the chat visuals folder to the chat scratch folder The per-chat folder agents write into is the chat's scratch space, not only a visuals folder. Its root becomes <state>/chat-scratch/<hash> (the hash is unchanged) and the agent variable becomes ORCA_CHAT_SCRATCH_DIR. The old ORCA_CHAT_VISUALS_DIR is never set and is still stripped from what every agent child inherits, Pi included. The visuals skill names the new variable and says the folder is temporary. * test(native-chat): keep the delivery test to the rename The launch parity snapshot already pins that every agent drops the pre-rename variable. * fix(files): refuse any dangling symlink in the missing-path walk Following a dangling link by hand resolved relative targets against the lexical parent, not the link's real folder: through a folder link the walk could loop forever or authorize the wrong file. Refuse instead: realpath can't say where a dangling link leads, but a write would follow it. * feat(runtime-files): the host serves a chat's scratch folder as a file root File commands accept `path:<this host's chat-scratch root>/<32 hex>` and resolve it only when it names this host's own folder, at the file-commands seam so the selector never reaches chat placement. They authorize against the project roots plus the chat-scratch root, refuse files.open/openDiff for the folder, and agentSession.readVisual's ok results carry the file's absolute path so a client can build the selector. * test(runtime-files): name the readVisual helper's parameter type * test(files): drop the loop case that duplicated the dangling-link refusal * test(runtime-files): run the readVisual RPC test, which opens a real SQLite store, under Node * test(runtime-files): put the same-suffix folder inside the authorized root so only the selector refuses it * test(runtime-files): wait for the stores to close before removing the state folder |
||
|
|
e5e6189f96 |
Split Jira issue workspace hooks and IPC param checks (#28759)
* refactor(jira): split issue workspace hooks and IPC param checks - Move IPC argument normalization into jira-ipc-params.ts so the jira:* handlers and its tests share one validator. Issue edits are now also checked for labelOperations, which the host reads, so malformed label edits are rejected before they reach Jira. - Move issue hydration and remote detail state out of JiraIssueWorkspace.tsx into use-jira-issue-workspace-data.ts, and comment submission into use-jira-issue-comment-submission.ts, so the component stays under the file-size limit. - Split the reopened-issue and rollback optimistic-edit tests into their own files to keep each test file focused. - Move runtime capability constants into runtime-capability-constants.ts and re-export them from protocol-version.ts, so the values keep the same names and exports for existing importers. * refactor(protocol): use named imports for runtime capability constants Import the runtime capability constants by name instead of destructuring them from a namespace object. The bindings and values are unchanged. Named imports make the dependency explicit to readers and tooling, and the protocol version comment now sits next to the constants it describes. |
||
|
|
93baa828be |
refactor(unread): one workspace-attention module owns every unread transition (#28538)
* test(unread): characterize today's workspace and pane unread transitions Pins, against the real store, what every unread trigger does today: the workspace flag per host row, the three tab/pane marker maps, persistence calls and payloads, lastActivityAt and sortEpoch bumps, the Dock count and the floating launcher dot. Events are replayed through one driver file so a later rewiring of who writes the state changes only the driver, never these expectations. * refactor(unread): one workspace-attention module owns every unread transition Every write to the workspace unread flag and the tab/pane/completion markers now goes through src/renderer/src/store/slices/workspace-attention: store operations named by the triggering event (bell, agent attention, pane input, viewed-agent auto-ack, manual mark read/unread) and pure transitions folded into other slices' set() calls (activation, tab activation, close, sleep, hibernate, retire, rekey, reconcile, mirror removal, purge, acknowledge). Behaviour, storage, readers, persistence and wire format are unchanged; the characterization suites pass without edits to their expectations. * refactor(unread): review fixes for the workspace-attention module - Ratchets: moved terminal-tab-attention baseline entries to terminal-tab-appearance; split the characterization setup/observables into an exempt fixture so the driver holds only events. - Removed the test-only writer seam; mocked-store tests assert the event they fire. - The slice owns the experimental pane gate for completions too; groupAttentionEnabled is gone from the attention request and write. - Collapsed marker removals to removeTabsAttention / removePanesAttention / removeCompletionAttention / removeTabMarkers / movePaneAttention; tab activation uses omitRecordKeys. - Mark read/unread is passed in like other store actions; readers of the workspace dot go through isWorkspaceUnread. * refactor(unread): drop reshapes the follow-up deletes; keep the flag functions module-internal Reverts the reconcile/mirror/activation/focus/group call sites and the isWorkspaceUnread selector to main, removes removeTabMarkers, removeCompletionAttention and the activation read helpers, and drives tests through public attention actions. |
||
|
|
dc146c09e2 |
fix(ssh): the CLI, phone and paired clients no longer list a converted host's retained rows (#28754)
* fix(ssh): the runtime lists a converted host's retained rows as hidden, as the desktop does * fix(ssh): never name a converted host as uncovered in runtime worktree listings * fix(ssh): a scoped worktree listing never names a hidden host either |
||
|
|
3879c6d96f |
feat(wsl-mover): fence moving projects from new terminals and hide them once the host owns them (D1b-5c) (#28668)
* feat(wsl-mover): a WSL move fences its projects from new terminals and hides them once the host owns them (D1b-5c) * fix(wsl-mover): hide owned rows from every list, follow respelled profile paths, let a live pane reattach (D1b-5c) * test(wsl-mover): fake stores without type assertions (D1b-5c) |
||
|
|
cc0217fe96 |
test(ci): bound the Windows OEM process-read test's cold PowerShell start (#28564)
* test(ci): give the Windows OEM process-read test the PowerShell cold-start watchdog The runner's first Windows PowerShell 5.1 start has reached 48 s on packaged CI; the test's 30 s cap failed package (windows) 7 times in ~1,000 runs. Match the 75 s watchdog nsis-process-check already uses for the same cold start. Co-Authored-By: Claude <noreply@anthropic.com> * test(ci): keep the OEM marker alive past a cold read, and bound the PowerShell read A blocking spawnSync can't be interrupted by the test timeout, and the marker child exited at 30 s, so a 48 s cold read could miss it. The reader now has its own 60 s bound. Co-Authored-By: Claude <noreply@anthropic.com> * fix(bench): keep idle-CPU cleanup running when the final process read fails Co-Authored-By: Claude <noreply@anthropic.com> * fix(bench): kill the app tree when the final process read fails Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
dd4d0fa51f |
Repair Jira integration fixtures and verification contracts (#28743)
## ELI5 Keep the test suite working with the Jira features that have just landed. There is no visible app change. ## What Changed The host-picker test now expects the host-qualified selection the parent already accepts. The startup fixture provides Electron's protocol handler and verifies that ready installs the Jira image scheme. Jira edit tests use exported wrappers with module-local setters that are cleared on unmount, preserving the issue/source switch tests without the banned mutable function export. The WSL storage inventory classifies Jira list columns, linked-view choice and prompt templates as device preferences, matching their keys and the existing Linear policy. Skill-guide tests check the actual generated discovery projection rather than assuming it is shorter than every full guide or uses one fixed phrase. The cache test follows the headless workflow's deliberate removal of its push trigger; cache-warmer checks remain intact. ## Why Final CI found six stale integration assumptions after the Jira batch. Updating the fixtures and inventory preserves the landed behavior and the underlying checks. Changing production code, padding the Jira guide, or restoring an intentionally removed workflow trigger would change the product to satisfy incorrect test assumptions. ## Linked Issue Follow-up to #28622, #28631 and #28592. The existing headless trigger policy was introduced in #28664. ## Visual Proof N/A — tests, test fixtures and storage inventory declarations only; no visual or interaction change. ## Testing - [x] Automated tests updated. - [x] 196 focused tests across nine files pass on macOS, covering every failed shard assertion, fixture consumers and the headless workflow policy. - [x] Node and web typechecks pass; all seven changed-code quality stages, formatting and diff checks pass. - Reproduced five failing assertions in startup/export/storage tests and the skill projection failure before the repairs. The host-picker owner also reproduced the stale selection failure before correcting it. - Final full CI will run on this PR. The prior Ubuntu 22.04 persistence job crashed in the native watcher build before persistence tests ran; this change does not claim a Linux release, live Jira or real SSH pass. ## Review Independent source review found no issues; all six reviewed file hashes and the complete diff match committed head `aa703eb50147ba95646cb82f10b6d86b4f890fc4`. Risk: low. No authentication, network, protocol implementation, workflow, renderer behavior, remote messages or migration rewrite logic changes. ## Agent skill upstream boundary - [x] Not applicable; no upstream skill-installer source or artifacts copied. ## Notes The three storage keys contain device-level preferences, without workspace paths or identifiers. Tests preserve host disambiguation and issue/source switching. Platform, SSH and provider behavior remains in the existing implementations. ## Checklist - [x] Small and focused. - [x] Explained the before/after, mechanism and choice of approach. - [x] Visual proof marked N/A with a reason. - [x] Self-reviewed for correctness and cleanup. - [x] Cross-platform and SSH impact considered. - [x] Focused tests, types, formatting and quality checks pass; full CI covers the broader build. |
||
|
|
c8ed629217 |
fix(cloud-auth): one owner for the cloud session; never drop a rotated token, stop after a 401 (#28523)
* fix(cloud-auth): never drop a rotated refresh token, and stop after a 401 even when the store cannot be written A refresh whose session save failed (write error, or a moved mutation fence) discarded the rotated token, so the relay broker's ~10 s renewal kept replaying the spent one until the server revoked the family. The 401 then could not clear the session because the revocation write failed the same way, so the broker looped on 401s indefinitely. * fix(cloud-auth): one compare-and-swap save for rotated tokens; org selection keeps them - Rotated tokens save only while the store still holds the spent token and the identity is not signed out; linkage (and a server-reported org change) moves only under the refresh's own fence. - Org selection refreshes through the shared single-flight and merges onto the latest stored session instead of writing back the tokens it started with. - A failed session write removes the stale file so a restart cannot replay it. - A cleared session refuses conditional saves until the next sign-in. * refactor(cloud-auth): one read-merge-save helper for stored sessions; tokens before relink - updateStoredOrcaCloudSession re-reads, applies an update and saves under the fence in one turn; org selection, capability refresh and rotation all use it. - Rotation saves tokens first and relinks best effort, so a failed fence write cannot leave the spent token stored. - Only a rotation removes the on-disk file after a failed write; other saves leave a still-valid token in place. - Capability refresh fences at request time, after any inner refresh relink. * fix(cloud-auth): roll the fence back when relinking after a refresh fails A fence left on the server-reported org while the profile link kept the old one made every later capability refresh return reconnect-required. * refactor(cloud-auth): one owner for each profile's cloud session profile-cloud-session-owner.ts is now the only code that reads or writes a profile's session. Renewal, org selection, capability refresh, sign-in and sign-out ask it for changes; it keeps an in-memory generation (sign-in/out) and link version (org changes) instead of the on-disk mutation fence. Deletes profile-cloud-session-mutation.ts (account-session-mutation.json), profile-cloud-session-rotation-save.ts, updateStoredOrcaCloudSession and the profile-switch fence write. * fix(cloud-auth): retry an unsaved rotation until it lands; sign-in save failures throw as before - The store keeps a rotation whose write failed and retries it on every read and at quit, so one failed write no longer signs the user out on the next restart. - Only a rotation keeps its session after a failed write; sign-in, org selection and capability writes throw as on main. - Org selection succeeds when the link already moved to the selected org. - The owner reads the profile's link itself and bumps its link version only on an org change; commitCloudSessionRelink returns the profile list. - Adds the auth characterization suite that pins main's behaviour. * fix(cloud-auth): a failed non-rotating save keeps a pending unsaved rotation Found in the real-app run: a capability save that failed while a rotation was unsaved dropped the pending rotation, so the next renewal resent the spent token. * fix(cloud-auth): flush unsaved rotations on OS shutdown; stale capability replies match main - Flush unsaved rotations on Windows session-end and powerMonitor shutdown, through the owner, which now also owns the quit flush. - Capability replies are refused once the org link moved at all, as on main; only org selection accepts a link that already reached the selected org. - Sign-in and sign-out reuse invalidateCloudSessionChanges; small store cleanups. - Pins the A->B->A stale capability reply in the characterization suite. * fix(cloud-auth): flush unsaved sessions before recording the Windows session end |
||
|
|
ef3406788d |
feat(jira): remember repository project defaults (#28622)
Remember an optional Jira project for each repository so its issue picker and Tasks list start with the intended project and site. Keep temporary project overrides separate from the saved default, and choose a mapped workspace destination while retaining the Jira account that supplied the issue. Older hosts that discard the optional saved field return an actionable message.
Keep account ownership separate from repository execution identity. An explicit matching repository owner disambiguates repeated IDs; automatic defaults require ID uniqueness, and overrides include execution-host identity. Preserve existing preselection behavior, saved/manual query classification and linked-view choices. Reuse existing persistence, identity and query builders; check the final UTF-8 query length for searches and project-filtered presets and show a recoverable error before dispatch.
Validation at reviewed
|
||
|
|
a0c46b405f |
feat(jira): load attachment images outside issue Markdown (#28631)
Load Jira attachment images separately from issue Markdown so descriptions and comments stay small while screenshots load lazily and open in the existing lightbox. Downloads begin when an image mounts, capture its owning host, require negotiated image support, and use bounded authenticated byte streams and caches. Older clients retain their inline-image handlers. Keep legacy and cancellable downloads in separate in-flight domains so cancelling a new image reader cannot abort a legacy reader; completed bytes share the bounded cache. Preserve the landed assignee, board, transition/comment queue and request lifetimes. Move unchanged project metadata IPC handlers into their domain module and tighten two inherited focus-check ceilings without changing behavior. Validation:410 tests/54 suites; all changed-source quality stages, lint, format, routing and contract checks; exact final node/web types; independent source review;48/48 fresh hidden Electron checks with226 stable source hashes and nine inspected screenshots. Synthetic transports exercise production clients and UI. Current CI static checks, mobile bundle, wire compatibility, Linux/Windows packaging and Windows serve pass; five test shards were pending at review. Extends the existing attachment work credited to Frank (@lifefloating) and Brennan Benson in PR #8938; existing contribution credits and media remain in this PR. |
||
|
|
624c4148cc |
View Jira work on a board and filter the current sprint (#28633)
Show Jira issues as a board alongside the existing list and add the current-sprint preset. Status moves use the existing owner-scoped mutation queue, collect required workflow fields/comments, retain rejected drafts, and reload the mounted comment timeline once after success. Source/session fences keep older detail failures from undoing newer board moves. Preserve statuses plus sprint in query preview and Edit-as-JQL. Older hosts must advertise sprint support; unsupported peers fail clearly. Existing capability definitions and test fixtures are split without changing public exports, wire strings, or coverage to meet current lint limits. Validation:351 tests/42 suites,all46 changed sources full-file lint/anti-slop and7quality stages,localization/RPC checks,and independent source review passed. Node types passed on runtime-identical99d and web types passed on final602d. Fresh hidden Electron54/54 checks passed on99d; final two test-only changes were hash and emitted-runtime audited. The inherited IPC301-line failure is byte-identical main and being corrected separately by the image PR. Adapted Eugenio Valeiras (@EugeValeiras)'s board contribution from PR #13054. Co-authored-by: Eugenio Valeiras <eugenio.valeiras@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8c5ac7a890 |
Make existing Jira assignees searchable and add Assign to me (#28612)
Add source-aware Jira assignee controls on the existing issue workspace and mutation queue. Search, self-assignment, rollback, pending edits, and stale-source replies retain captured account ownership alongside transition/comment forms. Move existing draft/menu callbacks into the existing actions module to stay within the current lint limit; correct the stale file-open arity fixture. Validation: exact-head node/web typechecks,133 tests/14 suites,all changed source full-file lint and7 quality stages,source lifetime/catalog checks,and independent source/action-extraction reviews passed. Fresh hidden-renderer41/41 checks passed across assignment/transition/comment and extracted title/label actions;35 source hashes stayed stable,zero renderer errors. All owned proof processes cleaned. Full CI still contains protocol/IPCs max-lines violations confirmed byte-identical to current main; separate board/image corrections are in review. Requested by Andy (@andyhorn) in issue #17052; no external source PR code copied. |
||
|
|
8e6848174c |
refactor: clear Jira CI lint failures without behavior changes (#28717)
Restore existing Jira CI lint checks without runtime behavior changes. Existing generation types are moved verbatim and re-exported; the mobile fixture retains object identity coverage with a named client type. Validation: renderer typecheck, 10 generation tests, 3 mobile identity tests, changed-file quality, full-file lint, formatting, and independent source review passed. |
||
|
|
fa5533e8cd |
test(relay): check invariant 4 (one demotion winner) in the step-5 simulation (#28696)
* test(relay): check invariant 4 (one demotion winner) in the step-5 simulation Every demotion now names its winner (the newer booking, or the row). The model flags a director that names a different winner for a divergence another already named, and a host whose two seats are each demoted for the other. A fault where directors break level ties by their own cell order shows the check fires. Violations are capped per invariant so one flood cannot hide another class. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * test(relay): bound unseen duplicates by the silence close and assert all invariants on contested ties A reserve seat the booking director's map had not seen (joined, then half-open within a poll) is never superseded and has no lease to re-check, so it lasts until the cell's control silence close (75 s + one 15 s ping). Invariant 3 now uses that bound for such seats, and the level-divergence config asserts every invariant. Stale maps now judge a divergence another director already demoted, so the config's "contested" counter (divergences judged by two or more directors) is the case invariant 4 guards. The silence-close constant now matches production (90 s, not 100 s). Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * test(relay): raise the floor on map-judged demotes and count only level contests A reconcile whose map has not seen another director's demotion still demotes in production, which raises its epoch floor; the model now does too. The contested counter counts only same-epoch pairs, the only ones invariant 4 can split. The keep-this-seat rule is one helper. Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * refactor(relay): name the simulation's fault-kept seat check for the fault Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f * fix(relay): count only confirmed level demotions and every second judgment, and bound duplicates by placement records alone Claude-Session: f2fe8cb5-4467-4a25-8aab-98598b70791f |
||
|
|
eb1ee8f908 |
fix(jira): collect required fields before changing status (#28588)
Collect required Jira transition fields through the shared issue save queue, preserve entered fields after rejected saves, and refresh the comment timeline after successful transition comments. Keep captured-host and older-peer compatibility. Co-authored-by: Wooseong Kim <innocarpe@gmail.com> |
||
|
|
d194712952 |
Choose Jira key casing and keep canonical Jira keys in review titles (#28596)
Choose Jira issue-key casing and review-title prefixes while preserving manual GitHub/GitLab title and body edits during generation, branch changes and remounts. Co-authored-by: chucoding <56211193+chucoding@users.noreply.github.com> |
||
|
|
702777e2fe |
Filter Jira preset views by multiple workflow statuses (#28623)
Combine remembered Jira status filters with presets and saved JQL on the connection host, protecting obsolete owner actions and keeping incompatible controls hidden in linked mode. Co-authored-by: Brennan Benson <brennankbenson@gmail.com> |
||
|
|
4731172bd8 |
feat(jira): choose planning columns in the issue list (#28615)
Choose and sort Jira planning columns while bounding optional field discovery, preserving complete Cloud searches and aligning copy/workspace actions in responsive rows. Co-authored-by: Dagan <idan.d@imagen-ai.com> |
||
|
|
d7315af456 |
Save and reuse named Jira JQL filters on the execution host (#28600)
Save and apply named Jira queries on their connection host. Reject obsolete owner actions and exit linked mode only after a saved query is actually applied. Co-authored-by: no-support <jwan0131@gmail.com> |
||
|
|
0c05e6d33f |
feat(jira): add row quick copy and reusable prompt templates (#28618)
Copy Jira keys, URLs and agent prompt templates through issue row menus while preserving linked-workspace actions, responsive spacing and row selection. |
||
|
|
cacce1790d |
feat(tasks): browse Jira and start workspaces on mobile (#28616)
Browse Jira on mobile and create linked workspaces through the paired desktop, retaining shared task queries and protecting account/session changes. Co-authored-by: Minho Yi <tisohjung@gmail.com> |
||
|
|
5ae088a24b |
fix(integrations): notice Jira and Linear state changes from other processes (#28594)
Reload externally changed Jira and Linear connection metadata and credentials on the next read using bounded file-identity caches. Existing captured requests and retained result expiry policies remain intact. Co-authored-by: Minho Yi <tisohjung@gmail.com> |
||
|
|
8f91313087 |
Show every linked Jira workspace and add a Has Workspace view (#28590)
Show linked workspaces for Jira issues and offer starting another workspace even when one link already exists; preserve site and execution-host identity. Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com> |