@solidrt/cli 0.0.50 → 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 +79 -36
- package/README.md +86 -15
- package/agents/assets.md +46 -0
- package/agents/debugging.md +294 -0
- package/dist/console.srtapp +94123 -73
- package/dist/server.js +3936 -0
- package/package.json +11 -10
- package/src/android/docs.md +21 -0
- package/src/android/main.ts +286 -0
- package/src/{bundler.ts → bundle/bundler.ts} +163 -76
- package/src/bundle/docs.md +12 -0
- package/src/bundle/main.ts +203 -0
- package/src/check/docs.md +10 -0
- package/src/check/main.ts +85 -0
- package/src/{commands/check.ts → check/typecheck.ts} +11 -34
- 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} +31 -25
- 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/pack/main.ts +86 -0
- package/src/pack/trailer.ts +97 -0
- package/src/render/docs.md +19 -0
- package/src/render/main.ts +49 -0
- 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 +246 -78
- 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/remap.ts +60 -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 -630
- 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 -68
- package/server/remap.ts +0 -47
- package/server/state.ts +0 -93
- package/src/args.ts +0 -212
- package/src/bundle-cli.ts +0 -13
- package/src/commands/bundle.ts +0 -76
- package/src/commands/client.ts +0 -34
- package/src/commands/mcp.ts +0 -603
- package/src/commands/pack.ts +0 -65
- package/src/commands/render.ts +0 -24
- 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/packer.ts +0 -103
- package/src/repl.ts +0 -233
- package/src/util.ts +0 -121
- package/src/watcher.ts +0 -69
- /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
|
@@ -23,13 +23,13 @@ const KEY_FILE = "tunnel.key"
|
|
|
23
23
|
/**
|
|
24
24
|
* Bind the tunnel endpoint and print its ticket (text + QR). The endpoint is
|
|
25
25
|
* kept stable across restarts so a paired client can re-dial the old ticket
|
|
26
|
-
* without re-scanning: the UDP port
|
|
27
|
-
* secret key is persisted in
|
|
28
|
-
* run). Both are needed - a moving
|
|
29
|
-
* the ticket. Stable across restarts on the same network only; a new machine IP
|
|
26
|
+
* without re-scanning: the UDP port follows the dev server's remembered port
|
|
27
|
+
* (ephemeral on a first run), and the secret key is persisted in
|
|
28
|
+
* <keyDir>/tunnel.key (generated on first run). Both are needed - a moving
|
|
29
|
+
* port or a fresh key each start would change the ticket. Stable across restarts on the same network only; a new machine IP
|
|
30
30
|
* still stales the ticket's addresses (that is the discovery/off-LAN story).
|
|
31
31
|
*/
|
|
32
|
-
export async function createTunnelEndpoint(port: number, keyDir: string): Promise<Endpoint> {
|
|
32
|
+
export async function createTunnelEndpoint(port: number | null, keyDir: string): Promise<Endpoint> {
|
|
33
33
|
let keyPath = join(keyDir, KEY_FILE)
|
|
34
34
|
|
|
35
35
|
let secretKey: string | undefined
|
|
@@ -39,7 +39,7 @@ export async function createTunnelEndpoint(port: number, keyDir: string): Promis
|
|
|
39
39
|
if (saved.length === 64) secretKey = saved
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
let endpoint = await Endpoint.create({ local: true, protocols: [TUNNEL_PROTOCOL], port, secretKey })
|
|
42
|
+
let endpoint = await Endpoint.create({ local: true, protocols: [TUNNEL_PROTOCOL], ...(port !== null ? { port } : {}), secretKey })
|
|
43
43
|
|
|
44
44
|
// First run (no saved key): persist the freshly generated one so the next run
|
|
45
45
|
// reuses it and the ticket stays the same.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { dir } from "flux:fs"
|
|
2
|
+
import { state } from "./state"
|
|
3
|
+
import { dirname } from "./mode"
|
|
4
|
+
import { rebuildAndBroadcast, showBuildFailure } from "./rebuild"
|
|
5
|
+
|
|
6
|
+
// Reload-on-save. Not a directory watch: the watch set is the bundle's own
|
|
7
|
+
// input list (BundleOutput.inputs: the app's modules, the dependency modules
|
|
8
|
+
// bundled in, inlined files, package.json, tsconfig.json), so a source file
|
|
9
|
+
// the running app does not import, or a dependency it does not use, never
|
|
10
|
+
// triggers anything, while an edit to a workspace package it does import
|
|
11
|
+
// does. Each input's parent directory is watched (never the file itself: an
|
|
12
|
+
// editor's atomic save replaces the inode, which a file watch would lose)
|
|
13
|
+
// and events are matched by name within that directory. On top of that, in
|
|
14
|
+
// project mode, the whole assets/ tree: the manifest lists the tree, so any
|
|
15
|
+
// change to it is a new version. While the last build failed the input list
|
|
16
|
+
// is gone, so the source directory is watched as a whole until a build
|
|
17
|
+
// succeeds again (the missing-import case: the file the build waits for is
|
|
18
|
+
// not in any list yet). Every hit debounces into the one
|
|
19
|
+
// rebuildAndBroadcast() path, which re-arms the watch from the new inputs.
|
|
20
|
+
// Paused by the MCP pause_watch tool while an agent edits (state.watchPaused):
|
|
21
|
+
// changes made meanwhile are not pushed; the agent's reload is.
|
|
22
|
+
|
|
23
|
+
const DEBOUNCE_MS = 100
|
|
24
|
+
const SOURCE_EXT = /\.(tsx?|jsx?)$/
|
|
25
|
+
|
|
26
|
+
let offs: (() => void)[] = []
|
|
27
|
+
let timer: ReturnType<typeof setTimeout> | null = null
|
|
28
|
+
let changed = new Set<string>()
|
|
29
|
+
let building = false
|
|
30
|
+
let dirty = false
|
|
31
|
+
|
|
32
|
+
function basename(path: string): string {
|
|
33
|
+
return path.slice(Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) + 1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A path with a dot component (below `root` when given) is never a source:
|
|
37
|
+
// .srt-data in particular is this server's own output, and rebuilding on it
|
|
38
|
+
// would rebuild forever. node_modules is the same in file mode, where the
|
|
39
|
+
// source directory may be a project root.
|
|
40
|
+
function isToolingPath(path: string, root: string): boolean {
|
|
41
|
+
let rel = path.startsWith(root) ? path.slice(root.length) : path
|
|
42
|
+
return rel.split(/[\\/]/).some((part) => part.startsWith(".") || part === "node_modules")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Arm the watch from a build's inputs; null (a failed build) watches the source tree as a whole. */
|
|
46
|
+
export function armWatcher(inputs: string[] | null) {
|
|
47
|
+
stopWatcher()
|
|
48
|
+
let config = state.config
|
|
49
|
+
let hit = (path: string) => onChange(path)
|
|
50
|
+
try {
|
|
51
|
+
if (inputs) {
|
|
52
|
+
let byDir = new Map<string, Set<string>>()
|
|
53
|
+
for (let input of inputs) {
|
|
54
|
+
let parent = dirname(input)
|
|
55
|
+
let names = byDir.get(parent)
|
|
56
|
+
if (!names) byDir.set(parent, (names = new Set()))
|
|
57
|
+
names.add(basename(input))
|
|
58
|
+
}
|
|
59
|
+
for (let [parent, names] of byDir) {
|
|
60
|
+
offs.push(dir(parent).watch((e) => names.has(basename(e.path)) && hit(e.path)))
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
let root = config.sourceDir
|
|
64
|
+
offs.push(
|
|
65
|
+
dir(root).watch((e) => SOURCE_EXT.test(e.path) && !isToolingPath(e.path, root) && hit(e.path), { recursive: true }),
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
if (config.projectDir) {
|
|
69
|
+
let assets = `${config.projectDir}/assets`
|
|
70
|
+
dir(assets)
|
|
71
|
+
.exists()
|
|
72
|
+
.then((exists) => {
|
|
73
|
+
if (exists && offs.length) offs.push(dir(assets).watch((e) => !isToolingPath(e.path, assets) && hit(e.path), { recursive: true }))
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.error(`[cli] Watch failed: ${e instanceof Error ? e.message : e}`)
|
|
78
|
+
stopWatcher()
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Drop every watch; the engine loop can go idle. */
|
|
83
|
+
export function stopWatcher() {
|
|
84
|
+
for (let off of offs) off()
|
|
85
|
+
offs = []
|
|
86
|
+
if (timer !== null) clearTimeout(timer)
|
|
87
|
+
timer = null
|
|
88
|
+
changed.clear()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function onChange(path: string) {
|
|
92
|
+
if (state.watchPaused) return
|
|
93
|
+
changed.add(path)
|
|
94
|
+
if (building) {
|
|
95
|
+
dirty = true
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
if (timer !== null) clearTimeout(timer)
|
|
99
|
+
timer = setTimeout(() => void rebuild(), DEBOUNCE_MS)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// One rebuild per burst; a change that lands while the bundle runs queues
|
|
103
|
+
// exactly one more, since the running build cannot have seen it.
|
|
104
|
+
async function rebuild() {
|
|
105
|
+
timer = null
|
|
106
|
+
building = true
|
|
107
|
+
let root = state.config.projectDir ?? state.config.sourceDir
|
|
108
|
+
let names = [...changed].map((p) => (p.startsWith(root) ? p.slice(root.length + 1) : p))
|
|
109
|
+
changed.clear()
|
|
110
|
+
console.log(`[cli] Change detected: ${names.slice(0, 3).join(", ")}${names.length > 3 ? ` (+${names.length - 3})` : ""}`)
|
|
111
|
+
let error = await rebuildAndBroadcast()
|
|
112
|
+
if (error) {
|
|
113
|
+
console.error(error)
|
|
114
|
+
showBuildFailure()
|
|
115
|
+
}
|
|
116
|
+
building = false
|
|
117
|
+
if (dirty) {
|
|
118
|
+
dirty = false
|
|
119
|
+
onChange(names[0] ?? root)
|
|
120
|
+
}
|
|
121
|
+
}
|
package/src/tool/main.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { readdirSync } from "node:fs"
|
|
2
|
+
import { join, resolve } from "node:path"
|
|
3
|
+
import { source, toolArgs } from "../lib/args"
|
|
4
|
+
|
|
5
|
+
// srt tool: the tools the installed @solidrt packages ship - build-time
|
|
6
|
+
// helpers that belong to an extension, not to core (a model converter in
|
|
7
|
+
// @solidrt/3d, say). Discovery is by convention, like demos: every
|
|
8
|
+
// `<package>/tools/<name>.ts` is a tool named `<package>/<name>`, run with
|
|
9
|
+
// bun in the caller's cwd with the arguments after the tool name passed
|
|
10
|
+
// through untouched. srt knows nothing about what a tool does; a tool
|
|
11
|
+
// prints its own usage.
|
|
12
|
+
|
|
13
|
+
type Tool = { name: string; script: string }
|
|
14
|
+
|
|
15
|
+
const SCOPE = join("node_modules", "@solidrt")
|
|
16
|
+
|
|
17
|
+
/** Every tool installed here, sorted so the listing is stable. The cwd and
|
|
18
|
+
* nothing above it - the same rule demos follow, so this lists what THIS
|
|
19
|
+
* project installed. */
|
|
20
|
+
function discover(): Tool[] {
|
|
21
|
+
let tools: Tool[] = []
|
|
22
|
+
for (let pkg of names(SCOPE)) {
|
|
23
|
+
let dir = join(SCOPE, pkg, "tools")
|
|
24
|
+
for (let file of names(dir)) {
|
|
25
|
+
if (!file.endsWith(".ts")) continue
|
|
26
|
+
tools.push({ name: `${pkg}/${file.slice(0, -".ts".length)}`, script: resolve(dir, file) })
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return tools
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// A missing folder is the normal case (most packages ship no tools), so it
|
|
33
|
+
// reads as an empty one rather than an error.
|
|
34
|
+
function names(dir: string): string[] {
|
|
35
|
+
try {
|
|
36
|
+
return readdirSync(dir).sort()
|
|
37
|
+
} catch {
|
|
38
|
+
return []
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function list(tools: Tool[]) {
|
|
43
|
+
for (let tool of tools) console.log(` ${tool.name}`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function main(): Promise<void> {
|
|
47
|
+
let tools = discover()
|
|
48
|
+
if (tools.length === 0) {
|
|
49
|
+
console.error(`No tools installed in ${process.cwd()} (looked in ${SCOPE}/*/tools/)`)
|
|
50
|
+
process.exit(1)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (source === undefined) {
|
|
54
|
+
list(tools)
|
|
55
|
+
console.log("\nRun one with: srt tool <pkg>/<name> [arguments]")
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let picked = tools.find((t) => t.name === source)
|
|
60
|
+
if (!picked) {
|
|
61
|
+
console.error(`No such tool: ${source}`)
|
|
62
|
+
list(tools)
|
|
63
|
+
process.exit(1)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let proc = Bun.spawn([process.execPath, picked.script, ...toolArgs], {
|
|
67
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
68
|
+
})
|
|
69
|
+
process.exit(await proc.exited)
|
|
70
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// What `srt bundle --json` (src/bundle/main.ts, a bun subprocess of the
|
|
2
|
+
// dev server) writes to stdout as one JSON object and the dev server
|
|
3
|
+
// (src/server/rebuild.ts) reads back. src/types/ holds the type-only contracts
|
|
4
|
+
// between the two programs: each has its own tsconfig (bun types on one
|
|
5
|
+
// side, flux types on the other), both include this folder, so nothing here
|
|
6
|
+
// may reference either runtime.
|
|
7
|
+
|
|
8
|
+
export type BundleOutput = {
|
|
9
|
+
code: string
|
|
10
|
+
/** Composed sourcemap JSON (bundle -> original .tsx sources), dev builds only. */
|
|
11
|
+
map: string | null
|
|
12
|
+
/** Version manifest JSON for this bundle; clients install pushes under its hash. */
|
|
13
|
+
manifest: string
|
|
14
|
+
/** The app's isolate bundles, one per "use isolate" module, in id order; maps dev builds only. */
|
|
15
|
+
isolates: { id: string; code: string; map: string | null }[]
|
|
16
|
+
/**
|
|
17
|
+
* Every file this bundle was built from, absolute and sorted: the app's
|
|
18
|
+
* modules, the dependency modules bundled in, files inlined by import
|
|
19
|
+
* attribute, and the project's package.json / tsconfig.json. The assets/
|
|
20
|
+
* tree is not listed (the manifest carries it). What the dev server
|
|
21
|
+
* watches for reload-on-save.
|
|
22
|
+
*/
|
|
23
|
+
inputs: string[]
|
|
24
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// The control API (/__control__/, server/control.ts) response shapes the
|
|
2
|
+
// MCP bridge (src/mcp/main.ts) reads fields from. Only the server-held
|
|
3
|
+
// answers are shaped here; queries forwarded to a client return whatever the
|
|
4
|
+
// client runtime answers. See bundle.d.ts for the folder.
|
|
5
|
+
|
|
6
|
+
export type ClientEntry = {
|
|
7
|
+
id: number
|
|
8
|
+
platform: string
|
|
9
|
+
/** The client runtime's version (git describe). */
|
|
10
|
+
version: string
|
|
11
|
+
/** Build profile: debug or release. */
|
|
12
|
+
profile: string
|
|
13
|
+
capabilities: string[]
|
|
14
|
+
/** Query kinds this client's runtime answers (empty on runtimes that predate
|
|
15
|
+
* the advertisement); dev tools plan their verification surface from it. */
|
|
16
|
+
queries: string[]
|
|
17
|
+
/** The client's storage tree on its own machine (`<data-root>/client<N>`
|
|
18
|
+
* for a dev client, the install folder for the launcher or a packed app),
|
|
19
|
+
* or null when it runs without writable storage or predates the field. */
|
|
20
|
+
clientDir: string | null
|
|
21
|
+
/** Whether its stats overlay is drawn (see POST /stats). */
|
|
22
|
+
stats: boolean
|
|
23
|
+
/** Its time scale as the client last reported it to POST /clock: 0 paused,
|
|
24
|
+
* 1 real time. Back to 1 on every push (a reload restarts the clock). */
|
|
25
|
+
timeScale: number
|
|
26
|
+
/** The client's process id on its own machine. */
|
|
27
|
+
pid: number | null
|
|
28
|
+
/** The runtime binary it runs. */
|
|
29
|
+
execPath: string | null
|
|
30
|
+
/** Its machine's hostname. */
|
|
31
|
+
host: string | null
|
|
32
|
+
/** The OS as a person names it ("Linux (Ubuntu 24.04)", "Android 15 on Pixel 9 Pro"). */
|
|
33
|
+
os: string | null
|
|
34
|
+
/** The kernel version. */
|
|
35
|
+
kernel: string | null
|
|
36
|
+
/** The SDL video driver ("wayland", "x11", "android", "offscreen", ...). */
|
|
37
|
+
videoDriver: string | null
|
|
38
|
+
/** The GPU strings as GL reports them; null on a client that connected
|
|
39
|
+
* before its GL context existed (a reconnect fills it in). */
|
|
40
|
+
gpu: GpuInfo | null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type GpuInfo = { vendor: string; renderer: string; version: string }
|
|
44
|
+
|
|
45
|
+
/** GET /clients */
|
|
46
|
+
export type ClientsResponse = {
|
|
47
|
+
/** Identity of this server run: client ids and log cursors are only valid within one. */
|
|
48
|
+
generation: number
|
|
49
|
+
key: string
|
|
50
|
+
mode: "project" | "file"
|
|
51
|
+
entry: string
|
|
52
|
+
projectDir: string | null
|
|
53
|
+
/** Whether the user's own input is muted on every client (see /mute). */
|
|
54
|
+
userInputMuted: boolean
|
|
55
|
+
/** Whether reload-on-save is paused (see /watch). */
|
|
56
|
+
watchPaused: boolean
|
|
57
|
+
clients: ClientEntry[]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type LogEntry = { seq: number; at: number; client: number; level: string; text: string }
|
|
61
|
+
|
|
62
|
+
/** GET /logs */
|
|
63
|
+
export type LogsResponse = {
|
|
64
|
+
/** Consecutive identical entries come back as one, with `repeats`. */
|
|
65
|
+
entries: (LogEntry & { repeats?: number })[]
|
|
66
|
+
/** The next `since` cursor. */
|
|
67
|
+
latest: number
|
|
68
|
+
generation: number
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** POST /reload */
|
|
72
|
+
export type ReloadResponse = { ok: true; clients: number }
|
|
73
|
+
|
|
74
|
+
/** POST /load: the canonical entry now served. */
|
|
75
|
+
export type LoadResponse = { ok: true; entry: string; clients: number }
|
|
76
|
+
|
|
77
|
+
/** POST /mute: the mute state now in force and the clients told. */
|
|
78
|
+
export type MuteResponse = { ok: true; active: boolean; clients: number }
|
|
79
|
+
|
|
80
|
+
/** POST /stats: whether the overlay is now on, and on how many clients. */
|
|
81
|
+
export type StatsResponse = { ok: true; active: boolean; clients: number }
|
|
82
|
+
|
|
83
|
+
/** POST /watch: whether reload-on-save is now active. */
|
|
84
|
+
export type WatchResponse = { ok: true; active: boolean }
|
|
85
|
+
|
|
86
|
+
/** GET /snapshot and /texture: png by default, RGBA8 bytes with format=raw. */
|
|
87
|
+
export type ImageResponse = { width: number; height: number; pngBase64?: string; rgbaBase64?: string }
|
|
88
|
+
|
|
89
|
+
/** Every non-2xx answer. */
|
|
90
|
+
export type ControlError = { error: string }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The dev server registry record: ~/.solidrt/servers/<key hash>/live.json,
|
|
2
|
+
// written by the server (server/registry.ts) and read by srt client, srt mcp
|
|
3
|
+
// and the launcher (src/lib/registry.ts). See bundle.d.ts for the folder.
|
|
4
|
+
|
|
5
|
+
export type LiveRecord = {
|
|
6
|
+
pid: number
|
|
7
|
+
port: number
|
|
8
|
+
address: string
|
|
9
|
+
/** The canonical project root or file path (see src/lib/mode.ts). */
|
|
10
|
+
key: string
|
|
11
|
+
mode: "project" | "file"
|
|
12
|
+
entry: string
|
|
13
|
+
projectDir: string | null
|
|
14
|
+
/** ISO timestamp of the bind. */
|
|
15
|
+
started: string
|
|
16
|
+
}
|