@dsh-workbench/core 0.3.9 → 0.3.11

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 (84) hide show
  1. package/README.md +19 -7
  2. package/bin/dsh-workbench +2 -2
  3. package/client.js +1687 -1022
  4. package/cordis.patch.yml +60 -35
  5. package/dist/client/client.body.js +1687 -1022
  6. package/dist/client/index.js +1372 -707
  7. package/dist/host/index.js +2897 -2335
  8. package/dist/types/app/client.d.ts +2 -1
  9. package/dist/types/app/layouts/env-gate/boot-gate.d.ts +1 -1
  10. package/dist/types/app/layouts/market/use-module-versions.d.ts +13 -2
  11. package/dist/types/app/layouts/rightbar/MarketView.d.ts +6 -3
  12. package/dist/types/app/layouts/rightbar/market-act.d.ts +6 -3
  13. package/dist/types/app/layouts/rightbar/market-rows.d.ts +1 -1
  14. package/dist/types/app/layouts/rightbar/market-settle-hold.d.ts +2 -0
  15. package/dist/types/app/layouts/rightbar/market-settle.d.ts +20 -0
  16. package/dist/types/app/layouts/rightbar/market-shared-rows.d.ts +0 -1
  17. package/dist/types/app/layouts/rightbar/market-update-verdict.d.ts +41 -0
  18. package/dist/types/app/layouts/rightbar/market-view-text.d.ts +4 -1
  19. package/dist/types/app/layouts/rightbar/store.d.ts +14 -0
  20. package/dist/types/app/layouts/sidebar/LongTaskDot.d.ts +12 -0
  21. package/dist/types/app/layouts/sidebar/LongTaskHover.d.ts +12 -0
  22. package/dist/types/app/layouts/sidebar/edition-boot.d.ts +24 -0
  23. package/dist/types/app/layouts/sidebar/edition.d.ts +22 -0
  24. package/dist/types/app/layouts/workbench-settings/ConfigSyncItem.d.ts +5 -0
  25. package/dist/types/app/layouts/workbench-settings/SettingsItem.d.ts +17 -0
  26. package/dist/types/app/layouts/workbench-settings/SidebarEditionItem.d.ts +11 -0
  27. package/dist/types/app/layouts/workbench-settings/WorkbenchSettingsSection.d.ts +11 -0
  28. package/dist/types/modules/panels/model/approval.d.ts +12 -4
  29. package/dist/types/modules/panels/model/diy-browser-tools.d.ts +1 -1
  30. package/dist/types/modules/panels/model/diy-context.d.ts +31 -14
  31. package/dist/types/modules/panels/model/diy-page.d.ts +3 -2
  32. package/dist/types/modules/panels/model/diy-record.d.ts +3 -3
  33. package/dist/types/modules/panels/model/diy-report.d.ts +6 -7
  34. package/dist/types/modules/panels/model/market-dependency-update.d.ts +21 -0
  35. package/dist/types/modules/panels/model/market-dispatch.d.ts +1 -0
  36. package/dist/types/modules/panels/model/market-types.d.ts +1 -0
  37. package/dist/types/modules/panels/model/market-update-bundle.d.ts +25 -0
  38. package/dist/types/modules/panels/model/market-verify.d.ts +31 -0
  39. package/dist/types/modules/panels/unit.d.ts +3 -4
  40. package/dist/types/shared/api/bundle-install.d.ts +13 -0
  41. package/dist/types/shared/api/host/approval-gate.d.ts +39 -0
  42. package/dist/types/shared/api/host/bundle-routes.d.ts +2 -1
  43. package/dist/types/shared/api/host/diy-artifacts.d.ts +14 -0
  44. package/dist/types/shared/api/host/diy-modules.d.ts +41 -0
  45. package/dist/types/shared/api/host/host-routes.d.ts +13 -0
  46. package/dist/types/shared/api/host/permission-mode.d.ts +9 -0
  47. package/dist/types/shared/api/host/runtime-seed.d.ts +2 -0
  48. package/dist/types/shared/api/host/self-update.d.ts +9 -2
  49. package/dist/types/shared/api/host/sidebar-edition.d.ts +46 -0
  50. package/dist/types/shared/api/host/workspace-root.d.ts +13 -0
  51. package/dist/types/shared/api/sidebar-edition.d.ts +14 -0
  52. package/dist/types/shared/api/unit-board.d.ts +20 -0
  53. package/dist/types/shared/api/write-outcome.d.ts +15 -0
  54. package/dist/types/shared/components/IconModules.d.ts +8 -0
  55. package/dist/types/shared/components/blocker-action.d.ts +16 -0
  56. package/dist/types/shared/hooks/sidebar-edition.d.ts +7 -0
  57. package/dist/types/shared/hooks/use-capabilities.d.ts +5 -0
  58. package/dist/types/shared/hooks/use-capability-gate.d.ts +1 -2
  59. package/dist/types/shared/hooks/use-host-write.d.ts +1 -1
  60. package/dist/types/shared/hooks/use-unit-board.d.ts +1 -1
  61. package/docs/HANDOFF.md +3 -3
  62. package/docs/OPERATIONS.md +16 -5
  63. package/package.json +3 -3
  64. package/preset/diy.patch.yml +2 -2
  65. package/profile/isolation.patch.yml +11 -0
  66. package/skills/workbench-module-diy/BUILD.md +62 -131
  67. package/skills/workbench-module-diy/COPY.md +89 -0
  68. package/skills/workbench-module-diy/DATASOURCE.md +84 -112
  69. package/skills/workbench-module-diy/DESIGN.md +75 -109
  70. package/skills/workbench-module-diy/FAMILY.md +70 -54
  71. package/skills/workbench-module-diy/KIT.md +77 -133
  72. package/skills/workbench-module-diy/LINKAGE.md +66 -105
  73. package/skills/workbench-module-diy/PANEL.md +79 -171
  74. package/skills/workbench-module-diy/REVIEW.md +67 -81
  75. package/skills/workbench-module-diy/SKILL.md +57 -96
  76. package/skills/workbench-module-diy/STEPS.md +66 -69
  77. package/skills/workbench-module-diy/TOOLING.md +34 -51
  78. package/skills/workbench-module-diy/TOOLS.md +110 -103
  79. package/skills/workbench-module-diy/WIRING.md +51 -83
  80. package/skills/workbench-module-diy/WRITES.md +89 -142
  81. package/dist/types/app/layouts/config-sync/ConfigSyncSection.d.ts +0 -5
  82. package/dist/types/shared/api/host/diy-workshop.d.ts +0 -23
  83. package/dist/types/shared/api/host/workshop-root.d.ts +0 -16
  84. /package/dist/types/shared/{api/host/diy-workshop.test.d.ts → components/blocker-action.test.d.ts} +0 -0
@@ -9,7 +9,7 @@ import * as capabilityGateModule from '../shared/hooks/use-capability-gate';
9
9
  import * as unitBoardModule from '../shared/hooks/use-unit-board';
10
10
  import * as visibleBusyModule from '../shared/hooks/use-visible-busy';
11
11
  import * as blockerStateModule from '../shared/components/BlockerState';
12
- import { ActivityAction, ActivityBlock, ActivityLine, ApprovalDetail, ApprovalPlan, Card, CardAnchor, CardBoundary, CardHead, CenteredState, ChoiceGroup, ConfirmBar, EmptyState, Field, Form, FormActions, FormRow, FormRows, IconBrandMark, IconConversation, IconModuleMark, IconNpm, IconOpencli, IconPanelScreen, Link, LongTaskRow, longTaskIsLive, Note, Row, Rows, SaveBar, SelectField, SettingsSection, SkeletonRows, Spinner, Stack, StateBlock, TextField, apiGet, apiPost, blockerOfCapability, blockerOfError, cardIdOf, cx, defaultSelectFilter, duplicateKeysOf, errorReasonOf, excerpt, filterSelectOptions, firstProblemOf, formFirstProblemOf, formValuesOf, holdBusy, parseJsonLoose, parseLocalTimestamp, readText, relativeTime, relativeTimeAgo, relativeTimeBucket, relativeTimeCompact, revealFirstProblem, searchTextOf, selectCursorValue, selectEntries, shortenPath, stepSelectCursor, writeText } from '@dsh-workbench/shared';
12
+ import { ActivityAction, ActivityBlock, ActivityLine, ApprovalDetail, ApprovalPlan, Card, CardAnchor, CardBoundary, CardHead, CenteredState, ChoiceGroup, ConfirmBar, EmptyState, Field, Form, FormActions, FormRow, FormRows, IconBrandMark, IconConversation, IconModuleMark, IconNpm, IconOpencli, IconPanelScreen, Link, LongTaskRow, longTaskIsLive, Note, Row, Rows, SaveBar, SelectField, SettingsSection, SkeletonRows, Spinner, Stack, StateBlock, TextField, apiGet, apiPost, blockerOfCapability, blockerOfError, cardIdOf, cx, defaultSelectFilter, duplicateKeysOf, errorReasonOf, excerpt, factOfRoute, filterSelectOptions, firstProblemOf, formFirstProblemOf, formValuesOf, holdBusy, parseJsonLoose, parseLocalTimestamp, readText, relativeTime, relativeTimeAgo, relativeTimeBucket, relativeTimeCompact, revealFirstProblem, searchTextOf, selectCursorValue, selectEntries, shortenPath, stepSelectCursor, writeText } from '@dsh-workbench/shared';
13
13
  export declare const kit: {
14
14
  hooks: {
15
15
  heldPhase(phase: visibleBusyModule.HeldPhase, refreshing: boolean): visibleBusyModule.HeldPhase;
@@ -100,6 +100,7 @@ export declare const kit: {
100
100
  CONTEXT_SOURCE: "workbench";
101
101
  apiGet: typeof apiGet;
102
102
  apiPost: typeof apiPost;
103
+ factOfRoute: typeof factOfRoute;
103
104
  };
104
105
  lib: {
105
106
  longTaskIsLive: typeof longTaskIsLive;
@@ -19,7 +19,7 @@ export interface BootGate {
19
19
  * 拿到这一拍之后门该怎么办:`close` 撤掉放行、`hold` 停在原地等用户动手、`wait` 接着轮询。
20
20
  * 桥接坏了(`bridgeIssues` 非空)与 DIY 模式挂不起来(`diyGap` 非空)都是**不拦路**的,
21
21
  * 但那块「怎么解决」得先真的画出来 —— 停在原地 + 一颗「先进入工作台」才叫不拦路,
22
- * 就绪即撤等于把那块提示连同修法一起丢掉,用户进去只会发现「工作台 DIY」整个不在。
22
+ * 就绪即撤等于把那块提示连同修法一起丢掉,用户进去只会发现「工作台 DIY 模式」整个不在。
23
23
  */
24
24
  export declare function gateActionOf(snapshot: PreflightSnapshot): 'close' | 'hold' | 'wait';
25
25
  export declare function createBootGate(ctx: {
@@ -1,18 +1,29 @@
1
- import type { ModuleVersion, WorkbenchVersion } from '../../../shared/api/bundle-install';
1
+ import type { ModuleVersion, WorkbenchSelfUpdate, WorkbenchVersion } from '../../../shared/api/bundle-install';
2
2
  import type { InstalledPlugin } from '../../../shared/api/installed-plugins';
3
3
  export interface ModuleVersionsState {
4
4
  readonly modules: readonly ModuleVersion[] | null;
5
5
  readonly plugins: readonly InstalledPlugin[] | null;
6
6
  readonly workbench: WorkbenchVersion | null;
7
+ readonly selfUpdate: WorkbenchSelfUpdate | null;
7
8
  readonly read: boolean;
8
9
  readonly checkedAt: number | null;
9
10
  }
10
11
  export interface ModuleVersionsView extends ModuleVersionsState {
11
12
  reload(options?: {
12
13
  readonly force?: boolean;
14
+ readonly fresh?: boolean;
13
15
  }): void;
14
16
  }
17
+ /**
18
+ * 写完之后把读数作废:这之前发出去的在飞读取即使回来也不许再发布(它读的是改之前的盘)。
19
+ * 每次写成功都调用一次,再配一次 `force + fresh` 的读。
20
+ */
21
+ export declare function bumpModuleVersionsEpoch(): void;
15
22
  export declare function moduleVersionsValue(): ModuleVersionsState;
23
+ /**
24
+ * 清掉这份读数(夹具与判据用):状态、订阅者、在飞读取与代际一起归零。
25
+ */
26
+ export declare function resetModuleVersions(): void;
16
27
  export declare function subscribeModuleVersions(listener: () => void): () => void;
17
- export declare function runModuleVersionsRead(force?: boolean): Promise<void>;
28
+ export declare function runModuleVersionsRead(force?: boolean, fresh?: boolean): Promise<void>;
18
29
  export declare function useModuleVersions(): ModuleVersionsView;
@@ -6,23 +6,26 @@ import type { InstalledPlugin } from '../../../shared/api/installed-plugins';
6
6
  import { type InstalledWorkbenchModule } from './market-rows';
7
7
  import type { MarketMock } from './market-mock';
8
8
  import type { ModuleUpdateMap } from './market-rows';
9
- import type { WorkbenchVersion } from '../../../shared/api/bundle-install';
9
+ import type { WorkbenchSelfUpdate, WorkbenchVersion } from '../../../shared/api/bundle-install';
10
10
  export interface MarketViewProps {
11
11
  readonly t: Translate;
12
12
  readonly manifests: readonly UnitManifest[];
13
13
  readonly installable?: ReadonlySet<string> | null | undefined;
14
14
  readonly capabilities: CapabilityMap | null;
15
15
  readonly freshness: MarketFreshness;
16
- readonly onChanged: () => void;
16
+ readonly onChanged: (options?: {
17
+ readonly force?: boolean;
18
+ }) => void;
17
19
  readonly onPending?: ((pending: boolean) => void) | undefined;
18
20
  readonly updates?: ModuleUpdateMap | undefined;
19
21
  readonly installed?: readonly InstalledWorkbenchModule[] | undefined;
20
22
  readonly installedRead?: boolean | undefined;
21
23
  readonly workbench?: WorkbenchVersion | null | undefined;
24
+ readonly selfUpdate?: WorkbenchSelfUpdate | null | undefined;
22
25
  readonly plugins?: readonly InstalledPlugin[] | null | undefined;
23
26
  readonly settling?: ReadonlySet<string> | undefined;
24
27
  readonly mock?: MarketMock | undefined;
25
28
  readonly defaults?: readonly string[] | undefined;
26
29
  readonly changed?: Readonly<Record<string, number>> | undefined;
27
30
  }
28
- export declare function MarketView({ t, manifests, installable, capabilities, freshness, onChanged, onPending, updates, installed, installedRead, workbench, plugins, settling, mock, defaults, changed, }: MarketViewProps): JSX.Element;
31
+ export declare function MarketView({ t, manifests, installable, capabilities, freshness, onChanged, onPending, updates, installed, installedRead, workbench, selfUpdate, plugins, settling, mock, defaults, changed, }: MarketViewProps): JSX.Element;
@@ -12,11 +12,14 @@ export interface MarketActSeats {
12
12
  } | null) => void;
13
13
  readonly setNotice: (next: string | null) => void;
14
14
  }
15
- export declare function marketActOf(options: {
15
+ export interface MarketActOptions {
16
16
  readonly t: Translate;
17
17
  readonly mocked: boolean;
18
18
  readonly rowOf: (id: string) => MarketRow | undefined;
19
19
  readonly seats: MarketActSeats;
20
20
  readonly send: (body: Record<string, unknown>) => Promise<WriteOutcome<unknown>>;
21
- readonly onChanged: () => void;
22
- }): (id: string, action: MarketRowAction) => Promise<void>;
21
+ readonly onChanged: (options?: {
22
+ readonly force?: boolean;
23
+ }) => void;
24
+ }
25
+ export declare function marketActOf(options: MarketActOptions): (id: string, action: MarketRowAction) => Promise<void>;
@@ -5,7 +5,7 @@ import type { SharedRow } from './market-shared-rows';
5
5
  import type { CapabilityMap } from '../../../shared/hooks/use-capabilities';
6
6
  export type { MarketHintKey, MarketNote, MarketRow, MarketRowAction, MarketState, ModuleUpdate, } from './market-row-types';
7
7
  export type { SharedRow, SharedState } from './market-shared-rows';
8
- export { SHARED_DOT, SHARED_STATE_KEY, sharedActions, sharedRows } from './market-shared-rows';
8
+ export { SHARED_STATE_KEY, sharedActions, sharedRows } from './market-shared-rows';
9
9
  export declare const MARKET_STATE_KEY: Readonly<Record<MarketState, string>>;
10
10
  export declare const MARKET_DOT: Readonly<Record<MarketState, 'ongoing' | 'done' | 'warning' | 'idle' | 'error'>>;
11
11
  export type ModuleUpdateMap = Readonly<Record<string, ModuleUpdate>>;
@@ -1,10 +1,12 @@
1
1
  import type { Translate } from '@dsh-workbench/shared';
2
+ import type { WorkbenchSelfUpdate } from '../../../shared/api/bundle-install';
2
3
  import type { Pending } from './market-view-text';
3
4
  export declare function useSettleHold(input: {
4
5
  readonly pending: Pending | null;
5
6
  readonly landed: boolean;
6
7
  readonly t: Translate;
7
8
  readonly onChanged: () => void;
9
+ readonly selfUpdate?: WorkbenchSelfUpdate | null | undefined;
8
10
  readonly setPending: (next: Pending | null) => void;
9
11
  readonly setFailed: (next: {
10
12
  readonly id: string;
@@ -1,4 +1,6 @@
1
+ import type { WorkbenchSelfUpdate } from '../../../shared/api/bundle-install';
1
2
  import type { MarketRowAction, ModuleUpdate } from './market-row-types';
3
+ import type { SharedState } from './market-shared-rows';
2
4
  export declare const MODULE_SETTLE_MS = 15000;
3
5
  export declare function holdBack(installed: readonly string[], roster: ReadonlySet<string>, active: ReadonlySet<string>, previous: ReadonlySet<string> | null): readonly string[];
4
6
  export declare const WORKBENCH_SWAP_MS = 180000;
@@ -20,5 +22,23 @@ export declare function settleLanded(input: {
20
22
  readonly entry: ModuleUpdate | undefined;
21
23
  readonly clicked: string | undefined;
22
24
  readonly outdated: boolean;
25
+ readonly sharedState?: SharedState | undefined;
26
+ readonly pluginOutdated?: boolean | null | undefined;
23
27
  }): boolean;
28
+ export interface SelfUpdateStop {
29
+ readonly kind: 'failed' | 'rolled-back';
30
+ readonly reason?: string;
31
+ readonly version?: string;
32
+ }
33
+ /**
34
+ * 工作台自更新是不是已经由外面那个进程判死了:`failed` / `rolled-back` 都算收尾,
35
+ * 不必再等盘上版本追上来(最多 3 分钟的等待里用户不该一直看「正在更新」)。
36
+ * `since` 是点下去那一刻(毫秒),marker 比它早太多说明是上一次的现场,不算。
37
+ * @returns `undefined` = 还在跑或没有现场;否则 `kind` 与日志尾里最后一句原因。
38
+ */
39
+ export declare function selfUpdateStop(input: {
40
+ readonly until: string | undefined;
41
+ readonly since: number | undefined;
42
+ readonly update: WorkbenchSelfUpdate | null | undefined;
43
+ }): SelfUpdateStop | undefined;
24
44
  export declare function holdWindowMs(until: string | undefined): number;
@@ -3,7 +3,6 @@ import type { CapabilityMap } from '../../../shared/hooks/use-capabilities';
3
3
  import type { MarketRowAction } from './market-row-types';
4
4
  export type SharedState = 'checking' | 'installed' | 'outdated' | 'unsatisfied' | 'missing' | 'unchecked';
5
5
  export declare const SHARED_STATE_KEY: Readonly<Record<SharedState, string>>;
6
- export declare const SHARED_DOT: Readonly<Record<SharedState, 'ongoing' | 'done' | 'warning' | 'idle'>>;
7
6
  export interface SharedRow {
8
7
  readonly id: string;
9
8
  readonly kind: 'plugin' | 'lib';
@@ -0,0 +1,41 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ import type { BundleChange } from '../../../shared/api/bundle-install';
3
+ import type { MarketRowAction } from './market-row-types';
4
+ export interface UpdatedModule {
5
+ readonly kind?: string;
6
+ readonly pkg?: string;
7
+ readonly version?: string;
8
+ }
9
+ export type UpdateVerdict = {
10
+ readonly kind: 'ok';
11
+ } | {
12
+ readonly kind: 'no-change';
13
+ } | {
14
+ readonly kind: 'gone';
15
+ readonly restored?: string;
16
+ } | {
17
+ readonly kind: 'behind';
18
+ readonly installed: string;
19
+ };
20
+ /**
21
+ * 更新那一拍到底算不算成了:只认**盘上这一版**,不认 `applied` 这个字。
22
+ * `no-change` = 点下去那版和盘上一样;`gone` = 跑完读不到模块(`restored` 是回滚成功的版本);
23
+ * `behind` = 版本动了但没到源上最新。`ok` 之外都要给用户一句失败原因。
24
+ * @param input.clicked 点下去那一刻盘上的版本;`latest` 当时源上最新那一版。
25
+ */
26
+ export declare function updateVerdictOf(input: {
27
+ readonly action: MarketRowAction;
28
+ readonly change: BundleChange | undefined;
29
+ readonly module: UpdatedModule | undefined;
30
+ readonly restored?: string | undefined;
31
+ readonly clicked?: string | undefined;
32
+ readonly latest?: string | undefined;
33
+ }): UpdateVerdict;
34
+ /**
35
+ * 把判死的更新结果翻成那一行底下的一句人话;`ok` 给 `undefined`。
36
+ * @param input.from 点下去那版(`no-change` 要说清"还是它")。
37
+ */
38
+ export declare function updateVerdictText(verdict: UpdateVerdict, t: Translate, input: {
39
+ readonly from?: string | undefined;
40
+ readonly latest?: string | undefined;
41
+ }): string | undefined;
@@ -1,6 +1,7 @@
1
1
  import type { UnitManifest } from '@dsh-workbench/shared';
2
2
  import type { CapabilityMap } from '../../../shared/hooks/use-capabilities';
3
3
  import type { MarketRow, MarketRowAction, ModuleUpdateMap } from './market-rows';
4
+ import type { SharedRow } from './market-shared-rows';
4
5
  export declare const PROGRESS_KEY: Readonly<Record<MarketRowAction, string>>;
5
6
  export declare const ACTION_LABEL_KEY: Readonly<Record<MarketRowAction, string>>;
6
7
  export interface HeldRow {
@@ -14,12 +15,14 @@ export interface Pending {
14
15
  readonly label?: string | undefined;
15
16
  readonly pkg?: string | undefined;
16
17
  readonly version?: string | undefined;
18
+ readonly latest?: string | undefined;
19
+ readonly since?: number | undefined;
17
20
  readonly row?: MarketRow | undefined;
18
21
  readonly until?: string | undefined;
19
22
  readonly readBack?: boolean | undefined;
20
23
  }
21
24
  export declare function holdOf(pending: Pending | null, application: string | undefined): HeldRow | undefined;
22
- export declare function pendingLanded(pending: Pending | null, updates: ModuleUpdateMap, capabilities: CapabilityMap | null, installed: string | undefined): boolean;
25
+ export declare function pendingLanded(pending: Pending | null, updates: ModuleUpdateMap, capabilities: CapabilityMap | null, installed: string | undefined, shared?: readonly SharedRow[], plugins?: readonly MarketRow[] | null): boolean;
23
26
  export declare function holdExpired(held: HeldRow | undefined, backInRoster: boolean, elapsedMs: number): boolean;
24
27
  export declare function heldIdOf(pending: Pending | null, held: HeldRow | undefined): string | null;
25
28
  export declare function pinnedRowOf(pending: Pending | null, held: HeldRow | undefined): MarketRow | undefined;
@@ -22,6 +22,20 @@ export interface RightbarPersistence {
22
22
  readText(key: string): string | null;
23
23
  writeText(key: string, value: string | null): void;
24
24
  }
25
+ /**
26
+ * 读一个布尔开关:键不存在时返回 `fallback`,只有存进去的 `'true'` 算真。
27
+ * 外壳自己那几个开合态用它(kit 上的 `readText` / `writeText` 是给模块的文本档)。
28
+ * @param key - localStorage 键。
29
+ * @param fallback - 没有这个键时的值。
30
+ * @returns 开关状态。
31
+ */
32
+ export declare function readFlag(key: string, fallback: boolean): boolean;
33
+ /**
34
+ * 把一个布尔开关写进 localStorage(存 `'true'` / `'false'`);写不进去静默作罢。
35
+ * @param key - localStorage 键。
36
+ * @param value - 开关状态。
37
+ */
38
+ export declare function writeFlag(key: string, value: boolean): void;
25
39
  export declare const RIGHTBAR_DEFAULT_EXPANDED = true;
26
40
  export declare const RIGHTBAR_DEFAULT_COLUMN: RightbarColumn;
27
41
  export interface RightbarColumnPressed {
@@ -0,0 +1,12 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ export interface LongTaskDotProps {
3
+ readonly sessionId: string;
4
+ readonly t: Translate;
5
+ }
6
+ /**
7
+ * 会话行前面那颗「长任务还在跑」的点;两种左栏共用同一个 `sidebar.session.row.leading` 座位。
8
+ * @param props.sessionId - 这一行的会话。
9
+ * @param props.t - 词表(只在提示里用)。
10
+ * @returns 有长任务时一个状态点,否则 `null`。
11
+ */
12
+ export declare function LongTaskDot({ sessionId, t }: LongTaskDotProps): JSX.Element | null;
@@ -0,0 +1,12 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ export interface LongTaskHoverProps {
3
+ readonly sessionId: string;
4
+ readonly t: Translate;
5
+ }
6
+ /**
7
+ * 悬停卡里那行「长任务在跑」;两种左栏共用一个 `sidebar.session.row.hover` 座位。
8
+ * @param props.sessionId - 这一行的会话。
9
+ * @param props.t - 词表。
10
+ * @returns 有长任务时一行灰字,否则 `null`。
11
+ */
12
+ export declare function LongTaskHover({ sessionId, t }: LongTaskHoverProps): JSX.Element | null;
@@ -0,0 +1,24 @@
1
+ import type { DshClientContext } from '@dsh-workbench/shared';
2
+ import type { SidebarEdition } from '../../../shared/api/sidebar-edition';
3
+ /**
4
+ * 设置项点下去之后记一笔“想切到哪一档”,刷新后据此等组合跟上;
5
+ * 不用它区分“刚切换”和“旧组合兜底”,否则官方档会被当成切坏了。
6
+ * @param edition 用户选的目标档位。
7
+ */
8
+ export declare function markSidebarEditionPending(edition: SidebarEdition): void;
9
+ /**
10
+ * 切自定义时先把“官方被摘掉就接管”挂上,再发写口——这样组合一生效就原地换成
11
+ * 我们的左栏,不必刷新,也不会出现左栏空一拍。
12
+ */
13
+ export declare function armCustomSidebarTakeover(): void;
14
+ /**
15
+ * 写口没成时把待接管撤掉,别在 3 秒后误刷新。
16
+ */
17
+ export declare function disarmCustomSidebarTakeover(): void;
18
+ /**
19
+ * 启动时按组合决定左栏:先把官方座位让出来;官方没落地才注册我们自己的。
20
+ * 官方 → 自定义刚写完时组合可能还没跟上,官方座位还在;这时最多自刷 2 次等它。
21
+ * @param ctx 客户端上下文(只读 slots)。
22
+ * @param registerOwn 注册工作台自己那套左栏(调用方保证幂等)。
23
+ */
24
+ export declare function bootSidebarEdition(ctx: DshClientContext, registerOwn: () => void): void;
@@ -0,0 +1,22 @@
1
+ import type { SidebarEdition } from '../../../shared/api/sidebar-edition';
2
+ /**
3
+ * 这一屏启动时按哪一档左栏渲染;组合层决定的,改它要刷新页面。
4
+ * @returns 运行态档位(默认官方)。
5
+ */
6
+ export declare function runtimeSidebarEdition(): SidebarEdition;
7
+ /**
8
+ * 记下这一屏的左栏档位(只在启动时由客户端调用一次)。
9
+ * @param next 读到的档位。
10
+ */
11
+ export declare function setRuntimeSidebarEdition(next: SidebarEdition): void;
12
+ /**
13
+ * 订阅运行态档位的变化(目前只在启动时变一次)。
14
+ * @param listener 变化时的回调。
15
+ * @returns 取消订阅。
16
+ */
17
+ export declare function subscribeSidebarEdition(listener: () => void): () => void;
18
+ /**
19
+ * 组件里读运行态档位(启动后解析出来才变一次,变了会重渲染)。
20
+ * @returns 运行态档位。
21
+ */
22
+ export declare function useRuntimeSidebarEdition(): SidebarEdition;
@@ -0,0 +1,5 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ export interface ConfigSyncItemProps {
3
+ readonly t: Translate;
4
+ }
5
+ export declare function ConfigSyncItem({ t }: ConfigSyncItemProps): JSX.Element;
@@ -0,0 +1,17 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface SettingsItemProps {
3
+ readonly title: string;
4
+ readonly description?: string | undefined;
5
+ readonly action?: ReactNode | undefined;
6
+ readonly children?: ReactNode | undefined;
7
+ }
8
+ /**
9
+ * 设置一节里的一个配置项:自己的标题、一句说明、右上动作与内容。
10
+ * 多个配置项叠在同一节里,项与项之间由样式画分隔线。
11
+ * @param props.title - 这一项的名字(同时给读屏,`aria-label`)。
12
+ * @param props.description - 项下面那句说明;不给不占位。
13
+ * @param props.action - 标题右侧的动作(如"重新读一遍");不给不占位。
14
+ * @param props.children - 这一项的内容。
15
+ * @returns 一个 `aria-label` 为标题的 `section`。
16
+ */
17
+ export declare function SettingsItem({ title, description, action, children }: SettingsItemProps): JSX.Element;
@@ -0,0 +1,11 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ export interface SidebarEditionItemProps {
3
+ readonly t: Translate;
4
+ }
5
+ /**
6
+ * 「工作台设置」里的「会话列表」项:选官方还是自定义左栏。
7
+ * 写入的是 profile patch 那一行;与当前这一屏的档位不同就提示刷新页面。
8
+ * @param props.t - 这一项的词表。
9
+ * @returns 一个配置项。
10
+ */
11
+ export declare function SidebarEditionItem({ t }: SidebarEditionItemProps): JSX.Element;
@@ -0,0 +1,11 @@
1
+ import type { Translate } from '@dsh-workbench/shared';
2
+ export interface WorkbenchSettingsSectionProps {
3
+ readonly t: Translate;
4
+ }
5
+ /**
6
+ * 设置页里「工作台设置」这一节:工作台自己这一侧的配置都收在这里,一项一张。
7
+ * 现在是「会话列表」与「配置同步」两项;再加配置项时按 `SettingsItem` 的形状往下排。
8
+ * @param props.t - 这一节的词表。
9
+ * @returns 设置页的一节。
10
+ */
11
+ export declare function WorkbenchSettingsSection({ t }: WorkbenchSettingsSectionProps): JSX.Element;
@@ -1,10 +1,18 @@
1
- import type { ApprovalPolicy } from '@dsh-workbench/shared/host';
1
+ import type { ApprovalPolicy, RecordState } from '@dsh-workbench/shared/host';
2
2
  import type { LongTaskRunsLookup } from './long-task-tools';
3
+ /**
4
+ * 面板族不带现场的那份策略:只按调用本身判(长任务按"别人的"问、录制一律问)。
5
+ * 要它认现场(这一趟是谁起的、此刻有没有活着的录制)就用 `panelsApprovalFor`。
6
+ */
3
7
  export declare const panelsApproval: ApprovalPolicy;
4
8
  /**
5
- * 面板族的审批策略:`panelsApproval` 再认长任务那一档(写成功要用户点头)。
9
+ * 面板族的审批策略:`panelsApproval` 再认两档现场 —— 长任务那一档(别人的写要用户点头)与
10
+ * 录制那一档(已经活着的一场录制:再 prepare 一定当场失败,连问都不问)。
6
11
  * `longTaskRuns` 用来查"这一趟是谁起的" —— 自己起的免问,别的会话起的 / 用户按的要问。
12
+ * `recording` 返回此刻活着的录制约定(没有就 `null`):活着时 `record_prepare` 回 `deny`(理由 = 处理函数
13
+ * 会回的那句"另一场还占着 / 你已持有一场"),因为那一拍占不到屏、问了也白问。
7
14
  * @param longTaskRuns 当前挂着的单元各自那把长任务注册表;没给就按"别人的"问(保守的那一侧)。
8
- * @returns 审批策略:认领的写工具回 ask / allow,不是本族的回 undefined。
15
+ * @param recording 活着的录制约定取值器;没给就照旧问(老外壳 / 老套件的那一侧)。
16
+ * @returns 审批策略:认领的写工具回 ask / allow / deny,不是本族的回 undefined。
9
17
  */
10
- export declare function panelsApprovalFor(longTaskRuns?: LongTaskRunsLookup | undefined): ApprovalPolicy;
18
+ export declare function panelsApprovalFor(longTaskRuns?: LongTaskRunsLookup | undefined, recording?: (() => RecordState | null) | undefined): ApprovalPolicy;
@@ -34,6 +34,6 @@ export declare function clipNote(clip: PngClip, viewport: {
34
34
  readonly width: number;
35
35
  readonly height: number;
36
36
  }): string;
37
- export declare function defaultShotPath(packagesDir: string, unit: string, stamp: number): string;
37
+ export declare function defaultShotPath(dir: string, unit: string, stamp: number): string;
38
38
  export declare const BROWSER_TOOLS: readonly BrowserToolRow[];
39
39
  export declare function registerBrowserTools(ctx: DshHostContext, tools: DshToolRegistry): readonly (() => void)[];
@@ -7,7 +7,7 @@ export declare const OUTPUT_SCHEMA: {
7
7
  text: {
8
8
  type: string;
9
9
  };
10
- workshop: {
10
+ workspace: {
11
11
  type: string;
12
12
  };
13
13
  modules: {
@@ -44,7 +44,7 @@ export declare const OUTPUT: {
44
44
  text: {
45
45
  type: string;
46
46
  };
47
- workshop: {
47
+ workspace: {
48
48
  type: string;
49
49
  };
50
50
  modules: {
@@ -89,22 +89,39 @@ export declare function showOrReason(panels: PanelsService, unit: string, worksp
89
89
  readonly reason?: string;
90
90
  };
91
91
  /**
92
- * 这一次 DIY 调用落在哪个工坊上:**先认工坊自己的家**(`$DSH_HOME/workbench/diy`,宿主就是按它把工坊
93
- * 登记成工作区的),**不跟着会话 cwd 走** —— 用户把自己的项目设成工作区时,cwd 往上找会撞上任意一个
94
- * 带 `packages/` 的仓库,模块列表与 `shots/` 落点会一起变样(真机踩过:录制落点跑到仓库根、截图 EPERM)。
95
- * 只有拿不到工坊的家时,才退回"从会话工作区往上找像工坊的目录"。
92
+ * 这条会话在哪个工作区上:cwd → 登记的 workspace(开在子目录也落到工作区根)。DIY 的模块、面板、
93
+ * 调试与工件全跟着它 —— **不猜、不回落到工坊**。
96
94
  * @param ctx - 宿主上下文。
97
- * @param exec - 这次工具调用(退回那一档要读它的会话工作区)。
98
- * @returns 工坊的 packages 目录、根路径与标题。
95
+ * @param exec - 这次工具调用(读它的会话 cwd)。
96
+ * @returns 工作区根与标题。
99
97
  */
100
- export declare function workshopOf(ctx: DshHostContext, exec: DshToolRunContext): Promise<{
101
- readonly packagesDir: string;
102
- readonly workspace: string | null;
98
+ export declare function workspaceOf(ctx: DshHostContext, exec: DshToolRunContext): Promise<{
99
+ readonly root: string;
103
100
  readonly title: string;
104
101
  }>;
105
- export declare function modulesOf(ctx: DshHostContext, packagesDir: string): {
102
+ export interface KnownUnit {
103
+ readonly unit: string;
104
+ readonly name: string;
105
+ readonly description: string;
106
+ readonly dir: string;
107
+ readonly installed: boolean;
108
+ }
109
+ /**
110
+ * 这条会话能看见的单元:**装进 profile 的**(不管源码在哪)+ 这个工作区里声明了的那几个。
111
+ * 看板 / 调试 / 上板只认"装没装"(源码在不在本机这个工作区里是另一件事);`dir` 空串表示
112
+ * 只有安装记录、这个工作区里没有它的源码。工作区是什么结构都不影响这一层。
113
+ * @param ctx - 宿主上下文(要 profile 服务)。
114
+ * @param root - 会话的登记工作区。
115
+ * @returns 已装 id 名单、工作区里的模块、以及两者合并后的单元表(按 unit 排序,同 id 以工作区那份为准)。
116
+ */
117
+ export declare function unitsOf(ctx: DshHostContext, root: string): {
118
+ installed: string[];
119
+ modules: readonly import("@/shared/api/host/diy-modules").DiyModule[];
120
+ units: readonly KnownUnit[];
121
+ };
122
+ export declare function modulesOf(ctx: DshHostContext, root: string): {
106
123
  installed: string[];
107
- modules: readonly import("@/shared/api/host/diy-workshop").WorkshopModule[];
124
+ modules: readonly import("@/shared/api/host/diy-modules").DiyModule[];
108
125
  };
109
- export declare function moduleDirsOf(packagesDir: string): readonly string[];
126
+ export declare function moduleDirsOf(root: string): readonly string[];
110
127
  export declare function panelEntriesOf(panels: PanelsService, workspace: string | null): import("./config").PanelEntry[];
@@ -4,7 +4,8 @@ import { type BoardFactState, type BoardProbe, type BoardSituation } from '@dsh-
4
4
  import { type WorkbenchPage } from './diy-browser';
5
5
  export type BoardState = BoardFactState;
6
6
  export interface PageHandle {
7
- readonly packagesDir: string;
7
+ readonly root: string;
8
+ readonly artifactsDir: string;
8
9
  readonly unit: string;
9
10
  readonly args: Record<string, unknown>;
10
11
  readonly shell: DshShell;
@@ -17,7 +18,7 @@ export interface PageHandle {
17
18
  export interface PageOptions {
18
19
  readonly requireWorkbench?: boolean | undefined;
19
20
  readonly requireUnit?: boolean | undefined;
20
- readonly requireBoard?: 'workshop' | false | undefined;
21
+ readonly requireBoard?: boolean | undefined;
21
22
  readonly requirePact?: boolean | undefined;
22
23
  }
23
24
  export declare function debugPausedText(held: DebugState): string;
@@ -14,12 +14,12 @@ export declare const DETAIL_MAX_BYTES = 60000;
14
14
  export declare const pauseFor: (ms: number) => Promise<void>;
15
15
  export declare function waitOf(value: unknown): number;
16
16
  export declare function foreignDomainText(design: unknown, url: string): string;
17
- export declare function captureFileOf(packagesDir: string, unit: string): string;
17
+ export declare function captureFileOf(artifactsDir: string, unit: string): string;
18
18
  export declare function lastCaptureFileOf(file: string): string;
19
19
  /**
20
- * 这一族自己的落图路径:跟 `rec-<unit>.jsonl` 同目录、`rec-shot-` 前缀(工坊那一页的图另有名字)。
20
+ * 这一族自己的落图路径:跟 `rec-<unit>.jsonl` 同目录(外壳的取证目录)、`rec-shot-` 前缀。
21
21
  * @param captureFile - 这一场捕获文件;图就落在它旁边。@param unit - 单元名。@param n - 页面「已拍」计数。
22
- * @returns 形如 `…/shots/rec-shot-<unit>-<n>.png` 的路径。
22
+ * @returns 形如 `…/artifacts/<工作区>/rec-shot-<unit>-<n>.png` 的路径。
23
23
  */
24
24
  export declare function shotFileOf(captureFile: string, unit: string, n: number): string;
25
25
  /**
@@ -1,11 +1,11 @@
1
1
  import type { PanelUnitReport } from '@dsh-workbench/shared/host';
2
- import { type WorkshopModule, type WorkshopSync, type WorkshopToolchain } from '../../../shared/api/host/diy-workshop';
2
+ import { type DiyModule, type SyncState, type Toolchain, type WorkspaceShape } from '../../../shared/api/host/diy-modules';
3
3
  export declare const SYNC_STALE_MINUTES = 15;
4
4
  export declare const SYNC_STALE_MS: number;
5
5
  export declare function syncNotice(input: {
6
- readonly sync: WorkshopSync | undefined;
6
+ readonly sync: SyncState | undefined;
7
7
  readonly shellVersion: string | undefined;
8
- readonly toolchain: WorkshopToolchain | undefined;
8
+ readonly toolchain: Toolchain | undefined;
9
9
  readonly now?: number;
10
10
  readonly windowMs?: number;
11
11
  }): string | undefined;
@@ -32,8 +32,7 @@ export declare function ageText(at: number, now: number): string;
32
32
  export declare function stampOf(at: number): string;
33
33
  export declare function readText(read: PanelUnitReport['cards'][number], now: number): string;
34
34
  export declare function renderPanel(options: {
35
- readonly packagesDir: string;
36
- readonly workspace: string | null;
35
+ readonly root: string;
37
36
  readonly rows: readonly {
38
37
  readonly unit: string;
39
38
  readonly name: string;
@@ -68,7 +67,7 @@ export declare function statusOf(options: {
68
67
  readonly open: boolean;
69
68
  readonly health: SuiteHealth;
70
69
  }): ModuleStatus;
71
- export declare function renderStatus(packagesDir: string, lines: readonly ModuleStatus[], options?: {
70
+ export declare function renderStatus(root: string, lines: readonly ModuleStatus[], options?: {
72
71
  readonly shellVersion?: string;
73
72
  }): string;
74
- export declare function renderList(packagesDir: string, modules: readonly WorkshopModule[]): string;
73
+ export declare function renderList(root: string, modules: readonly DiyModule[], shape?: WorkspaceShape): string;
@@ -0,0 +1,21 @@
1
+ import type { UnitCapability } from '../../../shared/api/host/probe-units';
2
+ import { type DependencyTarget, type SharedDependency } from './market-dependency';
3
+ export interface DependencyUpdateDeps {
4
+ readonly command: string;
5
+ readonly capabilityOf: (unit: string, force?: boolean) => Promise<UnitCapability>;
6
+ readonly runAll: (commands: readonly {
7
+ readonly line: string;
8
+ readonly optional?: true;
9
+ }[]) => Promise<void>;
10
+ readonly snapshot: () => Promise<readonly SharedDependency[]>;
11
+ readonly logger?: {
12
+ info?(message: string): void;
13
+ warn?(message: string): void;
14
+ } | undefined;
15
+ }
16
+ /**
17
+ * 共用依赖那一行的「更新」:只跑点名的那一份,跑完**强探**声明它的每个模块;
18
+ * 仍落后就抛出原因(含“这一行没有可执行的更新命令”),不静默返回旧清单。
19
+ * @param target `findDependency` 找到的那一份(插件或库)。
20
+ */
21
+ export declare function updateDependencyRow(target: DependencyTarget, deps: DependencyUpdateDeps): Promise<readonly SharedDependency[]>;
@@ -20,6 +20,7 @@ export type ProvisionResult = {
20
20
  readonly change: BundleChange;
21
21
  readonly module: InstalledModule;
22
22
  readonly supply: BundleSupply;
23
+ readonly restored?: string;
23
24
  } | {
24
25
  readonly ok: true;
25
26
  readonly action: 'remove-bundle';
@@ -48,6 +48,7 @@ export interface BundleInstallOutcome {
48
48
  readonly module: InstalledModule;
49
49
  readonly supply: BundleSupply;
50
50
  readonly plugin?: BundleInstalledPlugin;
51
+ readonly restored?: string;
51
52
  }
52
53
  export interface BundleRemoveOutcome {
53
54
  readonly change: BundleChange;