dsh-linked-workspace 0.5.12 → 0.5.13
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 +5 -0
- package/README.en.md +4 -0
- package/lib/client.js +83 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.13 — 2026-11-05
|
|
4
|
+
|
|
5
|
+
- The linked-workspace directory panel can now be resized by dragging the divider; double-click the divider to reset to 300 px. The width is persisted.
|
|
6
|
+
- The local directory tree now refreshes silently every 4 seconds (and on window focus), so newly created local subdirectories appear without a manual refresh; expanded folders are reloaded in place.
|
|
7
|
+
|
|
3
8
|
## 0.5.12 — 2026-11-04
|
|
4
9
|
|
|
5
10
|
- Published as **dsh-linked-workspace** on npm (public).
|
package/README.en.md
CHANGED
|
@@ -99,6 +99,10 @@ Old “Remote directories” tabs are restored after refresh through hidden lega
|
|
|
99
99
|
|
|
100
100
|
See [CHANGELOG.md](CHANGELOG.md) for the full version history.
|
|
101
101
|
|
|
102
|
+
### 0.5.13
|
|
103
|
+
|
|
104
|
+
The directory panel divider is draggable (double-click resets to 300 px; width persists). The local tree refreshes silently every 4 seconds and on window focus, so new local subdirectories appear without a manual refresh.
|
|
105
|
+
|
|
102
106
|
## Releases and marketplace updates
|
|
103
107
|
|
|
104
108
|
- The npm package is `dsh-linked-workspace`. To release, bump `package.json` and push a `v*` tag; `.github/workflows/release.yml` runs `npm publish --access public` (set an `NPM_TOKEN` repository secret).
|
package/lib/client.js
CHANGED
|
@@ -2057,6 +2057,7 @@ function fileIconSpec(name, isDir) {
|
|
|
2057
2057
|
openFileHint: '从工作区目录树中选择文件',
|
|
2058
2058
|
toggleDirectory: '开启/关闭联动工作区目录面板',
|
|
2059
2059
|
closeFile: '关闭文件标签',
|
|
2060
|
+
resizeDirectory: '拖动调整目录面板宽度;双击恢复默认宽度',
|
|
2060
2061
|
remoteTabTitle: '远程目录',
|
|
2061
2062
|
remoteTabDesc: '只读查看已添加的远程目录及其文件,不允许编辑。',
|
|
2062
2063
|
remoteDirsTitle: '远程目录',
|
|
@@ -2331,6 +2332,7 @@ function fileIconSpec(name, isDir) {
|
|
|
2331
2332
|
openFileHint: 'Select a file from the workspace directory tree',
|
|
2332
2333
|
toggleDirectory: 'Show or hide the linked workspace directory panel',
|
|
2333
2334
|
closeFile: 'Close file tab',
|
|
2335
|
+
resizeDirectory: 'Drag to resize the directory panel; double-click to reset',
|
|
2334
2336
|
remoteTabTitle: 'Remote directories',
|
|
2335
2337
|
remoteTabDesc: 'Read-only view of configured remote directories and files; editing is disabled.',
|
|
2336
2338
|
remoteDirsTitle: 'Remote directories',
|
|
@@ -2934,7 +2936,9 @@ function fileIconSpec(name, isDir) {
|
|
|
2934
2936
|
'.rw-ctx-backdrop{position:fixed;inset:0;z-index:70}',
|
|
2935
2937
|
'.rw-workspace-body{display:flex;flex:1 1 auto;min-height:0;min-width:0}',
|
|
2936
2938
|
'.rw-content-pane{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0}',
|
|
2937
|
-
'.rw-directory-pane{display:flex;flex-direction:column;flex:0 0
|
|
2939
|
+
'.rw-directory-pane{display:flex;flex-direction:column;flex:0 0 auto;max-width:60%;min-width:240px;min-height:0;border-left:1px solid var(--dsw-alias-border-l1)}',
|
|
2940
|
+
'.rw-pane-resizer{flex:0 0 6px;align-self:stretch;cursor:col-resize;background:transparent;position:relative;z-index:2;touch-action:none}',
|
|
2941
|
+
'.rw-pane-resizer:hover,.rw-pane-resizer:active{background:var(--dsw-alias-brand-primary)}',
|
|
2938
2942
|
'.rw-directory-head{display:flex;align-items:center;gap:6px;padding:5px 8px;font-size:10.5px;line-height:16px;letter-spacing:.03em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-1);border-bottom:1px solid var(--dsw-alias-border-l1);flex:none}',
|
|
2939
2943
|
'.rw-directory-body{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}',
|
|
2940
2944
|
'.rw-file-tabs{display:flex;align-items:stretch;gap:2px;min-height:30px;padding:3px 5px;overflow:auto;background:var(--dsw-alias-bg-layer-1);border-bottom:1px solid var(--dsw-alias-border-l1);flex:none}',
|
|
@@ -3889,6 +3893,11 @@ function fileIconSpec(name, isDir) {
|
|
|
3889
3893
|
var setCache = cacheState[1];
|
|
3890
3894
|
var pending = useRef(new Set());
|
|
3891
3895
|
|
|
3896
|
+
useEffect(function () {
|
|
3897
|
+
if (!props.refreshTick) return;
|
|
3898
|
+
Array.from(expanded).forEach(function (path) { load(path, true); });
|
|
3899
|
+
}, [props.refreshTick]);
|
|
3900
|
+
|
|
3892
3901
|
function toggle(path) {
|
|
3893
3902
|
setExpanded(function (previous) {
|
|
3894
3903
|
var next = new Set(previous);
|
|
@@ -3898,13 +3907,13 @@ function fileIconSpec(name, isDir) {
|
|
|
3898
3907
|
});
|
|
3899
3908
|
}
|
|
3900
3909
|
|
|
3901
|
-
function load(path) {
|
|
3910
|
+
function load(path, silent) {
|
|
3902
3911
|
if (pending.current.has(path)) return;
|
|
3903
3912
|
pending.current.add(path);
|
|
3904
3913
|
setCache(function (previous) {
|
|
3905
3914
|
var entries = new Map(previous.entries);
|
|
3906
3915
|
var existing = entries.get(path) || {};
|
|
3907
|
-
entries.set(path, { loading:
|
|
3916
|
+
entries.set(path, { loading: !silent, error: null, entries: existing.entries || [], loaded: existing.loaded });
|
|
3908
3917
|
return { entries: entries };
|
|
3909
3918
|
});
|
|
3910
3919
|
var request = props.kind === 'local'
|
|
@@ -4445,10 +4454,68 @@ function fileIconSpec(name, isDir) {
|
|
|
4445
4454
|
var directoryOpenState = useState(true);
|
|
4446
4455
|
var directoryOpen = directoryOpenState[0];
|
|
4447
4456
|
var setDirectoryOpen = directoryOpenState[1];
|
|
4457
|
+
var directoryWidthState = useState(function () {
|
|
4458
|
+
try {
|
|
4459
|
+
var saved = parseInt(window.localStorage.getItem('dsh-linked-workspace:directory-width'), 10);
|
|
4460
|
+
return saved >= 240 && saved <= 900 ? saved : 300;
|
|
4461
|
+
} catch (error) { return 300; }
|
|
4462
|
+
});
|
|
4463
|
+
var directoryWidth = directoryWidthState[0];
|
|
4464
|
+
var setDirectoryWidth = directoryWidthState[1];
|
|
4465
|
+
var directoryWidthRef = useRef(directoryWidth);
|
|
4466
|
+
var workbenchRef = useRef(null);
|
|
4467
|
+
var localTickState = useState(0);
|
|
4468
|
+
var localTick = localTickState[0];
|
|
4469
|
+
var setLocalTick = localTickState[1];
|
|
4448
4470
|
var fileDirtyState = useState({});
|
|
4449
4471
|
var fileDirty = fileDirtyState[0];
|
|
4450
4472
|
var setFileDirty = fileDirtyState[1];
|
|
4451
4473
|
var directoryTabId = props.tab && props.tab.id;
|
|
4474
|
+
|
|
4475
|
+
useEffect(function () {
|
|
4476
|
+
directoryWidthRef.current = directoryWidth;
|
|
4477
|
+
try { window.localStorage.setItem('dsh-linked-workspace:directory-width', String(directoryWidth)); } catch (error) { /* storage unavailable */ }
|
|
4478
|
+
}, [directoryWidth]);
|
|
4479
|
+
|
|
4480
|
+
useEffect(function () {
|
|
4481
|
+
if (!directoryOpen) return undefined;
|
|
4482
|
+
var bump = function () {
|
|
4483
|
+
if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return;
|
|
4484
|
+
setLocalTick(function (value) { return value + 1; });
|
|
4485
|
+
};
|
|
4486
|
+
var timer = setInterval(bump, 4000);
|
|
4487
|
+
if (timer && typeof timer.unref === 'function') timer.unref();
|
|
4488
|
+
window.addEventListener('focus', bump);
|
|
4489
|
+
return function () {
|
|
4490
|
+
clearInterval(timer);
|
|
4491
|
+
window.removeEventListener('focus', bump);
|
|
4492
|
+
};
|
|
4493
|
+
}, [directoryOpen, selectedKey]);
|
|
4494
|
+
|
|
4495
|
+
function beginResize(event) {
|
|
4496
|
+
if (event.button !== undefined && event.button !== 0) return;
|
|
4497
|
+
event.preventDefault();
|
|
4498
|
+
var startX = event.clientX;
|
|
4499
|
+
var startWidth = directoryWidthRef.current;
|
|
4500
|
+
var workbench = workbenchRef.current;
|
|
4501
|
+
var maxWidth = workbench ? Math.max(260, workbench.clientWidth - 320) : 720;
|
|
4502
|
+
document.body.style.cursor = 'col-resize';
|
|
4503
|
+
document.body.style.userSelect = 'none';
|
|
4504
|
+
function move(moveEvent) {
|
|
4505
|
+
var next = Math.max(240, Math.min(maxWidth, startWidth + (startX - moveEvent.clientX)));
|
|
4506
|
+
setDirectoryWidth(next);
|
|
4507
|
+
}
|
|
4508
|
+
function finish() {
|
|
4509
|
+
document.removeEventListener('pointermove', move);
|
|
4510
|
+
document.removeEventListener('pointerup', finish);
|
|
4511
|
+
document.removeEventListener('pointercancel', finish);
|
|
4512
|
+
document.body.style.cursor = '';
|
|
4513
|
+
document.body.style.userSelect = '';
|
|
4514
|
+
}
|
|
4515
|
+
document.addEventListener('pointermove', move);
|
|
4516
|
+
document.addEventListener('pointerup', finish);
|
|
4517
|
+
document.addEventListener('pointercancel', finish);
|
|
4518
|
+
}
|
|
4452
4519
|
function restoreDirectoryTab() {
|
|
4453
4520
|
if (!sidebar || typeof sidebar.activateTab !== 'function' || !directoryTabId) return;
|
|
4454
4521
|
setTimeout(function () {
|
|
@@ -4860,7 +4927,7 @@ function fileIconSpec(name, isDir) {
|
|
|
4860
4927
|
}, [searchOpen, searchQuery, selectedKey, version]);
|
|
4861
4928
|
|
|
4862
4929
|
if (!selected) {
|
|
4863
|
-
return h('div', { className: 'rw-workbench rw-workspace' },
|
|
4930
|
+
return h('div', { className: 'rw-workbench rw-workspace', ref: workbenchRef },
|
|
4864
4931
|
h('div', { className: 'rw-tree-scroll' },
|
|
4865
4932
|
data.data.loading
|
|
4866
4933
|
? h('div', { className: 'rw-row-msg' }, Spinner(13), t('loading'))
|
|
@@ -4923,6 +4990,7 @@ function fileIconSpec(name, isDir) {
|
|
|
4923
4990
|
selectedPath: selectedEntry && selectedEntry.side === 'local' ? selectedEntry.path : '',
|
|
4924
4991
|
onSelectPath: function (info) { setSelectedEntry(Object.assign({ side: 'local' }, info)); },
|
|
4925
4992
|
onSelect: function (filePath) { openByMode('local', filePath); },
|
|
4993
|
+
refreshTick: localTick,
|
|
4926
4994
|
onContextMenu: function (info) { setSelectedEntry(Object.assign({ side: 'local' }, info)); openContextMenu('local', info); },
|
|
4927
4995
|
}))
|
|
4928
4996
|
: null);
|
|
@@ -5024,7 +5092,17 @@ function fileIconSpec(name, isDir) {
|
|
|
5024
5092
|
: null,
|
|
5025
5093
|
h('div', { className: 'rw-content-body' }, contentArea)),
|
|
5026
5094
|
directoryOpen
|
|
5027
|
-
? h('div', {
|
|
5095
|
+
? h('div', {
|
|
5096
|
+
className: 'rw-pane-resizer',
|
|
5097
|
+
role: 'separator',
|
|
5098
|
+
'aria-orientation': 'vertical',
|
|
5099
|
+
title: t('resizeDirectory'),
|
|
5100
|
+
onPointerDown: beginResize,
|
|
5101
|
+
onDoubleClick: function () { setDirectoryWidth(300); },
|
|
5102
|
+
})
|
|
5103
|
+
: null,
|
|
5104
|
+
directoryOpen
|
|
5105
|
+
? h('div', { className: 'rw-directory-pane', style: { flexBasis: directoryWidth + 'px' } },
|
|
5028
5106
|
h('div', { className: 'rw-directory-head' },
|
|
5029
5107
|
IconFolder(11, false),
|
|
5030
5108
|
h('span', { style: { flex: '1 1 auto', minWidth: 0 } }, remoteOnly ? t('remoteTabTitle') : t('tabTitle')),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-linked-workspace",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.13",
|
|
4
4
|
"description": "Linked local ⇄ remote workspaces and SSH-backed remote directories for DeepSeek Harness: theme-aware split editor, file-type icons, and an agent tool that edits remote files directly.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|