@klarkxy/dsh-current-title 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/docs/README.zh-CN.md +4 -2
- package/lib/client.inner.cjs +66 -62
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +67 -224
- package/lib/index.d.ts +1 -1
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -10,12 +10,14 @@ The bundle insert is enabled after installation. It does not permanently turn of
|
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
|
-
Requires Node.js ≥22 and DSH `0.1.7-rc.2`. The **Auto Title** entry starts enabled and can be disabled in plugin settings. Native title storage and scheduling come from the host `sessionTitle`; generation uses the host `llm` service.
|
|
13
|
+
Requires Node.js ≥22 and DSH `0.1.7-rc.2`. The **Auto Title** entry starts enabled and can be disabled in plugin settings. Native title storage and scheduling come from the host `sessionTitle`; generation uses the host `llm` service. Install the published package into the target profile:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
|
|
16
|
+
dsh plugin --profile web add @klarkxy/dsh-current-title
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
Replace `web` with your profile name. To uninstall, run `dsh plugin --profile web remove @klarkxy/dsh-current-title`.
|
|
20
|
+
|
|
19
21
|
Hosts that bundle this feature usually enable it by default; where the host supports live plugin switching, the switch under Settings → Plugins takes effect without a restart. Installation or removal may require a restart when the host asks for one.
|
|
20
22
|
|
|
21
23
|
## Host RPC
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
## 安装
|
|
12
12
|
|
|
13
|
-
需要 Node.js ≥22 与 DSH `0.1.7-rc.2`。「自动标题」默认启用,可在插件设置中关闭。标题写入宿主 `sessionTitle`,由宿主调度;生成使用宿主 `llm`
|
|
13
|
+
需要 Node.js ≥22 与 DSH `0.1.7-rc.2`。「自动标题」默认启用,可在插件设置中关闭。标题写入宿主 `sessionTitle`,由宿主调度;生成使用宿主 `llm` 服务。把已发布包装进目标 profile:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
|
|
16
|
+
dsh plugin --profile web add @klarkxy/dsh-current-title
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
把 `web` 换成你的 profile 名。卸载用 `dsh plugin --profile web remove @klarkxy/dsh-current-title`。
|
|
20
|
+
|
|
19
21
|
部分宿主会预装并默认启用本功能;宿主支持热切换时,通过「设置 → 插件」开关无需重启。宿主提示需要重启时,安装或移除后重启。
|
|
20
22
|
|
|
21
23
|
## 宿主 RPC
|
package/lib/client.inner.cjs
CHANGED
|
@@ -3,6 +3,30 @@ let react = require("react");
|
|
|
3
3
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
4
4
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
5
|
//#region ../dsh-plugin-kit/src/client-utils.ts
|
|
6
|
+
/** Fixed pause for failing background reads; manual work is never replayed. */
|
|
7
|
+
function createPluginReadGate(now = Date.now) {
|
|
8
|
+
let pausedUntil = 0;
|
|
9
|
+
let epoch = 0;
|
|
10
|
+
return {
|
|
11
|
+
canRead: () => now() >= pausedUntil,
|
|
12
|
+
reset: () => {
|
|
13
|
+
epoch++;
|
|
14
|
+
pausedUntil = 0;
|
|
15
|
+
},
|
|
16
|
+
async run(read) {
|
|
17
|
+
const current = epoch;
|
|
18
|
+
try {
|
|
19
|
+
const value = await read();
|
|
20
|
+
if (current === epoch) pausedUntil = 0;
|
|
21
|
+
return value;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
const message = error instanceof Error ? error.message : "";
|
|
24
|
+
if (current === epoch && (/(?:^|\s)transport failure for .+: HTTP (?:404|405|503)\b/.test(message) || error instanceof TypeError && /^(?:Failed to fetch|fetch failed|NetworkError when attempting to fetch resource\.?)$/i.test(message))) pausedUntil = now() + 3e4;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
6
30
|
/** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */
|
|
7
31
|
function selectedSessionId(client) {
|
|
8
32
|
const workspace = client.uiWorkspace?.current;
|
|
@@ -482,8 +506,6 @@ const titleCopy = {
|
|
|
482
506
|
loading: "正在读取标题设置…",
|
|
483
507
|
model: "标题模型",
|
|
484
508
|
modelDefault: "跟随会话模型",
|
|
485
|
-
effort: "思考强度",
|
|
486
|
-
effortDefault: "默认",
|
|
487
509
|
cadence: "更新节奏",
|
|
488
510
|
cadenceAll: "跟随当前任务(每条消息)",
|
|
489
511
|
cadenceFirst: "仅首条消息",
|
|
@@ -503,8 +525,6 @@ const titleCopy = {
|
|
|
503
525
|
loading: "Loading title settings…",
|
|
504
526
|
model: "Title model",
|
|
505
527
|
modelDefault: "Use the session model",
|
|
506
|
-
effort: "Reasoning effort",
|
|
507
|
-
effortDefault: "Default",
|
|
508
528
|
cadence: "Update cadence",
|
|
509
529
|
cadenceAll: "Track the current task (every message)",
|
|
510
530
|
cadenceFirst: "First message only",
|
|
@@ -661,28 +681,17 @@ function catalogChoices(value, selected) {
|
|
|
661
681
|
const id = typeof item.id === "string" ? item.id : "";
|
|
662
682
|
if (!id) continue;
|
|
663
683
|
const name = typeof item.name === "string" && item.name ? item.name : id;
|
|
664
|
-
const reasoning = item.reasoning && typeof item.reasoning === "object" ? item.reasoning : void 0;
|
|
665
|
-
const efforts = Array.isArray(reasoning?.efforts) ? reasoning.efforts.flatMap((effort) => {
|
|
666
|
-
if (!effort || typeof effort !== "object") return [];
|
|
667
|
-
const entry = effort;
|
|
668
|
-
return typeof entry.id === "string" && entry.id ? [{
|
|
669
|
-
id: entry.id,
|
|
670
|
-
name: typeof entry.name === "string" && entry.name ? entry.name : entry.id
|
|
671
|
-
}] : [];
|
|
672
|
-
}) : [];
|
|
673
684
|
choices.push({
|
|
674
685
|
provider,
|
|
675
686
|
model: id,
|
|
676
|
-
label: `${providerName} / ${name}
|
|
677
|
-
efforts
|
|
687
|
+
label: `${providerName} / ${name}`
|
|
678
688
|
});
|
|
679
689
|
}
|
|
680
690
|
}
|
|
681
691
|
if (selected.provider && selected.model && !choices.some((item) => item.provider === selected.provider && item.model === selected.model)) choices.push({
|
|
682
692
|
provider: selected.provider,
|
|
683
693
|
model: selected.model,
|
|
684
|
-
label: `${selected.provider} / ${selected.model}
|
|
685
|
-
efforts: []
|
|
694
|
+
label: `${selected.provider} / ${selected.model}`
|
|
686
695
|
});
|
|
687
696
|
return choices;
|
|
688
697
|
}
|
|
@@ -699,15 +708,30 @@ function TitleSettings(props) {
|
|
|
699
708
|
const workRef = (0, react.useRef)(void 0);
|
|
700
709
|
if (!workRef.current) workRef.current = createTitleClientWork();
|
|
701
710
|
const work = workRef.current;
|
|
711
|
+
const readGateRef = (0, react.useRef)(void 0);
|
|
712
|
+
if (!readGateRef.current) readGateRef.current = createPluginReadGate();
|
|
713
|
+
const readGate = readGateRef.current;
|
|
702
714
|
const busyRef = (0, react.useRef)(busy);
|
|
703
715
|
busyRef.current = busy;
|
|
704
716
|
const call = (endpoint, payload = {}) => props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload);
|
|
717
|
+
const readCall = (endpoint, payload) => readGate.run(() => call(endpoint, payload));
|
|
705
718
|
function commitMarker(next) {
|
|
706
719
|
applyMarkerFromStatus(props.marker, next, true);
|
|
707
720
|
}
|
|
708
721
|
(0, react.useEffect)(() => () => {
|
|
722
|
+
readGate.reset();
|
|
709
723
|
work.dispose();
|
|
710
|
-
}, [work]);
|
|
724
|
+
}, [work, readGate]);
|
|
725
|
+
(0, react.useEffect)(() => props.client.connection.generation?.subscribe(() => {
|
|
726
|
+
readGate.reset();
|
|
727
|
+
work.beginLoad();
|
|
728
|
+
busyRef.current = false;
|
|
729
|
+
setBusy(false);
|
|
730
|
+
}), [
|
|
731
|
+
props.client,
|
|
732
|
+
work,
|
|
733
|
+
readGate
|
|
734
|
+
]);
|
|
711
735
|
(0, react.useEffect)(() => {
|
|
712
736
|
const catalog = props.client.remote?.session?.modelCatalog;
|
|
713
737
|
if (!catalog) return void 0;
|
|
@@ -730,12 +754,13 @@ function TitleSettings(props) {
|
|
|
730
754
|
]);
|
|
731
755
|
(0, react.useEffect)(() => {
|
|
732
756
|
const generation = work.beginLoad();
|
|
757
|
+
readGate.reset();
|
|
733
758
|
const isCurrent = () => work.isLoad(generation);
|
|
734
759
|
setBusy(false);
|
|
735
760
|
setError("");
|
|
736
761
|
setNote("");
|
|
737
762
|
runTitleStatusLoad({
|
|
738
|
-
call,
|
|
763
|
+
call: readCall,
|
|
739
764
|
sessionId: sessionId || void 0,
|
|
740
765
|
isCurrent,
|
|
741
766
|
failedMessage: text.failed,
|
|
@@ -754,20 +779,22 @@ function TitleSettings(props) {
|
|
|
754
779
|
work
|
|
755
780
|
]);
|
|
756
781
|
const refreshStatus = (0, react.useCallback)(() => {
|
|
757
|
-
if (shouldSkipTitleRefresh({ busy: busyRef.current }) || work.disposed) return;
|
|
758
|
-
|
|
782
|
+
if (!readGate.canRead() || shouldSkipTitleRefresh({ busy: busyRef.current }) || work.disposed) return;
|
|
783
|
+
readGate.reset();
|
|
784
|
+
const token = work.beginRequest();
|
|
759
785
|
runTitleStatusLoad({
|
|
760
|
-
call,
|
|
786
|
+
call: readCall,
|
|
761
787
|
sessionId: sessionId || void 0,
|
|
762
|
-
isCurrent: () => work.
|
|
788
|
+
isCurrent: () => work.isRequest(token) && !shouldSkipTitleRefresh({ busy: busyRef.current }),
|
|
763
789
|
failedMessage: text.failed,
|
|
764
790
|
onStatus: (next) => {
|
|
765
791
|
if (shouldSkipTitleRefresh({ busy: busyRef.current })) return;
|
|
766
792
|
setStatus(next);
|
|
793
|
+
setError("");
|
|
767
794
|
},
|
|
768
|
-
onError:
|
|
795
|
+
onError: setError,
|
|
769
796
|
onMarker: (next) => {
|
|
770
|
-
if (shouldSkipTitleRefresh({ busy: busyRef.current })) return;
|
|
797
|
+
if (!next || shouldSkipTitleRefresh({ busy: busyRef.current })) return;
|
|
771
798
|
commitMarker(next);
|
|
772
799
|
}
|
|
773
800
|
});
|
|
@@ -789,14 +816,9 @@ function TitleSettings(props) {
|
|
|
789
816
|
const pinned = status?.session?.pinned === true;
|
|
790
817
|
const weOwn = status?.support.weOwn === true;
|
|
791
818
|
const canRegenerate = Boolean(sessionId) && weOwn && !busy;
|
|
792
|
-
const selectedChoice = choices.find((item) => item.provider === savedModel.provider && item.model === savedModel.model);
|
|
793
|
-
const efforts = selectedChoice ? [...selectedChoice.efforts] : [];
|
|
794
|
-
if (selectedChoice && savedModel.reasoningEffort && !efforts.some((item) => item.id === savedModel.reasoningEffort)) efforts.push({
|
|
795
|
-
id: savedModel.reasoningEffort,
|
|
796
|
-
name: savedModel.reasoningEffort
|
|
797
|
-
});
|
|
798
819
|
function saveSettings(patch) {
|
|
799
820
|
if (!status) return;
|
|
821
|
+
readGate.reset();
|
|
800
822
|
const token = work.beginRequest();
|
|
801
823
|
setError("");
|
|
802
824
|
setNote("");
|
|
@@ -844,11 +866,20 @@ function TitleSettings(props) {
|
|
|
844
866
|
className: "dsh-ui-hint",
|
|
845
867
|
children: [text.inactive, status.support.limitation ? ` ${status.support.limitation}` : ""]
|
|
846
868
|
}) : null,
|
|
847
|
-
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
869
|
+
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
848
870
|
role: "alert",
|
|
849
871
|
className: "dsh-ui-error dsh-ui-wrap",
|
|
850
872
|
children: error
|
|
851
|
-
})
|
|
873
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
874
|
+
variant: "outline",
|
|
875
|
+
size: "sm",
|
|
876
|
+
disabled: busy,
|
|
877
|
+
onClick: () => {
|
|
878
|
+
readGate.reset();
|
|
879
|
+
refreshStatus();
|
|
880
|
+
},
|
|
881
|
+
children: seat.locale === "zh" ? "重试" : "Retry"
|
|
882
|
+
})] }) : null,
|
|
852
883
|
note ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
853
884
|
role: "status",
|
|
854
885
|
className: "dsh-ui-notice",
|
|
@@ -862,6 +893,7 @@ function TitleSettings(props) {
|
|
|
862
893
|
disabled: !canRegenerate,
|
|
863
894
|
onClick: () => {
|
|
864
895
|
if (!sessionId) return;
|
|
896
|
+
readGate.reset();
|
|
865
897
|
const token = work.beginRequest();
|
|
866
898
|
setError("");
|
|
867
899
|
setNote("");
|
|
@@ -903,6 +935,7 @@ function TitleSettings(props) {
|
|
|
903
935
|
setPrompt(void 0);
|
|
904
936
|
return;
|
|
905
937
|
}
|
|
938
|
+
readGate.reset();
|
|
906
939
|
const token = work.beginRequest();
|
|
907
940
|
setError("");
|
|
908
941
|
runTitleSettingsSave({
|
|
@@ -960,35 +993,6 @@ function TitleSettings(props) {
|
|
|
960
993
|
}, `${choice.provider}\u001f${choice.model}`))]
|
|
961
994
|
})]
|
|
962
995
|
}),
|
|
963
|
-
selectedChoice && efforts.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
964
|
-
className: "dsh-ui-field",
|
|
965
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
966
|
-
className: "dsh-ui-label",
|
|
967
|
-
children: text.effort
|
|
968
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
969
|
-
className: "dsh-ui-select",
|
|
970
|
-
value: savedModel.reasoningEffort ?? "",
|
|
971
|
-
disabled: busy || !status,
|
|
972
|
-
onChange: (event) => {
|
|
973
|
-
const effort = event.target.value;
|
|
974
|
-
const model = {
|
|
975
|
-
provider: savedModel.provider,
|
|
976
|
-
model: savedModel.model
|
|
977
|
-
};
|
|
978
|
-
saveSettings({ model: effort ? {
|
|
979
|
-
...model,
|
|
980
|
-
reasoningEffort: effort
|
|
981
|
-
} : model });
|
|
982
|
-
},
|
|
983
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
984
|
-
value: "",
|
|
985
|
-
children: text.effortDefault
|
|
986
|
-
}), efforts.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
987
|
-
value: effort.id,
|
|
988
|
-
children: effort.name
|
|
989
|
-
}, effort.id))]
|
|
990
|
-
})]
|
|
991
|
-
}) : null,
|
|
992
996
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
993
997
|
className: "dsh-ui-field",
|
|
994
998
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
package/lib/client.inner.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.inner.cjs","names":["useSyncExternalStore","useCallback","useRef","useState","useRef","useCallback","Button"],"sources":["../../dsh-plugin-kit/src/client-utils.ts","../../dsh-plugin-kit/src/official-ui.ts","../src/contracts.ts","../src/client-work.ts","../src/marker.ts","../src/client.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\nexport interface NativeSurfaceClient {\n sessions: {\n binding?(sessionId: string): { eventSource: { subscribe(listener: () => void): () => void } } | undefined\n }\n uiWorkspace: { current?: { getSnapshot(): { sessionId: string } | undefined; subscribe(listener: () => void): () => void } }\n uiSession: { adapter: { current: { getSnapshot(): { key?: string }; subscribe(listener: () => void): () => void } } }\n locale: { getSnapshot(): { active: string }; subscribe(listener: () => void): () => void }\n connection?: { generation?: { subscribe(listener: () => void): () => void } }\n}\n\n/** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */\nexport function selectedSessionId(client: Pick<NativeSurfaceClient, 'uiWorkspace' | 'uiSession'>): string {\n const workspace = client.uiWorkspace?.current\n return workspace\n ? workspace.getSnapshot()?.sessionId ?? ''\n : client.uiSession.adapter.current.getSnapshot().key ?? ''\n}\n\n/**\n * Owner props are data the host composed, never a Cordis context: reading an\n * undeclared property off one throws instead of returning undefined, which\n * would crash the slot entry and abdicate its cell for good. Tolerate a\n * throwing read so a mistaken prop degrades to \"not supplied\".\n */\nfunction read(source: unknown, key: string): unknown {\n if (source === null || typeof source !== 'object') return undefined\n try {\n return (source as Record<string, unknown>)[key]\n } catch {\n return undefined\n }\n}\n\nfunction readString(source: unknown, key: string): string | undefined {\n const value = read(source, key)\n return typeof value === 'string' ? value : undefined\n}\n\n/** Owner props win; native settings only supplies close, so resolve its selected session. */\nexport function useNativeSeat(client: NativeSurfaceClient, props?: unknown) {\n const current = useSyncExternalStore(\n useCallback((fn: () => void) => (client.uiWorkspace?.current ?? client.uiSession.adapter.current).subscribe(fn), [client]),\n useCallback(() => selectedSessionId(client), [client]),\n () => '',\n )\n const language = useSyncExternalStore(\n useCallback((fn: () => void) => client.locale.subscribe(fn), [client]),\n useCallback(() => client.locale.getSnapshot().active, [client]),\n () => 'en',\n )\n const sessionId = readString(props, 'sessionId') ?? readString(read(props, 'owner'), 'sessionId') ?? current\n const requestedLocale = read(props, 'locale') ?? read(read(props, 'owner'), 'locale') ?? language\n return { sessionId, locale: (String(requestedLocale).startsWith('zh') ? 'zh' : 'en') as 'zh' | 'en',\n hidden: read(props, 'hidden') === true || read(read(props, 'owner'), 'hidden') === true }\n}\n\n/** Refresh on native log boundaries/reconnect/focus. Read-only settling is bounded to an observed job. */\nexport function useFeatureRefresh(\n client: NativeSurfaceClient, sessionId: string, refresh: () => void,\n working = false, enabled = true,\n): void {\n const refreshRef = useRef(refresh)\n refreshRef.current = refresh\n useEffect(() => {\n if (!enabled) return\n let timer: ReturnType<typeof setTimeout> | undefined\n const queue = () => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n clearTimeout(timer)\n timer = setTimeout(() => refreshRef.current(), 150)\n }\n const source = sessionId ? client.sessions.binding?.(sessionId)?.eventSource : undefined\n const stopEvents = source?.subscribe(queue)\n const stopConnection = client.connection?.generation?.subscribe(queue)\n const visibility = () => { if (document.visibilityState === 'visible') queue() }\n window.addEventListener('focus', queue)\n document.addEventListener('visibilitychange', visibility)\n // Details are collapsed by default; opening an existing panel must get current state.\n document.addEventListener('toggle', queue, true)\n return () => {\n clearTimeout(timer)\n stopEvents?.(); stopConnection?.()\n window.removeEventListener('focus', queue)\n document.removeEventListener('visibilitychange', visibility)\n document.removeEventListener('toggle', queue, true)\n }\n }, [client, sessionId, enabled])\n useEffect(() => {\n if (!enabled || !working) return\n let delay = 250\n const until = Date.now() + 300_000\n let timer: ReturnType<typeof setTimeout>\n const tick = () => {\n if (Date.now() >= until) return\n if (document.visibilityState !== 'hidden') refreshRef.current()\n delay = Math.min(delay * 2, 2000)\n timer = setTimeout(tick, delay)\n }\n timer = setTimeout(tick, delay)\n return () => clearTimeout(timer)\n }, [client, sessionId, working, enabled])\n}\n","/**\n * Shared contract that keeps every plugin's browser-side UI on the official\n * DeepSeek Harness Web design language.\n *\n * Two rules produce that language, and both are load-bearing here:\n *\n * 1. Colour, radius, elevation and focus come from the host theme's real\n * `--dsw-*` tokens, written under their own names. Plugins never invent a\n * token, never alias the official ones behind a private palette (a private\n * alias is just a second, diverging theme), and never carries a literal\n * fallback — the host publishes light and dark, and a literal would pin one\n * of them. The only non-colour custom properties used are the host's own\n * content-font axis and frame clearance.\n *\n * 2. Anything the host already ships is used, not reimplemented. Controls come\n * from `@deepseek-ai/dsh-client-ui-primitives` (`Button`, `Input`,\n * `Checkbox`, `Switch`, `Tag`, `Pill`, `SegmentedControl`, `Menu`, `Modal`,\n * `Tooltip`, `Toast`, `DisclosureRow`, `StateDot`, `PathLabel`, the settings\n * form suite). This module only styles what primitives do not cover: page\n * scaffolding, field layout, banners, empty states and scroll regions.\n *\n * The metrics below are transcribed from the primitives' own CSS modules so a\n * feature panel lines up pixel-for-pixel with a native one: the 14/22 body and\n * 13/20 compact type tiers, the 0.5px hairline scale, and the elevation family\n * that draws a surface's edge in its shadow (`border: 0`) instead of a border.\n */\n\n/**\n * Every `--dsw-*` token this repo is allowed to reference, grouped by role.\n *\n * Plugins may only colour through this list. It is exported so the guard test\n * can fail a build when a stylesheet reaches for anything else — the failure\n * mode this prevents is silent: an unknown token resolves to nothing, so a\n * border disappears or a label inherits the wrong colour with no error anywhere.\n */\nexport const OFFICIAL_THEME_TOKENS = {\n /** Surfaces, from the page up to the topmost nested card. */\n surface: [\n '--dsw-alias-bg-base',\n '--dsw-alias-bg-layer-1',\n '--dsw-alias-bg-layer-2',\n '--dsw-alias-bg-layer-3',\n '--dsw-alias-bg-layer-4',\n '--dsw-alias-bg-module-platform',\n '--dsw-alias-bg-overlay',\n ],\n /** Hairlines. l1 is near-invisible on a menu surface, so menus use l2+. */\n border: ['--dsw-alias-border-l1', '--dsw-alias-border-l2', '--dsw-alias-border-l3', '--dsw-alias-border-l4'],\n /** Text. `caption` is menu shortcut text, `dimmed` is placeholder text. */\n label: [\n '--dsw-alias-label-primary',\n '--dsw-alias-label-secondary',\n '--dsw-alias-label-tertiary',\n '--dsw-alias-label-caption',\n '--dsw-alias-label-dimmed',\n '--dsw-alias-label-error',\n '--dsw-alias-label-primary-foreground',\n ],\n /** Interactive fills. The `-danger` hover belongs to destructive rows. */\n interactive: [\n '--dsw-alias-interactive-bg-hover',\n '--dsw-alias-interactive-bg-active',\n '--dsw-alias-interactive-bg-hover-danger',\n ],\n /** Accent and status. `business` is the focus ring's default colour. */\n accent: [\n '--dsw-alias-brand-primary',\n '--dsw-alias-button-primary-fill',\n '--dsw-alias-button-primary-hover',\n '--dsw-alias-button-tool-bar-fill',\n '--dsw-alias-button-tool-bar-hover',\n '--dsw-alias-button-ghost-active-fill',\n '--dsw-alias-button-ghost-active-border',\n ],\n state: [\n '--dsw-alias-state-business-primary',\n '--dsw-alias-state-success-primary',\n '--dsw-alias-state-warn-primary',\n '--dsw-alias-state-error-primary',\n '--dsw-alias-state-idle-primary',\n ],\n /** Corner scale: sm 8, md 12, lg the large card, panel the modal. */\n radius: ['--dsw-radius-sm', '--dsw-radius-md', '--dsw-radius-lg', '--dsw-radius-panel'],\n /** An elevated surface draws its edge in the shadow, so it keeps border: 0. */\n elevation: [\n '--dsw-elevation-soft',\n '--dsw-elevation-stroke',\n '--dsw-elevation-stroke-color',\n '--dsw-elevation-panel',\n '--dsw-elevation-prominent',\n ],\n /** Floats, masks and scrollbars. */\n overlay: [\n '--dsw-menu-surface-fill',\n '--dsw-menu-backdrop-filter',\n '--dsw-mask-blur',\n '--dsw-alias-bg-mask-1',\n '--dsw-alias-menu-icon',\n '--dsw-alias-scrollbar-bg-l2',\n '--dsw-alias-scrollbar-hover-l2',\n '--dsw-shadow-lv3',\n ],\n /** Motion, focus and type axis, published by the host rather than by a component. */\n system: [\n '--dsw-focus-ring-width',\n '--dsw-focus-ring-color',\n '--dsw-font-markdown-code-font-family',\n '--ds-transition-duration',\n '--ds-ease-in-out',\n '--ds-font-family-code',\n '--dsh-scrollbar-thumb',\n '--dsh-scrollbar-thumb-hover',\n '--dsh-content-font-size-secondary',\n '--dsh-content-font-delta',\n '--dsh-frame-top-clearance',\n ],\n} as const\n\n/** Every official token name, flat. Used by the token guard test. */\nexport const OFFICIAL_THEME_TOKEN_NAMES: readonly string[] = Object.values(OFFICIAL_THEME_TOKENS).flat()\n\n/** The elevation steps a surface can be raised by, softest first. */\nexport type OfficialElevation = 'soft' | 'stroke' | 'panel' | 'prominent'\n\n/**\n * The host's focus ring shorthand, verbatim. Writing this per control is how\n * rings drift apart; a stylesheet that draws its own focus style should use\n * {@link officialFocus} instead. The colour fallback is the host's own default.\n */\nexport const OFFICIAL_FOCUS_RING =\n 'var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))'\n\n/**\n * A complete `outline` declaration at the official geometry. `offset` defaults\n * to the 2px the native controls use; the host's inline field rules sit at 1px\n * and a segmented tab pulls the ring inside itself at -2px.\n */\nexport function officialFocus(offset = '2px'): string {\n return `outline: ${OFFICIAL_FOCUS_RING}; outline-offset: ${offset}`\n}\n\n/**\n * An elevated surface. The host draws a raised surface's edge inside its\n * shadow rather than as a border, so a card sets `border: 0` and takes the edge\n * from the elevation — which is also why its border stays off the alias-border\n * set that a flat, non-elevated rule would use.\n */\nexport function officialElevation(level: OfficialElevation): string {\n return `border: 0; box-shadow: var(--dsw-elevation-${level})`\n}\n\n/**\n * An elevated surface whose edge should read as a specific hairline. Rebinding\n * the stroke colour is how a menu card picks l1 while a panel picks l3, without\n * the two growing apart by hand.\n */\nexport function officialStrokedElevation(level: OfficialElevation, color: string): string {\n return `--dsw-elevation-stroke-color: ${color}; ${officialElevation(level)}`\n}\n\n/**\n * The shared stylesheet for a plugin UI, scoped under that plugin's root class.\n *\n * Scoping is what keeps this safe to always-bundle into every client: the rules\n * can only match inside the plugin's own subtree, so two plugins can both mount\n * `dsh-ui-card` without either styling the other's markup.\n *\n * Each recipe matches the root element *and* its descendants, because the\n * commonest arrangement is one element that is both — a surface that carries\n * the root class and `dsh-ui-card`, or a portaled dialog that is the root and\n * the `dsh-ui-surface`. A descendant-only scope would silently leave those\n * unstyled, with no error anywhere.\n *\n * A caveat worth knowing: `Modal` and `Menu` portal to `document.body`, so their\n * content leaves the plugin's subtree entirely. A portaled surface therefore\n * needs its own root class on an element inside the portal.\n *\n * Only patterns that primitives do not provide live here. If a control appears\n * below that `Button`/`Input`/`Switch`/`Tag`/`Menu` already covers, that is a\n * bug in this file: use the primitive and delete the recipe.\n */\nexport function officialUiCss(roots: string | readonly string[]): string {\n // One plugin often mounts several unrelated surfaces (a settings seat, a chat\n // card, a header menu), so the caller names every root. The rules below are\n // nested under a single selector list and use `&`, which the browser expands\n // per root — so one stylesheet covers all of them without duplicating itself.\n const scope = (typeof roots === 'string' ? [roots] : roots).map(root => `.${root}`).join(', ')\n const sheet = `\n/* Official DSH Web UI contract. Generated by @klarkxy/dsh-plugin-kit/official-ui.\n * Do not hand-edit the copy inside a plugin: change this module so every plugin\n * moves together. Scope: ${scope} */\n/* The scope rule below stays open for the whole sheet: every rule after it\n * nests with the parent selector, so one stylesheet can cover several unrelated\n * roots without leaking into a neighbouring plugin. Its closing brace is last. */\n${scope} {\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n min-width: 0;\n\n& *, & *::before, & *::after { box-sizing: border-box; }\n& h1, & h2, & h3, & h4, & p, & figure { margin: 0; }\n/* Keyboard focus only: pointer input keeps the native resting appearance. The\n * ring needs no radius of its own — the outline already follows the control's\n * own border-radius, and overriding it here would flatten every control. */\n& :focus-visible { ${officialFocus()}; }\n& [hidden] { display: none !important; }\n\n/* --- Type tiers. The same 14/22 and 13/20 steps the primitives use. --- */\n& .dsh-ui-title { font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-heading { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-compact { font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-meta { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-error { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-warn { color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-success { color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-muted { color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n& .dsh-ui-wrap { min-width: 0; overflow-wrap: anywhere; }\n\n/* --- Layout scaffolding. --- */\n& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }\n& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }\n& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n& .dsh-ui-spacer { flex: 1; min-width: 0; }\n/* A 0.5px l2 rule is the host's section divider; reserve the same rhythm. */\n& .dsh-ui-divider { height: 0.5px; background: var(--dsw-alias-border-l2); }\n& .dsh-ui-section { display: flex; flex-direction: column; gap: 12px; padding-top: 16px; border-top: 0.5px solid var(--dsw-alias-border-l2); }\n\n/* --- Card: a raised surface whose edge lives in the shadow. --- */\n& .dsh-ui-card {\n ${officialElevation('stroke')}\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n min-width: 0;\n}\n& .dsh-ui-card--flat { border: 0.5px solid var(--dsw-alias-border-l3); box-shadow: none; }\n& .dsh-ui-card--nested { background: var(--dsw-alias-bg-layer-2); }\n& .dsh-ui-card--plain { background: none; }\n\n/* --- Field: label, control, help, error. The control itself is an\n * official primitive, so this only owns the vertical rhythm. --- */\n& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }\n& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }\n& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-help p { margin: 0; }\n& .dsh-ui-help p + p { margin-top: 8px; }\n& .dsh-ui-required { color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-control { width: 100%; min-width: 0; }\n/* An invalid control is marked on the control, not only in the message. */\n& .dsh-ui-control[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-readonly { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-readonly > dt { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-readonly > dd { margin: 0; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }\n\n/* --- Buttons row. A no-op container: it exists so actions line up on the\n * trailing edge the way every native panel does. --- */\n& .dsh-ui-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 4px; }\n& .dsh-ui-actions-end { justify-content: flex-end; }\n\n/* --- Banners. A banner is a left-rail notice, the shape used for warnings,\n * deprecations and blocking instructions. --- */\n& .dsh-ui-banner {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px 14px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-left: 3px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-banner-title { font-weight: 500; color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-banner--info { border-left-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-banner--danger { border-left-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-banner--success { border-left-color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-banner p { margin: 0; }\n\n/* --- Inline notice: a transient confirmation with no chrome of its own. --- */\n& .dsh-ui-notice { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-notice--error { color: var(--dsw-alias-state-error-primary); }\n\n/* --- Empty and loading states. Both sit in a dashed well so an empty panel\n * reads as \"nothing here yet\" rather than as a broken layout. --- */\n& .dsh-ui-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n padding: 20px 16px;\n border: 0.5px dashed var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-loading { display: flex; align-items: center; gap: 8px; padding: 20px 0; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-secondary); }\n\n/* --- Selectable list. A row is a button-sized target with a hover fill and\n * a selected fill; the name carries the weight, the description does not. --- */\n& .dsh-ui-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n& .dsh-ui-list-scroll { max-height: min(66vh, 760px); overflow-y: auto; overflow-x: hidden; }\n& .dsh-ui-list-row { border-radius: var(--dsw-radius-md); }\n& .dsh-ui-list-row:hover { background: var(--dsw-alias-interactive-bg-hover); }\n& .dsh-ui-list-row[aria-selected='true'], & .dsh-ui-list-row[data-selected] { background: var(--dsw-alias-interactive-bg-active); }\n& .dsh-ui-list-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n min-width: 0;\n padding: 10px 12px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n& .dsh-ui-list-item:disabled { cursor: default; }\n& .dsh-ui-list-item:disabled:hover { background: none; }\n& .dsh-ui-list-name { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); overflow-wrap: anywhere; }\n& .dsh-ui-list-desc { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n\n/* --- Code and structured output. Wraps rather than scrolls, because a\n * feature panel is read rather than scanned. --- */\n& .dsh-ui-code {\n padding: 10px 12px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code, ui-monospace, 'Cascadia Mono', Consolas, monospace);\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n& .dsh-ui-scroll { max-height: 60vh; overflow: auto; overscroll-behavior: contain; }\n\n/* --- A toggle row: label on the left, switch on the trailing edge. This is\n * layout only; the switch itself is the official primitive. --- */\n& .dsh-ui-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-width: 0; padding: 12px 0; }\n& .dsh-ui-toggle-row + .dsh-ui-toggle-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n& .dsh-ui-toggle-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-toggle-label { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Floating surface: a panel anchored to a trigger. This is the material\n * a menu card is made of — the translucent fill plus its backdrop blur, with\n * the edge riding inside the prominent elevation. A plugin that hand-rolls this\n * is how tokens like --dsw-specific-menu get invented; use this instead. --- */\n& .dsh-ui-surface {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n position: relative;\n display: flex;\n flex-direction: column;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-menu-surface-fill);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n box-shadow: var(--dsw-elevation-prominent);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n line-height: 20px;\n min-width: 0;\n}\n& .dsh-ui-surface-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; overflow-y: auto; }\n& .dsh-ui-surface-head { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-surface-title { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Native select. The primitives ship no select, so a plugin that offers a\n * closed list of choices keeps the platform control and matches the official\n * settings field geometry exactly (34px, 0.5px l4, radius-md, layer-3). A\n * SegmentedControl is the primitive to reach for when the choices are few\n * enough to show at once. --- */\n& .dsh-ui-select {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n& .dsh-ui-select:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* Long panels scroll inside themselves instead of growing the host page. */\n& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n& .dsh-ui-panel-wide { max-width: 100%; }\n\n@media (prefers-reduced-motion: reduce) {\n & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }\n}\n}\n`\n // Widen every recipe from \"a descendant of the root\" to \"the root, or one of\n // its descendants\". Written as a transform rather than by hand so no recipe\n // can be added later with only the descendant form. The pattern is narrow on\n // purpose: a leading `&` followed by one recipe class and no combinator, so\n // sibling and child rules such as `.dsh-ui-field + .dsh-ui-field` keep their\n // own meaning and are left alone.\n return sheet.replace(/^& (\\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className: string) =>\n `&${className}, & ${className}`)\n}\n","/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nexport type { RpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-current-title'\nexport const FEATURE_ID = 'current-title'\nexport const PROVIDER_ID = '@klarkxy/dsh-current-title'\nexport const PURPOSE_ID = 'current-title.generate'\nexport const RPC_CHANNEL = '/dsh-current-title'\nexport const TITLE_CLIENT_SERVICE = 'dshCurrentTitleClient'\nexport const PROMPT_VERSION = 'current-title.v2'\nexport const SCHEMA_VERSION = 'title-json.v1'\nexport const CONTRACT_VERSION = 1\nexport const SETTINGS_KEY = 'current'\nexport const MAX_PROMPT_CHARS = 4000\n\nexport const DEFAULT_MAX_RECENT_MESSAGES = 8\nexport const DEFAULT_TARGET_WORDS = 5\nexport const DEFAULT_TARGET_CJK = 10\nexport const DEFAULT_MAX_INPUT_BYTES = 4096\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 256\nexport const DEFAULT_TIMEOUT_MS = 60_000\nexport const DEFAULT_MAX_TITLE_BYTES = 80\n\nexport type TitleLocaleMode = 'auto' | 'zh' | 'en'\nexport type TitleSourceKind = 'fallback' | 'provider' | 'user'\n/** Automatic generation cadence: every eligible message, or only the first. */\nexport type TitleCadence = 'all-prompts' | 'first-prompt'\n\nexport interface TitleMessage {\n readonly seq: number\n readonly text: string\n}\n\nexport interface TitleSnapshot {\n readonly title: string\n readonly messageSeqs: readonly number[]\n readonly source: { readonly kind: TitleSourceKind; readonly provider?: string }\n readonly eventSeq: number\n readonly updatedAt: number\n}\n\n/** Empty provider and model means the shared weak role. Both must be set together. */\nexport interface TitleModelRoute {\n provider: string\n model: string\n reasoningEffort?: string\n}\n\nexport interface TitleSettings {\n revision: number\n locale: TitleLocaleMode\n /** Empty keeps the built-in title instruction. */\n prompt: string\n model: TitleModelRoute\n cadence: TitleCadence\n}\n\nexport interface TitleSupport {\n nativeOwner: string | null\n weOwn: boolean\n limitation?: string\n}\n\nexport interface TitleStatus {\n settings: TitleSettings\n support: TitleSupport\n session?: {\n sessionId: string\n title?: string\n sourceKind?: TitleSourceKind\n generating: boolean\n pinned: boolean\n }\n}\n\nexport interface TitleClientMarker {\n active: boolean\n}\n\nexport interface GenerateConfig {\n readonly maxRecentMessages: number\n readonly locale: TitleLocaleMode\n readonly targetWords: number\n readonly targetCjkCharacters: number\n readonly maxInputBytes: number\n readonly maxOutputTokens: number\n readonly timeoutMs: number\n readonly maxTitleBytes: number\n}\n\nexport function defaultModelRoute(): TitleModelRoute {\n return { provider: '', model: '' }\n}\n\nexport function defaultSettings(locale: TitleLocaleMode = 'auto'): TitleSettings {\n return { revision: 0, locale, prompt: '', model: defaultModelRoute(), cadence: 'all-prompts' }\n}\n\nexport function normalizeCadence(value: unknown): TitleCadence {\n return value === 'first-prompt' ? 'first-prompt' : 'all-prompts'\n}\n\nexport function normalizePrompt(value: unknown): string {\n if (typeof value !== 'string') return ''\n return value.replace(/\\u0000/gu, '').trim().slice(0, MAX_PROMPT_CHARS)\n}\n\nexport function normalizeModelRoute(value: unknown): TitleModelRoute {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return defaultModelRoute()\n const route = value as Record<string, unknown>\n const provider = typeof route.provider === 'string' ? route.provider.trim() : ''\n const model = typeof route.model === 'string' ? route.model.trim() : ''\n const effort = typeof route.reasoningEffort === 'string' ? route.reasoningEffort.trim() : ''\n if (!provider || !model || provider.length > 250 || model.length > 250) return defaultModelRoute()\n return effort && effort.length <= 80 ? { provider, model, reasoningEffort: effort } : { provider, model }\n}\n\nexport function defaultGenerateConfig(locale: TitleLocaleMode = 'auto'): GenerateConfig {\n return {\n maxRecentMessages: DEFAULT_MAX_RECENT_MESSAGES,\n locale,\n targetWords: DEFAULT_TARGET_WORDS,\n targetCjkCharacters: DEFAULT_TARGET_CJK,\n maxInputBytes: DEFAULT_MAX_INPUT_BYTES,\n maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxTitleBytes: DEFAULT_MAX_TITLE_BYTES,\n }\n}\n\nexport function isTitleLocaleMode(value: unknown): value is TitleLocaleMode {\n return value === 'auto' || value === 'zh' || value === 'en'\n}\n","import type { RpcResult, TitleCadence, TitleModelRoute, TitleStatus } from './contracts.ts'\n\nexport const titleCopy = {\n zh: {\n label: '自动标题',\n pinned: '已手动命名',\n generating: '正在生成标题…',\n regenerate: '重新生成',\n locale: '类型标签语言',\n auto: '自动',\n prompt: '标题提示词',\n promptHint: '留空用内置说明,仍返回类型和摘要;离开输入框即保存。',\n loading: '正在读取标题设置…',\n model: '标题模型',\n modelDefault: '跟随会话模型',\n effort: '思考强度',\n effortDefault: '默认',\n cadence: '更新节奏',\n cadenceAll: '跟随当前任务(每条消息)',\n cadenceFirst: '仅首条消息',\n saved: '已保存。',\n failed: '无法读取标题设置。',\n inactive: '标题服务未接管,新消息暂时不会自动更新。',\n },\n en: {\n label: 'Auto Title',\n pinned: 'Renamed manually',\n generating: 'Generating title…',\n regenerate: 'Regenerate',\n locale: 'Type-label language',\n auto: 'Auto',\n prompt: 'Title prompt',\n promptHint: 'Empty uses the built-in instruction; a type and summary are still returned. Saves on blur.',\n loading: 'Loading title settings…',\n model: 'Title model',\n modelDefault: 'Use the session model',\n effort: 'Reasoning effort',\n effortDefault: 'Default',\n cadence: 'Update cadence',\n cadenceAll: 'Track the current task (every message)',\n cadenceFirst: 'First message only',\n saved: 'Saved.',\n failed: 'Could not read title settings.',\n inactive: 'Title generation is not active, so new messages will not rename this session.',\n },\n} as const\n\nexport function settingsCopy(locale: 'zh' | 'en') {\n return titleCopy[locale] ?? titleCopy.zh\n}\n\n/** `undefined` draft = not edited; an empty string is a real edit (use built-in instruction). */\nexport function promptFieldValue(draft: string | undefined, saved: string): string {\n return draft ?? saved\n}\n\n/** The prompt to persist on blur, or `undefined` when nothing changed. */\nexport function promptToSave(draft: string | undefined, saved: string): string | undefined {\n if (draft === undefined) return undefined\n const next = draft.trim()\n return next === saved ? undefined : next\n}\n\nexport function shouldSkipTitleRefresh(input: { busy: boolean }): boolean {\n return input.busy\n}\n\nexport function createTitleClientWork() {\n let generation = 0\n let request = 0\n let disposed = false\n return {\n get disposed() { return disposed },\n beginLoad() {\n generation += 1\n request += 1\n return generation\n },\n captureLoad() {\n return generation\n },\n beginRequest() {\n request += 1\n return { generation, request }\n },\n isLoad(generationToken: number) {\n return !disposed && generation === generationToken\n },\n isRequest(token: { generation: number; request: number }) {\n return !disposed && generation === token.generation && request === token.request\n },\n dispose() {\n disposed = true\n generation += 1\n request += 1\n },\n }\n}\n\nexport type TitleClientWork = ReturnType<typeof createTitleClientWork>\nexport type TitleClientCall = (endpoint: string, payload?: unknown) => Promise<unknown>\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\n\nasync function invoke<T>(call: TitleClientCall, endpoint: string, payload?: unknown): Promise<T> {\n return unwrap(await call(endpoint, payload) as RpcResult<T>)\n}\n\nexport async function runTitleStatusLoad(input: {\n call: TitleClientCall\n sessionId?: string\n isCurrent: () => boolean\n failedMessage: string\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n try {\n const status = await invoke<TitleStatus>(\n input.call,\n 'status',\n input.sessionId ? { sessionId: input.sessionId } : {},\n )\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch {\n if (!input.isCurrent()) return\n input.onMarker(undefined)\n input.onError(input.failedMessage)\n }\n}\n\nexport async function runTitleRegenerateFlow(input: {\n call: TitleClientCall\n sessionId: string\n isCurrent: () => boolean\n failedMessage: string\n onBusy: (busy: boolean) => void\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n if (!input.sessionId || !input.isCurrent()) return\n input.onBusy(true)\n try {\n await invoke(input.call, 'regenerate', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n const status = await invoke<TitleStatus>(input.call, 'status', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n\nexport async function runTitleSettingsSave(input: {\n call: TitleClientCall\n prompt?: string\n model?: TitleModelRoute\n cadence?: TitleCadence\n expectedRevision: number\n isCurrent: () => boolean\n savedMessage: string\n failedMessage: string\n onBusy: (busy: boolean) => void\n onSettings: (settings: TitleStatus['settings']) => void\n onNote: (note: string) => void\n onError: (message: string) => void\n}): Promise<void> {\n input.onBusy(true)\n try {\n const settings = await invoke<TitleStatus['settings']>(input.call, 'settings', {\n ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),\n ...(input.model !== undefined ? { model: input.model } : {}),\n ...(input.cadence !== undefined ? { cadence: input.cadence } : {}),\n expectedRevision: input.expectedRevision,\n })\n if (!input.isCurrent()) return\n input.onSettings(settings)\n input.onNote(input.savedMessage)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n","import type { TitleClientMarker, TitleStatus } from './contracts.ts'\n\nexport function createTitleClientMarker(): TitleClientMarker {\n return { active: false }\n}\n\nexport function applyMarkerFromStatus(marker: TitleClientMarker, status: Pick<TitleStatus, 'support'> | undefined, live: boolean): void {\n if (!live) return\n marker.active = status?.support.weOwn === true\n}\n\nexport function disposeTitleClientMarker(marker: TitleClientMarker): void {\n marker.active = false\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { NativeSurfaceClient } from '@klarkxy/dsh-plugin-kit/client-utils'\nimport { useFeatureRefresh, useNativeSeat } from '@klarkxy/dsh-plugin-kit/client-utils'\nimport { Button } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { officialUiCss } from '@klarkxy/dsh-plugin-kit/official-ui'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { RPC_CHANNEL, TITLE_CLIENT_SERVICE, type RpcResult, type TitleCadence, type TitleModelRoute, type TitleStatus } from './contracts.ts'\nimport {\n createTitleClientWork, promptFieldValue, promptToSave, runTitleRegenerateFlow, runTitleSettingsSave, runTitleStatusLoad,\n shouldSkipTitleRefresh, titleCopy, type TitleClientCall, type TitleClientWork,\n} from './client-work.ts'\nimport { applyMarkerFromStatus, createTitleClientMarker, disposeTitleClientMarker } from './marker.ts'\n\nexport const name = 'dsh-current-title-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.session', 'sessions', 'locale', 'uiWorkspace', 'uiSession'] as const\nexport { createTitleClientMarker, disposeTitleClientMarker, applyMarkerFromStatus }\n\ntype Client = NativeSurfaceClient & {\n connection: NonNullable<NativeSurfaceClient['connection']> & {\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n }\n remote?: { session?: { modelCatalog?: () => Promise<unknown> } }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; key: string }, render: unknown): () => void\n }\n}\n\ninterface CatalogChoice {\n provider: string\n model: string\n label: string\n efforts: ReadonlyArray<{ id: string; name: string }>\n}\n\nfunction catalogChoices(value: unknown, selected: TitleModelRoute): CatalogChoice[] {\n const envelope = value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined\n // Host remote calls resolve to a result envelope ({ ok, value }); accept the bare catalog too.\n const root = (envelope?.ok === true && envelope.value && typeof envelope.value === 'object' && !Array.isArray(envelope.value)\n ? envelope.value as Record<string, unknown>\n : undefined) ?? envelope ?? {}\n const groups = Array.isArray(root.groups) ? root.groups : []\n const choices: CatalogChoice[] = []\n for (const group of groups) {\n if (!group || typeof group !== 'object') continue\n const row = group as Record<string, unknown>\n const provider = typeof row.id === 'string' ? row.id : ''\n const providerName = typeof row.name === 'string' && row.name ? row.name : provider\n if (!provider || !Array.isArray(row.models)) continue\n for (const model of row.models) {\n if (!model || typeof model !== 'object') continue\n const item = model as Record<string, unknown>\n const id = typeof item.id === 'string' ? item.id : ''\n if (!id) continue\n const name = typeof item.name === 'string' && item.name ? item.name : id\n const reasoning = item.reasoning && typeof item.reasoning === 'object' ? item.reasoning as Record<string, unknown> : undefined\n const efforts = Array.isArray(reasoning?.efforts)\n ? reasoning.efforts.flatMap(effort => {\n if (!effort || typeof effort !== 'object') return []\n const entry = effort as Record<string, unknown>\n return typeof entry.id === 'string' && entry.id ? [{ id: entry.id, name: typeof entry.name === 'string' && entry.name ? entry.name : entry.id }] : []\n })\n : []\n choices.push({ provider, model: id, label: `${providerName} / ${name}`, efforts })\n }\n }\n if (selected.provider && selected.model && !choices.some(item => item.provider === selected.provider && item.model === selected.model)) {\n choices.push({ provider: selected.provider, model: selected.model, label: `${selected.provider} / ${selected.model}`, efforts: [] })\n }\n return choices\n}\n\nexport function TitleSettings(props: {\n client: Client\n marker: { active: boolean }\n}) {\n const seat = useNativeSeat(props.client)\n const sessionId = seat.sessionId\n const text = titleCopy[seat.locale]\n const [status, setStatus] = useState<TitleStatus>()\n const [busy, setBusy] = useState(false)\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n // undefined = not edited; '' is a deliberate clear (built-in instruction).\n const [prompt, setPrompt] = useState<string | undefined>(undefined)\n const [choices, setChoices] = useState<CatalogChoice[]>([])\n const workRef = useRef<TitleClientWork>(undefined)\n if (!workRef.current) workRef.current = createTitleClientWork()\n const work = workRef.current\n const busyRef = useRef(busy)\n busyRef.current = busy\n\n const call: TitleClientCall = (endpoint, payload = {}) => (\n props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload)\n )\n\n function commitMarker(next: TitleStatus | undefined) {\n applyMarkerFromStatus(props.marker, next, true)\n }\n\n useEffect(() => () => { work.dispose() }, [work])\n\n useEffect(() => {\n const catalog = props.client.remote?.session?.modelCatalog\n if (!catalog) return undefined\n let live = true\n void catalog().then(value => {\n if (live) setChoices(catalogChoices(value, status?.settings.model ?? { provider: '', model: '' }))\n }).catch(() => { if (live) setChoices([]) })\n return () => { live = false }\n }, [props.client, status?.settings.model.provider, status?.settings.model.model])\n\n useEffect(() => {\n const generation = work.beginLoad()\n const isCurrent = () => work.isLoad(generation)\n setBusy(false)\n setError('')\n setNote('')\n void runTitleStatusLoad({\n call,\n sessionId: sessionId || undefined,\n isCurrent,\n failedMessage: text.failed,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n return () => { if (work.isLoad(generation)) work.beginLoad() }\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n const refreshStatus = useCallback(() => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current }) || work.disposed) return\n const generation = work.captureLoad()\n void runTitleStatusLoad({\n call,\n sessionId: sessionId || undefined,\n isCurrent: () => work.isLoad(generation) && !shouldSkipTitleRefresh({ busy: busyRef.current }),\n failedMessage: text.failed,\n onStatus: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n setStatus(next)\n },\n onError: () => {},\n onMarker: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n commitMarker(next)\n },\n })\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n useFeatureRefresh(\n props.client,\n sessionId,\n refreshStatus,\n status?.session?.generating === true && !busy,\n Boolean(sessionId),\n )\n\n const savedPrompt = status?.settings.prompt ?? ''\n const savedModel = status?.settings.model ?? { provider: '', model: '' }\n const modelKey = savedModel.provider && savedModel.model ? `${savedModel.provider}\\u001f${savedModel.model}` : ''\n const title = status?.session?.title\n const pinned = status?.session?.pinned === true\n const weOwn = status?.support.weOwn === true\n const canRegenerate = Boolean(sessionId) && weOwn && !busy\n const selectedChoice = choices.find(item => item.provider === savedModel.provider && item.model === savedModel.model)\n const efforts = selectedChoice ? [...selectedChoice.efforts] : []\n if (selectedChoice && savedModel.reasoningEffort && !efforts.some(item => item.id === savedModel.reasoningEffort)) {\n efforts.push({ id: savedModel.reasoningEffort, name: savedModel.reasoningEffort })\n }\n\n function saveSettings(patch: { model?: TitleModelRoute; cadence?: TitleCadence }) {\n if (!status) return\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleSettingsSave({\n call,\n ...patch,\n expectedRevision: status.settings.revision,\n isCurrent: () => work.isRequest(token),\n savedMessage: text.saved,\n failedMessage: text.failed,\n onBusy: setBusy,\n onSettings: settings => setStatus(current => current ? { ...current, settings } : current),\n onNote: setNote,\n onError: setError,\n })\n }\n\n return <section className=\"current-title-settings ct-root dsh-ui-panel\" data-testid=\"current-title-settings\">\n {!status && !error ? <p role=\"status\" className=\"dsh-ui-hint\">{text.loading}</p> : null}\n {title ? <p translate=\"no\" className=\"dsh-ui-title dsh-ui-wrap\">{title}</p> : null}\n {pinned ? <p className=\"dsh-ui-meta\">{text.pinned}</p> : null}\n {status?.session?.generating ? <p role=\"status\" className=\"dsh-ui-hint\">{text.generating}</p> : null}\n {status && !weOwn ? <p role=\"status\" className=\"dsh-ui-hint\">{text.inactive}{status.support.limitation ? ` ${status.support.limitation}` : ''}</p> : null}\n {error ? <p role=\"alert\" className=\"dsh-ui-error dsh-ui-wrap\">{error}</p> : null}\n {note ? <p role=\"status\" className=\"dsh-ui-notice\">{note}</p> : null}\n <div className=\"dsh-ui-actions\">\n {sessionId ? <Button variant=\"outline\" size=\"md\" disabled={!canRegenerate}\n onClick={() => {\n if (!sessionId) return\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleRegenerateFlow({\n call,\n sessionId,\n isCurrent: () => work.isRequest(token),\n failedMessage: text.failed,\n onBusy: setBusy,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n }}>{text.regenerate}</Button> : null}\n </div>\n <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.prompt}</span>\n <textarea\n className=\"ct-prompt\"\n value={status ? promptFieldValue(prompt, savedPrompt) : ''}\n maxLength={4000}\n rows={5}\n disabled={busy || !status}\n onChange={event => { setPrompt(event.target.value); setNote('') }}\n onBlur={() => {\n if (!status) return\n const next = promptToSave(prompt, savedPrompt)\n if (next === undefined) { setPrompt(undefined); return }\n const token = work.beginRequest()\n setError('')\n void runTitleSettingsSave({\n call,\n prompt: next,\n expectedRevision: status.settings.revision,\n isCurrent: () => work.isRequest(token),\n savedMessage: text.saved,\n failedMessage: text.failed,\n onBusy: setBusy,\n onSettings: settings => { setStatus(current => current ? { ...current, settings } : current); setPrompt(undefined) },\n onNote: setNote,\n onError: setError,\n })\n }}\n />\n <span className=\"dsh-ui-help\">{text.promptHint}</span>\n </label>\n <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.model}</span>\n <select\n className=\"dsh-ui-select\"\n value={modelKey}\n disabled={busy || !status}\n onChange={event => {\n const value = event.target.value\n const choice = choices.find(item => `${item.provider}\\u001f${item.model}` === value)\n saveSettings({\n model: choice ? { provider: choice.provider, model: choice.model } : { provider: '', model: '' },\n })\n }}\n >\n <option value=\"\">{text.modelDefault}</option>\n {choices.map(choice => (\n <option key={`${choice.provider}\\u001f${choice.model}`} value={`${choice.provider}\\u001f${choice.model}`}>{choice.label}</option>\n ))}\n </select>\n </label>\n {selectedChoice && efforts.length > 0 ? <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.effort}</span>\n <select\n className=\"dsh-ui-select\"\n value={savedModel.reasoningEffort ?? ''}\n disabled={busy || !status}\n onChange={event => {\n const effort = event.target.value\n const model: TitleModelRoute = { provider: savedModel.provider, model: savedModel.model }\n saveSettings({ model: effort ? { ...model, reasoningEffort: effort } : model })\n }}\n >\n <option value=\"\">{text.effortDefault}</option>\n {efforts.map(effort => <option key={effort.id} value={effort.id}>{effort.name}</option>)}\n </select>\n </label> : null}\n <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.cadence}</span>\n <select\n className=\"dsh-ui-select\"\n value={status?.settings.cadence ?? 'all-prompts'}\n disabled={busy || !status}\n onChange={event => {\n saveSettings({ cadence: event.target.value === 'first-prompt' ? 'first-prompt' : 'all-prompts' })\n }}\n >\n <option value=\"all-prompts\">{text.cadenceAll}</option>\n <option value=\"first-prompt\">{text.cadenceFirst}</option>\n </select>\n </label>\n </section>\n}\n\n/* The contract owns every type tier, the field rhythm, the focus ring and the\n * select shell. The only geometry left here is this panel's own: its reading\n * width, and the prompt box — the one control the primitives do not ship, which\n * borrows the select's 34px / 0.5px l4 / radius-md shell at a taller size. */\nconst styles = `${officialUiCss('ct-root')}\n.ct-root { max-width: 760px; }\n.ct-prompt {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n min-height: 96px;\n resize: vertical;\n padding: 8px 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.ct-prompt:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.ct-prompt::placeholder { color: var(--dsw-alias-label-dimmed); }\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshCurrentTitleClient: { active: boolean } }\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n const marker = createTitleClientMarker()\n ctx.provide(TITLE_CLIENT_SERVICE, marker)\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', name)\n style.textContent = styles\n document.head.appendChild(style)\n return () => style.remove()\n }, 'current-title.styles')\n ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register(\n { name: 'plugins.bundle.config', key: '@klarkxy/dsh-current-title' },\n // A slot component never receives `ctx`: the host composes its own props, and a\n // Cordis context throws on any undeclared property read (so feeding one back\n // through `useNativeSeat` crashed the entry and abdicated the keyed cell).\n // The client and marker stay in the apply closure instead.\n () => <TitleSettings client={client} marker={marker} />,\n )), 'current-title.settings')\n ctx.effect(() => {\n let live = true\n void client.connection.rpc.call(RPC_CHANNEL, 'status', {}).then(result => {\n const row = result as RpcResult<TitleStatus>\n if (!live) return\n applyMarkerFromStatus(marker, row?.ok ? row.value : undefined, live)\n }).catch(() => { if (live) applyMarkerFromStatus(marker, undefined, live) })\n return () => { live = false; disposeTitleClientMarker(marker) }\n }, 'current-title.marker')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.inner.cjs","names":["useSyncExternalStore","useCallback","useRef","useState","useRef","useCallback","Button"],"sources":["../../dsh-plugin-kit/src/client-utils.ts","../../dsh-plugin-kit/src/official-ui.ts","../src/contracts.ts","../src/client-work.ts","../src/marker.ts","../src/client.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useSyncExternalStore } from 'react'\n\n/** Fixed pause for failing background reads; manual work is never replayed. */\nexport function createPluginReadGate(now: () => number = Date.now) {\n let pausedUntil = 0\n let epoch = 0\n return {\n canRead: () => now() >= pausedUntil,\n reset: () => { epoch++; pausedUntil = 0 },\n async run<T>(read: () => Promise<T>): Promise<T> {\n const current = epoch\n try {\n const value = await read()\n if (current === epoch) pausedUntil = 0\n return value\n } catch (error) {\n // The native Connection error is an Error with this exact HTTP text.\n // Authentication, application failures, and cancellation stay distinct.\n const message = error instanceof Error ? error.message : ''\n if (current === epoch && (/(?:^|\\s)transport failure for .+: HTTP (?:404|405|503)\\b/.test(message)\n || (error instanceof TypeError && /^(?:Failed to fetch|fetch failed|NetworkError when attempting to fetch resource\\.?)$/i.test(message)))) {\n pausedUntil = now() + 30_000\n }\n throw error\n }\n },\n }\n}\n\nexport interface NativeSurfaceClient {\n sessions: {\n binding?(sessionId: string): { eventSource: { subscribe(listener: () => void): () => void } } | undefined\n }\n uiWorkspace: { current?: { getSnapshot(): { sessionId: string } | undefined; subscribe(listener: () => void): () => void } }\n uiSession: { adapter: { current: { getSnapshot(): { key?: string }; subscribe(listener: () => void): () => void } } }\n locale: { getSnapshot(): { active: string }; subscribe(listener: () => void): () => void }\n connection?: { generation?: { subscribe(listener: () => void): () => void } }\n}\n\n/** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */\nexport function selectedSessionId(client: Pick<NativeSurfaceClient, 'uiWorkspace' | 'uiSession'>): string {\n const workspace = client.uiWorkspace?.current\n return workspace\n ? workspace.getSnapshot()?.sessionId ?? ''\n : client.uiSession.adapter.current.getSnapshot().key ?? ''\n}\n\n/**\n * Owner props are data the host composed, never a Cordis context: reading an\n * undeclared property off one throws instead of returning undefined, which\n * would crash the slot entry and abdicate its cell for good. Tolerate a\n * throwing read so a mistaken prop degrades to \"not supplied\".\n */\nfunction read(source: unknown, key: string): unknown {\n if (source === null || typeof source !== 'object') return undefined\n try {\n return (source as Record<string, unknown>)[key]\n } catch {\n return undefined\n }\n}\n\nfunction readString(source: unknown, key: string): string | undefined {\n const value = read(source, key)\n return typeof value === 'string' ? value : undefined\n}\n\n/** Owner props win; native settings only supplies close, so resolve its selected session. */\nexport function useNativeSeat(client: NativeSurfaceClient, props?: unknown) {\n const current = useSyncExternalStore(\n useCallback((fn: () => void) => (client.uiWorkspace?.current ?? client.uiSession.adapter.current).subscribe(fn), [client]),\n useCallback(() => selectedSessionId(client), [client]),\n () => '',\n )\n const language = useSyncExternalStore(\n useCallback((fn: () => void) => client.locale.subscribe(fn), [client]),\n useCallback(() => client.locale.getSnapshot().active, [client]),\n () => 'en',\n )\n const sessionId = readString(props, 'sessionId') ?? readString(read(props, 'owner'), 'sessionId') ?? current\n const requestedLocale = read(props, 'locale') ?? read(read(props, 'owner'), 'locale') ?? language\n return { sessionId, locale: (String(requestedLocale).startsWith('zh') ? 'zh' : 'en') as 'zh' | 'en',\n hidden: read(props, 'hidden') === true || read(read(props, 'owner'), 'hidden') === true }\n}\n\n/** Refresh on native log boundaries/reconnect/focus. Read-only settling is bounded to an observed job. */\nexport function useFeatureRefresh(\n client: NativeSurfaceClient, sessionId: string, refresh: () => void,\n working = false, enabled = true,\n): void {\n const refreshRef = useRef(refresh)\n refreshRef.current = refresh\n useEffect(() => {\n if (!enabled) return\n let timer: ReturnType<typeof setTimeout> | undefined\n const queue = () => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n clearTimeout(timer)\n timer = setTimeout(() => refreshRef.current(), 150)\n }\n const source = sessionId ? client.sessions.binding?.(sessionId)?.eventSource : undefined\n const stopEvents = source?.subscribe(queue)\n const stopConnection = client.connection?.generation?.subscribe(queue)\n const visibility = () => { if (document.visibilityState === 'visible') queue() }\n window.addEventListener('focus', queue)\n document.addEventListener('visibilitychange', visibility)\n // Details are collapsed by default; opening an existing panel must get current state.\n document.addEventListener('toggle', queue, true)\n return () => {\n clearTimeout(timer)\n stopEvents?.(); stopConnection?.()\n window.removeEventListener('focus', queue)\n document.removeEventListener('visibilitychange', visibility)\n document.removeEventListener('toggle', queue, true)\n }\n }, [client, sessionId, enabled])\n useEffect(() => {\n if (!enabled || !working) return\n let delay = 250\n const until = Date.now() + 300_000\n let timer: ReturnType<typeof setTimeout>\n const tick = () => {\n if (Date.now() >= until) return\n if (document.visibilityState !== 'hidden') refreshRef.current()\n delay = Math.min(delay * 2, 2000)\n timer = setTimeout(tick, delay)\n }\n timer = setTimeout(tick, delay)\n return () => clearTimeout(timer)\n }, [client, sessionId, working, enabled])\n}\n","/**\n * Shared contract that keeps every plugin's browser-side UI on the official\n * DeepSeek Harness Web design language.\n *\n * Two rules produce that language, and both are load-bearing here:\n *\n * 1. Colour, radius, elevation and focus come from the host theme's real\n * `--dsw-*` tokens, written under their own names. Plugins never invent a\n * token, never alias the official ones behind a private palette (a private\n * alias is just a second, diverging theme), and never carries a literal\n * fallback — the host publishes light and dark, and a literal would pin one\n * of them. The only non-colour custom properties used are the host's own\n * content-font axis and frame clearance.\n *\n * 2. Anything the host already ships is used, not reimplemented. Controls come\n * from `@deepseek-ai/dsh-client-ui-primitives` (`Button`, `Input`,\n * `Checkbox`, `Switch`, `Tag`, `Pill`, `SegmentedControl`, `Menu`, `Modal`,\n * `Tooltip`, `Toast`, `DisclosureRow`, `StateDot`, `PathLabel`, the settings\n * form suite). This module only styles what primitives do not cover: page\n * scaffolding, field layout, banners, empty states and scroll regions.\n *\n * The metrics below are transcribed from the primitives' own CSS modules so a\n * feature panel lines up pixel-for-pixel with a native one: the 14/22 body and\n * 13/20 compact type tiers, the 0.5px hairline scale, and the elevation family\n * that draws a surface's edge in its shadow (`border: 0`) instead of a border.\n */\n\n/**\n * Every `--dsw-*` token this repo is allowed to reference, grouped by role.\n *\n * Plugins may only colour through this list. It is exported so the guard test\n * can fail a build when a stylesheet reaches for anything else — the failure\n * mode this prevents is silent: an unknown token resolves to nothing, so a\n * border disappears or a label inherits the wrong colour with no error anywhere.\n */\nexport const OFFICIAL_THEME_TOKENS = {\n /** Surfaces, from the page up to the topmost nested card. */\n surface: [\n '--dsw-alias-bg-base',\n '--dsw-alias-bg-layer-1',\n '--dsw-alias-bg-layer-2',\n '--dsw-alias-bg-layer-3',\n '--dsw-alias-bg-layer-4',\n '--dsw-alias-bg-module-platform',\n '--dsw-alias-bg-overlay',\n ],\n /** Hairlines. l1 is near-invisible on a menu surface, so menus use l2+. */\n border: ['--dsw-alias-border-l1', '--dsw-alias-border-l2', '--dsw-alias-border-l3', '--dsw-alias-border-l4'],\n /** Text. `caption` is menu shortcut text, `dimmed` is placeholder text. */\n label: [\n '--dsw-alias-label-primary',\n '--dsw-alias-label-secondary',\n '--dsw-alias-label-tertiary',\n '--dsw-alias-label-caption',\n '--dsw-alias-label-dimmed',\n '--dsw-alias-label-error',\n '--dsw-alias-label-primary-foreground',\n ],\n /** Interactive fills. The `-danger` hover belongs to destructive rows. */\n interactive: [\n '--dsw-alias-interactive-bg-hover',\n '--dsw-alias-interactive-bg-active',\n '--dsw-alias-interactive-bg-hover-danger',\n ],\n /** Accent and status. `business` is the focus ring's default colour. */\n accent: [\n '--dsw-alias-brand-primary',\n '--dsw-alias-button-primary-fill',\n '--dsw-alias-button-primary-hover',\n '--dsw-alias-button-tool-bar-fill',\n '--dsw-alias-button-tool-bar-hover',\n '--dsw-alias-button-ghost-active-fill',\n '--dsw-alias-button-ghost-active-border',\n ],\n state: [\n '--dsw-alias-state-business-primary',\n '--dsw-alias-state-success-primary',\n '--dsw-alias-state-warn-primary',\n '--dsw-alias-state-error-primary',\n '--dsw-alias-state-idle-primary',\n ],\n /** Corner scale: sm 8, md 12, lg the large card, panel the modal. */\n radius: ['--dsw-radius-sm', '--dsw-radius-md', '--dsw-radius-lg', '--dsw-radius-panel'],\n /** An elevated surface draws its edge in the shadow, so it keeps border: 0. */\n elevation: [\n '--dsw-elevation-soft',\n '--dsw-elevation-stroke',\n '--dsw-elevation-stroke-color',\n '--dsw-elevation-panel',\n '--dsw-elevation-prominent',\n ],\n /** Floats, masks and scrollbars. */\n overlay: [\n '--dsw-menu-surface-fill',\n '--dsw-menu-backdrop-filter',\n '--dsw-mask-blur',\n '--dsw-alias-bg-mask-1',\n '--dsw-alias-menu-icon',\n '--dsw-alias-scrollbar-bg-l2',\n '--dsw-alias-scrollbar-hover-l2',\n '--dsw-shadow-lv3',\n ],\n /** Motion, focus and type axis, published by the host rather than by a component. */\n system: [\n '--dsw-focus-ring-width',\n '--dsw-focus-ring-color',\n '--dsw-font-markdown-code-font-family',\n '--ds-transition-duration',\n '--ds-ease-in-out',\n '--ds-font-family-code',\n '--dsh-scrollbar-thumb',\n '--dsh-scrollbar-thumb-hover',\n '--dsh-content-font-size-secondary',\n '--dsh-content-font-delta',\n '--dsh-frame-top-clearance',\n ],\n} as const\n\n/** Every official token name, flat. Used by the token guard test. */\nexport const OFFICIAL_THEME_TOKEN_NAMES: readonly string[] = Object.values(OFFICIAL_THEME_TOKENS).flat()\n\n/** The elevation steps a surface can be raised by, softest first. */\nexport type OfficialElevation = 'soft' | 'stroke' | 'panel' | 'prominent'\n\n/**\n * The host's focus ring shorthand, verbatim. Writing this per control is how\n * rings drift apart; a stylesheet that draws its own focus style should use\n * {@link officialFocus} instead. The colour fallback is the host's own default.\n */\nexport const OFFICIAL_FOCUS_RING =\n 'var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))'\n\n/**\n * A complete `outline` declaration at the official geometry. `offset` defaults\n * to the 2px the native controls use; the host's inline field rules sit at 1px\n * and a segmented tab pulls the ring inside itself at -2px.\n */\nexport function officialFocus(offset = '2px'): string {\n return `outline: ${OFFICIAL_FOCUS_RING}; outline-offset: ${offset}`\n}\n\n/**\n * An elevated surface. The host draws a raised surface's edge inside its\n * shadow rather than as a border, so a card sets `border: 0` and takes the edge\n * from the elevation — which is also why its border stays off the alias-border\n * set that a flat, non-elevated rule would use.\n */\nexport function officialElevation(level: OfficialElevation): string {\n return `border: 0; box-shadow: var(--dsw-elevation-${level})`\n}\n\n/**\n * An elevated surface whose edge should read as a specific hairline. Rebinding\n * the stroke colour is how a menu card picks l1 while a panel picks l3, without\n * the two growing apart by hand.\n */\nexport function officialStrokedElevation(level: OfficialElevation, color: string): string {\n return `--dsw-elevation-stroke-color: ${color}; ${officialElevation(level)}`\n}\n\n/**\n * The shared stylesheet for a plugin UI, scoped under that plugin's root class.\n *\n * Scoping is what keeps this safe to always-bundle into every client: the rules\n * can only match inside the plugin's own subtree, so two plugins can both mount\n * `dsh-ui-card` without either styling the other's markup.\n *\n * Each recipe matches the root element *and* its descendants, because the\n * commonest arrangement is one element that is both — a surface that carries\n * the root class and `dsh-ui-card`, or a portaled dialog that is the root and\n * the `dsh-ui-surface`. A descendant-only scope would silently leave those\n * unstyled, with no error anywhere.\n *\n * A caveat worth knowing: `Modal` and `Menu` portal to `document.body`, so their\n * content leaves the plugin's subtree entirely. A portaled surface therefore\n * needs its own root class on an element inside the portal.\n *\n * Only patterns that primitives do not provide live here. If a control appears\n * below that `Button`/`Input`/`Switch`/`Tag`/`Menu` already covers, that is a\n * bug in this file: use the primitive and delete the recipe.\n */\nexport function officialUiCss(roots: string | readonly string[]): string {\n // One plugin often mounts several unrelated surfaces (a settings seat, a chat\n // card, a header menu), so the caller names every root. The rules below are\n // nested under a single selector list and use `&`, which the browser expands\n // per root — so one stylesheet covers all of them without duplicating itself.\n const scope = (typeof roots === 'string' ? [roots] : roots).map(root => `.${root}`).join(', ')\n const sheet = `\n/* Official DSH Web UI contract. Generated by @klarkxy/dsh-plugin-kit/official-ui.\n * Do not hand-edit the copy inside a plugin: change this module so every plugin\n * moves together. Scope: ${scope} */\n/* The scope rule below stays open for the whole sheet: every rule after it\n * nests with the parent selector, so one stylesheet can cover several unrelated\n * roots without leaking into a neighbouring plugin. Its closing brace is last. */\n${scope} {\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n min-width: 0;\n\n& *, & *::before, & *::after { box-sizing: border-box; }\n& h1, & h2, & h3, & h4, & p, & figure { margin: 0; }\n/* Keyboard focus only: pointer input keeps the native resting appearance. The\n * ring needs no radius of its own — the outline already follows the control's\n * own border-radius, and overriding it here would flatten every control. */\n& :focus-visible { ${officialFocus()}; }\n& [hidden] { display: none !important; }\n\n/* --- Type tiers. The same 14/22 and 13/20 steps the primitives use. --- */\n& .dsh-ui-title { font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-heading { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-compact { font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-meta { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-error { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-warn { color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-success { color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-muted { color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n& .dsh-ui-wrap { min-width: 0; overflow-wrap: anywhere; }\n\n/* --- Layout scaffolding. --- */\n& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }\n& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }\n& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n& .dsh-ui-spacer { flex: 1; min-width: 0; }\n/* A 0.5px l2 rule is the host's section divider; reserve the same rhythm. */\n& .dsh-ui-divider { height: 0.5px; background: var(--dsw-alias-border-l2); }\n& .dsh-ui-section { display: flex; flex-direction: column; gap: 12px; padding-top: 16px; border-top: 0.5px solid var(--dsw-alias-border-l2); }\n\n/* --- Card: a raised surface whose edge lives in the shadow. --- */\n& .dsh-ui-card {\n ${officialElevation('stroke')}\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n min-width: 0;\n}\n& .dsh-ui-card--flat { border: 0.5px solid var(--dsw-alias-border-l3); box-shadow: none; }\n& .dsh-ui-card--nested { background: var(--dsw-alias-bg-layer-2); }\n& .dsh-ui-card--plain { background: none; }\n\n/* --- Field: label, control, help, error. The control itself is an\n * official primitive, so this only owns the vertical rhythm. --- */\n& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }\n& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }\n& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-help p { margin: 0; }\n& .dsh-ui-help p + p { margin-top: 8px; }\n& .dsh-ui-required { color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-control { width: 100%; min-width: 0; }\n/* An invalid control is marked on the control, not only in the message. */\n& .dsh-ui-control[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-readonly { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-readonly > dt { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-readonly > dd { margin: 0; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }\n\n/* --- Buttons row. A no-op container: it exists so actions line up on the\n * trailing edge the way every native panel does. --- */\n& .dsh-ui-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 4px; }\n& .dsh-ui-actions-end { justify-content: flex-end; }\n\n/* --- Banners. A banner is a left-rail notice, the shape used for warnings,\n * deprecations and blocking instructions. --- */\n& .dsh-ui-banner {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px 14px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-left: 3px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-banner-title { font-weight: 500; color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-banner--info { border-left-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-banner--danger { border-left-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-banner--success { border-left-color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-banner p { margin: 0; }\n\n/* --- Inline notice: a transient confirmation with no chrome of its own. --- */\n& .dsh-ui-notice { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-notice--error { color: var(--dsw-alias-state-error-primary); }\n\n/* --- Empty and loading states. Both sit in a dashed well so an empty panel\n * reads as \"nothing here yet\" rather than as a broken layout. --- */\n& .dsh-ui-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n padding: 20px 16px;\n border: 0.5px dashed var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-loading { display: flex; align-items: center; gap: 8px; padding: 20px 0; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-secondary); }\n\n/* --- Selectable list. A row is a button-sized target with a hover fill and\n * a selected fill; the name carries the weight, the description does not. --- */\n& .dsh-ui-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n& .dsh-ui-list-scroll { max-height: min(66vh, 760px); overflow-y: auto; overflow-x: hidden; }\n& .dsh-ui-list-row { border-radius: var(--dsw-radius-md); }\n& .dsh-ui-list-row:hover { background: var(--dsw-alias-interactive-bg-hover); }\n& .dsh-ui-list-row[aria-selected='true'], & .dsh-ui-list-row[data-selected] { background: var(--dsw-alias-interactive-bg-active); }\n& .dsh-ui-list-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n min-width: 0;\n padding: 10px 12px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n& .dsh-ui-list-item:disabled { cursor: default; }\n& .dsh-ui-list-item:disabled:hover { background: none; }\n& .dsh-ui-list-name { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); overflow-wrap: anywhere; }\n& .dsh-ui-list-desc { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n\n/* --- Code and structured output. Wraps rather than scrolls, because a\n * feature panel is read rather than scanned. --- */\n& .dsh-ui-code {\n padding: 10px 12px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code, ui-monospace, 'Cascadia Mono', Consolas, monospace);\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n& .dsh-ui-scroll { max-height: 60vh; overflow: auto; overscroll-behavior: contain; }\n\n/* --- A toggle row: label on the left, switch on the trailing edge. This is\n * layout only; the switch itself is the official primitive. --- */\n& .dsh-ui-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-width: 0; padding: 12px 0; }\n& .dsh-ui-toggle-row + .dsh-ui-toggle-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n& .dsh-ui-toggle-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-toggle-label { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Floating surface: a panel anchored to a trigger. This is the material\n * a menu card is made of — the translucent fill plus its backdrop blur, with\n * the edge riding inside the prominent elevation. A plugin that hand-rolls this\n * is how tokens like --dsw-specific-menu get invented; use this instead. --- */\n& .dsh-ui-surface {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n position: relative;\n display: flex;\n flex-direction: column;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-menu-surface-fill);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n box-shadow: var(--dsw-elevation-prominent);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n line-height: 20px;\n min-width: 0;\n}\n& .dsh-ui-surface-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; overflow-y: auto; }\n& .dsh-ui-surface-head { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-surface-title { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Native select. The primitives ship no select, so a plugin that offers a\n * closed list of choices keeps the platform control and matches the official\n * settings field geometry exactly (34px, 0.5px l4, radius-md, layer-3). A\n * SegmentedControl is the primitive to reach for when the choices are few\n * enough to show at once. --- */\n& .dsh-ui-select {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n& .dsh-ui-select:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* Long panels scroll inside themselves instead of growing the host page. */\n& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n& .dsh-ui-panel-wide { max-width: 100%; }\n\n@media (prefers-reduced-motion: reduce) {\n & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }\n}\n}\n`\n // Widen every recipe from \"a descendant of the root\" to \"the root, or one of\n // its descendants\". Written as a transform rather than by hand so no recipe\n // can be added later with only the descendant form. The pattern is narrow on\n // purpose: a leading `&` followed by one recipe class and no combinator, so\n // sibling and child rules such as `.dsh-ui-field + .dsh-ui-field` keep their\n // own meaning and are left alone.\n return sheet.replace(/^& (\\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className: string) =>\n `&${className}, & ${className}`)\n}\n","/** Browser-safe contracts. Shared RPC/result types stay on @klarkxy/dsh-plugin-kit. */\nexport type { RpcResult } from '@klarkxy/dsh-plugin-kit/contracts'\n\nexport const PLUGIN_NAME = '@klarkxy/dsh-current-title'\nexport const FEATURE_ID = 'current-title'\nexport const PROVIDER_ID = '@klarkxy/dsh-current-title'\nexport const PURPOSE_ID = 'current-title.generate'\nexport const RPC_CHANNEL = '/dsh-current-title'\nexport const TITLE_CLIENT_SERVICE = 'dshCurrentTitleClient'\nexport const PROMPT_VERSION = 'current-title.v2'\nexport const SCHEMA_VERSION = 'title-json.v1'\nexport const CONTRACT_VERSION = 1\nexport const SETTINGS_KEY = 'current'\nexport const MAX_PROMPT_CHARS = 4000\n\nexport const DEFAULT_MAX_RECENT_MESSAGES = 8\nexport const DEFAULT_TARGET_WORDS = 5\nexport const DEFAULT_TARGET_CJK = 10\nexport const DEFAULT_MAX_INPUT_BYTES = 4096\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 256\nexport const DEFAULT_TIMEOUT_MS = 60_000\nexport const DEFAULT_MAX_TITLE_BYTES = 80\n\nexport type TitleLocaleMode = 'auto' | 'zh' | 'en'\nexport type TitleSourceKind = 'fallback' | 'provider' | 'user'\n/** Automatic generation cadence: every eligible message, or only the first. */\nexport type TitleCadence = 'all-prompts' | 'first-prompt'\n\nexport interface TitleMessage {\n readonly seq: number\n readonly text: string\n}\n\nexport interface TitleSnapshot {\n readonly title: string\n readonly messageSeqs: readonly number[]\n readonly source: { readonly kind: TitleSourceKind; readonly provider?: string }\n readonly eventSeq: number\n readonly updatedAt: number\n}\n\n/** Empty provider and model means the shared weak role. Both must be set together. */\nexport interface TitleModelRoute {\n provider: string\n model: string\n reasoningEffort?: string\n}\n\nexport interface TitleSettings {\n revision: number\n locale: TitleLocaleMode\n /** Empty keeps the built-in title instruction. */\n prompt: string\n model: TitleModelRoute\n cadence: TitleCadence\n}\n\nexport interface TitleSupport {\n nativeOwner: string | null\n weOwn: boolean\n limitation?: string\n}\n\nexport interface TitleStatus {\n settings: TitleSettings\n support: TitleSupport\n session?: {\n sessionId: string\n title?: string\n sourceKind?: TitleSourceKind\n generating: boolean\n pinned: boolean\n }\n}\n\nexport interface TitleClientMarker {\n active: boolean\n}\n\nexport interface GenerateConfig {\n readonly maxRecentMessages: number\n readonly locale: TitleLocaleMode\n readonly targetWords: number\n readonly targetCjkCharacters: number\n readonly maxInputBytes: number\n readonly maxOutputTokens: number\n readonly timeoutMs: number\n readonly maxTitleBytes: number\n}\n\nexport function defaultModelRoute(): TitleModelRoute {\n return { provider: '', model: '' }\n}\n\nexport function defaultSettings(locale: TitleLocaleMode = 'auto'): TitleSettings {\n return { revision: 0, locale, prompt: '', model: defaultModelRoute(), cadence: 'all-prompts' }\n}\n\nexport function normalizeCadence(value: unknown): TitleCadence {\n return value === 'first-prompt' ? 'first-prompt' : 'all-prompts'\n}\n\nexport function normalizePrompt(value: unknown): string {\n if (typeof value !== 'string') return ''\n return value.replace(/\\u0000/gu, '').trim().slice(0, MAX_PROMPT_CHARS)\n}\n\nexport function normalizeModelRoute(value: unknown): TitleModelRoute {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return defaultModelRoute()\n const route = value as Record<string, unknown>\n const provider = typeof route.provider === 'string' ? route.provider.trim() : ''\n const model = typeof route.model === 'string' ? route.model.trim() : ''\n const effort = typeof route.reasoningEffort === 'string' ? route.reasoningEffort.trim() : ''\n if (!provider || !model || provider.length > 250 || model.length > 250) return defaultModelRoute()\n return effort && effort.length <= 80 ? { provider, model, reasoningEffort: effort } : { provider, model }\n}\n\nexport function defaultGenerateConfig(locale: TitleLocaleMode = 'auto'): GenerateConfig {\n return {\n maxRecentMessages: DEFAULT_MAX_RECENT_MESSAGES,\n locale,\n targetWords: DEFAULT_TARGET_WORDS,\n targetCjkCharacters: DEFAULT_TARGET_CJK,\n maxInputBytes: DEFAULT_MAX_INPUT_BYTES,\n maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxTitleBytes: DEFAULT_MAX_TITLE_BYTES,\n }\n}\n\nexport function isTitleLocaleMode(value: unknown): value is TitleLocaleMode {\n return value === 'auto' || value === 'zh' || value === 'en'\n}\n","import type { RpcResult, TitleCadence, TitleModelRoute, TitleStatus } from './contracts.ts'\n\nexport const titleCopy = {\n zh: {\n label: '自动标题',\n pinned: '已手动命名',\n generating: '正在生成标题…',\n regenerate: '重新生成',\n locale: '类型标签语言',\n auto: '自动',\n prompt: '标题提示词',\n promptHint: '留空用内置说明,仍返回类型和摘要;离开输入框即保存。',\n loading: '正在读取标题设置…',\n model: '标题模型',\n modelDefault: '跟随会话模型',\n cadence: '更新节奏',\n cadenceAll: '跟随当前任务(每条消息)',\n cadenceFirst: '仅首条消息',\n saved: '已保存。',\n failed: '无法读取标题设置。',\n inactive: '标题服务未接管,新消息暂时不会自动更新。',\n },\n en: {\n label: 'Auto Title',\n pinned: 'Renamed manually',\n generating: 'Generating title…',\n regenerate: 'Regenerate',\n locale: 'Type-label language',\n auto: 'Auto',\n prompt: 'Title prompt',\n promptHint: 'Empty uses the built-in instruction; a type and summary are still returned. Saves on blur.',\n loading: 'Loading title settings…',\n model: 'Title model',\n modelDefault: 'Use the session model',\n cadence: 'Update cadence',\n cadenceAll: 'Track the current task (every message)',\n cadenceFirst: 'First message only',\n saved: 'Saved.',\n failed: 'Could not read title settings.',\n inactive: 'Title generation is not active, so new messages will not rename this session.',\n },\n} as const\n\nexport function settingsCopy(locale: 'zh' | 'en') {\n return titleCopy[locale] ?? titleCopy.zh\n}\n\n/** `undefined` draft = not edited; an empty string is a real edit (use built-in instruction). */\nexport function promptFieldValue(draft: string | undefined, saved: string): string {\n return draft ?? saved\n}\n\n/** The prompt to persist on blur, or `undefined` when nothing changed. */\nexport function promptToSave(draft: string | undefined, saved: string): string | undefined {\n if (draft === undefined) return undefined\n const next = draft.trim()\n return next === saved ? undefined : next\n}\n\nexport function shouldSkipTitleRefresh(input: { busy: boolean }): boolean {\n return input.busy\n}\n\nexport function createTitleClientWork() {\n let generation = 0\n let request = 0\n let disposed = false\n return {\n get disposed() { return disposed },\n beginLoad() {\n generation += 1\n request += 1\n return generation\n },\n captureLoad() {\n return generation\n },\n beginRequest() {\n request += 1\n return { generation, request }\n },\n isLoad(generationToken: number) {\n return !disposed && generation === generationToken\n },\n isRequest(token: { generation: number; request: number }) {\n return !disposed && generation === token.generation && request === token.request\n },\n dispose() {\n disposed = true\n generation += 1\n request += 1\n },\n }\n}\n\nexport type TitleClientWork = ReturnType<typeof createTitleClientWork>\nexport type TitleClientCall = (endpoint: string, payload?: unknown) => Promise<unknown>\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\n\nasync function invoke<T>(call: TitleClientCall, endpoint: string, payload?: unknown): Promise<T> {\n return unwrap(await call(endpoint, payload) as RpcResult<T>)\n}\n\nexport async function runTitleStatusLoad(input: {\n call: TitleClientCall\n sessionId?: string\n isCurrent: () => boolean\n failedMessage: string\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n try {\n const status = await invoke<TitleStatus>(\n input.call,\n 'status',\n input.sessionId ? { sessionId: input.sessionId } : {},\n )\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch {\n if (!input.isCurrent()) return\n input.onMarker(undefined)\n input.onError(input.failedMessage)\n }\n}\n\nexport async function runTitleRegenerateFlow(input: {\n call: TitleClientCall\n sessionId: string\n isCurrent: () => boolean\n failedMessage: string\n onBusy: (busy: boolean) => void\n onStatus: (status: TitleStatus) => void\n onError: (message: string) => void\n onMarker: (status: TitleStatus | undefined) => void\n}): Promise<void> {\n if (!input.sessionId || !input.isCurrent()) return\n input.onBusy(true)\n try {\n await invoke(input.call, 'regenerate', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n const status = await invoke<TitleStatus>(input.call, 'status', { sessionId: input.sessionId })\n if (!input.isCurrent()) return\n input.onStatus(status)\n input.onMarker(status)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n\nexport async function runTitleSettingsSave(input: {\n call: TitleClientCall\n prompt?: string\n model?: TitleModelRoute\n cadence?: TitleCadence\n expectedRevision: number\n isCurrent: () => boolean\n savedMessage: string\n failedMessage: string\n onBusy: (busy: boolean) => void\n onSettings: (settings: TitleStatus['settings']) => void\n onNote: (note: string) => void\n onError: (message: string) => void\n}): Promise<void> {\n input.onBusy(true)\n try {\n const settings = await invoke<TitleStatus['settings']>(input.call, 'settings', {\n ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),\n ...(input.model !== undefined ? { model: input.model } : {}),\n ...(input.cadence !== undefined ? { cadence: input.cadence } : {}),\n expectedRevision: input.expectedRevision,\n })\n if (!input.isCurrent()) return\n input.onSettings(settings)\n input.onNote(input.savedMessage)\n } catch (cause) {\n if (!input.isCurrent()) return\n input.onError(cause instanceof Error ? cause.message : input.failedMessage)\n } finally {\n if (!input.isCurrent()) return\n input.onBusy(false)\n }\n}\n","import type { TitleClientMarker, TitleStatus } from './contracts.ts'\n\nexport function createTitleClientMarker(): TitleClientMarker {\n return { active: false }\n}\n\nexport function applyMarkerFromStatus(marker: TitleClientMarker, status: Pick<TitleStatus, 'support'> | undefined, live: boolean): void {\n if (!live) return\n marker.active = status?.support.weOwn === true\n}\n\nexport function disposeTitleClientMarker(marker: TitleClientMarker): void {\n marker.active = false\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { NativeSurfaceClient } from '@klarkxy/dsh-plugin-kit/client-utils'\nimport { createPluginReadGate, useFeatureRefresh, useNativeSeat } from '@klarkxy/dsh-plugin-kit/client-utils'\nimport { Button } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { officialUiCss } from '@klarkxy/dsh-plugin-kit/official-ui'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { RPC_CHANNEL, TITLE_CLIENT_SERVICE, type RpcResult, type TitleCadence, type TitleModelRoute, type TitleStatus } from './contracts.ts'\nimport {\n createTitleClientWork, promptFieldValue, promptToSave, runTitleRegenerateFlow, runTitleSettingsSave, runTitleStatusLoad,\n shouldSkipTitleRefresh, titleCopy, type TitleClientCall, type TitleClientWork,\n} from './client-work.ts'\nimport { applyMarkerFromStatus, createTitleClientMarker, disposeTitleClientMarker } from './marker.ts'\n\nexport const name = 'dsh-current-title-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.session', 'sessions', 'locale', 'uiWorkspace', 'uiSession'] as const\nexport { createTitleClientMarker, disposeTitleClientMarker, applyMarkerFromStatus }\n\ntype Client = NativeSurfaceClient & {\n connection: NonNullable<NativeSurfaceClient['connection']> & {\n rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> }\n }\n remote?: { session?: { modelCatalog?: () => Promise<unknown> } }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; key: string }, render: unknown): () => void\n }\n}\n\ninterface CatalogChoice {\n provider: string\n model: string\n label: string\n}\n\nfunction catalogChoices(value: unknown, selected: TitleModelRoute): CatalogChoice[] {\n const envelope = value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined\n // Host remote calls resolve to a result envelope ({ ok, value }); accept the bare catalog too.\n const root = (envelope?.ok === true && envelope.value && typeof envelope.value === 'object' && !Array.isArray(envelope.value)\n ? envelope.value as Record<string, unknown>\n : undefined) ?? envelope ?? {}\n const groups = Array.isArray(root.groups) ? root.groups : []\n const choices: CatalogChoice[] = []\n for (const group of groups) {\n if (!group || typeof group !== 'object') continue\n const row = group as Record<string, unknown>\n const provider = typeof row.id === 'string' ? row.id : ''\n const providerName = typeof row.name === 'string' && row.name ? row.name : provider\n if (!provider || !Array.isArray(row.models)) continue\n for (const model of row.models) {\n if (!model || typeof model !== 'object') continue\n const item = model as Record<string, unknown>\n const id = typeof item.id === 'string' ? item.id : ''\n if (!id) continue\n const name = typeof item.name === 'string' && item.name ? item.name : id\n choices.push({ provider, model: id, label: `${providerName} / ${name}` })\n }\n }\n if (selected.provider && selected.model && !choices.some(item => item.provider === selected.provider && item.model === selected.model)) {\n choices.push({ provider: selected.provider, model: selected.model, label: `${selected.provider} / ${selected.model}` })\n }\n return choices\n}\n\nexport function TitleSettings(props: {\n client: Client\n marker: { active: boolean }\n}) {\n const seat = useNativeSeat(props.client)\n const sessionId = seat.sessionId\n const text = titleCopy[seat.locale]\n const [status, setStatus] = useState<TitleStatus>()\n const [busy, setBusy] = useState(false)\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n // undefined = not edited; '' is a deliberate clear (built-in instruction).\n const [prompt, setPrompt] = useState<string | undefined>(undefined)\n const [choices, setChoices] = useState<CatalogChoice[]>([])\n const workRef = useRef<TitleClientWork>(undefined)\n if (!workRef.current) workRef.current = createTitleClientWork()\n const work = workRef.current\n const readGateRef = useRef<ReturnType<typeof createPluginReadGate>>(undefined)\n if (!readGateRef.current) readGateRef.current = createPluginReadGate()\n const readGate = readGateRef.current\n const busyRef = useRef(busy)\n busyRef.current = busy\n\n const call: TitleClientCall = (endpoint, payload = {}) => (\n props.client.connection.rpc.call(RPC_CHANNEL, endpoint, payload)\n )\n const readCall: TitleClientCall = (endpoint, payload) => readGate.run(() => call(endpoint, payload))\n\n function commitMarker(next: TitleStatus | undefined) {\n applyMarkerFromStatus(props.marker, next, true)\n }\n\n useEffect(() => () => { readGate.reset(); work.dispose() }, [work, readGate])\n useEffect(() => props.client.connection.generation?.subscribe(() => {\n readGate.reset()\n work.beginLoad()\n busyRef.current = false\n setBusy(false)\n }), [props.client, work, readGate])\n\n useEffect(() => {\n const catalog = props.client.remote?.session?.modelCatalog\n if (!catalog) return undefined\n let live = true\n void catalog().then(value => {\n if (live) setChoices(catalogChoices(value, status?.settings.model ?? { provider: '', model: '' }))\n }).catch(() => { if (live) setChoices([]) })\n return () => { live = false }\n }, [props.client, status?.settings.model.provider, status?.settings.model.model])\n\n useEffect(() => {\n const generation = work.beginLoad()\n readGate.reset()\n const isCurrent = () => work.isLoad(generation)\n setBusy(false)\n setError('')\n setNote('')\n void runTitleStatusLoad({\n call: readCall,\n sessionId: sessionId || undefined,\n isCurrent,\n failedMessage: text.failed,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n return () => { if (work.isLoad(generation)) work.beginLoad() }\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n const refreshStatus = useCallback(() => {\n if (!readGate.canRead() || shouldSkipTitleRefresh({ busy: busyRef.current }) || work.disposed) return\n readGate.reset()\n const token = work.beginRequest()\n void runTitleStatusLoad({\n call: readCall,\n sessionId: sessionId || undefined,\n isCurrent: () => work.isRequest(token) && !shouldSkipTitleRefresh({ busy: busyRef.current }),\n failedMessage: text.failed,\n onStatus: next => {\n if (shouldSkipTitleRefresh({ busy: busyRef.current })) return\n setStatus(next)\n setError('')\n },\n onError: setError,\n onMarker: next => {\n if (!next || shouldSkipTitleRefresh({ busy: busyRef.current })) return\n commitMarker(next)\n },\n })\n }, [props.client, props.marker, sessionId, text.failed, work])\n\n useFeatureRefresh(\n props.client,\n sessionId,\n refreshStatus,\n status?.session?.generating === true && !busy,\n Boolean(sessionId),\n )\n\n const savedPrompt = status?.settings.prompt ?? ''\n const savedModel = status?.settings.model ?? { provider: '', model: '' }\n const modelKey = savedModel.provider && savedModel.model ? `${savedModel.provider}\\u001f${savedModel.model}` : ''\n const title = status?.session?.title\n const pinned = status?.session?.pinned === true\n const weOwn = status?.support.weOwn === true\n const canRegenerate = Boolean(sessionId) && weOwn && !busy\n\n function saveSettings(patch: { model?: TitleModelRoute; cadence?: TitleCadence }) {\n if (!status) return\n readGate.reset()\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleSettingsSave({\n call,\n ...patch,\n expectedRevision: status.settings.revision,\n isCurrent: () => work.isRequest(token),\n savedMessage: text.saved,\n failedMessage: text.failed,\n onBusy: setBusy,\n onSettings: settings => setStatus(current => current ? { ...current, settings } : current),\n onNote: setNote,\n onError: setError,\n })\n }\n\n return <section className=\"current-title-settings ct-root dsh-ui-panel\" data-testid=\"current-title-settings\">\n {!status && !error ? <p role=\"status\" className=\"dsh-ui-hint\">{text.loading}</p> : null}\n {title ? <p translate=\"no\" className=\"dsh-ui-title dsh-ui-wrap\">{title}</p> : null}\n {pinned ? <p className=\"dsh-ui-meta\">{text.pinned}</p> : null}\n {status?.session?.generating ? <p role=\"status\" className=\"dsh-ui-hint\">{text.generating}</p> : null}\n {status && !weOwn ? <p role=\"status\" className=\"dsh-ui-hint\">{text.inactive}{status.support.limitation ? ` ${status.support.limitation}` : ''}</p> : null}\n {error ? <>\n <p role=\"alert\" className=\"dsh-ui-error dsh-ui-wrap\">{error}</p>\n <Button variant=\"outline\" size=\"sm\" disabled={busy} onClick={() => { readGate.reset(); refreshStatus() }}>\n {seat.locale === 'zh' ? '重试' : 'Retry'}\n </Button>\n </> : null}\n {note ? <p role=\"status\" className=\"dsh-ui-notice\">{note}</p> : null}\n <div className=\"dsh-ui-actions\">\n {sessionId ? <Button variant=\"outline\" size=\"md\" disabled={!canRegenerate}\n onClick={() => {\n if (!sessionId) return\n readGate.reset()\n const token = work.beginRequest()\n setError('')\n setNote('')\n void runTitleRegenerateFlow({\n call,\n sessionId,\n isCurrent: () => work.isRequest(token),\n failedMessage: text.failed,\n onBusy: setBusy,\n onStatus: setStatus,\n onError: setError,\n onMarker: commitMarker,\n })\n }}>{text.regenerate}</Button> : null}\n </div>\n <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.prompt}</span>\n <textarea\n className=\"ct-prompt\"\n value={status ? promptFieldValue(prompt, savedPrompt) : ''}\n maxLength={4000}\n rows={5}\n disabled={busy || !status}\n onChange={event => { setPrompt(event.target.value); setNote('') }}\n onBlur={() => {\n if (!status) return\n const next = promptToSave(prompt, savedPrompt)\n if (next === undefined) { setPrompt(undefined); return }\n readGate.reset()\n const token = work.beginRequest()\n setError('')\n void runTitleSettingsSave({\n call,\n prompt: next,\n expectedRevision: status.settings.revision,\n isCurrent: () => work.isRequest(token),\n savedMessage: text.saved,\n failedMessage: text.failed,\n onBusy: setBusy,\n onSettings: settings => { setStatus(current => current ? { ...current, settings } : current); setPrompt(undefined) },\n onNote: setNote,\n onError: setError,\n })\n }}\n />\n <span className=\"dsh-ui-help\">{text.promptHint}</span>\n </label>\n <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.model}</span>\n <select\n className=\"dsh-ui-select\"\n value={modelKey}\n disabled={busy || !status}\n onChange={event => {\n const value = event.target.value\n const choice = choices.find(item => `${item.provider}\\u001f${item.model}` === value)\n saveSettings({\n model: choice ? { provider: choice.provider, model: choice.model } : { provider: '', model: '' },\n })\n }}\n >\n <option value=\"\">{text.modelDefault}</option>\n {choices.map(choice => (\n <option key={`${choice.provider}\\u001f${choice.model}`} value={`${choice.provider}\\u001f${choice.model}`}>{choice.label}</option>\n ))}\n </select>\n </label>\n <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">{text.cadence}</span>\n <select\n className=\"dsh-ui-select\"\n value={status?.settings.cadence ?? 'all-prompts'}\n disabled={busy || !status}\n onChange={event => {\n saveSettings({ cadence: event.target.value === 'first-prompt' ? 'first-prompt' : 'all-prompts' })\n }}\n >\n <option value=\"all-prompts\">{text.cadenceAll}</option>\n <option value=\"first-prompt\">{text.cadenceFirst}</option>\n </select>\n </label>\n </section>\n}\n\n/* The contract owns every type tier, the field rhythm, the focus ring and the\n * select shell. The only geometry left here is this panel's own: its reading\n * width, and the prompt box — the one control the primitives do not ship, which\n * borrows the select's 34px / 0.5px l4 / radius-md shell at a taller size. */\nconst styles = `${officialUiCss('ct-root')}\n.ct-root { max-width: 760px; }\n.ct-prompt {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n min-height: 96px;\n resize: vertical;\n padding: 8px 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.ct-prompt:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.ct-prompt::placeholder { color: var(--dsw-alias-label-dimmed); }\n`\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context { dshCurrentTitleClient: { active: boolean } }\n}\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n const marker = createTitleClientMarker()\n ctx.provide(TITLE_CLIENT_SERVICE, marker)\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', name)\n style.textContent = styles\n document.head.appendChild(style)\n return () => style.remove()\n }, 'current-title.styles')\n ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register(\n { name: 'plugins.bundle.config', key: '@klarkxy/dsh-current-title' },\n // A slot component never receives `ctx`: the host composes its own props, and a\n // Cordis context throws on any undeclared property read (so feeding one back\n // through `useNativeSeat` crashed the entry and abdicated the keyed cell).\n // The client and marker stay in the apply closure instead.\n () => <TitleSettings client={client} marker={marker} />,\n )), 'current-title.settings')\n ctx.effect(() => {\n let live = true\n void client.connection.rpc.call(RPC_CHANNEL, 'status', {}).then(result => {\n const row = result as RpcResult<TitleStatus>\n if (!live) return\n applyMarkerFromStatus(marker, row?.ok ? row.value : undefined, live)\n }).catch(() => { if (live) applyMarkerFromStatus(marker, undefined, live) })\n return () => { live = false; disposeTitleClientMarker(marker) }\n }, 'current-title.marker')\n}\n"],"mappings":"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"}
|