* fix(source-control): use Codex's configured model by default
Source Control AI pinned Codex to gpt-5.5, which Codex retires on
2026-10-14. Any path that still resolves to that slug would then break
commit-message and PR-field generation.
Follow the Antigravity precedent (#21606): add a "Config default" entry
for Codex, make it the default, and omit --model when it is selected so
`codex exec` uses the model from the user's Codex config or Codex's own
default. Explicit model choices still pass --model.
Older remote servers would still build `--model default`, so advertise
git.codex-configured-model.v1 and have clients refuse the sentinel for
servers without it, the same way Antigravity is gated. The gate now
covers both agents, and the two capabilities live in their own module
because protocol-version.ts is at the max-lines limit.
Written with AI assistance (Claude Code).
Fixes#24481
* fix(source-control): honor -m, repo overrides and low effort for Codex
Review on #24495 found three gaps in the configured-model change.
The remote compatibility gate only recognized --model, so a recipe
passing Codex's -m short flag was rejected on older servers. The gate
also ignored the repository's per-operation model override that the
server applies. And moving Codex to Config default dropped the low
reasoning effort the pinned model used, which would change cost and
latency for users whose Codex config sets a higher effort.
* fix(source-control): match gate repo and model checks to the server
Repo ids can repeat across hosts, so the configured-model gate now reads
the repo row for the worktree's host instead of the first id match, the
same row the server applies. A recipe passing --model default or
-m default no longer counts as an explicit model, since an older server
still forwards that sentinel to the Codex CLI.
* fix(source-control): read only the worktree host's repo row in the gate
A worktree that names its own host must not fall back to the runtime
host's repo row, since the server applies the row for the worktree's
host. Also cover an environment id that needs URL encoding.
* fix(source-control): default Codex to GPT-5.6 Terra low
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Three fixes, all on paths this PR could not exercise locally.
The managed hook command was stored as a bare path. jcode tokenizes that
string shell-style before exec'ing it directly (parse_hook_command,
crates/jcode-terminal-launch/src/lib.rs): unquoted whitespace splits, and
every unquoted backslash is consumed as an escape. So on Windows
`C:\Users\me\.orca\agent-hooks\jcode-hook.cmd` reached exec as
`C:Usersme.orcaagent-hooksjcode-hook.cmd` and no hook fired at all, and a
POSIX home with a space split into two arguments. Store the path
single-quoted (verbatim, backslashes included), falling back to double
quotes for a path containing a single quote. Existing bare entries are
already repointed by the stale-key path, and getStatus accepts both forms
so the repair is not reported as a user-owned hook. The quoting helper was
previously dead code that only tests called; the three production sites
now use it. isJcodeManagedCommand also normalizes separators, since a
`/`-only needle never matched a Windows entry.
Commit-message generation feeds a staged patch to `jcode run` as the
prompt — attacker-influenced text — while jcode's default profile exposes
shell, read, write, and MCP. Pass `--tool-profile none`, which resolves to
an empty allowed-tool set in jcode's config (base_allowed_tools), matching
the read-only posture claude (plan) and codex (read-only) already take.
docs/reference/jcode-hook-events.md was never actually in this PR: the
repo ignores docs/** and tracks reference docs by allow-list only, so the
captured-payload evidence four source comments point at was silently
dropped. Allow-list it.
Co-authored-by: czzczz <chanzrz_zbf@foxmail.com>
Ports PR #10521 onto current main: agent catalog, managed hook service,
agent-status listener, session resume, AI Vault parser, per-pane daemon
isolation, and Source Control AI support.
Co-authored-by: Neil <neil@stably.ai>
* fix(source-control): generate clean OpenCode answers on local and SSH hosts
Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes.
Original-commit: 64bb15e3f2
fix(source-control): generate clean OpenCode answers on local and SSH hosts
Use configured models and JSON answer/error events, preserve run-first arguments, and handle the precise v2 variant rejection. Hydrate SSH execution-host PATH through the existing bounded login environment resolver before direct spawning.
Credits: andy-murr (PR #5197 SSH environment intent) and coelho-doti (PR #13065 argument-order intent).
Original-commit: 1b60ec5d11
fix(source-control): retry inline OpenCode model and variant options
Original-commit: 98fdecc7a3
Preserve OpenCode named errors without a data message
Restacked-from: 98fdecc7a3
Restacked-onto: f7b1f9d8be
* fix(ci): prevent concurrent pnpm refresh during mobile typechecks (#24776)
* fix(ci): run mobile typechecks without concurrent dependency refresh
* test(ci): check effective Linux E2E package list
* test(ci): preserve the mobile production compiler barrier
---------
Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example>
* test(terminal): restore the live fish fixture prerequisites (#24947)
A restored pane waits for the initial status replay before subscribing to
PTY output. This fixture never settled that replay, so fish printed its
mode-2031 arm before the renderer connected. Its PTY API also omitted the
reset-input listener required by the serializer, aborting attachment.
Settle and dispose the existing startup-snapshot registration and provide
the same reset-listener mock used by the other PTY tests. The real fish
child-stdin assertions and timeouts remain unchanged. No production change.
* fix(shortcuts): defer TUI editing chords in terminal-first mode (#24640)
Restack the original focused change onto current main, preserving every owned source and test blob and the merged CI contract and journal cleanup fixes.
Original-commit: f707cde14a
fix(shortcuts): defer TUI editing chords in terminal-first mode
Original-commit: 0c6348e49e
docs(shortcuts): describe deferred preview terminal chords
Original-commit: be62c1b6c6
Align worktree history shortcut metadata with terminal conflict policy
Restacked-from: be62c1b6c6
Restacked-onto: f7b1f9d8be
* Register supervised Qoder China and Qwen Code (#24616)
* Add Qoder session history and search with real CLI coverage
* Allow the real Qoder marker file to end with a newline
* Keep Qoder tool output out of history previews and search
* Keep Qoder search pages readable by older clients
* Verify persisted Qoder history after a real generated and resumed task
* Negotiate Qoder filters before searching an older execution host
* Combine search client imports for the CI plugin gate
* Keep the relay search oracle aligned with legacy agent filtering
* Register supervised Qoder China and Qwen lifecycle integration
* Cover Qoder China mobile assets and mixed-host resume gates
* Verify Qoder provider tags against the older released wire parser
* Verify China and Qwen keep independent Windows hook scripts
* Verify Qoder registrations against the installed older Windows release
* test(qoder): align search capability contracts and pin old-host fencing
* fix(qoder): rank exact picker identities and command aliases first
* test(qoder): preserve the regional CLI shared icon expectation
Keep the full bundled-asset and no-remote-image checks, with an explicit
shared-logo basename for Qoder China. The map also works with older
catalog type unions.
* fix(qoder): align China catalog entry with fallback order
---------
Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example>
* Use the measured pnpm lookup policy automatically in hosted root CI (#24951)
* Select lookup automatically for the measured hosted root-install profile
* Record hosted automatic-mode cold cache publication proof
* fix: bound remote generation setup and honor OpenCode option terminators
Count execution-host profile resolution inside the existing request deadline, cancel its waiter promptly, and pass only the remaining time to the child. Shared bounded profile probes keep their existing cache lifetime; the SSH transport margin is unchanged.
Read OpenCode output format from active final-argv options before -- so literal prompt arguments cannot select the JSON finalizer.
Fresh exact-source controls reproduce nine failures before; 139 related checks pass after, including primary/fallback delays, deadline boundaries, cancellation, parser metadata, and SSH lanes. Node typecheck and strict changed-file lint pass.
* Continue Antigravity IDE and 2.0 history in new CLI conversations (#24692)
* feat(antigravity): bridge IDE history into new CLI conversations
* fix(antigravity): preserve fresh-launch model and environment for IDE references
* fix(antigravity): forward IDE history opt-in through desktop IPC
* fix(antigravity): rebuild remote IDE reference startup on its host
* fix(antigravity): register IDE continuation action labels
* fix(antigravity): confine IDE references and bound metadata reads
* fix(antigravity): localize IDE continuation badges
* Preserve scanner service cache assertions and refresh Antigravity opening metadata
* Preserve Antigravity opening joins and target folder runtime authority
* fix(opencode): retry timed-out SSH plugin updates (#24666)
Preserve bounded retry behavior and the current-main status-envelope fields.
Original-PR: #24124
Reviewed-source: 103144f9c5
Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
* fix(opencode): keep Go credentials private and resolve backend keys (#24615)
Preserve the complete credential storage, migration, IPC, Settings and rate-limit refresh change alongside standalone GLM plans, current-main database diagnostics and the reviewed unknown-backend environment correction. Keep native discovery cancellation third and selected environment fourth.
Original-topic-commit: 7903f1cddb
Original-topic-commit: 588117b5cf
Original-topic-commit: dedd4f8c86
Original-topic-commit: 6645dae104
Original-topic-commit: a25b80c02c1af7830b0e6a65e72d965b3ad98276
Restacked-from: a25b80c02c1af7830b0e6a65e72d965b3ad98276
Restacked-onto: b032867021
Co-authored-by: kespineira <kespineira@users.noreply.github.com>
Co-authored-by: kevimux <kevimux@users.noreply.github.com>
Reported-by: pullfrog
Reviewed-full-source: 849fe093073f4c1606bd65d79a0c725d955d0d1f
Native-helper-source: 80dbe23237
Reviewed-full-current-source: 36acb57d44adb3d378c0289c8c15f7da0fda214c
* fix(opencode): enforce deadline through executable startup
Keep synchronous Windows PATH resolution and child startup within the existing request budget.
---------
Co-authored-by: Orca Integration Recovery <orca-validation@invalid.example>
Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
Removes ~74 assertions of the form `expect(SOME_CONSTANT).toBe(<literal>)` where
the literal is an internal tuning value — a timeout, retry count, debounce
interval, cache TTL, circuit-breaker window, Tailwind class string. Those cannot
fail for any reason a user would notice: they fail only when someone deliberately
changes the number, and then the test is simply updated. They are copies of the
declaration.
The same pattern is NOT junk when the exact value is observable outside this
process, so those were deliberately kept:
- terminal byte contracts: `\r`, `\x03` ETX, Kitty escapes, `\x1b[?1;2c`;
- wire and capability values: `agent.launch.v2`, protocol 3 / min-compatible 2,
daemon per-feature boundary versions (a daemon survives app updates, so those
pin what an old field daemon may be trusted with), relay header tokens;
- security invariants: the `127.0.0.1` bind default, an empty iframe `sandbox`;
- values external processes read: exit code 78 (EX_CONFIG) and exit code 3
(systemd `RestartPreventExitStatus`), `ORCA_AGENT_SESSION_SPAWN_TOKEN`,
`npx skills …` commands users paste, on-disk journal schema versions,
the `orca_<hash>` filename prefix the fish sweeper matches;
- third-party names: expo-router's `unstable_settings` / `ErrorBoundary`,
iOS Safari's 16px zoom threshold.
Where a case asserted a relation rather than a literal — `A < B`, a sum of parts,
a cap compared against a sibling budget — the relation stays and only the literal
went.
Test-only changes: no production file is touched and no test file is deleted.
Sixth and final wave over the modules that export symbols only tests import.
Deletes private-predicate cases whose behavior is already asserted through the
module's real entry point, then makes the symbol private again.
Also removes three distinct junk shapes the earlier detectors missed:
- a self-comparison whose expected empty row was produced by the helper under
test (`worktree-palette-search`), now a literal;
- expected values computed by a sibling helper rather than asserted
(`terminal-theme`), now read through the production `getBuiltinTheme`;
- a negative control that cannot fail — `expect('json' in jsonlMonarchLanguage)
.toBe(false)`, where `IMonarchLanguage` has no such key, so it guarded nothing
while appearing to guard "does not attach the JSON language service".
Dead production code removed where tests were its only callers:
`refreshWindowsTerminalCapabilities` (a one-line alias for
`loadWindowsTerminalCapabilities({force: true})`), `readSpoolRecords`,
`buildAgentPromptSubmitBytes`, and `getCommitMessageModelCapability`.
About 70% of everything this detector flagged across the whole vein was a false
positive, so most modules were left untouched. Bounds consumed as test input,
`*ForTests` seams, non-hook cores of `useSyncExternalStore` hooks, and
value-position registrations all look identical to a leaked internal from the
outside and are not.
* feat(agents): add first-class DeepSeek Harness (dsh) support
Register DSH as a supervised Orca agent: catalog entry and detection for its
dsh-tui profile, status/question hooks through DeepSeek's own Claude-Code hook
bridge, composer-ready prompt delivery, session resume, headless Source Control
AI, and title identity that no longer collides with Gemini's.
* fix(dsh): reach Orca through DSH's credential scrub and stop reading its title as Gemini
DSH runs command hooks through its own shell executor, which drops every env var whose
name contains KEY, TOKEN, SECRET or PASSWORD — taking ORCA_PANE_KEY and
ORCA_AGENT_LAUNCH_TOKEN with it, so every hook exited without posting. Mirror both onto
scrub-safe aliases at spawn and restore them at the top of the DSH hook script.
Its title collided too: DSH rests on the same glyph Gemini works on, so a resting DSH
pane was relabelled Gemini CLI and reported working forever. Defer both the Gemini
classifier and the title status detector on DSH's whale, in the base module both copies
of that classifier read.
* test(mobile): repin the session-route closure for the DSH agent icon
* fix(dsh): address review — never splice user rows, cover remote panes, keep the diff off argv
- findManagedDshPatchRegion paired an orphan start marker with a later block's end, so a
truncated write made install/remove delete the user's own rows. Pair each end with the
nearest preceding start; regression test fails without the fix.
- The relay PTY env builder never applied the scrub-safe aliases, so remote DSH status
silently never appeared even with the remote hook installed.
- Source Control AI sent the whole diff on argv; send it over stdin with DSH's '-' marker.
- dsh-tui/dst already chose the interactive profile, so a workspace folder named 'web' or
'plugin' no longer marks a live agent pane non-interactive.
- Isolate USERPROFILE as well as HOME so a Windows run cannot edit the real home.
- Drop the duplicate README badge and revert an incidental doc reformat.
* refactor(dsh): share the managed-hooks reader and tighten the new modules
Reuse before reimplementing: readManagedDshHookEvents was a near-verbatim copy of Muse's,
with byte-identical private helpers. Both now call one readManagedHookEventsFromJson.
Also: one readTextOrAbsent instead of two spellings of the same read (dropping an
existsSync TOCTOU), one status() builder instead of four inline literals, rmSync(force)
instead of exists-then-unlink, and a redundant empty-string guard before JSON.parse.
The patch-file transforms lose their index juggling for a predicate plus a filter.
* fix(dsh): refuse a flow-style patch file, keep its mode, and stop the relay inheriting a pane
- applyManagedDshPatch matched only an exact `[]`, so `[] # keep empty` or a non-empty
flow sequence got a block entry appended after it — invalid YAML that would leave DSH
unable to load the user's own patch layer either. It now strips the token from an empty
sequence (keeping a trailing comment) and returns null for a non-empty one; install
reports that and changes nothing.
- The patch rewrite dropped an owner-only file to the umask default (CWE-732); pass
preserveMode.
- The relay PTY env never dropped inherited pane identity the way the local and daemon
builders do, so a spawn that specified none could inherit the relay's own and every
agent's hook would report against that pane.
* fix(dsh): keep the flow-style refusal in every status read, and scope the mode test to POSIX
A refused patch file carries no managed region, so getStatus() fell through to a bare
not_installed with detail null — the actionable 'rewrite it as a block sequence' message
only ever reached the one-shot install() return. Export the predicate and check it first,
behind one shared message constant.
The owner-only mode assertion cannot hold on Windows, where chmod only toggles the
read-only attribute and mode & 0o777 reads 0o666 for any writable file.
* docs(readme): restore the DeepSeek Harness badge lost in the rebase
* test(mobile): repin the session-route closure to the measured 4221
Measured, not derived: 4220 without the DSH icon entry, 4221 with it. Two of the three
modules above main's 4218 pin are not this change's — they arrived with the mobile work
after #22570 and were never repinned; the changelog records that split explicitly.
* fix(dsh): settle tui-idle on the agent's own hook, so supervised workers see it ready
Reported by a tester on the adhoc build: `terminal wait --for tui-idle` ran to its 90s
timeout against an already-ready DSH composer, so a supervised worker never sees the agent
as ready.
Every existing tier reads the title, and DSH deliberately carries no title status: its rest
prefix is Gemini's working glyph, so the detector reports none. A fresh first-party `done`
is better evidence than any title anyway — it is the agent's own account of its own turn,
and normalizeDshEvent drops subagent events, so it is the lead's. Scoped to DSH: for agents
whose hooks report child turns, a mid-turn `done` is the #6011 class this file prevents.
* test(daemon): record the DSH transcript's true-colour I2 divergences
Adding the dsh-tui capture to __fixtures__ enrolled it in the serialize replay sweep, where
it reports 10 I2 divergences and failed the unlisted-transcript default of 0.
Every one is the same shape — visible-grid row=0, a 24-bit background the round trip does
not restore to default — which is DSH's whale intro painting whole rows of true colour.
Verified as an upstream limitation rather than a regression by replaying against the
previous build (build-serialize-addon-at-ref.mjs --ref origin/main): I1 and I3 both hold.
* fix(dsh): return the new tui-idle verdict from the first-party done lane
Main refactored isTuiIdleSatisfied into evaluateTuiIdle, which returns a verdict rather
than a boolean. The DSH lane still returned `true`; it is tier-1 positive evidence, so it
returns READY_STRONG like the title/body lane above it. Re-verified the regression test
still fails without the lane.
* test(relay): pin the scrub-safe pane-identity aliases on the relay spawn path
The relay builds a remote pane's env itself, so the alias mirroring there had no
test: removing the call left every suite green while remote DSH status silently
vanished. Both cases fail without it.
* docs(dsh): point the hook service at the integration reference
The reference doc had no inbound link from anywhere in the repo.
* feat(agents): add first-class Muse Code harness
Add Muse as a supervised Orca agent across desktop, mobile, session history, source control, local hooks, SSH, WSL, and native Windows. Preserve user settings, support Muse 1.3 hook environment allowlists, and recognize versioned foreground processes. Include question, waiting, completion, resume, and readiness coverage.
Co-authored-by: homesh-dev <300847526+homesh-dev@users.noreply.github.com>
Co-authored-by: jeffhuen <32542276+jeffhuen@users.noreply.github.com>
Co-authored-by: John Cusack <johncusackccm@gmail.com>
Co-authored-by: Adrien De oliveira <75085839+adriendeoliveira@users.noreply.github.com>
* test(agents): cover Muse remote hook registration
* test(agents): cover Muse hook and source-control contracts
* test(agents): exclude Muse hook metadata from script mode check
* test(agents): keep Muse skill picker coverage stable
* test(ai-vault): include Muse in every-agent fixture
* test(mobile): repin Muse agent icon closure
* fix(muse): detect questions and approvals from structured Muse signals
Muse 1.3 fires no hook for request_user_input, so a pending question left
the pane "working". Its internal reminder subagents also post hooks with
their own session ids (even after Stop), which surfaced "tool failed" rows
and flipped finished panes back to working.
- Read pending questions from Muse's session log
(user_input_prompt_requested/settled) via the existing transcript poll,
now generalized from Codex subagents to Muse on main and relay.
- Drop child-session hooks (SubagentStart ids, or turn_id === session_id).
- Treat Notification permission_prompt as the approval wait; PermissionRequest
also fires for auto-approved calls, so it only caches the approval card.
- Ignore Notification copy as the prompt; poll replays are not new prompts
or turn boundaries.
- Allowlist USERPROFILE so Windows cmd AutoRun doesn't fail every hook.
* perf(muse): parse only question events from the session log
Most Muse session-log lines are large model/tool records. Filter raw lines
by the user_input_prompt_ marker before JSON.parse via an optional
readJsonlCursor line filter.
* fix(muse): unwrap batched log records and scope questions to the live turn
Review follow-ups: question events inside retained_frame batches were
skipped, and a question left open by a crash or interrupt stayed pending
for the pane's life. Share the history scanner's retained_frame unwrapper,
and only report a pending question whose run_id matches the hook turn_id.
* refactor(muse): drop type assertion in retained_frame unwrap
* fix(agent-hooks): satisfy exhaustive-switch lint in transcript poll policy
---------
Co-authored-by: Adrien De oliveira <75085839+adriendeoliveira@users.noreply.github.com>
* fix(pi): let Source Control AI use Pi configured default
When Orca runs Pi for automatic branch names or commit messages without an explicit model override, omit --model so Pi resolves its configured provider. Preserve explicit discovered model selection and add regression coverage.
* fix(pi): preserve discovered fallback for non-Pi agents
Keep the configured-default sentinel behavior limited to agents whose default is the explicit CLI sentinel. Other dynamic agents still fall back to the first discovered model when their static default is unavailable.
* test(pi): pin configured-default dry-run arguments
Prove Source Control AI does not render the Pi configured-default sentinel as a literal model argument, and assert explicit model flag pairing positionally.
* feat(source-control-ai): support OMP text generation
Read prompts on stdin, retain OMP configured model by default, and reuse JSON model discovery.
Co-authored-by: unknown <1784931579@qq.com>
* test(source-control-ai): cover OMP large input and model overrides
* fix(omp): keep configured model default out of discovered catalog
* fix(omp): hide config default from model discovery catalog
* fix(omp): separate terminal discovery from generation defaults
* test(omp): keep model probe import compatible with CLI typecheck
* test: align Source Control AI registry contracts with OMP
---------
Co-authored-by: unknown <1784931579@qq.com>
* fix(commit-message): use Kimi --prompt instead of Claude --print
kimi-code rejects --print (suggesting --prompt). Deliver the generation
prompt as the --prompt argv value so branch auto-rename and commit
message generation work when Kimi is the selected agent.
Fixes#11669
* test(commit-message): cover Kimi argument defaults
* feat(native-chat): track Claude models from the installed CLI per host (STA-3330)
The Claude seed no longer pins version labels to aliases that resolve
differently across CLI versions, and the catalog now defines listModels
backed by a one-shot list_models control request over --print stream-json.
Hosts whose CLI predates the request answer with a control error and keep
the seed. Discovery also feeds Source Control AI via the commit-message
spec, and the /model echo detector matches resolved model names.
* fix(native-chat): preserve discovered Claude capabilities
* fix(native-chat): tolerate malformed Claude model entries
* fix(native-chat): discover models in folder workspaces
* fix(native-chat): trust discovered Claude capabilities
* fix(native-chat): remove Claude model fallbacks
* fix(native-chat): keep the Claude model picker rendered
The Claude picker rendered nothing until the per-host `list_models` probe
returned, so it popped in ~1s after mount and never appeared at all when
the probe failed — an old CLI without `list_models`, no `claude` on PATH,
or an older remote runtime whose response omits `catalogOrigin`.
Restore the version-neutral family seed as the starting list; discovery
still replaces it wholesale on success, so a host with a real catalog
never shows an obsolete hardcoded row.
Separately, the tracked model could fall outside the active list: the
terminal header scrape yields family ids (`opus`) while a current CLI
lists `opus[1m]` and no plain `opus`. That blanked the picker trigger and
dropped the model's effort and fast-mode controls. Reconcile the tracked
id into the active list once, so the snapshot, the appliers, and typed
command recording all see a labelled, operable row for it.
* Add agent enablement controls
Implements the Enable/Disable Agents Dashboard behavior described in docs/enable-disable-agents-dashboard.md, including persisted agent enablement state, filtered launch surfaces, and settings UI affordances.
* Clarify agent availability controls
* Respect disabled agents across workspace and AI defaults
- Filter disabled TUI agents from mobile and quick workspace selection
- Avoid implicitly choosing disabled agents for commit/PR AI settings
- Broadcast settings changes to open windows for disabled-agent updates
* rm design doc
* fix: complete agent enablement propagation