@mackwan84/dsh-tool-ui-mockup 0.1.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.
package/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # @mackwan84/dsh-tool-ui-mockup
2
+
3
+ `ui_mockup` 工具 Consumer:研讨阶段生成 UI 线框图/高保真设计稿,落盘设计资产库
4
+ `$DSH_HOME/mockups/<工作区>/images/`,写入同目录 `history.jsonl` 生成历史,
5
+ 并注入提示词规则引导"确认后写 `design/spec.md`、未确认不写实现代码"。
6
+
7
+ - 模型分层:按保真度取设置面板的分层默认,未配置时回落生效提供方的内置默认
8
+ (百炼 `qwen-image-3.0` / `qwen-image-3.0-pro`,火山 `doubao-seedream-4-5` / `5-0-pro`;可 `model` 覆盖);
9
+ - 参考图模式:`reference` 收 `design/images/…` 语义路径(宿主翻译到资产库)或工作区内自备图相对路径,图生图保持全站风格一致;
10
+ - 生成图落盘资产库 `images/`(文件名含时间戳与随机段,并发不覆盖),下载失败的单张不阻断其余图片;
11
+ - 结果通过 attachments 存为会话图片附件(超过 `imageLimits.maxImageBytes` 的仅落盘不入附件);
12
+ - 接口限流/轮询/凭据由 Provider 处理。
13
+
14
+ ## Model Experience
15
+
16
+ - **模型可见工具**:`ui_mockup`(参数与描述见 `src/index.ts` 的 defineTool 定义);
17
+ - **提示词规则**(`systemPrompt` 注入,name: `ui-mockup-usage`):何时主动提议草图、fidelity 选择、
18
+ 参考图一致性、确认后锁定 `design/spec.md` 的流程约束。
19
+
20
+ ## Known Limitations
21
+
22
+ - 编辑模式(`edit`)在 M4 提供。
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ui_mockup 客户端半区:keyed 工具卡片 + 设置面板(M3)+ 双语字典。
3
+ * 面板注册进 DSH 设置窗口的 settings.section 列表槽;偏好经 settings
4
+ * 命名空间镜像读写,历史/锚点/测试连接走 /ui-mockup 私有 RPC 通道。
5
+ */
6
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
7
+ /**
8
+ * 客户端半区硬依赖:卡片与设置槽注册、语言切换、connection 通道与设置域服务。
9
+ */
10
+ export declare const inject: string[];
11
+ export declare function apply(ctx: ClientContext): void;
@@ -0,0 +1,234 @@
1
+ /** ui_mockup 客户端 UI 文案(双语,跟随 DSH 语言切换):工具卡片 + 设置面板。 */
2
+ export declare const NS = "ui-mockup";
3
+ /** 简体中文 UI 文案。 */
4
+ export declare const zh: {
5
+ 'card.generating': string;
6
+ 'card.confirm': string;
7
+ 'card.select': string;
8
+ 'card.selectPlaceholder': string;
9
+ 'card.openOriginal': string;
10
+ 'card.feedback': string;
11
+ 'card.feedbackPlaceholder': string;
12
+ 'card.feedbackSubmit': string;
13
+ 'card.feedbackCancel': string;
14
+ 'card.confirmMessage': string;
15
+ 'card.selectMessage': string;
16
+ 'card.feedbackMessage': string;
17
+ 'card.setAnchor': string;
18
+ 'card.setAnchorButton': string;
19
+ 'card.setAnchorSelect': string;
20
+ 'card.setAnchorOption': string;
21
+ 'card.anchored': string;
22
+ 'panel.nav': string;
23
+ 'panel.tab.overview': string;
24
+ 'panel.tab.provider': string;
25
+ 'panel.tab.preferences': string;
26
+ 'panel.tab.history': string;
27
+ 'panel.loading': string;
28
+ 'panel.loadFailed': string;
29
+ 'panel.readonlyBanner': string;
30
+ 'panel.testConnection': string;
31
+ 'panel.testing': string;
32
+ 'panel.overview.intro': string;
33
+ 'panel.overview.quickTitle': string;
34
+ 'panel.overview.step1Title': string;
35
+ 'panel.overview.step1Body': string;
36
+ 'panel.overview.step2Title': string;
37
+ 'panel.overview.step2Body': string;
38
+ 'panel.overview.step3Title': string;
39
+ 'panel.overview.step3Body': string;
40
+ 'panel.overview.statusLine': string;
41
+ 'panel.provider.title': string;
42
+ 'panel.provider.dashscopeName': string;
43
+ 'panel.provider.volcengineName': string;
44
+ 'panel.provider.unknown': string;
45
+ 'panel.provider.fallbackActive': string;
46
+ 'panel.provider.unknownHint': string;
47
+ 'panel.provider.volcengineDisabled': string;
48
+ 'panel.provider.inactive': string;
49
+ 'panel.provider.modelsReset': string;
50
+ 'panel.credential.title': string;
51
+ 'panel.credential.ready': string;
52
+ 'panel.credential.missing': string;
53
+ 'panel.credential.checking': string;
54
+ 'panel.credential.howTitle': string;
55
+ 'panel.credential.way1': string;
56
+ 'panel.credential.way2': string;
57
+ 'panel.credential.way3': string;
58
+ 'panel.credential.way4': string;
59
+ 'panel.credential.readyWithSource': string;
60
+ 'panel.credential.keyInputLabel': string;
61
+ 'panel.credential.source.env': string;
62
+ 'panel.credential.source.file': string;
63
+ 'panel.credential.source.project-env': string;
64
+ 'panel.credential.source.user-env': string;
65
+ 'panel.credential.source.ambient': string;
66
+ 'panel.credential.writePlaceholder': string;
67
+ 'panel.credential.save': string;
68
+ 'panel.credential.clear': string;
69
+ 'panel.credential.savedNotice': string;
70
+ 'panel.credential.clearedNotice': string;
71
+ 'panel.credential.notWritable': string;
72
+ 'panel.test.ok': string;
73
+ 'panel.test.missingKey': string;
74
+ 'panel.test.invalidKey': string;
75
+ 'panel.test.gatewayFail': string;
76
+ 'panel.test.unknown': string;
77
+ 'panel.models.title': string;
78
+ 'panel.models.wireframe': string;
79
+ 'panel.models.highFidelity': string;
80
+ 'panel.models.followDefault': string;
81
+ 'panel.prefs.fidelity': string;
82
+ 'panel.prefs.fidelityWireframe': string;
83
+ 'panel.prefs.fidelityHigh': string;
84
+ 'panel.prefs.platform': string;
85
+ 'panel.prefs.count': string;
86
+ 'panel.prefs.pollTimeout': string;
87
+ 'panel.prefs.minutes': string;
88
+ 'panel.prefs.backoff': string;
89
+ 'panel.prefs.backoffFixed': string;
90
+ 'panel.prefs.size': string;
91
+ 'panel.prefs.reset': string;
92
+ 'panel.prefs.save': string;
93
+ 'panel.prefs.saved': string;
94
+ 'panel.prefs.writeNotApplied': string;
95
+ 'panel.prefs.writeNotAppliedField': string;
96
+ 'panel.history.search': string;
97
+ 'panel.history.searchLabel': string;
98
+ 'panel.history.searchPlaceholder': string;
99
+ 'panel.history.pendingSearch': string;
100
+ 'panel.history.clear': string;
101
+ 'panel.history.confirmClear': string;
102
+ 'panel.history.cancelClear': string;
103
+ 'panel.history.empty': string;
104
+ 'panel.history.setAnchor': string;
105
+ 'panel.history.unsetAnchor': string;
106
+ 'panel.history.anchorTag': string;
107
+ 'panel.history.anchorHint': string;
108
+ 'panel.history.prev': string;
109
+ 'panel.history.next': string;
110
+ 'panel.history.totalCount': string;
111
+ 'panel.history.anchorOnPage': string;
112
+ 'panel.history.goToAnchor': string;
113
+ 'panel.history.fileCount': string;
114
+ };
115
+ /** 卡片命名空间的字典键联合。 */
116
+ export type UiMockupKey = keyof typeof zh;
117
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
118
+ interface LocaleNamespaceMap {
119
+ /** ui_mockup 工具卡片与设置面板文案。 */
120
+ 'ui-mockup': UiMockupKey;
121
+ }
122
+ }
123
+ /** English UI copy. */
124
+ export declare const en: {
125
+ 'card.generating': string;
126
+ 'card.confirm': string;
127
+ 'card.select': string;
128
+ 'card.selectPlaceholder': string;
129
+ 'card.openOriginal': string;
130
+ 'card.feedback': string;
131
+ 'card.feedbackPlaceholder': string;
132
+ 'card.feedbackSubmit': string;
133
+ 'card.feedbackCancel': string;
134
+ 'card.confirmMessage': string;
135
+ 'card.selectMessage': string;
136
+ 'card.feedbackMessage': string;
137
+ 'card.setAnchor': string;
138
+ 'card.setAnchorButton': string;
139
+ 'card.setAnchorSelect': string;
140
+ 'card.setAnchorOption': string;
141
+ 'card.anchored': string;
142
+ 'panel.nav': string;
143
+ 'panel.tab.overview': string;
144
+ 'panel.tab.provider': string;
145
+ 'panel.tab.preferences': string;
146
+ 'panel.tab.history': string;
147
+ 'panel.loading': string;
148
+ 'panel.loadFailed': string;
149
+ 'panel.readonlyBanner': string;
150
+ 'panel.testConnection': string;
151
+ 'panel.testing': string;
152
+ 'panel.overview.intro': string;
153
+ 'panel.overview.quickTitle': string;
154
+ 'panel.overview.step1Title': string;
155
+ 'panel.overview.step1Body': string;
156
+ 'panel.overview.step2Title': string;
157
+ 'panel.overview.step2Body': string;
158
+ 'panel.overview.step3Title': string;
159
+ 'panel.overview.step3Body': string;
160
+ 'panel.overview.statusLine': string;
161
+ 'panel.provider.title': string;
162
+ 'panel.provider.dashscopeName': string;
163
+ 'panel.provider.volcengineName': string;
164
+ 'panel.provider.unknown': string;
165
+ 'panel.provider.fallbackActive': string;
166
+ 'panel.provider.unknownHint': string;
167
+ 'panel.provider.volcengineDisabled': string;
168
+ 'panel.provider.inactive': string;
169
+ 'panel.provider.modelsReset': string;
170
+ 'panel.credential.title': string;
171
+ 'panel.credential.ready': string;
172
+ 'panel.credential.missing': string;
173
+ 'panel.credential.checking': string;
174
+ 'panel.credential.howTitle': string;
175
+ 'panel.credential.way1': string;
176
+ 'panel.credential.way2': string;
177
+ 'panel.credential.way3': string;
178
+ 'panel.credential.way4': string;
179
+ 'panel.credential.readyWithSource': string;
180
+ 'panel.credential.keyInputLabel': string;
181
+ 'panel.credential.source.env': string;
182
+ 'panel.credential.source.file': string;
183
+ 'panel.credential.source.project-env': string;
184
+ 'panel.credential.source.user-env': string;
185
+ 'panel.credential.source.ambient': string;
186
+ 'panel.credential.writePlaceholder': string;
187
+ 'panel.credential.save': string;
188
+ 'panel.credential.clear': string;
189
+ 'panel.credential.savedNotice': string;
190
+ 'panel.credential.clearedNotice': string;
191
+ 'panel.credential.notWritable': string;
192
+ 'panel.test.ok': string;
193
+ 'panel.test.missingKey': string;
194
+ 'panel.test.invalidKey': string;
195
+ 'panel.test.gatewayFail': string;
196
+ 'panel.test.unknown': string;
197
+ 'panel.models.title': string;
198
+ 'panel.models.wireframe': string;
199
+ 'panel.models.highFidelity': string;
200
+ 'panel.models.followDefault': string;
201
+ 'panel.prefs.fidelity': string;
202
+ 'panel.prefs.fidelityWireframe': string;
203
+ 'panel.prefs.fidelityHigh': string;
204
+ 'panel.prefs.platform': string;
205
+ 'panel.prefs.count': string;
206
+ 'panel.prefs.pollTimeout': string;
207
+ 'panel.prefs.minutes': string;
208
+ 'panel.prefs.backoff': string;
209
+ 'panel.prefs.backoffFixed': string;
210
+ 'panel.prefs.size': string;
211
+ 'panel.prefs.reset': string;
212
+ 'panel.prefs.save': string;
213
+ 'panel.prefs.saved': string;
214
+ 'panel.prefs.writeNotApplied': string;
215
+ 'panel.prefs.writeNotAppliedField': string;
216
+ 'panel.history.search': string;
217
+ 'panel.history.searchLabel': string;
218
+ 'panel.history.searchPlaceholder': string;
219
+ 'panel.history.pendingSearch': string;
220
+ 'panel.history.clear': string;
221
+ 'panel.history.confirmClear': string;
222
+ 'panel.history.cancelClear': string;
223
+ 'panel.history.empty': string;
224
+ 'panel.history.setAnchor': string;
225
+ 'panel.history.unsetAnchor': string;
226
+ 'panel.history.anchorTag': string;
227
+ 'panel.history.anchorHint': string;
228
+ 'panel.history.prev': string;
229
+ 'panel.history.next': string;
230
+ 'panel.history.totalCount': string;
231
+ 'panel.history.anchorOnPage': string;
232
+ 'panel.history.goToAnchor': string;
233
+ 'panel.history.fileCount': string;
234
+ };
@@ -0,0 +1,33 @@
1
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { type ConnectionFace, type PrefScope } from './shared.js';
3
+ import type { NS } from './locales.js';
4
+ /** 偏好形状的客户端本地副本(不引入宿主 prefs 模块,避免把 schemastery 打进浏览器包)。 */
5
+ export interface PanelPrefs {
6
+ defaultFidelity: 'wireframe' | 'high-fidelity';
7
+ defaultPlatform: 'web' | 'mobile';
8
+ defaultCount: number;
9
+ outputDir: string;
10
+ pollTimeoutMinutes: number;
11
+ wireframeModel: string;
12
+ highFidelityModel: string;
13
+ defaultSize: string;
14
+ }
15
+ /**
16
+ * settings 域的客户端结构面(bind 由 ui-settings 插件在运行时提供)。
17
+ * 面板经由它把同名命名空间镜像绑到本插件 fiber;ScopeSnapshot/PrefScope
18
+ * 定义见 ./shared.js,客户端本地不再重复。
19
+ */
20
+ /** 注入给面板组件的运行时句柄。 */
21
+ export interface UiMockupPanelInjected {
22
+ prefs: PrefScope<PanelPrefs>;
23
+ connection: ConnectionFace;
24
+ }
25
+ type PanelProps = PropsLocale<typeof NS> & UiMockupPanelInjected;
26
+ export declare function UiMockupSection({ t, prefs, connection }: PanelProps): import("react").JSX.Element;
27
+ /** 面板用的凭据状态(与宿主 CredentialStatus 同构):只有三个事实,永不携带值。 */
28
+ export interface PanelCredential {
29
+ configured: boolean;
30
+ source?: string;
31
+ writable: boolean;
32
+ }
33
+ export {};
@@ -0,0 +1,60 @@
1
+ /** 工具卡片与设置面板共享的客户端最小面:图片路由 URL 与 RPC 调用折叠。 */
2
+ /** 图片文件名 → webServer 路由 URL(host 半区 /ui-mockup/images 服务资产库图片)。 */
3
+ export declare function imageUrl(name: string, cwd?: string): string;
4
+ /** connection 服务的客户端结构面(本包只用 rpc.call 与 isLoopback)。 */
5
+ export interface ConnectionFace {
6
+ readonly isLoopback: boolean;
7
+ readonly rpc: {
8
+ call(channel: string, endpoint: string, payload?: unknown, signal?: AbortSignal): Promise<RpcResultLike<unknown>>;
9
+ };
10
+ }
11
+ /** 与宿主半区同构的 RPC 结果形状。 */
12
+ export type RpcResultLike<T> = {
13
+ ok: true;
14
+ value: T;
15
+ } | {
16
+ ok: false;
17
+ error: {
18
+ code: string;
19
+ message: string;
20
+ };
21
+ };
22
+ /**
23
+ * 把 RPC 结果折叠成「值或抛错」:错误信息面向用户可读,
24
+ * 错误码保留在消息前缀便于排障。
25
+ * 注意:宿主信封校验要求 payload 必填(clientRequestSchema 的 payload 为
26
+ * z.unknown() 非可选),JSON.stringify 会丢弃值为 undefined 的字段,因此
27
+ * 无参端点(overview / test-connection)也必须发送一个 {}。
28
+ */
29
+ export declare function callPanel<T>(connection: ConnectionFace, endpoint: string, payload?: Record<string, unknown>): Promise<T>;
30
+ /**
31
+ * settings 域的客户端结构面(bind 由 ui-settings 插件在运行时提供);
32
+ * 面板经由它把同名命名空间镜像绑到本插件 fiber。
33
+ */
34
+ export interface SettingsScopeBinderFace {
35
+ bind<T>(spec: {
36
+ namespace: string;
37
+ }): PrefScope<T>;
38
+ }
39
+ export interface ScopeSnapshot<T> {
40
+ status: 'loading' | 'ready' | 'unavailable';
41
+ value: T | undefined;
42
+ user: unknown;
43
+ base: unknown;
44
+ revision: number | undefined;
45
+ writable: boolean;
46
+ mode: 'host' | 'memory';
47
+ }
48
+ export interface PrefScope<T> {
49
+ getSnapshot(): ScopeSnapshot<T>;
50
+ subscribe(listener: () => void): () => void;
51
+ set(field: string, value: unknown): Promise<void>;
52
+ unset(field: string): Promise<void>;
53
+ }
54
+ /**
55
+ * 历史分页每页条数——与宿主 prefs.ts 的 HISTORY_PAGE_SIZE 必须保持一致
56
+ * (两端各持一份纯常量,避免客户端 import 宿主模块带入 schemastery 等依赖)。
57
+ */
58
+ export declare const HISTORY_PAGE_SIZE = 5;
59
+ /** 锚点在过滤后列表中的索引 → 所在页码(1-based);无锚点(-1)返回 null。 */
60
+ export declare function anchorPageOf(anchorIndex: number, pageSize: number): number | null;
@@ -0,0 +1,12 @@
1
+ import type { ToolCallViewProps } from '@deepseek-ai/dsh-client-ui-tool/client';
2
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
3
+ import type { NS } from './locales.js';
4
+ type Props = ToolCallViewProps & PropsLocale<typeof NS> & {
5
+ anchor?: ToolviewAnchorFace;
6
+ };
7
+ /** 卡片锚点注入面:由注册方闭包捕获 connection 提供,直连 RPC 不经 agent。 */
8
+ export interface ToolviewAnchorFace {
9
+ set(file: string, cwd?: string): Promise<unknown>;
10
+ }
11
+ export declare function UiMockupToolview({ block, inputActions, cwd, t, anchor }: Props): import("react").JSX.Element;
12
+ export {};