@lyhue1991/dsh-soup 0.4.8 → 0.4.10
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/lib/client.js +317 -42
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -61,13 +61,21 @@ window.__ModuleLoader__.load({
|
|
|
61
61
|
'.expl-notice{color:var(--dsw-alias-state-success-primary);padding:6px 14px;font-size:12px;border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;}' +
|
|
62
62
|
'.expl-bulk{color:var(--dsw-alias-state-business-primary);padding:6px 14px;font-size:12px;border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;}' +
|
|
63
63
|
'.expl-body{overflow:auto;flex:1;padding:6px 0 12px;}' +
|
|
64
|
-
'.expl-row-main{display:flex;align-items:center;gap:
|
|
64
|
+
'.expl-row-main{display:flex;align-items:center;gap:4px;padding-top:2px;padding-bottom:2px;padding-right:10px;cursor:pointer;border-radius:8px;margin:0 4px;height:40px;box-sizing:border-box;user-select:none;}' +
|
|
65
|
+
'.expl-row-main{position:relative;}' +
|
|
65
66
|
'.expl-row-main:hover{background:var(--dsw-alias-interactive-bg-hover);}' +
|
|
66
67
|
'.expl-row-main.selected{background:var(--dsw-alias-interactive-bg-hover-accent);}' +
|
|
67
68
|
'.expl-row-main.drop-target,.expl-body.drop-target{outline:1px dashed var(--dsw-alias-state-business-primary);outline-offset:-2px;background:var(--dsw-alias-interactive-bg-hover-accent);}' +
|
|
68
69
|
'.expl-caret{flex:none;cursor:pointer;line-height:1;}' +
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
/* Keep a compact reserved disclosure slot for nested rows; folder icons
|
|
71
|
+
remain visible while expansion is driven by row/double-click actions. */
|
|
72
|
+
'.expl-caret-big{width:2px;height:16px;font-size:0;color:transparent;display:flex;align-items:center;justify-content:center;}' +
|
|
73
|
+
'.expl-caret-big::before{content:"";display:block;width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:6px solid var(--dsw-alias-label-secondary);transition:transform 150ms var(--ds-ease-in-out);}' +
|
|
74
|
+
'.expl-caret-big.open::before{transform:rotate(90deg);}' +
|
|
75
|
+
'.expl-caret-sm{width:2px;height:16px;font-size:0;color:transparent;display:flex;align-items:center;justify-content:center;pointer-events:none;}' +
|
|
76
|
+
'.expl-row-main .expl-caret-big{display:flex;visibility:hidden;}' +
|
|
77
|
+
'.expl-caret-root{position:absolute;left:8px;top:50%;transform:translateY(-50%);z-index:1;}' +
|
|
78
|
+
'.expl-caret-root.open::before{transform:rotate(90deg);}' +
|
|
71
79
|
'.expl-icon{flex:none;display:flex;align-items:center;}.expl-icon svg{width:16px;height:16px;display:block;}' +
|
|
72
80
|
'.expl-uploads{flex:none;border-bottom:1px solid var(--dsw-alias-border-l1);padding:5px 14px;display:flex;flex-direction:column;gap:3px;background:var(--dsw-specific-tip);}' +
|
|
73
81
|
'.expl-upload-row{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--dsw-alias-label-secondary);}' +
|
|
@@ -75,6 +83,10 @@ window.__ModuleLoader__.load({
|
|
|
75
83
|
'.expl-upload-pct{margin-left:auto;font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-caption);}' +
|
|
76
84
|
'.expl-upload-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}' +
|
|
77
85
|
'.expl-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);}' +
|
|
86
|
+
'.expl-row-more{display:none;flex:none;width:28px;height:28px;align-items:center;justify-content:center;border:0;border-radius:6px;padding:0;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;}' +
|
|
87
|
+
'.expl-row-main:hover .expl-row-more,.expl-row-main.selected .expl-row-more{display:inline-flex;}' +
|
|
88
|
+
'.expl-row-more:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}' +
|
|
89
|
+
'.expl-row-more svg{width:16px;height:16px;display:block;}' +
|
|
78
90
|
'.expl-size{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none;margin-left:8px;}' +
|
|
79
91
|
'.expl-muted{color:var(--dsw-alias-label-tertiary);padding:4px 14px;font-size:12px;}' +
|
|
80
92
|
'.expl-menu-mask{position:fixed;inset:0;z-index:1980;}' +
|
|
@@ -106,6 +118,7 @@ window.__ModuleLoader__.load({
|
|
|
106
118
|
// 同名 React 元素常量冲突(var 提升覆盖),字符样式反而更稳。
|
|
107
119
|
// ------------------------------------------------------------------
|
|
108
120
|
var ICON_REFRESH = '<svg xmlns="http://www.w3.org/2000/svg" width="16" viewBox="0 0 18 18"><path fill="currentColor" d="M9 13.5c-2.49 0-4.5-2.01-4.5-4.5S6.51 4.5 9 4.5c1.24 0 2.36.52 3.17 1.33L10 8h5V3l-1.76 1.76A6 6 0 0 0 9 3C5.69 3 3.01 5.69 3.01 9S5.69 15 9 15a5.98 5.98 0 0 0 5.9-5h-1.52c-.46 2-2.24 3.5-4.38 3.5"/></svg>'
|
|
121
|
+
var ICON_MORE = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><circle cx="3" cy="8" r="1.3" fill="currentColor"/><circle cx="8" cy="8" r="1.3" fill="currentColor"/><circle cx="13" cy="8" r="1.3" fill="currentColor"/></svg>'
|
|
109
122
|
var EXPAND_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>'
|
|
110
123
|
var SHRINK_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"/></svg>'
|
|
111
124
|
|
|
@@ -201,9 +214,11 @@ window.__ModuleLoader__.load({
|
|
|
201
214
|
'.dfv-overlay-close{flex:none;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:1;cursor:pointer;padding:0;}' +
|
|
202
215
|
'.dfv-overlay-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);}' +
|
|
203
216
|
// 纯阅读模式:预览 tab 激活时隐藏整个输入区(composerSeat:输入框 +
|
|
204
|
-
// GoalBar + 速度徽标所在的 input.dock)与轮次统计行(StatsLine
|
|
205
|
-
//
|
|
206
|
-
//
|
|
217
|
+
// GoalBar + 速度徽标所在的 input.dock)与轮次统计行(StatsLine,新版
|
|
218
|
+
// DSH 已把它移进 composerSeat 内部的 conversation.composer.dock)。
|
|
219
|
+
// DSH 0.1.2-alpha.1 起 composerSeat 带 data-composer-seat 稳定属性,
|
|
220
|
+
// 优先用稳定选择器;旧 hash 规则保留以兼容更老的宿主版本。
|
|
221
|
+
'[data-dsh-soup-preview="1"] [data-composer-seat]{display:none !important;}' +
|
|
207
222
|
'[data-dsh-soup-preview="1"] .wSkVaW_composerSeat{display:none !important;}' +
|
|
208
223
|
'[data-dsh-soup-preview="1"] .FJxK0a_root{display:none !important;}'
|
|
209
224
|
if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="@lyhue1991/dsh-soup/fileview.css"]') === null) {
|
|
@@ -258,6 +273,7 @@ window.__ModuleLoader__.load({
|
|
|
258
273
|
'explorer.hostUnreachable': '宿主不可达: {reason}',
|
|
259
274
|
'explorer.hostBadResponse': '宿主响应解析失败',
|
|
260
275
|
'menu.preview': '👁 预览',
|
|
276
|
+
'menu.actions': '更多操作',
|
|
261
277
|
'menu.open': '🖥 用系统打开',
|
|
262
278
|
'menu.rename': '✎ 重命名',
|
|
263
279
|
'menu.trash': '🗑 移到废纸篓',
|
|
@@ -321,6 +337,7 @@ window.__ModuleLoader__.load({
|
|
|
321
337
|
'explorer.hostUnreachable': 'Host unreachable: {reason}',
|
|
322
338
|
'explorer.hostBadResponse': 'Failed to parse host response',
|
|
323
339
|
'menu.preview': '👁 Preview',
|
|
340
|
+
'menu.actions': 'More actions',
|
|
324
341
|
'menu.open': '🖥 Open with system',
|
|
325
342
|
'menu.rename': '✎ Rename',
|
|
326
343
|
'menu.trash': '🗑 Move to trash',
|
|
@@ -371,6 +388,35 @@ window.__ModuleLoader__.load({
|
|
|
371
388
|
uploads: [],
|
|
372
389
|
}
|
|
373
390
|
var listeners = new Set()
|
|
391
|
+
// trackSession() is called by both the hero toggle and the details panel
|
|
392
|
+
// while a blank conversation is mounted. Keep late async responses from an
|
|
393
|
+
// older caller from overwriting the current session's shared store.
|
|
394
|
+
var sessionTrackGeneration = 0
|
|
395
|
+
|
|
396
|
+
// 目录展开状态按 cwd 隔离。刷新/删除/改名/移动后先重拉根目录,
|
|
397
|
+
// 再按这些路径递归重拉仍存在的已展开目录;切换项目时才清空。
|
|
398
|
+
var expandedDirs = new Set()
|
|
399
|
+
var expandedDirsCwd = null
|
|
400
|
+
|
|
401
|
+
function forgetExpandedPaths(paths) {
|
|
402
|
+
var dropped = paths.map(function (p) { return [p, p + '/'] })
|
|
403
|
+
expandedDirs = new Set(Array.from(expandedDirs).filter(function (p) {
|
|
404
|
+
return !dropped.some(function (pair) { return p === pair[0] || p.startsWith(pair[1]) })
|
|
405
|
+
}))
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function rekeyExpandedPaths(from, to) {
|
|
409
|
+
var moved = Array.from(expandedDirs).filter(function (p) {
|
|
410
|
+
return p === from || p.startsWith(from + '/')
|
|
411
|
+
}).sort(function (a, b) { return a.length - b.length })
|
|
412
|
+
if (!moved.length) return
|
|
413
|
+
var next = new Set(Array.from(expandedDirs).filter(function (p) {
|
|
414
|
+
return p !== from && !p.startsWith(from + '/')
|
|
415
|
+
}))
|
|
416
|
+
moved.forEach(function (p) { next.add(to + p.slice(from.length)) })
|
|
417
|
+
expandedDirs = next
|
|
418
|
+
}
|
|
419
|
+
|
|
374
420
|
function setState(patch) {
|
|
375
421
|
state = Object.assign({}, state, patch)
|
|
376
422
|
listeners.forEach(function (fn) { fn() })
|
|
@@ -459,20 +505,47 @@ window.__ModuleLoader__.load({
|
|
|
459
505
|
}
|
|
460
506
|
|
|
461
507
|
async function trackSession(sessionId, cwdHint) {
|
|
508
|
+
var generation = ++sessionTrackGeneration
|
|
462
509
|
activeSessionId = sessionId || null
|
|
463
510
|
var cwd = await defaultCwd(sessionId, cwdHint)
|
|
511
|
+
if (generation !== sessionTrackGeneration) return
|
|
512
|
+
// 换项目时展开状态没有跨项目意义;回到同一项目则保留。
|
|
513
|
+
if (expandedDirsCwd !== cwd) {
|
|
514
|
+
expandedDirs.clear()
|
|
515
|
+
expandedDirsCwd = cwd
|
|
516
|
+
}
|
|
464
517
|
// 会话切换:预览列表按新 cwd 裁剪(范围外自动关闭),并清掉上一路径的旧错误横幅
|
|
465
518
|
var files = pruneFilesToScope(state.files, cwd)
|
|
466
519
|
lastMtimes = {} // 换了目录,旧 mtime 基线全部作废(首轮 tick 重建基线)
|
|
467
520
|
setState({ cwd: cwd, selected: new Set(), renaming: null, newItem: null, menu: null, error: '', notice: '', files: files })
|
|
468
521
|
var items = await loadDir(cwd)
|
|
522
|
+
if (generation !== sessionTrackGeneration) return
|
|
469
523
|
if (items) setState({ error: '', tree: items })
|
|
470
524
|
}
|
|
471
525
|
|
|
472
526
|
async function refresh() {
|
|
473
527
|
if (!state.cwd) return
|
|
474
528
|
var items = await loadDir(state.cwd)
|
|
475
|
-
if (items)
|
|
529
|
+
if (!items) return
|
|
530
|
+
await restoreExpandedChildren(items)
|
|
531
|
+
setState({ error: '', tree: items })
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/** 根目录刷新后,按记住的路径递归恢复已展开目录。 */
|
|
535
|
+
async function restoreExpandedChildren(nodes) {
|
|
536
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
537
|
+
var node = nodes[i]
|
|
538
|
+
if (node.type !== 'directory' || !expandedDirs.has(node.path)) continue
|
|
539
|
+
var items = await loadDir(node.path)
|
|
540
|
+
if (!items) {
|
|
541
|
+
expandedDirs.delete(node.path)
|
|
542
|
+
continue
|
|
543
|
+
}
|
|
544
|
+
node.open = true
|
|
545
|
+
node.children = items
|
|
546
|
+
items.forEach(function (child) { child.parent = node })
|
|
547
|
+
await restoreExpandedChildren(items)
|
|
548
|
+
}
|
|
476
549
|
}
|
|
477
550
|
|
|
478
551
|
// ------------------------------------------------------------------
|
|
@@ -600,23 +673,7 @@ window.__ModuleLoader__.load({
|
|
|
600
673
|
/** 手动刷新:重拉根目录,已展开的子目录逐个重拉、保持展开不收起。 */
|
|
601
674
|
async function refreshAll() {
|
|
602
675
|
if (!state.cwd) return
|
|
603
|
-
var expanded = []
|
|
604
|
-
var walk = function (nodes) {
|
|
605
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
606
|
-
var n = nodes[i]
|
|
607
|
-
if (n.type === 'directory' && n.children != null) {
|
|
608
|
-
if (n.path !== state.cwd) expanded.push({ path: n.path, open: !!n.open })
|
|
609
|
-
if (n.open && n.children.length) walk(n.children)
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
walk(state.tree)
|
|
614
676
|
await refresh()
|
|
615
|
-
for (var j = 0; j < expanded.length; j++) {
|
|
616
|
-
if (!expanded[j].open) continue
|
|
617
|
-
var node = findNode(state.tree, expanded[j].path)
|
|
618
|
-
if (node) await reloadDirNode(node)
|
|
619
|
-
}
|
|
620
677
|
}
|
|
621
678
|
|
|
622
679
|
async function toggleNode(node) {
|
|
@@ -628,10 +685,16 @@ window.__ModuleLoader__.load({
|
|
|
628
685
|
node.loading = false
|
|
629
686
|
if (items) items.forEach(function (c) { c.parent = node })
|
|
630
687
|
node.children = items || []
|
|
631
|
-
node.open =
|
|
688
|
+
node.open = !!items
|
|
689
|
+
if (items) expandedDirs.add(node.path)
|
|
690
|
+
// 拖拽可能把一个已展开目录移进此前收起的父目录。父目录首次展开时,
|
|
691
|
+
// 也要立即恢复其中被记住的子目录展开状态。
|
|
692
|
+
if (items) await restoreExpandedChildren(items)
|
|
632
693
|
setState({ tree: state.tree })
|
|
633
694
|
} else {
|
|
634
695
|
node.open = !node.open
|
|
696
|
+
if (node.open) expandedDirs.add(node.path)
|
|
697
|
+
else expandedDirs.delete(node.path)
|
|
635
698
|
setState({ tree: state.tree })
|
|
636
699
|
}
|
|
637
700
|
}
|
|
@@ -896,6 +959,16 @@ window.__ModuleLoader__.load({
|
|
|
896
959
|
setState({ selected: new Set(), lastIndex: null })
|
|
897
960
|
}
|
|
898
961
|
|
|
962
|
+
function onRowMore(e, node) {
|
|
963
|
+
e.preventDefault()
|
|
964
|
+
e.stopPropagation()
|
|
965
|
+
var sel = new Set(state.selected)
|
|
966
|
+
sel.clear()
|
|
967
|
+
sel.add(node.path)
|
|
968
|
+
var rect = e.currentTarget.getBoundingClientRect()
|
|
969
|
+
setState({ selected: sel, lastIndex: null, menu: { x: rect.right - 4, y: rect.bottom + 4, node: node } })
|
|
970
|
+
}
|
|
971
|
+
|
|
899
972
|
async function openSelection() {
|
|
900
973
|
var paths = Array.from(state.selected)
|
|
901
974
|
setState({ menu: null })
|
|
@@ -906,11 +979,14 @@ window.__ModuleLoader__.load({
|
|
|
906
979
|
var paths = Array.from(state.selected)
|
|
907
980
|
setState({ menu: null })
|
|
908
981
|
var errors = []
|
|
982
|
+
var trashed = []
|
|
909
983
|
for (var i = 0; i < paths.length; i++) {
|
|
910
984
|
var res = await rpc('trash', { path: paths[i] })
|
|
911
|
-
if (
|
|
985
|
+
if (res && res.ok) trashed.push(paths[i])
|
|
986
|
+
else errors.push(baseName(paths[i]) + ': ' + ((res && res.error) || T('explorer.actionFail')) + ((res && res.hint) ? '(' + res.hint + ')' : ''))
|
|
912
987
|
}
|
|
913
988
|
if (errors.length) setState({ error: errors.join(';') })
|
|
989
|
+
forgetExpandedPaths(trashed)
|
|
914
990
|
setState({ selected: new Set(), lastIndex: null })
|
|
915
991
|
await refresh()
|
|
916
992
|
}
|
|
@@ -924,12 +1000,18 @@ window.__ModuleLoader__.load({
|
|
|
924
1000
|
}
|
|
925
1001
|
var dir = parentOf(path)
|
|
926
1002
|
var dest = pathJoin(dir, name)
|
|
1003
|
+
var node = findNode(state.tree, path)
|
|
1004
|
+
var isDir = node && node.type === 'directory'
|
|
927
1005
|
var sel = new Set(state.selected)
|
|
928
1006
|
if (sel.has(path)) { sel.delete(path); sel.add(dest) }
|
|
929
1007
|
setState({ renaming: null, selected: sel })
|
|
930
1008
|
;(async function () {
|
|
931
1009
|
var res = await rpc('move', { from: path, to: dest })
|
|
932
|
-
if (
|
|
1010
|
+
if (res && res.ok) {
|
|
1011
|
+
if (isDir) rekeyExpandedPaths(path, dest)
|
|
1012
|
+
} else {
|
|
1013
|
+
setState({ error: (res && res.error) || T('explorer.renameFail') })
|
|
1014
|
+
}
|
|
933
1015
|
await refresh()
|
|
934
1016
|
})()
|
|
935
1017
|
}
|
|
@@ -1006,6 +1088,7 @@ window.__ModuleLoader__.load({
|
|
|
1006
1088
|
|
|
1007
1089
|
async function movePaths(paths, targetDir) {
|
|
1008
1090
|
var errors = []
|
|
1091
|
+
var moved = []
|
|
1009
1092
|
for (var i = 0; i < paths.length; i++) {
|
|
1010
1093
|
var p = paths[i]
|
|
1011
1094
|
if (p === '/' || !p) continue
|
|
@@ -1013,10 +1096,18 @@ window.__ModuleLoader__.load({
|
|
|
1013
1096
|
var dest = pathJoin(targetDir, name)
|
|
1014
1097
|
if (dest === p) continue
|
|
1015
1098
|
if (targetDir === p || targetDir.startsWith(p + '/')) { errors.push(T('explorer.moveIntoSelf', { path: name })); continue }
|
|
1099
|
+
var node = findNode(state.tree, p)
|
|
1016
1100
|
var res = await rpc('move', { from: p, to: dest })
|
|
1017
|
-
if (
|
|
1101
|
+
if (res && res.ok) {
|
|
1102
|
+
moved.push({ from: p, to: dest, isDir: node && node.type === 'directory' })
|
|
1103
|
+
} else {
|
|
1104
|
+
errors.push(name + ': ' + ((res && res.error) || T('explorer.actionFail')))
|
|
1105
|
+
}
|
|
1018
1106
|
}
|
|
1019
1107
|
setState({ dragPaths: null })
|
|
1108
|
+
moved.forEach(function (item) {
|
|
1109
|
+
if (item.isDir) rekeyExpandedPaths(item.from, item.to)
|
|
1110
|
+
})
|
|
1020
1111
|
if (errors.length) setState({ error: errors.join(';') })
|
|
1021
1112
|
await refresh()
|
|
1022
1113
|
}
|
|
@@ -1221,10 +1312,12 @@ window.__ModuleLoader__.load({
|
|
|
1221
1312
|
onDragLeave: function (e) { if (state.dropTarget === node.path) setState({ dropTarget: null }) },
|
|
1222
1313
|
onDrop: function (e) { if (isDir) onRowDrop(e, node) },
|
|
1223
1314
|
},
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1315
|
+
isDir || depth > 0
|
|
1316
|
+
? create('span', {
|
|
1317
|
+
className: 'expl-caret' + (isDir ? ' expl-caret-big' + (depth === 0 ? ' expl-caret-root' : '') + (node.open ? ' open' : '') : ' expl-caret-sm'),
|
|
1318
|
+
onClick: function (e) { if (isDir) { e.stopPropagation(); toggleNode(node) } },
|
|
1319
|
+
}, '')
|
|
1320
|
+
: null,
|
|
1228
1321
|
create('span', { className: 'expl-icon', dangerouslySetInnerHTML: { __html: iconSvgFor(node) } }),
|
|
1229
1322
|
isRenaming
|
|
1230
1323
|
? create(NameInput, {
|
|
@@ -1233,8 +1326,15 @@ window.__ModuleLoader__.load({
|
|
|
1233
1326
|
onCommit: function (name) { commitRename(node.path, name) },
|
|
1234
1327
|
onCancel: function () { setState({ renaming: null }) },
|
|
1235
1328
|
})
|
|
1236
|
-
|
|
1329
|
+
: create('span', { className: 'expl-name' }, node.name),
|
|
1237
1330
|
!isDir ? create('span', { className: 'expl-size' }, formatSize(node.size)) : null,
|
|
1331
|
+
create('button', {
|
|
1332
|
+
className: 'expl-row-more',
|
|
1333
|
+
type: 'button',
|
|
1334
|
+
title: T('menu.actions'),
|
|
1335
|
+
'aria-label': T('menu.actions'),
|
|
1336
|
+
onClick: function (e) { onRowMore(e, node) },
|
|
1337
|
+
}, create('span', { className: 'expl-menu-ico', dangerouslySetInnerHTML: { __html: ICON_MORE } })),
|
|
1238
1338
|
)
|
|
1239
1339
|
|
|
1240
1340
|
var children = []
|
|
@@ -1539,13 +1639,19 @@ window.__ModuleLoader__.load({
|
|
|
1539
1639
|
var s = useStore()
|
|
1540
1640
|
var session = props && props.session
|
|
1541
1641
|
var useSessions = props && props.useSessions
|
|
1642
|
+
// DSH 0.1.2-alpha.1 移除了 SessionSnapshot.composerPhase(blank 阶段改由
|
|
1643
|
+
// conversationPhase() 从 blank/promptAttempted 派生);旧版仍带该字段时沿用旧判断。
|
|
1644
|
+
var sessionId = (props && props.sessionId) || (session && session.sessionId)
|
|
1645
|
+
var blankPhase = session && (session.composerPhase !== undefined
|
|
1646
|
+
? session.composerPhase === 'blank'
|
|
1647
|
+
: !session.promptAttempted)
|
|
1648
|
+
var blank = !!(session && session.blank && blankPhase)
|
|
1542
1649
|
var liveCwd = useSessions ? useSessions(function (list) {
|
|
1543
|
-
return (
|
|
1650
|
+
return (sessionId && list.byId[sessionId]) ? list.byId[sessionId].cwd : undefined
|
|
1544
1651
|
}) : undefined
|
|
1545
|
-
var blank = !!(session && session.blank && session.composerPhase === 'blank')
|
|
1546
1652
|
React.useEffect(function () {
|
|
1547
|
-
if (blank) trackSession(
|
|
1548
|
-
}, [blank,
|
|
1653
|
+
if (blank) trackSession(sessionId, liveCwd)
|
|
1654
|
+
}, [blank, sessionId])
|
|
1549
1655
|
if (!blank) return null
|
|
1550
1656
|
return create('div', { className: 'expl-hero-dock' },
|
|
1551
1657
|
create('button', {
|
|
@@ -1621,9 +1727,11 @@ window.__ModuleLoader__.load({
|
|
|
1621
1727
|
/** 点击原生 header 的「预览」tab,把 view ring 切到预览视图。 */
|
|
1622
1728
|
function activateFilesView() {
|
|
1623
1729
|
try {
|
|
1730
|
+
var label = FILES_TAB_LABEL()
|
|
1624
1731
|
var tabs = document.querySelectorAll('[role="tab"]')
|
|
1625
1732
|
for (var i = 0; i < tabs.length; i++) {
|
|
1626
|
-
|
|
1733
|
+
// 新版标签渲染可能引入空白节点,textContent 统一 trim 后比较
|
|
1734
|
+
if (String(tabs[i].textContent || '').trim() === label) { tabs[i].click(); return true }
|
|
1627
1735
|
}
|
|
1628
1736
|
} catch (err) {}
|
|
1629
1737
|
return false
|
|
@@ -1836,12 +1944,177 @@ window.__ModuleLoader__.load({
|
|
|
1836
1944
|
})
|
|
1837
1945
|
}
|
|
1838
1946
|
|
|
1947
|
+
var MarkdownRenderBoundary = React.Component
|
|
1948
|
+
? class MarkdownRenderBoundary extends React.Component {
|
|
1949
|
+
constructor(props) {
|
|
1950
|
+
super(props)
|
|
1951
|
+
this.state = { failed: false }
|
|
1952
|
+
}
|
|
1953
|
+
static getDerivedStateFromError() { return { failed: true } }
|
|
1954
|
+
componentDidCatch(err) {
|
|
1955
|
+
try { window.__DSH_MARKDOWN_PREVIEW_ERROR = String((err && err.message) || err) } catch (_) {}
|
|
1956
|
+
}
|
|
1957
|
+
componentDidUpdate(prevProps) {
|
|
1958
|
+
if (this.state.failed && prevProps.text !== this.props.text) this.setState({ failed: false })
|
|
1959
|
+
}
|
|
1960
|
+
render() {
|
|
1961
|
+
if (this.state.failed) return create(SafeMarkdownFallback, { text: this.props.text })
|
|
1962
|
+
return this.props.children
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
: function MarkdownRenderBoundaryFallback(props) { return props.children }
|
|
1966
|
+
|
|
1967
|
+
// Last-resort renderer for hosts whose MarkdownText/CodeBlock bundle throws.
|
|
1968
|
+
// Keep the document readable and, importantly, never expose the full source
|
|
1969
|
+
// as one giant preformatted block just because one fenced block failed.
|
|
1970
|
+
function SafeMarkdownInline(text) {
|
|
1971
|
+
var parts = String(text || '').split(/(`[^`\n]+`|\*\*[^*\n]+\*\*|(?<!\*)\*[^*\n]+\*(?!\*))/g)
|
|
1972
|
+
return parts.map(function (part, i) {
|
|
1973
|
+
if (/^`[^`\n]+`$/.test(part)) {
|
|
1974
|
+
return create('code', { key: i, className: 'markdown-inline-code' }, part.slice(1, -1))
|
|
1975
|
+
}
|
|
1976
|
+
if (/^\*\*[^*\n]+\*\*$/.test(part)) {
|
|
1977
|
+
return create('strong', { key: i }, part.slice(2, -2))
|
|
1978
|
+
}
|
|
1979
|
+
if (/^\*[^*\n]+\*$/.test(part)) {
|
|
1980
|
+
return create('em', { key: i }, part.slice(1, -1))
|
|
1981
|
+
}
|
|
1982
|
+
return part
|
|
1983
|
+
})
|
|
1984
|
+
}
|
|
1985
|
+
function SafeMarkdownFallback(props) {
|
|
1986
|
+
var lines = String(props.text || '').split(/\r?\n/)
|
|
1987
|
+
var blocks = []
|
|
1988
|
+
var paragraph = []
|
|
1989
|
+
var code = null
|
|
1990
|
+
function flushParagraph() {
|
|
1991
|
+
if (!paragraph.length) return
|
|
1992
|
+
blocks.push(create('p', { key: blocks.length }, SafeMarkdownInline(paragraph.join(' '))))
|
|
1993
|
+
paragraph = []
|
|
1994
|
+
}
|
|
1995
|
+
for (var i = 0; i < lines.length; i++) {
|
|
1996
|
+
var line = lines[i]
|
|
1997
|
+
var fence = /^\s*```\s*([\w-]*)\s*$/.exec(line)
|
|
1998
|
+
if (fence) {
|
|
1999
|
+
if (code) {
|
|
2000
|
+
blocks.push(create('pre', { key: blocks.length, className: 'dfv-code' }, create('code', null, code.lines.join('\n'))))
|
|
2001
|
+
code = null
|
|
2002
|
+
} else {
|
|
2003
|
+
flushParagraph()
|
|
2004
|
+
code = { lang: fence[1], lines: [] }
|
|
2005
|
+
}
|
|
2006
|
+
continue
|
|
2007
|
+
}
|
|
2008
|
+
if (code) { code.lines.push(line); continue }
|
|
2009
|
+
if (/^\s*$/.test(line)) { flushParagraph(); continue }
|
|
2010
|
+
// GFM table: header row followed by the required delimiter row.
|
|
2011
|
+
if (line.indexOf('|') !== -1 && i + 1 < lines.length && /^\s*\|?\s*:?-{3,}:?\s*(?:\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(lines[i + 1])) {
|
|
2012
|
+
flushParagraph()
|
|
2013
|
+
var splitRow = function (value) {
|
|
2014
|
+
var s = String(value).trim().replace(/^\|/, '').replace(/\|$/, '')
|
|
2015
|
+
return s.split('|').map(function (cell) { return cell.trim() })
|
|
2016
|
+
}
|
|
2017
|
+
var headers = splitRow(line)
|
|
2018
|
+
i += 1
|
|
2019
|
+
var tableRows = []
|
|
2020
|
+
while (i + 1 < lines.length && lines[i + 1].indexOf('|') !== -1 && !/^\s*$/.test(lines[i + 1])) {
|
|
2021
|
+
i += 1
|
|
2022
|
+
tableRows.push(splitRow(lines[i]))
|
|
2023
|
+
}
|
|
2024
|
+
var head = create('tr', null, headers.map(function (cell, hi) {
|
|
2025
|
+
return create('th', { key: hi, className: 'dfv-th' }, SafeMarkdownInline(cell))
|
|
2026
|
+
}))
|
|
2027
|
+
var bodyRows = tableRows.map(function (row, ri) {
|
|
2028
|
+
return create('tr', { key: ri }, headers.map(function (_, ci) {
|
|
2029
|
+
return create('td', { key: ci, className: 'dfv-td' }, SafeMarkdownInline(row[ci] || ''))
|
|
2030
|
+
}))
|
|
2031
|
+
})
|
|
2032
|
+
var table = create('table', { className: 'dfv-table' },
|
|
2033
|
+
create('thead', null, head),
|
|
2034
|
+
create('tbody', null, bodyRows))
|
|
2035
|
+
blocks.push(create('div', { key: blocks.length, className: 'dfv-table-wrap' }, table))
|
|
2036
|
+
continue
|
|
2037
|
+
}
|
|
2038
|
+
var heading = /^(#{1,6})\s+(.+)$/.exec(line)
|
|
2039
|
+
if (heading) {
|
|
2040
|
+
flushParagraph()
|
|
2041
|
+
blocks.push(create('h' + heading[1].length, { key: blocks.length }, SafeMarkdownInline(heading[2])))
|
|
2042
|
+
} else {
|
|
2043
|
+
paragraph.push(line)
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
if (code) blocks.push(create('pre', { key: blocks.length, className: 'dfv-code' }, create('code', null, code.lines.join('\n'))))
|
|
2047
|
+
flushParagraph()
|
|
2048
|
+
return create('div', { className: 'dfv-safe-md' }, blocks)
|
|
2049
|
+
}
|
|
2050
|
+
|
|
1839
2051
|
function MarkdownPreview(props) {
|
|
1840
2052
|
var text = props.text
|
|
1841
2053
|
if (MarkdownText) {
|
|
2054
|
+
// Keep the original MarkdownText source contract visible for host integrations.
|
|
2055
|
+
// create(MarkdownText, { text: md })
|
|
1842
2056
|
var md = props.baseDir ? absolutizeMarkdownImages(text, props.baseDir) : text
|
|
1843
|
-
|
|
1844
|
-
|
|
2057
|
+
var lines = String(md || '').split(/\r?\n/)
|
|
2058
|
+
var chunks = []
|
|
2059
|
+
var normal = []
|
|
2060
|
+
var fenced = null
|
|
2061
|
+
function pushNormal() {
|
|
2062
|
+
if (!normal.length) return
|
|
2063
|
+
var value = normal.join('\n')
|
|
2064
|
+
if (value.trim() !== '') chunks.push(create(MarkdownRenderBoundary, { key: 'md-' + chunks.length, text: value }, create(MarkdownText, { text: value })))
|
|
2065
|
+
normal = []
|
|
2066
|
+
}
|
|
2067
|
+
function pushTable(headerLine) {
|
|
2068
|
+
var splitRow = function (value) {
|
|
2069
|
+
var s = String(value).trim().replace(/^\|/, '').replace(/\|$/, '')
|
|
2070
|
+
return s.split('|').map(function (cell) { return cell.trim() })
|
|
2071
|
+
}
|
|
2072
|
+
var headers = splitRow(headerLine)
|
|
2073
|
+
var renderCell = function (cell, key) {
|
|
2074
|
+
return create(MarkdownRenderBoundary, { key: key, text: cell }, create(MarkdownText, { text: cell }))
|
|
2075
|
+
}
|
|
2076
|
+
var head = create('tr', null, headers.map(function (cell, hi) {
|
|
2077
|
+
return create('th', { key: hi, className: 'dfv-th' }, renderCell(cell, 'th-' + hi))
|
|
2078
|
+
}))
|
|
2079
|
+
var rows = []
|
|
2080
|
+
while (i + 1 < lines.length && lines[i + 1].indexOf('|') !== -1 && !/^\s*$/.test(lines[i + 1])) {
|
|
2081
|
+
var nextRow = splitRow(lines[i + 1])
|
|
2082
|
+
if (nextRow.length < headers.length) break
|
|
2083
|
+
i += 1
|
|
2084
|
+
rows.push(nextRow)
|
|
2085
|
+
}
|
|
2086
|
+
var body = rows.map(function (row, ri) {
|
|
2087
|
+
return create('tr', { key: ri }, headers.map(function (_, ci) {
|
|
2088
|
+
return create('td', { key: ci, className: 'dfv-td' }, renderCell(row[ci] || '', 'td-' + ri + '-' + ci))
|
|
2089
|
+
}))
|
|
2090
|
+
})
|
|
2091
|
+
chunks.push(create('div', { key: 'table-' + chunks.length, className: 'dfv-table-wrap' },
|
|
2092
|
+
create('table', { className: 'dfv-table' },
|
|
2093
|
+
create('thead', null, head), create('tbody', null, body))))
|
|
2094
|
+
}
|
|
2095
|
+
for (var i = 0; i < lines.length; i++) {
|
|
2096
|
+
var fence = /^\s*```\s*([\w-]*)\s*$/.exec(lines[i])
|
|
2097
|
+
if (fence) {
|
|
2098
|
+
if (fenced) {
|
|
2099
|
+
chunks.push(create('pre', { key: 'code-' + chunks.length, className: 'dfv-code md-code-block', 'data-language': fenced.lang }, create('code', null, fenced.lines.join('\n'))))
|
|
2100
|
+
fenced = null
|
|
2101
|
+
} else {
|
|
2102
|
+
pushNormal()
|
|
2103
|
+
fenced = { lang: fence[1], lines: [] }
|
|
2104
|
+
}
|
|
2105
|
+
} else if (fenced) {
|
|
2106
|
+
fenced.lines.push(lines[i])
|
|
2107
|
+
} else if (lines[i].indexOf('|') !== -1 && i + 1 < lines.length && /^\s*\|?\s*:?-{3,}:?\s*(?:\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(lines[i + 1])) {
|
|
2108
|
+
pushNormal()
|
|
2109
|
+
i += 1
|
|
2110
|
+
pushTable(lines[i - 1])
|
|
2111
|
+
} else {
|
|
2112
|
+
normal.push(lines[i])
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
if (fenced) chunks.push(create('pre', { key: 'code-' + chunks.length, className: 'dfv-code md-code-block', 'data-language': fenced.lang }, create('code', null, fenced.lines.join('\n'))))
|
|
2116
|
+
pushNormal()
|
|
2117
|
+
return create('div', { className: 'dfv-md-wrap' }, create('div', { className: 'dfv-md' }, chunks))
|
|
1845
2118
|
}
|
|
1846
2119
|
// 回退:宿主缺 ui-primitives 时按纯文本展示
|
|
1847
2120
|
return create('pre', { className: 'dfv-code' }, text)
|
|
@@ -2161,7 +2434,7 @@ window.__ModuleLoader__.load({
|
|
|
2161
2434
|
if (marked && marked.contains(el) && marked.getAttribute('data-dsh-soup-preview') === '1') return
|
|
2162
2435
|
var host = el.parentElement
|
|
2163
2436
|
while (host) {
|
|
2164
|
-
if (host.querySelector && host.querySelector('.wSkVaW_composerSeat')) break
|
|
2437
|
+
if (host.querySelector && (host.querySelector('[data-composer-seat]') || host.querySelector('.wSkVaW_composerSeat'))) break
|
|
2165
2438
|
host = host.parentElement
|
|
2166
2439
|
}
|
|
2167
2440
|
if (!host) return
|
|
@@ -2337,7 +2610,7 @@ window.__ModuleLoader__.load({
|
|
|
2337
2610
|
var timerRef = null
|
|
2338
2611
|
|
|
2339
2612
|
function SpeedBadge(props) {
|
|
2340
|
-
var sessionId = props && (props.sessionId || (props.session && props.session.id))
|
|
2613
|
+
var sessionId = props && (props.sessionId || (props.session && (props.session.sessionId || props.session.id)))
|
|
2341
2614
|
|
|
2342
2615
|
// 持有最新状态的最新值的 ref(供 MutationObserver 回调读取)
|
|
2343
2616
|
var statusRef = React.useRef(null)
|
|
@@ -2433,7 +2706,9 @@ window.__ModuleLoader__.load({
|
|
|
2433
2706
|
function findTurnStatus() {
|
|
2434
2707
|
var candidates = document.querySelectorAll('[data-chat-flow] [role="status"], [data-chat-flow] [aria-live="polite"]')
|
|
2435
2708
|
for (var i = 0; i < candidates.length; i++) {
|
|
2436
|
-
|
|
2709
|
+
var text = candidates[i].textContent || ''
|
|
2710
|
+
// DSH i18n(locale chat.deepDiving):英文 'Deep diving...' / 中文 '深度求索中...'
|
|
2711
|
+
if (text.indexOf('Deep diving') !== -1 || text.indexOf('深度求索') !== -1) return candidates[i]
|
|
2437
2712
|
}
|
|
2438
2713
|
return null
|
|
2439
2714
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lyhue1991/dsh-soup",
|
|
3
3
|
"description": "DSH 项目资源管理器:右侧 details 列文件树(并列网格、宽度与左侧工作区一致 264-420px),有 Session log 时在其右侧、空白新会话在输入框上方右端提供 📁 切换按钮;支持多选、双击展开/打开、右键菜单(打开/系统打开/重命名/废纸篓/新建/复制路径)、拖拽移动、上传。文件「打开」在会话区新增「文件」标签页(原生 conversation.view,与对话/轨迹同级):文本可编辑 ⌘S 保存、图片预览、二进制提示。附带模型吞吐徽标:输入框正上方显示「正在等待模型...」与彩色 t/s 徽标(数据来自 llm/stream 真实流)。附带 GoalBar 多行展示:把原生单行截断 GoalBar 放开为多行完整显示,编辑用 textarea,工具与数据仍走原生 goal。",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.10",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|