dsh-long-plugins 1.3.2 → 1.3.5

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 CHANGED
@@ -1,11 +1,11 @@
1
1
  # dsh-long-plugins
2
2
 
3
3
  Merged plugin bundle for [DeepSeek Harness](https://github.com/deepseek-ai/dsh) (DSH) Web:
4
- upload manager, workspace **输出文件** section, top-bar **文件** browser with a real Word (docx) preview,
5
- **技能文档** (skill docs) browser, and DeepSeek account balance — all in one installable plugin.
4
+ upload manager, workspace **输出文件** section, top-bar **文件** browser with real **Word / PPT (docx / pptx) preview**,
5
+ **技能文档** (skill docs) browser, DeepSeek account balance, and **turn ruler (session navigation)** — all in one installable plugin.
6
6
  Also ships an auto-repair install that relinks DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink).
7
7
 
8
- 一个插件整合 DSH Web 的常用增强:上传管理、顶栏「📂文件」工作区浏览 + Word 真实预览、工作区「输出文件」面板、技能文档浏览、账户余额显示。并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。
8
+ 一个插件整合 DSH Web 的常用增强:上传管理、顶栏「📂文件」工作区浏览 + 文件预览(Word、PPT 格式渲染)、工作区「输出文件」面板、技能文档浏览、账户余额显示。并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。会话记录导航。
9
9
 
10
10
  ## Features / 功能
11
11
 
@@ -14,39 +14,15 @@ Also ships an auto-repair install that relinks DSH core patches (reverse-proxy W
14
14
  | Upload manager | 输入框回形针按钮上传本地文件,待发送文件栏管理,设置面板「上传文件」(预览/下载/删除) |
15
15
  | Workspace output files | 设置面板「输出文件」:按工作区文件夹分组、预览、**编辑/保存**、复制全部、**放大窗口** |
16
16
  | Workspace file browser (顶栏「📂文件」) | 顶栏「📂文件」打开工作区/全部文件浏览,按文件夹分组;点文件名或「预览」在面板内预览,**Word (.docx) 用 docx-preview 浏览器端真实渲染(所见即所得)**;支持「←返回」「✕关闭」两层退出回列表,底部仅列表根时才整体退出;含下载/放大 |
17
+ | PowerPoint (.pptx) 预览 | 预览 `.pptx` 时用 **PptxViewJS 浏览器端真实渲染**(Canvas 逐页渲染、所见即所得),支持上一页/下一页翻页与**放大/缩小/适合宽度**;随包打包前端库 `client/vendor`(pptxviewjs / chart.js) |
17
18
  | Skill docs | 设置面板「技能文档」:按技能目录浏览 SKILL.md、弹窗预览、编辑/保存、复制、放大窗口 |
18
19
  | Account balance | 输入框下方显示 DeepSeek 账户余额(60s 自动刷新) |
19
20
  | md2docx | DSH 工具:把 Markdown 一键转成带页码页脚的 Word(`.docx`),标题/表格/加粗/列表/引用,生成的文件作为可点击交付物出现在消息里 |
20
- | Turn ruler | 会话右侧轮次导航:3 个比例刻度(最早/中间/最新)+ 预览窗列出全部轮次标题,光标点亮、点击蓝色标记并定位会话,滚到顶部自动加载更早历史,手机端竖向把手打开预览窗 |
21
+ | Turn ruler | 桌面端会话右侧 3 个比例刻度点,悬停打开「历史提问」预览窗;预览窗列出全部已加载轮次的标题,光标悬停点亮该行,点击行以蓝色标记并定位主会话;滚动到预览窗顶部自动加载更早历史(内容锚定恢复焦点,无震动、不跳跃),手机端触摸滚动已做性能优化;手机端右边缘竖向把手点击打开预览窗(居中弹窗,✕ 关闭) |
21
22
  | Auto-repair install | 安装时自动重打 DSH 核心补丁:反代 WebSocket 心跳(修复提问窗口自己消失)、升级后重连 |
22
23
  | Mobile layout | 手机端布局优化(输入栏、设置面板、主题选择、模型选择器) |
23
24
  | Drag & drop upload | 拖任意文件到会话框直接附加为「待发送」卡片(走与回形针同一上传管线);全屏虚线投掷遮罩提示;消除 DSH 核心"仅支持 PNG/JPG/WebP/GIF 格式的图片"误报 |
24
25
 
25
- ## 更新记录 / Releases
26
-
27
- ### v1.3.2
28
-
29
- **新增 · 顶栏「📂 文件」工作区浏览器 + Word 真实预览**:顶栏「📂文件」打开工作区/全部文件浏览,按文件夹分组;点文件名或「预览」在面板内预览。Word(`.docx`)走 `docx-preview` 浏览器端真实渲染(所见即所得,无需服务端转换),并随包打包前端库 `client/vendor`(docx-preview / jszip)。
30
-
31
- **优化 · 两层关闭**:预览某文件时「✕关闭」/ Esc / 预览页自带「关闭」都回到文件列表,仅列表根部才整体退出面板;头部新增「←返回」按钮。Word 预览页也补上自带「✕关闭」,与 md 预览一致的两层关闭。
32
-
33
- **新增 · PPT 真实预览(PptxViewJS)**:`.pptx` 也走浏览器端真实渲染(Canvas 逐页渲染、可翻页),与 docx 一致;随包打包 `client/vendor`(pptxviewjs / chart.js)。**优化 · 预览页固定顶栏**:Word / PPT / md 预览页顶部「下载 / ✕关闭」工具栏改为 sticky,滚动文档/幻灯片时不再被滚走。
34
-
35
- ### v1.3.0
36
-
37
- **新增 · 拖放上传**:拖文件到网页任意位置松手即附加为「待发送」卡片;支持 `md / docx / xlsx / pptx / pdf / txt / csv` 及 `png / jpg / webp / gif`;与回形针同一条上传管线;拖放时全屏虚线投掷遮罩。
38
-
39
- **🐛 修复**:消除核心"仅支持 PNG/JPG/WebP/GIF"误报——捕获阶段接管文件拖放。
40
-
41
- **兼容性**:仅对真正拖入文件生效;拖文本/链接不受影响;标准浏览器事件,多设备通用。
42
-
43
- ## Turn ruler / 轮次导航
44
-
45
- - 桌面端:会话右侧 3 个比例刻度点,悬停打开「历史提问」预览窗
46
- - 预览窗:列出全部已加载轮次的标题;光标悬停点亮该行,点击行以蓝色标记并定位主会话
47
- - 滚动到预览窗顶部自动加载更早历史(内容锚定恢复焦点,无震动、不跳跃);手机端触摸滚动已做性能优化
48
- - 手机端:右边缘竖向把手点击打开预览窗(居中弹窗,✕ 关闭)
49
-
50
26
  ## Install / 安装
51
27
 
52
28
  > **目录约定**:插件放 `$DSH_HOME/plugins/dsh-long-plugins`,DSH 运行脚本(`bin`)放 `$DSH_HOME/bin`,都别放工作目录。你的**工作目录**(名字任意)由用户指定,其下 `upload` 为上传根(`DSH_UPLOAD_DIR`)。目录缺失用 `mkdir -p` 补建。
package/dsh.plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-long-plugins",
3
- "description": "Merged DSH web plugins: upload manager (drag-and-drop attach any file to the message), workspace output files, skill docs, account balance, Markdown-to-Word (md2docx), polished file preview, and an auto-repair install for DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink). 一个插件整合 DSH Web 的常用增强:上传管理(拖放上传:拖任意文件到会话框直接附加)、工作区「输出文件」面板、技能文档浏览、账户余额显示、Markdown 转 Word(md2docx);并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。",
4
- "version": "1.3.2",
3
+ "description": "Merged DSH web plugins: upload manager (drag-and-drop attach any file to the message), workspace output files, skill docs, account balance, Markdown-to-Word (md2docx), and polished file preview (Word & PowerPoint real preview with zoom/pan, rendered Markdown), plus an auto-repair install for DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink). | 一个插件整合 DSH Web 的常用增强:上传管理(拖放上传:拖任意文件到会话框直接附加)、工作区「输出文件」面板、技能文档浏览、账户余额显示、Markdown 转 Word(md2docx)、Word/PowerPoint 真实预览(可缩放、翻页);并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。",
4
+ "version": "1.3.5",
5
5
  "entry": {
6
6
  "name": "dsh-long-plugins",
7
7
  "inject": [
package/lib/index.js CHANGED
@@ -971,20 +971,29 @@ export function createHandlers(options = {}) {
971
971
  <title>预览 - ${escapeHtml(name)}</title>
972
972
  <style>
973
973
  body{margin:0;background:#313b48;color:#1f2937}
974
- #container{padding:16px 0}
974
+ #container{padding:16px 0;overflow:auto}
975
975
  /* docx-preview 分页:每页一张"纸",页间留间隙(breakPages 模式下 .docx-wrapper 内每个 .docx 是一页) */
976
976
  #container .docx-wrapper{background:transparent;padding:0;margin:0}
977
977
  #container .docx-wrapper > .docx,
978
978
  #container .docx-wrapper > section.docx,
979
- #container .docx-wrapper section.docx{background:#fff;box-shadow:0 2px 12px rgba(0,0,0,.28);max-width:900px;margin:0 auto 24px;padding:56px 64px;box-sizing:border-box}
979
+ #container .docx-wrapper section.docx{background:#fff;box-shadow:0 2px 12px rgba(0,0,0,.28);max-width:900px;margin:0 0 24px;padding:56px 64px;box-sizing:border-box}
980
980
  #container .docx-wrapper > .docx{min-height:1100px}
981
981
  #container img{max-width:100%}
982
+ #container ._dsh-docx-stage{width:max-content !important;display:block !important}
983
+ #container ._dsh-docx-stage section.docx,
984
+ #container ._dsh-docx-stage .docx,
985
+ #container > .docx{margin:0 0 24px !important}
982
986
  </style>
983
987
  </head><body>
984
- <div style="position:sticky;top:0;z-index:20;display:flex;gap:8px;padding:10px 14px;align-items:center;background:#1a2530">
985
- <strong style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#e5e7eb">${escapeHtml(name)}</strong>
986
- <a class="btn" href="${downloadHref}" download style="padding:6px 12px;border:1px solid #2c3a47;border-radius:8px;color:#e5e7eb;text-decoration:none;font-size:13px">下载</a>
987
- <button type="button" onclick="closePreview()" style="padding:6px 12px;border:1px solid #2c3a47;border-radius:8px;color:#e5e7eb;background:transparent;text-decoration:none;font-size:13px;cursor:pointer">✕ 关闭</button>
988
+ <div style="position:sticky;top:0;z-index:20;display:flex;gap:6px;padding:8px 12px;align-items:center;flex-wrap:wrap;background:#1a2530">
989
+ <strong style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#e5e7eb;font-size:13px">${escapeHtml(name)}</strong>
990
+ <span style="display:flex;gap:4px;align-items:center;color:#9ca3af;font-size:12px">
991
+ <button type="button" title="缩小" onclick="zoomBy(0.8)" style="padding:4px 9px;border:1px solid #2c3a47;border-radius:7px;color:#e5e7eb;background:transparent;font-size:12px;cursor:pointer">−</button>
992
+ <button type="button" title="放大" onclick="zoomBy(1.25)" style="padding:4px 9px;border:1px solid #2c3a47;border-radius:7px;color:#e5e7eb;background:transparent;font-size:12px;cursor:pointer">+</button>
993
+ <button type="button" title="适合宽度" onclick="zoomFit()" style="padding:4px 9px;border:1px solid #2c3a47;border-radius:7px;color:#e5e7eb;background:transparent;font-size:12px;cursor:pointer">适合</button>
994
+ </span>
995
+ <a class="btn" href="${downloadHref}" download style="padding:5px 12px;border:1px solid #2c3a47;border-radius:8px;color:#e5e7eb;text-decoration:none;font-size:13px">下载</a>
996
+ <button type="button" onclick="closePreview()" style="padding:5px 12px;border:1px solid #2c3a47;border-radius:8px;color:#e5e7eb;background:transparent;text-decoration:none;font-size:13px;cursor:pointer">✕ 关闭</button>
988
997
  </div>
989
998
  <div id="container"><div style="padding:40px;text-align:center;color:#999">加载中…</div></div>
990
999
  <script src="${assetBase}?f=jszip.min.js"></script>
@@ -1002,6 +1011,34 @@ function closePreview() {
1002
1011
  window.close();
1003
1012
  }
1004
1013
  const c=document.getElementById('container');
1014
+ // docx 按纸张固定宽度渲染,手机上屏窄。这里用 transform:scale(统一缩放,不破坏内部绝对定位
1015
+ // 排版,不会像 CSS zoom 那样叠字)。默认「适合宽度」整页完整显示,可放大读数。
1016
+ var zoom=1, fitMode=true;
1017
+ function dw(){
1018
+ // 文档页可能在 .docx-wrapper / .docx-wrap / 或直接 #container 里。取承载页面的元素;
1019
+ // 若直接在 #container,就包一层,避免缩放影响容器自身。
1020
+ var host=c.querySelector('.docx-wrapper, .docx-wrap');
1021
+ if(!host){ var p=c.querySelector('section.docx, .docx'); host=p? p.parentElement : c; }
1022
+ if(host && host===c){
1023
+ var wrap=document.createElement('div'); wrap.className='_dsh-docx-stage';
1024
+ while(c.firstChild) wrap.appendChild(c.firstChild);
1025
+ c.appendChild(wrap); host=wrap;
1026
+ }
1027
+ if(host){ host.style.width='max-content'; host.style.margin='0 auto'; }
1028
+ return host || c;
1029
+ }
1030
+ function applyZoom(){
1031
+ var w=dw(); if(!w) return;
1032
+ w.style.transformOrigin='top left';
1033
+ w.style.transform='scale('+zoom+')';
1034
+ }
1035
+ function zoomFit(){
1036
+ var page=c.querySelector('section.docx, .docx'); if(!page) return;
1037
+ var natW=page.offsetWidth||1; var target=c.clientWidth||1;
1038
+ zoom=Math.min(1, target/natW); fitMode=true; applyZoom();
1039
+ }
1040
+ function zoom100(){ zoom=1; fitMode=false; applyZoom(); }
1041
+ function zoomBy(f){ zoom=Math.min(8, Math.max(0.05, zoom*f)); fitMode=false; applyZoom(); }
1005
1042
  (async()=>{
1006
1043
  try{
1007
1044
  const r=await fetch(${JSON.stringify(inlineHref)}, {cache:'no-store'});
@@ -1010,8 +1047,10 @@ const c=document.getElementById('container');
1010
1047
  c.innerHTML='';
1011
1048
  // styleContainer 传 null:docx-preview 用自带样式。分页靠下方 .docx-wrapper > .docx 的纸张 CSS 控制。
1012
1049
  await docx.renderAsync(buf, c, null, {inWrapper:true, breakPages:true, ignoreLastRenderedPageBreak:false, experimental:true, className:'docx', useBase64URL:false});
1050
+ zoomFit(); // 默认「适合宽度」:整页等比缩放(行距/字号比例按 word 原样),可再放大读数
1013
1051
  }catch(e){ c.innerHTML='<p style="color:#dc2626;padding:20px">渲染失败:'+(e&&e.message||e)+'</p>'; }
1014
1052
  })();
1053
+ window.addEventListener('resize', function(){ try{ if(fitMode) zoomFit(); else applyZoom(); }catch(e){} });
1015
1054
  </script>
1016
1055
  </body></html>`);
1017
1056
  } catch (error) {
@@ -1076,14 +1115,26 @@ const c=document.getElementById('container');
1076
1115
  .bar strong{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#e5e7eb;font-size:13px}
1077
1116
  .bar button,.bar a{padding:6px 12px;border:1px solid #2c3a47;border-radius:8px;background:transparent;color:#e5e7eb;text-decoration:none;font-size:13px;cursor:pointer;white-space:nowrap}
1078
1117
  .bar button:disabled{opacity:.45;cursor:default}
1079
- #stage{display:flex;align-items:center;justify-content:center;padding:56px 22px 48px;min-height:calc(100vh - 60px)}
1080
- #stage canvas{display:block;max-width:100%;max-height:calc(100vh - 150px);background:#fff;border-radius:8px;box-shadow:0 4px 22px rgba(0,0,0,.45)}
1118
+ #stage{display:block;overflow:auto;padding:20px 16px 44px;min-height:calc(100vh - 60px)}
1119
+ #stage canvas{display:block;margin:0 auto;background:#fff;border-radius:8px;box-shadow:0 4px 22px rgba(0,0,0,.45)}
1081
1120
  #status{font-size:12px;color:#9ca3af;min-width:70px;text-align:center}
1082
1121
  #msg{color:#9ca3af}
1122
+ /* 电脑预览器式左右翻页箭头:浮在幻灯片两侧 */
1123
+ .pv-arrow{position:fixed;top:50%;transform:translateY(-50%);z-index:30;width:48px;height:48px;border-radius:50%;border:1px solid rgba(255,255,255,.28);background:rgba(18,28,42,.55);color:#fff;font-size:26px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;user-select:none}
1124
+ .pv-arrow:hover{background:rgba(45,66,95,.85)}
1125
+ .pv-arrow:disabled{opacity:.28;cursor:default}
1126
+ .pv-prev{left:10px}
1127
+ .pv-next{right:10px}
1128
+ @media (max-width:767px){ .pv-arrow{width:40px;height:40px;font-size:22px} }
1083
1129
  </style>
1084
1130
  </head><body>
1085
1131
  <div class="bar">
1086
1132
  <strong>${escapeHtml(name)}</strong>
1133
+ <span style="display:flex;gap:4px;align-items:center">
1134
+ <button type="button" title="缩小" onclick="zoomBy(0.8)">−</button>
1135
+ <button type="button" title="放大" onclick="zoomBy(1.25)">+</button>
1136
+ <button type="button" title="适合宽度" onclick="zoomFit()">适合</button>
1137
+ </span>
1087
1138
  <button type="button" id="prev" disabled>‹ 上一页</button>
1088
1139
  <span id="status">— / —</span>
1089
1140
  <button type="button" id="next" disabled>下一页 ›</button>
@@ -1091,6 +1142,8 @@ const c=document.getElementById('container');
1091
1142
  <button type="button" onclick="closePreview()">✕ 关闭</button>
1092
1143
  </div>
1093
1144
  <div id="stage"><div id="msg">加载中…</div><canvas id="canvas" style="display:none"></canvas></div>
1145
+ <button type="button" class="pv-arrow pv-prev" id="prevOverlay" title="上一页" disabled>‹</button>
1146
+ <button type="button" class="pv-arrow pv-next" id="nextOverlay" title="下一页" disabled>›</button>
1094
1147
  <script src="${assetBase}?f=jszip.min.js"></script>
1095
1148
  <script src="${assetBase}?f=chart.umd.min.js"></script>
1096
1149
  <script src="${assetBase}?f=pptxviewjs.min.js"></script>
@@ -1105,14 +1158,34 @@ const stage=document.getElementById('stage');
1105
1158
  const msg=document.getElementById('msg');
1106
1159
  const prevBtn=document.getElementById('prev');
1107
1160
  const nextBtn=document.getElementById('next');
1161
+ const prevOverlay=document.getElementById('prevOverlay');
1162
+ const nextOverlay=document.getElementById('nextOverlay');
1108
1163
  const status=document.getElementById('status');
1109
1164
  let viewer=null,total=0;
1165
+ var zoom=1, fitMode=true;
1166
+ // 幻灯片缩放:控制 canvas 的 CSS 显示尺寸等比放大/缩小(transform 对 canvas 容易叠字/错位,
1167
+ // 用 CSS width/height 更稳)。默认「适合宽度」看整页,可放大读数。
1168
+ function applyZoom(){
1169
+ var nw=canvas.width||1280, nh=canvas.height||720;
1170
+ canvas.style.width=Math.round(nw*zoom)+'px';
1171
+ canvas.style.height=Math.round(nh*zoom)+'px';
1172
+ }
1173
+ function zoomFit(){
1174
+ var nw=canvas.width||1280;
1175
+ // 用「内容区宽度」(clientWidth - 左右 padding),否则 canvas 会多出 padding 宽度、造成横向溢出,
1176
+ // 拖到手势里「有溢出=已放大」的误判,导致滑动翻页失效。
1177
+ var cs=getComputedStyle(stage); var pl=parseFloat(cs.paddingLeft)||0, pr=parseFloat(cs.paddingRight)||0;
1178
+ var t=(stage.clientWidth-pl-pr)||1;
1179
+ zoom=Math.min(1, t/nw); fitMode=true; applyZoom();
1180
+ }
1181
+ function zoom100(){ zoom=1; fitMode=false; applyZoom(); }
1182
+ function zoomBy(f){ zoom=Math.min(2,Math.max(0.05,zoom*f)); fitMode=false; applyZoom(); }
1110
1183
  function update(){
1111
1184
  if(!viewer)return;
1112
1185
  const cur=viewer.getCurrentSlideIndex();
1113
1186
  status.textContent='第 '+(cur+1)+' / '+total+' 页';
1114
- prevBtn.disabled=cur<=0;
1115
- nextBtn.disabled=cur>=total-1;
1187
+ prevBtn.disabled=cur<=0; prevOverlay.disabled=cur<=0;
1188
+ nextBtn.disabled=cur>=total-1; nextOverlay.disabled=cur>=total-1;
1116
1189
  }
1117
1190
  (async()=>{
1118
1191
  try{
@@ -1121,12 +1194,13 @@ function update(){
1121
1194
  const blob=await r.blob();
1122
1195
  msg.style.display='none';
1123
1196
  canvas.style.display='block';
1124
- // 给一个确定的初始尺寸,确保库能正常渲染;显示由 CSS max-width/max-height 等比缩放
1125
- canvas.width=1280; canvas.height=720;
1197
+ // 给一个确定的初始尺寸,确保库能正常渲染;显示由 CSS 缩放(分辨率取高些,放大时更清晰)
1198
+ canvas.width=1920; canvas.height=1080;
1126
1199
  viewer=new window.PptxViewJS.PPTXViewer({canvas});
1127
1200
  await viewer.loadFile(new File([blob],${JSON.stringify(name)},{type:'application/vnd.openxmlformats-officedocument.presentationml.presentation'}));
1128
1201
  await viewer.render();
1129
1202
  total=viewer.getSlideCount();
1203
+ zoomFit();
1130
1204
  update();
1131
1205
  }catch(e){
1132
1206
  msg.style.display='';
@@ -1136,6 +1210,9 @@ function update(){
1136
1210
  })();
1137
1211
  prevBtn.addEventListener('click',async()=>{if(viewer){await viewer.previousSlide();update();}});
1138
1212
  nextBtn.addEventListener('click',async()=>{if(viewer){await viewer.nextSlide();update();}});
1213
+ prevOverlay.addEventListener('click',async()=>{if(viewer){await viewer.previousSlide();update();}});
1214
+ nextOverlay.addEventListener('click',async()=>{if(viewer){await viewer.nextSlide();update();}});
1215
+ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else applyZoom(); }catch(e){} });
1139
1216
  </script>
1140
1217
  </body></html>`);
1141
1218
  } catch (error) {
@@ -1659,8 +1736,8 @@ export async function apply(ctx, config = {}) {
1659
1736
  // 默认脚本随插件包分发(lib/md2docx.py),换机器也可靠;可用 config.md2docxScript 覆盖。
1660
1737
  const PACKAGE_DIR = dirname(fileURLToPath(import.meta.url));
1661
1738
  const MD2DOCX_SCRIPT = resolve(config.md2docxScript ?? join(PACKAGE_DIR, "md2docx.py"));
1662
- const runScript = (args) => new Promise((resolvePromise) => {
1663
- const child = spawn("python3", [MD2DOCX_SCRIPT, ...args], { stdio: ["ignore", "pipe", "pipe"] });
1739
+ const runScript = (script, args) => new Promise((resolvePromise) => {
1740
+ const child = spawn("python3", [script, ...args], { stdio: ["ignore", "pipe", "pipe"] });
1664
1741
  let stdout = "", stderr = "";
1665
1742
  child.stdout.on("data", (d) => { stdout += d.toString(); });
1666
1743
  child.stderr.on("data", (d) => { stderr += d.toString(); });
@@ -1713,7 +1790,7 @@ export async function apply(ctx, config = {}) {
1713
1790
  async execute(args) {
1714
1791
  const inPath = resolve(String(args.input ?? ""));
1715
1792
  const outPath = args.output ? resolve(String(args.output)) : inPath.replace(/\.md$/i, ".docx");
1716
- const result = await runScript([inPath, outPath]);
1793
+ const result = await runScript(MD2DOCX_SCRIPT, [inPath, outPath]);
1717
1794
  if (!result.ok) {
1718
1795
  return { ok: false, error: (result.stderr || result.stdout || String(result.error)).trim() || `md2docx failed (exit ${result.code})` };
1719
1796
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-long-plugins",
3
- "version": "1.3.2",
4
- "description": "Merged DSH web plugins: upload manager (drag-and-drop attach any file to the message), workspace output files, skill docs, account balance, Markdown-to-Word (md2docx), polished file preview, and an auto-repair install for DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink). 一个插件整合 DSH Web 的常用增强:上传管理(拖放上传:拖任意文件到会话框直接附加)、工作区「输出文件」面板、技能文档浏览、账户余额显示、Markdown 转 Word(md2docx);并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。",
3
+ "version": "1.3.5",
4
+ "description": "Merged DSH web plugins: upload manager (drag-and-drop attach any file to the message), workspace output files, skill docs, account balance, Markdown-to-Word (md2docx), and polished file preview (Word & PowerPoint real preview with zoom/pan, rendered Markdown), plus an auto-repair install for DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink). | 一个插件整合 DSH Web 的常用增强:上传管理(拖放上传:拖任意文件到会话框直接附加)、工作区「输出文件」面板、技能文档浏览、账户余额显示、Markdown 转 Word(md2docx)、Word/PowerPoint 真实预览(可缩放、翻页);并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "main": "lib/index.js",