@dsh-workbench/shared 0.3.8 → 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.
Files changed (42) hide show
  1. package/dist/api/dsh.d.ts +14 -0
  2. package/dist/components/MockStrip.css +1 -11
  3. package/dist/i18n/en.js +12 -1
  4. package/dist/i18n/index.d.ts +13 -2
  5. package/dist/i18n/zh.d.ts +12 -1
  6. package/dist/i18n/zh.js +12 -1
  7. package/dist/lib/lint-probe.d.ts +1 -0
  8. package/dist/lib/lint-probe.js +6 -0
  9. package/package.json +1 -1
  10. package/src/api/dsh.ts +16 -0
  11. package/src/i18n/en.ts +12 -1
  12. package/src/i18n/zh.ts +12 -1
  13. package/dist/components/StateDot.d.ts +0 -5
  14. package/dist/components/StateDot.js +0 -10
  15. package/dist/host/__tests__/fakes.d.ts +0 -41
  16. package/dist/host/__tests__/fakes.js +0 -76
  17. package/dist/host/__tests__/preflight-fixtures.d.ts +0 -19
  18. package/dist/host/__tests__/preflight-fixtures.js +0 -47
  19. package/dist/host/context-inject.d.ts +0 -24
  20. package/dist/host/context-inject.js +0 -74
  21. package/dist/host/events.d.ts +0 -9
  22. package/dist/host/events.js +0 -70
  23. package/dist/host/mount-units.d.ts +0 -52
  24. package/dist/host/mount-units.js +0 -186
  25. package/dist/host/preflight.d.ts +0 -58
  26. package/dist/host/preflight.js +0 -233
  27. package/dist/host/probe-cache.d.ts +0 -6
  28. package/dist/host/probe-cache.js +0 -19
  29. package/dist/host/probe-libs.d.ts +0 -45
  30. package/dist/host/probe-libs.js +0 -61
  31. package/dist/host/probe-units.d.ts +0 -17
  32. package/dist/host/probe-units.js +0 -102
  33. package/dist/host/probe-verdict.d.ts +0 -7
  34. package/dist/host/probe-verdict.js +0 -143
  35. package/dist/host/tool-scope.d.ts +0 -32
  36. package/dist/host/tool-scope.js +0 -84
  37. package/dist/host/unit-readiness.d.ts +0 -7
  38. package/dist/host/unit-readiness.js +0 -5
  39. package/dist/host/unit-registry.d.ts +0 -9
  40. package/dist/host/unit-registry.js +0 -33
  41. package/dist/host/version-range.d.ts +0 -2
  42. 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
  */
@@ -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, but fix it first.',
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',
@@ -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;
@@ -0,0 +1,6 @@
1
+ import { useRef } from './react';
2
+ export function useLintProbe() {
3
+ const probeRef = useRef(0);
4
+ probeRef.current = 1;
5
+ return probeRef.current;
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/shared",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "工作台与模块共享的纯代码与契约类型:类型、纯逻辑、哑组件、平台解析。宿主侧的东西从 /host 进(不影响浏览器产物)。",
5
5
  "license": "MIT",
6
6
  "type": "module",
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/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, but fix it first.',
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,5 +0,0 @@
1
- export type DotState = 'ongoing' | 'warning' | 'done' | 'idle' | string;
2
- export declare function StateDot({ state, size }: {
3
- state: DotState;
4
- size: number;
5
- }): JSX.Element;
@@ -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
- };
@@ -1,47 +0,0 @@
1
- import { createPreflight } from '../preflight';
2
- import { createFakeShell } from './fakes';
3
- export const GOOD_BRIDGE_REPORT = [
4
- 'opencli v1.8.7 doctor (node v24.15.0)',
5
- '',
6
- '[OK] Daemon: running on port 19825 (v1.8.7)',
7
- '[OK] Extension: connected (v1.0.24)',
8
- '[OK] Connectivity: connected in 0.0s',
9
- '',
10
- 'Everything looks good!',
11
- ].join('\n');
12
- export const ALL_OK = [{ stdout: '1.8.8\n' }, { stdout: GOOD_BRIDGE_REPORT }];
13
- export const STALE_DAEMON_BRIDGE = [
14
- 'opencli v1.8.7 doctor (node v24.15.0)',
15
- '',
16
- '[STALE] Daemon: running on port 19825 (v1.8.8 != CLI v1.8.7)',
17
- '[OK] Extension: connected (v1.0.24)',
18
- '[OK] Connectivity: connected in 0.0s',
19
- '',
20
- 'Issues:',
21
- ' • Stale daemon detected: daemon v1.8.8 != CLI v1.8.7.',
22
- ' Run: opencli daemon restart',
23
- ].join('\n');
24
- export const BROKEN_BRIDGE = [
25
- 'opencli v1.8.7 doctor (node v24.15.0)',
26
- '',
27
- '[MISSING] Daemon: not running',
28
- '[MISSING] Extension: not connected',
29
- '[FAIL] Connectivity: failed (daemon not reachable)',
30
- '',
31
- 'Issues:',
32
- " • Daemon is not running. It should start automatically when you run an opencli browser command.",
33
- ' • Daemon is running but the Chrome/Chromium extension is not connected.',
34
- 'If the extension is not installed:',
35
- ' 1. Download from https://github.com/jackwener/opencli/releases',
36
- ' 2. Open chrome://extensions/ → Enable Developer Mode',
37
- ' 3. Click "Load unpacked" → select the extension folder',
38
- ].join('\n');
39
- export function build(replies, install, warmReads) {
40
- const fake = createFakeShell(replies);
41
- const preflight = createPreflight({
42
- shell: fake.shell,
43
- ...(install === undefined ? {} : { install }),
44
- ...(warmReads === undefined ? {} : { warmReads }),
45
- });
46
- return { fake, preflight };
47
- }
@@ -1,24 +0,0 @@
1
- import { type ContextRef } from '@dsh-workbench/shared';
2
- import type { ContextRenderer } from './unit-face';
3
- export declare const CONTEXT_SOURCE_KIND = "workbench";
4
- export interface ScannableMessage {
5
- readonly source?: {
6
- readonly kind?: string;
7
- };
8
- readonly content?: readonly {
9
- readonly type?: string;
10
- readonly text?: string;
11
- }[];
12
- }
13
- export type { ContextRenderer };
14
- export declare function collectContextRefs(messages: readonly ScannableMessage[]): ContextRef[];
15
- export declare function buildContextMessage(text: string, summary: string): unknown;
16
- export interface ContextInjector {
17
- inject(messages: readonly ScannableMessage[], agent: unknown): Promise<unknown | undefined>;
18
- }
19
- export declare function createContextInjector(options: {
20
- renderers: ReadonlyMap<string, ContextRenderer>;
21
- logger?: {
22
- warn?(message: string): void;
23
- } | undefined;
24
- }): ContextInjector;