lecodes-cli 0.19.0 → 0.19.2
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/dist/index.js +730 -235
- package/package.json +14 -13
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +891 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +326 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +448 -0
- package/src/commands/appTemplates.ts +883 -0
- package/src/commands/appTemplatesAndroid.ts +599 -0
- package/src/commands/appTemplatesGradlew.ts +9 -0
- package/src/commands/assets.ts +28 -0
- package/src/commands/clone.ts +60 -0
- package/src/commands/compile.ts +253 -0
- package/src/commands/create.ts +59 -0
- package/src/commands/design.ts +863 -0
- package/src/commands/designTemplates.ts +11 -0
- package/src/commands/desktop.ts +122 -0
- package/src/commands/dev.ts +214 -0
- package/src/commands/diff.ts +59 -0
- package/src/commands/init.ts +191 -0
- package/src/commands/install.ts +198 -0
- package/src/commands/lightmap.ts +290 -0
- package/src/commands/link.ts +147 -0
- package/src/commands/login.ts +24 -0
- package/src/commands/navmesh.ts +225 -0
- package/src/commands/pn.ts +305 -0
- package/src/commands/projectTemplates.ts +129 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +414 -0
- package/src/commands/scene.ts +148 -0
- package/src/commands/shaders.ts +157 -0
- package/src/commands/status.ts +29 -0
- package/src/commands/test.ts +370 -0
- package/src/commands/thumbs.ts +178 -0
- package/src/commands/types.ts +87 -0
- package/src/commands/update.ts +190 -0
- package/src/compile/assetIcons.ts +214 -0
- package/src/compile/collect.ts +46 -0
- package/src/compile/collectLocal.ts +37 -0
- package/src/compile/designCompile.ts +104 -0
- package/src/compile/fonts.ts +156 -0
- package/src/compile/headlessBundle.ts +129 -0
- package/src/compile/nativeStack.ts +21 -0
- package/src/compile/projectCompile.ts +109 -0
- package/src/compile/sceneCompile.ts +113 -0
- package/src/compile/screenEntry.ts +127 -0
- package/src/compile/shaders.ts +245 -0
- package/src/config.ts +42 -0
- package/src/designMeta.ts +35 -0
- package/src/desktopRenderer.ts +532 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +292 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +491 -0
- package/src/lecodes-3d-editor.d.ts +41 -0
- package/src/lecodes-assets.d.ts +7 -0
- package/src/lecodes-design.d.ts +191 -0
- package/src/lecodes-renderer.d.ts +131 -0
- package/src/localFiles.ts +144 -0
- package/src/manifest.ts +46 -0
- package/src/matcTool.ts +137 -0
- package/src/peers.ts +40 -0
- package/src/project.ts +61 -0
- package/src/projectEnv.ts +94 -0
- package/src/qrcode-terminal.d.ts +9 -0
- package/src/releases.ts +125 -0
- package/src/serverDiff.ts +78 -0
- package/src/textDiff.ts +103 -0
- package/src/types.ts +0 -0
- package/src/util.ts +146 -0
- package/runtime/sdk/animate/animate.ts +0 -238
- package/runtime/sdk/animate/bezier.ts +0 -138
- package/runtime/sdk/animate/easings.ts +0 -126
- package/runtime/sdk/canvas/Canvas.ts +0 -305
- package/runtime/sdk/compile/aspectMacro.ts +0 -86
- package/runtime/sdk/compile/assetIconMacro.ts +0 -384
- package/runtime/sdk/compile/assetMacro.ts +0 -146
- package/runtime/sdk/compile/assetName.ts +0 -50
- package/runtime/sdk/compile/bundler.ts +0 -287
- package/runtime/sdk/compile/compileProject.ts +0 -129
- package/runtime/sdk/compile/detectEntry.ts +0 -128
- package/runtime/sdk/compile/fontMacro.ts +0 -459
- package/runtime/sdk/compile/fontRegistry.ts +0 -78
- package/runtime/sdk/compile/header.ts +0 -67
- package/runtime/sdk/compile/index.ts +0 -100
- package/runtime/sdk/compile/libraryImports.ts +0 -52
- package/runtime/sdk/compile/liteMaterial.ts +0 -247
- package/runtime/sdk/compile/sceneEditor.ts +0 -88
- package/runtime/sdk/compile/serverSplit.ts +0 -233
- package/runtime/sdk/compile/serverTypes.ts +0 -227
- package/runtime/sdk/compile/sfnt.ts +0 -98
- package/runtime/sdk/compile/shaderSchema.ts +0 -202
- package/runtime/sdk/compile/shaderTargets.ts +0 -81
- package/runtime/sdk/compile/sourcemap.ts +0 -25
- package/runtime/sdk/core/Aspect.ts +0 -568
- package/runtime/sdk/core/InspectorUI.ts +0 -212
- package/runtime/sdk/core/StateMachine.ts +0 -308
- package/runtime/sdk/core/color.ts +0 -66
- package/runtime/sdk/core/compWrite.ts +0 -42
- package/runtime/sdk/core/events.ts +0 -38
- package/runtime/sdk/core/fields.ts +0 -120
- package/runtime/sdk/core/registry.ts +0 -23
- package/runtime/sdk/core/signals.ts +0 -277
- package/runtime/sdk/core/time.ts +0 -84
- package/runtime/sdk/g2/Camera2D.ts +0 -40
- package/runtime/sdk/g2/CharacterController2D.ts +0 -276
- package/runtime/sdk/g2/Node2D.ts +0 -267
- package/runtime/sdk/g2/OneWay2D.ts +0 -66
- package/runtime/sdk/g2/Physics2D.ts +0 -346
- package/runtime/sdk/g2/Scene2D.ts +0 -209
- package/runtime/sdk/g2/Shape2D.ts +0 -259
- package/runtime/sdk/g2/Sprite.ts +0 -89
- package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
- package/runtime/sdk/g2/SpriteSheet.ts +0 -166
- package/runtime/sdk/g2/Texture2D.ts +0 -47
- package/runtime/sdk/g2/Tilemap.ts +0 -41
- package/runtime/sdk/g2/Tileset.ts +0 -71
- package/runtime/sdk/g2/Trigger2D.ts +0 -77
- package/runtime/sdk/g2/autotile.ts +0 -433
- package/runtime/sdk/g2/cells.ts +0 -91
- package/runtime/sdk/g2/defineScene2d.ts +0 -381
- package/runtime/sdk/g2/groups2d.ts +0 -106
- package/runtime/sdk/g2/loop.ts +0 -50
- package/runtime/sdk/g2/scenarios2d.ts +0 -69
- package/runtime/sdk/g2/touch.ts +0 -83
- package/runtime/sdk/gl/Camera.ts +0 -160
- package/runtime/sdk/gl/CameraPlace.ts +0 -52
- package/runtime/sdk/gl/CharacterController.ts +0 -238
- package/runtime/sdk/gl/Gearbox.ts +0 -212
- package/runtime/sdk/gl/Geometry.ts +0 -279
- package/runtime/sdk/gl/IK.ts +0 -193
- package/runtime/sdk/gl/InstancedMesh.ts +0 -132
- package/runtime/sdk/gl/Light.ts +0 -107
- package/runtime/sdk/gl/Lightmap.ts +0 -256
- package/runtime/sdk/gl/Material.ts +0 -260
- package/runtime/sdk/gl/Mesh.ts +0 -83
- package/runtime/sdk/gl/Model.ts +0 -124
- package/runtime/sdk/gl/NavAgent.ts +0 -337
- package/runtime/sdk/gl/NavMesh.ts +0 -397
- package/runtime/sdk/gl/Node.ts +0 -350
- package/runtime/sdk/gl/Noise.ts +0 -30
- package/runtime/sdk/gl/Particles.ts +0 -676
- package/runtime/sdk/gl/Physics.ts +0 -222
- package/runtime/sdk/gl/Plane.ts +0 -53
- package/runtime/sdk/gl/Ragdoll.ts +0 -270
- package/runtime/sdk/gl/Ray.ts +0 -16
- package/runtime/sdk/gl/Scene.ts +0 -486
- package/runtime/sdk/gl/Shape.ts +0 -409
- package/runtime/sdk/gl/Terrain.ts +0 -1092
- package/runtime/sdk/gl/Texture.ts +0 -63
- package/runtime/sdk/gl/Trigger.ts +0 -45
- package/runtime/sdk/gl/Vehicle.ts +0 -473
- package/runtime/sdk/gl/Wheel.ts +0 -240
- package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
- package/runtime/sdk/gl/animation/Animator.ts +0 -120
- package/runtime/sdk/gl/animation/Layer.ts +0 -31
- package/runtime/sdk/gl/animation/Loop.ts +0 -30
- package/runtime/sdk/gl/animation/Playback.ts +0 -44
- package/runtime/sdk/gl/animation/core.ts +0 -336
- package/runtime/sdk/gl/controls.ts +0 -95
- package/runtime/sdk/gl/physicsEvents.ts +0 -20
- package/runtime/sdk/gl/scenarios.ts +0 -291
- package/runtime/sdk/gl/state.ts +0 -6
- package/runtime/sdk/gl/terrainMesh.ts +0 -219
- package/runtime/sdk/gl/touch.ts +0 -68
- package/runtime/sdk/inject.ts +0 -197
- package/runtime/sdk/math/Mathf.ts +0 -118
- package/runtime/sdk/math/mat4.ts +0 -278
- package/runtime/sdk/math/quat.ts +0 -232
- package/runtime/sdk/math/vec.ts +0 -255
- package/runtime/sdk/net/codec.ts +0 -119
- package/runtime/sdk/net/core.ts +0 -384
- package/runtime/sdk/net/index.ts +0 -181
- package/runtime/sdk/net/replication.ts +0 -622
- package/runtime/sdk/plugins/camera.ts +0 -81
- package/runtime/sdk/plugins/geolocation.ts +0 -123
- package/runtime/sdk/plugins/oauth.ts +0 -61
- package/runtime/sdk/plugins/permission.ts +0 -7
- package/runtime/sdk/plugins/push.ts +0 -132
- package/runtime/sdk/plugins/qr.ts +0 -73
- package/runtime/sdk/plugins/service.ts +0 -47
- package/runtime/sdk/runtime/app.ts +0 -101
- package/runtime/sdk/runtime/appEvents.ts +0 -54
- package/runtime/sdk/runtime/channel.ts +0 -61
- package/runtime/sdk/runtime/clipboard.ts +0 -20
- package/runtime/sdk/runtime/datetime.ts +0 -329
- package/runtime/sdk/runtime/device.ts +0 -293
- package/runtime/sdk/runtime/fetch.ts +0 -77
- package/runtime/sdk/runtime/files.ts +0 -23
- package/runtime/sdk/runtime/input.ts +0 -175
- package/runtime/sdk/runtime/media.ts +0 -111
- package/runtime/sdk/runtime/misc.ts +0 -16
- package/runtime/sdk/runtime/net.ts +0 -36
- package/runtime/sdk/runtime/rpc.ts +0 -218
- package/runtime/sdk/runtime/service.ts +0 -83
- package/runtime/sdk/runtime/share.ts +0 -9
- package/runtime/sdk/runtime/storage.ts +0 -13
- package/runtime/sdk/runtime/touch.ts +0 -76
- package/runtime/sdk/scene/defineScene.ts +0 -1353
- package/runtime/sdk/scene/editorPlugins.ts +0 -110
- package/runtime/sdk/scene/gizmos.ts +0 -148
- package/runtime/sdk/scene/grammar.ts +0 -120
- package/runtime/sdk/scene/material.ts +0 -188
- package/runtime/sdk/server/auth/appConfig.ts +0 -12
- package/runtime/sdk/server/auth/global.ts +0 -80
- package/runtime/sdk/server/auth/host.ts +0 -318
- package/runtime/sdk/server/auth/models.ts +0 -83
- package/runtime/sdk/server/auth/types.ts +0 -50
- package/runtime/sdk/server/channel.ts +0 -56
- package/runtime/sdk/server/context.ts +0 -36
- package/runtime/sdk/server/db/defineDb.ts +0 -237
- package/runtime/sdk/server/db/fields.ts +0 -132
- package/runtime/sdk/server/db/httpTransport.ts +0 -93
- package/runtime/sdk/server/db/index.ts +0 -7
- package/runtime/sdk/server/db/marci/query.ts +0 -412
- package/runtime/sdk/server/db/types.ts +0 -202
- package/runtime/sdk/server/errors.ts +0 -12
- package/runtime/sdk/server/host.ts +0 -74
- package/runtime/sdk/server/inject.ts +0 -13
- package/runtime/sdk/server/runtime.ts +0 -133
- package/runtime/sdk/server/validate.ts +0 -87
- package/runtime/sdk/ui/NativeView.ts +0 -142
- package/runtime/sdk/ui/UI.ts +0 -39
- package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
- package/runtime/sdk/ui/UIButton.ts +0 -101
- package/runtime/sdk/ui/UIContainer.ts +0 -60
- package/runtime/sdk/ui/UIImage.ts +0 -83
- package/runtime/sdk/ui/UIInput.ts +0 -185
- package/runtime/sdk/ui/UIModal.ts +0 -139
- package/runtime/sdk/ui/UINode.ts +0 -830
- package/runtime/sdk/ui/UIPager.ts +0 -362
- package/runtime/sdk/ui/UIPopover.ts +0 -100
- package/runtime/sdk/ui/UIScreen.ts +0 -123
- package/runtime/sdk/ui/UIScrollable.ts +0 -87
- package/runtime/sdk/ui/UISpacer.ts +0 -14
- package/runtime/sdk/ui/UITabs.ts +0 -236
- package/runtime/sdk/ui/UIText.ts +0 -51
- package/runtime/sdk/ui/UIVideo.ts +0 -88
- package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
- package/runtime/sdk/ui/UIWidget.ts +0 -127
- package/runtime/sdk/ui/fonts.ts +0 -13
- package/runtime/sdk/ui/presentable.ts +0 -117
- package/runtime/sdk/ui/router.ts +0 -132
- package/runtime/sdk/ui/theme.ts +0 -84
package/dist/index.js
CHANGED
|
@@ -389,7 +389,7 @@ design/comments/
|
|
|
389
389
|
if (!existsSync2(file))
|
|
390
390
|
writeFileSync3(file, DEFAULT_IGNORE_FILE);
|
|
391
391
|
}, DEFAULT_GITIGNORE = `# LeCodes per-checkout state: generated IDE types + this machine's sync cursor
|
|
392
|
-
# (.lecodes/manifest.json). Regenerate with \`lecodes
|
|
392
|
+
# (.lecodes/manifest.json). Regenerate with \`lecodes update\` / re-attach with \`lecodes link\`.
|
|
393
393
|
.lecodes/
|
|
394
394
|
|
|
395
395
|
# Render / preview outputs and test failure frames
|
|
@@ -171654,10 +171654,7 @@ var init_detectEntry = __esm(() => {
|
|
|
171654
171654
|
});
|
|
171655
171655
|
|
|
171656
171656
|
// ../sdk/src/compile/shaderTargets.ts
|
|
171657
|
-
var externalSamplerReg, PLATFORM_BUILD, LOCAL_PLATFORM_BUILD, ALL_PLATFORM_BUILD, LOCAL_ONLY_PLATFORMS, TARGET_MATRIX_GENERATION = 1,
|
|
171658
|
-
externalSamplerReg.lastIndex = 0;
|
|
171659
|
-
return externalSamplerReg.test(text) ? ["opengl", "metal", "webgl", "desktop"] : ["opengl", "metal", "desktop"];
|
|
171660
|
-
}, matcArgs = (platform, outPath, inPath) => {
|
|
171657
|
+
var externalSamplerReg, PLATFORM_BUILD, LOCAL_PLATFORM_BUILD, ALL_PLATFORM_BUILD, LOCAL_ONLY_PLATFORMS, TARGET_MATRIX_GENERATION = 1, MATC_PLATFORMS, matcArgs = (platform, outPath, inPath) => {
|
|
171661
171658
|
const build = ALL_PLATFORM_BUILD[platform];
|
|
171662
171659
|
return ["-p", build.profile, "--no-essl1", "-a", build.api, "-o", outPath, inPath];
|
|
171663
171660
|
};
|
|
@@ -171666,7 +171663,6 @@ var init_shaderTargets = __esm(() => {
|
|
|
171666
171663
|
PLATFORM_BUILD = {
|
|
171667
171664
|
opengl: { profile: "mobile", api: "opengl", replaceExternal: false },
|
|
171668
171665
|
metal: { profile: "mobile", api: "metal", replaceExternal: false },
|
|
171669
|
-
webgl: { profile: "mobile", api: "opengl", replaceExternal: true },
|
|
171670
171666
|
desktop: { profile: "desktop", api: "opengl", replaceExternal: true }
|
|
171671
171667
|
};
|
|
171672
171668
|
LOCAL_PLATFORM_BUILD = {
|
|
@@ -171674,6 +171670,7 @@ var init_shaderTargets = __esm(() => {
|
|
|
171674
171670
|
};
|
|
171675
171671
|
ALL_PLATFORM_BUILD = { ...PLATFORM_BUILD, ...LOCAL_PLATFORM_BUILD };
|
|
171676
171672
|
LOCAL_ONLY_PLATFORMS = ["desktop-vulkan"];
|
|
171673
|
+
MATC_PLATFORMS = ["opengl", "metal", "desktop"];
|
|
171677
171674
|
});
|
|
171678
171675
|
|
|
171679
171676
|
// ../sdk/src/compile/liteMaterial.ts
|
|
@@ -172189,8 +172186,6 @@ var compileProject = async (opts) => {
|
|
|
172189
172186
|
const name = shaders[0].src.split(/[\\/]/).pop() ?? "";
|
|
172190
172187
|
const [prefix, suffix = ".filamat"] = name.split("_opengl");
|
|
172191
172188
|
files[e.path] = `export default ("id:" + _creatorUtils.fetchLocal(${JSON.stringify(prefix + "_")} + _creator.backend + ${JSON.stringify(suffix)}))`;
|
|
172192
|
-
} else if (shaders.length > 2) {
|
|
172193
|
-
files[e.path] = `export default \`${opts.publicUrl}${shaders[0].src.replace("_opengl", "_${_creator.subBackend ?? _creator.backend}")}\``;
|
|
172194
172189
|
} else if (shaders.length > 0) {
|
|
172195
172190
|
files[e.path] = `export default \`${opts.publicUrl}${shaders[0].src.replace("_opengl", "_${_creator.backend}")}\``;
|
|
172196
172191
|
} else {
|
|
@@ -173137,7 +173132,6 @@ __export(exports_compile, {
|
|
|
173137
173132
|
parseSfnt: () => parseSfnt,
|
|
173138
173133
|
parseJsonish: () => parseJsonish,
|
|
173139
173134
|
offsetSourceMap: () => offsetSourceMap,
|
|
173140
|
-
matcPlatformsFor: () => matcPlatformsFor,
|
|
173141
173135
|
matcArgs: () => matcArgs,
|
|
173142
173136
|
loadSceneHarness: () => loadSceneHarness,
|
|
173143
173137
|
isServerPath: () => isServerPath,
|
|
@@ -173168,6 +173162,7 @@ __export(exports_compile, {
|
|
|
173168
173162
|
SCENE_HARNESS_DIR: () => SCENE_HARNESS_DIR,
|
|
173169
173163
|
SCENE_ENTRY_PATH: () => SCENE_ENTRY_PATH,
|
|
173170
173164
|
PLATFORM_BUILD: () => PLATFORM_BUILD,
|
|
173165
|
+
MATC_PLATFORMS: () => MATC_PLATFORMS,
|
|
173171
173166
|
LOCAL_PLATFORM_BUILD: () => LOCAL_PLATFORM_BUILD,
|
|
173172
173167
|
LOCAL_ONLY_PLATFORMS: () => LOCAL_ONLY_PLATFORMS,
|
|
173173
173168
|
ICON_ID: () => ICON_ID,
|
|
@@ -173198,7 +173193,13 @@ var init_compile = __esm(() => {
|
|
|
173198
173193
|
import { existsSync as existsSync7 } from "node:fs";
|
|
173199
173194
|
import { createRequire as createRequire3 } from "node:module";
|
|
173200
173195
|
import { dirname as dirname5, join as join9 } from "node:path";
|
|
173201
|
-
var
|
|
173196
|
+
var resolveSdkInject = () => {
|
|
173197
|
+
try {
|
|
173198
|
+
return createRequire3(import.meta.url).resolve("lecodes-sdk/inject");
|
|
173199
|
+
} catch {}
|
|
173200
|
+
const vendored = join9(distRoot, "runtime", "sdk", "inject.ts");
|
|
173201
|
+
return existsSync7(vendored) ? vendored : null;
|
|
173202
|
+
}, sdkInject, resolveChiselBin2 = () => {
|
|
173202
173203
|
if (process.env.LECODES_CHISEL_BIN)
|
|
173203
173204
|
return process.env.LECODES_CHISEL_BIN;
|
|
173204
173205
|
try {
|
|
@@ -173230,9 +173231,9 @@ var vendoredInject, resolveChiselBin2 = () => {
|
|
|
173230
173231
|
var init_projectCompile = __esm(() => {
|
|
173231
173232
|
init_distRoot();
|
|
173232
173233
|
init_compile();
|
|
173233
|
-
|
|
173234
|
-
if (
|
|
173235
|
-
process.env.LECODES_SDK_INJECT =
|
|
173234
|
+
sdkInject = resolveSdkInject();
|
|
173235
|
+
if (sdkInject)
|
|
173236
|
+
process.env.LECODES_SDK_INJECT = sdkInject;
|
|
173236
173237
|
chiselBin = resolveChiselBin2();
|
|
173237
173238
|
if (chiselBin)
|
|
173238
173239
|
process.env.LECODES_CHISEL_BIN = chiselBin;
|
|
@@ -214125,6 +214126,7 @@ var init_esm30 = __esm(() => {
|
|
|
214125
214126
|
// src/types.ts
|
|
214126
214127
|
import { dirname as dirname13, join as join22, relative as relative3, sep } from "node:path";
|
|
214127
214128
|
import { existsSync as existsSync21, mkdirSync as mkdirSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, rmSync as rmSync8, statSync as statSync8, writeFileSync as writeFileSync17 } from "node:fs";
|
|
214129
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
214128
214130
|
var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
214129
214131
|
if (!existsSync21(dir))
|
|
214130
214132
|
return [];
|
|
@@ -214174,8 +214176,16 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
214174
214176
|
bundle[path2] = readFileSync18(join22(typesDir, path2), "utf8");
|
|
214175
214177
|
return bundle;
|
|
214176
214178
|
}, materializeTypes = async (root, apiUrl) => writeTypeBundle(root, await getTypes(apiUrl)), readLocalTypeBundle = () => {
|
|
214179
|
+
const fromPackage = (() => {
|
|
214180
|
+
try {
|
|
214181
|
+
return createRequire4(import.meta.url).resolve("lecodes-sdk/types.json");
|
|
214182
|
+
} catch {
|
|
214183
|
+
return null;
|
|
214184
|
+
}
|
|
214185
|
+
})();
|
|
214177
214186
|
const candidates = [
|
|
214178
214187
|
join22(distRoot, "runtime", "sdk-types.json"),
|
|
214188
|
+
...fromPackage ? [fromPackage] : [],
|
|
214179
214189
|
join22(distRoot, "..", "sdk", "dist", "types.json")
|
|
214180
214190
|
];
|
|
214181
214191
|
for (const path2 of candidates) {
|
|
@@ -214358,7 +214368,7 @@ var init_browserAuth = __esm(() => {
|
|
|
214358
214368
|
init_util();
|
|
214359
214369
|
});
|
|
214360
214370
|
|
|
214361
|
-
//
|
|
214371
|
+
// ../../../lecodes-tools/packages/lecodes-design/src/core/concept.ts
|
|
214362
214372
|
var SPEC_TEMPLATE = `# Concept
|
|
214363
214373
|
|
|
214364
214374
|
The narrative half of this design. \`meta.json\` + the canvas hold the *visual/flow* half (screens,
|
|
@@ -214394,7 +214404,7 @@ Behaviour that isn't visible in a single screen — validation, permissions, not
|
|
|
214394
214404
|
cases — and the decisions you've made and why, so they aren't re-litigated later.
|
|
214395
214405
|
`;
|
|
214396
214406
|
|
|
214397
|
-
//
|
|
214407
|
+
// ../../../lecodes-tools/packages/lecodes-design/src/templates.ts
|
|
214398
214408
|
var SPEC_MD, META_JSON = `{
|
|
214399
214409
|
"screens": {
|
|
214400
214410
|
"home": { "pos": [0, 0], "desc": "Example screen — replace me", "role": "list" }
|
|
@@ -216529,26 +216539,26 @@ var require_main = __commonJS((exports, module) => {
|
|
|
216529
216539
|
// package.json
|
|
216530
216540
|
var package_default = {
|
|
216531
216541
|
name: "lecodes-cli",
|
|
216532
|
-
version: "0.19.
|
|
216542
|
+
version: "0.19.2",
|
|
216533
216543
|
dependencies: {
|
|
216534
216544
|
"@letary/chisel": "^0.10.0",
|
|
216535
|
-
jimp: "^1.6.1"
|
|
216545
|
+
jimp: "^1.6.1",
|
|
216546
|
+
"lecodes-sdk": "workspace:*"
|
|
216536
216547
|
},
|
|
216537
216548
|
devDependencies: {
|
|
216538
|
-
"lecodes-design": "
|
|
216549
|
+
"lecodes-design": "link:lecodes-design",
|
|
216539
216550
|
"lecodes-renderer": "workspace:*",
|
|
216540
216551
|
"qrcode-terminal": "^0.12.0",
|
|
216541
|
-
"lecodes-3d-editor": "
|
|
216552
|
+
"lecodes-3d-editor": "link:lecodes-3d-editor",
|
|
216542
216553
|
"lecodes-assets": "workspace:*",
|
|
216543
|
-
"creator-nav": "workspace:*",
|
|
216544
|
-
|
|
216545
|
-
"viewer-lite": "workspace:*"
|
|
216554
|
+
"lecodes-creator-nav": "workspace:*",
|
|
216555
|
+
"lecodes-viewer-lite": "workspace:*"
|
|
216546
216556
|
},
|
|
216547
216557
|
peerDependencies: {
|
|
216548
|
-
"lecodes-design": "^0.
|
|
216549
|
-
"lecodes-renderer": "^0.
|
|
216550
|
-
"lecodes-3d-editor": "^0.
|
|
216551
|
-
"lecodes-assets": "^0.1
|
|
216558
|
+
"lecodes-design": "^0.9.0",
|
|
216559
|
+
"lecodes-renderer": "^0.19.2",
|
|
216560
|
+
"lecodes-3d-editor": "^0.7.0",
|
|
216561
|
+
"lecodes-assets": "^0.2.1"
|
|
216552
216562
|
},
|
|
216553
216563
|
bin: {
|
|
216554
216564
|
lecodes: "dist/index.js"
|
|
@@ -216559,6 +216569,7 @@ var package_default = {
|
|
|
216559
216569
|
},
|
|
216560
216570
|
files: [
|
|
216561
216571
|
"dist",
|
|
216572
|
+
"src",
|
|
216562
216573
|
"runtime",
|
|
216563
216574
|
"README.md"
|
|
216564
216575
|
],
|
|
@@ -216725,7 +216736,7 @@ init_fonts();
|
|
|
216725
216736
|
init_compile();
|
|
216726
216737
|
import { execFile } from "node:child_process";
|
|
216727
216738
|
import { createHash as createHash4, randomBytes } from "node:crypto";
|
|
216728
|
-
import {
|
|
216739
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
216729
216740
|
import { tmpdir } from "node:os";
|
|
216730
216741
|
import { basename as basename3, join as join13 } from "node:path";
|
|
216731
216742
|
|
|
@@ -216918,17 +216929,14 @@ var matcIdentity = (exe) => {
|
|
|
216918
216929
|
return `${stat.size}:${Math.trunc(stat.mtimeMs)}`;
|
|
216919
216930
|
};
|
|
216920
216931
|
var shaderHash = (text, matcId) => createHash4("sha256").update(`${TARGET_MATRIX_GENERATION}\x00${matcId}\x00${text}`).digest("hex").slice(0, 16);
|
|
216921
|
-
var artifactFamily = (
|
|
216922
|
-
const matcPlatforms = [...matcPlatformsFor(text), ...LOCAL_ONLY_PLATFORMS];
|
|
216923
|
-
return [...matcPlatforms, ...matcPlatforms.includes("webgl") ? [] : ["webgl"], "webgl-lite"];
|
|
216924
|
-
};
|
|
216932
|
+
var artifactFamily = () => [...MATC_PLATFORMS, ...LOCAL_ONLY_PLATFORMS, "webgl-lite"];
|
|
216925
216933
|
var shaderIsCompiled = (root, text, matcId) => {
|
|
216926
216934
|
const hash = shaderHash(text, matcId);
|
|
216927
|
-
return artifactFamily(
|
|
216935
|
+
return artifactFamily().every((p) => existsSync11(join13(shadersCacheDir(root), `${hash}_${p}.filamat`)));
|
|
216928
216936
|
};
|
|
216929
216937
|
var shaderCompiledPlatforms = (root, text, matcId) => {
|
|
216930
216938
|
const hash = shaderHash(text, matcId);
|
|
216931
|
-
return artifactFamily(
|
|
216939
|
+
return artifactFamily().filter((p) => existsSync11(join13(shadersCacheDir(root), `${hash}_${p}.filamat`)));
|
|
216932
216940
|
};
|
|
216933
216941
|
var localShaderArtifact = (root, text, platform) => {
|
|
216934
216942
|
const matcExe = resolveMatcExeCached();
|
|
@@ -216973,15 +216981,12 @@ var applyLocalShaders = async (entries, opts) => {
|
|
|
216973
216981
|
for (const entry of shaderEntries) {
|
|
216974
216982
|
const text = readFileSync11(entry.absPath, "utf8");
|
|
216975
216983
|
const hash = shaderHash(text, matcId);
|
|
216976
|
-
const family = artifactFamily(
|
|
216984
|
+
const family = artifactFamily();
|
|
216977
216985
|
const artifact = (platform) => `${hash}_${platform}.filamat`;
|
|
216978
216986
|
const has = (platform) => existsSync11(join13(cacheDir, artifact(platform)));
|
|
216979
216987
|
const wanted = opts.platforms ? family.filter((p) => opts.platforms.includes(p)) : family;
|
|
216980
|
-
if (wanted.includes("webgl") && !matcPlatformsFor(text).includes("webgl") && !wanted.includes("opengl")) {
|
|
216981
|
-
wanted.push("opengl");
|
|
216982
|
-
}
|
|
216983
216988
|
const missing = wanted.filter((p) => !has(p));
|
|
216984
|
-
const matcMissing = missing.filter((p) => p !== "webgl-lite"
|
|
216989
|
+
const matcMissing = missing.filter((p) => p !== "webgl-lite");
|
|
216985
216990
|
if (matcMissing.length > 0) {
|
|
216986
216991
|
const tempName = `lecodes-matc-${randomBytes(6).toString("hex")}.mat`;
|
|
216987
216992
|
const tempFile = join13(tmpdir(), tempName);
|
|
@@ -217001,9 +217006,6 @@ ${cleanMatcOutput(stderr, tempName, basename3(entry.path))}`);
|
|
|
217001
217006
|
rmSync2(tempFile, { force: true });
|
|
217002
217007
|
}
|
|
217003
217008
|
}
|
|
217004
|
-
if (missing.includes("webgl") && !matcPlatformsFor(text).includes("webgl")) {
|
|
217005
|
-
copyFileSync(join13(cacheDir, artifact("opengl")), join13(cacheDir, artifact("webgl")));
|
|
217006
|
-
}
|
|
217007
217009
|
if (missing.includes("webgl-lite")) {
|
|
217008
217010
|
writeFileSync7(join13(cacheDir, artifact("webgl-lite")), JSON.stringify(buildLiteMaterialArtifact(text)));
|
|
217009
217011
|
}
|
|
@@ -217018,7 +217020,7 @@ ${cleanMatcOutput(stderr, tempName, basename3(entry.path))}`);
|
|
|
217018
217020
|
artifacts.push({ name: artifact(platform), absPath: join13(cacheDir, artifact(platform)) });
|
|
217019
217021
|
}
|
|
217020
217022
|
} else {
|
|
217021
|
-
const order = ["opengl", "metal", "desktop", "webgl
|
|
217023
|
+
const order = ["opengl", "metal", "desktop", "webgl-lite"];
|
|
217022
217024
|
entry.shaders = order.map((platform) => ({ platform, src: `${opts.srcPrefix}/${artifact(platform)}` }));
|
|
217023
217025
|
}
|
|
217024
217026
|
}
|
|
@@ -218630,6 +218632,12 @@ Sync links the smallest SDK artifact covering the engines the compiled bundle ac
|
|
|
218630
218632
|
engine, sync switches automatically on the next run; set \`android.variant\` in \`../app.json\`
|
|
218631
218633
|
to force one (needs lecodes-android-sdk >= 1.3.0; older releases ship only the full AAR).
|
|
218632
218634
|
|
|
218635
|
+
Physics, navigation meshes and multiplayer ship in \`lecodes-sdk\` (full) ONLY —
|
|
218636
|
+
\`lecodes-sdk-3d\` is 3D rendering without the game stack. Auto-selection reads which RENDERING
|
|
218637
|
+
engines the bundle uses and cannot see those, so a project using \`Physics\`,
|
|
218638
|
+
\`CharacterController\`, \`NavMesh\` or networking must set \`android.variant: "full"\` in
|
|
218639
|
+
\`../app.json\` — otherwise those aspects silently do nothing on device.
|
|
218640
|
+
|
|
218633
218641
|
## App-local native code
|
|
218634
218642
|
|
|
218635
218643
|
Drop Kotlin files into \`app/src/main/java/\` and register them in \`MainActivity\` after the
|
|
@@ -219753,7 +219761,7 @@ import { basename as basename7, dirname as dirname11, join as join20, resolve as
|
|
|
219753
219761
|
|
|
219754
219762
|
// src/desktopRenderer.ts
|
|
219755
219763
|
import { execFileSync as execFileSync3, spawn as spawn2, spawnSync as spawnSync4 } from "node:child_process";
|
|
219756
|
-
import { copyFileSync
|
|
219764
|
+
import { copyFileSync, existsSync as existsSync17, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync2, readdirSync as readdirSync6, readFileSync as readFileSync16, rmSync as rmSync4, statSync as statSync4, writeFileSync as writeFileSync13 } from "node:fs";
|
|
219757
219765
|
import { homedir as homedir6, tmpdir as tmpdir2 } from "node:os";
|
|
219758
219766
|
import { join as join18, resolve as resolve5 } from "node:path";
|
|
219759
219767
|
init_util();
|
|
@@ -220083,7 +220091,7 @@ var stageBundle = (js, resources) => {
|
|
|
220083
220091
|
writeFileSync13(join18(runDir, "app.js"), js);
|
|
220084
220092
|
for (const r2 of resources) {
|
|
220085
220093
|
if (r2.absPath && existsSync17(r2.absPath) && statSync4(r2.absPath).isFile()) {
|
|
220086
|
-
|
|
220094
|
+
copyFileSync(r2.absPath, join18(runDir, r2.name));
|
|
220087
220095
|
}
|
|
220088
220096
|
}
|
|
220089
220097
|
return runDir;
|
|
@@ -220126,7 +220134,16 @@ var runDesktopApp = async (js, resources, opts = {}) => {
|
|
|
220126
220134
|
});
|
|
220127
220135
|
});
|
|
220128
220136
|
} finally {
|
|
220129
|
-
|
|
220137
|
+
for (let attempt = 0;; attempt++) {
|
|
220138
|
+
try {
|
|
220139
|
+
rmSync4(runDir, { recursive: true, force: true });
|
|
220140
|
+
break;
|
|
220141
|
+
} catch {
|
|
220142
|
+
if (attempt >= 5)
|
|
220143
|
+
break;
|
|
220144
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 200);
|
|
220145
|
+
}
|
|
220146
|
+
}
|
|
220130
220147
|
}
|
|
220131
220148
|
};
|
|
220132
220149
|
var runDesktopDev = async (url, opts = {}) => {
|
|
@@ -220204,7 +220221,16 @@ ${tail}` : "";
|
|
|
220204
220221
|
});
|
|
220205
220222
|
});
|
|
220206
220223
|
} finally {
|
|
220207
|
-
|
|
220224
|
+
for (let attempt = 0;; attempt++) {
|
|
220225
|
+
try {
|
|
220226
|
+
rmSync4(runDir, { recursive: true, force: true });
|
|
220227
|
+
break;
|
|
220228
|
+
} catch {
|
|
220229
|
+
if (attempt >= 5)
|
|
220230
|
+
break;
|
|
220231
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 200);
|
|
220232
|
+
}
|
|
220233
|
+
}
|
|
220208
220234
|
}
|
|
220209
220235
|
};
|
|
220210
220236
|
|
|
@@ -220214,7 +220240,7 @@ init_util();
|
|
|
220214
220240
|
// src/commands/appDesktopMac.ts
|
|
220215
220241
|
init_util();
|
|
220216
220242
|
import { execFileSync as execFileSync4, spawn as spawn3, spawnSync as spawnSync5 } from "node:child_process";
|
|
220217
|
-
import { cpSync as cpSync2, existsSync as existsSync18, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync14 } from "node:fs";
|
|
220243
|
+
import { cpSync as cpSync2, existsSync as existsSync18, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readdirSync as readdirSync7, rmSync as rmSync5, statSync as statSync5, symlinkSync, writeFileSync as writeFileSync14 } from "node:fs";
|
|
220218
220244
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
220219
220245
|
import { basename as basename6, join as join19, resolve as resolve6 } from "node:path";
|
|
220220
220246
|
var mb = (bytes) => `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
@@ -220336,11 +220362,12 @@ var signApp = async (app, signing, hostApp, tmp) => {
|
|
|
220336
220362
|
throw new CliError(`The signature doesn't verify:
|
|
220337
220363
|
${(verify.stdout + verify.stderr).trim()}`);
|
|
220338
220364
|
};
|
|
220339
|
-
var
|
|
220340
|
-
const
|
|
220341
|
-
|
|
220342
|
-
|
|
220343
|
-
|
|
220365
|
+
var notarize = (target, profile, tmp, what) => {
|
|
220366
|
+
const submission = target.endsWith(".app") ? join19(tmp, `${basename6(target, ".app")}.zip`) : target;
|
|
220367
|
+
if (submission !== target)
|
|
220368
|
+
execFileSync4("ditto", ["-c", "-k", "--keepParent", target, submission]);
|
|
220369
|
+
note(`Notarizing the ${what} with profile "${profile}" — this waits on Apple (usually 1–5 minutes)…`);
|
|
220370
|
+
const r2 = spawnSync5("xcrun", ["notarytool", "submit", submission, "--keychain-profile", profile, "--wait"], { encoding: "utf8" });
|
|
220344
220371
|
const out = (r2.stdout + `
|
|
220345
220372
|
` + r2.stderr).trim();
|
|
220346
220373
|
const id = /id: ([0-9a-f-]{36})/.exec(out)?.[1];
|
|
@@ -220349,11 +220376,44 @@ var notarizeApp = (app, profile, tmp) => {
|
|
|
220349
220376
|
${out}
|
|
220350
220377
|
` + (id ? ` Details: xcrun notarytool log ${id} --keychain-profile ${profile}` : ""));
|
|
220351
220378
|
}
|
|
220352
|
-
const staple = spawnSync5("xcrun", ["stapler", "staple",
|
|
220379
|
+
const staple = spawnSync5("xcrun", ["stapler", "staple", target], { encoding: "utf8" });
|
|
220353
220380
|
if (staple.status !== 0)
|
|
220354
220381
|
throw new CliError(`Stapling failed:
|
|
220355
220382
|
${(staple.stdout + staple.stderr).trim()}`);
|
|
220356
|
-
success(
|
|
220383
|
+
success(`Notarized + stapled (${what}).`);
|
|
220384
|
+
};
|
|
220385
|
+
var buildDmg = async (app, out, appName, signing, tmp) => {
|
|
220386
|
+
const dmg = join19(out, `${appName}.dmg`);
|
|
220387
|
+
rmSync5(dmg, { force: true });
|
|
220388
|
+
const stage = join19(tmp, "dmg");
|
|
220389
|
+
rmSync5(stage, { recursive: true, force: true });
|
|
220390
|
+
mkdirSync12(stage, { recursive: true });
|
|
220391
|
+
note("Building the disk image…");
|
|
220392
|
+
execFileSync4("cp", ["-R", app, join19(stage, basename6(app))]);
|
|
220393
|
+
symlinkSync("/Applications", join19(stage, "Applications"));
|
|
220394
|
+
const r2 = spawnSync5("hdiutil", [
|
|
220395
|
+
"create",
|
|
220396
|
+
"-volname",
|
|
220397
|
+
appName,
|
|
220398
|
+
"-srcfolder",
|
|
220399
|
+
stage,
|
|
220400
|
+
"-fs",
|
|
220401
|
+
"HFS+",
|
|
220402
|
+
"-format",
|
|
220403
|
+
"UDZO",
|
|
220404
|
+
"-ov",
|
|
220405
|
+
dmg
|
|
220406
|
+
], { encoding: "utf8" });
|
|
220407
|
+
rmSync5(stage, { recursive: true, force: true });
|
|
220408
|
+
if (r2.status !== 0)
|
|
220409
|
+
throw new CliError(`hdiutil failed:
|
|
220410
|
+
${(r2.stdout + r2.stderr).trim()}`);
|
|
220411
|
+
if (signing.identity !== "-") {
|
|
220412
|
+
await codesignRetrying(["--force", "--timestamp", "--sign", signing.identity, dmg]);
|
|
220413
|
+
if (signing.notaryProfile)
|
|
220414
|
+
notarize(dmg, signing.notaryProfile, tmp, "disk image");
|
|
220415
|
+
}
|
|
220416
|
+
success(`DMG: ${dmg} (${mb(statSync5(dmg).size)})`);
|
|
220357
220417
|
};
|
|
220358
220418
|
var gatekeeperVerdict = (app) => {
|
|
220359
220419
|
const r2 = spawnSync5("spctl", ["-a", "-t", "exec", "-vv", app], { encoding: "utf8" });
|
|
@@ -220487,7 +220547,7 @@ var buildMacApp = async (input) => {
|
|
|
220487
220547
|
}, developerIdInKeychain);
|
|
220488
220548
|
await signApp(app, signing, hostApp, tmp);
|
|
220489
220549
|
if (signing.notaryProfile) {
|
|
220490
|
-
|
|
220550
|
+
notarize(app, signing.notaryProfile, tmp, "app");
|
|
220491
220551
|
} else if (signing.identity !== "-") {
|
|
220492
220552
|
warn("Signed with Developer ID but NOT notarized — Gatekeeper refuses a downloaded copy on every other Mac.");
|
|
220493
220553
|
warn(" Set desktop.macos.notarize.profile in app.json (a `xcrun notarytool store-credentials` profile) or pass --notarize <profile>.");
|
|
@@ -220499,6 +220559,8 @@ var buildMacApp = async (input) => {
|
|
|
220499
220559
|
}
|
|
220500
220560
|
writeFileSync14(join19(out, "README.txt"), readmeText(appName, !!signing.notaryProfile, signing.identity !== "-"));
|
|
220501
220561
|
success(`App: ${app} (${mb(dirSize(app))})`);
|
|
220562
|
+
if (flagBool(args, "dmg"))
|
|
220563
|
+
await buildDmg(app, out, appName, signing, tmp);
|
|
220502
220564
|
if (flagBool(args, "probe"))
|
|
220503
220565
|
await probeMacApp(app, out, args);
|
|
220504
220566
|
if (flagBool(args, "zip")) {
|
|
@@ -220506,8 +220568,8 @@ var buildMacApp = async (input) => {
|
|
|
220506
220568
|
rmSync5(zip, { force: true });
|
|
220507
220569
|
execFileSync4("ditto", ["-c", "-k", "--keepParent", app, zip]);
|
|
220508
220570
|
success(`Zip: ${zip} (${mb(statSync5(zip).size)})`);
|
|
220509
|
-
} else {
|
|
220510
|
-
note("Tip: --zip packs the .app for sending
|
|
220571
|
+
} else if (!flagBool(args, "dmg")) {
|
|
220572
|
+
note("Tip: --zip packs the .app for sending; --dmg wraps it in a drag-to-Applications image.");
|
|
220511
220573
|
}
|
|
220512
220574
|
} finally {
|
|
220513
220575
|
rmSync5(tmp, { recursive: true, force: true });
|
|
@@ -220608,6 +220670,8 @@ var buildDesktop = async (args) => {
|
|
|
220608
220670
|
}
|
|
220609
220671
|
if (mac)
|
|
220610
220672
|
return buildMacApp({ root, config, name, slug, out, js, shipped, hostExe: exe, args });
|
|
220673
|
+
if (flagBool(args, "dmg"))
|
|
220674
|
+
warn("--dmg is a macOS format — ignored on this platform.");
|
|
220611
220675
|
const version = process.env.LECODES_DESKTOP_EXE ? "local build" : selectedDesktopVersion();
|
|
220612
220676
|
rmSync6(out, { recursive: true, force: true });
|
|
220613
220677
|
mkdirSync13(out, { recursive: true });
|
|
@@ -221660,7 +221724,7 @@ channel for game state that has no UI.
|
|
|
221660
221724
|
## SDK documentation
|
|
221661
221725
|
|
|
221662
221726
|
\`.lecodes/types/\` is the exact API surface (signatures only; generated and gitignored — run
|
|
221663
|
-
\`lecodes
|
|
221727
|
+
\`lecodes update\` if it's missing, never commit \`.lecodes/\`). For semantics and examples,
|
|
221664
221728
|
fetch the docs — they are served as raw markdown for AI tools:
|
|
221665
221729
|
|
|
221666
221730
|
- https://le.codes/llms.txt — the docs map; fetch it first to find the right page
|
|
@@ -222777,9 +222841,9 @@ lecodes app open # open it in Xcode, build & run
|
|
|
222777
222841
|
- \`CLAUDE.md\` — guidance for AI assistants (the headless feedback loop + testability conventions)
|
|
222778
222842
|
- \`assets/\` — images/fonts the app references (created on demand)
|
|
222779
222843
|
- \`tsconfig.json\` + \`.lecodes/types/\` — generated IDE types (rewritten by the CLI; don't edit).
|
|
222780
|
-
They come from the SDK bundled in the CLI; \`lecodes
|
|
222844
|
+
They come from the SDK bundled in the CLI; \`lecodes update\` refreshes them from the platform.
|
|
222781
222845
|
- \`.lecodes/\` is gitignored — per-checkout state (those types + \`manifest.json\`, this machine's
|
|
222782
|
-
sync cursor once linked). After a fresh git clone: \`lecodes
|
|
222846
|
+
sync cursor once linked). After a fresh git clone: \`lecodes update\`, then
|
|
222783
222847
|
\`lecodes link --project <uuid>\` to re-attach.
|
|
222784
222848
|
- \`.lecodesignore\` — files a future \`lecodes push\` would skip
|
|
222785
222849
|
|
|
@@ -223093,8 +223157,8 @@ var link = async (args) => {
|
|
|
223093
223157
|
|
|
223094
223158
|
// src/commands/lightmap.ts
|
|
223095
223159
|
init_manifest();
|
|
223096
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync21, mkdtempSync as mkdtempSync4, rmSync as rmSync9, statSync as statSync10, unlinkSync, writeFileSync as writeFileSync22 } from "node:fs";
|
|
223097
|
-
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
223160
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync21, mkdtempSync as mkdtempSync4, readFileSync as readFileSync25, renameSync as renameSync3, rmSync as rmSync9, statSync as statSync10, unlinkSync, writeFileSync as writeFileSync22 } from "node:fs";
|
|
223161
|
+
import { spawn as spawn6, spawnSync as spawnSync6 } from "node:child_process";
|
|
223098
223162
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
223099
223163
|
import { join as join30, relative as relative4, resolve as resolve13 } from "node:path";
|
|
223100
223164
|
init_util();
|
|
@@ -223136,14 +223200,26 @@ var requireToktx = () => {
|
|
|
223136
223200
|
}
|
|
223137
223201
|
return toktx;
|
|
223138
223202
|
};
|
|
223139
|
-
var encodeKtx2 = (toktx, png2, ktx2) => {
|
|
223203
|
+
var encodeKtx2 = (toktx, png2, ktx2) => new Promise((resolve14, reject) => {
|
|
223140
223204
|
const args = ["--t2", "--encode", "uastc", "--uastc_quality", "2", "--zcmp", "18", "--genmipmap", "--assign_oetf", "srgb", ktx2, png2];
|
|
223141
|
-
const p2 =
|
|
223142
|
-
|
|
223143
|
-
|
|
223144
|
-
|
|
223145
|
-
}
|
|
223146
|
-
|
|
223205
|
+
const p2 = spawn6(toktx, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
223206
|
+
let out = "";
|
|
223207
|
+
p2.stdout.on("data", (d) => {
|
|
223208
|
+
out += String(d);
|
|
223209
|
+
});
|
|
223210
|
+
p2.stderr.on("data", (d) => {
|
|
223211
|
+
out += String(d);
|
|
223212
|
+
});
|
|
223213
|
+
p2.on("error", (e2) => reject(new CliError(`toktx failed (${e2.message}) while encoding ${ktx2}`)));
|
|
223214
|
+
p2.on("close", (status2) => {
|
|
223215
|
+
if (status2 === 0)
|
|
223216
|
+
resolve14();
|
|
223217
|
+
else
|
|
223218
|
+
reject(new CliError(`toktx failed (${status2 ?? "?"}) while encoding ${ktx2}:
|
|
223219
|
+
${out.trim()}`));
|
|
223220
|
+
});
|
|
223221
|
+
});
|
|
223222
|
+
var pageFile = (stem, page, light, ext2 = ".ktx2") => `${stem}${light ? "-light" : ""}${page > 0 ? `_${page}` : ""}${ext2}`;
|
|
223147
223223
|
var bake = async (args) => {
|
|
223148
223224
|
let root;
|
|
223149
223225
|
try {
|
|
@@ -223153,6 +223229,9 @@ var bake = async (args) => {
|
|
|
223153
223229
|
}
|
|
223154
223230
|
const toktx = requireToktx();
|
|
223155
223231
|
const outDir = resolve13(root, flagStr(args, "out") ?? "assets/lightmap");
|
|
223232
|
+
const stem = flagStr(args, "name") ?? "lightmap";
|
|
223233
|
+
if (!/^[A-Za-z0-9_-]+$/.test(stem))
|
|
223234
|
+
throw new CliError(`--name wants a plain file stem (letters, digits, - and _), got "${stem}".`);
|
|
223156
223235
|
const entryFlag = flagStr(args, "entry");
|
|
223157
223236
|
const entryFile = entryFlag ?? "main.ts";
|
|
223158
223237
|
if (!existsSync28(resolve13(root, entryFile))) {
|
|
@@ -223162,11 +223241,19 @@ var bake = async (args) => {
|
|
|
223162
223241
|
outDir: outDir.replace(/\\/g, "/"),
|
|
223163
223242
|
size: num(args, "size", 4096, 256, 16384),
|
|
223164
223243
|
texel: num(args, "texel", 0.02, 0.001, 2),
|
|
223244
|
+
pages: num(args, "pages", 4, 1, 16),
|
|
223165
223245
|
sunRays: num(args, "sun-rays", 32, 1, 1024),
|
|
223166
223246
|
aoRays: num(args, "ao-rays", 64, 1, 4096),
|
|
223167
223247
|
aoDistance: num(args, "ao-distance", 2, 0.01, 1000),
|
|
223168
223248
|
bias: num(args, "bias", 0.02, 0.0001, 1),
|
|
223169
223249
|
sunAngle: num(args, "sun-angle", 0.5, 0.01, 30),
|
|
223250
|
+
lightRays: num(args, "light-rays", 16, 1, 256),
|
|
223251
|
+
lightRadius: num(args, "light-radius", 0.1, 0.001, 5),
|
|
223252
|
+
bounce: num(args, "bounce", 0, 0, 1),
|
|
223253
|
+
bounceDistance: num(args, "bounce-distance", 8, 0.5, 100),
|
|
223254
|
+
bounceRays: num(args, "bounce-rays", 1, 1, 32),
|
|
223255
|
+
coplanarSkip: num(args, "coplanar-skip", 0.05, 0, 1),
|
|
223256
|
+
denoise: num(args, "denoise", 2, 0, 4),
|
|
223170
223257
|
volumeCell: flagBool(args, "no-volume") ? 0 : num(args, "cell", 0.5, 0.05, 20)
|
|
223171
223258
|
};
|
|
223172
223259
|
const frames = num(args, "frames", 900, 30, 1e5);
|
|
@@ -223180,7 +223267,7 @@ var bake = async (args) => {
|
|
|
223180
223267
|
import ${JSON.stringify(importPath)}
|
|
223181
223268
|
`;
|
|
223182
223269
|
mkdirSync21(outDir, { recursive: true });
|
|
223183
|
-
ensurePlaceholders(outDir);
|
|
223270
|
+
ensurePlaceholders(outDir, stem);
|
|
223184
223271
|
const desktopRenderer = resolveDesktopRenderer(root, args);
|
|
223185
223272
|
const { js, resources } = await buildBundle(args, undefined, {
|
|
223186
223273
|
localAssets: true,
|
|
@@ -223190,10 +223277,10 @@ import ${JSON.stringify(importPath)}
|
|
|
223190
223277
|
});
|
|
223191
223278
|
const scratch = mkdtempSync4(join30(tmpdir4(), "lecodes-lightmap-"));
|
|
223192
223279
|
const outPng = join30(scratch, "frame.png");
|
|
223193
|
-
note(`Baking ${cfg.size}² at ${(cfg.texel * 100).toFixed(1)} cm texels (${cfg.sunRays} sun + ${cfg.aoRays} AO rays)${cfg.volumeCell ? ` + a ${cfg.volumeCell} m light volume` : ""} → ${relative4(root, outDir) || "."}
|
|
223280
|
+
note(`Baking up to ${cfg.pages} × ${cfg.size}² at ${(cfg.texel * 100).toFixed(1)} cm texels (${cfg.sunRays} sun + ${cfg.aoRays} AO + ${cfg.lightRays} light rays)${cfg.volumeCell ? ` + a ${cfg.volumeCell} m light volume` : ""} → ${relative4(root, outDir) || "."}/${stem}.*…`);
|
|
223194
223281
|
let output = "";
|
|
223195
223282
|
try {
|
|
223196
|
-
const timeoutMs = Number(flagStr(args, "timeout")) ||
|
|
223283
|
+
const timeoutMs = Number(flagStr(args, "timeout")) || 24 * 3600 * 1000;
|
|
223197
223284
|
const res = await runDesktopRender(js, resources, {
|
|
223198
223285
|
renderer: desktopRenderer,
|
|
223199
223286
|
width,
|
|
@@ -223211,28 +223298,76 @@ import ${JSON.stringify(importPath)}
|
|
|
223211
223298
|
throw e2;
|
|
223212
223299
|
output = msg;
|
|
223213
223300
|
} finally {
|
|
223214
|
-
|
|
223301
|
+
try {
|
|
223302
|
+
rmSync9(scratch, { recursive: true, force: true });
|
|
223303
|
+
} catch {}
|
|
223215
223304
|
}
|
|
223216
223305
|
const lines = output.split(/\r?\n/).filter((l2) => l2.startsWith("[lightmap]"));
|
|
223217
223306
|
for (const l2 of lines) {
|
|
223218
223307
|
const text = l2.slice("[lightmap]".length).trim();
|
|
223219
223308
|
if (text === "done")
|
|
223220
223309
|
continue;
|
|
223221
|
-
logErr(text.startsWith("error") ? c.red(`✗ ${text}`) : c.dim(` ${text}`));
|
|
223310
|
+
logErr(text.startsWith("error") ? c.red(`✗ ${text}`) : text.startsWith("warning") ? c.yellow(` ${text}`) : c.dim(` ${text}`));
|
|
223222
223311
|
}
|
|
223223
223312
|
if (/\[lightmap\] done/.test(output)) {
|
|
223224
|
-
const
|
|
223225
|
-
|
|
223226
|
-
|
|
223227
|
-
|
|
223313
|
+
const bakePath = join30(outDir, "lightmap.bake");
|
|
223314
|
+
if (!existsSync28(bakePath))
|
|
223315
|
+
throw new CliError(`The host reported a bake but ${bakePath} is missing.`);
|
|
223316
|
+
const data = JSON.parse(readFileSync25(bakePath, "utf8"));
|
|
223317
|
+
const pages = Math.max(1, data.pages ?? 1);
|
|
223318
|
+
const hasLight = !!data.lightTextures?.length;
|
|
223228
223319
|
const t0 = Date.now();
|
|
223229
|
-
|
|
223230
|
-
const
|
|
223231
|
-
|
|
223232
|
-
|
|
223233
|
-
|
|
223234
|
-
|
|
223235
|
-
|
|
223320
|
+
let pngKb = 0, ktxKb = 0;
|
|
223321
|
+
const encodePage = async (page, light) => {
|
|
223322
|
+
const png2 = join30(outDir, pageFile("lightmap", page, light, ".png"));
|
|
223323
|
+
const ktx2 = join30(outDir, pageFile(stem, page, light));
|
|
223324
|
+
if (!existsSync28(png2))
|
|
223325
|
+
throw new CliError(`The host reported a bake but ${png2} is missing.`);
|
|
223326
|
+
await encodeKtx2(toktx, png2, ktx2);
|
|
223327
|
+
pngKb += statSync10(png2).size / 1024;
|
|
223328
|
+
ktxKb += statSync10(ktx2).size / 1024;
|
|
223329
|
+
unlinkSync(png2);
|
|
223330
|
+
};
|
|
223331
|
+
const encodes = [];
|
|
223332
|
+
for (let p2 = 0;p2 < pages; p2++) {
|
|
223333
|
+
encodes.push(encodePage(p2, false));
|
|
223334
|
+
if (hasLight)
|
|
223335
|
+
encodes.push(encodePage(p2, true));
|
|
223336
|
+
}
|
|
223337
|
+
await Promise.all(encodes);
|
|
223338
|
+
for (let p2 = pages;p2 < 16; p2++) {
|
|
223339
|
+
for (const light of [false, true]) {
|
|
223340
|
+
const stale = join30(outDir, pageFile(stem, p2, light));
|
|
223341
|
+
if (existsSync28(stale) && statSync10(stale).size !== PLACEHOLDER_KTX2.length)
|
|
223342
|
+
writeFileSync22(stale, PLACEHOLDER_KTX2);
|
|
223343
|
+
}
|
|
223344
|
+
}
|
|
223345
|
+
if (!hasLight) {
|
|
223346
|
+
const light = join30(outDir, pageFile(stem, 0, true));
|
|
223347
|
+
if (existsSync28(light) && statSync10(light).size !== PLACEHOLDER_KTX2.length)
|
|
223348
|
+
writeFileSync22(light, PLACEHOLDER_KTX2);
|
|
223349
|
+
}
|
|
223350
|
+
data.texture = pageFile(stem, 0, false);
|
|
223351
|
+
data.textures = Array.from({ length: pages }, (_, p2) => pageFile(stem, p2, false));
|
|
223352
|
+
if (hasLight)
|
|
223353
|
+
data.lightTextures = Array.from({ length: pages }, (_, p2) => pageFile(stem, p2, true));
|
|
223354
|
+
if (data.volume)
|
|
223355
|
+
data.volume.file = `${stem}.volume`;
|
|
223356
|
+
writeFileSync22(join30(outDir, `${stem}.bake`), JSON.stringify(data, null, 1) + `
|
|
223357
|
+
`);
|
|
223358
|
+
if (stem !== "lightmap")
|
|
223359
|
+
unlinkSync(bakePath);
|
|
223360
|
+
const volumeSrc = join30(outDir, "lightmap.volume");
|
|
223361
|
+
const hasVolume = cfg.volumeCell > 0 && existsSync28(volumeSrc);
|
|
223362
|
+
if (hasVolume && stem !== "lightmap") {
|
|
223363
|
+
rmSync9(join30(outDir, `${stem}.volume`), { force: true });
|
|
223364
|
+
renameSync3(volumeSrc, join30(outDir, `${stem}.volume`));
|
|
223365
|
+
}
|
|
223366
|
+
logErr(c.dim(` encoded ${pages} page(s)${hasLight ? " + the light atlas" : ""} (UASTC + mips, ${Math.round(ktxKb)} KB from ${Math.round(pngKb)} KB of rasters) in ${((Date.now() - t0) / 1000).toFixed(1)} s`));
|
|
223367
|
+
logErr(c.green(`✓ baked → ${relative4(root, outDir) || "."}/${stem}.bake + ${data.textures.join(", ")}${hasLight ? ` + ${data.lightTextures.join(", ")}` : ""}${hasVolume ? ` + ${stem}.volume` : ""}`));
|
|
223368
|
+
const rel = (f3) => relative4(root, join30(outDir, f3)).replace(/\\/g, "/");
|
|
223369
|
+
const assets = (files) => files.length === 1 ? `asset('<rel>/${rel(files[0])}')` : `[${files.map((f3) => `asset('<rel>/${rel(f3)}')`).join(", ")}]`;
|
|
223370
|
+
logErr(c.dim(` scene file: env.lightmap: { data: asset('<rel>/${rel(`${stem}.bake`)}'), texture: ${assets(data.textures)}${hasLight ? `, light: ${assets(data.lightTextures)}` : ""}${hasVolume ? `, volume: asset('<rel>/${rel(`${stem}.volume`)}')` : ""} } — asset() paths are relative to the scene file`));
|
|
223236
223371
|
return;
|
|
223237
223372
|
}
|
|
223238
223373
|
if (lines.some((l2) => /no bake module/.test(l2))) {
|
|
@@ -223259,28 +223394,32 @@ var placeholderVolume = () => {
|
|
|
223259
223394
|
b[37] = 255;
|
|
223260
223395
|
return b;
|
|
223261
223396
|
};
|
|
223262
|
-
var ensurePlaceholders = (outDir) => {
|
|
223263
|
-
const
|
|
223264
|
-
const
|
|
223265
|
-
const
|
|
223266
|
-
|
|
223267
|
-
|
|
223397
|
+
var ensurePlaceholders = (outDir, stem) => {
|
|
223398
|
+
const missing = (f3) => !existsSync28(f3) || statSync10(f3).size === 0;
|
|
223399
|
+
const bake2 = join30(outDir, `${stem}.bake`);
|
|
223400
|
+
const ktx2 = join30(outDir, pageFile(stem, 0, false));
|
|
223401
|
+
const light = join30(outDir, pageFile(stem, 0, true));
|
|
223402
|
+
const volume = join30(outDir, `${stem}.volume`);
|
|
223403
|
+
if (missing(bake2))
|
|
223404
|
+
writeFileSync22(bake2, JSON.stringify({ version: 2, placeholder: true, size: 1, texel: 0, pages: 1, instances: [] }) + `
|
|
223268
223405
|
`);
|
|
223269
|
-
if (
|
|
223406
|
+
if (missing(ktx2))
|
|
223270
223407
|
writeFileSync22(ktx2, PLACEHOLDER_KTX2);
|
|
223271
|
-
if (
|
|
223408
|
+
if (missing(light))
|
|
223409
|
+
writeFileSync22(light, PLACEHOLDER_KTX2);
|
|
223410
|
+
if (missing(volume))
|
|
223272
223411
|
writeFileSync22(volume, placeholderVolume());
|
|
223273
223412
|
};
|
|
223274
223413
|
var lightmap = async (args) => {
|
|
223275
223414
|
const sub = args._[0];
|
|
223276
223415
|
if (sub === "bake")
|
|
223277
223416
|
return bake({ ...args, _: args._.slice(1) });
|
|
223278
|
-
throw new CliError("Usage: lecodes lightmap bake [--out assets/lightmap] [--size 4096] [--texel 0.02] [--sun-rays 32] [--ao-rays 64] [--ao-distance 2] [--bias 0.02] [--sun-angle 0.5] [--cell 0.5 | --no-volume] [--frames 900] [--entry main.ts] [--logs] (needs KTX-Software's toktx)");
|
|
223417
|
+
throw new CliError("Usage: lecodes lightmap bake [--out assets/lightmap] [--name lightmap] [--size 4096] [--pages 4] [--texel 0.02] [--sun-rays 32] [--ao-rays 64] [--ao-distance 2] [--bias 0.02] [--sun-angle 0.5] [--light-rays 16] [--light-radius 0.1] [--bounce 0..1] [--denoise 2] [--cell 0.5 | --no-volume] [--frames 900] [--timeout <ms>] [--entry main.ts] [--logs] (needs KTX-Software's toktx)");
|
|
223279
223418
|
};
|
|
223280
223419
|
|
|
223281
223420
|
// src/commands/navmesh.ts
|
|
223282
223421
|
init_manifest();
|
|
223283
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync5, readdirSync as readdirSync14, readFileSync as
|
|
223422
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync5, readdirSync as readdirSync14, readFileSync as readFileSync26, rmSync as rmSync10, statSync as statSync11, unlinkSync as unlinkSync2, writeFileSync as writeFileSync23 } from "node:fs";
|
|
223284
223423
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
223285
223424
|
import { basename as basename16, join as join31, relative as relative5, resolve as resolve14 } from "node:path";
|
|
223286
223425
|
init_util();
|
|
@@ -223299,8 +223438,8 @@ var createCreatorNav = (() => {
|
|
|
223299
223438
|
var ENVIRONMENT_IS_WORKER = typeof WorkerGlobalScope != "undefined";
|
|
223300
223439
|
var ENVIRONMENT_IS_NODE = typeof process == "object" && process.versions?.node && process.type != "renderer";
|
|
223301
223440
|
if (ENVIRONMENT_IS_NODE) {
|
|
223302
|
-
const { createRequire:
|
|
223303
|
-
var require2 =
|
|
223441
|
+
const { createRequire: createRequire5 } = await import("module");
|
|
223442
|
+
var require2 = createRequire5(import.meta.url);
|
|
223304
223443
|
}
|
|
223305
223444
|
var arguments_ = [];
|
|
223306
223445
|
var thisProgram = "./this.program";
|
|
@@ -224093,7 +224232,7 @@ var guessName = (root) => {
|
|
|
224093
224232
|
if (!f3.endsWith(".scene.ts"))
|
|
224094
224233
|
continue;
|
|
224095
224234
|
try {
|
|
224096
|
-
if (/\bnavmesh\s*:/.test(
|
|
224235
|
+
if (/\bnavmesh\s*:/.test(readFileSync26(join31(dir, f3), "utf8")))
|
|
224097
224236
|
return f3.slice(0, -".scene.ts".length);
|
|
224098
224237
|
} catch {}
|
|
224099
224238
|
}
|
|
@@ -224221,7 +224360,7 @@ import ${JSON.stringify(importPath)}
|
|
|
224221
224360
|
const geoPath = join31(outDir, `${name}.navgeo`);
|
|
224222
224361
|
if (!existsSync29(geoPath))
|
|
224223
224362
|
throw new CliError(`The host reported a dump but ${geoPath} is missing.`);
|
|
224224
|
-
const geo = readNgeo(new Uint8Array(
|
|
224363
|
+
const geo = readNgeo(new Uint8Array(readFileSync26(geoPath)));
|
|
224225
224364
|
const params = {
|
|
224226
224365
|
agentRadius: num2(args, "radius", config.agent.radius, 0.05, 10),
|
|
224227
224366
|
agentHeight: num2(args, "height", config.agent.height, 0.1, 20),
|
|
@@ -224307,7 +224446,7 @@ var login = async (args) => {
|
|
|
224307
224446
|
|
|
224308
224447
|
// src/commands/shaders.ts
|
|
224309
224448
|
init_manifest();
|
|
224310
|
-
import { readFileSync as
|
|
224449
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
224311
224450
|
init_util();
|
|
224312
224451
|
init_compile();
|
|
224313
224452
|
var collectShaders = () => {
|
|
@@ -224339,7 +224478,7 @@ var status2 = async () => {
|
|
|
224339
224478
|
if (matcId === null)
|
|
224340
224479
|
state = c.dim("unknown (matc not downloaded)");
|
|
224341
224480
|
else {
|
|
224342
|
-
const text =
|
|
224481
|
+
const text = readFileSync27(shader.absPath, "utf8");
|
|
224343
224482
|
if (shaderIsCompiled(root, text, matcId))
|
|
224344
224483
|
state = "compiled";
|
|
224345
224484
|
else {
|
|
@@ -224348,7 +224487,7 @@ var status2 = async () => {
|
|
|
224348
224487
|
}
|
|
224349
224488
|
}
|
|
224350
224489
|
log(` ${shader.path.padEnd(width)} ${state}`);
|
|
224351
|
-
const schema = parseShaderSchema(
|
|
224490
|
+
const schema = parseShaderSchema(readFileSync27(shader.absPath, "utf8"));
|
|
224352
224491
|
for (const p2 of schema.params) {
|
|
224353
224492
|
const range = p2.min !== undefined ? ` [${p2.min}..${p2.max}]` : "";
|
|
224354
224493
|
const def = p2.default !== null && p2.default !== undefined ? ` = ${JSON.stringify(p2.default)}` : "";
|
|
@@ -224391,7 +224530,7 @@ var compile3 = async (args) => {
|
|
|
224391
224530
|
}
|
|
224392
224531
|
const matcExe = await resolveMatcExe();
|
|
224393
224532
|
const matcId = matcIdentity(matcExe);
|
|
224394
|
-
const wasCompiled = new Map(shaders.map((s2) => [s2.path, shaderIsCompiled(root,
|
|
224533
|
+
const wasCompiled = new Map(shaders.map((s2) => [s2.path, shaderIsCompiled(root, readFileSync27(s2.absPath, "utf8"), matcId)]));
|
|
224395
224534
|
const errors2 = [];
|
|
224396
224535
|
for (const shader of shaders) {
|
|
224397
224536
|
try {
|
|
@@ -224425,7 +224564,7 @@ var shaders = async (args) => {
|
|
|
224425
224564
|
};
|
|
224426
224565
|
|
|
224427
224566
|
// src/commands/render.ts
|
|
224428
|
-
import { mkdirSync as mkdirSync23, readFileSync as
|
|
224567
|
+
import { mkdirSync as mkdirSync23, readFileSync as readFileSync29, writeFileSync as writeFileSync24 } from "node:fs";
|
|
224429
224568
|
import { dirname as dirname15, resolve as resolve17 } from "node:path";
|
|
224430
224569
|
|
|
224431
224570
|
// src/compile/headlessBundle.ts
|
|
@@ -224510,7 +224649,7 @@ var compileHeadlessBundle = async (args, opts = {}) => {
|
|
|
224510
224649
|
// src/compile/screenEntry.ts
|
|
224511
224650
|
init_designMeta();
|
|
224512
224651
|
init_util();
|
|
224513
|
-
import { existsSync as existsSync30, readFileSync as
|
|
224652
|
+
import { existsSync as existsSync30, readFileSync as readFileSync28, statSync as statSync12 } from "node:fs";
|
|
224514
224653
|
import { isAbsolute, join as join32, relative as relative6, resolve as resolve15 } from "node:path";
|
|
224515
224654
|
var SCREEN_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
224516
224655
|
var SCREEN_ENTRY_PATH = "/.screen-entry.ts";
|
|
@@ -224545,7 +224684,7 @@ var resolveScreenTarget = (root, file, opts = {}) => {
|
|
|
224545
224684
|
throw new CliError(`"${file}" is outside the project (${root}) — a screen renders as part of its project, so its ` + `imports and asset() files resolve from the same tree.`);
|
|
224546
224685
|
}
|
|
224547
224686
|
const key = toKey(rel);
|
|
224548
|
-
if (!/^\s*export\s+default\b/m.test(
|
|
224687
|
+
if (!/^\s*export\s+default\b/m.test(readFileSync28(abs, "utf8"))) {
|
|
224549
224688
|
throw new CliError(`${key.slice(1)} has no default export. A screen file ends with ` + `\`export default UIScreen([...])\` — or \`export default (state) => UIScreen([...])\` for screen states.`);
|
|
224550
224689
|
}
|
|
224551
224690
|
const invoke = opts.state !== undefined ? `screen(${JSON.stringify(opts.state)})` : "screen()";
|
|
@@ -224852,7 +224991,7 @@ var evaluateDesktopRun = (plan, output) => {
|
|
|
224852
224991
|
if (!error && st.expectLog !== undefined) {
|
|
224853
224992
|
const seen = consoleLines.slice(0, cutoff);
|
|
224854
224993
|
if (!seen.some((l2) => l2.includes(st.expectLog))) {
|
|
224855
|
-
const tail = seen.filter((l2) => l2.startsWith("[DEBUG]") || l2.startsWith("[INFO]") || l2.startsWith("[WARN]") || l2.startsWith("[ERROR]")).slice(-
|
|
224994
|
+
const tail = seen.filter((l2) => l2.startsWith("[DEBUG]") || l2.startsWith("[INFO]") || l2.startsWith("[WARN]") || l2.startsWith("[ERROR]")).slice(-8);
|
|
224856
224995
|
error = `expected a console line containing "${st.expectLog}" — ${tail.length === 0 ? "the app logged nothing" : `last lines: ${tail.map((l2) => `"${l2}"`).join(", ")}`}`;
|
|
224857
224996
|
}
|
|
224858
224997
|
}
|
|
@@ -224906,7 +225045,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
224906
225045
|
if (typeof value === "string") {
|
|
224907
225046
|
const abs = resolve17(baseDir, value);
|
|
224908
225047
|
try {
|
|
224909
|
-
map = JSON.parse(
|
|
225048
|
+
map = JSON.parse(readFileSync29(abs, "utf8"));
|
|
224910
225049
|
} catch (e2) {
|
|
224911
225050
|
throw new CliError(`Can't read fixtures "${value}": ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
224912
225051
|
}
|
|
@@ -224919,7 +225058,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
224919
225058
|
var readScenarioFile = (path2) => {
|
|
224920
225059
|
let raw;
|
|
224921
225060
|
try {
|
|
224922
|
-
raw = JSON.parse(
|
|
225061
|
+
raw = JSON.parse(readFileSync29(resolve17(path2), "utf8"));
|
|
224923
225062
|
} catch (e2) {
|
|
224924
225063
|
throw new CliError(`Can't read scenario "${path2}": ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
224925
225064
|
}
|
|
@@ -225133,6 +225272,26 @@ var render = async (args) => {
|
|
|
225133
225272
|
session.dispose();
|
|
225134
225273
|
}
|
|
225135
225274
|
}
|
|
225275
|
+
const mapFlag = flagStr(args, "map") ?? (flagBool(args, "map") ? "map.png" : undefined);
|
|
225276
|
+
if (mapFlag !== undefined) {
|
|
225277
|
+
note(`Rendering map…`);
|
|
225278
|
+
const title = root.split(/[\\/]/).pop();
|
|
225279
|
+
const { png: png2, data, warnings: mapWarnings } = await renderer.renderToMap(js, {
|
|
225280
|
+
...timing,
|
|
225281
|
+
maxPx: Number(flagStr(args, "max-px")) || undefined,
|
|
225282
|
+
title,
|
|
225283
|
+
labelAll: flagBool(args, "label-all")
|
|
225284
|
+
});
|
|
225285
|
+
for (const w of [...warnings, ...mapWarnings])
|
|
225286
|
+
warnErr(w);
|
|
225287
|
+
const pngPath = mapFlag.endsWith(".png") ? mapFlag : mapFlag + ".png";
|
|
225288
|
+
mkdirSync23(dirname15(resolve17(pngPath)), { recursive: true });
|
|
225289
|
+
writeFileSync24(resolve17(pngPath), png2);
|
|
225290
|
+
const jsonPath = pngPath.slice(0, -4) + ".json";
|
|
225291
|
+
writeFileSync24(resolve17(jsonPath), JSON.stringify(data, null, 2));
|
|
225292
|
+
note(`Wrote ${pngPath} + ${jsonPath}`);
|
|
225293
|
+
return done((cb) => cb());
|
|
225294
|
+
}
|
|
225136
225295
|
const pngFlag = flagStr(args, "png") ?? (flagBool(args, "png") ? "screenshot.png" : undefined);
|
|
225137
225296
|
if (pngFlag !== undefined) {
|
|
225138
225297
|
note(screen2 ? `Rendering ${screen2.label} (PNG)…` : "Rendering PNG…");
|
|
@@ -225180,7 +225339,7 @@ init_api();
|
|
|
225180
225339
|
init_config();
|
|
225181
225340
|
init_manifest();
|
|
225182
225341
|
init_util();
|
|
225183
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync31, readFileSync as
|
|
225342
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync31, readFileSync as readFileSync30, writeFileSync as writeFileSync25 } from "node:fs";
|
|
225184
225343
|
import { join as join33 } from "node:path";
|
|
225185
225344
|
var ENV_VAR = "LECODES_PUSH_KEY";
|
|
225186
225345
|
var context = () => {
|
|
@@ -225327,7 +225486,7 @@ var writeEnv = (root, key) => {
|
|
|
225327
225486
|
const touched = [];
|
|
225328
225487
|
const envPath = join33(root, ".env");
|
|
225329
225488
|
const line = `${ENV_VAR}=${key}`;
|
|
225330
|
-
const existing = existsSync31(envPath) ?
|
|
225489
|
+
const existing = existsSync31(envPath) ? readFileSync30(envPath, "utf8") : "";
|
|
225331
225490
|
if (new RegExp(`^${ENV_VAR}=`, "m").test(existing)) {
|
|
225332
225491
|
writeFileSync25(envPath, existing.replace(new RegExp(`^${ENV_VAR}=.*$`, "m"), line));
|
|
225333
225492
|
} else {
|
|
@@ -225339,7 +225498,7 @@ var writeEnv = (root, key) => {
|
|
|
225339
225498
|
}
|
|
225340
225499
|
touched.push(".env");
|
|
225341
225500
|
const ignorePath = join33(root, ".gitignore");
|
|
225342
|
-
const ignore = existsSync31(ignorePath) ?
|
|
225501
|
+
const ignore = existsSync31(ignorePath) ? readFileSync30(ignorePath, "utf8") : "";
|
|
225343
225502
|
if (!ignore.split(`
|
|
225344
225503
|
`).some((l2) => l2.trim() === ".env")) {
|
|
225345
225504
|
const separator = !ignore || ignore.endsWith(`
|
|
@@ -225525,7 +225684,7 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
225525
225684
|
|
|
225526
225685
|
// src/commands/scene.ts
|
|
225527
225686
|
init_manifest();
|
|
225528
|
-
import { existsSync as existsSync34, readFileSync as
|
|
225687
|
+
import { existsSync as existsSync34, readFileSync as readFileSync32, readdirSync as readdirSync15, statSync as statSync13, writeFileSync as writeFileSync28 } from "node:fs";
|
|
225529
225688
|
import { basename as basename17, dirname as dirname17, join as join36, resolve as resolve18 } from "node:path";
|
|
225530
225689
|
|
|
225531
225690
|
// src/compile/sceneCompile.ts
|
|
@@ -225535,7 +225694,7 @@ init_distRoot();
|
|
|
225535
225694
|
init_util();
|
|
225536
225695
|
init_projectCompile();
|
|
225537
225696
|
import { createHash as createHash8 } from "node:crypto";
|
|
225538
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync25, readFileSync as
|
|
225697
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync27 } from "node:fs";
|
|
225539
225698
|
import { join as join35 } from "node:path";
|
|
225540
225699
|
var TEXT_EXT = /\.(ts|js|json|svg|txt|md)$/i;
|
|
225541
225700
|
var rel = (key) => key.replace(/^\//, "");
|
|
@@ -225546,7 +225705,7 @@ var resolveHarness = (loadSceneHarness2) => {
|
|
|
225546
225705
|
} catch {
|
|
225547
225706
|
const vendored = join35(distRoot, "runtime", "scene-harness.json");
|
|
225548
225707
|
if (existsSync33(vendored))
|
|
225549
|
-
return JSON.parse(
|
|
225708
|
+
return JSON.parse(readFileSync31(vendored, "utf8"));
|
|
225550
225709
|
throw new CliError("scene-editor harness sources not found — reinstall the CLI or set LECODES_SCENE_HARNESS_DIR.");
|
|
225551
225710
|
}
|
|
225552
225711
|
};
|
|
@@ -225558,16 +225717,16 @@ var compileSceneEditor = async (opts) => {
|
|
|
225558
225717
|
for (const file of scan2.files) {
|
|
225559
225718
|
const path2 = "./" + rel(file.path);
|
|
225560
225719
|
if (TEXT_EXT.test(path2)) {
|
|
225561
|
-
entries.push({ path: path2, type: "text", text:
|
|
225720
|
+
entries.push({ path: path2, type: "text", text: readFileSync31(file.absPath, "utf8") });
|
|
225562
225721
|
} else if (/\.mat$/i.test(path2)) {
|
|
225563
|
-
entries.push({ path: path2, type: "shader", text:
|
|
225722
|
+
entries.push({ path: path2, type: "shader", text: readFileSync31(file.absPath, "utf8"), absPath: file.absPath });
|
|
225564
225723
|
} else {
|
|
225565
225724
|
entries.push({ path: path2, type: "resource", fileSrc: "/project/" + rel(file.path) });
|
|
225566
225725
|
}
|
|
225567
225726
|
}
|
|
225568
225727
|
const shaderEntries = entries.filter((e2) => e2.type === "shader");
|
|
225569
225728
|
if (shaderEntries.length > 0) {
|
|
225570
|
-
const { warnings } = await applyLocalShaders(shaderEntries, { root, srcPrefix: "/project/.lecodes/shaders", platforms: ["
|
|
225729
|
+
const { warnings } = await applyLocalShaders(shaderEntries, { root, srcPrefix: "/project/.lecodes/shaders", platforms: ["opengl", "webgl-lite"] });
|
|
225571
225730
|
for (const w of warnings)
|
|
225572
225731
|
warnErr(w);
|
|
225573
225732
|
const { buildLiteMaterialArtifact: buildLiteMaterialArtifact2 } = await Promise.resolve().then(() => (init_compile(), exports_compile));
|
|
@@ -225581,7 +225740,7 @@ var compileSceneEditor = async (opts) => {
|
|
|
225581
225740
|
if (!existsSync33(join35(dir, liteName)))
|
|
225582
225741
|
writeFileSync27(join35(dir, liteName), JSON.stringify(buildLiteMaterialArtifact2(e2.text ?? "")));
|
|
225583
225742
|
const src = `/project/.lecodes/shaders/${hash}_opengl.filamat`;
|
|
225584
|
-
e2.shaders = ["opengl", "webgl
|
|
225743
|
+
e2.shaders = ["opengl", "webgl-lite"].map((platform) => ({ platform, src }));
|
|
225585
225744
|
}
|
|
225586
225745
|
}
|
|
225587
225746
|
const scene = scenePath.startsWith("./") ? scenePath : "./" + rel(scenePath);
|
|
@@ -225621,6 +225780,13 @@ var findAppRoot = (start) => {
|
|
|
225621
225780
|
dir = parent;
|
|
225622
225781
|
}
|
|
225623
225782
|
};
|
|
225783
|
+
var projectRootOf = (dir) => {
|
|
225784
|
+
try {
|
|
225785
|
+
return findProjectRoot(dir);
|
|
225786
|
+
} catch {
|
|
225787
|
+
return findAppRoot(dir) ?? dir;
|
|
225788
|
+
}
|
|
225789
|
+
};
|
|
225624
225790
|
var getContext2 = (args) => {
|
|
225625
225791
|
let root;
|
|
225626
225792
|
let manifest;
|
|
@@ -225651,7 +225817,7 @@ var writeMcpConfig2 = (root, port) => {
|
|
|
225651
225817
|
let config = {};
|
|
225652
225818
|
if (existsSync34(path2)) {
|
|
225653
225819
|
try {
|
|
225654
|
-
config = JSON.parse(
|
|
225820
|
+
config = JSON.parse(readFileSync32(path2, "utf8"));
|
|
225655
225821
|
} catch {
|
|
225656
225822
|
warnErr(".mcp.json exists but isn't valid JSON — left it untouched. Add the lecodes-scene server by hand.");
|
|
225657
225823
|
return;
|
|
@@ -225715,13 +225881,170 @@ var scene = async (args) => {
|
|
|
225715
225881
|
openBrowser(server2.url);
|
|
225716
225882
|
};
|
|
225717
225883
|
|
|
225884
|
+
// src/commands/thumbs.ts
|
|
225885
|
+
import { createRequire as createRequire5 } from "node:module";
|
|
225886
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
225887
|
+
import { existsSync as existsSync35, mkdtempSync as mkdtempSync6, readdirSync as readdirSync16, rmSync as rmSync12, statSync as statSync14 } from "node:fs";
|
|
225888
|
+
import { tmpdir as tmpdir6 } from "node:os";
|
|
225889
|
+
import { extname, join as join37, relative as relative7, resolve as resolve19 } from "node:path";
|
|
225890
|
+
init_util();
|
|
225891
|
+
var DEFAULT_SIZE = 256;
|
|
225892
|
+
var IMAGE_EXT = /\.(png|jpe?g|webp|bmp|gif|tiff?|ktx2)$/i;
|
|
225893
|
+
var RENDERED_EXT = /\.(glb|gltf|material\.ts|scene\.ts)$/i;
|
|
225894
|
+
var findKtx = () => {
|
|
225895
|
+
const exe = process.platform === "win32" ? "ktx.exe" : "ktx";
|
|
225896
|
+
const candidates = [
|
|
225897
|
+
process.env.LECODES_KTX,
|
|
225898
|
+
process.env.KTX_CLI,
|
|
225899
|
+
process.env.KTX_TOKTX?.replace(/toktx(\.exe)?$/i, exe),
|
|
225900
|
+
process.platform === "win32" ? join37(process.env.LOCALAPPDATA ?? "", "Programs", "KTX-Software", "bin", exe) : null,
|
|
225901
|
+
process.platform === "win32" ? join37(process.env.ProgramFiles ?? "", "KTX-Software", "bin", exe) : null,
|
|
225902
|
+
"/usr/local/bin/ktx",
|
|
225903
|
+
"/opt/homebrew/bin/ktx"
|
|
225904
|
+
].filter((p2) => !!p2);
|
|
225905
|
+
for (const path2 of candidates) {
|
|
225906
|
+
if (existsSync35(path2))
|
|
225907
|
+
return path2;
|
|
225908
|
+
}
|
|
225909
|
+
try {
|
|
225910
|
+
execFileSync7(exe, ["--version"], { stdio: "ignore" });
|
|
225911
|
+
return exe;
|
|
225912
|
+
} catch {
|
|
225913
|
+
return null;
|
|
225914
|
+
}
|
|
225915
|
+
};
|
|
225916
|
+
var sharpResizer = () => {
|
|
225917
|
+
try {
|
|
225918
|
+
const req = createRequire5(import.meta.url);
|
|
225919
|
+
const sharp = createRequire5(req.resolve("lecodes-assets/cli"))("sharp");
|
|
225920
|
+
return async (file, size) => sharp(file).resize({ width: size, height: size, fit: "inside", withoutEnlargement: true }).png().toBuffer();
|
|
225921
|
+
} catch {
|
|
225922
|
+
return null;
|
|
225923
|
+
}
|
|
225924
|
+
};
|
|
225925
|
+
var jimpResizer = () => async (file, size) => {
|
|
225926
|
+
const { Jimp: Jimp2 } = await Promise.resolve().then(() => (init_esm30(), exports_esm2));
|
|
225927
|
+
const img = await Jimp2.read(file);
|
|
225928
|
+
if (Math.max(img.width, img.height) > size)
|
|
225929
|
+
img.scaleToFit({ w: size, h: size });
|
|
225930
|
+
return await img.getBuffer("image/png");
|
|
225931
|
+
};
|
|
225932
|
+
var ktxToPng = (ktx, file, out) => {
|
|
225933
|
+
const run2 = (args) => execFileSync7(ktx, args, { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
|
|
225934
|
+
try {
|
|
225935
|
+
run2(["extract", "--transcode", "rgba8", "--level", "0", file, out]);
|
|
225936
|
+
} catch (e2) {
|
|
225937
|
+
run2(["extract", "--level", "0", file, out]);
|
|
225938
|
+
if (!existsSync35(out))
|
|
225939
|
+
throw e2;
|
|
225940
|
+
}
|
|
225941
|
+
};
|
|
225942
|
+
var collect = (dir) => {
|
|
225943
|
+
const out = [];
|
|
225944
|
+
for (const name of readdirSync16(dir)) {
|
|
225945
|
+
if (name === "node_modules" || name.startsWith("."))
|
|
225946
|
+
continue;
|
|
225947
|
+
const full = join37(dir, name);
|
|
225948
|
+
if (statSync14(full).isDirectory())
|
|
225949
|
+
out.push(...collect(full));
|
|
225950
|
+
else if (IMAGE_EXT.test(name))
|
|
225951
|
+
out.push(full);
|
|
225952
|
+
}
|
|
225953
|
+
return out;
|
|
225954
|
+
};
|
|
225955
|
+
var thumbs = async (args) => {
|
|
225956
|
+
const root = projectRootOf(process.cwd());
|
|
225957
|
+
let sceneServer;
|
|
225958
|
+
try {
|
|
225959
|
+
sceneServer = await import("lecodes-3d-editor/server");
|
|
225960
|
+
} catch {
|
|
225961
|
+
throw new CliError("The scene editor isn't installed (it owns the preview cache). Run: npm install -g lecodes-3d-editor");
|
|
225962
|
+
}
|
|
225963
|
+
const size = Number(flagStr(args, "size")) || DEFAULT_SIZE;
|
|
225964
|
+
const force = flagBool(args, "force");
|
|
225965
|
+
let files = [];
|
|
225966
|
+
const rendered = [];
|
|
225967
|
+
if (args._.length > 0) {
|
|
225968
|
+
for (const arg of args._) {
|
|
225969
|
+
const abs = resolve19(process.cwd(), arg);
|
|
225970
|
+
if (!existsSync35(abs))
|
|
225971
|
+
throw new CliError(`No such file or folder: ${arg}`);
|
|
225972
|
+
if (statSync14(abs).isDirectory())
|
|
225973
|
+
files.push(...collect(abs));
|
|
225974
|
+
else if (IMAGE_EXT.test(abs))
|
|
225975
|
+
files.push(abs);
|
|
225976
|
+
else if (RENDERED_EXT.test(abs))
|
|
225977
|
+
rendered.push(arg);
|
|
225978
|
+
else
|
|
225979
|
+
throw new CliError(`Not a previewable asset: ${arg}`);
|
|
225980
|
+
}
|
|
225981
|
+
} else {
|
|
225982
|
+
files = collect(root);
|
|
225983
|
+
}
|
|
225984
|
+
files = [...new Set(files)];
|
|
225985
|
+
if (files.length === 0 && rendered.length === 0) {
|
|
225986
|
+
log("No images to thumbnail.");
|
|
225987
|
+
return;
|
|
225988
|
+
}
|
|
225989
|
+
const ktx = files.some((f3) => f3.toLowerCase().endsWith(".ktx2")) ? findKtx() : null;
|
|
225990
|
+
const sharp = sharpResizer();
|
|
225991
|
+
const resize = sharp ?? jimpResizer();
|
|
225992
|
+
const tmp = mkdtempSync6(join37(tmpdir6(), "lecodes-thumbs-"));
|
|
225993
|
+
let made = 0, fresh = 0;
|
|
225994
|
+
const skipped = [];
|
|
225995
|
+
try {
|
|
225996
|
+
for (const [i2, file] of files.entries()) {
|
|
225997
|
+
const asset = "./" + toKey(relative7(root, file));
|
|
225998
|
+
progress(i2, files.length, asset);
|
|
225999
|
+
const hash = sceneServer.hashAsset(root, asset);
|
|
226000
|
+
if (!hash)
|
|
226001
|
+
continue;
|
|
226002
|
+
if (!force && sceneServer.previewIsCurrent(root, asset, hash)) {
|
|
226003
|
+
fresh++;
|
|
226004
|
+
continue;
|
|
226005
|
+
}
|
|
226006
|
+
const ext2 = extname(file).toLowerCase();
|
|
226007
|
+
if (ext2 === ".webp" && !sharp) {
|
|
226008
|
+
skipped.push(`${asset} (webp needs sharp — npm install -g lecodes-assets)`);
|
|
226009
|
+
continue;
|
|
226010
|
+
}
|
|
226011
|
+
try {
|
|
226012
|
+
let source = file;
|
|
226013
|
+
if (ext2 === ".ktx2") {
|
|
226014
|
+
if (!ktx) {
|
|
226015
|
+
skipped.push(`${asset} (KTX2 needs KTX-Software's \`ktx\` — set LECODES_KTX or put it on PATH)`);
|
|
226016
|
+
continue;
|
|
226017
|
+
}
|
|
226018
|
+
source = join37(tmp, `${i2}.png`);
|
|
226019
|
+
ktxToPng(ktx, file, source);
|
|
226020
|
+
}
|
|
226021
|
+
sceneServer.writePreviewFile(root, asset, await resize(source, size));
|
|
226022
|
+
made++;
|
|
226023
|
+
} catch (e2) {
|
|
226024
|
+
skipped.push(`${asset} (${(e2?.message ?? String(e2)).split(`
|
|
226025
|
+
`)[0]})`);
|
|
226026
|
+
}
|
|
226027
|
+
}
|
|
226028
|
+
} finally {
|
|
226029
|
+
endProgress();
|
|
226030
|
+
rmSync12(tmp, { recursive: true, force: true });
|
|
226031
|
+
}
|
|
226032
|
+
log(`${c.bold(String(made))} generated · ${fresh} already current${skipped.length > 0 ? ` · ${skipped.length} skipped` : ""}`);
|
|
226033
|
+
for (const s2 of skipped)
|
|
226034
|
+
warnErr(s2);
|
|
226035
|
+
if (rendered.length > 0) {
|
|
226036
|
+
warnErr(`Models, materials and prefabs are RENDERED, not decoded — the scene editor does those: ${rendered.join(", ")}`);
|
|
226037
|
+
}
|
|
226038
|
+
note(`Cache: ${join37(root, ".lecodes", "preview")} (re-runs skip everything unchanged)`);
|
|
226039
|
+
};
|
|
226040
|
+
|
|
225718
226041
|
// src/commands/assets.ts
|
|
225719
226042
|
init_util();
|
|
225720
226043
|
|
|
225721
226044
|
// src/cmgenTool.ts
|
|
225722
|
-
import { existsSync as
|
|
226045
|
+
import { existsSync as existsSync36, readdirSync as readdirSync17 } from "node:fs";
|
|
225723
226046
|
import { homedir as homedir8 } from "node:os";
|
|
225724
|
-
import { join as
|
|
226047
|
+
import { join as join38, resolve as resolve20 } from "node:path";
|
|
225725
226048
|
init_util();
|
|
225726
226049
|
var exeName2 = () => process.platform === "win32" ? "cmgen.exe" : "cmgen";
|
|
225727
226050
|
var platformKey3 = () => {
|
|
@@ -225731,10 +226054,10 @@ var platformKey3 = () => {
|
|
|
225731
226054
|
return "linux-x64";
|
|
225732
226055
|
throw new CliError(process.platform === "darwin" ? "cmgen isn't published for macOS yet — build filament's host tools locally and set LECODES_CMGEN." : `cmgen isn't published for ${process.platform}.`);
|
|
225733
226056
|
};
|
|
225734
|
-
var cacheRoot3 = () =>
|
|
226057
|
+
var cacheRoot3 = () => join38(homedir8(), ".lecodes", "cmgen");
|
|
225735
226058
|
var findCmgenIn = (dir) => {
|
|
225736
|
-
for (const entry of
|
|
225737
|
-
const p2 =
|
|
226059
|
+
for (const entry of readdirSync17(dir, { withFileTypes: true })) {
|
|
226060
|
+
const p2 = join38(dir, entry.name);
|
|
225738
226061
|
if (entry.isFile() && entry.name === exeName2())
|
|
225739
226062
|
return p2;
|
|
225740
226063
|
if (entry.isDirectory()) {
|
|
@@ -225747,7 +226070,7 @@ var findCmgenIn = (dir) => {
|
|
|
225747
226070
|
};
|
|
225748
226071
|
var installedCmgenVersions = () => {
|
|
225749
226072
|
try {
|
|
225750
|
-
return
|
|
226073
|
+
return readdirSync17(cacheRoot3(), { withFileTypes: true }).filter((e2) => e2.isDirectory() && e2.name.startsWith("cmgen-")).map((e2) => e2.name.slice("cmgen-".length)).filter((v) => findCmgenIn(join38(cacheRoot3(), `cmgen-${v}`)) !== null).sort(semverNewer);
|
|
225751
226074
|
} catch {
|
|
225752
226075
|
return [];
|
|
225753
226076
|
}
|
|
@@ -225769,19 +226092,19 @@ var downloadCmgen = async (version, versions, dest) => {
|
|
|
225769
226092
|
var resolveCmgenExeCached = () => {
|
|
225770
226093
|
const override = process.env.LECODES_CMGEN;
|
|
225771
226094
|
if (override) {
|
|
225772
|
-
if (!
|
|
226095
|
+
if (!existsSync36(override))
|
|
225773
226096
|
throw new CliError(`LECODES_CMGEN points at "${override}" which doesn't exist.`);
|
|
225774
|
-
return
|
|
226097
|
+
return resolve20(override);
|
|
225775
226098
|
}
|
|
225776
226099
|
const cached = installedCmgenVersions()[0];
|
|
225777
|
-
return cached ? findCmgenIn(
|
|
226100
|
+
return cached ? findCmgenIn(join38(cacheRoot3(), `cmgen-${cached}`)) : null;
|
|
225778
226101
|
};
|
|
225779
226102
|
var resolveCmgenExe = async () => {
|
|
225780
226103
|
const cached = resolveCmgenExeCached();
|
|
225781
226104
|
if (cached)
|
|
225782
226105
|
return cached;
|
|
225783
226106
|
const { latest, versions } = await fetchCmgenManifest();
|
|
225784
|
-
const dir =
|
|
226107
|
+
const dir = join38(cacheRoot3(), `cmgen-${latest}`);
|
|
225785
226108
|
await downloadCmgen(latest, versions, dir);
|
|
225786
226109
|
const exe = findCmgenIn(dir);
|
|
225787
226110
|
if (!exe)
|
|
@@ -225839,8 +226162,8 @@ var status3 = async (_args) => {
|
|
|
225839
226162
|
};
|
|
225840
226163
|
|
|
225841
226164
|
// src/commands/test.ts
|
|
225842
|
-
import { existsSync as
|
|
225843
|
-
import { dirname as dirname18, resolve as
|
|
226165
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync26, readFileSync as readFileSync33, readdirSync as readdirSync18 } from "node:fs";
|
|
226166
|
+
import { dirname as dirname18, resolve as resolve21 } from "node:path";
|
|
225844
226167
|
init_manifest();
|
|
225845
226168
|
init_util();
|
|
225846
226169
|
var deriveDesignFlows = (meta, entryScreen) => {
|
|
@@ -225903,7 +226226,7 @@ var slug3 = (s2) => s2.replace(/[^a-zA-Z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").
|
|
|
225903
226226
|
var readFlowFile = (abs, displayName) => {
|
|
225904
226227
|
let raw;
|
|
225905
226228
|
try {
|
|
225906
|
-
raw = JSON.parse(
|
|
226229
|
+
raw = JSON.parse(readFileSync33(abs, "utf8"));
|
|
225907
226230
|
} catch (e2) {
|
|
225908
226231
|
throw new CliError(`Can't read "${displayName}": ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
225909
226232
|
}
|
|
@@ -225958,40 +226281,40 @@ var test = async (args) => {
|
|
|
225958
226281
|
if (!Number.isFinite(nativeFixedDt) || nativeFixedDt < 0 || nativeFixedDt > 1000)
|
|
225959
226282
|
throw new CliError(`--fixed-dt wants a number of ms (0 = wall clock, max 1000), got "${fixedDtFlag}".`);
|
|
225960
226283
|
const projectViewport = desktopDefaultViewport(root);
|
|
225961
|
-
const testsDir =
|
|
225962
|
-
const designMetaPath =
|
|
226284
|
+
const testsDir = resolve21(root, flagStr(args, "dir") ?? "tests");
|
|
226285
|
+
const designMetaPath = resolve21(root, flagStr(args, "design-dir") ?? "design", "meta.json");
|
|
225963
226286
|
const asJson = flagBool(args, "json");
|
|
225964
226287
|
const out = asJson ? logErr : log;
|
|
225965
226288
|
const cases = [];
|
|
225966
226289
|
if (args._.length > 0) {
|
|
225967
226290
|
for (const given of args._) {
|
|
225968
|
-
const candidates = [
|
|
225969
|
-
const abs = candidates.find((p2) =>
|
|
226291
|
+
const candidates = [resolve21(given), resolve21(testsDir, given), resolve21(testsDir, `${given}.flow.json`)];
|
|
226292
|
+
const abs = candidates.find((p2) => existsSync37(p2));
|
|
225970
226293
|
if (!abs)
|
|
225971
226294
|
throw new CliError(`No such test: "${given}" (looked in ${testsDir}).`);
|
|
225972
226295
|
cases.push(readFlowFile(abs, given));
|
|
225973
226296
|
}
|
|
225974
|
-
} else if (
|
|
225975
|
-
for (const f3 of
|
|
225976
|
-
cases.push(readFlowFile(
|
|
226297
|
+
} else if (existsSync37(testsDir)) {
|
|
226298
|
+
for (const f3 of readdirSync18(testsDir).filter((f4) => f4.endsWith(".flow.json")).sort()) {
|
|
226299
|
+
cases.push(readFlowFile(resolve21(testsDir, f3), f3));
|
|
225977
226300
|
}
|
|
225978
226301
|
}
|
|
225979
226302
|
const fixturesFlag = flagStr(args, "fixtures");
|
|
225980
|
-
const defaultPack =
|
|
225981
|
-
const flowFixtures = fixturesFlag !== undefined ? resolveFixtures(fixturesFlag, ".") :
|
|
226303
|
+
const defaultPack = resolve21(testsDir, "fixtures.json");
|
|
226304
|
+
const flowFixtures = fixturesFlag !== undefined ? resolveFixtures(fixturesFlag, ".") : existsSync37(defaultPack) ? resolveFixtures("fixtures.json", testsDir) : undefined;
|
|
225982
226305
|
const flowsOnly = flagBool(args, "flows");
|
|
225983
226306
|
const wantFlows = !flagBool(args, "no-flows") && args._.length === 0;
|
|
225984
226307
|
if (flowsOnly)
|
|
225985
226308
|
cases.length = 0;
|
|
225986
226309
|
let skipped = [];
|
|
225987
226310
|
let entryScreen = null;
|
|
225988
|
-
if (desktop2 && wantFlows &&
|
|
226311
|
+
if (desktop2 && wantFlows && existsSync37(designMetaPath)) {
|
|
225989
226312
|
note("Design-derived flows skipped with --desktop (they tap by name; run `lecodes test` headless for them).");
|
|
225990
226313
|
}
|
|
225991
|
-
if (!desktop2 && (wantFlows || flowsOnly) &&
|
|
226314
|
+
if (!desktop2 && (wantFlows || flowsOnly) && existsSync37(designMetaPath)) {
|
|
225992
226315
|
let meta;
|
|
225993
226316
|
try {
|
|
225994
|
-
meta = JSON.parse(
|
|
226317
|
+
meta = JSON.parse(readFileSync33(designMetaPath, "utf8"));
|
|
225995
226318
|
} catch (e2) {
|
|
225996
226319
|
throw new CliError(`Can't read ${designMetaPath}: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
225997
226320
|
}
|
|
@@ -226023,16 +226346,16 @@ var test = async (args) => {
|
|
|
226023
226346
|
}, timeoutMs);
|
|
226024
226347
|
killer.unref?.();
|
|
226025
226348
|
const onConsole = flagBool(args, "logs") ? (level, text) => logErr(`${c.dim(`[${level}]`)} ${text}`) : undefined;
|
|
226026
|
-
const artifactsRoot =
|
|
226349
|
+
const artifactsRoot = resolve21(root, flagStr(args, "artifacts") ?? resolve21(testsDir, ".artifacts"));
|
|
226027
226350
|
const results = [];
|
|
226028
226351
|
const runNativeCase = async (kase) => {
|
|
226029
|
-
const caseDir =
|
|
226352
|
+
const caseDir = resolve21(artifactsRoot, slug3(kase.name));
|
|
226030
226353
|
const plan = translateScenario(kase.steps, { outDir: caseDir, headroomFrames: nativeFrames });
|
|
226031
226354
|
for (const st of plan.steps)
|
|
226032
226355
|
if (st.screenshot)
|
|
226033
226356
|
mkdirSync26(dirname18(st.screenshot), { recursive: true });
|
|
226034
226357
|
mkdirSync26(caseDir, { recursive: true });
|
|
226035
|
-
const finalPng =
|
|
226358
|
+
const finalPng = resolve21(caseDir, "final.png");
|
|
226036
226359
|
const { output } = await runDesktopRender(native.js, native.resources, {
|
|
226037
226360
|
renderer: desktopRenderer,
|
|
226038
226361
|
width: Number(flagStr(args, "width")) || kase.width || projectViewport?.width || 390,
|
|
@@ -226084,14 +226407,14 @@ var test = async (args) => {
|
|
|
226084
226407
|
onConsole
|
|
226085
226408
|
});
|
|
226086
226409
|
try {
|
|
226087
|
-
const io = fileScenarioIO(
|
|
226410
|
+
const io = fileScenarioIO(resolve21(artifactsRoot, slug3(kase.name)));
|
|
226088
226411
|
const outcome = await renderer.runScenario(session, steps, io);
|
|
226089
226412
|
result = {
|
|
226090
226413
|
name: kase.name,
|
|
226091
226414
|
kind: kase.kind,
|
|
226092
226415
|
ok: outcome.ok,
|
|
226093
226416
|
steps: outcome.steps.map((s2) => ({ desc: s2.desc, ok: s2.ok, error: s2.error })),
|
|
226094
|
-
artifacts: outcome.failureArtifacts.map((p2) =>
|
|
226417
|
+
artifacts: outcome.failureArtifacts.map((p2) => resolve21(artifactsRoot, slug3(kase.name), p2))
|
|
226095
226418
|
};
|
|
226096
226419
|
} finally {
|
|
226097
226420
|
session.dispose();
|
|
@@ -226153,17 +226476,54 @@ var test = async (args) => {
|
|
|
226153
226476
|
process.exit(failed > 0 ? 1 : 0);
|
|
226154
226477
|
};
|
|
226155
226478
|
|
|
226479
|
+
// src/commands/update.ts
|
|
226480
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
226481
|
+
import { existsSync as existsSync39, readdirSync as readdirSync19 } from "node:fs";
|
|
226482
|
+
import { homedir as homedir9 } from "node:os";
|
|
226483
|
+
import { dirname as dirname20, join as join40, resolve as resolve23 } from "node:path";
|
|
226484
|
+
init_util();
|
|
226485
|
+
|
|
226486
|
+
// src/peers.ts
|
|
226487
|
+
import { existsSync as existsSync38, readFileSync as readFileSync34 } from "node:fs";
|
|
226488
|
+
import { createRequire as createRequire6 } from "node:module";
|
|
226489
|
+
import { dirname as dirname19, join as join39 } from "node:path";
|
|
226490
|
+
var OPTIONAL_PEERS = [
|
|
226491
|
+
["lecodes-renderer", "lecodes-renderer/headless"],
|
|
226492
|
+
["lecodes-design", "lecodes-design/server"],
|
|
226493
|
+
["lecodes-3d-editor", "lecodes-3d-editor/server"],
|
|
226494
|
+
["lecodes-assets", "lecodes-assets/cli"]
|
|
226495
|
+
];
|
|
226496
|
+
var peerVersion = (name, probe) => {
|
|
226497
|
+
try {
|
|
226498
|
+
const require2 = createRequire6(import.meta.url);
|
|
226499
|
+
let dir = dirname19(require2.resolve(probe));
|
|
226500
|
+
for (let depth = 0;depth < 16; depth++) {
|
|
226501
|
+
const manifest = join39(dir, "package.json");
|
|
226502
|
+
if (existsSync38(manifest)) {
|
|
226503
|
+
const parsed = JSON.parse(readFileSync34(manifest, "utf8"));
|
|
226504
|
+
if (parsed.name === name)
|
|
226505
|
+
return parsed.version ?? "unknown";
|
|
226506
|
+
}
|
|
226507
|
+
const parent = dirname19(dir);
|
|
226508
|
+
if (parent === dir)
|
|
226509
|
+
break;
|
|
226510
|
+
dir = parent;
|
|
226511
|
+
}
|
|
226512
|
+
} catch {}
|
|
226513
|
+
return null;
|
|
226514
|
+
};
|
|
226515
|
+
|
|
226156
226516
|
// src/commands/types.ts
|
|
226157
226517
|
init_api();
|
|
226158
226518
|
init_config();
|
|
226159
226519
|
init_manifest();
|
|
226160
226520
|
init_types4();
|
|
226161
226521
|
init_util();
|
|
226162
|
-
import { resolve as
|
|
226522
|
+
import { resolve as resolve22 } from "node:path";
|
|
226163
226523
|
var label = (bundle) => `${Object.keys(bundle).length} file(s)`;
|
|
226164
226524
|
var types4 = async (args) => {
|
|
226165
226525
|
const dirArg = args._[0];
|
|
226166
|
-
const root = dirArg ?
|
|
226526
|
+
const root = dirArg ? resolve22(dirArg) : (() => {
|
|
226167
226527
|
try {
|
|
226168
226528
|
return findProjectRoot(process.cwd());
|
|
226169
226529
|
} catch {
|
|
@@ -226198,9 +226558,9 @@ var types4 = async (args) => {
|
|
|
226198
226558
|
const same = bundleHash(onDisk) === bundleHash(bundle);
|
|
226199
226559
|
if (checkOnly) {
|
|
226200
226560
|
if (Object.keys(onDisk).length === 0)
|
|
226201
|
-
throw new CliError(`No types in ${LECODES_DIR}/types/ — run \`lecodes
|
|
226561
|
+
throw new CliError(`No types in ${LECODES_DIR}/types/ — run \`lecodes update\`.`);
|
|
226202
226562
|
if (!same)
|
|
226203
|
-
throw new CliError(`Types are out of date (${label(onDisk)} on disk) — run \`lecodes
|
|
226563
|
+
throw new CliError(`Types are out of date (${label(onDisk)} on disk) — run \`lecodes update\`.`);
|
|
226204
226564
|
success(`Types are up to date (${label(onDisk)}).`);
|
|
226205
226565
|
return;
|
|
226206
226566
|
}
|
|
@@ -226221,24 +226581,161 @@ var types4 = async (args) => {
|
|
|
226221
226581
|
note("Reload the TypeScript server in your editor to pick them up.");
|
|
226222
226582
|
};
|
|
226223
226583
|
|
|
226584
|
+
// src/commands/update.ts
|
|
226585
|
+
var findProjectDir = (start) => {
|
|
226586
|
+
const home = resolve23(homedir9());
|
|
226587
|
+
let dir = resolve23(start);
|
|
226588
|
+
while (true) {
|
|
226589
|
+
if (dir !== home && (existsSync39(join40(dir, "app.json")) || existsSync39(join40(dir, ".lecodes", "manifest.json")) || existsSync39(join40(dir, ".lecodes", "types"))))
|
|
226590
|
+
return dir;
|
|
226591
|
+
const parent = dirname20(dir);
|
|
226592
|
+
if (parent === dir)
|
|
226593
|
+
return null;
|
|
226594
|
+
dir = parent;
|
|
226595
|
+
}
|
|
226596
|
+
};
|
|
226597
|
+
var NPM = "https://registry.npmjs.org";
|
|
226598
|
+
var npmLatest = async (name) => {
|
|
226599
|
+
try {
|
|
226600
|
+
const res = await fetch(`${NPM}/${name}/latest`, { signal: AbortSignal.timeout(4000) });
|
|
226601
|
+
if (!res.ok)
|
|
226602
|
+
return null;
|
|
226603
|
+
const json = await res.json();
|
|
226604
|
+
return json.version ?? null;
|
|
226605
|
+
} catch {
|
|
226606
|
+
return null;
|
|
226607
|
+
}
|
|
226608
|
+
};
|
|
226609
|
+
var semverNewer2 = (a2, b) => {
|
|
226610
|
+
const pa = a2.split(/[.-]/).map(Number), pb = b.split(/[.-]/).map(Number);
|
|
226611
|
+
for (let i2 = 0;i2 < 3; i2++) {
|
|
226612
|
+
const d = (pa[i2] ?? 0) - (pb[i2] ?? 0);
|
|
226613
|
+
if (d)
|
|
226614
|
+
return d;
|
|
226615
|
+
}
|
|
226616
|
+
return 0;
|
|
226617
|
+
};
|
|
226618
|
+
var FROM_SOURCE = /[\\/]src[\\/]commands[\\/]/.test(import.meta.url);
|
|
226619
|
+
var STANDALONE = existsSync39(join40(dirname20(process.execPath), "runtime")) && existsSync39(join40(dirname20(process.execPath), process.platform === "win32" ? "chisel.exe" : "chisel"));
|
|
226620
|
+
var update = async (args) => {
|
|
226621
|
+
const steps = [];
|
|
226622
|
+
const heading = (name, what) => log(`
|
|
226623
|
+
${c.bold(name)} ${c.dim(what)}`);
|
|
226624
|
+
const run2 = async (name, what, fn) => {
|
|
226625
|
+
heading(name, what);
|
|
226626
|
+
try {
|
|
226627
|
+
const r2 = await fn();
|
|
226628
|
+
const [outcome, detail] = Array.isArray(r2) ? r2 : [r2, undefined];
|
|
226629
|
+
steps.push({ name, outcome, detail });
|
|
226630
|
+
if (outcome === "skipped" && detail)
|
|
226631
|
+
note(`skipped — ${detail}`);
|
|
226632
|
+
} catch (e2) {
|
|
226633
|
+
const msg = e2 instanceof CliError ? e2.message : e2 instanceof Error ? e2.message : String(e2);
|
|
226634
|
+
log(c.red("✗ ") + msg);
|
|
226635
|
+
steps.push({ name, outcome: "failed", detail: msg });
|
|
226636
|
+
}
|
|
226637
|
+
};
|
|
226638
|
+
const root = findProjectDir(process.cwd());
|
|
226639
|
+
await run2("desktop", "LeCodes Desktop host (desktop run / render --desktop)", async () => {
|
|
226640
|
+
if (process.env.LECODES_DESKTOP_EXE)
|
|
226641
|
+
return ["skipped", `LECODES_DESKTOP_EXE=${process.env.LECODES_DESKTOP_EXE} (a local build; \`lecodes desktop update\` refreshes the cache anyway)`];
|
|
226642
|
+
await updateDesktop();
|
|
226643
|
+
return "ok";
|
|
226644
|
+
});
|
|
226645
|
+
await run2("matc", "Filament material compiler for local shader compiles", async () => {
|
|
226646
|
+
if (process.env.LECODES_MATC)
|
|
226647
|
+
return ["skipped", `LECODES_MATC=${process.env.LECODES_MATC} (a local matc)`];
|
|
226648
|
+
await updateMatc();
|
|
226649
|
+
return "ok";
|
|
226650
|
+
});
|
|
226651
|
+
await run2("shaders", "recompile the project's .mat shaders with the current matc", async () => {
|
|
226652
|
+
if (!root)
|
|
226653
|
+
return ["skipped", "not inside a project"];
|
|
226654
|
+
await shaders({ _: ["compile"], flags: {} });
|
|
226655
|
+
return "ok";
|
|
226656
|
+
});
|
|
226657
|
+
await run2("types", flagBool(args, "local") ? "IDE types from the SDK bundled in this CLI" : "IDE types from the server", async () => {
|
|
226658
|
+
if (!root)
|
|
226659
|
+
return ["skipped", "not inside a project"];
|
|
226660
|
+
await types4({ _: [], flags: flagBool(args, "local") ? { local: true } : {} });
|
|
226661
|
+
return "ok";
|
|
226662
|
+
});
|
|
226663
|
+
await run2("shells", "ios/ + android/ pins → newest SDK release + plugin tags, then re-sync", async () => {
|
|
226664
|
+
if (!root)
|
|
226665
|
+
return ["skipped", "not inside a project"];
|
|
226666
|
+
if (flagBool(args, "no-shells"))
|
|
226667
|
+
return ["skipped", "--no-shells"];
|
|
226668
|
+
const present = ["ios", "android"].filter((d) => existsSync39(join40(root, d)) && readdirSync19(join40(root, d)).length > 0);
|
|
226669
|
+
if (present.length === 0)
|
|
226670
|
+
return ["skipped", "no ios/ or android/ shell in this project (`lecodes app init ios|android`)"];
|
|
226671
|
+
await app({ _: ["update"], flags: {} });
|
|
226672
|
+
return "ok";
|
|
226673
|
+
});
|
|
226674
|
+
await run2("cli", "lecodes-cli + its optional peers (global npm installs)", async () => {
|
|
226675
|
+
if (flagBool(args, "no-cli"))
|
|
226676
|
+
return ["skipped", "--no-cli"];
|
|
226677
|
+
if (FROM_SOURCE)
|
|
226678
|
+
return ["skipped", "running from the repo checkout — the CLI and its peers are the repo's own"];
|
|
226679
|
+
const rows = [];
|
|
226680
|
+
for (const [name, probe] of OPTIONAL_PEERS) {
|
|
226681
|
+
const installed = peerVersion(name, probe);
|
|
226682
|
+
rows.push({ name, installed, latest: installed ? await npmLatest(name) : null });
|
|
226683
|
+
}
|
|
226684
|
+
rows.push({ name: "lecodes-cli", installed: package_default.version, latest: await npmLatest("lecodes-cli") });
|
|
226685
|
+
if (rows.every((r3) => r3.latest === null))
|
|
226686
|
+
return ["skipped", "npm unreachable"];
|
|
226687
|
+
const behind = rows.filter((r3) => r3.installed && r3.latest && semverNewer2(r3.latest, r3.installed) > 0);
|
|
226688
|
+
for (const r3 of rows) {
|
|
226689
|
+
const state = !r3.installed ? c.dim("not installed (optional — npm install -g " + r3.name + ")") : !r3.latest ? c.dim("(npm: unknown)") : behind.includes(r3) ? c.yellow("→ " + r3.latest) : c.dim("(up to date)");
|
|
226690
|
+
log(" " + r3.name.padEnd(18) + " " + (r3.installed ?? "").padEnd(8) + " " + state);
|
|
226691
|
+
}
|
|
226692
|
+
if (behind.length === 0)
|
|
226693
|
+
return "ok";
|
|
226694
|
+
const specs = behind.map((r3) => r3.name + "@latest");
|
|
226695
|
+
if (flagBool(args, "check"))
|
|
226696
|
+
return ["updated", behind.length + " behind — run: npm install -g " + specs.join(" ")];
|
|
226697
|
+
if (STANDALONE && behind.some((r3) => r3.name === "lecodes-cli")) {
|
|
226698
|
+
note("this is the standalone build — the CLI updates by re-installing the release archive, not through npm; peers still go through npm");
|
|
226699
|
+
}
|
|
226700
|
+
const toInstall = STANDALONE ? specs.filter((s2) => !s2.startsWith("lecodes-cli@")) : specs;
|
|
226701
|
+
if (toInstall.length === 0)
|
|
226702
|
+
return ["skipped", "only the standalone CLI itself is behind — download the release"];
|
|
226703
|
+
log(" " + c.dim("$") + " npm install -g " + toInstall.join(" "));
|
|
226704
|
+
const r2 = spawnSync7("npm", ["install", "-g", ...toInstall], { stdio: "inherit", shell: true });
|
|
226705
|
+
if (r2.status !== 0)
|
|
226706
|
+
throw new CliError("npm install -g exited with " + (r2.status ?? "a signal"));
|
|
226707
|
+
const names3 = toInstall.map((s2) => s2.replace("@latest", "")).join(", ");
|
|
226708
|
+
const cliToo = toInstall.some((s2) => s2.startsWith("lecodes-cli@"));
|
|
226709
|
+
return ["updated", names3 + " → latest" + (cliToo ? " (the new CLI runs from your next command)" : "")];
|
|
226710
|
+
});
|
|
226711
|
+
log(`
|
|
226712
|
+
${c.bold("Summary")}`);
|
|
226713
|
+
const width = Math.max(...steps.map((s2) => s2.name.length));
|
|
226714
|
+
for (const s2 of steps) {
|
|
226715
|
+
const mark = s2.outcome === "failed" ? c.red("✗") : s2.outcome === "skipped" ? c.dim("–") : c.green("✓");
|
|
226716
|
+
log(` ${mark} ${s2.name.padEnd(width)} ${s2.outcome === "failed" ? c.red(s2.detail ?? "failed") : s2.outcome === "skipped" ? c.dim(s2.detail ?? "skipped") : s2.detail ?? s2.outcome}`);
|
|
226717
|
+
}
|
|
226718
|
+
if (steps.some((s2) => s2.outcome === "failed"))
|
|
226719
|
+
process.exitCode = 1;
|
|
226720
|
+
};
|
|
226721
|
+
|
|
226224
226722
|
// src/index.ts
|
|
226225
|
-
import { existsSync as
|
|
226226
|
-
import {
|
|
226227
|
-
import { delimiter as delimiter2, dirname as dirname21, join as join40 } from "node:path";
|
|
226723
|
+
import { existsSync as existsSync42, realpathSync as realpathSync2 } from "node:fs";
|
|
226724
|
+
import { delimiter as delimiter2, dirname as dirname23, join as join43 } from "node:path";
|
|
226228
226725
|
|
|
226229
226726
|
// src/commands/install.ts
|
|
226230
226727
|
init_util();
|
|
226231
|
-
import { execFileSync as
|
|
226232
|
-
import { appendFileSync as appendFileSync3, chmodSync as chmodSync2, cpSync as cpSync5, existsSync as
|
|
226233
|
-
import { homedir as
|
|
226234
|
-
import { basename as basename18, delimiter, dirname as
|
|
226728
|
+
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
226729
|
+
import { appendFileSync as appendFileSync3, chmodSync as chmodSync2, cpSync as cpSync5, existsSync as existsSync40, mkdirSync as mkdirSync27, readFileSync as readFileSync35, realpathSync, rmSync as rmSync13, symlinkSync as symlinkSync2 } from "node:fs";
|
|
226730
|
+
import { homedir as homedir10 } from "node:os";
|
|
226731
|
+
import { basename as basename18, delimiter, dirname as dirname21, join as join41, resolve as resolve24, sep as sep2 } from "node:path";
|
|
226235
226732
|
var isWin = process.platform === "win32";
|
|
226236
|
-
var HOME =
|
|
226733
|
+
var HOME = homedir10();
|
|
226237
226734
|
var safeRealpath = (p2) => {
|
|
226238
226735
|
try {
|
|
226239
226736
|
return realpathSync(p2);
|
|
226240
226737
|
} catch {
|
|
226241
|
-
return
|
|
226738
|
+
return resolve24(p2);
|
|
226242
226739
|
}
|
|
226243
226740
|
};
|
|
226244
226741
|
var onPath = (dir) => {
|
|
@@ -226254,13 +226751,13 @@ var onPath = (dir) => {
|
|
|
226254
226751
|
});
|
|
226255
226752
|
};
|
|
226256
226753
|
var install = async (args) => {
|
|
226257
|
-
const bundle =
|
|
226754
|
+
const bundle = dirname21(process.execPath);
|
|
226258
226755
|
const exeName3 = basename18(process.execPath);
|
|
226259
226756
|
const chiselName = isWin ? "chisel.exe" : "chisel";
|
|
226260
|
-
if (!
|
|
226757
|
+
if (!existsSync40(join41(bundle, "runtime")) || !existsSync40(join41(bundle, chiselName))) {
|
|
226261
226758
|
throw new CliError("`lecodes install` only works from the packaged release build (the archive containing lecodes + " + "chisel + runtime/). You appear to be running from source or an npm install — install globally " + "with your package manager there instead.");
|
|
226262
226759
|
}
|
|
226263
|
-
const companions = [exeName3, chiselName, "runtime", "README.txt"].filter((f3) =>
|
|
226760
|
+
const companions = [exeName3, chiselName, "runtime", "README.txt"].filter((f3) => existsSync40(join41(bundle, f3)));
|
|
226264
226761
|
if (isWin)
|
|
226265
226762
|
return installWindows(args, bundle, companions);
|
|
226266
226763
|
return installUnix(args, bundle, companions);
|
|
@@ -226270,9 +226767,9 @@ var copyBundle = (bundle, target, companions) => {
|
|
|
226270
226767
|
if (safeRealpath(target) === safeRealpath(bundle))
|
|
226271
226768
|
return;
|
|
226272
226769
|
for (const f3 of companions) {
|
|
226273
|
-
const dest =
|
|
226274
|
-
|
|
226275
|
-
cpSync5(
|
|
226770
|
+
const dest = join41(target, f3);
|
|
226771
|
+
rmSync13(dest, { recursive: true, force: true });
|
|
226772
|
+
cpSync5(join41(bundle, f3), dest, { recursive: true });
|
|
226276
226773
|
}
|
|
226277
226774
|
};
|
|
226278
226775
|
var permError = (e2, dir, system) => {
|
|
@@ -226284,41 +226781,41 @@ var permError = (e2, dir, system) => {
|
|
|
226284
226781
|
};
|
|
226285
226782
|
var installUnix = (args, bundle, companions) => {
|
|
226286
226783
|
const system = flagBool(args, "system");
|
|
226287
|
-
const libDir =
|
|
226288
|
-
const binDir =
|
|
226289
|
-
const link2 =
|
|
226784
|
+
const libDir = resolve24(flagStr(args, "dir") ?? (system ? "/usr/local/lib/lecodes-cli" : join41(HOME, ".local", "lib", "lecodes-cli")));
|
|
226785
|
+
const binDir = resolve24(flagStr(args, "bin") ?? (system ? "/usr/local/bin" : join41(HOME, ".local", "bin")));
|
|
226786
|
+
const link2 = join41(binDir, "lecodes");
|
|
226290
226787
|
try {
|
|
226291
226788
|
copyBundle(bundle, libDir, companions);
|
|
226292
|
-
chmodSync2(
|
|
226293
|
-
chmodSync2(
|
|
226789
|
+
chmodSync2(join41(libDir, "lecodes"), 493);
|
|
226790
|
+
chmodSync2(join41(libDir, "chisel"), 493);
|
|
226294
226791
|
} catch (e2) {
|
|
226295
226792
|
throw permError(e2, libDir, system);
|
|
226296
226793
|
}
|
|
226297
226794
|
try {
|
|
226298
226795
|
mkdirSync27(binDir, { recursive: true });
|
|
226299
|
-
|
|
226300
|
-
|
|
226796
|
+
rmSync13(link2, { force: true });
|
|
226797
|
+
symlinkSync2(join41(libDir, "lecodes"), link2);
|
|
226301
226798
|
} catch (e2) {
|
|
226302
226799
|
throw permError(e2, binDir, system);
|
|
226303
226800
|
}
|
|
226304
226801
|
success(`Installed to ${c.bold(libDir)}`);
|
|
226305
|
-
log(` ${c.dim(link2 + " → " +
|
|
226802
|
+
log(` ${c.dim(link2 + " → " + join41(libDir, "lecodes"))}`);
|
|
226306
226803
|
finishPathUnix(args, binDir);
|
|
226307
226804
|
};
|
|
226308
226805
|
var shellRc = () => {
|
|
226309
226806
|
const shell = basename18(process.env.SHELL ?? "");
|
|
226310
226807
|
if (shell === "zsh")
|
|
226311
|
-
return { file:
|
|
226808
|
+
return { file: join41(HOME, ".zshrc"), name: "~/.zshrc" };
|
|
226312
226809
|
if (shell === "bash")
|
|
226313
|
-
return { file:
|
|
226314
|
-
return { file:
|
|
226810
|
+
return { file: join41(HOME, ".bashrc"), name: "~/.bashrc" };
|
|
226811
|
+
return { file: join41(HOME, ".profile"), name: "~/.profile" };
|
|
226315
226812
|
};
|
|
226316
226813
|
var PATH_MARKER = "# Added by `lecodes install`";
|
|
226317
226814
|
var appendPathToShellRc = (binDir) => {
|
|
226318
226815
|
const { file, name } = shellRc();
|
|
226319
226816
|
const line = `export PATH="${binDir}:$PATH"`;
|
|
226320
226817
|
try {
|
|
226321
|
-
const existing =
|
|
226818
|
+
const existing = existsSync40(file) ? readFileSync35(file, "utf8") : "";
|
|
226322
226819
|
if (existing.includes(line))
|
|
226323
226820
|
return name;
|
|
226324
226821
|
appendFileSync3(file, `${existing && !existing.endsWith(`
|
|
@@ -226356,7 +226853,7 @@ var finishPathUnix = (args, binDir) => {
|
|
|
226356
226853
|
log(` • or install system-wide (no PATH edit): ${c.bold("sudo lecodes install --system")}`);
|
|
226357
226854
|
};
|
|
226358
226855
|
var installWindows = (args, bundle, companions) => {
|
|
226359
|
-
const target =
|
|
226856
|
+
const target = resolve24(flagStr(args, "dir") ?? join41(process.env.LOCALAPPDATA ?? join41(HOME, "AppData", "Local"), "Programs", "lecodes-cli"));
|
|
226360
226857
|
try {
|
|
226361
226858
|
copyBundle(bundle, target, companions);
|
|
226362
226859
|
} catch (e2) {
|
|
@@ -226384,7 +226881,7 @@ var installWindows = (args, bundle, companions) => {
|
|
|
226384
226881
|
var addToUserPathWindows = (dir) => {
|
|
226385
226882
|
const script = "$d = $env:LECODES_INSTALL_DIR;" + "$p = [Environment]::GetEnvironmentVariable('Path','User'); if (-not $p) { $p = '' };" + "$parts = @($p.Split(';') | Where-Object { $_ -ne '' });" + "if ($parts -notcontains $d) { [Environment]::SetEnvironmentVariable('Path', (@($parts + $d) -join ';'), 'User') }";
|
|
226386
226883
|
try {
|
|
226387
|
-
|
|
226884
|
+
execFileSync8("powershell", ["-NoProfile", "-NonInteractive", "-Command", script], { stdio: "ignore", env: { ...process.env, LECODES_INSTALL_DIR: dir } });
|
|
226388
226885
|
return true;
|
|
226389
226886
|
} catch {
|
|
226390
226887
|
return false;
|
|
@@ -226395,9 +226892,9 @@ var addToUserPathWindows = (dir) => {
|
|
|
226395
226892
|
init_util();
|
|
226396
226893
|
|
|
226397
226894
|
// src/projectEnv.ts
|
|
226398
|
-
import { existsSync as
|
|
226399
|
-
import { homedir as
|
|
226400
|
-
import { dirname as
|
|
226895
|
+
import { existsSync as existsSync41, readFileSync as readFileSync36 } from "node:fs";
|
|
226896
|
+
import { homedir as homedir11 } from "node:os";
|
|
226897
|
+
import { dirname as dirname22, join as join42, resolve as resolve25 } from "node:path";
|
|
226401
226898
|
var KEY_RE = /^(LECODES|CREATOR)_[A-Z0-9_]+$/;
|
|
226402
226899
|
var parseDotEnv = (text) => {
|
|
226403
226900
|
const out = {};
|
|
@@ -226432,19 +226929,19 @@ var applyDotEnv = (parsed, dir, env) => {
|
|
|
226432
226929
|
continue;
|
|
226433
226930
|
let value = raw;
|
|
226434
226931
|
if (value.startsWith("./") || value.startsWith("../"))
|
|
226435
|
-
value =
|
|
226932
|
+
value = resolve25(dir, value);
|
|
226436
226933
|
else if (value === "~" || value.startsWith("~/"))
|
|
226437
|
-
value =
|
|
226934
|
+
value = join42(homedir11(), value.slice(1));
|
|
226438
226935
|
out[key] = value;
|
|
226439
226936
|
}
|
|
226440
226937
|
return out;
|
|
226441
226938
|
};
|
|
226442
226939
|
var findEnvRoot = (start) => {
|
|
226443
|
-
let dir =
|
|
226940
|
+
let dir = resolve25(start);
|
|
226444
226941
|
while (true) {
|
|
226445
|
-
if (
|
|
226942
|
+
if (existsSync41(join42(dir, "app.json")) || existsSync41(join42(dir, ".lecodes")))
|
|
226446
226943
|
return dir;
|
|
226447
|
-
const parent =
|
|
226944
|
+
const parent = dirname22(dir);
|
|
226448
226945
|
if (parent === dir)
|
|
226449
226946
|
return null;
|
|
226450
226947
|
dir = parent;
|
|
@@ -226455,10 +226952,10 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
226455
226952
|
const root = findEnvRoot(cwd);
|
|
226456
226953
|
if (!root)
|
|
226457
226954
|
return [];
|
|
226458
|
-
const file =
|
|
226459
|
-
if (!
|
|
226955
|
+
const file = join42(root, ".env");
|
|
226956
|
+
if (!existsSync41(file))
|
|
226460
226957
|
return [];
|
|
226461
|
-
const added = applyDotEnv(parseDotEnv(
|
|
226958
|
+
const added = applyDotEnv(parseDotEnv(readFileSync36(file, "utf8")), root, process.env);
|
|
226462
226959
|
for (const [k, v] of Object.entries(added))
|
|
226463
226960
|
process.env[k] = v;
|
|
226464
226961
|
return Object.keys(added);
|
|
@@ -226468,12 +226965,12 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
226468
226965
|
};
|
|
226469
226966
|
|
|
226470
226967
|
// src/index.ts
|
|
226471
|
-
var
|
|
226472
|
-
const dir =
|
|
226968
|
+
var STANDALONE2 = (() => {
|
|
226969
|
+
const dir = dirname23(process.execPath);
|
|
226473
226970
|
const chisel = process.platform === "win32" ? "chisel.exe" : "chisel";
|
|
226474
|
-
return
|
|
226971
|
+
return existsSync42(join43(dir, "runtime")) && existsSync42(join43(dir, chisel));
|
|
226475
226972
|
})();
|
|
226476
|
-
var INSTALLED =
|
|
226973
|
+
var INSTALLED = STANDALONE2 && (() => {
|
|
226477
226974
|
const exe = process.platform === "win32" ? "lecodes.exe" : "lecodes";
|
|
226478
226975
|
const self2 = (() => {
|
|
226479
226976
|
try {
|
|
@@ -226486,14 +226983,14 @@ var INSTALLED = STANDALONE && (() => {
|
|
|
226486
226983
|
if (!d)
|
|
226487
226984
|
return false;
|
|
226488
226985
|
try {
|
|
226489
|
-
const cand =
|
|
226490
|
-
return
|
|
226986
|
+
const cand = join43(d, exe);
|
|
226987
|
+
return existsSync42(cand) && realpathSync2(cand) === self2;
|
|
226491
226988
|
} catch {
|
|
226492
226989
|
return false;
|
|
226493
226990
|
}
|
|
226494
226991
|
});
|
|
226495
226992
|
})();
|
|
226496
|
-
var INSTALL_HELP =
|
|
226993
|
+
var INSTALL_HELP = STANDALONE2 && !INSTALLED ? `
|
|
226497
226994
|
install Install this standalone build so 'lecodes' is on your PATH
|
|
226498
226995
|
(copies the bundle to a library folder + a symlink/PATH entry).
|
|
226499
226996
|
--modify-path also add it to PATH (edits your shell rc / user PATH)
|
|
@@ -226580,6 +227077,11 @@ ${c.bold("Commands:")}
|
|
|
226580
227077
|
-o, --out <file> write JSON to a file instead of stdout
|
|
226581
227078
|
--png [file] rasterize a PNG (default screenshot.png;
|
|
226582
227079
|
needs @napi-rs/canvas)
|
|
227080
|
+
--map [file] draw the 3D scene's annotated top-down map
|
|
227081
|
+
(grid + XZ footprints + named markers) as
|
|
227082
|
+
<file>.png + <file>.json world-space data
|
|
227083
|
+
(default map.png; --label-all, --max-px N;
|
|
227084
|
+
also a { "map": "f.png" } script step)
|
|
226583
227085
|
--script <file> drive the app through a step list (tap/type/
|
|
226584
227086
|
scroll/wait/expect/screenshot/json steps;
|
|
226585
227087
|
games: frames/drag/hold/key/keyDown/keyUp,
|
|
@@ -226643,13 +227145,22 @@ ${c.bold("Commands:")}
|
|
|
226643
227145
|
render --desktop
|
|
226644
227146
|
(+ the render timing flags: --width/--height, --settle,
|
|
226645
227147
|
--device, --safe-area, --wait-network, --logs, --entry)
|
|
226646
|
-
|
|
226647
|
-
|
|
226648
|
-
|
|
226649
|
-
|
|
226650
|
-
|
|
226651
|
-
|
|
226652
|
-
|
|
227148
|
+
update Move everything a project depends on to its newest published
|
|
227149
|
+
state, in dependency order: the desktop host ('desktop
|
|
227150
|
+
update'), matc ('shaders update'), the project's shader
|
|
227151
|
+
compiles, the IDE types (.lecodes/types/ + tsconfig.json,
|
|
227152
|
+
from the server — the former 'lecodes types'), the
|
|
227153
|
+
ios/android shell pins ('app update'), then the GLOBAL npm
|
|
227154
|
+
installs: every installed optional peer (lecodes-renderer,
|
|
227155
|
+
lecodes-design, lecodes-3d-editor, lecodes-assets) and this
|
|
227156
|
+
CLI that is behind npm's latest gets 'npm install -g'.
|
|
227157
|
+
Pinned tools are skipped, not overridden: LECODES_DESKTOP_EXE
|
|
227158
|
+
/ LECODES_MATC mean a local build. Keeps going when a step
|
|
227159
|
+
fails; the summary says which.
|
|
227160
|
+
--local types from the SDK bundled in this CLI
|
|
227161
|
+
--no-shells leave ios/android pins alone (no re-sync)
|
|
227162
|
+
--check npm step: report what's behind, install nothing
|
|
227163
|
+
--no-cli skip the npm step (offline)
|
|
226653
227164
|
design [serve] LeCodes Design — a live canvas of screens for AI-driven prototyping
|
|
226654
227165
|
(needs the optional 'lecodes-design' package; works inside a
|
|
226655
227166
|
cloned project or standalone in any folder)
|
|
@@ -226706,6 +227217,8 @@ ${c.bold("Commands:")}
|
|
|
226706
227217
|
--probe headless-render the staged folder to PNG
|
|
226707
227218
|
(macOS: a brief windowed run + snapshot)
|
|
226708
227219
|
--zip also pack the result for sending
|
|
227220
|
+
--dmg macOS: also build a drag-to-Applications
|
|
227221
|
+
disk image (signed + notarized too)
|
|
226709
227222
|
--sign <identity|adhoc> macOS codesign identity
|
|
226710
227223
|
--notarize <profile> / --no-notarize macOS
|
|
226711
227224
|
--zip <out>.zip, UTF-8/forward-slash entries
|
|
@@ -226743,6 +227256,13 @@ ${c.bold("Commands:")}
|
|
|
226743
227256
|
--port <n> editor-server port (default 4488)
|
|
226744
227257
|
--no-open don't open the browser
|
|
226745
227258
|
--no-mcp don't register the MCP server in .mcp.json
|
|
227259
|
+
thumbs [path…] Asset thumbnails for the scene editor, WITHOUT a browser: decodes
|
|
227260
|
+
the project's images (KTX2 too, via KTX-Software's ktx tool) into the
|
|
227261
|
+
editor's preview cache. Incremental — the cached name carries the
|
|
227262
|
+
asset's content hash, so unchanged files are skipped. Models,
|
|
227263
|
+
materials and prefabs are rendered by the editor, not here
|
|
227264
|
+
--force redo even the up-to-date ones
|
|
227265
|
+
--size <px> longest edge (default 256)
|
|
226746
227266
|
assets convert <model.fbx|.glb> [--clips a.fbx b.fbx …] [-o out.glb] [--drop-model-clips]
|
|
226747
227267
|
[--fix] [--ktx2|--ktx2-hq]
|
|
226748
227268
|
FBX → LeCodes-ready GLB: meters/Y-up, textures embedded, clips from
|
|
@@ -226841,35 +227361,10 @@ Config lives in ~/.lecodes/config.json (override with LECODES_API / LECODES_TOKE
|
|
|
226841
227361
|
A .env next to app.json is read at startup for LECODES_* / CREATOR_* keys (the shell's own
|
|
226842
227362
|
environment wins; ./ paths resolve against the project; the file is never pushed) — e.g.
|
|
226843
227363
|
LECODES_DESKTOP_EXE, LECODES_MATC, LECODES_NOTARY_PROFILE, LECODES_MACOS_SIGN_ID, LECODES_TOKEN.`;
|
|
226844
|
-
var commands = { init: init2, login, create, clone: clone3, link, status: status3, diff: diff2, pull, push, compile: compile2, preview: previewLegacy, render, test,
|
|
226845
|
-
if (
|
|
227364
|
+
var commands = { init: init2, login, create, clone: clone3, link, status: status3, diff: diff2, pull, push, compile: compile2, preview: previewLegacy, render, test, design, scene, thumbs, dev, app, pn, desktop, shaders, assets, lightmap, navmesh, update };
|
|
227365
|
+
if (STANDALONE2)
|
|
226846
227366
|
commands.install = install;
|
|
226847
227367
|
var readVersion = () => package_default.version ?? "unknown";
|
|
226848
|
-
var OPTIONAL_PEERS = [
|
|
226849
|
-
["lecodes-renderer", "lecodes-renderer/headless"],
|
|
226850
|
-
["lecodes-design", "lecodes-design/server"],
|
|
226851
|
-
["lecodes-3d-editor", "lecodes-3d-editor/server"],
|
|
226852
|
-
["lecodes-assets", "lecodes-assets/cli"]
|
|
226853
|
-
];
|
|
226854
|
-
var peerVersion = (name, probe) => {
|
|
226855
|
-
try {
|
|
226856
|
-
const require2 = createRequire4(import.meta.url);
|
|
226857
|
-
let dir = dirname21(require2.resolve(probe));
|
|
226858
|
-
for (let depth = 0;depth < 16; depth++) {
|
|
226859
|
-
const manifest = join40(dir, "package.json");
|
|
226860
|
-
if (existsSync39(manifest)) {
|
|
226861
|
-
const parsed = JSON.parse(readFileSync35(manifest, "utf8"));
|
|
226862
|
-
if (parsed.name === name)
|
|
226863
|
-
return parsed.version ?? "unknown";
|
|
226864
|
-
}
|
|
226865
|
-
const parent = dirname21(dir);
|
|
226866
|
-
if (parent === dir)
|
|
226867
|
-
break;
|
|
226868
|
-
dir = parent;
|
|
226869
|
-
}
|
|
226870
|
-
} catch {}
|
|
226871
|
-
return null;
|
|
226872
|
-
};
|
|
226873
227368
|
var printVersion = () => {
|
|
226874
227369
|
const rows = [["lecodes-cli", readVersion()]];
|
|
226875
227370
|
for (const [name, probe] of OPTIONAL_PEERS) {
|