@logictan/dsh-easyrewrite 2.7.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/client.js +333 -444
  2. package/package.json +12 -1
package/lib/client.js CHANGED
@@ -10,6 +10,7 @@ window.__ModuleLoader__.load({
10
10
  factory: function (require) {
11
11
  var React = require("react");
12
12
  var Primitives = require("@deepseek-ai/dsh-client-ui-primitives");
13
+ var UI = require("@logictan/dsh-plugins-shared-client");
13
14
 
14
15
  /**
15
16
  * 取第一个可用的图标导出。
@@ -1592,7 +1593,7 @@ window.__ModuleLoader__.load({
1592
1593
  errNoBoundary: "该消息之前没有可截断的闭合回合边界(截断/首条消息无法撤回或编辑)",
1593
1594
  errTurnOpen: "该消息所在回合尚未结束,请等待回复完成后再操作",
1594
1595
  errGeneric: "操作失败,请重试",
1595
- resetNotice: "对话处于半截状态,已重置——正在回到上一次模型回复处(或空白新对话)",
1596
+ resetNotice: "该消息之前没有可保留的历史,已重置——修改后的内容将作为新对话的第一条发出",
1596
1597
  turnOpenNotice: "回复仍在生成中,请等待回复完成后再撤回。",
1597
1598
  sectionUpdate: "更新",
1598
1599
  currentVersion: "当前版本",
@@ -1685,7 +1686,7 @@ window.__ModuleLoader__.load({
1685
1686
  errNoBoundary: "No truncation boundary before this message (first/truncated message cannot be recalled or edited)",
1686
1687
  errTurnOpen: "This message's turn is still running; wait for the reply to finish",
1687
1688
  errGeneric: "Operation failed, please retry",
1688
- resetNotice: "The conversation was in a truncated state and has been reset — returning to the last model reply (or a blank conversation)",
1689
+ resetNotice: "There is no earlier history to keep, so the conversation was reset — your edit will be sent as the first message of a new conversation",
1689
1690
  turnOpenNotice: "A reply is still being generated. Please wait for it to finish before recalling.",
1690
1691
  sectionUpdate: "Update",
1691
1692
  currentVersion: "Current version",
@@ -1778,7 +1779,7 @@ window.__ModuleLoader__.load({
1778
1779
  errNoBoundary: "このメッセージの前に切り詰め境界がありません(切り詰め後・最初のメッセージは撤回/編集できません)",
1779
1780
  errTurnOpen: "このメッセージのターンはまだ終了していません。返信完了後にお試しください",
1780
1781
  errGeneric: "操作に失敗しました。もう一度お試しください",
1781
- resetNotice: "会話が途中で切れた状態のためリセットしました——最後のモデル返信(または空白の会話)に戻ります",
1782
+ resetNotice: "このメッセージより前の履歴がないためリセットしました——編集内容は新しい会話の最初のメッセージとして送信されます",
1782
1783
  turnOpenNotice: "返信がまだ生成中です。返信が完了してから取り消してください",
1783
1784
  sectionUpdate: "更新",
1784
1785
  currentVersion: "現在のバージョン",
@@ -1851,19 +1852,7 @@ window.__ModuleLoader__.load({
1851
1852
  /** 设置卡片:注册进 plugins.row.config(设置 → 插件 → 插件配置)。
1852
1853
  * 插件页对每个配置项渲染两次:view==='summary' 取行标题下的一行摘要,view==='page' 取完整表单。 */
1853
1854
  function EasyRewriteSettingsCard(props) {
1854
- /**
1855
- * 是否由外部容器提供卡片外壳。
1856
- *
1857
- * 0.1.7 的插件页(plugins.item)自己画行外壳、标题取自插槽 label,卡片再画一层头部
1858
- * 就成了嵌套折叠;旧插槽 settings.plugin.item 没有外壳,卡片必须自画。由挂载方经
1859
- * inject 面传入,默认 false,保持旧行为。
1860
- */
1861
- var embedded = !!(props && props.embedded);
1862
1855
  var L = useUILocaleDict();
1863
- // embedded 时头部不渲染,但「展开时检查更新」这类 side effect 仍要照跑,故初始即展开。
1864
- var openState = React.useState(embedded);
1865
- var open = openState[0];
1866
- var setOpen = openState[1];
1867
1856
  // 控件状态(初始化自 localStorage)
1868
1857
  var sRewrite = React.useState(rewriteOnClick());
1869
1858
  var rewrite = sRewrite[0];
@@ -1948,10 +1937,10 @@ window.__ModuleLoader__.load({
1948
1937
  }
1949
1938
  }).catch(function () { setUpdateUpdating(false); setUpdateMsg(L.updateFailed); });
1950
1939
  }
1951
- // 展开折叠时无感触发一次检查(5 分钟节流,防频繁展开刷请求);
1952
- // 每日检查开关开启时,即使不展开也会按天自动检测
1940
+ // 卡片加载时无感触发一次检查(5 分钟节流,防频繁刷新刷请求);
1941
+ // 每日检查开关开启时,即使不打开也会按天自动检测
1953
1942
  React.useEffect(function () {
1954
- if (!open) return;
1943
+ if (props && props.view === "summary") return;
1955
1944
  var now = Date.now();
1956
1945
  var lastCheck = 0;
1957
1946
  try { lastCheck = parseInt(localStorage.getItem("dsh-easyrewrite:lastUpdateCheckTs") || "0", 10) || 0; } catch (e) { /* ignore */ }
@@ -1959,7 +1948,7 @@ window.__ModuleLoader__.load({
1959
1948
  try { localStorage.setItem("dsh-easyrewrite:lastUpdateCheckTs", String(now)); } catch (e) { /* ignore */ }
1960
1949
  if (!updateVer) setUpdateVer("…");
1961
1950
  doCheckUpdate();
1962
- }, [open]);
1951
+ }, [props && props.view]);
1963
1952
  // 每日检测:开关开启时每天首次触发一次(不依赖展开)
1964
1953
  React.useEffect(function () {
1965
1954
  var autoOn = getBool("dsh-easyrewrite:autoCheckUpdate", false);
@@ -2025,417 +2014,331 @@ window.__ModuleLoader__.load({
2025
2014
  var origImg = sOrigImg[0];
2026
2015
  var setOrigImg = sOrigImg[1];
2027
2016
 
2028
- // 官方 PluginCard 同款:卡片/展开态/头部/标题/描述/箭头/内容区
2029
- var cardStyle = {
2030
- border: "1px solid var(--dsw-alias-border-l2)",
2031
- background: "var(--dsw-alias-bg-layer-3)",
2032
- borderRadius: "12px",
2033
- listStyle: "none",
2034
- transition: "border-color .16s, background .16s"
2035
- };
2036
- var cardOpenStyle = { background: "var(--dsw-alias-bg-layer-2)", borderColor: "var(--dsw-alias-label-dimmed)" };
2037
- var headStyle = {
2038
- appearance: "none",
2039
- width: "100%",
2040
- font: "inherit",
2041
- color: "inherit",
2042
- textAlign: "left",
2043
- cursor: "pointer",
2044
- background: "transparent",
2045
- border: "none",
2046
- borderRadius: "12px",
2047
- display: "flex",
2048
- alignItems: "center",
2049
- gap: "12px",
2050
- padding: "14px 16px"
2051
- };
2052
- var headTextStyle = { display: "flex", flexDirection: "column", flex: "1", minWidth: "0", gap: "4px" };
2053
- var titleStyle = { color: "var(--dsw-alias-label-primary)", fontSize: "15px", fontWeight: 600, lineHeight: "1.4" };
2054
- var subStyle = { color: "var(--dsw-alias-label-tertiary)", fontSize: "13px", lineHeight: "1.5" };
2055
- var chevronStyle = { color: "var(--dsw-alias-label-tertiary)", flex: "none", transition: "transform .16s", transform: "rotate(90deg)" };
2056
- var chevronOpenStyle = { transform: "rotate(270deg)" };
2057
- var bodyStyle = {
2058
- borderTop: "1px solid var(--dsw-alias-border-l2)",
2059
- margin: "0 16px",
2060
- paddingTop: "14px",
2061
- paddingBottom: "8px",
2062
- display: "flex",
2063
- flexDirection: "column",
2064
- gap: "16px"
2065
- };
2066
- // 大项分组:组内 10px,组间 16px(bodyStyle gap);每级缩进 4 空格(16px)
2067
- var sectionStyle = { display: "flex", flexDirection: "column", gap: "10px", paddingLeft: "16px" };
2068
- var groupTitleStyle = {
2069
- fontSize: "14px",
2070
- fontWeight: 600,
2071
- color: "var(--dsw-alias-label-primary)",
2072
- letterSpacing: "0.02em",
2073
- lineHeight: "1.6"
2074
- };
2075
- var rowStyle = { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "12px", paddingLeft: "16px" };
2076
- var labelStyle = { fontSize: "13px", color: "var(--dsw-alias-label-primary)" };
2077
- var hintStyle = { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)" };
2078
- var groupStyle = { display: "flex", flexDirection: "column", gap: "6px", paddingLeft: "16px" };
2079
- var inputStyle = {
2080
- width: "90px",
2081
- border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.3))",
2082
- borderRadius: "8px",
2083
- padding: "4px 8px",
2084
- fontSize: "13px",
2085
- background: "var(--dsw-alias-bg-base)",
2086
- color: "var(--dsw-alias-label-primary)"
2087
- };
2088
- var disabledInputStyle = Object.assign({}, inputStyle, { opacity: 0.45, cursor: "not-allowed" });
2089
- function switchRow(label, value, onChange, extraHint, disabled) {
2090
- // 圆形勾选框:选中 = 白底黑勾(与确认胶囊同设计语言);未选中 = 灰色圆环
2091
- var checkSize = 20;
2092
- var checkStyle = {
2093
- width: checkSize,
2094
- height: checkSize,
2095
- borderRadius: "50%",
2096
- border: "2px solid " + (value ? "#ffffff" : "var(--dsw-alias-border-l2, rgba(128,128,128,0.45))"),
2097
- background: value ? "#ffffff" : "transparent",
2098
- display: "flex",
2099
- alignItems: "center",
2100
- justifyContent: "center",
2101
- color: value ? "#000000" : "transparent",
2102
- fontSize: "13px",
2103
- lineHeight: "13px",
2104
- cursor: "pointer",
2105
- flex: "none",
2106
- margin: "0 2px",
2107
- transition: "border-color .15s, background .15s, color .15s",
2108
- userSelect: "none",
2109
- boxSizing: "border-box"
2110
- };
2111
- return React.createElement("div", {
2112
- style: Object.assign({}, rowStyle, disabled ? { opacity: 0.45, cursor: "not-allowed" } : null),
2113
- "data-dsh-easyrewrite": "switch-row",
2114
- title: disabled ? (extraHint || "") : undefined
2115
- },
2116
- React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "2px", flex: "1", minWidth: "0" } },
2117
- React.createElement("span", { style: labelStyle }, label),
2118
- extraHint ? React.createElement("span", { style: hintStyle }, extraHint) : null
2119
- ),
2120
- React.createElement("div", {
2121
- role: "checkbox",
2122
- "aria-checked": !!value,
2123
- "aria-disabled": disabled || undefined,
2124
- style: Object.assign({}, checkStyle, disabled ? { cursor: "not-allowed" } : null),
2125
- onClick: function (e) { e.stopPropagation(); if (disabled) return; onChange(!value); }
2126
- }, value ? React.createElement(IconCheckOutline, null) : null)
2017
+ if (props && props.view === "summary") return L.subtitle;
2018
+
2019
+ function sectionHead(title) {
2020
+ return React.createElement(
2021
+ "div",
2022
+ { key: "head-" + title, className: "dsp-card-title", style: { fontSize: "14px", fontWeight: 600, marginTop: "8px" } },
2023
+ title,
2127
2024
  );
2128
2025
  }
2129
- // Apple 风格分段控件:灰色药丸长条 + 白色小药丸高亮当前项(滑动过渡,主题自适应)
2130
- function segmentedGroup(options, value, onChange) {
2131
- var n = options.length;
2132
- var idx = 0;
2133
- for (var i = 0; i < n; i++) { if (options[i][0] === value) { idx = i; break; } }
2134
- var segStyle = {
2135
- position: "relative",
2136
- display: "flex",
2137
- background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.1))",
2138
- borderRadius: "999px",
2139
- padding: "2px"
2140
- };
2141
- var thumbStyle = {
2142
- position: "absolute",
2143
- top: "2px",
2144
- left: "calc(" + idx + " * (100% - 4px) / " + n + ")",
2145
- width: "calc((100% - 4px) / " + n + ")",
2146
- height: "calc(100% - 4px)",
2147
- background: "var(--dsw-alias-bg-layer-3, #ffffff)",
2148
- borderRadius: "999px",
2149
- boxShadow: "0 1px 2px rgba(0, 0, 0, 0.12)",
2150
- transition: "left .18s ease",
2151
- zIndex: 1
2152
- };
2153
- return React.createElement("div", { style: segStyle, role: "radiogroup" },
2154
- React.createElement("div", { style: thumbStyle, "data-dsh-easyrewrite": "seg-thumb" }),
2155
- options.map(function (opt) {
2156
- var sel = value === opt[0];
2157
- return React.createElement("div", {
2158
- key: opt[0],
2159
- role: "radio",
2160
- "aria-checked": sel,
2161
- style: {
2162
- position: "relative",
2163
- zIndex: 2,
2164
- flex: "1",
2165
- padding: "3px 10px",
2166
- textAlign: "center",
2167
- fontSize: "13px",
2168
- lineHeight: "20px",
2169
- cursor: "pointer",
2170
- borderRadius: "999px",
2171
- color: sel ? "var(--dsw-alias-label-primary)" : "var(--dsw-alias-label-secondary)",
2172
- transition: "color .15s",
2173
- whiteSpace: "nowrap",
2174
- userSelect: "none"
2175
- },
2176
- onClick: function () { onChange(opt[0]); }
2177
- }, opt[1]);
2178
- })
2026
+
2027
+ function sectionDivider(key) {
2028
+ return React.createElement("hr", {
2029
+ key: key,
2030
+ style: { border: "none", borderTop: "1px solid var(--dsw-alias-border-l2)", margin: "8px 0" },
2031
+ });
2032
+ }
2033
+
2034
+ function renderSwitch(label, value, onChange, extraHint, disabled) {
2035
+ return React.createElement(
2036
+ UI.Field,
2037
+ {
2038
+ key: label,
2039
+ inline: true,
2040
+ label: label,
2041
+ hint: extraHint || undefined,
2042
+ },
2043
+ React.createElement(UI.Switch, {
2044
+ checked: !!value,
2045
+ disabled: !!disabled,
2046
+ label: label,
2047
+ onCheckedChange: onChange,
2048
+ }),
2179
2049
  );
2180
2050
  }
2181
2051
 
2182
- // 配置主体:两种挂法共用。
2183
- //
2184
- // 0.1.7 起卡片挂进 plugins.item,页面已经给了行外壳(标题来自插槽 label、描述、
2185
- // 展开由页面管),卡片只该交出主体。自带 <li> + 可点头部会变成页面里多出来的一层
2186
- // 折叠 —— 列表上一个下拉,点进去还有一个。旧插槽 settings.plugin.item 没有外壳,
2187
- // 那种挂法仍旧要卡片自画,所以分流在函数末尾按 embedded 做。
2188
- var cardBody = React.createElement("div", { style: bodyStyle },
2189
- // —— 编辑 ——
2190
- React.createElement("div", { style: sectionStyle },
2191
- React.createElement("span", { style: groupTitleStyle }, L.sectionEdit),
2192
- switchRow(L.rewrite, rewrite, function (v) { setRewrite(v); setBool("dsh-easyrewrite:rewriteOnClick", v); }),
2193
- switchRow(L.editOffShowRecall, showRecall, function (v) {
2194
- setShowRecall(v); setBool("dsh-easyrewrite:editOffShowRecall", v);
2195
- }, rewrite ? L.lockedHint : null, rewrite),
2196
- // 编辑宽度:三固定 + 自定义(固定时输入框禁用置灰)
2197
- React.createElement("div", { style: groupStyle },
2198
- React.createElement("span", { style: labelStyle }, L.editWidth),
2199
- segmentedGroup([["compact", L.wCompact], ["standard", L.wStandard], ["extended", L.wExtended], ["custom", L.wCustom]], widthMode, function (v) { setWidthMode(v); setSetting("dsh-easyrewrite:editWidth", v); }),
2200
- React.createElement("div", { style: rowStyle },
2201
- React.createElement("span", { style: labelStyle }, L.customWidth),
2202
- React.createElement("input", {
2203
- type: "number",
2204
- min: 100,
2205
- max: 1200,
2206
- style: widthMode === "custom" ? inputStyle : disabledInputStyle,
2207
- disabled: widthMode !== "custom",
2208
- placeholder: L.placeholderCustom,
2209
- value: customW,
2210
- onChange: function (e) {
2211
- setCustomW(e.target.value);
2212
- setSetting("dsh-easyrewrite:editWidthCustom", e.target.value);
2213
- }
2214
- })
2215
- )
2216
- )
2052
+ var children = [
2053
+ // —— 编辑 ——
2054
+ sectionHead(L.sectionEdit),
2055
+ renderSwitch(L.rewrite, rewrite, function (v) { setRewrite(v); setBool("dsh-easyrewrite:rewriteOnClick", v); }),
2056
+ renderSwitch(L.editOffShowRecall, showRecall, function (v) {
2057
+ setShowRecall(v); setBool("dsh-easyrewrite:editOffShowRecall", v);
2058
+ }, rewrite ? L.lockedHint : null, rewrite),
2059
+ React.createElement(
2060
+ UI.Field,
2061
+ {
2062
+ key: "edit-width",
2063
+ label: L.editWidth,
2064
+ },
2065
+ React.createElement(UI.Segmented, {
2066
+ label: L.editWidth,
2067
+ value: widthMode,
2068
+ options: [
2069
+ { value: "compact", label: L.wCompact },
2070
+ { value: "standard", label: L.wStandard },
2071
+ { value: "extended", label: L.wExtended },
2072
+ { value: "custom", label: L.wCustom },
2073
+ ],
2074
+ onChange: function (v) { setWidthMode(v); setSetting("dsh-easyrewrite:editWidth", v); },
2075
+ }),
2076
+ ),
2077
+ React.createElement(
2078
+ UI.Field,
2079
+ {
2080
+ key: "custom-width",
2081
+ inline: true,
2082
+ label: L.customWidth,
2083
+ },
2084
+ React.createElement(UI.NumberField, {
2085
+ min: 100,
2086
+ max: 1200,
2087
+ disabled: widthMode !== "custom",
2088
+ placeholder: L.placeholderCustom,
2089
+ value: customW,
2090
+ onValueChange: function (v) {
2091
+ setCustomW(v);
2092
+ setSetting("dsh-easyrewrite:editWidthCustom", v);
2093
+ },
2094
+ }),
2095
+ ),
2096
+
2097
+ sectionDivider("div-recall"),
2098
+
2099
+ // —— 撤回 ——
2100
+ sectionHead(L.sectionRecall),
2101
+ renderSwitch(L.recallConfirm, confirmCapsule, function (v) { setConfirmCapsule(v); setBool("dsh-easyrewrite:recallConfirm", v); }),
2102
+ renderSwitch(L.showOriginalImages, origImg, function (v) { setOrigImg(v); setBool("dsh-easyrewrite:showOriginalImages", v); }),
2103
+ React.createElement(
2104
+ UI.Field,
2105
+ {
2106
+ key: "visual-mode",
2107
+ label: L.visualMode,
2108
+ },
2109
+ React.createElement(UI.Segmented, {
2110
+ label: L.visualMode,
2111
+ value: visual,
2112
+ options: [
2113
+ { value: "simple", label: L.visualSimple },
2114
+ { value: "minimal", label: L.visualMinimal },
2115
+ { value: "info", label: L.visualInfo },
2116
+ ],
2117
+ onChange: function (v) { setVisual(v); setSetting("dsh-easyrewrite:visualMode", v); },
2118
+ }),
2119
+ ),
2120
+ renderSwitch(L.statOnlyUser, statOnly, function (v) { setStatOnly(v); setBool("dsh-easyrewrite:statOnlyUser", v); }),
2121
+ renderSwitch(L.hotkeyEnable, hotkeyOn, function (v) {
2122
+ setHotkeyOn(v);
2123
+ setHotkeyEnabledSetting(v);
2124
+ if (!v) setRecording(false);
2125
+ }, L.hotkeyHint),
2126
+ React.createElement(
2127
+ UI.Field,
2128
+ {
2129
+ key: "hotkey-field",
2130
+ inline: true,
2131
+ label: L.hotkey + ":" + (hotkey ? formatHotkey(hotkey) : L.hotkeyNone),
2132
+ hint: recording ? L.hotkeyRecording : (hotkey ? undefined : L.hotkeyHint),
2133
+ error: hotkeyInvalid ? L.hotkeyInvalid : undefined,
2134
+ },
2135
+ React.createElement(
2136
+ UI.Button,
2137
+ {
2138
+ variant: "secondary",
2139
+ size: "sm",
2140
+ disabled: !hotkeyOn,
2141
+ onClick: function () { setHotkeyInvalid(false); setRecording(!recording); },
2142
+ },
2143
+ recording ? L.hotkeyRecording : L.hotkeyRecord,
2217
2144
  ),
2218
- // —— 撤回 ——
2219
- React.createElement("div", { style: sectionStyle },
2220
- React.createElement("span", { style: groupTitleStyle }, L.sectionRecall),
2221
- switchRow(L.recallConfirm, confirmCapsule, function (v) { setConfirmCapsule(v); setBool("dsh-easyrewrite:recallConfirm", v); }),
2222
- switchRow(L.showOriginalImages, origImg, function (v) { setOrigImg(v); setBool("dsh-easyrewrite:showOriginalImages", v); }),
2223
- // 视觉模式
2224
- React.createElement("div", { style: groupStyle },
2225
- React.createElement("span", { style: labelStyle }, L.visualMode),
2226
- segmentedGroup([["simple", L.visualSimple], ["minimal", L.visualMinimal], ["info", L.visualInfo]], visual, function (v) { setVisual(v); setSetting("dsh-easyrewrite:visualMode", v); })
2227
- ),
2228
- switchRow(L.statOnlyUser, statOnly, function (v) { setStatOnly(v); setBool("dsh-easyrewrite:statOnlyUser", v); }),
2229
- // 撤回快捷键:总开关(Beta,默认关——避免与其他插件快捷键打架)
2230
- switchRow(L.hotkeyEnable, hotkeyOn, function (v) {
2231
- setHotkeyOn(v);
2232
- setHotkeyEnabledSetting(v);
2233
- if (!v) setRecording(false);
2234
- }, L.hotkeyHint),
2235
- // 键位行:始终显示;总开关关闭时录制按钮禁用置灰
2236
- React.createElement("div", { style: rowStyle },
2237
- React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "2px" } },
2238
- React.createElement("span", { style: labelStyle }, L.hotkey + ":" + (hotkey ? formatHotkey(hotkey) : L.hotkeyNone)),
2239
- React.createElement("span", { style: hintStyle }, recording ? L.hotkeyRecording : (hotkey ? null : L.hotkeyHint)),
2240
- hotkeyInvalid ? React.createElement("span", { style: { fontSize: "11px", color: "var(--dsw-alias-label-error, #d9534f)" } }, L.hotkeyInvalid) : null
2145
+ ),
2146
+
2147
+ sectionDivider("div-composer"),
2148
+
2149
+ // —— 回填 ——
2150
+ sectionHead(L.sectionComposer),
2151
+ React.createElement(
2152
+ UI.Field,
2153
+ {
2154
+ key: "conflict-mode",
2155
+ label: L.conflictMode,
2156
+ hint: conflict === "merge" ? L.conflictMerge : L.conflictOverwrite,
2157
+ },
2158
+ React.createElement(UI.Segmented, {
2159
+ label: L.conflictMode,
2160
+ value: conflict,
2161
+ options: [
2162
+ { value: "overwrite", label: L.conflictOverwriteShort },
2163
+ { value: "merge", label: L.conflictMergeShort },
2164
+ ],
2165
+ onChange: function (v) { setConflict(v); setSetting("dsh-easyrewrite:conflictMode", v); },
2166
+ }),
2167
+ ),
2168
+
2169
+ sectionDivider("div-versions"),
2170
+
2171
+ // —— 版本 ——
2172
+ sectionHead(L.sectionVersions),
2173
+ React.createElement(
2174
+ "div",
2175
+ { key: "versions-group", style: { display: "flex", flexDirection: "column", gap: "6px" } },
2176
+ (function () {
2177
+ var families = listVersionFamilies(props.ctxSessions);
2178
+ if (families.length === 0) return React.createElement("span", { className: "dsp-field-hint" }, L.versionFamilyNone);
2179
+ var snap = null;
2180
+ try { snap = props.ctxSessions.list.getSnapshot(); } catch (e) { /* ignore */ }
2181
+ var metaOf = function (vid) { return (snap && snap.byId && snap.byId[vid]) || {}; };
2182
+ var famName = function (fam) {
2183
+ var best = null, bt = -1;
2184
+ fam.versions.forEach(function (vid) {
2185
+ var m = metaOf(vid); var tt = m.updatedAt || 0;
2186
+ if (tt >= bt) { bt = tt; best = m.title || null; }
2187
+ });
2188
+ return best || (fam.versions.length + " " + L.versionCount);
2189
+ };
2190
+ var fmtStamp = function (tsv) {
2191
+ if (!tsv) return "—";
2192
+ var dd = new Date(tsv);
2193
+ var p2 = function (x) { return (x < 10 ? "0" : "") + x; };
2194
+ return dd.getFullYear() + "-" + p2(dd.getMonth() + 1) + "-" + p2(dd.getDate()) + " " + p2(dd.getHours()) + ":" + p2(dd.getMinutes());
2195
+ };
2196
+ var chev = function (openState) {
2197
+ return React.createElement("svg", {
2198
+ width: "16", height: "16", viewBox: "0 0 24 24",
2199
+ style: { flex: "none", display: "block", color: "var(--dsw-alias-label-tertiary)", transform: openState ? "rotate(90deg)" : "rotate(0deg)", transition: "transform .12s" }
2200
+ }, React.createElement("path", { d: "M9 6l6 6-6 6", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }));
2201
+ };
2202
+ var rowHead = { display: "flex", alignItems: "center", gap: "8px", padding: "4px 8px", borderRadius: "6px" };
2203
+ var hdrRow = { display: "flex", alignItems: "center", gap: "6px", cursor: "pointer", padding: "4px 0" };
2204
+ return React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "4px" } },
2205
+ React.createElement("div", { style: hdrRow, onClick: function () { setHistOpen(!histOpen); } },
2206
+ chev(histOpen),
2207
+ React.createElement("span", { style: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)" } }, L.versionHistory),
2208
+ React.createElement("span", { style: { marginLeft: "auto" } }, React.createElement(UI.Tag, { mono: true }, families.length + ""))
2241
2209
  ),
2242
- React.createElement("button", {
2243
- type: "button",
2244
- disabled: !hotkeyOn,
2245
- style: {
2246
- appearance: "none",
2247
- border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.3))",
2248
- background: "transparent",
2249
- color: "var(--dsw-alias-label-secondary)",
2250
- borderRadius: "6px",
2251
- padding: "3px 10px",
2252
- fontSize: "12px",
2253
- cursor: hotkeyOn ? "pointer" : "not-allowed",
2254
- fontFamily: "inherit",
2255
- flex: "none",
2256
- opacity: hotkeyOn ? 1 : 0.45
2257
- },
2258
- onClick: function () { setHotkeyInvalid(false); setRecording(!recording); }
2259
- }, recording ? L.hotkeyRecording : L.hotkeyRecord)
2260
- )
2261
- ),
2262
- // —— 回填 ——
2263
- React.createElement("div", { style: sectionStyle },
2264
- React.createElement("span", { style: groupTitleStyle }, L.sectionComposer),
2265
- // 回填冲突模式
2266
- React.createElement("div", { style: groupStyle },
2267
- React.createElement("span", { style: labelStyle }, L.conflictMode),
2268
- segmentedGroup([["overwrite", L.conflictOverwriteShort], ["merge", L.conflictMergeShort]], conflict, function (v) { setConflict(v); setSetting("dsh-easyrewrite:conflictMode", v); }),
2269
- React.createElement("span", { style: hintStyle }, conflict === "merge" ? L.conflictMerge : L.conflictOverwrite)
2270
- )
2271
- ),
2272
- // —— 版本 ——
2273
- React.createElement("div", { style: sectionStyle },
2274
- React.createElement("span", { style: groupTitleStyle }, L.sectionVersions),
2275
- // 版本历史(三层折叠):总开关默认收起 → 按对话名的家族折叠项 → 条目显最后对话时间
2276
- // (官方无归档恢复入口,此处保留恢复并打开;review #6 后家族来自官方 lineage)
2277
- React.createElement("div", { style: groupStyle },
2278
- (function () {
2279
- var families = listVersionFamilies(props.ctxSessions);
2280
- if (families.length === 0) return React.createElement("span", { style: hintStyle }, L.versionFamilyNone);
2281
- var snap = null;
2282
- try { snap = props.ctxSessions.list.getSnapshot(); } catch (e) { /* ignore */ }
2283
- var metaOf = function (vid) { return (snap && snap.byId && snap.byId[vid]) || {}; };
2284
- var famName = function (fam) {
2285
- var best = null, bt = -1;
2286
- fam.versions.forEach(function (vid) {
2287
- var m = metaOf(vid); var tt = m.updatedAt || 0;
2288
- if (tt >= bt) { bt = tt; best = m.title || null; }
2289
- });
2290
- return best || (fam.versions.length + " " + L.versionCount);
2291
- };
2292
- var fmtStamp = function (tsv) {
2293
- if (!tsv) return "—";
2294
- var dd = new Date(tsv);
2295
- var p2 = function (x) { return (x < 10 ? "0" : "") + x; };
2296
- return dd.getFullYear() + "-" + p2(dd.getMonth() + 1) + "-" + p2(dd.getDate()) + " " + p2(dd.getHours()) + ":" + p2(dd.getMinutes());
2297
- };
2298
- // 折叠箭头:SVG 描边(官方图标同风格),像素级对齐、无字距
2299
- var chev = function (openState) {
2300
- return React.createElement("svg", {
2301
- width: "18", height: "18", viewBox: "0 0 24 24",
2302
- style: { flex: "none", display: "block", color: "var(--dsw-alias-label-tertiary)", transform: openState ? "rotate(90deg)" : "rotate(0deg)", transition: "transform .12s" }
2303
- }, React.createElement("path", { d: "M9 6l6 6-6 6", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }));
2304
- };
2305
- var rowHead = { display: "flex", alignItems: "center", gap: "6px", padding: "5px 4px", cursor: "pointer", borderRadius: "6px" };
2306
- var hdrRow = { display: "flex", alignItems: "center", cursor: "pointer" }; // 无 gap:SVG 箭头紧贴文字
2307
- // 层1:版本历史总折叠(默认收起)
2308
- return React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "2px" } },
2309
- React.createElement("div", { style: hdrRow, onClick: function () { setHistOpen(!histOpen); } },
2310
- chev(histOpen),
2311
- React.createElement("span", { style: { fontSize: "12px", color: "var(--dsw-alias-label-secondary)" } }, L.versionHistory),
2312
- React.createElement("span", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", marginLeft: "auto" } }, families.length + "")
2210
+ histOpen ? families.map(function (fam) {
2211
+ var famOpen = !!famOpenMap[fam.rootId];
2212
+ return React.createElement("div", { key: fam.rootId, style: { display: "flex", flexDirection: "column", gap: "2px", padding: "2px 0 2px 14px", borderTop: "1px solid var(--dsw-alias-border-l2)" } },
2213
+ React.createElement("div", { style: hdrRow, onClick: function () { var nm = {}; for (var ok2 in famOpenMap) nm[ok2] = famOpenMap[ok2]; nm[fam.rootId] = !famOpen; setFamOpenMap(nm); } },
2214
+ chev(famOpen),
2215
+ React.createElement("span", { style: { fontSize: "13px", color: "var(--dsw-alias-label-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: "1" } }, famName(fam)),
2216
+ React.createElement("span", { style: { marginLeft: "auto" } }, React.createElement(UI.Tag, null, fam.versions.length + " " + L.versionCount))
2313
2217
  ),
2314
- histOpen ? families.map(function (fam) {
2315
- var open = !!famOpenMap[fam.rootId];
2316
- return React.createElement("div", { key: fam.rootId, style: { display: "flex", flexDirection: "column", gap: "2px", padding: "2px 0 2px 12px", borderTop: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.14))" } },
2317
- React.createElement("div", { style: hdrRow, onClick: function () { var nm = {}; for (var ok2 in famOpenMap) nm[ok2] = famOpenMap[ok2]; nm[fam.rootId] = !open; setFamOpenMap(nm); } },
2318
- chev(open),
2319
- React.createElement("span", { style: { fontSize: "12px", color: "var(--dsw-alias-label-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: "1" } }, famName(fam)),
2320
- React.createElement("span", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", flex: "none", marginLeft: "auto" } }, fam.versions.length + " " + L.versionCount)
2321
- ),
2322
- open ? fam.versions.map(function (vid, vi) {
2323
- return React.createElement("div", { key: vid, style: rowHead },
2324
- React.createElement("span", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", fontVariantNumeric: "tabular-nums", flex: "none", width: "26px" } }, "v" + (vi + 1)),
2325
- React.createElement("span", { style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", fontVariantNumeric: "tabular-nums", flex: "1" } }, fmtStamp(metaOf(vid).updatedAt)),
2326
- React.createElement("button", {
2327
- type: "button",
2328
- style: { appearance: "none", border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.3))", background: "transparent", color: "var(--dsw-alias-label-secondary)", borderRadius: "6px", padding: "2px 8px", fontSize: "12px", cursor: "pointer", fontFamily: "inherit", flex: "none" },
2329
- onClick: function (ev) {
2330
- ev.stopPropagation();
2331
- fetch("/bubble/unarchive", {
2332
- method: "POST",
2333
- headers: { "content-type": "application/json" },
2334
- body: JSON.stringify({ sessionId: vid }),
2335
- keepalive: true
2336
- }).then(function () {
2337
- if (typeof props.openSession === "function") props.openSession(vid);
2338
- }).catch(function () { /* ignore */ });
2339
- }
2340
- }, L.versionRestoreOpen)
2341
- );
2342
- }) : null
2218
+ famOpen ? fam.versions.map(function (vid, vi) {
2219
+ return React.createElement("div", { key: vid, style: rowHead },
2220
+ React.createElement("span", { style: { fontSize: "12px", color: "var(--dsw-alias-label-tertiary)", fontVariantNumeric: "tabular-nums", flex: "none", width: "28px" } }, "v" + (vi + 1)),
2221
+ React.createElement("span", { style: { fontSize: "12px", color: "var(--dsw-alias-label-tertiary)", fontVariantNumeric: "tabular-nums", flex: "1" } }, fmtStamp(metaOf(vid).updatedAt)),
2222
+ React.createElement(UI.Button, {
2223
+ variant: "secondary",
2224
+ size: "sm",
2225
+ onClick: function (ev) {
2226
+ ev.stopPropagation();
2227
+ fetch("/bubble/unarchive", {
2228
+ method: "POST",
2229
+ headers: { "content-type": "application/json" },
2230
+ body: JSON.stringify({ sessionId: vid }),
2231
+ keepalive: true
2232
+ }).then(function () {
2233
+ if (typeof props.openSession === "function") props.openSession(vid);
2234
+ }).catch(function () { /* ignore */ });
2235
+ }
2236
+ }, L.versionRestoreOpen)
2343
2237
  );
2344
2238
  }) : null
2345
2239
  );
2346
- })()
2347
- )
2240
+ }) : null
2241
+ );
2242
+ })()
2243
+ ),
2244
+
2245
+ sectionDivider("div-update"),
2246
+
2247
+ // —— 更新 ——
2248
+ sectionHead(L.sectionUpdate),
2249
+ React.createElement(
2250
+ "div",
2251
+ { key: "updates-group", style: { display: "flex", flexDirection: "column", gap: "10px" } },
2252
+ React.createElement(
2253
+ UI.Field,
2254
+ {
2255
+ key: "check-update-field",
2256
+ inline: true,
2257
+ label: L.currentVersion + ":" + (updateVer || "…"),
2258
+ hint: updateMsg || undefined,
2259
+ },
2260
+ React.createElement(UI.Button, {
2261
+ variant: "secondary",
2262
+ size: "sm",
2263
+ loading: updateChecking,
2264
+ onClick: function () { doCheckUpdate(); },
2265
+ }, updateChecking ? L.checking : L.checkUpdate),
2348
2266
  ),
2349
- // —— 更新 ——
2350
- React.createElement("div", { style: sectionStyle },
2351
- React.createElement("span", { style: groupTitleStyle }, L.sectionUpdate),
2352
- // 更新检查与执行(精简版:手动检查 + 每日检测可选 + 有新版提示)
2353
- React.createElement("div", { style: groupStyle },
2354
- React.createElement("span", { style: labelStyle }, L.currentVersion + ":" + (updateVer || "…")),
2355
- (function () {
2356
- if (!dshVer) return null;
2357
- if (cmpDsh(dshVer, MIN_DSH_VERSION) < 0) return React.createElement("div", { key: "dsh-low", style: { display: "flex", flexDirection: "column", gap: "4px", padding: "6px 8px", background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.1))", borderRadius: "8px" } },
2358
- React.createElement("span", { style: { fontSize: "12px", lineHeight: "18px", color: "var(--dsw-alias-label-primary)" } }, L.dshLowWarning.replace("{cur}", dshVer).replace("{min}", MIN_DSH_VERSION)),
2359
- React.createElement("div", { style: { display: "flex", alignItems: "center", gap: "6px" } },
2360
- React.createElement("code", { style: { fontSize: "11px", color: "var(--dsw-alias-label-secondary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: "1" } }, "npm install -g @deepseek-ai/dsh@" + MIN_DSH_VERSION),
2361
- React.createElement("button", { type: "button", style: { appearance: "none", border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.3))", background: "transparent", color: "var(--dsw-alias-label-secondary)", borderRadius: "6px", padding: "2px 8px", fontSize: "11px", cursor: "pointer", fontFamily: "inherit", flex: "none" }, onClick: function () { try { legacyCopy("npm install -g @deepseek-ai/dsh@" + MIN_DSH_VERSION); } catch (eC1) { /* ignore */ } } }, L.copyUpgradeCmd)
2362
- )
2363
- );
2364
- if (cmpDsh(MAX_TESTED_DSH_VERSION, dshVer) < 0) return React.createElement("div", { key: "dsh-new", style: { padding: "6px 8px", fontSize: "12px", lineHeight: "18px", color: "var(--dsw-alias-label-secondary)", background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.08))", borderRadius: "8px" } }, L.dshNewNotice.replace("{cur}", dshVer));
2365
- return null;
2366
- })(),
2367
- !remindClosed && !getBool("dsh-easyrewrite:autoCheckUpdate", false) ? React.createElement("div", { key: "remind", style: { display: "flex", alignItems: "center", gap: "8px", padding: "6px 8px", background: "rgba(77,107,254,0.08)", borderRadius: "8px" } },
2368
- React.createElement("span", { style: { fontSize: "12px", lineHeight: "18px", color: "var(--dsw-alias-label-primary)", flex: "1", minWidth: "0" } }, L.suggestAutoCheck),
2369
- React.createElement("button", { type: "button", style: { appearance: "none", border: "none", background: "var(--dsw-static-deepseek-500, #4d6bfe)", color: "#ffffff", borderRadius: "6px", padding: "3px 10px", fontSize: "12px", cursor: "pointer", fontFamily: "inherit", flex: "none" }, onClick: function () { setBool("dsh-easyrewrite:autoCheckUpdate", true); setBool("dsh-easyrewrite:autoCheckReminded", true); setAutoCheckOn(true); setRemindClosed(true); } }, L.enableNow),
2370
- React.createElement("button", { type: "button", title: L.remindIgnore, style: { appearance: "none", border: "none", background: "var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,0.16))", color: "var(--dsw-alias-label-secondary)", borderRadius: "6px", padding: "3px 10px", fontSize: "12px", cursor: "pointer", fontFamily: "inherit", flex: "none" }, onClick: function () { setBool("dsh-easyrewrite:autoCheckReminded", true); setRemindClosed(true); } }, L.remindIgnore)
2371
- ) : null,
2372
- React.createElement("div", { style: rowStyle },
2373
- React.createElement("span", { style: hintStyle, flex: "1" }, updateMsg || ""),
2374
- React.createElement("button", {
2375
- type: "button",
2376
- style: {
2377
- appearance: "none",
2378
- border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.3))",
2379
- background: "transparent",
2380
- color: "var(--dsw-alias-label-secondary)",
2381
- borderRadius: "6px",
2382
- padding: "3px 10px",
2383
- fontSize: "12px",
2384
- cursor: "pointer",
2385
- fontFamily: "inherit",
2386
- flex: "none"
2387
- },
2388
- onClick: function () { doCheckUpdate(); }
2389
- }, updateChecking ? L.checking : L.checkUpdate)
2390
- ),
2391
- updateAvailableVer ? React.createElement("div", { style: rowStyle },
2392
- React.createElement("span", { style: { fontSize: "12px", color: "var(--dsw-alias-brand-primary, #4d6bfe)", flex: "1" } }, L.newVersion.replace("{ver}", updateAvailableVer)),
2393
- React.createElement("button", {
2394
- type: "button",
2395
- style: {
2396
- appearance: "none",
2397
- border: "none",
2398
- background: "var(--dsw-static-deepseek-500, #4d6bfe)",
2399
- color: "#ffffff",
2400
- borderRadius: "6px",
2401
- padding: "3px 12px",
2402
- fontSize: "12px",
2403
- cursor: "pointer",
2404
- fontFamily: "inherit",
2405
- flex: "none"
2406
- },
2407
- onClick: function () { doUpdatePlugin(); }
2408
- }, updateUpdating ? L.updating : L.updateNow)
2409
- ) : null,
2410
- switchRow(L.autoCheckUpdate, autoCheckOn, function (v) {
2411
- setAutoCheckOn(v);
2412
- setBool("dsh-easyrewrite:autoCheckUpdate", v);
2413
- })
2267
+ (function () {
2268
+ if (!dshVer) return null;
2269
+ if (cmpDsh(dshVer, MIN_DSH_VERSION) < 0) return React.createElement(
2270
+ UI.Banner,
2271
+ { key: "dsh-low", kind: "warn" },
2272
+ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "4px", width: "100%" } },
2273
+ React.createElement("span", null, L.dshLowWarning.replace("{cur}", dshVer).replace("{min}", MIN_DSH_VERSION)),
2274
+ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: "6px" } },
2275
+ React.createElement("code", { style: { fontSize: "11px", flex: "1", minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, "npm install -g @deepseek-ai/dsh@" + MIN_DSH_VERSION),
2276
+ React.createElement(UI.Button, {
2277
+ variant: "secondary",
2278
+ size: "sm",
2279
+ onClick: function () { try { legacyCopy("npm install -g @deepseek-ai/dsh@" + MIN_DSH_VERSION); } catch (e) {} },
2280
+ }, L.copyUpgradeCmd)
2281
+ )
2282
+ )
2283
+ );
2284
+ if (cmpDsh(MAX_TESTED_DSH_VERSION, dshVer) < 0) return React.createElement(UI.Banner, { key: "dsh-new", kind: "info" }, L.dshNewNotice.replace("{cur}", dshVer));
2285
+ return null;
2286
+ })(),
2287
+ !remindClosed && !getBool("dsh-easyrewrite:autoCheckUpdate", false) ? React.createElement(
2288
+ UI.Banner,
2289
+ { key: "remind", kind: "info" },
2290
+ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px", width: "100%" } },
2291
+ React.createElement("span", { style: { flex: "1", minWidth: 0 } }, L.suggestAutoCheck),
2292
+ React.createElement(UI.Button, {
2293
+ variant: "primary",
2294
+ size: "sm",
2295
+ onClick: function () {
2296
+ setBool("dsh-easyrewrite:autoCheckUpdate", true);
2297
+ setBool("dsh-easyrewrite:autoCheckReminded", true);
2298
+ setAutoCheckOn(true);
2299
+ setRemindClosed(true);
2300
+ },
2301
+ }, L.enableNow),
2302
+ React.createElement(UI.Button, {
2303
+ variant: "ghost",
2304
+ size: "sm",
2305
+ title: L.remindIgnore,
2306
+ onClick: function () {
2307
+ setBool("dsh-easyrewrite:autoCheckReminded", true);
2308
+ setRemindClosed(true);
2309
+ },
2310
+ }, L.remindIgnore)
2414
2311
  )
2415
- ),
2416
- React.createElement("span", { style: hintStyle }, L.instant)
2417
- );
2418
- // plugins.item(0.1.7 起):页面把同一个组件按 view 渲染两次 —— summary 当列表行与
2419
- // 详情页的一行描述,page 当配置主体。图标、标题(取自插槽 label)、启用开关与详情页
2420
- // 外壳都由页面提供,所以这里两者都不画头部。
2421
- if (embedded) return props.view === "summary" ? L.subtitle : cardBody;
2422
- // settings.plugin.item(0.1.5 及以下):插槽不提供外壳,卡片自画可点头部。
2423
- return React.createElement("li", { style: Object.assign({}, cardStyle, open ? cardOpenStyle : null), "data-dsh-easyrewrite": "settings-card" },
2424
- React.createElement("button", {
2425
- type: "button",
2426
- style: headStyle,
2427
- "aria-expanded": open,
2428
- "aria-label": (open ? L.collapse : L.expand) + ": " + L.title,
2429
- onClick: function () { setOpen(!open); }
2430
- },
2431
- React.createElement("span", { style: headTextStyle },
2432
- React.createElement("span", { style: titleStyle }, L.title),
2433
- React.createElement("span", { style: subStyle }, L.subtitle)
2434
- ),
2435
- React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", style: Object.assign({}, chevronStyle, open ? chevronOpenStyle : null) },
2436
- React.createElement("path", { d: "M9 6l6 6-6 6", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }))
2312
+ ) : null,
2313
+ updateAvailableVer ? React.createElement(
2314
+ UI.Banner,
2315
+ { key: "update-avail", kind: "ok" },
2316
+ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px", width: "100%" } },
2317
+ React.createElement("span", { style: { flex: "1" } }, L.newVersion.replace("{ver}", updateAvailableVer)),
2318
+ React.createElement(UI.Button, {
2319
+ variant: "primary",
2320
+ size: "sm",
2321
+ loading: updateUpdating,
2322
+ onClick: function () { doUpdatePlugin(); },
2323
+ }, updateUpdating ? L.updating : L.updateNow)
2324
+ )
2325
+ ) : null,
2326
+ renderSwitch(L.autoCheckUpdate, autoCheckOn, function (v) {
2327
+ setAutoCheckOn(v);
2328
+ setBool("dsh-easyrewrite:autoCheckUpdate", v);
2329
+ }),
2437
2330
  ),
2438
- open ? cardBody : null
2331
+
2332
+ React.createElement("span", { key: "instant-hint", className: "dsp-field-hint" }, L.instant),
2333
+ ];
2334
+
2335
+ return React.createElement(
2336
+ UI.SettingsCard,
2337
+ {
2338
+ title: L.title,
2339
+ description: L.subtitle,
2340
+ },
2341
+ children,
2439
2342
  );
2440
2343
  }
2441
2344
 
@@ -2498,20 +2401,19 @@ window.__ModuleLoader__.load({
2498
2401
  }
2499
2402
 
2500
2403
  /** 极限场景重置(首条消息/截断会话首条,无前置闭合边界,无法 fork):
2501
- * - 家族会话(截断/分叉产物,版本 ≥2):归档当前 → 恢复并打开**父版本**(上一次模型回复处)重新开始;
2502
- * 编辑模式经 resume 机制把修改文本带到父版本自动重发。
2503
- * - 全新会话首条(无家族):归档当前 → 回到空白新对话(官方 project() 检测归档即回 hero)。
2404
+ * 归档当前会话 → 在所属工作区打开空白新会话;编辑模式经 resume 机制把修改后的文本
2405
+ * 作为新会话的**第一条**自动发出(DESIGN §2.3:目标消息之前没有历史,新对话即修改稿本身)。
2504
2406
  * @param mode - "recall" | "edit"
2505
2407
  * @param text - edit 模式的修改后文本
2506
2408
  * @param props - 组件 inject 面
2507
2409
  */
2508
2410
  function resetConversation(sessionId, mode, text, props, imageIds, selOverride, stagedDraft) {
2509
2411
  log("info", "reset", "首条消息重置对话", { sessionId: sessionId, mode: mode });
2510
- // v2.1.1:目标会话(父版本或空白新会话)发送前需要恢复当前模型/挡位
2412
+ // v2.1.1:新会话发送前需要恢复当前模型/挡位
2511
2413
  // v2.2:气泡编辑 chip 的本地选择优先(selOverride),撤回键路径不传 → 原语义
2512
2414
  var msel = selOverride || (props.modelSel ? props.modelSel.capture(sessionId) : null);
2513
2415
  writePending(sessionId, null);
2514
- // 1) 归档当前会话(两种场景都需要;project() 检测 current 归档 → 自动回 hero/父版本打开后列表更新)
2416
+ // 1) 归档当前会话(project() 检测 current 归档 → 自动回 hero;新会话随后被打开)
2515
2417
  try {
2516
2418
  var archiver = typeof props.archiveSession === "function"
2517
2419
  ? props.archiveSession
@@ -2524,26 +2426,10 @@ window.__ModuleLoader__.load({
2524
2426
  log("warn", "reset", "归档能力不可用", { sessionId: sessionId });
2525
2427
  }
2526
2428
  } catch (e) { /* ignore */ }
2527
- // 2) 场景 2:家族父版本(截断/分叉会话 → 回到上一次模型回复)
2528
- try {
2529
- var fam = familyOfSession(sessionId, props.ctxSessions);
2530
- log("info", "reset", "场景2家族判定", { sessionId: sessionId, found: !!fam, verLen: fam ? fam.versions.length : -1, index: fam ? fam.index : -1 });
2531
- var parentId = fam && fam.versions.length >= 2 && fam.index > 0 ? fam.versions[fam.index - 1] : null;
2532
- if (parentId) {
2533
- if (mode === "edit" && typeof text === "string") {
2534
- try { localStorage.setItem("dsh-easyrewrite:resume-send:" + parentId, JSON.stringify({ draftText: text, t: Date.now(), imageIds: imageIds || [], sel: msel, stagedDraft: stagedDraft || null })); } catch (e) { /* ignore */ }
2535
- }
2536
- var doOpenParent = function () {
2537
- safeOpenSession(parentId, props);
2538
- };
2539
- if (typeof props.restoreSession === "function") {
2540
- try { props.restoreSession(parentId).then(doOpenParent, doOpenParent); return; } catch (e) { /* fallthrough */ }
2541
- }
2542
- doOpenParent();
2543
- return;
2544
- }
2545
- } catch (e) { /* ignore */ }
2546
- // 3) 场景 1:全新会话首条 → 无缝打开空白新会话(编辑模式经 resume 自动发送编辑文本)
2429
+ // 2) 打开空白新会话(编辑模式经 resume 自动发送编辑文本)
2430
+ // 目标消息之前没有任何历史 → 新对话 = 修改后的消息本身(DESIGN §2.3)。
2431
+ // 此前这里先走「家族父版本」分支,把修改后的文本**追加到父版本历史末尾**:
2432
+ // 首条消息的编辑于是变成「整段旧历史 + 修改稿」,与 §2.3 的截断语义相反。
2547
2433
  try {
2548
2434
  var wsId = null;
2549
2435
  if (props.ctxWorkspaces && typeof props.ctxWorkspaces.list === "object" && typeof props.ctxWorkspaces.list.getSnapshot === "function") {
@@ -2557,7 +2443,7 @@ window.__ModuleLoader__.load({
2557
2443
  }
2558
2444
  }
2559
2445
  }
2560
- log("info", "reset", "场景1工作区定位", { sessionId: sessionId, wsId: wsId, hasConnect: !!(props.ctxWorkspaces && typeof props.ctxWorkspaces.connectWorkspace === "function") });
2446
+ log("info", "reset", "空白新会话:工作区定位", { sessionId: sessionId, wsId: wsId, hasConnect: !!(ctxUiWorkspaceRef && typeof ctxUiWorkspaceRef.connectWorkspace === "function") });
2561
2447
  var wsConnector = (ctxUiWorkspaceRef && typeof ctxUiWorkspaceRef.connectWorkspace === "function") ? ctxUiWorkspaceRef : ((props.ctxWorkspaces && typeof props.ctxWorkspaces.connectWorkspace === "function") ? props.ctxWorkspaces : null);
2562
2448
  if (wsId && wsConnector) {
2563
2449
  wsConnector.connectWorkspace(wsId).then(function (newId) {
@@ -2572,7 +2458,7 @@ window.__ModuleLoader__.load({
2572
2458
  }
2573
2459
  } catch (e) { /* ignore */ }
2574
2460
  // 兜底:归档已生效,官方自动回 hero
2575
- log("info", "reset", "重置完成(兜底路径)", { sessionId: sessionId, mode: mode });
2461
+ log("warn", "reset", "无可用的空白新会话通道(已归档,回 hero)", { sessionId: sessionId, mode: mode, wsId: wsId });
2576
2462
  }
2577
2463
 
2578
2464
  /** 版本翻页器 < X >:撤回/编辑重发产生的版本家族切换(官方 assistant-actions 操作区)。
@@ -4087,7 +3973,10 @@ window.__ModuleLoader__.load({
4087
3973
  } catch (eDbg) { /* ignore */ }
4088
3974
  try { ctxConversationRef = ctx.conversation; } catch (e) { ctxConversationRef = null; }
4089
3975
  try { ctxUiConversationRef = (typeof ctx.get === "function") ? (ctx.get("uiConversation") || null) : null; } catch (eUic) { ctxUiConversationRef = null; }
4090
- try { ctxUiWorkspaceRef = ctx.uiWorkspace || ((typeof ctx.get === "function") ? (ctx.get("uiWorkspace") || null) : null); } catch (eUiw) { ctxUiWorkspaceRef = null; }
3976
+ // 注意:uiWorkspace 不在本插件的 inject 清单内,`ctx.uiWorkspace` 抛错(见下方
3977
+ // invokeOpenSession 的 try/catch);此前把它放在 || 左侧,抛错被 catch 吞掉,导致
3978
+ // ctx.get("uiWorkspace") 永远不可达、ctxUiWorkspaceRef 恒为 null(空白新会话通道自 2.6.0 起失效)。
3979
+ try { ctxUiWorkspaceRef = (typeof ctx.get === "function") ? (ctx.get("uiWorkspace") || null) : null; } catch (eUiw) { ctxUiWorkspaceRef = null; }
4091
3980
  function invokeOpenSession(id) {
4092
3981
  try {
4093
3982
  if (ctx.uiWorkspace && typeof ctx.uiWorkspace.openSession === "function") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logictan/dsh-easyrewrite",
3
- "version": "2.7.0",
3
+ "version": "2.7.2",
4
4
  "description": "DSH Web内目前最无感的消息撤回、重编辑插件,原版体验,兼容性强,功能简单可开关,设置丰富,现代化轻量ui框架。The most seamless message recall & re-edit plugin for DSH Web — native experience, strong compatibility, simple toggles, rich settings, modern lightweight UI. DSH Web で最もシームレスなメッセージ撤回・再編集プラグイン——ネイティブ体験、高い互換性、シンプルなトグル、充実した設定、モダンで軽量な UI。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -14,6 +14,9 @@
14
14
  "patch": "./cordis.patch.yml"
15
15
  },
16
16
  "client": {
17
+ "external": [
18
+ "@logictan/dsh-plugins-shared-client"
19
+ ],
17
20
  "inject": [
18
21
  "slots",
19
22
  "sessions",
@@ -63,9 +66,17 @@
63
66
  "prepare": "node build.mjs",
64
67
  "prepack": "node build.mjs"
65
68
  },
69
+ "peerDependencies": {
70
+ "@logictan/dsh-plugins-shared-client": "^0.1.0"
71
+ },
66
72
  "repository": {
67
73
  "type": "git",
68
74
  "url": "git+https://github.com/dale0525/dsh-plugins.git",
69
75
  "directory": "packages/dsh-easyrewrite"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "@logictan/dsh-plugins-shared-client": {
79
+ "optional": true
80
+ }
70
81
  }
71
82
  }