feat(plugins): add setupGuide field for post-install guidance

Plugins can now include a setupGuide field in clawdbot.plugin.json
that will be displayed after installation, helping users with
configuration steps.

Changes:
- Add setupGuide field to PluginManifest type
- Parse setupGuide from plugin manifest
- Display setupGuide after successful plugin installation
This commit is contained in:
CoderMageFox 2026-01-27 19:27:04 +08:00
parent f4004054ab
commit aa44ea27bf
2 changed files with 17 additions and 0 deletions

View File

@ -7,6 +7,7 @@ import type { ClawdbotConfig } from "../config/config.js";
import { resolveArchiveKind } from "../infra/archive.js"; import { resolveArchiveKind } from "../infra/archive.js";
import { installPluginFromNpmSpec, installPluginFromPath } from "../plugins/install.js"; import { installPluginFromNpmSpec, installPluginFromPath } from "../plugins/install.js";
import { recordPluginInstall } from "../plugins/installs.js"; import { recordPluginInstall } from "../plugins/installs.js";
import { loadPluginManifest } from "../plugins/manifest.js";
import { applyExclusiveSlotSelection } from "../plugins/slots.js"; import { applyExclusiveSlotSelection } from "../plugins/slots.js";
import type { PluginRecord } from "../plugins/registry.js"; import type { PluginRecord } from "../plugins/registry.js";
import { buildPluginStatusReport } from "../plugins/status.js"; import { buildPluginStatusReport } from "../plugins/status.js";
@ -32,6 +33,16 @@ export type PluginUpdateOptions = {
dryRun?: boolean; dryRun?: boolean;
}; };
function printSetupGuideIfPresent(targetDir: string): void {
const manifestResult = loadPluginManifest(targetDir);
if (manifestResult.ok && manifestResult.manifest.setupGuide) {
defaultRuntime.log("");
defaultRuntime.log(theme.heading("Setup Guide:"));
defaultRuntime.log(manifestResult.manifest.setupGuide);
defaultRuntime.log("");
}
}
function formatPluginLine(plugin: PluginRecord, verbose = false): string { function formatPluginLine(plugin: PluginRecord, verbose = false): string {
const status = const status =
plugin.status === "loaded" plugin.status === "loaded"
@ -379,6 +390,7 @@ export function registerPluginsCli(program: Command) {
await writeConfigFile(next); await writeConfigFile(next);
logSlotWarnings(slotResult.warnings); logSlotWarnings(slotResult.warnings);
defaultRuntime.log(`Installed plugin: ${result.pluginId}`); defaultRuntime.log(`Installed plugin: ${result.pluginId}`);
printSetupGuideIfPresent(result.targetDir);
defaultRuntime.log(`Restart the gateway to load plugins.`); defaultRuntime.log(`Restart the gateway to load plugins.`);
return; return;
} }
@ -442,6 +454,7 @@ export function registerPluginsCli(program: Command) {
await writeConfigFile(next); await writeConfigFile(next);
logSlotWarnings(slotResult.warnings); logSlotWarnings(slotResult.warnings);
defaultRuntime.log(`Installed plugin: ${result.pluginId}`); defaultRuntime.log(`Installed plugin: ${result.pluginId}`);
printSetupGuideIfPresent(result.targetDir);
defaultRuntime.log(`Restart the gateway to load plugins.`); defaultRuntime.log(`Restart the gateway to load plugins.`);
}); });

View File

@ -16,6 +16,7 @@ export type PluginManifest = {
description?: string; description?: string;
version?: string; version?: string;
uiHints?: Record<string, PluginConfigUiHint>; uiHints?: Record<string, PluginConfigUiHint>;
setupGuide?: string;
}; };
export type PluginManifestLoadResult = export type PluginManifestLoadResult =
@ -75,6 +76,8 @@ export function loadPluginManifest(rootDir: string): PluginManifestLoadResult {
uiHints = raw.uiHints as Record<string, PluginConfigUiHint>; uiHints = raw.uiHints as Record<string, PluginConfigUiHint>;
} }
const setupGuide = typeof raw.setupGuide === "string" ? raw.setupGuide.trim() : undefined;
return { return {
ok: true, ok: true,
manifest: { manifest: {
@ -88,6 +91,7 @@ export function loadPluginManifest(rootDir: string): PluginManifestLoadResult {
description, description,
version, version,
uiHints, uiHints,
setupGuide,
}, },
manifestPath, manifestPath,
}; };