@plumeai/plugin-sdk 0.0.0-stage → 0.1.3

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.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/bin/plume-plugin.mjs +70 -0
  3. package/dist/client/styles/src/index.d.ts +123 -0
  4. package/dist/client/ui/src/avatar/AgentAvatar.d.ts +42 -0
  5. package/dist/client/ui/src/avatar/AvatarPile.d.ts +36 -0
  6. package/dist/client/ui/src/avatar/AvatarStack.d.ts +26 -0
  7. package/dist/client/ui/src/avatar/art.d.ts +32 -0
  8. package/dist/client/ui/src/fileIcon.d.ts +33 -0
  9. package/dist/client/ui/src/hooks/useCopied.d.ts +16 -0
  10. package/dist/client/ui/src/hooks/useLiveRefresh.d.ts +22 -0
  11. package/dist/client/ui/src/hooks/useNarrow.d.ts +16 -0
  12. package/dist/client/ui/src/i18n/context.d.ts +17 -0
  13. package/dist/client/ui/src/i18n/index.d.ts +2 -0
  14. package/dist/client/ui/src/i18n/list.d.ts +20 -0
  15. package/dist/client/ui/src/i18n/locales.d.ts +10 -0
  16. package/dist/client/ui/src/i18n/messages/en.d.ts +1418 -0
  17. package/dist/client/ui/src/i18n/messages/index.d.ts +6 -0
  18. package/dist/client/ui/src/i18n/messages/zh-CN.d.ts +1263 -0
  19. package/dist/client/ui/src/i18n/plural.d.ts +16 -0
  20. package/dist/client/ui/src/i18n/translate.d.ts +43 -0
  21. package/dist/client/ui/src/icons/index.d.ts +5 -0
  22. package/dist/client/ui/src/image/AnnotateCanvas.d.ts +29 -0
  23. package/dist/client/ui/src/image/AnnotateToolbar.d.ts +73 -0
  24. package/dist/client/ui/src/image/Annotator.d.ts +154 -0
  25. package/dist/client/ui/src/image/annotate.d.ts +227 -0
  26. package/dist/client/ui/src/image/paint.d.ts +35 -0
  27. package/dist/client/ui/src/image/screenshot-geometry.d.ts +112 -0
  28. package/dist/client/ui/src/image/useBarDrag.d.ts +31 -0
  29. package/dist/client/ui/src/image/useMovableBar.d.ts +26 -0
  30. package/dist/client/ui/src/image/useToolbarPlacement.d.ts +42 -0
  31. package/dist/client/ui/src/index.d.ts +140 -0
  32. package/dist/client/ui/src/inputs/ColorField.d.ts +9 -0
  33. package/dist/client/ui/src/inputs/ComposerToggle.d.ts +23 -0
  34. package/dist/client/ui/src/inputs/DateRangeField.d.ts +25 -0
  35. package/dist/client/ui/src/inputs/NativeField.d.ts +5 -0
  36. package/dist/client/ui/src/inputs/SearchField.d.ts +21 -0
  37. package/dist/client/ui/src/inputs/Segmented.d.ts +23 -0
  38. package/dist/client/ui/src/inputs/Select.d.ts +32 -0
  39. package/dist/client/ui/src/inputs/ShortcutRecorder.d.ts +8 -0
  40. package/dist/client/ui/src/inputs/Slider.d.ts +13 -0
  41. package/dist/client/ui/src/inputs/TextArea.d.ts +30 -0
  42. package/dist/client/ui/src/inputs/Toggle.d.ts +10 -0
  43. package/dist/client/ui/src/inputs/WorktreeToggle.d.ts +19 -0
  44. package/dist/client/ui/src/inputs/day-range.d.ts +57 -0
  45. package/dist/client/ui/src/inputs/pickers.d.ts +40 -0
  46. package/dist/client/ui/src/inputs/useFieldFade.d.ts +1 -0
  47. package/dist/client/ui/src/keyboard.d.ts +21 -0
  48. package/dist/client/ui/src/layout/ApprovalFrame.d.ts +33 -0
  49. package/dist/client/ui/src/layout/Collapse.d.ts +9 -0
  50. package/dist/client/ui/src/layout/CopyMark.d.ts +19 -0
  51. package/dist/client/ui/src/layout/Disclosure.d.ts +66 -0
  52. package/dist/client/ui/src/layout/ErrorBoundary.d.ts +26 -0
  53. package/dist/client/ui/src/layout/PageTopRow.d.ts +19 -0
  54. package/dist/client/ui/src/layout/PanelEmpty.d.ts +17 -0
  55. package/dist/client/ui/src/layout/ResizeHandle.d.ts +24 -0
  56. package/dist/client/ui/src/layout/RetainedViews.d.ts +32 -0
  57. package/dist/client/ui/src/layout/Settings.d.ts +41 -0
  58. package/dist/client/ui/src/layout/Splitter.d.ts +25 -0
  59. package/dist/client/ui/src/lib/agent-avatar.d.ts +58 -0
  60. package/dist/client/ui/src/lib/code/font-stack.d.ts +12 -0
  61. package/dist/client/ui/src/lib/code/themes.d.ts +35 -0
  62. package/dist/client/ui/src/lib/date-format.d.ts +8 -0
  63. package/dist/client/ui/src/lib/dispatches.d.ts +8 -0
  64. package/dist/client/ui/src/lib/hour-style.d.ts +13 -0
  65. package/dist/client/ui/src/lib/number-draft.d.ts +24 -0
  66. package/dist/client/ui/src/lib/relative-time.d.ts +18 -0
  67. package/dist/client/ui/src/lib/tiling.d.ts +89 -0
  68. package/dist/client/ui/src/lib/typing.d.ts +19 -0
  69. package/dist/client/ui/src/motion/RollWords.d.ts +26 -0
  70. package/dist/client/ui/src/motion/RollingText.d.ts +43 -0
  71. package/dist/client/ui/src/motion/TypedText.d.ts +9 -0
  72. package/dist/client/ui/src/motion/freeze.d.ts +22 -0
  73. package/dist/client/ui/src/motion/held.d.ts +17 -0
  74. package/dist/client/ui/src/motion/loaders.d.ts +65 -0
  75. package/dist/client/ui/src/motion/reduced.d.ts +13 -0
  76. package/dist/client/ui/src/motion/ticked.d.ts +24 -0
  77. package/dist/client/ui/src/motion/ticker.d.ts +31 -0
  78. package/dist/client/ui/src/motion/tokens.d.ts +29 -0
  79. package/dist/client/ui/src/motion/useNow.d.ts +6 -0
  80. package/dist/client/ui/src/overlay/Confirm.d.ts +96 -0
  81. package/dist/client/ui/src/overlay/ContextMenu.d.ts +40 -0
  82. package/dist/client/ui/src/overlay/Dialog.d.ts +60 -0
  83. package/dist/client/ui/src/overlay/Menu.d.ts +90 -0
  84. package/dist/client/ui/src/overlay/Overlay.d.ts +17 -0
  85. package/dist/client/ui/src/overlay/Popover.d.ts +127 -0
  86. package/dist/client/ui/src/overlay/Tooltip.d.ts +14 -0
  87. package/dist/client/ui/src/overlay/afterimage.d.ts +20 -0
  88. package/dist/client/ui/src/overlay/chrome-top.d.ts +8 -0
  89. package/dist/client/ui/src/overlay/hover-layers.d.ts +41 -0
  90. package/dist/client/ui/src/overlay/portal.d.ts +21 -0
  91. package/dist/client/ui/src/overlay/scrims.d.ts +20 -0
  92. package/dist/client/ui/src/overlay/tooltip-attribute.d.ts +62 -0
  93. package/dist/client/ui/src/primitives/Button.d.ts +64 -0
  94. package/dist/client/ui/src/primitives/Caret.d.ts +25 -0
  95. package/dist/client/ui/src/primitives/ChoiceMark.d.ts +12 -0
  96. package/dist/client/ui/src/primitives/ClosableTab.d.ts +23 -0
  97. package/dist/client/ui/src/primitives/CountUp.d.ts +21 -0
  98. package/dist/client/ui/src/primitives/GitHubMark.d.ts +12 -0
  99. package/dist/client/ui/src/primitives/IconButton.d.ts +55 -0
  100. package/dist/client/ui/src/primitives/MarkNumber.d.ts +12 -0
  101. package/dist/client/ui/src/primitives/RowDeleteButton.d.ts +6 -0
  102. package/dist/client/ui/src/primitives/Skeleton.d.ts +36 -0
  103. package/dist/client/ui/src/primitives/TabStrip.d.ts +29 -0
  104. package/dist/client/ui/src/primitives/Text.d.ts +341 -0
  105. package/dist/client/ui/src/primitives/TimeAgo.d.ts +13 -0
  106. package/dist/client/ui/src/primitives/useCountUp.d.ts +23 -0
  107. package/dist/client/ui/src/row/FlowRow.d.ts +31 -0
  108. package/dist/client/ui/src/row/HoverRow.d.ts +28 -0
  109. package/dist/client/ui/src/scroll/BackToLatest.d.ts +19 -0
  110. package/dist/client/ui/src/scroll/OverlayScrollbar.d.ts +9 -0
  111. package/dist/client/ui/src/scroll/ScrollText.d.ts +24 -0
  112. package/dist/client/ui/src/scroll/Scroller.d.ts +66 -0
  113. package/dist/client/ui/src/scroll/Sideways.d.ts +30 -0
  114. package/dist/client/ui/src/scroll/fade.d.ts +2 -0
  115. package/dist/client/ui/src/scroll/follow.d.ts +157 -0
  116. package/dist/client/ui/src/scroll/measure-batch.d.ts +13 -0
  117. package/dist/client/ui/src/scroll/memory.d.ts +22 -0
  118. package/dist/client/ui/src/scroll/signature.d.ts +24 -0
  119. package/dist/client/ui/src/scroll/useFollowBottom.d.ts +80 -0
  120. package/dist/client/ui/src/scroll/useSideways.d.ts +29 -0
  121. package/dist/contract/src/app.d.ts +16 -0
  122. package/dist/contract/src/changes.d.ts +50 -0
  123. package/dist/contract/src/diagnostics.d.ts +86 -0
  124. package/dist/contract/src/index.d.ts +18 -0
  125. package/dist/contract/src/plugin.d.ts +1391 -0
  126. package/dist/contract/src/resources.d.ts +79 -0
  127. package/dist/contract/src/service.d.ts +806 -0
  128. package/dist/contract/src/ui.d.ts +1039 -0
  129. package/dist/contract/src/usage.d.ts +102 -0
  130. package/dist/core/llm/ai/anthropic-messages-request.d.ts +82 -0
  131. package/dist/core/llm/ai/anthropic-messages.d.ts +43 -0
  132. package/dist/core/llm/ai/cache-routing.d.ts +53 -0
  133. package/dist/core/llm/ai/chat-delta.d.ts +107 -0
  134. package/dist/core/llm/ai/compat-key.d.ts +19 -0
  135. package/dist/core/llm/ai/endpoint.d.ts +57 -0
  136. package/dist/core/llm/ai/failure.d.ts +181 -0
  137. package/dist/core/llm/ai/index.d.ts +16 -0
  138. package/dist/core/llm/ai/openai-chat-completions-request.d.ts +49 -0
  139. package/dist/core/llm/ai/openai-chat-completions.d.ts +37 -0
  140. package/dist/core/llm/ai/openai-responses-request.d.ts +63 -0
  141. package/dist/core/llm/ai/openai-responses.d.ts +11 -0
  142. package/dist/core/llm/ai/prefix-fingerprint.d.ts +20 -0
  143. package/dist/core/llm/ai/reasoning-compat.d.ts +69 -0
  144. package/dist/core/llm/ai/request-params-compat.d.ts +39 -0
  145. package/dist/core/llm/ai/retry.d.ts +130 -0
  146. package/dist/core/llm/ai/sanitize-history.d.ts +23 -0
  147. package/dist/core/llm/ai/think-tag.d.ts +37 -0
  148. package/dist/core/llm/ai/thinking-options.d.ts +35 -0
  149. package/dist/core/llm/ai/tool-names.d.ts +17 -0
  150. package/dist/core/llm/ai/tool-pairing-compat.d.ts +53 -0
  151. package/dist/core/llm/ai/tool-result-images-compat.d.ts +24 -0
  152. package/dist/core/llm/ai/tool-schema.d.ts +20 -0
  153. package/dist/core/llm/ai/usage-fields.d.ts +30 -0
  154. package/dist/core/llm/ai/vendors/index.d.ts +20 -0
  155. package/dist/core/llm/ai/vendors/thinking.d.ts +39 -0
  156. package/dist/core/llm/ai/vendors/types.d.ts +47 -0
  157. package/dist/core/llm/config/image-models.d.ts +34 -0
  158. package/dist/core/llm/config/retry-policy.d.ts +35 -0
  159. package/dist/core/llm/images/chat-images.d.ts +11 -0
  160. package/dist/core/llm/images/dimensions.d.ts +15 -0
  161. package/dist/core/llm/images/generate.d.ts +15 -0
  162. package/dist/core/llm/images/openai-images.d.ts +11 -0
  163. package/dist/core/llm/images/quota.d.ts +9 -0
  164. package/dist/core/llm/images/shape.d.ts +44 -0
  165. package/dist/core/llm/images/types.d.ts +118 -0
  166. package/dist/core/llm/model-catalog-format.d.ts +50 -0
  167. package/dist/core/llm/model-catalog.d.ts +51 -0
  168. package/dist/core/llm/types/message.d.ts +450 -0
  169. package/dist/core/llm/types/provider.d.ts +169 -0
  170. package/dist/core/llm/types/tool.d.ts +23 -0
  171. package/dist/core/llm/types.d.ts +10 -0
  172. package/dist/core/llm/utils/pricing.d.ts +18 -0
  173. package/dist/core/llm/utils/record.d.ts +2 -0
  174. package/dist/core/llm/utils/sse.d.ts +69 -0
  175. package/dist/infra/rpc/src/endpoint.d.ts +36 -0
  176. package/dist/infra/rpc/src/index.d.ts +2 -0
  177. package/dist/infra/rpc/src/rpc.d.ts +54 -0
  178. package/dist/theme.css +336 -0
  179. package/dist/ui.d.ts +2 -0
  180. package/lib/build.mjs +143 -0
  181. package/lib/check.mjs +23 -0
  182. package/lib/dev.mjs +52 -0
  183. package/lib/icons.mjs +2 -0
  184. package/lib/init.mjs +109 -0
  185. package/lib/install.mjs +80 -0
  186. package/lib/link.mjs +44 -0
  187. package/lib/lint/i18n.mjs +149 -0
  188. package/lib/lint/imports.mjs +83 -0
  189. package/lib/lint/index.mjs +54 -0
  190. package/lib/lint/styles.mjs +160 -0
  191. package/lib/manifest.d.mts +9 -0
  192. package/lib/manifest.mjs +99 -0
  193. package/lib/targets.mjs +60 -0
  194. package/package.json +34 -4
  195. package/skill/SKILL.md +150 -0
  196. package/skill/references/components.md +2830 -0
  197. package/skill/references/logic.md +526 -0
  198. package/skill/references/style-i18n.md +70 -0
  199. package/skill/references/ui.md +532 -0
  200. package/template/AGENTS.md +17 -0
  201. package/template/CLAUDE.md +1 -0
  202. package/template/README.md +12 -0
  203. package/template/gitignore +2 -0
  204. package/template/src/index.ts +28 -0
  205. package/template/src/messages.ts +16 -0
  206. package/template/src/types.ts +8 -0
  207. package/template/src/ui.tsx +30 -0
  208. package/template/tsconfig.json +7 -0
  209. package/tsconfig.json +25 -0
  210. package/README.md +0 -3
@@ -0,0 +1,1039 @@
1
+ /**
2
+ * 插件界面入口 `dist/ui.mjs` 用的类型。界面入口跑在渲染进程,按 props 画;要 agent 进程里的东西,只能经 `remote()` 调自己的逻辑入口。
3
+ */
4
+ import type { Remote } from "../../infra/rpc/src/index.d.ts";
5
+ import type { ComponentType, MouseEvent, ReactNode } from "react";
6
+ import type { ChangeHunk } from "./changes.ts";
7
+ import type { Locale, SlashCommand, ToolCall, ToolOutput } from "./plugin.ts";
8
+ import type { ApprovalDecision, ApprovalRequest, ContextBreakdown, FileContents, OutgoingMessage, PermissionMode, SessionSummary, SessionTarget, SessionView, ThinkingLevel } from "./service.ts";
9
+ import type { AssistantMessage, DeliveredReport, UserMessage } from "../../core/llm/types.d.ts";
10
+ export type { Remote, SessionView, ToolCall, ToolOutput };
11
+ /** 回复正文中的围栏代码块;语法与内容由插件校验,宿主不执行其中的代码。 */
12
+ export interface CodeBlockProps {
13
+ language: string;
14
+ code: string;
15
+ sessionId: string;
16
+ /** 消息在此会话里的展示标识,不是数据库记录 id。 */
17
+ messageId: string;
18
+ /** 消息内的正文段及代码块位置。 */
19
+ blockId: string;
20
+ /** 消息仍在生成或平滑显示尚未结束。 */
21
+ streaming: boolean;
22
+ /** 原始围栏已闭合且消息成功完成;中断、截断不算完成。 */
23
+ complete: boolean;
24
+ fallback: ReactNode;
25
+ /** 只在真实点击或表单提交事件中同步调用;发送到此块所属会话。只读视图和未完成块没有此入口。 */
26
+ send?: (text: string, event: import("react").SyntheticEvent) => Promise<void>;
27
+ }
28
+ export interface ToolCardProps {
29
+ /** 这次调用所在的会话:子会话(子 Agent、侧边聊天)里的调用是那个子会话自己的 id。 */
30
+ sessionId: string;
31
+ call: ToolCall;
32
+ /** 参数尚在生成时的原始 JSON;只供安全的静态草稿展示。 */
33
+ argumentsText?: string;
34
+ streaming?: boolean;
35
+ /** 发送到卡片所属会话。只在真实点击/提交,或聚焦的卡片 iframe 发来的用户操作消息中同步调用;只读视图没有此入口。displayText 可提供气泡中显示的简短说明,text 仍是完整模型输入。 */
36
+ send?: (text: string, event: import("react").SyntheticEvent | MessageEvent, displayText?: string) => Promise<void>;
37
+ /**
38
+ * 卡片画在插件的子会话(侧边聊天)里时才有:把一件事排进它父会话的队列,标着来自侧边聊天,和
39
+ * `ToolRun.parent.enqueue` 同一条路。只在人点了卡片上写明要交出去什么的按钮时调(「交给主会话」),不拿来替人做决定。
40
+ */
41
+ handToParent?(instruction: string): Promise<void>;
42
+ status: "approval" | "running" | "done" | "failed";
43
+ /** 执行中的输出。 */
44
+ progress?: string;
45
+ /** 执行完才有。 */
46
+ result?: ToolOutput;
47
+ /** 通用卡片。认不出 details 时直接返回它。 */
48
+ fallback: ReactNode;
49
+ }
50
+ /** 内置工具里做同一类事的那个,见 `ToolLine.like`。 */
51
+ export type ToolLike = "read" | "grep" | "edit" | "write" | "bash";
52
+ /** `ui.toolLine`:转录里怎么说一个工具。 */
53
+ export interface ToolLine {
54
+ /**
55
+ * 做的事,一个动词短语(「查找符号」)。一次调用说成「动作 对象」(「查找符号 runAgent」),一段活里几次合在一起数个数
56
+ * (「查找符号 3 个」)。
57
+ */
58
+ verb: LocalizedText;
59
+ /** 这一次要点名的对象,从参数里取;参数是模型给的、没校验过,取不出就返回 undefined,只说动作。 */
60
+ subject?(args: Record<string, unknown>): string | undefined;
61
+ /**
62
+ * 做的事像哪个内置工具:和它归成一类(读、搜索归「探索」,改、写归「改文件」,`bash` 归「跑命令」),连着做时并进同一段活;
63
+ * 运行行用同一种说法;没给 `icon` 时用它的图标。不给就自成一类:只有连着调这个工具才合成一段,图标是终端那枚。
64
+ */
65
+ like?: ToolLike;
66
+ /**
67
+ * 归哪一类活,名字插件自己起(`"browser"`):同一类的几个工具连着做时合成一段,和读、跑命令、改文件那几类也接成一段——
68
+ * 边改边在页面上验是一件事。给了就不按 `like` 归类,`like` 照旧管运行行和图标。
69
+ */
70
+ group?: string;
71
+ /** 几次合在一起时数次数,不数个数:「操作网页 4 次」,不是读着像四张网页的「操作网页 4 个」。 */
72
+ times?: true;
73
+ /**
74
+ * `verb` 只说这一次调用(跑着时那一行、展开后的那一行);一段活收起后合在一起说时,照没登记说法的工具说「使用工具」。
75
+ * 给不算一件活、只是收尾手续的工具用(子智能体交结果的 `yield`)。
76
+ */
77
+ callOnly?: true;
78
+ /** 行首的图标,13px,颜色跟着文字走(currentColor)。 */
79
+ icon?: ComponentType<{
80
+ size?: number;
81
+ strokeWidth?: number;
82
+ className?: string;
83
+ }>;
84
+ }
85
+ export interface PanelProps {
86
+ /** 标签归属会话的只读视图,随事件更新;不跟随窗口焦点。子会话面板保留 owner 语义;新对话尚无会话时为空。 */
87
+ session?: SessionView;
88
+ /**
89
+ * 标签归属会话下一轮的工作目录;子会话面板沿用 owner 的目录语义。还没发消息的新对话是选中项目的目录,不属于项目的聊天为空。
90
+ * 后台标签仍收到自己的目录,不使用窗口当前聚焦会话的目录。
91
+ */
92
+ cwd?: string;
93
+ /**
94
+ * 这个面板所在标签的 id,标签关掉之前不变。能开好几个的面板用它分开各自的东西(终端:连的是哪个 shell)。
95
+ * 组件卸掉不等于标签关了:未设 keepAlive 时换会话、去设置页可能卸掉,回来再挂上同一个 id。
96
+ */
97
+ tab: string;
98
+ /**
99
+ * 标签归属会话正在显示、面板区已展开,而且它是当前标签。后台标签和收起的面板区看不见,
100
+ * 定时去网络上取东西之类只为了给人看的事,看不见时停下。
101
+ */
102
+ shown: boolean;
103
+ /** 改标签上的字,不给回到面板名。能开好几个的面板靠它让几个标签分得出谁是谁。 */
104
+ setTitle(title: string | undefined): void;
105
+ /**
106
+ * 人点标签上的 ✕ 时先调它:返回 false 就不关,关了的标签不会再回来,它自己的东西(终端的 shell)在这里收掉。
107
+ * 后设的替换先设的,返回的函数撤掉。没设就直接关。
108
+ */
109
+ onClose(handler: () => boolean | Promise<boolean>): () => void;
110
+ }
111
+ /** `ui.listCommands` 列出的一条命令。`plugin` 是供它的插件名,产品自己的命令没有。 */
112
+ export interface ListedCommand extends SlashCommand {
113
+ plugin?: string;
114
+ }
115
+ export interface PageProps {
116
+ /** 当前打开的会话;还没打开会话时为空。只读,随会话的事件更新。 */
117
+ session?: SessionView;
118
+ /**
119
+ * 当前工作区:打开着会话时是它的项目和工作目录(可能是工作树),没打开会话时是空白页选着的项目或目录;
120
+ * 哪个都没选时为空。项目的目录按 `project` 在 `ui.useProjects()` 里查。
121
+ */
122
+ workspace?: SessionTarget;
123
+ }
124
+ export interface PageOptions {
125
+ /** 页面的名字:侧栏里那一行的字。 */
126
+ title: LocalizedText;
127
+ /** 侧栏那一行的图标,颜色跟着文字走(currentColor);不给用产品的默认图标。 */
128
+ icon?: ComponentType<{
129
+ size?: number;
130
+ className?: string;
131
+ }>;
132
+ order?: number;
133
+ /**
134
+ * 页面自己画窗口顶行,默认 false。
135
+ *
136
+ * 平时宿主在页面上方留一行和标题栏一样高的空白(窗口的拖动区域)。两栏的页面(左边列表、右边详情)这样排,
137
+ * 分隔线从这一行下面才开始,悬在半空;盖满整页的一层也只能从它下面开始。设成 true 以后宿主不留这一行,页面从
138
+ * 正文卡片的顶边开始,每一栏最上面放一个 `@plume/ui` 的 `PageTopRow`(高度、拖动、给红绿灯让位都在里面)。
139
+ * 宿主在页面外层给 `--plume-top-row-height`(顶行高)和 `--plume-top-row-inset`(侧栏收起时左边要让出的宽度)。
140
+ */
141
+ topRow?: boolean;
142
+ }
143
+ /**
144
+ * 皮肤能改的 token,对应 @plume/styles theme.css 里的 `--plume-<名字>`;theme.css 加减 token 时同步这里。
145
+ *
146
+ * 前四个是种子:背景、前景、强调色、对比度(0–1,默认 0.6)。其余的面、线、字都由种子推出来,
147
+ * 皮肤通常只改种子;推出来的哪一档不满意,再单独覆盖那一档。
148
+ */
149
+ export type SkinToken = "bg" | "fg" | "accent" | "contrast" | "shell" | "root" | "accent-dim" | "sidebar" | "card" | "card-hover" | "elevated" | "input" | "float" | "knob" | "shade" | "window-tint" | "line" | "line-soft" | "line-float" | "ink" | "ink-muted" | "ink-faint" | "ok" | "danger" | "warning" | "violet" | "chart-2" | "chart-3" | "chart-4" | "chart-5" | "chart-6" | "on-accent" | "code-bg" | "code-fg" | "code-line-height" | "code-tracking" | "inline-code-bg" | "inline-code-fg" | "inline-code-ring" | "syntax-operator" | "diff-add" | "diff-remove" | "syntax-keyword" | "syntax-string" | "syntax-number" | "syntax-comment" | "syntax-function" | "syntax-type" | "syntax-variable" | "syntax-punctuation" | "syntax-tag" | "syntax-attribute" | "radius-panel" | "radius-field" | "radius-item" | "radius-menu" | "font-sans" | "font-mono" | "ui-size" | "code-size";
150
+ /**
151
+ * 插件给产品显示的一段字:固定的字符串,或者按当前界面语言给出的函数。
152
+ * 用函数而不是每种语言一份,界面加一种语言时插件的写法不用变;没翻译的语言由插件自己决定退回哪一种。
153
+ */
154
+ export type LocalizedText = string | ((locale: Locale) => string);
155
+ /**
156
+ * 回复里的网址、文件签还能用什么打开(内置浏览器),见 `UiContext.linkOpener`。
157
+ * 宿主只在人点了的那一刻调 `open`;开在哪、开成什么样由插件定。
158
+ */
159
+ export interface LinkOpener {
160
+ /** 网址右键菜单里那一行、文件签悬停按钮的字。 */
161
+ label: LocalizedText;
162
+ /** 那一行、那个按钮的图标,颜色跟着文字走(currentColor)。 */
163
+ icon?: ComponentType<{
164
+ size?: number;
165
+ className?: string;
166
+ }>;
167
+ /** 开得了网址(http、https):回复里网址的右键菜单多这一行。 */
168
+ web?: boolean;
169
+ /** 点网址时由它开,不交给系统浏览器(人在插件设置里选的);Shift 点照旧交给系统浏览器。点的那一刻同步问。 */
170
+ takesClicks?(): boolean;
171
+ /** 开得了这个本机文件(绝对路径):文件签悬停时多一个按钮,点签本身照旧在文件面板里打开。画的时候同步问,别做耗时的事。 */
172
+ file?(path: string): boolean;
173
+ /** 开它。`sessionId` 是链接所在的会话;新对话里为空。 */
174
+ open(target: {
175
+ url: string;
176
+ } | {
177
+ path: string;
178
+ }, sessionId: string | undefined): void | Promise<void>;
179
+ }
180
+ /**
181
+ * 排队条上一条消息「更多」菜单里多的一项(在侧边聊天中打开),见 `UiContext.queueAction`。
182
+ * 宿主只在人点了那一项时调 `run`,调之前已经把这条从排队里拿掉;拿到别处去发由插件定。
183
+ */
184
+ export interface QueueAction {
185
+ /** 菜单里那一行的字。 */
186
+ label: LocalizedText;
187
+ /** 那一行的图标,颜色跟着文字走(currentColor)。 */
188
+ icon?: ComponentType<{
189
+ size?: number;
190
+ className?: string;
191
+ }>;
192
+ /** `message` 是排着的那条,和直接发出去的一样(正文、附件、气泡上的字);`sessionId` 是它排在哪个会话。抛错时弹提示,这条不放回排队。 */
193
+ run(message: OutgoingMessage, sessionId: string): void | Promise<void>;
194
+ }
195
+ export interface PanelOptions {
196
+ /** 面板的名字:开始页卡片的标题、标签上的字。 */
197
+ title: LocalizedText;
198
+ /** 卡片上标题下面的一句说明。 */
199
+ description?: LocalizedText;
200
+ /** 卡片和标签上的图标,颜色跟着文字走(currentColor);不给用产品的默认图标。 */
201
+ icon?: ComponentType<{
202
+ size?: number;
203
+ className?: string;
204
+ }>;
205
+ /**
206
+ * 打开这个面板的快捷键,Electron accelerator 的写法(`Control+\``、`CommandOrControl+Shift+P`),卡片上会显示它。
207
+ * 作用于当前会话:面板区没开或在看别的就切到它(没开着就新开一个标签),正在看它就收起。和别的面板重了归后注册的,它撤下后还给前一个;Plume 自己的快捷键(⌘B、后退前进、Esc)和它自己面板的快捷键拿不走。
208
+ */
209
+ shortcut?: string;
210
+ order?: number;
211
+ /** 同一会话能不能开好几个标签(终端:一个标签一个 shell)。默认每会话只开一个;不同会话的标签分别保留。 */
212
+ multiple?: boolean;
213
+ /** 只从卡片打开的辅助面板设为 false,不在面板开始页列出;仍可经 openPanel 打开。默认 true。 */
214
+ listed?: boolean;
215
+ /** 可在重启后恢复标签。默认 false;声明后插件须按 tab 恢复自己的数据,不能只留在组件内存里。 */
216
+ restore?: boolean;
217
+ /** 可弹出到独立窗口。默认 false;声明后须能在另一渲染进程按 tab 接回数据,卸载不能销毁资源。 */
218
+ detachable?: boolean;
219
+ /**
220
+ * 标签一直挂着,直到关掉:换会话、去设置页都不卸掉组件,只是藏起来。给卸掉就丢东西、又没法从逻辑入口接回来的面板
221
+ * (网页:`<webview>` 一卸页面就没了,后台会话里 agent 也操作不了它)。默认 false。
222
+ * 所有 keepAlive 标签放在统一扁平常驻层,切换会话不重挂;后台仍收到标签归属会话的 `session` 和 `cwd`。
223
+ * 弹出、收回窗口仍会重新挂载,不改变 detachable 的资源恢复约定;用不着的页面自己少挂(挂着的每一页都是一个进程)。
224
+ */
225
+ keepAlive?: boolean;
226
+ /**
227
+ * 现在能不能新开。不给就一直能用;按目录(同 `PanelProps.cwd`)和有无会话分别计算。
228
+ * 目录或有无会话变化、窗口回到前台、一轮结束时重算;答 false(或还没答上来、抛错)时不列入新开列表、快捷键不新开,已有标签不隐藏、不卸载。
229
+ */
230
+ available?: (context: PanelAvailabilityContext) => boolean | Promise<boolean>;
231
+ }
232
+ export interface PanelAvailabilityContext {
233
+ /** 同 `PanelProps.cwd`。 */
234
+ cwd?: string;
235
+ /** 有没有打开的会话:新对话还没发消息时是 false。只围着一个会话转的面板(侧边聊天、子 Agent)没有会话就不列。 */
236
+ session: boolean;
237
+ }
238
+ /**
239
+ * 产品的对话视图画一个会话(插件自己的子会话:侧边聊天、子 Agent;或插件的独立会话:页面上的助手),和主列是同一套转录:
240
+ * 工具卡片、思考、运行行都一样。子会话等人批准时,审批卡压在主输入框上方,标明是哪个子会话在请求;独立会话不挂在哪个对话下,
241
+ * 审批卡压在这个视图的输入框上方。
242
+ */
243
+ export interface ConversationProps {
244
+ /** 要画的会话。还没有(侧边聊天的第一句还没发)时画 `empty` 和输入框。 */
245
+ sessionId?: string;
246
+ /**
247
+ * 底下的输入框。不给就只读(子 Agent 的全过程)。按发送时调 `send`,输入框随即清空;会话正在跑时发送键换成停止键,按了调 `stop`。
248
+ * 发出去的话怎么进会话由插件定(逻辑入口经 `ctx.sessions.send`),这里只管收字。
249
+ */
250
+ composer?: {
251
+ /** 输入框跨窗口保留文字、附件和引用时传 PanelProps.tab;页面上的助手传一个自己固定的名字。 */
252
+ draftKey?: string;
253
+ placeholder?: LocalizedText;
254
+ send(text: string): void | Promise<void>;
255
+ /** 支持附件时接收完整消息;不提供时保持纯文字输入。 */
256
+ sendMessage?(message: OutgoingMessage): void | Promise<void>;
257
+ /** steer 运行时也能发,发送键不变停止键。 */
258
+ mode?: "turn" | "steer";
259
+ disabled?: boolean;
260
+ /**
261
+ * 发送按钮左边的模型和思考档位,量的是这个会话(子会话没选的跟着父会话,独立会话没选的用默认模型);会话还没建时不画。
262
+ * `choose`:和主输入框同一枚按钮,能换,子会话的模型菜单最前面多一项「跟随主会话」;`show`:只读的模型名和档位,悬停说明末尾接 `modelTip`。
263
+ * 不给就不画。插件经 `ui.composerItem(…, { side: "end" })` 加的格子(上下文用量)不用声明,会话在就画。
264
+ */
265
+ model?: "choose" | "show";
266
+ /** `model: "show"` 时悬停说明的最后一句:模型是怎么定下的、去哪里改。 */
267
+ modelTip?: LocalizedText;
268
+ /** 发送按钮左边、用量和模型前面,插件自己的东西。 */
269
+ footer?: ReactNode;
270
+ stop?(): void;
271
+ };
272
+ /**
273
+ * 人在这里说的最后一句能「编辑并重新提问」:宿主截掉它和之后的,拿改过的字替插件重跑一轮(照常经 `prompt.submit`),
274
+ * 不问要不要连文件一起退回。没有撤回和分叉:那两样把话放回主对话的输入框、往会话列表里开新会话,子会话两样都没有。
275
+ * 一轮在跑时按钮置灰。侧边聊天开它;子 Agent 的全过程不开(它的话是派它的会话写的,不是人)。
276
+ */
277
+ reask?: boolean;
278
+ /** 仅定制这个视图里的用户消息;fallback 是产品原有气泡,不改存储。 */
279
+ renderUserMessage?(message: UserMessage, fallback: ReactNode): ReactNode;
280
+ /** 仅过滤这个视图的回复正文与复制,供回报卡去重,不影响工具、思考或历史。 */
281
+ replyText?(text: string, message: AssistantMessage): string;
282
+ /** 还没有消息时画在转录的位置上(`PanelEmpty` 之类)。不给就是空白。 */
283
+ empty?: ReactNode;
284
+ }
285
+ /**
286
+ * 插件给自己的工具画的审批卡(`ui.approvalCard`)。卡片压在输入框正上方的那一格由产品摆,排队、停下这一轮时撤卡也归产品;
287
+ * 组件画整张卡(外框、正文、按钮),人拍板时调 `respond`。要连同回答交给工具的别的话(修改意见、评论),先经自己的
288
+ * `remote()` 交给逻辑入口,再 `respond`:工具从 `run.ask` 返回以后去取。
289
+ */
290
+ export interface ApprovalCardProps {
291
+ request: ApprovalRequest;
292
+ /** 在问的会话;子会话(侧边聊天、子 Agent)问时是子会话的 id。 */
293
+ sessionId: string;
294
+ /** 问的是子会话时它的标题,卡上要写明是谁在请求。 */
295
+ from?: string;
296
+ /** 排在这张后面还在等的审批张数,卡上写 +N(`@plume/ui` 的 `ApprovalFrame` 替你写)。到期时刻在 `request.expiresAt`。 */
297
+ queued: number;
298
+ /** 交出回答。没送到时抛错,卡片自己把错误摆出来、让人再答。 */
299
+ respond(decision: ApprovalDecision): Promise<void>;
300
+ /** 设置里现在的权限模式。 */
301
+ permission: PermissionMode;
302
+ /**
303
+ * 把权限模式从请求批准切到帮我批准,给「接受并开启自动模式」这样的按钮:先切,再 `respond`。
304
+ * 只在人点了卡上的按钮时调;不在请求批准档时什么都不改(不会把完全访问降下来)。
305
+ */
306
+ allowAuto(): Promise<void>;
307
+ /** 窄窗口:面板区一次只摆一格,打开面板会盖住这张卡,要读的东西画在卡里。 */
308
+ compact: boolean;
309
+ /** 产品的通用审批卡。认不出这次请求时直接返回它。 */
310
+ fallback: ReactNode;
311
+ }
312
+ /** 始终位于主输入框上方的一整行,不随转录滚动或浮到侧边。 */
313
+ export interface ComposerAboveProps {
314
+ session: SessionView;
315
+ }
316
+ /** `ui.agentDelivery` 的组件收到的:送达所在的会话,和这一次送达里本插件的子会话交回的几份。 */
317
+ export interface AgentDeliveryProps {
318
+ sessionId: string;
319
+ reports: DeliveredReport[];
320
+ }
321
+ /** 复用产品 Markdown,包括会话范围内的文件链接。 */
322
+ export interface MarkdownProps {
323
+ text: string;
324
+ sessionId?: string;
325
+ streaming?: boolean;
326
+ className?: string;
327
+ /**
328
+ * 一句短话:只画行内记号(代码、加粗、强调、删除线),包在一个 `span` 里,不分段、不带段距;链接和图片只留字,不给点。
329
+ * 结构化回报里一条记录的一句话用它:交给整个 Markdown 会包出段落,原样摆着反引号又像一份没排版的草稿。
330
+ */
331
+ inline?: boolean;
332
+ }
333
+ export interface ComposerItemProps {
334
+ /** 输入框所在的会话。新对话里还没有会话,是 undefined:这一格在新对话的输入框里也画。 */
335
+ sessionId?: string;
336
+ /** 这个会话正在跑一轮。 */
337
+ running: boolean;
338
+ /** 下一轮会用的模型(会话选的,或默认模型);一个可用的模型都没有时为空。 */
339
+ model?: {
340
+ id: string;
341
+ name: string;
342
+ contextWindow: number;
343
+ };
344
+ }
345
+ export interface ComposerItemOptions {
346
+ /** `start` 排在「添加附件」那一组后面,只在主输入框;`end` 在右边、模型选择前面,插件子会话(`ui.Conversation`)的输入框里也画,拿到的是子会话。默认 `start`。 */
347
+ side?: "start" | "end";
348
+ order?: number;
349
+ }
350
+ export interface ComposerChipProps {
351
+ /** 输入框所在的会话;还没发出第一条消息的新会话为空。 */
352
+ sessionId?: string;
353
+ /** 下一轮在哪个目录里跑:会话的工作目录,新会话是选中项目的目录;不属于任何项目的聊天为空。 */
354
+ cwd?: string;
355
+ /** 这个会话正在跑一轮。 */
356
+ running: boolean;
357
+ /**
358
+ * 以人的身份在这个会话里发一句话,和人在输入框里打字按发送一样:画成人的气泡,模型当它是人说的;正在跑时排进队里。
359
+ * 只在人点了这一格里写明要发什么的按钮时调(工作树的「交给这个对话解决」),不拿来替人做决定。新对话(没有 `sessionId`)里什么都不做。
360
+ */
361
+ send(text: string): void;
362
+ }
363
+ /** `ui.environmentSection` 的组件拿到的:卡片跟着的会话。 */
364
+ export interface EnvironmentSectionProps {
365
+ session: SessionView;
366
+ }
367
+ /** 别的插件登记的一节环境卡片,见 `UiContext.useEnvironmentSections`。 */
368
+ export interface EnvironmentSectionEntry {
369
+ /** `插件名/id`,全局唯一,可以拿来记「这一节藏起来了」。 */
370
+ key: string;
371
+ /** 卡片「显示哪些内容」菜单里的名字。 */
372
+ label: LocalizedText;
373
+ order: number;
374
+ /** 已经包好错误边界:一节出错只撤下这一节。 */
375
+ component: ComponentType<EnvironmentSectionProps>;
376
+ /**
377
+ * 登记时给了 `attention` 才有:画环境卡片的插件把它挂在开关旁边(它什么都不画),这一节等人处理的那句话变了就调 `onChange`。
378
+ * 已经包好错误边界,出错时当作没有。
379
+ */
380
+ attention?: ComponentType<EnvironmentAttentionProps>;
381
+ }
382
+ /** `EnvironmentSectionEntry.attention` 拿到的。 */
383
+ export interface EnvironmentAttentionProps {
384
+ session: SessionView;
385
+ /** 这一节等人处理的那句话,见 `UiContext.environmentSection` 的 `attention`;没有时是 undefined。 */
386
+ onChange(text: string | undefined): void;
387
+ }
388
+ export interface ConversationCardProps {
389
+ /** 卡片跟着的会话:正文里开着的那一个。 */
390
+ session: SessionView;
391
+ /**
392
+ * 画在哪:`floating` 浮在转录右上角(或停靠在右边那一列),`inline` 在输入框正上方。浮着的要自己的底色和阴影,压在正文上面也读得清。
393
+ * 登记时给了 `lane` 的卡片总是 `floating`。
394
+ */
395
+ placement: "floating" | "inline";
396
+ /** 停下这个会话正在跑的一轮,和输入框的停止按钮一样。只在人点了卡片上的按钮时调。 */
397
+ stop(): void;
398
+ /**
399
+ * 替人说一句让它接着做,和转录底下的「继续」一样:这句话发给模型,界面不画成人的气泡、不当会话标题。
400
+ * 只在人点了卡片上的按钮时调(「继续」「重试这一步」),不拿来替人说别的。
401
+ */
402
+ carryOn(text: string): void;
403
+ }
404
+ export interface ComposerChipOptions {
405
+ /** `start` 排在项目签后面,`end` 靠右。默认 `start`。 */
406
+ side?: "start" | "end";
407
+ order?: number;
408
+ }
409
+ /**
410
+ * 侧栏一行会话行首的记号(14px 的状态槽)。在跑、未读由产品画,盖过插件的记号;空闲时才问插件。
411
+ * 不是自己要说的会话原样返回 `fallback`(下一个插件的记号,最里层是产品的空心圈)。图标 11px 左右、颜色用淡字,悬停说明经 `data-plume-tip`。
412
+ */
413
+ export interface SessionMarkProps {
414
+ session: SessionSummary;
415
+ fallback: ReactNode;
416
+ }
417
+ /** 提示条的轻重:`info` 留得短,`warn`、`error` 留得长些、颜色不同。 */
418
+ export type NotifyLevel = "info" | "warn" | "error";
419
+ /**
420
+ * 侧栏行首说的、会话摘要里没有的事:`waiting` 是它或它的子会话停下来等人批准,`done`、`failed` 是在人没看着时跑完、没跑完
421
+ * (出错、跑到上限、卡住)而人还没打开看。人按停的、看着跑完的不留记号;在跑看摘要的 `running`。
422
+ */
423
+ export type SessionActivity = "waiting" | "done" | "failed";
424
+ export interface SettingsSectionOptions {
425
+ /**
426
+ * 这一节的标题:插件详情里「设置」下面的小标题;单独占导航一行时是那一行的字和页头标题。放进产品的页面里时只当无障碍名,
427
+ * 页面上的小标题由组件自己画;`general`、`session-models` 例外,它是那一行的名字。
428
+ */
429
+ title: LocalizedText;
430
+ /** 小标题或页头标题下面的一段介绍;`general`、`session-models` 是那一行名字下面的一句说明。 */
431
+ detail?: LocalizedText;
432
+ /** 导航那一行的图标,颜色跟着文字走(currentColor);不给用产品的默认图标。只在 `page: "nav"` 时画。 */
433
+ icon?: ComponentType<{
434
+ size?: number;
435
+ className?: string;
436
+ }>;
437
+ order?: number;
438
+ /**
439
+ * `page: "nav"` 时排在导航哪一组,组里按 `order` 排;不是 `nav` 时给了算错:
440
+ * - 不给是「基本」组,排在产品自己那几行后面;
441
+ * - `agent` 是「Agent 能力」组,排在「智能体」后面。给的是管 Agent 能做什么的页(命令、钩子、网页搜索);
442
+ * - `data` 是「数据」组,排在「存储」前面。给的是读写本机数据的页(符号索引、使用统计);
443
+ * - `vcs` 是「代码与版本控制」组。给的是管仓库、工作树的页(工作树)。
444
+ */
445
+ group?: "agent" | "data" | "vcs";
446
+ /**
447
+ * 画在哪。不给时画进这个插件的详情(「插件市场」里点开它看到的那一页)的「设置」一节:只和这个插件有关的
448
+ * 选项放这里,不占设置导航。用户不管装了哪个插件、都会到设置里直接找的功能才另给位置:
449
+ * - `nav` 单独占设置导航的一行(使用统计这类),页头由产品按 `title`、`detail` 画;
450
+ * - `extensions-skills`、`extensions-connectors` 是「插件市场」页的「技能」「连接器」两类,画在分类标签下面,整节由组件自己画。
451
+ * 给的是管技能、MCP 连接器的插件:装了哪些、开着没有、配好没有,和还能装什么放在一处看。
452
+ * - `general` 是「常规」页「常规」那张卡里的一行,排在「显示思考过程」后面:名字和说明由产品按 `title`、`detail` 画,
453
+ * 组件只画右边的控件(通常是一个 `Toggle`)。给的是随应用发、不能停用的插件自己的开关(智能标题总结)。
454
+ * - `personalization` 是「个性化」页,画在「全局指令」和「语气」之间。给的是和那一页说的是同一件事的东西(比如记忆)。
455
+ * - `agents` 是「智能体」页,画在页头下面、「会话」一组上面,整节由组件自己画(子智能体的名单)。
456
+ * - `session-models` 是「智能体」页「会话」那张卡里的一行:名字和说明由产品按 `title`、`detail` 画,组件只画右边的控件
457
+ * (通常是一个 `ModelSelect`),给某个功能选用哪个模型。
458
+ * 「智能体」页只在有插件往里画东西时出现在导航里。给了位置的,插件详情里有一个去那里的入口。
459
+ */
460
+ page?: "nav" | "general" | "personalization" | "agents" | "session-models" | "extensions-skills" | "extensions-connectors";
461
+ }
462
+ /**
463
+ * 产品的模型下拉:和输入框旁的模型菜单是同一份列表(常用、按供应商分组、搜索),最前面多一项「跟随」。
464
+ * 只列可用的模型,不经手密钥。选了不改哪个会话,只把选中的模型 id(`SessionModel.id`)交给 `onChange`,选「跟随」给空串。
465
+ */
466
+ export interface ModelSelectProps {
467
+ /** 选中的模型 id;空串是跟随。 */
468
+ value: string;
469
+ onChange(modelId: string): void;
470
+ ariaLabel: string;
471
+ /** 「跟随」那一项的名字(「跟随主会话」)。 */
472
+ inheritLabel: string;
473
+ /** 「跟随」那一项下面的小字,也进悬停提示。 */
474
+ inheritDetail?: string;
475
+ /** 跟随时实际会用的模型;给了就在框里写它的名字,后面跟着 `inheritedSource`。 */
476
+ inheritedModelId?: string;
477
+ /** 跟随时写在模型名后面的来源(「随主会话」「默认」)。 */
478
+ inheritedSource?: string;
479
+ disabled?: boolean;
480
+ /**
481
+ * 只剩一枚箭头,贴在它管的那颗按钮旁边当分体按钮(计划卡上的「在新会话里执行」):窄处装不下一个带名字的选择。
482
+ * 选了什么由那颗按钮自己说,悬停提示说全名。
483
+ */
484
+ compact?: boolean;
485
+ }
486
+ /** 「跟随」时会落到哪个模型上,给设置页的下拉算继承的那一项。 */
487
+ export interface ModelDefaults {
488
+ /** 新会话的默认模型;一个可用的都没有时为空。 */
489
+ defaultModel?: string;
490
+ /** 当前打开的会话的模型;没打开会话时是默认模型。 */
491
+ sessionModel?: string;
492
+ /** 新会话的思考档位(设置 › 常规的默认推理强度)。 */
493
+ thinking: ThinkingLevel;
494
+ }
495
+ /** 登记过的项目。 */
496
+ export interface ProjectInfo {
497
+ id: string;
498
+ name: string;
499
+ path: string;
500
+ }
501
+ /** 屏幕上的一块矩形,逻辑像素。 */
502
+ export interface ScreenRect {
503
+ x: number;
504
+ y: number;
505
+ width: number;
506
+ height: number;
507
+ }
508
+ /**
509
+ * 截屏这件事里插件自己做不到的部分:拍屏幕、开盖住整块屏幕的窗口、钉在桌面上的窗口、系统剪贴板、全局快捷键。
510
+ * 这些只有主进程能做,宿主做;选区、标注、工具栏、设置由插件画(`screenOverlay`、`pinnedShot`、`settingsSection`)。
511
+ */
512
+ export interface ScreenCapture {
513
+ /**
514
+ * 拍下指针所在的那块屏幕,铺一层盖住它的浮层,浮层里画 `screenOverlay` 注册的组件。没有注册浮层组件时报错。
515
+ * macOS 没给屏幕录制权限时弹出系统的授权提示,这一次不开浮层,返回 false。
516
+ */
517
+ start(): Promise<boolean>;
518
+ /**
519
+ * 全局快捷键(Electron accelerator 的写法,如 `Alt+A`):Plume 不在前面也收得到,按下等于 `start()`。
520
+ * 传 null 取消。同一个插件只有一个,后设的替换先设的。被别的程序占了是 `taken`,写法不认识是 `invalid`。
521
+ */
522
+ setShortcut(accelerator: string | null): Promise<"ok" | "taken" | "invalid">;
523
+ /** 系统的选文件夹对话框(保存位置用);取消是 null。 */
524
+ pickDirectory(title: string): Promise<string | null>;
525
+ /** 系统桌面文件夹的路径:没设保存位置时存到这里。 */
526
+ desktopDirectory(): Promise<string>;
527
+ }
528
+ /** 一次截屏:浮层每开一次换一个 id,组件随之重新挂上。 */
529
+ export interface ScreenCaptureSession {
530
+ id: number;
531
+ /** 整块屏幕的快照,物理像素,RGBA 逐行排。 */
532
+ snapshot: {
533
+ pixels: Uint8ClampedArray;
534
+ width: number;
535
+ height: number;
536
+ };
537
+ /** 这块屏幕在全局坐标里的位置和大小,逻辑像素。浮层窗口正好盖住它,组件里的坐标都从它的左上角算。 */
538
+ bounds: ScreenRect;
539
+ /** 物理像素 / 逻辑像素。 */
540
+ scaleFactor: number;
541
+ /** 快照的色彩空间,画到 canvas 上要用同一个,颜色才不偏。 */
542
+ colorSpace: "srgb" | "display-p3";
543
+ /** 开始时指针在哪,相对 `bounds` 的左上角。 */
544
+ cursor: {
545
+ x: number;
546
+ y: number;
547
+ };
548
+ }
549
+ export interface ScreenOverlayProps {
550
+ session: ScreenCaptureSession;
551
+ /** 背景画好了。宿主这时才把浮层亮出来:先亮再画,屏幕会闪一下空白。 */
552
+ ready(): void;
553
+ /** 完成:浮层收起,Plume 回到前面(从 Plume 里发起的话)。给了 png(data URL)就放进剪贴板。 */
554
+ finish(png?: string): Promise<void>;
555
+ /** 不截了:浮层收起,焦点还给截屏前的窗口。 */
556
+ cancel(): void;
557
+ /** 把一张图钉在桌面上:浮层收起,在 `at`(全局坐标)开一个置顶的小窗口,里面画 `pinnedShot` 注册的组件。 */
558
+ pin(png: string, at: ScreenRect): Promise<void>;
559
+ /** 只放进剪贴板,浮层不收。 */
560
+ copy(png: string): Promise<void>;
561
+ /** 浮层暂时让鼠标点到底下去,Esc 也不再拦(浮层上只剩一条提示的时候)。 */
562
+ passThrough(on: boolean): void;
563
+ /** 订阅 Esc。截屏期间宿主注册了全局的 Esc,浮层没拿到焦点也收得到。返回的函数取消订阅。 */
564
+ onEscape(listener: () => void): () => void;
565
+ }
566
+ export interface PinnedShotProps {
567
+ /** 钉住的图,PNG data URL;宽高是逻辑像素,也是窗口的大小。 */
568
+ image: {
569
+ src: string;
570
+ width: number;
571
+ height: number;
572
+ };
573
+ /** 窗口准备好了(图画上了),宿主这时才显示它。 */
574
+ ready(): void;
575
+ close(): void;
576
+ /** 拖窗口:按下时调 dragStart,之后每次移动给出离按下点的偏移(屏幕坐标)。 */
577
+ dragStart(): void;
578
+ dragMove(dx: number, dy: number): void;
579
+ }
580
+ /** 浅色、深色分别覆盖哪些 token,值是 CSS 值;没写的沿用默认。 */
581
+ export interface Skin {
582
+ /** 数据皮肤的显示名;与 mode 一起提供时接管配色,外观页只读展示,停用后恢复用户偏好。 */
583
+ name?: string;
584
+ /** 临时覆盖应用深浅模式,不改写用户保存的主题偏好;system 跟随系统。不提供 token 时使用产品默认配色。 */
585
+ mode?: "system" | "light" | "dark";
586
+ light?: Partial<Record<SkinToken, string>>;
587
+ dark?: Partial<Record<SkinToken, string>>;
588
+ }
589
+ /** 已结束的最新一轮回复下面的扩展;跟随转录滚动,开始新一轮时撤下。 */
590
+ export interface TurnFooterProps {
591
+ session: SessionView;
592
+ /** 这一轮最后一条回复的时间戳。 */
593
+ timestamp: number;
594
+ }
595
+ /**
596
+ * 一轮收尾那条回复底下那一排操作(时间、复制、分叉)里的一个按钮,每一轮都有,不只最新一轮。
597
+ * `from` 是这一轮开口的那条消息在会话里的位置,`to` 是收尾那条回复的位置加一:插件按自己记下的消息位置挑出归这一轮的东西。
598
+ */
599
+ export interface ReplyActionProps {
600
+ sessionId: string;
601
+ from: number;
602
+ to: number;
603
+ }
604
+ export interface FileDiffProps {
605
+ hunks: ChangeHunk[];
606
+ path?: string;
607
+ showPath?: boolean;
608
+ maxLines?: number;
609
+ }
610
+ export interface FilePreviewProps {
611
+ sessionId: string;
612
+ path: string;
613
+ /** 插件通过自己的 remote 读取的文件,不扩大宿主的文件读取权限。 */
614
+ contents: FileContents;
615
+ }
616
+ /** 只读文档的数据由调用方读取;预览插件不接收磁盘路径,也不取得调用方的目录权限。 */
617
+ export interface DocumentPreviewProps {
618
+ name: string;
619
+ /** 文件或版本变化时换这个值,取消旧读取并重建预览。 */
620
+ identity: string;
621
+ readBytes(signal: AbortSignal): Promise<Uint8Array>;
622
+ fallback?: ReactNode;
623
+ }
624
+ export interface FileMenu {
625
+ open: boolean;
626
+ onContextMenu(event: MouseEvent, target: {
627
+ path: string;
628
+ onOpen?: () => void;
629
+ }): void;
630
+ element: ReactNode;
631
+ }
632
+ /** 只在人点击明确的按钮时打开空白对话并准备草稿,不发送、不创建会话记录。 */
633
+ export interface ConversationDraft {
634
+ /** 已登记项目的 id;与 cwd 二选一。 */
635
+ project?: string;
636
+ /** 没有本地项目时,逻辑入口准备好的工作目录的绝对路径。 */
637
+ cwd?: string;
638
+ text: string;
639
+ }
640
+ /** 一段引用保留正文及说话者,不携带 DOM。 */
641
+ export interface DraftQuote {
642
+ id: string;
643
+ text: string;
644
+ from: "user" | "assistant";
645
+ }
646
+ export interface QuoteAction {
647
+ label: LocalizedText;
648
+ run(quote: DraftQuote, sessionId: string): void | Promise<void>;
649
+ }
650
+ export interface SessionChange {
651
+ sessionId: string;
652
+ type: "messages" | "summary" | "deleted";
653
+ tools?: string[];
654
+ }
655
+ /** 插件在 `@` 菜单里提供的一项,选中只插入 token,不会自动发送。 */
656
+ export interface ComposerMention {
657
+ id: string;
658
+ title: string;
659
+ description?: string;
660
+ origin?: string;
661
+ kind: "subagent" | "plugin";
662
+ token: string;
663
+ avatar?: string;
664
+ }
665
+ export interface UiContext {
666
+ quoteAction(action: QuoteAction): void;
667
+ /** 追加到当前可见的同插件面板,或开新标签;保留草稿,不自动发送。 */
668
+ quoteInPanel(panelId: string, sessionId: string, quote: DraftQuote): void;
669
+ /** 仅接受当前真实点击,与主输入框的停止相同。 */
670
+ stopSession(sessionId: string, event: MouseEvent): Promise<void>;
671
+ onSessionsChanged(listener: (event: SessionChange) => void): () => void;
672
+ openMediaFile(name: string, sessionId: string): Promise<void>;
673
+ revealMediaFile(name: string): Promise<void>;
674
+ revealMediaLabel(): string;
675
+ ComposerSend: ComponentType<{
676
+ running: boolean;
677
+ disabled?: boolean;
678
+ tip?: string;
679
+ onSend(): void;
680
+ onStop(event: MouseEvent<HTMLButtonElement>): void;
681
+ }>;
682
+ /** 文件树等入口打开终端;处理器只在用户操作时运行。 */
683
+ terminalOpener(open: (directory: string, sessionId: string) => void | Promise<void>): void;
684
+ /**
685
+ * 回复里 shell 代码块的「在终端运行」:人点击后调用 `run(command, sessionId)`,`command` 已去掉提示符(`$ `、`> `)和注释行,
686
+ * 要原样执行;`sessionId` 是代码块所在的会话。登记和没有处理器时的提示同 `terminalOpener`。
687
+ */
688
+ terminalRunner(run: (command: string, sessionId: string) => void | Promise<void>): void;
689
+ /** 会话标题栏的局部控件;只在有会话时显示,组件不能接管标题或布局。 */
690
+ sessionToolbar(id: string, component: ComponentType<{
691
+ session: SessionView;
692
+ }>): void;
693
+ /** 会话菜单中的操作,点击后调用;没有会话时不显示。 */
694
+ sessionMenuItem(id: string, item: {
695
+ label: LocalizedText;
696
+ icon?: ComponentType<{
697
+ size?: number;
698
+ }>;
699
+ run(session: SessionSummary): void | Promise<void>;
700
+ }): void;
701
+ /** 运行时送达行的查看入口;后注册者生效,停用时恢复前一个。 */
702
+ deliveryAction(kind: "job", run: (sessionId: string, id: string) => void): void;
703
+ /**
704
+ * 本插件的子会话交回的结果(`ctx.sessions.report` 带了 `delivery` 的)在对话里画成哪一行:一次送达里本插件交的几份一起交给它,
705
+ * 画成一行。只画自己交的那几份,别的插件交的由它们自己登记的组件画;同一插件再登记换掉前一个,停用时撤下,没登记时不画。
706
+ */
707
+ agentDelivery(component: ComponentType<AgentDeliveryProps>): void;
708
+ /** 当前项目的系统打开方式;复用文件预览的默认目标和菜单。 */
709
+ readonly ProjectOpener: ComponentType<{
710
+ path: string;
711
+ }>;
712
+ readonly name: string;
713
+ /**
714
+ * 人明确选择入口时在主窗口打开一个会话,和点侧栏里那一行一样;不会自动发送,不替人换屏(只在人点了插件界面上的按钮时调,
715
+ * 如「打开上次会话」打开插件经 `ctx.sessions.launch` 开出来的会话)。没有的会话抛错。
716
+ */
717
+ openSession(sessionId: string): Promise<void>;
718
+ /** 按围栏语言(忽略大小写)接管回复正文代码块;order 和撤销规则同 toolCard,解析失败返回 fallback。 */
719
+ codeBlock(language: string, component: ComponentType<CodeBlockProps>, options?: {
720
+ order?: number;
721
+ /** 复制成功完成的助手回复时现取可读文字;undefined 或抛错保留源码。不改变显示或存储。 */
722
+ copyText?: (block: Pick<CodeBlockProps, "code" | "sessionId">) => string | undefined;
723
+ }): void;
724
+ /**
725
+ * order 小的生效,默认 0;同一 order 后注册的生效。精确工具名优先于 match: "prefix" 的前缀匹配,撤下后恢复前一个。
726
+ * 登记了卡片的调用在转录里单独一行;`inline: true` 的卡片只在通用卡片上补东西(多半直接返回 `fallback`),调用照常按归类
727
+ * 并进一段活,它那一行(单独一次时、展开一段活后)由这张卡画。
728
+ */
729
+ toolCard(tool: string, component: ComponentType<ToolCardProps>, options?: {
730
+ order?: number;
731
+ match?: "tool" | "prefix";
732
+ inline?: boolean;
733
+ }): void;
734
+ /**
735
+ * 转录里怎么说自己的工具:通用卡片那一行、合成一段活的那一行、运行行,见 `ToolLine`。只改说法和归类,画法照通用卡片;
736
+ * 同时登记了 `toolCard` 的,卡片单独一行(`inline` 的照常并进一段活),`fallback` 用这里的说法。同一工具后登记的生效,它撤下后前一个恢复;插件登记的
737
+ * 优先于产品给内置工具的说法。
738
+ */
739
+ toolLine(tool: string, line: ToolLine): void;
740
+ /**
741
+ * 给自己的工具画审批卡,见 `ApprovalCardProps`。`tool` 是 `ApprovalRequest.tool`;order 和让位规则同 `toolCard`:
742
+ * 渲染出错时让给下一个,都不行用产品的通用卡。
743
+ * `match: "kind"` 时第一个参数对的是 `ApprovalRequest.kind`:工具名不固定、一类问题从几个工具里问出来时用(MCP 服务
744
+ * 中途要人填的表单,问它的是哪个 `mcp__…` 工具都有可能)。同一次请求两种都对得上时,按工具名登记的在前。
745
+ */
746
+ approvalCard(tool: string, component: ComponentType<ApprovalCardProps>, options?: {
747
+ order?: number;
748
+ match?: "tool" | "kind";
749
+ }): void;
750
+ /**
751
+ * 往工作区加一个面板,标签按会话保留,宽度和收起偏好在窗口内共享。
752
+ * 全屏按会话保存,盖满工作区;窄窗口也盖满工作区,正文和面板放不下横排时上下排列。
753
+ * 面板区顶上一排标签,每个开着的面板一个;点「+」开一个开始页标签,上面每个面板一张卡片,按 order 从小到大排(默认 0,相同时按注册先后),点卡片这个标签就变成那个面板。
754
+ * id 在插件内唯一。标题、说明给函数的,产品每次按当前界面语言调用它;只给一个字符串就哪种语言都显示它。
755
+ */
756
+ panel(id: string, component: ComponentType<PanelProps>, options: PanelOptions): void;
757
+ /**
758
+ * 往侧栏的去处里加一个页面:侧栏一行,点了正文区整块换成这个页面。按 order 从小到大排(默认 0,相同时按注册先后),
759
+ * 都排在产品自己的「插件」前面。id 在插件内唯一;标题给函数的,产品每次按当前界面语言调用它。
760
+ */
761
+ page(id: string, component: ComponentType<PageProps>, options: PageOptions): void;
762
+ /** 换皮肤:可重复调用更新,null 撤下自己的皮肤;最后注册的生效,撤下后前一个恢复。 */
763
+ skin(skin: Skin | null): void;
764
+ /** 登记界面入口的订阅清理;停用、重载或加载失败时执行,旧入口不能再注册皮肤。 */
765
+ effect(dispose: () => void): void;
766
+ /**
767
+ * 输入框底下那排控件加一格:`start` 在左边,排在产品自己的「添加附件」和权限后面;`end` 在右边,排在模型选择前面
768
+ * (上下文用量这类读数)。各自按 order 从小到大(默认 0,相同时按注册先后)。
769
+ * 组件自己画按钮(`@plume/ui` 的 `IconButton`,`size="composer"`),这一格不该显示时返回 null。id 在插件内唯一。
770
+ */
771
+ composerItem(id: string, component: ComponentType<ComposerItemProps>, options?: ComposerItemOptions): void;
772
+ /**
773
+ * 输入框上方、项目签那一行加一格:`start` 跟在项目签后面,`end` 靠右,各自按 order 从小到大(默认 0,相同时按注册先后)。
774
+ * 组件自己画,高度用 `plume-composer-control`;这一格不该显示时返回 null。id 在插件内唯一。
775
+ */
776
+ composerChip(id: string, component: ComponentType<ComposerChipProps>, options?: ComposerChipOptions): void;
777
+ /** 主输入框上方独占一行;返回 null 不占位,按 order 排列,组件自己管理展开和退场。 */
778
+ composerAbove(id: string, component: ComponentType<ComposerAboveProps>, options?: {
779
+ order?: number;
780
+ }): void;
781
+ /**
782
+ * 跟着会话的一张卡片:一直在变的一件事(todo 清单做到哪了),不是转录里的又一条记录,所以不随消息滚走。
783
+ * 对话那一列放得下它(320px 的卡片之外还剩 420px 正文)时浮在转录右上角,放不下时在输入框正上方,经 `placement` 告诉组件。
784
+ * 按 order 从小到大(默认 0,相同时按注册先后);没什么可说时返回 null,不占地方。只画开着的会话,新对话不画。id 在插件内唯一。
785
+ *
786
+ * `lane: true` 的卡片(环境卡片)占右边 300px 宽的一列,从不放到输入框上方:对话那一列让出 324px 后正文还有 520px 时停靠,
787
+ * 转录和输入框整体往左让、卡片不盖住字;不够时浮在转录右上角。这一列从顶到转录底,卡片太长要自己滚(`max-height: 100%`、
788
+ * `min-height: 0`,正文 `overflow-y: auto`)。这一列有卡片时,别的卡片浮得下就排到它下面,浮不下照旧在输入框上方。
789
+ */
790
+ conversationCard(id: string, component: ComponentType<ConversationCardProps>, options?: {
791
+ order?: number;
792
+ lane?: boolean;
793
+ }): void;
794
+ /**
795
+ * 往会话的环境卡片里加一节(卡片由运行诊断插件画):和这个会话相关的一件周边的事,比如当前分支的拉取请求,每一行都只是入口,
796
+ * 点了去插件自己的页面或面板。没什么可说时返回 null,卡片不留空位,也不画分隔线。`label` 是卡片「显示哪些内容」菜单里的名字。
797
+ * 按 order 从小到大排进卡片自己的几节之间(默认 0)。id 在插件内唯一,停用时撤下。
798
+ *
799
+ * `attention` 是一个 React hook:这一节此刻有没有等人处理的事(建议的新会话还没人决定),有就返回一句给人看的话(按界面语言,
800
+ * 「2 条建议的新会话等你决定」),没有返回 undefined。卡片收着、这一节没被藏起来时,标题栏上开关卡片的那颗挂一个圆点,这句话
801
+ * 接在它的说明后面。只为提醒人回来做决定,不为「有东西在跑」——那样圆点会一直亮着。规则同 React 的 hook。
802
+ */
803
+ environmentSection(id: string, component: ComponentType<EnvironmentSectionProps>, options: {
804
+ label: LocalizedText;
805
+ order?: number;
806
+ attention?: (session: SessionView) => string | undefined;
807
+ }): void;
808
+ /** React hook:各插件登记的环境卡片分区,按 order 排好,给画环境卡片的插件用;增减跟着变。只在组件里调。 */
809
+ useEnvironmentSections(): readonly EnvironmentSectionEntry[];
810
+ /**
811
+ * 输入框空着时的灰字建议(下一步想说什么),按 Tab 整段填进去,人看过再自己发。宿主画输入框时按注册先后问,
812
+ * 取第一个给出字的;只问开着的会话,新对话不问。返回空串或 undefined 表示这次没有建议。
813
+ * 只在渲染时同步调,别在里面做耗时的事。一个插件只能有一个,再注册换掉上一个。
814
+ */
815
+ /** 每次打开 `@` 时列出当前目录可用的引用;停用后自动撤销,一个插件一份。 */
816
+ mentions(provider: (context: {
817
+ cwd?: string;
818
+ sessionId?: string;
819
+ }) => ComposerMention[] | Promise<ComposerMention[]>): void;
820
+ composerHint(hint: (session: SessionView) => string | undefined): void;
821
+ /**
822
+ * 画回复的正文、复制回复之前,把字过一遍:插件让模型在回复里顺带写的标记(下一步建议的 `:followup[…]`)从这里拿掉。
823
+ * 只改显示和复制,会话里存的、下一轮发给模型的都不变。正在生成的回复也会过,写了一半的标记也该拿掉。
824
+ * 按注册先后串起来调;抛错的那一个跳过。一个插件只能有一个,再注册换掉上一个。
825
+ */
826
+ replyText(transform: (text: string) => string): void;
827
+ /**
828
+ * 在窗口顶上弹一条提示,过一会儿自己消失,悬停时不走。说的是刚才那一下的结果(操作失败、导出好了),
829
+ * 不是一直存在的状态;同样的话连着说几次合成一条。
830
+ */
831
+ notify(message: string, level?: NotifyLevel): void;
832
+ /**
833
+ * 打开自己注册的面板 `id`,和按它的快捷键一样:开着就切过去,没开就新开一个标签,面板区收着就展开(只展开开着的那个会话的)。
834
+ * 能开好几个的面板给了 `tab`:开的是 id 为它的那个标签,没有就用这个 id 新开一个(id 要全局唯一,用 `crypto.randomUUID()`)。
835
+ * `background`:只加标签、不切过去、不展开面板区(网页自己开的新窗口)。
836
+ */
837
+ openPanel(id: string, sessionId?: string, options?: {
838
+ tab?: string;
839
+ background?: boolean;
840
+ }): void;
841
+ /** 关闭自己在该会话打开的面板,仍经过该面板的 onClose;给了 `tab` 只关那一个标签。 */
842
+ closePanel(id: string, sessionId?: string, tab?: string): void;
843
+ /**
844
+ * 在指定会话的文件面板打开已有文件,读取仍受该会话的文件边界约束;唯一的例外是这个会话最近一次请求的「记忆文件」
845
+ * (`PromptSection.files` 标的项目指令、项目记忆来源),在边界外也能只读打开。
846
+ */
847
+ openFile(path: string, sessionId: string): Promise<void>;
848
+ /**
849
+ * 纯文字里印出来的一条路径(终端输出、日志)在这个会话里指的那个文件,返回绝对路径。绝对路径看它在不在;相对路径先按会话工作目录、
850
+ * 项目源文件夹拼,不在就按结尾找,只认唯一的一个。不存在、不止一个、是文件夹、在会话文件边界外都是 null;答出来的 `openFile` 打得开。
851
+ */
852
+ findFile(path: string, sessionId: string): Promise<string | null>;
853
+ /**
854
+ * 一次拖放带着的本机绝对路径:访达里拖来的文件、文件面板里拖的行。不带路径的拖动是 null。
855
+ * 在 drop 处理函数里同步调,它返回后就读不到了;dragover 时浏览器不给读内容,带路径也只答空数组。
856
+ */
857
+ droppedPaths(transfer: DataTransfer): string[] | null;
858
+ /** 产品的文件右键菜单;root 用于复制相对路径,hook 只在组件里调用。 */
859
+ useFileMenu(root: string): FileMenu;
860
+ /** 产品的语法高亮 diff 和文件预览;插件不需要另带一套代码渲染器。 */
861
+ readonly FileDiff: ComponentType<FileDiffProps>;
862
+ readonly FilePreview: ComponentType<FilePreviewProps>;
863
+ /** 按扩展名注册只读预览;同扩展名后注册的生效,撤下后恢复前一个。 */
864
+ documentViewer(extensions: readonly string[], component: ComponentType<DocumentPreviewProps>): void;
865
+ /** 复用已注册的文档预览;无匹配或渲染失败时显示 fallback。 */
866
+ readonly DocumentPreview: ComponentType<DocumentPreviewProps>;
867
+ /** 最新一轮结束后跟着回复的卡片。每个组件有独立错误边界,返回 null 不占位。 */
868
+ turnFooter(id: string, component: ComponentType<TurnFooterProps>, options?: {
869
+ order?: number;
870
+ }): void;
871
+ /**
872
+ * 回复底下那一排操作里加一个按钮,见 `ReplyActionProps`。排在复制和分叉之间,几个插件按 `order`;组件返回 null 不占位,
873
+ * 每个有独立错误边界。这一排悬停才显出来、行高 24,按钮不要高过它(`IconButton` 默认尺寸),点开的东西用 `Popover`。
874
+ */
875
+ replyAction(id: string, component: ComponentType<ReplyActionProps>, options?: {
876
+ order?: number;
877
+ }): void;
878
+ /**
879
+ * 侧栏会话行首的记号,见 `SessionMarkProps`。几个插件都注册时按注册先后套起来,先注册的在外层。一个插件只能有一个,再注册换掉上一个。
880
+ */
881
+ sessionMark(component: ComponentType<SessionMarkProps>): void;
882
+ /**
883
+ * 删除确认框里补一句话:删掉这个会话会连带什么、会留下什么(工作树:没提交的文件留在哪、没合并的分支留着)。
884
+ * 确认框打开前问各插件,最多等 600ms,没答上来、返回空、抛错的不写;按注册先后接在产品那句后面。`locale` 是当前界面语言,按它选自己的文案。
885
+ * 一个插件只能有一个,再注册换掉上一个。
886
+ */
887
+ deleteNote(note: (sessionId: string, locale: Locale) => string | undefined | Promise<string | undefined>): void;
888
+ /**
889
+ * 回复里的网址、文件签多一种打开方式,见 `LinkOpener`。几个插件都注册时按注册先后排,点网址时第一个 `takesClicks` 的接手。
890
+ * 一个插件只能有一个,再注册换掉上一个。
891
+ */
892
+ linkOpener(opener: LinkOpener): void;
893
+ /**
894
+ * 主输入框排队条上,每条排着的消息「更多」菜单里多一项,见 `QueueAction`;排在产品自己的「编辑」后面,几个插件按注册先后。
895
+ * 没有插件登记时排队条直接放「编辑」按钮,不出菜单。一个插件只能有一个,再注册换掉上一个。
896
+ */
897
+ queueAction(action: QueueAction): void;
898
+ /** 用户点击时打开目标项目/目录的空白对话,已有草稿原样保留并追加 text;仍由人按发送。 */
899
+ openConversationDraft(options: ConversationDraft): Promise<void>;
900
+ /**
901
+ * 往输入框里放字:把字接在草稿后面(原来有字时空一行;`replace` 时换掉整段草稿)、`images` 作为附件挂上、标记落在最后,
902
+ * 光标移进去,人看过再自己发。给了 `sessionId` 先打开这个会话、放进它的输入框,打不开(删掉了)时抛错;
903
+ * 不给就放进眼前的输入框(当前对话,或还没发消息的新对话),不换会话。面板窗口里调用交给主窗口,只能交给面板来源的会话
904
+ * (不给 `sessionId` 也是它),给别的会话抛错。
905
+ * `send` 是人点了按钮、按了回车要直接发出去:只在人真的刚点过(浏览器的用户激活还在)且输入框原本是空的时发,
906
+ * 人写了一半的话不跟着发,照草稿留着等人自己发;没人点时只放进草稿。新对话就此开出会话。
907
+ */
908
+ draftInSession(sessionId: string | undefined, draft: SessionDraft): Promise<void>;
909
+ /**
910
+ * 打开这个会话,转录滚到这次工具调用的卡片(放在中间),卡片外层闪一下(带上 `data-plume-flash`,插件的样式按它画,
911
+ * 动画结束或两秒多以后撤掉)。会话还没读完时等它读完;打不开时抛错。
912
+ */
913
+ revealToolCall(sessionId: string, toolCallId: string): Promise<void>;
914
+ /**
915
+ * 会话媒体目录里的一张图(`ImageContent.media`、`ctx.media.save` 交回的名字)的地址,给 `<img src>` 用。名字不对时是空串。
916
+ * 给了 `thumb` 时是长边缩到这么多像素的缩略图(宿主算一次、存在盘上;原图不比它大时就是原图),格子、列表里用它,看图、另存用原图。
917
+ */
918
+ mediaUrl(name: string, thumb?: number): string;
919
+ /**
920
+ * 用产品的看图器看几张图:从 `from` 那个元素的位置飞出来、关上时飞回去;`edit` 时打开就进入标注。
921
+ * 标注完按「完成」,带标注的副本交给那张图的 `onAttach`(`data:` URL),没给 `onAttach` 的复制到剪贴板。
922
+ */
923
+ openImage(images: ViewerImage[], index: number, options?: {
924
+ from?: HTMLElement | null;
925
+ edit?: boolean;
926
+ }): void;
927
+ /** 弹保存对话框把一张图存到磁盘,和看图器的「另存为」一样;`src` 是 `data:` 或 `mediaUrl` 的地址。人取消了不算失败。 */
928
+ saveImage(src: string): Promise<void>;
929
+ /** 把一张图放进剪贴板(转成 PNG),和看图器的「复制」一样;剪贴板不接时退回存文件。`src` 同 `saveImage`。 */
930
+ copyImage(src: string): Promise<void>;
931
+ /** 截取本插件界面所在窗口的可见矩形(CSS 像素),临时隐藏浮动导航/通知/提示,返回 PNG data URL;不能读取其他窗口。 */
932
+ captureWindow(rect: {
933
+ x: number;
934
+ y: number;
935
+ width: number;
936
+ height: number;
937
+ }): Promise<string>;
938
+ /** 打开本插件注册的、单独占导航一行(`page: "nav"`)的设置分区,不接受其他插件或产品设置的地址。 */
939
+ openSettings(id: string): void;
940
+ /** 打开本插件注册的页面,和点侧栏去处里那一行一样;不接受别的插件的页面。只在人点了按钮时调(输入框上方提示条的「查看」)。 */
941
+ openPage(id: string): void;
942
+ /**
943
+ * 侧栏去处里本插件那一页的那一行右端挂一个数(有东西在等人看:没人看见的失败)。`null` 或 0 拿掉;人正在那一页上时不画。
944
+ * `label` 说这个数是什么意思,给读屏和悬停提示。`attention` 为 true 时也列进通知菜单。只能挂本插件注册的页面;插件停用时一起拿掉。
945
+ */
946
+ pageBadge(id: string, badge: {
947
+ count: number;
948
+ label: LocalizedText;
949
+ attention?: boolean;
950
+ } | null): void;
951
+ /** 用户点击时在系统浏览器打开 HTTP(S) 链接,不允许凭据或其他协议。 */
952
+ openExternal(url: string): Promise<void>;
953
+ /**
954
+ * 像人点了回复里的网址那样打开 HTTP(S) 链接:有插件接手点击(`LinkOpener.takesClicks`,比如内置浏览器)时开在它那里,否则系统浏览器。
955
+ * `sessionId` 是链接所在的会话;规则同 `openExternal`,只在用户点击时调。
956
+ */
957
+ openLink(url: string, sessionId: string | undefined): Promise<void>;
958
+ /** 加一节设置,默认画进本插件的详情,`options.page` 改放到设置导航或产品的某一页;同一处按 order 从小到大。id 在插件内唯一。 */
959
+ settingsSection(id: string, component: ComponentType, options: SettingsSectionOptions): void;
960
+ /** 截屏用的宿主能力,见 `ScreenCapture`。 */
961
+ readonly screen: ScreenCapture;
962
+ /** 截屏浮层里画的组件。同一时间只有一个,后注册的生效,它撤下后前一个恢复。 */
963
+ screenOverlay(component: ComponentType<ScreenOverlayProps>): void;
964
+ /** 钉在桌面上的那个小窗口里画的组件。同一时间只有一个,后注册的生效,它撤下后前一个恢复。 */
965
+ pinnedShot(component: ComponentType<PinnedShotProps>): void;
966
+ /**
967
+ * React hook:一个会话的视图,随它的事件更新(消息、草稿、进度、审批);还没读到、会话不在了是 undefined。
968
+ * 子 Agent 的卡片拿它画子会话的进度。只在组件里调,规则同 React 的 hook。
969
+ */
970
+ useSession(sessionId: string | undefined): SessionView | undefined;
971
+ /**
972
+ * React hook:侧栏行首给这个会话的记号,见 `SessionActivity`;人打开那个会话后,`done`、`failed` 就清掉(看过了),没有记号是 undefined。
973
+ * 只在内存里,重开应用后都算看过。只在组件里调,规则同 React 的 hook。
974
+ */
975
+ useSessionActivity(sessionId: string): SessionActivity | undefined;
976
+ /**
977
+ * 这个会话的上下文窗口用到哪儿了:对话消息、工具表、系统提示词、项目指令、项目记忆各占多少,项目指令和项目记忆来自哪几个文件,见 `ContextBreakdown`。
978
+ * 各段按最近一次发出的请求估,本次启动后这个会话还没发过请求时是 null。每次调用现算,在要看的时候调(比如点开读数时),别每次渲染都调。
979
+ */
980
+ contextBreakdown(sessionId: string): Promise<ContextBreakdown | null>;
981
+ /**
982
+ * 输入框 `/` 菜单此刻有的命令,同名去重后的样子:产品自己的(`/clear`,没有 `plugin`)在前,再是各插件经 `ctx.commands`
983
+ * 供的。`cwd` 是按哪个目录列(项目里的命令文件、技能跟着变)。只读,展开、发送仍走输入框。每次调用现问,要看时再调。
984
+ */
985
+ listCommands(context?: {
986
+ cwd?: string;
987
+ }): Promise<ListedCommand[]>;
988
+ /** 产品的对话视图,见 `ConversationProps`。 */
989
+ readonly Conversation: ComponentType<ConversationProps>;
990
+ /** 产品的会话背景设置:选图、拖入图片、预览、铺放、效果、浓淡和显示位置;外观页不再有这一节,背景只经它设置。 */
991
+ readonly ChatBackgroundSettings: ComponentType<{
992
+ title?: string;
993
+ }>;
994
+ /** 产品的正文渲染器,插件的任务和回报卡不另带一套 Markdown。 */
995
+ readonly Markdown: ComponentType<MarkdownProps>;
996
+ /** 产品的模型下拉,见 `ModelSelectProps`。 */
997
+ readonly ModelSelect: ComponentType<ModelSelectProps>;
998
+ /** React hook:「跟随」会落到的模型和默认思考档位,见 `ModelDefaults`;设置改了跟着变。只在组件里调。 */
999
+ useModelDefaults(): ModelDefaults;
1000
+ /** React hook:登记过的项目,按侧栏的顺序;增删改跟着变。只在组件里调。 */
1001
+ useProjects(): readonly ProjectInfo[];
1002
+ /**
1003
+ * 自己逻辑入口经 `ctx.serve` 开出来的对象。apply 时拿到,存起来给组件用;逻辑入口没开或停用了,调用以错误结束。
1004
+ * T 写逻辑入口那边的接口,末尾的 CallContext 参数这边不传。
1005
+ */
1006
+ remote<T extends object>(): Remote<T>;
1007
+ }
1008
+ /** `ui.draftInSession` 放进输入框的东西。 */
1009
+ export interface SessionDraft {
1010
+ text: string;
1011
+ /** 作为附件挂上的图,base64(不带 `data:` 前缀)。 */
1012
+ images?: ComposerImage[];
1013
+ /** 输入框原本是空的、人刚点过时直接发出去,见 `UiContext.draftInSession`。 */
1014
+ send?: boolean;
1015
+ /** 换掉整段草稿,而不是接在后面。 */
1016
+ replace?: boolean;
1017
+ }
1018
+ /** 放进输入框的一张图。 */
1019
+ export interface ComposerImage {
1020
+ data: string;
1021
+ mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
1022
+ /** 附件的名字;不给按截图起名。 */
1023
+ name?: string;
1024
+ /** 它是媒体目录里哪张图的标注副本(`ImageContent.from`):发出去以后记在图片块上,画廊的链路据此穿过这一步。 */
1025
+ from?: string;
1026
+ }
1027
+ /** `ui.openImage` 看的一张图。 */
1028
+ export interface ViewerImage {
1029
+ /** `data:` URL 或 `ui.mediaUrl` 的地址。 */
1030
+ src: string;
1031
+ alt?: string;
1032
+ /** 标注完按「完成」时带标注的副本去哪(`data:` URL)。 */
1033
+ onAttach?: (dataUrl: string) => void;
1034
+ }
1035
+ /** 界面入口的默认导出,name 必须和逻辑入口相同。 */
1036
+ export interface UiPlugin {
1037
+ name: string;
1038
+ apply(ui: UiContext): void;
1039
+ }