@dsh-workbench/shared 0.2.15 → 0.2.16
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/host-write.d.ts +1 -1
- package/dist/components/FormRows.css +10 -4
- package/dist/components/Rows.css +12 -5
- package/dist/config/constants.d.ts +2 -0
- package/dist/config/constants.js +2 -0
- package/dist/host/http.d.ts +3 -0
- package/dist/host/http.js +10 -1
- package/dist/host.d.ts +1 -0
- package/dist/host.js +1 -0
- package/dist/i18n/en.js +13 -7
- package/dist/i18n/index.d.ts +14 -8
- package/dist/i18n/zh.d.ts +13 -7
- package/dist/i18n/zh.js +13 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/board-fact.d.ts +13 -0
- package/dist/lib/board-fact.js +28 -0
- package/dist/lib/diy-debug.d.ts +2 -1
- package/dist/lib/diy-debug.js +3 -10
- package/package.json +1 -1
- package/src/api/host-write.ts +5 -1
- package/src/components/FormRows.css +10 -4
- package/src/components/Rows.css +12 -5
- package/src/config/constants.ts +3 -0
- package/src/host/http.ts +16 -3
- package/src/host.ts +1 -0
- package/src/i18n/en.ts +13 -7
- package/src/i18n/zh.ts +13 -7
- package/src/index.ts +1 -0
- package/src/lib/board-fact.test.ts +86 -0
- package/src/lib/board-fact.ts +45 -0
- package/src/lib/diy-debug.test.ts +15 -8
- package/src/lib/diy-debug.ts +6 -10
package/dist/api/host-write.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiResponse } from './workbench-client.js';
|
|
2
|
-
export type WriteChannel = 'prefs' | 'actions' | 'provision';
|
|
2
|
+
export type WriteChannel = 'prefs' | 'actions' | 'provision' | 'diy-debug';
|
|
3
3
|
export declare function writeRoute(channel: WriteChannel, resource: string): string;
|
|
4
4
|
export type WriteOutcome<T> = {
|
|
5
5
|
readonly ok: true;
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
row-gap: var(--wb-len-8);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
.wb-formRows > .wb-formRow {
|
|
22
|
-
grid-template-columns: subgrid;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
21
|
.wb-formRow[data-layout='stacked'] {
|
|
26
22
|
grid-template-columns: minmax(0, 1fr);
|
|
27
23
|
align-items: stretch;
|
|
@@ -67,3 +63,13 @@
|
|
|
67
63
|
.wb-formRow:has(:disabled) .wb-formLabel {
|
|
68
64
|
opacity: 0.4;
|
|
69
65
|
}
|
|
66
|
+
|
|
67
|
+
.wb-formRows > .wb-formRow {
|
|
68
|
+
grid-template-columns: subgrid;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@supports not (grid-template-columns: subgrid) {
|
|
72
|
+
.wb-formRows > .wb-formRow {
|
|
73
|
+
grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/dist/components/Rows.css
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
.wb-row:has(> [data-wb-dot]) {
|
|
3
|
-
grid-template-columns: 84px minmax(0, 1fr);
|
|
4
|
-
}
|
|
5
1
|
.wb-rows {
|
|
6
2
|
display: flex;
|
|
7
3
|
flex-direction: column;
|
|
8
4
|
}
|
|
9
5
|
.wb-row {
|
|
10
6
|
display: grid;
|
|
11
|
-
grid-template-columns:
|
|
7
|
+
grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
|
|
12
8
|
align-items: baseline;
|
|
13
9
|
gap: var(--wb-len-8);
|
|
14
10
|
padding: var(--wb-len-4) 0;
|
|
@@ -17,6 +13,7 @@
|
|
|
17
13
|
border-top: 0.5px solid var(--dsw-alias-border-l2);
|
|
18
14
|
}
|
|
19
15
|
.wb-rowKey {
|
|
16
|
+
white-space: nowrap;
|
|
20
17
|
font-size: var(--dsw-font-xxxs-11-font-size);
|
|
21
18
|
line-height: var(--wb-line-16);
|
|
22
19
|
color: var(--dsw-alias-label-tertiary);
|
|
@@ -28,3 +25,13 @@
|
|
|
28
25
|
color: var(--dsw-alias-label-primary);
|
|
29
26
|
overflow-wrap: anywhere;
|
|
30
27
|
}
|
|
28
|
+
|
|
29
|
+
.wb-rows > .wb-row {
|
|
30
|
+
grid-template-columns: subgrid;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@supports not (grid-template-columns: subgrid) {
|
|
34
|
+
.wb-rows > .wb-row {
|
|
35
|
+
grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -6,6 +6,8 @@ export declare const EVENTS_PATH = "/workbench/events";
|
|
|
6
6
|
export declare const ACTIONS_PREFIX = "/workbench/api/actions";
|
|
7
7
|
export declare const PROVISION_PREFIX = "/workbench/api/provision";
|
|
8
8
|
export declare const PANEL_STATE_PATH = "panel-state";
|
|
9
|
+
export declare const DIY_DEBUG_PATH = "diy-debug";
|
|
10
|
+
export declare const DIY_DEBUG_ACT_PATH = "diy-debug/act";
|
|
9
11
|
export declare const PANEL_STATE_PREFIX = "/workbench/api/panel-state";
|
|
10
12
|
export declare const OPENCLI_PIN = "1.8.8";
|
|
11
13
|
export declare const CODING_ISSUES_SERVICE = "workbenchCodingIssues";
|
package/dist/config/constants.js
CHANGED
|
@@ -9,6 +9,8 @@ export const EVENTS_PATH = "/workbench/events";
|
|
|
9
9
|
export const ACTIONS_PREFIX = `${API_PREFIX}/actions`;
|
|
10
10
|
export const PROVISION_PREFIX = `${API_PREFIX}/provision`;
|
|
11
11
|
export const PANEL_STATE_PATH = "panel-state";
|
|
12
|
+
export const DIY_DEBUG_PATH = "diy-debug";
|
|
13
|
+
export const DIY_DEBUG_ACT_PATH = `${DIY_DEBUG_PATH}/act`;
|
|
12
14
|
export const PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
|
|
13
15
|
export const OPENCLI_PIN = "1.8.8";
|
|
14
16
|
export const CODING_ISSUES_SERVICE = "workbenchCodingIssues";
|
package/dist/host/http.d.ts
CHANGED
|
@@ -41,3 +41,6 @@ export declare function healthHandler(ctx: DshHostContext, opencli?: OpencliHeal
|
|
|
41
41
|
export declare function registerPrefs(ctx: DshHostContext, resources: readonly PostResource[], wrote?: ((resource: string, write: PostWrite) => void) | undefined): () => void;
|
|
42
42
|
export declare function registerActions(ctx: DshHostContext, resources: readonly PostResource[], wrote?: ((resource: string, write: PostWrite) => void) | undefined): () => void;
|
|
43
43
|
export declare function registerPanelState(ctx: DshHostContext, store: PanelStateStore): () => void;
|
|
44
|
+
export declare function registerDiyDebugAct(ctx: DshHostContext, resource: PostResource, log?: {
|
|
45
|
+
bump(facts: readonly string[]): unknown;
|
|
46
|
+
} | undefined): () => void;
|
package/dist/host/http.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { unitFactScope } from '../api/facts.js';
|
|
2
2
|
import { parseCardsReport, parseCrashReport } from '../lib/panel-state.js';
|
|
3
|
-
import { ACTIONS_PREFIX, API_PREFIX, PANEL_STATE_PREFIX, PLUGIN_ID, PREFS_PREFIX, PROVISION_PREFIX } from '../config/constants.js';
|
|
3
|
+
import { ACTIONS_PREFIX, API_PREFIX, DIY_DEBUG_PATH, PANEL_STATE_PREFIX, PLUGIN_ID, PREFS_PREFIX, PROVISION_PREFIX } from '../config/constants.js';
|
|
4
4
|
import { parseProvisionBody, } from './provision.js';
|
|
5
5
|
import { WorkbenchDataError } from '../host/opencli.js';
|
|
6
6
|
import { writeResultForClient } from './write-result.js';
|
|
@@ -255,3 +255,12 @@ export function registerPanelState(ctx, store) {
|
|
|
255
255
|
],
|
|
256
256
|
});
|
|
257
257
|
}
|
|
258
|
+
export function registerDiyDebugAct(ctx, resource, log) {
|
|
259
|
+
return registerPost(ctx, {
|
|
260
|
+
prefix: `${API_PREFIX}/${DIY_DEBUG_PATH}`,
|
|
261
|
+
what: '工作台 DIY 调试动作',
|
|
262
|
+
refusedCode: 'action-refused',
|
|
263
|
+
resources: [resource],
|
|
264
|
+
wrote: () => log?.bump(['diy-debug']),
|
|
265
|
+
});
|
|
266
|
+
}
|
package/dist/host.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './api/long-task.js';
|
|
|
7
7
|
export * from './lib/text.js';
|
|
8
8
|
export * from './lib/ui.js';
|
|
9
9
|
export * from './lib/panel-state.js';
|
|
10
|
+
export * from './lib/board-fact.js';
|
|
10
11
|
export * from './lib/diy-debug.js';
|
|
11
12
|
export * from './api/blocker-table.js';
|
|
12
13
|
export * from './host/browser-find.js';
|
package/dist/host.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './api/long-task.js';
|
|
|
7
7
|
export * from './lib/text.js';
|
|
8
8
|
export * from './lib/ui.js';
|
|
9
9
|
export * from './lib/panel-state.js';
|
|
10
|
+
export * from './lib/board-fact.js';
|
|
10
11
|
export * from './lib/diy-debug.js';
|
|
11
12
|
export * from './api/blocker-table.js';
|
|
12
13
|
export * from './host/browser-find.js';
|
package/dist/i18n/en.js
CHANGED
|
@@ -406,12 +406,18 @@ export const en = {
|
|
|
406
406
|
'configSync.noSource': 'This machine has no other profile to sync from',
|
|
407
407
|
'configSync.emptyProviders': 'The workbench has no model provider yet — sync the llm- rows from some profile, or configure one under Models.',
|
|
408
408
|
'configSync.failed': 'The sync did not go through; try again.',
|
|
409
|
-
'debug.status': '
|
|
410
|
-
'debug.
|
|
411
|
-
'debug.
|
|
412
|
-
'debug.
|
|
409
|
+
'debug.status': 'Workbench DIY debugging',
|
|
410
|
+
'debug.status.trouble': 'Workbench DIY debugging needs attention',
|
|
411
|
+
'debug.stalled': 'Workbench DIY debugging paused',
|
|
412
|
+
'debug.act.pause': 'Pause debugging',
|
|
413
|
+
'debug.act.resume': 'Resume debugging',
|
|
414
|
+
'debug.act.stop': 'Stop debugging',
|
|
415
|
+
'debug.act.stop.ask': 'Confirm stop',
|
|
416
|
+
'debug.card.here.title': 'Workbench DIY debugging is on',
|
|
417
|
+
'debug.card.here.note': 'Do not switch workspaces or touch the panel',
|
|
418
|
+
'debug.card.away.title': 'Workbench DIY debugging is on',
|
|
419
|
+
'debug.card.away.note': 'Switch to the Workbench DIY workspace',
|
|
420
|
+
'debug.card.paused.note': 'Paused',
|
|
421
|
+
'debug.card.hidden.note': 'Switch to the Workbench panel',
|
|
413
422
|
'debug.back': 'Back to the workshop screen',
|
|
414
|
-
'debug.strip.active': 'Debugging · {unit} · {since}',
|
|
415
|
-
'debug.strip.note': 'Tell the agent to pause when you are done',
|
|
416
|
-
'debug.stripStalled': 'Debug stalled — tell the agent to continue',
|
|
417
423
|
};
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -408,16 +408,22 @@ export declare const dictionaries: {
|
|
|
408
408
|
readonly 'configSync.noSource': "这台机器上只有工作台这一个 profile,没有可同步的来源";
|
|
409
409
|
readonly 'configSync.emptyProviders': "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把 llm- 那几行搬过来,或自己去「模型」里配。";
|
|
410
410
|
readonly 'configSync.failed': "同步没成功,再试一次。";
|
|
411
|
-
readonly 'debug.status': "
|
|
412
|
-
readonly 'debug.
|
|
413
|
-
readonly 'debug.
|
|
414
|
-
readonly 'debug.
|
|
411
|
+
readonly 'debug.status': "工作台 DIY 开发调试中";
|
|
412
|
+
readonly 'debug.status.trouble': "工作台 DIY 开发调试异常";
|
|
413
|
+
readonly 'debug.stalled': "工作台 DIY 调试暂停";
|
|
414
|
+
readonly 'debug.act.pause': "暂停调试";
|
|
415
|
+
readonly 'debug.act.resume': "继续调试";
|
|
416
|
+
readonly 'debug.act.stop': "结束调试";
|
|
417
|
+
readonly 'debug.act.stop.ask': "确认结束";
|
|
418
|
+
readonly 'debug.card.here.title': "当前工作台 DIY 开发调试中";
|
|
419
|
+
readonly 'debug.card.here.note': "请勿切换工作区和操作面板";
|
|
420
|
+
readonly 'debug.card.away.title': "工作台 DIY 开发调试中";
|
|
421
|
+
readonly 'debug.card.away.note': "请切换到工作台 DIY 工作区";
|
|
422
|
+
readonly 'debug.card.paused.note': "已暂停";
|
|
423
|
+
readonly 'debug.card.hidden.note': "请切换到工作台面板";
|
|
415
424
|
readonly 'debug.back': "回到工坊那一屏";
|
|
416
|
-
readonly 'debug.strip.active': "调试中 · {unit} · {since}";
|
|
417
|
-
readonly 'debug.strip.note': "要停就对 agent 说一句「暂停」";
|
|
418
|
-
readonly 'debug.stripStalled': "调试搁置 —— 对 agent 说一句「继续」";
|
|
419
425
|
};
|
|
420
|
-
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.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.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.status" | "debug.stalled" | "debug.tip.active" | "debug.tip.stalled" | "debug.back" | "debug.strip.active" | "debug.strip.note" | "debug.stripStalled", string>;
|
|
426
|
+
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.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.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.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.title" | "debug.card.away.note" | "debug.card.paused.note" | "debug.card.hidden.note" | "debug.back", string>;
|
|
421
427
|
};
|
|
422
428
|
export type { WorkbenchMessages };
|
|
423
429
|
export interface Dictionaries {
|
package/dist/i18n/zh.d.ts
CHANGED
|
@@ -406,13 +406,19 @@ export declare const zh: {
|
|
|
406
406
|
readonly 'configSync.noSource': "这台机器上只有工作台这一个 profile,没有可同步的来源";
|
|
407
407
|
readonly 'configSync.emptyProviders': "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把 llm- 那几行搬过来,或自己去「模型」里配。";
|
|
408
408
|
readonly 'configSync.failed': "同步没成功,再试一次。";
|
|
409
|
-
readonly 'debug.status': "
|
|
410
|
-
readonly 'debug.
|
|
411
|
-
readonly 'debug.
|
|
412
|
-
readonly 'debug.
|
|
409
|
+
readonly 'debug.status': "工作台 DIY 开发调试中";
|
|
410
|
+
readonly 'debug.status.trouble': "工作台 DIY 开发调试异常";
|
|
411
|
+
readonly 'debug.stalled': "工作台 DIY 调试暂停";
|
|
412
|
+
readonly 'debug.act.pause': "暂停调试";
|
|
413
|
+
readonly 'debug.act.resume': "继续调试";
|
|
414
|
+
readonly 'debug.act.stop': "结束调试";
|
|
415
|
+
readonly 'debug.act.stop.ask': "确认结束";
|
|
416
|
+
readonly 'debug.card.here.title': "当前工作台 DIY 开发调试中";
|
|
417
|
+
readonly 'debug.card.here.note': "请勿切换工作区和操作面板";
|
|
418
|
+
readonly 'debug.card.away.title': "工作台 DIY 开发调试中";
|
|
419
|
+
readonly 'debug.card.away.note': "请切换到工作台 DIY 工作区";
|
|
420
|
+
readonly 'debug.card.paused.note': "已暂停";
|
|
421
|
+
readonly 'debug.card.hidden.note': "请切换到工作台面板";
|
|
413
422
|
readonly 'debug.back': "回到工坊那一屏";
|
|
414
|
-
readonly 'debug.strip.active': "调试中 · {unit} · {since}";
|
|
415
|
-
readonly 'debug.strip.note': "要停就对 agent 说一句「暂停」";
|
|
416
|
-
readonly 'debug.stripStalled': "调试搁置 —— 对 agent 说一句「继续」";
|
|
417
423
|
};
|
|
418
424
|
export type WorkbenchMessages = typeof zh;
|
package/dist/i18n/zh.js
CHANGED
|
@@ -406,12 +406,18 @@ export const zh = {
|
|
|
406
406
|
'configSync.noSource': '这台机器上只有工作台这一个 profile,没有可同步的来源',
|
|
407
407
|
'configSync.emptyProviders': '工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把 llm- 那几行搬过来,或自己去「模型」里配。',
|
|
408
408
|
'configSync.failed': '同步没成功,再试一次。',
|
|
409
|
-
'debug.status': '
|
|
410
|
-
'debug.
|
|
411
|
-
'debug.
|
|
412
|
-
'debug.
|
|
409
|
+
'debug.status': '工作台 DIY 开发调试中',
|
|
410
|
+
'debug.status.trouble': '工作台 DIY 开发调试异常',
|
|
411
|
+
'debug.stalled': '工作台 DIY 调试暂停',
|
|
412
|
+
'debug.act.pause': '暂停调试',
|
|
413
|
+
'debug.act.resume': '继续调试',
|
|
414
|
+
'debug.act.stop': '结束调试',
|
|
415
|
+
'debug.act.stop.ask': '确认结束',
|
|
416
|
+
'debug.card.here.title': '当前工作台 DIY 开发调试中',
|
|
417
|
+
'debug.card.here.note': '请勿切换工作区和操作面板',
|
|
418
|
+
'debug.card.away.title': '工作台 DIY 开发调试中',
|
|
419
|
+
'debug.card.away.note': '请切换到工作台 DIY 工作区',
|
|
420
|
+
'debug.card.paused.note': '已暂停',
|
|
421
|
+
'debug.card.hidden.note': '请切换到工作台面板',
|
|
413
422
|
'debug.back': '回到工坊那一屏',
|
|
414
|
-
'debug.strip.active': '调试中 · {unit} · {since}',
|
|
415
|
-
'debug.strip.note': '要停就对 agent 说一句「暂停」',
|
|
416
|
-
'debug.stripStalled': '调试搁置 —— 对 agent 说一句「继续」',
|
|
417
423
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export * from './i18n/zh.js';
|
|
|
45
45
|
export * from './lib/blocker-action.js';
|
|
46
46
|
export * from './lib/busy.js';
|
|
47
47
|
export * from './lib/form-problem.js';
|
|
48
|
+
export * from './lib/board-fact.js';
|
|
48
49
|
export * from './lib/diy-debug.js';
|
|
49
50
|
export * from './lib/panel-state.js';
|
|
50
51
|
export * from './lib/react.js';
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ export * from './i18n/zh.js';
|
|
|
45
45
|
export * from './lib/blocker-action.js';
|
|
46
46
|
export * from './lib/busy.js';
|
|
47
47
|
export * from './lib/form-problem.js';
|
|
48
|
+
export * from './lib/board-fact.js';
|
|
48
49
|
export * from './lib/diy-debug.js';
|
|
49
50
|
export * from './lib/panel-state.js';
|
|
50
51
|
export * from './lib/react.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type BoardFactState = 'workshop' | 'other' | 'hidden' | 'unknown';
|
|
2
|
+
export type BoardSituation = 'ok' | 'off-workspace' | 'panel-closed' | 'other-board' | 'unknown';
|
|
3
|
+
export interface BoardProbe {
|
|
4
|
+
readonly workbench: boolean;
|
|
5
|
+
readonly where: string;
|
|
6
|
+
readonly bar: boolean;
|
|
7
|
+
readonly board: string;
|
|
8
|
+
readonly open: boolean;
|
|
9
|
+
readonly drawn: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function insideWorkshop(root: string, target: string): boolean;
|
|
12
|
+
export declare function boardFactOf(probe: BoardProbe, workshop: string | null): BoardFactState;
|
|
13
|
+
export declare function boardSituation(probe: BoardProbe, workshop: string | null): BoardSituation;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function insideWorkshop(root, target) {
|
|
2
|
+
if (target === root)
|
|
3
|
+
return true;
|
|
4
|
+
const base = root.endsWith('/') ? root : `${root}/`;
|
|
5
|
+
return target.startsWith(base);
|
|
6
|
+
}
|
|
7
|
+
export function boardFactOf(probe, workshop) {
|
|
8
|
+
if (!probe.workbench)
|
|
9
|
+
return 'unknown';
|
|
10
|
+
if (!probe.bar || !probe.open || !probe.drawn)
|
|
11
|
+
return 'hidden';
|
|
12
|
+
if (probe.board === '' || workshop === null)
|
|
13
|
+
return 'unknown';
|
|
14
|
+
return insideWorkshop(workshop, probe.board) ? 'workshop' : 'other';
|
|
15
|
+
}
|
|
16
|
+
export function boardSituation(probe, workshop) {
|
|
17
|
+
if (!probe.workbench || workshop === null)
|
|
18
|
+
return 'unknown';
|
|
19
|
+
const drawn = probe.bar && probe.open && probe.drawn;
|
|
20
|
+
if (drawn) {
|
|
21
|
+
if (probe.board === '')
|
|
22
|
+
return 'unknown';
|
|
23
|
+
return insideWorkshop(workshop, probe.board) ? 'ok' : 'other-board';
|
|
24
|
+
}
|
|
25
|
+
if (probe.where !== '' && !insideWorkshop(workshop, probe.where))
|
|
26
|
+
return 'off-workspace';
|
|
27
|
+
return 'panel-closed';
|
|
28
|
+
}
|
package/dist/lib/diy-debug.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type DebugPhase = 'debugging' | 'paused';
|
|
2
|
+
export type DebugIntent = 'pause' | 'resume' | 'stop';
|
|
3
|
+
export declare function parseDebugIntent(value: unknown): DebugIntent | null;
|
|
2
4
|
export declare const DEBUG_STALE_MS: number;
|
|
3
5
|
export interface DebugState {
|
|
4
6
|
readonly phase: DebugPhase;
|
|
@@ -29,7 +31,6 @@ export type DebugMove = {
|
|
|
29
31
|
export interface DebugStore {
|
|
30
32
|
live(now: number): DebugState | null;
|
|
31
33
|
begin(pact: DebugPact): DebugMove;
|
|
32
|
-
stall(sessionId: string, now: number): DebugMove;
|
|
33
34
|
pause(sessionId: string, now: number): DebugMove;
|
|
34
35
|
resume(sessionId: string, now: number): DebugMove;
|
|
35
36
|
stop(sessionId: string, now: number): DebugMove;
|
package/dist/lib/diy-debug.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export function parseDebugIntent(value) {
|
|
2
|
+
return value === 'pause' || value === 'resume' || value === 'stop' ? value : null;
|
|
3
|
+
}
|
|
1
4
|
export const DEBUG_STALE_MS = 4 * 60 * 60 * 1000;
|
|
2
5
|
function alive(state, now) {
|
|
3
6
|
if (state === null)
|
|
@@ -33,16 +36,6 @@ export function createDebugStore() {
|
|
|
33
36
|
held = state;
|
|
34
37
|
return { ok: true, state };
|
|
35
38
|
},
|
|
36
|
-
stall(sessionId, now) {
|
|
37
|
-
const found = ownerOf(held, sessionId, now);
|
|
38
|
-
if (typeof found === 'string')
|
|
39
|
-
return { ok: false, code: found };
|
|
40
|
-
if (found.phase === 'paused')
|
|
41
|
-
return { ok: false, code: 'already-paused' };
|
|
42
|
-
const state = { ...found, phase: 'paused', at: now };
|
|
43
|
-
held = state;
|
|
44
|
-
return { ok: true, state };
|
|
45
|
-
},
|
|
46
39
|
pause(sessionId, now) {
|
|
47
40
|
const found = ownerOf(held, sessionId, now);
|
|
48
41
|
if (typeof found === 'string')
|
package/package.json
CHANGED
package/src/api/host-write.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ApiResponse } from './workbench-client.js';
|
|
2
2
|
|
|
3
|
-
export type WriteChannel =
|
|
3
|
+
export type WriteChannel =
|
|
4
|
+
| 'prefs'
|
|
5
|
+
| 'actions'
|
|
6
|
+
| 'provision'
|
|
7
|
+
| 'diy-debug';
|
|
4
8
|
|
|
5
9
|
export function writeRoute(channel: WriteChannel, resource: string): string {
|
|
6
10
|
if (channel === 'provision') return 'provision';
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
row-gap: var(--wb-len-8);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
.wb-formRows > .wb-formRow {
|
|
22
|
-
grid-template-columns: subgrid;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
21
|
.wb-formRow[data-layout='stacked'] {
|
|
26
22
|
grid-template-columns: minmax(0, 1fr);
|
|
27
23
|
align-items: stretch;
|
|
@@ -67,3 +63,13 @@
|
|
|
67
63
|
.wb-formRow:has(:disabled) .wb-formLabel {
|
|
68
64
|
opacity: 0.4;
|
|
69
65
|
}
|
|
66
|
+
|
|
67
|
+
.wb-formRows > .wb-formRow {
|
|
68
|
+
grid-template-columns: subgrid;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@supports not (grid-template-columns: subgrid) {
|
|
72
|
+
.wb-formRows > .wb-formRow {
|
|
73
|
+
grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/components/Rows.css
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
.wb-row:has(> [data-wb-dot]) {
|
|
3
|
-
grid-template-columns: 84px minmax(0, 1fr);
|
|
4
|
-
}
|
|
5
1
|
.wb-rows {
|
|
6
2
|
display: flex;
|
|
7
3
|
flex-direction: column;
|
|
8
4
|
}
|
|
9
5
|
.wb-row {
|
|
10
6
|
display: grid;
|
|
11
|
-
grid-template-columns:
|
|
7
|
+
grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
|
|
12
8
|
align-items: baseline;
|
|
13
9
|
gap: var(--wb-len-8);
|
|
14
10
|
padding: var(--wb-len-4) 0;
|
|
@@ -17,6 +13,7 @@
|
|
|
17
13
|
border-top: 0.5px solid var(--dsw-alias-border-l2);
|
|
18
14
|
}
|
|
19
15
|
.wb-rowKey {
|
|
16
|
+
white-space: nowrap;
|
|
20
17
|
font-size: var(--dsw-font-xxxs-11-font-size);
|
|
21
18
|
line-height: var(--wb-line-16);
|
|
22
19
|
color: var(--dsw-alias-label-tertiary);
|
|
@@ -28,3 +25,13 @@
|
|
|
28
25
|
color: var(--dsw-alias-label-primary);
|
|
29
26
|
overflow-wrap: anywhere;
|
|
30
27
|
}
|
|
28
|
+
|
|
29
|
+
.wb-rows > .wb-row {
|
|
30
|
+
grid-template-columns: subgrid;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@supports not (grid-template-columns: subgrid) {
|
|
34
|
+
.wb-rows > .wb-row {
|
|
35
|
+
grid-template-columns: minmax(72px, max-content) minmax(0, 1fr);
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/config/constants.ts
CHANGED
|
@@ -16,6 +16,9 @@ export const PROVISION_PREFIX = `${API_PREFIX}/provision`;
|
|
|
16
16
|
|
|
17
17
|
export const PANEL_STATE_PATH = "panel-state";
|
|
18
18
|
|
|
19
|
+
export const DIY_DEBUG_PATH = "diy-debug";
|
|
20
|
+
export const DIY_DEBUG_ACT_PATH = `${DIY_DEBUG_PATH}/act`;
|
|
21
|
+
|
|
19
22
|
export const PANEL_STATE_PREFIX = `${API_PREFIX}/${PANEL_STATE_PATH}`;
|
|
20
23
|
|
|
21
24
|
export const OPENCLI_PIN = "1.8.8";
|
package/src/host/http.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { DshHostContext, DshRequest, DshResponse } from '../api/dsh.js';
|
|
2
2
|
import { unitFactScope } from '../api/facts.js';
|
|
3
3
|
import { parseCardsReport, parseCrashReport, type PanelStateStore } from '../lib/panel-state.js';
|
|
4
|
-
import { ACTIONS_PREFIX, API_PREFIX, PANEL_STATE_PREFIX, PLUGIN_ID, PREFS_PREFIX, PROVISION_PREFIX } from '../config/constants.js';
|
|
4
|
+
import { ACTIONS_PREFIX, API_PREFIX, DIY_DEBUG_PATH, PANEL_STATE_PREFIX, PLUGIN_ID, PREFS_PREFIX, PROVISION_PREFIX } from '../config/constants.js';
|
|
5
5
|
import {
|
|
6
6
|
parseProvisionBody,
|
|
7
7
|
type ProvisionHandler,
|
|
@@ -300,8 +300,7 @@ export function registerActions(
|
|
|
300
300
|
});
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
export function registerPanelState(ctx: DshHostContext, store: PanelStateStore): () => void {
|
|
304
|
-
return registerPost(ctx, {
|
|
303
|
+
export function registerPanelState(ctx: DshHostContext, store: PanelStateStore): () => void { return registerPost(ctx, {
|
|
305
304
|
prefix: PANEL_STATE_PREFIX,
|
|
306
305
|
what: '面板运行态',
|
|
307
306
|
refusedCode: 'report-refused',
|
|
@@ -327,3 +326,17 @@ export function registerPanelState(ctx: DshHostContext, store: PanelStateStore):
|
|
|
327
326
|
],
|
|
328
327
|
});
|
|
329
328
|
}
|
|
329
|
+
|
|
330
|
+
export function registerDiyDebugAct(
|
|
331
|
+
ctx: DshHostContext,
|
|
332
|
+
resource: PostResource,
|
|
333
|
+
log?: { bump(facts: readonly string[]): unknown } | undefined,
|
|
334
|
+
): () => void {
|
|
335
|
+
return registerPost(ctx, {
|
|
336
|
+
prefix: `${API_PREFIX}/${DIY_DEBUG_PATH}`,
|
|
337
|
+
what: '工作台 DIY 调试动作',
|
|
338
|
+
refusedCode: 'action-refused',
|
|
339
|
+
resources: [resource],
|
|
340
|
+
wrote: () => log?.bump(['diy-debug']),
|
|
341
|
+
});
|
|
342
|
+
}
|
package/src/host.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './api/long-task.js';
|
|
|
7
7
|
export * from './lib/text.js';
|
|
8
8
|
export * from './lib/ui.js';
|
|
9
9
|
export * from './lib/panel-state.js';
|
|
10
|
+
export * from './lib/board-fact.js';
|
|
10
11
|
export * from './lib/diy-debug.js';
|
|
11
12
|
export * from './api/blocker-table.js';
|
|
12
13
|
export * from './host/browser-find.js';
|
package/src/i18n/en.ts
CHANGED
|
@@ -421,12 +421,18 @@ export const en: Record<keyof WorkbenchMessages, string> = {
|
|
|
421
421
|
'configSync.emptyProviders': 'The workbench has no model provider yet — sync the llm- rows from some profile, or configure one under Models.',
|
|
422
422
|
'configSync.failed': 'The sync did not go through; try again.',
|
|
423
423
|
|
|
424
|
-
'debug.status': '
|
|
425
|
-
'debug.
|
|
426
|
-
'debug.
|
|
427
|
-
'debug.
|
|
424
|
+
'debug.status': 'Workbench DIY debugging',
|
|
425
|
+
'debug.status.trouble': 'Workbench DIY debugging needs attention',
|
|
426
|
+
'debug.stalled': 'Workbench DIY debugging paused',
|
|
427
|
+
'debug.act.pause': 'Pause debugging',
|
|
428
|
+
'debug.act.resume': 'Resume debugging',
|
|
429
|
+
'debug.act.stop': 'Stop debugging',
|
|
430
|
+
'debug.act.stop.ask': 'Confirm stop',
|
|
431
|
+
'debug.card.here.title': 'Workbench DIY debugging is on',
|
|
432
|
+
'debug.card.here.note': 'Do not switch workspaces or touch the panel',
|
|
433
|
+
'debug.card.away.title': 'Workbench DIY debugging is on',
|
|
434
|
+
'debug.card.away.note': 'Switch to the Workbench DIY workspace',
|
|
435
|
+
'debug.card.paused.note': 'Paused',
|
|
436
|
+
'debug.card.hidden.note': 'Switch to the Workbench panel',
|
|
428
437
|
'debug.back': 'Back to the workshop screen',
|
|
429
|
-
'debug.strip.active': 'Debugging · {unit} · {since}',
|
|
430
|
-
'debug.strip.note': 'Tell the agent to pause when you are done',
|
|
431
|
-
'debug.stripStalled': 'Debug stalled — tell the agent to continue',
|
|
432
438
|
};
|
package/src/i18n/zh.ts
CHANGED
|
@@ -416,14 +416,20 @@ export const zh = {
|
|
|
416
416
|
'configSync.emptyProviders': '工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把 llm- 那几行搬过来,或自己去「模型」里配。',
|
|
417
417
|
'configSync.failed': '同步没成功,再试一次。',
|
|
418
418
|
|
|
419
|
-
'debug.status': '
|
|
420
|
-
'debug.
|
|
421
|
-
'debug.
|
|
422
|
-
'debug.
|
|
419
|
+
'debug.status': '工作台 DIY 开发调试中',
|
|
420
|
+
'debug.status.trouble': '工作台 DIY 开发调试异常',
|
|
421
|
+
'debug.stalled': '工作台 DIY 调试暂停',
|
|
422
|
+
'debug.act.pause': '暂停调试',
|
|
423
|
+
'debug.act.resume': '继续调试',
|
|
424
|
+
'debug.act.stop': '结束调试',
|
|
425
|
+
'debug.act.stop.ask': '确认结束',
|
|
426
|
+
'debug.card.here.title': '当前工作台 DIY 开发调试中',
|
|
427
|
+
'debug.card.here.note': '请勿切换工作区和操作面板',
|
|
428
|
+
'debug.card.away.title': '工作台 DIY 开发调试中',
|
|
429
|
+
'debug.card.away.note': '请切换到工作台 DIY 工作区',
|
|
430
|
+
'debug.card.paused.note': '已暂停',
|
|
431
|
+
'debug.card.hidden.note': '请切换到工作台面板',
|
|
423
432
|
'debug.back': '回到工坊那一屏',
|
|
424
|
-
'debug.strip.active': '调试中 · {unit} · {since}',
|
|
425
|
-
'debug.strip.note': '要停就对 agent 说一句「暂停」',
|
|
426
|
-
'debug.stripStalled': '调试搁置 —— 对 agent 说一句「继续」',
|
|
427
433
|
} as const;
|
|
428
434
|
|
|
429
435
|
export type WorkbenchMessages = typeof zh;
|
package/src/index.ts
CHANGED
|
@@ -45,6 +45,7 @@ export * from './i18n/zh.js';
|
|
|
45
45
|
export * from './lib/blocker-action.js';
|
|
46
46
|
export * from './lib/busy.js';
|
|
47
47
|
export * from './lib/form-problem.js';
|
|
48
|
+
export * from './lib/board-fact.js';
|
|
48
49
|
export * from './lib/diy-debug.js';
|
|
49
50
|
export * from './lib/panel-state.js';
|
|
50
51
|
export * from './lib/react.js';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { boardFactOf, boardSituation, insideWorkshop, type BoardProbe } from './board-fact.js';
|
|
3
|
+
|
|
4
|
+
const WORKSHOP = '/w/workbench/diy';
|
|
5
|
+
const FL0XIN = '/w/floxin-app';
|
|
6
|
+
|
|
7
|
+
const probe = (over: Partial<BoardProbe> = {}): BoardProbe => ({
|
|
8
|
+
workbench: true,
|
|
9
|
+
where: WORKSHOP,
|
|
10
|
+
bar: true,
|
|
11
|
+
board: WORKSHOP,
|
|
12
|
+
open: true,
|
|
13
|
+
drawn: true,
|
|
14
|
+
...over,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const gone = { bar: false, board: '', open: false, drawn: false } as const;
|
|
18
|
+
|
|
19
|
+
describe('板事实:一份判据,两边共用', () => {
|
|
20
|
+
it('★★ 画着的就是工坊那块板(含子路径)⇒ workshop', () => {
|
|
21
|
+
expect(boardFactOf(probe(), WORKSHOP)).toBe('workshop');
|
|
22
|
+
expect(boardFactOf(probe({ board: `${WORKSHOP}/packages` }), WORKSHOP)).toBe('workshop');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('★★ 画的是别的项目的板 ⇒ other(前缀像但没落在里面也算 other)', () => {
|
|
26
|
+
expect(boardFactOf(probe({ board: '/w/project' }), WORKSHOP)).toBe('other');
|
|
27
|
+
expect(boardFactOf(probe({ board: `${WORKSHOP}-other` }), WORKSHOP)).toBe('other');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('★★ 那块板没画在屏上 ⇒ hidden:不挂、没声明开着、量出来不可见,三条里任一条不成立都算', () => {
|
|
31
|
+
expect(boardFactOf(probe({ bar: false }), WORKSHOP)).toBe('hidden');
|
|
32
|
+
expect(boardFactOf(probe({ open: false }), WORKSHOP)).toBe('hidden');
|
|
33
|
+
expect(boardFactOf(probe({ drawn: false }), WORKSHOP)).toBe('hidden');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('★★ 工作台没答话(旧外壳 / 夹具页)⇒ unknown:放行,但不许当成"就是工坊板"', () => {
|
|
37
|
+
expect(boardFactOf(probe({ workbench: false }), WORKSHOP)).toBe('unknown');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('★ 画着板但说不清是哪块、或不知道工坊在哪 ⇒ unknown', () => {
|
|
41
|
+
expect(boardFactOf(probe({ board: '' }), WORKSHOP)).toBe('unknown');
|
|
42
|
+
expect(boardFactOf(probe(), null)).toBe('unknown');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('★★ 顺序要紧:没画在屏上,就别去猜是哪块板', () => {
|
|
46
|
+
expect(boardFactOf(probe({ board: WORKSHOP, drawn: false }), WORKSHOP)).toBe('hidden');
|
|
47
|
+
expect(boardFactOf(probe({ workbench: false, bar: false }), WORKSHOP)).toBe('unknown');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('干不了活是为什么:先看人在不在工坊,再看板画没画在屏上', () => {
|
|
52
|
+
it('★★ 在位 ⇒ ok(跟 boardFactOf === "workshop" 是同一个条件)', () => {
|
|
53
|
+
expect(boardSituation(probe(), WORKSHOP)).toBe('ok');
|
|
54
|
+
expect(boardSituation(probe({ board: `${WORKSHOP}/packages` }), WORKSHOP)).toBe('ok');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('★★ 用户根本不在工坊那个工作区 ⇒ off-workspace(哪怕右栏整个没挂也说得清)', () => {
|
|
58
|
+
expect(boardSituation(probe({ where: FL0XIN, ...gone }), WORKSHOP)).toBe('off-workspace');
|
|
59
|
+
expect(boardSituation(probe({ where: FL0XIN }), WORKSHOP)).toBe('ok');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('★★ 人在工坊、可那块板没画在屏上 ⇒ panel-closed', () => {
|
|
63
|
+
expect(boardSituation(probe({ ...gone }), WORKSHOP)).toBe('panel-closed');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('★★ 人在工坊、画着的却是别家的板 ⇒ other-board', () => {
|
|
67
|
+
expect(boardSituation(probe({ board: '/w/project' }), WORKSHOP)).toBe('other-board');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('★ 问不出来(旧外壳 / 夹具页)⇒ unknown:两边都放行、都别喊狼来了', () => {
|
|
71
|
+
expect(boardSituation(probe({ workbench: false }), WORKSHOP)).toBe('unknown');
|
|
72
|
+
expect(boardSituation(probe({ where: '', ...gone }), WORKSHOP)).toBe('panel-closed');
|
|
73
|
+
expect(boardSituation(probe({ board: '' }), WORKSHOP)).toBe('unknown');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('★★ 优先级:不在工坊这一条压过"面板没开"(先说更根本的那一步)', () => {
|
|
77
|
+
expect(boardSituation(probe({ where: FL0XIN, ...gone }), WORKSHOP)).toBe('off-workspace');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('★ 路径归属的纯规则:相同就是里面,前缀必须落在斜杠上', () => {
|
|
81
|
+
expect(insideWorkshop('/a/b', '/a/b')).toBe(true);
|
|
82
|
+
expect(insideWorkshop('/a/b', '/a/b/c')).toBe(true);
|
|
83
|
+
expect(insideWorkshop('/a/b', '/a/bc')).toBe(false);
|
|
84
|
+
expect(insideWorkshop('/a/b/', '/a/b/c')).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type BoardFactState =
|
|
2
|
+
| 'workshop'
|
|
3
|
+
| 'other'
|
|
4
|
+
| 'hidden'
|
|
5
|
+
| 'unknown';
|
|
6
|
+
|
|
7
|
+
export type BoardSituation =
|
|
8
|
+
| 'ok'
|
|
9
|
+
| 'off-workspace'
|
|
10
|
+
| 'panel-closed'
|
|
11
|
+
| 'other-board'
|
|
12
|
+
| 'unknown';
|
|
13
|
+
|
|
14
|
+
export interface BoardProbe {
|
|
15
|
+
readonly workbench: boolean;
|
|
16
|
+
readonly where: string;
|
|
17
|
+
readonly bar: boolean;
|
|
18
|
+
readonly board: string;
|
|
19
|
+
readonly open: boolean;
|
|
20
|
+
readonly drawn: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function insideWorkshop(root: string, target: string): boolean {
|
|
24
|
+
if (target === root) return true;
|
|
25
|
+
const base = root.endsWith('/') ? root : `${root}/`;
|
|
26
|
+
return target.startsWith(base);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function boardFactOf(probe: BoardProbe, workshop: string | null): BoardFactState {
|
|
30
|
+
if (!probe.workbench) return 'unknown';
|
|
31
|
+
if (!probe.bar || !probe.open || !probe.drawn) return 'hidden';
|
|
32
|
+
if (probe.board === '' || workshop === null) return 'unknown';
|
|
33
|
+
return insideWorkshop(workshop, probe.board) ? 'workshop' : 'other';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function boardSituation(probe: BoardProbe, workshop: string | null): BoardSituation {
|
|
37
|
+
if (!probe.workbench || workshop === null) return 'unknown';
|
|
38
|
+
const drawn = probe.bar && probe.open && probe.drawn;
|
|
39
|
+
if (drawn) {
|
|
40
|
+
if (probe.board === '') return 'unknown';
|
|
41
|
+
return insideWorkshop(workshop, probe.board) ? 'ok' : 'other-board';
|
|
42
|
+
}
|
|
43
|
+
if (probe.where !== '' && !insideWorkshop(workshop, probe.where)) return 'off-workspace';
|
|
44
|
+
return 'panel-closed';
|
|
45
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { DEBUG_STALE_MS, createDebugStore, type DebugPact } from './diy-debug.js';
|
|
2
|
+
import { DEBUG_STALE_MS, createDebugStore, parseDebugIntent, type DebugPact } from './diy-debug.js';
|
|
3
3
|
|
|
4
4
|
const pact = (sessionId: string, now = 1000, unit = 'demo'): DebugPact => ({
|
|
5
5
|
sessionId,
|
|
@@ -80,16 +80,12 @@ describe('调试态:一台机器一次一条,谁开始谁收工', () => {
|
|
|
80
80
|
expect(store.live(1500)?.sessionId).toBe('s1');
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
it('★★
|
|
83
|
+
it('★★ 状态机里没有"自动落 paused"这回事:只有 agent 主动 pause / resume / stop(2026-10-17 夜口径)', () => {
|
|
84
84
|
const store = createDebugStore();
|
|
85
85
|
store.begin(pact('s1', 1000));
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
expect(st.ok && st.state.phase).toBe('paused');
|
|
90
|
-
expect(store.live(2000)?.phase).toBe('paused');
|
|
91
|
-
expect(store.stall('s1', 2100)).toEqual({ ok: false, code: 'already-paused' });
|
|
92
|
-
expect(store.stall('s2', 2100)).toEqual({ ok: false, code: 'not-owner' });
|
|
87
|
+
expect(Object.keys(store)).toEqual(['live', 'begin', 'pause', 'resume', 'stop']);
|
|
88
|
+
expect(store.live(2000)?.phase).toBe('debugging');
|
|
93
89
|
});
|
|
94
90
|
|
|
95
91
|
it('★ 过期当它不存在(时间隔太久,别把上一场调试留给下一个人)', () => {
|
|
@@ -101,3 +97,14 @@ describe('调试态:一台机器一次一条,谁开始谁收工', () => {
|
|
|
101
97
|
expect(store.begin(pact('s2', 1001 + DEBUG_STALE_MS)).ok).toBe(true);
|
|
102
98
|
});
|
|
103
99
|
});
|
|
100
|
+
|
|
101
|
+
describe('用户在那一格上按的三个键:意图词表只此一份', () => {
|
|
102
|
+
it('★ 认得出三个,其余一律 null(别把别的字当成指令)', () => {
|
|
103
|
+
expect(parseDebugIntent('pause')).toBe('pause');
|
|
104
|
+
expect(parseDebugIntent('resume')).toBe('resume');
|
|
105
|
+
expect(parseDebugIntent('stop')).toBe('stop');
|
|
106
|
+
for (const bad of ['', 'PAUSE', 'Pause', 'kill', 'end', null, undefined, 1, {}, []]) {
|
|
107
|
+
expect(parseDebugIntent(bad)).toBeNull();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
package/src/lib/diy-debug.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export type DebugPhase = 'debugging' | 'paused';
|
|
2
2
|
|
|
3
|
+
export type DebugIntent = 'pause' | 'resume' | 'stop';
|
|
4
|
+
|
|
5
|
+
export function parseDebugIntent(value: unknown): DebugIntent | null {
|
|
6
|
+
return value === 'pause' || value === 'resume' || value === 'stop' ? value : null;
|
|
7
|
+
}
|
|
8
|
+
|
|
3
9
|
export const DEBUG_STALE_MS = 4 * 60 * 60 * 1000;
|
|
4
10
|
|
|
5
11
|
export interface DebugState {
|
|
@@ -37,7 +43,6 @@ export type DebugMove =
|
|
|
37
43
|
export interface DebugStore {
|
|
38
44
|
live(now: number): DebugState | null;
|
|
39
45
|
begin(pact: DebugPact): DebugMove;
|
|
40
|
-
stall(sessionId: string, now: number): DebugMove;
|
|
41
46
|
pause(sessionId: string, now: number): DebugMove;
|
|
42
47
|
resume(sessionId: string, now: number): DebugMove;
|
|
43
48
|
stop(sessionId: string, now: number): DebugMove;
|
|
@@ -81,15 +86,6 @@ export function createDebugStore(): DebugStore {
|
|
|
81
86
|
return { ok: true, state };
|
|
82
87
|
},
|
|
83
88
|
|
|
84
|
-
stall(sessionId, now) {
|
|
85
|
-
const found = ownerOf(held, sessionId, now);
|
|
86
|
-
if (typeof found === 'string') return { ok: false, code: found };
|
|
87
|
-
if (found.phase === 'paused') return { ok: false, code: 'already-paused' };
|
|
88
|
-
const state: DebugState = { ...found, phase: 'paused', at: now };
|
|
89
|
-
held = state;
|
|
90
|
-
return { ok: true, state };
|
|
91
|
-
},
|
|
92
|
-
|
|
93
89
|
pause(sessionId, now) {
|
|
94
90
|
const found = ownerOf(held, sessionId, now);
|
|
95
91
|
if (typeof found === 'string') return { ok: false, code: found };
|