dsh-composer-plus 1.20.0 → 1.21.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 +71 -9
- package/README.es.md +71 -9
- package/README.fr.md +71 -9
- package/README.hi.md +71 -9
- package/README.id.md +71 -9
- package/README.ja.md +71 -9
- package/README.ko.md +71 -9
- package/README.md +71 -9
- package/README.pt-BR.md +71 -9
- package/README.ru.md +71 -9
- package/README.tr.md +71 -9
- package/README.vi.md +71 -9
- package/README.zh.md +71 -9
- package/assets/features/diffComments.webp +0 -0
- package/assets/features/memoryCopy.webp +0 -0
- package/assets/features/memoryExport.webp +0 -0
- package/assets/features/memoryHistory.webp +0 -0
- package/assets/features/memoryPerChat.webp +0 -0
- package/assets/features/memorySource.webp +0 -0
- package/assets/features/memoryStale.webp +0 -0
- package/assets/features/memorySuggest.webp +0 -0
- package/assets/features/nextWaiting.webp +0 -0
- package/assets/features/optionPicks.webp +0 -0
- package/assets/features/quoteReply.webp +0 -0
- package/assets/features/rejectNote.webp +0 -0
- package/assets/features/remoteComputers.webp +0 -0
- package/assets/features/secretInput.webp +0 -0
- package/assets/features/sideChat.webp +0 -0
- package/assets/features/taskBoard.webp +0 -0
- package/client.js +2587 -169
- package/index.js +1432 -77
- package/package.json +4 -3
- package/release-notes.json +14 -14
- package/tether/gateway/server.mjs +246 -21
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ dsh plugin --profile web add dsh-composer-plus
|
|
|
27
27
|
|
|
28
28
|
Then restart dsh. (The CLI can't install into the desktop profile; the app manages it.)
|
|
29
29
|
|
|
30
|
-
> dsh's pnpm skips versions younger than 24 hours. Right after a release, add the version: `dsh-composer-plus@1.
|
|
30
|
+
> dsh's pnpm skips versions younger than 24 hours. Right after a release, add the version: `dsh-composer-plus@1.21.0`.
|
|
31
31
|
|
|
32
32
|
## Features
|
|
33
33
|
|
|
@@ -69,9 +69,21 @@ Then restart dsh. (The CLI can't install into the desktop profile; the app manag
|
|
|
69
69
|
| **Planned steps** | <a id="feature-plannedsteps"></a>Off by default: switch it on in **Settings → Composer Plus**. The agent gets the tool `plan_next_steps`: in the same message as a command, it can plan the next commands with their exact arguments and a condition, for example "run `npm test` when the build passes". When the result meets the condition, Composer Plus runs the next step itself, without a new model call, so a long chat uses fewer tokens. The step shows in the chat as a short line, "Composer Plus · Planned steps: ran `test` … without a model call", followed by its tool call and its result. Only `bash`, `read`, `grep` and `glob` steps; approvals, the sandbox and Protected files apply to each step as usual. The model answers again when a condition fails, when two steps are ready at the same time, after the last step, and when you send a message. The idea comes from HarnessMM (arXiv 2610.32813). | <a href="assets/features/plannedSteps.webp"><img src="assets/features/plannedSteps.webp" width="160" alt="Screenshot: Planned steps"></a> |
|
|
70
70
|
| **Protected files** | <a id="feature-protectedfiles"></a>On by default. The agent's own file tools cannot read or change files that match your patterns: `read`, `read_image` and `grep` on a file are refused for **read and write** patterns, and `write`, `edit` and `str_replace_editor` for both kinds. The agent reads why and is told to ask you. The defaults are `.env*`, `*.pem` and `*.key`. Settings → Composer Plus → **Protected files**: add a pattern (for example `published/**` or `config/*.yml`), click its kind to switch between **read and write** and **write only**, remove it with ✕, or **Use the defaults**. A pattern without `/` matches a file name in any folder. This is a guard rail, not a sandbox: a shell command (`cat .env`), a script or an MCP tool can still reach the file (see Limits). | <a href="assets/features/protectedFiles.webp"><img src="assets/features/protectedFiles.webp" width="160" alt="Screenshot: Protected files"></a> |
|
|
71
71
|
| **Blocked commands** | <a id="feature-blockedcommands"></a>On by default, with an empty list. The agent's shell commands (`bash`, `pwsh`) cannot run a command that matches your rules: a **block** rule refuses the call (the agent reads why and is told to ask you), an **ask first** rule shows dsh's approval card, and the command runs only when you allow it. Settings → Composer Plus → **Blocked commands**: type a rule (for example `npm publish`, `git push --force` or `ssh *192.168.2.19`), click the kind to switch between **block** and **ask first**, then **Add**; click a rule's kind to change it, remove it with ✕. A rule is a command name and words that must come after it in this order; `*` matches any text. It also finds the command after `&&`, `;`, `\|`, inside `$(…)`, `bash -c "…"` or `eval`, and after `sudo` or `env`. This is a guard rail, not a sandbox: a variable (`$CMD`), a script file or another program can still run the command (see Limits). | <a href="assets/features/blockedCommands.webp"><img src="assets/features/blockedCommands.webp" width="160" alt="Screenshot: Blocked commands"></a> |
|
|
72
|
-
| **Task board** | <a id="feature-taskboard"></a>Left sidebar → **Task board
|
|
72
|
+
| **Task board** | <a id="feature-taskboard"></a>Left sidebar → **Task board**, or press `Cmd+Shift+K` (`Ctrl+Shift+K` on Windows and Linux) anywhere in dsh. A kanban board of your dsh chats with the live state that the sidebar shows: a chat that waits for your approval, answer or plan review is in **Review** with an orange dot, a running chat is in **Doing**, a finished chat that you did not open yet is in **Done** (green). When you open a chat, its card leaves **Done** by itself; click **Recently finished (N)** under the green cards to see the finished chats that you read (the newest 10, then **Show N older**; open or closed is kept on this device). A chat that finishes while it is open behind the board (a **New task**) stays green until you open it. Click the project name at the top of the board to open the project list, then pick a project or **All projects**; a Branch per chat folder counts as its project. The list closes after the pick, with `Esc` or with a click outside it. Type in **Search projects** at the top of the list to find a project by its name (case and accents do not matter; `Esc` empties the box) and press `Enter` to pick the first match, and click **Active in the last 2 hours** to show only projects with a chat that waits, runs, finished unseen or changed in the last 2 hours (kept on this device). **New task** (or `n`) opens dsh's own new chat in the project that the board shows (with **All projects**, the project that dsh's New session picks), so you can add files, use commands and pick the model as in any chat. When your first message goes, the board comes back by itself. Until then the chat waits at the top of **Doing** as **New task**: click it to write the first message. A project with a chat that waits for you has an orange dot in the project list (the project name at the top has it too while any chat waits). dsh names the chat and the chat's model writes up to 3 tags from that message. Click a card to open its chat. Click an orange card (or its **Answer**) to answer it on the board; the panel has **Open chat** for the whole chat: **Reject** or **Allow once**, **Approve** or **Request changes** for a plan, or the options and your own text for a question. Click **×** on a finished card to take it off the board, or open **Recently finished** and click **Clear all** at the top of **Done** to take those cards off it: it first shows how many cards of which project go, and unread (green) cards stay. For 8 seconds after, **Undo** puts the cards back; **Removed (N)** under **Done** lists the cards that are off the board, and **Put back** shows one in **Done** again. No chat is deleted: the chats stay in dsh's sidebar, the board remembers this after a restart (Tether shows the same board), and a chat that runs again comes back. Point at a card in **Doing** (or move the keyboard focus to it) to see its progress: how long it runs, the step of its todo list, the tool that runs now and the agent's last line. In Settings → Composer Plus → Task board, **Progress on hover** picks **Fast (no AI)** (the default: it reads the chat only) or **AI summary** (one short call to the chat's model also writes one or two sentences). | <a href="assets/features/taskBoard.webp"><img src="assets/features/taskBoard.webp" width="160" alt="Screenshot: Task board"></a> |
|
|
73
73
|
| **Project memory** | <a id="feature-projectmemory"></a>Off by default: switch it on in **Settings → Composer Plus**. Each project folder gets its own memory, which later chats of that project read, as DS Bot keeps one per Bot. After each finished turn, one call to the chat's model reads the new messages (not rolled-back ones) and keeps your lasting preferences, decisions and facts as short notes, and changes or removes old ones. The agent can also save, remove and search notes itself (`memory_remember`, `memory_forget`, `memory_recall`). A note can also be global: every project reads it. A new chat gets the notes in its system prompt; a note saved later shows from the next chat. The files are Markdown under the dsh home (`storages/dsh-composer-plus/memory/`), never in the project folder. **Open memory** in the same row shows every saved note, grouped by project (and the global memory), with a filter. Write what to change in your own words (for example "I switched from yarn to pnpm"), then **Preview changes**: dsh's default model proposes the changes, and only **Apply** saves them. In Tether: chat title menu → Project memory. | <a href="assets/features/projectMemory.webp"><img src="assets/features/projectMemory.webp" width="160" alt="Screenshot: Project memory"></a> |
|
|
74
|
+
| **Memory version history** | <a id="feature-memoryhistory"></a>On by default while **Project memory** is on. Before each save of the memory (the agent, the review after a turn, **Open memory**), a copy of the notes as they were is kept. In **Open memory**, select a project or **Global memory**, then **History**: the versions by date and who changed the memory after each one. Select a version to see what a restore changes as a diff, then **Restore**. The notes before a restore are kept too, so you can undo it. The newest 50 versions of each memory stay. In Tether: chat title menu → Project memory → History. | <a href="assets/features/memoryHistory.webp"><img src="assets/features/memoryHistory.webp" width="160" alt="Screenshot: Memory version history"></a> |
|
|
75
|
+
| **Export memory to AGENTS.md** | <a id="feature-memoryexport"></a>In **Open memory**, select a project, then **Export to AGENTS.md**: the notes of that project go into a marked section of `AGENTS.md` in its folder, so you can commit them and share them with your team and other agent tools. You see the change as a diff first; only **Write AGENTS.md** saves it. The next export replaces only that section. The global memory, sources and dates stay out. In Tether: chat title menu → Project memory → Export to AGENTS.md. | <a href="assets/features/memoryExport.webp"><img src="assets/features/memoryExport.webp" width="160" alt="Screenshot: Export memory to AGENTS.md"></a> |
|
|
76
|
+
| **Memory note source link** | <a id="feature-memorysource"></a>In **Open memory**, a note that came from a chat (the agent saved it, the review after a turn kept it, or you accepted a suggestion) has **Source** next to it: a click opens that chat at the message, so you can check why the note is there before you change or remove it. A note from an earlier version opens only its chat. In Tether: chat title menu → Project memory → Source. | <a href="assets/features/memorySource.webp"><img src="assets/features/memorySource.webp" width="160" alt="Screenshot: Memory note source link"></a> |
|
|
77
|
+
| **Copy memory to another project** | <a id="feature-memorycopy"></a>In **Open memory**, select a project or **Global memory**, then **Copy to project**: tick the notes, search dsh's projects and click one. All the ticked notes go into that project's memory (with their topic and source), or none: when one does not fit, nothing is copied and the reason shows. A note the project already has is skipped. In Tether: chat title menu → Project memory → Copy to project. | <a href="assets/features/memoryCopy.webp"><img src="assets/features/memoryCopy.webp" width="160" alt="Screenshot: Copy memory to another project"></a> |
|
|
78
|
+
| **Find stale memory notes** | <a id="feature-memorystale"></a>When you select a project in **Open memory**, the file paths (in `code`), npm scripts and branch names that its notes name are checked against the project now. A note that names something the project does not have any more shows ⚠ with what is missing, so you can fix or remove it before the model works from it. It reads only regular files inside the project folder and one git list of branches; it changes nothing and calls no model. In Tether: chat title menu → Project memory. | <a href="assets/features/memoryStale.webp"><img src="assets/features/memoryStale.webp" width="160" alt="Screenshot: Find stale memory notes"></a> |
|
|
79
|
+
| **Do not use memory in this chat** | <a id="feature-memoryperchat"></a>While **Project memory** is on, the chat header shows **Memory on**: click it to switch the memory off for that chat only (**Memory off**). That chat's model then gets no memory section and no memory tools, and the review after each turn does not read it. On dsh 0.2.1 and later the same button is on the New chat screen, so a test chat starts without the memory. Other chats are not changed. In Tether: chat title menu → Use project memory. | <a href="assets/features/memoryPerChat.webp"><img src="assets/features/memoryPerChat.webp" width="160" alt="Screenshot: Do not use memory in this chat"></a> |
|
|
80
|
+
| **Suggest memory notes from a chat** | <a id="feature-memorysuggest"></a>While **Project memory** is on, the chat header has **Suggest for memory**: a click asks the chat's own model which rules and decisions of this chat are worth keeping for later chats. Each suggestion shows why; **Accept** saves it with a link to the chat and the message it came from, **Reject** drops it. Nothing is saved before you accept, and the model is called only when you click. Messages withdrawn by a rollback are not sent. In Tether: chat title menu → Suggest for memory. | <a href="assets/features/memorySuggest.webp"><img src="assets/features/memorySuggest.webp" width="160" alt="Screenshot: Suggest memory notes from a chat"></a> |
|
|
74
81
|
| **Allow for this chat** | <a id="feature-allowforchat"></a>When Auto Review asks you, the approval card gets **Allow for this chat**: the same tool in the same chat is allowed from then on, with any arguments, until the time limit ends (1 hour by default; choose it under **Settings → Composer Plus → Allow for this chat**). Then the agent asks again. A header chip lists the grants with their end time and revokes them. Grants survive a restart. | <a href="assets/features/allowForChat.webp"><img src="assets/features/allowForChat.webp" width="160" alt="Screenshot: Allow for this chat"></a> |
|
|
82
|
+
| **Reject with note** | <a id="feature-rejectnote"></a>An approval card gets **Reject with note…** next to **Reject**. Click it, write why, or what to do instead, and click **Reject** (or press `Enter`; `Shift+Enter` adds a line, `Esc` closes the field). The note goes to the agent first, as a message into the waiting turn, then the request is rejected: the model reads the rejection and your note in the same turn, without one more message from you. If the note cannot be sent, nothing is rejected and the field stays. In Tether: approval sheet → Reject with note. | <a href="assets/features/rejectNote.webp"><img src="assets/features/rejectNote.webp" width="160" alt="Screenshot: Reject with note"></a> |
|
|
83
|
+
| **Secret input** | <a id="feature-secretinput"></a>The agent gets the tool `request_secret`. When it needs a password, a token or an API key, it asks with it instead of in the chat: a card shows on the tool's row with the label, why it needs the value, a password field, **Save** and **Decline**. **Save** writes the value to a file on this Mac that only you can read, and the agent gets only the file's path, which it uses as input in a command (for example `"$(cat <path>)"`). When a later tool result shows the value, `[secret]` replaces it before the model sees it. The file is deleted when the turn ends. **Decline** tells the agent that you did not give it. Switch it off in **Settings → Composer Plus** to remove the tool. In Tether: a "Secret: …" bar above the composer → Enter. | <a href="assets/features/secretInput.webp"><img src="assets/features/secretInput.webp" width="160" alt="Screenshot: Secret input"></a> |
|
|
84
|
+
| **Quote in reply** | <a id="feature-quotereply"></a>Select a part of an answer: a **Quote** button shows above the selection. Click it: the part goes into the composer at the caret as a Markdown quote (`> …`), with an empty line after it, and the composer gets the focus, so you write your reply below it. Only the answer text counts, not the reasoning, tool rows or your own messages. A quote has at most 2,000 characters. `Cmd+Z` (`Ctrl+Z`) removes it. In Tether: touch and hold an answer → Quote (the whole answer). | <a href="assets/features/quoteReply.webp"><img src="assets/features/quoteReply.webp" width="160" alt="Screenshot: Quote in reply"></a> |
|
|
85
|
+
| **Side chat** | <a id="feature-sidechat"></a>Type a side question in the composer and click the speech-bubbles button (**Ask in a side chat**): a copy of the chat opens and answers it in dsh's read-only mode, while the chat goes on working. The copy knows the chat up to now, except messages that still wait in the queue, and keeps its model. A bar above its composer has **Bring back**: the chat opens and its composer gets your questions (as `> ` quotes) and the answers. **Back to the chat** only opens the chat. The side chat stays in the sidebar as "↳ <question>"; archive it there. In Tether: the chat title menu → Side chat…. | <a href="assets/features/sideChat.webp"><img src="assets/features/sideChat.webp" width="160" alt="Screenshot: Side chat"></a> |
|
|
86
|
+
| **Diff notes** | <a id="feature-diffcomments"></a>In **Changes panel**, open a file's diff and click **+** at a line (Shift+click a second line of the same block for a range), write a note and click **Save note**. The chat's notes wait in a bar at the top of the panel; **Send to composer** puts them at the composer's caret as Markdown: `path:12-14`, the lines as a `diff` block and your note. **Clear** drops them. The notes stay in this browser until you send or clear them. Needs **Changes panel**. In Tether: a file's diff → touch and hold a line → Add note…. | <a href="assets/features/diffComments.webp"><img src="assets/features/diffComments.webp" width="160" alt="Screenshot: Diff notes"></a> |
|
|
75
87
|
| **Project status** | <a id="feature-projectstatus"></a>A project row in the sidebar shows the same spinner / waiting / done marker as its chats, so a collapsed project still tells you a chat inside is working or needs you. A chat waiting for you shows first, then a finished chat you have not opened yet (the green dot, also while another chat still runs), then the spinner. Hover it for details. In **Workspace Tree**, the row of a parent folder also shows the chats of each project inside it (for example each branch folder in `.worktrees/`), also while it is collapsed. | <a href="assets/features/projectStatus.webp"><img src="assets/features/projectStatus.webp" width="160" alt="Screenshot: Project status"></a> |
|
|
76
88
|
| **Git branch on chat rows** | <a id="feature-sessionbranch"></a>In the sidebar's “In one list” view, each chat row shows a small grey pill with the git branch that the chat's project folder was on at the chat's last turn (for example `main` or `feature/login`; a detached HEAD has no branch and shows no pill). Two chats of one project on different branches no longer look the same, and you see at once when you are about to continue a chat on the wrong branch. Hover the pill for the full name. The Host half reads the branch (`git branch --show-current`, read-only) when a turn starts and when it ends; a chat with no turn since you installed this, or a folder that is not a git repository, shows no pill. In “WorkSpace” and “Workspace Tree”, no chat row shows the pill, because the chat is already under its project row. | <a href="assets/features/sessionBranch.webp"><img src="assets/features/sessionBranch.webp" width="160" alt="Screenshot: Git branch on chat rows"></a> |
|
|
77
89
|
| **Mark all as read** | <a id="feature-markprojectread"></a>In the sidebar, click a project's **…** button → **Mark all as read**. Every chat in that project loses its green unread dot at once; other projects keep theirs. The item is greyed out (**No unread chats**) when the project has none. | <a href="assets/features/markProjectRead.webp"><img src="assets/features/markProjectRead.webp" width="160" alt="Screenshot: Mark all as read"></a> |
|
|
@@ -81,8 +93,11 @@ Then restart dsh. (The CLI can't install into the desktop profile; the app manag
|
|
|
81
93
|
| **Order by status** | <a id="feature-statusorder"></a>Sidebar → view options → **Order by** → **By status** (with **In one list**). Finished chats come first (dsh's “done” dot, which a turn that ended with an error also gets), then running or waiting chats, then chats with an active automation (Schedule), then the rest in dsh's order. Opening a finished chat moves it down. Only the view changes: select **Manual** or **Last updated** to go back. | <a href="assets/features/statusOrder.webp"><img src="assets/features/statusOrder.webp" width="160" alt="Screenshot: Order by status"></a> |
|
|
82
94
|
| **Background notifications** | <a id="feature-notifications"></a>While dsh is in the background you get a notification when a turn finishes (first line of the reply), or when a chat really waits for you: an approval (tool name), an answer (the question) or a plan review. A request must still be open 1.5 s later, so approvals answered automatically (Auto Review grants, other plugins) stay silent, and a notification is withdrawn as soon as its request is answered. The Dock/taskbar badge counts waiting chats. Clicking opens that chat. | <a href="assets/features/notifications.webp"><img src="assets/features/notifications.webp" width="160" alt="Screenshot: Background notifications"></a> |
|
|
83
95
|
| **Open waiting chat when idle** | <a id="feature-idleswitch"></a>When a chat asks a question, or waits for an approval or a plan review (the orange dot), or finishes a turn that you have not read yet (the green dot), and you do not use dsh for 30 seconds, dsh opens that chat. Orange chats open before green ones. In each group, the one that waits longest opens first; the next one opens after another 30 seconds without use. A key, a click, a mouse move, the scroll wheel or a touch starts the 30 seconds again. Text in the field that has the focus, selected text, or an open menu or dialog also stops the switch. While a waiting chat is on screen, nothing moves. When you leave a waiting chat without an answer, it can open again after the next 30 seconds without use. When a green chat opens, its dot goes; the next green chat opens only after you use dsh again and then do not use it for 30 seconds. This also works while dsh is in the background, but dsh does not come to the front. | <a href="assets/features/idleSwitch.webp"><img src="assets/features/idleSwitch.webp" width="160" alt="Screenshot: Open waiting chat when idle"></a> |
|
|
96
|
+
| **Next waiting chat** | <a id="feature-nextwaiting"></a>A button in the sidebar header shows how many other chats wait for you, with a dot in the color of the next one: orange when it asks a question or waits for an approval or a plan review, green when it finished a turn that you have not read. Click it, or press Cmd+Shift+E (Ctrl+Shift+E on Windows and Linux), to open that chat. Orange chats come before green ones; in each group, the chat that waits longest comes first. The chat on screen does not count. When no other chat waits, the button is not shown and the key does nothing. You can change the key on dsh's Keyboard shortcuts page (Next waiting chat). | <a href="assets/features/nextWaiting.webp"><img src="assets/features/nextWaiting.webp" width="160" alt="Screenshot: Next waiting chat"></a> |
|
|
97
|
+
| **Option buttons** | <a id="feature-optionpicks"></a>When an answer ends with a list of options (a numbered list of 1 to 9 items under an "Options" heading or a bold "Options" line, also "Next steps" and the same words in the app's languages), a button for each option shows under the answer. A click sends "Option N: …" with the whole option as your message, as if you typed it. The option marked "(recommended)" is marked. The buttons show only under the newest answer, while the chat is idle and the composer is empty; a picked answer and an answer that a rollback withdrew show none. While they show, Next message prediction makes no guess. On a question card of the agent, the keys 1–9 pick that option, as a click does (not in the answer field, and not in the first 0.8 seconds after the question shows). | <a href="assets/features/optionPicks.webp"><img src="assets/features/optionPicks.webp" width="160" alt="Screenshot: Option buttons"></a> |
|
|
84
98
|
| **Application language** | <a id="feature-language"></a>Settings → Composer Plus → **Application language** switches the whole dsh interface to Türkçe, Español, Português (Brasil), Français, Deutsch, Русский, 日本語, 한국어, Bahasa Indonesia, Tiếng Việt or हिन्दी (see below). | <a href="assets/features/language.webp"><img src="assets/features/language.webp" width="160" alt="Screenshot: Application language"></a> |
|
|
85
99
|
| **Mobile connect (iPhone)** | <a id="feature-mobileconnect"></a>Use dsh from your iPhone with the [Tether](tether/) app, on the same Wi-Fi or over [Tailscale](https://tailscale.com). Switch it on in **Settings → Composer Plus** (it is off by default, because it opens a network port on this Mac). Then click **Mobile connect** at the bottom left of the sidebar: scan the QR code with the iPhone Camera (tap **Open in Tether**) or with **Scan code** in Tether, tap **Connect** and click **Approve**. Tether must be installed first: without it the Camera cannot open the code. The phone shows your chats, sends messages (with photos: the composer's **+** → Camera, Photos or Paste image), answers approvals and questions, and switches models and agents. Pair as many Macs as you like: the Mac name at the top left of the app switches between them. The **Mobile connect** panel lists the paired iPhones with their last connection: **Remove** cuts one off at once. **Tailscale only** refuses the local network (for a shared Wi-Fi), and the access log shows who tried to connect. In Tether, **Settings → Privacy** locks the app with Face ID. | <a href="assets/features/mobileConnect.webp"><img src="assets/features/mobileConnect.webp" width="160" alt="Screenshot: Mobile connect (iPhone)"></a> |
|
|
100
|
+
| **Remote computers** | <a id="feature-remotecomputers"></a>Open the dsh of your other Macs over [Tailscale](https://tailscale.com) and continue their chats here. Switch it on in **Settings → Composer Plus** on each Mac (it is off by default, because it opens network ports). On the Mac that you want to open, switch on **Let other computers open this Mac**, click **Create pairing link** and copy the link. On this Mac, pick **Add a computer…** in the computer picker at the left of the chat title, paste the link, click **Connect**, then click **Approve** on the other Mac. The picker then lists **This Mac** and your computers: pick one and its dsh opens in the Browser tab of the right sidebar (or in a browser window), with its own chats, tools and files. The Settings panel renames and removes computers, and lists the computers that can open this Mac (**Remove** cuts one off at once). | <a href="assets/features/remoteComputers.webp"><img src="assets/features/remoteComputers.webp" width="160" alt="Screenshot: Remote computers"></a> |
|
|
86
101
|
| **Automatic updates** | <a id="feature-autoupdate"></a>When dsh starts, the plugin checks the [latest GitHub release](https://github.com/furkancak1r/dsh-composer-plus/releases/latest). If it is newer and already on npm, it installs that exact version through dsh's own plugin manager (the same path as Settings → Plugins) and notifies you. Restart dsh to load it. **Settings → Composer Plus → Composer Plus updates** shows the version and has **Check for updates** / **Update now**. The first time dsh starts with the new version, a **What’s new in Composer Plus N** window shows the release notes of that version once, in the language of **Application language** (they come with the new version, no extra network call; a language without notes shows the English notes); **Close** or `Esc` closes it. | <a href="assets/features/autoUpdate.webp"><img src="assets/features/autoUpdate.webp" width="160" alt="Screenshot: Automatic updates"></a> |
|
|
87
102
|
| **Backup** | <a id="feature-backup"></a>Settings → Composer Plus → **Backup** → **Back up now** writes your whole dsh home (chats, settings, plugins, MCP, skills) into one archive in `~/Desktop/dsh-backups`, with a checksum. Secrets are masked in the archive: credential files, key files (`.pem`, `.key`) and the token, secret and password values of the yml settings stay on this computer only, in the folder's `vault`. `cache/`, `dsh-runtimes/` and `node_modules` are not archived (dsh makes them again). Each backup in the list has **Check** (reads it fully), **For another computer** (a folder to copy to the new computer, with the rescue console) and **Delete**. dsh-backup's archives in the same folder show and work too. To restore, quit dsh and use the rescue console. | <a href="assets/features/backup.webp"><img src="assets/features/backup.webp" width="160" alt="Screenshot: Backup"></a> |
|
|
88
103
|
| **Automatic backup** | <a id="feature-autobackup"></a>Switch on **Automatic backup** (off by default: each copy is about as large as your dsh home without its cache). Choose how often (**Every**: 6 hours to 7 days, 24 hours by default) and how many backups stay (**Keep**: 3 to 14, 7 by default). The next time shows under the switch; a failed backup shows there too and is tried again 30 minutes later. When dsh or Composer Plus starts with a new version, a snapshot comes soon after the start, before the new version has used your data for long (the two newest stay, marked **Before an upgrade**). | <a href="assets/features/autoBackup.webp"><img src="assets/features/autoBackup.webp" width="160" alt="Screenshot: Automatic backup"></a> |
|
|
@@ -135,6 +150,9 @@ Each pack has 3,280 texts: every UI text of dsh `0.2.0-rc.2` and `0.2.1-rc.2` (c
|
|
|
135
150
|
| `Cmd+F` on a Mac, `Ctrl+F` on Windows and Linux | open chat | open **Find in chat** |
|
|
136
151
|
| `Enter` / `Shift+Enter`, `↓` / `↑` | **Find in chat** box | next / previous match |
|
|
137
152
|
| `Esc` | **Find in chat** box | close the box |
|
|
153
|
+
| `Cmd+Shift+E` on a Mac, `Ctrl+Shift+E` on Windows and Linux | anywhere in dsh | open the **Next waiting chat** (change it on dsh's Keyboard shortcuts page) |
|
|
154
|
+
| `Cmd+Shift+K` on a Mac, `Ctrl+Shift+K` on Windows and Linux | anywhere in dsh | open the **Task board** (change it on dsh's Keyboard shortcuts page) |
|
|
155
|
+
| `1`–`9` | dsh's question card, not in its answer field | pick that option (**Option buttons**) |
|
|
138
156
|
|
|
139
157
|
An open `/` or `@` menu keeps these keys for itself.
|
|
140
158
|
|
|
@@ -160,17 +178,20 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
160
178
|
- **Allow for this chat:** grants are stored with the time they were given in `$DSH_HOME/storages/dsh-composer-plus/chat-grants.json` (owner-only permissions). A grant covers one exact tool in one chat, until the time limit ends (1 hour by default). If that tool can write, the grant covers any write too. Revoke it from the header chip.
|
|
161
179
|
- Auto Review still runs on every call; review failures are never auto-allowed.
|
|
162
180
|
- **Mobile connect:** off until you switch it on. While it is on, the Host half runs the Tether gateway: HTTPS on port 19390 that accepts only your Wi-Fi subnet and your tailnet (100.64.0.0/10), and a pairing page on `127.0.0.1:19391` (this Mac only). A phone needs a one-time code from the QR code (5 minutes) and your **Approve** on the Mac. The phone pins the gateway's certificate. The Mac keeps only a hash of each phone's token (30 days, renewed while used); **Remove** closes that phone's connections at once. Phones can call only an allowlist of dsh methods (chats, prompts, attachments, slash commands, approvals, questions, models, agents, goals), not settings, credentials, the file browser or the terminal. **Tailscale only** refuses every connection from the local network, also open ones. The access log keeps the newest 200 connection attempts (time, IP address, device name, allowed or refused, and why) in `access.json`; it never holds a token or a pairing code. Data: `$DSH_HOME/storages/dsh-composer-plus/mobile/` (owner-only files). Details: [tether/README.md](tether/README.md).
|
|
181
|
+
- **Remote computers:** off until you switch it on, on each Mac. **Let other computers open this Mac** opens a second HTTPS port (19392) on this Mac's Tailscale address only (not on the Wi-Fi, not announced with Bonjour). Another Mac needs a one-time pairing link (5 minutes), the matching certificate (pinned) and your **Approve**; this Mac keeps only a hash of its token. A paired computer gets full control of dsh on this Mac, as if you used it here: its chats, models, tools, files and terminal. Remove it in the Settings panel and its connections close at once. The Mac that opens another one keeps that computer's token in `$DSH_HOME/storages/dsh-composer-plus/computers.json` (owner-only). It opens a relay on `127.0.0.1` for each computer that you pick: the page gets a one-time link (60 seconds), and the relay accepts only its own page (its address, no other site). A page that another Mac opened shows no computer picker and cannot change this Mac's computers.
|
|
163
182
|
- **Updates:** the Host half asks `api.github.com` for the latest release and `registry.npmjs.org` for that exact version; nothing about you or your chats is sent. Installation uses dsh's plugin manager (`pnpm add dsh-composer-plus@<version>`; when dsh 0.2.1 refuses that for an installed plugin, `pnpm add https://registry.npmjs.org/dsh-composer-plus/-/dsh-composer-plus-<version>.tgz`, and the profile then lists that URL as the plugin's source), so dsh's own registry, script and version-compatibility checks apply. Pre-release tags and older versions are never installed.
|
|
183
|
+
- **Usage count:** once a day, the Host half asks GitHub for the small `active.txt` file of the release of the installed version (`github.com/furkancak1r/dsh-composer-plus/releases/download/v<version>/active.txt`). GitHub counts these requests per file, so the owner sees only how many copies of each version asked that day. The request has no id, cookie or data about you or your chats; GitHub sees your IP address, as with each update check. The day of the last request is kept in `$DSH_HOME/storages/dsh-composer-plus/active.json`. A git checkout of this repository and a renamed copy send nothing. There is no switch for it.
|
|
164
184
|
- **Next message prediction:** on by default; switch it off in **Settings → Composer Plus** to stop these model calls. After each finished turn, the Host half sends the chat's own user messages and the agent's text replies (no tool output, no hidden context, no reasoning), at most about 6,000 characters (the newest part), to the chosen model (dsh's default unless you pick another). It goes through dsh's own provider settings, as one request. Nothing is saved in the chat: the guess is not added to the chat history. The switch and the model choice are in `$DSH_HOME/storages/dsh-composer-plus/predict.json` (owner-only file).
|
|
165
185
|
- **Complete while typing:** off until you switch it on. While it is on, at each pause while you type, the Host half sends the text that you typed so far and the chat's own user messages and agent text replies (no tool output, no hidden context, no reasoning), at most about 3,000 characters of chat, to the model chosen under **Complete while typing** (by default the model of **Next message prediction**). A newer pause stops the older request. Nothing is saved in the chat. The switch is in `$DSH_HOME/storages/dsh-composer-plus/complete.json` (owner-only file).
|
|
166
186
|
- **Improve prompt:** nothing runs until you click the magic wand. Then the Host half sends your draft, the chat's own user messages and agent text replies (no tool output, no hidden context, no reasoning, no rolled-back messages; at most about 6,000 characters, the newest part), the same project summary as **Feature ideas** (with the same file rules: no `.env*` or key files, no symlink out of the folder, no FIFO), the paths that `git status` lists as changed and up to 30 tracked or untracked (not ignored) paths whose names share words with your draft, to the model chosen under **Improve prompt** (by default the chat's own model), as one request. File contents other than that summary are not sent. Nothing is written to the chat or the project: the answer only replaces your draft in the composer, and you decide whether to send it. The model choice is in `$DSH_HOME/storages/dsh-composer-plus/improve.json` (owner-only file).
|
|
167
187
|
- **Goal check:** it runs only when the agent marks a `/goal` complete in an automatic round (or when you click **Run now**). The Host half runs the test command in the chat's folder with the chat's sandbox mode (as dsh's own `bash` tool: the same file-access policy; when that sandbox cannot start, the test does not run and the check fails). It reads only `package.json`, `Makefile`, `Cargo.toml`, `go.mod`, `pyproject.toml` and `pytest.ini` to find the command, as regular files inside the folder (no symlink out of it, no FIFO). Then it sends the goal, the chat since the goal started (your messages, the agent's replies, tool calls cut to 1,000 characters and the last 2,000 characters of each tool result; no reasoning, no rolled-back steps; at most about 60,000 characters, the newest part), `git status --short` and the end of the test output to the model chosen under **Goal check** (by default the chat's own model), as one request with no tools. Tool output can contain what the agent read, so this request can hold parts of your files, as the chat itself does. Nothing is written to the chat or the project. Your test command, the limits, the last result (with the end of its output) and the model choice are in `$DSH_HOME/storages/dsh-composer-plus/goal-check.json` (owner-only file, newest 500 chats).
|
|
168
188
|
- **Continue in a new chat:** nothing runs until you click it. Then the Host half sends the chat (as Goal check reads it: no reasoning, no rolled-back steps) to the chat's own model and shows the note; only **Start new chat** makes a new chat. Nothing is written to the project.
|
|
169
189
|
- **Context breakdown:** reads only the chat log on the Host; no model call, no project file.
|
|
170
|
-
- **Task board:** the board shows dsh's own chats from dsh's own lists in this window; it adds no chat data of its own. **New task** opens dsh's own new chat, and you write the first message in dsh's composer, so approvals, the sandbox and the chat's model apply as usual. The Host half keeps that chat's first message as the card's prompt and sends it (its first 4,000 characters, nothing else) to that chat's model in one more request, with no tools, for up to 3 tags. The prompt, the tags and the start time of each task are kept in `$DSH_HOME/storages/dsh-composer-plus/board-chats.json` (owner-only file, the newest 2,000); the switch is in `board-switch.json` next to it. Nothing is written to a project folder. **Answer** sends your answer to dsh's own pending request, the same way the chat's own card does. The old task list of earlier versions (`board.json`) stays on disk as it was and is not read. **Progress on hover** reads the chat's log on this Mac. With **Fast (no AI)** (the default), nothing is sent. With **AI summary**, while a running card's progress box shows (or while Tether's board is open, for up to 8 running cards), the Host half sends that chat's newest part (at most about 6,000 characters: your messages, the agent's text replies, its tool calls and the end of their results; no reasoning, no rolled-back messages) to the chat's model, as one request with no tools. It sends again only after the chat moved on, at most once every 20 seconds per chat. The note is kept only in memory; the setting is in `$DSH_HOME/storages/dsh-composer-plus/board-progress.json` (owner-only file).
|
|
190
|
+
- **Task board:** the board shows dsh's own chats from dsh's own lists in this window; it adds no chat data of its own. **New task** opens dsh's own new chat, and you write the first message in dsh's composer, so approvals, the sandbox and the chat's model apply as usual. The Host half keeps that chat's first message as the card's prompt and sends it (its first 4,000 characters, nothing else) to that chat's model in one more request, with no tools, for up to 3 tags. The prompt, the tags and the start time of each task are kept in `$DSH_HOME/storages/dsh-composer-plus/board-chats.json` (owner-only file, the newest 2,000), with the ids of the chats that you took off the board with **×** or **Clear all** (the newest 5,000); the switch is in `board-switch.json` next to it. Nothing is written to a project folder. **Answer** sends your answer to dsh's own pending request, the same way the chat's own card does. The old task list of earlier versions (`board.json`) stays on disk as it was and is not read. **Progress on hover** reads the chat's log on this Mac. With **Fast (no AI)** (the default), nothing is sent. With **AI summary**, while a running card's progress box shows (or while Tether's board is open, for up to 8 running cards), the Host half sends that chat's newest part (at most about 6,000 characters: your messages, the agent's text replies, its tool calls and the end of their results; no reasoning, no rolled-back messages) to the chat's model, as one request with no tools. It sends again only after the chat moved on, at most once every 20 seconds per chat. The note is kept only in memory; the setting is in `$DSH_HOME/storages/dsh-composer-plus/board-progress.json` (owner-only file).
|
|
171
191
|
- **Protected files:** the list and the switch are in `$DSH_HOME/storages/dsh-composer-plus/protected-files.json` (owner-only file). The check reads only the path of each file tool call (and its real path), never the file.
|
|
172
192
|
- **Blocked commands:** the rules and the switch are in `$DSH_HOME/storages/dsh-composer-plus/blocked-commands.json` (owner-only file). The check reads only the command text of each `bash` and `pwsh` call; it runs nothing and sends nothing.
|
|
173
|
-
- **
|
|
193
|
+
- **Secret input:** the value goes from the card (or from Tether, through the gateway, which does not log request bodies) to the Host only in the answer request. The Host writes it to `$DSH_HOME/storages/dsh-composer-plus/secrets/<random name>` (folder 0700, file 0600); nothing goes into the project, the chat log or the tool result. The Host keeps the value in memory to replace it with `[secret]` in later tool results of that chat. The file and that copy go when the chat's turn ends and at dsh start. The switch is in `secrets.json` next to it. A command that the agent runs with the file can send the value where that command sends it: that is the purpose.
|
|
194
|
+
- **Project memory:** off until you switch it on. While it is on, after each finished turn of a top-level chat, the Host half sends the chat's own new messages since the last review (your messages and the agent's text replies; no tool output, no reasoning, no hidden context, no rolled-back messages; a fork's copy of its parent is left out; at most about 16,000 characters) and the saved notes to the chat's own model, as one request with no tools. The notes are Markdown files under `$DSH_HOME/storages/dsh-composer-plus/memory/` (owner-only files): `projects/<id>/` for each project folder (`<id>` is a hash of the folder's real path; `project.json` names the folder), `global/`, `journal.jsonl` (every change with the line before and after) and `reviewed.json` (how far each chat was read). Nothing is written to the project folder. Notes that look like a key, a token, a password or an ID number are refused. The notes of a project go into the system prompt of each new chat in that folder, so they reach the model with every request of that chat. The switch is in `memory.json` next to it. **Open memory** sends nothing until you click **Preview changes**; then it sends the notes it shows and your text to dsh's default model, as one request with no tools. Its changes are written only on **Apply**, with `editor` in the journal. Tether reads and changes the notes through the same route. **Memory version history** (on by default) keeps a copy of the memory files before each save in `memory/history/` next to them (owner-only files, the newest 50 per memory); it sends nothing to a model. **Export memory to AGENTS.md** sends nothing to a model and writes only when you click **Write AGENTS.md**: it reads and writes `AGENTS.md` in the memory's own project folder (only a regular file inside it, never through a symlink that leaves it), and changes only its marked section. **Find stale memory notes** sends nothing to a model and writes nothing: it checks paths inside the project folder with realpath (no file is read), reads `package.json` only as a regular file inside the folder, and runs one `git for-each-ref` there. **Do not use memory in this chat** keeps each chat that you switch off in `memory-chats.json` next to it (owner-only, the newest 500); such a chat sends no memory to its model. **Suggest memory notes from a chat** sends nothing until you click **Suggest for memory**; then it sends the saved notes of the chat's project and the global notes, and the chat's own messages and text replies (no tool output, no rolled-back messages; a fork's copy of its parent is left out; at most about 24,000 characters), to the chat's own model, as one request with no tools. A suggestion is saved only on **Accept**.
|
|
174
195
|
- **Backup:** nothing leaves your machine. Archives go to `~/Desktop/dsh-backups` (owner-only files). Secrets are not in an archive: credential files (`.credentials.yaml`, `.env`), key files (`.pem`, `.key`, `.p12`, `.pfx`) and the values of token, secret, password and API key settings in the yml files are masked; their real copies stay in `composer-plus-vault/<archive>/` in the same folder (owner-only), on this computer only. **For another computer** copies no vault: enter those secrets again there. Your chat logs, settings and the rest of the dsh home are in the archive as they are: keep the folder private, as `$DSH_HOME` itself. The backup reads files with `O_NOFOLLOW | O_NONBLOCK`; a symbolic link is stored as a link (never followed) and a FIFO or device is skipped. The automatic backup switch and settings are in `$DSH_HOME/storages/dsh-composer-plus/auto-backup.json`, the rescue console switch in `rescue-console.json`, and while dsh runs, `running/host-<pid>.json` names each dsh process (the rescue console reads them to refuse a restore).
|
|
175
196
|
- **Rescue console:** a terminal menu; it opens no network port. A restore writes only into a new folder next to the dsh home (files with `O_EXCL | O_NOFOLLOW`, symbolic links last and never followed) and refuses an archive with an unsafe name (`..`, an absolute path), a device or FIFO, more than one top folder or an entry below a link.
|
|
176
197
|
|
|
@@ -192,7 +213,7 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
192
213
|
- **No branch pill on a chat row:** the sidebar is not in “In one list” (in “WorkSpace” and “Workspace Tree”, no chat row shows a pill), the chat had no turn since you installed this version, its folder is not a git repository, or **Git branch on chat rows** is off. After an update, restart dsh (the Host half records the branch).
|
|
193
214
|
- **Goal check says the test exited with code 127 or "not found":** dsh started from the Finder or the Dock can have a shorter PATH than your terminal, so it does not find `npm`, `pnpm` or `cargo`. Start dsh from a terminal, or set your own test command with the full path under **Goal check** → **Edit**. **Run now** shows the result at once.
|
|
194
215
|
- **The goal does not close and the agent keeps working:** **Goal check** found a failing test or missing work; the row under the goal shows why (hover the result for the details). Fix the cause or the test command, or complete the goal yourself with `/goal` or the goal bar (that is not checked).
|
|
195
|
-
- **Install fails right after a release:** add the version (`dsh-composer-plus@1.
|
|
216
|
+
- **Install fails right after a release:** add the version (`dsh-composer-plus@1.21.0`), see the install note above.
|
|
196
217
|
- **Back up now says "another backup action is running":** an action runs in another dsh window or in the rescue console (they share a lock file, `.composer-plus.lock`, in the backup folder). Wait for it. If no action runs, the lock of a closed process is taken over at the next click.
|
|
197
218
|
- **The rescue console says "dsh is running":** quit dsh first. If dsh is really closed, the file named in the message is left from a crash: remove it and try again.
|
|
198
219
|
- **After a restore, dsh does not start or a plugin is missing:** the plugin packages of a profile must be installed again. The rescue console offers it after a restore; or run `pnpm install` in each folder under `$DSH_HOME/profiles/` that it lists. Secrets that were not in the vault (another computer) must be entered again: the console lists them.
|
|
@@ -213,11 +234,17 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
213
234
|
- dsh's queue has no `move` action, so the plugin's Host moves the queued message itself in dsh's queue (one change, the same message). Messages with images or files move too. Only your own messages move: a goal round or a question reply in the queue stays where it is. If a message starts to send while you drag, nothing moves and a notice says so.
|
|
214
235
|
- dsh 0.2.1 loads an update at once when the new version changes no dsh settings; otherwise, and on dsh 0.2.0, restart dsh to load it. The plugin never restarts dsh for you. Web/CLI profiles without dsh's plugin manager only report a new version.
|
|
215
236
|
- **What’s new in Composer Plus N** shows the notes in the language of **Application language**. A UI language with another region gets the notes of its base language (`en-GB` gets the English notes, `zh-TW` the Chinese notes of `zh`). A language without notes (one that another language pack adds, or `pt-PT`, which is not `pt-BR`) shows the English notes. The notes come with the new version. When the running copy has no readable notes file (`release-notes.json`), the window shows the English notes from GitHub.
|
|
237
|
+
- **Reject with note** sends the note as a message into the waiting turn, then rejects the request; dsh shows the note in the chat as your message. While the note field is open, the card shows only **Cancel** and **Reject**, so a click cannot allow the request by mistake; `Esc` or **Cancel** brings dsh's buttons back. An empty note sends nothing (use dsh's own **Reject**). If the rejection fails after the note went (for example, the request was answered elsewhere in the meantime), the note stays in the chat and the model reads it at its next step. The button goes into dsh's approval card markup (`data-approval-key`), because dsh has no slot for card actions; if a dsh update changes that markup, the button is not shown and dsh's own **Reject** works as before. A note can have at most 4,000 characters.
|
|
238
|
+
- **Secret input** hides only the exact text of a value: `[secret]` replaces it in the later tool results of the same chat. The agent can still read the file with a shell command and print the value in another form (base64, a part of it, with spaces), and that form reaches the model. The agent's own file tools (read, grep, write, edit) cannot open the secrets folder. When the value is also a common word, other results of that chat show `[secret]` too. The file stays until the turn ends; when dsh quits during the turn, the next start deletes it. A chat can have one open request at a time. The tool adds about 870 characters (about 220 tokens, estimated) to each model request: switch it off when you do not use it.
|
|
239
|
+
- **Quote in reply** quotes the text as the page shows it: a code block, a table or a list comes as plain lines, without its Markdown marks. A selection that starts in one answer and ends in another, or that touches the reasoning, a tool row or your own message, shows no button: select inside one answer. The button finds an answer through dsh's chat markup, because dsh has no slot for a text selection; if a dsh update changes that markup, the button does not show. When the quote ends the field, one more empty line goes after it so the next line that you type starts below it; dsh removes empty lines at the end when it sends.
|
|
240
|
+
- **Side chat** is read-only through dsh's own read-only mode: file tools cannot write and shell commands run in dsh's sandbox without writes (or do not run when the sandbox cannot start). The agent can still ask for more access with dsh's approval card, and a network call (for example an API request) can still change something outside the computer. The copy is made at the newest moment at which no message waits in the queue, so a question asked while queued messages wait does not see what happened after them. A running step of the chat is closed in the copy, so the side chat knows the start of that step but not its result. The side chat is an ordinary chat: it stays in the sidebar and counts toward your model use; archive it there. Bring back takes the side chat's own messages (at most 12,000 characters), only the last reply of each question; the agent's notes between its tool calls stay out. dsh has no slot for a chat inside the right sidebar for a plugin, so the side chat opens in the main view.
|
|
241
|
+
- **Diff notes** works in the Changes panel only, not on dsh's own Last Turn view. A range must stay in one block of the diff (one `@@` part). The notes are kept in this browser's storage, so another browser or the dsh app on another computer does not see them; Tether keeps its own notes in memory. A note keeps the lines as they were when you clicked: when the agent changes the file later, the note still shows the old lines and numbers. At most 50 notes per chat, 2,000 characters per note and 40 lines per note (then a `…` line).
|
|
216
242
|
- **Allow for this chat** counts the time limit from the moment of the grant. A new time limit applies at once to the grants that run, so a shorter one can end them at once. Grants from version 1.12 and earlier have no time: after the update, the agent asks once again for those tools.
|
|
217
243
|
- **Keep composer focus** gives the focus back only after a `/` command or skill. While dsh resolves the command, the composer stays read-only for a few milliseconds, so keys pressed in that time are lost. If dsh's `/` menu is still open, `Enter` picks the highlighted row and does not send.
|
|
218
244
|
- **Fit question card to window** changes only dsh's question card, not the plan review card. It finds the card by dsh's markup (`data-question-key`, `data-question-scroll`); if a dsh update changes that markup, the card shows as dsh draws it. The card's height follows the window, not the chat: in a chat in a narrow side panel, a tall card can still reach above the chat.
|
|
219
245
|
- **Fit chat header to window** finds dsh's chat header by its generated class names (`_titleRow`, `_titleCluster`, `_crumbs`, `_headerActions`, `_headerUtilities`), because dsh has no layout hook for it. If a dsh update renames them, the header shows as dsh draws it. In a very narrow chat column the header can take two or three lines, so the chat area above the messages gets lower.
|
|
220
|
-
- **Mobile connect** works on macOS only (it uses `en0`, `openssl`, `swift` and `dns-sd`). It uses fixed ports 19390 and 19391, so only one dsh on each Mac can run it at a time (each Mac is one entry in the phone's Mac list). The phone gets notifications only while Tether is open or just went to the background (no push service). Tether sends them only after you switch on **Settings → Notifications → Send notifications** in Tether.
|
|
246
|
+
- **Mobile connect** works on macOS only (it uses `en0`, `openssl`, `swift` and `dns-sd`). It uses fixed ports 19390 and 19391, so only one dsh on each Mac can run it at a time (each Mac is one entry in the phone's Mac list). The phone gets notifications only while Tether is open or just went to the background (no push service). Tether sends them only after you switch on **Settings → Notifications → Send notifications** in Tether. Tether keeps this switch and its hours separately for each paired Mac. The switch is off by default for each Mac, and iOS asks for the permission when you switch it on. The iOS app is not on the App Store yet: build it from `tether/ios` with Xcode. **Tailscale only** still needs a Wi-Fi or Ethernet address on the Mac (the gateway starts only with one). The access log is per Mac and keeps only the newest 200 attempts; a repeated attempt within a minute counts up one row. Tether's app lock does not hide notification previews on the iPhone Lock Screen: turn them off in iOS Settings. Tether's green dots follow the Mac: a chat that you open in dsh loses its dot on the phone too. A chat that you open in Tether loses its dot on the phones only; dsh's own dot on the Mac stays until you open the chat there.
|
|
247
|
+
- **Remote computers** needs Tailscale on both Macs, and Composer Plus with this feature on the Mac that you open. That Mac must be awake with dsh running. The other computer opens in the Browser tab of the right sidebar of the chat on screen: the tab belongs to that chat, so another chat shows its own sidebar. Without a chat (or on dsh web without its Browser tab), the computer opens in a browser window. The picker shows only while a chat or the New chat screen is in the main area, not on the Task board. It uses port 19392 (only one dsh on each Mac can let other computers in). A computer that you opened inside another computer's page has no picker, so you cannot open a third Mac from there.
|
|
221
248
|
- A session link works inside chats; clicking it does not open the chat. A **Copy message link** link opens its message only on dsh 0.2.1 and later, and only from a message in a chat (dsh 0.2.0 has no user-text rules, so there the link is copied but shows as plain text). A message that a rollback took out, or that compaction removed from the history that dsh loads, cannot be shown: the link then says so. The 🔗 buttons attach to dsh's message rows; if a dsh update changes that markup, they do not show.
|
|
222
249
|
- **Mark all as read** changes dsh's own unread dots through a part of dsh that is not a public API (the `completionUnread` list of dsh's session status). If a dsh update renames it, the item does not show. The item goes into dsh's project "…" menu, which has no slot for plugins; if dsh changes that menu, the item does not show either.
|
|
223
250
|
- **Edit queued message in place** does not change a message that started to send meanwhile, and it does not overwrite a message that changed meanwhile (for example in Tether on the iPhone): a notice tells you. A new image needs a model that takes images (dsh's own image limits apply), and a new file must finish its upload before you can save. Only your own queued messages can be edited: a goal round or a question reply in the queue cannot. After a plugin update, only text-only edits work at once: restart dsh before you save a message with images or files (the Host half loads at start).
|
|
@@ -232,6 +259,8 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
232
259
|
- **Branches in the workspace tree** writes to git without a click: when it moves a chat, it switches the project folder back to its branch (`git switch`) and adds a worktree (`git worktree add`). It never deletes a branch, a worktree or a file. dsh cannot change the folder of a chat, so a moved chat is a copy (dsh's own fork, with a new id) and the old chat is archived. The copy continues the stopped task; a tool call that was running when the branch appeared ends with a refusal, and the agent runs it again in the new folder. A goal of the old chat does not move with it. Only a chat whose folder is the repository's main folder moves, and only for a branch that it created and switched to in that turn (`git switch -c`, `git checkout -b`): a branch made with `git branch` alone, a folder with uncommitted changes, a linked worktree or a subfolder moves nothing. Only worktrees directly in `<project>/.worktrees/` with a branch show in the tree; a detached worktree or one elsewhere does not. The copy opens by itself only when its chat was the open one (the plugin reads dsh's sidebar row for that); else it is in the branch project.
|
|
233
260
|
- **Find in chat** searches only what the page shows: the messages and replies that are loaded (scroll up or click **Load earlier** for older ones), not tool steps that are closed and not the text inside a tool's output that is folded. It counts at most 2,000 matches (then "2000+"). It uses the browser's highlight API (Chromium 105 and later; the desktop app has it): in an older browser the count and the moves work without the color. `Cmd+F` on a Mac (`Ctrl+F` on Windows and Linux) opens it only while a chat is on screen; elsewhere the browser's own find works as before. On a Mac, `Ctrl+F` keeps its macOS use in text fields (the cursor moves one character forward).
|
|
234
261
|
- **Open waiting chat when idle** knows only what dsh's own window sees: work in another app does not count, so while dsh is in the background it can open a waiting chat after 30 seconds. It does not bring dsh to the front. Reading without a key, a click or a mouse move counts as idle. It looks only at chats with dsh's orange dot (a question, an approval or a plan review) or green dot (a finished turn that you have not opened); a subagent's request shows in its parent chat. Orange chats open first. Opening a green chat removes its dot, so the next green chat waits for your next key, click, mouse move, scroll wheel or touch before its 30 seconds start: when you come back, the other green dots are still there. Nothing opens while a waiting chat is on screen; a chat that you left without an answer can open again after the next 30 seconds without use. The 30 seconds cannot be changed.
|
|
262
|
+
- **Next waiting chat** counts the same chats as **Open waiting chat when idle**: dsh's orange dot (a question, an approval or a plan review that you can answer here) and green dot (a finished turn that you have not opened); a subagent's request shows in its parent chat. dsh does not record when a chat began to wait, so the order counts from the moment this window saw it: after a reload, the chats that already waited keep dsh's order. The key is a dsh shortcut: in a browser on Linux it has no key until you set one on dsh's Keyboard shortcuts page, and a browser extension or another app can take `Cmd+Shift+E` first. dsh has no slot in the sidebar header, so the button goes into dsh's header markup; if a dsh update changes it, the button is not shown and the key still works. The button is not in the narrow sidebar.
|
|
263
|
+
- **Option buttons** reads only answers that end with an option list: a numbered list of 1 to 9 items, numbered from 1, as the last part of the answer, right under a heading or a bold line "Options", "Choices" or "Next steps" (or the same words in the app's languages). A list in the middle of an answer, in a code block or under another heading gets no buttons. Composer Plus does not ask the agent to write such a list. The buttons show only under the newest answer, while the chat is idle and the composer is empty, and only after Composer Plus knows which answers a rollback withdrew. On dsh's question card, the keys 1–9 do nothing in the first 0.8 seconds after a question shows, so that a key that you meant for something else does not pick an option that you did not read. dsh has no key API for its question card, so the keys find dsh's option buttons in its markup; if a dsh update changes it, the keys do nothing.
|
|
235
264
|
- A notification sent before a restart only brings dsh to the front when clicked.
|
|
236
265
|
- Active projects are moved with dsh's saved project order, so the new order is kept after a restart. Chats outside any project ("Ungrouped") can't be moved; dsh always lists them last.
|
|
237
266
|
- dsh has no extension point in the sidebar's view options menu, so the recent projects option is added to dsh's own menu. If a dsh update changes that menu, the option is not shown and all projects stay visible. The filter works on project rows, so **In one list** is not filtered. In **Workspace Tree**, a parent folder stays while a project inside it is active, and the chat rows that were not active in the last 2 hours hide too; in **WorkSpace**, only project rows are filtered. The filter reads which view dsh shows from dsh's saved view setting (not a public API); if a dsh update renames it, **Workspace Tree** is filtered like **WorkSpace**. Project status reads the same setting: in **Workspace Tree**, a parent folder's row also counts the chats of the projects inside it; if dsh renames the setting, each row shows only its own chats. **By status** has the same kind of limit: dsh has no order slot, so the item and the row order attach to dsh's menu and list markup.
|
|
@@ -247,9 +276,16 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
247
276
|
- **Continue in a new chat** sends the chat (messages, tool calls and the end of each tool result, at most about 60,000 characters, the newest part) to the chat's own model. The note can miss a decision or a file: read it before you start. The new chat knows only the note and the linked chat (dsh attaches the old chat as read-only context); its model context starts small, the old chat stays as it is. One note or start per chat at a time.
|
|
248
277
|
- **Context breakdown** shows estimates with dsh's own rule (about 4 characters per token), the same rule as dsh's context ring; the model's own count can differ. Tool definitions are the ones of the newest request. It shows the context as the chat log has it; a turn that runs now appears after its next step.
|
|
249
278
|
- **Planned steps** saves tokens only when the model plans: while it is on, each request carries the `plan_next_steps` tool and a short instruction (about 500 tokens), also in chats where the model never plans. A condition proves only what it says (for example: the build exit code was 0), not that the work is right. `ok` reads dsh's own result marks (`[exit code: N]`, timeouts, sandbox denials); a command that fails without a non-zero exit code passes. Steps run one at a time; two steps that are ready at the same time go back to the model. The step's message is stored as an assistant message of the chat's model (dsh has no mark for a message that a plugin wrote), so its text says that Composer Plus ran it. Not in Tether.
|
|
250
|
-
- **Task board** shows the chats that dsh lists in this window: a chat outside a project shows only in **All projects**, and a Branch per chat folder (`<project>/.worktrees/<name>`) counts as its project. A card's column is the chat's live state, so cards cannot be dragged: a chat goes to **Done** when its turn ends, also after an error or a stop, and back to **Doing** when it runs again. The green dot is dsh's own done dot, which dsh keeps only in this window: after a reload, finished chats show without it. **Done** shows the newest 50 chats (**Show N older** shows the rest). **Search projects** finds a project by its name only, not by its folder path. **Active in the last 2 hours** hides a project when each of its chats is older than 2 hours, idle and read; the board still shows the project that you picked. **New task** remembers only the newest new chat of this window: when you open another chat before the first message, that chat stays
|
|
279
|
+
- **Task board** shows the chats that dsh lists in this window: a chat outside a project shows only in **All projects**, and a Branch per chat folder (`<project>/.worktrees/<name>`) counts as its project. A card's column is the chat's live state, so cards cannot be dragged: a chat goes to **Done** when its turn ends, also after an error or a stop, and back to **Doing** when it runs again. The green dot is dsh's own done dot, which dsh keeps only in this window: after a reload, finished chats show without it. **Done** shows the newest 50 chats (**Show N older** shows the rest). **Search projects** finds a project by its name only, not by its folder path. **Active in the last 2 hours** hides a project when each of its chats is older than 2 hours, idle and read; the board still shows the project that you picked. **New task** remembers only the newest new chat of this window: when you open another chat before the first message, that chat stays at the top of **Doing** as **New task** until you write in it, but the board comes back by itself only for the newest one. After a reload, a new chat without a message is not on the board (dsh keeps it as its empty New session). The tags come from one model call per task, from its first message: they can be wrong, and a chat that you did not start on the board has none. The title is dsh's own chat title (dsh's title service, with the chat's model); until it comes, the card shows the first line of the first message. **×** and **Clear all** take cards off the board only: no chat is deleted. **Undo** shows for 8 seconds only, in this window; later, **Removed (N)** → **Put back** brings a card back, and a chat that runs again comes back by itself. **Clear all** asks first and takes the read finished cards of the shown project (all projects with **All projects**), also the ones behind **Show N older**; an unread (green) card stays. dsh keeps its green dot only in this window, so after a reload Clear all can take a card whose answer you did not read. The list is kept on this Mac for every window and for Tether; when it has 5,000 chats, the oldest come back. **Answer** answers only the newest request of the chat: when the chat answered it elsewhere (another window, Tether, Auto Review) or asks something new, the panel says so and sends nothing. Earlier versions had a task list with comments and agent tools; they are gone, and the old `board.json` is not shown. The idea and the look come from [Kanzo](https://github.com/emanuele-em/kanzo) by emanuele-em (AGPL-3.0); Composer Plus uses no code from it. `Cmd+Shift+K` is a dsh shortcut: in a browser on Linux it has no default key (set one on dsh's Keyboard shortcuts page), and a browser extension or another app can take it first. A card leaves **Done** when dsh's own green dot goes (you opened the chat) or, for a chat that finished behind the board while it was the open chat, when that chat shows with no panel over it. This read state lives only in this dsh window, as dsh's own dots: after a reload or in another window every finished chat is read, so it is in **Recently finished**.
|
|
251
280
|
- **Send after Stop goes first** works only after you stop the chat (or after a turn that failed, or when you open a chat that still has a queue): a message that you send while a turn runs still waits at the end of the queue. It moves only past your own queued messages: when a goal round or a question reply waits in the queue, dsh's own order stays. It reads a part of dsh that is not a public API (whether the stopped turn still ends); if a dsh update renames it, the message moves only after that turn has ended. Subagent chats keep dsh's own order.
|
|
252
281
|
- **Project memory** belongs to the chat's first folder (dsh's project folder): a chat that changes its folder with `cd` keeps its first project's memory, and the same folder opened through another path to the same files shares it. A chat freezes its memory section when it starts, so a note saved later shows from the next chat (`memory_recall` finds it at once). The review keeps only what the model decides to keep: it can miss a fact or keep a wrong one; check them in **Open memory** and change them there, or edit the files by hand while dsh is closed. **Open memory** sends the notes of the selected project and the global notes (all projects when you select All notes; at most about 60,000 characters, the rest is counted and cannot change in that request) and your text to dsh's default model, not to the chat's model. A preview is kept on the Mac for 30 minutes and until dsh restarts; when a review or the agent changes the notes in between, **Apply** refuses and you preview again. **Apply** saves all the changes of a preview or none: when one change cannot be saved (for example, MEMORY.md is full), the notes stay as they were and the reason shows. Each finished turn with a message from you costs one model call; a failed call reads the same messages again after the next turn. Subagent chats are not reviewed. The idea and the file format come from [DS Bot](https://github.com/Fei2411/DS-Bot) (Apache-2.0); Composer Plus uses no code from it, and it never reads or writes DS Bot's own memory.
|
|
282
|
+
- **Memory version history** keeps the newest 50 versions of each memory (each project and the global memory); older ones go. A version holds the whole memory of that project, not one note. **Restore** puts back every file of that version (topics included) and refuses when the memory changed after you opened the version; the memory before the restore becomes a new version, so you can undo it. While the switch is off, no new version is kept and **Restore** refuses; the kept versions stay. A version from before this feature does not exist: the history starts with the first save after you install it.
|
|
283
|
+
- **Export memory to AGENTS.md** writes only the notes of one project memory; global notes, sources and dates stay out. The next export replaces the whole marked section, so a change that you make by hand inside it is lost (the diff shows it first); text outside the markers stays. When the markers are broken (one is missing or they are there twice), the export refuses until you fix them. AGENTS.md larger than 512 kB, a symlink that leaves the project folder, and anything but a regular file are refused. When AGENTS.md or the notes change after the preview, **Write AGENTS.md** refuses and you export again.
|
|
284
|
+
- **Memory note source link** works for notes saved after you install this version: an older note names only its chat (or nothing), so **Source** opens only the chat or does not show. When the message is gone (a rollback withdrew it, or the chat was deleted), the chat opens and a notice says that the message is not there.
|
|
285
|
+
- **Copy memory to another project** copies at most 100 notes at a time, only into a project that dsh lists (it reads dsh's own project list; no path comes from the window). Each copy is independent: a later change to a note in one project does not change the copy. When one ticked note does not fit (the target's MEMORY.md or topic is full, or it has 40 topics), nothing is copied. A note whose text and topic are already in the target is skipped, and the count says how many.
|
|
286
|
+
- **Find stale memory notes** finds only what a note writes in a form it knows: a path in a code span (`src/cart.ts`), an npm script after `npm run` (or `npm test`, `pnpm lint`), a branch name in a code span next to the word "branch". A path that leaves the project folder is not reported; a script is checked only when the project has a `package.json`, a branch only in a git repository. It checks at most 200 things at a time. A warning means "not found now", not "wrong": a file that a build makes later is reported too.
|
|
287
|
+
- **Do not use memory in this chat** acts from the chat's next model request: a request that already runs keeps what it has. Switching it in a running chat changes its system prompt once, so the model provider's cache cannot be used for that one request. A subagent follows its root chat. The review does not read the messages that a chat gets while its memory is off, also when you switch it on again later. On dsh 0.2.0 the New chat screen has no place for the button: it shows in the chat header after the first message.
|
|
288
|
+
- **Suggest memory notes from a chat** shows at most 10 suggestions and keeps them for 30 minutes and until dsh restarts; after that, accept asks you to suggest again. A long chat sends its newest messages: the oldest agent replies go first. A suggestion can be wrong: read it before you accept it, and use **Open memory** to change a note later. A rejected suggestion can come again at the next click.
|
|
253
289
|
- **Backup** keeps one fixed folder, `~/Desktop/dsh-backups` (dsh-backup's default, so its archives stay usable); there is no setting for another folder. An archive is about as large as the dsh home without `cache/` and `dsh-runtimes/` (measured: 1.6 GB of files gave an 830 MB archive in about 30 s on Apple Silicon; dsh stayed responsive). A file that changes while it is read is stored as it was when the backup opened it, so an open chat's log can end in a cut-off record, which dsh repairs at its next write. Masking finds a secret in a yml file by its key name on one line (`token:`, `apiKey:`, …); a secret in a flow map (`{token: x}`), in a list under such a key, in a JSON file (for example an MCP server's `apiKey` in a `.json` file) or under another name stays in the archive. dsh-backup's typed archives (`dsh-t-…`) are not listed. **For another computer** copies the archive (a clone on APFS: no extra space); the vault does not go with it. **Back up now** deletes no backup. An automatic backup keeps the newest backups that Composer Plus made (the **Keep** setting of **Automatic backup**) and deletes its older ones; snapshots before an upgrade are counted apart (the newest 2 stay). Archives of dsh-backup are never deleted: remove them with **Delete**. While dsh-backup is still installed, it counts the Composer Plus archives in its own keep count and can delete them.
|
|
254
290
|
- **Restore** runs only in the rescue console, while dsh is closed: it replaces the whole dsh home. The old one stays next to it as `.dsh.pre-restore-<time>` until you remove it, so the disk needs room for both. Chats keep their project paths: on another computer, a project at another path shows as missing until you add it again. Symbolic links that point outside the dsh home (for example skills linked from another folder) come back as links; their targets must exist on that computer.
|
|
255
291
|
- **Session log check** reads the newest log of each chat with dsh's own rules for what opens: a row that is not JSON or is out of order counts as damage only when a turn end comes after it (else dsh opens the chat without the rows from there, so it is not listed). It does not check a log's events against dsh's own event rules, so a log that it calls healthy can still fail to open after a dsh upgrade. A repair takes the copy from a backup: the messages after that backup are lost from that chat (the damaged file stays next to it). A chat that is open in this dsh is not repaired in Settings: dsh holds it.
|
|
@@ -284,7 +320,13 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
284
320
|
|
|
285
321
|
**Can the agent remember my preferences across chats, like DS Bot's memory?** Yes, with **Project memory** (off by default): switch it on in **Settings → Composer Plus**. After each turn, your lasting preferences and decisions are kept as short notes for the chat's project, and each new chat in that project reads them. Ask the agent to remember something and it saves it at once. To see or change the notes, click **Open memory** in the same row and write what to change.
|
|
286
322
|
|
|
287
|
-
**
|
|
323
|
+
**I or the AI made a wrong change to the memory. Can I get the old notes back?** Yes, with **Memory version history** (on by default): in **Open memory**, select the project, then **History**. Select the version before the change to see what comes back, then **Restore**.
|
|
324
|
+
|
|
325
|
+
**Can I share the project memory with my team or another agent tool?** Yes, with **Export memory to AGENTS.md** (on by default): in **Open memory**, select the project, then **Export to AGENTS.md**. Check the diff, then **Write AGENTS.md**, and commit the file.
|
|
326
|
+
|
|
327
|
+
**Can the AI suggest what to keep from a long chat?** Yes, with **Suggest memory notes from a chat** (on by default, while **Project memory** is on): click **Suggest for memory** in the chat header, then **Accept** the notes worth keeping.
|
|
328
|
+
|
|
329
|
+
**Can I see all my chats as a kanban board and start new ones from it?** Yes, with **Task board** (on by default): open it in the left sidebar. Each chat is a card in **Doing**, **Review** (it waits for you) or **Done**. **New task** opens dsh's new chat in the project, and the board comes back when your first message goes; click **Answer** on an orange card to answer it without opening the chat. **Clear all** in **Done** asks first and takes the finished cards that you read off the board; **Undo** and **Removed (N)** bring them back, and the chats stay in dsh.
|
|
288
330
|
|
|
289
331
|
**Can dsh back up my chats and settings, like dsh-backup?** Yes: **Settings → Composer Plus → Backup → Back up now**. It writes the same archive format into the same folder (`~/Desktop/dsh-backups`), so dsh-backup's archives show and restore too, and you can remove dsh-backup. Switch on **Automatic backup** for a schedule.
|
|
290
332
|
|
|
@@ -312,10 +354,22 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
312
354
|
|
|
313
355
|
**How do I stop the agent from running `npm publish` or `git push --force`?** **Settings → Composer Plus → Blocked commands**: type `npm publish`, choose **block** or **ask first**, then click **Add**. **block** refuses the command and the agent asks you; **ask first** shows the approval card each time. Protected files covers the agent's file tools; Blocked commands covers its shell commands.
|
|
314
356
|
|
|
357
|
+
**Can I tell the agent why I rejected a tool call?** Yes, with **Reject with note** (on by default): click **Reject with note…** on the approval card, write why or what to do instead, and click **Reject**. The agent reads the rejection and your note in the same turn.
|
|
358
|
+
|
|
359
|
+
**How do I give the agent a password or a token without writing it in the chat?** With **Secret input** (on by default): ask the agent to use `request_secret`, or wait until it asks. Type the value in the card on the tool's row and click **Save**. The agent gets only the path of a file that holds the value, and the file is deleted when the turn ends.
|
|
360
|
+
|
|
361
|
+
**How do I answer one part of a long answer?** Select that part and click **Quote** above the selection (**Quote in reply**, on by default). The part goes into the composer as a `> …` quote, and you write your reply below it.
|
|
362
|
+
|
|
363
|
+
**Can I ask something while the agent works, without stopping it?** Type the question and click **Ask in a side chat** in the composer (**Side chat**, on by default). A read-only copy of the chat answers it while the chat goes on. In the side chat, **Bring back** puts the answer into the chat's composer.
|
|
364
|
+
|
|
365
|
+
**How do I tell the agent what to change in its diff?** In **Changes panel**, open the file's diff, click **+** at a line and write a note (**Diff notes**, on by default). Then click **Send to composer**: the notes go into the composer with the file, the line numbers and the lines.
|
|
366
|
+
|
|
315
367
|
**How do I stop Auto Review asking about the same tool in one chat?** Click **Allow for this chat** on the approval card. It covers that exact tool in that chat only, for 1 hour by default; revoke it from the header chip. Change the time in **Settings → Composer Plus → Allow for this chat**.
|
|
316
368
|
|
|
317
369
|
**I lost my iPhone. How do I stop it from reaching my Mac?** Click **Mobile connect** at the bottom left of the sidebar and click **Remove** next to that iPhone. Its key stops working at once; it can come back only with a new pairing that you approve on the Mac.
|
|
318
370
|
|
|
371
|
+
**How do I continue a chat of my other Mac from this one?** On the other Mac, switch on **Settings → Composer Plus → Remote computers** and **Let other computers open this Mac**, click **Create pairing link** and copy the link (send it to yourself, for example with AirDrop or Notes). On this Mac, switch on **Remote computers** too, pick **Add a computer…** at the left of the chat title, paste the link and click **Connect**, then click **Approve** on the other Mac. From then on, pick that computer in the same menu.
|
|
372
|
+
|
|
319
373
|
**Can I lock Tether with Face ID?** Yes: in Tether, **Settings → Privacy → Lock with Face ID**. Tether then asks for Face ID (or the passcode) when it opens and when you come back to it.
|
|
320
374
|
|
|
321
375
|
**How do I show only the projects I used today in the dsh sidebar?** Sidebar → view options (sliders icon) → **Active in the last 2 hours**. Select it again to show all projects.
|
|
@@ -328,6 +382,10 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
328
382
|
|
|
329
383
|
**Can dsh open the chat that asks me a question by itself?** Yes, with **Open waiting chat when idle** (on by default): when a chat waits for an answer, an approval or a plan review and you do not use dsh for 30 seconds, dsh opens it. A chat that finished a turn that you have not read (the green dot) opens the same way, after the orange ones. While you type, scroll or move the mouse, it waits.
|
|
330
384
|
|
|
385
|
+
**Can I jump to the next chat that waits for me?** Yes, with **Next waiting chat** (on by default): press `Cmd+Shift+E` (`Ctrl+Shift+E` on Windows and Linux) or click the button with the count in the sidebar header. Chats that ask a question or wait for an approval come first, then chats that finished a turn that you have not read.
|
|
386
|
+
|
|
387
|
+
**Can I answer an agent's options with one click?** Yes, with **Option buttons** (on by default): when an answer ends with an "Options" list, click a button under it. It sends "Option N: …" as your message. On a question card of the agent, press 1–9.
|
|
388
|
+
|
|
331
389
|
**How do I switch the DeepSeek Harness interface to Turkish, Spanish, Japanese…?** Settings → Composer Plus → **Application language**.
|
|
332
390
|
|
|
333
391
|
**How do I use dsh from my iPhone?** Build the Tether app from `tether/ios` (Xcode), switch on **Settings → Composer Plus → Mobile connect (iPhone)**, click **Mobile connect** at the bottom left, scan the QR code (iPhone Camera or **Scan code** in Tether), tap **Connect** and click **Approve**. Away from home, use Tailscale on both devices.
|
|
@@ -357,6 +415,10 @@ PLAYWRIGHT=/path/to/playwright node test/browser-recent-finished.mjs /path/to/ds
|
|
|
357
415
|
PLAYWRIGHT=/path/to/playwright node test/browser-recent-tree.mjs /path/to/dsh/lib/bin.js
|
|
358
416
|
# Order by status (fake model + Schedule): real-app test + its thumbnail
|
|
359
417
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-status-order.mjs /path/to/dsh/lib/bin.js
|
|
418
|
+
# Next waiting chat and Option buttons (fake model): the sidebar button and Cmd+Shift+E open the waiting chats in order, the Keyboard shortcuts row, the option buttons and the question card keys, switch off + their thumbnails
|
|
419
|
+
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-agentbox-ideas.mjs /path/to/dsh/lib/bin.js
|
|
420
|
+
# Reject with note, Secret input, Quote in reply, Side chat and Diff notes (fake model + a test-only approval gate): the button on dsh's card, the note after the rejection in the next request, Esc; the secret card, Save, the value in no request, file or page, Decline, Stop; a selected part of an answer → Quote → the sent message; a side question while the chat waits on a card (read-only, no queued message in it), Bring back; notes on a diff line and range → Send to composer → the sent message; switch off + their thumbnails
|
|
421
|
+
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-t3code-ideas.mjs /path/to/dsh/lib/bin.js
|
|
360
422
|
# every Settings feature row shows a loading screenshot and a ? link to its README row
|
|
361
423
|
PLAYWRIGHT=/path/to/playwright node test/browser-settings-shots.mjs /path/to/dsh/lib/bin.js
|
|
362
424
|
# What's new after an update: the release notes show once, Esc and Close close them
|
|
@@ -406,7 +468,7 @@ PLAYWRIGHT=/path/to/playwright node test/browser-continue-queue.mjs /path/to/dsh
|
|
|
406
468
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-queue-stop-send.mjs /path/to/dsh/lib/bin.js
|
|
407
469
|
# Edit queued message in place with images and files (slow fake model) + its thumbnail
|
|
408
470
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-queue-edit.mjs /path/to/dsh/lib/bin.js
|
|
409
|
-
# Task board: New task opens dsh's new chat and comes back after the first message, AI tags, live columns, Answer on the board,
|
|
471
|
+
# Task board: New task opens dsh's new chat and comes back after the first message, AI tags, live columns, Answer on the board, × with Undo, Clear all with its question (unread cards stay), Removed and Put back (kept after a restart), the switch
|
|
410
472
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-task-board.mjs /path/to/dsh/lib/bin.js
|
|
411
473
|
```
|
|
412
474
|
|