dsh-composer-plus 1.16.1 → 1.18.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 +43 -14
- package/README.es.md +43 -14
- package/README.fr.md +43 -14
- package/README.hi.md +43 -14
- package/README.id.md +43 -14
- package/README.ja.md +43 -14
- package/README.ko.md +43 -14
- package/README.md +43 -14
- package/README.pt-BR.md +43 -14
- package/README.ru.md +43 -14
- package/README.tr.md +43 -14
- package/README.vi.md +43 -14
- package/README.zh.md +43 -14
- package/assets/features/blockedCommands.webp +0 -0
- package/assets/features/contextBreakdown.webp +0 -0
- package/assets/features/handoffChat.webp +0 -0
- package/assets/features/headerFit.webp +0 -0
- package/assets/features/plannedSteps.webp +0 -0
- package/assets/features/projectMemory.webp +0 -0
- package/assets/features/protectedFiles.webp +0 -0
- package/assets/features/taskBoard.webp +0 -0
- package/client.js +1569 -50
- package/index.js +1766 -41
- package/package.json +2 -2
- package/tether/gateway/server.mjs +2 -1
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.18.0`.
|
|
31
31
|
|
|
32
32
|
## Features
|
|
33
33
|
|
|
@@ -45,6 +45,7 @@ Then restart dsh. (The CLI can't install into the desktop profile; the app manag
|
|
|
45
45
|
| **Shift+Tab plan mode** | <a id="feature-plantoggle"></a>`Shift+Tab` adds `/plan ` to the start of the draft (press again to remove it). If the chat is already in plan mode, `Shift+Tab` leaves it. | <a href="assets/features/planToggle.webp"><img src="assets/features/planToggle.webp" width="160" alt="Screenshot: Shift+Tab plan mode"></a> |
|
|
46
46
|
| **Keep composer focus** | <a id="feature-keepfocus"></a>After you send a `/` command or skill, the cursor stays in the composer, and you can type again at once. This also works for keyboard macros that type a command and press `Enter`. dsh makes the composer read-only while it resolves the command, and the browser then removes the focus. This feature puts the focus back, unless a menu, a dialog or another field has it. | <a href="assets/features/keepFocus.webp"><img src="assets/features/keepFocus.webp" width="160" alt="Screenshot: Keep composer focus"></a> |
|
|
47
47
|
| **Fit question card to window** | <a id="feature-questionfit"></a>When the agent asks you a question, the question and its answers scroll together in the card, and **Skip** and **Submit** stay in view at the bottom. The card uses the height of the window (less 200 px for the chat header and a strip of the chat), so it grows and shrinks with the window. Without this feature, dsh keeps the card at 60% of the window (at most 520 px) and only the answers scroll: a long question can push its own end, the answers and the buttons out of the card. | <a href="assets/features/questionFit.webp"><img src="assets/features/questionFit.webp" width="160" alt="Screenshot: Fit question card to window"></a> |
|
|
48
|
+
| **Fit chat header to window** | <a id="feature-headerfit"></a>In a narrow window, the buttons in dsh's chat header (the mode, subagents, background jobs, Open in, the branch pill and the grants chip) no longer cover each other. The chat title keeps at least 120 px; the buttons that do not fit move to a second line at the right, and each one stays clickable. When everything fits on one line (a wide window), the header is exactly dsh's. Without this feature, dsh shrinks only the title: with a subagent and background jobs, its buttons slide over each other in a narrow chat column. The branch pill (**Branch per chat**) and the grants chip (**Allow for this chat**) also fit the header when this switch is off. | <a href="assets/features/headerFit.webp"><img src="assets/features/headerFit.webp" width="160" alt="Screenshot: Fit chat header to window"></a> |
|
|
48
49
|
| **One-click Continue** | <a id="feature-continuebutton"></a>After a stopped, failed or cut-off turn, an empty composer shows **▶**. One click resumes from the existing conversation without writing in the input or adding a visible chat message (the model receives a short hidden “continue from where it stopped” note, because some providers, such as Claude, reject a request that ends on an assistant reply). Messages that wait in the queue stay there: ▶ continues only the stopped task, then the queue runs. A completed turn keeps the regular Send button. | <a href="assets/features/continueButton.webp"><img src="assets/features/continueButton.webp" width="160" alt="Screenshot: One-click Continue"></a> |
|
|
49
50
|
| **Resume after restart** | <a id="feature-resumeafterrestart"></a>Off by default: switch it on in **Settings → Composer Plus**. If you quit dsh (or it closes) while a chat is working, that chat continues by itself when you open dsh again, with the same hidden note as One-click Continue. If a goal round (`/goal`) was running, the goal goes on with its next round (dsh pauses goals at every start until you resume them). Chats that you stopped, that finished or that failed do not continue. dsh itself has no setting for this: it only marks such a turn as interrupted. | <a href="assets/features/resumeAfterRestart.webp"><img src="assets/features/resumeAfterRestart.webp" width="160" alt="Screenshot: Resume after restart"></a> |
|
|
50
51
|
| **Queue drag-and-drop** | <a id="feature-queuereorder"></a>Queued messages get a grip (⠿). Drag to reorder, or focus the grip and press `↑` / `↓`. `Esc` cancels. | <a href="assets/features/queueReorder.webp"><img src="assets/features/queueReorder.webp" width="160" alt="Screenshot: Queue drag-and-drop"></a> |
|
|
@@ -61,19 +62,25 @@ Then restart dsh. (The CLI can't install into the desktop profile; the app manag
|
|
|
61
62
|
| **Branches in the workspace tree** | <a id="feature-branchtree"></a>Settings → Composer Plus → **Branches in the workspace tree** (off by default). Each branch that has a worktree folder in `<project>/.worktrees/` then shows as a project inside its project; choose dsh's **View options** → **Workspace Tree** to see it nested. A branch whose folder is deleted leaves the list, and dsh shows its chats under **Ungrouped**. When the agent of a chat in the project folder creates a branch and switches to it (`git switch -c`, `git checkout -b`) while the folder has no uncommitted changes, the project folder goes back to its branch, the branch gets its own folder, and the chat moves into it: a copy opens in the branch project and goes on with the task, and the old chat is archived. The list is checked at start, every 30 seconds, after each turn and when you come back to the window. | <a href="assets/features/branchTree.webp"><img src="assets/features/branchTree.webp" width="160" alt="Screenshot: Branches in the workspace tree"></a> |
|
|
62
63
|
| **Next message prediction** | <a id="feature-nextprediction"></a>On by default; switch it off in **Settings → Composer Plus**. When the agent finishes a turn (not a stopped or failed one), the empty composer shows a guess of your next message in grey, with a **Tab to accept** hint. `Tab` puts the text in the composer, but does not send it. `Esc` hides it for that turn. Typing also hides it, and a new turn replaces it. The **Model** menu under the switch lists dsh's own models (the same list as dsh's model menu). **dsh default** is selected by default and follows dsh's default model. Each finished turn costs one short model call. In Tether, the guess shows above the empty composer: tap it to put it in the field. | <a href="assets/features/nextPrediction.webp"><img src="assets/features/nextPrediction.webp" width="160" alt="Screenshot: Next message prediction"></a> |
|
|
63
64
|
| **Complete while typing** | <a id="feature-typingcompletion"></a>Off by default; switch it on in **Settings → Composer Plus**. While you type, grey text right after the cursor shows how your message may go on. `Tab` adds it to the message, but does not send it. `Esc` hides it. It suggests only your own next words: never an answer to you, and no made-up error texts or names. When the message looks complete or the model is not sure, nothing shows. Typing the next letters of the grey text keeps it, with no new model call. It has its own **Model** menu under its switch. Its first entry, **Same as Next message prediction**, uses the model of **Next message prediction** (the default); pick another model to use a different one for each feature, for example a faster model for completions. It makes one model call at each pause while you type, so it uses many more tokens than the prediction: pick a fast, low-cost model. It does not run for a slash command, a message with a file chip, or when the cursor is not at the end. In Tether, the rest shows above the field while you type: tap it to add it. | <a href="assets/features/typingCompletion.webp"><img src="assets/features/typingCompletion.webp" width="160" alt="Screenshot: Complete while typing"></a> |
|
|
64
|
-
| **Improve prompt** | <a id="feature-promptimprove"></a>Type a rough request, then click the magic wand (**Improve prompt**) next to the model menu. One model call rewrites it as a clearer prompt: the goal first, short numbered steps when there are several parts, and the check to run. It reads this chat (rolled-back messages left out), the project's README, AGENTS.md and manifest, the changed files and the files whose names match your words, and keeps your language. It never makes up file names. The new text replaces your draft but is not sent: read it, edit it, then press `Enter`. `Cmd/Ctrl+Z` brings your text back in one step, and so does the button (**Undo improvement**). If you type while it works, your new text stays. `Esc` or a second click cancels. It has its own **Model** menu in Settings (default: **Same as the chat's model**). Not for slash commands or a message with a file chip. In Tether, the wand is next to the field. | <a href="assets/features/promptImprove.webp"><img src="assets/features/promptImprove.webp" width="160" alt="Screenshot: Improve prompt"></a> |
|
|
65
|
-
| **Goal check** | <a id="feature-goalcheck"></a>Start a goal with `/goal`. When the agent marks the goal complete in an automatic round, the goal closes only after two checks. First, the project's test command runs in the chat's folder, under the chat's sandbox mode. The command is your own one or the one found in `package.json`, `Makefile`, `Cargo.toml`, `go.mod` or pytest. When the agent's own newest step was a passing run of that test, it does not run again. Then one independent model call, with no tools, reads the goal, this chat, `git status` and the test result. If a check fails, the goal stays active and the agent reads
|
|
66
|
-
| **
|
|
65
|
+
| **Improve prompt** | <a id="feature-promptimprove"></a>Type a rough request, then click the magic wand (**Improve prompt**) next to the model menu. One model call rewrites it as a clearer prompt: the goal first, short numbered steps when there are several parts, and the check to run. It reads this chat (rolled-back messages left out), the project's README, AGENTS.md and manifest, the changed files and the files whose names match your words, and keeps your language. It never makes up file names. The new text replaces your draft but is not sent: read it, edit it, then press `Enter`. `Cmd/Ctrl+Z` brings your text back in one step, and so does the button (**Undo improvement**). If you type while it works, your new text stays. `Esc` or a second click cancels. It has its own **Model** menu in Settings (default: **Same as the chat's model**). On a `/goal <objective>` message it rewrites only the objective, as a completion condition that **Goal check** can verify: the outputs, the checks that must pass, the evidence to show in the chat, a part that cannot be done marked as unresolved, and a stop when the same blocker stays. The `/goal` command stays. Not for other slash commands, a `/goal` control word (`clear`, `pause`, `resume`) or a message with a file chip. In Tether, the wand is next to the field. | <a href="assets/features/promptImprove.webp"><img src="assets/features/promptImprove.webp" width="160" alt="Screenshot: Improve prompt"></a> |
|
|
66
|
+
| **Goal check** | <a id="feature-goalcheck"></a>Start a goal with `/goal`. When the agent marks the goal complete in an automatic round, the goal closes only after two checks. First, the project's test command runs in the chat's folder, under the chat's sandbox mode. The command is your own one or the one found in `package.json`, `Makefile`, `Cargo.toml`, `go.mod` or pytest. When the agent's own newest step was a passing run of that test, it does not run again. Then one independent model call, with no tools, reads the goal, this chat, `git status` and the test result. The model answers with an evidence table: each part of the goal is verified, incorrect or unresolved, with the evidence and the fix; the goal closes only when every part is verified. If a check fails, the goal stays active and the agent reads each open part with its evidence and fix, then the next round goes on. A row under the goal bar (**Goal check**) shows the test, the last result and how many parts were verified (hover it for the table). **Edit** sets your own test command and a time or token limit; over the limit the goal becomes blocked. The token limit also counts the chat's subagents. **Run now** runs the check without closing the goal. It has its own **Model** menu in Settings (default: **Same as the chat's model**). When you complete the goal yourself, nothing is checked. | <a href="assets/features/goalCheck.webp"><img src="assets/features/goalCheck.webp" width="160" alt="Screenshot: Goal check"></a> |
|
|
67
|
+
| **Continue in a new chat** | <a id="feature-handoffchat"></a>Right-click a chat in the sidebar (or open its **…** menu) → **Continue in a new chat…**. One call to the chat's own model writes a handoff note from the chat: Task, Outputs, Completed, Decisions, Open issues and Next action, from what the chat shows (tool calls and results are the evidence; steps that you rolled back are left out). The note opens in a dialog: read it and edit it. **Write again** writes a new note. **Start new chat** (or `Cmd/Ctrl+Enter`) opens a new chat in the same project with the note and a link to the old chat as its first message; the old chat stays as it is. Use it when a long chat is full or slow, or to continue tomorrow. Nothing is written to the project. | <a href="assets/features/handoffChat.webp"><img src="assets/features/handoffChat.webp" width="160" alt="Screenshot: Continue in a new chat"></a> |
|
|
68
|
+
| **Context breakdown** | <a id="feature-contextbreakdown"></a>Right sidebar → `+` → **Context**. The page shows what fills the open chat's model context now and how much of the context window it uses: the system prompt, project instructions (AGENTS.md), skills, your messages, agent replies and tool calls, tool results (by tool), MCP results (by server), tool definitions, the compact summary and other context notes, each with its tokens and its share. Click a part to see its tools or servers. It reads the chat log only, after `/compact` and rollbacks, and calls no model; it reads again after each turn and with **Refresh**. Use it to see why a chat is slow or full, for example a big MCP tool result or many tool definitions. | <a href="assets/features/contextBreakdown.webp"><img src="assets/features/contextBreakdown.webp" width="160" alt="Screenshot: Context breakdown"></a> |
|
|
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
|
+
| **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
|
+
| **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**. A kanban board of your dsh projects for you and the agents: **Todo**, **Doing**, **Review** and **Done** (and **Backlog**, see below). Pick a project or **All projects** on the left. **New task** (or `n`) opens a new card: type its title and press `Enter`. Drag a card to another column or between two cards. Click a card to see and change its **Status**, **Tags**, **Human** (agents skip it), description (Markdown) and comments. `/` searches every project, `h` shows only human tasks, the export button saves the board as Markdown or JSON. Agents get board tools: ask a chat to "take the next task from the board" and it moves the top **Todo** card to **Doing**, comments on what it did and moves it to **Review**; you move it to **Done**. In a project with open tasks, each chat gets this rule by itself. Settings → Composer Plus → **Task board** has the **Backlog** column switch: agents leave its cards to you. | <a href="assets/features/taskBoard.webp"><img src="assets/features/taskBoard.webp" width="160" alt="Screenshot: Task board"></a> |
|
|
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> |
|
|
67
74
|
| **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> |
|
|
68
75
|
| **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> |
|
|
69
|
-
| **Git branch on chat rows** | <a id="feature-sessionbranch"></a>Each chat row in the sidebar 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
|
|
76
|
+
| **Git branch on chat rows** | <a id="feature-sessionbranch"></a>Each chat row in the sidebar 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. A chat under a project row with its branch's name (a “Branch per chat” folder) shows no pill, except in “In one list”. | <a href="assets/features/sessionBranch.webp"><img src="assets/features/sessionBranch.webp" width="160" alt="Screenshot: Git branch on chat rows"></a> |
|
|
70
77
|
| **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> |
|
|
71
78
|
| **Active projects first** | <a id="feature-activeprojectsfirst"></a>When a chat starts running or needs you, its project moves to the top of the sidebar with dsh's own row animation (the same move as dragging it there). Finished projects stay where they are; drag them anywhere as usual. Moves are saved to dsh's project order, so turning this off keeps the current order. | <a href="assets/features/projectStatus.webp"><img src="assets/features/projectStatus.webp" width="160" alt="Screenshot: Active projects first"></a> |
|
|
72
79
|
| **Recent projects filter** | <a id="feature-recentprojects"></a>Sidebar → view options (sliders icon) → **Active in the last 2 hours**. While it is selected, the sidebar shows only projects with a chat that was active in the last 2 hours: a chat updated in that time, a running or waiting chat, the open chat, or a finished chat that you did not open yet (dsh's green “done” dot), also after the 2 hours. Projects without such a chat are hidden, also new and empty ones. In **Workspace Tree**, a parent folder stays while a project inside it is active, and the chats that were not active in the last 2 hours hide too, so only the recent chats show. Select it again to show all projects. The choice is kept on this device. | <a href="assets/features/recentProjects.webp"><img src="assets/features/recentProjects.webp" width="160" alt="Screenshot: Recent projects filter"></a> |
|
|
73
80
|
| **Collapse all projects** | <a id="feature-collapseprojects"></a>While a project is open in the sidebar, a button appears next to the view options (sliders icon). Click it to close every open project at once, for example 3 open projects out of 5. The button hides again when no project is open. | <a href="assets/features/collapseProjects.webp"><img src="assets/features/collapseProjects.webp" width="160" alt="Screenshot: Collapse all projects"></a> |
|
|
74
81
|
| **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> |
|
|
75
82
|
| **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> |
|
|
76
|
-
| **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), and you do not use dsh for 30 seconds, dsh opens that chat.
|
|
83
|
+
| **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> |
|
|
77
84
|
| **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> |
|
|
78
85
|
| **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> |
|
|
79
86
|
| **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 (taken from the same update check, no extra network call); **Close** or `Esc` closes it. | <a href="assets/features/autoUpdate.webp"><img src="assets/features/autoUpdate.webp" width="160" alt="Screenshot: Automatic updates"></a> |
|
|
@@ -158,7 +165,12 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
158
165
|
- **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).
|
|
159
166
|
- **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).
|
|
160
167
|
- **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).
|
|
161
|
-
- **
|
|
168
|
+
- **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
|
+
- **Context breakdown:** reads only the chat log on the Host; no model call, no project file.
|
|
170
|
+
- **Task board:** the board (titles, descriptions, tags and comments of your tasks, the project folder paths and their short ids) is in `$DSH_HOME/storages/dsh-composer-plus/board.json` (owner-only file); the switch is in `board-switch.json` next to it. Nothing leaves your machine and nothing is written to a project folder. The board tools give the agents what you wrote on the board, so the text of a task reaches the chat's model when an agent reads it. A broken board file is kept as `board.json.broken-<time>` and the board starts empty.
|
|
171
|
+
- **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
|
+
- **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
|
+
- **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.
|
|
162
174
|
- **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).
|
|
163
175
|
- **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.
|
|
164
176
|
|
|
@@ -180,7 +192,7 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
180
192
|
- **No branch pill on a chat row:** 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).
|
|
181
193
|
- **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.
|
|
182
194
|
- **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).
|
|
183
|
-
- **Install fails right after a release:** add the version (`dsh-composer-plus@1.
|
|
195
|
+
- **Install fails right after a release:** add the version (`dsh-composer-plus@1.18.0`), see the install note above.
|
|
184
196
|
- **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.
|
|
185
197
|
- **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.
|
|
186
198
|
- **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.
|
|
@@ -203,6 +215,7 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
203
215
|
- **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.
|
|
204
216
|
- **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.
|
|
205
217
|
- **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.
|
|
218
|
+
- **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.
|
|
206
219
|
- **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. This switch is off by default, 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.
|
|
207
220
|
- 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.
|
|
208
221
|
- **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.
|
|
@@ -217,7 +230,7 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
217
230
|
- **Branch per chat**: when a chat's branch folder (`<project>/.worktrees/<name>`) is deleted, for example when the chat's own agent removes the worktree and deletes the branch, the chat's next step moves the chat out of it. Its branch folder project goes from the sidebar, and the chat shows under Ungrouped and stays open. On dsh 0.2.1 and later the chat continues in the main project folder, and the model gets a note about the new folder. On dsh 0.2.0 the chat keeps the deleted folder: a command there fails until you start a new chat. A project of a deleted branch that no chat uses also leaves the sidebar: Composer Plus checks the branch folders at start and every 30 seconds, also with no sidebar filter. While a chat moves, **New branch** in the same repository answers "try again". With the switch off, dsh's own error shows again ("working-directory: directory does not exist").
|
|
218
231
|
- **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.
|
|
219
232
|
- **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).
|
|
220
|
-
- **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); a subagent's request shows in its parent chat. 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.
|
|
233
|
+
- **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.
|
|
221
234
|
- A notification sent before a restart only brings dsh to the front when clicked.
|
|
222
235
|
- 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.
|
|
223
236
|
- 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.
|
|
@@ -226,10 +239,16 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
226
239
|
- dsh has no hook that chooses where **New session** opens either. **Default workspace for New session** wraps a method of dsh that is not a public API (`startSession` of dsh's workspace service). If a dsh update renames it, **New session** opens where dsh chooses (the open or the most recent project). Every call that names no project uses the default: the sidebar button, its shortcut, the logo, and also **New** on the **Automation tasks** page. dsh still opens the last chat when it starts. The general folder is made and added to your projects at the first use; on Windows or Linux with a moved Documents folder it can be a different folder from dsh's own.
|
|
227
240
|
- dsh has no extension point for a composer hint either, so the **Next message prediction** text sits over dsh's own placeholder (`[data-composer-placeholder]`). If a dsh update changes that markup, no prediction shows. While it is on, each finished turn costs one short model call.
|
|
228
241
|
- **Complete while typing** shows its text through dsh's own composer hint (the `--dsh-composer-hint` style that dsh uses for a slash command's argument hint). It does not run for a slash command, a message with a file or symbol chip, or when the cursor is not at the end of the message. If a dsh update changes that style, no completion shows. Each pause while you type costs one model call.
|
|
229
|
-
- **Improve prompt** sees only a short project summary, the changed paths and the paths whose names match your words: not the code itself. So it can miss the right file, and it names only paths that it was given. Read the new text before you send it. It does not run for a slash command or a message with a file or symbol chip (the new text is plain text, so it would lose the chip), and a message can have at most 8,000 characters. Images stay attached: only the text changes. Each click costs one model call; a strong model can take a minute (`Esc` cancels).
|
|
230
|
-
- **Goal check** checks only a completion that the agent makes in an automatic goal round: a completion that you ask for in the chat, `/goal` and the goal bar are not checked. The agent can change the tests or the test command's files itself; the verifier reads the chat and can see that, but it can be wrong in both directions (a wrong "not done" costs one more round; a wrong "done" closes the goal). The verifier sees the chat and `git status`, not the code itself. A test run is reused only when the agent's newest step that can change files was its own passing `bash` run of exactly the same command in the same folder; a command with a pipe (`| tail`) or `&&` is not reused. The budget is measured when a turn ends, so one turn can go past it.
|
|
242
|
+
- **Improve prompt** sees only a short project summary, the changed paths and the paths whose names match your words: not the code itself. So it can miss the right file, and it names only paths that it was given. Read the new text before you send it. It does not run for a slash command other than `/goal <objective>`, for a `/goal` control word (`clear`, `pause`, `resume`) or for a message with a file or symbol chip (the new text is plain text, so it would lose the chip), and a message can have at most 8,000 characters. For a `/goal` objective it writes conditions only from the draft and the context; a condition that is too strict can cost goal rounds, so read it before you send it. Images stay attached: only the text changes. Each click costs one model call; a strong model can take a minute (`Esc` cancels).
|
|
243
|
+
- **Goal check** checks only a completion that the agent makes in an automatic goal round: a completion that you ask for in the chat, `/goal` and the goal bar are not checked. The agent can change the tests or the test command's files itself; the verifier reads the chat and can see that, but it can be wrong in both directions (a wrong "not done" costs one more round; a wrong "done" closes the goal). The verifier sees the chat and `git status`, not the code itself. A test run is reused only when the agent's newest step that can change files was its own passing `bash` run of exactly the same command in the same folder; a command with a pipe (`| tail`) or `&&` is not reused. The budget is measured when a turn ends, so one turn can go past it. The token budget also counts the calls of the chat's subagent chats (read from their saved logs at each turn end, so a chat with many subagents takes a little longer to check). The evidence table comes from the verifier's own reading of the chat: a part that it calls verified still needs your own look when it matters. `update_goal` waits while the check runs (the test at most 15 minutes, the verifier at most 3 minutes). A fork gets a new chat id, so it starts without the parent's own test command and limits. Each completion that reaches the verifier costs one model call.
|
|
244
|
+
- **Protected files** is a guard rail, not a sandbox. It covers dsh's own file tools (`read`, `read_image`, `grep` on a file, `write`, `edit`, `str_replace_editor`). A shell command (`cat .env`), a script that the agent writes, a subagent's shell, an MCP tool, a `glob` listing and a `grep` over a whole folder can still reach a protected file. For a real limit, use dsh's sandbox modes or keep secrets out of the project folder. Patterns know `*`, `**` and `?`, not `{a,b}` or `[ab]`, and they ignore letter case.
|
|
245
|
+
- **Blocked commands** is a guard rail, not a sandbox. It reads the command text of dsh's `bash` and `pwsh` tools only. A variable or an alias that names the command (`CMD=npm; $CMD publish`), a shell function, a script file that the agent writes, another program (`python -c`, `node -e`, `make`), an MCP tool and your own terminal can still run it. A rule matches more than you may want: any word of a command can be the command name (`echo npm publish` matches `npm publish`), and other words can come between the rule's words (`git push --force` also matches `git push origin main --force`). Make a rule longer when it matches too much. **ask first** needs a chat that can ask: in a chat whose approval policy is never (for example a delegated subagent), dsh cannot show the card, so the call is refused with the reason. The approval card shows the reason in English. **Allow for this chat** does not answer an **ask first** card.
|
|
246
|
+
- **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.
|
|
247
|
+
- **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.
|
|
248
|
+
- **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.
|
|
249
|
+
- **Task board** knows only dsh's projects: a chat outside a project shows **All projects**, and a Branch per chat folder (`<project>/.worktrees/<name>`) counts as its project. The project ids (`acme#12`) come from the folder name and stay when you rename the project in dsh. The rule "keep the board current" goes into a chat only when its project has open tasks; a chat that got it keeps it. Agents are told to leave **Done**, **Backlog** and human tasks to you, but the tools do not refuse it: an agent can still move such a card. The board tools are in every chat's tool list while the feature is on (about 1,000 tokens per request); switch it off if you do not use the board. The page reads the board every 2 seconds while it shows; a change by an agent shows within that time. A text that you edit while an agent changes the same field is not saved: the panel shows the new text and the reason. No images, no git sync between computers and no sharing over the network (Kanzo has them). 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.
|
|
231
250
|
- **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.
|
|
232
|
-
- **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;
|
|
251
|
+
- **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.
|
|
233
252
|
- **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.
|
|
234
253
|
- **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.
|
|
235
254
|
- **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.
|
|
@@ -262,7 +281,9 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
262
281
|
|
|
263
282
|
**Can the agent stop marking its own work as done, like the verifier loops in loop engineering?** Yes, with **Goal check** (on by default): start a goal with `/goal`. When the agent says the goal is complete, the project's tests run and an independent model call checks the goal against the chat; if either fails, the goal stays open and the agent reads why. Set your own test command, a time limit or a token limit with **Edit** in the **Goal check** row under the goal.
|
|
264
283
|
|
|
265
|
-
**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.
|
|
284
|
+
**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.
|
|
285
|
+
|
|
286
|
+
**Can my agents and I share one task board, like Kanzo?** Yes, with **Task board** (on by default): open it in the left sidebar and add tasks with **New task**. In a chat, ask the agent to "take the next task from the board": it moves the card to **Doing**, comments on what it did and moves it to **Review**. Mark a task **Human** to keep it for yourself.
|
|
266
287
|
|
|
267
288
|
**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.
|
|
268
289
|
|
|
@@ -288,6 +309,8 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
288
309
|
|
|
289
310
|
**How do I see only the files that one chat changed?** Right sidebar → **Changes** → **This chat**. Click **␣** to hide changes that are only whitespace.
|
|
290
311
|
|
|
312
|
+
**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.
|
|
313
|
+
|
|
291
314
|
**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**.
|
|
292
315
|
|
|
293
316
|
**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.
|
|
@@ -302,7 +325,7 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
302
325
|
|
|
303
326
|
**How do I get macOS / Windows notifications when a dsh task finishes or needs approval?** Keep **Background notifications** on (default) and allow notifications for DeepSeek Harness in the OS settings.
|
|
304
327
|
|
|
305
|
-
**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. While you type, scroll or move the mouse, it waits.
|
|
328
|
+
**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.
|
|
306
329
|
|
|
307
330
|
**How do I switch the DeepSeek Harness interface to Turkish, Spanish, Japanese…?** Settings → Composer Plus → **Application language**.
|
|
308
331
|
|
|
@@ -316,6 +339,8 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-rc.2` (web). CI runs the
|
|
|
316
339
|
|
|
317
340
|
**Can I send a photo from my iPhone?** Yes. In a Tether chat, tap **+** next to the message field → Camera, Photos (up to 4) or Paste image. The photos go to the chat on the Mac as attachments of your message, so the model sees them.
|
|
318
341
|
|
|
342
|
+
**Can dsh run the next command without asking the model again?** Yes, with **Planned steps** (off by default): switch it on in Settings → Composer Plus. The model can then plan its next commands with a condition, for example "run the tests when the build passes", and Composer Plus runs a step without a new model call when the result meets the condition. Approvals and the sandbox stay as they are.
|
|
343
|
+
|
|
319
344
|
**Does it work with the desktop app?** Yes: Settings → Plugins → **Add plugin** → `dsh-composer-plus`. Tested on dsh 0.2.0-rc.2 (desktop and web) and 0.2.1-rc.2 (web).
|
|
320
345
|
|
|
321
346
|
## Development
|
|
@@ -341,6 +366,8 @@ PLAYWRIGHT=/path/to/playwright node test/browser-readme-anchors.mjs
|
|
|
341
366
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-keep-focus.mjs /path/to/dsh/lib/bin.js
|
|
342
367
|
# Fit question card to window (fake model asks a long question at 1280 × 820): question, answers, Skip and Submit readable, height follows the window + its thumbnail
|
|
343
368
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-question-fit.mjs /path/to/dsh/lib/bin.js
|
|
369
|
+
# Fit chat header to window (fake model, subagent + background jobs, branch pill, grants chip): no overlap from 1280 to 320 px, wide header unchanged + its thumbnail
|
|
370
|
+
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-header-fit.mjs /path/to/dsh/lib/bin.js
|
|
344
371
|
# Mobile connect: switch on, QR popover, a fake iPhone pairs and calls dsh through the gateway, switch off + its thumbnail
|
|
345
372
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-mobile-connect.mjs /path/to/dsh/lib/bin.js
|
|
346
373
|
# Resume after restart (fake slow model, real quit and start): a running chat and a goal continue, a stopped chat does not
|
|
@@ -378,6 +405,8 @@ PLAYWRIGHT=/path/to/playwright node test/browser-continue-queue.mjs /path/to/dsh
|
|
|
378
405
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-queue-stop-send.mjs /path/to/dsh/lib/bin.js
|
|
379
406
|
# Edit queued message in place with images and files (slow fake model) + its thumbnail
|
|
380
407
|
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-queue-edit.mjs /path/to/dsh/lib/bin.js
|
|
408
|
+
# Task board: the page, the agent tools (fake model), drag and drop, search, the switch
|
|
409
|
+
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-task-board.mjs /path/to/dsh/lib/bin.js
|
|
381
410
|
```
|
|
382
411
|
|
|
383
412
|
```sh
|