@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.
- 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 +66 -1
- package/dist/api/long-task.js +59 -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.css +31 -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.css +52 -0
- package/dist/components/LongTaskRow.d.ts +35 -0
- package/dist/components/LongTaskRow.js +45 -4
- 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/long-task.d.ts +7 -0
- package/dist/host/long-task.js +31 -5
- package/dist/host/tool-approval.d.ts +1 -0
- package/dist/host/unit-face.d.ts +6 -1
- package/dist/i18n/en.d.ts +1 -0
- package/dist/i18n/en.js +10 -8
- package/dist/i18n/index.d.ts +13 -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 +11 -8
- package/dist/i18n/zh.js +10 -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/__tests__/long-task.test.ts +41 -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 +79 -1
- 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.css +31 -0
- package/src/components/FormRows.test.tsx +71 -1
- 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.css +52 -0
- package/src/components/LongTaskRow.tsx +76 -2
- 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/__tests__/long-task-row.test.ts +115 -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/__tests__/long-task.test.ts +264 -0
- package/src/host/long-task.ts +43 -7
- package/src/host/tool-approval.ts +1 -0
- package/src/host/unit-face.ts +7 -1
- package/src/i18n/en.ts +11 -8
- package/src/i18n/index.ts +3 -0
- package/src/i18n/merge.ts +5 -0
- package/src/i18n/zh.ts +11 -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
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
const HERE = new URL('../', import.meta.url);
|
|
5
|
+
const read = (name: string): string => readFileSync(new URL(name, HERE), 'utf8');
|
|
6
|
+
|
|
7
|
+
const ROW = read('LongTaskRow.tsx');
|
|
8
|
+
const CSS = read('LongTaskRow.css');
|
|
9
|
+
|
|
10
|
+
describe('两按停止钮:接线(这仓的组件测试是 node 环境,读源码断言)', () => {
|
|
11
|
+
it('★★ 不给 stop ⇒ 那颗钮整个不出现;文件里也再没有第二颗 button', () => {
|
|
12
|
+
const gate = ROW.indexOf('{stop === undefined ? null : (');
|
|
13
|
+
const button = ROW.indexOf('<button');
|
|
14
|
+
|
|
15
|
+
expect(ROW).toContain('const stop = props.stop;');
|
|
16
|
+
expect(gate).toBeGreaterThan(0);
|
|
17
|
+
expect(button).toBeGreaterThan(gate);
|
|
18
|
+
expect(ROW.indexOf('<button', button + 1)).toBe(-1);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('★★ 住在 .wb-longTaskHead 里、最右边那颗(margin-left: auto)', () => {
|
|
22
|
+
const head = ROW.indexOf('className="wb-longTaskHead"');
|
|
23
|
+
const button = ROW.indexOf('<button');
|
|
24
|
+
const close = ROW.indexOf('</p>', button);
|
|
25
|
+
|
|
26
|
+
expect(head).toBeGreaterThan(0);
|
|
27
|
+
expect(button).toBeGreaterThan(head);
|
|
28
|
+
expect(close).toBeGreaterThan(button);
|
|
29
|
+
expect(CSS).toContain('margin-left: auto');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('★★ 两按只走 longTaskStopPress(longTaskStopStage({ armed, busy })):arm 上膛 / fire 落膛并 onStop / ignore 不动', () => {
|
|
33
|
+
expect(ROW).toContain('longTaskStopPress(longTaskStopStage({ armed, busy }))');
|
|
34
|
+
expect(ROW).toContain('onClick={onStopPress}');
|
|
35
|
+
expect(ROW).toContain("if (press === 'ignore') return;");
|
|
36
|
+
expect(ROW).toContain("if (press === 'arm') {");
|
|
37
|
+
expect(ROW).toContain('setArmed(true);');
|
|
38
|
+
expect(ROW).toMatch(/setArmed\(false\);\s*stop\.onStop\(\);/);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('★★ onBlur 落膛(焦点一走就退回没上膛)', () => {
|
|
42
|
+
expect(ROW).toContain('onBlur={() => setArmed(false)}');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('★★ 上膛后 3 秒自己落膛:用 LONG_TASK_STOP_ARM_MS,卸载 / 落膛都清掉计时器', () => {
|
|
46
|
+
expect(ROW).toContain("from '../api/long-task.js'");
|
|
47
|
+
expect(ROW).toContain('setTimeout(() => setArmed(false), LONG_TASK_STOP_ARM_MS)');
|
|
48
|
+
expect(ROW).toContain('clearTimeout(timer)');
|
|
49
|
+
expect(ROW).toContain('}, [armed]);');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('★★ data-stop-state 交出那一档(照 dsh 的 data-kill-state)', () => {
|
|
53
|
+
expect(ROW).toContain('data-stop-state={longTaskStopStage({ armed, busy })}');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('★★ busy 时 disabled;上膛时多一个 span 显示 askLabel;三句词全部由调用点给', () => {
|
|
57
|
+
expect(ROW).toContain('const busy = stop?.busy === true;');
|
|
58
|
+
expect(ROW).toContain('disabled={busy}');
|
|
59
|
+
expect(ROW).toContain('<span className="wb-longTaskStopLabel">{stop.askLabel}</span>');
|
|
60
|
+
expect(ROW).toContain('aria-label={armed ? stop.armedLabel ?? stop.askLabel : stop.label}');
|
|
61
|
+
expect(ROW).toContain('<IconStopFillRegular size={12} />');
|
|
62
|
+
expect(ROW).toContain('type="button"');
|
|
63
|
+
expect(ROW).not.toContain('Translate');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('★★ failed 非空 ⇒ 在 problem 那行后面再画一行(wb-longTaskStopWhy)', () => {
|
|
67
|
+
const problem = ROW.indexOf('className="wb-longTaskProblem"');
|
|
68
|
+
const why = ROW.indexOf('className="wb-longTaskStopWhy"');
|
|
69
|
+
|
|
70
|
+
expect(ROW).toContain("const stopWhy = stop?.failed ?? '';");
|
|
71
|
+
expect(ROW).toContain('className="wb-longTaskStopWhy">{stopWhy}');
|
|
72
|
+
expect(problem).toBeGreaterThan(0);
|
|
73
|
+
expect(why).toBeGreaterThan(problem);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('★★ 没有 stop 的行一个像素都不变:既要的规则一个字没动,新规则也只在带钮的行上起作用', () => {
|
|
77
|
+
expect(CSS).toContain('.wb-longTaskHeadline {\n margin: 0;');
|
|
78
|
+
expect(CSS).toContain('.wb-longTaskLink {\n flex: none;\n}');
|
|
79
|
+
expect(CSS).toContain('.wb-longTaskHead {');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('两按停止钮:样式跟 dsh 那颗钮同款(组件自带,同目录一份 .css)', () => {
|
|
84
|
+
it('★★ 四个类都在同目录那份 .css 里', () => {
|
|
85
|
+
for (const cls of [
|
|
86
|
+
'.wb-longTaskStop {',
|
|
87
|
+
'.wb-longTaskStopArmed,',
|
|
88
|
+
'.wb-longTaskStopLabel {',
|
|
89
|
+
'.wb-longTaskStopWhy {',
|
|
90
|
+
]) {
|
|
91
|
+
expect(CSS).toContain(cls);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('★★ 上膛变宽(width: auto),取值照 dsh:error 45% 边框 + 12% 底 + gap 4 + padding 0 7px', () => {
|
|
96
|
+
expect(CSS).toMatch(/\.wb-longTaskStopArmed[\s\S]*width: auto/);
|
|
97
|
+
expect(CSS).toContain('color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent)');
|
|
98
|
+
expect(CSS).toContain('color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)');
|
|
99
|
+
expect(CSS).toContain('gap: var(--wb-len-4)');
|
|
100
|
+
expect(CSS).toContain('padding: 0 var(--wb-len-7)');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('★★ 上膛那颗字 11px / 18px;失败那行 error 色', () => {
|
|
104
|
+
expect(CSS).toContain('font-size: var(--dsw-font-xxxs-11-font-size)');
|
|
105
|
+
expect(CSS).toContain('line-height: var(--wb-line-18)');
|
|
106
|
+
expect(CSS).toMatch(/\.wb-longTaskStopWhy \{[\s\S]*--dsw-alias-state-error-primary/);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('★ 一格注释都没有,颜色不写字面值(尺寸走 --wb-len-*)', () => {
|
|
110
|
+
expect(CSS).not.toContain('/*');
|
|
111
|
+
expect(CSS).not.toContain('#');
|
|
112
|
+
expect(CSS).toContain('var(--wb-len-20)');
|
|
113
|
+
expect(CSS).not.toMatch(/(^|[^a-z-])rgb\(/);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -4,10 +4,16 @@ import type { UnitManifest } from '../api/unit.js';
|
|
|
4
4
|
import type { CapabilityPayload } from '../api/workbench-contract.js';
|
|
5
5
|
import type { Dictionaries } from '../i18n/index.js';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* 面板要跳去的一格:只用 `kind` 说去哪,具体负载由各 unit 自己约定。
|
|
9
|
+
*/
|
|
7
10
|
export interface PanelStep {
|
|
8
11
|
readonly kind: string;
|
|
9
12
|
}
|
|
10
13
|
|
|
14
|
+
/**
|
|
15
|
+
* 交给面板渲染的宿主世界:工作区与会话快照、装着的 unit、面板开关、能力表与当前选中。
|
|
16
|
+
*/
|
|
11
17
|
export interface SuiteWorld {
|
|
12
18
|
readonly workspaces: WorkspaceSnapshot;
|
|
13
19
|
readonly sessions: SessionsSnapshot;
|
|
@@ -20,6 +26,9 @@ export interface SuiteWorld {
|
|
|
20
26
|
};
|
|
21
27
|
}
|
|
22
28
|
|
|
29
|
+
/**
|
|
30
|
+
* 面板视图的统一 prop:一份世界快照 + 刷新令牌 + 四个通知回调 + 翻译函数。
|
|
31
|
+
*/
|
|
23
32
|
export interface BoardModuleProps {
|
|
24
33
|
readonly world: SuiteWorld;
|
|
25
34
|
readonly refreshToken: number;
|
|
@@ -30,16 +39,25 @@ export interface BoardModuleProps {
|
|
|
30
39
|
readonly t: Translate;
|
|
31
40
|
}
|
|
32
41
|
|
|
42
|
+
/**
|
|
43
|
+
* 一张卡报给宿主的摘要:此刻在不在刷新、上次读到是哪个时刻。
|
|
44
|
+
*/
|
|
33
45
|
export interface ModuleSummary {
|
|
34
46
|
readonly refreshing: boolean;
|
|
35
47
|
readonly at: number | null;
|
|
36
48
|
}
|
|
37
49
|
|
|
50
|
+
/**
|
|
51
|
+
* unit 的一个子步骤:标题文案键 + 渲染这件视图的组件。
|
|
52
|
+
*/
|
|
38
53
|
export interface UnitStep {
|
|
39
54
|
readonly titleKey: string;
|
|
40
55
|
readonly View: (props: BoardModuleProps) => ReactNode;
|
|
41
56
|
}
|
|
42
57
|
|
|
58
|
+
/**
|
|
59
|
+
* 一个面板单元的注册面:id、标题键、排序、视图,可带一组子步骤。
|
|
60
|
+
*/
|
|
43
61
|
export interface BoardModule {
|
|
44
62
|
readonly id: string;
|
|
45
63
|
readonly titleKey: string;
|
|
@@ -48,6 +66,9 @@ export interface BoardModule {
|
|
|
48
66
|
readonly steps?: Readonly<Record<string, UnitStep>>;
|
|
49
67
|
}
|
|
50
68
|
|
|
69
|
+
/**
|
|
70
|
+
* 模块在浏览器侧交出来的那份面:卡片、子步骤、自己的字典,以及审批渲染。
|
|
71
|
+
*/
|
|
51
72
|
export interface UnitClientFace {
|
|
52
73
|
readonly unit: string;
|
|
53
74
|
readonly card?: (props: BoardModuleProps) => ReactNode;
|
|
@@ -61,15 +82,24 @@ export interface UnitClientFace {
|
|
|
61
82
|
| undefined;
|
|
62
83
|
}
|
|
63
84
|
|
|
85
|
+
/**
|
|
86
|
+
* 带着自己 manifest 的模块面(外壳按 unit 认领时用)。
|
|
87
|
+
*/
|
|
64
88
|
export interface UnitOwnedClientFace extends UnitClientFace {
|
|
65
89
|
readonly manifest: UnitManifest;
|
|
66
90
|
}
|
|
67
91
|
|
|
92
|
+
/**
|
|
93
|
+
* 一次审批要看的输入:工具名,与它这次收到的参数。
|
|
94
|
+
*/
|
|
68
95
|
export interface ApprovalInput {
|
|
69
96
|
readonly tool: string;
|
|
70
97
|
readonly args: Readonly<Record<string, unknown>>;
|
|
71
98
|
}
|
|
72
99
|
|
|
100
|
+
/**
|
|
101
|
+
* 模块注册进外壳的那个口:注册一份面(拿回注销函数)、列出已装 unit。
|
|
102
|
+
*/
|
|
73
103
|
export interface UnitClientApi {
|
|
74
104
|
registerUnit(face: UnitClientFace): () => void;
|
|
75
105
|
manifests(): readonly UnitManifest[];
|
package/src/components/icons.tsx
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { h, type ReactNode } from '../lib/react.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 自绘图标的契约:只给边长像素。
|
|
5
|
+
*/
|
|
3
6
|
export interface IconProps {
|
|
4
7
|
size?: number;
|
|
5
8
|
}
|
|
@@ -31,6 +34,11 @@ function Shell({
|
|
|
31
34
|
);
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
/**
|
|
38
|
+
* 会话图标:一枚对话气泡,dsh 的图标表里没有,留给我们自己用;默认 16px。
|
|
39
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
40
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
41
|
+
*/
|
|
34
42
|
export function IconConversation({ size = 16 }: IconProps) {
|
|
35
43
|
return (
|
|
36
44
|
<Shell size={size} strokeWidth={1.3}>
|
|
@@ -43,6 +51,11 @@ export function IconConversation({ size = 16 }: IconProps) {
|
|
|
43
51
|
);
|
|
44
52
|
}
|
|
45
53
|
|
|
54
|
+
/**
|
|
55
|
+
* 品牌标:侧栏顶上那枚工作台方块标;默认 24px(它是品牌物,别拿它当通用图标)。
|
|
56
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
57
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
58
|
+
*/
|
|
46
59
|
export function IconBrandMark({ size = 24 }: IconProps) {
|
|
47
60
|
return (
|
|
48
61
|
<Shell size={size} strokeWidth={1.6} viewBox="0 0 24 24">
|
|
@@ -56,6 +69,11 @@ export function IconBrandMark({ size = 24 }: IconProps) {
|
|
|
56
69
|
);
|
|
57
70
|
}
|
|
58
71
|
|
|
72
|
+
/**
|
|
73
|
+
* opencli 的标:包类型那一格用它;颜色写死的品牌物,不跟主题走。默认 16px。
|
|
74
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
75
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
76
|
+
*/
|
|
59
77
|
export function IconOpencli({ size = 16 }: IconProps) {
|
|
60
78
|
return (
|
|
61
79
|
<Shell size={size} viewBox="0 0 64 64">
|
|
@@ -83,6 +101,11 @@ export function IconOpencli({ size = 16 }: IconProps) {
|
|
|
83
101
|
);
|
|
84
102
|
}
|
|
85
103
|
|
|
104
|
+
/**
|
|
105
|
+
* npm 的标:包类型那一格用它;保留品牌红,不跟主题走。默认 16px。
|
|
106
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
107
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
108
|
+
*/
|
|
86
109
|
export function IconNpm({ size = 16 }: IconProps) {
|
|
87
110
|
return (
|
|
88
111
|
<Shell size={size} viewBox="0 0 1024 1024">
|
|
@@ -94,6 +117,11 @@ export function IconNpm({ size = 16 }: IconProps) {
|
|
|
94
117
|
);
|
|
95
118
|
}
|
|
96
119
|
|
|
120
|
+
/**
|
|
121
|
+
* 四宫格:"模块"这个概念的通用单色图标(侧栏、面板那颗钮、市场节的标题);默认 16px。
|
|
122
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
123
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
124
|
+
*/
|
|
97
125
|
export function IconModules({ size = 16 }: IconProps) {
|
|
98
126
|
return (
|
|
99
127
|
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
@@ -105,6 +133,11 @@ export function IconModules({ size = 16 }: IconProps) {
|
|
|
105
133
|
);
|
|
106
134
|
}
|
|
107
135
|
|
|
136
|
+
/**
|
|
137
|
+
* 模块类型标:渐变方块 + 白四宫格,用在"这是个模块"的行首;品牌物,颜色不跟主题走。默认 16px。
|
|
138
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
139
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
140
|
+
*/
|
|
108
141
|
export function IconModuleMark({ size = 16 }: IconProps) {
|
|
109
142
|
return (
|
|
110
143
|
<Shell size={size} viewBox="0 0 24 24">
|
|
@@ -124,6 +157,11 @@ export function IconModuleMark({ size = 16 }: IconProps) {
|
|
|
124
157
|
);
|
|
125
158
|
}
|
|
126
159
|
|
|
160
|
+
/**
|
|
161
|
+
* 面板 / 卡片那类的图标:整屏与柱状那种形状,给"面板"这一档用;默认 16px。
|
|
162
|
+
* @param props.size - 边长像素,同时给 `width` 与 `height`。
|
|
163
|
+
* @returns 一枚 `aria-hidden` 的 svg。
|
|
164
|
+
*/
|
|
127
165
|
export function IconPanelScreen({ size = 16 }: IconProps) {
|
|
128
166
|
return (
|
|
129
167
|
<svg
|
package/src/config/constants.ts
CHANGED
|
@@ -1,79 +1,122 @@
|
|
|
1
|
+
/** 外壳插件的包名:浏览器模块表与宿主按它注册、认领这枚插件。 */
|
|
1
2
|
export const PLUGIN_ID = "@dsh-workbench/core";
|
|
2
3
|
|
|
4
|
+
/** 与外壳同批发布的兄弟包名:`release.ts` 用它判一版三包是否都已在源上。 */
|
|
3
5
|
export const RELEASE_SIBLINGS = [
|
|
4
6
|
"@dsh-workbench/shared",
|
|
5
7
|
"@dsh-workbench/module-tools",
|
|
6
8
|
] as const;
|
|
7
9
|
|
|
10
|
+
/** 外壳宿主 HTTP API 的根前缀;prefs / actions / provision 等路由都挂在它下面。 */
|
|
8
11
|
export const API_PREFIX = "/workbench/api";
|
|
9
12
|
|
|
13
|
+
/** 模块偏好读写的路由前缀,挂在外壳 API 下:走写通道,拒写回 write-refused。 */
|
|
10
14
|
export const PREFS_PREFIX = `${API_PREFIX}/prefs`;
|
|
11
15
|
|
|
16
|
+
/** 事实(facts)SSE 事件流的端点路径;前端 `EventSource` 按它带 `since` 游标续传。 */
|
|
12
17
|
export const EVENTS_PATH = "/workbench/events";
|
|
18
|
+
/** 写动作的路由前缀,挂在外壳 API 下:模块的写通道 POST 到这里。 */
|
|
13
19
|
export const ACTIONS_PREFIX = `${API_PREFIX}/actions`;
|
|
14
20
|
|
|
21
|
+
/** 机器供给(provision)的路由前缀:只收 POST,装机时用它铺一份运行环境。 */
|
|
15
22
|
export const PROVISION_PREFIX = `${API_PREFIX}/provision`;
|
|
16
23
|
|
|
24
|
+
/** 面板运行态上报的路径段:崩溃与卡片收尾分别 POST 到 `panel-state/crash`、`panel-state/cards`。 */
|
|
17
25
|
export const PANEL_STATE_PATH = "panel-state";
|
|
18
26
|
|
|
27
|
+
/** DIY 调试动作的路径段;宿主按它登记 `/workbench/api/diy-debug` 前缀。 */
|
|
19
28
|
export const DIY_DEBUG_PATH = "diy-debug";
|
|
29
|
+
/** 调试动作的子路径(`diy-debug/act`);仓内暂无调用点,动作现走 `DIY_DEBUG_SERVICE`。 */
|
|
20
30
|
export const DIY_DEBUG_ACT_PATH = `${DIY_DEBUG_PATH}/act`;
|
|
21
31
|
|
|
32
|
+
/** DIY 录制交接的路径段;宿主按它登记 `/workbench/api/diy-record` 前缀。 */
|
|
22
33
|
export const DIY_RECORD_PATH = "diy-record";
|
|
34
|
+
/** 录制动作的子路径(`diy-record/act`);仓内暂无调用点,录制现走 `DIY_RECORD_SERVICE`。 */
|
|
23
35
|
export const DIY_RECORD_ACT_PATH = `${DIY_RECORD_PATH}/act`;
|
|
24
36
|
|
|
37
|
+
/** 面板运行态的路由前缀,挂在外壳 API 下:上报口用它,拒报回 report-refused。 */
|
|
25
38
|
export const PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
|
|
26
39
|
|
|
40
|
+
/** 钉住的 opencli 插件版本:`opencli-runtime` 按它校验、取那一份。 */
|
|
27
41
|
export const OPENCLI_PIN = "1.8.8";
|
|
28
42
|
|
|
43
|
+
/** 缺陷看板套件的 dsh 服务名(`workbenchCodingIssues`):套件照它登记自己那份服务。 */
|
|
29
44
|
export const CODING_ISSUES_SERVICE = "workbenchCodingIssues";
|
|
30
45
|
|
|
46
|
+
/** 面板套件的 dsh 服务名(`workbenchPanels`):宿主经它取套件公布的清单与订阅。 */
|
|
31
47
|
export const PANELS_SERVICE = "workbenchPanels";
|
|
32
48
|
|
|
49
|
+
/** 单元花名册服务的 dsh 服务名(`workbenchUnits`):模块经它认领自己的单元。 */
|
|
33
50
|
export const UNITS_SERVICE = "workbenchUnits";
|
|
34
51
|
|
|
52
|
+
/** 面板运行态服务的 dsh 服务名(`workbenchPanelState`):宿主注册,读口按它取。 */
|
|
35
53
|
export const PANEL_STATE_SERVICE = "workbenchPanelState";
|
|
36
54
|
|
|
55
|
+
/** DIY 调试约定服务的 dsh 服务名(`workbenchDiyDebug`):调试动作走它,不走 HTTP。 */
|
|
37
56
|
export const DIY_DEBUG_SERVICE = "workbenchDiyDebug";
|
|
38
57
|
|
|
58
|
+
/** DIY 录制交接服务的 dsh 服务名(`workbenchDiyRecord`):`diy-acts.ts` 经它收发录制三拍。 */
|
|
39
59
|
export const DIY_RECORD_SERVICE = "workbenchDiyRecord";
|
|
40
60
|
|
|
61
|
+
/** 会话投影服务的 dsh 服务名(`sessionProjections`):宿主经 `stateOf(session, 'agentPreset')` 读那一档。 */
|
|
62
|
+
export const SESSION_PROJECTIONS_SERVICE = "sessionProjections";
|
|
63
|
+
|
|
64
|
+
/** 面板清单一次取回的行数上限(条):外部模块拿它当 opencli `--pageSize`。 */
|
|
41
65
|
export const PANEL_LIST_LIMIT = 50;
|
|
42
66
|
|
|
67
|
+
/** 单次 opencli 调用的默认超时(毫秒);调用点没传 `timeoutMs` 时按它算。 */
|
|
43
68
|
export const OPENCLI_TIMEOUT_MS = 120_000;
|
|
44
69
|
|
|
70
|
+
/** 同时最多几条 opencli 在跑(条):`opencli.ts` 超出就排队。 */
|
|
45
71
|
export const OPENCLI_MAX_CONCURRENT = 4;
|
|
46
72
|
|
|
73
|
+
/** 启动预热站点那一跳的超时(毫秒);超时按未热对待,不挡面板。 */
|
|
47
74
|
export const WARM_TIMEOUT_MS = 20_000;
|
|
48
75
|
|
|
76
|
+
/** 装 / 卸模块包的超时(毫秒):pnpm 与取包内容都按它算。 */
|
|
49
77
|
export const INSTALL_TIMEOUT_MS = 300_000;
|
|
50
78
|
|
|
79
|
+
/** 查 registry 版本那一次请求的超时(毫秒)。 */
|
|
51
80
|
export const VERSION_CHECK_TIMEOUT_MS = 10_000;
|
|
52
81
|
|
|
82
|
+
/** 版本查询结果的缓存有效期(毫秒):期内不发第二次请求。 */
|
|
53
83
|
export const VERSION_CHECK_TTL_MS = 600_000;
|
|
54
84
|
|
|
85
|
+
/** 单元探测结果的缓存有效期(毫秒)。 */
|
|
55
86
|
export const PROBE_TTL_MS = 30_000;
|
|
56
87
|
|
|
88
|
+
/** 加载态至少显示多久(毫秒):一瞬完成的读写也得让用户看见那一下。 */
|
|
57
89
|
export const MIN_BUSY_MS = 500;
|
|
58
90
|
|
|
91
|
+
/** 工具读出来的值交给面板后的保留时长(毫秒):过期就不再算这一拍。 */
|
|
59
92
|
export const HANDOFF_TTL_MS = 15_000;
|
|
60
93
|
|
|
94
|
+
/** 跑本地 git 命令的超时(毫秒);短于对外的 `OPENCLI_TIMEOUT_MS`。 */
|
|
61
95
|
export const GIT_TIMEOUT_MS = 10_000;
|
|
62
96
|
|
|
97
|
+
/** 面板轮询事实的间隔(毫秒):SSE 断了走这条兜底轮询。 */
|
|
63
98
|
export const PANEL_POLL_MS = 2000;
|
|
64
99
|
|
|
100
|
+
/** 没起中文名的工作区默认标题:左栏按它分组、显示。 */
|
|
65
101
|
export const DEFAULT_WORKSPACE_TITLE = "default-workspace";
|
|
66
102
|
|
|
103
|
+
/** 记住当前项目的 localStorage 键。 */
|
|
67
104
|
export const STORAGE_KEY_PROJECT = "dsh-workbench.project";
|
|
68
105
|
|
|
106
|
+
/** 记住右栏展开与否的 localStorage 键。 */
|
|
69
107
|
export const STORAGE_KEY_RIGHTBAR = "dsh-workbench.rightbar.expanded";
|
|
70
108
|
|
|
109
|
+
/** 记住右栏当前列的 localStorage 键。 */
|
|
71
110
|
export const STORAGE_KEY_RIGHTBAR_COLUMN = "dsh-workbench.rightbar.column";
|
|
72
111
|
|
|
112
|
+
/** 记住右栏宽度(像素数字的字符串)的 localStorage 键。 */
|
|
73
113
|
export const STORAGE_KEY_RIGHTBAR_WIDTH = "dsh-workbench.rightbar.width";
|
|
74
114
|
|
|
115
|
+
/** 右栏宽度达到或超过多少像素就按全屏对待(阈值,像素)。 */
|
|
75
116
|
export const RIGHTBAR_FULLSCREEN_WIDTH = 768;
|
|
76
117
|
|
|
118
|
+
/** dsh i18n 的命名空间:词表都注册在它下面,`ctx.locale.register` / `bind` 按它取。 */
|
|
77
119
|
export const LOCALE_NS = "workbench";
|
|
78
120
|
|
|
121
|
+
/** 外壳支持的语言标识,顺序即回退顺序:首项是基准,其余词表必须与它逐键同构。 */
|
|
79
122
|
export const LOCALES = ["zh", "en"] as const;
|
package/src/config/storage.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** 读 localStorage 里的一段文本;没有这个键、或存储不可用(隐私模式)时返回 null。 */
|
|
1
2
|
export function readText(key: string): string | null {
|
|
2
3
|
try {
|
|
3
4
|
return window.localStorage.getItem(key);
|
|
@@ -6,6 +7,7 @@ export function readText(key: string): string | null {
|
|
|
6
7
|
}
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
/** 写一段文本进 localStorage;`value` 为 null 时删掉这个键,写不进去就静默作罢。 */
|
|
9
11
|
export function writeText(key: string, value: string | null): void {
|
|
10
12
|
try {
|
|
11
13
|
if (value === null) window.localStorage.removeItem(key);
|
|
@@ -14,12 +16,14 @@ export function writeText(key: string, value: string | null): void {
|
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
/** 读一个布尔开关:键不存在时返回 `fallback`,只有存进去的 `'true'` 算真。 */
|
|
17
20
|
export function readFlag(key: string, fallback: boolean): boolean {
|
|
18
21
|
const raw = readText(key);
|
|
19
22
|
if (raw === null) return fallback;
|
|
20
23
|
return raw === 'true';
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
/** 把一个布尔开关写进 localStorage(存 `'true'` / `'false'`);失败静默。 */
|
|
23
27
|
export function writeFlag(key: string, value: boolean): void {
|
|
24
28
|
writeText(key, value ? 'true' : 'false');
|
|
25
29
|
}
|