dsh-composer-plus 1.7.1 → 1.9.0
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 +37 -11
- package/assets/features/contentSearch.webp +0 -0
- package/assets/features/deleteChat.webp +0 -0
- package/assets/features/featureIdeas.webp +0 -0
- package/assets/features/turnRollback.webp +0 -0
- package/client.js +478 -40
- package/cordis.patch.yml +12 -0
- package/index.js +576 -28
- package/locale/de.json +1 -1
- package/locale/en.json +1 -1
- package/locale/es.json +1 -1
- package/locale/fr.json +1 -1
- package/locale/hi.json +1 -1
- package/locale/id.json +1 -1
- package/locale/ja.json +1 -1
- package/locale/ko.json +1 -1
- package/locale/pt-BR.json +1 -1
- package/locale/ru.json +1 -1
- package/locale/tr.json +1 -1
- package/locale/vi.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +10 -4
- package/tether/gateway/server.mjs +16 -6
package/locale/de.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Änderungsansicht, Karten mit Funktionsideen, Eingabeverlauf, Shift+Tab /plan, Fortsetzen mit einem Klick, Fortsetzen nach Neustart, Warteschlange per Drag-and-drop, Links, Benachrichtigungen, iPhone-Zugriff (Tether), 11 Sprachen und automatische Updates."
|
|
4
|
+
"description": "Änderungsansicht, Karten mit Funktionsideen, Suche in Nachrichten, Eingabeverlauf, Shift+Tab /plan, Fortsetzen mit einem Klick, Fortsetzen nach Neustart, Warteschlange per Drag-and-drop, Links, Benachrichtigungen, iPhone-Zugriff (Tether), 11 Sprachen und automatische Updates."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Changes panel, feature idea cards, input history, Shift+Tab /plan, one-click Continue, resume after restart, queue drag-and-drop, deeplinks, notifications, iPhone access (Tether), 11 UI languages and automatic updates."
|
|
4
|
+
"description": "Changes panel, feature idea cards, search in messages, input history, Shift+Tab /plan, one-click Continue, resume after restart, queue drag-and-drop, deeplinks, notifications, iPhone access (Tether), 11 UI languages and automatic updates."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/es.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Panel de cambios, tarjetas de ideas de funciones, historial de entrada, Shift+Tab /plan, Continuar con un clic, reanudar tras reiniciar, reordenar la cola arrastrando, enlaces, notificaciones, acceso desde iPhone (Tether), 11 idiomas y actualizaciones automáticas."
|
|
4
|
+
"description": "Panel de cambios, tarjetas de ideas de funciones, búsqueda en los mensajes, historial de entrada, Shift+Tab /plan, Continuar con un clic, reanudar tras reiniciar, reordenar la cola arrastrando, enlaces, notificaciones, acceso desde iPhone (Tether), 11 idiomas y actualizaciones automáticas."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/fr.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Panneau des modifications, cartes d’idées de fonctionnalités, historique de saisie, Shift+Tab /plan, Continuer en un clic, reprise après redémarrage, file réorganisable par glisser-déposer, liens, notifications, accès depuis l’iPhone (Tether), 11 langues et mises à jour automatiques."
|
|
4
|
+
"description": "Panneau des modifications, cartes d’idées de fonctionnalités, recherche dans les messages, historique de saisie, Shift+Tab /plan, Continuer en un clic, reprise après redémarrage, file réorganisable par glisser-déposer, liens, notifications, accès depuis l’iPhone (Tether), 11 langues et mises à jour automatiques."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/hi.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "बदलाव पैनल, फ़ीचर आइडिया कार्ड, इनपुट इतिहास, Shift+Tab /plan, एक क्लिक में जारी रखें, रीस्टार्ट के बाद जारी रखें, कतार ड्रैग-एंड-ड्रॉप, लिंक, सूचनाएं, iPhone से एक्सेस (Tether), 11 भाषाएं और अपने-आप अपडेट।"
|
|
4
|
+
"description": "बदलाव पैनल, फ़ीचर आइडिया कार्ड, संदेशों में खोज, इनपुट इतिहास, Shift+Tab /plan, एक क्लिक में जारी रखें, रीस्टार्ट के बाद जारी रखें, कतार ड्रैग-एंड-ड्रॉप, लिंक, सूचनाएं, iPhone से एक्सेस (Tether), 11 भाषाएं और अपने-आप अपडेट।"
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/id.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Panel perubahan, kartu ide fitur, riwayat input, Shift+Tab /plan, Lanjutkan sekali klik, lanjutkan setelah mulai ulang, urutkan antrean dengan seret, tautan, notifikasi, akses dari iPhone (Tether), 11 bahasa, dan pembaruan otomatis."
|
|
4
|
+
"description": "Panel perubahan, kartu ide fitur, pencarian isi pesan, riwayat input, Shift+Tab /plan, Lanjutkan sekali klik, lanjutkan setelah mulai ulang, urutkan antrean dengan seret, tautan, notifikasi, akses dari iPhone (Tether), 11 bahasa, dan pembaruan otomatis."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/ja.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "変更パネル、機能アイデアのカード、メッセージ内容の検索、入力履歴、Shift+Tab で /plan、ワンクリック続行、再起動後の再開、キューのドラッグ並べ替え、リンク、通知、iPhone からの操作(Tether)、11 言語、自動アップデート。"
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/ko.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "변경 사항 패널, 기능 아이디어 카드, 입력 기록, Shift+Tab /plan, 원클릭 계속, 재시작 후 이어서 실행, 대기열 끌어서 정렬, 링크, 알림, iPhone 연결(Tether), 11개 언어와 자동 업데이트."
|
|
4
|
+
"description": "변경 사항 패널, 기능 아이디어 카드, 메시지 내용 검색, 입력 기록, Shift+Tab /plan, 원클릭 계속, 재시작 후 이어서 실행, 대기열 끌어서 정렬, 링크, 알림, iPhone 연결(Tether), 11개 언어와 자동 업데이트."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/pt-BR.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Painel de alterações, cartões de ideias de recursos, histórico de entrada, Shift+Tab /plan, Continuar com um clique, retomar após reiniciar, reordenar a fila arrastando, links, notificações, acesso pelo iPhone (Tether), 11 idiomas e atualizações automáticas."
|
|
4
|
+
"description": "Painel de alterações, cartões de ideias de recursos, pesquisa nas mensagens, histórico de entrada, Shift+Tab /plan, Continuar com um clique, retomar após reiniciar, reordenar a fila arrastando, links, notificações, acesso pelo iPhone (Tether), 11 idiomas e atualizações automáticas."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/ru.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Панель изменений, карточки идей функций, история ввода, Shift+Tab /plan, продолжение в один клик, продолжение после перезапуска, перетаскивание очереди, ссылки, уведомления, доступ с iPhone (Tether), 11 языков и автообновления."
|
|
4
|
+
"description": "Панель изменений, карточки идей функций, поиск по сообщениям, история ввода, Shift+Tab /plan, продолжение в один клик, продолжение после перезапуска, перетаскивание очереди, ссылки, уведомления, доступ с iPhone (Tether), 11 языков и автообновления."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/tr.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Değişiklikler paneli, özellik fikri kartları, giriş geçmişi, Shift+Tab /plan, tek tıkla devam, yeniden açılışta sürdürme, sıradaki mesajları sürükle-bırak, bağlantılar, bildirimler, iPhone’dan erişim (Tether), 11 arayüz dili ve otomatik güncellemeler."
|
|
4
|
+
"description": "Değişiklikler paneli, özellik fikri kartları, mesaj içeriğinde arama, giriş geçmişi, Shift+Tab /plan, tek tıkla devam, yeniden açılışta sürdürme, sıradaki mesajları sürükle-bırak, bağlantılar, bildirimler, iPhone’dan erişim (Tether), 11 arayüz dili ve otomatik güncellemeler."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/vi.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "Bảng thay đổi, thẻ ý tưởng tính năng, lịch sử nhập, Shift+Tab /plan, Tiếp tục một chạm, tiếp tục sau khi khởi động lại, kéo thả hàng đợi, liên kết, thông báo, truy cập từ iPhone (Tether), 11 ngôn ngữ và tự động cập nhật."
|
|
4
|
+
"description": "Bảng thay đổi, thẻ ý tưởng tính năng, tìm trong nội dung tin nhắn, lịch sử nhập, Shift+Tab /plan, Tiếp tục một chạm, tiếp tục sau khi khởi động lại, kéo thả hàng đợi, liên kết, thông báo, truy cập từ iPhone (Tether), 11 ngôn ngữ và tự động cập nhật."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/zh.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Composer Plus",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "改动面板、功能创意卡片、消息内容搜索、输入历史、Shift+Tab /plan、一键继续、重启后继续、队列拖拽排序、会话链接、通知、iPhone 远程使用(Tether)、11 种界面语言和自动更新。"
|
|
5
5
|
}
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-composer-plus",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "DeepSeek Harness helpers: 11 extra UI languages (Türkçe, Español, Français, Deutsch, 日本語…), Changes panel, swipe-card feature ideas, input history, Shift+Tab /plan, one-click Continue, resume running chats after a restart, queue drag-and-drop, deeplinks, Auto Review allow-for-chat, notifications, iPhone access with the Tether app, automatic updates",
|
|
3
|
+
"version": "1.9.0",
|
|
4
|
+
"description": "DeepSeek Harness helpers: 11 extra UI languages (Türkçe, Español, Français, Deutsch, 日本語…), Changes panel, swipe-card feature ideas, sidebar search in message text, turn rollback with git file restore, delete chats to the Trash, input history, Shift+Tab /plan, one-click Continue, resume running chats after a restart, queue drag-and-drop, deeplinks, Auto Review allow-for-chat, notifications, iPhone access with the Tether app, automatic updates",
|
|
5
5
|
"icon": "./assets/icon.svg",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -19,12 +19,14 @@
|
|
|
19
19
|
"deepseek",
|
|
20
20
|
"deepseek-harness",
|
|
21
21
|
"deepseek-harness-plugin",
|
|
22
|
+
"delete-chat",
|
|
22
23
|
"drag-and-drop",
|
|
23
24
|
"dsh",
|
|
24
25
|
"dsh-composer-plus",
|
|
25
26
|
"dsh-plugin",
|
|
26
27
|
"dsh-plugins",
|
|
27
28
|
"feature-ideas",
|
|
29
|
+
"full-text-search",
|
|
28
30
|
"git",
|
|
29
31
|
"git-diff",
|
|
30
32
|
"i18n",
|
|
@@ -41,10 +43,14 @@
|
|
|
41
43
|
"remote-control",
|
|
42
44
|
"restart",
|
|
43
45
|
"resume",
|
|
46
|
+
"rewind",
|
|
47
|
+
"rollback",
|
|
48
|
+
"search",
|
|
44
49
|
"sort-by-status",
|
|
45
50
|
"tailscale",
|
|
46
51
|
"tether",
|
|
47
|
-
"translation"
|
|
52
|
+
"translation",
|
|
53
|
+
"undo"
|
|
48
54
|
],
|
|
49
55
|
"exports": {
|
|
50
56
|
".": "./index.js",
|
|
@@ -67,7 +73,7 @@
|
|
|
67
73
|
"assets/features/*.webp"
|
|
68
74
|
],
|
|
69
75
|
"scripts": {
|
|
70
|
-
"test": "node scripts/build-locales.mjs --check && node test/locale.test.mjs && node test/continue.test.mjs && node test/continue-host.test.mjs && node test/resume-restart.test.mjs && node test/queue-drag.test.mjs && node test/plan-toggle.test.mjs && node test/keep-focus.test.mjs && node test/mobile-connect.test.mjs && node test/tether-gateway.test.mjs && node test/deeplink.test.mjs && node test/chat-grant.test.mjs && node test/notify.test.mjs && node test/changes.test.mjs && node test/feature-ideas.test.mjs && node test/feature-ideas-client.test.mjs && node test/project-status.test.mjs && node test/recent-projects.test.mjs && node test/project-tools.test.mjs && node test/status-order.test.mjs && node test/toggles.test.mjs && node test/update.test.mjs && node test/meta.test.mjs && node test/shots.test.mjs",
|
|
76
|
+
"test": "node scripts/build-locales.mjs --check && node test/locale.test.mjs && node test/continue.test.mjs && node test/continue-host.test.mjs && node test/resume-restart.test.mjs && node test/content-search.test.mjs && node test/turn-rollback.test.mjs && node test/turn-rollback-client.test.mjs && node test/delete-chat.test.mjs && node test/queue-drag.test.mjs && node test/plan-toggle.test.mjs && node test/keep-focus.test.mjs && node test/mobile-connect.test.mjs && node test/tether-gateway.test.mjs && node test/deeplink.test.mjs && node test/chat-grant.test.mjs && node test/notify.test.mjs && node test/changes.test.mjs && node test/feature-ideas.test.mjs && node test/feature-ideas-client.test.mjs && node test/project-status.test.mjs && node test/recent-projects.test.mjs && node test/project-tools.test.mjs && node test/status-order.test.mjs && node test/toggles.test.mjs && node test/update.test.mjs && node test/meta.test.mjs && node test/shots.test.mjs",
|
|
71
77
|
"build:locales": "node scripts/build-locales.mjs",
|
|
72
78
|
"prepublishOnly": "npm test"
|
|
73
79
|
},
|
|
@@ -6,7 +6,7 @@ import { createServer as createHttp, request as httpRequest } from 'node:http'
|
|
|
6
6
|
import { createHash, randomBytes, randomUUID, timingSafeEqual, X509Certificate } from 'node:crypto'
|
|
7
7
|
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
8
8
|
import { execFile, execFileSync, spawn } from 'node:child_process'
|
|
9
|
-
import { homedir, networkInterfaces } from 'node:os'
|
|
9
|
+
import { homedir, hostname, networkInterfaces } from 'node:os'
|
|
10
10
|
import { dirname, join } from 'node:path'
|
|
11
11
|
import { fileURLToPath } from 'node:url'
|
|
12
12
|
|
|
@@ -14,6 +14,14 @@ const HERE = dirname(fileURLToPath(import.meta.url))
|
|
|
14
14
|
const TOKEN_TTL = 30 * 864e5
|
|
15
15
|
const MAX_BODY = 16 << 20
|
|
16
16
|
|
|
17
|
+
/** The name the phone shows for this Mac in its Mac picker: the Mac's own "Computer Name", else the host name. */
|
|
18
|
+
export function macName(read = () => execFileSync('scutil', ['--get', 'ComputerName'], { encoding: 'utf8', timeout: 2000 })) {
|
|
19
|
+
let n = ''
|
|
20
|
+
try { n = String(read()).trim() } catch {}
|
|
21
|
+
if (!n) n = hostname().replace(/\.local$/i, '')
|
|
22
|
+
return n.replace(/[\u0000-\u001f]/g, '').slice(0, 64) || 'Mac'
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
// Allowlisted DSH remote methods. Everything else is 403.
|
|
18
26
|
export const RPC = new Set([
|
|
19
27
|
'session/list', 'session/page', 'session/create', 'session/rename', 'session/prompt', 'session/cancel',
|
|
@@ -220,6 +228,7 @@ export function createGateway(opts = {}) {
|
|
|
220
228
|
const a = (networkInterfaces()[iface] ?? []).find(i => i.family === 'IPv4' && !i.internal)
|
|
221
229
|
return a && { address: a.address, netmask: a.netmask }
|
|
222
230
|
})
|
|
231
|
+
const mac = opts.macName ?? macName()
|
|
223
232
|
const codeTtl = opts.codeTtlMs ?? 5 * 60e3
|
|
224
233
|
const waterfallTtl = opts.waterfallTimeoutMs ?? 10 * 60e3
|
|
225
234
|
mkdirSync(dir, { recursive: true, mode: 0o700 })
|
|
@@ -290,7 +299,7 @@ export function createGateway(opts = {}) {
|
|
|
290
299
|
function newCode() {
|
|
291
300
|
const net = bound ?? netInfo()
|
|
292
301
|
code = { value: randomBytes(16).toString('base64url'), expires: Date.now() + codeTtl }
|
|
293
|
-
code.payload = JSON.stringify({ v: 1, host: net?.address, port, fp, code: code.value, ...(ts.online && ts.ip ? { ts: ts.ip } : {}) })
|
|
302
|
+
code.payload = JSON.stringify({ v: 1, host: net?.address, port, fp, code: code.value, mac, ...(ts.online && ts.ip ? { ts: ts.ip } : {}) })
|
|
294
303
|
qrReady = false
|
|
295
304
|
if (opts.qr !== false) {
|
|
296
305
|
const c = code
|
|
@@ -320,7 +329,7 @@ export function createGateway(opts = {}) {
|
|
|
320
329
|
const token = randomBytes(32).toString('base64url') // 256-bit; only its hash is stored
|
|
321
330
|
const d = { id: randomUUID(), name: p.name, tokenHash: sha(token), createdAt: new Date().toISOString(), expiresAt: new Date(Date.now() + TOKEN_TTL).toISOString() }
|
|
322
331
|
devices.push(d); saveDevices()
|
|
323
|
-
reply(p.res, 200, { token, deviceId: d.id, name: d.name, expiresAt: d.expiresAt })
|
|
332
|
+
reply(p.res, 200, { token, deviceId: d.id, name: d.name, expiresAt: d.expiresAt, mac })
|
|
324
333
|
return true
|
|
325
334
|
}
|
|
326
335
|
|
|
@@ -395,7 +404,7 @@ export function createGateway(opts = {}) {
|
|
|
395
404
|
const dev = auth(req)
|
|
396
405
|
if (!dev) { fail(ip); return reply(res, 401, { error: 'unauthorized' }) }
|
|
397
406
|
track(dev.id, req.socket)
|
|
398
|
-
if (req.method === 'GET' && path === '/me') return reply(res, 200, { deviceId: dev.id, name: dev.name, expiresAt: dev.expiresAt, upstream: upState, tailscale: ts.online ? ts.ip : null })
|
|
407
|
+
if (req.method === 'GET' && path === '/me') return reply(res, 200, { deviceId: dev.id, name: dev.name, expiresAt: dev.expiresAt, upstream: upState, tailscale: ts.online ? ts.ip : null, mac })
|
|
399
408
|
if (req.method !== 'POST' || !path.startsWith('/api/')) return reply(res, 404, { error: 'not found' })
|
|
400
409
|
const method = path.slice(5)
|
|
401
410
|
let body
|
|
@@ -475,7 +484,8 @@ export function createGateway(opts = {}) {
|
|
|
475
484
|
await new Promise((ok, bad) => { s.once('error', bad); s.listen(port, net.bind ?? '::', ok) })
|
|
476
485
|
server = s; bound = net; port = s.address().port; running = true
|
|
477
486
|
if (opts.bonjour !== false) {
|
|
478
|
-
|
|
487
|
+
// The service name is the Mac's name, so the phone's "Macs on this network" list tells two Macs apart.
|
|
488
|
+
bonjour = spawn('dns-sd', ['-R', mac, '_dshmobile._tcp', 'local', String(port), 'fp=' + fp], { stdio: 'ignore' })
|
|
479
489
|
bonjour.on('error', () => {})
|
|
480
490
|
}
|
|
481
491
|
connectEvents()
|
|
@@ -505,7 +515,7 @@ export function createGateway(opts = {}) {
|
|
|
505
515
|
watch.unref()
|
|
506
516
|
|
|
507
517
|
const state = () => ({
|
|
508
|
-
running, address: bound?.address ?? netInfo()?.address ?? null, port, tls: running ? 'TLS 1.2+, self-signed' : 'off',
|
|
518
|
+
mac, running, address: bound?.address ?? netInfo()?.address ?? null, port, tls: running ? 'TLS 1.2+, self-signed' : 'off',
|
|
509
519
|
fingerprint: fp ?? null, upstream: upState, tailscale: ts, lastTlsError,
|
|
510
520
|
code: code && Date.now() < code.expires ? { payload: code.payload, expiresAt: new Date(code.expires).toISOString(), qr: qrReady } : null,
|
|
511
521
|
pending: [...pending.values()].map(({ id, name, ip, at }) => ({ id, name, ip, at })),
|