@dsh-workbench/core 0.1.17 → 0.2.0

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 (64) hide show
  1. package/client.js +1026 -554
  2. package/dist/board.css +31 -0
  3. package/dist/client/client.body.js +1026 -554
  4. package/dist/client/index.js +1027 -555
  5. package/dist/host/index.js +1175 -146
  6. package/dist/types/app/client.d.ts +111 -69
  7. package/dist/types/app/layouts/market/__tests__/add-module-stages.test.d.ts +1 -0
  8. package/dist/types/app/layouts/market/add-module-text.d.ts +16 -1
  9. package/dist/types/app/layouts/market/use-add-module.d.ts +2 -8
  10. package/dist/types/app/layouts/market/use-module-versions.d.ts +2 -1
  11. package/dist/types/app/layouts/rightbar/MarketView.d.ts +5 -1
  12. package/dist/types/app/layouts/rightbar/ModulesPage.d.ts +4 -2
  13. package/dist/types/app/layouts/rightbar/PanelModules.d.ts +2 -2
  14. package/dist/types/app/layouts/rightbar/PanelPluginRows.d.ts +9 -0
  15. package/dist/types/app/layouts/rightbar/PanelRowControls.d.ts +14 -0
  16. package/dist/types/app/layouts/rightbar/__tests__/market-row-icon.test.d.ts +1 -0
  17. package/dist/types/app/layouts/rightbar/__tests__/market-section-icon.test.d.ts +1 -0
  18. package/dist/types/app/layouts/rightbar/__tests__/market-workbench.test.d.ts +1 -0
  19. package/dist/types/app/layouts/rightbar/__tests__/panel-plugin-rows.test.d.ts +1 -0
  20. package/dist/types/app/layouts/rightbar/__tests__/panel-scope-ui.test.d.ts +1 -0
  21. package/dist/types/app/layouts/rightbar/board-selection.d.ts +11 -0
  22. package/dist/types/app/layouts/rightbar/market-act.d.ts +21 -0
  23. package/dist/types/app/layouts/rightbar/market-freshness.d.ts +1 -0
  24. package/dist/types/app/layouts/rightbar/market-mock.d.ts +6 -1
  25. package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +3 -1
  26. package/dist/types/app/layouts/rightbar/market-row-icon.d.ts +7 -0
  27. package/dist/types/app/layouts/rightbar/market-row-types.d.ts +35 -0
  28. package/dist/types/app/layouts/rightbar/market-rows.d.ts +8 -35
  29. package/dist/types/app/layouts/rightbar/market-section-icon.d.ts +3 -0
  30. package/dist/types/app/layouts/rightbar/market-section.d.ts +18 -0
  31. package/dist/types/app/layouts/rightbar/market-view-text.d.ts +7 -1
  32. package/dist/types/app/layouts/rightbar/market-workbench-row.d.ts +5 -0
  33. package/dist/types/app/layouts/rightbar/panel-mock.d.ts +2 -1
  34. package/dist/types/app/layouts/rightbar/use-panels.d.ts +15 -1
  35. package/dist/types/app/units/registry.d.ts +1 -1
  36. package/dist/types/modules/panels/__tests__/plugin-panel-market-parity.test.d.ts +1 -0
  37. package/dist/types/modules/panels/__tests__/plugin-panel.test.d.ts +1 -0
  38. package/dist/types/modules/panels/__tests__/plugin-tool-units.test.d.ts +1 -0
  39. package/dist/types/modules/panels/__tests__/scope-machine.test.d.ts +1 -0
  40. package/dist/types/modules/panels/__tests__/scope-support.d.ts +51 -0
  41. package/dist/types/modules/panels/model/config.d.ts +19 -0
  42. package/dist/types/modules/panels/model/market-dispatch.d.ts +4 -0
  43. package/dist/types/modules/panels/model/market-registry.d.ts +12 -0
  44. package/dist/types/modules/panels/model/market-registry.test.d.ts +1 -0
  45. package/dist/types/modules/panels/model/market-types.d.ts +1 -0
  46. package/dist/types/modules/panels/model/market.d.ts +3 -2
  47. package/dist/types/modules/panels/model/plugin-panel.d.ts +3 -0
  48. package/dist/types/modules/panels/model/prefs.d.ts +3 -1
  49. package/dist/types/modules/panels/model/service.d.ts +5 -1
  50. package/dist/types/shared/api/bundle-install.d.ts +15 -1
  51. package/dist/types/shared/api/host/__tests__/plugin-catalog.test.d.ts +1 -0
  52. package/dist/types/shared/api/host/__tests__/plugin-login-hint.test.d.ts +1 -0
  53. package/dist/types/shared/api/host/__tests__/plugin-tools.test.d.ts +1 -0
  54. package/dist/types/shared/api/host/bundle-inspect-kind.test.d.ts +1 -0
  55. package/dist/types/shared/api/host/bundle-routes-self.test.d.ts +1 -0
  56. package/dist/types/shared/api/host/installed-module.d.ts +10 -0
  57. package/dist/types/shared/api/host/plugin-catalog.d.ts +60 -0
  58. package/dist/types/shared/api/host/plugin-login-hint.d.ts +2 -0
  59. package/dist/types/shared/api/host/plugin-tools.d.ts +10 -0
  60. package/dist/types/shared/api/host/plugin-units.d.ts +47 -0
  61. package/dist/types/shared/api/host/unit-registry.d.ts +3 -0
  62. package/package.json +2 -2
  63. package/skills/workbench-module-diy/REVIEW.md +2 -2
  64. package/skills/workbench-module-diy/TOOLS.md +4 -1
@@ -1,8 +1,8 @@
1
1
  import type { DshShell } from '@dsh-workbench/shared';
2
2
  import type { UnitManifest } from '@dsh-workbench/shared';
3
3
  import type { BundleManager } from '../../../shared/api/host/bundle-manager';
4
- import type { InstalledModule, ProfileModule } from '../../../shared/api/host/installed-module';
5
- import { type RegistryNotebook } from '../../../shared/api/host/profile-registries';
4
+ import type { InstalledModule, ProfileModule, ProfilePackage } from '../../../shared/api/host/installed-module';
5
+ import type { RegistryNotebook } from '../../../shared/api/host/profile-registries';
6
6
  import type { UnitMountDeps } from '@dsh-workbench/shared/host';
7
7
  import { type PluginReferences } from './plugin-actions';
8
8
  import type { PluginLedger } from './plugin-ledger';
@@ -21,6 +21,7 @@ export declare function createMarketService(options: {
21
21
  bundles?: BundleManager | undefined;
22
22
  installed?: ((pkg: string) => InstalledModule) | undefined;
23
23
  modules?: (() => readonly ProfileModule[]) | undefined;
24
+ workbench?: ((pkg: string) => ProfilePackage | undefined) | undefined;
24
25
  registries?: RegistryNotebook | undefined;
25
26
  ledger?: PluginLedger | undefined;
26
27
  references?: (() => PluginReferences) | undefined;
@@ -0,0 +1,3 @@
1
+ import type { PanelPluginRef } from './config';
2
+ import type { PluginLedger } from './plugin-ledger';
3
+ export declare function pluginPanelRefs(ledger: PluginLedger): PanelPluginRef[];
@@ -1,10 +1,12 @@
1
+ import type { BoardTarget } from './config';
1
2
  import type { PanelsService } from './service';
2
3
  export declare const PANELS_PREF_RESOURCE = "panels";
3
4
  export interface PanelsPrefAction {
4
- readonly action: 'show' | 'hide' | 'enable' | 'disable' | 'move' | 'reset';
5
+ readonly action: 'show' | 'hide' | 'move' | 'reset' | 'follow';
5
6
  readonly id?: string;
6
7
  readonly index?: number;
7
8
  readonly path?: string;
9
+ readonly scope?: BoardTarget;
8
10
  }
9
11
  export declare function parsePanelsPrefAction(payload: unknown): PanelsPrefAction;
10
12
  export declare function applyPanelsPref(panels: PanelsService, payload: unknown): {
@@ -1,11 +1,12 @@
1
1
  import type { WorkspaceStore } from '@dsh-workbench/shared/host';
2
2
  import type { UnitManifest } from '@dsh-workbench/shared';
3
- import { type BoardTarget, type PanelEntry, type ScopeBoards } from './config';
3
+ import { type BoardTarget, type PanelEntry, type PanelPluginEntry, type PanelPluginRef, type ScopeBoards } from './config';
4
4
  export declare const PANELS_MODULE_ID = "panels";
5
5
  export declare const PANELS_FILE = "config.json";
6
6
  export declare const RELEASED_FILE = "released.json";
7
7
  export interface PanelsService {
8
8
  list(workspace: string | null, target?: BoardTarget): PanelEntry[];
9
+ listPlugins(workspace: string | null, target?: BoardTarget): PanelPluginEntry[];
9
10
  boards(workspace: string | null): ScopeBoards;
10
11
  isReleased(id: string): boolean;
11
12
  release(id: string): void;
@@ -16,11 +17,14 @@ export interface PanelsService {
16
17
  hide(id: string, workspace: string | null, target?: BoardTarget): PanelEntry[];
17
18
  move(id: string, index: number, workspace: string | null, target?: BoardTarget): PanelEntry[];
18
19
  reset(workspace: string | null, target?: BoardTarget): PanelEntry[];
20
+ follow(workspace: string | null, id?: string): PanelEntry[];
21
+ changedBy(): ReadonlyMap<string, number>;
19
22
  }
20
23
  export declare function createPanelsService(options: {
21
24
  manifests: () => readonly UnitManifest[];
22
25
  store: WorkspaceStore;
23
26
  owned?: (() => readonly string[]) | undefined;
27
+ plugins?: (() => readonly PanelPluginRef[]) | undefined;
24
28
  logger?: {
25
29
  warn?(message: string): void;
26
30
  } | undefined;
@@ -26,7 +26,14 @@ export interface BundleInspectionRefused {
26
26
  readonly reason: string;
27
27
  readonly registries?: readonly BundleRegistry[];
28
28
  }
29
- export type BundleInspection = BundleInspectionAccepted | BundleInspectionRefused;
29
+ export interface BundleInspectionPlugin {
30
+ readonly status: 'plugin';
31
+ readonly pkg: string;
32
+ readonly registry: BundleRegistry;
33
+ readonly pluginName?: string;
34
+ readonly version?: string;
35
+ }
36
+ export type BundleInspection = BundleInspectionAccepted | BundleInspectionRefused | BundleInspectionPlugin;
30
37
  export interface BundleRegistriesPayload {
31
38
  readonly available: boolean;
32
39
  readonly registries: BundleRegistries | null;
@@ -100,6 +107,13 @@ export interface ModuleVersion {
100
107
  readonly local?: boolean;
101
108
  readonly refused?: readonly string[];
102
109
  }
110
+ export interface WorkbenchVersion {
111
+ readonly pkg: string;
112
+ readonly installed: string;
113
+ readonly latest?: string;
114
+ readonly local?: boolean;
115
+ }
103
116
  export interface ModuleVersionsPayload {
104
117
  readonly modules: readonly ModuleVersion[];
118
+ readonly workbench?: WorkbenchVersion;
105
119
  }
@@ -30,4 +30,14 @@ export interface DeclarationGap {
30
30
  readonly problems: readonly string[];
31
31
  }
32
32
  export declare function declarationGaps(profileDir: string | null): readonly DeclarationGap[] | undefined;
33
+ export declare function declaredPluginCommands(profileDir: string | null): ReadonlyMap<string, ReadonlySet<string>>;
33
34
  export declare function readInstalledModule(profileDir: string | null, pkg: string): InstalledModule;
35
+ export declare function isLocalDependencySpec(spec: string): boolean;
36
+ export interface ProfilePackage {
37
+ readonly pkg: string;
38
+ readonly version: string;
39
+ readonly registry?: string;
40
+ readonly local?: boolean;
41
+ }
42
+ export declare function readProfilePackage(profileDir: string | null, pkg: string): ProfilePackage | undefined;
43
+ export declare function packageVersionAt(packageRoot: string): string | undefined;
@@ -0,0 +1,60 @@
1
+ import type { DshShell } from '@dsh-workbench/shared';
2
+ export interface PluginCommandArg {
3
+ readonly name: string;
4
+ readonly type: string;
5
+ readonly required: boolean;
6
+ readonly positional: boolean;
7
+ readonly valueRequired: boolean;
8
+ readonly choices: readonly string[];
9
+ readonly defaultValue?: unknown;
10
+ readonly help: string;
11
+ }
12
+ export interface PluginCommand {
13
+ readonly plugin: string;
14
+ readonly name: string;
15
+ readonly description: string;
16
+ readonly access: string;
17
+ readonly domain?: string;
18
+ readonly args: readonly PluginCommandArg[];
19
+ }
20
+ export interface PluginCommandSet {
21
+ readonly plugin: string;
22
+ readonly version: string;
23
+ readonly commands: readonly PluginCommand[];
24
+ }
25
+ export interface PluginRow {
26
+ readonly name: string;
27
+ readonly version: string;
28
+ readonly commands: readonly string[];
29
+ }
30
+ export interface CommandRow {
31
+ readonly site: string;
32
+ readonly name: string;
33
+ readonly description: string;
34
+ readonly access: string;
35
+ readonly args: readonly PluginCommandArg[];
36
+ }
37
+ export interface PluginCatalogSnapshot {
38
+ readonly ok: boolean;
39
+ readonly at: number;
40
+ readonly sets: readonly PluginCommandSet[];
41
+ readonly problems: readonly string[];
42
+ }
43
+ export interface PluginCatalog {
44
+ refresh(options?: {
45
+ readonly force?: boolean;
46
+ }): Promise<PluginCatalogSnapshot>;
47
+ snapshot(): PluginCatalogSnapshot;
48
+ }
49
+ export interface PluginCatalogOptions {
50
+ readonly shell?: DshShell | undefined;
51
+ readonly command: string;
52
+ readonly timeoutMs?: number;
53
+ }
54
+ export declare function parsePluginRows(stdout: string): PluginRow[] | undefined;
55
+ export declare function parseCommandRows(stdout: string): CommandRow[] | undefined;
56
+ export declare function attributeCommands(plugins: readonly PluginRow[], rows: readonly CommandRow[]): {
57
+ readonly sets: PluginCommandSet[];
58
+ readonly problems: string[];
59
+ };
60
+ export declare function createPluginCatalog(options: PluginCatalogOptions): PluginCatalog;
@@ -0,0 +1,2 @@
1
+ export declare function loginUrlOfDomain(domain: string | undefined): string | undefined;
2
+ export declare function pluginLoginHint(error: unknown, domain: string | undefined): string;
@@ -0,0 +1,10 @@
1
+ import type { ApprovalDetail, ApprovalPolicy } from '@dsh-workbench/shared/host';
2
+ import type { PluginCommand } from './plugin-catalog';
3
+ export declare function pluginToolName(plugin: string, command: string): string;
4
+ export declare function pluginToolParameters(command: PluginCommand): Record<string, unknown>;
5
+ export declare function pluginToolDescription(command: PluginCommand): string;
6
+ export declare function pluginToolWrites(command: PluginCommand): boolean;
7
+ export declare function pluginToolArgv(command: PluginCommand, raw: unknown): string[];
8
+ export declare function pluginKeyArgs(command: PluginCommand, raw: unknown): string;
9
+ export declare function pluginApprovalQuestion(command: PluginCommand, raw: unknown): ApprovalDetail;
10
+ export declare function pluginApprovalFor(command: PluginCommand): ApprovalPolicy;
@@ -0,0 +1,47 @@
1
+ import type { Opencli } from '@dsh-workbench/shared/host';
2
+ import type { PluginCatalog } from './plugin-catalog';
3
+ import type { UnitRegistry } from './unit-registry';
4
+ export interface PluginRowRef {
5
+ readonly id: string;
6
+ readonly pkg: string;
7
+ readonly name?: string | undefined;
8
+ }
9
+ export interface PluginRowsSource {
10
+ listPlugins(workspace: string | null): readonly PluginRowRef[];
11
+ subscribe?(listener: () => void): () => void;
12
+ }
13
+ export interface PluginUnitRow {
14
+ readonly plugin: string;
15
+ readonly pkg: string;
16
+ readonly version: string;
17
+ readonly commands: number;
18
+ readonly synthesized: number;
19
+ readonly tools: readonly string[];
20
+ }
21
+ export interface PluginUnitReport {
22
+ readonly ok: boolean;
23
+ readonly at: number;
24
+ readonly plugins: readonly PluginUnitRow[];
25
+ readonly problems: readonly string[];
26
+ }
27
+ export interface PluginUnits {
28
+ refresh(options?: {
29
+ readonly force?: boolean;
30
+ }): Promise<PluginUnitReport>;
31
+ touch(): void;
32
+ report(): PluginUnitReport;
33
+ dispose(): void;
34
+ }
35
+ export interface PluginUnitsOptions {
36
+ readonly registry: UnitRegistry;
37
+ readonly catalog: PluginCatalog;
38
+ readonly rows: () => readonly PluginRowRef[];
39
+ readonly declared: (plugin: string) => ReadonlySet<string>;
40
+ readonly opencliFor: (plugin: string) => Opencli;
41
+ readonly toolNames?: () => ReadonlySet<string>;
42
+ readonly logger?: {
43
+ info?(message: string): void;
44
+ warn?(message: string): void;
45
+ } | undefined;
46
+ }
47
+ export declare function createPluginUnits(options: PluginUnitsOptions): PluginUnits;
@@ -10,6 +10,8 @@ export type UnitSource = {
10
10
  readonly pkg: string;
11
11
  } | {
12
12
  readonly kind: 'owned';
13
+ } | {
14
+ readonly kind: 'plugin';
13
15
  };
14
16
  export interface HostUnit {
15
17
  readonly unit: string;
@@ -24,6 +26,7 @@ export interface UnitDeclarationSource {
24
26
  export interface UnitRegistry {
25
27
  register(face: UnitModuleFace): () => void;
26
28
  registerOwned(face: UnitOwnedFace): () => void;
29
+ registerPlugin(face: UnitOwnedFace): () => void;
27
30
  all(): readonly HostUnit[];
28
31
  owned(): readonly string[];
29
32
  refusals(): readonly UnitRefusal[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/core",
3
- "version": "0.1.17",
3
+ "version": "0.2.0",
4
4
  "description": "个人工作台:Agent 工作台外壳(左栏 + 常驻对话 + 自研右侧数据面板)。",
5
5
  "type": "module",
6
6
  "icon": "./icon.svg",
@@ -87,7 +87,7 @@
87
87
  "access": "public"
88
88
  },
89
89
  "dependencies": {
90
- "@dsh-workbench/shared": "0.1.17"
90
+ "@dsh-workbench/shared": "0.2.0"
91
91
  },
92
92
  "scripts": {
93
93
  "build": "node scripts/build.mjs && node scripts/build-types.mjs",
@@ -5,13 +5,13 @@
5
5
 
6
6
  | 判据 | 它防的事故 | 红了的典型说法 | 怎么修 |
7
7
  |---|---|---|---|
8
- | `contracts` | dsh 组合阶段**不校验**你 `package.json` 里的声明 —— 错的 `external` 要到浏览器 `require` 那一刻才炸;清单与代码、底稿与清单之间漂了也没人拦 | `单元 id "x" 与 … 撞了` / `dsh.workbenchFaces.client 指的文件不存在` / `dsh.workbenchFaces.host 没声明` / `没有对 @dsh-workbench/core 的 peer 依赖` / `没有 typecheck 脚本` / `它不是 private,却既没声明 publishConfig.access=public…` / `dsh.workbench 声明的能力与代码真正注册的对不上` / `design.json 的能力行里有「x」,清单的 tools[] 里却没有它` | 按报的那一条改 `package.json`;`unit` 换个不撞的名字;`dsh.workbenchFaces` 补上两个**源码**入口;四个脚本补全;私有不发就保持 `private: true`。**工具只声明在清单里**(`dsh.workbench.tools`)且必须与 `mount()` 里 `registerTools()` 真正注册的**不重不漏**;写了 `design.json` 的话,它的 `capabilities[].name` 与清单的 `tools[].name` 也要不重不漏(U1c 的**键集合对账**,只对名字 —— 内容各写一处);`gate.deniedTools` 是可选的运行期收窄,门禁不再对它做声明对账(协议里的 `scope` 已删 —— 哪些工作区出现由用户的板决定) |
8
+ | `contracts` | dsh 组合阶段**不校验**你 `package.json` 里的声明 —— 错的 `external` 要到浏览器 `require` 那一刻才炸;清单与代码、底稿与清单之间漂了也没人拦 | `单元 id "x" 与 … 撞了` / `dsh.workbenchFaces.client 指的文件不存在` / `dsh.workbenchFaces.host 没声明` / `没有对 @dsh-workbench/core 的 peer 依赖` / `没有 typecheck 脚本` / `它不是 private,却既没声明 publishConfig.access=public…` / `src/declared-tools.ts 与清单对不上(生成物过期…)` / `工具名的字面量又写回了源码` / `…没有 key` / `dsh.workbench 声明的能力与代码真正注册的对不上` / `design.json 的能力行里有「x」,清单的 tools[] 里却没有它` | 按报的那一条改 `package.json`(生成物对不上就跑 `dsh-wb-module sync`;工具名的字面量只许留在清单里);`unit` 换个不撞的名字;`dsh.workbenchFaces` 补上两个**源码**入口;四个脚本补全;私有不发就保持 `private: true`。**工具只声明在清单里**(`dsh.workbench.tools`)且必须与 `mount()` 里 `registerTools()` 真正注册的**不重不漏**;写了 `design.json` 的话,它的 `capabilities[].name` 与清单的 `tools[].name` 也要不重不漏(U1c 的**键集合对账**,只对名字 —— 内容各写一处);`gate.deniedTools` 是可选的运行期收窄,门禁不再对它做声明对账(协议里的 `scope` 已删 —— 哪些工作区出现由用户的板决定) |
9
9
  | `protocol` | `dsh.workbench` 是外壳读你得懂的那份声明:缺版本、形状不对、**多一个键**、枚举值不认都要在装机前拦下来。多出来的键最阴 —— 外壳会**静默忽略**它(拼错一个键 = 那句话白写) | `没有 apiVersion` / `apiVersion 是 99,这份只认 1` / `声明了 apiVersion 就要把静态半写全 —— 缺 dsh.workbench.tools` / `dsh.workbench 里有协议 v1 不认识的键 "faces"` / `card 里有不认的键 "enabledByDefault"`(这个键连外壳里都没有了 —— A-3 删的,见 [ADR-0038](../../../../docs/adr/0038-module-declaration-protocol.md) §6.7) / `tools[0] 里有协议不认的键 "scopes"` / `tools[0] 里有不认的键 "scope"`(`scope` 自本轮更正起**不在协议里**:能力在哪些工作区出现由用户的板决定,见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md)) | 补 `"apiVersion": 1`;把 `unit` / `card` / `tools` / `host` 四个键写全(没卡片写 `"card": null`、没工具写 `"tools": []`、一个服务都不要写 `"host": { "inject": [] }`);删掉协议外的键(`faces` 自 A-2 起搬到 `dsh.workbenchFaces`,写回 `dsh.workbench` 里就是生字段);`scope` **不要写**(协议不认它,写了就是生字段)。字段清单见 `dsh-wb-module` 的 README「协议」那一节 |
10
10
  | `bundles` | 两个运行时互串:浏览器产物里带 node 内置、宿主产物里带 DOM / react | `浏览器产物里出现了 node 内置 …` / `宿主产物里出现了 react` | 宿主面别 import 浏览器侧的东西;浏览器面别 import `node:*`。两侧只通过服务名相接 |
11
11
  | `source` | 非种子词的 `@deepseek-ai/*`、宿主侧碰 dsh 的浏览器包、`@/` 指到工作台源码 | `…在宿主侧可达` / `不是平台种子词` | 宿主侧只用 Node 侧的东西;dsh 原语一律走 `kit`;`@/` 只指自己的 `src/` |
12
12
  | `primitives` | 声明了 `external` 却没有产物物证 ⇒ dsh 原语被**内联**成第二份实例 | `…用了却没声明 external` / `宿主产物里出现了` | 在 `dsh.client.external` 里显式声明它;确认产物里是 `require(...)` 而不是被打包进来 |
13
13
  | `kit` | 用了 peer 下限那份外壳**还没有**的 kit 成员 ⇒ 卡片首帧 `Element type is invalid`,整块面板被 React 卸掉 | `kit.components.X 在这份外壳里没有` / `peer 下限比 devDependency 还旧` | 只用 peer 范围里真有的成员;把 `peerDependencies` 的下限提到你实际用的那档 |
14
- | `cards` | 卡片拿**空数据**就抛 ⇒ 用户看到"卡片一直不出来 / 点一下白屏" | `空数据下卡片抛了` / `卡片只画出一个节点` / `卡片没套外壳的卡壳` | 让卡片在没数据时也画得出来(已有的加载 / 空 / 阻断态);外面套 `kit.components.Card` |
14
+ | `cards` | 卡片拿**空数据**就抛 ⇒ 用户看到"卡片一直不出来 / 点一下白屏" | `空数据下卡片抛了` / `卡片只画出一个节点` / `卡片没套外壳的卡壳` / `清单的 card.titleKey「x」在模块字典的 en 里没有` / `…没有落点` | 让卡片在没数据时也画得出来(已有的加载 / 空 / 阻断态);外面套 `kit.components.Card`;清单写了 `titleKey`,`registerUnit` 交的 `messages` 里 `zh` / `en` 都得有那一条(漏了面板上显示的是原始键名) |
15
15
  | `standalone` | "只有工作台源码在场才编得过" ⇒ 发布出去就散架 | `build 在外壳源码不在场时失败` / `typecheck 在外壳源码不在场时失败` | 别引用工作台源码;`tsconfig` 里 `paths` 的值必须是**相对路径**(`"./src/*"`,不是 `"src/*"`) |
16
16
  | `markers` | 内网域名 / 企业内部名泄进要公开发布的包 | `命中内网 npm 源` / `命中内网域名` | 那些值不该写进包里;要配就落到模块自己的配置面,或走用户自己声明的来源 |
17
17
  | `alias` | `@/` 伸进工作台源码 ⇒ 装的人手上没有那份源码 | `…指向外壳源码` | `@/` 只许指自己的 `src/`;跨包的东西走包名 |
@@ -79,7 +79,7 @@
79
79
  ### 6.1 写法(清单 + 两个函数;缺一个门禁就红)
80
80
 
81
81
  ```ts
82
- tools: [{ name: 'workbench_demo_rebuild', writes: true }],
82
+ tools: [{ name: 'workbench_demo_rebuild', writes: true, key: 'rebuild' }],
83
83
 
84
84
  needsApproval: (call) => ({
85
85
  kind: 'ask',
@@ -91,6 +91,9 @@ needsApproval: (call) => ({
91
91
  approvalDetail: async (call) => ({ zh: '会覆盖这 3 个模块的产物,不碰源码', en: '…' }),
92
92
  ```
93
93
 
94
+ * `key` 是代码里那个短名(lowerCamelCase)。给了它就 `dsh-wb-module sync` 一次,生成
95
+ `src/declared-tools.ts`,代码写 `DECLARED_TOOLS.rebuild.name` —— 工具名的字面量只剩清单这一处
96
+ (键写错是编译错;生成物过期、半写 key、源码里又写字面量,门禁都红)。一个 key 都不写也行(不适用那一档)。
94
97
  * `needsApproval` 回 `{ kind: 'read' }` = 这件不用问;回 `{ kind: 'ask', … }` = 要问;
95
98
  **清单写着 `writes: true` 却不认领,外壳当场 deny**("在套件的 needsApproval 里补一条审批")——
96
99
  但那条错误只有真跑一次才看得见,所以 `check --only contracts` 会替用户先看一遍:缺 `needsApproval`、