@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.
- 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 +18 -0
- 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 +12 -0
- package/dist/components/ApprovalDetail.js +9 -0
- 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 +42 -0
- package/dist/config/constants.js +42 -0
- package/dist/config/storage.d.ts +4 -0
- package/dist/config/storage.js +4 -0
- package/dist/host/unit-face.d.ts +5 -1
- package/dist/i18n/en.d.ts +1 -0
- package/dist/i18n/en.js +8 -8
- package/dist/i18n/index.d.ts +11 -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 +9 -8
- package/dist/i18n/zh.js +8 -8
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -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 +41 -0
- package/dist/lib/diy-record.js +17 -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 +18 -0
- 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 +12 -0
- 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 +43 -0
- package/src/config/storage.ts +4 -0
- package/src/host/unit-face.ts +6 -1
- package/src/i18n/en.ts +8 -8
- package/src/i18n/index.ts +3 -0
- package/src/i18n/merge.ts +5 -0
- package/src/i18n/zh.ts +9 -8
- package/src/index.ts +6 -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.ts +41 -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/dist/lib/react.js
CHANGED
|
@@ -1,13 +1,49 @@
|
|
|
1
1
|
const react = require('react');
|
|
2
|
+
/**
|
|
3
|
+
* React 的 `createElement` 换个短名字再导出 —— 这套代码用 `h(...)` 写元素。
|
|
4
|
+
*/
|
|
2
5
|
export const h = react.createElement;
|
|
6
|
+
/**
|
|
7
|
+
* React 的 `Fragment` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
8
|
+
*/
|
|
3
9
|
export const Fragment = react.Fragment;
|
|
10
|
+
/**
|
|
11
|
+
* React 的 `Component` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
12
|
+
*/
|
|
4
13
|
export const Component = react.Component;
|
|
14
|
+
/**
|
|
15
|
+
* React 的 `createContext` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
16
|
+
*/
|
|
5
17
|
export const createContext = react.createContext;
|
|
18
|
+
/**
|
|
19
|
+
* React 的 `useContext` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
20
|
+
*/
|
|
6
21
|
export const useContext = react.useContext;
|
|
22
|
+
/**
|
|
23
|
+
* React 的 `useState` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
24
|
+
*/
|
|
7
25
|
export const useState = react.useState;
|
|
26
|
+
/**
|
|
27
|
+
* React 的 `useEffect` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
28
|
+
*/
|
|
8
29
|
export const useEffect = react.useEffect;
|
|
30
|
+
/**
|
|
31
|
+
* React 的 `useLayoutEffect` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
32
|
+
*/
|
|
9
33
|
export const useLayoutEffect = react.useLayoutEffect;
|
|
34
|
+
/**
|
|
35
|
+
* React 的 `useMemo` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
36
|
+
*/
|
|
10
37
|
export const useMemo = react.useMemo;
|
|
38
|
+
/**
|
|
39
|
+
* React 的 `useCallback` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
40
|
+
*/
|
|
11
41
|
export const useCallback = react.useCallback;
|
|
42
|
+
/**
|
|
43
|
+
* React 的 `useRef` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
44
|
+
*/
|
|
12
45
|
export const useRef = react.useRef;
|
|
46
|
+
/**
|
|
47
|
+
* React 的 `useSyncExternalStore` 原样再导出 —— 模块从这里拿,就不必自己直接依赖 react。
|
|
48
|
+
*/
|
|
13
49
|
export const useSyncExternalStore = react.useSyncExternalStore;
|
package/dist/lib/text.d.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 把一个值裹成 shell 里的单引号字面量(值里的单引号一并转义),保证元字符按字面量传递。
|
|
3
|
+
* @param value - 任意值;不是字符串的先 `String()`。
|
|
4
|
+
* @returns 可安全拼进 `/bin/sh -c` 的一段文本 —— 含空格 / `$()` / `;` / 通配符的值都不会被当成语法。
|
|
5
|
+
*/
|
|
1
6
|
export declare function quoteShellArg(value: unknown): string;
|
|
7
|
+
/**
|
|
8
|
+
* 取一段文本的末尾若干行(如命令输出),顺带去掉首尾空白。
|
|
9
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
10
|
+
* @param lines - 最多留几行,默认 6;0 给全篇、负数从开头砍掉那么多行(都是 `slice` 语义),调用方传正数。
|
|
11
|
+
* @returns 末尾若干行、去首尾空行后的文本;原文行数不够就全给,空输入给空串。
|
|
12
|
+
*/
|
|
2
13
|
export declare function tailLines(text: string | null | undefined, lines?: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* 宽松解析一段前后可能夹着人话的 JSON:整段不通就从行首的 `[` / `{` 起、截到最后一个闭合符再试。
|
|
16
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
17
|
+
* @returns 解析出的值(对象 / 数组 / 标量都原样);空输入或怎么都解析不出给 `undefined`,调用方据此报「输出认不出」。
|
|
18
|
+
*/
|
|
3
19
|
export declare function parseJsonLoose(text: string | null | undefined): unknown;
|
|
20
|
+
/**
|
|
21
|
+
* 把一段 Markdown 压成一行纯文本摘要:图片剥掉、链接只留可见文字、标记符号压成空格,超长按字符截断。
|
|
22
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
23
|
+
* @param limit - 摘要最多多少字符,默认 80。
|
|
24
|
+
* @returns 单行摘要;没超限原样给,超了截到 `limit` 并补省略号(总长 `limit + 1`;第 `limit` 个字符是空白时会被 `trimEnd` 去掉、略短),空输入给空串。
|
|
25
|
+
*/
|
|
4
26
|
export declare function excerpt(text: string | null | undefined, limit?: number): string;
|
package/dist/lib/text.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 把一个值裹成 shell 里的单引号字面量(值里的单引号一并转义),保证元字符按字面量传递。
|
|
3
|
+
* @param value - 任意值;不是字符串的先 `String()`。
|
|
4
|
+
* @returns 可安全拼进 `/bin/sh -c` 的一段文本 —— 含空格 / `$()` / `;` / 通配符的值都不会被当成语法。
|
|
5
|
+
*/
|
|
1
6
|
export function quoteShellArg(value) {
|
|
2
7
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
3
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* 取一段文本的末尾若干行(如命令输出),顺带去掉首尾空白。
|
|
11
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
12
|
+
* @param lines - 最多留几行,默认 6;0 给全篇、负数从开头砍掉那么多行(都是 `slice` 语义),调用方传正数。
|
|
13
|
+
* @returns 末尾若干行、去首尾空行后的文本;原文行数不够就全给,空输入给空串。
|
|
14
|
+
*/
|
|
4
15
|
export function tailLines(text, lines = 6) {
|
|
5
16
|
const all = String(text ?? '')
|
|
6
17
|
.trim()
|
|
@@ -24,6 +35,11 @@ function candidateStarts(raw) {
|
|
|
24
35
|
}
|
|
25
36
|
return starts;
|
|
26
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* 宽松解析一段前后可能夹着人话的 JSON:整段不通就从行首的 `[` / `{` 起、截到最后一个闭合符再试。
|
|
40
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
41
|
+
* @returns 解析出的值(对象 / 数组 / 标量都原样);空输入或怎么都解析不出给 `undefined`,调用方据此报「输出认不出」。
|
|
42
|
+
*/
|
|
27
43
|
export function parseJsonLoose(text) {
|
|
28
44
|
const raw = String(text ?? '').trim();
|
|
29
45
|
if (!raw)
|
|
@@ -50,6 +66,12 @@ export function parseJsonLoose(text) {
|
|
|
50
66
|
const MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
|
|
51
67
|
const MARKDOWN_LINK = /\[([^\]]*)\]\([^)]*\)/g;
|
|
52
68
|
const MARKDOWN_MARKS = /[*`_>#]/g;
|
|
69
|
+
/**
|
|
70
|
+
* 把一段 Markdown 压成一行纯文本摘要:图片剥掉、链接只留可见文字、标记符号压成空格,超长按字符截断。
|
|
71
|
+
* @param text - 原文;`null` / `undefined` 当空串。
|
|
72
|
+
* @param limit - 摘要最多多少字符,默认 80。
|
|
73
|
+
* @returns 单行摘要;没超限原样给,超了截到 `limit` 并补省略号(总长 `limit + 1`;第 `limit` 个字符是空白时会被 `trimEnd` 去掉、略短),空输入给空串。
|
|
74
|
+
*/
|
|
53
75
|
export function excerpt(text, limit = 80) {
|
|
54
76
|
const flat = String(text ?? '')
|
|
55
77
|
.replace(MARKDOWN_IMAGE, ' ')
|
package/dist/lib/ui.d.ts
CHANGED
|
@@ -1,13 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 拼类名:只留真值、用空格连接(`false` / `null` / `undefined` / 空串都丢掉)。
|
|
3
|
+
* @param parts - 若干类名或条件值。
|
|
4
|
+
* @returns 拼好的类字符串;一个真值都没有给空串。
|
|
5
|
+
*/
|
|
1
6
|
export declare function cx(...parts: Array<string | false | null | undefined>): string;
|
|
7
|
+
/**
|
|
8
|
+
* 时间文案取词:i18n 的 `(key, params) => 文案`;相对时间那几件都从它拿词。
|
|
9
|
+
*/
|
|
2
10
|
export type TimeTranslate = (key: string, params?: Record<string, unknown>) => string;
|
|
11
|
+
/**
|
|
12
|
+
* 相对时间的档位名,对应词表里的 `time.short.*`。
|
|
13
|
+
*/
|
|
3
14
|
export type RelativeTimeUnit = 'now' | 'minutes' | 'hours' | 'days' | 'months' | 'years';
|
|
15
|
+
/**
|
|
16
|
+
* 相对时间的一档:`unit` 是档位,`n` 是这一档的数量(单位随档位,见 `relativeTimeBucket`)。
|
|
17
|
+
*/
|
|
4
18
|
export interface RelativeTimeBucket {
|
|
5
19
|
readonly unit: RelativeTimeUnit;
|
|
6
20
|
readonly n: number;
|
|
7
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* 把时间戳按 dsh 的分档切成「刚刚 / N 分钟 / N 小时 / N 天 / N 月 / N 年」—— 30 天进月、365 天进年。
|
|
24
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
25
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
26
|
+
* @returns 档位与数量;时间戳或基准不是有限数给 `null`,未来时间钳到「刚刚」(`now` / 0)。
|
|
27
|
+
*/
|
|
8
28
|
export declare function relativeTimeBucket(epochMs: number, now?: number): RelativeTimeBucket | null;
|
|
29
|
+
/**
|
|
30
|
+
* 行内用的紧凑相对时间(「3 分钟」这种,不带「前」)。
|
|
31
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
32
|
+
* @param t - 词表取词函数。
|
|
33
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
34
|
+
* @returns 紧凑文案;时间戳非法给空串。
|
|
35
|
+
*/
|
|
9
36
|
export declare function relativeTimeCompact(epochMs: number, t: TimeTranslate, now?: number): string;
|
|
37
|
+
/**
|
|
38
|
+
* 悬停卡里用的相对时间(「3 分钟前」);「刚刚」那一档不加「前」。
|
|
39
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
40
|
+
* @param t - 词表取词函数。
|
|
41
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
42
|
+
* @returns 带「前」的文案;时间戳非法给空串。
|
|
43
|
+
*/
|
|
10
44
|
export declare function relativeTimeAgo(epochMs: number, t: TimeTranslate, now?: number): string;
|
|
45
|
+
/**
|
|
46
|
+
* 会话行那一版相对时间:一小时内按分钟、一天内按小时、七天内按天,再久直接给绝对时间(到秒)。
|
|
47
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
48
|
+
* @param t - 词表取词函数。
|
|
49
|
+
* @returns 文案;时间戳不是有限数给空串,未来时间落「刚刚」,七天及以上给本地化的年月日时分秒。
|
|
50
|
+
*/
|
|
11
51
|
export declare function relativeTime(epochMs: number, t: TimeTranslate): string;
|
|
52
|
+
/**
|
|
53
|
+
* 把 `/Users/<用户名>/…` 缩成 `~/…`,免得会话行里全是一样的长前缀。
|
|
54
|
+
* @param path - 任意值。
|
|
55
|
+
* @returns 缩好的路径;不在用户主目录下原样返回,不是字符串给空串。
|
|
56
|
+
*/
|
|
12
57
|
export declare function shortenPath(path: unknown): string;
|
|
58
|
+
/**
|
|
59
|
+
* 解析不带时区的本地时间戳(`YYYY-MM-DD HH:mm:ss`,也接受 `T` 分隔),按本机时区换算。
|
|
60
|
+
* @param text - 原文;`null` / `undefined` 当空串;首尾空白容忍。
|
|
61
|
+
* @returns 毫秒时间戳;形态不认识给 `NaN`(调用方据此回退到原始字符串,宁可不换算也不显示错时间)。
|
|
62
|
+
*/
|
|
13
63
|
export declare function parseLocalTimestamp(text: string | null | undefined): number;
|
package/dist/lib/ui.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 拼类名:只留真值、用空格连接(`false` / `null` / `undefined` / 空串都丢掉)。
|
|
3
|
+
* @param parts - 若干类名或条件值。
|
|
4
|
+
* @returns 拼好的类字符串;一个真值都没有给空串。
|
|
5
|
+
*/
|
|
1
6
|
export function cx(...parts) {
|
|
2
7
|
return parts.filter(Boolean).join(' ');
|
|
3
8
|
}
|
|
@@ -6,6 +11,12 @@ const HOUR = 60 * MINUTE;
|
|
|
6
11
|
const DAY = 24 * HOUR;
|
|
7
12
|
const MONTH = 30 * DAY;
|
|
8
13
|
const YEAR = 365 * DAY;
|
|
14
|
+
/**
|
|
15
|
+
* 把时间戳按 dsh 的分档切成「刚刚 / N 分钟 / N 小时 / N 天 / N 月 / N 年」—— 30 天进月、365 天进年。
|
|
16
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
17
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
18
|
+
* @returns 档位与数量;时间戳或基准不是有限数给 `null`,未来时间钳到「刚刚」(`now` / 0)。
|
|
19
|
+
*/
|
|
9
20
|
export function relativeTimeBucket(epochMs, now = Date.now()) {
|
|
10
21
|
if (!Number.isFinite(epochMs) || !Number.isFinite(now))
|
|
11
22
|
return null;
|
|
@@ -25,10 +36,24 @@ export function relativeTimeBucket(epochMs, now = Date.now()) {
|
|
|
25
36
|
function bucketLabel(bucket, t) {
|
|
26
37
|
return bucket.unit === 'now' ? t('time.now') : t(`time.short.${bucket.unit}`, { n: bucket.n });
|
|
27
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* 行内用的紧凑相对时间(「3 分钟」这种,不带「前」)。
|
|
41
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
42
|
+
* @param t - 词表取词函数。
|
|
43
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
44
|
+
* @returns 紧凑文案;时间戳非法给空串。
|
|
45
|
+
*/
|
|
28
46
|
export function relativeTimeCompact(epochMs, t, now) {
|
|
29
47
|
const bucket = relativeTimeBucket(epochMs, now);
|
|
30
48
|
return bucket === null ? '' : bucketLabel(bucket, t);
|
|
31
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* 悬停卡里用的相对时间(「3 分钟前」);「刚刚」那一档不加「前」。
|
|
52
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
53
|
+
* @param t - 词表取词函数。
|
|
54
|
+
* @param now - 基准时间,默认 `Date.now()`。
|
|
55
|
+
* @returns 带「前」的文案;时间戳非法给空串。
|
|
56
|
+
*/
|
|
32
57
|
export function relativeTimeAgo(epochMs, t, now) {
|
|
33
58
|
const bucket = relativeTimeBucket(epochMs, now);
|
|
34
59
|
if (bucket === null)
|
|
@@ -36,6 +61,12 @@ export function relativeTimeAgo(epochMs, t, now) {
|
|
|
36
61
|
const label = bucketLabel(bucket, t);
|
|
37
62
|
return bucket.unit === 'now' ? label : t('time.ago', { t: label });
|
|
38
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* 会话行那一版相对时间:一小时内按分钟、一天内按小时、七天内按天,再久直接给绝对时间(到秒)。
|
|
66
|
+
* @param epochMs - 要换算的时间戳(毫秒)。
|
|
67
|
+
* @param t - 词表取词函数。
|
|
68
|
+
* @returns 文案;时间戳不是有限数给空串,未来时间落「刚刚」,七天及以上给本地化的年月日时分秒。
|
|
69
|
+
*/
|
|
39
70
|
export function relativeTime(epochMs, t) {
|
|
40
71
|
if (!Number.isFinite(epochMs))
|
|
41
72
|
return '';
|
|
@@ -57,6 +88,11 @@ export function relativeTime(epochMs, t) {
|
|
|
57
88
|
second: '2-digit',
|
|
58
89
|
});
|
|
59
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* 把 `/Users/<用户名>/…` 缩成 `~/…`,免得会话行里全是一样的长前缀。
|
|
93
|
+
* @param path - 任意值。
|
|
94
|
+
* @returns 缩好的路径;不在用户主目录下原样返回,不是字符串给空串。
|
|
95
|
+
*/
|
|
60
96
|
export function shortenPath(path) {
|
|
61
97
|
if (typeof path !== 'string')
|
|
62
98
|
return '';
|
|
@@ -64,6 +100,11 @@ export function shortenPath(path) {
|
|
|
64
100
|
return hit === null ? path : path.replace(hit[0], '~');
|
|
65
101
|
}
|
|
66
102
|
const LOCAL_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})$/;
|
|
103
|
+
/**
|
|
104
|
+
* 解析不带时区的本地时间戳(`YYYY-MM-DD HH:mm:ss`,也接受 `T` 分隔),按本机时区换算。
|
|
105
|
+
* @param text - 原文;`null` / `undefined` 当空串;首尾空白容忍。
|
|
106
|
+
* @returns 毫秒时间戳;形态不认识给 `NaN`(调用方据此回退到原始字符串,宁可不换算也不显示错时间)。
|
|
107
|
+
*/
|
|
67
108
|
export function parseLocalTimestamp(text) {
|
|
68
109
|
const raw = String(text ?? '').trim();
|
|
69
110
|
if (!LOCAL_TIMESTAMP.test(raw))
|
package/package.json
CHANGED
package/src/api/blocker-table.ts
CHANGED
|
@@ -12,6 +12,13 @@ function copyAction(t: Translate, text: string): BlockerAction {
|
|
|
12
12
|
return { kind: 'copy', label: t('blocker.copy'), text };
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* 把一次读失败翻成一张卡住态,交给卡片直接渲染。
|
|
17
|
+
* @param error 读口回的错误;undefined 表示连错误都没拿到(多半是网络断,回「原因未知」)。
|
|
18
|
+
* @param t 文案函数,只取 blocker.* 命名空间的键。
|
|
19
|
+
* @param context 判定现场;platform 缺省时标题不带平台名。
|
|
20
|
+
* @returns 一定有一张卡,actions 至少一颗「重试」。
|
|
21
|
+
*/
|
|
15
22
|
export function blockerOfError(
|
|
16
23
|
error: ApiError | undefined,
|
|
17
24
|
t: Translate,
|
|
@@ -103,6 +110,12 @@ export function blockerOfError(
|
|
|
103
110
|
}
|
|
104
111
|
}
|
|
105
112
|
|
|
113
|
+
/**
|
|
114
|
+
* 把宿主回的环境读数翻成卡住态:探针没查过(unchecked)只算提示,不挡卡片。
|
|
115
|
+
* @param capability 宿主回的单元环境读数。
|
|
116
|
+
* @param t 文案函数,键都在 env.unit.* / blocker.* 下。
|
|
117
|
+
* @returns status 为 'ok' 时给 undefined(没有卡住态),其余状态一律给一张。
|
|
118
|
+
*/
|
|
106
119
|
export function blockerOfCapability(capability: CapabilityPayload, t: Translate): ModuleBlocker | undefined {
|
|
107
120
|
if (capability.status === 'ok') return undefined;
|
|
108
121
|
|
package/src/api/blocker.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 卡住时用户能点的那一下(开链接 / 复制命令 / 重试 / 装或升模块):由判据产出,卡片照原样渲染。
|
|
3
|
+
*/
|
|
1
4
|
export type BlockerAction =
|
|
2
5
|
| {
|
|
3
6
|
readonly kind: 'open-url';
|
|
@@ -15,6 +18,9 @@ export type BlockerAction =
|
|
|
15
18
|
}
|
|
16
19
|
| { readonly kind: 'open-market'; readonly label: string; readonly unit: string };
|
|
17
20
|
|
|
21
|
+
/**
|
|
22
|
+
* 一个单元此刻的卡住态:block 顶掉整张卡片,notice 只在角上提示一句;读口与探针产出,卡片消费。
|
|
23
|
+
*/
|
|
18
24
|
export interface ModuleBlocker {
|
|
19
25
|
readonly id: string;
|
|
20
26
|
readonly severity: 'block' | 'notice';
|
package/src/api/context-ref.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 引用标记的固定名字;完整标记是 @<这个名字>:<编码文本>,改它等于作废历史会话里已写下的引用。
|
|
3
|
+
*/
|
|
1
4
|
export const CONTEXT_MARKER_NAME = '工作台';
|
|
2
5
|
|
|
6
|
+
/**
|
|
7
|
+
* 一条解析后的引用(种类加路径分段):输入框写标记时产出,跳转与展示时消费。
|
|
8
|
+
*/
|
|
3
9
|
export interface ContextRef {
|
|
4
10
|
readonly kind: string;
|
|
5
11
|
readonly parts: readonly string[];
|
|
@@ -9,10 +15,20 @@ const MARKER = new RegExp(`@${CONTEXT_MARKER_NAME}:([a-z][a-z0-9-]*:[A-Za-z0-9._
|
|
|
9
15
|
|
|
10
16
|
const TRAILING_PUNCTUATION = /[.,;:!?]+$/;
|
|
11
17
|
|
|
18
|
+
/**
|
|
19
|
+
* 把引用拼回标记体里的那一段文本(不含 @ 与标记名)。
|
|
20
|
+
* @param ref 要拼的引用。
|
|
21
|
+
* @returns 形如 kind:part/part;分段里的 / 不转义,所以分段名本身不能含 /。
|
|
22
|
+
*/
|
|
12
23
|
export function encodeRef(ref: ContextRef): string {
|
|
13
24
|
return `${ref.kind}:${ref.parts.join('/')}`;
|
|
14
25
|
}
|
|
15
26
|
|
|
27
|
+
/**
|
|
28
|
+
* 把 kind:part/part 文本读回引用。
|
|
29
|
+
* @param text 待解析文本。
|
|
30
|
+
* @returns 没冒号、冒号在首尾、种类不是小写字母开头、或冒号后为空时给 undefined;不抛异常。
|
|
31
|
+
*/
|
|
16
32
|
export function decodeRef(text: string): ContextRef | undefined {
|
|
17
33
|
const at = text.indexOf(':');
|
|
18
34
|
if (at <= 0 || at === text.length - 1) return undefined;
|
|
@@ -23,14 +39,29 @@ export function decodeRef(text: string): ContextRef | undefined {
|
|
|
23
39
|
return { kind, parts };
|
|
24
40
|
}
|
|
25
41
|
|
|
42
|
+
/**
|
|
43
|
+
* 拼出 @ 后面那半截(标记名加已编码文本),比较与拼接都用它。
|
|
44
|
+
* @param encoded encodeRef 的结果。
|
|
45
|
+
* @returns 形如 工作台:file:src/a.ts。
|
|
46
|
+
*/
|
|
26
47
|
export function markerBody(encoded: string): string {
|
|
27
48
|
return `${CONTEXT_MARKER_NAME}:${encoded}`;
|
|
28
49
|
}
|
|
29
50
|
|
|
51
|
+
/**
|
|
52
|
+
* 把一条引用拼成能写进对话文本的完整标记。
|
|
53
|
+
* @param ref 要标记的引用。
|
|
54
|
+
* @returns 形如 @工作台:file:src/a.ts 的一段文本。
|
|
55
|
+
*/
|
|
30
56
|
export function buildMarker(ref: ContextRef): string {
|
|
31
57
|
return `@${markerBody(encodeRef(ref))}`;
|
|
32
58
|
}
|
|
33
59
|
|
|
60
|
+
/**
|
|
61
|
+
* 从一段文本里按出现顺序捞出所有标记引用,同一个引用只留第一次。
|
|
62
|
+
* @param text 任意文本;null / undefined 当空串。
|
|
63
|
+
* @returns 解析不出来的标记会被丢掉,所以结果只含合法引用,可能为空数组。
|
|
64
|
+
*/
|
|
34
65
|
export function parseMarkers(text: string): ContextRef[] {
|
|
35
66
|
const seen = new Set<string>();
|
|
36
67
|
const refs: ContextRef[] = [];
|
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;
|