@jcy2387/dsh-conversation-ui 0.2.0-rc.2 → 0.2.1-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +27 -26
- package/README.md +27 -26
- package/cordis.patch.yml +1 -1
- package/lib/client.js +1156 -1879
- package/lib/client.js.map +1 -1
- package/lib/index.js +102 -28
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +34 -35
- package/src/channel-bridge.ts +8 -7
- package/src/client/ConversationCard.module.css +47 -0
- package/src/client/ConversationCard.tsx +57 -1
- package/src/client/DeliverablesCard.module.css +1 -5
- package/src/client/DeliverablesCard.tsx +67 -50
- package/src/client/NativeAssistantEnhancement.tsx +148 -0
- package/src/client/conversation-ui-card-controller.ts +15 -8
- package/src/client/conversation-ui-settings-api.ts +7 -3
- package/src/client/deliverables.ts +123 -27
- package/src/client/developer-tools.ts +51 -0
- package/src/client/index.ts +52 -147
- package/src/client/locales.ts +50 -2
- package/src/client/useConversationContent.ts +15 -2
- package/src/config.ts +1 -1
- package/src/package-meta.ts +3 -0
- package/src/plugin.ts +63 -16
- package/src/profile-installation.ts +22 -3
- package/src/settings-api.ts +3 -3
- package/src/settings.ts +17 -15
- package/src/client/AnimatedDisclosure.tsx +0 -89
- package/src/client/CodexTurnProcessNodeView.tsx +0 -127
- package/src/client/FollowHost.tsx +0 -31
- package/src/client/ToolActivityGroup.tsx +0 -303
- package/src/client/TranscriptViewBridge.tsx +0 -26
- package/src/client/TypewriterAssistantNodeView.module.css +0 -1226
- package/src/client/TypewriterAssistantNodeView.tsx +0 -422
- package/src/client/TypewriterToolNodeView.tsx +0 -831
- package/src/client/turnElapsed.ts +0 -23
- package/src/client/turnProcessFallback.ts +0 -91
- package/src/client/useChatSeatHidden.ts +0 -91
- package/src/client/useFpsGuard.ts +0 -84
- package/src/client/useSearchableHidden.ts +0 -23
package/lib/client.js
CHANGED
|
@@ -4,61 +4,9 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
-
//#region \0rolldown/runtime.js
|
|
8
|
-
var __create = Object.create;
|
|
9
|
-
var __defProp = Object.defineProperty;
|
|
10
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
-
var __copyProps = (to, from, except, desc) => {
|
|
15
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
16
|
-
key = keys[i];
|
|
17
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
18
|
-
get: ((k) => from[k]).bind(null, key),
|
|
19
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
return to;
|
|
23
|
-
};
|
|
24
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
25
|
-
value: mod,
|
|
26
|
-
enumerable: true
|
|
27
|
-
}) : target, mod));
|
|
28
|
-
//#endregion
|
|
29
7
|
let react = require("react");
|
|
30
|
-
react = __toESM(react, 1);
|
|
31
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
32
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
33
|
-
let react_dom = require("react-dom");
|
|
34
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.0-rc.2_@deepseek-ai+cordis@4.0.4/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
|
|
35
|
-
/**
|
|
36
|
-
* Browser-safe Workspace path and display helpers.
|
|
37
|
-
* @module @deepseek-ai/dsh-util-workspace-path
|
|
38
|
-
*/
|
|
39
|
-
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
40
|
-
function isWindowsStylePath(value) {
|
|
41
|
-
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Whether a path is absolute in either spelling the Host accepts: POSIX (`/a/b`) or Windows drive or UNC.
|
|
45
|
-
* @param path - the path to classify.
|
|
46
|
-
* @returns `true` for an absolute path; `false` for a Workspace-relative one.
|
|
47
|
-
*/
|
|
48
|
-
function isAbsoluteWorkspacePath(path) {
|
|
49
|
-
return path.startsWith("/") || isWindowsStylePath(path);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Address a decoded absolute file path through the authenticated file route.
|
|
53
|
-
* @param base - HTTP(S) application base, including its deployment prefix, or `dsh-app://app/`.
|
|
54
|
-
* @param path - Native file path; URL escapes in authored Markdown must already be decoded.
|
|
55
|
-
* @returns File URL, or undefined for unsupported transports and non-absolute paths.
|
|
56
|
-
*/
|
|
57
|
-
function fileMediaUrl(base, path) {
|
|
58
|
-
if (!/^https?:/u.test(base) && !base.startsWith("dsh-app://app/") || !isAbsoluteWorkspacePath(path) || /^[/\\]{2}/u.test(path) || /[\u0000-\u001f\u007f]/u.test(path)) return void 0;
|
|
59
|
-
return new URL(`api/file?path=${encodeURIComponent(path)}`, base).href;
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
10
|
//#region src/client/useConversationContent.ts
|
|
63
11
|
/**
|
|
64
12
|
* Stream-smoothing reveal hook.
|
|
@@ -192,7 +140,7 @@ window.__ModuleLoader__.load({
|
|
|
192
140
|
* @param options - Preset, guard, and steady-rate wiring.
|
|
193
141
|
* @returns The displayed content, revealed at the smoothed cadence.
|
|
194
142
|
*/
|
|
195
|
-
function useConversationContent(content, { enabled = true, preset = "balanced", shouldHoldBack, steadyCps, defaultCps, speedCpsRef } = {}) {
|
|
143
|
+
function useConversationContent(content, { enabled = true, preset = "balanced", shouldHoldBack, steadyCps, settleCps, defaultCps, speedCpsRef } = {}) {
|
|
196
144
|
const config = PRESET_CONFIG[preset];
|
|
197
145
|
const seedCps = defaultCps ?? config.defaultCps;
|
|
198
146
|
const [displayedContent, setDisplayedContent] = (0, react.useState)(content);
|
|
@@ -210,7 +158,9 @@ window.__ModuleLoader__.load({
|
|
|
210
158
|
const lastFrameTsRef = (0, react.useRef)(null);
|
|
211
159
|
const wakeTimerRef = (0, react.useRef)(null);
|
|
212
160
|
const holdBackRef = (0, react.useRef)(shouldHoldBack);
|
|
161
|
+
const settleCpsRef = (0, react.useRef)(settleCps);
|
|
213
162
|
const speedOutRef = (0, react.useRef)(speedCpsRef);
|
|
163
|
+
settleCpsRef.current = settleCps;
|
|
214
164
|
speedOutRef.current = speedCpsRef;
|
|
215
165
|
(0, react.useEffect)(() => {
|
|
216
166
|
holdBackRef.current = shouldHoldBack;
|
|
@@ -286,6 +236,7 @@ window.__ModuleLoader__.load({
|
|
|
286
236
|
const settling = !inputActive && idleMs >= config.settleAfterMs;
|
|
287
237
|
let revealChars;
|
|
288
238
|
if (steadyCps !== void 0) {
|
|
239
|
+
const effectiveSteadyCps = inputActive ? steadyCps : settleCpsRef.current ?? steadyCps;
|
|
289
240
|
const step = computeRevealStep(config, {
|
|
290
241
|
backlog,
|
|
291
242
|
chunkSizeEma: chunkSizeEmaRef.current,
|
|
@@ -293,7 +244,7 @@ window.__ModuleLoader__.load({
|
|
|
293
244
|
emaCps: emaCpsRef.current,
|
|
294
245
|
inputActive,
|
|
295
246
|
settling,
|
|
296
|
-
steadyCps
|
|
247
|
+
steadyCps: effectiveSteadyCps
|
|
297
248
|
}, dtSeconds);
|
|
298
249
|
revealChars = Math.min(step.revealChars, backlog);
|
|
299
250
|
} else revealChars = computeQueueReveal(backlog, frameIntervalMs);
|
|
@@ -377,1590 +328,166 @@ window.__ModuleLoader__.load({
|
|
|
377
328
|
return displayedContent;
|
|
378
329
|
}
|
|
379
330
|
//#endregion
|
|
380
|
-
//#region src/client/
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const FPS_THRESHOLD = 30;
|
|
391
|
-
const FPS_ALPHA = .12;
|
|
392
|
-
const RECOVER_FRAMES = 6;
|
|
393
|
-
const MAX_FRAME_MS = 100;
|
|
394
|
-
function useFpsGuard(active) {
|
|
395
|
-
const fpsRef = (0, react.useRef)({
|
|
396
|
-
emaMs: 0,
|
|
397
|
-
lastMs: 0,
|
|
398
|
-
healthyRun: 0,
|
|
399
|
-
degraded: false
|
|
400
|
-
});
|
|
401
|
-
const visibleRef = (0, react.useRef)(true);
|
|
402
|
-
const elementRef = (0, react.useRef)(null);
|
|
403
|
-
(0, react.useEffect)(() => {
|
|
404
|
-
if (!active) return;
|
|
405
|
-
let rafId = 0;
|
|
406
|
-
const frame = (now) => {
|
|
407
|
-
rafId = requestAnimationFrame(frame);
|
|
408
|
-
const fps = fpsRef.current;
|
|
409
|
-
if (fps.lastMs === 0) {
|
|
410
|
-
fps.lastMs = now;
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
const delta = Math.min(MAX_FRAME_MS, Math.max(1, now - fps.lastMs));
|
|
414
|
-
fps.lastMs = now;
|
|
415
|
-
fps.emaMs = fps.emaMs === 0 ? delta : fps.emaMs + FPS_ALPHA * (delta - fps.emaMs);
|
|
416
|
-
if (1e3 / fps.emaMs < FPS_THRESHOLD) {
|
|
417
|
-
fps.healthyRun = 0;
|
|
418
|
-
fps.degraded = true;
|
|
419
|
-
} else if (fps.degraded) {
|
|
420
|
-
fps.healthyRun += 1;
|
|
421
|
-
if (fps.healthyRun >= RECOVER_FRAMES) fps.degraded = false;
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
rafId = requestAnimationFrame(frame);
|
|
425
|
-
return () => {
|
|
426
|
-
cancelAnimationFrame(rafId);
|
|
427
|
-
fpsRef.current = {
|
|
428
|
-
emaMs: 0,
|
|
429
|
-
lastMs: 0,
|
|
430
|
-
healthyRun: 0,
|
|
431
|
-
degraded: false
|
|
432
|
-
};
|
|
433
|
-
};
|
|
434
|
-
}, [active]);
|
|
435
|
-
const ref = (0, react.useCallback)((element) => {
|
|
436
|
-
elementRef.current = element;
|
|
437
|
-
}, []);
|
|
438
|
-
(0, react.useEffect)(() => {
|
|
439
|
-
const element = elementRef.current;
|
|
440
|
-
if (element === null || typeof IntersectionObserver === "undefined") return;
|
|
441
|
-
const observer = new IntersectionObserver((entries) => {
|
|
442
|
-
for (const entry of entries) visibleRef.current = entry.isIntersecting;
|
|
443
|
-
}, { rootMargin: "120px 0px" });
|
|
444
|
-
observer.observe(element);
|
|
445
|
-
return () => observer.disconnect();
|
|
446
|
-
});
|
|
447
|
-
return {
|
|
448
|
-
ref,
|
|
449
|
-
shouldHoldBack: (0, react.useCallback)(() => {
|
|
450
|
-
return active && fpsRef.current.degraded && !visibleRef.current;
|
|
451
|
-
}, [active])
|
|
331
|
+
//#region src/client/NativeAssistantEnhancement.tsx
|
|
332
|
+
const REDUCED_MOTION = "(prefers-reduced-motion: reduce)";
|
|
333
|
+
function reducedMotion() {
|
|
334
|
+
return window.matchMedia?.(REDUCED_MOTION).matches === true;
|
|
335
|
+
}
|
|
336
|
+
function subscribeMotion(listener) {
|
|
337
|
+
const query = window.matchMedia?.(REDUCED_MOTION);
|
|
338
|
+
query?.addEventListener("change", listener);
|
|
339
|
+
return () => {
|
|
340
|
+
query?.removeEventListener("change", listener);
|
|
452
341
|
};
|
|
453
342
|
}
|
|
454
|
-
//#endregion
|
|
455
|
-
//#region \0dsh-css:/home/runner/work/dsh-codex-suite/dsh-codex-suite/packages/conversation-ui/src/client/TypewriterAssistantNodeView.module.css.mjs
|
|
456
|
-
const css$2 = ".Sp5wgW_root{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:16px;line-height:28px;display:flex}.Sp5wgW_root[data-streaming=true]{animation:.14s ease-out both Sp5wgW_dsh-codex-stream-enter}[data-chat-anchor-key][hidden=until-found][data-codex-process-hidden],[data-chat-anchor-key][hidden=until-found][data-turn-process-hidden]{clip-path:inset(50%)!important;content-visibility:hidden!important;contain-intrinsic-size:0 0!important;pointer-events:none!important;block-size:1px!important;min-block-size:0!important;inline-size:1px!important;min-inline-size:0!important;position:absolute!important;overflow:hidden!important}.Sp5wgW_body{flex-direction:column;gap:16px;min-width:0;display:flex}.Sp5wgW_markdownFlow{min-width:0}.Sp5wgW_root .Sp5wgW_markdownFlow pre{overflow-wrap:normal;white-space:pre;word-break:normal;tab-size:2;max-height:min(60vh,480px);overflow:auto}.Sp5wgW_root .Sp5wgW_markdownFlow pre code{white-space:inherit;word-break:inherit}.Sp5wgW_markdownFlow>div>:where(ul,ol)+p{margin-block-start:24px}.Sp5wgW_root[data-stream-phase=streaming],.Sp5wgW_root[data-stream-phase=process]{color:var(--dsw-alias-label-primary)}.Sp5wgW_root[data-stream-phase=streaming] .Sp5wgW_markdownFlow>div,.Sp5wgW_root[data-stream-phase=process] .Sp5wgW_markdownFlow>div{font-family:inherit;font-size:16px;font-weight:400;line-height:28px}.Sp5wgW_root[data-stream-phase=streaming] .Sp5wgW_markdownFlow strong,.Sp5wgW_root[data-stream-phase=process] .Sp5wgW_markdownFlow strong{font-weight:400!important}.Sp5wgW_root[data-stream-phase=final]{margin-block-start:2px}.Sp5wgW_turnFoldRow{color:var(--dsw-alias-label-secondary);flex-direction:column;align-items:stretch;gap:6px;margin-block:0 14px;font-size:14px;line-height:24px;display:flex}.Sp5wgW_turnFoldRow:after{background:var(--dsw-alias-border-l2);content:\"\";flex:none;width:100%;height:1px}.Sp5wgW_turnFoldButton{color:inherit;cursor:pointer;font:inherit;background:0 0;border:0;border-radius:4px;flex:none;align-self:flex-start;align-items:center;gap:6px;padding:2px 0;display:inline-flex}.Sp5wgW_turnFoldButton:hover{color:var(--dsw-alias-label-primary)}.Sp5wgW_turnFoldButton:disabled{color:inherit;cursor:default}.Sp5wgW_turnFoldButton:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:3px}.Sp5wgW_turnFoldButton>svg{flex:none}[data-chat-anchor-key]:has([data-tool-group-proxy]){display:none!important}.Sp5wgW_root[data-stream-phase=interrupted]{color:var(--dsw-alias-label-secondary)}.Sp5wgW_eventRow{min-width:0;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:24px;animation:.14s ease-out both Sp5wgW_dsh-codex-stream-enter}.Sp5wgW_eventRow[data-stream-node=tool-call],.Sp5wgW_eventRow[data-stream-node=workflow-run],.Sp5wgW_eventRow[data-stream-node=model-retry],.Sp5wgW_eventRow[data-stream-node=compaction],.Sp5wgW_eventRow[data-stream-node=manual-compaction]{margin-block:2px}.Sp5wgW_eventRow[data-stream-state=running]{color:var(--dsw-alias-label-tertiary)}.Sp5wgW_eventRow[data-stream-node=compaction] [data-compaction-disclosure],.Sp5wgW_eventRow[data-stream-node=manual-compaction] [data-compaction-disclosure]{display:none!important}.Sp5wgW_eventRow[data-stream-node=compaction] button:has([data-compaction-icon]),.Sp5wgW_eventRow[data-stream-node=manual-compaction] button:has([data-compaction-icon]){cursor:default}.Sp5wgW_eventRow[data-stream-node=compaction] button:has([data-compaction-icon]):hover,.Sp5wgW_eventRow[data-stream-node=compaction] button:has([data-compaction-icon]):focus-visible,.Sp5wgW_eventRow[data-stream-node=manual-compaction] button:has([data-compaction-icon]):hover,.Sp5wgW_eventRow[data-stream-node=manual-compaction] button:has([data-compaction-icon]):focus-visible{background:0 0!important}.Sp5wgW_eventRow[data-stream-node=compaction] [data-compaction-icon],.Sp5wgW_eventRow[data-stream-node=manual-compaction] [data-compaction-icon]{color:var(--dsw-alias-label-secondary)!important;opacity:1!important}.Sp5wgW_eventRow[data-stream-node=compaction] button:has([data-compaction-icon]),.Sp5wgW_eventRow[data-stream-node=manual-compaction] button:has([data-compaction-icon]){color:var(--dsw-alias-label-secondary)!important}.Sp5wgW_eventRow[data-stream-node=compaction] button:has([data-compaction-icon])>span,.Sp5wgW_eventRow[data-stream-node=manual-compaction] button:has([data-compaction-icon])>span{color:var(--dsw-alias-label-secondary)!important}button:has([data-compaction-icon]),button:has([data-compaction-icon])>span{color:var(--dsw-alias-label-secondary)!important;opacity:1!important}.Sp5wgW_toolGroupAnchor{min-width:0}.Sp5wgW_toolGroupFrame{background:0 0;min-width:0;margin-block:2px 8px;overflow:hidden}.Sp5wgW_toolGroupHeader{width:100%;min-height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;text-align:start;background:0 0;border:0;align-items:center;gap:6px;padding:2px 8px 2px 22px;font-size:14px;line-height:24px;display:flex;position:relative}.Sp5wgW_toolGroupHeader:hover{color:var(--dsw-alias-label-primary);background:0 0}.Sp5wgW_toolGroupHeader:focus-visible{background:0 0;outline:none}.Sp5wgW_toolGroupHeaderIcon{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex;position:absolute;inset-block-start:50%;inset-inline-start:0;transform:translateY(-50%)}.Sp5wgW_toolGroupHeaderGlyph{justify-content:center;align-items:center;width:14px;height:14px;display:inline-flex}.Sp5wgW_toolGroupHeaderLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Sp5wgW_toolGroupHeaderChevron{color:var(--dsw-alias-label-tertiary);flex:none;margin-inline-start:0;display:inline-flex}.Sp5wgW_editStats{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:none;margin-inline-start:4px;font-size:14px;line-height:24px}.Sp5wgW_toolGroupContent{min-width:0}.Sp5wgW_toolGroupFrame .Sp5wgW_eventRow[data-stream-tool-group-member]{background:0 0;border:0;border-radius:0;margin-block:0;padding-inline:8px 6px}.Sp5wgW_toolGroupFrame .Sp5wgW_toolSemanticIcon,.Sp5wgW_toolGroupFrame .Sp5wgW_streamSemanticIcon{inset-block-start:4px;transform:none}.Sp5wgW_eventRow [data-disclosure-row]{min-width:0}.Sp5wgW_eventRow[data-stream-tool-row]{position:relative}.Sp5wgW_eventRow[data-stream-tool-row][data-stream-progress=active]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row],.Sp5wgW_eventRow[data-stream-tool-row][data-stream-progress=active]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash]{position:relative;overflow:hidden}.Sp5wgW_eventRow[data-stream-tool-row][data-stream-progress=active]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row]:after,.Sp5wgW_eventRow[data-stream-tool-row][data-stream-progress=active]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash]:after{inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);content:\"\";pointer-events:none;width:300px;animation:2.6s ease-out infinite Sp5wgW_dsh-conversation-ui-think-sweep;position:absolute;left:-300px}.Sp5wgW_toolSemanticIcon,.Sp5wgW_streamSemanticIcon{z-index:1;width:14px;height:14px;color:var(--dsw-alias-label-tertiary);pointer-events:none;justify-content:center;align-items:center;display:inline-flex;position:absolute;inset-block-start:4px;inset-inline-start:0}.Sp5wgW_eventRow[data-stream-semantic-icon-owned]{position:relative}.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]>:first-child{display:contents}.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]>:first-child>:first-child:not(:last-child){opacity:1}.Sp5wgW_eventRow[data-stream-semantic-icon-owned]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]{padding-inline-start:22px}.Sp5wgW_eventRow[data-stream-semantic-icon-owned]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]>:first-child>:first-child:not(:last-child){display:none}.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]>:first-child>svg{opacity:0;color:var(--dsw-alias-label-secondary);flex:none;order:4;margin:0 0 0 6px;transition:opacity .1s,transform .12s;position:static}.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]:hover>:first-child>svg,.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded]:focus-visible>:first-child>svg{opacity:1}.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded=false]>:first-child>svg{transform:rotate(-90deg)}.Sp5wgW_eventRow[data-stream-native-disclosure]>:not(.Sp5wgW_streamSemanticIcon)>[data-disclosure-row][aria-expanded=true]>:first-child>svg{transform:rotate(0)}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row]{padding-inline-start:22px}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row]:not([aria-expanded])>:first-child{display:none}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:first-child{display:contents}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:first-child>:first-child:not(:last-child){display:none}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:nth-child(n+3){flex-grow:0}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:first-child>svg{opacity:0;color:var(--dsw-alias-label-secondary);flex:none;order:4;margin:0 0 0 6px;transition:opacity .1s,transform .12s;position:static}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]:hover>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]:focus-visible>:first-child>svg{opacity:1}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded=false]>:first-child>svg{transform:rotate(-90deg)}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded=true]>:first-child>svg{transform:rotate(0)}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash]{padding-inline-start:22px}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash]:not([aria-expanded])>:first-child{display:none}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:first-child{display:contents}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:first-child>:first-child:not(:last-child){display:none}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:nth-child(n+3){flex-grow:0}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:first-child>svg{opacity:0;color:var(--dsw-alias-label-secondary);flex:none;order:4;margin:0 0 0 6px;transition:opacity .1s,transform .12s;position:static}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]:hover>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]:focus-visible>:first-child>svg{opacity:1}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded=false]>:first-child>svg{transform:rotate(-90deg)}.Sp5wgW_eventRow[data-stream-tool-row]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded=true]>:first-child>svg{transform:rotate(0)}.Sp5wgW_nestedToolSemanticIcon{z-index:1;width:14px;height:14px;color:var(--dsw-alias-label-tertiary);pointer-events:none;justify-content:center;align-items:center;display:inline-flex;position:absolute;inset-block-start:5px;inset-inline-start:1px}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]:has(>.Sp5wgW_nestedToolSemanticIcon),.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]:has(>.Sp5wgW_nestedToolSemanticIcon){padding-inline-start:22px}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]:has(>.Sp5wgW_nestedToolSemanticIcon)>:first-child>:first-child:not(:last-child),.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]:has(>.Sp5wgW_nestedToolSemanticIcon)>:first-child>:first-child:not(:last-child){display:none}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:first-child,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:first-child{display:contents}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:nth-child(n+3),.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:nth-child(n+3){flex-grow:0}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]>:first-child>svg{opacity:0;color:var(--dsw-alias-label-secondary);flex:none;order:4;margin:0 0 0 6px;transition:opacity .1s,transform .12s;position:static}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]:hover>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded]:focus-visible>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]:hover>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded]:focus-visible>:first-child>svg{opacity:1}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded=false]>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded=false]>:first-child>svg{transform:rotate(-90deg)}.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row][aria-expanded=true]>:first-child>svg,.Sp5wgW_eventRow[data-stream-tool-row] [data-subcalls]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash][aria-expanded=true]>:first-child>svg{transform:rotate(0)}@keyframes Sp5wgW_dsh-codex-stream-enter{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.Sp5wgW_body>[data-turn-process-inline][hidden]{margin-bottom:-16px}.Sp5wgW_reasoningDisclosure{margin:0}.Sp5wgW_reasoningSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:24px;list-style-position:inside}.Sp5wgW_reasoningSummary:hover{color:var(--dsw-alias-label-primary)}.Sp5wgW_reasoningText{min-width:0;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:24px}.Sp5wgW_reasoningText>div{font-family:inherit;font-size:14px;font-weight:400;line-height:24px}.Sp5wgW_reasoningText p,.Sp5wgW_reasoningText li,.Sp5wgW_reasoningText blockquote,.Sp5wgW_reasoningText strong,.Sp5wgW_reasoningText h1,.Sp5wgW_reasoningText h2,.Sp5wgW_reasoningText h3,.Sp5wgW_reasoningText h4,.Sp5wgW_reasoningText h5,.Sp5wgW_reasoningText h6{font-size:14px;font-weight:400;line-height:24px}.Sp5wgW_reasoningText strong{font-weight:400!important}.Sp5wgW_reasoningText h1,.Sp5wgW_reasoningText h2,.Sp5wgW_reasoningText h3,.Sp5wgW_reasoningText h4,.Sp5wgW_reasoningText h5,.Sp5wgW_reasoningText h6{margin-block:8px}.Sp5wgW_reasoningText[data-stream-state=running]{color:var(--dsw-alias-label-secondary)}.Sp5wgW_think{flex-direction:column;display:flex}.Sp5wgW_thinkRow{position:relative;overflow:hidden}.Sp5wgW_think[data-state=running] .Sp5wgW_thinkRow:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite Sp5wgW_dsh-conversation-ui-think-sweep;position:absolute;left:0}@keyframes Sp5wgW_dsh-conversation-ui-think-sweep{0%{left:-300px}90%,to{left:100%}}.Sp5wgW_thinkLeading{flex-shrink:0}.Sp5wgW_thinkChevron{color:var(--dsw-alias-label-secondary)}.Sp5wgW_thinkTitle{font-weight:400}.Sp5wgW_thinkSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Sp5wgW_thinkSummary{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;font-size:14px;line-height:24px;overflow:hidden}.Sp5wgW_thinkSummary[data-follow-end]{text-overflow:clip}.Sp5wgW_thinkBody{color:var(--dsw-alias-label-tertiary);white-space:pre-wrap;word-break:break-word;padding:4px 0 4px 22px;font-size:14px;line-height:24px}.Sp5wgW_disclosureRoot{flex-direction:column;width:100%;min-width:0;display:flex}.Sp5wgW_disclosureRow{cursor:pointer;align-items:center;min-width:0;height:24px;display:flex;position:relative;overflow:hidden}.Sp5wgW_disclosureLeading{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:6px;display:inline-flex;position:relative}.Sp5wgW_disclosureTitle{color:var(--dsw-alias-label-secondary);flex:none;font-size:14px;line-height:24px}.Sp5wgW_disclosureTrailing{opacity:0;width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-left:6px;transition:opacity .1s;display:inline-flex}.Sp5wgW_disclosureRow:hover .Sp5wgW_disclosureTrailing,.Sp5wgW_disclosureRow:focus-visible .Sp5wgW_disclosureTrailing{opacity:1}.Sp5wgW_disclosureContent{visibility:visible;transition:grid-template-rows var(--ds-transition-duration,.2s) var(--ds-ease-in-out,cubic-bezier(.4, 0, .2, 1)), visibility 0s;grid-template-rows:1fr;display:grid}.Sp5wgW_disclosureContent[data-collapsed]{visibility:hidden;transition:grid-template-rows var(--ds-transition-duration,.2s) var(--ds-ease-in-out,cubic-bezier(.4, 0, .2, 1)), visibility 0s var(--ds-transition-duration,.2s);grid-template-rows:0fr}.Sp5wgW_disclosureContent>*{min-height:0;overflow:hidden}@media (prefers-reduced-motion:reduce){.Sp5wgW_root,.Sp5wgW_eventRow,.Sp5wgW_think[data-state=running] .Sp5wgW_thinkRow:after{animation:none}.Sp5wgW_eventRow[data-stream-tool-row][data-stream-progress=active]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>[data-tool]>*>[data-disclosure-row]:after,.Sp5wgW_eventRow[data-stream-tool-row][data-stream-progress=active]>[data-chat-call-id]>[data-slot=\"tool.call.toolview\"]>*>[data-sample=bash]:after{animation:none}.Sp5wgW_disclosureContent,.Sp5wgW_disclosureContent[data-collapsed]{transition:none}}.Sp5wgW_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;padding:0 6px;font-size:11px;line-height:18px}.Sp5wgW_visuallyHidden{clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.Sp5wgW_follow{min-width:0}@supports (text-box-trim:trim-both){.Sp5wgW_root :is(p,h1,h2,h3,h4,h5,h6,blockquote):not(:has(code)){text-box-trim:trim-both;text-box-edge:text}}";
|
|
457
|
-
const tagId$2 = "@jcy2387/dsh-conversation-ui/TypewriterAssistantNodeView.module.css";
|
|
458
|
-
if (typeof document !== "undefined") {
|
|
459
|
-
let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]");
|
|
460
|
-
if (tag === null) {
|
|
461
|
-
tag = document.createElement("style");
|
|
462
|
-
tag.dataset.plugin = "@jcy2387/dsh-conversation-ui";
|
|
463
|
-
tag.dataset.pluginCss = tagId$2;
|
|
464
|
-
document.head.appendChild(tag);
|
|
465
|
-
}
|
|
466
|
-
tag.textContent = css$2;
|
|
467
|
-
}
|
|
468
|
-
var TypewriterAssistantNodeView_module_css_default = {
|
|
469
|
-
"toolGroupHeaderChevron": "Sp5wgW_toolGroupHeaderChevron",
|
|
470
|
-
"thinkBody": "Sp5wgW_thinkBody",
|
|
471
|
-
"toolGroupHeaderLabel": "Sp5wgW_toolGroupHeaderLabel",
|
|
472
|
-
"thinkSummary": "Sp5wgW_thinkSummary",
|
|
473
|
-
"follow": "Sp5wgW_follow",
|
|
474
|
-
"disclosureContent": "Sp5wgW_disclosureContent",
|
|
475
|
-
"toolSemanticIcon": "Sp5wgW_toolSemanticIcon",
|
|
476
|
-
"body": "Sp5wgW_body",
|
|
477
|
-
"root": "Sp5wgW_root",
|
|
478
|
-
"editStats": "Sp5wgW_editStats",
|
|
479
|
-
"reasoningText": "Sp5wgW_reasoningText",
|
|
480
|
-
"disclosureRow": "Sp5wgW_disclosureRow",
|
|
481
|
-
"disclosureLeading": "Sp5wgW_disclosureLeading",
|
|
482
|
-
"thinkLeading": "Sp5wgW_thinkLeading",
|
|
483
|
-
"thinkTitle": "Sp5wgW_thinkTitle",
|
|
484
|
-
"disclosureTitle": "Sp5wgW_disclosureTitle",
|
|
485
|
-
"streamSemanticIcon": "Sp5wgW_streamSemanticIcon",
|
|
486
|
-
"think": "Sp5wgW_think",
|
|
487
|
-
"disclosureTrailing": "Sp5wgW_disclosureTrailing",
|
|
488
|
-
"toolGroupFrame": "Sp5wgW_toolGroupFrame",
|
|
489
|
-
"nestedToolSemanticIcon": "Sp5wgW_nestedToolSemanticIcon",
|
|
490
|
-
"disclosureRoot": "Sp5wgW_disclosureRoot",
|
|
491
|
-
"eventRow": "Sp5wgW_eventRow",
|
|
492
|
-
"reasoningSummary": "Sp5wgW_reasoningSummary",
|
|
493
|
-
"toolGroupHeaderIcon": "Sp5wgW_toolGroupHeaderIcon",
|
|
494
|
-
"dsh-conversation-ui-think-sweep": "Sp5wgW_dsh-conversation-ui-think-sweep",
|
|
495
|
-
"stopped": "Sp5wgW_stopped",
|
|
496
|
-
"thinkRow": "Sp5wgW_thinkRow",
|
|
497
|
-
"visuallyHidden": "Sp5wgW_visuallyHidden",
|
|
498
|
-
"toolGroupContent": "Sp5wgW_toolGroupContent",
|
|
499
|
-
"markdownFlow": "Sp5wgW_markdownFlow",
|
|
500
|
-
"turnFoldRow": "Sp5wgW_turnFoldRow",
|
|
501
|
-
"toolGroupHeaderGlyph": "Sp5wgW_toolGroupHeaderGlyph",
|
|
502
|
-
"toolGroupHeader": "Sp5wgW_toolGroupHeader",
|
|
503
|
-
"toolGroupAnchor": "Sp5wgW_toolGroupAnchor",
|
|
504
|
-
"reasoningDisclosure": "Sp5wgW_reasoningDisclosure",
|
|
505
|
-
"turnFoldButton": "Sp5wgW_turnFoldButton",
|
|
506
|
-
"thinkChevron": "Sp5wgW_thinkChevron",
|
|
507
|
-
"dsh-codex-stream-enter": "Sp5wgW_dsh-codex-stream-enter",
|
|
508
|
-
"thinkSeparator": "Sp5wgW_thinkSeparator"
|
|
509
|
-
};
|
|
510
|
-
//#endregion
|
|
511
|
-
//#region src/client/FollowHost.tsx
|
|
512
343
|
/**
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
*
|
|
344
|
+
* Enhance assistant input while delegating every visual and owner prop to the
|
|
345
|
+
* registered renderer. DSH retains Markdown, images, work-details policy,
|
|
346
|
+
* disclosure resets, interrupted output, and final-answer actions.
|
|
347
|
+
* @param NativeAssistant - existing assistant renderer, including memo components.
|
|
348
|
+
* @param preference - live reveal and auto-expand preferences.
|
|
349
|
+
* @returns a renderer with no additional DOM or styles.
|
|
519
350
|
*/
|
|
520
|
-
function
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
const DEFAULT_CONVERSATION_SETTINGS = { thinkAutoExpand: true };
|
|
547
|
-
//#endregion
|
|
548
|
-
//#region src/client/useSearchableHidden.ts
|
|
549
|
-
/** Keep a hidden subtree mounted and reveal it for focus or browser find. */
|
|
550
|
-
function useSearchableHidden(hidden, reveal) {
|
|
551
|
-
const ref = (0, react.useRef)(null);
|
|
552
|
-
(0, react.useLayoutEffect)(() => {
|
|
553
|
-
const element = ref.current;
|
|
554
|
-
if (element === null) return;
|
|
555
|
-
if (hidden && element.contains(element.ownerDocument.activeElement)) {
|
|
556
|
-
reveal();
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
if (hidden) element.setAttribute("hidden", "until-found");
|
|
560
|
-
else element.removeAttribute("hidden");
|
|
561
|
-
}, [hidden, reveal]);
|
|
562
|
-
(0, react.useEffect)(() => {
|
|
563
|
-
const element = ref.current;
|
|
564
|
-
if (element === null) return;
|
|
565
|
-
element.addEventListener("beforematch", reveal);
|
|
566
|
-
return () => {
|
|
567
|
-
element.removeEventListener("beforematch", reveal);
|
|
568
|
-
};
|
|
569
|
-
}, [reveal]);
|
|
570
|
-
return ref;
|
|
571
|
-
}
|
|
572
|
-
//#endregion
|
|
573
|
-
//#region src/client/useChatSeatHidden.ts
|
|
574
|
-
const OWNER_ATTR = "data-codex-process-hidden";
|
|
575
|
-
/**
|
|
576
|
-
* Apply searchable hiding to the outer Chat row for a proven paginated-history
|
|
577
|
-
* fallback. Resolving the seat on every render follows rows moved by Tool-group
|
|
578
|
-
* portals without leaving ownership or beforematch listeners on stale seats.
|
|
579
|
-
*/
|
|
580
|
-
function useChatSeatHidden(hidden, reveal) {
|
|
581
|
-
const rootRef = (0, react.useRef)(null);
|
|
582
|
-
const revealRef = (0, react.useRef)(reveal);
|
|
583
|
-
revealRef.current = reveal;
|
|
584
|
-
const ref = (0, react.useCallback)((element) => {
|
|
585
|
-
rootRef.current = element;
|
|
586
|
-
}, []);
|
|
587
|
-
(0, react.useLayoutEffect)(() => {
|
|
588
|
-
const seat = rootRef.current?.closest("[data-chat-anchor-key]");
|
|
589
|
-
if (seat === null || seat === void 0) return;
|
|
590
|
-
if (!hidden) {
|
|
591
|
-
if (seat.hasAttribute(OWNER_ATTR)) {
|
|
592
|
-
seat.removeAttribute(OWNER_ATTR);
|
|
593
|
-
seat.removeAttribute("hidden");
|
|
351
|
+
function enhanceNativeAssistant(NativeAssistant, preference) {
|
|
352
|
+
function EnhancedAssistant(props) {
|
|
353
|
+
const live = (0, react.useSyncExternalStore)(preference.subscribe, preference.getSnapshot, preference.getSnapshot);
|
|
354
|
+
const autoExpand = live.thinkAutoExpand;
|
|
355
|
+
const reduced = (0, react.useSyncExternalStore)(subscribeMotion, reducedMotion, () => false);
|
|
356
|
+
const running = props.node.data.status === "running";
|
|
357
|
+
const blocks = props.node.data.blocks;
|
|
358
|
+
const source = (0, react.useMemo)(() => blocks.flatMap((block) => {
|
|
359
|
+
if (block.kind !== "text" && block.kind !== "reasoning") return [];
|
|
360
|
+
if (props.groupPart === "reasoning" && block.kind !== "reasoning") return [];
|
|
361
|
+
if (props.groupPart === "response" && block.kind === "reasoning") return [];
|
|
362
|
+
return [block.text];
|
|
363
|
+
}).join(""), [blocks, props.groupPart]);
|
|
364
|
+
const typewriter = live.mode === "typewriter" && !reduced;
|
|
365
|
+
const [draining, setDraining] = (0, react.useState)(running);
|
|
366
|
+
const revealing = typewriter && (running || draining);
|
|
367
|
+
const displayed = useConversationContent(source, {
|
|
368
|
+
enabled: revealing,
|
|
369
|
+
preset: live.preset,
|
|
370
|
+
steadyCps: live.revealCharsPerSec,
|
|
371
|
+
settleCps: Math.max(live.revealCharsPerSec * 4, 240)
|
|
372
|
+
});
|
|
373
|
+
(0, react.useEffect)(() => {
|
|
374
|
+
if (!typewriter) {
|
|
375
|
+
if (draining) setDraining(false);
|
|
376
|
+
return;
|
|
594
377
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const beforeMatch = () => {
|
|
598
|
-
revealRef.current();
|
|
599
|
-
};
|
|
600
|
-
seat.addEventListener("beforematch", beforeMatch);
|
|
601
|
-
const applyHidden = () => {
|
|
602
|
-
if (seat.contains(seat.ownerDocument.activeElement)) {
|
|
603
|
-
revealRef.current();
|
|
378
|
+
if (running) {
|
|
379
|
+
if (!draining) setDraining(true);
|
|
604
380
|
return;
|
|
605
381
|
}
|
|
606
|
-
if (
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
rootRef.current = element;
|
|
633
|
-
}, []);
|
|
634
|
-
(0, react.useLayoutEffect)(() => {
|
|
635
|
-
if (!visible) return;
|
|
636
|
-
const seat = rootRef.current?.closest("[data-chat-anchor-key]");
|
|
637
|
-
if (seat === null || seat === void 0) return;
|
|
638
|
-
const applyVisible = () => {
|
|
639
|
-
seat.setAttribute(VISIBLE_OWNER_ATTR, "");
|
|
640
|
-
seat.removeAttribute("hidden");
|
|
641
|
-
};
|
|
642
|
-
applyVisible();
|
|
643
|
-
const observer = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(() => {
|
|
644
|
-
applyVisible();
|
|
645
|
-
});
|
|
646
|
-
observer?.observe(seat, {
|
|
647
|
-
attributes: true,
|
|
648
|
-
attributeFilter: ["hidden"]
|
|
649
|
-
});
|
|
650
|
-
return () => {
|
|
651
|
-
observer?.disconnect();
|
|
652
|
-
seat.removeAttribute(VISIBLE_OWNER_ATTR);
|
|
653
|
-
};
|
|
654
|
-
});
|
|
655
|
-
return ref;
|
|
656
|
-
}
|
|
657
|
-
//#endregion
|
|
658
|
-
//#region src/client/turnProcessFallback.ts
|
|
659
|
-
const INDEPENDENT_KINDS = /* @__PURE__ */ new Set([
|
|
660
|
-
"system-prompt",
|
|
661
|
-
"user",
|
|
662
|
-
"steering",
|
|
663
|
-
"turn-trigger",
|
|
664
|
-
"turn-process",
|
|
665
|
-
"turn-error",
|
|
666
|
-
"turn-max-tokens",
|
|
667
|
-
"turn-tail"
|
|
668
|
-
]);
|
|
669
|
-
function isChatNode(value) {
|
|
670
|
-
if (value === null || typeof value !== "object") return false;
|
|
671
|
-
const candidate = value;
|
|
672
|
-
return typeof candidate.kind === "string" && typeof candidate.anchorSeq === "number" && candidate.location !== void 0 && candidate.data !== void 0;
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Prove that this Turn's actual start event is present in the loaded location.
|
|
676
|
-
* A Chat row does not normally anchor at `turn/start`, so scanning row anchors
|
|
677
|
-
* cannot establish this boundary; the shared Turn location is the authority.
|
|
678
|
-
*/
|
|
679
|
-
function loadedProcessStart(node, turnProcess) {
|
|
680
|
-
if (!isChatNode(node) || turnProcess === void 0) return false;
|
|
681
|
-
const location = node.location;
|
|
682
|
-
if (location.kind !== "turn" && location.kind !== "step") return false;
|
|
683
|
-
return location.turn.start?.seq === turnProcess.spec.processStartSeq;
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Current DSH disables native folding for every loaded Turn while any older
|
|
687
|
-
* history page remains. In Compact mode Codex presentation can safely fall
|
|
688
|
-
* back only when the loaded window includes this Turn's start boundary.
|
|
689
|
-
*/
|
|
690
|
-
function usesTurnProcessFallback(node, turnProcess, gate) {
|
|
691
|
-
if (!gate.compactTranscript || !gate.historyIncomplete || !gate.processStartLoaded) return false;
|
|
692
|
-
if (!isChatNode(node) || turnProcess === void 0 || turnProcess.foldable) return false;
|
|
693
|
-
const location = node.location;
|
|
694
|
-
if (location.kind !== "turn" && location.kind !== "step") return false;
|
|
695
|
-
const spec = turnProcess.spec;
|
|
696
|
-
if (location.turn.status !== "closed" || location.turn.end?.data.reason.kind !== "completed" || location.turn.turn !== spec.turn || spec.answerAnchorSeq === null) return false;
|
|
697
|
-
return spec.inlineReasoning || spec.messageCount > 0 || spec.toolCallCount > 0 || spec.subagentCount > 0;
|
|
698
|
-
}
|
|
699
|
-
/** Whether this row belongs to the fallback's bounded process window. */
|
|
700
|
-
function isFallbackProcessMember(node, turnProcess, gate) {
|
|
701
|
-
if (!isChatNode(node) || !usesTurnProcessFallback(node, turnProcess, gate) || turnProcess === void 0) return false;
|
|
702
|
-
const answerAnchor = turnProcess.spec.answerAnchorSeq;
|
|
703
|
-
return answerAnchor !== null && !INDEPENDENT_KINDS.has(node.kind) && node.anchorSeq >= turnProcess.spec.processStartSeq && node.anchorSeq < answerAnchor;
|
|
704
|
-
}
|
|
705
|
-
/** Whether this Assistant is the finalized answer that can host fallback control. */
|
|
706
|
-
function ownsFallbackProcessControl(node, turnProcess, gate) {
|
|
707
|
-
return usesTurnProcessFallback(node, turnProcess, gate) && turnProcess?.spec.answerStep === node.data.step;
|
|
708
|
-
}
|
|
709
|
-
//#endregion
|
|
710
|
-
//#region src/client/TranscriptViewBridge.tsx
|
|
711
|
-
const CompactTranscriptContext = (0, react.createContext)(false);
|
|
712
|
-
/** Read the authoritative DSH transcript preference inside Chat node seats. */
|
|
713
|
-
function useCompactTranscript() {
|
|
714
|
-
return (0, react.useContext)(CompactTranscriptContext);
|
|
715
|
-
}
|
|
716
|
-
/** Preserve the native Chat view while exposing its injected preference to descendants. */
|
|
717
|
-
function wrapTranscriptView(Inner) {
|
|
718
|
-
return function TranscriptViewBridge(props) {
|
|
719
|
-
const compact = props.usePresentation((policy) => !policy.liveProcessDetail && policy.foldCompletedTurns);
|
|
720
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CompactTranscriptContext.Provider, {
|
|
721
|
-
value: compact,
|
|
722
|
-
children: (0, react.createElement)(Inner, props)
|
|
723
|
-
});
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
//#endregion
|
|
727
|
-
//#region src/client/TypewriterAssistantNodeView.tsx
|
|
728
|
-
function localPathMediaUrl(base, value) {
|
|
729
|
-
let path;
|
|
730
|
-
try {
|
|
731
|
-
path = decodeURIComponent(value.split(/[?#]/u)[0] ?? "");
|
|
732
|
-
} catch {
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
return fileMediaUrl(base, path);
|
|
736
|
-
}
|
|
737
|
-
function usePrefersReducedMotion() {
|
|
738
|
-
const [reduced, setReduced] = (0, react.useState)(() => typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true);
|
|
739
|
-
(0, react.useEffect)(() => {
|
|
740
|
-
if (typeof window === "undefined" || window.matchMedia === void 0) return;
|
|
741
|
-
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
742
|
-
const onChange = () => setReduced(query.matches);
|
|
743
|
-
query.addEventListener("change", onChange);
|
|
744
|
-
return () => query.removeEventListener("change", onChange);
|
|
745
|
-
}, []);
|
|
746
|
-
return reduced;
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Smooth streaming text arm. While the reply runs, the accumulated source is
|
|
750
|
-
* revealed through the smoother at a rate that tracks the model's arrival
|
|
751
|
-
* and rendered by the Harness `MarkdownText`
|
|
752
|
-
* streaming arm (incremental parse, frozen non-tail blocks), so there is no
|
|
753
|
-
* raw-text tail and no text-to-markdown swap: the tree stays markdown
|
|
754
|
-
* throughout. DSH ChatView remains the sole owner of viewport follow while
|
|
755
|
-
* this component only smooths content reveal. Once the stream closes and the
|
|
756
|
-
* reveal queue drains, the settled full parse (KaTeX math, fence highlighting, file
|
|
757
|
-
* mentions) swaps in exactly once.
|
|
758
|
-
*/
|
|
759
|
-
function AnimatedMarkdownText({ text, labels, fileMentions, pathImages, streaming, announce, ownFollow, mode, preset, revealCharsPerSec, scrollSpeedPxPerSec, maxScrollSpeedPxPerSec, shouldHoldBack }) {
|
|
760
|
-
const reduced = usePrefersReducedMotion();
|
|
761
|
-
const [typing, setTyping] = (0, react.useState)(streaming);
|
|
762
|
-
const speedCpsRef = (0, react.useRef)(35);
|
|
763
|
-
const displayed = useConversationContent(text, {
|
|
764
|
-
enabled: mode === "typewriter" && typing && !reduced,
|
|
765
|
-
preset,
|
|
766
|
-
shouldHoldBack,
|
|
767
|
-
steadyCps: mode === "typewriter" ? revealCharsPerSec : void 0,
|
|
768
|
-
speedCpsRef
|
|
769
|
-
});
|
|
770
|
-
const shown = reduced || mode === "teleprompter" ? text : displayed;
|
|
771
|
-
const live = typing && !reduced;
|
|
772
|
-
(0, react.useEffect)(() => {
|
|
773
|
-
if (typing && !streaming && shown.length === text.length) setTyping(false);
|
|
774
|
-
}, [
|
|
775
|
-
shown,
|
|
776
|
-
streaming,
|
|
777
|
-
text,
|
|
778
|
-
typing
|
|
779
|
-
]);
|
|
780
|
-
if (live) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [announce && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
781
|
-
className: TypewriterAssistantNodeView_module_css_default.visuallyHidden,
|
|
782
|
-
"aria-live": "polite",
|
|
783
|
-
children: text
|
|
784
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FollowHost, {
|
|
785
|
-
active: ownFollow,
|
|
786
|
-
speedCpsRef,
|
|
787
|
-
minSpeedPxPerSec: scrollSpeedPxPerSec,
|
|
788
|
-
maxSpeedPxPerSec: maxScrollSpeedPxPerSec,
|
|
789
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
790
|
-
className: TypewriterAssistantNodeView_module_css_default.markdownFlow,
|
|
791
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
792
|
-
text: shown,
|
|
793
|
-
streaming: true,
|
|
794
|
-
labels,
|
|
795
|
-
pathImages
|
|
796
|
-
})
|
|
797
|
-
})
|
|
798
|
-
})] });
|
|
799
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
800
|
-
className: TypewriterAssistantNodeView_module_css_default.markdownFlow,
|
|
801
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
802
|
-
text,
|
|
803
|
-
labels,
|
|
804
|
-
fileMentions,
|
|
805
|
-
pathImages
|
|
806
|
-
})
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Think is part of the Turn document flow rather than a second disclosure
|
|
811
|
-
* card. It uses the same streaming smoother as ordinary assistant prose, so
|
|
812
|
-
* reasoning reads as a continuous body while the surrounding Turn still owns
|
|
813
|
-
* process folding and viewport follow.
|
|
814
|
-
*/
|
|
815
|
-
function AnimatedReasoning({ text, labels, running, mode, preset, revealCharsPerSec, shouldHoldBack }) {
|
|
816
|
-
const reduced = usePrefersReducedMotion();
|
|
817
|
-
const [typing, setTyping] = (0, react.useState)(running);
|
|
818
|
-
const speedCpsRef = (0, react.useRef)(35);
|
|
819
|
-
const displayed = useConversationContent(text, {
|
|
820
|
-
enabled: mode === "typewriter" && typing && !reduced,
|
|
821
|
-
preset,
|
|
822
|
-
shouldHoldBack,
|
|
823
|
-
steadyCps: mode === "typewriter" ? revealCharsPerSec : void 0,
|
|
824
|
-
speedCpsRef
|
|
825
|
-
});
|
|
826
|
-
const shown = reduced || mode === "teleprompter" ? text : displayed;
|
|
827
|
-
(0, react.useEffect)(() => {
|
|
828
|
-
if (typing && !running && shown.length === text.length) setTyping(false);
|
|
829
|
-
}, [
|
|
830
|
-
shown,
|
|
831
|
-
running,
|
|
832
|
-
text,
|
|
833
|
-
typing
|
|
834
|
-
]);
|
|
835
|
-
const live = typing && !reduced;
|
|
836
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
837
|
-
className: TypewriterAssistantNodeView_module_css_default.reasoningText,
|
|
838
|
-
"data-stream-node": "reasoning",
|
|
839
|
-
"data-stream-state": running ? "running" : "settled",
|
|
840
|
-
"data-stream-reasoning": "",
|
|
841
|
-
children: live ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
842
|
-
text: shown,
|
|
843
|
-
streaming: true,
|
|
844
|
-
labels
|
|
845
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
846
|
-
text,
|
|
847
|
-
labels
|
|
848
|
-
})
|
|
849
|
-
});
|
|
850
|
-
}
|
|
851
|
-
function ProcessReasoning({ hidden, reveal, autoExpand, t, children }) {
|
|
852
|
-
const ref = useSearchableHidden(hidden, reveal);
|
|
853
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
854
|
-
ref,
|
|
855
|
-
"data-turn-process-inline": hidden || void 0,
|
|
856
|
-
children: autoExpand ? children : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
857
|
-
className: TypewriterAssistantNodeView_module_css_default.reasoningDisclosure,
|
|
858
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", {
|
|
859
|
-
className: TypewriterAssistantNodeView_module_css_default.reasoningSummary,
|
|
860
|
-
children: t("message.turnProcess.thoughtForAWhile")
|
|
861
|
-
}), children]
|
|
862
|
-
})
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
/**
|
|
866
|
-
* Assistant renderer for the Codex-style event stream. Teleprompter mode
|
|
867
|
-
* publishes each latest model snapshot immediately; typewriter mode reveals
|
|
868
|
-
* complete grapheme clusters at the configured rate. Reasoning stays in the
|
|
869
|
-
* same document flow as ordinary prose, and the final Assistant message is marked separately
|
|
870
|
-
* from intermediate process updates. The FPS guard holds offscreen typewriter
|
|
871
|
-
* commits when the frame rate is degraded. Settled text uses the full Markdown
|
|
872
|
-
* pipeline.
|
|
873
|
-
*/
|
|
874
|
-
const TypewriterAssistantNodeView = (0, react.memo)(function TypewriterAssistantNodeView({ mode = DEFAULT_CONVERSATION_CONFIG.mode, preset = DEFAULT_CONVERSATION_CONFIG.preset, revealCharsPerSec = DEFAULT_CONVERSATION_CONFIG.revealCharsPerSec, scrollSpeedPxPerSec = DEFAULT_CONVERSATION_CONFIG.scrollSpeedPxPerSec, maxScrollSpeedPxPerSec = DEFAULT_CONVERSATION_CONFIG.maxScrollSpeedPxPerSec, thinkAutoExpand = DEFAULT_CONVERSATION_SETTINGS.thinkAutoExpand, node, groupPart, turnProcess, useTurnData, useSession, openFile, renderMessageImages, fileMentions, t }) {
|
|
875
|
-
const data = node.data;
|
|
876
|
-
const streaming = data.status === "running";
|
|
877
|
-
const reducedMotion = usePrefersReducedMotion();
|
|
878
|
-
const { ref: guardRef, shouldHoldBack } = useFpsGuard(streaming);
|
|
879
|
-
const rootSpeedRef = (0, react.useRef)(35);
|
|
880
|
-
const turn = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
|
|
881
|
-
const fallbackGate = {
|
|
882
|
-
compactTranscript: useCompactTranscript(),
|
|
883
|
-
historyIncomplete: useSession((snapshot) => snapshot.hasMore),
|
|
884
|
-
processStartLoaded: loadedProcessStart(node, turnProcess)
|
|
885
|
-
};
|
|
886
|
-
const tail = useTurnData("turn-tail");
|
|
887
|
-
const finalAnswer = data.status === "settled" && data.finalNode !== void 0 && tail?.closing?.finalNode.seq === data.finalNode.seq;
|
|
888
|
-
const phase = streaming ? "streaming" : data.status === "interrupted" ? "interrupted" : finalAnswer ? "final" : "process";
|
|
889
|
-
const owner = (0, react.useMemo)(() => {
|
|
890
|
-
if (turn?.status !== "closed" || data.finalNode === void 0) return void 0;
|
|
891
|
-
if (tail?.closing?.finalNode.seq !== data.finalNode.seq) return void 0;
|
|
892
|
-
return {
|
|
893
|
-
turn,
|
|
894
|
-
seq: data.finalNode.seq,
|
|
895
|
-
openFile
|
|
896
|
-
};
|
|
897
|
-
}, [
|
|
898
|
-
data.finalNode,
|
|
899
|
-
openFile,
|
|
900
|
-
tail,
|
|
901
|
-
turn
|
|
902
|
-
]);
|
|
903
|
-
const mentions = (0, react.useMemo)(() => owner === void 0 ? void 0 : fileMentions(owner), [fileMentions, owner]);
|
|
904
|
-
const labels = (0, react.useMemo)(() => ({
|
|
905
|
-
code: {
|
|
906
|
-
copyLabel: t("copy"),
|
|
907
|
-
copiedLabel: t("copied")
|
|
908
|
-
},
|
|
909
|
-
footnotes: t("markdown.footnotes")
|
|
910
|
-
}), [t]);
|
|
911
|
-
const pathImages = (0, react.useMemo)(() => ({ resolve: (value) => localPathMediaUrl(document.baseURI, value) }), []);
|
|
912
|
-
const blocks = (0, react.useMemo)(() => groupPart === "reasoning" ? data.blocks.filter((block) => block.kind === "reasoning") : groupPart === "response" ? data.blocks.filter((block) => block.kind !== "reasoning") : data.blocks, [data.blocks, groupPart]);
|
|
913
|
-
const hasVisible = streaming || data.status === "interrupted" || blocks.some((block) => block.kind !== "tool-call");
|
|
914
|
-
const fallbackControl = ownsFallbackProcessControl(node, turnProcess, fallbackGate);
|
|
915
|
-
const fallbackMember = isFallbackProcessMember(node, turnProcess, fallbackGate);
|
|
916
|
-
const reasoningHidden = (turnProcess?.foldable === true || fallbackControl) && turnProcess?.spec.answerStep === data.step && turnProcess.spec.inlineReasoning && !turnProcess.open;
|
|
917
|
-
const fallbackHidden = fallbackMember && turnProcess?.open === false;
|
|
918
|
-
const revealProcess = (0, react.useCallback)(() => {
|
|
919
|
-
turnProcess?.setOpen(true);
|
|
920
|
-
}, [turnProcess]);
|
|
921
|
-
const seatRef = useChatSeatHidden(fallbackHidden, revealProcess);
|
|
922
|
-
const rootRef = (0, react.useCallback)((element) => {
|
|
923
|
-
guardRef(element);
|
|
924
|
-
seatRef(element);
|
|
925
|
-
}, [guardRef, seatRef]);
|
|
926
|
-
if (!hasVisible) return null;
|
|
927
|
-
const rendered = [];
|
|
928
|
-
const last = blocks.length - 1;
|
|
929
|
-
let lastFollow = -1;
|
|
930
|
-
for (let index = 0; index < blocks.length; index += 1) {
|
|
931
|
-
const kind = blocks[index]?.kind;
|
|
932
|
-
if (kind === "text" || kind === "reasoning") lastFollow = index;
|
|
933
|
-
}
|
|
934
|
-
let nodeTailBlock;
|
|
935
|
-
for (let index = data.blocks.length - 1; index >= 0; index -= 1) {
|
|
936
|
-
const kind = data.blocks[index]?.kind;
|
|
937
|
-
if (kind === "text" || kind === "reasoning") {
|
|
938
|
-
nodeTailBlock = data.blocks[index];
|
|
939
|
-
break;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
const followsTail = lastFollow >= 0 && lastFollow === last && blocks[lastFollow] === nodeTailBlock;
|
|
943
|
-
const stoppedHere = data.status === "interrupted" && (groupPart === void 0 || groupPart === "response" || !data.blocks.some((block) => block !== void 0 && block.kind !== "reasoning" && block.kind !== "tool-call"));
|
|
944
|
-
for (let index = 0; index < blocks.length; index += 1) {
|
|
945
|
-
const block = blocks[index];
|
|
946
|
-
if (block === void 0) continue;
|
|
947
|
-
switch (block.kind) {
|
|
948
|
-
case "text":
|
|
949
|
-
rendered.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnimatedMarkdownText, {
|
|
950
|
-
text: block.text,
|
|
951
|
-
labels,
|
|
952
|
-
fileMentions: mentions,
|
|
953
|
-
pathImages,
|
|
954
|
-
streaming,
|
|
955
|
-
announce: index === last,
|
|
956
|
-
ownFollow: !streaming && index === lastFollow,
|
|
957
|
-
mode,
|
|
958
|
-
preset,
|
|
959
|
-
revealCharsPerSec,
|
|
960
|
-
scrollSpeedPxPerSec,
|
|
961
|
-
maxScrollSpeedPxPerSec,
|
|
962
|
-
shouldHoldBack
|
|
963
|
-
}, index));
|
|
964
|
-
break;
|
|
965
|
-
case "reasoning":
|
|
966
|
-
rendered.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessReasoning, {
|
|
967
|
-
hidden: reasoningHidden,
|
|
968
|
-
reveal: revealProcess,
|
|
969
|
-
autoExpand: thinkAutoExpand || !streaming,
|
|
970
|
-
t,
|
|
971
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnimatedReasoning, {
|
|
972
|
-
text: block.text,
|
|
973
|
-
labels,
|
|
974
|
-
running: streaming && index === last,
|
|
975
|
-
mode,
|
|
976
|
-
preset,
|
|
977
|
-
revealCharsPerSec,
|
|
978
|
-
shouldHoldBack
|
|
382
|
+
if (draining && displayed.length >= source.length) setDraining(false);
|
|
383
|
+
}, [
|
|
384
|
+
displayed.length,
|
|
385
|
+
draining,
|
|
386
|
+
running,
|
|
387
|
+
source.length,
|
|
388
|
+
typewriter
|
|
389
|
+
]);
|
|
390
|
+
const shown = revealing ? displayed : source;
|
|
391
|
+
const node = (0, react.useMemo)(() => {
|
|
392
|
+
if (shown === source) return props.node;
|
|
393
|
+
let remaining = shown.length;
|
|
394
|
+
return {
|
|
395
|
+
...props.node,
|
|
396
|
+
data: {
|
|
397
|
+
...props.node.data,
|
|
398
|
+
blocks: blocks.map((block) => {
|
|
399
|
+
if (block.kind !== "text" && block.kind !== "reasoning") return block;
|
|
400
|
+
if (props.groupPart === "reasoning" && block.kind !== "reasoning") return block;
|
|
401
|
+
if (props.groupPart === "response" && block.kind === "reasoning") return block;
|
|
402
|
+
const text = block.text.slice(0, remaining);
|
|
403
|
+
remaining = Math.max(0, remaining - block.text.length);
|
|
404
|
+
return text === block.text ? block : {
|
|
405
|
+
...block,
|
|
406
|
+
text
|
|
407
|
+
};
|
|
979
408
|
})
|
|
980
|
-
}, index));
|
|
981
|
-
break;
|
|
982
|
-
case "image": {
|
|
983
|
-
const start = index;
|
|
984
|
-
const group = [block];
|
|
985
|
-
while (index + 1 < blocks.length) {
|
|
986
|
-
const next = blocks[index + 1];
|
|
987
|
-
if (next === void 0 || next.kind !== "image") break;
|
|
988
|
-
group.push(next);
|
|
989
|
-
index += 1;
|
|
990
409
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
children: t("message.stopped")
|
|
1021
|
-
})]
|
|
1022
|
-
})
|
|
1023
|
-
})
|
|
1024
|
-
});
|
|
1025
|
-
});
|
|
1026
|
-
//#endregion
|
|
1027
|
-
//#region src/client/turnElapsed.ts
|
|
1028
|
-
function formatRunDuration(ms, t) {
|
|
1029
|
-
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
1030
|
-
const hours = Math.floor(total / 3600);
|
|
1031
|
-
const minutes = Math.floor(total / 60) % 60;
|
|
1032
|
-
const seconds = total % 60;
|
|
1033
|
-
const parts = [];
|
|
1034
|
-
if (hours > 0) parts.push(String(hours), t("duration.hourUnit"));
|
|
1035
|
-
if (total >= 60) parts.push(String(minutes), t("duration.minuteUnit"));
|
|
1036
|
-
parts.push(String(seconds), t("duration.secondUnit"));
|
|
1037
|
-
return parts.join("");
|
|
1038
|
-
}
|
|
1039
|
-
function formatTurnElapsed(ms, t) {
|
|
1040
|
-
const duration = formatRunDuration(ms, t);
|
|
1041
|
-
const label = t("message.turnProcess.took");
|
|
1042
|
-
return `${label === "已完成,用时 " ? "耗时 " : label}${duration}`;
|
|
1043
|
-
}
|
|
1044
|
-
//#endregion
|
|
1045
|
-
//#region src/client/CodexTurnProcessNodeView.tsx
|
|
1046
|
-
/** Shared Codex disclosure button for native and paginated-history fallback seats. */
|
|
1047
|
-
function CodexTurnProcessControl({ turn, messageCount, toolCallCount, subagentCount, elapsedMs, reason, canCollapse, turnProcess, t, fallback = false, rootRef }) {
|
|
1048
|
-
const label = reason === "aborted" ? t("message.stopped") : reason === "error" ? t("message.turnProcess.failed") : elapsedMs === void 0 ? t("message.turnProcess.worked") : formatTurnElapsed(Math.max(1e3, elapsedMs), t);
|
|
1049
|
-
const announcement = reason === "aborted" ? t("message.stopped") : reason === "error" ? t("message.turnProcess.failed") : t("message.turnProcess.worked");
|
|
1050
|
-
const open = !canCollapse || turnProcess.open;
|
|
1051
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1052
|
-
className: TypewriterAssistantNodeView_module_css_default.visuallyHidden,
|
|
1053
|
-
role: "status",
|
|
1054
|
-
"aria-live": "polite",
|
|
1055
|
-
"aria-atomic": "true",
|
|
1056
|
-
children: announcement
|
|
1057
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1058
|
-
ref: rootRef,
|
|
1059
|
-
className: TypewriterAssistantNodeView_module_css_default.turnFoldRow,
|
|
1060
|
-
"data-turn-fold-row": "",
|
|
1061
|
-
"data-turn-fold-state": reason === "aborted" ? "stopped" : reason === "error" ? "failed" : "completed",
|
|
1062
|
-
"data-turn-process-fallback": fallback || void 0,
|
|
1063
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1064
|
-
type: "button",
|
|
1065
|
-
className: TypewriterAssistantNodeView_module_css_default.turnFoldButton,
|
|
1066
|
-
"data-open": open || void 0,
|
|
1067
|
-
"data-turn-process": turn,
|
|
1068
|
-
"data-turn-process-messages": messageCount,
|
|
1069
|
-
"data-turn-process-tool-calls": toolCallCount,
|
|
1070
|
-
"data-turn-process-subagents": subagentCount,
|
|
1071
|
-
disabled: !canCollapse,
|
|
1072
|
-
"aria-expanded": turnProcess.hasContent || fallback ? open : void 0,
|
|
1073
|
-
onClick: (event) => {
|
|
1074
|
-
event.currentTarget.focus();
|
|
1075
|
-
turnProcess.setOpen(!open);
|
|
1076
|
-
},
|
|
1077
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), canCollapse && (open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium, {}))]
|
|
1078
|
-
})
|
|
1079
|
-
})] });
|
|
1080
|
-
}
|
|
1081
|
-
/** Codex-style presentation over DSH's authoritative Turn-process state. */
|
|
1082
|
-
const CodexTurnProcessNodeView = (0, react.memo)(function CodexTurnProcessNodeView({ node, turnProcess, useSession, t }) {
|
|
1083
|
-
if (turnProcess === void 0) throw new Error("turn-process node requires DSH turnProcess owner state");
|
|
1084
|
-
const fallback = usesTurnProcessFallback(node, turnProcess, {
|
|
1085
|
-
compactTranscript: useCompactTranscript(),
|
|
1086
|
-
historyIncomplete: useSession((snapshot) => snapshot.hasMore),
|
|
1087
|
-
processStartLoaded: loadedProcessStart(node, turnProcess)
|
|
1088
|
-
});
|
|
1089
|
-
const seatRef = useChatSeatVisible(fallback);
|
|
1090
|
-
const location = node.location;
|
|
1091
|
-
const turn = location.kind === "turn" || location.kind === "step" ? location.turn : void 0;
|
|
1092
|
-
if (turn?.status !== "closed") return null;
|
|
1093
|
-
const reason = turn.end?.data.reason.kind;
|
|
1094
|
-
const canCollapse = turnProcess.foldable && turnProcess.hasContent && reason !== "aborted" && reason !== "error" || fallback;
|
|
1095
|
-
const elapsedMs = turn?.start !== void 0 && turn.end !== void 0 ? turn.end.time - turn.start.time : void 0;
|
|
1096
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexTurnProcessControl, {
|
|
1097
|
-
turn: node.data.turn,
|
|
1098
|
-
messageCount: node.data.messageCount,
|
|
1099
|
-
toolCallCount: node.data.toolCallCount,
|
|
1100
|
-
subagentCount: node.data.subagentCount,
|
|
1101
|
-
elapsedMs,
|
|
1102
|
-
reason,
|
|
1103
|
-
canCollapse,
|
|
1104
|
-
turnProcess,
|
|
1105
|
-
t,
|
|
1106
|
-
fallback,
|
|
1107
|
-
rootRef: seatRef
|
|
1108
|
-
});
|
|
1109
|
-
});
|
|
1110
|
-
//#endregion
|
|
1111
|
-
//#region ../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/lib/iconContext.mjs
|
|
1112
|
-
var DefaultContext = {
|
|
1113
|
-
color: void 0,
|
|
1114
|
-
size: void 0,
|
|
1115
|
-
className: void 0,
|
|
1116
|
-
style: void 0,
|
|
1117
|
-
attr: void 0
|
|
1118
|
-
};
|
|
1119
|
-
var IconContext = react.default.createContext && /*#__PURE__*/ react.default.createContext(DefaultContext);
|
|
1120
|
-
//#endregion
|
|
1121
|
-
//#region ../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/lib/iconBase.mjs
|
|
1122
|
-
var _excluded = [
|
|
1123
|
-
"attr",
|
|
1124
|
-
"size",
|
|
1125
|
-
"title"
|
|
1126
|
-
];
|
|
1127
|
-
function _objectWithoutProperties(source, excluded) {
|
|
1128
|
-
if (source == null) return {};
|
|
1129
|
-
var target = _objectWithoutPropertiesLoose(source, excluded);
|
|
1130
|
-
var key, i;
|
|
1131
|
-
if (Object.getOwnPropertySymbols) {
|
|
1132
|
-
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
|
1133
|
-
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
|
1134
|
-
key = sourceSymbolKeys[i];
|
|
1135
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
1136
|
-
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
1137
|
-
target[key] = source[key];
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
return target;
|
|
1141
|
-
}
|
|
1142
|
-
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
1143
|
-
if (source == null) return {};
|
|
1144
|
-
var target = {};
|
|
1145
|
-
for (var key in source) if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1146
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
1147
|
-
target[key] = source[key];
|
|
1148
|
-
}
|
|
1149
|
-
return target;
|
|
1150
|
-
}
|
|
1151
|
-
function _extends() {
|
|
1152
|
-
_extends = Object.assign ? Object.assign.bind() : function(target) {
|
|
1153
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
1154
|
-
var source = arguments[i];
|
|
1155
|
-
for (var key in source) if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
|
|
1156
|
-
}
|
|
1157
|
-
return target;
|
|
1158
|
-
};
|
|
1159
|
-
return _extends.apply(this, arguments);
|
|
1160
|
-
}
|
|
1161
|
-
function ownKeys(e, r) {
|
|
1162
|
-
var t = Object.keys(e);
|
|
1163
|
-
if (Object.getOwnPropertySymbols) {
|
|
1164
|
-
var o = Object.getOwnPropertySymbols(e);
|
|
1165
|
-
r && (o = o.filter(function(r) {
|
|
1166
|
-
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
|
1167
|
-
})), t.push.apply(t, o);
|
|
1168
|
-
}
|
|
1169
|
-
return t;
|
|
1170
|
-
}
|
|
1171
|
-
function _objectSpread(e) {
|
|
1172
|
-
for (var r = 1; r < arguments.length; r++) {
|
|
1173
|
-
var t = null != arguments[r] ? arguments[r] : {};
|
|
1174
|
-
r % 2 ? ownKeys(Object(t), !0).forEach(function(r) {
|
|
1175
|
-
_defineProperty(e, r, t[r]);
|
|
1176
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) {
|
|
1177
|
-
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
410
|
+
};
|
|
411
|
+
}, [
|
|
412
|
+
blocks,
|
|
413
|
+
props.groupPart,
|
|
414
|
+
props.node,
|
|
415
|
+
shown,
|
|
416
|
+
source
|
|
417
|
+
]);
|
|
418
|
+
const originalDisclosure = props.useDisclosure;
|
|
419
|
+
const useDisclosure = (0, react.useCallback)(() => {
|
|
420
|
+
const disclosure = originalDisclosure();
|
|
421
|
+
const { setExpanded } = disclosure;
|
|
422
|
+
(0, react.useEffect)(() => {
|
|
423
|
+
if (running) setExpanded(autoExpand);
|
|
424
|
+
}, [
|
|
425
|
+
autoExpand,
|
|
426
|
+
running,
|
|
427
|
+
setExpanded
|
|
428
|
+
]);
|
|
429
|
+
return disclosure;
|
|
430
|
+
}, [
|
|
431
|
+
autoExpand,
|
|
432
|
+
originalDisclosure,
|
|
433
|
+
running
|
|
434
|
+
]);
|
|
435
|
+
return (0, react.createElement)(NativeAssistant, {
|
|
436
|
+
...props,
|
|
437
|
+
node,
|
|
438
|
+
useDisclosure
|
|
1178
439
|
});
|
|
1179
440
|
}
|
|
1180
|
-
return
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
key = _toPropertyKey(key);
|
|
1184
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
1185
|
-
value,
|
|
1186
|
-
enumerable: true,
|
|
1187
|
-
configurable: true,
|
|
1188
|
-
writable: true
|
|
1189
|
-
});
|
|
1190
|
-
else obj[key] = value;
|
|
1191
|
-
return obj;
|
|
1192
|
-
}
|
|
1193
|
-
function _toPropertyKey(t) {
|
|
1194
|
-
var i = _toPrimitive(t, "string");
|
|
1195
|
-
return "symbol" == typeof i ? i : i + "";
|
|
1196
|
-
}
|
|
1197
|
-
function _toPrimitive(t, r) {
|
|
1198
|
-
if ("object" != typeof t || !t) return t;
|
|
1199
|
-
var e = t[Symbol.toPrimitive];
|
|
1200
|
-
if (void 0 !== e) {
|
|
1201
|
-
var i = e.call(t, r || "default");
|
|
1202
|
-
if ("object" != typeof i) return i;
|
|
1203
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
1204
|
-
}
|
|
1205
|
-
return ("string" === r ? String : Number)(t);
|
|
1206
|
-
}
|
|
1207
|
-
function Tree2Element(tree) {
|
|
1208
|
-
return tree && tree.map((node, i) => /*#__PURE__*/ react.default.createElement(node.tag, _objectSpread({ key: i }, node.attr), Tree2Element(node.child)));
|
|
1209
|
-
}
|
|
1210
|
-
function GenIcon(data) {
|
|
1211
|
-
return (props) => /*#__PURE__*/ react.default.createElement(IconBase, _extends({ attr: _objectSpread({}, data.attr) }, props), Tree2Element(data.child));
|
|
1212
|
-
}
|
|
1213
|
-
function IconBase(props) {
|
|
1214
|
-
var elem = (conf) => {
|
|
1215
|
-
var { attr, size, title } = props, svgProps = _objectWithoutProperties(props, _excluded);
|
|
1216
|
-
var computedSize = size || conf.size || "1em";
|
|
1217
|
-
var className;
|
|
1218
|
-
if (conf.className) className = conf.className;
|
|
1219
|
-
if (props.className) className = (className ? className + " " : "") + props.className;
|
|
1220
|
-
return /*#__PURE__*/ react.default.createElement("svg", _extends({
|
|
1221
|
-
stroke: "currentColor",
|
|
1222
|
-
fill: "currentColor",
|
|
1223
|
-
strokeWidth: "0"
|
|
1224
|
-
}, conf.attr, attr, svgProps, {
|
|
1225
|
-
className,
|
|
1226
|
-
style: _objectSpread(_objectSpread({ color: props.color || conf.color }, conf.style), props.style),
|
|
1227
|
-
height: computedSize,
|
|
1228
|
-
width: computedSize,
|
|
1229
|
-
xmlns: "http://www.w3.org/2000/svg"
|
|
1230
|
-
}), title && /*#__PURE__*/ react.default.createElement("title", null, title), props.children);
|
|
1231
|
-
};
|
|
1232
|
-
return IconContext !== void 0 ? /*#__PURE__*/ react.default.createElement(IconContext.Consumer, null, (conf) => elem(conf)) : elem(DefaultContext);
|
|
1233
|
-
}
|
|
1234
|
-
//#endregion
|
|
1235
|
-
//#region ../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/fi/index.mjs
|
|
1236
|
-
function FiTool(props) {
|
|
1237
|
-
return GenIcon({
|
|
1238
|
-
"tag": "svg",
|
|
1239
|
-
"attr": {
|
|
1240
|
-
"viewBox": "0 0 24 24",
|
|
1241
|
-
"fill": "none",
|
|
1242
|
-
"stroke": "currentColor",
|
|
1243
|
-
"strokeWidth": "2",
|
|
1244
|
-
"strokeLinecap": "round",
|
|
1245
|
-
"strokeLinejoin": "round"
|
|
1246
|
-
},
|
|
1247
|
-
"child": [{
|
|
1248
|
-
"tag": "path",
|
|
1249
|
-
"attr": { "d": "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" },
|
|
1250
|
-
"child": []
|
|
1251
|
-
}]
|
|
1252
|
-
})(props);
|
|
1253
|
-
}
|
|
1254
|
-
//#endregion
|
|
1255
|
-
//#region src/client/ToolActivityGroup.tsx
|
|
1256
|
-
const groupStates = /* @__PURE__ */ new Map();
|
|
1257
|
-
const groupMounts = /* @__PURE__ */ new Map();
|
|
1258
|
-
function groupState(id) {
|
|
1259
|
-
const current = groupStates.get(id);
|
|
1260
|
-
if (current !== void 0) return current;
|
|
1261
|
-
const created = {
|
|
1262
|
-
collapsed: false,
|
|
1263
|
-
listeners: /* @__PURE__ */ new Set()
|
|
1264
|
-
};
|
|
1265
|
-
groupStates.set(id, created);
|
|
1266
|
-
return created;
|
|
1267
|
-
}
|
|
1268
|
-
function groupMount(id) {
|
|
1269
|
-
const current = groupMounts.get(id);
|
|
1270
|
-
if (current !== void 0) return current;
|
|
1271
|
-
const created = {
|
|
1272
|
-
target: null,
|
|
1273
|
-
listeners: /* @__PURE__ */ new Set()
|
|
1274
|
-
};
|
|
1275
|
-
groupMounts.set(id, created);
|
|
1276
|
-
return created;
|
|
1277
|
-
}
|
|
1278
|
-
function notify(listeners) {
|
|
1279
|
-
for (const listener of listeners) listener();
|
|
1280
|
-
}
|
|
1281
|
-
function subscribeGroup(id, listener) {
|
|
1282
|
-
const state = groupState(id);
|
|
1283
|
-
state.listeners.add(listener);
|
|
1284
|
-
return () => {
|
|
1285
|
-
state.listeners.delete(listener);
|
|
1286
|
-
if (state.listeners.size === 0) groupStates.delete(id);
|
|
1287
|
-
};
|
|
1288
|
-
}
|
|
1289
|
-
function subscribeMount(id, listener) {
|
|
1290
|
-
const mount = groupMount(id);
|
|
1291
|
-
mount.listeners.add(listener);
|
|
1292
|
-
return () => {
|
|
1293
|
-
mount.listeners.delete(listener);
|
|
1294
|
-
if (mount.listeners.size === 0 && mount.target === null) groupMounts.delete(id);
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
function setMount(id, target) {
|
|
1298
|
-
const mount = groupMount(id);
|
|
1299
|
-
if (mount.target === target) return;
|
|
1300
|
-
mount.target = target;
|
|
1301
|
-
notify(mount.listeners);
|
|
1302
|
-
}
|
|
1303
|
-
function hash(value) {
|
|
1304
|
-
let result = 2166136261;
|
|
1305
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
1306
|
-
result ^= value.charCodeAt(index);
|
|
1307
|
-
result = Math.imul(result, 16777619);
|
|
1308
|
-
}
|
|
1309
|
-
return (result >>> 0).toString(36);
|
|
1310
|
-
}
|
|
1311
|
-
/** Stable identity for one contiguous semantic tool group in a Turn. */
|
|
1312
|
-
function toolActivityGroupId(sessionId, turn, semantic, firstNodeKey) {
|
|
1313
|
-
return `dsh-tool-group-${hash(`${sessionId}\u0000${turn}\u0000${semantic}\u0000${firstNodeKey}`)}`;
|
|
1314
|
-
}
|
|
1315
|
-
function useToolActivityFold(id) {
|
|
1316
|
-
const subscribe = (0, react.useCallback)((listener) => subscribeGroup(id, listener), [id]);
|
|
1317
|
-
return {
|
|
1318
|
-
collapsed: (0, react.useSyncExternalStore)(subscribe, () => groupState(id).collapsed, () => false),
|
|
1319
|
-
toggle: (0, react.useCallback)(() => {
|
|
1320
|
-
const state = groupState(id);
|
|
1321
|
-
state.collapsed = !state.collapsed;
|
|
1322
|
-
notify(state.listeners);
|
|
1323
|
-
}, [id]),
|
|
1324
|
-
collapse: (0, react.useCallback)(() => {
|
|
1325
|
-
const state = groupState(id);
|
|
1326
|
-
if (state.collapsed) return;
|
|
1327
|
-
state.collapsed = true;
|
|
1328
|
-
notify(state.listeners);
|
|
1329
|
-
}, [id]),
|
|
1330
|
-
expand: (0, react.useCallback)(() => {
|
|
1331
|
-
const state = groupState(id);
|
|
1332
|
-
if (!state.collapsed) return;
|
|
1333
|
-
state.collapsed = false;
|
|
1334
|
-
notify(state.listeners);
|
|
1335
|
-
}, [id])
|
|
1336
|
-
};
|
|
1337
|
-
}
|
|
1338
|
-
function useToolActivityMount(id) {
|
|
1339
|
-
const subscribe = (0, react.useCallback)((listener) => subscribeMount(id, listener), [id]);
|
|
1340
|
-
return (0, react.useSyncExternalStore)(subscribe, () => groupMount(id).target, () => null);
|
|
1341
|
-
}
|
|
1342
|
-
function ToolActivityGroupFrame({ group, collapsed, toggle, header, children }) {
|
|
1343
|
-
const register = (0, react.useCallback)((element) => {
|
|
1344
|
-
setMount(group.id, element);
|
|
1345
|
-
}, [group.id]);
|
|
1346
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1347
|
-
ref: register,
|
|
1348
|
-
id: group.domId,
|
|
1349
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupFrame,
|
|
1350
|
-
"data-stream-tool-group": group.semantic,
|
|
1351
|
-
"data-stream-tool-group-frame": "",
|
|
1352
|
-
"data-stream-tool-group-position": group.position,
|
|
1353
|
-
"data-stream-tool-group-count": group.count,
|
|
1354
|
-
"data-stream-tool-group-collapsed": collapsed || void 0,
|
|
1355
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1356
|
-
type: "button",
|
|
1357
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupHeader,
|
|
1358
|
-
"aria-expanded": !collapsed,
|
|
1359
|
-
"aria-controls": group.domId,
|
|
1360
|
-
"data-stream-tool-group-toggle": "",
|
|
1361
|
-
onClick: toggle,
|
|
1362
|
-
children: [header, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1363
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupHeaderChevron,
|
|
1364
|
-
"aria-hidden": true,
|
|
1365
|
-
children: collapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, { size: 14 })
|
|
1366
|
-
})]
|
|
1367
|
-
}), children]
|
|
1368
|
-
});
|
|
1369
|
-
}
|
|
1370
|
-
function SearchableActivityContent({ hidden, reveal, member = false, children }) {
|
|
1371
|
-
const ref = useSearchableHidden(hidden, reveal);
|
|
1372
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1373
|
-
ref,
|
|
1374
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupContent,
|
|
1375
|
-
"data-tool-group-member": member || void 0,
|
|
1376
|
-
"data-tool-group-hidden": hidden || void 0,
|
|
1377
|
-
children
|
|
1378
|
-
});
|
|
1379
|
-
}
|
|
1380
|
-
/**
|
|
1381
|
-
* Mount the first member as a group host and portal subsequent tool members
|
|
1382
|
-
* into the same host. DSH's outer Chat Node seat owns Turn visibility while a
|
|
1383
|
-
* contiguous run of commands keeps its own Codex-style disclosure block.
|
|
1384
|
-
*/
|
|
1385
|
-
function ToolActivityGroupMember({ group, memberRef, eventAttributes, header, children }) {
|
|
1386
|
-
const activity = useToolActivityFold(group.id);
|
|
1387
|
-
const mount = useToolActivityMount(group.id);
|
|
1388
|
-
(0, react.useEffect)(() => {
|
|
1389
|
-
if (group.position === "start" && !group.hasGrowing) activity.collapse();
|
|
1390
|
-
}, [
|
|
1391
|
-
activity.collapse,
|
|
1392
|
-
group.hasGrowing,
|
|
1393
|
-
group.position
|
|
1394
|
-
]);
|
|
1395
|
-
if (group.position === "start") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1396
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupAnchor,
|
|
1397
|
-
"data-stream-tool-group-anchor": "",
|
|
1398
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolActivityGroupFrame, {
|
|
1399
|
-
group,
|
|
1400
|
-
collapsed: activity.collapsed,
|
|
1401
|
-
toggle: activity.toggle,
|
|
1402
|
-
header,
|
|
1403
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchableActivityContent, {
|
|
1404
|
-
hidden: activity.collapsed,
|
|
1405
|
-
reveal: activity.expand,
|
|
1406
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1407
|
-
...eventAttributes,
|
|
1408
|
-
ref: memberRef,
|
|
1409
|
-
className: TypewriterAssistantNodeView_module_css_default.eventRow,
|
|
1410
|
-
"data-stream-tool-group-member": "",
|
|
1411
|
-
"data-stream-tool-group-position": "start",
|
|
1412
|
-
"data-stream-tool-group-collapsed": activity.collapsed || void 0,
|
|
1413
|
-
children
|
|
1414
|
-
})
|
|
1415
|
-
})
|
|
1416
|
-
})
|
|
1417
|
-
});
|
|
1418
|
-
const member = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchableActivityContent, {
|
|
1419
|
-
hidden: activity.collapsed,
|
|
1420
|
-
reveal: activity.expand,
|
|
1421
|
-
member: true,
|
|
1422
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1423
|
-
...eventAttributes,
|
|
1424
|
-
ref: memberRef,
|
|
1425
|
-
className: TypewriterAssistantNodeView_module_css_default.eventRow,
|
|
1426
|
-
"data-stream-tool-group-member": "",
|
|
1427
|
-
"data-stream-tool-group-position": group.position,
|
|
1428
|
-
"data-stream-tool-group-collapsed": activity.collapsed || void 0,
|
|
1429
|
-
children
|
|
1430
|
-
})
|
|
1431
|
-
});
|
|
1432
|
-
if (mount === null) return member;
|
|
1433
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1434
|
-
"data-tool-group-proxy": "",
|
|
1435
|
-
"aria-hidden": true,
|
|
1436
|
-
children: (0, react_dom.createPortal)(member, mount)
|
|
441
|
+
return (props) => (0, react.createElement)(EnhancedAssistant, {
|
|
442
|
+
...props,
|
|
443
|
+
key: `${props.sessionId}:${props.node.key}:${props.groupPart ?? ""}`
|
|
1437
444
|
});
|
|
1438
445
|
}
|
|
1439
|
-
/** Render the group heading with the semantic icon supplied by the tool view. */
|
|
1440
|
-
function ToolActivityGroupHeader({ label, icon }) {
|
|
1441
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1442
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupHeaderIcon,
|
|
1443
|
-
"aria-hidden": true,
|
|
1444
|
-
children: icon
|
|
1445
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1446
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupHeaderLabel,
|
|
1447
|
-
children: label
|
|
1448
|
-
})] });
|
|
1449
|
-
}
|
|
1450
|
-
//#endregion
|
|
1451
|
-
//#region src/client/TypewriterToolNodeView.tsx
|
|
1452
|
-
const TOOL_ICONS = {
|
|
1453
|
-
search: _deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineMedium,
|
|
1454
|
-
read: _deepseek_ai_dsh_client_ui_primitives.IconBrowseOutlineMedium,
|
|
1455
|
-
edit: _deepseek_ai_dsh_client_ui_primitives.IconEditOutlineMedium,
|
|
1456
|
-
terminal: _deepseek_ai_dsh_client_ui_primitives.IconApiOutlineMedium,
|
|
1457
|
-
data: _deepseek_ai_dsh_client_ui_primitives.IconDataOutlineMedium,
|
|
1458
|
-
web: _deepseek_ai_dsh_client_ui_primitives.IconGlobeOutlineMedium,
|
|
1459
|
-
code: FiTool,
|
|
1460
|
-
skill: _deepseek_ai_dsh_client_ui_primitives.IconSkillOutlineMedium,
|
|
1461
|
-
agent: _deepseek_ai_dsh_client_ui_primitives.IconAgentPresetOutlineMedium,
|
|
1462
|
-
plugin: _deepseek_ai_dsh_client_ui_primitives.IconCordisPluginOutlineMedium,
|
|
1463
|
-
question: _deepseek_ai_dsh_client_ui_primitives.IconQuestionOutlineMedium,
|
|
1464
|
-
settings: _deepseek_ai_dsh_client_ui_primitives.IconSettingsOutlineMedium,
|
|
1465
|
-
checklist: _deepseek_ai_dsh_client_ui_primitives.IconChecklistOutlineMedium,
|
|
1466
|
-
other: FiTool
|
|
1467
|
-
};
|
|
1468
|
-
const CONVERSATION_NODE_ICONS = { context: _deepseek_ai_dsh_client_ui_primitives.IconBrowseOutlineMedium };
|
|
1469
|
-
function toolTokens(toolName) {
|
|
1470
|
-
return toolName.replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase().split(/[^a-z\d]+/).filter(Boolean);
|
|
1471
|
-
}
|
|
1472
446
|
/**
|
|
1473
|
-
*
|
|
1474
|
-
*
|
|
1475
|
-
*
|
|
447
|
+
* Enhance the winning assistant renderer in place. dsh 0.2.1 gives the native
|
|
448
|
+
* assistant entry its own child slots (reasoning body, message images), which
|
|
449
|
+
* a separate shadowing registration could not carry; swapping the entry's
|
|
450
|
+
* component keeps children, inject, store, and locale seats untouched while
|
|
451
|
+
* the enhancement delegates every visual to the native renderer.
|
|
452
|
+
* @param ctx - browser context with the slot registry.
|
|
453
|
+
* @param preference - live reveal and auto-expand preferences.
|
|
454
|
+
* @returns disposer restoring the original component.
|
|
1476
455
|
*/
|
|
1477
|
-
function
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
if (has("scope", "config", "settings", "setting")) return "settings";
|
|
1485
|
-
if (has("database", "db", "sql", "schema", "table", "record", "records", "dataset", "memory")) return "data";
|
|
1486
|
-
if (has("plan", "todo", "task", "checklist", "goal")) return "checklist";
|
|
1487
|
-
if (has("edit", "write", "patch", "replace", "create", "delete", "remove", "move", "copy")) return "edit";
|
|
1488
|
-
if (has("bash", "shell", "terminal", "exec", "command", "cmd", "powershell", "pwsh")) return "terminal";
|
|
1489
|
-
if (has("web", "browser", "url", "http", "https", "crawl", "scrape")) return "web";
|
|
1490
|
-
if (has("read", "load", "open", "file", "files")) return "read";
|
|
1491
|
-
if (has("search", "find", "grep", "glob", "query", "lookup", "knowledge", "retrieve", "index", "log", "logs", "trace")) return "search";
|
|
1492
|
-
if (has("code", "codegraph", "graph", "python", "javascript", "typescript", "node", "program")) return "code";
|
|
1493
|
-
return "other";
|
|
1494
|
-
}
|
|
1495
|
-
function toolPresentation(node) {
|
|
1496
|
-
if (node === null || typeof node !== "object" || !("data" in node)) return null;
|
|
1497
|
-
const data = node.data;
|
|
1498
|
-
if (data === null || typeof data !== "object" || !("root" in data)) return null;
|
|
1499
|
-
const root = data.root;
|
|
1500
|
-
if (root === null || typeof root !== "object") return null;
|
|
1501
|
-
const name = "name" in root && typeof root.name === "string" ? root.name : "call" in root && root.call !== null && typeof root.call === "object" && "name" in root.call && typeof root.call.name === "string" ? root.call.name : "";
|
|
1502
|
-
if (name === "") return null;
|
|
1503
|
-
const isError = "isError" in root && root.isError === true || "error" in root && root.error !== null && root.error !== void 0;
|
|
1504
|
-
const errorCode = "error" in root && root.error !== null && typeof root.error === "object" && "code" in root.error && typeof root.error.code === "string" ? root.error.code.toLowerCase() : "";
|
|
1505
|
-
const stopped = /cancel|interrupt|abort|stop/.test(errorCode);
|
|
1506
|
-
return {
|
|
1507
|
-
name,
|
|
1508
|
-
semantic: semanticToolKind(name),
|
|
1509
|
-
state: stopped ? "stopped" : isError ? "error" : null
|
|
1510
|
-
};
|
|
1511
|
-
}
|
|
1512
|
-
function diffLineCount(value) {
|
|
1513
|
-
if (typeof value !== "string" || value === "") return 0;
|
|
1514
|
-
const body = value.endsWith("\n") ? value.slice(0, -1) : value.endsWith("\\n") ? value.slice(0, -2) : value;
|
|
1515
|
-
return body === "" ? 0 : body.split(/\r?\n|\\n/).length;
|
|
1516
|
-
}
|
|
1517
|
-
/**
|
|
1518
|
-
* Derive the compact +/- suffix shown beside an edit file path. The native
|
|
1519
|
-
* edit card already owns the actual diff body; this only mirrors its counts
|
|
1520
|
-
* into the collapsed summary row.
|
|
1521
|
-
*/
|
|
1522
|
-
function editDiffFilePath(node) {
|
|
1523
|
-
const presentation = toolPresentation(node);
|
|
1524
|
-
if (presentation?.semantic !== "edit" || presentation.state !== null || node === null || typeof node !== "object") return void 0;
|
|
1525
|
-
const data = node.data;
|
|
1526
|
-
if (data === null || typeof data !== "object" || !("root" in data)) return void 0;
|
|
1527
|
-
const root = data.root;
|
|
1528
|
-
if (root === null || typeof root !== "object") return void 0;
|
|
1529
|
-
const view = "resultView" in root ? root.resultView ?? root.callView : "callView" in root ? root.callView : void 0;
|
|
1530
|
-
if (view === null || typeof view !== "object" || view.card !== "diff") return void 0;
|
|
1531
|
-
const diffs = view.diffs;
|
|
1532
|
-
if (!Array.isArray(diffs)) return void 0;
|
|
1533
|
-
const first = diffs.find((diff) => diff !== null && typeof diff === "object" && typeof diff.path === "string");
|
|
1534
|
-
return first === void 0 ? void 0 : first.path;
|
|
1535
|
-
}
|
|
1536
|
-
function editDiffStats(node) {
|
|
1537
|
-
const presentation = toolPresentation(node);
|
|
1538
|
-
if (presentation?.semantic !== "edit" || presentation.state !== null || node === null || typeof node !== "object") return void 0;
|
|
1539
|
-
const data = node.data;
|
|
1540
|
-
if (data === null || typeof data !== "object" || !("root" in data)) return void 0;
|
|
1541
|
-
const root = data.root;
|
|
1542
|
-
if (root === null || typeof root !== "object") return void 0;
|
|
1543
|
-
const view = "resultView" in root ? root.resultView ?? root.callView : "callView" in root ? root.callView : void 0;
|
|
1544
|
-
if (view === null || typeof view !== "object" || view.card !== "diff") return void 0;
|
|
1545
|
-
const diffs = view.diffs;
|
|
1546
|
-
if (!Array.isArray(diffs)) return void 0;
|
|
1547
|
-
let added = 0;
|
|
1548
|
-
let removed = 0;
|
|
1549
|
-
for (const diff of diffs) {
|
|
1550
|
-
if (diff === null || typeof diff !== "object") continue;
|
|
1551
|
-
added += diffLineCount(diff.newText);
|
|
1552
|
-
removed += diffLineCount(diff.oldText);
|
|
1553
|
-
}
|
|
1554
|
-
return added === 0 && removed === 0 ? void 0 : `+${added} -${removed}`;
|
|
1555
|
-
}
|
|
1556
|
-
const TOOL_GROUP_LABELS = {
|
|
1557
|
-
search: "搜索",
|
|
1558
|
-
read: "读取了文件",
|
|
1559
|
-
edit: "编辑了文件",
|
|
1560
|
-
terminal: "运行了命令",
|
|
1561
|
-
data: "查询了数据",
|
|
1562
|
-
web: "浏览了网页",
|
|
1563
|
-
code: "运行了代码",
|
|
1564
|
-
skill: "使用了技能",
|
|
1565
|
-
agent: "调用了智能体",
|
|
1566
|
-
plugin: "调用了插件",
|
|
1567
|
-
question: "发起了提问",
|
|
1568
|
-
settings: "更新了设置",
|
|
1569
|
-
checklist: "更新了清单",
|
|
1570
|
-
other: "执行了操作"
|
|
1571
|
-
};
|
|
1572
|
-
function visibleNode(node) {
|
|
1573
|
-
if (node === null || typeof node !== "object") return false;
|
|
1574
|
-
return !("visibility" in node) || node.visibility === "visible";
|
|
1575
|
-
}
|
|
1576
|
-
function chatParts(snapshot) {
|
|
1577
|
-
if (snapshot === null || typeof snapshot !== "object") return void 0;
|
|
1578
|
-
const candidate = "chat" in snapshot ? snapshot.chat : snapshot;
|
|
1579
|
-
if (candidate === null || typeof candidate !== "object" || !("order" in candidate) || !("nodes" in candidate)) return void 0;
|
|
1580
|
-
const order = candidate.order;
|
|
1581
|
-
const nodes = candidate.nodes;
|
|
1582
|
-
if (!Array.isArray(order) || nodes === null || typeof nodes !== "object" || !("get" in nodes)) return void 0;
|
|
1583
|
-
const get = nodes.get;
|
|
1584
|
-
if (typeof get !== "function") return void 0;
|
|
1585
|
-
return {
|
|
1586
|
-
order,
|
|
1587
|
-
get: (key) => get.call(nodes, key),
|
|
1588
|
-
timeline: "timeline" in candidate ? candidate.timeline : void 0
|
|
1589
|
-
};
|
|
1590
|
-
}
|
|
1591
|
-
function sameActivityGroupNode(node, nodeKind, turn, semantic, requiresTurn) {
|
|
1592
|
-
return visibleNode(node) && chatNodeKind(node) === nodeKind && (!requiresTurn || turnDetailsFromNode(node)?.turn === turn) && (nodeKind !== "tool-call" || toolPresentation(node)?.semantic === semantic);
|
|
1593
|
-
}
|
|
1594
|
-
function activityGroup(snapshot, currentKey, sessionId, turn, nodeKind, semantic, label, requiresTurn) {
|
|
1595
|
-
const chat = chatParts(snapshot);
|
|
1596
|
-
if (chat === void 0) return void 0;
|
|
1597
|
-
const currentIndex = chat.order.indexOf(currentKey);
|
|
1598
|
-
if (currentIndex === -1) return void 0;
|
|
1599
|
-
const read = (index) => {
|
|
1600
|
-
const key = chat.order[index];
|
|
1601
|
-
return typeof key === "string" ? chat.get(key) : void 0;
|
|
456
|
+
function registerAssistantEnhancement(ctx, preference) {
|
|
457
|
+
let target;
|
|
458
|
+
let original;
|
|
459
|
+
const restore = () => {
|
|
460
|
+
if (target !== void 0) target.component = original;
|
|
461
|
+
target = void 0;
|
|
462
|
+
original = void 0;
|
|
1602
463
|
};
|
|
1603
|
-
const
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
const firstKey = chat.order[first];
|
|
1612
|
-
if (typeof firstKey !== "string") return void 0;
|
|
1613
|
-
let hasGrowing = false;
|
|
1614
|
-
for (let index = first; index <= last; index += 1) if (isGrowingChatNode(read(index))) {
|
|
1615
|
-
hasGrowing = true;
|
|
1616
|
-
break;
|
|
1617
|
-
}
|
|
1618
|
-
const groupId = toolActivityGroupId(sessionId, turn, semantic, firstKey);
|
|
1619
|
-
return {
|
|
1620
|
-
id: groupId,
|
|
1621
|
-
domId: `${groupId}-frame`,
|
|
1622
|
-
semantic,
|
|
1623
|
-
label,
|
|
1624
|
-
count,
|
|
1625
|
-
position: currentIndex === first ? "start" : currentIndex === last ? "end" : "middle",
|
|
1626
|
-
hasGrowing
|
|
464
|
+
const reconcile = () => {
|
|
465
|
+
const winner = ctx.slots.entries("conversation.chat.node").find((entry) => entry.options.key === "assistant-step");
|
|
466
|
+
if (winner === target) return;
|
|
467
|
+
restore();
|
|
468
|
+
if (winner === void 0 || winner.component === null || typeof winner.component !== "function" && typeof winner.component !== "object") return;
|
|
469
|
+
target = winner;
|
|
470
|
+
original = winner.component;
|
|
471
|
+
winner.component = enhanceNativeAssistant(original, preference);
|
|
1627
472
|
};
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
function toolActivityGroup(snapshot, currentKey, sessionId, turn, semantic) {
|
|
1631
|
-
return activityGroup(snapshot, currentKey, sessionId, turn, "tool-call", semantic, TOOL_GROUP_LABELS[semantic], true);
|
|
1632
|
-
}
|
|
1633
|
-
function ToolSemanticIcon({ presentation, className = TypewriterAssistantNodeView_module_css_default.toolSemanticIcon }) {
|
|
1634
|
-
const Icon = TOOL_ICONS[presentation.semantic];
|
|
1635
|
-
const glyph = presentation.semantic === "code" || presentation.semantic === "other" ? "wrench" : presentation.semantic;
|
|
1636
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1637
|
-
className,
|
|
1638
|
-
"data-tool-semantic-icon": presentation.semantic,
|
|
1639
|
-
"data-tool-glyph": glyph,
|
|
1640
|
-
"aria-hidden": true,
|
|
1641
|
-
children: presentation.state === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }) : presentation.state === "stopped" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "warning" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { size: 14 })
|
|
473
|
+
const off = ctx.on("slots/changed", (name) => {
|
|
474
|
+
if (name === "conversation.chat.node") reconcile();
|
|
1642
475
|
});
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
}
|
|
1650
|
-
/** Find expandable nested Tool headers rendered by the Harness Tool tree. */
|
|
1651
|
-
function nestedToolIconTargets(root) {
|
|
1652
|
-
const targets = [];
|
|
1653
|
-
root.querySelectorAll("[data-subcalls] [data-chat-call-id]").forEach((callRow, index) => {
|
|
1654
|
-
const slot = Array.from(callRow.children).find((child) => child instanceof HTMLElement && child.matches("[data-slot=\"tool.call.toolview\"]"));
|
|
1655
|
-
if (slot === void 0) return;
|
|
1656
|
-
const toolRoot = slot.querySelector(":scope > [data-tool]");
|
|
1657
|
-
const bashRoot = slot.querySelector(":scope > * > [data-sample=\"bash\"]");
|
|
1658
|
-
const target = toolRoot?.querySelector(":scope > * > [data-disclosure-row][aria-expanded]") ?? (bashRoot?.matches("[aria-expanded]") === true ? bashRoot : null);
|
|
1659
|
-
if (target === null) return;
|
|
1660
|
-
const name = toolRoot?.getAttribute("data-tool") ?? "bash";
|
|
1661
|
-
const stateName = toolRoot?.getAttribute("data-state") ?? bashRoot?.getAttribute("data-state");
|
|
1662
|
-
const state = stateName === "error" ? "error" : stateName === "stopped" ? "stopped" : null;
|
|
1663
|
-
targets.push({
|
|
1664
|
-
key: callRow.getAttribute("data-chat-call-id") ?? `${name}-${index}`,
|
|
1665
|
-
target,
|
|
1666
|
-
presentation: {
|
|
1667
|
-
name,
|
|
1668
|
-
semantic: semanticToolKind(name),
|
|
1669
|
-
state
|
|
1670
|
-
}
|
|
1671
|
-
});
|
|
1672
|
-
});
|
|
1673
|
-
return targets;
|
|
1674
|
-
}
|
|
1675
|
-
/**
|
|
1676
|
-
* Nested DisclosureRows replace their leading icon with a chevron when open.
|
|
1677
|
-
* A portal owned by this plugin keeps a semantic icon mounted in each header
|
|
1678
|
-
* across that internal state change while Harness continues to own the body.
|
|
1679
|
-
*/
|
|
1680
|
-
function NestedToolSemanticIcons({ owner, revision }) {
|
|
1681
|
-
const [targets, setTargets] = (0, react.useState)([]);
|
|
1682
|
-
(0, react.useLayoutEffect)(() => {
|
|
1683
|
-
const next = owner === null ? [] : nestedToolIconTargets(owner);
|
|
1684
|
-
setTargets((current) => sameNestedToolIconTargets(current, next) ? current : next);
|
|
1685
|
-
}, [owner, revision]);
|
|
1686
|
-
return targets.map(({ key, target, presentation }) => {
|
|
1687
|
-
const Icon = TOOL_ICONS[presentation.semantic];
|
|
1688
|
-
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1689
|
-
className: TypewriterAssistantNodeView_module_css_default.nestedToolSemanticIcon,
|
|
1690
|
-
"data-stream-nested-tool-icon": presentation.semantic,
|
|
1691
|
-
"aria-hidden": true,
|
|
1692
|
-
children: presentation.state === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }) : presentation.state === "stopped" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "warning" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { size: 14 })
|
|
1693
|
-
}), target, key);
|
|
1694
|
-
});
|
|
1695
|
-
}
|
|
1696
|
-
function ConversationNodeSemanticIcon({ kind, className = TypewriterAssistantNodeView_module_css_default.streamSemanticIcon }) {
|
|
1697
|
-
const Icon = CONVERSATION_NODE_ICONS[kind];
|
|
1698
|
-
if (Icon === void 0) return null;
|
|
1699
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1700
|
-
className,
|
|
1701
|
-
"data-stream-semantic-icon": kind,
|
|
1702
|
-
"aria-hidden": true,
|
|
1703
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { size: 14 })
|
|
1704
|
-
});
|
|
1705
|
-
}
|
|
1706
|
-
function chatNodeKind(node) {
|
|
1707
|
-
if (node === null || typeof node !== "object" || !("kind" in node)) return "unknown";
|
|
1708
|
-
const kind = node.kind;
|
|
1709
|
-
return typeof kind === "string" ? kind : "unknown";
|
|
1710
|
-
}
|
|
1711
|
-
const KEEP_VISIBLE_KINDS = /* @__PURE__ */ new Set([
|
|
1712
|
-
"turn-tail",
|
|
1713
|
-
"turn-error",
|
|
1714
|
-
"turn-max-tokens"
|
|
1715
|
-
]);
|
|
1716
|
-
function turnDetailsFromNode(node) {
|
|
1717
|
-
if (node === null || typeof node !== "object" || !("location" in node)) return void 0;
|
|
1718
|
-
const location = node.location;
|
|
1719
|
-
if (location === null || typeof location !== "object" || !("kind" in location)) return void 0;
|
|
1720
|
-
const kind = location.kind;
|
|
1721
|
-
if (kind !== "turn" && kind !== "step") return void 0;
|
|
1722
|
-
const turn = location.turn;
|
|
1723
|
-
if (turn === null || typeof turn !== "object" || !("turn" in turn)) return void 0;
|
|
1724
|
-
const turnNumber = turn.turn;
|
|
1725
|
-
if (typeof turnNumber !== "number") return void 0;
|
|
1726
|
-
return { turn: turnNumber };
|
|
1727
|
-
}
|
|
1728
|
-
function processAddress(node) {
|
|
1729
|
-
const details = turnDetailsFromNode(node);
|
|
1730
|
-
return details === void 0 ? void 0 : { turn: details.turn };
|
|
1731
|
-
}
|
|
1732
|
-
function nodeKey(node) {
|
|
1733
|
-
if (node === null || typeof node !== "object" || !("key" in node)) return void 0;
|
|
1734
|
-
const key = node.key;
|
|
1735
|
-
return typeof key === "string" ? key : void 0;
|
|
1736
|
-
}
|
|
1737
|
-
/**
|
|
1738
|
-
* Keep the latest settled Tool visibly active while the Agent is still
|
|
1739
|
-
* running but has not published its next Chat row yet. A later visible row
|
|
1740
|
-
* ends this handoff state; `turn-tail` is presentation metadata rather than
|
|
1741
|
-
* the next piece of model/process output.
|
|
1742
|
-
*/
|
|
1743
|
-
function isAwaitingNextTurnNode(snapshot, running, currentKey, turnNumber) {
|
|
1744
|
-
if (!running) return false;
|
|
1745
|
-
const chat = chatParts(snapshot);
|
|
1746
|
-
if (chat === void 0) return false;
|
|
1747
|
-
if (chat.timeline !== void 0) {
|
|
1748
|
-
const timeline = chat.timeline;
|
|
1749
|
-
if (timeline !== null && typeof timeline === "object" && "turns" in timeline) {
|
|
1750
|
-
const turns = timeline.turns;
|
|
1751
|
-
if (turns instanceof Map) {
|
|
1752
|
-
const turn = turns.get(turnNumber);
|
|
1753
|
-
if (turn !== void 0 && turn !== null && typeof turn === "object" && "status" in turn && turn.status !== "open") return false;
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
const currentIndex = chat.order.indexOf(currentKey);
|
|
1758
|
-
if (currentIndex === -1) return false;
|
|
1759
|
-
for (let index = currentIndex + 1; index < chat.order.length; index += 1) {
|
|
1760
|
-
const key = chat.order[index];
|
|
1761
|
-
if (typeof key !== "string") continue;
|
|
1762
|
-
const candidate = chat.get(key);
|
|
1763
|
-
if (candidate === null || typeof candidate !== "object") continue;
|
|
1764
|
-
if ("visibility" in candidate && candidate.visibility !== "visible") continue;
|
|
1765
|
-
if ("kind" in candidate && candidate.kind === "turn-tail") continue;
|
|
1766
|
-
return false;
|
|
1767
|
-
}
|
|
1768
|
-
return true;
|
|
1769
|
-
}
|
|
1770
|
-
/**
|
|
1771
|
-
* True while a Chat node is still growing: an assistant/workflow `status:
|
|
1772
|
-
* 'running'` payload, a Tool root that has not settled (`kind` absent), or a
|
|
1773
|
-
* model-retry whose current attempt is still `scheduled`.
|
|
1774
|
-
* @param node - The Chat node's view `node` prop.
|
|
1775
|
-
* @returns whether this row should own conversation follow.
|
|
1776
|
-
*/
|
|
1777
|
-
function isGrowingChatNode(node) {
|
|
1778
|
-
if (node === null || typeof node !== "object" || !("data" in node)) return false;
|
|
1779
|
-
const data = node.data;
|
|
1780
|
-
if (data === null || typeof data !== "object") return false;
|
|
1781
|
-
if ("status" in data && data.status === "running") return true;
|
|
1782
|
-
if ("root" in data) {
|
|
1783
|
-
const root = data.root;
|
|
1784
|
-
if (root !== null && typeof root === "object" && !("kind" in root)) return true;
|
|
1785
|
-
}
|
|
1786
|
-
if ("current" in data) {
|
|
1787
|
-
const current = data.current;
|
|
1788
|
-
if (current !== null && typeof current === "object" && "retryState" in current && current.retryState === "scheduled") return true;
|
|
476
|
+
try {
|
|
477
|
+
reconcile();
|
|
478
|
+
} catch (error) {
|
|
479
|
+
off();
|
|
480
|
+
restore();
|
|
481
|
+
throw error;
|
|
1789
482
|
}
|
|
1790
|
-
return
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
* Wrap a prior Chat node renderer with Codex activity presentation while DSH
|
|
1794
|
-
* retains exclusive scroll ownership. Kit seats (`renderSlot`, locale, inject)
|
|
1795
|
-
* pass through unchanged.
|
|
1796
|
-
* @param Inner - The already-registered row component.
|
|
1797
|
-
* @returns A structurally hosted row.
|
|
1798
|
-
*/
|
|
1799
|
-
function wrapFollowNodeView(Inner, motion = {}) {
|
|
1800
|
-
return function TypewriterFollowNodeView(props) {
|
|
1801
|
-
const kind = chatNodeKind(props.node);
|
|
1802
|
-
const directAddress = KEEP_VISIBLE_KINDS.has(kind) ? void 0 : processAddress(props.node);
|
|
1803
|
-
const key = nodeKey(props.node);
|
|
1804
|
-
const useChat = props.useChat;
|
|
1805
|
-
const useSession = props.useSession;
|
|
1806
|
-
if (directAddress !== void 0 && kind === "tool-call" && key !== void 0 && typeof useChat === "function" && typeof useSession === "function") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TailAwareToolFollowNodeView, {
|
|
1807
|
-
Inner,
|
|
1808
|
-
motion,
|
|
1809
|
-
props,
|
|
1810
|
-
address: directAddress,
|
|
1811
|
-
nodeKey: key,
|
|
1812
|
-
useChat,
|
|
1813
|
-
useSession
|
|
1814
|
-
});
|
|
1815
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FollowNodeView, {
|
|
1816
|
-
Inner,
|
|
1817
|
-
motion,
|
|
1818
|
-
props,
|
|
1819
|
-
address: directAddress
|
|
1820
|
-
});
|
|
1821
|
-
};
|
|
1822
|
-
}
|
|
1823
|
-
function TailAwareToolFollowNodeView({ Inner, motion, props, address, nodeKey: currentKey, useChat, useSession }) {
|
|
1824
|
-
const running = useSession((snapshot) => snapshot !== null && typeof snapshot === "object" && "running" in snapshot && snapshot.running === true);
|
|
1825
|
-
const awaitingNext = useChat((snapshot) => isAwaitingNextTurnNode(snapshot, running, currentKey, address.turn));
|
|
1826
|
-
const presentation = toolPresentation(props.node);
|
|
1827
|
-
const group = useChat((snapshot) => typeof props.sessionId === "string" && presentation !== null ? toolActivityGroup(snapshot, currentKey, props.sessionId, address.turn, presentation.semantic) : void 0);
|
|
1828
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FollowNodeView, {
|
|
1829
|
-
Inner,
|
|
1830
|
-
motion,
|
|
1831
|
-
props,
|
|
1832
|
-
address,
|
|
1833
|
-
awaitingNext,
|
|
1834
|
-
toolGroup: group
|
|
1835
|
-
});
|
|
1836
|
-
}
|
|
1837
|
-
function FollowNodeView({ Inner, motion, props, address, awaitingNext = false, toolGroup }) {
|
|
1838
|
-
const speedCpsRef = (0, react.useRef)(35);
|
|
1839
|
-
const turnProcess = props.turnProcess;
|
|
1840
|
-
const fallbackGate = {
|
|
1841
|
-
compactTranscript: useCompactTranscript(),
|
|
1842
|
-
historyIncomplete: typeof props.useSession === "function" && props.useSession((snapshot) => snapshot.hasMore === true),
|
|
1843
|
-
processStartLoaded: loadedProcessStart(props.node, turnProcess)
|
|
1844
|
-
};
|
|
1845
|
-
const seatRef = useChatSeatHidden(isFallbackProcessMember(props.node, turnProcess, fallbackGate) && turnProcess?.open === false, (0, react.useCallback)(() => {
|
|
1846
|
-
turnProcess?.setOpen(true);
|
|
1847
|
-
}, [turnProcess]));
|
|
1848
|
-
const [eventElement, setEventElement] = (0, react.useState)(null);
|
|
1849
|
-
const eventRef = (0, react.useCallback)((element) => {
|
|
1850
|
-
seatRef(element);
|
|
1851
|
-
setEventElement(element);
|
|
1852
|
-
}, [seatRef]);
|
|
1853
|
-
const growing = isGrowingChatNode(props.node);
|
|
1854
|
-
const kind = chatNodeKind(props.node);
|
|
1855
|
-
const staticCompaction = kind === "compaction" || kind === "manual-compaction";
|
|
1856
|
-
(0, react.useLayoutEffect)(() => {
|
|
1857
|
-
if (!staticCompaction || eventElement === null) return;
|
|
1858
|
-
const button = eventElement.querySelector("[data-compaction-disclosure]")?.closest("button");
|
|
1859
|
-
if (button === null || button === void 0) return;
|
|
1860
|
-
const previousDisabled = button.disabled;
|
|
1861
|
-
const previousExpanded = button.getAttribute("aria-expanded");
|
|
1862
|
-
button.disabled = true;
|
|
1863
|
-
button.removeAttribute("aria-expanded");
|
|
1864
|
-
return () => {
|
|
1865
|
-
button.disabled = previousDisabled;
|
|
1866
|
-
if (previousExpanded === null) button.removeAttribute("aria-expanded");
|
|
1867
|
-
else button.setAttribute("aria-expanded", previousExpanded);
|
|
1868
|
-
};
|
|
1869
|
-
}, [
|
|
1870
|
-
eventElement,
|
|
1871
|
-
props.node,
|
|
1872
|
-
staticCompaction
|
|
1873
|
-
]);
|
|
1874
|
-
const preventCompactionExpand = staticCompaction ? (event) => {
|
|
1875
|
-
event.preventDefault();
|
|
1876
|
-
event.stopPropagation();
|
|
1877
|
-
} : void 0;
|
|
1878
|
-
const tool = kind === "tool-call" ? toolPresentation(props.node) : null;
|
|
1879
|
-
const editStats = tool === null ? void 0 : editDiffStats(props.node);
|
|
1880
|
-
const [editStatsRow, setEditStatsRow] = (0, react.useState)(null);
|
|
1881
|
-
(0, react.useLayoutEffect)(() => {
|
|
1882
|
-
const row = editStats === void 0 || eventElement === null ? null : eventElement.querySelector("[data-disclosure-row]");
|
|
1883
|
-
setEditStatsRow((previous) => previous === row ? previous : row);
|
|
1884
|
-
}, [
|
|
1885
|
-
editStats,
|
|
1886
|
-
eventElement,
|
|
1887
|
-
props.node
|
|
1888
|
-
]);
|
|
1889
|
-
const ownsStreamSemanticIcon = tool === null && CONVERSATION_NODE_ICONS[kind] !== void 0;
|
|
1890
|
-
const toolProgressActive = tool !== null && (growing || awaitingNext);
|
|
1891
|
-
const inner = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1892
|
-
tool !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolSemanticIcon, { presentation: tool }),
|
|
1893
|
-
ownsStreamSemanticIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationNodeSemanticIcon, { kind }),
|
|
1894
|
-
(0, react.createElement)(Inner, props),
|
|
1895
|
-
tool !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NestedToolSemanticIcons, {
|
|
1896
|
-
owner: eventElement,
|
|
1897
|
-
revision: props.node
|
|
1898
|
-
}),
|
|
1899
|
-
editStats !== void 0 && editStatsRow !== null && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1900
|
-
className: TypewriterAssistantNodeView_module_css_default.editStats,
|
|
1901
|
-
"data-stream-edit-stats": "",
|
|
1902
|
-
"data-stream-edit-file": editDiffFilePath(props.node),
|
|
1903
|
-
onClick: (event) => {
|
|
1904
|
-
event.stopPropagation();
|
|
1905
|
-
event.currentTarget.closest("[data-disclosure-row][data-expandable]")?.click();
|
|
1906
|
-
},
|
|
1907
|
-
children: editStats
|
|
1908
|
-
}), editStatsRow)
|
|
1909
|
-
] });
|
|
1910
|
-
const activityRunning = growing || toolGroup?.hasGrowing === true;
|
|
1911
|
-
const headerIcon = tool !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolSemanticIcon, {
|
|
1912
|
-
presentation: tool,
|
|
1913
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupHeaderGlyph
|
|
1914
|
-
}) : ownsStreamSemanticIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationNodeSemanticIcon, {
|
|
1915
|
-
kind,
|
|
1916
|
-
className: TypewriterAssistantNodeView_module_css_default.toolGroupHeaderGlyph
|
|
1917
|
-
}) : null;
|
|
1918
|
-
const eventAttributes = {
|
|
1919
|
-
"data-stream-node": kind,
|
|
1920
|
-
"data-stream-turn": address === void 0 ? void 0 : String(address.turn),
|
|
1921
|
-
"data-stream-state": activityRunning ? "running" : "settled",
|
|
1922
|
-
"data-stream-progress": toolProgressActive ? "active" : void 0,
|
|
1923
|
-
"data-stream-tool-row": tool === null ? void 0 : "",
|
|
1924
|
-
"data-stream-native-disclosure": tool === null ? "" : void 0,
|
|
1925
|
-
"data-stream-semantic-icon-owned": ownsStreamSemanticIcon ? kind : void 0,
|
|
1926
|
-
"data-tool-semantic": tool?.semantic,
|
|
1927
|
-
"data-tool-name": tool?.name
|
|
483
|
+
return () => {
|
|
484
|
+
off();
|
|
485
|
+
restore();
|
|
1928
486
|
};
|
|
1929
|
-
const activityHeader = toolGroup !== void 0 && headerIcon !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolActivityGroupHeader, {
|
|
1930
|
-
label: toolGroup.label,
|
|
1931
|
-
icon: headerIcon
|
|
1932
|
-
}) : null;
|
|
1933
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FollowHost, {
|
|
1934
|
-
active: activityRunning,
|
|
1935
|
-
speedCpsRef,
|
|
1936
|
-
minSpeedPxPerSec: motion.minSpeedPxPerSec,
|
|
1937
|
-
maxSpeedPxPerSec: motion.maxSpeedPxPerSec,
|
|
1938
|
-
children: address !== void 0 && toolGroup !== void 0 && activityHeader !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolActivityGroupMember, {
|
|
1939
|
-
group: toolGroup,
|
|
1940
|
-
memberRef: eventRef,
|
|
1941
|
-
eventAttributes,
|
|
1942
|
-
header: activityHeader,
|
|
1943
|
-
children: inner
|
|
1944
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1945
|
-
ref: eventRef,
|
|
1946
|
-
className: TypewriterAssistantNodeView_module_css_default.eventRow,
|
|
1947
|
-
onClickCapture: preventCompactionExpand,
|
|
1948
|
-
"data-stream-node": kind,
|
|
1949
|
-
"data-stream-turn": address?.turn,
|
|
1950
|
-
"data-stream-state": growing ? "running" : "settled",
|
|
1951
|
-
"data-stream-progress": toolProgressActive ? "active" : void 0,
|
|
1952
|
-
"data-stream-tool-row": tool === null ? void 0 : "",
|
|
1953
|
-
"data-stream-native-disclosure": tool === null ? "" : void 0,
|
|
1954
|
-
"data-stream-semantic-icon-owned": ownsStreamSemanticIcon ? kind : void 0,
|
|
1955
|
-
"data-tool-semantic": tool?.semantic,
|
|
1956
|
-
"data-tool-name": tool?.name,
|
|
1957
|
-
children: inner
|
|
1958
|
-
})
|
|
1959
|
-
});
|
|
1960
487
|
}
|
|
1961
488
|
//#endregion
|
|
1962
489
|
//#region \0dsh-css:/home/runner/work/dsh-codex-suite/dsh-codex-suite/packages/conversation-ui/src/client/ConversationCard.module.css.mjs
|
|
1963
|
-
const css$1 = ".XFnqVW_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;min-width:0;list-style:none;transition:border-color .16s,background .16s;display:flex}.XFnqVW_card:hover{border-color:var(--dsw-alias-label-dimmed)}.XFnqVW_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.XFnqVW_header{flex-wrap:wrap;align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.XFnqVW_headText{overflow-wrap:anywhere;flex-direction:column;flex:16rem;gap:4px;min-width:0;display:flex}.XFnqVW_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.XFnqVW_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.XFnqVW_metadata{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;max-width:100%;display:flex}.XFnqVW_version{overflow-wrap:anywhere;min-width:0;max-width:100%;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.XFnqVW_pending{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.XFnqVW_body{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;margin:0 16px;padding-bottom:8px;display:flex}.XFnqVW_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.XFnqVW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.XFnqVW_fieldHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.XFnqVW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.XFnqVW_toggle{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer}.XFnqVW_toggle:disabled{cursor:default}.XFnqVW_toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.XFnqVW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.XFnqVW_failure{justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XFnqVW_updateRow{border-top:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XFnqVW_updateCopy{flex-direction:column;gap:4px;min-width:0;display:flex}.XFnqVW_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.XFnqVW_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.XFnqVW_save,.XFnqVW_discard,.XFnqVW_update{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.XFnqVW_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.XFnqVW_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.XFnqVW_discard:hover:not(:disabled),.XFnqVW_update:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}.XFnqVW_update{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;flex:none;align-items:center;gap:6px;display:inline-flex}.XFnqVW_discard:disabled,.XFnqVW_save:disabled,.XFnqVW_update:disabled{opacity:.4;cursor:default}.XFnqVW_discard:focus-visible,.XFnqVW_save:focus-visible,.XFnqVW_update:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
490
|
+
const css$1 = ".XFnqVW_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;min-width:0;list-style:none;transition:border-color .16s,background .16s;display:flex}.XFnqVW_card:hover{border-color:var(--dsw-alias-label-dimmed)}.XFnqVW_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.XFnqVW_header{flex-wrap:wrap;align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.XFnqVW_headText{overflow-wrap:anywhere;flex-direction:column;flex:16rem;gap:4px;min-width:0;display:flex}.XFnqVW_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.XFnqVW_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.XFnqVW_metadata{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;max-width:100%;display:flex}.XFnqVW_version{overflow-wrap:anywhere;min-width:0;max-width:100%;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.XFnqVW_pending{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.XFnqVW_body{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;margin:0 16px;padding-bottom:8px;display:flex}.XFnqVW_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.XFnqVW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.XFnqVW_fieldHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.XFnqVW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.XFnqVW_toggle{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer}.XFnqVW_toggle:disabled{cursor:default}.XFnqVW_toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.XFnqVW_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);min-width:9.5rem;color:var(--dsw-alias-label-primary);font:inherit;border-radius:6px;flex:none;padding:3px 8px;font-size:12px;line-height:1.5}.XFnqVW_select:disabled{opacity:.5;cursor:default}.XFnqVW_select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.XFnqVW_value{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;line-height:1.5}.XFnqVW_range{width:100%;accent-color:var(--dsw-alias-brand-primary);cursor:pointer}.XFnqVW_range:disabled{opacity:.4;cursor:default}.XFnqVW_range:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.XFnqVW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.XFnqVW_failure{justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XFnqVW_updateRow{border-top:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.XFnqVW_updateCopy{flex-direction:column;gap:4px;min-width:0;display:flex}.XFnqVW_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.XFnqVW_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.XFnqVW_save,.XFnqVW_discard,.XFnqVW_update{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.XFnqVW_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.XFnqVW_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.XFnqVW_discard:hover:not(:disabled),.XFnqVW_update:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}.XFnqVW_update{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;flex:none;align-items:center;gap:6px;display:inline-flex}.XFnqVW_discard:disabled,.XFnqVW_save:disabled,.XFnqVW_update:disabled{opacity:.4;cursor:default}.XFnqVW_discard:focus-visible,.XFnqVW_save:focus-visible,.XFnqVW_update:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
1964
491
|
const tagId$1 = "@jcy2387/dsh-conversation-ui/ConversationCard.module.css";
|
|
1965
492
|
if (typeof document !== "undefined") {
|
|
1966
493
|
let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]");
|
|
@@ -1973,30 +500,33 @@ window.__ModuleLoader__.load({
|
|
|
1973
500
|
tag.textContent = css$1;
|
|
1974
501
|
}
|
|
1975
502
|
var ConversationCard_module_css_default = {
|
|
1976
|
-
"
|
|
1977
|
-
"
|
|
1978
|
-
"
|
|
503
|
+
"metadata": "XFnqVW_metadata",
|
|
504
|
+
"headText": "XFnqVW_headText",
|
|
505
|
+
"fieldHead": "XFnqVW_fieldHead",
|
|
1979
506
|
"toggle": "XFnqVW_toggle",
|
|
1980
|
-
"
|
|
507
|
+
"pending": "XFnqVW_pending",
|
|
508
|
+
"cardOpen": "XFnqVW_cardOpen",
|
|
509
|
+
"field": "XFnqVW_field",
|
|
1981
510
|
"label": "XFnqVW_label",
|
|
511
|
+
"value": "XFnqVW_value",
|
|
512
|
+
"updateCopy": "XFnqVW_updateCopy",
|
|
513
|
+
"select": "XFnqVW_select",
|
|
1982
514
|
"description": "XFnqVW_description",
|
|
1983
|
-
"
|
|
1984
|
-
"fieldHead": "XFnqVW_fieldHead",
|
|
1985
|
-
"hint": "XFnqVW_hint",
|
|
515
|
+
"readOnly": "XFnqVW_readOnly",
|
|
1986
516
|
"failure": "XFnqVW_failure",
|
|
1987
|
-
"
|
|
1988
|
-
"version": "XFnqVW_version",
|
|
1989
|
-
"metadata": "XFnqVW_metadata",
|
|
1990
|
-
"body": "XFnqVW_body",
|
|
517
|
+
"updateRow": "XFnqVW_updateRow",
|
|
1991
518
|
"footer": "XFnqVW_footer",
|
|
1992
|
-
"pending": "XFnqVW_pending",
|
|
1993
|
-
"cardOpen": "XFnqVW_cardOpen",
|
|
1994
|
-
"header": "XFnqVW_header",
|
|
1995
519
|
"failed": "XFnqVW_failed",
|
|
520
|
+
"header": "XFnqVW_header",
|
|
1996
521
|
"save": "XFnqVW_save",
|
|
1997
522
|
"discard": "XFnqVW_discard",
|
|
523
|
+
"card": "XFnqVW_card",
|
|
1998
524
|
"update": "XFnqVW_update",
|
|
1999
|
-
"
|
|
525
|
+
"range": "XFnqVW_range",
|
|
526
|
+
"version": "XFnqVW_version",
|
|
527
|
+
"name": "XFnqVW_name",
|
|
528
|
+
"body": "XFnqVW_body",
|
|
529
|
+
"hint": "XFnqVW_hint"
|
|
2000
530
|
};
|
|
2001
531
|
//#endregion
|
|
2002
532
|
//#region src/client/ConversationCard.tsx
|
|
@@ -2057,6 +587,103 @@ window.__ModuleLoader__.load({
|
|
|
2057
587
|
role: "status",
|
|
2058
588
|
children: t("readOnly")
|
|
2059
589
|
}) : null,
|
|
590
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
591
|
+
className: ConversationCard_module_css_default.field,
|
|
592
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
593
|
+
className: ConversationCard_module_css_default.fieldHead,
|
|
594
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
595
|
+
className: ConversationCard_module_css_default.label,
|
|
596
|
+
children: t("mode")
|
|
597
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
598
|
+
className: ConversationCard_module_css_default.select,
|
|
599
|
+
value: state.mode,
|
|
600
|
+
disabled: !state.writable,
|
|
601
|
+
onChange: (event) => {
|
|
602
|
+
props.edit({ mode: event.target.value });
|
|
603
|
+
},
|
|
604
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
605
|
+
value: "typewriter",
|
|
606
|
+
children: t("modeTypewriter")
|
|
607
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
608
|
+
value: "teleprompter",
|
|
609
|
+
children: t("modeTeleprompter")
|
|
610
|
+
})]
|
|
611
|
+
})]
|
|
612
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
613
|
+
className: ConversationCard_module_css_default.hint,
|
|
614
|
+
children: t("modeHint")
|
|
615
|
+
})]
|
|
616
|
+
}),
|
|
617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
618
|
+
className: ConversationCard_module_css_default.field,
|
|
619
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
620
|
+
className: ConversationCard_module_css_default.fieldHead,
|
|
621
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
622
|
+
className: ConversationCard_module_css_default.label,
|
|
623
|
+
children: t("preset")
|
|
624
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
625
|
+
className: ConversationCard_module_css_default.select,
|
|
626
|
+
value: state.preset,
|
|
627
|
+
disabled: !state.writable,
|
|
628
|
+
onChange: (event) => {
|
|
629
|
+
props.edit({ preset: event.target.value });
|
|
630
|
+
},
|
|
631
|
+
children: [
|
|
632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
633
|
+
value: "realtime",
|
|
634
|
+
children: t("presetRealtime")
|
|
635
|
+
}),
|
|
636
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
637
|
+
value: "balanced",
|
|
638
|
+
children: t("presetBalanced")
|
|
639
|
+
}),
|
|
640
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
641
|
+
value: "silky",
|
|
642
|
+
children: t("presetSilky")
|
|
643
|
+
})
|
|
644
|
+
]
|
|
645
|
+
})]
|
|
646
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
647
|
+
className: ConversationCard_module_css_default.hint,
|
|
648
|
+
children: t("presetHint")
|
|
649
|
+
})]
|
|
650
|
+
}),
|
|
651
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
652
|
+
className: ConversationCard_module_css_default.field,
|
|
653
|
+
children: [
|
|
654
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
655
|
+
className: ConversationCard_module_css_default.fieldHead,
|
|
656
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
657
|
+
className: ConversationCard_module_css_default.label,
|
|
658
|
+
children: t("revealSpeed")
|
|
659
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
660
|
+
className: ConversationCard_module_css_default.value,
|
|
661
|
+
children: [
|
|
662
|
+
state.revealCharsPerSec,
|
|
663
|
+
" ",
|
|
664
|
+
t("charsPerSecond")
|
|
665
|
+
]
|
|
666
|
+
})]
|
|
667
|
+
}),
|
|
668
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
669
|
+
type: "range",
|
|
670
|
+
className: ConversationCard_module_css_default.range,
|
|
671
|
+
min: 5,
|
|
672
|
+
max: 200,
|
|
673
|
+
step: 5,
|
|
674
|
+
value: state.revealCharsPerSec,
|
|
675
|
+
disabled: !state.writable || state.mode !== "typewriter",
|
|
676
|
+
onChange: (event) => {
|
|
677
|
+
const value = Number(event.target.value);
|
|
678
|
+
if (Number.isFinite(value)) props.edit({ revealCharsPerSec: value });
|
|
679
|
+
}
|
|
680
|
+
}),
|
|
681
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
682
|
+
className: ConversationCard_module_css_default.hint,
|
|
683
|
+
children: t("revealSpeedHint")
|
|
684
|
+
})
|
|
685
|
+
]
|
|
686
|
+
}),
|
|
2060
687
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2061
688
|
className: ConversationCard_module_css_default.field,
|
|
2062
689
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -2070,7 +697,7 @@ window.__ModuleLoader__.load({
|
|
|
2070
697
|
checked: state.thinkAutoExpand,
|
|
2071
698
|
disabled: !state.writable,
|
|
2072
699
|
onChange: (event) => {
|
|
2073
|
-
props.edit(event.target.checked);
|
|
700
|
+
props.edit({ thinkAutoExpand: event.target.checked });
|
|
2074
701
|
}
|
|
2075
702
|
})]
|
|
2076
703
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -2690,7 +1317,7 @@ window.__ModuleLoader__.load({
|
|
|
2690
1317
|
immer.createDraft.bind(immer);
|
|
2691
1318
|
immer.finishDraft.bind(immer);
|
|
2692
1319
|
//#endregion
|
|
2693
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-client-store@0.2.
|
|
1320
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-client-store@0.2.1-rc.2_@deepseek-ai+cordis@4.0.5/node_modules/@deepseek-ai/dsh-client-store/lib/index.js
|
|
2694
1321
|
/**
|
|
2695
1322
|
* React-free snapshot store engine (zustand vanilla + immer + subscribeWithSelector +
|
|
2696
1323
|
* rafFlush middleware + opt-in persist + dev freeze) plus the declarative
|
|
@@ -2807,6 +1434,38 @@ window.__ModuleLoader__.load({
|
|
|
2807
1434
|
return freeze(value, true);
|
|
2808
1435
|
}
|
|
2809
1436
|
//#endregion
|
|
1437
|
+
//#region src/config.ts
|
|
1438
|
+
/** Defaults shared by the Host schema and the client-side fallback. */
|
|
1439
|
+
const DEFAULT_CONVERSATION_CONFIG = {
|
|
1440
|
+
mode: "typewriter",
|
|
1441
|
+
preset: "balanced",
|
|
1442
|
+
revealCharsPerSec: 80,
|
|
1443
|
+
scrollSpeedPxPerSec: 48,
|
|
1444
|
+
maxScrollSpeedPxPerSec: 1e3
|
|
1445
|
+
};
|
|
1446
|
+
/**
|
|
1447
|
+
* Window global the Host writes into the served index HTML. The browser boot
|
|
1448
|
+
* graph carries no per-entry config, so this inline script is the only
|
|
1449
|
+
* Host-to-client configuration channel for a composed web plugin.
|
|
1450
|
+
*/
|
|
1451
|
+
const CONVERSATION_BOOT_GLOBAL = "__DSH_CONVERSATION_UI_CONFIG__";
|
|
1452
|
+
//#endregion
|
|
1453
|
+
//#region src/settings.ts
|
|
1454
|
+
/**
|
|
1455
|
+
* User-owned settings for the conversation-ui plugin, exposed to the Host
|
|
1456
|
+
* settings service and edited from the Web Settings "plugin configuration"
|
|
1457
|
+
* page. The profile overlay still supplies deployment defaults (including the
|
|
1458
|
+
* deprecated scroll fields), but these fields are the live, durable
|
|
1459
|
+
* user-facing preferences.
|
|
1460
|
+
*/
|
|
1461
|
+
/** Defaults shared by the Host schema, the client fallback, and the boot bridge. */
|
|
1462
|
+
const DEFAULT_CONVERSATION_SETTINGS = {
|
|
1463
|
+
thinkAutoExpand: true,
|
|
1464
|
+
mode: DEFAULT_CONVERSATION_CONFIG.mode,
|
|
1465
|
+
preset: DEFAULT_CONVERSATION_CONFIG.preset,
|
|
1466
|
+
revealCharsPerSec: DEFAULT_CONVERSATION_CONFIG.revealCharsPerSec
|
|
1467
|
+
};
|
|
1468
|
+
//#endregion
|
|
2810
1469
|
//#region src/client/conversation-ui-card-controller.ts
|
|
2811
1470
|
/** Staged form state for the plugin-owned conversation-ui settings RPC. */
|
|
2812
1471
|
/** Bridges the plugin's protected Host interface onto a staged settings form. */
|
|
@@ -2845,8 +1504,12 @@ window.__ModuleLoader__.load({
|
|
|
2845
1504
|
inject() {
|
|
2846
1505
|
return {
|
|
2847
1506
|
hooks: { conversationUiCard: this.store },
|
|
2848
|
-
edit: (
|
|
2849
|
-
|
|
1507
|
+
edit: (patch) => {
|
|
1508
|
+
if (Object.keys(patch).length === 0) return;
|
|
1509
|
+
this.staged = {
|
|
1510
|
+
...this.staged,
|
|
1511
|
+
...patch
|
|
1512
|
+
};
|
|
2850
1513
|
this.failed = false;
|
|
2851
1514
|
this.publish();
|
|
2852
1515
|
},
|
|
@@ -2871,10 +1534,13 @@ window.__ModuleLoader__.load({
|
|
|
2871
1534
|
return {
|
|
2872
1535
|
status: this.loadStatus,
|
|
2873
1536
|
writable: this.loaded?.writable ?? false,
|
|
2874
|
-
dirty: this.staged !== void 0,
|
|
1537
|
+
dirty: this.staged !== void 0 && Object.keys(this.staged).length > 0,
|
|
2875
1538
|
saving: this.saving,
|
|
2876
1539
|
failed: this.failed,
|
|
2877
|
-
thinkAutoExpand: this.staged ?? this.loaded?.thinkAutoExpand ?? DEFAULT_CONVERSATION_SETTINGS.thinkAutoExpand,
|
|
1540
|
+
thinkAutoExpand: this.staged?.thinkAutoExpand ?? this.loaded?.thinkAutoExpand ?? DEFAULT_CONVERSATION_SETTINGS.thinkAutoExpand,
|
|
1541
|
+
mode: this.staged?.mode ?? this.loaded?.mode ?? DEFAULT_CONVERSATION_SETTINGS.mode,
|
|
1542
|
+
preset: this.staged?.preset ?? this.loaded?.preset ?? DEFAULT_CONVERSATION_SETTINGS.preset,
|
|
1543
|
+
revealCharsPerSec: this.staged?.revealCharsPerSec ?? this.loaded?.revealCharsPerSec ?? DEFAULT_CONVERSATION_SETTINGS.revealCharsPerSec,
|
|
2878
1544
|
version: this.loaded?.version,
|
|
2879
1545
|
installation: this.loaded?.installation ?? "unmanaged",
|
|
2880
1546
|
canUpgrade: this.loaded?.canUpgrade ?? false,
|
|
@@ -2901,7 +1567,7 @@ window.__ModuleLoader__.load({
|
|
|
2901
1567
|
this.publish();
|
|
2902
1568
|
}
|
|
2903
1569
|
async save() {
|
|
2904
|
-
if (this.staged === void 0 || this.saving || this.loaded?.writable !== true) return;
|
|
1570
|
+
if (this.staged === void 0 || Object.keys(this.staged).length === 0 || this.saving || this.loaded?.writable !== true) return;
|
|
2905
1571
|
const value = this.staged;
|
|
2906
1572
|
this.saving = true;
|
|
2907
1573
|
this.failed = false;
|
|
@@ -2935,7 +1601,524 @@ window.__ModuleLoader__.load({
|
|
|
2935
1601
|
}
|
|
2936
1602
|
};
|
|
2937
1603
|
//#endregion
|
|
2938
|
-
//#region ../../node_modules/.pnpm
|
|
1604
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/base.js
|
|
1605
|
+
var Diff = class {
|
|
1606
|
+
diff(oldStr, newStr, options = {}) {
|
|
1607
|
+
let callback;
|
|
1608
|
+
if (typeof options === "function") {
|
|
1609
|
+
callback = options;
|
|
1610
|
+
options = {};
|
|
1611
|
+
} else if ("callback" in options) callback = options.callback;
|
|
1612
|
+
const oldString = this.castInput(oldStr, options);
|
|
1613
|
+
const newString = this.castInput(newStr, options);
|
|
1614
|
+
const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
|
|
1615
|
+
const newTokens = this.removeEmpty(this.tokenize(newString, options));
|
|
1616
|
+
return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
|
|
1617
|
+
}
|
|
1618
|
+
diffWithOptionsObj(oldTokens, newTokens, options, callback) {
|
|
1619
|
+
var _a;
|
|
1620
|
+
const done = (value) => {
|
|
1621
|
+
value = this.postProcess(value, options);
|
|
1622
|
+
if (callback) {
|
|
1623
|
+
setTimeout(function() {
|
|
1624
|
+
callback(value);
|
|
1625
|
+
}, 0);
|
|
1626
|
+
return;
|
|
1627
|
+
} else return value;
|
|
1628
|
+
};
|
|
1629
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
1630
|
+
let editLength = 1;
|
|
1631
|
+
let maxEditLength = newLen + oldLen;
|
|
1632
|
+
if (options.maxEditLength != null) maxEditLength = Math.min(maxEditLength, options.maxEditLength);
|
|
1633
|
+
const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
|
|
1634
|
+
const abortAfterTimestamp = Date.now() + maxExecutionTime;
|
|
1635
|
+
const bestPath = [{
|
|
1636
|
+
oldPos: -1,
|
|
1637
|
+
lastComponent: void 0
|
|
1638
|
+
}];
|
|
1639
|
+
let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
|
|
1640
|
+
if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
|
|
1641
|
+
let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
|
|
1642
|
+
const execEditLength = () => {
|
|
1643
|
+
for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
|
|
1644
|
+
let basePath;
|
|
1645
|
+
const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
|
|
1646
|
+
if (removePath) bestPath[diagonalPath - 1] = void 0;
|
|
1647
|
+
let canAdd = false;
|
|
1648
|
+
if (addPath) {
|
|
1649
|
+
const addPathNewPos = addPath.oldPos - diagonalPath;
|
|
1650
|
+
canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
|
|
1651
|
+
}
|
|
1652
|
+
const canRemove = removePath && removePath.oldPos + 1 < oldLen;
|
|
1653
|
+
if (!canAdd && !canRemove) {
|
|
1654
|
+
bestPath[diagonalPath] = void 0;
|
|
1655
|
+
continue;
|
|
1656
|
+
}
|
|
1657
|
+
if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) basePath = this.addToPath(addPath, true, false, 0, options);
|
|
1658
|
+
else basePath = this.addToPath(removePath, false, true, 1, options);
|
|
1659
|
+
newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
|
|
1660
|
+
if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
|
|
1661
|
+
else {
|
|
1662
|
+
bestPath[diagonalPath] = basePath;
|
|
1663
|
+
if (basePath.oldPos + 1 >= oldLen) maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
|
|
1664
|
+
if (newPos + 1 >= newLen) minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
editLength++;
|
|
1668
|
+
};
|
|
1669
|
+
if (callback) (function exec() {
|
|
1670
|
+
setTimeout(function() {
|
|
1671
|
+
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) return callback(void 0);
|
|
1672
|
+
if (!execEditLength()) exec();
|
|
1673
|
+
}, 0);
|
|
1674
|
+
})();
|
|
1675
|
+
else while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
|
|
1676
|
+
const ret = execEditLength();
|
|
1677
|
+
if (ret) return ret;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
addToPath(path, added, removed, oldPosInc, options) {
|
|
1681
|
+
const last = path.lastComponent;
|
|
1682
|
+
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) return {
|
|
1683
|
+
oldPos: path.oldPos + oldPosInc,
|
|
1684
|
+
lastComponent: {
|
|
1685
|
+
count: last.count + 1,
|
|
1686
|
+
added,
|
|
1687
|
+
removed,
|
|
1688
|
+
previousComponent: last.previousComponent
|
|
1689
|
+
}
|
|
1690
|
+
};
|
|
1691
|
+
else return {
|
|
1692
|
+
oldPos: path.oldPos + oldPosInc,
|
|
1693
|
+
lastComponent: {
|
|
1694
|
+
count: 1,
|
|
1695
|
+
added,
|
|
1696
|
+
removed,
|
|
1697
|
+
previousComponent: last
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
|
|
1702
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
1703
|
+
let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
|
|
1704
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
|
|
1705
|
+
newPos++;
|
|
1706
|
+
oldPos++;
|
|
1707
|
+
commonCount++;
|
|
1708
|
+
if (options.oneChangePerToken) basePath.lastComponent = {
|
|
1709
|
+
count: 1,
|
|
1710
|
+
previousComponent: basePath.lastComponent,
|
|
1711
|
+
added: false,
|
|
1712
|
+
removed: false
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
if (commonCount && !options.oneChangePerToken) basePath.lastComponent = {
|
|
1716
|
+
count: commonCount,
|
|
1717
|
+
previousComponent: basePath.lastComponent,
|
|
1718
|
+
added: false,
|
|
1719
|
+
removed: false
|
|
1720
|
+
};
|
|
1721
|
+
basePath.oldPos = oldPos;
|
|
1722
|
+
return newPos;
|
|
1723
|
+
}
|
|
1724
|
+
equals(left, right, options) {
|
|
1725
|
+
if (options.comparator) return options.comparator(left, right);
|
|
1726
|
+
else return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
1727
|
+
}
|
|
1728
|
+
removeEmpty(array) {
|
|
1729
|
+
const ret = [];
|
|
1730
|
+
for (let i = 0; i < array.length; i++) if (array[i]) ret.push(array[i]);
|
|
1731
|
+
return ret;
|
|
1732
|
+
}
|
|
1733
|
+
castInput(value, options) {
|
|
1734
|
+
return value;
|
|
1735
|
+
}
|
|
1736
|
+
tokenize(value, options) {
|
|
1737
|
+
return Array.from(value);
|
|
1738
|
+
}
|
|
1739
|
+
join(chars) {
|
|
1740
|
+
return chars.join("");
|
|
1741
|
+
}
|
|
1742
|
+
postProcess(changeObjects, options) {
|
|
1743
|
+
return changeObjects;
|
|
1744
|
+
}
|
|
1745
|
+
get useLongestToken() {
|
|
1746
|
+
return false;
|
|
1747
|
+
}
|
|
1748
|
+
buildValues(lastComponent, newTokens, oldTokens) {
|
|
1749
|
+
const components = [];
|
|
1750
|
+
let nextComponent;
|
|
1751
|
+
while (lastComponent) {
|
|
1752
|
+
components.push(lastComponent);
|
|
1753
|
+
nextComponent = lastComponent.previousComponent;
|
|
1754
|
+
delete lastComponent.previousComponent;
|
|
1755
|
+
lastComponent = nextComponent;
|
|
1756
|
+
}
|
|
1757
|
+
components.reverse();
|
|
1758
|
+
const componentLen = components.length;
|
|
1759
|
+
let componentPos = 0, newPos = 0, oldPos = 0;
|
|
1760
|
+
for (; componentPos < componentLen; componentPos++) {
|
|
1761
|
+
const component = components[componentPos];
|
|
1762
|
+
if (!component.removed) {
|
|
1763
|
+
if (!component.added && this.useLongestToken) {
|
|
1764
|
+
let value = newTokens.slice(newPos, newPos + component.count);
|
|
1765
|
+
value = value.map(function(value, i) {
|
|
1766
|
+
const oldValue = oldTokens[oldPos + i];
|
|
1767
|
+
return oldValue.length > value.length ? oldValue : value;
|
|
1768
|
+
});
|
|
1769
|
+
component.value = this.join(value);
|
|
1770
|
+
} else component.value = this.join(newTokens.slice(newPos, newPos + component.count));
|
|
1771
|
+
newPos += component.count;
|
|
1772
|
+
if (!component.added) oldPos += component.count;
|
|
1773
|
+
} else {
|
|
1774
|
+
component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
|
|
1775
|
+
oldPos += component.count;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
return components;
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
//#endregion
|
|
1782
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/character.js
|
|
1783
|
+
var CharacterDiff = class extends Diff {};
|
|
1784
|
+
new CharacterDiff();
|
|
1785
|
+
//#endregion
|
|
1786
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/util/string.js
|
|
1787
|
+
function longestCommonPrefix(str1, str2) {
|
|
1788
|
+
let i;
|
|
1789
|
+
for (i = 0; i < str1.length && i < str2.length; i++) if (str1[i] != str2[i]) return str1.slice(0, i);
|
|
1790
|
+
return str1.slice(0, i);
|
|
1791
|
+
}
|
|
1792
|
+
function longestCommonSuffix(str1, str2) {
|
|
1793
|
+
let i;
|
|
1794
|
+
if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) return "";
|
|
1795
|
+
for (i = 0; i < str1.length && i < str2.length; i++) if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) return str1.slice(-i);
|
|
1796
|
+
return str1.slice(-i);
|
|
1797
|
+
}
|
|
1798
|
+
function replacePrefix(string, oldPrefix, newPrefix) {
|
|
1799
|
+
if (string.slice(0, oldPrefix.length) != oldPrefix) throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);
|
|
1800
|
+
return newPrefix + string.slice(oldPrefix.length);
|
|
1801
|
+
}
|
|
1802
|
+
function replaceSuffix(string, oldSuffix, newSuffix) {
|
|
1803
|
+
if (!oldSuffix) return string + newSuffix;
|
|
1804
|
+
if (string.slice(-oldSuffix.length) != oldSuffix) throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);
|
|
1805
|
+
return string.slice(0, -oldSuffix.length) + newSuffix;
|
|
1806
|
+
}
|
|
1807
|
+
function removePrefix(string, oldPrefix) {
|
|
1808
|
+
return replacePrefix(string, oldPrefix, "");
|
|
1809
|
+
}
|
|
1810
|
+
function removeSuffix(string, oldSuffix) {
|
|
1811
|
+
return replaceSuffix(string, oldSuffix, "");
|
|
1812
|
+
}
|
|
1813
|
+
function maximumOverlap(string1, string2) {
|
|
1814
|
+
return string2.slice(0, overlapCount(string1, string2));
|
|
1815
|
+
}
|
|
1816
|
+
function overlapCount(a, b) {
|
|
1817
|
+
let startA = 0;
|
|
1818
|
+
if (a.length > b.length) startA = a.length - b.length;
|
|
1819
|
+
let endB = b.length;
|
|
1820
|
+
if (a.length < b.length) endB = a.length;
|
|
1821
|
+
const map = Array(endB);
|
|
1822
|
+
let k = 0;
|
|
1823
|
+
map[0] = 0;
|
|
1824
|
+
for (let j = 1; j < endB; j++) {
|
|
1825
|
+
if (b[j] == b[k]) map[j] = map[k];
|
|
1826
|
+
else map[j] = k;
|
|
1827
|
+
while (k > 0 && b[j] != b[k]) k = map[k];
|
|
1828
|
+
if (b[j] == b[k]) k++;
|
|
1829
|
+
}
|
|
1830
|
+
k = 0;
|
|
1831
|
+
for (let i = startA; i < a.length; i++) {
|
|
1832
|
+
while (k > 0 && a[i] != b[k]) k = map[k];
|
|
1833
|
+
if (a[i] == b[k]) k++;
|
|
1834
|
+
}
|
|
1835
|
+
return k;
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Split a string into segments using a word segmenter, merging consecutive
|
|
1839
|
+
* segments if they are both whitespace segments. Whitespace segments can
|
|
1840
|
+
* appear adjacent to one another for two reasons:
|
|
1841
|
+
* - newlines always get their own segment
|
|
1842
|
+
* - where a diacritic is attached to a whitespace character in the text, the
|
|
1843
|
+
* segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
|
|
1844
|
+
* This function therefore runs the segmenter's .segment() method and then
|
|
1845
|
+
* merges consecutive segments of whitespace into a single part.
|
|
1846
|
+
*/
|
|
1847
|
+
function segment(string, segmenter) {
|
|
1848
|
+
const parts = [];
|
|
1849
|
+
for (const segmentObj of Array.from(segmenter.segment(string))) {
|
|
1850
|
+
const segment = segmentObj.segment;
|
|
1851
|
+
if (parts.length && /\s/.test(parts[parts.length - 1]) && /\s/.test(segment)) parts[parts.length - 1] += segment;
|
|
1852
|
+
else parts.push(segment);
|
|
1853
|
+
}
|
|
1854
|
+
return parts;
|
|
1855
|
+
}
|
|
1856
|
+
function trailingWs(string, segmenter) {
|
|
1857
|
+
if (segmenter) return leadingAndTrailingWs(string, segmenter)[1];
|
|
1858
|
+
let i;
|
|
1859
|
+
for (i = string.length - 1; i >= 0; i--) if (!string[i].match(/\s/)) break;
|
|
1860
|
+
return string.substring(i + 1);
|
|
1861
|
+
}
|
|
1862
|
+
function leadingWs(string, segmenter) {
|
|
1863
|
+
if (segmenter) return leadingAndTrailingWs(string, segmenter)[0];
|
|
1864
|
+
const match = string.match(/^\s*/);
|
|
1865
|
+
return match ? match[0] : "";
|
|
1866
|
+
}
|
|
1867
|
+
function leadingAndTrailingWs(string, segmenter) {
|
|
1868
|
+
if (!segmenter) return [leadingWs(string), trailingWs(string)];
|
|
1869
|
+
if (segmenter.resolvedOptions().granularity != "word") throw new Error("The segmenter passed must have a granularity of \"word\"");
|
|
1870
|
+
const segments = segment(string, segmenter);
|
|
1871
|
+
const firstSeg = segments[0];
|
|
1872
|
+
const lastSeg = segments[segments.length - 1];
|
|
1873
|
+
return [/\s/.test(firstSeg) ? firstSeg : "", /\s/.test(lastSeg) ? lastSeg : ""];
|
|
1874
|
+
}
|
|
1875
|
+
//#endregion
|
|
1876
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/word.js
|
|
1877
|
+
const extendedWordChars = "a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";
|
|
1878
|
+
const tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug");
|
|
1879
|
+
var WordDiff = class extends Diff {
|
|
1880
|
+
equals(left, right, options) {
|
|
1881
|
+
if (options.ignoreCase) {
|
|
1882
|
+
left = left.toLowerCase();
|
|
1883
|
+
right = right.toLowerCase();
|
|
1884
|
+
}
|
|
1885
|
+
return left.trim() === right.trim();
|
|
1886
|
+
}
|
|
1887
|
+
tokenize(value, options = {}) {
|
|
1888
|
+
let parts;
|
|
1889
|
+
if (options.intlSegmenter) {
|
|
1890
|
+
const segmenter = options.intlSegmenter;
|
|
1891
|
+
if (segmenter.resolvedOptions().granularity != "word") throw new Error("The segmenter passed must have a granularity of \"word\"");
|
|
1892
|
+
parts = segment(value, segmenter);
|
|
1893
|
+
} else parts = value.match(tokenizeIncludingWhitespace) || [];
|
|
1894
|
+
const tokens = [];
|
|
1895
|
+
let prevPart = null;
|
|
1896
|
+
parts.forEach((part) => {
|
|
1897
|
+
if (/\s/.test(part)) {
|
|
1898
|
+
if (prevPart == null) tokens.push(part);
|
|
1899
|
+
else tokens.push(tokens.pop() + part);
|
|
1900
|
+
} else if (prevPart != null && /\s/.test(prevPart)) {
|
|
1901
|
+
if (tokens[tokens.length - 1] == prevPart) tokens.push(tokens.pop() + part);
|
|
1902
|
+
else tokens.push(prevPart + part);
|
|
1903
|
+
} else tokens.push(part);
|
|
1904
|
+
prevPart = part;
|
|
1905
|
+
});
|
|
1906
|
+
return tokens;
|
|
1907
|
+
}
|
|
1908
|
+
join(tokens) {
|
|
1909
|
+
return tokens.map((token, i) => {
|
|
1910
|
+
if (i == 0) return token;
|
|
1911
|
+
else return token.replace(/^\s+/, "");
|
|
1912
|
+
}).join("");
|
|
1913
|
+
}
|
|
1914
|
+
postProcess(changes, options) {
|
|
1915
|
+
if (!changes || options.oneChangePerToken) return changes;
|
|
1916
|
+
let lastKeep = null;
|
|
1917
|
+
let insertion = null;
|
|
1918
|
+
let deletion = null;
|
|
1919
|
+
changes.forEach((change) => {
|
|
1920
|
+
if (change.added) insertion = change;
|
|
1921
|
+
else if (change.removed) deletion = change;
|
|
1922
|
+
else {
|
|
1923
|
+
if (insertion || deletion) dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change, options.intlSegmenter);
|
|
1924
|
+
lastKeep = change;
|
|
1925
|
+
insertion = null;
|
|
1926
|
+
deletion = null;
|
|
1927
|
+
}
|
|
1928
|
+
});
|
|
1929
|
+
if (insertion || deletion) dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
|
|
1930
|
+
return changes;
|
|
1931
|
+
}
|
|
1932
|
+
};
|
|
1933
|
+
new WordDiff();
|
|
1934
|
+
function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep, segmenter) {
|
|
1935
|
+
if (deletion && insertion) {
|
|
1936
|
+
const [oldWsPrefix, oldWsSuffix] = leadingAndTrailingWs(deletion.value, segmenter);
|
|
1937
|
+
const [newWsPrefix, newWsSuffix] = leadingAndTrailingWs(insertion.value, segmenter);
|
|
1938
|
+
if (startKeep) {
|
|
1939
|
+
const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
|
|
1940
|
+
startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
|
|
1941
|
+
deletion.value = removePrefix(deletion.value, commonWsPrefix);
|
|
1942
|
+
insertion.value = removePrefix(insertion.value, commonWsPrefix);
|
|
1943
|
+
}
|
|
1944
|
+
if (endKeep) {
|
|
1945
|
+
const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
|
|
1946
|
+
endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
|
|
1947
|
+
deletion.value = removeSuffix(deletion.value, commonWsSuffix);
|
|
1948
|
+
insertion.value = removeSuffix(insertion.value, commonWsSuffix);
|
|
1949
|
+
}
|
|
1950
|
+
} else if (insertion) {
|
|
1951
|
+
if (startKeep) {
|
|
1952
|
+
const ws = leadingWs(insertion.value, segmenter);
|
|
1953
|
+
insertion.value = insertion.value.substring(ws.length);
|
|
1954
|
+
}
|
|
1955
|
+
if (endKeep) {
|
|
1956
|
+
const ws = leadingWs(endKeep.value, segmenter);
|
|
1957
|
+
endKeep.value = endKeep.value.substring(ws.length);
|
|
1958
|
+
}
|
|
1959
|
+
} else if (startKeep && endKeep) {
|
|
1960
|
+
const newWsFull = leadingWs(endKeep.value, segmenter), [delWsStart, delWsEnd] = leadingAndTrailingWs(deletion.value, segmenter);
|
|
1961
|
+
const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
|
|
1962
|
+
deletion.value = removePrefix(deletion.value, newWsStart);
|
|
1963
|
+
const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
|
|
1964
|
+
deletion.value = removeSuffix(deletion.value, newWsEnd);
|
|
1965
|
+
endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
|
|
1966
|
+
startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
|
|
1967
|
+
} else if (endKeep) {
|
|
1968
|
+
const endKeepWsPrefix = leadingWs(endKeep.value, segmenter);
|
|
1969
|
+
const overlap = maximumOverlap(trailingWs(deletion.value, segmenter), endKeepWsPrefix);
|
|
1970
|
+
deletion.value = removeSuffix(deletion.value, overlap);
|
|
1971
|
+
} else if (startKeep) {
|
|
1972
|
+
const overlap = maximumOverlap(trailingWs(startKeep.value, segmenter), leadingWs(deletion.value, segmenter));
|
|
1973
|
+
deletion.value = removePrefix(deletion.value, overlap);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
var WordsWithSpaceDiff = class extends Diff {
|
|
1977
|
+
tokenize(value) {
|
|
1978
|
+
const regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug");
|
|
1979
|
+
return value.match(regex) || [];
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
new WordsWithSpaceDiff();
|
|
1983
|
+
//#endregion
|
|
1984
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/line.js
|
|
1985
|
+
var LineDiff = class extends Diff {
|
|
1986
|
+
constructor() {
|
|
1987
|
+
super(...arguments);
|
|
1988
|
+
this.tokenize = tokenize;
|
|
1989
|
+
}
|
|
1990
|
+
equals(left, right, options) {
|
|
1991
|
+
if (options.ignoreWhitespace) {
|
|
1992
|
+
if (!options.newlineIsToken || !left.includes("\n")) left = left.trim();
|
|
1993
|
+
if (!options.newlineIsToken || !right.includes("\n")) right = right.trim();
|
|
1994
|
+
} else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
|
|
1995
|
+
if (left.endsWith("\n")) left = left.slice(0, -1);
|
|
1996
|
+
if (right.endsWith("\n")) right = right.slice(0, -1);
|
|
1997
|
+
}
|
|
1998
|
+
return super.equals(left, right, options);
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
const lineDiff = new LineDiff();
|
|
2002
|
+
function diffLines(oldStr, newStr, options) {
|
|
2003
|
+
return lineDiff.diff(oldStr, newStr, options);
|
|
2004
|
+
}
|
|
2005
|
+
function tokenize(value, options) {
|
|
2006
|
+
if (options.stripTrailingCr) value = value.replace(/\r\n/g, "\n");
|
|
2007
|
+
const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
|
|
2008
|
+
if (!linesAndNewlines[linesAndNewlines.length - 1]) linesAndNewlines.pop();
|
|
2009
|
+
for (let i = 0; i < linesAndNewlines.length; i++) {
|
|
2010
|
+
const line = linesAndNewlines[i];
|
|
2011
|
+
if (i % 2 && !options.newlineIsToken) retLines[retLines.length - 1] += line;
|
|
2012
|
+
else retLines.push(line);
|
|
2013
|
+
}
|
|
2014
|
+
return retLines;
|
|
2015
|
+
}
|
|
2016
|
+
//#endregion
|
|
2017
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/sentence.js
|
|
2018
|
+
function isSentenceEndPunct(char) {
|
|
2019
|
+
return char == "." || char == "!" || char == "?";
|
|
2020
|
+
}
|
|
2021
|
+
var SentenceDiff = class extends Diff {
|
|
2022
|
+
tokenize(value) {
|
|
2023
|
+
var _a;
|
|
2024
|
+
const result = [];
|
|
2025
|
+
let tokenStartI = 0;
|
|
2026
|
+
for (let i = 0; i < value.length; i++) {
|
|
2027
|
+
if (i == value.length - 1) {
|
|
2028
|
+
result.push(value.slice(tokenStartI));
|
|
2029
|
+
break;
|
|
2030
|
+
}
|
|
2031
|
+
if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\s/)) {
|
|
2032
|
+
result.push(value.slice(tokenStartI, i + 1));
|
|
2033
|
+
i = tokenStartI = i + 1;
|
|
2034
|
+
while ((_a = value[i + 1]) === null || _a === void 0 ? void 0 : _a.match(/\s/)) i++;
|
|
2035
|
+
result.push(value.slice(tokenStartI, i + 1));
|
|
2036
|
+
tokenStartI = i + 1;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
return result;
|
|
2040
|
+
}
|
|
2041
|
+
};
|
|
2042
|
+
new SentenceDiff();
|
|
2043
|
+
//#endregion
|
|
2044
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/css.js
|
|
2045
|
+
var CssDiff = class extends Diff {
|
|
2046
|
+
tokenize(value) {
|
|
2047
|
+
return value.split(/([{}:;,]|\s+)/);
|
|
2048
|
+
}
|
|
2049
|
+
};
|
|
2050
|
+
new CssDiff();
|
|
2051
|
+
//#endregion
|
|
2052
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/json.js
|
|
2053
|
+
var JsonDiff = class extends Diff {
|
|
2054
|
+
constructor() {
|
|
2055
|
+
super(...arguments);
|
|
2056
|
+
this.tokenize = tokenize;
|
|
2057
|
+
}
|
|
2058
|
+
get useLongestToken() {
|
|
2059
|
+
return true;
|
|
2060
|
+
}
|
|
2061
|
+
castInput(value, options) {
|
|
2062
|
+
const { undefinedReplacement, stringifyReplacer = (k, v) => typeof v === "undefined" ? undefinedReplacement : v } = options;
|
|
2063
|
+
return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), null, " ");
|
|
2064
|
+
}
|
|
2065
|
+
equals(left, right, options) {
|
|
2066
|
+
return super.equals(left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options);
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
new JsonDiff();
|
|
2070
|
+
function canonicalize(obj, stack, replacementStack, replacer, key) {
|
|
2071
|
+
stack = stack || [];
|
|
2072
|
+
replacementStack = replacementStack || [];
|
|
2073
|
+
if (replacer) obj = replacer(key === void 0 ? "" : key, obj);
|
|
2074
|
+
let i;
|
|
2075
|
+
for (i = 0; i < stack.length; i += 1) if (stack[i] === obj) return replacementStack[i];
|
|
2076
|
+
let canonicalizedObj;
|
|
2077
|
+
if ("[object Array]" === Object.prototype.toString.call(obj)) {
|
|
2078
|
+
stack.push(obj);
|
|
2079
|
+
canonicalizedObj = new Array(obj.length);
|
|
2080
|
+
replacementStack.push(canonicalizedObj);
|
|
2081
|
+
for (i = 0; i < obj.length; i += 1) canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, String(i));
|
|
2082
|
+
stack.pop();
|
|
2083
|
+
replacementStack.pop();
|
|
2084
|
+
return canonicalizedObj;
|
|
2085
|
+
}
|
|
2086
|
+
if (obj && obj.toJSON) obj = obj.toJSON();
|
|
2087
|
+
if (typeof obj === "object" && obj !== null) {
|
|
2088
|
+
stack.push(obj);
|
|
2089
|
+
canonicalizedObj = {};
|
|
2090
|
+
replacementStack.push(canonicalizedObj);
|
|
2091
|
+
const sortedKeys = [];
|
|
2092
|
+
let key;
|
|
2093
|
+
for (key in obj)
|
|
2094
|
+
/* istanbul ignore else */
|
|
2095
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) sortedKeys.push(key);
|
|
2096
|
+
sortedKeys.sort();
|
|
2097
|
+
for (i = 0; i < sortedKeys.length; i += 1) {
|
|
2098
|
+
key = sortedKeys[i];
|
|
2099
|
+
canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack, replacer, key);
|
|
2100
|
+
}
|
|
2101
|
+
stack.pop();
|
|
2102
|
+
replacementStack.pop();
|
|
2103
|
+
} else canonicalizedObj = obj;
|
|
2104
|
+
return canonicalizedObj;
|
|
2105
|
+
}
|
|
2106
|
+
//#endregion
|
|
2107
|
+
//#region ../../node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/diff/array.js
|
|
2108
|
+
var ArrayDiff = class extends Diff {
|
|
2109
|
+
tokenize(value) {
|
|
2110
|
+
return value.slice();
|
|
2111
|
+
}
|
|
2112
|
+
join(value) {
|
|
2113
|
+
return value;
|
|
2114
|
+
}
|
|
2115
|
+
removeEmpty(value) {
|
|
2116
|
+
return value;
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
new ArrayDiff();
|
|
2120
|
+
//#endregion
|
|
2121
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-session@0.2.1-rc.2_@deepseek-ai+cordis@4.0.5_@deepseek-ai+dsh-scope@0._f72072f8db4331da4f9afb922400d5de/node_modules/@deepseek-ai/dsh-session/lib/types/surface.js
|
|
2939
2122
|
/** Runtime counterpart of the message-producing event union. */
|
|
2940
2123
|
const SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
2941
2124
|
"system/message",
|
|
@@ -2976,11 +2159,86 @@ window.__ModuleLoader__.load({
|
|
|
2976
2159
|
function stringValue(value) {
|
|
2977
2160
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
2978
2161
|
}
|
|
2979
|
-
|
|
2980
|
-
|
|
2162
|
+
/** Preserve file contents verbatim; only reject empty/non-string values. */
|
|
2163
|
+
function textValue(value) {
|
|
2164
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
2165
|
+
}
|
|
2166
|
+
function lineCount(value) {
|
|
2167
|
+
const text = textValue(value);
|
|
2981
2168
|
if (text === void 0) return 0;
|
|
2982
|
-
const body = text.endsWith("\n") ? text.slice(0, -1) : text
|
|
2983
|
-
return body === "" ? 0 : body.split(/\r?\n
|
|
2169
|
+
const body = text.endsWith("\n") ? text.slice(0, -1) : text;
|
|
2170
|
+
return body === "" ? 0 : body.split(/\r?\n/).length;
|
|
2171
|
+
}
|
|
2172
|
+
/**
|
|
2173
|
+
* Real added/removed line counts for one edited file. Metadata `diffs` carry
|
|
2174
|
+
* the replaced snippet, so counting the whole `oldText`/`newText` as changed
|
|
2175
|
+
* over-reports a one-line edit in a large block. Fall back to raw line counts
|
|
2176
|
+
* only when the diff engine cannot process the values.
|
|
2177
|
+
*/
|
|
2178
|
+
function fileStat(oldValue, newValue) {
|
|
2179
|
+
const oldText = textValue(oldValue);
|
|
2180
|
+
const newText = textValue(newValue);
|
|
2181
|
+
if (oldText === void 0 && newText === void 0) return {
|
|
2182
|
+
added: 0,
|
|
2183
|
+
removed: 0
|
|
2184
|
+
};
|
|
2185
|
+
if (oldText === void 0) return {
|
|
2186
|
+
added: lineCount(newText),
|
|
2187
|
+
removed: 0
|
|
2188
|
+
};
|
|
2189
|
+
if (newText === void 0) return {
|
|
2190
|
+
added: 0,
|
|
2191
|
+
removed: lineCount(oldText)
|
|
2192
|
+
};
|
|
2193
|
+
try {
|
|
2194
|
+
let added = 0;
|
|
2195
|
+
let removed = 0;
|
|
2196
|
+
for (const change of diffLines(oldText, newText)) {
|
|
2197
|
+
const count = change.count ?? 0;
|
|
2198
|
+
if (change.added) added += count;
|
|
2199
|
+
else if (change.removed) removed += count;
|
|
2200
|
+
}
|
|
2201
|
+
return {
|
|
2202
|
+
added,
|
|
2203
|
+
removed
|
|
2204
|
+
};
|
|
2205
|
+
} catch {
|
|
2206
|
+
return {
|
|
2207
|
+
added: lineCount(newText),
|
|
2208
|
+
removed: lineCount(oldText)
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
/** Normalize separators, a leading `./`, and macOS's `/private` aliases. */
|
|
2213
|
+
function normalizePath(path) {
|
|
2214
|
+
let normalized = path.replaceAll("\\", "/");
|
|
2215
|
+
if (normalized.startsWith("./")) normalized = normalized.slice(2);
|
|
2216
|
+
for (const root of [
|
|
2217
|
+
"/private/tmp",
|
|
2218
|
+
"/private/var",
|
|
2219
|
+
"/private/etc"
|
|
2220
|
+
]) {
|
|
2221
|
+
if (normalized === root) return root.slice(8);
|
|
2222
|
+
if (normalized.startsWith(`${root}/`)) return normalized.slice(8);
|
|
2223
|
+
}
|
|
2224
|
+
return normalized;
|
|
2225
|
+
}
|
|
2226
|
+
function isAbsolutePath$1(path) {
|
|
2227
|
+
return path.startsWith("/") || /^[A-Za-z]:\//.test(path);
|
|
2228
|
+
}
|
|
2229
|
+
/** Whether two spellings name the same file (relative vs absolute target). */
|
|
2230
|
+
function samePath(left, right) {
|
|
2231
|
+
const a = normalizePath(left);
|
|
2232
|
+
const b = normalizePath(right);
|
|
2233
|
+
if (a === b) return true;
|
|
2234
|
+
return a.endsWith(`/${b}`) || b.endsWith(`/${a}`);
|
|
2235
|
+
}
|
|
2236
|
+
/** Prefer the workspace-relative spelling for display and native file open. */
|
|
2237
|
+
function preferredPath(left, right) {
|
|
2238
|
+
const a = normalizePath(left);
|
|
2239
|
+
const b = normalizePath(right);
|
|
2240
|
+
if (isAbsolutePath$1(a) !== isAbsolutePath$1(b)) return isAbsolutePath$1(a) ? b : a;
|
|
2241
|
+
return a.length <= b.length ? a : b;
|
|
2984
2242
|
}
|
|
2985
2243
|
function jsonArgs(argsRaw) {
|
|
2986
2244
|
if (argsRaw === void 0) return {};
|
|
@@ -3006,8 +2264,7 @@ window.__ModuleLoader__.load({
|
|
|
3006
2264
|
if (path === void 0) return [];
|
|
3007
2265
|
return [{
|
|
3008
2266
|
path,
|
|
3009
|
-
|
|
3010
|
-
removed: diffLines(item?.oldText),
|
|
2267
|
+
...fileStat(item?.oldText, item?.newText),
|
|
3011
2268
|
kind: "file"
|
|
3012
2269
|
}];
|
|
3013
2270
|
});
|
|
@@ -3036,14 +2293,22 @@ window.__ModuleLoader__.load({
|
|
|
3036
2293
|
"artifact"
|
|
3037
2294
|
].includes(token));
|
|
3038
2295
|
}
|
|
2296
|
+
/** Read tool-result text only; metadata/args URLs are not deliverables. */
|
|
2297
|
+
function resultText(value) {
|
|
2298
|
+
if (typeof value === "string") return value;
|
|
2299
|
+
const message = record$1(value);
|
|
2300
|
+
const content = Array.isArray(message?.content) ? message.content : [];
|
|
2301
|
+
const parts = [];
|
|
2302
|
+
for (const item of content) {
|
|
2303
|
+
const text = textValue(record$1(item)?.text);
|
|
2304
|
+
if (text !== void 0) parts.push(text);
|
|
2305
|
+
}
|
|
2306
|
+
return parts.join("\n");
|
|
2307
|
+
}
|
|
3039
2308
|
function resultWebsiteEntries(name, value) {
|
|
3040
2309
|
if (!websiteTool(name)) return [];
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
text = JSON.stringify(value) ?? "";
|
|
3044
|
-
} catch {
|
|
3045
|
-
return [];
|
|
3046
|
-
}
|
|
2310
|
+
const text = resultText(value);
|
|
2311
|
+
if (text === "") return [];
|
|
3047
2312
|
const urls = text.match(/https?:\/\/[^\s"'<>\\]+/gi) ?? [];
|
|
3048
2313
|
return [...new Set(urls.map((url) => url.replace(/[),.;]+$/g, "")))].map((path) => ({
|
|
3049
2314
|
path,
|
|
@@ -3068,7 +2333,7 @@ window.__ModuleLoader__.load({
|
|
|
3068
2333
|
function appendEntries(current, next, seq) {
|
|
3069
2334
|
const entries = [...current];
|
|
3070
2335
|
for (const candidate of next) {
|
|
3071
|
-
const existing = entries.findIndex((entry) => entry.
|
|
2336
|
+
const existing = entries.findIndex((entry) => entry.kind === candidate.kind && (candidate.kind === "website" ? entry.path === candidate.path : samePath(entry.path, candidate.path)));
|
|
3072
2337
|
if (existing === -1) {
|
|
3073
2338
|
entries.push({
|
|
3074
2339
|
...candidate,
|
|
@@ -3080,7 +2345,8 @@ window.__ModuleLoader__.load({
|
|
|
3080
2345
|
if (previous === void 0) continue;
|
|
3081
2346
|
entries[existing] = {
|
|
3082
2347
|
...previous,
|
|
3083
|
-
|
|
2348
|
+
...candidate.kind === "file" ? { path: preferredPath(previous.path, candidate.path) } : {},
|
|
2349
|
+
seq: Math.max(previous.seq, seq),
|
|
3084
2350
|
added: previous.added + candidate.added,
|
|
3085
2351
|
removed: previous.removed + candidate.removed
|
|
3086
2352
|
};
|
|
@@ -3093,8 +2359,7 @@ window.__ModuleLoader__.load({
|
|
|
3093
2359
|
const args = jsonArgs(call.argsRaw);
|
|
3094
2360
|
return [{
|
|
3095
2361
|
path,
|
|
3096
|
-
|
|
3097
|
-
removed: diffLines(args.old_string ?? args.old_text),
|
|
2362
|
+
...fileStat(args.old_string ?? args.old_text ?? args.old_str, args.new_string ?? args.new_text ?? args.new_str ?? args.content ?? args.file_text),
|
|
3098
2363
|
kind: "file"
|
|
3099
2364
|
}];
|
|
3100
2365
|
}
|
|
@@ -3173,15 +2438,18 @@ window.__ModuleLoader__.load({
|
|
|
3173
2438
|
value: { entries: context.state.entries }
|
|
3174
2439
|
}
|
|
3175
2440
|
};
|
|
2441
|
+
function nativeDeliverables(owner) {
|
|
2442
|
+
return record$1(owner.turn.data.get("deliverables"));
|
|
2443
|
+
}
|
|
3176
2444
|
function nativeProducedEntries(owner) {
|
|
3177
|
-
const produced =
|
|
2445
|
+
const produced = nativeDeliverables(owner)?.produced;
|
|
3178
2446
|
if (!Array.isArray(produced)) return [];
|
|
3179
2447
|
const entries = [];
|
|
3180
2448
|
for (const item of produced) {
|
|
3181
2449
|
const value = record$1(item);
|
|
3182
2450
|
const path = stringValue(value?.path);
|
|
3183
2451
|
const seq = typeof value?.seq === "number" ? value.seq : Number.POSITIVE_INFINITY;
|
|
3184
|
-
if (path === void 0 || seq > owner.seq || entries.some((entry) => entry.path
|
|
2452
|
+
if (path === void 0 || seq > owner.seq || entries.some((entry) => samePath(entry.path, path))) continue;
|
|
3185
2453
|
entries.push({
|
|
3186
2454
|
path,
|
|
3187
2455
|
seq,
|
|
@@ -3192,19 +2460,72 @@ window.__ModuleLoader__.load({
|
|
|
3192
2460
|
}
|
|
3193
2461
|
return entries;
|
|
3194
2462
|
}
|
|
3195
|
-
/**
|
|
2463
|
+
/**
|
|
2464
|
+
* Whether DSH's own turn-tail deliverables card will claim this Turn. It
|
|
2465
|
+
* renders changed files when developer tools are enabled, so the plugin must
|
|
2466
|
+
* not draw a second file card in that case.
|
|
2467
|
+
*/
|
|
2468
|
+
function nativeDeliverablesPresent(owner) {
|
|
2469
|
+
return nativeDeliverables(owner)?.changes !== void 0;
|
|
2470
|
+
}
|
|
2471
|
+
/**
|
|
2472
|
+
* Select entries that were delivered before the closing assistant message.
|
|
2473
|
+
* Native produced paths are merged instead of replacing the plugin's richer
|
|
2474
|
+
* entries, so a tool the plugin did not classify cannot hide the file.
|
|
2475
|
+
*/
|
|
3196
2476
|
function selectDeliverables(owner) {
|
|
3197
2477
|
const value = owner.turn.data.get(DELIVERABLES_DATA_KEY);
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
2478
|
+
let entries = [...value === void 0 ? [] : value.entries.filter((entry) => entry.seq <= owner.seq)];
|
|
2479
|
+
for (const entry of nativeProducedEntries(owner)) entries = appendEntries(entries, [{
|
|
2480
|
+
path: entry.path,
|
|
2481
|
+
added: entry.added,
|
|
2482
|
+
removed: entry.removed,
|
|
2483
|
+
kind: entry.kind
|
|
2484
|
+
}], entry.seq);
|
|
2485
|
+
return entries.length === 0 ? null : entries;
|
|
3204
2486
|
}
|
|
3205
2487
|
//#endregion
|
|
2488
|
+
//#region src/client/developer-tools.ts
|
|
2489
|
+
var DeveloperToolsPreferenceCell = class {
|
|
2490
|
+
listeners = /* @__PURE__ */ new Set();
|
|
2491
|
+
source;
|
|
2492
|
+
value = false;
|
|
2493
|
+
/** Point the cell at the settings service, or detach when it unloads. */
|
|
2494
|
+
attach(source) {
|
|
2495
|
+
this.source = source;
|
|
2496
|
+
this.refresh();
|
|
2497
|
+
const unsubscribe = source.subscribe(() => {
|
|
2498
|
+
this.refresh();
|
|
2499
|
+
});
|
|
2500
|
+
return () => {
|
|
2501
|
+
unsubscribe();
|
|
2502
|
+
if (this.source !== source) return;
|
|
2503
|
+
this.source = void 0;
|
|
2504
|
+
this.refresh();
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
read() {
|
|
2508
|
+
return this.source?.getSnapshot() ?? false;
|
|
2509
|
+
}
|
|
2510
|
+
refresh() {
|
|
2511
|
+
const next = this.read();
|
|
2512
|
+
if (next === this.value) return;
|
|
2513
|
+
this.value = next;
|
|
2514
|
+
for (const listener of this.listeners) listener();
|
|
2515
|
+
}
|
|
2516
|
+
getSnapshot = () => this.value;
|
|
2517
|
+
subscribe = (listener) => {
|
|
2518
|
+
this.listeners.add(listener);
|
|
2519
|
+
return () => {
|
|
2520
|
+
this.listeners.delete(listener);
|
|
2521
|
+
};
|
|
2522
|
+
};
|
|
2523
|
+
};
|
|
2524
|
+
/** Shared cell consumed by the deliverables tail. */
|
|
2525
|
+
const developerTools = new DeveloperToolsPreferenceCell();
|
|
2526
|
+
//#endregion
|
|
3206
2527
|
//#region \0dsh-css:/home/runner/work/dsh-codex-suite/dsh-codex-suite/packages/conversation-ui/src/client/DeliverablesCard.module.css.mjs
|
|
3207
|
-
const css = "
|
|
2528
|
+
const css = ".sLyncq_root{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-primary);color:var(--dsw-alias-label-secondary);box-sizing:border-box;border-radius:12px;flex-direction:column;gap:0;margin-top:16px;padding:12px 12px 10px;font-size:14px;line-height:22px;display:flex}.sLyncq_header{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:flex-start;gap:12px;min-width:0;padding:4px 8px 12px;display:flex}.sLyncq_headerIcon{background:var(--dsw-alias-interactive-bg-hover);width:40px;height:40px;color:var(--dsw-alias-label-secondary);border-radius:10px;flex:none;justify-content:center;align-items:center;display:inline-flex}.sLyncq_heading{flex-direction:column;gap:1px;min-width:0;display:flex}.sLyncq_title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:500;line-height:24px}.sLyncq_subtitle{color:var(--dsw-alias-label-tertiary);font:inherit;text-align:start;cursor:pointer;background:0 0;border:0;margin:0;padding:0;font-size:14px;line-height:20px}.sLyncq_subtitle:hover{color:var(--dsw-alias-label-secondary);text-decoration:underline}.sLyncq_list{flex-direction:column;min-width:0;padding:10px 8px 0;display:flex}.sLyncq_item{width:100%;min-width:0;min-height:28px;color:inherit;font:inherit;text-align:start;cursor:pointer;background:0 0;border:0;border-radius:5px;align-items:center;gap:0;margin:0;padding:2px 0;line-height:22px;display:flex}.sLyncq_item:hover{color:var(--dsw-alias-label-primary)}.sLyncq_item:focus-visible,.sLyncq_more:focus-visible,.sLyncq_subtitle:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.sLyncq_filePath,.sLyncq_websitePath{white-space:nowrap;flex:auto;min-width:0;display:flex;overflow:hidden}.sLyncq_parentPath{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sLyncq_fileName{color:var(--dsw-alias-label-secondary);flex:none}.sLyncq_websitePath{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;overflow:hidden}.sLyncq_stats{white-space:nowrap;flex:none;gap:6px;margin-inline-start:8px;font-size:13px;line-height:22px;display:inline-flex}.sLyncq_added{color:var(--dsw-alias-label-success,#2f9e44)}.sLyncq_removed{color:var(--dsw-alias-label-danger,#d94841)}.sLyncq_external{color:var(--dsw-alias-label-tertiary);flex:none}.sLyncq_more{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-self:flex-start;align-items:center;gap:5px;margin:8px 8px 0;padding:0;line-height:22px;display:inline-flex}.sLyncq_more:hover{color:var(--dsw-alias-label-primary)}.sLyncq_moreIcon{flex:none;justify-content:center;align-items:center;width:14px;height:14px;display:inline-flex}";
|
|
3208
2529
|
const tagId = "@jcy2387/dsh-conversation-ui/DeliverablesCard.module.css";
|
|
3209
2530
|
if (typeof document !== "undefined") {
|
|
3210
2531
|
let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]");
|
|
@@ -3217,24 +2538,24 @@ window.__ModuleLoader__.load({
|
|
|
3217
2538
|
tag.textContent = css;
|
|
3218
2539
|
}
|
|
3219
2540
|
var DeliverablesCard_module_css_default = {
|
|
3220
|
-
"list": "sLyncq_list",
|
|
3221
|
-
"heading": "sLyncq_heading",
|
|
3222
|
-
"root": "sLyncq_root",
|
|
3223
|
-
"headerIcon": "sLyncq_headerIcon",
|
|
3224
|
-
"fileName": "sLyncq_fileName",
|
|
3225
2541
|
"websitePath": "sLyncq_websitePath",
|
|
3226
|
-
"
|
|
3227
|
-
"
|
|
3228
|
-
"filePath": "sLyncq_filePath",
|
|
2542
|
+
"fileName": "sLyncq_fileName",
|
|
2543
|
+
"external": "sLyncq_external",
|
|
3229
2544
|
"subtitle": "sLyncq_subtitle",
|
|
3230
2545
|
"added": "sLyncq_added",
|
|
3231
|
-
"parentPath": "sLyncq_parentPath",
|
|
3232
2546
|
"moreIcon": "sLyncq_moreIcon",
|
|
3233
|
-
"
|
|
3234
|
-
"item": "sLyncq_item",
|
|
3235
|
-
"external": "sLyncq_external",
|
|
2547
|
+
"root": "sLyncq_root",
|
|
3236
2548
|
"header": "sLyncq_header",
|
|
3237
|
-
"
|
|
2549
|
+
"heading": "sLyncq_heading",
|
|
2550
|
+
"item": "sLyncq_item",
|
|
2551
|
+
"parentPath": "sLyncq_parentPath",
|
|
2552
|
+
"removed": "sLyncq_removed",
|
|
2553
|
+
"title": "sLyncq_title",
|
|
2554
|
+
"more": "sLyncq_more",
|
|
2555
|
+
"stats": "sLyncq_stats",
|
|
2556
|
+
"headerIcon": "sLyncq_headerIcon",
|
|
2557
|
+
"list": "sLyncq_list",
|
|
2558
|
+
"filePath": "sLyncq_filePath"
|
|
3238
2559
|
};
|
|
3239
2560
|
//#endregion
|
|
3240
2561
|
//#region src/client/DeliverablesCard.tsx
|
|
@@ -3255,60 +2576,67 @@ window.__ModuleLoader__.load({
|
|
|
3255
2576
|
name: path.slice(separator + 1)
|
|
3256
2577
|
};
|
|
3257
2578
|
}
|
|
3258
|
-
function
|
|
3259
|
-
|
|
3260
|
-
if (entries.every((entry) => !isWebsite(entry))) return "文件";
|
|
3261
|
-
return "产物";
|
|
2579
|
+
function isAbsolutePath(path) {
|
|
2580
|
+
return path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path);
|
|
3262
2581
|
}
|
|
3263
|
-
|
|
2582
|
+
/** First segments from relative entries, used to trim absolute siblings. */
|
|
2583
|
+
function relativePrefixes(entries) {
|
|
2584
|
+
const prefixes = /* @__PURE__ */ new Set();
|
|
2585
|
+
for (const entry of entries) {
|
|
2586
|
+
if (isWebsite(entry) || isAbsolutePath(entry.path)) continue;
|
|
2587
|
+
const first = entry.path.replaceAll("\\", "/").split("/")[0];
|
|
2588
|
+
if (first !== void 0 && first !== "" && first !== "." && first !== "..") prefixes.add(first);
|
|
2589
|
+
}
|
|
2590
|
+
return [...prefixes];
|
|
2591
|
+
}
|
|
2592
|
+
/**
|
|
2593
|
+
* Prefer the workspace-relative spelling for display. The slot owner does not
|
|
2594
|
+
* expose the session cwd, but a sibling relative entry identifies the first
|
|
2595
|
+
* path segment (`packages`, `src`, ...), which is enough to trim an absolute
|
|
2596
|
+
* tool-reported path without changing the path used for `openFile`.
|
|
2597
|
+
*/
|
|
2598
|
+
function displayPath(path, prefixes) {
|
|
2599
|
+
if (!isAbsolutePath(path)) return path;
|
|
2600
|
+
const normalized = path.replaceAll("\\", "/");
|
|
2601
|
+
for (const prefix of prefixes) {
|
|
2602
|
+
const marker = `/${prefix}/`;
|
|
2603
|
+
const index = normalized.indexOf(marker);
|
|
2604
|
+
if (index >= 0) return normalized.slice(index + 1);
|
|
2605
|
+
}
|
|
2606
|
+
return path;
|
|
2607
|
+
}
|
|
2608
|
+
function hiddenKindLabel(entries, t) {
|
|
2609
|
+
if (entries.every(isWebsite)) return t("deliveriesWebsites");
|
|
2610
|
+
if (entries.every((entry) => !isWebsite(entry))) return t("deliveriesFiles");
|
|
2611
|
+
return t("deliveriesItems");
|
|
2612
|
+
}
|
|
2613
|
+
function countLabel(entries, t) {
|
|
3264
2614
|
const files = entries.filter((entry) => !isWebsite(entry)).length;
|
|
3265
2615
|
const websites = entries.length - files;
|
|
3266
|
-
if (files > 0 && websites === 0) return
|
|
3267
|
-
if (files === 0) return
|
|
3268
|
-
return
|
|
3269
|
-
}
|
|
3270
|
-
function collectEditStats(turn) {
|
|
3271
|
-
const result = /* @__PURE__ */ new Map();
|
|
3272
|
-
if (typeof document === "undefined") return result;
|
|
3273
|
-
for (const element of document.querySelectorAll("[data-stream-edit-stats]")) {
|
|
3274
|
-
if (element.closest("[data-stream-turn]")?.getAttribute("data-stream-turn") !== String(turn)) continue;
|
|
3275
|
-
const path = element.getAttribute("data-stream-edit-file");
|
|
3276
|
-
const match = /\+(\d+)\s+-\s*(\d+)/.exec(element.textContent ?? "");
|
|
3277
|
-
if (path === null || match === null) continue;
|
|
3278
|
-
result.set(path, {
|
|
3279
|
-
added: Number(match[1]),
|
|
3280
|
-
removed: Number(match[2])
|
|
3281
|
-
});
|
|
3282
|
-
}
|
|
3283
|
-
return result;
|
|
2616
|
+
if (files > 0 && websites === 0) return t("deliveriesEdited").replace("{count}", String(files));
|
|
2617
|
+
if (files === 0) return t("deliveriesWebsitesCount").replace("{count}", String(websites));
|
|
2618
|
+
return t("deliveriesCount").replace("{count}", String(entries.length));
|
|
3284
2619
|
}
|
|
3285
2620
|
/** Render this list contribution only when its Turn has delivered files or websites. */
|
|
3286
2621
|
function DeliverablesTail(props) {
|
|
3287
2622
|
const matched = selectDeliverables(props);
|
|
3288
|
-
|
|
2623
|
+
const showNativeFiles = (0, react.useSyncExternalStore)(developerTools.subscribe, developerTools.getSnapshot, developerTools.getSnapshot) && nativeDeliverablesPresent(props);
|
|
2624
|
+
if (matched === null) return null;
|
|
2625
|
+
const entries = showNativeFiles ? matched.filter(isWebsite) : matched;
|
|
2626
|
+
return entries.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeliverablesCard, {
|
|
3289
2627
|
...props,
|
|
3290
|
-
matched
|
|
2628
|
+
matched: entries
|
|
3291
2629
|
});
|
|
3292
2630
|
}
|
|
3293
2631
|
/** Codex-style turn-tail card for edited files and deployed websites. */
|
|
3294
|
-
function DeliverablesCard({ matched
|
|
2632
|
+
function DeliverablesCard({ matched: entries, openFile, t }) {
|
|
3295
2633
|
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
3296
|
-
const [domStats, setDomStats] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
3297
|
-
(0, react.useLayoutEffect)(() => {
|
|
3298
|
-
setDomStats(collectEditStats(turn.turn));
|
|
3299
|
-
}, [turn.turn, matched]);
|
|
3300
|
-
const entries = matched.map((entry) => {
|
|
3301
|
-
const stats = domStats.get(entry.path);
|
|
3302
|
-
return stats === void 0 || entry.added > 0 || entry.removed > 0 ? entry : {
|
|
3303
|
-
...entry,
|
|
3304
|
-
...stats
|
|
3305
|
-
};
|
|
3306
|
-
});
|
|
3307
2634
|
const visible = expanded ? entries : entries.slice(0, 3);
|
|
3308
2635
|
const hidden = entries.length - visible.length;
|
|
3309
|
-
const summary = countLabel(entries);
|
|
2636
|
+
const summary = countLabel(entries, t);
|
|
3310
2637
|
const hasFiles = entries.some((entry) => !isWebsite(entry));
|
|
3311
2638
|
const firstWebsite = entries.find(isWebsite);
|
|
2639
|
+
const prefixes = relativePrefixes(entries);
|
|
3312
2640
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3313
2641
|
className: DeliverablesCard_module_css_default.root,
|
|
3314
2642
|
"data-stream-deliverables-card": true,
|
|
@@ -3325,20 +2653,13 @@ window.__ModuleLoader__.load({
|
|
|
3325
2653
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
3326
2654
|
className: DeliverablesCard_module_css_default.title,
|
|
3327
2655
|
children: summary
|
|
3328
|
-
}), hasFiles ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3329
|
-
type: "button",
|
|
3330
|
-
className: DeliverablesCard_module_css_default.subtitle,
|
|
3331
|
-
onClick: () => {
|
|
3332
|
-
setExpanded(true);
|
|
3333
|
-
},
|
|
3334
|
-
children: "查看更改 ↗"
|
|
3335
|
-
}) : firstWebsite !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2656
|
+
}), !hasFiles && firstWebsite !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3336
2657
|
type: "button",
|
|
3337
2658
|
className: DeliverablesCard_module_css_default.subtitle,
|
|
3338
2659
|
onClick: () => {
|
|
3339
2660
|
openWebsite(firstWebsite.path);
|
|
3340
2661
|
},
|
|
3341
|
-
children: "
|
|
2662
|
+
children: [t("deliveriesOpenWebsite"), " ↗"]
|
|
3342
2663
|
}) : null]
|
|
3343
2664
|
})]
|
|
3344
2665
|
}),
|
|
@@ -3346,7 +2667,8 @@ window.__ModuleLoader__.load({
|
|
|
3346
2667
|
className: DeliverablesCard_module_css_default.list,
|
|
3347
2668
|
children: visible.map((entry) => {
|
|
3348
2669
|
const website = isWebsite(entry);
|
|
3349
|
-
const
|
|
2670
|
+
const display = displayPath(entry.path, prefixes);
|
|
2671
|
+
const parts = pathParts(display);
|
|
3350
2672
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3351
2673
|
type: "button",
|
|
3352
2674
|
className: DeliverablesCard_module_css_default.item,
|
|
@@ -3365,7 +2687,7 @@ window.__ModuleLoader__.load({
|
|
|
3365
2687
|
children: parts.parent
|
|
3366
2688
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3367
2689
|
className: DeliverablesCard_module_css_default.fileName,
|
|
3368
|
-
children: parts.name ||
|
|
2690
|
+
children: parts.name || display
|
|
3369
2691
|
})]
|
|
3370
2692
|
}),
|
|
3371
2693
|
!website && (entry.added > 0 || entry.removed > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -3393,17 +2715,11 @@ window.__ModuleLoader__.load({
|
|
|
3393
2715
|
onClick: () => {
|
|
3394
2716
|
setExpanded(true);
|
|
3395
2717
|
},
|
|
3396
|
-
children: [
|
|
3397
|
-
|
|
3398
|
-
hidden,
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3402
|
-
className: DeliverablesCard_module_css_default.moreIcon,
|
|
3403
|
-
"aria-hidden": true,
|
|
3404
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, {})
|
|
3405
|
-
})
|
|
3406
|
-
]
|
|
2718
|
+
children: [t("deliveriesMore").replace("{count}", String(hidden)).replace("{kind}", hiddenKindLabel(entries.slice(visible.length), t)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2719
|
+
className: DeliverablesCard_module_css_default.moreIcon,
|
|
2720
|
+
"aria-hidden": true,
|
|
2721
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, {})
|
|
2722
|
+
})]
|
|
3407
2723
|
}),
|
|
3408
2724
|
expanded && entries.length > 3 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3409
2725
|
type: "button",
|
|
@@ -3411,18 +2727,21 @@ window.__ModuleLoader__.load({
|
|
|
3411
2727
|
onClick: () => {
|
|
3412
2728
|
setExpanded(false);
|
|
3413
2729
|
},
|
|
3414
|
-
children: [
|
|
3415
|
-
|
|
3416
|
-
"
|
|
3417
|
-
|
|
3418
|
-
|
|
2730
|
+
children: [
|
|
2731
|
+
t("deliveriesCollapse"),
|
|
2732
|
+
" ",
|
|
2733
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2734
|
+
className: DeliverablesCard_module_css_default.moreIcon,
|
|
2735
|
+
"aria-hidden": true,
|
|
2736
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutlineMedium, {})
|
|
2737
|
+
})
|
|
2738
|
+
]
|
|
3419
2739
|
})
|
|
3420
2740
|
]
|
|
3421
2741
|
});
|
|
3422
2742
|
}
|
|
3423
2743
|
//#endregion
|
|
3424
2744
|
//#region src/settings-api.ts
|
|
3425
|
-
/** Shared wire vocabulary for the plugin-owned settings RPC channel. */
|
|
3426
2745
|
/** Dedicated, loopback-only RPC channel registered by the Host half. */
|
|
3427
2746
|
const CONVERSATION_SETTINGS_RPC_CHANNEL = "/conversation-ui";
|
|
3428
2747
|
/** Endpoints accepted by {@link CONVERSATION_SETTINGS_RPC_CHANNEL}. */
|
|
@@ -3442,7 +2761,11 @@ window.__ModuleLoader__.load({
|
|
|
3442
2761
|
"npm",
|
|
3443
2762
|
"development",
|
|
3444
2763
|
"unmanaged"
|
|
3445
|
-
].includes(data.installation) || typeof data.writable !== "boolean" || typeof data.thinkAutoExpand !== "boolean" ||
|
|
2764
|
+
].includes(data.installation) || typeof data.writable !== "boolean" || typeof data.thinkAutoExpand !== "boolean" || !["typewriter", "teleprompter"].includes(data.mode) || ![
|
|
2765
|
+
"realtime",
|
|
2766
|
+
"balanced",
|
|
2767
|
+
"silky"
|
|
2768
|
+
].includes(data.preset) || typeof data.revealCharsPerSec !== "number" || typeof data.canUpgrade !== "boolean") throw new Error("dsh-conversation-ui: malformed settings response");
|
|
3446
2769
|
return data;
|
|
3447
2770
|
}
|
|
3448
2771
|
function upgradeView(value) {
|
|
@@ -3459,8 +2782,8 @@ window.__ModuleLoader__.load({
|
|
|
3459
2782
|
async read() {
|
|
3460
2783
|
return settingsView(accepted(await connection.rpc.call(CONVERSATION_SETTINGS_RPC_CHANNEL, CONVERSATION_SETTINGS_RPC.read, {})));
|
|
3461
2784
|
},
|
|
3462
|
-
async write(
|
|
3463
|
-
return settingsView(accepted(await connection.rpc.call(CONVERSATION_SETTINGS_RPC_CHANNEL, CONVERSATION_SETTINGS_RPC.write,
|
|
2785
|
+
async write(patch) {
|
|
2786
|
+
return settingsView(accepted(await connection.rpc.call(CONVERSATION_SETTINGS_RPC_CHANNEL, CONVERSATION_SETTINGS_RPC.write, patch)));
|
|
3464
2787
|
},
|
|
3465
2788
|
async upgrade() {
|
|
3466
2789
|
return upgradeView(accepted(await connection.rpc.call(CONVERSATION_SETTINGS_RPC_CHANNEL, CONVERSATION_SETTINGS_RPC.upgrade, {})));
|
|
@@ -3475,9 +2798,21 @@ window.__ModuleLoader__.load({
|
|
|
3475
2798
|
/** English copy. */
|
|
3476
2799
|
const en = {
|
|
3477
2800
|
title: "Conversation UI",
|
|
3478
|
-
description: "
|
|
2801
|
+
description: "Assistant reveal and deliveries using the native DSH conversation UI.",
|
|
3479
2802
|
thinkAutoExpand: "Auto-expand thinking",
|
|
3480
2803
|
thinkAutoExpandHint: "Open the thinking block while it streams. Turn off to keep it collapsed.",
|
|
2804
|
+
mode: "Reveal mode",
|
|
2805
|
+
modeHint: "Typewriter reveals each grapheme; Teleprompter shows the newest snapshot immediately.",
|
|
2806
|
+
modeTypewriter: "Typewriter",
|
|
2807
|
+
modeTeleprompter: "Teleprompter",
|
|
2808
|
+
preset: "Smoothing preset",
|
|
2809
|
+
presetHint: "Controls how the reveal cadence follows the model stream.",
|
|
2810
|
+
presetRealtime: "Realtime",
|
|
2811
|
+
presetBalanced: "Balanced",
|
|
2812
|
+
presetSilky: "Silky",
|
|
2813
|
+
revealSpeed: "Reveal speed",
|
|
2814
|
+
revealSpeedHint: "Graphemes per second while typewriter mode is streaming; the settle drain is faster.",
|
|
2815
|
+
charsPerSecond: "chars/s",
|
|
3481
2816
|
readOnly: "This deployment stores settings read-only.",
|
|
3482
2817
|
loading: "Loading plugin settings…",
|
|
3483
2818
|
unavailable: "Plugin settings are unavailable in this connection.",
|
|
@@ -3492,6 +2827,15 @@ window.__ModuleLoader__.load({
|
|
|
3492
2827
|
updating: "Updating…",
|
|
3493
2828
|
restartRequired: "Updated. Restart Harness to load the new version.",
|
|
3494
2829
|
updateFailed: "The package update failed; your current version is unchanged.",
|
|
2830
|
+
deliveriesFiles: "files",
|
|
2831
|
+
deliveriesWebsites: "websites",
|
|
2832
|
+
deliveriesItems: "items",
|
|
2833
|
+
deliveriesEdited: "Edited {count} files",
|
|
2834
|
+
deliveriesWebsitesCount: "Delivered {count} websites",
|
|
2835
|
+
deliveriesCount: "Delivered {count} items",
|
|
2836
|
+
deliveriesOpenWebsite: "Open website",
|
|
2837
|
+
deliveriesMore: "Show {count} more {kind}",
|
|
2838
|
+
deliveriesCollapse: "Collapse",
|
|
3495
2839
|
save: "Save",
|
|
3496
2840
|
saving: "Saving…",
|
|
3497
2841
|
discard: "Discard",
|
|
@@ -3501,9 +2845,21 @@ window.__ModuleLoader__.load({
|
|
|
3501
2845
|
/** Simplified Chinese copy. */
|
|
3502
2846
|
const zh = {
|
|
3503
2847
|
title: "对话界面增强",
|
|
3504
|
-
description: "
|
|
2848
|
+
description: "在 DSH 原生对话界面中增强助手揭示和产物展示。",
|
|
3505
2849
|
thinkAutoExpand: "自动展开思考",
|
|
3506
2850
|
thinkAutoExpandHint: "思考块在流式时自动展开;关闭后保持折叠,可手动展开。",
|
|
2851
|
+
mode: "揭示模式",
|
|
2852
|
+
modeHint: "typewriter 按字素逐字揭示;teleprompter 直接显示最新快照。",
|
|
2853
|
+
modeTypewriter: "打字机",
|
|
2854
|
+
modeTeleprompter: "即时",
|
|
2855
|
+
preset: "平滑预设",
|
|
2856
|
+
presetHint: "控制揭示节奏如何跟随模型流。",
|
|
2857
|
+
presetRealtime: "实时",
|
|
2858
|
+
presetBalanced: "均衡",
|
|
2859
|
+
presetSilky: "丝滑",
|
|
2860
|
+
revealSpeed: "揭示速度",
|
|
2861
|
+
revealSpeedHint: "typewriter 流式时的字素数/秒;收尾排空会更快。",
|
|
2862
|
+
charsPerSecond: "字/秒",
|
|
3507
2863
|
readOnly: "本部署的设置为只读。",
|
|
3508
2864
|
loading: "正在加载插件设置…",
|
|
3509
2865
|
unavailable: "当前连接无法访问插件设置。",
|
|
@@ -3518,6 +2874,15 @@ window.__ModuleLoader__.load({
|
|
|
3518
2874
|
updating: "更新中…",
|
|
3519
2875
|
restartRequired: "已更新;重启 Harness 后加载新版本。",
|
|
3520
2876
|
updateFailed: "包更新失败,当前版本未改变。",
|
|
2877
|
+
deliveriesFiles: "文件",
|
|
2878
|
+
deliveriesWebsites: "网站",
|
|
2879
|
+
deliveriesItems: "产物",
|
|
2880
|
+
deliveriesEdited: "已编辑 {count} 个文件",
|
|
2881
|
+
deliveriesWebsitesCount: "交付 {count} 个网站",
|
|
2882
|
+
deliveriesCount: "已交付 {count} 项产物",
|
|
2883
|
+
deliveriesOpenWebsite: "打开网站",
|
|
2884
|
+
deliveriesMore: "再显示 {count} 个{kind}",
|
|
2885
|
+
deliveriesCollapse: "收起",
|
|
3521
2886
|
save: "保存",
|
|
3522
2887
|
saving: "保存中…",
|
|
3523
2888
|
discard: "放弃修改",
|
|
@@ -3539,15 +2904,6 @@ window.__ModuleLoader__.load({
|
|
|
3539
2904
|
"balanced",
|
|
3540
2905
|
"silky"
|
|
3541
2906
|
];
|
|
3542
|
-
/** Input rows stay native; Assistant and Turn control are replaced. */
|
|
3543
|
-
const SKIP_WRAP = /* @__PURE__ */ new Set([
|
|
3544
|
-
"assistant-step",
|
|
3545
|
-
"turn-process",
|
|
3546
|
-
"user",
|
|
3547
|
-
"steering",
|
|
3548
|
-
"turn-trigger",
|
|
3549
|
-
"command-input"
|
|
3550
|
-
]);
|
|
3551
2907
|
/**
|
|
3552
2908
|
* Read the Host-bridged boot config. The inline script is produced by this
|
|
3553
2909
|
* plugin's Host half from a schema-validated value, so only the structural
|
|
@@ -3567,82 +2923,20 @@ window.__ModuleLoader__.load({
|
|
|
3567
2923
|
return raw;
|
|
3568
2924
|
}
|
|
3569
2925
|
/**
|
|
3570
|
-
* Wrap every keyed Chat row except `assistant-step` in place. A second
|
|
3571
|
-
* register with the same `children` table throws because the child slot is
|
|
3572
|
-
* already declared, and only the winning entry receives `renderSlot`;
|
|
3573
|
-
* swapping `entry.component` keeps the original children, locale, and inject
|
|
3574
|
-
* seats. `assistant-step` is replaced below so text and Think use the
|
|
3575
|
-
* Codex-style Assistant presentation.
|
|
3576
|
-
* @param ctx - Browser context carrying the slot registry.
|
|
3577
|
-
* @returns Restorer that puts the original components back.
|
|
3578
|
-
*/
|
|
3579
|
-
function wrapGrowingChatRows(ctx, config) {
|
|
3580
|
-
const restores = [];
|
|
3581
|
-
const wrapped = /* @__PURE__ */ new WeakSet();
|
|
3582
|
-
const wrapAll = () => {
|
|
3583
|
-
for (const entry of ctx.slots.entries("conversation.chat.node")) {
|
|
3584
|
-
const key = entry.options.key;
|
|
3585
|
-
if (key === void 0 || SKIP_WRAP.has(key)) continue;
|
|
3586
|
-
const current = entry.component;
|
|
3587
|
-
if (typeof current !== "function" && (typeof current !== "object" || current === null) || wrapped.has(current)) continue;
|
|
3588
|
-
const inner = current;
|
|
3589
|
-
const next = wrapFollowNodeView(inner, {
|
|
3590
|
-
minSpeedPxPerSec: config.scrollSpeedPxPerSec,
|
|
3591
|
-
maxSpeedPxPerSec: config.maxScrollSpeedPxPerSec
|
|
3592
|
-
});
|
|
3593
|
-
wrapped.add(next);
|
|
3594
|
-
entry.component = next;
|
|
3595
|
-
restores.push(() => {
|
|
3596
|
-
if (entry.component === next) entry.component = inner;
|
|
3597
|
-
});
|
|
3598
|
-
}
|
|
3599
|
-
};
|
|
3600
|
-
wrapAll();
|
|
3601
|
-
const off = ctx.on("slots/changed", (key) => {
|
|
3602
|
-
if (key === "conversation.chat.node") wrapAll();
|
|
3603
|
-
});
|
|
3604
|
-
return () => {
|
|
3605
|
-
off();
|
|
3606
|
-
for (const restore of restores) restore();
|
|
3607
|
-
};
|
|
3608
|
-
}
|
|
3609
|
-
/** Bridge DSH's transcript preference through the native Chat view tree. */
|
|
3610
|
-
function wrapNativeChatView(ctx) {
|
|
3611
|
-
const restores = [];
|
|
3612
|
-
const wrapped = /* @__PURE__ */ new WeakSet();
|
|
3613
|
-
const wrapAll = () => {
|
|
3614
|
-
for (const entry of ctx.slots.entries("conversation.view")) {
|
|
3615
|
-
if (entry.options.id !== "chat") continue;
|
|
3616
|
-
const current = entry.component;
|
|
3617
|
-
if (typeof current !== "function" && (typeof current !== "object" || current === null) || wrapped.has(current)) continue;
|
|
3618
|
-
const inner = current;
|
|
3619
|
-
const next = wrapTranscriptView(inner);
|
|
3620
|
-
wrapped.add(next);
|
|
3621
|
-
entry.component = next;
|
|
3622
|
-
restores.push(() => {
|
|
3623
|
-
if (entry.component === next) entry.component = inner;
|
|
3624
|
-
});
|
|
3625
|
-
}
|
|
3626
|
-
};
|
|
3627
|
-
wrapAll();
|
|
3628
|
-
const off = ctx.on("slots/changed", (key) => {
|
|
3629
|
-
if (key === "conversation.view") wrapAll();
|
|
3630
|
-
});
|
|
3631
|
-
return () => {
|
|
3632
|
-
off();
|
|
3633
|
-
for (const restore of restores) restore();
|
|
3634
|
-
};
|
|
3635
|
-
}
|
|
3636
|
-
/**
|
|
3637
2926
|
* A live preference cell read by `useSyncExternalStore`. It starts on the
|
|
3638
|
-
*
|
|
3639
|
-
*
|
|
3640
|
-
* ships no settings surface keeps the
|
|
2927
|
+
* boot-bridged composition defaults and, once the plugin-owned settings
|
|
2928
|
+
* controller has loaded, tracks the durable reveal and thinking preferences.
|
|
2929
|
+
* A composition (or test) that ships no settings surface keeps the fallback.
|
|
3641
2930
|
*/
|
|
3642
2931
|
var PreferenceCell = class {
|
|
2932
|
+
fallback;
|
|
3643
2933
|
listeners = /* @__PURE__ */ new Set();
|
|
3644
2934
|
card;
|
|
3645
|
-
value
|
|
2935
|
+
value;
|
|
2936
|
+
constructor(fallback) {
|
|
2937
|
+
this.fallback = fallback;
|
|
2938
|
+
this.value = fallback;
|
|
2939
|
+
}
|
|
3646
2940
|
/** Re-point the cell at the plugin-owned settings controller. */
|
|
3647
2941
|
attach(card) {
|
|
3648
2942
|
this.card = card;
|
|
@@ -3658,11 +2952,18 @@ window.__ModuleLoader__.load({
|
|
|
3658
2952
|
};
|
|
3659
2953
|
}
|
|
3660
2954
|
read() {
|
|
3661
|
-
|
|
2955
|
+
const snapshot = this.card?.getSnapshot();
|
|
2956
|
+
if (snapshot === void 0 || snapshot.status !== "ready") return this.fallback;
|
|
2957
|
+
return {
|
|
2958
|
+
thinkAutoExpand: snapshot.thinkAutoExpand,
|
|
2959
|
+
mode: snapshot.mode,
|
|
2960
|
+
preset: snapshot.preset,
|
|
2961
|
+
revealCharsPerSec: snapshot.revealCharsPerSec
|
|
2962
|
+
};
|
|
3662
2963
|
}
|
|
3663
2964
|
refresh() {
|
|
3664
2965
|
const next = this.read();
|
|
3665
|
-
if (next
|
|
2966
|
+
if (sameSettings(next, this.value)) return;
|
|
3666
2967
|
this.value = next;
|
|
3667
2968
|
for (const listener of this.listeners) listener();
|
|
3668
2969
|
}
|
|
@@ -3674,29 +2975,41 @@ window.__ModuleLoader__.load({
|
|
|
3674
2975
|
};
|
|
3675
2976
|
};
|
|
3676
2977
|
};
|
|
2978
|
+
function sameSettings(left, right) {
|
|
2979
|
+
return left.thinkAutoExpand === right.thinkAutoExpand && left.mode === right.mode && left.preset === right.preset && left.revealCharsPerSec === right.revealCharsPerSec;
|
|
2980
|
+
}
|
|
3677
2981
|
/**
|
|
3678
|
-
*
|
|
3679
|
-
*
|
|
3680
|
-
*
|
|
3681
|
-
* workflow runs keep their Codex presentation without taking ownership of the
|
|
3682
|
-
* DSH scrollport. The Host-bridged configuration selects immediate or
|
|
3683
|
-
* typewriter reveal and smoothing; the plugin-owned settings RPC supplies the
|
|
3684
|
-
* settings surface is composed.
|
|
3685
|
-
* @param ctx - Browser context carrying the shared slot registry.
|
|
2982
|
+
* Add assistant reveal/preferences and independent delivery/settings cards.
|
|
2983
|
+
* Native ChatView, tools, Turn controls, grouping, and scroll remain untouched.
|
|
2984
|
+
* @param ctx - browser context carrying the shared slot registry.
|
|
3686
2985
|
*/
|
|
3687
2986
|
function apply(ctx) {
|
|
3688
|
-
const
|
|
3689
|
-
const preference = new PreferenceCell(
|
|
3690
|
-
|
|
2987
|
+
const bootConfig = readBootConfig();
|
|
2988
|
+
const preference = new PreferenceCell({
|
|
2989
|
+
...DEFAULT_CONVERSATION_SETTINGS,
|
|
2990
|
+
mode: bootConfig.mode,
|
|
2991
|
+
preset: bootConfig.preset,
|
|
2992
|
+
revealCharsPerSec: bootConfig.revealCharsPerSec
|
|
2993
|
+
});
|
|
2994
|
+
ctx.inject(["configForms"], (configCtx) => {
|
|
2995
|
+
const source = configCtx.configForms.developerTools?.enabled;
|
|
2996
|
+
if (source === void 0) return;
|
|
2997
|
+
return developerTools.attach(source);
|
|
2998
|
+
});
|
|
3691
2999
|
ctx.slots.inject("conversation.chat.turnTail", () => ctx.slots.register({
|
|
3692
3000
|
name: "conversation.chat.turnTail",
|
|
3693
3001
|
id: "@jcy2387/dsh-conversation-ui",
|
|
3694
3002
|
priority: -100,
|
|
3695
|
-
registrant: "dsh-conversation-ui"
|
|
3003
|
+
registrant: "dsh-conversation-ui",
|
|
3004
|
+
locale: NS
|
|
3696
3005
|
}, DeliverablesTail));
|
|
3697
3006
|
ctx.inject(["uiConversation"], (deliverablesCtx) => {
|
|
3698
3007
|
return deliverablesCtx.uiConversation.events.register(deliverablesDefinition);
|
|
3699
3008
|
});
|
|
3009
|
+
ctx.inject(["locale"], (localeCtx) => localeCtx.effect(() => localeCtx.locale.register(NS, {
|
|
3010
|
+
zh,
|
|
3011
|
+
en
|
|
3012
|
+
}), "dsh-conversation-ui: dictionaries"));
|
|
3700
3013
|
ctx.inject([
|
|
3701
3014
|
"slots",
|
|
3702
3015
|
"locale",
|
|
@@ -3705,10 +3018,6 @@ window.__ModuleLoader__.load({
|
|
|
3705
3018
|
const card = new ConversationCardController(createConversationSettingsApi(settingsCtx.get("connection")));
|
|
3706
3019
|
const detachPreference = preference.attach(card);
|
|
3707
3020
|
card.start();
|
|
3708
|
-
settingsCtx.effect(() => settingsCtx.locale.register(NS, {
|
|
3709
|
-
zh,
|
|
3710
|
-
en
|
|
3711
|
-
}), "dsh-conversation-ui: settings dictionaries");
|
|
3712
3021
|
for (const bundle of ["@jcy2387/dsh-conversation-ui", "@jcy2387/dsh-suite"]) settingsCtx.slots.inject("plugins.bundle.config", () => settingsCtx.slots.register({
|
|
3713
3022
|
name: "plugins.bundle.config",
|
|
3714
3023
|
key: bundle,
|
|
@@ -3720,39 +3029,7 @@ window.__ModuleLoader__.load({
|
|
|
3720
3029
|
detachPreference();
|
|
3721
3030
|
};
|
|
3722
3031
|
});
|
|
3723
|
-
|
|
3724
|
-
const thinkAutoExpand = (0, react.useSyncExternalStore)(preference.subscribe, preference.getSnapshot, preference.getSnapshot);
|
|
3725
|
-
return (0, react.createElement)(TypewriterAssistantNodeView, {
|
|
3726
|
-
...props,
|
|
3727
|
-
mode: config.mode,
|
|
3728
|
-
preset: config.preset,
|
|
3729
|
-
revealCharsPerSec: config.revealCharsPerSec,
|
|
3730
|
-
scrollSpeedPxPerSec: config.scrollSpeedPxPerSec,
|
|
3731
|
-
maxScrollSpeedPxPerSec: config.maxScrollSpeedPxPerSec,
|
|
3732
|
-
thinkAutoExpand
|
|
3733
|
-
});
|
|
3734
|
-
};
|
|
3735
|
-
ctx.slots.inject("conversation.chat.node", () => {
|
|
3736
|
-
const unwrap = wrapGrowingChatRows(ctx, config);
|
|
3737
|
-
const unshadow = ctx.slots.register({
|
|
3738
|
-
name: "conversation.chat.node",
|
|
3739
|
-
key: "assistant-step",
|
|
3740
|
-
priority: -100,
|
|
3741
|
-
locale: "chat",
|
|
3742
|
-
registrant: "dsh-conversation-ui"
|
|
3743
|
-
}, configured);
|
|
3744
|
-
return () => {
|
|
3745
|
-
unshadow();
|
|
3746
|
-
unwrap();
|
|
3747
|
-
};
|
|
3748
|
-
});
|
|
3749
|
-
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
3750
|
-
name: "conversation.chat.node",
|
|
3751
|
-
key: "turn-process",
|
|
3752
|
-
priority: -100,
|
|
3753
|
-
locale: "chat",
|
|
3754
|
-
registrant: "dsh-conversation-ui"
|
|
3755
|
-
}, CodexTurnProcessNodeView));
|
|
3032
|
+
ctx.slots.inject("conversation.chat.node", () => registerAssistantEnhancement(ctx, preference));
|
|
3756
3033
|
}
|
|
3757
3034
|
//#endregion
|
|
3758
3035
|
exports.apply = apply;
|