Files
openclaw/tsdown.config.ts
T
Peter Steinberger fada067277 feat(browser): add zero-click Chrome extension bootstrap (#121586)
* feat(browser): add zero-click extension bootstrap

Pre-register deterministic path-derived extension IDs and install a strict native messaging host.

Keep the popup and options UI minimal while removing the obsolete copilot and page-share flows.

* fix(browser): satisfy native bootstrap CI guards

* test(browser): isolate native bootstrap Chrome roots

* test(browser): flush native bootstrap profile before status

* test(browser): seed Linux native bootstrap identity

* fix(browser): preserve native bootstrap upgrade safety

Allow immutable root-owned package inputs while keeping mutable state, manifests, and launchers user-owned. Preserve all retired copilot keys whenever active or unrecognized recovery custody remains.

* fix(browser): preserve pending copilot custody

Retired cleanup now removes copilot state only when the durable registry is exactly empty. Any session, archive, malformed value, future shape, or read failure preserves every retired key.

* fix(browser): guard native bootstrap upgrades

Fail closed while retired copilot custody remains and make discard durable across partial failures.

Require exact launcher-embedded origins and repair full launcher drift without accepting mismatched registrations.

* fix(browser): remove stale layout export

* chore(release): leave changelog to release flow
2026-08-10 19:31:13 -07:00

699 lines
25 KiB
TypeScript

// tsdown config defines package build entrypoints and output options.
import fs from "node:fs";
import path from "node:path";
import type { UserConfig } from "tsdown";
import {
collectBundledPluginBuildEntries,
NON_PACKAGED_BUNDLED_PLUGIN_DIRS,
} from "./scripts/lib/bundled-plugin-build-entries.mjs";
import {
buildPluginSdkEntrySources,
pluginSdkEntrypoints,
productionPluginSdkEntrypoints,
publicPluginSdkEntrypoints,
} from "./scripts/lib/plugin-sdk-entries.mts";
import {
createStateSchemaInlinePlugin,
STATE_SCHEMA_INLINE_PLUGIN_NAME,
} from "./scripts/lib/state-schema-inline-plugin.mts";
import {
TSDOWN_PACKAGE_CONFIG_GROUP,
TSDOWN_UNIFIED_CONFIG_GROUP,
TSDOWN_UNIFIED_DTS_CONFIG_GROUPS,
} from "./scripts/lib/tsdown-config-groups.mts";
import { tsdownPackageOutputRoot } from "./scripts/lib/tsdown-output-roots.mts";
type InputOptionsFactory = Extract<NonNullable<UserConfig["inputOptions"]>, Function>;
type InputOptionsArg = InputOptionsFactory extends (
options: infer Options,
format: infer _Format,
context: infer _Context,
) => infer _Return
? Options
: never;
type InputOptionsReturn = InputOptionsFactory extends (
options: infer _Options,
format: infer _Format,
context: infer _Context,
) => infer Return
? Return
: never;
type OnLogFunction = InputOptionsArg extends { onLog?: infer OnLog } ? NonNullable<OnLog> : never;
type ExternalOptionFunction = (
id: string,
parentId: string | undefined,
isResolved: boolean,
) => boolean | null | undefined;
const env = {
NODE_ENV: "production",
};
const OUTPUT_SOURCE_MAPS = process.env.OUTPUT_SOURCE_MAPS === "1";
const RUN_NODE_SKIP_DTS_BUILD = process.env.OPENCLAW_RUN_NODE_SKIP_DTS_BUILD === "1";
const TSDOWN_DECLARATIONS = !RUN_NODE_SKIP_DTS_BUILD;
export { createStateSchemaInlinePlugin, STATE_SCHEMA_INLINE_PLUGIN_NAME };
const SUPPRESSED_EVAL_WARNING_PATHS = [
"@protobufjs/inquire/index.js",
"bottleneck/lib/IORedisConnection.js",
"bottleneck/lib/RedisConnection.js",
] as const;
function normalizedLogHaystack(log: { message?: string; id?: string; importer?: string }): string {
return [log.message, log.id, log.importer].filter(Boolean).join("\n").replaceAll("\\", "/");
}
function matchesExternalOption(
option: unknown,
id: string,
parentId: string | undefined,
isResolved: boolean,
): boolean {
if (!option) {
return false;
}
if (typeof option === "function") {
return (option as ExternalOptionFunction)(id, parentId, isResolved) === true;
}
if (typeof option === "string") {
return option === id;
}
if (option instanceof RegExp) {
return option.test(id);
}
if (Array.isArray(option)) {
return option.some((entry) => matchesExternalOption(entry, id, parentId, isResolved));
}
return false;
}
function buildInputOptions(options: InputOptionsArg): InputOptionsReturn {
if (process.env.OPENCLAW_BUILD_VERBOSE === "1") {
return undefined;
}
const previousOnLog = typeof options.onLog === "function" ? options.onLog : undefined;
const previousExternal = (options as { external?: unknown }).external;
function isSuppressedLog(log: {
code?: string;
message?: string;
id?: string;
importer?: string;
plugin?: string;
}) {
if (log.code === "PLUGIN_TIMINGS") {
return true;
}
if (log.code === "UNRESOLVED_IMPORT") {
return normalizedLogHaystack(log).includes("extensions/");
}
if (
log.code === "PLUGIN_WARNING" &&
log.plugin === "rolldown-plugin-dts:fake-js" &&
typeof log.message === "string" &&
log.message.includes("uses CommonJS dts syntax")
) {
return true;
}
if (log.code !== "EVAL") {
return false;
}
const haystack = normalizedLogHaystack(log);
return SUPPRESSED_EVAL_WARNING_PATHS.some((pathLocal) => haystack.includes(pathLocal));
}
return {
...options,
external(id: string, parentId: string | undefined, isResolved: boolean) {
return (
shouldNeverBundleDependency(id) ||
matchesExternalOption(previousExternal, id, parentId, isResolved)
);
},
onLog(...args: Parameters<OnLogFunction>) {
const [level, log, defaultHandler] = args;
if (isSuppressedLog(log)) {
return;
}
if (typeof previousOnLog === "function") {
previousOnLog(level, log, defaultHandler);
return;
}
defaultHandler(level, log);
},
};
}
function nodeBuildConfig(
config: UserConfig,
declarations: UserConfig["dts"] = TSDOWN_DECLARATIONS,
): UserConfig {
return {
...config,
dts: declarations,
env,
outExtensions: () => ({ js: ".js", dts: ".d.ts" }),
fixedExtension: false,
sourcemap: OUTPUT_SOURCE_MAPS,
inputOptions: buildInputOptions,
};
}
function nodeWorkspacePackageBuildConfig(packageDir: string, config: UserConfig = {}): UserConfig {
return {
...config,
dts: TSDOWN_DECLARATIONS,
entry: config.entry ?? buildPackageDistEntriesFromExports(packageDir),
env,
name: config.name ?? TSDOWN_PACKAGE_CONFIG_GROUP,
outDir: config.outDir ?? tsdownPackageOutputRoot(packageDir),
sourcemap: OUTPUT_SOURCE_MAPS,
inputOptions: buildInputOptions,
};
}
const bundledPluginBuildEntries = collectBundledPluginBuildEntries();
const shouldBuildPrivateQaEntries = process.env.OPENCLAW_BUILD_PRIVATE_QA === "1";
const selectedPluginSdkEntrypoints = shouldBuildPrivateQaEntries
? pluginSdkEntrypoints
: productionPluginSdkEntrypoints;
function buildBundledHookEntries(): Record<string, string> {
const hooksRoot = path.join(process.cwd(), "src", "hooks", "bundled");
const entries: Record<string, string> = {};
if (!fs.existsSync(hooksRoot)) {
return entries;
}
for (const dirent of fs.readdirSync(hooksRoot, { withFileTypes: true })) {
if (!dirent.isDirectory()) {
continue;
}
const hookName = dirent.name;
const handlerPath = path.join(hooksRoot, hookName, "handler.ts");
if (!fs.existsSync(handlerPath)) {
continue;
}
entries[`bundled/${hookName}/handler`] = handlerPath;
}
return entries;
}
const bundledHookEntries = buildBundledHookEntries();
const bundledPluginRoot = (pluginId: string) => ["extensions", pluginId].join("/");
const bundledPluginFile = (pluginId: string, relativePath: string) =>
`${bundledPluginRoot(pluginId)}/${relativePath}`;
const explicitNeverBundleDependencies = [
"@anthropic-ai/vertex-sdk",
"@slack/bolt",
"@slack/web-api",
"@discordjs/voice",
"@lancedb/lancedb",
"@larksuiteoapi/node-sdk",
"@matrix-org/matrix-sdk-crypto-nodejs",
"@openclaw/ai",
"@vitest/expect",
"jimp",
"matrix-js-sdk",
"prism-media",
"qrcode-terminal",
"sharp",
"typescript",
"vitest",
].toSorted((left, right) => left.localeCompare(right));
function shouldNeverBundleDependency(id: string): boolean {
return explicitNeverBundleDependencies.some((dependency) => {
return id === dependency || id.startsWith(`${dependency}/`);
});
}
function shouldNeverBundleDeclarationDependency(id: string): boolean {
return shouldNeverBundleDependency(id) || id === "zod" || id.startsWith("zod/");
}
function shouldAlwaysBundleDependency(id: string): boolean {
return (
id === "openclaw/plugin-sdk/ssrf-runtime-internal" ||
id === "@openclaw/fs-safe" ||
id.startsWith("@openclaw/fs-safe/") ||
id === "@openclaw/normalization-core" ||
id.startsWith("@openclaw/normalization-core/") ||
id === "@openclaw/retry" ||
id === "@openclaw/media-core" ||
id.startsWith("@openclaw/media-core/") ||
[
"@openclaw/acp-core",
"@openclaw/session-url-contract",
"@openclaw/workboard-contract",
].includes(id) ||
id.startsWith("@openclaw/acp-core/") ||
id === "zod" ||
id.startsWith("zod/")
);
}
function listBundledPluginEntrySources(
entries: Array<{
id: string;
sourceEntries: string[];
}>,
): Record<string, string> {
return Object.fromEntries(
entries.flatMap(({ id, sourceEntries }) =>
sourceEntries.map((entry) => {
const normalizedEntry = entry.replace(/^\.\//u, "");
const entryKey = bundledPluginFile(id, normalizedEntry.replace(/\.[^.]+$/u, ""));
return [
entryKey,
normalizedEntry ? `extensions/${id}/${normalizedEntry}` : `extensions/${id}`,
];
}),
),
);
}
function buildCoreDistEntries(): Record<string, string> {
return {
index: "src/index.ts",
entry: "src/entry.ts",
"docker-healthcheck": "src/docker-healthcheck.ts",
// Ensure this module is bundled as an entry so legacy CLI shims can resolve its exports.
"cli/daemon-cli": "src/cli/daemon-cli.ts",
// Keep long-lived lazy runtime boundaries on stable filenames so rebuilt
// dist/ trees do not strand already-running gateways on stale hashed chunks.
"agents/auth-profiles.runtime": "src/agents/auth-profiles.runtime.ts",
"agents/model-catalog.runtime": "src/agents/model-catalog.runtime.ts",
"agents/models-config.runtime": "src/agents/models-config.runtime.ts",
"agents/code-mode.worker": "src/agents/code-mode.worker.ts",
"agents/compaction-planning.worker": "src/agents/compaction-planning.worker.ts",
"agents/model-provider-auth.worker": "src/agents/model-provider-auth.worker.ts",
"audit/audit-event-writer.worker": "src/audit/audit-event-writer.worker.ts",
"config/sessions/session-accessor.sqlite-archive.worker":
"src/config/sessions/session-accessor.sqlite-archive.worker.ts",
"config/sessions/session-transcript-reconcile.worker":
"src/config/sessions/session-transcript-reconcile.worker.ts",
"state/openclaw-database-verify.worker": "src/state/openclaw-database-verify.worker.ts",
"system-agent/setup-inference-detection.worker":
"src/system-agent/setup-inference-detection.worker.ts",
"acp/control-plane/manager": "src/acp/control-plane/manager.ts",
"cli/gateway-lifecycle.runtime": "src/cli/gateway-cli/lifecycle.runtime.ts",
"provider-dispatcher.runtime": "src/auto-reply/reply/provider-dispatcher.runtime.ts",
"server-close.runtime": "src/gateway/server-close.runtime.ts",
"gateway/plugin-channel-reload-targets": "src/gateway/plugin-channel-reload-targets.ts",
"gateway/worker-environments/runtime": "src/gateway/worker-environments/runtime.ts",
"worker/workspace-rsync-receiver": "src/worker/workspace-rsync-receiver.ts",
"plugins/hook-runner-global": "src/plugins/hook-runner-global.ts",
"plugins/memory-state": "src/plugins/memory-state.ts",
"plugins/synthetic-auth.runtime": "src/plugins/synthetic-auth.runtime.ts",
"subagent-registry.runtime": "src/agents/subagents/registry/subagent-registry.runtime.ts",
"task-registry-control.runtime": "src/tasks/task-registry-control.runtime.ts",
"link-understanding/apply.runtime": "src/link-understanding/apply.runtime.ts",
"media-understanding/apply.runtime": "src/media-understanding/apply.runtime.ts",
"commands/doctor/shared/plugin-registry-migration":
"src/commands/doctor/shared/plugin-registry-migration.ts",
"commands/status.summary.runtime": "src/status/summary.runtime.ts",
"infra/boundary-file-read": "src/infra/boundary-file-read.ts",
"plugins/provider-discovery.runtime": "src/plugins/provider-discovery.runtime.ts",
"plugins/provider-runtime.runtime": "src/plugins/provider-runtime.runtime.ts",
"web-fetch/runtime": "src/web-fetch/runtime.ts",
"plugins/public-surface-runtime": "src/plugins/public-surface-runtime.ts",
"plugins/loader": "src/plugins/loader.ts",
"plugins/sdk-alias": "src/plugins/sdk-alias.ts",
"facade-activation-check.runtime": "src/plugin-sdk/facade-activation-check.runtime.ts",
"infra/warning-filter": "src/infra/warning-filter.ts",
"telegram-ingress-worker.runtime": bundledPluginFile(
"telegram",
"src/telegram-ingress-worker.runtime.ts",
),
"telegram/audit": bundledPluginFile("telegram", "src/audit.ts"),
"telegram/token": bundledPluginFile("telegram", "src/token.ts"),
"plugins/build-smoke-entry": "src/plugins/build-smoke-entry.ts",
"plugins/runtime/index": "src/plugins/runtime/index.ts",
"llm-slug-generator": "src/hooks/llm-slug-generator.ts",
"mcp/plugin-tools-serve": "src/mcp/plugin-tools-serve.ts",
"mcp/openclaw-tools-serve": "src/mcp/openclaw-tools-serve.ts",
};
}
function buildDockerE2eHarnessEntries(): Record<string, string> {
return {
// Mounted Docker harnesses need stable package dist entries for asserted internal modules.
"agents/agent-bundle-mcp-materialize": "src/agents/agent-bundle-mcp-materialize.ts",
"agents/agent-bundle-mcp-runtime": "src/agents/agent-bundle-mcp-runtime.ts",
"agents/conversation-capability-profile": "src/agents/conversation-capability-profile.ts",
"agents/embedded-agent-runner/effective-tool-policy":
"src/agents/embedded-agent-runner/effective-tool-policy.ts",
"agents/embedded-agent-runner/tool-split": "src/agents/embedded-agent-runner/tool-split.ts",
"agents/embedded-agent-runner/run/runtime-context-prompt":
"src/agents/embedded-agent-runner/run/runtime-context-prompt.ts",
"auto-reply/reply/commands-system-agent": "src/auto-reply/reply/commands-system-agent.ts",
"cli/run-main": "src/cli/run-main.ts",
"config/config": "src/config/config.ts",
"infra/sqlite-audit-record-store": "src/infra/sqlite-audit-record-store.ts",
"system-agent/audit": "src/system-agent/audit.ts",
"system-agent/system-agent": "src/system-agent/system-agent.ts",
"system-agent/rescue-message": "src/system-agent/rescue-message.ts",
"system-agent/setup-inference": "src/system-agent/setup-inference.ts",
"gateway/protocol/index": "packages/gateway-protocol/src/index.ts",
"infra/errors": "src/infra/errors.ts",
"infra/ws": "src/infra/ws.ts",
"plugin-sdk/provider-onboard": "src/plugin-sdk/provider-onboard.ts",
"plugins/tools": "src/plugins/tools.ts",
"normalization-core/string-coerce": "packages/normalization-core/src/string-coerce.ts",
};
}
function buildAgentCoreDistEntries(): Record<string, string> {
return {
index: "packages/agent-core/src/index.ts",
agent: "packages/agent-core/src/agent.ts",
"agent-loop": "packages/agent-core/src/agent-loop.ts",
llm: "packages/agent-core/src/llm.ts",
"runtime-deps": "packages/agent-core/src/runtime-deps.ts",
types: "packages/agent-core/src/types.ts",
validation: "packages/agent-core/src/validation.ts",
"harness/messages": "packages/agent-core/src/harness/messages.ts",
"harness/env/kill-tree": "packages/agent-core/src/harness/env/kill-tree.ts",
"harness/compaction": "packages/agent-core/src/harness/compaction/compaction.ts",
"harness/branch-summarization":
"packages/agent-core/src/harness/compaction/branch-summarization.ts",
"harness/prompt-template-arguments":
"packages/agent-core/src/harness/prompt-template-arguments.ts",
"harness/utils/truncate": "packages/agent-core/src/harness/utils/truncate.ts",
};
}
function buildPackageDistEntriesFromExports(packageDir: string): Record<string, string> {
const packageJsonPath = path.join("packages", packageDir, "package.json");
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as {
exports?: Record<string, unknown>;
};
const entries: Record<string, string> = {};
for (const [exportKey, value] of Object.entries(packageJson.exports ?? {})) {
const entry =
exportKey === "." ? "index" : exportKey.startsWith("./") ? exportKey.slice(2) : "";
if (!entry || entry.includes("..")) {
continue;
}
const importPath =
typeof value === "object" && value !== null && !Array.isArray(value)
? (value as Record<string, unknown>).import
: value;
if (typeof importPath !== "string" || !importPath.startsWith("./dist/")) {
continue;
}
const sourcePath = importPath
.replace(/^\.\/dist\//u, `packages/${packageDir}/src/`)
.replace(/\.mjs$/u, ".ts");
entries[entry] = sourcePath;
}
return Object.fromEntries(Object.entries(entries).toSorted(([a], [b]) => a.localeCompare(b)));
}
function buildLlmCoreDistEntries(): Record<string, string> {
return {
index: "packages/llm-core/src/index.ts",
types: "packages/llm-core/src/types.ts",
"utils/diagnostics": "packages/llm-core/src/utils/diagnostics.ts",
"utils/event-stream": "packages/llm-core/src/utils/event-stream.ts",
validation: "packages/llm-core/src/validation.ts",
};
}
function shouldExternalizeAgentCoreDependency(id: string): boolean {
return (
id === "@openclaw/ai" ||
id.startsWith("@openclaw/ai/") ||
id === "@openclaw/llm-core" ||
id.startsWith("@openclaw/llm-core/") ||
id === "ignore" ||
id === "openclaw" ||
id.startsWith("openclaw/") ||
id === "typebox" ||
id.startsWith("typebox/") ||
id === "yaml" ||
id.startsWith("yaml/")
);
}
function shouldExternalizeGatewayProtocolDependency(id: string): boolean {
return id === "typebox" || id.startsWith("typebox/");
}
function shouldExternalizeGatewayClientDependency(id: string): boolean {
return ["ws", "@openclaw/gateway-protocol"].some(
(dependency) => id === dependency || id.startsWith(`${dependency}/`),
);
}
function shouldExternalizeNetPolicyDependency(id: string): boolean {
return id === "ipaddr.js" || id.startsWith("ipaddr.js/");
}
function shouldExternalizeLlmCoreDependency(id: string): boolean {
return id === "typebox" || id.startsWith("typebox/");
}
function shouldExternalizeMarkdownCoreDependency(id: string): boolean {
return (
id === "markdown-it" || id.startsWith("markdown-it/") || id === "yaml" || id.startsWith("yaml/")
);
}
function shouldExternalizeTerminalCoreDependency(id: string): boolean {
return id === "@clack/prompts" || id.startsWith("@clack/prompts/") || id === "chalk";
}
const coreDistEntries = buildCoreDistEntries();
const dockerE2eHarnessEntries = buildDockerE2eHarnessEntries();
const rootBundledPluginBuildEntries = bundledPluginBuildEntries.filter(
({ id }) => shouldBuildPrivateQaEntries || !NON_PACKAGED_BUNDLED_PLUGIN_DIRS.has(id),
);
function buildUnifiedDistEntries(): Record<string, string> {
return {
...coreDistEntries,
...dockerE2eHarnessEntries,
...Object.fromEntries(
Object.entries(buildPackageDistEntriesFromExports("normalization-core")).map(
([entry, source]) => [`normalization-core/${entry}`, source],
),
),
...Object.fromEntries(
Object.entries(buildPackageDistEntriesFromExports("retry")).map(([entry, source]) => [
`retry/${entry}`,
source,
]),
),
...Object.fromEntries(
Object.entries(buildPackageDistEntriesFromExports("media-core")).map(([entry, source]) => [
`media-core/${entry}`,
source,
]),
),
...Object.fromEntries(
Object.entries(buildPackageDistEntriesFromExports("acp-core")).map(([entry, source]) => [
`acp-core/${entry}`,
source,
]),
),
...Object.fromEntries(
Object.entries(buildPackageDistEntriesFromExports("terminal-core")).map(([entry, source]) => [
`terminal-core/${entry}`,
source,
]),
),
// Private bundled Codex helper for app-server user MCP config projection.
"plugin-sdk/codex-mcp-projection": "src/plugin-sdk/codex-mcp-projection.ts",
// Private bundled Codex helper for app-server transcript mirroring.
"plugin-sdk/codex-session-transcript-runtime":
"src/plugin-sdk/codex-session-transcript-runtime.ts",
...Object.fromEntries(
Object.entries(buildPluginSdkEntrySources(selectedPluginSdkEntrypoints)).map(
([entry, source]) => [`plugin-sdk/${entry}`, source],
),
),
...(shouldBuildPrivateQaEntries
? {
"plugin-sdk/qa-lab": "src/plugin-sdk/qa-lab.ts",
"plugin-sdk/qa-runtime": "src/plugin-sdk/qa-runtime.ts",
}
: {}),
"memory-core-local-embedding-worker":
"packages/memory-host-sdk/src/host/embeddings-worker-child.ts",
...listBundledPluginEntrySources(rootBundledPluginBuildEntries),
"extensions/browser/native-host-entry": "extensions/browser/native-host-entry.ts",
...bundledHookEntries,
};
}
type UnifiedEntry = [name: string, source: string];
function partitionUnifiedEntryGroups(
entryGroups: UnifiedEntry[][],
partitionCount: number,
): UnifiedEntry[][] {
const partitions = Array.from({ length: partitionCount }, () => [] as UnifiedEntry[]);
for (const entryGroup of entryGroups) {
let targetIndex = 0;
for (let index = 1; index < partitions.length; index += 1) {
const candidate = partitions[index];
const target = partitions[targetIndex];
if (candidate && target && candidate.length < target.length) {
targetIndex = index;
}
}
const target = partitions[targetIndex];
if (!target) {
throw new Error("unified declaration partition count must be positive");
}
target.push(...entryGroup);
}
return partitions;
}
function normalizeDeclarationEntrySource(source: string): string {
const relativeSource = path.isAbsolute(source) ? path.relative(process.cwd(), source) : source;
return relativeSource.replaceAll(path.sep, "/");
}
function buildUnifiedDeclarationPartitions(
entries: Record<string, string>,
): Array<{ name: string; sources: string[] }> {
const sortedEntries = Object.entries(entries).toSorted(([left], [right]) =>
left.localeCompare(right),
);
const baseEntries = sortedEntries.filter(
([name]) => !name.startsWith("plugin-sdk/") && !name.startsWith("extensions/"),
);
const pluginSdkEntries = sortedEntries.filter(([name]) => name.startsWith("plugin-sdk/"));
const extensionEntriesById = new Map<string, UnifiedEntry[]>();
for (const entry of sortedEntries) {
const [name] = entry;
if (!name.startsWith("extensions/")) {
continue;
}
const extensionId = name.split("/", 3)[1];
if (!extensionId) {
continue;
}
const extensionEntries = extensionEntriesById.get(extensionId) ?? [];
extensionEntries.push(entry);
extensionEntriesById.set(extensionId, extensionEntries);
}
const publicPluginSdkEntryNames = new Set(
publicPluginSdkEntrypoints.map((entry) => `plugin-sdk/${entry}`),
);
const pluginSdkPartitions = [
pluginSdkEntries.filter(([name]) => publicPluginSdkEntryNames.has(name)),
pluginSdkEntries.filter(([name]) => !publicPluginSdkEntryNames.has(name)),
];
const extensionPartitions = partitionUnifiedEntryGroups(
[...extensionEntriesById.entries()]
.toSorted(([left], [right]) => left.localeCompare(right))
.map(([, extensionEntries]) => extensionEntries),
5,
);
const partitions = [baseEntries, ...pluginSdkPartitions, ...extensionPartitions];
return TSDOWN_UNIFIED_DTS_CONFIG_GROUPS.map((name, index) => {
const partition = partitions[index];
if (!partition) {
throw new Error(`missing unified declaration partition for ${name}`);
}
return {
name,
sources: partition.map(([, source]) => normalizeDeclarationEntrySource(source)),
};
});
}
const unifiedDistEntries = buildUnifiedDistEntries();
const unifiedDeps = {
alwaysBundle: shouldAlwaysBundleDependency,
neverBundle: shouldNeverBundleDependency,
// Keep dependency-owned types canonical across independently emitted declaration graphs.
dts: { neverBundle: shouldNeverBundleDeclarationDependency },
};
const configs = [
nodeBuildConfig({
name: TSDOWN_PACKAGE_CONFIG_GROUP,
entry: buildAgentCoreDistEntries(),
outDir: tsdownPackageOutputRoot("agent-core"),
deps: {
neverBundle: shouldExternalizeAgentCoreDependency,
},
}),
nodeWorkspacePackageBuildConfig("gateway-protocol", {
deps: {
neverBundle: shouldExternalizeGatewayProtocolDependency,
},
}),
nodeWorkspacePackageBuildConfig("gateway-client", {
deps: {
neverBundle: shouldExternalizeGatewayClientDependency,
},
}),
nodeWorkspacePackageBuildConfig("net-policy", {
deps: {
neverBundle: shouldExternalizeNetPolicyDependency,
},
}),
nodeWorkspacePackageBuildConfig("media-generation-core"),
nodeWorkspacePackageBuildConfig("media-understanding-common"),
nodeWorkspacePackageBuildConfig("markdown-core", {
deps: {
neverBundle: shouldExternalizeMarkdownCoreDependency,
},
}),
nodeWorkspacePackageBuildConfig("normalization-core"),
nodeWorkspacePackageBuildConfig("retry"),
nodeWorkspacePackageBuildConfig("media-core"),
nodeWorkspacePackageBuildConfig("acp-core"),
nodeWorkspacePackageBuildConfig("terminal-core", {
deps: {
neverBundle: shouldExternalizeTerminalCoreDependency,
},
}),
nodeWorkspacePackageBuildConfig("llm-core", {
entry: buildLlmCoreDistEntries(),
deps: {
neverBundle: shouldExternalizeLlmCoreDependency,
},
}),
nodeWorkspacePackageBuildConfig("model-catalog-core"),
nodeBuildConfig(
{
name: TSDOWN_UNIFIED_CONFIG_GROUP,
// Build core entrypoints, plugin-sdk subpaths, bundled plugin entrypoints,
// and bundled hooks in one graph so runtime singletons are emitted once.
entry: unifiedDistEntries,
deps: unifiedDeps,
plugins: [createStateSchemaInlinePlugin()],
},
false,
),
...(TSDOWN_DECLARATIONS
? buildUnifiedDeclarationPartitions(unifiedDistEntries).map(({ name, sources }) =>
nodeBuildConfig(
{
name,
entry: unifiedDistEntries,
deps: unifiedDeps,
},
{ emitDtsOnly: true, entry: sources },
),
)
: []),
] satisfies UserConfig[];
export default configs;