@solidrt/cli 0.0.51 → 0.0.52
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/AGENTS.md +68 -38
- package/README.md +86 -15
- package/agents/assets.md +19 -5
- package/agents/debugging.md +169 -17
- package/dist/console.srtapp +94123 -73
- package/dist/server.js +3936 -0
- package/package.json +10 -11
- package/src/android/docs.md +21 -0
- package/src/android/main.ts +286 -0
- package/src/{bundler.ts → bundle/bundler.ts} +67 -55
- package/src/bundle/docs.md +12 -0
- package/src/{commands/bundle.ts → bundle/main.ts} +67 -25
- package/src/check/docs.md +10 -0
- package/src/check/main.ts +85 -0
- package/src/{commands/check.ts → check/typecheck.ts} +11 -41
- package/src/client/docs.md +9 -0
- package/src/client/main.ts +33 -0
- package/src/console/docs.md +14 -0
- package/src/console/main.ts +21 -0
- package/src/demo/docs.md +27 -0
- package/src/demo/main.ts +67 -0
- package/src/init/docs.md +11 -0
- package/src/{commands/init.ts → init/main.ts} +21 -15
- package/src/init/scaffold/AGENTS.md +98 -0
- package/src/init/scaffold/package.json +23 -0
- package/{scaffold → src/init/scaffold}/templates/components/index.tsx +2 -3
- package/{scaffold → src/init/scaffold}/templates/default/index.tsx +2 -3
- package/src/lib/args.ts +194 -0
- package/src/{artifacts.ts → lib/artifacts.ts} +41 -1
- package/src/{dev-dir.ts → lib/dev-dir.ts} +10 -8
- package/src/{fonts.ts → lib/fonts.ts} +12 -26
- package/src/lib/mode.ts +77 -0
- package/src/{project.ts → lib/project.ts} +109 -61
- package/src/lib/registry.ts +120 -0
- package/src/lib/server-bundle.ts +24 -0
- package/src/lib/usage.ts +117 -0
- package/src/lib/util.ts +36 -0
- package/src/main.ts +109 -31
- package/src/mcp/docs.md +22 -0
- package/src/mcp/main.ts +719 -0
- package/src/pack/docs.md +18 -0
- package/src/{pack-folder.ts → pack/layout.ts} +13 -22
- package/src/{commands/pack.ts → pack/main.ts} +28 -17
- package/src/{packer.ts → pack/trailer.ts} +32 -42
- package/src/render/docs.md +19 -0
- package/src/{commands/render.ts → render/main.ts} +17 -15
- package/src/server/args.ts +126 -0
- package/src/server/binaries.ts +47 -0
- package/src/server/config.ts +54 -0
- package/{server → src/server}/control.ts +239 -81
- package/src/server/docs.md +51 -0
- package/src/server/line-editor.ts +200 -0
- package/src/server/main.ts +473 -0
- package/src/server/mode.ts +92 -0
- package/src/server/rebuild.ts +90 -0
- package/src/server/registry.ts +138 -0
- package/src/server/repl.ts +223 -0
- package/src/server/state.ts +54 -0
- package/{server → src/server}/tsconfig.json +1 -1
- package/{server → src/server}/tunnel.ts +6 -6
- package/src/server/watcher.ts +121 -0
- package/src/tool/main.ts +70 -0
- package/src/types/bundle.d.ts +24 -0
- package/src/types/control.d.ts +90 -0
- package/src/types/registry.d.ts +16 -0
- package/scaffold/AGENTS.md +0 -185
- package/scaffold/package.json +0 -22
- package/scaffold/templates/components/icon.tsx +0 -48
- package/scaffold/templates/default/icon.tsx +0 -48
- package/server/main.ts +0 -308
- package/server/rebuild.ts +0 -76
- package/server/state.ts +0 -94
- package/src/args.ts +0 -210
- package/src/bundle-cli.ts +0 -13
- package/src/commands/client.ts +0 -34
- package/src/commands/mcp.ts +0 -617
- package/src/commands/server.ts +0 -73
- package/src/dev-android.ts +0 -176
- package/src/dev-client.ts +0 -29
- package/src/dev-server.ts +0 -302
- package/src/repl.ts +0 -249
- package/src/util.ts +0 -122
- package/src/watcher.ts +0 -73
- /package/src/{untyped-deps.d.ts → bundle/untyped-deps.d.ts} +0 -0
- /package/src/{prompt.ts → init/prompt.ts} +0 -0
- /package/{scaffold → src/init/scaffold}/gitignore +0 -0
- /package/{scaffold → src/init/scaffold}/icon.svg +0 -0
- /package/{scaffold → src/init/scaffold}/mcp.json +0 -0
- /package/{scaffold → src/init/scaffold}/tsconfig.json +0 -0
- /package/{server → src/server}/cache.ts +0 -0
- /package/{server → src/server}/proxy.ts +0 -0
- /package/{server → src/server}/qr.ts +0 -0
- /package/{server → src/server}/remap.ts +0 -0
package/AGENTS.md
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
# @solidrt/cli - agent notes
|
|
2
2
|
|
|
3
|
-
Dense, self-contained facts for running and verifying a SolidRT app.
|
|
4
|
-
|
|
5
|
-
reactivity), see @solidrt/core (its
|
|
3
|
+
Dense, self-contained facts for running and verifying a SolidRT app. The
|
|
4
|
+
prose lives in README.md and src/<command>/docs.md (also the website). For
|
|
5
|
+
the authoring model (elements, props, reactivity), see @solidrt/core (its
|
|
6
|
+
AGENTS.md).
|
|
6
7
|
|
|
7
8
|
`srt` is the dev tool. Bun is a dev prerequisite only; SolidRT apps run on the
|
|
8
9
|
bundled `flux` runtime, not on Bun. Invoke via `bunx srt <command>`.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
The dev loop against a running app is pause_watch -> edit -> reload ->
|
|
12
|
+
resume_watch -> get_logs -> get_snapshot, with mute_user_input while you
|
|
13
|
+
measure or test and unmute_user_input after; agents/debugging.md has the
|
|
14
|
+
why of each hold. `reload` surfaces build errors but not type errors:
|
|
15
|
+
`bunx srt check` is for those.
|
|
16
|
+
|
|
17
|
+
agents/ carries the depth this one leaves out; read the one that matches
|
|
18
|
+
the work before starting it:
|
|
19
|
+
- agents/debugging.md - driving a running app over MCP, pointing an agent
|
|
20
|
+
client at the `srt mcp` server, what the dev server serves and its control
|
|
21
|
+
API without MCP (a shell, a CI step), and the debugging lessons that cost
|
|
22
|
+
real time. Read before investigating a bug, verifying a change against the
|
|
23
|
+
live app, or scripting against a server.
|
|
24
|
+
- agents/assets.md - the assets/ folder, inlined imports and the bundle
|
|
25
|
+
output; fonts, the `solidrt` package.json identity key, and distribution
|
|
26
|
+
builds. Read before adding an asset or a font, or building to distribute.
|
|
18
27
|
|
|
19
28
|
## Commands
|
|
20
29
|
|
|
@@ -22,19 +31,34 @@ matches the work before starting it:
|
|
|
22
31
|
folder: package.json, tsconfig.json, AGENTS.md, a starter src/index.tsx, an
|
|
23
32
|
empty assets/ (everything in it ships with the app), then installs deps. Greenfield shortcut (no install needed first):
|
|
24
33
|
`bun create solidrt <dir>`.
|
|
25
|
-
- `bunx srt run
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
- `bunx srt run` - dev server + a local client window, from the project root
|
|
35
|
+
(entry `solidrt.entry` in package.json, default src/index.tsx); `bunx srt run
|
|
36
|
+
<file>` serves a single file outside a project. NEEDS A DISPLAY (opens a GUI
|
|
37
|
+
window). Not usable headless. Reloads on save (the bundle's inputs and
|
|
38
|
+
`assets/`); an agent pauses that with `pause_watch` and pushes its edits
|
|
39
|
+
with the MCP `reload` tool.
|
|
40
|
+
- `bunx srt tool` - list the build-time tools the installed `@solidrt/*`
|
|
41
|
+
packages ship (`<package>/tools/<name>.ts`, named `<package>/<name>`);
|
|
42
|
+
`bunx srt tool <package>/<name> [arguments]` runs one under bun in the
|
|
43
|
+
project, everything after the name passed through as the tool's own
|
|
44
|
+
arguments (each tool prints its own usage on `--help`). What a tool does
|
|
45
|
+
is the package's business (e.g. `3d/model` bakes a glTF into a model
|
|
46
|
+
file); srt only finds and runs them.
|
|
47
|
+
- `bunx srt check [file|dir]` - build in memory and typecheck, no output
|
|
48
|
+
and no reload. With a folder it covers every entry under it (src/index.tsx
|
|
49
|
+
and examples/*), so `bunx srt check .` answers "did I break any example"
|
|
50
|
+
in one call. The dev server runs it once at startup without gating on it.
|
|
51
|
+
- `bunx srt bundle` - bundle the project into `dist/bundle/` (or
|
|
28
52
|
`--output <dir>`): `<name>.srt.js` plus the app's isolate modules as
|
|
29
53
|
`isolates/<id>.js`. With `--compile`, bytecode (`.srt.bin`/`.bin`)
|
|
30
54
|
instead. Move the dir, not the bare file - a bundle loaded without its
|
|
31
55
|
isolates/ dir loses them (`--stdout` cannot carry them at all).
|
|
32
56
|
`--minify`, `--dev` also available.
|
|
33
|
-
- `bunx srt render
|
|
57
|
+
- `bunx srt render [flags]` - render the project OFFSCREEN to PNG frames,
|
|
34
58
|
optionally replaying a `--script` file recorded via `--capture`.
|
|
35
59
|
- `bunx srt server [file]` / `bunx srt client` - the two halves of `run`
|
|
36
60
|
separately (server distributes code; clients on other devices connect to it).
|
|
37
|
-
- `bunx srt run
|
|
61
|
+
- `bunx srt run --capture out.script.json` - records keydown/keyup
|
|
38
62
|
from every connected client into one script file (written on client
|
|
39
63
|
disconnect), for replaying later with `render --script`. The file is JSON
|
|
40
64
|
Lines and hand-authorable: one object per line,
|
|
@@ -47,8 +71,8 @@ matches the work before starting it:
|
|
|
47
71
|
|
|
48
72
|
Two reliable checks that need no GUI:
|
|
49
73
|
|
|
50
|
-
1. `bunx srt bundle
|
|
51
|
-
2. `bunx srt render
|
|
74
|
+
1. `bunx srt bundle` - exit 0 means the app compiles. Fast.
|
|
75
|
+
2. `bunx srt render --size 480x640 --duration 1 --fps 2` -
|
|
52
76
|
renders offscreen via EGL and writes `frame-NNNNNN.png`. This actually
|
|
53
77
|
proves the app renders. Combine with `--fps`/`--duration` (defaults
|
|
54
78
|
1280x720, 60fps, 1s). No display needed: rendering uses SDL's offscreen
|
|
@@ -76,29 +100,35 @@ behavior in isolation.
|
|
|
76
100
|
(Wayland) and the pbuffer path on Windows from a desktop session; a
|
|
77
101
|
non-interactive Windows session and macOS are unverified.
|
|
78
102
|
|
|
79
|
-
##
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
## Servers (what is served, and finding it again)
|
|
104
|
+
|
|
105
|
+
- A dev server serves a project (started in its root: the cwd must hold the
|
|
106
|
+
package.json) or a single file (`srt run <file>` outside a project). Both
|
|
107
|
+
in one place is ambiguous, so `srt run <file>` in a project root needs
|
|
108
|
+
`--project` (the project, with this entry) or `--file` (the file alone).
|
|
109
|
+
Nothing searches upward for a package.json.
|
|
110
|
+
- One server per project or file. The server binds the port it had last
|
|
111
|
+
time, else the first free one from 34884 up, and prints it; `--port <N>`
|
|
112
|
+
pins it. Loopback only
|
|
113
|
+
unless `--lan`, which is what phones and other devices (and `srt android`
|
|
114
|
+
on a real device) need; `--tunnel` works without it.
|
|
115
|
+
- `-c <N>` / `--client <N>` picks the client data tree (default 0). Storage
|
|
116
|
+
is per app inside a tree, so two projects share client 0; only two clients
|
|
117
|
+
of the same app need distinct slots.
|
|
118
|
+
- Dev state lives in `~/.solidrt/`: `servers/<key hash>/` holds each server's
|
|
119
|
+
`live.json` (the registry record, written by the server and removed at
|
|
120
|
+
exit), its remembered `port` and tunnel key; `clients/client<M>/` the
|
|
121
|
+
client trees (srt passes `--data-root ~/.solidrt/clients` to every locally
|
|
122
|
+
spawned client). A record left behind by a crash is pruned when the next
|
|
123
|
+
server starts, and `srt client`, `srt mcp` and `srt android` confirm a
|
|
124
|
+
record against the server (its control API names the key it serves)
|
|
125
|
+
before using it.
|
|
126
|
+
- `srt client` and `srt mcp` need no port: run from the project root (or the
|
|
127
|
+
directory of a served file) they resolve the server from the registry;
|
|
128
|
+
`--port` pins one.
|
|
95
129
|
|
|
96
130
|
## Dev server proxies (when clients on other devices need your machine's data)
|
|
97
131
|
|
|
98
132
|
- `--proxy-http` - route `fetch` through the dev server; responses cached in
|
|
99
133
|
`.srt-data/http-cache.db` in the project root (delete the file to clear).
|
|
100
134
|
|
|
101
|
-
## REPL (opened by `run`/`server`)
|
|
102
|
-
|
|
103
|
-
`load <file>`, `reload [n]`, `stop [n]`, `list`, `!<cmd>`, `quit`/`exit`.
|
|
104
|
-
`load` is bound to the project root the server was started in.
|
package/README.md
CHANGED
|
@@ -1,26 +1,97 @@
|
|
|
1
1
|
# @solidrt/cli
|
|
2
2
|
|
|
3
|
-
Developer tooling for SolidRT
|
|
3
|
+
Developer tooling for SolidRT: `srt`, one command-line tool covering the
|
|
4
|
+
whole cycle of a `@solidrt/core` application: scaffold, develop, inspect,
|
|
5
|
+
ship. A GUI inspector, itself a SolidRT app, is in progress alongside it.
|
|
4
6
|
|
|
5
|
-
> LLM agents:
|
|
7
|
+
> LLM agents: `AGENTS.md` in this package is a dense, self-contained quickstart.
|
|
8
|
+
|
|
9
|
+
Bun is a dev prerequisite only; apps run on the bundled `flux` runtime.
|
|
10
|
+
Invoke via `bunx srt <command>`. A scaffolded project wires the common
|
|
11
|
+
commands into scripts, so day-to-day work is `bun run dev`, `bun run
|
|
12
|
+
android` (and `server`, `client`, `pack` for the rest).
|
|
6
13
|
|
|
7
14
|
## Commands
|
|
8
15
|
|
|
16
|
+
| Command | |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| [`srt init <dir>`](src/init/docs.md) | scaffold a new project into a new (empty) folder |
|
|
19
|
+
| [`srt run [file]`](src/server/docs.md) | dev server + local client window |
|
|
20
|
+
| [`srt server [file]`](src/server/docs.md) | dev server only |
|
|
21
|
+
| [`srt client`](src/client/docs.md) | client only, attached to the project's dev server |
|
|
22
|
+
| [`srt android`](src/android/docs.md) | install and launch the client on a connected Android device |
|
|
23
|
+
| [`srt demo [n]`](src/demo/docs.md) | list the demos the installed packages ship, or run one |
|
|
24
|
+
| [`srt console`](src/console/docs.md) | start the dev console: the dev servers on this machine and their clients |
|
|
25
|
+
| [`srt check [file]`](src/check/docs.md) | build and typecheck, writing nothing |
|
|
26
|
+
| [`srt bundle [file]`](src/bundle/docs.md) | transpile to JS or bytecode (dist/bundle/) |
|
|
27
|
+
| [`srt render [file]`](src/render/docs.md) | render frames offscreen, optionally replaying a script |
|
|
28
|
+
| [`srt pack [file]`](src/pack/docs.md) | bundle + compile to a standalone executable (experimental) |
|
|
29
|
+
| [`srt mcp`](src/mcp/docs.md) | MCP server (stdio) exposing the running dev server to agents |
|
|
30
|
+
|
|
31
|
+
`srt --help` lists every command and option; `srt --version` prints the
|
|
32
|
+
version. Run from the project root to work on the project (its entry is
|
|
33
|
+
`solidrt.entry` in package.json, default `src/index.tsx`); pass a file to
|
|
34
|
+
work on that file on its own.
|
|
35
|
+
|
|
36
|
+
## Develop
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
srt run
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Starts the dev server and a local client window against it. The server
|
|
43
|
+
pushes the bundle to every connected client, so one server can drive a
|
|
44
|
+
desktop window and a phone at the same time; edits reach them on an
|
|
45
|
+
explicit reload (the MCP `reload` tool) or on save.
|
|
46
|
+
|
|
47
|
+
Split them when you need to:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
srt server # server only
|
|
51
|
+
srt client # client only, the project's server (from its root)
|
|
52
|
+
srt client --server 192.168.1.5:34884 # client only, pointed at that address
|
|
53
|
+
srt android # install and launch on a connected device
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Inspect
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
srt mcp
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Exposes the running app to a coding agent: logs, stats, the live render
|
|
63
|
+
tree, screenshots, GPU resources, input injection, a virtual-time transport,
|
|
64
|
+
reload, and the app's own debug commands. A scaffolded project ships an
|
|
65
|
+
`.mcp.json`, so Claude Code attaches with no setup.
|
|
66
|
+
|
|
67
|
+
## Record and replay
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
srt run --capture session.json
|
|
71
|
+
srt render --script session.json --fps 60 --duration 5
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`--capture` records key events from connected clients to a script; `render`
|
|
75
|
+
replays it headlessly and writes frames, which makes bug reports
|
|
76
|
+
reproducible and turns an interaction into a video.
|
|
77
|
+
|
|
78
|
+
## Ship
|
|
79
|
+
|
|
9
80
|
```sh
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
81
|
+
srt check . # build and typecheck every entry, no build output
|
|
82
|
+
srt bundle # transpile to JS or bytecode
|
|
83
|
+
srt pack # standalone executable (experimental)
|
|
13
84
|
```
|
|
14
85
|
|
|
15
|
-
|
|
86
|
+
`srt bundle --flux` and `srt pack --flux` target the bare Flux runtime
|
|
87
|
+
instead of a SolidRT app, for scripts and servers with no UI.
|
|
16
88
|
|
|
17
|
-
|
|
89
|
+
## Layout
|
|
18
90
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| `quit` / `exit` | exit the dev server |
|
|
91
|
+
One folder per command under `src/`, named for what it does; the first line
|
|
92
|
+
of each says its runtime. `src/server/` is the dev server, a flux script
|
|
93
|
+
(`bun`-free at runtime, its own tsconfig); every other command runs on bun.
|
|
94
|
+
`src/lib/` is what the bun commands share, `src/types/` the type-only
|
|
95
|
+
contracts between the two runtimes. Each command folder carries its
|
|
96
|
+
`docs.md` (this site); the depth agents need lives in `agents/` at the
|
|
97
|
+
package root, as in the other packages.
|
package/agents/assets.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
# Assets and
|
|
1
|
+
# Assets, fonts, identity and distribution
|
|
2
2
|
|
|
3
|
-
Read this before adding an asset
|
|
4
|
-
distribution.
|
|
3
|
+
Read this before adding an asset or a font, setting the app's identity, or
|
|
4
|
+
preparing a build for distribution.
|
|
5
|
+
|
|
6
|
+
## Assets and inlined imports
|
|
5
7
|
|
|
6
8
|
- Everything under `assets/` ships with the app: the folder is collected
|
|
7
9
|
wholesale into each build's version manifest (no bundler analysis, no
|
|
@@ -16,6 +18,17 @@ distribution.
|
|
|
16
18
|
`.frag`) are declared as text modules out of the box, so they typecheck
|
|
17
19
|
without setup. Inlining trades update granularity for zero I/O - keep big or
|
|
18
20
|
streamable files (audio, images) in `assets/`.
|
|
21
|
+
- `bunx srt bundle` writes `dist/bundle/` (or `--output <dir>`):
|
|
22
|
+
`<name>.srt.js` plus the app's isolate modules as `isolates/<id>.js`; with
|
|
23
|
+
`--compile`, bytecode (`.srt.bin`/`.bin`) instead. Move the dir, not the
|
|
24
|
+
bare file - a bundle loaded without its isolates/ dir loses them
|
|
25
|
+
(`--stdout` cannot carry them at all). Isolates (`"use isolate"` modules)
|
|
26
|
+
exist in projects only, not for a file served on its own.
|
|
27
|
+
- `bunx srt bundle --json` is the dev server's rebuild contract: one JSON
|
|
28
|
+
object (code, sourcemap, manifest, isolates) on stdout. Not for humans.
|
|
29
|
+
|
|
30
|
+
## Fonts, identity and distribution
|
|
31
|
+
|
|
19
32
|
- Custom fonts go in `assets/fonts/` and are declared in the `solidrt.fonts`
|
|
20
33
|
map in package.json (alias -> file path; role aliases `sans`/`serif`/`mono`
|
|
21
34
|
replace the built-in defaults, `false` drops one, other keys add fonts
|
|
@@ -26,7 +39,8 @@ distribution.
|
|
|
26
39
|
folder, defaults from the package name in dev, and `srt pack` warns
|
|
27
40
|
while defaulted. `org` and `displayName` are optional display metadata
|
|
28
41
|
(future launcher/window naming) with no storage meaning.
|
|
29
|
-
- `bunx srt pack
|
|
30
|
-
|
|
42
|
+
- `bunx srt pack` builds a single-file executable (the runner with the
|
|
43
|
+
bytecode, manifest, assets and fonts appended as a trailer);
|
|
44
|
+
`bunx srt pack --folder` writes the flat app folder
|
|
31
45
|
(runner + manifest.json + bundle + assets/, plus the runner's GL
|
|
32
46
|
libraries on Windows and macOS) to `dist/pack/`.
|
package/agents/debugging.md
CHANGED
|
@@ -1,30 +1,46 @@
|
|
|
1
1
|
# Debugging a running app
|
|
2
2
|
|
|
3
3
|
Read this before investigating a bug in a running app, or before driving the
|
|
4
|
-
app over MCP
|
|
4
|
+
app to verify a change: over MCP, or through the same control API from a
|
|
5
|
+
shell or a CI step ("The control API without MCP" below).
|
|
5
6
|
|
|
6
7
|
## Driving the app over MCP
|
|
7
8
|
|
|
8
|
-
The project ships an MCP server (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
The project ships an MCP server (`srt mcp`) that talks to the dev server
|
|
10
|
+
`bunx srt run` starts. If your client lists no `solidrt` tools, it has not
|
|
11
|
+
been pointed at the server yet - see "Wiring up an agent client" below. Each
|
|
12
|
+
tool documents itself in full - read the tool description rather than guessing
|
|
13
|
+
at its arguments. What the individual descriptions cannot tell you:
|
|
12
14
|
|
|
13
15
|
- If `list_clients` is empty, no app is running: ask the user to start
|
|
14
|
-
`bunx srt run
|
|
15
|
-
The bridge
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
`bunx srt run` rather than starting a second one yourself.
|
|
17
|
+
The bridge needs no port: it resolves the server currently serving this
|
|
18
|
+
project, whatever `--port` it was started with, and re-resolves when
|
|
19
|
+
that server goes away or a different project's server takes its port.
|
|
20
|
+
Passing the flag to `srt mcp` pins the bridge to that one server instead.
|
|
18
21
|
- Several clients may be attached at once (desktop window, phone, tablet)
|
|
19
22
|
with different sizes, display scales and safe areas. `reload` pushes to all
|
|
20
|
-
of them, but `call_debug` / `send_input` / `get_snapshot`
|
|
21
|
-
|
|
22
|
-
client leaves the others sitting on the initial
|
|
23
|
-
crash to a human holding that device. So: when
|
|
24
|
-
`call_debug`, send the same call to every client (or say
|
|
25
|
-
are using); and before calling a visual change done,
|
|
26
|
-
form factor at least once - a layout that fits one
|
|
27
|
-
overflow another.
|
|
23
|
+
of them, but `call_debug` / `send_input` / `get_snapshot` are per client
|
|
24
|
+
(`get_logs` takes a `client` filter), and interactive state does NOT sync
|
|
25
|
+
- a flow driven on one client leaves the others sitting on the initial
|
|
26
|
+
screen, which reads as a crash to a human holding that device. So: when
|
|
27
|
+
driving state via `call_debug`, send the same call to every client (or say
|
|
28
|
+
which client you are using); and before calling a visual change done,
|
|
29
|
+
snapshot each distinct form factor at least once - a layout that fits one
|
|
30
|
+
window can clip or overflow another.
|
|
31
|
+
- Measuring or testing? `mute_user_input` first: it mutes the user's own
|
|
32
|
+
input on every client (a stray click or keypress mid-measurement corrupts
|
|
33
|
+
the result); `send_input` still works. `unmute_user_input` the moment you
|
|
34
|
+
are done, or whenever you need the human to press something: they see an
|
|
35
|
+
unresponsive client meanwhile. The bridge unmutes when it exits, the
|
|
36
|
+
server when it stops, but neither is a reason to leave a mute on.
|
|
37
|
+
- Editing? `pause_watch` first: the server reloads on save, and a
|
|
38
|
+
half-finished save would land on the user's screens as a build error or
|
|
39
|
+
a broken app. Edit, `reload`, then `resume_watch`. The two holds are
|
|
40
|
+
separate on purpose: the mute keeps the human out while you measure, the
|
|
41
|
+
pause keeps your own saves out while you edit, and a human editing next
|
|
42
|
+
to you keeps auto-reload unless you hold it. The bridge resumes when it
|
|
43
|
+
exits, but do not rely on that.
|
|
28
44
|
- A `shader` on `<window>` runs on the finished frame past the point every
|
|
29
45
|
capture reads: `get_snapshot` returns the UNSHADED content (window node
|
|
30
46
|
included), `get_texture` has no id for the shaded layer, and
|
|
@@ -40,6 +56,142 @@ descriptions cannot tell you:
|
|
|
40
56
|
~/.claude/settings.json to cover every solidrt project). This is the user's
|
|
41
57
|
call to make, once, in their own tooling.
|
|
42
58
|
|
|
59
|
+
## Wiring up an agent client
|
|
60
|
+
|
|
61
|
+
`.mcp.json` in the project root is Claude Code's convention, and a scaffolded
|
|
62
|
+
app ships one. MCP standardizes the protocol, not how a client discovers
|
|
63
|
+
servers, so every other client reads its own file. The entry is the same
|
|
64
|
+
everywhere, in the client's syntax:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{ "command": "bun", "args": ["node_modules/@solidrt/cli/bin/srt", "mcp"] }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Where it goes (these locations move between client releases; check the
|
|
71
|
+
client's own docs if it does not match):
|
|
72
|
+
|
|
73
|
+
- Claude Code: `.mcp.json` in the project root, under `mcpServers`. Claude
|
|
74
|
+
Code asks once, per project, before it will launch a server from this
|
|
75
|
+
file; until that is approved the `solidrt` tools are absent.
|
|
76
|
+
- Cursor: `.cursor/mcp.json`, under `mcpServers`
|
|
77
|
+
- VS Code / Copilot: `.vscode/mcp.json`, under `servers`
|
|
78
|
+
- Gemini CLI: `.gemini/settings.json`, under `mcpServers`
|
|
79
|
+
- Codex CLI: `~/.codex/config.toml`, under `[mcp_servers.solidrt]`
|
|
80
|
+
|
|
81
|
+
Several of these also ship a command that writes the entry for you
|
|
82
|
+
(`claude mcp add`, `codex mcp add`); prefer it over hand-editing.
|
|
83
|
+
|
|
84
|
+
The one constraint: the bridge must run with the project as its working
|
|
85
|
+
directory. It finds the dev server through the nearest package.json above
|
|
86
|
+
its cwd, and the `args` path is relative to the project root. A per-project
|
|
87
|
+
file gives that for free. A user-level entry works too, but only while the
|
|
88
|
+
client itself was launched from the project root (or the client supports a
|
|
89
|
+
`cwd` field and it is set); launched from elsewhere, every tool call answers
|
|
90
|
+
"No dev server for ..." while one is running.
|
|
91
|
+
|
|
92
|
+
## The dev server
|
|
93
|
+
|
|
94
|
+
What the dev server (`srt run` / `srt server`) is and what it serves.
|
|
95
|
+
|
|
96
|
+
- A dev server serves a project (started in its root: the cwd must hold the
|
|
97
|
+
package.json) or a single file (`srt run <file>` outside a project). Both
|
|
98
|
+
in one place is ambiguous, so `srt run <file>` in a project root needs
|
|
99
|
+
`--project` (the project, with this entry) or `--file` (the file alone).
|
|
100
|
+
Nothing searches upward for a package.json.
|
|
101
|
+
- One server per project or file. The server binds the port it had last
|
|
102
|
+
time, else the first free one from 34884 up, and prints it; `--port <N>`
|
|
103
|
+
pins it. Loopback only unless `--lan`.
|
|
104
|
+
- Dev state lives in `~/.solidrt/`: `servers/<key hash>/` holds each server's
|
|
105
|
+
`live.json` (the registry record, written by the server and removed at
|
|
106
|
+
exit), its remembered `port` and tunnel key; `clients/client<N>/` the
|
|
107
|
+
client trees. `srt client` and `srt mcp` resolve the server from the
|
|
108
|
+
registry by the project (or served file) at their cwd; `--port` pins one.
|
|
109
|
+
A record whose process died is pruned when the next server starts, and
|
|
110
|
+
resolution confirms a record against the server before using it.
|
|
111
|
+
- The server is one flux process, complete on its own:
|
|
112
|
+
`flux dist/server.js [file] [--project|--file] [--port N] [--lan]
|
|
113
|
+
[--proxy-http] [--capture f] [--tunnel] [--stats] [--client N ...] [-- args]`
|
|
114
|
+
(src/server/args.ts). It finds the platform binaries, bun and srt through
|
|
115
|
+
`SRT_PLATFORM_DIR`, `SRT_BUN` and `SRT_CLI`, which `srt` sets; started by
|
|
116
|
+
hand in a checkout it needs only `SRT_HOME`.
|
|
117
|
+
- Reload-on-save watches the bundle's inputs (every file the running
|
|
118
|
+
bundle was built from, dependencies included) and the `assets/` tree, not
|
|
119
|
+
a directory: a file the app does not import never triggers a rebuild.
|
|
120
|
+
While the last build failed, the source tree is watched as a whole until
|
|
121
|
+
a build succeeds. `POST /__control__/watch?active=false` pauses it (the
|
|
122
|
+
MCP `pause_watch` tool) while an agent edits; `POST /__control__/reload`
|
|
123
|
+
(the `reload` tool) is the agent's push.
|
|
124
|
+
|
|
125
|
+
## The control API without MCP
|
|
126
|
+
|
|
127
|
+
Every MCP tool is a thin wrapper over the dev server's HTTP control API, so
|
|
128
|
+
a shell script, a CI step, or an agent with no MCP bridge can drive the app
|
|
129
|
+
the same way. Base: `http://127.0.0.1:<port>/__control__/`, where `<port>`
|
|
130
|
+
is the one `srt run` printed at startup (also in the server's
|
|
131
|
+
`~/.solidrt/servers/*/live.json` record). GET unless noted;
|
|
132
|
+
every endpoint answers JSON and an error is `{ "error": "..." }` with a
|
|
133
|
+
4xx/5xx status, and every response carries `x-solidrt-project` (the key
|
|
134
|
+
served) and `x-solidrt-generation` (the server run) headers, so a caller can
|
|
135
|
+
confirm it reached the server it meant and notice a restart. Endpoints that
|
|
136
|
+
talk to a client take `?client=<id>` (from `/clients`); it may be omitted
|
|
137
|
+
when exactly one client is connected.
|
|
138
|
+
|
|
139
|
+
- `/clients` - `{ generation, key, mode, entry, projectDir, userInputMuted,
|
|
140
|
+
watchPaused, clients: [{ id, ... }] }`. Check `key` (the project root or
|
|
141
|
+
single file served) is the app you mean.
|
|
142
|
+
- `/logs?since=<seq>&level=<lvl>&contains=<text>&wait=<ms>&client=<id>` -
|
|
143
|
+
`{ entries: [{ seq, at, client, level, text, repeats? }], latest,
|
|
144
|
+
generation }`. Pass the previous `latest` as `since` to read only new
|
|
145
|
+
output; `client` keeps one client's entries (all clients without); a
|
|
146
|
+
changed `generation` means the server restarted and cursors and client
|
|
147
|
+
ids are stale.
|
|
148
|
+
- `/tree?query=<text>&root=<id>&depth=<n>&props=true` - `{ limit, matches:
|
|
149
|
+
[{ id, kind, path, x, y, width, height }] }` for a query, the nested tree
|
|
150
|
+
otherwise. Node ids are per client and change on reload; re-query after
|
|
151
|
+
`/reload`.
|
|
152
|
+
- `/snapshot?node=<id>` - `{ width, height, pngBase64 }`, display-scaled;
|
|
153
|
+
add `&format=raw` for `rgbaBase64` (RGBA8 bytes, no decoder needed for
|
|
154
|
+
pixel assertions), `&x=&y=&width=&height=` (all four) to crop,
|
|
155
|
+
`&scale=<1-8>`. Snapshot the smallest node that shows the change, not the
|
|
156
|
+
window root.
|
|
157
|
+
- `/texture?id=<textureId>` - same shape and options as `/snapshot`, at the
|
|
158
|
+
texture's native size (a scene or shader target behind a `<texture>` leaf).
|
|
159
|
+
- `/gpu?label=<text>` - the GPU resource inventory; `label` keeps only the
|
|
160
|
+
resources created with exactly that label (ids change on reload, labels
|
|
161
|
+
do not).
|
|
162
|
+
- `/buffer?id=<bufferId>&offset=<n>&length=<n>&as=<f32|u16|u8>` - vertex
|
|
163
|
+
buffer contents (default f32; reads cap at 64 KiB).
|
|
164
|
+
- `/stats?window=<ms>` - the performance statistics. POST
|
|
165
|
+
`/stats?active=true|false` switches the on-screen stats overlay instead
|
|
166
|
+
(the `set_stats_overlay` tool): one client with `&client=<id>`, every
|
|
167
|
+
client (and the setting new clients join with) without; `/clients`
|
|
168
|
+
reports each client's `stats`.
|
|
169
|
+
- `/debug` - the app's registered debug commands; POST
|
|
170
|
+
`/debug?name=<cmd>` with a JSON body as its args to call one.
|
|
171
|
+
- POST `/input` with `{ "events": [...] }` - synthetic input through the
|
|
172
|
+
real pipeline, same event shape as the `send_input` tool (tap real
|
|
173
|
+
coordinates read from `/tree`).
|
|
174
|
+
- POST `/clock?scale=<x>` (0 pauses) / `?step=<n>` frames while paused;
|
|
175
|
+
`{ scale, pendingSteps }` back. `/clients` reports each client's `timeScale`,
|
|
176
|
+
reset to 1 by every push.
|
|
177
|
+
- POST `/reload` - rebuild and push to every client; `{ ok, clients }` or
|
|
178
|
+
the build error.
|
|
179
|
+
- POST `/load` with `{ "entry": "<path>" }` - switch the entry and push it;
|
|
180
|
+
`{ ok, entry, clients }` or the build error. Relative paths resolve
|
|
181
|
+
against the project root (file mode: the served file's directory). A
|
|
182
|
+
project server only loads files inside its project.
|
|
183
|
+
- POST `/mute?active=true|false` - mute/unmute the user's own input on
|
|
184
|
+
every client, gamepads included (synthetic `/input` still goes through;
|
|
185
|
+
resize and close cannot be muted). `{ ok, active, clients }`. The mute
|
|
186
|
+
lifts when the server stops; unmute yourself when done.
|
|
187
|
+
- POST `/watch?active=true|false` - resume/pause reload-on-save (`active`
|
|
188
|
+
is whether it watches). `{ ok, active }`. Paused, saves push nothing
|
|
189
|
+
until `/reload`; changes made meanwhile are not replayed on resume. The
|
|
190
|
+
pause lifts when the server stops; resume yourself when done.
|
|
191
|
+
|
|
192
|
+
The loop is the same as over MCP: `/reload`, then `/logs?since=`, then
|
|
193
|
+
`/tree` for coordinates and `/snapshot` of the smallest relevant node.
|
|
194
|
+
|
|
43
195
|
## Lessons that cost real time
|
|
44
196
|
|
|
45
197
|
- console.log + get_logs is your primary probe into runtime state. For state
|