@dsh-workbench/shared 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/api/blocker-table.d.ts +13 -0
  2. package/dist/api/blocker-table.js +13 -0
  3. package/dist/api/blocker.d.ts +6 -0
  4. package/dist/api/context-ref.d.ts +31 -0
  5. package/dist/api/context-ref.js +28 -0
  6. package/dist/api/dsh-client.d.ts +99 -0
  7. package/dist/api/dsh.d.ts +55 -3
  8. package/dist/api/facts.d.ts +42 -0
  9. package/dist/api/facts.js +33 -0
  10. package/dist/api/host-write.d.ts +18 -0
  11. package/dist/api/host-write.js +12 -0
  12. package/dist/api/long-task.d.ts +66 -1
  13. package/dist/api/long-task.js +59 -0
  14. package/dist/api/unit-board.d.ts +25 -0
  15. package/dist/api/unit-board.js +16 -0
  16. package/dist/api/unit-declaration.d.ts +36 -0
  17. package/dist/api/unit-declaration.js +24 -0
  18. package/dist/api/unit.d.ts +32 -0
  19. package/dist/api/unit.js +5 -0
  20. package/dist/api/workbench-client.d.ts +25 -0
  21. package/dist/api/workbench-client.js +13 -0
  22. package/dist/api/workbench-contract.d.ts +12 -0
  23. package/dist/components/Activity.d.ts +33 -0
  24. package/dist/components/Activity.js +24 -0
  25. package/dist/components/ApprovalDetail.d.ts +12 -0
  26. package/dist/components/ApprovalDetail.js +9 -0
  27. package/dist/components/ApprovalPlan.d.ts +14 -0
  28. package/dist/components/ApprovalPlan.js +8 -0
  29. package/dist/components/Card.d.ts +13 -0
  30. package/dist/components/Card.js +10 -0
  31. package/dist/components/CardAnchor.d.ts +14 -0
  32. package/dist/components/CardAnchor.js +11 -0
  33. package/dist/components/CardBoundary.d.ts +20 -0
  34. package/dist/components/CardBoundary.js +14 -0
  35. package/dist/components/CardHead.d.ts +13 -0
  36. package/dist/components/CardHead.js +10 -0
  37. package/dist/components/ChoiceGroup.d.ts +24 -0
  38. package/dist/components/ChoiceGroup.js +12 -0
  39. package/dist/components/Field.d.ts +10 -0
  40. package/dist/components/Field.js +7 -0
  41. package/dist/components/Form.css +6 -0
  42. package/dist/components/Form.d.ts +20 -0
  43. package/dist/components/Form.js +58 -0
  44. package/dist/components/FormActions.d.ts +14 -0
  45. package/dist/components/FormActions.js +5 -0
  46. package/dist/components/FormNodes.d.ts +103 -0
  47. package/dist/components/FormNodes.js +153 -0
  48. package/dist/components/FormRows.css +31 -0
  49. package/dist/components/FormRows.d.ts +20 -0
  50. package/dist/components/FormRows.js +14 -0
  51. package/dist/components/FormTypes.d.ts +59 -0
  52. package/dist/components/FormTypes.js +1 -0
  53. package/dist/components/Link.d.ts +12 -0
  54. package/dist/components/Link.js +9 -0
  55. package/dist/components/LongTaskRow.css +52 -0
  56. package/dist/components/LongTaskRow.d.ts +35 -0
  57. package/dist/components/LongTaskRow.js +45 -4
  58. package/dist/components/Note.d.ts +11 -0
  59. package/dist/components/Note.js +8 -0
  60. package/dist/components/ResourceStates.d.ts +25 -0
  61. package/dist/components/ResourceStates.js +22 -0
  62. package/dist/components/Rows.d.ts +17 -0
  63. package/dist/components/Rows.js +11 -0
  64. package/dist/components/SaveBar.d.ts +12 -0
  65. package/dist/components/SaveBar.js +9 -0
  66. package/dist/components/SelectField.d.ts +26 -0
  67. package/dist/components/SelectField.js +22 -0
  68. package/dist/components/SelectFieldNodes.d.ts +24 -0
  69. package/dist/components/SelectFieldNodes.js +24 -0
  70. package/dist/components/SettingsSection.d.ts +11 -0
  71. package/dist/components/SettingsSection.js +8 -0
  72. package/dist/components/Spinner.d.ts +9 -0
  73. package/dist/components/Spinner.js +6 -0
  74. package/dist/components/Stack.d.ts +8 -0
  75. package/dist/components/Stack.js +5 -0
  76. package/dist/components/StateBlock.d.ts +13 -0
  77. package/dist/components/StateBlock.js +10 -0
  78. package/dist/components/TextField.d.ts +8 -0
  79. package/dist/components/TextField.js +5 -0
  80. package/dist/components/board-module.d.ts +30 -0
  81. package/dist/components/icons.d.ts +38 -0
  82. package/dist/components/icons.js +35 -0
  83. package/dist/config/constants.d.ts +42 -0
  84. package/dist/config/constants.js +42 -0
  85. package/dist/config/storage.d.ts +4 -0
  86. package/dist/config/storage.js +4 -0
  87. package/dist/host/long-task.d.ts +7 -0
  88. package/dist/host/long-task.js +31 -5
  89. package/dist/host/tool-approval.d.ts +1 -0
  90. package/dist/host/unit-face.d.ts +6 -1
  91. package/dist/i18n/en.d.ts +1 -0
  92. package/dist/i18n/en.js +10 -8
  93. package/dist/i18n/index.d.ts +13 -9
  94. package/dist/i18n/index.js +1 -0
  95. package/dist/i18n/merge.d.ts +5 -0
  96. package/dist/i18n/merge.js +2 -0
  97. package/dist/i18n/zh.d.ts +11 -8
  98. package/dist/i18n/zh.js +10 -8
  99. package/dist/index.d.ts +6 -2
  100. package/dist/index.js +6 -2
  101. package/dist/lib/blocker-action.d.ts +22 -0
  102. package/dist/lib/blocker-action.js +13 -0
  103. package/dist/lib/board-fact.d.ts +27 -0
  104. package/dist/lib/board-fact.js +18 -0
  105. package/dist/lib/busy.d.ts +10 -0
  106. package/dist/lib/busy.js +7 -0
  107. package/dist/lib/diy-debug.d.ts +42 -2
  108. package/dist/lib/diy-debug.js +19 -1
  109. package/dist/lib/diy-record.d.ts +41 -0
  110. package/dist/lib/diy-record.js +17 -0
  111. package/dist/lib/form-problem.d.ts +10 -0
  112. package/dist/lib/form-problem.js +10 -0
  113. package/dist/lib/panel-state.d.ts +60 -0
  114. package/dist/lib/panel-state.js +30 -0
  115. package/dist/lib/react.d.ts +39 -0
  116. package/dist/lib/react.js +36 -0
  117. package/dist/lib/text.d.ts +22 -0
  118. package/dist/lib/text.js +22 -0
  119. package/dist/lib/ui.d.ts +50 -0
  120. package/dist/lib/ui.js +41 -0
  121. package/package.json +1 -1
  122. package/src/api/__tests__/long-task.test.ts +41 -1
  123. package/src/api/blocker-table.ts +13 -0
  124. package/src/api/blocker.ts +6 -0
  125. package/src/api/context-ref.ts +31 -0
  126. package/src/api/dsh-client.ts +99 -0
  127. package/src/api/dsh.ts +56 -1
  128. package/src/api/facts.ts +42 -0
  129. package/src/api/host-write.ts +18 -0
  130. package/src/api/long-task.ts +79 -1
  131. package/src/api/unit-board.ts +25 -0
  132. package/src/api/unit-declaration.ts +36 -0
  133. package/src/api/unit.ts +32 -0
  134. package/src/api/workbench-client.ts +25 -0
  135. package/src/api/workbench-contract.ts +12 -0
  136. package/src/components/Activity.tsx +33 -0
  137. package/src/components/ApprovalDetail.tsx +12 -0
  138. package/src/components/ApprovalPlan.tsx +14 -0
  139. package/src/components/Card.tsx +13 -0
  140. package/src/components/CardAnchor.tsx +14 -0
  141. package/src/components/CardBoundary.tsx +20 -0
  142. package/src/components/CardHead.tsx +13 -0
  143. package/src/components/ChoiceGroup.tsx +24 -0
  144. package/src/components/Field.tsx +10 -0
  145. package/src/components/Form.css +6 -0
  146. package/src/components/Form.test.tsx +475 -0
  147. package/src/components/Form.tsx +78 -0
  148. package/src/components/FormActions.tsx +14 -0
  149. package/src/components/FormNodes.tsx +193 -0
  150. package/src/components/FormRows.css +31 -0
  151. package/src/components/FormRows.test.tsx +71 -1
  152. package/src/components/FormRows.tsx +20 -0
  153. package/src/components/FormTypes.ts +65 -0
  154. package/src/components/FormWiring.test.tsx +88 -0
  155. package/src/components/Link.tsx +12 -0
  156. package/src/components/LongTaskRow.css +52 -0
  157. package/src/components/LongTaskRow.tsx +76 -2
  158. package/src/components/Note.tsx +11 -0
  159. package/src/components/ResourceStates.tsx +25 -0
  160. package/src/components/Rows.tsx +17 -0
  161. package/src/components/SaveBar.tsx +12 -0
  162. package/src/components/SelectField.tsx +26 -0
  163. package/src/components/SelectFieldNodes.tsx +24 -0
  164. package/src/components/SettingsSection.tsx +11 -0
  165. package/src/components/Spinner.tsx +9 -0
  166. package/src/components/Stack.tsx +8 -0
  167. package/src/components/StateBlock.tsx +13 -0
  168. package/src/components/TextField.tsx +8 -0
  169. package/src/components/__tests__/long-task-row.test.ts +115 -0
  170. package/src/components/board-module.ts +30 -0
  171. package/src/components/icons.tsx +38 -0
  172. package/src/config/constants.ts +43 -0
  173. package/src/config/storage.ts +4 -0
  174. package/src/host/__tests__/long-task.test.ts +264 -0
  175. package/src/host/long-task.ts +43 -7
  176. package/src/host/tool-approval.ts +1 -0
  177. package/src/host/unit-face.ts +7 -1
  178. package/src/i18n/en.ts +11 -8
  179. package/src/i18n/index.ts +3 -0
  180. package/src/i18n/merge.ts +5 -0
  181. package/src/i18n/zh.ts +11 -8
  182. package/src/index.ts +6 -2
  183. package/src/lib/blocker-action.ts +22 -0
  184. package/src/lib/board-fact.ts +27 -0
  185. package/src/lib/busy.ts +10 -0
  186. package/src/lib/diy-debug.test.ts +2 -1
  187. package/src/lib/diy-debug.ts +44 -3
  188. package/src/lib/diy-record.ts +41 -0
  189. package/src/lib/form-problem.ts +10 -0
  190. package/src/lib/panel-state.ts +60 -0
  191. package/src/lib/react.ts +39 -0
  192. package/src/lib/text.ts +22 -0
  193. package/src/lib/ui.ts +50 -0
@@ -2,8 +2,21 @@ import type { Translate } from './dsh-client.js';
2
2
  import type { CapabilityPayload } from './workbench-contract.js';
3
3
  import type { ApiError } from './workbench-client.js';
4
4
  import type { ModuleBlocker } from './blocker.js';
5
+ /**
6
+ * 把一次读失败翻成一张卡住态,交给卡片直接渲染。
7
+ * @param error 读口回的错误;undefined 表示连错误都没拿到(多半是网络断,回「原因未知」)。
8
+ * @param t 文案函数,只取 blocker.* 命名空间的键。
9
+ * @param context 判定现场;platform 缺省时标题不带平台名。
10
+ * @returns 一定有一张卡,actions 至少一颗「重试」。
11
+ */
5
12
  export declare function blockerOfError(error: ApiError | undefined, t: Translate, context?: {
6
13
  path?: string | null;
7
14
  platform?: string;
8
15
  }): ModuleBlocker;
16
+ /**
17
+ * 把宿主回的环境读数翻成卡住态:探针没查过(unchecked)只算提示,不挡卡片。
18
+ * @param capability 宿主回的单元环境读数。
19
+ * @param t 文案函数,键都在 env.unit.* / blocker.* 下。
20
+ * @returns status 为 'ok' 时给 undefined(没有卡住态),其余状态一律给一张。
21
+ */
9
22
  export declare function blockerOfCapability(capability: CapabilityPayload, t: Translate): ModuleBlocker | undefined;
@@ -5,6 +5,13 @@ function retryAction(t) {
5
5
  function copyAction(t, text) {
6
6
  return { kind: 'copy', label: t('blocker.copy'), text };
7
7
  }
8
+ /**
9
+ * 把一次读失败翻成一张卡住态,交给卡片直接渲染。
10
+ * @param error 读口回的错误;undefined 表示连错误都没拿到(多半是网络断,回「原因未知」)。
11
+ * @param t 文案函数,只取 blocker.* 命名空间的键。
12
+ * @param context 判定现场;platform 缺省时标题不带平台名。
13
+ * @returns 一定有一张卡,actions 至少一颗「重试」。
14
+ */
8
15
  export function blockerOfError(error, t, context = {}) {
9
16
  if (error === undefined) {
10
17
  return {
@@ -82,6 +89,12 @@ export function blockerOfError(error, t, context = {}) {
82
89
  };
83
90
  }
84
91
  }
92
+ /**
93
+ * 把宿主回的环境读数翻成卡住态:探针没查过(unchecked)只算提示,不挡卡片。
94
+ * @param capability 宿主回的单元环境读数。
95
+ * @param t 文案函数,键都在 env.unit.* / blocker.* 下。
96
+ * @returns status 为 'ok' 时给 undefined(没有卡住态),其余状态一律给一张。
97
+ */
85
98
  export function blockerOfCapability(capability, t) {
86
99
  if (capability.status === 'ok')
87
100
  return undefined;
@@ -1,3 +1,6 @@
1
+ /**
2
+ * 卡住时用户能点的那一下(开链接 / 复制命令 / 重试 / 装或升模块):由判据产出,卡片照原样渲染。
3
+ */
1
4
  export type BlockerAction = {
2
5
  readonly kind: 'open-url';
3
6
  readonly label: string;
@@ -20,6 +23,9 @@ export type BlockerAction = {
20
23
  readonly label: string;
21
24
  readonly unit: string;
22
25
  };
26
+ /**
27
+ * 一个单元此刻的卡住态:block 顶掉整张卡片,notice 只在角上提示一句;读口与探针产出,卡片消费。
28
+ */
23
29
  export interface ModuleBlocker {
24
30
  readonly id: string;
25
31
  readonly severity: 'block' | 'notice';
@@ -1,10 +1,41 @@
1
+ /**
2
+ * 引用标记的固定名字;完整标记是 @<这个名字>:<编码文本>,改它等于作废历史会话里已写下的引用。
3
+ */
1
4
  export declare const CONTEXT_MARKER_NAME = "\u5DE5\u4F5C\u53F0";
5
+ /**
6
+ * 一条解析后的引用(种类加路径分段):输入框写标记时产出,跳转与展示时消费。
7
+ */
2
8
  export interface ContextRef {
3
9
  readonly kind: string;
4
10
  readonly parts: readonly string[];
5
11
  }
12
+ /**
13
+ * 把引用拼回标记体里的那一段文本(不含 @ 与标记名)。
14
+ * @param ref 要拼的引用。
15
+ * @returns 形如 kind:part/part;分段里的 / 不转义,所以分段名本身不能含 /。
16
+ */
6
17
  export declare function encodeRef(ref: ContextRef): string;
18
+ /**
19
+ * 把 kind:part/part 文本读回引用。
20
+ * @param text 待解析文本。
21
+ * @returns 没冒号、冒号在首尾、种类不是小写字母开头、或冒号后为空时给 undefined;不抛异常。
22
+ */
7
23
  export declare function decodeRef(text: string): ContextRef | undefined;
24
+ /**
25
+ * 拼出 @ 后面那半截(标记名加已编码文本),比较与拼接都用它。
26
+ * @param encoded encodeRef 的结果。
27
+ * @returns 形如 工作台:file:src/a.ts。
28
+ */
8
29
  export declare function markerBody(encoded: string): string;
30
+ /**
31
+ * 把一条引用拼成能写进对话文本的完整标记。
32
+ * @param ref 要标记的引用。
33
+ * @returns 形如 @工作台:file:src/a.ts 的一段文本。
34
+ */
9
35
  export declare function buildMarker(ref: ContextRef): string;
36
+ /**
37
+ * 从一段文本里按出现顺序捞出所有标记引用,同一个引用只留第一次。
38
+ * @param text 任意文本;null / undefined 当空串。
39
+ * @returns 解析不出来的标记会被丢掉,所以结果只含合法引用,可能为空数组。
40
+ */
10
41
  export declare function parseMarkers(text: string): ContextRef[];
@@ -1,9 +1,22 @@
1
+ /**
2
+ * 引用标记的固定名字;完整标记是 @<这个名字>:<编码文本>,改它等于作废历史会话里已写下的引用。
3
+ */
1
4
  export const CONTEXT_MARKER_NAME = '工作台';
2
5
  const MARKER = new RegExp(`@${CONTEXT_MARKER_NAME}:([a-z][a-z0-9-]*:[A-Za-z0-9._~%#/-]+)`, 'g');
3
6
  const TRAILING_PUNCTUATION = /[.,;:!?]+$/;
7
+ /**
8
+ * 把引用拼回标记体里的那一段文本(不含 @ 与标记名)。
9
+ * @param ref 要拼的引用。
10
+ * @returns 形如 kind:part/part;分段里的 / 不转义,所以分段名本身不能含 /。
11
+ */
4
12
  export function encodeRef(ref) {
5
13
  return `${ref.kind}:${ref.parts.join('/')}`;
6
14
  }
15
+ /**
16
+ * 把 kind:part/part 文本读回引用。
17
+ * @param text 待解析文本。
18
+ * @returns 没冒号、冒号在首尾、种类不是小写字母开头、或冒号后为空时给 undefined;不抛异常。
19
+ */
7
20
  export function decodeRef(text) {
8
21
  const at = text.indexOf(':');
9
22
  if (at <= 0 || at === text.length - 1)
@@ -16,12 +29,27 @@ export function decodeRef(text) {
16
29
  return undefined;
17
30
  return { kind, parts };
18
31
  }
32
+ /**
33
+ * 拼出 @ 后面那半截(标记名加已编码文本),比较与拼接都用它。
34
+ * @param encoded encodeRef 的结果。
35
+ * @returns 形如 工作台:file:src/a.ts。
36
+ */
19
37
  export function markerBody(encoded) {
20
38
  return `${CONTEXT_MARKER_NAME}:${encoded}`;
21
39
  }
40
+ /**
41
+ * 把一条引用拼成能写进对话文本的完整标记。
42
+ * @param ref 要标记的引用。
43
+ * @returns 形如 @工作台:file:src/a.ts 的一段文本。
44
+ */
22
45
  export function buildMarker(ref) {
23
46
  return `@${markerBody(encodeRef(ref))}`;
24
47
  }
48
+ /**
49
+ * 从一段文本里按出现顺序捞出所有标记引用,同一个引用只留第一次。
50
+ * @param text 任意文本;null / undefined 当空串。
51
+ * @returns 解析不出来的标记会被丢掉,所以结果只含合法引用,可能为空数组。
52
+ */
25
53
  export function parseMarkers(text) {
26
54
  const seen = new Set();
27
55
  const refs = [];
@@ -1,4 +1,7 @@
1
1
  import type { ReactNode } from 'react';
2
+ /**
3
+ * 左栏一行的来源:dsh workspaces.list 快照里的一项,两个时间戳都是毫秒。
4
+ */
2
5
  export interface WorkspaceView {
3
6
  readonly workspaceId: string;
4
7
  readonly path: string;
@@ -7,11 +10,17 @@ export interface WorkspaceView {
7
10
  readonly createdAt: number;
8
11
  readonly updatedAt: number;
9
12
  }
13
+ /**
14
+ * workspaces.list 的整份快照:可见工作区,加上归档与置顶的会话 id;外壳只读不改。
15
+ */
10
16
  export interface WorkspaceSnapshot {
11
17
  readonly items: readonly WorkspaceView[];
12
18
  readonly archivedSessionIds: readonly string[];
13
19
  readonly pinnedSessionIds: readonly string[];
14
20
  }
21
+ /**
22
+ * 会话一行的来源(标题、空会话、在跑与否、被谁留住);retainedBy 按视图名记留住它的份数,mainView 大于 0 即正被主视图占着。
23
+ */
15
24
  export interface SessionSummary {
16
25
  readonly id: string;
17
26
  readonly displayTitle: string;
@@ -21,9 +30,15 @@ export interface SessionSummary {
21
30
  readonly origin?: string;
22
31
  readonly retainedBy: Readonly<Partial<Record<string, number>>>;
23
32
  }
33
+ /**
34
+ * 会话投影里的一条子代理目录项;外壳只认 id,其余字段随 dsh 变。
35
+ */
24
36
  export interface SubagentCatalogEntry {
25
37
  readonly id: string;
26
38
  }
39
+ /**
40
+ * dsh sessions.list 的快照:按 id 找会话,投影里可能挂着一串子代理目录。
41
+ */
27
42
  export interface SessionsSnapshot {
28
43
  readonly byId: Readonly<Record<string, SessionSummary>>;
29
44
  readonly projectionsBySession: Readonly<Record<string, {
@@ -32,6 +47,9 @@ export interface SessionsSnapshot {
32
47
  };
33
48
  } | undefined>>;
34
49
  }
50
+ /**
51
+ * 一个会话的三个状态位(在跑 / 有未读完成 / 等着用户交互);字段缺省就是这一位不知道。
52
+ */
35
53
  export interface SessionStatus {
36
54
  readonly running?: boolean;
37
55
  readonly completionUnread?: boolean;
@@ -39,22 +57,43 @@ export interface SessionStatus {
39
57
  readonly kind?: string;
40
58
  };
41
59
  }
60
+ /**
61
+ * 会话 id 到状态位的只读表;查不到的 id 就是没有这一条状态。
62
+ */
42
63
  export type SessionStatusSnapshot = ReadonlyMap<string, SessionStatus>;
64
+ /**
65
+ * dsh layout 的面板选择位;activePanelId 为 null 表示用户把面板关了。
66
+ */
43
67
  export interface PanelInfo {
44
68
  readonly activePanelId: string | null;
45
69
  }
70
+ /**
71
+ * 某个插槽上注册着的一项(id、顺序、文案);label 允许是函数,因为文案要跟语言走。
72
+ */
46
73
  export interface PanelEntry {
47
74
  readonly id: string;
48
75
  readonly order: number;
49
76
  readonly label: string | (() => string);
50
77
  }
78
+ /**
79
+ * 选择器 hook 的形状(dsh 那套 useSyncExternalStore):外壳拿它从快照里取一小块并在变更时重取。
80
+ */
51
81
  export type SnapshotSelectorHook<T> = <R>(selector: (state: T) => R) => R;
82
+ /**
83
+ * 渲染 dsh 某个插槽的函数;key 定插槽,fallback 是空槽兜底,only 用来只渲染其中一个注册项。
84
+ */
52
85
  export type RenderSlot = (key: string, owner?: Record<string, unknown>, options?: {
53
86
  fallback?: ReactNode;
54
87
  hookContext?: unknown;
55
88
  only?: string;
56
89
  }) => ReactNode;
90
+ /**
91
+ * 文案函数:给键(可带参数)回一句当前语言的文本;缺键时由 dsh 决定回什么,调用点不兜。
92
+ */
57
93
  export type Translate = (key: string, params?: Record<string, unknown>) => string;
94
+ /**
95
+ * 往 dsh 插槽注册一项要给的参数;priority 与 order 小者靠前,inject 声明这一项要用到的作用域。
96
+ */
58
97
  export interface SlotRegisterOptions {
59
98
  name: string;
60
99
  priority?: number;
@@ -66,6 +105,9 @@ export interface SlotRegisterOptions {
66
105
  children?: Record<string, unknown>;
67
106
  inject?: (scope?: unknown) => Record<string, unknown>;
68
107
  }
108
+ /**
109
+ * dsh 的插槽服务:注册一项、注入作用域、订阅变更,以及按名取已注册项。
110
+ */
69
111
  export interface DshSlots {
70
112
  inject(name: string, callback: () => void | (() => void) | Iterable<() => void>): () => void;
71
113
  register(options: SlotRegisterOptions, component: unknown): () => void;
@@ -76,10 +118,16 @@ export interface DshSlots {
76
118
  specDynamic?(name: string): unknown;
77
119
  onMutate?(callback: (name: string) => void): () => void;
78
120
  }
121
+ /**
122
+ * dsh 的语言服务:按命名空间注册字典,再取回那个命名空间的文案函数。
123
+ */
79
124
  export interface DshLocale {
80
125
  register(namespace: string, dictionaries: Record<string, Record<string, string>>): () => void;
81
126
  bind(namespace: string): Translate;
82
127
  }
128
+ /**
129
+ * dsh 的布局服务:选面板、开关左栏、开合右栏;右栏宽度经可选的 panels 写。
130
+ */
83
131
  export interface DshLayout {
84
132
  selectPanel(panelId: string | null): void;
85
133
  toggleSidebar(): void;
@@ -87,25 +135,43 @@ export interface DshLayout {
87
135
  closeRightbar(): void;
88
136
  readonly panels?: DshLayoutPanels;
89
137
  }
138
+ /**
139
+ * layout 上那个可选的右栏宽度写口;dsh 没给这一位时右栏宽度就只是内存态。
140
+ */
90
141
  export interface DshLayoutPanels {
91
142
  setRightbar?(px: number): void;
92
143
  }
144
+ /**
145
+ * 快捷键目录的口子;外壳只把它透出去,形状与内容随 dsh。
146
+ */
93
147
  export interface DshShortcutCatalog {
94
148
  readonly catalog: unknown;
95
149
  }
150
+ /**
151
+ * 起一个新会话时能带的选项;目前只有 agent 预设这一项。
152
+ */
96
153
  export interface DshSessionStartOptions {
97
154
  readonly agentPreset?: string;
98
155
  }
156
+ /**
157
+ * dsh 的工作区与会话动作:开工作区、开会话、起会话、挑目录。
158
+ */
99
159
  export interface DshUiWorkspace {
100
160
  openWorkspace(workspaceId: string): Promise<unknown>;
101
161
  openSession(sessionId: string): void;
102
162
  startSession(workspaceId: string, options?: DshSessionStartOptions): void;
103
163
  pickDirectory(): Promise<string | null>;
104
164
  }
165
+ /**
166
+ * 工作区写口回的那点事实(新 id 或新标题);字段都可能缺,缺了按「没写回」算。
167
+ */
105
168
  export interface DshWorkspaceWritten {
106
169
  readonly workspaceId?: string;
107
170
  readonly title?: string;
108
171
  }
172
+ /**
173
+ * dsh 的工作区服务:list 是可订阅快照,create 与 rename 是写口。
174
+ */
109
175
  export interface DshWorkspaces {
110
176
  readonly list: DshObservable<WorkspaceSnapshot>;
111
177
  create(request: {
@@ -113,6 +179,9 @@ export interface DshWorkspaces {
113
179
  }): Promise<DshWorkspaceWritten | undefined>;
114
180
  rename(workspaceId: string, title: string): Promise<DshWorkspaceWritten>;
115
181
  }
182
+ /**
183
+ * 往输入框插一条引用时要给的载荷:来源、引用文本、显示文案与剪贴板文本。
184
+ */
116
185
  export interface DshReferenceInsert {
117
186
  readonly source: string;
118
187
  readonly ref: string;
@@ -120,11 +189,17 @@ export interface DshReferenceInsert {
120
189
  readonly appearance?: 'session' | 'file' | 'folder';
121
190
  readonly clipboardText: string;
122
191
  }
192
+ /**
193
+ * 输入框里一段 token 的区间;draftRev 用来确认还是同一版草稿,插入引用时用它定位。
194
+ */
123
195
  export interface DshTokenSpan {
124
196
  readonly start: number;
125
197
  readonly end: number;
126
198
  readonly draftRev: number;
127
199
  }
200
+ /**
201
+ * 某一个会话的输入框句柄;外壳借它插引用与弹提示,state 用来核对草稿版本。
202
+ */
128
203
  export interface DshSessionInput {
129
204
  caretSpan?: () => {
130
205
  start: number;
@@ -138,6 +213,9 @@ export interface DshSessionInput {
138
213
  insertReference(ref: DshReferenceInsert, span: DshTokenSpan): boolean;
139
214
  notify(level: 'info' | 'error', text: string): void;
140
215
  }
216
+ /**
217
+ * 注册 @ 触发源的口子:候选由外壳现取,选中后的动作也归外壳,dsh 只负责触发。
218
+ */
141
219
  export interface DshInputTriggers {
142
220
  registerSource(source: {
143
221
  readonly trigger: '@';
@@ -153,11 +231,17 @@ export interface DshInputTriggers {
153
231
  };
154
232
  }): () => void;
155
233
  }
234
+ /**
235
+ * dsh 的对话服务;外壳只用它按会话取输入框句柄。
236
+ */
156
237
  export interface DshConversationService {
157
238
  readonly input: {
158
239
  for(actx: unknown): DshSessionInput;
159
240
  };
160
241
  }
242
+ /**
243
+ * 浏览器侧的会话服务:快照加按 id 取作用域;create 是可选写口,不是每个 dsh 版本都有。
244
+ */
161
245
  export interface DshSessionsService {
162
246
  readonly list: {
163
247
  getSnapshot(): SessionsSnapshot;
@@ -170,10 +254,16 @@ export interface DshSessionsService {
170
254
  readonly agentPreset?: string;
171
255
  }): Promise<unknown>;
172
256
  }
257
+ /**
258
+ * dsh 侧最小的可订阅值:取当前快照加订阅变更,外壳用它接进 React。
259
+ */
173
260
  export interface DshObservable<T> {
174
261
  getSnapshot(): T;
175
262
  subscribe(listener: () => void): () => void;
176
263
  }
264
+ /**
265
+ * dsh 的右栏服务:mounted 是在场与否的可订阅值,展开与开资源另走方法。
266
+ */
177
267
  export interface DshSidebarRight {
178
268
  readonly mounted: DshObservable<string | undefined>;
179
269
  isExpanded(): boolean;
@@ -181,6 +271,9 @@ export interface DshSidebarRight {
181
271
  openResource(address: string, options?: unknown): void;
182
272
  openTab(kind: string, options?: unknown): void;
183
273
  }
274
+ /**
275
+ * remote.sessions 写口:在宿主侧建会话并回会话 id。
276
+ */
184
277
  export interface DshSessionsRemote {
185
278
  create(request: {
186
279
  readonly workspaceId?: string;
@@ -190,9 +283,15 @@ export interface DshSessionsRemote {
190
283
  readonly sessionId: string;
191
284
  }>;
192
285
  }
286
+ /**
287
+ * dsh 客户端的远端写口集合;目前只有会话一家。
288
+ */
193
289
  export interface DshClientRemote {
194
290
  readonly sessions: DshSessionsRemote;
195
291
  }
292
+ /**
293
+ * 客户端插件拿到的上下文:所有服务从它取,effect 注册的清理随插件卸载跑。
294
+ */
196
295
  export interface DshClientContext {
197
296
  get<T = unknown>(name: string): T | undefined;
198
297
  provide(name: string, value: unknown): void;
package/dist/api/dsh.d.ts CHANGED
@@ -1,12 +1,21 @@
1
+ /**
2
+ * 宿主侧的日志口;info 与 warn 都可能没有,调用前要判存在。
3
+ */
1
4
  export interface DshLogger {
2
5
  info?(message: string): void;
3
6
  warn?(message: string): void;
4
7
  }
8
+ /**
9
+ * 宿主 HTTP 路由拿到的请求:方法与 URL,请求体是异步可迭代的字节流。
10
+ */
5
11
  export interface DshRequest {
6
12
  readonly method?: string;
7
13
  readonly url?: string;
8
14
  [Symbol.asyncIterator]?(): AsyncIterator<Uint8Array>;
9
15
  }
16
+ /**
17
+ * 宿主 HTTP 路由要写的响应:statusCode、setHeader 与 end 必备,流式那几个方法可选。
18
+ */
10
19
  export interface DshResponse {
11
20
  statusCode: number;
12
21
  setHeader(name: string, value: string): void;
@@ -15,27 +24,45 @@ export interface DshResponse {
15
24
  write?(chunk: string): void;
16
25
  on?(event: 'close', listener: () => void): void;
17
26
  }
27
+ /**
28
+ * 一条挂到 dsh web 服务器上的路由;kind 说明 path 是前缀还是全等匹配,handler 自己写响应。
29
+ */
18
30
  export interface DshWebRoute {
19
31
  readonly kind: 'prefix' | 'exact';
20
32
  readonly path: string;
21
33
  readonly handler: (req: DshRequest, res: DshResponse) => void | Promise<void>;
22
34
  }
35
+ /**
36
+ * 宿主插件能看到的 profile 现场;dir 缺省表示 dsh 没给这个信息。
37
+ */
23
38
  export interface DshProfileContext {
24
39
  readonly dir?: string;
25
40
  }
41
+ /**
42
+ * 工具声明的静态半(名字加其余关键字);外壳只按 name 认工具。
43
+ */
26
44
  export interface DshToolSchema {
27
45
  readonly name: string;
28
46
  readonly [key: string]: unknown;
29
47
  }
48
+ /**
49
+ * 系统提示词装配到一半的那份;tools 是可改的工具表,其余字段随 dsh。
50
+ */
30
51
  export interface DshPromptAssembly {
31
52
  readonly tools?: readonly DshToolSchema[] | undefined;
32
53
  readonly [key: string]: unknown;
33
54
  }
55
+ /**
56
+ * 装配提示词时给判定方的现场(哪个 agent、哪个作用域);两者都可能缺。
57
+ */
34
58
  export interface DshAssemblyContext {
35
59
  readonly agent?: unknown;
36
60
  readonly scope?: unknown;
37
61
  readonly [key: string]: unknown;
38
62
  }
63
+ /**
64
+ * 宿主插件上下文:on 订阅 dsh 的钩子(提示词装配、工具执行前后、agent 生命周期),webServer 挂路由。
65
+ */
39
66
  export interface DshHostContext {
40
67
  on?: {
41
68
  (event: 'system-prompt/assemble', listener: (assembly: DshPromptAssembly, context: DshAssemblyContext, next: () => Promise<DshPromptAssembly>) => Promise<DshPromptAssembly>): (() => void) | undefined;
@@ -97,6 +124,9 @@ export interface DshHostContext {
97
124
  register(route: DshWebRoute): () => void;
98
125
  };
99
126
  }
127
+ /**
128
+ * 一次 shell 执行的结果口:result() 给退出码、超时与中断标志,以及截断过的 stdout / stderr。
129
+ */
100
130
  export interface DshShellExecution {
101
131
  result(): Promise<{
102
132
  exitCode: number | null;
@@ -112,6 +142,9 @@ export interface DshShellExecution {
112
142
  };
113
143
  }>;
114
144
  }
145
+ /**
146
+ * dsh 的 shell 服务:先 resolve 出执行规格,再把它原样喂给 execute。
147
+ */
115
148
  export interface DshShell {
116
149
  resolve(request: {
117
150
  command: string;
@@ -123,22 +156,35 @@ export interface DshShell {
123
156
  }): unknown;
124
157
  execute(spec: unknown): Promise<DshShellExecution>;
125
158
  }
159
+ /** 一条工作区记录:id、磁盘路径与显示名(登记处按路径认领 / 新建时认的就是它)。 */
160
+ export interface DshWorkspaceRecord {
161
+ readonly id: string;
162
+ readonly path: string;
163
+ readonly title: string;
164
+ }
165
+ /**
166
+ * 宿主侧的工作区登记处:按 id 查、按路径认领、按路径新建。
167
+ */
126
168
  export interface DshWorkspaceRegistry {
127
169
  get(id: string): {
128
170
  id: string;
129
171
  path?: string;
130
172
  title?: string;
131
173
  } | undefined;
132
- resolveByPath(path: string): Promise<{
133
- readonly id: unknown;
134
- } | undefined>;
174
+ resolveByPath(path: string): Promise<DshWorkspaceRecord | undefined>;
135
175
  create(path: string, title?: string): Promise<{
136
176
  id?: string;
137
177
  path?: string;
138
178
  title?: string;
139
179
  } | undefined>;
140
180
  }
181
+ /**
182
+ * 把相对路径拼成 dsh home 下的绝对路径(服务名 dshHomePath);外壳存自己的状态用它,不自己拼 home。
183
+ */
141
184
  export type DshHomePath = (relative: string) => string;
185
+ /**
186
+ * 要注册进 dsh 的一把工具:名字、描述、参数表、输出渲染与执行体。
187
+ */
142
188
  export interface DshToolDefinition {
143
189
  name: string;
144
190
  description: string;
@@ -149,6 +195,9 @@ export interface DshToolDefinition {
149
195
  };
150
196
  execute(args: unknown, exec: DshToolRunContext): Promise<unknown>;
151
197
  }
198
+ /**
199
+ * 工具执行时给的那点现场(会话 id 与 cwd);层级都可能缺,缺了就当不知道。
200
+ */
152
201
  export interface DshToolRunContext {
153
202
  readonly agent?: {
154
203
  readonly session?: {
@@ -159,6 +208,9 @@ export interface DshToolRunContext {
159
208
  } | undefined;
160
209
  } | undefined;
161
210
  }
211
+ /**
212
+ * dsh 的工具表;register 回的清理函数负责在插件卸载时摘掉这条工具。
213
+ */
162
214
  export interface DshToolRegistry {
163
215
  register(definition: DshToolDefinition): () => void;
164
216
  }
@@ -1,18 +1,45 @@
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
  }
9
+ /**
10
+ * 范围查法的后缀:cmdb/* 这类名字表示「这个前缀下的一族」,不是一条事实。
11
+ */
6
12
  export declare const FACT_SCOPE_SUFFIX = "*";
13
+ /**
14
+ * 由单元 id 拼出它那一族事实的范围名。
15
+ * @param unit 单元 id,不带后缀。
16
+ * @returns <unit>* —— 永远是范围名,不是某一条事实。
17
+ */
7
18
  export declare function unitFactScope(unit: string): string;
19
+ /**
20
+ * 判一个名字是不是范围查法,不是问这条事实存不存在。
21
+ * @param name 事实名或范围名。
22
+ * @returns 单字符 * 不算范围;只有「至少一个字符加 *」才算。
23
+ */
8
24
  export declare function isFactScope(name: string): boolean;
25
+ /**
26
+ * 取范围名对应的前缀,普通事实名原样返回。
27
+ * @param name 事实名或范围名。
28
+ * @returns 去掉末尾 * 的前缀;本来不是范围就给原值。
29
+ */
9
30
  export declare function scopePrefixOf(name: string): string;
31
+ /**
32
+ * 事实的来路:start 建连并按帧回调,cursor 报已收到的宿主 rev(断线重连时交给宿主)。
33
+ */
10
34
  export interface FactTransport {
11
35
  start(handlers: {
12
36
  readonly onFrame: (frame: FactFrame) => void;
13
37
  readonly cursor: () => number;
14
38
  }): () => void;
15
39
  }
40
+ /**
41
+ * 浏览器侧的事实通道:订阅、读版本、手动刷新,帧到了由它分发给订阅者。
42
+ */
16
43
  export interface FactChannel {
17
44
  subscribe(fact: string, listener: () => void): () => void;
18
45
  revisionOf(fact: string): number;
@@ -20,8 +47,23 @@ export interface FactChannel {
20
47
  applyFrame(frame: FactFrame): void;
21
48
  subscriberCount(): number;
22
49
  }
50
+ /**
51
+ * 造一条事实通道:第一次订阅时才连传输层,最后一个订阅者走掉就断开。
52
+ * @param options 传输层,用来连宿主。
53
+ * @returns 通道句柄;没记录过的事实版本给 0,refresh() 不带事实名时刷新全部并逐个通知。
54
+ */
23
55
  export declare function createFactChannel(options: {
24
56
  readonly transport: FactTransport;
25
57
  }): FactChannel;
58
+ /**
59
+ * 把传输层收到的原始数据读成一帧;坏数据当没收到。
60
+ * @param data 帧的原始数据,期望是 JSON 字符串。
61
+ * @returns 合法帧;不是字符串、JSON 坏了、或 rev 不是数字都给 null。
62
+ */
26
63
  export declare function parseFactFrame(data: unknown): FactFrame | null;
64
+ /**
65
+ * 读口路由到事实名的映射,当前一对一。
66
+ * @param route 读口路由。
67
+ * @returns 该路由对应的事实名(就是路由本身)。
68
+ */
27
69
  export declare function factOfRoute(route: string): string;