toyon 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -23
- package/dist/CHANGELOG.md +60 -0
- package/dist/bridge.js +1 -1
- package/dist/cli.js +92 -3
- package/dist/daemon.js +11459 -10168
- package/dist/shell/assets/{Editor-1fCgxkUp.js → Editor-Dq4a0gFv.js} +181 -181
- package/dist/shell/assets/Editor-Dq4a0gFv.js.br +0 -0
- package/dist/shell/assets/Editor-Dq4a0gFv.js.gz +0 -0
- package/dist/shell/assets/XTerm-BfuBg96X.js +58 -0
- package/dist/shell/assets/XTerm-BfuBg96X.js.br +0 -0
- package/dist/shell/assets/XTerm-BfuBg96X.js.gz +0 -0
- package/dist/shell/assets/{cssMode-1LqDnQzX.js → cssMode-An1EUPnJ.js} +1 -1
- package/dist/shell/assets/cssMode-An1EUPnJ.js.br +0 -0
- package/dist/shell/assets/cssMode-An1EUPnJ.js.gz +0 -0
- package/dist/shell/assets/{freemarker2-BJFDEJKJ.js → freemarker2-PYOY2M7v.js} +1 -1
- package/dist/shell/assets/freemarker2-PYOY2M7v.js.br +0 -0
- package/dist/shell/assets/freemarker2-PYOY2M7v.js.gz +0 -0
- package/dist/shell/assets/{grammar-DVeERVO3.js → grammar-e2yQ-Xdq.js} +1 -1
- package/dist/shell/assets/grammar-e2yQ-Xdq.js.br +0 -0
- package/dist/shell/assets/grammar-e2yQ-Xdq.js.gz +0 -0
- package/dist/shell/assets/{handlebars-BGFLy2DH.js → handlebars-BtSTwhBl.js} +1 -1
- package/dist/shell/assets/handlebars-BtSTwhBl.js.br +0 -0
- package/dist/shell/assets/handlebars-BtSTwhBl.js.gz +0 -0
- package/dist/shell/assets/{html-CPJflvc5.js → html-lmman0qi.js} +1 -1
- package/dist/shell/assets/html-lmman0qi.js.br +0 -0
- package/dist/shell/assets/html-lmman0qi.js.gz +0 -0
- package/dist/shell/assets/{htmlMode-CjqzceBV.js → htmlMode-CYUUrmIv.js} +1 -1
- package/dist/shell/assets/htmlMode-CYUUrmIv.js.br +0 -0
- package/dist/shell/assets/htmlMode-CYUUrmIv.js.gz +0 -0
- package/dist/shell/assets/index-BDzHAr7c.css +1 -0
- package/dist/shell/assets/index-BDzHAr7c.css.br +0 -0
- package/dist/shell/assets/index-BDzHAr7c.css.gz +0 -0
- package/dist/shell/assets/index-o7SjsIYr.js +294 -0
- package/dist/shell/assets/index-o7SjsIYr.js.br +0 -0
- package/dist/shell/assets/index-o7SjsIYr.js.gz +0 -0
- package/dist/shell/assets/{javascript-B4CelO-C.js → javascript-CHVOacyY.js} +1 -1
- package/dist/shell/assets/{jsonMode-C2JxYuT6.js → jsonMode-WaLJvHyp.js} +1 -1
- package/dist/shell/assets/jsonMode-WaLJvHyp.js.br +0 -0
- package/dist/shell/assets/jsonMode-WaLJvHyp.js.gz +0 -0
- package/dist/shell/assets/{liquid-BfXRgBm_.js → liquid-Bhzd8TLd.js} +1 -1
- package/dist/shell/assets/liquid-Bhzd8TLd.js.br +0 -0
- package/dist/shell/assets/liquid-Bhzd8TLd.js.gz +0 -0
- package/dist/shell/assets/{lspLanguageFeatures-CAi6hRgs.js → lspLanguageFeatures-DS22S_fR.js} +2 -2
- package/dist/shell/assets/lspLanguageFeatures-DS22S_fR.js.br +0 -0
- package/dist/shell/assets/lspLanguageFeatures-DS22S_fR.js.gz +0 -0
- package/dist/shell/assets/{mdx-DeBYGdge.js → mdx-1x45Dt5R.js} +1 -1
- package/dist/shell/assets/mdx-1x45Dt5R.js.br +0 -0
- package/dist/shell/assets/mdx-1x45Dt5R.js.gz +0 -0
- package/dist/shell/assets/{python-CFhHKm43.js → python-B0fHYRyj.js} +1 -1
- package/dist/shell/assets/python-B0fHYRyj.js.br +0 -0
- package/dist/shell/assets/python-B0fHYRyj.js.gz +0 -0
- package/dist/shell/assets/{razor-C-gkU4Y9.js → razor-C48vGnF3.js} +1 -1
- package/dist/shell/assets/razor-C48vGnF3.js.br +0 -0
- package/dist/shell/assets/razor-C48vGnF3.js.gz +0 -0
- package/dist/shell/assets/toyon-mono-bold-u3Ky0k2u.woff2 +0 -0
- package/dist/shell/assets/toyon-mono-regular-BC3CdGld.woff2 +0 -0
- package/dist/shell/assets/{tsMode-8E7grKbo.js → tsMode-2SIN2sKE.js} +1 -1
- package/dist/shell/assets/tsMode-2SIN2sKE.js.br +0 -0
- package/dist/shell/assets/tsMode-2SIN2sKE.js.gz +0 -0
- package/dist/shell/assets/{xml-CBoTF2r1.js → xml-DPJN-pu8.js} +1 -1
- package/dist/shell/assets/xml-DPJN-pu8.js.br +0 -0
- package/dist/shell/assets/xml-DPJN-pu8.js.gz +0 -0
- package/dist/shell/assets/{yaml-CyKxhzxl.js → yaml-CDzmW7EM.js} +1 -1
- package/dist/shell/assets/yaml-CDzmW7EM.js.br +0 -0
- package/dist/shell/assets/yaml-CDzmW7EM.js.gz +0 -0
- package/dist/shell/index.html +2 -2
- package/package.json +1 -1
- package/dist/shell/assets/Editor-1fCgxkUp.js.br +0 -0
- package/dist/shell/assets/Editor-1fCgxkUp.js.gz +0 -0
- package/dist/shell/assets/XTerm-B_hkTWne.js +0 -58
- package/dist/shell/assets/XTerm-B_hkTWne.js.br +0 -0
- package/dist/shell/assets/XTerm-B_hkTWne.js.gz +0 -0
- package/dist/shell/assets/cssMode-1LqDnQzX.js.br +0 -0
- package/dist/shell/assets/cssMode-1LqDnQzX.js.gz +0 -0
- package/dist/shell/assets/freemarker2-BJFDEJKJ.js.br +0 -0
- package/dist/shell/assets/freemarker2-BJFDEJKJ.js.gz +0 -0
- package/dist/shell/assets/grammar-DVeERVO3.js.br +0 -0
- package/dist/shell/assets/grammar-DVeERVO3.js.gz +0 -0
- package/dist/shell/assets/handlebars-BGFLy2DH.js.br +0 -0
- package/dist/shell/assets/handlebars-BGFLy2DH.js.gz +0 -0
- package/dist/shell/assets/html-CPJflvc5.js.br +0 -0
- package/dist/shell/assets/html-CPJflvc5.js.gz +0 -0
- package/dist/shell/assets/htmlMode-CjqzceBV.js.br +0 -0
- package/dist/shell/assets/htmlMode-CjqzceBV.js.gz +0 -0
- package/dist/shell/assets/index-DdrVWdNt.js +0 -292
- package/dist/shell/assets/index-DdrVWdNt.js.br +0 -0
- package/dist/shell/assets/index-DdrVWdNt.js.gz +0 -0
- package/dist/shell/assets/index-Dx-i3szQ.css +0 -1
- package/dist/shell/assets/index-Dx-i3szQ.css.br +0 -0
- package/dist/shell/assets/index-Dx-i3szQ.css.gz +0 -0
- package/dist/shell/assets/jsonMode-C2JxYuT6.js.br +0 -0
- package/dist/shell/assets/jsonMode-C2JxYuT6.js.gz +0 -0
- package/dist/shell/assets/liquid-BfXRgBm_.js.br +0 -0
- package/dist/shell/assets/liquid-BfXRgBm_.js.gz +0 -0
- package/dist/shell/assets/lspLanguageFeatures-CAi6hRgs.js.br +0 -0
- package/dist/shell/assets/lspLanguageFeatures-CAi6hRgs.js.gz +0 -0
- package/dist/shell/assets/mdx-DeBYGdge.js.br +0 -0
- package/dist/shell/assets/mdx-DeBYGdge.js.gz +0 -0
- package/dist/shell/assets/python-CFhHKm43.js.br +0 -0
- package/dist/shell/assets/python-CFhHKm43.js.gz +0 -0
- package/dist/shell/assets/razor-C-gkU4Y9.js.br +0 -0
- package/dist/shell/assets/razor-C-gkU4Y9.js.gz +0 -0
- package/dist/shell/assets/tsMode-8E7grKbo.js.br +0 -0
- package/dist/shell/assets/tsMode-8E7grKbo.js.gz +0 -0
- package/dist/shell/assets/xml-CBoTF2r1.js.br +0 -0
- package/dist/shell/assets/xml-CBoTF2r1.js.gz +0 -0
- package/dist/shell/assets/yaml-CyKxhzxl.js.br +0 -0
- package/dist/shell/assets/yaml-CyKxhzxl.js.gz +0 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Toyon is where you ask for changes to your web app and try them as they happen.
|
|
|
4
4
|
|
|
5
5
|
Each copy runs on your own machine, and the next one is pre-warmed. Works with Claude Code, Codex and OpenCode over the Agent Client Protocol (ACP).
|
|
6
6
|
|
|
7
|
-
[toyon.dev](https://toyon.dev) · [How it works](#how-it-works) · [Install](#install) · [Under the hood](#under-the-hood) · [Trust](#trust) · [Uninstall](#uninstall)
|
|
7
|
+
[toyon.dev](https://toyon.dev) · [Docs](https://toyon.dev/docs/) · [How it works](#how-it-works) · [Install](#install) · [Under the hood](#under-the-hood) · [Trust](#trust) · [Uninstall](#uninstall) · [Changelog](https://github.com/toyon-dev/toyon/blob/main/CHANGELOG.md)
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
@@ -34,6 +34,8 @@ When your check passes, land merges into main on your machine by default, or pus
|
|
|
34
34
|
|
|
35
35
|
Built for web apps. A project without a page still works; the chat takes the middle instead of the preview.
|
|
36
36
|
|
|
37
|
+
How to use it is in [docs/using.md](https://github.com/toyon-dev/toyon/blob/main/docs/using.md). Every feature and shortcut is in [docs/features.md](https://github.com/toyon-dev/toyon/blob/main/docs/features.md).
|
|
38
|
+
|
|
37
39
|
## Install
|
|
38
40
|
|
|
39
41
|
Try it in a project:
|
|
@@ -50,7 +52,7 @@ npm i -g toyon
|
|
|
50
52
|
toyon ~/projects/app
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
`toyon .` opens the folder you are in and `toyon --help` lists the rest. The install button in the top bar makes Toyon an app of its own in Chrome, Arc, Brave or Edge, with a Dock icon and no browser bar; from then on `toyon .` opens that. A global install keeps itself updated; `TOYON_UPDATES=off` stops it. Started with npx, Toyon offers the global install above the chat box once it has answered you. Run outside a project, Toyon opens with none: describe a new one in a sentence, or give the project picker a git URL to clone. `toyon https://github.com/you/app` opens it with that repository ready to clone into the folder you are in; a link to a branch, a file or a pull request on GitHub, GitLab or Codeberg is read back to its repository.
|
|
55
|
+
`toyon .` opens the folder you are in and `toyon --help` lists the rest. The install button in the top bar makes Toyon an app of its own in Chrome, Arc, Brave or Edge, with a Dock icon and no browser bar; from then on `toyon .` opens that. A global install keeps itself updated; `TOYON_UPDATES=off` stops it. Started with npx, Toyon offers the global install above the chat box once it has answered you. Run outside a project, Toyon opens with none: describe a new one in a sentence, or give the project picker a git URL to clone. `toyon https://github.com/you/app` opens it with that repository ready to clone into the folder you are in; a link to a branch, a file or a pull request on GitHub, GitLab or Codeberg is read back to its repository. `toyon send "fix the flaky test"` from a terminal inside a project sends that message into Toyon the way the chat box would: a new worktree from the main checkout, a take-over of a worktree Toyon does not run, or the chat of one it does; an agent running in that terminal can run it too, and `--carry` moves main's uncommitted changes along.
|
|
54
56
|
|
|
55
57
|
You need:
|
|
56
58
|
|
|
@@ -59,7 +61,7 @@ You need:
|
|
|
59
61
|
- An account for the agent you pick: a Claude plan or an Anthropic API key for Claude Code, a ChatGPT plan or an OpenAI API key for Codex, or any provider OpenCode signs into.
|
|
60
62
|
- On Linux, bubblewrap and socat for the agents' sandbox (`sudo apt install bubblewrap socat`). `toyon doctor` checks both and prints the AppArmor profile Ubuntu 24.04 and later ask for.
|
|
61
63
|
|
|
62
|
-
Each agent signs in from the chat. Claude Code and Codex install on first start; OpenCode is a larger download with no subagents, effort levels or steering mid-turn. What each one reads and can do is in [docs/agents.md](https://github.com/toyon-dev/toyon/blob/main/docs/agents.md).
|
|
64
|
+
Each agent signs in from the chat. Claude Code and Codex install on first start; OpenCode is a larger download with no subagents, effort levels or steering mid-turn. What each one reads and can do is in [docs/agents.md](https://github.com/toyon-dev/toyon/blob/main/docs/agents.md). Requirements, updating and uninstalling are in [docs/install.md](https://github.com/toyon-dev/toyon/blob/main/docs/install.md), and every command is in [docs/commands.md](https://github.com/toyon-dev/toyon/blob/main/docs/commands.md).
|
|
63
65
|
|
|
64
66
|
## How is this different from what you use now?
|
|
65
67
|
|
|
@@ -72,7 +74,7 @@ Each agent signs in from the chat. Claude Code and Codex install on first start;
|
|
|
72
74
|
|
|
73
75
|
## Under the hood
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
A `.toyon/settings.json` in the project lists the setup commands, the commands to `run`, an optional `check` and how work lands. Toyon guesses it the first time you open a project. Each `run` command must stay in the foreground and listen on `$PORT`.
|
|
76
78
|
|
|
77
79
|
A project with a page and an API behind it:
|
|
78
80
|
|
|
@@ -81,46 +83,49 @@ A project with a page and an API behind it:
|
|
|
81
83
|
"setup": ["npm install"],
|
|
82
84
|
"run": {
|
|
83
85
|
"web": "vite --port $PORT --strictPort",
|
|
84
|
-
"api":
|
|
86
|
+
"api": "node --watch server/index.js"
|
|
85
87
|
},
|
|
86
88
|
"check": "npm test",
|
|
87
89
|
"land": { "route": "pr" }
|
|
88
90
|
}
|
|
89
91
|
```
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
- Backend commands run once, in the main checkout, and every chat shares them until a chat changes backend files.
|
|
94
|
+
- A chat's servers stop when it has not been opened for two hours. The chat and the agent keep running.
|
|
95
|
+
- `toyon doctor` reports what is running and why a page cannot connect.
|
|
92
96
|
|
|
93
|
-
|
|
97
|
+
Every setting is in [docs/settings.md](https://github.com/toyon-dev/toyon/blob/main/docs/settings.md). Sharing a backend and a database per chat are in [docs/backends.md](https://github.com/toyon-dev/toyon/blob/main/docs/backends.md).
|
|
94
98
|
|
|
95
99
|
## What it does not do
|
|
96
100
|
|
|
97
|
-
- It
|
|
98
|
-
-
|
|
99
|
-
- It
|
|
100
|
-
- It does not keep copies apart from services they share. Each copy runs your setup and your commands on its own, so a database or a compose stack they all point at is shared, migrations included. `TOYON_WORKTREE` in every command's environment lets a project give each copy its own (`app_$TOYON_WORKTREE` as the database name); [docs/settings.md](https://github.com/toyon-dev/toyon/blob/main/docs/settings.md#keeping-copies-apart) has the recipes.
|
|
101
|
-
- It does not carry a login between copies. Each preview has its own cookies, so a new chat's app starts signed out, and an OAuth provider cannot redirect into a preview at all.
|
|
101
|
+
- It does not push unless you land with a route that pushes. Agents are told not to push or delete branches.
|
|
102
|
+
- It does not give each chat its own database. A database or a compose stack that every chat connects to is shared, migrations included. [docs/backends.md](https://github.com/toyon-dev/toyon/blob/main/docs/backends.md#a-database-per-copy) has recipes for Postgres, Neon, Docker Compose and SQLite.
|
|
103
|
+
- It does not carry a login between chats. Each preview has its own cookies, so a new chat's app starts signed out, and an OAuth provider cannot redirect into a preview.
|
|
102
104
|
|
|
103
105
|
## Your own server
|
|
104
106
|
|
|
105
|
-
Toyon can also run on a box you open from your phone, or on your own Fly account with the laptop closed. This moves Toyon and its copies off your laptop; it does not publish your app.
|
|
107
|
+
Toyon can also run on a box you open from your phone, or on your own Fly account with the laptop closed. This moves Toyon and its copies off your laptop; it does not publish your app. There is no hosted Toyon service, and your code and keys are never sent to Toyon. `toyon remote` puts a box on your own domain behind Caddy or on your Tailscale tailnet, `toyon deploy fly up` builds a machine on your Fly account and prints the link, and the Dockerfile in the package runs on any host with a disk and a port range. A Fly machine measured about $4-6 a month in ordinary use, plus whatever your agents spend, and its first chat can sign in with your Claude plan. A phone or a second machine pairs by opening the address and being let in from Toyon's window.
|
|
106
108
|
|
|
107
|
-
These routes are new. How to set each one up, and what it has been checked with, is in [docs/remote.md](https://github.com/toyon-dev/toyon/blob/main/docs/remote.md).
|
|
109
|
+
These routes are new. How to set each one up, and what it has been checked with, is in [docs/remote.md](https://github.com/toyon-dev/toyon/blob/main/docs/remote.md). Pairing a phone is in [docs/phone.md](https://github.com/toyon-dev/toyon/blob/main/docs/phone.md).
|
|
108
110
|
|
|
109
111
|
## Disk
|
|
110
112
|
|
|
111
|
-
Each copy is a
|
|
113
|
+
Each chat's copy is a git worktree under `~/.toyon/worktrees.noindex`. On APFS, btrfs and XFS it is cloned copy-on-write, so it takes seconds and almost no space. On ext4 each one is a full copy, `node_modules` included. See [docs/using.md](https://github.com/toyon-dev/toyon/blob/main/docs/using.md#disk).
|
|
112
114
|
|
|
113
115
|
## Trust
|
|
114
116
|
|
|
115
|
-
|
|
117
|
+
Agents run in an OS sandbox, Seatbelt on macOS and bubblewrap on Linux, and can write only inside their copy of the project. Toyon listens on loopback only, and every request carries a per-machine token.
|
|
116
118
|
|
|
117
|
-
|
|
119
|
+
Known gaps:
|
|
118
120
|
|
|
119
|
-
|
|
121
|
+
- `git push` is blocked by a command filter for Claude Code and OpenCode, and is not blocked for Codex. If your git credentials are on the machine, an agent could still find a way to push.
|
|
122
|
+
- Codex's shell commands can read Toyon's token.
|
|
123
|
+
- MCP servers run outside the sandbox.
|
|
124
|
+
- Opening a repository runs its setup commands, its dev server and its agent configuration. Open only repositories you trust.
|
|
120
125
|
|
|
121
|
-
|
|
126
|
+
Each chat has a permission mode: auto, ask or plan. On a company machine, IT can turn features off with a policy file.
|
|
122
127
|
|
|
123
|
-
|
|
128
|
+
The details are in [docs/trust.md](https://github.com/toyon-dev/toyon/blob/main/docs/trust.md) and [docs/policy.md](https://github.com/toyon-dev/toyon/blob/main/docs/policy.md).
|
|
124
129
|
|
|
125
130
|
## Uninstall
|
|
126
131
|
|
|
@@ -129,15 +134,15 @@ toyon uninstall
|
|
|
129
134
|
npm uninstall -g toyon
|
|
130
135
|
```
|
|
131
136
|
|
|
132
|
-
|
|
137
|
+
`toyon uninstall` asks before it removes anything, and keeps your projects and your `toyon/` branches. Delete a Fly machine first, with `toyon deploy fly destroy <name>`. See [docs/commands.md](https://github.com/toyon-dev/toyon/blob/main/docs/commands.md#toyon-uninstall).
|
|
133
138
|
|
|
134
139
|
## Telemetry
|
|
135
140
|
|
|
136
|
-
|
|
141
|
+
Toyon sends no telemetry. It checks for updates every six hours. To disable it, use `TOYON_UPDATES=off`. Every request Toyon makes is listed in [docs/trust.md](https://github.com/toyon-dev/toyon/blob/main/docs/trust.md#telemetry).
|
|
137
142
|
|
|
138
143
|
## Help build it
|
|
139
144
|
|
|
140
|
-
Toyon is early, and there is more worth doing than there are hands. The most useful thing right now is an issue: what you ran, what broke, and what your project is built with, especially anything that is not a Node app. Pull requests are welcome too; [CONTRIBUTING.md](https://github.com/toyon-dev/toyon/blob/main/CONTRIBUTING.md) has the setup
|
|
145
|
+
Toyon is early, and there is more worth doing than there are hands. The most useful thing right now is an issue: what you ran, what broke, and what your project is built with, especially anything that is not a Node app. Pull requests are welcome too; [CONTRIBUTING.md](https://github.com/toyon-dev/toyon/blob/main/CONTRIBUTING.md) has the setup. Run `bun run check` before you open one.
|
|
141
146
|
|
|
142
147
|
## License
|
|
143
148
|
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
What changed in each release of Toyon, newest first.
|
|
4
4
|
|
|
5
|
+
## 0.24.0 (2026-11-12)
|
|
6
|
+
|
|
7
|
+
Changed markdown files open as a rendered diff, landing no longer drops work, and the daemon and the shell close several holes around tokens and links.
|
|
8
|
+
|
|
9
|
+
### New
|
|
10
|
+
- A changed markdown file opens as a rendered diff that marks which words, table cells and list items came and went. It follows the code diff's inline or split choice, and the editor head has one file, inline and split control in place of the separate markdown knobs.
|
|
11
|
+
- Once you open a changes row rendered, the next file you arrow or click to opens rendered too; a file that cannot render opens on its diff, and picking diff or file by hand ends the hold. Rows whose file can render show an eye on hover, and a second click on a previewed row takes it back to the diff.
|
|
12
|
+
- Back and forward step onto archived pages, switching project first when the archive belongs to another.
|
|
13
|
+
- Code blocks in chat keep their copy button visible on a touch screen, where there is no hover to reveal it.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Landing writes the commit message at press time. When the box is empty the quick model writes it under a "writing the message" step, and the land goes on without running the check again; with no answer the land is refused and nothing is committed.
|
|
17
|
+
- A land, commit, sync or PR press moves the row to the top of the rail as the work starts, whatever the outcome, instead of when it finishes. Automatic runs still move nothing.
|
|
18
|
+
- The handoff card opens its list page on arrival on the active worktree, except on a phone. Typing a letter or pressing n opens the note under "not now", a slide opens it on touch, and words sent with "not now" reach the worktree's agent once its turn ends.
|
|
19
|
+
- Panel chords such as cmd+L, cmd+J and cmd+B leave zen when a file fills the page and land in the panel asked for. Quick open keeps zen, and Esc on a file closes the file and leaves zen on the page.
|
|
20
|
+
- Toyon Mono was rebuilt three times: a slashed zero inside the ring, a wider asterisk, a thinner underscore, a new question mark hook, resized colon dots and new braces and j. Wrap and full-size are icon switches in the editor head, so a file name fits in a narrow pane.
|
|
21
|
+
- Links that are not routed go through one guard in the card band, PR comments and paste chips. Rendered documents drop styles, form controls and foreign classes, and every link that opens outside Toyon opens with noopener and noreferrer.
|
|
22
|
+
- The daemon refuses a let-me-in knock that arrives from its own preview, process or forwarder ports, another .localhost name or a preview under the public name; file routes carry a sandbox content security policy, and a short token file is regenerated.
|
|
23
|
+
- A read row that repeats keeps its shine through the gap between reads, as an edit row does. A kbd tag in a markdown preview draws as a boxed key, and a heading made only of a code span reads as a heading.
|
|
24
|
+
- The docs gained features, shortcuts, commands, using, backends and phone pages, and the remote, settings, agents, trust and policy pages were rewritten in shorter sentences.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- Landing or archiving a worktree could silently discard committed or unpushed work, or leave main half-merged. The leftover check now compares commits by content, so a rebased copy after a sync does not count as new work, and the push asks origin where the branch stands first: a plain push, a leased forced push over your own earlier tip, or a refusal that says why.
|
|
28
|
+
- A file with an accented or quoted name, such as café.txt, made the changes panel throw. Paths are read from git without quoting now, and git messages stay in English whatever the system language.
|
|
29
|
+
- Once Toyon Mono loaded, every mono line reflowed, because the stand-in faces had a different letter height. The fallbacks are now faces with the same cell, so nothing moves when the font arrives.
|
|
30
|
+
- A restart no longer kills an agent that is still starting, and a crashed adapter keeps its own exit text.
|
|
31
|
+
- Slow sideways trackpad scrolls in the editor were dropped once the gesture had settled as vertical; the turn is judged on travel summed over the gesture.
|
|
32
|
+
- Monaco's right-click menu, sticky scroll and inlay hint menus overlapped the files dock without a background. They are drawn as the shell's own menu in the top layer.
|
|
33
|
+
- @ offers the project's other worktrees on an archived or found chat, where before the mention went to the agent as plain text.
|
|
34
|
+
- A pull request merged while the row was open was recorded once, not again when the poll heard of it, and the comments row no longer runs "1 comment" into "on PR".
|
|
35
|
+
- Committing on a large repository no longer rebuilds the file tree, the folder list and the mention index when no paths changed, which blocked the page for about a fifth of a second on a 150k file repository.
|
|
36
|
+
|
|
37
|
+
## 0.23.0 (2026-11-10)
|
|
38
|
+
|
|
39
|
+
The shell reads in Toyon Mono, a face of its own, and a worktree reaches main's servers by default instead of starting every command again.
|
|
40
|
+
|
|
41
|
+
### New
|
|
42
|
+
- Code, the terminal, the editor and every other mono line read in Toyon Mono, a monospaced face drawn for Toyon and shipped with the shell, so the same letters show on every machine. The face is new and still being tuned; a letter that reads wrong is worth an issue.
|
|
43
|
+
- Main runs each command once, on its own working tree, and every worktree's page reaches it at its usual address. A worktree whose changes touch a command's files starts its own and the address quietly points there; one that only changes the page never pays for a server of its own. The page itself is never shared.
|
|
44
|
+
- When a command flips to a worktree, a card in the chat names the command and the file that caused it and offers the other places it could run: main's, or a remote named in settings. The chip under the composer follows the choice. A command moved back to main's by hand stays there until a further file under it changes, and it shows as preparing while its setup runs.
|
|
45
|
+
- `toyon send "fix the flaky test"` from a terminal inside a project sends that message into Toyon the way the chat box would: a new worktree from main, a take-over of a worktree Toyon does not run, or the chat of one it does. `--carry` brings main's uncommitted changes along, and an agent running in that terminal can run it too.
|
|
46
|
+
- A handoff row opens the plan page it came from: the eye control and the row menu offer open preview, open file, reveal and copy path.
|
|
47
|
+
- On a touch screen, a long press on plain transcript text selects it as the browser would. The message menu still opens on a link or a code block.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
- `"paths": []` in settings is refused; write `"from": "trunk"` alone, which means the same thing: main runs the command and no file change flips it.
|
|
51
|
+
- The handoff going row lists each worktree by name as it is made, with its live dot once it exists, as the done row does. Handoff and worktrees tool rows read as a sentence, the piece titles or "the open ones and the newest archived", instead of a bare tool name.
|
|
52
|
+
- Asking the agent to split off, spin off or break out part of the work, or to put it in its own worktree, starts a handoff.
|
|
53
|
+
- Chat search ranks a hit that starts a word above one inside a longer word, so "rips" no longer sits level with "trips" and "strips", and the highlighted mark lands on the standalone word.
|
|
54
|
+
- opt+left and opt+right step the panel tabs when the focused field is empty, as cmd+left and cmd+right do. A field with text keeps the word jump.
|
|
55
|
+
- Under a picked option in your answer bubble, the option's description reads a step below the label and sits before the note you typed.
|
|
56
|
+
- Skill rows have a slash icon of their own, and a web search row wears the globe from the start instead of swapping to it once the call arrives.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- The PR button offered create pr on a worktree whose branch already had a pull request. Toyon now finds the PR on GitHub when a turn settles and when the window returns; a merged one is taken only when its commits are in the worktree's own history, so a reused branch name cannot pull in a stranger's.
|
|
60
|
+
- A landed worktree with a merged PR and uncommitted changes still said land in the composer, the rail menu and the changes tab.
|
|
61
|
+
- The shine on a long running command's line was sized to the whole hidden command and flashed the entire visible line. It is now one glint of one width travelling at one speed.
|
|
62
|
+
- Restoring an old worktree whose settings differed from main's crashed. Each worktree now reads its own settings file, and a config reload restarts only the rows whose command changed.
|
|
63
|
+
- A row held open for a background command or a booked wakeup now keeps the machine awake and the worktree out of sleep, as a running turn does.
|
|
64
|
+
|
|
5
65
|
## 0.22.0 (2026-11-03)
|
|
6
66
|
|
|
7
67
|
Your own messages and the agent's replies read the same way, with code, links and line breaks drawn as written, and the editor gains a split diff and an SVG preview.
|
package/dist/bridge.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var v=[{id:"quick-open",key:"p"},{id:"commands",key:"p",shift:!0,bareAlias:"F1"},{id:"search",key:"f",shift:!0},{id:"chats",key:"g"},{id:"changes",key:"b",ctrlAlias:{key:"g",shift:!0}},{id:"files",key:"e",shift:!0},{id:"panel-tab-prev",key:"ArrowLeft",alt:!0,textKeeps:!0},{id:"panel-tab-next",key:"ArrowRight",alt:!0,textKeeps:!0},{id:"composer",key:"l"},{id:"rail",key:"k",shift:!0},{id:"keys",key:","},{id:"terminal",key:"j",ctrlAlias:{key:"`"}},{id:"design",key:"d"},{id:"term-tab",key:"`",ctrl:!0,shift:!0},{id:"pick",key:"e"},{id:"inspect",key:"i"},{id:"zen",key:"."},{id:"new",key:"k",aliases:["n"]},{id:"worktree",key:"1-9"},{id:"wt-prev",key:"ArrowUp",alt:!0,ctrlAlias:{key:"Tab",shift:!0},cmdShiftAlias:["[","{"]},{id:"wt-next",key:"ArrowDown",alt:!0,ctrlAlias:{key:"Tab"},cmdShiftAlias:["]","}"]},{id:"wt-unseen-prev",key:"ArrowUp",alt:!0,shift:!0},{id:"wt-unseen-next",key:"ArrowDown",alt:!0,shift:!0},{id:"wt-back",key:"ArrowLeft",textKeeps:!0,emptyGives:!0},{id:"wt-forward",key:"ArrowRight",textKeeps:!0,emptyGives:!0},{id:"wt-archive",key:"Backspace",alt:!0,textKeeps:!0,emptyGives:!0},{id:"mark-unread",key:"u",alt:!0,textKeeps:!0},{id:"project",key:"o",ctrlAlias:{key:"r",hostOnly:!0},cmdShiftAlias:["o"]},{id:"refs",key:"g",shift:!0},{id:"routes",key:"u"},{id:"reload",key:"r"},{id:"back",key:"["},{id:"forward",key:"]"},{id:"close",key:"w"}],U=new Set(["zen","close","back","forward","wt-back","wt-forward"]);function q(e,{guest:t=!1}={}){if(e.altKey){if(e.metaKey||e.ctrlKey)return null;let r=v.find((o)=>o.alt&&!!o.shift===e.shiftKey&&(o.key===e.key||o.key.length===1&&e.code===`Key${o.key.toUpperCase()}`));return r&&r.id!=="worktree"?{id:r.id}:null}if(!e.metaKey&&!e.ctrlKey){if(e.shiftKey||t)return null;let r=v.find((o)=>o.bareAlias===e.key);return r&&r.id!=="worktree"?{id:r.id}:null}if(!!e.ctrlKey===e.metaKey)return null;let n=e.key.length===1?e.key.toLowerCase():e.key;if(e.metaKey&&!e.shiftKey&&n>="1"&&n<="9")return{id:"worktree",digit:Number(n)};for(let r of v){if(r.id==="worktree")continue;let o=r.ctrlAlias;if(o&&e.ctrlKey&&o.key===n&&!!o.shift===e.shiftKey&&!(t&&o.hostOnly))return{id:r.id};if(e.metaKey&&e.shiftKey&&r.cmdShiftAlias?.includes(n))return{id:r.id};if(r.alt)continue;if(e.ctrlKey&&!r.ctrl||!!r.shift!==e.shiftKey)continue;if(r.key===n||r.aliases?.includes(n))return{id:r.id}}return null}function Y(e){if(e.altKey||e.key.toLowerCase()!=="s")return!1;return!!e.ctrlKey!==e.metaKey}function Z(e){let t=v.find((n)=>n.id===e);if(!t)throw Error(`unknown chord ${e}`);return t}function V(e){let t=e;if(!t?.tagName)return!1;if(t.isContentEditable||t.tagName==="TEXTAREA")return!0;return t.tagName==="INPUT"&&!["button","checkbox","radio","range","submit","reset"].includes(t.type??"")}var se=Symbol.for("react.forward_ref"),ce=Symbol.for("react.memo");function J(e){if(e._debugSource?.fileName)return{file:e._debugSource.fileName,line:e._debugSource.lineNumber};let t=e._debugStack?.stack;if(t){let n=t.match(/https?:\/\/[^/]+(\/src\/[^)\s?]+)(?:\?[^:)\s]*)?:(\d+):\d+/);if(n?.[1])return{file:n[1],line:Number(n[2])||void 0}}return null}function _(e){for(let t=e;t;t=t.return){let n=J(t);if(n)return n}return null}function L(e){if(typeof e==="function")return e.displayName||e.name||null;let t=e;if(t?.$$typeof===se)return t.displayName||L(t.render);if(t?.$$typeof===ce)return t.displayName||L(t.type);return null}var ue=(e)=>typeof e.type==="string"||e.tag===6,de=(e,t)=>!!e&&(e===t||!!e.stateNode&&e.stateNode===t.stateNode);function fe(e){let t=null,n=(r)=>{for(let o=r.child??null;o;o=o.sibling??null)if(ue(o)){if(t)return!1;t=o}else if(!n(o))return!1;return!0};return n(e)?t:null}function pe(e){for(let t=e;t;t=t.return){let n=J(t);if(n)return t._debugOwner===null?null:n}return null}function N(e){let t=_(e),n=null,r=null,o=!1;for(let i=e;i;i=i.return){let a=L(i.type);if(!a)continue;let l=!!e&&de(fe(i),e),c=pe(i);if(n&&!(l&&c))break;if(n=a,r=c,o=l,!l)break}if(r&&t&&r.file===t.file&&r.line===t.line)r=null;return{src:t,comp:n,call:r,wraps:o}}function F({src:e,call:t,wraps:n},r){let o=n?t:e,i=n?e:t;return(r?i??o:o??i)??null}if(window.__toyonBridge)throw Error("Toyon bridge already installed");window.__toyonBridge=!0;var E=window.__toyonShellOrigins??[],R=null,s=(e)=>{try{let t=R?[R]:E.length?E:["*"];for(let n of t)window.parent.postMessage({__toyon:!0,...e},n)}catch{}};s({type:"loaded",url:location.href,title:document.title});var x="#fa891e",ee="#1d2021";window.addEventListener("vite:afterUpdate",()=>s({type:"hmr"}));window.addEventListener("error",(e)=>{s({type:"page-error",message:String(e.message),source:e.filename,line:e.lineno})});window.addEventListener("unhandledrejection",(e)=>{s({type:"page-error",message:`unhandled rejection: ${String(e.reason)}`})});var C=()=>s({type:"navigated",url:location.href,title:document.title}),he=history.pushState.bind(history);history.pushState=(...e)=>{he(...e),H(),C()};var ye=history.replaceState.bind(history);history.replaceState=(...e)=>{ye(...e),C()};window.addEventListener("popstate",C);window.addEventListener("hashchange",C);var me=window.navigation,g=null;function H(){g=me?.currentEntry?.index??null}H();window.addEventListener("popstate",()=>{let e=g;H();let t=e===null||g===null||e===g?void 0:g<e?"back":"forward";s({type:"traversed",...t?{dir:t}:{}})});var ge=performance.getEntriesByType("navigation")[0];if(ge?.type==="back_forward")s({type:"traversed"});window.addEventListener("pageshow",(e)=>{if(e.persisted)s({type:"traversed"})});var M=document.title;if(document.head)new MutationObserver(()=>{if(document.title===M)return;M=document.title,s({type:"title",title:M})}).observe(document.head,{childList:!0,subtree:!0,characterData:!0});var te=!1,B=null;window.addEventListener("keyup",(e)=>{if(window.__toyonShell||e.key!==B)return;B=null,s({type:"key",key:e.key,meta:!1,up:!0})},!0);window.addEventListener("keydown",(e)=>{if(window.__toyonShell)return;if(Y(e))e.preventDefault();let t=q(e,{guest:!0});if(t&&Z(t.id).textKeeps&&V(e.target))return;if(te){if(!t||!U.has(t.id))return}else if(e.key==="Escape"){s({type:"key",key:"Escape",meta:!1});return}else if(!t)return;e.preventDefault(),e.stopPropagation(),s({type:"key",key:e.key,code:e.code,meta:e.metaKey,ctrl:e.ctrlKey,shift:e.shiftKey,alt:e.altKey}),B=e.altKey?"Alt":e.ctrlKey?"Control":e.metaKey?"Meta":null},!0);var I=()=>s({type:"focus",gesture:navigator.userActivation?.isActive??!0});window.addEventListener("focusin",I,!0);window.addEventListener("focus",I);if(document.hasFocus()&&document.activeElement&&document.activeElement!==document.body)I();var W=(e)=>!e.defaultPrevented&&!!e.dataTransfer?.types.includes("Files");window.addEventListener("dragover",(e)=>{if(!W(e))return;if(e.preventDefault(),e.dataTransfer)e.dataTransfer.dropEffect="copy";s({type:"drag-files",over:!0})});window.addEventListener("dragleave",(e)=>{if(W(e))s({type:"drag-files",over:!1})});window.addEventListener("drop",(e)=>{if(!W(e))return;e.preventDefault(),s({type:"drop-files",files:Array.from(e.dataTransfer?.files??[])})});function G(e){for(let t of Object.keys(e))if(t.startsWith("__reactFiber$"))return e[t]??null;return null}var u=null,D=typeof HTMLElement<"u"&&"showPopover"in HTMLElement.prototype;function ke(){if(!u?.isConnected){if(u=document.createElement("div"),u.style.cssText="position:fixed;inset:0;width:auto;height:auto;max-width:none;max-height:none;margin:0;padding:0;border:0;background:transparent;overflow:visible;pointer-events:none;z-index:2147483647;",D)u.popover="manual";document.documentElement.appendChild(u)}if(D&&!u.matches(":popover-open"))u.showPopover();return u}function m(){if(!u)return;if(u.innerHTML="",D&&u.matches(":popover-open"))u.hidePopover()}var O=20;function S(e,t,n=!0){let r=document.createElement("div");if(r.style.cssText=`position:fixed;left:${e.left}px;top:${e.top}px;width:${e.width}px;height:${e.height}px;outline:2px solid ${x};outline-offset:-1px;${n?`background:${x}14;`:""}border-radius:2px;`,t){let o=e.top>=O,i=e.bottom+O<=window.innerHeight;if(t.style.top=o?`${-O}px`:i?`${e.height+4}px`:"2px",!o&&!i)t.style.left="2px";r.appendChild(t)}if(ke().appendChild(r),t){let o=t.getBoundingClientRect(),i=o.right-(window.innerWidth-2);if(i>0){let a=Number.parseFloat(t.style.left||"0");t.style.left=`${a-Math.min(i,Math.max(0,o.left-2))}px`}}}function k(e,t){let n=document.createElement("div");if(n.textContent=e,n.style.cssText=`position:absolute;left:0;background:${x};color:${ee};font:11px -apple-system,sans-serif;padding:1px 6px;border-radius:3px;white-space:nowrap;`,t){let r=document.createElement("span");r.textContent=` ${t}`,r.style.opacity="0.55",n.appendChild(r)}return n}var A=!1,f=null,h=!1,p=!1,y=!1,P=(e)=>`${oe(e.file)}${e.line?`:${e.line}`:""}`;function K(e){f=e,m();let t=N(G(e)),{src:n,comp:r,call:o}=t,i=F(t,p),a=i===n?o:n,l=h!==y,c=(...b)=>b.filter(Boolean).join(" ")||void 0,d=l?i?k(`open ${P(i)}`,c(a&&`⇧ ${P(a)}`,y&&"⌥ chat")):k(`find ${Q(e)}`,c(y&&"⌥ chat")):k(r?`<${r} />${i?` · ${P(i)}`:""}`:Q(e),c(!y&&"⌥ code"));S(e.getBoundingClientRect(),d,l)}function Q(e){let t=e.tagName.toLowerCase(),n=e.classList[0];return(e.id?`${t}#${e.id}`:n?`${t}.${n}`:t).slice(0,48)}var we=new Set(["name","placeholder","aria-label","title","alt","for","href","type","role","src"]);function be(e){let t="";for(let r of Array.from(e.childNodes))if(r.nodeType===Node.TEXT_NODE)t+=r.textContent??"";let n=[];for(let r of Array.from(e.attributes)){if(n.length===12)break;if(r.value&&(we.has(r.name)||r.name.startsWith("data-")))n.push([r.name.slice(0,40),r.value.slice(0,200)])}return{tag:e.tagName.toLowerCase().slice(0,40),id:e.id.slice(0,200),classes:Array.from(e.classList).slice(0,16).map((r)=>r.slice(0,120)),text:t.replace(/\s+/g," ").trim().slice(0,200),attrs:n}}function ne(e){let t=document.elementFromPoint(e.clientX,e.clientY);if(!t)return;let n=t!==f||e.altKey!==h||e.shiftKey!==p;if(h=e.altKey,p=e.shiftKey,n)K(t)}function re(e){e.preventDefault(),e.stopPropagation();let t=f??document.elementFromPoint(e.clientX,e.clientY),n=N(t?G(t):null),{src:r,comp:o,call:i}=n;p=e.shiftKey;let a=F(n,p),l=e.altKey!==y;if(X(),!t)return;s({type:"picked",verb:l?"code":"chat",site:a&&a===i?"call":"source",component:o,file:r?.file??null,line:r?.line??null,callFile:i?.file??null,callLine:i?.line??null,selector:Ee(t),tag:t.tagName.toLowerCase(),classes:t.className?.toString?.().slice(0,200)??"",text:t.textContent?.trim().slice(0,120)??"",html:t.outerHTML.slice(0,600),route:location.pathname+location.search,element:be(t)})}function T(e){if(e.key==="Escape"&&e.type==="keydown"){e.preventDefault(),e.stopPropagation(),X(),s({type:"pick-cancel"});return}if((e.key==="Alt"||e.key==="Shift")&&(h!==e.altKey||p!==e.shiftKey)){if(h=e.altKey,p=e.shiftKey,f)K(f)}}function ve(e){if(y=e,A){if(f)K(f);return}A=!0,f=null,h=!1,p=!1,document.addEventListener("mousemove",ne,!0),document.addEventListener("click",re,!0),document.addEventListener("keydown",T,!0),document.addEventListener("keyup",T,!0),document.documentElement.style.cursor="crosshair"}function X(){A=!1,y=!1,f=null,h=!1,p=!1,m(),document.removeEventListener("mousemove",ne,!0),document.removeEventListener("click",re,!0),document.removeEventListener("keydown",T,!0),document.removeEventListener("keyup",T,!0),document.documentElement.style.cursor=""}function Ee(e){let t=[],n=e;for(let r=0;n&&n!==document.documentElement&&r<6;r++){if(n.id){t.unshift(`#${CSS.escape(n.id)}`);break}let o=n.parentElement,i=o?Array.from(o.children).indexOf(n)+1:1;t.unshift(`${n.tagName.toLowerCase()}:nth-child(${i})`),n=o}return t.join(" > ")}function oe(e){let t=e.lastIndexOf("/src/");return t>=0?e.slice(t+1):e.split("/").slice(-2).join("/")}function xe(e,t){return e.endsWith(t)||t.endsWith(oe(e))}function Se(e,t){let n=[],r=0;for(let a of Array.from(document.querySelectorAll("*"))){let l=_(G(a));if(l)r++;if(!l||!xe(l.file,e))continue;n.push({el:a,line:l.line??-1})}if(!t||t.length===0)return{matched:n,fromFile:n,withSource:r};if(t.length===1&&t[0][0]===t[0][1]){let a=t[0][0],l=n.filter((d)=>d.line===a);if(l.length>0)return{matched:l,fromFile:n,withSource:r};let c=n.filter((d)=>d.line>0&&d.line<a);return c.sort((d,b)=>b.line-d.line),{matched:c.slice(0,1),fromFile:n,withSource:r}}return{matched:n.filter((a)=>t.some(([l,c])=>a.line>=l-8&&a.line<=c+1)),fromFile:n,withSource:r}}function Ae(e,t){m();let{matched:n,fromFile:r,withSource:o}=Se(e,t),i=0;for(let{el:a}of n){if(i>=40)break;let l=a.getBoundingClientRect();if(l.width>0&&l.height>0)S(l),i++}if(i===0)s({type:"highlight-miss",path:e,fileMatched:r.length,withSource:o,ranges:t})}var ie=!1,w=!1,Te=(e)=>{for(let t=e;t&&t!==document.documentElement;t=t.parentElement){let n=getComputedStyle(t),r=n.overflowX;if((r==="auto"||r==="scroll")&&t.scrollWidth>t.clientWidth+1)return!0;if(window.__toyonShell)continue;let o=n.touchAction;if(o!=="auto"&&o!=="manipulation"&&!o.includes("pan-x"))return!0}return!1},le=(e,t)=>{let n=e.touches[0]??e.changedTouches[0];if(n)s({type:"touch",phase:t,x:n.clientX,y:n.clientY})};window.addEventListener("touchstart",(e)=>{if(w=!1,!ie||e.touches.length!==1)return;let t=e.target instanceof Element?e.target:null;if(t?.closest("input, textarea, [contenteditable]")||Te(t))return;w=!0,le(e,"start")},{capture:!0,passive:!0});var j=(e,t)=>{if(!w)return;setTimeout(()=>{if(!w)return;let n=t==="move"&&(e.defaultPrevented||e.touches.length!==1);if(t!=="move"||n)w=!1;le(e,n?"cancel":t)},0)};window.addEventListener("touchmove",(e)=>j(e,"move"),{passive:!0});window.addEventListener("touchend",(e)=>j(e,"end"),!0);window.addEventListener("touchcancel",(e)=>j(e,"cancel"),!0);window.addEventListener("message",(e)=>{if(e.source!==window.parent)return;if(E.length&&!E.includes(e.origin))return;let t=e.data;if(!t?.__toyon)return;R=e.origin;let n=t;switch(n.type){case"reload":location.reload();break;case"navigate":if(/^[/?#]/.test(n.path))location.assign(n.path);break;case"back":case"forward":{let r=window.navigation;if((n.type==="back"?r?.canGoBack:r?.canGoForward)===!1)break;if(n.type==="back")history.back();else history.forward();break}case"touches":ie=n.on;break;case"links":{let r=new Set,o=[];for(let i of Array.from(document.querySelectorAll("a[href]"))){if(i.origin!==location.origin||i.target==="_blank"||i.hasAttribute("download"))continue;let a=i.pathname+(i.hash.startsWith("#/")?i.hash:"");if(a.startsWith("/__toyon")||r.has(a))continue;r.add(a);let l=(i.textContent||i.getAttribute("aria-label")||"").replace(/\s+/g," ").trim();if(o.push({path:a,text:l.slice(0,80)}),o.length>=200)break}s({type:"links",links:o});break}case"pick-start":ve(n.verb==="code");break;case"pick-mods":if(A&&(h!==n.alt||p!==n.shift)){if(h=n.alt,p=n.shift,f)K(f)}break;case"pick-cancel":X();break;case"highlight-file":Ae(n.path,n.ranges??null);break;case"highlight-computed":{m();let r=/^(color|font|line-height|letter-|text-|word-)/,o=(l)=>{if(/^(INPUT|TEXTAREA|SELECT)$/.test(l.tagName))return!0;for(let c=l.firstChild;c;c=c.nextSibling)if(c.nodeType===3&&c.textContent&&c.textContent.trim())return!0;return!1},i=document.querySelectorAll("*"),a=!0;for(let l=0;l<i.length;l++){let c=getComputedStyle(i[l]),d=([z,ae])=>c.getPropertyValue(z)===ae&&(!r.test(z)||o(i[l]));if(n.match==="any"?n.props.some(d):n.props.every(d))S(i[l].getBoundingClientRect(),a&&n.label?k(n.label):void 0),a=!1}break}case"highlight-selector":{m();try{let r=document.querySelectorAll(n.selector);for(let o=0;o<r.length;o++)S(r[o].getBoundingClientRect(),o===0&&n.label?k(n.label):void 0)}catch{}break}case"highlight-clear":m();break;case"zen":te=n.on;break;case"theme":if(/^#[0-9a-f]{3,8}$/i.test(n.accent))x=n.accent;if(/^#[0-9a-f]{3,8}$/i.test(n.accentFg))ee=n.accentFg;break}});
|
|
1
|
+
var v=[{id:"quick-open",key:"p"},{id:"commands",key:"p",shift:!0,bareAlias:"F1"},{id:"search",key:"f",shift:!0},{id:"chats",key:"g"},{id:"changes",key:"b",ctrlAlias:{key:"g",shift:!0}},{id:"files",key:"e",shift:!0},{id:"panel-tab-prev",key:"ArrowLeft",alt:!0,textKeeps:!0,emptyGives:!0},{id:"panel-tab-next",key:"ArrowRight",alt:!0,textKeeps:!0,emptyGives:!0},{id:"composer",key:"l"},{id:"rail",key:"k",shift:!0},{id:"keys",key:","},{id:"terminal",key:"j",ctrlAlias:{key:"`"}},{id:"design",key:"d"},{id:"term-tab",key:"`",ctrl:!0,shift:!0},{id:"pick",key:"e"},{id:"inspect",key:"i"},{id:"zen",key:"."},{id:"new",key:"k",aliases:["n"]},{id:"worktree",key:"1-9"},{id:"wt-prev",key:"ArrowUp",alt:!0,ctrlAlias:{key:"Tab",shift:!0},cmdShiftAlias:["[","{"]},{id:"wt-next",key:"ArrowDown",alt:!0,ctrlAlias:{key:"Tab"},cmdShiftAlias:["]","}"]},{id:"wt-unseen-prev",key:"ArrowUp",alt:!0,shift:!0},{id:"wt-unseen-next",key:"ArrowDown",alt:!0,shift:!0},{id:"wt-back",key:"ArrowLeft",textKeeps:!0,emptyGives:!0},{id:"wt-forward",key:"ArrowRight",textKeeps:!0,emptyGives:!0},{id:"wt-archive",key:"Backspace",alt:!0,textKeeps:!0,emptyGives:!0},{id:"mark-unread",key:"u",alt:!0,textKeeps:!0},{id:"project",key:"o",ctrlAlias:{key:"r",hostOnly:!0},cmdShiftAlias:["o"]},{id:"refs",key:"g",shift:!0},{id:"routes",key:"u"},{id:"reload",key:"r"},{id:"back",key:"["},{id:"forward",key:"]"},{id:"close",key:"w"}],U=new Set(["zen","close","back","forward","wt-back","wt-forward"]);function q(e,{guest:t=!1}={}){if(e.altKey){if(e.metaKey||e.ctrlKey)return null;let r=v.find((o)=>o.alt&&!!o.shift===e.shiftKey&&(o.key===e.key||o.key.length===1&&e.code===`Key${o.key.toUpperCase()}`));return r&&r.id!=="worktree"?{id:r.id}:null}if(!e.metaKey&&!e.ctrlKey){if(e.shiftKey||t)return null;let r=v.find((o)=>o.bareAlias===e.key);return r&&r.id!=="worktree"?{id:r.id}:null}if(!!e.ctrlKey===e.metaKey)return null;let n=e.key.length===1?e.key.toLowerCase():e.key;if(e.metaKey&&!e.shiftKey&&n>="1"&&n<="9")return{id:"worktree",digit:Number(n)};for(let r of v){if(r.id==="worktree")continue;let o=r.ctrlAlias;if(o&&e.ctrlKey&&o.key===n&&!!o.shift===e.shiftKey&&!(t&&o.hostOnly))return{id:r.id};if(e.metaKey&&e.shiftKey&&r.cmdShiftAlias?.includes(n))return{id:r.id};if(r.alt)continue;if(e.ctrlKey&&!r.ctrl||!!r.shift!==e.shiftKey)continue;if(r.key===n||r.aliases?.includes(n))return{id:r.id}}return null}function Y(e){if(e.altKey||e.key.toLowerCase()!=="s")return!1;return!!e.ctrlKey!==e.metaKey}function Z(e){let t=v.find((n)=>n.id===e);if(!t)throw Error(`unknown chord ${e}`);return t}function V(e){let t=e;if(!t?.tagName)return!1;if(t.isContentEditable||t.tagName==="TEXTAREA")return!0;return t.tagName==="INPUT"&&!["button","checkbox","radio","range","submit","reset"].includes(t.type??"")}var se=Symbol.for("react.forward_ref"),ce=Symbol.for("react.memo");function J(e){if(e._debugSource?.fileName)return{file:e._debugSource.fileName,line:e._debugSource.lineNumber};let t=e._debugStack?.stack;if(t){let n=t.match(/https?:\/\/[^/]+(\/src\/[^)\s?]+)(?:\?[^:)\s]*)?:(\d+):\d+/);if(n?.[1])return{file:n[1],line:Number(n[2])||void 0}}return null}function _(e){for(let t=e;t;t=t.return){let n=J(t);if(n)return n}return null}function L(e){if(typeof e==="function")return e.displayName||e.name||null;let t=e;if(t?.$$typeof===se)return t.displayName||L(t.render);if(t?.$$typeof===ce)return t.displayName||L(t.type);return null}var ue=(e)=>typeof e.type==="string"||e.tag===6,de=(e,t)=>!!e&&(e===t||!!e.stateNode&&e.stateNode===t.stateNode);function fe(e){let t=null,n=(r)=>{for(let o=r.child??null;o;o=o.sibling??null)if(ue(o)){if(t)return!1;t=o}else if(!n(o))return!1;return!0};return n(e)?t:null}function pe(e){for(let t=e;t;t=t.return){let n=J(t);if(n)return t._debugOwner===null?null:n}return null}function N(e){let t=_(e),n=null,r=null,o=!1;for(let i=e;i;i=i.return){let a=L(i.type);if(!a)continue;let l=!!e&&de(fe(i),e),c=pe(i);if(n&&!(l&&c))break;if(n=a,r=c,o=l,!l)break}if(r&&t&&r.file===t.file&&r.line===t.line)r=null;return{src:t,comp:n,call:r,wraps:o}}function F({src:e,call:t,wraps:n},r){let o=n?t:e,i=n?e:t;return(r?i??o:o??i)??null}if(window.__toyonBridge)throw Error("Toyon bridge already installed");window.__toyonBridge=!0;var E=window.__toyonShellOrigins??[],R=null,s=(e)=>{try{let t=R?[R]:E.length?E:["*"];for(let n of t)window.parent.postMessage({__toyon:!0,...e},n)}catch{}};s({type:"loaded",url:location.href,title:document.title});var x="#fa891e",ee="#1d2021";window.addEventListener("vite:afterUpdate",()=>s({type:"hmr"}));window.addEventListener("error",(e)=>{s({type:"page-error",message:String(e.message),source:e.filename,line:e.lineno})});window.addEventListener("unhandledrejection",(e)=>{s({type:"page-error",message:`unhandled rejection: ${String(e.reason)}`})});var C=()=>s({type:"navigated",url:location.href,title:document.title}),he=history.pushState.bind(history);history.pushState=(...e)=>{he(...e),H(),C()};var ye=history.replaceState.bind(history);history.replaceState=(...e)=>{ye(...e),C()};window.addEventListener("popstate",C);window.addEventListener("hashchange",C);var me=window.navigation,g=null;function H(){g=me?.currentEntry?.index??null}H();window.addEventListener("popstate",()=>{let e=g;H();let t=e===null||g===null||e===g?void 0:g<e?"back":"forward";s({type:"traversed",...t?{dir:t}:{}})});var ge=performance.getEntriesByType("navigation")[0];if(ge?.type==="back_forward")s({type:"traversed"});window.addEventListener("pageshow",(e)=>{if(e.persisted)s({type:"traversed"})});var M=document.title;if(document.head)new MutationObserver(()=>{if(document.title===M)return;M=document.title,s({type:"title",title:M})}).observe(document.head,{childList:!0,subtree:!0,characterData:!0});var te=!1,B=null;window.addEventListener("keyup",(e)=>{if(window.__toyonShell||e.key!==B)return;B=null,s({type:"key",key:e.key,meta:!1,up:!0})},!0);window.addEventListener("keydown",(e)=>{if(window.__toyonShell)return;if(Y(e))e.preventDefault();let t=q(e,{guest:!0});if(t&&Z(t.id).textKeeps&&V(e.target))return;if(te){if(!t||!U.has(t.id))return}else if(e.key==="Escape"){s({type:"key",key:"Escape",meta:!1});return}else if(!t)return;e.preventDefault(),e.stopPropagation(),s({type:"key",key:e.key,code:e.code,meta:e.metaKey,ctrl:e.ctrlKey,shift:e.shiftKey,alt:e.altKey}),B=e.altKey?"Alt":e.ctrlKey?"Control":e.metaKey?"Meta":null},!0);var I=()=>s({type:"focus",gesture:navigator.userActivation?.isActive??!0});window.addEventListener("focusin",I,!0);window.addEventListener("focus",I);if(document.hasFocus()&&document.activeElement&&document.activeElement!==document.body)I();var G=(e)=>!e.defaultPrevented&&!!e.dataTransfer?.types.includes("Files");window.addEventListener("dragover",(e)=>{if(!G(e))return;if(e.preventDefault(),e.dataTransfer)e.dataTransfer.dropEffect="copy";s({type:"drag-files",over:!0})});window.addEventListener("dragleave",(e)=>{if(G(e))s({type:"drag-files",over:!1})});window.addEventListener("drop",(e)=>{if(!G(e))return;e.preventDefault(),s({type:"drop-files",files:Array.from(e.dataTransfer?.files??[])})});function W(e){for(let t of Object.keys(e))if(t.startsWith("__reactFiber$"))return e[t]??null;return null}var u=null,D=typeof HTMLElement<"u"&&"showPopover"in HTMLElement.prototype;function ke(){if(!u?.isConnected){if(u=document.createElement("div"),u.style.cssText="position:fixed;inset:0;width:auto;height:auto;max-width:none;max-height:none;margin:0;padding:0;border:0;background:transparent;overflow:visible;pointer-events:none;z-index:2147483647;",D)u.popover="manual";document.documentElement.appendChild(u)}if(D&&!u.matches(":popover-open"))u.showPopover();return u}function m(){if(!u)return;if(u.innerHTML="",D&&u.matches(":popover-open"))u.hidePopover()}var O=20;function S(e,t,n=!0){let r=document.createElement("div");if(r.style.cssText=`position:fixed;left:${e.left}px;top:${e.top}px;width:${e.width}px;height:${e.height}px;outline:2px solid ${x};outline-offset:-1px;${n?`background:${x}14;`:""}border-radius:2px;`,t){let o=e.top>=O,i=e.bottom+O<=window.innerHeight;if(t.style.top=o?`${-O}px`:i?`${e.height+4}px`:"2px",!o&&!i)t.style.left="2px";r.appendChild(t)}if(ke().appendChild(r),t){let o=t.getBoundingClientRect(),i=o.right-(window.innerWidth-2);if(i>0){let a=Number.parseFloat(t.style.left||"0");t.style.left=`${a-Math.min(i,Math.max(0,o.left-2))}px`}}}function k(e,t){let n=document.createElement("div");if(n.textContent=e,n.style.cssText=`position:absolute;left:0;background:${x};color:${ee};font:11px -apple-system,sans-serif;padding:1px 6px;border-radius:3px;white-space:nowrap;`,t){let r=document.createElement("span");r.textContent=` ${t}`,r.style.opacity="0.55",n.appendChild(r)}return n}var A=!1,f=null,h=!1,p=!1,y=!1,P=(e)=>`${oe(e.file)}${e.line?`:${e.line}`:""}`;function K(e){f=e,m();let t=N(W(e)),{src:n,comp:r,call:o}=t,i=F(t,p),a=i===n?o:n,l=h!==y,c=(...b)=>b.filter(Boolean).join(" ")||void 0,d=l?i?k(`open ${P(i)}`,c(a&&`⇧ ${P(a)}`,y&&"⌥ chat")):k(`find ${Q(e)}`,c(y&&"⌥ chat")):k(r?`<${r} />${i?` · ${P(i)}`:""}`:Q(e),c(!y&&"⌥ code"));S(e.getBoundingClientRect(),d,l)}function Q(e){let t=e.tagName.toLowerCase(),n=e.classList[0];return(e.id?`${t}#${e.id}`:n?`${t}.${n}`:t).slice(0,48)}var we=new Set(["name","placeholder","aria-label","title","alt","for","href","type","role","src"]);function be(e){let t="";for(let r of Array.from(e.childNodes))if(r.nodeType===Node.TEXT_NODE)t+=r.textContent??"";let n=[];for(let r of Array.from(e.attributes)){if(n.length===12)break;if(r.value&&(we.has(r.name)||r.name.startsWith("data-")))n.push([r.name.slice(0,40),r.value.slice(0,200)])}return{tag:e.tagName.toLowerCase().slice(0,40),id:e.id.slice(0,200),classes:Array.from(e.classList).slice(0,16).map((r)=>r.slice(0,120)),text:t.replace(/\s+/g," ").trim().slice(0,200),attrs:n}}function ne(e){let t=document.elementFromPoint(e.clientX,e.clientY);if(!t)return;let n=t!==f||e.altKey!==h||e.shiftKey!==p;if(h=e.altKey,p=e.shiftKey,n)K(t)}function re(e){e.preventDefault(),e.stopPropagation();let t=f??document.elementFromPoint(e.clientX,e.clientY),n=N(t?W(t):null),{src:r,comp:o,call:i}=n;p=e.shiftKey;let a=F(n,p),l=e.altKey!==y;if(X(),!t)return;s({type:"picked",verb:l?"code":"chat",site:a&&a===i?"call":"source",component:o,file:r?.file??null,line:r?.line??null,callFile:i?.file??null,callLine:i?.line??null,selector:Ee(t),tag:t.tagName.toLowerCase(),classes:t.className?.toString?.().slice(0,200)??"",text:t.textContent?.trim().slice(0,120)??"",html:t.outerHTML.slice(0,600),route:location.pathname+location.search,element:be(t)})}function T(e){if(e.key==="Escape"&&e.type==="keydown"){e.preventDefault(),e.stopPropagation(),X(),s({type:"pick-cancel"});return}if((e.key==="Alt"||e.key==="Shift")&&(h!==e.altKey||p!==e.shiftKey)){if(h=e.altKey,p=e.shiftKey,f)K(f)}}function ve(e){if(y=e,A){if(f)K(f);return}A=!0,f=null,h=!1,p=!1,document.addEventListener("mousemove",ne,!0),document.addEventListener("click",re,!0),document.addEventListener("keydown",T,!0),document.addEventListener("keyup",T,!0),document.documentElement.style.cursor="crosshair"}function X(){A=!1,y=!1,f=null,h=!1,p=!1,m(),document.removeEventListener("mousemove",ne,!0),document.removeEventListener("click",re,!0),document.removeEventListener("keydown",T,!0),document.removeEventListener("keyup",T,!0),document.documentElement.style.cursor=""}function Ee(e){let t=[],n=e;for(let r=0;n&&n!==document.documentElement&&r<6;r++){if(n.id){t.unshift(`#${CSS.escape(n.id)}`);break}let o=n.parentElement,i=o?Array.from(o.children).indexOf(n)+1:1;t.unshift(`${n.tagName.toLowerCase()}:nth-child(${i})`),n=o}return t.join(" > ")}function oe(e){let t=e.lastIndexOf("/src/");return t>=0?e.slice(t+1):e.split("/").slice(-2).join("/")}function xe(e,t){return e.endsWith(t)||t.endsWith(oe(e))}function Se(e,t){let n=[],r=0;for(let a of Array.from(document.querySelectorAll("*"))){let l=_(W(a));if(l)r++;if(!l||!xe(l.file,e))continue;n.push({el:a,line:l.line??-1})}if(!t||t.length===0)return{matched:n,fromFile:n,withSource:r};if(t.length===1&&t[0][0]===t[0][1]){let a=t[0][0],l=n.filter((d)=>d.line===a);if(l.length>0)return{matched:l,fromFile:n,withSource:r};let c=n.filter((d)=>d.line>0&&d.line<a);return c.sort((d,b)=>b.line-d.line),{matched:c.slice(0,1),fromFile:n,withSource:r}}return{matched:n.filter((a)=>t.some(([l,c])=>a.line>=l-8&&a.line<=c+1)),fromFile:n,withSource:r}}function Ae(e,t){m();let{matched:n,fromFile:r,withSource:o}=Se(e,t),i=0;for(let{el:a}of n){if(i>=40)break;let l=a.getBoundingClientRect();if(l.width>0&&l.height>0)S(l),i++}if(i===0)s({type:"highlight-miss",path:e,fileMatched:r.length,withSource:o,ranges:t})}var ie=!1,w=!1,Te=(e)=>{for(let t=e;t&&t!==document.documentElement;t=t.parentElement){let n=getComputedStyle(t),r=n.overflowX;if((r==="auto"||r==="scroll")&&t.scrollWidth>t.clientWidth+1)return!0;if(window.__toyonShell)continue;let o=n.touchAction;if(o!=="auto"&&o!=="manipulation"&&!o.includes("pan-x"))return!0}return!1},le=(e,t)=>{let n=e.touches[0]??e.changedTouches[0];if(n)s({type:"touch",phase:t,x:n.clientX,y:n.clientY})};window.addEventListener("touchstart",(e)=>{if(w=!1,!ie||e.touches.length!==1)return;let t=e.target instanceof Element?e.target:null;if(t?.closest("input, textarea, [contenteditable]")||Te(t))return;w=!0,le(e,"start")},{capture:!0,passive:!0});var j=(e,t)=>{if(!w)return;setTimeout(()=>{if(!w)return;let n=t==="move"&&(e.defaultPrevented||e.touches.length!==1);if(t!=="move"||n)w=!1;le(e,n?"cancel":t)},0)};window.addEventListener("touchmove",(e)=>j(e,"move"),{passive:!0});window.addEventListener("touchend",(e)=>j(e,"end"),!0);window.addEventListener("touchcancel",(e)=>j(e,"cancel"),!0);window.addEventListener("message",(e)=>{if(e.source!==window.parent)return;if(E.length&&!E.includes(e.origin))return;let t=e.data;if(!t?.__toyon)return;R=e.origin;let n=t;switch(n.type){case"reload":location.reload();break;case"navigate":if(/^[/?#]/.test(n.path))location.assign(n.path);break;case"back":case"forward":{let r=window.navigation;if((n.type==="back"?r?.canGoBack:r?.canGoForward)===!1)break;if(n.type==="back")history.back();else history.forward();break}case"touches":ie=n.on;break;case"links":{let r=new Set,o=[];for(let i of Array.from(document.querySelectorAll("a[href]"))){if(i.origin!==location.origin||i.target==="_blank"||i.hasAttribute("download"))continue;let a=i.pathname+(i.hash.startsWith("#/")?i.hash:"");if(a.startsWith("/__toyon")||r.has(a))continue;r.add(a);let l=(i.textContent||i.getAttribute("aria-label")||"").replace(/\s+/g," ").trim();if(o.push({path:a,text:l.slice(0,80)}),o.length>=200)break}s({type:"links",links:o});break}case"pick-start":ve(n.verb==="code");break;case"pick-mods":if(A&&(h!==n.alt||p!==n.shift)){if(h=n.alt,p=n.shift,f)K(f)}break;case"pick-cancel":X();break;case"highlight-file":Ae(n.path,n.ranges??null);break;case"highlight-computed":{m();let r=/^(color|font|line-height|letter-|text-|word-)/,o=(l)=>{if(/^(INPUT|TEXTAREA|SELECT)$/.test(l.tagName))return!0;for(let c=l.firstChild;c;c=c.nextSibling)if(c.nodeType===3&&c.textContent&&c.textContent.trim())return!0;return!1},i=document.querySelectorAll("*"),a=!0;for(let l=0;l<i.length;l++){let c=getComputedStyle(i[l]),d=([z,ae])=>c.getPropertyValue(z)===ae&&(!r.test(z)||o(i[l]));if(n.match==="any"?n.props.some(d):n.props.every(d))S(i[l].getBoundingClientRect(),a&&n.label?k(n.label):void 0),a=!1}break}case"highlight-selector":{m();try{let r=document.querySelectorAll(n.selector);for(let o=0;o<r.length;o++)S(r[o].getBoundingClientRect(),o===0&&n.label?k(n.label):void 0)}catch{}break}case"highlight-clear":m();break;case"zen":te=n.on;break;case"theme":if(/^#[0-9a-f]{3,8}$/i.test(n.accent))x=n.accent;if(/^#[0-9a-f]{3,8}$/i.test(n.accentFg))ee=n.accentFg;break}});
|
package/dist/cli.js
CHANGED
|
@@ -5290,7 +5290,7 @@ function parseVersion(v) {
|
|
|
5290
5290
|
// package.json
|
|
5291
5291
|
var package_default = {
|
|
5292
5292
|
name: "toyon",
|
|
5293
|
-
version: "0.
|
|
5293
|
+
version: "0.24.0",
|
|
5294
5294
|
description: "Toyon is where coding agents work on your web app while you check each change by using it. Every chat gets its own running copy with a live preview.",
|
|
5295
5295
|
license: "MIT",
|
|
5296
5296
|
type: "module",
|
|
@@ -5644,6 +5644,7 @@ var VERBS = new Set([
|
|
|
5644
5644
|
"uninstall",
|
|
5645
5645
|
"remote",
|
|
5646
5646
|
"pair",
|
|
5647
|
+
"send",
|
|
5647
5648
|
"deploy",
|
|
5648
5649
|
"help"
|
|
5649
5650
|
]);
|
|
@@ -5704,6 +5705,8 @@ function parseArgs(argv) {
|
|
|
5704
5705
|
}
|
|
5705
5706
|
return { kind: "remote", to, ports, tailscale };
|
|
5706
5707
|
}
|
|
5708
|
+
case "send":
|
|
5709
|
+
return parseSend(rest);
|
|
5707
5710
|
case "deploy":
|
|
5708
5711
|
return parseDeploy(rest);
|
|
5709
5712
|
}
|
|
@@ -5735,6 +5738,30 @@ function parseLogs(rest) {
|
|
|
5735
5738
|
}
|
|
5736
5739
|
return { kind: "logs", follow, lines };
|
|
5737
5740
|
}
|
|
5741
|
+
function parseSend(rest) {
|
|
5742
|
+
let text = null;
|
|
5743
|
+
let file = null;
|
|
5744
|
+
let carry = false;
|
|
5745
|
+
for (let i = 0;i < rest.length; i++) {
|
|
5746
|
+
const a = rest[i];
|
|
5747
|
+
if (a === "--file" || a === "-f") {
|
|
5748
|
+
const value = rest[++i];
|
|
5749
|
+
if (!value)
|
|
5750
|
+
return { kind: "error", message: `${a} needs a path` };
|
|
5751
|
+
file = value;
|
|
5752
|
+
} else if (a === "--carry")
|
|
5753
|
+
carry = true;
|
|
5754
|
+
else if (a.startsWith("-"))
|
|
5755
|
+
return { kind: "error", message: `unknown option ${a}` };
|
|
5756
|
+
else if (text !== null)
|
|
5757
|
+
return { kind: "error", message: "toyon send takes one message; quote it" };
|
|
5758
|
+
else
|
|
5759
|
+
text = a;
|
|
5760
|
+
}
|
|
5761
|
+
if (text !== null && file !== null)
|
|
5762
|
+
return { kind: "error", message: "toyon send takes the message as text or from --file, not both" };
|
|
5763
|
+
return { kind: "send", text, file, carry };
|
|
5764
|
+
}
|
|
5738
5765
|
var FLY_APP = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
5739
5766
|
function parseDeploy(rest) {
|
|
5740
5767
|
const error = (message) => ({ kind: "error", message });
|
|
@@ -5787,6 +5814,10 @@ usage
|
|
|
5787
5814
|
toyon <git url> open the shell with that repository ready to clone into the current
|
|
5788
5815
|
directory; a page on GitHub, GitLab or Codeberg is read back to its
|
|
5789
5816
|
repository, and to its branch
|
|
5817
|
+
toyon send [text] send a message to Toyon about the current directory: a new worktree
|
|
5818
|
+
of its project, a take-over of a worktree Toyon does not run, or the
|
|
5819
|
+
chat of one it does; the text, --file <path>, or stdin
|
|
5820
|
+
--carry move main's uncommitted changes into the worktree started for it
|
|
5790
5821
|
toyon start start the daemon if it is not running, and open nothing
|
|
5791
5822
|
toyon stop stop the daemon and every dev server and agent it runs
|
|
5792
5823
|
toyon restart stop the daemon and start it again from what is installed now; every
|
|
@@ -6887,15 +6918,71 @@ async function restart() {
|
|
|
6887
6918
|
return 0;
|
|
6888
6919
|
}
|
|
6889
6920
|
|
|
6921
|
+
// src/send.ts
|
|
6922
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
6923
|
+
function sentBy(env = process.env) {
|
|
6924
|
+
return env.CLAUDECODE || env.CLAUDE_CODE_ENTRYPOINT ? "Claude Code" : undefined;
|
|
6925
|
+
}
|
|
6926
|
+
async function messageOf(cmd) {
|
|
6927
|
+
if (cmd.text !== null)
|
|
6928
|
+
return cmd.text;
|
|
6929
|
+
if (cmd.file !== null)
|
|
6930
|
+
return readFileSync8(cmd.file, "utf8");
|
|
6931
|
+
if (process.stdin.isTTY)
|
|
6932
|
+
return null;
|
|
6933
|
+
return await Bun.stdin.text();
|
|
6934
|
+
}
|
|
6935
|
+
async function send(cmd) {
|
|
6936
|
+
let text;
|
|
6937
|
+
try {
|
|
6938
|
+
text = await messageOf(cmd);
|
|
6939
|
+
} catch (e) {
|
|
6940
|
+
console.error(`toyon: could not read ${cmd.file}: ${e.message}`);
|
|
6941
|
+
return 1;
|
|
6942
|
+
}
|
|
6943
|
+
if (!text?.trim()) {
|
|
6944
|
+
console.error("toyon: give the message as text, with --file, or on stdin");
|
|
6945
|
+
return 2;
|
|
6946
|
+
}
|
|
6947
|
+
const daemon = await ensureDaemon();
|
|
6948
|
+
if (!daemon)
|
|
6949
|
+
return 1;
|
|
6950
|
+
const by = sentBy();
|
|
6951
|
+
const res = await post("/send", daemon.token, {
|
|
6952
|
+
path: process.cwd(),
|
|
6953
|
+
text,
|
|
6954
|
+
...by ? { by } : {},
|
|
6955
|
+
...cmd.carry ? { carry: true } : {}
|
|
6956
|
+
});
|
|
6957
|
+
if (!res.ok) {
|
|
6958
|
+
console.error(`could not send: ${await res.text()}`);
|
|
6959
|
+
return 1;
|
|
6960
|
+
}
|
|
6961
|
+
const reply = await res.json();
|
|
6962
|
+
console.log(sentLine(reply));
|
|
6963
|
+
if (reply.delivered)
|
|
6964
|
+
focusShell();
|
|
6965
|
+
else
|
|
6966
|
+
openShell(daemon);
|
|
6967
|
+
return 0;
|
|
6968
|
+
}
|
|
6969
|
+
function sentLine(reply) {
|
|
6970
|
+
if (reply.kind === "sent")
|
|
6971
|
+
return `toyon: sent to ${reply.title} in Toyon`;
|
|
6972
|
+
const stayed = reply.stayed && reply.stayed > 0 ? `; ${reply.stayed} uncommitted ${reply.stayed === 1 ? "file" : "files"} stayed on main, --carry moves them` : "";
|
|
6973
|
+
const notice = reply.notice ? `; ${reply.notice}` : "";
|
|
6974
|
+
return `toyon: ${reply.title} is open in Toyon${stayed}${notice}`;
|
|
6975
|
+
}
|
|
6976
|
+
|
|
6890
6977
|
// src/uninstall.ts
|
|
6891
|
-
import { existsSync as existsSync12, readFileSync as
|
|
6978
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9, rmSync as rmSync4 } from "fs";
|
|
6892
6979
|
import { join as join7 } from "path";
|
|
6893
6980
|
function readState() {
|
|
6894
6981
|
const file = join7(home, DAEMON_FILES.state);
|
|
6895
6982
|
if (!existsSync12(file))
|
|
6896
6983
|
return {};
|
|
6897
6984
|
try {
|
|
6898
|
-
return JSON.parse(
|
|
6985
|
+
return JSON.parse(readFileSync9(file, "utf8"));
|
|
6899
6986
|
} catch {
|
|
6900
6987
|
return {};
|
|
6901
6988
|
}
|
|
@@ -7137,6 +7224,8 @@ async function run(cmd) {
|
|
|
7137
7224
|
return remote(cmd);
|
|
7138
7225
|
case "pair":
|
|
7139
7226
|
return pair();
|
|
7227
|
+
case "send":
|
|
7228
|
+
return send(cmd);
|
|
7140
7229
|
case "deploy":
|
|
7141
7230
|
return deploy(cmd);
|
|
7142
7231
|
case "open":
|