Skip to content

release: fix packaged release-check workflow#124

Merged
linfangw merged 1 commit into
mainfrom
linfangw-release-check-fixes-2026-04-18
Apr 18, 2026
Merged

release: fix packaged release-check workflow#124
linfangw merged 1 commit into
mainfrom
linfangw-release-check-fixes-2026-04-18

Conversation

@linfangw

Copy link
Copy Markdown
Member

Summary

  • Problem: pnpm release:check in the @qverisai/qverisbot fork was blocked by a stale removed script reference, heavy bundled channel config metadata loading, incorrect
    packaged bundled-channel entry shape for x, package-name-specific self-import failures in built bundled extensions, and a few missing packaged build/static artifacts.
  • Why it matters: release validation could not complete on the QVerisBot fork, so packaged install smoke failed before publish-time verification could finish.
  • What changed: removed the stale release-check script reference, narrowed googlechat and telegram config-schema imports to schema-only SDK surfaces, added a proper bundled
    channel entry surface for x, made release/build aliasing and packaged self-import rewriting honor the root package name, and ensured the required packaged build artifacts/
    static assets are emitted and copied.
  • What did NOT change (scope boundary): no user-facing channel behavior, auth flow, provider logic, or public config semantics were intentionally changed beyond fixing
    packaging/release validation and schema-loading paths.

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

  • Closes #N/A
  • Related #N/A
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: release/build code still assumed the upstream openclaw package identity in several packaged-extension paths, while the forked package name is @qverisai/
    qverisbot; in parallel, some bundled channel surfaces used overly broad imports during metadata generation, and extensions/x/index.ts still exported a plain plugin instead
    of a bundled channel entry contract.
  • Missing detection / guardrail: there was no narrow regression coverage for package-name-aware bundled extension self-import rewriting, no dedicated contract check for the x
    bundled channel entry, and release-time packaged smoke was the first guardrail exercising the installed tarball under the renamed package.
  • Contributing context (if known): pnpm build could leave follow-up build artifacts incomplete when the local build flow stalled after runtime-postbuild, which made release-
    check surface additional missing packaged files.

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/release-check.test.ts, test/scripts/runtime-postbuild.test.ts, src/plugins/contracts/plugin-sdk-root-alias.test.ts, src/plugins/sdk-alias.test.ts,
    extensions/x/index.test.ts, and packaged smoke via scripts/test-built-bundled-channel-entry-smoke.mjs.
  • Scenario the test should lock in: release:check must succeed for the @qverisai/qverisbot package name, bundled extensions in dist/ must rewrite self-imports away from
    openclaw/..., x must export a bundled-channel-entry, and channel config metadata generation must stay on narrow schema-only imports.
  • Why this is the smallest reliable guardrail: unit tests cover the alias/rewrite logic cheaply, while the packaged bundled-channel smoke is the smallest reliable installed-
    artifact check for tarball-time module resolution.
  • Existing test that already covers this (if any): scripts/test-built-bundled-channel-entry-smoke.mjs already covered the installed bundled-entry path once release-check could
    reach it.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

None for end users.
Maintainer/release behavior changes: pnpm release:check now succeeds for the QVerisBot forked package and packaged bundled channel smoke passes.

Diagram (if applicable)

Before:
[pnpm release:check] -> [packaged install smoke] -> [stale script / broad schema import / wrong entry shape / openclaw self-import / missing artifacts] -> [fail]

After:
[pnpm release:check] -> [package-name-aware build + packaged smoke] -> [bundled entries load under @qverisai/qverisbot] -> [pass]

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: N/A

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local checkout with Node 24.2.0 and pnpm
  • Model/provider: N/A
  • Integration/channel (if any): bundled packaged channels, especially googlechat, telegram, x, discord; static packaged assets in acpx and diffs
  • Relevant config (redacted): root package renamed to @qverisai/qverisbot; local ~/.openclaw/extensions/qveris present and emits a non-blocking duplicate-plugin warning during
    checks

Steps

  1. Run pnpm release:check from the QVerisBot fork.
  2. Observe the packaged validation failures in release-check.
  3. Apply this PR and rerun pnpm release:check.

Expected

  • Release validation completes, including packaged install smoke and bundled channel entry smoke.

Actual

  • Before this PR, release validation failed on stale script references, bundled channel metadata loading, packaged entry resolution, and missing packaged artifacts.
  • After this PR, pnpm release:check passes end to end.

Evidence

Attach at least one:

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

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: pnpm check:bundled-channel-config-metadata, node scripts/run-vitest.mjs run extensions/x/index.test.ts, pnpm build:plugin-sdk:dts, node scripts/check-
    plugin-sdk-exports.mjs, static asset/build artifact presence in dist/, and pnpm release:check.
  • Edge cases checked: packaged bundled channel smoke under installed @qverisai/qverisbot, x bundled entry contract shape, narrow schema-only loading for googlechat and
    telegram, and packaged static sidecars for acpx / diffs.
  • What you did not verify: actual publish/tag workflow, npm publish, or post-publish install verification against a published registry version.

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: N/A

Risks and Mitigations

  • Risk: future bundled extension outputs could introduce new self-import spellings that the current rewrite pass does not catch.
    • Mitigation: release-check packaged smoke and the added runtime-postbuild / alias tests now cover the current contract and will fail again if packaging regresses.
  • Risk: narrowing config-schema imports could drift if plugin barrels are changed later without keeping schema-only paths aligned.
    • Mitigation: bundled channel config metadata check now exercises these schema entrypoints directly, and the release gate depends on it.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces dynamic package name resolution for the plugin SDK, enabling support for forks and renamed packages. Key changes include refactoring the X extension with narrow entry points, adding a post-build script to rewrite self-imports in bundled extensions, and updating the release check process to use an isolated npm environment. Feedback was provided regarding the performance of the dynamic alias resolution in root-alias.cjs, specifically recommending the use of a cache to avoid redundant synchronous disk I/O during plugin loading.

const jitiLoaders = new Map();
const pluginSdkSubpathsCache = new Map();
const pluginSdkPackageNames = ["openclaw/plugin-sdk", "@openclaw/plugin-sdk"];
const pluginSdkSourceExtensions = [".ts", ".mts", ".js", ".mjs", ".cts", ".cjs"];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The hardcoded pluginSdkPackageNames constant was removed in favor of a dynamic lookup, but the new lookup function listPluginSdkPackageNames is called repeatedly within loops in buildPluginSdkAliasMap. Since it performs synchronous disk I/O to read package.json, this can significantly impact performance during plugin loading.

I suggest adding a cache variable at the top level to store the resolved package names.

let pluginSdkPackageNamesCache = null;
const pluginSdkSourceExtensions = [".ts", ".mts", ".js", ".mjs", ".cts", ".cjs"];

Comment on lines +90 to +104
function listPluginSdkPackageNames() {
const packageNames = new Set(["openclaw/plugin-sdk", "@openclaw/plugin-sdk"]);
try {
const packageJson = JSON.parse(
fs.readFileSync(path.join(getPackageRoot(), "package.json"), "utf8"),
);
const rootPackageName = typeof packageJson?.name === "string" ? packageJson.name.trim() : "";
if (rootPackageName) {
packageNames.add(`${rootPackageName}/plugin-sdk`);
}
} catch {
// Keep the canonical aliases even if package.json is unavailable.
}
return [...packageNames];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Implement caching in listPluginSdkPackageNames to avoid redundant synchronous disk I/O when resolving package names multiple times. This is particularly important because this function is called inside a loop over all exported subpaths in buildPluginSdkAliasMap.

function listPluginSdkPackageNames() {
  if (pluginSdkPackageNamesCache) {
    return pluginSdkPackageNamesCache;
  }
  const packageNames = new Set(["openclaw/plugin-sdk", "@openclaw/plugin-sdk"]);
  try {
    const packageJson = JSON.parse(
      fs.readFileSync(path.join(getPackageRoot(), "package.json"), "utf8"),
    );
    const rootPackageName = typeof packageJson?.name === "string" ? packageJson.name.trim() : "";
    if (rootPackageName) {
      packageNames.add(`${rootPackageName}/plugin-sdk`);
    }
  } catch {
    // Keep the canonical aliases even if package.json is unavailable.
  }
  pluginSdkPackageNamesCache = [...packageNames];
  return pluginSdkPackageNamesCache;
}

@linfangw
linfangw merged commit 638f42c into main Apr 18, 2026
2 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant