@kanyun-ai-infra/band-plugin-react 0.0.0-stage → 0.1.2
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/chunk-47BPPTXZ.js +8 -0
- package/dist/chunk-6VMUZ4PQ.js +26 -0
- package/dist/chunk-HX653UQN.js +729 -0
- package/dist/chunk-IJBJEU3H.js +56 -0
- package/dist/chunk-VKASR4EL.js +46 -0
- package/dist/chunk-X32B5VUS.js +107 -0
- package/dist/components.d.ts +313 -0
- package/dist/components.js +94 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.js +18 -0
- package/dist/first-delivery.d.ts +52 -0
- package/dist/first-delivery.js +28 -0
- package/dist/image-view.d.ts +153 -0
- package/dist/image-view.js +788 -0
- package/dist/index.d.ts +1311 -0
- package/dist/index.js +5796 -0
- package/dist/scroll.d.ts +20 -0
- package/dist/scroll.js +6 -0
- package/dist/stopped-turn.d.ts +8 -0
- package/dist/stopped-turn.js +6 -0
- package/dist/upgrade-text.d.ts +81 -0
- package/dist/upgrade-text.js +9 -0
- package/package.json +64 -4
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1311 @@
|
|
|
1
|
+
import { ThreadStatus, Comment, formatByteSize, ReactionEmoji, Reaction, Actor, MemoryChange, SystemEvent } from '@kanyun-ai-infra/band-contracts';
|
|
2
|
+
export { REACTION_EMOJI, Reaction, ReactionEmoji } from '@kanyun-ai-infra/band-contracts';
|
|
3
|
+
import { MemberView, Anchor, TurnState, StageRunSummary, GateState, Version, ProjectCtx, ThreadView, Comment as Comment$1, Dispose, HTMLElementLike, AppCtx, AppData, ArtifactRole, EventPattern, RouteState, ProjectDeletedState, ATTACHMENT_LIMITS, MessageExtras, UploadedAttachment, ProjectApi, Capability, Connector, ProjectAttachment } from '@kanyun-ai-infra/band-plugin-sdk';
|
|
4
|
+
export { Capability, Connector, ImeKeyEvent, imeOwns, withImeGuard } from '@kanyun-ai-infra/band-plugin-sdk';
|
|
5
|
+
export { stoppedTurnText } from './stopped-turn.js';
|
|
6
|
+
export { UPGRADE_TEXT, UpgradeProjectRef, upgradeErrorText } from './upgrade-text.js';
|
|
7
|
+
export { FIRST_DELIVERY_LABEL, FIRST_DELIVERY_PICK, FIRST_DELIVERY_REMOVE, FIRST_DELIVERY_REPLACED, FIRST_DELIVERY_SUBMIT, FirstDelivery, FirstDeliveryEntry, FirstDeliverySlot, fileSizeText, firstDeliveryEntry, firstDeliveryFilesText, firstDeliveryMissing, firstDeliveryMissingText, firstDeliveryNotStoreNote, firstDeliverySlots } from './first-delivery.js';
|
|
8
|
+
import * as react from 'react';
|
|
9
|
+
import { ReactNode, CompositionEvent, RefObject, KeyboardEvent } from 'react';
|
|
10
|
+
export { FORBIDDEN_CODE, NETWORK_LOST, NETWORK_LOST_CODE, errorText, failedBecause, isForbidden, isNetworkLost } from './errors.js';
|
|
11
|
+
import { SettingsGroup, SettingsBackTarget, SettingsTarget } from './components.js';
|
|
12
|
+
export { AgentAvatar, Avatar, BandMark, ErrorNote, Glyph, GlyphKind, INSTRUMENTS, InfoNote, Instrument, LogoLockup, PaneHeader, SettingsActions, SettingsBack, SettingsChoices, SettingsDanger, SettingsDangerRow, SettingsDialog, SettingsEmpty, SettingsFact, SettingsFacts, SettingsField, SettingsFieldProps, SettingsForm, SettingsHead, SettingsLayout, SettingsLoading, SettingsNavItem, SettingsNoAccess, SettingsNotice, SettingsReadError, SettingsRow, SettingsRows, SettingsSaveState, SettingsSaved, SettingsSection, SettingsSingle, WorkshopEmblem, WorkshopIcon, agentInstrument, avatarInitial, avatarTone, instrumentOf, memberOrder, settingsLinkHandler } from './components.js';
|
|
13
|
+
import { ModelCredential, ProjectAgentModels } from '@kanyun-ai-infra/band-contracts/api';
|
|
14
|
+
export { MODEL_CREDENTIAL_CHANGED, MODEL_NOT_CONFIGURED, MODEL_PROJECT_CONSENT_PENDING, MODEL_SELECTION_REQUIRED, MODEL_SERVICE_NOT_FOUND } from '@kanyun-ai-infra/band-contracts/api';
|
|
15
|
+
export { scrollIntoPanel } from './scroll.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 插件共用的纯函数:线程状态的文字与颜色、@ 解析、队列位置。全平台一致(v8 §6 内核规则)。
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
declare const STATUS_CHIP: Record<ThreadStatus, string>;
|
|
22
|
+
/**
|
|
23
|
+
* 意见卡片上「落在哪」的一句话:优先 `payload.label`;整份产物写「整份产物」,项目级(建项目时的首条需求)写「整个项目」;
|
|
24
|
+
* 没存 label 的旧意见(如拆包前 viewer-media 的图片点位)给文件名,不把类型串露给人看。
|
|
25
|
+
*/
|
|
26
|
+
declare function anchorLabel(anchor: Pick<Anchor, "kind" | "payload">): string;
|
|
27
|
+
/**
|
|
28
|
+
* 上一回合没做成的原因:回合栏「回合 #N 没做完」后面那一句人话,取宿主给的 `last.reason`(旧宿主不填,见 protocol/CHANGELOG)。交付了、人停下的、
|
|
29
|
+
* 没有回合、宿主没记下原因(或是旧宿主)都返回 undefined,调用方只说没做成,不留空的「:」。
|
|
30
|
+
* 主区的第一版说明和回执缺失的提示共用这一个,别再各写一份。
|
|
31
|
+
*/
|
|
32
|
+
declare function failureReason(last: TurnState["last"]): string | undefined;
|
|
33
|
+
/** 阶段还没做出第一版、上一回合就结束了:停下了,还是没做成(带原因);重试重跑 `retryStage`。 */
|
|
34
|
+
type FirstTurnEnd = {
|
|
35
|
+
how: "stopped";
|
|
36
|
+
retryStage: string;
|
|
37
|
+
number: number;
|
|
38
|
+
}
|
|
39
|
+
/** `retryStage` 缺省 = 重试也不会好(宿主按失败码判的永久失败),只说没做成和原因,不给重试。 */
|
|
40
|
+
| {
|
|
41
|
+
how: "failed";
|
|
42
|
+
retryStage?: string;
|
|
43
|
+
reason?: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* 第一版之前上一回合怎么结束的:停下了 / 没做成,否则 undefined(还没开始、正在做、旧宿主不给 `retryStage`),
|
|
47
|
+
* 调用方照原来的说法写。主区的第一版说明、阶段回看、流程条、对话框的「发送并重新开始」都读它,别再各按
|
|
48
|
+
* `stoppedBy` / `outcome` 判一份。宿主保证回合已结束且 `stoppedBy` 有值 ⟺ 确实是停下结束的(点了停止却因别的原因
|
|
49
|
+
* 结束的,收口时清掉),这里照读。
|
|
50
|
+
*
|
|
51
|
+
* 给了 `stage` 就只认这个阶段:上一回合和阶段之间只有 `retryStage` 这一条线(`last` 不带阶段),而且阶段还没开始
|
|
52
|
+
* (`ready` / `blocked`)——宿主对过期(`stale`)、已经有版本的阶段也给 `retryStage`,那不是「没做出第一版」。
|
|
53
|
+
* 不给 `stage` 时调用方自己保证项目里还没有版本(主区的第一版说明)。
|
|
54
|
+
*/
|
|
55
|
+
declare function firstTurnEnd(turn: TurnState | null | undefined, stage?: Pick<StageRunSummary, "stage" | "status">): FirstTurnEnd | undefined;
|
|
56
|
+
/** `firstTurnEnd` 的一个词:流程条胶囊、阶段回看标题下用,和回合栏「没做完」同一个说法。 */
|
|
57
|
+
declare function turnEndWord(end: Pick<FirstTurnEnd, "how">): string;
|
|
58
|
+
/**
|
|
59
|
+
* 回执下面那行文件:只写文件名。回执的 `files` 照协议第 8 节写:代码是仓库根目录起的相对路径(`src/Btn.vue`),
|
|
60
|
+
* store 产物写 zip 里的路径(`<类型>/<键>/<文件>`,如 `work/main/codes.md`),这些路径对看回执的人没意义。
|
|
61
|
+
* 规则:每个文件取在本条回执里唯一的最短尾部——不重名的只写文件名,重名的往上带父目录,带到能区分为止
|
|
62
|
+
* (`about/index.html`、`blog/index.html`);完全相同的路径只写一次;按第一次出现的顺序。字符串上分不出哪段是
|
|
63
|
+
* `<类型>/<键>`,所以它们只在恰好是唯一区别时出现:扇出的几份改了同一个文件(`main/index.html`、
|
|
64
|
+
* `alt/index.html`),或不同类型同键同文件(只能写全)。以 `.agent/band-outputs/` 开头的是工作区路径,协议不该
|
|
65
|
+
* 这么写,兜底先去掉。对话、意见卡、评论框与「复制为 Markdown」共用这一个。
|
|
66
|
+
*/
|
|
67
|
+
declare function receiptFileNames(files: readonly string[]): string[];
|
|
68
|
+
/** 排着的消息被人停下后回到未处理:写清这句话没被执行,不和「待处理」混在一起。 */
|
|
69
|
+
declare const STOPPED_UNDONE = "\u6CA1\u505A\uFF0C\u5DF2\u505C\u4E0B";
|
|
70
|
+
/**
|
|
71
|
+
* 这条线程最近一次结果是不是「回合被人停下」:线程尾部(回执、停下事件,按时间)最后一条是 `turn.stopped`。
|
|
72
|
+
* 只在状态是 open 时有意义;之后有了回执就不算,重新交给 Agent 后状态也不再是 open。
|
|
73
|
+
*/
|
|
74
|
+
declare function wasStopped(comments: readonly Pick<Comment, "kind" | "system">[] | undefined): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* 线程状态的文字;排队时带位次,处理中带 Agent 名。位次按回合数:同一个修改请求的几条意见同一回合做,位次相同,
|
|
77
|
+
* 写明几条一起(「排队 · 第 1 位(2 条一起)」),免得人以为排了两个第 1 位(band/lead 10-29)。
|
|
78
|
+
*/
|
|
79
|
+
declare function statusText(status: ThreadStatus, opts?: {
|
|
80
|
+
position?: number;
|
|
81
|
+
together?: number;
|
|
82
|
+
agent?: string;
|
|
83
|
+
stopped?: boolean;
|
|
84
|
+
}): string;
|
|
85
|
+
/** 版本的显示名 `meta.label`(如 v4)。经 ctx 拿到的版本宿主已补好(内核的显示缺省);id 只是 `meta` 不带类型时的兜底。 */
|
|
86
|
+
declare function versionLabel(v: Pick<Version, "id" | "meta">): string;
|
|
87
|
+
/**
|
|
88
|
+
* 线程在队列里的位置:`position` 是它的修改请求排第几(从 1 起,一个修改请求一个回合),`together` 是这个修改请求
|
|
89
|
+
* 一共几条意见。不在队列里返回 undefined。
|
|
90
|
+
*/
|
|
91
|
+
declare function queueSlot(turn: TurnState | undefined, threadId: string): {
|
|
92
|
+
position: number;
|
|
93
|
+
together: number;
|
|
94
|
+
} | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* 钉着旧版插件的项目还在 import 它(共享模块永远由宿主当前构建提供,删导出会让旧插件加载失败)。新代码用 `queueSlot`。
|
|
97
|
+
*
|
|
98
|
+
* @deprecated 只为已发布的旧插件保留,行为与删除前一致;删除要走协议大版本。
|
|
99
|
+
*/
|
|
100
|
+
declare function queuePosition(turn: TurnState | undefined, threadId: string): number | undefined;
|
|
101
|
+
/** 输入框光标前正在打的 `@xxx`:返回查询词与 `@` 的位置;不在 @ 里返回 null。 */
|
|
102
|
+
declare function mentionQuery(text: string, caret: number): {
|
|
103
|
+
query: string;
|
|
104
|
+
start: number;
|
|
105
|
+
} | null;
|
|
106
|
+
/** @ 候选:人在前、Agent 在后,按显示名或 id 前缀匹配。 */
|
|
107
|
+
declare function mentionCandidates(members: readonly MemberView[], query: string): MemberView[];
|
|
108
|
+
/**
|
|
109
|
+
* 正文里 @ 到的成员(含 Agent)的 actor id,按出现顺序去重。
|
|
110
|
+
* 每个 `@` 取最长的那个显示名(「@李然」不算 @李);名字后紧跟英文字母或数字不算(「@Rondo2」不是 @Rondo)。
|
|
111
|
+
*/
|
|
112
|
+
declare function mentionsIn(text: string, members: readonly MemberView[]): string[];
|
|
113
|
+
/** 文字里 @ 到的第一个 Agent:交给它,且「交给 AI」的勾选框自动勾上(v8 §7 @Agent)。 */
|
|
114
|
+
declare function agentIn(text: string, members: readonly MemberView[]): MemberView | undefined;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 建项目表单上目标仓库输入框标签旁的灰字:从建项目的人的角度说这个仓库放什么(「使用说明和教具网页会提交到这里」,
|
|
118
|
+
* `label` 由服务端按存在里面的产物类型拼好);工坊没给显示名时写仓库的键。标签本身只写「仓库地址」。主页和工坊页两个表单共用。
|
|
119
|
+
*/
|
|
120
|
+
declare function repoFieldHint(repo: {
|
|
121
|
+
name: string;
|
|
122
|
+
label?: string;
|
|
123
|
+
}): string;
|
|
124
|
+
/** 目标仓库输入框的示例占位:example 域名,不写真实的内网仓库。 */
|
|
125
|
+
declare const REPO_URL_EXAMPLE = "\u4F8B\u5982 https://gitlab.example.com/band-workshops/my-target";
|
|
126
|
+
/**
|
|
127
|
+
* 中文句子里嵌一个名字(角色、成员、阶段):名字头尾是字母或数字时补一个空格(「以 owner 身份批准」),
|
|
128
|
+
* 汉字不补(「以审核人身份批准」)。
|
|
129
|
+
*/
|
|
130
|
+
declare function inline(name: string): string;
|
|
131
|
+
/**
|
|
132
|
+
* 门禁要求的一句话,按角色说,与引擎判通过同一口径(v8 §4):`any` 这些角色里任一人;`all` 每个角色各一人
|
|
133
|
+
* (不是每个人);法定人数数不同的人。`roles` 是显示名,没有角色时调用方自己写。主页「待我处理」、资料库分组头、
|
|
134
|
+
* 工坊页流程图共用;`mode` 也收主页拿到的字符串形态(`quorum:N`)。
|
|
135
|
+
*/
|
|
136
|
+
declare function gateRule(roles: readonly string[], mode: GateState["mode"] | string): string;
|
|
137
|
+
/**
|
|
138
|
+
* 同上,但不带「批准」两个字:流程图里那一条前面已经写了「批准:」,再接「老师一人批准」会重复
|
|
139
|
+
* (走查 C2:「批准:老师一人」)。
|
|
140
|
+
*/
|
|
141
|
+
declare function gateWho(roles: readonly string[], mode: GateState["mode"] | string): string;
|
|
142
|
+
/**
|
|
143
|
+
* 贴着按钮弹的弹层(宽 width)在视口里的左边(DESIGN.md「弹层贴着触发它的元素」):先和按钮左边对齐;往右放不下就和
|
|
144
|
+
* 按钮右边对齐;两边都放不下(手机上按钮在中间)夹进视口,左右各留 gutter。
|
|
145
|
+
*/
|
|
146
|
+
declare function popoverLeft(button: {
|
|
147
|
+
left: number;
|
|
148
|
+
right: number;
|
|
149
|
+
}, width: number, viewport: number, gutter?: number): number;
|
|
150
|
+
|
|
151
|
+
declare function FirstDeliveryAction({ ctx, stage, }: {
|
|
152
|
+
ctx: ProjectCtx;
|
|
153
|
+
stage: Pick<StageRunSummary, "stage" | "failure">;
|
|
154
|
+
}): react.JSX.Element | null;
|
|
155
|
+
|
|
156
|
+
/** 三个线程界面共用确认人规则,调用引擎独立纯函数;写操作仍由锁定插件交服务端校验。 */
|
|
157
|
+
|
|
158
|
+
declare function threadConfirmation(thread: Pick<ThreadView, "createdBy" | "sentBy">, member: Pick<ProjectCtx["member"], "id" | "can">, members: readonly MemberView[] | undefined): {
|
|
159
|
+
allowed: boolean;
|
|
160
|
+
hint: string;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/** 一次读多条线程的评论:有 `commentsOf` 就一次,旧宿主没有时逐条读。对话流、意见栏共用。 */
|
|
164
|
+
declare function readComments(ctx: Pick<ProjectCtx, "threads">, ids: readonly string[]): Promise<Record<string, Comment$1[]>>;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 挂载函数:在挂载点里放一个自己的容器、开一个 React root,清理时卸载。ctx 与参数的类型由调用方给,
|
|
168
|
+
* 插件协议的挂载面(`defineSurface`)拿到的参数是 `{ owner, config, matched, entry }`。
|
|
169
|
+
* 外面包一层错误边界(`SurfaceBoundary`):渲染期抛错只画这一块的错误卡(`entry` 的插件名与标题)和「重试」。
|
|
170
|
+
*
|
|
171
|
+
* 宿主本身可能是 React 组件,清理发生在它的提交阶段;同步卸载另一个 root 会被 React 推迟,
|
|
172
|
+
* 而宿主随后会清空挂载点。所以 root 开在自己的容器上,卸载放到下一个任务。
|
|
173
|
+
*
|
|
174
|
+
* `render` 的第三个参数是挂载点本身(`ctx.anchors.host` 的矩形相对它)。
|
|
175
|
+
*/
|
|
176
|
+
declare function reactMount<C, P>(render: (ctx: C, props: P, mount: HTMLElement) => ReactNode): (ctx: C, el: HTMLElementLike, props: P) => Dispose;
|
|
177
|
+
/**
|
|
178
|
+
* 自己声明的插槽在这个位置可见的贡献(见 CHANGELOG `ctx.slots.entries`),贡献增减或字段变了时刷新。
|
|
179
|
+
* 内容不变时返回同一个数组,可以放进依赖列表。贡献是清单里的纯数据,按 JSON 比较。
|
|
180
|
+
*/
|
|
181
|
+
declare function useSlotEntries<E extends {
|
|
182
|
+
key: string;
|
|
183
|
+
}>(ctx: {
|
|
184
|
+
slots: {
|
|
185
|
+
entries(slot: string): readonly E[];
|
|
186
|
+
subscribe(slot: string, fn: () => void): Dispose;
|
|
187
|
+
};
|
|
188
|
+
}, slot: string): readonly E[];
|
|
189
|
+
/**
|
|
190
|
+
* 按条目挂载的插槽里,挂在这一条上的贡献:贡献的 `field` 字段没写的挂在每一条上,写了的只挂在值相等的那条上
|
|
191
|
+
* (`band-stages/stage.extras` 的 `stage`、`band-artifacts/item.badges` 的 `artifact-type`)。
|
|
192
|
+
*/
|
|
193
|
+
declare function entriesFor<E extends {
|
|
194
|
+
meta: Record<string, unknown>;
|
|
195
|
+
}>(entries: readonly E[], field: string, value: string): E[];
|
|
196
|
+
/**
|
|
197
|
+
* 在 React 里留一个挂载点,把 `mount` 挂进去(如 `ctx.slots.mount(el, 插槽, …)`);`deps` 变了重挂,
|
|
198
|
+
* 卸载时调返回的清理函数。插槽的声明者用它在自己的界面里渲染插槽。
|
|
199
|
+
*/
|
|
200
|
+
declare function Mount({ mount, deps, className, ...data }: {
|
|
201
|
+
mount: (el: HTMLElement) => undefined | Dispose;
|
|
202
|
+
deps: readonly unknown[];
|
|
203
|
+
className?: string;
|
|
204
|
+
} & {
|
|
205
|
+
[k: `data-${string}`]: string | undefined;
|
|
206
|
+
}): react.JSX.Element;
|
|
207
|
+
/**
|
|
208
|
+
* 读一份数据,并在服务端发来相关事件时重读。`pattern` 照 ctx.events 的写法(`thread.*`、`*`),可以给多个。
|
|
209
|
+
* 类型是 {@link EventPattern}:拼错的事件名(如 `turn.ended`——那是观测日志名,事件叫 `turn.delivered` /
|
|
210
|
+
* `turn.failed`)tsc 直接报错(#1862 r1 裁定①)。同一组 `deps` 下重读期间、读失败时都保留上一份数据,
|
|
211
|
+
* 把错误给调用方显示。`deps`(或 `ctx`)变了(比如换了产物)时旧的一份和旧的错误都不再返回,回到 undefined
|
|
212
|
+
* 直到新的读完,免得把上一份产物的数据当成这一份画出来。
|
|
213
|
+
*
|
|
214
|
+
* `keepPrevious`:数据按条目 id 取、换了 deps 上一份对没变的条目仍然对时(比如 deps 带着线程状态,
|
|
215
|
+
* 评论按线程 id 取),给 true,换 deps 时不闪空;错误照样只给当前 deps 的。`ctx` 换了时不留。
|
|
216
|
+
*/
|
|
217
|
+
declare function useCtxData<T>(ctx: Pick<ProjectCtx, "events">, load: () => Promise<T>, deps: readonly unknown[], pattern?: EventPattern | readonly EventPattern[], options?: {
|
|
218
|
+
keepPrevious?: boolean;
|
|
219
|
+
}): {
|
|
220
|
+
data: T | undefined;
|
|
221
|
+
error: string | null;
|
|
222
|
+
reload: () => void;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* 这份产物是交付物还是过程文档(1.2.0,`ArtifactView.role`),版本变了重读。没读到(或没给 id)时是
|
|
226
|
+
* undefined:调用方按「还不知道」处理,别先当交付物把提意见的入口开出来、读到了再收回。
|
|
227
|
+
*/
|
|
228
|
+
declare function useArtifactRole(ctx: Pick<ProjectCtx, "events" | "artifacts">, artifactId: string | undefined): ArtifactRole | undefined;
|
|
229
|
+
/**
|
|
230
|
+
* 读一份应用数据(`ctx.app.data`),数据变了(`data.subscribe`:建了项目、标了已读、别人的动作)时重读。
|
|
231
|
+
* 第一次读完之前 `data` 是 undefined;之后同一组 `deps` 下重读期间保留上一份,不闪空。`deps` 变了(比如换了
|
|
232
|
+
* 工坊作用域)时旧的一份不再返回,回到 undefined 直到新的读完,免得把上一个作用域的数据当成这一个的画出来。
|
|
233
|
+
* 读失败时保留上一份,给出错误。
|
|
234
|
+
*/
|
|
235
|
+
declare function useAppData<T>(ctx: Pick<AppCtx, "app">, load: (data: AppData) => Promise<T>, deps: readonly unknown[]): {
|
|
236
|
+
data: T | undefined;
|
|
237
|
+
error: string | null;
|
|
238
|
+
reload: () => void;
|
|
239
|
+
};
|
|
240
|
+
/** 当前路由(`ctx.app.route()`),换页、改写地址时刷新。 */
|
|
241
|
+
declare function useRoute(ctx: Pick<AppCtx, "app">): RouteState;
|
|
242
|
+
/** 线程列表、队列与回合状态随这些事件变:线程本身、交给 AI、回合进度。 */
|
|
243
|
+
declare const THREAD_EVENTS: readonly ["thread.*", "comment.*", "change.*", "turn.*"];
|
|
244
|
+
/** 流程、门禁、阶段参数这类面板的刷新事件。 */
|
|
245
|
+
declare const STAGE_EVENTS: readonly ["run.*", "stage.*", "gate.*", "external.*", "turn.*"];
|
|
246
|
+
/**
|
|
247
|
+
* 项目成员:成员变动(`member.*`)时重读;流程实例开始(`run.started`)时也重读,干活的 Agent 从这时起才是成员
|
|
248
|
+
* (空项目交出第一条需求时)。不跟着线程、回合事件刷。
|
|
249
|
+
*/
|
|
250
|
+
declare function useMembers(ctx: Pick<ProjectCtx, "events" | "members">): readonly MemberView[];
|
|
251
|
+
/** 插件内的一小块状态:activate 里的请求处理与挂载面之间共享(每个内核一份插件实例)。 */
|
|
252
|
+
declare function createState<T>(initial: T): {
|
|
253
|
+
get: () => T;
|
|
254
|
+
set(next: T): void;
|
|
255
|
+
subscribe(fn: () => void): () => void;
|
|
256
|
+
};
|
|
257
|
+
type PluginState<T> = ReturnType<typeof createState<T>>;
|
|
258
|
+
declare function useStateOf<T>(s: PluginState<T>): T;
|
|
259
|
+
/** `10-21 09:40`:界面上的本地时间,与侧栏共用钟点格式。 */
|
|
260
|
+
declare function shortTime(iso: string): string;
|
|
261
|
+
/** 本地时区的日期:`10-21`,`{ year: true }` 写 `2026-10-21`。不能直接切 ISO 字符串,那是 UTC 日期。 */
|
|
262
|
+
declare function localDay(iso: string, opts?: {
|
|
263
|
+
year?: boolean;
|
|
264
|
+
}): string;
|
|
265
|
+
/** 列表行尾的时间:今天写 `09:40`,昨天写「昨天」,今年写 `10/21`,更早写 `2025/10/21`。按本地时区。 */
|
|
266
|
+
declare function shortWhen(iso: string, now: Date): string;
|
|
267
|
+
/** 显示名;成员表里还没有(刚开始、成员表没重读完)时按 `agentDisplayName` 的规则:Rondo 写「Rondo」,其余写 id。 */
|
|
268
|
+
declare function memberName(members: readonly MemberView[] | undefined, id: string): string;
|
|
269
|
+
/** 成员的第一个角色的显示名;Agent 没有角色:Rondo 写「默认 Agent」,其他 Agent 写「Agent」(DESIGN.md「Rondo」)。 */
|
|
270
|
+
declare function roleLabel(members: readonly MemberView[] | undefined, id: string): string;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 当前选中的产物(官方面板共用)。产物列表写 `selection`(kind: "artifact"),意见栏读它筛选。
|
|
274
|
+
* 选中槽是所有插件共享的,别的插件写锚点、实体选中时不能把产物的选择冲掉:
|
|
275
|
+
* 只认 kind 为 artifact 的写入,记住最后一次;从没选过时跟着当前版本所属的产物。
|
|
276
|
+
*/
|
|
277
|
+
declare function useSelectedArtifact(ctx: Pick<ProjectCtx, "selection" | "version">): string | null;
|
|
278
|
+
/** 共享选中里的实体。 */
|
|
279
|
+
interface SelectedEntity {
|
|
280
|
+
entityType: string;
|
|
281
|
+
id: string;
|
|
282
|
+
artifactId?: string;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 当前选中的实体(`{ kind: "entity" }`)。别的插件写锚点、时间点时保留上一次的实体;
|
|
286
|
+
* 选中清空、换成产物,或当前版本换到了别的产物上时清掉。
|
|
287
|
+
*/
|
|
288
|
+
declare function useSelectedEntity(ctx: Pick<ProjectCtx, "selection" | "version">): SelectedEntity | null;
|
|
289
|
+
/** 线程已经交给 agent(排着或在做)时再点「交给」:不是错误,告诉人不用再做什么。 */
|
|
290
|
+
declare function alreadyHandedText(agent: string): string;
|
|
291
|
+
/**
|
|
292
|
+
* 意见栏与对话流共用:勾选几条待处理的意见,一起交给 Agent(`ctx.propose.changeRequest`)。
|
|
293
|
+
* 只留下仍是待处理的勾选(别人先交了、线程被关掉,勾选自然失效),按意见编号排好再交。
|
|
294
|
+
* `anchor` 是最近勾上、还勾着的那条:「交给 …(N 条)」画在它旁边,勾完手不用挪远(取消了它就退到编号最大的那条)。
|
|
295
|
+
*/
|
|
296
|
+
declare function useHandToAgent(ctx: Pick<ProjectCtx, "propose" | "member" | "threads">, threads: readonly ThreadView[],
|
|
297
|
+
/** 说明里 agent 怎么叫;调用方多半有 `agentLabel(members, …)` */
|
|
298
|
+
agentName?: string): {
|
|
299
|
+
selected: ReadonlySet<string>;
|
|
300
|
+
picked: string[];
|
|
301
|
+
anchor: string | null;
|
|
302
|
+
toggle: (id: string) => void;
|
|
303
|
+
send: () => Promise<void>;
|
|
304
|
+
sendOne: (id: string) => Promise<void>;
|
|
305
|
+
busy: boolean;
|
|
306
|
+
error: string | null;
|
|
307
|
+
notice: string | null;
|
|
308
|
+
canSend: boolean;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* agent 的显示名:项目成员里有它就写它的显示名,没有(成员还没读到)时按 `agentDisplayName` 的规则(Rondo 写「Rondo」,别的写 id)。
|
|
312
|
+
* 调用方传哪个 agent 就写哪个;目前多数地方传工坊的缺省 `ctx.project.agent`,按阶段取的 agent 见 `StageRunSummary.agent`。
|
|
313
|
+
*/
|
|
314
|
+
declare function agentLabel(members: readonly MemberView[], agent: string): string;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 边打边搜、边打边过滤的输入框:拿去搜索、过滤的字(`settled`)在组字期间(拼音还没选成字)停在组字前,
|
|
318
|
+
* 组字结束才跟上,免得半截拼音(「luod」)闪一下「没有叫……」。输入框照常受控(`text` 是输入框里的字,含拼音),
|
|
319
|
+
* 再展开 `imeProps`;搜索、过滤、空结果文案都用 `settled`。
|
|
320
|
+
*
|
|
321
|
+
* 组字结束时两种浏览器的次序不同:Chrome 先派最后一次 input(还在组字中)、再 compositionend;Safari 先
|
|
322
|
+
* compositionend、再补一次不在组字中的 input。所以组字结束取输入框当下的值,`text` 还没跟上(Safari 那一下)时
|
|
323
|
+
* 先用它,`text` 一变就回到 `text`。
|
|
324
|
+
*/
|
|
325
|
+
declare function useSettledText(text: string): {
|
|
326
|
+
settled: string;
|
|
327
|
+
imeProps: {
|
|
328
|
+
onCompositionStart(): void;
|
|
329
|
+
onCompositionEnd(e: CompositionEvent<HTMLInputElement | HTMLTextAreaElement>): void;
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* 组字状态,给不能只看一段文字的地方(按光标前的字找 @、# 候选):组字期间 `composing.current` 为 true,调用方别按
|
|
334
|
+
* 半截拼音找;组字结束调 `onEnd(输入框)`,按选好的字再找一次(两种浏览器的次序见 `useSettledText`,都从输入框取)。
|
|
335
|
+
*/
|
|
336
|
+
declare function useComposition(onEnd: (el: HTMLInputElement | HTMLTextAreaElement) => void): {
|
|
337
|
+
composing: {
|
|
338
|
+
readonly current: boolean;
|
|
339
|
+
};
|
|
340
|
+
imeProps: {
|
|
341
|
+
onCompositionStart(): void;
|
|
342
|
+
onCompositionEnd(e: CompositionEvent<HTMLInputElement | HTMLTextAreaElement>): void;
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
/** 下拉里的一项。`group` 相同的排在一段,段的顺序按它第一次出现的顺序。 */
|
|
347
|
+
interface ComboboxItem {
|
|
348
|
+
value: string;
|
|
349
|
+
label: string;
|
|
350
|
+
group?: string;
|
|
351
|
+
/** 行尾的补充说明(部门、类型),用等宽字体。 */
|
|
352
|
+
meta?: string;
|
|
353
|
+
/** label 之外用来搜索的文字(部门、拼音备注),不进占位提示。 */
|
|
354
|
+
keywords?: string;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* 可搜索的单选 / 多选(样张 §2「Combobox」)。键盘:↑↓ 移动、回车选中、「空格」在多选里切换选中、
|
|
358
|
+
* Esc 关闭、输入过滤;退格在空输入时删掉最后一个已选。
|
|
359
|
+
*
|
|
360
|
+
* 空格只在查询为空时切换选中:查询里带了字时空格照常输入,否则「Wang Min」这种名字搜不了
|
|
361
|
+
* (样张只演示了空查询下的多选,这一点按能打字优先定)。
|
|
362
|
+
*/
|
|
363
|
+
declare function Combobox({ label, items, value, onChange, multiple, placeholder, emptyText, onCreate, createLabel, disabled, }: {
|
|
364
|
+
/** 输入框的无障碍名,也是空结果那句「没有匹配的<label>」里的名字。 */
|
|
365
|
+
label: string;
|
|
366
|
+
items: readonly ComboboxItem[];
|
|
367
|
+
/** 受控:已选的值,按选中的先后。 */
|
|
368
|
+
value: readonly string[];
|
|
369
|
+
onChange(next: readonly string[]): void;
|
|
370
|
+
/** 多选:回车与空格切换选中、列表不关;单选:回车选中并关闭。 */
|
|
371
|
+
multiple?: boolean;
|
|
372
|
+
placeholder?: string;
|
|
373
|
+
/** 空结果那一行的整句,缺省「没有匹配的<label>」。 */
|
|
374
|
+
emptyText?: string;
|
|
375
|
+
/**
|
|
376
|
+
* 查询非空、且没有名字正好相同的候选时,列表末尾多一行「新建」。选中它时把这句查询交回调用方
|
|
377
|
+
* (建完由调用方把新值放进 `value`)。
|
|
378
|
+
*/
|
|
379
|
+
onCreate?(name: string): void;
|
|
380
|
+
/** 「新建」那行的写法,缺省「新建「<查询>」」。 */
|
|
381
|
+
createLabel?(name: string): string;
|
|
382
|
+
disabled?: boolean;
|
|
383
|
+
}): react.JSX.Element;
|
|
384
|
+
/**
|
|
385
|
+
* 一段文字拆成标签:按逗号(半角、全角)、换行、制表符拆,去掉首尾空白与空串,**不去重**
|
|
386
|
+
* (重复要提示,不能悄悄吃掉)。纯函数,单测与 TagInput 共用。
|
|
387
|
+
*/
|
|
388
|
+
declare function splitTags(text: string): string[];
|
|
389
|
+
/**
|
|
390
|
+
* 数组值(样张 §2「Tag Input」):值受控,回车或逗号确认一个,粘贴带分隔符时整段拆开;重复的值不加入,
|
|
391
|
+
* 已有的那个闪一下红底并在下面写一句(「「x」重复了,已跳过」,1.8 秒后退回);输入框空着时退格删最后一个。
|
|
392
|
+
*
|
|
393
|
+
* 输入法:回车、退格都经 `withImeGuard`——组字中选字的回车不能当成「加一个标签」。
|
|
394
|
+
*/
|
|
395
|
+
declare function TagInput({ label, value, onChange, placeholder, hint, disabled, id, }: {
|
|
396
|
+
/** 输入框的无障碍名。 */
|
|
397
|
+
label: string;
|
|
398
|
+
/** 受控:标签,按加入的先后。 */
|
|
399
|
+
value: readonly string[];
|
|
400
|
+
onChange(next: readonly string[]): void;
|
|
401
|
+
placeholder?: string;
|
|
402
|
+
/** 常态那句说明(「粘贴「五年级, 分数」会拆成两个」);重复时换成提示,1.8 秒后退回这句。 */
|
|
403
|
+
hint?: string;
|
|
404
|
+
disabled?: boolean;
|
|
405
|
+
id?: string;
|
|
406
|
+
}): react.JSX.Element;
|
|
407
|
+
/** 筛选项:一段里的一个值。 */
|
|
408
|
+
interface FilterOption {
|
|
409
|
+
value: string;
|
|
410
|
+
label: string;
|
|
411
|
+
}
|
|
412
|
+
/** 一段筛选:`key` 是行数据里的字段名。 */
|
|
413
|
+
interface FilterGroup {
|
|
414
|
+
key: string;
|
|
415
|
+
label: string;
|
|
416
|
+
options: readonly FilterOption[];
|
|
417
|
+
}
|
|
418
|
+
/** 一行在各分组上的取值(`row[group.key]`)。 */
|
|
419
|
+
type FilterRow = Readonly<Record<string, string>>;
|
|
420
|
+
/** 已选:分组 key → 选中的值(段内是「或」)。 */
|
|
421
|
+
type FilterSelection = Readonly<Record<string, readonly string[]>>;
|
|
422
|
+
/**
|
|
423
|
+
* 计数(样张 §2「Filter Menu」的 faceted 口径):某个选项的计数 = 在**其他**分组的已选条件下还剩多少行,
|
|
424
|
+
* 也带自己这一段——和产物库的「勾了别的组,这一段的数跟着缩」同一口径。纯函数,单测与 FilterMenu 共用。
|
|
425
|
+
*/
|
|
426
|
+
declare function facetedCount(rows: readonly FilterRow[], groups: readonly FilterGroup[], selection: FilterSelection, groupKey: string, value: string): number;
|
|
427
|
+
/** 按已选筛行:每组内是「或」,组之间是「且」。纯函数。 */
|
|
428
|
+
declare function filterRows(rows: readonly FilterRow[], groups: readonly FilterGroup[], selection: FilterSelection): readonly FilterRow[];
|
|
429
|
+
/**
|
|
430
|
+
* 分组筛选(样张 §2「Filter Menu」)。分组可折叠(组标题是按钮,`aria-expanded`),计数按当前其他分组
|
|
431
|
+
* 的已选算(`facetedCount`),已选的做成 chip 可单个移除,右端「清空」。值受控。
|
|
432
|
+
*
|
|
433
|
+
* 键盘:组标题与每个勾选框都在正常的 Tab 顺序里(勾选框是原生 `<input type="checkbox">`),空格切换;
|
|
434
|
+
* 点组标题只折叠/展开,不改筛选。
|
|
435
|
+
*/
|
|
436
|
+
declare function FilterMenu({ groups, rows, value, onChange, emptyText, }: {
|
|
437
|
+
groups: readonly FilterGroup[];
|
|
438
|
+
/** 用来算计数的行(通常是未筛选的全量;传筛过的会让计数越筛越小)。 */
|
|
439
|
+
rows: readonly FilterRow[];
|
|
440
|
+
value: FilterSelection;
|
|
441
|
+
onChange(next: FilterSelection): void;
|
|
442
|
+
/** 一段里一个选项都没有时那一行,缺省「没有可筛的」。 */
|
|
443
|
+
emptyText?: string;
|
|
444
|
+
}): react.JSX.Element;
|
|
445
|
+
|
|
446
|
+
/** 重跑上一回合没做成或停下的阶段 `stage`(宿主给的 `retryStage`);没有 submit-change 的人置灰(服务端照旧逐动作判)。 */
|
|
447
|
+
declare function Retry({ ctx, stage }: {
|
|
448
|
+
ctx: ProjectCtx;
|
|
449
|
+
stage: string;
|
|
450
|
+
}): react.JSX.Element;
|
|
451
|
+
|
|
452
|
+
declare const STOP_COST = "\u505C\u4E0B\u540E\u8FD9\u4E00\u56DE\u5408\u7684\u7ED3\u679C\u4E0D\u4FDD\u7559\uFF1B\u8981\u662F\u505C\u4E0B\u524D\u5DF2\u7ECF\u505A\u5B8C\uFF0C\u4F1A\u7167\u5E38\u4EA4\u4ED8\u3002";
|
|
453
|
+
/** 排着的消息条数:每个排队项带的线程之和(没有线程的首次产出等不算「消息」)。 */
|
|
454
|
+
declare function queuedMessages(queue: readonly {
|
|
455
|
+
threadIds: readonly string[];
|
|
456
|
+
}[]): number;
|
|
457
|
+
declare function stopQueuedNote(queued: number): string;
|
|
458
|
+
declare function StopTurn({ stop, can, noteClassName, queued, elsewhere, }: {
|
|
459
|
+
/** 真停:回合栏、评论框调 `ctx.collab.stopTurn`,对话流调 `ctx.turns.requestStop`。 */
|
|
460
|
+
stop: () => Promise<void>;
|
|
461
|
+
/** 有没有 submit-change。 */
|
|
462
|
+
can: boolean;
|
|
463
|
+
/** 代价那句话的类名:回合栏用它自己的灰字,状态消息用状态消息的。 */
|
|
464
|
+
noteClassName: string;
|
|
465
|
+
/** 停下后排着的消息条数({@link queuedMessages});大于 0 时在代价后补一句「不受影响」。 */
|
|
466
|
+
queued?: number;
|
|
467
|
+
/** 页面别处已有「停止」:没点开时不画,点开了的确认行照留到人答完。 */
|
|
468
|
+
elsewhere?: boolean;
|
|
469
|
+
}): react.JSX.Element | null;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* 已删除项目(`ctx.project.deleted`)给人看的那句:期限内「项目已删除,<期限> 前可以恢复」,过了说不能再恢复。
|
|
473
|
+
* 对话区输入位、记忆页这类「现在只能看」的地方用它,不写成「你不是成员」「没有权限」(走查分诊 R01b)。
|
|
474
|
+
*/
|
|
475
|
+
declare function deletedProjectText(deleted: Pick<ProjectDeletedState, "restoreUntil">, now?: Date): string;
|
|
476
|
+
/** 还能不能恢复:期限内、宿主给了恢复(只给官方插件)。 */
|
|
477
|
+
declare function canRestoreProject(deleted: ProjectDeletedState | undefined, now?: Date): boolean;
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* 建项目时用哪份模型配置的提示(工坊声明 `userModelKey`)。`off` 与没读到工坊声明不画;
|
|
481
|
+
* `allow` 只在有默认配置时提示(没有就走团队 key,没什么可说);`require` 没有默认配置时项目建不出来,要给去个人设置的入口。
|
|
482
|
+
*/
|
|
483
|
+
declare function modelHintText(policy: "off" | "allow" | "require" | undefined, def: Pick<ModelCredential, "name"> | null): {
|
|
484
|
+
text: string;
|
|
485
|
+
action: boolean;
|
|
486
|
+
} | null;
|
|
487
|
+
/**
|
|
488
|
+
* 建项目表单「模型」小节的固定提示(own-key note 决定 2:建项目时提示一次花费落在谁头上;稿
|
|
489
|
+
* docs/design/model-config-page.md §5)。选了本人名下的一份就写这句;名下没有时换成「现在用工坊的团队 key /
|
|
490
|
+
* 先配一份」,并给个人设置入口——`action` 为 true 时调用方画「我的模型与凭据」。
|
|
491
|
+
*
|
|
492
|
+
* 这句与首页默认配置提示不同:后者同时说明创建即同意(还没有得选),
|
|
493
|
+
* 这句是说选中的这一份花谁的钱。
|
|
494
|
+
*/
|
|
495
|
+
declare const PROJECT_MODEL_SPEND = "\u8FD9\u4E2A\u9879\u76EE\u4EE5\u540E\u6240\u6709\u6210\u5458\u53D1\u8D77\u7684\u56DE\u5408\u90FD\u82B1\u8FD9\u628A key\u3002";
|
|
496
|
+
/**
|
|
497
|
+
* 首页需求框发送键旁那一行短句(走查 C5):框里只说「想做什么」,花费归属挪到这里一句。
|
|
498
|
+
* 全文(创建即同意、去个人设置改)放在这一行的 `title` 里,鼠标停在上面能看到。
|
|
499
|
+
*/
|
|
500
|
+
declare function composerSpendLine(def: Pick<ModelCredential, "name">): string;
|
|
501
|
+
declare function projectModelNote(policy: "allow" | "require", picked: Pick<ModelCredential, "name"> | null): {
|
|
502
|
+
text: string;
|
|
503
|
+
action: boolean;
|
|
504
|
+
};
|
|
505
|
+
/**
|
|
506
|
+
* 名下没有模型配置、部署能自动开通 ModelGate 时,建项目提交前的同意文案(开通 note 决定 1、10)。提交即同意:
|
|
507
|
+
* 写明花费归属(这个项目里所有人发起的回合都花建项目人的个人额度)与「提交后 Band 用你的账号开通」。
|
|
508
|
+
*/
|
|
509
|
+
declare function provisionConsentText(quotaUsd: number): string;
|
|
510
|
+
/** 「模型」小节的标题:`off` 与没开通模型配置的部署不画。 */
|
|
511
|
+
declare const PROJECT_MODEL_HEADING = "\u8FD9\u4E2A\u9879\u76EE\u7528\u54EA\u4EFD\u6A21\u578B\u914D\u7F6E";
|
|
512
|
+
/** 下拉里一项:名字 · 预设 · 末 4 位(key 短于 12 位时没有末 4 位,见父 note 决定 2)。掩码与个人设置同一种写法。 */
|
|
513
|
+
declare function credentialOptionLabel(c: Pick<ModelCredential, "name" | "last4">, presetLabel: string): string;
|
|
514
|
+
/** `null`(部署没开通模型配置)回 `undefined`:不画提示;开通了没有默认配置回 `null`。 */
|
|
515
|
+
declare function defaultOf(r: {
|
|
516
|
+
credentials: readonly Pick<ModelCredential, "name" | "isDefault">[];
|
|
517
|
+
} | null): Pick<ModelCredential, "name"> | null | undefined;
|
|
518
|
+
declare function ModelHint({ ctx, policy, className, }: {
|
|
519
|
+
ctx: AppCtx;
|
|
520
|
+
policy: "off" | "allow" | "require" | undefined;
|
|
521
|
+
/** 宿主页面自己的排版类(工坊页的 `.band-workshops-note`),加在共用类后面。 */
|
|
522
|
+
className?: string;
|
|
523
|
+
}): react.JSX.Element | null;
|
|
524
|
+
|
|
525
|
+
/** 用户文档里「目标仓库」那一页(apps/docs/start/target-repo.md):找谁建、管理员怎么建、建好以后怎么填。 */
|
|
526
|
+
declare const TARGET_REPO_DOCS = "/docs/start/target-repo";
|
|
527
|
+
/**
|
|
528
|
+
* 建项目表单上目标仓库输入框下面那几句。`id` 给输入框的 `aria-describedby` 用:说明那句是 `id`,服务端拒了这个仓库时
|
|
529
|
+
* 那句话(`error`,见 {@link errorRepo})放在上面、id 是 {@link targetRepoErrorId}。M0 只能提交到 Band 建好的目标仓库
|
|
530
|
+
* (服务端建项目时按写入守卫同一条规则查),表单不自己判断地址,也不教人往自己的仓库里加账号([M1] 自填仓库)。
|
|
531
|
+
* 主页和工坊页两个表单共用。
|
|
532
|
+
*/
|
|
533
|
+
declare function TargetRepoNote({ id, error, requestAccessUrl, }: {
|
|
534
|
+
id: string;
|
|
535
|
+
error?: string | undefined;
|
|
536
|
+
/** 服务端拒绝时给的组页面地址({@link errorRequestAccessUrl}):不在组里的人去那里点「Request access」。 */
|
|
537
|
+
requestAccessUrl?: string | undefined;
|
|
538
|
+
}): react.JSX.Element;
|
|
539
|
+
declare function targetRepoErrorId(id: string): string;
|
|
540
|
+
/**
|
|
541
|
+
* 建项目失败时,错在哪一格目标仓库:服务端给用户填的仓库出的错在错误体里带仓库的键(`repo`),宿主的数据层把它放在
|
|
542
|
+
* 错误的 `details` 上。不是这种错时返回 undefined,表单照常把错误写在提示行。
|
|
543
|
+
*/
|
|
544
|
+
declare function errorRepo(e: unknown): string | undefined;
|
|
545
|
+
/** 建项目被拒时服务端给的「申请加入」组页面地址(仓库在工坊 group 下、建项目的人不是成员);只认 https 地址,其余当没有。 */
|
|
546
|
+
declare function errorRequestAccessUrl(e: unknown): string | undefined;
|
|
547
|
+
|
|
548
|
+
type DraftItem = {
|
|
549
|
+
kind: "file";
|
|
550
|
+
/** 草稿内唯一,界面与上传任务用它对上号。 */
|
|
551
|
+
key: string;
|
|
552
|
+
name: string;
|
|
553
|
+
size: number;
|
|
554
|
+
/** 压缩前的字节数,用于说明上传结果。 */
|
|
555
|
+
originalSize?: number;
|
|
556
|
+
mime: string;
|
|
557
|
+
state: "uploading" | "done" | "failed";
|
|
558
|
+
/** 0–1,上传中才有。 */
|
|
559
|
+
progress?: number;
|
|
560
|
+
/** 上传成功后宿主给的附件 id。 */
|
|
561
|
+
attachmentId?: string;
|
|
562
|
+
error?: string;
|
|
563
|
+
/** 谁加的:缺省是用户自己;插件经 `composer.attach` 加的写插件包名。 */
|
|
564
|
+
source?: string;
|
|
565
|
+
} | {
|
|
566
|
+
kind: "ref";
|
|
567
|
+
key: string;
|
|
568
|
+
label: string;
|
|
569
|
+
anchor?: Anchor;
|
|
570
|
+
entityRef?: string;
|
|
571
|
+
threadId?: string;
|
|
572
|
+
versionId?: string;
|
|
573
|
+
source?: string;
|
|
574
|
+
/**
|
|
575
|
+
* 只给人看的一行(引用的原文、元素的文字)。有它的引用在输入框里画成卡片,没有的画成 `#` 胶囊;
|
|
576
|
+
* 不随消息发出(`MessageRef` 没有这个字段)。
|
|
577
|
+
*/
|
|
578
|
+
detail?: string;
|
|
579
|
+
} | {
|
|
580
|
+
/** 一段文字作为附件:粘贴的长文本,或插件给的上下文。 */
|
|
581
|
+
kind: "text";
|
|
582
|
+
key: string;
|
|
583
|
+
label: string;
|
|
584
|
+
text: string;
|
|
585
|
+
source?: string;
|
|
586
|
+
};
|
|
587
|
+
type FileItem = Extract<DraftItem, {
|
|
588
|
+
kind: "file";
|
|
589
|
+
}>;
|
|
590
|
+
type RefItem = Extract<DraftItem, {
|
|
591
|
+
kind: "ref";
|
|
592
|
+
}>;
|
|
593
|
+
interface Draft {
|
|
594
|
+
/** 正文。`@` 提及照旧留在文字里,发出时用 `mentionsIn` 解析。 */
|
|
595
|
+
text: string;
|
|
596
|
+
items: DraftItem[];
|
|
597
|
+
/** 选中的能力 id(`/` 菜单)。 */
|
|
598
|
+
capabilities: string[];
|
|
599
|
+
/** 选中的连接器 id。 */
|
|
600
|
+
connectors: string[];
|
|
601
|
+
/**
|
|
602
|
+
* 落盘时刻(毫秒)。只有从本机存储读回来的草稿才有;老版本写下的草稿没有这个字段,
|
|
603
|
+
* 当作「很久以前」的残留(见 `plugins/comment` 的残留草稿清理)。
|
|
604
|
+
*/
|
|
605
|
+
savedAt?: number;
|
|
606
|
+
}
|
|
607
|
+
/** 上传限额,形状同 `ATTACHMENT_LIMITS`(宿主一般直接传它)。 */
|
|
608
|
+
type FileLimits = {
|
|
609
|
+
readonly [K in keyof typeof ATTACHMENT_LIMITS]: number;
|
|
610
|
+
};
|
|
611
|
+
/** 粘贴的纯文本超过这么多字就折成「粘贴的文本」附件(方案 U4)。 */
|
|
612
|
+
declare const PASTE_FOLD_CHARS = 2000;
|
|
613
|
+
declare function emptyDraft(): Draft;
|
|
614
|
+
/** 有东西可发:正文不空,或至少一项附件 / 引用。能力与连接器本身不算内容。 */
|
|
615
|
+
declare function hasContent(d: Draft): boolean;
|
|
616
|
+
declare function uploading(d: Draft): FileItem[];
|
|
617
|
+
declare function failed(d: Draft): FileItem[];
|
|
618
|
+
/** 文件卡片上的类型字样:扩展名大写(最多 5 位),没有就写「文件」。托盘和消息里的附件共用。 */
|
|
619
|
+
declare function fileExt(name: string): string;
|
|
620
|
+
/** 字节数写成人话:`512 B`、`1.2 MB`。 */
|
|
621
|
+
declare const formatBytes: typeof formatByteSize;
|
|
622
|
+
/** 上传中的图片按压缩后的最大大小预留,已完成的按实际大小。 */
|
|
623
|
+
declare function draftFileBytes(items: readonly DraftItem[]): number;
|
|
624
|
+
interface FileCheck<F> {
|
|
625
|
+
accepted: F[];
|
|
626
|
+
rejected: {
|
|
627
|
+
name: string;
|
|
628
|
+
reason: string;
|
|
629
|
+
}[];
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* 加文件之前核限额:超过个数的、超大的、空文件拒掉并说原因。加入前就拒,不让用户等上传失败。
|
|
633
|
+
* `existing` 是草稿里已有的条数。
|
|
634
|
+
*/
|
|
635
|
+
declare function checkFiles<F extends {
|
|
636
|
+
name: string;
|
|
637
|
+
size: number;
|
|
638
|
+
type: string;
|
|
639
|
+
}>(files: readonly F[], existing: number, limits: FileLimits, existingBytes?: number, prepared?: boolean): FileCheck<F>;
|
|
640
|
+
/**
|
|
641
|
+
* 没传上去的那几个文件写成输入框上方的提示:写清是哪个文件、为什么(原因是宿主给的能照着做的话:上限、配额哪项满了怎么腾位置、
|
|
642
|
+
* 网络断了点重试)。原因相同的合成一行,不同的各一行,最多 `max` 行,再多写「还有 N 个没传上去」(同队列的
|
|
643
|
+
* 「没撤成」,#393)。托盘里图片卡片只有缩略图,原因只能在这里看到。
|
|
644
|
+
*/
|
|
645
|
+
declare function uploadFailureLines(items: readonly DraftItem[], max?: number): string[];
|
|
646
|
+
/** 拒掉的文件合成一句提示。 */
|
|
647
|
+
declare function rejectionText(rejected: readonly {
|
|
648
|
+
name: string;
|
|
649
|
+
reason: string;
|
|
650
|
+
}[]): string | null;
|
|
651
|
+
/** 输入框里的三种唤起字符。 */
|
|
652
|
+
type Trigger = "@" | "#" | "/";
|
|
653
|
+
/**
|
|
654
|
+
* 光标前正在打的 `@xxx`、`#xxx`、`/xxx`。唤起字符要在行首、空白或非 ASCII 字符之后:中文里常连着写
|
|
655
|
+
* 「请@李然」「,@Rondo」,紧跟 ASCII 字符的不算(`a@b` 是邮箱,`a/b` 是路径);
|
|
656
|
+
* `/` 只认整段开头或行首,避免「左/右」这种中文里的斜杠误触。
|
|
657
|
+
*/
|
|
658
|
+
declare function triggerAt(text: string, caret: number, enabled: readonly Trigger[]): {
|
|
659
|
+
trigger: Trigger;
|
|
660
|
+
query: string;
|
|
661
|
+
start: number;
|
|
662
|
+
} | null;
|
|
663
|
+
/** 把 `start..caret` 这段(唤起字符 + 查询词)换成 `insert`,返回新正文与光标位置。 */
|
|
664
|
+
declare function replaceRange(text: string, start: number, caret: number, insert: string): {
|
|
665
|
+
text: string;
|
|
666
|
+
caret: number;
|
|
667
|
+
};
|
|
668
|
+
/** 按 `q` 过滤候选:名字或 id 前缀优先,其次包含。 */
|
|
669
|
+
declare function filterByQuery<T>(items: readonly T[], q: string, keys: (t: T) => string[]): T[];
|
|
670
|
+
/**
|
|
671
|
+
* 存本机前的草稿:传到一半与失败的文件存不下(`File` 不能序列化),丢掉;
|
|
672
|
+
* 已传完的只留附件 id 与元数据。
|
|
673
|
+
*/
|
|
674
|
+
declare function persistable(d: Draft): Draft;
|
|
675
|
+
/** 从本机读回来的东西不一定是本版本写的:形状不对就当没有草稿。 */
|
|
676
|
+
declare function parseDraft(raw: unknown): Draft | null;
|
|
677
|
+
/** 草稿条目的 key:同一页里唯一即可。 */
|
|
678
|
+
declare function itemKey(prefix: string): string;
|
|
679
|
+
/**
|
|
680
|
+
* 草稿 → 发给 `collab.createThread` / `comment` / `reject` 的附带部分(`MessageExtras`)。
|
|
681
|
+
* 只认传完的文件(发送前组件已等过上传);粘贴的文本与插件给的文字作为带 `text` 的引用。
|
|
682
|
+
* 空的字段不写,免得评论里出现一串空数组。
|
|
683
|
+
*/
|
|
684
|
+
declare function toMessageExtras(d: Draft): MessageExtras;
|
|
685
|
+
/**
|
|
686
|
+
* 锚点引用的原文(text-range 剥掉 Markdown 记号),压成一行:划选的那段(`text-range` 的 `quote.exact`)、点选元素的文字(`dom` 的 `text`)、
|
|
687
|
+
* 外部文档的段落(`external-block` 的 `quote`)。别的类型、读不出来时为 null。引用卡片的那行字和对话里的
|
|
688
|
+
* 引用块都用它。
|
|
689
|
+
*/
|
|
690
|
+
declare function anchorQuote(anchor: Pick<Anchor, "kind" | "payload">): string | null;
|
|
691
|
+
/**
|
|
692
|
+
* 引用在界面上怎么画,按锚点类型定(不比较文字):
|
|
693
|
+
* - `quote`:标签只是原文的截断(划选)或原文的位置说明(外部块),有原文就只画原文,没有才回落到标签;
|
|
694
|
+
* - `label`:标签本身就是给人看的写法(点选元素的 `标题「文字」`、镜头、时间码……),画标签,不另写原文。
|
|
695
|
+
* 新增锚点类型要在这里填一行,不填编译不过。
|
|
696
|
+
*/
|
|
697
|
+
declare const QUOTE_DRAW: {
|
|
698
|
+
readonly artifact: "label";
|
|
699
|
+
readonly dom: "label";
|
|
700
|
+
readonly "text-range": "quote";
|
|
701
|
+
readonly entity: "label";
|
|
702
|
+
readonly timecode: "label";
|
|
703
|
+
readonly "external-block": "quote";
|
|
704
|
+
readonly "runtime-error": "label";
|
|
705
|
+
readonly region: "label";
|
|
706
|
+
readonly shot: "label";
|
|
707
|
+
readonly project: "label";
|
|
708
|
+
};
|
|
709
|
+
/** 引用块、引用卡片要单独画的原文;`label` 类锚点、读不出原文时为 null(画标签)。四个画引用的地方都经它。 */
|
|
710
|
+
declare function quoteFace(anchor: Pick<Anchor, "kind" | "payload">): string | null;
|
|
711
|
+
/**
|
|
712
|
+
* 钉着旧版 chat 等插件的项目还在 import 它:plugin-react 属共享模块,永远由宿主当前构建提供,
|
|
713
|
+
* 删导出会让旧插件在加载时整体失败。新代码用 `quoteFace`。
|
|
714
|
+
*
|
|
715
|
+
* @deprecated 只为已发布的旧插件保留,行为与删除前一致;删除要走协议大版本。
|
|
716
|
+
*/
|
|
717
|
+
declare function quoteLine(label: string, text: string | null | undefined): string | null;
|
|
718
|
+
/** 一条引用指向几样东西;协议要求恰好一个(`MessageRef`),不是 1 的不能进草稿。 */
|
|
719
|
+
declare function refTargets(r: {
|
|
720
|
+
anchor?: unknown;
|
|
721
|
+
entityRef?: string;
|
|
722
|
+
threadId?: string;
|
|
723
|
+
versionId?: string;
|
|
724
|
+
}): number;
|
|
725
|
+
/**
|
|
726
|
+
* 发送成功后草稿里还该留什么:发出去的那一份去掉,发送途中新敲的字、新加的附件留着。
|
|
727
|
+
* 正文以发出的正文开头时去掉这段前缀,否则(用户改了已发的部分)整段保留。
|
|
728
|
+
*/
|
|
729
|
+
declare function afterSend(sent: Draft, cur: Draft): Draft;
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* 输入框只消费回调,不直接访问连接器或网络。`read` 读成的附件带 `existing` 时(同一份字节已经有了),输入框提示「已有同一份」。
|
|
733
|
+
*/
|
|
734
|
+
interface ExternalImportSource<T = UploadedAttachment> {
|
|
735
|
+
label: string;
|
|
736
|
+
connected(): Promise<boolean>;
|
|
737
|
+
read(ref: string): Promise<T>;
|
|
738
|
+
manage(): void;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* 个人导入的来源。`exchange`:按登录账号现换现用的连接器(石墨),没有要先连上的个人连接,可用与否由导入时服务端回;
|
|
742
|
+
* 其余(docz)要先在「我的连接」连上。
|
|
743
|
+
*/
|
|
744
|
+
declare function personalImportSource(ctx: AppCtx, attachments: Pick<ProjectApi["attachments"], "importExternal">, connector: string, options?: {
|
|
745
|
+
label?: string;
|
|
746
|
+
exchange?: boolean;
|
|
747
|
+
}): ExternalImportSource | undefined;
|
|
748
|
+
/** 「从 docz 导入」「从石墨导入」:拉丁名两边留空格,中文名不留。 */
|
|
749
|
+
declare function importFrom(label: string, rest?: string): string;
|
|
750
|
+
/**
|
|
751
|
+
* 外部产物按工坊声明的来源(`artifactTypes.<类型>.source`)选个人导入的连接器:石墨按登录账号现换;
|
|
752
|
+
* 其余与没写来源的照旧走 docz(个人 token)。
|
|
753
|
+
*/
|
|
754
|
+
declare function importConnector(source: string | undefined): {
|
|
755
|
+
connector: string;
|
|
756
|
+
label: string;
|
|
757
|
+
exchange: boolean;
|
|
758
|
+
};
|
|
759
|
+
/** 平台官方插件共用的个人导入来源:docz(个人 token)与石墨(按登录账号现换)。 */
|
|
760
|
+
declare function personalImportSources(ctx: AppCtx, attachments: Pick<ProjectApi["attachments"], "importExternal">): ExternalImportSource[];
|
|
761
|
+
declare function ExternalImportPanel<T = UploadedAttachment>({ source, onAdd, onClose, onBusy, }: {
|
|
762
|
+
source: ExternalImportSource<T>;
|
|
763
|
+
onAdd(attachment: T): void;
|
|
764
|
+
onClose(): void;
|
|
765
|
+
onBusy(busy: boolean): void;
|
|
766
|
+
}): react.JSX.Element;
|
|
767
|
+
|
|
768
|
+
/** `#` 引用的候选:线程、产物、版本、实体。 */
|
|
769
|
+
interface RefCandidate {
|
|
770
|
+
key: string;
|
|
771
|
+
label: string;
|
|
772
|
+
detail?: string;
|
|
773
|
+
anchor?: Extract<DraftItem, {
|
|
774
|
+
kind: "ref";
|
|
775
|
+
}>["anchor"];
|
|
776
|
+
entityRef?: string;
|
|
777
|
+
threadId?: string;
|
|
778
|
+
versionId?: string;
|
|
779
|
+
}
|
|
780
|
+
/** 插件往草稿里加的东西(`composer.attach` 的 `add`)。 */
|
|
781
|
+
type AddableItem = {
|
|
782
|
+
kind: "file";
|
|
783
|
+
file: File;
|
|
784
|
+
} | {
|
|
785
|
+
kind: "ref";
|
|
786
|
+
label: string;
|
|
787
|
+
anchor?: RefCandidate["anchor"];
|
|
788
|
+
entityRef?: string;
|
|
789
|
+
threadId?: string;
|
|
790
|
+
versionId?: string;
|
|
791
|
+
} | {
|
|
792
|
+
kind: "text";
|
|
793
|
+
label: string;
|
|
794
|
+
text: string;
|
|
795
|
+
};
|
|
796
|
+
/** 「+」菜单里一条插件来源:选中后在输入框上方挂它的选择器。 */
|
|
797
|
+
interface AttachSource {
|
|
798
|
+
id: string;
|
|
799
|
+
label: string;
|
|
800
|
+
/** 来源插件包名,加进草稿的条目带上它,界面上标出来。 */
|
|
801
|
+
source: string;
|
|
802
|
+
mount(el: HTMLElement, owner: {
|
|
803
|
+
add(items: AddableItem[]): number;
|
|
804
|
+
close(): void;
|
|
805
|
+
}): () => void;
|
|
806
|
+
}
|
|
807
|
+
interface Uploader {
|
|
808
|
+
upload(file: File, o: {
|
|
809
|
+
signal: AbortSignal;
|
|
810
|
+
onProgress(p: number): void;
|
|
811
|
+
}): Promise<{
|
|
812
|
+
attachmentId: string;
|
|
813
|
+
size?: number;
|
|
814
|
+
name?: string;
|
|
815
|
+
mime?: string;
|
|
816
|
+
/** 项目里已有同一份字节:回的是那一条,`name` 是回包给的名字(通常是那一条原来的,被别的素材占了就已加「 (n)」),框上提示「已有同一份:<回包的名字>」。 */
|
|
817
|
+
existing?: boolean;
|
|
818
|
+
}>;
|
|
819
|
+
limits: FileLimits;
|
|
820
|
+
/** 已传完的附件(例如草稿恢复后)的预览地址;不给就只显示文件卡片。 */
|
|
821
|
+
previewUrl?(attachmentId: string): string | undefined;
|
|
822
|
+
}
|
|
823
|
+
interface PromptInputProps {
|
|
824
|
+
draft: Draft;
|
|
825
|
+
onDraft(next: Draft): void;
|
|
826
|
+
/**
|
|
827
|
+
* 发送。成功后输入框清空草稿。抛错:错误写在框上方,草稿留着。返回 `false`:宿主没发出去、自己已经说明了原因(首页把焦点移到没填的仓库那一格),
|
|
828
|
+
* 草稿和附件原样留着,不写错误。返回值只认 `false`(或兑现成 false 的 Promise),别的都当发出去了;类型写成
|
|
829
|
+
* unknown,返回 void、Promise<void> 或带 false 的回调都能直接传。
|
|
830
|
+
*/
|
|
831
|
+
onSubmit(draft: Draft): unknown;
|
|
832
|
+
/**
|
|
833
|
+
* 只决定外观(`prompt` 是页面上的大框,`comment` / `reply` 是弹层里的小框),按键全站一致:
|
|
834
|
+
* Enter 发送、Shift+Enter 换行(走查 B6;owner 11-11 的修复方案:统一在 PromptInput 一处,各插件不自己处理按键)。
|
|
835
|
+
*/
|
|
836
|
+
variant: "prompt" | "comment" | "reply";
|
|
837
|
+
label: string;
|
|
838
|
+
placeholder?: string;
|
|
839
|
+
/** 底栏左侧的说明,如「Agent 正在处理,新消息排到下一回合」。放不下截断,窄屏(≤ 860px)不显示。 */
|
|
840
|
+
hint?: ReactNode;
|
|
841
|
+
/** 要人看到的一句话(如「引用没加上……」):占提示的位置,窄屏也显示。 */
|
|
842
|
+
notice?: ReactNode;
|
|
843
|
+
/** 给了就不画输入框,只画这句话(没权限、看着旧版本)。 */
|
|
844
|
+
disabledReason?: string;
|
|
845
|
+
/** 外部的忙(例如回合状态在读);发送键禁用但能继续打字。 */
|
|
846
|
+
busy?: boolean;
|
|
847
|
+
/**
|
|
848
|
+
* 框里还有别的必填格(首页选了要填仓库的工坊),整个框当表单用:正文空着(只带附件也算)发送键也能按,按了不发,正文标红
|
|
849
|
+
* (`aria-invalid`)、焦点回到正文,再调 `onMissing` 让宿主把自己没填的格一起标红。填上字就消。缺省关:
|
|
850
|
+
* 发送框的惯例是空着就灰。
|
|
851
|
+
*/
|
|
852
|
+
required?: boolean;
|
|
853
|
+
onMissing?(): void;
|
|
854
|
+
mentions?: {
|
|
855
|
+
members: readonly MemberView[];
|
|
856
|
+
};
|
|
857
|
+
references?: {
|
|
858
|
+
search(q: string): Promise<RefCandidate[]>;
|
|
859
|
+
};
|
|
860
|
+
capabilities?: {
|
|
861
|
+
list: readonly Capability[];
|
|
862
|
+
};
|
|
863
|
+
connectors?: {
|
|
864
|
+
list: readonly Connector[];
|
|
865
|
+
manageHref?: string;
|
|
866
|
+
};
|
|
867
|
+
attach?: Uploader;
|
|
868
|
+
sources?: readonly AttachSource[];
|
|
869
|
+
/** 「+」菜单里的「从 X 导入」:一个或几个来源(docz、石墨),各占一项。 */
|
|
870
|
+
externalImport?: ExternalImportSource | readonly ExternalImportSource[];
|
|
871
|
+
/** 底栏「+」之后、说明之前的位置:「交给 Rondo」开关、工坊选择这类。 */
|
|
872
|
+
footerStart?: ReactNode;
|
|
873
|
+
/** 框里、底栏之上的附加字段(首页的目标仓库地址):和输入框同在一圈里。 */
|
|
874
|
+
fields?: ReactNode;
|
|
875
|
+
/**
|
|
876
|
+
* 长粘贴折成「粘贴的文本」条目(缺省开)。条目要由宿主发出去(`toMessageExtras` 把它当带 `text` 的引用);
|
|
877
|
+
* `onSubmit` 不把 `text` 条目发出去的入口一律传 false(首页的首条需求只有正文和附件;对话框「发送并重新开始」的补发只收正文和附件,同理),
|
|
878
|
+
* 粘贴照普通输入框留在正文里。开着却不发条目,粘的那段会静默丢掉。
|
|
879
|
+
*/
|
|
880
|
+
foldPaste?: boolean;
|
|
881
|
+
/** 发送键的无障碍名称:发送 / 开始 / 发布 / 回复。 */
|
|
882
|
+
submitLabel?: string;
|
|
883
|
+
/** 发送键用文字按钮而不是圆形箭头(浮层里的「发布」「回复」)。 */
|
|
884
|
+
submitText?: string;
|
|
885
|
+
/** 文字发送键悬停时的说明(键上只写短动词,整句放这里) */
|
|
886
|
+
submitTitle?: string;
|
|
887
|
+
autoFocus?: boolean;
|
|
888
|
+
/** 底栏右侧、发送键之前:取消按钮这类。 */
|
|
889
|
+
footerEnd?: ReactNode;
|
|
890
|
+
}
|
|
891
|
+
declare function PromptInput(props: PromptInputProps): react.JSX.Element;
|
|
892
|
+
|
|
893
|
+
/** 登记一个「把未保存内容落盘」的函数,返回注销函数。插件自己存的草稿(记忆稿等)也可以登记。 */
|
|
894
|
+
declare function registerDraftFlusher(fn: () => boolean): () => void;
|
|
895
|
+
/**
|
|
896
|
+
* 只放在内存里的未保存内容(评论小框、参数表单这类不存本机的):有内容就让 `flushAllDrafts()` 返回 false,
|
|
897
|
+
* 自动刷新退回「请先复制或提交内容,再点刷新」,宁可不刷也不丢(note 决定第 6 条)。`hasUnsaved` 每次渲染更新。
|
|
898
|
+
*/
|
|
899
|
+
declare function useUnsavedGuard(hasUnsaved: boolean): void;
|
|
900
|
+
/** 落盘页面上所有登记过的草稿;全部成功才返回 true,任何一处失败返回 false(调用方不该刷新)。 */
|
|
901
|
+
declare function flushAllDrafts(): boolean;
|
|
902
|
+
/** `key` 写位置,如 `<项目>:chat`、`<项目>:thread:<id>:reply`;`null` 表示不存本机。 */
|
|
903
|
+
declare function useDraft(key: string | null): [Draft, (d: Draft) => void];
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* 消息操作与表情回应的纯逻辑(docs/design/message-actions.md):回应的合并与说明文字、复制的两种文本、
|
|
907
|
+
* 线程深链。界面在 Message.tsx。
|
|
908
|
+
*/
|
|
909
|
+
|
|
910
|
+
/** 六个表情读屏时的意思(§4.1)。 */
|
|
911
|
+
declare const REACTION_MEANING: Record<ReactionEmoji, string>;
|
|
912
|
+
declare function reactedBy(r: Pick<Reaction, "actors"> | undefined, me: Actor): boolean;
|
|
913
|
+
/** 一个还没落到服务端的回应:发送中先显示(半透明),失败退回原样。 */
|
|
914
|
+
interface PendingReaction {
|
|
915
|
+
on: boolean;
|
|
916
|
+
/** `sending` 等服务端回话;`sent` 服务端成功了、等回应事件把新数据带回来。 */
|
|
917
|
+
state: "sending" | "sent";
|
|
918
|
+
}
|
|
919
|
+
interface ShownReaction extends Reaction {
|
|
920
|
+
mine: boolean;
|
|
921
|
+
pending: boolean;
|
|
922
|
+
}
|
|
923
|
+
/** 把本地未落定的回应叠到服务端给的回应上:加的排到末尾,取消到没人的去掉;顺序照第一次出现。 */
|
|
924
|
+
declare function mergeReactions(live: readonly Reaction[] | undefined, pending: ReadonlyMap<ReactionEmoji, PendingReaction>, me: Actor): ShownReaction[];
|
|
925
|
+
/** 服务端数据已经和本地意图一致的未落定回应可以丢掉(发送中的不丢:还不知道结果)。 */
|
|
926
|
+
declare function settledPending(live: readonly Reaction[] | undefined, pending: ReadonlyMap<ReactionEmoji, PendingReaction>, me: Actor): ReactionEmoji[];
|
|
927
|
+
/** 胶囊上的提示:谁回的。超过 5 人写前三个名字加「等 N 人」(§3.3)。 */
|
|
928
|
+
declare function reactionWho(actors: readonly Actor[], members: readonly MemberView[], me: Actor): string;
|
|
929
|
+
/** 读屏念的:「👀,Rondo 和林晓,按下可添加」。两个人用「和」,多人照提示。 */
|
|
930
|
+
declare function reactionLabel(r: ShownReaction, members: readonly MemberView[], me: Actor, canReact: boolean): string;
|
|
931
|
+
/**
|
|
932
|
+
* 「复制」用的纯文本:去掉 Markdown 记号,保留换行。列表项换成「• 」,代码块只留代码,链接只留文字。
|
|
933
|
+
*/
|
|
934
|
+
declare function plainText(md: string): string;
|
|
935
|
+
/**
|
|
936
|
+
* 「复制为 Markdown」:原文;回执再加所在版本与改动文件清单(§3.1)。文件和界面同一个口径(`receiptFileNames`):
|
|
937
|
+
* 不重名的只写文件名,重名的带上能区分的父目录。
|
|
938
|
+
*/
|
|
939
|
+
declare function markdownOf(c: Pick<Comment, "body" | "receipt">, versionLabel?: string): string;
|
|
940
|
+
/**
|
|
941
|
+
* 线程深链 `/w/<工坊>/<短名>/t/<线程>`;不在工坊下时用 `/p/<项目主键>/t/<线程>`(`/p/` 只按主键解析)。
|
|
942
|
+
* §3.1:落到线程,不落到单条。
|
|
943
|
+
*/
|
|
944
|
+
declare function threadPath(ctx: Pick<ProjectCtx, "app" | "project">, threadId: string): string;
|
|
945
|
+
|
|
946
|
+
type Ctx$1 = Pick<ProjectCtx, "threads" | "member" | "app" | "project" | "events" | "attachments" | "report">;
|
|
947
|
+
/**
|
|
948
|
+
* 回应变了(`reaction.changed`)只重读那一条线程,局部替换(§4.4:不跟着 `comment.*` 把整页重读)。
|
|
949
|
+
* `base` 是调用方整份重读出来的数据,换了一份就丢掉旧的局部替换(新数据里已经带着回应)。
|
|
950
|
+
*/
|
|
951
|
+
declare function useReactionPatches(ctx: Pick<ProjectCtx, "events" | "threads">, base: unknown): (c: Comment) => readonly Reaction[] | undefined;
|
|
952
|
+
/**
|
|
953
|
+
* 消息列表的键盘走法(§3.2):`Tab` 进列表落在一条消息上(上次停的那条,没有就最新一条),`↑` `↓` 在
|
|
954
|
+
* 消息间移动,`Home` `End` 到头尾。返回值挂在列表容器上。
|
|
955
|
+
*/
|
|
956
|
+
declare function useMessageList<T extends HTMLElement>(): {
|
|
957
|
+
ref: RefObject<T>;
|
|
958
|
+
onKeyDown: (e: KeyboardEvent<T>) => void;
|
|
959
|
+
onFocus: (e: React.FocusEvent<T>) => void;
|
|
960
|
+
};
|
|
961
|
+
interface MessageProps {
|
|
962
|
+
ctx: Ctx$1;
|
|
963
|
+
threadId: string;
|
|
964
|
+
comment: Comment;
|
|
965
|
+
members: readonly MemberView[];
|
|
966
|
+
/** 实时回应:传 `useReactionPatches` 的结果;没有实时来源就传 `comment.reactions`。 */
|
|
967
|
+
reactions: readonly Reaction[] | undefined;
|
|
968
|
+
/** 读屏念的消息名,如「林晓的消息」。 */
|
|
969
|
+
label: string;
|
|
970
|
+
/** 回执所在版本:`label` 进「复制为 Markdown」,给了 `open` 才有「查看 …」。 */
|
|
971
|
+
version?: {
|
|
972
|
+
label: string;
|
|
973
|
+
open?: () => void;
|
|
974
|
+
};
|
|
975
|
+
/** 操作条贴哪:`bubble` 消息只占气泡宽、贴气泡右上角;`row` 占整行(回执)。 */
|
|
976
|
+
fit?: "bubble" | "row";
|
|
977
|
+
/** 能不能「引用」(已解决的线程在评论框里不能回复)。缺省有 `comment` 权限就能。 */
|
|
978
|
+
quotable?: boolean;
|
|
979
|
+
className?: string;
|
|
980
|
+
children: ReactNode;
|
|
981
|
+
}
|
|
982
|
+
/** 一条消息:内容 + 回应胶囊 + 悬停操作条 + 菜单 / 底部操作单。 */
|
|
983
|
+
declare function Message({ ctx, threadId, comment: c, members, reactions, label, version, fit, quotable, className, children, }: MessageProps): react.JSX.Element;
|
|
984
|
+
|
|
985
|
+
type Ctx = Pick<ProjectCtx, "attachments" | "events" | "report">;
|
|
986
|
+
/** 本插件共用的项目附件清单;还没读到时是 undefined。 */
|
|
987
|
+
declare function useProjectAttachments(ctx: Ctx): readonly ProjectAttachment[] | undefined;
|
|
988
|
+
interface MessageAttachmentsProps {
|
|
989
|
+
ctx: Ctx;
|
|
990
|
+
/** 评论带的附件 id(`comment.attachments`)。 */
|
|
991
|
+
ids: readonly string[];
|
|
992
|
+
/** 意见卡上的一条紧凑行:只画前 3 张缩略图,其余写「+N」,不能点开。 */
|
|
993
|
+
compact?: boolean;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* 消息里的附件:图片一行缩略图,点开是大图浮层,能在这条消息的几张图之间切换;其他文件是文件卡片(类型、名字、
|
|
997
|
+
* 大小),PDF、音视频、文本在新标签页打开,会执行的类型只给下载。缩略图取不到就退回文件卡片,不出破图。
|
|
998
|
+
*/
|
|
999
|
+
declare function MessageAttachments({ ctx, ids: given, compact }: MessageAttachmentsProps): react.JSX.Element | null;
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* 回执里「改了记忆」那一行的文字(docs/design/agent-memory.md §1 第 3 条、§4):从这一版相对上一版的变化里
|
|
1003
|
+
* 挑一句新写下的话;只删不加时写改了哪些文件。界面代码在 MemoryNote.tsx。
|
|
1004
|
+
*/
|
|
1005
|
+
|
|
1006
|
+
interface MemoNote {
|
|
1007
|
+
/** 「记下了:…」后面那句;没有新写的话时是 null,界面改写「改了记忆:文件」。 */
|
|
1008
|
+
memo: string | null;
|
|
1009
|
+
/** 新写下的话一共几句(不含索引文件)。 */
|
|
1010
|
+
more: number;
|
|
1011
|
+
/** 动过的文件,索引排后面。 */
|
|
1012
|
+
files: string[];
|
|
1013
|
+
}
|
|
1014
|
+
declare function memoNote(changes: readonly MemoryChange[]): MemoNote;
|
|
1015
|
+
/**
|
|
1016
|
+
* 设置页「记忆」分页里指向某一版的那一项(地址 `/settings/memory/<item>`):回执点开时拼,记忆插件读。
|
|
1017
|
+
*/
|
|
1018
|
+
declare function memoryItem(version: number): string;
|
|
1019
|
+
/** `memoryItem` 的反面:不是这个写法返回 null。 */
|
|
1020
|
+
declare function parseMemoryItem(item: string | undefined): number | null;
|
|
1021
|
+
|
|
1022
|
+
declare function MemoryNote({ ctx, turnId }: {
|
|
1023
|
+
ctx: ProjectCtx;
|
|
1024
|
+
turnId: string;
|
|
1025
|
+
}): react.JSX.Element | null;
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* 页面里的 toast(backlog #5):刚做完一件事的即时回执。宿主(外壳)画唯一一层容器 `ToastHost`,
|
|
1029
|
+
* 插件与锁定插件只 import 这里的 `toast()` 入队,不自己画容器——两个插件同时弹也落进同一摞,不会各画一层。
|
|
1030
|
+
*
|
|
1031
|
+
* 模块级 store 是有意为之:`@kanyun-ai-infra/band-plugin-react` 是宿主提供的共享模块,宿主与每个插件拿到同一个
|
|
1032
|
+
* 实例;而每个插件各开一个 React root,React context 跨不过去,ctx 也没有这个能力(加它要改协议)。
|
|
1033
|
+
*
|
|
1034
|
+
* 规则照样张(docs/design/specimens/band-design-components.html §5,本卡按它实现):
|
|
1035
|
+
* - 成功 4 秒自己收;鼠标停在上面时不收,移开后 2 秒再收;
|
|
1036
|
+
* - 错误不自己走,要么点「重试」要么关掉(没给动作时容器补一个「关闭」);
|
|
1037
|
+
* - 进行中做完在同一条里变成勾(用同一个 id 再调一次 `toast`),不新弹一条;
|
|
1038
|
+
* - 同时最多三条,第四条挤掉最早的一条(进行中的先留着)。
|
|
1039
|
+
*
|
|
1040
|
+
* 模块级状态跟着页面活:测试要清干净用 `dismissAllToasts`。
|
|
1041
|
+
*/
|
|
1042
|
+
type ToastKind = "ok" | "bad" | "busy";
|
|
1043
|
+
/** toast 上的一个动作(错误一般是「重试」)。 */
|
|
1044
|
+
interface ToastAction {
|
|
1045
|
+
label: string;
|
|
1046
|
+
onClick: () => void;
|
|
1047
|
+
}
|
|
1048
|
+
interface ToastOptions {
|
|
1049
|
+
/** 缺省 `ok`。 */
|
|
1050
|
+
kind?: ToastKind;
|
|
1051
|
+
/** 一行说明。 */
|
|
1052
|
+
text: string;
|
|
1053
|
+
/** 第二行小字。 */
|
|
1054
|
+
detail?: string;
|
|
1055
|
+
/** 一个动作;错误的「重试」放这里。 */
|
|
1056
|
+
action?: ToastAction;
|
|
1057
|
+
/** 传已有的 id:改那一条(进行中做完变成勾),不新弹一条。 */
|
|
1058
|
+
id?: string;
|
|
1059
|
+
}
|
|
1060
|
+
interface ToastItem {
|
|
1061
|
+
id: string;
|
|
1062
|
+
kind: ToastKind;
|
|
1063
|
+
text: string;
|
|
1064
|
+
detail?: string;
|
|
1065
|
+
action?: ToastAction;
|
|
1066
|
+
}
|
|
1067
|
+
/** 弹一条;传 `id` 就是改那一条。返回它的 id。 */
|
|
1068
|
+
declare function toast(opts: ToastOptions): string;
|
|
1069
|
+
/** 收起一条(动作、Esc、关掉都走这里)。 */
|
|
1070
|
+
declare function dismissToast(id: string): void;
|
|
1071
|
+
/** 全部收掉(换身份、测试收尾)。 */
|
|
1072
|
+
declare function dismissAllToasts(): void;
|
|
1073
|
+
|
|
1074
|
+
/** 宿主画的一次性容器;一页只有一个(`band-shell`)。插件调 `toast()`,不自己画。 */
|
|
1075
|
+
declare function ToastHost(): react.JSX.Element;
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Rondo 状态消息与回执页脚的写法([note](../../../../.agents/notes/proposed/feature/2026-10-28-agent-presence-in-thread.md)
|
|
1079
|
+
* §3、§7):用时怎么念、回执页脚那一句怎么拼。纯函数,`band-chat`、`band-comment`、`band-turn-bar` 共用。
|
|
1080
|
+
*/
|
|
1081
|
+
|
|
1082
|
+
/** 毫秒 → 「40 秒」「3 分 12 秒」「1 小时 5 分」。不到 1 秒算 1 秒,负数与非数当 0 秒。 */
|
|
1083
|
+
declare function durationText(ms: number): string;
|
|
1084
|
+
/**
|
|
1085
|
+
* 「比平时久(通常约 X)」里的 X(band/lead 10-30 的取整规则):中位数不到 1 分钟写「不到 1 分钟」,
|
|
1086
|
+
* 其余四舍五入到分钟再按 {@link durationText} 念(「约 3 分」「约 1 小时 5 分」),不写秒。
|
|
1087
|
+
*/
|
|
1088
|
+
declare function usualDurationText(ms: number): string;
|
|
1089
|
+
/** 长回合的判断依据(`TurnState.current.stall`):最后一条会话事件的时刻与部署的两个阈值。 */
|
|
1090
|
+
interface StallView {
|
|
1091
|
+
lastProgressAt: string;
|
|
1092
|
+
stallMs: number;
|
|
1093
|
+
noProgressMs: number;
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* 「已 N 分钟没有新进展,可以继续等,也可以停下」([长回合提示 note](../../../../.agents/notes/proposed/feature/2026-11-11-long-turn-stall-alerts.md) 决定 3):
|
|
1097
|
+
* **已用超过 `stallMs` 且离最后一条会话事件超过 `noProgressMs`** 时才给,否则 undefined(界面退回「比平时久」)。
|
|
1098
|
+
* 阈值与时刻都是宿主给的,判断和念法在这里做一次,回合栏与状态消息共用;`now` 由页面上的表给,不在这里取钟。
|
|
1099
|
+
*
|
|
1100
|
+
* 为什么看「会话事件」而不是「在做什么那一句」:agent 连续调同一个工具时那句话不动,活动却在走(card-3193 的现场)。
|
|
1101
|
+
*/
|
|
1102
|
+
declare function stallNoteOf(turn: {
|
|
1103
|
+
startedAt?: string | undefined;
|
|
1104
|
+
stall?: StallView | undefined;
|
|
1105
|
+
}, now: number): string | undefined;
|
|
1106
|
+
/**
|
|
1107
|
+
* 等待说明里的预计时长(card-3183):工坊声明了 `estimate.minutes` 就用它(「一般 3–8 分钟」),没声明时用同阶段
|
|
1108
|
+
* 历史成功回合的中位数(`usualMs`,就是「通常要多久」那一个读数),写成「一般约 3 分钟」。两个都没有时返回 null,
|
|
1109
|
+
* 界面就不写数字——没有依据的时长比不写更糟。
|
|
1110
|
+
*
|
|
1111
|
+
* 中位数不造区间:中位数只有一个读数,上下加多少都是编的。破折号用 en dash,和文档里的说法一致。
|
|
1112
|
+
*
|
|
1113
|
+
* 区间反了(`[8, 3]`)或不是正整数时当没声明:工坊 schema 编译期就拦着,这里再挡一次是因为协议只要求两个正整数、
|
|
1114
|
+
* 不要求顺序,插件手上的宿主数据不一定是编译器产出的。
|
|
1115
|
+
*/
|
|
1116
|
+
declare function estimateMinutesText(declared: readonly [number, number] | undefined, usualMs: number | undefined): string | null;
|
|
1117
|
+
/**
|
|
1118
|
+
* 回执评论的页脚(§7):按回合结果写——第一版只写用时(正文已经说了做好)、改了「改了 2 个文件」/「改好了」、没改「没有改文件」、
|
|
1119
|
+
* 要成员补充「在等你回答」。`stageName` 把 `upstream` 建议的阶段 key 换成名字。
|
|
1120
|
+
* 不是回执、或旧回执没有 `durationMs`,返回 null(不显示页脚,不猜用时)。
|
|
1121
|
+
*/
|
|
1122
|
+
declare function receiptFooter(comment: Pick<Comment, "kind" | "receipt">, stageName?: (stage: string) => string): string | null;
|
|
1123
|
+
|
|
1124
|
+
/** 「已用」:从 `startedAt` 起,按页面共用的那只表走。没有开始时刻返回 null。 */
|
|
1125
|
+
declare function useElapsed(startedAt: string | undefined): number | null;
|
|
1126
|
+
/**
|
|
1127
|
+
* 页面共用的那只表的当前时刻(毫秒):长回合的「已 N 分钟没有新进展」跟着它走,和「已用」同一拍。
|
|
1128
|
+
* `active` 为假时不起表(没在跑的回合不用每秒钟重画)。
|
|
1129
|
+
*/
|
|
1130
|
+
declare function useNow(active?: boolean): number;
|
|
1131
|
+
declare function StatusMessage({ turn, members, context, stop, }: {
|
|
1132
|
+
turn: NonNullable<TurnState["current"]>;
|
|
1133
|
+
members: readonly MemberView[] | undefined;
|
|
1134
|
+
/** 名字后面的一小段(如「改「讲义」」「回合 #3」);不给就只写名字。 */
|
|
1135
|
+
context?: ReactNode;
|
|
1136
|
+
/** 「停止」:`run` 停下这一回合,`can` 是有没有 submit-change。不给就不放。 */
|
|
1137
|
+
stop?: {
|
|
1138
|
+
run: () => Promise<void>;
|
|
1139
|
+
can: boolean;
|
|
1140
|
+
queued?: number;
|
|
1141
|
+
} | undefined;
|
|
1142
|
+
}): react.JSX.Element;
|
|
1143
|
+
|
|
1144
|
+
declare const TURN_STATUS_ATTR = "data-band-turn-status";
|
|
1145
|
+
/** 页面上现在有没有这个回合的、看得见的带「停止」的状态消息。订阅期间随文档变化更新。 */
|
|
1146
|
+
declare function useTurnStatusOnPage(changeRequestId: string): boolean;
|
|
1147
|
+
|
|
1148
|
+
type TurnStoppedEvent = Extract<SystemEvent, {
|
|
1149
|
+
type: "turn.stopped";
|
|
1150
|
+
}>;
|
|
1151
|
+
/** 这条评论是不是「有人停下了回合」那一行:是就给出事件,不是(人写的、回执、别的系统评论)给 null。 */
|
|
1152
|
+
declare function turnStoppedOf(c: Pick<Comment, "kind" | "system">): TurnStoppedEvent | null;
|
|
1153
|
+
/** 线程尾部按时间排的回执与「停下了回合」:两样都落在状态消息原来的位置,混排才不乱序。 */
|
|
1154
|
+
declare function isThreadTail(c: Pick<Comment, "kind" | "system">): boolean;
|
|
1155
|
+
declare function TurnStopped({ event, members, }: {
|
|
1156
|
+
event: TurnStoppedEvent;
|
|
1157
|
+
members: readonly MemberView[];
|
|
1158
|
+
}): react.JSX.Element;
|
|
1159
|
+
|
|
1160
|
+
interface VersionReferenceInfo {
|
|
1161
|
+
version: Version;
|
|
1162
|
+
artifactName: string;
|
|
1163
|
+
label: string;
|
|
1164
|
+
latest: boolean;
|
|
1165
|
+
}
|
|
1166
|
+
interface VersionReferences {
|
|
1167
|
+
versions: ReadonlyMap<string, VersionReferenceInfo>;
|
|
1168
|
+
artifactNames: ReadonlyMap<string, string>;
|
|
1169
|
+
}
|
|
1170
|
+
declare function loadVersionReferences(ctx: Pick<ProjectCtx, "artifacts" | "version">): Promise<VersionReferences>;
|
|
1171
|
+
declare function useVersionReferences(ctx: Pick<ProjectCtx, "artifacts" | "version" | "events">): {
|
|
1172
|
+
data: VersionReferences | undefined;
|
|
1173
|
+
error: string | null;
|
|
1174
|
+
reload: () => void;
|
|
1175
|
+
};
|
|
1176
|
+
declare function versionReferenceLabel(refs: VersionReferences | undefined, id: string, currentArtifact?: string | null): string;
|
|
1177
|
+
/** 引用保留原文标签,历史标签若带版本 id 就替换;否则补上版本上下文。 */
|
|
1178
|
+
declare function versionReferenceText(text: string, refs: VersionReferences | undefined, id: string, currentArtifact?: string | null): string;
|
|
1179
|
+
/** 不解析 id,不猜目标;完整标签留给读屏与悬停,窄栏内只省略视觉文字。 */
|
|
1180
|
+
declare function VersionReference({ label, open, }: {
|
|
1181
|
+
label: string;
|
|
1182
|
+
open?: (() => void) | undefined;
|
|
1183
|
+
}): react.JSX.Element;
|
|
1184
|
+
|
|
1185
|
+
/** 服务端拦截时放在错误 `details.reason` 的码。 */
|
|
1186
|
+
declare const MODEL_REQUIRED_REASON = "model-required";
|
|
1187
|
+
/** 个人设置里「我的模型与凭据」页,带上要回去的工坊(路由 `/settings/models/for/:workshop`)。 */
|
|
1188
|
+
declare const MODELS_FOR_PAGE = "@kanyun-ai-infra/band-settings/models-for";
|
|
1189
|
+
/** 个人设置里「模型配置」页(没有要回去的工坊)。 */
|
|
1190
|
+
declare const PERSONAL_MODELS_PAGE = "@kanyun-ai-infra/band-settings/models";
|
|
1191
|
+
/** 配好回来的新建表单(路由 `/w/:workshop/new/resume`):取回草稿并自动建一次。 */
|
|
1192
|
+
declare const RESUME_PAGE = "@kanyun-ai-infra/band-workshops/resume";
|
|
1193
|
+
declare const NO_KEY_TEXT = "\u8FD9\u4E2A\u5DE5\u574A\u8981\u7528\u4F60\u81EA\u5DF1\u7684\u6A21\u578B\u914D\u7F6E\uFF0C\u4F60\u8FD8\u6CA1\u6709\u3002\u5148\u914D\u4E00\u4EFD\uFF0C\u914D\u597D\u4F1A\u81EA\u52A8\u56DE\u5230\u8FD9\u91CC\u63A5\u7740\u5EFA\u3002";
|
|
1194
|
+
declare const NO_KEY_BUTTON = "\u53BB\u914D\u7F6E\u6A21\u578B";
|
|
1195
|
+
/** 建项目的错是不是「名下没有可绑的模型配置」。 */
|
|
1196
|
+
declare function isModelRequired(e: unknown): boolean;
|
|
1197
|
+
/** 服务端放在错误 `details.reason` 的码:ModelGate 自动开通没成(决定 5 的四类失败与「还在开通」)。 */
|
|
1198
|
+
declare const MODEL_PROVISION_REASON = "model-provision";
|
|
1199
|
+
/** 建项目的错是不是「ModelGate 自动开通没成」。 */
|
|
1200
|
+
declare function isProvisionFailure(e: unknown): boolean;
|
|
1201
|
+
/** 草稿内容由调用方定(JSON 可序列化);存不下(隐私模式、配额)就当没存,引导照常能点。 */
|
|
1202
|
+
declare function saveDraft(workshop: string, draft: unknown): void;
|
|
1203
|
+
/** 取回并删除:只能取一次。 */
|
|
1204
|
+
declare function takeDraft<T>(workshop: string): T | undefined;
|
|
1205
|
+
/** 拦截提示:一句话加一个按钮。`onGo` 里调用方先存草稿再导航。 */
|
|
1206
|
+
declare function NoKeyNotice({ id, onGo }: {
|
|
1207
|
+
id?: string;
|
|
1208
|
+
onGo: () => void;
|
|
1209
|
+
}): react.JSX.Element;
|
|
1210
|
+
/** 「需要你」的两个入口按钮。 */
|
|
1211
|
+
declare const MODEL_NEEDS_SETTINGS = "\u53BB\u9879\u76EE\u8BBE\u7F6E\u9009\u7528";
|
|
1212
|
+
declare const MODEL_NEEDS_PERSONAL = "\u53BB\u4E2A\u4EBA\u8BBE\u7F6E\u914D\u7F6E";
|
|
1213
|
+
/** 这一块的读屏名(项目页上的琥珀提示)。 */
|
|
1214
|
+
declare const PROJECT_MODEL_NEEDS_ME = "\u6A21\u578B\u914D\u7F6E\u9700\u8981\u4F60\u5904\u7406";
|
|
1215
|
+
/** 一个项目里要点名给管理员的四种情况,按读口的结论计数。 */
|
|
1216
|
+
interface ProjectModelNeeds {
|
|
1217
|
+
/** `selection_required`:`require` 的工坊里没选、派发也自动绑不上的 agent 数。 */
|
|
1218
|
+
missing: number;
|
|
1219
|
+
/** `not_configured`:`off` / `allow` 的工坊没有团队 key,也没有选用的 agent 数。 */
|
|
1220
|
+
unconfigured: number;
|
|
1221
|
+
/** `selection_required` 但真实原因是「项目主人的 ModelGate 个人额度还没确认」的 agent 数。 */
|
|
1222
|
+
consent: number;
|
|
1223
|
+
/** 额度未确认的原句(读口 `message`,逐字用),`consent > 0` 时不少于一条。 */
|
|
1224
|
+
consentMessages: readonly string[];
|
|
1225
|
+
/** `lastModelFailure`:选用的配置用不了(被删、换了 key、AgentHub 上找不到了)的 agent 数。 */
|
|
1226
|
+
broken: number;
|
|
1227
|
+
/** 用不了的原句(读口 `message`,逐字用),`broken > 0` 时不少于一条。 */
|
|
1228
|
+
brokenMessages: readonly string[];
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* 数出「需要你」的几种情况。`unavailable` 与 `lastModelFailure` 最多一个非 null(契约),先看前者。
|
|
1232
|
+
* `selection_required` 里额度未确认的那一类要分开:服务端也回这个 reason,但 `message` 是
|
|
1233
|
+
* `MODEL_PROJECT_CONSENT_PENDING`(`apps/server/src/project-agent-models-api.ts`),后果与下一步都不是「去选一份」——
|
|
1234
|
+
* 自动绑定根本不会发生,要用读口给的原句,不能另写一句。
|
|
1235
|
+
*/
|
|
1236
|
+
declare function projectModelNeedsOf(agents: readonly Pick<ProjectAgentModels["agents"][number], "unavailable" | "lastModelFailure">[]): ProjectModelNeeds;
|
|
1237
|
+
/**
|
|
1238
|
+
* 「需要你」那一句;没有要人处理的事时 null。额度未确认与用不了的句子逐字用读口的 `message`:只有一个 agent 时
|
|
1239
|
+
* 就是那一句,多个时把它们并在一句里(同一原因只写一次)。
|
|
1240
|
+
*/
|
|
1241
|
+
declare function projectModelNeedsText(n: ProjectModelNeeds): string | null;
|
|
1242
|
+
|
|
1243
|
+
/** 只读说明文本;breaks 只控制段内的单换行,代码块照原文。 */
|
|
1244
|
+
declare function Markdown({ text, breaks }: {
|
|
1245
|
+
text: string;
|
|
1246
|
+
breaks?: boolean;
|
|
1247
|
+
}): react.JSX.Element;
|
|
1248
|
+
|
|
1249
|
+
/** 宿主跳转的最小面:AppCtx 与 ProjectCtx 的 `app` 都有。 */
|
|
1250
|
+
type Navigator = Pick<AppCtx, "app">;
|
|
1251
|
+
/** 先过未保存守卫再跳:设置里所有页内链接都走这里。 */
|
|
1252
|
+
declare function settingsNavigate(ctx: Navigator, target: SettingsTarget): void;
|
|
1253
|
+
/** 链接的点击处理:只在主键上点(没按修饰键)时走页内跳转;其余交给浏览器(新标签页)。 */
|
|
1254
|
+
declare function settingsLink(ctx: Navigator, page: string, params?: Record<string, string>): (e: react.MouseEvent<HTMLAnchorElement>) => void;
|
|
1255
|
+
/**
|
|
1256
|
+
* 现在是不是手机宽度。目录页(`/settings` 与项目设置的根地址)据此二选一:窄屏导航自成一页,
|
|
1257
|
+
* 宽屏旁边就是导航,内容区直接画第一个分区。
|
|
1258
|
+
*/
|
|
1259
|
+
declare function useNarrow(): boolean;
|
|
1260
|
+
/**
|
|
1261
|
+
* 骨架在内容区上挂一次:给表单控件记初始值,离开前比一次。
|
|
1262
|
+
*
|
|
1263
|
+
* 上一页的卸载是**推迟一拍**做的(`reactMount` 的清理在 setTimeout 里):换地址时新页先挂上、旧页后卸,
|
|
1264
|
+
* 旧页的清理不能把新页刚装好的那份探针抹掉,所以清理前先认一下是不是自己那份。
|
|
1265
|
+
*/
|
|
1266
|
+
declare function useLeaveGuard(root: RefObject<HTMLElement | null>): void;
|
|
1267
|
+
/**
|
|
1268
|
+
* 离开这一页:填过东西就先问({@link SettingsLeaveDialog}),没填过就直接走。
|
|
1269
|
+
* 表单的「取消」也走这里,免得只有导航链接被拦住、取消照旧一走了之。
|
|
1270
|
+
*/
|
|
1271
|
+
declare function leaveThen(go: () => void): void;
|
|
1272
|
+
/**
|
|
1273
|
+
* 四个作用域共用的外框:{@link SettingsLayout} 加上按 ctx 跳转、未保存离开的守卫与确认弹窗。
|
|
1274
|
+
* 作用域只决定导航头与分区名单。
|
|
1275
|
+
*/
|
|
1276
|
+
declare function SettingsFrame({ ctx, navLabel, title, obj, crumb, groups, current, view, back, backMobile, children, }: {
|
|
1277
|
+
ctx: Navigator;
|
|
1278
|
+
navLabel: string;
|
|
1279
|
+
title: string;
|
|
1280
|
+
obj?: ReactNode;
|
|
1281
|
+
crumb?: ReactNode;
|
|
1282
|
+
groups: readonly SettingsGroup[];
|
|
1283
|
+
current?: string | undefined;
|
|
1284
|
+
view?: "page" | "index";
|
|
1285
|
+
back?: SettingsBackTarget | undefined;
|
|
1286
|
+
backMobile?: SettingsBackTarget | undefined;
|
|
1287
|
+
children: ReactNode;
|
|
1288
|
+
}): react.JSX.Element;
|
|
1289
|
+
/** 记下「刚存的那一条」:目标分区的列表挂上时那一行垫 `--ok-soft` 标出来。 */
|
|
1290
|
+
declare function markFresh(slug: string, id: string): void;
|
|
1291
|
+
/** 一次建了几条时全标出来。 */
|
|
1292
|
+
declare function markFreshMany(slug: string, ids: readonly string[]): void;
|
|
1293
|
+
/** 分区页挂上来时报到:挂上来的不是写下它的那个分区(目录页也算「不是」),槽里的东西一律作废。 */
|
|
1294
|
+
declare function enterSection(slug: string | null): void;
|
|
1295
|
+
/** 读「刚存的那一条」,不清(清在挂上之后:StrictMode 会重放初始化器)。 */
|
|
1296
|
+
declare function peekFresh(slug: string): string | null;
|
|
1297
|
+
declare function peekFreshAll(slug: string): readonly string[];
|
|
1298
|
+
declare function clearFresh(): void;
|
|
1299
|
+
/** 记下一句跨页的提示(「已保存」「已删除」「已撤销」),写明它要给哪个分区。 */
|
|
1300
|
+
declare function markNotice(slug: string, text: string): void;
|
|
1301
|
+
/** 取走那句提示:只给一次,且只给它写明的那个分区。 */
|
|
1302
|
+
declare function takeNotice(slug: string): string | null;
|
|
1303
|
+
/** 列表页的「刚存的那一条」:挂上后读一次并在这一帧之后清掉。 */
|
|
1304
|
+
declare function useFreshRow(slug: string): string | null;
|
|
1305
|
+
declare function useFreshRows(slug: string): readonly string[];
|
|
1306
|
+
/** 「已保存」停四拍(2s)就走:一句话加一个计时器,`flash` 一调用就重新计时。 */
|
|
1307
|
+
declare function useSavedNote(): [string, (text: string) => void];
|
|
1308
|
+
/** 跨页提示落到本页:挂上后取一次(放在 effect 里:`aria-live` 只在内容变化时播报)。 */
|
|
1309
|
+
declare function useCrossPageNotice(slug: string): [string, (text: string) => void];
|
|
1310
|
+
|
|
1311
|
+
export { type AddableItem, type AttachSource, Combobox, type ComboboxItem, type Draft, type DraftItem, ExternalImportPanel, type ExternalImportSource, type FileCheck, type FileItem, type FileLimits, type FilterGroup, FilterMenu, type FilterOption, type FilterRow, type FilterSelection, FirstDeliveryAction, type FirstTurnEnd, MODELS_FOR_PAGE, MODEL_NEEDS_PERSONAL, MODEL_NEEDS_SETTINGS, MODEL_PROVISION_REASON, MODEL_REQUIRED_REASON, Markdown, type MemoNote, MemoryNote, Message, MessageAttachments, type MessageAttachmentsProps, type MessageProps, ModelHint, Mount, NO_KEY_BUTTON, NO_KEY_TEXT, NoKeyNotice, PASTE_FOLD_CHARS, PERSONAL_MODELS_PAGE, PROJECT_MODEL_HEADING, PROJECT_MODEL_NEEDS_ME, PROJECT_MODEL_SPEND, type PendingReaction, type PluginState, type ProjectModelNeeds, PromptInput, type PromptInputProps, QUOTE_DRAW, REACTION_MEANING, REPO_URL_EXAMPLE, RESUME_PAGE, type RefCandidate, type RefItem, Retry, STAGE_EVENTS, STATUS_CHIP, STOPPED_UNDONE, STOP_COST, type SelectedEntity, SettingsBackTarget, SettingsFrame, SettingsGroup, SettingsTarget, type ShownReaction, type StallView, StatusMessage, StopTurn, TARGET_REPO_DOCS, THREAD_EVENTS, TURN_STATUS_ATTR, TagInput, TargetRepoNote, type ToastAction, ToastHost, type ToastItem, type ToastKind, type ToastOptions, type Trigger, TurnStopped, type TurnStoppedEvent, type Uploader, VersionReference, type VersionReferenceInfo, type VersionReferences, afterSend, agentIn, agentLabel, alreadyHandedText, anchorLabel, anchorQuote, canRestoreProject, checkFiles, clearFresh, composerSpendLine, createState, credentialOptionLabel, defaultOf, deletedProjectText, dismissAllToasts, dismissToast, draftFileBytes, durationText, emptyDraft, enterSection, entriesFor, errorRepo, errorRequestAccessUrl, estimateMinutesText, facetedCount, failed, failureReason, fileExt, filterByQuery, filterRows, firstTurnEnd, flushAllDrafts, formatBytes, gateRule, gateWho, hasContent, importConnector, importFrom, inline, isModelRequired, isProvisionFailure, isThreadTail, itemKey, leaveThen, loadVersionReferences, localDay, markFresh, markFreshMany, markNotice, markdownOf, memberName, memoNote, memoryItem, mentionCandidates, mentionQuery, mentionsIn, mergeReactions, modelHintText, parseDraft, parseMemoryItem, peekFresh, peekFreshAll, persistable, personalImportSource, personalImportSources, plainText, popoverLeft, projectModelNeedsOf, projectModelNeedsText, projectModelNote, provisionConsentText, queuePosition, queueSlot, queuedMessages, quoteFace, quoteLine, reactMount, reactedBy, reactionLabel, reactionWho, readComments, receiptFileNames, receiptFooter, refTargets, registerDraftFlusher, rejectionText, replaceRange, repoFieldHint, roleLabel, saveDraft, settingsLink, settingsNavigate, settledPending, shortTime, shortWhen, splitTags, stallNoteOf, statusText, stopQueuedNote, takeDraft, takeNotice, targetRepoErrorId, threadConfirmation, threadPath, toMessageExtras, toast, triggerAt, turnEndWord, turnStoppedOf, uploadFailureLines, uploading, useAppData, useArtifactRole, useComposition, useCrossPageNotice, useCtxData, useDraft, useElapsed, useFreshRow, useFreshRows, useHandToAgent, useLeaveGuard, useMembers, useMessageList, useNarrow, useNow, useProjectAttachments, useReactionPatches, useRoute, useSavedNote, useSelectedArtifact, useSelectedEntity, useSettledText, useSlotEntries, useStateOf, useTurnStatusOnPage, useUnsavedGuard, useVersionReferences, usualDurationText, versionLabel, versionReferenceLabel, versionReferenceText, wasStopped };
|