Skip to content

release: mirror bundled channel deps at root#63065

Merged
scoootscooob merged 4 commits intoopenclaw:mainfrom
scoootscooob:codex/p0-runtime-deps-release
Apr 8, 2026
Merged

release: mirror bundled channel deps at root#63065
scoootscooob merged 4 commits intoopenclaw:mainfrom
scoootscooob:codex/p0-runtime-deps-release

Conversation

@scoootscooob
Copy link
Copy Markdown
Contributor

Summary

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

  • Root cause: bundled channel/plugin code was code-split into root dist/*.js chunks that resolve packages from the package root, but the root npm manifest did not mirror those runtime dependencies.
  • Missing detection / guardrail: the existing release checks only validated a small set of mirrored deps and the postpublish verify path did not exercise the installed openclaw binary or validate mirrored root deps from bundled extension manifests.
  • Contributing context (if known): the package still relied on best-effort postinstall repair, so environments where that recovery path failed surfaced user-visible missing-module crashes.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: test/openclaw-npm-postpublish-verify.test.ts
  • Scenario the test should lock in: bundled extensions that declare root-mirrored runtime deps must be satisfied by the installed package root manifest, and published install verification must reject drift.
  • Why this is the smallest reliable guardrail: it validates the packaged manifest contract directly without needing a full publish cycle.
  • Existing test that already covers this (if any): test/release-check.test.ts already covers the generic root-mirror allowlist rules.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • npm installs now carry the bundled channel runtime deps that root dist/*.js chunks actually import, instead of relying on postinstall recovery to backfill them.
  • Postpublish verification now fails if the installed package loses those mirrored deps or if the installed openclaw binary cannot report its version.

Diagram (if applicable)

Before:
[npm install openclaw] -> [root dist chunk imports bundled channel package] -> [package missing at root] -> [runtime crash unless postinstall recovers]

After:
[npm install openclaw] -> [root manifest already mirrors root-resolved bundled channel deps] -> [runtime import resolves] -> [binary smoke + postpublish verify catch drift]

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS 15.7.1 host
  • Runtime/container: Node 25 host tooling, repo release scripts
  • Model/provider: N/A
  • Integration/channel (if any): Slack / Telegram / Discord / Feishu packaging surfaces
  • Relevant config (redacted): N/A

Steps

  1. Build the repo release artifact surfaces.
  2. Run the packaging checks and postpublish verifier unit tests.
  3. Confirm root dist/*.js imports are mirrored in the root manifest through extension allowlists.

Expected

  • Release checks pass.
  • The packaged manifest explicitly mirrors root-resolved bundled channel deps.
  • Postpublish verification would fail if those mirrored deps drift again.

Actual

  • pnpm release:check passed after pnpm build and pnpm ui:build.
  • Targeted verifier tests passed.
  • The four affected bundled extensions now declare the mirrored root deps they require.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: pnpm test test/openclaw-npm-postpublish-verify.test.ts, pnpm test test/release-check.test.ts, pnpm build, pnpm ui:build, pnpm release:check
  • Edge cases checked: optional root mirror for @discordjs/opus; installed-package manifest drift detection for mirrored bundled deps
  • What you did not verify: I did not fully re-test the separate Web UI self-update corruption path from Web UI "Update" button corrupts installation — missing core files, gateway unable to start #62984, and the local tarball global-install smoke was slower than the targeted release checks so I relied on the hardened verifier + release gate rather than waiting for that extra run.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: root dependency surface grows for the mirrored bundled channel packages.
    • Mitigation: each added mirror is now declared by the owning extension through rootDependencyMirrorAllowlist, checked by release-check, and validated again in postpublish verification.

@openclaw-barnacle openclaw-barnacle Bot added channel: discord Channel integration: discord channel: slack Channel integration: slack channel: telegram Channel integration: telegram scripts Repository scripts channel: feishu Channel integration: feishu size: M maintainer Maintainer-authored PR labels Apr 8, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR fixes a class of missing-module crashes on fresh npm installs by mirroring the root-resolved runtime deps of four bundled channel extensions (Discord, Slack, Telegram, Feishu) into the root package.json, and by wiring those mirrors through an owned openclaw.releaseChecks.rootDependencyMirrorAllowlist field that a new postpublish verifier checks. The postpublish verifier also now smoke-tests the installed openclaw binary. All version specs are consistent between the extension manifests and the root manifest.

Confidence Score: 5/5

Safe to merge — fixes a real install-time crash with a well-scoped, verified change.

All findings are P2: one suggestion to surface malformed extension package.json parse errors instead of silently skipping them, and one suggestion to add a test for the version-spec mismatch branch. Neither blocks correct behavior today. The core logic (allowlist wiring, exact-spec matching, binary smoke-test) is correct and all version specs are consistent between extension manifests and the root.

No files require special attention.

Vulnerabilities

No security concerns identified. The change adds package metadata fields and a postpublish verification script; no new network calls, token handling, or execution surface is introduced.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/openclaw-npm-postpublish-verify.ts
Line: 100-113

Comment:
**Silent skip on malformed extension `package.json`**

When `JSON.parse` throws (e.g., a packaging step produces a truncated file), the catch block returns `[]`, so that extension's `rootDependencyMirrorAllowlist` is silently ignored and the mirrored-dep check passes for it. A corrupted `package.json` is itself a packaging failure worth surfacing — pushing an error string into the caller's errors array would prevent drift from going undetected. As written, a bad JSON file in `dist/extensions/*/package.json` causes the entire allowlist check for that extension to be skipped without any diagnostic.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: test/openclaw-npm-postpublish-verify.test.ts
Line: 62-126

Comment:
**No test for the version-spec mismatch branch**

The `collectInstalledMirroredRootDependencyManifestErrors` suite covers "missing root dep" and "dep in optionalDependencies" but never exercises the `rootSpec !== extensionSpec` branch (lines 165–169 of the script). A case where root declares `"^7.16.0"` while the extension declares `"^7.15.0"` would be silently missed. Adding a third `it` block that writes mismatched specs and asserts the version-mismatch error string would lock in that path.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "release: mirror bundled channel deps at ..." | Re-trigger Greptile

Comment on lines +100 to +113
.filter((entry) => entry.isDirectory())
.flatMap((entry) => {
const packageJsonPath = join(extensionsDir, entry.name, "package.json");
if (!existsSync(packageJsonPath)) {
return [];
}
try {
return [
JSON.parse(readFileSync(packageJsonPath, "utf8")) as InstalledBundledExtensionPackageJson,
];
} catch {
return [];
}
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Silent skip on malformed extension package.json

When JSON.parse throws (e.g., a packaging step produces a truncated file), the catch block returns [], so that extension's rootDependencyMirrorAllowlist is silently ignored and the mirrored-dep check passes for it. A corrupted package.json is itself a packaging failure worth surfacing — pushing an error string into the caller's errors array would prevent drift from going undetected. As written, a bad JSON file in dist/extensions/*/package.json causes the entire allowlist check for that extension to be skipped without any diagnostic.

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/openclaw-npm-postpublish-verify.ts
Line: 100-113

Comment:
**Silent skip on malformed extension `package.json`**

When `JSON.parse` throws (e.g., a packaging step produces a truncated file), the catch block returns `[]`, so that extension's `rootDependencyMirrorAllowlist` is silently ignored and the mirrored-dep check passes for it. A corrupted `package.json` is itself a packaging failure worth surfacing — pushing an error string into the caller's errors array would prevent drift from going undetected. As written, a bad JSON file in `dist/extensions/*/package.json` causes the entire allowlist check for that extension to be skipped without any diagnostic.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +62 to +126
describe("collectInstalledMirroredRootDependencyManifestErrors", () => {
function makeInstalledPackageRoot(): string {
return mkdtempSync(join(tmpdir(), "openclaw-postpublish-installed-"));
}

function writePackageFile(root: string, relativePath: string, value: unknown): void {
const fullPath = join(root, relativePath);
mkdirSync(dirname(fullPath), { recursive: true });
writeFileSync(fullPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
}

it("flags missing mirrored root dependencies required by bundled extensions", () => {
const packageRoot = makeInstalledPackageRoot();

try {
writePackageFile(packageRoot, "package.json", {
version: "2026.4.9",
dependencies: {},
});
writePackageFile(packageRoot, "dist/extensions/slack/package.json", {
dependencies: {
"@slack/web-api": "^7.15.0",
},
openclaw: {
releaseChecks: {
rootDependencyMirrorAllowlist: ["@slack/web-api"],
},
},
});

expect(collectInstalledMirroredRootDependencyManifestErrors(packageRoot)).toEqual([
"installed package is missing mirrored root runtime dependency '@slack/web-api' required by a bundled extension.",
]);
} finally {
rmSync(packageRoot, { recursive: true, force: true });
}
});

it("accepts mirrored root dependencies declared in package optionalDependencies", () => {
const packageRoot = makeInstalledPackageRoot();

try {
writePackageFile(packageRoot, "package.json", {
version: "2026.4.9",
optionalDependencies: {
"@discordjs/opus": "^0.10.0",
},
});
writePackageFile(packageRoot, "dist/extensions/discord/package.json", {
optionalDependencies: {
"@discordjs/opus": "^0.10.0",
},
openclaw: {
releaseChecks: {
rootDependencyMirrorAllowlist: ["@discordjs/opus"],
},
},
});

expect(collectInstalledMirroredRootDependencyManifestErrors(packageRoot)).toEqual([]);
} finally {
rmSync(packageRoot, { recursive: true, force: true });
}
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No test for the version-spec mismatch branch

The collectInstalledMirroredRootDependencyManifestErrors suite covers "missing root dep" and "dep in optionalDependencies" but never exercises the rootSpec !== extensionSpec branch (lines 165–169 of the script). A case where root declares "^7.16.0" while the extension declares "^7.15.0" would be silently missed. Adding a third it block that writes mismatched specs and asserts the version-mismatch error string would lock in that path.

Prompt To Fix With AI
This is a comment left during a code review.
Path: test/openclaw-npm-postpublish-verify.test.ts
Line: 62-126

Comment:
**No test for the version-spec mismatch branch**

The `collectInstalledMirroredRootDependencyManifestErrors` suite covers "missing root dep" and "dep in optionalDependencies" but never exercises the `rootSpec !== extensionSpec` branch (lines 165–169 of the script). A case where root declares `"^7.16.0"` while the extension declares `"^7.15.0"` would be silently missed. Adding a third `it` block that writes mismatched specs and asserts the version-mismatch error string would lock in that path.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6516538970

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -89,6 +195,14 @@ function installSpec(prefixDir: string, spec: string, cwd: string): void {
npmExec(["install", "-g", "--prefix", prefixDir, spec, "--no-fund", "--no-audit"], cwd);
}

function readInstalledBinaryVersion(prefixDir: string, cwd: string): string {
return execFileSync(join(prefixDir, "bin", "openclaw"), ["--version"], {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve installed binary from npm global bin path

The new binary smoke check hardcodes join(prefixDir, "bin", "openclaw"), but npm’s global bin location is platform-dependent ({prefix}/bin on Unix and {prefix} on Windows). On Windows this path will be wrong, so postpublish verification fails with ENOENT even when npm install -g --prefix ... succeeded. Resolve the bin path via npm’s global-bin logic (or branch on win32 and invoke openclaw.cmd).

Useful? React with 👍 / 👎.

Comment on lines +110 to +111
} catch {
return [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail verification when bundled manifest parsing fails

Bundled extension package.json parse failures are silently ignored (catch { return [] }), which means mirror checks are skipped for broken extensions instead of failing verification. If a published artifact contains a malformed dist/extensions/<id>/package.json, collectInstalledMirroredRootDependencyManifestErrors can incorrectly pass and miss dependency drift. This should report an explicit error for unreadable/invalid extension manifests.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9192a6e98f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -89,6 +214,14 @@ function installSpec(prefixDir: string, spec: string, cwd: string): void {
npmExec(["install", "-g", "--prefix", prefixDir, spec, "--no-fund", "--no-audit"], cwd);
}

function readInstalledBinaryVersion(prefixDir: string, cwd: string): string {
return execFileSync(join(prefixDir, "bin", "openclaw"), ["--version"], {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve installed CLI from npm global bin location

Fresh evidence in this commit: readInstalledBinaryVersion hardcodes execFileSync(join(prefixDir, "bin", "openclaw"), ...). npm’s global executable path is platform-specific, and on Windows the shim is created under the prefix root as openclaw.cmd rather than {prefix}/bin/openclaw, so this verifier reports ENOENT even after a successful npm install -g --prefix ...; that makes postpublish verification fail on Windows-only environments.

Useful? React with 👍 / 👎.

@scoootscooob scoootscooob self-assigned this Apr 8, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 86f293e643

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +125 to +127
if (!existsSync(packageJsonPath)) {
continue;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when bundled extension manifest is absent

readBundledExtensionPackageJsons silently continues when dist/extensions/<id>/package.json is missing, so postpublish verification skips mirror checks for that extension entirely. In a packaging regression (or a dangling symlink that makes existsSync return false), this allows collectInstalledMirroredRootDependencyManifestErrors to pass even though the bundled extension artifact is incomplete and its required mirrored root dependencies were never validated.

Useful? React with 👍 / 👎.

@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 8, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Symlink-based path traversal when reading bundled extension manifests
1. 🟡 Symlink-based path traversal when reading bundled extension manifests
Property Value
Severity Medium
CWE CWE-22
Location scripts/openclaw-npm-postpublish-verify.ts:124-156

Description

The post-publish verification script walks dist/extensions/*/package.json and resolves real paths, but it does not ensure that the resolved extension directory stays within the package tree.

If an entry under dist/extensions is (or is treated as) a directory while actually being a symlink/junction to an arbitrary location, the script will:

  • accept the entry (entry.isDirectory() may be true for symlinked dirs/junctions on some platforms/filesystems)
  • compute packageJsonPath under that entry and existsSync / lstatSync it
  • realpathSync(extensionDirPath) and realpathSync(packageJsonPath) will then resolve to the external target
  • the relative check only verifies package.json is within the resolved extension directory, not that the extension directory is within dist/extensions

This allows reading and JSON.parse of files outside the installed package tree (information exposure) and can also cause denial of service (e.g., by pointing at special files or very large directories, though the manifest size check only applies after following the parent path).

Vulnerable code:

const extensionDirPath = join(extensionsDir, entry.name);
...
const realExtensionDirPath = realpathSync(extensionDirPath);
const realPackageJsonPath = realpathSync(packageJsonPath);

Recommendation

Harden the directory traversal logic by rejecting symlinked extension directories and ensuring the real path stays under the real dist/extensions root.

Suggested fix:

const realExtensionsDir = realpathSync(extensionsDir);

for (const entry of readdirSync(extensionsDir, { withFileTypes: true })) {
  const extensionDirPath = join(extensionsDir, entry.name);// Reject symlinks/junctions explicitly
  const extStat = lstatSync(extensionDirPath);
  if (!extStat.isDirectory() || extStat.isSymbolicLink()) continue;

  const realExtensionDirPath = realpathSync(extensionDirPath);
  if (!realExtensionDirPath.startsWith(realExtensionsDir + require("node:path").sep)) {
    errors.push(`bundled extension directory resolves outside extensions root: ${extensionDirPath}`);
    continue;
  }// then resolve/validate package.json as you already do
}

This prevents reading manifests from locations outside the package root even if symlinks/junctions are present.


Analyzed PR: #63065 at commit ac26799

Last updated on: 2026-04-08T11:04:17Z

@scoootscooob scoootscooob force-pushed the codex/p0-runtime-deps-release branch from c760f1a to ac26799 Compare April 8, 2026 10:59
@scoootscooob scoootscooob merged commit d52d5ad into openclaw:main Apr 8, 2026
7 checks passed
@scoootscooob
Copy link
Copy Markdown
Contributor Author

Merged via squash.

Thanks @scoootscooob!

@powerdot
Copy link
Copy Markdown

powerdot commented Apr 8, 2026

Thank you, @scoootscooob

@tonydehnke
Copy link
Copy Markdown
Contributor

Do we need to wait for a new version to be released to do a clean safe install?

@powerdot
Copy link
Copy Markdown

powerdot commented Apr 8, 2026

Do we need to wait for a new version to be released to do a clean safe install?

Yes, or you just can copy package.json content to your current version and run npm i

eleqtrizit pushed a commit that referenced this pull request Apr 8, 2026
Merged via squash.

Prepared head SHA: ac26799
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
greidron added a commit to greidron/openclaw that referenced this pull request Apr 10, 2026
* release: mirror bundled channel deps at root (openclaw#63065)

Merged via squash.

Prepared head SHA: ac26799
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob

* fix(test): keep warn log capture under openclaw temp dir

* revert: undo background alive review findings fix

* feat: add qa character vibes eval

* test: stabilize plugin boundary invariants

* test: isolate agent gateway cli command mocks

* test: skip duplicate package boundary wrapper in ci

* test: fix postpublish verifier sidecar handling

* test: keep status tests off live usage probes

* auto-reply: type status auth overrides

* plugins: read contract inventory from manifests

* test: inline cli metadata channel fixture

* ci: skip duplicate full extension shard

* test: isolate discord directory live token env

* test: keep followup runner memory mock complete

* ci: split parallel full suite into leaf shards

* test: guard loader fixtures against broad sdk imports

* test: keep bundled channel entry smokes descriptor-only

* ci: reduce full suite test parallelism

* test: avoid bundled test api smokes in matrix and telegram

* test: keep discord and irc entry smokes descriptor-only

* test: keep web provider artifact coverage manifest-only

* test: keep provider policy artifact coverage narrow

* test: keep web provider artifact test in boundary

* test: keep status message tests off auth auto-detection

* status: avoid plugin lookup for direct channel model overrides

* channels: fast-path direct model override matches

* test: restore manifest-only web provider coverage

* fix: allow blank TLS manual port default (openclaw#63134) (thanks @Tyler-RNG)

* make port optional for TLS manual connections

* fix: restrict manual blank-port fallback to tls

* fix: allow blank TLS manual port default (openclaw#63134) (thanks @Tyler-RNG)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>

* test: fix full suite CI test isolation

* fix: align LLM idle timeout policy

* test: exercise models json file mode without provider discovery

* test: keep shared dm policy contract off channel facades

* test: keep web provider artifact test in boundary

* test: keep kilocode provider tests on plugin-owned helpers

* ci: restore sequential full suite tests

* test: keep public artifact coverage on cheap boundaries

* test: keep openclaw tools registration tests on a fast shell

* test: keep bundled metadata sidecar scan inventory-only

* docs(inferrs): fix Gemma model id from gg-hf-gg to google (openclaw#62586)

* fix: harden bundled plugin dependency release checks

* ci: isolate full suite leaf shards

* test: keep openclaw tools registration policy pure

* fix: support Codex CLI QA auth

* feat: add QA character eval reports

* docs: document QA character eval workflow

* refactor: dedupe media generation tool helpers

* refactor: dedupe internal helper glue

* refactor: dedupe shared helper branches

* refactor: dedupe browser navigation guard tests

* refactor: dedupe config and subagent tests

* refactor: dedupe test helpers and script warning filter

* refactor: dedupe plugin test harnesses

* refactor: dedupe media runtime test mocks

* refactor: dedupe plugin metadata test helpers

* refactor: dedupe firecrawl and directive helpers

* refactor: dedupe exec defaults tests

* refactor: dedupe approval runtime tests

* refactor: dedupe matrix exec approval tests

* refactor: dedupe telegram exec approval tests

* refactor: dedupe doctor codex oauth tests

* refactor: dedupe agent command test fixtures

* refactor: dedupe embedding provider test fixtures

* refactor: share html entity tool call decoding

* fix: keep minimax provider mocks package-local

* test: keep pdf and update-plan registration tests pure

* test: keep model reasoning override coverage on merge helpers

* fix: default OpenAI reasoning effort to high

* test: keep kimi implicit provider tests on provider catalog

* fix(build): prune stale bundled plugin node_modules

* fix(build): address bundled plugin prune review

* fix(build): honor postinstall disable flag

* test: keep chutes implicit provider tests on provider catalog

* fix(plugin-sdk): export channel plugin base

* docs: reorder changelog entries

* test: keep bundled web-search owner checks on public artifacts

* fix(build): keep tsdown prune best-effort

* test: trust gateway exec fixture node path

* fix: keep runtime task test harness behind task seams

* test: explain gateway exec fixture trust

* Reply: surface OAuth reauth failures (openclaw#63217)

Merged via squash.

Prepared head SHA: 68b7ffd
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* test: make character eval scenario natural

* feat: add character eval model options

* test: keep pi fs workspace tests on fs tool factories

* test: keep media runtime tests on same-directory provider mocks

* fix(android): auto-resume pairing approval

* fix(android): prefer bootstrap auth on qr pairing

* fix(android): reset auth on new setup codes

* fix(android): tighten pairing retry behavior

* fix(android): prefer stored device auth after pairing

* fix: restore android qr pairing flow (openclaw#63199)

* fix(auto-reply): strip leading NO_REPLY tokens to prevent silent-reply leak (openclaw#63068)

* fix(auto-reply): strip leading NO_REPLY tokens to prevent silent-reply leak

* fix(auto-reply): preserve substantive NO_REPLY leading text

* fix(agents): preserve ACP silent-prefix cumulative deltas

* fix(auto-reply): harden silent-token streaming paths

* fix(auto-reply): normalize glued silent tokens consistently

---------

Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net>

* fix(gateway): clear auto-fallback model override on session reset (openclaw#63155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in cb0a752 ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net>

* test: stabilize ci test isolation

* test: isolate volcengine byteplus auth resolver imports

* fix: patch hono security advisories

* fix: pass system prompt to codex cli

* fix(plugins): prevent untrusted workspace plugins from hijacking bundled provider auth choices [AI] (openclaw#62368)

* fix: address issue

* fix: address review feedback

* docs(changelog): add onboarding auth-choice guard entry

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>

* test: isolate provider runtime test mocks

* feat(plugins): support provider auth aliases

* feat(memory): add grounded REM backfill lane (openclaw#63273)

Merged via squash.

Prepared head SHA: 4450f25
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* feat(memory): harden grounded REM extraction (openclaw#63297)

Merged via squash.

Prepared head SHA: e188b7e
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* feat(ui): add dreaming diary controls and navigation (openclaw#63298)

Merged via squash.

Prepared head SHA: 0a2ae66
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* chore(ui): refresh zh-TW control ui locale

* chore(ui): refresh zh-CN control ui locale

* chore(ui): refresh pt-BR control ui locale

* chore(ui): refresh de control ui locale

* chore(ui): refresh es control ui locale

* chore(ui): refresh ko control ui locale

* chore(ui): refresh ja-JP control ui locale

* chore(ui): refresh fr control ui locale

* docs(matrix): tighten setup and config guidance

* chore(ui): refresh tr control ui locale

* chore(ui): refresh uk control ui locale

* chore(ui): refresh pl control ui locale

* chore(ui): refresh id control ui locale

* test: stabilize full-suite execution

* fix(matrix): contain sync outage failures (openclaw#62779)

Merged via squash.

Prepared head SHA: 901bb76
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* Align remote node exec event system messages with untrusted handling (openclaw#62659)

* fix(nodes): downgrade remote exec system events

* docs(changelog): add remote node exec event entry

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>

* test: reuse image generate tool imports

* test: reuse followup runner imports

* docs(config): tighten wording in reference

* test: harden provider mock isolation

* fix(memory): accept embedded dreaming heartbeat tokens

* test: harden Parallels macOS smoke fallback

* build: narrow plugin SDK declaration build

* fix(dotenv): block workspace runtime env vars (openclaw#62660)

* fix(dotenv): block workspace runtime env vars

Co-authored-by: zsx <git@zsxsoft.com>

* docs(changelog): add workspace dotenv runtime-control entry

* fix(dotenv): block workspace gateway port override

---------

Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>

* build: stage nostr runtime dependencies

* fix: load QA live provider overrides

* feat: parallelize character eval runs

* auth: avoid external cli sync on profile upsert

* test(doctor): mock memory-core runtime seam

* auth: persist explicit profile upserts directly

* Matrix: report startup failures as errors

* fix(browser): harden browser control override loading (openclaw#62663)

* fix(browser): harden browser control overrides

* fix(lint): prepare boundary artifacts for extension oxlint

* docs(changelog): add browser override hardening entry

* fix(lint): avoid duplicate boundary prep

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
Co-authored-by: Devin Robison <drobison00@users.noreply.github.com>

* test: reuse exec directive reply imports

* test: reuse verbose directive reply imports

* fix(browser): re-check interaction-driven navigations (openclaw#63226)

* fix(browser): guard interaction-driven navigations

* fix(browser): avoid rechecking unchanged interaction urls

* fix(browser): guard delayed interaction navigations

* fix(browser): guard interaction-driven navigations for full action duration

* fix(browser): avoid waiting on interaction grace timer

* fix(browser): ignore same-document hash-only URL changes in navigation guard

* fix(browser): dedupe interaction nav guards

* fix(browser): guard same-URL reloads in interaction navigation listeners

* docs(changelog): add interaction navigation guard entry

* fix(browser): drop duplicate ssrfPolicy props

* fix(browser): tighten interaction navigation guards

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>

* test: move directive state coverage to pure tests

* fix: enable thinking support for the ollama api (openclaw#62712)

Merged via squash.

Prepared head SHA: c0b9950
Co-authored-by: hoyyeva <63033505+hoyyeva@users.noreply.github.com>
Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com>
Reviewed-by: @BruceMacD

* Slack: treat ACP block text as visible output (openclaw#62858)

Merged via squash.

Prepared head SHA: 14f202e
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* fix: fail fast on qa live auth errors

* fix: fail fast across qa scenario wait paths

* test: cover qa scenario wait failure replies

* fix: sanitize qa missing-key replies

* test: cover sanitized qa missing-key replies

* fix: align qa wait cursor semantics

* test: cover mixed-traffic qa wait cursors

* fix: classify curated qa missing-key replies

* test: cover curated qa missing-key reply classification

* fix: harden qa missing-key provider messages

* test: cover unsafe qa missing-key providers

* docs(changelog): add qa auth fail-fast entry (openclaw#63333) (thanks @shakkernerd)

* fix(matrix/doctor): migrate legacy channels.matrix.dm.policy 'trusted' (fixes openclaw#62931) (openclaw#62942)

Merged via squash.

Prepared head SHA: d9f553b
Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* Memory/dreaming: feed grounded backfill into short-term promotion (openclaw#63370)

Merged via squash.

Prepared head SHA: 5dfe246
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* docs: update unreleased changelog

* fix(gateway): classify dream diary actions

* fix(memory): align dreaming status payloads

* Memory/dreaming: harden grounded backfill follow-ups

* test: reuse inline directive reply imports

* Docs/memory: explain grounded backfill flows

* fix(deps): patch basic-ftp advisory

* test: move inline directive collisions to pure tests

* Slack: dedupe partial streaming replies (openclaw#62859)

Merged via squash.

Prepared head SHA: cbecb50
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* test: replace exec directive e2e with pure coverage

* fix(plugins): keep test helpers out of contract barrels (openclaw#63311)

Merged via squash.

Prepared head SHA: 769e90c
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf

* test: move cron heartbeat delivery coverage below full turns

* fix: inter-session messages must not overwrite established external lastRoute (openclaw#58013)

Merged via squash.

Prepared head SHA: 820ea20
Co-authored-by: duqaXxX <12242811+duqaXxX@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* fix(gateway): suppress announce/reply skip chat leakage (openclaw#51739)

Merged via squash.

Prepared head SHA: 2f53f3b
Co-authored-by: Pinghuachiu <9033138+Pinghuachiu@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* Slack: key turn-local dedupe by dispatch kind

Scope Slack turn-local delivery dedupe by reply dispatch kind so identical tool and final payloads on the same thread do not collapse into one send.

Expose the existing dispatcher kind on the public reply-runtime seam and cover the Slack tracker and preview-fallback paths with regression tests.

* Dreaming: surface grounded scene lane (openclaw#63395)

Merged via squash.

Prepared head SHA: 0c7f586
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* test: avoid runtime auth overlays in failure-state coverage

* fix(ci): align ollama thinking expectations

* chore(ui): refresh zh-CN control ui locale

* chore(ui): refresh pt-BR control ui locale

* chore(ui): refresh zh-TW control ui locale

* chore(ui): refresh de control ui locale

* test(docker): reduce e2e log noise

* chore(ui): refresh es control ui locale

* chore(ui): refresh fr control ui locale

* chore(ui): refresh ja-JP control ui locale

* chore(ui): refresh ko control ui locale

* chore(ui): refresh uk control ui locale

* chore(ui): refresh id control ui locale

* chore(ui): refresh pl control ui locale

* chore(ui): refresh tr control ui locale

* fix: restore main ci

* fix(ci): drop silent history before truncation

* docs: reorder unreleased changelog

* test(docker): quiet success-path e2e logs

* style: sort session import

* build: mirror bundled plugin runtime deps

* plugins: load lightweight provider discovery entries

* ci: narrow Windows node test lane

* fix: filter provider auth aliases by plugin trust

* fix: surface delayed browser navigation blocks

* style: format memory and gateway touchups

* Delete docs/plans directory

Unused artifact

* test: avoid remote ollama timeout in api-key preservation coverage

* test: keep auth-choice default-model coverage on lightweight provider

* test: keep undefined-token auth-choice coverage generic

* fix: stabilize character eval and Qwen model routing

* test: keep agent command tests off external auth overlays

* fix openrouter model picker refs (openclaw#63416)

* fix openrouter model picker refs

Signed-off-by: sallyom <somalley@redhat.com>

* test(ui): cover openrouter slash-id /model resolution

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Vignesh Natarajan <vignesh.natarajan92@gmail.com>

* ci: stabilize macOS and transcript policy tests

* test: keep cli-provider agent command tests off external auth overlays

* chore(lint): clear extension lint regressions and add openclaw#63416 changelog

* test: update modelstudio catalog contract sentinel

* test: update character eval public panel

* fix: repair Windows dev-channel updater

* test: move copilot models-json injection coverage to plan tests

* plugin-sdk: split command status surface

* plugin-sdk: keep command status compatibility path light

* plugin-sdk: drop investigative weixin repro harness

* tests: document config mock choice for eager warmup

* fix: update command-status SDK baseline (openclaw#63174) (thanks @hxy91819)

* test: cap broad live model sweeps

* fix: drop raw gateway chat control replies

* test: make shared-token reload deterministic

* test: isolate agentic suite smoke tests

* test: replace models-config matrix with narrow coverage

* test: isolate onboard skills status mock

* plugins: add lightweight anthropic vertex discovery

* test: isolate model auth module state

* test: isolate subagent registry resume imports

* plugins: keep google provider policy lightweight

* test: keep ollama unreachable discovery on localhost

* test: mock auth profile external overlay in oauth tests

* auth: avoid plugin setup scans during common auth resolution

* fix(logging): break console/logger type cycle

* fix(config): stop owner-display barrel cycles

* fix(commands): split auth choice apply types

* fix(infra): extract exec approvals allowlist types

* fix(commands): split doctor prompt option types

* chore: prepare 2026.4.9-beta.1 release

* chore: refresh config schema version for 2026.4.9-beta.1

* chore: refresh plugin SDK API baseline

* test: run local full suite project shards in parallel

* wizard: add explicit skip option to plugin setup (openclaw#63436)

* Wizard: allow skipping plugin setup

* Agents: reset nodes tool test modules

* tests: reset discord native-command seams in model picker (openclaw#63267)

* ci: tolerate noisy npm pack json output

* test: isolate slack thread-ts recovery

* fix(msteams): isolate channel thread sessions by replyToId (openclaw#58615) (openclaw#62713)

* fix(msteams): isolate thread sessions by replyToId (openclaw#58615)

* fix(msteams): align thread ID extraction + fix test types

* fix(msteams): route thread replies to correct thread via replyToId (openclaw#58030) (openclaw#62715)

* fix(msteams): pin reply target at inbound time to prevent DM/channel leak (openclaw#54520) (openclaw#62716)

* test: keep local full suite serial by default

* chore: prepare 2026.4.9 stable release

* Agents: guard legacy pi transport override

* Agents: restore upstream pi runner sources

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Nimrod Gutman <nimrod.gutman@gmail.com>
Co-authored-by: Tyler Warburton <Ethan.gold-Steinberg@protonmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Eric Curtin <eric.curtin@docker.com>
Co-authored-by: Mariano <mbelinky@gmail.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net>
Co-authored-by: Pavan Kumar Gondhi <pgondhi@nvidia.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: Agustin Rivera <31522568+eleqtrizit@users.noreply.github.com>
Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison00@users.noreply.github.com>
Co-authored-by: Eva H <63033505+hoyyeva@users.noreply.github.com>
Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com>
Co-authored-by: Shakker <shakkerdroid@gmail.com>
Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com>
Co-authored-by: Altay <altay@uinaf.dev>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Co-authored-by: Accunza <12242811+duqaXxX@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: Pinghuachiu <9033138+Pinghuachiu@users.noreply.github.com>
Co-authored-by: Radek Sienkiewicz <mail@velvetshark.com>
Co-authored-by: Sally O'Malley <somalley@redhat.com>
Co-authored-by: Vignesh Natarajan <vignesh.natarajan92@gmail.com>
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: pashpashpash <nik@vault77.ai>
Co-authored-by: sudie-codes <suvenkat95@gmail.com>
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request Apr 27, 2026
Merged via squash.

Prepared head SHA: ac26799
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
Merged via squash.

Prepared head SHA: ac26799
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Merged via squash.

Prepared head SHA: ac26799
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord channel: feishu Channel integration: feishu channel: slack Channel integration: slack channel: telegram Channel integration: telegram maintainer Maintainer-authored PR scripts Repository scripts size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: npm install -g openclaw crashes - stageRuntimeDependencies not staging @buape/carbon and @larksuiteoapi/node-sdk

3 participants