* feat(managed-server): offer Update and Update anyway on a managed SSH server's row
A managed SSH server only updated on connect, and every connect deferred while
a terminal ran there. Its row now offers Update when this desktop bundles a
newer build than the Orca that runs the host. When running terminals defer it,
Update anyway restarts the server past them; the terminal daemon carries them
across the restart.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(managed-server): Update anyway passes only counted live terminals and keeps Update's version admission
Update anyway now sends the incumbent build it confirmed over; under the host
fence it is refused if another desktop activated a build since, keeps the
newer-host downgrade refusal, and never passes an uncounted terminal census.
The offer also covers hosts activated before the Orca version was recorded,
for the build this desktop already deferred there.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(managed-server): Update anyway also confirms a menu Update the row does not advertise
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(managed-server): the row shows one confirmation at a time
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* ci(e2e): route managed-server update sources to the Update anyway Docker spec
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(daemon): contain ConPTY output-relay write errors to the one terminal instead of killing the daemon
* fix(daemon): end a Windows terminal whose output relay dies before connecting
* fix(daemon): kill a Windows terminal whose output relay fails before its first output
Run 40149801617 timed the SysWOW64 probe out at the 60s watchdog after it
had printed its policy receipt, so PowerShell had started and the first
Win32_Process query on the fresh runner was the slow part; the System32
probe right after took 14.7s. Run each probe once with a 150s bound in
beforeAll so the watchdog measures the probe rather than WMI's first query.
* test(mobile-web): act on the HTML preview frame only once the browser routes input into it
Chromium runs the sandboxed preview frame in its own process. The rig decided an arm was
ready once the artifact had parsed, but the embedder can still be showing the frame's white
before its surface is composited, and still keep pointer input over the frame for itself
until it holds the frame's hit-test region. A click in that window landed on the
embedder's <iframe>, Playwright reported success, and the arm waited for a navigation
that never came (or read white as pixelBefore).
The rig now waits for the artifact's paint before reading pixelBefore, and before acting
moves the pointer over the frame until the embedder stops receiving it.
* test(mobile-web): name the arm in the input-routing timeout and trim history comments
* chore(lint): remove disable directives that suppress nothing
Each was reported unused by the oxlint config that owns its rule (root,
casting, react-doctor, anti-slop, native-plugins), including 17 file-level
react-doctor blanket disables whose rule no longer fires. An unused
react-hooks disable was masking a react/purity finding in
useAgentBucketCounts (compiler rules skip functions with hook
suppressions); suppress that one explicitly where the code explains it.
* test(tab-bar): use typed tab/file fixtures instead of @ts-expect-error partials
* chore(lint): fix misc suppressed lint violations instead of disabling
- consistent-type-imports: the "vi.importActual requires inline import()"
rationale was wrong; use typed vi.mock(import(...), importOriginal) or a
type-only namespace import.
- no-control-regex: source-control commit/push failure summaries, shell PATH
hydration, and ipynb ANSI parsing reuse the shared ansi-escape-sequences
stripper and control-character pattern instead of private copies.
- no-explicit-any / no-useless-spread / no-this-alias: typed `this` in
bridge test mocks, drop blanket file-level disables, drop a this-alias.
* refactor(main): replace avoidable type assertions with checked narrowing
17 production cast suppressions in main/wsl-guest removed: untrusted IPC
and RPC payloads (Jira issue update, WSL guest plugin install, handshake
type) now narrow through isRecord/type guards and build typed results;
redundant casts dropped; hand-rolled object checks and errno casts use the
existing isRecord / hasErrorCode helpers.
* refactor(renderer,mobile): replace avoidable type assertions with checked types
13 production cast suppressions removed: RPC failures read through the
`ok` discriminant instead of casting to RpcFailure; react-native-web host
refs narrowed with instanceof HTMLElement; redundant reply/diff casts
become checked annotations; the TUI agent param uses z.custom(isTuiAgent)
like its sibling schemas; the agent-status slice cast that hid missing
actions is gone so the creator's return type checks the whole slice.
* chore(lint): drop dead tiptap wrapper; scope anti-slop mocking rule to test support
- safe-react-node-view-renderer patched handleSelectionUpdate, which
@tiptap/react 3.31.3 no longer has, so it always returned early. Use the
stock ReactNodeViewRenderer.
- The anti-slop test override only matched *.test.{ts,tsx}, forcing
file-level no-module-mocking disables in test harnesses and fixtures.
Match *-test-harness, *-test-fixture(s), .test-fixture and *.test.mjs,
then drop those disables and the now-redundant per-file exemptions.
* test: replace repeated cast suppressions with typed fixtures (main/shared/e2e)
Net -119 cast directives. Typed fixtures replace recurring casts:
unusedSshConnection/unusedOrcadHostTransport placeholders, a typed
readPersistedState harness read (exposed a test treating optional
httpProxyUrl as always set), real Response objects in fetch spies, an
updater main-window fixture, a CDP webContents adapter, one shared
releaseModuleExport for cross-version tests, and requireOverlayDir in
place of `as string` on possibly-undefined overlay paths.
* fix(runtime): validate loaded device rows and host scope instead of casting
Two cast suppressions claimed checks that did not happen:
- device-registry-file-read: "normalizeLoadedDeviceRow re-validates every
field" was false; deviceId, token, name and timestamps were never
checked. Rows without an identity are now dropped and the file is set
aside through the existing corrupt-file path (registry reads as
doubtful, so no revocation verdicts); a non-string token is stripped
so the row stays listed but cannot authenticate.
- client-ui: "only optionality differs" was false; any string reached
persisted workspaceHostScope. Narrow it with isWorkspaceHostScope and
ignore unknown scopes (wire schema unchanged for mixed versions). The
remaining cast now states what it actually covers.
* test(runtime,ipc): drop redundant cast suppressions; typed runtime store fixture
-98 cast directives across runtime/ipc tests: 61 casts that typecheck
without the assertion; a typed vi.fn for scoped invalidation; a
partialRuntimeStore fixture in place of `store as never` for
OrcaRuntimeService; typed worker terminal/authority builders in the
incarnation-fallback suite (the old stub lacked runtimeId, ptyId,
worktreeId and launchTokenHash) plus removal of stacked duplicate
directives there.
* chore(lint): typed vi.mock imports and explicit listener snapshot in shared-bucket tests
Remaining files from the misc-rule pass that overlapped other buckets:
codex-accounts mocks use the typed vi.mock(import(...)) form instead of
a consistent-type-imports disable; the daemon late-exit fixture copies
its listener set with Array.from instead of a no-useless-spread disable.
* refactor(github,mobile): narrow routing settings type; drop remaining avoidable casts
- work-item-routing cast a one-field object to AppState['settings'] under
a claim that readers only consume activeRuntimeEnvironmentId. Return the
existing RuntimeFocusSettings pick instead and narrow the cache-key
chain's parameters, so the compiler enforces that claim.
- mobile file preview reads refusals through the RpcResponse `ok`
discriminant rather than a cast.
- terminal document host-notify accepts `unknown` errors, removing the
message-bridge cast.
- native chat readability drops a redundant repo-list cast.
* test(renderer): replace repeated cast suppressions with typed fixtures
-140 cast directives (and ~150 unsuppressed casts of the same shapes):
- mockPanePtyArgs owns the connectPanePty fixture casts, so a wrong
argument order or fixture is now a type error; drop binding casts for
members PanePtyBinding already declares.
- Seed AppState tab rows with the typed makeTerminalTab; this exposed a
split direction 'row' that is not a TerminalPaneSplitDirection.
- Partial GlobalSettings use getDefaultSettings overrides; Jira-only
stores use createTestStore; runtime environment rows/statuses come from
a typed paired-runtime-environment fixture.
* chore(lint): drop no-module-mocking disable now covered by the test-fixture glob
* test(e2e): fix all 221 grandfathered e2e type errors; baseline to zero
The e2e typecheck baseline grandfathered 221 errors in 119 files. About a
third were tests drifted from the current API, several of which would
fail or mislead at runtime:
- terminal-shortcuts called a nonexistent xterm buffer method;
- the daemon-lifecycle fake lacked terminateOwnedTree, hidden by importing
its type from a module that does not export it;
- arguments in the wrong position (listProcesses(hostId, opts), a dropped
pty.write inputKind, an extra toWebTerminalSurfaceTabId argument);
- removed enum values ('drawer', 'idle', 'editor',
'session-insecure-origin') and a launch_source the telemetry schema
rejects;
- missing required fields (turnScope, childWorkOpen, providerIdentity,
reviewLookupOutcome, runtimeServiceAccount behind an `as RelayConfig`);
- dead reads (tab.customTitle, bucket.targets, changedPixels).
Also lifts variables that narrowed to `never` after poll-callback
assignment, and adds a typed xterm render-dimensions accessor. Includes
the cross-version suites' shared releaseModuleExport adoption.
* chore(typecheck): gate the now-clean e2e typecheck in local lint
The e2e baseline is empty, so the ratchet now rejects any tests/ type
error. CI already runs it via run-ratchets; add it to pnpm lint's
explicit ratchet list and replace the stale 'not yet clean' note.
* test(mobile): typecheck every mobile test; baseline 105 files -> 0
mobile/tests-typecheck-baseline.txt grandfathered 105 test files (531
errors) whose types CI never checked. Contract changes had landed without
these tests following, and type pins in them silently checked nothing.
- Root cause: salvagedOptional (src/shared/zod-salvage.ts) cast away
zod's optional marker, so every reply type built on it claimed
salvaged fields were always present. Return a real ZodOptional;
runtime is unchanged (the outer optional short-circuits undefined).
- Production now takes the port it uses: RpcOperationSender instead of
RpcClient for send-only callers, a narrow fetch signature, and only the
request fields push-receive reads.
- findAllByHostType/findByHostType replace `'Text' as never` lookups;
stubRpcClient gives tests a typed RpcClient.
- Real test bugs: settings-host-client-lifecycle "relay" hosts were
direct hosts (relayHostId no longer exists); two toEqualTypeOf pins
could never hold; a recovery hook ran with an undefined scope key;
a create-PR test cast to a never-imported type; "no URL" assertions
passed on null; plus stale required props, args and enum values.
* test(e2e): parse workerStart result instead of casting it
* test(runtime): typed partial runtime stores with production-shaped fixture data
Route every partial store passed to OrcaRuntimeService through
partialRuntimeStore with typed row builders, removing 60 cast directives
that hid fixture data production never produces:
- paired-client-navigation-test-harness keyed setWorktreeMeta writes by
`[object Object]` (it took an id where the store takes a target), so
reads never saw them;
- invalid worktree lineage origin/capture and incomplete workspace lineage;
- getWorkspaceSession returning null where the store returns the default
session; getGitHubCache returning undefined;
- orcad migration states missing migrationId/manifest/receipt, with a
toEqual pinned to that incomplete shape;
- partial repos, metadata, folders, project groups and notification rows.
* refactor(renderer): resolve suppressed React hook lint instead of disabling it
109 of 187 react-hooks/react-doctor suppressions fixed:
- ~95 exhaustive-deps disables only hid stable refs and setters passed
through controller objects; list them (identity never changes, so
nothing re-runs), plus a few real stale closures (tabId/worktreeId).
- Effects keyed on one value that read the latest props now use
useEffectEvent (WebConnect, skill freshness, Bitbucket dialog seeding,
Landing preflight, automation catalog, structured-session recovery,
file explorer).
- The conditional layout-owner hook is selected once at module load from
the build constant instead of a rules-of-hooks disable that also hid
the whole controller from compiler and react-doctor rules.
- A hook disable was masking a react/purity Date.now() in the palette's
recent-tabs memo; sample it when the snapshot is captured.
- Three identical debounced-search effects share
useTaskSearchDebouncedApply; layout snapshot merge helpers move out to
stay under max-lines.
Remaining suppressions are mount-once resources, invalidation epochs,
deliberately keyed fields, and test harnesses that mock the dispatcher.
* chore(ratchet): exempt test harnesses and fixtures from the focus-read ratchet
The ratchet skipped *.test-fixture.ts but scanned *-test-harness,
*-test-fixture(s) and *.test-support files. Those seed settings with
getDefaultSettings (which the ratchet discovers as a focus reader) and
never route host work, so 17 baseline entries were false positives, and
replacing a test's `settings: {...} as never` with typed defaults tripped
it. Match the repo's test-support names and prune (which also drops one
stale entry), and rename the frame-ordering harness to *-test-harness like
its siblings. A blanket "-harness" match would also exempt
e2e-terminal-pty-harness, which production imports, so the names stay
explicit.
* test: merge duplicate shared/constants imports
* revert(file-explorer): restore original tree load effects pending SSH e2e investigation
* test(runtime): drop RuntimeStore cast now that the fixture is typed
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* test(mobile-web): click the drawer chip once it is actionable, and honour the wait timeouts
* test(mobile-web): say why the drawer trial click stays, and report a failed open with page errors
The census built a whole-repo TypeScript program (17,740 root files) inside
a unit worker, peaking at about 7 GB, and ran out of memory on loaded
machines. Its invariant, that a layout-owner build never reads or writes a
PTY record's pane copies, is proven at runtime by
pty-pane-copies-untouched-main.test.ts, which traps every access.
* test: run the terminal-retirement SQLite fixture's suites under Node
The acknowledged-tab retirement fixture opens profile-state SQLite, but the
runtime scan only sees direct imports, so its four suites ran under Bun. On
macOS Bun's node:sqlite is the system SQLite, which cannot open a closed WAL
database read-only, so the quit-flush durability case failed on every local
macOS run. Naming the fixture as a SQLite harness runs them on Node, the
runtime the product ships.
* test: run every suite that opens profile-state SQLite under Node
Tests that import the profile-state SQLite authority directly ran under Bun,
whose macOS node:sqlite is the system SQLite. Listing the authority as a
SQLite module sends them to Node with the other SQLite suites.
* fix(ssh): move a managed tunnel off an unbindable saved local port
When the saved local port of a managed SSH server's tunnel can no longer
be bound (EADDRINUSE from another listener, or EACCES from a Windows
excluded port range), pick a free port, save it with the pairing and the
deployment link together, and build the tunnel again. The pairing, server
identity, remote port and projects are unchanged.
A move interrupted between its sidecar and store writes reads the moved
port from the stored endpoint, so the deployment link is never dropped.
Fixes#33182
Co-authored-by: SahilZ0810 <sahil@zamp.ai>
* test(e2e): drop squatter connections so teardown never waits on them
* fix(ssh): move the tunnel port before pairing repair and retire old transports
Move outside buildWithPairingRepair so a refusal on the moved port is
repaired against the revision the move saved, and retire transports and
status owners still dialing the old port, as a repair does.
* fix(ssh): refresh maintenance pairings on the current tunnel port
Update, rollback and restart reread the deployment's local port when they
save the new pairing, since the census before them may have moved it.
* fix(ssh): let concurrent tunnel builds follow a port another caller moved
---------
Co-authored-by: SahilZ0810 <sahil@zamp.ai>
* fix(windows): include registry addon in relocated daemon host
* test(windows): preserve registry path in native-read child script
* fix(ci): match registry gate command to recorded validation
* ci: fail when a checked-in test file has no runner
Two node:test files under .github/actions lost their runner when #31792
trimmed cloud pretest, and the two monaco .bench.ts budgets were never run
by any CI job. Wire both back in and add a static check that every
test-like file is collected by a declared runner or imported by a
collected entry (the src .spec.* suite-module convention).
* ci: ignore type-only imports and quote the lease glob for cmd.exe
* ci: parse type-only imports, cover UNIT_EXCLUDE, route cloud runner edits
Type-only imports are now dropped with the TypeScript parser, so a type
alias before a runtime re-export no longer hides it. UNIT_EXCLUDE files
must be named by a pr.yml or unit-tests.yml step. A cloud-only diff that
adds a test or edits a runner config now runs the static job. The monaco
benchmarks stay manual (pnpm test:perf:benchmarks) until a CI runner
proves their wall-clock budgets.
* ci: require UNIT_INCLUDE names in dedicated jobs and erase typeof import()
* ci: resolve each runtime import to the one file Vite loads
The unit dependency graph keeps every plausible candidate so it can
invalidate conservatively, which cannot prove a suite runs: an import of
./case.spec counted both case.spec.ts and case.spec.tsx. Resolve with
Vite's extension order instead.
* ci: take runtime imports from transpiled output
Imports used only as types are erased without a type modifier, so
parsing for type-only syntax still followed them. Derive edges from
ts.transpileModule output, which erases what Vitest's transform erases,
and only transpile files that can reach an uncollected candidate.
* ci: fix the agent-status benchmark config and route all cloud code
The agent-status benchmark config inherited the unit projects, whose
includes override its own, so it ran the whole unit suite and never the
benchmark. Clear projects as the performance config does. Route every
cloud code file to the static job, since content-detected tests can have
any name.
* A Claude chat shows the turns made outside it
When a Claude chat's agent next opens, turns written to the same
conversation elsewhere (claude --resume in a terminal) are appended once,
in order, under the existing "Continued outside this chat." divider.
Streamed reply and thinking rows are now keyed by their source block
(message id and block index), which Claude also saves on each transcript
row, so the chat can tell which saved rows it already shows. The read goes
back from the end of the transcript only to the chat's saved turn-end leaf,
replays the rows through Claude's own translator in an isolated sink, and
commits them in one settlement that writes nothing if the chat moved.
Imported prompts are display-only and never settle a send; any failure
opens the chat normally.
* test(claude): name the transcript row shapes the catch-up test builds
* fix(claude): read a catch-up row's uuid once as a string
* fix(claude): parse transcript tail rows without type assertions
* refactor(native-chat): share the catch-up open runner across agents
The Codex catch-up's agent-neutral parts move to one module: the open-time
envelope (its own deadline and cancellation, never gating the open), the
bounded staged batch, the single settlement commit that re-checks the
journal before writing, and the "Continued outside this chat." divider.
Codex keeps only how it reads its saved turns and what the chat already
holds. No behavior change; the other agents' catch-up builds on this
instead of copying it.
* refactor(claude): catch up through the shared history catch-up runner
* chore: remove unrelated pnpm executable metadata
* refactor(native-chat): the catch-up runner reads the chat's view only when the agent asks
* chore: remove regenerated pnpm executable metadata
* fix(native-chat): the catch-up deadline also bounds waiting for its commit to be written
A journal write barrier that never settled after the import was admitted held
the provider's open past the catch-up deadline. The wait now ends with the
deadline or the open's cancellation, like every other step.
* test: type the history catch-up sink fixture without assertions
* fix(native-chat): bound and revoke history preparation
* test(claude): expect source block identity in stream cadence
* fix(claude): preserve final output and history coverage
* feat(native-chat): validate expected saved items during history catch-up
* fix(claude): integrate conditional history settlement
* fix(claude): use new content and provider prompt identities for catch-up
* fix(claude): retain qualified completed leaves through session exit
* fix(claude): preserve unresolved membership for recovered follow-ups
* test(claude): use fork epoch reason for rewind preservation
* fix(claude): consolidate translator sink type imports
* fix(claude): preserve source message times during catch-up
* fix(claude): narrow staged history mutations to items
* test: bound Claude retained-leaf catch-up work
* fix(claude): settle imported work at source boundaries
* test(claude): keep shared journal harness portable
* test(mobile): await editor listener cleanup before snapshot
* test: isolate retained slice measurements and accept closed socket EPIPE