@goodandready/dsh-remote-workspace 0.3.0 → 0.3.2
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 +17 -0
- package/README.ru.md +17 -0
- package/README.zh.md +17 -0
- package/docs/design/DESIGN.md +1 -1
- package/lib/alert-service.js +109 -0
- package/lib/client.js +2316 -1991
- package/lib/diagnose-service.js +57 -0
- package/lib/docker-service.js +1 -1
- package/lib/env-service.js +122 -0
- package/lib/index.js +83 -16
- package/lib/mirror-sync-service.js +2 -2
- package/lib/routes/docker.js +85 -0
- package/lib/routes/env.js +60 -0
- package/lib/routes/files.js +88 -0
- package/lib/routes/helpers.js +40 -0
- package/lib/routes/profiles.js +141 -0
- package/lib/routes/sync.js +52 -0
- package/lib/routes/terminal.js +103 -0
- package/lib/routes/tunnels.js +59 -0
- package/lib/routes.js +47 -516
- package/lib/ssh-config-parser.js +89 -0
- package/lib/ssh-service.js +24 -9
- package/lib/tar-sync-service.js +85 -0
- package/lib/tools.js +78 -3
- package/lib/tunnel-service.js +2 -2
- package/lib/updater-service.js +338 -0
- package/lib/vault-service.js +29 -5
- package/lib/watcher-service.js +3 -3
- package/package.json +6 -3
- package/docs/plans/findings.md +0 -19
- package/docs/plans/progress.md +0 -15
- package/docs/plans/task_plan.md +0 -23
package/lib/vault-service.js
CHANGED
|
@@ -8,6 +8,7 @@ import os from 'node:os';
|
|
|
8
8
|
*/
|
|
9
9
|
export class VaultService {
|
|
10
10
|
constructor(customPath = null) {
|
|
11
|
+
this.permissionError = null;
|
|
11
12
|
if (customPath) {
|
|
12
13
|
this.envPath = customPath;
|
|
13
14
|
} else {
|
|
@@ -17,7 +18,16 @@ export class VaultService {
|
|
|
17
18
|
if (!fs.existsSync(secretsDir)) {
|
|
18
19
|
fs.mkdirSync(secretsDir, { recursive: true, mode: 0o700 });
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
if (fs.existsSync(secretsDir)) {
|
|
22
|
+
try {
|
|
23
|
+
fs.chmodSync(secretsDir, 0o700);
|
|
24
|
+
} catch (chmodErr) {
|
|
25
|
+
this.permissionError = `Failed to set 0700 permissions on secrets dir: ${chmodErr.message}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
} catch (mkdirErr) {
|
|
29
|
+
this.permissionError = `Failed to initialize secrets directory: ${mkdirErr.message}`;
|
|
30
|
+
}
|
|
21
31
|
this.envPath = path.join(secretsDir, 'dsh-remote-workspace.env');
|
|
22
32
|
}
|
|
23
33
|
this.ensureEnvFile();
|
|
@@ -29,9 +39,23 @@ export class VaultService {
|
|
|
29
39
|
fs.writeFileSync(this.envPath, '# DSH Remote Workspace Encrypted Secrets Vault\n', { mode: 0o600, encoding: 'utf8' });
|
|
30
40
|
} else {
|
|
31
41
|
// Ensure file permissions are restricted to owner only
|
|
32
|
-
try {
|
|
42
|
+
try {
|
|
43
|
+
fs.chmodSync(this.envPath, 0o600);
|
|
44
|
+
} catch (chmodErr) {
|
|
45
|
+
this.permissionError = `Failed to restrict permissions on ${this.envPath}: ${chmodErr.message}`;
|
|
46
|
+
}
|
|
33
47
|
}
|
|
34
|
-
} catch (
|
|
48
|
+
} catch (err) {
|
|
49
|
+
this.permissionError = `Failed to ensure vault file: ${err.message}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getPermissionStatus() {
|
|
54
|
+
return {
|
|
55
|
+
secure: !this.permissionError,
|
|
56
|
+
error: this.permissionError,
|
|
57
|
+
path: this.envPath
|
|
58
|
+
};
|
|
35
59
|
}
|
|
36
60
|
|
|
37
61
|
/**
|
|
@@ -61,14 +85,14 @@ export class VaultService {
|
|
|
61
85
|
currentKey = key;
|
|
62
86
|
currentValue = val.slice(1) + '\n';
|
|
63
87
|
} else if (val.startsWith('"') && val.endsWith('"') && val.length >= 2) {
|
|
64
|
-
store[key] = val.slice(1, -1).replace(/\\n/g, '\n').replace(/\\r/g, '\r');
|
|
88
|
+
store[key] = val.slice(1, -1).replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\r/g, '\r');
|
|
65
89
|
} else {
|
|
66
90
|
store[key] = val;
|
|
67
91
|
}
|
|
68
92
|
} else {
|
|
69
93
|
if (line.endsWith('"')) {
|
|
70
94
|
currentValue += line.slice(0, -1);
|
|
71
|
-
store[currentKey] = currentValue.replace(/\\n/g, '\n').replace(/\\r/g, '\r');
|
|
95
|
+
store[currentKey] = currentValue.replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\r/g, '\r');
|
|
72
96
|
isMultiline = false;
|
|
73
97
|
currentKey = null;
|
|
74
98
|
currentValue = '';
|
package/lib/watcher-service.js
CHANGED
|
@@ -59,7 +59,7 @@ export class WatcherService {
|
|
|
59
59
|
if (this.onSyncCallback) {
|
|
60
60
|
this.onSyncCallback({ profileId: profile.id, syncRes });
|
|
61
61
|
}
|
|
62
|
-
} catch (
|
|
62
|
+
} catch (err) { /* best-effort cleanup */ }
|
|
63
63
|
}, this.debounceMs);
|
|
64
64
|
|
|
65
65
|
this.debounceTimers.set(profile.id, timer);
|
|
@@ -81,7 +81,7 @@ export class WatcherService {
|
|
|
81
81
|
if (item) {
|
|
82
82
|
try {
|
|
83
83
|
item.watcher.close();
|
|
84
|
-
} catch (
|
|
84
|
+
} catch (err) { /* best-effort cleanup */ }
|
|
85
85
|
this.watchers.delete(profileId);
|
|
86
86
|
return true;
|
|
87
87
|
}
|
|
@@ -100,7 +100,7 @@ export class WatcherService {
|
|
|
100
100
|
for (const [id, item] of this.watchers.entries()) {
|
|
101
101
|
try {
|
|
102
102
|
item.watcher.close();
|
|
103
|
-
} catch (
|
|
103
|
+
} catch (err) { /* best-effort cleanup */ }
|
|
104
104
|
if (this.debounceTimers.has(id)) {
|
|
105
105
|
clearTimeout(this.debounceTimers.get(id));
|
|
106
106
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-remote-workspace",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Enterprise Remote Workspace Plugin for DeepSeek Harness: SSH2 connection pool, SFTP operations, 3-way conflict-aware mirror sync, port forwarding, and native DSH UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"README.md",
|
|
17
17
|
"README.ru.md",
|
|
18
18
|
"README.zh.md",
|
|
19
|
-
"docs/",
|
|
19
|
+
"docs/design/DESIGN.md",
|
|
20
20
|
"LICENSE"
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
@@ -49,7 +49,10 @@
|
|
|
49
49
|
},
|
|
50
50
|
"client": {
|
|
51
51
|
"platform": "web",
|
|
52
|
-
"inject": [
|
|
52
|
+
"inject": [
|
|
53
|
+
"@deepseek-ai/dsh-client-locale",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
55
|
+
]
|
|
53
56
|
}
|
|
54
57
|
},
|
|
55
58
|
"dependencies": {
|
package/docs/plans/findings.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# findings.md — dsh-remote-workspace
|
|
2
|
-
|
|
3
|
-
## Ключевые выводы анализа dsh-remote
|
|
4
|
-
1. Преимущество 3-way sync: snapshot хешей предотвращает перезапись изменений при одновременном редактировании на сервере и локально.
|
|
5
|
-
2. Проблема 21 инструмента rw_*: перегружает LLM prompt. В новом плагине объединяем в 4 сбалансированных инструмента:
|
|
6
|
-
emote_exec,
|
|
7
|
-
emote_fs,
|
|
8
|
-
emote_sync,
|
|
9
|
-
emote_tunnel.
|
|
10
|
-
3. Модульность: вместо спагетти в index.js реализуем 4 отдельных Cordis сервиса.
|
|
11
|
-
4. UI: использование нативных CSS переменных DSH, чистый React, поддержка i18n (EN/RU/ZH).
|
|
12
|
-
|
|
13
|
-
## Результаты аудита стабильности и UI (Фаза 8)
|
|
14
|
-
1. **Баг localMirrorPath**: в форме профиля отсутствовало поле ввода localMirrorPath, что блокировало синхронизацию зеркала (400 Error).
|
|
15
|
-
2. **Баг рассинхронизации полей testConnection**: бэкенд отдавал latency/os, клиент ожидал latencyMs/
|
|
16
|
-
emoteOs.
|
|
17
|
-
3. **Утечка кэшированных SSH-соединений**: при смене хоста или ключа/пароля в профиле старое соединение с тем же id не сбрасывалось из пула SshService.
|
|
18
|
-
4. **Отсутствие UI для SSH-туннелей**: туннели были поддержаны на бэкенде, но не имели интерфейса в карточке настроек.
|
|
19
|
-
5. **Безопасность API**: отсутствовал фильтр isTrustedSettingsRequest(req) на мутирующих маршрутах.
|
package/docs/plans/progress.md
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# progress.md — dsh-remote-workspace
|
|
2
|
-
|
|
3
|
-
## Журнал выполнения
|
|
4
|
-
- **2026-09-08**:
|
|
5
|
-
- Создан репозиторий goodandready/dsh-remote-workspace в Gitea.
|
|
6
|
-
- Создана задача Issue #1: [critical] Initial implementation of dsh-remote-workspace plugin.
|
|
7
|
-
- Оформлен дизайн-контракт docs/design/DESIGN.md.
|
|
8
|
-
- Реализованы 4 сервиса и 4 инструмента модели.
|
|
9
|
-
- Пройдены первые 12 тестов.
|
|
10
|
-
- **2026-09-09**:
|
|
11
|
-
- Обогащена документация по стандарту dsh-documentation-standard (EN/RU/ZH).
|
|
12
|
-
- **2026-09-10**:
|
|
13
|
-
- Создано worktree stability-and-clinebot-ui для реализации Фазы 8.
|
|
14
|
-
- Выполнен детальный аудит стабильности кода и визуального слоя.
|
|
15
|
-
- Подготовлен и утвержден комплексный план.
|
package/docs/plans/task_plan.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# task_plan.md — dsh-remote-workspace
|
|
2
|
-
|
|
3
|
-
## Цель
|
|
4
|
-
Создать высоконадежный корпоративный плагин удаленной разработки dsh-remote-workspace для DeepSeek Harness с современным UI, сервисной архитектурой Cordis, 3-way mirror sync, SSH port forwarding и компактным набором инструментов LLM.
|
|
5
|
-
|
|
6
|
-
## Фазы реализации
|
|
7
|
-
- [x] **Фаза 1**: Анализ dsh-remote, формирование архитектуры, инициализация репозитория Gitea и worktree.
|
|
8
|
-
- [x] **Фаза 2**: Конфигурация сборки и репозитория (package.json, .gitignore, cordis.patch.yml).
|
|
9
|
-
- [x] **Фаза 3**: Ядро backend сервисов (SshService, RemoteFsService, MirrorSyncService, TunnelService).
|
|
10
|
-
- [x] **Фаза 4**: Инструменты модели (
|
|
11
|
-
emote_exec,
|
|
12
|
-
emote_fs,
|
|
13
|
-
emote_sync,
|
|
14
|
-
emote_tunnel) и API маршруты.
|
|
15
|
-
- [x] **Фаза 5**: Клиентская часть (i18n RU/EN/ZH, UI слоты).
|
|
16
|
-
- [x] **Фаза 6**: Комплексное тестирование базовых модулей (12/12 pass).
|
|
17
|
-
- [x] **Фаза 7**: Дополнительные ручные сценарии и документация (Docs standard EN/RU/ZH).
|
|
18
|
-
- [/] **Фаза 8**: Стабильность, аудит багов, расширение тестов и дизайн в едином стиле dsh-clinebot:
|
|
19
|
-
- [ ] 8.1. Исправление стабильности: безопасный доступ к Cordis сервисам (ctx.get), сброс соединений при смене реквизитов профиля, нормализация полей в estConnection (latencyMs / remoteOs).
|
|
20
|
-
- [ ] 8.2. Безопасность и отказоустойчивость: фильтрация isTrustedSettingsRequest на API маршрутах, обработка ошибок стримов в TunnelService, автосоздание папок в MirrorSyncService.
|
|
21
|
-
- [ ] 8.3. Редизайн UI в едином стиле dsh-clinebot: модульные карточки, статусные бейджи в шапке, добавление поля localMirrorPath, секция управления туннелями в интерфейсе.
|
|
22
|
-
- [ ] 8.4. Расширение набора тестов (тесты API routes, tools, store/apply, client registration).
|
|
23
|
-
- [ ] 8.5. Тестирование на изолированном MiniPC сервере (dsh-test-plugin).
|