Merged
Size
XL
Change Breakdown
Refactor40%
Security20%
Maintenance15%
Config15%
Testing10%
#61548refactor: add xai plugin-sdk boundary canary

Plugin SDK package boundaries enforced by TypeScript

Extensions can no longer sneak illegal imports past the type checker—a new @openclaw/plugin-sdk package and boundary tsconfig now catch cross-package violations at compile time.

TypeScript could not enforce where bundled extensions fetched their dependencies. Import paths like looked valid inside an extension's local editing context because the repo carried a permissive root alias. Nothing failed until runtime—or worse, until production.

A new @openclaw/plugin-sdk workspace package now provides a proper import surface. The xAI extension has been migrated to use it: instead of openclaw/plugin-sdk/provider-web-search, imports now read @openclaw/plugin-sdk/provider-web-search. A new tsconfig base () wires those paths to generated declaration files, and TypeScript now fails with TS6059 when an extension tries to reach outside its own package root.

The change is surgical—only the xAI extension is opted in, as a canary. Existing bundled extensions continue working through the legacy alias. The groundwork is laid for other extensions to adopt stricter boundaries incrementally. Plugin authors who accidentally reach into forbidden source directories will now hear about it from the compiler, not from a production incident.

View Original GitHub DescriptionFact Check

Summary

  • Problem: bundled extensions still rely on the root openclaw/plugin-sdk/* path alias, so TypeScript does not fail closed when an extension reaches outside its own package root.
  • Why it matters: an illegal import like ../../src/cli/acp-cli.ts can look valid in normal extension-local editing unless a separate boundary script catches it.
  • What changed: I added a real internal @openclaw/plugin-sdk workspace package, opted extensions/xai into a package-boundary tsconfig, and added focused contract tests that prove clean typechecking plus TS6059 failure for a bad relative import.
  • What did NOT change (scope boundary): I did not migrate the rest of the extension tree yet, and this first canary still bridges types through generated plugin-sdk declaration artifacts.

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 #
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: extension-local TypeScript projects were not resolving allowed SDK imports through a real package surface, so adding rootDir alone either did nothing or broke allowed imports along with forbidden ones.
  • Missing detection / guardrail: the repo had boundary scripts, but normal extension-local TypeScript checking did not fail closed for opted-in packages.
  • Contributing context (if known): the root repo still carries a broad openclaw/plugin-sdk/* alias for legacy extensions, so the incremental rollout needs both legacy and opt-in modes in parallel.

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: src/plugins/contracts/extension-package-project-boundaries.test.ts and test/extension-package-tsc-boundary.test.ts
  • Scenario the test should lock in: extensions/xai typechecks through @openclaw/plugin-sdk/*, and a canary import of ../../src/cli/acp-cli.ts fails with TS6059.
  • Why this is the smallest reliable guardrail: it exercises the real extension-local tsconfig.json boundary instead of only checking custom lint or report scripts.
  • Existing test that already covers this (if any): the existing check-extension-plugin-sdk-boundary script still covers the relative-outside-package rule.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

None.

Diagram (if applicable)

Before:
[xai source] -> openclaw/plugin-sdk/* root alias -> raw src/plugin-sdk/*.ts
[xai source] -> ../../src/... -> allowed by local tsc

After:
[xai source] -> @openclaw/plugin-sdk/* -> internal package runtime + declaration bridge
[xai source] -> ../../src/... -> TS6059 failure

Security Impact (required)

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

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local Node 22 workspace
  • Model/provider: N/A
  • Integration/channel (if any): xAI bundled plugin
  • Relevant config (redacted): default repo workspace config

Steps

  1. Run ./node_modules/.bin/tsc -p tsconfig.plugin-sdk.dts.json.
  2. Run ./node_modules/.bin/tsc -p extensions/xai/tsconfig.json --noEmit.
  3. Add a temporary import * as foo from "../../src/cli/acp-cli.ts"; canary under extensions/xai and rerun the extension typecheck.

Expected

  • extensions/xai typechecks cleanly through @openclaw/plugin-sdk/*.
  • The canary bad import fails with TS6059.

Actual

  • Verified locally.

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: tsc -p tsconfig.plugin-sdk.dts.json, tsc -p extensions/xai/tsconfig.json --noEmit, pnpm test src/plugins/contracts/extension-package-project-boundaries.test.ts test/extension-package-tsc-boundary.test.ts, pnpm test extensions/xai/onboard.test.ts, and the deliberate boundary canary through both tsc and node scripts/check-extension-plugin-sdk-boundary.mjs --mode=relative-outside-package.
  • Edge cases checked: the bad relative import canary under extensions/xai fails while the clean package import path still typechecks.
  • What you did not verify: I did not migrate the other first-wave extensions yet, and I did not yet remove the declaration bridge from this canary.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

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

Risks and Mitigations

  • Risk: the canary still depends on generated plugin-sdk declaration artifacts for type resolution.
    • Mitigation: I kept the rollout to xai only and I am following this with a deeper change to make the package own its source/types end to end.
© 2026 · via Gitpulse