Commit Graph

81255 Commits

Author SHA1 Message Date
Ayaan Zaidi f2754e4318 fix(slack): stream native task rows as deltas (#125168)
Slack appends task_update details/output per update for the same id (only title/status replace); the native progress stream re-sent every row each snapshot, so bash rows accumulated "completedcompleted…". Reconcile now emits only changed rows with append-only field deltas, keeps status words out of details, and puts the once-emitted result (file delta or failing exit) in output.
2026-08-17 14:39:20 +05:30
Peter Steinberger 5fbf12c0e2 fix(cron): preserve update caller authority (#125180) 2026-08-17 02:05:10 -07:00
Ayaan Zaidi 8c6976e1fc fix(agents): report recovered tool retries (#125078)
Preserve attempt-local recovery state so successful mutation retries emit a redacted terminal receipt without stale failure warnings.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-17 14:35:00 +05:30
Peter Steinberger e8c761ea70 fix: source-external plugins fail after packaging (#125173)
* fix(plugins): keep external runtime roots aligned

* chore: leave changelog to release automation
2026-08-17 02:04:10 -07:00
Peter Steinberger e3d553b734 fix(channels): surface Discord voice failures and preserve Telegram controls (#125152)
* fix(channels): surface degraded Discord and Telegram sends

* fix(telegram): preserve legacy slash callbacks

* fix(ci): correct env-var count after version define removal
2026-08-17 01:56:38 -07:00
Peter Steinberger 0e7f8c9ce9 feat(ui): load session transcripts instantly from snapshots (#125128)
* feat(ui): persist chat session snapshots

* perf(ui): defer snapshot sanitize to flush

* feat(ui): prefetch recent session snapshots

* perf(ui): index snapshot savedAt for prefetch

* fix(ui): keep snapshot invalidation off startup path

* perf(ui): fold snapshot invalidation into deletion handling

* fix(ui): keep snapshot cache out of startup chunk

* fix(ui): avoid snapshot runtime binding shadow

* fix(ui): invalidate session snapshots across tabs

* style(ui): annotate invalidation catch parameter

* chore(ui): drop unused invalidation type export
2026-08-17 01:56:33 -07:00
Peter Steinberger 5ebfbbf8d7 fix(plugins): honor per-agent runtime config (#124978)
* fix(plugins): resolve per-agent config through SDK

* test(codex): preserve agent runtime exports

* test(telegram): make default owner explicit

* refactor(plugins): use lightweight agent scope runtime

* fix(codex): preserve multi-agent execution ownership

* chore(plugin-sdk): record approved agent scope exports

* fix(codex): keep scoped sandbox ownership authoritative

* fix(codex): preserve agent scope in native side actions

* fix(ci): avoid counting node check as environment variable
2026-08-17 01:53:08 -07:00
Peter Steinberger 31a4bab070 fix(runtime): stop counting node check as env var (#125175)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00eb3-f24f-72f5-a885-2d4d81f68433

Co-authored-by: Amp <amp@ampcode.com>
2026-08-17 01:51:05 -07:00
Peter Steinberger 5275eae477 fix(voice-call): honor routed agent credentials for realtime calls (#125144)
* fix(voice-call): select realtime provider per routed call

* test(voice-call): track routing temp directory

* fix(ci): stop counting node check as environment variable
2026-08-17 01:47:16 -07:00
Peter Steinberger 65d1fa4189 test(ui): enforce sidebar cold-open invariant (#125174) 2026-08-17 01:45:17 -07:00
Peter Steinberger ee86b24ac1 fix(node-host): recover MCP catalogs and sessions (#125092)
* fix(node-host): recover MCP catalogs and sessions

Share placement-neutral MCP lifecycle and result projection while keeping Gateway session ownership and node process ownership separate. Refresh node catalogs live, recover closed or expired transports without replay, and preserve MCP application errors across node.invoke.\n\nFixes #125044

* test: register node MCP CI inventory

* fix(node-host): stop MCP recovery after abort
2026-08-17 01:39:33 -07:00
Peter Steinberger fcb499a4ce refactor(channels): move read-gate policy to channel plugins (#125136)
* refactor(channels): move read-gate policy to plugins

* test(channels): declare bundled Discord read gates
2026-08-17 01:38:30 -07:00
Peter Steinberger fb0e8b145e refactor: consolidate final mechanical audit paths (#125165) 2026-08-17 01:30:21 -07:00
WhatsSkiLL 657b6e8f49 feat(android): pin gateway-backed session search in the sidebar (#124338)
* fix-android-chat-session-picker

* fix-search-all-android-sessions

* fix-native-i18n-inventory

* fix-android-share-session-browser-policy

* fix(android): show loading during session search

* refactor(android): move gateway-backed session search into the pinned sidebar

The sidebar header and search field no longer scroll away: they sit above
the scrolling sections, and the search field is always visible instead of
hidden behind a toggle. Queries now run through the shared session-browser
search state (debounced gateway search with offline fallback) instead of a
local filter over cached rows, and matching threads replace the section
list while a query is active.

The in-chat bottom-sheet picker is removed: the compact switcher's All
button navigates straight to the Sessions screen again, and the sidebar
owns in-context session search. The shared rememberSessionBrowserSearchState
extraction from the Sessions screen is kept and gains the sidebar as its
second consumer.

* style(android): fix sidebar import ordering for ktlint

---------

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-17 01:22:16 -07:00
Peter Steinberger 42a46250d4 fix(update): keep a committed post-core result when stopping the child signals (#125150)
* fix(update): keep a committed post-core result when stopping the child signals

The post-core wait settles from three places: a result-file poll, child "error",
and child "exit". The poll stopped the child before claiming the settle, and
stopping delivers a signal, so the still-unclaimed exit handler could reject with
"post-update process terminated by signal SIGTERM" for an update whose child had
already written a valid result. The outer catch then restored the tentative
plugin index, rolling back work that actually succeeded.

Claim the settle first, then stop. The exit handler sees settled and returns.
Net zero production lines; pure reordering plus the invariant comment.

This is the error that leaked across tests in the agentic-cli shard on
2026-08-17 (run 31997770370), where it surfaced inside an unrelated test and
cascaded into 34 failures in src/cli/update-cli.test.ts.

Regression test drives the exact ordering: the child commits its result, then the
parent's stop delivers SIGTERM. It fails on pre-fix code with
"promise rejected ... instead of resolving / post-update process terminated by
signal SIGTERM".

* test(update): satisfy strict indexed access in the post-core signal regression
2026-08-17 01:19:47 -07:00
Peter Steinberger d6b2e14f63 feat(cron): enable automation triggers by default (#125025)
* feat(cron): enable automation triggers by default

Condition watchers, script payloads, and stream schedules were gated behind
cron.triggers.enabled=false, so the capability shipped dark and the automations
tool told the model to call it unsupported.

The gate did not buy what its warning implied. cronJobUsesToolRuntime treats
agentTurn, script, and trigger.script identically for tool policy, and jobs are
capped to the creating agent's allowlist via creatorToolAllowlist -- but an
agentTurn cron job was never gated, so unattended recurring exec with that same
creator-capped authority was already reachable. The gated paths are strictly
tighter: a condition gate gets 30s, 5 tool calls, 16KB state and a 30s minimum
interval, where an agentTurn has no such budget. Sandboxing already applies to
trigger scripts, which resolve sandbox context and redirect the workspace when
access is not rw.

Absent config now means enabled; an explicit cron.triggers.enabled: false still
disables every surface it disabled before, and the error text names the opt-out
instead of telling operators to turn something on. No new config key, no
migration.

Docs: reword the trigger warning for default-on while keeping the unattended
execution note, and record the new default in the configuration reference.

* test(cron): refresh prompt snapshots for default-on triggers

Trigger, stream-schedule, and script-payload surfaces are now advertised in the
automations tool description by default, so the committed fixtures drift.

This also records the cost: dynamicToolsJson grows 49,477 -> 52,541 chars and
the snapshot total 76,861 -> 79,925 (~766 rough tokens per prompt). That is the
price of no longer dark-shipping the capability.

* test(mcp): expect trigger surfaces by default in the tools bridge

The MCP tools bridge mirrors the scheduler gate, so an absent cron.triggers
config now advertises the trigger surface. Explicit false still narrows it and
explicit true still widens it; both assertions are unchanged.
2026-08-17 01:12:10 -07:00
Peter Steinberger 57e3ee6513 fix(ui): make project browser the Files panel default (#125138) 2026-08-17 01:08:28 -07:00
Peter Steinberger 8e44c90f53 test(plugins): drop duplicate SDK-alias loader case that timed out under load (#125134)
The deleted case took ~54s and exceeded the 120s per-test timeout under CPU contention. Its coverage is already provided by the sibling pre-split SDK bridge case, which spans both private-local-only and public alias classes, and by extensions/llama-cpp/index.test.ts.
2026-08-17 01:03:45 -07:00
Peter Steinberger faed554dd6 fix(ci): refresh Control UI startup gzip baseline (#125156) 2026-08-17 01:01:00 -07:00
Peter Steinberger 05bbd48c51 docs(install): clarify lifecycle script trust (#124727)
* docs(install): approve OpenClaw lifecycle scripts

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(update): bind npm lifecycle policy to install owner

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(update): gate npm lifecycle policy before mutation

* test(update): cover npm lifecycle ownership

* fix(update): defer backup cleanup until package preflight passes

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(update): preflight npm policy before service stop

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* docs(install): avoid unsupported lifecycle claim

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-17 01:00:17 -07:00
Peter Steinberger e446679131 perf(test): reuse SMS test modules (#125151) 2026-08-17 00:56:34 -07:00
Peter Steinberger 3b8f9fb5a2 fix(talk): preserve agent scope in browser capabilities (#125142)
Ensure gateway-control capability checks use the same routed agent as realtime provider readiness and browser-session authentication.
2026-08-17 00:42:54 -07:00
Peter Steinberger 23ea04a375 refactor(media): remove orphan runtime facades (#125121) 2026-08-17 00:42:33 -07:00
Peter Steinberger a917c99e92 fix(runtime): classify Node releases consistently across install and launch (#124812)
* fix(runtime): align Node release version guards

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(runtime): include Node version helper in source fixture

* fix(install): align Node release checks across boundaries

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix: keep node version guard legacy-compatible

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(runtime): exercise legacy launcher preflight

* fix(installer): validate installed Node release versions

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(installer): compare Node version parts numerically

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(installer): cover 17-digit Node major

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-17 00:42:23 -07:00
Peter Steinberger 9a947e4bb8 fix(sessions): flatten Markdown in session list previews (#125113)
* fix(sessions): flatten Markdown in session list previews

Session-list previews were extracted verbatim from the last transcript
message, so raw Markdown leaked into every surface that renders the
subtitle as plain text — Control UI sidebar, TUI picker, native session
lists, and the sessions_list tool. A finished session read as
"Landed [PR #124879](https://github.com/...)".

Flatten lastMessagePreview at the Gateway producer, inside the
watermark-validated title-field cache, so the cost is amortized and no
consumer re-implements stripping. The flattener is the regex chain that
already existed privately in the Control UI narration line; it moves to
@openclaw/normalization-core/markdown-plain-text and both surfaces now
share one implementation. Session titles keep their own normalization
and are unchanged.

Also let an unread final observer digest outrank the raw last reply in
the sidebar subtitle, so the utility model's headline wins the slot it
was written for. The finalDigestUnread gate is untouched, so an
already-read digest still falls back to the flattened preview.

* fix(ci): register Markdown preview module

* fix(sessions): preserve literal preview punctuation

* fix(sessions): flatten previews before truncation

* fix(test): adapt session projection callback
2026-08-17 00:40:16 -07:00
Peter Steinberger 8c2d5f9147 fix(security): warn on main-scoped group rooms (#125054)
* fix(security): warn on main-scoped group rooms

* fix(security): ignore direct-only group scope bindings

* fix(security): honor group binding precedence
2026-08-17 00:37:35 -07:00
Peter Steinberger 8f145789b5 fix: diagnose gateways that cannot host nodes (#125132)
* fix(doctor): expose node hosting preconditions

* fix(doctor): use canonical string coercion

* fix(auth): narrow identity header rejection
2026-08-17 00:30:21 -07:00
Peter Steinberger 7fd6d06848 fix(onboard): cancel cleanly when stdin ends (#124780)
* fix(onboard): cancel prompts on terminal EOF

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(onboard): isolate EOF cancellation process

* test(onboard): run EOF process test from source

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(onboard): isolate EOF process proof

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(onboard): inline EOF process fixture

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(kilocode): allow elapsed timeout budget

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-17 00:25:46 -07:00
Peter Steinberger f59e945013 feat(gateway): move sessions between Gateway and runners (#125036)
* chore: preserve session placement move work

* feat(gateway): move sessions between runners

* test(gateway): align recovery fixture with move barriers

* fix(protocol): format literal-only Swift initializers

* test(ui): prove session move terminal state

* refactor(gateway): narrow session move target fence

* fix(gateway): preserve pending result recovery ownership

* test(workers): migrate reclaim lifecycle fixtures

* refactor(gateway): keep move internals private

* test(gateway): align split bootstrap fixture with moves

* fix(gateway): recover session moves through exact intent

* refactor(gateway): derive move placement subtypes locally
2026-08-17 00:23:13 -07:00
Peter Steinberger 2a43508756 docs(markers): tag transitional marker surfaces with their removal trigger
Every surface that survives only until the messages.visibleReplies default
flips to message_tool now carries a greppable TRANSITIONAL(marker-retirement)
comment naming that trigger: the reply/audio parser family, streaming
tail-buffering, the write-boundary applier, automatic-mode prompt teaching,
the [[tts]] DSL + streaming cleaner, and the live narration strip. Comment-only.
2026-08-17 00:21:37 -07:00
Peter Steinberger 2a556234c2 fix(install): persist OpenClaw PATH in Unix shells (#124779)
* fix(installer): persist user bin across fresh shells

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(installer): stop when profile copy fails

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(install): follow Bash profile precedence

* fix(install): safely update read-only shell profiles

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(installer): isolate login profile proof

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-17 00:21:11 -07:00
Peter Steinberger ab143955aa fix(discord): restore voice auto-join on multi-agent gateways (#125069)
* fix(discord): report voice channel access failures

* fix(discord): keep realtime auth agent-scoped

* test(discord): model followed-channel lookup failure

* fix(discord): preserve cancelled voice joins

* refactor(discord): centralize cancelled join result
2026-08-17 00:18:14 -07:00
Peter Steinberger 2b2c11e748 fix(install): keep stable channel when npm install retries (#124778)
* fix(installer): keep npm channel target immutable

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(install): fail after repeated CLI package install errors

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(installer): verify npm package publication

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* fix(install): satisfy shellcheck for entry validation

* fix(installer): link the packaged OpenClaw launcher

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

* test(installer): keep retry fixture version-valid

Amp-Thread-ID: https://ampcode.com/threads/T-01a00ae0-190d-718b-8a76-b75f3e8d1fae

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-17 00:17:26 -07:00
Peter Steinberger 1027837d96 fix(msteams): avoid ambiguous delivery replay (#125127) 2026-08-17 00:13:59 -07:00
Peter Steinberger 0e3a3aa203 refactor: finish canonicalization stragglers (#125056)
* refactor: finish canonicalization stragglers

* chore: remove release-owned changelog entry

* refactor: narrow SecretRef SDK import
2026-08-17 00:09:29 -07:00
Peter Steinberger 60f238c5af fix(ci): scope the Node toolchain cache to runners that need it
GitHub-hosted images carry Node 24.19.0 in /opt/hostedtoolcache, so hosted jobs
resolved from there and never populated the cached root. They still ran a
restore that could only miss and then a save whose path did not exist, logging
"Path Validation Error: Path(s) specified in the action for caching do(es) not
exist" on every hosted job. No entry was ever written, so nothing was poisoned,
but the warning is noise and the steps are pure waste on ~30 jobs per run.

Gate both steps on runner.environment != 'github-hosted', the signal this
workflow already uses for Blacksmith-only behavior, and gate the save on the
setup step reporting that a download actually populated the root. That second
guard also covers a future self-hosted image whose toolcache clears the floor.

Verified on Blacksmith: a satisfying image toolcache leaves the root absent so
the save is skipped, and a download populates it so the save runs.
2026-08-17 00:04:53 -07:00
Peter Steinberger 53cede420f perf(test): complete managed handoff explicitly (#125129) 2026-08-16 23:56:29 -07:00
ClawSweeper 84853266e7 fix(ui): widen the review sidebar by default (#125116)
* fix(ui): widen code review panel by default

* test(ui): align sidebar layout default

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-16 23:55:49 -07:00
Peter Steinberger 2e1a9a1a3d perf(gateway): reduce chat history read-path work (#125123) 2026-08-16 23:54:20 -07:00
Peter Steinberger 83d279a4c1 fix(cli): honor channel resolve agent ownership (#125109)
* fix(cli): honor channel resolve agent ownership

Forward explicit channel owners through command-time secret collection and later workspace/channel resolution, preventing AGENT_SELECTION_REQUIRED in multi-agent configurations.

* fix(cli): narrow explicit agent option value

Use runtime string narrowing for the Commander option so agent-owner forwarding remains assertion-free and satisfies the assertion-safety ratchet.

* docs(cli): document channel resolve agent owner
2026-08-16 23:50:52 -07:00
Peter Steinberger 7b18510e6c fix(config): materialize fresh-install defaults for missing config (#125110)
* fix(config): materialize fresh-install defaults for missing config

A missing config file (fresh install) skipped runtime-defaults
materialization on both loadConfig and readConfigFileSnapshot, while an
existing empty {} config got the full defaults (compaction safeguard,
session/cron/model defaults). Out-of-box behavior silently diverged from
the documented defaults until the first config write created the file.
The drift dates to bc75968074, which dropped the missing-branch
materializeRuntimeConfig call during an import-trim.

Route the missing-file branches through the same load/snapshot
materialization as existing configs, and delete the now-unreferenced
per-mode defaults profile table in materialize.ts — load and snapshot
must materialize identically anyway (prepared-runtime exact-config
resolution depends on it), so the profile indirection only invited
drift.

* chore(ratchet): shrink io.load.ts assertion baseline to 2

The missing-config fix removed an 'as OpenClawConfig' cast; the
assertion-safety ratchet requires the baseline to shrink with it.
2026-08-16 23:48:46 -07:00
Peter Steinberger b1e76c4640 refactor(ui): define review default document (#125105) 2026-08-16 23:48:28 -07:00
Peter Steinberger 29b105beda docs(gateway): record why Control UI admission exemptions exist (#125108)
* docs(gateway): record why Control UI admission exemptions exist

* docs(gateway): state the configured-root exemption reason precisely
2026-08-16 23:45:54 -07:00
ClawSweeper 1d65e7b449 test: default trusted checks to local execution (#125120)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-16 23:45:50 -07:00
Peter Steinberger 4e1f26dc18 refactor(gateway,ui): one bounded display projection; delete marker strip sites (#124997)
* refactor(gateway,ui): one bounded display projection; delete marker strip sites

Persisted transcripts are marker-free since the write-boundary projection
(#124793), the historical migration (#124888), and TTS facts (#124913), so
display surfaces stop compensating. sessions.list.lastMessagePreview and its
siblings (sessions.preview/describe, TUI picker, sessions_list tool, MCP) now
share one bounded role-aware projection (240 chars, tool/system/thinking and
suppressed control replies excluded, directive-only rows fall through). The
web reply chip reads the typed openclawDelivery fact instead of parsing text;
chat.history preserves the field to the UI. Post-hoc display strips are
deleted across web/TUI/MCP/sessions-list; live streaming cleaners stay.
Stale gateway-protocol preview comments corrected; no schema change.
Assertion-safety baseline pruned for shrunk files (sanctioned direction).

Production net -173, tests net -137. Fixes the sidebar [[reply_to_current]]
preview leak and the empty-code-pill overstrip of quoted markers.

* fix(agents): preserve restart recovery transcript reads

* refactor(gateway): remove obsolete transcript exports

* fix(gateway): normalize injected delivery directives

* fix(ci): scope projection and recovery checks

* chore(ci): shrink plugin SDK surface budgets

* test: deflake loaded side question and worker checks

* test: align display projection CI fixtures

* style: format display projection fixture
2026-08-16 23:44:29 -07:00
Peter Steinberger 59c661bf66 fix(gateway): prevent large history from blocking chat startup (#124994)
* fix(gateway): bound startup history materialization

Apply SQLite byte limits before loading history payloads and share a yielded, fingerprinted Claude CLI snapshot across concurrent startup clients. Preserve marker, cursor, redaction, and external identity semantics, and clarify that shrink-only ratchet updates need no separate approval.

* test(browser): await all lazy command groups

* fix(gateway): bound history snapshot state

* fix(gateway): preserve oversized history responsiveness
2026-08-16 23:43:40 -07:00
Peter Steinberger 73ab74eccc fix(discord): preserve routed agent for realtime voice (#125111) 2026-08-16 23:41:38 -07:00
ClawSweeper 6b86199892 fix(ui): keep session status icons visible (#125096)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-16 23:39:21 -07:00
Peter Steinberger 3010318ba3 fix(android): isolate debug app installs (#125099) 2026-08-16 23:36:57 -07:00
Peter Steinberger ac5c8be001 fix(ui): keep agent terminals backgrounded (#125101) 2026-08-16 23:32:06 -07:00