@dsh-workbench/core 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.js +785 -2361
- package/dist/board.css +0 -12
- package/dist/client/client.body.js +785 -2361
- package/dist/client/index.js +786 -2362
- package/dist/host/index.js +2902 -859
- package/dist/types/app/client.d.ts +42 -52
- package/dist/types/app/layouts/rightbar/board-mock.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/board-plan.d.ts +2 -12
- package/dist/types/app/layouts/rightbar/board-shape.d.ts +14 -0
- package/dist/types/app/layouts/rightbar/kit-preview-controls.d.ts +10 -0
- package/dist/types/app/layouts/rightbar/kit-preview-frame.d.ts +14 -0
- package/dist/types/app/layouts/rightbar/kit-preview-rows.d.ts +5 -0
- package/dist/types/app/layouts/rightbar/kit-preview.d.ts +3 -0
- package/dist/types/app/layouts/rightbar/market-row-icon.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/market-section-icon.d.ts +1 -1
- package/dist/types/app/layouts/sidebar/workspace-groups.d.ts +0 -1
- package/dist/types/app/layouts/sidebar/workspace-items.d.ts +2 -3
- package/dist/types/dev/MockStrip.d.ts +15 -0
- package/dist/types/dev/surface-types.d.ts +53 -0
- package/dist/types/dev/surface.d.ts +2 -0
- package/dist/types/dev/surface.stub.d.ts +2 -0
- package/dist/types/modules/panels/__tests__/diy-harness.d.ts +32 -0
- package/dist/types/modules/panels/__tests__/market-tools-harness.d.ts +1 -1
- package/dist/types/modules/panels/__tests__/scope-support.d.ts +1 -1
- package/dist/types/modules/panels/model/diy-act.d.ts +4 -0
- package/dist/types/modules/panels/model/diy-act.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-browser-act.d.ts +47 -0
- package/dist/types/modules/panels/model/diy-browser.d.ts +47 -0
- package/dist/types/modules/panels/model/diy-browser.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-context.d.ts +102 -0
- package/dist/types/modules/panels/model/diy-context.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-logs.d.ts +18 -0
- package/dist/types/modules/panels/model/diy-logs.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-look.d.ts +14 -0
- package/dist/types/modules/panels/model/diy-look.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-net.d.ts +3 -0
- package/dist/types/modules/panels/model/diy-net.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-page.d.ts +15 -0
- package/dist/types/modules/panels/model/diy-page.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-schema.d.ts +9 -0
- package/dist/types/modules/panels/model/diy-schema.test.d.ts +1 -0
- package/dist/types/modules/panels/model/diy-scripts.d.ts +64 -0
- package/dist/types/modules/panels/unit.d.ts +43 -3
- package/dist/types/shared/api/diy.d.ts +4 -0
- package/dist/types/shared/api/host/__tests__/png-fixtures.d.ts +17 -0
- package/dist/types/shared/api/host/mount-units.d.ts +6 -0
- package/dist/types/shared/api/host/png-crop.d.ts +21 -0
- package/dist/types/shared/api/host/png-crop.test.d.ts +1 -0
- package/package.json +2 -2
- package/skills/workbench-module-diy/BUILD.md +4 -3
- package/skills/workbench-module-diy/DATASOURCE.md +4 -4
- package/skills/workbench-module-diy/DESIGN.md +1 -1
- package/skills/workbench-module-diy/KIT.md +121 -0
- package/skills/workbench-module-diy/PANEL.md +12 -2
- package/skills/workbench-module-diy/REVIEW.md +12 -6
- package/skills/workbench-module-diy/SKILL.md +7 -6
- package/skills/workbench-module-diy/TOOLING.md +5 -4
- package/skills/workbench-module-diy/TOOLS.md +3 -3
- package/skills/workbench-module-diy/WIRING.md +6 -6
- package/dist/types/app/layouts/sidebar/WorkspaceSearchField.d.ts +0 -9
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { DshHostContext, DshToolRunContext } from '@dsh-workbench/shared';
|
|
2
|
+
import { type BrowserFindResult, type BrowserReadResult } from '@dsh-workbench/shared/host';
|
|
3
|
+
import type { BundleChange } from '../../../shared/api/bundle-install';
|
|
4
|
+
import type { PanelsService } from './service';
|
|
5
|
+
export declare const OUTPUT_SCHEMA: {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: {
|
|
8
|
+
text: {
|
|
9
|
+
type: string;
|
|
10
|
+
};
|
|
11
|
+
workshop: {
|
|
12
|
+
type: string;
|
|
13
|
+
};
|
|
14
|
+
modules: {
|
|
15
|
+
type: string;
|
|
16
|
+
items: {
|
|
17
|
+
type: string;
|
|
18
|
+
additionalProperties: boolean;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
unit: {
|
|
22
|
+
type: string;
|
|
23
|
+
};
|
|
24
|
+
path: {
|
|
25
|
+
type: string;
|
|
26
|
+
};
|
|
27
|
+
install: {
|
|
28
|
+
type: string;
|
|
29
|
+
additionalProperties: boolean;
|
|
30
|
+
};
|
|
31
|
+
alreadyInstalled: {
|
|
32
|
+
type: string;
|
|
33
|
+
};
|
|
34
|
+
panel: {
|
|
35
|
+
type: string;
|
|
36
|
+
additionalProperties: boolean;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
additionalProperties: boolean;
|
|
40
|
+
};
|
|
41
|
+
export declare const OUTPUT: {
|
|
42
|
+
schema: {
|
|
43
|
+
type: string;
|
|
44
|
+
properties: {
|
|
45
|
+
text: {
|
|
46
|
+
type: string;
|
|
47
|
+
};
|
|
48
|
+
workshop: {
|
|
49
|
+
type: string;
|
|
50
|
+
};
|
|
51
|
+
modules: {
|
|
52
|
+
type: string;
|
|
53
|
+
items: {
|
|
54
|
+
type: string;
|
|
55
|
+
additionalProperties: boolean;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
unit: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
path: {
|
|
62
|
+
type: string;
|
|
63
|
+
};
|
|
64
|
+
install: {
|
|
65
|
+
type: string;
|
|
66
|
+
additionalProperties: boolean;
|
|
67
|
+
};
|
|
68
|
+
alreadyInstalled: {
|
|
69
|
+
type: string;
|
|
70
|
+
};
|
|
71
|
+
panel: {
|
|
72
|
+
type: string;
|
|
73
|
+
additionalProperties: boolean;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
additionalProperties: boolean;
|
|
77
|
+
};
|
|
78
|
+
render: (_args: unknown, value: unknown) => {
|
|
79
|
+
type: string;
|
|
80
|
+
text: string;
|
|
81
|
+
}[];
|
|
82
|
+
};
|
|
83
|
+
export declare function asRecord(value: unknown): Record<string, unknown>;
|
|
84
|
+
export declare function asNumber(value: unknown): number | undefined;
|
|
85
|
+
export declare function asText(value: unknown): string;
|
|
86
|
+
export declare function plainJson<T>(value: T): T;
|
|
87
|
+
export declare function verdictOf(change: BundleChange): string;
|
|
88
|
+
export declare function renderProbe(out: BrowserReadResult): string;
|
|
89
|
+
export declare function renderFind(out: BrowserFindResult): string;
|
|
90
|
+
export declare function showOrReason(panels: PanelsService, unit: string, workspace: string | null): {
|
|
91
|
+
readonly ok: boolean;
|
|
92
|
+
readonly reason?: string;
|
|
93
|
+
};
|
|
94
|
+
export declare function workshopOf(ctx: DshHostContext, exec: DshToolRunContext): {
|
|
95
|
+
readonly packagesDir: string;
|
|
96
|
+
readonly workspace: string | null;
|
|
97
|
+
};
|
|
98
|
+
export declare function modulesOf(ctx: DshHostContext, packagesDir: string): {
|
|
99
|
+
installed: string[];
|
|
100
|
+
modules: readonly import("@/shared/api/host/diy-workshop").WorkshopModule[];
|
|
101
|
+
};
|
|
102
|
+
export declare function panelEntriesOf(panels: PanelsService, workspace: string | null): import("./config").PanelEntry[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DshHostContext, DshToolRegistry } from '@dsh-workbench/shared';
|
|
2
|
+
export declare const LOGS_ARM_SCRIPT: string;
|
|
3
|
+
export declare const LOGS_READ_SCRIPT: string;
|
|
4
|
+
export declare const LOGS_STOP_SCRIPT: string;
|
|
5
|
+
export interface LogLine {
|
|
6
|
+
readonly level: string;
|
|
7
|
+
readonly text: string;
|
|
8
|
+
readonly at: number;
|
|
9
|
+
}
|
|
10
|
+
export interface LogsRead {
|
|
11
|
+
readonly ok: boolean;
|
|
12
|
+
readonly code: string;
|
|
13
|
+
readonly seen: number;
|
|
14
|
+
readonly lines: readonly LogLine[];
|
|
15
|
+
}
|
|
16
|
+
export declare function logsReadOf(payload: Record<string, unknown> | undefined): LogsRead;
|
|
17
|
+
export declare function renderLogs(read: LogsRead): string;
|
|
18
|
+
export declare function registerLogTools(ctx: DshHostContext, tools: DshToolRegistry): readonly (() => void)[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DshHostContext, DshToolRegistry } from '@dsh-workbench/shared';
|
|
2
|
+
import { type Shot } from './diy-browser';
|
|
3
|
+
import { type CardView, type PickRequest, type SlotFacts } from './diy-scripts';
|
|
4
|
+
export declare function registerLookTools(ctx: DshHostContext, tools: DshToolRegistry): readonly (() => void)[];
|
|
5
|
+
export declare function rgbOf(value: string): readonly [number, number, number] | undefined;
|
|
6
|
+
export declare function contrastOf(foreground: string, background: string): number | undefined;
|
|
7
|
+
export declare function styleLineOf(view: CardView, pick: PickRequest): string;
|
|
8
|
+
export declare function partsLineOf(view: CardView, pick: PickRequest): string;
|
|
9
|
+
export declare function slotText(slot: SlotFacts, width: number): string;
|
|
10
|
+
export declare function slotLineOf(view: CardView): string;
|
|
11
|
+
export declare function outlineText(view: CardView): string;
|
|
12
|
+
export declare function contrastLineOf(view: CardView): string;
|
|
13
|
+
export declare function renderLook(unit: string, view: CardView, shot: Shot, pick: PickRequest): string;
|
|
14
|
+
export declare function renderMissingCard(unit: string, cards: number, anchored: boolean): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DshHostContext, DshToolRegistry } from '@dsh-workbench/shared';
|
|
2
|
+
export declare function nearestKeyOf(payload: Record<string, unknown> | undefined, key: string): string;
|
|
3
|
+
export declare function registerNetTools(ctx: DshHostContext, tools: DshToolRegistry): readonly (() => void)[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DshHostContext, DshShell, DshToolRunContext } from '@dsh-workbench/shared';
|
|
2
|
+
export interface PageHandle {
|
|
3
|
+
readonly packagesDir: string;
|
|
4
|
+
readonly unit: string;
|
|
5
|
+
readonly args: Record<string, unknown>;
|
|
6
|
+
readonly shell: DshShell;
|
|
7
|
+
readonly command: string;
|
|
8
|
+
readonly session: string;
|
|
9
|
+
readonly bound: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface PageOptions {
|
|
12
|
+
readonly requireWorkbench?: boolean | undefined;
|
|
13
|
+
readonly requireUnit?: boolean | undefined;
|
|
14
|
+
}
|
|
15
|
+
export declare function pageAt(ctx: DshHostContext, exec: DshToolRunContext, raw: unknown, options?: PageOptions): Promise<PageHandle>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const UNIT_PROP: {
|
|
2
|
+
type: string;
|
|
3
|
+
description: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const SESSION_PROP: {
|
|
6
|
+
type: string;
|
|
7
|
+
description: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function pageSchema(extra?: Record<string, unknown>, required?: readonly string[]): Record<string, unknown>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export declare const PAGE_PROBE = "(async () => {\n const answer = await fetch('/workbench/api/health').then((one) => one.json()).catch(() => null);\n return JSON.stringify({\n plugin: answer === null ? null : answer.plugin,\n pid: answer === null ? null : answer.pid,\n url: location.href,\n title: document.title,\n });\n})()";
|
|
2
|
+
export declare function cardSelectorOf(unit: string): string;
|
|
3
|
+
export type DomMode = 'none' | 'outline' | 'html';
|
|
4
|
+
export interface PickRequest {
|
|
5
|
+
readonly props: readonly string[];
|
|
6
|
+
readonly parts: readonly string[];
|
|
7
|
+
readonly dom: DomMode;
|
|
8
|
+
}
|
|
9
|
+
export declare const DOM_MODES: readonly DomMode[];
|
|
10
|
+
export interface PickFacts {
|
|
11
|
+
readonly card: Readonly<Record<string, string>>;
|
|
12
|
+
readonly parts: Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_PROPS: readonly ["display", "flexDirection", "gap", "padding", "width", "height", "overflow", "backgroundColor", "color", "borderRadius", "fontSize", "lineHeight", "fontFamily", "boxSizing", "--dsw-radius-xl", "--dsw-alias-bg-layer-1", "--dsw-alias-label-primary"];
|
|
15
|
+
export declare const DEFAULT_PARTS: readonly [".wb-cardHead", ".wb-cardBody"];
|
|
16
|
+
export declare function cleanNames(value: unknown, cap: number): readonly string[];
|
|
17
|
+
export declare function pickOf(raw: Record<string, unknown>): PickRequest;
|
|
18
|
+
export interface CardView {
|
|
19
|
+
readonly ok: boolean;
|
|
20
|
+
readonly anchored: boolean;
|
|
21
|
+
readonly width: number;
|
|
22
|
+
readonly height: number;
|
|
23
|
+
readonly head: string;
|
|
24
|
+
readonly text: string;
|
|
25
|
+
readonly clipped: boolean;
|
|
26
|
+
readonly cards: number;
|
|
27
|
+
readonly rect: {
|
|
28
|
+
readonly x: number;
|
|
29
|
+
readonly y: number;
|
|
30
|
+
readonly width: number;
|
|
31
|
+
readonly height: number;
|
|
32
|
+
};
|
|
33
|
+
readonly dpr: number;
|
|
34
|
+
readonly viewport: {
|
|
35
|
+
readonly width: number;
|
|
36
|
+
readonly height: number;
|
|
37
|
+
};
|
|
38
|
+
readonly pick: PickFacts;
|
|
39
|
+
readonly slot: SlotFacts;
|
|
40
|
+
readonly outline: readonly CardNode[];
|
|
41
|
+
readonly html: string;
|
|
42
|
+
}
|
|
43
|
+
export interface SlotFacts {
|
|
44
|
+
readonly parentWidth: number;
|
|
45
|
+
readonly parentDisplay: string;
|
|
46
|
+
readonly columns: string;
|
|
47
|
+
readonly index: number;
|
|
48
|
+
readonly cards: number;
|
|
49
|
+
readonly viewportHeight: number;
|
|
50
|
+
readonly scrollHeight: number;
|
|
51
|
+
}
|
|
52
|
+
export interface CardNode {
|
|
53
|
+
readonly depth: number;
|
|
54
|
+
readonly tag: string;
|
|
55
|
+
readonly cls: string;
|
|
56
|
+
readonly role: string;
|
|
57
|
+
readonly name: string;
|
|
58
|
+
readonly text: string;
|
|
59
|
+
}
|
|
60
|
+
export declare const EMPTY_CARD: CardView;
|
|
61
|
+
export declare function measureScriptOf(unit: string, pick: PickRequest): string;
|
|
62
|
+
export declare function nodesOf(value: unknown): readonly CardNode[];
|
|
63
|
+
export declare function slotOf(value: unknown): SlotFacts;
|
|
64
|
+
export declare function pickFactsOf(value: unknown): PickFacts;
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
import type { UnitManifest } from '@dsh-workbench/shared';
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
2
|
+
export declare const PANELS_LIST_TOOL = "workbench_panels_list";
|
|
3
|
+
export declare const PANELS_SHOW_TOOL = "workbench_panels_show";
|
|
4
|
+
export declare const PANELS_HIDE_TOOL = "workbench_panels_hide";
|
|
5
|
+
export declare const PANELS_MOVE_TOOL = "workbench_panels_move";
|
|
6
|
+
export declare const PANELS_RESET_TOOL = "workbench_panels_reset";
|
|
7
|
+
export declare const PANELS_FOLLOW_TOOL = "workbench_panels_follow";
|
|
8
|
+
export declare const MODULES_LIST_TOOL = "workbench_modules_list";
|
|
9
|
+
export declare const MODULES_INSTALL_TOOL = "workbench_modules_install";
|
|
10
|
+
export declare const MODULES_UPDATE_TOOL = "workbench_modules_update";
|
|
11
|
+
export declare const MODULES_UNINSTALL_TOOL = "workbench_modules_uninstall";
|
|
12
|
+
export declare const MODULES_INSTALL_BUNDLE_TOOL = "workbench_modules_install_bundle";
|
|
13
|
+
export declare const MODULES_UPDATE_DEPENDENCY_TOOL = "workbench_modules_update_dependency";
|
|
14
|
+
export declare const MODULES_UPDATE_PLUGIN_TOOL = "workbench_modules_update_plugin";
|
|
15
|
+
export declare const MODULES_UNINSTALL_PLUGIN_TOOL = "workbench_modules_uninstall_plugin";
|
|
16
|
+
export declare const MODULES_UPDATE_WORKBENCH_TOOL = "workbench_modules_update_workbench";
|
|
17
|
+
export declare const DIY_LIST_TOOL = "workbench_diy_list";
|
|
18
|
+
export declare const DIY_STATUS_TOOL = "workbench_diy_status";
|
|
19
|
+
export declare const DIY_PANEL_TOOL = "workbench_diy_panel";
|
|
20
|
+
export declare const DIY_RECON_TOOL = "workbench_diy_recon";
|
|
21
|
+
export declare const DIY_PROBE_TOOL = "workbench_diy_probe";
|
|
22
|
+
export declare const DIY_LOOK_TOOL = "workbench_diy_look";
|
|
23
|
+
export declare const DIY_INSTALL_TOOL = "workbench_diy_install";
|
|
24
|
+
export declare const DIY_SHOW_TOOL = "workbench_diy_show";
|
|
25
|
+
export declare const DIY_CLICK_TOOL = "workbench_diy_click";
|
|
26
|
+
export declare const DIY_TYPE_TOOL = "workbench_diy_type";
|
|
27
|
+
export declare const DIY_FILL_TOOL = "workbench_diy_fill";
|
|
28
|
+
export declare const DIY_KEYS_TOOL = "workbench_diy_keys";
|
|
29
|
+
export declare const DIY_HOVER_TOOL = "workbench_diy_hover";
|
|
30
|
+
export declare const DIY_SELECT_TOOL = "workbench_diy_select";
|
|
31
|
+
export declare const DIY_SCROLL_TOOL = "workbench_diy_scroll";
|
|
32
|
+
export declare const DIY_RELOAD_TOOL = "workbench_diy_reload";
|
|
33
|
+
export declare const DIY_VIEWPORT_TOOL = "workbench_diy_viewport";
|
|
34
|
+
export declare const DIY_NET_WATCH_TOOL = "workbench_diy_net_watch";
|
|
35
|
+
export declare const DIY_NET_READ_TOOL = "workbench_diy_net_read";
|
|
36
|
+
export declare const DIY_NET_STOP_TOOL = "workbench_diy_net_stop";
|
|
37
|
+
export declare const DIY_LOGS_WATCH_TOOL = "workbench_diy_logs_watch";
|
|
38
|
+
export declare const DIY_LOGS_READ_TOOL = "workbench_diy_logs_read";
|
|
39
|
+
export declare const DIY_LOGS_STOP_TOOL = "workbench_diy_logs_stop";
|
|
40
|
+
export declare const ALL_TOOLS: readonly ["workbench_panels_list", "workbench_panels_show", "workbench_panels_hide", "workbench_panels_move", "workbench_panels_reset", "workbench_panels_follow", "workbench_modules_list", "workbench_modules_install", "workbench_modules_update", "workbench_modules_uninstall", "workbench_modules_install_bundle", "workbench_modules_update_dependency", "workbench_modules_update_plugin", "workbench_modules_uninstall_plugin", "workbench_modules_update_workbench", "workbench_diy_list", "workbench_diy_status", "workbench_diy_panel", "workbench_diy_recon", "workbench_diy_probe", "workbench_diy_look", "workbench_diy_install", "workbench_diy_show", "workbench_diy_click", "workbench_diy_type", "workbench_diy_fill", "workbench_diy_keys", "workbench_diy_hover", "workbench_diy_select", "workbench_diy_scroll", "workbench_diy_reload", "workbench_diy_viewport", "workbench_diy_net_watch", "workbench_diy_net_read", "workbench_diy_net_stop", "workbench_diy_logs_watch", "workbench_diy_logs_read", "workbench_diy_logs_stop"];
|
|
41
|
+
export type PanelsToolName = (typeof ALL_TOOLS)[number];
|
|
42
|
+
export declare const READ_TOOLS: readonly ["workbench_panels_list", "workbench_modules_list", "workbench_diy_list", "workbench_diy_status", "workbench_diy_panel", "workbench_diy_recon", "workbench_diy_probe", "workbench_diy_look", "workbench_diy_click", "workbench_diy_type", "workbench_diy_fill", "workbench_diy_keys", "workbench_diy_hover", "workbench_diy_select", "workbench_diy_scroll", "workbench_diy_reload", "workbench_diy_viewport", "workbench_diy_net_watch", "workbench_diy_net_read", "workbench_diy_net_stop", "workbench_diy_logs_watch", "workbench_diy_logs_read", "workbench_diy_logs_stop"];
|
|
43
|
+
export declare const WRITE_TOOLS: readonly ["workbench_panels_show", "workbench_panels_hide", "workbench_panels_move", "workbench_panels_reset", "workbench_panels_follow", "workbench_modules_install", "workbench_modules_update", "workbench_modules_uninstall", "workbench_modules_install_bundle", "workbench_modules_update_dependency", "workbench_modules_update_plugin", "workbench_modules_uninstall_plugin", "workbench_modules_update_workbench", "workbench_diy_install", "workbench_diy_show"];
|
|
44
|
+
export declare const DIY_TOOLS: readonly ["workbench_diy_list", "workbench_diy_status", "workbench_diy_panel", "workbench_diy_recon", "workbench_diy_probe", "workbench_diy_look", "workbench_diy_install", "workbench_diy_show", "workbench_diy_click", "workbench_diy_type", "workbench_diy_fill", "workbench_diy_keys", "workbench_diy_hover", "workbench_diy_select", "workbench_diy_scroll", "workbench_diy_reload", "workbench_diy_viewport", "workbench_diy_net_watch", "workbench_diy_net_read", "workbench_diy_net_stop", "workbench_diy_logs_watch", "workbench_diy_logs_read", "workbench_diy_logs_stop"];
|
|
5
45
|
export declare const panelsUnit: UnitManifest;
|
|
@@ -3,3 +3,7 @@ export declare const WORKSHOP_RELATIVE = "workbench/diy";
|
|
|
3
3
|
export declare const WORKSHOP_TITLE = "\u5DE5\u4F5C\u53F0DIY";
|
|
4
4
|
export declare const WORKSHOP_PAST_TITLES: readonly string[];
|
|
5
5
|
export declare function isWorkshopPath(path: string): boolean;
|
|
6
|
+
export interface DiyStartOptions {
|
|
7
|
+
readonly agentPreset: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function diyStartOptions(workspaceId: string, workshopId: string | undefined): DiyStartOptions | undefined;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const PNG_SIGNATURE: Buffer<ArrayBuffer>;
|
|
2
|
+
export declare function fixtureOf(options: {
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
color?: number;
|
|
6
|
+
depth?: number;
|
|
7
|
+
interlace?: number;
|
|
8
|
+
filter?: number;
|
|
9
|
+
}): Buffer;
|
|
10
|
+
export interface Pixels {
|
|
11
|
+
readonly width: number;
|
|
12
|
+
readonly height: number;
|
|
13
|
+
readonly color: number;
|
|
14
|
+
readonly pixels: Buffer;
|
|
15
|
+
}
|
|
16
|
+
export declare function pixelsOf(bytes: Buffer): Pixels;
|
|
17
|
+
export declare function blockOf(x: number, y: number, width: number, height: number, color: number): Buffer;
|
|
@@ -12,6 +12,7 @@ export interface MountedUnit {
|
|
|
12
12
|
readonly host: HostUnit;
|
|
13
13
|
readonly result: UnitMountResult;
|
|
14
14
|
readonly readiness: UnitReadiness;
|
|
15
|
+
readonly rollbackTools: () => void;
|
|
15
16
|
}
|
|
16
17
|
export interface UnitsPlan {
|
|
17
18
|
readonly mounted: readonly MountedUnit[];
|
|
@@ -41,6 +42,11 @@ interface NamedEntry {
|
|
|
41
42
|
handle(payload: unknown): unknown;
|
|
42
43
|
}
|
|
43
44
|
export declare function failureReasonOf(error: unknown): string;
|
|
45
|
+
export interface PlanFailureSinks {
|
|
46
|
+
readonly note: (unit: string, reason: string) => void;
|
|
47
|
+
readonly warn: (message: string) => void;
|
|
48
|
+
}
|
|
49
|
+
export declare function applyPlanFailures(failures: readonly UnitFailure[], sinks: PlanFailureSinks): void;
|
|
44
50
|
export declare function mountUnits(units: readonly HostUnit[], deps: {
|
|
45
51
|
ctx: DshHostContext;
|
|
46
52
|
logger?: {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface PngRect {
|
|
2
|
+
readonly x: number;
|
|
3
|
+
readonly y: number;
|
|
4
|
+
readonly width: number;
|
|
5
|
+
readonly height: number;
|
|
6
|
+
}
|
|
7
|
+
export interface PngCrop {
|
|
8
|
+
readonly ok: boolean;
|
|
9
|
+
readonly bytes: Buffer;
|
|
10
|
+
readonly width: number;
|
|
11
|
+
readonly height: number;
|
|
12
|
+
readonly clamped: boolean;
|
|
13
|
+
readonly reason: string;
|
|
14
|
+
}
|
|
15
|
+
export interface PngCropFile {
|
|
16
|
+
readonly ok: boolean;
|
|
17
|
+
readonly clamped: boolean;
|
|
18
|
+
readonly reason: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function cropPng(bytes: Buffer, rect: PngRect): PngCrop;
|
|
21
|
+
export declare function cropPngFile(input: string, output: string, rect: PngRect): PngCropFile;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
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.2.
|
|
90
|
+
"@dsh-workbench/shared": "0.2.12"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "node scripts/build.mjs && node scripts/build-types.mjs",
|
|
@@ -53,7 +53,7 @@ pnpm exec dsh-wb-module init <unit> --dir <工坊>/packages/module-<unit> --temp
|
|
|
53
53
|
| 模板 | 是什么 | 什么时候用 |
|
|
54
54
|
|---|---|---|
|
|
55
55
|
| `minimal`(不写就是它) | 空壳:卡壳、文案、测试都接好了,但**没有数据源** | 你已经清楚要读什么、想从零写 |
|
|
56
|
-
| `diy` |
|
|
56
|
+
| `diy` | 一张**读当前项目的样板卡**:宿主侧一条真读目录的只读路由、卡片五态(待机 / 加载 / 就绪 / 就绪但空 / 出错) | 你要照着改出一个"真能出数据"的最小版本 —— **建议先用它** |
|
|
57
57
|
|
|
58
58
|
⚠️ `diy` 那份是**给别人照抄的**,所以它自己也必须开箱全绿 —— 门禁会**两个模板各 init 一遍、各跑一遍全套**。
|
|
59
59
|
|
|
@@ -112,8 +112,9 @@ pnpm selfcheck # 构建 + 把 client.js 当加载器跑一遍(`diy` 骨架
|
|
|
112
112
|
这次没查的那几条逐条列出来;**要验它们,回工作台仓库根跑一次 `dsh-wb-module check`**。
|
|
113
113
|
所以「8 通过 · 2 不适用」不等于十一条全绿 —— 别把这句话念给用户听。
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
装上板那一步不是命令,是一套 agent 工具(一个动词一把):`workbench_diy_list` 看工坊里有什么、
|
|
116
|
+
`workbench_diy_status`(`unit=<单元 id>`)看它现在走到哪一步、`workbench_diy_install` 装上并上板、
|
|
117
|
+
`workbench_diy_show` 只上板 —— 见 §7。**上完板看一眼**:`workbench_diy_look`(只截那张卡 + 按你点的项读样式)—— 用户那一页不会被改动,但他得把工作台切到前台。卡片有没有报错先看 `workbench_diy_panel` 的「崩过 / 读到了」;真要这一页的控制台,用 `workbench_diy_logs_watch` → 做那件事 → `workbench_diy_logs_read`(钩子有上限,见 [REVIEW.md](REVIEW.md) 四步取证的 4)。
|
|
117
118
|
|
|
118
119
|
## 4 两个面的形状
|
|
119
120
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
2. **数据从哪来 —— 四层,从上往下试**(**用户不知道 opencli 是什么,这一整步是你的活**:
|
|
21
21
|
别问他"你用哪个插件 / 有没有 API",他说的是"我想看 X",把 X 翻成关键词是你的活)。
|
|
22
22
|
|
|
23
|
-
① **先看 opencli 自带的**:`
|
|
23
|
+
① **先看 opencli 自带的**:`workbench_diy_recon`(`keyword=<站点名 / 系统名 / 域名>`,
|
|
24
24
|
也可以直接给 `url` 让它取域名)。它回这台机器上**已经能用**的能力:站点、命令、`strategy`
|
|
25
25
|
(PUBLIC / COOKIE / INTERCEPT / UI)以及**要不要用户的 Chrome 登录**,还有能直接照抄的那一行。
|
|
26
26
|
**有就直接复用:不用装、不用点头。** 官方那份发现指引:`opencli skills read opencli-usage`。
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
- 想长期用 → 给这个站点写 adapter:`opencli skills read opencli-adapter-author`(侦察 → 字段解码 →
|
|
42
42
|
写 → verify);以后 adapter 失效:`opencli skills read opencli-autofix`。
|
|
43
43
|
|
|
44
|
-
**④ 才轮到探** —— 用工具:`
|
|
44
|
+
**④ 才轮到探** —— 用工具:`workbench_diy_probe`(`url=<那套系统的地址>, script=<一段回 JSON 的脚本>`;
|
|
45
45
|
页面里没有接口就给 `css=<选择器>`,走的是同一条固定 DOM 读,`{entries:[{text}]}` 直接回给你)。
|
|
46
46
|
它用**用户浏览器里现有的登录**去读,并把"读不到"归一成阻断屏认的那几个码 —— 两拍(不在站点上就自己
|
|
47
47
|
打开 `url` 再读一遍)、刚重启时的重试、平台码到阻断码的映射**都在工具里**,不用你记。
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
[ADR-0036](../../../../docs/adr/0036-opencli-always-background.md))。
|
|
68
68
|
- **页面里没有接口时(DOM 读)不要用 `eval` 去 `document.querySelectorAll`**:产物边界判据会拦
|
|
69
69
|
(宿主产物里不许出现 `document.` / `window.` 字样),而且那样解析只能窝在字符串里、测不了。
|
|
70
|
-
探的时候 `
|
|
70
|
+
探的时候 `workbench_diy_probe`(`url=…, css=<选择器>`)就是这个口子;
|
|
71
71
|
固化时走 `browserFind`,它内部用的就是 `opencli browser <session> find --css '<选择器>' --limit N --text-max M`,
|
|
72
72
|
回 `{ entries: [{ text, tag, nth }] }` —— **一行的单元格按换行拼在 `text` 里**(`美元\n668.3\n…`),
|
|
73
73
|
所以"切格 + 按列序取值"是两个纯函数,能单测。很多公开站点一条 XHR 都不发,就该走这条。
|
|
@@ -119,4 +119,4 @@
|
|
|
119
119
|
|
|
120
120
|
- 数据源写在**宿主半侧**,卡片只消费它的返回;
|
|
121
121
|
- 只读路由出错时回 `{ ok: false, error: { code, message, hint? } }`(HTTP 仍是 200,外壳原样转发);
|
|
122
|
-
-
|
|
122
|
+
- 验收时把「正常 / 空 / 出错」三条路都走一遍 —— 真机上造不出来的那几条,写清**怎么才能真看到**(换个空目录、换个不存在的路径那种),别为它写夹具(**2026-10-16 起模板与指引都不带评审夹具**)。
|
|
@@ -101,7 +101,7 @@ key 固定 `idle|loading|ready|empty|unreadable`)+ `config[]` + `capabilities[
|
|
|
101
101
|
`link` 这类**可选格**留空渲染成 `—`,不算空格。
|
|
102
102
|
|
|
103
103
|
`design.json` 是**设计底稿**:只装人话。"这条能力在哪些工作区出现"**哪里都别写** ——
|
|
104
|
-
它既不在底稿、也不在清单:那是**用户**的事(他在 `
|
|
104
|
+
它既不在底稿、也不在清单:那是**用户**的事(他在 `workbench_panels_show` / `workbench_panels_hide` 里决定,见 [TOOLS.md](TOOLS.md) §12)。
|
|
105
105
|
协议里那个 `scope`(`tools[].scope` / `card.scope`)**已经删掉**:用户口径是「模块开发者不能定义 scope,
|
|
106
106
|
scope 永远是用户来决定的」(见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md))。
|
|
107
107
|
`contracts` 只拿名字把底稿与清单对起来(键集合对账)。
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# kit 速查:要做什么 → 用哪一件 → 最小写法
|
|
2
|
+
|
|
3
|
+
`dsh-wb-module check --only kit` 列的是**名字**,这一份给的是**用法**。两处都别看漏:
|
|
4
|
+
名字那份是这台机器上**真有的**(别照抄别的模块),这一份是**怎么拼**。
|
|
5
|
+
|
|
6
|
+
**能拿 kit 的就别自己画。** 理由只有一条:主题、语言、悬停、禁用、焦点环、空态、被裁的处理
|
|
7
|
+
都只维护一份。自己画的不会跟着换主题,也不会跟着我们改口径 —— 这就是"同一个东西长得不一样"的来源。
|
|
8
|
+
|
|
9
|
+
> 全部从 `const { … } = kit.components`(`@dsh-workbench/core/client`)拿。
|
|
10
|
+
> 例子里的 `h` = `createElement`(`import { createElement as h } from 'react'`)。
|
|
11
|
+
|
|
12
|
+
## 1 卡片外壳
|
|
13
|
+
|
|
14
|
+
**`Card`** —— 一张卡的壳:标题 + 刷新钮 + 卡片体。面板上每一格都是它。
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
h(Card, {
|
|
18
|
+
t: props.t,
|
|
19
|
+
title: t('myunit.cardTitle'),
|
|
20
|
+
refreshing: resource.phase === 'loading',
|
|
21
|
+
onRefresh: props.onRefresh,
|
|
22
|
+
}, body)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**`CardHead`** —— 你自己拼卡头时用它(`Card` 内部就是它):`t` / `title` / `meta` / `refreshing` /
|
|
26
|
+
`onRefresh` / `gear` / `onToggleGear`(右上那颗齿轮展开设置面)/ **`platformHref`**(跳整张卡对应的
|
|
27
|
+
那个系统:只给这一颗就够,那颗 ↗ 立刻画出来)。
|
|
28
|
+
|
|
29
|
+
**`CardAnchor`** —— 外壳自己盖的锚点(`#wb-card-<unit>`)。**别自己写**,也别删。
|
|
30
|
+
|
|
31
|
+
**`CardBoundary`** —— 卡片级错误边界。一张卡炸了不许把整块面板带走;**别自己 try/catch 包渲染**。
|
|
32
|
+
|
|
33
|
+
## 2 状态:这是下限最集中的地方
|
|
34
|
+
|
|
35
|
+
先想清五态(`design.json` 的状态矩阵就是这五格):**待机 / 在读 / 就绪 / 就绪但空 / 读不到**。
|
|
36
|
+
每一态都要有东西画,一个不落。
|
|
37
|
+
|
|
38
|
+
| 什么时候 | 用 |
|
|
39
|
+
|---|---|
|
|
40
|
+
| 有内容了 | `StateBlock`(标题 + `hint` 一行 + 正文) |
|
|
41
|
+
| 要他先选一个 / 正在读 / 读不到 | `CenteredState`(居中一屏) |
|
|
42
|
+
| 就绪但空 | `EmptyState`(它只是 `CenteredState` 的简写) |
|
|
43
|
+
| 在读、且你已经有大概形状 | `SkeletonRows`(骨架) |
|
|
44
|
+
| 一句说明 / 一句报错 | `Note`(`tone: 'problem'` 是报错) |
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
h(CenteredState, { icon: null, title: t('myunit.loading'), hint: t('myunit.loadingHint'), compact: true })
|
|
48
|
+
h(CenteredState, { icon: null, title: t('myunit.errorTitle'), detail: `${code}: ${message}`, hint: t('myunit.errorHint'), compact: true })
|
|
49
|
+
h(EmptyState, { text: t('myunit.empty'), icon: h(IconPanelScreen, { size: 20 }), compact: true })
|
|
50
|
+
h(StateBlock, { title: rows.title, hint: `3 条 · ${when}`, resolving: t('myunit.rows') }, table)
|
|
51
|
+
h(Note, { children: t('myunit.hint') })
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**读不到就说读不到**:`detail` 里放原始错误码与那句话,**绝不显示 0**(0 是"真的是 0",不是"没读到")。
|
|
55
|
+
|
|
56
|
+
## 3 一行一行
|
|
57
|
+
|
|
58
|
+
**`Rows` + `Row`** —— 键值行(左边名字、右边值)。**别自己写 `ul`/`li` 或 div 行**:
|
|
59
|
+
分隔线、行距、对齐、两端溢出都在这两件里。
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
h(Rows, null,
|
|
63
|
+
...items.map((one) => h(Row, { key: one.name, label: one.name, value: `${size} · ${when}` })))
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**`ActivityBlock` / `ActivityLine` / `ActivityAction`** —— "它做过什么"那一块:
|
|
67
|
+
`ActivityLine` 有 `dot` / `text` / `at`(时间)/ `actions`;`ActivityAction` 是行尾那个动作
|
|
68
|
+
(`label` / `icon` / `href` 或 `onClick` / `failed`)。时间一律用它,别自己拼。
|
|
69
|
+
|
|
70
|
+
**`LongTaskRow`** —— 长任务那一行:`status`(四态)+ `headline` + `problem` + `links` + `steps` +
|
|
71
|
+
`raw`。跑得久的事(发布、扫描、迁移)都用它,别自己画进度。
|
|
72
|
+
|
|
73
|
+
**`ApprovalDetail` / `ApprovalPlan`** —— 审批屏上那两格(要用户点头的写操作)。
|
|
74
|
+
|
|
75
|
+
## 4 表单
|
|
76
|
+
|
|
77
|
+
**`Field`** —— 标签 + 输入的排布(`label` / `hint`),输入框放里面。
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
h(Field, { label: t('myunit.mode'), hint: t('myunit.modeHint') },
|
|
81
|
+
h(TextField, { value, onChange: (event) => setMode(event.target.value) }))
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**`TextField`** —— 单行输入(`invalid` 标红;其余是原生 input 的 props)。
|
|
85
|
+
**`ChoiceGroup`** —— 单选 / 多选(`multi` 区分;`value` 或 `values` + `onChange`;选项 `{ value, label, hint?, disabled? }`)。
|
|
86
|
+
**`SelectField`** —— 下拉:默认是**常规下拉框**(跟 `TextField` 一套),无边框那种给 `variant: 'ghost'`;
|
|
87
|
+
搜索、分组、禁用项、加载态、空态、页脚都是它的 prop。
|
|
88
|
+
**`SaveBar`** —— 设置面底下那条"取消 / 保存"(`busy` / `disabled` / `labels` / `onCancel` / `onSave`)。
|
|
89
|
+
|
|
90
|
+
**别手写 `<button>` / `<input>` / `<select>`**:dsh 有 `Button`(`variant` / `size`),
|
|
91
|
+
kit 有上面这几件;手写的会拿到浏览器默认样式,而且**判据会红**(`check:style`)。
|
|
92
|
+
`<textarea>` 例外(dsh 与 kit 都没有多行输入)——真要用就直接写,其余形态别开这个口子。
|
|
93
|
+
|
|
94
|
+
## 5 别的
|
|
95
|
+
|
|
96
|
+
- **`Link`** —— **唯一**的外链写法:`h(Link, { href, children })`。自带新窗口 + `rel="noopener noreferrer"`
|
|
97
|
+
+ 正文色 + hover 下划线 + 那颗小箭头。**别去掉箭头、别在文案里自带 `→`、别手写 `<a>`**(判据红)。
|
|
98
|
+
- **`SettingsSection`** —— 一屏设置里的一节(`label` / `title` / `action`)。
|
|
99
|
+
- **`Stack`** —— 竖排 + 统一间距(懒得分组时的默认容器)。
|
|
100
|
+
- **`BlockerState`** —— 阻断屏:要登录 / 没权限 / 能力没装好那一类(`blocker` / `t` / `onRetry` / `onOpenMarket`)。
|
|
101
|
+
- **`Tip`** —— Tooltip:图标钮与只有图的地方**必须**有它(或 `aria-label`)。
|
|
102
|
+
- **别给模块带夹具**:2026-10-16 起模板 / `init` 文案 / 这份指引都不带评审夹具了(`?wbMock=1` 那套、`useFixturePick` / `MockStrip` / `mockNote` 都从模板里删了)。夹具是模块作者负担里最不值的那一份 —— 而**你自己那份 `plugin.test.ts` 就能把五态各喂一遍**,门禁从来只问"空数据画不画得出"(`check:cards`)。外壳自己那套 `?wbMock=1` 夹具是给**外壳的卡片**用的,模块不必跟(机制仍在,谁想要仍然可以用,但**不是你要做的事**)。
|
|
103
|
+
- **图标** —— `IconPanelScreen`(面板/卡片那类)、`IconModuleMark`(我们的模块类型标)、
|
|
104
|
+
`IconNpm` / `IconOpencli`(包类型);其余图形一律从 dsh 的 `Icon*Regular` 拿,**别自己画图标**。
|
|
105
|
+
|
|
106
|
+
## 6 三条纪律
|
|
107
|
+
|
|
108
|
+
1. **调用点只给数据与语义**:`h(Card, { title, refreshing, onRefresh }, …)`。别从外面塞外观类名
|
|
109
|
+
—— 只有布局槽例外(通栏、外边距、网格位置)。
|
|
110
|
+
2. **字号与颜色走 kit 与令牌**(`--dsw-*` / `--wb-*`),不写字面值。**重点可以大**:
|
|
111
|
+
一个"余额 / 总数"那种要突出的数字,用刻度里最大那档 `--dsw-font-xl-24`(24/32、600),
|
|
112
|
+
数字加 `font-variant-numeric: tabular-nums`(见 [PANEL.md](PANEL.md) §6)。
|
|
113
|
+
刻度外非要一个字面值(比如更大的标题数)时,在模块 `README.md` 里写一句为什么。
|
|
114
|
+
3. **自己写 CSS 只写布局**(flex / grid / gap / 对齐)。要一个新的"长得像控件"的东西时,
|
|
115
|
+
先问一句:kit 里是不是已经有了?
|
|
116
|
+
|
|
117
|
+
## 7 kit 里没有、但你确定要标准控件
|
|
118
|
+
|
|
119
|
+
见 [PANEL.md](PANEL.md) §9:可以引 dsh 的客户端原语,但**只在浏览器侧**、并在
|
|
120
|
+
`package.json` 的 `dsh.client.external` 里声明 `@deepseek-ai/dsh-client-ui-primitives`
|
|
121
|
+
(宿主侧一个字都不许碰 —— `check` 的源码边界判据会红)。能拿 kit 的时候仍然别自己画。
|
|
@@ -133,6 +133,16 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
|
|
|
133
133
|
dsh 的 `Button`,或阻断屏里的 `action`。区别在"跳去哪"和"它是不是一个动作",不在好看不好看。
|
|
134
134
|
- **标签 + 输入框的排布用 `Field`**,输入框用 `TextField` —— 内边距与排版是外壳给的默认,
|
|
135
135
|
别为"能看"写模块自己的 CSS(见 §5.1)。
|
|
136
|
+
- **要做什么用哪件,照 [KIT.md](KIT.md) 抄**("要做什么 → 用哪件 → 最小写法"的表)。
|
|
137
|
+
下面几条是口径,KIT.md 是写法。
|
|
138
|
+
- **字号与重点**:走那把刻度(`--dsw-font-*`:11 / 12 / 13 / 14 / 16 / 20 / 24),
|
|
139
|
+
**但不许"整张卡一样大"** —— 要有重点。最该大的那个数字(余额、总数、还剩多少)
|
|
140
|
+
就用刻度里最大那档 `--dsw-font-xl-24`(24/32、600 重),它旁边的说明 12。
|
|
141
|
+
这一档是**给重点留的、鼓励用**:卡里最大的字比正文大一倍,比全卡 12 号好读得多。
|
|
142
|
+
刻度外非要一个字面值(28/32 那种)时,在模块 `README.md` 里写一句为什么,别静悄悄写。
|
|
143
|
+
成列的数字加 `font-variant-numeric: tabular-nums`。
|
|
144
|
+
**别为了"统一"把重点压回正文大小**——那才是不合口径。
|
|
145
|
+
- **颜色与间距也走令牌**(`--dsw-*` / `--wb-*`);自己写 CSS 只写布局(flex / grid / gap / 对齐)。
|
|
136
146
|
|
|
137
147
|
## 7 状态矩阵怎么写
|
|
138
148
|
|
|
@@ -154,7 +164,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
|
|
|
154
164
|
- **平台没给的那一格就不占位**(不留孤零零的字段名、不留空的一行)。
|
|
155
165
|
- **读不到就说读不到**,并说清为什么(例:手上这份能力太旧);**绝不显示 0**。
|
|
156
166
|
- 有确定答案就不打扰他(能按默认读出来就别弹设置面)。
|
|
157
|
-
-
|
|
167
|
+
- 真机上造不出来的状态也要**在设计上**画出来(照这一格写清)—— 但**不必为它写夹具**:2026-10-16 起模板与指引都不带评审夹具,模块自己的 `plugin.test.ts` 把五态各喂一遍就够(门禁只问"空数据画不画得出")。
|
|
158
168
|
|
|
159
169
|
### 7.1 图例就是把屏幕画成 ASCII
|
|
160
170
|
|
|
@@ -177,7 +187,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
|
|
|
177
187
|
- **用真字**:图里的文案用界面上真实那句(例「没有指派给你的缺陷。」),别写"一句空态文案"。
|
|
178
188
|
- **别拿图标代替画面**:给状态起个名字、配个 `⛔` 这类符号,用户还是分不清;一眼能认的是**形状**(整卡换掉 vs 多一行)与**位置**(行首的点、行尾的两颗)。
|
|
179
189
|
- **画不成的才写词**:动作、agent 的下一步、时间性的"不变 / 自己变",写成词并说清意思。
|
|
180
|
-
-
|
|
190
|
+
- **真机上造不出来的状态**:沟通时照样画(画的是设计意图);实现时**要让它能用真实输入走到**(换个空目录、换个坏路径、先不选),而不是给它写夹具 —— 2026-10-16 起模板与指引都不带评审夹具,模块自己的 `plugin.test.ts` 把五态各喂一遍就够。
|
|
181
191
|
|
|
182
192
|
## 8 范例(真实产出的形状)
|
|
183
193
|
|