13334 Commits

Author SHA1 Message Date
Bryan Marty
e13a94df72
fix: classify tunneled loopback gateway URLs as remote when mode=remote is configured
When gateway.mode=remote is configured with a non-loopback remote.url,
a loopback gatewayUrl (ws://127.0.0.1:...) is likely an SSH port-forward
tunnel endpoint (ssh -N -L <local>:remote-host:<remote>). Previously,
resolveGatewayTarget() classified any loopback URL as 'local', causing
gateway-tool to forward live deliveryContext into remote config.apply /
config.patch / update.run writes. Because server handlers prefer
params.deliveryContext, post-restart wake messages were misrouted to the
caller's local chat context instead of the remote session.

Fix both classification sites:
1. validateGatewayUrlOverrideForAgentTools: when a loopback URL hits
   localAllowed, check isNonLoopbackRemoteUrlConfigured(cfg); if true,
   return 'remote' (tunnel) rather than 'local'.
2. resolveGatewayTarget fallback (rejected URL path): same check for
   the isLoopback branch — prefer 'remote' when mode=remote with a
   non-loopback remote.url is present.

Add isNonLoopbackRemoteUrlConfigured() helper (returns true iff
gateway.mode=remote AND gateway.remote.url is a non-loopback hostname).

Tests: add SSH tunnel cases in gateway.test.ts; update the
'OPENCLAW_GATEWAY_URL takes precedence' test which now correctly
returns 'remote' when mode=remote with non-loopback remote.url; add
a variant without remote config to cover the 'local' precedence case.
2026-03-21 04:16:07 +00:00
Bryan Marty
d629945255
fix: classify env gateway URL overrides with callGateway semantics in resolveGatewayTarget
When OPENCLAW_GATEWAY_URL/CLAWDBOT_GATEWAY_URL is set to a valid remote URL
that doesn't match gateway.remote.url (or has a non-root path like /ws),
validateGatewayUrlOverrideForAgentTools throws and the old code silently fell
through to config-based resolution, returning undefined (local). But
callGateway/buildGatewayConnectionDetails still uses the env URL verbatim, so
the actual call goes remote while resolveGatewayTarget returned local — causing
gateway-tool to forward live deliveryContext into remote config.apply /
config.patch / update.run writes, which can misroute or leak post-restart wake
messages across hosts.

Fix: when validateGatewayUrlOverrideForAgentTools throws for an env URL
override, fall back to hostname-based loopback detection instead of silently
treating the target as local. Only truly malformed URLs (that new URL() cannot
parse) fall through to config-based resolution.

Adds tests for:
- env-only remote URL not matching gateway.remote.url → 'remote'
- env URL with no configured remote URL → 'remote'
- env URL with /ws path → 'remote'
- loopback env URL with /ws path → 'local'
2026-03-21 04:16:07 +00:00
Bryan Marty
3c914b8f38
fix: enqueue fallback event on delivery throw and align resolveGatewayTarget with callGateway URL resolution
Two regressions addressed (PR #34580 CR review):

1. server-restart-sentinel.ts – deliverOutboundPayloads catch block was
   silently swallowing errors and proceeding to agentCommand without any
   fallback. When delivery throws before bestEffort handling (e.g. channel
   plugin error), the user would receive neither the deterministic notice
   nor a system event if the resumed run emits no payloads. Fix: enqueue a
   system event in the catch block, mirroring prior behaviour.

2. gateway.ts resolveGatewayTarget – two mismatches with callGateway's
   actual URL resolution path:
   a. gateway.mode=remote + missing gateway.remote.url: callGateway falls
      back to local loopback, but resolveGatewayTarget returned 'remote',
      suppressing deliveryContext for what is actually a local call.
   b. Env URL overrides (OPENCLAW_GATEWAY_URL / CLAWDBOT_GATEWAY_URL) are
      picked up by callGateway but were ignored here, causing incorrect
      local/remote classification. Fix: check env overrides first, then
      require both mode=remote AND remote.url present for 'remote'.

Tests: add regression coverage for both fixes.
2026-03-21 04:16:07 +00:00
Bryan Marty
f7132aeb79
fix(tests): correct mock types to satisfy tsgo strict checking
Vitest infers mock return types from the initial factory function, causing
tsgo to reject mockReturnValueOnce/mockResolvedValueOnce calls that pass
types incompatible with the inferred return. Fix by:

- Widening resolveGatewayTarget mock to () => 'local' | 'remote' | undefined
- Widening extractDeliveryInfo mock threadId/accountId to string | undefined
- Using 'as never' on mockReturnValueOnce/mockResolvedValueOnce overrides
  that pass edge-case values (null sentinel, undefined merge results,
  partial payload objects) that intentionally don't match the strict type

All 71 tests still pass.
2026-03-21 04:16:02 +00:00
Bryan Marty
874b906b3d
fix: merge accountId fallback from extractDeliveryInfo in update.run handler
When a caller forwards live channel/to via deliveryContext but omits
accountId (e.g. /tools/invoke without x-openclaw-account-id), the
update.run handler was using paramsDeliveryContext as-is, dropping any
account binding that existed in the session store. The restart sentinel
would then be written without accountId, causing scheduleRestartSentinelWake
to deliver using the channel default account — misrouting in multi-account
setups.

Apply the same accountId fallback pattern that config.ts already uses:
when paramsDeliveryContext is present but its accountId is undefined,
merge in extractedDeliveryContext.accountId as fallback. See #18612.
2026-03-21 04:16:02 +00:00
Bryan Marty
93f4a3a7f7
test: expand regression coverage for restart sentinel and delivery context
Grows test count from 21 → 71 across three test files. Each suite now
covers the full expected-behavior matrix to catch regressions.

gateway-tool.test.ts (10 → 29 tests)
- RPC delivery context suite: happy-path full context forwarding,
  agentAccountId/agentThreadId included, all three write actions
  (config.apply, config.patch, update.run), partial context suppression
  (missing channel or to), empty-string guards, stale heartbeat override,
  same-session aliases ('main' canonicalization), cross-session / cross-agent
  suppression, remote gateway suppression (explicit URL + gateway.mode=remote),
  local loopback forwarding, undefined (default local) forwarding
- Restart sentinel suite: live context used/suppressed, heartbeat override,
  threadId included / excluded on cross-session, cross-agent 'main' alias,
  kind/status/sessionKey fields on the payload

server-restart-sentinel.test.ts (4 → 16 tests)
- Two-step delivery+resume: ordering assertion, senderIsOwner=false guard,
  no-op when no sentinel file
- Fallback suite: no sessionKey, unresolvable target, missing channel/to,
  agentCommand throws (notice already delivered), deliverOutboundPayloads
  throws (resume still runs)
- Thread routing: Slack replyToId mapping, non-Slack threadId passthrough,
  agentCommand receives threadId, sentinel threadId beats session-derived
- Context priority: sentinel beats stale heartbeat store, session-store
  fallback when sentinel has no deliveryContext

restart-request.test.ts (7 → 26 tests)
- Reject absent/null/non-object deliveryContext
- Reject partial contexts (channel-only, to-only, empty strings, whitespace)
- Reject non-string field types (number, boolean)
- Accept full contexts with all combinations of optional fields
- Whitespace trimming for all four fields
- undefined returned for empty-after-trim optional fields
- Extra/unknown fields are ignored
2026-03-21 04:16:02 +00:00
Bryan Marty
fd1dd6fa80
fix: merge accountId when preferring live delivery context for restart sentinel
When liveContext (gateway-tool.ts) or paramsDeliveryContext (config.ts) is
present but lacks an accountId, fall back to the accountId from the extracted
session store rather than dropping it entirely. This prevents restart follow-up
notices from being misrouted on multi-account channels when callers supply
channel/to without an explicit accountId.

Addresses CR comments on PR #34580.
2026-03-21 04:16:02 +00:00
Bryan Marty
645def7535
fix: treat config-based remote gateway (gateway.mode=remote) as remote target
resolveGatewayTarget() previously returned undefined when no gatewayUrl
override was provided, even when gateway.mode=remote routes the call to
gateway.remote.url. This caused isRemoteGateway to be false in that path,
so deliveryContext was forwarded to the remote host and could stamp the
restart sentinel with the local chat route, misdelivering post-restart
wake messages.

Fix: check gateway.mode=remote in the no-override branch and return
'remote' so deliveryContext is suppressed for config-based remote targets
the same way it is for explicit gatewayUrl overrides.

Adds a test covering the config-based remote mode case (no gatewayUrl).

Closes #34580 (P1 review comment).
2026-03-21 04:16:02 +00:00
Bryan Marty
e705d9b23d
fix: distinguish local vs remote gatewayUrl before suppressing deliveryContext
isRemoteGateway was inferred from gatewayUrl being present, but gatewayUrl
overrides are valid for loopback/local targets too (ws://127.0.0.1:<port>,
localhost, [::1]). These local-override calls should still forward
deliveryContext — treating them as remote falls back to
extractDeliveryInfo(sessionKey) and reintroduces the stale heartbeat routing
this patch was meant to fix.

Fix: export resolveGatewayTarget() from gateway.ts (returns 'local' | 'remote'
| undefined) and use it instead of Boolean(gatewayUrl?.trim()). Only
gatewayUrl values that classify as 'remote' now suppress deliveryContext.

Adds test coverage for the local loopback case.
2026-03-21 04:16:02 +00:00
Bryan Marty
33c24858ff
fix: omit live deliveryContext when targeting a remote gateway
resolveGatewayWriteMeta() was forwarding the local agent run's
deliveryContext to config.apply/config.patch/update.run even when
gatewayUrl pointed to a remote gateway. Server handlers now prefer
params.deliveryContext over extractDeliveryInfo(sessionKey), so a
remote restart sentinel would be written with the local chat's channel/
to, causing post-restart wake messages to be delivered to the caller's
chat instead of the session that lives on the remote gateway.

Fix: gate deliveryContext forwarding on isRemoteGateway (truthy
gatewayOpts.gatewayUrl). When targeting a remote gateway, omit
deliveryContext so the remote server's extractDeliveryInfo(sessionKey)
remains authoritative for the routing of that session. See #18612.
2026-03-21 04:16:02 +00:00
Bryan Marty
80538c607d
fix: deliver restart notice explicitly before agent resume
Restore deliverOutboundPayloads() to send the restart summary
deterministically before calling agentCommand() for the agent resume
turn. Previously the notice was only delivered as input to the model
via agentCommand(), making it model-dependent: if the model rewrote or
omitted the content, the user would never see the restart summary/note.

The new two-step flow:
1. deliverOutboundPayloads() — guaranteed delivery of the exact restart
   notice (model-independent). Restores the Slack replyToId mapping
   from main that ensures threaded replies land in the right thread.
2. agentCommand() — agent resume turn so the agent can continue
   autonomously and optionally provide additional context.

Update test to assert deliverOutboundPayloads fires before agentCommand
and verify the two-step ordering is preserved.
2026-03-21 04:16:02 +00:00
Bryan Marty
045bf781a4
fix: derive canonicalize agentId from target key, not current session
When a non-default agent (e.g. agent:shopping-claw:main) calls restart or
config/update with sessionKey="main", the gateway treats "main" as
resolveMainSessionKey(cfg) = the default agent's session. Previously,
isTargetingOtherSession canonicalized the target key using the CURRENT
session's agentId, so "main" mapped to the current agent's main session
rather than the default agent's — falsely treating a cross-agent request
as same-session and forwarding the wrong chat's deliveryContext.

Fix: canonicalize each key using its own agentId (resolveAgentIdFromSessionKey
on the key itself). For bare "main", this returns DEFAULT_AGENT_ID so
"main" → "agent:main:main" regardless of which agent is calling. Applied
to both the restart path and the RPC path (resolveGatewayWriteMeta).

Add two regression tests covering the cross-agent alias scenario.
2026-03-21 04:16:02 +00:00
Bryan Marty
3849101443
fix(gateway-tool): require both channel and to before forwarding live delivery context
Forwarding liveDeliveryContextForRpc (or liveContext for restart) when
only agentChannel is set but agentTo is missing causes the server to
prefer an incomplete deliveryContext over extractDeliveryInfo(). The
sentinel is then written without `to`, and scheduleRestartSentinelWake
bails on `if (!channel || !to)`, silently degrading to a system event
with no delivery or agent resume.

Fix: guard both liveContext (restart path) and liveDeliveryContextForRpc
(config.apply/config.patch/update.run) to require both channel and to
before forwarding.

Add gateway-tool.test.ts covering the partial-context guard for both
the restart and RPC code paths.

Fixes: chatgpt-codex-connector P2 review on #34580
2026-03-21 04:14:45 +00:00
Bryan Marty
331f09b82d
fix: guard threadId with same session check as deliveryContext in restart
opts.agentThreadId belongs to the current agent's thread. When the
restart action targets a different sessionKey, forwarding it into the
sentinel would cause scheduleRestartSentinelWake to deliver the
post-restart reply to the wrong thread.

Apply the same isTargetingOtherSession guard used for deliveryContext:
only take opts.agentThreadId when the restart targets the current
session; otherwise use extracted.threadId from extractDeliveryInfo,
which correctly derives threadId from the target session key.
2026-03-21 04:14:45 +00:00
Bryan Marty
292546cb09
fix: only forward live delivery context when targeting own session
When a gateway tool call (restart, config.apply, config.patch, update.run)
specifies an explicit sessionKey that differs from the current agent's
session, the live delivery context (agentChannel/agentTo/agentAccountId)
belongs to the wrong session and would misroute post-restart replies.

Only set deliveryContext in the sentinel/RPC params when:
- No explicit sessionKey is provided (falls back to own session), or
- The explicit sessionKey matches the current agent's session key

Otherwise omit deliveryContext so the server falls back to
extractDeliveryInfo(sessionKey), which correctly resolves routing for
the target session.
2026-03-21 04:14:45 +00:00
Bryan Marty
db21905291
refactor: address code review feedback on restart sentinel fix
- Extract parseDeliveryContextFromParams() into restart-request.ts and
  import it in both config.ts and update.ts, eliminating the duplicated
  inline IIFE parsing in update.ts

- Add comment in gateway-tool.ts explaining why agentThreadId is
  intentionally excluded from liveDeliveryContextForRpc: threadId is
  reliably derived server-side from the session key via
  parseSessionThreadInfo() and is not subject to heartbeat contamination

- Add beforeEach(vi.clearAllMocks) to server-restart-sentinel.test.ts
  and remove ad-hoc mockClear() calls from individual tests to prevent
  mock state from leaking between test cases
2026-03-21 04:14:45 +00:00
Bryan Marty
ade14241ba
fix: restore agent resume after self-triggered gateway restart (#12768, #18612)
Fixes two related issues:
- #12768: Gateway restart notification
- #18612: Agent does not resume after self-triggered gateway restart

## Root cause

In ab4a08a82 ('fix: defer gateway restart until all replies are sent'),
agentCommand() was replaced with deliverOutboundPayloads() in
scheduleRestartSentinelWake(). This fixed a pre-restart race condition
(correct) but accidentally made delivery one-way: the user is notified
but the agent never sees the restart message and does not resume.

A compounding bug meant the sentinel was also being written with stale
routing data. extractDeliveryInfo() reads the persisted session store,
which heartbeat runs frequently overwrite to { channel: 'webchat',
to: 'heartbeat' } — an internal sink. So even restoring agentCommand()
alone would fail: the sentinel's deliveryContext was pointing nowhere.

## Fix (four parts)

**Part 1 — src/agents/openclaw-tools.ts**
Forward the live delivery fields (agentChannel, agentTo, agentThreadId,
agentAccountId) from createOpenClawTools() into createGatewayTool().
These values are captured from the current inbound message context and
are accurate; they were available at the callsite but not being passed.

**Part 2 — src/agents/tools/gateway-tool.ts**
Prefer liveDeliveryContext (built from opts.agentChannel / agentTo /
agentAccountId) over extractDeliveryInfo() when writing the sentinel.
Pass deliveryContext in config.apply, config.patch, and update.run RPC
calls so the server-side handlers receive it.

**Part 3 — src/gateway/server-restart-sentinel.ts**
Restore agentCommand() in place of deliverOutboundPayloads(). The
function runs in the new process post-restart, where there are zero
in-flight replies, so the pre-restart race condition does not apply.
agentCommand() creates a full agent turn: the restart message is
delivered to the user AND the agent sees it in its conversation history,
allowing it to resume without waiting for the user to send a new message.

**Part 4 — src/gateway/protocol/schema/config.ts**
Add deliveryContext as an optional field to ConfigApplyLikeParamsSchema
(shared by config.apply and config.patch) and UpdateRunParamsSchema.
The additionalProperties: false constraint was silently dropping the
field before it reached the server-side handlers. Also updated
resolveConfigRestartRequest() in config.ts and the update.run handler
in update.ts to prefer params.deliveryContext over extractDeliveryInfo().

## Why the heartbeat approach fails

An alternative approach (requestHeartbeatNow + enqueueSystemEvent) was
tested and rejected: the heartbeat does fire, but its delivery target
comes from the session store (lastChannel/lastTo), which reads
'webchat/heartbeat' due to heartbeat contamination. Responses route to
an internal sink and are silently dropped. agentCommand() is the correct
tool because it creates a turn with explicit delivery context attached.
2026-03-21 04:14:44 +00:00
wesley
598f1826d8
fix(subagent): include partial progress when subagent times out (#40700)
* fix(subagent): preserve timeout partial progress reporting

* refactor: unify subagent output selection

* test: cover distilled subagent timeout output

* fix: remove timeout-only subagent path

---------

Co-authored-by: Wesley <imwyvern@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-03-21 08:44:38 +05:30
Tyler Yust
5e417b44e1 Outbound: skip broadcast channel scan when channel is explicit 2026-03-20 18:21:01 -07:00
Tyler Yust
b71686ab44 Enhance web search provider config validation and compatibility handling
- Added a test to ensure no warnings for legacy Brave config when bundled web search allowlist compatibility is applied.
- Updated validation logic to incorporate compatibility configuration for bundled web search plugins.
- Refactored the ensureRegistry function to utilize the new compatibility handling.
2026-03-20 18:20:50 -07:00
Danh Doan
e78129a4d9
feat(context-engine): pass incoming prompt to assemble (#50848)
Merged via squash.

Prepared head SHA: 282dc9264d4157c78959c626bbe6f33ea364def5
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-20 17:03:21 -07:00
Josh Lehman
751d5b7849
feat: add context engine transcript maintenance (#51191)
Merged via squash.

Prepared head SHA: b42a3c28b4395bd8a253c7728080f09100d02f42
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-20 16:28:27 -07:00
Peter Steinberger
6526074c85 test: trim singleton cold-start reloads 2026-03-20 23:14:28 +00:00
Josh Lehman
2364e45fe4
test: align extension runtime mocks with plugin-sdk (#51289)
* test: align extension runtime mocks with plugin-sdk

Update stale extension tests to mock the plugin-sdk runtime barrels that production code now imports, and harden the Signal tool-result harness around system-event assertions so the channels lane matches current extension boundaries.

Regeneration-Prompt: |
  Verify the failing channels-lane tests against current origin/main in an isolated worktree before changing anything. If the failures reproduce on main, keep the fix test-only unless production behavior is clearly wrong. Recent extension refactors moved Telegram, WhatsApp, and Signal code onto plugin-sdk runtime barrels, so update stale tests that still mock old core module paths to intercept the seams production code now uses. For Signal reaction notifications, avoid brittle assertions that depend on shared queued system-event state when a direct harness spy on enqueue behavior is sufficient. Preserve scope: only touch the failing tests and their local harness, then rerun the reproduced targeted tests plus the full channels lane and repo check gate.

* test: fix extension test drift on main

* fix: lazy-load bundled web search plugin registry

* test: make matrix sweeper failure injection portable

* fix: split heavy matrix runtime-api seams

* fix: simplify bundled web search id lookup

* test: tolerate windows env key casing
2026-03-20 15:59:53 -07:00
Vincent Koc
e635cedb85 test(openai): cover bundle media surfaces 2026-03-20 15:53:12 -07:00
Sally O'Malley
6e20c4baa0
feat: add anthropic-vertex provider for Claude via GCP Vertex AI (#43356)
Reuse pi-ai's Anthropic client injection seam for streaming, and add
the OpenClaw-side provider discovery, auth, model catalog, and tests
needed to expose anthropic-vertex cleanly.

Signed-off-by: sallyom <somalley@redhat.com>
2026-03-20 18:48:42 -04:00
Josh Lehman
c3972982b5
fix: sanitize malformed replay tool calls (#50005)
Merged via squash.

Prepared head SHA: 64ad5563f7ae321b749d5a52bc0b477d666dc6be
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-20 15:03:30 -07:00
Peter Steinberger
994b42a5a5 test: parallelize safe audit case tables 2026-03-20 21:16:01 +00:00
Josh Avant
7abfff756d
Exec: harden host env override handling across gateway and node (#51207)
* Exec: harden host env override enforcement and fail closed

* Node host: enforce env override diagnostics before shell filtering

* Env overrides: align Windows key handling and mac node rejection
2026-03-20 15:44:15 -05:00
Josh Avant
c7134e629c
LINE: harden Express webhook parsing to verified raw body (#51202)
* LINE: enforce signed-raw webhook parsing

* LINE: narrow scope and add buffer regression

* changelog

Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>

---------

Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-03-20 15:32:55 -05:00
Vincent Koc
11d71ca352
pairing: keep setup codes bootstrap-token only (#51259) 2026-03-20 13:27:39 -07:00
Peter Steinberger
5a5e84ca1d test: drop duplicate web search helper 2026-03-20 20:25:24 +00:00
Peter Steinberger
fa71ad7c5d test: repair latest-main web search regressions 2026-03-20 20:17:11 +00:00
Josh Lehman
23fef04c4e
test: fix setup finalize web search mocks (#51253) 2026-03-20 13:07:22 -07:00
Teddy Tennant
a20ba74978
test: add SSRF guard coverage for URL credential bypass vectors (#50523)
* security: add SSRF guard tests for URL credential bypass vectors

* test(security): strengthen SSRF redirect guard coverage

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-03-20 12:45:06 -07:00
Gustavo Madeira Santana
3da66718f4
Web: derive search provider metadata from plugin contracts (#50935)
Merged via squash.

Prepared head SHA: e1c7d72833afff6ef33e8d32cdd395190742dc08
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-20 12:41:04 -07:00
Peter Steinberger
acf32287b4 test: trim more extension startup from unit tests 2026-03-20 19:28:32 +00:00
Jaaneek
916f496b51
Add Grok 4.20 reasoning and non-reasoning to xAI model catalog (#50772)
Merged via squash.

Prepared head SHA: 095e645ea58b2259b25c923aeaf11bbcb2990c8f
Co-authored-by: Jaaneek <25470423+Jaaneek@users.noreply.github.com>
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Reviewed-by: @huntharo
2026-03-20 15:28:30 -04:00
Peter Steinberger
f6b3245a7b fix: pass full sdk gate 2026-03-20 19:24:10 +00:00
Peter Steinberger
62ddc9d9e0 refactor: consolidate plugin sdk surface 2026-03-20 19:24:10 +00:00
Vincent Koc
46854a84a4 test(plugin-sdk): cover legacy root diagnostic listeners 2026-03-20 12:23:02 -07:00
Peter Steinberger
7b00a0620a test: stabilize gateway alias coverage 2026-03-20 19:17:44 +00:00
Peter Steinberger
39053bddd7 test: decouple zalo outbound payload contract from channel runtime 2026-03-20 19:02:07 +00:00
Peter Steinberger
a7401366ef test: trim more channel-heavy startup in unit tests 2026-03-20 18:50:52 +00:00
Peter Steinberger
b26edfe1ff test: trim plugin-heavy unit test imports 2026-03-20 18:35:39 +00:00
Tak Hoffman
16e055c083
restore extension-api backward compatibility with migration warning 2026-03-20 13:27:30 -05:00
Vincent Koc
c64893a9c2
fix(config): use static channel metadata in docs baseline (#51161) 2026-03-20 10:52:40 -07:00
Vincent Koc
a2e1991ed3 refactor(plugin-sdk): route bundled runtime barrels through public subpaths 2026-03-20 10:38:55 -07:00
Vincent Koc
fb3550ef5e test(sessions): stabilize pruning integration setup 2026-03-20 10:38:55 -07:00
Vincent Koc
a39c440d39 fix(config): share json compatibility parsing 2026-03-20 10:17:53 -07:00