hiwork-core 0.0.30 → 0.0.35
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/cordis.patch.yml +15 -1
- package/lib/ai-router-client.js +394 -2
- package/lib/client-policy.js +2 -2
- package/lib/client.js +2413 -439
- package/lib/image-rpc.js +306 -0
- package/lib/imagegen.js +424 -0
- package/lib/index.js +19212 -7694
- package/lib/knowledge-config.js +91 -1
- package/lib/provision-session.js +10 -2
- package/lib/tool-names.js +10 -0
- package/lib/tools.js +205 -0
- package/lib/types/ai-router-client.d.ts +255 -2
- package/lib/types/client/about-section.d.ts +27 -7
- package/lib/types/client/controller.d.ts +17 -9
- package/lib/types/client/feature-center.d.ts +46 -1
- package/lib/types/client/feature-registry.d.ts +36 -3
- package/lib/types/client/image-cards.d.ts +218 -0
- package/lib/types/client/image-styles.d.ts +9 -0
- package/lib/types/client/images-data.d.ts +127 -0
- package/lib/types/client/images-page.d.ts +97 -0
- package/lib/types/client/index.d.ts +0 -1
- package/lib/types/client/login-gate.d.ts +2 -2
- package/lib/types/client/logo.d.ts +7 -2
- package/lib/types/client/menu-preferences.d.ts +163 -0
- package/lib/types/client/menu-section.d.ts +5 -0
- package/lib/types/client/menu-store.d.ts +101 -0
- package/lib/types/client/styles.d.ts +16 -0
- package/lib/types/client/types.d.ts +9 -0
- package/lib/types/image-rpc.d.ts +142 -0
- package/lib/types/imagegen.d.ts +241 -0
- package/lib/types/index.d.ts +70 -8
- package/lib/types/knowledge-config.d.ts +50 -2
- package/lib/types/tool-names.d.ts +11 -0
- package/lib/types/tools.d.ts +80 -0
- package/lib/types/user-agent.d.ts +31 -0
- package/lib/user-agent.js +54 -0
- package/lib/web-search.js +2 -2
- package/package.json +34 -24
package/lib/client.js
CHANGED
|
@@ -65,6 +65,10 @@ var secondaryButton = {
|
|
|
65
65
|
color: textSecondary,
|
|
66
66
|
fontSize: 14
|
|
67
67
|
};
|
|
68
|
+
var disabledButton = {
|
|
69
|
+
opacity: 0.45,
|
|
70
|
+
cursor: "not-allowed"
|
|
71
|
+
};
|
|
68
72
|
var textInput = {
|
|
69
73
|
padding: "9px 12px",
|
|
70
74
|
borderRadius: 10,
|
|
@@ -110,7 +114,338 @@ var interactionCss = [
|
|
|
110
114
|
// 账号行图标钮(用户名/设置/退出账号)hover:底变浅、图标提亮,同侧边栏 iconButton。
|
|
111
115
|
`[data-hiwork-core-icon]:hover { background: ${interactiveHover} !important; color: ${textPrimary} !important; }`,
|
|
112
116
|
// 品牌蓝按钮(登录门禁)hover:提亮而非换底色,保留渐变。
|
|
113
|
-
`[data-hiwork-core-brand]:hover:not(:disabled) { filter: brightness(1.08) !important; }
|
|
117
|
+
`[data-hiwork-core-brand]:hover:not(:disabled) { filter: brightness(1.08) !important; }`,
|
|
118
|
+
// 行内文字链接(设置「关于」的版本/官网/手册):hover 补下划线,走颜色之外的
|
|
119
|
+
// 唯一提示维度,不抢布局。
|
|
120
|
+
`[data-hiwork-core-linktext]:hover { text-decoration: underline; }`
|
|
121
|
+
].join("\n");
|
|
122
|
+
var imageCardsCss = [
|
|
123
|
+
/* ---- 会话内卡片 ---- */
|
|
124
|
+
`.hiwork-image-card {`,
|
|
125
|
+
` display: flex;`,
|
|
126
|
+
` flex-direction: column;`,
|
|
127
|
+
` gap: 8px;`,
|
|
128
|
+
` margin: 6px 0;`,
|
|
129
|
+
` padding: 10px 12px;`,
|
|
130
|
+
` border: 1px solid ${borderL2};`,
|
|
131
|
+
` border-radius: 10px;`,
|
|
132
|
+
` background: ${bgLayer2};`,
|
|
133
|
+
`}`,
|
|
134
|
+
`.hiwork-image-card-head {`,
|
|
135
|
+
` display: flex;`,
|
|
136
|
+
` align-items: baseline;`,
|
|
137
|
+
` gap: 8px;`,
|
|
138
|
+
`}`,
|
|
139
|
+
`.hiwork-image-card-title {`,
|
|
140
|
+
` font-size: 13px;`,
|
|
141
|
+
` font-weight: 600;`,
|
|
142
|
+
` color: ${textPrimary};`,
|
|
143
|
+
`}`,
|
|
144
|
+
`.hiwork-image-card-summary {`,
|
|
145
|
+
` margin-left: auto;`,
|
|
146
|
+
` font-size: 12px;`,
|
|
147
|
+
` color: ${textTertiary};`,
|
|
148
|
+
` font-variant-numeric: tabular-nums;`,
|
|
149
|
+
`}`,
|
|
150
|
+
`.hiwork-image-card-prompt {`,
|
|
151
|
+
` margin: 0;`,
|
|
152
|
+
` font-size: 12px;`,
|
|
153
|
+
` line-height: 18px;`,
|
|
154
|
+
` color: ${textSecondary};`,
|
|
155
|
+
` white-space: pre-wrap;`,
|
|
156
|
+
` word-break: break-word;`,
|
|
157
|
+
`}`,
|
|
158
|
+
`.hiwork-image-card-figure {`,
|
|
159
|
+
` display: flex;`,
|
|
160
|
+
` flex-direction: column;`,
|
|
161
|
+
` gap: 6px;`,
|
|
162
|
+
` margin: 0;`,
|
|
163
|
+
`}`,
|
|
164
|
+
`.hiwork-image-card-img {`,
|
|
165
|
+
` display: block;`,
|
|
166
|
+
` max-width: 100%;`,
|
|
167
|
+
` max-height: 320px;`,
|
|
168
|
+
` border: 1px solid ${borderL2};`,
|
|
169
|
+
` border-radius: 8px;`,
|
|
170
|
+
` background: ${bgLayer1};`,
|
|
171
|
+
` cursor: zoom-in;`,
|
|
172
|
+
`}`,
|
|
173
|
+
`.hiwork-image-card-path {`,
|
|
174
|
+
` font-size: 11px;`,
|
|
175
|
+
` line-height: 16px;`,
|
|
176
|
+
` color: ${textCaption};`,
|
|
177
|
+
` word-break: break-all;`,
|
|
178
|
+
`}`,
|
|
179
|
+
`.hiwork-image-card-meta {`,
|
|
180
|
+
` font-size: 11px;`,
|
|
181
|
+
` color: ${textTertiary};`,
|
|
182
|
+
` font-variant-numeric: tabular-nums;`,
|
|
183
|
+
`}`,
|
|
184
|
+
`.hiwork-image-card-actions {`,
|
|
185
|
+
` display: flex;`,
|
|
186
|
+
` align-items: center;`,
|
|
187
|
+
` gap: 8px;`,
|
|
188
|
+
` flex-wrap: wrap;`,
|
|
189
|
+
`}`,
|
|
190
|
+
`.hiwork-image-card-action {`,
|
|
191
|
+
` padding: 4px 10px;`,
|
|
192
|
+
` border: 1px solid ${borderL2};`,
|
|
193
|
+
` border-radius: 8px;`,
|
|
194
|
+
` background: transparent;`,
|
|
195
|
+
` color: ${textSecondary};`,
|
|
196
|
+
` font: inherit;`,
|
|
197
|
+
` font-size: 11px;`,
|
|
198
|
+
` line-height: 16px;`,
|
|
199
|
+
` cursor: pointer;`,
|
|
200
|
+
`}`,
|
|
201
|
+
`.hiwork-image-card-action:hover {`,
|
|
202
|
+
` background: ${interactiveHover};`,
|
|
203
|
+
` color: ${textPrimary};`,
|
|
204
|
+
`}`,
|
|
205
|
+
`.hiwork-image-card-copy-state {`,
|
|
206
|
+
` font-size: 11px;`,
|
|
207
|
+
` color: ${textTertiary};`,
|
|
208
|
+
`}`,
|
|
209
|
+
`.hiwork-image-card-error {`,
|
|
210
|
+
` margin: 0;`,
|
|
211
|
+
` font-size: 12px;`,
|
|
212
|
+
` line-height: 18px;`,
|
|
213
|
+
` color: ${errorText};`,
|
|
214
|
+
`}`,
|
|
215
|
+
`.hiwork-image-card-retry-hint {`,
|
|
216
|
+
` margin-left: 6px;`,
|
|
217
|
+
` font-size: 11px;`,
|
|
218
|
+
` color: ${warnText};`,
|
|
219
|
+
`}`,
|
|
220
|
+
/* ---- 放大浮层(半透明黑是浮层自带的,不引用宿主内部变量)---- */
|
|
221
|
+
`.hiwork-image-zoom {`,
|
|
222
|
+
` position: fixed;`,
|
|
223
|
+
` inset: 0;`,
|
|
224
|
+
` z-index: 2147483000;`,
|
|
225
|
+
` display: flex;`,
|
|
226
|
+
` align-items: center;`,
|
|
227
|
+
` justify-content: center;`,
|
|
228
|
+
` padding: 32px;`,
|
|
229
|
+
` background: rgba(0, 0, 0, 0.72);`,
|
|
230
|
+
` cursor: zoom-out;`,
|
|
231
|
+
`}`,
|
|
232
|
+
`.hiwork-image-zoom img {`,
|
|
233
|
+
` max-width: 100%;`,
|
|
234
|
+
` max-height: 100%;`,
|
|
235
|
+
` border-radius: 8px;`,
|
|
236
|
+
` background: ${bgLayer1};`,
|
|
237
|
+
`}`,
|
|
238
|
+
`.hiwork-image-zoom-close {`,
|
|
239
|
+
` position: absolute;`,
|
|
240
|
+
` top: 16px;`,
|
|
241
|
+
` right: 20px;`,
|
|
242
|
+
` padding: 4px 12px;`,
|
|
243
|
+
` border: 1px solid rgba(255, 255, 255, 0.4);`,
|
|
244
|
+
` border-radius: 8px;`,
|
|
245
|
+
` background: transparent;`,
|
|
246
|
+
` color: #ffffff;`,
|
|
247
|
+
` font: inherit;`,
|
|
248
|
+
` font-size: 12px;`,
|
|
249
|
+
` cursor: pointer;`,
|
|
250
|
+
`}`
|
|
251
|
+
].join("\n");
|
|
252
|
+
var imagesPageCss = [
|
|
253
|
+
`.hiwork-images {`,
|
|
254
|
+
` display: flex;`,
|
|
255
|
+
` flex-direction: column;`,
|
|
256
|
+
` gap: 14px;`,
|
|
257
|
+
` box-sizing: border-box;`,
|
|
258
|
+
` height: 100%;`,
|
|
259
|
+
` padding: 20px 24px;`,
|
|
260
|
+
` color: ${textPrimary};`,
|
|
261
|
+
` overflow: hidden;`,
|
|
262
|
+
`}`,
|
|
263
|
+
`.hiwork-images-head {`,
|
|
264
|
+
` display: flex;`,
|
|
265
|
+
` align-items: baseline;`,
|
|
266
|
+
` gap: 10px;`,
|
|
267
|
+
` flex-wrap: wrap;`,
|
|
268
|
+
`}`,
|
|
269
|
+
`.hiwork-images-title {`,
|
|
270
|
+
` margin: 0;`,
|
|
271
|
+
` font-size: 18px;`,
|
|
272
|
+
` font-weight: 600;`,
|
|
273
|
+
` color: ${textPrimary};`,
|
|
274
|
+
`}`,
|
|
275
|
+
`.hiwork-images-count {`,
|
|
276
|
+
` font-size: 12px;`,
|
|
277
|
+
` color: ${textTertiary};`,
|
|
278
|
+
` font-variant-numeric: tabular-nums;`,
|
|
279
|
+
`}`,
|
|
280
|
+
`.hiwork-images-body {`,
|
|
281
|
+
` display: grid;`,
|
|
282
|
+
` grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);`,
|
|
283
|
+
` gap: 16px;`,
|
|
284
|
+
` flex: 1;`,
|
|
285
|
+
` min-height: 0;`,
|
|
286
|
+
`}`,
|
|
287
|
+
`.hiwork-images-list {`,
|
|
288
|
+
` display: flex;`,
|
|
289
|
+
` flex-direction: column;`,
|
|
290
|
+
` gap: 6px;`,
|
|
291
|
+
` box-sizing: border-box;`,
|
|
292
|
+
` margin: 0;`,
|
|
293
|
+
` padding: 8px;`,
|
|
294
|
+
` border: 1px solid ${borderL2};`,
|
|
295
|
+
` border-radius: 10px;`,
|
|
296
|
+
` list-style: none;`,
|
|
297
|
+
` overflow-y: auto;`,
|
|
298
|
+
`}`,
|
|
299
|
+
`.hiwork-images-row {`,
|
|
300
|
+
` display: flex;`,
|
|
301
|
+
` flex-direction: column;`,
|
|
302
|
+
` gap: 4px;`,
|
|
303
|
+
` box-sizing: border-box;`,
|
|
304
|
+
` width: 100%;`,
|
|
305
|
+
` padding: 8px 10px;`,
|
|
306
|
+
` border: 1px solid transparent;`,
|
|
307
|
+
` border-radius: 8px;`,
|
|
308
|
+
` background: transparent;`,
|
|
309
|
+
` color: inherit;`,
|
|
310
|
+
` font: inherit;`,
|
|
311
|
+
` text-align: left;`,
|
|
312
|
+
` cursor: pointer;`,
|
|
313
|
+
`}`,
|
|
314
|
+
`.hiwork-images-row:hover {`,
|
|
315
|
+
` background: ${interactiveHover};`,
|
|
316
|
+
`}`,
|
|
317
|
+
`.hiwork-images-row[aria-pressed="true"] {`,
|
|
318
|
+
` border-color: ${brandAccent};`,
|
|
319
|
+
` background: var(--dsw-alias-interactive-bg-active, rgba(15, 17, 21, 0.1));`,
|
|
320
|
+
`}`,
|
|
321
|
+
`.hiwork-images-row-prompt {`,
|
|
322
|
+
` font-size: 12px;`,
|
|
323
|
+
` line-height: 18px;`,
|
|
324
|
+
` color: ${textPrimary};`,
|
|
325
|
+
` overflow: hidden;`,
|
|
326
|
+
` text-overflow: ellipsis;`,
|
|
327
|
+
` white-space: nowrap;`,
|
|
328
|
+
`}`,
|
|
329
|
+
`.hiwork-images-row-meta {`,
|
|
330
|
+
` font-size: 11px;`,
|
|
331
|
+
` color: ${textTertiary};`,
|
|
332
|
+
` font-variant-numeric: tabular-nums;`,
|
|
333
|
+
`}`,
|
|
334
|
+
`.hiwork-images-preview {`,
|
|
335
|
+
` display: flex;`,
|
|
336
|
+
` flex-direction: column;`,
|
|
337
|
+
` gap: 10px;`,
|
|
338
|
+
` box-sizing: border-box;`,
|
|
339
|
+
` min-width: 0;`,
|
|
340
|
+
` min-height: 0;`,
|
|
341
|
+
` padding: 14px;`,
|
|
342
|
+
` border: 1px solid ${borderL2};`,
|
|
343
|
+
` border-radius: 10px;`,
|
|
344
|
+
` background: ${bgLayer2};`,
|
|
345
|
+
` overflow: auto;`,
|
|
346
|
+
`}`,
|
|
347
|
+
`.hiwork-images-image {`,
|
|
348
|
+
` display: block;`,
|
|
349
|
+
` max-width: 100%;`,
|
|
350
|
+
` max-height: 60vh;`,
|
|
351
|
+
` margin: 0 auto;`,
|
|
352
|
+
` border-radius: 8px;`,
|
|
353
|
+
` background: ${bgLayer1};`,
|
|
354
|
+
`}`,
|
|
355
|
+
`.hiwork-images-preview-body {`,
|
|
356
|
+
` display: flex;`,
|
|
357
|
+
` flex-direction: column;`,
|
|
358
|
+
` gap: 10px;`,
|
|
359
|
+
` min-height: 0;`,
|
|
360
|
+
`}`,
|
|
361
|
+
`.hiwork-images-empty {`,
|
|
362
|
+
` display: flex;`,
|
|
363
|
+
` flex-direction: column;`,
|
|
364
|
+
` gap: 6px;`,
|
|
365
|
+
` align-items: flex-start;`,
|
|
366
|
+
` padding: 24px 4px;`,
|
|
367
|
+
`}`,
|
|
368
|
+
`.hiwork-images-preview-prompt {`,
|
|
369
|
+
` margin: 0;`,
|
|
370
|
+
` font-size: 12px;`,
|
|
371
|
+
` line-height: 18px;`,
|
|
372
|
+
` color: ${textSecondary};`,
|
|
373
|
+
` white-space: pre-wrap;`,
|
|
374
|
+
` word-break: break-word;`,
|
|
375
|
+
`}`,
|
|
376
|
+
`.hiwork-images-note {`,
|
|
377
|
+
` margin: 0;`,
|
|
378
|
+
` font-size: 12px;`,
|
|
379
|
+
` line-height: 18px;`,
|
|
380
|
+
` color: ${textTertiary};`,
|
|
381
|
+
`}`,
|
|
382
|
+
`.hiwork-images-empty-title {`,
|
|
383
|
+
` margin: 0;`,
|
|
384
|
+
` font-size: 14px;`,
|
|
385
|
+
` font-weight: 600;`,
|
|
386
|
+
` color: ${textSecondary};`,
|
|
387
|
+
`}`,
|
|
388
|
+
`.hiwork-images-error {`,
|
|
389
|
+
` margin: 0;`,
|
|
390
|
+
` font-size: 12px;`,
|
|
391
|
+
` line-height: 18px;`,
|
|
392
|
+
` color: ${errorText};`,
|
|
393
|
+
`}`,
|
|
394
|
+
`.hiwork-images-banner {`,
|
|
395
|
+
` display: flex;`,
|
|
396
|
+
` align-items: center;`,
|
|
397
|
+
` gap: 8px;`,
|
|
398
|
+
` padding: 8px 10px;`,
|
|
399
|
+
` border-radius: 8px;`,
|
|
400
|
+
` background: ${warnFill};`,
|
|
401
|
+
` color: ${warnText};`,
|
|
402
|
+
` font-size: 12px;`,
|
|
403
|
+
` line-height: 18px;`,
|
|
404
|
+
`}`,
|
|
405
|
+
`.hiwork-images-saved {`,
|
|
406
|
+
` font-size: 11px;`,
|
|
407
|
+
` line-height: 16px;`,
|
|
408
|
+
` color: ${textSecondary};`,
|
|
409
|
+
` word-break: break-all;`,
|
|
410
|
+
`}`,
|
|
411
|
+
`.hiwork-images-actions {`,
|
|
412
|
+
` display: flex;`,
|
|
413
|
+
` align-items: center;`,
|
|
414
|
+
` gap: 8px;`,
|
|
415
|
+
` flex-wrap: wrap;`,
|
|
416
|
+
`}`,
|
|
417
|
+
`.hiwork-images-action {`,
|
|
418
|
+
` padding: 5px 12px;`,
|
|
419
|
+
` border: 1px solid ${borderL2};`,
|
|
420
|
+
` border-radius: 8px;`,
|
|
421
|
+
` background: transparent;`,
|
|
422
|
+
` color: ${textSecondary};`,
|
|
423
|
+
` font: inherit;`,
|
|
424
|
+
` font-size: 12px;`,
|
|
425
|
+
` line-height: 18px;`,
|
|
426
|
+
` cursor: pointer;`,
|
|
427
|
+
`}`,
|
|
428
|
+
`.hiwork-images-action:hover:not(:disabled) {`,
|
|
429
|
+
` background: ${interactiveHover};`,
|
|
430
|
+
` color: ${textPrimary};`,
|
|
431
|
+
`}`,
|
|
432
|
+
`.hiwork-images-action:disabled {`,
|
|
433
|
+
` opacity: 0.45;`,
|
|
434
|
+
` cursor: not-allowed;`,
|
|
435
|
+
`}`,
|
|
436
|
+
`.hiwork-images-more {`,
|
|
437
|
+
` padding: 6px 12px;`,
|
|
438
|
+
` border: 1px solid ${borderL2};`,
|
|
439
|
+
` border-radius: 8px;`,
|
|
440
|
+
` background: transparent;`,
|
|
441
|
+
` color: ${textSecondary};`,
|
|
442
|
+
` font: inherit;`,
|
|
443
|
+
` font-size: 12px;`,
|
|
444
|
+
` cursor: pointer;`,
|
|
445
|
+
`}`,
|
|
446
|
+
`.hiwork-images-more:hover:not(:disabled) {`,
|
|
447
|
+
` background: ${interactiveHover};`,
|
|
448
|
+
`}`
|
|
114
449
|
].join("\n");
|
|
115
450
|
var CORE_STYLE_OWNER = "hiwork-core";
|
|
116
451
|
function ownStyleTag(style, cssTagId) {
|
|
@@ -386,12 +721,12 @@ function openExternalUrl(url) {
|
|
|
386
721
|
function openAuthorizeUrl(url) {
|
|
387
722
|
openExternalUrl(url);
|
|
388
723
|
}
|
|
389
|
-
async function requestBrowserLogin(
|
|
390
|
-
await
|
|
724
|
+
async function requestBrowserLogin(form) {
|
|
725
|
+
await form.set("browserLoginRequest", { at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
391
726
|
}
|
|
392
|
-
async function clearBrowserLogin(
|
|
393
|
-
await
|
|
394
|
-
await
|
|
727
|
+
async function clearBrowserLogin(form) {
|
|
728
|
+
await form.unset("browserLoginRequest");
|
|
729
|
+
await form.unset("browserLogin");
|
|
395
730
|
}
|
|
396
731
|
function project(value) {
|
|
397
732
|
const base = {
|
|
@@ -419,8 +754,8 @@ function project(value) {
|
|
|
419
754
|
return base;
|
|
420
755
|
}
|
|
421
756
|
var AiRouterCardController = class {
|
|
422
|
-
constructor(
|
|
423
|
-
this.
|
|
757
|
+
constructor(form, storeCredential) {
|
|
758
|
+
this.form = form;
|
|
424
759
|
this.storeCredential = storeCredential;
|
|
425
760
|
this.store = (0, import_dsh_client_store.createSnapshotStore)({
|
|
426
761
|
status: "ready",
|
|
@@ -439,10 +774,10 @@ var AiRouterCardController = class {
|
|
|
439
774
|
browserLoginPending: false
|
|
440
775
|
});
|
|
441
776
|
const publish = () => {
|
|
442
|
-
const snapshot = this.
|
|
777
|
+
const snapshot = this.form.getSnapshot();
|
|
443
778
|
if (snapshot.status === "ready") this.store.set(project(snapshot.value));
|
|
444
779
|
};
|
|
445
|
-
this.
|
|
780
|
+
this.form.subscribe(() => publish());
|
|
446
781
|
publish();
|
|
447
782
|
}
|
|
448
783
|
store;
|
|
@@ -462,24 +797,24 @@ var AiRouterCardController = class {
|
|
|
462
797
|
}
|
|
463
798
|
async submitLogin(username, password) {
|
|
464
799
|
await this.storeCredential(PENDING_PASSWORD_REF, password);
|
|
465
|
-
await this.
|
|
800
|
+
await this.form.set("pendingLogin", { username, passwordRef: PENDING_PASSWORD_REF });
|
|
466
801
|
}
|
|
467
802
|
/** 切换 Key:先落 keyId 配置,再触发一次刷新(Host 以新 keyId 重拉额度与模型)。 */
|
|
468
803
|
async selectKey(keyId) {
|
|
469
|
-
await this.
|
|
470
|
-
await this.
|
|
804
|
+
await this.form.set("keyId", keyId);
|
|
805
|
+
await this.form.set("refreshRequest", { at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
471
806
|
}
|
|
472
807
|
async refresh() {
|
|
473
|
-
await this.
|
|
808
|
+
await this.form.set("refreshRequest", { at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
474
809
|
}
|
|
475
810
|
async logout() {
|
|
476
|
-
await this.
|
|
811
|
+
await this.form.set("logoutRequest", { at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
477
812
|
}
|
|
478
813
|
async startBrowserLogin() {
|
|
479
|
-
await requestBrowserLogin(this.
|
|
814
|
+
await requestBrowserLogin(this.form);
|
|
480
815
|
}
|
|
481
816
|
async cancelBrowserLogin() {
|
|
482
|
-
await clearBrowserLogin(this.
|
|
817
|
+
await clearBrowserLogin(this.form);
|
|
483
818
|
}
|
|
484
819
|
/** 重新打开授权页:URL 取自最近一次投影,缺省 no-op(登录门禁另有自动打开)。 */
|
|
485
820
|
reopenBrowserLogin() {
|
|
@@ -1198,7 +1533,7 @@ function UserBadge(props) {
|
|
|
1198
1533
|
title: "\u8BBE\u7F6E",
|
|
1199
1534
|
"aria-label": "\u8BBE\u7F6E",
|
|
1200
1535
|
onClick: openGatewaySettings,
|
|
1201
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.
|
|
1536
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.IconSettingsOutlineMedium, { size: 16 })
|
|
1202
1537
|
}
|
|
1203
1538
|
),
|
|
1204
1539
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -1235,7 +1570,7 @@ var logo_with_text_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACSYA
|
|
|
1235
1570
|
var HIWORK_LOGO = logo_default;
|
|
1236
1571
|
var HIWORK_LOGO_TEXT = logo_text_default;
|
|
1237
1572
|
var HIWORK_LOGO_WITH_TEXT = logo_with_text_default;
|
|
1238
|
-
var HIWORK_VERSION = "1.0.
|
|
1573
|
+
var HIWORK_VERSION = "1.0.7";
|
|
1239
1574
|
|
|
1240
1575
|
// src/client/brand.tsx
|
|
1241
1576
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
@@ -1321,13 +1656,123 @@ function createAppVersion(rpc) {
|
|
|
1321
1656
|
};
|
|
1322
1657
|
}
|
|
1323
1658
|
|
|
1659
|
+
// src/client/about-section.tsx
|
|
1660
|
+
var import_react4 = require("react");
|
|
1661
|
+
|
|
1662
|
+
// src/client/manual-link.ts
|
|
1663
|
+
var MANUAL_URL = "https://hiworkapp.hivery.cn/manual.html";
|
|
1664
|
+
var MANUAL_STYLE_ID = "hiwork-core-manual-style";
|
|
1665
|
+
var MANUAL_STYLE = `
|
|
1666
|
+
[data-hiwork-core-manual-entry]{box-sizing:border-box;flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;margin-left:auto;padding:0;border:0;border-radius:999px;background:transparent;color:var(--dsw-alias-label-tertiary,#71717a);font-family:inherit;font-size:14px;line-height:1;font-weight:600;cursor:pointer;user-select:none;transition:background .16s ease,color .16s ease}
|
|
1667
|
+
[data-hiwork-core-manual-entry]:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(24,24,27,.06));color:var(--dsw-alias-label-secondary,#3f3f46)}
|
|
1668
|
+
[data-hiwork-core-manual-entry]:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#4c8dff);outline-offset:2px}
|
|
1669
|
+
body[data-ds-dark-theme] [data-hiwork-core-manual-entry]{color:var(--dsw-alias-label-tertiary,#9ba3b4)}
|
|
1670
|
+
body[data-ds-dark-theme] [data-hiwork-core-manual-entry]:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-secondary,#a6adb8)}
|
|
1671
|
+
@media (prefers-reduced-motion: reduce){[data-hiwork-core-manual-entry]{transition:none}}
|
|
1672
|
+
`;
|
|
1673
|
+
function ensureManualStyle(doc) {
|
|
1674
|
+
if (doc.getElementById(MANUAL_STYLE_ID) !== null) return;
|
|
1675
|
+
if (doc.head === null) return;
|
|
1676
|
+
const style = doc.createElement("style");
|
|
1677
|
+
style.id = MANUAL_STYLE_ID;
|
|
1678
|
+
ownStyleTag(style, "hiwork-core/manual-link.css");
|
|
1679
|
+
style.textContent = MANUAL_STYLE;
|
|
1680
|
+
doc.head.append(style);
|
|
1681
|
+
}
|
|
1682
|
+
function openManual() {
|
|
1683
|
+
openExternalUrl(MANUAL_URL);
|
|
1684
|
+
}
|
|
1685
|
+
function findManualMount(doc) {
|
|
1686
|
+
const hero = doc.querySelector('[data-phase="hero"]');
|
|
1687
|
+
if (hero === null) return null;
|
|
1688
|
+
return hero.querySelector('[class*="_heroWorkspaceRow"]');
|
|
1689
|
+
}
|
|
1690
|
+
function buildButton(doc) {
|
|
1691
|
+
const button = doc.createElement("button");
|
|
1692
|
+
button.dataset.hiworkCoreManualEntry = "";
|
|
1693
|
+
button.type = "button";
|
|
1694
|
+
button.title = "\u4F7F\u7528\u624B\u518C";
|
|
1695
|
+
button.setAttribute("aria-label", "\u4F7F\u7528\u624B\u518C");
|
|
1696
|
+
button.append(doc.createTextNode("?"));
|
|
1697
|
+
button.addEventListener("click", (event) => {
|
|
1698
|
+
event.preventDefault();
|
|
1699
|
+
event.stopPropagation();
|
|
1700
|
+
openManual();
|
|
1701
|
+
});
|
|
1702
|
+
return button;
|
|
1703
|
+
}
|
|
1704
|
+
function removeStaleManualEntry(doc) {
|
|
1705
|
+
for (const stale of Array.from(doc.querySelectorAll("[data-hiwork-core-manual-entry]"))) {
|
|
1706
|
+
stale.remove();
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
function decorateManualEntry(doc) {
|
|
1710
|
+
const row = findManualMount(doc);
|
|
1711
|
+
if (row === null) {
|
|
1712
|
+
removeStaleManualEntry(doc);
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
const existing = row.querySelector(":scope > [data-hiwork-core-manual-entry]");
|
|
1716
|
+
if (existing !== null) return;
|
|
1717
|
+
removeStaleManualEntry(doc);
|
|
1718
|
+
row.append(buildButton(doc));
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1324
1721
|
// src/client/about-section.tsx
|
|
1325
1722
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1326
1723
|
var KEYWORDS = ["\u667A\u80FD\u4F1A\u8BDD", "\u5C97\u4F4D\u667A\u80FD\u4F53", "\u6280\u80FD\u4E2D\u5FC3", "\u4F01\u4E1A IM \u96C6\u6210", "\u4F1A\u8BDD\u5F52\u6863", "\u5B9A\u65F6\u81EA\u52A8\u5316"];
|
|
1724
|
+
var WEBSITE_ORIGIN = new URL(MANUAL_URL).origin;
|
|
1725
|
+
var WEBSITE_HOST = new URL(MANUAL_URL).host;
|
|
1726
|
+
function versionClipboardText(version) {
|
|
1727
|
+
return `HiWork v${version}`;
|
|
1728
|
+
}
|
|
1729
|
+
async function copyVersionText(text6) {
|
|
1730
|
+
const clipboard = typeof navigator === "undefined" ? void 0 : navigator.clipboard;
|
|
1731
|
+
if (clipboard === void 0 || typeof clipboard.writeText !== "function") return false;
|
|
1732
|
+
try {
|
|
1733
|
+
await clipboard.writeText(text6);
|
|
1734
|
+
return true;
|
|
1735
|
+
} catch {
|
|
1736
|
+
return false;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
var COPY_HINTS = { idle: "\u70B9\u51FB\u590D\u5236", copied: "\u5DF2\u590D\u5236", failed: "\u590D\u5236\u5931\u8D25" };
|
|
1740
|
+
var COPY_HINT_REVERT_MS = 1800;
|
|
1741
|
+
function ExternalLinkButton({ url, text: text6 }) {
|
|
1742
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1743
|
+
"button",
|
|
1744
|
+
{
|
|
1745
|
+
type: "button",
|
|
1746
|
+
"data-hiwork-core-linktext": true,
|
|
1747
|
+
style: linkValueStyle,
|
|
1748
|
+
title: `\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\uFF1A${url}`,
|
|
1749
|
+
onClick: () => {
|
|
1750
|
+
openExternalUrl(url);
|
|
1751
|
+
},
|
|
1752
|
+
children: [
|
|
1753
|
+
text6,
|
|
1754
|
+
" \u2197"
|
|
1755
|
+
]
|
|
1756
|
+
}
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1327
1759
|
var sectionStyle2 = { color: "var(--dsw-alias-label-primary)" };
|
|
1328
1760
|
var brandStyle = { display: "block", height: 32, width: "auto" };
|
|
1329
1761
|
var taglineStyle = { margin: "12px 0 0", fontSize: 15, fontWeight: 600, lineHeight: "22px" };
|
|
1330
1762
|
var subnoteStyle = { margin: "4px 0 0", color: "var(--dsw-alias-label-secondary)", fontSize: 12, lineHeight: "18px" };
|
|
1763
|
+
var versionRowStyle = { display: "flex", alignItems: "baseline", gap: 8, margin: "10px 0 0" };
|
|
1764
|
+
var versionValueStyle = {
|
|
1765
|
+
padding: 0,
|
|
1766
|
+
border: 0,
|
|
1767
|
+
background: "transparent",
|
|
1768
|
+
cursor: "pointer",
|
|
1769
|
+
font: "inherit",
|
|
1770
|
+
fontSize: 13,
|
|
1771
|
+
fontWeight: 600,
|
|
1772
|
+
lineHeight: "18px",
|
|
1773
|
+
color: textPrimary
|
|
1774
|
+
};
|
|
1775
|
+
var versionHintStyle = { color: textTertiary, fontSize: 11, lineHeight: "18px" };
|
|
1331
1776
|
var dividerStyle = { margin: "24px 0 16px", border: 0, borderTop: "1px solid var(--dsw-alias-border-l2)" };
|
|
1332
1777
|
var keywordsStyle = { display: "flex", flexWrap: "wrap", gap: 8, margin: 0, padding: 0, listStyle: "none" };
|
|
1333
1778
|
var keywordStyle = {
|
|
@@ -1339,20 +1784,94 @@ var keywordStyle = {
|
|
|
1339
1784
|
lineHeight: "16px"
|
|
1340
1785
|
};
|
|
1341
1786
|
var securityStyle = { margin: "20px 0 0", color: "var(--dsw-alias-label-tertiary)", fontSize: 12, lineHeight: "18px" };
|
|
1787
|
+
var metaListStyle = { display: "flex", flexDirection: "column", gap: 10, margin: 0 };
|
|
1788
|
+
var metaRowStyle = { display: "flex", alignItems: "baseline", gap: 12 };
|
|
1789
|
+
var metaLabelStyle = { flex: "none", width: "4em", color: textTertiary, fontSize: 12, lineHeight: "18px" };
|
|
1790
|
+
var metaValueStyle = { margin: 0, color: textSecondary, fontSize: 12, lineHeight: "18px", minWidth: 0 };
|
|
1791
|
+
var linkValueStyle = {
|
|
1792
|
+
padding: 0,
|
|
1793
|
+
border: 0,
|
|
1794
|
+
background: "transparent",
|
|
1795
|
+
cursor: "pointer",
|
|
1796
|
+
textAlign: "left",
|
|
1797
|
+
font: "inherit",
|
|
1798
|
+
fontSize: 12,
|
|
1799
|
+
lineHeight: "18px",
|
|
1800
|
+
color: brandAccent
|
|
1801
|
+
};
|
|
1342
1802
|
var copyrightStyle = { margin: "8px 0 0", color: "var(--dsw-alias-label-tertiary)", fontSize: 12, lineHeight: "18px" };
|
|
1343
|
-
function AboutSection(
|
|
1803
|
+
function AboutSection({ appVersion }) {
|
|
1804
|
+
const [version, setVersion] = (0, import_react4.useState)(void 0);
|
|
1805
|
+
const [copyHint, setCopyHint] = (0, import_react4.useState)("idle");
|
|
1806
|
+
const revertTimer = (0, import_react4.useRef)(void 0);
|
|
1807
|
+
(0, import_react4.useEffect)(() => {
|
|
1808
|
+
let alive = true;
|
|
1809
|
+
void appVersion.version().then(
|
|
1810
|
+
(value) => {
|
|
1811
|
+
if (alive) setVersion(value ?? null);
|
|
1812
|
+
},
|
|
1813
|
+
() => {
|
|
1814
|
+
if (alive) setVersion(null);
|
|
1815
|
+
}
|
|
1816
|
+
);
|
|
1817
|
+
return () => {
|
|
1818
|
+
alive = false;
|
|
1819
|
+
};
|
|
1820
|
+
}, [appVersion]);
|
|
1821
|
+
(0, import_react4.useEffect)(() => () => {
|
|
1822
|
+
if (revertTimer.current !== void 0) window.clearTimeout(revertTimer.current);
|
|
1823
|
+
}, []);
|
|
1824
|
+
const onCopyVersion = () => {
|
|
1825
|
+
if (version === void 0) return;
|
|
1826
|
+
void copyVersionText(versionClipboardText(version ?? HIWORK_VERSION)).then((ok) => {
|
|
1827
|
+
setCopyHint(ok ? "copied" : "failed");
|
|
1828
|
+
if (revertTimer.current !== void 0) window.clearTimeout(revertTimer.current);
|
|
1829
|
+
revertTimer.current = window.setTimeout(() => {
|
|
1830
|
+
setCopyHint("idle");
|
|
1831
|
+
}, COPY_HINT_REVERT_MS);
|
|
1832
|
+
});
|
|
1833
|
+
};
|
|
1344
1834
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { "aria-label": "\u5173\u4E8E", style: sectionStyle2, children: [
|
|
1345
1835
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { children: [
|
|
1346
1836
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: HIWORK_LOGO_WITH_TEXT, alt: "HiWork", className: "hiwork-brand-wordmark", style: brandStyle }),
|
|
1347
1837
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: taglineStyle, children: "\u667A\u8054\u4E07\u7269\uFF0C\u4ECE\u667A\u8054\u5DE5\u4F5C\u5F00\u59CB\u3002" }),
|
|
1348
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: subnoteStyle, children: "\u6E90\u81EA\u6D77\u666E HiCap \u7684\u4F01\u4E1A\u7EA7 AI \u5DE5\u4F5C\u53F0" })
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: subnoteStyle, children: "\u6E90\u81EA\u6D77\u666E HiCap \u7684\u4F01\u4E1A\u7EA7 AI \u5DE5\u4F5C\u53F0" }),
|
|
1839
|
+
version === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: versionRowStyle, children: [
|
|
1840
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1841
|
+
"button",
|
|
1842
|
+
{
|
|
1843
|
+
type: "button",
|
|
1844
|
+
"data-hiwork-core-linktext": true,
|
|
1845
|
+
style: versionValueStyle,
|
|
1846
|
+
title: "\u70B9\u51FB\u590D\u5236\u7248\u672C\u4FE1\u606F",
|
|
1847
|
+
"aria-label": `\u590D\u5236\u7248\u672C\u4FE1\u606F v${version ?? HIWORK_VERSION}`,
|
|
1848
|
+
onClick: onCopyVersion,
|
|
1849
|
+
children: [
|
|
1850
|
+
"v",
|
|
1851
|
+
version ?? HIWORK_VERSION
|
|
1852
|
+
]
|
|
1853
|
+
}
|
|
1854
|
+
),
|
|
1855
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: versionHintStyle, children: COPY_HINTS[copyHint] })
|
|
1856
|
+
] })
|
|
1349
1857
|
] }),
|
|
1350
1858
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("hr", { style: dividerStyle }),
|
|
1351
1859
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { style: keywordsStyle, children: KEYWORDS.map((keyword) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { style: keywordStyle, children: keyword }, keyword)) }),
|
|
1352
1860
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: securityStyle, children: "\u6570\u636E\u4E0D\u51FA\u57DF \xB7 \u4E0D\u7528\u4E8E\u8BAD\u7EC3 \xB7 \u5168\u94FE\u8DEF\u52A0\u5BC6" }),
|
|
1353
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("
|
|
1354
|
-
|
|
1355
|
-
|
|
1861
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("hr", { style: dividerStyle }),
|
|
1862
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("dl", { style: metaListStyle, children: [
|
|
1863
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: metaRowStyle, children: [
|
|
1864
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { style: metaLabelStyle, children: "\u5B98\u65B9\u7F51\u7AD9" }),
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { style: metaValueStyle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExternalLinkButton, { url: WEBSITE_ORIGIN, text: WEBSITE_HOST }) })
|
|
1866
|
+
] }),
|
|
1867
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: metaRowStyle, children: [
|
|
1868
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { style: metaLabelStyle, children: "\u4F7F\u7528\u624B\u518C" }),
|
|
1869
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { style: metaValueStyle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ExternalLinkButton, { url: MANUAL_URL, text: "\u5728\u7EBF\u67E5\u770B" }) })
|
|
1870
|
+
] })
|
|
1871
|
+
] }),
|
|
1872
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: copyrightStyle, children: "\xA9 2026 \u6D77\u666E\u667A\u8054\u79D1\u6280\u80A1\u4EFD\u6709\u9650\u516C\u53F8 \xB7 \u4EC5\u9650\u5185\u90E8\u5458\u5DE5\u4F7F\u7528" })
|
|
1873
|
+
] });
|
|
1874
|
+
}
|
|
1356
1875
|
|
|
1357
1876
|
// src/client/daily-data.ts
|
|
1358
1877
|
var DAILY_CHANNEL = "/hiwork-daily";
|
|
@@ -1551,65 +2070,6 @@ function removeStaleHeroGreeting(doc) {
|
|
|
1551
2070
|
for (const stale of Array.from(doc.querySelectorAll("[data-hiwork-hero-greeting]"))) stale.remove();
|
|
1552
2071
|
}
|
|
1553
2072
|
|
|
1554
|
-
// src/client/manual-link.ts
|
|
1555
|
-
var MANUAL_URL = "https://hiworkapp.hivery.cn/manual.html";
|
|
1556
|
-
var MANUAL_STYLE_ID = "hiwork-core-manual-style";
|
|
1557
|
-
var MANUAL_STYLE = `
|
|
1558
|
-
[data-hiwork-core-manual-entry]{box-sizing:border-box;flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;margin-left:auto;padding:0;border:0;border-radius:999px;background:transparent;color:var(--dsw-alias-label-tertiary,#71717a);font-family:inherit;font-size:14px;line-height:1;font-weight:600;cursor:pointer;user-select:none;transition:background .16s ease,color .16s ease}
|
|
1559
|
-
[data-hiwork-core-manual-entry]:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(24,24,27,.06));color:var(--dsw-alias-label-secondary,#3f3f46)}
|
|
1560
|
-
[data-hiwork-core-manual-entry]:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#4c8dff);outline-offset:2px}
|
|
1561
|
-
body[data-ds-dark-theme] [data-hiwork-core-manual-entry]{color:var(--dsw-alias-label-tertiary,#9ba3b4)}
|
|
1562
|
-
body[data-ds-dark-theme] [data-hiwork-core-manual-entry]:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-secondary,#a6adb8)}
|
|
1563
|
-
@media (prefers-reduced-motion: reduce){[data-hiwork-core-manual-entry]{transition:none}}
|
|
1564
|
-
`;
|
|
1565
|
-
function ensureManualStyle(doc) {
|
|
1566
|
-
if (doc.getElementById(MANUAL_STYLE_ID) !== null) return;
|
|
1567
|
-
if (doc.head === null) return;
|
|
1568
|
-
const style = doc.createElement("style");
|
|
1569
|
-
style.id = MANUAL_STYLE_ID;
|
|
1570
|
-
ownStyleTag(style, "hiwork-core/manual-link.css");
|
|
1571
|
-
style.textContent = MANUAL_STYLE;
|
|
1572
|
-
doc.head.append(style);
|
|
1573
|
-
}
|
|
1574
|
-
function openManual() {
|
|
1575
|
-
openExternalUrl(MANUAL_URL);
|
|
1576
|
-
}
|
|
1577
|
-
function findManualMount(doc) {
|
|
1578
|
-
const hero = doc.querySelector('[data-phase="hero"]');
|
|
1579
|
-
if (hero === null) return null;
|
|
1580
|
-
return hero.querySelector('[class*="_heroWorkspaceRow"]');
|
|
1581
|
-
}
|
|
1582
|
-
function buildButton(doc) {
|
|
1583
|
-
const button = doc.createElement("button");
|
|
1584
|
-
button.dataset.hiworkCoreManualEntry = "";
|
|
1585
|
-
button.type = "button";
|
|
1586
|
-
button.title = "\u4F7F\u7528\u624B\u518C";
|
|
1587
|
-
button.setAttribute("aria-label", "\u4F7F\u7528\u624B\u518C");
|
|
1588
|
-
button.append(doc.createTextNode("?"));
|
|
1589
|
-
button.addEventListener("click", (event) => {
|
|
1590
|
-
event.preventDefault();
|
|
1591
|
-
event.stopPropagation();
|
|
1592
|
-
openManual();
|
|
1593
|
-
});
|
|
1594
|
-
return button;
|
|
1595
|
-
}
|
|
1596
|
-
function removeStaleManualEntry(doc) {
|
|
1597
|
-
for (const stale of Array.from(doc.querySelectorAll("[data-hiwork-core-manual-entry]"))) {
|
|
1598
|
-
stale.remove();
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
function decorateManualEntry(doc) {
|
|
1602
|
-
const row = findManualMount(doc);
|
|
1603
|
-
if (row === null) {
|
|
1604
|
-
removeStaleManualEntry(doc);
|
|
1605
|
-
return;
|
|
1606
|
-
}
|
|
1607
|
-
const existing = row.querySelector(":scope > [data-hiwork-core-manual-entry]");
|
|
1608
|
-
if (existing !== null) return;
|
|
1609
|
-
removeStaleManualEntry(doc);
|
|
1610
|
-
row.append(buildButton(doc));
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
2073
|
// src/client/daily-card.ts
|
|
1614
2074
|
var DAILY_CARD_STYLE_ID = "dcu-daily-card-style";
|
|
1615
2075
|
var DAILY_MAIN_FONT_SIZE_MAX = 64;
|
|
@@ -1991,7 +2451,7 @@ function observeAboutNavIcon(doc = document) {
|
|
|
1991
2451
|
}
|
|
1992
2452
|
|
|
1993
2453
|
// src/client/login-gate.tsx
|
|
1994
|
-
var
|
|
2454
|
+
var import_react5 = require("react");
|
|
1995
2455
|
var import_client = require("react-dom/client");
|
|
1996
2456
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1997
2457
|
var INK = "#111b2f";
|
|
@@ -2105,12 +2565,12 @@ function loginGateVisible(snapshot) {
|
|
|
2105
2565
|
return snapshot.value?.lastLogin === void 0 || errorCode === "SESSION_EXPIRED";
|
|
2106
2566
|
}
|
|
2107
2567
|
function LoginGateModal(props) {
|
|
2108
|
-
const [username, setUsername] = (0,
|
|
2109
|
-
const [password, setPassword] = (0,
|
|
2110
|
-
const [rememberPassword, setRememberPassword] = (0,
|
|
2111
|
-
const [submitError, setSubmitError] = (0,
|
|
2112
|
-
const [formOpen, setFormOpen] = (0,
|
|
2113
|
-
(0,
|
|
2568
|
+
const [username, setUsername] = (0, import_react5.useState)(props.initialUsername ?? "");
|
|
2569
|
+
const [password, setPassword] = (0, import_react5.useState)("");
|
|
2570
|
+
const [rememberPassword, setRememberPassword] = (0, import_react5.useState)(props.initialRememberPassword === true);
|
|
2571
|
+
const [submitError, setSubmitError] = (0, import_react5.useState)();
|
|
2572
|
+
const [formOpen, setFormOpen] = (0, import_react5.useState)(false);
|
|
2573
|
+
(0, import_react5.useEffect)(() => {
|
|
2114
2574
|
openAuthorizeUrl(props.browserLoginUrl);
|
|
2115
2575
|
}, [props.browserLoginUrl]);
|
|
2116
2576
|
const showBrowserLogin = props.loginMode !== "form";
|
|
@@ -2123,7 +2583,7 @@ function LoginGateModal(props) {
|
|
|
2123
2583
|
const submit = () => {
|
|
2124
2584
|
if (loginDisabled) return;
|
|
2125
2585
|
setSubmitError(void 0);
|
|
2126
|
-
void props.storeCredential(PENDING_PASSWORD_REF, password).then(() => props.
|
|
2586
|
+
void props.storeCredential(PENDING_PASSWORD_REF, password).then(() => props.form.set("rememberPassword", rememberPassword)).then(() => props.form.set("pendingLogin", { username, passwordRef: PENDING_PASSWORD_REF })).catch(() => setSubmitError("\u767B\u5F55\u8BF7\u6C42\u53D1\u9001\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"));
|
|
2127
2587
|
};
|
|
2128
2588
|
const onSubmit = (event) => {
|
|
2129
2589
|
event.preventDefault();
|
|
@@ -2134,9 +2594,9 @@ function LoginGateModal(props) {
|
|
|
2134
2594
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: browserHintStyle, children: "\u5DF2\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u6388\u6743\u9875\uFF0C\u5B8C\u6210\u767B\u5F55\u540E\u672C\u7A97\u53E3\u4F1A\u81EA\u52A8\u7EE7\u7EED\u3002" }),
|
|
2135
2595
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: browserActionsStyle, children: [
|
|
2136
2596
|
props.browserLoginUrl === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-secondary": true, "data-hiwork-core-browser-reopen": true, type: "button", style: linkButton, onClick: () => openAuthorizeUrl(props.browserLoginUrl), children: "\u91CD\u65B0\u6253\u5F00\u6388\u6743\u9875" }),
|
|
2137
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-secondary": true, "data-hiwork-core-browser-cancel": true, type: "button", style: linkButton, onClick: () => void clearBrowserLogin(props.
|
|
2597
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-secondary": true, "data-hiwork-core-browser-cancel": true, type: "button", style: linkButton, onClick: () => void clearBrowserLogin(props.form), children: "\u53D6\u6D88" })
|
|
2138
2598
|
] })
|
|
2139
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-brand": true, "data-hiwork-core-browser-login": true, type: "button", style: props.loggingIn ? loginButtonDisabled : loginButton, disabled: props.loggingIn, onClick: () => void requestBrowserLogin(props.
|
|
2599
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-brand": true, "data-hiwork-core-browser-login": true, type: "button", style: props.loggingIn ? loginButtonDisabled : loginButton, disabled: props.loggingIn, onClick: () => void requestBrowserLogin(props.form), children: "\u4F7F\u7528\u6D4F\u89C8\u5668\u767B\u5F55" }) : null;
|
|
2140
2600
|
const form = formVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { onSubmit, style: { display: "flex", flexDirection: "column", gap: 14 }, children: [
|
|
2141
2601
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: fieldStyle, children: [
|
|
2142
2602
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: "hiwork-core-username", style: labelStyle, children: "\u7528\u6237\u540D" }),
|
|
@@ -2151,7 +2611,7 @@ function LoginGateModal(props) {
|
|
|
2151
2611
|
"\u8BB0\u4F4F\u5BC6\u7801\uFF0C\u4E0B\u6B21\u81EA\u52A8\u767B\u5F55"
|
|
2152
2612
|
] }),
|
|
2153
2613
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-brand": true, type: "submit", style: loginDisabled ? loginButtonDisabled : loginButton, disabled: loginDisabled, children: props.loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B \u5F55" }),
|
|
2154
|
-
noKey ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-secondary": true, type: "button", style: linkButton, onClick: () => void props.
|
|
2614
|
+
noKey ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-secondary": true, type: "button", style: linkButton, onClick: () => void props.form.set("refreshRequest", { at: (/* @__PURE__ */ new Date()).toISOString() }), children: "\u6211\u5DF2\u5206\u914D KEY\uFF0C\u5237\u65B0" }) : null
|
|
2155
2615
|
] }) : !passwordFormOffered ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { "data-hiwork-core-secondary": true, "data-hiwork-core-form-toggle": true, type: "button", style: toggleStyle, onClick: () => setFormOpen(true), children: props.loginMode === "browser" ? "\u6D4F\u89C8\u5668\u767B\u5F55\u4E0D\u53EF\u7528\uFF1F\u4F7F\u7528\u8D26\u53F7\u5BC6\u7801\u767B\u5F55" : "\u4F7F\u7528\u8D26\u53F7\u5BC6\u7801\u767B\u5F55" });
|
|
2156
2616
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: overlayStyle, children: [
|
|
2157
2617
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OceanWaves, {}),
|
|
@@ -2192,7 +2652,7 @@ function LoginGateModal(props) {
|
|
|
2192
2652
|
] })
|
|
2193
2653
|
] });
|
|
2194
2654
|
}
|
|
2195
|
-
function mountLoginGate(
|
|
2655
|
+
function mountLoginGate(form, storeCredential) {
|
|
2196
2656
|
let root;
|
|
2197
2657
|
let gateContainer;
|
|
2198
2658
|
const appRoot = typeof document === "undefined" ? null : document.getElementById("root");
|
|
@@ -2208,7 +2668,7 @@ function mountLoginGate(scope, storeCredential) {
|
|
|
2208
2668
|
markReady();
|
|
2209
2669
|
};
|
|
2210
2670
|
const render = () => {
|
|
2211
|
-
const snapshot =
|
|
2671
|
+
const snapshot = form.getSnapshot();
|
|
2212
2672
|
if (!loginGateVisible(snapshot)) {
|
|
2213
2673
|
unmount();
|
|
2214
2674
|
return;
|
|
@@ -2222,10 +2682,10 @@ function mountLoginGate(scope, storeCredential) {
|
|
|
2222
2682
|
root = (0, import_client.createRoot)(gateContainer);
|
|
2223
2683
|
if (appRoot !== null) appRoot.inert = true;
|
|
2224
2684
|
}
|
|
2225
|
-
root.render(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LoginGateModal, {
|
|
2685
|
+
root.render(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LoginGateModal, { form, storeCredential, lastError: value?.lastError, loggingIn: value?.pendingLogin !== void 0, initialUsername: value?.username, initialRememberPassword: value?.rememberPassword === true, passwordLogin: passwordLoginOf(value), ...browserLoginViewOf(value) }));
|
|
2226
2686
|
};
|
|
2227
2687
|
render();
|
|
2228
|
-
const dispose =
|
|
2688
|
+
const dispose = form.subscribe(() => render());
|
|
2229
2689
|
return () => {
|
|
2230
2690
|
dispose();
|
|
2231
2691
|
unmount();
|
|
@@ -2233,7 +2693,7 @@ function mountLoginGate(scope, storeCredential) {
|
|
|
2233
2693
|
}
|
|
2234
2694
|
|
|
2235
2695
|
// src/client/usage-section.tsx
|
|
2236
|
-
var
|
|
2696
|
+
var import_react6 = require("react");
|
|
2237
2697
|
|
|
2238
2698
|
// src/client/usage-data.ts
|
|
2239
2699
|
var USAGE_CHANNEL = "/hiwork-usage";
|
|
@@ -2565,16 +3025,16 @@ function RatioRow({ name, value, pct }) {
|
|
|
2565
3025
|
}
|
|
2566
3026
|
function UsageSection(props) {
|
|
2567
3027
|
const card = props.useAiRouterCard((snapshot) => snapshot);
|
|
2568
|
-
const [selectedKeyId, setSelectedKeyId] = (0,
|
|
2569
|
-
const [result, setResult] = (0,
|
|
2570
|
-
const [loading, setLoading] = (0,
|
|
2571
|
-
const alive = (0,
|
|
2572
|
-
const ticket = (0,
|
|
3028
|
+
const [selectedKeyId, setSelectedKeyId] = (0, import_react6.useState)(void 0);
|
|
3029
|
+
const [result, setResult] = (0, import_react6.useState)(void 0);
|
|
3030
|
+
const [loading, setLoading] = (0, import_react6.useState)(true);
|
|
3031
|
+
const alive = (0, import_react6.useRef)(true);
|
|
3032
|
+
const ticket = (0, import_react6.useRef)(0);
|
|
2573
3033
|
const settingsKeyId = card.activeKeyId;
|
|
2574
3034
|
const requestKeyId = selectedKeyId ?? settingsKeyId;
|
|
2575
3035
|
const displayKeyId = requestKeyId ?? result?.data.keys?.[0]?.id;
|
|
2576
3036
|
const loader = props.usage;
|
|
2577
|
-
const load = (0,
|
|
3037
|
+
const load = (0, import_react6.useCallback)(async (force) => {
|
|
2578
3038
|
const current = ticket.current + 1;
|
|
2579
3039
|
ticket.current = current;
|
|
2580
3040
|
setLoading(true);
|
|
@@ -2587,13 +3047,13 @@ function UsageSection(props) {
|
|
|
2587
3047
|
setResult(next);
|
|
2588
3048
|
setLoading(false);
|
|
2589
3049
|
}, [loader, requestKeyId]);
|
|
2590
|
-
(0,
|
|
3050
|
+
(0, import_react6.useEffect)(() => {
|
|
2591
3051
|
alive.current = true;
|
|
2592
3052
|
return () => {
|
|
2593
3053
|
alive.current = false;
|
|
2594
3054
|
};
|
|
2595
3055
|
}, []);
|
|
2596
|
-
(0,
|
|
3056
|
+
(0, import_react6.useEffect)(() => {
|
|
2597
3057
|
void load(false);
|
|
2598
3058
|
}, [load]);
|
|
2599
3059
|
const data = result?.data;
|
|
@@ -2732,179 +3192,27 @@ function UsageSection(props) {
|
|
|
2732
3192
|
] });
|
|
2733
3193
|
}
|
|
2734
3194
|
|
|
2735
|
-
// src/client/
|
|
2736
|
-
var
|
|
2737
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2738
|
-
var SESSION_COST_ENDPOINT = "estimate";
|
|
2739
|
-
var SESSION_COST_CACHE_TTL_MS = 5 * 6e4;
|
|
2740
|
-
var SESSION_COST_HINT = "\u6309\u7F51\u5173\u4EF7\u683C\u4F30\u7B97\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF1B\u4EE5\u300C\u7528\u91CF\u4E0E\u6210\u672C\u300D\u4E2D\u7684\u6743\u5A01\u8D26\u5355\u4E3A\u51C6";
|
|
2741
|
-
var SESSION_COST_ESTIMATED_SUFFIX = "\uFF08\u4F30\u7B97\uFF09";
|
|
2742
|
-
function nonNegativeInteger(value) {
|
|
2743
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
2744
|
-
}
|
|
2745
|
-
function sessionCostMatchOf(data) {
|
|
2746
|
-
if (typeof data !== "object" || data === null) return null;
|
|
2747
|
-
const turn = nonNegativeInteger(data.turn);
|
|
2748
|
-
if (turn === void 0) return null;
|
|
2749
|
-
const usage = data.tokenUsage;
|
|
2750
|
-
if (typeof usage !== "object" || usage === null) return null;
|
|
2751
|
-
const input = nonNegativeInteger(usage.uncachedInputTokens);
|
|
2752
|
-
const output = nonNegativeInteger(usage.outputTokens);
|
|
2753
|
-
if (input === void 0 || output === void 0) return null;
|
|
2754
|
-
const routes = usage.routes;
|
|
2755
|
-
if (!Array.isArray(routes) || routes.length === 0) return null;
|
|
2756
|
-
const pairs = [];
|
|
2757
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2758
|
-
for (const entry of routes) {
|
|
2759
|
-
if (typeof entry !== "object" || entry === null) return null;
|
|
2760
|
-
const { provider, model } = entry;
|
|
2761
|
-
if (typeof provider !== "string" || provider === "" || typeof model !== "string" || model === "") return null;
|
|
2762
|
-
const key = `${provider}\0${model}`;
|
|
2763
|
-
if (seen.has(key)) continue;
|
|
2764
|
-
seen.add(key);
|
|
2765
|
-
pairs.push({ route: provider, model });
|
|
2766
|
-
}
|
|
2767
|
-
if (pairs.length === 0) return null;
|
|
2768
|
-
const cacheRead = nonNegativeInteger(usage.cacheReadTokens);
|
|
2769
|
-
const cacheWrite = nonNegativeInteger(usage.cacheWriteTokens);
|
|
2770
|
-
if (input === 0 && output === 0 && (cacheRead ?? 0) === 0 && (cacheWrite ?? 0) === 0) return null;
|
|
2771
|
-
const first = pairs[0];
|
|
2772
|
-
if (first === void 0) return null;
|
|
2773
|
-
const at = rfc3339Of(data.time);
|
|
2774
|
-
const item = {
|
|
2775
|
-
route: first.route,
|
|
2776
|
-
model: first.model,
|
|
2777
|
-
input_tokens: input,
|
|
2778
|
-
output_tokens: output,
|
|
2779
|
-
// 桶缺失表示「并非每次尝试都上报了该桶」——原样省略,绝不猜 0。
|
|
2780
|
-
...cacheRead === void 0 ? {} : { cache_read_tokens: cacheRead },
|
|
2781
|
-
...cacheWrite === void 0 ? {} : { cache_write_tokens: cacheWrite },
|
|
2782
|
-
...at === void 0 ? {} : { at }
|
|
2783
|
-
};
|
|
2784
|
-
const ambiguous = pairs.length > 1 || cacheRead === void 0 || cacheWrite === void 0;
|
|
2785
|
-
return { items: [item], turn, ambiguous };
|
|
2786
|
-
}
|
|
2787
|
-
function rfc3339Of(time) {
|
|
2788
|
-
if (typeof time !== "number" || !Number.isFinite(time) || time <= 0) return void 0;
|
|
2789
|
-
const date = new Date(time);
|
|
2790
|
-
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
2791
|
-
}
|
|
2792
|
-
function closingTurnTailData(snapshot, messageId) {
|
|
2793
|
-
for (const key of snapshot.order) {
|
|
2794
|
-
const node = snapshot.nodes.get(key);
|
|
2795
|
-
if (node === void 0 || node.kind !== "turn-tail") continue;
|
|
2796
|
-
const data = node.data;
|
|
2797
|
-
if (data === void 0) continue;
|
|
2798
|
-
if (data.closing?.finalNode?.messageId === messageId) return data;
|
|
2799
|
-
}
|
|
2800
|
-
return void 0;
|
|
2801
|
-
}
|
|
2802
|
-
function sessionCostKey(sessionId, match) {
|
|
2803
|
-
return `${sessionId}\0${match.turn}\0${JSON.stringify(match.items)}`;
|
|
2804
|
-
}
|
|
2805
|
-
function normalizeSessionCost(value) {
|
|
2806
|
-
if (typeof value !== "object" || value === null) return void 0;
|
|
2807
|
-
const record = value;
|
|
2808
|
-
if (record.priced !== true) return void 0;
|
|
2809
|
-
const cost = record.cost;
|
|
2810
|
-
if (typeof cost !== "number" || !Number.isFinite(cost) || cost < 0) return void 0;
|
|
2811
|
-
return { cost, channelResolved: record.channelResolved === true };
|
|
2812
|
-
}
|
|
2813
|
-
var SessionCostStore = class {
|
|
2814
|
-
constructor(rpc, options = {}) {
|
|
2815
|
-
this.rpc = rpc;
|
|
2816
|
-
this.now = options.now ?? (() => Date.now());
|
|
2817
|
-
this.ttlMs = options.ttlMs ?? SESSION_COST_CACHE_TTL_MS;
|
|
2818
|
-
}
|
|
2819
|
-
entries = /* @__PURE__ */ new Map();
|
|
2820
|
-
pending = /* @__PURE__ */ new Map();
|
|
2821
|
-
now;
|
|
2822
|
-
ttlMs;
|
|
2823
|
-
/** 当前缓存条目数(测试断言用)。 */
|
|
2824
|
-
get size() {
|
|
2825
|
-
return this.entries.size;
|
|
2826
|
-
}
|
|
2827
|
-
/** 清空缓存(登出 / 切换账号)。 */
|
|
2828
|
-
clear() {
|
|
2829
|
-
this.entries.clear();
|
|
2830
|
-
}
|
|
2831
|
-
async estimate(input) {
|
|
2832
|
-
const key = sessionCostKey(input.sessionId, { turn: input.turn, items: [...input.items] });
|
|
2833
|
-
const cached = this.entries.get(key);
|
|
2834
|
-
if (cached !== void 0 && this.now() - cached.fetchedAt < this.ttlMs) return cached.result;
|
|
2835
|
-
const inflight = this.pending.get(key);
|
|
2836
|
-
if (inflight !== void 0) return await inflight;
|
|
2837
|
-
const task = this.request(key, input);
|
|
2838
|
-
this.pending.set(key, task);
|
|
2839
|
-
try {
|
|
2840
|
-
return await task;
|
|
2841
|
-
} finally {
|
|
2842
|
-
this.pending.delete(key);
|
|
2843
|
-
}
|
|
2844
|
-
}
|
|
2845
|
-
async request(key, input) {
|
|
2846
|
-
try {
|
|
2847
|
-
const raw = await this.rpc.call(USAGE_CHANNEL, SESSION_COST_ENDPOINT, { items: input.items }, input.signal);
|
|
2848
|
-
const result = normalizeSessionCost(unwrapUsageResult(raw));
|
|
2849
|
-
if (result !== void 0) this.entries.set(key, { result, fetchedAt: this.now() });
|
|
2850
|
-
return result;
|
|
2851
|
-
} catch {
|
|
2852
|
-
return void 0;
|
|
2853
|
-
}
|
|
2854
|
-
}
|
|
2855
|
-
};
|
|
2856
|
-
var costStyle = {
|
|
2857
|
-
// 字号/颜色与同一行的「用量」「用时」胶囊同源变量,保证在动作行里不显得突兀。
|
|
2858
|
-
color: textTertiary,
|
|
2859
|
-
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
2860
|
-
lineHeight: "18px",
|
|
2861
|
-
whiteSpace: "nowrap",
|
|
2862
|
-
cursor: "default"
|
|
2863
|
-
};
|
|
2864
|
-
function SessionCost({ messageId, sessionId, useChat, store }) {
|
|
2865
|
-
const data = useChat((snapshot) => closingTurnTailData(snapshot, messageId));
|
|
2866
|
-
const match = sessionCostMatchOf(data);
|
|
2867
|
-
const key = match === null ? null : sessionCostKey(sessionId, match);
|
|
2868
|
-
const [shown, setShown] = (0, import_react6.useState)(void 0);
|
|
2869
|
-
(0, import_react6.useEffect)(() => {
|
|
2870
|
-
if (match === null || key === null) return;
|
|
2871
|
-
let disposed = false;
|
|
2872
|
-
const controller = new AbortController();
|
|
2873
|
-
void store.estimate({ sessionId, turn: match.turn, items: match.items, signal: controller.signal }).then((value) => {
|
|
2874
|
-
if (!disposed) setShown({ key, result: value });
|
|
2875
|
-
}).catch(() => {
|
|
2876
|
-
if (!disposed) setShown({ key, result: void 0 });
|
|
2877
|
-
});
|
|
2878
|
-
return () => {
|
|
2879
|
-
disposed = true;
|
|
2880
|
-
controller.abort();
|
|
2881
|
-
};
|
|
2882
|
-
}, [store, key]);
|
|
2883
|
-
if (match === null || key === null || shown === void 0 || shown.key !== key || shown.result === void 0) return null;
|
|
2884
|
-
const result = shown.result;
|
|
2885
|
-
const estimated = !result.channelResolved || match.ambiguous;
|
|
2886
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: costStyle, "data-hiwork-session-cost": estimated ? "estimated" : "exact", title: SESSION_COST_HINT, children: `\u2248 ${formatYuan(result.cost)}${estimated ? SESSION_COST_ESTIMATED_SUFFIX : ""}` });
|
|
2887
|
-
}
|
|
3195
|
+
// src/client/menu-section.tsx
|
|
3196
|
+
var import_react8 = require("react");
|
|
2888
3197
|
|
|
2889
|
-
// src/client/
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
}
|
|
2893
|
-
function observeAccountChange(source, onChange) {
|
|
2894
|
-
let identity = accountIdentityOf(source.getSnapshot());
|
|
2895
|
-
const unsubscribe = source.subscribe(() => {
|
|
2896
|
-
const next = accountIdentityOf(source.getSnapshot());
|
|
2897
|
-
if (next === identity) return;
|
|
2898
|
-
identity = next;
|
|
2899
|
-
onChange();
|
|
2900
|
-
});
|
|
2901
|
-
return () => {
|
|
2902
|
-
unsubscribe();
|
|
2903
|
-
};
|
|
2904
|
-
}
|
|
3198
|
+
// src/client/feature-center.ts
|
|
3199
|
+
var import_react7 = require("react");
|
|
3200
|
+
var import_client2 = require("react-dom/client");
|
|
2905
3201
|
|
|
2906
3202
|
// src/client/feature-registry.ts
|
|
2907
3203
|
var DEFAULT_FEATURE_ORDER = 1e3;
|
|
3204
|
+
var DEFAULT_FEATURE_ICON = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.84457 5.06199C11.6605 4.93876 14.7962 6.14848 14.8484 7.76397C14.8875 8.97461 13.1838 10.0696 10.7215 10.5942" stroke="currentColor" stroke-width="1.2"></path><path d="M5.12742 8.07731C5.00419 4.26138 6.21391 1.12568 7.8294 1.07351C9.04004 1.03441 10.135 2.73808 10.6596 5.20037" stroke="currentColor" stroke-width="1.2"></path><path d="M8.02457 10.6802C4.20865 10.8034 1.07294 9.5937 1.02077 7.97821C0.981678 6.76758 2.68535 5.67262 5.14763 5.14798" stroke="currentColor" stroke-width="1.2"></path><path d="M10.7476 7.89535C10.8708 11.7113 9.66109 14.847 8.0456 14.8991C6.83496 14.9382 5.74 13.2346 5.21536 10.7723" stroke="currentColor" stroke-width="1.2"></path></svg>';
|
|
3205
|
+
var NATIVE_PLUGINS_MENU_ID = "__native_plugins__";
|
|
3206
|
+
var NATIVE_PLUGINS_MENU_LABEL = "\u63D2\u4EF6";
|
|
3207
|
+
var NATIVE_PLUGINS_MENU_ORDER = 70;
|
|
3208
|
+
function nativePluginsMenuItem() {
|
|
3209
|
+
return {
|
|
3210
|
+
id: NATIVE_PLUGINS_MENU_ID,
|
|
3211
|
+
label: () => NATIVE_PLUGINS_MENU_LABEL,
|
|
3212
|
+
icon: DEFAULT_FEATURE_ICON,
|
|
3213
|
+
order: NATIVE_PLUGINS_MENU_ORDER
|
|
3214
|
+
};
|
|
3215
|
+
}
|
|
2908
3216
|
function compareFeatures(left, right) {
|
|
2909
3217
|
const leftOrder = left.order ?? DEFAULT_FEATURE_ORDER;
|
|
2910
3218
|
const rightOrder = right.order ?? DEFAULT_FEATURE_ORDER;
|
|
@@ -2970,11 +3278,145 @@ function createFeatureRegistry() {
|
|
|
2970
3278
|
};
|
|
2971
3279
|
}
|
|
2972
3280
|
|
|
2973
|
-
// src/client/
|
|
2974
|
-
var
|
|
2975
|
-
var
|
|
2976
|
-
var
|
|
2977
|
-
var
|
|
3281
|
+
// src/client/menu-preferences.ts
|
|
3282
|
+
var HIWORK_MENU_NS = "hiwork-menu";
|
|
3283
|
+
var DEFAULT_SIDEBAR_LIMIT = 5;
|
|
3284
|
+
var MORE_MENU_ITEM_ID = "__hiwork_more__";
|
|
3285
|
+
var MORE_MENU_LABEL = "\u66F4\u591A";
|
|
3286
|
+
var MENU_SECTION_LABEL = "\u4FA7\u680F\u83DC\u5355";
|
|
3287
|
+
var MENU_PLACEMENTS = ["sidebar", "more", "hidden"];
|
|
3288
|
+
var EMPTY_MENU_PREFERENCES = { order: [], sidebar: [], more: [], hidden: [] };
|
|
3289
|
+
function uniqueIds(value) {
|
|
3290
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3291
|
+
const result = [];
|
|
3292
|
+
for (const item of value) {
|
|
3293
|
+
if (typeof item !== "string") continue;
|
|
3294
|
+
const id = item.trim();
|
|
3295
|
+
if (id === "" || seen.has(id)) continue;
|
|
3296
|
+
seen.add(id);
|
|
3297
|
+
result.push(id);
|
|
3298
|
+
}
|
|
3299
|
+
return result;
|
|
3300
|
+
}
|
|
3301
|
+
function idList(value) {
|
|
3302
|
+
return Array.isArray(value) ? uniqueIds(value.filter((item) => typeof item === "string")) : [];
|
|
3303
|
+
}
|
|
3304
|
+
function normalizeMenuPreferences(raw) {
|
|
3305
|
+
if (raw === null || typeof raw !== "object") return EMPTY_MENU_PREFERENCES;
|
|
3306
|
+
const value = raw;
|
|
3307
|
+
return {
|
|
3308
|
+
order: idList(value.order),
|
|
3309
|
+
sidebar: idList(value.sidebar),
|
|
3310
|
+
more: idList(value.more),
|
|
3311
|
+
hidden: idList(value.hidden)
|
|
3312
|
+
};
|
|
3313
|
+
}
|
|
3314
|
+
function placementOf(preferences, id) {
|
|
3315
|
+
if (preferences.hidden.includes(id)) return "hidden";
|
|
3316
|
+
if (preferences.more.includes(id)) return "more";
|
|
3317
|
+
if (preferences.sidebar.includes(id)) return "sidebar";
|
|
3318
|
+
return void 0;
|
|
3319
|
+
}
|
|
3320
|
+
function compareFeatures2(left, right) {
|
|
3321
|
+
const leftOrder = left.order ?? DEFAULT_FEATURE_ORDER;
|
|
3322
|
+
const rightOrder = right.order ?? DEFAULT_FEATURE_ORDER;
|
|
3323
|
+
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
|
3324
|
+
if (left.id === right.id) return 0;
|
|
3325
|
+
return left.id < right.id ? -1 : 1;
|
|
3326
|
+
}
|
|
3327
|
+
function orderedFeatureIds(features, preferences) {
|
|
3328
|
+
const known = new Set(features.map((feature) => feature.id));
|
|
3329
|
+
const result = [];
|
|
3330
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3331
|
+
for (const id of preferences.order) {
|
|
3332
|
+
if (!known.has(id) || seen.has(id)) continue;
|
|
3333
|
+
seen.add(id);
|
|
3334
|
+
result.push(id);
|
|
3335
|
+
}
|
|
3336
|
+
for (const feature of [...features].sort(compareFeatures2)) {
|
|
3337
|
+
if (seen.has(feature.id)) continue;
|
|
3338
|
+
seen.add(feature.id);
|
|
3339
|
+
result.push(feature.id);
|
|
3340
|
+
}
|
|
3341
|
+
return result;
|
|
3342
|
+
}
|
|
3343
|
+
function menuLayout(features, preferences) {
|
|
3344
|
+
const hidden = new Set(preferences.hidden);
|
|
3345
|
+
const explicitMore = new Set(preferences.more.filter((id) => !hidden.has(id)));
|
|
3346
|
+
const explicitSidebar = new Set(preferences.sidebar.filter((id) => !hidden.has(id) && !explicitMore.has(id)));
|
|
3347
|
+
const byId = new Map(features.map((feature) => [feature.id, feature]));
|
|
3348
|
+
const markedMore = [...explicitMore].filter((id) => byId.has(id)).length;
|
|
3349
|
+
const budget = Math.max(0, DEFAULT_SIDEBAR_LIMIT - markedMore);
|
|
3350
|
+
const sidebar = [];
|
|
3351
|
+
const more = [];
|
|
3352
|
+
for (const id of orderedFeatureIds(features, preferences)) {
|
|
3353
|
+
const feature = byId.get(id);
|
|
3354
|
+
if (feature === void 0 || hidden.has(id)) continue;
|
|
3355
|
+
if (explicitSidebar.has(id)) {
|
|
3356
|
+
sidebar.push(feature);
|
|
3357
|
+
continue;
|
|
3358
|
+
}
|
|
3359
|
+
if (explicitMore.has(id) || sidebar.length >= budget) {
|
|
3360
|
+
more.push(feature);
|
|
3361
|
+
continue;
|
|
3362
|
+
}
|
|
3363
|
+
sidebar.push(feature);
|
|
3364
|
+
}
|
|
3365
|
+
return { sidebar, more };
|
|
3366
|
+
}
|
|
3367
|
+
function withoutPlacement(preferences, id) {
|
|
3368
|
+
return {
|
|
3369
|
+
order: preferences.order,
|
|
3370
|
+
sidebar: preferences.sidebar.filter((item) => item !== id),
|
|
3371
|
+
more: preferences.more.filter((item) => item !== id),
|
|
3372
|
+
hidden: preferences.hidden.filter((item) => item !== id)
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
function setMenuPlacement(preferences, id, placement) {
|
|
3376
|
+
const current = placementOf(preferences, id);
|
|
3377
|
+
if (current === placement) return preferences;
|
|
3378
|
+
const base = withoutPlacement(preferences, id);
|
|
3379
|
+
if (placement === "sidebar") return { ...base, sidebar: [...base.sidebar, id] };
|
|
3380
|
+
if (placement === "more") return { ...base, more: [...base.more, id] };
|
|
3381
|
+
return { ...base, hidden: [...base.hidden, id] };
|
|
3382
|
+
}
|
|
3383
|
+
function moveMenuEntry(preferences, features, id, targetIndex) {
|
|
3384
|
+
const ids = orderedFeatureIds(features, preferences);
|
|
3385
|
+
const from = ids.indexOf(id);
|
|
3386
|
+
if (from < 0) return preferences;
|
|
3387
|
+
const to = Math.max(0, Math.min(ids.length - 1, Math.trunc(targetIndex)));
|
|
3388
|
+
if (to === from) return preferences;
|
|
3389
|
+
const next = [...ids];
|
|
3390
|
+
next.splice(from, 1);
|
|
3391
|
+
next.splice(to, 0, id);
|
|
3392
|
+
return { ...preferences, order: next };
|
|
3393
|
+
}
|
|
3394
|
+
function sameIds(left, right) {
|
|
3395
|
+
return left.length === right.length && left.every((item, index) => item === right[index]);
|
|
3396
|
+
}
|
|
3397
|
+
function moveMenuEntryNear(preferences, features, id, targetId, position) {
|
|
3398
|
+
const ids = orderedFeatureIds(features, preferences);
|
|
3399
|
+
const from = ids.indexOf(id);
|
|
3400
|
+
if (from < 0 || id === targetId || !ids.includes(targetId)) return preferences;
|
|
3401
|
+
const rest = ids.filter((item) => item !== id);
|
|
3402
|
+
const anchor = rest.indexOf(targetId);
|
|
3403
|
+
const next = [...rest];
|
|
3404
|
+
next.splice(position === "before" ? anchor : anchor + 1, 0, id);
|
|
3405
|
+
if (sameIds(next, ids)) return preferences;
|
|
3406
|
+
return { ...preferences, order: next };
|
|
3407
|
+
}
|
|
3408
|
+
function menuPreferenceOps(current, next) {
|
|
3409
|
+
const ops = [];
|
|
3410
|
+
for (const field of ["order", "sidebar", "more", "hidden"]) {
|
|
3411
|
+
if (sameIds(current[field], next[field])) continue;
|
|
3412
|
+
ops.push({ op: "set", path: [field], value: [...next[field]] });
|
|
3413
|
+
}
|
|
3414
|
+
return ops;
|
|
3415
|
+
}
|
|
3416
|
+
|
|
3417
|
+
// src/client/feature-center.ts
|
|
3418
|
+
var SIDEBAR_SELECTOR = '[data-pane="sidebar"], [class*="sidebarCol"]';
|
|
3419
|
+
var CONVERSATION_SELECTOR = '[data-pane="conversation"], [class*="centerCol"]';
|
|
2978
3420
|
var REGION_SELECTOR = '[class*="regionArea"]';
|
|
2979
3421
|
var NEW_SESSION_SELECTOR = [
|
|
2980
3422
|
'button[data-testid="new-session"]',
|
|
@@ -2983,11 +3425,16 @@ var NEW_SESSION_SELECTOR = [
|
|
|
2983
3425
|
].join(", ");
|
|
2984
3426
|
var MENU_ATTRIBUTE = "data-hiwork-feature-menu";
|
|
2985
3427
|
var MENU_ITEM_ATTRIBUTE = "data-hiwork-feature-menu-item";
|
|
3428
|
+
var MENU_BUTTON_ATTRIBUTE = "data-hiwork-feature-menu-button";
|
|
3429
|
+
var MORE_TOGGLE_ATTRIBUTE = "data-hiwork-feature-more-toggle";
|
|
3430
|
+
var MORE_PANEL_ATTRIBUTE = "data-hiwork-feature-more-panel";
|
|
3431
|
+
var MORE_PANEL_ITEM_ATTRIBUTE = "data-hiwork-feature-more-item";
|
|
2986
3432
|
var MENU_ICON_ATTRIBUTE = "data-hiwork-feature-menu-icon";
|
|
2987
3433
|
var MENU_LABEL_ATTRIBUTE = "data-hiwork-feature-menu-label";
|
|
2988
3434
|
var TOOLTIP_ATTRIBUTE = "data-hiwork-feature-tooltip";
|
|
2989
3435
|
var TOOLTIP_VISIBLE_ATTRIBUTE = "data-hiwork-feature-tooltip-visible";
|
|
2990
3436
|
var NATIVE_HIDDEN_ATTRIBUTE = "data-hiwork-native-new-session";
|
|
3437
|
+
var NATIVE_PANEL_LIST_ATTRIBUTE = "data-hiwork-native-panel-list";
|
|
2991
3438
|
var FEATURE_ROOT_ATTRIBUTE = "data-hiwork-feature-root";
|
|
2992
3439
|
var OWNER_ATTRIBUTE = "data-hiwork-owner";
|
|
2993
3440
|
var ACTIVE_PAGE_ATTRIBUTE = "data-hiwork-active-page";
|
|
@@ -2997,7 +3444,7 @@ var STYLE_ELEMENT_ID = "hiwork-feature-center-styles";
|
|
|
2997
3444
|
var TOOLTIP_DELAY_MS = 500;
|
|
2998
3445
|
var TOOLTIP_GAP_PX = 8;
|
|
2999
3446
|
var DEFAULT_NEW_SESSION_ICON = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.00003 0.3237C3.76075 0.3237 0.32373 3.76072 0.32373 8C0.32373 9.17603 0.589121 10.2922 1.0632 11.2901L1.35291 11.8989L2.5705 11.3205L2.28079 10.7117C1.89079 9.89074 1.67301 8.97167 1.67301 8C1.67301 4.50546 4.50549 1.67298 8.00003 1.67298C11.4946 1.67298 14.3271 4.50546 14.3271 8C14.3271 11.4945 11.4946 14.327 8.00003 14.327C7.28473 14.327 6.76077 14.277 6.29621 14.1487C5.83857 14.0224 5.40441 13.8109 4.88514 13.4488C4.12569 12.919 3.03778 12.7316 2.141 13.2978L2.12682 13.307L2.11264 13.3171L1.34886 13.854L1.79659 15.188L2.86122 14.4384C3.19068 14.2305 3.68325 14.2542 4.11326 14.5539C4.72789 14.9826 5.30042 15.2724 5.93762 15.4484C6.56803 15.6224 7.22776 15.6763 8.00003 15.6763C12.2393 15.6763 15.6763 12.2393 15.6763 8C15.6763 3.76072 12.2393 0.3237 8.00003 0.3237ZM7.32033 4.82535V7.32536H4.82538V8.67464H7.32033V11.1747H8.6696V8.67464H11.1747V7.32536H8.6696V4.82535H7.32033Z" fill="currentColor"></path></svg>';
|
|
3000
|
-
var
|
|
3447
|
+
var MORE_ICON = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="3.2" cy="8" r="1.15" fill="currentColor"></circle><circle cx="8" cy="8" r="1.15" fill="currentColor"></circle><circle cx="12.8" cy="8" r="1.15" fill="currentColor"></circle></svg>';
|
|
3001
3448
|
var SESSION_ROW_SELECTOR = [
|
|
3002
3449
|
'[class*="sessionRow"]',
|
|
3003
3450
|
'[class*="projectRow"]',
|
|
@@ -3007,18 +3454,22 @@ var SESSION_ROW_SELECTOR = [
|
|
|
3007
3454
|
].join(", ");
|
|
3008
3455
|
var featureCenterCss = [
|
|
3009
3456
|
`[${NATIVE_HIDDEN_ATTRIBUTE}="hidden"] { display: none !important; }`,
|
|
3457
|
+
`[${NATIVE_PANEL_LIST_ATTRIBUTE}="hidden"] { display: none !important; }`,
|
|
3010
3458
|
`[${MENU_ATTRIBUTE}] { display: flex; flex-direction: column; gap: 2px; margin: 0 2px 8px; }`,
|
|
3011
|
-
`[${
|
|
3012
|
-
`[${
|
|
3013
|
-
`[${
|
|
3459
|
+
`[${MENU_BUTTON_ATTRIBUTE}] { display: flex; align-items: center; gap: 8px; width: 100%; box-sizing: border-box; padding: 8px 10px; border: 0; border-radius: 10px; background: transparent; color: var(--dsw-alias-label-primary, #0f1115); font-size: 14px; line-height: 22px; text-align: left; cursor: pointer; }`,
|
|
3460
|
+
`[${MENU_BUTTON_ATTRIBUTE}]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 17, 21, 0.06)); }`,
|
|
3461
|
+
`[${MENU_BUTTON_ATTRIBUTE}][data-hiwork-feature-active="true"] { background: var(--dsw-alias-interactive-bg-active, rgba(15, 17, 21, 0.1)); }`,
|
|
3014
3462
|
`[${MENU_ICON_ATTRIBUTE}] { display: inline-flex; flex: none; width: 16px; height: 16px; }`,
|
|
3015
3463
|
`[${MENU_ICON_ATTRIBUTE}] > svg { display: block; width: 16px; height: 16px; }`,
|
|
3016
3464
|
// 侧栏折叠:宿主在侧栏根元素上加 `*_collapsed`(rc.1 为 hHd-Xa_collapsed),
|
|
3017
3465
|
// 原生控件此时只显示图标;注入菜单必须同形,否则文字会在 56px 宽栏里竖排。
|
|
3018
3466
|
`[class*="sidebarCol"] [class*="collapsed"] [${MENU_ATTRIBUTE}] { margin: 0 4px 8px; }`,
|
|
3019
3467
|
`[class*="sidebarCol"] [class*="collapsed"] [${MENU_LABEL_ATTRIBUTE}] { display: none; }`,
|
|
3020
|
-
`[class*="sidebarCol"] [class*="collapsed"] [${
|
|
3468
|
+
`[class*="sidebarCol"] [class*="collapsed"] [${MENU_BUTTON_ATTRIBUTE}] { justify-content: center; padding: 8px 0; }`,
|
|
3021
3469
|
`[class*="sidebarCol"] [class*="collapsed"] [${MENU_ICON_ATTRIBUTE}], [class*="sidebarCol"] [class*="collapsed"] [${MENU_ICON_ATTRIBUTE}] > svg { width: 18px; height: 18px; }`,
|
|
3470
|
+
// 「更多」浮层:与框架浮层(Tooltip/Popover)同色同圆角,固定定位挂 body(不受侧栏 overflow 裁剪)。
|
|
3471
|
+
`[${MORE_PANEL_ATTRIBUTE}] { position: fixed; z-index: 100; display: flex; flex-direction: column; gap: 2px; box-sizing: border-box; min-width: 168px; max-width: 260px; max-height: 60vh; overflow-y: auto; padding: 4px; border: 1px solid var(--dsw-alias-border-l2, rgba(15, 17, 21, 0.1)); border-radius: 12px; background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 8px 24px rgba(15, 17, 21, 0.16); }`,
|
|
3472
|
+
`[${MORE_PANEL_ATTRIBUTE}] [${MENU_BUTTON_ATTRIBUTE}] { white-space: nowrap; }`,
|
|
3022
3473
|
// 折叠态提示气泡:几何与配色逐项对齐框架 `ui-primitives` 的 `Tooltip.module.css`
|
|
3023
3474
|
// (黑底白字、3px 7px 内边距、8px 圆角、13/20 字号、150ms 淡入、最大半屏宽)。
|
|
3024
3475
|
`[${TOOLTIP_ATTRIBUTE}] { position: fixed; z-index: 100; display: none; width: max-content; max-width: 50vw; padding: 3px 7px; border-radius: 8px; background: var(--dsw-alias-tooltip-bg, #2c2c2e); color: var(--dsw-static-neutral-bluish-00, #fff); font-size: 13px; line-height: 20px; white-space: pre-line; overflow-wrap: break-word; pointer-events: none; transform: translateY(-50%); }`,
|
|
@@ -3061,6 +3512,7 @@ function nativeNewSessionButton(root) {
|
|
|
3061
3512
|
function conversationContainer() {
|
|
3062
3513
|
return document.querySelector(CONVERSATION_SELECTOR) ?? void 0;
|
|
3063
3514
|
}
|
|
3515
|
+
var PANEL_LIST_SELECTOR = 'nav[class*="panelList"]';
|
|
3064
3516
|
function isCollapsedRail(item) {
|
|
3065
3517
|
const host = item.closest('[class*="collapsed"]');
|
|
3066
3518
|
if (host === null) return false;
|
|
@@ -3077,12 +3529,15 @@ function mountFeatureCenter(options) {
|
|
|
3077
3529
|
return { dispose: () => void 0, openNativeHome: () => void 0 };
|
|
3078
3530
|
}
|
|
3079
3531
|
const isActiveOwner = () => activeOwner === owner;
|
|
3080
|
-
for (const stale of Array.from(document.querySelectorAll(`[${MENU_ATTRIBUTE}], [${FEATURE_ROOT_ATTRIBUTE}], [${TOOLTIP_ATTRIBUTE}], #${STYLE_ELEMENT_ID}`))) {
|
|
3532
|
+
for (const stale of Array.from(document.querySelectorAll(`[${MENU_ATTRIBUTE}], [${MORE_PANEL_ATTRIBUTE}], [${FEATURE_ROOT_ATTRIBUTE}], [${TOOLTIP_ATTRIBUTE}], #${STYLE_ELEMENT_ID}`))) {
|
|
3081
3533
|
stale.remove();
|
|
3082
3534
|
}
|
|
3083
3535
|
for (const hidden of Array.from(document.querySelectorAll(`[${NATIVE_HIDDEN_ATTRIBUTE}]`))) {
|
|
3084
3536
|
hidden.removeAttribute(NATIVE_HIDDEN_ATTRIBUTE);
|
|
3085
3537
|
}
|
|
3538
|
+
for (const hidden of Array.from(document.querySelectorAll(`[${NATIVE_PANEL_LIST_ATTRIBUTE}]`))) {
|
|
3539
|
+
hidden.removeAttribute(NATIVE_PANEL_LIST_ATTRIBUTE);
|
|
3540
|
+
}
|
|
3086
3541
|
document.documentElement.removeAttribute(ACTIVE_PAGE_ATTRIBUTE);
|
|
3087
3542
|
activeOwner = owner;
|
|
3088
3543
|
const style = document.createElement("style");
|
|
@@ -3102,6 +3557,87 @@ function mountFeatureCenter(options) {
|
|
|
3102
3557
|
let tooltipElement;
|
|
3103
3558
|
let tooltipTimer;
|
|
3104
3559
|
let tooltipItem;
|
|
3560
|
+
let morePanel;
|
|
3561
|
+
let moreToggle;
|
|
3562
|
+
let morePanelOpen = false;
|
|
3563
|
+
let layout = { sidebar: [], more: [] };
|
|
3564
|
+
const preferences = () => options.preferences?.() ?? EMPTY_MENU_PREFERENCES;
|
|
3565
|
+
const menuFeatures = () => [
|
|
3566
|
+
...registry.list(),
|
|
3567
|
+
...options.additionalFeatures?.() ?? []
|
|
3568
|
+
];
|
|
3569
|
+
const hideMorePanel = (restoreFocus = false) => {
|
|
3570
|
+
const panel = morePanel;
|
|
3571
|
+
const toggle = moreToggle;
|
|
3572
|
+
morePanel = void 0;
|
|
3573
|
+
moreToggle = void 0;
|
|
3574
|
+
if (!morePanelOpen && panel === void 0) return;
|
|
3575
|
+
morePanelOpen = false;
|
|
3576
|
+
panel?.remove();
|
|
3577
|
+
if (toggle !== void 0 && toggle.isConnected) {
|
|
3578
|
+
toggle.setAttribute("aria-expanded", "false");
|
|
3579
|
+
toggle.removeAttribute("data-hiwork-feature-active");
|
|
3580
|
+
if (restoreFocus) toggle.focus();
|
|
3581
|
+
}
|
|
3582
|
+
};
|
|
3583
|
+
const createMorePanelItem = (feature, active) => {
|
|
3584
|
+
const item = createMenuItem(feature.id, feature.label(), feature.icon ?? DEFAULT_FEATURE_ICON, active);
|
|
3585
|
+
item.setAttribute(MORE_PANEL_ITEM_ATTRIBUTE, feature.id);
|
|
3586
|
+
item.setAttribute("role", "menuitem");
|
|
3587
|
+
return item;
|
|
3588
|
+
};
|
|
3589
|
+
const renderMorePanel = () => {
|
|
3590
|
+
const panel = morePanel;
|
|
3591
|
+
if (panel === void 0) return;
|
|
3592
|
+
const active = registry.activeId();
|
|
3593
|
+
const pluginsActive = options.nativePanel?.pluginsActive() ?? false;
|
|
3594
|
+
panel.replaceChildren(...layout.more.map((feature) => createMorePanelItem(feature, feature.id === NATIVE_PLUGINS_MENU_ID ? pluginsActive : feature.id === active)));
|
|
3595
|
+
};
|
|
3596
|
+
const placeMorePanel = (toggle, panel) => {
|
|
3597
|
+
const rect = toggle.getBoundingClientRect();
|
|
3598
|
+
const width = panel.offsetWidth;
|
|
3599
|
+
const height = panel.offsetHeight;
|
|
3600
|
+
const overflowRight = rect.right + TOOLTIP_GAP_PX + width > window.innerWidth;
|
|
3601
|
+
const left = overflowRight ? rect.left - TOOLTIP_GAP_PX - width : rect.right + TOOLTIP_GAP_PX;
|
|
3602
|
+
panel.style.left = `${Math.max(0, left)}px`;
|
|
3603
|
+
panel.style.top = `${Math.max(8, Math.min(rect.top, window.innerHeight - height - 8))}px`;
|
|
3604
|
+
};
|
|
3605
|
+
const showMorePanel = (toggle) => {
|
|
3606
|
+
hideMorePanel();
|
|
3607
|
+
if (layout.more.length === 0) return;
|
|
3608
|
+
const panel = document.createElement("div");
|
|
3609
|
+
panel.setAttribute(MORE_PANEL_ATTRIBUTE, "");
|
|
3610
|
+
panel.setAttribute(OWNER_ATTRIBUTE, owner);
|
|
3611
|
+
panel.setAttribute("role", "menu");
|
|
3612
|
+
panel.addEventListener("click", onMorePanelClick);
|
|
3613
|
+
document.body.appendChild(panel);
|
|
3614
|
+
morePanel = panel;
|
|
3615
|
+
moreToggle = toggle;
|
|
3616
|
+
morePanelOpen = true;
|
|
3617
|
+
toggle.setAttribute("aria-expanded", "true");
|
|
3618
|
+
if (layout.more.some((feature) => feature.id === registry.activeId())) toggle.setAttribute("data-hiwork-feature-active", "true");
|
|
3619
|
+
renderMorePanel();
|
|
3620
|
+
placeMorePanel(toggle, panel);
|
|
3621
|
+
};
|
|
3622
|
+
const toggleMorePanel = (toggle) => {
|
|
3623
|
+
if (morePanelOpen) hideMorePanel();
|
|
3624
|
+
else showMorePanel(toggle);
|
|
3625
|
+
};
|
|
3626
|
+
function onMorePanelClick(event) {
|
|
3627
|
+
const target = event.target;
|
|
3628
|
+
if (!(target instanceof Element)) return;
|
|
3629
|
+
const item = target.closest(`[${MORE_PANEL_ITEM_ATTRIBUTE}]`);
|
|
3630
|
+
if (item === null) return;
|
|
3631
|
+
const id = item.getAttribute(MORE_PANEL_ITEM_ATTRIBUTE);
|
|
3632
|
+
hideMorePanel();
|
|
3633
|
+
if (id === null) return;
|
|
3634
|
+
if (id === NATIVE_PLUGINS_MENU_ID) {
|
|
3635
|
+
if (registry.activeId() !== null) registry.openNative();
|
|
3636
|
+
options.nativePanel?.openPlugins();
|
|
3637
|
+
return;
|
|
3638
|
+
}
|
|
3639
|
+
registry.open(id);
|
|
3640
|
+
}
|
|
3105
3641
|
const hideTooltip = () => {
|
|
3106
3642
|
if (tooltipTimer !== void 0) {
|
|
3107
3643
|
clearTimeout(tooltipTimer);
|
|
@@ -3203,11 +3739,21 @@ function mountFeatureCenter(options) {
|
|
|
3203
3739
|
renderContext.openNativeHome();
|
|
3204
3740
|
return;
|
|
3205
3741
|
}
|
|
3742
|
+
if (id === MORE_MENU_ITEM_ID) {
|
|
3743
|
+
toggleMorePanel(item);
|
|
3744
|
+
return;
|
|
3745
|
+
}
|
|
3746
|
+
if (id === NATIVE_PLUGINS_MENU_ID) {
|
|
3747
|
+
if (registry.activeId() !== null) registry.openNative();
|
|
3748
|
+
options.nativePanel?.openPlugins();
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3206
3751
|
registry.open(id);
|
|
3207
3752
|
};
|
|
3208
3753
|
const createMenuItem = (id, label, icon, active) => {
|
|
3209
3754
|
const item = document.createElement("button");
|
|
3210
3755
|
item.type = "button";
|
|
3756
|
+
item.setAttribute(MENU_BUTTON_ATTRIBUTE, "");
|
|
3211
3757
|
item.setAttribute(MENU_ITEM_ATTRIBUTE, id);
|
|
3212
3758
|
if (active) item.setAttribute("data-hiwork-feature-active", "true");
|
|
3213
3759
|
item.setAttribute("aria-label", label);
|
|
@@ -3222,6 +3768,13 @@ function mountFeatureCenter(options) {
|
|
|
3222
3768
|
item.append(labelSpan);
|
|
3223
3769
|
return item;
|
|
3224
3770
|
};
|
|
3771
|
+
const createMoreRow = (active) => {
|
|
3772
|
+
const item = createMenuItem(MORE_MENU_ITEM_ID, MORE_MENU_LABEL, MORE_ICON, active);
|
|
3773
|
+
item.setAttribute(MORE_TOGGLE_ATTRIBUTE, "");
|
|
3774
|
+
item.setAttribute("aria-haspopup", "menu");
|
|
3775
|
+
item.setAttribute("aria-expanded", morePanelOpen ? "true" : "false");
|
|
3776
|
+
return item;
|
|
3777
|
+
};
|
|
3225
3778
|
const nativeIcon = (native) => {
|
|
3226
3779
|
const svg = native?.querySelector("svg");
|
|
3227
3780
|
return svg === null || svg === void 0 ? DEFAULT_NEW_SESSION_ICON : svg.outerHTML;
|
|
@@ -3230,7 +3783,12 @@ function mountFeatureCenter(options) {
|
|
|
3230
3783
|
const element = menuElement;
|
|
3231
3784
|
if (element === void 0) return;
|
|
3232
3785
|
const active = registry.activeId();
|
|
3233
|
-
const features =
|
|
3786
|
+
const features = menuFeatures();
|
|
3787
|
+
const prefs = preferences();
|
|
3788
|
+
const next = menuLayout(features, prefs);
|
|
3789
|
+
const nativePanel = options.nativePanel;
|
|
3790
|
+
const pluginsAvailable = nativePanel?.pluginsAvailable() ?? false;
|
|
3791
|
+
const pluginsActive = pluginsAvailable && (nativePanel?.pluginsActive() ?? false);
|
|
3234
3792
|
const sidebar = sidebarRoot();
|
|
3235
3793
|
const native = sidebar === void 0 ? void 0 : nativeNewSessionButton(sidebar);
|
|
3236
3794
|
const newSessionLabel = options.newSessionLabel?.() ?? DEFAULT_NEW_SESSION_LABEL;
|
|
@@ -3238,17 +3796,27 @@ function mountFeatureCenter(options) {
|
|
|
3238
3796
|
native === void 0 ? "no-native" : `native:${nativeIcon(native)}`,
|
|
3239
3797
|
newSessionLabel,
|
|
3240
3798
|
active ?? "",
|
|
3799
|
+
// 官方入口的可用性/激活态进签名:plugin-manager 装载完成后(面板注册进 main 槽)
|
|
3800
|
+
// 与用户在原生面板间切换时,菜单都要跟着重绘一次。
|
|
3801
|
+
`panel:${pluginsAvailable ? pluginsActive ? "active" : "idle" : "off"}`,
|
|
3802
|
+
// 分组与顺序都进签名:偏好一变(设置面板里拖一下)就必须重建,否则侧栏不动。
|
|
3803
|
+
`layout:${next.sidebar.map((item) => item.id).join(",")}>${next.more.map((item) => item.id).join(",")}`,
|
|
3241
3804
|
...features.map((item) => `${item.id}:${item.order ?? ""}:${item.label()}:${item.icon ?? ""}`)
|
|
3242
3805
|
].join("|");
|
|
3243
3806
|
if (signature === menuSignature) return;
|
|
3244
3807
|
menuSignature = signature;
|
|
3808
|
+
layout = next;
|
|
3245
3809
|
hideTooltip();
|
|
3810
|
+
hideMorePanel();
|
|
3246
3811
|
const items = [];
|
|
3247
3812
|
if (native !== void 0) items.push(createMenuItem(NATIVE_MENU_ITEM_ID, newSessionLabel, nativeIcon(native), false));
|
|
3248
|
-
for (const item of
|
|
3249
|
-
|
|
3813
|
+
for (const item of next.sidebar) {
|
|
3814
|
+
const rowActive = item.id === NATIVE_PLUGINS_MENU_ID ? pluginsActive : item.id === active;
|
|
3815
|
+
items.push(createMenuItem(item.id, item.label(), item.icon ?? DEFAULT_FEATURE_ICON, rowActive));
|
|
3250
3816
|
}
|
|
3817
|
+
if (next.more.length > 0) items.push(createMoreRow(next.more.some((item) => item.id === active)));
|
|
3251
3818
|
element.replaceChildren(...items);
|
|
3819
|
+
syncNativePanelList(pluginsAvailable);
|
|
3252
3820
|
};
|
|
3253
3821
|
const ensureMenu = (sidebar, native) => {
|
|
3254
3822
|
let element = menuElement;
|
|
@@ -3274,6 +3842,13 @@ function mountFeatureCenter(options) {
|
|
|
3274
3842
|
if (node.getAttribute(OWNER_ATTRIBUTE) !== owner) node.remove();
|
|
3275
3843
|
}
|
|
3276
3844
|
};
|
|
3845
|
+
const syncNativePanelList = (pluginsAvailable) => {
|
|
3846
|
+
const sidebar = sidebarRoot();
|
|
3847
|
+
const nav = sidebar?.querySelector(PANEL_LIST_SELECTOR) ?? null;
|
|
3848
|
+
if (nav === null) return;
|
|
3849
|
+
if (pluginsAvailable) nav.setAttribute(NATIVE_PANEL_LIST_ATTRIBUTE, "hidden");
|
|
3850
|
+
else nav.removeAttribute(NATIVE_PANEL_LIST_ATTRIBUTE);
|
|
3851
|
+
};
|
|
3277
3852
|
const syncMenu = () => {
|
|
3278
3853
|
dedupe(`[${MENU_ATTRIBUTE}]`);
|
|
3279
3854
|
const sidebar = sidebarRoot();
|
|
@@ -3294,6 +3869,7 @@ function mountFeatureCenter(options) {
|
|
|
3294
3869
|
clearTakeover();
|
|
3295
3870
|
return;
|
|
3296
3871
|
}
|
|
3872
|
+
if (options.nativePanel?.anyActive() === true) options.nativePanel.returnToConversation();
|
|
3297
3873
|
const host = conversationContainer();
|
|
3298
3874
|
if (host === void 0) {
|
|
3299
3875
|
clearTakeover();
|
|
@@ -3312,96 +3888,1435 @@ function mountFeatureCenter(options) {
|
|
|
3312
3888
|
const reactRoot = (0, import_client2.createRoot)(element);
|
|
3313
3889
|
root = reactRoot;
|
|
3314
3890
|
try {
|
|
3315
|
-
reactRoot.render((0, import_react7.createElement)(FeatureErrorBoundary, { onError: onRenderError }, target.render(renderContext)));
|
|
3316
|
-
} catch (error) {
|
|
3317
|
-
onRenderError(error);
|
|
3891
|
+
reactRoot.render((0, import_react7.createElement)(FeatureErrorBoundary, { onError: onRenderError }, target.render(renderContext)));
|
|
3892
|
+
} catch (error) {
|
|
3893
|
+
onRenderError(error);
|
|
3894
|
+
}
|
|
3895
|
+
};
|
|
3896
|
+
const pending = () => {
|
|
3897
|
+
const sidebar = sidebarRoot();
|
|
3898
|
+
if (sidebar === void 0) return true;
|
|
3899
|
+
if (menuElement === void 0 || !sidebar.contains(menuElement)) return true;
|
|
3900
|
+
if (registry.activeId() === null) return false;
|
|
3901
|
+
const host = conversationContainer();
|
|
3902
|
+
if (host === void 0) return true;
|
|
3903
|
+
return container === void 0 || !host.contains(container);
|
|
3904
|
+
};
|
|
3905
|
+
const scheduleRetry = () => {
|
|
3906
|
+
if (disposed || retryTimer !== void 0 || retries >= maxRetries) return;
|
|
3907
|
+
retryTimer = setTimeout(() => {
|
|
3908
|
+
retryTimer = void 0;
|
|
3909
|
+
retries += 1;
|
|
3910
|
+
sync();
|
|
3911
|
+
if (pending()) scheduleRetry();
|
|
3912
|
+
}, interval);
|
|
3913
|
+
};
|
|
3914
|
+
const onDocumentClickCapture = (event) => {
|
|
3915
|
+
const target = event.target;
|
|
3916
|
+
if (morePanelOpen) {
|
|
3917
|
+
const inside = target instanceof Element && (target.closest(`[${MORE_PANEL_ATTRIBUTE}]`) !== null || target.closest(`[${MORE_TOGGLE_ATTRIBUTE}]`) !== null);
|
|
3918
|
+
if (!inside) hideMorePanel();
|
|
3919
|
+
}
|
|
3920
|
+
if (registry.activeId() === null) return;
|
|
3921
|
+
if (!(target instanceof Element)) return;
|
|
3922
|
+
if (target.closest(`[${FEATURE_ROOT_ATTRIBUTE}]`) !== null) return;
|
|
3923
|
+
if (target.closest(`[${MENU_ATTRIBUTE}]`) !== null) return;
|
|
3924
|
+
if (target.closest(SESSION_ROW_SELECTOR) === null) return;
|
|
3925
|
+
registry.openNative();
|
|
3926
|
+
};
|
|
3927
|
+
const onDocumentKeyDown = (event) => {
|
|
3928
|
+
if (event.key !== "Escape" || !morePanelOpen) return;
|
|
3929
|
+
event.stopPropagation();
|
|
3930
|
+
hideMorePanel(true);
|
|
3931
|
+
};
|
|
3932
|
+
const onScrollOrResize = () => {
|
|
3933
|
+
hideTooltip();
|
|
3934
|
+
hideMorePanel();
|
|
3935
|
+
};
|
|
3936
|
+
const unsubscribeRegistry = registry.subscribe(() => {
|
|
3937
|
+
sync();
|
|
3938
|
+
});
|
|
3939
|
+
let unsubscribeLocale;
|
|
3940
|
+
if (options.subscribeLocale !== void 0) {
|
|
3941
|
+
try {
|
|
3942
|
+
unsubscribeLocale = options.subscribeLocale(() => {
|
|
3943
|
+
menuSignature = "";
|
|
3944
|
+
rebuildMenuItems();
|
|
3945
|
+
});
|
|
3946
|
+
} catch (error) {
|
|
3947
|
+
console.warn("hiwork feature center: locale subscription unavailable", error);
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
let unsubscribePreferences;
|
|
3951
|
+
if (options.subscribePreferences !== void 0) {
|
|
3952
|
+
try {
|
|
3953
|
+
unsubscribePreferences = options.subscribePreferences(() => {
|
|
3954
|
+
menuSignature = "";
|
|
3955
|
+
rebuildMenuItems();
|
|
3956
|
+
});
|
|
3957
|
+
} catch (error) {
|
|
3958
|
+
console.warn("hiwork feature center: menu preferences subscription unavailable", error);
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
let unsubscribeNativePanel;
|
|
3962
|
+
if (options.nativePanel !== void 0) {
|
|
3963
|
+
try {
|
|
3964
|
+
unsubscribeNativePanel = options.nativePanel.subscribe(() => {
|
|
3965
|
+
if (disposed) return;
|
|
3966
|
+
if (options.nativePanel?.anyActive() === true && registry.activeId() !== null) {
|
|
3967
|
+
registry.openNative();
|
|
3968
|
+
return;
|
|
3969
|
+
}
|
|
3970
|
+
menuSignature = "";
|
|
3971
|
+
rebuildMenuItems();
|
|
3972
|
+
});
|
|
3973
|
+
} catch (error) {
|
|
3974
|
+
console.warn("hiwork feature center: native panel subscription unavailable", error);
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
const observer = new MutationObserver(() => {
|
|
3978
|
+
sync();
|
|
3979
|
+
});
|
|
3980
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
3981
|
+
document.addEventListener("click", onDocumentClickCapture, true);
|
|
3982
|
+
document.addEventListener("keydown", onDocumentKeyDown, true);
|
|
3983
|
+
document.addEventListener("scroll", onScrollOrResize, true);
|
|
3984
|
+
window.addEventListener("resize", onScrollOrResize);
|
|
3985
|
+
const sync = () => {
|
|
3986
|
+
if (disposed || !isActiveOwner()) return;
|
|
3987
|
+
syncMenu();
|
|
3988
|
+
syncTakeover();
|
|
3989
|
+
if (pending()) scheduleRetry();
|
|
3990
|
+
};
|
|
3991
|
+
sync();
|
|
3992
|
+
return {
|
|
3993
|
+
dispose: () => {
|
|
3994
|
+
if (disposed) return;
|
|
3995
|
+
disposed = true;
|
|
3996
|
+
observer.disconnect();
|
|
3997
|
+
if (retryTimer !== void 0) clearTimeout(retryTimer);
|
|
3998
|
+
retryTimer = void 0;
|
|
3999
|
+
unsubscribeRegistry();
|
|
4000
|
+
unsubscribeLocale?.();
|
|
4001
|
+
unsubscribePreferences?.();
|
|
4002
|
+
unsubscribeNativePanel?.();
|
|
4003
|
+
document.removeEventListener("click", onDocumentClickCapture, true);
|
|
4004
|
+
document.removeEventListener("keydown", onDocumentKeyDown, true);
|
|
4005
|
+
document.removeEventListener("scroll", onScrollOrResize, true);
|
|
4006
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
4007
|
+
hideTooltip();
|
|
4008
|
+
hideMorePanel();
|
|
4009
|
+
const tooltip = tooltipElement;
|
|
4010
|
+
tooltipElement = void 0;
|
|
4011
|
+
if (tooltip !== void 0 && tooltip.getAttribute(OWNER_ATTRIBUTE) === owner) tooltip.remove();
|
|
4012
|
+
for (const panel of Array.from(document.querySelectorAll(`[${MORE_PANEL_ATTRIBUTE}]`))) {
|
|
4013
|
+
if (panel.getAttribute(OWNER_ATTRIBUTE) === owner) panel.remove();
|
|
4014
|
+
}
|
|
4015
|
+
clearTakeover();
|
|
4016
|
+
const element = menuElement;
|
|
4017
|
+
menuElement = void 0;
|
|
4018
|
+
if (element !== void 0) {
|
|
4019
|
+
element.removeEventListener("click", onMenuClick);
|
|
4020
|
+
if (element.getAttribute(OWNER_ATTRIBUTE) === owner) element.remove();
|
|
4021
|
+
}
|
|
4022
|
+
if (!isActiveOwner()) return;
|
|
4023
|
+
activeOwner = null;
|
|
4024
|
+
for (const hidden of Array.from(document.querySelectorAll(`[${NATIVE_HIDDEN_ATTRIBUTE}]`))) {
|
|
4025
|
+
hidden.removeAttribute(NATIVE_HIDDEN_ATTRIBUTE);
|
|
4026
|
+
}
|
|
4027
|
+
for (const hidden of Array.from(document.querySelectorAll(`[${NATIVE_PANEL_LIST_ATTRIBUTE}]`))) {
|
|
4028
|
+
hidden.removeAttribute(NATIVE_PANEL_LIST_ATTRIBUTE);
|
|
4029
|
+
}
|
|
4030
|
+
if (style.getAttribute(OWNER_ATTRIBUTE) === owner) style.remove();
|
|
4031
|
+
},
|
|
4032
|
+
openNativeHome: () => {
|
|
4033
|
+
renderContext.openNativeHome();
|
|
4034
|
+
}
|
|
4035
|
+
};
|
|
4036
|
+
}
|
|
4037
|
+
|
|
4038
|
+
// src/client/menu-section.tsx
|
|
4039
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
4040
|
+
var PLACEMENT_LABELS = {
|
|
4041
|
+
sidebar: "\u4FA7\u680F",
|
|
4042
|
+
more: "\u66F4\u591A",
|
|
4043
|
+
hidden: "\u9690\u85CF"
|
|
4044
|
+
};
|
|
4045
|
+
var sectionStyle4 = { display: "flex", flexDirection: "column", gap: 16 };
|
|
4046
|
+
var headerStyle2 = { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, flexWrap: "wrap" };
|
|
4047
|
+
var titleStyle3 = { margin: 0, fontSize: 18, fontWeight: 600, color: textPrimary };
|
|
4048
|
+
var noteStyle2 = { margin: 0, fontSize: 12, lineHeight: "18px", color: textSecondary };
|
|
4049
|
+
var reasonStyle = { margin: 0, fontSize: 12, lineHeight: "18px", color: textTertiary };
|
|
4050
|
+
var listStyle2 = { display: "flex", flexDirection: "column", gap: 2, margin: 0, padding: 0, listStyle: "none" };
|
|
4051
|
+
var rowStyle = (drop, dragging) => ({
|
|
4052
|
+
display: "flex",
|
|
4053
|
+
alignItems: "center",
|
|
4054
|
+
gap: 10,
|
|
4055
|
+
padding: "6px 8px",
|
|
4056
|
+
borderRadius: 8,
|
|
4057
|
+
// 插入线:拖拽落点用 2px 主题色描边标出(不占位,不引起跳动)。
|
|
4058
|
+
...drop === "before" ? { boxShadow: `inset 0 2px 0 0 ${brandAccent}` } : {},
|
|
4059
|
+
...drop === "after" ? { boxShadow: `inset 0 -2px 0 0 ${brandAccent}` } : {},
|
|
4060
|
+
...dragging ? { opacity: 0.5 } : {}
|
|
4061
|
+
});
|
|
4062
|
+
var handleStyle = (writable) => ({
|
|
4063
|
+
display: "flex",
|
|
4064
|
+
alignItems: "center",
|
|
4065
|
+
justifyContent: "center",
|
|
4066
|
+
width: 18,
|
|
4067
|
+
height: 24,
|
|
4068
|
+
flex: "0 0 auto",
|
|
4069
|
+
borderRadius: 6,
|
|
4070
|
+
color: writable ? textTertiary : textTertiary,
|
|
4071
|
+
cursor: writable ? "grab" : "default"
|
|
4072
|
+
});
|
|
4073
|
+
var iconStyle = {
|
|
4074
|
+
display: "flex",
|
|
4075
|
+
alignItems: "center",
|
|
4076
|
+
justifyContent: "center",
|
|
4077
|
+
width: 16,
|
|
4078
|
+
height: 16,
|
|
4079
|
+
flex: "0 0 auto",
|
|
4080
|
+
color: textSecondary
|
|
4081
|
+
};
|
|
4082
|
+
var labelStyle2 = {
|
|
4083
|
+
flex: 1,
|
|
4084
|
+
minWidth: 0,
|
|
4085
|
+
fontSize: 13,
|
|
4086
|
+
lineHeight: "20px",
|
|
4087
|
+
color: textPrimary,
|
|
4088
|
+
overflow: "hidden",
|
|
4089
|
+
textOverflow: "ellipsis",
|
|
4090
|
+
whiteSpace: "nowrap"
|
|
4091
|
+
};
|
|
4092
|
+
var markedStyle = { flex: "0 0 auto", fontSize: 11, lineHeight: "16px", color: textTertiary };
|
|
4093
|
+
var groupStyle = {
|
|
4094
|
+
display: "flex",
|
|
4095
|
+
alignItems: "center",
|
|
4096
|
+
gap: 2,
|
|
4097
|
+
flex: "0 0 auto",
|
|
4098
|
+
padding: 2,
|
|
4099
|
+
borderRadius: 8,
|
|
4100
|
+
background: bgLayer2,
|
|
4101
|
+
border: `1px solid ${borderL2}`
|
|
4102
|
+
};
|
|
4103
|
+
var optionStyle = (active, writable) => ({
|
|
4104
|
+
border: 0,
|
|
4105
|
+
borderRadius: 6,
|
|
4106
|
+
padding: "3px 10px",
|
|
4107
|
+
font: "inherit",
|
|
4108
|
+
fontSize: 12,
|
|
4109
|
+
lineHeight: "18px",
|
|
4110
|
+
color: active ? textPrimary : textSecondary,
|
|
4111
|
+
background: active ? "var(--dsw-alias-bg-layer-1, #ffffff)" : "transparent",
|
|
4112
|
+
boxShadow: active ? "0 1px 2px rgba(15,17,21,0.08)" : "none",
|
|
4113
|
+
cursor: writable ? "pointer" : "default",
|
|
4114
|
+
opacity: writable ? 1 : 0.6
|
|
4115
|
+
});
|
|
4116
|
+
var HANDLE_ICON = '<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="4" r="1.1"></circle><circle cx="10" cy="4" r="1.1"></circle><circle cx="6" cy="8" r="1.1"></circle><circle cx="10" cy="8" r="1.1"></circle><circle cx="6" cy="12" r="1.1"></circle><circle cx="10" cy="12" r="1.1"></circle></svg>';
|
|
4117
|
+
function MenuRow({
|
|
4118
|
+
entry,
|
|
4119
|
+
writable,
|
|
4120
|
+
dragging,
|
|
4121
|
+
drop,
|
|
4122
|
+
onPlacement,
|
|
4123
|
+
onDragStart,
|
|
4124
|
+
onDragOver,
|
|
4125
|
+
onDrop,
|
|
4126
|
+
onDragEnd,
|
|
4127
|
+
onKeyDown
|
|
4128
|
+
}) {
|
|
4129
|
+
const rowRef = (0, import_react8.useRef)(null);
|
|
4130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4131
|
+
"li",
|
|
4132
|
+
{
|
|
4133
|
+
ref: rowRef,
|
|
4134
|
+
tabIndex: 0,
|
|
4135
|
+
role: "listitem",
|
|
4136
|
+
"aria-label": `${entry.label}\uFF0C\u7B2C ${entry.index + 1} \u9879\uFF0C\u5171 ${entry.total} \u9879`,
|
|
4137
|
+
style: rowStyle(drop, dragging),
|
|
4138
|
+
"data-hiwork-menu-row": entry.id,
|
|
4139
|
+
"data-hiwork-menu-placement": entry.placement,
|
|
4140
|
+
...entry.marked ? { "data-hiwork-menu-marked": "true" } : {},
|
|
4141
|
+
...drop === void 0 ? {} : { "data-hiwork-menu-drop": drop },
|
|
4142
|
+
draggable: writable,
|
|
4143
|
+
onDragStart: (event) => {
|
|
4144
|
+
event.dataTransfer.effectAllowed = "move";
|
|
4145
|
+
event.dataTransfer.setData("text/plain", entry.id);
|
|
4146
|
+
onDragStart(entry.id);
|
|
4147
|
+
},
|
|
4148
|
+
onDragEnd,
|
|
4149
|
+
onKeyDown: (event) => {
|
|
4150
|
+
onKeyDown(event, entry);
|
|
4151
|
+
},
|
|
4152
|
+
onDragOver: (event) => {
|
|
4153
|
+
onDragOver(event, entry.id);
|
|
4154
|
+
},
|
|
4155
|
+
onDrop: (event) => {
|
|
4156
|
+
onDrop(event, entry.id);
|
|
4157
|
+
},
|
|
4158
|
+
children: [
|
|
4159
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4160
|
+
"span",
|
|
4161
|
+
{
|
|
4162
|
+
style: handleStyle(writable),
|
|
4163
|
+
draggable: writable,
|
|
4164
|
+
"aria-hidden": "true",
|
|
4165
|
+
"data-hiwork-menu-handle": entry.id,
|
|
4166
|
+
dangerouslySetInnerHTML: { __html: HANDLE_ICON }
|
|
4167
|
+
}
|
|
4168
|
+
),
|
|
4169
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: iconStyle, dangerouslySetInnerHTML: { __html: entry.icon ?? DEFAULT_FEATURE_ICON } }),
|
|
4170
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: labelStyle2, children: entry.label }),
|
|
4171
|
+
entry.marked ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: markedStyle, children: "\u5DF2\u8BBE\u7F6E" }) : null,
|
|
4172
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: groupStyle, role: "group", "aria-label": `${entry.label} \u663E\u793A\u4F4D\u7F6E`, children: MENU_PLACEMENTS.map((placement) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4173
|
+
"button",
|
|
4174
|
+
{
|
|
4175
|
+
type: "button",
|
|
4176
|
+
style: optionStyle(entry.placement === placement, writable),
|
|
4177
|
+
"aria-pressed": entry.placement === placement,
|
|
4178
|
+
"data-hiwork-menu-option": placement,
|
|
4179
|
+
disabled: !writable,
|
|
4180
|
+
onClick: () => {
|
|
4181
|
+
onPlacement(entry.id, placement);
|
|
4182
|
+
},
|
|
4183
|
+
children: PLACEMENT_LABELS[placement]
|
|
4184
|
+
},
|
|
4185
|
+
placement
|
|
4186
|
+
)) })
|
|
4187
|
+
]
|
|
4188
|
+
}
|
|
4189
|
+
);
|
|
4190
|
+
}
|
|
4191
|
+
function MenuSection(props) {
|
|
4192
|
+
const state = props.useMenu((snapshot) => snapshot);
|
|
4193
|
+
const [dragId, setDragId] = (0, import_react8.useState)(void 0);
|
|
4194
|
+
const [drop, setDrop] = (0, import_react8.useState)(void 0);
|
|
4195
|
+
const { setPlacement, move, moveNear, reset } = props.actions;
|
|
4196
|
+
const writable = state.writable;
|
|
4197
|
+
const onDragOver = (event, id) => {
|
|
4198
|
+
if (dragId === void 0 || dragId === id) return;
|
|
4199
|
+
event.preventDefault();
|
|
4200
|
+
event.dataTransfer.dropEffect = "move";
|
|
4201
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
4202
|
+
const position = event.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
4203
|
+
setDrop((current) => current?.id === id && current.position === position ? current : { id, position });
|
|
4204
|
+
};
|
|
4205
|
+
const onDrop = (event, id) => {
|
|
4206
|
+
if (dragId === void 0 || dragId === id) return;
|
|
4207
|
+
event.preventDefault();
|
|
4208
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
4209
|
+
const position = event.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
4210
|
+
const moving = dragId;
|
|
4211
|
+
setDragId(void 0);
|
|
4212
|
+
setDrop(void 0);
|
|
4213
|
+
void moveNear(moving, id, position);
|
|
4214
|
+
};
|
|
4215
|
+
const onKeyDown = (event, entry) => {
|
|
4216
|
+
if (!writable) return;
|
|
4217
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
4218
|
+
if (event.target !== event.currentTarget) return;
|
|
4219
|
+
event.preventDefault();
|
|
4220
|
+
void move(entry.id, event.key === "ArrowUp" ? -1 : 1);
|
|
4221
|
+
};
|
|
4222
|
+
const marked = state.entries.some((entry) => entry.marked);
|
|
4223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { "aria-label": "\u4FA7\u680F\u83DC\u5355", style: sectionStyle4, "data-hiwork-menu-section": "", children: [
|
|
4224
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { style: headerStyle2, children: [
|
|
4225
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: titleStyle3, children: "\u4FA7\u680F\u83DC\u5355" }),
|
|
4226
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4227
|
+
"button",
|
|
4228
|
+
{
|
|
4229
|
+
type: "button",
|
|
4230
|
+
style: writable && marked ? secondaryButton : disabledButton,
|
|
4231
|
+
disabled: !writable || !marked,
|
|
4232
|
+
"data-hiwork-menu-reset": "",
|
|
4233
|
+
onClick: () => {
|
|
4234
|
+
void reset();
|
|
4235
|
+
},
|
|
4236
|
+
children: "\u6062\u590D\u9ED8\u8BA4"
|
|
4237
|
+
}
|
|
4238
|
+
)
|
|
4239
|
+
] }),
|
|
4240
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: noteStyle2, children: [
|
|
4241
|
+
"\u4FA7\u680F\u53EA\u663E\u793A\u4F60\u9009\u5B9A\u7684\u5165\u53E3\uFF0C\u5176\u4F59\u6536\u8FDB\u300C\u66F4\u591A\u300D\u2014\u2014\u70B9\u4FA7\u680F\u6700\u540E\u4E00\u884C\u300C\u66F4\u591A\u300D\u5C31\u80FD\u770B\u5230\u3002 \u653E\u5230\u300C\u66F4\u591A\u300D\u6216\u300C\u9690\u85CF\u300D\u90FD\u4F1A\u8BA9\u4FA7\u680F\u5C11\u4E00\u884C\uFF1B\u5F53\u524D\u6700\u591A\u663E\u793A ",
|
|
4242
|
+
state.limit,
|
|
4243
|
+
" \u4E2A\u5165\u53E3\u3002"
|
|
4244
|
+
] }),
|
|
4245
|
+
state.reason === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: reasonStyle, "data-hiwork-menu-reason": "", children: state.reason }),
|
|
4246
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { style: listStyle2, children: state.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4247
|
+
MenuRow,
|
|
4248
|
+
{
|
|
4249
|
+
entry,
|
|
4250
|
+
writable,
|
|
4251
|
+
dragging: dragId === entry.id,
|
|
4252
|
+
drop: drop?.id === entry.id ? drop.position : void 0,
|
|
4253
|
+
onPlacement: (id, placement) => {
|
|
4254
|
+
void setPlacement(id, placement);
|
|
4255
|
+
},
|
|
4256
|
+
onDragStart: setDragId,
|
|
4257
|
+
onDragOver,
|
|
4258
|
+
onDrop,
|
|
4259
|
+
onDragEnd: () => {
|
|
4260
|
+
setDragId(void 0);
|
|
4261
|
+
setDrop(void 0);
|
|
4262
|
+
},
|
|
4263
|
+
onKeyDown
|
|
4264
|
+
},
|
|
4265
|
+
entry.id
|
|
4266
|
+
)) }),
|
|
4267
|
+
state.entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: noteStyle2, children: "\u5F53\u524D\u8FD8\u6CA1\u6709\u53EF\u914D\u7F6E\u7684\u5165\u53E3\u3002" }) : null,
|
|
4268
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: reasonStyle, children: "\u63D0\u793A\uFF1A\u62D6\u52A8\u5DE6\u4FA7\u624B\u67C4\u53EF\u4EE5\u8C03\u6574\u987A\u5E8F\uFF1B\u952E\u76D8\u4E0A/\u4E0B\u65B9\u5411\u952E\u4E5F\u80FD\u79FB\u52A8\u3002" })
|
|
4269
|
+
] });
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
// src/client/menu-store.ts
|
|
4273
|
+
var import_dsh_client_store2 = require("@deepseek-ai/dsh-client-store");
|
|
4274
|
+
var MENU_FIELD = "menu";
|
|
4275
|
+
var LOADING_STATE = {
|
|
4276
|
+
status: "loading",
|
|
4277
|
+
writable: false,
|
|
4278
|
+
entries: [],
|
|
4279
|
+
limit: DEFAULT_SIDEBAR_LIMIT,
|
|
4280
|
+
reason: void 0
|
|
4281
|
+
};
|
|
4282
|
+
function reasonFor(status, writable) {
|
|
4283
|
+
if (status === "loading") return "\u6B63\u5728\u8BFB\u53D6\u5F53\u524D\u8BBE\u7F6E\u2026";
|
|
4284
|
+
if (status === "unavailable") return "\u5F53\u524D\u8FDE\u63A5\u4E0D\u652F\u6301\u4FDD\u5B58\u672C\u673A\u504F\u597D\uFF0C\u83DC\u5355\u6682\u6309\u9ED8\u8BA4\u663E\u793A\u3002";
|
|
4285
|
+
if (!writable) return "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u83DC\u5355\u504F\u597D\u3002";
|
|
4286
|
+
return void 0;
|
|
4287
|
+
}
|
|
4288
|
+
function toPathOps(ops) {
|
|
4289
|
+
return ops.map((op) => ({ op: "set", path: [MENU_FIELD, ...op.path], value: [...op.value] }));
|
|
4290
|
+
}
|
|
4291
|
+
var MenuStore = class {
|
|
4292
|
+
/**
|
|
4293
|
+
* @param form - `ai-router` entry 的配置表单(与网关卡片同一个共享实例,见 `src/client/index.ts`)。
|
|
4294
|
+
* @param registry - feature 注册表(列表内容与顺序的另一个来源)。
|
|
4295
|
+
* @param additionalFeatures - 追加的非注册表条目(官方「插件」代理项;可用性由调用方判断)。
|
|
4296
|
+
* 缺省时列表只有注册表成员——与旧版行为一致。
|
|
4297
|
+
*/
|
|
4298
|
+
constructor(form, registry, additionalFeatures) {
|
|
4299
|
+
this.form = form;
|
|
4300
|
+
this.registry = registry;
|
|
4301
|
+
this.additionalFeatures = additionalFeatures;
|
|
4302
|
+
this.store = (0, import_dsh_client_store2.createSnapshotStore)(LOADING_STATE);
|
|
4303
|
+
const publish = () => {
|
|
4304
|
+
this.store.set(this.view());
|
|
4305
|
+
};
|
|
4306
|
+
publish();
|
|
4307
|
+
this.unsubscribe.push(form.subscribe(publish));
|
|
4308
|
+
this.unsubscribe.push(registry.subscribe(publish));
|
|
4309
|
+
}
|
|
4310
|
+
store;
|
|
4311
|
+
unsubscribe = [];
|
|
4312
|
+
/** 当前偏好(未就绪 / 值非法时按「从未自定义」处理)。 */
|
|
4313
|
+
preferences() {
|
|
4314
|
+
const snapshot = this.form.getSnapshot();
|
|
4315
|
+
if (snapshot.status !== "ready") return EMPTY_MENU_PREFERENCES;
|
|
4316
|
+
return normalizeMenuPreferences(snapshot.value?.menu);
|
|
4317
|
+
}
|
|
4318
|
+
/** 订阅偏好变化(菜单适配器用;与 `preferences()` 同源)。 */
|
|
4319
|
+
subscribePreferences(listener) {
|
|
4320
|
+
return this.form.subscribe(listener);
|
|
4321
|
+
}
|
|
4322
|
+
/** 菜单条目全集(注册表 + 追加的代理项),与侧栏适配器的来源同构。 */
|
|
4323
|
+
menuFeatures() {
|
|
4324
|
+
return [...this.registry.list(), ...this.additionalFeatures?.() ?? []];
|
|
4325
|
+
}
|
|
4326
|
+
/** 当前渲染状态。 */
|
|
4327
|
+
view() {
|
|
4328
|
+
const snapshot = this.form.getSnapshot();
|
|
4329
|
+
const value = snapshot.status === "ready" ? normalizeMenuPreferences(snapshot.value?.menu) : EMPTY_MENU_PREFERENCES;
|
|
4330
|
+
const features = this.menuFeatures();
|
|
4331
|
+
const layout = menuLayout(features, value);
|
|
4332
|
+
const placementById = new Map([
|
|
4333
|
+
...layout.sidebar.map((feature) => [feature.id, "sidebar"]),
|
|
4334
|
+
...layout.more.map((feature) => [feature.id, "more"])
|
|
4335
|
+
]);
|
|
4336
|
+
const byId = new Map(features.map((feature) => [feature.id, feature]));
|
|
4337
|
+
const ordered = orderedFeatureIds(features, value);
|
|
4338
|
+
const entries = ordered.flatMap((id, index) => {
|
|
4339
|
+
const feature = byId.get(id);
|
|
4340
|
+
if (feature === void 0) return [];
|
|
4341
|
+
return [{
|
|
4342
|
+
id,
|
|
4343
|
+
label: feature.label(),
|
|
4344
|
+
icon: feature.icon,
|
|
4345
|
+
// 生效去向:不在前两组里的就是被隐藏的(hidden 的项两者都不出现)。
|
|
4346
|
+
placement: placementById.get(id) ?? "hidden",
|
|
4347
|
+
marked: placementOf(value, id) !== void 0,
|
|
4348
|
+
index,
|
|
4349
|
+
total: ordered.length
|
|
4350
|
+
}];
|
|
4351
|
+
});
|
|
4352
|
+
const limit = Math.max(0, DEFAULT_SIDEBAR_LIMIT - value.more.filter((id) => features.some((feature) => feature.id === id)).length);
|
|
4353
|
+
return {
|
|
4354
|
+
status: snapshot.status,
|
|
4355
|
+
writable: snapshot.status === "ready" && snapshot.writable,
|
|
4356
|
+
entries,
|
|
4357
|
+
limit,
|
|
4358
|
+
reason: reasonFor(snapshot.status, snapshot.writable)
|
|
4359
|
+
};
|
|
4360
|
+
}
|
|
4361
|
+
/** 清掉在这份 store 上的全部订阅(插件卸载时调用)。 */
|
|
4362
|
+
dispose() {
|
|
4363
|
+
for (const off of this.unsubscribe.splice(0)) off();
|
|
4364
|
+
}
|
|
4365
|
+
/** 立即重算渲染状态(追加条目的可用性变化等非表单/注册表来源的变化走这里)。 */
|
|
4366
|
+
refresh() {
|
|
4367
|
+
this.store.set(this.view());
|
|
4368
|
+
}
|
|
4369
|
+
/** 注入面:设置分区组件消费。 */
|
|
4370
|
+
inject() {
|
|
4371
|
+
return {
|
|
4372
|
+
hooks: { menu: this.store },
|
|
4373
|
+
actions: {
|
|
4374
|
+
setPlacement: (id, placement) => this.setPlacement(id, placement),
|
|
4375
|
+
move: (id, offset) => this.move(id, offset),
|
|
4376
|
+
moveNear: (id, targetId, position) => this.moveNear(id, targetId, position),
|
|
4377
|
+
reset: () => this.reset()
|
|
4378
|
+
}
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
async setPlacement(id, placement) {
|
|
4382
|
+
const current = this.preferences();
|
|
4383
|
+
const effective = this.view().entries.find((entry) => entry.id === id)?.placement;
|
|
4384
|
+
if (effective === placement) return;
|
|
4385
|
+
await this.write(setMenuPlacement(current, id, placement), current);
|
|
4386
|
+
}
|
|
4387
|
+
async move(id, offset) {
|
|
4388
|
+
const current = this.preferences();
|
|
4389
|
+
const ids = this.view().entries.map((entry) => entry.id);
|
|
4390
|
+
const index = ids.indexOf(id);
|
|
4391
|
+
if (index < 0) return;
|
|
4392
|
+
await this.write(moveMenuEntry(current, this.menuFeatures(), id, index + offset), current);
|
|
4393
|
+
}
|
|
4394
|
+
async moveNear(id, targetId, position) {
|
|
4395
|
+
const current = this.preferences();
|
|
4396
|
+
await this.write(moveMenuEntryNear(current, this.menuFeatures(), id, targetId, position), current);
|
|
4397
|
+
}
|
|
4398
|
+
async reset() {
|
|
4399
|
+
const current = this.form.getSnapshot();
|
|
4400
|
+
if (current.status !== "ready" || !current.writable) return;
|
|
4401
|
+
await this.form.mutate([{ op: "unset", path: [MENU_FIELD] }]);
|
|
4402
|
+
}
|
|
4403
|
+
/** 未标记项的生效去向已由 `view()` 给出,这里不再另算一份。 */
|
|
4404
|
+
async write(next, current) {
|
|
4405
|
+
const snapshot = this.form.getSnapshot();
|
|
4406
|
+
if (snapshot.status !== "ready" || !snapshot.writable) return;
|
|
4407
|
+
const ops = menuPreferenceOps(current, next);
|
|
4408
|
+
if (ops.length === 0) return;
|
|
4409
|
+
await this.form.mutate(toPathOps(ops));
|
|
4410
|
+
}
|
|
4411
|
+
};
|
|
4412
|
+
|
|
4413
|
+
// src/client/images-data.ts
|
|
4414
|
+
var IMAGE_CHANNEL = "/hiwork-image";
|
|
4415
|
+
var IMAGE_LIST_PAGE_SIZE = 20;
|
|
4416
|
+
var IMAGE_LIST_MAX_PAGE_SIZE = 100;
|
|
4417
|
+
var IMAGE_DATA_ERROR_TEXT = "\u56FE\u7247\u8BB0\u5F55\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
|
|
4418
|
+
var ImageRpcError = class extends Error {
|
|
4419
|
+
constructor(code, message) {
|
|
4420
|
+
super(message);
|
|
4421
|
+
this.code = code;
|
|
4422
|
+
this.name = "ImageRpcError";
|
|
4423
|
+
}
|
|
4424
|
+
};
|
|
4425
|
+
function unwrapImageResult(value) {
|
|
4426
|
+
if (typeof value !== "object" || value === null || !("ok" in value)) {
|
|
4427
|
+
throw new ImageRpcError("internal", "\u56FE\u7247\u4E3B\u673A\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\u3002");
|
|
4428
|
+
}
|
|
4429
|
+
const result = value;
|
|
4430
|
+
if (result.ok === true) return result.value;
|
|
4431
|
+
if (result.ok === false) {
|
|
4432
|
+
const code = typeof result.error?.code === "string" ? result.error.code : "internal";
|
|
4433
|
+
const message = typeof result.error?.message === "string" && result.error.message.trim() !== "" ? result.error.message : IMAGE_DATA_ERROR_TEXT;
|
|
4434
|
+
throw new ImageRpcError(code, message);
|
|
4435
|
+
}
|
|
4436
|
+
throw new ImageRpcError("internal", "\u56FE\u7247\u4E3B\u673A\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\u3002");
|
|
4437
|
+
}
|
|
4438
|
+
function imageErrorOf(error) {
|
|
4439
|
+
if (error instanceof ImageRpcError) return { code: error.code, message: error.message };
|
|
4440
|
+
return { code: "internal", message: IMAGE_DATA_ERROR_TEXT };
|
|
4441
|
+
}
|
|
4442
|
+
function str(value) {
|
|
4443
|
+
return typeof value === "string" ? value : "";
|
|
4444
|
+
}
|
|
4445
|
+
function num(value) {
|
|
4446
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
4447
|
+
}
|
|
4448
|
+
function normalizeImageListPage(value, fallbackPage, fallbackPageSize) {
|
|
4449
|
+
const record = typeof value === "object" && value !== null ? value : {};
|
|
4450
|
+
const rawItems = record["items"];
|
|
4451
|
+
if (!Array.isArray(rawItems)) throw new ImageRpcError("internal", "\u56FE\u7247\u5217\u8868\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\u3002");
|
|
4452
|
+
const items = [];
|
|
4453
|
+
for (const entry of rawItems) {
|
|
4454
|
+
const row = typeof entry === "object" && entry !== null ? entry : {};
|
|
4455
|
+
items.push({
|
|
4456
|
+
id: num(row["id"]),
|
|
4457
|
+
prompt: str(row["prompt"]),
|
|
4458
|
+
...str(row["revisedPrompt"]) === "" ? {} : { revisedPrompt: str(row["revisedPrompt"]) },
|
|
4459
|
+
model: str(row["model"]),
|
|
4460
|
+
// `size` 是网关侧唯一的新增投影(spec §5.2 末);缺失时留空串,视图渲染 `—`。
|
|
4461
|
+
size: str(row["size"]),
|
|
4462
|
+
format: str(row["format"]),
|
|
4463
|
+
mimeType: str(row["mimeType"]),
|
|
4464
|
+
byteSize: num(row["byteSize"]),
|
|
4465
|
+
generationMs: num(row["generationMs"]),
|
|
4466
|
+
createdAt: str(row["createdAt"])
|
|
4467
|
+
});
|
|
4468
|
+
}
|
|
4469
|
+
return {
|
|
4470
|
+
items,
|
|
4471
|
+
total: num(record["total"]),
|
|
4472
|
+
page: num(record["page"]) > 0 ? num(record["page"]) : fallbackPage,
|
|
4473
|
+
pageSize: num(record["pageSize"]) > 0 ? num(record["pageSize"]) : fallbackPageSize
|
|
4474
|
+
};
|
|
4475
|
+
}
|
|
4476
|
+
function normalizeImageBytes(value) {
|
|
4477
|
+
const record = typeof value === "object" && value !== null ? value : {};
|
|
4478
|
+
const dataBase64 = str(record["dataBase64"]);
|
|
4479
|
+
if (dataBase64 === "") throw new ImageRpcError("internal", "\u56FE\u7247\u6570\u636E\u4E3A\u7A7A\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
|
|
4480
|
+
return {
|
|
4481
|
+
dataBase64,
|
|
4482
|
+
mimeType: str(record["mimeType"]) === "" ? "image/png" : str(record["mimeType"]),
|
|
4483
|
+
byteSize: num(record["byteSize"])
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
var ImageGallerySource = class {
|
|
4487
|
+
constructor(rpc) {
|
|
4488
|
+
this.rpc = rpc;
|
|
4489
|
+
}
|
|
4490
|
+
/** 分页拉取历史记录(`page` 从 1 开始;`pageSize` 上限 100)。 */
|
|
4491
|
+
async list(page = 1, pageSize = IMAGE_LIST_PAGE_SIZE) {
|
|
4492
|
+
const size = Math.min(Math.max(1, Math.trunc(pageSize)), IMAGE_LIST_MAX_PAGE_SIZE);
|
|
4493
|
+
const raw = await this.rpc.call(IMAGE_CHANNEL, "list", { page: Math.max(1, Math.trunc(page)), pageSize: size });
|
|
4494
|
+
return normalizeImageListPage(unwrapImageResult(raw), page, size);
|
|
4495
|
+
}
|
|
4496
|
+
/** 取一张图的本体(**点哪张拉哪张**;超 20MiB 由 Host 回 `IMAGE_TOO_LARGE`)。 */
|
|
4497
|
+
async fetch(id) {
|
|
4498
|
+
const raw = await this.rpc.call(IMAGE_CHANNEL, "fetch", { id });
|
|
4499
|
+
return normalizeImageBytes(unwrapImageResult(raw));
|
|
4500
|
+
}
|
|
4501
|
+
/** 把一张图存到工作区(缺省落默认工作区,由 Host 决定)。 */
|
|
4502
|
+
async save(id, workspaceId) {
|
|
4503
|
+
const payload = workspaceId === void 0 || workspaceId === "" ? { id } : { id, workspaceId };
|
|
4504
|
+
const raw = await this.rpc.call(IMAGE_CHANNEL, "save", payload);
|
|
4505
|
+
return { path: str(unwrapImageResult(raw)["path"]) };
|
|
4506
|
+
}
|
|
4507
|
+
};
|
|
4508
|
+
function imageDataUrl(bytes) {
|
|
4509
|
+
const mime = bytes.mimeType === "" ? "image/png" : bytes.mimeType;
|
|
4510
|
+
return `data:${mime};base64,${bytes.dataBase64}`;
|
|
4511
|
+
}
|
|
4512
|
+
function formatImageBytes(bytes) {
|
|
4513
|
+
if (bytes === void 0 || !Number.isFinite(bytes) || bytes <= 0) return "";
|
|
4514
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
4515
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
4516
|
+
return `${bytes} B`;
|
|
4517
|
+
}
|
|
4518
|
+
function imagePromptSummary(prompt, limit = 42) {
|
|
4519
|
+
const text6 = prompt.trim().replace(/\s+/g, " ");
|
|
4520
|
+
if (text6 === "") return "\uFF08\u65E0\u63D0\u793A\u8BCD\uFF09";
|
|
4521
|
+
return text6.length <= limit ? text6 : `${text6.slice(0, limit)}\u2026`;
|
|
4522
|
+
}
|
|
4523
|
+
function imageTimeLabel(createdAt) {
|
|
4524
|
+
const date = new Date(createdAt);
|
|
4525
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
4526
|
+
return date.toLocaleString("zh-CN", { hour12: false });
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
// src/client/images-page.tsx
|
|
4530
|
+
var import_react9 = require("react");
|
|
4531
|
+
|
|
4532
|
+
// src/client/image-styles.ts
|
|
4533
|
+
var IMAGES_STYLE_ID = "hiwork-core-images-styles";
|
|
4534
|
+
var IMAGES_STYLE_TAG_ID = "hiwork-core/images.css";
|
|
4535
|
+
function ensureImagesStyle(doc) {
|
|
4536
|
+
if (doc.getElementById(IMAGES_STYLE_ID) !== null) return;
|
|
4537
|
+
const style = doc.createElement("style");
|
|
4538
|
+
style.id = IMAGES_STYLE_ID;
|
|
4539
|
+
ownStyleTag(style, IMAGES_STYLE_TAG_ID);
|
|
4540
|
+
style.textContent = [imageCardsCss, imagesPageCss].join("\n");
|
|
4541
|
+
doc.head.appendChild(style);
|
|
4542
|
+
}
|
|
4543
|
+
|
|
4544
|
+
// src/client/images-page.tsx
|
|
4545
|
+
var IMAGES_FEATURE_ID = "images";
|
|
4546
|
+
var IMAGES_FEATURE_ORDER = 60;
|
|
4547
|
+
var IMAGES_FEATURE_LABEL = "\u6211\u7684\u56FE\u7247";
|
|
4548
|
+
var IMAGES_FEATURE_EFFECT_LABEL = "hiwork-core: images feature";
|
|
4549
|
+
var IMAGES_FEATURE_ICON = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="1.6" y="2.6" width="12.8" height="10.8" rx="1.8" stroke="currentColor" stroke-width="1.2"></rect><circle cx="5.7" cy="6.3" r="1.05" fill="currentColor"></circle><path d="M2.6 11.4l3.1-2.9c.4-.4 1-.4 1.4 0l2.1 2 1.4-1.3c.4-.4 1-.4 1.4 0l1.4 1.3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"></path></svg>';
|
|
4550
|
+
var IMAGES_EMPTY_TEXT = "\u8FD8\u6CA1\u6709\u751F\u6210\u8FC7\u56FE\u7247";
|
|
4551
|
+
var IMAGES_EMPTY_HINT = "\u5728\u4F1A\u8BDD\u91CC\u8BF4\u300E\u753B\u4E00\u5F20\u2026\u300F\u5C31\u80FD\u751F\u6210";
|
|
4552
|
+
var IMAGES_LOADING_TEXT = "\u6B63\u5728\u52A0\u8F7D\u56FE\u7247\u8BB0\u5F55\u2026";
|
|
4553
|
+
var IMAGES_PREVIEW_PLACEHOLDER = "\u4ECE\u5DE6\u4FA7\u9009\u4E00\u5F20\u56FE\u7247\u67E5\u770B";
|
|
4554
|
+
var IMAGES_PREVIEW_LOADING_TEXT = "\u6B63\u5728\u52A0\u8F7D\u56FE\u7247\u2026";
|
|
4555
|
+
var IMAGES_DISABLED_NOTE = "\u7BA1\u7406\u5458\u8FD8\u6CA1\u5F00\u542F\u56FE\u7247\u751F\u6210";
|
|
4556
|
+
var IMAGES_MISSING_TEXT = "\u2014";
|
|
4557
|
+
var IMAGES_SAVE_TEXT = "\u5B58\u5230\u5DE5\u4F5C\u533A";
|
|
4558
|
+
var IMAGES_SAVE_SAVED_PREFIX = "\u5DF2\u4FDD\u5B58\u5230 ";
|
|
4559
|
+
var IMAGES_SAVE_RUNNING_TEXT = "\u6B63\u5728\u4FDD\u5B58\u2026";
|
|
4560
|
+
var IMAGES_COPY_TEXT = "\u590D\u5236\u63D0\u793A\u8BCD";
|
|
4561
|
+
var IMAGES_MORE_TEXT = "\u52A0\u8F7D\u66F4\u591A";
|
|
4562
|
+
var IMAGES_RETRY_TEXT = "\u91CD\u8BD5";
|
|
4563
|
+
var IMAGES_SAVE_HINT = "\u56FE\u7247\u4F1A\u5B58\u5230\u4F60\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u533A\uFF08~/HiWork/Default\uFF09\u7684\u300C\u56FE\u7247\u300D\u76EE\u5F55\u3002";
|
|
4564
|
+
var IMAGES_COPY_HINTS = { copied: "\u5DF2\u590D\u5236", failed: "\u590D\u5236\u5931\u8D25" };
|
|
4565
|
+
async function copyText(text6) {
|
|
4566
|
+
const clipboard = typeof navigator === "undefined" ? void 0 : navigator.clipboard;
|
|
4567
|
+
if (clipboard === void 0 || typeof clipboard.writeText !== "function") return false;
|
|
4568
|
+
try {
|
|
4569
|
+
await clipboard.writeText(text6);
|
|
4570
|
+
return true;
|
|
4571
|
+
} catch {
|
|
4572
|
+
return false;
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
function rowMeta(row) {
|
|
4576
|
+
const time = imageTimeLabel(row.createdAt);
|
|
4577
|
+
return [
|
|
4578
|
+
row.size === "" ? IMAGES_MISSING_TEXT : row.size,
|
|
4579
|
+
time === "" ? IMAGES_MISSING_TEXT : time,
|
|
4580
|
+
formatImageBytes(row.byteSize)
|
|
4581
|
+
].filter((part) => part !== "").join(" \xB7 ");
|
|
4582
|
+
}
|
|
4583
|
+
function ImagesPage({ source }) {
|
|
4584
|
+
const [rows, setRows] = (0, import_react9.useState)([]);
|
|
4585
|
+
const [total, setTotal] = (0, import_react9.useState)(0);
|
|
4586
|
+
const [page, setPage] = (0, import_react9.useState)(1);
|
|
4587
|
+
const [listState, setListState] = (0, import_react9.useState)("loading");
|
|
4588
|
+
const [listFailure, setListFailure] = (0, import_react9.useState)(null);
|
|
4589
|
+
const [selectedId, setSelectedId] = (0, import_react9.useState)(void 0);
|
|
4590
|
+
const [preview, setPreview] = (0, import_react9.useState)({ status: "idle" });
|
|
4591
|
+
const [saveState, setSaveState] = (0, import_react9.useState)({ status: "idle" });
|
|
4592
|
+
const [copyHint, setCopyHint] = (0, import_react9.useState)("");
|
|
4593
|
+
const listTicket = (0, import_react9.useRef)(0);
|
|
4594
|
+
const previewTicket = (0, import_react9.useRef)(0);
|
|
4595
|
+
const alive = (0, import_react9.useRef)(true);
|
|
4596
|
+
(0, import_react9.useEffect)(() => {
|
|
4597
|
+
if (typeof document === "undefined") return;
|
|
4598
|
+
ensureImagesStyle(document);
|
|
4599
|
+
}, []);
|
|
4600
|
+
(0, import_react9.useEffect)(() => {
|
|
4601
|
+
alive.current = true;
|
|
4602
|
+
return () => {
|
|
4603
|
+
alive.current = false;
|
|
4604
|
+
};
|
|
4605
|
+
}, []);
|
|
4606
|
+
const load = (0, import_react9.useCallback)(async (nextPage, append) => {
|
|
4607
|
+
const current = listTicket.current + 1;
|
|
4608
|
+
listTicket.current = current;
|
|
4609
|
+
setListState("loading");
|
|
4610
|
+
try {
|
|
4611
|
+
const result = await source.list(nextPage, IMAGE_LIST_PAGE_SIZE);
|
|
4612
|
+
if (!alive.current || current !== listTicket.current) return;
|
|
4613
|
+
setRows((prev) => append ? [...prev, ...result.items.filter((item) => !prev.some((existing) => existing.id === item.id))] : result.items);
|
|
4614
|
+
setTotal(result.total);
|
|
4615
|
+
setPage(result.page);
|
|
4616
|
+
setListFailure(null);
|
|
4617
|
+
setListState("ready");
|
|
4618
|
+
} catch (error) {
|
|
4619
|
+
if (!alive.current || current !== listTicket.current) return;
|
|
4620
|
+
setListFailure(imageErrorOf(error));
|
|
4621
|
+
setListState("failed");
|
|
4622
|
+
}
|
|
4623
|
+
}, [source]);
|
|
4624
|
+
(0, import_react9.useEffect)(() => {
|
|
4625
|
+
void load(1, false);
|
|
4626
|
+
}, [load]);
|
|
4627
|
+
const select = (0, import_react9.useCallback)(async (row) => {
|
|
4628
|
+
setSelectedId(row.id);
|
|
4629
|
+
setSaveState({ status: "idle" });
|
|
4630
|
+
setCopyHint("");
|
|
4631
|
+
const current = previewTicket.current + 1;
|
|
4632
|
+
previewTicket.current = current;
|
|
4633
|
+
setPreview({ status: "loading" });
|
|
4634
|
+
try {
|
|
4635
|
+
const bytes = await source.fetch(row.id);
|
|
4636
|
+
if (!alive.current || current !== previewTicket.current) return;
|
|
4637
|
+
setPreview({ status: "ready", url: imageDataUrl(bytes), byteSize: bytes.byteSize });
|
|
4638
|
+
} catch (error) {
|
|
4639
|
+
if (!alive.current || current !== previewTicket.current) return;
|
|
4640
|
+
const failure = imageErrorOf(error);
|
|
4641
|
+
setPreview({ status: "failed", code: failure.code, message: failure.message });
|
|
4642
|
+
}
|
|
4643
|
+
}, [source]);
|
|
4644
|
+
const save = (0, import_react9.useCallback)(async () => {
|
|
4645
|
+
if (selectedId === void 0) return;
|
|
4646
|
+
setSaveState({ status: "saving" });
|
|
4647
|
+
try {
|
|
4648
|
+
const { path } = await source.save(selectedId);
|
|
4649
|
+
if (!alive.current) return;
|
|
4650
|
+
setSaveState({ status: "saved", path });
|
|
4651
|
+
} catch (error) {
|
|
4652
|
+
if (!alive.current) return;
|
|
4653
|
+
setSaveState({ status: "failed", message: imageErrorOf(error).message });
|
|
4654
|
+
}
|
|
4655
|
+
}, [source, selectedId]);
|
|
4656
|
+
const selected = rows.find((row) => row.id === selectedId);
|
|
4657
|
+
const disabled = listFailure?.code === "IMAGE_DISABLED" || preview.status === "failed" && preview.code === "IMAGE_DISABLED";
|
|
4658
|
+
const previewBody = (() => {
|
|
4659
|
+
if (preview.status === "idle") {
|
|
4660
|
+
return (0, import_react9.createElement)("p", { className: "hiwork-images-note", "data-hiwork-images-placeholder": "" }, IMAGES_PREVIEW_PLACEHOLDER);
|
|
4661
|
+
}
|
|
4662
|
+
if (preview.status === "loading") {
|
|
4663
|
+
return (0, import_react9.createElement)("p", { className: "hiwork-images-note", "data-hiwork-images-loading": "" }, IMAGES_PREVIEW_LOADING_TEXT);
|
|
4664
|
+
}
|
|
4665
|
+
if (preview.status === "failed") {
|
|
4666
|
+
return (0, import_react9.createElement)(
|
|
4667
|
+
"div",
|
|
4668
|
+
{ className: "hiwork-images-actions", "data-hiwork-images-preview-error": preview.code },
|
|
4669
|
+
(0, import_react9.createElement)("span", { className: "hiwork-images-error" }, preview.message),
|
|
4670
|
+
selected === void 0 ? null : (0, import_react9.createElement)(
|
|
4671
|
+
"button",
|
|
4672
|
+
{ type: "button", className: "hiwork-images-action", "data-hiwork-images-retry-preview": "", onClick: () => {
|
|
4673
|
+
void select(selected);
|
|
4674
|
+
} },
|
|
4675
|
+
IMAGES_RETRY_TEXT
|
|
4676
|
+
)
|
|
4677
|
+
);
|
|
4678
|
+
}
|
|
4679
|
+
return (0, import_react9.createElement)(
|
|
4680
|
+
"div",
|
|
4681
|
+
{ className: "hiwork-images-preview-body" },
|
|
4682
|
+
// 字节来自本次 fetch:data URL 渲染,**不写盘、不指向任何本地文件**。
|
|
4683
|
+
(0, import_react9.createElement)("img", {
|
|
4684
|
+
className: "hiwork-images-image",
|
|
4685
|
+
src: preview.url,
|
|
4686
|
+
alt: selected === void 0 || selected.prompt.trim() === "" ? "\u5386\u53F2\u56FE\u7247" : selected.prompt.trim(),
|
|
4687
|
+
"data-hiwork-images-image": ""
|
|
4688
|
+
}),
|
|
4689
|
+
selected === void 0 ? null : (0, import_react9.createElement)("p", { className: "hiwork-images-preview-prompt", "data-hiwork-images-prompt": "" }, selected.prompt),
|
|
4690
|
+
selected === void 0 ? null : (0, import_react9.createElement)("p", { className: "hiwork-images-note", "data-hiwork-images-preview-meta": "" }, [
|
|
4691
|
+
rowMeta(selected),
|
|
4692
|
+
formatImageBytes(preview.byteSize)
|
|
4693
|
+
].filter((part) => part !== "").join(" \xB7 ")),
|
|
4694
|
+
(0, import_react9.createElement)(
|
|
4695
|
+
"div",
|
|
4696
|
+
{ className: "hiwork-images-actions" },
|
|
4697
|
+
(0, import_react9.createElement)(
|
|
4698
|
+
"button",
|
|
4699
|
+
{
|
|
4700
|
+
type: "button",
|
|
4701
|
+
className: "hiwork-images-action",
|
|
4702
|
+
"data-hiwork-images-save": "",
|
|
4703
|
+
disabled: saveState.status === "saving",
|
|
4704
|
+
onClick: () => {
|
|
4705
|
+
void save();
|
|
4706
|
+
}
|
|
4707
|
+
},
|
|
4708
|
+
saveState.status === "saving" ? IMAGES_SAVE_RUNNING_TEXT : IMAGES_SAVE_TEXT
|
|
4709
|
+
),
|
|
4710
|
+
(0, import_react9.createElement)(
|
|
4711
|
+
"button",
|
|
4712
|
+
{
|
|
4713
|
+
type: "button",
|
|
4714
|
+
className: "hiwork-images-action",
|
|
4715
|
+
"data-hiwork-images-copy": "",
|
|
4716
|
+
onClick: () => {
|
|
4717
|
+
void copyText(selected?.prompt ?? "").then((ok) => {
|
|
4718
|
+
setCopyHint(ok ? IMAGES_COPY_HINTS.copied : IMAGES_COPY_HINTS.failed);
|
|
4719
|
+
});
|
|
4720
|
+
}
|
|
4721
|
+
},
|
|
4722
|
+
IMAGES_COPY_TEXT
|
|
4723
|
+
),
|
|
4724
|
+
copyHint === "" ? null : (0, import_react9.createElement)("span", { className: "hiwork-images-note", "data-hiwork-images-copy-state": copyHint }, copyHint)
|
|
4725
|
+
),
|
|
4726
|
+
saveState.status === "saved" ? (0, import_react9.createElement)("span", { className: "hiwork-images-saved", "data-hiwork-images-saved": "" }, `${IMAGES_SAVE_SAVED_PREFIX}${saveState.path}`) : null,
|
|
4727
|
+
saveState.status === "failed" ? (0, import_react9.createElement)("span", { className: "hiwork-images-error", "data-hiwork-images-save-error": "" }, saveState.message) : null,
|
|
4728
|
+
(0, import_react9.createElement)("p", { className: "hiwork-images-note" }, IMAGES_SAVE_HINT)
|
|
4729
|
+
);
|
|
4730
|
+
})();
|
|
4731
|
+
const empty = listState === "ready" && rows.length === 0;
|
|
4732
|
+
return (0, import_react9.createElement)(
|
|
4733
|
+
"section",
|
|
4734
|
+
{ className: "hiwork-images", "data-hiwork-images": "", "data-hiwork-images-state": listState },
|
|
4735
|
+
(0, import_react9.createElement)(
|
|
4736
|
+
"div",
|
|
4737
|
+
{ className: "hiwork-images-head" },
|
|
4738
|
+
(0, import_react9.createElement)("h2", { className: "hiwork-images-title" }, IMAGES_FEATURE_LABEL),
|
|
4739
|
+
(0, import_react9.createElement)(
|
|
4740
|
+
"span",
|
|
4741
|
+
{ className: "hiwork-images-count", "data-hiwork-images-count": "" },
|
|
4742
|
+
listState === "loading" && rows.length === 0 ? IMAGES_LOADING_TEXT : `\u5171 ${total} \u5F20`
|
|
4743
|
+
)
|
|
4744
|
+
),
|
|
4745
|
+
// 关开关只关「生成」不关「查看」:历史照常可见,但要说清当前不能再生成(spec §7.2 V11)。
|
|
4746
|
+
disabled ? (0, import_react9.createElement)("div", { className: "hiwork-images-banner", "data-hiwork-images-disabled": "" }, IMAGES_DISABLED_NOTE) : null,
|
|
4747
|
+
// 列表级失败:行内红字 + 重试(成功过一页的话**保留已有行**,不清空)。
|
|
4748
|
+
listFailure === null ? null : (0, import_react9.createElement)(
|
|
4749
|
+
"div",
|
|
4750
|
+
{ className: "hiwork-images-actions", "data-hiwork-images-error": listFailure.code },
|
|
4751
|
+
(0, import_react9.createElement)("span", { className: "hiwork-images-error" }, listFailure.message),
|
|
4752
|
+
(0, import_react9.createElement)(
|
|
4753
|
+
"button",
|
|
4754
|
+
{ type: "button", className: "hiwork-images-action", "data-hiwork-images-retry": "", onClick: () => {
|
|
4755
|
+
void load(page, rows.length > 0);
|
|
4756
|
+
} },
|
|
4757
|
+
IMAGES_RETRY_TEXT
|
|
4758
|
+
)
|
|
4759
|
+
),
|
|
4760
|
+
empty ? (0, import_react9.createElement)(
|
|
4761
|
+
"div",
|
|
4762
|
+
{ className: "hiwork-images-empty", "data-hiwork-images-empty": "" },
|
|
4763
|
+
(0, import_react9.createElement)("p", { className: "hiwork-images-empty-title" }, IMAGES_EMPTY_TEXT),
|
|
4764
|
+
(0, import_react9.createElement)("p", { className: "hiwork-images-note" }, IMAGES_EMPTY_HINT)
|
|
4765
|
+
) : (0, import_react9.createElement)(
|
|
4766
|
+
"div",
|
|
4767
|
+
{ className: "hiwork-images-body" },
|
|
4768
|
+
(0, import_react9.createElement)(
|
|
4769
|
+
"ul",
|
|
4770
|
+
{ className: "hiwork-images-list", "data-hiwork-images-list": "" },
|
|
4771
|
+
...rows.map((row) => (0, import_react9.createElement)(
|
|
4772
|
+
"li",
|
|
4773
|
+
{ key: row.id },
|
|
4774
|
+
(0, import_react9.createElement)(
|
|
4775
|
+
"button",
|
|
4776
|
+
{
|
|
4777
|
+
type: "button",
|
|
4778
|
+
className: "hiwork-images-row",
|
|
4779
|
+
"data-hiwork-images-row": row.id,
|
|
4780
|
+
"aria-pressed": row.id === selectedId,
|
|
4781
|
+
onClick: () => {
|
|
4782
|
+
void select(row);
|
|
4783
|
+
}
|
|
4784
|
+
},
|
|
4785
|
+
(0, import_react9.createElement)("span", { className: "hiwork-images-row-prompt" }, imagePromptSummary(row.prompt)),
|
|
4786
|
+
(0, import_react9.createElement)("span", { className: "hiwork-images-row-meta", "data-hiwork-images-row-meta": "" }, rowMeta(row))
|
|
4787
|
+
)
|
|
4788
|
+
))
|
|
4789
|
+
),
|
|
4790
|
+
(0, import_react9.createElement)("div", { className: "hiwork-images-preview", "data-hiwork-images-preview": "" }, previewBody)
|
|
4791
|
+
),
|
|
4792
|
+
rows.length > 0 && rows.length < total ? (0, import_react9.createElement)(
|
|
4793
|
+
"button",
|
|
4794
|
+
{
|
|
4795
|
+
type: "button",
|
|
4796
|
+
className: "hiwork-images-more",
|
|
4797
|
+
"data-hiwork-images-more": "",
|
|
4798
|
+
disabled: listState === "loading",
|
|
4799
|
+
onClick: () => {
|
|
4800
|
+
void load(page + 1, true);
|
|
4801
|
+
}
|
|
4802
|
+
},
|
|
4803
|
+
IMAGES_MORE_TEXT
|
|
4804
|
+
) : null
|
|
4805
|
+
);
|
|
4806
|
+
}
|
|
4807
|
+
function imagesFeature(source) {
|
|
4808
|
+
return {
|
|
4809
|
+
id: IMAGES_FEATURE_ID,
|
|
4810
|
+
order: IMAGES_FEATURE_ORDER,
|
|
4811
|
+
label: () => IMAGES_FEATURE_LABEL,
|
|
4812
|
+
icon: IMAGES_FEATURE_ICON,
|
|
4813
|
+
render: () => (0, import_react9.createElement)(ImagesPage, { source })
|
|
4814
|
+
};
|
|
4815
|
+
}
|
|
4816
|
+
function installImagesFeature(scope, registry, source) {
|
|
4817
|
+
scope.effect(() => registry.register(imagesFeature(source)), IMAGES_FEATURE_EFFECT_LABEL);
|
|
4818
|
+
}
|
|
4819
|
+
|
|
4820
|
+
// src/client/image-cards.tsx
|
|
4821
|
+
var import_react10 = require("react");
|
|
4822
|
+
var IMAGE_GENERATE_TOOL_NAME = "image_generate";
|
|
4823
|
+
var TOOL_VIEW_SLOT = "tool.call.toolview";
|
|
4824
|
+
var IMAGE_CARD_TITLE = "\u751F\u6210\u56FE\u7247";
|
|
4825
|
+
var IMAGE_CARD_GENERIC_ERROR = "\u56FE\u7247\u751F\u6210\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
|
|
4826
|
+
var IMAGE_ERROR_TEXT = {
|
|
4827
|
+
IMAGE_DISABLED: "\u7BA1\u7406\u5458\u8FD8\u6CA1\u5F00\u542F\u56FE\u7247\u751F\u6210",
|
|
4828
|
+
IMAGE_NOT_CONFIGURED: "\u56FE\u7247\u751F\u6210\u8FD8\u6CA1\u6709\u914D\u7F6E\u597D\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458",
|
|
4829
|
+
IMAGE_BUDGET_EXCEEDED: "\u751F\u56FE\u6682\u65F6\u4E0D\u53EF\u7528\uFF1A\u53EF\u80FD\u662F\u672C\u6708\u989D\u5EA6\u7528\u5C3D\uFF0C\u4E5F\u53EF\u80FD\u662F\u8FD9\u4E2A\u6A21\u578B\u8FD8\u6CA1\u914D\u7F6E\u597D\u2014\u2014\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458",
|
|
4830
|
+
IMAGE_BAD_REQUEST: "\u8FD9\u4E2A\u63D0\u793A\u8BCD\u6CA1\u80FD\u751F\u6210\uFF0C\u6362\u4E2A\u8BF4\u6CD5\u518D\u8BD5",
|
|
4831
|
+
IMAGE_TOO_LARGE: "\u751F\u6210\u7684\u56FE\u7247\u592A\u5927\u4E86\uFF0C\u6362\u4E2A\u5C0F\u4E00\u70B9\u7684\u5C3A\u5BF8\uFF08\u5982 1024x1024\uFF09",
|
|
4832
|
+
IMAGE_TIMEOUT: "\u751F\u6210\u8D85\u65F6\u4E86\uFF0C\u518D\u8BD5\u4E00\u6B21\uFF08\u590D\u6742\u753B\u9762\u4F1A\u6BD4\u8F83\u6162\uFF09",
|
|
4833
|
+
IMAGE_UPSTREAM_ERROR: "\u56FE\u7247\u751F\u6210\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
|
|
4834
|
+
GATEWAY_UNREACHABLE: "\u56FE\u7247\u751F\u6210\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
|
|
4835
|
+
// spec §6.6 把 SESSION_EXPIRED 并入「服务不可用」那一行(**逐字同该行**),只在括号里
|
|
4836
|
+
// 注明例外「提示重新登录」——所以不加自创文案,另给一句 {@link IMAGE_RELOGIN_HINT}。
|
|
4837
|
+
SESSION_EXPIRED: "\u56FE\u7247\u751F\u6210\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
|
|
4838
|
+
// Host 侧写盘失败(src/imagegen.ts 的两种原因):图已经生成、也已经计费,绝不能让
|
|
4839
|
+
// 员工以为白花了钱——文案必须说清「图在,只是没落到工作区」。
|
|
4840
|
+
"write-failed": "\u56FE\u7247\u5DF2\u751F\u6210\u4F46\u6CA1\u80FD\u4FDD\u5B58\u5230\u5DE5\u4F5C\u533A",
|
|
4841
|
+
"path-outside-workspace": "\u56FE\u7247\u6CA1\u80FD\u4FDD\u5B58\u5230\u5DE5\u4F5C\u533A\uFF1A\u76EE\u6807\u8DEF\u5F84\u4E0D\u5728\u5DE5\u4F5C\u533A\u91CC",
|
|
4842
|
+
cancelled: "\u5DF2\u53D6\u6D88",
|
|
4843
|
+
// 平台级中断码(`interrupted` 是 shell 自己的停止标记,不是网关错误码)。
|
|
4844
|
+
interrupted: "\u5DF2\u505C\u6B62"
|
|
4845
|
+
};
|
|
4846
|
+
var IMAGE_RETRYABLE_CODES = [
|
|
4847
|
+
"IMAGE_BAD_REQUEST",
|
|
4848
|
+
"IMAGE_TOO_LARGE",
|
|
4849
|
+
"IMAGE_TIMEOUT",
|
|
4850
|
+
"IMAGE_UPSTREAM_ERROR",
|
|
4851
|
+
"GATEWAY_UNREACHABLE"
|
|
4852
|
+
];
|
|
4853
|
+
var IMAGE_RELOGIN_CODES = ["SESSION_EXPIRED"];
|
|
4854
|
+
var IMAGE_RELOGIN_HINT = "\u8BF7\u91CD\u65B0\u767B\u5F55";
|
|
4855
|
+
function needsRelogin(code) {
|
|
4856
|
+
return IMAGE_RELOGIN_CODES.includes(code);
|
|
4857
|
+
}
|
|
4858
|
+
function imageErrorText(code, message = "") {
|
|
4859
|
+
const known = IMAGE_ERROR_TEXT[code];
|
|
4860
|
+
if (known !== void 0) return known;
|
|
4861
|
+
return message.trim() === "" ? IMAGE_CARD_GENERIC_ERROR : message;
|
|
4862
|
+
}
|
|
4863
|
+
function isRetryableImageError(code) {
|
|
4864
|
+
return IMAGE_RETRYABLE_CODES.includes(code);
|
|
4865
|
+
}
|
|
4866
|
+
function asRecord(value) {
|
|
4867
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
4868
|
+
}
|
|
4869
|
+
function str2(value) {
|
|
4870
|
+
return typeof value === "string" ? value : "";
|
|
4871
|
+
}
|
|
4872
|
+
function num2(value) {
|
|
4873
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4874
|
+
}
|
|
4875
|
+
function parseImageArgs(argsRaw) {
|
|
4876
|
+
if (typeof argsRaw !== "string" || argsRaw.trim() === "") return {};
|
|
4877
|
+
try {
|
|
4878
|
+
return asRecord(JSON.parse(argsRaw));
|
|
4879
|
+
} catch {
|
|
4880
|
+
return {};
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4883
|
+
function parseImageOutcome(content) {
|
|
4884
|
+
if (!Array.isArray(content)) return null;
|
|
4885
|
+
for (const block of content) {
|
|
4886
|
+
const text6 = typeof block?.text === "string" ? block.text : "";
|
|
4887
|
+
if (text6 === "") continue;
|
|
4888
|
+
const trimmed = text6.trim();
|
|
4889
|
+
if (!trimmed.startsWith("{")) continue;
|
|
4890
|
+
let parsed;
|
|
4891
|
+
try {
|
|
4892
|
+
parsed = JSON.parse(trimmed);
|
|
4893
|
+
} catch {
|
|
4894
|
+
continue;
|
|
4895
|
+
}
|
|
4896
|
+
const record = asRecord(parsed);
|
|
4897
|
+
if (typeof record["ok"] !== "boolean") continue;
|
|
4898
|
+
return record;
|
|
4899
|
+
}
|
|
4900
|
+
return null;
|
|
4901
|
+
}
|
|
4902
|
+
function parseImagePathsFromText(content) {
|
|
4903
|
+
if (!Array.isArray(content)) return [];
|
|
4904
|
+
const paths = [];
|
|
4905
|
+
for (const block of content) {
|
|
4906
|
+
const text6 = typeof block?.text === "string" ? block.text : "";
|
|
4907
|
+
for (const match of text6.matchAll(/<path>([^<>]+)<\/path>/g)) {
|
|
4908
|
+
const path = (match[1] ?? "").trim();
|
|
4909
|
+
if (path !== "" && !paths.includes(path)) paths.push(path);
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
return paths;
|
|
4913
|
+
}
|
|
4914
|
+
function isAbsoluteImagePath(path) {
|
|
4915
|
+
return path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path);
|
|
4916
|
+
}
|
|
4917
|
+
function imageFileUrl(path, baseURI) {
|
|
4918
|
+
if (!isAbsoluteImagePath(path)) return "";
|
|
4919
|
+
return new URL(`api/file?path=${encodeURIComponent(path)}`, baseURI).href;
|
|
4920
|
+
}
|
|
4921
|
+
function abbreviateHome(path, home) {
|
|
4922
|
+
if (home === void 0 || home === "") return path;
|
|
4923
|
+
const trimmed = home.replace(/[\\/]+$/, "");
|
|
4924
|
+
if (trimmed === "") return path;
|
|
4925
|
+
if (path === trimmed) return "~";
|
|
4926
|
+
if (path.startsWith(`${trimmed}/`) || path.startsWith(`${trimmed}\\`)) return `~${path.slice(trimmed.length)}`;
|
|
4927
|
+
return path;
|
|
4928
|
+
}
|
|
4929
|
+
function formatGenerationMs(ms) {
|
|
4930
|
+
if (ms === void 0 || ms < 0) return "";
|
|
4931
|
+
if (ms < 1e3) return `${ms} \u6BEB\u79D2`;
|
|
4932
|
+
return `${(ms / 1e3).toFixed(1)} \u79D2`;
|
|
4933
|
+
}
|
|
4934
|
+
function formatByteSize(bytes) {
|
|
4935
|
+
if (bytes === void 0 || bytes < 0) return "";
|
|
4936
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
4937
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
4938
|
+
return `${bytes} B`;
|
|
4939
|
+
}
|
|
4940
|
+
function toImageCardModel(block, baseURI) {
|
|
4941
|
+
const settled = block?.kind === "tool-result" || block?.phase === "result";
|
|
4942
|
+
const errorRecord = asRecord(block?.error);
|
|
4943
|
+
const errorCode = str2(errorRecord["code"]);
|
|
4944
|
+
const state = settled ? errorCode === "interrupted" ? "stopped" : block?.isError === true ? "error" : "ok" : "running";
|
|
4945
|
+
const args = parseImageArgs(settled ? block?.call?.argsRaw : block?.argsRaw);
|
|
4946
|
+
const outcome = settled ? parseImageOutcome(block?.content) : null;
|
|
4947
|
+
const prompt = str2(outcome?.["prompt"]) || str2(args["prompt"]);
|
|
4948
|
+
const size = str2(outcome?.["size"]) || str2(args["size"]);
|
|
4949
|
+
const model = str2(outcome?.["model"]);
|
|
4950
|
+
const generationMs = num2(outcome?.["generationMs"]);
|
|
4951
|
+
const alt = prompt.trim() === "" ? "\u751F\u6210\u7684\u56FE\u7247" : prompt.trim();
|
|
4952
|
+
const outcomeFailed = outcome !== null && outcome["ok"] === false;
|
|
4953
|
+
const transportFailed = !outcomeFailed && (state === "error" || state === "stopped");
|
|
4954
|
+
const rawFailureCode = outcomeFailed ? str2(outcome["code"]) : errorCode;
|
|
4955
|
+
const failureCode = rawFailureCode === "" && transportFailed ? "IMAGE_UPSTREAM_ERROR" : rawFailureCode;
|
|
4956
|
+
const failure = outcomeFailed ? imageErrorText(failureCode, str2(outcome["message"])) : transportFailed ? imageErrorText(failureCode, str2(errorRecord["reason"]) || str2(errorRecord["name"])) : null;
|
|
4957
|
+
const files = [];
|
|
4958
|
+
if (settled && failure === null) {
|
|
4959
|
+
const rawFiles = Array.isArray(outcome?.["files"]) ? outcome["files"] : void 0;
|
|
4960
|
+
if (rawFiles !== void 0) {
|
|
4961
|
+
for (const entry of rawFiles) {
|
|
4962
|
+
const record = asRecord(entry);
|
|
4963
|
+
const path = str2(record["path"]);
|
|
4964
|
+
const url = imageFileUrl(path, baseURI);
|
|
4965
|
+
if (url === "") continue;
|
|
4966
|
+
files.push({
|
|
4967
|
+
path,
|
|
4968
|
+
url,
|
|
4969
|
+
alt,
|
|
4970
|
+
byteSize: num2(record["byteSize"]),
|
|
4971
|
+
mimeType: str2(record["mimeType"]),
|
|
4972
|
+
revisedPrompt: str2(record["revisedPrompt"]) === "" ? void 0 : str2(record["revisedPrompt"])
|
|
4973
|
+
});
|
|
4974
|
+
}
|
|
4975
|
+
} else {
|
|
4976
|
+
for (const path of parseImagePathsFromText(block?.content)) {
|
|
4977
|
+
const url = imageFileUrl(path, baseURI);
|
|
4978
|
+
if (url !== "") {
|
|
4979
|
+
files.push({ path, url, alt, byteSize: void 0, mimeType: "", revisedPrompt: void 0 });
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
}
|
|
4984
|
+
return {
|
|
4985
|
+
state,
|
|
4986
|
+
prompt,
|
|
4987
|
+
size,
|
|
4988
|
+
model,
|
|
4989
|
+
generationMs,
|
|
4990
|
+
files,
|
|
4991
|
+
error: failure,
|
|
4992
|
+
errorCode: failureCode,
|
|
4993
|
+
retryable: failure !== null && isRetryableImageError(failureCode)
|
|
4994
|
+
};
|
|
4995
|
+
}
|
|
4996
|
+
var COPY_HINTS2 = { idle: "", copied: "\u5DF2\u590D\u5236", failed: "\u590D\u5236\u5931\u8D25" };
|
|
4997
|
+
async function copyPromptText(text6) {
|
|
4998
|
+
const clipboard = typeof navigator === "undefined" ? void 0 : navigator.clipboard;
|
|
4999
|
+
if (clipboard === void 0 || typeof clipboard.writeText !== "function") return false;
|
|
5000
|
+
try {
|
|
5001
|
+
await clipboard.writeText(text6);
|
|
5002
|
+
return true;
|
|
5003
|
+
} catch {
|
|
5004
|
+
return false;
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
var COPY_HINT_REVERT_MS2 = 1800;
|
|
5008
|
+
function currentBaseURI() {
|
|
5009
|
+
return typeof document === "undefined" ? "" : document.baseURI;
|
|
5010
|
+
}
|
|
5011
|
+
function ImageToolCard(props) {
|
|
5012
|
+
const { block, toolName = IMAGE_GENERATE_TOOL_NAME, home, openFile, inspect } = props;
|
|
5013
|
+
const model = toImageCardModel(block, currentBaseURI());
|
|
5014
|
+
const [zoom, setZoom] = (0, import_react10.useState)(null);
|
|
5015
|
+
const [copyHint, setCopyHint] = (0, import_react10.useState)(COPY_HINTS2.idle);
|
|
5016
|
+
const revertTimer = (0, import_react10.useRef)(void 0);
|
|
5017
|
+
(0, import_react10.useEffect)(() => {
|
|
5018
|
+
if (typeof document === "undefined") return;
|
|
5019
|
+
ensureImagesStyle(document);
|
|
5020
|
+
}, []);
|
|
5021
|
+
(0, import_react10.useEffect)(() => () => {
|
|
5022
|
+
if (revertTimer.current !== void 0) clearTimeout(revertTimer.current);
|
|
5023
|
+
}, []);
|
|
5024
|
+
const copy = (0, import_react10.useCallback)(() => {
|
|
5025
|
+
void copyPromptText(model.prompt).then((ok) => {
|
|
5026
|
+
setCopyHint(ok ? COPY_HINTS2.copied : COPY_HINTS2.failed);
|
|
5027
|
+
if (revertTimer.current !== void 0) clearTimeout(revertTimer.current);
|
|
5028
|
+
revertTimer.current = setTimeout(() => {
|
|
5029
|
+
setCopyHint(COPY_HINTS2.idle);
|
|
5030
|
+
}, COPY_HINT_REVERT_MS2);
|
|
5031
|
+
});
|
|
5032
|
+
}, [model.prompt]);
|
|
5033
|
+
const summary = () => {
|
|
5034
|
+
if (model.state === "running") return "\u6B63\u5728\u751F\u6210\u56FE\u7247\u2026";
|
|
5035
|
+
if (model.error !== null && model.files.length === 0) return "\u5931\u8D25";
|
|
5036
|
+
const count = model.files.length === 0 ? "" : `\u5DF2\u751F\u6210 ${model.files.length} \u5F20`;
|
|
5037
|
+
const elapsed = formatGenerationMs(model.generationMs);
|
|
5038
|
+
return [count, elapsed].filter((part) => part !== "").join(" \xB7 ");
|
|
5039
|
+
};
|
|
5040
|
+
const meta = () => {
|
|
5041
|
+
const parts = [model.size, formatGenerationMs(model.generationMs), model.model].filter((part) => part !== "");
|
|
5042
|
+
return parts.join(" \xB7 ");
|
|
5043
|
+
};
|
|
5044
|
+
return (0, import_react10.createElement)(
|
|
5045
|
+
"div",
|
|
5046
|
+
{
|
|
5047
|
+
className: "hiwork-image-card",
|
|
5048
|
+
"data-hiwork-image-card": toolName,
|
|
5049
|
+
"data-state": model.state
|
|
5050
|
+
},
|
|
5051
|
+
(0, import_react10.createElement)(
|
|
5052
|
+
"div",
|
|
5053
|
+
{ className: "hiwork-image-card-head" },
|
|
5054
|
+
(0, import_react10.createElement)("span", { className: "hiwork-image-card-title" }, IMAGE_CARD_TITLE),
|
|
5055
|
+
(0, import_react10.createElement)("span", { className: "hiwork-image-card-summary" }, summary())
|
|
5056
|
+
),
|
|
5057
|
+
// 提示词:running 阶段(start)就要显示——那是用户唯一的「它在按我说的画」凭据。
|
|
5058
|
+
model.prompt === "" ? null : (0, import_react10.createElement)("p", { className: "hiwork-image-card-prompt", "data-hiwork-image-prompt": "" }, model.prompt),
|
|
5059
|
+
...model.files.map((file) => (0, import_react10.createElement)(
|
|
5060
|
+
"figure",
|
|
5061
|
+
{ key: file.path, className: "hiwork-image-card-figure" },
|
|
5062
|
+
(0, import_react10.createElement)("img", {
|
|
5063
|
+
className: "hiwork-image-card-img",
|
|
5064
|
+
// 只画绝对路径(相对路径与远端 URL 保持惰性,与平台同规则):地址为空时不渲染本块。
|
|
5065
|
+
src: file.url,
|
|
5066
|
+
alt: file.alt,
|
|
5067
|
+
title: file.alt,
|
|
5068
|
+
"data-hiwork-image-file": file.path,
|
|
5069
|
+
onClick: () => {
|
|
5070
|
+
setZoom(file);
|
|
5071
|
+
}
|
|
5072
|
+
}),
|
|
5073
|
+
(0, import_react10.createElement)(
|
|
5074
|
+
"figcaption",
|
|
5075
|
+
{ className: "hiwork-image-card-actions" },
|
|
5076
|
+
(0, import_react10.createElement)("span", { className: "hiwork-image-card-path", title: file.path, "data-hiwork-image-path": "" }, abbreviateHome(file.path, home)),
|
|
5077
|
+
meta() === "" ? null : (0, import_react10.createElement)("span", { className: "hiwork-image-card-meta", "data-hiwork-image-meta": "" }, [meta(), formatByteSize(file.byteSize)].filter((part) => part !== "").join(" \xB7 ")),
|
|
5078
|
+
// 可选能力:宿主没给 openFile 就不渲染按钮(渲染一个点了没反应的控件更差)。
|
|
5079
|
+
typeof openFile === "function" ? (0, import_react10.createElement)(
|
|
5080
|
+
"button",
|
|
5081
|
+
{
|
|
5082
|
+
type: "button",
|
|
5083
|
+
className: "hiwork-image-card-action",
|
|
5084
|
+
"data-hiwork-image-open": file.path,
|
|
5085
|
+
onClick: () => {
|
|
5086
|
+
openFile(file.path);
|
|
5087
|
+
}
|
|
5088
|
+
},
|
|
5089
|
+
"\u6253\u5F00"
|
|
5090
|
+
) : null
|
|
5091
|
+
)
|
|
5092
|
+
)),
|
|
5093
|
+
// 卡片级动作:复制提示词(提示词是卡片级信息,每张图复制一次即可)。
|
|
5094
|
+
model.prompt === "" ? null : (0, import_react10.createElement)(
|
|
5095
|
+
"div",
|
|
5096
|
+
{ className: "hiwork-image-card-actions" },
|
|
5097
|
+
(0, import_react10.createElement)(
|
|
5098
|
+
"button",
|
|
5099
|
+
{ type: "button", className: "hiwork-image-card-action", "data-hiwork-image-copy": "", onClick: copy },
|
|
5100
|
+
"\u590D\u5236\u63D0\u793A\u8BCD"
|
|
5101
|
+
),
|
|
5102
|
+
copyHint === "" ? null : (0, import_react10.createElement)("span", { className: "hiwork-image-card-copy-state", "data-hiwork-image-copy-state": copyHint }, copyHint),
|
|
5103
|
+
inspect === void 0 ? null : (0, import_react10.createElement)(
|
|
5104
|
+
"button",
|
|
5105
|
+
{ type: "button", className: "hiwork-image-card-action", "data-hiwork-image-inspect": "", onClick: inspect },
|
|
5106
|
+
"\u67E5\u770B\u8F68\u8FF9"
|
|
5107
|
+
)
|
|
5108
|
+
),
|
|
5109
|
+
model.error === null ? null : (0, import_react10.createElement)(
|
|
5110
|
+
"p",
|
|
5111
|
+
{ className: "hiwork-image-card-error", role: "alert", "data-hiwork-image-error": model.errorCode },
|
|
5112
|
+
model.error,
|
|
5113
|
+
model.retryable ? (0, import_react10.createElement)("span", { className: "hiwork-image-card-retry-hint", "data-hiwork-image-retry-hint": "" }, "\u53EF\u4EE5\u518D\u8BD5\u4E00\u6B21") : null,
|
|
5114
|
+
needsRelogin(model.errorCode) ? (0, import_react10.createElement)("span", { className: "hiwork-image-card-retry-hint", "data-hiwork-image-relogin-hint": "" }, IMAGE_RELOGIN_HINT) : null
|
|
5115
|
+
),
|
|
5116
|
+
zoom === null ? null : (0, import_react10.createElement)(
|
|
5117
|
+
"div",
|
|
5118
|
+
{
|
|
5119
|
+
className: "hiwork-image-zoom",
|
|
5120
|
+
role: "dialog",
|
|
5121
|
+
"aria-label": zoom.alt,
|
|
5122
|
+
"data-hiwork-image-zoom": "",
|
|
5123
|
+
onClick: () => {
|
|
5124
|
+
setZoom(null);
|
|
5125
|
+
}
|
|
5126
|
+
},
|
|
5127
|
+
(0, import_react10.createElement)("img", { src: zoom.url, alt: zoom.alt }),
|
|
5128
|
+
(0, import_react10.createElement)(
|
|
5129
|
+
"button",
|
|
5130
|
+
{
|
|
5131
|
+
type: "button",
|
|
5132
|
+
className: "hiwork-image-zoom-close",
|
|
5133
|
+
"data-hiwork-image-zoom-close": "",
|
|
5134
|
+
onClick: () => {
|
|
5135
|
+
setZoom(null);
|
|
5136
|
+
}
|
|
5137
|
+
},
|
|
5138
|
+
"\u5173\u95ED"
|
|
5139
|
+
)
|
|
5140
|
+
)
|
|
5141
|
+
);
|
|
5142
|
+
}
|
|
5143
|
+
function installImageToolCard(ctx) {
|
|
5144
|
+
const slots = ctx.slots;
|
|
5145
|
+
if (slots === void 0 || typeof slots.inject !== "function") return;
|
|
5146
|
+
slots.inject(TOOL_VIEW_SLOT, () => slots.register(
|
|
5147
|
+
{ name: TOOL_VIEW_SLOT, key: IMAGE_GENERATE_TOOL_NAME },
|
|
5148
|
+
ImageToolCard
|
|
5149
|
+
));
|
|
5150
|
+
}
|
|
5151
|
+
|
|
5152
|
+
// src/client/session-cost.tsx
|
|
5153
|
+
var import_react11 = require("react");
|
|
5154
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5155
|
+
var SESSION_COST_ENDPOINT = "estimate";
|
|
5156
|
+
var SESSION_COST_CACHE_TTL_MS = 5 * 6e4;
|
|
5157
|
+
var SESSION_COST_HINT = "\u6309\u7F51\u5173\u4EF7\u683C\u4F30\u7B97\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF1B\u4EE5\u300C\u7528\u91CF\u4E0E\u6210\u672C\u300D\u4E2D\u7684\u6743\u5A01\u8D26\u5355\u4E3A\u51C6";
|
|
5158
|
+
var SESSION_COST_ESTIMATED_SUFFIX = "\uFF08\u4F30\u7B97\uFF09";
|
|
5159
|
+
function nonNegativeInteger(value) {
|
|
5160
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
5161
|
+
}
|
|
5162
|
+
function sessionCostMatchOf(data) {
|
|
5163
|
+
if (typeof data !== "object" || data === null) return null;
|
|
5164
|
+
const turn = nonNegativeInteger(data.turn);
|
|
5165
|
+
if (turn === void 0) return null;
|
|
5166
|
+
const usage = data.tokenUsage;
|
|
5167
|
+
if (typeof usage !== "object" || usage === null) return null;
|
|
5168
|
+
const input = nonNegativeInteger(usage.uncachedInputTokens);
|
|
5169
|
+
const output = nonNegativeInteger(usage.outputTokens);
|
|
5170
|
+
if (input === void 0 || output === void 0) return null;
|
|
5171
|
+
const routes = usage.routes;
|
|
5172
|
+
if (!Array.isArray(routes) || routes.length === 0) return null;
|
|
5173
|
+
const pairs = [];
|
|
5174
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5175
|
+
for (const entry of routes) {
|
|
5176
|
+
if (typeof entry !== "object" || entry === null) return null;
|
|
5177
|
+
const { provider, model } = entry;
|
|
5178
|
+
if (typeof provider !== "string" || provider === "" || typeof model !== "string" || model === "") return null;
|
|
5179
|
+
const key = `${provider}\0${model}`;
|
|
5180
|
+
if (seen.has(key)) continue;
|
|
5181
|
+
seen.add(key);
|
|
5182
|
+
pairs.push({ route: provider, model });
|
|
5183
|
+
}
|
|
5184
|
+
if (pairs.length === 0) return null;
|
|
5185
|
+
const cacheRead = nonNegativeInteger(usage.cacheReadTokens);
|
|
5186
|
+
const cacheWrite = nonNegativeInteger(usage.cacheWriteTokens);
|
|
5187
|
+
if (input === 0 && output === 0 && (cacheRead ?? 0) === 0 && (cacheWrite ?? 0) === 0) return null;
|
|
5188
|
+
const first = pairs[0];
|
|
5189
|
+
if (first === void 0) return null;
|
|
5190
|
+
const at = rfc3339Of(data.time);
|
|
5191
|
+
const item = {
|
|
5192
|
+
route: first.route,
|
|
5193
|
+
model: first.model,
|
|
5194
|
+
input_tokens: input,
|
|
5195
|
+
output_tokens: output,
|
|
5196
|
+
// 桶缺失表示「并非每次尝试都上报了该桶」——原样省略,绝不猜 0。
|
|
5197
|
+
...cacheRead === void 0 ? {} : { cache_read_tokens: cacheRead },
|
|
5198
|
+
...cacheWrite === void 0 ? {} : { cache_write_tokens: cacheWrite },
|
|
5199
|
+
...at === void 0 ? {} : { at }
|
|
5200
|
+
};
|
|
5201
|
+
const ambiguous = pairs.length > 1 || cacheRead === void 0 || cacheWrite === void 0;
|
|
5202
|
+
return { items: [item], turn, ambiguous };
|
|
5203
|
+
}
|
|
5204
|
+
function rfc3339Of(time) {
|
|
5205
|
+
if (typeof time !== "number" || !Number.isFinite(time) || time <= 0) return void 0;
|
|
5206
|
+
const date = new Date(time);
|
|
5207
|
+
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
5208
|
+
}
|
|
5209
|
+
function closingTurnTailData(snapshot, messageId) {
|
|
5210
|
+
for (const key of snapshot.order) {
|
|
5211
|
+
const node = snapshot.nodes.get(key);
|
|
5212
|
+
if (node === void 0 || node.kind !== "turn-tail") continue;
|
|
5213
|
+
const data = node.data;
|
|
5214
|
+
if (data === void 0) continue;
|
|
5215
|
+
if (data.closing?.finalNode?.messageId === messageId) return data;
|
|
5216
|
+
}
|
|
5217
|
+
return void 0;
|
|
5218
|
+
}
|
|
5219
|
+
function sessionCostKey(sessionId, match) {
|
|
5220
|
+
return `${sessionId}\0${match.turn}\0${JSON.stringify(match.items)}`;
|
|
5221
|
+
}
|
|
5222
|
+
function normalizeSessionCost(value) {
|
|
5223
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
5224
|
+
const record = value;
|
|
5225
|
+
if (record.priced !== true) return void 0;
|
|
5226
|
+
const cost = record.cost;
|
|
5227
|
+
if (typeof cost !== "number" || !Number.isFinite(cost) || cost < 0) return void 0;
|
|
5228
|
+
return { cost, channelResolved: record.channelResolved === true };
|
|
5229
|
+
}
|
|
5230
|
+
var SessionCostStore = class {
|
|
5231
|
+
constructor(rpc, options = {}) {
|
|
5232
|
+
this.rpc = rpc;
|
|
5233
|
+
this.now = options.now ?? (() => Date.now());
|
|
5234
|
+
this.ttlMs = options.ttlMs ?? SESSION_COST_CACHE_TTL_MS;
|
|
5235
|
+
}
|
|
5236
|
+
entries = /* @__PURE__ */ new Map();
|
|
5237
|
+
pending = /* @__PURE__ */ new Map();
|
|
5238
|
+
now;
|
|
5239
|
+
ttlMs;
|
|
5240
|
+
/** 当前缓存条目数(测试断言用)。 */
|
|
5241
|
+
get size() {
|
|
5242
|
+
return this.entries.size;
|
|
5243
|
+
}
|
|
5244
|
+
/** 清空缓存(登出 / 切换账号)。 */
|
|
5245
|
+
clear() {
|
|
5246
|
+
this.entries.clear();
|
|
5247
|
+
}
|
|
5248
|
+
async estimate(input) {
|
|
5249
|
+
const key = sessionCostKey(input.sessionId, { turn: input.turn, items: [...input.items] });
|
|
5250
|
+
const cached = this.entries.get(key);
|
|
5251
|
+
if (cached !== void 0 && this.now() - cached.fetchedAt < this.ttlMs) return cached.result;
|
|
5252
|
+
const inflight = this.pending.get(key);
|
|
5253
|
+
if (inflight !== void 0) return await inflight;
|
|
5254
|
+
const task = this.request(key, input);
|
|
5255
|
+
this.pending.set(key, task);
|
|
5256
|
+
try {
|
|
5257
|
+
return await task;
|
|
5258
|
+
} finally {
|
|
5259
|
+
this.pending.delete(key);
|
|
3318
5260
|
}
|
|
3319
|
-
}
|
|
3320
|
-
|
|
3321
|
-
const sidebar = sidebarRoot();
|
|
3322
|
-
if (sidebar === void 0) return true;
|
|
3323
|
-
if (menuElement === void 0 || !sidebar.contains(menuElement)) return true;
|
|
3324
|
-
if (registry.activeId() === null) return false;
|
|
3325
|
-
const host = conversationContainer();
|
|
3326
|
-
if (host === void 0) return true;
|
|
3327
|
-
return container === void 0 || !host.contains(container);
|
|
3328
|
-
};
|
|
3329
|
-
const scheduleRetry = () => {
|
|
3330
|
-
if (disposed || retryTimer !== void 0 || retries >= maxRetries) return;
|
|
3331
|
-
retryTimer = setTimeout(() => {
|
|
3332
|
-
retryTimer = void 0;
|
|
3333
|
-
retries += 1;
|
|
3334
|
-
sync();
|
|
3335
|
-
if (pending()) scheduleRetry();
|
|
3336
|
-
}, interval);
|
|
3337
|
-
};
|
|
3338
|
-
const onDocumentClickCapture = (event) => {
|
|
3339
|
-
if (registry.activeId() === null) return;
|
|
3340
|
-
const target = event.target;
|
|
3341
|
-
if (!(target instanceof Element)) return;
|
|
3342
|
-
if (target.closest(`[${FEATURE_ROOT_ATTRIBUTE}]`) !== null) return;
|
|
3343
|
-
if (target.closest(`[${MENU_ATTRIBUTE}]`) !== null) return;
|
|
3344
|
-
if (target.closest(SESSION_ROW_SELECTOR) === null) return;
|
|
3345
|
-
registry.openNative();
|
|
3346
|
-
};
|
|
3347
|
-
const unsubscribeRegistry = registry.subscribe(() => {
|
|
3348
|
-
sync();
|
|
3349
|
-
});
|
|
3350
|
-
let unsubscribeLocale;
|
|
3351
|
-
if (options.subscribeLocale !== void 0) {
|
|
5261
|
+
}
|
|
5262
|
+
async request(key, input) {
|
|
3352
5263
|
try {
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
} catch
|
|
3358
|
-
|
|
5264
|
+
const raw = await this.rpc.call(USAGE_CHANNEL, SESSION_COST_ENDPOINT, { items: input.items }, input.signal);
|
|
5265
|
+
const result = normalizeSessionCost(unwrapUsageResult(raw));
|
|
5266
|
+
if (result !== void 0) this.entries.set(key, { result, fetchedAt: this.now() });
|
|
5267
|
+
return result;
|
|
5268
|
+
} catch {
|
|
5269
|
+
return void 0;
|
|
3359
5270
|
}
|
|
3360
5271
|
}
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
5272
|
+
};
|
|
5273
|
+
var costStyle = {
|
|
5274
|
+
// 字号/颜色与同一行的「用量」「用时」胶囊同源变量,保证在动作行里不显得突兀。
|
|
5275
|
+
color: textTertiary,
|
|
5276
|
+
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
5277
|
+
lineHeight: "18px",
|
|
5278
|
+
whiteSpace: "nowrap",
|
|
5279
|
+
cursor: "default"
|
|
5280
|
+
};
|
|
5281
|
+
function SessionCost({ messageId, sessionId, useChat, store }) {
|
|
5282
|
+
const data = useChat((snapshot) => closingTurnTailData(snapshot, messageId));
|
|
5283
|
+
const match = sessionCostMatchOf(data);
|
|
5284
|
+
const key = match === null ? null : sessionCostKey(sessionId, match);
|
|
5285
|
+
const [shown, setShown] = (0, import_react11.useState)(void 0);
|
|
5286
|
+
(0, import_react11.useEffect)(() => {
|
|
5287
|
+
if (match === null || key === null) return;
|
|
5288
|
+
let disposed = false;
|
|
5289
|
+
const controller = new AbortController();
|
|
5290
|
+
void store.estimate({ sessionId, turn: match.turn, items: match.items, signal: controller.signal }).then((value) => {
|
|
5291
|
+
if (!disposed) setShown({ key, result: value });
|
|
5292
|
+
}).catch(() => {
|
|
5293
|
+
if (!disposed) setShown({ key, result: void 0 });
|
|
5294
|
+
});
|
|
5295
|
+
return () => {
|
|
3376
5296
|
disposed = true;
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
if (style.getAttribute(OWNER_ATTRIBUTE) === owner) style.remove();
|
|
3401
|
-
},
|
|
3402
|
-
openNativeHome: () => {
|
|
3403
|
-
renderContext.openNativeHome();
|
|
3404
|
-
}
|
|
5297
|
+
controller.abort();
|
|
5298
|
+
};
|
|
5299
|
+
}, [store, key]);
|
|
5300
|
+
if (match === null || key === null || shown === void 0 || shown.key !== key || shown.result === void 0) return null;
|
|
5301
|
+
const result = shown.result;
|
|
5302
|
+
const estimated = !result.channelResolved || match.ambiguous;
|
|
5303
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: costStyle, "data-hiwork-session-cost": estimated ? "estimated" : "exact", title: SESSION_COST_HINT, children: `\u2248 ${formatYuan(result.cost)}${estimated ? SESSION_COST_ESTIMATED_SUFFIX : ""}` });
|
|
5304
|
+
}
|
|
5305
|
+
|
|
5306
|
+
// src/client/account-cache.ts
|
|
5307
|
+
function accountIdentityOf(state) {
|
|
5308
|
+
return `${state.username ?? ""}\0${state.activeKeyId ?? ""}`;
|
|
5309
|
+
}
|
|
5310
|
+
function observeAccountChange(source, onChange) {
|
|
5311
|
+
let identity = accountIdentityOf(source.getSnapshot());
|
|
5312
|
+
const unsubscribe = source.subscribe(() => {
|
|
5313
|
+
const next = accountIdentityOf(source.getSnapshot());
|
|
5314
|
+
if (next === identity) return;
|
|
5315
|
+
identity = next;
|
|
5316
|
+
onChange();
|
|
5317
|
+
});
|
|
5318
|
+
return () => {
|
|
5319
|
+
unsubscribe();
|
|
3405
5320
|
};
|
|
3406
5321
|
}
|
|
3407
5322
|
|
|
@@ -4405,17 +6320,17 @@ var PmsTodoStore = class {
|
|
|
4405
6320
|
};
|
|
4406
6321
|
|
|
4407
6322
|
// src/client/voice/MicButton.tsx
|
|
4408
|
-
var
|
|
4409
|
-
var
|
|
6323
|
+
var import_react12 = require("react");
|
|
6324
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4410
6325
|
function MicIcon({ size }) {
|
|
4411
|
-
return /* @__PURE__ */ (0,
|
|
4412
|
-
/* @__PURE__ */ (0,
|
|
4413
|
-
/* @__PURE__ */ (0,
|
|
4414
|
-
/* @__PURE__ */ (0,
|
|
6326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6327
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "9", y: "2.75", width: "6", height: "11.5", rx: "3", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
6328
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M5.5 11.5a6.5 6.5 0 0 0 13 0", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
6329
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 18v3.25", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
4415
6330
|
] });
|
|
4416
6331
|
}
|
|
4417
6332
|
function MicButton({ open }) {
|
|
4418
|
-
return /* @__PURE__ */ (0,
|
|
6333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4419
6334
|
"button",
|
|
4420
6335
|
{
|
|
4421
6336
|
type: "button",
|
|
@@ -4424,13 +6339,13 @@ function MicButton({ open }) {
|
|
|
4424
6339
|
"aria-label": "\u8BED\u97F3\u8F93\u5165",
|
|
4425
6340
|
"aria-haspopup": "dialog",
|
|
4426
6341
|
onClick: () => open(),
|
|
4427
|
-
children: /* @__PURE__ */ (0,
|
|
6342
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MicIcon, { size: 18 })
|
|
4428
6343
|
}
|
|
4429
6344
|
);
|
|
4430
6345
|
}
|
|
4431
6346
|
|
|
4432
6347
|
// src/client/voice/entry.ts
|
|
4433
|
-
var
|
|
6348
|
+
var import_react14 = require("react");
|
|
4434
6349
|
var import_client3 = require("react-dom/client");
|
|
4435
6350
|
|
|
4436
6351
|
// src/client/voice/composer.ts
|
|
@@ -4486,7 +6401,7 @@ function insertDraftText(sessions, text6, sessionId) {
|
|
|
4486
6401
|
}
|
|
4487
6402
|
|
|
4488
6403
|
// src/client/voice/VoiceOverlay.tsx
|
|
4489
|
-
var
|
|
6404
|
+
var import_react13 = require("react");
|
|
4490
6405
|
|
|
4491
6406
|
// src/client/voice/recording.ts
|
|
4492
6407
|
var RecordingError = class extends Error {
|
|
@@ -4769,7 +6684,7 @@ function createVoiceRuntime(rpc) {
|
|
|
4769
6684
|
}
|
|
4770
6685
|
|
|
4771
6686
|
// src/client/voice/VoiceOverlay.tsx
|
|
4772
|
-
var
|
|
6687
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4773
6688
|
var BAR_COUNT = 28;
|
|
4774
6689
|
var LEVEL_INTERVAL_MS = 80;
|
|
4775
6690
|
var TICK_INTERVAL_MS = 200;
|
|
@@ -4783,25 +6698,25 @@ function rmsToLevel(rms) {
|
|
|
4783
6698
|
return Math.min(1, Math.max(0, rms) * 6);
|
|
4784
6699
|
}
|
|
4785
6700
|
function MicIcon2({ size }) {
|
|
4786
|
-
return /* @__PURE__ */ (0,
|
|
4787
|
-
/* @__PURE__ */ (0,
|
|
4788
|
-
/* @__PURE__ */ (0,
|
|
4789
|
-
/* @__PURE__ */ (0,
|
|
6701
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6702
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { x: "9", y: "2.75", width: "6", height: "11.5", rx: "3", stroke: "currentColor", strokeWidth: "1.6" }),
|
|
6703
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M5.5 11.5a6.5 6.5 0 0 0 13 0", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
6704
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 18v3.25", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
4790
6705
|
] });
|
|
4791
6706
|
}
|
|
4792
6707
|
function VoiceOverlay(props) {
|
|
4793
6708
|
const { runtime, onClose, insertDraft } = props;
|
|
4794
|
-
const [phase, setPhase] = (0,
|
|
4795
|
-
const [error, setError] = (0,
|
|
4796
|
-
const [levels, setLevels] = (0,
|
|
4797
|
-
const [elapsed, setElapsed] = (0,
|
|
4798
|
-
const [maxDuration, setMaxDuration] = (0,
|
|
4799
|
-
const [copied, setCopied] = (0,
|
|
4800
|
-
const recordingRef = (0,
|
|
4801
|
-
const wavRef = (0,
|
|
4802
|
-
const startedAtRef = (0,
|
|
4803
|
-
const abortRef = (0,
|
|
4804
|
-
const disposedRef = (0,
|
|
6709
|
+
const [phase, setPhase] = (0, import_react13.useState)("checking");
|
|
6710
|
+
const [error, setError] = (0, import_react13.useState)(void 0);
|
|
6711
|
+
const [levels, setLevels] = (0, import_react13.useState)(() => Array.from({ length: BAR_COUNT }, () => 0.06));
|
|
6712
|
+
const [elapsed, setElapsed] = (0, import_react13.useState)(0);
|
|
6713
|
+
const [maxDuration, setMaxDuration] = (0, import_react13.useState)(60);
|
|
6714
|
+
const [copied, setCopied] = (0, import_react13.useState)(false);
|
|
6715
|
+
const recordingRef = (0, import_react13.useRef)(void 0);
|
|
6716
|
+
const wavRef = (0, import_react13.useRef)(void 0);
|
|
6717
|
+
const startedAtRef = (0, import_react13.useRef)(0);
|
|
6718
|
+
const abortRef = (0, import_react13.useRef)(void 0);
|
|
6719
|
+
const disposedRef = (0, import_react13.useRef)(false);
|
|
4805
6720
|
const failWith = (message, opts = {}) => {
|
|
4806
6721
|
if (disposedRef.current) return;
|
|
4807
6722
|
setPhase("error");
|
|
@@ -4898,7 +6813,7 @@ function VoiceOverlay(props) {
|
|
|
4898
6813
|
failWith(err instanceof Error ? err.message : "\u5F55\u97F3\u5904\u7406\u5931\u8D25\u3002", { holdWav: false });
|
|
4899
6814
|
});
|
|
4900
6815
|
};
|
|
4901
|
-
(0,
|
|
6816
|
+
(0, import_react13.useEffect)(() => {
|
|
4902
6817
|
disposedRef.current = false;
|
|
4903
6818
|
let cancelled = false;
|
|
4904
6819
|
runtime.status().then((status) => {
|
|
@@ -4921,7 +6836,7 @@ function VoiceOverlay(props) {
|
|
|
4921
6836
|
recordingRef.current = void 0;
|
|
4922
6837
|
};
|
|
4923
6838
|
}, []);
|
|
4924
|
-
(0,
|
|
6839
|
+
(0, import_react13.useEffect)(() => {
|
|
4925
6840
|
if (phase !== "recording") return;
|
|
4926
6841
|
const levelTimer = window.setInterval(() => {
|
|
4927
6842
|
const rms = recordingRef.current?.amplitude() ?? 0;
|
|
@@ -4935,7 +6850,7 @@ function VoiceOverlay(props) {
|
|
|
4935
6850
|
window.clearInterval(clockTimer);
|
|
4936
6851
|
};
|
|
4937
6852
|
}, [phase]);
|
|
4938
|
-
(0,
|
|
6853
|
+
(0, import_react13.useEffect)(() => {
|
|
4939
6854
|
if (phase !== "recording") return;
|
|
4940
6855
|
if (elapsed < maxDuration) return;
|
|
4941
6856
|
finish();
|
|
@@ -4944,7 +6859,7 @@ function VoiceOverlay(props) {
|
|
|
4944
6859
|
abortRef.current?.abort();
|
|
4945
6860
|
onClose();
|
|
4946
6861
|
};
|
|
4947
|
-
(0,
|
|
6862
|
+
(0, import_react13.useEffect)(() => {
|
|
4948
6863
|
const onKey = (event) => {
|
|
4949
6864
|
if (event.key !== "Escape") return;
|
|
4950
6865
|
event.preventDefault();
|
|
@@ -4962,21 +6877,21 @@ function VoiceOverlay(props) {
|
|
|
4962
6877
|
const idle = phase === "checking" || phase === "requesting" || phase === "transcribing";
|
|
4963
6878
|
const canRetryTranscribe = error?.holdWav === true && error.recognizedText === void 0;
|
|
4964
6879
|
const canRestart = error?.canRestart === true;
|
|
4965
|
-
return /* @__PURE__ */ (0,
|
|
6880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4966
6881
|
"div",
|
|
4967
6882
|
{
|
|
4968
6883
|
className: "hiwv-backdrop",
|
|
4969
6884
|
onMouseDown: (event) => {
|
|
4970
6885
|
if (event.target === event.currentTarget && !idle) handleClose();
|
|
4971
6886
|
},
|
|
4972
|
-
children: /* @__PURE__ */ (0,
|
|
4973
|
-
/* @__PURE__ */ (0,
|
|
4974
|
-
/* @__PURE__ */ (0,
|
|
4975
|
-
/* @__PURE__ */ (0,
|
|
6887
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "hiwv-panel", role: "dialog", "aria-modal": "true", "aria-label": "\u8BED\u97F3\u8F93\u5165", children: [
|
|
6888
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "hiwv-head", children: [
|
|
6889
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "hiwv-title", children: "\u8BED\u97F3\u8F93\u5165" }),
|
|
6890
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "hiwv-hint", children: recording ? `\u5DF2\u5F55 ${formatClock(elapsed)} / \u4E0A\u9650 ${formatClock(maxDuration)}` : `\u5355\u6B21\u6700\u957F ${formatClock(maxDuration)}` })
|
|
4976
6891
|
] }),
|
|
4977
|
-
/* @__PURE__ */ (0,
|
|
4978
|
-
/* @__PURE__ */ (0,
|
|
4979
|
-
/* @__PURE__ */ (0,
|
|
6892
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `hiwv-stage${recording ? "" : " hiwv-stageIdle"}`, children: recording || phase === "transcribing" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
6893
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `hiwv-orb${phase === "transcribing" ? " hiwv-orbBusy" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MicIcon2, { size: 30 }) }),
|
|
6894
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hiwv-bars", "aria-hidden": "true", children: levels.map((level, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4980
6895
|
"i",
|
|
4981
6896
|
{
|
|
4982
6897
|
style: { height: `${Math.round(8 + level * 46)}px` },
|
|
@@ -4984,19 +6899,19 @@ function VoiceOverlay(props) {
|
|
|
4984
6899
|
},
|
|
4985
6900
|
index
|
|
4986
6901
|
)) }),
|
|
4987
|
-
/* @__PURE__ */ (0,
|
|
4988
|
-
] }) : phase === "checking" || phase === "requesting" ? /* @__PURE__ */ (0,
|
|
4989
|
-
/* @__PURE__ */ (0,
|
|
4990
|
-
error?.recognizedText !== void 0 && /* @__PURE__ */ (0,
|
|
4991
|
-
/* @__PURE__ */ (0,
|
|
4992
|
-
/* @__PURE__ */ (0,
|
|
6902
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hiwv-status", children: phase === "transcribing" ? "\u6B63\u5728\u8BC6\u522B\u2026" : "\u6B63\u5728\u8046\u542C\uFF0C\u8BB2\u5B8C\u540E\u70B9\u300C\u5B8C\u6210\u300D" })
|
|
6903
|
+
] }) : phase === "checking" || phase === "requesting" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hiwv-status", children: "\u6B63\u5728\u51C6\u5907\u9EA6\u514B\u98CE\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "hiwv-errorBox", children: [
|
|
6904
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hiwv-errorMsg", children: error?.message ?? "\u51FA\u4E86\u70B9\u95EE\u9898\u3002" }),
|
|
6905
|
+
error?.recognizedText !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "hiwv-recognized", children: [
|
|
6906
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hiwv-recognizedText", children: error.recognizedText }),
|
|
6907
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "hiwv-btn hiwv-btnSecondary", onClick: copyRecognized, children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u6587\u672C" })
|
|
4993
6908
|
] })
|
|
4994
6909
|
] }) }),
|
|
4995
|
-
/* @__PURE__ */ (0,
|
|
4996
|
-
/* @__PURE__ */ (0,
|
|
4997
|
-
recording && /* @__PURE__ */ (0,
|
|
4998
|
-
phase === "error" && canRetryTranscribe && /* @__PURE__ */ (0,
|
|
4999
|
-
phase === "error" && canRestart && /* @__PURE__ */ (0,
|
|
6910
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "hiwv-actions", children: [
|
|
6911
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "hiwv-btn hiwv-btnSecondary", onClick: handleClose, children: "\u53D6\u6D88" }),
|
|
6912
|
+
recording && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "hiwv-btn hiwv-btnPrimary", onClick: finish, children: "\u5B8C\u6210" }),
|
|
6913
|
+
phase === "error" && canRetryTranscribe && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "hiwv-btn hiwv-btnPrimary", onClick: transcribeWav, children: "\u91CD\u8BD5\u8BC6\u522B" }),
|
|
6914
|
+
phase === "error" && canRestart && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5000
6915
|
"button",
|
|
5001
6916
|
{
|
|
5002
6917
|
type: "button",
|
|
@@ -5060,7 +6975,7 @@ function createOverlayController(deps) {
|
|
|
5060
6975
|
doc.body.appendChild(container);
|
|
5061
6976
|
root = (0, import_client3.createRoot)(container);
|
|
5062
6977
|
root.render(
|
|
5063
|
-
(0,
|
|
6978
|
+
(0, import_react14.createElement)(VoiceOverlay, {
|
|
5064
6979
|
runtime: deps.runtime,
|
|
5065
6980
|
onClose: close,
|
|
5066
6981
|
// 会话 id 缺省(拿不到槽位注入)时由 insertDraftText 退到当前打开会话;
|
|
@@ -5133,7 +7048,7 @@ async function installVoiceInput(deps) {
|
|
|
5133
7048
|
}
|
|
5134
7049
|
|
|
5135
7050
|
// src/client/index.ts
|
|
5136
|
-
var inject = ["slots", "locale", "remote", "remote.credentials", "
|
|
7051
|
+
var inject = ["slots", "locale", "remote", "remote.credentials", "configForms", "connection", "layout"];
|
|
5137
7052
|
var INTERACTION_STYLE_ID = "hiwork-core-interaction-styles";
|
|
5138
7053
|
function injectInteractionStyles() {
|
|
5139
7054
|
if (typeof document === "undefined") return;
|
|
@@ -5146,12 +7061,12 @@ function injectInteractionStyles() {
|
|
|
5146
7061
|
}
|
|
5147
7062
|
function apply(ctx) {
|
|
5148
7063
|
injectInteractionStyles();
|
|
5149
|
-
const
|
|
7064
|
+
const form = ctx.configForms.get(AI_ROUTER_NS);
|
|
5150
7065
|
const storeCredential = async (ref, value) => {
|
|
5151
7066
|
const response = await ctx.remote.credentials.set(ref, value);
|
|
5152
7067
|
if (!response.ok) throw new Error(response.error.message);
|
|
5153
7068
|
};
|
|
5154
|
-
const controller = new AiRouterCardController(
|
|
7069
|
+
const controller = new AiRouterCardController(form, storeCredential);
|
|
5155
7070
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
5156
7071
|
name: "settings.section",
|
|
5157
7072
|
id: AI_ROUTER_NS,
|
|
@@ -5159,12 +7074,6 @@ function apply(ctx) {
|
|
|
5159
7074
|
label: () => AI_ROUTER_SECTION_LABEL,
|
|
5160
7075
|
inject: () => controller.inject()
|
|
5161
7076
|
}, AiRouterSection));
|
|
5162
|
-
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
5163
|
-
name: "settings.section",
|
|
5164
|
-
id: "hiwork-about",
|
|
5165
|
-
order: Number.MAX_SAFE_INTEGER,
|
|
5166
|
-
label: () => "\u5173\u4E8E"
|
|
5167
|
-
}, AboutSection));
|
|
5168
7077
|
const connection = ctx.get("connection");
|
|
5169
7078
|
if (connection === void 0) throw new Error("connection service unavailable");
|
|
5170
7079
|
const usage = new UsageDataStore(connection.rpc);
|
|
@@ -5175,6 +7084,13 @@ function apply(ctx) {
|
|
|
5175
7084
|
const managedWorkbench = new ManagedWorkbenchStore(connection.rpc);
|
|
5176
7085
|
const pmsTodo = new PmsTodoStore(connection.rpc);
|
|
5177
7086
|
const appVersion = createAppVersion(connection.rpc);
|
|
7087
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
7088
|
+
name: "settings.section",
|
|
7089
|
+
id: "hiwork-about",
|
|
7090
|
+
order: Number.MAX_SAFE_INTEGER,
|
|
7091
|
+
label: () => "\u5173\u4E8E",
|
|
7092
|
+
inject: () => ({ appVersion })
|
|
7093
|
+
}, AboutSection));
|
|
5178
7094
|
const pluginUpdates = createPluginUpdates(connection.rpc);
|
|
5179
7095
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
5180
7096
|
name: "settings.section",
|
|
@@ -5183,6 +7099,57 @@ function apply(ctx) {
|
|
|
5183
7099
|
label: () => "\u7528\u91CF\u4E0E\u6210\u672C",
|
|
5184
7100
|
inject: () => ({ hooks: controller.inject().hooks, usage })
|
|
5185
7101
|
}, UsageSection));
|
|
7102
|
+
const featureRegistry = createFeatureRegistry();
|
|
7103
|
+
const images = new ImageGallerySource(connection.rpc);
|
|
7104
|
+
installImagesFeature(ctx, featureRegistry, images);
|
|
7105
|
+
installImageToolCard(ctx);
|
|
7106
|
+
const PLUGINS_PANEL_ID = "plugins";
|
|
7107
|
+
const asPanelId = (id) => id;
|
|
7108
|
+
const layoutFace = () => {
|
|
7109
|
+
try {
|
|
7110
|
+
return ctx.layout ?? void 0;
|
|
7111
|
+
} catch {
|
|
7112
|
+
return void 0;
|
|
7113
|
+
}
|
|
7114
|
+
};
|
|
7115
|
+
const nativePanel = {
|
|
7116
|
+
pluginsAvailable: () => {
|
|
7117
|
+
const layout = layoutFace();
|
|
7118
|
+
if (layout === void 0) return false;
|
|
7119
|
+
try {
|
|
7120
|
+
return ctx.slots.entries("main").some((entry) => entry.options.key === PLUGINS_PANEL_ID);
|
|
7121
|
+
} catch {
|
|
7122
|
+
return false;
|
|
7123
|
+
}
|
|
7124
|
+
},
|
|
7125
|
+
anyActive: () => (layoutFace()?.panelInfo.getSnapshot().activePanelId ?? null) !== null,
|
|
7126
|
+
pluginsActive: () => layoutFace()?.panelInfo.getSnapshot().activePanelId === PLUGINS_PANEL_ID,
|
|
7127
|
+
openPlugins: () => {
|
|
7128
|
+
layoutFace()?.selectPanel(asPanelId(PLUGINS_PANEL_ID));
|
|
7129
|
+
},
|
|
7130
|
+
returnToConversation: () => {
|
|
7131
|
+
layoutFace()?.selectPanel(null);
|
|
7132
|
+
},
|
|
7133
|
+
subscribe: (listener) => {
|
|
7134
|
+
const layout = layoutFace();
|
|
7135
|
+
if (layout === void 0) return () => void 0;
|
|
7136
|
+
const offSlots = ctx.slots.subscribe("main", listener);
|
|
7137
|
+
const offPanel = layout.panelInfo.subscribe(listener);
|
|
7138
|
+
return () => {
|
|
7139
|
+
offSlots();
|
|
7140
|
+
offPanel();
|
|
7141
|
+
};
|
|
7142
|
+
}
|
|
7143
|
+
};
|
|
7144
|
+
const additionalFeatures = () => nativePanel.pluginsAvailable() ? [nativePluginsMenuItem()] : [];
|
|
7145
|
+
const menuStore = new MenuStore(form, featureRegistry, additionalFeatures);
|
|
7146
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
7147
|
+
name: "settings.section",
|
|
7148
|
+
id: HIWORK_MENU_NS,
|
|
7149
|
+
order: 3,
|
|
7150
|
+
label: () => MENU_SECTION_LABEL,
|
|
7151
|
+
inject: () => menuStore.inject()
|
|
7152
|
+
}, MenuSection));
|
|
5186
7153
|
ctx.slots.inject("conversation.chat.assistant-actions", () => ctx.slots.register({
|
|
5187
7154
|
name: "conversation.chat.assistant-actions",
|
|
5188
7155
|
id: "hiwork-session-cost",
|
|
@@ -5248,12 +7215,11 @@ function apply(ctx) {
|
|
|
5248
7215
|
id: AI_ROUTER_NS,
|
|
5249
7216
|
inject: () => ({ ...controller.inject(), pluginUpdates })
|
|
5250
7217
|
}, UserBadge));
|
|
5251
|
-
ctx.effect(() => mountLoginGate(
|
|
7218
|
+
ctx.effect(() => mountLoginGate(form, storeCredential), "hiwork-core: login gate");
|
|
5252
7219
|
ctx.effect(() => observeHeroDecorations(document, dailyQuotes), "hiwork-core: hero decorations");
|
|
5253
|
-
installFeatureCenter(ctx, managedMcp, managedSkills, managedWorkbench, pmsTodo);
|
|
7220
|
+
installFeatureCenter(ctx, featureRegistry, menuStore, managedMcp, managedSkills, managedWorkbench, pmsTodo, additionalFeatures, nativePanel);
|
|
5254
7221
|
}
|
|
5255
|
-
function installFeatureCenter(ctx, managedMcp, managedSkills, managedWorkbench, pmsTodo) {
|
|
5256
|
-
const featureRegistry = createFeatureRegistry();
|
|
7222
|
+
function installFeatureCenter(ctx, featureRegistry, menuStore, managedMcp, managedSkills, managedWorkbench, pmsTodo, additionalFeatures, nativePanel) {
|
|
5257
7223
|
let center;
|
|
5258
7224
|
const resolveSessions = () => ctx.get("sessions");
|
|
5259
7225
|
const locale = ctx.get("locale");
|
|
@@ -5332,12 +7298,20 @@ function installFeatureCenter(ctx, managedMcp, managedSkills, managedWorkbench,
|
|
|
5332
7298
|
openNativeSession: (sessionId) => {
|
|
5333
7299
|
resolveSessions()?.open(sessionId);
|
|
5334
7300
|
},
|
|
5335
|
-
|
|
7301
|
+
additionalFeatures,
|
|
7302
|
+
nativePanel,
|
|
7303
|
+
...locale === void 0 ? {} : { subscribeLocale: (listener) => locale.subscribe(listener) },
|
|
7304
|
+
// 侧栏分组与顺序(`hiwork-menu`,见 menu-preferences.ts / menu-store.ts):
|
|
7305
|
+
// `preferences` 每次重建菜单时现取,`subscribePreferences` 让设置页里的一次改动
|
|
7306
|
+
// 立刻反映到侧栏,不需要重启。
|
|
7307
|
+
preferences: () => menuStore.preferences(),
|
|
7308
|
+
subscribePreferences: (listener) => menuStore.subscribePreferences(listener)
|
|
5336
7309
|
});
|
|
5337
7310
|
return () => {
|
|
5338
7311
|
center?.dispose();
|
|
5339
7312
|
center = void 0;
|
|
5340
7313
|
};
|
|
5341
7314
|
}, "hiwork-core: feature center");
|
|
7315
|
+
ctx.effect(() => () => menuStore.dispose(), "hiwork-core: menu preferences");
|
|
5342
7316
|
}
|
|
5343
7317
|
return module.exports; } });
|