fix: merge plugin manifest types
This commit is contained in:
@@ -2,7 +2,7 @@ import path from "node:path";
|
|||||||
|
|
||||||
import { discoverClawdbotPlugins } from "../../plugins/discovery.js";
|
import { discoverClawdbotPlugins } from "../../plugins/discovery.js";
|
||||||
import type { PluginOrigin } from "../../plugins/types.js";
|
import type { PluginOrigin } from "../../plugins/types.js";
|
||||||
import type { ClawdbotManifest } from "../../plugins/manifest.js";
|
import type { ClawdbotPackageManifest } from "../../plugins/manifest.js";
|
||||||
import type { ChannelMeta } from "./types.js";
|
import type { ChannelMeta } from "./types.js";
|
||||||
|
|
||||||
export type ChannelPluginCatalogEntry = {
|
export type ChannelPluginCatalogEntry = {
|
||||||
@@ -27,7 +27,7 @@ const ORIGIN_PRIORITY: Record<PluginOrigin, number> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function toChannelMeta(params: {
|
function toChannelMeta(params: {
|
||||||
channel: NonNullable<ClawdbotManifest["channel"]>;
|
channel: NonNullable<ClawdbotPackageManifest["channel"]>;
|
||||||
id: string;
|
id: string;
|
||||||
}): ChannelMeta | null {
|
}): ChannelMeta | null {
|
||||||
const label = params.channel.label?.trim();
|
const label = params.channel.label?.trim();
|
||||||
@@ -70,7 +70,7 @@ function toChannelMeta(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveInstallInfo(params: {
|
function resolveInstallInfo(params: {
|
||||||
manifest: ClawdbotManifest;
|
manifest: ClawdbotPackageManifest;
|
||||||
packageName?: string;
|
packageName?: string;
|
||||||
packageDir?: string;
|
packageDir?: string;
|
||||||
workspaceDir?: string;
|
workspaceDir?: string;
|
||||||
@@ -93,7 +93,7 @@ function buildCatalogEntry(candidate: {
|
|||||||
packageName?: string;
|
packageName?: string;
|
||||||
packageDir?: string;
|
packageDir?: string;
|
||||||
workspaceDir?: string;
|
workspaceDir?: string;
|
||||||
packageClawdbot?: ClawdbotManifest;
|
packageClawdbot?: ClawdbotPackageManifest;
|
||||||
}): ChannelPluginCatalogEntry | null {
|
}): ChannelPluginCatalogEntry | null {
|
||||||
const manifest = candidate.packageClawdbot;
|
const manifest = candidate.packageClawdbot;
|
||||||
if (!manifest?.channel) return null;
|
if (!manifest?.channel) return null;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import path from "node:path";
|
|||||||
|
|
||||||
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
||||||
import { resolveBundledPluginsDir } from "./bundled-dir.js";
|
import { resolveBundledPluginsDir } from "./bundled-dir.js";
|
||||||
import type { ClawdbotManifest, PackageManifest } from "./manifest.js";
|
import type { ClawdbotPackageManifest, PackageManifest } from "./manifest.js";
|
||||||
import type { PluginDiagnostic, PluginOrigin } from "./types.js";
|
import type { PluginDiagnostic, PluginOrigin } from "./types.js";
|
||||||
|
|
||||||
const EXTENSION_EXTS = new Set([".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"]);
|
const EXTENSION_EXTS = new Set([".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"]);
|
||||||
@@ -18,7 +18,7 @@ export type PluginCandidate = {
|
|||||||
packageVersion?: string;
|
packageVersion?: string;
|
||||||
packageDescription?: string;
|
packageDescription?: string;
|
||||||
packageDir?: string;
|
packageDir?: string;
|
||||||
packageClawdbot?: ClawdbotManifest;
|
packageClawdbot?: ClawdbotPackageManifest;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PluginDiscoveryResult = {
|
export type PluginDiscoveryResult = {
|
||||||
|
|||||||
@@ -1,4 +1,97 @@
|
|||||||
export type PluginManifestChannel = {
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
import type { PluginConfigUiHint, PluginKind } from "./types.js";
|
||||||
|
|
||||||
|
export const PLUGIN_MANIFEST_FILENAME = "clawdbot.plugin.json";
|
||||||
|
|
||||||
|
export type PluginManifest = {
|
||||||
|
id: string;
|
||||||
|
configSchema: Record<string, unknown>;
|
||||||
|
kind?: PluginKind;
|
||||||
|
channels?: string[];
|
||||||
|
providers?: string[];
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
version?: string;
|
||||||
|
uiHints?: Record<string, PluginConfigUiHint>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PluginManifestLoadResult =
|
||||||
|
| { ok: true; manifest: PluginManifest; manifestPath: string }
|
||||||
|
| { ok: false; error: string; manifestPath: string };
|
||||||
|
|
||||||
|
function normalizeStringList(value: unknown): string[] {
|
||||||
|
if (!Array.isArray(value)) return [];
|
||||||
|
return value.map((entry) => (typeof entry === "string" ? entry.trim() : "")).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolvePluginManifestPath(rootDir: string): string {
|
||||||
|
return path.join(rootDir, PLUGIN_MANIFEST_FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadPluginManifest(rootDir: string): PluginManifestLoadResult {
|
||||||
|
const manifestPath = resolvePluginManifestPath(rootDir);
|
||||||
|
if (!fs.existsSync(manifestPath)) {
|
||||||
|
return { ok: false, error: `plugin manifest not found: ${manifestPath}`, manifestPath };
|
||||||
|
}
|
||||||
|
let raw: unknown;
|
||||||
|
try {
|
||||||
|
raw = JSON.parse(fs.readFileSync(manifestPath, "utf-8")) as unknown;
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
error: `failed to parse plugin manifest: ${String(err)}`,
|
||||||
|
manifestPath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!isRecord(raw)) {
|
||||||
|
return { ok: false, error: "plugin manifest must be an object", manifestPath };
|
||||||
|
}
|
||||||
|
const id = typeof raw.id === "string" ? raw.id.trim() : "";
|
||||||
|
if (!id) {
|
||||||
|
return { ok: false, error: "plugin manifest requires id", manifestPath };
|
||||||
|
}
|
||||||
|
const configSchema = isRecord(raw.configSchema) ? raw.configSchema : null;
|
||||||
|
if (!configSchema) {
|
||||||
|
return { ok: false, error: "plugin manifest requires configSchema", manifestPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
const kind = typeof raw.kind === "string" ? (raw.kind as PluginKind) : undefined;
|
||||||
|
const name = typeof raw.name === "string" ? raw.name.trim() : undefined;
|
||||||
|
const description = typeof raw.description === "string" ? raw.description.trim() : undefined;
|
||||||
|
const version = typeof raw.version === "string" ? raw.version.trim() : undefined;
|
||||||
|
const channels = normalizeStringList(raw.channels);
|
||||||
|
const providers = normalizeStringList(raw.providers);
|
||||||
|
|
||||||
|
let uiHints: Record<string, PluginConfigUiHint> | undefined;
|
||||||
|
if (isRecord(raw.uiHints)) {
|
||||||
|
uiHints = raw.uiHints as Record<string, PluginConfigUiHint>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
manifest: {
|
||||||
|
id,
|
||||||
|
configSchema,
|
||||||
|
kind,
|
||||||
|
channels,
|
||||||
|
providers,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
version,
|
||||||
|
uiHints,
|
||||||
|
},
|
||||||
|
manifestPath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// package.json "clawdbot" metadata (used for onboarding/catalog)
|
||||||
|
export type PluginPackageChannel = {
|
||||||
id?: string;
|
id?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
selectionLabel?: string;
|
selectionLabel?: string;
|
||||||
@@ -16,21 +109,21 @@ export type PluginManifestChannel = {
|
|||||||
preferSessionLookupForAnnounceTarget?: boolean;
|
preferSessionLookupForAnnounceTarget?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PluginManifestInstall = {
|
export type PluginPackageInstall = {
|
||||||
npmSpec?: string;
|
npmSpec?: string;
|
||||||
localPath?: string;
|
localPath?: string;
|
||||||
defaultChoice?: "npm" | "local";
|
defaultChoice?: "npm" | "local";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ClawdbotManifest = {
|
export type ClawdbotPackageManifest = {
|
||||||
extensions?: string[];
|
extensions?: string[];
|
||||||
channel?: PluginManifestChannel;
|
channel?: PluginPackageChannel;
|
||||||
install?: PluginManifestInstall;
|
install?: PluginPackageInstall;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PackageManifest = {
|
export type PackageManifest = {
|
||||||
name?: string;
|
name?: string;
|
||||||
version?: string;
|
version?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
clawdbot?: ClawdbotManifest;
|
clawdbot?: ClawdbotPackageManifest;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user