Commit Graph

78549 Commits

Author SHA1 Message Date
Peter Steinberger 4fcd9e12d9 fix(build): cancel stalled CLI metadata renderers (#122634)
* fix(build): drain startup metadata renderers

* fix(build): preserve undrained metadata state
2026-08-12 07:01:46 -07:00
Peter Steinberger df707a9670 feat: view this machine in the Desktop panel (#122545)
* feat(gateway): add gateway-host desktop source behind desktop.host lab

Introduce the host as a first-class desktop source so operators can view
the machine OpenClaw runs on, not just cloud-worker environments:

- protocol: desktop.observe / desktop.launch with a discriminated
  DesktopSource union (host | environment) plus an additive auth hint;
  EnvironmentSummary gains a top-level desktop flag
- config: desktop.host { enabled, port?, passwordFile? }, Labs-gated
- rfb-probe: pure RFB version/security-type parser used to detect an
  already-running loopback VNC server and classify its auth
- host-source: attaches to 127.0.0.1:<port>, refuses unauthenticated
  (None) and unsupported (VeNCrypt) servers, and refuses ARD with the
  supported alternative until the macOS milestone
- host-guidance: per-OS enablement text so no path dead-ends
- doctor + status report host desktop availability and auth type only

worker.desktop.observe/launch stay as delegating aliases with identical
behavior. Also drops the now-unused WorkerDesktopTunnels type export.

Live-verified against macOS Screen Sharing: probe reads RFB 003.889,
returns security types [30,33,36,35], classifies ard-account.

* test(gateway): probe RFB handshakes through the socket boundary

The probe's banner and security-offer parsers were exported solely so
unit tests could call them, which the dead-export gate rejects and which
tests internals rather than behavior. Keep them module-local and drive
the probe through a scripted loopback server instead.

The boundary tests also cover what pure-function vectors could not:
handshakes split across packets, legacy RFB 3.3 single-word security,
server-rejected handshakes, early hangups, and connect timeouts.

* feat(ui): let the Desktop panel view this machine, not just cloud workers

The Desktop panel was gated on a cloud-worker session placement, so an
operator running OpenClaw locally had no way to see the machine hosting
their main session even with a VNC server running on it.

Availability now follows the advertised desktop.observe method plus
operator.admin instead of session placement, and the picker lists every
environment whose summary reports a desktop, with the gateway row shown
as "This machine". Sources are passed to the generic desktop.observe /
desktop.launch RPCs; the app launcher stays worker-only. When a host
attach needs a password the gateway did not supply, the panel prompts and
keeps the value in memory for that connection only.

Adds the hostDesktop Labs toggle for desktop.host.enabled.

* fix(scripts): keep the env-var ratchet usable in shallow checkouts

The env-var budget check resolved its base ref, then hard-failed when
`git merge-base` found no shared ancestor. Shallow clones and grafted
agent checkouts resolve origin/main but truncate the history behind it,
so an advisory growth ratchet took down the whole check:changed gate
with "Could not resolve env-var count merge base for: origin/main".

Only the growth comparison needs a baseline, and the script already has
a no-baseline path. Treat git's exit 1 with empty output (no shared
ancestor) as that case and say so on stderr; a genuine failure still
exits 128 and still throws, and the absolute count-vs-budget check runs
either way.

* test(ui): measure the inline-code chip against its line box

The inline-code spacing test compared the chip's height to a prose text
rect, so it silently measured the monospace font's default line spacing.
That is ~17px on macOS and several px shorter on Linux, so the assertion
passed on CI and failed locally at 4.5 against a 3.75 bound -- after the
bound had already been widened once to chase browser font metrics.

Compare the chip to the paragraph's CSS line box instead, which is what
"the chip must not disrupt the line" actually means and is platform
independent. The horizontal gap stays as-is: it is em-derived padding
plus border, and it is the assertion that catches detached punctuation.

Verified both directions on macOS: the file is fully green, and
restoring the pre-fix 0.15em/0.35em padding still fails the gap
assertion at 5.41.

* feat(gateway): view macOS Screen Sharing from the Desktop panel

Modern macOS only offers ARD account authentication for Screen Sharing,
so the host desktop source refused every Mac. The Gateway now performs
the ARD handshake itself against the loopback server and hands the
browser a plain RFB 003.008 no-auth handshake, so the operator's macOS
account password authenticates the desktop without ever reaching the
browser, the observe result, a URL, or a log.

- rfb-preauth: ARD (type 30) Diffie-Hellman with MD5-derived AES-128-ECB
  credentials, and VncAuth (type 2) bit-reversed DES, both under a single
  10s negotiation deadline; Apple's RFB 003.889 maps to 3.8
- observe-bridge: runs pre-auth before splicing and starts the view-only
  filter at clientInit, since the browser handshake is consumed here;
  worker tokens keep the original version start phase
- host-source: attaches ARD, requiring per-observation credentials that
  live only in the one-shot observer token and are dropped after use
- doctor: offers an explicitly confirmed sudo launchctl repair when
  Screen Sharing is off, and prints the System Settings path otherwise

Live-verified against this Mac's Screen Sharing: the DH exchange and
credential framing are accepted and the server returns SecurityResult.
The VncAuth DES vector is confirmed against OpenSSL independently.
2026-08-12 06:58:30 -07:00
Peter Steinberger cc99d99f24 fix(installer): resolve relative CLI install paths (#122626) 2026-08-12 06:32:15 -07:00
Peter Steinberger 1e5e0d786c test(doctor): isolate Claude CLI health checks (#122627)
Amp-Thread-ID: https://ampcode.com/threads/T-019fee8d-665d-707b-a380-23f2a6a1ce03

Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 06:27:03 -07:00
Peter Steinberger 2cb9a75648 improve(gateway): compose live session stress probes (#122519)
* test(gateway): compose live session stress probes

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* fix(ai): resume after Responses compaction checkpoints

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* test(gateway): compose multi-session subagent probes

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* fix(test): invalidate inlined schema transforms

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

* test(ai): cover empty compaction owners

Amp-Thread-ID: https://ampcode.com/threads/T-019feaaa-c7ed-769e-9f29-a3612bec72e7

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 06:22:08 -07:00
Vincent Koc 9b90e104c5 fix(tts): preserve hidden-only tagged fallback text (#122608)
Punchcard-Session: golden-brook-lantern-zw
2026-08-12 21:18:15 +08:00
Peter Steinberger ade3456dd4 feat: add one-paste node onboarding (#122499)
* feat(pairing): add short join onboarding

* fix(gateway): isolate device join routing tests
2026-08-12 06:17:39 -07:00
Paul Frederiksen fb9a62e995 fix(heartbeat): suppress silent exec acknowledgements (#73785)
Punchcard-Session: golden-meadow-orchard-ng
2026-08-12 20:57:39 +08:00
Peter Steinberger bdc595d1bd fix(gateway): refresh health after account removal (#122620) 2026-08-12 05:56:01 -07:00
Vincent Koc beb576c2ad test(slack): restore tool result reaction state (#122592) 2026-08-12 20:54:06 +08:00
Peter Steinberger 67dd56c51e test(cron): focus direct delivery coverage (#122621)
Amp-Thread-ID: https://ampcode.com/threads/T-019fee8d-665d-707b-a380-23f2a6a1ce03

Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 05:43:18 -07:00
Vincent Koc c702bf2796 fix(ci): repair Slack enterprise fixture routing (#122589) 2026-08-12 20:32:41 +08:00
Peter Steinberger 209b3ade0f test(browser): model DNS lookup overloads (#122614) 2026-08-12 05:23:43 -07:00
Peter Steinberger 40cb6f0e3b feat(ui): keep Where picker destinations live (#122531)
* feat(gateway): enrich environment summaries

* chore(sdk): refresh plugin API surface

surface drift approved: additive EnvironmentSummary enrichment (runners plan rev 2, milestone 4)

* feat(ui): keep where picker destinations live

* docs: link picker liveness milestone PR

* fix(ui): deduplicate picker locale keys

* test(ui): update picker section expectations

* fix(ssrf): narrow lookup resolver contract

* fix(gateway): publish authoritative environment facts
2026-08-12 05:11:46 -07:00
Vincent Koc fc14a5a587 fix(sessions): reject missing explicit session targets (#122564)
* fix(sessions): reject missing explicit session targets

Punchcard-Session: brisk-willow-summit-k0

* fix(sessions): scope strict resolution to send and history

Punchcard-Session: brisk-willow-summit-k0
2026-08-12 20:11:27 +08:00
Peter Steinberger c97f3207a0 fix(outbound): report broadcast delivery truth (#122605)
Derive broadcast success from structured send outcomes instead of treating every returned send as delivered.
2026-08-12 05:09:32 -07:00
Peter Steinberger 5209d6cb05 test(gateway): keep session search tests focused (#122603)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 05:08:21 -07:00
Ziyang Guo 220b2dcec7 fix(skills): reconcile manually created proposal targets (#118676)
* fix(skills): reconcile manually created proposal targets (#90388)

* fix(skills): preserve stale apply lifecycle errors

* fix(skills): stale existing create targets

* fix(skills): dispatch reconciliation hooks outside target lease

* test(skills): prove manual target reconciliation

* fix(skills): serialize proposal reconciliation with collection writes

* fix(skills): surface proposal reconciliation failures

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-12 20:06:56 +08:00
Peter Steinberger 79ac476b0f fix(test): type CDP DNS lookup mocks (#122607)
Amp-Thread-ID: https://ampcode.com/threads/T-019ff3db-c467-70ad-8ed3-81f2ba94b0c0

Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 04:45:15 -07:00
Vincent Koc 3e6aec1d55 fix(state): avoid startup ownership snapshots (#122518) 2026-08-12 19:07:15 +08:00
Vincent Koc ce56c40dab fix(test): wait for gateway hook model activity (#122584) 2026-08-12 19:02:21 +08:00
James Tatum 5235269b3c fix(agents): heartbeats lose all conversation context on claude-cli chat↔heartbeat transitions (#121509)
* fix(agents): resolve session-stable reply mode for direct resolver turns

Heartbeat wakes and other direct getReplyFromConfig callers bypass
dispatch, so no session-stable delivery mode reached their CLI binding
facts and prepare computed no messageToolPolicyHash, while dispatched
chat turns hashed the stable mode. resolveCliSessionReuse treats that
one-sided hash as a policy change, hard-invalidating the binding on
every chat<->heartbeat transition and leaving heartbeats to run in
fresh CLI sessions with no conversation history (historyPrompt=none).

Extract the synthetic-turn stable-mode resolution that
prepareAgentCommandExecution already used into
resolveSessionStableReplyMode, and apply it in prepareReplyRunContext
whenever a synthetic turn arrives without dispatch's injected mode, so
every turn kind on a session derives the same binding facts and hash.

Fixes #121485

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(agents): derive synthetic binding facts from the dispatch policy owner

Consolidate the synthetic-turn stable-mode resolution onto dispatch's own
policy pieces instead of a simplified parallel resolver:

- resolveVisibleRepliesPolicy is extracted from dispatch prepare-context
  (configured visible-replies guard + harness default chain) and shared, so
  the fallback and dispatch cannot drift on harness defaults, live-vs-entry
  chat facts, or ExplicitDeliverRoute.
- The stable fact now applies dispatch's messageToolAvailable downgrade via
  the canonical tool-policy resolvers: tool-only delivery with a policy-denied
  message tool records automatic, matching dispatch.
- Synthetic turns no longer fall back to their effective turn mode: a
  response-tool heartbeat's message_tool_only is per-turn enforcement, not
  session policy, and previously bypassed the stable fallback entirely.

Regression coverage: response-tool heartbeat facts match dispatched turns,
and a message-tool-denied config downgrades the synthetic stable fact.

Refs #121485

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(agents): keep the session-stable reply mode sender-independent

Dispatch's stable-mode downgrade used the turn's sender-aware message-tool
availability, so a sender-scoped message denial hashed the stable policy as
automatic on chat turns while sender-less synthetic turns hashed tool-only —
the same binding reset loop on another axis.

resolveStableMessageToolAvailability becomes the one sender-independent
owner: dispatch passes it as sessionStableMessageToolAvailable for the
stable-mode resolution only (effective per-turn enforcement keeps the
sender-aware verdict), and synthetic binding facts already consume it.
Computed only when the visible-replies candidate is message_tool.

Refs #121485

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(agents): derive stable reply facts from session surfaces, not wake plumbing

Third-pass review fixes on the #121485 consolidation:

- Strip system-event wake providers ("heartbeat", "cron-event") from the
  stable context and resolve origin-less entries as internal, so synthetic
  facts take the same internal-channel branch dispatch's live webchat turns
  do instead of falling through to harness defaults.
- Fall back to persisted session facts (delivery channel/origin, groupId,
  groupChannel/subject, accountId) for the sender-independent availability
  stack, so bare-ctx callers like command prepare resolve the same
  group/account-scoped policies as dispatched turns; dispatch now passes its
  session entry too.
- Collapse the redundant second mode resolution into the availability
  downgrade, surface dispatch's injected stable mode separately from
  resolvePromptSourceReplyMode so the synthetic slot has one owner, and
  reuse resolveTurnModelOverride instead of an inline copy.
- Refresh docs/.generated/plugin-sdk-api-baseline.jsonl: closure hashes only
  (17 exports, zero declaration changes, verified) — plugin-sdk reply/meeting
  entrypoints transitively bundle the reply pipeline this branch refactors.

Regression: origin-less entry heartbeat resolves internal-automatic facts.

Refs #121485

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: adapt to main module moves and split API baseline

Mechanical rebase refresh onto d3696f8d76: subagent-capabilities moved to
src/agents/subagents/spawn/, and the plugin-sdk API baseline is now
per-entrypoint content hashes (#122082) — regenerated for the reply-pipeline
closure this branch touches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-12 16:25:38 +05:30
Peter Steinberger 6780d87e4f test(gateway): skip reconnect wall-clock waits (#122588)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 03:49:04 -07:00
Peter Steinberger ee535c5e1d fix(doctor): report legacy cache scan failures (#122585)
* fix(doctor): report usage cache scan failures

Treat only missing legacy cache paths as absent and surface permission or I/O failures without partial cleanup.

* fix(doctor): preserve cache scan error causes
2026-08-12 03:48:17 -07:00
Pavan Kumar Gondhi 92f5f07da1 fix(browser): keep guarded CDP sockets on validated endpoints [AI] (#114506)
* fix(browser): keep guarded CDP sockets on validated endpoints

* fix(browser): avoid retrying rate-limited CDP discovery

* fix(browser): close Chrome MCP CDP policy gaps

* test(browser): match Chrome MCP policy error

* test(browser): satisfy transport type and lint checks

* fix(browser): narrow guarded CDP transport changes

* fix(browser): separate upload filesystem locality

* fix(browser): keep strict remote CDP hosts untrusted
2026-08-12 16:16:12 +05:30
Peter Steinberger 786c646d88 improve(ci): rebalance compact Node shards from hosted medians (#122547)
* ci: refresh compact Node shard timings

Amp-Thread-ID: https://ampcode.com/threads/T-019ff3db-c467-70ad-8ed3-81f2ba94b0c0

* docs(ci): clarify compact planner counts

Amp-Thread-ID: https://ampcode.com/threads/T-019ff3db-c467-70ad-8ed3-81f2ba94b0c0

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 03:41:34 -07:00
Peter Steinberger fea6d96378 fix(qa): artifact write failure preserves previous files (#122580)
* fix(qa): publish suite artifacts atomically

* test(qa): consolidate artifact durability coverage
2026-08-12 03:29:34 -07:00
Josh Avant 562391b9af feat(audit): explain denied operator approvals (#119815)
* Audit: add durable decision receipts

* Audit: route generic decision facts through writer

* Audit: satisfy strict decision count typing

* Test: align decision writer type coverage

* Refactor: isolate decision receipt projection

* Fix: preserve ambiguous approval correlation

* Fix decision coverage across pages

* Fix approval coverage across corrupt pages

* Fix decision summaries across retention and paging

* Remove superseded decision fact count path

* Keep session-derived approval links conservative

* Test decision paging at owner boundary

* Audit: bind approval receipts to exact execution

* Test: keep decision receipt coverage focused

* docs(agents): preserve decision receipt ownership

* Docs: refresh Plugin SDK split baselines

* Docs: require opt-in for future decision facts

* Fix: bound decision receipt inspection
2026-08-12 05:23:29 -05:00
clawSean 654fc632cd docs(backup): describe manual restore flow (#86971)
* docs(backup): describe manual restore flow

* docs(backup): make restore copy-back fail closed

* docs(backup): make inspect-and-stage block fail closed

Add set -euo pipefail to the first restore staging snippet so a failed
openclaw backup verify stops before mktemp/tar extraction, matching the
fail-closed copy-back block. Addresses ClawSweeper P1 on docs/cli/backup.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(backup): reconcile restore guidance with exclusions

Punchcard-Session: brisk-harbor-harbor-6w

* docs(backup): centralize archive restore guidance

Punchcard-Session: calm-cedar-workshop-by

---------

Co-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-12 18:09:26 +08:00
Peter Steinberger fa4a197177 perf: accelerate sqlite reliability proof (#122576)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 03:07:19 -07:00
Vincent Koc fb788e7a3e refactor(diagnostics-otel): unify event attribute projection (#122559) 2026-08-12 18:06:08 +08:00
Vincent Koc 9324843d42 fix(release): trust frozen beta Telegram candidates (#122575) 2026-08-12 18:03:15 +08:00
SunnyShu 6fa383695f fix(gateway): preserve inbound media references in chat history (#122031)
* fix(gateway): retain managed inbound media reference in chat history
* fix(gateway): simplify inbound media projection (#122031) (thanks @SunnyShu0925)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
2026-08-12 15:31:39 +05:30
Vincent Koc 2c26f13606 fix(qa): accept staged compaction summaries (#122528) 2026-08-12 17:52:14 +08:00
Pavan Kumar Gondhi 5eb18c1387 fix(ios): keep authenticated Control UI pages bound to the trusted Gateway [AI] (#119906)
* fix(ios): enforce gateway TLS pins in control pages

* test(ios): run control UI trust regressions in CI

* test(ios): avoid nested Testing macros

* fix(ios): preserve control page navigation

* fix(ios): keep authenticated control pages on origin

* fix(ios): canonicalize control page IPv6 hosts

* chore(ios): refresh native i18n inventory

* fix(ios): normalize default TLS challenge ports

* fix(apps): share gateway TLS authority matching

* test(apps): fix authority CI validation

* chore(ci): drop control UI test routing
2026-08-12 15:18:19 +05:30
Peter Steinberger cb58073a90 fix(ui): paginate all active tasks (#122565)
Preserve task-list cursors and drain every active page so supported running work remains visible and cancellable.
2026-08-12 02:46:55 -07:00
Peter Steinberger 30131a572b perf: speed changed-test import scans (#122572)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 02:30:32 -07:00
Peter Steinberger 7e42dae611 refactor(memory-core): split index manager along the inheritance chain (#122540)
* refactor(memory-core): split index manager along the inheritance chain

* fix(memory): restore the manager lazy boundary

* refactor(memory-core): delete dead manager plumbing

* chore(lint): ratchet max-lines baseline after memory manager split

* fix(memory): keep the manager out of the runtime facade

* test(memory): cover transitive manager facade imports
2026-08-12 02:28:20 -07:00
Peter Steinberger e5dd254561 fix(memory-wiki): publish lint report atomically (#122568) 2026-08-12 02:23:48 -07:00
zhifu gao 42ad83142e fix(whatsapp): label voice transcripts as untrusted (#113111)
* fix(whatsapp): label voice transcripts as untrusted

* fix(whatsapp): preserve audio provenance in group history

Frame deferred voice transcripts while retaining their structured audio facts for later model-visible replay.

Refs #87269

---------

Signed-off-by: zhifu gao <lauragpt@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: zhifu gao <lauragpt@users.noreply.github.com>
2026-08-12 17:14:55 +08:00
Peter Steinberger 5350b92dc8 fix(browser): wake extension relay through gateway (#122537)
* fix(browser): wake extension relay through gateway

* fix(browser): preserve manual extension relay pairing
2026-08-12 02:13:03 -07:00
Vincent Koc 08b7fcc05e test(cli): cover node daemon adapters (#122562)
Punchcard-Session: golden-valley-cedar-5x

Co-authored-by: xin zhuang <65798732+1052326311@users.noreply.github.com>
2026-08-12 17:09:07 +08:00
Peter Steinberger 66009308bb test: parallelize doctor process coverage (#122563)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 02:08:55 -07:00
Vincent Koc 7e2ec43e54 fix(ci): keep hosted gate verifier standalone (#122561)
Punchcard-Session: silver-valley-orchard-nq
2026-08-12 17:08:09 +08:00
Peter Steinberger d44f70eb4b feat(pairing): one-paste device pairing via oc-pair setup links (#120768)
* feat(pairing): one-paste device pairing via oc-pair setup links

Implements milestone 3 from docs/plan/runners.md.

* fix(pairing): sign bootstrap handshake, keep URL candidates, wire pairing countdown

* test(gateway): update client callsite guard

* fix(pairing): preserve setup URL context paths

* fix(ui): keep pairing help aligned with setup mode

* fix(pairing): isolate bootstrap credentials

* perf(ui): keep one-paste pairing within bundle budget

* refactor(pairing): isolate native pair URL prefix parsing

* fix(pairing): preserve candidate lifecycle state

* fix(pairing): retire shared credentials after bootstrap

* fix(pairing): apply rotated manifest through client owner

* test(pairing): prove bootstrap retirement across reconnect

* fix(pairing): preserve native gateway context paths

* fix(pairing): carry native context paths through reconnect

* fix(ios): preserve encoded gateway context path

* chore(plugin-sdk): refresh pairing API baselines
2026-08-12 02:01:33 -07:00
Josh Avant 3b01ea7905 fix(audit): show authenticated users for Gateway runs (#122484)
* fix(audit): show authenticated users for Gateway runs

* fix(audit): keep profile labels out of sessions

* test(qa): verify session label retention at storage

* fix(sessions): preserve canonical profile ownership

* test(qa): require full identity inspection proof

* docs(agents): preserve execution identity ownership boundary
2026-08-12 08:50:37 +00:00
Peter Steinberger 6d973d114f test: trim duplicate target registry coverage (#122555)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-12 01:46:38 -07:00
Peter Steinberger 92ed766673 fix(camera): publish URL downloads atomically (#122550) 2026-08-12 01:38:18 -07:00
Peter Steinberger 432ccac74b fix(channels): honor terminal reaction holds (#122544)
Serialize done and error holds before restoring initial reactions, and restore Slack error reactions through the shared lifecycle.
2026-08-12 01:36:54 -07:00
Vincent Koc 1672d78d17 refactor(plugins): share bounded run id tracking (#122362) 2026-08-12 16:23:33 +08:00