lecodes-cli 0.20.2 → 2.0.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 +56 -57
- package/dist/index.js +11052 -7592
- package/package.json +14 -8
- package/runtime/materials/decal-relief.mat +12 -1
- package/runtime/materials/decal.mat +17 -3
- package/runtime/materials/lightmap.mat +117 -138
- package/runtime/materials/particles-quad.mat +6 -2
- package/runtime/materials/terrain-lightmap.mat +123 -0
- package/runtime/materials/terrain.mat +36 -55
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/VERSION.json +5 -0
- package/runtime/web/assets/camera-5XOM8eHl.js +1 -0
- package/runtime/web/assets/creator-2d-D9WKYM6h.js +1 -0
- package/runtime/web/assets/creator-2d-ukvEmNEp.wasm +0 -0
- package/runtime/web/assets/creator-full-BBXzQlhq.js +1 -0
- package/runtime/web/assets/creator-full-D2dSDdDj.wasm +0 -0
- package/runtime/web/assets/creator-full.js-BYswGsqR.symbols +8124 -0
- package/runtime/web/assets/creator-ui-DIc92ion.wasm +0 -0
- package/runtime/web/assets/creator-ui-_1Z_AX2M.js +1 -0
- package/runtime/web/assets/geolocation-BjTKN9_P.js +1 -0
- package/runtime/web/assets/inspect-C7x78PNs.js +2 -0
- package/runtime/web/assets/map-CyBxOSV0.js +1 -0
- package/runtime/web/assets/map-XzoOFt0E.js +2 -0
- package/runtime/web/assets/mapImpl-bxvQ2h1Z.js +823 -0
- package/runtime/web/assets/maplibre-gl-worker-B7LXXUkR.js +8 -0
- package/runtime/web/assets/materials-uri4FvPE.bin +0 -0
- package/runtime/web/assets/materials-world-CQWt8TAm.bin +0 -0
- package/runtime/web/assets/qr-scanner-CK_cYoJR.js +1 -0
- package/runtime/web/assets/uberarchive-DLH-kBhM.bin +0 -0
- package/runtime/web/index.html +36 -0
- package/runtime/web/player.js +21 -0
- package/runtime/web-page/index.html +41 -0
- package/runtime/web-page/page.css +1 -0
- package/runtime/web-page/page.js +31 -0
- package/src/api.ts +1 -302
- package/src/cli/args.ts +37 -0
- package/src/cli/command.ts +113 -0
- package/src/cli/errors.ts +13 -0
- package/src/cli/help.ts +158 -0
- package/src/cli/index.ts +7 -0
- package/src/cli/output.ts +102 -0
- package/src/cli/run.ts +106 -0
- package/src/commands/{appAndroid.ts → app/android.ts} +454 -43
- package/src/commands/{appDesktop.ts → app/desktop.ts} +64 -33
- package/src/commands/{appDesktopMac.ts → app/desktopMac.ts} +34 -27
- package/src/commands/{appIcon.ts → app/icon.ts} +11 -8
- package/src/commands/{app.ts → app/index.ts} +400 -290
- package/src/commands/{appShared.ts → app/shared.ts} +43 -44
- package/src/commands/{appTemplatesAndroid.ts → app/templates/android.ts} +72 -39
- package/src/commands/{appTemplatesGradlew.ts → app/templates/gradlew.ts} +1 -1
- package/src/commands/{appTemplates.ts → app/templates/ios.ts} +2 -2
- package/src/commands/assets.ts +23 -21
- package/src/commands/clone.ts +48 -51
- package/src/commands/compile.ts +76 -89
- package/src/commands/create.ts +46 -47
- package/src/commands/design/comments.ts +361 -0
- package/src/commands/design/context.ts +101 -0
- package/src/commands/design/index.ts +391 -0
- package/src/commands/design/snapshot.ts +134 -0
- package/src/commands/{designTemplates.ts → design/templates.ts} +4 -3
- package/src/commands/desktop.ts +94 -82
- package/src/commands/dev.ts +260 -182
- package/src/commands/diff.ts +39 -51
- package/src/commands/index.ts +64 -0
- package/src/commands/{init.ts → init/index.ts} +195 -191
- package/src/commands/{projectTemplates.ts → init/templates.ts} +64 -21
- package/src/commands/install.ts +80 -67
- package/src/commands/lightmap.ts +543 -252
- package/src/commands/link.ts +87 -94
- package/src/commands/login.ts +25 -23
- package/src/commands/navmesh.ts +169 -139
- package/src/commands/plugin.ts +46 -0
- package/src/commands/pn.ts +201 -244
- package/src/commands/pull.ts +49 -56
- package/src/commands/push.ts +48 -54
- package/src/commands/render.ts +176 -111
- package/src/commands/scene.ts +63 -55
- package/src/commands/serve.ts +58 -0
- package/src/commands/{shaders.ts → shaders/index.ts} +61 -42
- package/src/commands/{shadersNew.ts → shaders/new.ts} +3 -3
- package/src/commands/shared.ts +79 -0
- package/src/commands/status.ts +22 -26
- package/src/commands/test.ts +94 -63
- package/src/commands/thumbs.ts +185 -175
- package/src/commands/update/index.ts +226 -0
- package/src/commands/{types.ts → update/types.ts} +31 -22
- package/src/compile/collect.ts +5 -5
- package/src/compile/collectLocal.ts +3 -3
- package/src/compile/designCompile.ts +4 -4
- package/src/compile/headlessBundle.ts +16 -12
- package/src/compile/nativeStack.ts +1 -1
- package/src/compile/projectCompile.ts +12 -4
- package/src/compile/sceneCompile.ts +14 -26
- package/src/compile/screenEntry.ts +123 -127
- package/src/compile/shaders.ts +3 -3
- package/src/{lecodes-3d-editor.d.ts → declarations/lecodes-3d-editor.d.ts} +4 -0
- package/src/{lecodes-assets.d.ts → declarations/lecodes-assets.d.ts} +1 -1
- package/src/{lecodes-renderer.d.ts → declarations/lecodes-headless.d.ts} +3 -3
- package/src/dev/androidDev.ts +1 -1
- package/src/dev/clientTemplates.ts +18 -14
- package/src/dev/devServer.ts +78 -41
- package/src/dev/iosDev.ts +180 -0
- package/src/dev/webRunner.ts +83 -15
- package/src/{cmgenTool.ts → hosts/cmgenTool.ts} +2 -2
- package/src/{desktopRenderer.ts → hosts/desktopRenderer.ts} +104 -32
- package/src/{desktopScript.ts → hosts/desktopScript.ts} +151 -36
- package/src/{distRoot.ts → hosts/distRoot.ts} +9 -5
- package/src/{matcTool.ts → hosts/matcTool.ts} +2 -2
- package/src/{peerInstall.ts → hosts/peerInstall.ts} +7 -7
- package/src/{peers.ts → hosts/peers.ts} +2 -2
- package/src/{releases.ts → hosts/releases.ts} +1 -1
- package/src/index.ts +35 -480
- package/src/platform/api.ts +302 -0
- package/src/{browserAuth.ts → platform/browserAuth.ts} +1 -1
- package/src/{config.ts → platform/config.ts} +1 -1
- package/src/{serverDiff.ts → platform/serverDiff.ts} +3 -3
- package/src/plugin/contract.ts +438 -0
- package/src/plugin/emitKotlin.ts +357 -0
- package/src/plugin/emitSdk.ts +259 -0
- package/src/plugin/emitSwift.ts +336 -0
- package/src/plugin/emitWeb.ts +383 -0
- package/src/plugin/generate.ts +157 -0
- package/src/plugin/lines.ts +28 -0
- package/src/plugin/lower.ts +231 -0
- package/src/plugin/manifest.ts +192 -0
- package/src/{projectEnv.ts → project/env.ts} +33 -2
- package/src/{ignore.ts → project/ignore.ts} +164 -163
- package/src/{localFiles.ts → project/localFiles.ts} +1 -1
- package/src/{manifest.ts → project/manifest.ts} +1 -1
- package/src/{project.ts → project/materialize.ts} +2 -2
- package/src/project/paths.ts +20 -0
- package/src/{textDiff.ts → project/textDiff.ts} +1 -1
- package/src/{types.ts → project/types.ts} +0 -0
- package/runtime/materials/lightmap-baked-lite.mat +0 -175
- package/runtime/materials/lightmap-baked.mat +0 -176
- package/runtime/scene-harness.json +0 -1
- package/runtime/web/assets/__vite-browser-external-BIHI7g3E.js +0 -1
- package/runtime/web/assets/basis-C64VHDVD.js +0 -1
- package/runtime/web/assets/basis_transcoder-VXdx5NbI.wasm +0 -0
- package/runtime/web/assets/createViewerLite-Ct_PZdof.js +0 -852
- package/runtime/web/assets/draco-BiISTFcR.js +0 -118
- package/runtime/web/assets/draco_decoder-DsQ12WqX.wasm +0 -0
- package/runtime/web/assets/index-BMt7AnC5.js +0 -2
- package/runtime/web/assets/mapViewImpl-B2JcES8l.js +0 -810
- package/runtime/web/assets/maplibre-gl-worker-CJfwIrte.js +0 -8
- package/runtime/web/assets/worker-Caf-yYEI.js +0 -2
- package/runtime/web/embed.html +0 -32
- package/runtime/web/embed.js +0 -171
- package/src/commands/design.ts +0 -846
- package/src/commands/update.ts +0 -211
- package/src/util.ts +0 -146
- /package/src/{lecodes-design.d.ts → declarations/lecodes-design.d.ts} +0 -0
- /package/src/{qrcode-terminal.d.ts → declarations/qrcode-terminal.d.ts} +0 -0
- /package/src/{designMeta.ts → project/designMeta.ts} +0 -0
package/src/commands/push.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { basename } from "node:path"
|
|
2
1
|
import { readFileSync } from "node:fs"
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { basename } from "node:path"
|
|
3
|
+
import { CliError, bool, c, confirm, defineCommand, info, log, prompt, str, success, warn } from "../cli"
|
|
4
|
+
import { getCommits, getProject, publishProject, sync, uploadBlob, type Project, type SyncFileInput, type SyncFolderInput } from "../platform/api"
|
|
5
|
+
import { computeServerDiff } from "../platform/serverDiff"
|
|
6
|
+
import { classifyKind, diffLocal, hasChanges, isTextKind, scanProject } from "../project/localFiles"
|
|
7
|
+
import { writeManifest, type FileKind, type Manifest, type ManifestFile } from "../project/manifest"
|
|
8
|
+
import { buildPaths } from "../project/materialize"
|
|
9
|
+
import { linkedProject } from "./shared"
|
|
10
10
|
|
|
11
11
|
/*
|
|
12
12
|
* `lecodes push -m "message"` — diff the working tree against the manifest, upload changed binaries,
|
|
@@ -21,33 +21,42 @@ import { CliError, c, confirm, flagBool, flagStr, info, log, prompt, success, wa
|
|
|
21
21
|
* arrives before the fix is a lie the reviewer has no way to detect. That ordering is why nothing
|
|
22
22
|
* else in the toolchain sends a comment upward.
|
|
23
23
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
|
|
25
|
+
export const pushFlags = {
|
|
26
|
+
message: str("checkpoint message (asked for when omitted)", { alias: "m", value: "<text>" }),
|
|
27
|
+
publish: bool("also deploy the project live (compile) with the push"),
|
|
28
|
+
force: bool("push even if the server moved on (shows + confirms which server files get overwritten)"),
|
|
29
|
+
yes: bool("skip the --force overwrite confirmation", { alias: "y" }),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type PushOptions = { message?: string, publish?: boolean, force?: boolean, yes?: boolean }
|
|
33
|
+
|
|
34
|
+
export default defineCommand({
|
|
35
|
+
name: "push",
|
|
36
|
+
summary: "Push local changes as one new checkpoint",
|
|
37
|
+
flags: pushFlags,
|
|
38
|
+
examples: ['lecodes push -m "Tweak the menu"', "lecodes push --publish"],
|
|
39
|
+
run: ({ flags }) => runPush(flags),
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
/** The push itself — `lecodes link --push` runs it too. */
|
|
43
|
+
export const runPush = async (opts: PushOptions): Promise<void> => {
|
|
44
|
+
const { root, manifest, apiUrl, token } = linkedProject()
|
|
45
|
+
const publish = !!opts.publish
|
|
32
46
|
const scan = scanProject(root, manifest)
|
|
33
47
|
const diff = diffLocal(manifest, scan)
|
|
34
48
|
if (!hasChanges(diff)) {
|
|
35
|
-
if (publish) {
|
|
36
|
-
|
|
37
|
-
success("No file changes — published the current project state.")
|
|
38
|
-
} else {
|
|
39
|
-
info(c.dim("Working tree clean — nothing to push."))
|
|
40
|
-
}
|
|
49
|
+
if (publish) { await publishProject(apiUrl, token, manifest.uuid); success("No file changes — published the current project state.") }
|
|
50
|
+
else info(c.dim("Working tree clean — nothing to push."))
|
|
41
51
|
// Still flush: a queued answer must not be stuck behind "no files changed", which is exactly the
|
|
42
52
|
// state you're in after resolving a comment about something you already pushed.
|
|
43
|
-
await flushComments(
|
|
53
|
+
await flushComments()
|
|
44
54
|
return
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
const force = flagBool(args, "force")
|
|
48
57
|
// Concurrency guard: a push rewrites the server's WHOLE tree (set-tree), so anything that changed
|
|
49
58
|
// on the server since we cloned/pulled would be clobbered. Two kinds of drift to catch:
|
|
50
|
-
if (!force && manifest.baseHeadId !== null) {
|
|
59
|
+
if (!opts.force && manifest.baseHeadId !== null) {
|
|
51
60
|
const commits = await getCommits(apiUrl, token, manifest.uuid)
|
|
52
61
|
// (1) A new checkpoint was frozen on the server — that advances the head id.
|
|
53
62
|
if (commits.headId !== manifest.baseHeadId) {
|
|
@@ -58,28 +67,24 @@ export const push = async (args: Args) => {
|
|
|
58
67
|
// manifest (e.g. a resource was added in the editor) a blind push would silently DELETE it. Bail.
|
|
59
68
|
if (commits.dirty) {
|
|
60
69
|
const drift = serverPathDrift(await getProject(apiUrl, token, manifest.uuid), manifest)
|
|
61
|
-
if (drift) {
|
|
62
|
-
throw new CliError(`The project has uncommitted changes in the web editor your checkout doesn't have (${drift}). Run \`lecodes pull\` to take them, or \`lecodes push --force\` to overwrite the server.`)
|
|
63
|
-
}
|
|
70
|
+
if (drift) throw new CliError(`The project has uncommitted changes in the web editor your checkout doesn't have (${drift}). Run \`lecodes pull\` to take them, or \`lecodes push --force\` to overwrite the server.`)
|
|
64
71
|
}
|
|
65
72
|
}
|
|
66
73
|
|
|
67
74
|
// With --force we may clobber server-side edits. Show exactly what changes on the server and
|
|
68
75
|
// confirm (interactive only; skip with --yes or when piped).
|
|
69
|
-
if (force) {
|
|
76
|
+
if (opts.force) {
|
|
70
77
|
const project = await getProject(apiUrl, token, manifest.uuid)
|
|
71
78
|
const serverDiff = computeServerDiff(project, scan)
|
|
72
79
|
if (serverDiff.length) {
|
|
73
80
|
info(c.yellow(`--force will overwrite the server. ${serverDiff.length} file${serverDiff.length === 1 ? "" : "s"} change:`))
|
|
74
81
|
const label: Record<string, string> = { added: c.green(" create "), removed: c.red(" delete "), modified: c.yellow(" update ") }
|
|
75
82
|
for (const e of serverDiff) log(label[e.status] + e.path + (e.binary ? c.dim(" (binary)") : ""))
|
|
76
|
-
if (process.stdin.isTTY && !
|
|
77
|
-
if (!(await confirm("Overwrite the server with your local copy?", false))) { info(c.dim("Aborted.")); return }
|
|
78
|
-
}
|
|
83
|
+
if (process.stdin.isTTY && !opts.yes && !(await confirm("Overwrite the server with your local copy?", false))) { info(c.dim("Aborted.")); return }
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
const message = (
|
|
87
|
+
const message = (opts.message ?? await prompt("Checkpoint message")) || "Update from lecodes CLI"
|
|
83
88
|
|
|
84
89
|
// The identity source for a path: the same path in the manifest, else its move origin.
|
|
85
90
|
const sourceFor = (path: string): ManifestFile | undefined =>
|
|
@@ -92,10 +97,8 @@ export const push = async (args: Args) => {
|
|
|
92
97
|
const kind: FileKind = source?.type ?? classifyKind(basename(file.path))
|
|
93
98
|
const entry: SyncFileInput = { path: file.path, type: kind }
|
|
94
99
|
if (source) entry.assetId = source.id
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
entry.text = readFileSync(file.absPath, "utf8")
|
|
98
|
-
} else if (!source || source.sha !== file.sha) {
|
|
100
|
+
if (isTextKind(kind)) entry.text = readFileSync(file.absPath, "utf8")
|
|
101
|
+
else if (!source || source.sha !== file.sha) {
|
|
99
102
|
// New or changed binary — upload it and reference the fresh blob.
|
|
100
103
|
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename(file.path), readFileSync(file.absPath))
|
|
101
104
|
entry.blobFileId = blob.id
|
|
@@ -104,7 +107,6 @@ export const push = async (args: Args) => {
|
|
|
104
107
|
// Else: unchanged binary — assetId alone tells the server to keep the existing blob.
|
|
105
108
|
files.push(entry)
|
|
106
109
|
}
|
|
107
|
-
|
|
108
110
|
const folders: SyncFolderInput[] = scan.dirs.map(path => ({ path }))
|
|
109
111
|
|
|
110
112
|
if (uploaded > 0) info(c.dim(`Uploaded ${uploaded} binary file${uploaded === 1 ? "" : "s"}.`))
|
|
@@ -118,9 +120,7 @@ export const push = async (args: Args) => {
|
|
|
118
120
|
// Rebuild the manifest from the authoritative server tree + local hashes.
|
|
119
121
|
const shaByPath = new Map(scan.files.map(f => [f.path, f.sha]))
|
|
120
122
|
const newFiles: Record<string, ManifestFile> = {}
|
|
121
|
-
for (const node of res.nodes) {
|
|
122
|
-
newFiles[node.path] = { id: node.id, type: node.type as FileKind, sha: shaByPath.get(node.path) ?? "" }
|
|
123
|
-
}
|
|
123
|
+
for (const node of res.nodes) newFiles[node.path] = { id: node.id, type: node.type as FileKind, sha: shaByPath.get(node.path) ?? "" }
|
|
124
124
|
writeManifest(root, { ...manifest, baseHeadId: res.headId, files: newFiles })
|
|
125
125
|
|
|
126
126
|
const counts = [
|
|
@@ -131,19 +131,17 @@ export const push = async (args: Args) => {
|
|
|
131
131
|
].filter(Boolean).join(", ")
|
|
132
132
|
success(`Pushed checkpoint${res.seq ? ` #${res.seq}` : ""}${counts ? ` (${counts})` : ""}: ${message}`)
|
|
133
133
|
if (publish) reportPublish(res)
|
|
134
|
-
await flushComments(
|
|
134
|
+
await flushComments()
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/** Send the design board's queued comment writes, now that the design they describe is up. Silent
|
|
138
138
|
* when there's no design folder, no queue, or no login — this is a rider on the push, not a step
|
|
139
139
|
* the user asked for. */
|
|
140
|
-
const flushComments = async (
|
|
140
|
+
const flushComments = async (): Promise<void> => {
|
|
141
141
|
const { flushDesignComments } = await import("./design")
|
|
142
|
-
const result = await flushDesignComments(
|
|
142
|
+
const result = await flushDesignComments()
|
|
143
143
|
if (!result) return
|
|
144
|
-
if (result.threads) {
|
|
145
|
-
success(`Sent ${result.sent} comment update${result.sent === 1 ? "" : "s"} across ${result.threads} thread${result.threads === 1 ? "" : "s"}.`)
|
|
146
|
-
}
|
|
144
|
+
if (result.threads) success(`Sent ${result.sent} comment update${result.sent === 1 ? "" : "s"} across ${result.threads} thread${result.threads === 1 ? "" : "s"}.`)
|
|
147
145
|
for (const failure of result.failures) warn(`Comment not sent — ${failure} (still queued; the next push retries it).`)
|
|
148
146
|
}
|
|
149
147
|
|
|
@@ -157,17 +155,13 @@ const serverPathDrift = (project: Project, manifest: Manifest): string | null =>
|
|
|
157
155
|
const manifestPaths = new Set(Object.keys(manifest.files))
|
|
158
156
|
const added = [...serverPaths].filter(p => !manifestPaths.has(p))
|
|
159
157
|
const removed = [...manifestPaths].filter(p => !serverPaths.has(p))
|
|
160
|
-
const describe = (label: string, paths: string[]) =>
|
|
161
|
-
|
|
162
|
-
const parts = [
|
|
163
|
-
added.length ? describe("added", added) : "",
|
|
164
|
-
removed.length ? describe("removed", removed) : "",
|
|
165
|
-
].filter(Boolean)
|
|
158
|
+
const describe = (label: string, paths: string[]) => `${paths.length} ${label} on the server: ${paths.slice(0, 3).join(", ")}${paths.length > 3 ? ", …" : ""}`
|
|
159
|
+
const parts = [added.length ? describe("added", added) : "", removed.length ? describe("removed", removed) : ""].filter(Boolean)
|
|
166
160
|
return parts.length ? parts.join("; ") : null
|
|
167
161
|
}
|
|
168
162
|
|
|
169
163
|
/** Report the outcome of a --publish deploy bundled with the push (best-effort on the server). */
|
|
170
|
-
const reportPublish = (res: { published?: boolean, publishError?: string }) => {
|
|
164
|
+
const reportPublish = (res: { published?: boolean, publishError?: string }): void => {
|
|
171
165
|
if (res.published) success("Published — the project is now live.")
|
|
172
166
|
else warn(`Push landed, but publish failed: ${res.publishError ?? "unknown error"}`)
|
|
173
167
|
}
|