@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/src/lib/react.ts CHANGED
@@ -2,21 +2,60 @@ import type * as ReactTypes from 'react';
2
2
 
3
3
  const react = require('react') as typeof ReactTypes;
4
4
 
5
+ /**
6
+ * React 的 `createElement` 换个短名字再导出 —— 这套代码用 `h(...)` 写元素。
7
+ */
5
8
  export const h = react.createElement;
6
9
 
10
+ /**
11
+ * React 的 `Fragment` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
12
+ */
7
13
  export const Fragment = react.Fragment;
8
14
 
15
+ /**
16
+ * React 的 `Component` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
17
+ */
9
18
  export const Component = react.Component;
10
19
 
20
+ /**
21
+ * React 的 `createContext` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
22
+ */
11
23
  export const createContext = react.createContext;
24
+ /**
25
+ * React 的 `useContext` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
26
+ */
12
27
  export const useContext = react.useContext;
13
28
 
29
+ /**
30
+ * React 的 `useState` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
31
+ */
14
32
  export const useState = react.useState;
33
+ /**
34
+ * React 的 `useEffect` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
35
+ */
15
36
  export const useEffect = react.useEffect;
37
+ /**
38
+ * React 的 `useLayoutEffect` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
39
+ */
16
40
  export const useLayoutEffect = react.useLayoutEffect;
41
+ /**
42
+ * React 的 `useMemo` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
43
+ */
17
44
  export const useMemo = react.useMemo;
45
+ /**
46
+ * React 的 `useCallback` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
47
+ */
18
48
  export const useCallback = react.useCallback;
49
+ /**
50
+ * React 的 `useRef` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
51
+ */
19
52
  export const useRef = react.useRef;
53
+ /**
54
+ * React 的 `useSyncExternalStore` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
55
+ */
20
56
  export const useSyncExternalStore = react.useSyncExternalStore;
21
57
 
58
+ /**
59
+ * 从 react 借来的三个类型(`ReactNode` / `CSSProperties` / `ChangeEvent`)—— 模块从这里拿,就不必自己直接依赖 react。
60
+ */
22
61
  export type { ReactNode, CSSProperties, ChangeEvent } from 'react';
package/src/lib/text.ts CHANGED
@@ -1,7 +1,18 @@
1
+ /**
2
+ * 把一个值裹成 shell 里的单引号字面量(值里的单引号一并转义),保证元字符按字面量传递。
3
+ * @param value - 任意值;不是字符串的先 `String()`。
4
+ * @returns 可安全拼进 `/bin/sh -c` 的一段文本 —— 含空格 / `$()` / `;` / 通配符的值都不会被当成语法。
5
+ */
1
6
  export function quoteShellArg(value: unknown): string {
2
7
  return `'${String(value).replace(/'/g, `'\\''`)}'`;
3
8
  }
4
9
 
10
+ /**
11
+ * 取一段文本的末尾若干行(如命令输出),顺带去掉首尾空白。
12
+ * @param text - 原文;`null` / `undefined` 当空串。
13
+ * @param lines - 最多留几行,默认 6;0 给全篇、负数从开头砍掉那么多行(都是 `slice` 语义),调用方传正数。
14
+ * @returns 末尾若干行、去首尾空行后的文本;原文行数不够就全给,空输入给空串。
15
+ */
5
16
  export function tailLines(text: string | null | undefined, lines = 6): string {
6
17
  const all = String(text ?? '')
7
18
  .trim()
@@ -24,6 +35,11 @@ function candidateStarts(raw: string): number[] {
24
35
  return starts;
25
36
  }
26
37
 
38
+ /**
39
+ * 宽松解析一段前后可能夹着人话的 JSON:整段不通就从行首的 `[` / `{` 起、截到最后一个闭合符再试。
40
+ * @param text - 原文;`null` / `undefined` 当空串。
41
+ * @returns 解析出的值(对象 / 数组 / 标量都原样);空输入或怎么都解析不出给 `undefined`,调用方据此报「输出认不出」。
42
+ */
27
43
  export function parseJsonLoose(text: string | null | undefined): unknown {
28
44
  const raw = String(text ?? '').trim();
29
45
  if (!raw) return undefined;
@@ -48,6 +64,12 @@ const MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
48
64
  const MARKDOWN_LINK = /\[([^\]]*)\]\([^)]*\)/g;
49
65
  const MARKDOWN_MARKS = /[*`_>#]/g;
50
66
 
67
+ /**
68
+ * 把一段 Markdown 压成一行纯文本摘要:图片剥掉、链接只留可见文字、标记符号压成空格,超长按字符截断。
69
+ * @param text - 原文;`null` / `undefined` 当空串。
70
+ * @param limit - 摘要最多多少字符,默认 80。
71
+ * @returns 单行摘要;没超限原样给,超了截到 `limit` 并补省略号(总长 `limit + 1`;第 `limit` 个字符是空白时会被 `trimEnd` 去掉、略短),空输入给空串。
72
+ */
51
73
  export function excerpt(text: string | null | undefined, limit = 80): string {
52
74
  const flat = String(text ?? '')
53
75
  .replace(MARKDOWN_IMAGE, ' ')
package/src/lib/ui.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 拼类名:只留真值、用空格连接(`false` / `null` / `undefined` / 空串都丢掉)。
3
+ * @param parts - 若干类名或条件值。
4
+ * @returns 拼好的类字符串;一个真值都没有给空串。
5
+ */
1
6
  export function cx(...parts: Array<string | false | null | undefined>): string {
2
7
  return parts.filter(Boolean).join(' ');
3
8
  }
@@ -8,15 +13,30 @@ const DAY = 24 * HOUR;
8
13
  const MONTH = 30 * DAY;
9
14
  const YEAR = 365 * DAY;
10
15
 
16
+ /**
17
+ * 时间文案取词:i18n 的 `(key, params) => 文案`;相对时间那几件都从它拿词。
18
+ */
11
19
  export type TimeTranslate = (key: string, params?: Record<string, unknown>) => string;
12
20
 
21
+ /**
22
+ * 相对时间的档位名,对应词表里的 `time.short.*`。
23
+ */
13
24
  export type RelativeTimeUnit = 'now' | 'minutes' | 'hours' | 'days' | 'months' | 'years';
14
25
 
26
+ /**
27
+ * 相对时间的一档:`unit` 是档位,`n` 是这一档的数量(单位随档位,见 `relativeTimeBucket`)。
28
+ */
15
29
  export interface RelativeTimeBucket {
16
30
  readonly unit: RelativeTimeUnit;
17
31
  readonly n: number;
18
32
  }
19
33
 
34
+ /**
35
+ * 把时间戳按 dsh 的分档切成「刚刚 / N 分钟 / N 小时 / N 天 / N 月 / N 年」—— 30 天进月、365 天进年。
36
+ * @param epochMs - 要换算的时间戳(毫秒)。
37
+ * @param now - 基准时间,默认 `Date.now()`。
38
+ * @returns 档位与数量;时间戳或基准不是有限数给 `null`,未来时间钳到「刚刚」(`now` / 0)。
39
+ */
20
40
  export function relativeTimeBucket(epochMs: number, now: number = Date.now()): RelativeTimeBucket | null {
21
41
  if (!Number.isFinite(epochMs) || !Number.isFinite(now)) return null;
22
42
  const diff = Math.max(0, now - epochMs);
@@ -32,11 +52,25 @@ function bucketLabel(bucket: RelativeTimeBucket, t: TimeTranslate): string {
32
52
  return bucket.unit === 'now' ? t('time.now') : t(`time.short.${bucket.unit}`, { n: bucket.n });
33
53
  }
34
54
 
55
+ /**
56
+ * 行内用的紧凑相对时间(「3 分钟」这种,不带「前」)。
57
+ * @param epochMs - 要换算的时间戳(毫秒)。
58
+ * @param t - 词表取词函数。
59
+ * @param now - 基准时间,默认 `Date.now()`。
60
+ * @returns 紧凑文案;时间戳非法给空串。
61
+ */
35
62
  export function relativeTimeCompact(epochMs: number, t: TimeTranslate, now?: number): string {
36
63
  const bucket = relativeTimeBucket(epochMs, now);
37
64
  return bucket === null ? '' : bucketLabel(bucket, t);
38
65
  }
39
66
 
67
+ /**
68
+ * 悬停卡里用的相对时间(「3 分钟前」);「刚刚」那一档不加「前」。
69
+ * @param epochMs - 要换算的时间戳(毫秒)。
70
+ * @param t - 词表取词函数。
71
+ * @param now - 基准时间,默认 `Date.now()`。
72
+ * @returns 带「前」的文案;时间戳非法给空串。
73
+ */
40
74
  export function relativeTimeAgo(epochMs: number, t: TimeTranslate, now?: number): string {
41
75
  const bucket = relativeTimeBucket(epochMs, now);
42
76
  if (bucket === null) return '';
@@ -44,6 +78,12 @@ export function relativeTimeAgo(epochMs: number, t: TimeTranslate, now?: number)
44
78
  return bucket.unit === 'now' ? label : t('time.ago', { t: label });
45
79
  }
46
80
 
81
+ /**
82
+ * 会话行那一版相对时间:一小时内按分钟、一天内按小时、七天内按天,再久直接给绝对时间(到秒)。
83
+ * @param epochMs - 要换算的时间戳(毫秒)。
84
+ * @param t - 词表取词函数。
85
+ * @returns 文案;时间戳不是有限数给空串,未来时间落「刚刚」,七天及以上给本地化的年月日时分秒。
86
+ */
47
87
  export function relativeTime(epochMs: number, t: TimeTranslate): string {
48
88
  if (!Number.isFinite(epochMs)) return '';
49
89
  const diff = Date.now() - epochMs;
@@ -61,6 +101,11 @@ export function relativeTime(epochMs: number, t: TimeTranslate): string {
61
101
  });
62
102
  }
63
103
 
104
+ /**
105
+ * 把 `/Users/<用户名>/…` 缩成 `~/…`,免得会话行里全是一样的长前缀。
106
+ * @param path - 任意值。
107
+ * @returns 缩好的路径;不在用户主目录下原样返回,不是字符串给空串。
108
+ */
64
109
  export function shortenPath(path: unknown): string {
65
110
  if (typeof path !== 'string') return '';
66
111
  const hit = path.match(/^\/Users\/[^/]+/);
@@ -69,6 +114,11 @@ export function shortenPath(path: unknown): string {
69
114
 
70
115
  const LOCAL_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})$/;
71
116
 
117
+ /**
118
+ * 解析不带时区的本地时间戳(`YYYY-MM-DD HH:mm:ss`,也接受 `T` 分隔),按本机时区换算。
119
+ * @param text - 原文;`null` / `undefined` 当空串;首尾空白容忍。
120
+ * @returns 毫秒时间戳;形态不认识给 `NaN`(调用方据此回退到原始字符串,宁可不换算也不显示错时间)。
121
+ */
72
122
  export function parseLocalTimestamp(text: string | null | undefined): number {
73
123
  const raw = String(text ?? '').trim();
74
124
  if (!LOCAL_TIMESTAMP.test(raw)) return Number.NaN;