dsh-ide-git 0.19.9 → 0.19.11

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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-ide-git",
3
- "version": "0.19.9",
3
+ "version": "0.19.11",
4
4
  "main": "./src/index.js",
5
5
  "description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ide-git",
3
- "version": "0.19.9",
3
+ "version": "0.19.11",
4
4
  "description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
5
5
  "type": "module",
6
6
  "repository": {
package/src/client.js CHANGED
@@ -8201,13 +8201,19 @@ window.__ModuleLoader__.load({
8201
8201
  for (const child of node.dirs.values()) total += countOf(child)
8202
8202
  return total
8203
8203
  }
8204
- const sortedChildren = (node) => Array.from(node.dirs.values()).sort((a, b) => a.path[a.path.length - 1].localeCompare(b.path[b.path.length - 1]))
8204
+ /* Compress at EVERY level, not just the roots (issue #18): the roots
8205
+ were condensed into "a/b/c" chains, but renderFolder's recursion and
8206
+ the fold-all id walk both read this function — which used to hand
8207
+ back the raw single-child chains below the first level, so a deep
8208
+ package path repeated its full prefix on every row. Each returned
8209
+ child is the deepest node of its single-child, file-less chain. */
8210
+ const sortedChildren = (node) => Array.from(node.dirs.values()).map(compress).sort((a, b) => a.path[a.path.length - 1].localeCompare(b.path[b.path.length - 1]))
8205
8211
  const ids = []
8206
8212
  const collect = (node) => {
8207
8213
  ids.push(groupKey + '|' + node.path.join('/'))
8208
8214
  for (const child of sortedChildren(node)) collect(child)
8209
8215
  }
8210
- const roots = sortedChildren(root).map((child) => compress(child))
8216
+ const roots = sortedChildren(root)
8211
8217
  for (const node of roots) collect(node)
8212
8218
  return { roots: roots, rootFiles: root.files, ids: ids, countOf: countOf, sortedChildren: sortedChildren }
8213
8219
  }
@@ -11028,7 +11034,11 @@ window.__ModuleLoader__.load({
11028
11034
  return
11029
11035
  }
11030
11036
  const forest = buildDirForest(sorted, key)
11031
- const renderFolder = (node, depth) => {
11037
+ /* The label is the chain THIS node adds below its parent (issue
11038
+ #18): a compressed "java/cn/com/pxwk/base" node repeats only the
11039
+ segments below "…/src/main", not the full path from the group
11040
+ root — same convention as the IDE commit tree. */
11041
+ const renderFolder = (node, depth, parentLen) => {
11032
11042
  const id = key + '|' + node.path.join('/')
11033
11043
  const open = foldedDirs[id] !== true
11034
11044
  out.push({
@@ -11040,13 +11050,13 @@ window.__ModuleLoader__.load({
11040
11050
  },
11041
11051
  E('span', { className: 'dig-chevron' + (open ? ' dig-chevron-open' : '') }, E(Icon, { name: 'chevron', size: 10 })),
11042
11052
  E('span', { className: 'dig-row-icon dig-tone-accent' }, E(Icon, { name: 'folder', size: 10 })),
11043
- E('span', { className: 'dig-folder-name' }, node.path.join('/')),
11053
+ E('span', { className: 'dig-folder-name' }, node.path.slice(typeof parentLen === 'number' ? parentLen : 0).join('/')),
11044
11054
  E('span', { className: 'dig-count' }, String(forest.countOf(node)))),
11045
11055
  })
11046
11056
  if (open === true) {
11047
11057
  /* VS Code order inside a folder: subfolders first (recursively,
11048
11058
  each indented one more level), then this folder's own files. */
11049
- for (const child of forest.sortedChildren(node)) renderFolder(child, depth + 1)
11059
+ for (const child of forest.sortedChildren(node)) renderFolder(child, depth + 1, node.path.length)
11050
11060
  for (const item of sortedOf(node.files)) out.push({ kind: 'row', key: key + ':' + item.path, h: ITEM_HEIGHTS.row, node: entryRow(key, item, depth) })
11051
11061
  }
11052
11062
  }
@@ -12075,6 +12085,7 @@ window.__ModuleLoader__.load({
12075
12085
  useMeasureLayoutEffect(() => {
12076
12086
  const node = hostRef.current
12077
12087
  const holder = node === null || typeof node.closest !== 'function' ? null : node.closest('.dig-conversation-seat[data-immersive="1"]')
12088
+ if (gateNestedLoop() === false) return
12078
12089
  setImmersiveSeat(holder !== null)
12079
12090
  })
12080
12091
  const compact = size.width > 0 && size.width < COMPACT_MAX_WIDTH
@@ -12144,14 +12155,40 @@ window.__ModuleLoader__.load({
12144
12155
  apart read as a smooth resize in a low-fps screen recording. Later
12145
12156
  runs still track content arrival; the layout-phase cost is one
12146
12157
  querySelectorAll over the 3-4 panes the post-paint run already paid. */
12158
+ /* ---------- measurement loop fuse (issue #17) ---------- */
12159
+
12160
+ /* Every effect below runs on EVERY render and feeds a state update.
12161
+ In a steady UI the bail-out comparisons stop the chain, but when the
12162
+ realized layout disagrees with the just-measured one — a float pane
12163
+ being created/resized on the desktop client hit exactly this — each
12164
+ render re-measures a DIFFERENT box, the update nests synchronously
12165
+ and React aborts at depth 50 with #185, leaving the pane white
12166
+ behind the host's slot boundary. The gate detects that nesting
12167
+ directly: runs are counted in a 40 ms window and a nested render
12168
+ loop (50 commits inside one task) trips it long before React's
12169
+ limit, while legitimate per-event work (a pointermove drag renders
12170
+ at most twice in 40 ms) never comes close. Skipping a measurement
12171
+ during a pathological burst only freezes the affected number until
12172
+ the next window — degraded ratios for a frame, never a white pane. */
12173
+ const measureGate = useRef({ n: 0, at: 0 })
12174
+ const gateNestedLoop = () => {
12175
+ const slot = measureGate.current
12176
+ const now = Date.now()
12177
+ if (now - slot.at > 40) { slot.at = now; slot.n = 0 }
12178
+ slot.n += 1
12179
+ return slot.n <= 6
12180
+ }
12181
+
12147
12182
  useMeasureLayoutEffect(() => {
12148
12183
  const found = measurePanes()
12184
+ if (gateNestedLoop() === false) return
12149
12185
  setPaneSizes((current) => (samePaneSizes(current, found) ? current : found))
12150
12186
  })
12151
12187
  useEffect(() => {
12152
12188
  const node = hostRef.current
12153
12189
  const holder = node === null || typeof node.closest !== 'function' ? null : node.closest('[data-dockkit-float]')
12154
12190
  const next = holder === null ? null : holder.getAttribute('data-dockkit-float')
12191
+ if (gateNestedLoop() === false) return
12155
12192
  setFloatPaneId((current) => (current === next ? current : next))
12156
12193
  })
12157
12194
  const dock = props.dock === undefined ? null : props.dock