diff --git a/AGENTS.md b/AGENTS.md index daef230c6fe..db9f06e84e2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -132,7 +132,9 @@ - `pnpm tsgo:core:test`: core colocated tests. - `pnpm tsgo:extensions`: bundled extension production graph. - `pnpm tsgo:extensions:test`: bundled extension colocated tests. - - `pnpm tsgo:all`: every TypeScript graph above; this is what `pnpm check` runs. + - `pnpm tsgo:core:all`: core production + core test project references (`tsconfig.core.projects.json`). + - `pnpm tsgo:extensions:all`: extension production + extension test project references (`tsconfig.extensions.projects.json`). + - `pnpm tsgo:all`: every TypeScript graph above through the project-reference root (`tsconfig.projects.json`); this is what `pnpm check` runs. - `pnpm tsgo:profile [core-test|extensions-test|--all]`: profile fresh graph cost into `.artifacts/tsgo-profile/`. Diagnostic-only profile slices (`core-test-agents`, `core-test-non-agents`) exist for investigating agent graph cost; do not treat them as normal user-facing checks. - Narrow aliases remain for local loops: `pnpm tsgo:test:src`, `pnpm tsgo:test:ui`, `pnpm tsgo:test:packages`. - Do not add `tsc --noEmit`, `typecheck`, or `check:types` lanes for repo type checking. Use `tsgo` graphs. `tsc` is allowed only when emitting declaration/package-boundary compatibility artifacts that `tsgo` does not replace. @@ -147,6 +149,7 @@ - A landing gate is the broader bar before pushing `main`, usually `pnpm check`, `pnpm test`, and `pnpm build` when the touched surface can affect build output, packaging, lazy-loading/module boundaries, or published surfaces. - A CI gate is whatever the relevant workflow enforces for that lane (for example `check`, `check-additional`, `build-smoke`, or release validation). - Local dev gate: prefer `pnpm check` for the normal edit loop. It keeps the repo-architecture policy guards out of the default local loop. +- Timed local gate: use `pnpm check:timed` to see per-stage cost. Add `:architecture` only when investigating the CI architecture gate locally. - CI architecture gate: `check-additional` enforces architecture and boundary policy guards that are intentionally kept out of the default local loop. - Formatting gate: the pre-commit hook runs targeted formatting on staged source files before `pnpm check`. If you want a repo-wide formatting-only preflight locally, run `pnpm format:check` explicitly. - If you need a fast commit loop, `FAST_COMMIT=1 git commit ...` skips the hook’s repo-wide `pnpm check`; targeted formatting/linting still runs, so use that only when you are deliberately covering the touched surface some other way. @@ -190,7 +193,7 @@ - New runtime control-flow code should not branch on `error: string` or `reason: string` when a closed code union would be reasonable. - Dynamic import guardrail: do not mix `await import("x")` and static `import ... from "x"` for the same module in production code paths. If you need lazy loading, create a dedicated `*.runtime.ts` boundary (that re-exports from `x`) and dynamically import that boundary from lazy callers only. - Dynamic import verification: after refactors that touch lazy-loading/module boundaries, run `pnpm build` and check for `[INEFFECTIVE_DYNAMIC_IMPORT]` warnings before submitting. -- Circular dependencies: keep both `pnpm check:import-cycles` and `pnpm check:madge-import-cycles` green; do not reintroduce runtime import cycles or madge-detected import loops. +- Circular dependencies: `pnpm check` runs the fast runtime import-cycle guard. `pnpm check:architecture` (and CI `check-additional`) also runs the broader madge import-cycle guard; keep both green before landing architecture-sensitive changes. - Extension SDK self-import guardrail: inside an extension package, do not import that same extension via `openclaw/plugin-sdk/` from production files. Route internal imports through a local barrel such as `./api.ts` or `./runtime-api.ts`, and keep the `plugin-sdk/` path as the external contract only. - Extension package boundary guardrail: inside a bundled plugin package, do not use relative imports/exports that resolve outside that same package root. If shared code belongs in the plugin SDK, import `openclaw/plugin-sdk/` instead of reaching into `src/plugin-sdk/**` or other repo paths via `../`. - Extension API surface rule: `openclaw/plugin-sdk/` is the only public cross-package contract for extension-facing SDK code. If an extension needs a new seam, add a public subpath first; do not reach into `src/plugin-sdk/**` by relative path. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f05dd31f86..05f1a03d191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Docs: https://docs.openclaw.ai ## Unreleased +## 2026.4.20 + ### Changes - Plugins/tasks: add a detached runtime registration contract so plugin executors can own detached task lifecycle and cancellation without reaching into core task internals. (#68915) Thanks @mbelinky. diff --git a/apps/android/app/build.gradle.kts b/apps/android/app/build.gradle.kts index 0499cd1a26f..de08f5ecc25 100644 --- a/apps/android/app/build.gradle.kts +++ b/apps/android/app/build.gradle.kts @@ -65,8 +65,8 @@ android { applicationId = "ai.openclaw.app" minSdk = 31 targetSdk = 36 - versionCode = 2026041902 - versionName = "2026.4.19-beta.2" + versionCode = 2026042000 + versionName = "2026.4.20" ndk { // Support all major ABIs — native libs are tiny (~47 KB per ABI) abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") diff --git a/apps/ios/CHANGELOG.md b/apps/ios/CHANGELOG.md index 5ef3a2594a1..8cd1fac26c1 100644 --- a/apps/ios/CHANGELOG.md +++ b/apps/ios/CHANGELOG.md @@ -1,5 +1,9 @@ # OpenClaw iOS Changelog +## 2026.4.20 - 2026-04-20 + +Maintenance update for the current OpenClaw release. + ## 2026.4.19 - 2026-04-19 Maintenance update for the current OpenClaw beta release. diff --git a/apps/ios/Config/Version.xcconfig b/apps/ios/Config/Version.xcconfig index 24923d50bca..fc650b9e4eb 100644 --- a/apps/ios/Config/Version.xcconfig +++ b/apps/ios/Config/Version.xcconfig @@ -2,8 +2,8 @@ // Source of truth: apps/ios/version.json // Generated by scripts/ios-sync-versioning.ts. -OPENCLAW_IOS_VERSION = 2026.4.19 -OPENCLAW_MARKETING_VERSION = 2026.4.19 +OPENCLAW_IOS_VERSION = 2026.4.20 +OPENCLAW_MARKETING_VERSION = 2026.4.20 OPENCLAW_BUILD_VERSION = 1 #include? "../build/Version.xcconfig" diff --git a/apps/ios/fastlane/metadata/en-US/release_notes.txt b/apps/ios/fastlane/metadata/en-US/release_notes.txt index 5090e4186ab..99afd00b10b 100644 --- a/apps/ios/fastlane/metadata/en-US/release_notes.txt +++ b/apps/ios/fastlane/metadata/en-US/release_notes.txt @@ -1 +1 @@ -Maintenance update for the current OpenClaw beta release. +Maintenance update for the current OpenClaw release. diff --git a/apps/ios/version.json b/apps/ios/version.json index 12e69f6617b..d12a7e41436 100644 --- a/apps/ios/version.json +++ b/apps/ios/version.json @@ -1,3 +1,3 @@ { - "version": "2026.4.19" + "version": "2026.4.20" } diff --git a/apps/macos/Sources/OpenClaw/Resources/Info.plist b/apps/macos/Sources/OpenClaw/Resources/Info.plist index be7fdd834b2..dbc3943063a 100644 --- a/apps/macos/Sources/OpenClaw/Resources/Info.plist +++ b/apps/macos/Sources/OpenClaw/Resources/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2026.4.19-beta.2 + 2026.4.20 CFBundleVersion - 2026041902 + 2026042000 CFBundleIconFile OpenClaw CFBundleURLTypes diff --git a/docs/.generated/config-baseline.sha256 b/docs/.generated/config-baseline.sha256 index 550499df716..85a14925092 100644 --- a/docs/.generated/config-baseline.sha256 +++ b/docs/.generated/config-baseline.sha256 @@ -1,4 +1,4 @@ -889094f0a34a8a8a8b7672b846f4cbe41e273ebb6fd230f1955ec80c65339bef config-baseline.json -10b7c57a6198526b846471e1bcda6e361c1f3db2e3b1cd24abd8bac11db56e16 config-baseline.core.json +b199851e694368264c24ba3d347a84764a19f632769e049fe94a82787c5e5d93 config-baseline.json +cbb9a6ee1cb69068d5eb63f00f95512ba19778415ea5b2eabe056aaea38978b5 config-baseline.core.json 0982fc3d264047919333a57dfba1ba948e6639fb19659a400f947dfdd8b8d1de config-baseline.channel.json b695cb31b4c0cf1d31f842f2892e99cc3ff8d84263ae72b72977cae844b81d6e config-baseline.plugin.json diff --git a/docs/.i18n/glossary.zh-CN.json b/docs/.i18n/glossary.zh-CN.json index abcb56f2c57..1d1989f53fc 100644 --- a/docs/.i18n/glossary.zh-CN.json +++ b/docs/.i18n/glossary.zh-CN.json @@ -374,5 +374,17 @@ { "source": "Testing", "target": "测试" + }, + { + "source": "/gateway/configuration#strict-validation", + "target": "/gateway/configuration#strict-validation" + }, + { + "source": "/gateway/configuration#config-hot-reload", + "target": "/gateway/configuration#config-hot-reload" + }, + { + "source": "/cli/config", + "target": "/cli/config" } ] diff --git a/docs/ci.md b/docs/ci.md index 514ec5ab7cd..373fafeeec9 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -57,9 +57,10 @@ On pushes, the `checks` matrix adds the push-only `compat-node22` lane. On pull ## Local Equivalents ```bash -pnpm check # types + lint + format +pnpm check # fast local gate: project-reference tsgo + lint + fast guards +pnpm check:timed # same gate with per-stage timings pnpm build:strict-smoke -pnpm check:import-cycles +pnpm check:architecture pnpm test:gateway:watch-regression pnpm test # vitest tests pnpm test:channels diff --git a/docs/cli/config.md b/docs/cli/config.md index 6bb8f081c65..df2ebe89c3d 100644 --- a/docs/cli/config.md +++ b/docs/cli/config.md @@ -336,6 +336,34 @@ If dry-run fails: - `Dry run note: skipped exec SecretRef resolvability check(s)`: dry-run skipped exec refs; rerun with `--allow-exec` if you need exec resolvability validation. - For batch mode, fix failing entries and rerun `--dry-run` before writing. +## Write safety + +`openclaw config set` and other OpenClaw-owned config writers validate the full +post-change config before committing it to disk. If the new payload fails schema +validation or looks like a destructive clobber, the active config is left alone +and the rejected payload is saved beside it as `openclaw.json.rejected.*`. + +Prefer CLI writes for small edits: + +```bash +openclaw config set gateway.reload.mode hybrid --dry-run +openclaw config set gateway.reload.mode hybrid +openclaw config validate +``` + +If a write is rejected, inspect the saved payload and fix the full config shape: + +```bash +CONFIG="$(openclaw config file)" +ls -lt "$CONFIG".rejected.* 2>/dev/null | head +openclaw config validate +``` + +Direct editor writes are still allowed, but the running Gateway treats them as +untrusted until they validate. Invalid direct edits can be restored from the +last-known-good backup during startup or hot reload. See +[Gateway troubleshooting](/gateway/troubleshooting#gateway-restored-last-known-good-config). + ## Subcommands - `config file`: Print the active config file path (resolved from `OPENCLAW_CONFIG_PATH` or default location). diff --git a/docs/gateway/configuration.md b/docs/gateway/configuration.md index 9f0ea090996..7c88a628542 100644 --- a/docs/gateway/configuration.md +++ b/docs/gateway/configuration.md @@ -96,6 +96,17 @@ When validation fails: - Run `openclaw doctor` to see exact issues - Run `openclaw doctor --fix` (or `--yes`) to apply repairs +The Gateway also keeps a trusted last-known-good copy after a successful startup. If +`openclaw.json` is later changed outside OpenClaw and no longer validates, startup +and hot reload preserve the broken file as a timestamped `.clobbered.*` snapshot, +restore the last-known-good copy, and log a loud warning with the recovery reason. +The next main-agent turn also receives a system-event warning telling it that the +config was restored and must not be blindly rewritten. Last-known-good promotion +is updated after validated startup and after accepted hot reloads, including +OpenClaw-owned config writes whose persisted file hash still matches the accepted +write. Promotion is skipped when the candidate contains redacted secret +placeholders such as `***` or shortened token values. + ## Common tasks @@ -494,6 +505,19 @@ When validation fails: The Gateway watches `~/.openclaw/openclaw.json` and applies changes automatically — no manual restart needed for most settings. +Direct file edits are treated as untrusted until they validate. The watcher waits +for editor temp-write/rename churn to settle, reads the final file, and rejects +invalid external edits by restoring the last-known-good config. OpenClaw-owned +config writes use the same schema gate before writing; destructive clobbers such +as dropping `gateway.mode` or shrinking the file by more than half are rejected +and saved as `.rejected.*` for inspection. + +If you see `Config auto-restored from last-known-good` or +`config reload restored last-known-good config` in logs, inspect the matching +`.clobbered.*` file next to `openclaw.json`, fix the rejected payload, then run +`openclaw config validate`. See [Gateway troubleshooting](/gateway/troubleshooting#gateway-restored-last-known-good-config) +for the recovery checklist. + ### Reload modes | Mode | Behavior | diff --git a/docs/gateway/troubleshooting.md b/docs/gateway/troubleshooting.md index c4c16fe5726..8819aba67d8 100644 --- a/docs/gateway/troubleshooting.md +++ b/docs/gateway/troubleshooting.md @@ -262,6 +262,63 @@ Related: - [/gateway/configuration](/gateway/configuration) - [/gateway/doctor](/gateway/doctor) +## Gateway restored last-known-good config + +Use this when the Gateway starts, but logs say it restored `openclaw.json`. + +```bash +openclaw logs --follow +openclaw config file +openclaw config validate +openclaw doctor +``` + +Look for: + +- `Config auto-restored from last-known-good` +- `gateway: invalid config was restored from last-known-good backup` +- `config reload restored last-known-good config after invalid-config` +- A timestamped `openclaw.json.clobbered.*` file beside the active config +- A main-agent system event that starts with `Config recovery warning` + +What happened: + +- The rejected config did not validate during startup or hot reload. +- OpenClaw preserved the rejected payload as `.clobbered.*`. +- The active config was restored from the last validated last-known-good copy. +- The next main-agent turn is warned not to blindly rewrite the rejected config. + +Inspect and repair: + +```bash +CONFIG="$(openclaw config file)" +ls -lt "$CONFIG".clobbered.* "$CONFIG".rejected.* 2>/dev/null | head +diff -u "$CONFIG" "$(ls -t "$CONFIG".clobbered.* 2>/dev/null | head -n 1)" +openclaw config validate +openclaw doctor +``` + +Common signatures: + +- `.clobbered.*` exists → an external direct edit or startup read was restored. +- `.rejected.*` exists → an OpenClaw-owned config write failed schema or clobber checks before commit. +- `Config write rejected:` → the write tried to drop required shape, shrink the file sharply, or persist invalid config. +- `Config last-known-good promotion skipped` → the candidate contained redacted secret placeholders such as `***`. + +Fix options: + +1. Keep the restored active config if it is correct. +2. Copy only the intended keys from `.clobbered.*` or `.rejected.*`, then apply them with `openclaw config set` or `config.patch`. +3. Run `openclaw config validate` before restarting. +4. If you edit by hand, keep the full JSON5 config, not just the partial object you wanted to change. + +Related: + +- [/gateway/configuration#strict-validation](/gateway/configuration#strict-validation) +- [/gateway/configuration#config-hot-reload](/gateway/configuration#config-hot-reload) +- [/cli/config](/cli/config) +- [/gateway/doctor](/gateway/doctor) + ## Gateway probe warnings Use this when `openclaw gateway probe` reaches something, but still prints a warning block. diff --git a/docs/help/faq.md b/docs/help/faq.md index f40e55b3429..6101e6c07db 100644 --- a/docs/help/faq.md +++ b/docs/help/faq.md @@ -1629,10 +1629,20 @@ for usage/billing and raise limits as needed. `config.apply` replaces the **entire config**. If you send a partial object, everything else is removed. + Current OpenClaw protects many accidental clobbers: + + - OpenClaw-owned config writes validate the full post-change config before writing. + - Invalid or destructive OpenClaw-owned writes are rejected and saved as `openclaw.json.rejected.*`. + - If a direct edit breaks startup or hot reload, the Gateway restores the last-known-good config and saves the rejected file as `openclaw.json.clobbered.*`. + - The main agent receives a boot warning after recovery so it does not blindly write the bad config again. + Recover: - - Restore from backup (git or a copied `~/.openclaw/openclaw.json`). - - If you have no backup, re-run `openclaw doctor` and reconfigure channels/models. + - Check `openclaw logs --follow` for `Config auto-restored from last-known-good`, `Config write rejected:`, or `config reload restored last-known-good config`. + - Inspect the newest `openclaw.json.clobbered.*` or `openclaw.json.rejected.*` beside the active config. + - Keep the active restored config if it works, then copy only the intended keys back with `openclaw config set` or `config.patch`. + - Run `openclaw config validate` and `openclaw doctor`. + - If you have no last-known-good or rejected payload, restore from backup, or re-run `openclaw doctor` and reconfigure channels/models. - If this was unexpected, file a bug and include your last known config or any backup. - A local coding agent can often reconstruct a working config from logs or history. @@ -1644,7 +1654,7 @@ for usage/billing and raise limits as needed. - Use `config.patch` for partial RPC edits; keep `config.apply` for full-config replacement only. - If you are using the owner-only `gateway` tool from an agent run, it will still reject writes to `tools.exec.ask` / `tools.exec.security` (including legacy `tools.bash.*` aliases that normalize to the same protected exec paths). - Docs: [Config](/cli/config), [Configure](/cli/configure), [Doctor](/gateway/doctor). + Docs: [Config](/cli/config), [Configure](/cli/configure), [Gateway troubleshooting](/gateway/troubleshooting#gateway-restored-last-known-good-config), [Doctor](/gateway/doctor). diff --git a/extensions/acpx/package.json b/extensions/acpx/package.json index 4c46c4f3853..9814b29e94c 100644 --- a/extensions/acpx/package.json +++ b/extensions/acpx/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/acpx", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw ACP runtime backend", "type": "module", "dependencies": { diff --git a/extensions/alibaba/package.json b/extensions/alibaba/package.json index 933ef1f9c61..58ec1371654 100644 --- a/extensions/alibaba/package.json +++ b/extensions/alibaba/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/alibaba-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Alibaba Model Studio video provider plugin", "type": "module", diff --git a/extensions/amazon-bedrock-mantle/package.json b/extensions/amazon-bedrock-mantle/package.json index b61ff3492f0..9eaa1c441be 100644 --- a/extensions/amazon-bedrock-mantle/package.json +++ b/extensions/amazon-bedrock-mantle/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/amazon-bedrock-mantle-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Amazon Bedrock Mantle (OpenAI-compatible) provider plugin", "type": "module", diff --git a/extensions/amazon-bedrock/package.json b/extensions/amazon-bedrock/package.json index d7e7f329d9a..7a95c369855 100644 --- a/extensions/amazon-bedrock/package.json +++ b/extensions/amazon-bedrock/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/amazon-bedrock-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Amazon Bedrock provider plugin", "type": "module", diff --git a/extensions/anthropic-vertex/package.json b/extensions/anthropic-vertex/package.json index 105f60b9e28..1992c452c1f 100644 --- a/extensions/anthropic-vertex/package.json +++ b/extensions/anthropic-vertex/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/anthropic-vertex-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Anthropic Vertex provider plugin", "type": "module", diff --git a/extensions/anthropic/package.json b/extensions/anthropic/package.json index dad285b59ab..9a1aa4e594a 100644 --- a/extensions/anthropic/package.json +++ b/extensions/anthropic/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/anthropic-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Anthropic provider plugin", "type": "module", diff --git a/extensions/arcee/package.json b/extensions/arcee/package.json index c62678b4e96..b03039a8397 100644 --- a/extensions/arcee/package.json +++ b/extensions/arcee/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/arcee-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Arcee provider plugin", "type": "module", diff --git a/extensions/bluebubbles/package.json b/extensions/bluebubbles/package.json index 4b5c3f1373a..da46c46a98b 100644 --- a/extensions/bluebubbles/package.json +++ b/extensions/bluebubbles/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/bluebubbles", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw BlueBubbles channel plugin", "type": "module", "devDependencies": { @@ -8,7 +8,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -43,10 +43,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/brave/package.json b/extensions/brave/package.json index 734d0b1f8d7..4ed4a142e45 100644 --- a/extensions/brave/package.json +++ b/extensions/brave/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/brave-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Brave plugin", "type": "module", diff --git a/extensions/browser/package.json b/extensions/browser/package.json index f74a87379f4..9129ebc43a7 100644 --- a/extensions/browser/package.json +++ b/extensions/browser/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/browser-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw browser tool plugin", "type": "module", diff --git a/extensions/byteplus/package.json b/extensions/byteplus/package.json index a0ea9d7b9fe..3d95c322bba 100644 --- a/extensions/byteplus/package.json +++ b/extensions/byteplus/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/byteplus-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw BytePlus provider plugin", "type": "module", diff --git a/extensions/chutes/package.json b/extensions/chutes/package.json index 5ab472852ca..c55e04e4916 100644 --- a/extensions/chutes/package.json +++ b/extensions/chutes/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/chutes-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Chutes.ai provider plugin", "type": "module", diff --git a/extensions/cloudflare-ai-gateway/package.json b/extensions/cloudflare-ai-gateway/package.json index fbadfd72bc4..bc025c6ee3f 100644 --- a/extensions/cloudflare-ai-gateway/package.json +++ b/extensions/cloudflare-ai-gateway/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/cloudflare-ai-gateway-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Cloudflare AI Gateway provider plugin", "type": "module", diff --git a/extensions/codex/package.json b/extensions/codex/package.json index 38a3499283e..12d9e1a0304 100644 --- a/extensions/codex/package.json +++ b/extensions/codex/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/codex", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Codex harness and model provider plugin", "type": "module", "dependencies": { diff --git a/extensions/comfy/package.json b/extensions/comfy/package.json index 425a826cc95..89fd3fd126d 100644 --- a/extensions/comfy/package.json +++ b/extensions/comfy/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/comfy-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw ComfyUI provider plugin", "type": "module", diff --git a/extensions/copilot-proxy/package.json b/extensions/copilot-proxy/package.json index 3c73828a1eb..f68a3e3217b 100644 --- a/extensions/copilot-proxy/package.json +++ b/extensions/copilot-proxy/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/copilot-proxy", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Copilot Proxy provider plugin", "type": "module", diff --git a/extensions/deepgram/package.json b/extensions/deepgram/package.json index a886cfd79d2..b729d652ad3 100644 --- a/extensions/deepgram/package.json +++ b/extensions/deepgram/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/deepgram-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Deepgram media-understanding provider", "type": "module", diff --git a/extensions/deepseek/package.json b/extensions/deepseek/package.json index 8395fc77ea1..221e85c8506 100644 --- a/extensions/deepseek/package.json +++ b/extensions/deepseek/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/deepseek-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw DeepSeek provider plugin", "type": "module", diff --git a/extensions/diagnostics-otel/package.json b/extensions/diagnostics-otel/package.json index 42c31dce521..51740b29ac8 100644 --- a/extensions/diagnostics-otel/package.json +++ b/extensions/diagnostics-otel/package.json @@ -1,19 +1,19 @@ { "name": "@openclaw/diagnostics-otel", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw diagnostics OpenTelemetry exporter", "type": "module", "dependencies": { "@opentelemetry/api": "^1.9.1", - "@opentelemetry/api-logs": "^0.214.0", - "@opentelemetry/exporter-logs-otlp-proto": "^0.214.0", - "@opentelemetry/exporter-metrics-otlp-proto": "^0.214.0", - "@opentelemetry/exporter-trace-otlp-proto": "^0.214.0", - "@opentelemetry/resources": "^2.6.1", - "@opentelemetry/sdk-logs": "^0.214.0", - "@opentelemetry/sdk-metrics": "^2.6.1", - "@opentelemetry/sdk-node": "^0.214.0", - "@opentelemetry/sdk-trace-base": "^2.6.1", + "@opentelemetry/api-logs": "^0.215.0", + "@opentelemetry/exporter-logs-otlp-proto": "^0.215.0", + "@opentelemetry/exporter-metrics-otlp-proto": "^0.215.0", + "@opentelemetry/exporter-trace-otlp-proto": "^0.215.0", + "@opentelemetry/resources": "^2.7.0", + "@opentelemetry/sdk-logs": "^0.215.0", + "@opentelemetry/sdk-metrics": "^2.7.0", + "@opentelemetry/sdk-node": "^0.215.0", + "@opentelemetry/sdk-trace-base": "^2.7.0", "@opentelemetry/semantic-conventions": "^1.40.0" }, "devDependencies": { @@ -24,10 +24,10 @@ "./index.ts" ], "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/diffs/package.json b/extensions/diffs/package.json index fc8ea9ec626..1f1fbc56865 100644 --- a/extensions/diffs/package.json +++ b/extensions/diffs/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/diffs", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw diff viewer plugin", "type": "module", diff --git a/extensions/discord/package.json b/extensions/discord/package.json index 6060ffece08..05b763343c3 100644 --- a/extensions/discord/package.json +++ b/extensions/discord/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/discord", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Discord channel plugin", "type": "module", "dependencies": { @@ -16,7 +16,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -52,10 +52,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "bundle": { "stageRuntimeDependencies": true diff --git a/extensions/duckduckgo/package.json b/extensions/duckduckgo/package.json index db8270151cc..da4a33fd528 100644 --- a/extensions/duckduckgo/package.json +++ b/extensions/duckduckgo/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/duckduckgo-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw DuckDuckGo plugin", "type": "module", diff --git a/extensions/elevenlabs/package.json b/extensions/elevenlabs/package.json index 3428e84891a..f8aca5f71b8 100644 --- a/extensions/elevenlabs/package.json +++ b/extensions/elevenlabs/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/elevenlabs-speech", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw ElevenLabs speech plugin", "type": "module", diff --git a/extensions/exa/package.json b/extensions/exa/package.json index 0c136139374..3358d7b87b5 100644 --- a/extensions/exa/package.json +++ b/extensions/exa/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/exa-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Exa plugin", "type": "module", diff --git a/extensions/fal/package.json b/extensions/fal/package.json index 3500617cf95..cff7655f862 100644 --- a/extensions/fal/package.json +++ b/extensions/fal/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/fal-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw fal provider plugin", "type": "module", diff --git a/extensions/feishu/package.json b/extensions/feishu/package.json index e174ff65000..c7dfd9da723 100644 --- a/extensions/feishu/package.json +++ b/extensions/feishu/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/feishu", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng)", "type": "module", "dependencies": { @@ -13,7 +13,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -44,10 +44,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "bundle": { "stageRuntimeDependencies": true diff --git a/extensions/firecrawl/package.json b/extensions/firecrawl/package.json index 888432b48fb..defde5e3962 100644 --- a/extensions/firecrawl/package.json +++ b/extensions/firecrawl/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/firecrawl-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Firecrawl plugin", "type": "module", diff --git a/extensions/fireworks/package.json b/extensions/fireworks/package.json index 9416e63a0ee..a34bcd34537 100644 --- a/extensions/fireworks/package.json +++ b/extensions/fireworks/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/fireworks-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Fireworks provider plugin", "type": "module", diff --git a/extensions/github-copilot/package.json b/extensions/github-copilot/package.json index 9a685f14fd7..14f720a47ad 100644 --- a/extensions/github-copilot/package.json +++ b/extensions/github-copilot/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/github-copilot-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw GitHub Copilot provider plugin", "type": "module", diff --git a/extensions/google/package.json b/extensions/google/package.json index 4fb9099ddfd..91d297de875 100644 --- a/extensions/google/package.json +++ b/extensions/google/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/google-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Google plugin", "type": "module", diff --git a/extensions/googlechat/package.json b/extensions/googlechat/package.json index 196dd3ed745..10410f8b19b 100644 --- a/extensions/googlechat/package.json +++ b/extensions/googlechat/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/googlechat", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Google Chat channel plugin", "type": "module", @@ -12,7 +12,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/groq/package.json b/extensions/groq/package.json index acb158ce2c8..517f4da8403 100644 --- a/extensions/groq/package.json +++ b/extensions/groq/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/groq-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Groq media-understanding provider", "type": "module", diff --git a/extensions/huggingface/package.json b/extensions/huggingface/package.json index bfa1ed7da56..991dd5c2b19 100644 --- a/extensions/huggingface/package.json +++ b/extensions/huggingface/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/huggingface-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Hugging Face provider plugin", "type": "module", diff --git a/extensions/image-generation-core/package.json b/extensions/image-generation-core/package.json index c2cf116f2ec..050590ca622 100644 --- a/extensions/image-generation-core/package.json +++ b/extensions/image-generation-core/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/image-generation-core", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw image generation runtime package", "type": "module", diff --git a/extensions/imessage/package.json b/extensions/imessage/package.json index 8d5947abfbf..874b9812664 100644 --- a/extensions/imessage/package.json +++ b/extensions/imessage/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/imessage", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw iMessage channel plugin", "type": "module", diff --git a/extensions/irc/package.json b/extensions/irc/package.json index beda195854d..2e75e90df24 100644 --- a/extensions/irc/package.json +++ b/extensions/irc/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/irc", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw IRC channel plugin", "type": "module", "devDependencies": { diff --git a/extensions/kilocode/package.json b/extensions/kilocode/package.json index 1feb00ddbcf..0ef15c3b0c4 100644 --- a/extensions/kilocode/package.json +++ b/extensions/kilocode/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/kilocode-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Kilo Gateway provider plugin", "type": "module", diff --git a/extensions/kimi-coding/package.json b/extensions/kimi-coding/package.json index ba036cadb3a..679a7dc9ccf 100644 --- a/extensions/kimi-coding/package.json +++ b/extensions/kimi-coding/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/kimi-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Kimi provider plugin", "type": "module", diff --git a/extensions/line/package.json b/extensions/line/package.json index bfd5f55b573..10926368342 100644 --- a/extensions/line/package.json +++ b/extensions/line/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/line", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw LINE channel plugin", "type": "module", @@ -12,7 +12,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/litellm/package.json b/extensions/litellm/package.json index 7460e7e3988..0f8c9ad3562 100644 --- a/extensions/litellm/package.json +++ b/extensions/litellm/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/litellm-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw LiteLLM provider plugin", "type": "module", diff --git a/extensions/llm-task/package.json b/extensions/llm-task/package.json index f9ae3643c18..65321d341ab 100644 --- a/extensions/llm-task/package.json +++ b/extensions/llm-task/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/llm-task", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw JSON-only LLM task plugin", "type": "module", diff --git a/extensions/lmstudio/package.json b/extensions/lmstudio/package.json index 3016f53aabf..7bbcea36bbf 100644 --- a/extensions/lmstudio/package.json +++ b/extensions/lmstudio/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/lmstudio-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw LM Studio provider plugin", "type": "module", diff --git a/extensions/lobster/package.json b/extensions/lobster/package.json index d920b5ad8f3..9470664e41c 100644 --- a/extensions/lobster/package.json +++ b/extensions/lobster/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/lobster", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)", "type": "module", "dependencies": { @@ -15,10 +15,10 @@ "./index.ts" ], "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/matrix/CHANGELOG.md b/extensions/matrix/CHANGELOG.md index 318fc0d2a11..09442e7e40d 100644 --- a/extensions/matrix/CHANGELOG.md +++ b/extensions/matrix/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2026.4.20 + +### Changes + +- Version alignment with core OpenClaw release numbers. + ## 2026.4.19-beta.1 ### Changes diff --git a/extensions/matrix/package.json b/extensions/matrix/package.json index 37490177f32..63df5333475 100644 --- a/extensions/matrix/package.json +++ b/extensions/matrix/package.json @@ -1,11 +1,11 @@ { "name": "@openclaw/matrix", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Matrix channel plugin", "type": "module", "dependencies": { "@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0", - "@matrix-org/matrix-sdk-crypto-wasm": "18.0.0", + "@matrix-org/matrix-sdk-crypto-wasm": "18.1.0", "fake-indexeddb": "^6.2.5", "markdown-it": "14.1.1", "matrix-js-sdk": "41.3.0", @@ -16,7 +16,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/mattermost/package.json b/extensions/mattermost/package.json index c5e5151d8fd..8ad89488e3b 100644 --- a/extensions/mattermost/package.json +++ b/extensions/mattermost/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/mattermost", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Mattermost channel plugin", "type": "module", "dependencies": { @@ -12,7 +12,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/media-understanding-core/package.json b/extensions/media-understanding-core/package.json index 0dec0a07b5c..60ab617574f 100644 --- a/extensions/media-understanding-core/package.json +++ b/extensions/media-understanding-core/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/media-understanding-core", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw media understanding runtime package", "type": "module", diff --git a/extensions/memory-core/package.json b/extensions/memory-core/package.json index 648d919689c..0cc35195f6e 100644 --- a/extensions/memory-core/package.json +++ b/extensions/memory-core/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/memory-core", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw core memory search plugin", "type": "module", @@ -9,7 +9,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/memory-lancedb/package.json b/extensions/memory-lancedb/package.json index 34e68ba14a1..da72ffc5d94 100644 --- a/extensions/memory-lancedb/package.json +++ b/extensions/memory-lancedb/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/memory-lancedb", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture", "type": "module", "dependencies": { @@ -21,10 +21,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/memory-wiki/package.json b/extensions/memory-wiki/package.json index 49d67f48240..8df2e96cc51 100644 --- a/extensions/memory-wiki/package.json +++ b/extensions/memory-wiki/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/memory-wiki", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw persistent wiki plugin", "type": "module", @@ -12,7 +12,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/microsoft-foundry/package.json b/extensions/microsoft-foundry/package.json index ebe58f39594..99ba5f2bdfe 100644 --- a/extensions/microsoft-foundry/package.json +++ b/extensions/microsoft-foundry/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/microsoft-foundry", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Microsoft Foundry provider plugin", "type": "module", diff --git a/extensions/microsoft/package.json b/extensions/microsoft/package.json index 2255a7e38fe..b76a7c9899f 100644 --- a/extensions/microsoft/package.json +++ b/extensions/microsoft/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/microsoft-speech", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Microsoft speech plugin", "type": "module", diff --git a/extensions/minimax/package.json b/extensions/minimax/package.json index 30a7cb2bc35..fc5893e3a9c 100644 --- a/extensions/minimax/package.json +++ b/extensions/minimax/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/minimax-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw MiniMax provider and OAuth plugin", "type": "module", diff --git a/extensions/mistral/package.json b/extensions/mistral/package.json index 9959a4b10ba..c49bad4118c 100644 --- a/extensions/mistral/package.json +++ b/extensions/mistral/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/mistral-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Mistral provider plugin", "type": "module", diff --git a/extensions/moonshot/package.json b/extensions/moonshot/package.json index 4444ba0cf1f..d83f5c50ad2 100644 --- a/extensions/moonshot/package.json +++ b/extensions/moonshot/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/moonshot-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Moonshot provider plugin", "type": "module", diff --git a/extensions/msteams/package.json b/extensions/msteams/package.json index a5e283c766f..2f5ade1d98e 100644 --- a/extensions/msteams/package.json +++ b/extensions/msteams/package.json @@ -1,12 +1,12 @@ { "name": "@openclaw/msteams", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Microsoft Teams channel plugin", "type": "module", "dependencies": { "@azure/identity": "^4.13.1", - "@microsoft/teams.api": "2.0.7", - "@microsoft/teams.apps": "2.0.7", + "@microsoft/teams.api": "2.0.8", + "@microsoft/teams.apps": "2.0.8", "@sinclair/typebox": "0.34.49", "express": "^5.2.1", "jsonwebtoken": "^9.0.3", @@ -18,7 +18,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -48,10 +48,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/nextcloud-talk/package.json b/extensions/nextcloud-talk/package.json index 4c41dc2c6f3..53c115fa036 100644 --- a/extensions/nextcloud-talk/package.json +++ b/extensions/nextcloud-talk/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/nextcloud-talk", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Nextcloud Talk channel plugin", "type": "module", "devDependencies": { @@ -8,7 +8,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -40,10 +40,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/nostr/package.json b/extensions/nostr/package.json index a72f0941446..ee5ce39dc5a 100644 --- a/extensions/nostr/package.json +++ b/extensions/nostr/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/nostr", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Nostr channel plugin for NIP-04 encrypted DMs", "type": "module", "dependencies": { @@ -11,7 +11,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -39,10 +39,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "bundle": { "stageRuntimeDependencies": true diff --git a/extensions/nvidia/package.json b/extensions/nvidia/package.json index e26a0d6301a..828a958f6ed 100644 --- a/extensions/nvidia/package.json +++ b/extensions/nvidia/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/nvidia-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw NVIDIA provider plugin", "type": "module", diff --git a/extensions/ollama/package.json b/extensions/ollama/package.json index 376229c8e8c..10a69bdfaa7 100644 --- a/extensions/ollama/package.json +++ b/extensions/ollama/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/ollama-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Ollama provider plugin", "type": "module", diff --git a/extensions/open-prose/package.json b/extensions/open-prose/package.json index 5076bd8cffb..972d0a76df3 100644 --- a/extensions/open-prose/package.json +++ b/extensions/open-prose/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/open-prose", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenProse VM skill pack plugin (slash command + telemetry).", "type": "module", diff --git a/extensions/openai/package.json b/extensions/openai/package.json index ab185acdbf8..0e651c57b3b 100644 --- a/extensions/openai/package.json +++ b/extensions/openai/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/openai-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw OpenAI provider plugins", "type": "module", diff --git a/extensions/opencode-go/package.json b/extensions/opencode-go/package.json index c73adcea9f2..6db34878f74 100644 --- a/extensions/opencode-go/package.json +++ b/extensions/opencode-go/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/opencode-go-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw OpenCode Go provider plugin", "type": "module", diff --git a/extensions/opencode/package.json b/extensions/opencode/package.json index a0673e2046f..2ee15e8526f 100644 --- a/extensions/opencode/package.json +++ b/extensions/opencode/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/opencode-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw OpenCode Zen provider plugin", "type": "module", diff --git a/extensions/openrouter/package.json b/extensions/openrouter/package.json index b0a4c82382e..728507b4de1 100644 --- a/extensions/openrouter/package.json +++ b/extensions/openrouter/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/openrouter-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw OpenRouter provider plugin", "type": "module", diff --git a/extensions/openshell/package.json b/extensions/openshell/package.json index a5fb817b606..7b204165eaa 100644 --- a/extensions/openshell/package.json +++ b/extensions/openshell/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/openshell-sandbox", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw OpenShell sandbox backend", "type": "module", diff --git a/extensions/perplexity/package.json b/extensions/perplexity/package.json index 97494dafa41..c01a23d6ffa 100644 --- a/extensions/perplexity/package.json +++ b/extensions/perplexity/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/perplexity-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Perplexity plugin", "type": "module", diff --git a/extensions/qa-channel/package.json b/extensions/qa-channel/package.json index f32bd9a4fff..554701b4b08 100644 --- a/extensions/qa-channel/package.json +++ b/extensions/qa-channel/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/qa-channel", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw QA synthetic channel plugin", "type": "module", @@ -9,7 +9,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/qa-lab/package.json b/extensions/qa-lab/package.json index 49f196ef20b..e921a23d1b3 100644 --- a/extensions/qa-lab/package.json +++ b/extensions/qa-lab/package.json @@ -1,11 +1,11 @@ { "name": "@openclaw/qa-lab", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw QA lab plugin with private debugger UI and scenario runner", "type": "module", "dependencies": { - "@copilotkit/aimock": "1.14.0", + "@copilotkit/aimock": "1.14.3", "playwright-core": "1.59.1" }, "devDependencies": { @@ -13,7 +13,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -30,7 +30,7 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" } } } diff --git a/extensions/qa-matrix/package.json b/extensions/qa-matrix/package.json index b1dc8048202..098e5771453 100644 --- a/extensions/qa-matrix/package.json +++ b/extensions/qa-matrix/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/qa-matrix", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Matrix QA runner plugin", "type": "module", @@ -10,7 +10,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -22,7 +22,7 @@ "./index.ts" ], "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" } } } diff --git a/extensions/qianfan/package.json b/extensions/qianfan/package.json index fd5291a68c8..81f18adcd7e 100644 --- a/extensions/qianfan/package.json +++ b/extensions/qianfan/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/qianfan-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Qianfan provider plugin", "type": "module", diff --git a/extensions/qqbot/package.json b/extensions/qqbot/package.json index 8c6093d2d35..4fa8d614671 100644 --- a/extensions/qqbot/package.json +++ b/extensions/qqbot/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/qqbot", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": false, "description": "OpenClaw QQ Bot channel plugin", "type": "module", @@ -15,7 +15,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -44,10 +44,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "bundle": { "stageRuntimeDependencies": true diff --git a/extensions/qwen/package.json b/extensions/qwen/package.json index 6205972e5d1..435ef3f9305 100644 --- a/extensions/qwen/package.json +++ b/extensions/qwen/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/qwen-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Qwen Cloud provider plugin", "type": "module", diff --git a/extensions/runway/package.json b/extensions/runway/package.json index 959cc0b0350..a67737831bc 100644 --- a/extensions/runway/package.json +++ b/extensions/runway/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/runway-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Runway video provider plugin", "type": "module", diff --git a/extensions/searxng/package.json b/extensions/searxng/package.json index 4927c044edd..e42aa1be883 100644 --- a/extensions/searxng/package.json +++ b/extensions/searxng/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/searxng-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw SearXNG plugin", "type": "module", diff --git a/extensions/sglang/package.json b/extensions/sglang/package.json index bd70badefa5..e881173cca4 100644 --- a/extensions/sglang/package.json +++ b/extensions/sglang/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/sglang-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw SGLang provider plugin", "type": "module", diff --git a/extensions/signal/package.json b/extensions/signal/package.json index f9f8dd2a856..3d3cce0f756 100644 --- a/extensions/signal/package.json +++ b/extensions/signal/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/signal", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Signal channel plugin", "type": "module", diff --git a/extensions/slack/package.json b/extensions/slack/package.json index 8bacfe530b6..6a0b9919578 100644 --- a/extensions/slack/package.json +++ b/extensions/slack/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/slack", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Slack channel plugin", "type": "module", diff --git a/extensions/speech-core/package.json b/extensions/speech-core/package.json index 561c744e4ae..7d2cc05f1cd 100644 --- a/extensions/speech-core/package.json +++ b/extensions/speech-core/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/speech-core", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw speech runtime package", "type": "module", diff --git a/extensions/stepfun/package.json b/extensions/stepfun/package.json index cfd3a4da4a2..12e44110a9f 100644 --- a/extensions/stepfun/package.json +++ b/extensions/stepfun/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/stepfun-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw StepFun provider plugin", "type": "module", diff --git a/extensions/synology-chat/package.json b/extensions/synology-chat/package.json index 32708002ca9..1f0d678df22 100644 --- a/extensions/synology-chat/package.json +++ b/extensions/synology-chat/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/synology-chat", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "Synology Chat channel plugin for OpenClaw", "type": "module", "devDependencies": { diff --git a/extensions/synthetic/package.json b/extensions/synthetic/package.json index 750f34d9ed0..e12d20949a6 100644 --- a/extensions/synthetic/package.json +++ b/extensions/synthetic/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/synthetic-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Synthetic provider plugin", "type": "module", diff --git a/extensions/tavily/package.json b/extensions/tavily/package.json index 3e3d77a9d51..55dbae0b459 100644 --- a/extensions/tavily/package.json +++ b/extensions/tavily/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/tavily-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Tavily plugin", "type": "module", diff --git a/extensions/telegram/package.json b/extensions/telegram/package.json index e9f8765ee2a..3fbd3fb0636 100644 --- a/extensions/telegram/package.json +++ b/extensions/telegram/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/telegram", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Telegram channel plugin", "type": "module", diff --git a/extensions/tlon/package.json b/extensions/tlon/package.json index 822d39c049c..cad08ba5d62 100644 --- a/extensions/tlon/package.json +++ b/extensions/tlon/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/tlon", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Tlon/Urbit channel plugin", "type": "module", "dependencies": { @@ -14,7 +14,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { diff --git a/extensions/together/package.json b/extensions/together/package.json index 5fbf8533338..cdf12945486 100644 --- a/extensions/together/package.json +++ b/extensions/together/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/together-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Together provider plugin", "type": "module", diff --git a/extensions/twitch/package.json b/extensions/twitch/package.json index 7affa2c58a5..bc2259c0460 100644 --- a/extensions/twitch/package.json +++ b/extensions/twitch/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/twitch", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Twitch channel plugin", "type": "module", "dependencies": { diff --git a/extensions/venice/package.json b/extensions/venice/package.json index 9432b0364a3..6c6d346c072 100644 --- a/extensions/venice/package.json +++ b/extensions/venice/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/venice-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Venice provider plugin", "type": "module", diff --git a/extensions/vercel-ai-gateway/package.json b/extensions/vercel-ai-gateway/package.json index 5af68108d60..856f6c2af65 100644 --- a/extensions/vercel-ai-gateway/package.json +++ b/extensions/vercel-ai-gateway/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/vercel-ai-gateway-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Vercel AI Gateway provider plugin", "type": "module", diff --git a/extensions/video-generation-core/package.json b/extensions/video-generation-core/package.json index efcc059c51f..e4e47c21b7d 100644 --- a/extensions/video-generation-core/package.json +++ b/extensions/video-generation-core/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/video-generation-core", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw video generation runtime package", "type": "module", diff --git a/extensions/vllm/package.json b/extensions/vllm/package.json index 9f41cbb6b6b..41fb82d3728 100644 --- a/extensions/vllm/package.json +++ b/extensions/vllm/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/vllm-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw vLLM provider plugin", "type": "module", diff --git a/extensions/voice-call/package.json b/extensions/voice-call/package.json index 4630096e9c0..75434671084 100644 --- a/extensions/voice-call/package.json +++ b/extensions/voice-call/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/voice-call", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw voice-call plugin", "type": "module", "dependencies": { @@ -13,7 +13,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -28,10 +28,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/volcengine/package.json b/extensions/volcengine/package.json index c6094dbf5b8..040bd02580b 100644 --- a/extensions/volcengine/package.json +++ b/extensions/volcengine/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/volcengine-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Volcengine provider plugin", "type": "module", diff --git a/extensions/voyage/package.json b/extensions/voyage/package.json index 52bb99a71b7..142590bdb6e 100644 --- a/extensions/voyage/package.json +++ b/extensions/voyage/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/voyage-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Voyage embedding provider plugin", "type": "module", diff --git a/extensions/vydra/package.json b/extensions/vydra/package.json index cfbea9d6752..f3bfd05e549 100644 --- a/extensions/vydra/package.json +++ b/extensions/vydra/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/vydra-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Vydra media provider plugin", "type": "module", diff --git a/extensions/webhooks/package.json b/extensions/webhooks/package.json index 785d605f1bd..3d21b93b745 100644 --- a/extensions/webhooks/package.json +++ b/extensions/webhooks/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/webhooks", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw webhook bridge plugin", "type": "module", diff --git a/extensions/whatsapp/package.json b/extensions/whatsapp/package.json index 1a54649bc46..876605bf410 100644 --- a/extensions/whatsapp/package.json +++ b/extensions/whatsapp/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/whatsapp", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw WhatsApp channel plugin", "type": "module", "dependencies": { @@ -13,7 +13,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -49,13 +49,13 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "bundle": { "stageRuntimeDependencies": true }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/xai/package.json b/extensions/xai/package.json index 815bdba82dc..299b67d1c59 100644 --- a/extensions/xai/package.json +++ b/extensions/xai/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/xai-plugin", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw xAI plugin", "type": "module", diff --git a/extensions/xiaomi/package.json b/extensions/xiaomi/package.json index 3919e2a7ba5..04f35469beb 100644 --- a/extensions/xiaomi/package.json +++ b/extensions/xiaomi/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/xiaomi-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Xiaomi provider plugin", "type": "module", diff --git a/extensions/zai/package.json b/extensions/zai/package.json index ce907e86e8a..57d4052b90d 100644 --- a/extensions/zai/package.json +++ b/extensions/zai/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/zai-provider", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "private": true, "description": "OpenClaw Z.AI provider plugin", "type": "module", diff --git a/extensions/zalo/package.json b/extensions/zalo/package.json index 67be195fcf4..3c92dc587ea 100644 --- a/extensions/zalo/package.json +++ b/extensions/zalo/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/zalo", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Zalo channel plugin", "type": "module", "dependencies": { @@ -11,7 +11,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -42,10 +42,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/extensions/zalouser/package.json b/extensions/zalouser/package.json index 91f1cab6c48..dee50e2d8b4 100644 --- a/extensions/zalouser/package.json +++ b/extensions/zalouser/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/zalouser", - "version": "2026.4.19-beta.1", + "version": "2026.4.20", "description": "OpenClaw Zalo Personal Account plugin via native zca-js integration", "type": "module", "dependencies": { @@ -12,7 +12,7 @@ "openclaw": "workspace:*" }, "peerDependencies": { - "openclaw": ">=2026.4.19-beta.1" + "openclaw": ">=2026.4.20" }, "peerDependenciesMeta": { "openclaw": { @@ -43,10 +43,10 @@ "minHostVersion": ">=2026.4.10" }, "compat": { - "pluginApi": ">=2026.4.19-beta.1" + "pluginApi": ">=2026.4.20" }, "build": { - "openclawVersion": "2026.4.19-beta.1" + "openclawVersion": "2026.4.20" }, "release": { "publishToClawHub": true, diff --git a/package.json b/package.json index c2bfe797091..4110e2dab2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openclaw", - "version": "2026.4.19-beta.2", + "version": "2026.4.20", "description": "Multi-channel AI gateway with extensible messaging integrations", "keywords": [], "homepage": "https://github.com/openclaw/openclaw#readme", @@ -1236,7 +1236,8 @@ "canon:check:json": "node scripts/canon.mjs check --json", "canon:enforce": "node scripts/canon.mjs enforce --json", "canvas:a2ui:bundle": "node scripts/bundle-a2ui.mjs", - "check": "pnpm check:no-conflict-markers && pnpm tool-display:check && pnpm check:host-env-policy:swift && pnpm tsgo:all && pnpm lint && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope && pnpm check:import-cycles && pnpm check:madge-import-cycles", + "check": "pnpm check:no-conflict-markers && pnpm tool-display:check && pnpm check:host-env-policy:swift && pnpm tsgo:all && pnpm lint && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope && pnpm check:import-cycles", + "check:architecture": "pnpm check:import-cycles && pnpm check:madge-import-cycles", "check:base-config-schema": "node --import tsx scripts/generate-base-config-schema.ts --check", "check:bundled-channel-config-metadata": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --check", "check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-i18n-glossary && pnpm docs:check-links", @@ -1246,6 +1247,8 @@ "check:madge-import-cycles": "node --import tsx scripts/check-madge-import-cycles.ts", "check:no-conflict-markers": "node scripts/check-no-conflict-markers.mjs", "check:static-import-sccs": "pnpm check:madge-import-cycles", + "check:timed": "node scripts/check-timed.mjs", + "check:timed:architecture": "node scripts/check-timed.mjs --include-architecture", "codex-app-server:protocol:check": "node --import tsx scripts/check-codex-app-server-protocol.ts", "config:channels:check": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --check", "config:channels:gen": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --write", @@ -1471,10 +1474,12 @@ "tool-display:write": "node --import tsx scripts/tool-display.ts --write", "ts-topology": "node --import tsx scripts/ts-topology.ts", "tsgo": "pnpm tsgo:core", - "tsgo:all": "pnpm tsgo:core && pnpm tsgo:core:test && pnpm tsgo:extensions && pnpm tsgo:extensions:test", + "tsgo:all": "node scripts/run-tsgo.mjs -b tsconfig.projects.json", "tsgo:core": "node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo", + "tsgo:core:all": "node scripts/run-tsgo.mjs -b tsconfig.core.projects.json", "tsgo:core:test": "node scripts/run-tsgo.mjs -p tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo", "tsgo:extensions": "node scripts/run-tsgo.mjs -p tsconfig.extensions.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions.tsbuildinfo", + "tsgo:extensions:all": "node scripts/run-tsgo.mjs -b tsconfig.extensions.projects.json", "tsgo:extensions:test": "node scripts/run-tsgo.mjs -p tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo", "tsgo:prod": "pnpm tsgo:core && pnpm tsgo:extensions", "tsgo:profile": "node scripts/profile-tsgo.mjs", @@ -1511,7 +1516,7 @@ "@mariozechner/pi-ai": "0.67.68", "@mariozechner/pi-coding-agent": "0.67.68", "@mariozechner/pi-tui": "0.67.68", - "@matrix-org/matrix-sdk-crypto-wasm": "18.0.0", + "@matrix-org/matrix-sdk-crypto-wasm": "18.1.0", "@modelcontextprotocol/sdk": "1.29.0", "@mozilla/readability": "^0.6.0", "@pierre/diffs": "1.1.15", @@ -1562,7 +1567,7 @@ "zod": "^4.3.6" }, "devDependencies": { - "@copilotkit/aimock": "1.14.0", + "@copilotkit/aimock": "1.14.3", "@grammyjs/types": "^3.26.0", "@lit-labs/signals": "^0.2.0", "@lit/context": "^1.1.6", @@ -1584,7 +1589,7 @@ "signal-utils": "0.21.1", "tsdown": "0.21.9", "tsx": "^4.21.0", - "typescript": "^6.0.2", + "typescript": "^6.0.3", "vitest": "^4.1.4" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a57af5e72b4..bd144d9b170 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,8 +96,8 @@ importers: specifier: 0.67.68 version: 0.67.68 '@matrix-org/matrix-sdk-crypto-wasm': - specifier: 18.0.0 - version: 18.0.0 + specifier: 18.1.0 + version: 18.1.0 '@modelcontextprotocol/sdk': specifier: 1.29.0 version: 1.29.0(zod@4.3.6) @@ -199,7 +199,7 @@ importers: version: 3.18.1(typescript@6.0.2) nostr-tools: specifier: ^2.23.3 - version: 2.23.3(typescript@6.0.2) + version: 2.23.3(typescript@6.0.3) openai: specifier: ^6.34.0 version: 6.34.0(ws@8.20.0)(zod@4.3.6) @@ -250,8 +250,8 @@ importers: version: 4.3.6 devDependencies: '@copilotkit/aimock': - specifier: 1.14.0 - version: 1.14.0 + specifier: 1.14.3 + version: 1.14.3 '@grammyjs/types': specifier: ^3.26.0 version: 3.26.0 @@ -293,7 +293,7 @@ importers: version: 3.3.2 madge: specifier: ^8.0.0 - version: 8.0.0(typescript@6.0.2) + version: 8.0.0(typescript@6.0.3) oxfmt: specifier: 0.45.0 version: 0.45.0 @@ -311,13 +311,13 @@ importers: version: 0.21.1(signal-polyfill@0.2.2) tsdown: specifier: 0.21.9 - version: 0.21.9(@typescript/native-preview@7.0.0-dev.20260418.1)(typescript@6.0.2) + version: 0.21.9(@typescript/native-preview@7.0.0-dev.20260418.1)(typescript@6.0.3) tsx: specifier: ^4.21.0 version: 4.21.0 typescript: - specifier: ^6.0.2 - version: 6.0.2 + specifier: ^6.0.3 + version: 6.0.3 vitest: specifier: ^4.1.4 version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -480,32 +480,32 @@ importers: specifier: ^1.9.1 version: 1.9.1 '@opentelemetry/api-logs': - specifier: ^0.214.0 - version: 0.214.0 + specifier: ^0.215.0 + version: 0.215.0 '@opentelemetry/exporter-logs-otlp-proto': - specifier: ^0.214.0 - version: 0.214.0(@opentelemetry/api@1.9.1) + specifier: ^0.215.0 + version: 0.215.0(@opentelemetry/api@1.9.1) '@opentelemetry/exporter-metrics-otlp-proto': - specifier: ^0.214.0 - version: 0.214.0(@opentelemetry/api@1.9.1) + specifier: ^0.215.0 + version: 0.215.0(@opentelemetry/api@1.9.1) '@opentelemetry/exporter-trace-otlp-proto': - specifier: ^0.214.0 - version: 0.214.0(@opentelemetry/api@1.9.1) + specifier: ^0.215.0 + version: 0.215.0(@opentelemetry/api@1.9.1) '@opentelemetry/resources': - specifier: ^2.6.1 - version: 2.6.1(@opentelemetry/api@1.9.1) + specifier: ^2.7.0 + version: 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-logs': - specifier: ^0.214.0 - version: 0.214.0(@opentelemetry/api@1.9.1) + specifier: ^0.215.0 + version: 0.215.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-metrics': - specifier: ^2.6.1 - version: 2.6.1(@opentelemetry/api@1.9.1) + specifier: ^2.7.0 + version: 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-node': - specifier: ^0.214.0 - version: 0.214.0(@opentelemetry/api@1.9.1) + specifier: ^0.215.0 + version: 0.215.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': - specifier: ^2.6.1 - version: 2.6.1(@opentelemetry/api@1.9.1) + specifier: ^2.7.0 + version: 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': specifier: ^1.40.0 version: 1.40.0 @@ -744,8 +744,8 @@ importers: specifier: ^0.4.0 version: 0.4.0 '@matrix-org/matrix-sdk-crypto-wasm': - specifier: 18.0.0 - version: 18.0.0 + specifier: 18.1.0 + version: 18.1.0 fake-indexeddb: specifier: ^6.2.5 version: 6.2.5 @@ -866,11 +866,11 @@ importers: specifier: ^4.13.1 version: 4.13.1 '@microsoft/teams.api': - specifier: 2.0.7 - version: 2.0.7 + specifier: 2.0.8 + version: 2.0.8 '@microsoft/teams.apps': - specifier: 2.0.7 - version: 2.0.7 + specifier: 2.0.8 + version: 2.0.8 '@sinclair/typebox': specifier: 0.34.49 version: 0.34.49 @@ -907,7 +907,7 @@ importers: dependencies: nostr-tools: specifier: ^2.23.3 - version: 2.23.3(typescript@6.0.2) + version: 2.23.3(typescript@6.0.3) devDependencies: '@openclaw/plugin-sdk': specifier: workspace:* @@ -990,8 +990,8 @@ importers: extensions/qa-lab: dependencies: '@copilotkit/aimock': - specifier: 1.14.0 - version: 1.14.0 + specifier: 1.14.3 + version: 1.14.3 playwright-core: specifier: 1.59.1 version: 1.59.1 @@ -1343,8 +1343,8 @@ importers: specifier: ^2.1.1 version: 2.1.1 marked: - specifier: ^18.0.0 - version: 18.0.0 + specifier: ^18.0.1 + version: 18.0.1 devDependencies: '@types/markdown-it': specifier: ^14.1.2 @@ -1393,8 +1393,8 @@ packages: resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@asamuzakjp/dom-selector@7.0.10': - resolution: {integrity: sha512-KyOb19eytNSELkmdqzZZUXWCU25byIlOld5qVFg0RYdS0T3tt7jeDByxk9hIAC73frclD8GKrHttr0SUjKCCdQ==} + '@asamuzakjp/dom-selector@7.1.0': + resolution: {integrity: sha512-ASf825+5vsGuYWoyFyNsex2mNtPTXpCvYTR942+w/eNw7PqS0Lhl/PE1hC7bajneI3m/Oxi+yrP3vTOPxfwM8A==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} '@asamuzakjp/generational-cache@1.0.1': @@ -1435,18 +1435,14 @@ packages: resolution: {integrity: sha512-r8SoLJ0RyGUaNqRMMCr7X4Y9atZtcyWsK4b7HkJZm4IFHJm3AVtTOZrc/xLAmhjy9peOoNCMcRPBmBjfEiHgiw==} engines: {node: '>=20.0.0'} - '@aws-sdk/client-cognito-identity@3.1030.0': - resolution: {integrity: sha512-PD9RIT5eJEXsP+Dq8fncTXOFAOI+EP3fRa/z1te2xehAVawixEpAJkjEE03A4msqPWGJ2S0TM2bb6zDbP66w3g==} + '@aws-sdk/client-cognito-identity@3.1032.0': + resolution: {integrity: sha512-TVgbjyb1fJoHZDoBAmW85hNcx00zxi5qXFG3wvS/2C213Q2PusCQIih7Zlub9mKE3iRtES5epxazFmp8jVeLyQ==} engines: {node: '>=20.0.0'} '@aws-sdk/client-s3@3.1032.0': resolution: {integrity: sha512-A1wjVhV3IgsZ5td2l4AWgK03EjZ+ldwbiorxuO1hPf7RHJtSdr6oq/gKzyUwP7Tm7ma/M2xS/tplg5C8XB8RWg==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.973.27': - resolution: {integrity: sha512-CUZ5m8hwMCH6OYI4Li/WgMfIEx10Q2PLI9Y3XOUTPGZJ53aZ0007jCv+X/ywsaERyKPdw5MRZWk877roQksQ4A==} - engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.974.1': resolution: {integrity: sha512-gy/gffKz0zaHDaqRiLCdIvgHmaAL/HXuAtMcBP7euYSFx4BsbsdlfmUBJag+Gqe62z6/XuloKyQyaiH+kS3Vrg==} engines: {node: '>=20.0.0'} @@ -1455,38 +1451,22 @@ packages: resolution: {integrity: sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-cognito-identity@3.972.22': - resolution: {integrity: sha512-ih6ORpme4i2qJqGckOQ9Lt2iiZ+5tm3bnfsT5TwoPyFnuDURXv3OdhYa3Nr/m0iJr38biqKYKdGKb5GR1KB2hw==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/credential-provider-env@3.972.25': - resolution: {integrity: sha512-6QfI0wv4jpG5CrdO/AO0JfZ2ux+tKwJPrUwmvxXF50vI5KIypKVGNF6b4vlkYEnKumDTI1NX2zUBi8JoU5QU3A==} + '@aws-sdk/credential-provider-cognito-identity@3.972.24': + resolution: {integrity: sha512-i6eMWlKfgQkNY3S/kg1ZnBZm2lhd6r8B3yobCalvrfCCGjvthREwsyDViuWl7gOWSvuUjQEFFGcJhGbCstcqJg==} engines: {node: '>=20.0.0'} '@aws-sdk/credential-provider-env@3.972.27': resolution: {integrity: sha512-xfUt2CUZDC+Tf16A6roD1b4pk/nrXdkoLY3TEhv198AXDtBo5xUJP1zd0e8SmuKLN4PpIBX96OizZbmMlcI6oQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.27': - resolution: {integrity: sha512-3V3Usj9Gs93h865DqN4M2NWJhC5kXU9BvZskfN3+69omuYlE3TZxOEcVQtBGLOloJB7BVfJKXVLqeNhOzHqSlQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.29': resolution: {integrity: sha512-hjNeYb6oLyHgMihra83ie0J/T2y9om3cy1qC90h9DRgvYXEoN4BCFf8bHguZjKhXunnv7YkmZRuYL5Mkk77eCA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.29': - resolution: {integrity: sha512-SiBuAnXecCbT/OpAf3vqyI/AVE3mTaYr9ShXLybxZiPLBiPCCOIWSGAtYYGQWMRvobBTiqOewaB+wcgMMZI2Aw==} - engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.31': resolution: {integrity: sha512-PuQ7e8WYzAPpzvFcajxf8c0LqSzakVHVlKw8M0oubk8Kf347YOCCqT1seQrHs5AdZuIh2RD9LX4O+Xa5ImEBfQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.29': - resolution: {integrity: sha512-OGOslTbOlxXexKMqhxCEbBQbUIfuhGxU5UXw3Fm56ypXHvrXH4aTt/xb5Y884LOoteP1QST1lVZzHfcTnWhiPQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.31': resolution: {integrity: sha512-bBmWDmtSpmLOZR6a0kmowBcVL1hiL8Vlap/RXeMpFd7JbWl87YcwqL6T9LH/0oBVEZXu1dUZAtojgSuZgMO5xw==} engines: {node: '>=20.0.0'} @@ -1495,32 +1475,20 @@ packages: resolution: {integrity: sha512-9aj0x9hGYUondBZSD0XkksAdHhOKttFw4BWpLCeggeg40qSJxGrAP++g0GCm0VqWc1WtC/NRFiAVzPCy56vmog==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.25': - resolution: {integrity: sha512-HR7ynNRdNhNsdVCOCegy1HsfsRzozCOPtD3RzzT1JouuaHobWyRfJzCBue/3jP7gECHt+kQyZUvwg/cYLWurNQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.27': resolution: {integrity: sha512-1CZvfb1WzudWWIFAVQkd1OI/T1RxPcSvNWzNsb2BMBVsBJzBtB8dV5f2nymHVU4UqwxipdVt/DAbgdDRf33JDg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.29': - resolution: {integrity: sha512-HWv4SEq3jZDYPlwryZVef97+U8CxxRos5mK8sgGO1dQaFZpV5giZLzqGE5hkDmh2csYcBO2uf5XHjPTpZcJlig==} - engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.31': resolution: {integrity: sha512-x8Mx18S48XMl9bEEpYwmXDTvjWGPIfDadReN37Lc099/DUrlL4Zs9T9rwwggo6DkKS1aev6v+MTUx7JTa87TZQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.29': - resolution: {integrity: sha512-PdMBza1WEKEUPFEmMGCfnU2RYCz9MskU2e8JxjyUOsMKku7j9YaDKvbDi2dzC0ihFoM6ods2SbhfAAro+Gwlew==} - engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.31': resolution: {integrity: sha512-zfuNMIkGfjYsHis9qytYf74Bcmq6Ji9Xwf4w53baRCI/b2otTwZv3SW1uRiJ5Di7999QzRGhHZ96+eUeo3gSOA==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-providers@3.1030.0': - resolution: {integrity: sha512-hQhRax7MzsG40mc6Es2Muvfai+jfWt1j1odqP4UQtUok6Fu4qbJNRGgQ/EAi7Sb6VAL0EdY5JGGMevHz2oO+AA==} + '@aws-sdk/credential-providers@3.1032.0': + resolution: {integrity: sha512-OT+4/Kf62PKslLoJJGEzpQricgaMOuXFNf65FR56i3QugNLlNHfkhDWkk1CDvN1NYCHZbYZMJusdGjxVxQKgjQ==} engines: {node: '>=20.0.0'} '@aws-sdk/eventstream-handler-node@3.972.14': @@ -1547,10 +1515,6 @@ packages: resolution: {integrity: sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-host-header@3.972.9': - resolution: {integrity: sha512-je5vRdNw4SkuTnmRbFZLdye4sQ0faLt8kwka5wnnSU30q1mHO4X+idGEJOOE+Tn1ME7Oryn05xxkDvIb3UaLaQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-location-constraint@3.972.10': resolution: {integrity: sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ==} engines: {node: '>=20.0.0'} @@ -1559,14 +1523,6 @@ packages: resolution: {integrity: sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-logger@3.972.9': - resolution: {integrity: sha512-HsVgDrruhqI28RkaXALm8grJ7Agc1wF6Et0xh6pom8NdO2VdO/SD9U/tPwUjewwK/pVoka+EShBxyCvgsPCtog==} - engines: {node: '>=20.0.0'} - - '@aws-sdk/middleware-recursion-detection@3.972.10': - resolution: {integrity: sha512-RVQQbq5orQ/GHUnXvqEOj2HHPBJm+mM+ySwZKS5UaLBwra5ugRtiH09PLUoOZRl7a1YzaOzXSuGbn9iD5j60WQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-recursion-detection@3.972.11': resolution: {integrity: sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==} engines: {node: '>=20.0.0'} @@ -1579,10 +1535,6 @@ packages: resolution: {integrity: sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.29': - resolution: {integrity: sha512-f/sIRzuTfEjg6NsbMYvye2VsmnQoNgntntleQyx5uGacUYzszbfIlO3GcI6G6daWUmTm0IDZc11qMHWwF0o0mQ==} - engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.31': resolution: {integrity: sha512-L+hXN2HDomlIsWSHW5DVD7ppccCeRnlHXZ5uHG34ePTjF5bm0I1fmrJLbUGiW97xRXWryit5cjdP4Sx2FwiGog==} engines: {node: '>=20.0.0'} @@ -1591,18 +1543,10 @@ packages: resolution: {integrity: sha512-86+S9oCyRVGzoMRpQhxkArp7kD2K75GPmaNevd9B6EyNhWoNvnCZZ3WbgN4j7ZT+jvtvBCGZvI2XHsWZJ+BRIg==} engines: {node: '>= 14.0.0'} - '@aws-sdk/nested-clients@3.996.19': - resolution: {integrity: sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q==} - engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.996.21': resolution: {integrity: sha512-Me3d/ua2lb2G0bQfFmvCeQQp3+nN6GSPqMxDmi/IQlQ8CrlpQ5C0JJHpz2AnOUkEFI0lBNrAL3Vnt29l44ndkA==} engines: {node: '>=20.0.0'} - '@aws-sdk/region-config-resolver@3.972.11': - resolution: {integrity: sha512-6Q8B1dcx6BBqUTY1Mc/eROKA0FImEEY5VPSd6AGPEUf0ErjExz4snVqa9kNJSoVDV1rKaNf3qrWojgcKW+SdDg==} - engines: {node: '>=20.0.0'} - '@aws-sdk/region-config-resolver@3.972.12': resolution: {integrity: sha512-QQI43Mxd53nBij0pm8HXC+t4IOC6gnhhZfzxE0OATQyO6QfPV4e+aTIRRuAJKA6Nig/cR8eLwPryqYTX9ZrjAQ==} engines: {node: '>=20.0.0'} @@ -1615,18 +1559,10 @@ packages: resolution: {integrity: sha512-4KT8UXRmvNAP5zKq9UI1MIwbnmSChZncBt89RKu/skMqZSSWGkBZTAJsZ+no+txfmF3kVaUFv31CTBZkQ5BJpQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1026.0': - resolution: {integrity: sha512-Ieq/HiRrbEtrYP387Nes0XlR7H1pJiJOZKv+QyQzMYpvTiDs0VKy2ZB3E2Zf+aFovWmeE7lRE4lXyF7dYM6GgA==} - engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1032.0': resolution: {integrity: sha512-n+PU8Z+gll7p3wDrH+Wo6fkt8sPrVnq30YYM6Ryga95oJlEneNMEbDHj0iqjMX3V7gaGdJo/hJWyPo4lscP+mA==} engines: {node: '>=20.0.0'} - '@aws-sdk/types@3.973.7': - resolution: {integrity: sha512-reXRwoJ6CfChoqAsBszUYajAF8Z2LRE+CRcKocvFSMpIiLOtYU3aJ9trmn6VVPAzbbY5LXF+FfmUslbXk1SYFg==} - engines: {node: '>=20.0.0'} - '@aws-sdk/types@3.973.8': resolution: {integrity: sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==} engines: {node: '>=20.0.0'} @@ -1635,10 +1571,6 @@ packages: resolution: {integrity: sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.996.6': - resolution: {integrity: sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg==} - engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.996.7': resolution: {integrity: sha512-ty4LQxN1QC+YhUP28NfEgZDEGXkyqOQy+BDriBozqHsrYO4JMgiPhfizqOGF7P+euBTZ5Ez6SKlLAMCLo8tzmw==} engines: {node: '>=20.0.0'} @@ -1647,10 +1579,6 @@ packages: resolution: {integrity: sha512-DEKiHNJVtNxdyTeQspzY+15Po/kHm6sF0Cs4HV9Q2+lplB63+DrvdeiSoOSdWEWAoO2RcY1veoXVDz2tWxWCgQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-format-url@3.972.9': - resolution: {integrity: sha512-fNJXHrs0ZT7Wx0KGIqKv7zLxlDXt2vqjx9z6oKUQFmpE5o4xxnSryvVHfHpIifYHWKz94hFccIldJ0YSZjlCBw==} - engines: {node: '>=20.0.0'} - '@aws-sdk/util-locate-window@3.965.5': resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} engines: {node: '>=20.0.0'} @@ -1658,18 +1586,6 @@ packages: '@aws-sdk/util-user-agent-browser@3.972.10': resolution: {integrity: sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==} - '@aws-sdk/util-user-agent-browser@3.972.9': - resolution: {integrity: sha512-sn/LMzTbGjYqCCF24390WxPd6hkpoSptiUn5DzVp4cD71yqw+yGEGm1YCxyEoPXyc8qciM8UzLJcZBFslxo5Uw==} - - '@aws-sdk/util-user-agent-node@3.973.15': - resolution: {integrity: sha512-fYn3s9PtKdgQkczGZCFMgkNEe8aq1JCVbnRqjqN9RSVW43xn2RV9xdcZ3z01a48Jpkuh/xCmBKJxdLOo4Ozg7w==} - engines: {node: '>=20.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - '@aws-sdk/util-user-agent-node@3.973.17': resolution: {integrity: sha512-utF5qjjbuJQuU9VdCkWl7L87sr93cApsrD+uxGfUnlafX8iyEzJrb7EZnufjThURZVTOtelRMXrblWxpefElUg==} engines: {node: '>=20.0.0'} @@ -1679,10 +1595,6 @@ packages: aws-crt: optional: true - '@aws-sdk/xml-builder@3.972.17': - resolution: {integrity: sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg==} - engines: {node: '>=20.0.0'} - '@aws-sdk/xml-builder@3.972.18': resolution: {integrity: sha512-BMDNVG1ETXRhl1tnisQiYBef3RShJ1kfZA7x7afivTFMLirfHNTb6U71K569HNXhSXbQZsweHvSDZ6euBw8hPA==} engines: {node: '>=20.0.0'} @@ -1727,24 +1639,24 @@ packages: resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} engines: {node: '>=20.0.0'} - '@azure/msal-browser@5.6.3': - resolution: {integrity: sha512-sTjMtUm+bJpENU/1WlRzHEsgEHppZDZ1EtNyaOODg/sQBtMxxJzGB+MOCM+T2Q5Qe1fKBrdxUmjyRxm0r7Ez9w==} + '@azure/msal-browser@5.7.0': + resolution: {integrity: sha512-uYbJ0YarxkVGWEq814BysJry/IPvpDNkVKmc2bMZp4G+igUQkJ5nlFirycwPGUeA9ICLQqCxqExCA1Z1E07bPA==} engines: {node: '>=0.8.0'} '@azure/msal-common@15.17.0': resolution: {integrity: sha512-VQ5/gTLFADkwue+FohVuCqlzFPUq4xSrX8jeZe+iwZuY6moliNC8xt86qPVNYdtbQfELDf2Nu6LI+demFPHGgw==} engines: {node: '>=0.8.0'} - '@azure/msal-common@16.4.1': - resolution: {integrity: sha512-Bl8f+w37xkXsYh7QRkAKCFGYtWMYuOVO7Lv+BxILrvGz3HbIEF22Pt0ugyj0QPOl6NLrHcnNUQ9yeew98P/5iw==} + '@azure/msal-common@16.5.0': + resolution: {integrity: sha512-i3eS/5pmxDbIU/mLMENs88Qg3k6XxqJytJy6PpB7L1tCBjdXHJDadCD3Hu1TyTooe7iQo7CYqbocgL/l/8u90g==} engines: {node: '>=0.8.0'} '@azure/msal-node@3.8.10': resolution: {integrity: sha512-0Hz7Kx4hs70KZWep/Rd7aw/qOLUF92wUOhn7ZsOuB5xNR/06NL1E2RAI9+UKH1FtvN8nD6mFjH7UKSjv6vOWvQ==} engines: {node: '>=16'} - '@azure/msal-node@5.1.2': - resolution: {integrity: sha512-DoeSJ9U5KPAIZoHsPywvfEj2MhBniQe0+FSpjLUTdWoIkI999GB5USkW6nNEHnIaLVxROHXvprWA1KzdS1VQ4A==} + '@azure/msal-node@5.1.3': + resolution: {integrity: sha512-LqT8mRZpEils9zGR9eW+Ljqifh2aMA99UF/X0jxIKDYZeHr6onlHwhVP4xHCeLhh55BI63JCbdf1iWJbMh1mPw==} engines: {node: '>=20'} '@babel/generator@8.0.0-rc.3': @@ -1834,8 +1746,8 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@copilotkit/aimock@1.14.0': - resolution: {integrity: sha512-1NqwWEameArC7HWT7UHBlkq3pNlCA0eHBocaeL6mS5CULolT9XFL27tC9jJ+OSmREzLwkKbFYaAl2SssaXexVA==} + '@copilotkit/aimock@1.14.3': + resolution: {integrity: sha512-8ChHHNi/gdYvATG/6bDY2aoBsZNS7hVtgp6nntqUI21d+A+WoQ7v6Bg6P8oXHknWnzyOq7xt5ytE6irHH1KzVg==} engines: {node: '>=20.15.0'} hasBin: true @@ -2684,28 +2596,28 @@ packages: resolution: {integrity: sha512-+qqgpn39XFSbsD0dFjssGO9vHEP7sTyfs8yTpt8vuqWpUpF20QMwpCZi0jpYw7GxjErNTsMshopuo8677DfGEA==} engines: {node: '>= 22'} - '@matrix-org/matrix-sdk-crypto-wasm@18.0.0': - resolution: {integrity: sha512-88+n+dvxLI1cjS10UIlKXVYK7TGWbpAnnaDC9fow7ch/hCvdu3dFhJ3tS3/13N9s9+1QFXB4FFuommj+tHJPhQ==} + '@matrix-org/matrix-sdk-crypto-wasm@18.1.0': + resolution: {integrity: sha512-GxXK2U39+2qWNvR3fXJY7nxdikvpiT17RaS0/Dktk6R8FMKDk3vm79Hq65yrCWLBmT7pJZoerfILNZqhrcUHrg==} engines: {node: '>= 18'} - '@microsoft/teams.api@2.0.7': - resolution: {integrity: sha512-SQu7d/alQ3ZKgBX2ur/0VbtxsDLMZb3HmGUVnzIWkvSzFkGcPQ8uPK//670gpEyFJVh2qqP0wFwOwH98/tO57w==} + '@microsoft/teams.api@2.0.8': + resolution: {integrity: sha512-N13idaRZNnfL7aefzsn2rhPtujqke1QVM81bNWq1XeK+5yeXod3aLTmBY701DEKkZUXiSG0AogvzkNwVnBw4+g==} engines: {node: '>=20'} - '@microsoft/teams.apps@2.0.7': - resolution: {integrity: sha512-1y7mLrM/HZfRn8tHK/vInMZCpMXjRPQ6QawboNXttJqEQxvlwNRK9nzDjnzuIyBF32oTVt/ro7Id38oNnhaXeQ==} + '@microsoft/teams.apps@2.0.8': + resolution: {integrity: sha512-6YBOxnQSoEPu841zMa1SDBdwH3gsuzrz0LCONuaGOHJ3Kmv2S+7ih1DqEx4Ak3iAYHeCvxnWGqjcYSBhgeiuMQ==} engines: {node: '>=20'} - '@microsoft/teams.cards@2.0.7': - resolution: {integrity: sha512-HUGw5OWKc6eCdinRLYqHgFyvScTplQs+PqUqHnf79wH1QNqAKCX+p7uF71YxTm383laJYOqDGYU6uvFEoTvOsA==} + '@microsoft/teams.cards@2.0.8': + resolution: {integrity: sha512-WrGAgkDKqhvFhnsKPwFeKTkhAXu/fbySxq5+uIOqY1ffdgiEdEoj6c0cjyQJy0HJ9B5u/0SQ4hO2KUc6jlZSZw==} engines: {node: '>=20'} - '@microsoft/teams.common@2.0.7': - resolution: {integrity: sha512-O3qWC/RbLbiJSAHyk1j5Ybx3GAxmM7DhFbfLW5a2sebEQ+Sn/hB/8rr+IsxlG2FAaUgrcKkir8B55wuKTlZPYw==} + '@microsoft/teams.common@2.0.8': + resolution: {integrity: sha512-nkolOYX9qCpfK2uitiuAYm3EvMleHer5P3OCx3IBOp2gxkkFvNNOcOIDXuPZ6BtiENt47FPn4fYMMgJrawCHcA==} engines: {node: '>=20'} - '@microsoft/teams.graph@2.0.7': - resolution: {integrity: sha512-hHX1gsCL7GFhAUz1CAT+PFar5U20/nA6sV4yJJaLygu0Wft10XgX3tJh1FckXBQlO1vCaDRtmcMJ9Eey0Z/wRg==} + '@microsoft/teams.graph@2.0.8': + resolution: {integrity: sha512-M/skUNJFD+lIVNa+ng0iy8t3sFmki6NOiWpGwnWOBAKFgTYBTJVtPfWm6SNdGFTCUsV9rjep4s9S5zTKUg2HJg==} engines: {node: '>=20'} '@mistralai/mistralai@2.2.0': @@ -2731,8 +2643,8 @@ packages: cpu: [arm64] os: [android] - '@napi-rs/canvas-android-arm64@0.1.98': - resolution: {integrity: sha512-O45Ifr0WZJUrSyg0QgB+67TiC0zYBRkBK+d43ZV4JtlwH3XttiVxLvlxEeULiH5y1MSELruspF0bjF6xXwJNPQ==} + '@napi-rs/canvas-android-arm64@0.1.99': + resolution: {integrity: sha512-9OCRt8VVxA17m32NWZKyNC2qamdaS/SC5CEOIQwFngRq0DIeVm4PDal+6Ljnhqm2whZiC63DNuKZ4xSp2nbj9w==} engines: {node: '>= 10'} cpu: [arm64] os: [android] @@ -2743,8 +2655,8 @@ packages: cpu: [arm64] os: [darwin] - '@napi-rs/canvas-darwin-arm64@0.1.98': - resolution: {integrity: sha512-1b/nQhw6Isdv14JokUqat+i5wrAYD+ce3egiotedBGRUjVxYSj4s2uQCh2bFsyX5/9A5iTKVGsWoQhFft+j7Lg==} + '@napi-rs/canvas-darwin-arm64@0.1.99': + resolution: {integrity: sha512-lupMDMy1+H38dhyCcLirOKKVUyzzlxi7j7rGPLI3vViMHOoPjcXO1b10ivy+ad+q6MiwHfoLjKTCoLke5ySOBg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -2755,8 +2667,8 @@ packages: cpu: [x64] os: [darwin] - '@napi-rs/canvas-darwin-x64@0.1.98': - resolution: {integrity: sha512-oefzfBM8mwnyYp6S+yNXwjCoLdkOalFG24mssHgvrJDS0FulOryyI35Q7GdJGmrzuL4oo1XW3ZTOcTBLdJ8Zkg==} + '@napi-rs/canvas-darwin-x64@0.1.99': + resolution: {integrity: sha512-fdz02t4w8n6Ii/rYhWig6STb/zcTmCC/6YZTGmjoDeidDwn9Wf0ukQVynhCPEs29vqUc66wHZKsuIgMs9tycCg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -2767,8 +2679,8 @@ packages: cpu: [arm] os: [linux] - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.98': - resolution: {integrity: sha512-NDH5QXGmf8wlo5yhijCNGVFiJk7an5GvHwb2LHyfLQWY/6/S48i5+YtY6FPqPVVCUckNGudYOfXEJnb3/FiJGQ==} + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.99': + resolution: {integrity: sha512-w4FwVwlNo00ezeRhfY62IVIyt6G3u8wodkPtiqWc52BUHx+VDBUM2vkS3ogfANaLI7hnf3s6WK4LyZVUjBg1lA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] @@ -2780,8 +2692,8 @@ packages: os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-arm64-gnu@0.1.98': - resolution: {integrity: sha512-KBLLM6tu1xs80LSAqdSLBKkgct0S23MCEf/aq8yxzg5imAceqp1ulKeELgWaYm27MgpUhm3Q7jmegX12FfphwA==} + '@napi-rs/canvas-linux-arm64-gnu@0.1.99': + resolution: {integrity: sha512-8JvHeexKQ8c7g0q7YJ29NVQwnf1ePghP9ys9ZN0R0qzyqJQ9Uw6N9qnDINArlm3IYHexB7LjzArIfhQiqSDGvQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2794,8 +2706,8 @@ packages: os: [linux] libc: [musl] - '@napi-rs/canvas-linux-arm64-musl@0.1.98': - resolution: {integrity: sha512-mfMNhjN5zDcJafqQ6sHj4Tc3YMTRxP5UA3MHtp/ssytBR/k6XO0x+1IIPtscnUKwha+ql1++WjDCGEgqu8OfWQ==} + '@napi-rs/canvas-linux-arm64-musl@0.1.99': + resolution: {integrity: sha512-Z+6nyLdJXWzLPVxi4H6g9TJop4DwN3KSgHWto5JCbZV5/uKoVqcSynPs0tGlUHOoWI8S8tEvJspz51GQkvr07w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2808,8 +2720,8 @@ packages: os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-riscv64-gnu@0.1.98': - resolution: {integrity: sha512-nfW8esrcaeuhrO3qGA5cwuyk4Ak6cn2eB0LtEYtqROIl+fz06CNGNCU0M95+Tspw5ZgfSbc98SaigT5r5B3LVQ==} + '@napi-rs/canvas-linux-riscv64-gnu@0.1.99': + resolution: {integrity: sha512-jAnfOUv4IO1l8Levk5t85oVtEBOXLa07KnIUgWo1CDlPxiqpxS3uBfiE38Lvj/CQgHaNF6Nxk/SaemwLgsVJgw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] @@ -2822,8 +2734,8 @@ packages: os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-gnu@0.1.98': - resolution: {integrity: sha512-318UT8j6Gro2bTjtutjQXHWp9SLTNw+WRS4wQ6XIRPAyzBGnGHg7x2ndD+oqkPrrSRIbYLA5WoBcCasaF7lSTQ==} + '@napi-rs/canvas-linux-x64-gnu@0.1.99': + resolution: {integrity: sha512-mIkXw3fGmbYyFjSmfWEvty4jN+rwEOmv0+Dy9bRvvTzLYWCgm3RMgUEQVfAKFw96nIRFnyNZiK83KNQaVVFjng==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2836,8 +2748,8 @@ packages: os: [linux] libc: [musl] - '@napi-rs/canvas-linux-x64-musl@0.1.98': - resolution: {integrity: sha512-0vZhI74UxnA4VqlW4UvM0dFRrjE1RLEe/OXSBjzytGIxV+yOG4exlrhGoIpAQaIpQQQXMCdb1EmbvPC1k9vEqQ==} + '@napi-rs/canvas-linux-x64-musl@0.1.99': + resolution: {integrity: sha512-f3Uz2P0RgrtBHISxZqr6yiYXJlTDyCVBumDacxo+4AmSg7z0HiqYZKGWC/gszq3fbPhyQUya1W2AEteKxT9Y6A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2849,8 +2761,8 @@ packages: cpu: [arm64] os: [win32] - '@napi-rs/canvas-win32-arm64-msvc@0.1.98': - resolution: {integrity: sha512-oiC/IxgFEEVcZ7VH7JXXlmgsqRvmFb57PIQ4gQck35IKFZCNUvdNCcN3OeoLP7Hpf5160MWJf9jj/+E5V0bSvw==} + '@napi-rs/canvas-win32-arm64-msvc@0.1.99': + resolution: {integrity: sha512-XE6KUkfqRsCNejcoRMiMr3RaUeObxNf6y7dut3hrq2rn7PzfRTZgrjF1F/B2C7FcdgqY/vSHWpQeMuNz1vTNHg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -2861,8 +2773,8 @@ packages: cpu: [x64] os: [win32] - '@napi-rs/canvas-win32-x64-msvc@0.1.98': - resolution: {integrity: sha512-ZqstKAJBSyZetU8udUvBQWPlGN9buawFvjuo9mgCAxzbOoJAgXX39ihec/nn42T5Vb6/qyn45eTimx5ND9kMEw==} + '@napi-rs/canvas-win32-x64-msvc@0.1.99': + resolution: {integrity: sha512-plMYGVbc/vmmPF9MtmHbwNk1rL1Aj53vQZt+Gnv1oZn6gmd9jEHHJ0n9Nd2nxa5sKH7TS5IjkCDM6289O0d6PQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2871,8 +2783,8 @@ packages: resolution: {integrity: sha512-q7ZaUCJkEU5BeOdE7fBx1XWRd2T5Ady65nxq4brMf5L4cE1VV/ACq5w9Z5b/IVJs8CwSSIwc30nlthH0gFo4Ig==} engines: {node: '>= 10'} - '@napi-rs/canvas@0.1.98': - resolution: {integrity: sha512-WDg3lxYMqlrg49sDVUlrHVfIEPsd5AjYDRuGD6Fu82K5agJx0UnWA+l5qd53GNLRiMN2WhOw7FLR+Er5QB/0SA==} + '@napi-rs/canvas@0.1.99': + resolution: {integrity: sha512-zN4eQlK3eBf7aJBcTHZilpBH3tDekBzPMIWC8r0s94Ecl73XfOyFi4w7yKFMRVUT0lvNQjtOL8YSrwqQj6mZFg==} engines: {node: '>= 10'} '@napi-rs/wasm-runtime@1.1.4': @@ -2996,166 +2908,166 @@ packages: resolution: {integrity: sha512-tlc/FcYIv5i8RYsl2iDil4A0gOihaas1R5jPcIC4Zw3GhjKsVilw90aHcVlhZPTBLGBzd379S+VcnsDjd9ChiA==} engines: {node: '>=12.4.0'} - '@opentelemetry/api-logs@0.214.0': - resolution: {integrity: sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==} + '@opentelemetry/api-logs@0.215.0': + resolution: {integrity: sha512-xrFlqhdhUyO8wSRn6DjE0145/HPWSJ5Nm0C7vWua6TdL/FSEAZvEyvdsa9CRXuxo9ebb7j/NEPhEcO62IJ0qUA==} engines: {node: '>=8.0.0'} '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/configuration@0.214.0': - resolution: {integrity: sha512-Q+awuEwxhETwIAXuxHvIY5ZMEP0ZqvxLTi9kclrkyVJppEUXYL3Bhiw3jYrxdHYMh0Y0tVInQH9FEZ1aMinvLA==} + '@opentelemetry/configuration@0.215.0': + resolution: {integrity: sha512-FSWvDryxjinHROfzEVbJGBw10FqGzLEm2C1LPX6Lot6hvxq3lFJzNLlue8vm64C5yIbqSQVjWsPhYu56ThQS4Q==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.9.0 - '@opentelemetry/context-async-hooks@2.6.1': - resolution: {integrity: sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ==} + '@opentelemetry/context-async-hooks@2.7.0': + resolution: {integrity: sha512-MWXggArM+Y11mPS8VOrqxOj+YMGQSRuvhM91eSBX4xFpJa05mpkeVvM8pPux5ElkEjV5RMgrkisrlP/R83SpBQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.6.1': - resolution: {integrity: sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==} + '@opentelemetry/core@2.7.0': + resolution: {integrity: sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/exporter-logs-otlp-grpc@0.214.0': - resolution: {integrity: sha512-SwmFRwO8mi6nndzbsjPgSFg7qy1WeNHRFD+s6uCsdiUDUt3+yzI2qiHE3/ub2f37+/CbeGcG+Ugc8Gwr6nu2Aw==} + '@opentelemetry/exporter-logs-otlp-grpc@0.215.0': + resolution: {integrity: sha512-MVq+9ma/63XRXc0AcnS+XyWSD6VBYn39OucsvpzjqxTpzTOiGXNxTwsbV3zbnvgUexb5hc2ZjJlZUK2W/19UUw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-logs-otlp-http@0.214.0': - resolution: {integrity: sha512-9qv2Tl/Hq6qc5pJCbzFJnzA0uvlb9DgM70yGJPYf3bA5LlLkRCpcn81i4JbcIH4grlQIWY6A+W7YG0LLvS1BAw==} + '@opentelemetry/exporter-logs-otlp-http@0.215.0': + resolution: {integrity: sha512-U7Qb+TVX2GZH5RSC+Gx9aE5zChKP1kPg87X3PlI/41lWVPJdBIzmgMmuE28MmQlrK84nLHCIqUOOben8YkSzBw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-logs-otlp-proto@0.214.0': - resolution: {integrity: sha512-IWAVvCO1TlpotRjFmhQFz9RSfQy5BsLtDRBtptSrXZRwfyRPpuql/RMe5zdmu0Gxl3ERDFwOzOqkf3bwy7Jzcw==} + '@opentelemetry/exporter-logs-otlp-proto@0.215.0': + resolution: {integrity: sha512-vs2xKKTdt/vKWMuBzw+LZYYCKqulodCRoonWWiyToIQfa6JgbyWjTu/iy6qpBLhLi+t6fNc1bwJGwu3vkot2Jg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-grpc@0.214.0': - resolution: {integrity: sha512-0NGxWHVYHgbp51SEzmsP+Hdups81eRs229STcSWHo3WO0aqY6RpJ9csxfyEtFgaNrBDv6UfOh0je4ss/ROS6XA==} + '@opentelemetry/exporter-metrics-otlp-grpc@0.215.0': + resolution: {integrity: sha512-1TAMliHQvzc+v1OtnLMHSk5sU8BSkJbxIKrWzuCWcQjajWrvem/r5ugLK6agI0PjPz/ADfZju5AVYedlNyeO9g==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-http@0.214.0': - resolution: {integrity: sha512-Tx/59RmjBgkXJ3qnsD04rpDrVWL53LU/czpgLJh+Ab98nAroe91I7vZ3uGN9mxwPS0jsZEnmqmHygVwB2vRMlA==} + '@opentelemetry/exporter-metrics-otlp-http@0.215.0': + resolution: {integrity: sha512-FRydO5j7MWnXK9ghfykKxiSM8I5UeiicK/UNl3/mv86xoEKkb+LKz1I3WXgkuYVOQf22VNqbPO58s2W1mVWtEQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-metrics-otlp-proto@0.214.0': - resolution: {integrity: sha512-pJIcghFGhx3VSCgP5U+yZx+OMNj0t+ttnhC8IjL5Wza7vWIczctF6t3AGcVQffi2dEqX+ZHANoBwoPR8y6RMKA==} + '@opentelemetry/exporter-metrics-otlp-proto@0.215.0': + resolution: {integrity: sha512-d8/Sys9MtxLbn0S+RE1pUNcuoI9ZyI4SPfOO+yskSEQiPFoKCTMwwthB8MTY4S8qxCBAWyM+P7QMX+vEIT7PZw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-prometheus@0.214.0': - resolution: {integrity: sha512-4TGYoZKebUWVuYkV6r5wS2dUF4zH7EbWFw/Uqz1ZM1tGHQeFT9wzHGXq3iSIXMUrwu5jRdxjfMaXrYejPu2kpQ==} + '@opentelemetry/exporter-prometheus@0.215.0': + resolution: {integrity: sha512-7ghCl1G84jccmxG3B8UwUMZ1OlequBzB1jt5tZ4DDiAyVKeA4Roz5D6VK8SQ0ZyBQffVyX/rtXrpVXKVzRCGfg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-grpc@0.214.0': - resolution: {integrity: sha512-FWRZ7AWoTryYhthralHkfXUuyO3l7cRsnr49WcDio1orl2a7KxT8aDZdwQtV1adzoUvZ9Gfo+IstElghCS4zfw==} + '@opentelemetry/exporter-trace-otlp-grpc@0.215.0': + resolution: {integrity: sha512-+SuWfPFVjPTvHJhlzTCBetLsPVu86xSFPR3fv8TN+H7lpe5aZzF96TUsfMHDR0lwpIwlJpG57CJnGalIfrpXkg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-http@0.214.0': - resolution: {integrity: sha512-kIN8nTBMgV2hXzV/a20BCFilPZdAIMYYJGSgfMMRm/Xa+07y5hRDS2Vm12A/z8Cdu3Sq++ZvJfElokX2rkgGgw==} + '@opentelemetry/exporter-trace-otlp-http@0.215.0': + resolution: {integrity: sha512-k4J9ISeGpb0Bm/wCrlcrbroMFTkiWMrdhNxQGrlktxLy127Yzd4/7nrTawn5d/ApktYTknvdixsE6++34Qfi1w==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-trace-otlp-proto@0.214.0': - resolution: {integrity: sha512-ON0spYWb2yAdQ9b+ItNyK0c6qdtcs+0eVR4YFJkhJL7agfT8sHFg0e5EesauSRiTHPZHiDobI92k77q0lwAmqg==} + '@opentelemetry/exporter-trace-otlp-proto@0.215.0': + resolution: {integrity: sha512-+QclHuJmlp/I3Z2fNn+j1dAajMjJqJ4Sgo8ajwiK6Tzmg5SNwBGmBX66AZvTLe/3/bc3L7bo90m9gsaJBrzEsA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/exporter-zipkin@2.6.1': - resolution: {integrity: sha512-km2/hD3inLTqtLnUAHDGz7ZP/VOyZNslrC/iN66x4jkmpckwlONW54LRPNI6fm09/musDtZga9EWsxgwnjGUlw==} + '@opentelemetry/exporter-zipkin@2.7.0': + resolution: {integrity: sha512-tbzcYDmZWtX4hgJn15qP7/iYFVd1yzbUloBuSYsQtn0XQTxJsG7vgwkPKEBellriH0XJmlZJxYtWkHpwzHBhaQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.0.0 - '@opentelemetry/instrumentation@0.214.0': - resolution: {integrity: sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==} + '@opentelemetry/instrumentation@0.215.0': + resolution: {integrity: sha512-SyJONuqypQ2xWdYMy99vF7JhZ2kDTGx4oRmM/jZV+kRtZ96JTnJmEINbIJgHz7Gnhtw0bimHwbPy/pguA5wpPQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-exporter-base@0.214.0': - resolution: {integrity: sha512-u1Gdv0/E9wP+apqWf7Wv2npXmgJtxsW2XL0TEv9FZloTZRuMBKmu8cYVXwS4Hm3q/f/3FuCnPTgiwYvIqRSpRg==} + '@opentelemetry/otlp-exporter-base@0.215.0': + resolution: {integrity: sha512-lHrfbmeLSmesGSkkHiqDwOzfaEMSWXdc7q6UoLfbW8byONCb+bE/zkAr0kapN4US1baT/2nbpNT7Cn9XoB96Vg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-grpc-exporter-base@0.214.0': - resolution: {integrity: sha512-IDP6zcyA24RhNZ289MP6eToIZcinlmirHjX8v3zKCQ2ZhPpt5cGwkN91tCth337lqHIgWcTy90uKRiX/SzALDw==} + '@opentelemetry/otlp-grpc-exporter-base@0.215.0': + resolution: {integrity: sha512-WkuHkUrhwNxTKrm7Xuf6S+HmLNbk2T8S2YiZhN606RfgetSQb9xLp4NizWLwXvw63uxGsBaK262dirFO2yht2g==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/otlp-transformer@0.214.0': - resolution: {integrity: sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w==} + '@opentelemetry/otlp-transformer@0.215.0': + resolution: {integrity: sha512-cWwBvaV+vkXHkSoTYR8hGw+AW03UlgTr6xtrUKOMeum3T+8vffYXIfXu6KY5MLu8O9QtoBKqaKWw9I5xoOepng==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/propagator-b3@2.6.1': - resolution: {integrity: sha512-Dvz9TA6cPqIbxolSzQ5x9br6iQlqdGhVYrm+oYc7pfJ7LaVXz8F0XIqhWbnKB5YvfZ6SUmabBUUxnvHs/9uhxA==} + '@opentelemetry/propagator-b3@2.7.0': + resolution: {integrity: sha512-HNm+tdXY5i8dzAo4YankchNWdZ4Z1Boop7lhbb3wltWT0MwEMo0QADRJwrF83pXEeDT+5Bmq4J8sStFaUywE3g==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/propagator-jaeger@2.6.1': - resolution: {integrity: sha512-kKFMxBcjBZAC1vBch5mtZ/dJQvcAEKWga+c+q5iGgRLPIE6Mc649zEwMaCIQCzalziMJQiyUadFYMHmELB7AFw==} + '@opentelemetry/propagator-jaeger@2.7.0': + resolution: {integrity: sha512-lKMAjekRkFYWrjmPTaxUJt+V8Mr1iB94sP3HDZZCmdZ/LUV/wtqAGqXhgnkIbdlnWxxvEs9MGEIMdJC+xObMFg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/resources@2.6.1': - resolution: {integrity: sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==} + '@opentelemetry/resources@2.7.0': + resolution: {integrity: sha512-K+oi0hNMv94EpZbnW3eyu2X6SGVpD3O5DhG2NIp65Hc7lhAj9brRXTAVzh3wB82+q3ThakEf7Zd7RsFUqcTc7A==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-logs@0.214.0': - resolution: {integrity: sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA==} + '@opentelemetry/sdk-logs@0.215.0': + resolution: {integrity: sha512-y3ucOmphzc4vgBTyIGchs+N/1rkACmoka8QalT2z1LBNM232Z17zMYayHcMl+dgMoOadZ0b72UZv7mDtqy1cFA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' - '@opentelemetry/sdk-metrics@2.6.1': - resolution: {integrity: sha512-9t9hJHX15meBy2NmTJxL+NJfXmnausR2xUDvE19XQce0Qi/GBtDGamU8nS1RMbdgDmhgpm3VaOu2+fiS/SfTpQ==} + '@opentelemetry/sdk-metrics@2.7.0': + resolution: {integrity: sha512-Vd7h95av/LYRsAVN7wbprvvJnHkq7swMXAo7Uad0Uxf9jl6NSReLa0JNivrcc5BVIx/vl2t+cgdVQQbnVhsR9w==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.9.0 <1.10.0' - '@opentelemetry/sdk-node@0.214.0': - resolution: {integrity: sha512-gl2XvQBJuPjhGcw9SsnQO5qxChAPMuGRPFaD8lqtF+Cey91NgGUQ0sio2vlDFOSm3JOLzc44vL+OAfx1dXuZjg==} + '@opentelemetry/sdk-node@0.215.0': + resolution: {integrity: sha512-YunKvZOMhYNMBJ66YRjbGShuoV/w1y21U7MGPRx0iPJenPszOddtYEQFJv8piAEOn94BUFIfJHtHjptrHsGiIA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace-base@2.6.1': - resolution: {integrity: sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==} + '@opentelemetry/sdk-trace-base@2.7.0': + resolution: {integrity: sha512-Yg9zEXJB50DLVLpsKPk7NmNqlPlS+OvqhJGh0A8oawIOTPOwlm4eXs9BMJV7L79lvEwI+dWtAj+YjTyddV336A==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/sdk-trace-node@2.6.1': - resolution: {integrity: sha512-Hh2i4FwHWRFhnO2Q/p6svMxy8MPsNCG0uuzUY3glqm0rwM0nQvbTO1dXSp9OqQoTKXcQzaz9q1f65fsurmOhNw==} + '@opentelemetry/sdk-trace-node@2.7.0': + resolution: {integrity: sha512-RrFHOXw0IYp/OThew6QORdybnnLitUAUMCJKcQNBYS0hDkCYarO2vTkVxfrGxCIqd5XHSMvbCpBd/T8ZMw8oSg==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -4719,8 +4631,8 @@ packages: bare-events: optional: true - bare-url@2.4.0: - resolution: {integrity: sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==} + bare-url@2.4.1: + resolution: {integrity: sha512-fZapLWNB25gS+etK27NV9KgBNXgo2yeYHuj+OyPblQd6GYAE3JVy6aKxszMV5jhGGFwraXQKA5fldvf3lMyEqw==} base-x@5.0.1: resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} @@ -5332,8 +5244,8 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + eventsource-parser@3.0.7: + resolution: {integrity: sha512-zwxwiQqexizSXFZV13zMiEtW1E3lv7RlUv+1f5FBiR4x7wFhEjm3aFTyYkZQWzyN08WnPdox015GoRH5D/E5YA==} engines: {node: '>=18.0.0'} eventsource@3.0.7: @@ -5395,8 +5307,8 @@ packages: fast-wrap-ansi@0.1.6: resolution: {integrity: sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==} - fast-xml-builder@1.1.4: - resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==} + fast-xml-builder@1.1.5: + resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} fast-xml-parser@5.5.7: resolution: {integrity: sha512-LteOsISQ2GEiDHZch6L9hB0+MLoYVLToR7xotrzU0opCICBkxOPgHAy1HxAvtxfJNXDJpgAsQN30mkrfpO2Prg==} @@ -5629,8 +5541,8 @@ packages: resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} engines: {node: '>=20'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} hast-util-to-html@9.0.5: @@ -5980,8 +5892,8 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - koffi@2.16.0: - resolution: {integrity: sha512-h/2NJueOKWd0YYycEOWDspomizgNfuOKf/V7ZE2fytvuRtHoY9Tb+y4x6GJ6pFqaVndWn9dLK+sCI14eWtu5rA==} + koffi@2.16.1: + resolution: {integrity: sha512-0Ie6CfD026dNfWSosDw9dPxPzO9Rlyo0N8m5r05S8YjytIpuilzMFDMY4IDy/8xQsTwpuVinhncD+S8n3bcYZQ==} lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -6208,8 +6120,8 @@ packages: engines: {node: '>= 18'} hasBin: true - marked@18.0.0: - resolution: {integrity: sha512-2e7Qiv/HJSXj8rDEpgTvGKsP8yYtI9xXHKDnrftrmnrJPaFNM7VRb2YCzWaX4BP1iCJ/XPduzDJZMFoqTCcIMA==} + marked@18.0.1: + resolution: {integrity: sha512-IILJE4Aap/KIGu4ZRCzQcYMxkhumblXnbqfQe+HAD4f982wrRAsJEGKGM653yAioS6g3Yq3yOhjrUebcrtOgRA==} engines: {node: '>= 20'} hasBin: true @@ -7560,6 +7472,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + typical@4.0.0: resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} engines: {node: '>=8'} @@ -7962,7 +7879,7 @@ snapshots: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 - '@asamuzakjp/dom-selector@7.0.10': + '@asamuzakjp/dom-selector@7.1.0': dependencies: '@asamuzakjp/generational-cache': 1.0.1 '@asamuzakjp/nwsapi': 2.3.9 @@ -8118,21 +8035,21 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-cognito-identity@3.1030.0': + '@aws-sdk/client-cognito-identity@3.1032.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.27 + '@aws-sdk/core': 3.974.1 '@aws-sdk/credential-provider-node': 3.972.32 - '@aws-sdk/middleware-host-header': 3.972.9 - '@aws-sdk/middleware-logger': 3.972.9 - '@aws-sdk/middleware-recursion-detection': 3.972.10 - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/region-config-resolver': 3.972.11 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@aws-sdk/util-user-agent-browser': 3.972.9 - '@aws-sdk/util-user-agent-node': 3.973.15 + '@aws-sdk/middleware-host-header': 3.972.10 + '@aws-sdk/middleware-logger': 3.972.10 + '@aws-sdk/middleware-recursion-detection': 3.972.11 + '@aws-sdk/middleware-user-agent': 3.972.31 + '@aws-sdk/region-config-resolver': 3.972.12 + '@aws-sdk/types': 3.973.8 + '@aws-sdk/util-endpoints': 3.996.7 + '@aws-sdk/util-user-agent-browser': 3.972.10 + '@aws-sdk/util-user-agent-node': 3.973.17 '@smithy/config-resolver': 4.4.16 '@smithy/core': 3.23.15 '@smithy/fetch-http-handler': 5.3.17 @@ -8222,22 +8139,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.973.27': - dependencies: - '@aws-sdk/types': 3.973.7 - '@aws-sdk/xml-builder': 3.972.17 - '@smithy/core': 3.23.15 - '@smithy/node-config-provider': 4.3.14 - '@smithy/property-provider': 4.2.14 - '@smithy/protocol-http': 5.3.14 - '@smithy/signature-v4': 5.3.14 - '@smithy/smithy-client': 4.12.11 - '@smithy/types': 4.14.1 - '@smithy/util-base64': 4.3.2 - '@smithy/util-middleware': 4.2.14 - '@smithy/util-utf8': 4.2.2 - tslib: 2.8.1 - '@aws-sdk/core@3.974.1': dependencies: '@aws-sdk/types': 3.973.8 @@ -8259,24 +8160,16 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-cognito-identity@3.972.22': + '@aws-sdk/credential-provider-cognito-identity@3.972.24': dependencies: - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/nested-clients': 3.996.21 + '@aws-sdk/types': 3.973.8 '@smithy/property-provider': 4.2.14 '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-env@3.972.25': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.14 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.27': dependencies: '@aws-sdk/core': 3.974.1 @@ -8285,19 +8178,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.27': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@smithy/fetch-http-handler': 5.3.17 - '@smithy/node-http-handler': 4.5.3 - '@smithy/property-provider': 4.2.14 - '@smithy/protocol-http': 5.3.14 - '@smithy/smithy-client': 4.12.11 - '@smithy/types': 4.14.1 - '@smithy/util-stream': 4.5.23 - tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.29': dependencies: '@aws-sdk/core': 3.974.1 @@ -8311,25 +8191,6 @@ snapshots: '@smithy/util-stream': 4.5.23 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.972.29': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/credential-provider-env': 3.972.25 - '@aws-sdk/credential-provider-http': 3.972.27 - '@aws-sdk/credential-provider-login': 3.972.29 - '@aws-sdk/credential-provider-process': 3.972.25 - '@aws-sdk/credential-provider-sso': 3.972.29 - '@aws-sdk/credential-provider-web-identity': 3.972.29 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/credential-provider-imds': 4.2.14 - '@smithy/property-provider': 4.2.14 - '@smithy/shared-ini-file-loader': 4.4.9 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-ini@3.972.31': dependencies: '@aws-sdk/core': 3.974.1 @@ -8349,19 +8210,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.972.29': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.14 - '@smithy/protocol-http': 5.3.14 - '@smithy/shared-ini-file-loader': 4.4.9 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-login@3.972.31': dependencies: '@aws-sdk/core': 3.974.1 @@ -8392,15 +8240,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.972.25': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.14 - '@smithy/shared-ini-file-loader': 4.4.9 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/credential-provider-process@3.972.27': dependencies: '@aws-sdk/core': 3.974.1 @@ -8410,19 +8249,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.972.29': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/token-providers': 3.1026.0 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.14 - '@smithy/shared-ini-file-loader': 4.4.9 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-sso@3.972.31': dependencies: '@aws-sdk/core': 3.974.1 @@ -8436,18 +8262,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.29': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.14 - '@smithy/shared-ini-file-loader': 4.4.9 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.31': dependencies: '@aws-sdk/core': 3.974.1 @@ -8460,21 +8274,21 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-providers@3.1030.0': + '@aws-sdk/credential-providers@3.1032.0': dependencies: - '@aws-sdk/client-cognito-identity': 3.1030.0 - '@aws-sdk/core': 3.973.27 - '@aws-sdk/credential-provider-cognito-identity': 3.972.22 - '@aws-sdk/credential-provider-env': 3.972.25 - '@aws-sdk/credential-provider-http': 3.972.27 - '@aws-sdk/credential-provider-ini': 3.972.29 - '@aws-sdk/credential-provider-login': 3.972.29 + '@aws-sdk/client-cognito-identity': 3.1032.0 + '@aws-sdk/core': 3.974.1 + '@aws-sdk/credential-provider-cognito-identity': 3.972.24 + '@aws-sdk/credential-provider-env': 3.972.27 + '@aws-sdk/credential-provider-http': 3.972.29 + '@aws-sdk/credential-provider-ini': 3.972.31 + '@aws-sdk/credential-provider-login': 3.972.31 '@aws-sdk/credential-provider-node': 3.972.32 - '@aws-sdk/credential-provider-process': 3.972.25 - '@aws-sdk/credential-provider-sso': 3.972.29 - '@aws-sdk/credential-provider-web-identity': 3.972.29 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/credential-provider-process': 3.972.27 + '@aws-sdk/credential-provider-sso': 3.972.31 + '@aws-sdk/credential-provider-web-identity': 3.972.31 + '@aws-sdk/nested-clients': 3.996.21 + '@aws-sdk/types': 3.973.8 '@smithy/config-resolver': 4.4.16 '@smithy/core': 3.23.15 '@smithy/credential-provider-imds': 4.2.14 @@ -8540,13 +8354,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.972.9': - dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/protocol-http': 5.3.14 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/middleware-location-constraint@3.972.10': dependencies: '@aws-sdk/types': 3.973.8 @@ -8559,20 +8366,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.972.9': - dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - - '@aws-sdk/middleware-recursion-detection@3.972.10': - dependencies: - '@aws-sdk/types': 3.973.7 - '@aws/lambda-invoke-store': 0.2.4 - '@smithy/protocol-http': 5.3.14 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.972.11': dependencies: '@aws-sdk/types': 3.973.8 @@ -8604,17 +8397,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.29': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@smithy/core': 3.23.15 - '@smithy/protocol-http': 5.3.14 - '@smithy/types': 4.14.1 - '@smithy/util-retry': 4.3.2 - tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.31': dependencies: '@aws-sdk/core': 3.974.1 @@ -8641,49 +8423,6 @@ snapshots: '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.996.19': - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.27 - '@aws-sdk/middleware-host-header': 3.972.9 - '@aws-sdk/middleware-logger': 3.972.9 - '@aws-sdk/middleware-recursion-detection': 3.972.10 - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/region-config-resolver': 3.972.11 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@aws-sdk/util-user-agent-browser': 3.972.9 - '@aws-sdk/util-user-agent-node': 3.973.15 - '@smithy/config-resolver': 4.4.16 - '@smithy/core': 3.23.15 - '@smithy/fetch-http-handler': 5.3.17 - '@smithy/hash-node': 4.2.14 - '@smithy/invalid-dependency': 4.2.14 - '@smithy/middleware-content-length': 4.2.14 - '@smithy/middleware-endpoint': 4.4.30 - '@smithy/middleware-retry': 4.5.3 - '@smithy/middleware-serde': 4.2.18 - '@smithy/middleware-stack': 4.2.14 - '@smithy/node-config-provider': 4.3.14 - '@smithy/node-http-handler': 4.5.3 - '@smithy/protocol-http': 5.3.14 - '@smithy/smithy-client': 4.12.11 - '@smithy/types': 4.14.1 - '@smithy/url-parser': 4.2.14 - '@smithy/util-base64': 4.3.2 - '@smithy/util-body-length-browser': 4.2.2 - '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.47 - '@smithy/util-defaults-mode-node': 4.2.52 - '@smithy/util-endpoints': 3.4.1 - '@smithy/util-middleware': 4.2.14 - '@smithy/util-retry': 4.3.2 - '@smithy/util-utf8': 4.2.2 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/nested-clients@3.996.21': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -8727,14 +8466,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/region-config-resolver@3.972.11': - dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/config-resolver': 4.4.16 - '@smithy/node-config-provider': 4.3.14 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.972.12': dependencies: '@aws-sdk/types': 3.973.8 @@ -8763,18 +8494,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1026.0': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.14 - '@smithy/shared-ini-file-loader': 4.4.9 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/token-providers@3.1032.0': dependencies: '@aws-sdk/core': 3.974.1 @@ -8787,11 +8506,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.973.7': - dependencies: - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/types@3.973.8': dependencies: '@smithy/types': 4.14.1 @@ -8801,14 +8515,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.996.6': - dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.1 - '@smithy/url-parser': 4.2.14 - '@smithy/util-endpoints': 3.4.1 - tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.996.7': dependencies: '@aws-sdk/types': 3.973.8 @@ -8824,13 +8530,6 @@ snapshots: '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/util-format-url@3.972.9': - dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/querystring-builder': 4.2.14 - '@smithy/types': 4.14.1 - tslib: 2.8.1 - '@aws-sdk/util-locate-window@3.965.5': dependencies: tslib: 2.8.1 @@ -8842,22 +8541,6 @@ snapshots: bowser: 2.14.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.972.9': - dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.1 - bowser: 2.14.1 - tslib: 2.8.1 - - '@aws-sdk/util-user-agent-node@3.973.15': - dependencies: - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/types': 3.973.7 - '@smithy/node-config-provider': 4.3.14 - '@smithy/types': 4.14.1 - '@smithy/util-config-provider': 4.2.2 - tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.973.17': dependencies: '@aws-sdk/middleware-user-agent': 3.972.31 @@ -8867,12 +8550,6 @@ snapshots: '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.17': - dependencies: - '@smithy/types': 4.14.1 - fast-xml-parser: 5.5.7 - tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.18': dependencies: '@smithy/types': 4.14.1 @@ -8881,8 +8558,8 @@ snapshots: '@aws/bedrock-token-generator@1.1.0': dependencies: - '@aws-sdk/credential-providers': 3.1030.0 - '@aws-sdk/util-format-url': 3.972.9 + '@aws-sdk/credential-providers': 3.1032.0 + '@aws-sdk/util-format-url': 3.972.10 '@smithy/config-resolver': 4.4.16 '@smithy/hash-node': 4.2.14 '@smithy/invalid-dependency': 4.2.14 @@ -8952,8 +8629,8 @@ snapshots: '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 - '@azure/msal-browser': 5.6.3 - '@azure/msal-node': 5.1.2 + '@azure/msal-browser': 5.7.0 + '@azure/msal-node': 5.1.3 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -8966,13 +8643,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/msal-browser@5.6.3': + '@azure/msal-browser@5.7.0': dependencies: - '@azure/msal-common': 16.4.1 + '@azure/msal-common': 16.5.0 '@azure/msal-common@15.17.0': {} - '@azure/msal-common@16.4.1': {} + '@azure/msal-common@16.5.0': {} '@azure/msal-node@3.8.10': dependencies: @@ -8980,9 +8657,9 @@ snapshots: jsonwebtoken: 9.0.3 uuid: 8.3.2 - '@azure/msal-node@5.1.2': + '@azure/msal-node@5.1.3': dependencies: - '@azure/msal-common': 16.4.1 + '@azure/msal-common': 16.5.0 jsonwebtoken: 9.0.3 uuid: 8.3.2 @@ -9114,7 +8791,7 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@copilotkit/aimock@1.14.0': {} + '@copilotkit/aimock@1.14.3': {} '@create-markdown/preview@2.0.3(shiki@3.23.0)': optionalDependencies: @@ -10034,7 +9711,7 @@ snapshots: marked: 15.0.12 mime-types: 3.0.2 optionalDependencies: - koffi: 2.16.0 + koffi: 2.16.1 '@matrix-org/matrix-sdk-crypto-nodejs@0.4.0': dependencies: @@ -10043,23 +9720,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@matrix-org/matrix-sdk-crypto-wasm@18.0.0': {} + '@matrix-org/matrix-sdk-crypto-wasm@18.1.0': {} - '@microsoft/teams.api@2.0.7': + '@microsoft/teams.api@2.0.8': dependencies: - '@microsoft/teams.cards': 2.0.7 - '@microsoft/teams.common': 2.0.7 + '@microsoft/teams.cards': 2.0.8 + '@microsoft/teams.common': 2.0.8 jwt-decode: 4.0.0 qs: 6.14.2 transitivePeerDependencies: - debug - '@microsoft/teams.apps@2.0.7': + '@microsoft/teams.apps@2.0.8': dependencies: '@azure/msal-node': 3.8.10 - '@microsoft/teams.api': 2.0.7 - '@microsoft/teams.common': 2.0.7 - '@microsoft/teams.graph': 2.0.7 + '@microsoft/teams.api': 2.0.8 + '@microsoft/teams.common': 2.0.8 + '@microsoft/teams.graph': 2.0.8 axios: 1.15.0 cors: 2.8.6 express: 5.2.1 @@ -10070,17 +9747,17 @@ snapshots: - debug - supports-color - '@microsoft/teams.cards@2.0.7': {} + '@microsoft/teams.cards@2.0.8': {} - '@microsoft/teams.common@2.0.7': + '@microsoft/teams.common@2.0.8': dependencies: axios: 1.15.0 transitivePeerDependencies: - debug - '@microsoft/teams.graph@2.0.7': + '@microsoft/teams.graph@2.0.8': dependencies: - '@microsoft/teams.common': 2.0.7 + '@microsoft/teams.common': 2.0.8 qs: 6.14.2 transitivePeerDependencies: - debug @@ -10103,7 +9780,7 @@ snapshots: cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 - eventsource-parser: 3.0.6 + eventsource-parser: 3.0.7 express: 5.2.1 express-rate-limit: 8.3.2(express@5.2.1) hono: 4.12.14 @@ -10121,67 +9798,67 @@ snapshots: '@napi-rs/canvas-android-arm64@0.1.92': optional: true - '@napi-rs/canvas-android-arm64@0.1.98': + '@napi-rs/canvas-android-arm64@0.1.99': optional: true '@napi-rs/canvas-darwin-arm64@0.1.92': optional: true - '@napi-rs/canvas-darwin-arm64@0.1.98': + '@napi-rs/canvas-darwin-arm64@0.1.99': optional: true '@napi-rs/canvas-darwin-x64@0.1.92': optional: true - '@napi-rs/canvas-darwin-x64@0.1.98': + '@napi-rs/canvas-darwin-x64@0.1.99': optional: true '@napi-rs/canvas-linux-arm-gnueabihf@0.1.92': optional: true - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.98': + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.99': optional: true '@napi-rs/canvas-linux-arm64-gnu@0.1.92': optional: true - '@napi-rs/canvas-linux-arm64-gnu@0.1.98': + '@napi-rs/canvas-linux-arm64-gnu@0.1.99': optional: true '@napi-rs/canvas-linux-arm64-musl@0.1.92': optional: true - '@napi-rs/canvas-linux-arm64-musl@0.1.98': + '@napi-rs/canvas-linux-arm64-musl@0.1.99': optional: true '@napi-rs/canvas-linux-riscv64-gnu@0.1.92': optional: true - '@napi-rs/canvas-linux-riscv64-gnu@0.1.98': + '@napi-rs/canvas-linux-riscv64-gnu@0.1.99': optional: true '@napi-rs/canvas-linux-x64-gnu@0.1.92': optional: true - '@napi-rs/canvas-linux-x64-gnu@0.1.98': + '@napi-rs/canvas-linux-x64-gnu@0.1.99': optional: true '@napi-rs/canvas-linux-x64-musl@0.1.92': optional: true - '@napi-rs/canvas-linux-x64-musl@0.1.98': + '@napi-rs/canvas-linux-x64-musl@0.1.99': optional: true '@napi-rs/canvas-win32-arm64-msvc@0.1.92': optional: true - '@napi-rs/canvas-win32-arm64-msvc@0.1.98': + '@napi-rs/canvas-win32-arm64-msvc@0.1.99': optional: true '@napi-rs/canvas-win32-x64-msvc@0.1.92': optional: true - '@napi-rs/canvas-win32-x64-msvc@0.1.98': + '@napi-rs/canvas-win32-x64-msvc@0.1.99': optional: true '@napi-rs/canvas@0.1.92': @@ -10198,19 +9875,19 @@ snapshots: '@napi-rs/canvas-win32-arm64-msvc': 0.1.92 '@napi-rs/canvas-win32-x64-msvc': 0.1.92 - '@napi-rs/canvas@0.1.98': + '@napi-rs/canvas@0.1.99': optionalDependencies: - '@napi-rs/canvas-android-arm64': 0.1.98 - '@napi-rs/canvas-darwin-arm64': 0.1.98 - '@napi-rs/canvas-darwin-x64': 0.1.98 - '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.98 - '@napi-rs/canvas-linux-arm64-gnu': 0.1.98 - '@napi-rs/canvas-linux-arm64-musl': 0.1.98 - '@napi-rs/canvas-linux-riscv64-gnu': 0.1.98 - '@napi-rs/canvas-linux-x64-gnu': 0.1.98 - '@napi-rs/canvas-linux-x64-musl': 0.1.98 - '@napi-rs/canvas-win32-arm64-msvc': 0.1.98 - '@napi-rs/canvas-win32-x64-msvc': 0.1.98 + '@napi-rs/canvas-android-arm64': 0.1.99 + '@napi-rs/canvas-darwin-arm64': 0.1.99 + '@napi-rs/canvas-darwin-x64': 0.1.99 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.99 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.99 + '@napi-rs/canvas-linux-arm64-musl': 0.1.99 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.99 + '@napi-rs/canvas-linux-x64-gnu': 0.1.99 + '@napi-rs/canvas-linux-x64-musl': 0.1.99 + '@napi-rs/canvas-win32-arm64-msvc': 0.1.99 + '@napi-rs/canvas-win32-x64-msvc': 0.1.99 optional: true '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.10.0)': @@ -10290,241 +9967,241 @@ snapshots: '@nolyfill/domexception@1.0.28': {} - '@opentelemetry/api-logs@0.214.0': + '@opentelemetry/api-logs@0.215.0': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api@1.9.1': {} - '@opentelemetry/configuration@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/configuration@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) yaml: 2.8.3 - '@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/context-async-hooks@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/core@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/exporter-logs-otlp-grpc@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-logs-otlp-grpc@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-grpc-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.215.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-logs-otlp-http@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-logs-otlp-http@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.215.0 + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.215.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-logs-otlp-proto@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-logs-otlp-proto@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.215.0 + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-grpc@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-metrics-otlp-grpc@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-grpc-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-http@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-metrics-otlp-http@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-proto@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-metrics-otlp-proto@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-prometheus@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-prometheus@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/exporter-trace-otlp-grpc@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-trace-otlp-grpc@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-grpc-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-grpc-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-trace-otlp-http@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-trace-otlp-http@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-trace-otlp-proto@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-trace-otlp-proto@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-zipkin@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/exporter-zipkin@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 + '@opentelemetry/api-logs': 0.215.0 import-in-the-middle: 3.0.1 require-in-the-middle: 8.0.1 transitivePeerDependencies: - supports-color - '@opentelemetry/otlp-exporter-base@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-exporter-base@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-grpc-exporter-base@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-grpc-exporter-base@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@grpc/grpc-js': 1.14.3 '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.215.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-transformer@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/otlp-transformer@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.215.0 + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) protobufjs: 7.5.5 - '@opentelemetry/propagator-b3@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/propagator-b3@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/propagator-jaeger@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/propagator-jaeger@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-logs@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-logs@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.215.0 + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-metrics@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-metrics@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-node@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-node@0.215.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - '@opentelemetry/configuration': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-logs-otlp-grpc': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-logs-otlp-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-logs-otlp-proto': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-grpc': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-metrics-otlp-proto': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-prometheus': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-trace-otlp-grpc': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-trace-otlp-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-trace-otlp-proto': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/exporter-zipkin': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/otlp-exporter-base': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/propagator-b3': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/propagator-jaeger': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-logs': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-node': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/api-logs': 0.215.0 + '@opentelemetry/configuration': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/context-async-hooks': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-logs-otlp-grpc': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-logs-otlp-http': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-logs-otlp-proto': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-grpc': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-http': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-metrics-otlp-proto': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-prometheus': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-grpc': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-http': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-trace-otlp-proto': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/exporter-zipkin': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/propagator-b3': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/propagator-jaeger': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.215.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-node': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 transitivePeerDependencies: - supports-color - '@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace-base@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sdk-trace-node@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/sdk-trace-node@2.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/context-async-hooks': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 2.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.0(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions@1.40.0': {} @@ -12063,7 +11740,7 @@ snapshots: bare-events: 2.8.2 bare-path: 3.0.0 bare-stream: 2.13.0(bare-events@2.8.2) - bare-url: 2.4.0 + bare-url: 2.4.1 fast-fifo: 1.3.2 transitivePeerDependencies: - bare-abort-controller @@ -12084,7 +11761,7 @@ snapshots: transitivePeerDependencies: - react-native-b4a - bare-url@2.4.0: + bare-url@2.4.1: dependencies: bare-path: 3.0.0 @@ -12607,7 +12284,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 esbuild@0.27.7: optionalDependencies: @@ -12680,11 +12357,11 @@ snapshots: events@3.3.0: {} - eventsource-parser@3.0.6: {} + eventsource-parser@3.0.7: {} eventsource@3.0.7: dependencies: - eventsource-parser: 3.0.6 + eventsource-parser: 3.0.7 execa@4.1.0: dependencies: @@ -12778,13 +12455,13 @@ snapshots: dependencies: fast-string-width: 1.1.0 - fast-xml-builder@1.1.4: + fast-xml-builder@1.1.5: dependencies: path-expression-matcher: 1.5.0 fast-xml-parser@5.5.7: dependencies: - fast-xml-builder: 1.1.4 + fast-xml-builder: 1.1.5 path-expression-matcher: 1.5.0 strnum: 2.2.3 @@ -12955,7 +12632,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 math-intrinsics: 1.1.0 get-own-enumerable-property-symbols@3.0.2: {} @@ -13084,7 +12761,7 @@ snapshots: dependencies: hookified: 1.15.1 - hasown@2.0.2: + hasown@2.0.3: dependencies: function-bind: 1.1.2 @@ -13263,7 +12940,7 @@ snapshots: is-core-module@2.16.1: dependencies: - hasown: 2.0.2 + hasown: 2.0.3 is-docker@3.0.0: {} @@ -13311,7 +12988,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 is-regexp@1.0.0: {} @@ -13413,7 +13090,7 @@ snapshots: jsdom@29.0.2(@noble/hashes@2.0.1): dependencies: '@asamuzakjp/css-color': 5.1.11 - '@asamuzakjp/dom-selector': 7.0.10 + '@asamuzakjp/dom-selector': 7.1.0 '@bramus/specificity': 2.4.2 '@csstools/css-syntax-patches-for-csstree': 1.1.3(css-tree@3.2.1) '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) @@ -13525,7 +13202,7 @@ snapshots: klona@2.0.6: {} - koffi@2.16.0: + koffi@2.16.1: optional: true lie@3.3.0: @@ -13679,7 +13356,7 @@ snapshots: lru_map@0.4.1: {} - madge@8.0.0(typescript@6.0.2): + madge@8.0.0(typescript@6.0.3): dependencies: chalk: 4.1.2 commander: 7.2.0 @@ -13694,7 +13371,7 @@ snapshots: ts-graphviz: 2.1.6 walkdir: 0.4.1 optionalDependencies: - typescript: 6.0.2 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -13734,7 +13411,7 @@ snapshots: marked@15.0.12: {} - marked@18.0.0: {} + marked@18.0.1: {} math-intrinsics@1.1.0: {} @@ -13743,7 +13420,7 @@ snapshots: matrix-js-sdk@41.3.0: dependencies: '@babel/runtime': 7.29.2 - '@matrix-org/matrix-sdk-crypto-wasm': 18.0.0 + '@matrix-org/matrix-sdk-crypto-wasm': 18.1.0 another-json: 0.2.0 bs58: 6.0.0 content-type: 1.0.5 @@ -13987,7 +13664,7 @@ snapshots: abbrev: 1.1.1 optional: true - nostr-tools@2.23.3(typescript@6.0.2): + nostr-tools@2.23.3(typescript@6.0.3): dependencies: '@noble/ciphers': 2.1.1 '@noble/curves': 2.0.1 @@ -13997,7 +13674,7 @@ snapshots: '@scure/bip39': 2.0.1 nostr-wasm: 0.1.0 optionalDependencies: - typescript: 6.0.2 + typescript: 6.0.3 nostr-wasm@0.1.0: {} @@ -14297,7 +13974,7 @@ snapshots: pdfjs-dist@5.6.205: optionalDependencies: - '@napi-rs/canvas': 0.1.98 + '@napi-rs/canvas': 0.1.99 node-readable-to-web-readable-stream: 0.4.2 pend@1.2.0: {} @@ -14684,7 +14361,7 @@ snapshots: glob: 7.2.3 optional: true - rolldown-plugin-dts@0.23.2(@typescript/native-preview@7.0.0-dev.20260418.1)(rolldown@1.0.0-rc.16)(typescript@6.0.2): + rolldown-plugin-dts@0.23.2(@typescript/native-preview@7.0.0-dev.20260418.1)(rolldown@1.0.0-rc.16)(typescript@6.0.3): dependencies: '@babel/generator': 8.0.0-rc.3 '@babel/helper-validator-identifier': 8.0.0-rc.3 @@ -14699,7 +14376,7 @@ snapshots: rolldown: 1.0.0-rc.16 optionalDependencies: '@typescript/native-preview': 7.0.0-dev.20260418.1 - typescript: 6.0.2 + typescript: 6.0.3 transitivePeerDependencies: - oxc-resolver @@ -15255,7 +14932,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsdown@0.21.9(@typescript/native-preview@7.0.0-dev.20260418.1)(typescript@6.0.2): + tsdown@0.21.9(@typescript/native-preview@7.0.0-dev.20260418.1)(typescript@6.0.3): dependencies: ansis: 4.2.0 cac: 7.0.0 @@ -15266,7 +14943,7 @@ snapshots: obug: 2.1.1 picomatch: 4.0.4 rolldown: 1.0.0-rc.16 - rolldown-plugin-dts: 0.23.2(@typescript/native-preview@7.0.0-dev.20260418.1)(rolldown@1.0.0-rc.16)(typescript@6.0.2) + rolldown-plugin-dts: 0.23.2(@typescript/native-preview@7.0.0-dev.20260418.1)(rolldown@1.0.0-rc.16)(typescript@6.0.3) semver: 7.7.4 tinyexec: 1.1.1 tinyglobby: 0.2.16 @@ -15274,7 +14951,7 @@ snapshots: unconfig-core: 7.5.0 unrun: 0.2.36 optionalDependencies: - typescript: 6.0.2 + typescript: 6.0.3 transitivePeerDependencies: - '@ts-macro/tsc' - '@typescript/native-preview' @@ -15303,7 +14980,10 @@ snapshots: typescript@5.9.3: {} - typescript@6.0.2: {} + typescript@6.0.2: + optional: true + + typescript@6.0.3: {} typical@4.0.0: {} diff --git a/scripts/check-timed.mjs b/scripts/check-timed.mjs new file mode 100644 index 00000000000..43d1b5a14e3 --- /dev/null +++ b/scripts/check-timed.mjs @@ -0,0 +1,57 @@ +import { spawnSync } from "node:child_process"; +import { performance } from "node:perf_hooks"; + +const includeArchitecture = process.argv.includes("--include-architecture"); + +const stages = [ + { name: "conflict markers", args: ["check:no-conflict-markers"] }, + { name: "tool display", args: ["tool-display:check"] }, + { name: "host env policy", args: ["check:host-env-policy:swift"] }, + { name: "typecheck", args: ["tsgo:all"] }, + { name: "lint", args: ["lint"] }, + { name: "webhook body guard", args: ["lint:webhook:no-low-level-body-read"] }, + { name: "pairing store guard", args: ["lint:auth:no-pairing-store-group"] }, + { name: "pairing account guard", args: ["lint:auth:pairing-account-scope"] }, + { name: "runtime import cycles", args: ["check:import-cycles"] }, +]; + +if (includeArchitecture) { + stages.push({ name: "architecture import cycles", args: ["check:madge-import-cycles"] }); +} + +const timings = []; +let exitCode = 0; + +for (const { name, args } of stages) { + const startedAt = performance.now(); + console.error(`\n[check:timed] ${name}`); + const result = spawnSync("pnpm", args, { + stdio: "inherit", + shell: process.platform === "win32", + }); + const durationMs = performance.now() - startedAt; + timings.push({ name, durationMs, status: result.status ?? 1 }); + + if (result.error) { + throw result.error; + } + if (result.status !== 0) { + exitCode = result.status ?? 1; + break; + } +} + +console.error("\n[check:timed] summary"); +for (const timing of timings) { + const status = timing.status === 0 ? "ok" : `failed:${timing.status}`; + console.error(`${formatMs(timing.durationMs).padStart(8)} ${status.padEnd(9)} ${timing.name}`); +} + +process.exitCode = exitCode; + +function formatMs(durationMs) { + if (durationMs < 1000) { + return `${Math.round(durationMs)}ms`; + } + return `${(durationMs / 1000).toFixed(2)}s`; +} diff --git a/src/auto-reply/reply.triggers.group-intro-prompts.cases.ts b/src/auto-reply/reply.triggers.group-intro-prompts.cases.ts index 860c023db1e..2ef22af5a40 100644 --- a/src/auto-reply/reply.triggers.group-intro-prompts.cases.ts +++ b/src/auto-reply/reply.triggers.group-intro-prompts.cases.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { makeCfg } from "./reply.triggers.trigger-handling.test-harness.js"; +import { makeCfg } from "../../test/helpers/auto-reply/trigger-handling-test-harness.js"; import { buildGroupChatContext, buildGroupIntro } from "./reply/groups.js"; type GetReplyFromConfig = typeof import("./reply.js").getReplyFromConfig; diff --git a/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts b/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts index d0f6d3edb1f..13a1087fcc9 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.ts @@ -7,7 +7,7 @@ import { makeCfg, requireSessionStorePath, withTempHome, -} from "./reply.triggers.trigger-handling.test-harness.js"; +} from "../../test/helpers/auto-reply/trigger-handling-test-harness.js"; type GetReplyFromConfig = typeof import("./reply.js").getReplyFromConfig; diff --git a/src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts b/src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts index 57dbaec15ef..7ae187d02d4 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts @@ -1,9 +1,6 @@ import fs from "node:fs/promises"; import { join } from "node:path"; import { describe, expect, it, vi } from "vitest"; -import { loadSessionStore, resolveSessionKey } from "../config/sessions.js"; -import { registerGroupIntroPromptCases } from "./reply.triggers.group-intro-prompts.cases.js"; -import { registerTriggerHandlingUsageSummaryCases } from "./reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.js"; import { expectInlineCommandHandledAndStripped, getAbortEmbeddedPiRunMock, @@ -16,7 +13,10 @@ import { requireSessionStorePath, runGreetingPromptForBareNewOrReset, withTempHome, -} from "./reply.triggers.trigger-handling.test-harness.js"; +} from "../../test/helpers/auto-reply/trigger-handling-test-harness.js"; +import { loadSessionStore, resolveSessionKey } from "../config/sessions.js"; +import { registerGroupIntroPromptCases } from "./reply.triggers.group-intro-prompts.cases.js"; +import { registerTriggerHandlingUsageSummaryCases } from "./reply.triggers.trigger-handling.filters-usage-summary-current-model-provider.cases.js"; import { withFullRuntimeReplyConfig } from "./reply/get-reply-fast-path.js"; import { enqueueFollowupRun, getFollowupQueueDepth, type FollowupRun } from "./reply/queue.js"; import { HEARTBEAT_TOKEN } from "./tokens.js"; diff --git a/src/canvas-host/a2ui/.bundle.hash b/src/canvas-host/a2ui/.bundle.hash index ff0514621f1..f9e812b1047 100644 --- a/src/canvas-host/a2ui/.bundle.hash +++ b/src/canvas-host/a2ui/.bundle.hash @@ -1 +1 @@ -2e95c8126f91a618593517cd50e7e96c3b4fa9672c917d761581b49b988bafc4 +d122c7a344b122b9938b5fa578105b4ca5f619f65aa0c1030f42f36c6e52f105 diff --git a/src/channels/plugins/contracts/channel-import-guardrails.test.ts b/src/channels/plugins/contracts/channel-import-guardrails.test.ts index 3bac99b3b6b..07a6d8a8a5f 100644 --- a/src/channels/plugins/contracts/channel-import-guardrails.test.ts +++ b/src/channels/plugins/contracts/channel-import-guardrails.test.ts @@ -44,9 +44,6 @@ const GUARDED_CHANNEL_EXTENSIONS = new Set([ "zalo", "zalouser", ]); -// Shared config validation intentionally consumes this curated Telegram contract. -const ALLOWED_CORE_CHANNEL_SDK_SUBPATHS = new Set(["telegram-command-config"]); - function bundledPluginFile(pluginId: string, relativePath: string): string { const rootDir = bundledPluginRoots.get(pluginId); if (!rootDir) { @@ -509,9 +506,6 @@ function expectCoreSourceStaysOffPluginSpecificSdkFacades(file: string, imports: continue; } const targetSubpath = specifier.split("/plugin-sdk/")[1]?.replace(/\.[cm]?[jt]sx?$/u, "") ?? ""; - if (ALLOWED_CORE_CHANNEL_SDK_SUBPATHS.has(targetSubpath)) { - continue; - } const targetExtensionId = [...GUARDED_CHANNEL_EXTENSIONS].find( (extensionId) => diff --git a/src/config/config.ts b/src/config/config.ts index f2eee8fc96d..45ebd5d56b7 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -12,10 +12,12 @@ export { readBestEffortConfig, readSourceConfigBestEffort, parseConfigJson5, + promoteConfigSnapshotToLastKnownGood, readConfigFileSnapshot, readConfigFileSnapshotForWrite, readSourceConfigSnapshot, readSourceConfigSnapshotForWrite, + recoverConfigFromLastKnownGood, resetConfigRuntimeState, resolveConfigSnapshotHash, setRuntimeConfigSnapshotRefreshHandler, diff --git a/src/config/io.audit.ts b/src/config/io.audit.ts index db40375d381..9bef1969fc4 100644 --- a/src/config/io.audit.ts +++ b/src/config/io.audit.ts @@ -3,7 +3,7 @@ import { resolveStateDir } from "./paths.js"; const CONFIG_AUDIT_LOG_FILENAME = "config-audit.jsonl"; -export type ConfigWriteAuditResult = "rename" | "copy-fallback" | "failed"; +export type ConfigWriteAuditResult = "rename" | "copy-fallback" | "failed" | "rejected"; export type ConfigWriteAuditRecord = { ts: string; @@ -269,7 +269,7 @@ export function finalizeConfigWriteAuditRecord(params: { uid: null, gid: null, }; - const success = params.result !== "failed"; + const success = params.result !== "failed" && params.result !== "rejected"; return { ...params.base, result: params.result, diff --git a/src/config/io.observe-recovery.test.ts b/src/config/io.observe-recovery.test.ts index 623390ed22f..cd74942d19c 100644 --- a/src/config/io.observe-recovery.test.ts +++ b/src/config/io.observe-recovery.test.ts @@ -7,8 +7,12 @@ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { maybeRecoverSuspiciousConfigRead, maybeRecoverSuspiciousConfigReadSync, + promoteConfigSnapshotToLastKnownGood, + recoverConfigFromLastKnownGood, + resolveLastKnownGoodConfigPath, type ObserveRecoveryDeps, } from "./io.observe-recovery.js"; +import type { ConfigFileSnapshot } from "./types.js"; describe("config observe recovery", () => { let fixtureRoot = ""; @@ -33,6 +37,26 @@ describe("config observe recovery", () => { await fsp.writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8"); } + async function makeSnapshot(configPath: string, config: Record) { + const raw = `${JSON.stringify(config, null, 2)}\n`; + await fsp.mkdir(path.dirname(configPath), { recursive: true }); + await fsp.writeFile(configPath, raw, "utf-8"); + return { + path: configPath, + exists: true, + raw, + parsed: config, + sourceConfig: config, + resolved: config, + valid: true, + runtimeConfig: config, + config, + issues: [], + warnings: [], + legacyIssues: [], + } satisfies ConfigFileSnapshot; + } + function makeDeps( home: string, warn = vi.fn(), @@ -158,4 +182,65 @@ describe("config observe recovery", () => { expect(observe?.lastKnownGoodIno ?? null).toBeNull(); }); }); + + it("promotes a valid startup config and restores it after an invalid direct edit", async () => { + await withSuiteHome(async (home) => { + const { deps, configPath, auditPath, warn } = makeDeps(home); + const snapshot = await makeSnapshot(configPath, { + gateway: { mode: "local", auth: { mode: "token", token: "secret-token" } }, + channels: { discord: { enabled: true, dmPolicy: "pairing" } }, + }); + + await expect( + promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + ).resolves.toBe(true); + await expect(fsp.readFile(resolveLastKnownGoodConfigPath(configPath), "utf-8")).resolves.toBe( + snapshot.raw, + ); + + const brokenRaw = "{ gateway: { mode: 123 } }\n"; + await fsp.writeFile(configPath, brokenRaw, "utf-8"); + const restored = await recoverConfigFromLastKnownGood({ + deps, + snapshot: { + ...snapshot, + raw: brokenRaw, + parsed: { gateway: { mode: 123 } }, + valid: false, + issues: [{ path: "gateway.mode", message: "Expected string" }], + }, + reason: "test-invalid-config", + }); + + expect(restored).toBe(true); + await expect(fsp.readFile(configPath, "utf-8")).resolves.toBe(snapshot.raw); + expect(warn).toHaveBeenCalledWith( + expect.stringContaining("Config auto-restored from last-known-good:"), + ); + const lines = (await fsp.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean); + const observe = lines + .map((line) => JSON.parse(line) as Record) + .findLast((line) => line.event === "config.observe"); + expect(observe?.restoredFromBackup).toBe(true); + expect(observe?.restoredBackupPath).toBe(resolveLastKnownGoodConfigPath(configPath)); + }); + }); + + it("refuses to promote redacted secret placeholders", async () => { + await withSuiteHome(async (home) => { + const warn = vi.fn(); + const { deps, configPath } = makeDeps(home, warn); + const snapshot = await makeSnapshot(configPath, { + gateway: { mode: "local", auth: { mode: "token", token: "***" } }, + }); + + await expect( + promoteConfigSnapshotToLastKnownGood({ deps, snapshot, logger: deps.logger }), + ).resolves.toBe(false); + await expect(fsp.stat(resolveLastKnownGoodConfigPath(configPath))).rejects.toThrow(); + expect(warn).toHaveBeenCalledWith( + expect.stringContaining("Config last-known-good promotion skipped"), + ); + }); + }); }); diff --git a/src/config/io.observe-recovery.ts b/src/config/io.observe-recovery.ts index c27488006dc..5f13a47bd51 100644 --- a/src/config/io.observe-recovery.ts +++ b/src/config/io.observe-recovery.ts @@ -7,6 +7,7 @@ import { type ConfigObserveAuditRecord, } from "./io.audit.js"; import { resolveStateDir } from "./paths.js"; +import type { ConfigFileSnapshot } from "./types.openclaw.js"; export type ObserveRecoveryDeps = { fs: { @@ -28,6 +29,7 @@ export type ObserveRecoveryDeps = { options?: { encoding?: BufferEncoding; mode?: number; flag?: string }, ): Promise; copyFile(src: string, dest: string): Promise; + chmod?(path: string, mode: number): Promise; mkdir(path: string, options?: { recursive?: boolean; mode?: number }): Promise; appendFile( path: string, @@ -55,6 +57,7 @@ export type ObserveRecoveryDeps = { options?: { encoding?: BufferEncoding; mode?: number; flag?: string }, ): unknown; copyFileSync(src: string, dest: string): unknown; + chmodSync?(path: string, mode: number): unknown; mkdirSync(path: string, options?: { recursive?: boolean; mode?: number }): unknown; appendFileSync( path: string, @@ -109,6 +112,7 @@ type ConfigStatMetadataSource = type ConfigHealthEntry = { lastKnownGood?: ConfigHealthFingerprint; + lastPromotedGood?: ConfigHealthFingerprint; lastObservedSuspiciousSignature?: string | null; }; @@ -506,6 +510,47 @@ function formatConfigArtifactTimestamp(ts: string): string { return ts.replaceAll(":", "-").replaceAll(".", "-"); } +export function resolveLastKnownGoodConfigPath(configPath: string): string { + return `${configPath}.last-good`; +} + +function isSensitiveConfigPath(pathLabel: string): boolean { + return /(^|\.)(api[-_]?key|auth|bearer|credential|password|private[-_]?key|secret|token)(\.|$)/i.test( + pathLabel, + ); +} + +function collectPollutedSecretPlaceholders( + value: unknown, + pathLabel = "", + output: string[] = [], +): string[] { + if (typeof value === "string") { + const trimmed = value.trim(); + if (trimmed === "***" || trimmed === "[redacted]") { + output.push(pathLabel || ""); + return output; + } + if (isSensitiveConfigPath(pathLabel) && (trimmed.includes("...") || trimmed.includes("…"))) { + output.push(pathLabel || ""); + } + return output; + } + if (Array.isArray(value)) { + value.forEach((item, index) => + collectPollutedSecretPlaceholders(item, `${pathLabel}[${index}]`, output), + ); + return output; + } + if (isRecord(value)) { + for (const [key, child] of Object.entries(value)) { + const childPath = pathLabel ? `${pathLabel}.${key}` : key; + collectPollutedSecretPlaceholders(child, childPath, output); + } + } + return output; +} + async function persistClobberedConfigSnapshot(params: { deps: ObserveRecoveryDeps; configPath: string; @@ -760,6 +805,7 @@ export async function observeConfigSnapshot( if (suspicious.length === 0) { if (snapshot.valid) { const nextEntry: ConfigHealthEntry = { + ...entry, lastKnownGood: current, lastObservedSuspiciousSignature: null, }; @@ -858,6 +904,7 @@ export function observeConfigSnapshotSync( if (suspicious.length === 0) { if (snapshot.valid) { healthState = setConfigHealthEntry(healthState, snapshot.path, { + ...entry, lastKnownGood: current, lastObservedSuspiciousSignature: null, }); @@ -902,3 +949,129 @@ export function observeConfigSnapshotSync( ); writeConfigHealthStateSync(deps, healthState); } + +export async function promoteConfigSnapshotToLastKnownGood(params: { + deps: ObserveRecoveryDeps; + snapshot: ConfigFileSnapshot; + logger?: Pick; +}): Promise { + const { deps, snapshot } = params; + if (!snapshot.exists || !snapshot.valid || typeof snapshot.raw !== "string") { + return false; + } + const polluted = collectPollutedSecretPlaceholders(snapshot.parsed); + if (polluted.length > 0) { + params.logger?.warn( + `Config last-known-good promotion skipped: redacted secret placeholder at ${polluted[0]}`, + ); + return false; + } + const stat = await deps.fs.promises.stat(snapshot.path).catch(() => null); + const now = new Date().toISOString(); + const current = createConfigHealthFingerprint({ + hash: resolveConfigSnapshotHash(snapshot) ?? hashConfigRaw(snapshot.raw), + raw: snapshot.raw, + parsed: snapshot.parsed, + gatewaySource: snapshot.resolved, + stat: stat as ConfigStatMetadataSource, + observedAt: now, + }); + const lastGoodPath = resolveLastKnownGoodConfigPath(snapshot.path); + await deps.fs.promises.writeFile(lastGoodPath, snapshot.raw, { + encoding: "utf-8", + mode: 0o600, + }); + await deps.fs.promises.chmod?.(lastGoodPath, 0o600).catch(() => {}); + const healthState = await readConfigHealthState(deps); + const entry = getConfigHealthEntry(healthState, snapshot.path); + await writeConfigHealthState( + deps, + setConfigHealthEntry(healthState, snapshot.path, { + ...entry, + lastKnownGood: current, + lastPromotedGood: current, + lastObservedSuspiciousSignature: null, + }), + ); + return true; +} + +export async function recoverConfigFromLastKnownGood(params: { + deps: ObserveRecoveryDeps; + snapshot: ConfigFileSnapshot; + reason: string; +}): Promise { + const { deps, snapshot } = params; + if (!snapshot.exists || typeof snapshot.raw !== "string") { + return false; + } + const healthState = await readConfigHealthState(deps); + const entry = getConfigHealthEntry(healthState, snapshot.path); + const promoted = entry.lastPromotedGood; + if (!promoted?.hash) { + return false; + } + const lastGoodPath = resolveLastKnownGoodConfigPath(snapshot.path); + const backupRaw = await deps.fs.promises.readFile(lastGoodPath, "utf-8").catch(() => null); + if (!backupRaw || hashConfigRaw(backupRaw) !== promoted.hash) { + return false; + } + let backupParsed: unknown; + try { + backupParsed = deps.json5.parse(backupRaw); + } catch { + return false; + } + const polluted = collectPollutedSecretPlaceholders(backupParsed); + if (polluted.length > 0) { + deps.logger.warn( + `Config last-known-good recovery skipped: redacted secret placeholder at ${polluted[0]}`, + ); + return false; + } + const now = new Date().toISOString(); + const stat = await deps.fs.promises.stat(snapshot.path).catch(() => null); + const current = createConfigHealthFingerprint({ + hash: resolveConfigSnapshotHash(snapshot) ?? hashConfigRaw(snapshot.raw), + raw: snapshot.raw, + parsed: snapshot.parsed, + gatewaySource: snapshot.resolved, + stat: stat as ConfigStatMetadataSource, + observedAt: now, + }); + const clobberedPath = await persistClobberedConfigSnapshot({ + deps, + configPath: snapshot.path, + raw: snapshot.raw, + observedAt: now, + }); + await deps.fs.promises.copyFile(lastGoodPath, snapshot.path); + await deps.fs.promises.chmod?.(snapshot.path, 0o600).catch(() => {}); + deps.logger.warn( + `Config auto-restored from last-known-good: ${snapshot.path} (${params.reason})`, + ); + await appendConfigAuditRecord( + createConfigObserveAuditAppendParams(deps, { + ts: now, + configPath: snapshot.path, + valid: snapshot.valid, + current, + suspicious: [params.reason], + lastKnownGood: promoted, + backup: promoted, + clobberedPath, + restoredFromBackup: true, + restoredBackupPath: lastGoodPath, + }), + ); + await writeConfigHealthState( + deps, + setConfigHealthEntry(healthState, snapshot.path, { + ...entry, + lastKnownGood: promoted, + lastPromotedGood: promoted, + lastObservedSuspiciousSignature: null, + }), + ); + return true; +} diff --git a/src/config/io.ts b/src/config/io.ts index 3a0d8f583d2..9c8647dff04 100644 --- a/src/config/io.ts +++ b/src/config/io.ts @@ -48,6 +48,8 @@ import { throwInvalidConfig } from "./io.invalid-config.js"; import { maybeRecoverSuspiciousConfigRead, maybeRecoverSuspiciousConfigReadSync, + promoteConfigSnapshotToLastKnownGood as promoteConfigSnapshotToLastKnownGoodWithDeps, + recoverConfigFromLastKnownGood as recoverConfigFromLastKnownGoodWithDeps, } from "./io.observe-recovery.js"; import { persistGeneratedOwnerDisplaySecret } from "./io.owner-display-secret.js"; import { @@ -126,6 +128,7 @@ type ConfigHealthFingerprint = { type ConfigHealthEntry = { lastKnownGood?: ConfigHealthFingerprint; + lastPromotedGood?: ConfigHealthFingerprint; lastObservedSuspiciousSignature?: string | null; }; @@ -160,6 +163,11 @@ export type ConfigWriteOptions = { * the post-write runtime snapshot refresh/reload tail entirely. */ skipRuntimeSnapshotRefresh?: boolean; + /** + * Allow intentionally destructive config writes, such as explicit reset flows. + * Normal writers must keep this false so clobbers are rejected before disk commit. + */ + allowDestructiveWrite?: boolean; }; export type ReadConfigFileSnapshotForWriteResult = { @@ -333,6 +341,12 @@ function resolveConfigWriteSuspiciousReasons(params: { return reasons; } +function resolveConfigWriteBlockingReasons(suspicious: string[]): string[] { + return suspicious.filter( + (reason) => reason.startsWith("size-drop:") || reason === "gateway-mode-removed", + ); +} + async function readConfigHealthState(deps: Required): Promise { try { const healthPath = resolveConfigHealthStatePath(deps.env, deps.homedir); @@ -601,6 +615,7 @@ async function observeConfigSnapshot( if (suspicious.length === 0) { if (snapshot.valid) { const nextEntry: ConfigHealthEntry = { + ...entry, lastKnownGood: current, lastObservedSuspiciousSignature: null, }; @@ -734,6 +749,7 @@ function observeConfigSnapshotSync( if (suspicious.length === 0) { if (snapshot.valid) { const nextEntry: ConfigHealthEntry = { + ...entry, lastKnownGood: current, lastObservedSuspiciousSignature: null, }; @@ -1395,6 +1411,27 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { return result.snapshot; } + async function promoteConfigSnapshotToLastKnownGood( + snapshot: ConfigFileSnapshot, + ): Promise { + return await promoteConfigSnapshotToLastKnownGoodWithDeps({ + deps, + snapshot, + logger: deps.logger, + }); + } + + async function recoverConfigFromLastKnownGood(params: { + snapshot: ConfigFileSnapshot; + reason: string; + }): Promise { + return await recoverConfigFromLastKnownGoodWithDeps({ + deps, + snapshot: params.snapshot, + reason: params.reason, + }); + } + async function readConfigFileSnapshotForWrite(): Promise { const result = await readConfigFileSnapshotInternal(); return { @@ -1656,6 +1693,26 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { }), }); }; + const blockingReasons = resolveConfigWriteBlockingReasons(suspiciousReasons); + if (blockingReasons.length > 0 && options.allowDestructiveWrite !== true) { + const rejectedPath = `${configPath}.rejected.${formatConfigArtifactTimestamp(new Date().toISOString())}`; + await deps.fs.promises + .writeFile(rejectedPath, json, { + encoding: "utf-8", + mode: 0o600, + flag: "wx", + }) + .catch(() => {}); + const message = `Config write rejected: ${configPath} (${blockingReasons.join(", ")}). Rejected payload saved to ${rejectedPath}.`; + const err = Object.assign(new Error(message), { + code: "CONFIG_WRITE_REJECTED", + rejectedPath, + reasons: blockingReasons, + }); + deps.logger.warn(message); + await appendWriteAudit("rejected", err); + throw err; + } const tmp = path.join( dir, @@ -1720,6 +1777,8 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) { readSourceConfigBestEffort, readConfigFileSnapshot, readConfigFileSnapshotForWrite, + promoteConfigSnapshotToLastKnownGood, + recoverConfigFromLastKnownGood, writeConfigFile, }; } @@ -1820,6 +1879,19 @@ export async function readConfigFileSnapshot(): Promise { return await createConfigIO().readConfigFileSnapshot(); } +export async function promoteConfigSnapshotToLastKnownGood( + snapshot: ConfigFileSnapshot, +): Promise { + return await createConfigIO().promoteConfigSnapshotToLastKnownGood(snapshot); +} + +export async function recoverConfigFromLastKnownGood(params: { + snapshot: ConfigFileSnapshot; + reason: string; +}): Promise { + return await createConfigIO().recoverConfigFromLastKnownGood(params); +} + export async function readSourceConfigSnapshot(): Promise { return await readConfigFileSnapshot(); } @@ -1853,6 +1925,7 @@ export async function writeConfigFile( envSnapshotForRestore: options.envSnapshotForRestore, }), unsetPaths: options.unsetPaths, + allowDestructiveWrite: options.allowDestructiveWrite, skipRuntimeSnapshotRefresh: options.skipRuntimeSnapshotRefresh, }); if ( diff --git a/src/config/io.write-config.test.ts b/src/config/io.write-config.test.ts index 14fefab83b9..21653a3bb44 100644 --- a/src/config/io.write-config.test.ts +++ b/src/config/io.write-config.test.ts @@ -233,6 +233,38 @@ describe("config io write", () => { }); }); + it("rejects destructive internal writes before replacing the config", async () => { + await withSuiteHome(async (home) => { + const configPath = path.join(home, ".openclaw", "openclaw.json"); + await fs.mkdir(path.dirname(configPath), { recursive: true }); + const original = { + gateway: { mode: "local" }, + channels: { telegram: { enabled: true, dmPolicy: "pairing" } }, + agents: { list: [{ id: "main", default: true, workspace: "/tmp/openclaw-main" }] }, + tools: { profile: "safe" }, + commands: { ownerDisplay: "hash" }, + }; + await fs.writeFile(configPath, `${JSON.stringify(original, null, 2)}\n`, "utf-8"); + const warn = vi.fn(); + const io = createConfigIO({ + env: { VITEST: "true" } as NodeJS.ProcessEnv, + homedir: () => home, + logger: { warn, error: vi.fn() }, + }); + + await expect(io.writeConfigFile({ update: { channel: "beta" } })).rejects.toMatchObject({ + code: "CONFIG_WRITE_REJECTED", + }); + + await expect(fs.readFile(configPath, "utf-8")).resolves.toBe( + `${JSON.stringify(original, null, 2)}\n`, + ); + const entries = await fs.readdir(path.dirname(configPath)); + expect(entries.some((entry) => entry.includes(".rejected."))).toBe(true); + expect(warn).toHaveBeenCalledWith(expect.stringContaining("Config write rejected:")); + }); + }); + it("does not inject include-only $schema into the root config during partial writes", async () => { await withSuiteHome(async (home) => { const configPath = path.join(home, ".openclaw", "openclaw.json"); diff --git a/src/config/schema.base.generated.ts b/src/config/schema.base.generated.ts index fe89ba1a930..a0cf9dfbac6 100644 --- a/src/config/schema.base.generated.ts +++ b/src/config/schema.base.generated.ts @@ -27471,6 +27471,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = { tags: ["advanced", "url-secret"], }, }, - version: "2026.4.19-beta.2", + version: "2026.4.20", generatedAt: "2026-03-22T21:17:33.302Z", }; diff --git a/src/gateway/config-recovery-notice.test.ts b/src/gateway/config-recovery-notice.test.ts new file mode 100644 index 00000000000..1516aade740 --- /dev/null +++ b/src/gateway/config-recovery-notice.test.ts @@ -0,0 +1,44 @@ +import { afterEach, describe, expect, it } from "vitest"; +import { + drainSystemEvents, + peekSystemEvents, + resetSystemEventsForTest, +} from "../infra/system-events.js"; +import { + enqueueConfigRecoveryNotice, + formatConfigRecoveryNotice, +} from "./config-recovery-notice.js"; + +describe("config recovery notice", () => { + afterEach(() => { + resetSystemEventsForTest(); + }); + + it("formats a prompt-facing warning for recovered configs", () => { + expect( + formatConfigRecoveryNotice({ + phase: "startup", + reason: "startup-invalid-config", + configPath: "/home/test/.openclaw/openclaw.json", + }), + ).toBe( + "Config recovery warning: OpenClaw restored openclaw.json from the last-known-good backup during startup (startup-invalid-config). The rejected config was invalid and was preserved as a timestamped .clobbered.* file. Do not write openclaw.json again unless you validate the full config first.", + ); + }); + + it("queues the notice for the main agent session", () => { + expect( + enqueueConfigRecoveryNotice({ + cfg: {}, + phase: "reload", + reason: "reload-invalid-config", + configPath: "/home/test/.openclaw/openclaw.json", + }), + ).toBe(true); + + expect(peekSystemEvents("agent:main:main")).toHaveLength(1); + expect(drainSystemEvents("agent:main:main")[0]).toContain( + "Do not write openclaw.json again unless you validate the full config first.", + ); + }); +}); diff --git a/src/gateway/config-recovery-notice.ts b/src/gateway/config-recovery-notice.ts new file mode 100644 index 00000000000..ad7e45b2059 --- /dev/null +++ b/src/gateway/config-recovery-notice.ts @@ -0,0 +1,31 @@ +import path from "node:path"; +import { resolveMainSessionKey } from "../config/sessions/main-session.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import { enqueueSystemEvent } from "../infra/system-events.js"; + +export type ConfigRecoveryNoticePhase = "startup" | "reload"; + +export function formatConfigRecoveryNotice(params: { + phase: ConfigRecoveryNoticePhase; + reason: string; + configPath: string; +}): string { + const configName = path.basename(params.configPath) || "openclaw.json"; + return [ + `Config recovery warning: OpenClaw restored ${configName} from the last-known-good backup during ${params.phase} (${params.reason}).`, + "The rejected config was invalid and was preserved as a timestamped .clobbered.* file.", + `Do not write ${configName} again unless you validate the full config first.`, + ].join(" "); +} + +export function enqueueConfigRecoveryNotice(params: { + cfg: OpenClawConfig; + phase: ConfigRecoveryNoticePhase; + reason: string; + configPath: string; +}): boolean { + return enqueueSystemEvent(formatConfigRecoveryNotice(params), { + sessionKey: resolveMainSessionKey(params.cfg), + contextKey: `config-recovery:${params.phase}:${params.reason}`, + }); +} diff --git a/src/gateway/config-reload.test.ts b/src/gateway/config-reload.test.ts index 94a426d6d20..54f2b615f56 100644 --- a/src/gateway/config-reload.test.ts +++ b/src/gateway/config-reload.test.ts @@ -368,7 +368,16 @@ function makeSnapshot(partial: Partial = {}): ConfigFileSnap function createReloaderHarness( readSnapshot: () => Promise, - options: { initialInternalWriteHash?: string | null } = {}, + options: { + initialInternalWriteHash?: string | null; + recoverSnapshot?: (snapshot: ConfigFileSnapshot, reason: string) => Promise; + promoteSnapshot?: (snapshot: ConfigFileSnapshot, reason: string) => Promise; + onRecovered?: (params: { + reason: string; + snapshot: ConfigFileSnapshot; + recoveredSnapshot: ConfigFileSnapshot; + }) => void | Promise; + } = {}, ) { const watcher = createWatcherMock(); vi.spyOn(chokidar, "watch").mockReturnValue(watcher as unknown as never); @@ -392,6 +401,9 @@ function createReloaderHarness( initialConfig: { gateway: { reload: { debounceMs: 0 } } }, initialInternalWriteHash: options.initialInternalWriteHash, readSnapshot, + recoverSnapshot: options.recoverSnapshot, + promoteSnapshot: options.promoteSnapshot, + onRecovered: options.onRecovered, subscribeToWrites, onHotReload, onRestart, @@ -515,6 +527,145 @@ describe("startGatewayConfigReloader", () => { } }); + it("restores last-known-good on invalid external config edits and reloads recovered snapshot", async () => { + const readSnapshot = vi + .fn<() => Promise>() + .mockResolvedValueOnce( + makeSnapshot({ + valid: false, + raw: "{ gateway: { mode: 123 } }", + issues: [{ path: "gateway.mode", message: "Expected string" }], + hash: "bad-1", + }), + ) + .mockResolvedValueOnce( + makeSnapshot({ + config: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + hash: "last-good-1", + }), + ); + const recoverSnapshot = vi.fn(async () => true); + const promoteSnapshot = vi.fn(async () => true); + const onRecovered = vi.fn(); + const { watcher, onHotReload, onRestart, log, reloader } = createReloaderHarness(readSnapshot, { + recoverSnapshot, + promoteSnapshot, + onRecovered, + }); + + watcher.emit("change"); + await vi.runAllTimersAsync(); + + expect(recoverSnapshot).toHaveBeenCalledWith( + expect.objectContaining({ valid: false }), + "invalid-config", + ); + expect(readSnapshot).toHaveBeenCalledTimes(2); + expect(onRecovered).toHaveBeenCalledWith( + expect.objectContaining({ + reason: "invalid-config", + snapshot: expect.objectContaining({ valid: false }), + recoveredSnapshot: expect.objectContaining({ hash: "last-good-1" }), + }), + ); + expect(onHotReload).toHaveBeenCalledTimes(1); + expect(onRestart).not.toHaveBeenCalled(); + expect(promoteSnapshot).toHaveBeenCalledWith( + expect.objectContaining({ hash: "last-good-1" }), + "valid-config", + ); + expect(log.warn).toHaveBeenCalledWith( + "config reload restored last-known-good config after invalid-config", + ); + + await reloader.stop(); + }); + + it("promotes valid external config edits after they are accepted", async () => { + const acceptedSnapshot = makeSnapshot({ + config: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + hash: "external-good-1", + }); + const readSnapshot = vi + .fn<() => Promise>() + .mockResolvedValueOnce(acceptedSnapshot); + const promoteSnapshot = vi.fn(async () => true); + const { watcher, onHotReload, reloader } = createReloaderHarness(readSnapshot, { + promoteSnapshot, + }); + + watcher.emit("change"); + await vi.runAllTimersAsync(); + + expect(onHotReload).toHaveBeenCalledTimes(1); + expect(promoteSnapshot).toHaveBeenCalledWith(acceptedSnapshot, "valid-config"); + + await reloader.stop(); + }); + + it("does not promote external config edits when hot reload rejects them", async () => { + const acceptedSnapshot = makeSnapshot({ + config: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + hash: "external-rejected-1", + }); + const readSnapshot = vi + .fn<() => Promise>() + .mockResolvedValueOnce(acceptedSnapshot); + const promoteSnapshot = vi.fn(async () => true); + const { watcher, onHotReload, log, reloader } = createReloaderHarness(readSnapshot, { + promoteSnapshot, + }); + onHotReload.mockRejectedValueOnce(new Error("reload refused")); + + watcher.emit("change"); + await vi.runAllTimersAsync(); + + expect(onHotReload).toHaveBeenCalledTimes(1); + expect(promoteSnapshot).not.toHaveBeenCalled(); + expect(log.error).toHaveBeenCalledWith("config reload failed: Error: reload refused"); + + await reloader.stop(); + }); + + it("keeps accepted external config reloads applied when last-known-good promotion fails", async () => { + const acceptedSnapshot = makeSnapshot({ + config: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + hash: "external-promotion-fails-1", + }); + const readSnapshot = vi + .fn<() => Promise>() + .mockResolvedValueOnce(acceptedSnapshot); + const promoteSnapshot = vi.fn(async () => { + throw new Error("disk full"); + }); + const { watcher, onHotReload, log, reloader } = createReloaderHarness(readSnapshot, { + promoteSnapshot, + }); + + watcher.emit("change"); + await vi.runAllTimersAsync(); + + expect(onHotReload).toHaveBeenCalledTimes(1); + expect(promoteSnapshot).toHaveBeenCalledWith(acceptedSnapshot, "valid-config"); + expect(log.warn).toHaveBeenCalledWith( + "config reload last-known-good promotion failed: Error: disk full", + ); + + await reloader.stop(); + }); + it("reuses in-process write notifications and dedupes watcher rereads by persisted hash", async () => { const readSnapshot = vi .fn<() => Promise>() @@ -534,6 +685,22 @@ describe("startGatewayConfigReloader", () => { hash: "internal-1", }), ) + .mockResolvedValueOnce( + makeSnapshot({ + sourceConfig: { + gateway: { reload: { debounceMs: 0 } }, + }, + runtimeConfig: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + config: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + hash: "internal-1", + }), + ) .mockResolvedValueOnce( makeSnapshot({ sourceConfig: { @@ -548,7 +715,8 @@ describe("startGatewayConfigReloader", () => { hash: "external-1", }), ); - const harness = createReloaderHarness(readSnapshot); + const promoteSnapshot = vi.fn(async () => true); + const harness = createReloaderHarness(readSnapshot, { promoteSnapshot }); harness.emitWrite({ configPath: "/tmp/openclaw.json", @@ -562,26 +730,68 @@ describe("startGatewayConfigReloader", () => { }); await vi.runOnlyPendingTimersAsync(); - expect(readSnapshot).not.toHaveBeenCalled(); - expect(harness.onHotReload).toHaveBeenCalledTimes(1); - - harness.watcher.emit("change"); - harness.watcher.emit("change"); - await vi.runOnlyPendingTimersAsync(); - expect(readSnapshot).toHaveBeenCalledTimes(1); expect(harness.onHotReload).toHaveBeenCalledTimes(1); + expect(promoteSnapshot).toHaveBeenCalledWith( + expect.objectContaining({ hash: "internal-1" }), + "in-process-write", + ); + harness.watcher.emit("change"); harness.watcher.emit("change"); await vi.runOnlyPendingTimersAsync(); expect(readSnapshot).toHaveBeenCalledTimes(2); expect(harness.onHotReload).toHaveBeenCalledTimes(1); + + harness.watcher.emit("change"); + await vi.runOnlyPendingTimersAsync(); + + expect(readSnapshot).toHaveBeenCalledTimes(3); + expect(harness.onHotReload).toHaveBeenCalledTimes(1); expect(harness.onRestart).toHaveBeenCalledTimes(1); await harness.reloader.stop(); }); + it("skips in-process promotion when the persisted file hash no longer matches the write", async () => { + const readSnapshot = vi.fn<() => Promise>().mockResolvedValueOnce( + makeSnapshot({ + sourceConfig: { + gateway: { reload: { debounceMs: 0 }, port: 19002 }, + }, + runtimeConfig: { + gateway: { reload: { debounceMs: 0 }, port: 19002 }, + }, + config: { + gateway: { reload: { debounceMs: 0 }, port: 19002 }, + }, + hash: "racing-external-edit", + }), + ); + const promoteSnapshot = vi.fn(async () => true); + const harness = createReloaderHarness(readSnapshot, { promoteSnapshot }); + + harness.emitWrite({ + configPath: "/tmp/openclaw.json", + sourceConfig: { gateway: { reload: { debounceMs: 0 } } }, + runtimeConfig: { + gateway: { reload: { debounceMs: 0 } }, + hooks: { enabled: true }, + }, + persistedHash: "internal-1", + writtenAtMs: Date.now(), + }); + await vi.runOnlyPendingTimersAsync(); + + expect(harness.onHotReload).toHaveBeenCalledTimes(1); + expect(readSnapshot).toHaveBeenCalledTimes(1); + expect(promoteSnapshot).not.toHaveBeenCalled(); + expect(harness.log.warn).not.toHaveBeenCalled(); + + await harness.reloader.stop(); + }); + it("dedupes the first watcher reread for startup internal writes", async () => { const readSnapshot = vi .fn<() => Promise>() diff --git a/src/gateway/config-reload.ts b/src/gateway/config-reload.ts index f6bbd48dba2..3e236b6bb95 100644 --- a/src/gateway/config-reload.ts +++ b/src/gateway/config-reload.ts @@ -104,6 +104,13 @@ export function startGatewayConfigReloader(opts: { readSnapshot: () => Promise; onHotReload: (plan: GatewayReloadPlan, nextConfig: OpenClawConfig) => Promise; onRestart: (plan: GatewayReloadPlan, nextConfig: OpenClawConfig) => void | Promise; + recoverSnapshot?: (snapshot: ConfigFileSnapshot, reason: string) => Promise; + promoteSnapshot?: (snapshot: ConfigFileSnapshot, reason: string) => Promise; + onRecovered?: (params: { + reason: string; + snapshot: ConfigFileSnapshot; + recoveredSnapshot: ConfigFileSnapshot; + }) => void | Promise; subscribeToWrites?: (listener: (event: ConfigWriteNotification) => void) => () => void; log: { info: (msg: string) => void; @@ -120,7 +127,7 @@ export function startGatewayConfigReloader(opts: { let stopped = false; let restartQueued = false; let missingConfigRetries = 0; - let pendingInProcessConfig: OpenClawConfig | null = null; + let pendingInProcessConfig: { config: OpenClawConfig; persistedHash: string } | null = null; let lastAppliedWriteHash = opts.initialInternalWriteHash ?? null; const scheduleAfter = (wait: number) => { @@ -180,6 +187,32 @@ export function startGatewayConfigReloader(opts: { return true; }; + const recoverAndReadSnapshot = async ( + snapshot: ConfigFileSnapshot, + reason: string, + ): Promise => { + if (!opts.recoverSnapshot) { + return null; + } + const recovered = await opts.recoverSnapshot(snapshot, reason); + if (!recovered) { + return null; + } + opts.log.warn(`config reload restored last-known-good config after ${reason}`); + const nextSnapshot = await opts.readSnapshot(); + if (!nextSnapshot.valid) { + const issues = formatConfigIssueLines(nextSnapshot.issues, "").join(", "); + opts.log.warn(`config reload recovery snapshot is invalid: ${issues}`); + return null; + } + try { + await opts.onRecovered?.({ reason, snapshot, recoveredSnapshot: nextSnapshot }); + } catch (err) { + opts.log.warn(`config reload recovery notice failed: ${String(err)}`); + } + return nextSnapshot; + }; + const applySnapshot = async (nextConfig: OpenClawConfig) => { const changedPaths = diffConfigPaths(currentConfig, nextConfig); currentConfig = nextConfig; @@ -224,6 +257,32 @@ export function startGatewayConfigReloader(opts: { await opts.onHotReload(plan, nextConfig); }; + const promoteAcceptedSnapshot = async (snapshot: ConfigFileSnapshot, reason: string) => { + if (!opts.promoteSnapshot || !snapshot.exists || !snapshot.valid) { + return; + } + try { + await opts.promoteSnapshot(snapshot, reason); + } catch (err) { + opts.log.warn(`config reload last-known-good promotion failed: ${String(err)}`); + } + }; + + const promoteAcceptedInProcessWrite = async (persistedHash: string) => { + if (!opts.promoteSnapshot) { + return; + } + try { + const snapshot = await opts.readSnapshot(); + if (snapshot.hash !== persistedHash || !snapshot.valid) { + return; + } + await promoteAcceptedSnapshot(snapshot, "in-process-write"); + } catch (err) { + opts.log.warn(`config reload in-process last-known-good promotion failed: ${String(err)}`); + } + }; + const runReload = async () => { if (stopped) { return; @@ -239,13 +298,14 @@ export function startGatewayConfigReloader(opts: { } try { if (pendingInProcessConfig) { - const nextConfig = pendingInProcessConfig; + const pendingWrite = pendingInProcessConfig; pendingInProcessConfig = null; missingConfigRetries = 0; - await applySnapshot(nextConfig); + await applySnapshot(pendingWrite.config); + await promoteAcceptedInProcessWrite(pendingWrite.persistedHash); return; } - const snapshot = await opts.readSnapshot(); + let snapshot = await opts.readSnapshot(); if (lastAppliedWriteHash && typeof snapshot.hash === "string") { if (snapshot.hash === lastAppliedWriteHash) { return; @@ -255,10 +315,16 @@ export function startGatewayConfigReloader(opts: { if (handleMissingSnapshot(snapshot)) { return; } - if (handleInvalidSnapshot(snapshot)) { - return; + if (!snapshot.valid) { + const recoveredSnapshot = await recoverAndReadSnapshot(snapshot, "invalid-config"); + if (!recoveredSnapshot) { + handleInvalidSnapshot(snapshot); + return; + } + snapshot = recoveredSnapshot; } await applySnapshot(snapshot.config); + await promoteAcceptedSnapshot(snapshot, "valid-config"); } catch (err) { opts.log.error(`config reload failed: ${String(err)}`); } finally { @@ -285,7 +351,10 @@ export function startGatewayConfigReloader(opts: { if (event.configPath !== opts.watchPath) { return; } - pendingInProcessConfig = event.runtimeConfig; + pendingInProcessConfig = { + config: event.runtimeConfig, + persistedHash: event.persistedHash, + }; lastAppliedWriteHash = event.persistedHash; scheduleAfter(0); }) ?? (() => {}); diff --git a/src/gateway/server-reload-handlers.ts b/src/gateway/server-reload-handlers.ts index a5696c4ac47..e71663cc007 100644 --- a/src/gateway/server-reload-handlers.ts +++ b/src/gateway/server-reload-handlers.ts @@ -23,6 +23,7 @@ import { } from "../secrets/runtime.js"; import { getInspectableTaskRegistrySummary } from "../tasks/task-registry.maintenance.js"; import type { ChannelHealthMonitor } from "./channel-health-monitor.js"; +import { enqueueConfigRecoveryNotice } from "./config-recovery-notice.js"; import type { ChannelKind } from "./config-reload-plan.js"; import { startGatewayConfigReloader, type GatewayReloadPlan } from "./config-reload.js"; import { resolveHooksConfig } from "./hooks.js"; @@ -82,6 +83,8 @@ type ManagedGatewayConfigReloaderParams = Omit< initialInternalWriteHash: string | null; watchPath: string; readSnapshot: typeof import("../config/config.js").readConfigFileSnapshot; + recoverSnapshot: typeof import("../config/config.js").recoverConfigFromLastKnownGood; + promoteSnapshot: typeof import("../config/config.js").promoteConfigSnapshotToLastKnownGood; subscribeToWrites: typeof import("../config/config.js").registerConfigWriteListener; logReload: GatewayReloadLog & { error: (msg: string) => void; @@ -300,6 +303,17 @@ export function startManagedGatewayConfigReloader(params: ManagedGatewayConfigRe initialConfig: params.initialConfig, initialInternalWriteHash: params.initialInternalWriteHash, readSnapshot: params.readSnapshot, + recoverSnapshot: async (snapshot, reason) => + await params.recoverSnapshot({ snapshot, reason: `reload-${reason}` }), + promoteSnapshot: async (snapshot, _reason) => await params.promoteSnapshot(snapshot), + onRecovered: ({ reason, snapshot, recoveredSnapshot }) => { + enqueueConfigRecoveryNotice({ + cfg: recoveredSnapshot.config, + phase: "reload", + reason: `reload-${reason}`, + configPath: snapshot.path, + }); + }, subscribeToWrites: params.subscribeToWrites, onHotReload: async (plan, nextConfig) => { const previousSharedGatewaySessionGeneration = diff --git a/src/gateway/server-startup-config.recovery.test.ts b/src/gateway/server-startup-config.recovery.test.ts new file mode 100644 index 00000000000..eb1cdbb0629 --- /dev/null +++ b/src/gateway/server-startup-config.recovery.test.ts @@ -0,0 +1,107 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import type { ConfigFileSnapshot, OpenClawConfig } from "../config/types.js"; +import { buildTestConfigSnapshot } from "./test-helpers.config-snapshots.js"; + +vi.mock("../config/config.js", () => ({ + applyConfigOverrides: vi.fn((config: OpenClawConfig) => config), + isNixMode: false, + readConfigFileSnapshot: vi.fn(), + recoverConfigFromLastKnownGood: vi.fn(), + writeConfigFile: vi.fn(), +})); + +vi.mock("./config-recovery-notice.js", () => ({ + enqueueConfigRecoveryNotice: vi.fn(), +})); + +let loadGatewayStartupConfigSnapshot: typeof import("./server-startup-config.js").loadGatewayStartupConfigSnapshot; +let configIo: typeof import("../config/config.js"); +let recoveryNotice: typeof import("./config-recovery-notice.js"); + +const configPath = "/tmp/openclaw-startup-recovery.json"; +const validConfig = { + gateway: { + mode: "local", + }, +} as OpenClawConfig; + +function buildSnapshot(params: { + valid: boolean; + raw: string; + config?: OpenClawConfig; +}): ConfigFileSnapshot { + return buildTestConfigSnapshot({ + path: configPath, + exists: true, + raw: params.raw, + parsed: params.config ?? null, + valid: params.valid, + config: params.config ?? ({} as OpenClawConfig), + issues: params.valid ? [] : [{ path: "gateway.mode", message: "Expected 'local' or 'remote'" }], + legacyIssues: [], + }); +} + +describe("gateway startup config recovery", () => { + beforeAll(async () => { + ({ loadGatewayStartupConfigSnapshot } = await import("./server-startup-config.js")); + configIo = await import("../config/config.js"); + recoveryNotice = await import("./config-recovery-notice.js"); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("restores last-known-good config before startup validation", async () => { + const invalidSnapshot = buildSnapshot({ valid: false, raw: "{ invalid json" }); + const recoveredSnapshot = buildSnapshot({ + valid: true, + raw: `${JSON.stringify(validConfig)}\n`, + config: validConfig, + }); + vi.mocked(configIo.readConfigFileSnapshot) + .mockResolvedValueOnce(invalidSnapshot) + .mockResolvedValueOnce(recoveredSnapshot); + vi.mocked(configIo.recoverConfigFromLastKnownGood).mockResolvedValueOnce(true); + const log = { info: vi.fn(), warn: vi.fn() }; + + await expect( + loadGatewayStartupConfigSnapshot({ + minimalTestGateway: true, + log, + }), + ).resolves.toBe(recoveredSnapshot); + + expect(configIo.recoverConfigFromLastKnownGood).toHaveBeenCalledWith({ + snapshot: invalidSnapshot, + reason: "startup-invalid-config", + }); + expect(log.warn).toHaveBeenCalledWith( + `gateway: invalid config was restored from last-known-good backup: ${configPath}`, + ); + expect(recoveryNotice.enqueueConfigRecoveryNotice).toHaveBeenCalledWith({ + cfg: recoveredSnapshot.config, + phase: "startup", + reason: "startup-invalid-config", + configPath, + }); + }); + + it("keeps startup validation loud when last-known-good recovery is unavailable", async () => { + const invalidSnapshot = buildSnapshot({ valid: false, raw: "{ invalid json" }); + vi.mocked(configIo.readConfigFileSnapshot).mockResolvedValueOnce(invalidSnapshot); + vi.mocked(configIo.recoverConfigFromLastKnownGood).mockResolvedValueOnce(false); + + await expect( + loadGatewayStartupConfigSnapshot({ + minimalTestGateway: true, + log: { info: vi.fn(), warn: vi.fn() }, + }), + ).rejects.toThrow( + `Invalid config at ${configPath}.\ngateway.mode: Expected 'local' or 'remote'\nRun "openclaw doctor --fix" to repair, then retry.`, + ); + + expect(recoveryNotice.enqueueConfigRecoveryNotice).not.toHaveBeenCalled(); + }); +}); diff --git a/src/gateway/server-startup-config.ts b/src/gateway/server-startup-config.ts index c5d9dc1717c..516b1f2d34c 100644 --- a/src/gateway/server-startup-config.ts +++ b/src/gateway/server-startup-config.ts @@ -7,6 +7,7 @@ import { applyConfigOverrides, isNixMode, readConfigFileSnapshot, + recoverConfigFromLastKnownGood, writeConfigFile, } from "../config/config.js"; import { formatConfigIssueLines } from "../config/issue-format.js"; @@ -21,6 +22,7 @@ import { prepareSecretsRuntimeSnapshot, } from "../secrets/runtime.js"; import { resolveGatewayAuth } from "./auth.js"; +import { enqueueConfigRecoveryNotice } from "./config-recovery-notice.js"; import { assertGatewayAuthNotKnownWeak } from "./known-weak-gateway-secrets.js"; import { ensureGatewayStartupAuth, @@ -60,6 +62,26 @@ export async function loadGatewayStartupConfigSnapshot(params: { ); } if (configSnapshot.exists) { + if (!configSnapshot.valid) { + const recovered = await recoverConfigFromLastKnownGood({ + snapshot: configSnapshot, + reason: "startup-invalid-config", + }); + if (recovered) { + params.log.warn( + `gateway: invalid config was restored from last-known-good backup: ${configSnapshot.path}`, + ); + configSnapshot = await readConfigFileSnapshot(); + if (configSnapshot.valid) { + enqueueConfigRecoveryNotice({ + cfg: configSnapshot.config, + phase: "startup", + reason: "startup-invalid-config", + configPath: configSnapshot.path, + }); + } + } + } assertValidGatewayStartupConfigSnapshot(configSnapshot, { includeDoctorHint: true }); } diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index 2bbc3367c0a..7611810e678 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -10,7 +10,9 @@ import { getRuntimeConfig, isNixMode, loadConfig, + promoteConfigSnapshotToLastKnownGood, readConfigFileSnapshot, + recoverConfigFromLastKnownGood, registerConfigWriteListener, writeConfigFile, } from "../config/config.js"; @@ -243,6 +245,7 @@ export async function startGatewayServer( let cfgAtStart: OpenClawConfig; let startupInternalWriteHash: string | null = null; + let startupLastGoodSnapshot = configSnapshot; const startupRuntimeConfig = applyConfigOverrides(configSnapshot.config); const authBootstrap = await prepareGatewayStartupConfig({ configSnapshot, @@ -294,6 +297,7 @@ export async function startGatewayServer( { const startupSnapshot = await readConfigFileSnapshot(); startupInternalWriteHash = startupSnapshot.hash ?? null; + startupLastGoodSnapshot = startupSnapshot; } const pluginBootstrap = await prepareGatewayPluginBootstrap({ cfgAtStart, @@ -782,6 +786,8 @@ export async function startGatewayServer( initialInternalWriteHash: startupInternalWriteHash, watchPath: configSnapshot.path, readSnapshot: readConfigFileSnapshot, + recoverSnapshot: recoverConfigFromLastKnownGood, + promoteSnapshot: promoteConfigSnapshotToLastKnownGood, subscribeToWrites: registerConfigWriteListener, deps, broadcast, @@ -812,6 +818,9 @@ export async function startGatewayServer( sharedGatewaySessionGenerationState, clients, }); + await promoteConfigSnapshotToLastKnownGood(startupLastGoodSnapshot).catch((err) => { + log.warn(`gateway: failed to promote config last-known-good backup: ${String(err)}`); + }); } catch (err) { await closeOnStartupFailure(); throw err; diff --git a/src/infra/outbound/outbound-session.ts b/src/infra/outbound/outbound-session.ts index cbe91ae4ddd..d622c21b31c 100644 --- a/src/infra/outbound/outbound-session.ts +++ b/src/infra/outbound/outbound-session.ts @@ -7,9 +7,10 @@ import { resolveStorePath, } from "../../config/sessions/inbound.runtime.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; -import { buildAgentSessionKey, type RoutePeer } from "../../routing/resolve-route.js"; +import type { RoutePeer } from "../../routing/resolve-route.js"; import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js"; +import { buildOutboundBaseSessionKey } from "./base-session-key.js"; import type { ResolvedMessagingTarget } from "./target-resolver.js"; export type OutboundSessionRoute = { @@ -76,23 +77,6 @@ function inferPeerKind(params: { return "direct"; } -function buildBaseSessionKey(params: { - cfg: OpenClawConfig; - agentId: string; - channel: ChannelId; - accountId?: string | null; - peer: RoutePeer; -}): string { - return buildAgentSessionKey({ - agentId: params.agentId, - channel: params.channel, - accountId: params.accountId, - peer: params.peer, - dmScope: params.cfg.session?.dmScope ?? "main", - identityLinks: params.cfg.session?.identityLinks, - }); -} - function resolveFallbackSession( params: ResolveOutboundSessionRouteParams, ): OutboundSessionRoute | null { @@ -109,7 +93,7 @@ function resolveFallbackSession( return null; } const peer: RoutePeer = { kind: peerKind, id: peerId }; - const baseSessionKey = buildBaseSessionKey({ + const baseSessionKey = buildOutboundBaseSessionKey({ cfg: params.cfg, agentId: params.agentId, channel: params.channel, diff --git a/src/plugin-sdk/testing.ts b/src/plugin-sdk/testing.ts index b8d677fb277..f2fc5290e92 100644 --- a/src/plugin-sdk/testing.ts +++ b/src/plugin-sdk/testing.ts @@ -52,11 +52,6 @@ export { installCommonResolveTargetErrorCases } from "../test-helpers/resolve-ta export { sanitizeTerminalText } from "../terminal/safe-text.js"; export { withStateDirEnv } from "../test-helpers/state-dir-env.js"; export { countLines, hasBalancedFences } from "../test-utils/chunk-test-helpers.js"; -export { - loadBundledPluginPublicSurfaceSync, - loadBundledPluginTestApiSync, - resolveRelativeBundledPluginPublicModuleId, -} from "../test-utils/bundled-plugin-public-surface.js"; export { expectGeneratedTokenPersistedToGatewayAuth } from "../test-utils/auth-token-assertions.js"; export { captureEnv, withEnv, withEnvAsync } from "../test-utils/env.js"; export { withFetchPreconnect, type FetchMock } from "../test-utils/fetch-mock.js"; diff --git a/src/plugins/contracts/boundary-invariants.test.ts b/src/plugins/contracts/boundary-invariants.test.ts index 7508e234ddd..1f23bbe2e93 100644 --- a/src/plugins/contracts/boundary-invariants.test.ts +++ b/src/plugins/contracts/boundary-invariants.test.ts @@ -8,33 +8,6 @@ const REPO_ROOT = resolve(SRC_ROOT, ".."); const sourceCache = new Map(); const tsFilesCache = new Map(); -const ALLOWED_BUNDLED_CAPABILITY_METADATA_CONSUMERS = new Set([ - "src/media-generation/provider-capabilities.contract.test.ts", - "src/plugins/bundled-capability-metadata.test.ts", - "src/plugins/contracts/boundary-invariants.test.ts", -]); - -const ALLOWED_EXTENSION_PATH_STRING_TESTS = new Set([ - "src/plugin-sdk/browser-maintenance.test.ts", - "src/channels/plugins/bundled.shape-guard.test.ts", - "src/cli/capability-cli.test.ts", - "src/commands/doctor-legacy-config.migrations.test.ts", - "src/plugins/contracts/bundled-extension-config-api-guardrails.test.ts", - "src/scripts/test-projects.test.ts", -]); - -const ALLOWED_CONTRACT_BUNDLED_PATH_HELPERS = new Set([ - "src/plugins/contracts/boundary-invariants.test.ts", - "src/plugins/contracts/plugin-sdk-index.bundle.test.ts", - "src/plugins/contracts/plugin-sdk-runtime-api-guardrails.test.ts", -]); - -const ALLOWED_CHANNEL_BUNDLED_METADATA_CONSUMERS = new Set([ - "src/channels/plugins/bundled.ts", - "src/channels/plugins/contracts/runtime-artifacts.ts", - "src/channels/plugins/session-conversation.bundled-fallback.test.ts", -]); - type FileFilter = { excludeTests?: boolean; testOnly?: boolean; @@ -90,7 +63,11 @@ describe("plugin contract boundary invariants", () => { it("keeps bundled-capability-metadata confined to contract/test inventory", () => { const files = listTsFiles("src"); const offenders = files.filter((file) => { - if (ALLOWED_BUNDLED_CAPABILITY_METADATA_CONSUMERS.has(file)) { + if ( + file === "src/plugins/contracts/boundary-invariants.test.ts" || + file.endsWith(".contract.test.ts") || + file.endsWith("-capability-metadata.test.ts") + ) { return false; } return readRepoSource(file).includes("contracts/inventory/bundled-capability-metadata"); @@ -109,9 +86,6 @@ describe("plugin contract boundary invariants", () => { it("keeps core tests off bundled extension deep imports", () => { const files = listTsFiles("src", { testOnly: true }); const offenders = files.filter((file) => { - if (ALLOWED_EXTENSION_PATH_STRING_TESTS.has(file)) { - return false; - } const source = readRepoSource(file); return ( /from\s+["'][^"']*extensions\/.+(?:api|runtime-api|test-api)\.js["']/u.test(source) || @@ -125,7 +99,7 @@ describe("plugin contract boundary invariants", () => { it("keeps plugin contract tests off bundled path helpers unless the test is explicitly about paths", () => { const files = listTsFiles("src/plugins/contracts", { testOnly: true }); const offenders = files.filter((file) => { - if (ALLOWED_CONTRACT_BUNDLED_PATH_HELPERS.has(file)) { + if (file === "src/plugins/contracts/boundary-invariants.test.ts") { return false; } return readRepoSource(file).includes("test/helpers/bundled-plugin-paths"); @@ -136,9 +110,6 @@ describe("plugin contract boundary invariants", () => { it("keeps channel production code off bundled-plugin-metadata helpers", () => { const files = listTsFiles("src/channels", { excludeTests: true }); const offenders = files.filter((file) => { - if (ALLOWED_CHANNEL_BUNDLED_METADATA_CONSUMERS.has(file)) { - return false; - } return readRepoSource(file).includes("plugins/bundled-plugin-metadata"); }); expect(offenders).toEqual([]); diff --git a/src/plugins/contracts/provider-vitest-registry.ts b/src/plugins/contracts/provider-vitest-registry.ts deleted file mode 100644 index 061a786be10..00000000000 --- a/src/plugins/contracts/provider-vitest-registry.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { loadBundledPluginApiSync } from "../../test-utils/bundled-plugin-public-surface.js"; -import type { ProviderPlugin } from "../types.js"; - -export type ProviderContractEntry = { - pluginId: string; - provider: ProviderPlugin; -}; - -let providerContractRegistryCache: ProviderContractEntry[] | null = null; - -type ProviderApiSurface = Record ProviderPlugin>; -type AnthropicApiSurface = ProviderApiSurface<"buildAnthropicProvider">; -type GoogleApiSurface = ProviderApiSurface<"buildGoogleProvider" | "buildGoogleGeminiCliProvider">; -type OpenAIApiSurface = ProviderApiSurface< - "buildOpenAIProvider" | "buildOpenAICodexProviderPlugin" ->; - -export function loadVitestProviderContractRegistry(): ProviderContractEntry[] { - const anthropicApi = loadBundledPluginApiSync("anthropic"); - const googleApi = loadBundledPluginApiSync("google"); - const openAIApi = loadBundledPluginApiSync("openai"); - providerContractRegistryCache ??= [ - { pluginId: "anthropic", provider: anthropicApi.buildAnthropicProvider() }, - { pluginId: "google", provider: googleApi.buildGoogleProvider() }, - { pluginId: "google", provider: googleApi.buildGoogleGeminiCliProvider() }, - { pluginId: "openai", provider: openAIApi.buildOpenAIProvider() }, - { pluginId: "openai", provider: openAIApi.buildOpenAICodexProviderPlugin() }, - ]; - return providerContractRegistryCache; -} diff --git a/src/plugins/contracts/registry.retry.test.ts b/src/plugins/contracts/registry.retry.test.ts index 3421aedda94..4a3244ad635 100644 --- a/src/plugins/contracts/registry.retry.test.ts +++ b/src/plugins/contracts/registry.retry.test.ts @@ -46,32 +46,32 @@ describe("plugin contract registry scoped retries", () => { .mockReturnValueOnce( createMockRuntimeRegistry({ plugin: { - id: "xai", + id: "arcee", status: "error", - error: "transient xai load failure", + error: "transient arcee load failure", providerIds: [], webFetchProviderIds: [], webSearchProviderIds: [], }, - diagnostics: [{ pluginId: "xai", message: "transient xai load failure" }], + diagnostics: [{ pluginId: "arcee", message: "transient arcee load failure" }], }), ) .mockReturnValueOnce( createMockRuntimeRegistry({ plugin: { - id: "xai", + id: "arcee", status: "loaded", - providerIds: ["xai"], + providerIds: ["arcee"], webFetchProviderIds: [], - webSearchProviderIds: ["grok"], + webSearchProviderIds: [], }, providers: [ { - pluginId: "xai", + pluginId: "arcee", provider: { - id: "xai", - label: "xAI", - docsPath: "/providers/xai", + id: "arcee", + label: "Arcee", + docsPath: "/providers/arcee", auth: [], } as ProviderPlugin, }, @@ -82,12 +82,15 @@ describe("plugin contract registry scoped retries", () => { vi.doMock("../bundled-capability-runtime.js", () => ({ loadBundledCapabilityRuntimeRegistry, })); + vi.doMock("../provider-contract-public-artifacts.js", () => ({ + resolveBundledExplicitProviderContractsFromPublicArtifacts: () => null, + })); const { resolveProviderContractProvidersForPluginIds } = await import("./registry.js"); expect( - resolveProviderContractProvidersForPluginIds(["xai"]).map((provider) => provider.id), - ).toEqual(["xai"]); + resolveProviderContractProvidersForPluginIds(["arcee"]).map((provider) => provider.id), + ).toEqual(["arcee"]); expect(loadBundledCapabilityRuntimeRegistry).toHaveBeenCalledTimes(2); }); @@ -97,36 +100,36 @@ describe("plugin contract registry scoped retries", () => { .mockReturnValueOnce( createMockRuntimeRegistry({ plugin: { - id: "xai", + id: "searxng", status: "error", - error: "transient grok load failure", + error: "transient searxng load failure", providerIds: [], webFetchProviderIds: [], webSearchProviderIds: [], }, - diagnostics: [{ pluginId: "xai", message: "transient grok load failure" }], + diagnostics: [{ pluginId: "searxng", message: "transient searxng load failure" }], }), ) .mockReturnValueOnce( createMockRuntimeRegistry({ plugin: { - id: "xai", + id: "searxng", status: "loaded", - providerIds: ["xai"], + providerIds: [], webFetchProviderIds: [], - webSearchProviderIds: ["grok"], + webSearchProviderIds: ["searxng"], }, webSearchProviders: [ { - pluginId: "xai", + pluginId: "searxng", provider: { - id: "grok", - label: "Grok Search", - hint: "Search the web with Grok", - envVars: ["XAI_API_KEY"], - placeholder: "XAI_API_KEY", - signupUrl: "https://x.ai", - credentialPath: "plugins.entries.xai.config.webSearch.apiKey", + id: "searxng", + label: "SearXNG", + hint: "Search the web with SearXNG", + envVars: ["SEARXNG_URL"], + placeholder: "https://search.example.test", + signupUrl: "https://docs.searxng.org", + credentialPath: "plugins.entries.searxng.config.webSearch.url", requiresCredential: true, getCredentialValue: () => undefined, setCredentialValue() {}, @@ -144,12 +147,17 @@ describe("plugin contract registry scoped retries", () => { vi.doMock("../bundled-capability-runtime.js", () => ({ loadBundledCapabilityRuntimeRegistry, })); + vi.doMock("../web-provider-public-artifacts.explicit.js", () => ({ + resolveBundledExplicitWebSearchProvidersFromPublicArtifacts: () => null, + })); const { resolveWebSearchProviderContractEntriesForPluginId } = await import("./registry.js"); expect( - resolveWebSearchProviderContractEntriesForPluginId("xai").map((entry) => entry.provider.id), - ).toEqual(["grok"]); + resolveWebSearchProviderContractEntriesForPluginId("searxng").map( + (entry) => entry.provider.id, + ), + ).toEqual(["searxng"]); expect(loadBundledCapabilityRuntimeRegistry).toHaveBeenCalledTimes(2); }); @@ -180,6 +188,9 @@ describe("plugin contract registry scoped retries", () => { vi.doMock("../bundled-capability-runtime.js", () => ({ loadBundledCapabilityRuntimeRegistry, })); + vi.doMock("../provider-contract-public-artifacts.js", () => ({ + resolveBundledExplicitProviderContractsFromPublicArtifacts: () => null, + })); const { requireProviderContractProvider } = await import("./registry.js"); @@ -189,9 +200,9 @@ describe("plugin contract registry scoped retries", () => { it("uses provider public artifacts before falling back to the bundled runtime registry", async () => { const loadBundledCapabilityRuntimeRegistry = vi.fn(() => { - throw new Error("provider contract vitest fast path should not hit bundled runtime registry"); + throw new Error("provider contract public artifact should not hit bundled runtime registry"); }); - const loadVitestProviderContractRegistry = vi.fn(() => [ + const resolveBundledExplicitProviderContractsFromPublicArtifacts = vi.fn(() => [ { pluginId: "openai", provider: { @@ -229,8 +240,8 @@ describe("plugin contract registry scoped retries", () => { vi.doMock("../bundled-capability-runtime.js", () => ({ loadBundledCapabilityRuntimeRegistry, })); - vi.doMock("./provider-vitest-registry.js", () => ({ - loadVitestProviderContractRegistry, + vi.doMock("../provider-contract-public-artifacts.js", () => ({ + resolveBundledExplicitProviderContractsFromPublicArtifacts, })); const { resolveProviderContractProvidersForPluginIds } = await import("./registry.js"); @@ -238,24 +249,34 @@ describe("plugin contract registry scoped retries", () => { expect( resolveProviderContractProvidersForPluginIds(["openai"]).map((provider) => provider.id), ).toEqual(["openai", "openai-codex"]); - expect(loadVitestProviderContractRegistry).toHaveBeenCalledTimes(1); + expect(resolveBundledExplicitProviderContractsFromPublicArtifacts).toHaveBeenCalledTimes(1); expect(loadBundledCapabilityRuntimeRegistry).not.toHaveBeenCalled(); }); it("uses web search public artifacts before falling back to the bundled runtime registry", async () => { const loadBundledCapabilityRuntimeRegistry = vi.fn(() => { throw new Error( - "web search contract vitest fast path should not hit bundled runtime registry", + "web search contract public artifact should not hit bundled runtime registry", ); }); - const loadVitestWebSearchProviderContractRegistry = vi.fn(() => [ + const resolveBundledExplicitWebSearchProvidersFromPublicArtifacts = vi.fn(() => [ { pluginId: "google", - provider: { - id: "gemini", - label: "Gemini", - credentialPath: "plugins.entries.google.config.webSearch.apiKey", - } as WebSearchProviderPlugin, + id: "gemini", + label: "Gemini", + hint: "Search with Gemini", + envVars: ["GEMINI_API_KEY"], + placeholder: "GEMINI_API_KEY", + signupUrl: "https://aistudio.google.com", + credentialPath: "plugins.entries.google.config.webSearch.apiKey", + requiresCredential: true, + getCredentialValue: () => undefined, + setCredentialValue() {}, + createTool: () => ({ + description: "search", + parameters: {}, + execute: async () => ({}), + }), credentialValue: "AIzaSyDUMMY", }, ]); @@ -263,8 +284,8 @@ describe("plugin contract registry scoped retries", () => { vi.doMock("../bundled-capability-runtime.js", () => ({ loadBundledCapabilityRuntimeRegistry, })); - vi.doMock("./web-provider-vitest-registry.js", () => ({ - loadVitestWebSearchProviderContractRegistry, + vi.doMock("../web-provider-public-artifacts.explicit.js", () => ({ + resolveBundledExplicitWebSearchProvidersFromPublicArtifacts, })); const { resolveWebSearchProviderContractEntriesForPluginId } = await import("./registry.js"); @@ -274,7 +295,7 @@ describe("plugin contract registry scoped retries", () => { (entry) => entry.provider.id, ), ).toEqual(["gemini"]); - expect(loadVitestWebSearchProviderContractRegistry).toHaveBeenCalledTimes(1); + expect(resolveBundledExplicitWebSearchProvidersFromPublicArtifacts).toHaveBeenCalledTimes(1); expect(loadBundledCapabilityRuntimeRegistry).not.toHaveBeenCalled(); }); diff --git a/src/plugins/contracts/registry.ts b/src/plugins/contracts/registry.ts index 3a82a78beb3..f6ea0be6ee8 100644 --- a/src/plugins/contracts/registry.ts +++ b/src/plugins/contracts/registry.ts @@ -4,6 +4,7 @@ import { loadPluginManifestRegistry, resolveManifestContractPluginIds, } from "../manifest-registry.js"; +import { resolveBundledExplicitProviderContractsFromPublicArtifacts } from "../provider-contract-public-artifacts.js"; import type { ImageGenerationProviderPlugin, MediaUnderstandingProviderPlugin, @@ -16,8 +17,8 @@ import type { WebFetchProviderPlugin, WebSearchProviderPlugin, } from "../types.js"; +import { resolveBundledExplicitWebSearchProvidersFromPublicArtifacts } from "../web-provider-public-artifacts.explicit.js"; import { BUNDLED_PLUGIN_CONTRACT_SNAPSHOTS } from "./inventory/bundled-capability-metadata.js"; -import { loadVitestProviderContractRegistry } from "./provider-vitest-registry.js"; import { uniqueStrings } from "./shared.js"; import { loadVitestImageGenerationProviderContractRegistry, @@ -28,7 +29,6 @@ import { loadVitestSpeechProviderContractRegistry, loadVitestVideoGenerationProviderContractRegistry, } from "./speech-vitest-registry.js"; -import { loadVitestWebSearchProviderContractRegistry } from "./web-provider-vitest-registry.js"; type BundledCapabilityRuntimeRegistry = ReturnType; type CapabilityContractEntry = { @@ -316,14 +316,12 @@ function loadProviderContractEntriesForPluginId(pluginId: string): ProviderContr return cached; } - if (process.env.VITEST) { - const vitestEntries = loadVitestProviderContractRegistry().filter( - (entry) => entry.pluginId === pluginId, - ); - if (vitestEntries.length > 0) { - cache.set(pluginId, vitestEntries); - return vitestEntries; - } + const publicArtifactEntries = resolveBundledExplicitProviderContractsFromPublicArtifacts({ + onlyPluginIds: [pluginId], + }); + if (publicArtifactEntries) { + cache.set(pluginId, publicArtifactEntries); + return publicArtifactEntries; } try { @@ -356,8 +354,14 @@ function loadProviderContractRegistry(): ProviderContractEntry[] { if (!providerContractRegistryCache) { try { providerContractLoadError = undefined; - const vitestEntries = process.env.VITEST ? loadVitestProviderContractRegistry() : []; - const coveredPluginIds = new Set(vitestEntries.map((entry) => entry.pluginId)); + const pluginIds = resolveBundledProviderContractPluginIds(); + const publicArtifactEntries = pluginIds.flatMap( + (pluginId) => + resolveBundledExplicitProviderContractsFromPublicArtifacts({ + onlyPluginIds: [pluginId], + }) ?? [], + ); + const coveredPluginIds = new Set(publicArtifactEntries.map((entry) => entry.pluginId)); const remainingPluginIds = resolveBundledProviderContractPluginIds().filter( (pluginId) => !coveredPluginIds.has(pluginId), ); @@ -371,7 +375,7 @@ function loadProviderContractRegistry(): ProviderContractEntry[] { provider: entry.provider, })) : []; - providerContractRegistryCache = [...vitestEntries, ...runtimeEntries]; + providerContractRegistryCache = [...publicArtifactEntries, ...runtimeEntries]; } catch (error) { providerContractLoadError = error instanceof Error ? error : new Error(String(error)); providerContractRegistryCache = []; @@ -475,8 +479,19 @@ export function resolveWebFetchProviderContractEntriesForPluginId( function loadWebSearchProviderContractRegistry(): WebSearchProviderContractEntry[] { if (!webSearchProviderContractRegistryCache) { - const vitestEntries = process.env.VITEST ? loadVitestWebSearchProviderContractRegistry() : []; - const coveredPluginIds = new Set(vitestEntries.map((entry) => entry.pluginId)); + const pluginIds = resolveBundledManifestContractPluginIds("webSearchProviders"); + const publicArtifactEntries = pluginIds.flatMap((pluginId) => + ( + resolveBundledExplicitWebSearchProvidersFromPublicArtifacts({ + onlyPluginIds: [pluginId], + }) ?? [] + ).map((provider) => ({ + pluginId: provider.pluginId, + provider, + credentialValue: resolveWebSearchCredentialValue(provider), + })), + ); + const coveredPluginIds = new Set(publicArtifactEntries.map((entry) => entry.pluginId)); const remainingPluginIds = resolveBundledManifestContractPluginIds("webSearchProviders").filter( (pluginId) => !coveredPluginIds.has(pluginId), ); @@ -491,7 +506,7 @@ function loadWebSearchProviderContractRegistry(): WebSearchProviderContractEntry credentialValue: resolveWebSearchCredentialValue(entry.provider), })) : []; - webSearchProviderContractRegistryCache = [...vitestEntries, ...runtimeEntries]; + webSearchProviderContractRegistryCache = [...publicArtifactEntries, ...runtimeEntries]; } return webSearchProviderContractRegistryCache; } @@ -512,14 +527,16 @@ export function resolveWebSearchProviderContractEntriesForPluginId( return cached; } - if (process.env.VITEST) { - const vitestEntries = loadVitestWebSearchProviderContractRegistry().filter( - (entry) => entry.pluginId === pluginId, - ); - if (vitestEntries.length > 0) { - cache.set(pluginId, vitestEntries); - return vitestEntries; - } + const publicArtifactEntries = resolveBundledExplicitWebSearchProvidersFromPublicArtifacts({ + onlyPluginIds: [pluginId], + })?.map((provider) => ({ + pluginId: provider.pluginId, + provider, + credentialValue: resolveWebSearchCredentialValue(provider), + })); + if (publicArtifactEntries) { + cache.set(pluginId, publicArtifactEntries); + return publicArtifactEntries; } const entries = loadScopedCapabilityRuntimeRegistryEntries({ diff --git a/src/plugins/contracts/web-provider-vitest-registry.ts b/src/plugins/contracts/web-provider-vitest-registry.ts deleted file mode 100644 index 416513ba520..00000000000 --- a/src/plugins/contracts/web-provider-vitest-registry.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { loadBundledPluginPublicSurfaceSync } from "../../test-utils/bundled-plugin-public-surface.js"; -import type { WebSearchProviderPlugin } from "../types.js"; - -export type WebSearchProviderContractEntry = { - pluginId: string; - provider: WebSearchProviderPlugin; - credentialValue: unknown; -}; - -let webSearchProviderContractRegistryCache: WebSearchProviderContractEntry[] | null = null; - -type GoogleWebSearchContractApiSurface = { - createGeminiWebSearchProvider: () => WebSearchProviderPlugin; -}; - -export function loadVitestWebSearchProviderContractRegistry(): WebSearchProviderContractEntry[] { - const googleWebSearchContractApi = - loadBundledPluginPublicSurfaceSync({ - pluginId: "google", - artifactBasename: "web-search-contract-api.js", - }); - webSearchProviderContractRegistryCache ??= [ - { - pluginId: "google", - provider: googleWebSearchContractApi.createGeminiWebSearchProvider(), - credentialValue: "AIzaSyDUMMY", - }, - ]; - return webSearchProviderContractRegistryCache; -} diff --git a/src/plugins/provider-contract-public-artifacts.ts b/src/plugins/provider-contract-public-artifacts.ts new file mode 100644 index 00000000000..bcd9cf1dcbe --- /dev/null +++ b/src/plugins/provider-contract-public-artifacts.ts @@ -0,0 +1,81 @@ +import { loadBundledPluginPublicArtifactModuleSync } from "./public-surface-loader.js"; +import type { ProviderPlugin } from "./types.js"; + +type ProviderContractEntry = { + pluginId: string; + provider: ProviderPlugin; +}; + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function isProviderPlugin(value: unknown): value is ProviderPlugin { + return ( + isRecord(value) && + typeof value.id === "string" && + typeof value.label === "string" && + Array.isArray(value.auth) + ); +} + +function tryLoadProviderContractApi(pluginId: string): Record | null { + try { + return loadBundledPluginPublicArtifactModuleSync>({ + dirName: pluginId, + artifactBasename: "provider-contract-api.js", + }); + } catch (error) { + if ( + error instanceof Error && + error.message.startsWith("Unable to resolve bundled plugin public surface ") + ) { + return null; + } + throw error; + } +} + +function collectProviderContractEntries(params: { + pluginId: string; + mod: Record; +}): ProviderContractEntry[] { + const providers: ProviderContractEntry[] = []; + for (const [name, exported] of Object.entries(params.mod).toSorted(([left], [right]) => + left.localeCompare(right), + )) { + if ( + typeof exported !== "function" || + exported.length !== 0 || + !name.startsWith("create") || + !name.endsWith("Provider") + ) { + continue; + } + const candidate = exported(); + if (isProviderPlugin(candidate)) { + providers.push({ pluginId: params.pluginId, provider: candidate }); + } + } + return providers; +} + +export function resolveBundledExplicitProviderContractsFromPublicArtifacts(params: { + onlyPluginIds: readonly string[]; +}): ProviderContractEntry[] | null { + const providers: ProviderContractEntry[] = []; + for (const pluginId of [...new Set(params.onlyPluginIds)].toSorted((left, right) => + left.localeCompare(right), + )) { + const mod = tryLoadProviderContractApi(pluginId); + if (!mod) { + return null; + } + const entries = collectProviderContractEntries({ pluginId, mod }); + if (entries.length === 0) { + return null; + } + providers.push(...entries); + } + return providers; +} diff --git a/src/plugins/web-provider-public-artifacts.explicit.ts b/src/plugins/web-provider-public-artifacts.explicit.ts index db8c87ee13f..7a096d784fa 100644 --- a/src/plugins/web-provider-public-artifacts.explicit.ts +++ b/src/plugins/web-provider-public-artifacts.explicit.ts @@ -107,21 +107,24 @@ function normalizeExplicitBundledPluginIds(pluginIds: readonly string[]): string return [...new Set(pluginIds)].toSorted((left, right) => left.localeCompare(right)); } -export function loadBundledWebSearchProviderEntriesFromDir(params: { +function loadBundledProviderEntriesFromDir(params: { dirName: string; pluginId: string; -}): PluginWebSearchProviderEntry[] | null { + artifactCandidates: readonly string[]; + suffix: string; + isProvider: (value: unknown) => value is TProvider; +}): Array | null { const mod = tryLoadBundledPublicArtifactModule({ dirName: params.dirName, - artifactCandidates: WEB_SEARCH_ARTIFACT_CANDIDATES, + artifactCandidates: params.artifactCandidates, }); if (!mod) { return null; } const providers = collectProviderFactories({ mod, - suffix: "WebSearchProvider", - isProvider: isWebSearchProviderPlugin, + suffix: params.suffix, + isProvider: params.isProvider, }); if (providers.length === 0) { return null; @@ -129,48 +132,43 @@ export function loadBundledWebSearchProviderEntriesFromDir(params: { return providers.map((provider) => Object.assign({}, provider, { pluginId: params.pluginId })); } +export function loadBundledWebSearchProviderEntriesFromDir(params: { + dirName: string; + pluginId: string; +}): PluginWebSearchProviderEntry[] | null { + return loadBundledProviderEntriesFromDir({ + dirName: params.dirName, + pluginId: params.pluginId, + artifactCandidates: WEB_SEARCH_ARTIFACT_CANDIDATES, + suffix: "WebSearchProvider", + isProvider: isWebSearchProviderPlugin, + }); +} + export function loadBundledRuntimeWebSearchProviderEntriesFromDir(params: { dirName: string; pluginId: string; }): PluginWebSearchProviderEntry[] | null { - const mod = tryLoadBundledPublicArtifactModule({ + return loadBundledProviderEntriesFromDir({ dirName: params.dirName, + pluginId: params.pluginId, artifactCandidates: WEB_SEARCH_RUNTIME_ARTIFACT_CANDIDATES, - }); - if (!mod) { - return null; - } - const providers = collectProviderFactories({ - mod, suffix: "WebSearchProvider", isProvider: isWebSearchProviderPlugin, }); - if (providers.length === 0) { - return null; - } - return providers.map((provider) => Object.assign({}, provider, { pluginId: params.pluginId })); } export function loadBundledWebFetchProviderEntriesFromDir(params: { dirName: string; pluginId: string; }): PluginWebFetchProviderEntry[] | null { - const mod = tryLoadBundledPublicArtifactModule({ + return loadBundledProviderEntriesFromDir({ dirName: params.dirName, + pluginId: params.pluginId, artifactCandidates: WEB_FETCH_ARTIFACT_CANDIDATES, - }); - if (!mod) { - return null; - } - const providers = collectProviderFactories({ - mod, suffix: "WebFetchProvider", isProvider: isWebFetchProviderPlugin, }); - if (providers.length === 0) { - return null; - } - return providers.map((provider) => Object.assign({}, provider, { pluginId: params.pluginId })); } export function resolveBundledExplicitWebSearchProvidersFromPublicArtifacts(params: { diff --git a/src/routing/binding-scope.ts b/src/routing/binding-scope.ts index 40e1daa14f0..998edd47b4e 100644 --- a/src/routing/binding-scope.ts +++ b/src/routing/binding-scope.ts @@ -1,3 +1,8 @@ +import { normalizeChatChannelId } from "../channels/ids.js"; +import type { AgentRouteBinding } from "../config/types.agents.js"; +import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; +import { normalizeAccountId, normalizeAgentId } from "./session-key.js"; + export type RouteBindingScopeConstraint = { guildId?: string | null; teamId?: string | null; @@ -11,6 +16,12 @@ export type RouteBindingScope = { memberRoleIds?: Iterable | null; }; +export type NormalizedRouteBindingMatch = { + agentId: string; + accountId: string; + channelId: string; +}; + export function normalizeRouteBindingId(value: unknown): string { if (typeof value === "string") { return value.trim(); @@ -25,6 +36,40 @@ export function normalizeRouteBindingRoles(value: string[] | null | undefined): return Array.isArray(value) && value.length > 0 ? value : null; } +export function normalizeRouteBindingChannelId(raw?: string | null): string | null { + const normalized = normalizeChatChannelId(raw); + if (normalized) { + return normalized; + } + const fallback = normalizeLowercaseStringOrEmpty(raw); + return fallback || null; +} + +export function resolveNormalizedRouteBindingMatch( + binding: AgentRouteBinding, +): NormalizedRouteBindingMatch | null { + if (!binding || typeof binding !== "object") { + return null; + } + const match = binding.match; + if (!match || typeof match !== "object") { + return null; + } + const channelId = normalizeRouteBindingChannelId(match.channel); + if (!channelId) { + return null; + } + const accountId = typeof match.accountId === "string" ? match.accountId.trim() : ""; + if (!accountId || accountId === "*") { + return null; + } + return { + agentId: normalizeAgentId(binding.agentId), + accountId: normalizeAccountId(accountId), + channelId, + }; +} + function scopeIdMatches(params: { constraint: string | null | undefined; exact: string; diff --git a/src/routing/bindings.ts b/src/routing/bindings.ts index 23e3c50e378..4e9b1c40929 100644 --- a/src/routing/bindings.ts +++ b/src/routing/bindings.ts @@ -1,59 +1,25 @@ import { resolveDefaultAgentId } from "../agents/agent-scope.js"; -import { normalizeChatChannelId } from "../channels/ids.js"; import { listRouteBindings } from "../config/bindings.js"; import type { AgentRouteBinding } from "../config/types.agents.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; -import { normalizeAccountId, normalizeAgentId } from "./session-key.js"; - -function normalizeBindingChannelId(raw?: string | null): string | null { - const normalized = normalizeChatChannelId(raw); - if (normalized) { - return normalized; - } - const fallback = normalizeLowercaseStringOrEmpty(raw); - return fallback || null; -} +import { + normalizeRouteBindingChannelId, + resolveNormalizedRouteBindingMatch, +} from "./binding-scope.js"; +import { normalizeAgentId } from "./session-key.js"; export function listBindings(cfg: OpenClawConfig): AgentRouteBinding[] { return listRouteBindings(cfg); } -function resolveNormalizedBindingMatch(binding: AgentRouteBinding): { - agentId: string; - accountId: string; - channelId: string; -} | null { - if (!binding || typeof binding !== "object") { - return null; - } - const match = binding.match; - if (!match || typeof match !== "object") { - return null; - } - const channelId = normalizeBindingChannelId(match.channel); - if (!channelId) { - return null; - } - const accountId = typeof match.accountId === "string" ? match.accountId.trim() : ""; - if (!accountId || accountId === "*") { - return null; - } - return { - agentId: normalizeAgentId(binding.agentId), - accountId: normalizeAccountId(accountId), - channelId, - }; -} - export function listBoundAccountIds(cfg: OpenClawConfig, channelId: string): string[] { - const normalizedChannel = normalizeBindingChannelId(channelId); + const normalizedChannel = normalizeRouteBindingChannelId(channelId); if (!normalizedChannel) { return []; } const ids = new Set(); for (const binding of listBindings(cfg)) { - const resolved = resolveNormalizedBindingMatch(binding); + const resolved = resolveNormalizedRouteBindingMatch(binding); if (!resolved || resolved.channelId !== normalizedChannel) { continue; } @@ -66,13 +32,13 @@ export function resolveDefaultAgentBoundAccountId( cfg: OpenClawConfig, channelId: string, ): string | null { - const normalizedChannel = normalizeBindingChannelId(channelId); + const normalizedChannel = normalizeRouteBindingChannelId(channelId); if (!normalizedChannel) { return null; } const defaultAgentId = normalizeAgentId(resolveDefaultAgentId(cfg)); for (const binding of listBindings(cfg)) { - const resolved = resolveNormalizedBindingMatch(binding); + const resolved = resolveNormalizedRouteBindingMatch(binding); if ( !resolved || resolved.channelId !== normalizedChannel || @@ -88,7 +54,7 @@ export function resolveDefaultAgentBoundAccountId( export function buildChannelAccountBindings(cfg: OpenClawConfig) { const map = new Map>(); for (const binding of listBindings(cfg)) { - const resolved = resolveNormalizedBindingMatch(binding); + const resolved = resolveNormalizedRouteBindingMatch(binding); if (!resolved) { continue; } diff --git a/src/routing/bound-account-read.ts b/src/routing/bound-account-read.ts index c98590d8de7..26b58cb533e 100644 --- a/src/routing/bound-account-read.ts +++ b/src/routing/bound-account-read.ts @@ -1,27 +1,18 @@ import { normalizeChatType, type ChatType } from "../channels/chat-type.js"; -import { normalizeChatChannelId } from "../channels/ids.js"; import { listRouteBindings } from "../config/bindings.js"; import type { AgentRouteBinding } from "../config/types.agents.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; import { + normalizeRouteBindingChannelId, normalizeRouteBindingId, normalizeRouteBindingRoles, + resolveNormalizedRouteBindingMatch, routeBindingScopeMatches, } from "./binding-scope.js"; import { peerKindMatches } from "./peer-kind-match.js"; -import { normalizeAccountId, normalizeAgentId } from "./session-key.js"; +import { normalizeAgentId } from "./session-key.js"; -function normalizeBindingChannelId(raw?: string | null): string | null { - const normalized = normalizeChatChannelId(raw); - if (normalized) { - return normalized; - } - const fallback = normalizeLowercaseStringOrEmpty(raw); - return fallback || null; -} - -function resolveNormalizedBindingMatch(binding: AgentRouteBinding): { +function resolveNormalizedBoundAccountMatch(binding: AgentRouteBinding): { agentId: string; accountId: string; channelId: string; @@ -31,27 +22,15 @@ function resolveNormalizedBindingMatch(binding: AgentRouteBinding): { teamId?: string | null; roles?: string[] | null; } | null { - if (!binding || typeof binding !== "object") { - return null; - } + const baseMatch = resolveNormalizedRouteBindingMatch(binding); const match = binding.match; - if (!match || typeof match !== "object") { - return null; - } - const channelId = normalizeBindingChannelId(match.channel); - if (!channelId) { - return null; - } - const accountId = typeof match.accountId === "string" ? match.accountId.trim() : ""; - if (!accountId || accountId === "*") { + if (!baseMatch || !match || typeof match !== "object") { return null; } const peerId = match.peer && typeof match.peer.id === "string" ? match.peer.id.trim() : undefined; const peerKind = match.peer ? normalizeChatType(match.peer.kind) : undefined; return { - agentId: normalizeAgentId(binding.agentId), - accountId: normalizeAccountId(accountId), - channelId, + ...baseMatch, peerId: peerId || undefined, peerKind: peerKind ?? undefined, guildId: normalizeRouteBindingId(match.guildId) || null, @@ -88,7 +67,7 @@ export function resolveFirstBoundAccountId(params: { groupSpace?: string | null; memberRoleIds?: string[]; }): string | undefined { - const normalizedChannel = normalizeBindingChannelId(params.channelId); + const normalizedChannel = normalizeRouteBindingChannelId(params.channelId); if (!normalizedChannel) { return undefined; } @@ -103,7 +82,7 @@ export function resolveFirstBoundAccountId(params: { let wildcardPeerMatch: string | undefined; let channelOnlyFallback: string | undefined; for (const binding of listRouteBindings(params.cfg)) { - const resolved = resolveNormalizedBindingMatch(binding); + const resolved = resolveNormalizedBoundAccountMatch(binding); if ( !resolved || resolved.channelId !== normalizedChannel || diff --git a/test/extension-test-boundary.test.ts b/test/extension-test-boundary.test.ts index bd8647b1d1c..69ce50079da 100644 --- a/test/extension-test-boundary.test.ts +++ b/test/extension-test-boundary.test.ts @@ -9,32 +9,6 @@ const ALLOWED_EXTENSION_PUBLIC_SURFACE_BASENAMES = new Set( GUARDED_EXTENSION_PUBLIC_SURFACE_BASENAMES, ); -const allowedNonExtensionTests = new Set([ - "src/agents/pi-embedded-runner-extraparams-moonshot.test.ts", - "src/agents/pi-embedded-runner-extraparams.test.ts", - "src/agents/pi-embedded-runner-extraparams-moonshot.test.ts", - "src/channels/plugins/contracts/dm-policy.contract.test.ts", - "src/channels/plugins/contracts/group-policy.contract.test.ts", - "src/commands/channels.surfaces-signal-runtime-errors-channels-status-output.test.ts", - "src/commands/onboard-channels.e2e.test.ts", - "src/gateway/hooks.test.ts", - "src/infra/outbound/deliver.test.ts", - "src/plugins/interactive.test.ts", - "src/plugins/contracts/discovery.contract.test.ts", - "src/plugin-sdk/telegram-command-config.test.ts", - "src/security/audit-channel-slack-command-findings.test.ts", - "src/security/audit-feishu-doc-risk.test.ts", - "src/secrets/runtime-channel-inactive-variants.test.ts", - "src/secrets/runtime-discord-surface.test.ts", - "src/secrets/runtime-inactive-telegram-surfaces.test.ts", - "src/secrets/runtime-legacy-x-search.test.ts", - "src/secrets/runtime-matrix-shadowing.test.ts", - "src/secrets/runtime-matrix-top-level.test.ts", - "src/secrets/runtime-nextcloud-talk-file-precedence.test.ts", - "src/secrets/runtime-telegram-token-inheritance.test.ts", - "src/secrets/runtime-zalo-token-activity.test.ts", -]); - function walk(dir: string, entries: string[] = []): string[] { for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const fullPath = path.join(dir, entry.name); @@ -136,7 +110,7 @@ describe("non-extension test boundaries", () => { if (imports.length === 0) { return null; } - if (allowedNonExtensionTests.has(file) || isAllowedCoreContractSuite(file, imports)) { + if (isAllowedCoreContractSuite(file, imports)) { return null; } return { @@ -170,20 +144,12 @@ describe("non-extension test boundaries", () => { expect(imports).toEqual([]); }); - it("keeps bundled plugin public-surface imports on an explicit core allowlist", () => { - const allowed = new Set([ - "src/auto-reply/reply.triggers.trigger-handling.test-harness.ts", - "src/agents/models-config.providers.ollama.test.ts", - "src/commands/channel-test-registry.ts", - "src/plugins/contracts/provider-vitest-registry.ts", - "src/plugins/contracts/web-provider-vitest-registry.ts", - "src/plugin-sdk/testing.ts", - ]); + it("keeps bundled plugin public-surface imports out of core source", () => { const files = walkCode(path.join(repoRoot, "src")); const offenders = files.filter((file) => { const source = fs.readFileSync(path.join(repoRoot, file), "utf8"); - return findBundledPluginPublicSurfaceImports(source).length > 0 && !allowed.has(file); + return findBundledPluginPublicSurfaceImports(source).length > 0; }); expect(offenders).toEqual([]); diff --git a/src/auto-reply/reply.triggers.trigger-handling.test-harness.ts b/test/helpers/auto-reply/trigger-handling-test-harness.ts similarity index 90% rename from src/auto-reply/reply.triggers.trigger-handling.test-harness.ts rename to test/helpers/auto-reply/trigger-handling-test-harness.ts index a688c57f1e0..fdac3c99da1 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.test-harness.ts +++ b/test/helpers/auto-reply/trigger-handling-test-harness.ts @@ -3,11 +3,11 @@ import fs from "node:fs/promises"; import os from "node:os"; import { join } from "node:path"; import { afterAll, afterEach, beforeAll, expect, vi } from "vitest"; -import { clearRuntimeAuthProfileStoreSnapshots } from "../agents/auth-profiles.js"; -import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { resetProviderRuntimeHookCacheForTest } from "../plugins/provider-runtime.js"; -import { resolveRelativeBundledPluginPublicModuleId } from "../test-utils/bundled-plugin-public-surface.js"; -import { withFastReplyConfig } from "./reply/get-reply-fast-path.js"; +import { clearRuntimeAuthProfileStoreSnapshots } from "../../../src/agents/auth-profiles.js"; +import { withFastReplyConfig } from "../../../src/auto-reply/reply/get-reply-fast-path.js"; +import type { OpenClawConfig } from "../../../src/config/types.openclaw.js"; +import { resetProviderRuntimeHookCacheForTest } from "../../../src/plugins/provider-runtime.js"; +import { resolveRelativeBundledPluginPublicModuleId } from "../../../src/test-utils/bundled-plugin-public-surface.js"; // Avoid exporting vitest mock types (TS2742 under pnpm + d.ts emit). type AnyMock = any; @@ -49,7 +49,7 @@ export function getQueueEmbeddedPiMessageMock(): AnyMock { } const installPiEmbeddedMock = () => - vi.doMock("../agents/pi-embedded.js", () => ({ + vi.doMock("../../../src/agents/pi-embedded.js", () => ({ abortEmbeddedPiRun: (...args: unknown[]) => piEmbeddedMocks.abortEmbeddedPiRun(...args), compactEmbeddedPiSession: (...args: unknown[]) => piEmbeddedMocks.compactEmbeddedPiSession(...args), @@ -65,7 +65,7 @@ const installPiEmbeddedMock = () => installPiEmbeddedMock(); -vi.doMock("../agents/pi-embedded-runner/runs.js", () => ({ +vi.doMock("../../../src/agents/pi-embedded-runner/runs.js", () => ({ abortEmbeddedPiRun: (...args: unknown[]) => piEmbeddedMocks.abortEmbeddedPiRun(...args), })); @@ -83,7 +83,7 @@ export function getProviderUsageMocks(): AnyMocks { return providerUsageMocks; } -vi.mock("../infra/provider-usage.js", () => providerUsageMocks); +vi.mock("../../../src/infra/provider-usage.js", () => providerUsageMocks); const modelCatalogMocks = getSharedMocks("openclaw.trigger-handling.model-catalog-mocks", () => ({ loadModelCatalog: vi.fn().mockResolvedValue([ @@ -112,15 +112,15 @@ export function getModelCatalogMocks(): AnyMocks { } const installModelCatalogMock = () => - vi.doMock("../agents/model-catalog.js", () => modelCatalogMocks); + vi.doMock("../../../src/agents/model-catalog.js", () => modelCatalogMocks); installModelCatalogMock(); -vi.doMock("../agents/model-catalog.runtime.js", () => ({ +vi.doMock("../../../src/agents/model-catalog.runtime.js", () => ({ loadModelCatalog: (...args: unknown[]) => modelCatalogMocks.loadModelCatalog(...args), })); -vi.doMock("../plugins/provider-runtime.runtime.js", () => ({ +vi.doMock("../../../src/plugins/provider-runtime.runtime.js", () => ({ augmentModelCatalogWithProviderPlugins: async (params: { catalog?: unknown[] }) => params.catalog ?? [], buildProviderAuthDoctorHintWithPlugin: () => undefined, @@ -150,11 +150,11 @@ export function getModelFallbackMocks(): AnyMocks { } const installModelFallbackMock = () => - vi.doMock("../agents/model-fallback.js", () => modelFallbackMocks); + vi.doMock("../../../src/agents/model-fallback.js", () => modelFallbackMocks); installModelFallbackMock(); -vi.doMock("../infra/git-commit.js", () => ({ +vi.doMock("../../../src/infra/git-commit.js", () => ({ resolveCommitHash: vi.fn(() => "abcdef0"), })); @@ -302,12 +302,12 @@ export function makeCfg(home: string): OpenClawConfig { } export async function loadGetReplyFromConfig() { - return (await import("./reply.js")).getReplyFromConfig; + return (await import("../../../src/auto-reply/reply.js")).getReplyFromConfig; } export function installTriggerHandlingReplyHarness( setGetReplyFromConfig: ( - getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig, + getReplyFromConfig: typeof import("../../../src/auto-reply/reply.js").getReplyFromConfig, ) => void, ): void { beforeAll(async () => { @@ -357,7 +357,7 @@ export function makeWhatsAppElevatedCfg( export async function runDirectElevatedToggleAndLoadStore(params: { cfg: OpenClawConfig; - getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig; + getReplyFromConfig: typeof import("../../../src/auto-reply/reply.js").getReplyFromConfig; body?: string; }): Promise<{ text: string | undefined; @@ -386,7 +386,7 @@ export async function runDirectElevatedToggleAndLoadStore(params: { export async function expectInlineCommandHandledAndStripped(params: { home: string; - getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig; + getReplyFromConfig: typeof import("../../../src/auto-reply/reply.js").getReplyFromConfig; body: string; stripToken: string; blockReplyContains: string; @@ -419,7 +419,7 @@ export async function expectInlineCommandHandledAndStripped(params: { export async function runGreetingPromptForBareNewOrReset(params: { home: string; body: "/new" | "/reset"; - getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig; + getReplyFromConfig: typeof import("../../../src/auto-reply/reply.js").getReplyFromConfig; }) { const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock(); runEmbeddedPiAgentMock.mockClear(); diff --git a/test/helpers/plugins/provider-contract.ts b/test/helpers/plugins/provider-contract.ts index a907bf422bf..846f7097232 100644 --- a/test/helpers/plugins/provider-contract.ts +++ b/test/helpers/plugins/provider-contract.ts @@ -4,7 +4,7 @@ import { providerContractLoadError, resolveProviderContractProvidersForPluginIds, } from "../../../src/plugins/contracts/registry.js"; -import { loadBundledPluginPublicArtifactModuleSync } from "../../../src/plugins/public-surface-loader.js"; +import { resolveBundledExplicitProviderContractsFromPublicArtifacts } from "../../../src/plugins/provider-contract-public-artifacts.js"; import type { ProviderPlugin } from "../../../src/plugins/types.js"; import { installProviderPluginContractSuite } from "./provider-contract-suites.js"; @@ -13,56 +13,10 @@ type ProviderContractEntry = { provider: ProviderPlugin; }; -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - -function isProviderPlugin(value: unknown): value is ProviderPlugin { - return ( - isRecord(value) && - typeof value.id === "string" && - typeof value.label === "string" && - Array.isArray(value.auth) - ); -} - function resolveProviderContractProvidersFromPublicArtifact( pluginId: string, ): ProviderContractEntry[] | null { - let mod: Record; - try { - mod = loadBundledPluginPublicArtifactModuleSync>({ - dirName: pluginId, - artifactBasename: "provider-contract-api.js", - }); - } catch (error) { - if ( - error instanceof Error && - error.message.startsWith("Unable to resolve bundled plugin public surface ") - ) { - return null; - } - throw error; - } - - const providers: ProviderContractEntry[] = []; - for (const [name, exported] of Object.entries(mod).toSorted(([left], [right]) => - left.localeCompare(right), - )) { - if ( - typeof exported !== "function" || - exported.length !== 0 || - !name.startsWith("create") || - !name.endsWith("Provider") - ) { - continue; - } - const provider = exported(); - if (isProviderPlugin(provider)) { - providers.push({ pluginId, provider }); - } - } - return providers.length > 0 ? providers : null; + return resolveBundledExplicitProviderContractsFromPublicArtifacts({ onlyPluginIds: [pluginId] }); } export function describeProviderContracts(pluginId: string) { diff --git a/tsconfig.core.projects.json b/tsconfig.core.projects.json new file mode 100644 index 00000000000..611edf76190 --- /dev/null +++ b/tsconfig.core.projects.json @@ -0,0 +1,4 @@ +{ + "files": [], + "references": [{ "path": "./tsconfig.core.json" }, { "path": "./tsconfig.core.test.json" }] +} diff --git a/tsconfig.extensions.projects.json b/tsconfig.extensions.projects.json new file mode 100644 index 00000000000..0cd86db0446 --- /dev/null +++ b/tsconfig.extensions.projects.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.extensions.json" }, + { "path": "./tsconfig.extensions.test.json" } + ] +} diff --git a/tsconfig.projects.json b/tsconfig.projects.json new file mode 100644 index 00000000000..3b5517c1943 --- /dev/null +++ b/tsconfig.projects.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.core.projects.json" }, + { "path": "./tsconfig.extensions.projects.json" } + ] +} diff --git a/ui/package.json b/ui/package.json index 848e5207c4d..c8745cb99d0 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,7 +15,7 @@ "lit": "^3.3.2", "markdown-it": "^14.1.1", "markdown-it-task-lists": "^2.1.1", - "marked": "^18.0.0" + "marked": "^18.0.1" }, "devDependencies": { "@types/markdown-it": "^14.1.2",