dsh-doc-assistant 0.1.18 → 0.1.19

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
@@ -127,6 +127,11 @@
127
127
 
128
128
  ## 安装
129
129
 
130
+ ### 书架标题栏与自动构建(0.1.19)
131
+
132
+ - 文档预览左栏的“项目”改为“书架”。书架总览移除独立标题行,书架数、文档数和刷新按钮统一放在顶部标题栏。
133
+ - 从项目目录执行 `npm publish` 会通过 `prepublishOnly` 自动运行 `npm run build`。发布前仍需更新版本号。
134
+
130
135
  ### 通用排版保护与并行生成(0.1.18)
131
136
 
132
137
  - 不同选区可以同时润色、扩写;每个任务独立保留选区原文、位置、模型及处理状态,完成顺序不影响结果。生成期间不会写入文档,接受时按文档逐次写入。
@@ -202,7 +207,7 @@
202
207
  - 点击发送后立即显示问题和引文,再显示「思考中」;失败时保留问题和引用供重新编辑。
203
208
 
204
209
  更新安装包后请**完全退出 DSH 再重新打开**,macOS 使用 `⌘Q`;仅关闭窗口可能仍在运行旧版。
205
- 可在插件设置 → 关于确认运行版本为 `0.1.18`。
210
+ 可在插件设置 → 关于确认运行版本为 `0.1.19`。
206
211
 
207
212
  ### Word 选区完整性(0.1.5)
208
213
 
package/lib/client.js CHANGED
@@ -12,7 +12,7 @@
12
12
  * ./shelf <- src/client/70-shelf.js
13
13
  * ./boot <- src/client/90-boot.js
14
14
  *
15
- * Source digest: d5cb4638b3c119ba
15
+ * Source digest: c658d39f146f3f3a
16
16
  *
17
17
  * This is the hand-written lazy-CJS bundle the DSH client module system
18
18
  * expects: it calls `window.__ModuleLoader__.load({ id, factory })` with the
@@ -2187,7 +2187,7 @@ window.__ModuleLoader__.load({
2187
2187
  const DISPLAY_NAME = '企业文档助手';
2188
2188
 
2189
2189
  /** 客户端版本号,与 package.json 的 version 同步维护(`/state` 不回传版本时用它)。 */
2190
- const CLIENT_VERSION = '0.1.18';
2190
+ const CLIENT_VERSION = '0.1.19';
2191
2191
 
2192
2192
  /** 设置窗口的分区。 */
2193
2193
  const SECTIONS = [
@@ -7346,6 +7346,7 @@ window.__ModuleLoader__.load({
7346
7346
  const [shelfDialogOpen, setShelfDialogOpen] = React.useState(false);
7347
7347
  /** 书架重新拉数据的信号(上传 / 生成封面后 +1)。 */
7348
7348
  const [shelfReloadKey, setShelfReloadKey] = React.useState(0);
7349
+ const [shelfSummary, setShelfSummary] = React.useState({ projects: 0, documents: 0, loading: true });
7349
7350
  const [uploadProgress, setUploadProgress] = React.useState(null);
7350
7351
  const [uploadOutcome, setUploadOutcome] = React.useState(null);
7351
7352
  const uploadBusyRef = React.useRef(false);
@@ -8229,7 +8230,7 @@ window.__ModuleLoader__.load({
8229
8230
  // ---- 渲染:左栏(§17.6:顺序改为「大纲 → 文档树」,阅读时大纲是第一需要)
8230
8231
  const left = (!leftOpen || hideRail) ? null : h('aside', { key: 'left', className: P + 'Left', 'data-reader-rail': '1' }, [
8231
8232
  h('div', { key: 'proj', className: P + 'Section' }, [
8232
- h('div', { key: 't', className: P + 'SectionTitle' }, '项目'),
8233
+ h('div', { key: 't', className: P + 'SectionTitle' }, '书架'),
8233
8234
  projects.length === 0
8234
8235
  ? h('div', { key: 'e', className: P + 'Hint' }, '还没有书架。点右上角「+ 新建书架」。')
8235
8236
  : h('select', {
@@ -8636,6 +8637,8 @@ window.__ModuleLoader__.load({
8636
8637
  ]);
8637
8638
 
8638
8639
  const currentProject = projects.find((item) => item && item.id === projectId) || null;
8640
+ const shelfSummaryText = shelfSummary.loading && shelfSummary.projects === 0
8641
+ ? '正在载入书架…' : `${shelfSummary.projects} 个书架 · ${shelfSummary.documents} 份文档`;
8639
8642
 
8640
8643
  // ---- 渲染:顶栏(标题 + + 新建书架 + 右上角齿轮),§17.5
8641
8644
  const topBar = h('div', { key: 'top', className: cx(P + 'TopBar', P + 'DragBar'), 'data-shell-top': '1', 'data-window-drag': true, 'data-window-drag-bar': 'title' }, [
@@ -8655,6 +8658,10 @@ window.__ModuleLoader__.load({
8655
8658
  onClick: () => setLeftOpen(value => !value),
8656
8659
  }, h(PanelLeftIcon, { flipped: !leftOpen })) : null,
8657
8660
  h('span', { key: 'title', className: P + 'TopTitle', 'data-window-drag': true }, '企业文档助手'),
8661
+ screen === 'shelf' ? h('span', {
8662
+ key: 'shelf-summary', className: P + 'TopCrumb', 'data-shelf-summary': '1',
8663
+ title: shelfSummaryText, 'data-window-drag': true, 'aria-live': 'polite',
8664
+ }, h('span', { className: P + 'BarTitle' }, shelfSummaryText)) : null,
8658
8665
  screen === 'reader' && docName !== '未选择文档'
8659
8666
  ? h('span', { key: 'crumb', className: P + 'TopCrumb', title: docName, 'data-window-drag': true }, [
8660
8667
  h('span', { key: 'dot' }, '· '), h('span', { key: 'name', className: P + 'BarTitle' }, docName),
@@ -8670,6 +8677,14 @@ window.__ModuleLoader__.load({
8670
8677
  h('path', { key: 'pen', d: 'm7 9 1.5-.3L14 3.2 12.8 2 7.3 7.5 7 9Z' }),
8671
8678
  ])) : null,
8672
8679
  h('div', { key: 'grow', className: P + 'BarSpacer', 'data-window-drag': true, 'data-title-drag-blank': true, 'aria-hidden': true }),
8680
+ screen === 'shelf' && uploadText ? h('span', {
8681
+ key: 'shelf-busy', className: P + 'TopBusy', 'data-shelf-busy': '1',
8682
+ }, uploadText) : null,
8683
+ screen === 'shelf' ? h('button', {
8684
+ key: 'shelf-refresh', type: 'button', className: P + 'Btn', 'data-shelf-reload': '1',
8685
+ title: '重新载入书架', disabled: shelfSummary.loading,
8686
+ onClick: () => setShelfReloadKey(value => value + 1),
8687
+ }, '刷新') : null,
8673
8688
  h('button', {
8674
8689
  key: 'newShelf',
8675
8690
  type: 'button',
@@ -8723,6 +8738,7 @@ window.__ModuleLoader__.load({
8723
8738
  }, h(Shelf, {
8724
8739
  transport,
8725
8740
  reloadKey: shelfReloadKey,
8741
+ onSummaryChange: setShelfSummary,
8726
8742
  onOpenDoc: openFromShelf,
8727
8743
  onDocsRemoved: onShelfDocsRemoved,
8728
8744
  onAddDocs: (project) => {
@@ -9775,7 +9791,8 @@ window.__ModuleLoader__.load({
9775
9791
  * onOpenDoc(doc) 点某本书;doc = { projectId, relPath, title, format }
9776
9792
  * onAddDocs(project) 架内「+ 添加文档」
9777
9793
  * reloadKey 变化时重新拉数据(上传 / 新建书架后由上层 +1)
9778
- * busyText 顶栏显示的上传进度文案
9794
+ * onSummaryChange 将书架数量、文档数量和加载状态同步到工作区标题栏
9795
+ * busyText 上传进度;上传期间禁用添加文档按钮
9779
9796
  */
9780
9797
  function Shelf(props) {
9781
9798
  const p = props || {};
@@ -9972,21 +9989,11 @@ window.__ModuleLoader__.load({
9972
9989
 
9973
9990
  const totalBooks = racks.reduce((sum, rack) => sum + rack.books.length, 0);
9974
9991
 
9975
- const head = h('div', { key: 'head', className: P + 'Head' }, [
9976
- h('div', { key: 't', className: P + 'HeadTitle' }, '书架'),
9977
- h('div', { key: 'meta', className: P + 'HeadMeta' },
9978
- `${projects.length} 个书架 · ${totalBooks} 份文档`),
9979
- h('span', { key: 'grow', className: P + 'HeadSpacer' }),
9980
- p.busyText ? h('span', { key: 'busy', className: P + 'HeadBusy', 'data-shelf-busy': '1' }, p.busyText) : null,
9981
- h('button', {
9982
- key: 'reload',
9983
- type: 'button',
9984
- className: P + 'GhostBtn',
9985
- title: '重新载入书架',
9986
- 'data-shelf-reload': '1',
9987
- onClick: reload,
9988
- }, '刷新'),
9989
- ]);
9992
+ React.useEffect(() => {
9993
+ if (typeof p.onSummaryChange === 'function') p.onSummaryChange({
9994
+ projects: projects.length, documents: totalBooks, loading: state === 'loading',
9995
+ });
9996
+ }, [p.onSummaryChange, projects.length, totalBooks, state]);
9990
9997
 
9991
9998
  let body;
9992
9999
  if (state === 'loading' && projects.length === 0) {
@@ -10202,7 +10209,7 @@ window.__ModuleLoader__.load({
10202
10209
  className: P + 'Shelf',
10203
10210
  'data-shelf': '1',
10204
10211
  'data-shelf-selecting': selectMode ? '1' : undefined,
10205
- }, [head, noticeEl, selectBar, body, menuEl, confirmEl]);
10212
+ }, [noticeEl, selectBar, body, menuEl, confirmEl]);
10206
10213
  }
10207
10214
 
10208
10215
  // =========================================================================
@@ -10213,11 +10220,7 @@ window.__ModuleLoader__.load({
10213
10220
  .${P}Shelf{display:flex;flex-direction:column;height:100%;min-height:0;box-sizing:border-box;overflow:hidden;
10214
10221
  background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);
10215
10222
  font-family:var(--dsw-font-family,system-ui)}
10216
- .${P}Head{display:flex;align-items:center;gap:8px;flex:none;padding:12px 18px 8px}
10217
- .${P}HeadTitle{font-size:15px;font-weight:650}
10218
- .${P}HeadMeta{font-size:11px;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary))}
10219
10223
  .${P}HeadSpacer{flex:1;min-width:0}
10220
- .${P}HeadBusy{font-size:11px;color:var(--dsw-alias-brand-primary)}
10221
10224
  .${P}GhostBtn{border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);
10222
10225
  font:inherit;font-size:12px;padding:2px 9px;border-radius:var(--dsw-radius-sm,5px);cursor:pointer}
10223
10226
  .${P}GhostBtn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.12));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-doc-assistant",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "author": "stone086",
5
5
  "private": false,
6
6
  "description": "企业文档助手 (Enterprise Document Assistant) — a DSH plugin that turns the harness into a document workbench: project-scoped document library, an e-reader style three-column page (tree | document | AI chat), selection-to-ask, and AI rewrite shown as tracked-change revisions with accept/revert.",
@@ -23,6 +23,7 @@
23
23
  },
24
24
  "scripts": {
25
25
  "build": "node dev/build-client.mjs",
26
+ "prepublishOnly": "npm run build",
26
27
  "test": "node dev/harness.mjs && npm run test:regression",
27
28
  "test:regression": "node --test dev/review-regression.mjs dev/review-tool-regression.mjs dev/runtime-regression.mjs dev/word-selection-regression.mjs dev/expansion-regression.mjs dev/chat-revision-regression.mjs dev/office-editor-regression.mjs dev/document-watch-regression.mjs dev/ocr-regression.mjs dev/cover-regression.mjs dev/visual-context-regression.mjs dev/revision-boundary-regression.mjs dev/word-multipart-regression.mjs dev/compound-word-api-regression.mjs dev/legacy-word-regression.mjs dev/revision-rebase-regression.mjs dev/parallel-generation-host-regression.mjs dev/word-layout-regression.mjs dev/layout-warning-regression.mjs",
28
29
  "test:render": "node dev/render-test.mjs",
@@ -34,7 +34,7 @@ __define('./library', (module, exports, require) => {
34
34
  const DISPLAY_NAME = '企业文档助手';
35
35
 
36
36
  /** 客户端版本号,与 package.json 的 version 同步维护(`/state` 不回传版本时用它)。 */
37
- const CLIENT_VERSION = '0.1.18';
37
+ const CLIENT_VERSION = '0.1.19';
38
38
 
39
39
  /** 设置窗口的分区。 */
40
40
  const SECTIONS = [
@@ -3784,6 +3784,7 @@ __define('./reader', (module, exports, require) => {
3784
3784
  const [shelfDialogOpen, setShelfDialogOpen] = React.useState(false);
3785
3785
  /** 书架重新拉数据的信号(上传 / 生成封面后 +1)。 */
3786
3786
  const [shelfReloadKey, setShelfReloadKey] = React.useState(0);
3787
+ const [shelfSummary, setShelfSummary] = React.useState({ projects: 0, documents: 0, loading: true });
3787
3788
  const [uploadProgress, setUploadProgress] = React.useState(null);
3788
3789
  const [uploadOutcome, setUploadOutcome] = React.useState(null);
3789
3790
  const uploadBusyRef = React.useRef(false);
@@ -4667,7 +4668,7 @@ __define('./reader', (module, exports, require) => {
4667
4668
  // ---- 渲染:左栏(§17.6:顺序改为「大纲 → 文档树」,阅读时大纲是第一需要)
4668
4669
  const left = (!leftOpen || hideRail) ? null : h('aside', { key: 'left', className: P + 'Left', 'data-reader-rail': '1' }, [
4669
4670
  h('div', { key: 'proj', className: P + 'Section' }, [
4670
- h('div', { key: 't', className: P + 'SectionTitle' }, '项目'),
4671
+ h('div', { key: 't', className: P + 'SectionTitle' }, '书架'),
4671
4672
  projects.length === 0
4672
4673
  ? h('div', { key: 'e', className: P + 'Hint' }, '还没有书架。点右上角「+ 新建书架」。')
4673
4674
  : h('select', {
@@ -5074,6 +5075,8 @@ __define('./reader', (module, exports, require) => {
5074
5075
  ]);
5075
5076
 
5076
5077
  const currentProject = projects.find((item) => item && item.id === projectId) || null;
5078
+ const shelfSummaryText = shelfSummary.loading && shelfSummary.projects === 0
5079
+ ? '正在载入书架…' : `${shelfSummary.projects} 个书架 · ${shelfSummary.documents} 份文档`;
5077
5080
 
5078
5081
  // ---- 渲染:顶栏(标题 + + 新建书架 + 右上角齿轮),§17.5
5079
5082
  const topBar = h('div', { key: 'top', className: cx(P + 'TopBar', P + 'DragBar'), 'data-shell-top': '1', 'data-window-drag': true, 'data-window-drag-bar': 'title' }, [
@@ -5093,6 +5096,10 @@ __define('./reader', (module, exports, require) => {
5093
5096
  onClick: () => setLeftOpen(value => !value),
5094
5097
  }, h(PanelLeftIcon, { flipped: !leftOpen })) : null,
5095
5098
  h('span', { key: 'title', className: P + 'TopTitle', 'data-window-drag': true }, '企业文档助手'),
5099
+ screen === 'shelf' ? h('span', {
5100
+ key: 'shelf-summary', className: P + 'TopCrumb', 'data-shelf-summary': '1',
5101
+ title: shelfSummaryText, 'data-window-drag': true, 'aria-live': 'polite',
5102
+ }, h('span', { className: P + 'BarTitle' }, shelfSummaryText)) : null,
5096
5103
  screen === 'reader' && docName !== '未选择文档'
5097
5104
  ? h('span', { key: 'crumb', className: P + 'TopCrumb', title: docName, 'data-window-drag': true }, [
5098
5105
  h('span', { key: 'dot' }, '· '), h('span', { key: 'name', className: P + 'BarTitle' }, docName),
@@ -5108,6 +5115,14 @@ __define('./reader', (module, exports, require) => {
5108
5115
  h('path', { key: 'pen', d: 'm7 9 1.5-.3L14 3.2 12.8 2 7.3 7.5 7 9Z' }),
5109
5116
  ])) : null,
5110
5117
  h('div', { key: 'grow', className: P + 'BarSpacer', 'data-window-drag': true, 'data-title-drag-blank': true, 'aria-hidden': true }),
5118
+ screen === 'shelf' && uploadText ? h('span', {
5119
+ key: 'shelf-busy', className: P + 'TopBusy', 'data-shelf-busy': '1',
5120
+ }, uploadText) : null,
5121
+ screen === 'shelf' ? h('button', {
5122
+ key: 'shelf-refresh', type: 'button', className: P + 'Btn', 'data-shelf-reload': '1',
5123
+ title: '重新载入书架', disabled: shelfSummary.loading,
5124
+ onClick: () => setShelfReloadKey(value => value + 1),
5125
+ }, '刷新') : null,
5111
5126
  h('button', {
5112
5127
  key: 'newShelf',
5113
5128
  type: 'button',
@@ -5161,6 +5176,7 @@ __define('./reader', (module, exports, require) => {
5161
5176
  }, h(Shelf, {
5162
5177
  transport,
5163
5178
  reloadKey: shelfReloadKey,
5179
+ onSummaryChange: setShelfSummary,
5164
5180
  onOpenDoc: openFromShelf,
5165
5181
  onDocsRemoved: onShelfDocsRemoved,
5166
5182
  onAddDocs: (project) => {
@@ -594,7 +594,8 @@ __define('./shelf', (module, exports, require) => {
594
594
  * onOpenDoc(doc) 点某本书;doc = { projectId, relPath, title, format }
595
595
  * onAddDocs(project) 架内「+ 添加文档」
596
596
  * reloadKey 变化时重新拉数据(上传 / 新建书架后由上层 +1)
597
- * busyText 顶栏显示的上传进度文案
597
+ * onSummaryChange 将书架数量、文档数量和加载状态同步到工作区标题栏
598
+ * busyText 上传进度;上传期间禁用添加文档按钮
598
599
  */
599
600
  function Shelf(props) {
600
601
  const p = props || {};
@@ -791,21 +792,11 @@ __define('./shelf', (module, exports, require) => {
791
792
 
792
793
  const totalBooks = racks.reduce((sum, rack) => sum + rack.books.length, 0);
793
794
 
794
- const head = h('div', { key: 'head', className: P + 'Head' }, [
795
- h('div', { key: 't', className: P + 'HeadTitle' }, '书架'),
796
- h('div', { key: 'meta', className: P + 'HeadMeta' },
797
- `${projects.length} 个书架 · ${totalBooks} 份文档`),
798
- h('span', { key: 'grow', className: P + 'HeadSpacer' }),
799
- p.busyText ? h('span', { key: 'busy', className: P + 'HeadBusy', 'data-shelf-busy': '1' }, p.busyText) : null,
800
- h('button', {
801
- key: 'reload',
802
- type: 'button',
803
- className: P + 'GhostBtn',
804
- title: '重新载入书架',
805
- 'data-shelf-reload': '1',
806
- onClick: reload,
807
- }, '刷新'),
808
- ]);
795
+ React.useEffect(() => {
796
+ if (typeof p.onSummaryChange === 'function') p.onSummaryChange({
797
+ projects: projects.length, documents: totalBooks, loading: state === 'loading',
798
+ });
799
+ }, [p.onSummaryChange, projects.length, totalBooks, state]);
809
800
 
810
801
  let body;
811
802
  if (state === 'loading' && projects.length === 0) {
@@ -1021,7 +1012,7 @@ __define('./shelf', (module, exports, require) => {
1021
1012
  className: P + 'Shelf',
1022
1013
  'data-shelf': '1',
1023
1014
  'data-shelf-selecting': selectMode ? '1' : undefined,
1024
- }, [head, noticeEl, selectBar, body, menuEl, confirmEl]);
1015
+ }, [noticeEl, selectBar, body, menuEl, confirmEl]);
1025
1016
  }
1026
1017
 
1027
1018
  // =========================================================================
@@ -1032,11 +1023,7 @@ __define('./shelf', (module, exports, require) => {
1032
1023
  .${P}Shelf{display:flex;flex-direction:column;height:100%;min-height:0;box-sizing:border-box;overflow:hidden;
1033
1024
  background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);
1034
1025
  font-family:var(--dsw-font-family,system-ui)}
1035
- .${P}Head{display:flex;align-items:center;gap:8px;flex:none;padding:12px 18px 8px}
1036
- .${P}HeadTitle{font-size:15px;font-weight:650}
1037
- .${P}HeadMeta{font-size:11px;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary))}
1038
1026
  .${P}HeadSpacer{flex:1;min-width:0}
1039
- .${P}HeadBusy{font-size:11px;color:var(--dsw-alias-brand-primary)}
1040
1027
  .${P}GhostBtn{border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);
1041
1028
  font:inherit;font-size:12px;padding:2px 9px;border-radius:var(--dsw-radius-sm,5px);cursor:pointer}
1042
1029
  .${P}GhostBtn:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.12));