@plumeai/plugin-sdk 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@ export interface ToolOutput {
37
37
  * 给工具卡片和插件自己用的结构化数据,存进会话,不发给模型。形状由插件定,本体不看里面,只认这几个通用声明:
38
38
  * 带 `checklist`(`ChecklistDetails`)是一份进度清单,带 `job`(`BackgroundJobDetails`)是在后台起了一个任务,
39
39
  * 带 `path`、`added`、`removed`、`hunks`(`FileDiffDetails`)是改了一个文件、通用卡片画出 diff,
40
- * 出错的结果带 `cancelled: true`(`CancelledDetails`)是人按了停、不是失败。
40
+ * 出错的结果带 `cancelled: true`(`CancelledDetails`)是人按了停、不是失败,带 `spill`(`SpillDetails`)是结果截过、全文在别处。
41
41
  * 插件之间另认一个:让模型看了文件的哪一块(`FileViewDetails`)。改了哪些文件不在这里,见 `changes`。
42
42
  */
43
43
  details?: unknown;
@@ -110,6 +110,19 @@ export interface FileViewDetails {
110
110
  verbatim: boolean;
111
111
  };
112
112
  }
113
+ /**
114
+ * 工具结果的 `details` 带上 `spill`,就是声明「这次结果截过,全文在 `address`」:`address` 是资源地址(`run.files.spill` 给的
115
+ * `artifact://`),`read` 能按行、按窗口读回来;`path` 是它在磁盘上的位置,给人打开、给别的插件核对用;`characters` 是全文多少字。
116
+ *
117
+ * 本体和插件都不按工具名找它:诊断从结果上认出它就能看全文,不再拼某个插件的目录。`details` 里别的字段照旧归插件。
118
+ */
119
+ export interface SpillDetails {
120
+ spill: {
121
+ address: string;
122
+ path: string;
123
+ characters: number;
124
+ };
125
+ }
113
126
  /**
114
127
  * 出错的工具结果(`isError`)的 `details` 带上 `cancelled: true`,就是声明「没做完是因为人按了停,不是失败」:转录画成「已停止」,
115
128
  * 不画成出错。工具被停下时自己交结果的(命令跑到一半被杀)自己带上;本体替停下的调用交结果、或停下以后工具交回的错误结果
@@ -377,6 +390,22 @@ export interface RunFiles {
377
390
  ok: false;
378
391
  message: string;
379
392
  }>;
393
+ /**
394
+ * 结果截过以后,把没交给模型的那份原文存在会话的临时目录里,交回它的地址和位置(`SpillDetails` 的形状,直接放进
395
+ * `ToolOutput.details.spill`)。地址是 `artifact://<id>`,按 `tool` 和内容算:同一段原文每次换回同一个地址,后来重发的历史里
396
+ * 那句提示逐字不变。模型要读了经 `read` 按行、按窗口取回;会话删掉时一起清掉,重开应用以后还在。
397
+ *
398
+ * 每个会话最多留 30 份,超了丢最旧的。写不进去(磁盘满、会话没有临时目录)时抛错,由工具自己决定少说一句还是报错——
399
+ * 截断本身不该因此失败。不记改动快照、不问人:临时目录是会话自己的草稿。只在这次调用里用。
400
+ *
401
+ * 同步的:调用它的都在同步地生成一条结果(压缩剪一条结果、mcp 把服务器的回复换成交给模型的样子),内容已经在内存里,
402
+ * 写成异步只会把「这条结果长什么样」摊成两步,还得让这些路径都变成异步。写的是几百 KB 到磁盘。
403
+ */
404
+ spill(tool: string, content: string): {
405
+ address: string;
406
+ path: string;
407
+ characters: number;
408
+ };
380
409
  /**
381
410
  * 这次调用的结果也算上一条命令改的文件:`process` 是经 `exec`(`recordChanges`)起的进程或它留下的进程,可以是之前的调用起的(后台命令)。
382
411
  * 命令已经结束就算上它记下的,还在跑就记一句「结束后才记」。读后台命令输出的调用用。不是这个会话里经 `exec` 观测的进程时什么都不做。
@@ -1912,7 +1941,47 @@ export interface PluginWorkspace {
1912
1941
  * 不在 git 仓库里、或 git 答不上来时是 null,由调用方自己走目录。不问人:要不要读 `root` 由调用方先经 `ToolRun.files.read` 判。
1913
1942
  */
1914
1943
  files(root: string): Promise<string[] | null>;
1944
+ /**
1945
+ * 在同一个隔离视图里跑一组 git 命令,结束即删:HEAD、引用、分支的上游和远端地址都照着真实仓库抄好,分支、ahead / behind、
1946
+ * 日志上的装饰和在真实仓库里跑一样,读不到仓库自己的配置(`core.fsmonitor`、过滤器、`diff.external`、钩子)、也不会连网。
1947
+ * 一组读共用一个视图:搭一个要先跑几条命令,每条命令各搭一个就是每次刷新几十个进程。
1948
+ *
1949
+ * `root` 不在检出里时 `work` 不跑,交回 null。只读:暂存、提交、推送、切分支这些人点了才做的事仍由插件自己在真实仓库上跑,
1950
+ * 那样钩子、凭据助手正是人要的。除了要写 stdin 的那一个(`gitWithInput`,`cat-file --batch`),
1951
+ * 要按二进制读的用 `gitBuffer`:`git show HEAD:logo.png` 回的不是文字。
1952
+ */
1953
+ git<T>(root: string, work: (view: PluginGitView) => Promise<T>): Promise<T | null>;
1954
+ }
1955
+ /**
1956
+ * `ctx.workspace.git` 给的视图。路径、pathspec 相对 `cwd`,和在该目录直接跑 git 一样。
1957
+ * 读的结果没有替调用方决定是不是文字,失败时抛错(和 git 自己一样:非零退出就算失败,stderr 上那些不是错误的话不管)。
1958
+ */
1959
+ export interface PluginGitView {
1960
+ /** 调用方给的目录:命令在这里跑。 */
1961
+ readonly cwd: string;
1962
+ git(args: string[]): Promise<string>;
1963
+ gitBuffer(args: string[]): Promise<Uint8Array>;
1964
+ gitWithInput(args: string[], input: string): Promise<Uint8Array>;
1965
+ /**
1966
+ * 没人点的那种获取(面板露面时、之后每五分钟):在视图里 `fetch --prune`,再把变了的引用搬回真实仓库。
1967
+ * 别人的改动被拒时整批不搬(每条引用带着抄快照时的旧值)。浅克隆的边界变了就不搬,留给人点的那次获取。
1968
+ *
1969
+ * `cancelled` 是调用方叫停的,不算失败;`timedOut` 是到了时限被杀;其余失败带 git 自己的话(`stderr`),原话交给调用方去说。
1970
+ */
1971
+ fetch(options: {
1972
+ signal?: AbortSignal;
1973
+ timeoutMs: number;
1974
+ }): Promise<PluginGitFetch>;
1915
1975
  }
1976
+ /** 见 `PluginGitView.fetch`。 */
1977
+ export type PluginGitFetch = {
1978
+ ok: true;
1979
+ } | {
1980
+ ok: false;
1981
+ cancelled?: boolean;
1982
+ timedOut?: boolean;
1983
+ stderr?: string;
1984
+ };
1916
1985
  /**
1917
1986
  * 沙箱的模式:只读、能写项目目录、不设限。权限模式对应哪一档由本体定:请求批准只读,帮我批准能写项目目录和临时目录,
1918
1987
  * 完全访问不设限;`ToolExecution.readOnly` 一律只读。macOS 用 seatbelt,Windows 用受限令牌,Linux 没有后端。
@@ -843,8 +843,8 @@ export interface AgentService {
843
843
  * 图标和回复里的文件签,不认工具名;变了推 `tools` 事件。
844
844
  */
845
845
  listTools(): RegisteredToolInfo[];
846
- /** 启用或停用一个插件(按插件名),写进 plugins.json,立即生效。 */
847
- setPluginEnabled(name: string, enabled: boolean): Promise<PluginStatus[]>;
846
+ /** 启用或停用一个插件(按 `PluginStatus.key`),写进 plugins.json,立即生效。停用着的插件不导入。 */
847
+ setPluginEnabled(key: string, enabled: boolean): Promise<PluginStatus[]>;
848
848
  /** 界面语言变了:agent 进程之后给人看的报错、提示用这种语言。发给模型的文字不跟着变。 */
849
849
  setLocale(locale: Locale): void;
850
850
  /** 订阅所有会话的事件,直到调用方取消。 */
@@ -243,7 +243,7 @@ export interface PanelOptions {
243
243
  }>;
244
244
  /**
245
245
  * 打开这个面板的快捷键,Electron accelerator 的写法(`Control+\``、`CommandOrControl+Shift+P`),卡片上会显示它。
246
- * 作用于当前会话:面板区没开或在看别的就切到它(没开着就新开一个标签),正在看它就收起。和别的面板重了归后注册的,它撤下后还给前一个;Plume 自己的快捷键(⌘B、后退前进、Esc)和它自己面板的快捷键拿不走。
246
+ * 作用于当前会话:面板区没开或在看别的就切到它(没开着就新开一个标签),正在看它就收起。和别的面板重了归后注册的,它撤下后还给前一个;Plume 自己的快捷键(⌘B、后退前进、Esc,本体文件树的 ⌘P、文件面板的 ⌥⌘P)拿不走。
247
247
  */
248
248
  shortcut?: string;
249
249
  order?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeai/plugin-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "写 Plume 插件用的类型、命令(新建、检查、构建、安装)、插件模板和给 agent 的 skill。随 Plume 应用带一份,也发在 npm 上(插件仓库按版本依赖)。",
5
5
  "license": "MIT",
6
6
  "repository": {
package/skill/SKILL.md CHANGED
@@ -64,8 +64,9 @@ description: 写、改、排查 Plume 插件:工具、钩子(tool.execute、
64
64
  - 工具答完以后在后台接着跑的事,结束或有新进展时经 `run.background()` 的渠道送回这个会话(`report`,闲时开一轮、忙时在步骤边界读入,人按停后作废;只有顶层会话有)。还在跑的任务经 `run.track` 登记进本体(会自己结束的才算会话没闲,监视(`wakes`)和认出是长跑服务后经 `stand()` 标上的不算;删会话、退出时本体经你给的 `stop` 停掉),约会话过一会儿接着做经 `run.schedule`(到点经渠道送你给的话,不挡会话闲下来);别的插件经 `ctx.sessions.jobs` / `wakeups` 列出、停掉、取消。
65
65
  - 会话之间递话:顶层会话里,工具那次调用经 `run.letter(to, letter)` 给另一个顶层会话寄一封信(请求、答复或通知,本体照实填发件方、在前面说明不是用户的话),回执的 `read` 告诉你读到没有;请求的答复由本体配对,收件方没答、没读到、删掉了时本体代答,你不用记账。`run.letter`、`run.parent` 只在这次调用里能用,调用答完再用就抛错。
66
66
  - 工具里写、改用户的文件经 `run.files.change(path, edit)`:本体守写的边界(Plume 自己的数据目录、别的会话的临时目录不写,看着在工作区里的链接写不出去),同一个文件排队、写之前再核一遍没被别处改过,把这次改动记成快照、记在这次调用的结果上(`ToolOutput.changes`,本体填,工具写了也不算;交付卡、撤回据它退文件)。`edit` 拿到现在的 `{ path, text, stamp }`(不存在时 `text`、`stamp` 是 null),交回 `{ text?, value }`,不给 `text` 就不写;问不问人归工具自己(`run.ask`)。写资源地址(`scratch://`)经 `run.files.write(address, content)`;模型写的路径要换成绝对路径(显示、记「读过了」)用 `run.files.resolve(path)`。可能改文件的命令经 `run.exec(command, { recordChanges: true })` 跑,本体在命令前后对比工作区记下它改了什么;命令到这次调用答完还在跑的,读它输出的那次调用经 `run.files.includeChanges(process)` 把记下的算进来。读、撤销某个会话里记下的改动经 `ctx.changes.collect(sessionId, ids)`、`ctx.changes.undo(sessionId, ids, path?)`,`ids` 取工具结果的 `changes.ids`。
67
- - 工具里读用户的文件经 `run.files.read(path)`(路径或资源地址):本体守读的边界(工作区、项目目录、符号链接、密钥按文件问),和内置文件工具共用批准记录,只授予读取,成功后读交回的 `path`;跑命令的工具起命令前经 `run.files.readCommand(command)` 判命令写明要读的路径。列项目文件经 `ctx.workspace.files(root)`(git 认为该看的,不执行仓库配置的程序),不自己跑 `git ls-files`。
67
+ - 工具里读用户的文件经 `run.files.read(path)`(路径或资源地址):本体守读的边界(工作区、项目目录、符号链接、密钥按文件问),和内置文件工具共用批准记录,只授予读取,成功后读交回的 `path`;跑命令的工具起命令前经 `run.files.readCommand(command)` 判命令写明要读的路径。列项目文件经 `ctx.workspace.files(root)`(git 认为该看的,不执行仓库配置的程序),不自己跑 `git ls-files`;没人点就要读仓库(status、diff、日志、后台获取)经 `ctx.workspace.git(root, work)`,在本体搭的隔离视图里跑,人点的暂存、提交、推送仍由插件自己在真实仓库上跑。
68
68
  - 把只为这次答案写的文件放进会话的临时目录(`run.scratchDir`,会话删掉时一起删):太大不值得交给模型的图写在这里、`output` 给路径、图放进结果的 `shownImages` 只给人看;经 `ctx.resources.register` 加一种资源地址(`scheme://路径`,模型用 read、ls 读它),或经 `ctx.resources.keepArtifact` 把大块原文存成 `artifact://` 地址。
69
+ - 工具结果截过时,把没交给模型的全文经 `run.files.spill(tool, content)` 存下(同步返回 `{ address, path, characters }`,按 `tool` 和内容算地址、同一段原文换回同一个,每个会话最多 30 份、重开应用后还在),把它放进 `details.spill`(`SpillDetails`):本体按这个形状认「结果截过、全文在别处」,界面上能读回来;`output` 里再给一句地址,模型自己按行、按窗口读。`details` 里另有 `outputPath` 的是命令完整输出的位置(`plume.tools` 的 bash),两者可以同时有。
69
70
 
70
71
  插件做不到的:替换模型调用或 agent 循环、换掉别的工具(本体的、别的插件的)的审批卡、改模型回复(存下的那份;显示时拿掉标记见 `ui.replyText`)、在没有用户停止操作时让本来要接着做的一轮停下(`step.end` 只能多做或给结束换原因,`ui.stopSession` 只接受真实点击)、任意往会话里写东西或发起一轮(只允许自己的子会话和独立会话、钩子 `say` / `context`、宿主校验过的后台运行结果 `report`、工具经 `run.background()` 送回本会话的后台结果、工具经 `run.letter` 寄给另一个顶层会话的信(标着来自哪个会话)、`launch` 开出来的新会话的第一句话,以及自己的子会话里经 `run.parent` / `handToParent` 排进它父会话的任务;不能往别的已有会话里发、不能指定任意父会话或冒充用户授权)、没人点按钮时替人发送、绕过公开草稿接口操纵输入框、新增钩子或界面扩展点。
71
72
 
@@ -135,7 +136,7 @@ description: 写、改、排查 Plume 插件:工具、钩子(tool.execute、
135
136
  | `todo` | 注册工具、details 让本体的转录认得(不注册卡片,调用并进一段活);`step.end` 在本体的结论外面追问一句、工具结果带 `terminate` 结束这一轮、`run.calls` 看同一步的其他调用;跟着会话的卡片(`ui.conversationCard`)从会话的消息里读最新一份、按 `placement` 换外观、按钮经 `stop` / `carryOn` 停下或接着做;插件自带样式表;`messages.ts` 的写法 |
136
137
  | `terminal` | `ctx.serve` / `ui.remote()` 流式输出和取消、原生依赖、`ctx.effect`、多标签面板、插件自带样式表、点链接打开文件和网址、拖文件进来粘贴路径 |
137
138
  | `scheduled` | `ctx.dataDir` 存数据、页面(`ui.page`)经 `ui.remote()` 读写;逻辑入口常驻定时器按时 `ctx.sessions.launch` 开新会话、等第一轮结束判失败;`watch` 推状态,界面入口一直连着、给页面挂数目(`ui.pageBadge`)、在输入框上方说失败(`ui.composerAbove`、`ui.openPage`),卡片上「打开上次会话」(`ui.openSession`) |
138
- | `git` | 大一点的插件:逻辑入口跑子进程、`ctx.model.complete` 写提交说明;面板里多个视图、`ui.remote()` 的 `.cancel()` 叫停远端调用;项目签那一行加格子(`ui.composerChip`)、`ui.notify`、`ui.openPanel`、`ui.draftInSession`;diff 评论攒起来经 `ui.draftInSession` 的 `send` 交给面板所在的会话;几个样式表一起挂;`ctx.provide` 提供服务 `session.worktree`;对话自己的工作树:`prompt.submit` 的 `cwd` 在第一轮把会话挪进去,`ctx.sessions.onDeleted`、`onArchived` 收回、检出回来,项目签那一格的 `send`、`ui.sessionMark`、`ui.deleteNote`、设置分区 |
139
+ | `git` | 大一点的插件:逻辑入口跑子进程、自动刷新的读和后台获取经 `ctx.workspace.git`、`ctx.model.complete` 写提交说明;面板里多个视图、`ui.remote()` 的 `.cancel()` 叫停远端调用;项目签那一行加格子(`ui.composerChip`)、`ui.notify`、`ui.openPanel`、`ui.draftInSession`;diff 评论攒起来经 `ui.draftInSession` 的 `send` 交给面板所在的会话;几个样式表一起挂;`ctx.provide` 提供服务 `session.worktree`;对话自己的工作树:`prompt.submit` 的 `cwd` 在第一轮把会话挪进去,`ctx.sessions.onDeleted`、`onArchived` 收回、检出回来,项目签那一格的 `send`、`ui.sessionMark`、`ui.deleteNote`、设置分区 |
139
140
  | `memory` | `model.context` 按段插提示词、每个会话冻结一份;按条件对模型藏起工具;`ctx.sessions` 读旧会话、`ctx.model.complete` 在后台定时总结;设置分区画进「个性化」页(`page`),「智能体」页「会话」那张卡里一行选总结用的模型(`ui.ModelSelect`) |
140
141
  | `usage` | 设置 › 数据里的一页(`ui.settingsSection` 的 `page: "nav"` 加 `group: "data"`,页头介绍用 `detail`);逻辑入口经 `ctx.model.usage` 读花销、`ctx.serve` 转给界面;SVG 自己画的堆叠柱状图(悬停气泡 fixed 定位)、环图(`stroke-dasharray` 分段)、热力图和色点,插件自带的模型品牌标 |
141
142
  | `screenshot` | 截屏浮层(`ui.screen`、`ui.screenOverlay`、`ui.pinnedShot`)、标注组件、输入框按钮(`ui.composerItem`)、占导航一行的设置分区(`ui.settingsSection` 的 `page: "nav"`)、逻辑入口跑子进程 |
@@ -54,9 +54,10 @@ export default {
54
54
  | `ctx.commands.provide(provider)` | 给输入框的 `/` 菜单供命令(见下面「`/` 命令」),停用时撤下 |
55
55
  | `ctx.plugins.list()` | 现在启用着、加载好了的插件:`name`、`dir`(插件目录)、`builtin`。给要读别的插件随包文件的插件用(技能插件读各插件的 `skills/`);每次调都是当时的样子 |
56
56
  | `ctx.plugins.onChange(listener)` | 插件装上、卸下、启用、停用以后叫一次(这时 `list()` 已经是新的),停用时撤下。读别的插件随包文件、又要当场跟上的插件用(MCP 插件读各插件的 `.mcp.json`,装上就连) |
57
- | `ctx.resources.register(handler)` / `list()` / `keepArtifact(sessionId, tool, content)` | 资源地址 `scheme://路径[:行-行]`,本体给、换不掉,解析统一走 `run.files.read`(见「工具」),类型在 `@plume/contract` 的 `ResourceHandler` 等。`register` 加一个只读的 scheme(`describe` 写进系统提示词的地址清单,`resolve` 读一个地址、找不到时抛错,错误信息直接交给模型;可选 `list` 给 `read scheme://` 列目录、`locate` 给 ls 一个磁盘位置),返回撤下的函数,停用时本体替你撤下;塞了 `write` 也写不进去。内容不是你写的(第三方文档、外部服务)时给 `origin`,plume.tools 的 read 把它包进 `<resource origin="…">`。路径的越界(`..`、软链出去)由 scheme 自己挡。`list()` 是现在登记着的(`{ scheme, describe, writable }`,只有 `scratch://` 可写)。`keepArtifact` 存一大块原文换回 `artifact://<id>`(按内容算,同一段每次同一个地址;按会话在内存里,最多 30 份,会话删掉时丢掉)。本体自带 `scratch://`(会话的临时目录)、`artifact://`、`session://`(别的会话的转录)、`plugin://`(插件的 README 和目录里的文件),技能插件加了 `skill://` |
57
+ | `ctx.resources.register(handler)` / `list()` / `keepArtifact(sessionId, tool, content)` | 资源地址 `scheme://路径[:行-行]`,本体给、换不掉,解析统一走 `run.files.read`(见「工具」),类型在 `@plume/contract` 的 `ResourceHandler` 等。`register` 加一个只读的 scheme(`describe` 写进系统提示词的地址清单,`resolve` 读一个地址、找不到时抛错,错误信息直接交给模型;可选 `list` 给 `read scheme://` 列目录、`locate` 给 ls 一个磁盘位置),返回撤下的函数,停用时本体替你撤下;塞了 `write` 也写不进去。内容不是你写的(第三方文档、外部服务)时给 `origin`,plume.tools 的 read 把它包进 `<resource origin="…">`。路径的越界(`..`、软链出去)由 scheme 自己挡。`list()` 是现在登记着的(`{ scheme, describe, writable }`,只有 `scratch://` 可写)。`keepArtifact` 存一大块原文换回 `artifact://<id>`(按内容算,同一段每次同一个地址;存在会话的临时目录里,每个会话最多 30 份,重开应用后还在,会话删掉时一起删;和 `run.files.spill` 是同一处)。本体自带 `scratch://`(会话的临时目录)、`artifact://`、`session://`(别的会话的转录)、`plugin://`(插件的 README 和目录里的文件),技能插件加了 `skill://` |
58
58
  | `ctx.changes.collect(sessionId, ids)` / `undo(sessionId, ids, path?)` | 本体记下的文件改动(工具经 `run.files.change` 写的、带 `recordChanges` 的命令改的),`ids` 取工具结果上的 `changes.ids`(`ToolResultMessage.changes`,本体填,按这个认,不认是哪个工具交的),工作目录用会话自己的。`collect` 交回按文件合并的净变化(`FileChangesSummary`:`files` 每项 `{ path, added, removed, hunks, canUndo, undoReason?, undoProblem? }`,`warnings`),改了又改回原样的不列;`undo` 撤销整批或其中一个文件:重新读快照,不收界面给的原文,查当前内容、连续的修改链和项目边界,有一个不对就都不写,命令改的不能自动撤销;撤销进行中、同一个或嵌套的项目里还有会话在跑一轮时抛错,`message` 给人看。界面先问人再调,显示状态不是写入许可。例子是 plume.delivery、plume.side-chat |
59
59
  | `ctx.workspace.files(root)` | `root` 之下 git 认为该看的文件(已跟踪的加上未跟踪且没被忽略的),绝对路径;不在 git 仓库里、git 答不上来时是 null,自己走目录。本体在隔离视图里问 git,不执行仓库能控制的程序(`core.fsmonitor`、过滤器、钩子:沙箱里的命令写得到 `.git/config`),插件要列项目文件就用它,不要自己跑 `git ls-files` |
60
+ | `ctx.workspace.git(root, work)` | 在一个隔离视图里跑一组 git 读,`work` 结束即删;`root` 不在检出里时 `work` 不跑、交回 null。视图(`PluginGitView`)的 `git`、`gitBuffer`(二进制,如 `show HEAD:logo.png`)、`gitWithInput`(要写 stdin 的,如 `cat-file --batch`)在 `cwd` 下跑,失败时抛错;HEAD、引用、上游、远端地址、浅克隆边界照真实仓库抄好,分支、ahead / behind、日志装饰和直接跑一样,读不到仓库自己的配置和钩子、不连网。`fetch({ signal, timeoutMs })` 是没人点的那种获取:在视图里 `fetch --prune`,再把变了的引用搬回真实仓库,交回 `PluginGitFetch`(`cancelled`、`timedOut`、git 的原话 `stderr`,怎么跟人说归插件)。一组读共用一个视图,别每条命令各开一个。只读:暂存、提交、推送、切分支这些人点了才做的事由插件自己在真实仓库上跑,那样钩子和凭据助手正是人要的。例子是 plume.git |
60
61
  | `ctx.provide(name, service)` | 提供一项服务给别的插件用(见下面「服务」),停用时撤下 |
61
62
  | `ctx.use(name)` | 用一项别的插件提供的服务,只能用 `inject` 里写了的(见下面「服务」) |
62
63
  | `ctx.sessions.observe(listener)` | 只读订阅会话的运行观察(请求、回复、审批、运行状态、收场……);默认只收和自己有关的会话的,要看全部在默认导出上写 `observe: "all"`。见下文「只读运行观察和后台任务」 |
@@ -545,7 +545,7 @@ function ModelSetting() {
545
545
 
546
546
  `ui.skin({ light: { … }, dark: { … } })`,只能覆盖 `SkinToken` 列出的 token(就是 `--plume-*` 去掉前缀),值是 CSS 值。颜色由四个种子 `bg`、`fg`、`accent`、`contrast`(0–1)推出整套面、线、字,通常只给种子;推出来的哪一档不满意再单独覆盖。同一时间只有一个皮肤,后注册的生效,它撤下后前一个恢复;同一入口可反复调用更新,`ui.skin(null)` 只撤下自己的皮肤。
547
547
 
548
- 同时提供 `name`(非空、最多 80 字符)和 `mode: "system" | "light" | "dark"` 时成为管理配色的数据皮肤。宿主暂时忽略用户保存的界面种子与深浅模式,外观页实时显示当前皮肤名和只读配色;字体、代码外观和其他偏好仍可改,原配色不被改写,皮肤停用后恢复。只提供 `{ light, dark }` 的旧皮肤不接管偏好,用户明确设置的项仍优先。深浅模式由宿主主进程按窗口暂存,插件不访问内部配置或 `window.plume`。
548
+ 同时提供 `name`(非空、最多 80 字符)和 `mode: "system" | "light" | "dark"` 时成为管理配色的数据皮肤。宿主暂时忽略用户保存的界面种子与深浅模式,外观页实时显示当前皮肤名和只读配色;字体、代码外观和其他偏好仍可改,原配色不被改写,皮肤停用后恢复。只提供 `{ light, dark }` 的普通皮肤不接管偏好,用户明确设置的项仍优先。深浅模式由宿主主进程按窗口暂存,插件不访问内部配置或 `window.plume`。
549
549
 
550
550
  只传 `{ name: "Plume", mode: "system" }`、不传 token 时,使用产品原生配色并跟随系统;`light`、`dark` 则固定模式。这和 `ui.skin(null)` 不同:前者暂时管理配色并屏蔽原有种子覆盖,后者退出管理、恢复原用户偏好。
551
551