fix: unblock cli startup metadata

This commit is contained in:
Peter Steinberger
2026-04-04 02:35:23 +01:00
parent 143d377c5a
commit 1e6e685347
36 changed files with 674 additions and 79 deletions

View File

@@ -0,0 +1,16 @@
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "browser",
name: "Browser",
description: "Default browser tool plugin",
register(api) {
api.registerCli(
async ({ program }) => {
const { registerBrowserCli } = await import("./runtime-api.js");
registerBrowserCli(program);
},
{ commands: ["browser"] },
);
},
});

View File

@@ -0,0 +1,10 @@
export { normalizeCompatibilityConfig, legacyConfigRules } from "./src/doctor-contract.js";
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-config-contract.js";
export {
unsupportedSecretRefSurfacePatterns,
collectUnsupportedSecretRefConfigCandidates,
} from "./src/security-contract.js";
export { deriveLegacySessionChatType } from "./src/session-contract.js";

View File

@@ -0,0 +1,5 @@
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";
export { messageActionTargetAliases } from "./src/message-action-contract.js";

View File

@@ -0,0 +1,4 @@
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";

View File

@@ -1,4 +1,4 @@
import { coerceSecretRef } from "openclaw/plugin-sdk/config-runtime";
import { coerceSecretRef } from "openclaw/plugin-sdk/provider-auth";
import {
getChannelSurface,
hasOwnProperty,

View File

@@ -0,0 +1,103 @@
import path from "node:path";
import type { OpenClawConfig } from "./runtime-api.js";
import { resolveIMessageAccount } from "./src/accounts.js";
const DEFAULT_IMESSAGE_ATTACHMENT_ROOTS = ["/Users/*/Library/Messages/Attachments"] as const;
const WILDCARD_SEGMENT = "*";
const WINDOWS_DRIVE_ABS_RE = /^[A-Za-z]:\//;
const WINDOWS_DRIVE_ROOT_RE = /^[A-Za-z]:$/;
function normalizePosixAbsolutePath(value: string): string | undefined {
const trimmed = value.trim();
if (!trimmed || trimmed.includes("\0")) {
return undefined;
}
const normalized = path.posix.normalize(trimmed.replaceAll("\\", "/"));
const isAbsolute = normalized.startsWith("/") || WINDOWS_DRIVE_ABS_RE.test(normalized);
if (!isAbsolute || normalized === "/") {
return undefined;
}
const withoutTrailingSlash = normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
if (WINDOWS_DRIVE_ROOT_RE.test(withoutTrailingSlash)) {
return undefined;
}
return withoutTrailingSlash;
}
function splitPathSegments(value: string): string[] {
return value.split("/").filter(Boolean);
}
function isValidInboundPathRootPattern(value: string): boolean {
const normalized = normalizePosixAbsolutePath(value);
if (!normalized) {
return false;
}
const segments = splitPathSegments(normalized);
if (segments.length === 0) {
return false;
}
return segments.every((segment) => segment === WILDCARD_SEGMENT || !segment.includes("*"));
}
function normalizeInboundPathRoots(roots?: readonly string[]): string[] {
const normalized: string[] = [];
const seen = new Set<string>();
for (const root of roots ?? []) {
if (typeof root !== "string") {
continue;
}
if (!isValidInboundPathRootPattern(root)) {
continue;
}
const candidate = normalizePosixAbsolutePath(root);
if (!candidate || seen.has(candidate)) {
continue;
}
seen.add(candidate);
normalized.push(candidate);
}
return normalized;
}
function mergeInboundPathRoots(...rootsLists: Array<readonly string[] | undefined>): string[] {
const merged: string[] = [];
const seen = new Set<string>();
for (const roots of rootsLists) {
const normalized = normalizeInboundPathRoots(roots);
for (const root of normalized) {
if (seen.has(root)) {
continue;
}
seen.add(root);
merged.push(root);
}
}
return merged;
}
export function resolveInboundAttachmentRoots(params: {
cfg: OpenClawConfig;
accountId?: string | null;
}): string[] {
const account = resolveIMessageAccount(params);
return mergeInboundPathRoots(
account.config.attachmentRoots,
params.cfg.channels?.imessage?.attachmentRoots,
DEFAULT_IMESSAGE_ATTACHMENT_ROOTS,
);
}
export function resolveRemoteInboundAttachmentRoots(params: {
cfg: OpenClawConfig;
accountId?: string | null;
}): string[] {
const account = resolveIMessageAccount(params);
return mergeInboundPathRoots(
account.config.remoteAttachmentRoots,
params.cfg.channels?.imessage?.remoteAttachmentRoots,
account.config.attachmentRoots,
params.cfg.channels?.imessage?.attachmentRoots,
DEFAULT_IMESSAGE_ATTACHMENT_ROOTS,
);
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,9 @@
import { definePluginEntry } from "openclaw/plugin-sdk/core";
import { registerMatrixCliMetadata } from "./src/cli-metadata.js";
export default definePluginEntry({
id: "matrix",
name: "Matrix",
description: "Matrix channel plugin (matrix-js-sdk)",
register: registerMatrixCliMetadata,
});

View File

@@ -0,0 +1,9 @@
export {
namedAccountPromotionKeys,
resolveSingleAccountPromotionTarget,
singleAccountKeysToMove,
} from "./src/setup-contract.js";
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";

View File

@@ -1,5 +1,6 @@
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
import { matrixPlugin } from "./src/channel.js";
import { registerMatrixCliMetadata } from "./src/cli-metadata.js";
import { setMatrixRuntime } from "./src/runtime.js";
export { matrixPlugin } from "./src/channel.js";
@@ -11,23 +12,7 @@ export default defineChannelPluginEntry({
description: "Matrix channel plugin (matrix-js-sdk)",
plugin: matrixPlugin,
setRuntime: setMatrixRuntime,
registerCliMetadata(api) {
api.registerCli(
async ({ program }) => {
const { registerMatrixCli } = await import("./src/cli.js");
registerMatrixCli({ program });
},
{
descriptors: [
{
name: "matrix",
description: "Manage Matrix accounts, verification, devices, and profile state",
hasSubcommands: true,
},
],
},
);
},
registerCliMetadata: registerMatrixCliMetadata,
registerFull(api) {
void import("./src/plugin-entry.runtime.js")
.then(({ ensureMatrixCryptoRuntime }) =>

View File

@@ -0,0 +1,19 @@
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
export function registerMatrixCliMetadata(api: OpenClawPluginApi) {
api.registerCli(
async ({ program }) => {
const { registerMatrixCli } = await import("./cli.js");
registerMatrixCli({ program });
},
{
descriptors: [
{
name: "matrix",
description: "Manage Matrix accounts, verification, devices, and profile state",
hasSubcommands: true,
},
],
},
);
}

View File

@@ -0,0 +1,4 @@
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";

View File

@@ -0,0 +1,24 @@
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "memory-core",
name: "Memory (Core)",
description: "File-backed memory search tools and CLI",
register(api) {
api.registerCli(
async ({ program }) => {
const { registerMemoryCli } = await import("./src/cli.js");
registerMemoryCli(program);
},
{
descriptors: [
{
name: "memory",
description: "Search, inspect, and reindex memory files",
hasSubcommands: true,
},
],
},
);
},
});

View File

@@ -0,0 +1,10 @@
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "memory-lancedb",
name: "Memory LanceDB",
description: "LanceDB-backed memory provider",
register(api) {
api.registerCli(() => {}, { commands: ["ltm"] });
},
});

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,5 @@
export { normalizeCompatibilityConfig, legacyConfigRules } from "./src/doctor-contract.js";
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,6 @@
export { normalizeCompatibilityConfig, legacyConfigRules } from "./src/doctor-contract.js";
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";
export { singleAccountKeysToMove } from "./src/setup-contract.js";

View File

@@ -0,0 +1,10 @@
import { definePluginEntry } from "openclaw/plugin-sdk/core";
export default definePluginEntry({
id: "voice-call",
name: "Voice Call",
description: "Voice call channel plugin",
register(api) {
api.registerCli(() => {}, { commands: ["voicecall"] });
},
});

View File

@@ -0,0 +1,49 @@
type UnsupportedSecretRefConfigCandidate = {
path: string;
value: unknown;
};
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}
export const unsupportedSecretRefSurfacePatterns = [
"channels.whatsapp.creds.json",
"channels.whatsapp.accounts.*.creds.json",
] as const;
export function collectUnsupportedSecretRefConfigCandidates(
raw: unknown,
): UnsupportedSecretRefConfigCandidate[] {
if (!isRecord(raw)) {
return [];
}
if (!isRecord(raw.channels) || !isRecord(raw.channels.whatsapp)) {
return [];
}
const candidates: UnsupportedSecretRefConfigCandidate[] = [];
const whatsapp = raw.channels.whatsapp;
const creds = isRecord(whatsapp.creds) ? whatsapp.creds : null;
if (creds) {
candidates.push({
path: "channels.whatsapp.creds.json",
value: creds.json,
});
}
const accounts = isRecord(whatsapp.accounts) ? whatsapp.accounts : null;
if (!accounts) {
return candidates;
}
for (const [accountId, account] of Object.entries(accounts)) {
if (!isRecord(account) || !isRecord(account.creds)) {
continue;
}
candidates.push({
path: `channels.whatsapp.accounts.${accountId}.creds.json`,
value: account.creds.json,
});
}
return candidates;
}

View File

@@ -0,0 +1,4 @@
export {
collectRuntimeConfigAssignments,
secretTargetRegistryEntries,
} from "./src/secret-contract.js";

View File

@@ -0,0 +1 @@
export {};