dsh-ask-from-text 0.1.13 → 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/CHANGELOG.md CHANGED
@@ -4,12 +4,109 @@ All notable changes to `dsh-ask-from-text` are documented here. The format is
4
4
  based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
5
5
  project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.1.19] - 2026-11-13
8
+
9
+ ### Fixed
10
+
11
+ - Do not pin a selected branch row above the group. Only the root/main Session
12
+ is allowed above `追问分支`; clicking a branch keeps it in the group.
13
+
14
+ ## [0.1.18] - 2026-11-13
15
+
16
+ ### Fixed
17
+
18
+ - Put the shared `追问分支` header before the topmost branch row in visual
19
+ document order, so collapsing/expanding no longer moves it below the group.
20
+
21
+ ## [0.1.17] - 2026-11-13
22
+
23
+ ### Fixed
24
+
25
+ - Keep the shared branch-group header when the group is collapsed by ignoring
26
+ rows hidden by the plugin itself, while still ignoring rows hidden inside a
27
+ folded Workspace or a stale search tree.
28
+
29
+ ## [0.1.16] - 2026-11-13
30
+
31
+ ### Fixed
32
+
33
+ - Restore the shared `追问分支` header by inserting it inside the first branch
34
+ row wrapper, where the sidebar animation layer participates in layout, and
35
+ keep only one header for all branch rows.
36
+
37
+ ## [0.1.15] - 2026-11-13
38
+
39
+ ### Fixed
40
+
41
+ - Group all branch Session rows under one shared `追问分支` header even when
42
+ the sidebar gives each row its own animated wrapper, and keep the selected
43
+ main row above that shared header.
44
+
45
+ ## [0.1.14] - 2026-11-13
46
+
47
+ ### Fixed
48
+
49
+ - Handle main and branch Sessions that the sidebar places in different
50
+ Workspace sections by moving the main section above the first branch section.
51
+
7
52
  ## [0.1.13] - 2026-11-13
8
53
 
9
54
  ### Fixed
10
55
 
11
56
  - README screenshots now use absolute CDN URLs so they render on the npm package page.
12
57
 
58
+ ## [0.1.19] - 2026-11-13
59
+
60
+ ### Fixed
61
+
62
+ - Do not pin a selected branch row above the group. Only the root/main Session
63
+ is allowed above `追问分支`; clicking a branch keeps it in the group.
64
+
65
+ ## [0.1.18] - 2026-11-13
66
+
67
+ ### Fixed
68
+
69
+ - Put the shared `追问分支` header before the topmost branch row in visual
70
+ document order, so collapsing/expanding no longer moves it below the group.
71
+
72
+ ## [0.1.17] - 2026-11-13
73
+
74
+ ### Fixed
75
+
76
+ - Keep the shared branch-group header when the group is collapsed by ignoring
77
+ rows hidden by the plugin itself, while still ignoring rows hidden inside a
78
+ folded Workspace or a stale search tree.
79
+
80
+ ## [0.1.16] - 2026-11-13
81
+
82
+ ### Fixed
83
+
84
+ - Restore the shared `追问分支` header by inserting it inside the first branch
85
+ row wrapper, where the sidebar animation layer participates in layout, and
86
+ keep only one header for all branch rows.
87
+
88
+ ## [0.1.15] - 2026-11-13
89
+
90
+ ### Fixed
91
+
92
+ - Group all branch Session rows under one shared `追问分支` header even when
93
+ the sidebar gives each row its own animated wrapper, and keep the selected
94
+ main row above that shared header.
95
+
96
+ ## [0.1.14] - 2026-11-13
97
+
98
+ ### Fixed
99
+
100
+ - Handle main and branch Sessions that the sidebar places in different
101
+ Workspace sections by moving the main section above the first branch section.
102
+
103
+ ## [0.1.13] - 2026-11-13
104
+
105
+ ### Fixed
106
+
107
+ - Prefer the selected sidebar row when pinning the main conversation above its
108
+ branch group, and re-evaluate when the selected Session changes.
109
+
13
110
  ## [0.1.12] - 2026-11-13
14
111
 
15
112
  ### Changed
@@ -91,3 +188,16 @@ project follows [Semantic Versioning](https://semver.org/).
91
188
  [0.1.11]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.11
92
189
  [0.1.12]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.12
93
190
  [0.1.13]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.13
191
+ [0.1.14]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.14
192
+ [0.1.15]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.15
193
+ [0.1.16]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.16
194
+ [0.1.17]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.17
195
+ [0.1.18]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.18
196
+ [0.1.19]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.19
197
+ [0.1.13]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.13
198
+ [0.1.14]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.14
199
+ [0.1.15]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.15
200
+ [0.1.16]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.16
201
+ [0.1.17]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.17
202
+ [0.1.18]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.18
203
+ [0.1.19]: https://github.com/gbn0219/dsh-ask-from-text/releases/tag/v0.1.19
package/README.md CHANGED
@@ -10,13 +10,13 @@
10
10
 
11
11
  需要 DeepSeek Harness 0.2.2-rc.x。
12
12
 
13
- ### 从 GitHub 安装(当前可用)
13
+ ### 从 GitHub 安装
14
14
 
15
15
  ```sh
16
16
  dsh plugin --profile web add github:gbn0219/dsh-ask-from-text
17
17
  ```
18
18
 
19
- ### 从 npm 安装(发布后可用)
19
+ ### 从 npm 安装
20
20
 
21
21
  ```sh
22
22
  dsh plugin --profile web add dsh-ask-from-text
@@ -132,13 +132,13 @@ dsh plugin --profile web add /absolute/path/to/dsh-ask-from-text
132
132
 
133
133
  Requires DeepSeek Harness 0.2.2-rc.x.
134
134
 
135
- #### From GitHub (available now)
135
+ #### From GitHub
136
136
 
137
137
  ```sh
138
138
  dsh plugin --profile web add github:gbn0219/dsh-ask-from-text
139
139
  ```
140
140
 
141
- #### From npm (after the npm release)
141
+ #### From npm
142
142
 
143
143
  ```sh
144
144
  dsh plugin --profile web add dsh-ask-from-text
package/client.js CHANGED
@@ -1013,7 +1013,13 @@ window.__ModuleLoader__.load({
1013
1013
  })
1014
1014
  if (!own) scheduleProject()
1015
1015
  })
1016
- mutationObserver.observe(document.body, { childList: true, subtree: true, characterData: true })
1016
+ mutationObserver.observe(document.body, {
1017
+ childList: true,
1018
+ subtree: true,
1019
+ characterData: true,
1020
+ attributes: true,
1021
+ attributeFilter: ['aria-selected'],
1022
+ })
1017
1023
  }
1018
1024
  scheduleProject()
1019
1025
  return () => {
@@ -1263,57 +1269,96 @@ window.__ModuleLoader__.load({
1263
1269
  const ids = new Set(state.order
1264
1270
  .map(id => state.branches[id]?.sessionId)
1265
1271
  .filter(Boolean))
1266
- const parents = new Map()
1272
+ const rows = []
1267
1273
  for (const id of ids) {
1268
1274
  for (const row of document.querySelectorAll(`[data-row-key="session:${cssEscape(id)}"]`)) {
1269
1275
  if (row.closest('[data-ifu-root]')) continue
1270
- const parent = row.parentElement
1271
- if (!parent) continue
1272
- const list = parents.get(parent) || []
1273
- list.push(row)
1274
- parents.set(parent, list)
1276
+ // Keep rows hidden by our own collapsed state in the group so the
1277
+ // header stays clickable; skip rows hidden inside a folded
1278
+ // Workspace or a stale search tree.
1279
+ if (row.getClientRects().length === 0 && !row.classList.contains('ifu-sidebar-hidden')) continue
1280
+ rows.push(row)
1275
1281
  }
1276
1282
  }
1277
- const activeParents = new Set(parents.keys())
1278
- for (const header of document.querySelectorAll('[data-ifu-sidebar-group]')) {
1279
- if (!activeParents.has(header.parentElement)) header.remove()
1280
- }
1281
- for (const [parent, rows] of parents) {
1282
- let header = parent.querySelector(':scope > [data-ifu-sidebar-group]')
1283
- if (!header) {
1284
- header = document.createElement('button')
1285
- header.type = 'button'
1286
- header.className = 'ifu-sidebar-group'
1287
- header.setAttribute('data-ifu-sidebar-group', '')
1288
- header.addEventListener('click', (event) => {
1289
- event.preventDefault()
1290
- event.stopPropagation()
1291
- toggleSidebarBranches()
1292
- })
1293
- }
1294
- const first = rows[0]
1295
- if (header.nextSibling !== first) parent.insertBefore(header, first)
1296
- const label = `${state.sidebarCollapsed ? '▸' : '▾'} 追问分支 · ${rows.length}`
1297
- if (header.textContent !== label) header.textContent = label
1298
- for (const row of rows) row.classList.toggle('ifu-sidebar-hidden', state.sidebarCollapsed)
1299
- // Keep the main conversation row above its branch rows even when the
1300
- // host sort places a recently used branch first. Moving the row at
1301
- // the React-owned DOM level is deliberate: the Session list is not a
1302
- // flex/order container, and the collapsible group header sits here.
1303
- const mainId = state.mainSessionId
1304
- const mainRow = mainId
1305
- ? parent.querySelector(`:scope > [data-row-key="session:${cssEscape(mainId)}"]`)
1306
- : null
1307
- if (mainRow && mainRow !== header
1283
+ rows.sort((a, b) => a === b ? 0
1284
+ : (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1)
1285
+ if (rows.length === 0) {
1286
+ for (const header of document.querySelectorAll('[data-ifu-sidebar-group]')) header.remove()
1287
+ for (const row of document.querySelectorAll('.ifu-sidebar-hidden')) row.classList.remove('ifu-sidebar-hidden')
1288
+ return
1289
+ }
1290
+ const first = rows[0]
1291
+ const firstParent = first.parentElement
1292
+ if (!firstParent) return
1293
+ let header = firstParent.querySelector(':scope > [data-ifu-sidebar-group]')
1294
+ if (!header) {
1295
+ header = document.createElement('button')
1296
+ header.type = 'button'
1297
+ header.className = 'ifu-sidebar-group'
1298
+ header.setAttribute('data-ifu-sidebar-group', '')
1299
+ header.addEventListener('click', (event) => {
1300
+ event.preventDefault()
1301
+ event.stopPropagation()
1302
+ toggleSidebarBranches()
1303
+ })
1304
+ }
1305
+ // Keep one shared header, inside the first branch wrapper. Putting it
1306
+ // at the animated tree root would be clipped or ignored by the row
1307
+ // animation layer; a wrapper child participates in the same layout as
1308
+ // the original per-row header did.
1309
+ for (const other of document.querySelectorAll('[data-ifu-sidebar-group]')) {
1310
+ if (other !== header) other.remove()
1311
+ }
1312
+ if (header.nextSibling !== first) firstParent.insertBefore(header, first)
1313
+ const label = `${state.sidebarCollapsed ? '▸' : '▾'} 追问分支 · ${rows.length}`
1314
+ if (header.textContent !== label) header.textContent = label
1315
+ for (const row of rows) row.classList.toggle('ifu-sidebar-hidden', state.sidebarCollapsed)
1316
+
1317
+ const branchSessionIds = ids
1318
+ const rootSessionIds = new Set(state.order
1319
+ .map(id => state.branches[id]?.rootSessionId)
1320
+ .filter(Boolean))
1321
+ const sessionIdOf = (row) => {
1322
+ const key = row.getAttribute('data-row-key') || ''
1323
+ return key.startsWith('session:') ? key.slice('session:'.length) : null
1324
+ }
1325
+ const selectedRow = Array.from(document.querySelectorAll('[data-row-key^="session:"][aria-selected="true"]'))
1326
+ .find(row => row.getClientRects().length > 0) || null
1327
+ // A branch row can be selected too (opening it as the main view). Only a
1328
+ // root/main Session may be pinned above the branch group; otherwise
1329
+ // clicking a branch would make that branch jump above its siblings.
1330
+ const selectedMain = selectedRow && rootSessionIds.has(sessionIdOf(selectedRow))
1331
+ ? selectedRow
1332
+ : null
1333
+ let mainId = state.mainSessionId
1334
+ if (mainId && branchSessionIds.has(mainId)) {
1335
+ mainId = branchBySession(mainId)?.rootSessionId || null
1336
+ }
1337
+ const mainRow = selectedMain || (mainId
1338
+ ? Array.from(document.querySelectorAll(`[data-row-key="session:${cssEscape(mainId)}"]`))
1339
+ .find(row => row.getClientRects().length > 0) || null
1340
+ : null)
1341
+ if (!mainRow) return
1342
+ if (mainRow.parentElement === firstParent) {
1343
+ if (mainRow !== header
1308
1344
  && (mainRow.compareDocumentPosition(header) & Node.DOCUMENT_POSITION_FOLLOWING) === 0) {
1309
- parent.insertBefore(mainRow, header)
1345
+ firstParent.insertBefore(mainRow, header)
1310
1346
  }
1347
+ return
1311
1348
  }
1312
- // Keep row classes correct even when no parent could be found this pass.
1313
- for (const id of ids) {
1314
- for (const row of document.querySelectorAll(`[data-row-key="session:${cssEscape(id)}"]`)) {
1315
- if (!row.closest('[data-ifu-root]')) row.classList.toggle('ifu-sidebar-hidden', state.sidebarCollapsed)
1316
- }
1349
+ let common = mainRow.parentElement
1350
+ while (common && !common.contains(firstParent)) common = common.parentElement
1351
+ if (!common || common === document.body || common === document.documentElement) return
1352
+ const directChild = (node) => {
1353
+ let element = node
1354
+ while (element && element.parentElement !== common) element = element.parentElement
1355
+ return element && element.parentElement === common ? element : null
1356
+ }
1357
+ const mainChild = directChild(mainRow)
1358
+ const branchChild = directChild(firstParent)
1359
+ if (mainChild && branchChild && mainChild !== branchChild
1360
+ && (mainChild.compareDocumentPosition(branchChild) & Node.DOCUMENT_POSITION_FOLLOWING) === 0) {
1361
+ common.insertBefore(mainChild, branchChild)
1317
1362
  }
1318
1363
  }
1319
1364
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ask-from-text",
3
- "version": "0.1.13",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "description": "Ask a follow-up from selected text in a DeepSeek Harness answer, in a real Session branch with a tree of context.",
6
6
  "exports": {