Commit Graph

30497 Commits

Author SHA1 Message Date
Gio Della-Libera
c85feace54 Policy: add secret and auth conformance checks (#81974)
* feat(policy): add secrets auth conformance

* fix(policy): include sandbox ssh secret data

* fix(policy): complete secret input provenance

* fix(policy): cover media request secrets

* fix(policy): satisfy policy lint

* fix(policy): narrow secret conformance evidence

* fix(policy): cover request bearer token secrets
2026-05-22 12:48:14 -07:00
Sebastien Tardif
f75789f803 fix(delivery): log failDelivery errors instead of silently swallowing (#84449)
Replace empty .catch(() => {}) on two failDelivery calls with
log.warn() so delivery queue mark-failed errors leave a diagnostic
trail instead of being silently discarded.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-05-22 20:45:26 +01:00
Jayesh Betala
5c866a17d7 fix(cli): validate debug proxy numeric options (#84260) 2026-05-22 20:45:17 +01:00
Andy Tien
501e74ddf3 fix(daemon): use exit code instead of localized text for schtasks fallback (#85347)
* fix(daemon): use exit code instead of localized text for schtasks fallback

Problem:
- shouldFallbackToStartupEntry() only matched English/Spanish error messages
  ("access is denied" / "acceso denegado"), causing silent fallback failure
  on non-English Windows systems (Chinese, Japanese, French, German, etc.)

Fix:
- Replace regex matching with exit code check (params.code === 1)
- schtasks returns exit code 1 for access denied / generic failure
  regardless of system locale

Fixes: #85255

* test(daemon): cover localized schtasks fallback

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-22 20:43:40 +01:00
infracore
5c614de29a fix(auto-reply): enforce word boundary in slash command prefix match (#84634)
`parseSlashCommandActionArgs` used a naive `startsWith` against the
configured slash prefix. When a skill name shares a prefix with a
built-in command (e.g. a skill named `config-check` vs the built-in
`/config`), the longer name was captured by the shorter built-in
handler and surfaced as an invalid action:

  ⚠️  /config is disabled. Set commands.config=true to enable.

Any skill whose name starts with a built-in command prefix
(`config-*`, `debug-*`, `models-*`, etc.) was unreachable via slash
invocation from any channel.

Fix: after the prefix match, require that the next character is
whitespace, a colon, or end-of-string. Otherwise the prefix
collided with a longer command name and we return `no-match` so the
longer handler — or the skill router — gets a chance to claim it.

Adds a regression test file `commands-slash-parse.test.ts` covering:
- `/config-check <args>` returns null (the reported case)
- `/configfoo` (no separator) returns null
- `/modelsy` returns null for the `/models` prefix
- `/config:json` still matches (colon is a valid boundary)
- `/config show enabled` still parses cleanly (whitespace boundary)
- empty body still returns the default action

Fixes #84572.

Co-authored-by: infracore <infracore@users.noreply.github.com>
2026-05-22 20:42:22 +01:00
zhang-guiping
63545693a0 fix(message-tool): normalize send body aliases (#84102) 2026-05-22 20:38:08 +01:00
Peter Steinberger
e0fda55cf7 docs: absorb maintainer docs sweep
Co-authored-by: Bob Du <i@bobdu.cc>
Co-authored-by: alitariksahin <alitariksah@gmail.com>
Co-authored-by: Jefsky <hwj3344@hotmail.com>
Co-authored-by: Musaab Hasan <m9.3b@Hotmail.com>
Co-authored-by: Intern Dev <dev@wukongai.io>
Co-authored-by: majin.nathan <majin.nathan@bytedance.com>
2026-05-22 20:29:10 +01:00
Peter Steinberger
d946a02a13 fix(gateway): coalesce provider auth rewarms
Coalesce provider auth-state rewarms after auth-profile failures and include event-loop delay in provider auth warm logs.
2026-05-22 20:28:13 +01:00
吴杨帆
88f50e8cd1 docs(config): quote bracket config paths (#83058) 2026-05-22 20:20:10 +01:00
Dallin Romney
b741ddb66f fix(tui): dismiss watchdog notice when response actually arrives (#77375)
* fix(tui): dismiss watchdog notice when response actually arrives

The streaming watchdog renders 'This response is taking longer than
expected. Send another message to continue.' after 30s without a chat
delta. If a delta or final then arrives — common for runs that are slow
but not stuck — the notice stays in the log alongside the recovered
response and contradicts what the user sees.

Track the notice by runId in the chat log via a new `addPendingSystem`
+ `dismissPendingSystem` pair (mirroring the existing pendingUsers
pattern) and dismiss it from `handleChatEvent` whenever any further chat
event for that run is processed. The watchdog's internal cleanup
(`activeChatRunId` reset, status idle, history reload) is unchanged.

Refs #67052, #69081 (closed). Prior attempt #69026 raised the threshold
and suppressed the notice entirely; this is the narrower fix that keeps
the warning useful for genuinely stuck runs.

* fix(tui): adapt pending notice to repeatable system entries

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-22 20:02:36 +01:00
Sebastien Tardif
99e44f623e fix(gateway): add .catch() to SIGTERM/SIGUSR1 signal handlers (#83131)
The SIGTERM handler's fire-and-forget IIFE can reject if the graceful
drain or tunnel-teardown throws. Without a catch, this becomes an
unhandled promise rejection. Add .catch() that logs the error and
falls back to a hard stop request. Same treatment for SIGUSR1.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-05-22 19:47:09 +01:00
yozakura-ava
247e536fa6 fix: release cron runtime state after isolated runs (#85053)
* fix: release cron runtime state after isolated runs

After an isolated cron/subagent run completes, the prepared context retains
references to the full in-memory session store and the registered agent run
context. Over many runs, these retained objects accumulate -- heap snapshots
showed ~2.0 GiB from ~113k copies of the skill prompt string flowing through
skillsSnapshot.prompt -> session entry -> cronSession.store -> cron run context.

Changes:
- Add disposeCronRunContext() to runCronIsolatedAgentTurn's finally block
- Calls clearAgentRunContext(sessionId) to remove the run context from the
  global agent-events map
- Nulls cronSession.store to release the in-memory session registry copy
- Export clearAgentRunContext from run-execution.runtime.ts barrel
- The disposal is shallow O(1) -- no deep traversal, no hot-path disk writes
- Session persistence is unaffected (on-disk sessions.json is untouched)

The finally block guarantees cleanup on both success and error paths,
including timeout/abort scenarios.

Includes unit tests for clearAgentRunContext, store disposal, and
sweepStaleRunContexts.

* fix: remove duplicate storePath property in test fixture

* fix: remove unused clearAgentRunContext import from run-executor

* fix(cron): use initial sessionId for disposeCronRunContext in finally block

finalizeCronRun calls adoptCronRunSessionMetadata() which can rotate
sessionEntry.sessionId before the finally block runs. Capturing the
sessionId before the try block ensures clearAgentRunContext clears the
correct registered context instead of the potentially-rotated one.

Also removes unused imports (vi, beforeEach) from the runtime cleanup test.

* chore: trigger CI re-check for proof gate

* chore: retrigger CI proof gate

* test(cron): prove isolated run cleanup path

* fix(cron): keep shared run contexts active

* test(cron): avoid spreading typed-never fixture

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-22 19:46:58 +01:00
Sergio Cadavid
0c7220f5da fix(cron): suppress fatal error completion announce (#83724)
* fix(cron): suppress fatal error completion announce

* fix(cron): preserve cleanup for fatal announce suppression

* test(cron): avoid spreading typed-never announce fixture

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-22 19:46:54 +01:00
amittell
34c441c746 fix(exec): parse nested approval metadata in async followups (#72268)
* fix(exec): parse nested approval metadata in followups

(cherry picked from commit 10ff9b318e77cda3d65f40d59bbab0f4a3f59da8)

* docs(changelog): note exec approval nested-paren parser fix

* fix(exec): sanitize denied-reason literals in (...)-delimited approval messages

The exec-approval followup wire format is `Exec denied (gateway id=..., <deniedReason>): cmd`. The producer at `src/agents/bash-tools.exec-host-gateway.ts:606` was emitting `approval-timeout (allowlist-miss)`, which embedded literal parens inside the metadata segment and broke the metadata/body boundary for naive parsers. Switch the literal to a colon-separated form (`approval-timeout: allowlist-miss`) so the surrounding `(...)` delimiter stays unambiguous.

The Gateway node-event surface at `src/gateway/server-node-events.ts:734` interpolates an untrusted `obj.reason` into the same `Exec denied (node=..., <reason>)` format. Strip parens from that field before interpolation so a buggy or hostile node payload cannot smuggle metadata into the body slot.

The robust nested-paren parser already in `src/agents/exec-approval-result.ts` stays as defense in depth. Extend `exec-approval-result.test.ts` to cover the canonical colon-separated `deniedReason` and confirm `formatExecDeniedUserMessage` still maps it to the timeout copy.

* fix(exec): require gateway/node metadata source to reject spoofed approval wrappers

The exec-approval result parser previously accepted any string starting with
"Exec denied (..." or "Exec finished (..." as a structured approval wrapper.
Generic command stdout that happened to start with these tokens would be
classified as kind: "denied" or "finished", letting a tool's output spoof a
resolved-approval event in pi-embedded-subscribe.handlers.tools.ts:1173.

Reported by Aisle as CWE-841 (Improper Enforcement of Behavioral Workflow),
medium severity. The fix validates that the parenthesized metadata starts with
either "gateway id=" or "node=" — both prefixes are emitted by the legitimate
approval generators (bash-tools.exec-host-gateway.ts, bash-tools.exec-host-node.ts,
gateway/server-node-events.ts) and are unlikely to appear in arbitrary command
output. Inputs that fail this check now return kind: "other", which all callers
already handle as a no-op.

* fix(exec): keep sandbox_blocked classification for raw exec-denied messages

After the spoof-guard tightening of parseExecApprovalResultText, inputs that
lack a gateway/node-sourced metadata prefix (such as the synthetic
"exec denied (allowlist-miss):" string used in classifier tests) no longer
return kind: "denied" and therefore no longer trigger formatExecDeniedUserMessage,
so isSandboxBlockedErrorMessage stopped recognising them.

Add a direct \bexec denied\s*\( alternative to SANDBOX_BLOCKED_RE so the
classifier still treats any raw "exec denied (" prefix as sandbox-blocked,
independent of whether the parser accepts the surrounding wrapper. This keeps
classifyProviderRuntimeFailureKind's existing behavior for unstructured exec-
denied messages.
2026-05-22 19:46:49 +01:00
CodeReclaimers
6f416537ee fix(gateway): preserve fresh agent session state
Fixes #5369.

Preserve fresh session-store state when the agent handler observes a stale cached session entry, including model/provider overrides, send policy, delivery metadata, lifecycle timestamps, and fresh session rotations.

Co-authored-by: CodeReclaimers <github@codereclaimers.com>
2026-05-22 19:11:20 +01:00
Vincent Koc
77c3bdb3ca fix(gateway): attribute agent wait timeouts 2026-05-23 02:07:44 +08:00
safrano9999
936dfaaac9 Speed up /models browse replies (#84735)
Summary:
- keep default `/models` browse replies on the bounded read-only catalog path
- share the browse catalog loading policy with Gateway model listing
- add helper coverage, preserve full catalog loading for `all` and provider wildcard views, and add the maintainer changelog entry

Verification:
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts src/agents/model-catalog-browse.test.ts`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server-methods/models.test.ts`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.auto-reply-reply.config.ts src/auto-reply/reply/commands-models.test.ts src/auto-reply/reply/directive-handling.model.test.ts`
- `pnpm check:changed` via Blacksmith Testbox `tbx_01ks8bs93c60rjt4ayde91fnjq`
- autoreview clean: no accepted/actionable findings
- GitHub CI, CodeQL, CodeQL Critical Quality, OpenGrep, Workflow Sanity green on `107282aebc2aadde9a3c2acf0cb39fb84b55ade3` before latest changelog-only rebase

Co-authored-by: safrano9999 <240768512+safrano9999@users.noreply.github.com>
2026-05-22 18:56:15 +01:00
Andy Ye
af12082ec8 Let binding commands escape plugin routes 2026-05-22 18:54:37 +01:00
Pavan Kumar Gondhi
10cb0a5ec0 Restore Control UI gateway token pairing [AI] (#85459)
* fix: restore control ui gateway token pairing

* docs: add changelog entry for PR merge
2026-05-22 23:13:32 +05:30
Peter Steinberger
59aef2ff0d fix: apply docs sweep updates 2026-05-22 18:40:20 +01:00
Vincent Koc
769fd0b14a fix(update): roll back failed git updates 2026-05-23 01:37:39 +08:00
Peter Steinberger
9f1472ed8f test(docker): expect prod store seed command 2026-05-22 18:31:11 +01:00
狼哥
46de078b2a fix(agents): bound embedded compaction write locks
Fixes the embedded attempt session write-lock watchdog so the fallback max hold time follows the resolved compaction timeout plus the existing lock grace window, instead of inheriting the full run timeout.

Adds regression coverage for the helper and settled-compaction lock lifecycle, plus a changelog entry thanking @luoyanglang.

Verification:
- `pnpm test src/agents/session-write-lock.test.ts src/agents/pi-embedded-runner/run/attempt.test.ts src/agents/pi-embedded-runner/run/attempt.session-lock.test.ts`
- `pnpm check:changed` via Blacksmith Testbox `tbx_01ks8b6vn8se5cg1dfn3te3g47` / https://github.com/openclaw/openclaw/actions/runs/26301988670
- Autoreview clean: `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- PR CI green on `79e8c5f1a637981d263c0268bf5666967ff4e778`: https://github.com/openclaw/openclaw/actions/runs/26302152844 and https://github.com/openclaw/openclaw/actions/runs/26302152798

Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
2026-05-22 18:30:38 +01:00
FullerStackDev
571f364cd7 fix(update): repair managed npm plugin peers 2026-05-22 18:29:14 +01:00
Peter Steinberger
d8b973638e fix(docker): precreate owned named volume targets (#85454) 2026-05-22 18:25:19 +01:00
Peter Steinberger
9210dfc091 fix(skills): accept macos os requirement on darwin (#85451)
* fix(skills): accept macos os requirement on darwin

* fix: satisfy lint for macos os alias
2026-05-22 18:23:31 +01:00
Eva
87b2046575 fix(gateway): preserve message-tool replies in chat history
Preserve current-chat message.send replies in gateway history and live SSE refreshes, while keeping explicit routed sends out of the active chat.

Proof posted on the PR before merge: https://github.com/openclaw/openclaw/pull/84268#issuecomment-4521077098

Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
2026-05-22 18:18:18 +01:00
Peter Steinberger
9a816f41a9 test: track Docker prod store seed command 2026-05-22 18:17:36 +01:00
Vincent Koc
30333b2e0b test(plugins): clear lookup metadata memo 2026-05-22 19:10:10 +02:00
Aman113114-IITD
6ab32bed5c fix(gateway): point model override error to config docs
Summary:
- Point allowModelOverride denial errors to the current configuration reference anchor.

Verification:
- Source check: docs/gateway/configuration-reference.md documents plugins.entries.<id>.subagent.allowModelOverride.
- PR CI: gateway tests and required shards succeeded.
2026-05-22 17:59:10 +01:00
Peter Steinberger
d9c6c5f600 fix(gateway): preserve OpenAI usage aliases in chat history (#85383) 2026-05-22 17:34:24 +01:00
Colin Johnson
e730e9bd0b feat(ios): add realtime talk relay mode
Adds realtime Gateway Talk relay support for iOS, including OpenAI realtime provider selection and voice selection controls.

Maintainer fixups preserved provider auth fallback resolution, kept setup-code/manual auth through TLS trust prompts, recomputed pairing auth from current form fields, fixed the realtime voice label Swift compile issue, added provider auth regression coverage, and refreshed shrinkwrap metadata for the current CI merge base.

Verification:
- `fnm exec --using 24.15.0 pnpm deps:shrinkwrap:check`
- `git diff --check`
- `swiftformat --lint --config config/swiftformat --unexclude apps/ios/Sources apps/ios/Sources/Gateway/GatewayConnectionController.swift apps/ios/Sources/Onboarding/GatewayOnboardingView.swift apps/ios/Sources/Onboarding/OnboardingWizardView.swift apps/ios/Sources/Settings/SettingsTab.swift apps/ios/Sources/Voice/TalkModeGatewayConfig.swift`
- `swiftlint lint --config apps/ios/.swiftlint.yml apps/ios/Sources/Gateway/GatewayConnectionController.swift apps/ios/Sources/Onboarding/GatewayOnboardingView.swift apps/ios/Sources/Onboarding/OnboardingWizardView.swift apps/ios/Sources/Settings/SettingsTab.swift apps/ios/Sources/Voice/TalkModeGatewayConfig.swift`
- `AUTOREVIEW_AUTO_TESTS=0 .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub CI clean for `8a76c829611c0eb70d4c3b5328f1868aaf3516e1` (cancelled `auto-response` ignored)

Co-authored-by: Colin Johnson <colin@solvely.net>
2026-05-22 17:34:06 +01:00
Vincent Koc
adc6adccd8 fix(update): detect nested macOS gateway ancestry (#85391)
* fix(update): detect nested macOS gateway ancestry

* fix(release): refresh shrinkwrap for CI npm

* fix(update): inherit gateway runtime pid for update guard
2026-05-23 00:00:38 +08:00
Peter Steinberger
cc91ff04cc fix(release): stabilize config restart QA 2026-05-22 15:53:50 +01:00
Bryan P
f9d35dc681 fix(codex): deliver native subagent completions
Deliver Codex-native subagent completions through the generic plugin harness task runtime.

Proof:
- Autoreview clean on final branch.
- Testbox changed gate: tbx_01ks80eqs7d2e3jq3p99zbm4wd, pnpm check:changed, exit 0.
- Live Codex harness: tbx_01ks80p4ky32sqv2ksan2p0w0q, codex/gpt-5.5 API-key auth, native parent/child bridge tokens observed, exit 0.

Co-authored-by: bryanpearson <bryanmpearson@gmail.com>
2026-05-22 15:28:46 +01:00
Josh Lehman
cff5244a5b feat: add context-engine host capability requirements (#84994)
* feat(context-engine): add host capability requirements

* fix(context-engine): advertise pi host capabilities

* fix: repair incompatible context engine slots
2026-05-22 10:28:08 -04:00
Peter Steinberger
dc04503a7e fix: surface plan updates as status notices 2026-05-22 15:21:19 +01:00
clawsweeper[bot]
69255f8f32 fix(gateway): defer provider auth prewarm after startup (#85369)
Summary:
- The PR moves gateway provider auth-state prewarm into cancelable post-ready gateway lifetime work, uses current runtime config for delayed warms, and adds related gateway/provider-auth tests plus a changelog entry.
- Reproducibility: no. high-confidence runtime reproduction was run in this review. Source inspection shows th ... th on current main, and the source PR supplies live after-fix proof for the focused startup-ordering slice.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(gateway): defer provider auth prewarm after startup

Validation:
- ClawSweeper review passed for head 31ea4288e3.
- Required merge gates passed before the squash merge.

Prepared head SHA: 31ea4288e3
Review: https://github.com/openclaw/openclaw/pull/85369#issuecomment-4519123491

Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
2026-05-22 14:14:50 +00:00
VACInc
683ad75b31 fix(talk): stabilize realtime voice consults
Stabilize realtime Talk playback, transcript ordering, and consult routing across Android, Web, and the gateway relay.

- serialize Android realtime playback and transcript updates
- add opt-in forced consult routing for Talk realtime sessions
- keep web/gateway consult turns behind OpenClaw results with ordered transcript bubbles
- document the new `talk.realtime.consultRouting` config and keep prompt wording generic

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-05-22 15:12:39 +01:00
Vincent Koc
bdcaac06c6 fix(diagnostics): bound diagnostic buffers 2026-05-22 22:01:41 +08:00
Mason Huang
6ea907cec1 fix(cli): recover replaced device approvals (#85342)
Summary:
- The PR teaches `openclaw devices approve <requestId>` to approve a compatible same-device replacement request during local fallback and adds focused CLI, infra, and changelog coverage.
- Reproducibility: yes. Source inspection shows current main rejects the gateway's replacement requestId as a  ...  adds focused infra and CLI tests for the churn path; I did not run tests because this review is read-only.

Automerge notes:
- PR branch already contained follow-up commit before automerge: docs: note device approval recovery

Validation:
- ClawSweeper review passed for head 1d2f2e9b2f.
- Required merge gates passed before the squash merge.

Prepared head SHA: 1d2f2e9b2f
Review: https://github.com/openclaw/openclaw/pull/85342#issuecomment-4518449317

Co-authored-by: masonxhuang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
2026-05-22 13:44:15 +00:00
zhang-guiping
937a756f7f fix(runtime-llm): avoid duplicate provider prefix in allowlist diagnostics (#84946)
normalizeAllowedModelRef() and the resolved override ref interpolated
${provider}/${model} after normalizeModelRef(), so a provider-qualified
model id like openrouter/gpt-5.4-mini surfaced as
openrouter/openrouter/gpt-5.4-mini in the allowlist set and policy
denial message, masking the actionable model ref.

Route both sites through modelKey() (src/agents/model-ref-shared.ts)
so the provider segment is collapsed when the model id already starts
with it. Add regression tests covering allowlist hit and denial paths
for the OpenRouter shape.

Fixes #84887
2026-05-22 21:36:13 +08:00
Jayesh Betala
66d1d13889 fix(gateway): include openclaw bin in service PATH (#84475)
* fix(gateway): include openclaw bin in service PATH

* fix(doctor): accept expected service PATH

* docs(changelog): mention managed service PATH bin fix

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-22 21:28:50 +08:00
googlerest
ba86716999 fix(gateway): handle concurrent launchd bootstrap restart race (#84722)
* Handle concurrent launchd bootstrap restart

* docs(changelog): mention launchd bootstrap restart race fix

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-22 21:21:23 +08:00
Peter Steinberger
04ebdc6da5 test(release): align prerelease validation baselines 2026-05-22 14:15:46 +01:00
NianJiu
fc7a531f6c fix(gateway): harden launchd reload handoff race recovery (#84641)
* fix(gateway): harden launchd reload handoff race recovery

* docs(changelog): mention launchd reload handoff race fix

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-22 21:13:26 +08:00
Huvee
ca2b9ad289 fix: honor per-model provider transport overrides (#80488)
Summary:
- Honor per-model api/baseUrl overrides during custom provider auth hook lookup and transport selection.
- Keep models-add metadata safeguards intact and add focused auth/model resolver regression coverage.
- Add maintainer changelog credit for @huveewomg.

Verification:
- git diff --check
- GitHub CI green on 277629e992
- GitHub CodeQL green on 277629e992
- GitHub CodeQL Critical Quality green on 277629e992
- GitHub Real behavior proof green on 277629e992
- Local focused Vitest was stopped after 8 minutes on a busy host without producing a result; PR CI supplied the final proof.

Co-authored-by: huveewomg <wongrenthou1265@gmail.com>
2026-05-22 14:12:11 +01:00
openperf
19ff77e9c9 fix(skills): document watcher edge cases, add teardown/rebuild tests, add changelog 2026-05-22 14:10:56 +01:00
openperf
bb73f0a5c3 fix(skills): type watcher mock calls in dedupe regression tests 2026-05-22 14:10:56 +01:00
openperf
3e94290460 fix(skills): dedupe shared-directory watchers across agent workspaces (#84968) 2026-05-22 14:10:56 +01:00