diff --git a/CHANGELOG.md b/CHANGELOG.md index c70e2cff..25c272ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## 7.8.0 + +### Open the workspace in VS Code + +- **One button, local or remote.** A project row and the file viewer now hand the + workspace to your desktop editor. A remote SSH project opens through **VS Code + Remote-SSH**, already at the right path — no reconnecting by hand, no hunting for + the folder. + +- **It opens on the machine you are sitting at.** The studio launches the editor + itself when it can find a `code` binary on the host; when it cannot — inside + Docker, on a headless server, on Windows — it hands your browser a `vscode://` + link instead, and the desktop handler takes it from there. One rule, no + platform-sniffing, and it lands correctly whether the studio runs on your laptop + or three time zones away. + +- **Not only VS Code.** Insiders, VSCodium, Cursor and Windsurf are selectable in + Settings → *UI*. All four are VS Code forks, so the remote-SSH link means the same + thing in each; only the scheme and the binary change. + +- **A remote workspace on a non-standard port carries it.** Omitting the port would + not be the cautious choice — the connection would simply be attempted against 22 + and fail. + +- **Refusals say what is wrong.** A remote project recorded with a `~/project` + workdir cannot be expressed as a URI (Remote-SSH would look for a directory + literally named `~`), so it is refused by name rather than opening the wrong + folder. Per-file opening stays local-only on purpose: VS Code's own URL handler + opens a remote *file* link as a folder, so the button comes off rather than doing + the wrong thing — the project row still opens the remote workspace. + ## 7.7.0 Three things that were true only in one place become true everywhere: the file diff --git a/CLAUDE.md b/CLAUDE.md index 1b07f991..afe4dbb4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,7 +20,7 @@ docker compose up -d docker compose logs -f claude-chat ``` -No linting and no build step configured. `npm test` chains 63 test files under `test/`: 18 DOM-less render/UI-logic tests (`test/render/*.test.mjs`, run through `node --test`) plus 45 plain-`node` suites in `test/` covering the overload detector, env load order, multi-agent results, terminals, bots, telegram, updates, kanban scheduling, i18n completeness, the config precedence resolver plus its secret masking, usage-limit detection, the filesystem path guard (including the SVG sandbox header and the symlink rule on the `@`-mention search endpoints) plus the tunnel-blocks-terminal rule, WS session re-subscription, the SSH remote CLI-session import, the live engine pane / interactive-prompt watchdog, the cross-project global workspace aggregation, the rule that an SSH credential never leaves the server process, the Windows command-quoting oracle, the auth token lifecycle, the multi-agent dependency scheduler (waves, plan sanitising, and the rule that a failure warning must survive dep-context truncation), the SSH stream parser's three guards, the remote non-interactive shell environment (`remote-env.test.js`, which runs the generated prelude through real `bash -lc`: it must parse, print nothing on stdout, and never end on a false test — the caller chains `&& claude …` behind it), the remote CLI-list framing parser, the bot inbox's SQL seam (`bot-inbox.test.js` pins that `from_bot AS "from"` keeps the exact key `planInboxDelivery` reads — rename one without the other and every letter is silently retired as malformed), the one-time config/.env migration onto CCS_CONFIG_PATH and the mid-task clarification delivery contract on the subscription engine (`interrupt-delivery.test.js` — pins that the tmux injection block sits BEFORE the poll loop's completion `break`, that draining does not imply delivery, that a failed paste is re-queued and warns non-terminally, and that the task runner passes the same callbacks the chat path does), the CLAUDE.md / AGENTS.md discovery rules (`agents-md.test.js`, which also pins that AGENTS.md reaches the subprocess as `--append-system-prompt` and never as `--system-prompt`), and the remote file browser's three guard layers (`remote-files.test.js` runs the generated POSIX script through a real `/bin/sh` against a temp tree that contains symlinks OUT of the project; `remote-files-api.test.js` boots a server against a fake remote via `CCS_REMOTE_EXEC_HOOK` and drives `/api/files` the way the SPA does), and the new-chat defaults chain (`chat-defaults.test.js` pins the pure resolver — the built-ins are asserted to be exactly what the SPA hardcoded before #58, and the choice lists to be exactly the toolbar's `data-v` sets and `MODEL_MAP`'s aliases; `chat-defaults-api.test.js` boots a real server in a throwaway `APP_DIR` and pins that a project writes back a SPARSE override object — a five-key snapshot passes every other assertion in that file and still breaks the feature). On the render side, `tables.test.mjs` also pins the ReDoS bound in renderMd step 3.4, `xss.test.mjs` runs 24 adversarial payloads end-to-end, and `forged-tokens.test.mjs` covers the case where user text contains the renderer's own placeholder control bytes, and `pane-font.test.mjs` pins the clamp DIRECTION of `_fitEnginePaneFont` (a wide engine pane may only shrink; a narrow split pane must be allowed to grow). `script-scope.test.mjs` pins which `