@dsh-workbench/shared 0.3.5 → 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/long-task.d.ts +33 -4
- package/dist/api/long-task.js +34 -2
- package/dist/components/FormRows.css +31 -0
- package/dist/components/LongTaskRow.css +52 -0
- package/dist/components/LongTaskRow.d.ts +18 -2
- package/dist/components/LongTaskRow.js +33 -5
- 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 +1 -0
- package/dist/i18n/en.js +2 -0
- package/dist/i18n/index.d.ts +3 -1
- package/dist/i18n/zh.d.ts +2 -0
- package/dist/i18n/zh.js +2 -0
- package/package.json +1 -1
- package/src/api/__tests__/long-task.test.ts +41 -1
- package/src/api/long-task.ts +46 -4
- package/src/components/FormRows.css +31 -0
- package/src/components/FormRows.test.tsx +71 -1
- package/src/components/LongTaskRow.css +52 -0
- package/src/components/LongTaskRow.tsx +59 -4
- package/src/components/__tests__/long-task-row.test.ts +115 -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 +1 -0
- package/src/i18n/en.ts +3 -0
- package/src/i18n/zh.ts +2 -0
package/dist/api/long-task.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 一条长任务的五种态;needs-login 与 running 一样算还没结束,stopped 是用户自己按停的。
|
|
3
3
|
*/
|
|
4
|
-
export type LongTaskStatus = 'running' | 'needs-login' | 'ok' | 'failed';
|
|
4
|
+
export type LongTaskStatus = 'running' | 'needs-login' | 'stopped' | 'ok' | 'failed';
|
|
5
5
|
/**
|
|
6
6
|
* 长任务步骤流里的一行:kind 定样式,登录那一步带 loginUrl 给用户去点。
|
|
7
7
|
*/
|
|
@@ -16,6 +16,12 @@ export interface LongTaskStep {
|
|
|
16
16
|
* @returns <unit>/runs。
|
|
17
17
|
*/
|
|
18
18
|
export declare function runsRouteOf(unit: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* 停止那条写路由(走 actions 通道的资源名):`<单元>/runs/stop`。
|
|
21
|
+
* @param unit 单元 id。
|
|
22
|
+
* @returns <unit>/runs/stop。
|
|
23
|
+
*/
|
|
24
|
+
export declare function stopRouteOf(unit: string): string;
|
|
19
25
|
/**
|
|
20
26
|
* 长任务读口回的载荷:一串 run,形状由模块自己定,外壳只透传。
|
|
21
27
|
*/
|
|
@@ -48,7 +54,30 @@ export declare function longTaskRunsOf<T>(state: {
|
|
|
48
54
|
}): readonly T[];
|
|
49
55
|
/**
|
|
50
56
|
* 把长任务态折成状态点的那一档。
|
|
51
|
-
* @param status
|
|
52
|
-
* @returns ongoing / done / error / idle;needs-login
|
|
57
|
+
* @param status 长任务的五种态。
|
|
58
|
+
* @returns ongoing / done / error / idle;needs-login 也算进行中;`stopped` 落进 idle —— 灰点:不是成功、不是出错,是用户自己按停的。
|
|
53
59
|
*/
|
|
54
60
|
export declare function longTaskDot(status: LongTaskStatus): 'ongoing' | 'done' | 'error' | 'idle';
|
|
61
|
+
/**
|
|
62
|
+
* 停止钮的三档:没上膛 / 上了膛 / 请求在飞。
|
|
63
|
+
*/
|
|
64
|
+
export type LongTaskStopStage = 'idle' | 'armed' | 'busy';
|
|
65
|
+
/**
|
|
66
|
+
* 算停止钮现在在哪一档。
|
|
67
|
+
* @param state armed = 已经按过第一下、在等第二下;busy = 停止请求已经在飞。
|
|
68
|
+
* @returns busy 优先(在飞时按不动),其次 armed,否则 idle。
|
|
69
|
+
*/
|
|
70
|
+
export declare function longTaskStopStage(state: {
|
|
71
|
+
readonly armed: boolean;
|
|
72
|
+
readonly busy: boolean;
|
|
73
|
+
}): LongTaskStopStage;
|
|
74
|
+
/**
|
|
75
|
+
* 按一下该干什么:第一次只上膛('arm'),上了膛再按才真发('fire'),在飞时按不动('ignore')。
|
|
76
|
+
* @param stage 现在这一档(先过 `longTaskStopStage`)。
|
|
77
|
+
* @returns 'arm' / 'fire' / 'ignore',调用点照它上膛、落膛加发请求、或什么都不做。
|
|
78
|
+
*/
|
|
79
|
+
export declare function longTaskStopPress(stage: LongTaskStopStage): 'arm' | 'fire' | 'ignore';
|
|
80
|
+
/**
|
|
81
|
+
* 上膛后多久自己落膛(毫秒)。3 秒 = dsh 那行现在的取值。
|
|
82
|
+
*/
|
|
83
|
+
export declare const LONG_TASK_STOP_ARM_MS = 3000;
|
package/dist/api/long-task.js
CHANGED
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
export function runsRouteOf(unit) {
|
|
7
7
|
return `${unit}/runs`;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* 停止那条写路由(走 actions 通道的资源名):`<单元>/runs/stop`。
|
|
11
|
+
* @param unit 单元 id。
|
|
12
|
+
* @returns <unit>/runs/stop。
|
|
13
|
+
*/
|
|
14
|
+
export function stopRouteOf(unit) {
|
|
15
|
+
return `${unit}/runs/stop`;
|
|
16
|
+
}
|
|
9
17
|
/**
|
|
10
18
|
* 有长任务在跑时的轮询间隔(毫秒)。
|
|
11
19
|
*/
|
|
@@ -35,8 +43,8 @@ export function longTaskRunsOf(state) {
|
|
|
35
43
|
}
|
|
36
44
|
/**
|
|
37
45
|
* 把长任务态折成状态点的那一档。
|
|
38
|
-
* @param status
|
|
39
|
-
* @returns ongoing / done / error / idle;needs-login
|
|
46
|
+
* @param status 长任务的五种态。
|
|
47
|
+
* @returns ongoing / done / error / idle;needs-login 也算进行中;`stopped` 落进 idle —— 灰点:不是成功、不是出错,是用户自己按停的。
|
|
40
48
|
*/
|
|
41
49
|
export function longTaskDot(status) {
|
|
42
50
|
if (status === 'ok')
|
|
@@ -47,3 +55,27 @@ export function longTaskDot(status) {
|
|
|
47
55
|
return 'ongoing';
|
|
48
56
|
return 'idle';
|
|
49
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* 算停止钮现在在哪一档。
|
|
60
|
+
* @param state armed = 已经按过第一下、在等第二下;busy = 停止请求已经在飞。
|
|
61
|
+
* @returns busy 优先(在飞时按不动),其次 armed,否则 idle。
|
|
62
|
+
*/
|
|
63
|
+
export function longTaskStopStage(state) {
|
|
64
|
+
if (state.busy)
|
|
65
|
+
return 'busy';
|
|
66
|
+
return state.armed ? 'armed' : 'idle';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 按一下该干什么:第一次只上膛('arm'),上了膛再按才真发('fire'),在飞时按不动('ignore')。
|
|
70
|
+
* @param stage 现在这一档(先过 `longTaskStopStage`)。
|
|
71
|
+
* @returns 'arm' / 'fire' / 'ignore',调用点照它上膛、落膛加发请求、或什么都不做。
|
|
72
|
+
*/
|
|
73
|
+
export function longTaskStopPress(stage) {
|
|
74
|
+
if (stage === 'busy')
|
|
75
|
+
return 'ignore';
|
|
76
|
+
return stage === 'armed' ? 'fire' : 'arm';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 上膛后多久自己落膛(毫秒)。3 秒 = dsh 那行现在的取值。
|
|
80
|
+
*/
|
|
81
|
+
export const LONG_TASK_STOP_ARM_MS = 3000;
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
gap: var(--wb-len-6);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
.wb-formRows > .wb-formRow[data-layout='stacked'] {
|
|
28
|
+
grid-template-columns: minmax(0, 1fr);
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
.wb-formLabel {
|
|
28
32
|
min-width: 0;
|
|
29
33
|
font-size: var(--dsw-font-xs-13-font-size);
|
|
@@ -36,12 +40,39 @@
|
|
|
36
40
|
white-space: normal;
|
|
37
41
|
}
|
|
38
42
|
|
|
43
|
+
.wb-formRow[data-layout='stacked'] .wb-formHint,
|
|
44
|
+
.wb-formRow[data-layout='stacked'] .wb-formProblem {
|
|
45
|
+
grid-column: 1 / -1;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
.wb-formControl {
|
|
40
49
|
display: flex;
|
|
41
50
|
align-items: center;
|
|
42
51
|
min-width: 0;
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
.wb-formControl
|
|
55
|
+
> :where(
|
|
56
|
+
.wb-selectAnchor,
|
|
57
|
+
.wb-choiceMenu,
|
|
58
|
+
input:not(
|
|
59
|
+
[type='checkbox'],
|
|
60
|
+
[type='radio'],
|
|
61
|
+
[type='button'],
|
|
62
|
+
[type='submit'],
|
|
63
|
+
[type='reset'],
|
|
64
|
+
[type='image'],
|
|
65
|
+
[type='color'],
|
|
66
|
+
[type='range']
|
|
67
|
+
),
|
|
68
|
+
select,
|
|
69
|
+
textarea
|
|
70
|
+
) {
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
width: 100%;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
45
76
|
.wb-formHint {
|
|
46
77
|
grid-column: 2;
|
|
47
78
|
font-size: var(--dsw-font-xxs-12-font-size);
|
|
@@ -45,4 +45,56 @@
|
|
|
45
45
|
margin: var(--wb-len-4) 0 0;
|
|
46
46
|
max-height: var(--wb-len-220);
|
|
47
47
|
overflow: auto;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.wb-longTaskStop {
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
flex: none;
|
|
53
|
+
align-items: center;
|
|
54
|
+
align-self: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
width: var(--wb-len-20);
|
|
57
|
+
height: var(--wb-len-20);
|
|
58
|
+
padding: 0;
|
|
59
|
+
margin-left: auto;
|
|
60
|
+
border: 0.5px solid var(--dsw-alias-border-l2);
|
|
61
|
+
border-radius: var(--dsw-radius-sm);
|
|
62
|
+
background: var(--dsw-specific-menu);
|
|
63
|
+
color: var(--dsw-alias-label-secondary);
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.wb-longTaskStop:hover:not(:disabled),
|
|
68
|
+
.wb-longTaskStop:focus-visible {
|
|
69
|
+
border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);
|
|
70
|
+
color: var(--dsw-alias-state-error-primary);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.wb-longTaskStop:disabled {
|
|
74
|
+
cursor: default;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.wb-longTaskStopArmed,
|
|
78
|
+
.wb-longTaskStopArmed:hover:not(:disabled),
|
|
79
|
+
.wb-longTaskStopArmed:focus-visible {
|
|
80
|
+
gap: var(--wb-len-4);
|
|
81
|
+
width: auto;
|
|
82
|
+
padding: 0 var(--wb-len-7);
|
|
83
|
+
border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);
|
|
84
|
+
background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent);
|
|
85
|
+
color: var(--dsw-alias-state-error-primary);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.wb-longTaskStopLabel {
|
|
89
|
+
white-space: nowrap;
|
|
90
|
+
font-size: var(--dsw-font-xxxs-11-font-size);
|
|
91
|
+
line-height: var(--wb-line-18);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.wb-longTaskStopWhy {
|
|
95
|
+
margin: 0;
|
|
96
|
+
font-size: var(--dsw-font-xxxs-11-font-size);
|
|
97
|
+
line-height: var(--wb-line-16);
|
|
98
|
+
color: var(--dsw-alias-state-error-primary);
|
|
99
|
+
overflow-wrap: anywhere;
|
|
48
100
|
}
|
|
@@ -8,7 +8,21 @@ export interface LongTaskRowLink {
|
|
|
8
8
|
readonly text: string;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* `LongTaskRow`
|
|
11
|
+
* `LongTaskRow` 那颗两按停止钮的契约:确认之后真发的那一下、三句词、在飞与失败两态。
|
|
12
|
+
* `label` 是没上膛时那颗钮的 aria-label(dsh 的词:`停止任务 {label}`);`askLabel` 是上膛时那颗钮上显示的字(`确认停止`);
|
|
13
|
+
* `armedLabel` 是上膛时的 aria-label,不给就用 `askLabel`(`再次点击确认停止`);`busy` = 这一趟正在被停、钮禁用;
|
|
14
|
+
* `failed` 给了才在问题那行后面再画一行。
|
|
15
|
+
*/
|
|
16
|
+
export interface LongTaskRowStop {
|
|
17
|
+
readonly onStop: () => void;
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly askLabel: string;
|
|
20
|
+
readonly armedLabel?: string | undefined;
|
|
21
|
+
readonly busy?: boolean | undefined;
|
|
22
|
+
readonly failed?: string | null | undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* `LongTaskRow` 的契约:状态、标题、问题、链接,两处可展开的原始输出,与最右边那颗可选的停止钮。
|
|
12
26
|
*/
|
|
13
27
|
export interface LongTaskRowProps {
|
|
14
28
|
readonly status: LongTaskStatus;
|
|
@@ -21,11 +35,12 @@ export interface LongTaskRowProps {
|
|
|
21
35
|
readonly rawTitle?: string | undefined;
|
|
22
36
|
readonly copyLabel?: string | undefined;
|
|
23
37
|
readonly copiedLabel?: string | undefined;
|
|
38
|
+
readonly stop?: LongTaskRowStop | undefined;
|
|
24
39
|
}
|
|
25
40
|
/**
|
|
26
41
|
* 长任务那一行:状态点 + 标题 + 链接,跑失败时把步骤与原始输出收在两处可展开里。
|
|
27
42
|
* 发布、扫描、迁移这类跑得久的事都用它,别自己画进度。
|
|
28
|
-
* @param props.status - `longTaskDot`
|
|
43
|
+
* @param props.status - `longTaskDot` 认的五态之一,决定状态点颜色与要不要画"失败"那两块。
|
|
29
44
|
* @param props.headline - 这一行在干什么(一句话)。
|
|
30
45
|
* @param props.problem - 失败原因;不给不画。
|
|
31
46
|
* @param props.links - 行尾的链接,通常指向产物或日志。
|
|
@@ -33,6 +48,7 @@ export interface LongTaskRowProps {
|
|
|
33
48
|
* @param props.raw - 原始输出;只在失败时画,且要同时给 `rawTitle` 才成一块可展开。
|
|
34
49
|
* @param props.stepsTitle - 步骤那块展开行的标题;`rawTitle` 同理是原始输出那块。
|
|
35
50
|
* @param props.copyLabel - 复制钮文案:给了才画复制钮;`copiedLabel` 是复制成功后那句。
|
|
51
|
+
* @param props.stop - 给了才在最右边画那颗两按停止钮;**不给就一个像素都不变**。只在生产方认 `signal` 时给。
|
|
36
52
|
* @returns 一行长任务。
|
|
37
53
|
*/
|
|
38
54
|
export declare function LongTaskRow(props: LongTaskRowProps): JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { longTaskDot } from '../api/long-task.js';
|
|
1
|
+
import { longTaskDot, longTaskStopPress, longTaskStopStage, LONG_TASK_STOP_ARM_MS } from '../api/long-task.js';
|
|
2
2
|
import { Link } from './Link.js';
|
|
3
|
-
import { Fragment, h, useState } from '../lib/react.js';
|
|
4
|
-
import { CodeBlock, DisclosureRow, IconCodeOutlineRegular, IconFlatListOutlineRegular, StateDot, } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import { Fragment, h, useEffect, useState } from '../lib/react.js';
|
|
4
|
+
import { CodeBlock, DisclosureRow, IconCodeOutlineRegular, IconFlatListOutlineRegular, IconStopFillRegular, StateDot, } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
5
5
|
import './LongTaskRow.css';
|
|
6
6
|
function RowLink({ href, text }) {
|
|
7
7
|
return (h(Link, { href: href, className: "wb-longTaskLink" }, text));
|
|
@@ -9,7 +9,7 @@ function RowLink({ href, text }) {
|
|
|
9
9
|
/**
|
|
10
10
|
* 长任务那一行:状态点 + 标题 + 链接,跑失败时把步骤与原始输出收在两处可展开里。
|
|
11
11
|
* 发布、扫描、迁移这类跑得久的事都用它,别自己画进度。
|
|
12
|
-
* @param props.status - `longTaskDot`
|
|
12
|
+
* @param props.status - `longTaskDot` 认的五态之一,决定状态点颜色与要不要画"失败"那两块。
|
|
13
13
|
* @param props.headline - 这一行在干什么(一句话)。
|
|
14
14
|
* @param props.problem - 失败原因;不给不画。
|
|
15
15
|
* @param props.links - 行尾的链接,通常指向产物或日志。
|
|
@@ -17,21 +17,49 @@ function RowLink({ href, text }) {
|
|
|
17
17
|
* @param props.raw - 原始输出;只在失败时画,且要同时给 `rawTitle` 才成一块可展开。
|
|
18
18
|
* @param props.stepsTitle - 步骤那块展开行的标题;`rawTitle` 同理是原始输出那块。
|
|
19
19
|
* @param props.copyLabel - 复制钮文案:给了才画复制钮;`copiedLabel` 是复制成功后那句。
|
|
20
|
+
* @param props.stop - 给了才在最右边画那颗两按停止钮;**不给就一个像素都不变**。只在生产方认 `signal` 时给。
|
|
20
21
|
* @returns 一行长任务。
|
|
21
22
|
*/
|
|
22
23
|
export function LongTaskRow(props) {
|
|
23
24
|
const [stepsOpen, setStepsOpen] = useState(false);
|
|
24
25
|
const [rawOpen, setRawOpen] = useState(false);
|
|
26
|
+
const [armed, setArmed] = useState(false);
|
|
25
27
|
const failed = props.status === 'failed';
|
|
26
28
|
const problem = props.problem ?? '';
|
|
27
29
|
const raw = (props.raw ?? '').trim();
|
|
28
30
|
const steps = props.steps ?? [];
|
|
31
|
+
const stop = props.stop;
|
|
32
|
+
const busy = stop?.busy === true;
|
|
33
|
+
const stopWhy = stop?.failed ?? '';
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!armed)
|
|
36
|
+
return undefined;
|
|
37
|
+
const timer = setTimeout(() => setArmed(false), LONG_TASK_STOP_ARM_MS);
|
|
38
|
+
return () => clearTimeout(timer);
|
|
39
|
+
}, [armed]);
|
|
40
|
+
const onStopPress = () => {
|
|
41
|
+
if (stop === undefined)
|
|
42
|
+
return;
|
|
43
|
+
const press = longTaskStopPress(longTaskStopStage({ armed, busy }));
|
|
44
|
+
if (press === 'ignore')
|
|
45
|
+
return;
|
|
46
|
+
if (press === 'arm') {
|
|
47
|
+
setArmed(true);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
setArmed(false);
|
|
51
|
+
stop.onStop();
|
|
52
|
+
};
|
|
29
53
|
return (h("div", { className: "wb-longTask" },
|
|
30
54
|
h("p", { className: "wb-longTaskHead" },
|
|
31
55
|
h(StateDot, { state: longTaskDot(props.status), size: 10 }),
|
|
32
56
|
h("span", { className: "wb-longTaskHeadline" }, props.headline),
|
|
33
|
-
(props.links ?? []).map((link) => (h(RowLink, { href: link.href, key: `${link.text}@${link.href}`, text: link.text })))
|
|
57
|
+
(props.links ?? []).map((link) => (h(RowLink, { href: link.href, key: `${link.text}@${link.href}`, text: link.text }))),
|
|
58
|
+
stop === undefined ? null : (h("button", { type: "button", className: `wb-longTaskStop${armed ? ' wb-longTaskStopArmed' : ''}`, "data-stop-state": longTaskStopStage({ armed, busy }), "aria-label": armed ? stop.armedLabel ?? stop.askLabel : stop.label, disabled: busy, onClick: onStopPress, onBlur: () => setArmed(false) },
|
|
59
|
+
h(IconStopFillRegular, { size: 12 }),
|
|
60
|
+
armed ? h("span", { className: "wb-longTaskStopLabel" }, stop.askLabel) : null))),
|
|
34
61
|
problem === '' ? null : h("p", { className: "wb-longTaskProblem" }, problem),
|
|
62
|
+
stopWhy === '' ? null : h("p", { className: "wb-longTaskStopWhy" }, stopWhy),
|
|
35
63
|
!failed ? null : (h(Fragment, null,
|
|
36
64
|
steps.length === 0 || props.stepsTitle === undefined ? null : (h(DisclosureRow, { className: "wb-longTaskDump", icon: h(IconFlatListOutlineRegular, { size: 14 }), title: props.stepsTitle, open: stepsOpen, expandable: true, expandOnRowClick: true, previewChevron: true, onToggle: () => setStepsOpen(!stepsOpen) },
|
|
37
65
|
h(CodeBlock, { code: steps.join('\n'), className: "wb-longTaskDump", showHeader: props.copyLabel !== undefined, copyLabel: props.copyLabel ?? '', copiedLabel: props.copiedLabel ?? '' }))),
|
package/dist/host/long-task.d.ts
CHANGED
|
@@ -10,24 +10,29 @@ export interface LongTaskBase {
|
|
|
10
10
|
readonly why?: string | undefined;
|
|
11
11
|
readonly startedAt: string;
|
|
12
12
|
readonly at: string;
|
|
13
|
+
readonly session?: string | undefined;
|
|
13
14
|
}
|
|
14
15
|
export interface LongTaskStart {
|
|
15
16
|
readonly workspace: string;
|
|
16
17
|
readonly target: string;
|
|
17
18
|
readonly payload?: unknown;
|
|
19
|
+
readonly session?: string | undefined;
|
|
18
20
|
}
|
|
19
21
|
export interface LongTaskChange<S extends LongTaskBase> {
|
|
20
22
|
readonly kind: 'start' | 'step' | 'settle';
|
|
21
23
|
readonly snapshot: S;
|
|
22
24
|
readonly step?: LongTaskStep | undefined;
|
|
25
|
+
readonly by?: string | undefined;
|
|
23
26
|
}
|
|
24
27
|
export interface LongTaskDeps<S extends LongTaskBase> {
|
|
25
28
|
readonly run: (options: {
|
|
26
29
|
readonly payload: unknown;
|
|
27
30
|
readonly onStep: (step: LongTaskStep) => void;
|
|
31
|
+
readonly signal: AbortSignal;
|
|
28
32
|
}) => Promise<unknown>;
|
|
29
33
|
readonly step?: ((step: LongTaskStep, current: S) => Partial<S>) | undefined;
|
|
30
34
|
readonly outcome?: ((result: unknown, current: S) => Partial<S>) | undefined;
|
|
35
|
+
readonly stopped?: ((current: S) => Partial<S>) | undefined;
|
|
31
36
|
readonly view: (snapshot: S) => Readonly<Record<string, unknown>>;
|
|
32
37
|
readonly now?: (() => string) | undefined;
|
|
33
38
|
readonly nextId?: (() => string) | undefined;
|
|
@@ -39,6 +44,7 @@ export interface LongTaskRegistry<S extends LongTaskBase> {
|
|
|
39
44
|
snapshot(id: string): S | null;
|
|
40
45
|
active(workspace: string, target: string): S | null;
|
|
41
46
|
current(workspace: string): readonly Readonly<Record<string, unknown>>[];
|
|
47
|
+
stop(id: string, by?: string): boolean;
|
|
42
48
|
onChange(listener: (change: LongTaskChange<S>) => void): () => void;
|
|
43
49
|
}
|
|
44
50
|
export declare function createLongTaskRegistry<S extends LongTaskBase>(deps: LongTaskDeps<S>): LongTaskRegistry<S>;
|
|
@@ -52,6 +58,7 @@ export declare function createLongTaskHost(options: {
|
|
|
52
58
|
readonly scope: string;
|
|
53
59
|
readonly unit: string;
|
|
54
60
|
readonly bump: (facts: readonly string[]) => void;
|
|
61
|
+
readonly notify?: ((change: LongTaskChange<LongTaskBase>) => void) | undefined;
|
|
55
62
|
}): {
|
|
56
63
|
readonly host: LongTaskHost;
|
|
57
64
|
dispose(): void;
|
package/dist/host/long-task.js
CHANGED
|
@@ -3,11 +3,18 @@ const LIVE = new Set(['running', 'needs-login']);
|
|
|
3
3
|
const RECENT_MS = 10 * 60 * 1000;
|
|
4
4
|
export function createLongTaskRegistry(deps) {
|
|
5
5
|
const runs = new Map();
|
|
6
|
+
const controls = new Map();
|
|
6
7
|
const now = deps.now ?? (() => new Date().toISOString());
|
|
7
8
|
let counter = 0;
|
|
8
9
|
const nextId = deps.nextId ?? (() => `run-${Date.now()}-${(counter += 1)}`);
|
|
9
10
|
const recentMs = deps.recentMs ?? RECENT_MS;
|
|
10
11
|
const listeners = new Set();
|
|
12
|
+
const live = (id) => {
|
|
13
|
+
const current = runs.get(id);
|
|
14
|
+
if (current === undefined || !LIVE.has(current.status))
|
|
15
|
+
return null;
|
|
16
|
+
return current;
|
|
17
|
+
};
|
|
11
18
|
const notify = (change) => {
|
|
12
19
|
for (const listener of [...listeners]) {
|
|
13
20
|
try {
|
|
@@ -46,7 +53,7 @@ export function createLongTaskRegistry(deps) {
|
|
|
46
53
|
return [...newest.values()]
|
|
47
54
|
.filter((snapshot) => LIVE.has(snapshot.status) || Date.parse(snapshot.at) >= floor)
|
|
48
55
|
.reverse()
|
|
49
|
-
.map((snapshot) => deps.view(snapshot));
|
|
56
|
+
.map((snapshot) => ({ ...deps.view(snapshot), id: snapshot.id }));
|
|
50
57
|
},
|
|
51
58
|
start(options) {
|
|
52
59
|
const running = this.active(options.workspace, options.target);
|
|
@@ -63,11 +70,12 @@ export function createLongTaskRegistry(deps) {
|
|
|
63
70
|
steps: [],
|
|
64
71
|
startedAt,
|
|
65
72
|
at: startedAt,
|
|
73
|
+
...(options.session === undefined ? {} : { session: options.session }),
|
|
66
74
|
});
|
|
67
75
|
notify({ kind: 'start', snapshot: runs.get(id) });
|
|
68
76
|
const onStep = (step) => {
|
|
69
|
-
const current =
|
|
70
|
-
if (current ===
|
|
77
|
+
const current = live(id);
|
|
78
|
+
if (current === null)
|
|
71
79
|
return;
|
|
72
80
|
const steps = [...current.steps, `${step.kind === 'fail' ? '✗ ' : ''}${step.text}`].slice(-20);
|
|
73
81
|
const extra = deps.step?.(step, current) ?? {};
|
|
@@ -83,13 +91,21 @@ export function createLongTaskRegistry(deps) {
|
|
|
83
91
|
...(current.status === 'needs-login' ? { loginUrl: undefined } : {}),
|
|
84
92
|
}, { kind: 'step', step });
|
|
85
93
|
};
|
|
94
|
+
const control = new AbortController();
|
|
95
|
+
controls.set(id, control);
|
|
86
96
|
void deps
|
|
87
|
-
.run({ payload: options.payload, onStep })
|
|
97
|
+
.run({ payload: options.payload, onStep, signal: control.signal })
|
|
88
98
|
.then((result) => {
|
|
89
|
-
const current =
|
|
99
|
+
const current = live(id);
|
|
100
|
+
if (current === null)
|
|
101
|
+
return;
|
|
102
|
+
controls.delete(id);
|
|
90
103
|
patch(id, { status: 'ok', ...(deps.outcome?.(result, current) ?? {}), loginUrl: undefined }, { kind: 'settle' });
|
|
91
104
|
})
|
|
92
105
|
.catch((error) => {
|
|
106
|
+
if (live(id) === null)
|
|
107
|
+
return;
|
|
108
|
+
controls.delete(id);
|
|
93
109
|
patch(id, {
|
|
94
110
|
status: 'failed',
|
|
95
111
|
why: error instanceof Error ? error.message : String(error),
|
|
@@ -98,6 +114,15 @@ export function createLongTaskRegistry(deps) {
|
|
|
98
114
|
});
|
|
99
115
|
return runs.get(id);
|
|
100
116
|
},
|
|
117
|
+
stop(id, by) {
|
|
118
|
+
const current = live(id);
|
|
119
|
+
if (current === null)
|
|
120
|
+
return false;
|
|
121
|
+
controls.get(id)?.abort();
|
|
122
|
+
controls.delete(id);
|
|
123
|
+
patch(id, { ...(deps.stopped?.(current) ?? {}), status: 'stopped', loginUrl: undefined }, { kind: 'settle', by });
|
|
124
|
+
return true;
|
|
125
|
+
},
|
|
101
126
|
snapshot(id) {
|
|
102
127
|
return runs.get(id) ?? null;
|
|
103
128
|
},
|
|
@@ -136,6 +161,7 @@ export function createLongTaskHost(options) {
|
|
|
136
161
|
offs.push(registry.onChange((change) => {
|
|
137
162
|
const named = [runsRouteOf(options.unit), ...(facts?.(change) ?? [])];
|
|
138
163
|
options.bump([...new Set(named)]);
|
|
164
|
+
options.notify?.(change);
|
|
139
165
|
}));
|
|
140
166
|
return registry;
|
|
141
167
|
},
|
package/dist/host/unit-face.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface UnitMountDeps {
|
|
|
28
28
|
readonly force?: boolean;
|
|
29
29
|
}) => Promise<UnitCapability | undefined>;
|
|
30
30
|
readonly longTasks?: LongTaskHost | undefined;
|
|
31
|
+
readonly longTaskRuns?: (() => ReadonlyMap<string, LongTaskRegistry<LongTaskBase>>) | undefined;
|
|
31
32
|
}
|
|
32
33
|
export type ContextRenderer = (ref: {
|
|
33
34
|
readonly kind: string;
|
package/dist/i18n/en.js
CHANGED
|
@@ -436,4 +436,6 @@ export const en = {
|
|
|
436
436
|
'approval.record.noUrl': 'no site given (this call gets refused)',
|
|
437
437
|
'approval.record.oneAction': 'one action',
|
|
438
438
|
'approval.record.noSwitch': 'it will not switch you back (the leftbar footer shows the state)',
|
|
439
|
+
'approval.longTask.what': 'Stops',
|
|
440
|
+
'approval.longTask.signal': 'stopping only sends an interrupt signal — how the platform-side run finishes is up to the module',
|
|
439
441
|
};
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -438,8 +438,10 @@ export declare const dictionaries: {
|
|
|
438
438
|
readonly 'approval.record.noUrl': "没给站点地址(这次会被当场拒)";
|
|
439
439
|
readonly 'approval.record.oneAction': "一次操作";
|
|
440
440
|
readonly 'approval.record.noSwitch': "录完不会替你切回来(左栏底部会亮一条状态)";
|
|
441
|
+
readonly 'approval.longTask.what': "要停的那一趟";
|
|
442
|
+
readonly 'approval.longTask.signal': "停了只是让外壳发出中断信号 —— 平台侧那趟活儿的收尾看模块自己";
|
|
441
443
|
};
|
|
442
|
-
en: Record<"time.now" | "time.ago" | "time.minutes" | "time.hours" | "time.days" | "blocker.retry" | "blocker.copy" | "blocker.unknown.title" | "blocker.login.go" | "blocker.login.titleGeneric" | "blocker.login.title" | "blocker.login.manual" | "blocker.login.hint" | "blocker.forbidden.open" | "blocker.forbidden.titleGeneric" | "blocker.forbidden.title" | "blocker.forbidden.hint" | "blocker.timeout.hint" | "blocker.exec.hint" | "blocker.fix.install" | "blocker.fix.update" | "blocker.market.open" | "env.unit.failed" | "env.unit.failedHint" | "env.unit.missingPlugin" | "env.unit.hint" | "env.unit.missingCommands" | "env.unit.missingCommandsHint" | "env.unit.unchecked" | "env.unit.uncheckedHint" | "brand.name" | "toggle.open" | "toggle.collapse" | "project.label" | "workspace.section" | "project.none" | "project.empty" | "project.add" | "project.add.busy" | "project.add.failed" | "project.search.label" | "project.search.placeholder" | "project.search.empty" | "project.group.workspaces" | "project.group.defaultWorkspace" | "project.group.workshop" | "project.rename.row" | "project.rename.current" | "project.rename.title" | "project.rename.description" | "project.rename.field" | "project.rename.placeholder" | "project.rename.hint" | "project.rename.save" | "project.rename.saving" | "project.rename.cancel" | "project.rename.failed" | "session.new" | "session.new.label" | "session.empty" | "session.noProject" | "session.list.label" | "session.copy" | "session.pinned" | "session.actions" | "status.idle" | "status.running" | "status.waitingApproval" | "status.planReview" | "status.waitingAnswer" | "status.compact.approval" | "status.compact.planReview" | "status.compact.answer" | "status.completed" | "status.subagentsRunning.one" | "status.subagentsRunning.other" | "project.attention.warning.one" | "project.attention.warning.other" | "project.attention.running.one" | "project.attention.running.other" | "project.attention.done.one" | "project.attention.done.other" | "project.attention.state.warning" | "project.attention.state.running" | "project.attention.state.done" | "hover.copied" | "time.short.minutes" | "time.short.hours" | "time.short.days" | "time.short.months" | "time.short.years" | "panels.title" | "panels.groupBoardless" | "panels.groupPlugins" | "panels.market.defaultHint" | "panels.market.defaultLabel" | "panels.market.defaultLocked" | "panels.followAll" | "panels.followAllConfirmTitle" | "panels.followAllConfirmDetail" | "panels.followAllConfirmAck" | "panels.followAllConfirmYes" | "panels.followAllConfirmNo" | "panels.enabled" | "panels.disabled" | "panels.choose" | "panels.buildModule" | "panels.failed" | "panels.dragHint" | "panels.unknownStep" | "panels.labelWithHint" | "panels.hintJoin" | "panels.dep.failed" | "panels.dep.missingPlugin" | "panels.dep.missingCommands" | "panels.dep.unchecked" | "panels.tab.modules" | "panels.tab.market" | "panels.browseMarket" | "panels.noneInstalled" | "panels.noneInstalledHint" | "panels.market.installed" | "panels.market.notActive" | "panels.market.notUsable" | "panels.market.broken" | "panels.market.hasNew" | "panels.market.hasProblem" | "panels.market.missing" | "panels.market.unchecked" | "panels.market.checking" | "panels.market.sectionInstalled" | "panels.market.sectionPending" | "panels.market.sectionShared" | "panels.market.sharedUsedBy" | "panels.market.listSeparator" | "panels.market.sharedMissing" | "panels.market.sharedOutdated" | "panels.market.sharedUnsatisfied" | "panels.market.sharedOk" | "panels.market.versionArrow" | "panels.market.lead" | "panels.market.install" | "panels.market.update" | "panels.market.swapSlow" | "panels.market.uninstall" | "panels.market.uninstallLabel" | "panels.market.installing" | "panels.market.updating" | "panels.market.uninstalling" | "panels.market.confirmUninstallTitle" | "panels.market.confirmUninstallDetail" | "panels.market.confirmUninstallAck" | "panels.market.confirmYes" | "panels.market.confirmNo" | "panels.market.failed" | "panels.market.needEnv" | "panels.market.needCommands" | "panels.market.localMark" | "panels.market.localHint" | "panels.market.noSource" | "panels.market.badSource" | "panels.market.empty" | "panels.market.sectionPlugins" | "panels.market.moduleOutdated" | "panels.market.moduleRefused" | "panels.market.moduleRefusedDetail" | "panels.market.moduleRestartHint" | "panels.market.pendingRestart" | "panels.market.workbenchName" | "panels.market.workbenchLocal" | "panels.market.pluginKeptInUse" | "panels.market.pluginKeptUnsure" | "panels.market.pluginKeptHeld" | "panels.market.pluginKeptUnnamed" | "panels.market.pluginBroken" | "panels.market.restartNeeded" | "panels.market.foot" | "panels.market.recheck" | "panels.market.checkUpdates" | "panels.market.checkedAt" | "panels.market.justNow" | "panels.market.minutesAgo" | "panels.market.hoursAgo" | "panels.market.add.description" | "panels.market.add.specPlaceholder" | "panels.market.add.guideToggle" | "panels.market.add.guideHide" | "panels.market.add.guideIdTitle" | "panels.market.add.guideIdExample" | "panels.market.add.guideIdHint" | "panels.market.add.guideGitTitle" | "panels.market.add.guideGitExample" | "panels.market.add.guideGitHint" | "panels.market.add.guidePathTitle" | "panels.market.add.guidePathExample" | "panels.market.add.guidePathHint" | "panels.market.add.guideExampleLabel" | "panels.market.add.guideFill" | "panels.market.add.guideSafety" | "panels.market.add.registryLegend" | "panels.market.add.registryOfficial" | "panels.market.add.registryMirror" | "panels.market.add.registryWithHost" | "panels.market.add.registryToggle" | "panels.market.add.installVersion" | "panels.market.add.registryDefault" | "panels.market.add.registryCustom" | "panels.market.add.registryCustomPlaceholder" | "panels.market.add.registryCustomHint" | "panels.market.add.registryCustomInvalid" | "panels.market.add.run" | "panels.market.add.edit" | "panels.market.add.changeRegistry" | "panels.market.add.installingTitle" | "panels.market.add.installedTitle" | "panels.market.add.failedTitle" | "panels.market.add.cancelledTitle" | "panels.market.add.failureNetworkHost" | "panels.market.add.problemInvalid" | "panels.market.add.problemInstalled" | "panels.market.add.problemNotFound" | "panels.market.add.problemNotPackage" | "panels.market.add.problemNotBundle" | "panels.market.add.problemNotWorkbenchModule" | "panels.market.add.problemNotModuleOrPlugin" | "panels.market.add.failureNotModuleOrPlugin" | "panels.market.add.installedPlugin" | "panels.market.add.pluginPreview" | "panels.market.add.pluginAlias" | "panels.market.add.problemNetwork" | "panels.market.add.problemUnknown" | "panels.market.add.failureNetwork" | "panels.market.add.failureNotFound" | "panels.market.add.failureNoMatchingVersion" | "panels.market.add.failureDiskFull" | "panels.market.add.failurePermission" | "panels.market.add.failureBuildBlocked" | "panels.market.add.failureIntegrity" | "panels.market.add.failureTimeout" | "panels.market.add.failurePnpmMissing" | "panels.market.add.failureInstalled" | "panels.market.add.failureGeneric" | "panels.market.add.approveTitle" | "panels.market.add.approveCaution" | "panels.market.add.approveRun" | "panels.market.add.restart" | "panels.market.add.tookEffect" | "panels.market.add.details" | "panels.market.add.open" | "panels.market.add.title" | "panels.market.add.intro" | "panels.market.add.specLabel" | "panels.market.add.specHint" | "panels.market.add.exampleTitle" | "panels.market.add.exampleFill" | "panels.market.add.registryLabel" | "panels.market.add.registryProfile" | "panels.market.add.registryPnpm" | "panels.market.add.check" | "panels.market.add.checking" | "panels.market.add.classifying" | "panels.market.add.change" | "panels.market.add.previewTitle" | "panels.market.add.fieldName" | "panels.market.add.fieldVersion" | "panels.market.add.fieldDescription" | "panels.market.add.fieldSource" | "panels.market.add.install" | "panels.market.add.installing" | "panels.market.add.cancel" | "panels.market.add.close" | "panels.market.add.retry" | "panels.market.add.changeSource" | "panels.market.add.approveBuilds" | "panels.market.add.approveHint" | "panels.market.add.doneApplied" | "panels.market.add.doneRestart" | "panels.market.add.restartWhy" | "panels.market.add.restartWhy.no-hmr" | "panels.market.add.restartWhy.package-moved" | "panels.market.add.restartWhy.host-module" | "panels.market.add.restartWhy.unmanaged-plugin" | "panels.market.add.restartWhy.module-comparison" | "panels.market.add.cancelled" | "panels.market.add.failed" | "panels.market.add.removed" | "panels.market.add.supplyPending" | "panels.market.add.supplyFailed" | "panels.market.add.notModule" | "panels.market.add.removedRestart" | "panels.market.add.remove" | "panels.market.add.problem.invalidSpec" | "panels.market.add.problem.alreadyInstalled" | "panels.market.add.problem.notFound" | "panels.market.add.problem.notAPackage" | "panels.market.add.problem.notABundle" | "panels.market.add.problem.network" | "panels.market.add.problem.unknown" | "panels.market.add.reason.invalidSpec" | "panels.market.add.reason.incompatible" | "panels.market.add.reason.notBundle" | "panels.market.add.reason.notRemovable" | "panels.market.add.reason.bundleInUse" | "panels.market.add.reason.stopProfile" | "panels.market.add.reason.staleApproval" | "panels.market.add.reason.operationError" | "panels.market.add.reason.buildBlocked" | "panels.market.add.reason.pnpmMissing" | "panels.market.add.reason.noMatchingVersion" | "panels.market.add.reason.diskFull" | "panels.market.add.reason.permission" | "panels.market.add.reason.integrity" | "panels.market.add.reason.timeout" | "panels.market.add.reason.network" | "panels.market.add.reason.notFound" | "panels.market.add.reason.unknown" | "blocker.fix.running" | "blocker.fix.failed" | "blocker.retry.running" | "panels.reading" | "panels.cardBroken" | "panels.cardRetry" | "panels.empty" | "panels.emptyHint" | "env.title" | "env.checking" | "env.installing" | "env.failed" | "env.elapsed" | "env.stepFailed.install" | "env.stepFailed.path" | "env.stepFailed.shell" | "env.bridge.ok" | "env.bridge.short" | "env.bridge.why" | "env.bridge.daemon" | "env.bridge.extension" | "env.bridge.extensionLink" | "env.bridge.profile" | "env.bridge.stale" | "env.bridge.unknown" | "env.fix.title" | "env.fix.why" | "env.fix.whyPath" | "env.fix.whyShell" | "env.fix.step" | "env.fix.stepPath" | "env.fix.stepShell" | "env.fix.permission" | "env.fix.network" | "env.fix.details" | "env.retry" | "env.copyCommand" | "env.copied" | "env.step.opencli" | "env.step.codingPlugin" | "env.step.bridge" | "env.step.warm" | "env.warm.done" | "env.warm.short" | "rightbar.label" | "rightbar.expand" | "rightbar.collapse" | "rightbar.column.label" | "rightbar.column.workbench" | "rightbar.column.dsh" | "rightbar.refresh" | "rightbar.refreshing" | "rightbar.updatedAt" | "rightbar.noProject" | "rightbar.openPlatform" | "coding.notARepo.title" | "error.unknown" | "board.title" | "panel.conversation" | "panels.label" | "configSync.nav" | "configSync.lead" | "configSync.source" | "configSync.sourceBroken" | "configSync.sourceRows" | "configSync.sourceDead" | "configSync.refresh" | "configSync.loading" | "configSync.readHint" | "configSync.tag.new" | "configSync.tag.differs" | "configSync.conflictNote" | "configSync.code.lang" | "configSync.code.copy" | "configSync.code.copied" | "configSync.code.wrap" | "configSync.code.unwrap" | "configSync.code.collapse" | "configSync.code.collapseAria" | "configSync.code.expandAria" | "configSync.code.expand" | "configSync.missing" | "configSync.apply" | "configSync.applyNone" | "configSync.applying" | "configSync.applied" | "configSync.appliedIds" | "configSync.skippedIds" | "configSync.nothing" | "configSync.unreadable" | "configSync.noSource" | "configSync.emptyProviders" | "configSync.failed" | "debug.workspace" | "debug.status" | "debug.status.trouble" | "debug.stalled" | "debug.act.pause" | "debug.act.resume" | "debug.act.stop" | "debug.act.stop.ask" | "debug.card.here.title" | "debug.card.here.note" | "debug.card.away.note" | "debug.card.paused.note" | "debug.card.hidden.note" | "record.waiting" | "record.waiting.note" | "record.recording" | "record.recording.note" | "record.finished" | "record.finished.note" | "record.act.cancel" | "record.act.halt" | "approval.record.site" | "approval.record.what" | "approval.record.lands" | "approval.record.noUrl" | "approval.record.oneAction" | "approval.record.noSwitch", string>;
|
|
444
|
+
en: Record<"time.now" | "time.ago" | "time.minutes" | "time.hours" | "time.days" | "blocker.retry" | "blocker.copy" | "blocker.unknown.title" | "blocker.login.go" | "blocker.login.titleGeneric" | "blocker.login.title" | "blocker.login.manual" | "blocker.login.hint" | "blocker.forbidden.open" | "blocker.forbidden.titleGeneric" | "blocker.forbidden.title" | "blocker.forbidden.hint" | "blocker.timeout.hint" | "blocker.exec.hint" | "blocker.fix.install" | "blocker.fix.update" | "blocker.market.open" | "env.unit.failed" | "env.unit.failedHint" | "env.unit.missingPlugin" | "env.unit.hint" | "env.unit.missingCommands" | "env.unit.missingCommandsHint" | "env.unit.unchecked" | "env.unit.uncheckedHint" | "brand.name" | "toggle.open" | "toggle.collapse" | "project.label" | "workspace.section" | "project.none" | "project.empty" | "project.add" | "project.add.busy" | "project.add.failed" | "project.search.label" | "project.search.placeholder" | "project.search.empty" | "project.group.workspaces" | "project.group.defaultWorkspace" | "project.group.workshop" | "project.rename.row" | "project.rename.current" | "project.rename.title" | "project.rename.description" | "project.rename.field" | "project.rename.placeholder" | "project.rename.hint" | "project.rename.save" | "project.rename.saving" | "project.rename.cancel" | "project.rename.failed" | "session.new" | "session.new.label" | "session.empty" | "session.noProject" | "session.list.label" | "session.copy" | "session.pinned" | "session.actions" | "status.idle" | "status.running" | "status.waitingApproval" | "status.planReview" | "status.waitingAnswer" | "status.compact.approval" | "status.compact.planReview" | "status.compact.answer" | "status.completed" | "status.subagentsRunning.one" | "status.subagentsRunning.other" | "project.attention.warning.one" | "project.attention.warning.other" | "project.attention.running.one" | "project.attention.running.other" | "project.attention.done.one" | "project.attention.done.other" | "project.attention.state.warning" | "project.attention.state.running" | "project.attention.state.done" | "hover.copied" | "time.short.minutes" | "time.short.hours" | "time.short.days" | "time.short.months" | "time.short.years" | "panels.title" | "panels.groupBoardless" | "panels.groupPlugins" | "panels.market.defaultHint" | "panels.market.defaultLabel" | "panels.market.defaultLocked" | "panels.followAll" | "panels.followAllConfirmTitle" | "panels.followAllConfirmDetail" | "panels.followAllConfirmAck" | "panels.followAllConfirmYes" | "panels.followAllConfirmNo" | "panels.enabled" | "panels.disabled" | "panels.choose" | "panels.buildModule" | "panels.failed" | "panels.dragHint" | "panels.unknownStep" | "panels.labelWithHint" | "panels.hintJoin" | "panels.dep.failed" | "panels.dep.missingPlugin" | "panels.dep.missingCommands" | "panels.dep.unchecked" | "panels.tab.modules" | "panels.tab.market" | "panels.browseMarket" | "panels.noneInstalled" | "panels.noneInstalledHint" | "panels.market.installed" | "panels.market.notActive" | "panels.market.notUsable" | "panels.market.broken" | "panels.market.hasNew" | "panels.market.hasProblem" | "panels.market.missing" | "panels.market.unchecked" | "panels.market.checking" | "panels.market.sectionInstalled" | "panels.market.sectionPending" | "panels.market.sectionShared" | "panels.market.sharedUsedBy" | "panels.market.listSeparator" | "panels.market.sharedMissing" | "panels.market.sharedOutdated" | "panels.market.sharedUnsatisfied" | "panels.market.sharedOk" | "panels.market.versionArrow" | "panels.market.lead" | "panels.market.install" | "panels.market.update" | "panels.market.swapSlow" | "panels.market.uninstall" | "panels.market.uninstallLabel" | "panels.market.installing" | "panels.market.updating" | "panels.market.uninstalling" | "panels.market.confirmUninstallTitle" | "panels.market.confirmUninstallDetail" | "panels.market.confirmUninstallAck" | "panels.market.confirmYes" | "panels.market.confirmNo" | "panels.market.failed" | "panels.market.needEnv" | "panels.market.needCommands" | "panels.market.localMark" | "panels.market.localHint" | "panels.market.noSource" | "panels.market.badSource" | "panels.market.empty" | "panels.market.sectionPlugins" | "panels.market.moduleOutdated" | "panels.market.moduleRefused" | "panels.market.moduleRefusedDetail" | "panels.market.moduleRestartHint" | "panels.market.pendingRestart" | "panels.market.workbenchName" | "panels.market.workbenchLocal" | "panels.market.pluginKeptInUse" | "panels.market.pluginKeptUnsure" | "panels.market.pluginKeptHeld" | "panels.market.pluginKeptUnnamed" | "panels.market.pluginBroken" | "panels.market.restartNeeded" | "panels.market.foot" | "panels.market.recheck" | "panels.market.checkUpdates" | "panels.market.checkedAt" | "panels.market.justNow" | "panels.market.minutesAgo" | "panels.market.hoursAgo" | "panels.market.add.description" | "panels.market.add.specPlaceholder" | "panels.market.add.guideToggle" | "panels.market.add.guideHide" | "panels.market.add.guideIdTitle" | "panels.market.add.guideIdExample" | "panels.market.add.guideIdHint" | "panels.market.add.guideGitTitle" | "panels.market.add.guideGitExample" | "panels.market.add.guideGitHint" | "panels.market.add.guidePathTitle" | "panels.market.add.guidePathExample" | "panels.market.add.guidePathHint" | "panels.market.add.guideExampleLabel" | "panels.market.add.guideFill" | "panels.market.add.guideSafety" | "panels.market.add.registryLegend" | "panels.market.add.registryOfficial" | "panels.market.add.registryMirror" | "panels.market.add.registryWithHost" | "panels.market.add.registryToggle" | "panels.market.add.installVersion" | "panels.market.add.registryDefault" | "panels.market.add.registryCustom" | "panels.market.add.registryCustomPlaceholder" | "panels.market.add.registryCustomHint" | "panels.market.add.registryCustomInvalid" | "panels.market.add.run" | "panels.market.add.edit" | "panels.market.add.changeRegistry" | "panels.market.add.installingTitle" | "panels.market.add.installedTitle" | "panels.market.add.failedTitle" | "panels.market.add.cancelledTitle" | "panels.market.add.failureNetworkHost" | "panels.market.add.problemInvalid" | "panels.market.add.problemInstalled" | "panels.market.add.problemNotFound" | "panels.market.add.problemNotPackage" | "panels.market.add.problemNotBundle" | "panels.market.add.problemNotWorkbenchModule" | "panels.market.add.problemNotModuleOrPlugin" | "panels.market.add.failureNotModuleOrPlugin" | "panels.market.add.installedPlugin" | "panels.market.add.pluginPreview" | "panels.market.add.pluginAlias" | "panels.market.add.problemNetwork" | "panels.market.add.problemUnknown" | "panels.market.add.failureNetwork" | "panels.market.add.failureNotFound" | "panels.market.add.failureNoMatchingVersion" | "panels.market.add.failureDiskFull" | "panels.market.add.failurePermission" | "panels.market.add.failureBuildBlocked" | "panels.market.add.failureIntegrity" | "panels.market.add.failureTimeout" | "panels.market.add.failurePnpmMissing" | "panels.market.add.failureInstalled" | "panels.market.add.failureGeneric" | "panels.market.add.approveTitle" | "panels.market.add.approveCaution" | "panels.market.add.approveRun" | "panels.market.add.restart" | "panels.market.add.tookEffect" | "panels.market.add.details" | "panels.market.add.open" | "panels.market.add.title" | "panels.market.add.intro" | "panels.market.add.specLabel" | "panels.market.add.specHint" | "panels.market.add.exampleTitle" | "panels.market.add.exampleFill" | "panels.market.add.registryLabel" | "panels.market.add.registryProfile" | "panels.market.add.registryPnpm" | "panels.market.add.check" | "panels.market.add.checking" | "panels.market.add.classifying" | "panels.market.add.change" | "panels.market.add.previewTitle" | "panels.market.add.fieldName" | "panels.market.add.fieldVersion" | "panels.market.add.fieldDescription" | "panels.market.add.fieldSource" | "panels.market.add.install" | "panels.market.add.installing" | "panels.market.add.cancel" | "panels.market.add.close" | "panels.market.add.retry" | "panels.market.add.changeSource" | "panels.market.add.approveBuilds" | "panels.market.add.approveHint" | "panels.market.add.doneApplied" | "panels.market.add.doneRestart" | "panels.market.add.restartWhy" | "panels.market.add.restartWhy.no-hmr" | "panels.market.add.restartWhy.package-moved" | "panels.market.add.restartWhy.host-module" | "panels.market.add.restartWhy.unmanaged-plugin" | "panels.market.add.restartWhy.module-comparison" | "panels.market.add.cancelled" | "panels.market.add.failed" | "panels.market.add.removed" | "panels.market.add.supplyPending" | "panels.market.add.supplyFailed" | "panels.market.add.notModule" | "panels.market.add.removedRestart" | "panels.market.add.remove" | "panels.market.add.problem.invalidSpec" | "panels.market.add.problem.alreadyInstalled" | "panels.market.add.problem.notFound" | "panels.market.add.problem.notAPackage" | "panels.market.add.problem.notABundle" | "panels.market.add.problem.network" | "panels.market.add.problem.unknown" | "panels.market.add.reason.invalidSpec" | "panels.market.add.reason.incompatible" | "panels.market.add.reason.notBundle" | "panels.market.add.reason.notRemovable" | "panels.market.add.reason.bundleInUse" | "panels.market.add.reason.stopProfile" | "panels.market.add.reason.staleApproval" | "panels.market.add.reason.operationError" | "panels.market.add.reason.buildBlocked" | "panels.market.add.reason.pnpmMissing" | "panels.market.add.reason.noMatchingVersion" | "panels.market.add.reason.diskFull" | "panels.market.add.reason.permission" | "panels.market.add.reason.integrity" | "panels.market.add.reason.timeout" | "panels.market.add.reason.network" | "panels.market.add.reason.notFound" | "panels.market.add.reason.unknown" | "blocker.fix.running" | "blocker.fix.failed" | "blocker.retry.running" | "panels.reading" | "panels.cardBroken" | "panels.cardRetry" | "panels.empty" | "panels.emptyHint" | "env.title" | "env.checking" | "env.installing" | "env.failed" | "env.elapsed" | "env.stepFailed.install" | "env.stepFailed.path" | "env.stepFailed.shell" | "env.bridge.ok" | "env.bridge.short" | "env.bridge.why" | "env.bridge.daemon" | "env.bridge.extension" | "env.bridge.extensionLink" | "env.bridge.profile" | "env.bridge.stale" | "env.bridge.unknown" | "env.fix.title" | "env.fix.why" | "env.fix.whyPath" | "env.fix.whyShell" | "env.fix.step" | "env.fix.stepPath" | "env.fix.stepShell" | "env.fix.permission" | "env.fix.network" | "env.fix.details" | "env.retry" | "env.copyCommand" | "env.copied" | "env.step.opencli" | "env.step.codingPlugin" | "env.step.bridge" | "env.step.warm" | "env.warm.done" | "env.warm.short" | "rightbar.label" | "rightbar.expand" | "rightbar.collapse" | "rightbar.column.label" | "rightbar.column.workbench" | "rightbar.column.dsh" | "rightbar.refresh" | "rightbar.refreshing" | "rightbar.updatedAt" | "rightbar.noProject" | "rightbar.openPlatform" | "coding.notARepo.title" | "error.unknown" | "board.title" | "panel.conversation" | "panels.label" | "configSync.nav" | "configSync.lead" | "configSync.source" | "configSync.sourceBroken" | "configSync.sourceRows" | "configSync.sourceDead" | "configSync.refresh" | "configSync.loading" | "configSync.readHint" | "configSync.tag.new" | "configSync.tag.differs" | "configSync.conflictNote" | "configSync.code.lang" | "configSync.code.copy" | "configSync.code.copied" | "configSync.code.wrap" | "configSync.code.unwrap" | "configSync.code.collapse" | "configSync.code.collapseAria" | "configSync.code.expandAria" | "configSync.code.expand" | "configSync.missing" | "configSync.apply" | "configSync.applyNone" | "configSync.applying" | "configSync.applied" | "configSync.appliedIds" | "configSync.skippedIds" | "configSync.nothing" | "configSync.unreadable" | "configSync.noSource" | "configSync.emptyProviders" | "configSync.failed" | "debug.workspace" | "debug.status" | "debug.status.trouble" | "debug.stalled" | "debug.act.pause" | "debug.act.resume" | "debug.act.stop" | "debug.act.stop.ask" | "debug.card.here.title" | "debug.card.here.note" | "debug.card.away.note" | "debug.card.paused.note" | "debug.card.hidden.note" | "record.waiting" | "record.waiting.note" | "record.recording" | "record.recording.note" | "record.finished" | "record.finished.note" | "record.act.cancel" | "record.act.halt" | "approval.record.site" | "approval.record.what" | "approval.record.lands" | "approval.record.noUrl" | "approval.record.oneAction" | "approval.record.noSwitch" | "approval.longTask.what" | "approval.longTask.signal", string>;
|
|
443
445
|
};
|
|
444
446
|
/** 中文词表的键类型(从 `zh.ts` 转出):`en` 与模块词表都得覆盖同一批键。 */
|
|
445
447
|
export type { WorkbenchMessages };
|
package/dist/i18n/zh.d.ts
CHANGED
|
@@ -436,6 +436,8 @@ export declare const zh: {
|
|
|
436
436
|
readonly 'approval.record.noUrl': "没给站点地址(这次会被当场拒)";
|
|
437
437
|
readonly 'approval.record.oneAction': "一次操作";
|
|
438
438
|
readonly 'approval.record.noSwitch': "录完不会替你切回来(左栏底部会亮一条状态)";
|
|
439
|
+
readonly 'approval.longTask.what': "要停的那一趟";
|
|
440
|
+
readonly 'approval.longTask.signal': "停了只是让外壳发出中断信号 —— 平台侧那趟活儿的收尾看模块自己";
|
|
439
441
|
};
|
|
440
442
|
/** 中文词表的键类型:`en` 与模块词表都得覆盖同一批键。 */
|
|
441
443
|
export type WorkbenchMessages = typeof zh;
|
package/dist/i18n/zh.js
CHANGED
|
@@ -436,4 +436,6 @@ export const zh = {
|
|
|
436
436
|
'approval.record.noUrl': '没给站点地址(这次会被当场拒)',
|
|
437
437
|
'approval.record.oneAction': '一次操作',
|
|
438
438
|
'approval.record.noSwitch': '录完不会替你切回来(左栏底部会亮一条状态)',
|
|
439
|
+
'approval.longTask.what': '要停的那一趟',
|
|
440
|
+
'approval.longTask.signal': '停了只是让外壳发出中断信号 —— 平台侧那趟活儿的收尾看模块自己',
|
|
439
441
|
};
|