dsh-prompt-rewriter 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  记录每个**已发布**版本对使用者可见的变化。中英双语并列,中文在前。
4
4
 
5
+ ## 1.6.2
6
+
7
+ **中文**
8
+
9
+ - 增强进行中的鱼尾动效改用品牌蓝。此前它跟随按钮的文字色,深色主题下接近白色,与旁边的鱼形图标不同色。
10
+ - 输入框里的图片读取更可靠:宿主服务取不到时改从输入框自身的通道取图;两处都无法回答时不再静默跳过,文字改写照常完成,状态区会告诉你少读了几张。
11
+
12
+ **English**
13
+
14
+ - The tail animation shown while an enhancement runs now uses the brand blue. It previously followed the button's text colour, which is near white in the dark theme and did not match the fish icon beside it.
15
+ - Composer images are read more reliably: when the host service cannot answer, the composer's own channel is used instead; when neither can, the images are no longer skipped silently — the text-only rewrite still completes and the status area reports how many were missed.
5
16
  ## 1.6.0
6
17
 
7
18
  **中文**
@@ -86,4 +97,4 @@
86
97
 
87
98
  **English**
88
99
 
89
- - Added the bilingual README and screenshots; fixed images and the Chinese guide missing from the npm package.
100
+ - Added the bilingual README and screenshots; fixed images and the Chinese guide missing from the npm package.
package/README.md CHANGED
@@ -43,7 +43,7 @@ An enhancement is a real model call, and **how fast the result comes back depend
43
43
 
44
44
  If it feels slow, switch the session to a model that is more stable and responds faster — the same draft can take a few seconds on one model and well over ten on another. The button does not favour any particular model; it uses whichever one you picked.
45
45
 
46
- > Want a fixed model just for enhancement, without affecting normal chat? Open `Settings → Prompt rewriter` and turn on **Use a fixed model**.
46
+ > Want a fixed model just for enhancement, without affecting normal chat? Open `Settings → Prompt Enhance` and turn on **Use a fixed model**.
47
47
 
48
48
  ### You can navigate away mid-rewrite
49
49
 
@@ -55,7 +55,7 @@ That wasn't true in 1.0.x: switching sessions aborted the task, and coming back
55
55
 
56
56
  ### Keyboard shortcut (off by default)
57
57
 
58
- Turn it on at **Settings → Prompt rewriter → Shortcut**. Desktop uses `Ctrl+E` (`Cmd+E` on macOS); the browser uses `Ctrl+Alt+E` (`Cmd+Alt+E`).
58
+ Turn it on at **Settings → Prompt Enhance → Shortcut**. Desktop uses `Ctrl+E` (`Cmd+E` on macOS); the browser uses `Ctrl+Alt+E` (`Cmd+Alt+E`).
59
59
 
60
60
  - Press once to enhance; press again while it runs to pause. It acts on the composer of the current conversation.
61
61
  - **Same as clicking the icon** — the shortcut runs the icon's own click handler, including its undo state, so the two paths cannot drift. Restoring a draft stays on the button or `Ctrl+Z`.
@@ -95,7 +95,7 @@ Only images **currently sitting in the composer** — **never images from earlie
95
95
 
96
96
  ## Settings
97
97
 
98
- `Settings → Prompt rewriter`. Three switches and one dropdown, affecting **only this button, never normal sending**.
98
+ `Settings → Prompt Enhance`. Four switches and one dropdown, affecting **only this button, never normal sending**.
99
99
 
100
100
  ![Settings page](https://raw.githubusercontent.com/huaguoxingkong/dsh-prompt-rewriter/main/docs/images/03-settings-en.png)
101
101
 
@@ -104,6 +104,7 @@ Only images **currently sitting in the composer** — **never images from earlie
104
104
  | Use a fixed model | Off | Off: follow the model of the current conversation. On: always use the model picked below. |
105
105
  | Reference the conversation | **On** | Read earlier turns. More accurate, but extra tokens and slower on long chats. |
106
106
  | Reference composer images | Off | Images in the composer take part. Earlier messages' images are never read. |
107
+ | Shortcut | Off | Lets the keyboard trigger a rewrite. Off by default, so no global key fires unasked. |
107
108
 
108
109
  - The model dropdown lists **the providers and models you actually have** — you can't type in one that doesn't exist.
109
110
  - Turning the model switch off does not clear your selection; flipping it back on shows the same choice.
@@ -137,7 +138,7 @@ Download the zip from [Releases](https://github.com/huaguoxingkong/dsh-prompt-re
137
138
 
138
139
  ## FAQ
139
140
 
140
- **Clicked it and nothing happened.** The composer is empty, or *Use a fixed model* is on with no model picked.
141
+ **Clicked it and nothing happened.** The composer is empty, or *Use a fixed model* is on with no model picked. If you used the shortcut instead, check that the Shortcut switch is on and that no conflict is reported.
141
142
 
142
143
  **"No credentials configured for the current model."** That model has no key set. Switch models, or pin one that works in settings.
143
144
 
@@ -147,7 +148,7 @@ Download the zip from [Releases](https://github.com/huaguoxingkong/dsh-prompt-re
147
148
 
148
149
  ## Configuration
149
150
 
150
- Every `config` key on the profile plugin line is optional. The first five are managed by the settings page; the last seven are operational ceilings and are not exposed in the UI.
151
+ Every `config` key on the profile plugin line is optional. The first six are managed by the settings page; the last seven are operational ceilings and are not exposed in the UI.
151
152
 
152
153
  ```yaml
153
154
  - id: dsh-prompt-rewriter
@@ -159,6 +160,7 @@ Every `config` key on the profile plugin line is optional. The first five are ma
159
160
  enhanceModel: ""
160
161
  referenceImages: false # read composer images
161
162
  referenceContext: true # read earlier turns
163
+ shortcutEnabled: false # keyboard shortcut (off by default)
162
164
 
163
165
  # operational ceilings (not exposed in the UI)
164
166
  maxDraftChars: 8000 # draft length cap
package/README.zh.md CHANGED
@@ -44,7 +44,7 @@
44
44
 
45
45
  如果觉得等得久,把会话用的模型换成一个更稳定、响应更快的——同一个草稿,换个模型往往就是几秒和十几秒的差别。这个按钮不挑模型,你选哪个它就用哪个。
46
46
 
47
- > 想固定用某个模型专门做增强(不影响正常对话)?去 `设置 → 提示词改写` 打开「用哪个模型改写」。
47
+ > 想固定用某个模型专门做增强(不影响正常对话)?去 `设置 → 提示词增强` 打开「用哪个模型改写」。
48
48
 
49
49
  ### 增强过程中可以切走
50
50
 
@@ -56,7 +56,7 @@
56
56
 
57
57
  ### 键盘快捷键(默认关闭)
58
58
 
59
- 到 **设置 → 提示词改写 → 快捷键** 打开开关。桌面端为 `Ctrl+E`(macOS `Cmd+E`),浏览器端为 `Ctrl+Alt+E`(macOS `Cmd+Alt+E`)。
59
+ 到 **设置 → 提示词增强 → 快捷键** 打开开关。桌面端为 `Ctrl+E`(macOS `Cmd+E`),浏览器端为 `Ctrl+Alt+E`(macOS `Cmd+Alt+E`)。
60
60
 
61
61
  - 按一次增强,运行中再按一次暂停。作用对象是当前会话的输入框。
62
62
  - **与点击图标完全等价**:走的是图标自身的点击入口,含「撤销」态,不存在第二套逻辑。回退仍由按钮或 `Ctrl+Z` 负责。
@@ -96,7 +96,7 @@
96
96
 
97
97
  ## 设置
98
98
 
99
- `设置 → 提示词改写`。三个开关一个下拉,**只影响这个按钮,不影响正常发送**。
99
+ `设置 → 提示词增强`。四个开关一个下拉,**只影响这个按钮,不影响正常发送**。
100
100
 
101
101
  ![设置页](https://raw.githubusercontent.com/huaguoxingkong/dsh-prompt-rewriter/main/docs/images/03-settings.png)
102
102
 
@@ -105,6 +105,7 @@
105
105
  | 用哪个模型改写 | 关 | 关:跟随当前对话的模型。开:固定用下拉选定的模型。 |
106
106
  | 参考之前的对话 | **开** | 读前面的内容。更准,但多耗 token、长对话更慢。 |
107
107
  | 参考输入框里的图片 | 关 | 输入框里的图一起参与。历史消息里的图片始终不读。 |
108
+ | 快捷键 | 关 | 打开后可用键盘触发改写。默认关闭,不会在你没要求时抢占按键。 |
108
109
 
109
110
  - 模型下拉列出你**实际拥有**的渠道与模型,填不进不存在的模型。
110
111
  - 关掉模型开关不会清空你的选择,重新打开还是同一个。
@@ -138,7 +139,7 @@ dsh plugin --profile web add github:huaguoxingkong/dsh-prompt-rewriter
138
139
 
139
140
  ## 常见问题
140
141
 
141
- **点了没反应?** 输入框是空的,或者「用哪个模型改写」打开了但没选模型。
142
+ **点了没反应?** 输入框是空的,或者「用哪个模型改写」打开了但没选模型。如果用的是快捷键,先确认「快捷键」开关已打开、且没有提示冲突。
142
143
 
143
144
  **报「当前模型尚未配置可用的凭据」?** 这个模型没配 key。换个模型,或在设置里固定一个能用的。
144
145
 
@@ -148,7 +149,7 @@ dsh plugin --profile web add github:huaguoxingkong/dsh-prompt-rewriter
148
149
 
149
150
  ## 配置
150
151
 
151
- profile 插件行的 `config` 全部可选。前五项由设置页托管,后七项是运维上限,不暴露在界面上:
152
+ profile 插件行的 `config` 全部可选。前六项由设置页托管,后七项是运维上限,不暴露在界面上:
152
153
 
153
154
  ```yaml
154
155
  - id: dsh-prompt-rewriter
@@ -160,6 +161,7 @@ profile 插件行的 `config` 全部可选。前五项由设置页托管,后
160
161
  enhanceModel: ""
161
162
  referenceImages: false # 是否参考输入框图片
162
163
  referenceContext: true # 是否参考前文
164
+ shortcutEnabled: false # 键盘快捷键(默认关闭)
163
165
 
164
166
  # 运维上限(不暴露在设置页)
165
167
  maxDraftChars: 8000 # 草稿字符上限
package/client.js CHANGED
@@ -75,7 +75,7 @@ window.__ModuleLoader__.load({
75
75
  // Colour: the official brand blue, not `currentColor`. The tail is a graphic,
76
76
  // not text, so inheriting the button's label colour made it render white on
77
77
  // the dark composer — visually detached from the fish mark it replaces.
78
- '.dsh-pe_twist{display:block;width:20px;height:16px;overflow:visible;color:inherit}',
78
+ '.dsh-pe_twist{display:block;width:20px;height:16px;overflow:visible;color:var(--dsw-alias-brand-primary-new-colorprimary-new-color,#4176e6)}',
79
79
  '.dsh-pe_twist path{fill:currentColor;fill-rule:evenodd}',
80
80
  '.dsh-pe_icon{display:block;width:15px;height:15px}',
81
81
  // Context-mode mark: a dot on the seat that reports an EXPECTATION — "if you
@@ -708,10 +708,6 @@ window.__ModuleLoader__.load({
708
708
  // feature is opt-in, so a global key never fires on a user who did not ask for
709
709
  // it. Read from the same settings response as the other switches.
710
710
  const [shortcutOn, setShortcutOn] = useState(false);
711
- // Exposed on the seat as data-ctx-debug so a missing dot can be diagnosed
712
- // without guessing: it records which of the two facts was false, and whether
713
- // either request failed. Not shown to users; harmless in the DOM.
714
- const [ctxProbe, setCtxProbe] = useState('pending');
715
711
  useEffect(() => {
716
712
  let cancelled = false;
717
713
  const read = async () => {
@@ -730,16 +726,11 @@ window.__ModuleLoader__.load({
730
726
  const allowed = settings?.ok === true && settings.values?.shortcutEnabled === true;
731
727
  setShortcutOn(allowed);
732
728
  taskStore.setShortcutEnabled(allowed);
733
- setCtxProbe(
734
- `sw=${switchOn ? 1 : 0},hc=${hasContext ? 1 : 0},`
735
- + `sHttp=${settingsResponse.status},cHttp=${statusResponse.status}`,
736
- );
737
729
  } catch (error) {
738
730
  // An unreachable route means "we cannot promise context"; showing no dot
739
731
  // is the honest default rather than promising a context-aware run.
740
732
  if (!cancelled) {
741
733
  setWillUseContext(false);
742
- setCtxProbe(`error:${error?.message ?? 'unknown'}`);
743
734
  }
744
735
  }
745
736
  };
@@ -819,19 +810,52 @@ window.__ModuleLoader__.load({
819
810
  * @param signal - cancellation.
820
811
  * @returns `{ images, skipped }`.
821
812
  */
822
- async function readComposerImages(conversation, ids, signal) {
823
- const images = [];
824
- let skipped = 0;
825
- if (!Array.isArray(ids) || ids.length === 0) return { images, skipped };
826
- if (conversation === undefined || typeof conversation.resolveDraftAttachments !== 'function') {
827
- return { images, skipped: ids.length };
813
+ /**
814
+ * Resolve the composer draft descriptors for these ids.
815
+ *
816
+ * Two owners can answer, and which one is reachable depends on the shell:
817
+ *
818
+ * 1. the `conversation` client service, which owns the draft map;
819
+ * 2. the composer action face handed to the slot, which exposes the same
820
+ * lookup when the host chooses to publish it there.
821
+ *
822
+ * Trying both removes the single point of failure that made every image come
823
+ * back unreadable when the first owner was absent.
824
+ *
825
+ * @param inputActions - the composer action face from slot props.
826
+ * @param ids - draft attachment ids.
827
+ * @returns `{ descriptors, source }` where source is the owner that answered.
828
+ */
829
+ function resolveDraftDescriptors(inputActions, ids) {
830
+ const conversation = conversationResolver();
831
+ if (conversation !== undefined && typeof conversation.resolveDraftAttachments === 'function') {
832
+ try {
833
+ return { descriptors: conversation.resolveDraftAttachments(ids) ?? [], source: 'service' };
834
+ } catch {
835
+ // Fall through to the action face.
836
+ }
828
837
  }
829
- let descriptors;
830
- try {
831
- descriptors = conversation.resolveDraftAttachments(ids) ?? [];
832
- } catch {
833
- return { images, skipped: ids.length };
838
+ if (inputActions !== undefined && typeof inputActions.resolveDraftAttachments === 'function') {
839
+ try {
840
+ return { descriptors: inputActions.resolveDraftAttachments(ids) ?? [], source: 'actions' };
841
+ } catch {
842
+ // Neither owner could answer.
843
+ }
834
844
  }
845
+ return { descriptors: [], source: 'none' };
846
+ }
847
+
848
+ /**
849
+ * Turn resolved draft descriptors into request images.
850
+ *
851
+ * @param descriptors - draft descriptors carrying the original browser `File`.
852
+ * @param signal - cancellation.
853
+ * @returns `{ images, skipped }`.
854
+ */
855
+ async function readComposerImages(descriptors, signal) {
856
+ const images = [];
857
+ let skipped = 0;
858
+ if (!Array.isArray(descriptors) || descriptors.length === 0) return { images, skipped };
835
859
  for (const descriptor of descriptors.slice(0, 4)) {
836
860
  if (signal.aborted) return { images, skipped };
837
861
  if (descriptor?.kind !== 'image') continue;
@@ -900,10 +924,17 @@ window.__ModuleLoader__.load({
900
924
  // race entirely and keeps one authority for the switch.
901
925
  // Resolved here, not at activation: the service mounts with the
902
926
  // conversation plugin, which can come up after this plugin.
903
- const conversation = attachmentIds.length > 0 ? conversationResolver() : undefined;
927
+ const drafts = attachmentIds.length > 0
928
+ ? resolveDraftDescriptors(inputActions, attachmentIds)
929
+ : { descriptors: [], source: 'none' };
904
930
  const collected = attachmentIds.length > 0
905
- ? await readComposerImages(conversation, attachmentIds, controller.signal)
931
+ ? await readComposerImages(drafts.descriptors, controller.signal)
906
932
  : { images: [], skipped: 0 };
933
+ if (attachmentIds.length > 0 && drafts.source === 'none') {
934
+ // Nothing could read the attachments. Report it through the same notice
935
+ // the Host uses for a skipped image, instead of dropping them silently.
936
+ collected.skipped = attachmentIds.length;
937
+ }
907
938
  if (controller.signal.aborted) return;
908
939
  const response = await fetch('/api/prompt-enhance', {
909
940
  method: 'POST',
@@ -1112,7 +1143,6 @@ window.__ModuleLoader__.load({
1112
1143
  className: 'dsh-pe_root',
1113
1144
  'data-prompt-enhance': '1',
1114
1145
  'data-context': showContextMark ? 'true' : 'false',
1115
- 'data-ctx-debug': ctxProbe,
1116
1146
  'data-notice': failure !== null ? 'true' : 'false',
1117
1147
  },
1118
1148
  h(
@@ -1371,7 +1401,6 @@ window.__ModuleLoader__.load({
1371
1401
  // Keep the reason: an empty picker with no explanation is
1372
1402
  // indistinguishable from a slow load, and the message is shown to the
1373
1403
  // user instead of being swallowed.
1374
- if (typeof console !== 'undefined') console.warn('[dsh-prompt-rewriter] model catalog failed:', failure?.message ?? failure);
1375
1404
  setCatalog({ status: 'error', groups: [] });
1376
1405
  }
1377
1406
  })();
@@ -1925,9 +1954,9 @@ window.__ModuleLoader__.load({
1925
1954
  modals: [],
1926
1955
  });
1927
1956
  return dispose;
1928
- } catch (error) {
1929
- // Record the failure instead of letting `ctx.effect` swallow it; the
1930
- // console then explains why the key does nothing.
1957
+ } catch {
1958
+ // A throw here is swallowed by the effect wrapper; the keydown fallback
1959
+ // below still serves the shortcut, so it must not fail activation.
1931
1960
  return undefined;
1932
1961
  }
1933
1962
  }, 'dsh-prompt-rewriter: shortcut');
@@ -1994,10 +2023,9 @@ window.__ModuleLoader__.load({
1994
2023
  };
1995
2024
 
1996
2025
  /**
1997
- * Walk the whole guard chain and report which link decided.
2026
+ * Does this keyboard event match a binding this plugin owns?
1998
2027
  *
1999
- * Kept separate from `onKey` so the periodic probe can evaluate the same
2000
- * chain without ever triggering an enhancement.
2028
+ * Kept separate from `onKey` so the pure judgement is testable on its own.
2001
2029
  */
2002
2030
  const evaluate = (event) => {
2003
2031
  const base = {
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-prompt-rewriter",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "One-click prompt enhancement beside the DeepSeek Harness composer: rewrites a draft in place without sending it.",
5
5
  "type": "module",
6
6
  "icon": "icon.svg",