@dsh-workbench/shared 0.3.7 → 0.3.9
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/dsh.d.ts +14 -0
- package/dist/api/long-task.d.ts +8 -0
- package/dist/api/long-task.js +10 -0
- package/dist/components/MockStrip.css +1 -11
- package/dist/i18n/en.js +12 -1
- package/dist/i18n/index.d.ts +13 -2
- package/dist/i18n/zh.d.ts +12 -1
- package/dist/i18n/zh.js +12 -1
- package/dist/lib/lint-probe.d.ts +1 -0
- package/dist/lib/lint-probe.js +6 -0
- package/package.json +1 -1
- package/src/api/__tests__/long-task.test.ts +15 -0
- package/src/api/dsh.ts +16 -0
- package/src/api/long-task.ts +11 -0
- package/src/i18n/en.ts +12 -1
- package/src/i18n/zh.ts +12 -1
- package/dist/components/StateDot.d.ts +0 -5
- package/dist/components/StateDot.js +0 -10
- package/dist/host/__tests__/fakes.d.ts +0 -41
- package/dist/host/__tests__/fakes.js +0 -76
- package/dist/host/__tests__/preflight-fixtures.d.ts +0 -19
- package/dist/host/__tests__/preflight-fixtures.js +0 -47
- package/dist/host/context-inject.d.ts +0 -24
- package/dist/host/context-inject.js +0 -74
- package/dist/host/events.d.ts +0 -9
- package/dist/host/events.js +0 -70
- package/dist/host/mount-units.d.ts +0 -52
- package/dist/host/mount-units.js +0 -186
- package/dist/host/preflight.d.ts +0 -58
- package/dist/host/preflight.js +0 -233
- package/dist/host/probe-cache.d.ts +0 -6
- package/dist/host/probe-cache.js +0 -19
- package/dist/host/probe-libs.d.ts +0 -45
- package/dist/host/probe-libs.js +0 -61
- package/dist/host/probe-units.d.ts +0 -17
- package/dist/host/probe-units.js +0 -102
- package/dist/host/probe-verdict.d.ts +0 -7
- package/dist/host/probe-verdict.js +0 -143
- package/dist/host/tool-scope.d.ts +0 -32
- package/dist/host/tool-scope.js +0 -84
- package/dist/host/unit-readiness.d.ts +0 -7
- package/dist/host/unit-readiness.js +0 -5
- package/dist/host/unit-registry.d.ts +0 -9
- package/dist/host/unit-registry.js +0 -33
- package/dist/host/version-range.d.ts +0 -2
- package/dist/host/version-range.js +0 -73
package/dist/api/dsh.d.ts
CHANGED
|
@@ -178,6 +178,20 @@ export interface DshWorkspaceRegistry {
|
|
|
178
178
|
title?: string;
|
|
179
179
|
} | undefined>;
|
|
180
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* agent preset 名单里的一行:id 与显示名;`broken` 非空表示这一行**挂不起来**(dsh 自己给的原因原文)。
|
|
183
|
+
*/
|
|
184
|
+
export interface DshAgentPresetRow {
|
|
185
|
+
readonly id: string;
|
|
186
|
+
readonly name?: string;
|
|
187
|
+
readonly broken?: string;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 宿主侧的 agent preset 名册(服务名 `agentPresets`):只读它的 `list()` —— 启动体检拿它判 DIY 模式挂不挂得起来。
|
|
191
|
+
*/
|
|
192
|
+
export interface DshAgentPresetRegistry {
|
|
193
|
+
list(): Promise<readonly DshAgentPresetRow[]>;
|
|
194
|
+
}
|
|
181
195
|
/**
|
|
182
196
|
* 把相对路径拼成 dsh home 下的绝对路径(服务名 dshHomePath);外壳存自己的状态用它,不自己拼 home。
|
|
183
197
|
*/
|
package/dist/api/long-task.d.ts
CHANGED
|
@@ -58,6 +58,14 @@ export declare function longTaskRunsOf<T>(state: {
|
|
|
58
58
|
* @returns ongoing / done / error / idle;needs-login 也算进行中;`stopped` 落进 idle —— 灰点:不是成功、不是出错,是用户自己按停的。
|
|
59
59
|
*/
|
|
60
60
|
export declare function longTaskDot(status: LongTaskStatus): 'ongoing' | 'done' | 'error' | 'idle';
|
|
61
|
+
/**
|
|
62
|
+
* 这一趟还在不在跑(`running` 与 `needs-login` 都算)。
|
|
63
|
+
* 卡片要判"这一行要不要摆停止钮""这套环境里有没有活着的跑"时用这个 —— **不是** `longTaskDot`:
|
|
64
|
+
* 那一件是状态点的**长相**(四档),归 `LongTaskRow` 自己用,不该被调用点拿去当判据。
|
|
65
|
+
* @param status 长任务的五种态。
|
|
66
|
+
* @returns 在跑 `true`;成功 / 失败 / 用户按停都是 `false`。
|
|
67
|
+
*/
|
|
68
|
+
export declare function longTaskIsLive(status: LongTaskStatus): boolean;
|
|
61
69
|
/**
|
|
62
70
|
* 停止钮的三档:没上膛 / 上了膛 / 请求在飞。
|
|
63
71
|
*/
|
package/dist/api/long-task.js
CHANGED
|
@@ -55,6 +55,16 @@ export function longTaskDot(status) {
|
|
|
55
55
|
return 'ongoing';
|
|
56
56
|
return 'idle';
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* 这一趟还在不在跑(`running` 与 `needs-login` 都算)。
|
|
60
|
+
* 卡片要判"这一行要不要摆停止钮""这套环境里有没有活着的跑"时用这个 —— **不是** `longTaskDot`:
|
|
61
|
+
* 那一件是状态点的**长相**(四档),归 `LongTaskRow` 自己用,不该被调用点拿去当判据。
|
|
62
|
+
* @param status 长任务的五种态。
|
|
63
|
+
* @returns 在跑 `true`;成功 / 失败 / 用户按停都是 `false`。
|
|
64
|
+
*/
|
|
65
|
+
export function longTaskIsLive(status) {
|
|
66
|
+
return status === 'running' || status === 'needs-login';
|
|
67
|
+
}
|
|
58
68
|
/**
|
|
59
69
|
* 算停止钮现在在哪一档。
|
|
60
70
|
* @param state armed = 已经按过第一下、在等第二下;busy = 停止请求已经在飞。
|
|
@@ -36,14 +36,4 @@
|
|
|
36
36
|
border-color: transparent;
|
|
37
37
|
background: var(--dsw-alias-brand-primary);
|
|
38
38
|
color: var(--dsw-alias-label-primary-foreground);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.wb-mockChipOn:hover {
|
|
42
|
-
border-color: transparent;
|
|
43
|
-
background: var(--dsw-alias-brand-primary);
|
|
44
|
-
color: var(--dsw-alias-label-primary-foreground);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.wb-panelBody.wb-panelMany .wb-mockStrip {
|
|
48
|
-
display: none;
|
|
49
|
-
}
|
|
39
|
+
}
|
package/dist/i18n/en.js
CHANGED
|
@@ -329,7 +329,8 @@ export const en = {
|
|
|
329
329
|
'env.stepFailed.shell': 'no shell channel',
|
|
330
330
|
'env.bridge.ok': 'Connected',
|
|
331
331
|
'env.bridge.short': 'Not connected',
|
|
332
|
-
'env.bridge.why': 'Panel data goes through the login state in your browser: with this channel down, modules cannot fetch data. It does not block startup
|
|
332
|
+
'env.bridge.why': 'Panel data goes through the login state in your browser: with this channel down, modules cannot fetch data. It does not block startup: fix it, or enter the workbench first.',
|
|
333
|
+
'env.bridge.hold': 'The browser bridge is not connected yet \u2014 fix it below and hit Retry, or enter the workbench first.',
|
|
333
334
|
'env.bridge.daemon': 'The background service is not running. It usually starts by itself \u2014 run the command below in your terminal first.',
|
|
334
335
|
'env.bridge.extension': 'The browser extension is not connected. Install it once from the Chrome Web Store (then hit Retry here). If it is already installed, run the command below first.',
|
|
335
336
|
'env.bridge.extensionLink': 'Get the extension in the Chrome Web Store',
|
|
@@ -347,11 +348,21 @@ export const en = {
|
|
|
347
348
|
'env.fix.network': 'Network unreachable: check your network or proxy, then retry.',
|
|
348
349
|
'env.fix.details': 'Details (for troubleshooting)',
|
|
349
350
|
'env.retry': 'Retry',
|
|
351
|
+
'env.bridge.continue': 'Enter the workbench anyway',
|
|
352
|
+
'env.diy.ok': 'Available',
|
|
353
|
+
'env.diy.short': 'Cannot load',
|
|
354
|
+
'env.diy.hold': 'DIY mode cannot load \u2014 upgrade dsh, then hit Retry; or enter the workbench first.',
|
|
355
|
+
'env.diy.why': '\u201cWorkbench DIY\u201d is a dsh agent preset, and it is generated from the dsh generation this shell was verified against. The dsh on this machine is older and does not ship some of those rows, so the whole preset fails to mount. dsh lists only the presets that mount, so the mode will simply not appear \u2014 panels and everything else are unaffected.',
|
|
356
|
+
'env.diy.rows': 'This dsh is missing these rows: {rows}',
|
|
357
|
+
'env.diy.noRow': 'The health check did not find \u201cWorkbench DIY\u201d in dsh\u2019s preset roster \u2014 most likely this bundle\u2019s preset patch did not apply.',
|
|
358
|
+
'env.diy.step': 'Upgrade dsh, then restart the workbench:',
|
|
359
|
+
'env.diy.continue': 'Enter the workbench anyway',
|
|
350
360
|
'env.copyCommand': 'Copy command',
|
|
351
361
|
'env.copied': 'Copied',
|
|
352
362
|
'env.step.opencli': 'Checking the workbench opencli',
|
|
353
363
|
'env.step.codingPlugin': 'Checking the coding plugin',
|
|
354
364
|
'env.step.bridge': 'Checking the browser bridge',
|
|
365
|
+
'env.step.diy': 'Checking DIY mode',
|
|
355
366
|
'env.step.warm': 'Warming up site sessions',
|
|
356
367
|
'env.warm.done': '{n} site(s) warmed up',
|
|
357
368
|
'env.warm.short': 'Not warmed this time — harmless; the panel heals on first read',
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -331,7 +331,8 @@ export declare const dictionaries: {
|
|
|
331
331
|
readonly 'env.stepFailed.shell': "执行通道不可用";
|
|
332
332
|
readonly 'env.bridge.ok': "已连接";
|
|
333
333
|
readonly 'env.bridge.short': "没连上";
|
|
334
|
-
readonly 'env.bridge.why': "
|
|
334
|
+
readonly 'env.bridge.why': "面板的数据要走你浏览器里的登录态:这个通道没连上,模块就取不到数据(不拦路:修好它,或者先进入工作台)。";
|
|
335
|
+
readonly 'env.bridge.hold': "浏览器通道还没连上 —— 按下面修好后点「重试」,也可以先进工作台。";
|
|
335
336
|
readonly 'env.bridge.daemon': "后台服务没起来:正常它会自己起,先在终端跑下面这条命令。";
|
|
336
337
|
readonly 'env.bridge.extension': "浏览器扩展没连上:在 Chrome 应用商店装一次就好(装完回来点「重试」)。已经装过的话,先跑下面这条命令。";
|
|
337
338
|
readonly 'env.bridge.extensionLink': "去 Chrome 应用商店装扩展";
|
|
@@ -349,11 +350,21 @@ export declare const dictionaries: {
|
|
|
349
350
|
readonly 'env.fix.network': "网络不通:检查网络或代理设置后重试。";
|
|
350
351
|
readonly 'env.fix.details': "详细输出(排障用)";
|
|
351
352
|
readonly 'env.retry': "重试";
|
|
353
|
+
readonly 'env.bridge.continue': "先进入工作台";
|
|
354
|
+
readonly 'env.diy.ok': "可用";
|
|
355
|
+
readonly 'env.diy.short': "挂不起来";
|
|
356
|
+
readonly 'env.diy.hold': "DIY 模式挂不起来 —— 升级 dsh 后点「重试」,也可以先进工作台。";
|
|
357
|
+
readonly 'env.diy.why': "「工作台 DIY」是 dsh 的一个 agent preset,而它是照这份外壳验过的那一代 dsh 生成的:这台机器上的 dsh 比它旧,其中几行 dsh 根本没有,于是这个模式整个挂不起来。dsh 的模式选择器只列挂得起来的,进去之后它会整个不出现 —— 面板与其它功能不受影响。";
|
|
358
|
+
readonly 'env.diy.rows': "这一代 dsh 缺这几行:{rows}";
|
|
359
|
+
readonly 'env.diy.noRow': "体检没在 dsh 的 preset 名单里看到「工作台 DIY」—— 多半是这份 bundle 的 preset 补丁没生效。";
|
|
360
|
+
readonly 'env.diy.step': "升级 dsh,然后重启一次工作台:";
|
|
361
|
+
readonly 'env.diy.continue': "先进入工作台";
|
|
352
362
|
readonly 'env.copyCommand': "复制命令";
|
|
353
363
|
readonly 'env.copied': "已复制";
|
|
354
364
|
readonly 'env.step.opencli': "检测工作台的 opencli";
|
|
355
365
|
readonly 'env.step.codingPlugin': "检测 coding 插件";
|
|
356
366
|
readonly 'env.step.bridge': "检测浏览器通道";
|
|
367
|
+
readonly 'env.step.diy': "检查 DIY 模式";
|
|
357
368
|
readonly 'env.step.warm': "预热站点登录态";
|
|
358
369
|
readonly 'env.warm.done': "已预热 {n} 个站点";
|
|
359
370
|
readonly 'env.warm.short': "这次没热上 —— 不影响用,面板第一次读取会自己补";
|
|
@@ -445,7 +456,7 @@ export declare const dictionaries: {
|
|
|
445
456
|
readonly 'approval.longTask.what': "要停的那一趟";
|
|
446
457
|
readonly 'approval.longTask.signal': "停了只是让外壳发出中断信号 —— 平台侧那趟活儿的收尾看模块自己";
|
|
447
458
|
};
|
|
448
|
-
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.longTask" | "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.longTask.one" | "project.attention.longTask.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.recording.shots" | "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>;
|
|
459
|
+
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.longTask" | "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.longTask.one" | "project.attention.longTask.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.hold" | "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.bridge.continue" | "env.diy.ok" | "env.diy.short" | "env.diy.hold" | "env.diy.why" | "env.diy.rows" | "env.diy.noRow" | "env.diy.step" | "env.diy.continue" | "env.copyCommand" | "env.copied" | "env.step.opencli" | "env.step.codingPlugin" | "env.step.bridge" | "env.step.diy" | "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.recording.shots" | "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>;
|
|
449
460
|
};
|
|
450
461
|
/** 中文词表的键类型(从 `zh.ts` 转出):`en` 与模块词表都得覆盖同一批键。 */
|
|
451
462
|
export type { WorkbenchMessages };
|
package/dist/i18n/zh.d.ts
CHANGED
|
@@ -329,7 +329,8 @@ export declare const zh: {
|
|
|
329
329
|
readonly 'env.stepFailed.shell': "执行通道不可用";
|
|
330
330
|
readonly 'env.bridge.ok': "已连接";
|
|
331
331
|
readonly 'env.bridge.short': "没连上";
|
|
332
|
-
readonly 'env.bridge.why': "
|
|
332
|
+
readonly 'env.bridge.why': "面板的数据要走你浏览器里的登录态:这个通道没连上,模块就取不到数据(不拦路:修好它,或者先进入工作台)。";
|
|
333
|
+
readonly 'env.bridge.hold': "浏览器通道还没连上 —— 按下面修好后点「重试」,也可以先进工作台。";
|
|
333
334
|
readonly 'env.bridge.daemon': "后台服务没起来:正常它会自己起,先在终端跑下面这条命令。";
|
|
334
335
|
readonly 'env.bridge.extension': "浏览器扩展没连上:在 Chrome 应用商店装一次就好(装完回来点「重试」)。已经装过的话,先跑下面这条命令。";
|
|
335
336
|
readonly 'env.bridge.extensionLink': "去 Chrome 应用商店装扩展";
|
|
@@ -347,11 +348,21 @@ export declare const zh: {
|
|
|
347
348
|
readonly 'env.fix.network': "网络不通:检查网络或代理设置后重试。";
|
|
348
349
|
readonly 'env.fix.details': "详细输出(排障用)";
|
|
349
350
|
readonly 'env.retry': "重试";
|
|
351
|
+
readonly 'env.bridge.continue': "先进入工作台";
|
|
352
|
+
readonly 'env.diy.ok': "可用";
|
|
353
|
+
readonly 'env.diy.short': "挂不起来";
|
|
354
|
+
readonly 'env.diy.hold': "DIY 模式挂不起来 —— 升级 dsh 后点「重试」,也可以先进工作台。";
|
|
355
|
+
readonly 'env.diy.why': "「工作台 DIY」是 dsh 的一个 agent preset,而它是照这份外壳验过的那一代 dsh 生成的:这台机器上的 dsh 比它旧,其中几行 dsh 根本没有,于是这个模式整个挂不起来。dsh 的模式选择器只列挂得起来的,进去之后它会整个不出现 —— 面板与其它功能不受影响。";
|
|
356
|
+
readonly 'env.diy.rows': "这一代 dsh 缺这几行:{rows}";
|
|
357
|
+
readonly 'env.diy.noRow': "体检没在 dsh 的 preset 名单里看到「工作台 DIY」—— 多半是这份 bundle 的 preset 补丁没生效。";
|
|
358
|
+
readonly 'env.diy.step': "升级 dsh,然后重启一次工作台:";
|
|
359
|
+
readonly 'env.diy.continue': "先进入工作台";
|
|
350
360
|
readonly 'env.copyCommand': "复制命令";
|
|
351
361
|
readonly 'env.copied': "已复制";
|
|
352
362
|
readonly 'env.step.opencli': "检测工作台的 opencli";
|
|
353
363
|
readonly 'env.step.codingPlugin': "检测 coding 插件";
|
|
354
364
|
readonly 'env.step.bridge': "检测浏览器通道";
|
|
365
|
+
readonly 'env.step.diy': "检查 DIY 模式";
|
|
355
366
|
readonly 'env.step.warm': "预热站点登录态";
|
|
356
367
|
readonly 'env.warm.done': "已预热 {n} 个站点";
|
|
357
368
|
readonly 'env.warm.short': "这次没热上 —— 不影响用,面板第一次读取会自己补";
|
package/dist/i18n/zh.js
CHANGED
|
@@ -329,7 +329,8 @@ export const zh = {
|
|
|
329
329
|
'env.stepFailed.shell': '执行通道不可用',
|
|
330
330
|
'env.bridge.ok': '已连接',
|
|
331
331
|
'env.bridge.short': '没连上',
|
|
332
|
-
'env.bridge.why': '
|
|
332
|
+
'env.bridge.why': '面板的数据要走你浏览器里的登录态:这个通道没连上,模块就取不到数据(不拦路:修好它,或者先进入工作台)。',
|
|
333
|
+
'env.bridge.hold': '浏览器通道还没连上 —— 按下面修好后点「重试」,也可以先进工作台。',
|
|
333
334
|
'env.bridge.daemon': '后台服务没起来:正常它会自己起,先在终端跑下面这条命令。',
|
|
334
335
|
'env.bridge.extension': '浏览器扩展没连上:在 Chrome 应用商店装一次就好(装完回来点「重试」)。已经装过的话,先跑下面这条命令。',
|
|
335
336
|
'env.bridge.extensionLink': '去 Chrome 应用商店装扩展',
|
|
@@ -347,11 +348,21 @@ export const zh = {
|
|
|
347
348
|
'env.fix.network': '网络不通:检查网络或代理设置后重试。',
|
|
348
349
|
'env.fix.details': '详细输出(排障用)',
|
|
349
350
|
'env.retry': '重试',
|
|
351
|
+
'env.bridge.continue': '先进入工作台',
|
|
352
|
+
'env.diy.ok': '可用',
|
|
353
|
+
'env.diy.short': '挂不起来',
|
|
354
|
+
'env.diy.hold': 'DIY 模式挂不起来 —— 升级 dsh 后点「重试」,也可以先进工作台。',
|
|
355
|
+
'env.diy.why': '「工作台 DIY」是 dsh 的一个 agent preset,而它是照这份外壳验过的那一代 dsh 生成的:这台机器上的 dsh 比它旧,其中几行 dsh 根本没有,于是这个模式整个挂不起来。dsh 的模式选择器只列挂得起来的,进去之后它会整个不出现 —— 面板与其它功能不受影响。',
|
|
356
|
+
'env.diy.rows': '这一代 dsh 缺这几行:{rows}',
|
|
357
|
+
'env.diy.noRow': '体检没在 dsh 的 preset 名单里看到「工作台 DIY」—— 多半是这份 bundle 的 preset 补丁没生效。',
|
|
358
|
+
'env.diy.step': '升级 dsh,然后重启一次工作台:',
|
|
359
|
+
'env.diy.continue': '先进入工作台',
|
|
350
360
|
'env.copyCommand': '复制命令',
|
|
351
361
|
'env.copied': '已复制',
|
|
352
362
|
'env.step.opencli': '检测工作台的 opencli',
|
|
353
363
|
'env.step.codingPlugin': '检测 coding 插件',
|
|
354
364
|
'env.step.bridge': '检测浏览器通道',
|
|
365
|
+
'env.step.diy': '检查 DIY 模式',
|
|
355
366
|
'env.step.warm': '预热站点登录态',
|
|
356
367
|
'env.warm.done': '已预热 {n} 个站点',
|
|
357
368
|
'env.warm.short': '这次没热上 —— 不影响用,面板第一次读取会自己补',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useLintProbe(): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import {
|
|
3
3
|
longTaskDot,
|
|
4
|
+
longTaskIsLive,
|
|
4
5
|
longTaskPollMs,
|
|
5
6
|
longTaskRunsOf,
|
|
6
7
|
longTaskStopPress,
|
|
@@ -38,6 +39,20 @@ describe('longTaskDot', () => {
|
|
|
38
39
|
});
|
|
39
40
|
});
|
|
40
41
|
|
|
42
|
+
describe('longTaskIsLive(调用点判「还在跑」用的那个谓词)', () => {
|
|
43
|
+
it('★ 只认 running 与 needs-login —— 与 longTaskDot 的 ongoing 同一口径', () => {
|
|
44
|
+
for (const status of ['running', 'needs-login', 'ok', 'failed', 'stopped'] as const) {
|
|
45
|
+
expect(longTaskIsLive(status)).toBe(longTaskDot(status) === 'ongoing');
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('★ 结束的三态(成功 / 失败 / 用户按停)都不是"在跑"', () => {
|
|
50
|
+
expect(longTaskIsLive('ok')).toBe(false);
|
|
51
|
+
expect(longTaskIsLive('failed')).toBe(false);
|
|
52
|
+
expect(longTaskIsLive('stopped')).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
41
56
|
describe('longTaskStopStage / longTaskStopPress(两按:第一次上膛,第二次才真发)', () => {
|
|
42
57
|
it('★ 三档:没上膛 / 上了膛 / 请求在飞;在飞压过一切', () => {
|
|
43
58
|
expect(longTaskStopStage({ armed: false, busy: false })).toBe('idle');
|
package/src/api/dsh.ts
CHANGED
|
@@ -178,6 +178,22 @@ export interface DshWorkspaceRegistry {
|
|
|
178
178
|
create(path: string, title?: string): Promise<{ id?: string; path?: string; title?: string } | undefined>;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
/**
|
|
182
|
+
* agent preset 名单里的一行:id 与显示名;`broken` 非空表示这一行**挂不起来**(dsh 自己给的原因原文)。
|
|
183
|
+
*/
|
|
184
|
+
export interface DshAgentPresetRow {
|
|
185
|
+
readonly id: string;
|
|
186
|
+
readonly name?: string;
|
|
187
|
+
readonly broken?: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 宿主侧的 agent preset 名册(服务名 `agentPresets`):只读它的 `list()` —— 启动体检拿它判 DIY 模式挂不挂得起来。
|
|
192
|
+
*/
|
|
193
|
+
export interface DshAgentPresetRegistry {
|
|
194
|
+
list(): Promise<readonly DshAgentPresetRow[]>;
|
|
195
|
+
}
|
|
196
|
+
|
|
181
197
|
/**
|
|
182
198
|
* 把相对路径拼成 dsh home 下的绝对路径(服务名 dshHomePath);外壳存自己的状态用它,不自己拼 home。
|
|
183
199
|
*/
|
package/src/api/long-task.ts
CHANGED
|
@@ -82,6 +82,17 @@ export function longTaskDot(status: LongTaskStatus): 'ongoing' | 'done' | 'error
|
|
|
82
82
|
return 'idle';
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* 这一趟还在不在跑(`running` 与 `needs-login` 都算)。
|
|
87
|
+
* 卡片要判"这一行要不要摆停止钮""这套环境里有没有活着的跑"时用这个 —— **不是** `longTaskDot`:
|
|
88
|
+
* 那一件是状态点的**长相**(四档),归 `LongTaskRow` 自己用,不该被调用点拿去当判据。
|
|
89
|
+
* @param status 长任务的五种态。
|
|
90
|
+
* @returns 在跑 `true`;成功 / 失败 / 用户按停都是 `false`。
|
|
91
|
+
*/
|
|
92
|
+
export function longTaskIsLive(status: LongTaskStatus): boolean {
|
|
93
|
+
return status === 'running' || status === 'needs-login';
|
|
94
|
+
}
|
|
95
|
+
|
|
85
96
|
/**
|
|
86
97
|
* 停止钮的三档:没上膛 / 上了膛 / 请求在飞。
|
|
87
98
|
*/
|
package/src/i18n/en.ts
CHANGED
|
@@ -340,7 +340,8 @@ export const en: Record<keyof WorkbenchMessages, string> = {
|
|
|
340
340
|
'env.stepFailed.shell': 'no shell channel',
|
|
341
341
|
'env.bridge.ok': 'Connected',
|
|
342
342
|
'env.bridge.short': 'Not connected',
|
|
343
|
-
'env.bridge.why': 'Panel data goes through the login state in your browser: with this channel down, modules cannot fetch data. It does not block startup
|
|
343
|
+
'env.bridge.why': 'Panel data goes through the login state in your browser: with this channel down, modules cannot fetch data. It does not block startup: fix it, or enter the workbench first.',
|
|
344
|
+
'env.bridge.hold': 'The browser bridge is not connected yet \u2014 fix it below and hit Retry, or enter the workbench first.',
|
|
344
345
|
'env.bridge.daemon': 'The background service is not running. It usually starts by itself \u2014 run the command below in your terminal first.',
|
|
345
346
|
'env.bridge.extension': 'The browser extension is not connected. Install it once from the Chrome Web Store (then hit Retry here). If it is already installed, run the command below first.',
|
|
346
347
|
'env.bridge.extensionLink': 'Get the extension in the Chrome Web Store',
|
|
@@ -358,11 +359,21 @@ export const en: Record<keyof WorkbenchMessages, string> = {
|
|
|
358
359
|
'env.fix.network': 'Network unreachable: check your network or proxy, then retry.',
|
|
359
360
|
'env.fix.details': 'Details (for troubleshooting)',
|
|
360
361
|
'env.retry': 'Retry',
|
|
362
|
+
'env.bridge.continue': 'Enter the workbench anyway',
|
|
363
|
+
'env.diy.ok': 'Available',
|
|
364
|
+
'env.diy.short': 'Cannot load',
|
|
365
|
+
'env.diy.hold': 'DIY mode cannot load \u2014 upgrade dsh, then hit Retry; or enter the workbench first.',
|
|
366
|
+
'env.diy.why': '\u201cWorkbench DIY\u201d is a dsh agent preset, and it is generated from the dsh generation this shell was verified against. The dsh on this machine is older and does not ship some of those rows, so the whole preset fails to mount. dsh lists only the presets that mount, so the mode will simply not appear \u2014 panels and everything else are unaffected.',
|
|
367
|
+
'env.diy.rows': 'This dsh is missing these rows: {rows}',
|
|
368
|
+
'env.diy.noRow': 'The health check did not find \u201cWorkbench DIY\u201d in dsh\u2019s preset roster \u2014 most likely this bundle\u2019s preset patch did not apply.',
|
|
369
|
+
'env.diy.step': 'Upgrade dsh, then restart the workbench:',
|
|
370
|
+
'env.diy.continue': 'Enter the workbench anyway',
|
|
361
371
|
'env.copyCommand': 'Copy command',
|
|
362
372
|
'env.copied': 'Copied',
|
|
363
373
|
'env.step.opencli': 'Checking the workbench opencli',
|
|
364
374
|
'env.step.codingPlugin': 'Checking the coding plugin',
|
|
365
375
|
'env.step.bridge': 'Checking the browser bridge',
|
|
376
|
+
'env.step.diy': 'Checking DIY mode',
|
|
366
377
|
'env.step.warm': 'Warming up site sessions',
|
|
367
378
|
'env.warm.done': '{n} site(s) warmed up',
|
|
368
379
|
'env.warm.short': 'Not warmed this time — harmless; the panel heals on first read',
|
package/src/i18n/zh.ts
CHANGED
|
@@ -335,7 +335,8 @@ export const zh = {
|
|
|
335
335
|
'env.stepFailed.shell': '执行通道不可用',
|
|
336
336
|
'env.bridge.ok': '已连接',
|
|
337
337
|
'env.bridge.short': '没连上',
|
|
338
|
-
'env.bridge.why': '
|
|
338
|
+
'env.bridge.why': '面板的数据要走你浏览器里的登录态:这个通道没连上,模块就取不到数据(不拦路:修好它,或者先进入工作台)。',
|
|
339
|
+
'env.bridge.hold': '浏览器通道还没连上 —— 按下面修好后点「重试」,也可以先进工作台。',
|
|
339
340
|
'env.bridge.daemon': '后台服务没起来:正常它会自己起,先在终端跑下面这条命令。',
|
|
340
341
|
'env.bridge.extension': '浏览器扩展没连上:在 Chrome 应用商店装一次就好(装完回来点「重试」)。已经装过的话,先跑下面这条命令。',
|
|
341
342
|
'env.bridge.extensionLink': '去 Chrome 应用商店装扩展',
|
|
@@ -353,11 +354,21 @@ export const zh = {
|
|
|
353
354
|
'env.fix.network': '网络不通:检查网络或代理设置后重试。',
|
|
354
355
|
'env.fix.details': '详细输出(排障用)',
|
|
355
356
|
'env.retry': '重试',
|
|
357
|
+
'env.bridge.continue': '先进入工作台',
|
|
358
|
+
'env.diy.ok': '可用',
|
|
359
|
+
'env.diy.short': '挂不起来',
|
|
360
|
+
'env.diy.hold': 'DIY 模式挂不起来 —— 升级 dsh 后点「重试」,也可以先进工作台。',
|
|
361
|
+
'env.diy.why': '「工作台 DIY」是 dsh 的一个 agent preset,而它是照这份外壳验过的那一代 dsh 生成的:这台机器上的 dsh 比它旧,其中几行 dsh 根本没有,于是这个模式整个挂不起来。dsh 的模式选择器只列挂得起来的,进去之后它会整个不出现 —— 面板与其它功能不受影响。',
|
|
362
|
+
'env.diy.rows': '这一代 dsh 缺这几行:{rows}',
|
|
363
|
+
'env.diy.noRow': '体检没在 dsh 的 preset 名单里看到「工作台 DIY」—— 多半是这份 bundle 的 preset 补丁没生效。',
|
|
364
|
+
'env.diy.step': '升级 dsh,然后重启一次工作台:',
|
|
365
|
+
'env.diy.continue': '先进入工作台',
|
|
356
366
|
'env.copyCommand': '复制命令',
|
|
357
367
|
'env.copied': '已复制',
|
|
358
368
|
'env.step.opencli': '检测工作台的 opencli',
|
|
359
369
|
'env.step.codingPlugin': '检测 coding 插件',
|
|
360
370
|
'env.step.bridge': '检测浏览器通道',
|
|
371
|
+
'env.step.diy': '检查 DIY 模式',
|
|
361
372
|
'env.step.warm': '预热站点登录态',
|
|
362
373
|
'env.warm.done': '已预热 {n} 个站点',
|
|
363
374
|
'env.warm.short': '这次没热上 —— 不影响用,面板第一次读取会自己补',
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { h } from '../lib/react.js';
|
|
2
|
-
export function StateDot({ state, size }) {
|
|
3
|
-
if (state === 'ongoing') {
|
|
4
|
-
return (h("svg", { className: "wb-loading", viewBox: "0 0 24 24", width: size, height: size, "aria-hidden": "true", style: { display: 'block' } },
|
|
5
|
-
h("g", { className: "wb-loadingMotion" },
|
|
6
|
-
h("circle", { className: "wb-loadingTrack", cx: 12, cy: 12, r: 9.5 }),
|
|
7
|
-
h("circle", { className: "wb-loadingArc", cx: 12, cy: 12, r: 9.5 }))));
|
|
8
|
-
}
|
|
9
|
-
return (h("span", { className: "wb-stateDot", "data-state": state, style: { width: size, height: size }, "aria-hidden": "true" }));
|
|
10
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { DshShell } from '../../api/dsh.js';
|
|
2
|
-
import type { Opencli } from '../../host/opencli.js';
|
|
3
|
-
export interface ShellCall {
|
|
4
|
-
command: string;
|
|
5
|
-
workdir?: string;
|
|
6
|
-
timeoutMs?: number;
|
|
7
|
-
onExpiry?: string;
|
|
8
|
-
stdoutMaxBytes?: number;
|
|
9
|
-
}
|
|
10
|
-
export interface ShellReply {
|
|
11
|
-
stdout?: string;
|
|
12
|
-
stderr?: string;
|
|
13
|
-
exitCode?: number | null;
|
|
14
|
-
timedOut?: boolean;
|
|
15
|
-
aborted?: boolean;
|
|
16
|
-
failWith?: Error;
|
|
17
|
-
}
|
|
18
|
-
export declare function createFakeShell(replies?: ShellReply[] | ((call: ShellCall, index: number) => ShellReply)): {
|
|
19
|
-
shell: DshShell;
|
|
20
|
-
calls: ShellCall[];
|
|
21
|
-
peak: () => number;
|
|
22
|
-
commands: () => string[];
|
|
23
|
-
};
|
|
24
|
-
export interface OpencliCall {
|
|
25
|
-
args: readonly string[];
|
|
26
|
-
key?: string;
|
|
27
|
-
workdir?: string;
|
|
28
|
-
refresh?: boolean;
|
|
29
|
-
}
|
|
30
|
-
export declare function createFakeOpencli(replies?: Array<unknown | Error> | ((call: OpencliCall, index: number) => unknown | Error)): {
|
|
31
|
-
opencli: Opencli;
|
|
32
|
-
calls: OpencliCall[];
|
|
33
|
-
keys: () => (string | undefined)[];
|
|
34
|
-
};
|
|
35
|
-
export declare function createFakeLogger(): {
|
|
36
|
-
logger: {
|
|
37
|
-
info: () => void;
|
|
38
|
-
warn: (message: string) => void;
|
|
39
|
-
};
|
|
40
|
-
warnings: string[];
|
|
41
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { setTimeout as delay } from 'node:timers/promises';
|
|
2
|
-
const tick = () => delay(0);
|
|
3
|
-
export function createFakeShell(replies = []) {
|
|
4
|
-
const calls = [];
|
|
5
|
-
let running = 0;
|
|
6
|
-
let peak = 0;
|
|
7
|
-
const replyAt = (index) => typeof replies === 'function' ? replies(calls[index], index) : (replies[index] ?? {});
|
|
8
|
-
const shell = {
|
|
9
|
-
resolve(request) {
|
|
10
|
-
calls.push(request);
|
|
11
|
-
return request;
|
|
12
|
-
},
|
|
13
|
-
async execute() {
|
|
14
|
-
const index = calls.length - 1;
|
|
15
|
-
const reply = replyAt(index);
|
|
16
|
-
if (reply.failWith !== undefined)
|
|
17
|
-
throw reply.failWith;
|
|
18
|
-
running += 1;
|
|
19
|
-
peak = Math.max(peak, running);
|
|
20
|
-
return {
|
|
21
|
-
async result() {
|
|
22
|
-
await tick();
|
|
23
|
-
running -= 1;
|
|
24
|
-
return {
|
|
25
|
-
exitCode: reply.exitCode ?? 0,
|
|
26
|
-
timedOut: reply.timedOut ?? false,
|
|
27
|
-
aborted: reply.aborted ?? false,
|
|
28
|
-
stdout: { text: reply.stdout ?? '', truncated: false },
|
|
29
|
-
stderr: { text: reply.stderr ?? '', truncated: false },
|
|
30
|
-
};
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
return {
|
|
36
|
-
shell,
|
|
37
|
-
calls,
|
|
38
|
-
peak: () => peak,
|
|
39
|
-
commands: () => calls.map((call) => call.command),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
export function createFakeOpencli(replies = []) {
|
|
43
|
-
const calls = [];
|
|
44
|
-
const opencli = {
|
|
45
|
-
async json(args, options = {}) {
|
|
46
|
-
const call = {
|
|
47
|
-
args,
|
|
48
|
-
...(options.key === undefined ? {} : { key: options.key }),
|
|
49
|
-
...(options.workdir === undefined ? {} : { workdir: options.workdir }),
|
|
50
|
-
};
|
|
51
|
-
calls.push(call);
|
|
52
|
-
const index = calls.length - 1;
|
|
53
|
-
const reply = typeof replies === 'function' ? replies(call, index) : (replies[index] ?? []);
|
|
54
|
-
if (reply instanceof Error)
|
|
55
|
-
throw reply;
|
|
56
|
-
return { value: reply, at: Date.now() };
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return {
|
|
60
|
-
opencli,
|
|
61
|
-
calls,
|
|
62
|
-
keys: () => calls.map((call) => call.key),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
export function createFakeLogger() {
|
|
66
|
-
const warnings = [];
|
|
67
|
-
return {
|
|
68
|
-
logger: {
|
|
69
|
-
info: () => { },
|
|
70
|
-
warn: (message) => {
|
|
71
|
-
warnings.push(message);
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
warnings,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { createFakeShell } from './fakes';
|
|
2
|
-
export declare const GOOD_BRIDGE_REPORT: string;
|
|
3
|
-
export declare const ALL_OK: {
|
|
4
|
-
stdout: string;
|
|
5
|
-
}[];
|
|
6
|
-
export declare const STALE_DAEMON_BRIDGE: string;
|
|
7
|
-
export declare const BROKEN_BRIDGE: string;
|
|
8
|
-
export declare function build(replies: Parameters<typeof createFakeShell>[0], install?: () => Promise<{
|
|
9
|
-
ok: boolean;
|
|
10
|
-
detail: string;
|
|
11
|
-
}>, warmReads?: () => readonly (readonly string[])[]): {
|
|
12
|
-
fake: {
|
|
13
|
-
shell: import("../..").DshShell;
|
|
14
|
-
calls: import("./fakes").ShellCall[];
|
|
15
|
-
peak: () => number;
|
|
16
|
-
commands: () => string[];
|
|
17
|
-
};
|
|
18
|
-
preflight: import("../preflight").Preflight;
|
|
19
|
-
};
|