mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-19 05:50:47 +00:00
refactor: remove remaining extension src imports
This commit is contained in:
@@ -1147,11 +1147,18 @@ authoring plugins:
|
||||
- Domain subpaths such as `openclaw/plugin-sdk/channel-config-helpers`,
|
||||
`openclaw/plugin-sdk/channel-config-schema`,
|
||||
`openclaw/plugin-sdk/channel-policy`,
|
||||
`openclaw/plugin-sdk/channel-runtime`,
|
||||
`openclaw/plugin-sdk/config-runtime`,
|
||||
`openclaw/plugin-sdk/agent-runtime`,
|
||||
`openclaw/plugin-sdk/lazy-runtime`,
|
||||
`openclaw/plugin-sdk/reply-history`,
|
||||
`openclaw/plugin-sdk/routing`,
|
||||
`openclaw/plugin-sdk/runtime-store`, and
|
||||
`openclaw/plugin-sdk/directory-runtime` for shared runtime/config helpers.
|
||||
- Narrow channel-core subpaths such as `openclaw/plugin-sdk/discord-core`,
|
||||
`openclaw/plugin-sdk/telegram-core`, `openclaw/plugin-sdk/whatsapp-core`,
|
||||
and `openclaw/plugin-sdk/line-core` for channel-specific primitives that
|
||||
should stay smaller than the full channel helper barrels.
|
||||
- `openclaw/plugin-sdk/compat` remains as a legacy migration surface for older
|
||||
external plugins. Bundled plugins should not use it, and non-test imports emit
|
||||
a one-time deprecation warning outside test environments.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
|
||||
import {
|
||||
type ActionGate,
|
||||
assertMediaNotDataUrl,
|
||||
type ActionGate,
|
||||
jsonResult,
|
||||
readNumberParam,
|
||||
readReactionParams,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { optionalStringEnum } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import { jsonResult, readNumberParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime";
|
||||
import { optionalStringEnum } from "openclaw/plugin-sdk/core";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime";
|
||||
import { runFirecrawlScrape } from "./firecrawl-client.js";
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
listLineAccountIds,
|
||||
normalizeAccountId,
|
||||
resolveLineAccount,
|
||||
type ChannelSetupAdapter,
|
||||
type LineConfig,
|
||||
type OpenClawConfig,
|
||||
} from "openclaw/plugin-sdk/line-core";
|
||||
import type { ChannelSetupAdapter, OpenClawConfig } from "openclaw/plugin-sdk/setup";
|
||||
|
||||
const channel = "line" as const;
|
||||
|
||||
@@ -158,4 +158,4 @@ export const lineSetupAdapter: ChannelSetupAdapter = {
|
||||
},
|
||||
};
|
||||
|
||||
export { listLineAccountIds } from "openclaw/plugin-sdk/line-core";
|
||||
export { listLineAccountIds };
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import crypto from "node:crypto";
|
||||
import { configureClient } from "@tloncorp/api";
|
||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime";
|
||||
import type {
|
||||
ChannelAccountSnapshot,
|
||||
ChannelOutboundAdapter,
|
||||
ChannelPlugin,
|
||||
OpenClawConfig,
|
||||
} from "../api.js";
|
||||
import { createLoggerBackedRuntime, createReplyPrefixOptions } from "../api.js";
|
||||
} from "openclaw/plugin-sdk/channel-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
|
||||
import { createLoggerBackedRuntime } from "openclaw/plugin-sdk/runtime";
|
||||
import { monitorTlonProvider } from "./monitor/index.js";
|
||||
import { tlonSetupWizard } from "./setup-surface.js";
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ChannelAccountSnapshot, ChannelPlugin } from "openclaw/plugin-sdk/channel-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import type { ChannelAccountSnapshot, ChannelPlugin, OpenClawConfig } from "../api.js";
|
||||
import { tlonChannelConfigSchema } from "./config-schema.js";
|
||||
import {
|
||||
applyTlonSetupConfig,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { z } from "zod";
|
||||
import { buildChannelConfigSchema } from "../api.js";
|
||||
|
||||
const ShipSchema = z.string().min(1);
|
||||
const ChannelNestSchema = z.string().min(1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/plugin-runtime";
|
||||
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
||||
import type { PluginRuntime } from "../api.js";
|
||||
|
||||
const { setRuntime: setTlonRuntime, getRuntime: getTlonRuntime } =
|
||||
createPluginRuntimeStore<PluginRuntime>("Tlon runtime not initialized");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { OpenClawConfig } from "../api.js";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
|
||||
export type TlonResolvedAccount = {
|
||||
accountId: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isBlockedHostnameOrIp } from "../../api.js";
|
||||
import { isBlockedHostnameOrIp } from "openclaw/plugin-sdk/infra-runtime";
|
||||
|
||||
export type UrbitBaseUrlValidation =
|
||||
| { ok: true; baseUrl: string; hostname: string }
|
||||
|
||||
@@ -487,7 +487,7 @@
|
||||
"build:plugin-sdk:dts": "tsc -p tsconfig.plugin-sdk.dts.json || true",
|
||||
"build:strict-smoke": "pnpm canvas:a2ui:bundle && node scripts/tsdown-build.mjs && node scripts/runtime-postbuild.mjs && pnpm build:plugin-sdk:dts",
|
||||
"canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
|
||||
"check": "pnpm check:host-env-policy:swift && pnpm format:check && pnpm tsgo && pnpm plugin-sdk:check-exports && pnpm lint && pnpm lint:tmp:no-random-messaging && pnpm lint:tmp:channel-agnostic-boundaries && pnpm lint:tmp:no-raw-channel-fetch && pnpm lint:agent:ingress-owner && pnpm lint:plugins:no-register-http-handler && pnpm lint:plugins:no-monolithic-plugin-sdk-entry-imports && pnpm lint:plugins:no-extension-test-core-imports && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope",
|
||||
"check": "pnpm check:host-env-policy:swift && pnpm format:check && pnpm tsgo && pnpm plugin-sdk:check-exports && pnpm lint && pnpm lint:tmp:no-random-messaging && pnpm lint:tmp:channel-agnostic-boundaries && pnpm lint:tmp:no-raw-channel-fetch && pnpm lint:agent:ingress-owner && pnpm lint:plugins:no-register-http-handler && pnpm lint:plugins:no-monolithic-plugin-sdk-entry-imports && pnpm lint:plugins:no-extension-src-imports && pnpm lint:plugins:no-extension-test-core-imports && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope",
|
||||
"check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-i18n-glossary && pnpm docs:check-links",
|
||||
"check:host-env-policy:swift": "node scripts/generate-host-env-security-policy-swift.mjs --check",
|
||||
"check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500",
|
||||
@@ -539,6 +539,7 @@
|
||||
"lint:docs": "pnpm dlx markdownlint-cli2",
|
||||
"lint:docs:fix": "pnpm dlx markdownlint-cli2 --fix",
|
||||
"lint:fix": "oxlint --type-aware --fix && pnpm format",
|
||||
"lint:plugins:no-extension-src-imports": "node --import tsx scripts/check-no-extension-src-imports.ts",
|
||||
"lint:plugins:no-extension-test-core-imports": "node --import tsx scripts/check-no-extension-test-core-imports.ts",
|
||||
"lint:plugins:no-monolithic-plugin-sdk-entry-imports": "node --import tsx scripts/check-no-monolithic-plugin-sdk-entry-imports.ts",
|
||||
"lint:plugins:no-register-http-handler": "node scripts/check-no-register-http-handler.mjs",
|
||||
|
||||
88
scripts/check-no-extension-src-imports.ts
Normal file
88
scripts/check-no-extension-src-imports.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const FORBIDDEN_REPO_SRC_IMPORT = /["'](?:\.\.\/)+(?:src\/)[^"']+["']/;
|
||||
|
||||
function isSourceFile(filePath: string): boolean {
|
||||
if (filePath.endsWith(".d.ts")) {
|
||||
return false;
|
||||
}
|
||||
return /\.(?:[cm]?ts|[cm]?js|tsx|jsx)$/u.test(filePath);
|
||||
}
|
||||
|
||||
function isProductionExtensionFile(filePath: string): boolean {
|
||||
return !(
|
||||
filePath.includes(".test.") ||
|
||||
filePath.includes(".spec.") ||
|
||||
filePath.includes(".fixture.") ||
|
||||
filePath.includes(".snap") ||
|
||||
filePath.includes("test-harness") ||
|
||||
filePath.includes("test-support") ||
|
||||
filePath.includes("/__tests__/") ||
|
||||
filePath.includes("/coverage/") ||
|
||||
filePath.includes("/dist/") ||
|
||||
filePath.includes("/node_modules/")
|
||||
);
|
||||
}
|
||||
|
||||
function collectExtensionSourceFiles(rootDir: string): string[] {
|
||||
const files: string[] = [];
|
||||
const stack = [rootDir];
|
||||
while (stack.length > 0) {
|
||||
const current = stack.pop();
|
||||
if (!current) {
|
||||
continue;
|
||||
}
|
||||
let entries: fs.Dirent[] = [];
|
||||
try {
|
||||
entries = fs.readdirSync(current, { withFileTypes: true });
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(current, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage") {
|
||||
continue;
|
||||
}
|
||||
stack.push(fullPath);
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && isSourceFile(fullPath) && isProductionExtensionFile(fullPath)) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const extensionsDir = path.join(process.cwd(), "extensions");
|
||||
const files = collectExtensionSourceFiles(extensionsDir);
|
||||
const offenders: string[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
const content = fs.readFileSync(file, "utf8");
|
||||
if (FORBIDDEN_REPO_SRC_IMPORT.test(content)) {
|
||||
offenders.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (offenders.length > 0) {
|
||||
console.error("Production extension files must not import the repo src/ tree directly.");
|
||||
for (const offender of offenders.toSorted()) {
|
||||
const relative = path.relative(process.cwd(), offender) || offender;
|
||||
console.error(`- ${relative}`);
|
||||
}
|
||||
console.error(
|
||||
"Publish a focused openclaw/plugin-sdk/<subpath> seam or use the extension's own public barrel instead.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`OK: production extension files avoid direct repo src/ imports (${files.length} checked).`,
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -3,6 +3,7 @@
|
||||
export * from "../agents/agent-scope.js";
|
||||
export * from "../agents/auth-profiles.js";
|
||||
export * from "../agents/current-time.js";
|
||||
export * from "../agents/date-time.js";
|
||||
export * from "../agents/defaults.js";
|
||||
export * from "../agents/identity-avatar.js";
|
||||
export * from "../agents/identity.js";
|
||||
@@ -13,6 +14,7 @@ export * from "../agents/model-selection.js";
|
||||
export * from "../agents/pi-embedded-block-chunker.js";
|
||||
export * from "../agents/pi-embedded-utils.js";
|
||||
export * from "../agents/provider-id.js";
|
||||
export * from "../agents/sandbox-paths.js";
|
||||
export * from "../agents/schema/typebox.js";
|
||||
export * from "../agents/sglang-defaults.js";
|
||||
export * from "../agents/tools/common.js";
|
||||
|
||||
@@ -42,6 +42,7 @@ export * from "../channels/plugins/outbound/interactive.js";
|
||||
export * from "../channels/plugins/status-issues/shared.js";
|
||||
export * from "../channels/plugins/whatsapp-heartbeat.js";
|
||||
export * from "../infra/outbound/send-deps.js";
|
||||
export * from "../polls.js";
|
||||
export * from "../utils/message-channel.js";
|
||||
export * from "./channel-lifecycle.js";
|
||||
export type {
|
||||
|
||||
@@ -72,6 +72,12 @@ export {
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export { getChatChannelMeta } from "../channels/registry.js";
|
||||
export { buildOauthProviderAuthResult } from "./provider-auth-result.js";
|
||||
export {
|
||||
channelTargetSchema,
|
||||
channelTargetsSchema,
|
||||
optionalStringEnum,
|
||||
stringEnum,
|
||||
} from "../agents/schema/typebox.js";
|
||||
export {
|
||||
DEFAULT_SECRET_FILE_MAX_BYTES,
|
||||
loadSecretFileSync,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export type { ChannelPlugin } from "./channel-plugin-common.js";
|
||||
export type { DiscordActionConfig } from "../config/types.js";
|
||||
export { buildChannelConfigSchema, getChatChannelMeta } from "./channel-plugin-common.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { DiscordActionConfig } from "../config/types.js";
|
||||
|
||||
@@ -11,6 +11,9 @@ export {
|
||||
export type { ChannelSetupAdapter, ChannelSetupDmPolicy, ChannelSetupWizard } from "./setup.js";
|
||||
export {
|
||||
listLineAccountIds,
|
||||
normalizeAccountId,
|
||||
resolveDefaultLineAccountId,
|
||||
resolveLineAccount,
|
||||
} from "../line/accounts.js";
|
||||
export type { ResolvedLineAccount } from "../line/types.js";
|
||||
export { LineConfigSchema } from "../line/config-schema.js";
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as discordSdk from "openclaw/plugin-sdk/discord";
|
||||
import * as imessageSdk from "openclaw/plugin-sdk/imessage";
|
||||
import * as lazyRuntimeSdk from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import * as lineSdk from "openclaw/plugin-sdk/line";
|
||||
import * as lineCoreSdk from "openclaw/plugin-sdk/line-core";
|
||||
import * as msteamsSdk from "openclaw/plugin-sdk/msteams";
|
||||
import * as nostrSdk from "openclaw/plugin-sdk/nostr";
|
||||
import * as ollamaSetupSdk from "openclaw/plugin-sdk/ollama-setup";
|
||||
@@ -67,6 +68,7 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expect(typeof coreSdk.definePluginEntry).toBe("function");
|
||||
expect(typeof coreSdk.defineChannelPluginEntry).toBe("function");
|
||||
expect(typeof coreSdk.defineSetupPluginEntry).toBe("function");
|
||||
expect(typeof coreSdk.optionalStringEnum).toBe("function");
|
||||
expect("runPassiveAccountLifecycle" in asExports(coreSdk)).toBe(false);
|
||||
expect("createLoggerBackedRuntime" in asExports(coreSdk)).toBe(false);
|
||||
expect("registerSandboxBackend" in asExports(coreSdk)).toBe(false);
|
||||
@@ -207,6 +209,12 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expect(typeof lineSdk.lineSetupAdapter).toBe("object");
|
||||
});
|
||||
|
||||
it("exports narrow LINE core helpers", () => {
|
||||
expect(typeof lineCoreSdk.resolveLineAccount).toBe("function");
|
||||
expect(typeof lineCoreSdk.listLineAccountIds).toBe("function");
|
||||
expect(typeof lineCoreSdk.LineConfigSchema).toBe("object");
|
||||
});
|
||||
|
||||
it("exports Microsoft Teams helpers", () => {
|
||||
expect(typeof msteamsSdk.resolveControlCommandGate).toBe("function");
|
||||
expect(typeof msteamsSdk.loadOutboundMediaFromUrl).toBe("function");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { TelegramActionConfig } from "../config/types.js";
|
||||
export type { ChannelPlugin } from "./channel-plugin-common.js";
|
||||
export type { TelegramActionConfig } from "../config/types.js";
|
||||
export { buildChannelConfigSchema, getChatChannelMeta } from "./channel-plugin-common.js";
|
||||
export { normalizeAccountId } from "../routing/session-key.js";
|
||||
export {
|
||||
|
||||
@@ -23,5 +23,5 @@ export {
|
||||
readStringParam,
|
||||
} from "../agents/tools/common.js";
|
||||
export { WhatsAppConfigSchema } from "../config/zod-schema.providers-whatsapp.js";
|
||||
export { normalizeE164 } from "../utils.js";
|
||||
export { resolveWhatsAppOutboundTarget } from "../whatsapp/resolve-outbound-target.js";
|
||||
export { normalizeE164 } from "../utils.js";
|
||||
|
||||
Reference in New Issue
Block a user