feat: 插件声明式设置体系——registerSettings schema + 标准控件表单 + 一级导航入口开关

This commit is contained in:
Rick Ye
2026-09-11 01:45:32 +08:00
parent 8349db9947
commit 2ad1743e10
10 changed files with 887 additions and 13 deletions
+1
View File
@@ -3,5 +3,6 @@
* 插件页(iframe)请改用 '@aso/plugin-sdk/client' 子入口(不含 pi SDK 类型依赖路径)。
*/
export * from './manifest'
export * from './settings'
export * from './status'
export * from './plugin'
+10
View File
@@ -4,6 +4,7 @@
*/
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'
import type { PluginManifest } from './manifest'
import type { PluginSettingsSchema, PluginSettingValues } from './settings'
import type { StatusItem, ToolbarButtonDef } from './status'
/** 插件私有 KV 存储(主进程落盘 userData/aso-plugin-storage.json,按 pluginId 命名空间隔离) */
@@ -24,6 +25,15 @@ export interface HarnessUiApi {
/** 注册输入区工具行按钮(按 id 键控;dispose 自动清理) */
registerToolbarButton(button: ToolbarButtonDef): void
removeToolbarButton(id: string): void
/** 声明插件设置表单(声明式 schema;items 为空 = 无配置页,一级入口开关随之不出现)。
* 值由宿主持久化并广播;每次插件激活时重新声明(重载后生效)。 */
registerSettings(schema: PluginSettingsSchema): void
/** 读取当前设置值(schema 默认值已合并) */
getSettingValues(): PluginSettingValues
/** 设置值变化推送(用户在设置页修改后实时触发) */
onSettingsChange(listener: (values: PluginSettingValues) => void): () => void
/** 设置页按钮条目点击回调(key = 按钮项的 key) */
onSettingsAction(listener: (key: string) => void): () => void
}
/** 插件工厂收到的完整 API */
+157
View File
@@ -0,0 +1,157 @@
/**
* 插件设置契约(声明式 schema):插件在 main.mjs 里经 api.ui.registerSettings(schema)
* 声明配置项,宿主负责渲染表单、持久化值(userData/aso-plugin-values.json,按插件隔离),
* 并把变更实时推回插件(ui.onSettingsChange)。按钮类条目的点击经 ui.onSettingsAction
* 回到插件主进程侧执行。
*
* schema 是纯数据(不可含函数/React 元素),保证主进程可持久化快照、渲染层零信任渲染。
*/
import type { PluginManifest } from './manifest'
/** 文件/目录选择模式(path / image 共用) */
export type PluginPathMode = 'file' | 'directory' | 'image'
/** 单个配置项(discriminated union on type) */
export type PluginSettingItem =
| {
/** 单行输入框;password: true 时掩码显示 */
type: 'string'
key: string
label: string
placeholder?: string
password?: boolean
default?: string
description?: string
}
| {
/** 多行文本 */
type: 'text'
key: string
label: string
placeholder?: string
rows?: number
default?: string
description?: string
}
| {
/** 数字输入 */
type: 'number'
key: string
label: string
min?: number
max?: number
step?: number
default?: number
description?: string
}
| {
/** 开关 */
type: 'boolean'
key: string
label: string
default?: boolean
description?: string
}
| {
/** 下拉单选 */
type: 'select'
key: string
label: string
options: Array<{ value: string; label: string }>
default?: string
description?: string
}
| {
/** 多选(checkbox 组) */
type: 'multiSelect'
key: string
label: string
options: Array<{ value: string; label: string }>
default?: string[]
description?: string
}
| {
/** 滑条(min/max 必填) */
type: 'slider'
key: string
label: string
min: number
max: number
step?: number
default?: number
description?: string
}
| {
/** 颜色选择(#rrggbb) */
type: 'color'
key: string
label: string
default?: string
description?: string
}
| {
/** 路径选择(文件 / 目录) */
type: 'path'
key: string
label: string
mode: Extract<PluginPathMode, 'file' | 'directory'>
placeholder?: string
default?: string
description?: string
}
| {
/** 图片选择(选择文件 + 缩略图预览) */
type: 'image'
key: string
label: string
default?: string
description?: string
}
| {
/** 动作按钮:点击回调到插件(ui.onSettingsAction,key 为本项 key) */
type: 'button'
key: string
label: string
/** primary 实心 / ghost 描边(缺省 ghost) */
variant?: 'primary' | 'ghost'
description?: string
}
| {
/** 静态说明文字(无 key,不产生配置值) */
type: 'info'
label: string
description?: string
}
| {
/** 分割线(label 可作为小节标题) */
type: 'divider'
label?: string
}
/** 插件设置 schema:items 为空数组 = 无配置页(一级入口开关随之不出现) */
export interface PluginSettingsSchema {
/** 配置页标题(缺省用插件名) */
title?: string
items: PluginSettingItem[]
}
/** 渲染层/插件共用的设置值快照(defaults 已合并) */
export type PluginSettingValues = Record<string, unknown>
/** 插件设置清单快照(管理页/导航消费) */
export type PluginSettingsSchemas = Record<string, PluginSettingsSchema>
export type PluginSettingsValuesMap = Record<string, PluginSettingValues>
/** 从 schema 提取默认值(宿主合并进 getSettingValues 返回) */
export function settingsDefaults(schema: PluginSettingsSchema): PluginSettingValues {
const out: PluginSettingValues = {}
for (const item of schema.items) {
if ('default' in item && item.default !== undefined) out[item.key] = item.default
}
return out
}
/** 设置页身份信息(导航项渲染用) */
export interface PluginSettingsMeta {
manifest: Pick<PluginManifest, 'id' | 'name' | 'icon' | 'description'>
}