toyon 0.21.0 → 0.23.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 +5 -5
- package/dist/CHANGELOG.md +54 -0
- package/dist/bridge.js +1 -1
- package/dist/cli.js +93 -4
- package/dist/daemon.js +10062 -9007
- package/dist/shell/assets/{Editor-D_bxx8PL.js → Editor-C2e_GpDQ.js} +179 -179
- package/dist/shell/assets/Editor-C2e_GpDQ.js.br +0 -0
- package/dist/shell/assets/Editor-C2e_GpDQ.js.gz +0 -0
- package/dist/shell/assets/XTerm-B84G0H5I.js +58 -0
- package/dist/shell/assets/XTerm-B84G0H5I.js.br +0 -0
- package/dist/shell/assets/XTerm-B84G0H5I.js.gz +0 -0
- package/dist/shell/assets/{cssMode-BxHmuU8y.js → cssMode-DhDLwjyN.js} +1 -1
- package/dist/shell/assets/cssMode-DhDLwjyN.js.br +0 -0
- package/dist/shell/assets/cssMode-DhDLwjyN.js.gz +0 -0
- package/dist/shell/assets/{freemarker2-Cx9ZoWdp.js → freemarker2-rc8sP22g.js} +1 -1
- package/dist/shell/assets/freemarker2-rc8sP22g.js.br +0 -0
- package/dist/shell/assets/freemarker2-rc8sP22g.js.gz +0 -0
- package/dist/shell/assets/{grammar-DlhzivAk.js → grammar-Cty-NAQC.js} +1 -1
- package/dist/shell/assets/grammar-Cty-NAQC.js.br +0 -0
- package/dist/shell/assets/grammar-Cty-NAQC.js.gz +0 -0
- package/dist/shell/assets/{handlebars-D0MhpM71.js → handlebars-BOQxV3p5.js} +1 -1
- package/dist/shell/assets/handlebars-BOQxV3p5.js.br +0 -0
- package/dist/shell/assets/handlebars-BOQxV3p5.js.gz +0 -0
- package/dist/shell/assets/{html-Da9gyCH4.js → html-CxndUpse.js} +1 -1
- package/dist/shell/assets/html-CxndUpse.js.br +0 -0
- package/dist/shell/assets/html-CxndUpse.js.gz +0 -0
- package/dist/shell/assets/{htmlMode-CGo3ddCJ.js → htmlMode-CG7eVDLo.js} +1 -1
- package/dist/shell/assets/htmlMode-CG7eVDLo.js.br +0 -0
- package/dist/shell/assets/htmlMode-CG7eVDLo.js.gz +0 -0
- package/dist/shell/assets/index-DpSfPmkM.css +1 -0
- package/dist/shell/assets/index-DpSfPmkM.css.br +0 -0
- package/dist/shell/assets/index-DpSfPmkM.css.gz +0 -0
- package/dist/shell/assets/index-DzfHDra7.js +294 -0
- package/dist/shell/assets/index-DzfHDra7.js.br +0 -0
- package/dist/shell/assets/index-DzfHDra7.js.gz +0 -0
- package/dist/shell/assets/{javascript-BXQxakKJ.js → javascript-CafoevnZ.js} +1 -1
- package/dist/shell/assets/{jsonMode-DT4ON4ij.js → jsonMode-Cg_4sMB_.js} +1 -1
- package/dist/shell/assets/jsonMode-Cg_4sMB_.js.br +0 -0
- package/dist/shell/assets/jsonMode-Cg_4sMB_.js.gz +0 -0
- package/dist/shell/assets/{liquid-Bm6Hq-FF.js → liquid-DxW_HNid.js} +1 -1
- package/dist/shell/assets/liquid-DxW_HNid.js.br +0 -0
- package/dist/shell/assets/liquid-DxW_HNid.js.gz +0 -0
- package/dist/shell/assets/{lspLanguageFeatures-DWvAzXxS.js → lspLanguageFeatures-Dhat9l4L.js} +1 -1
- package/dist/shell/assets/lspLanguageFeatures-Dhat9l4L.js.br +0 -0
- package/dist/shell/assets/lspLanguageFeatures-Dhat9l4L.js.gz +0 -0
- package/dist/shell/assets/{mdx-DNcDUEs7.js → mdx-ZdMhgPNL.js} +1 -1
- package/dist/shell/assets/mdx-ZdMhgPNL.js.br +0 -0
- package/dist/shell/assets/mdx-ZdMhgPNL.js.gz +0 -0
- package/dist/shell/assets/{python-BgETNCIe.js → python-Bae_7wMM.js} +1 -1
- package/dist/shell/assets/python-Bae_7wMM.js.br +0 -0
- package/dist/shell/assets/python-Bae_7wMM.js.gz +0 -0
- package/dist/shell/assets/{razor-Cf_D69YI.js → razor-CtwiCIJH.js} +1 -1
- package/dist/shell/assets/razor-CtwiCIJH.js.br +0 -0
- package/dist/shell/assets/razor-CtwiCIJH.js.gz +0 -0
- package/dist/shell/assets/toyon-mono-bold-9c1iJO0D.woff2 +0 -0
- package/dist/shell/assets/toyon-mono-regular-BXyxgSUK.woff2 +0 -0
- package/dist/shell/assets/{tsMode-BQA_zU_Q.js → tsMode-DH9rMbRS.js} +1 -1
- package/dist/shell/assets/tsMode-DH9rMbRS.js.br +0 -0
- package/dist/shell/assets/tsMode-DH9rMbRS.js.gz +0 -0
- package/dist/shell/assets/{xml-DrZtVQVT.js → xml-rA-vNTCn.js} +1 -1
- package/dist/shell/assets/xml-rA-vNTCn.js.br +0 -0
- package/dist/shell/assets/xml-rA-vNTCn.js.gz +0 -0
- package/dist/shell/assets/{yaml-CzR4Kx36.js → yaml-pOtRRozm.js} +1 -1
- package/dist/shell/assets/yaml-pOtRRozm.js.br +0 -0
- package/dist/shell/assets/yaml-pOtRRozm.js.gz +0 -0
- package/dist/shell/index.html +2 -2
- package/package.json +1 -1
- package/dist/shell/assets/Editor-D_bxx8PL.js.br +0 -0
- package/dist/shell/assets/Editor-D_bxx8PL.js.gz +0 -0
- package/dist/shell/assets/XTerm-DNFNsoHC.js +0 -58
- package/dist/shell/assets/XTerm-DNFNsoHC.js.br +0 -0
- package/dist/shell/assets/XTerm-DNFNsoHC.js.gz +0 -0
- package/dist/shell/assets/cssMode-BxHmuU8y.js.br +0 -0
- package/dist/shell/assets/cssMode-BxHmuU8y.js.gz +0 -0
- package/dist/shell/assets/freemarker2-Cx9ZoWdp.js.br +0 -0
- package/dist/shell/assets/freemarker2-Cx9ZoWdp.js.gz +0 -0
- package/dist/shell/assets/grammar-DlhzivAk.js.br +0 -0
- package/dist/shell/assets/grammar-DlhzivAk.js.gz +0 -0
- package/dist/shell/assets/handlebars-D0MhpM71.js.br +0 -0
- package/dist/shell/assets/handlebars-D0MhpM71.js.gz +0 -0
- package/dist/shell/assets/html-Da9gyCH4.js.br +0 -0
- package/dist/shell/assets/html-Da9gyCH4.js.gz +0 -0
- package/dist/shell/assets/htmlMode-CGo3ddCJ.js.br +0 -0
- package/dist/shell/assets/htmlMode-CGo3ddCJ.js.gz +0 -0
- package/dist/shell/assets/index-DJ0qL1Ze.css +0 -1
- package/dist/shell/assets/index-DJ0qL1Ze.css.br +0 -0
- package/dist/shell/assets/index-DJ0qL1Ze.css.gz +0 -0
- package/dist/shell/assets/index-DMDdU-hM.js +0 -288
- package/dist/shell/assets/index-DMDdU-hM.js.br +0 -0
- package/dist/shell/assets/index-DMDdU-hM.js.gz +0 -0
- package/dist/shell/assets/jsonMode-DT4ON4ij.js.br +0 -0
- package/dist/shell/assets/jsonMode-DT4ON4ij.js.gz +0 -0
- package/dist/shell/assets/liquid-Bm6Hq-FF.js.br +0 -0
- package/dist/shell/assets/liquid-Bm6Hq-FF.js.gz +0 -0
- package/dist/shell/assets/lspLanguageFeatures-DWvAzXxS.js.br +0 -0
- package/dist/shell/assets/lspLanguageFeatures-DWvAzXxS.js.gz +0 -0
- package/dist/shell/assets/mdx-DNcDUEs7.js.br +0 -0
- package/dist/shell/assets/mdx-DNcDUEs7.js.gz +0 -0
- package/dist/shell/assets/python-BgETNCIe.js.br +0 -0
- package/dist/shell/assets/python-BgETNCIe.js.gz +0 -0
- package/dist/shell/assets/razor-Cf_D69YI.js.br +0 -0
- package/dist/shell/assets/razor-Cf_D69YI.js.gz +0 -0
- package/dist/shell/assets/tsMode-BQA_zU_Q.js.br +0 -0
- package/dist/shell/assets/tsMode-BQA_zU_Q.js.gz +0 -0
- package/dist/shell/assets/xml-DrZtVQVT.js.br +0 -0
- package/dist/shell/assets/xml-DrZtVQVT.js.gz +0 -0
- package/dist/shell/assets/yaml-CzR4Kx36.js.br +0 -0
- package/dist/shell/assets/yaml-CzR4Kx36.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
|
-
[How it works](#how-it-works) · [Install](#install) · [Under the hood](#under-the-hood) · [Trust](#trust) · [Uninstall](#uninstall)
|
|
7
|
+
[toyon.dev](https://toyon.dev) · [How it works](#how-it-works) · [Install](#install) · [Under the hood](#under-the-hood) · [Trust](#trust) · [Uninstall](#uninstall)
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
@@ -50,7 +50,7 @@ npm i -g toyon
|
|
|
50
50
|
toyon ~/projects/app
|
|
51
51
|
```
|
|
52
52
|
|
|
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.
|
|
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. `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
54
|
|
|
55
55
|
You need:
|
|
56
56
|
|
|
@@ -81,14 +81,14 @@ A project with a page and an API behind it:
|
|
|
81
81
|
"setup": ["npm install"],
|
|
82
82
|
"run": {
|
|
83
83
|
"web": "vite --port $PORT --strictPort",
|
|
84
|
-
"api":
|
|
84
|
+
"api": "node --watch server/index.js"
|
|
85
85
|
},
|
|
86
86
|
"check": "npm test",
|
|
87
87
|
"land": { "route": "pr" }
|
|
88
88
|
}
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
Each command gets its own `$PORT`, and the addresses of the others as `<NAME>_URL` (`API_URL` here), so the page can proxy to its API. The preview shows `web`. A command
|
|
91
|
+
Each command gets its own `$PORT`, and the addresses of the others as `<NAME>_URL` (`API_URL` here), so the page can proxy to its API. The preview shows `web`. A command that names a folder of the tree, `server/` here, runs once, in the main checkout, and every copy's page reaches that one until the copy's own changes touch that folder; then the copy starts its own. A copy that only changes the page costs one Vite.
|
|
92
92
|
|
|
93
93
|
Copies start when you open them, and stop their servers when nobody has looked at them for a while; the chat and the agent keep going. Close the window and the daemon stops itself once nothing has needed it for half an hour; `toyon stop` stops it now, and everything it runs. `toyon doctor` says what is running and why a page cannot connect. Every setting, the port rules and the sleep delay are in [docs/settings.md](https://github.com/toyon-dev/toyon/blob/main/docs/settings.md).
|
|
94
94
|
|
|
@@ -100,7 +100,7 @@ Copies start when you open them, and stop their servers when nobody has looked a
|
|
|
100
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
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.
|
|
102
102
|
|
|
103
|
-
##
|
|
103
|
+
## Your own server
|
|
104
104
|
|
|
105
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. None of it passes through a Toyon server; there is none. `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
106
|
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
What changed in each release of Toyon, newest first.
|
|
4
4
|
|
|
5
|
+
## 0.23.0 (2026-11-10)
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
### New
|
|
10
|
+
- 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.
|
|
11
|
+
- 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.
|
|
12
|
+
- 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.
|
|
13
|
+
- `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.
|
|
14
|
+
- 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.
|
|
15
|
+
- 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.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- `"paths": []` in settings is refused; write `"from": "trunk"` alone, which means the same thing: main runs the command and no file change flips it.
|
|
19
|
+
- 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.
|
|
20
|
+
- 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.
|
|
21
|
+
- 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.
|
|
22
|
+
- 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.
|
|
23
|
+
- 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.
|
|
24
|
+
- 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.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- 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.
|
|
28
|
+
- A landed worktree with a merged PR and uncommitted changes still said land in the composer, the rail menu and the changes tab.
|
|
29
|
+
- 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.
|
|
30
|
+
- 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.
|
|
31
|
+
- 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.
|
|
32
|
+
|
|
33
|
+
## 0.22.0 (2026-11-03)
|
|
34
|
+
|
|
35
|
+
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.
|
|
36
|
+
|
|
37
|
+
### New
|
|
38
|
+
- The diff view has a split and inline toggle. Split closes the chat to make room and brings it back when you turn split off, unless you moved the chat yourself. It is hidden on a phone and for files with no other side.
|
|
39
|
+
- SVG files open in a preview in the editor, drawn from the file text so nothing runs or loads from outside, from the files tab, cmd+P or a tool row. It can expand to full size on a paper ground.
|
|
40
|
+
- Code spans and fenced blocks in your own messages are drawn as code, in the sent bubble and while the message is queued or uploading, with the same colouring the agent's fences get.
|
|
41
|
+
- A reference such as owner/repo#123 in chat links to the issue or pull request on GitHub, and a bare or backticked web address links in both the agent's rows and your own messages.
|
|
42
|
+
- Clicking a blame note in the editor opens the pull request for that line, or the commit page when the commit came without one. A commit the remote does not have gets no link, so nothing opens a 404.
|
|
43
|
+
- Agent adapters install from a private registry such as Artifactory. When a registry's release-age gate holds a package back, the composer says so and offers install anyway, and a certificate error or a 404 gets one sentence with the way out.
|
|
44
|
+
- In the full view of a picture, a double tap zooms about the tapped point and a second one returns; one finger pans while zoomed.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
- A single newline in a reply is a line break, as it is in a GitHub comment or Claude Code's terminal, so multi-line quotes no longer run together. Documents such as the markdown preview and the release notes keep their wrapped paragraphs.
|
|
48
|
+
- An open question card no longer counts as work. The idle clock treats a waiting row as a candidate and expires the card when it fires, and the archive sweep, idle stop, auto update and port eviction no longer wait on an open card.
|
|
49
|
+
- The red failed and blue landed row colours show only while a server is up under the row; an asleep row reads as quiet gray until you open it.
|
|
50
|
+
- In zen, cmd+left and cmd+right step back and forward through the page like cmd+[ and cmd+]. Outside zen they still walk the worktrees you viewed.
|
|
51
|
+
- The let-me-in page, opened on localhost, says that running toyon in a terminal on this machine opens the shell already let in.
|
|
52
|
+
- The version chip's menu has a toyon.dev row, and the README leads its links with the site.
|
|
53
|
+
- The docs gained an install page, and the preview, agents and trust pages were rewritten as references in plainer prose.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- A long press on a rail, changes or files row on a touch screen started a drag instead of opening the menu. Rows still drag into the composer where there is a pointer.
|
|
57
|
+
- The purple dot for a commit, land or sync in flight showed only in the rail; the @ menu, transcript marks and worktree chip showed green.
|
|
58
|
+
|
|
5
59
|
## 0.21.0 (2026-11-02)
|
|
6
60
|
|
|
7
61
|
Splitting work is called handoff again and the pieces it starts wake each other as they land, pull request review lands in a page of its own, and the project switcher clones from a URL.
|
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-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:"ArrowLeft",textKeeps:!0},{id:"forward",key:"ArrowRight",textKeeps:!0},{id:"close",key:"w"}],q=new Set(["zen","close","back","forward"]);function z(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 V(e){let t=v.find((n)=>n.id===e);if(!t)throw Error(`unknown chord ${e}`);return t}function Z(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 ae=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===ae)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 s=L(i.type);if(!s)continue;let l=!!e&&de(fe(i),e),c=pe(i);if(n&&!(l&&c))break;if(n=s,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,a=(e)=>{try{let t=R?[R]:E.length?E:["*"];for(let n of t)window.parent.postMessage({__toyon:!0,...e},n)}catch{}};a({type:"loaded",url:location.href,title:document.title});var x="#fa891e",ee="#1d2021";window.addEventListener("vite:afterUpdate",()=>a({type:"hmr"}));window.addEventListener("error",(e)=>{a({type:"page-error",message:String(e.message),source:e.filename,line:e.lineno})});window.addEventListener("unhandledrejection",(e)=>{a({type:"page-error",message:`unhandled rejection: ${String(e.reason)}`})});var K=()=>a({type:"navigated",url:location.href,title:document.title}),he=history.pushState.bind(history);history.pushState=(...e)=>{he(...e),H(),K()};var ye=history.replaceState.bind(history);history.replaceState=(...e)=>{ye(...e),K()};window.addEventListener("popstate",K);window.addEventListener("hashchange",K);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";a({type:"traversed",...t?{dir:t}:{}})});var ge=performance.getEntriesByType("navigation")[0];if(ge?.type==="back_forward")a({type:"traversed"});window.addEventListener("pageshow",(e)=>{if(e.persisted)a({type:"traversed"})});var O=document.title;if(document.head)new MutationObserver(()=>{if(document.title===O)return;O=document.title,a({type:"title",title:O})}).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,a({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=z(e,{guest:!0});if(t&&V(t.id).textKeeps&&Z(e.target))return;if(te){if(!t||!q.has(t.id))return}else if(e.key==="Escape"){a({type:"key",key:"Escape",meta:!1});return}else if(!t)return;e.preventDefault(),e.stopPropagation(),a({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=()=>a({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";a({type:"drag-files",over:!0})});window.addEventListener("dragleave",(e)=>{if(W(e))a({type:"drag-files",over:!1})});window.addEventListener("drop",(e)=>{if(!W(e))return;e.preventDefault(),a({type:"drop-files",files:Array.from(e.dataTransfer?.files??[])})});function X(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 P=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>=P,i=e.bottom+P<=window.innerHeight;if(t.style.top=o?`${-P}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 s=Number.parseFloat(t.style.left||"0");t.style.left=`${s-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,M=(e)=>`${oe(e.file)}${e.line?`:${e.line}`:""}`;function C(e){f=e,m();let t=N(X(e)),{src:n,comp:r,call:o}=t,i=F(t,p),s=i===n?o:n,l=h!==y,c=(...b)=>b.filter(Boolean).join(" ")||void 0,d=l?i?k(`open ${M(i)}`,c(s&&`⇧ ${M(s)}`,y&&"⌥ chat")):k(`find ${Q(e)}`,c(y&&"⌥ chat")):k(r?`<${r} />${i?` · ${M(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)C(t)}function re(e){e.preventDefault(),e.stopPropagation();let t=f??document.elementFromPoint(e.clientX,e.clientY),n=N(t?X(t):null),{src:r,comp:o,call:i}=n;p=e.shiftKey;let s=F(n,p),l=e.altKey!==y;if(j(),!t)return;a({type:"picked",verb:l?"code":"chat",site:s&&s===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(),j(),a({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)C(f)}}function ve(e){if(y=e,A){if(f)C(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 j(){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 s of Array.from(document.querySelectorAll("*"))){let l=_(X(s));if(l)r++;if(!l||!xe(l.file,e))continue;n.push({el:s,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 s=t[0][0],l=n.filter((d)=>d.line===s);if(l.length>0)return{matched:l,fromFile:n,withSource:r};let c=n.filter((d)=>d.line>0&&d.line<s);return c.sort((d,b)=>b.line-d.line),{matched:c.slice(0,1),fromFile:n,withSource:r}}return{matched:n.filter((s)=>t.some(([l,c])=>s.line>=l-8&&s.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:s}of n){if(i>=40)break;let l=s.getBoundingClientRect();if(l.width>0&&l.height>0)S(l),i++}if(i===0)a({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)a({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 G=(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)=>G(e,"move"),{passive:!0});window.addEventListener("touchend",(e)=>G(e,"end"),!0);window.addEventListener("touchcancel",(e)=>G(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 s=i.pathname+(i.hash.startsWith("#/")?i.hash:"");if(s.startsWith("/__toyon")||r.has(s))continue;r.add(s);let l=(i.textContent||i.getAttribute("aria-label")||"").replace(/\s+/g," ").trim();if(o.push({path:s,text:l.slice(0,80)}),o.length>=200)break}a({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)C(f)}break;case"pick-cancel":j();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("*"),s=!0;for(let l=0;l<i.length;l++){let c=getComputedStyle(i[l]),d=([U,se])=>c.getPropertyValue(U)===se&&(!r.test(U)||o(i[l]));if(n.match==="any"?n.props.some(d):n.props.every(d))S(i[l].getBoundingClientRect(),s&&n.label?k(n.label):void 0),s=!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.23.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
|
|
@@ -6311,7 +6342,7 @@ function agentLines(agents) {
|
|
|
6311
6342
|
continue;
|
|
6312
6343
|
const state = a.installed === null ? `${a.id} ${a.pinned} is not installed` : `${a.id} runs ${a.installed}, not the pinned ${a.pinned}`;
|
|
6313
6344
|
if (a.error)
|
|
6314
|
-
lines.push(line(false, "agents", `${state}: ${a.error}. The agent's install button in Settings or \`${restartCmd}\` tries again`));
|
|
6345
|
+
lines.push(line(false, "agents", a.held ? `${state}: ${a.error}. The agent's install anyway button in Settings runs it past the rule` : `${state}: ${a.error}. The agent's install button in Settings or \`${restartCmd}\` tries again`));
|
|
6315
6346
|
else
|
|
6316
6347
|
lines.push(line(true, "agents", `${state}; it may still be installing`));
|
|
6317
6348
|
}
|
|
@@ -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":
|