@ycodium-ai/plugin-api 0.2.2982 → 0.2.2984
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.
- package/dist/cache.d.ts +47 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +7 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +61 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +153 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +12 -0
- package/dist/commands.js.map +1 -0
- package/dist/decisions.d.ts +78 -0
- package/dist/decisions.d.ts.map +1 -0
- package/dist/decisions.js +2 -0
- package/dist/decisions.js.map +1 -0
- package/dist/definition.d.ts +25 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +5 -0
- package/dist/definition.js.map +1 -0
- package/dist/derivedState.d.ts +46 -0
- package/dist/derivedState.d.ts.map +1 -0
- package/dist/derivedState.js +2 -0
- package/dist/derivedState.js.map +1 -0
- package/dist/events.d.ts +227 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +103 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +18 -809
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -126
- package/dist/index.js.map +1 -1
- package/dist/interval.d.ts +31 -0
- package/dist/interval.d.ts.map +1 -0
- package/dist/interval.js +8 -0
- package/dist/interval.js.map +1 -0
- package/dist/logger.d.ts +15 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +7 -0
- package/dist/logger.js.map +1 -0
- package/dist/settings-card-shape.d.ts +194 -0
- package/dist/settings-card-shape.d.ts.map +1 -0
- package/dist/settings-card-shape.js +19 -0
- package/dist/settings-card-shape.js.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,24 @@ export * from "./executorModelOptions.ts";
|
|
|
24
24
|
export type * from "./communication.ts";
|
|
25
25
|
export type * from "./pending-requests.ts";
|
|
26
26
|
export type * from "./process-socket.ts";
|
|
27
|
+
import type { PluginCache, PluginPaths } from "./cache.ts";
|
|
28
|
+
import type { PluginCliCommand } from "./cli.ts";
|
|
29
|
+
import type { PluginCommand, PluginStreamCommand } from "./commands.ts";
|
|
30
|
+
import type { PluginDecisions } from "./decisions.ts";
|
|
31
|
+
import type { PluginDerivedState, PluginDerivedStateHandle } from "./derivedState.ts";
|
|
32
|
+
import type { PluginEvents, PluginReactor } from "./events.ts";
|
|
33
|
+
import type { PluginInterval } from "./interval.ts";
|
|
34
|
+
import type { PluginLogger } from "./logger.ts";
|
|
35
|
+
export type * from "./cache.ts";
|
|
36
|
+
export type * from "./cli.ts";
|
|
37
|
+
export * from "./commands.ts";
|
|
38
|
+
export type * from "./decisions.ts";
|
|
39
|
+
export * from "./definition.ts";
|
|
40
|
+
export type * from "./derivedState.ts";
|
|
41
|
+
export * from "./events.ts";
|
|
42
|
+
export * from "./interval.ts";
|
|
43
|
+
export type * from "./logger.ts";
|
|
44
|
+
export * from "./settings-card-shape.ts";
|
|
27
45
|
export { parseRetryAfterMs } from "./usage.ts";
|
|
28
46
|
export type { ExecutorQuotaBalance, ExecutorQuotaReading, ExecutorQuotaResetResult, ExecutorQuotaUnavailableReason, ExecutorQuotaWindow, ExecutorTokenRecord, ExecutorTokenTotals, ExecutorTokenUsageReading, ExecutorUsage, ExecutorUsageText, } from "./usage.ts";
|
|
29
47
|
export type { ExecutorCard, ExecutorContribution, ExecutorFormControl, ExecutorFormField, ExecutorFormFieldAnnotation, ExecutorHost, ExecutorInstance, ExecutorSessionCandidate, ExecutorSessionRecord, } from "./executor.ts";
|
|
@@ -41,727 +59,6 @@ export type PluginApiVersion = 5;
|
|
|
41
59
|
* 一条 warning,返回一个 **no-op disposer**,那条贡献不会进已经死掉的记录,也不抛错。
|
|
42
60
|
*/
|
|
43
61
|
export type PluginDisposer = () => void;
|
|
44
|
-
export interface PluginLogFields {
|
|
45
|
-
readonly [key: string]: unknown;
|
|
46
|
-
}
|
|
47
|
-
/** 日志自动带 pluginId,不进 i18n catalog。 */
|
|
48
|
-
export interface PluginLogger {
|
|
49
|
-
readonly info: (message: string, fields?: PluginLogFields) => void;
|
|
50
|
-
readonly warn: (message: string, fields?: PluginLogFields) => void;
|
|
51
|
-
readonly error: (message: string, fields?: PluginLogFields) => void;
|
|
52
|
-
}
|
|
53
|
-
export interface PluginPaths {
|
|
54
|
-
/**
|
|
55
|
-
* 插件代码所在目录(只读地用,宿主不保证可写)。
|
|
56
|
-
*
|
|
57
|
-
* 自带翻译包的插件把 catalog 放在这个目录下的 `locales/<locale>.json`
|
|
58
|
-
* (`en.json`、`zh-CN.json`……),宿主加载时读进 `plugin:<pluginId>` 命名
|
|
59
|
-
* 空间,缺 locale 回落英文。宿主只加载,不翻译第三方插件的文案。
|
|
60
|
-
*/
|
|
61
|
-
readonly pluginDir: string;
|
|
62
|
-
/** `<ycodium home>/plugin-data/<pluginId>`,卸载插件时不动。 */
|
|
63
|
-
readonly dataDir: string;
|
|
64
|
-
/**
|
|
65
|
-
* `<dataDir>/cache`。语义是**可随时重建**:宿主(或用户)随时可以整个删掉,
|
|
66
|
-
* 插件必须能从零重新算出来。要保留的东西写 `dataDir`。
|
|
67
|
-
*
|
|
68
|
-
* 目录惰性创建 —— 读到这个属性时才建,没用过缓存的插件不留空目录。
|
|
69
|
-
*/
|
|
70
|
-
readonly cacheDir: string;
|
|
71
|
-
}
|
|
72
|
-
export interface PluginCacheResult<T> {
|
|
73
|
-
readonly value: T;
|
|
74
|
-
readonly stale: boolean;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* 落 `paths.cacheDir` 下的按 key JSON 缓存(口子 #11):插件不用自己拼文件名、
|
|
78
|
-
* 手搓 TTL 判断。文件名是 `sha256(key)` 的十六进制串。
|
|
79
|
-
*
|
|
80
|
-
* `getJson` 的过期语义:
|
|
81
|
-
* - 不传 `maxAgeMs`:文件存在且能解析就返回,`stale` 恒 `false`(不做新鲜度判断,
|
|
82
|
-
* 写的时候自己决定要不要覆盖)。
|
|
83
|
-
* - 传了 `maxAgeMs` 且未过期:返回,`stale` `false`。
|
|
84
|
-
* - 传了 `maxAgeMs` 且已过期:`allowStale` 为 `true` 时照样返回旧值,标
|
|
85
|
-
* `stale: true`;否则视同没有缓存,返回 `null`——这是"退回旧结果顶一阵"与
|
|
86
|
-
* "过期就必须重新请求"两种插件都要用到的口子,用一个参数分开。
|
|
87
|
-
* - 缺失 / JSON 解析失败 / 形状不对:返回 `null`;后两种情况宿主会顺手删掉这份
|
|
88
|
-
* 坏文件,不留着占位置。
|
|
89
|
-
*/
|
|
90
|
-
export interface PluginCache {
|
|
91
|
-
readonly getJson: <T = unknown>(key: string, maxAgeMs?: number, allowStale?: boolean) => Promise<PluginCacheResult<T> | null>;
|
|
92
|
-
readonly setJson: (key: string, value: unknown) => Promise<void>;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* 插件看到的编排事件。字段是宿主事件信封的子集 —— 插件不 import contracts,
|
|
96
|
-
* 所以这里是结构化描述,payload 保持 unknown,由插件自己按 `type` 收窄。
|
|
97
|
-
*/
|
|
98
|
-
export interface PluginEvent {
|
|
99
|
-
readonly type: string;
|
|
100
|
-
readonly payload: unknown;
|
|
101
|
-
readonly sequence: number;
|
|
102
|
-
readonly eventId: string;
|
|
103
|
-
readonly aggregateKind: string;
|
|
104
|
-
readonly aggregateId: string;
|
|
105
|
-
readonly occurredAt: string;
|
|
106
|
-
}
|
|
107
|
-
export type PluginEventHandler = (event: PluginEvent) => void | Promise<void>;
|
|
108
|
-
/**
|
|
109
|
-
* 一条触发事件是谁报的。宿主从编排事件翻出来的是 `host`;插件经 `ctx.events.emit`
|
|
110
|
-
* 报的带那个插件的 id。
|
|
111
|
-
*/
|
|
112
|
-
export type PluginTriggerEventSource = {
|
|
113
|
-
readonly kind: "host";
|
|
114
|
-
} | {
|
|
115
|
-
readonly kind: "plugin";
|
|
116
|
-
readonly pluginId: string;
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* 触发事件使用开放的 kind,领域标识放在 data 中;宿主补充事件来源。
|
|
120
|
-
*/
|
|
121
|
-
export interface PluginTriggerEvent {
|
|
122
|
-
readonly eventId: string;
|
|
123
|
-
readonly kind: string;
|
|
124
|
-
readonly occurredAt: string;
|
|
125
|
-
readonly projectId: string | null;
|
|
126
|
-
readonly threadId: string | null;
|
|
127
|
-
/** 事件相关的短文本(thread 标题、审批摘要、run 结局)。 */
|
|
128
|
-
readonly summary: string;
|
|
129
|
-
/** 谁报的。用户配的触发器与界面靠它分辨真事件与某个插件的说法。 */
|
|
130
|
-
readonly source: PluginTriggerEventSource;
|
|
131
|
-
/** kind 特有的结构化字段;宿主翻出来的事件只放长期稳定的标识与有界摘要,没有就是空对象。 */
|
|
132
|
-
readonly data: Readonly<Record<string, unknown>>;
|
|
133
|
-
}
|
|
134
|
-
export type PluginTriggerHandler = (event: PluginTriggerEvent) => void | Promise<void>;
|
|
135
|
-
/** 审批或提问被回答、撤回时宿主发的触发事件。`ctx.events.on` 的 kind。 */
|
|
136
|
-
export declare const REQUEST_RESOLVED_TRIGGER_KIND = "thread.request-resolved";
|
|
137
|
-
/**
|
|
138
|
-
* `thread.request-resolved` 的 `data`。`outcome`:审批放行为 `accepted`、拒绝为 `declined`、
|
|
139
|
-
* 撤回(含会话退出补的收口)为 `cancelled`。提问被回答为 `answered`;轮次结束、会话退出时没人
|
|
140
|
-
* 回答而被宿主收口(以及 provider 给了空答案)为 `cancelled`。`decision` 是 provider
|
|
141
|
-
* 原样的审批决定(accept / acceptForSession / acceptAlways / decline / cancel),提问没有。
|
|
142
|
-
* **不带应答者**:事件里没有这个事实,要分辨是不是自己答的,用自己落的状态判断。
|
|
143
|
-
*/
|
|
144
|
-
export interface PluginRequestResolved {
|
|
145
|
-
readonly requestId: string;
|
|
146
|
-
readonly requestKind: "approval" | "user-input";
|
|
147
|
-
readonly outcome: "accepted" | "declined" | "cancelled" | "answered";
|
|
148
|
-
readonly decision?: string;
|
|
149
|
-
}
|
|
150
|
-
/** 从触发事件里读出 `thread.request-resolved` 的数据;kind 不对或形状不对返回 null,不抛。 */
|
|
151
|
-
export declare const readRequestResolved: (event: PluginTriggerEvent) => PluginRequestResolved | null;
|
|
152
|
-
/** agent 等人回答提问时宿主发的触发事件。`ctx.events.on` 的 kind;撤卡订 `REQUEST_RESOLVED_TRIGGER_KIND`。 */
|
|
153
|
-
export declare const USER_INPUT_PENDING_TRIGGER_KIND = "thread.user-input-pending";
|
|
154
|
-
/**
|
|
155
|
-
* `thread.user-input-pending` 的 `data`。只有请求标识与题数:题面、选项与答题形态用
|
|
156
|
-
* `ctx.projections.listPendingUserInputs` 按 `requestId` 取回(事件里不放正文,与其它宿主
|
|
157
|
-
* 触发事件同一立场)。题数按能答的题算,与读取接口一致;没有 requestId 或题面解不出来的
|
|
158
|
-
* 请求谁也答不了,宿主不发这条事件。
|
|
159
|
-
*/
|
|
160
|
-
export interface PluginUserInputPending {
|
|
161
|
-
readonly requestId: string;
|
|
162
|
-
readonly questionCount: number;
|
|
163
|
-
}
|
|
164
|
-
/** 从触发事件里读出 `thread.user-input-pending` 的数据;kind 不对或形状不对返回 null,不抛。 */
|
|
165
|
-
export declare const readUserInputPending: (event: PluginTriggerEvent) => PluginUserInputPending | null;
|
|
166
|
-
/**
|
|
167
|
-
* 轮次进度节拍:一轮里「现在到哪了」的有界摘要,`ctx.events.on` 的 kind。
|
|
168
|
-
*
|
|
169
|
-
* **节拍高频,handler 自己合并、别做重活。** 所有插件共用宿主的一个串行 worker,handler
|
|
170
|
-
* 里 `await` 网络会拖住全体插件:只记下最新快照并立刻返回,要发请求就由你自己的循环去发。
|
|
171
|
-
* 宿主前沿即发、尾部约 250ms 合并,`phase: "ended"` 一定立即发。只有订阅了才会产生节拍,
|
|
172
|
-
* 它不进去重表,也不能被用户绑成触发器。
|
|
173
|
-
*/
|
|
174
|
-
export declare const TURN_PROGRESS_TRIGGER_KIND = "thread.turn-progress";
|
|
175
|
-
export interface PluginTurnProgressSegment {
|
|
176
|
-
/** 助手消息 id。正文不在节拍里:按它调 `ctx.projections.getThreadMessage` 点读累计文本。 */
|
|
177
|
-
readonly messageId: string;
|
|
178
|
-
/** 该段是否还在流式。 */
|
|
179
|
-
readonly streaming: boolean;
|
|
180
|
-
}
|
|
181
|
-
export interface PluginTurnProgressTool {
|
|
182
|
-
readonly toolCallId: string;
|
|
183
|
-
/** 服务器拼好的一行标签,没有时回落到活动摘要。 */
|
|
184
|
-
readonly label: string;
|
|
185
|
-
readonly itemType: string;
|
|
186
|
-
readonly status: "running" | "completed" | "failed" | "declined" | "stopped";
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* `thread.turn-progress` 的 `data`。**不带正文**:助手文本与思考全文都不在里面。
|
|
190
|
-
* `seq` 在同一 (threadId, turnId) 内单调递增,拿它丢弃乱序与重复;`phase: "ended"` 是这一轮
|
|
191
|
-
* 的最后一拍。`turnId` 可为 null(助手消息的 turnId 本来可空)。
|
|
192
|
-
*/
|
|
193
|
-
export interface PluginTurnProgress {
|
|
194
|
-
readonly turnId: string | null;
|
|
195
|
-
readonly seq: number;
|
|
196
|
-
readonly phase: "running" | "ended";
|
|
197
|
-
readonly segments: ReadonlyArray<PluginTurnProgressSegment>;
|
|
198
|
-
readonly thinking: {
|
|
199
|
-
readonly active: boolean;
|
|
200
|
-
readonly chars: number;
|
|
201
|
-
};
|
|
202
|
-
/** 最近 100 条工具调用;更早的只计入 `toolCount`。 */
|
|
203
|
-
readonly tools: ReadonlyArray<PluginTurnProgressTool>;
|
|
204
|
-
/** 本轮出现过的工具调用总数,含已被挤出 `tools` 的。 */
|
|
205
|
-
readonly toolCount: number;
|
|
206
|
-
}
|
|
207
|
-
/** 从触发事件里读出 `thread.turn-progress` 的数据;kind 不对或形状不对返回 null,不抛。 */
|
|
208
|
-
export declare const readTurnProgress: (event: PluginTriggerEvent) => PluginTurnProgress | null;
|
|
209
|
-
/** `ctx.events.emit` 的那一半:宿主补 `eventId`、`source`,缺省补 `occurredAt`。 */
|
|
210
|
-
export interface PluginTriggerEventInput {
|
|
211
|
-
/** 重试同一触发时保持不变;宿主补插件命名空间。 */
|
|
212
|
-
readonly idempotencyKey?: string;
|
|
213
|
-
/** 事件相关的短文本。用户把它绑到团队时,这句就是那次 run 的 goal。 */
|
|
214
|
-
readonly summary: string;
|
|
215
|
-
readonly projectId?: string | null | undefined;
|
|
216
|
-
readonly threadId?: string | null | undefined;
|
|
217
|
-
/** ISO 时间;不给就是宿主收到这条的时刻。 */
|
|
218
|
-
readonly occurredAt?: string | undefined;
|
|
219
|
-
/** kind 特有的结构化字段。只放长期稳定的标识,订阅者靠它定位这条事件说的是谁。 */
|
|
220
|
-
readonly data?: Readonly<Record<string, unknown>> | undefined;
|
|
221
|
-
}
|
|
222
|
-
export interface PluginEvents {
|
|
223
|
-
/** 本插件作为目标的机器级触发绑定;读取实际设置,不读取插件局部配置。 */
|
|
224
|
-
readonly listBindings: () => Promise<Readonly<Record<string, PluginTriggerBinding>>>;
|
|
225
|
-
/**
|
|
226
|
-
* 订阅一类触发事件。串行、可 drain,按 eventId 去重。
|
|
227
|
-
*
|
|
228
|
-
* 宿主只有一个串行 worker 给全体插件用:handler 要同步返回,别在里面 `await` 网络。
|
|
229
|
-
* `thread.turn-progress`(`TURN_PROGRESS_TRIGGER_KIND`)是高频节拍,handler 自己合并、
|
|
230
|
-
* 别做重活;这一类不去重,也没有用户触发器。
|
|
231
|
-
*/
|
|
232
|
-
readonly on: (kind: string, handler: PluginTriggerHandler) => PluginDisposer;
|
|
233
|
-
/**
|
|
234
|
-
* 报一条触发事件,进的是宿主翻译出来的那些事件的同一条分发链:同一份去重、同一批
|
|
235
|
-
* 插件订阅者、同一套用户配的触发器。`kind` 是非空字符串,插件拥有其领域命名。
|
|
236
|
-
*
|
|
237
|
-
* **你报的事件带你的插件 id**(`event.source`),用户看得见是谁报的——所以这里没有
|
|
238
|
-
* 权限门:能报假事件的插件本来也能直接调命令。
|
|
239
|
-
*
|
|
240
|
-
* 你自己的 `on` 处理器收不到你自己报的事件,`emit` → `on` → `emit` 转不起来。
|
|
241
|
-
*/
|
|
242
|
-
readonly emit: (kind: string, event: PluginTriggerEventInput) => Promise<void>;
|
|
243
|
-
/**
|
|
244
|
-
* 订阅原始编排事件类型。等价于 `ctx.reactor({ events: [type], handle })`;
|
|
245
|
-
* 形状随宿主演进,能用触发事件就别用它。
|
|
246
|
-
*/
|
|
247
|
-
readonly onRaw: (type: string, handler: PluginEventHandler) => PluginDisposer;
|
|
248
|
-
/**
|
|
249
|
-
* 把你自己的一条事实写进宿主同一条事件日志。
|
|
250
|
-
*
|
|
251
|
-
* 什么时候用它:你要记住的东西跨事件、跨重启(看板、名册、信箱)。把它攒在内存里
|
|
252
|
-
* 就是已知会丢的那条路;落成事实,再用 `ctx.derivedState` 折出来。
|
|
253
|
-
*
|
|
254
|
-
* 三条硬规矩:
|
|
255
|
-
* - `name` 会被宿主强制成 `<你的插件 id>/…`。不带这个前缀当场拒绝——两个插件的
|
|
256
|
-
* 事件名撞上,谁的折叠都会吃到对方的事实。
|
|
257
|
-
* - `data` 是你自己的形状,宿主原样存、原样发回,**不校验也不解释**。形状变了
|
|
258
|
-
* 要么自己兼容旧数据,要么把 `derivedState` 的 `version` 加一从头重折。
|
|
259
|
-
* - 事实挂在哪个聚合上由你指定(project / thread / plugin)。挂错了不会报错,但
|
|
260
|
-
* 按聚合查的人找不到它。
|
|
261
|
-
*
|
|
262
|
-
* 写进去的事实之后会以 `plugin.event-appended` 出现在 `onRaw` 与 `reactor` 里,
|
|
263
|
-
* 你自己的也一样——要区分是不是自己写的,看 `payload.pluginId`。
|
|
264
|
-
* 返回提交序号,可传给派生状态 `get({ throughSequence })` 读取这次写入。
|
|
265
|
-
*/
|
|
266
|
-
readonly append: (input: PluginEventAppendInput) => Promise<{
|
|
267
|
-
readonly sequence: number;
|
|
268
|
-
}>;
|
|
269
|
-
}
|
|
270
|
-
export interface PluginTriggerBinding {
|
|
271
|
-
readonly bindingId: string;
|
|
272
|
-
readonly enabled: boolean;
|
|
273
|
-
readonly projectId: string;
|
|
274
|
-
readonly source: {
|
|
275
|
-
readonly kind: "event";
|
|
276
|
-
readonly eventKind: string;
|
|
277
|
-
};
|
|
278
|
-
readonly target: {
|
|
279
|
-
readonly kind: "plugin";
|
|
280
|
-
readonly pluginId: string;
|
|
281
|
-
readonly command: string;
|
|
282
|
-
readonly payload: Readonly<Record<string, unknown>>;
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
/** `ctx.events.append` 的入参。 */
|
|
286
|
-
export interface PluginEventAppendInput {
|
|
287
|
-
/** 同一操作重试时保持不变;宿主按安装条目、插件与数据目录隔离。省略则每次新建。 */
|
|
288
|
-
readonly commandId?: string;
|
|
289
|
-
/** 事实的名字。宿主会强制它以 `<你的插件 id>/` 开头。 */
|
|
290
|
-
readonly name: string;
|
|
291
|
-
/** 事实挂在哪个聚合上。 */
|
|
292
|
-
readonly aggregate: {
|
|
293
|
-
readonly kind: "project";
|
|
294
|
-
readonly id: string;
|
|
295
|
-
} | {
|
|
296
|
-
readonly kind: "thread";
|
|
297
|
-
readonly id: string;
|
|
298
|
-
} | {
|
|
299
|
-
readonly kind: "plugin";
|
|
300
|
-
readonly id: string;
|
|
301
|
-
};
|
|
302
|
-
/** 你自己的形状。必须是能 JSON 序列化的值。 */
|
|
303
|
-
readonly data: unknown;
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* 一块由事件折出来的状态,宿主替你记住、替你重建。
|
|
307
|
-
*
|
|
308
|
-
* 什么时候用它:你要记住的东西跨事件、跨重启(看板、名册、信箱)。**别把这种东西攒
|
|
309
|
-
* 在插件的模块变量或 Map 里** —— 插件停用、宿主重启、会话换进程,那份内存就没了,
|
|
310
|
-
* 而且没有任何东西会告诉你它没了。
|
|
311
|
-
*
|
|
312
|
-
* 只有一条硬规矩,但它排掉一整类缺陷:**`apply` 必须是纯函数**。同样的入参给同样的
|
|
313
|
-
* 结果,不读时钟、不读随机数、不发请求、不改传进来的 `state`(返回新值)。它会被跑
|
|
314
|
-
* 两次——事件来的时候一次,重启重建的时候一次——不纯就意味着两次结果不同,而你只会
|
|
315
|
-
* 在重启之后才发现。
|
|
316
|
-
*
|
|
317
|
-
* 状态必须能 JSON 序列化。宿主不校验它的形状:改了形状就把 `version` 加一,宿主会
|
|
318
|
-
* 丢掉旧的从头重折。不加,旧状态会带着旧规则一直用下去。
|
|
319
|
-
*/
|
|
320
|
-
export interface PluginDerivedState<S> {
|
|
321
|
-
/** 你自己的名字,插件内唯一。宿主会加上你的插件 id 做前缀,和别人撞不上。 */
|
|
322
|
-
readonly key: string;
|
|
323
|
-
/** 折法或状态形状改了就 +1。宿主据此丢掉旧的重折。 */
|
|
324
|
-
readonly version: number;
|
|
325
|
-
/** 只折这些事件类型;省略表示全收。过滤在宿主侧做,不进你的进程时间。 */
|
|
326
|
-
readonly events?: readonly string[] | undefined;
|
|
327
|
-
/** 空状态。重建从这里起折。 */
|
|
328
|
-
readonly init: () => S;
|
|
329
|
-
/** 纯折叠。不许就地改 `state`。 */
|
|
330
|
-
readonly apply: (state: S, event: PluginEvent) => S;
|
|
331
|
-
}
|
|
332
|
-
/** `ctx.derivedState` 给回来的把手。 */
|
|
333
|
-
export interface PluginDerivedStateHandle<S> {
|
|
334
|
-
/**
|
|
335
|
-
* 此刻的状态。在 `reactor` / `events.onRaw` 处理器里读到的,**已经含当前这条事件**
|
|
336
|
-
* ——宿主先推进状态再把事件发给你。
|
|
337
|
-
* 指定 throughSequence 会直接补读已提交日志,保证包含该序号;不等待 reactor 队列。
|
|
338
|
-
* 未提交的未来序号会拒绝,不会挂起等待。
|
|
339
|
-
*/
|
|
340
|
-
readonly get: (options?: {
|
|
341
|
-
readonly throughSequence: number;
|
|
342
|
-
}) => Promise<S>;
|
|
343
|
-
}
|
|
344
|
-
export interface PluginReactor {
|
|
345
|
-
/** 用于日志归因,插件内唯一即可。 */
|
|
346
|
-
readonly name: string;
|
|
347
|
-
/** 关心的事件类型;省略表示全收。过滤在宿主侧做,不进插件进程时间。 */
|
|
348
|
-
readonly events?: readonly string[] | undefined;
|
|
349
|
-
/** 串行执行;抛错只记 warning,不断流、不影响别的插件。 */
|
|
350
|
-
readonly handle: PluginEventHandler;
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* 宿主托管的重复任务(路线图 #37)。
|
|
354
|
-
*
|
|
355
|
-
* 只在**没有编排事件可驱动**时才用它 —— 要跟的东西是别的程序写的(终端会话导入
|
|
356
|
-
* 跟读别人写的记录就是这么一例)。有事件能驱动就用 `ctx.events.on`:定时器每一跳
|
|
357
|
-
* 都是白花的电。
|
|
358
|
-
*
|
|
359
|
-
* 别自己 `setInterval`:那种循环宿主看不见(`ycodium_inspect` 与插件卡上数不到),
|
|
360
|
-
* 停用插件时也没人替你关。
|
|
361
|
-
*/
|
|
362
|
-
export interface PluginInterval {
|
|
363
|
-
/** 用于日志归因与插件卡展示,插件内唯一;重名当场抛错,与命令同一条规矩。 */
|
|
364
|
-
readonly name: string;
|
|
365
|
-
/** 两次开跑之间的间隔。下限 `MIN_PLUGIN_INTERVAL_MS`,低于它当场抛错。 */
|
|
366
|
-
readonly everyMs: number;
|
|
367
|
-
/** 默认 false:第一跳在一个间隔之后。true 表示注册当场先跑一次。 */
|
|
368
|
-
readonly runImmediately?: boolean | undefined;
|
|
369
|
-
/**
|
|
370
|
-
* 同一条循环不会重入:上一跳没跑完,下一跳等它。抛错只记一条 warning,循环照跑,
|
|
371
|
-
* 不影响别的插件,也不会把宿主带下水。
|
|
372
|
-
*/
|
|
373
|
-
readonly handle: () => void | Promise<void>;
|
|
374
|
-
}
|
|
375
|
-
/** `everyMs` 的下限。比这更密的循环没有正当用途,只会烧 CPU。 */
|
|
376
|
-
export declare const MIN_PLUGIN_INTERVAL_MS = 1000;
|
|
377
|
-
/**
|
|
378
|
-
* 位置参数。声明顺序即命令行顺序;`variadic` 只能是最后一个。
|
|
379
|
-
*/
|
|
380
|
-
export interface PluginCliArgument {
|
|
381
|
-
/** 也是 `input.arguments` 里的键。 */
|
|
382
|
-
readonly name: string;
|
|
383
|
-
readonly description?: string | undefined;
|
|
384
|
-
/** 默认 true。可选参数缺席时键不出现。 */
|
|
385
|
-
readonly required?: boolean | undefined;
|
|
386
|
-
/** 吃掉剩下的全部参数,值是 `string[]`。只能声明在最后一个。 */
|
|
387
|
-
readonly variadic?: boolean | undefined;
|
|
388
|
-
}
|
|
389
|
-
/** `--name` 选项。`kind` 决定 `input.options[name]` 的类型。 */
|
|
390
|
-
export interface PluginCliOption {
|
|
391
|
-
readonly name: string;
|
|
392
|
-
readonly kind?: "string" | "boolean" | undefined;
|
|
393
|
-
/** 单字母短名,`-n`。 */
|
|
394
|
-
readonly alias?: string | undefined;
|
|
395
|
-
readonly description?: string | undefined;
|
|
396
|
-
/** 缺省值。不给的话 string 选项缺席即 undefined,boolean 缺席即 false。 */
|
|
397
|
-
readonly defaultValue?: string | boolean | undefined;
|
|
398
|
-
}
|
|
399
|
-
export interface PluginCliInput {
|
|
400
|
-
/** 按声明的名字取;variadic 的那个是 `string[]`。 */
|
|
401
|
-
readonly arguments: Readonly<Record<string, string | readonly string[]>>;
|
|
402
|
-
readonly options: Readonly<Record<string, string | boolean | undefined>>;
|
|
403
|
-
}
|
|
404
|
-
/** 命令的输出通道。日志走 `ctx.log`,给人看的输出走这里。 */
|
|
405
|
-
export interface PluginCliIo {
|
|
406
|
-
/** 写一行到 stdout。 */
|
|
407
|
-
readonly out: (line: string) => void;
|
|
408
|
-
/** 写一行到 stderr。 */
|
|
409
|
-
readonly err: (line: string) => void;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* 一条 `ycodium x <pluginId> <name>` 子命令(路线图 #6)。
|
|
413
|
-
*
|
|
414
|
-
* 跑它的是 **CLI 进程**,不是服务器进程:那里没有编排引擎也没有数据库,所以
|
|
415
|
-
* `ctx.commands.dispatch` / `ctx.decisions` / `ctx.projections` / `ctx.providers` /
|
|
416
|
-
* `ctx.ports` 一律被拒(`reason: "host-unavailable"`)。`ctx.config` / `ctx.fs` /
|
|
417
|
-
* `ctx.http` / `ctx.process` / `ctx.cache` / `ctx.settings` 照常可用。
|
|
418
|
-
*
|
|
419
|
-
* 参数与选项是**声明**,由宿主翻成真正的命令行解析——插件不 import CLI 框架,
|
|
420
|
-
* `--help`、缺参报错、类型转换都由宿主给。
|
|
421
|
-
*
|
|
422
|
-
* 返回值即退出码:`undefined` / 0 表示成功,非 0 会让 `ycodium x` 以该码退出。
|
|
423
|
-
*/
|
|
424
|
-
export interface PluginCliCommand {
|
|
425
|
-
/** 插件内唯一;重名当场抛错。与 `ctx.command` 是两张名字表,可以同名。 */
|
|
426
|
-
readonly name: string;
|
|
427
|
-
readonly description?: string | undefined;
|
|
428
|
-
readonly arguments?: readonly PluginCliArgument[] | undefined;
|
|
429
|
-
readonly options?: readonly PluginCliOption[] | undefined;
|
|
430
|
-
readonly handle: (input: PluginCliInput, io: PluginCliIo) => void | number | Promise<void | number>;
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* `password` 的值不落 patch 文件、也不下发给客户端:宿主把它存进机器上的密文库,
|
|
434
|
-
* patch 里只留一条引用,装配期解出来放进 `ctx.config`。所以卡片上永远不会回显
|
|
435
|
-
* 已存的密码,改密码只能整值替换,并且换值会让本插件重启一次。
|
|
436
|
-
*/
|
|
437
|
-
/**
|
|
438
|
-
* `proxy` 字段里「明确不加代理」那一档的值。空串是「跟机器默认走」,其余是某个代理的 id。
|
|
439
|
-
*
|
|
440
|
-
* 常量在这里,别在插件里各写一份 `"direct"`:三态语义是宿主定的,字面量散出去之后
|
|
441
|
-
* 改一个就得找齐所有副本。
|
|
442
|
-
*/
|
|
443
|
-
export declare const PLUGIN_PROXY_DIRECT = "direct";
|
|
444
|
-
export type PluginSettingsColumnKind = "text" | "password" | "number" | "boolean" | "select"
|
|
445
|
-
/**
|
|
446
|
-
* 代理选择器。**选项不用你填**:宿主会画出「跟机器默认」「不加代理」,以及这台机器
|
|
447
|
-
* 上配的每一个代理;值就是 `ctx.proxies.fetch` 认的那三态(空串/`"direct"`/某个 id)。
|
|
448
|
-
*
|
|
449
|
-
* 之所以不是一个自带选项的 `select`:宿主要**看得懂**这个值。删代理前设置里会问
|
|
450
|
-
* 「谁还在用」,而配置里的一串文字它认不出是代理引用——声明成这一种它就认得出,
|
|
451
|
-
* 你正用着的代理因此删不掉(路线图 #64)。
|
|
452
|
-
*/
|
|
453
|
-
| "proxy";
|
|
454
|
-
/** `table` 的值形状见 `PluginSettingsTableValue`;其余种类的值是标量。 */
|
|
455
|
-
export type PluginSettingsFieldKind = PluginSettingsColumnKind | "table";
|
|
456
|
-
export interface PluginSettingsFieldOption {
|
|
457
|
-
readonly value: string;
|
|
458
|
-
/** 与 `labelKey` 二选一,见 {@link PluginSettingsField}。 */
|
|
459
|
-
readonly label?: string | undefined;
|
|
460
|
-
/** 插件自己 `locales/<locale>.json` 里的键。 */
|
|
461
|
-
readonly labelKey?: string | undefined;
|
|
462
|
-
/**
|
|
463
|
-
* 选项图标。与页面 / 面板槽位同一套写法、同一份白名单:宿主的图标名,或指向自己
|
|
464
|
-
* `assets` 目录里一张 PNG 的相对路径。认不出就只画文字,不留空格子。
|
|
465
|
-
*/
|
|
466
|
-
readonly icon?: string | undefined;
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* 一个格子什么时候才出现:同一层里另一个格子的值落在 `equals` 里。
|
|
470
|
-
*
|
|
471
|
-
* 用来表达「先选类型、再填对应字段」。没有它,声明只能把所有变体的字段并排摊开——选了
|
|
472
|
-
* Telegram 的那一行,飞书与企微的凭据列空着摆在旁边。
|
|
473
|
-
*
|
|
474
|
-
* **只看同一层**:列看同一行的别的列,顶层字段看别的顶层字段。指向不存在的 key、或
|
|
475
|
-
* `equals` 是空数组,都表示恒不显示。
|
|
476
|
-
*
|
|
477
|
-
* **隐藏不等于清空**:藏起来的格子值仍然留着,改回去还能看见。所以插件读配置时该按自己
|
|
478
|
-
* 的语义判断,不能假设隐藏的格子是空的。
|
|
479
|
-
*/
|
|
480
|
-
export interface PluginSettingsVisibility {
|
|
481
|
-
readonly key: string;
|
|
482
|
-
readonly equals: readonly string[];
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* 实例表的一列。列复用字段的全部声明与校验,只是种类里没有 `table`——表不能自嵌套。
|
|
486
|
-
* `password` 列走的是顶层 password 字段那一套:每行每列一条密文引用,明文不进
|
|
487
|
-
* patch 文件也不下发给客户端,装配期解出来放回同一格。
|
|
488
|
-
*/
|
|
489
|
-
export interface PluginSettingsColumn {
|
|
490
|
-
readonly key: string;
|
|
491
|
-
readonly kind: PluginSettingsColumnKind;
|
|
492
|
-
/** 与 `labelKey` 二选一,见 {@link PluginSettingsField}。 */
|
|
493
|
-
readonly label?: string | undefined;
|
|
494
|
-
readonly labelKey?: string | undefined;
|
|
495
|
-
readonly description?: string | undefined;
|
|
496
|
-
readonly descriptionKey?: string | undefined;
|
|
497
|
-
readonly placeholder?: string | undefined;
|
|
498
|
-
readonly placeholderKey?: string | undefined;
|
|
499
|
-
readonly required?: boolean | undefined;
|
|
500
|
-
readonly options?: readonly PluginSettingsFieldOption[] | undefined;
|
|
501
|
-
/** 缺席=一直显示。见 {@link PluginSettingsVisibility}。 */
|
|
502
|
-
readonly showWhen?: PluginSettingsVisibility | undefined;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* 行 id:字母开头,后接字母 / 数字 / `_` / `-`,最长 64。不许数字开头——那种键会被
|
|
506
|
-
* JS 重排到最前,界面上的行序就跟加行顺序对不上了。
|
|
507
|
-
*/
|
|
508
|
-
export type PluginSettingsRowId = string;
|
|
509
|
-
/** 表的一行:列 key → 值。 */
|
|
510
|
-
export type PluginSettingsTableRow = Readonly<Record<string, unknown>>;
|
|
511
|
-
/**
|
|
512
|
-
* `kind: "table"` 字段在 config 里的值。整表替换:保存时没出现的行就是被删掉的行,
|
|
513
|
-
* 它那几格密文跟着回收;行的顺序即 `Object.keys` 的顺序。
|
|
514
|
-
*/
|
|
515
|
-
export type PluginSettingsTableValue = Readonly<Record<PluginSettingsRowId, PluginSettingsTableRow>>;
|
|
516
|
-
/**
|
|
517
|
-
* 文案有两种写法,同一项只能选一种:
|
|
518
|
-
*
|
|
519
|
-
* - 字面量(`label` / `description` / `placeholder`):原样显示,不随界面语言变。
|
|
520
|
-
* - 键(`labelKey` / `descriptionKey` / `placeholderKey`):键写在插件自己的
|
|
521
|
-
* `locales/<locale>.json` 里,宿主按界面语言解析;当前语言缺这个键就回落到
|
|
522
|
-
* `en.json`,英文也缺才显示键名(并在控制台告警)。
|
|
523
|
-
*
|
|
524
|
-
* `label` 与 `labelKey` 必须给一个;`description`、`placeholder` 可以都不给,但
|
|
525
|
-
* 不能两种同时给。`ctx.settingsCard` 注册时校验,违反即当场抛错,错误里点名
|
|
526
|
-
* 插件与字段。选项({@link PluginSettingsFieldOption})与表格列同理。
|
|
527
|
-
*
|
|
528
|
-
* `kind: "table"` 是一张实例表——一行一个实例,`columns` 声明每行有哪些子字段。
|
|
529
|
-
* 声明表时 `columns` 必须给;`rowIds` 说明行 id 谁生成:`client`(缺席即此)表示
|
|
530
|
-
* 人在界面上加行、客户端生成 id,`plugin` 表示行由插件预置进 config,界面只能改
|
|
531
|
-
* 值不能增删行。表字段自己的 `placeholder` / `options` 不用。
|
|
532
|
-
*/
|
|
533
|
-
export interface PluginSettingsField extends Omit<PluginSettingsColumn, "kind"> {
|
|
534
|
-
readonly kind: PluginSettingsFieldKind;
|
|
535
|
-
readonly columns?: readonly PluginSettingsColumn[] | undefined;
|
|
536
|
-
readonly rowIds?: "client" | "plugin" | undefined;
|
|
537
|
-
/** 只有 `kind: "table"` 读它:每行一个按钮,见 {@link PluginSettingsRowAction}。 */
|
|
538
|
-
readonly rowActions?: readonly PluginSettingsRowAction[] | undefined;
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* 表字段每一行上的一个动作按钮。点开后宿主弹一个对话框,订阅本插件的一条 `ctx.stream`
|
|
542
|
-
* 命令,按固定词汇(二维码、状态、步骤清单、完成、失败)显示进度;成功时把 `fills` 白名单
|
|
543
|
-
* 里的值写进**这一行的草稿**,由用户自己点卡片的 Save——宿主不替用户保存。
|
|
544
|
-
*
|
|
545
|
-
* 文案只给键(`labelKey` 等),在插件自己的 `locales/<locale>.json` 里解析,注册时
|
|
546
|
-
* 纳入设置卡的键齐全守卫。命令与列的引用也在注册阶段校验:列名在 `ctx.settingsCard`
|
|
547
|
-
* 当场查,命令在 `activate` 结束后查(命令可以晚于卡注册);引用不存在的命令、非流式命令、
|
|
548
|
-
* scope 不是 `operate` 的命令,或不属于本表的列,插件装载失败并点名出错的动作。
|
|
549
|
-
*
|
|
550
|
-
* 流的 payload 由宿主给出:`{ rowId, values }`,`values` 是这一行当前草稿里**除 password
|
|
551
|
-
* 列外**的格子(未保存的也在,所以插件读得到用户刚选的域名之类)。流发出的条目词汇见
|
|
552
|
-
* {@link PluginRowActionItem};形状不对的条目客户端整条丢掉,不报错,所以发条目时用这个类型。
|
|
553
|
-
*
|
|
554
|
-
* 移动端不渲染行动作,也不会因它报错。
|
|
555
|
-
*/
|
|
556
|
-
export interface PluginSettingsRowAction {
|
|
557
|
-
/** 同一张表内唯一。 */
|
|
558
|
-
readonly id: string;
|
|
559
|
-
readonly labelKey: string;
|
|
560
|
-
readonly descriptionKey?: string | undefined;
|
|
561
|
-
/** 按钮旁的小标记,例如 "Beta"。 */
|
|
562
|
-
readonly badgeKey?: string | undefined;
|
|
563
|
-
/** 按钮下方一直可见的提示(例如「依赖非公开接口」)。 */
|
|
564
|
-
readonly warningKey?: string | undefined;
|
|
565
|
-
/** 本插件 `ctx.stream` 注册的命令名,scope 必须是 `operate`。 */
|
|
566
|
-
readonly command: string;
|
|
567
|
-
/** 只在这一行的某一列取值落在 `equals` 里时显示按钮;`key` 必须是本表的列。 */
|
|
568
|
-
readonly showWhen?: PluginSettingsVisibility | undefined;
|
|
569
|
-
/** 完成条目允许写进这一行草稿的列 key 白名单;条目里白名单之外的值被丢弃。 */
|
|
570
|
-
readonly fills: readonly string[];
|
|
571
|
-
}
|
|
572
|
-
/** 行动作条目里文案键的插值参数,代入插件翻译包里的 `{{name}}`。只认字符串值。 */
|
|
573
|
-
export type PluginRowActionParams = {
|
|
574
|
-
readonly [name: string]: string;
|
|
575
|
-
};
|
|
576
|
-
/** 行动作里一个步骤的状态。 */
|
|
577
|
-
export type PluginRowActionStepState = "pending" | "running" | "done" | "skipped" | "failed";
|
|
578
|
-
/**
|
|
579
|
-
* 行动作的流条目。宿主按 `kind` 画对话框:
|
|
580
|
-
* - `qr`:二维码;后来的替换先前的。`expiresAt` 是 ISO 时间字符串,只是提示。
|
|
581
|
-
* - `status`:一行状态文案;`expired: true` 表示码失效,客户端撤掉二维码、给「换一个新码」。
|
|
582
|
-
* - `steps`:整张步骤清单,每次整表替换。
|
|
583
|
-
* - `done`:终态,`fills` 按行动作的 `fills` 白名单写进这一行草稿,用户点保存才落盘。
|
|
584
|
-
* - `failed`:终态,`detail` 原样显示,进来之前要脱敏。
|
|
585
|
-
* 形状与宿主契约一致(测试锁着);不合形状的条目在客户端整条丢掉。
|
|
586
|
-
*/
|
|
587
|
-
export type PluginRowActionItem = {
|
|
588
|
-
readonly kind: "qr";
|
|
589
|
-
readonly payload: string;
|
|
590
|
-
readonly expiresAt?: string | undefined;
|
|
591
|
-
} | {
|
|
592
|
-
readonly kind: "status";
|
|
593
|
-
readonly statusKey: string;
|
|
594
|
-
readonly params?: PluginRowActionParams | undefined;
|
|
595
|
-
readonly expired?: boolean | undefined;
|
|
596
|
-
} | {
|
|
597
|
-
readonly kind: "steps";
|
|
598
|
-
readonly steps: ReadonlyArray<{
|
|
599
|
-
readonly id: string;
|
|
600
|
-
readonly labelKey: string;
|
|
601
|
-
readonly state: PluginRowActionStepState;
|
|
602
|
-
}>;
|
|
603
|
-
} | {
|
|
604
|
-
readonly kind: "done";
|
|
605
|
-
readonly fills: {
|
|
606
|
-
readonly [column: string]: string;
|
|
607
|
-
};
|
|
608
|
-
readonly messageKey?: string | undefined;
|
|
609
|
-
readonly warnings?: ReadonlyArray<{
|
|
610
|
-
readonly key: string;
|
|
611
|
-
readonly params?: PluginRowActionParams | undefined;
|
|
612
|
-
}> | undefined;
|
|
613
|
-
} | {
|
|
614
|
-
readonly kind: "failed";
|
|
615
|
-
readonly reasonKey: string;
|
|
616
|
-
readonly params?: PluginRowActionParams | undefined;
|
|
617
|
-
readonly detail?: string | undefined;
|
|
618
|
-
};
|
|
619
|
-
/**
|
|
620
|
-
* 命令被调用时宿主知道的上下文。RPC 是全局作用域(thread-scoped 命令刻意
|
|
621
|
-
* 推迟),所以这里只有调用方的粗粒度信息;字段只增不改。
|
|
622
|
-
*/
|
|
623
|
-
export interface PluginCommandInvocation {
|
|
624
|
-
/** 调用方凭据已通过的 scope("read" 或 "operate")。 */
|
|
625
|
-
readonly scope: "read" | "operate";
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* JSON Schema,draft-07 的一个**白名单子集**。宿主自带编译器(仓库没有 JSON Schema
|
|
629
|
-
* 运行时依赖),认不出来的关键字一律编译期报错——插件 activate 当场失败,不会静默
|
|
630
|
-
* 变成"写了等于没写"。
|
|
631
|
-
*
|
|
632
|
-
* 下面这份清单**以 `apps/server/src/pluginHost/jsonSchema.ts` 为准**(`SUPPORTED_KEYWORDS`
|
|
633
|
-
* 与 `ANNOTATION_KEYWORDS` 两张表),那边改了这里跟着改。
|
|
634
|
-
*
|
|
635
|
-
* 支持:`type`(object / string / number / integer / boolean / array / null,也可以
|
|
636
|
-
* 写成数组表示可空)、`properties`、`required`、`additionalProperties`(布尔或
|
|
637
|
-
* schema)、`enum`、`const`、`items`(单个 schema,不支持元组形式)、
|
|
638
|
-
* `minimum` / `maximum` / `exclusiveMinimum` / `exclusiveMaximum`、
|
|
639
|
-
* `minLength` / `maxLength`、`pattern`(`u` flag 的 RegExp)、`minItems` / `maxItems`、
|
|
640
|
-
* `oneOf`(至少两个分支,恰好一个匹配才算过)。
|
|
641
|
-
* 另外接受但不校验这几个注解:`description`、`title`、`default`、`examples`、
|
|
642
|
-
* `$schema`、`$comment`。
|
|
643
|
-
*
|
|
644
|
-
* 判别联合就写 `oneOf`:共有字段留在同层的 `properties` / `required` 上(同层关键字
|
|
645
|
-
* 与分支一起生效),分支里只写判别键的 `const` 与那一支自己的 `required`,这样
|
|
646
|
-
* "status 是 ok 却没带 items" 会被挡在出口。
|
|
647
|
-
*
|
|
648
|
-
* 不支持:`$ref`、`anyOf` / `allOf` / `not`、`if` / `then` / `else`、
|
|
649
|
-
* `patternProperties`、`dependencies`、`format`。一个 `oneOf` 足够表达判别联合,
|
|
650
|
-
* 其余组合关键字是复杂度不换收益。
|
|
651
|
-
*
|
|
652
|
-
* 顶层形状只有 `payloadSchema` 有额外限制(必须 `"type": "object"`);`resultSchema`
|
|
653
|
-
* 与 `itemSchema` 顶层随意。
|
|
654
|
-
*/
|
|
655
|
-
export type PluginJsonSchema = Record<string, unknown>;
|
|
656
|
-
/**
|
|
657
|
-
* 请求-响应命令。客户端经宿主的 `plugins.invoke` 单信封调用;payload 在
|
|
658
|
-
* 信封入口按 payloadSchema 校验,不合格的请求不会到达 handle。handle 抛错
|
|
659
|
-
* 会以 handler-failed 的错误形状过线,message 原样透出——别把秘密放进异常。
|
|
660
|
-
*
|
|
661
|
-
* 要让调用方能**分辨**是哪一类失败,就在抛出的错误上挂一个字符串 `code`:宿主把
|
|
662
|
-
* 它原样放进过线错误的 `pluginCode`。过线错误的 `code` 字段是宿主自己的信封分类
|
|
663
|
-
* (plugin-unavailable / invalid-payload / forbidden / handler-failed),插件写不
|
|
664
|
-
* 进去;调用方也不该去 parse 人读的 message。
|
|
665
|
-
*
|
|
666
|
-
* 要让调用方**照着做**(等到几点再试之类),再挂一个 `data`:宿主做一次 JSON 往返
|
|
667
|
-
* 后放进过线错误的 `pluginData`。只有 JSON 值能过去,序列化不了的整个丢掉;形状由
|
|
668
|
-
* 插件与它的调用方约定,宿主不解释。速率限制的写法是 `{ retryAt: <epoch ms> }`。
|
|
669
|
-
*/
|
|
670
|
-
/**
|
|
671
|
-
* 宿主 contracts schema 的名字(如 `"UsageSummary"`),用来替代手写 JSON Schema。
|
|
672
|
-
*
|
|
673
|
-
* 只允许第一方包引用宿主已登记的名字;按 manifest 包名判断,目录与 npm 安装一致。
|
|
674
|
-
* 第三方包须声明自己的 JSON Schema;未知契约名在注册时失败。
|
|
675
|
-
*
|
|
676
|
-
* 与同一条命令上对应的 `*Schema` 字段**互斥**:两个都给是注册错误,一个都不给
|
|
677
|
-
* (payload 侧)也是注册错误。校验只判合法、不改值:contracts 里的
|
|
678
|
-
* `TrimmedNonEmptyString` 之类是 transformation,宿主丢弃 decode 的产物,命令的
|
|
679
|
-
* payload 与结果都按原值过线。
|
|
680
|
-
*/
|
|
681
|
-
export type PluginContractName = string;
|
|
682
|
-
export interface PluginCommand {
|
|
683
|
-
/**
|
|
684
|
-
* 插件内唯一;跨插件由 pluginId 隔开,不会撞名。
|
|
685
|
-
*
|
|
686
|
-
* 同一插件内重复注册同名命令**当场抛错**,不顶掉旧的:命令名是过线的寻址键,静默
|
|
687
|
-
* 替换会让已经在飞的调用换了含义。抛在 `ctx.command` / `ctx.stream` 调用处,即
|
|
688
|
-
* activate 失败、整个插件挂载失败。`ctx.command` 与 `ctx.stream` 共用同一张名字表。
|
|
689
|
-
*/
|
|
690
|
-
readonly name: string;
|
|
691
|
-
readonly description?: string | undefined;
|
|
692
|
-
/** 缺省 "read"。声明 "operate" 的命令要求调用方持有 operate 凭据。 */
|
|
693
|
-
readonly scope?: "read" | "operate" | undefined;
|
|
694
|
-
/**
|
|
695
|
-
* 顶层必须是 `"type": "object"`;handle 收到的就是它校验过的形状。与
|
|
696
|
-
* `payloadContract` 二选一,缺一不可。
|
|
697
|
-
*/
|
|
698
|
-
readonly payloadSchema?: PluginJsonSchema | undefined;
|
|
699
|
-
/** 仅第一方插件:按名引用宿主注册表里的 contracts schema,替代 `payloadSchema`。 */
|
|
700
|
-
readonly payloadContract?: PluginContractName | undefined;
|
|
701
|
-
/**
|
|
702
|
-
* 可选。声明了,宿主就在**出口**按它校验 handle 的返回值:不合格的返回值不过线,
|
|
703
|
-
* 调用方收到 `invalid-result` 错误(detail 是 JSON Pointer 风格的第一条违例),
|
|
704
|
-
* 宿主同时打一条带 pluginId / command 的 warn。不声明就不校验,返回值原样过线。
|
|
705
|
-
*
|
|
706
|
-
* 与 `payloadSchema` 不同,**顶层不限于 `"type": "object"`**:结果可以是数组、
|
|
707
|
-
* 字符串、数字这类标量,用的是同一个编译器(同一份关键字白名单)。
|
|
708
|
-
*
|
|
709
|
-
* 声明它的价值在于形状漂移当场可见:命令结果的类型在插件与调用方两边各写一份,
|
|
710
|
-
* 只有出口校验能让"少了个字段"在运行期炸出来,而不是客户端拿到半个对象。
|
|
711
|
-
*/
|
|
712
|
-
readonly resultSchema?: PluginJsonSchema | undefined;
|
|
713
|
-
/** 仅第一方插件:按名引用宿主注册表里的 contracts schema,替代 `resultSchema`。 */
|
|
714
|
-
readonly resultContract?: PluginContractName | undefined;
|
|
715
|
-
/** 返回值必须可 JSON 序列化;形状由插件与自己的 UI/调用方约定。 */
|
|
716
|
-
readonly handle: (payload: Record<string, unknown>, invocation: PluginCommandInvocation) => Promise<unknown> | unknown;
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* `buffer.latest` 的上限。留得越多,慢订阅方压在宿主内存里的东西越多——这个数封的
|
|
720
|
-
* 正是那个。够用就行:宿主自己的高频流留 8 条。
|
|
721
|
-
*/
|
|
722
|
-
export declare const MAX_PLUGIN_STREAM_BUFFER = 1024;
|
|
723
|
-
/**
|
|
724
|
-
* 流式命令(`plugins.subscribe`)。emit 的每个值必须可 JSON 序列化;signal
|
|
725
|
-
* 中止表示订阅方挂断,handle 应尽快返回,之后的 emit 会被宿主静默丢弃。
|
|
726
|
-
*/
|
|
727
|
-
export interface PluginStreamCommand {
|
|
728
|
-
/** 与 `PluginCommand.name` 同一张表:重复即抛错,activate 失败。 */
|
|
729
|
-
readonly name: string;
|
|
730
|
-
readonly description?: string | undefined;
|
|
731
|
-
readonly scope?: "read" | "operate" | undefined;
|
|
732
|
-
/**
|
|
733
|
-
* 顶层必须是 `"type": "object"`;handle 收到的就是它校验过的形状。与
|
|
734
|
-
* `payloadContract` 二选一,缺一不可。
|
|
735
|
-
*/
|
|
736
|
-
readonly payloadSchema?: PluginJsonSchema | undefined;
|
|
737
|
-
/** 仅第一方插件:按名引用宿主注册表里的 contracts schema,替代 `payloadSchema`。 */
|
|
738
|
-
readonly payloadContract?: PluginContractName | undefined;
|
|
739
|
-
/**
|
|
740
|
-
* 可选。声明了,宿主就在出口按它校验**每一个** emit 的值:出现不合格的值时这条流
|
|
741
|
-
* 立刻以 `invalid-result` 结束(此前已发出的值不撤回),并打一条带 pluginId /
|
|
742
|
-
* command 的 warn。不声明就不校验。
|
|
743
|
-
*
|
|
744
|
-
* 与 `resultSchema` 一样,**顶层不限于 `"type": "object"`** —— 只有 `payloadSchema`
|
|
745
|
-
* 那一处有这条限制。
|
|
746
|
-
*/
|
|
747
|
-
readonly itemSchema?: PluginJsonSchema | undefined;
|
|
748
|
-
/** 仅第一方插件:按名引用宿主注册表里的 contracts schema,替代 `itemSchema`。 */
|
|
749
|
-
readonly itemContract?: PluginContractName | undefined;
|
|
750
|
-
/**
|
|
751
|
-
* 订阅方收得比你发得慢时,积压怎么办。
|
|
752
|
-
*
|
|
753
|
-
* **省略=全留**(今天的行为),适合「跑一次就完」的流——diff 分片、扫描进度:
|
|
754
|
-
* 丢中间一块等于结果是错的,宁可积压。这类流的总量由那一次操作封顶,涨不到天上去。
|
|
755
|
-
*
|
|
756
|
-
* **持续推状态的流必须写 `{ latest: N }`**:只留最近 N 条,慢订阅方丢掉的是**旧的**。
|
|
757
|
-
* 一秒一份的快照配「全留」,订阅方一慢内存就一直涨——宿主自己的高频流用的正是这个
|
|
758
|
-
* 策略(`PubSub.sliding(8)`)。N 的上限见 `MAX_PLUGIN_STREAM_BUFFER`。
|
|
759
|
-
*/
|
|
760
|
-
readonly buffer?: {
|
|
761
|
-
readonly latest: number;
|
|
762
|
-
} | undefined;
|
|
763
|
-
readonly handle: (payload: Record<string, unknown>, emit: (value: unknown) => void, signal: AbortSignal, invocation: PluginCommandInvocation) => Promise<void>;
|
|
764
|
-
}
|
|
765
62
|
export interface PluginSettings<Config> {
|
|
766
63
|
/** 读本插件在 home patch 层的那份 config(`password` 已解成明文);home 层没写过就回退到 `ctx.config`,不是空对象。 */
|
|
767
64
|
readonly read: () => Promise<Config>;
|
|
@@ -899,77 +196,6 @@ export interface PluginCommands {
|
|
|
899
196
|
readonly threadId?: string;
|
|
900
197
|
}) => Promise<PluginCommandReceipt>;
|
|
901
198
|
}
|
|
902
|
-
/** 卡上的一个按钮。`id` 是回答里回传的那个值,一张卡内唯一。 */
|
|
903
|
-
export interface PluginDecisionOption {
|
|
904
|
-
/** 小写字母开头,`[a-zA-Z0-9._-]`。 */
|
|
905
|
-
readonly id: string;
|
|
906
|
-
readonly label: string;
|
|
907
|
-
/** 只影响按钮的显示档位;`danger` 用于「这一下会拆掉东西」。 */
|
|
908
|
-
readonly tone?: "default" | "primary" | "danger";
|
|
909
|
-
}
|
|
910
|
-
/**
|
|
911
|
-
* 一张待决定的卡。内容封顶四样:一行标题、几行说明、一块可折叠的文本或代码、
|
|
912
|
-
* 若干按钮。塞不进任意组件——渲染只有一份,web / mobile 一致。
|
|
913
|
-
*/
|
|
914
|
-
export interface PluginDecisionRequest {
|
|
915
|
-
/** 卡挂在哪条会话上。决定卡只有会话级,没有「与任何会话无关」的问法。 */
|
|
916
|
-
readonly threadId: string;
|
|
917
|
-
readonly title: string;
|
|
918
|
-
/** 说明行;给字符串就是一行。最多 8 行,超出截断。 */
|
|
919
|
-
readonly body?: string | readonly string[];
|
|
920
|
-
/** 折叠体。`language` 给了就按代码渲染。 */
|
|
921
|
-
readonly detail?: {
|
|
922
|
-
readonly label?: string;
|
|
923
|
-
readonly text: string;
|
|
924
|
-
readonly language?: string;
|
|
925
|
-
};
|
|
926
|
-
/** 1 到 5 个按钮,缺一个卡就按不下去。 */
|
|
927
|
-
readonly options: readonly PluginDecisionOption[];
|
|
928
|
-
/**
|
|
929
|
-
* 幂等键。同一个值重复贴只出一张卡(宿主会在前面加上 `plugin:<你的 id>:`)。
|
|
930
|
-
* 省略就由宿主发一个。
|
|
931
|
-
*/
|
|
932
|
-
readonly requestId?: string;
|
|
933
|
-
}
|
|
934
|
-
export interface PluginDecisionAnswer {
|
|
935
|
-
readonly requestId: string;
|
|
936
|
-
readonly threadId: string;
|
|
937
|
-
/** 人按的那个按钮的 `id`。 */
|
|
938
|
-
readonly optionId: string;
|
|
939
|
-
readonly answeredAt: string;
|
|
940
|
-
}
|
|
941
|
-
export interface PluginDecisionHandle {
|
|
942
|
-
/** 宿主发的完整 id,`cancel` 与 `on` 里看到的就是它。 */
|
|
943
|
-
readonly requestId: string;
|
|
944
|
-
}
|
|
945
|
-
export type PluginDecisionHandler = (answer: PluginDecisionAnswer) => void | Promise<void>;
|
|
946
|
-
/**
|
|
947
|
-
* 问一个人。**卡上带你的插件 id,用户看得见是谁在问**——所以这里没有权限门。
|
|
948
|
-
*
|
|
949
|
-
* 两种等法:`ask` 贴完就走,答案经 `on` 回来;`askAndWait` 等到有人按,
|
|
950
|
-
* `timeoutMs` 到点自动把卡作废并 resolve 成 null。长活儿用前者:等待占着一条
|
|
951
|
-
* Promise,插件被停用时它会以 null 收场。
|
|
952
|
-
*
|
|
953
|
-
* 没人答的卡会挡住这个项目的归档和拿掉文件夹;不再需要时用 `cancel` 收回。
|
|
954
|
-
*/
|
|
955
|
-
export interface PluginDecisions {
|
|
956
|
-
/** 贴一张卡就走。返回宿主发的 requestId。 */
|
|
957
|
-
readonly ask: (request: PluginDecisionRequest) => Promise<PluginDecisionHandle>;
|
|
958
|
-
/**
|
|
959
|
-
* 贴一张卡并等回答。超时、被作废、插件停用都 resolve 成 null,不 reject——
|
|
960
|
-
* 「没人回答」是正常结局,不是错误。
|
|
961
|
-
*/
|
|
962
|
-
readonly askAndWait: (request: PluginDecisionRequest & {
|
|
963
|
-
readonly timeoutMs?: number;
|
|
964
|
-
}) => Promise<PluginDecisionAnswer | null>;
|
|
965
|
-
/** 收本插件贴的卡的回答。别的插件的卡收不到。 */
|
|
966
|
-
readonly on: (handler: PluginDecisionHandler) => PluginDisposer;
|
|
967
|
-
/**
|
|
968
|
-
* 收回一张还没人答的卡。已经答过的静默忽略。
|
|
969
|
-
* 没答的卡会挡住这个项目的归档;不再需要它时用这个收回。
|
|
970
|
-
*/
|
|
971
|
-
readonly cancel: (requestId: string, summary?: string) => Promise<void>;
|
|
972
|
-
}
|
|
973
199
|
/** 这台 environment 的身份。用户看到的名字是「机器」。 */
|
|
974
200
|
export interface PluginEnvironment {
|
|
975
201
|
/** 服务器持久化的 environment id,不是主机名:两台机器可以同名。 */
|
|
@@ -1719,21 +945,4 @@ export interface PluginContext<Config = Record<string, unknown>> extends Capabil
|
|
|
1719
945
|
/** 兜底 finalizer;与各注册的 disposer 一起逆序执行。 */
|
|
1720
946
|
readonly onDispose: (dispose: () => void | Promise<void>) => void;
|
|
1721
947
|
}
|
|
1722
|
-
export interface PluginDefinition<Config = Record<string, unknown>> {
|
|
1723
|
-
/** 必须与 patch 条目 id 的后缀一致,否则宿主拒绝加载。 */
|
|
1724
|
-
readonly id: string;
|
|
1725
|
-
/** 静态声明插件针对的 API 版本,不能用宿主当前的运行时版本替代兼容性声明。 */
|
|
1726
|
-
readonly apiVersion: PluginApiVersion;
|
|
1727
|
-
/**
|
|
1728
|
-
* 执行器贡献。缺席或空数组 = 普通功能插件。非空则 manifest 必须声明
|
|
1729
|
-
* `{ kind: "executor" }`,否则拒载。名片在 activate 之前即可聚合。
|
|
1730
|
-
*/
|
|
1731
|
-
readonly executors?: ReadonlyArray<ExecutorContribution>;
|
|
1732
|
-
/** 超过 5 秒未返回视为加载失败,插件被隔离掉。 */
|
|
1733
|
-
readonly activate: (ctx: PluginContext<Config>) => void | Promise<void>;
|
|
1734
|
-
}
|
|
1735
|
-
/**
|
|
1736
|
-
* 只做类型锚定:默认导出经过它,宿主校验的字段就都被 TS 盯住了。
|
|
1737
|
-
*/
|
|
1738
|
-
export declare const definePlugin: <Config = Record<string, unknown>>(definition: PluginDefinition<Config>) => PluginDefinition<Config>;
|
|
1739
948
|
//# sourceMappingURL=index.d.ts.map
|