@dsh-workbench/shared 0.3.3 → 0.3.5
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/api/blocker-table.d.ts +13 -0
- package/dist/api/blocker-table.js +13 -0
- package/dist/api/blocker.d.ts +6 -0
- package/dist/api/context-ref.d.ts +31 -0
- package/dist/api/context-ref.js +28 -0
- package/dist/api/dsh-client.d.ts +99 -0
- package/dist/api/dsh.d.ts +55 -3
- package/dist/api/facts.d.ts +42 -0
- package/dist/api/facts.js +33 -0
- package/dist/api/host-write.d.ts +19 -1
- package/dist/api/host-write.js +12 -0
- package/dist/api/long-task.d.ts +36 -0
- package/dist/api/long-task.js +27 -0
- package/dist/api/unit-board.d.ts +25 -0
- package/dist/api/unit-board.js +16 -0
- package/dist/api/unit-declaration.d.ts +36 -0
- package/dist/api/unit-declaration.js +24 -0
- package/dist/api/unit.d.ts +32 -0
- package/dist/api/unit.js +5 -0
- package/dist/api/workbench-client.d.ts +25 -0
- package/dist/api/workbench-client.js +13 -0
- package/dist/api/workbench-contract.d.ts +12 -0
- package/dist/components/Activity.d.ts +33 -0
- package/dist/components/Activity.js +24 -0
- package/dist/components/ApprovalDetail.d.ts +15 -1
- package/dist/components/ApprovalDetail.js +13 -1
- package/dist/components/ApprovalPlan.d.ts +14 -0
- package/dist/components/ApprovalPlan.js +8 -0
- package/dist/components/Card.d.ts +13 -0
- package/dist/components/Card.js +10 -0
- package/dist/components/CardAnchor.d.ts +14 -0
- package/dist/components/CardAnchor.js +11 -0
- package/dist/components/CardBoundary.d.ts +20 -0
- package/dist/components/CardBoundary.js +14 -0
- package/dist/components/CardHead.d.ts +13 -0
- package/dist/components/CardHead.js +10 -0
- package/dist/components/ChoiceGroup.d.ts +24 -0
- package/dist/components/ChoiceGroup.js +12 -0
- package/dist/components/Field.d.ts +10 -0
- package/dist/components/Field.js +7 -0
- package/dist/components/Form.css +6 -0
- package/dist/components/Form.d.ts +20 -0
- package/dist/components/Form.js +58 -0
- package/dist/components/FormActions.d.ts +14 -0
- package/dist/components/FormActions.js +5 -0
- package/dist/components/FormNodes.d.ts +103 -0
- package/dist/components/FormNodes.js +153 -0
- package/dist/components/FormRows.d.ts +20 -0
- package/dist/components/FormRows.js +14 -0
- package/dist/components/FormTypes.d.ts +59 -0
- package/dist/components/FormTypes.js +1 -0
- package/dist/components/Link.d.ts +12 -0
- package/dist/components/Link.js +9 -0
- package/dist/components/LongTaskRow.d.ts +19 -0
- package/dist/components/LongTaskRow.js +13 -0
- package/dist/components/Note.d.ts +11 -0
- package/dist/components/Note.js +8 -0
- package/dist/components/ResourceStates.d.ts +25 -0
- package/dist/components/ResourceStates.js +22 -0
- package/dist/components/Rows.d.ts +17 -0
- package/dist/components/Rows.js +11 -0
- package/dist/components/SaveBar.d.ts +12 -0
- package/dist/components/SaveBar.js +9 -0
- package/dist/components/SelectField.d.ts +26 -0
- package/dist/components/SelectField.js +22 -0
- package/dist/components/SelectFieldNodes.d.ts +24 -0
- package/dist/components/SelectFieldNodes.js +24 -0
- package/dist/components/SettingsSection.d.ts +11 -0
- package/dist/components/SettingsSection.js +8 -0
- package/dist/components/Spinner.d.ts +9 -0
- package/dist/components/Spinner.js +6 -0
- package/dist/components/Stack.d.ts +8 -0
- package/dist/components/Stack.js +5 -0
- package/dist/components/StateBlock.d.ts +13 -0
- package/dist/components/StateBlock.js +10 -0
- package/dist/components/TextField.d.ts +8 -0
- package/dist/components/TextField.js +5 -0
- package/dist/components/board-module.d.ts +30 -0
- package/dist/components/icons.d.ts +38 -0
- package/dist/components/icons.js +35 -0
- package/dist/config/constants.d.ts +45 -0
- package/dist/config/constants.js +45 -0
- package/dist/config/storage.d.ts +4 -0
- package/dist/config/storage.js +4 -0
- package/dist/host/browser-read.d.ts +1 -0
- package/dist/host/browser-read.js +1 -0
- package/dist/host/http.d.ts +3 -0
- package/dist/host/http.js +10 -1
- package/dist/host/tool-approval.d.ts +5 -0
- package/dist/host/tool-approval.js +11 -5
- package/dist/host/unit-face.d.ts +5 -1
- package/dist/host.d.ts +1 -0
- package/dist/host.js +1 -0
- package/dist/i18n/en.d.ts +1 -0
- package/dist/i18n/en.js +22 -8
- package/dist/i18n/index.d.ts +25 -9
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/merge.d.ts +5 -0
- package/dist/i18n/merge.js +2 -0
- package/dist/i18n/zh.d.ts +23 -8
- package/dist/i18n/zh.js +22 -8
- package/dist/index.d.ts +7 -2
- package/dist/index.js +7 -2
- package/dist/lib/blocker-action.d.ts +22 -0
- package/dist/lib/blocker-action.js +13 -0
- package/dist/lib/board-fact.d.ts +27 -0
- package/dist/lib/board-fact.js +18 -0
- package/dist/lib/busy.d.ts +10 -0
- package/dist/lib/busy.js +7 -0
- package/dist/lib/diy-debug.d.ts +42 -2
- package/dist/lib/diy-debug.js +19 -1
- package/dist/lib/diy-record.d.ts +98 -0
- package/dist/lib/diy-record.js +96 -0
- package/dist/lib/form-problem.d.ts +10 -0
- package/dist/lib/form-problem.js +10 -0
- package/dist/lib/panel-state.d.ts +60 -0
- package/dist/lib/panel-state.js +30 -0
- package/dist/lib/react.d.ts +39 -0
- package/dist/lib/react.js +36 -0
- package/dist/lib/text.d.ts +22 -0
- package/dist/lib/text.js +22 -0
- package/dist/lib/ui.d.ts +50 -0
- package/dist/lib/ui.js +41 -0
- package/package.json +1 -1
- package/src/api/blocker-table.ts +13 -0
- package/src/api/blocker.ts +6 -0
- package/src/api/context-ref.ts +31 -0
- package/src/api/dsh-client.ts +99 -0
- package/src/api/dsh.ts +56 -1
- package/src/api/facts.ts +42 -0
- package/src/api/host-write.ts +20 -1
- package/src/api/long-task.ts +36 -0
- package/src/api/unit-board.ts +25 -0
- package/src/api/unit-declaration.ts +36 -0
- package/src/api/unit.ts +32 -0
- package/src/api/workbench-client.ts +25 -0
- package/src/api/workbench-contract.ts +12 -0
- package/src/components/Activity.tsx +33 -0
- package/src/components/ApprovalDetail.tsx +17 -1
- package/src/components/ApprovalPlan.tsx +14 -0
- package/src/components/Card.tsx +13 -0
- package/src/components/CardAnchor.tsx +14 -0
- package/src/components/CardBoundary.tsx +20 -0
- package/src/components/CardHead.tsx +13 -0
- package/src/components/ChoiceGroup.tsx +24 -0
- package/src/components/Field.tsx +10 -0
- package/src/components/Form.css +6 -0
- package/src/components/Form.test.tsx +475 -0
- package/src/components/Form.tsx +78 -0
- package/src/components/FormActions.tsx +14 -0
- package/src/components/FormNodes.tsx +193 -0
- package/src/components/FormRows.tsx +20 -0
- package/src/components/FormTypes.ts +65 -0
- package/src/components/FormWiring.test.tsx +88 -0
- package/src/components/Link.tsx +12 -0
- package/src/components/LongTaskRow.tsx +19 -0
- package/src/components/Note.tsx +11 -0
- package/src/components/ResourceStates.tsx +25 -0
- package/src/components/Rows.tsx +17 -0
- package/src/components/SaveBar.tsx +12 -0
- package/src/components/SelectField.tsx +26 -0
- package/src/components/SelectFieldNodes.tsx +24 -0
- package/src/components/SettingsSection.tsx +11 -0
- package/src/components/Spinner.tsx +9 -0
- package/src/components/Stack.tsx +8 -0
- package/src/components/StateBlock.tsx +13 -0
- package/src/components/TextField.tsx +8 -0
- package/src/components/board-module.ts +30 -0
- package/src/components/icons.tsx +38 -0
- package/src/config/constants.ts +48 -0
- package/src/config/storage.ts +4 -0
- package/src/host/browser-read.ts +1 -0
- package/src/host/http.ts +15 -1
- package/src/host/tool-approval.ts +18 -4
- package/src/host/unit-face.ts +6 -1
- package/src/host.ts +1 -0
- package/src/i18n/en.ts +22 -8
- package/src/i18n/index.ts +3 -0
- package/src/i18n/merge.ts +5 -0
- package/src/i18n/zh.ts +23 -8
- package/src/index.ts +7 -2
- package/src/lib/blocker-action.ts +22 -0
- package/src/lib/board-fact.ts +27 -0
- package/src/lib/busy.ts +10 -0
- package/src/lib/diy-debug.test.ts +2 -1
- package/src/lib/diy-debug.ts +44 -3
- package/src/lib/diy-record.test.ts +171 -0
- package/src/lib/diy-record.ts +185 -0
- package/src/lib/form-problem.ts +10 -0
- package/src/lib/panel-state.ts +60 -0
- package/src/lib/react.ts +39 -0
- package/src/lib/text.ts +22 -0
- package/src/lib/ui.ts +50 -0
package/src/api/dsh-client.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 左栏一行的来源:dsh workspaces.list 快照里的一项,两个时间戳都是毫秒。
|
|
5
|
+
*/
|
|
3
6
|
export interface WorkspaceView {
|
|
4
7
|
readonly workspaceId: string;
|
|
5
8
|
readonly path: string;
|
|
@@ -9,12 +12,18 @@ export interface WorkspaceView {
|
|
|
9
12
|
readonly updatedAt: number;
|
|
10
13
|
}
|
|
11
14
|
|
|
15
|
+
/**
|
|
16
|
+
* workspaces.list 的整份快照:可见工作区,加上归档与置顶的会话 id;外壳只读不改。
|
|
17
|
+
*/
|
|
12
18
|
export interface WorkspaceSnapshot {
|
|
13
19
|
readonly items: readonly WorkspaceView[];
|
|
14
20
|
readonly archivedSessionIds: readonly string[];
|
|
15
21
|
readonly pinnedSessionIds: readonly string[];
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
/**
|
|
25
|
+
* 会话一行的来源(标题、空会话、在跑与否、被谁留住);retainedBy 按视图名记留住它的份数,mainView 大于 0 即正被主视图占着。
|
|
26
|
+
*/
|
|
18
27
|
export interface SessionSummary {
|
|
19
28
|
readonly id: string;
|
|
20
29
|
readonly displayTitle: string;
|
|
@@ -25,10 +34,16 @@ export interface SessionSummary {
|
|
|
25
34
|
readonly retainedBy: Readonly<Partial<Record<string, number>>>;
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
/**
|
|
38
|
+
* 会话投影里的一条子代理目录项;外壳只认 id,其余字段随 dsh 变。
|
|
39
|
+
*/
|
|
28
40
|
export interface SubagentCatalogEntry {
|
|
29
41
|
readonly id: string;
|
|
30
42
|
}
|
|
31
43
|
|
|
44
|
+
/**
|
|
45
|
+
* dsh sessions.list 的快照:按 id 找会话,投影里可能挂着一串子代理目录。
|
|
46
|
+
*/
|
|
32
47
|
export interface SessionsSnapshot {
|
|
33
48
|
readonly byId: Readonly<Record<string, SessionSummary>>;
|
|
34
49
|
readonly projectionsBySession: Readonly<
|
|
@@ -36,34 +51,58 @@ export interface SessionsSnapshot {
|
|
|
36
51
|
>;
|
|
37
52
|
}
|
|
38
53
|
|
|
54
|
+
/**
|
|
55
|
+
* 一个会话的三个状态位(在跑 / 有未读完成 / 等着用户交互);字段缺省就是这一位不知道。
|
|
56
|
+
*/
|
|
39
57
|
export interface SessionStatus {
|
|
40
58
|
readonly running?: boolean;
|
|
41
59
|
readonly completionUnread?: boolean;
|
|
42
60
|
readonly pendingInteraction?: { readonly kind?: string };
|
|
43
61
|
}
|
|
44
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 会话 id 到状态位的只读表;查不到的 id 就是没有这一条状态。
|
|
65
|
+
*/
|
|
45
66
|
export type SessionStatusSnapshot = ReadonlyMap<string, SessionStatus>;
|
|
46
67
|
|
|
68
|
+
/**
|
|
69
|
+
* dsh layout 的面板选择位;activePanelId 为 null 表示用户把面板关了。
|
|
70
|
+
*/
|
|
47
71
|
export interface PanelInfo {
|
|
48
72
|
readonly activePanelId: string | null;
|
|
49
73
|
}
|
|
50
74
|
|
|
75
|
+
/**
|
|
76
|
+
* 某个插槽上注册着的一项(id、顺序、文案);label 允许是函数,因为文案要跟语言走。
|
|
77
|
+
*/
|
|
51
78
|
export interface PanelEntry {
|
|
52
79
|
readonly id: string;
|
|
53
80
|
readonly order: number;
|
|
54
81
|
readonly label: string | (() => string);
|
|
55
82
|
}
|
|
56
83
|
|
|
84
|
+
/**
|
|
85
|
+
* 选择器 hook 的形状(dsh 那套 useSyncExternalStore):外壳拿它从快照里取一小块并在变更时重取。
|
|
86
|
+
*/
|
|
57
87
|
export type SnapshotSelectorHook<T> = <R>(selector: (state: T) => R) => R;
|
|
58
88
|
|
|
89
|
+
/**
|
|
90
|
+
* 渲染 dsh 某个插槽的函数;key 定插槽,fallback 是空槽兜底,only 用来只渲染其中一个注册项。
|
|
91
|
+
*/
|
|
59
92
|
export type RenderSlot = (
|
|
60
93
|
key: string,
|
|
61
94
|
owner?: Record<string, unknown>,
|
|
62
95
|
options?: { fallback?: ReactNode; hookContext?: unknown; only?: string },
|
|
63
96
|
) => ReactNode;
|
|
64
97
|
|
|
98
|
+
/**
|
|
99
|
+
* 文案函数:给键(可带参数)回一句当前语言的文本;缺键时由 dsh 决定回什么,调用点不兜。
|
|
100
|
+
*/
|
|
65
101
|
export type Translate = (key: string, params?: Record<string, unknown>) => string;
|
|
66
102
|
|
|
103
|
+
/**
|
|
104
|
+
* 往 dsh 插槽注册一项要给的参数;priority 与 order 小者靠前,inject 声明这一项要用到的作用域。
|
|
105
|
+
*/
|
|
67
106
|
export interface SlotRegisterOptions {
|
|
68
107
|
name: string;
|
|
69
108
|
priority?: number;
|
|
@@ -76,6 +115,9 @@ export interface SlotRegisterOptions {
|
|
|
76
115
|
inject?: (scope?: unknown) => Record<string, unknown>;
|
|
77
116
|
}
|
|
78
117
|
|
|
118
|
+
/**
|
|
119
|
+
* dsh 的插槽服务:注册一项、注入作用域、订阅变更,以及按名取已注册项。
|
|
120
|
+
*/
|
|
79
121
|
export interface DshSlots {
|
|
80
122
|
inject(name: string, callback: () => void | (() => void) | Iterable<() => void>): () => void;
|
|
81
123
|
register(options: SlotRegisterOptions, component: unknown): () => void;
|
|
@@ -85,11 +127,17 @@ export interface DshSlots {
|
|
|
85
127
|
onMutate?(callback: (name: string) => void): () => void;
|
|
86
128
|
}
|
|
87
129
|
|
|
130
|
+
/**
|
|
131
|
+
* dsh 的语言服务:按命名空间注册字典,再取回那个命名空间的文案函数。
|
|
132
|
+
*/
|
|
88
133
|
export interface DshLocale {
|
|
89
134
|
register(namespace: string, dictionaries: Record<string, Record<string, string>>): () => void;
|
|
90
135
|
bind(namespace: string): Translate;
|
|
91
136
|
}
|
|
92
137
|
|
|
138
|
+
/**
|
|
139
|
+
* dsh 的布局服务:选面板、开关左栏、开合右栏;右栏宽度经可选的 panels 写。
|
|
140
|
+
*/
|
|
93
141
|
export interface DshLayout {
|
|
94
142
|
selectPanel(panelId: string | null): void;
|
|
95
143
|
toggleSidebar(): void;
|
|
@@ -98,18 +146,30 @@ export interface DshLayout {
|
|
|
98
146
|
readonly panels?: DshLayoutPanels;
|
|
99
147
|
}
|
|
100
148
|
|
|
149
|
+
/**
|
|
150
|
+
* layout 上那个可选的右栏宽度写口;dsh 没给这一位时右栏宽度就只是内存态。
|
|
151
|
+
*/
|
|
101
152
|
export interface DshLayoutPanels {
|
|
102
153
|
setRightbar?(px: number): void;
|
|
103
154
|
}
|
|
104
155
|
|
|
156
|
+
/**
|
|
157
|
+
* 快捷键目录的口子;外壳只把它透出去,形状与内容随 dsh。
|
|
158
|
+
*/
|
|
105
159
|
export interface DshShortcutCatalog {
|
|
106
160
|
readonly catalog: unknown;
|
|
107
161
|
}
|
|
108
162
|
|
|
163
|
+
/**
|
|
164
|
+
* 起一个新会话时能带的选项;目前只有 agent 预设这一项。
|
|
165
|
+
*/
|
|
109
166
|
export interface DshSessionStartOptions {
|
|
110
167
|
readonly agentPreset?: string;
|
|
111
168
|
}
|
|
112
169
|
|
|
170
|
+
/**
|
|
171
|
+
* dsh 的工作区与会话动作:开工作区、开会话、起会话、挑目录。
|
|
172
|
+
*/
|
|
113
173
|
export interface DshUiWorkspace {
|
|
114
174
|
openWorkspace(workspaceId: string): Promise<unknown>;
|
|
115
175
|
openSession(sessionId: string): void;
|
|
@@ -117,17 +177,26 @@ export interface DshUiWorkspace {
|
|
|
117
177
|
pickDirectory(): Promise<string | null>;
|
|
118
178
|
}
|
|
119
179
|
|
|
180
|
+
/**
|
|
181
|
+
* 工作区写口回的那点事实(新 id 或新标题);字段都可能缺,缺了按「没写回」算。
|
|
182
|
+
*/
|
|
120
183
|
export interface DshWorkspaceWritten {
|
|
121
184
|
readonly workspaceId?: string;
|
|
122
185
|
readonly title?: string;
|
|
123
186
|
}
|
|
124
187
|
|
|
188
|
+
/**
|
|
189
|
+
* dsh 的工作区服务:list 是可订阅快照,create 与 rename 是写口。
|
|
190
|
+
*/
|
|
125
191
|
export interface DshWorkspaces {
|
|
126
192
|
readonly list: DshObservable<WorkspaceSnapshot>;
|
|
127
193
|
create(request: { path: string }): Promise<DshWorkspaceWritten | undefined>;
|
|
128
194
|
rename(workspaceId: string, title: string): Promise<DshWorkspaceWritten>;
|
|
129
195
|
}
|
|
130
196
|
|
|
197
|
+
/**
|
|
198
|
+
* 往输入框插一条引用时要给的载荷:来源、引用文本、显示文案与剪贴板文本。
|
|
199
|
+
*/
|
|
131
200
|
export interface DshReferenceInsert {
|
|
132
201
|
readonly source: string;
|
|
133
202
|
readonly ref: string;
|
|
@@ -136,12 +205,18 @@ export interface DshReferenceInsert {
|
|
|
136
205
|
readonly clipboardText: string;
|
|
137
206
|
}
|
|
138
207
|
|
|
208
|
+
/**
|
|
209
|
+
* 输入框里一段 token 的区间;draftRev 用来确认还是同一版草稿,插入引用时用它定位。
|
|
210
|
+
*/
|
|
139
211
|
export interface DshTokenSpan {
|
|
140
212
|
readonly start: number;
|
|
141
213
|
readonly end: number;
|
|
142
214
|
readonly draftRev: number;
|
|
143
215
|
}
|
|
144
216
|
|
|
217
|
+
/**
|
|
218
|
+
* 某一个会话的输入框句柄;外壳借它插引用与弹提示,state 用来核对草稿版本。
|
|
219
|
+
*/
|
|
145
220
|
export interface DshSessionInput {
|
|
146
221
|
caretSpan?: () => { start: number; end: number };
|
|
147
222
|
readonly state: { getSnapshot(): { draftRev: number } | undefined };
|
|
@@ -149,6 +224,9 @@ export interface DshSessionInput {
|
|
|
149
224
|
notify(level: 'info' | 'error', text: string): void;
|
|
150
225
|
}
|
|
151
226
|
|
|
227
|
+
/**
|
|
228
|
+
* 注册 @ 触发源的口子:候选由外壳现取,选中后的动作也归外壳,dsh 只负责触发。
|
|
229
|
+
*/
|
|
152
230
|
export interface DshInputTriggers {
|
|
153
231
|
registerSource(source: {
|
|
154
232
|
readonly trigger: '@';
|
|
@@ -165,10 +243,16 @@ export interface DshInputTriggers {
|
|
|
165
243
|
}): () => void;
|
|
166
244
|
}
|
|
167
245
|
|
|
246
|
+
/**
|
|
247
|
+
* dsh 的对话服务;外壳只用它按会话取输入框句柄。
|
|
248
|
+
*/
|
|
168
249
|
export interface DshConversationService {
|
|
169
250
|
readonly input: { for(actx: unknown): DshSessionInput };
|
|
170
251
|
}
|
|
171
252
|
|
|
253
|
+
/**
|
|
254
|
+
* 浏览器侧的会话服务:快照加按 id 取作用域;create 是可选写口,不是每个 dsh 版本都有。
|
|
255
|
+
*/
|
|
172
256
|
export interface DshSessionsService {
|
|
173
257
|
readonly list: { getSnapshot(): SessionsSnapshot };
|
|
174
258
|
scope(sessionId: string): unknown | undefined;
|
|
@@ -180,11 +264,17 @@ export interface DshSessionsService {
|
|
|
180
264
|
}): Promise<unknown>;
|
|
181
265
|
}
|
|
182
266
|
|
|
267
|
+
/**
|
|
268
|
+
* dsh 侧最小的可订阅值:取当前快照加订阅变更,外壳用它接进 React。
|
|
269
|
+
*/
|
|
183
270
|
export interface DshObservable<T> {
|
|
184
271
|
getSnapshot(): T;
|
|
185
272
|
subscribe(listener: () => void): () => void;
|
|
186
273
|
}
|
|
187
274
|
|
|
275
|
+
/**
|
|
276
|
+
* dsh 的右栏服务:mounted 是在场与否的可订阅值,展开与开资源另走方法。
|
|
277
|
+
*/
|
|
188
278
|
export interface DshSidebarRight {
|
|
189
279
|
readonly mounted: DshObservable<string | undefined>;
|
|
190
280
|
isExpanded(): boolean;
|
|
@@ -193,6 +283,9 @@ export interface DshSidebarRight {
|
|
|
193
283
|
openTab(kind: string, options?: unknown): void;
|
|
194
284
|
}
|
|
195
285
|
|
|
286
|
+
/**
|
|
287
|
+
* remote.sessions 写口:在宿主侧建会话并回会话 id。
|
|
288
|
+
*/
|
|
196
289
|
export interface DshSessionsRemote {
|
|
197
290
|
create(request: {
|
|
198
291
|
readonly workspaceId?: string;
|
|
@@ -201,10 +294,16 @@ export interface DshSessionsRemote {
|
|
|
201
294
|
}): Promise<{ readonly sessionId: string }>;
|
|
202
295
|
}
|
|
203
296
|
|
|
297
|
+
/**
|
|
298
|
+
* dsh 客户端的远端写口集合;目前只有会话一家。
|
|
299
|
+
*/
|
|
204
300
|
export interface DshClientRemote {
|
|
205
301
|
readonly sessions: DshSessionsRemote;
|
|
206
302
|
}
|
|
207
303
|
|
|
304
|
+
/**
|
|
305
|
+
* 客户端插件拿到的上下文:所有服务从它取,effect 注册的清理随插件卸载跑。
|
|
306
|
+
*/
|
|
208
307
|
export interface DshClientContext {
|
|
209
308
|
get<T = unknown>(name: string): T | undefined;
|
|
210
309
|
provide(name: string, value: unknown): void;
|
package/src/api/dsh.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主侧的日志口;info 与 warn 都可能没有,调用前要判存在。
|
|
3
|
+
*/
|
|
1
4
|
export interface DshLogger {
|
|
2
5
|
info?(message: string): void;
|
|
3
6
|
warn?(message: string): void;
|
|
4
7
|
}
|
|
5
8
|
|
|
9
|
+
/**
|
|
10
|
+
* 宿主 HTTP 路由拿到的请求:方法与 URL,请求体是异步可迭代的字节流。
|
|
11
|
+
*/
|
|
6
12
|
export interface DshRequest {
|
|
7
13
|
readonly method?: string;
|
|
8
14
|
readonly url?: string;
|
|
9
15
|
[Symbol.asyncIterator]?(): AsyncIterator<Uint8Array>;
|
|
10
16
|
}
|
|
11
17
|
|
|
18
|
+
/**
|
|
19
|
+
* 宿主 HTTP 路由要写的响应:statusCode、setHeader 与 end 必备,流式那几个方法可选。
|
|
20
|
+
*/
|
|
12
21
|
export interface DshResponse {
|
|
13
22
|
statusCode: number;
|
|
14
23
|
setHeader(name: string, value: string): void;
|
|
@@ -18,32 +27,50 @@ export interface DshResponse {
|
|
|
18
27
|
on?(event: 'close', listener: () => void): void;
|
|
19
28
|
}
|
|
20
29
|
|
|
30
|
+
/**
|
|
31
|
+
* 一条挂到 dsh web 服务器上的路由;kind 说明 path 是前缀还是全等匹配,handler 自己写响应。
|
|
32
|
+
*/
|
|
21
33
|
export interface DshWebRoute {
|
|
22
34
|
readonly kind: 'prefix' | 'exact';
|
|
23
35
|
readonly path: string;
|
|
24
36
|
readonly handler: (req: DshRequest, res: DshResponse) => void | Promise<void>;
|
|
25
37
|
}
|
|
26
38
|
|
|
39
|
+
/**
|
|
40
|
+
* 宿主插件能看到的 profile 现场;dir 缺省表示 dsh 没给这个信息。
|
|
41
|
+
*/
|
|
27
42
|
export interface DshProfileContext {
|
|
28
43
|
readonly dir?: string;
|
|
29
44
|
}
|
|
30
45
|
|
|
46
|
+
/**
|
|
47
|
+
* 工具声明的静态半(名字加其余关键字);外壳只按 name 认工具。
|
|
48
|
+
*/
|
|
31
49
|
export interface DshToolSchema {
|
|
32
50
|
readonly name: string;
|
|
33
51
|
readonly [key: string]: unknown;
|
|
34
52
|
}
|
|
35
53
|
|
|
54
|
+
/**
|
|
55
|
+
* 系统提示词装配到一半的那份;tools 是可改的工具表,其余字段随 dsh。
|
|
56
|
+
*/
|
|
36
57
|
export interface DshPromptAssembly {
|
|
37
58
|
readonly tools?: readonly DshToolSchema[] | undefined;
|
|
38
59
|
readonly [key: string]: unknown;
|
|
39
60
|
}
|
|
40
61
|
|
|
62
|
+
/**
|
|
63
|
+
* 装配提示词时给判定方的现场(哪个 agent、哪个作用域);两者都可能缺。
|
|
64
|
+
*/
|
|
41
65
|
export interface DshAssemblyContext {
|
|
42
66
|
readonly agent?: unknown;
|
|
43
67
|
readonly scope?: unknown;
|
|
44
68
|
readonly [key: string]: unknown;
|
|
45
69
|
}
|
|
46
70
|
|
|
71
|
+
/**
|
|
72
|
+
* 宿主插件上下文:on 订阅 dsh 的钩子(提示词装配、工具执行前后、agent 生命周期),webServer 挂路由。
|
|
73
|
+
*/
|
|
47
74
|
export interface DshHostContext {
|
|
48
75
|
on?: {
|
|
49
76
|
(
|
|
@@ -107,6 +134,9 @@ export interface DshHostContext {
|
|
|
107
134
|
readonly webServer: { register(route: DshWebRoute): () => void };
|
|
108
135
|
}
|
|
109
136
|
|
|
137
|
+
/**
|
|
138
|
+
* 一次 shell 执行的结果口:result() 给退出码、超时与中断标志,以及截断过的 stdout / stderr。
|
|
139
|
+
*/
|
|
110
140
|
export interface DshShellExecution {
|
|
111
141
|
result(): Promise<{
|
|
112
142
|
exitCode: number | null;
|
|
@@ -117,6 +147,9 @@ export interface DshShellExecution {
|
|
|
117
147
|
}>;
|
|
118
148
|
}
|
|
119
149
|
|
|
150
|
+
/**
|
|
151
|
+
* dsh 的 shell 服务:先 resolve 出执行规格,再把它原样喂给 execute。
|
|
152
|
+
*/
|
|
120
153
|
export interface DshShell {
|
|
121
154
|
resolve(request: {
|
|
122
155
|
command: string;
|
|
@@ -129,14 +162,30 @@ export interface DshShell {
|
|
|
129
162
|
execute(spec: unknown): Promise<DshShellExecution>;
|
|
130
163
|
}
|
|
131
164
|
|
|
165
|
+
/** 一条工作区记录:id、磁盘路径与显示名(登记处按路径认领 / 新建时认的就是它)。 */
|
|
166
|
+
export interface DshWorkspaceRecord {
|
|
167
|
+
readonly id: string;
|
|
168
|
+
readonly path: string;
|
|
169
|
+
readonly title: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 宿主侧的工作区登记处:按 id 查、按路径认领、按路径新建。
|
|
174
|
+
*/
|
|
132
175
|
export interface DshWorkspaceRegistry {
|
|
133
176
|
get(id: string): { id: string; path?: string; title?: string } | undefined;
|
|
134
|
-
resolveByPath(path: string): Promise<
|
|
177
|
+
resolveByPath(path: string): Promise<DshWorkspaceRecord | undefined>;
|
|
135
178
|
create(path: string, title?: string): Promise<{ id?: string; path?: string; title?: string } | undefined>;
|
|
136
179
|
}
|
|
137
180
|
|
|
181
|
+
/**
|
|
182
|
+
* 把相对路径拼成 dsh home 下的绝对路径(服务名 dshHomePath);外壳存自己的状态用它,不自己拼 home。
|
|
183
|
+
*/
|
|
138
184
|
export type DshHomePath = (relative: string) => string;
|
|
139
185
|
|
|
186
|
+
/**
|
|
187
|
+
* 要注册进 dsh 的一把工具:名字、描述、参数表、输出渲染与执行体。
|
|
188
|
+
*/
|
|
140
189
|
export interface DshToolDefinition {
|
|
141
190
|
name: string;
|
|
142
191
|
description: string;
|
|
@@ -148,6 +197,9 @@ export interface DshToolDefinition {
|
|
|
148
197
|
execute(args: unknown, exec: DshToolRunContext): Promise<unknown>;
|
|
149
198
|
}
|
|
150
199
|
|
|
200
|
+
/**
|
|
201
|
+
* 工具执行时给的那点现场(会话 id 与 cwd);层级都可能缺,缺了就当不知道。
|
|
202
|
+
*/
|
|
151
203
|
export interface DshToolRunContext {
|
|
152
204
|
readonly agent?:
|
|
153
205
|
| {
|
|
@@ -161,6 +213,9 @@ export interface DshToolRunContext {
|
|
|
161
213
|
| undefined;
|
|
162
214
|
}
|
|
163
215
|
|
|
216
|
+
/**
|
|
217
|
+
* dsh 的工具表;register 回的清理函数负责在插件卸载时摘掉这条工具。
|
|
218
|
+
*/
|
|
164
219
|
export interface DshToolRegistry {
|
|
165
220
|
register(definition: DshToolDefinition): () => void;
|
|
166
221
|
}
|
package/src/api/facts.ts
CHANGED
|
@@ -1,27 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主推来的一帧事实变更:rev 在同一纪元里单调,facts 是这一帧动过的名字。
|
|
3
|
+
*/
|
|
1
4
|
export interface FactFrame {
|
|
2
5
|
readonly epoch?: string;
|
|
3
6
|
readonly rev: number;
|
|
4
7
|
readonly facts: readonly string[];
|
|
5
8
|
}
|
|
6
9
|
|
|
10
|
+
/**
|
|
11
|
+
* 范围查法的后缀:cmdb/* 这类名字表示「这个前缀下的一族」,不是一条事实。
|
|
12
|
+
*/
|
|
7
13
|
export const FACT_SCOPE_SUFFIX = '*';
|
|
8
14
|
|
|
15
|
+
/**
|
|
16
|
+
* 由单元 id 拼出它那一族事实的范围名。
|
|
17
|
+
* @param unit 单元 id,不带后缀。
|
|
18
|
+
* @returns <unit>* —— 永远是范围名,不是某一条事实。
|
|
19
|
+
*/
|
|
9
20
|
export function unitFactScope(unit: string): string {
|
|
10
21
|
return `${unit}${FACT_SCOPE_SUFFIX}`;
|
|
11
22
|
}
|
|
12
23
|
|
|
24
|
+
/**
|
|
25
|
+
* 判一个名字是不是范围查法,不是问这条事实存不存在。
|
|
26
|
+
* @param name 事实名或范围名。
|
|
27
|
+
* @returns 单字符 * 不算范围;只有「至少一个字符加 *」才算。
|
|
28
|
+
*/
|
|
13
29
|
export function isFactScope(name: string): boolean {
|
|
14
30
|
return name.length > 1 && name.endsWith(FACT_SCOPE_SUFFIX);
|
|
15
31
|
}
|
|
16
32
|
|
|
33
|
+
/**
|
|
34
|
+
* 取范围名对应的前缀,普通事实名原样返回。
|
|
35
|
+
* @param name 事实名或范围名。
|
|
36
|
+
* @returns 去掉末尾 * 的前缀;本来不是范围就给原值。
|
|
37
|
+
*/
|
|
17
38
|
export function scopePrefixOf(name: string): string {
|
|
18
39
|
return isFactScope(name) ? name.slice(0, -FACT_SCOPE_SUFFIX.length) : name;
|
|
19
40
|
}
|
|
20
41
|
|
|
42
|
+
/**
|
|
43
|
+
* 事实的来路:start 建连并按帧回调,cursor 报已收到的宿主 rev(断线重连时交给宿主)。
|
|
44
|
+
*/
|
|
21
45
|
export interface FactTransport {
|
|
22
46
|
start(handlers: { readonly onFrame: (frame: FactFrame) => void; readonly cursor: () => number }): () => void;
|
|
23
47
|
}
|
|
24
48
|
|
|
49
|
+
/**
|
|
50
|
+
* 浏览器侧的事实通道:订阅、读版本、手动刷新,帧到了由它分发给订阅者。
|
|
51
|
+
*/
|
|
25
52
|
export interface FactChannel {
|
|
26
53
|
subscribe(fact: string, listener: () => void): () => void;
|
|
27
54
|
revisionOf(fact: string): number;
|
|
@@ -35,6 +62,11 @@ interface FactEntry {
|
|
|
35
62
|
readonly listeners: Set<() => void>;
|
|
36
63
|
}
|
|
37
64
|
|
|
65
|
+
/**
|
|
66
|
+
* 造一条事实通道:第一次订阅时才连传输层,最后一个订阅者走掉就断开。
|
|
67
|
+
* @param options 传输层,用来连宿主。
|
|
68
|
+
* @returns 通道句柄;没记录过的事实版本给 0,refresh() 不带事实名时刷新全部并逐个通知。
|
|
69
|
+
*/
|
|
38
70
|
export function createFactChannel(options: { readonly transport: FactTransport }): FactChannel {
|
|
39
71
|
const entries = new Map<string, FactEntry>();
|
|
40
72
|
let epoch: string | null = null;
|
|
@@ -146,6 +178,11 @@ export function createFactChannel(options: { readonly transport: FactTransport }
|
|
|
146
178
|
return channel;
|
|
147
179
|
}
|
|
148
180
|
|
|
181
|
+
/**
|
|
182
|
+
* 把传输层收到的原始数据读成一帧;坏数据当没收到。
|
|
183
|
+
* @param data 帧的原始数据,期望是 JSON 字符串。
|
|
184
|
+
* @returns 合法帧;不是字符串、JSON 坏了、或 rev 不是数字都给 null。
|
|
185
|
+
*/
|
|
149
186
|
export function parseFactFrame(data: unknown): FactFrame | null {
|
|
150
187
|
if (typeof data !== 'string') return null;
|
|
151
188
|
try {
|
|
@@ -161,6 +198,11 @@ export function parseFactFrame(data: unknown): FactFrame | null {
|
|
|
161
198
|
}
|
|
162
199
|
}
|
|
163
200
|
|
|
201
|
+
/**
|
|
202
|
+
* 读口路由到事实名的映射,当前一对一。
|
|
203
|
+
* @param route 读口路由。
|
|
204
|
+
* @returns 该路由对应的事实名(就是路由本身)。
|
|
205
|
+
*/
|
|
164
206
|
export function factOfRoute(route: string): string {
|
|
165
207
|
return route;
|
|
166
208
|
}
|
package/src/api/host-write.ts
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import type { ApiResponse } from './workbench-client.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 宿主写口的五条通道(偏好、动作、供给、工坊调试、工坊录制),是写路由的第一段。
|
|
5
|
+
*/
|
|
3
6
|
export type WriteChannel =
|
|
4
7
|
| 'prefs'
|
|
5
8
|
| 'actions'
|
|
6
9
|
| 'provision'
|
|
7
|
-
| 'diy-debug'
|
|
10
|
+
| 'diy-debug'
|
|
11
|
+
| 'diy-record';
|
|
8
12
|
|
|
13
|
+
/**
|
|
14
|
+
* 由通道与资源拼出写路由。
|
|
15
|
+
* @param channel 写通道。
|
|
16
|
+
* @param resource 该通道下的资源名。
|
|
17
|
+
* @returns 路由字符串;provision 只有一段,其余是 channel/resource。
|
|
18
|
+
*/
|
|
9
19
|
export function writeRoute(channel: WriteChannel, resource: string): string {
|
|
10
20
|
if (channel === 'provision') return 'provision';
|
|
11
21
|
return `${channel}/${resource}`;
|
|
12
22
|
}
|
|
13
23
|
|
|
24
|
+
/**
|
|
25
|
+
* 写通道统一的结果:成了带值,没成带一句能给人看的话(可选明细与帮助链接)。
|
|
26
|
+
*/
|
|
14
27
|
export type WriteOutcome<T> =
|
|
15
28
|
| { readonly ok: true; readonly value: T }
|
|
16
29
|
| {
|
|
@@ -20,6 +33,12 @@ export type WriteOutcome<T> =
|
|
|
20
33
|
readonly helpUrl?: string;
|
|
21
34
|
};
|
|
22
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 把写通道的响应翻成 WriteOutcome。
|
|
38
|
+
* @param response 写口回的响应;null 表示请求本身没成(网络断了,宿主没答)。
|
|
39
|
+
* @param networkText 拿不到任何服务端文案时兜底的那句。
|
|
40
|
+
* @returns 失败时 message 优先用服务端自己的话,没有才用响应正文或 networkText。
|
|
41
|
+
*/
|
|
23
42
|
export function writeOutcomeOf<T>(response: ApiResponse<T> | null, networkText: string): WriteOutcome<T> {
|
|
24
43
|
if (response === null) return { ok: false, message: networkText };
|
|
25
44
|
if (!response.ok) {
|
package/src/api/long-task.ts
CHANGED
|
@@ -1,28 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一条长任务的四种态;needs-login 与 running 一样算还没结束。
|
|
3
|
+
*/
|
|
1
4
|
export type LongTaskStatus = 'running' | 'needs-login' | 'ok' | 'failed';
|
|
2
5
|
|
|
6
|
+
/**
|
|
7
|
+
* 长任务步骤流里的一行:kind 定样式,登录那一步带 loginUrl 给用户去点。
|
|
8
|
+
*/
|
|
3
9
|
export interface LongTaskStep {
|
|
4
10
|
readonly kind: 'start' | 'succeed' | 'fail' | 'info' | 'warn';
|
|
5
11
|
readonly text: string;
|
|
6
12
|
readonly loginUrl?: string | undefined;
|
|
7
13
|
}
|
|
8
14
|
|
|
15
|
+
/**
|
|
16
|
+
* 单元的长任务读口路由。
|
|
17
|
+
* @param unit 单元 id。
|
|
18
|
+
* @returns <unit>/runs。
|
|
19
|
+
*/
|
|
9
20
|
export function runsRouteOf(unit: string): string {
|
|
10
21
|
return `${unit}/runs`;
|
|
11
22
|
}
|
|
12
23
|
|
|
24
|
+
/**
|
|
25
|
+
* 长任务读口回的载荷:一串 run,形状由模块自己定,外壳只透传。
|
|
26
|
+
*/
|
|
13
27
|
export interface LongTasksPayload {
|
|
14
28
|
readonly runs: readonly Readonly<Record<string, unknown>>[];
|
|
15
29
|
}
|
|
16
30
|
|
|
31
|
+
/**
|
|
32
|
+
* 有长任务在跑时的轮询间隔(毫秒)。
|
|
33
|
+
*/
|
|
17
34
|
export const LONG_TASK_POLL_MS = 1500;
|
|
18
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 没有长任务时的轮询间隔(毫秒),比在跑那一档大一个量级。
|
|
38
|
+
*/
|
|
19
39
|
export const LONG_TASK_IDLE_MS = 10_000;
|
|
20
40
|
|
|
41
|
+
/**
|
|
42
|
+
* 算这次该隔多久再问一次长任务。
|
|
43
|
+
* @param live 是否有在跑的长任务。
|
|
44
|
+
* @param override 调用点指定的间隔;给了就用它,不再看 live。
|
|
45
|
+
* @returns 毫秒:有活 1500,没活 10000。
|
|
46
|
+
*/
|
|
21
47
|
export function longTaskPollMs(live: boolean, override?: number | undefined): number {
|
|
22
48
|
if (override !== undefined) return override;
|
|
23
49
|
return live ? LONG_TASK_POLL_MS : LONG_TASK_IDLE_MS;
|
|
24
50
|
}
|
|
25
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 从读口状态里取 run 列表。
|
|
54
|
+
* @param state 读口状态;value 还没到就按空算。
|
|
55
|
+
* @returns 一串 run(形状由调用点自己判),没有就给空数组。
|
|
56
|
+
*/
|
|
26
57
|
export function longTaskRunsOf<T>(state: {
|
|
27
58
|
readonly phase?: string | undefined;
|
|
28
59
|
readonly value?: LongTasksPayload | undefined;
|
|
@@ -30,6 +61,11 @@ export function longTaskRunsOf<T>(state: {
|
|
|
30
61
|
return (state.value?.runs ?? []) as readonly T[];
|
|
31
62
|
}
|
|
32
63
|
|
|
64
|
+
/**
|
|
65
|
+
* 把长任务态折成状态点的那一档。
|
|
66
|
+
* @param status 长任务的四种态。
|
|
67
|
+
* @returns ongoing / done / error / idle;needs-login 也算进行中。
|
|
68
|
+
*/
|
|
33
69
|
export function longTaskDot(status: LongTaskStatus): 'ongoing' | 'done' | 'error' | 'idle' {
|
|
34
70
|
if (status === 'ok') return 'done';
|
|
35
71
|
if (status === 'failed') return 'error';
|
package/src/api/unit-board.ts
CHANGED
|
@@ -2,25 +2,45 @@ import type { ModuleBlocker } from './blocker.js';
|
|
|
2
2
|
import type { CapabilityPayload } from './workbench-contract.js';
|
|
3
3
|
import type { ApiError } from './workbench-client.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* 卡片闸的两种档:capability 按环境读数判,none 无条件放行。
|
|
7
|
+
*/
|
|
5
8
|
export type GateMode =
|
|
6
9
|
| 'capability'
|
|
7
10
|
| 'none';
|
|
8
11
|
|
|
12
|
+
/**
|
|
13
|
+
* 一次放行判定的结果;gated 为假时卡片不画。
|
|
14
|
+
*/
|
|
9
15
|
export interface UnitGate {
|
|
10
16
|
readonly gated: boolean;
|
|
11
17
|
}
|
|
12
18
|
|
|
19
|
+
/**
|
|
20
|
+
* 判这张卡现在能不能画。
|
|
21
|
+
* @param capability 环境读数;还没读到给 null。
|
|
22
|
+
* @param mode 闸档。
|
|
23
|
+
* @returns mode 为 none 或读数还没到都放行(先放行让它读);读到明确不通过(ok 与 unchecked 之外)才拦。
|
|
24
|
+
*/
|
|
13
25
|
export function gateOf(capability: CapabilityPayload | null, mode: GateMode): UnitGate {
|
|
14
26
|
if (mode === 'none') return { gated: true };
|
|
15
27
|
if (capability === null) return { gated: true };
|
|
16
28
|
return { gated: capability.status === 'ok' || capability.status === 'unchecked' };
|
|
17
29
|
}
|
|
18
30
|
|
|
31
|
+
/**
|
|
32
|
+
* 一个单元攒下的卡住态:blocker 顶掉卡片,notice 只提示;组装方产出,卡片消费。
|
|
33
|
+
*/
|
|
19
34
|
export interface UnitBlockers {
|
|
20
35
|
readonly blocker?: ModuleBlocker;
|
|
21
36
|
readonly notice?: ModuleBlocker;
|
|
22
37
|
}
|
|
23
38
|
|
|
39
|
+
/**
|
|
40
|
+
* 把候选卡住态分档,每档只留第一个。
|
|
41
|
+
* @param candidates 候选(可能含 undefined),按优先级从高到低给。
|
|
42
|
+
* @returns 分出的 blocker 与 notice;已经有 blocker 时不带 notice(挡住就不必再提示)。
|
|
43
|
+
*/
|
|
24
44
|
export function splitBlocker(candidates: readonly (ModuleBlocker | undefined)[]): UnitBlockers {
|
|
25
45
|
let blocker: ModuleBlocker | undefined;
|
|
26
46
|
let notice: ModuleBlocker | undefined;
|
|
@@ -38,6 +58,11 @@ export function splitBlocker(candidates: readonly (ModuleBlocker | undefined)[])
|
|
|
38
58
|
};
|
|
39
59
|
}
|
|
40
60
|
|
|
61
|
+
/**
|
|
62
|
+
* 由读口错误算出「出错搭车强探」的防抖键:同一个键只自动重探一次。
|
|
63
|
+
* @param error 读口错误;undefined 表示这次没有错误。
|
|
64
|
+
* @returns 键字符串;空 code 归一到 unknown。
|
|
65
|
+
*/
|
|
41
66
|
export function probeKeyOf(error: ApiError | undefined): string | null {
|
|
42
67
|
if (error === undefined) return null;
|
|
43
68
|
return error.code === '' ? 'unknown' : error.code;
|