@solidrt/cli 0.0.32 → 0.0.33
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 +3 -5
- package/fonts/NotoSans.ttf +0 -0
- package/fonts/NotoSansMono.ttf +0 -0
- package/fonts/NotoSerif.ttf +0 -0
- package/fonts/OFL.txt +93 -0
- package/package.json +8 -7
- package/scaffold/AGENTS.md +26 -0
- package/scaffold/gitignore +2 -1
- package/scaffold/package.json +4 -4
- package/server/cache.ts +5 -3
- package/server/main.ts +26 -39
- package/server/rebuild.ts +11 -6
- package/server/state.ts +7 -2
- package/server/tunnel.ts +5 -5
- package/src/args.ts +25 -2
- package/src/bundler.ts +5 -1
- package/src/commands/client.ts +11 -7
- package/src/commands/init.ts +6 -0
- package/src/commands/pack.ts +43 -7
- package/src/commands/server.ts +11 -3
- package/src/dev-client.ts +2 -2
- package/src/dev-server.ts +29 -9
- package/src/fonts.ts +91 -0
- package/src/pack-folder.ts +112 -0
- package/src/packer.ts +55 -12
- package/src/project.ts +171 -0
- package/src/repl.ts +11 -3
- package/src/util.ts +6 -0
- package/src/watcher.ts +53 -27
package/src/repl.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { readdirSync } from "node:fs"
|
|
|
4
4
|
import { state, print, printErr, shutdown } from "./util"
|
|
5
5
|
import { buildReload, getClients, sendReload, sendStop, sendStats, sendWatch, showBuildFailure } from "./dev-server"
|
|
6
6
|
import { bundle } from "./bundler"
|
|
7
|
+
import { buildManifest, projectDirFor } from "./project"
|
|
7
8
|
import { startWatcher, stopWatcher } from "./watcher"
|
|
8
9
|
|
|
9
10
|
// Resolve repl client indexes ("0 2") against the server's client list,
|
|
@@ -28,6 +29,7 @@ async function cmdStop(args: string) {
|
|
|
28
29
|
stopWatcher()
|
|
29
30
|
state.currentCode = null
|
|
30
31
|
state.currentMap = null
|
|
32
|
+
state.currentManifest = null
|
|
31
33
|
state.source = undefined
|
|
32
34
|
await sendStop()
|
|
33
35
|
print("[cli] Sent stop to all clients")
|
|
@@ -50,8 +52,9 @@ async function cmdReload(args: string) {
|
|
|
50
52
|
}
|
|
51
53
|
state.currentCode = result.code
|
|
52
54
|
state.currentMap = result.map
|
|
55
|
+
state.currentManifest = result.manifest
|
|
53
56
|
}
|
|
54
|
-
let msg = buildReload({ code: state.currentCode })
|
|
57
|
+
let msg = buildReload({ code: state.currentCode, manifest: state.currentManifest })
|
|
55
58
|
if (!args) {
|
|
56
59
|
await sendReload(msg, { latch: true, map: state.currentMap })
|
|
57
60
|
print("[cli] Sent reload to all clients")
|
|
@@ -106,9 +109,11 @@ async function cmdLoad(file: string) {
|
|
|
106
109
|
}
|
|
107
110
|
state.currentCode = result.code
|
|
108
111
|
state.currentMap = result.map
|
|
112
|
+
state.currentManifest = result.manifest
|
|
109
113
|
} else if (file.endsWith(".srt.js")) {
|
|
110
114
|
state.currentCode = await Bun.file(path).text()
|
|
111
115
|
state.currentMap = null
|
|
116
|
+
state.currentManifest = buildManifest(state.currentCode, path)
|
|
112
117
|
} else if (file.endsWith(".srt.bin")) {
|
|
113
118
|
let bytes = await Bun.file(path).arrayBuffer()
|
|
114
119
|
// One-shot: bytecode loads are pushed but not latched for late joiners.
|
|
@@ -121,12 +126,15 @@ async function cmdLoad(file: string) {
|
|
|
121
126
|
}
|
|
122
127
|
state.source = path
|
|
123
128
|
state.sourceDir = dirname(path)
|
|
129
|
+
state.projectDir = projectDirFor(path)
|
|
124
130
|
startWatcher()
|
|
125
131
|
// The load also moves the server's file-serving root to the new source dir,
|
|
126
|
-
//
|
|
127
|
-
|
|
132
|
+
// its /assets/ root to the new project dir, and its rebuild entry to the
|
|
133
|
+
// new file (for a later MCP reload).
|
|
134
|
+
await sendReload(buildReload({ code: state.currentCode, manifest: state.currentManifest }), {
|
|
128
135
|
latch: true,
|
|
129
136
|
sourceDir: state.sourceDir,
|
|
137
|
+
projectDir: state.projectDir,
|
|
130
138
|
entry: file.endsWith(".tsx") ? path : undefined,
|
|
131
139
|
map: state.currentMap,
|
|
132
140
|
})
|
package/src/util.ts
CHANGED
|
@@ -11,8 +11,14 @@ export let state = {
|
|
|
11
11
|
// The bundle's composed sourcemap (dev builds), sent to the server alongside
|
|
12
12
|
// reloads so it can remap logged stack traces to .tsx positions.
|
|
13
13
|
currentMap: null as string | null,
|
|
14
|
+
// The bundle's version manifest (canonical JSON string, see buildManifest);
|
|
15
|
+
// travels with code reloads so clients install the push as a version.
|
|
16
|
+
currentManifest: null as string | null,
|
|
14
17
|
source: undefined as string | undefined,
|
|
15
18
|
sourceDir: process.cwd(),
|
|
19
|
+
// The project root the assets/ convention hangs off (see project.ts
|
|
20
|
+
// projectDirFor); the server's /assets/ route serves from under it.
|
|
21
|
+
projectDir: process.cwd(),
|
|
16
22
|
child: null as ReturnType<typeof Bun.spawn> | null,
|
|
17
23
|
// The spawned flux dev-server process (see dev-server.ts startServer).
|
|
18
24
|
serverProc: null as ReturnType<typeof Bun.spawn> | null,
|
package/src/watcher.ts
CHANGED
|
@@ -1,43 +1,69 @@
|
|
|
1
|
-
import { watch } from "node:fs"
|
|
2
|
-
import { resolve, dirname } from "path"
|
|
1
|
+
import { existsSync, watch } from "node:fs"
|
|
2
|
+
import { resolve, dirname, sep, basename } from "path"
|
|
3
3
|
import { state, print, printErr } from "./util"
|
|
4
4
|
import { buildReload, sendReload, showBuildFailure, watchAllowed } from "./dev-server"
|
|
5
5
|
import { bundle } from "./bundler"
|
|
6
6
|
|
|
7
|
-
let
|
|
7
|
+
let watchers: ReturnType<typeof watch>[] = []
|
|
8
8
|
|
|
9
9
|
export function stopWatcher() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
for (let w of watchers) w.close()
|
|
11
|
+
watchers = []
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function rebuild(filename: string) {
|
|
15
|
+
if (!(await watchAllowed())) {
|
|
16
|
+
print(`[cli] Change detected: ${filename} (auto-reload paused by agent; "watch on" resumes)`)
|
|
17
|
+
return
|
|
13
18
|
}
|
|
19
|
+
|
|
20
|
+
print(`[cli] Change detected: ${filename}`)
|
|
21
|
+
let result = await bundle(state.source)
|
|
22
|
+
if (!result) {
|
|
23
|
+
printErr("[cli] Build failed, waiting for changes...")
|
|
24
|
+
await showBuildFailure()
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
state.currentCode = result.code
|
|
28
|
+
state.currentMap = result.map
|
|
29
|
+
state.currentManifest = result.manifest
|
|
30
|
+
await sendReload(buildReload({ code: state.currentCode, manifest: state.currentManifest }), {
|
|
31
|
+
latch: true,
|
|
32
|
+
map: state.currentMap,
|
|
33
|
+
})
|
|
14
34
|
}
|
|
15
35
|
|
|
16
36
|
export function startWatcher() {
|
|
17
37
|
if (!state.source) return
|
|
18
38
|
let watchDir = dirname(resolve(state.source))
|
|
19
39
|
|
|
20
|
-
|
|
40
|
+
stopWatcher()
|
|
41
|
+
|
|
42
|
+
// An asset edit re-pushes too: the assets/ tree is part of the manifest, so
|
|
43
|
+
// clients install the new version. The tree roots at the project dir; the
|
|
44
|
+
// project dir is an ancestor of (or equal to) the entry's dir, so assets/
|
|
45
|
+
// is inside watchDir exactly when they are the same dir. An assets/ folder
|
|
46
|
+
// created after startup needs a restart or `load` to be picked up.
|
|
47
|
+
let assetsDir = resolve(state.projectDir, "assets")
|
|
48
|
+
let covered = resolve(state.projectDir) === watchDir
|
|
49
|
+
let isAsset = (filename: string) =>
|
|
50
|
+
(filename === "assets" || filename.startsWith("assets" + sep)) && !basename(filename).startsWith(".")
|
|
21
51
|
|
|
22
52
|
print(`[cli] Watching ${watchDir} for changes...`)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
state.currentCode = result.code
|
|
40
|
-
state.currentMap = result.map
|
|
41
|
-
await sendReload(buildReload({ code: state.currentCode }), { latch: true, map: state.currentMap })
|
|
42
|
-
})
|
|
53
|
+
watchers.push(
|
|
54
|
+
watch(watchDir, { recursive: true }, (_event, filename) => {
|
|
55
|
+
if (!filename) return
|
|
56
|
+
if (!/\.(tsx?|jsx?)$/.test(filename) && !(covered && isAsset(filename))) return
|
|
57
|
+
rebuild(filename)
|
|
58
|
+
}),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if (!covered && existsSync(assetsDir)) {
|
|
62
|
+
watchers.push(
|
|
63
|
+
watch(assetsDir, { recursive: true }, (_event, filename) => {
|
|
64
|
+
if (!filename || basename(filename).startsWith(".")) return
|
|
65
|
+
rebuild("assets" + sep + filename)
|
|
66
|
+
}),
|
|
67
|
+
)
|
|
68
|
+
}
|
|
43
69
|
}
|