Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
5ee28c8
perf(bench): add a reproducible runtime benchmark
BIackFIame Sep 28, 2026
15fe7ed
perf(terminal): release scrollback chunks as soon as the ring drops them
BIackFIame Sep 28, 2026
3824b02
perf(terminal): replay only the missed output when a card becomes vis…
BIackFIame Sep 28, 2026
13c3f76
perf(agents): look orchestrated sessions up by id instead of snapshot…
BIackFIame Sep 28, 2026
88da65e
perf(redaction): mask a bounded window around the tail agents and plu…
BIackFIame Sep 28, 2026
dfb0b25
perf(kimi): probe the Kimi CLI in the background instead of on the fi…
BIackFIame Sep 28, 2026
98db10f
perf(even-g2): parse only the sessions the glasses read
BIackFIame Sep 28, 2026
cd7e107
perf(canvas): keep a pan from re-rendering every terminal card
BIackFIame Sep 28, 2026
a4204f4
perf(renderer): ship the Hermes and Codex marks at icon size with a 2…
BIackFIame Sep 28, 2026
d10187d
perf(renderer): minify the renderer production bundle
BIackFIame Sep 28, 2026
61daece
fix(terminal): wait for every PTY to exit before the app finishes qui…
BIackFIame Sep 28, 2026
44a5fa7
fix(redaction): find held values with a linear search, not a pattern …
BIackFIame Sep 28, 2026
8b2de25
perf(runtime): send Claude Code lifecycle hooks over loopback HTTP
BIackFIame Sep 28, 2026
1360b4a
fix(browser): keep saving tabs after one failed write
BIackFIame Sep 28, 2026
bdfb9a7
fix(safety): fail closed when the decision hook cannot reach CanvasTTY
BIackFIame Sep 28, 2026
13c4c40
fix(safety): read wrapped and bundled-flag command forms in base prot…
BIackFIame Sep 28, 2026
90308ce
fix(ipc): accept settings, plugin, secret and terminal calls only fro…
BIackFIame Sep 28, 2026
a5bb450
fix(windows): escape batch provider arguments for the shim's second c…
BIackFIame Sep 28, 2026
14112d8
fix(agent-control): bound request receipts without locking out contro…
BIackFIame Sep 28, 2026
37c2ab5
fix(windows): handle pipe host stdio errors instead of crashing the m…
BIackFIame Sep 28, 2026
2dcff05
fix(gateways): recover from a failed Windows pipe host and clean up a…
BIackFIame Sep 28, 2026
0141276
fix(windows): pass the real search path to plugin environment wrappers
BIackFIame Sep 28, 2026
d4dde5d
fix(orchestration): let cancel and disconnect reach the running tool …
BIackFIame Sep 28, 2026
232a9fd
fix(plugins): run only the service entry bytes that match the trusted…
BIackFIame Sep 28, 2026
7d52290
fix(agent-runtime): close hook connections that never send their message
BIackFIame Sep 28, 2026
6a77cb6
fix(storage): remove the temporary file when an atomic write fails
BIackFIame Sep 28, 2026
ebdbba7
fix(browser-audit): recover from a record cut off during a write
BIackFIame Sep 28, 2026
754dffe
fix(browser-audit): hash records with a locale-independent key order
BIackFIame Sep 28, 2026
37f80d9
fix(windows): find cmd.exe the same way for the terminal and batch pr…
BIackFIame Sep 28, 2026
9c64479
fix(github-auth): keep polling the device code through network errors
BIackFIame Sep 28, 2026
89be9d5
fix(settings): apply provider availability in write order
BIackFIame Sep 28, 2026
4315658
fix(limits): do not start `kimi web` after the limits service was dis…
BIackFIame Sep 28, 2026
03fdaa7
fix(plugin-media): do not follow a link at the playlist temp name
BIackFIame Sep 28, 2026
b16bee2
fix(plugin-cards): do not count hidden badges of revoked plugins
BIackFIame Sep 28, 2026
4839f0a
fix(plugins): do not wipe plugin storage when it cannot be read
BIackFIame Sep 28, 2026
1c58f2a
fix(plugins): keep the service entry guard out of the main bundle's C…
BIackFIame Sep 28, 2026
f577fdb
fix(redaction): mask a held value as written when its wrap characters…
BIackFIame Sep 28, 2026
6cd6d66
fix(redaction): start the tail window at a line no match crosses
BIackFIame Sep 28, 2026
e4c46da
fix(safety): read every curl and wget file option, and --output-dir i…
BIackFIame Sep 28, 2026
4d616f7
fix(plugins): check the main module node resolves, not only the path …
BIackFIame Sep 28, 2026
7d6009c
test(kimi): compare the two probes with a generous time limit
BIackFIame Sep 28, 2026
d2fddde
fix(safety): give each curl operation its own --output-dir, and let -…
BIackFIame Sep 28, 2026
b57b9dd
Merge #89, #90, #92 and #93 as the base for this change
BIackFIame Sep 28, 2026
6a40740
perf(startup): start services while the startup page loads
BIackFIame Sep 28, 2026
eda1fea
perf(startup): load cold-path dependencies on first use
BIackFIame Sep 28, 2026
0f9ef2d
perf(limits): run `codex app-server` only while limits are read
BIackFIame Sep 28, 2026
2b86482
perf(startup): stat each CLI search directory once, not every candida…
BIackFIame Sep 28, 2026
59bdb1c
refactor: one NDJSON line reader for every stream and socket reader
BIackFIame Sep 28, 2026
9cd7f7a
refactor(gateways): share token checks and socket endpoint handling
BIackFIame Sep 28, 2026
4ba0a1b
refactor: one canonical JSON serializer
BIackFIame Sep 28, 2026
85b5095
refactor: one "path inside root" check
BIackFIame Sep 28, 2026
7149934
refactor(redaction): one list of sensitive names
BIackFIame Sep 28, 2026
7b8b61b
refactor(providers): derive provider lists from the catalog
BIackFIame Sep 28, 2026
d0c68a5
refactor(provider-config): one lock, CAS and atomic write for config …
BIackFIame Sep 28, 2026
31d3696
test: share the provider registry and PTY spawner stubs
BIackFIame Sep 28, 2026
8accbd1
refactor: remove a dead function and exports nothing imports
BIackFIame Sep 28, 2026
73dcffe
perf(renderer): route terminal output to its own card in the preload
BIackFIame Sep 28, 2026
c3bfee8
perf(terminal): send one renderer message per output flush for the wh…
BIackFIame Sep 28, 2026
7f50b8b
perf(terminal): draw every on-screen card with WebGL from a bounded c…
BIackFIame Sep 28, 2026
d409204
perf(workspace): composite the scene while the wheel or trackpad pans it
BIackFIame Sep 28, 2026
aab91b5
perf(terminal): let output-driven WebGL replans wait for the camera t…
BIackFIame Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- Added launch contributors (`launch:contribute`): a trusted plugin service can declare launcher options (boolean, select, text) shown under **Advanced** in the agent launcher. For launches where the person chose the plugin, and their restarts and restores, CanvasTTY asks the service to prepare the launch and adds its environment variables, secret variables resolved from the plugin's own secrets (masked in text other agents and the control CLI read), arguments and per-run files. Contributors merge in plugin-id order; a refusal, a 5 s timeout, a conflict, a reserved name or an approval/conversation argument refuses the launch with the reason on the card, and a restored card whose plugin is unavailable comes back stopped. The chosen values are saved with the session. A contributor may also declare `launch.policy`: it is then asked before every launch of its agents where the person did not choose it (`chosen: false`), may only refuse, and no answer refuses too. Examples: `examples/plugins/launch-env`, `examples/plugins/yolo-guard` (a launch policy).
- Added session environments (`environment:provide`): a trusted plugin service can offer places a card runs in (a git worktree, a container, a remote host), chosen under **Where** in the launcher's Advanced section; terminals get the same launcher while such an environment applies to them. The service prepares the place once, then wraps every start (validated: an absolute program path or a bare name resolved on PATH, never a shell string; launch-contributor env rules; plugin secrets masked) while CanvasTTY keeps spawning the PTY. The opaque ref is saved with the card; restore resumes environments first, then parents before children, and a missing, disabled or untrusted plugin, a stopped environment or a timeout brings the card back stopped with the reason, never run locally. Closing such a card asks once "Keep environment data?" and releases it accordingly. Launch contributors and policies are told the card's environment (`environment` in `canvastty.launch.prepare`). Example: `examples/plugins/env-worktree` (one git worktree per card).
- Added base protection and decision hooks. Base protection (Settings → Agents, on by default, the person can turn it off) refuses, before a local Claude Code, Codex, Qwen Code or OpenCode tool call runs (YOLO included), sudo and other elevation, curl | sh and download-and-run, disk and format commands, fork bombs, and writes or deletes outside the working folder (`/tmp` and the home folder included, and deleting the folder itself; the agent's own plan and memory folders excepted), telling the model what to do instead. A trusted plugin service can declare `decide` (`decision:provide`) and answer `canvastty.decide` with deny, ask or allow: base protection runs first, any deny wins, a timeout or error asks the person, and an allow counts only after a separate **May allow agent actions** confirmation. A service may declare `decide.timeoutMs` (1–60 s, 3 s by default): CanvasTTY waits that long, tells the service its `budgetMs`, and sizes each card's hook, helper and gateway deadlines at launch for the longest budget that applies (the default keeps today's deadlines). Example: `examples/plugins/deny-rm`. Every text one agent reads from another (`observe_agent`, `get_agent_result`, the control CLI's screen, result and failure details) is now masked for vault keys, launch secrets, values a service registers (`redaction.register`) or reads (`secrets.get`), keys wrapped over lines, and common key shapes.
- The decision hook now fails closed. While base protection is on or a decision plugin applies, a Claude Code, Codex, Qwen Code or OpenCode shell or file-writing call that CanvasTTY cannot check (the socket is missing or refused, no answer in time, an unreadable answer, the gateway's own failure where the CLI cannot ask, hook input it cannot read) is refused with "CanvasTTY safety check unavailable" instead of running unchecked. With base protection off and no decision plugin nothing changes, and answered calls take no extra time.
- Base protection now reads more command forms: a command after `do`, `then`, `else`, `if`, `while`, `until` or `!`; `env -i`/`-u`/`-C`/`-S`, `stdbuf`, `busybox`/`toybox` applets and `script -c` / `script file cmd`; `perl -i` and `ruby -i` in-place edits; `find -L`/`-H`/`-P`/`-O2`/`-f`; `cp`/`mv`/`install`/`ln -t DIR`; `tar -C DIR -x…` and `--directory=`; `unzip -o … -d DIR`; bundled `curl -fsSLo FILE`, `--output=`, `--output-dir` before or after `-O`/`-o` (a relative `-o` lands in it), the cookie jar, header dump, trace, `--stderr`, `--libcurl`, `--etag-save`, `--hsts`, `--alt-svc` and `-w '%output{FILE}'` files in every spelling, `wget -qO`/`-qP`, its log (`-o`/`-a`/`--output-file`/`--append-output`), `--save-cookies`, `--rejected-log` and `--warc-file`; `-o /dev/null` and `-D -` write no file and are no longer refused. Each is refused outside the project exactly like the plain command, a download run in the same command is download-and-run however its output flag is written, and the same forms inside the project stay allowed (`find -L dir -exec rm {} +` inside the project is no longer refused).
- Added plugin agent tools, session events and card badges and actions. A trusted service can offer `tools` (`tools:agents`) that appear in `canvastty_agents` as `<pluginId>__<tool>` (dots in the id as `_`, the tool-name shape Anthropic and OpenAI accept) for the session roles they list (orchestrator, agent, subagent; Claude Code, Codex, Qwen Code, OpenCode); calls carry the caller's session id, and answers are masked, capped at 32 K characters and 15 s. A service can subscribe to card events (`sessions:events`: created, restored, status, exited, closed, with folders and the environment ref; the end of the output only with `sessions:read-screen`, masked), start cards through the normal launch pipeline (`sessions:launch`), and type into or close only the cards it started (`sessions:control`; ownership is saved with the card, so it survives a restore). With `cards:decorate` it sets plain-text badges on cards and adds actions to the card menu of matching cards (provider, environment kind, role); the answer shows as a toast on the card. Example: `examples/plugins/collect-demo` (**Show changes** on worktree cards and `collect-demo__diffstat` for orchestrators).
- Reworked "Windows after restart" into one "Agent sessions after restart" model: **Don't save**, **Reopen windows** (new conversations), or **Continue conversations** (the old "on" migrates here). Claude Code and OpenCode now resume their own conversation by the id their lifecycle hook reported, as Codex does (`claude --resume`, `opencode --session`); two cards of one CLI in one folder no longer continue the same conversation. Finished agents come back stopped with Restart / Continue instead of rerunning, the card options menu has **Don't restore this card**, and session records (v2, read-compatible with v1) keep no scrollback, prompts or secrets.
- Made the agent orchestration endpoint an explicit setting (Settings → Agents → "Agent orchestration endpoint", `agentControlEnabled`, off by default; `--agent-control` / `CANVASTTY_AGENT_CONTROL=1` still force it on for one launch) that starts and stops the endpoint at runtime, and added an **Orchestrator** role to the launch dialog next to the normal/YOLO profile: the session keeps the provider you opened the dialog for, gets `CANVASTTY_CONTROL_CONNECTION` and `CANVASTTY_CONTROL_CLI` in its environment so the bundled CLI works without setup, shows an "Orchestrator" badge, keeps its role across restore, and the dialog offers to enable the endpoint first when it is off instead of enabling anything silently. The endpoint's `create` now accepts every agent provider (`codex, claude, qwen, kimi, opencode, hermes, grok, omp, pi`) and reports `capabilities { result, menus }` per worker on `create` and `list`: both are `true` for Codex only; other providers' `screen` has no menu interaction, `choose`/`dismiss` fail with `NOT_SUPPORTED`, `send` relies on the idle status alone, and `result` completes as `no_result`.
Expand All @@ -28,7 +30,8 @@
- Added a HOME attention queue of sessions that need approval or have failed, derived only from session snapshots, always rendering its title row and an explicit empty state; clicking a row focuses that session. Failure details (trigger, popover, copy) were extracted into one shared implementation used by both the queue and the existing session rows.
- Added an attention ring on cards whose session needs approval or has failed, plus the “Notify when attention is needed” setting in Settings → General (on by default) that raises one OS notification on a genuine transition into needing approval or failing: repeated snapshots and already-seen restore-time failures stay silent, and a failure the user triggers by restarting also notifies. Toggling the setting persists.
- Cards now report whether they render live output: those in semantic summary mode (zoom below 0.5) stop receiving streamed output while their scrollback stays canonical and complete within the bounded history, and the missed output is replayed once when the card becomes visible again; if more output was produced while hidden than the bounded history holds, the oldest part of that stretch is gone and the replay says so instead of pretending the output is continuous.
- Limited WebGL to the focused terminal card: one context at a time, disposed when focus leaves, with a fallback to the DOM renderer when the context is lost. Palette and transparency rendering are unchanged.
- Terminal cards on screen draw with WebGL from a pool of 10 contexts (Chromium allows 16 per renderer process): the focused card first, then the cards covering the most screen, then the most recently used. Cards that leave the screen, zoom above 1× or go to summary mode give their context back, and changes from panning or zooming wait until the camera is still, so moving around does not rebuild contexts. Every other card keeps the DOM renderer, and a card whose context is lost falls back to it with its contents intact and stays there for a while. Palette and transparency rendering are unchanged.
- Panning the canvas with the wheel or trackpad now moves the already drawn scene on the compositor, as dragging it already did, instead of repainting every card on each frame; the scene is re-rasterized once the gesture stops.
- Added a self-update section in Settings → Updates with the honest states: idle, checking, update available with the version, downloading with the percent when known, ready to install, and unavailable for dev, offline, or error. Downloading and installing are explicit user actions, install-and-restart is offered only once the update is downloaded, and in development the row reports unavailable instead of throwing.
- Hardened the repository secret audit to ignore key prefixes embedded inside identifiers, so names such as `disk-…` or `task-…` no longer produce false positives while real keys still match.
- Added Cursor, MiniMax Code, Devin and Antigravity agents (PR #63).
Expand Down
Loading
Loading