dsh-composer-plus 1.22.0 → 1.24.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.de.md +46 -11
- package/README.es.md +46 -11
- package/README.fr.md +46 -11
- package/README.hi.md +46 -11
- package/README.id.md +46 -11
- package/README.ja.md +46 -11
- package/README.ko.md +46 -11
- package/README.md +46 -11
- package/README.pt-BR.md +46 -11
- package/README.ru.md +46 -11
- package/README.tr.md +46 -11
- package/README.vi.md +46 -11
- package/README.zh.md +46 -11
- package/assets/features/assistant.webp +0 -0
- package/assets/features/featureFilter.webp +0 -0
- package/assets/features/issueReport.webp +0 -0
- package/assets/features/previewQuote.webp +0 -0
- package/assets/features/remoteComputers.webp +0 -0
- package/assets/features/turkishSkill.webp +0 -0
- package/assets/features/untangleCodebase.webp +0 -0
- package/assets/features/windowSize.webp +0 -0
- package/assets/skills/untangle-codebase/LICENSE +21 -0
- package/assets/skills/untangle-codebase/SKILL.md +142 -0
- package/client.js +1044 -164
- package/index.js +800 -39
- package/package.json +4 -3
- package/release-notes.json +14 -14
- package/tether/gateway/server.mjs +40 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-composer-plus",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
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",
|
|
@@ -76,10 +76,11 @@
|
|
|
76
76
|
"/README.md",
|
|
77
77
|
"LICENSE",
|
|
78
78
|
"locales/LICENSE",
|
|
79
|
-
"assets/features/*.webp"
|
|
79
|
+
"assets/features/*.webp",
|
|
80
|
+
"assets/skills/"
|
|
80
81
|
],
|
|
81
82
|
"scripts": {
|
|
82
|
-
"test": "node scripts/build-locales.mjs --check && node scripts/build-docs.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/export-chat.test.mjs && node test/project-name.test.mjs && node test/queue-drag.test.mjs && node test/queue-move.test.mjs && node test/queue-edit.test.mjs && node test/send-first.test.mjs && node test/message-link.test.mjs && node test/mark-read.test.mjs && node test/plan-toggle.test.mjs && node test/keep-focus.test.mjs && node test/question-fit.test.mjs && node test/header-fit.test.mjs && node test/mobile-connect.test.mjs && node test/unread.test.mjs && node test/unread-client.test.mjs && node test/tether-gateway.test.mjs && node test/tether-parity.test.mjs && node test/tether-notify-per-mac.test.mjs && node test/tether-push-words.test.mjs && node test/deeplink.test.mjs && node test/chat-grant.test.mjs && node test/reject-note.test.mjs && node test/grant-ttl.test.mjs && node test/notify.test.mjs && node test/idle-switch.test.mjs && node test/next-waiting.test.mjs && node test/option-picks.test.mjs && node test/option-picks-ui.test.mjs && node test/changes.test.mjs && node test/chat-changes.test.mjs && node test/changes-tree.test.mjs && node test/file-chats.test.mjs && node test/file-chats-client.test.mjs && node test/feature-ideas.test.mjs && node test/feature-ideas-client.test.mjs && node test/github-issue.test.mjs && node test/project-status.test.mjs && node test/session-branch.test.mjs && node test/recent-projects.test.mjs && node test/project-tools.test.mjs && node test/has-selectors.test.mjs && node test/project-picker.test.mjs && node test/worktree-chats.test.mjs && node test/worktree-chats-client.test.mjs && node test/branch-tree.test.mjs && node test/branch-tree-client.test.mjs && node test/default-workspace.test.mjs && node test/default-workspace-client.test.mjs && node test/find-in-chat.test.mjs && node test/predict.test.mjs && node test/predict-client.test.mjs && node test/complete.test.mjs && node test/complete-client.test.mjs && node test/prompt-improve.test.mjs && node test/prompt-improve-client.test.mjs && node test/goal-check.test.mjs && node test/goal-check-client.test.mjs && node test/backup.test.mjs && node test/backup-host.test.mjs && node test/backup-client.test.mjs && node test/project-memory.test.mjs && node test/memory-editor.test.mjs && node test/memory-base.test.mjs && node test/memory-history.test.mjs && node test/memory-export.test.mjs && node test/memory-source.test.mjs && node test/memory-copy.test.mjs && node test/memory-stale.test.mjs && node test/memory-per-chat.test.mjs && node test/memory-suggest.test.mjs && node test/status-order.test.mjs && node test/toggles.test.mjs && node test/update.test.mjs && node test/whats-new-current.test.mjs && node test/release-notes.test.mjs && node test/active-count.test.mjs && node test/meta.test.mjs && node test/shots.test.mjs && node test/readme.test.mjs && node test/readme-labels.test.mjs && node test/feature-docs.test.mjs && node test/routes.test.mjs && node test/protected-files.test.mjs && node test/blocked-commands.test.mjs && node test/blocked-commands-client.test.mjs && node test/handoff.test.mjs && node test/context-breakdown.test.mjs && node test/task-board.test.mjs && node test/task-board-client.test.mjs && node test/planned-steps.test.mjs && node --test --test-timeout=120000 test/computers.test.mjs test/computers-host.test.mjs && node test/computers-client.test.mjs && node test/secret-input.test.mjs && node test/secret-input-client.test.mjs && node test/quote-reply.test.mjs && node test/side-chat.test.mjs && node test/diff-comments.test.mjs",
|
|
83
|
+
"test": "node scripts/build-locales.mjs --check && node scripts/build-docs.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/export-chat.test.mjs && node test/project-name.test.mjs && node test/queue-drag.test.mjs && node test/queue-move.test.mjs && node test/queue-edit.test.mjs && node test/send-first.test.mjs && node test/message-link.test.mjs && node test/mark-read.test.mjs && node test/plan-toggle.test.mjs && node test/keep-focus.test.mjs && node test/question-fit.test.mjs && node test/header-fit.test.mjs && node test/window-size.test.mjs && node test/mobile-connect.test.mjs && node test/unread.test.mjs && node test/unread-client.test.mjs && node test/tether-gateway.test.mjs && node test/tether-parity.test.mjs && node test/tether-notify-per-mac.test.mjs && node test/tether-push-words.test.mjs && node test/deeplink.test.mjs && node test/chat-grant.test.mjs && node test/reject-note.test.mjs && node test/grant-ttl.test.mjs && node test/notify.test.mjs && node test/idle-switch.test.mjs && node test/next-waiting.test.mjs && node test/next-waiting-locate.test.mjs && node test/option-picks.test.mjs && node test/option-picks-ui.test.mjs && node test/changes.test.mjs && node test/chat-changes.test.mjs && node test/changes-tree.test.mjs && node test/file-chats.test.mjs && node test/file-chats-client.test.mjs && node test/feature-ideas.test.mjs && node test/feature-ideas-client.test.mjs && node test/github-issue.test.mjs && node test/issue-report.test.mjs && node test/issue-report-client.test.mjs && node test/project-status.test.mjs && node test/session-branch.test.mjs && node test/recent-projects.test.mjs && node test/project-tools.test.mjs && node test/has-selectors.test.mjs && node test/project-picker.test.mjs && node test/worktree-chats.test.mjs && node test/worktree-chats-client.test.mjs && node test/branch-tree.test.mjs && node test/branch-tree-client.test.mjs && node test/default-workspace.test.mjs && node test/default-workspace-client.test.mjs && node test/find-in-chat.test.mjs && node test/predict.test.mjs && node test/predict-client.test.mjs && node test/complete.test.mjs && node test/complete-client.test.mjs && node test/prompt-improve.test.mjs && node test/prompt-improve-client.test.mjs && node test/goal-check.test.mjs && node test/goal-check-client.test.mjs && node test/backup.test.mjs && node test/backup-host.test.mjs && node test/backup-client.test.mjs && node test/project-memory.test.mjs && node test/memory-editor.test.mjs && node test/memory-base.test.mjs && node test/memory-history.test.mjs && node test/memory-export.test.mjs && node test/memory-source.test.mjs && node test/memory-copy.test.mjs && node test/memory-stale.test.mjs && node test/memory-per-chat.test.mjs && node test/memory-suggest.test.mjs && node test/status-order.test.mjs && node test/toggles.test.mjs && node test/feature-filter.test.mjs && node test/update.test.mjs && node test/whats-new-current.test.mjs && node test/whats-new-star.test.mjs && node test/release-notes.test.mjs && node test/active-count.test.mjs && node test/meta.test.mjs && node test/shots.test.mjs && node test/readme.test.mjs && node test/readme-labels.test.mjs && node test/feature-docs.test.mjs && node test/routes.test.mjs && node test/protected-files.test.mjs && node test/blocked-commands.test.mjs && node test/blocked-commands-client.test.mjs && node test/handoff.test.mjs && node test/context-breakdown.test.mjs && node test/task-board.test.mjs && node test/task-board-client.test.mjs && node test/assistant.test.mjs && node test/assistant-client.test.mjs && node test/planned-steps.test.mjs && node test/untangle-codebase.test.mjs && node test/turkish-skill.test.mjs && node --test --test-timeout=120000 test/computers.test.mjs test/computers-host.test.mjs && node test/computers-client.test.mjs && node test/secret-input.test.mjs && node test/secret-input-client.test.mjs && node test/quote-reply.test.mjs && node test/preview-quote.test.mjs && node test/side-chat.test.mjs && node test/diff-comments.test.mjs",
|
|
83
84
|
"build:locales": "node scripts/build-locales.mjs",
|
|
84
85
|
"build:readme": "node scripts/build-docs.mjs",
|
|
85
86
|
"prepublishOnly": "npm test"
|
package/release-notes.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.24.0",
|
|
3
3
|
"notes": {
|
|
4
|
-
"en": "## New\n\n- **
|
|
5
|
-
"zh": "## 新功能\n\n-
|
|
6
|
-
"tr": "## Yeni\n\n- **
|
|
7
|
-
"es": "## Novedades\n\n- **
|
|
8
|
-
"pt-BR": "## Novidades\n\n- **
|
|
9
|
-
"fr": "## Nouveautés\n\n- **
|
|
10
|
-
"de": "## Neu\n\n- **
|
|
11
|
-
"ru": "## Новое\n\n-
|
|
12
|
-
"ja": "## 新機能\n\n-
|
|
13
|
-
"ko": "## 새 기능\n\n-
|
|
14
|
-
"id": "## Baru\n\n- **
|
|
15
|
-
"vi": "## Mới\n\n- **
|
|
16
|
-
"hi": "## नया\n\n-
|
|
4
|
+
"en": "## New\n\n- **Assistant** (off by default): switch it on in Settings → Composer Plus, then click **Assistant** in the left sidebar, right under **Task board**. It opens one lasting chat in `~/Assistant` that you use as your personal assistant. It sets reminders and automations with dsh's scheduled tasks, searches the web, and lists and reads your other chats. It sends a message to a chat, or starts, stops or archives a chat, only after you click **Allow once**. It cannot delete a chat. Keep your profile in this project's memory, topic `profil`. In Tether, the \"Assistant\" button in the Sessions toolbar opens the same chat.\n\n## Changes\n\n- **Remote computers**: the bar at the top of the window is gone. While the dsh of another Mac fills the window, the computer picker in the left sidebar says **Back to this Mac**. With one other computer, a click comes back at once. With more, the click opens the menu.\n- Tether (a new build): a question that dsh asks while Tether is closed now waits for your phone, and you can answer it when you open Tether. The Mac shows it too. \"New branch\" in the `+` menu of the message field shows in every chat. When the Mac cannot make a branch, it is off and shows the reason.\n\n## Fixes\n\n- Tether: the text that you send while a turn runs no longer stays in the message field.",
|
|
5
|
+
"zh": "## 新功能\n\n- **助理**(默认关闭):在 设置 → Composer Plus 中打开,然后点击左侧边栏中 **任务看板** 正下方的 **助理**。它会在 `~/Assistant` 中打开一个长期保留的对话,你可以把它当作个人助理。它用 dsh 的定时任务设置提醒和自动化,搜索网页,并列出和阅读你的其他对话。只有在你点击 **允许一次** 之后,它才会向某个对话发送消息,或新建、停止、归档对话。它不能删除对话。请把你的个人资料保存在该项目的记忆中,主题为 `profil`。在 Tether 中,Sessions 工具栏里的“Assistant”按钮会打开同一个对话。\n\n## 变更\n\n- **远程电脑**:窗口顶部的横条已移除。当另一台 Mac 的 dsh 占满窗口时,左侧边栏中的电脑选择器显示 **返回本机**。只有一台其他电脑时,点击一次即可立即返回。有多台时,点击会打开菜单。\n- Tether(新版本):Tether 关闭时 dsh 提出的问题现在会等待你的手机,你打开 Tether 后即可回答。Mac 上也会显示这个问题。消息框 `+` 菜单中的“New branch”现在会在每个对话中显示。Mac 无法创建分支时,它会被停用并显示原因。\n\n## 修复\n\n- Tether:轮次运行时发送的文本不再留在消息框中。",
|
|
6
|
+
"tr": "## Yeni\n\n- **Asistan** (varsayılan olarak kapalı): Ayarlar → Composer Plus içinden açın, sonra sol kenar çubuğunda **Görev panosu**'nun hemen altındaki **Asistan**'a tıklayın. `~/Assistant` klasöründe, kişisel asistanınız olarak kullandığınız tek ve kalıcı bir sohbet açılır. dsh'nin zamanlanmış görevleriyle hatırlatma ve otomasyon kurar, web'de arar, öteki sohbetlerinizi listeler ve okur. Bir sohbete mesaj göndermeden, sohbet açmadan, durdurmadan ya da arşivlemeden önce sizin **Bir kez izin ver**'e tıklamanızı bekler. Sohbet silemez. Profilinizi bu projenin hafızasında, `profil` konusunda tutun. Tether'da Sessions araç çubuğundaki \"Assistant\" düğmesi aynı sohbeti açar.\n\n## Değişiklikler\n\n- **Uzak bilgisayarlar**: pencerenin üstündeki şerit kaldırıldı. Başka bir Mac'in dsh'si pencereyi kaplarken sol kenar çubuğundaki bilgisayar seçici **Bu Mac’e dön** der. Tek bir başka bilgisayar varsa bir tıklama hemen geri döner. Daha fazlası varsa tıklama menüyü açar.\n- Tether (yeni derleme): Tether kapalıyken dsh'nin sorduğu soru artık telefonunuzu bekler ve Tether'ı açınca yanıtlayabilirsiniz. Soru Mac'te de görünür. Mesaj alanının `+` menüsündeki \"New branch\" her sohbette görünür. Mac dal oluşturamıyorsa seçenek kapalıdır ve nedenini gösterir.\n\n## Düzeltmeler\n\n- Tether: bir tur çalışırken gönderdiğiniz metin artık mesaj alanında kalmaz.",
|
|
7
|
+
"es": "## Novedades\n\n- **Asistente** (desactivado de forma predeterminada): actívalo en Configuración → Composer Plus y haz clic en **Asistente** en la barra lateral izquierda, justo debajo de **Tablero de tareas**. Abre un chat permanente en `~/Assistant` que usas como tu asistente personal. Crea recordatorios y automatizaciones con las tareas programadas de dsh, busca en la web y lista y lee tus otros chats. Solo envía un mensaje a un chat, o inicia, detiene o archiva un chat, después de que hagas clic en **Permitir una vez**. No puede eliminar chats. Guarda tu perfil en la memoria de este proyecto, tema `profil`. En Tether, el botón \"Assistant\" de la barra de herramientas de Sessions abre el mismo chat.\n\n## Cambios\n\n- **Equipos remotos**: la barra de la parte superior de la ventana ya no está. Mientras el dsh de otro Mac ocupa la ventana, el selector de equipos de la barra lateral izquierda dice **Volver a este Mac**. Con un solo equipo más, un clic vuelve al instante. Con más, el clic abre el menú.\n- Tether (nueva compilación): una pregunta que dsh hace mientras Tether está cerrado ahora espera a tu teléfono, y puedes responderla al abrir Tether. El Mac también la muestra. \"New branch\" en el menú `+` del campo de mensaje aparece en todos los chats. Cuando el Mac no puede crear una rama, está desactivado y muestra el motivo.\n\n## Correcciones\n\n- Tether: el texto que envías mientras se ejecuta un turno ya no se queda en el campo de mensaje.",
|
|
8
|
+
"pt-BR": "## Novidades\n\n- **Assistente** (desativado por padrão): ative em Configurações → Composer Plus e clique em **Assistente** na barra lateral esquerda, logo abaixo de **Quadro de tarefas**. Ele abre um chat permanente em `~/Assistant` que você usa como seu assistente pessoal. Ele cria lembretes e automações com as tarefas agendadas do dsh, pesquisa na web e lista e lê seus outros chats. Ele só envia uma mensagem a um chat, ou inicia, para ou arquiva um chat, depois que você clica em **Permitir uma vez**. Ele não pode excluir chats. Guarde seu perfil na memória deste projeto, tema `profil`. No Tether, o botão \"Assistant\" da barra de ferramentas de Sessions abre o mesmo chat.\n\n## Alterações\n\n- **Computadores remotos**: a barra no topo da janela foi removida. Enquanto o dsh de outro Mac ocupa a janela, o seletor de computadores na barra lateral esquerda mostra **Voltar para este Mac**. Com só mais um computador, um clique volta na hora. Com mais, o clique abre o menu.\n- Tether (nova versão): uma pergunta que o dsh faz enquanto o Tether está fechado agora espera pelo seu celular, e você pode respondê-la ao abrir o Tether. O Mac também a mostra. \"New branch\" no menu `+` do campo de mensagem aparece em todos os chats. Quando o Mac não pode criar um branch, a opção fica desativada e mostra o motivo.\n\n## Correções\n\n- Tether: o texto que você envia enquanto um turno está em execução não fica mais no campo de mensagem.",
|
|
9
|
+
"fr": "## Nouveautés\n\n- **Assistant** (désactivé par défaut) : activez-le dans Réglages → Composer Plus, puis cliquez sur **Assistant** dans la barre latérale gauche, juste sous **Tableau des tâches**. Il ouvre une discussion durable dans `~/Assistant` que vous utilisez comme assistant personnel. Il crée des rappels et des automatisations avec les tâches planifiées de dsh, cherche sur le web, et liste et lit vos autres discussions. Il n’envoie un message à une discussion, ou ne lance, n’arrête ou n’archive une discussion, qu’après un clic sur **Autoriser une fois**. Il ne peut pas supprimer de discussion. Gardez votre profil dans la mémoire de ce projet, sujet `profil`. Dans Tether, le bouton « Assistant » de la barre d’outils de Sessions ouvre la même discussion.\n\n## Modifications\n\n- **Ordinateurs distants** : la barre en haut de la fenêtre a disparu. Pendant que le dsh d’un autre Mac remplit la fenêtre, le sélecteur d’ordinateurs de la barre latérale gauche affiche **Revenir à ce Mac**. Avec un seul autre ordinateur, un clic revient tout de suite. Avec plusieurs, le clic ouvre le menu.\n- Tether (nouvelle version) : une question que dsh pose pendant que Tether est fermé attend maintenant votre téléphone, et vous pouvez y répondre quand vous ouvrez Tether. Le Mac l’affiche aussi. « New branch » dans le menu `+` du champ de message apparaît dans chaque discussion. Quand le Mac ne peut pas créer de branche, l’option est désactivée et indique la raison.\n\n## Corrections\n\n- Tether : le texte que vous envoyez pendant qu’un tour s’exécute ne reste plus dans le champ de message.",
|
|
10
|
+
"de": "## Neu\n\n- **Assistent** (standardmäßig aus): Schalte ihn unter Einstellungen → Composer Plus ein und klicke dann in der linken Seitenleiste direkt unter **Aufgabentafel** auf **Assistent**. Er öffnet einen dauerhaften Chat in `~/Assistant`, den du als persönlichen Assistenten nutzt. Er legt mit den geplanten Aufgaben von dsh Erinnerungen und Automatisierungen an, sucht im Web und listet und liest deine anderen Chats. Er sendet eine Nachricht an einen Chat oder startet, stoppt oder archiviert einen Chat erst, nachdem du auf **Einmal zulassen** geklickt hast. Er kann keinen Chat löschen. Speichere dein Profil im Gedächtnis dieses Projekts, Thema `profil`. In Tether öffnet die Schaltfläche „Assistant“ in der Symbolleiste von Sessions denselben Chat.\n\n## Änderungen\n\n- **Remote-Computer**: Die Leiste oben im Fenster ist weg. Während das dsh eines anderen Mac das Fenster füllt, zeigt die Computerauswahl in der linken Seitenleiste **Zurück zu diesem Mac**. Bei nur einem anderen Computer führt ein Klick sofort zurück. Bei mehreren öffnet der Klick das Menü.\n- Tether (neuer Build): Eine Frage, die dsh stellt, während Tether geschlossen ist, wartet jetzt auf dein iPhone, und du kannst sie beantworten, wenn du Tether öffnest. Der Mac zeigt sie ebenfalls. „New branch“ im Menü `+` des Nachrichtenfelds erscheint in jedem Chat. Wenn der Mac keinen Branch anlegen kann, ist die Option aus und nennt den Grund.\n\n## Korrekturen\n\n- Tether: Text, den du sendest, während ein Durchlauf läuft, bleibt nicht mehr im Nachrichtenfeld.",
|
|
11
|
+
"ru": "## Новое\n\n- **Ассистент** (по умолчанию выключено): включите его в Настройки → Composer Plus, затем нажмите **Ассистент** на левой боковой панели, сразу под **Доска задач**. Откроется один постоянный чат в `~/Assistant`, которым вы пользуетесь как личным ассистентом. Он создаёт напоминания и автоматизации с помощью запланированных задач dsh, ищет в интернете, показывает список ваших других чатов и читает их. Отправить сообщение в чат, начать, остановить или архивировать чат он может только после того, как вы нажмёте **Разрешить один раз**. Удалять чаты он не может. Храните свой профиль в памяти этого проекта, тема `profil`. В Tether кнопка «Assistant» на панели инструментов Sessions открывает тот же чат.\n\n## Изменения\n\n- **Удалённые компьютеры**: полоса вверху окна убрана. Пока dsh другого Mac занимает окно, переключатель компьютеров на левой боковой панели показывает **Вернуться к этому Mac**. Если другой компьютер один, нажатие сразу возвращает назад. Если их больше, нажатие открывает меню.\n- Tether (новая сборка): вопрос, который dsh задаёт, пока Tether закрыт, теперь ждёт ваш телефон, и вы можете ответить на него, когда откроете Tether. Mac тоже показывает его. «New branch» в меню `+` поля сообщения есть в каждом чате. Если Mac не может создать ветку, пункт выключен и показывает причину.\n\n## Исправления\n\n- Tether: текст, который вы отправляете во время выполнения хода, больше не остаётся в поле сообщения.",
|
|
12
|
+
"ja": "## 新機能\n\n- **アシスタント**(既定ではオフ):設定 → Composer Plus でオンにして、左サイドバーの **タスクボード** のすぐ下にある **アシスタント** をクリックします。`~/Assistant` に、パーソナルアシスタントとして使う長く続く 1 つのチャットが開きます。dsh のスケジュールされたタスクでリマインダーと自動化を設定し、Web を検索し、ほかのチャットを一覧表示して読みます。チャットへのメッセージ送信と、チャットの開始、停止、アーカイブは、あなたが **1回だけ許可** をクリックした後にだけ行います。チャットは削除できません。プロフィールは、このプロジェクトのメモリーのトピック `profil` に保存してください。Tether では、Sessions のツールバーにある「Assistant」ボタンが同じチャットを開きます。\n\n## 変更点\n\n- **リモートコンピュータ**:ウィンドウ上部のバーはなくなりました。別の Mac の dsh がウィンドウ全体に表示されている間、左サイドバーのコンピュータ選択は **この Mac に戻る** と表示します。ほかのコンピュータが 1 台だけなら、1 回のクリックですぐに戻ります。複数あるときは、クリックでメニューが開きます。\n- Tether(新しいビルド):Tether が閉じている間に dsh が出した質問は、iPhone を待つようになりました。Tether を開いたときに回答できます。Mac にも表示されます。メッセージ欄の `+` メニューにある「New branch」は、すべてのチャットに表示されます。Mac がブランチを作れないときはオフになり、理由を表示します。\n\n## 修正\n\n- Tether:ターンの実行中に送信したテキストが、メッセージ欄に残らなくなりました。",
|
|
13
|
+
"ko": "## 새 기능\n\n- **어시스턴트**(기본적으로 꺼짐): 설정 → Composer Plus에서 켠 다음, 왼쪽 사이드바에서 **작업 보드** 바로 아래의 **어시스턴트**를 클릭하세요. `~/Assistant`에 개인 어시스턴트로 쓰는, 오래 유지되는 채팅 하나가 열립니다. dsh의 예약 작업으로 미리 알림과 자동화를 설정하고, 웹을 검색하고, 다른 채팅을 나열하고 읽습니다. 채팅에 메시지를 보내거나 채팅을 시작, 중지, 보관하는 일은 **한 번 허용**을 클릭한 뒤에만 합니다. 채팅을 삭제할 수는 없습니다. 프로필은 이 프로젝트의 메모리에 `profil` 주제로 저장해 두세요. Tether에서는 Sessions 도구 막대의 \"Assistant\" 버튼이 같은 채팅을 엽니다.\n\n## 변경 사항\n\n- **원격 컴퓨터**: 창 위쪽의 막대가 없어졌습니다. 다른 Mac의 dsh가 창을 채우는 동안, 왼쪽 사이드바의 컴퓨터 선택기에 **이 Mac으로 돌아가기**가 표시됩니다. 다른 컴퓨터가 하나뿐이면 한 번의 클릭으로 바로 돌아옵니다. 더 많으면 클릭할 때 메뉴가 열립니다.\n- Tether(새 빌드): Tether가 닫혀 있는 동안 dsh가 묻는 질문은 이제 휴대폰을 기다리며, Tether를 열 때 답할 수 있습니다. Mac에도 표시됩니다. 메시지 입력란의 `+` 메뉴에 있는 \"New branch\"가 모든 채팅에 표시됩니다. Mac이 브랜치를 만들 수 없으면 꺼지고 이유를 보여 줍니다.\n\n## 수정 사항\n\n- Tether: 턴이 실행되는 동안 보낸 텍스트가 더 이상 메시지 입력란에 남지 않습니다.",
|
|
14
|
+
"id": "## Baru\n\n- **Asisten** (nonaktif secara default): aktifkan di Pengaturan → Composer Plus, lalu klik **Asisten** di bilah samping kiri, tepat di bawah **Papan tugas**. Fitur ini membuka satu obrolan tetap di `~/Assistant` yang Anda pakai sebagai asisten pribadi. Asisten membuat pengingat dan otomatisasi dengan tugas terjadwal dsh, mencari di web, serta menampilkan dan membaca obrolan Anda yang lain. Asisten hanya mengirim pesan ke obrolan, atau memulai, menghentikan, atau mengarsipkan obrolan, setelah Anda mengklik **Izinkan sekali**. Asisten tidak dapat menghapus obrolan. Simpan profil Anda di memori proyek ini, topik `profil`. Di Tether, tombol \"Assistant\" di bilah alat Sessions membuka obrolan yang sama.\n\n## Perubahan\n\n- **Komputer jarak jauh**: bilah di bagian atas jendela sudah dihapus. Saat dsh dari Mac lain memenuhi jendela, pemilih komputer di bilah samping kiri menampilkan **Kembali ke Mac ini**. Jika hanya ada satu komputer lain, satu klik langsung kembali. Jika lebih, klik membuka menu.\n- Tether (build baru): pertanyaan yang diajukan dsh saat Tether tertutup kini menunggu ponsel Anda, dan Anda dapat menjawabnya saat membuka Tether. Mac juga menampilkannya. \"New branch\" di menu `+` kolom pesan muncul di setiap obrolan. Jika Mac tidak dapat membuat branch, opsi ini nonaktif dan menampilkan alasannya.\n\n## Perbaikan\n\n- Tether: teks yang Anda kirim saat giliran berjalan tidak lagi tertinggal di kolom pesan.",
|
|
15
|
+
"vi": "## Mới\n\n- **Trợ lý** (mặc định tắt): bật trong Cài đặt → Composer Plus, rồi nhấp **Trợ lý** ở thanh bên trái, ngay bên dưới **Bảng tác vụ**. Tính năng này mở một cuộc trò chuyện lâu dài trong `~/Assistant` mà bạn dùng làm trợ lý cá nhân. Trợ lý đặt lời nhắc và tự động hóa bằng các tác vụ theo lịch của dsh, tìm kiếm trên web, liệt kê và đọc các cuộc trò chuyện khác của bạn. Trợ lý chỉ gửi tin nhắn đến một cuộc trò chuyện, hoặc bắt đầu, dừng hay lưu trữ một cuộc trò chuyện, sau khi bạn nhấp **Cho phép một lần**. Trợ lý không thể xóa cuộc trò chuyện. Hãy lưu hồ sơ của bạn trong bộ nhớ của dự án này, chủ đề `profil`. Trong Tether, nút \"Assistant\" trên thanh công cụ Sessions mở cùng cuộc trò chuyện đó.\n\n## Thay đổi\n\n- **Máy tính từ xa**: thanh ở đầu cửa sổ đã được bỏ. Khi dsh của một máy Mac khác chiếm toàn bộ cửa sổ, bộ chọn máy tính ở thanh bên trái hiện **Quay lại máy Mac này**. Nếu chỉ có một máy tính khác, một lần nhấp sẽ quay lại ngay. Nếu có nhiều hơn, lần nhấp sẽ mở menu.\n- Tether (bản dựng mới): câu hỏi mà dsh đặt ra khi Tether đang đóng giờ sẽ chờ điện thoại của bạn, và bạn có thể trả lời khi mở Tether. Mac cũng hiện câu hỏi đó. \"New branch\" trong menu `+` của ô tin nhắn hiện ở mọi cuộc trò chuyện. Khi Mac không thể tạo branch, tùy chọn này bị tắt và cho biết lý do.\n\n## Sửa lỗi\n\n- Tether: văn bản bạn gửi trong khi một lượt đang chạy không còn nằm lại trong ô tin nhắn.",
|
|
16
|
+
"hi": "## नया\n\n- **असिस्टेंट** (डिफ़ॉल्ट रूप से बंद): इसे सेटिंग → Composer Plus में चालू करें, फिर बाएं साइडबार में **टास्क बोर्ड** के ठीक नीचे **असिस्टेंट** पर क्लिक करें। यह `~/Assistant` में एक स्थायी चैट खोलता है, जिसे आप अपने निजी असिस्टेंट की तरह इस्तेमाल करते हैं। यह dsh के शेड्यूल किए गए टास्क से रिमाइंडर और ऑटोमेशन बनाता है, वेब पर खोजता है, और आपकी दूसरी चैट की सूची दिखाता और उन्हें पढ़ता है। यह किसी चैट को संदेश भेजने, या चैट शुरू करने, रोकने या आर्काइव करने का काम तभी करता है जब आप **एक बार अनुमति दें** पर क्लिक करते हैं। यह चैट डिलीट नहीं कर सकता। अपनी प्रोफ़ाइल इस प्रोजेक्ट की मेमोरी में, विषय `profil` में रखें। Tether में, Sessions टूलबार का \"Assistant\" बटन वही चैट खोलता है।\n\n## बदलाव\n\n- **रिमोट कंप्यूटर**: विंडो के ऊपर वाली पट्टी हटा दी गई है। जब किसी दूसरे Mac का dsh विंडो भरता है, तब बाएं साइडबार का कंप्यूटर पिकर **इस Mac पर वापस जाएं** दिखाता है। सिर्फ़ एक दूसरा कंप्यूटर होने पर एक क्लिक तुरंत वापस ले आता है। ज़्यादा होने पर क्लिक मेन्यू खोलता है।\n- Tether (नया बिल्ड): Tether बंद होने पर dsh जो सवाल पूछता है, वह अब आपके फ़ोन का इंतज़ार करता है, और Tether खोलने पर आप उसका जवाब दे सकते हैं। Mac भी उसे दिखाता है। मैसेज फ़ील्ड के `+` मेन्यू में \"New branch\" हर चैट में दिखता है। जब Mac ब्रांच नहीं बना सकता, तब यह बंद रहता है और कारण बताता है।\n\n## सुधार\n\n- Tether: टर्न चलते समय भेजा गया टेक्स्ट अब मैसेज फ़ील्ड में नहीं रहता।"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -51,6 +51,7 @@ export const PLUS = new Map([
|
|
|
51
51
|
['queue-move', ['POST']], ['queue-edit', ['POST']], ['branches', ['GET']], ['predict', ['POST']], ['complete', ['POST']], ['improve', ['POST']], ['unread', ['GET', 'POST']],
|
|
52
52
|
['worktrees', ['GET', 'POST']], ['new-session-workspace', ['POST']], ['memory-edit', ['GET', 'POST']], ['memory-history', ['GET', 'POST']], ['memory-export', ['POST']], ['memory-copy', ['GET', 'POST']], ['memory-stale', ['GET']], ['memory-chat', ['GET', 'POST']], ['memory-suggest', ['POST']], ['handoff', ['POST']], ['context', ['GET']],
|
|
53
53
|
['board-chats', ['GET', 'POST']], ['board-progress', ['GET']], ['secret-answer', ['GET', 'POST']], ['side-chat', ['GET', 'POST']],
|
|
54
|
+
['issue-report', ['POST']], ['assistant', ['GET']],
|
|
54
55
|
])
|
|
55
56
|
/** Allow for this chat: an Auto Review ask (`approval/request` with this reason) for a tool that the chat granted. */
|
|
56
57
|
export const AUTO_REVIEW_ASK = 'Auto review denied tool '
|
|
@@ -291,10 +292,14 @@ function pipeUpgrade(req, socket, head, opts) {
|
|
|
291
292
|
up.end()
|
|
292
293
|
}
|
|
293
294
|
|
|
294
|
-
/**
|
|
295
|
-
*
|
|
296
|
-
|
|
297
|
-
|
|
295
|
+
/** The paths that the relay answers itself (never sent to the computer): the other Mac's page asks which computers this
|
|
296
|
+
* Mac has (`opener`) and switches this Mac's window to one of them (`switch`). */
|
|
297
|
+
export const RELAY_OWN = '/__composer-plus/'
|
|
298
|
+
/** Remote computers, the Mac that opens: one loopback port per paired computer. dsh's window (a `<webview>` on desktop, an
|
|
299
|
+
* iframe on dsh web) gets a one-time ticket URL; the ticket becomes this port's own cookie. Each request then goes to the
|
|
300
|
+
* computer over TLS that must show the pinned certificate (checked before one byte goes out), with the computer's token.
|
|
301
|
+
* `peer`: `{ opener(), signal(event) }` of this Mac, for the paths under `RELAY_OWN`. */
|
|
302
|
+
export function createRelay({ host, port, fp, token, ticketTtlMs = 60e3, onUnauthorized, connectTimeoutMs = 5000, frameAncestors = [], peer }) {
|
|
298
303
|
const pin = normFp(fp)
|
|
299
304
|
const tickets = new Map() // one-time ticket → expiry
|
|
300
305
|
const cookieValue = randomBytes(32).toString('base64url')
|
|
@@ -349,14 +354,28 @@ export function createRelay({ host, port, fp, token, ticketTtlMs = 60e3, onUnaut
|
|
|
349
354
|
return res.end()
|
|
350
355
|
}
|
|
351
356
|
if (!hasCookie(req)) return text(res, 401, 'Pick the computer again in dsh.')
|
|
352
|
-
// Each answer may show only in this port's own frames and in dsh's page (its
|
|
357
|
+
// Each answer may show only in this port's own frames and in dsh's page (its window).
|
|
353
358
|
const writeHead = res.writeHead.bind(res)
|
|
354
359
|
res.writeHead = (code, headers = {}) => writeHead(code, { ...headers, 'content-security-policy': [headers['content-security-policy'] ?? [], `frame-ancestors ${ancestors}`].flat() })
|
|
360
|
+
if (url.pathname.startsWith(RELAY_OWN)) return ownPath(req, res, url.pathname.slice(RELAY_OWN.length))
|
|
355
361
|
let unpaired = false
|
|
356
362
|
await pipeHttp(req, res, next(req), { onStatus: (code) => { const r = status(code); if (r === 'skip') unpaired = true; return r },
|
|
357
363
|
onError: (r) => text(r, 502, fail === 'pin' ? 'This computer shows another certificate. Pair it again in dsh.' : 'This computer does not answer over Tailscale. Make sure that it is awake and that Tailscale is on.') })
|
|
358
364
|
if (unpaired) text(res, 401, UNPAIRED)
|
|
359
365
|
}
|
|
366
|
+
/** The other Mac's page (in this Mac's window) reads this Mac's computers and switches the window: nothing else. */
|
|
367
|
+
async function ownPath(req, res, name) {
|
|
368
|
+
if (peer === undefined) return reply(res, 404, { error: 'not found' })
|
|
369
|
+
if (name === 'opener' && req.method === 'GET') { peer.signal({ hello: true }); return reply(res, 200, peer.opener()) }
|
|
370
|
+
if (name === 'switch' && req.method === 'POST') {
|
|
371
|
+
let to
|
|
372
|
+
try { to = JSON.parse(await readBody(req, 1024))?.to } catch { return reply(res, 400, { error: 'bad request' }) }
|
|
373
|
+
if (to !== 'self' && to !== 'add' && !(typeof to === 'string' && /^[0-9a-f]{64}$/.test(to))) return reply(res, 400, { error: 'bad request' })
|
|
374
|
+
peer.signal({ switch: to })
|
|
375
|
+
return reply(res, 200, { ok: true })
|
|
376
|
+
}
|
|
377
|
+
return reply(res, 404, { error: 'not found' })
|
|
378
|
+
}
|
|
360
379
|
function onUpgrade(req, socket, head) {
|
|
361
380
|
if (!trusted(req) || !hasCookie(req)) return socket.end('HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n')
|
|
362
381
|
pipeUpgrade(req, socket, head, next(req))
|
|
@@ -649,6 +668,8 @@ export function createGateway(opts = {}) {
|
|
|
649
668
|
if (devices.length !== before) saveDevices()
|
|
650
669
|
for (const s of devSockets.get(id) ?? []) s.destroy()
|
|
651
670
|
devSockets.delete(id)
|
|
671
|
+
// No paired phone is left to answer the questions that wait for one: they go back to dsh's desktop.
|
|
672
|
+
if (devices.length === 0) for (const e of [...pendingEv.keys()]) dropPending(e, { kind: 'next' })
|
|
652
673
|
return devices.length !== before
|
|
653
674
|
}
|
|
654
675
|
function notify(msg) {
|
|
@@ -736,11 +757,13 @@ export function createGateway(opts = {}) {
|
|
|
736
757
|
if (v.type === 'cancel' && dropPending(v.eventId)) return toPhones({ type: 'cancel', eventId: v.eventId })
|
|
737
758
|
if (v.type !== 'waterfall') return
|
|
738
759
|
if (v.event === 'approval/request') return grantedOrAsk(v)
|
|
739
|
-
if (!EVENTS.has(v.event) ||
|
|
760
|
+
if (!EVENTS.has(v.event) || devices.length === 0) return answer(v.eventId, { kind: 'next' }).catch(() => {})
|
|
740
761
|
askPhones(v)
|
|
741
762
|
}
|
|
742
|
-
/** The gateway keeps an
|
|
743
|
-
* and Tether gets the ask when it connects. dsh's desktop can answer it at the same time.
|
|
763
|
+
/** The gateway keeps an approval for the phones while one is connected, or while a phone gets pushes: the push opens
|
|
764
|
+
* Tether, and Tether gets the ask when it connects. dsh's desktop can answer it at the same time. A question
|
|
765
|
+
* (`ask_user_question`) waits for a paired phone also while Tether is closed: dsh's "next" would leave it on the desktop
|
|
766
|
+
* only, and the phone that opens later could not answer it. The question still shows on the desktop meanwhile. */
|
|
744
767
|
const holds = () => evSubs.size > 0 || pushTo().length > 0
|
|
745
768
|
/** Allow for this chat, also with no dsh window open: the gateway allows a granted tool itself (the grants that the
|
|
746
769
|
* desktop and the phone save in dsh-composer-plus). Any other approval goes to the phones. */
|
|
@@ -757,8 +780,10 @@ export function createGateway(opts = {}) {
|
|
|
757
780
|
const frame = { type: 'waterfall', event: v.event, eventId: v.eventId, agentId: v.agentId, request: v.request }
|
|
758
781
|
if (v.event === 'approval/request') pushAll('Approval needed', v.request?.toolName, v.agentId)
|
|
759
782
|
else pushAll('DSH has a question', v.request?.questions?.[0]?.question, v.agentId)
|
|
760
|
-
// shortcut: unanswered
|
|
761
|
-
|
|
783
|
+
// shortcut: an unanswered approval falls back to 'next' (DSH desktop still decides) after a fixed timeout; make it configurable if users want longer.
|
|
784
|
+
// A question has no timeout: dsh waits for its answer, and the phone that opens hours later must still get it.
|
|
785
|
+
const timer = v.event === 'approval/request'
|
|
786
|
+
? setTimeout(() => { if (dropPending(v.eventId, { kind: 'next' })) toPhones({ type: 'cancel', eventId: v.eventId }) }, waterfallTtl) : undefined
|
|
762
787
|
pendingEv.set(v.eventId, { frame, timer })
|
|
763
788
|
toPhones(frame)
|
|
764
789
|
}
|
|
@@ -892,7 +917,11 @@ export function createGateway(opts = {}) {
|
|
|
892
917
|
// A failed connect (DSH restarting) is forgotten so the next stream open retries instead of failing forever.
|
|
893
918
|
const getUp = () => upP ??= upstream.mux().then(u => { up = u; u.onText = t => ws.send(t); u.onClose = () => ws.close(1011); return u }, e => { upP = null; throw e })
|
|
894
919
|
const err = (streamId, message) => ws.send(JSON.stringify({ type: 'error', streamId, error: { code: 'mobile/forbidden', message } }))
|
|
895
|
-
|
|
920
|
+
// The last phone left: its approvals go back to dsh's desktop; its questions keep waiting for the phone (askPhones).
|
|
921
|
+
const unsub = id => {
|
|
922
|
+
const s = subs.get(id); if (!s) return; subs.delete(id); evSubs.delete(s)
|
|
923
|
+
if (!holds()) for (const [e, p] of [...pendingEv]) if (p.frame.event === 'approval/request') dropPending(e, { kind: 'next' })
|
|
924
|
+
}
|
|
896
925
|
ws.onText = async text => {
|
|
897
926
|
let f
|
|
898
927
|
try { f = JSON.parse(text) } catch { return ws.close(1007) }
|