# 插件全局设置

在清单顶层声明 `settingsSchema`，用户在桌面端“拓展 → 详情 → 插件设置”中编辑。设置属于当前宿主用户配置中的插件 ID，供该插件所有动作、服务与超级块后台共享；不依赖用户放置超级块。停止或禁用插件时仍可编辑，重新启动后读取已保存值；同 ID 升级保留设置。卸载保留用户配置，重新安装同 ID 可继续使用。

声明 `hostCapabilities.required` 中的 `"settings.global": 1`，明确声明使用的宿主接口。不需要额外权限。默认界面由宿主生成。也可声明顶层 `configPage`，用 [FlyonDeckPluginConfig](./plugin-config-page.md) 提供自定义页面；动态候选项目前不支持。

```json
{
  "hostCapabilities": { "required": { "settings.global": 1 } },
  "settingsSchema": {
    "properties": {
      "cliPath": { "type": "string", "title": "CLI 路径", "default": "" },
      "delivery": { "type": "string", "title": "默认执行方式", "default": "desktop", "options": [
        { "label": "桌面端", "value": "desktop" }, { "label": "服务端", "value": "server" }
      ] },
      "apiKey": { "type": "string", "title": "API Key", "control": "password" }
    }
  }
}
```

全局设置与 `widgets[].settingsSchema` 独立：后者继续表示单个实例的设置。宿主不会自动合并两个作用域；插件根据业务规则选择实例覆盖全局默认值。不要把密钥写入清单默认值。

## get()

```ts
context.settings.get(): Promise<Readonly<Record<string, string | number | boolean>>>
```

读取当前插件的最新设置，包括私密值及声明的默认值。未保存且没有默认值的字段缺省。空字符串是有效字符串，不会自动替换为默认值。插件只能读取自己的全局设置。

## onChange()

```ts
context.settings.onChange(listener: (values: Readonly<Record<string, string | number | boolean>>) => void | Promise<void>): () => void
```

订阅后台运行期间保存成功后的完整设置快照，返回取消订阅函数。注册时不发送初始快照；在 `onStart` 中读取 `get()`。通知不等待异步监听器完成，插件自行管理连接重建、并发与异常恢复；重新启动后始终重新读取设置。

```js
let preferences = {};
definePlugin({
  async onStart(context) {
    context.settings.onChange(values => { preferences = values; });
    preferences = await context.settings.get();
  }
});
```

## 私密值与保存行为

`visibility: "private"` 或 `control: "password"` 的值只由宿主保存并交给插件后台。桌面编辑器只收到已配置标记，空白密码框保持原值；替换值需重新填写，清除需点击明确的清除操作，再保存。全局设置不会自动进入页面上下文、状态快照或设备布局；后台不要主动转发私密值。配置文件以受限文件权限保存在宿主用户数据目录，不是系统钥匙串，也不承诺加密存储。

保存时宿主校验字段、类型、范围与总大小，并使用原子替换。不同编辑窗口基于版本号检测冲突，冲突后重新读取。恢复默认值先修改表单，点击保存后生效。已保存配置必须符合当前 Schema；未知字段或类型不符会明确报错，保存操作不推断历史格式或静默替换。插件版本升级时，可通过 configurationVersion 与 configurationMigrations 在启动前迁移历史格式，见[更新与迁移](../migrations/compatibility.md)。默认值只用于未配置的字段。

## PluginSettings

### `PluginSettings.properties`

`Record<string, PluginSetting>` · 必填。最多 32 项，键名以小写字母开头，可含字母、数字、下划线，最多 64 字符。已保存覆盖值合计最多 64 KiB。

## PluginSetting

### `PluginSetting.type`

`"string" | "integer" | "boolean"` · 必填。

### `PluginSetting.title`

`string` · 必填，非空，最多 80 字符。

### `PluginSetting.description`

`string` · 可选，最多 240 字符。

### `PluginSetting.control`

`"password" | "search-select"` · 可选，仅字符串。password 按私密值处理，不能同时声明 options；search-select 需声明静态 options。

### `PluginSetting.visibility`

`"public" | "private"` · 可选，默认 public。public 允许在桌面设置表单显示，不代表自动对设备页面或其他插件公开。

### `PluginSetting.default`

`string | integer | boolean` · 可选，必须符合字段类型与约束。没有保存值时使用。

### `PluginSetting.minimum`

`integer` · 可选，仅整数，必须是安全整数，包含边界。

### `PluginSetting.maximum`

`integer` · 可选，仅整数，必须是安全整数，包含边界，不小于 minimum。

### `PluginSetting.maxLength`

`integer` · 可选，仅字符串，1–4096，默认 4096。

### `PluginSetting.options`

`PluginSettingOption[]` · 可选，仅字符串，1–512 个静态候选项；保存值必须在选项中。不支持 dynamicOptions。

## PluginSettingOption

### `PluginSettingOption.label`

`string` · 必填，非空，最多 80 字符。

### `PluginSettingOption.value`

`string` · 必填，非空、不重复，长度不超过字段 maxLength。

标签国际化使用与其他清单字段相同的 titleKey、descriptionKey、labelKey，见[国际化](./i18n.md)。
