Plugins: rename extensions to native plugins

This commit is contained in:
Onur Solmaz 2026-03-20 09:30:16 +01:00
parent f1e012e0fc
commit 8f1e91c350
2553 changed files with 3590 additions and 3308 deletions

View File

@ -24,7 +24,7 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- `prlctl exec` is fine for deterministic repo commands, but use the guest Terminal or `prlctl enter` when installer parity or shell-sensitive behavior matters.
- On the fresh Tahoe snapshot, `brew` exists but `node` may be missing from PATH in noninteractive exec. Use `/opt/homebrew/bin/node` when needed.
- Fresh host-served tgz installs should install as guest root with `HOME=/var/root`, then run onboarding as the desktop user via `prlctl exec --current-user`.
- Root-installed tgz smoke can log plugin blocks for world-writable `extensions/*`; do not treat that as an onboarding or gateway failure unless plugin loading is the task.
- Root-installed tgz smoke can log plugin blocks for world-writable `native-plugins/*`; do not treat that as an onboarding or gateway failure unless plugin loading is the task.
## Windows flow

174
.github/labeler.yml vendored
View File

@ -1,107 +1,107 @@
"channel: bluebubbles":
- changed-files:
- any-glob-to-any-file:
- "extensions/bluebubbles/**"
- "native-plugins/bluebubbles/**"
- "docs/channels/bluebubbles.md"
"channel: discord":
- changed-files:
- any-glob-to-any-file:
- "extensions/discord/**"
- "native-plugins/discord/**"
- "docs/channels/discord.md"
"channel: irc":
- changed-files:
- any-glob-to-any-file:
- "extensions/irc/**"
- "native-plugins/irc/**"
- "docs/channels/irc.md"
"channel: feishu":
- changed-files:
- any-glob-to-any-file:
- "src/feishu/**"
- "extensions/feishu/**"
- "native-plugins/feishu/**"
- "docs/channels/feishu.md"
"channel: googlechat":
- changed-files:
- any-glob-to-any-file:
- "extensions/googlechat/**"
- "native-plugins/googlechat/**"
- "docs/channels/googlechat.md"
"channel: imessage":
- changed-files:
- any-glob-to-any-file:
- "extensions/imessage/**"
- "native-plugins/imessage/**"
- "docs/channels/imessage.md"
"channel: line":
- changed-files:
- any-glob-to-any-file:
- "extensions/line/**"
- "native-plugins/line/**"
- "docs/channels/line.md"
"channel: matrix":
- changed-files:
- any-glob-to-any-file:
- "extensions/matrix/**"
- "native-plugins/matrix/**"
- "docs/channels/matrix.md"
"channel: mattermost":
- changed-files:
- any-glob-to-any-file:
- "extensions/mattermost/**"
- "native-plugins/mattermost/**"
- "docs/channels/mattermost.md"
"channel: msteams":
- changed-files:
- any-glob-to-any-file:
- "extensions/msteams/**"
- "native-plugins/msteams/**"
- "docs/channels/msteams.md"
"channel: nextcloud-talk":
- changed-files:
- any-glob-to-any-file:
- "extensions/nextcloud-talk/**"
- "native-plugins/nextcloud-talk/**"
- "docs/channels/nextcloud-talk.md"
"channel: nostr":
- changed-files:
- any-glob-to-any-file:
- "extensions/nostr/**"
- "native-plugins/nostr/**"
- "docs/channels/nostr.md"
"channel: signal":
- changed-files:
- any-glob-to-any-file:
- "extensions/signal/**"
- "native-plugins/signal/**"
- "docs/channels/signal.md"
"channel: slack":
- changed-files:
- any-glob-to-any-file:
- "extensions/slack/**"
- "native-plugins/slack/**"
- "docs/channels/slack.md"
"channel: telegram":
- changed-files:
- any-glob-to-any-file:
- "extensions/telegram/**"
- "native-plugins/telegram/**"
- "docs/channels/telegram.md"
"channel: tlon":
- changed-files:
- any-glob-to-any-file:
- "extensions/tlon/**"
- "native-plugins/tlon/**"
- "docs/channels/tlon.md"
"channel: twitch":
- changed-files:
- any-glob-to-any-file:
- "extensions/twitch/**"
- "native-plugins/twitch/**"
- "docs/channels/twitch.md"
"channel: voice-call":
- changed-files:
- any-glob-to-any-file:
- "extensions/voice-call/**"
- "native-plugins/voice-call/**"
"channel: whatsapp-web":
- changed-files:
- any-glob-to-any-file:
- "extensions/whatsapp/**"
- "native-plugins/whatsapp/**"
- "docs/channels/whatsapp.md"
"channel: zalo":
- changed-files:
- any-glob-to-any-file:
- "extensions/zalo/**"
- "native-plugins/zalo/**"
- "docs/channels/zalo.md"
"channel: zalouser":
- changed-files:
- any-glob-to-any-file:
- "extensions/zalouser/**"
- "native-plugins/zalouser/**"
- "docs/channels/zalouser.md"
"app: android":
@ -193,135 +193,135 @@
- "docs/cli/security.md"
- "docs/gateway/security.md"
"extensions: copilot-proxy":
"native plugins: copilot-proxy":
- changed-files:
- any-glob-to-any-file:
- "extensions/copilot-proxy/**"
"extensions: diagnostics-otel":
- "native-plugins/copilot-proxy/**"
"native plugins: diagnostics-otel":
- changed-files:
- any-glob-to-any-file:
- "extensions/diagnostics-otel/**"
"extensions: llm-task":
- "native-plugins/diagnostics-otel/**"
"native plugins: llm-task":
- changed-files:
- any-glob-to-any-file:
- "extensions/llm-task/**"
"extensions: lobster":
- "native-plugins/llm-task/**"
"native plugins: lobster":
- changed-files:
- any-glob-to-any-file:
- "extensions/lobster/**"
"extensions: memory-core":
- "native-plugins/lobster/**"
"native plugins: memory-core":
- changed-files:
- any-glob-to-any-file:
- "extensions/memory-core/**"
"extensions: memory-lancedb":
- "native-plugins/memory-core/**"
"native plugins: memory-lancedb":
- changed-files:
- any-glob-to-any-file:
- "extensions/memory-lancedb/**"
"extensions: open-prose":
- "native-plugins/memory-lancedb/**"
"native plugins: open-prose":
- changed-files:
- any-glob-to-any-file:
- "extensions/open-prose/**"
"extensions: qwen-portal-auth":
- "native-plugins/open-prose/**"
"native plugins: qwen-portal-auth":
- changed-files:
- any-glob-to-any-file:
- "extensions/qwen-portal-auth/**"
"extensions: device-pair":
- "native-plugins/qwen-portal-auth/**"
"native plugins: device-pair":
- changed-files:
- any-glob-to-any-file:
- "extensions/device-pair/**"
"extensions: acpx":
- "native-plugins/device-pair/**"
"native plugins: acpx":
- changed-files:
- any-glob-to-any-file:
- "extensions/acpx/**"
"extensions: byteplus":
- "native-plugins/acpx/**"
"native plugins: byteplus":
- changed-files:
- any-glob-to-any-file:
- "extensions/byteplus/**"
"extensions: anthropic":
- "native-plugins/byteplus/**"
"native plugins: anthropic":
- changed-files:
- any-glob-to-any-file:
- "extensions/anthropic/**"
"extensions: cloudflare-ai-gateway":
- "native-plugins/anthropic/**"
"native plugins: cloudflare-ai-gateway":
- changed-files:
- any-glob-to-any-file:
- "extensions/cloudflare-ai-gateway/**"
"extensions: minimax-portal-auth":
- "native-plugins/cloudflare-ai-gateway/**"
"native plugins: minimax-portal-auth":
- changed-files:
- any-glob-to-any-file:
- "extensions/minimax-portal-auth/**"
"extensions: huggingface":
- "native-plugins/minimax-portal-auth/**"
"native plugins: huggingface":
- changed-files:
- any-glob-to-any-file:
- "extensions/huggingface/**"
"extensions: kilocode":
- "native-plugins/huggingface/**"
"native plugins: kilocode":
- changed-files:
- any-glob-to-any-file:
- "extensions/kilocode/**"
"extensions: openai":
- "native-plugins/kilocode/**"
"native plugins: openai":
- changed-files:
- any-glob-to-any-file:
- "extensions/openai/**"
"extensions: kimi-coding":
- "native-plugins/openai/**"
"native plugins: kimi-coding":
- changed-files:
- any-glob-to-any-file:
- "extensions/kimi-coding/**"
"extensions: minimax":
- "native-plugins/kimi-coding/**"
"native plugins: minimax":
- changed-files:
- any-glob-to-any-file:
- "extensions/minimax/**"
"extensions: modelstudio":
- "native-plugins/minimax/**"
"native plugins: modelstudio":
- changed-files:
- any-glob-to-any-file:
- "extensions/modelstudio/**"
"extensions: moonshot":
- "native-plugins/modelstudio/**"
"native plugins: moonshot":
- changed-files:
- any-glob-to-any-file:
- "extensions/moonshot/**"
"extensions: nvidia":
- "native-plugins/moonshot/**"
"native plugins: nvidia":
- changed-files:
- any-glob-to-any-file:
- "extensions/nvidia/**"
"extensions: phone-control":
- "native-plugins/nvidia/**"
"native plugins: phone-control":
- changed-files:
- any-glob-to-any-file:
- "extensions/phone-control/**"
"extensions: qianfan":
- "native-plugins/phone-control/**"
"native plugins: qianfan":
- changed-files:
- any-glob-to-any-file:
- "extensions/qianfan/**"
"extensions: synthetic":
- "native-plugins/qianfan/**"
"native plugins: synthetic":
- changed-files:
- any-glob-to-any-file:
- "extensions/synthetic/**"
"extensions: tavily":
- "native-plugins/synthetic/**"
"native plugins: tavily":
- changed-files:
- any-glob-to-any-file:
- "extensions/tavily/**"
"extensions: talk-voice":
- "native-plugins/tavily/**"
"native plugins: talk-voice":
- changed-files:
- any-glob-to-any-file:
- "extensions/talk-voice/**"
"extensions: together":
- "native-plugins/talk-voice/**"
"native plugins: together":
- changed-files:
- any-glob-to-any-file:
- "extensions/together/**"
"extensions: venice":
- "native-plugins/together/**"
"native plugins: venice":
- changed-files:
- any-glob-to-any-file:
- "extensions/venice/**"
"extensions: vercel-ai-gateway":
- "native-plugins/venice/**"
"native plugins: vercel-ai-gateway":
- changed-files:
- any-glob-to-any-file:
- "extensions/vercel-ai-gateway/**"
"extensions: volcengine":
- "native-plugins/vercel-ai-gateway/**"
"native plugins: volcengine":
- changed-files:
- any-glob-to-any-file:
- "extensions/volcengine/**"
"extensions: xiaomi":
- "native-plugins/volcengine/**"
"native plugins: xiaomi":
- changed-files:
- any-glob-to-any-file:
- "extensions/xiaomi/**"
"extensions: fal":
- "native-plugins/xiaomi/**"
"native plugins: fal":
- changed-files:
- any-glob-to-any-file:
- "extensions/fal/**"
- "native-plugins/fal/**"

View File

@ -78,13 +78,13 @@ jobs:
node scripts/ci-changed-scope.mjs --base "$BASE" --head HEAD
changed-extensions:
changed-native-plugins:
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
outputs:
has_changed_extensions: ${{ steps.changed.outputs.has_changed_extensions }}
changed_extensions_matrix: ${{ steps.changed.outputs.changed_extensions_matrix }}
has_changed_native_plugins: ${{ steps.changed.outputs.has_changed_native_plugins }}
changed_native_plugins_matrix: ${{ steps.changed.outputs.changed_native_plugins_matrix }}
steps:
- name: Checkout
uses: actions/checkout@v6
@ -93,7 +93,7 @@ jobs:
fetch-tags: false
submodules: false
- name: Ensure changed-extensions base commit
- name: Ensure changed-native-plugins base commit
uses: ./.github/actions/ensure-base-commit
with:
base-sha: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
@ -106,20 +106,20 @@ jobs:
install-deps: "false"
use-sticky-disk: "false"
- name: Detect changed extensions
- name: Detect changed native plugins
id: changed
env:
BASE_SHA: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
run: |
node --input-type=module <<'EOF'
import { appendFileSync } from "node:fs";
import { listChangedExtensionIds } from "./scripts/test-extension.mjs";
import { listChangedNativePluginIds } from "./scripts/test-native-plugin.mjs";
const extensionIds = listChangedExtensionIds({ base: process.env.BASE_SHA, head: "HEAD" });
const matrix = JSON.stringify({ include: extensionIds.map((extension) => ({ extension })) });
const nativePluginIds = listChangedNativePluginIds({ base: process.env.BASE_SHA, head: "HEAD" });
const matrix = JSON.stringify({ include: nativePluginIds.map((nativePlugin) => ({ nativePlugin })) });
appendFileSync(process.env.GITHUB_OUTPUT, `has_changed_extensions=${extensionIds.length > 0}\n`, "utf8");
appendFileSync(process.env.GITHUB_OUTPUT, `changed_extensions_matrix=${matrix}\n`, "utf8");
appendFileSync(process.env.GITHUB_OUTPUT, `has_changed_native_plugins=${nativePluginIds.length > 0}\n`, "utf8");
appendFileSync(process.env.GITHUB_OUTPUT, `changed_native_plugins_matrix=${matrix}\n`, "utf8");
EOF
# Build dist once for Node-relevant changes and share it with downstream jobs.
@ -201,8 +201,8 @@ jobs:
shard_count: 2
command: pnpm canvas:a2ui:bundle && pnpm test
- runtime: node
task: extensions
command: pnpm test:extensions
task: native-plugins
command: pnpm test:native-plugins
- runtime: node
task: channels
command: pnpm test:channels
@ -263,14 +263,14 @@ jobs:
if: github.event_name != 'pull_request' || (matrix.runtime != 'bun' && matrix.task != 'compat-node22')
run: ${{ matrix.command }}
extension-fast:
name: "extension-fast"
needs: [docs-scope, changed-scope, changed-extensions]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true' && needs.changed-extensions.outputs.has_changed_extensions == 'true'
native-plugin-fast:
name: "native-plugin-fast"
needs: [docs-scope, changed-scope, changed-native-plugins]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true' && needs.changed-native-plugins.outputs.has_changed_native_plugins == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.changed-extensions.outputs.changed_extensions_matrix) }}
matrix: ${{ fromJson(needs.changed-native-plugins.outputs.changed_native_plugins_matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6
@ -283,10 +283,10 @@ jobs:
install-bun: "false"
use-sticky-disk: "false"
- name: Run changed extension tests
- name: Run changed native plugin tests
env:
OPENCLAW_CHANGED_EXTENSION: ${{ matrix.extension }}
run: pnpm test:extension "$OPENCLAW_CHANGED_EXTENSION"
OPENCLAW_CHANGED_NATIVE_PLUGIN: ${{ matrix.nativePlugin }}
run: pnpm test:native-plugin "$OPENCLAW_CHANGED_NATIVE_PLUGIN"
# Types, lint, and format check.
check:
@ -315,8 +315,8 @@ jobs:
- name: Enforce safe external URL opening policy
run: pnpm lint:ui:no-raw-window-open
plugin-extension-boundary:
name: "plugin-extension-boundary"
plugin-native-plugin-boundary:
name: "plugin-native-plugin-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
@ -332,8 +332,8 @@ jobs:
install-bun: "false"
use-sticky-disk: "false"
- name: Run plugin extension boundary guard
run: pnpm run lint:plugins:no-extension-imports
- name: Run plugin native plugin boundary guard
run: pnpm run lint:plugins:no-native-plugin-imports
web-search-provider-boundary:
name: "web-search-provider-boundary"
@ -355,8 +355,8 @@ jobs:
- name: Run web search provider boundary guard
run: pnpm run lint:web-search-provider-boundaries
extension-src-outside-plugin-sdk-boundary:
name: "extension-src-outside-plugin-sdk-boundary"
native-plugin-src-outside-plugin-sdk-boundary:
name: "native-plugin-src-outside-plugin-sdk-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
@ -372,11 +372,11 @@ jobs:
install-bun: "false"
use-sticky-disk: "false"
- name: Run extension src boundary guard
run: pnpm run lint:extensions:no-src-outside-plugin-sdk
- name: Run native plugin src boundary guard
run: pnpm run lint:native-plugins:no-src-outside-plugin-sdk
extension-plugin-sdk-internal-boundary:
name: "extension-plugin-sdk-internal-boundary"
native-plugin-plugin-sdk-internal-boundary:
name: "native-plugin-plugin-sdk-internal-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
@ -392,8 +392,8 @@ jobs:
install-bun: "false"
use-sticky-disk: "false"
- name: Run extension plugin-sdk-internal guard
run: pnpm run lint:extensions:no-plugin-sdk-internal
- name: Run native plugin plugin-sdk-internal guard
run: pnpm run lint:native-plugins:no-plugin-sdk-internal
build-smoke:
name: "build-smoke"

View File

@ -84,8 +84,8 @@ jobs:
openclaw --version &&
node -e "
const Module = require(\"node:module\");
const matrixPackage = require(\"/app/extensions/matrix/package.json\");
const requireFromMatrix = Module.createRequire(\"/app/extensions/matrix/package.json\");
const matrixPackage = require(\"/app/native-plugins/matrix/package.json\");
const requireFromMatrix = Module.createRequire(\"/app/native-plugins/matrix/package.json\");
const runtimeDeps = Object.keys(matrixPackage.dependencies ?? {});
if (runtimeDeps.length === 0) {
throw new Error(
@ -109,7 +109,7 @@ jobs:
const matrixDiag = (parsed.diagnostics || []).filter(
(diag) =>
typeof diag.source === \"string\" &&
diag.source.includes(\"/extensions/matrix\") &&
diag.source.includes(\"/native-plugins/matrix\") &&
typeof diag.message === \"string\" &&
diag.message.includes(\"extension entry escapes package directory\"),
);

View File

@ -6,7 +6,7 @@ on:
- main
paths:
- ".github/workflows/plugin-npm-release.yml"
- "extensions/**"
- "native-plugins/**"
- "package.json"
- "scripts/lib/plugin-npm-release.ts"
- "scripts/plugin-npm-publish.sh"

View File

@ -26,7 +26,7 @@
"assets/",
"dist/",
"docs/_layouts/",
"extensions/",
"native-plugins/",
"node_modules/",
"patches/",
"pnpm-lock.yaml",

View File

@ -10780,561 +10780,561 @@
"line_number": 94
}
],
"extensions/bluebubbles/src/actions.test.ts": [
"native-plugins/bluebubbles/src/actions.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/actions.test.ts",
"filename": "native-plugins/bluebubbles/src/actions.test.ts",
"hashed_secret": "789cbe0407840b1c2041cb33452ff60f19bf58cc",
"is_verified": false,
"line_number": 54
}
],
"extensions/bluebubbles/src/attachments.test.ts": [
"native-plugins/bluebubbles/src/attachments.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/attachments.test.ts",
"filename": "native-plugins/bluebubbles/src/attachments.test.ts",
"hashed_secret": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"is_verified": false,
"line_number": 79
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/attachments.test.ts",
"filename": "native-plugins/bluebubbles/src/attachments.test.ts",
"hashed_secret": "789cbe0407840b1c2041cb33452ff60f19bf58cc",
"is_verified": false,
"line_number": 90
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/attachments.test.ts",
"filename": "native-plugins/bluebubbles/src/attachments.test.ts",
"hashed_secret": "db1530e1ea43af094d3d75b8dbaf19a4a182a318",
"is_verified": false,
"line_number": 154
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/attachments.test.ts",
"filename": "native-plugins/bluebubbles/src/attachments.test.ts",
"hashed_secret": "052f076c732648ab32d2fcde9fe255319bfa0c7b",
"is_verified": false,
"line_number": 260
}
],
"extensions/bluebubbles/src/chat.test.ts": [
"native-plugins/bluebubbles/src/chat.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/chat.test.ts",
"filename": "native-plugins/bluebubbles/src/chat.test.ts",
"hashed_secret": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"is_verified": false,
"line_number": 68
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/chat.test.ts",
"filename": "native-plugins/bluebubbles/src/chat.test.ts",
"hashed_secret": "789cbe0407840b1c2041cb33452ff60f19bf58cc",
"is_verified": false,
"line_number": 93
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/chat.test.ts",
"filename": "native-plugins/bluebubbles/src/chat.test.ts",
"hashed_secret": "5c5a15a8b0b3e154d77746945e563ba40100681b",
"is_verified": false,
"line_number": 115
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/chat.test.ts",
"filename": "native-plugins/bluebubbles/src/chat.test.ts",
"hashed_secret": "faacad0ce4ea1c19b46e128fd79679d37d3d331d",
"is_verified": false,
"line_number": 158
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/chat.test.ts",
"filename": "native-plugins/bluebubbles/src/chat.test.ts",
"hashed_secret": "4dcc26a1d99532846fedf1265df4f40f4e0005b8",
"is_verified": false,
"line_number": 239
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/chat.test.ts",
"filename": "native-plugins/bluebubbles/src/chat.test.ts",
"hashed_secret": "fd2a721f7be1ee3d691a011affcdb11d0ca365a8",
"is_verified": false,
"line_number": 302
}
],
"extensions/bluebubbles/src/monitor.test.ts": [
"native-plugins/bluebubbles/src/monitor.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/monitor.test.ts",
"filename": "native-plugins/bluebubbles/src/monitor.test.ts",
"hashed_secret": "789cbe0407840b1c2041cb33452ff60f19bf58cc",
"is_verified": false,
"line_number": 169
}
],
"extensions/bluebubbles/src/reactions.test.ts": [
"native-plugins/bluebubbles/src/reactions.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/reactions.test.ts",
"filename": "native-plugins/bluebubbles/src/reactions.test.ts",
"hashed_secret": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"is_verified": false,
"line_number": 35
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/reactions.test.ts",
"filename": "native-plugins/bluebubbles/src/reactions.test.ts",
"hashed_secret": "789cbe0407840b1c2041cb33452ff60f19bf58cc",
"is_verified": false,
"line_number": 192
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/reactions.test.ts",
"filename": "native-plugins/bluebubbles/src/reactions.test.ts",
"hashed_secret": "a4a05c9a6449eb9d6cdac81dd7edc49230e327e6",
"is_verified": false,
"line_number": 223
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/reactions.test.ts",
"filename": "native-plugins/bluebubbles/src/reactions.test.ts",
"hashed_secret": "a2833da9f0a16f09994754d0a31749cecf8c8c77",
"is_verified": false,
"line_number": 295
}
],
"extensions/bluebubbles/src/send.test.ts": [
"native-plugins/bluebubbles/src/send.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/send.test.ts",
"filename": "native-plugins/bluebubbles/src/send.test.ts",
"hashed_secret": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"is_verified": false,
"line_number": 79
},
{
"type": "Secret Keyword",
"filename": "extensions/bluebubbles/src/send.test.ts",
"filename": "native-plugins/bluebubbles/src/send.test.ts",
"hashed_secret": "faacad0ce4ea1c19b46e128fd79679d37d3d331d",
"is_verified": false,
"line_number": 757
}
],
"extensions/bluebubbles/src/targets.test.ts": [
"native-plugins/bluebubbles/src/targets.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/bluebubbles/src/targets.test.ts",
"filename": "native-plugins/bluebubbles/src/targets.test.ts",
"hashed_secret": "a3af2fb0c1e2a30bb038049e1e4b401593af6225",
"is_verified": false,
"line_number": 62
}
],
"extensions/copilot-proxy/index.ts": [
"native-plugins/copilot-proxy/index.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/copilot-proxy/index.ts",
"filename": "native-plugins/copilot-proxy/index.ts",
"hashed_secret": "50f013532a9770a2c2cfdc38b7581dd01df69b70",
"is_verified": false,
"line_number": 9
}
],
"extensions/feishu/skills/feishu-doc/SKILL.md": [
"native-plugins/feishu/skills/feishu-doc/SKILL.md": [
{
"type": "Hex High Entropy String",
"filename": "extensions/feishu/skills/feishu-doc/SKILL.md",
"filename": "native-plugins/feishu/skills/feishu-doc/SKILL.md",
"hashed_secret": "8a2256bca273bb01a4e09ae6555b1e6652d9ff8c",
"is_verified": false,
"line_number": 20
}
],
"extensions/feishu/skills/feishu-wiki/SKILL.md": [
"native-plugins/feishu/skills/feishu-wiki/SKILL.md": [
{
"type": "Hex High Entropy String",
"filename": "extensions/feishu/skills/feishu-wiki/SKILL.md",
"filename": "native-plugins/feishu/skills/feishu-wiki/SKILL.md",
"hashed_secret": "8a2256bca273bb01a4e09ae6555b1e6652d9ff8c",
"is_verified": false,
"line_number": 40
}
],
"extensions/feishu/src/channel.test.ts": [
"native-plugins/feishu/src/channel.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/feishu/src/channel.test.ts",
"filename": "native-plugins/feishu/src/channel.test.ts",
"hashed_secret": "8437d84cae482d10a2b9fd3f555d45006979e4be",
"is_verified": false,
"line_number": 21
}
],
"extensions/feishu/src/docx.test.ts": [
"native-plugins/feishu/src/docx.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/feishu/src/docx.test.ts",
"filename": "native-plugins/feishu/src/docx.test.ts",
"hashed_secret": "f49922d511d666848f250663c4fca84074b856a8",
"is_verified": false,
"line_number": 124
}
],
"extensions/feishu/src/media.test.ts": [
"native-plugins/feishu/src/media.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/feishu/src/media.test.ts",
"filename": "native-plugins/feishu/src/media.test.ts",
"hashed_secret": "f49922d511d666848f250663c4fca84074b856a8",
"is_verified": false,
"line_number": 76
}
],
"extensions/feishu/src/reply-dispatcher.test.ts": [
"native-plugins/feishu/src/reply-dispatcher.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/feishu/src/reply-dispatcher.test.ts",
"filename": "native-plugins/feishu/src/reply-dispatcher.test.ts",
"hashed_secret": "f49922d511d666848f250663c4fca84074b856a8",
"is_verified": false,
"line_number": 74
}
],
"extensions/google-antigravity-auth/index.ts": [
"native-plugins/google-antigravity-auth/index.ts": [
{
"type": "Base64 High Entropy String",
"filename": "extensions/google-antigravity-auth/index.ts",
"filename": "native-plugins/google-antigravity-auth/index.ts",
"hashed_secret": "709d0f232b6ac4f8d24dec3e4fabfdb14257174f",
"is_verified": false,
"line_number": 14
}
],
"extensions/google-gemini-cli-auth/oauth.test.ts": [
"native-plugins/google-gemini-cli-auth/oauth.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/google-gemini-cli-auth/oauth.test.ts",
"filename": "native-plugins/google-gemini-cli-auth/oauth.test.ts",
"hashed_secret": "021343c1f561d7bcbc3b513df45cc3a6baf67b43",
"is_verified": false,
"line_number": 43
}
],
"extensions/irc/src/accounts.ts": [
"native-plugins/irc/src/accounts.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/irc/src/accounts.ts",
"filename": "native-plugins/irc/src/accounts.ts",
"hashed_secret": "920f8f5815b381ea692e9e7c2f7119f2b1aa620a",
"is_verified": false,
"line_number": 23
}
],
"extensions/irc/src/client.test.ts": [
"native-plugins/irc/src/client.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/irc/src/client.test.ts",
"filename": "native-plugins/irc/src/client.test.ts",
"hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4",
"is_verified": false,
"line_number": 8
},
{
"type": "Secret Keyword",
"filename": "extensions/irc/src/client.test.ts",
"filename": "native-plugins/irc/src/client.test.ts",
"hashed_secret": "b1cc3814a07fc3d7094f4cc181df7b57b51d165b",
"is_verified": false,
"line_number": 39
}
],
"extensions/line/src/channel.startup.test.ts": [
"native-plugins/line/src/channel.startup.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/line/src/channel.startup.test.ts",
"filename": "native-plugins/line/src/channel.startup.test.ts",
"hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4",
"is_verified": false,
"line_number": 94
}
],
"extensions/matrix/src/matrix/accounts.test.ts": [
"native-plugins/matrix/src/matrix/accounts.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/matrix/src/matrix/accounts.test.ts",
"filename": "native-plugins/matrix/src/matrix/accounts.test.ts",
"hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4",
"is_verified": false,
"line_number": 74
}
],
"extensions/matrix/src/matrix/client.test.ts": [
"native-plugins/matrix/src/matrix/client.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/matrix/src/matrix/client.test.ts",
"filename": "native-plugins/matrix/src/matrix/client.test.ts",
"hashed_secret": "fe7fcdaea49ece14677acd32374d2f1225819d5c",
"is_verified": false,
"line_number": 13
},
{
"type": "Secret Keyword",
"filename": "extensions/matrix/src/matrix/client.test.ts",
"filename": "native-plugins/matrix/src/matrix/client.test.ts",
"hashed_secret": "3dc927d80543dc0f643940b70d066bd4b4c4b78e",
"is_verified": false,
"line_number": 23
}
],
"extensions/matrix/src/matrix/client/storage.ts": [
"native-plugins/matrix/src/matrix/client/storage.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/matrix/src/matrix/client/storage.ts",
"filename": "native-plugins/matrix/src/matrix/client/storage.ts",
"hashed_secret": "7505d64a54e061b7acd54ccd58b49dc43500b635",
"is_verified": false,
"line_number": 8
}
],
"extensions/memory-lancedb/config.ts": [
"native-plugins/memory-lancedb/config.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/memory-lancedb/config.ts",
"filename": "native-plugins/memory-lancedb/config.ts",
"hashed_secret": "ecb252044b5ea0f679ee78ec1a12904739e2904d",
"is_verified": false,
"line_number": 105
}
],
"extensions/memory-lancedb/index.test.ts": [
"native-plugins/memory-lancedb/index.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/memory-lancedb/index.test.ts",
"filename": "native-plugins/memory-lancedb/index.test.ts",
"hashed_secret": "ed65c049bb2f78ee4f703b2158ba9cc6ea31fb7e",
"is_verified": false,
"line_number": 71
}
],
"extensions/msteams/src/probe.test.ts": [
"native-plugins/msteams/src/probe.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/msteams/src/probe.test.ts",
"filename": "native-plugins/msteams/src/probe.test.ts",
"hashed_secret": "1a91d62f7ca67399625a4368a6ab5d4a3baa6073",
"is_verified": false,
"line_number": 35
}
],
"extensions/nextcloud-talk/src/accounts.ts": [
"native-plugins/nextcloud-talk/src/accounts.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/nextcloud-talk/src/accounts.ts",
"filename": "native-plugins/nextcloud-talk/src/accounts.ts",
"hashed_secret": "920f8f5815b381ea692e9e7c2f7119f2b1aa620a",
"is_verified": false,
"line_number": 28
},
{
"type": "Secret Keyword",
"filename": "extensions/nextcloud-talk/src/accounts.ts",
"filename": "native-plugins/nextcloud-talk/src/accounts.ts",
"hashed_secret": "71f8e7976e4cbc4561c9d62fb283e7f788202acb",
"is_verified": false,
"line_number": 147
}
],
"extensions/nextcloud-talk/src/channel.ts": [
"native-plugins/nextcloud-talk/src/channel.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/nextcloud-talk/src/channel.ts",
"filename": "native-plugins/nextcloud-talk/src/channel.ts",
"hashed_secret": "71f8e7976e4cbc4561c9d62fb283e7f788202acb",
"is_verified": false,
"line_number": 403
}
],
"extensions/nostr/README.md": [
"native-plugins/nostr/README.md": [
{
"type": "Secret Keyword",
"filename": "extensions/nostr/README.md",
"filename": "native-plugins/nostr/README.md",
"hashed_secret": "edeb23e25a619c434d22bb7f1c3ca4841166b4e8",
"is_verified": false,
"line_number": 46
}
],
"extensions/nostr/src/channel.test.ts": [
"native-plugins/nostr/src/channel.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/channel.test.ts",
"filename": "native-plugins/nostr/src/channel.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 48
},
{
"type": "Secret Keyword",
"filename": "extensions/nostr/src/channel.test.ts",
"filename": "native-plugins/nostr/src/channel.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 48
}
],
"extensions/nostr/src/nostr-bus.fuzz.test.ts": [
"native-plugins/nostr/src/nostr-bus.fuzz.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.fuzz.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.fuzz.test.ts",
"hashed_secret": "2b4489606a23fb31fcdc849fa7e577ba90f6d39a",
"is_verified": false,
"line_number": 193
},
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.fuzz.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.fuzz.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 194
},
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.fuzz.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.fuzz.test.ts",
"hashed_secret": "b84cb0c3925d34496e6c8b0e55b8c1664a438035",
"is_verified": false,
"line_number": 199
}
],
"extensions/nostr/src/nostr-bus.test.ts": [
"native-plugins/nostr/src/nostr-bus.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 11
},
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.test.ts",
"hashed_secret": "7258e28563f03fb4c5994e8402e6f610d1f0f110",
"is_verified": false,
"line_number": 33
},
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.test.ts",
"hashed_secret": "2b4489606a23fb31fcdc849fa7e577ba90f6d39a",
"is_verified": false,
"line_number": 101
},
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.test.ts",
"hashed_secret": "ef717286343f6da3f4e6f68c6de02a5148a801c4",
"is_verified": false,
"line_number": 106
},
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-bus.test.ts",
"filename": "native-plugins/nostr/src/nostr-bus.test.ts",
"hashed_secret": "98b35fe4c45011220f509ebb5546d3889b55a891",
"is_verified": false,
"line_number": 111
}
],
"extensions/nostr/src/nostr-profile.fuzz.test.ts": [
"native-plugins/nostr/src/nostr-profile.fuzz.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-profile.fuzz.test.ts",
"filename": "native-plugins/nostr/src/nostr-profile.fuzz.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 11
}
],
"extensions/nostr/src/nostr-profile.test.ts": [
"native-plugins/nostr/src/nostr-profile.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/nostr-profile.test.ts",
"filename": "native-plugins/nostr/src/nostr-profile.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 14
}
],
"extensions/nostr/src/types.test.ts": [
"native-plugins/nostr/src/types.test.ts": [
{
"type": "Hex High Entropy String",
"filename": "extensions/nostr/src/types.test.ts",
"filename": "native-plugins/nostr/src/types.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 4
},
{
"type": "Secret Keyword",
"filename": "extensions/nostr/src/types.test.ts",
"filename": "native-plugins/nostr/src/types.test.ts",
"hashed_secret": "ce4303f6b22257d9c9cf314ef1dee4707c6e1c13",
"is_verified": false,
"line_number": 4
},
{
"type": "Secret Keyword",
"filename": "extensions/nostr/src/types.test.ts",
"filename": "native-plugins/nostr/src/types.test.ts",
"hashed_secret": "3bee216ebc256d692260fc3adc765050508fef5e",
"is_verified": false,
"line_number": 141
}
],
"extensions/open-prose/skills/prose/SKILL.md": [
"native-plugins/open-prose/skills/prose/SKILL.md": [
{
"type": "Basic Auth Credentials",
"filename": "extensions/open-prose/skills/prose/SKILL.md",
"filename": "native-plugins/open-prose/skills/prose/SKILL.md",
"hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684",
"is_verified": false,
"line_number": 204
}
],
"extensions/open-prose/skills/prose/state/postgres.md": [
"native-plugins/open-prose/skills/prose/state/postgres.md": [
{
"type": "Secret Keyword",
"filename": "extensions/open-prose/skills/prose/state/postgres.md",
"filename": "native-plugins/open-prose/skills/prose/state/postgres.md",
"hashed_secret": "fa9beb99e4029ad5a6615399e7bbae21356086b3",
"is_verified": false,
"line_number": 77
},
{
"type": "Basic Auth Credentials",
"filename": "extensions/open-prose/skills/prose/state/postgres.md",
"filename": "native-plugins/open-prose/skills/prose/state/postgres.md",
"hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684",
"is_verified": false,
"line_number": 200
}
],
"extensions/twitch/src/onboarding.test.ts": [
"native-plugins/twitch/src/onboarding.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/twitch/src/onboarding.test.ts",
"filename": "native-plugins/twitch/src/onboarding.test.ts",
"hashed_secret": "f2b14f68eb995facb3a1c35287b778d5bd785511",
"is_verified": false,
"line_number": 239
},
{
"type": "Secret Keyword",
"filename": "extensions/twitch/src/onboarding.test.ts",
"filename": "native-plugins/twitch/src/onboarding.test.ts",
"hashed_secret": "c8d8f8140951794fa875ea2c2d010c4382f36566",
"is_verified": false,
"line_number": 249
}
],
"extensions/twitch/src/status.test.ts": [
"native-plugins/twitch/src/status.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/twitch/src/status.test.ts",
"filename": "native-plugins/twitch/src/status.test.ts",
"hashed_secret": "f2b14f68eb995facb3a1c35287b778d5bd785511",
"is_verified": false,
"line_number": 92
}
],
"extensions/voice-call/README.md": [
"native-plugins/voice-call/README.md": [
{
"type": "Secret Keyword",
"filename": "extensions/voice-call/README.md",
"filename": "native-plugins/voice-call/README.md",
"hashed_secret": "48004f85d79e636cfd408c3baddcb1f0bbdd611a",
"is_verified": false,
"line_number": 49
}
],
"extensions/voice-call/src/config.test.ts": [
"native-plugins/voice-call/src/config.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/voice-call/src/config.test.ts",
"filename": "native-plugins/voice-call/src/config.test.ts",
"hashed_secret": "62207a469ec2fdcfc7d66b04c2980ac1501acbf0",
"is_verified": false,
"line_number": 44
}
],
"extensions/voice-call/src/providers/telnyx.test.ts": [
"native-plugins/voice-call/src/providers/telnyx.test.ts": [
{
"type": "Secret Keyword",
"filename": "extensions/voice-call/src/providers/telnyx.test.ts",
"filename": "native-plugins/voice-call/src/providers/telnyx.test.ts",
"hashed_secret": "62207a469ec2fdcfc7d66b04c2980ac1501acbf0",
"is_verified": false,
"line_number": 30
}
],
"extensions/zalo/README.md": [
"native-plugins/zalo/README.md": [
{
"type": "Secret Keyword",
"filename": "extensions/zalo/README.md",
"filename": "native-plugins/zalo/README.md",
"hashed_secret": "f51aaee16a4a756d287f126b99c081b73cba7f15",
"is_verified": false,
"line_number": 41

View File

@ -1,7 +1,7 @@
# Repository Guidelines
- Repo: https://github.com/openclaw/openclaw
- In chat replies, file references must be repo-root relative only (example: `extensions/bluebubbles/src/channel.ts:80`); never absolute paths or `~/...`.
- In chat replies, file references must be repo-root relative only (example: `native-plugins/bluebubbles/src/channel.ts:80`); never absolute paths or `~/...`.
- Do not edit files covered by security-focused `CODEOWNERS` rules unless a listed owner explicitly asked for the change or is already reviewing it with you. Treat those paths as restricted surfaces, not drive-by cleanup.
## Project Structure & Module Organization
@ -9,15 +9,15 @@
- Source code: `src/` (CLI wiring in `src/cli`, commands in `src/commands`, web provider in `src/provider-web.ts`, infra in `src/infra`, media pipeline in `src/media`).
- Tests: colocated `*.test.ts`.
- Docs: `docs/` (images, queue, Pi config). Built output lives in `dist/`.
- Plugins/extensions: live under `extensions/*` (workspace packages). Keep plugin-only deps in the extension `package.json`; do not add them to the root `package.json` unless core uses them.
- Plugins/extensions: live under `native-plugins/*` (workspace packages). Keep plugin-only deps in the extension `package.json`; do not add them to the root `package.json` unless core uses them.
- Plugins: install runs `npm install --omit=dev` in plugin dir; runtime deps must live in `dependencies`. Avoid `workspace:*` in `dependencies` (npm install breaks); put `openclaw` in `devDependencies` or `peerDependencies` instead (runtime resolves `openclaw/plugin-sdk` via jiti alias).
- Import boundaries: extension production code should treat `openclaw/plugin-sdk/*` plus local `api.ts` / `runtime-api.ts` barrels as the public surface. Do not import core `src/**`, `src/plugin-sdk-internal/**`, or another extension's `src/**` directly.
- Installers served from `https://openclaw.ai/*`: live in the sibling repo `../openclaw.ai` (`public/install.sh`, `public/install-cli.sh`, `public/install.ps1`).
- Messaging channels: always consider **all** built-in + extension channels when refactoring shared logic (routing, allowlists, pairing, command gating, onboarding, docs).
- Core channel docs: `docs/channels/`
- Core channel code: `src/telegram`, `src/discord`, `src/slack`, `src/signal`, `src/imessage`, `src/web` (WhatsApp web), `src/channels`, `src/routing`
- Extensions (channel plugins): `extensions/*` (e.g. `extensions/msteams`, `extensions/matrix`, `extensions/zalo`, `extensions/zalouser`, `extensions/voice-call`)
- When adding channels/extensions/apps/docs, update `.github/labeler.yml` and create matching GitHub labels (use existing channel/extension label colors).
- Extensions (channel plugins): `native-plugins/*` (e.g. `native-plugins/msteams`, `native-plugins/matrix`, `native-plugins/zalo`, `native-plugins/zalouser`, `native-plugins/voice-call`)
- When adding channels/native-plugins/apps/docs, update `.github/labeler.yml` and create matching GitHub labels (use existing channel/extension label colors).
## Docs Linking (Mintlify)
@ -86,7 +86,7 @@
- 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.
- Extension SDK self-import guardrail: inside an extension package, do not import that same extension via `openclaw/plugin-sdk/<extension>` from production files. Route internal imports through a local barrel such as `./api.ts` or `./runtime-api.ts`, and keep the `plugin-sdk/<extension>` path as the external contract only.
- Extension package boundary guardrail: inside `extensions/<id>/**`, do not use relative imports/exports that resolve outside that same `extensions/<id>` package root. If shared code belongs in the plugin SDK, import `openclaw/plugin-sdk/<subpath>` instead of reaching into `src/plugin-sdk/**` or other repo paths via `../`.
- Extension package boundary guardrail: inside `native-plugins/<id>/**`, do not use relative imports/exports that resolve outside that same `native-plugins/<id>` package root. If shared code belongs in the plugin SDK, import `openclaw/plugin-sdk/<subpath>` instead of reaching into `src/plugin-sdk/**` or other repo paths via `../`.
- Extension API surface rule: `openclaw/plugin-sdk/<subpath>` 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.
- Never share class behavior via prototype mutation (`applyPrototypeMixins`, `Object.defineProperty` on `.prototype`, or exporting `Class.prototype` for merges). Use explicit inheritance/composition (`A extends B extends C`) or helper composition so TypeScript can typecheck.
- If this pattern is needed, stop and get explicit approval before shipping; default behavior is to split/refactor into an explicit class hierarchy and keep members strongly typed.

View File

@ -36,7 +36,7 @@ Docs: https://docs.openclaw.ai
- Models/OpenAI: add native forward-compat support for `gpt-5.4-mini` and `gpt-5.4-nano` in the OpenAI provider catalog, runtime resolution, and reasoning capability gates. Thanks @vincentkoc.
- Plugins/bundles: make enabled bundle MCP servers expose runnable tools in embedded Pi, and default relative bundle MCP launches to the bundle root so marketplace bundles like Context7 work through Pi instead of stopping at config import.
- Scope message SecretRef resolution and harden doctor/status paths. (#48728) Thanks @joshavant.
- Plugins/testing: add a public `openclaw/plugin-sdk/testing` surface for plugin-author test helpers, and move bundled-extension-only test bridges out of `extensions/` into private repo test helpers.
- Plugins/testing: add a public `openclaw/plugin-sdk/testing` surface for plugin-author test helpers, and move bundled-native-plugin-only test bridges out of `native-plugins/` into private repo test helpers.
- Plugins/Chutes: add a bundled Chutes provider with plugin-owned OAuth/API-key auth, dynamic model discovery, and default-on extension wiring. (#41416) Thanks @Veightor.
- Plugins/binding: add `onConversationBindingResolved(...)` so plugins can react immediately after bind approvals or denies without blocking channel interaction acknowledgements. (#48678) Thanks @huntharo.
- CLI/config: expand `config set` with SecretRef and provider builder modes, JSON/batch assignment support, and `--dry-run` validation with structured JSON output. (#49296) Thanks @joshavant.
@ -104,7 +104,7 @@ Docs: https://docs.openclaw.ai
- Control UI/logging: make browser-safe logger imports avoid eager temp-dir resolution so the bundled Control UI no longer crashes to a blank screen when logging reaches `tmp-openclaw-dir`. (#48469) Fixes #48062. Thanks @7inspire.
- Plugins/scoped ids: preserve scoped plugin ids during install and config keying, and keep bundled plugins ahead of discovered duplicate ids by default so `@scope/name` plugins no longer collide with unscoped installs. (#47413) Thanks @vincentkoc.
- Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) Thanks @gumadeiras.
- Gateway/watch mode: recreate bundled plugin runtime metadata after clean or stale `dist` states, so `pnpm gateway:watch` no longer fails on missing `dist/extensions/*/openclaw.plugin.json` manifests after a rebuild. Thanks @gumadeiras.
- Gateway/watch mode: recreate bundled plugin runtime metadata after clean or stale `dist` states, so `pnpm gateway:watch` no longer fails on missing `dist/native-plugins/*/openclaw.plugin.json` manifests after a rebuild. Thanks @gumadeiras.
- Control UI/chat sessions: show human-readable labels in the grouped session dropdown again, keep unique scoped fallbacks when metadata is missing, and disambiguate duplicate labels only when needed. (#45130) Thanks @luzhidong.
- Control UI: scope persisted session selection per gateway, prevent stale session bleed across tokenized gateway opens, and cap stored gateway session history. (#47453) Thanks @sallyom.
- Control UI/dashboard: preserve structured gateway shutdown reasons across restart disconnects so config-triggered restarts no longer fall back to `disconnected (1006): no reason`. (#46580) Fixes #46532. Thanks @vincentkoc.
@ -123,13 +123,13 @@ Docs: https://docs.openclaw.ai
- CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc.
- Slack/startup: harden `@slack/bolt` import interop across current bundled runtime shapes so Slack monitors no longer crash with `App is not a constructor` after plugin-sdk bundling changes. (#45953) Thanks @merc1305.
- Windows/gateway status: accept `schtasks` `Last Result` output as an alias for `Last Run Result`, so running scheduled-task installs no longer show `Runtime: unknown`. (#47844) Thanks @MoerAI.
- ACP/acpx: resolve the bundled plugin root from the actual plugin directory so plugin-local installs stay under `dist/extensions/acpx` instead of escaping to `dist/extensions` and failing runtime setup. (#47601) Thanks @ngutman.
- ACP/acpx: resolve the bundled plugin root from the actual plugin directory so plugin-local installs stay under `dist/native-plugins/acpx` instead of escaping to `dist/extensions` and failing runtime setup. (#47601) Thanks @ngutman.
- Gateway/WS handshake: raise the default pre-auth handshake timeout to 10 seconds and add `OPENCLAW_HANDSHAKE_TIMEOUT_MS` as a runtime override so busy local gateways stop dropping healthy CLI connections at 3 seconds. (#49262) Thanks @fuller-stack-dev.
- Gateway/websocket pairing bypass for disabled auth: skip device-pairing enforcement for Control UI operator sessions when `gateway.auth.mode=none`, so reverse-proxied dashboards no longer get stuck on `pairing required` despite auth being explicitly disabled. (#47148) Thanks @ademczuk.
- Control UI/model switching: preserve the selected provider prefix when switching models from the chat dropdown, so multi-provider setups no longer send `anthropic/gpt-5.2`-style mismatches when the user picked `openai/gpt-5.2`. (#47581) Thanks @chrishham.
- Control UI/storage: scope persisted settings keys by gateway base path, with migration from the legacy shared key, so multiple gateways under one domain stop overwriting each other's dashboard preferences. (#47932) Thanks @bobBot-claw.
- Agents/usage tracking: stop forcing `supportsUsageInStreaming: false` on non-native OpenAI-completions providers so compatible backends report token usage and cost again instead of showing all zeros. (#46500) Fixes #46142. Thanks @ademczuk.
- ACP/acpx: keep plugin-local backend installs under `extensions/acpx` in live repo checkouts so rebuilds no longer delete the runtime binary, and avoid package-lock churn during runtime repair.
- ACP/acpx: keep plugin-local backend installs under `native-plugins/acpx` in live repo checkouts so rebuilds no longer delete the runtime binary, and avoid package-lock churn during runtime repair.
- Plugins/subagents: preserve gateway-owned plugin subagent access across runtime, tool, and embedded-runner load paths so gateway plugin tools and context engines can still spawn and manage subagents after the loader cache split. (#46648) Thanks @jalehman.
- Control UI/overview: keep the language dropdown aligned with the persisted locale during dashboard startup so refreshing the page does not fall back to English before locale hydration completes. (#48019) Thanks @git-jxj.
- Agents/compaction: rerun transcript repair after `session.compact()` so orphaned `tool_result` blocks cannot survive compaction and break later Anthropic requests. (#16095) thanks @claw-sylphx.
@ -876,7 +876,7 @@ Docs: https://docs.openclaw.ai
- Gateway/loopback announce URLs: treat `http://` and `https://` aliases with the same loopback/private-network policy as websocket URLs so loopback cron announce delivery no longer fails secure URL validation. (#39064) Thanks @Narcooo.
- Models/default provider fallback: when the hardcoded default provider is removed from `models.providers`, resolve defaults from configured providers instead of reporting stale removed-provider defaults in status output. (#38947) Thanks @davidemanuelDEV.
- Agents/cache-trace stability: guard stable stringify against circular references in trace payloads so near-limit payloads no longer crash with `Maximum call stack size exceeded`; adds regression coverage. (#38935) Thanks @MumuTW.
- Extensions/diffs CI stability: add `headers` to the `localReq` test helper in `extensions/diffs/index.test.ts` so forwarding-hint checks no longer crash with `req.headers` undefined. (supersedes #39063) Thanks @Shennng.
- Extensions/diffs CI stability: add `headers` to the `localReq` test helper in `native-plugins/diffs/index.test.ts` so forwarding-hint checks no longer crash with `req.headers` undefined. (supersedes #39063) Thanks @Shennng.
- Agents/compaction thresholding: apply `agents.defaults.contextTokens` cap to the model passed into embedded run and `/compact` session creation so auto-compaction thresholds use the effective context window, not native model max context. (#39099) Thanks @MumuTW.
- Models/merge mode provider precedence: when `models.mode: "merge"` is active and config explicitly sets a provider `baseUrl`, keep config as source of truth instead of preserving stale runtime `models.json` `baseUrl` values; includes normalized provider-key coverage. (#39103) Thanks @BigUncle.
- UI/Control chat tool streaming: render tool events live in webchat without requiring refresh by enabling `tool-events` capability, fixing stream/event correlation, and resetting/reloading stream state around tool results and terminal events. (#39104) Thanks @jakepresent.
@ -1145,7 +1145,7 @@ Docs: https://docs.openclaw.ai
- Hooks/runtime stability: keep the internal hook handler registry on a `globalThis` singleton so hook registration/dispatch remains consistent when bundling emits duplicate module copies. (#32292) Thanks @Drickon.
- Hooks/after_tool_call: include embedded session context (`sessionKey`, `agentId`) and fire the hook exactly once per tool execution by removing duplicate adapter-path dispatch in embedded runs. (#32201) Thanks @jbeno, @scoootscooob, @vincentkoc.
- Hooks/tool-call correlation: include `runId` and `toolCallId` in plugin tool hook payloads/context and scope tool start/adjusted-param tracking by run to prevent cross-run collisions in `before_tool_call` and `after_tool_call`. (#32360) Thanks @vincentkoc.
- Plugins/install diagnostics: reject legacy plugin package shapes without `openclaw.extensions` and return an explicit upgrade hint with troubleshooting docs for repackaging. (#32055) Thanks @liuxiaopai-ai.
- Plugins/install diagnostics: reject legacy plugin package shapes without `openclaw.plugins` and return an explicit upgrade hint with troubleshooting docs for repackaging. (#32055) Thanks @liuxiaopai-ai.
- Hooks/plugin context parity: ensure `llm_input` hooks in embedded attempts receive the same `trigger` and `channelId`-aware `hookCtx` used by the other hook phases, preserving channel/trigger-scoped plugin behavior. (#28623) Thanks @davidrudduck and @vincentkoc.
- Plugins/hardlink install compatibility: allow bundled plugin manifests and entry files to load when installed via hardlink-based package managers (`pnpm`, `bun`) while keeping hardlink rejection enabled for non-bundled plugin sources. (#32119) Fixes #28175, #28404, #29455. Thanks @markfietje.
- Cron/session reaper reliability: move cron session reaper sweeps into `onTimer` `finally` and keep pruning active even when timer ticks fail early (for example cron store parse failures), preventing stale isolated run sessions from accumulating indefinitely. (#31996) Fixes #31946. Thanks @scoootscooob.
@ -2083,7 +2083,7 @@ Docs: https://docs.openclaw.ai
- Security/Agents: make owner-ID obfuscation use a dedicated HMAC secret from configuration (`ownerDisplaySecret`) and update hashing behavior so obfuscation is decoupled from gateway token handling for improved control. (#7343) Thanks @vincentkoc.
- Security/Infra: switch gateway lock and tool-call synthetic IDs from SHA-1 to SHA-256 with unchanged truncation length to strengthen hash basis while keeping deterministic behavior and lock key format. (#7343) Thanks @vincentkoc.
- Dependencies/Tooling: add non-blocking dead-code scans in CI via Knip/ts-prune/ts-unused-exports to surface unused dependencies and exports earlier. (#22468) Thanks @vincentkoc.
- Dependencies/Unused Dependencies: remove or scope unused root and extension deps (`@larksuiteoapi/node-sdk`, `signal-utils`, `ollama`, `lit`, `@lit/context`, `@lit-labs/signals`, `@microsoft/agents-hosting-express`, `@microsoft/agents-hosting-extensions-teams`, and plugin-local `openclaw` devDeps in `extensions/open-prose`, `extensions/lobster`, and `extensions/llm-task`). (#22471, #22495) Thanks @vincentkoc.
- Dependencies/Unused Dependencies: remove or scope unused root and extension deps (`@larksuiteoapi/node-sdk`, `signal-utils`, `ollama`, `lit`, `@lit/context`, `@lit-labs/signals`, `@microsoft/agents-hosting-express`, `@microsoft/agents-hosting-extensions-teams`, and plugin-local `openclaw` devDeps in `native-plugins/open-prose`, `native-plugins/lobster`, and `native-plugins/llm-task`). (#22471, #22495) Thanks @vincentkoc.
- Dependencies/A2UI: harden dependency resolution after root cleanup (resolve `lit`, `@lit/context`, `@lit-labs/signals`, and `signal-utils` from workspace/root) and simplify bundling fallback behavior, including `pnpm dlx rolldown` compatibility. (#22481, #22507) Thanks @vincentkoc.
### Fixes
@ -2263,7 +2263,7 @@ Docs: https://docs.openclaw.ai
- Security/Net: enforce strict dotted-decimal IPv4 literals in SSRF checks and fail closed on unsupported legacy forms (octal/hex/short/packed, for example `0177.0.0.1`, `127.1`, `2130706433`) before DNS lookup.
- Security/Discord: enforce trusted-sender guild permission checks for moderation actions (`timeout`, `kick`, `ban`) and ignore untrusted `senderUserId` params to prevent privilege escalation in tool-driven flows. Thanks @aether-ai-agent for reporting.
- Security/ACP+Exec: add `openclaw acp --token-file/--password-file` secret-file support (with inline secret flag warnings), redact ACP working-directory prefixes to `~` home-relative paths, constrain exec script preflight file inspection to the effective `workdir` boundary, and add security-audit warnings when `tools.exec.host="sandbox"` is configured while sandbox mode is off.
- Security/Plugins/Hooks: enforce runtime/package path containment with realpath checks so `openclaw.extensions`, `openclaw.hooks`, and hook handler modules cannot escape their trusted roots via traversal or symlinks.
- Security/Plugins/Hooks: enforce runtime/package path containment with realpath checks so `openclaw.plugins`, `openclaw.hooks`, and hook handler modules cannot escape their trusted roots via traversal or symlinks.
- Security/Discord: centralize trusted sender checks for moderation actions in message-action dispatch, share moderation command parsing across handlers, and clarify permission helpers with explicit any/all semantics.
- Security/ACP: harden ACP bridge session management with duplicate-session refresh, idle-session reaping, oldest-idle soft-cap eviction, and burst rate limiting on session creation to reduce local DoS risk without disrupting normal IDE usage.
- Security/ACP: bound ACP prompt text payloads to 2 MiB before gateway forwarding, account for join separator bytes during pre-concatenation size checks, and avoid stale active-run session state when oversized prompts are rejected. Thanks @aether-ai-agent for reporting.
@ -2886,7 +2886,7 @@ Docs: https://docs.openclaw.ai
- Feishu: probe status uses the resolved account context for multi-account credential checks. (#11233) Thanks @onevcat.
- Feishu: add streaming card replies via Card Kit API and preserve `renderMode=auto` fallback behavior for plain-text responses. (#10379) Thanks @xzq-xu.
- Feishu DocX: preserve top-level converted block order using `firstLevelBlockIds` when writing/appending documents. (#13994) Thanks @Cynosure159.
- Feishu plugin packaging: remove `workspace:*` `openclaw` dependency from `extensions/feishu` and sync lockfile for install compatibility. (#14423) Thanks @jackcooper2015.
- Feishu plugin packaging: remove `workspace:*` `openclaw` dependency from `native-plugins/feishu` and sync lockfile for install compatibility. (#14423) Thanks @jackcooper2015.
- CLI/Wizard: exit with code 1 when `configure`, `agents add`, or interactive `onboard` wizards are canceled, so `set -e` automation stops correctly. (#14156) Thanks @0xRaini.
- Media: strip `MEDIA:` lines with local paths instead of leaking as visible text. (#14399) Thanks @0xRaini.
- Config/Cron: exclude `maxTokens` from config redaction and honor `deleteAfterRun` on skipped cron jobs. (#13342) Thanks @niceysam.
@ -4246,7 +4246,7 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Auth: read Codex keychain credentials and make the lookup platform-aware.
- macOS/Release: avoid bundling dist artifacts in relay builds and generate appcasts from zip-only sources.
- Doctor: surface plugin diagnostics in the report.
- Plugins: treat `plugins.load.paths` directory entries as package roots when they contain `package.json` + `openclaw.extensions`; load plugin packages from config dirs; extract archives without system tar.
- Plugins: treat `plugins.load.paths` directory entries as package roots when they contain `package.json` + `openclaw.plugins`; load plugin packages from config dirs; extract archives without system tar.
- Config: expand `~` in `CLAWDBOT_CONFIG_PATH` and common path-like config fields (including `plugins.load.paths`); guard invalid `$include` paths. (#731) — thanks @pasogott.
- Agents: stop pre-creating session transcripts so first user messages persist in JSONL history.
- Agents: skip pre-compaction memory flush when the session workspace is read-only.

View File

@ -6,7 +6,7 @@
# Multi-stage build produces a minimal runtime image without build tools,
# source code, or Bun. Works with Docker, Buildx, and Podman.
# The ext-deps stage extracts only the package.json files we need from
# extensions/, so the main build layer is not invalidated by unrelated
# native-plugins/, so the main build layer is not invalidated by unrelated
# extension source changes.
#
# Two runtime variants:
@ -30,9 +30,9 @@ COPY extensions /tmp/extensions
# Copy package.json for opted-in extensions so pnpm resolves their deps.
RUN mkdir -p /out && \
for ext in $OPENCLAW_EXTENSIONS; do \
if [ -f "/tmp/extensions/$ext/package.json" ]; then \
if [ -f "/tmp/native-plugins/$ext/package.json" ]; then \
mkdir -p "/out/$ext" && \
cp "/tmp/extensions/$ext/package.json" "/out/$ext/package.json"; \
cp "/tmp/native-plugins/$ext/package.json" "/out/$ext/package.json"; \
fi; \
done
@ -61,7 +61,7 @@ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY ui/package.json ./ui/package.json
COPY patches ./patches
COPY --from=ext-deps /out/ ./extensions/
COPY --from=ext-deps /out/ ./native-plugins/
# Reduce OOM risk on low-memory hosts during dependency installation.
# Docker builds on small VMs may otherwise fail with "Killed" (exit 137).

View File

@ -57471,7 +57471,7 @@
"storage"
],
"label": "Plugin Install Path",
"help": "Resolved install directory (usually ~/.openclaw/extensions/<id>).",
"help": "Resolved install directory (usually ~/.openclaw/native-plugins/<id>).",
"hasChildren": false
},
{

View File

@ -4943,7 +4943,7 @@
{"recordType":"path","path":"plugins.installs","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Install Records","help":"CLI-managed install metadata (used by `openclaw plugins update` to locate install sources).","hasChildren":true}
{"recordType":"path","path":"plugins.installs.*","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.installs.*.installedAt","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Install Time","help":"ISO timestamp of last install/update.","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.installPath","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Plugin Install Path","help":"Resolved install directory (usually ~/.openclaw/extensions/<id>).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.installPath","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Plugin Install Path","help":"Resolved install directory (usually ~/.openclaw/native-plugins/<id>).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.integrity","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Resolved Integrity","help":"Resolved npm dist integrity hash for the fetched artifact (if reported by npm).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.marketplaceName","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Marketplace Name","help":"Marketplace display name recorded for marketplace-backed plugin installs (if available).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.marketplacePlugin","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Marketplace Plugin","help":"Plugin entry name inside the source marketplace, used for later updates.","hasChildren":false}

View File

@ -28,7 +28,7 @@ openclaw plugins install @openclaw/line
Local checkout (when running from a git repo):
```bash
openclaw plugins install ./extensions/line
openclaw plugins install ./native-plugins/line
```
## Setup

View File

@ -24,7 +24,7 @@ openclaw plugins install @openclaw/matrix
Install from a local checkout:
```bash
openclaw plugins install ./extensions/matrix
openclaw plugins install ./native-plugins/matrix
```
See [Plugins](/tools/plugin) for plugin behavior and install rules.

View File

@ -25,7 +25,7 @@ openclaw plugins install @openclaw/mattermost
Local checkout (when running from a git repo):
```bash
openclaw plugins install ./extensions/mattermost
openclaw plugins install ./native-plugins/mattermost
```
If you choose Mattermost during setup and a git checkout is detected,

View File

@ -30,7 +30,7 @@ openclaw plugins install @openclaw/msteams
Local checkout (when running from a git repo):
```bash
openclaw plugins install ./extensions/msteams
openclaw plugins install ./native-plugins/msteams
```
If you choose Teams during setup and a git checkout is detected,
@ -242,7 +242,7 @@ This is often easier than hand-editing JSON manifests.
1. **Install the Microsoft Teams plugin**
- From npm: `openclaw plugins install @openclaw/msteams`
- From a local checkout: `openclaw plugins install ./extensions/msteams`
- From a local checkout: `openclaw plugins install ./native-plugins/msteams`
2. **Bot registration**
- Create an Azure Bot (see above) and note:

View File

@ -22,7 +22,7 @@ openclaw plugins install @openclaw/nextcloud-talk
Local checkout (when running from a git repo):
```bash
openclaw plugins install ./extensions/nextcloud-talk
openclaw plugins install ./native-plugins/nextcloud-talk
```
If you choose Nextcloud Talk during setup and a git checkout is detected,

View File

@ -35,7 +35,7 @@ openclaw plugins install @openclaw/nostr
Use a local checkout (dev workflows):
```bash
openclaw plugins install --link <path-to-openclaw>/extensions/nostr
openclaw plugins install --link <path-to-openclaw>/native-plugins/nostr
```
Restart the Gateway after installing or enabling plugins.

View File

@ -19,7 +19,7 @@ Synology Chat is plugin-based and not part of the default core channel install.
Install from a local checkout:
```bash
openclaw plugins install ./extensions/synology-chat
openclaw plugins install ./native-plugins/synology-chat
```
Details: [Plugins](/tools/plugin)

View File

@ -27,7 +27,7 @@ openclaw plugins install @openclaw/tlon
Local checkout (when running from a git repo):
```bash
openclaw plugins install ./extensions/tlon
openclaw plugins install ./native-plugins/tlon
```
Details: [Plugins](/tools/plugin)

View File

@ -22,7 +22,7 @@ openclaw plugins install @openclaw/twitch
Local checkout (when running from a git repo):
```bash
openclaw plugins install ./extensions/twitch
openclaw plugins install ./native-plugins/twitch
```
Details: [Plugins](/tools/plugin)

View File

@ -20,7 +20,7 @@ Zalo ships as a plugin and is not bundled with the core install.
## Quick setup (beginner)
1. Install the Zalo plugin:
- From a source checkout: `openclaw plugins install ./extensions/zalo`
- From a source checkout: `openclaw plugins install ./native-plugins/zalo`
- From npm (if published): `openclaw plugins install @openclaw/zalo`
- Or pick **Zalo** in setup and confirm the install prompt
2. Set the token:

View File

@ -17,7 +17,7 @@ Status: experimental. This integration automates a **personal Zalo account** via
Zalo Personal ships as a plugin and is not bundled with the core install.
- Install via CLI: `openclaw plugins install @openclaw/zalouser`
- Or from a source checkout: `openclaw plugins install ./extensions/zalouser`
- Or from a source checkout: `openclaw plugins install ./native-plugins/zalouser`
- Details: [Plugins](/tools/plugin)
No external `zca`/`openzca` CLI binary is required.

View File

@ -102,7 +102,7 @@ For local paths and archives, OpenClaw auto-detects:
component layout)
- Cursor-compatible bundles (`.cursor-plugin/plugin.json`)
Compatible bundles install into the normal extensions root and participate in
Compatible bundles install into the normal plugins root and participate in
the same list/info/enable/disable flow. Today, bundle skills, Claude
command-skills, Claude `settings.json` defaults, Cursor command-skills, and compatible Codex hook
directories are supported; other detected bundle capabilities are shown in
@ -130,7 +130,7 @@ the plugin allowlist, and linked `plugins.load.paths` entries when applicable.
For active memory plugins, the memory slot resets to `memory-core`.
By default, uninstall also removes the plugin install directory under the active
state dir extensions root (`$OPENCLAW_STATE_DIR/extensions/<id>`). Use
state dir plugins root (`$OPENCLAW_STATE_DIR/plugins/<id>`). Use
`--keep-files` to keep files on disk.
`--keep-config` is supported as a deprecated alias for `--keep-files`.

View File

@ -1075,7 +1075,7 @@
{
"group": "Extensions",
"pages": [
"plugins/building-extensions",
"plugins/building-native-plugins",
"plugins/architecture",
"plugins/community",
"plugins/bundles",

View File

@ -2415,7 +2415,7 @@ See [Local Models](/gateway/local-models). TL;DR: run MiniMax M2.5 via LM Studio
}
```
- Loaded from `~/.openclaw/extensions`, `<workspace>/.openclaw/extensions`, plus `plugins.load.paths`.
- Loaded from `~/.openclaw/plugins`, `<workspace>/.openclaw/plugins`, plus `plugins.load.paths`.
- Discovery accepts native OpenClaw plugins plus compatible Codex bundles and Claude bundles, including manifestless Claude default-layout bundles.
- **Config changes require a gateway restart.**
- `allow`: optional allowlist (only listed plugins load). `deny` wins.

View File

@ -451,7 +451,7 @@ Plugins run **in-process** with the Gateway. Treat them as trusted code:
- Review plugin config before enabling.
- Restart the Gateway after plugin changes.
- If you install plugins from npm (`openclaw plugins install <npm-spec>`), treat it like running untrusted code:
- The install path is `~/.openclaw/extensions/<pluginId>/` (or `$OPENCLAW_STATE_DIR/extensions/<pluginId>/`).
- The install path is `~/.openclaw/plugins/<pluginId>/` (or `$OPENCLAW_STATE_DIR/plugins/<pluginId>/`).
- OpenClaw uses `npm pack` and then runs `npm install --omit=dev` in that directory (npm lifecycle scripts can execute code during install).
- Prefer pinned, exact versions (`@scope/pkg@1.2.3`), and inspect the unpacked code on disk before enabling.
@ -850,7 +850,7 @@ Assume anything under `~/.openclaw/` (or `$OPENCLAW_STATE_DIR/`) may contain sec
- `secrets.json` (optional): file-backed secret payload used by `file` SecretRef providers (`secrets.providers`).
- `agents/<agentId>/agent/auth.json`: legacy compatibility file. Static `api_key` entries are scrubbed when discovered.
- `agents/<agentId>/sessions/**`: session transcripts (`*.jsonl`) + routing metadata (`sessions.json`) that can contain private messages and tool output.
- `extensions/**`: installed plugins (plus their `node_modules/`).
- `native-plugins/**`: installed plugins (plus their `node_modules/`).
- `sandboxes/**`: tool sandbox workspaces; can accumulate copies of files you read/write inside the sandbox.
Hardening tips:

View File

@ -42,8 +42,8 @@ Think of the suites as “increasing realism” (and increasing flakiness/cost):
### Unit / integration (default)
- Command: `pnpm test`
- Config: `scripts/test-parallel.mjs` (runs `vitest.unit.config.ts`, `vitest.extensions.config.ts`, `vitest.gateway.config.ts`)
- Files: `src/**/*.test.ts`, `extensions/**/*.test.ts`
- Config: `scripts/test-parallel.mjs` (runs `vitest.unit.config.ts`, `vitest.native-plugins.config.ts`, `vitest.gateway.config.ts`)
- Files: `src/**/*.test.ts`, `native-plugins/**/*.test.ts`
- Scope:
- Pure unit tests
- In-process integration tests (gateway auth, routing, tooling, parsing, config)

View File

@ -42,12 +42,12 @@ go to [/gateway/troubleshooting#anthropic-429-extra-usage-required-for-long-cont
## Plugin install fails with missing openclaw extensions
If install fails with `package.json missing openclaw.extensions`, the plugin package
If install fails with `package.json missing openclaw.plugins`, the plugin package
is using an old shape that OpenClaw no longer accepts.
Fix in the plugin package:
1. Add `openclaw.extensions` to `package.json`.
1. Add `openclaw.plugins` to `package.json`.
2. Point entries at built runtime files (usually `./dist/index.js`).
3. Republish the plugin and run `openclaw plugins install <npm-spec>` again.
@ -58,7 +58,7 @@ Example:
"name": "@openclaw/my-plugin",
"version": "1.2.3",
"openclaw": {
"extensions": ["./dist/index.js"]
"plugins": ["./dist/index.js"]
}
}
```

View File

@ -197,7 +197,7 @@ If the old store reports room keys that were never backed up, OpenClaw warns ins
`Legacy Matrix encrypted state was detected, but the Matrix plugin helper is unavailable. Install or repair @openclaw/matrix so OpenClaw can inspect the old rust crypto store before upgrading.`
- Meaning: OpenClaw found old encrypted Matrix state, but it could not load the helper entrypoint from the Matrix plugin that normally inspects that store.
- What to do: reinstall or repair the Matrix plugin (`openclaw plugins install @openclaw/matrix`, or `openclaw plugins install ./extensions/matrix` for a repo checkout), then rerun `openclaw doctor --fix` or restart the gateway.
- What to do: reinstall or repair the Matrix plugin (`openclaw plugins install @openclaw/matrix`, or `openclaw plugins install ./native-plugins/matrix` for a repo checkout), then rerun `openclaw doctor --fix` or restart the gateway.
`Matrix plugin helper path is unsafe: ... Reinstall @openclaw/matrix and try again.`
@ -312,7 +312,7 @@ If you accept losing unrecoverable old encrypted history, you can instead reset
`Matrix is installed from a custom path that no longer exists: ...`
- Meaning: your plugin install record points at a local path that is gone.
- What to do: reinstall with `openclaw plugins install @openclaw/matrix`, or if you are running from a repo checkout, `openclaw plugins install ./extensions/matrix`.
- What to do: reinstall with `openclaw plugins install @openclaw/matrix`, or if you are running from a repo checkout, `openclaw plugins install ./native-plugins/matrix`.
## If encrypted history still does not come back

View File

@ -132,10 +132,10 @@ src/agents/
Channel-specific message action runtimes now live in the plugin-owned extension
directories instead of under `src/agents/tools`, for example:
- `extensions/discord/src/actions/runtime*.ts`
- `extensions/slack/src/action-runtime.ts`
- `extensions/telegram/src/action-runtime.ts`
- `extensions/whatsapp/src/action-runtime.ts`
- `native-plugins/discord/src/actions/runtime*.ts`
- `native-plugins/slack/src/action-runtime.ts`
- `native-plugins/telegram/src/action-runtime.ts`
- `native-plugins/whatsapp/src/action-runtime.ts`
## Core Integration Flow

View File

@ -948,14 +948,14 @@ authoring plugins:
channel helper barrels.
- Bundled extension internals remain private. External plugins should use only
`openclaw/plugin-sdk/*` subpaths. OpenClaw core/test code may use the repo
public entry points under `extensions/<id>/index.js`, `api.js`, `runtime-api.js`,
public entry points under `native-plugins/<id>/index.js`, `api.js`, `runtime-api.js`,
`setup-entry.js`, and narrowly scoped files such as `login-qr-api.js`. Never
import `extensions/<id>/src/*` from core or from another extension.
import `native-plugins/<id>/src/*` from core or from another extension.
- Repo entry point split:
`extensions/<id>/api.js` is the helper/types barrel,
`extensions/<id>/runtime-api.js` is the runtime-only barrel,
`extensions/<id>/index.js` is the bundled plugin entry,
and `extensions/<id>/setup-entry.js` is the setup plugin entry.
`native-plugins/<id>/api.js` is the helper/types barrel,
`native-plugins/<id>/runtime-api.js` is the runtime-only barrel,
`native-plugins/<id>/index.js` is the bundled plugin entry,
and `native-plugins/<id>/setup-entry.js` is the setup plugin entry.
- `openclaw/plugin-sdk/telegram` for Telegram channel plugin types and shared channel-facing helpers. Built-in Telegram implementation internals stay private to the bundled extension.
- `openclaw/plugin-sdk/discord` for Discord channel plugin types and shared channel-facing helpers. Built-in Discord implementation internals stay private to the bundled extension.
- `openclaw/plugin-sdk/slack` for Slack channel plugin types and shared channel-facing helpers. Built-in Slack implementation internals stay private to the bundled extension.
@ -1105,13 +1105,13 @@ path" instead of crashing or misreporting the account as not configured.
## Package packs
A plugin directory may include a `package.json` with `openclaw.extensions`:
A plugin directory may include a `package.json` with `openclaw.plugins`:
```json
{
"name": "my-pack",
"openclaw": {
"extensions": ["./src/safety.ts", "./src/tools.ts"],
"plugins": ["./src/safety.ts", "./src/tools.ts"],
"setupEntry": "./src/setup-entry.ts"
}
}
@ -1123,7 +1123,7 @@ becomes `name/<fileBase>`.
If your plugin imports npm deps, install them in that directory so
`node_modules` is available (`npm install` / `pnpm install`).
Security guardrail: every `openclaw.extensions` entry must stay inside the plugin
Security guardrail: every `openclaw.plugins` entry must stay inside the plugin
directory after symlink resolution. Entries that escape the package directory are
rejected.
@ -1160,7 +1160,7 @@ Example:
{
"name": "@scope/my-channel",
"openclaw": {
"extensions": ["./index.ts"],
"plugins": ["./index.ts"],
"setupEntry": "./setup-entry.ts",
"startup": {
"deferConfiguredChannelFullLoadUntilAfterListen": true
@ -1180,7 +1180,7 @@ Example:
{
"name": "@openclaw/nextcloud-talk",
"openclaw": {
"extensions": ["./index.ts"],
"plugins": ["./index.ts"],
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
@ -1193,7 +1193,7 @@ Example:
},
"install": {
"npmSpec": "@openclaw/nextcloud-talk",
"localPath": "extensions/nextcloud-talk",
"localPath": "native-plugins/nextcloud-talk",
"defaultChoice": "npm"
}
}

View File

@ -1,15 +1,15 @@
---
title: "Building Extensions"
summary: "Step-by-step guide for creating OpenClaw channel and provider extensions"
title: "Building Native Plugins"
summary: "Step-by-step guide for creating OpenClaw channel and provider native plugins"
read_when:
- You want to create a new OpenClaw plugin or extension
- You want to create a new OpenClaw native plugin
- You need to understand the plugin SDK import patterns
- You are adding a new channel or provider to OpenClaw
---
# Building Extensions
# Building Native Plugins
This guide walks through creating an OpenClaw extension from scratch. Extensions
This guide walks through creating an OpenClaw native plugin from scratch. Native plugins
can add channels, model providers, tools, or other capabilities.
## Prerequisites
@ -17,12 +17,12 @@ can add channels, model providers, tools, or other capabilities.
- OpenClaw repository cloned and dependencies installed (`pnpm install`)
- Familiarity with TypeScript (ESM)
## Extension structure
## Native plugin structure
Every extension lives under `extensions/<name>/` and follows this layout:
Every native plugin lives under `native-plugins/<name>/` and follows this layout:
```
extensions/my-channel/
native-plugins/my-channel/
├── package.json # npm metadata + openclaw config
├── index.ts # Entry point (defineChannelPluginEntry)
├── setup-entry.ts # Setup wizard (optional)
@ -36,7 +36,7 @@ extensions/my-channel/
## Step 1: Create the package
Create `extensions/my-channel/package.json`:
Create `native-plugins/my-channel/package.json`:
```json
{
@ -46,7 +46,7 @@ Create `extensions/my-channel/package.json`:
"type": "module",
"dependencies": {},
"openclaw": {
"extensions": ["./index.ts"],
"plugins": ["./index.ts"],
"setupEntry": "./setup-entry.ts",
"channel": {
"id": "my-channel",
@ -59,7 +59,7 @@ Create `extensions/my-channel/package.json`:
},
"install": {
"npmSpec": "@openclaw/my-channel",
"localPath": "extensions/my-channel"
"localPath": "native-plugins/my-channel"
}
}
}
@ -70,7 +70,7 @@ For provider plugins, use `providers` instead of `channel`.
## Step 2: Define the entry point
Create `extensions/my-channel/index.ts`:
Create `native-plugins/my-channel/index.ts`:
```typescript
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";

View File

@ -73,7 +73,7 @@ OpenClaw prefers native OpenClaw plugin/package layouts before bundle handling.
Practical effect:
- `openclaw.plugin.json` wins over bundle detection
- package installs with valid `package.json` + `openclaw.extensions` use the
- package installs with valid `package.json` + `openclaw.plugins` use the
native install path
- if a directory contains both native and bundle metadata, OpenClaw treats it
as native first

View File

@ -44,8 +44,8 @@ Restart the Gateway afterwards.
### Option B: install from a local folder (dev, no copying)
```bash
openclaw plugins install ./extensions/voice-call
cd ./extensions/voice-call && pnpm install
openclaw plugins install ./native-plugins/voice-call
cd ./native-plugins/voice-call && pnpm install
```
Restart the Gateway afterwards.

View File

@ -37,8 +37,8 @@ Restart the Gateway afterwards.
### Option B: install from a local folder (dev)
```bash
openclaw plugins install ./extensions/zalouser
cd ./extensions/zalouser && pnpm install
openclaw plugins install ./native-plugins/zalouser
cd ./native-plugins/zalouser && pnpm install
```
Restart the Gateway afterwards.

View File

@ -29,7 +29,7 @@ openclaw plugins enable open-prose
Restart the Gateway after enabling the plugin.
Dev/local checkout: `openclaw plugins install ./extensions/open-prose`
Dev/local checkout: `openclaw plugins install ./native-plugins/open-prose`
Related docs: [Plugins](/tools/plugin), [Plugin manifest](/plugins/manifest), [Skills](/tools/skills).

View File

@ -38,7 +38,7 @@ You will be prompted to select an endpoint:
- **Global** - International users (`api.minimax.io`)
- **CN** - Users in China (`api.minimaxi.com`)
See [MiniMax plugin README](https://github.com/openclaw/openclaw/tree/main/extensions/minimax) for details.
See [MiniMax plugin README](https://github.com/openclaw/openclaw/tree/main/native-plugins/minimax) for details.
### MiniMax M2.7 (API key)

View File

@ -164,7 +164,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
## Extensions + plugins
- [Plugins overview](/tools/plugin)
- [Building extensions](/plugins/building-extensions)
- [Building native plugins](/plugins/building-native-plugins)
- [Plugin manifest](/plugins/manifest)
- [Agent tools](/plugins/agent-tools)
- [Plugin bundles](/plugins/bundles)

View File

@ -517,7 +517,7 @@ openclaw config set plugins.entries.acpx.enabled true
Local workspace install during development:
```bash
openclaw plugins install ./extensions/acpx
openclaw plugins install ./native-plugins/acpx
```
Then verify backend health:
@ -530,7 +530,7 @@ Then verify backend health:
By default, the acpx plugin (published as `@openclaw/acpx`) uses the plugin-local pinned binary:
1. Command defaults to `extensions/acpx/node_modules/.bin/acpx`.
1. Command defaults to `native-plugins/acpx/node_modules/.bin/acpx`.
2. Expected version defaults to the extension pin.
3. Startup registers ACP backend immediately as not-ready.
4. A background ensure job verifies `acpx --version`.

View File

@ -78,7 +78,7 @@ For a new capability, expect to touch these areas:
- `src/plugins/runtime/index.ts`
- `src/plugin-sdk/<capability>.ts`
- `src/plugin-sdk/<capability>-runtime.ts`
- one or more `extensions/<vendor>/...`
- one or more `native-plugins/<vendor>/...`
- config/docs/tests
## Example: image generation

View File

@ -177,19 +177,19 @@ OpenClaw scans, in order:
2. Workspace extensions
- `<workspace>/.openclaw/extensions/*.ts`
- `<workspace>/.openclaw/extensions/*/index.ts`
- `<workspace>/.openclaw/plugins/*.ts`
- `<workspace>/.openclaw/plugins/*/index.ts`
3. Global extensions
- `~/.openclaw/extensions/*.ts`
- `~/.openclaw/extensions/*/index.ts`
- `~/.openclaw/plugins/*.ts`
- `~/.openclaw/plugins/*/index.ts`
4. Bundled extensions (shipped with OpenClaw; mixed default-on/default-off)
- `<openclaw>/dist/extensions/*` in packaged installs
- `<workspace>/dist-runtime/extensions/*` in local built checkouts
- `<workspace>/extensions/*` in source/Vitest workflows
- `<openclaw>/dist/native-plugins/*` in packaged installs
- `<workspace>/dist-runtime/native-plugins/*` in local built checkouts
- `<workspace>/native-plugins/*` in source/Vitest workflows
Many bundled provider plugins are enabled by default so model catalogs/runtime
hooks stay available without extra setup. Others still require explicit
@ -198,10 +198,10 @@ enablement via `plugins.entries.<id>.enabled` or
Bundled plugin runtime dependencies are owned by each plugin package. Packaged
builds stage opted-in bundled dependencies under
`dist/extensions/<id>/node_modules` instead of requiring mirrored copies in the
`dist/native-plugins/<id>/node_modules` instead of requiring mirrored copies in the
root package. Very large official plugins can ship as metadata-only bundled
entries and install their runtime package on demand. npm artifacts ship the
built `dist/extensions/*` tree; source `extensions/*` directories stay in source
built `dist/native-plugins/*` tree; source `native-plugins/*` directories stay in source
checkouts only.
Installed plugins are enabled by default, but can be disabled the same way.
@ -279,11 +279,11 @@ openclaw plugins doctor # issue-focused diagnostics
```bash
openclaw plugins list
openclaw plugins inspect <id>
openclaw plugins install <path> # copy a local file/dir into ~/.openclaw/extensions/<id>
openclaw plugins install ./extensions/voice-call # relative path ok
openclaw plugins install <path> # copy a local file/dir into ~/.openclaw/plugins/<id>
openclaw plugins install ./native-plugins/voice-call # relative path ok
openclaw plugins install ./plugin.tgz # install from a local tarball
openclaw plugins install ./plugin.zip # install from a local zip
openclaw plugins install -l ./extensions/voice-call # link (no copy) for dev
openclaw plugins install -l ./native-plugins/voice-call # link (no copy) for dev
openclaw plugins install @openclaw/voice-call # install from npm
openclaw plugins install @openclaw/voice-call --pin # store exact resolved name@version
openclaw plugins update <id-or-npm-spec>
@ -329,7 +329,7 @@ See [Plugin manifest](/plugins/manifest) for the manifest file format.
- [Plugin architecture and internals](/plugins/architecture) -- capability model,
ownership model, contracts, load pipeline, runtime helpers, and developer API
reference
- [Building extensions](/plugins/building-extensions)
- [Building native plugins](/plugins/building-native-plugins)
- [Plugin bundles](/plugins/bundles)
- [Plugin manifest](/plugins/manifest)
- [Plugin agent tools](/plugins/agent-tools)

View File

@ -4,8 +4,8 @@ const rootEntries = [
"src/entry.ts!",
"src/cli/daemon-cli.ts!",
"src/infra/warning-filter.ts!",
"extensions/telegram/src/audit.ts!",
"extensions/telegram/src/token.ts!",
"native-plugins/telegram/src/audit.ts!",
"native-plugins/telegram/src/token.ts!",
"src/line/accounts.ts!",
"src/line/send.ts!",
"src/line/template-messages.ts!",
@ -64,12 +64,12 @@ const config = {
"src/gateway/live-tool-probe-utils.ts",
"src/gateway/server.auth.shared.ts",
"src/shared/text/assistant-visible-text.ts",
"extensions/telegram/src/bot/reply-threading.ts",
"extensions/telegram/src/draft-chunking.ts",
"extensions/msteams/src/conversation-store-memory.ts",
"extensions/msteams/src/polls-store-memory.ts",
"extensions/voice-call/src/providers/index.ts",
"extensions/voice-call/src/providers/tts-openai.ts",
"native-plugins/telegram/src/bot/reply-threading.ts",
"native-plugins/telegram/src/draft-chunking.ts",
"native-plugins/msteams/src/conversation-store-memory.ts",
"native-plugins/msteams/src/polls-store-memory.ts",
"native-plugins/voice-call/src/providers/index.ts",
"native-plugins/voice-call/src/providers/tts-openai.ts",
],
workspaces: {
".": {
@ -89,7 +89,7 @@ const config = {
entry: ["index.js!", "scripts/postinstall.js!"],
project: ["index.js!", "scripts/**/*.js!"],
},
"extensions/*": {
"native-plugins/*": {
entry: ["index.ts!"],
project: ["index.ts!", "src/**/*.ts!"],
ignoreDependencies: ["openclaw"],

View File

@ -7,7 +7,7 @@
"acpx": "0.3.0"
},
"openclaw": {
"extensions": [
"plugins": [
"./index.ts"
]
}

View File

@ -94,7 +94,7 @@ Required behavior when ACP backend is unavailable:
1. Do not immediately ask the user to pick an alternate path.
2. First attempt automatic local repair:
- ensure plugin-local pinned acpx is installed in `extensions/acpx`
- ensure plugin-local pinned acpx is installed in `native-plugins/acpx`
- verify `${ACPX_CMD} --version`
3. After reinstall/repair, restart the gateway and explicitly offer to run that restart for the user.
4. Retry ACP thread spawn once after repair.
@ -112,20 +112,20 @@ Do not default to subagent runtime for these requests.
For this repo, direct `acpx` calls must follow the same pinned policy as the `@openclaw/acpx` extension.
1. Prefer plugin-local binary, not global PATH:
- `./extensions/acpx/node_modules/.bin/acpx`
- `./native-plugins/acpx/node_modules/.bin/acpx`
2. Resolve pinned version from extension dependency:
- `node -e "console.log(require('./extensions/acpx/package.json').dependencies.acpx)"`
- `node -e "console.log(require('./native-plugins/acpx/package.json').dependencies.acpx)"`
3. If binary is missing or version mismatched, install plugin-local pinned version:
- `cd extensions/acpx && npm install --omit=dev --no-save acpx@<pinnedVersion>`
- `cd native-plugins/acpx && npm install --omit=dev --no-save acpx@<pinnedVersion>`
4. Verify before use:
- `./extensions/acpx/node_modules/.bin/acpx --version`
- `./native-plugins/acpx/node_modules/.bin/acpx --version`
5. If install/repair changed ACPX artifacts, restart the gateway and offer to run the restart.
6. Do not run `npm install -g acpx` unless the user explicitly asks for global install.
Set and reuse:
```bash
ACPX_CMD="./extensions/acpx/node_modules/.bin/acpx"
ACPX_CMD="./native-plugins/acpx/node_modules/.bin/acpx"
```
## Direct acpx path ("telephone game")
@ -202,7 +202,7 @@ If `~/.acpx/config.json` overrides `agents`, those overrides replace defaults.
### Failure handling
- `acpx: command not found`:
- for thread-spawn ACP requests, install plugin-local pinned acpx in `extensions/acpx` immediately
- for thread-spawn ACP requests, install plugin-local pinned acpx in `native-plugins/acpx` immediately
- restart gateway after install and offer to run the restart automatically
- then retry once
- do not ask for install permission first unless policy explicitly requires it

View File

@ -39,7 +39,7 @@ describe("acpx plugin config parsing", () => {
}
});
it("prefers the workspace plugin root for dist/extensions/acpx bundles", () => {
it("prefers the workspace plugin root for dist/native-plugins/acpx bundles", () => {
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acpx-root-workspace-"));
const workspacePluginRoot = path.join(repoRoot, "extensions", "acpx");
const bundledPluginRoot = path.join(repoRoot, "dist", "extensions", "acpx");

View File

@ -5,7 +5,7 @@ import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
const tempDirs: string[] = [];
const proxyPath = path.resolve("extensions/acpx/src/runtime-internals/mcp-proxy.mjs");
const proxyPath = path.resolve("native-plugins/acpx/src/runtime-internals/mcp-proxy.mjs");
async function makeTempScript(name: string, content: string): Promise<string> {
const dir = await mkdtemp(path.join(os.tmpdir(), "openclaw-acpx-mcp-proxy-"));

View File

@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { registerSingleProviderPlugin } from "../../test/helpers/extensions/plugin-registration.js";
import { registerSingleProviderPlugin } from "../../test/helpers/native-plugins/plugin-registration.js";
import amazonBedrockPlugin from "./index.js";
describe("amazon-bedrock provider plugin", () => {

View File

@ -5,7 +5,7 @@
"description": "OpenClaw Amazon Bedrock provider plugin",
"type": "module",
"openclaw": {
"extensions": [
"plugins": [
"./index.ts"
]
}

View File

@ -5,7 +5,7 @@
"description": "OpenClaw Anthropic provider plugin",
"type": "module",
"openclaw": {
"extensions": [
"plugins": [
"./index.ts"
]
}

View File

@ -8,22 +8,22 @@ If youre looking for **how to use BlueBubbles as an agent/tool user**, see:
## Layout
- Extension package: `extensions/bluebubbles/` (entry: `index.ts`).
- Channel implementation: `extensions/bluebubbles/src/channel.ts`.
- Webhook handling: `extensions/bluebubbles/src/monitor.ts` (register per-account route via `registerPluginHttpRoute`).
- REST helpers: `extensions/bluebubbles/src/send.ts` + `extensions/bluebubbles/src/probe.ts`.
- Runtime bridge: `extensions/bluebubbles/src/runtime.ts` (set via `api.runtime`).
- Extension package: `native-plugins/bluebubbles/` (entry: `index.ts`).
- Channel implementation: `native-plugins/bluebubbles/src/channel.ts`.
- Webhook handling: `native-plugins/bluebubbles/src/monitor.ts` (register per-account route via `registerPluginHttpRoute`).
- REST helpers: `native-plugins/bluebubbles/src/send.ts` + `native-plugins/bluebubbles/src/probe.ts`.
- Runtime bridge: `native-plugins/bluebubbles/src/runtime.ts` (set via `api.runtime`).
- Catalog entry for setup selection: `src/channels/plugins/catalog.ts`.
## Internal helpers (use these, not raw API calls)
- `probeBlueBubbles` in `extensions/bluebubbles/src/probe.ts` for health checks.
- `sendMessageBlueBubbles` in `extensions/bluebubbles/src/send.ts` for text delivery.
- `resolveChatGuidForTarget` in `extensions/bluebubbles/src/send.ts` for chat lookup.
- `sendBlueBubblesReaction` in `extensions/bluebubbles/src/reactions.ts` for tapbacks.
- `sendBlueBubblesTyping` + `markBlueBubblesChatRead` in `extensions/bluebubbles/src/chat.ts`.
- `downloadBlueBubblesAttachment` in `extensions/bluebubbles/src/attachments.ts` for inbound media.
- `buildBlueBubblesApiUrl` + `blueBubblesFetchWithTimeout` in `extensions/bluebubbles/src/types.ts` for shared REST plumbing.
- `probeBlueBubbles` in `native-plugins/bluebubbles/src/probe.ts` for health checks.
- `sendMessageBlueBubbles` in `native-plugins/bluebubbles/src/send.ts` for text delivery.
- `resolveChatGuidForTarget` in `native-plugins/bluebubbles/src/send.ts` for chat lookup.
- `sendBlueBubblesReaction` in `native-plugins/bluebubbles/src/reactions.ts` for tapbacks.
- `sendBlueBubblesTyping` + `markBlueBubblesChatRead` in `native-plugins/bluebubbles/src/chat.ts`.
- `downloadBlueBubblesAttachment` in `native-plugins/bluebubbles/src/attachments.ts` for inbound media.
- `buildBlueBubblesApiUrl` + `blueBubblesFetchWithTimeout` in `native-plugins/bluebubbles/src/types.ts` for shared REST plumbing.
## Webhooks

View File

@ -7,7 +7,7 @@
"zod": "^4.3.6"
},
"openclaw": {
"extensions": [
"plugins": [
"./index.ts"
],
"setupEntry": "./setup-entry.ts",
@ -30,7 +30,7 @@
},
"install": {
"npmSpec": "@openclaw/bluebubbles",
"localPath": "extensions/bluebubbles",
"localPath": "native-plugins/bluebubbles",
"defaultChoice": "npm"
},
"release": {

Some files were not shown because too many files have changed in this diff Show More