@dsh-workbench/core 0.3.7 → 0.3.8
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/client.js
CHANGED
|
@@ -559,6 +559,16 @@ window.__ModuleLoader__.load({
|
|
|
559
559
|
return "idle";
|
|
560
560
|
}
|
|
561
561
|
/**
|
|
562
|
+
* 这一趟还在不在跑(`running` 与 `needs-login` 都算)。
|
|
563
|
+
* 卡片要判"这一行要不要摆停止钮""这套环境里有没有活着的跑"时用这个 —— **不是** `longTaskDot`:
|
|
564
|
+
* 那一件是状态点的**长相**(四档),归 `LongTaskRow` 自己用,不该被调用点拿去当判据。
|
|
565
|
+
* @param status 长任务的五种态。
|
|
566
|
+
* @returns 在跑 `true`;成功 / 失败 / 用户按停都是 `false`。
|
|
567
|
+
*/
|
|
568
|
+
function longTaskIsLive(status) {
|
|
569
|
+
return status === "running" || status === "needs-login";
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
562
572
|
* 算停止钮现在在哪一档。
|
|
563
573
|
* @param state armed = 已经按过第一下、在等第二下;busy = 停止请求已经在飞。
|
|
564
574
|
* @returns busy 优先(在飞时按不动),其次 armed,否则 idle。
|
|
@@ -10837,17 +10847,19 @@ window.__ModuleLoader__.load({
|
|
|
10837
10847
|
setStopping((current) => current === id ? null : current);
|
|
10838
10848
|
}
|
|
10839
10849
|
}, [send]);
|
|
10840
|
-
const every = longTaskPollMs(runs.some((run) =>
|
|
10850
|
+
const every = longTaskPollMs(runs.some((run) => longTaskIsLive(run.status)), options.pollMs);
|
|
10841
10851
|
useEffect(() => {
|
|
10842
10852
|
if (!enabled) return void 0;
|
|
10843
10853
|
const timer = setInterval(() => setTick((count) => count + 1), every);
|
|
10844
10854
|
return () => clearInterval(timer);
|
|
10845
10855
|
}, [enabled, every]);
|
|
10856
|
+
const refresh = useCallback(() => setTick((count) => count + 1), []);
|
|
10846
10857
|
return {
|
|
10847
10858
|
runs,
|
|
10848
10859
|
stop,
|
|
10849
10860
|
stopping,
|
|
10850
|
-
stopFailed: write.failed
|
|
10861
|
+
stopFailed: write.failed,
|
|
10862
|
+
refresh
|
|
10851
10863
|
};
|
|
10852
10864
|
}
|
|
10853
10865
|
//#endregion
|
|
@@ -11103,6 +11115,7 @@ window.__ModuleLoader__.load({
|
|
|
11103
11115
|
...context_chips_exports
|
|
11104
11116
|
},
|
|
11105
11117
|
lib: {
|
|
11118
|
+
longTaskIsLive,
|
|
11106
11119
|
MIN_BUSY_MS: 500,
|
|
11107
11120
|
blockerOfCapability,
|
|
11108
11121
|
blockerOfError,
|
|
@@ -552,6 +552,16 @@ function longTaskDot(status) {
|
|
|
552
552
|
return "idle";
|
|
553
553
|
}
|
|
554
554
|
/**
|
|
555
|
+
* 这一趟还在不在跑(`running` 与 `needs-login` 都算)。
|
|
556
|
+
* 卡片要判"这一行要不要摆停止钮""这套环境里有没有活着的跑"时用这个 —— **不是** `longTaskDot`:
|
|
557
|
+
* 那一件是状态点的**长相**(四档),归 `LongTaskRow` 自己用,不该被调用点拿去当判据。
|
|
558
|
+
* @param status 长任务的五种态。
|
|
559
|
+
* @returns 在跑 `true`;成功 / 失败 / 用户按停都是 `false`。
|
|
560
|
+
*/
|
|
561
|
+
function longTaskIsLive(status) {
|
|
562
|
+
return status === "running" || status === "needs-login";
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
555
565
|
* 算停止钮现在在哪一档。
|
|
556
566
|
* @param state armed = 已经按过第一下、在等第二下;busy = 停止请求已经在飞。
|
|
557
567
|
* @returns busy 优先(在飞时按不动),其次 armed,否则 idle。
|
|
@@ -10830,17 +10840,19 @@ function useLongTask(options) {
|
|
|
10830
10840
|
setStopping((current) => current === id ? null : current);
|
|
10831
10841
|
}
|
|
10832
10842
|
}, [send]);
|
|
10833
|
-
const every = longTaskPollMs(runs.some((run) =>
|
|
10843
|
+
const every = longTaskPollMs(runs.some((run) => longTaskIsLive(run.status)), options.pollMs);
|
|
10834
10844
|
useEffect(() => {
|
|
10835
10845
|
if (!enabled) return void 0;
|
|
10836
10846
|
const timer = setInterval(() => setTick((count) => count + 1), every);
|
|
10837
10847
|
return () => clearInterval(timer);
|
|
10838
10848
|
}, [enabled, every]);
|
|
10849
|
+
const refresh = useCallback(() => setTick((count) => count + 1), []);
|
|
10839
10850
|
return {
|
|
10840
10851
|
runs,
|
|
10841
10852
|
stop,
|
|
10842
10853
|
stopping,
|
|
10843
|
-
stopFailed: write.failed
|
|
10854
|
+
stopFailed: write.failed,
|
|
10855
|
+
refresh
|
|
10844
10856
|
};
|
|
10845
10857
|
}
|
|
10846
10858
|
//#endregion
|
|
@@ -11096,6 +11108,7 @@ var kit = {
|
|
|
11096
11108
|
...context_chips_exports
|
|
11097
11109
|
},
|
|
11098
11110
|
lib: {
|
|
11111
|
+
longTaskIsLive,
|
|
11099
11112
|
MIN_BUSY_MS: 500,
|
|
11100
11113
|
blockerOfCapability,
|
|
11101
11114
|
blockerOfError,
|
package/dist/client/index.js
CHANGED
|
@@ -555,6 +555,16 @@ function longTaskDot(status) {
|
|
|
555
555
|
return "idle";
|
|
556
556
|
}
|
|
557
557
|
/**
|
|
558
|
+
* 这一趟还在不在跑(`running` 与 `needs-login` 都算)。
|
|
559
|
+
* 卡片要判"这一行要不要摆停止钮""这套环境里有没有活着的跑"时用这个 —— **不是** `longTaskDot`:
|
|
560
|
+
* 那一件是状态点的**长相**(四档),归 `LongTaskRow` 自己用,不该被调用点拿去当判据。
|
|
561
|
+
* @param status 长任务的五种态。
|
|
562
|
+
* @returns 在跑 `true`;成功 / 失败 / 用户按停都是 `false`。
|
|
563
|
+
*/
|
|
564
|
+
function longTaskIsLive(status) {
|
|
565
|
+
return status === "running" || status === "needs-login";
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
558
568
|
* 算停止钮现在在哪一档。
|
|
559
569
|
* @param state armed = 已经按过第一下、在等第二下;busy = 停止请求已经在飞。
|
|
560
570
|
* @returns busy 优先(在飞时按不动),其次 armed,否则 idle。
|
|
@@ -10833,17 +10843,19 @@ function useLongTask(options) {
|
|
|
10833
10843
|
setStopping((current) => current === id ? null : current);
|
|
10834
10844
|
}
|
|
10835
10845
|
}, [send]);
|
|
10836
|
-
const every = longTaskPollMs(runs.some((run) =>
|
|
10846
|
+
const every = longTaskPollMs(runs.some((run) => longTaskIsLive(run.status)), options.pollMs);
|
|
10837
10847
|
useEffect(() => {
|
|
10838
10848
|
if (!enabled) return void 0;
|
|
10839
10849
|
const timer = setInterval(() => setTick((count) => count + 1), every);
|
|
10840
10850
|
return () => clearInterval(timer);
|
|
10841
10851
|
}, [enabled, every]);
|
|
10852
|
+
const refresh = useCallback(() => setTick((count) => count + 1), []);
|
|
10842
10853
|
return {
|
|
10843
10854
|
runs,
|
|
10844
10855
|
stop,
|
|
10845
10856
|
stopping,
|
|
10846
|
-
stopFailed: write.failed
|
|
10857
|
+
stopFailed: write.failed,
|
|
10858
|
+
refresh
|
|
10847
10859
|
};
|
|
10848
10860
|
}
|
|
10849
10861
|
//#endregion
|
|
@@ -11099,6 +11111,7 @@ var kit = {
|
|
|
11099
11111
|
...context_chips_exports
|
|
11100
11112
|
},
|
|
11101
11113
|
lib: {
|
|
11114
|
+
longTaskIsLive,
|
|
11102
11115
|
MIN_BUSY_MS: 500,
|
|
11103
11116
|
blockerOfCapability,
|
|
11104
11117
|
blockerOfError,
|
|
@@ -9,7 +9,7 @@ import * as capabilityGateModule from '../shared/hooks/use-capability-gate';
|
|
|
9
9
|
import * as unitBoardModule from '../shared/hooks/use-unit-board';
|
|
10
10
|
import * as visibleBusyModule from '../shared/hooks/use-visible-busy';
|
|
11
11
|
import * as blockerStateModule from '../shared/components/BlockerState';
|
|
12
|
-
import { ActivityAction, ActivityBlock, ActivityLine, ApprovalDetail, ApprovalPlan, Card, CardAnchor, CardBoundary, CardHead, CenteredState, ChoiceGroup, ConfirmBar, EmptyState, Field, Form, FormActions, FormRow, FormRows, IconBrandMark, IconConversation, IconModuleMark, IconNpm, IconOpencli, IconPanelScreen, Link, LongTaskRow, Note, Row, Rows, SaveBar, SelectField, SettingsSection, SkeletonRows, Spinner, Stack, StateBlock, TextField, apiGet, apiPost, blockerOfCapability, blockerOfError, cardIdOf, cx, defaultSelectFilter, duplicateKeysOf, errorReasonOf, excerpt, filterSelectOptions, firstProblemOf, formFirstProblemOf, formValuesOf, holdBusy, parseJsonLoose, parseLocalTimestamp, readText, relativeTime, relativeTimeAgo, relativeTimeBucket, relativeTimeCompact, revealFirstProblem, searchTextOf, selectCursorValue, selectEntries, shortenPath, stepSelectCursor, writeText } from '@dsh-workbench/shared';
|
|
12
|
+
import { ActivityAction, ActivityBlock, ActivityLine, ApprovalDetail, ApprovalPlan, Card, CardAnchor, CardBoundary, CardHead, CenteredState, ChoiceGroup, ConfirmBar, EmptyState, Field, Form, FormActions, FormRow, FormRows, IconBrandMark, IconConversation, IconModuleMark, IconNpm, IconOpencli, IconPanelScreen, Link, LongTaskRow, longTaskIsLive, Note, Row, Rows, SaveBar, SelectField, SettingsSection, SkeletonRows, Spinner, Stack, StateBlock, TextField, apiGet, apiPost, blockerOfCapability, blockerOfError, cardIdOf, cx, defaultSelectFilter, duplicateKeysOf, errorReasonOf, excerpt, filterSelectOptions, firstProblemOf, formFirstProblemOf, formValuesOf, holdBusy, parseJsonLoose, parseLocalTimestamp, readText, relativeTime, relativeTimeAgo, relativeTimeBucket, relativeTimeCompact, revealFirstProblem, searchTextOf, selectCursorValue, selectEntries, shortenPath, stepSelectCursor, writeText } from '@dsh-workbench/shared';
|
|
13
13
|
export declare const kit: {
|
|
14
14
|
hooks: {
|
|
15
15
|
heldPhase(phase: visibleBusyModule.HeldPhase, refreshing: boolean): visibleBusyModule.HeldPhase;
|
|
@@ -102,6 +102,7 @@ export declare const kit: {
|
|
|
102
102
|
apiPost: typeof apiPost;
|
|
103
103
|
};
|
|
104
104
|
lib: {
|
|
105
|
+
longTaskIsLive: typeof longTaskIsLive;
|
|
105
106
|
MIN_BUSY_MS: number;
|
|
106
107
|
blockerOfCapability: typeof blockerOfCapability;
|
|
107
108
|
blockerOfError: typeof blockerOfError;
|
|
@@ -3,12 +3,15 @@ import { type LongTaskStatus, type WriteOutcome } from '@dsh-workbench/shared';
|
|
|
3
3
|
* 这一单元的长任务清单与停止口:`runs` 是这次读交回的那一批(读数还没回来时是空数组);
|
|
4
4
|
* `stop(id)` 请外壳停某一趟 —— 回执没成就带回一句人话(调用点自己决定说不说);
|
|
5
5
|
* `stopping` 是正在请求停止的那一趟 id(没有就是 `null`),`stopFailed` 是上一次停止请求失败那句话(没有就是 `null`)。
|
|
6
|
+
* `refresh()` 让这一格**立刻**重读一次(不必等下一拍轮询)—— 自己写完/发起完之后用它,
|
|
7
|
+
* 别去拼读口路由、也别为一个读数去碰事实通道。
|
|
6
8
|
*/
|
|
7
9
|
export interface LongTaskFeed<T> {
|
|
8
10
|
readonly runs: readonly T[];
|
|
9
11
|
stop(id: string): Promise<WriteOutcome<unknown>>;
|
|
10
12
|
readonly stopping: string | null;
|
|
11
13
|
readonly stopFailed: string | null;
|
|
14
|
+
refresh(): void;
|
|
12
15
|
}
|
|
13
16
|
/**
|
|
14
17
|
* 卡片要轮询长任务那一行时调用:有在跑的(`running` / `needs-login`)按 `longTaskPollMs` 走快档、空闲走慢档;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "./icon.svg",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"access": "public"
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@dsh-workbench/shared": "0.3.
|
|
90
|
+
"@dsh-workbench/shared": "0.3.8"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|
|
@@ -105,7 +105,7 @@ h(Form<{ branch: string }>, {
|
|
|
105
105
|
|
|
106
106
|
**`ConfirmBar`** —— 「先问一句再动手」那一条(标题 / 说明 / 键值 / 失败那句 / 动作区一次收口):
|
|
107
107
|
键值走 `Rows` / `Row`、错走 `Note tone="problem"`、动作走 `FormActions` —— **别自己拼这四个槽**。
|
|
108
|
-
|
|
108
|
+
**要不要问归调用点**(`danger` 只标"破坏性")。口径见 ADR-0073。
|
|
109
109
|
|
|
110
110
|
怎么排(标签位置、错误态、尺寸)见 §5。
|
|
111
111
|
|
|
@@ -120,7 +120,7 @@ kit 的 hook 也分四个场合,**别自己 `useState` + `setTimeout` 造一
|
|
|
120
120
|
| "至少转一会儿"的忙态 | `useVisibleBusy`(投影那两件 `busyView` / `heldPhase`) |
|
|
121
121
|
| 一格**卡片**起步(gate + 忙 + 探针 + 上报 + blocker 一次叠好) | `useUnitBoard`(`read(gated)` 里自己调 `useApiResource`) |
|
|
122
122
|
| 只要一格的能力门 / 整张能力表 | `useCapabilityGate` / `useCapabilityMap` |
|
|
123
|
-
| 写(**别在组件里 `fetch`**) / 轮询长任务 | `useHostWrite` / `useLongTask`(画用 `LongTaskRow`
|
|
123
|
+
| 写(**别在组件里 `fetch`**) / 轮询长任务 | `useHostWrite` / `useLongTask`(画用 `LongTaskRow`;判「还在跑」`longTaskIsLive`、写完让这一格立刻重读 `refresh()`) |
|
|
124
124
|
|
|
125
125
|
取数那条链的图见 [LINKAGE.md](LINKAGE.md) §8,写通道与配置见 [PANEL.md](PANEL.md) §5。
|
|
126
126
|
|
|
@@ -131,8 +131,8 @@ kit 的 hook 也分四个场合,**别自己 `useState` + `setTimeout` 造一
|
|
|
131
131
|
它自己组 `[...extra, ...cancel, submit(primary)]`(提交钮永远在右;「一会在左一会在右」就是自己摆的结果);
|
|
132
132
|
其余口径(时机 / 第一处错误 / `busy` / `disabled`)看它的 JSDoc 与 ADR-0068 / ADR-0074。
|
|
133
133
|
|
|
134
|
-
`FormRows` + `FormRow` + `FormActions`
|
|
135
|
-
|
|
134
|
+
`FormRows` + `FormRow` + `FormActions` 留给**不是整张表单**的地方:单行(一格字段嵌在别处)、
|
|
135
|
+
非表单的一组动作(工具栏、卡头那几颗钮)—— 那里才自己拼这三件:
|
|
136
136
|
|
|
137
137
|
```tsx
|
|
138
138
|
h(FormRows, null,
|
|
@@ -145,7 +145,7 @@ h(FormRows, null,
|
|
|
145
145
|
- **`hint` 与 `problem` 二选一**:有错先显示错。
|
|
146
146
|
|
|
147
147
|
**错误态**:位置与长相归 `FormRow.problem` + 控件的 `invalid`;**算错的逻辑留在模块**(纯函数 + 文案,
|
|
148
|
-
交给 `FormField.validate`)—— **别指望外壳给校验引擎**(不做 `rules` / 异步 /
|
|
148
|
+
交给 `FormField.validate`)—— **别指望外壳给校验引擎**(不做 `rules` / 异步 / 联动),
|
|
149
149
|
**"提交过没有"与聚焦第一处错也归 `Form`**(别自己记布尔、别自己调 `revealFirstProblem`)。
|
|
150
150
|
|
|
151
151
|
**选择类用哪件**:候选多 / 要搜索 / 要分组 / 名单可能读不到 ⇒ `SelectField`;候选少、要一眼看全 / 多选 ⇒
|
|
@@ -172,7 +172,7 @@ h('form', …) // ← 裸 <form> / 手写行槽
|
|
|
172
172
|
- **`Link`** —— **唯一**的外链写法(`h(Link, { href, children })`):**别去掉箭头、别在文案里自带 `→`、
|
|
173
173
|
别手写 `<a>`**(判据红)。
|
|
174
174
|
- **`SettingsSection` / `Stack` / `BlockerState` / `Tip`** —— 一屏设置里的一节 / 竖排间距 / 阻断屏 /
|
|
175
|
-
Tooltip
|
|
175
|
+
Tooltip(只有图的地方**必须**有它或 `aria-label`);prop 看 `.d.ts`。
|
|
176
176
|
- **真机上造不出来的那几态**:拿你自己那份 `plugin.test.ts` 把五态各喂一遍(`check --only cards`
|
|
177
177
|
拿七种外壳侧输入各喂一遍,只问"退化得干不干净")。
|
|
178
178
|
- **图标** —— `IconPanelScreen` / `IconModuleMark` / `IconNpm` / `IconOpencli`;其余图形一律从 dsh 的
|
|
@@ -189,11 +189,10 @@ h('form', …) // ← 裸 <form> / 手写行槽
|
|
|
189
189
|
|
|
190
190
|
## 8 kit 里没有、但你确定要标准控件
|
|
191
191
|
|
|
192
|
-
**先问工具**:DIY 会话里调 `workbench_diy_components
|
|
193
|
-
回它的类型文件与声明)。工程域用 `dsh-wb-module check --only primitives`
|
|
192
|
+
**先问工具**:DIY 会话里调 `workbench_diy_components`(不填给清单;`name=Button` 回它的类型与声明)。工程域用 `dsh-wb-module check --only primitives`
|
|
194
193
|
(`--all` 全表 / `--json` 机器档)—— 分桶导出 + 与 kit 求交(`kit 里已有` 的优先用)+
|
|
195
194
|
该写进 `package.json` 的那两行;骨架默认已备好。
|
|
196
|
-
**要看某一件**:`--file <名字>`(`--files | grep
|
|
195
|
+
**要看某一件**:`--file <名字>`(`--files | grep <名字>`)。
|
|
197
196
|
|
|
198
197
|
```jsonc
|
|
199
198
|
"dsh": { "client": { "external": [ "@dsh-workbench/core/client", "@deepseek-ai/dsh-client-ui-primitives" ] } },
|