@dsh-workbench/shared 0.3.4 → 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.
Files changed (180) 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 +36 -0
  13. package/dist/api/long-task.js +27 -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.d.ts +20 -0
  49. package/dist/components/FormRows.js +14 -0
  50. package/dist/components/FormTypes.d.ts +59 -0
  51. package/dist/components/FormTypes.js +1 -0
  52. package/dist/components/Link.d.ts +12 -0
  53. package/dist/components/Link.js +9 -0
  54. package/dist/components/LongTaskRow.d.ts +19 -0
  55. package/dist/components/LongTaskRow.js +13 -0
  56. package/dist/components/Note.d.ts +11 -0
  57. package/dist/components/Note.js +8 -0
  58. package/dist/components/ResourceStates.d.ts +25 -0
  59. package/dist/components/ResourceStates.js +22 -0
  60. package/dist/components/Rows.d.ts +17 -0
  61. package/dist/components/Rows.js +11 -0
  62. package/dist/components/SaveBar.d.ts +12 -0
  63. package/dist/components/SaveBar.js +9 -0
  64. package/dist/components/SelectField.d.ts +26 -0
  65. package/dist/components/SelectField.js +22 -0
  66. package/dist/components/SelectFieldNodes.d.ts +24 -0
  67. package/dist/components/SelectFieldNodes.js +24 -0
  68. package/dist/components/SettingsSection.d.ts +11 -0
  69. package/dist/components/SettingsSection.js +8 -0
  70. package/dist/components/Spinner.d.ts +9 -0
  71. package/dist/components/Spinner.js +6 -0
  72. package/dist/components/Stack.d.ts +8 -0
  73. package/dist/components/Stack.js +5 -0
  74. package/dist/components/StateBlock.d.ts +13 -0
  75. package/dist/components/StateBlock.js +10 -0
  76. package/dist/components/TextField.d.ts +8 -0
  77. package/dist/components/TextField.js +5 -0
  78. package/dist/components/board-module.d.ts +30 -0
  79. package/dist/components/icons.d.ts +38 -0
  80. package/dist/components/icons.js +35 -0
  81. package/dist/config/constants.d.ts +42 -0
  82. package/dist/config/constants.js +42 -0
  83. package/dist/config/storage.d.ts +4 -0
  84. package/dist/config/storage.js +4 -0
  85. package/dist/host/unit-face.d.ts +5 -1
  86. package/dist/i18n/en.d.ts +1 -0
  87. package/dist/i18n/en.js +8 -8
  88. package/dist/i18n/index.d.ts +11 -9
  89. package/dist/i18n/index.js +1 -0
  90. package/dist/i18n/merge.d.ts +5 -0
  91. package/dist/i18n/merge.js +2 -0
  92. package/dist/i18n/zh.d.ts +9 -8
  93. package/dist/i18n/zh.js +8 -8
  94. package/dist/index.d.ts +6 -2
  95. package/dist/index.js +6 -2
  96. package/dist/lib/blocker-action.d.ts +22 -0
  97. package/dist/lib/blocker-action.js +13 -0
  98. package/dist/lib/board-fact.d.ts +27 -0
  99. package/dist/lib/board-fact.js +18 -0
  100. package/dist/lib/busy.d.ts +10 -0
  101. package/dist/lib/busy.js +7 -0
  102. package/dist/lib/diy-debug.d.ts +42 -2
  103. package/dist/lib/diy-debug.js +19 -1
  104. package/dist/lib/diy-record.d.ts +41 -0
  105. package/dist/lib/diy-record.js +17 -0
  106. package/dist/lib/form-problem.d.ts +10 -0
  107. package/dist/lib/form-problem.js +10 -0
  108. package/dist/lib/panel-state.d.ts +60 -0
  109. package/dist/lib/panel-state.js +30 -0
  110. package/dist/lib/react.d.ts +39 -0
  111. package/dist/lib/react.js +36 -0
  112. package/dist/lib/text.d.ts +22 -0
  113. package/dist/lib/text.js +22 -0
  114. package/dist/lib/ui.d.ts +50 -0
  115. package/dist/lib/ui.js +41 -0
  116. package/package.json +1 -1
  117. package/src/api/blocker-table.ts +13 -0
  118. package/src/api/blocker.ts +6 -0
  119. package/src/api/context-ref.ts +31 -0
  120. package/src/api/dsh-client.ts +99 -0
  121. package/src/api/dsh.ts +56 -1
  122. package/src/api/facts.ts +42 -0
  123. package/src/api/host-write.ts +18 -0
  124. package/src/api/long-task.ts +36 -0
  125. package/src/api/unit-board.ts +25 -0
  126. package/src/api/unit-declaration.ts +36 -0
  127. package/src/api/unit.ts +32 -0
  128. package/src/api/workbench-client.ts +25 -0
  129. package/src/api/workbench-contract.ts +12 -0
  130. package/src/components/Activity.tsx +33 -0
  131. package/src/components/ApprovalDetail.tsx +12 -0
  132. package/src/components/ApprovalPlan.tsx +14 -0
  133. package/src/components/Card.tsx +13 -0
  134. package/src/components/CardAnchor.tsx +14 -0
  135. package/src/components/CardBoundary.tsx +20 -0
  136. package/src/components/CardHead.tsx +13 -0
  137. package/src/components/ChoiceGroup.tsx +24 -0
  138. package/src/components/Field.tsx +10 -0
  139. package/src/components/Form.css +6 -0
  140. package/src/components/Form.test.tsx +475 -0
  141. package/src/components/Form.tsx +78 -0
  142. package/src/components/FormActions.tsx +14 -0
  143. package/src/components/FormNodes.tsx +193 -0
  144. package/src/components/FormRows.tsx +20 -0
  145. package/src/components/FormTypes.ts +65 -0
  146. package/src/components/FormWiring.test.tsx +88 -0
  147. package/src/components/Link.tsx +12 -0
  148. package/src/components/LongTaskRow.tsx +19 -0
  149. package/src/components/Note.tsx +11 -0
  150. package/src/components/ResourceStates.tsx +25 -0
  151. package/src/components/Rows.tsx +17 -0
  152. package/src/components/SaveBar.tsx +12 -0
  153. package/src/components/SelectField.tsx +26 -0
  154. package/src/components/SelectFieldNodes.tsx +24 -0
  155. package/src/components/SettingsSection.tsx +11 -0
  156. package/src/components/Spinner.tsx +9 -0
  157. package/src/components/Stack.tsx +8 -0
  158. package/src/components/StateBlock.tsx +13 -0
  159. package/src/components/TextField.tsx +8 -0
  160. package/src/components/board-module.ts +30 -0
  161. package/src/components/icons.tsx +38 -0
  162. package/src/config/constants.ts +43 -0
  163. package/src/config/storage.ts +4 -0
  164. package/src/host/unit-face.ts +6 -1
  165. package/src/i18n/en.ts +8 -8
  166. package/src/i18n/index.ts +3 -0
  167. package/src/i18n/merge.ts +5 -0
  168. package/src/i18n/zh.ts +9 -8
  169. package/src/index.ts +6 -2
  170. package/src/lib/blocker-action.ts +22 -0
  171. package/src/lib/board-fact.ts +27 -0
  172. package/src/lib/busy.ts +10 -0
  173. package/src/lib/diy-debug.test.ts +2 -1
  174. package/src/lib/diy-debug.ts +44 -3
  175. package/src/lib/diy-record.ts +41 -0
  176. package/src/lib/form-problem.ts +10 -0
  177. package/src/lib/panel-state.ts +60 -0
  178. package/src/lib/react.ts +39 -0
  179. package/src/lib/text.ts +22 -0
  180. package/src/lib/ui.ts +50 -0
package/dist/api/facts.js CHANGED
@@ -1,13 +1,36 @@
1
+ /**
2
+ * 范围查法的后缀:cmdb/* 这类名字表示「这个前缀下的一族」,不是一条事实。
3
+ */
1
4
  export const FACT_SCOPE_SUFFIX = '*';
5
+ /**
6
+ * 由单元 id 拼出它那一族事实的范围名。
7
+ * @param unit 单元 id,不带后缀。
8
+ * @returns <unit>* —— 永远是范围名,不是某一条事实。
9
+ */
2
10
  export function unitFactScope(unit) {
3
11
  return `${unit}${FACT_SCOPE_SUFFIX}`;
4
12
  }
13
+ /**
14
+ * 判一个名字是不是范围查法,不是问这条事实存不存在。
15
+ * @param name 事实名或范围名。
16
+ * @returns 单字符 * 不算范围;只有「至少一个字符加 *」才算。
17
+ */
5
18
  export function isFactScope(name) {
6
19
  return name.length > 1 && name.endsWith(FACT_SCOPE_SUFFIX);
7
20
  }
21
+ /**
22
+ * 取范围名对应的前缀,普通事实名原样返回。
23
+ * @param name 事实名或范围名。
24
+ * @returns 去掉末尾 * 的前缀;本来不是范围就给原值。
25
+ */
8
26
  export function scopePrefixOf(name) {
9
27
  return isFactScope(name) ? name.slice(0, -FACT_SCOPE_SUFFIX.length) : name;
10
28
  }
29
+ /**
30
+ * 造一条事实通道:第一次订阅时才连传输层,最后一个订阅者走掉就断开。
31
+ * @param options 传输层,用来连宿主。
32
+ * @returns 通道句柄;没记录过的事实版本给 0,refresh() 不带事实名时刷新全部并逐个通知。
33
+ */
11
34
  export function createFactChannel(options) {
12
35
  const entries = new Map();
13
36
  let epoch = null;
@@ -124,6 +147,11 @@ export function createFactChannel(options) {
124
147
  };
125
148
  return channel;
126
149
  }
150
+ /**
151
+ * 把传输层收到的原始数据读成一帧;坏数据当没收到。
152
+ * @param data 帧的原始数据,期望是 JSON 字符串。
153
+ * @returns 合法帧;不是字符串、JSON 坏了、或 rev 不是数字都给 null。
154
+ */
127
155
  export function parseFactFrame(data) {
128
156
  if (typeof data !== 'string')
129
157
  return null;
@@ -141,6 +169,11 @@ export function parseFactFrame(data) {
141
169
  return null;
142
170
  }
143
171
  }
172
+ /**
173
+ * 读口路由到事实名的映射,当前一对一。
174
+ * @param route 读口路由。
175
+ * @returns 该路由对应的事实名(就是路由本身)。
176
+ */
144
177
  export function factOfRoute(route) {
145
178
  return route;
146
179
  }
@@ -1,6 +1,18 @@
1
1
  import type { ApiResponse } from './workbench-client.js';
2
+ /**
3
+ * 宿主写口的五条通道(偏好、动作、供给、工坊调试、工坊录制),是写路由的第一段。
4
+ */
2
5
  export type WriteChannel = 'prefs' | 'actions' | 'provision' | 'diy-debug' | 'diy-record';
6
+ /**
7
+ * 由通道与资源拼出写路由。
8
+ * @param channel 写通道。
9
+ * @param resource 该通道下的资源名。
10
+ * @returns 路由字符串;provision 只有一段,其余是 channel/resource。
11
+ */
3
12
  export declare function writeRoute(channel: WriteChannel, resource: string): string;
13
+ /**
14
+ * 写通道统一的结果:成了带值,没成带一句能给人看的话(可选明细与帮助链接)。
15
+ */
4
16
  export type WriteOutcome<T> = {
5
17
  readonly ok: true;
6
18
  readonly value: T;
@@ -10,4 +22,10 @@ export type WriteOutcome<T> = {
10
22
  readonly detail?: string;
11
23
  readonly helpUrl?: string;
12
24
  };
25
+ /**
26
+ * 把写通道的响应翻成 WriteOutcome。
27
+ * @param response 写口回的响应;null 表示请求本身没成(网络断了,宿主没答)。
28
+ * @param networkText 拿不到任何服务端文案时兜底的那句。
29
+ * @returns 失败时 message 优先用服务端自己的话,没有才用响应正文或 networkText。
30
+ */
13
31
  export declare function writeOutcomeOf<T>(response: ApiResponse<T> | null, networkText: string): WriteOutcome<T>;
@@ -1,8 +1,20 @@
1
+ /**
2
+ * 由通道与资源拼出写路由。
3
+ * @param channel 写通道。
4
+ * @param resource 该通道下的资源名。
5
+ * @returns 路由字符串;provision 只有一段,其余是 channel/resource。
6
+ */
1
7
  export function writeRoute(channel, resource) {
2
8
  if (channel === 'provision')
3
9
  return 'provision';
4
10
  return `${channel}/${resource}`;
5
11
  }
12
+ /**
13
+ * 把写通道的响应翻成 WriteOutcome。
14
+ * @param response 写口回的响应;null 表示请求本身没成(网络断了,宿主没答)。
15
+ * @param networkText 拿不到任何服务端文案时兜底的那句。
16
+ * @returns 失败时 message 优先用服务端自己的话,没有才用响应正文或 networkText。
17
+ */
6
18
  export function writeOutcomeOf(response, networkText) {
7
19
  if (response === null)
8
20
  return { ok: false, message: networkText };
@@ -1,18 +1,54 @@
1
+ /**
2
+ * 一条长任务的四种态;needs-login 与 running 一样算还没结束。
3
+ */
1
4
  export type LongTaskStatus = 'running' | 'needs-login' | 'ok' | 'failed';
5
+ /**
6
+ * 长任务步骤流里的一行:kind 定样式,登录那一步带 loginUrl 给用户去点。
7
+ */
2
8
  export interface LongTaskStep {
3
9
  readonly kind: 'start' | 'succeed' | 'fail' | 'info' | 'warn';
4
10
  readonly text: string;
5
11
  readonly loginUrl?: string | undefined;
6
12
  }
13
+ /**
14
+ * 单元的长任务读口路由。
15
+ * @param unit 单元 id。
16
+ * @returns <unit>/runs。
17
+ */
7
18
  export declare function runsRouteOf(unit: string): string;
19
+ /**
20
+ * 长任务读口回的载荷:一串 run,形状由模块自己定,外壳只透传。
21
+ */
8
22
  export interface LongTasksPayload {
9
23
  readonly runs: readonly Readonly<Record<string, unknown>>[];
10
24
  }
25
+ /**
26
+ * 有长任务在跑时的轮询间隔(毫秒)。
27
+ */
11
28
  export declare const LONG_TASK_POLL_MS = 1500;
29
+ /**
30
+ * 没有长任务时的轮询间隔(毫秒),比在跑那一档大一个量级。
31
+ */
12
32
  export declare const LONG_TASK_IDLE_MS = 10000;
33
+ /**
34
+ * 算这次该隔多久再问一次长任务。
35
+ * @param live 是否有在跑的长任务。
36
+ * @param override 调用点指定的间隔;给了就用它,不再看 live。
37
+ * @returns 毫秒:有活 1500,没活 10000。
38
+ */
13
39
  export declare function longTaskPollMs(live: boolean, override?: number | undefined): number;
40
+ /**
41
+ * 从读口状态里取 run 列表。
42
+ * @param state 读口状态;value 还没到就按空算。
43
+ * @returns 一串 run(形状由调用点自己判),没有就给空数组。
44
+ */
14
45
  export declare function longTaskRunsOf<T>(state: {
15
46
  readonly phase?: string | undefined;
16
47
  readonly value?: LongTasksPayload | undefined;
17
48
  }): readonly T[];
49
+ /**
50
+ * 把长任务态折成状态点的那一档。
51
+ * @param status 长任务的四种态。
52
+ * @returns ongoing / done / error / idle;needs-login 也算进行中。
53
+ */
18
54
  export declare function longTaskDot(status: LongTaskStatus): 'ongoing' | 'done' | 'error' | 'idle';
@@ -1,16 +1,43 @@
1
+ /**
2
+ * 单元的长任务读口路由。
3
+ * @param unit 单元 id。
4
+ * @returns <unit>/runs。
5
+ */
1
6
  export function runsRouteOf(unit) {
2
7
  return `${unit}/runs`;
3
8
  }
9
+ /**
10
+ * 有长任务在跑时的轮询间隔(毫秒)。
11
+ */
4
12
  export const LONG_TASK_POLL_MS = 1500;
13
+ /**
14
+ * 没有长任务时的轮询间隔(毫秒),比在跑那一档大一个量级。
15
+ */
5
16
  export const LONG_TASK_IDLE_MS = 10_000;
17
+ /**
18
+ * 算这次该隔多久再问一次长任务。
19
+ * @param live 是否有在跑的长任务。
20
+ * @param override 调用点指定的间隔;给了就用它,不再看 live。
21
+ * @returns 毫秒:有活 1500,没活 10000。
22
+ */
6
23
  export function longTaskPollMs(live, override) {
7
24
  if (override !== undefined)
8
25
  return override;
9
26
  return live ? LONG_TASK_POLL_MS : LONG_TASK_IDLE_MS;
10
27
  }
28
+ /**
29
+ * 从读口状态里取 run 列表。
30
+ * @param state 读口状态;value 还没到就按空算。
31
+ * @returns 一串 run(形状由调用点自己判),没有就给空数组。
32
+ */
11
33
  export function longTaskRunsOf(state) {
12
34
  return (state.value?.runs ?? []);
13
35
  }
36
+ /**
37
+ * 把长任务态折成状态点的那一档。
38
+ * @param status 长任务的四种态。
39
+ * @returns ongoing / done / error / idle;needs-login 也算进行中。
40
+ */
14
41
  export function longTaskDot(status) {
15
42
  if (status === 'ok')
16
43
  return 'done';
@@ -1,14 +1,39 @@
1
1
  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
+ /**
5
+ * 卡片闸的两种档:capability 按环境读数判,none 无条件放行。
6
+ */
4
7
  export type GateMode = 'capability' | 'none';
8
+ /**
9
+ * 一次放行判定的结果;gated 为假时卡片不画。
10
+ */
5
11
  export interface UnitGate {
6
12
  readonly gated: boolean;
7
13
  }
14
+ /**
15
+ * 判这张卡现在能不能画。
16
+ * @param capability 环境读数;还没读到给 null。
17
+ * @param mode 闸档。
18
+ * @returns mode 为 none 或读数还没到都放行(先放行让它读);读到明确不通过(ok 与 unchecked 之外)才拦。
19
+ */
8
20
  export declare function gateOf(capability: CapabilityPayload | null, mode: GateMode): UnitGate;
21
+ /**
22
+ * 一个单元攒下的卡住态:blocker 顶掉卡片,notice 只提示;组装方产出,卡片消费。
23
+ */
9
24
  export interface UnitBlockers {
10
25
  readonly blocker?: ModuleBlocker;
11
26
  readonly notice?: ModuleBlocker;
12
27
  }
28
+ /**
29
+ * 把候选卡住态分档,每档只留第一个。
30
+ * @param candidates 候选(可能含 undefined),按优先级从高到低给。
31
+ * @returns 分出的 blocker 与 notice;已经有 blocker 时不带 notice(挡住就不必再提示)。
32
+ */
13
33
  export declare function splitBlocker(candidates: readonly (ModuleBlocker | undefined)[]): UnitBlockers;
34
+ /**
35
+ * 由读口错误算出「出错搭车强探」的防抖键:同一个键只自动重探一次。
36
+ * @param error 读口错误;undefined 表示这次没有错误。
37
+ * @returns 键字符串;空 code 归一到 unknown。
38
+ */
14
39
  export declare function probeKeyOf(error: ApiError | undefined): string | null;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * 判这张卡现在能不能画。
3
+ * @param capability 环境读数;还没读到给 null。
4
+ * @param mode 闸档。
5
+ * @returns mode 为 none 或读数还没到都放行(先放行让它读);读到明确不通过(ok 与 unchecked 之外)才拦。
6
+ */
1
7
  export function gateOf(capability, mode) {
2
8
  if (mode === 'none')
3
9
  return { gated: true };
@@ -5,6 +11,11 @@ export function gateOf(capability, mode) {
5
11
  return { gated: true };
6
12
  return { gated: capability.status === 'ok' || capability.status === 'unchecked' };
7
13
  }
14
+ /**
15
+ * 把候选卡住态分档,每档只留第一个。
16
+ * @param candidates 候选(可能含 undefined),按优先级从高到低给。
17
+ * @returns 分出的 blocker 与 notice;已经有 blocker 时不带 notice(挡住就不必再提示)。
18
+ */
8
19
  export function splitBlocker(candidates) {
9
20
  let blocker;
10
21
  let notice;
@@ -22,6 +33,11 @@ export function splitBlocker(candidates) {
22
33
  ...(blocker !== undefined || notice === undefined ? {} : { notice }),
23
34
  };
24
35
  }
36
+ /**
37
+ * 由读口错误算出「出错搭车强探」的防抖键:同一个键只自动重探一次。
38
+ * @param error 读口错误;undefined 表示这次没有错误。
39
+ * @returns 键字符串;空 code 归一到 unknown。
40
+ */
25
41
  export function probeKeyOf(error) {
26
42
  if (error === undefined)
27
43
  return null;
@@ -1,15 +1,30 @@
1
1
  import type { UnitEnvNeeds, UnitHostNeeds, UnitManifest } from './unit.js';
2
+ /**
3
+ * 声明协议当前版本;模块清单的 dsh.workbench.apiVersion 要写这个整数。
4
+ */
2
5
  export declare const WORKBENCH_API_VERSION = 1;
6
+ /**
7
+ * 外壳愿意认的协议版本;不在表里的模块当场被拒,不猜语义。
8
+ */
3
9
  export declare const SUPPORTED_API_VERSIONS: readonly number[];
10
+ /**
11
+ * 清单里那半张卡片声明:文案键加排序位;卡片默认显不显示不在这里(那是运行期面板配置的事)。
12
+ */
4
13
  export interface UnitCardDeclaration {
5
14
  readonly titleKey: string;
6
15
  readonly order: number;
7
16
  }
17
+ /**
18
+ * 清单里的一条工具声明:进 dsh 工具表的全名、会不会写,以及生成物里的键名。
19
+ */
8
20
  export interface UnitToolDeclaration {
9
21
  readonly name: string;
10
22
  readonly writes: boolean;
11
23
  readonly key?: string;
12
24
  }
25
+ /**
26
+ * 模块清单里 dsh.workbench 那一段的完整形状(协议版本、单元 id、卡片、工具、宿主与环境需要)。
27
+ */
13
28
  export interface UnitDeclaration {
14
29
  readonly apiVersion: number;
15
30
  readonly unit: string;
@@ -18,12 +33,33 @@ export interface UnitDeclaration {
18
33
  readonly host: UnitHostNeeds;
19
34
  readonly env?: UnitEnvNeeds;
20
35
  }
36
+ /**
37
+ * 协议认得的全部键;写了别的键不会被采纳(外壳静默忽略),所以字段名拼错不会有提示。
38
+ */
21
39
  export declare const DECLARATION_KEYS: readonly string[];
40
+ /**
41
+ * 协议要求必写的键;env 不在其中(没有环境需要就不写)。
42
+ */
22
43
  export declare const DECLARATION_REQUIRED_KEYS: readonly string[];
44
+ /**
45
+ * 查清单里 dsh.workbench 那一段的形状,回一串给人看的问题(中文,带字段路径)。
46
+ * @param subject 报错时用的主语,一般是包名。
47
+ * @param raw 清单里那段原始值,可能什么都不是。
48
+ * @returns 空数组表示形状过得去;版本不对就当场返回(后面的字段无从判起)。
49
+ */
23
50
  export declare function declarationProblemsOf(subject: string, raw: unknown): readonly string[];
51
+ /**
52
+ * 读一份清单的结果:要么带着规整过的声明与 manifest,要么只带一串问题。
53
+ */
24
54
  export interface DeclarationRead {
25
55
  readonly declaration?: UnitDeclaration;
26
56
  readonly manifest?: UnitManifest;
27
57
  readonly problems: readonly string[];
28
58
  }
59
+ /**
60
+ * 读一份清单:先查形状,过了再把声明规整成 manifest。
61
+ * @param subject 报错时用的主语。
62
+ * @param raw 清单里 dsh.workbench 那段原始值。
63
+ * @returns 有问题时只有 problems;没问题时 declaration 与 manifest 都给,manifest 里的字符串已 trim。
64
+ */
29
65
  export declare function readDeclaration(subject: string, raw: unknown): DeclarationRead;
@@ -1,5 +1,14 @@
1
+ /**
2
+ * 声明协议当前版本;模块清单的 dsh.workbench.apiVersion 要写这个整数。
3
+ */
1
4
  export const WORKBENCH_API_VERSION = 1;
5
+ /**
6
+ * 外壳愿意认的协议版本;不在表里的模块当场被拒,不猜语义。
7
+ */
2
8
  export const SUPPORTED_API_VERSIONS = [WORKBENCH_API_VERSION];
9
+ /**
10
+ * 协议认得的全部键;写了别的键不会被采纳(外壳静默忽略),所以字段名拼错不会有提示。
11
+ */
3
12
  export const DECLARATION_KEYS = [
4
13
  'apiVersion',
5
14
  'unit',
@@ -8,6 +17,9 @@ export const DECLARATION_KEYS = [
8
17
  'host',
9
18
  'env',
10
19
  ];
20
+ /**
21
+ * 协议要求必写的键;env 不在其中(没有环境需要就不写)。
22
+ */
11
23
  export const DECLARATION_REQUIRED_KEYS = [
12
24
  'apiVersion',
13
25
  'unit',
@@ -36,6 +48,12 @@ function stringArrayProblems(at, value) {
36
48
  return [`${at} 要是一串字符串,现在是 ${JSON.stringify(value)}`];
37
49
  return value.flatMap((item, index) => text(item) === '' ? [`${at}[${index}] 不是非空字符串:${JSON.stringify(item)}`] : []);
38
50
  }
51
+ /**
52
+ * 查清单里 dsh.workbench 那一段的形状,回一串给人看的问题(中文,带字段路径)。
53
+ * @param subject 报错时用的主语,一般是包名。
54
+ * @param raw 清单里那段原始值,可能什么都不是。
55
+ * @returns 空数组表示形状过得去;版本不对就当场返回(后面的字段无从判起)。
56
+ */
39
57
  export function declarationProblemsOf(subject, raw) {
40
58
  if (!isRecord(raw))
41
59
  return [`${subject}: dsh.workbench 不是一个对象 —— ${JSON.stringify(raw)}`];
@@ -158,6 +176,12 @@ export function declarationProblemsOf(subject, raw) {
158
176
  }
159
177
  return problems;
160
178
  }
179
+ /**
180
+ * 读一份清单:先查形状,过了再把声明规整成 manifest。
181
+ * @param subject 报错时用的主语。
182
+ * @param raw 清单里 dsh.workbench 那段原始值。
183
+ * @returns 有问题时只有 problems;没问题时 declaration 与 manifest 都给,manifest 里的字符串已 trim。
184
+ */
161
185
  export function readDeclaration(subject, raw) {
162
186
  const problems = declarationProblemsOf(subject, raw);
163
187
  if (problems.length > 0)
@@ -1,15 +1,27 @@
1
+ /**
2
+ * 一张卡片在清单里的静态声明(文案键加排序位);默认显不显示由运行期面板配置定。
3
+ */
1
4
  export interface UnitCard {
2
5
  readonly titleKey: string;
3
6
  readonly order: number;
4
7
  }
8
+ /**
9
+ * 一条工具在清单里的样子:全名加会不会写;审批按 writes 认领。
10
+ */
5
11
  export interface UnitTool {
6
12
  readonly name: string;
7
13
  readonly writes: boolean;
8
14
  }
15
+ /**
16
+ * 模块要外壳的哪些服务:inject 缺一个就挂不上,optional 缺了照挂。
17
+ */
9
18
  export interface UnitHostNeeds {
10
19
  readonly inject: readonly string[];
11
20
  readonly optional?: readonly string[];
12
21
  }
22
+ /**
23
+ * 一个 opencli 插件的来源三选一(git / 本地 / npm);npm 那支的安装源先看 registryEnv 那个环境变量,没设才用 registryDefault。
24
+ */
13
25
  export type PluginSource = {
14
26
  readonly kind: 'git';
15
27
  readonly url: string;
@@ -22,11 +34,17 @@ export type PluginSource = {
22
34
  readonly registryEnv: string;
23
35
  readonly registryDefault?: string;
24
36
  };
37
+ /**
38
+ * 模块要的一个 opencli 插件:名字、它得提供的命令,以及装它的来源(没写就是不代装)。
39
+ */
25
40
  export interface UnitPluginNeed {
26
41
  readonly name: string;
27
42
  readonly commands?: readonly string[];
28
43
  readonly installSource?: PluginSource;
29
44
  }
45
+ /**
46
+ * 模块要的一个共用库:名字、期望范围与它为什么要这个版本(purpose 会进申报文案)。
47
+ */
30
48
  export interface UnitLibNeed {
31
49
  readonly name: string;
32
50
  readonly version?: string | undefined;
@@ -34,15 +52,24 @@ export interface UnitLibNeed {
34
52
  readonly registryDefault: string;
35
53
  readonly purpose: string;
36
54
  }
55
+ /**
56
+ * 模块的整份环境需要:一条自检命令,加上插件与共用库两张表。
57
+ */
37
58
  export interface UnitEnvNeeds {
38
59
  readonly command?: string;
39
60
  readonly plugins?: readonly UnitPluginNeed[];
40
61
  readonly libs?: readonly UnitLibNeed[];
41
62
  }
63
+ /**
64
+ * 已装插件与源上最新版那一对,用来判该不该提示升级;latest 缺省表示还没查到。
65
+ */
42
66
  export interface PluginRelease {
43
67
  readonly installed: string;
44
68
  readonly latest?: string;
45
69
  }
70
+ /**
71
+ * 装配期用的模块清单:单元 id、卡片、工具与宿主 / 环境需要,比声明少一层协议包装。
72
+ */
46
73
  export interface UnitManifest {
47
74
  readonly id: string;
48
75
  readonly card: UnitCard | null;
@@ -50,4 +77,9 @@ export interface UnitManifest {
50
77
  readonly host: UnitHostNeeds;
51
78
  readonly env?: UnitEnvNeeds;
52
79
  }
80
+ /**
81
+ * 判这个模块要不要往外装东西。
82
+ * @param manifest 模块清单。
83
+ * @returns 插件与共用库两张表都空时给 false。
84
+ */
53
85
  export declare function hasEnvSupply(manifest: UnitManifest): boolean;
package/dist/api/unit.js CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 判这个模块要不要往外装东西。
3
+ * @param manifest 模块清单。
4
+ * @returns 插件与共用库两张表都空时给 false。
5
+ */
1
6
  export function hasEnvSupply(manifest) {
2
7
  return (manifest.env?.plugins ?? []).length > 0 || (manifest.env?.libs ?? []).length > 0;
3
8
  }
@@ -1,3 +1,6 @@
1
+ /**
2
+ * 宿主读口 / 写口回的错误:code 给判据分档,message 给人看,helpUrl 有就去点。
3
+ */
1
4
  export interface ApiError {
2
5
  readonly code: string;
3
6
  readonly message: string;
@@ -5,15 +8,37 @@ export interface ApiError {
5
8
  readonly hint?: string;
6
9
  readonly helpUrl?: string;
7
10
  }
11
+ /**
12
+ * 读口的统一响应:成了把载荷摊平在顶层,没成只有一条 ApiError。
13
+ */
8
14
  export type ApiResponse<T> = ({
9
15
  readonly ok: true;
10
16
  } & T) | {
11
17
  readonly ok: false;
12
18
  readonly error: ApiError;
13
19
  };
20
+ /**
21
+ * GET 的查询参数:值为 undefined 的键直接丢掉,不进 URL。
22
+ */
14
23
  export type Query = Record<string, string | number | boolean | undefined>;
24
+ /**
25
+ * GET 的可选项;目前只有中止信号。
26
+ */
15
27
  export interface ApiGetOptions {
16
28
  readonly signal?: AbortSignal | undefined;
17
29
  }
30
+ /**
31
+ * 打一条宿主读口。
32
+ * @param route 路由,相对 API_PREFIX,不带前导斜杠。
33
+ * @param query 查询参数,undefined 的值不序列化。
34
+ * @param options 中止信号等。
35
+ * @returns HTTP 不是 2xx 时给 ok: false(code 为 http);响应体不是 JSON 会当场抛,调用点要接住。
36
+ */
18
37
  export declare function apiGet<T>(route: string, query?: Query, options?: ApiGetOptions): Promise<ApiResponse<T>>;
38
+ /**
39
+ * 打一条宿主写口。
40
+ * @param route 路由,相对 API_PREFIX,不带前导斜杠。
41
+ * @param body 请求体,按 JSON 序列化。
42
+ * @returns HTTP 不是 2xx 时给 ok: false(code 为 http);响应体不是 JSON 会当场抛。
43
+ */
19
44
  export declare function apiPost<T>(route: string, body: Record<string, unknown>): Promise<ApiResponse<T>>;
@@ -1,4 +1,11 @@
1
1
  import { API_PREFIX } from '../config/constants.js';
2
+ /**
3
+ * 打一条宿主读口。
4
+ * @param route 路由,相对 API_PREFIX,不带前导斜杠。
5
+ * @param query 查询参数,undefined 的值不序列化。
6
+ * @param options 中止信号等。
7
+ * @returns HTTP 不是 2xx 时给 ok: false(code 为 http);响应体不是 JSON 会当场抛,调用点要接住。
8
+ */
2
9
  export async function apiGet(route, query = {}, options = {}) {
3
10
  const { signal } = options;
4
11
  const search = new URLSearchParams();
@@ -20,6 +27,12 @@ export async function apiGet(route, query = {}, options = {}) {
20
27
  }
21
28
  return (await response.json());
22
29
  }
30
+ /**
31
+ * 打一条宿主写口。
32
+ * @param route 路由,相对 API_PREFIX,不带前导斜杠。
33
+ * @param body 请求体,按 JSON 序列化。
34
+ * @returns HTTP 不是 2xx 时给 ok: false(code 为 http);响应体不是 JSON 会当场抛。
35
+ */
23
36
  export async function apiPost(route, body) {
24
37
  const response = await fetch(`${API_PREFIX}/${route}`, {
25
38
  method: 'POST',
@@ -1,5 +1,11 @@
1
1
  import type { PluginRelease } from '../api/unit.js';
2
+ /**
3
+ * 供给动作的那几档(装 / 升 / 卸,模块、共用依赖与插件各一套);写口按它分派。
4
+ */
2
5
  export type ProvisionAction = 'install' | 'update' | 'uninstall' | 'update-dependency' | 'install-bundle' | 'update-bundle' | 'remove-bundle' | 'cancel-install' | 'update-plugin' | 'uninstall-plugin' | 'update-workbench';
6
+ /**
7
+ * 宿主报的一个 opencli 插件此刻的状态:装没装、缺哪些命令、该不该升,以及怎么升。
8
+ */
3
9
  export interface PluginStatePayload {
4
10
  readonly name: string;
5
11
  readonly status: 'ok' | 'outdated' | 'missing';
@@ -8,6 +14,9 @@ export interface PluginStatePayload {
8
14
  readonly command?: string;
9
15
  readonly release?: PluginRelease;
10
16
  }
17
+ /**
18
+ * 宿主对「这个单元现在能不能用」的那份读数:状态、缺的命令与插件、修复动作和供给细节。
19
+ */
11
20
  export interface CapabilityPayload {
12
21
  readonly unit: string;
13
22
  readonly status: 'ok' | 'failed' | 'missing-commands' | 'missing-plugin' | 'unchecked';
@@ -22,6 +31,9 @@ export interface CapabilityPayload {
22
31
  readonly install?: 'ready' | 'not-declared' | 'env-missing' | 'malformed';
23
32
  readonly libs?: readonly LibStatePayload[];
24
33
  }
34
+ /**
35
+ * 宿主报的一个共用库此刻的状态(装没装、版本对不对)与它为什么要这个版本。
36
+ */
25
37
  export interface LibStatePayload {
26
38
  readonly name: string;
27
39
  readonly purpose: string;
@@ -1,17 +1,40 @@
1
1
  import type { ReactNode } from '../lib/react.js';
2
2
  import './Activity.css';
3
+ /**
4
+ * `ActivityBlock` 的契约:块头与块内容。
5
+ */
3
6
  export interface ActivityBlockProps {
4
7
  readonly head?: ReactNode | undefined;
5
8
  readonly children?: ReactNode | undefined;
6
9
  }
10
+ /**
11
+ * "它做过什么"那一块:上面一行块头、下面一列活动行,卡里放时间线就用它。
12
+ * @param props.head - 块头(如"最近 10 次");不给不画那一行。
13
+ * @param props.children - 块内容,通常是一串 `ActivityLine`。
14
+ * @returns 一个 div。
15
+ */
7
16
  export declare function ActivityBlock({ head, children }: ActivityBlockProps): JSX.Element;
17
+ /**
18
+ * `ActivityLine` 的契约:状态点、正文、时间与行尾动作。
19
+ */
8
20
  export interface ActivityLineProps {
9
21
  readonly dot?: ReactNode | undefined;
10
22
  readonly text: ReactNode;
11
23
  readonly at?: ReactNode | undefined;
12
24
  readonly actions?: ReactNode | undefined;
13
25
  }
26
+ /**
27
+ * 一条活动:状态点 + 正文 + 时间,行尾可挂动作;时间一律用它,别自己拼。
28
+ * @param props.dot - 行首那枚状态点;不给就只留正文。
29
+ * @param props.text - 这一条干了什么。
30
+ * @param props.at - 时间那一格(相对时间文本);不给不画。
31
+ * @param props.actions - 行尾动作,通常是一两颗 `ActivityAction`;不给不画。
32
+ * @returns 一行。
33
+ */
14
34
  export declare function ActivityLine({ dot, text, at, actions }: ActivityLineProps): JSX.Element;
35
+ /**
36
+ * `ActivityAction` 的契约:一颗图标钮、一个外链,或一个失败态。
37
+ */
15
38
  export interface ActivityActionProps {
16
39
  readonly label: string;
17
40
  readonly hint?: string | undefined;
@@ -20,4 +43,14 @@ export interface ActivityActionProps {
20
43
  readonly onClick?: (() => void) | undefined;
21
44
  readonly failed?: boolean | undefined;
22
45
  }
46
+ /**
47
+ * 活动行尾那颗动作:给 `href` 就是外链,否则是图标钮并带上 tooltip。
48
+ * @param props.label - 读屏名,也是 `hint` 不给时的 tooltip 文案。
49
+ * @param props.hint - tooltip 上那句更细的说明;不给退化成 `label`。
50
+ * @param props.icon - 那颗图标。
51
+ * @param props.href - 给了就渲染成新窗口外链;与 `onClick` 同时给时以它为准。
52
+ * @param props.onClick - 图标钮的点击回调。
53
+ * @param props.failed - 上一次动作失败了:钮换成危险色(默认 false)。
54
+ * @returns 一个 `<a>` 或一颗 `Button`。
55
+ */
23
56
  export declare function ActivityAction({ label, hint, icon, href, onClick, failed }: ActivityActionProps): JSX.Element;