@copylee/dsh-office 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
  | 不需要窗口在前台 | 修改不靠鼠标键盘,Office 窗口被挡住或在后台也照常进行,你可以同时用电脑做别的事 |
16
16
  | 跟随与静默 | 默认“跟随”:AI 改到哪里,窗口自动滚动到哪里(Word 滚到那一段,Excel 滚到那片单元格,PowerPoint 切到那一页),不动你的光标和选区。关闭即静默执行,不动你的视图 |
17
17
  | 逐字写入 | 文字分小段写出,像打字一样出现,表格逐行填入,而不是整块贴上去。每段最多多花约 1 秒,可关闭 |
18
- | 迷你卡片 | AI 编辑时屏幕右下角出现一张小卡片:正在改哪个文档、改到第几项,带“跟随”“逐字”两个开关,点一下立即生效(正在进行的这一批也跟着变)。可拖动,不抢焦点,AI 停手几秒后自动消失 |
18
+ | 迷你卡片 | AI 打开或编辑文档时屏幕右下角出现一张小卡片:正在改哪个文档、改到第几项,带“跟随”“逐字”两个开关,点一下立即生效(正在进行的这一批也跟着变)。点“跟随”会把文档窗口带到前台并开始跟随;你切到别的窗口后它自动熄灭,再点一次回来。可拖动,不抢焦点,AI 停手几秒后自动消失 |
19
19
  | Word 原生公式 | AI 在文字里用 `$...$`(行内)和 `$$...$$`(单独一行)写 LaTeX,插件转成 Word 原生公式(分式、根号、上下标、希腊字母、求和、积分、上划线等常用写法);单独一行的公式末尾加 `\tag{1}` 即在右侧对齐编号 |
20
20
  | 填模板 | 报告模板常把正文放在大单元格里。这类表格会按段落展开给模型看,正文、公式、表格都写进单元格里面,而不是堆到文档末尾;新写的正文沿用旁边正文的字体、字号和行距 |
21
21
  | 规范的图表题注 | 插入表格或图片时给出题注,插件按规范排:自动编号(“表 1”“图 1”,是 Word 题注域,增删后自动重排)、居中、表题在上、图题在下;图表前后留出段间距,图片居中 |
@@ -78,7 +78,7 @@ AI 只有在调用保存时才写入文件,不会替你关闭文档。
78
78
  |---|---|---|
79
79
  | 跟随 AI 的修改位置 | 开 | 窗口自动滚动到 AI 正在修改的位置;关闭为静默执行 |
80
80
  | 逐字写入 | 开 | 文字像打字一样逐步出现;关闭后写得最快 |
81
- | 迷你卡片 | 开 | AI 编辑时在右下角显示带“跟随”“逐字”开关的小卡片。在卡片上切换过的开关,到 DSH 重启前以卡片为准 |
81
+ | 迷你卡片 | 开 | AI 编辑时在右下角显示带“跟随”“逐字”开关的小卡片。在卡片上切换过的开关(包括你离开文档窗口后自动熄灭的“跟随”),到 DSH 重启前以卡片为准 |
82
82
  | 交付前整体视觉检查 | 开 | 保存时自动把各页渲染图交给 AI 检查;会多用一些 token |
83
83
  | 优先在真实 Office 里操作 | 开 | DSH 桌面版自带 office-docx / office-xlsx / office-pptx 技能,用脚本生成文件。开启后,AI 第一次想加载这些技能时会被引回本插件(对应的 Office 应用已安装时才拦);它再次请求时放行 |
84
84
  | 打开文档时显示到前台 | 开 | 关闭后文档仍会打开,只是不抢当前窗口 |
@@ -119,6 +119,20 @@ class Card : Form
119
119
  readonly System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
120
120
 
121
121
  [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr handle, int command);
122
+ [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow();
123
+ [DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr handle);
124
+ [DllImport("user32.dll")] static extern bool IsIconic(IntPtr handle);
125
+
126
+ /// The user is looking at the document: its window is the foreground one.
127
+ static bool Watching()
128
+ {
129
+ IntPtr doc = Program.DocWindow;
130
+ return doc != IntPtr.Zero && GetForegroundWindow() == doc;
131
+ }
132
+
133
+ // Following means "keep the document in front of me and scroll to the edits". It holds while the user
134
+ // stays in that window; once they go elsewhere it switches itself off, and the button brings them back.
135
+ bool wasWatching, lit;
122
136
 
123
137
  protected override bool ShowWithoutActivation { get { return true; } }
124
138
 
@@ -147,7 +161,21 @@ class Card : Form
147
161
  Location = new Point(area.Right - Width - S(18), area.Bottom - Height - S(18));
148
162
  using (System.Drawing.Drawing2D.GraphicsPath path = Rounded(new Rectangle(0, 0, Width, Height), S(10))) Region = new Region(path);
149
163
  timer.Interval = 500;
150
- timer.Tick += delegate { if (Visible && (DateTime.UtcNow - shown).TotalSeconds > 6) Hide(); };
164
+ timer.Tick += delegate
165
+ {
166
+ bool watching = Watching();
167
+ if (watching) wasWatching = true;
168
+ else if (wasWatching && Program.Following)
169
+ {
170
+ // The user left the document for another window.
171
+ wasWatching = false;
172
+ Program.Following = false;
173
+ FollowChosen = true;
174
+ }
175
+ bool nowLit = Program.Following && watching;
176
+ if (nowLit != lit) { lit = nowLit; Invalidate(); }
177
+ if (Visible && (DateTime.UtcNow - shown).TotalSeconds > 6) Hide();
178
+ };
151
179
  timer.Start();
152
180
  }
153
181
 
@@ -187,7 +215,7 @@ class Card : Form
187
215
  {
188
216
  int right = Width - S(10);
189
217
  Chip(g, font, "逐字", Program.Typing, ref right, out typingBox);
190
- Chip(g, font, "跟随", Program.Following, ref right, out followBox);
218
+ Chip(g, font, "跟随", Program.Following && Watching(), ref right, out followBox);
191
219
  using (SolidBrush dot = new SolidBrush(Color.FromArgb(217, 119, 87))) g.FillEllipse(dot, S(12), (Height - S(8)) / 2, S(8), S(8));
192
220
  Rectangle text = new Rectangle(S(26), 0, right - S(30), Height);
193
221
  TextRenderer.DrawText(g, line, font, text, Color.FromArgb(235, 235, 240), TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix);
@@ -208,7 +236,23 @@ class Card : Form
208
236
  {
209
237
  pressed = false;
210
238
  if (dragged) return;
211
- if (followBox.Contains(e.Location)) { Program.Following = !Program.Following; FollowChosen = true; }
239
+ if (followBox.Contains(e.Location))
240
+ {
241
+ FollowChosen = true;
242
+ if (Program.Following && Watching()) Program.Following = false;
243
+ else
244
+ {
245
+ // Bring the document to the front and follow from here on.
246
+ Program.Following = true;
247
+ wasWatching = true;
248
+ IntPtr doc = Program.DocWindow;
249
+ if (doc != IntPtr.Zero)
250
+ {
251
+ if (IsIconic(doc)) ShowWindow(doc, 9);
252
+ SetForegroundWindow(doc);
253
+ }
254
+ }
255
+ }
212
256
  else if (typingBox.Contains(e.Location)) { Program.Typing = !Program.Typing; TypingChosen = true; }
213
257
  shown = DateTime.UtcNow;
214
258
  Invalidate();
@@ -560,6 +604,7 @@ static class Program
560
604
  }
561
605
  Dictionary<string, object> info = Info(kind, doc, Active(kind, app));
562
606
  info["how"] = how;
607
+ Remember(doc);
563
608
  if (a.Flag("card", false))
564
609
  {
565
610
  if (!cardStarted) { cardStarted = true; Card.Start(); }
@@ -680,6 +725,14 @@ static class Program
680
725
 
681
726
  /// Scroll the window to where the agent is working (off = silent mode: the user's view is left alone).
682
727
  public static volatile bool Following;
728
+ /// The window of the document being worked on (0 when unknown), for the card to bring forward.
729
+ public static IntPtr DocWindow = IntPtr.Zero;
730
+
731
+ static void Remember(dynamic doc)
732
+ {
733
+ try { DocWindow = new IntPtr(Convert.ToInt64(doc.Windows[1].Hwnd)); }
734
+ catch (Exception) { DocWindow = IntPtr.Zero; }
735
+ }
683
736
  /// Write text a few characters at a time, the way a person types, instead of all at once.
684
737
  public static volatile bool Typing;
685
738
 
@@ -1793,6 +1846,7 @@ static class Program
1793
1846
  if (!Card.FollowChosen) Following = a.Flag("follow", false);
1794
1847
  if (!Card.TypingChosen) Typing = a.Flag("typing", false);
1795
1848
  bool card = a.Flag("card", false);
1849
+ Remember(doc);
1796
1850
  if (card && !cardStarted) { cardStarted = true; Card.Start(); }
1797
1851
  string docName = (string)doc.Name;
1798
1852
  dynamic undo = null;
package/lib/client.js CHANGED
@@ -491,7 +491,7 @@ window.__ModuleLoader__.load({
491
491
  } }, !app.installed ? "未安装" : !app.running ? "已安装,未运行(需要时自动启动)" : app.documents.length === 0 ? "运行中,没有打开的文档" : `运行中:${app.documents.map((doc) => doc.name + (doc.saved ? "" : "(未保存)")).join("、")}`))), h("p", { style: S.hint }, "需要本机装有微软 Office。Word 里 AI 的一批修改可以用一次 Ctrl+Z 撤回;Excel 和 PowerPoint 的修改无法用 Ctrl+Z 撤回。你正在单元格里输入或开着对话框时,AI 会等你。")), h("section", { style: S.card }, h("h3", { style: S.cardTitle }, "行为"), h("div", { style: S.toggleRow }, h("div", { style: S.toggleText }, "跟随 AI 的修改位置", h("span", { style: {
492
492
  ...S.hint,
493
493
  fontWeight: 400
494
- } }, "AI 改到哪里,窗口就自动滚动到哪里(Word 滚到那一段,Excel 滚到那片单元格,PowerPoint 切到那一页),不用自己翻找。关闭即静默执行:AI 照常修改,但不动你的视图。")), h(Switch, {
494
+ } }, "AI 改到哪里,窗口就自动滚动到哪里(Word 滚到那一段,Excel 滚到那片单元格,PowerPoint 切到那一页),不用自己翻找。关闭即静默执行:AI 照常修改,但不动你的视图。想看时点迷你卡片上的“跟随”:文档窗口被带到前台并开始跟随;你切到别的窗口后它自动熄灭,再点一次回来。")), h(Switch, {
495
495
  checked: settings.follow,
496
496
  disabled,
497
497
  label: "跟随 AI 的修改位置",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@copylee/dsh-office",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "DeepSeek Harness Office 插件(Windows):AI 直接在你打开的 Word / Excel / PowerPoint 里改文档,改动实时出现在窗口中,你可以同时编辑;读结构、批量编辑、渲染成图核对、保存。",
5
5
  "type": "module",
6
6
  "author": "copylee",