mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-20 06:20:55 +00:00
ACP: harden startup and move configured routing behind plugin seams (#48197)
* ACPX: keep plugin-local runtime installs out of dist * Gateway: harden ACP startup and service PATH * ACP: reinitialize error-state configured bindings * ACP: classify pre-turn runtime failures as session init failures * Plugins: move configured ACP routing behind channel seams * Telegram tests: align startup probe assertions after rebase * Discord: harden ACP configured binding recovery * ACP: recover Discord bindings after stale runtime exits * ACPX: replace dead sessions during ensure * Discord: harden ACP binding recovery * Discord: fix review follow-ups * ACP bindings: load channel snapshots across workspaces * ACP bindings: cache snapshot channel plugin resolution * Experiments: add ACP pluginification holy grail plan * Experiments: rename ACP pluginification plan doc * Experiments: drop old ACP pluginification doc path * ACP: move configured bindings behind plugin services * Experiments: update bindings capability architecture plan * Bindings: isolate configured binding routing and targets * Discord tests: fix runtime env helper path * Tests: fix channel binding CI regressions * Tests: normalize ACP workspace assertion on Windows * Bindings: isolate configured binding registry * Bindings: finish configured binding cleanup * Bindings: finish generic cleanup * Bindings: align runtime approval callbacks * ACP: delete residual bindings barrel * Bindings: restore legacy compatibility * Revert "Bindings: restore legacy compatibility" This reverts commit ac2ed68fa2426ecc874d68278c71c71ad363fcfe. * Tests: drop ACP route legacy helper names * Discord/ACP: fix binding regressions --------- Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,43 @@
|
||||
// Public pairing/session-binding helpers for plugins that manage conversation ownership.
|
||||
// Public binding helpers for both runtime plugin-owned bindings and
|
||||
// config-driven channel bindings.
|
||||
|
||||
export * from "../acp/persistent-bindings.route.js";
|
||||
export {
|
||||
createConversationBindingRecord,
|
||||
getConversationBindingCapabilities,
|
||||
listSessionBindingRecords,
|
||||
resolveConversationBindingRecord,
|
||||
touchConversationBindingRecord,
|
||||
unbindConversationBindingRecord,
|
||||
} from "../bindings/records.js";
|
||||
export {
|
||||
ensureConfiguredBindingRouteReady,
|
||||
resolveConfiguredBindingRoute,
|
||||
type ConfiguredBindingRouteResult,
|
||||
} from "../channels/plugins/binding-routing.js";
|
||||
export {
|
||||
primeConfiguredBindingRegistry,
|
||||
resolveConfiguredBinding,
|
||||
resolveConfiguredBindingRecord,
|
||||
resolveConfiguredBindingRecordBySessionKey,
|
||||
resolveConfiguredBindingRecordForConversation,
|
||||
} from "../channels/plugins/binding-registry.js";
|
||||
export {
|
||||
ensureConfiguredBindingTargetReady,
|
||||
ensureConfiguredBindingTargetSession,
|
||||
resetConfiguredBindingTargetInPlace,
|
||||
} from "../channels/plugins/binding-targets.js";
|
||||
export type {
|
||||
ConfiguredBindingConversation,
|
||||
ConfiguredBindingResolution,
|
||||
CompiledConfiguredBinding,
|
||||
StatefulBindingTargetDescriptor,
|
||||
} from "../channels/plugins/binding-types.js";
|
||||
export type {
|
||||
StatefulBindingTargetDriver,
|
||||
StatefulBindingTargetReadyResult,
|
||||
StatefulBindingTargetResetResult,
|
||||
StatefulBindingTargetSessionResult,
|
||||
} from "../channels/plugins/stateful-target-drivers.js";
|
||||
export {
|
||||
type BindingStatus,
|
||||
type BindingTargetKind,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js";
|
||||
export type {
|
||||
ChannelAccountSnapshot,
|
||||
ChannelGatewayContext,
|
||||
ChannelMessageActionAdapter,
|
||||
} from "../channels/plugins/types.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { DiscordAccountConfig, DiscordActionConfig } from "../config/types.js";
|
||||
export type { DiscordPluralKitConfig } from "../../extensions/discord/src/pluralkit.js";
|
||||
@@ -13,6 +17,11 @@ export type {
|
||||
ThreadBindingRecord,
|
||||
ThreadBindingTargetKind,
|
||||
} from "../../extensions/discord/src/monitor/thread-bindings.js";
|
||||
export type {
|
||||
ChannelConfiguredBindingProvider,
|
||||
ChannelConfiguredBindingConversationRef,
|
||||
ChannelConfiguredBindingMatch,
|
||||
} from "../channels/plugins/types.adapters.js";
|
||||
export type {
|
||||
ChannelMessageActionContext,
|
||||
ChannelPlugin,
|
||||
|
||||
@@ -31,6 +31,11 @@ export type {
|
||||
ChannelMeta,
|
||||
ChannelOutboundAdapter,
|
||||
} from "../channels/plugins/types.js";
|
||||
export type {
|
||||
ChannelConfiguredBindingProvider,
|
||||
ChannelConfiguredBindingConversationRef,
|
||||
ChannelConfiguredBindingMatch,
|
||||
} from "../channels/plugins/types.adapters.js";
|
||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export { createReplyPrefixContext } from "../channels/reply-prefix.js";
|
||||
export { createTypingCallbacks } from "../channels/typing.js";
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import fs from "node:fs/promises";
|
||||
import { createRequire } from "node:module";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildPluginSdkEntrySources,
|
||||
buildPluginSdkPackageExports,
|
||||
buildPluginSdkSpecifiers,
|
||||
pluginSdkEntrypoints,
|
||||
@@ -11,6 +15,9 @@ import {
|
||||
import * as sdk from "./index.js";
|
||||
|
||||
const pluginSdkSpecifiers = buildPluginSdkSpecifiers();
|
||||
const execFileAsync = promisify(execFile);
|
||||
const require = createRequire(import.meta.url);
|
||||
const tsdownModuleUrl = pathToFileURL(require.resolve("tsdown")).href;
|
||||
|
||||
describe("plugin-sdk exports", () => {
|
||||
it("does not expose runtime modules", () => {
|
||||
@@ -63,16 +70,33 @@ describe("plugin-sdk exports", () => {
|
||||
});
|
||||
|
||||
it("emits importable bundled subpath entries", { timeout: 240_000 }, async () => {
|
||||
const outDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-plugin-sdk-build-"));
|
||||
const fixtureDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-plugin-sdk-consumer-"));
|
||||
const repoDistDir = path.join(process.cwd(), "dist");
|
||||
|
||||
try {
|
||||
await expect(fs.access(path.join(repoDistDir, "plugin-sdk"))).resolves.toBeUndefined();
|
||||
const buildScriptPath = path.join(fixtureDir, "build-plugin-sdk.mjs");
|
||||
await fs.writeFile(
|
||||
buildScriptPath,
|
||||
`import { build } from ${JSON.stringify(tsdownModuleUrl)};
|
||||
await build(${JSON.stringify({
|
||||
clean: true,
|
||||
config: false,
|
||||
dts: false,
|
||||
entry: buildPluginSdkEntrySources(),
|
||||
env: { NODE_ENV: "production" },
|
||||
fixedExtension: false,
|
||||
logLevel: "error",
|
||||
outDir,
|
||||
platform: "node",
|
||||
})});
|
||||
`,
|
||||
);
|
||||
await execFileAsync(process.execPath, [buildScriptPath], {
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
for (const entry of pluginSdkEntrypoints) {
|
||||
const module = await import(
|
||||
pathToFileURL(path.join(repoDistDir, "plugin-sdk", `${entry}.js`)).href
|
||||
);
|
||||
const module = await import(pathToFileURL(path.join(outDir, `${entry}.js`)).href);
|
||||
expect(module).toBeTypeOf("object");
|
||||
}
|
||||
|
||||
@@ -80,8 +104,8 @@ describe("plugin-sdk exports", () => {
|
||||
const consumerDir = path.join(fixtureDir, "consumer");
|
||||
const consumerEntry = path.join(consumerDir, "import-plugin-sdk.mjs");
|
||||
|
||||
await fs.mkdir(packageDir, { recursive: true });
|
||||
await fs.symlink(repoDistDir, path.join(packageDir, "dist"), "dir");
|
||||
await fs.mkdir(path.join(packageDir, "dist"), { recursive: true });
|
||||
await fs.symlink(outDir, path.join(packageDir, "dist", "plugin-sdk"), "dir");
|
||||
await fs.writeFile(
|
||||
path.join(packageDir, "package.json"),
|
||||
JSON.stringify(
|
||||
@@ -114,6 +138,7 @@ describe("plugin-sdk exports", () => {
|
||||
Object.fromEntries(pluginSdkSpecifiers.map((specifier: string) => [specifier, "object"])),
|
||||
);
|
||||
} finally {
|
||||
await fs.rm(outDir, { recursive: true, force: true });
|
||||
await fs.rm(fixtureDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,8 +14,25 @@ export type {
|
||||
ChannelMessageActionName,
|
||||
ChannelStatusIssue,
|
||||
} from "../channels/plugins/types.js";
|
||||
export type {
|
||||
ChannelConfiguredBindingConversationRef,
|
||||
ChannelConfiguredBindingMatch,
|
||||
ChannelConfiguredBindingProvider,
|
||||
} from "../channels/plugins/types.adapters.js";
|
||||
export type { ChannelConfigSchema, ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { ChannelSetupAdapter, ChannelSetupInput } from "../channels/plugins/types.js";
|
||||
export type {
|
||||
ConfiguredBindingConversation,
|
||||
ConfiguredBindingResolution,
|
||||
CompiledConfiguredBinding,
|
||||
StatefulBindingTargetDescriptor,
|
||||
} from "../channels/plugins/binding-types.js";
|
||||
export type {
|
||||
StatefulBindingTargetDriver,
|
||||
StatefulBindingTargetReadyResult,
|
||||
StatefulBindingTargetResetResult,
|
||||
StatefulBindingTargetSessionResult,
|
||||
} from "../channels/plugins/stateful-target-drivers.js";
|
||||
export type {
|
||||
ChannelSetupWizard,
|
||||
ChannelSetupWizardAllowFromEntry,
|
||||
|
||||
@@ -12,6 +12,11 @@ export type {
|
||||
TelegramActionConfig,
|
||||
TelegramNetworkConfig,
|
||||
} from "../config/types.js";
|
||||
export type {
|
||||
ChannelConfiguredBindingProvider,
|
||||
ChannelConfiguredBindingConversationRef,
|
||||
ChannelConfiguredBindingMatch,
|
||||
} from "../channels/plugins/types.adapters.js";
|
||||
export type { InspectedTelegramAccount } from "../../extensions/telegram/src/account-inspect.js";
|
||||
export type { ResolvedTelegramAccount } from "../../extensions/telegram/src/accounts.js";
|
||||
export type { TelegramProbe } from "../../extensions/telegram/src/probe.js";
|
||||
@@ -26,7 +31,6 @@ export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.j
|
||||
export { parseTelegramTopicConversation } from "../acp/conversation-id.js";
|
||||
export { formatCliCommand } from "../cli/command-format.js";
|
||||
export { formatDocsLink } from "../terminal/links.js";
|
||||
|
||||
export {
|
||||
PAIRING_APPROVED_MESSAGE,
|
||||
applyAccountNameToChannelSection,
|
||||
|
||||
Reference in New Issue
Block a user