lecodes-cli 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +1069 -396
- package/package.json +14 -13
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/assets/Roboto-Variable-DHm9jpd-.woff2 +0 -0
- package/runtime/web/assets/__vite-browser-external-BIHI7g3E.js +1 -0
- package/runtime/web/assets/basis-C64VHDVD.js +1 -0
- package/runtime/web/assets/basis_transcoder-VXdx5NbI.wasm +0 -0
- package/runtime/web/assets/createViewerLite-BvHobVhp.js +852 -0
- package/runtime/web/assets/draco-BiISTFcR.js +118 -0
- package/runtime/web/assets/draco_decoder-DsQ12WqX.wasm +0 -0
- package/runtime/web/assets/index-CfNCCBjN.js +2 -0
- package/runtime/web/assets/mapViewImpl-B2JcES8l.js +810 -0
- package/runtime/web/assets/maplibre-gl-worker-CJfwIrte.js +8 -0
- package/runtime/web/assets/neutral_ibl128-D-lzdkLN.ktx +0 -0
- package/runtime/web/assets/worker-Caf-yYEI.js +2 -0
- package/runtime/web/embed.html +32 -0
- package/runtime/web/embed.js +171 -0
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +896 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +339 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +542 -0
- package/src/commands/appTemplates.ts +907 -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 +127 -0
- package/src/commands/dev.ts +236 -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 +130 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +416 -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 +371 -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 +545 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +333 -0
- package/src/dev/webRunner.ts +22 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +494 -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
|
|
@@ -3177,7 +3177,7 @@ var require_source_map_support = __commonJS((exports, module) => {
|
|
|
3177
3177
|
|
|
3178
3178
|
// ../../node_modules/.bun/typescript@5.8.3/node_modules/typescript/lib/typescript.js
|
|
3179
3179
|
var require_typescript = __commonJS((exports, module) => {
|
|
3180
|
-
var __dirname = "
|
|
3180
|
+
var __dirname = "/Users/den/Desktop/Ingenuity/le-codes/node_modules/.bun/typescript@5.8.3/node_modules/typescript/lib", __filename = "/Users/den/Desktop/Ingenuity/le-codes/node_modules/.bun/typescript@5.8.3/node_modules/typescript/lib/typescript.js";
|
|
3181
3181
|
/*! *****************************************************************************
|
|
3182
3182
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3183
3183
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
@@ -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 {
|
|
@@ -172198,6 +172193,8 @@ var compileProject = async (opts) => {
|
|
|
172198
172193
|
}
|
|
172199
172194
|
} else if (e.path.toLowerCase().endsWith(".svg")) {
|
|
172200
172195
|
files[e.path] = `export default SvgSource(\`${e.text ?? ""}\`)`;
|
|
172196
|
+
} else if (e.path.toLowerCase().endsWith(".json")) {
|
|
172197
|
+
files[e.path] = `export default ${e.text?.trim() || "null"}`;
|
|
172201
172198
|
} else {
|
|
172202
172199
|
files[e.path] = e.text ?? "";
|
|
172203
172200
|
}
|
|
@@ -173137,7 +173134,6 @@ __export(exports_compile, {
|
|
|
173137
173134
|
parseSfnt: () => parseSfnt,
|
|
173138
173135
|
parseJsonish: () => parseJsonish,
|
|
173139
173136
|
offsetSourceMap: () => offsetSourceMap,
|
|
173140
|
-
matcPlatformsFor: () => matcPlatformsFor,
|
|
173141
173137
|
matcArgs: () => matcArgs,
|
|
173142
173138
|
loadSceneHarness: () => loadSceneHarness,
|
|
173143
173139
|
isServerPath: () => isServerPath,
|
|
@@ -173168,6 +173164,7 @@ __export(exports_compile, {
|
|
|
173168
173164
|
SCENE_HARNESS_DIR: () => SCENE_HARNESS_DIR,
|
|
173169
173165
|
SCENE_ENTRY_PATH: () => SCENE_ENTRY_PATH,
|
|
173170
173166
|
PLATFORM_BUILD: () => PLATFORM_BUILD,
|
|
173167
|
+
MATC_PLATFORMS: () => MATC_PLATFORMS,
|
|
173171
173168
|
LOCAL_PLATFORM_BUILD: () => LOCAL_PLATFORM_BUILD,
|
|
173172
173169
|
LOCAL_ONLY_PLATFORMS: () => LOCAL_ONLY_PLATFORMS,
|
|
173173
173170
|
ICON_ID: () => ICON_ID,
|
|
@@ -173198,7 +173195,13 @@ var init_compile = __esm(() => {
|
|
|
173198
173195
|
import { existsSync as existsSync7 } from "node:fs";
|
|
173199
173196
|
import { createRequire as createRequire3 } from "node:module";
|
|
173200
173197
|
import { dirname as dirname5, join as join9 } from "node:path";
|
|
173201
|
-
var
|
|
173198
|
+
var resolveSdkInject = () => {
|
|
173199
|
+
try {
|
|
173200
|
+
return createRequire3(import.meta.url).resolve("lecodes-sdk/inject");
|
|
173201
|
+
} catch {}
|
|
173202
|
+
const vendored = join9(distRoot, "runtime", "sdk", "inject.ts");
|
|
173203
|
+
return existsSync7(vendored) ? vendored : null;
|
|
173204
|
+
}, sdkInject, resolveChiselBin2 = () => {
|
|
173202
173205
|
if (process.env.LECODES_CHISEL_BIN)
|
|
173203
173206
|
return process.env.LECODES_CHISEL_BIN;
|
|
173204
173207
|
try {
|
|
@@ -173230,9 +173233,9 @@ var vendoredInject, resolveChiselBin2 = () => {
|
|
|
173230
173233
|
var init_projectCompile = __esm(() => {
|
|
173231
173234
|
init_distRoot();
|
|
173232
173235
|
init_compile();
|
|
173233
|
-
|
|
173234
|
-
if (
|
|
173235
|
-
process.env.LECODES_SDK_INJECT =
|
|
173236
|
+
sdkInject = resolveSdkInject();
|
|
173237
|
+
if (sdkInject)
|
|
173238
|
+
process.env.LECODES_SDK_INJECT = sdkInject;
|
|
173236
173239
|
chiselBin = resolveChiselBin2();
|
|
173237
173240
|
if (chiselBin)
|
|
173238
173241
|
process.env.LECODES_CHISEL_BIN = chiselBin;
|
|
@@ -214124,25 +214127,26 @@ var init_esm30 = __esm(() => {
|
|
|
214124
214127
|
|
|
214125
214128
|
// src/types.ts
|
|
214126
214129
|
import { dirname as dirname13, join as join22, relative as relative3, sep } from "node:path";
|
|
214127
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync15, readdirSync as
|
|
214130
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync15, readdirSync as readdirSync11, readFileSync as readFileSync18, rmSync as rmSync8, statSync as statSync9, writeFileSync as writeFileSync17 } from "node:fs";
|
|
214131
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
214128
214132
|
var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
214129
214133
|
if (!existsSync21(dir))
|
|
214130
214134
|
return [];
|
|
214131
214135
|
const out = [];
|
|
214132
|
-
for (const name of
|
|
214136
|
+
for (const name of readdirSync11(dir)) {
|
|
214133
214137
|
const path2 = join22(dir, name);
|
|
214134
|
-
if (
|
|
214138
|
+
if (statSync9(path2).isDirectory())
|
|
214135
214139
|
out.push(...listBundleFiles(path2, base));
|
|
214136
214140
|
else
|
|
214137
214141
|
out.push(relative3(base, path2).split(sep).join("/"));
|
|
214138
214142
|
}
|
|
214139
214143
|
return out;
|
|
214140
214144
|
}, pruneEmptyDirs = (dir, root) => {
|
|
214141
|
-
if (!existsSync21(dir) || !
|
|
214145
|
+
if (!existsSync21(dir) || !statSync9(dir).isDirectory())
|
|
214142
214146
|
return;
|
|
214143
|
-
for (const name of
|
|
214147
|
+
for (const name of readdirSync11(dir))
|
|
214144
214148
|
pruneEmptyDirs(join22(dir, name), root);
|
|
214145
|
-
if (dir !== root &&
|
|
214149
|
+
if (dir !== root && readdirSync11(dir).length === 0)
|
|
214146
214150
|
rmSync8(dir, { recursive: true });
|
|
214147
214151
|
}, writeTypeBundle = (root, bundle) => {
|
|
214148
214152
|
const typesDir = join22(root, LECODES_DIR, "types");
|
|
@@ -214174,8 +214178,16 @@ var TSCONFIG, listBundleFiles = (dir, base = dir) => {
|
|
|
214174
214178
|
bundle[path2] = readFileSync18(join22(typesDir, path2), "utf8");
|
|
214175
214179
|
return bundle;
|
|
214176
214180
|
}, materializeTypes = async (root, apiUrl) => writeTypeBundle(root, await getTypes(apiUrl)), readLocalTypeBundle = () => {
|
|
214181
|
+
const fromPackage = (() => {
|
|
214182
|
+
try {
|
|
214183
|
+
return createRequire4(import.meta.url).resolve("lecodes-sdk/types.json");
|
|
214184
|
+
} catch {
|
|
214185
|
+
return null;
|
|
214186
|
+
}
|
|
214187
|
+
})();
|
|
214177
214188
|
const candidates = [
|
|
214178
214189
|
join22(distRoot, "runtime", "sdk-types.json"),
|
|
214190
|
+
...fromPackage ? [fromPackage] : [],
|
|
214179
214191
|
join22(distRoot, "..", "sdk", "dist", "types.json")
|
|
214180
214192
|
];
|
|
214181
214193
|
for (const path2 of candidates) {
|
|
@@ -214220,13 +214232,13 @@ var init_types4 = __esm(() => {
|
|
|
214220
214232
|
|
|
214221
214233
|
// src/compile/designCompile.ts
|
|
214222
214234
|
import { readFileSync as readFileSync19 } from "node:fs";
|
|
214223
|
-
import { basename as
|
|
214235
|
+
import { basename as basename10 } from "node:path";
|
|
214224
214236
|
var LOCAL_ASSET_SCHEME = "lecodesfile://", compileDesignScreen = async (opts) => {
|
|
214225
214237
|
const { root, manifest, designDir, designKey, screenId, state } = opts;
|
|
214226
214238
|
const entries = [];
|
|
214227
214239
|
const scan2 = scanLocal(root, { ignore: loadIgnore(root), tracked: new Set(Object.keys(manifest?.files ?? {})) });
|
|
214228
214240
|
for (const file of scan2.files) {
|
|
214229
|
-
const type = manifest?.files[file.path]?.type ?? classifyKind(
|
|
214241
|
+
const type = manifest?.files[file.path]?.type ?? classifyKind(basename10(file.path));
|
|
214230
214242
|
if (type === "resource") {
|
|
214231
214243
|
entries.push({
|
|
214232
214244
|
path: file.path,
|
|
@@ -214358,7 +214370,7 @@ var init_browserAuth = __esm(() => {
|
|
|
214358
214370
|
init_util();
|
|
214359
214371
|
});
|
|
214360
214372
|
|
|
214361
|
-
//
|
|
214373
|
+
// ../../../lecodes-tools/packages/lecodes-design/src/core/concept.ts
|
|
214362
214374
|
var SPEC_TEMPLATE = `# Concept
|
|
214363
214375
|
|
|
214364
214376
|
The narrative half of this design. \`meta.json\` + the canvas hold the *visual/flow* half (screens,
|
|
@@ -214394,7 +214406,7 @@ Behaviour that isn't visible in a single screen — validation, permissions, not
|
|
|
214394
214406
|
cases — and the decisions you've made and why, so they aren't re-litigated later.
|
|
214395
214407
|
`;
|
|
214396
214408
|
|
|
214397
|
-
//
|
|
214409
|
+
// ../../../lecodes-tools/packages/lecodes-design/src/templates.ts
|
|
214398
214410
|
var SPEC_MD, META_JSON = `{
|
|
214399
214411
|
"screens": {
|
|
214400
214412
|
"home": { "pos": [0, 0], "desc": "Example screen — replace me", "role": "list" }
|
|
@@ -214862,8 +214874,8 @@ __export(exports_design, {
|
|
|
214862
214874
|
flushDesignComments: () => flushDesignComments,
|
|
214863
214875
|
design: () => design
|
|
214864
214876
|
});
|
|
214865
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync18, readFileSync as readFileSync21, readdirSync as
|
|
214866
|
-
import { basename as
|
|
214877
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync18, readFileSync as readFileSync21, readdirSync as readdirSync14, writeFileSync as writeFileSync19, appendFileSync } from "node:fs";
|
|
214878
|
+
import { basename as basename11, join as join25 } from "node:path";
|
|
214867
214879
|
var DEFAULT_DIR = "design", DEFAULT_PORT = 4477, getContext = (args) => {
|
|
214868
214880
|
let root;
|
|
214869
214881
|
let manifest;
|
|
@@ -214878,7 +214890,7 @@ var DEFAULT_DIR = "design", DEFAULT_PORT = 4477, getContext = (args) => {
|
|
|
214878
214890
|
return {
|
|
214879
214891
|
root,
|
|
214880
214892
|
manifest,
|
|
214881
|
-
name: manifest?.name ??
|
|
214893
|
+
name: manifest?.name ?? basename11(root),
|
|
214882
214894
|
dirName,
|
|
214883
214895
|
designDir: join25(root, dirName),
|
|
214884
214896
|
designKey: "/" + dirName.replace(/\\/g, "/")
|
|
@@ -214919,7 +214931,7 @@ var DEFAULT_DIR = "design", DEFAULT_PORT = 4477, getContext = (args) => {
|
|
|
214919
214931
|
const dir = join25(designDir, "screens");
|
|
214920
214932
|
if (!existsSync24(dir))
|
|
214921
214933
|
return [];
|
|
214922
|
-
return
|
|
214934
|
+
return readdirSync14(dir).filter((f3) => f3.endsWith(".ts") && !f3.startsWith(".")).map((f3) => f3.slice(0, -3)).sort();
|
|
214923
214935
|
}, writeMcpConfig = (ctx, port) => {
|
|
214924
214936
|
const path2 = join25(ctx.root, ".mcp.json");
|
|
214925
214937
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
@@ -216529,26 +216541,26 @@ var require_main = __commonJS((exports, module) => {
|
|
|
216529
216541
|
// package.json
|
|
216530
216542
|
var package_default = {
|
|
216531
216543
|
name: "lecodes-cli",
|
|
216532
|
-
version: "0.
|
|
216544
|
+
version: "0.20.0",
|
|
216533
216545
|
dependencies: {
|
|
216534
216546
|
"@letary/chisel": "^0.10.0",
|
|
216535
|
-
jimp: "^1.6.1"
|
|
216547
|
+
jimp: "^1.6.1",
|
|
216548
|
+
"lecodes-sdk": "workspace:*"
|
|
216536
216549
|
},
|
|
216537
216550
|
devDependencies: {
|
|
216538
|
-
"lecodes-design": "
|
|
216551
|
+
"lecodes-design": "link:lecodes-design",
|
|
216539
216552
|
"lecodes-renderer": "workspace:*",
|
|
216540
216553
|
"qrcode-terminal": "^0.12.0",
|
|
216541
|
-
"lecodes-3d-editor": "
|
|
216554
|
+
"lecodes-3d-editor": "link:lecodes-3d-editor",
|
|
216542
216555
|
"lecodes-assets": "workspace:*",
|
|
216543
|
-
"creator-nav": "workspace:*",
|
|
216544
|
-
|
|
216545
|
-
"viewer-lite": "workspace:*"
|
|
216556
|
+
"lecodes-creator-nav": "workspace:*",
|
|
216557
|
+
"lecodes-viewer-lite": "workspace:*"
|
|
216546
216558
|
},
|
|
216547
216559
|
peerDependencies: {
|
|
216548
|
-
"lecodes-design": "^0.
|
|
216549
|
-
"lecodes-renderer": "^0.
|
|
216550
|
-
"lecodes-3d-editor": "^0.
|
|
216551
|
-
"lecodes-assets": "^0.1
|
|
216560
|
+
"lecodes-design": "^0.9.0",
|
|
216561
|
+
"lecodes-renderer": "^0.20.0",
|
|
216562
|
+
"lecodes-3d-editor": "^0.7.0",
|
|
216563
|
+
"lecodes-assets": "^0.2.1"
|
|
216552
216564
|
},
|
|
216553
216565
|
bin: {
|
|
216554
216566
|
lecodes: "dist/index.js"
|
|
@@ -216559,6 +216571,7 @@ var package_default = {
|
|
|
216559
216571
|
},
|
|
216560
216572
|
files: [
|
|
216561
216573
|
"dist",
|
|
216574
|
+
"src",
|
|
216562
216575
|
"runtime",
|
|
216563
216576
|
"README.md"
|
|
216564
216577
|
],
|
|
@@ -216598,7 +216611,7 @@ var package_default = {
|
|
|
216598
216611
|
init_manifest();
|
|
216599
216612
|
init_config();
|
|
216600
216613
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
216601
|
-
import { cpSync as cpSync4, existsSync as existsSync20, mkdirSync as mkdirSync14, readFileSync as readFileSync17, readdirSync as
|
|
216614
|
+
import { cpSync as cpSync4, existsSync as existsSync20, mkdirSync as mkdirSync14, readFileSync as readFileSync17, readdirSync as readdirSync10, rmSync as rmSync7, statSync as statSync8, writeFileSync as writeFileSync16 } from "node:fs";
|
|
216602
216615
|
import { homedir as homedir7 } from "node:os";
|
|
216603
216616
|
import { basename as basename8, dirname as dirname12, join as join21, resolve as resolve8 } from "node:path";
|
|
216604
216617
|
|
|
@@ -216725,7 +216738,7 @@ init_fonts();
|
|
|
216725
216738
|
init_compile();
|
|
216726
216739
|
import { execFile } from "node:child_process";
|
|
216727
216740
|
import { createHash as createHash4, randomBytes } from "node:crypto";
|
|
216728
|
-
import {
|
|
216741
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync11, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
216729
216742
|
import { tmpdir } from "node:os";
|
|
216730
216743
|
import { basename as basename3, join as join13 } from "node:path";
|
|
216731
216744
|
|
|
@@ -216918,17 +216931,14 @@ var matcIdentity = (exe) => {
|
|
|
216918
216931
|
return `${stat.size}:${Math.trunc(stat.mtimeMs)}`;
|
|
216919
216932
|
};
|
|
216920
216933
|
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
|
-
};
|
|
216934
|
+
var artifactFamily = () => [...MATC_PLATFORMS, ...LOCAL_ONLY_PLATFORMS, "webgl-lite"];
|
|
216925
216935
|
var shaderIsCompiled = (root, text, matcId) => {
|
|
216926
216936
|
const hash = shaderHash(text, matcId);
|
|
216927
|
-
return artifactFamily(
|
|
216937
|
+
return artifactFamily().every((p) => existsSync11(join13(shadersCacheDir(root), `${hash}_${p}.filamat`)));
|
|
216928
216938
|
};
|
|
216929
216939
|
var shaderCompiledPlatforms = (root, text, matcId) => {
|
|
216930
216940
|
const hash = shaderHash(text, matcId);
|
|
216931
|
-
return artifactFamily(
|
|
216941
|
+
return artifactFamily().filter((p) => existsSync11(join13(shadersCacheDir(root), `${hash}_${p}.filamat`)));
|
|
216932
216942
|
};
|
|
216933
216943
|
var localShaderArtifact = (root, text, platform) => {
|
|
216934
216944
|
const matcExe = resolveMatcExeCached();
|
|
@@ -216973,15 +216983,12 @@ var applyLocalShaders = async (entries, opts) => {
|
|
|
216973
216983
|
for (const entry of shaderEntries) {
|
|
216974
216984
|
const text = readFileSync11(entry.absPath, "utf8");
|
|
216975
216985
|
const hash = shaderHash(text, matcId);
|
|
216976
|
-
const family = artifactFamily(
|
|
216986
|
+
const family = artifactFamily();
|
|
216977
216987
|
const artifact = (platform) => `${hash}_${platform}.filamat`;
|
|
216978
216988
|
const has = (platform) => existsSync11(join13(cacheDir, artifact(platform)));
|
|
216979
216989
|
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
216990
|
const missing = wanted.filter((p) => !has(p));
|
|
216984
|
-
const matcMissing = missing.filter((p) => p !== "webgl-lite"
|
|
216991
|
+
const matcMissing = missing.filter((p) => p !== "webgl-lite");
|
|
216985
216992
|
if (matcMissing.length > 0) {
|
|
216986
216993
|
const tempName = `lecodes-matc-${randomBytes(6).toString("hex")}.mat`;
|
|
216987
216994
|
const tempFile = join13(tmpdir(), tempName);
|
|
@@ -217001,9 +217008,6 @@ ${cleanMatcOutput(stderr, tempName, basename3(entry.path))}`);
|
|
|
217001
217008
|
rmSync2(tempFile, { force: true });
|
|
217002
217009
|
}
|
|
217003
217010
|
}
|
|
217004
|
-
if (missing.includes("webgl") && !matcPlatformsFor(text).includes("webgl")) {
|
|
217005
|
-
copyFileSync(join13(cacheDir, artifact("opengl")), join13(cacheDir, artifact("webgl")));
|
|
217006
|
-
}
|
|
217007
217011
|
if (missing.includes("webgl-lite")) {
|
|
217008
217012
|
writeFileSync7(join13(cacheDir, artifact("webgl-lite")), JSON.stringify(buildLiteMaterialArtifact(text)));
|
|
217009
217013
|
}
|
|
@@ -217018,7 +217022,7 @@ ${cleanMatcOutput(stderr, tempName, basename3(entry.path))}`);
|
|
|
217018
217022
|
artifacts.push({ name: artifact(platform), absPath: join13(cacheDir, artifact(platform)) });
|
|
217019
217023
|
}
|
|
217020
217024
|
} else {
|
|
217021
|
-
const order = ["opengl", "metal", "desktop", "webgl
|
|
217025
|
+
const order = ["opengl", "metal", "desktop", "webgl-lite"];
|
|
217022
217026
|
entry.shaders = order.map((platform) => ({ platform, src: `${opts.srcPrefix}/${artifact(platform)}` }));
|
|
217023
217027
|
}
|
|
217024
217028
|
}
|
|
@@ -217034,12 +217038,13 @@ init_manifest();
|
|
|
217034
217038
|
init_ignore();
|
|
217035
217039
|
init_util();
|
|
217036
217040
|
import { execFileSync } from "node:child_process";
|
|
217037
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
|
|
217041
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync5, readFileSync as readFileSync13, statSync as statSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
217038
217042
|
import { homedir as homedir4 } from "node:os";
|
|
217039
217043
|
import { dirname as dirname8, join as join15, resolve as resolve2 } from "node:path";
|
|
217040
217044
|
var FIRST_PARTY_PLUGINS = {
|
|
217041
217045
|
camera: "letary/lecodes-plugins",
|
|
217042
217046
|
"qr-scanner": "letary/lecodes-plugins",
|
|
217047
|
+
map: "letary/lecodes-plugins",
|
|
217043
217048
|
geolocation: "letary/lecodes-plugins",
|
|
217044
217049
|
push: "letary/lecodes-plugins"
|
|
217045
217050
|
};
|
|
@@ -217070,6 +217075,7 @@ var desktopDefaultViewport = (root) => {
|
|
|
217070
217075
|
height: cfg.desktop.window?.height ?? DESKTOP_DEFAULT_WINDOW.height
|
|
217071
217076
|
};
|
|
217072
217077
|
};
|
|
217078
|
+
var swiftPackageName = (url) => (url.replace(/\/+$/, "").split("/").pop() ?? url).replace(/\.git$/, "");
|
|
217073
217079
|
var readJson = (path) => {
|
|
217074
217080
|
if (!existsSync13(path))
|
|
217075
217081
|
return null;
|
|
@@ -217223,7 +217229,8 @@ var ensureRepo = (repo, wantTag, lock) => {
|
|
|
217223
217229
|
git(cache, "checkout", "--quiet", "--detach", commit);
|
|
217224
217230
|
return { dir: cache, tag: tag ?? "unknown", commit };
|
|
217225
217231
|
};
|
|
217226
|
-
var
|
|
217232
|
+
var PLUGIN_PLATFORM_LABEL = { ios: "iOS", android: "Android", desktop: "desktop" };
|
|
217233
|
+
function resolvePlugin(id, spec, lock, platform, opts) {
|
|
217227
217234
|
let repo;
|
|
217228
217235
|
let subdir;
|
|
217229
217236
|
let wantTag = null;
|
|
@@ -217247,7 +217254,9 @@ var resolvePlugin = (id, spec, lock, platform) => {
|
|
|
217247
217254
|
if (manifest.id !== id)
|
|
217248
217255
|
throw new CliError(`Plugin "${id}": manifest declares id "${manifest.id}"`);
|
|
217249
217256
|
if (!manifest[platform]) {
|
|
217250
|
-
|
|
217257
|
+
if (opts?.optional)
|
|
217258
|
+
return null;
|
|
217259
|
+
throw new CliError(`Plugin "${id}" does not support ${PLUGIN_PLATFORM_LABEL[platform]} (manifest "${platform}" is null)`);
|
|
217251
217260
|
}
|
|
217252
217261
|
if (spec.startsWith("github:")) {
|
|
217253
217262
|
const names = [...manifest.provides?.views ?? [], ...manifest.provides?.services ?? []];
|
|
@@ -217262,7 +217271,7 @@ var resolvePlugin = (id, spec, lock, platform) => {
|
|
|
217262
217271
|
manifest,
|
|
217263
217272
|
lock: { repo, tag: checkout.tag, commit: checkout.commit, version: manifest.version ?? "unknown" }
|
|
217264
217273
|
};
|
|
217265
|
-
}
|
|
217274
|
+
}
|
|
217266
217275
|
var latestPluginTag = (repo) => {
|
|
217267
217276
|
try {
|
|
217268
217277
|
return ensureRepo(repo, null, undefined).tag;
|
|
@@ -217270,6 +217279,55 @@ var latestPluginTag = (repo) => {
|
|
|
217270
217279
|
return null;
|
|
217271
217280
|
}
|
|
217272
217281
|
};
|
|
217282
|
+
var desktopPluginTarget = () => `${process.platform}-${process.arch}`;
|
|
217283
|
+
var isDesktopPluginLibrary = (name) => {
|
|
217284
|
+
const n = name.toLowerCase();
|
|
217285
|
+
return process.platform === "win32" ? n.endsWith(".dll") : n.endsWith(".so");
|
|
217286
|
+
};
|
|
217287
|
+
var desktopPluginLibraries = (root, opts = {}) => {
|
|
217288
|
+
const dirs = [];
|
|
217289
|
+
const files = [];
|
|
217290
|
+
const local = join15(root, "plugins");
|
|
217291
|
+
if (existsSync13(local) && statSync3(local).isDirectory()) {
|
|
217292
|
+
dirs.push(local);
|
|
217293
|
+
for (const f2 of readdirSync5(local))
|
|
217294
|
+
if (isDesktopPluginLibrary(f2))
|
|
217295
|
+
files.push(join15(local, f2));
|
|
217296
|
+
}
|
|
217297
|
+
const config = readJson(join15(root, "app.json"));
|
|
217298
|
+
const specs = Object.entries(config?.plugins ?? {});
|
|
217299
|
+
if (specs.length === 0)
|
|
217300
|
+
return { dirs, files };
|
|
217301
|
+
const lock = readJson(join15(root, "plugins.lock.json"))?.plugins ?? {};
|
|
217302
|
+
const target = desktopPluginTarget();
|
|
217303
|
+
for (const [id, spec] of specs) {
|
|
217304
|
+
let plugin;
|
|
217305
|
+
try {
|
|
217306
|
+
plugin = resolvePlugin(id, spec, lock[id], "desktop", { optional: true });
|
|
217307
|
+
} catch (e) {
|
|
217308
|
+
if (opts.strict)
|
|
217309
|
+
throw e;
|
|
217310
|
+
warn(`Plugin "${id}": ${e.message} — skipped for this desktop run`);
|
|
217311
|
+
continue;
|
|
217312
|
+
}
|
|
217313
|
+
const rel = plugin?.manifest.desktop?.library?.[target];
|
|
217314
|
+
if (!plugin || !rel)
|
|
217315
|
+
continue;
|
|
217316
|
+
const abs = resolve2(plugin.dir, rel);
|
|
217317
|
+
if (!existsSync13(abs)) {
|
|
217318
|
+
const msg = `Plugin "${id}": desktop library ${abs} is missing (manifest desktop.library["${target}"])`;
|
|
217319
|
+
if (opts.strict)
|
|
217320
|
+
throw new CliError(msg);
|
|
217321
|
+
warn(`${msg} — skipped for this desktop run`);
|
|
217322
|
+
continue;
|
|
217323
|
+
}
|
|
217324
|
+
files.push(abs);
|
|
217325
|
+
const dir = dirname8(abs);
|
|
217326
|
+
if (!dirs.includes(dir))
|
|
217327
|
+
dirs.push(dir);
|
|
217328
|
+
}
|
|
217329
|
+
return { dirs, files };
|
|
217330
|
+
};
|
|
217273
217331
|
|
|
217274
217332
|
// src/commands/compile.ts
|
|
217275
217333
|
init_util();
|
|
@@ -218074,13 +218132,31 @@ var APP_ICON_JSON = `{
|
|
|
218074
218132
|
`;
|
|
218075
218133
|
var runtimePackageTemplate = (sdkVersion, variant, plugins) => {
|
|
218076
218134
|
const product = `LeCodesSDK-${variant}`;
|
|
218077
|
-
const
|
|
218135
|
+
const packages = new Map;
|
|
218136
|
+
for (const p of plugins) {
|
|
218137
|
+
for (const pkg of p.packages ?? []) {
|
|
218138
|
+
const prior = packages.get(pkg.url);
|
|
218139
|
+
if (prior && (prior.exact !== pkg.exact || prior.from !== pkg.from)) {
|
|
218140
|
+
throw new Error(`Plugin "${p.id}" pins ${pkg.url} at ${pkg.exact ?? `from ${pkg.from}`} but another plugin pins ${prior.exact ?? `from ${prior.from}`} — the shell can link one version.`);
|
|
218141
|
+
}
|
|
218142
|
+
packages.set(pkg.url, pkg);
|
|
218143
|
+
}
|
|
218144
|
+
}
|
|
218145
|
+
const packageDecls = [...packages.values()].map((pkg) => `
|
|
218146
|
+
.package(url: "${pkg.url}", ${pkg.exact ? `exact: "${pkg.exact}"` : `from: "${pkg.from}"`}),`).join("");
|
|
218147
|
+
const pluginTargets = plugins.map((p) => {
|
|
218148
|
+
const deps = [
|
|
218149
|
+
`.product(name: "${product}", package: "lecodes-ios-sdk")`,
|
|
218150
|
+
...(p.packages ?? []).flatMap((pkg) => pkg.products.map((name) => `.product(name: "${name}", package: "${swiftPackageName(pkg.url)}")`))
|
|
218151
|
+
];
|
|
218152
|
+
return `
|
|
218078
218153
|
// plugin: ${p.id} (vendored — see plugins.lock.json)
|
|
218079
218154
|
.target(
|
|
218080
218155
|
name: "${p.module}",
|
|
218081
|
-
dependencies: [.
|
|
218156
|
+
dependencies: [${deps.join(", ")}],
|
|
218082
218157
|
path: "Sources/${p.module}"
|
|
218083
|
-
)
|
|
218158
|
+
),`;
|
|
218159
|
+
}).join("");
|
|
218084
218160
|
const runtimeDeps = [`.product(name: "${product}", package: "lecodes-ios-sdk")`, ...plugins.map((p) => `"${p.module}"`)];
|
|
218085
218161
|
return `// swift-tools-version:5.9
|
|
218086
218162
|
//
|
|
@@ -218099,7 +218175,7 @@ let package = Package(
|
|
|
218099
218175
|
.library(name: "LeCodesRuntime", targets: ["LeCodesRuntime"]),
|
|
218100
218176
|
],
|
|
218101
218177
|
dependencies: [
|
|
218102
|
-
.package(url: "https://github.com/letary/lecodes-ios-sdk.git", exact: "${sdkVersion}")
|
|
218178
|
+
.package(url: "https://github.com/letary/lecodes-ios-sdk.git", exact: "${sdkVersion}"),${packageDecls}
|
|
218103
218179
|
],
|
|
218104
218180
|
targets: [
|
|
218105
218181
|
.target(
|
|
@@ -218245,7 +218321,7 @@ buildNumber) — edit it there, then re-run \`lecodes app sync\`. Plugins are ma
|
|
|
218245
218321
|
init_manifest();
|
|
218246
218322
|
import { execFileSync as execFileSync2, spawn, spawnSync as spawnSync3 } from "node:child_process";
|
|
218247
218323
|
import { createHash as createHash6 } from "node:crypto";
|
|
218248
|
-
import { chmodSync, cpSync, existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync15, readdirSync as
|
|
218324
|
+
import { chmodSync, cpSync, existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync15, readdirSync as readdirSync6, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync4, writeFileSync as writeFileSync12 } from "node:fs";
|
|
218249
218325
|
import { homedir as homedir5 } from "node:os";
|
|
218250
218326
|
import { basename as basename5, dirname as dirname10, join as join17 } from "node:path";
|
|
218251
218327
|
init_util();
|
|
@@ -218630,6 +218706,12 @@ Sync links the smallest SDK artifact covering the engines the compiled bundle ac
|
|
|
218630
218706
|
engine, sync switches automatically on the next run; set \`android.variant\` in \`../app.json\`
|
|
218631
218707
|
to force one (needs lecodes-android-sdk >= 1.3.0; older releases ship only the full AAR).
|
|
218632
218708
|
|
|
218709
|
+
Physics, navigation meshes and multiplayer ship in \`lecodes-sdk\` (full) ONLY —
|
|
218710
|
+
\`lecodes-sdk-3d\` is 3D rendering without the game stack. Auto-selection reads which RENDERING
|
|
218711
|
+
engines the bundle uses and cannot see those, so a project using \`Physics\`,
|
|
218712
|
+
\`CharacterController\`, \`NavMesh\` or networking must set \`android.variant: "full"\` in
|
|
218713
|
+
\`../app.json\` — otherwise those aspects silently do nothing on device.
|
|
218714
|
+
|
|
218633
218715
|
## App-local native code
|
|
218634
218716
|
|
|
218635
218717
|
Drop Kotlin files into \`app/src/main/java/\` and register them in \`MainActivity\` after the
|
|
@@ -219486,7 +219568,7 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
219486
219568
|
}
|
|
219487
219569
|
const namespace = register.split(".").slice(0, -1).join(".");
|
|
219488
219570
|
const libsDir = join17(dest, "libs");
|
|
219489
|
-
const aarNames = existsSync16(libsDir) ?
|
|
219571
|
+
const aarNames = existsSync16(libsDir) ? readdirSync6(libsDir).filter((f3) => f3.endsWith(".aar")) : [];
|
|
219490
219572
|
for (const aar of aarNames) {
|
|
219491
219573
|
const base = aar.replace(/\.aar$/, "");
|
|
219492
219574
|
const wrapDir = join17(libsDir, base);
|
|
@@ -219502,8 +219584,8 @@ var syncAndroid = async (root, config, prior) => {
|
|
|
219502
219584
|
log(`${c.green("plugin")} ${id}@${plugin.lock.version} (${plugin.lock.tag} → plugins/${module})`);
|
|
219503
219585
|
}
|
|
219504
219586
|
const keep = new Set(runtimePlugins.map((p2) => p2.module));
|
|
219505
|
-
for (const entry of existsSync16(pluginsDir) ?
|
|
219506
|
-
if (!keep.has(entry) &&
|
|
219587
|
+
for (const entry of existsSync16(pluginsDir) ? readdirSync6(pluginsDir) : []) {
|
|
219588
|
+
if (!keep.has(entry) && statSync4(join17(pluginsDir, entry)).isDirectory()) {
|
|
219507
219589
|
rmrf(join17(pluginsDir, entry));
|
|
219508
219590
|
log(`${c.yellow("removed")} android/plugins/${entry} (plugin uninstalled)`);
|
|
219509
219591
|
}
|
|
@@ -219668,7 +219750,7 @@ var buildAndroid = async (args) => {
|
|
|
219668
219750
|
for (const dir of [apkDir, aabDir]) {
|
|
219669
219751
|
if (!existsSync16(dir))
|
|
219670
219752
|
continue;
|
|
219671
|
-
for (const f3 of
|
|
219753
|
+
for (const f3 of readdirSync6(dir)) {
|
|
219672
219754
|
if (f3.endsWith(".apk") || f3.endsWith(".aab"))
|
|
219673
219755
|
outputs.push(join17(dir, f3));
|
|
219674
219756
|
}
|
|
@@ -219725,7 +219807,7 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
219725
219807
|
const validVariant = requestedVariant === "auto" || SDK_VARIANTS.includes(requestedVariant);
|
|
219726
219808
|
check(validVariant, `android.variant "${requestedVariant}"`, `use "auto" or one of ${SDK_VARIANTS.join(", ")}`);
|
|
219727
219809
|
const wrapperJar = join17(androidDir, "gradle", "wrapper", "gradle-wrapper.jar");
|
|
219728
|
-
check(existsSync16(wrapperJar) &&
|
|
219810
|
+
check(existsSync16(wrapperJar) && statSync4(wrapperJar).size > 0, "Gradle wrapper jar", `run \`gradle wrapper --gradle-version ${GRADLE_VERSION}\` in android/ (or let Android Studio repair it)`);
|
|
219729
219811
|
check(existsSync16(join17(androidDir, "app", "src", "main", "assets", "app.js")), "Bundled app.js", "run `lecodes app sync`");
|
|
219730
219812
|
const linked = shellSdkVersionAndroid(androidDir);
|
|
219731
219813
|
const pin = config.android?.sdk ?? "latest";
|
|
@@ -219748,14 +219830,14 @@ var doctorAndroidChecks = async (root, config, check) => {
|
|
|
219748
219830
|
|
|
219749
219831
|
// src/commands/appDesktop.ts
|
|
219750
219832
|
import { execFileSync as execFileSync5, spawn as spawn4 } from "node:child_process";
|
|
219751
|
-
import { cpSync as cpSync3, existsSync as existsSync19, mkdirSync as mkdirSync13, readdirSync as
|
|
219833
|
+
import { cpSync as cpSync3, existsSync as existsSync19, mkdirSync as mkdirSync13, readdirSync as readdirSync9, rmSync as rmSync6, statSync as statSync7, writeFileSync as writeFileSync15 } from "node:fs";
|
|
219752
219834
|
import { basename as basename7, dirname as dirname11, join as join20, resolve as resolve7 } from "node:path";
|
|
219753
219835
|
|
|
219754
219836
|
// src/desktopRenderer.ts
|
|
219755
219837
|
import { execFileSync as execFileSync3, spawn as spawn2, spawnSync as spawnSync4 } from "node:child_process";
|
|
219756
|
-
import { copyFileSync
|
|
219838
|
+
import { copyFileSync, existsSync as existsSync17, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync2, readdirSync as readdirSync7, readFileSync as readFileSync16, rmSync as rmSync4, statSync as statSync5, writeFileSync as writeFileSync13 } from "node:fs";
|
|
219757
219839
|
import { homedir as homedir6, tmpdir as tmpdir2 } from "node:os";
|
|
219758
|
-
import { join as join18, resolve as resolve5 } from "node:path";
|
|
219840
|
+
import { delimiter, join as join18, resolve as resolve5 } from "node:path";
|
|
219759
219841
|
init_util();
|
|
219760
219842
|
|
|
219761
219843
|
// ../viewer-lite/src/sourcemapError.ts
|
|
@@ -219875,7 +219957,7 @@ var isMac = () => process.platform === "darwin";
|
|
|
219875
219957
|
var exeName = () => process.platform === "win32" ? "lecodes-desktop.exe" : isMac() ? "lecodes-app" : "lecodes-desktop";
|
|
219876
219958
|
var findExe = (dir) => {
|
|
219877
219959
|
const name = exeName();
|
|
219878
|
-
for (const entry of
|
|
219960
|
+
for (const entry of readdirSync7(dir, { withFileTypes: true })) {
|
|
219879
219961
|
const p2 = join18(dir, entry.name);
|
|
219880
219962
|
if (entry.isFile() && entry.name === name)
|
|
219881
219963
|
return p2;
|
|
@@ -219891,7 +219973,7 @@ var cacheRoot2 = () => join18(homedir6(), ".lecodes", "renderer");
|
|
|
219891
219973
|
var currentFile = () => join18(cacheRoot2(), "current.json");
|
|
219892
219974
|
var installedDesktopVersions = () => {
|
|
219893
219975
|
try {
|
|
219894
|
-
return
|
|
219976
|
+
return readdirSync7(cacheRoot2(), { withFileTypes: true }).filter((e2) => e2.isDirectory() && e2.name.startsWith("desktop-")).map((e2) => e2.name.slice("desktop-".length)).filter((v) => findExe(join18(cacheRoot2(), `desktop-${v}`)) !== null).sort(semverNewer);
|
|
219895
219977
|
} catch {
|
|
219896
219978
|
return [];
|
|
219897
219979
|
}
|
|
@@ -219916,7 +219998,7 @@ var extractDmg = (archive, stage) => {
|
|
|
219916
219998
|
mkdirSync11(mount, { recursive: true });
|
|
219917
219999
|
execFileSync3("hdiutil", ["attach", "-nobrowse", "-readonly", "-quiet", "-mountpoint", mount, archive]);
|
|
219918
220000
|
try {
|
|
219919
|
-
const app =
|
|
220001
|
+
const app = readdirSync7(mount).find((n2) => n2.endsWith(".app"));
|
|
219920
220002
|
if (!app)
|
|
219921
220003
|
throw new CliError("The downloaded DMG holds no .app bundle.");
|
|
219922
220004
|
execFileSync3("cp", ["-R", join18(mount, app), join18(stage, app)]);
|
|
@@ -220037,8 +220119,12 @@ var updateDesktop = async () => {
|
|
|
220037
220119
|
else
|
|
220038
220120
|
note(`Desktop renderer set to ${latest} (was ${before}).`);
|
|
220039
220121
|
};
|
|
220122
|
+
var pluginEnv = (dirs) => {
|
|
220123
|
+
const all = [...dirs ?? [], ...process.env.CREATOR_PLUGIN_DIRS ? [process.env.CREATOR_PLUGIN_DIRS] : []];
|
|
220124
|
+
return all.length > 0 ? { CREATOR_PLUGIN_DIRS: all.join(delimiter) } : {};
|
|
220125
|
+
};
|
|
220040
220126
|
var windowEnv = (opts) => {
|
|
220041
|
-
const env = {};
|
|
220127
|
+
const env = { ...pluginEnv(opts.pluginDirs) };
|
|
220042
220128
|
const width = opts.width ?? (opts.height !== undefined ? 1280 : undefined);
|
|
220043
220129
|
const height = opts.height ?? (opts.width !== undefined ? 720 : undefined);
|
|
220044
220130
|
if (width && height)
|
|
@@ -220082,8 +220168,8 @@ var stageBundle = (js, resources) => {
|
|
|
220082
220168
|
const runDir = mkdtempSync2(join18(tmpdir2(), "lecodes-render-"));
|
|
220083
220169
|
writeFileSync13(join18(runDir, "app.js"), js);
|
|
220084
220170
|
for (const r2 of resources) {
|
|
220085
|
-
if (r2.absPath && existsSync17(r2.absPath) &&
|
|
220086
|
-
|
|
220171
|
+
if (r2.absPath && existsSync17(r2.absPath) && statSync5(r2.absPath).isFile()) {
|
|
220172
|
+
copyFileSync(r2.absPath, join18(runDir, r2.name));
|
|
220087
220173
|
}
|
|
220088
220174
|
}
|
|
220089
220175
|
return runDir;
|
|
@@ -220126,7 +220212,16 @@ var runDesktopApp = async (js, resources, opts = {}) => {
|
|
|
220126
220212
|
});
|
|
220127
220213
|
});
|
|
220128
220214
|
} finally {
|
|
220129
|
-
|
|
220215
|
+
for (let attempt = 0;; attempt++) {
|
|
220216
|
+
try {
|
|
220217
|
+
rmSync4(runDir, { recursive: true, force: true });
|
|
220218
|
+
break;
|
|
220219
|
+
} catch {
|
|
220220
|
+
if (attempt >= 5)
|
|
220221
|
+
break;
|
|
220222
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 200);
|
|
220223
|
+
}
|
|
220224
|
+
}
|
|
220130
220225
|
}
|
|
220131
220226
|
};
|
|
220132
220227
|
var runDesktopDev = async (url, opts = {}) => {
|
|
@@ -220165,6 +220260,7 @@ var runDesktopRender = async (js, resources, opts) => {
|
|
|
220165
220260
|
env.CREATOR_CAMERA = opts.camera;
|
|
220166
220261
|
if (opts.view)
|
|
220167
220262
|
env.CREATOR_VIEW = opts.view;
|
|
220263
|
+
Object.assign(env, pluginEnv(opts.pluginDirs));
|
|
220168
220264
|
const demangle = makeStackDemangler(js) ?? ((text) => text);
|
|
220169
220265
|
return await new Promise((done, fail) => {
|
|
220170
220266
|
const child = spawn2(exe, [appJs], { cwd: runDir, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -220204,7 +220300,16 @@ ${tail}` : "";
|
|
|
220204
220300
|
});
|
|
220205
220301
|
});
|
|
220206
220302
|
} finally {
|
|
220207
|
-
|
|
220303
|
+
for (let attempt = 0;; attempt++) {
|
|
220304
|
+
try {
|
|
220305
|
+
rmSync4(runDir, { recursive: true, force: true });
|
|
220306
|
+
break;
|
|
220307
|
+
} catch {
|
|
220308
|
+
if (attempt >= 5)
|
|
220309
|
+
break;
|
|
220310
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 200);
|
|
220311
|
+
}
|
|
220312
|
+
}
|
|
220208
220313
|
}
|
|
220209
220314
|
};
|
|
220210
220315
|
|
|
@@ -220214,13 +220319,13 @@ init_util();
|
|
|
220214
220319
|
// src/commands/appDesktopMac.ts
|
|
220215
220320
|
init_util();
|
|
220216
220321
|
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
|
|
220322
|
+
import { cpSync as cpSync2, existsSync as existsSync18, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readdirSync as readdirSync8, rmSync as rmSync5, statSync as statSync6, symlinkSync, writeFileSync as writeFileSync14 } from "node:fs";
|
|
220218
220323
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
220219
220324
|
import { basename as basename6, join as join19, resolve as resolve6 } from "node:path";
|
|
220220
220325
|
var mb = (bytes) => `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
220221
|
-
var dirSize = (dir) =>
|
|
220326
|
+
var dirSize = (dir) => readdirSync8(dir, { withFileTypes: true }).reduce((sum, e2) => {
|
|
220222
220327
|
const p2 = join19(dir, e2.name);
|
|
220223
|
-
return sum + (e2.isDirectory() ? dirSize(p2) : e2.isSymbolicLink() ? 0 :
|
|
220328
|
+
return sum + (e2.isDirectory() ? dirSize(p2) : e2.isSymbolicLink() ? 0 : statSync6(p2).size);
|
|
220224
220329
|
}, 0);
|
|
220225
220330
|
var cleanBundleName = (name) => name.replace(/[/:]/g, "").trim() || "App";
|
|
220226
220331
|
var macHostAppOf = (exe) => {
|
|
@@ -220233,7 +220338,7 @@ var macHostAppOf = (exe) => {
|
|
|
220233
220338
|
var macHostProvidedNames = (exe) => {
|
|
220234
220339
|
const names3 = new Set;
|
|
220235
220340
|
const walk = (dir) => {
|
|
220236
|
-
for (const e2 of
|
|
220341
|
+
for (const e2 of readdirSync8(dir, { withFileTypes: true })) {
|
|
220237
220342
|
if (e2.isDirectory())
|
|
220238
220343
|
walk(join19(dir, e2.name));
|
|
220239
220344
|
else
|
|
@@ -220336,11 +220441,12 @@ var signApp = async (app, signing, hostApp, tmp) => {
|
|
|
220336
220441
|
throw new CliError(`The signature doesn't verify:
|
|
220337
220442
|
${(verify.stdout + verify.stderr).trim()}`);
|
|
220338
220443
|
};
|
|
220339
|
-
var
|
|
220340
|
-
const
|
|
220341
|
-
|
|
220342
|
-
|
|
220343
|
-
|
|
220444
|
+
var notarize = (target, profile, tmp, what) => {
|
|
220445
|
+
const submission = target.endsWith(".app") ? join19(tmp, `${basename6(target, ".app")}.zip`) : target;
|
|
220446
|
+
if (submission !== target)
|
|
220447
|
+
execFileSync4("ditto", ["-c", "-k", "--keepParent", target, submission]);
|
|
220448
|
+
note(`Notarizing the ${what} with profile "${profile}" — this waits on Apple (usually 1–5 minutes)…`);
|
|
220449
|
+
const r2 = spawnSync5("xcrun", ["notarytool", "submit", submission, "--keychain-profile", profile, "--wait"], { encoding: "utf8" });
|
|
220344
220450
|
const out = (r2.stdout + `
|
|
220345
220451
|
` + r2.stderr).trim();
|
|
220346
220452
|
const id = /id: ([0-9a-f-]{36})/.exec(out)?.[1];
|
|
@@ -220349,11 +220455,44 @@ var notarizeApp = (app, profile, tmp) => {
|
|
|
220349
220455
|
${out}
|
|
220350
220456
|
` + (id ? ` Details: xcrun notarytool log ${id} --keychain-profile ${profile}` : ""));
|
|
220351
220457
|
}
|
|
220352
|
-
const staple = spawnSync5("xcrun", ["stapler", "staple",
|
|
220458
|
+
const staple = spawnSync5("xcrun", ["stapler", "staple", target], { encoding: "utf8" });
|
|
220353
220459
|
if (staple.status !== 0)
|
|
220354
220460
|
throw new CliError(`Stapling failed:
|
|
220355
220461
|
${(staple.stdout + staple.stderr).trim()}`);
|
|
220356
|
-
success(
|
|
220462
|
+
success(`Notarized + stapled (${what}).`);
|
|
220463
|
+
};
|
|
220464
|
+
var buildDmg = async (app, out, appName, signing, tmp) => {
|
|
220465
|
+
const dmg = join19(out, `${appName}.dmg`);
|
|
220466
|
+
rmSync5(dmg, { force: true });
|
|
220467
|
+
const stage = join19(tmp, "dmg");
|
|
220468
|
+
rmSync5(stage, { recursive: true, force: true });
|
|
220469
|
+
mkdirSync12(stage, { recursive: true });
|
|
220470
|
+
note("Building the disk image…");
|
|
220471
|
+
execFileSync4("cp", ["-R", app, join19(stage, basename6(app))]);
|
|
220472
|
+
symlinkSync("/Applications", join19(stage, "Applications"));
|
|
220473
|
+
const r2 = spawnSync5("hdiutil", [
|
|
220474
|
+
"create",
|
|
220475
|
+
"-volname",
|
|
220476
|
+
appName,
|
|
220477
|
+
"-srcfolder",
|
|
220478
|
+
stage,
|
|
220479
|
+
"-fs",
|
|
220480
|
+
"HFS+",
|
|
220481
|
+
"-format",
|
|
220482
|
+
"UDZO",
|
|
220483
|
+
"-ov",
|
|
220484
|
+
dmg
|
|
220485
|
+
], { encoding: "utf8" });
|
|
220486
|
+
rmSync5(stage, { recursive: true, force: true });
|
|
220487
|
+
if (r2.status !== 0)
|
|
220488
|
+
throw new CliError(`hdiutil failed:
|
|
220489
|
+
${(r2.stdout + r2.stderr).trim()}`);
|
|
220490
|
+
if (signing.identity !== "-") {
|
|
220491
|
+
await codesignRetrying(["--force", "--timestamp", "--sign", signing.identity, dmg]);
|
|
220492
|
+
if (signing.notaryProfile)
|
|
220493
|
+
notarize(dmg, signing.notaryProfile, tmp, "disk image");
|
|
220494
|
+
}
|
|
220495
|
+
success(`DMG: ${dmg} (${mb(statSync6(dmg).size)})`);
|
|
220357
220496
|
};
|
|
220358
220497
|
var gatekeeperVerdict = (app) => {
|
|
220359
220498
|
const r2 = spawnSync5("spctl", ["-a", "-t", "exec", "-vv", app], { encoding: "utf8" });
|
|
@@ -220454,12 +220593,12 @@ var buildMacApp = async (input) => {
|
|
|
220454
220593
|
writeFileSync14(join19(proj, "app.js"), js);
|
|
220455
220594
|
let assetBytes = 0, assetCount = 0;
|
|
220456
220595
|
for (const r2 of shipped) {
|
|
220457
|
-
if (!r2.absPath || !existsSync18(r2.absPath) || !
|
|
220596
|
+
if (!r2.absPath || !existsSync18(r2.absPath) || !statSync6(r2.absPath).isFile()) {
|
|
220458
220597
|
warn(`asset "${r2.name}" (${r2.path}) has no local file — skipped`);
|
|
220459
220598
|
continue;
|
|
220460
220599
|
}
|
|
220461
220600
|
cpSync2(r2.absPath, join19(proj, "assets", r2.name));
|
|
220462
|
-
assetBytes +=
|
|
220601
|
+
assetBytes += statSync6(r2.absPath).size;
|
|
220463
220602
|
assetCount++;
|
|
220464
220603
|
}
|
|
220465
220604
|
note(` assets: ${assetCount} files, ${mb(assetBytes)} → Contents/Resources/project/assets/`);
|
|
@@ -220487,7 +220626,7 @@ var buildMacApp = async (input) => {
|
|
|
220487
220626
|
}, developerIdInKeychain);
|
|
220488
220627
|
await signApp(app, signing, hostApp, tmp);
|
|
220489
220628
|
if (signing.notaryProfile) {
|
|
220490
|
-
|
|
220629
|
+
notarize(app, signing.notaryProfile, tmp, "app");
|
|
220491
220630
|
} else if (signing.identity !== "-") {
|
|
220492
220631
|
warn("Signed with Developer ID but NOT notarized — Gatekeeper refuses a downloaded copy on every other Mac.");
|
|
220493
220632
|
warn(" Set desktop.macos.notarize.profile in app.json (a `xcrun notarytool store-credentials` profile) or pass --notarize <profile>.");
|
|
@@ -220499,15 +220638,17 @@ var buildMacApp = async (input) => {
|
|
|
220499
220638
|
}
|
|
220500
220639
|
writeFileSync14(join19(out, "README.txt"), readmeText(appName, !!signing.notaryProfile, signing.identity !== "-"));
|
|
220501
220640
|
success(`App: ${app} (${mb(dirSize(app))})`);
|
|
220641
|
+
if (flagBool(args, "dmg"))
|
|
220642
|
+
await buildDmg(app, out, appName, signing, tmp);
|
|
220502
220643
|
if (flagBool(args, "probe"))
|
|
220503
220644
|
await probeMacApp(app, out, args);
|
|
220504
220645
|
if (flagBool(args, "zip")) {
|
|
220505
220646
|
const zip = join19(out, `${appName}.zip`);
|
|
220506
220647
|
rmSync5(zip, { force: true });
|
|
220507
220648
|
execFileSync4("ditto", ["-c", "-k", "--keepParent", app, zip]);
|
|
220508
|
-
success(`Zip: ${zip} (${mb(
|
|
220509
|
-
} else {
|
|
220510
|
-
note("Tip: --zip packs the .app for sending
|
|
220649
|
+
success(`Zip: ${zip} (${mb(statSync6(zip).size)})`);
|
|
220650
|
+
} else if (!flagBool(args, "dmg")) {
|
|
220651
|
+
note("Tip: --zip packs the .app for sending; --dmg wraps it in a drag-to-Applications image.");
|
|
220511
220652
|
}
|
|
220512
220653
|
} finally {
|
|
220513
220654
|
rmSync5(tmp, { recursive: true, force: true });
|
|
@@ -220529,9 +220670,9 @@ or remove the quarantine flag in Terminal: xattr -dr com.apple.quarantine "` +
|
|
|
220529
220670
|
|
|
220530
220671
|
// src/commands/appDesktop.ts
|
|
220531
220672
|
var mb2 = (bytes) => `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
220532
|
-
var dirSize2 = (dir) =>
|
|
220673
|
+
var dirSize2 = (dir) => readdirSync9(dir, { withFileTypes: true }).reduce((sum, e2) => {
|
|
220533
220674
|
const p2 = join20(dir, e2.name);
|
|
220534
|
-
return sum + (e2.isDirectory() ? dirSize2(p2) :
|
|
220675
|
+
return sum + (e2.isDirectory() ? dirSize2(p2) : statSync7(p2).size);
|
|
220535
220676
|
}, 0);
|
|
220536
220677
|
var initDesktop = async (args) => {
|
|
220537
220678
|
const root = projectRoot();
|
|
@@ -220560,7 +220701,7 @@ var buildDesktop = async (args) => {
|
|
|
220560
220701
|
const slug = flagStr(args, "slug") ?? cleanFileName(name);
|
|
220561
220702
|
const out = resolve7(root, flagStr(args, "o", "out") ?? join20(root, "dist", slug));
|
|
220562
220703
|
if (existsSync19(out)) {
|
|
220563
|
-
const entries =
|
|
220704
|
+
const entries = readdirSync9(out);
|
|
220564
220705
|
const looksLikeBuild = entries.length === 0 || entries.includes("app.js") || entries.some((e2) => e2.endsWith(".app"));
|
|
220565
220706
|
if (!looksLikeBuild) {
|
|
220566
220707
|
throw new CliError(`${out} exists and doesn't look like a previous desktop build — pick another -o or clear it yourself.`);
|
|
@@ -220597,7 +220738,7 @@ var buildDesktop = async (args) => {
|
|
|
220597
220738
|
const hostProvided = mac ? macHostProvidedNames(exe) : new Set;
|
|
220598
220739
|
if (!mac) {
|
|
220599
220740
|
try {
|
|
220600
|
-
for (const f3 of
|
|
220741
|
+
for (const f3 of readdirSync9(join20(hostDir, "assets")))
|
|
220601
220742
|
hostProvided.add(f3);
|
|
220602
220743
|
} catch {}
|
|
220603
220744
|
}
|
|
@@ -220608,10 +220749,12 @@ var buildDesktop = async (args) => {
|
|
|
220608
220749
|
}
|
|
220609
220750
|
if (mac)
|
|
220610
220751
|
return buildMacApp({ root, config, name, slug, out, js, shipped, hostExe: exe, args });
|
|
220752
|
+
if (flagBool(args, "dmg"))
|
|
220753
|
+
warn("--dmg is a macOS format — ignored on this platform.");
|
|
220611
220754
|
const version = process.env.LECODES_DESKTOP_EXE ? "local build" : selectedDesktopVersion();
|
|
220612
220755
|
rmSync6(out, { recursive: true, force: true });
|
|
220613
220756
|
mkdirSync13(out, { recursive: true });
|
|
220614
|
-
for (const entry of
|
|
220757
|
+
for (const entry of readdirSync9(hostDir, { withFileTypes: true })) {
|
|
220615
220758
|
if (entry.isFile() && entry.name.toLowerCase().endsWith(".dll")) {
|
|
220616
220759
|
cpSync3(join20(hostDir, entry.name), join20(out, entry.name));
|
|
220617
220760
|
} else if (entry.isDirectory() && entry.name === "assets") {
|
|
@@ -220631,12 +220774,12 @@ var buildDesktop = async (args) => {
|
|
|
220631
220774
|
if (shipped.length > 0)
|
|
220632
220775
|
mkdirSync13(join20(out, ASSETS_DIR), { recursive: true });
|
|
220633
220776
|
for (const r2 of shipped) {
|
|
220634
|
-
if (!r2.absPath || !existsSync19(r2.absPath) || !
|
|
220777
|
+
if (!r2.absPath || !existsSync19(r2.absPath) || !statSync7(r2.absPath).isFile()) {
|
|
220635
220778
|
warn(`asset "${r2.name}" (${r2.path}) has no local file — skipped`);
|
|
220636
220779
|
continue;
|
|
220637
220780
|
}
|
|
220638
220781
|
cpSync3(r2.absPath, join20(out, ASSETS_DIR, r2.name));
|
|
220639
|
-
assetBytes +=
|
|
220782
|
+
assetBytes += statSync7(r2.absPath).size;
|
|
220640
220783
|
assetCount++;
|
|
220641
220784
|
}
|
|
220642
220785
|
note(` assets: ${assetCount} files, ${mb2(assetBytes)} → ${ASSETS_DIR}/`);
|
|
@@ -220645,6 +220788,15 @@ var buildDesktop = async (args) => {
|
|
|
220645
220788
|
await writeIco(root, config, join20(out, "app.ico"));
|
|
220646
220789
|
note(" app.ico rendered from " + config.icon);
|
|
220647
220790
|
}
|
|
220791
|
+
{
|
|
220792
|
+
const { files } = desktopPluginLibraries(root, { strict: true });
|
|
220793
|
+
if (files.length > 0) {
|
|
220794
|
+
mkdirSync13(join20(out, "plugins"), { recursive: true });
|
|
220795
|
+
for (const f3 of files)
|
|
220796
|
+
cpSync3(f3, join20(out, "plugins", basename7(f3)));
|
|
220797
|
+
note(` plugins: ${files.map((f3) => basename7(f3)).join(", ")} → plugins/`);
|
|
220798
|
+
}
|
|
220799
|
+
}
|
|
220648
220800
|
writeFileSync15(join20(out, "README.txt"), "\uFEFF" + readmeText2(name, exeName2, version));
|
|
220649
220801
|
success(`Portable build: ${out} (${mb2(dirSize2(out))})`);
|
|
220650
220802
|
if (flagBool(args, "probe"))
|
|
@@ -220744,7 +220896,7 @@ var zipBuild = (out) => {
|
|
|
220744
220896
|
} else {
|
|
220745
220897
|
execFileSync5("zip", ["-rq", zip, basename7(out)], { cwd: dirname11(out) });
|
|
220746
220898
|
}
|
|
220747
|
-
success(`Zip: ${zip} (${mb2(
|
|
220899
|
+
success(`Zip: ${zip} (${mb2(statSync7(zip).size)})`);
|
|
220748
220900
|
};
|
|
220749
220901
|
var readmeText2 = (name, exeName2, version) => `${name}
|
|
220750
220902
|
${"=".repeat(Math.max(name.length, 4))}
|
|
@@ -220951,13 +221103,18 @@ var syncIos = async (root, config) => {
|
|
|
220951
221103
|
for (const [key, value] of Object.entries(ios.entitlements ?? {})) {
|
|
220952
221104
|
(entitlementValues[key] ??= []).push(value);
|
|
220953
221105
|
}
|
|
220954
|
-
|
|
221106
|
+
for (const pkg of ios.packages ?? []) {
|
|
221107
|
+
if (!pkg.url || !Array.isArray(pkg.products) || pkg.products.length === 0 || !pkg.exact && !pkg.from || pkg.exact && pkg.from) {
|
|
221108
|
+
throw new CliError(`Plugin "${id}": manifest ios.packages entries need { url, exact | from, products: [...] } — got ${JSON.stringify(pkg)}`);
|
|
221109
|
+
}
|
|
221110
|
+
}
|
|
221111
|
+
runtimePlugins.push({ id, module, register, packages: ios.packages });
|
|
220955
221112
|
newLock[id] = plugin.lock;
|
|
220956
221113
|
log(`${c.green("plugin")} ${id}@${plugin.lock.version} (${plugin.lock.tag} → Sources/${module})`);
|
|
220957
221114
|
}
|
|
220958
221115
|
const keep = new Set(["LeCodesRuntime", ...runtimePlugins.map((p2) => p2.module)]);
|
|
220959
|
-
for (const entry of existsSync20(sourcesDir) ?
|
|
220960
|
-
if (!keep.has(entry) &&
|
|
221116
|
+
for (const entry of existsSync20(sourcesDir) ? readdirSync10(sourcesDir) : []) {
|
|
221117
|
+
if (!keep.has(entry) && statSync8(join21(sourcesDir, entry)).isDirectory()) {
|
|
220961
221118
|
rmSync7(join21(sourcesDir, entry), { recursive: true });
|
|
220962
221119
|
log(`${c.yellow("removed")} ios/LeCodesRuntime/Sources/${entry} (plugin uninstalled)`);
|
|
220963
221120
|
}
|
|
@@ -220985,7 +221142,7 @@ var syncIos = async (root, config) => {
|
|
|
220985
221142
|
if (variant === "3d" || variant === "full") {
|
|
220986
221143
|
const sdkResources = await ensureSdkResourcesBundle(sdkVersion);
|
|
220987
221144
|
cpSync4(sdkResources, join21(resourcesDir, "LeCodesSDKResources.bundle"), { recursive: true });
|
|
220988
|
-
for (const f3 of
|
|
221145
|
+
for (const f3 of readdirSync10(sdkResources))
|
|
220989
221146
|
if (f3 !== "Info.plist")
|
|
220990
221147
|
sdkProvided.add(f3);
|
|
220991
221148
|
log(`${c.green("resources")} LeCodesSDKResources.bundle (filament) → ios/App/Resources/`);
|
|
@@ -221323,7 +221480,7 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
221323
221480
|
check(xcodeVersion !== "", `Xcode CLI (${xcodeVersion || "not found"})`, "install Xcode + command line tools");
|
|
221324
221481
|
check(!!config.ios.teamId, "Development team set", "lecodes app init wrote app.json — fill ios.teamId", false);
|
|
221325
221482
|
const iconDir = join21(root, "ios", "App", "Assets.xcassets", "AppIcon.appiconset");
|
|
221326
|
-
const hasIcon = existsSync20(iconDir) &&
|
|
221483
|
+
const hasIcon = existsSync20(iconDir) && readdirSync10(iconDir).some((f3) => f3.endsWith(".png"));
|
|
221327
221484
|
check(hasIcon, "App icon present", "drop a 1024×1024 PNG into ios/App/Assets.xcassets/AppIcon.appiconset/ (App Store requires it)", false);
|
|
221328
221485
|
const bundle = join21(root, "ios", "App", "Resources", "app.js");
|
|
221329
221486
|
check(existsSync20(bundle), "Bundled app.js", "run `lecodes app sync`");
|
|
@@ -221366,7 +221523,7 @@ var doctorIosChecks = async (root, config, check) => {
|
|
|
221366
221523
|
const plist = readFileSync17(join21(root, "ios", "App", "Info.plist"), "utf8");
|
|
221367
221524
|
check(plist.includes("<key>LeCodesUpdateURL</key>"), "OTA update URL in Info.plist", "run `lecodes app sync`", false);
|
|
221368
221525
|
const appDir = join21(root, "ios", "App");
|
|
221369
|
-
const callsUpdater =
|
|
221526
|
+
const callsUpdater = readdirSync10(appDir).some((f3) => f3.endsWith(".swift") && readFileSync17(join21(appDir, f3), "utf8").includes("LeCodesUpdater.activeBundle"));
|
|
221370
221527
|
check(callsUpdater, "App code launches via LeCodesUpdater", `no App/*.swift calls LeCodesUpdater.activeBundle() — downloaded updates would never run; see "Over-the-air updates" in ios/README.md for the ViewController snippet`, false);
|
|
221371
221528
|
}
|
|
221372
221529
|
const asc = readJson(join21(homedir7(), ".lecodes", "asc.json"));
|
|
@@ -221519,7 +221676,7 @@ var app = async (args) => {
|
|
|
221519
221676
|
init_api();
|
|
221520
221677
|
init_config();
|
|
221521
221678
|
init_manifest();
|
|
221522
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync16, readdirSync as
|
|
221679
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync16, readdirSync as readdirSync12 } from "node:fs";
|
|
221523
221680
|
import { resolve as resolve9 } from "node:path";
|
|
221524
221681
|
init_types4();
|
|
221525
221682
|
init_ignore();
|
|
@@ -221542,7 +221699,7 @@ var clone3 = async (args) => {
|
|
|
221542
221699
|
const project = await getProject(apiUrl, token, uuid);
|
|
221543
221700
|
const dir = args._[1] ?? slug(project.name);
|
|
221544
221701
|
const root = resolve9(dir);
|
|
221545
|
-
if (existsSync22(root) &&
|
|
221702
|
+
if (existsSync22(root) && readdirSync12(root).length > 0) {
|
|
221546
221703
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
221547
221704
|
}
|
|
221548
221705
|
mkdirSync16(root, { recursive: true });
|
|
@@ -221568,7 +221725,7 @@ init_config();
|
|
|
221568
221725
|
init_manifest();
|
|
221569
221726
|
init_types4();
|
|
221570
221727
|
init_ignore();
|
|
221571
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync17, readdirSync as
|
|
221728
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync17, readdirSync as readdirSync13, writeFileSync as writeFileSync18 } from "node:fs";
|
|
221572
221729
|
import { join as join23, resolve as resolve10 } from "node:path";
|
|
221573
221730
|
|
|
221574
221731
|
// src/commands/projectTemplates.ts
|
|
@@ -221591,7 +221748,7 @@ lecodes render src/screens/cart.ts # ONE screen module, without booting the ap
|
|
|
221591
221748
|
# --state <name> picks the branch). Same flags as above.
|
|
221592
221749
|
lecodes render --desktop --png shot.png # NATIVE render: real Filament 3D + UI + 2D composited —
|
|
221593
221750
|
# use this to SEE 3D scenes / procedural geometry (headless
|
|
221594
|
-
# renders record 3D as JSON
|
|
221751
|
+
# renders record 3D as JSON — simulated, not drawn). Windows/Linux; downloads
|
|
221595
221752
|
# the renderer on first use. --frames <n> for slow loads.
|
|
221596
221753
|
lecodes render --script <file> # drive the app through a scenario (format below)
|
|
221597
221754
|
lecodes render --desktop --view iso --png iso.png # 3D: inspection camera fitted to the WHOLE
|
|
@@ -221640,8 +221797,9 @@ advance in fixed 1/60 steps driven by \`wait\`/\`frames\`/\`drag\`/\`key\` — n
|
|
|
221640
221797
|
so a flow that passes once passes every time. \`Input.key(code)\` reads the keys a flow holds and
|
|
221641
221798
|
\`Input.on('keydown' | 'keyup', e => e.code)\` fires for each \`key\`/\`keyDown\`/\`keyUp\` step
|
|
221642
221799
|
(events land before the next loop tick); \`stick\` values are what \`Input.gamepad(0).axis()\` reads.
|
|
221643
|
-
Headless draws UI + the 2D scene (sprites, tilemaps, Box2D); 3D is captured as JSON
|
|
221644
|
-
|
|
221800
|
+
Headless draws UI + the 2D scene (sprites, tilemaps, Box2D); 3D is captured as JSON with REAL Jolt
|
|
221801
|
+
physics (bodies fall, characters collide, triggers fire, ragdolls drop — a character with no ground
|
|
221802
|
+
under it falls, like on device) — use \`--desktop\` for 3D pixels. \`console.log\` + \`expect.log\` is the assertion
|
|
221645
221803
|
channel for game state that has no UI.
|
|
221646
221804
|
|
|
221647
221805
|
## Make the app testable
|
|
@@ -221660,7 +221818,7 @@ channel for game state that has no UI.
|
|
|
221660
221818
|
## SDK documentation
|
|
221661
221819
|
|
|
221662
221820
|
\`.lecodes/types/\` is the exact API surface (signatures only; generated and gitignored — run
|
|
221663
|
-
\`lecodes
|
|
221821
|
+
\`lecodes update\` if it's missing, never commit \`.lecodes/\`). For semantics and examples,
|
|
221664
221822
|
fetch the docs — they are served as raw markdown for AI tools:
|
|
221665
221823
|
|
|
221666
221824
|
- https://le.codes/llms.txt — the docs map; fetch it first to find the right page
|
|
@@ -221710,7 +221868,7 @@ var create = async (args) => {
|
|
|
221710
221868
|
throw new CliError("Usage: lecodes create <name> [directory]");
|
|
221711
221869
|
const dir = args._[1] ?? slug2(name);
|
|
221712
221870
|
const root = resolve10(dir);
|
|
221713
|
-
if (existsSync23(root) &&
|
|
221871
|
+
if (existsSync23(root) && readdirSync13(root).length > 0) {
|
|
221714
221872
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
221715
221873
|
}
|
|
221716
221874
|
mkdirSync17(root, { recursive: true });
|
|
@@ -221733,6 +221891,7 @@ var create = async (args) => {
|
|
|
221733
221891
|
// src/commands/desktop.ts
|
|
221734
221892
|
init_util();
|
|
221735
221893
|
init_manifest();
|
|
221894
|
+
import { basename as basename9 } from "node:path";
|
|
221736
221895
|
var resolveScale = (flag, cfg) => {
|
|
221737
221896
|
const raw = flag ?? cfg;
|
|
221738
221897
|
if (raw === undefined || raw === "system")
|
|
@@ -221766,9 +221925,13 @@ var run = async (args) => {
|
|
|
221766
221925
|
const renderer = resolveDesktopRenderer(root, args);
|
|
221767
221926
|
const { js, resources } = await buildBundle(args, undefined, { localAssets: true, desktopRenderer: renderer });
|
|
221768
221927
|
assertRendererSupportsBundle(renderer, js);
|
|
221928
|
+
const { dirs: pluginDirs, files: pluginFiles } = desktopPluginLibraries(root);
|
|
221929
|
+
if (pluginFiles.length > 0)
|
|
221930
|
+
note(`Native plugins: ${pluginFiles.map((f3) => basename9(f3)).join(", ")}`);
|
|
221769
221931
|
note(`Launching LeCodes Desktop${renderer === "vulkan" ? " (Vulkan)" : ""}… (close the window to return)`);
|
|
221770
221932
|
await runDesktopApp(js, resources, {
|
|
221771
221933
|
renderer,
|
|
221934
|
+
pluginDirs,
|
|
221772
221935
|
width: Number(flagStr(args, "width")) || win?.width,
|
|
221773
221936
|
height: Number(flagStr(args, "height")) || win?.height,
|
|
221774
221937
|
minWidth: win?.minWidth,
|
|
@@ -221822,15 +221985,15 @@ init_design();
|
|
|
221822
221985
|
// src/commands/dev.ts
|
|
221823
221986
|
init_manifest();
|
|
221824
221987
|
init_ignore();
|
|
221825
|
-
import { existsSync as
|
|
221988
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync19, readFileSync as readFileSync22, watch, writeFileSync as writeFileSync20 } from "node:fs";
|
|
221826
221989
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
221827
221990
|
import { networkInterfaces } from "node:os";
|
|
221828
|
-
import { basename as
|
|
221991
|
+
import { basename as basename12, join as join28 } from "node:path";
|
|
221829
221992
|
|
|
221830
221993
|
// src/dev/devServer.ts
|
|
221831
221994
|
init_localFiles();
|
|
221832
221995
|
import { createServer as createServer2 } from "node:http";
|
|
221833
|
-
import { createReadStream, statSync as
|
|
221996
|
+
import { createReadStream, statSync as statSync10 } from "node:fs";
|
|
221834
221997
|
import { join as join26 } from "node:path";
|
|
221835
221998
|
init_projectCompile();
|
|
221836
221999
|
init_fonts();
|
|
@@ -222094,7 +222257,12 @@ var MIME = {
|
|
|
222094
222257
|
woff2: "font/woff2",
|
|
222095
222258
|
json: "application/json",
|
|
222096
222259
|
txt: "text/plain",
|
|
222097
|
-
js: "text/javascript"
|
|
222260
|
+
js: "text/javascript",
|
|
222261
|
+
mjs: "text/javascript",
|
|
222262
|
+
css: "text/css",
|
|
222263
|
+
html: "text/html",
|
|
222264
|
+
wasm: "application/wasm",
|
|
222265
|
+
map: "application/json"
|
|
222098
222266
|
};
|
|
222099
222267
|
var contentType = (path2) => {
|
|
222100
222268
|
const i2 = path2.lastIndexOf(".");
|
|
@@ -222189,22 +222357,58 @@ var startDevServer = async (options) => {
|
|
|
222189
222357
|
else if (m.type === "error")
|
|
222190
222358
|
log2(`[device:error] ${demangle(m.text ?? "")}`);
|
|
222191
222359
|
};
|
|
222192
|
-
const transportOf = (url) =>
|
|
222360
|
+
const transportOf = (url) => {
|
|
222361
|
+
const t2 = url.searchParams.get("t");
|
|
222362
|
+
return t2 === "poll" ? "poll" : t2 === "web" ? "web" : "ws";
|
|
222363
|
+
};
|
|
222364
|
+
const withPrelude = (js, url, v2) => {
|
|
222365
|
+
const transport = transportOf(url);
|
|
222366
|
+
return transport === "web" ? js : js + `
|
|
222367
|
+
` + renderPrelude({ origin, base, transport, v: v2 });
|
|
222368
|
+
};
|
|
222369
|
+
const webDir = options.webDir ?? null;
|
|
222193
222370
|
const handle = async (req, res) => {
|
|
222194
222371
|
const url = new URL(req.url ?? "/", origin);
|
|
222195
222372
|
const path2 = url.pathname;
|
|
222373
|
+
if (path2 === "/favicon.ico") {
|
|
222374
|
+
res.writeHead(204);
|
|
222375
|
+
res.end();
|
|
222376
|
+
return;
|
|
222377
|
+
}
|
|
222196
222378
|
if (!path2.startsWith(base + "/"))
|
|
222197
222379
|
return sendText(res, 404, "text/plain", "Not found");
|
|
222198
222380
|
const route = path2.slice(base.length);
|
|
222199
222381
|
if (route === "/dev.js") {
|
|
222200
|
-
return sendText(res, 200, "text/javascript", devJs
|
|
222201
|
-
` + renderPrelude({ origin, base, transport: transportOf(url), v: -1 }));
|
|
222382
|
+
return sendText(res, 200, "text/javascript", withPrelude(devJs, url, -1));
|
|
222202
222383
|
}
|
|
222203
222384
|
if (route === "/bundle.js") {
|
|
222204
222385
|
if (bundleJs === null)
|
|
222205
222386
|
return sendText(res, 503, "text/plain", "No successful compile yet — check the terminal.");
|
|
222206
|
-
|
|
222207
|
-
|
|
222387
|
+
res.setHeader("x-lecodes-v", String(v));
|
|
222388
|
+
return sendText(res, 200, "text/javascript", withPrelude(bundleJs, url, v));
|
|
222389
|
+
}
|
|
222390
|
+
if (route === "/web") {
|
|
222391
|
+
res.writeHead(302, { location: `${base}/web/${url.search}` });
|
|
222392
|
+
res.end();
|
|
222393
|
+
return;
|
|
222394
|
+
}
|
|
222395
|
+
if (route.startsWith("/web/")) {
|
|
222396
|
+
if (!webDir)
|
|
222397
|
+
return sendText(res, 404, "text/plain", "No Web Lite runner vendored with this CLI (lecodes-viewer-lite dist-embed).");
|
|
222398
|
+
const rel = route === "/web/" ? "embed.html" : route.slice("/web/".length);
|
|
222399
|
+
if (rel.split("/").some((seg) => seg === ".." || seg === "" || seg === "."))
|
|
222400
|
+
return sendText(res, 400, "text/plain", "Bad path");
|
|
222401
|
+
const abs = join26(webDir, ...rel.split("/"));
|
|
222402
|
+
try {
|
|
222403
|
+
if (!statSync10(abs).isFile())
|
|
222404
|
+
throw new Error("not a file");
|
|
222405
|
+
} catch {
|
|
222406
|
+
return sendText(res, 404, "text/plain", "Not found");
|
|
222407
|
+
}
|
|
222408
|
+
const hashed = rel.startsWith("assets/");
|
|
222409
|
+
res.writeHead(200, { "content-type": contentType(rel), "cache-control": hashed ? "max-age=31536000, immutable" : "no-store" });
|
|
222410
|
+
createReadStream(abs).pipe(res);
|
|
222411
|
+
return;
|
|
222208
222412
|
}
|
|
222209
222413
|
if (route === "/version") {
|
|
222210
222414
|
return sendJson(res, 200, { v });
|
|
@@ -222219,7 +222423,7 @@ var startDevServer = async (options) => {
|
|
|
222219
222423
|
return sendText(res, 400, "text/plain", "Bad path");
|
|
222220
222424
|
const abs = join26(shadersCacheDir(root), name2);
|
|
222221
222425
|
try {
|
|
222222
|
-
if (!
|
|
222426
|
+
if (!statSync10(abs).isFile())
|
|
222223
222427
|
throw new Error("not a file");
|
|
222224
222428
|
} catch {
|
|
222225
222429
|
return sendText(res, 404, "text/plain", "Not found");
|
|
@@ -222236,7 +222440,7 @@ var startDevServer = async (options) => {
|
|
|
222236
222440
|
return sendText(res, 400, "text/plain", "Bad path");
|
|
222237
222441
|
}
|
|
222238
222442
|
const abs = resolveLocalPath(root, key);
|
|
222239
|
-
if (!abs || !
|
|
222443
|
+
if (!abs || !statSync10(abs).isFile())
|
|
222240
222444
|
return sendText(res, 404, "text/plain", "Not found");
|
|
222241
222445
|
res.writeHead(200, { "content-type": contentType(key), "cache-control": "no-store" });
|
|
222242
222446
|
createReadStream(abs).pipe(res);
|
|
@@ -222290,6 +222494,7 @@ var startDevServer = async (options) => {
|
|
|
222290
222494
|
const boundPort = typeof address === "object" && address !== null ? address.port : options.port;
|
|
222291
222495
|
return {
|
|
222292
222496
|
url: `${origin}${base}/dev.js`,
|
|
222497
|
+
webUrl: webDir ? `${origin}${base}/web/` : null,
|
|
222293
222498
|
base,
|
|
222294
222499
|
port: boundPort,
|
|
222295
222500
|
v: () => v,
|
|
@@ -222303,7 +222508,25 @@ var startDevServer = async (options) => {
|
|
|
222303
222508
|
};
|
|
222304
222509
|
};
|
|
222305
222510
|
|
|
222511
|
+
// src/dev/webRunner.ts
|
|
222512
|
+
init_distRoot();
|
|
222513
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
222514
|
+
import { createRequire as createRequire5 } from "node:module";
|
|
222515
|
+
import { dirname as dirname14, join as join27 } from "node:path";
|
|
222516
|
+
var resolveWebRunnerDir = () => {
|
|
222517
|
+
const candidates = [join27(distRoot, "runtime", "web")];
|
|
222518
|
+
try {
|
|
222519
|
+
const pkg = createRequire5(import.meta.url).resolve("lecodes-viewer-lite/package.json");
|
|
222520
|
+
candidates.push(join27(dirname14(pkg), "dist-embed"));
|
|
222521
|
+
} catch {}
|
|
222522
|
+
for (const dir of candidates)
|
|
222523
|
+
if (existsSync25(join27(dir, "embed.html")) && existsSync25(join27(dir, "embed.js")))
|
|
222524
|
+
return dir;
|
|
222525
|
+
return null;
|
|
222526
|
+
};
|
|
222527
|
+
|
|
222306
222528
|
// src/commands/dev.ts
|
|
222529
|
+
init_browserAuth();
|
|
222307
222530
|
init_util();
|
|
222308
222531
|
var DEFAULT_PORT2 = 4499;
|
|
222309
222532
|
var DEBOUNCE_MS = 120;
|
|
@@ -222331,14 +222554,14 @@ var lanCandidates = () => {
|
|
|
222331
222554
|
return out.sort((x2, y2) => x2.rank - y2.rank).map(({ address, iface }) => ({ address, iface }));
|
|
222332
222555
|
};
|
|
222333
222556
|
var loadDevToken = (root) => {
|
|
222334
|
-
const path2 =
|
|
222557
|
+
const path2 = join28(root, LECODES_DIR, "dev.json");
|
|
222335
222558
|
try {
|
|
222336
222559
|
const token2 = JSON.parse(readFileSync22(path2, "utf8")).token;
|
|
222337
222560
|
if (token2 && /^[a-z0-9]{8,}$/.test(token2))
|
|
222338
222561
|
return token2;
|
|
222339
222562
|
} catch {}
|
|
222340
222563
|
const token = randomBytes3(6).toString("hex");
|
|
222341
|
-
mkdirSync19(
|
|
222564
|
+
mkdirSync19(join28(root, LECODES_DIR), { recursive: true });
|
|
222342
222565
|
writeFileSync20(path2, JSON.stringify({ token }, null, 2) + `
|
|
222343
222566
|
`);
|
|
222344
222567
|
return token;
|
|
@@ -222364,7 +222587,7 @@ var dev = async (args) => {
|
|
|
222364
222587
|
root = process.cwd();
|
|
222365
222588
|
manifest = null;
|
|
222366
222589
|
}
|
|
222367
|
-
const name = manifest?.name ??
|
|
222590
|
+
const name = manifest?.name ?? basename12(root);
|
|
222368
222591
|
if (typeof globalThis.Bun !== "undefined") {
|
|
222369
222592
|
warnErr("Running under Bun: the websocket reload channel doesn't work here — run `lecodes dev` with Node (or use ?t=poll on the device URL).");
|
|
222370
222593
|
}
|
|
@@ -222376,6 +222599,10 @@ var dev = async (args) => {
|
|
|
222376
222599
|
const alternatives = candidates.filter((c4) => c4.address !== host);
|
|
222377
222600
|
const origin = `http://${host}:${port}`;
|
|
222378
222601
|
const token = loadDevToken(root);
|
|
222602
|
+
const webDir = resolveWebRunnerDir();
|
|
222603
|
+
if (flagBool(args, "web") && !webDir) {
|
|
222604
|
+
throw new CliError("No Web Lite runner found for --web: this CLI has no runtime/web (a monorepo checkout needs `bun run build:embed` in packages/viewer-lite).");
|
|
222605
|
+
}
|
|
222379
222606
|
const server2 = await startDevServer({
|
|
222380
222607
|
root,
|
|
222381
222608
|
manifest,
|
|
@@ -222384,6 +222611,7 @@ var dev = async (args) => {
|
|
|
222384
222611
|
port,
|
|
222385
222612
|
token,
|
|
222386
222613
|
entryOverride: flagStr(args, "entry"),
|
|
222614
|
+
webDir,
|
|
222387
222615
|
log: note
|
|
222388
222616
|
}).catch((e2) => {
|
|
222389
222617
|
const msg = e2 instanceof Error ? e2.message : String(e2);
|
|
@@ -222452,14 +222680,21 @@ ${result.error}`);
|
|
|
222452
222680
|
if (!flagBool(args, "no-qr"))
|
|
222453
222681
|
await printQr(server2.url);
|
|
222454
222682
|
log(`Scan the QR with the LeCodes app, or open: ${c.bold(server2.url)}`);
|
|
222683
|
+
const webLocal = server2.webUrl ? server2.webUrl.replace(`http://${host}:`, "http://localhost:") : null;
|
|
222684
|
+
if (server2.webUrl && webLocal)
|
|
222685
|
+
log(`In the browser (Web Lite): ${c.bold(webLocal)} (LAN: ${server2.webUrl})`);
|
|
222455
222686
|
note(`Older desktop builds (no websocket bridge): ${server2.url}?t=poll`);
|
|
222456
222687
|
if (alternatives.length > 0) {
|
|
222457
222688
|
note(`Device can't reach it? This machine also has ${alternatives.map((a2) => `${a2.address} (${a2.iface})`).join(", ")} — retry with --host <ip>.`);
|
|
222458
222689
|
}
|
|
222459
|
-
if (
|
|
222690
|
+
if (existsSync26(join28(root, LECODES_DIR, "manifest.json")))
|
|
222460
222691
|
note(`Token stored in ${LECODES_DIR}/dev.json (delete it to rotate the URL).`);
|
|
222461
222692
|
log("");
|
|
222462
222693
|
log(`Watching ${root} — save a file to hot-reload. Ctrl+C to stop.`);
|
|
222694
|
+
if (flagBool(args, "web") && webLocal) {
|
|
222695
|
+
note("Opening the browser…");
|
|
222696
|
+
openBrowser(webLocal);
|
|
222697
|
+
}
|
|
222463
222698
|
if (flagBool(args, "desktop")) {
|
|
222464
222699
|
const appCfg = readAppConfigAt(root);
|
|
222465
222700
|
const win = appCfg?.desktop?.window;
|
|
@@ -222486,7 +222721,7 @@ init_localFiles();
|
|
|
222486
222721
|
// src/serverDiff.ts
|
|
222487
222722
|
init_localFiles();
|
|
222488
222723
|
import { readFileSync as readFileSync23 } from "node:fs";
|
|
222489
|
-
import { basename as
|
|
222724
|
+
import { basename as basename13 } from "node:path";
|
|
222490
222725
|
var isTextAsset = (t2) => t2 === "text" || t2 === "shader" || t2 === "scene";
|
|
222491
222726
|
var computeServerDiff = (project, scan2) => {
|
|
222492
222727
|
const pathById = buildPaths(project.assets);
|
|
@@ -222503,7 +222738,7 @@ var computeServerDiff = (project, scan2) => {
|
|
|
222503
222738
|
const server2 = serverByPath.get(path2);
|
|
222504
222739
|
const local = localByPath.get(path2);
|
|
222505
222740
|
if (local && !server2) {
|
|
222506
|
-
const text = isTextKind(classifyKind(
|
|
222741
|
+
const text = isTextKind(classifyKind(basename13(path2)));
|
|
222507
222742
|
entries.push({ path: path2, status: "added", binary: !text, serverText: "", localText: text ? readFileSync23(local.absPath, "utf8") : undefined });
|
|
222508
222743
|
continue;
|
|
222509
222744
|
}
|
|
@@ -222678,8 +222913,8 @@ var statusLabel = (e2) => e2.status === "added" ? c.green(" added ") : e2.st
|
|
|
222678
222913
|
init_manifest();
|
|
222679
222914
|
init_types4();
|
|
222680
222915
|
init_ignore();
|
|
222681
|
-
import { existsSync as
|
|
222682
|
-
import { basename as
|
|
222916
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync20, writeFileSync as writeFileSync21 } from "node:fs";
|
|
222917
|
+
import { basename as basename14, dirname as dirname15, join as join29, resolve as resolve11 } from "node:path";
|
|
222683
222918
|
init_util();
|
|
222684
222919
|
var STARTER2 = `// Welcome to LeCodes — the whole SDK is available as globals, no imports needed.
|
|
222685
222920
|
// Run it live on a device with \`lecodes dev\`, or bundle it with \`lecodes compile -o app.js\`.
|
|
@@ -222777,9 +223012,9 @@ lecodes app open # open it in Xcode, build & run
|
|
|
222777
223012
|
- \`CLAUDE.md\` — guidance for AI assistants (the headless feedback loop + testability conventions)
|
|
222778
223013
|
- \`assets/\` — images/fonts the app references (created on demand)
|
|
222779
223014
|
- \`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
|
|
223015
|
+
They come from the SDK bundled in the CLI; \`lecodes update\` refreshes them from the platform.
|
|
222781
223016
|
- \`.lecodes/\` is gitignored — per-checkout state (those types + \`manifest.json\`, this machine's
|
|
222782
|
-
sync cursor once linked). After a fresh git clone: \`lecodes
|
|
223017
|
+
sync cursor once linked). After a fresh git clone: \`lecodes update\`, then
|
|
222783
223018
|
\`lecodes link --project <uuid>\` to re-attach.
|
|
222784
223019
|
- \`.lecodesignore\` — files a future \`lecodes push\` would skip
|
|
222785
223020
|
|
|
@@ -222788,16 +223023,16 @@ Full command list: \`lecodes --help\`.
|
|
|
222788
223023
|
var init2 = async (args) => {
|
|
222789
223024
|
const dirArg = (args._[0] ?? ".").replace(/[/\\]+$/, "") || ".";
|
|
222790
223025
|
const root = resolve11(dirArg);
|
|
222791
|
-
const name =
|
|
223026
|
+
const name = basename14(root);
|
|
222792
223027
|
mkdirSync20(root, { recursive: true });
|
|
222793
223028
|
let created = 0;
|
|
222794
223029
|
const write = (rel, content) => {
|
|
222795
|
-
const abs =
|
|
222796
|
-
if (
|
|
223030
|
+
const abs = join29(root, rel);
|
|
223031
|
+
if (existsSync27(abs)) {
|
|
222797
223032
|
note(`kept ${rel}`);
|
|
222798
223033
|
return;
|
|
222799
223034
|
}
|
|
222800
|
-
mkdirSync20(
|
|
223035
|
+
mkdirSync20(dirname15(abs), { recursive: true });
|
|
222801
223036
|
writeFileSync21(abs, content);
|
|
222802
223037
|
log(`${c.green("created")} ${rel}`);
|
|
222803
223038
|
created++;
|
|
@@ -222845,8 +223080,8 @@ init_config();
|
|
|
222845
223080
|
init_ignore();
|
|
222846
223081
|
init_localFiles();
|
|
222847
223082
|
init_manifest();
|
|
222848
|
-
import { existsSync as
|
|
222849
|
-
import { basename as
|
|
223083
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
223084
|
+
import { basename as basename16, join as join30, resolve as resolve12 } from "node:path";
|
|
222850
223085
|
init_types4();
|
|
222851
223086
|
init_util();
|
|
222852
223087
|
|
|
@@ -222855,7 +223090,7 @@ init_api();
|
|
|
222855
223090
|
init_config();
|
|
222856
223091
|
init_manifest();
|
|
222857
223092
|
init_localFiles();
|
|
222858
|
-
import { basename as
|
|
223093
|
+
import { basename as basename15 } from "node:path";
|
|
222859
223094
|
import { readFileSync as readFileSync24 } from "node:fs";
|
|
222860
223095
|
init_util();
|
|
222861
223096
|
var push = async (args) => {
|
|
@@ -222912,14 +223147,14 @@ var push = async (args) => {
|
|
|
222912
223147
|
let uploaded = 0;
|
|
222913
223148
|
for (const file of scan2.files) {
|
|
222914
223149
|
const source = sourceFor(file.path);
|
|
222915
|
-
const kind = source?.type ?? classifyKind(
|
|
223150
|
+
const kind = source?.type ?? classifyKind(basename15(file.path));
|
|
222916
223151
|
const entry = { path: file.path, type: kind };
|
|
222917
223152
|
if (source)
|
|
222918
223153
|
entry.assetId = source.id;
|
|
222919
223154
|
if (isTextKind(kind)) {
|
|
222920
223155
|
entry.text = readFileSync24(file.absPath, "utf8");
|
|
222921
223156
|
} else if (!source || source.sha !== file.sha) {
|
|
222922
|
-
const blob = await uploadBlob(apiUrl, token, manifest.uuid,
|
|
223157
|
+
const blob = await uploadBlob(apiUrl, token, manifest.uuid, basename15(file.path), readFileSync24(file.absPath));
|
|
222923
223158
|
entry.blobFileId = blob.id;
|
|
222924
223159
|
uploaded++;
|
|
222925
223160
|
}
|
|
@@ -223027,9 +223262,9 @@ var link = async (args) => {
|
|
|
223027
223262
|
const token = requireToken(config);
|
|
223028
223263
|
const dirArg = args._[0];
|
|
223029
223264
|
const root = dirArg ? resolve12(dirArg) : process.cwd();
|
|
223030
|
-
if (!
|
|
223265
|
+
if (!existsSync28(root))
|
|
223031
223266
|
throw new CliError(`No such directory: ${root}`);
|
|
223032
|
-
if (
|
|
223267
|
+
if (existsSync28(join30(root, LECODES_DIR, "manifest.json")) && !flagBool(args, "force")) {
|
|
223033
223268
|
throw new CliError("This folder is already linked (.lecodes/manifest.json exists) — use `lecodes push`, or `lecodes link --force` to re-link it to another project.");
|
|
223034
223269
|
}
|
|
223035
223270
|
let enclosing = null;
|
|
@@ -223056,7 +223291,7 @@ var link = async (args) => {
|
|
|
223056
223291
|
}
|
|
223057
223292
|
name = project.name;
|
|
223058
223293
|
} else {
|
|
223059
|
-
name = flagStr(args, "name") ??
|
|
223294
|
+
name = flagStr(args, "name") ?? basename16(root);
|
|
223060
223295
|
info(c.dim(`Creating project ${c.bold(name)}…`));
|
|
223061
223296
|
uuid = (await createProject(apiUrl, token, name, flagStr(args, "team"))).uuid;
|
|
223062
223297
|
files = {};
|
|
@@ -223093,10 +223328,10 @@ var link = async (args) => {
|
|
|
223093
223328
|
|
|
223094
223329
|
// src/commands/lightmap.ts
|
|
223095
223330
|
init_manifest();
|
|
223096
|
-
import { existsSync as
|
|
223097
|
-
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
223331
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync21, mkdtempSync as mkdtempSync4, readFileSync as readFileSync25, renameSync as renameSync3, rmSync as rmSync9, statSync as statSync11, unlinkSync, writeFileSync as writeFileSync22 } from "node:fs";
|
|
223332
|
+
import { spawn as spawn6, spawnSync as spawnSync6 } from "node:child_process";
|
|
223098
223333
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
223099
|
-
import { join as
|
|
223334
|
+
import { join as join31, relative as relative4, resolve as resolve13 } from "node:path";
|
|
223100
223335
|
init_util();
|
|
223101
223336
|
var num = (args, key, fallback, min, max) => {
|
|
223102
223337
|
const raw = flagStr(args, key);
|
|
@@ -223109,13 +223344,13 @@ var num = (args, key, fallback, min, max) => {
|
|
|
223109
223344
|
};
|
|
223110
223345
|
var findToktx = () => {
|
|
223111
223346
|
const env = process.env.KTX_TOKTX;
|
|
223112
|
-
if (env &&
|
|
223347
|
+
if (env && existsSync29(env))
|
|
223113
223348
|
return env;
|
|
223114
|
-
for (const base of [process.env.LOCALAPPDATA &&
|
|
223349
|
+
for (const base of [process.env.LOCALAPPDATA && join31(process.env.LOCALAPPDATA, "Programs"), process.env.ProgramFiles]) {
|
|
223115
223350
|
if (!base)
|
|
223116
223351
|
continue;
|
|
223117
|
-
const guess =
|
|
223118
|
-
if (
|
|
223352
|
+
const guess = join31(base, "KTX-Software", "bin", "toktx.exe");
|
|
223353
|
+
if (existsSync29(guess))
|
|
223119
223354
|
return guess;
|
|
223120
223355
|
}
|
|
223121
223356
|
return "toktx";
|
|
@@ -223136,14 +223371,26 @@ var requireToktx = () => {
|
|
|
223136
223371
|
}
|
|
223137
223372
|
return toktx;
|
|
223138
223373
|
};
|
|
223139
|
-
var encodeKtx2 = (toktx, png2, ktx2) => {
|
|
223374
|
+
var encodeKtx2 = (toktx, png2, ktx2) => new Promise((resolve14, reject) => {
|
|
223140
223375
|
const args = ["--t2", "--encode", "uastc", "--uastc_quality", "2", "--zcmp", "18", "--genmipmap", "--assign_oetf", "srgb", ktx2, png2];
|
|
223141
|
-
const p2 =
|
|
223142
|
-
|
|
223143
|
-
|
|
223144
|
-
|
|
223145
|
-
}
|
|
223146
|
-
|
|
223376
|
+
const p2 = spawn6(toktx, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
223377
|
+
let out = "";
|
|
223378
|
+
p2.stdout.on("data", (d) => {
|
|
223379
|
+
out += String(d);
|
|
223380
|
+
});
|
|
223381
|
+
p2.stderr.on("data", (d) => {
|
|
223382
|
+
out += String(d);
|
|
223383
|
+
});
|
|
223384
|
+
p2.on("error", (e2) => reject(new CliError(`toktx failed (${e2.message}) while encoding ${ktx2}`)));
|
|
223385
|
+
p2.on("close", (status2) => {
|
|
223386
|
+
if (status2 === 0)
|
|
223387
|
+
resolve14();
|
|
223388
|
+
else
|
|
223389
|
+
reject(new CliError(`toktx failed (${status2 ?? "?"}) while encoding ${ktx2}:
|
|
223390
|
+
${out.trim()}`));
|
|
223391
|
+
});
|
|
223392
|
+
});
|
|
223393
|
+
var pageFile = (stem, page, light, ext2 = ".ktx2") => `${stem}${light ? "-light" : ""}${page > 0 ? `_${page}` : ""}${ext2}`;
|
|
223147
223394
|
var bake = async (args) => {
|
|
223148
223395
|
let root;
|
|
223149
223396
|
try {
|
|
@@ -223153,20 +223400,31 @@ var bake = async (args) => {
|
|
|
223153
223400
|
}
|
|
223154
223401
|
const toktx = requireToktx();
|
|
223155
223402
|
const outDir = resolve13(root, flagStr(args, "out") ?? "assets/lightmap");
|
|
223403
|
+
const stem = flagStr(args, "name") ?? "lightmap";
|
|
223404
|
+
if (!/^[A-Za-z0-9_-]+$/.test(stem))
|
|
223405
|
+
throw new CliError(`--name wants a plain file stem (letters, digits, - and _), got "${stem}".`);
|
|
223156
223406
|
const entryFlag = flagStr(args, "entry");
|
|
223157
223407
|
const entryFile = entryFlag ?? "main.ts";
|
|
223158
|
-
if (!
|
|
223408
|
+
if (!existsSync29(resolve13(root, entryFile))) {
|
|
223159
223409
|
throw new CliError(`No ${entryFile} in ${root} — pass --entry <file> (the file that builds the scene and calls Lightmap.load).`);
|
|
223160
223410
|
}
|
|
223161
223411
|
const cfg = {
|
|
223162
223412
|
outDir: outDir.replace(/\\/g, "/"),
|
|
223163
223413
|
size: num(args, "size", 4096, 256, 16384),
|
|
223164
223414
|
texel: num(args, "texel", 0.02, 0.001, 2),
|
|
223415
|
+
pages: num(args, "pages", 4, 1, 16),
|
|
223165
223416
|
sunRays: num(args, "sun-rays", 32, 1, 1024),
|
|
223166
223417
|
aoRays: num(args, "ao-rays", 64, 1, 4096),
|
|
223167
223418
|
aoDistance: num(args, "ao-distance", 2, 0.01, 1000),
|
|
223168
223419
|
bias: num(args, "bias", 0.02, 0.0001, 1),
|
|
223169
223420
|
sunAngle: num(args, "sun-angle", 0.5, 0.01, 30),
|
|
223421
|
+
lightRays: num(args, "light-rays", 16, 1, 256),
|
|
223422
|
+
lightRadius: num(args, "light-radius", 0.1, 0.001, 5),
|
|
223423
|
+
bounce: num(args, "bounce", 0, 0, 1),
|
|
223424
|
+
bounceDistance: num(args, "bounce-distance", 8, 0.5, 100),
|
|
223425
|
+
bounceRays: num(args, "bounce-rays", 1, 1, 32),
|
|
223426
|
+
coplanarSkip: num(args, "coplanar-skip", 0.05, 0, 1),
|
|
223427
|
+
denoise: num(args, "denoise", 2, 0, 4),
|
|
223170
223428
|
volumeCell: flagBool(args, "no-volume") ? 0 : num(args, "cell", 0.5, 0.05, 20)
|
|
223171
223429
|
};
|
|
223172
223430
|
const frames = num(args, "frames", 900, 30, 1e5);
|
|
@@ -223180,7 +223438,7 @@ var bake = async (args) => {
|
|
|
223180
223438
|
import ${JSON.stringify(importPath)}
|
|
223181
223439
|
`;
|
|
223182
223440
|
mkdirSync21(outDir, { recursive: true });
|
|
223183
|
-
ensurePlaceholders(outDir);
|
|
223441
|
+
ensurePlaceholders(outDir, stem);
|
|
223184
223442
|
const desktopRenderer = resolveDesktopRenderer(root, args);
|
|
223185
223443
|
const { js, resources } = await buildBundle(args, undefined, {
|
|
223186
223444
|
localAssets: true,
|
|
@@ -223188,12 +223446,12 @@ import ${JSON.stringify(importPath)}
|
|
|
223188
223446
|
extraEntries: [{ path: entryPath, type: "text", text: entryText }],
|
|
223189
223447
|
entryOverride: entryPath
|
|
223190
223448
|
});
|
|
223191
|
-
const scratch = mkdtempSync4(
|
|
223192
|
-
const outPng =
|
|
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) || "."}
|
|
223449
|
+
const scratch = mkdtempSync4(join31(tmpdir4(), "lecodes-lightmap-"));
|
|
223450
|
+
const outPng = join31(scratch, "frame.png");
|
|
223451
|
+
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
223452
|
let output = "";
|
|
223195
223453
|
try {
|
|
223196
|
-
const timeoutMs = Number(flagStr(args, "timeout")) ||
|
|
223454
|
+
const timeoutMs = Number(flagStr(args, "timeout")) || 24 * 3600 * 1000;
|
|
223197
223455
|
const res = await runDesktopRender(js, resources, {
|
|
223198
223456
|
renderer: desktopRenderer,
|
|
223199
223457
|
width,
|
|
@@ -223211,28 +223469,76 @@ import ${JSON.stringify(importPath)}
|
|
|
223211
223469
|
throw e2;
|
|
223212
223470
|
output = msg;
|
|
223213
223471
|
} finally {
|
|
223214
|
-
|
|
223472
|
+
try {
|
|
223473
|
+
rmSync9(scratch, { recursive: true, force: true });
|
|
223474
|
+
} catch {}
|
|
223215
223475
|
}
|
|
223216
223476
|
const lines = output.split(/\r?\n/).filter((l2) => l2.startsWith("[lightmap]"));
|
|
223217
223477
|
for (const l2 of lines) {
|
|
223218
223478
|
const text = l2.slice("[lightmap]".length).trim();
|
|
223219
223479
|
if (text === "done")
|
|
223220
223480
|
continue;
|
|
223221
|
-
logErr(text.startsWith("error") ? c.red(`✗ ${text}`) : c.dim(` ${text}`));
|
|
223481
|
+
logErr(text.startsWith("error") ? c.red(`✗ ${text}`) : text.startsWith("warning") ? c.yellow(` ${text}`) : c.dim(` ${text}`));
|
|
223222
223482
|
}
|
|
223223
223483
|
if (/\[lightmap\] done/.test(output)) {
|
|
223224
|
-
const
|
|
223225
|
-
|
|
223226
|
-
|
|
223227
|
-
|
|
223484
|
+
const bakePath = join31(outDir, "lightmap.bake");
|
|
223485
|
+
if (!existsSync29(bakePath))
|
|
223486
|
+
throw new CliError(`The host reported a bake but ${bakePath} is missing.`);
|
|
223487
|
+
const data = JSON.parse(readFileSync25(bakePath, "utf8"));
|
|
223488
|
+
const pages = Math.max(1, data.pages ?? 1);
|
|
223489
|
+
const hasLight = !!data.lightTextures?.length;
|
|
223228
223490
|
const t0 = Date.now();
|
|
223229
|
-
|
|
223230
|
-
const
|
|
223231
|
-
|
|
223232
|
-
|
|
223233
|
-
|
|
223234
|
-
|
|
223235
|
-
|
|
223491
|
+
let pngKb = 0, ktxKb = 0;
|
|
223492
|
+
const encodePage = async (page, light) => {
|
|
223493
|
+
const png2 = join31(outDir, pageFile("lightmap", page, light, ".png"));
|
|
223494
|
+
const ktx2 = join31(outDir, pageFile(stem, page, light));
|
|
223495
|
+
if (!existsSync29(png2))
|
|
223496
|
+
throw new CliError(`The host reported a bake but ${png2} is missing.`);
|
|
223497
|
+
await encodeKtx2(toktx, png2, ktx2);
|
|
223498
|
+
pngKb += statSync11(png2).size / 1024;
|
|
223499
|
+
ktxKb += statSync11(ktx2).size / 1024;
|
|
223500
|
+
unlinkSync(png2);
|
|
223501
|
+
};
|
|
223502
|
+
const encodes = [];
|
|
223503
|
+
for (let p2 = 0;p2 < pages; p2++) {
|
|
223504
|
+
encodes.push(encodePage(p2, false));
|
|
223505
|
+
if (hasLight)
|
|
223506
|
+
encodes.push(encodePage(p2, true));
|
|
223507
|
+
}
|
|
223508
|
+
await Promise.all(encodes);
|
|
223509
|
+
for (let p2 = pages;p2 < 16; p2++) {
|
|
223510
|
+
for (const light of [false, true]) {
|
|
223511
|
+
const stale = join31(outDir, pageFile(stem, p2, light));
|
|
223512
|
+
if (existsSync29(stale) && statSync11(stale).size !== PLACEHOLDER_KTX2.length)
|
|
223513
|
+
writeFileSync22(stale, PLACEHOLDER_KTX2);
|
|
223514
|
+
}
|
|
223515
|
+
}
|
|
223516
|
+
if (!hasLight) {
|
|
223517
|
+
const light = join31(outDir, pageFile(stem, 0, true));
|
|
223518
|
+
if (existsSync29(light) && statSync11(light).size !== PLACEHOLDER_KTX2.length)
|
|
223519
|
+
writeFileSync22(light, PLACEHOLDER_KTX2);
|
|
223520
|
+
}
|
|
223521
|
+
data.texture = pageFile(stem, 0, false);
|
|
223522
|
+
data.textures = Array.from({ length: pages }, (_, p2) => pageFile(stem, p2, false));
|
|
223523
|
+
if (hasLight)
|
|
223524
|
+
data.lightTextures = Array.from({ length: pages }, (_, p2) => pageFile(stem, p2, true));
|
|
223525
|
+
if (data.volume)
|
|
223526
|
+
data.volume.file = `${stem}.volume`;
|
|
223527
|
+
writeFileSync22(join31(outDir, `${stem}.bake`), JSON.stringify(data, null, 1) + `
|
|
223528
|
+
`);
|
|
223529
|
+
if (stem !== "lightmap")
|
|
223530
|
+
unlinkSync(bakePath);
|
|
223531
|
+
const volumeSrc = join31(outDir, "lightmap.volume");
|
|
223532
|
+
const hasVolume = cfg.volumeCell > 0 && existsSync29(volumeSrc);
|
|
223533
|
+
if (hasVolume && stem !== "lightmap") {
|
|
223534
|
+
rmSync9(join31(outDir, `${stem}.volume`), { force: true });
|
|
223535
|
+
renameSync3(volumeSrc, join31(outDir, `${stem}.volume`));
|
|
223536
|
+
}
|
|
223537
|
+
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`));
|
|
223538
|
+
logErr(c.green(`✓ baked → ${relative4(root, outDir) || "."}/${stem}.bake + ${data.textures.join(", ")}${hasLight ? ` + ${data.lightTextures.join(", ")}` : ""}${hasVolume ? ` + ${stem}.volume` : ""}`));
|
|
223539
|
+
const rel = (f3) => relative4(root, join31(outDir, f3)).replace(/\\/g, "/");
|
|
223540
|
+
const assets = (files) => files.length === 1 ? `asset('<rel>/${rel(files[0])}')` : `[${files.map((f3) => `asset('<rel>/${rel(f3)}')`).join(", ")}]`;
|
|
223541
|
+
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
223542
|
return;
|
|
223237
223543
|
}
|
|
223238
223544
|
if (lines.some((l2) => /no bake module/.test(l2))) {
|
|
@@ -223259,30 +223565,34 @@ var placeholderVolume = () => {
|
|
|
223259
223565
|
b[37] = 255;
|
|
223260
223566
|
return b;
|
|
223261
223567
|
};
|
|
223262
|
-
var ensurePlaceholders = (outDir) => {
|
|
223263
|
-
const
|
|
223264
|
-
const
|
|
223265
|
-
const
|
|
223266
|
-
|
|
223267
|
-
|
|
223568
|
+
var ensurePlaceholders = (outDir, stem) => {
|
|
223569
|
+
const missing = (f3) => !existsSync29(f3) || statSync11(f3).size === 0;
|
|
223570
|
+
const bake2 = join31(outDir, `${stem}.bake`);
|
|
223571
|
+
const ktx2 = join31(outDir, pageFile(stem, 0, false));
|
|
223572
|
+
const light = join31(outDir, pageFile(stem, 0, true));
|
|
223573
|
+
const volume = join31(outDir, `${stem}.volume`);
|
|
223574
|
+
if (missing(bake2))
|
|
223575
|
+
writeFileSync22(bake2, JSON.stringify({ version: 2, placeholder: true, size: 1, texel: 0, pages: 1, instances: [] }) + `
|
|
223268
223576
|
`);
|
|
223269
|
-
if (
|
|
223577
|
+
if (missing(ktx2))
|
|
223270
223578
|
writeFileSync22(ktx2, PLACEHOLDER_KTX2);
|
|
223271
|
-
if (
|
|
223579
|
+
if (missing(light))
|
|
223580
|
+
writeFileSync22(light, PLACEHOLDER_KTX2);
|
|
223581
|
+
if (missing(volume))
|
|
223272
223582
|
writeFileSync22(volume, placeholderVolume());
|
|
223273
223583
|
};
|
|
223274
223584
|
var lightmap = async (args) => {
|
|
223275
223585
|
const sub = args._[0];
|
|
223276
223586
|
if (sub === "bake")
|
|
223277
223587
|
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)");
|
|
223588
|
+
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
223589
|
};
|
|
223280
223590
|
|
|
223281
223591
|
// src/commands/navmesh.ts
|
|
223282
223592
|
init_manifest();
|
|
223283
|
-
import { existsSync as
|
|
223593
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync22, mkdtempSync as mkdtempSync5, readdirSync as readdirSync15, readFileSync as readFileSync26, rmSync as rmSync10, statSync as statSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync23 } from "node:fs";
|
|
223284
223594
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
223285
|
-
import { basename as
|
|
223595
|
+
import { basename as basename17, join as join32, relative as relative5, resolve as resolve14 } from "node:path";
|
|
223286
223596
|
init_util();
|
|
223287
223597
|
|
|
223288
223598
|
// ../creator-nav/dist/creatorNav.js
|
|
@@ -223299,8 +223609,8 @@ var createCreatorNav = (() => {
|
|
|
223299
223609
|
var ENVIRONMENT_IS_WORKER = typeof WorkerGlobalScope != "undefined";
|
|
223300
223610
|
var ENVIRONMENT_IS_NODE = typeof process == "object" && process.versions?.node && process.type != "renderer";
|
|
223301
223611
|
if (ENVIRONMENT_IS_NODE) {
|
|
223302
|
-
const { createRequire:
|
|
223303
|
-
var require2 =
|
|
223612
|
+
const { createRequire: createRequire6 } = await import("module");
|
|
223613
|
+
var require2 = createRequire6(import.meta.url);
|
|
223304
223614
|
}
|
|
223305
223615
|
var arguments_ = [];
|
|
223306
223616
|
var thisProgram = "./this.program";
|
|
@@ -224079,13 +224389,13 @@ var num2 = (args, key, fallback, min, max) => {
|
|
|
224079
224389
|
return n2;
|
|
224080
224390
|
};
|
|
224081
224391
|
var guessName = (root) => {
|
|
224082
|
-
const dirs = [
|
|
224392
|
+
const dirs = [join32(root, "src"), root];
|
|
224083
224393
|
for (const dir of dirs) {
|
|
224084
|
-
if (!
|
|
224394
|
+
if (!existsSync30(dir))
|
|
224085
224395
|
continue;
|
|
224086
224396
|
let entries;
|
|
224087
224397
|
try {
|
|
224088
|
-
entries =
|
|
224398
|
+
entries = readdirSync15(dir);
|
|
224089
224399
|
} catch {
|
|
224090
224400
|
continue;
|
|
224091
224401
|
}
|
|
@@ -224093,7 +224403,7 @@ var guessName = (root) => {
|
|
|
224093
224403
|
if (!f3.endsWith(".scene.ts"))
|
|
224094
224404
|
continue;
|
|
224095
224405
|
try {
|
|
224096
|
-
if (/\bnavmesh\s*:/.test(
|
|
224406
|
+
if (/\bnavmesh\s*:/.test(readFileSync26(join32(dir, f3), "utf8")))
|
|
224097
224407
|
return f3.slice(0, -".scene.ts".length);
|
|
224098
224408
|
} catch {}
|
|
224099
224409
|
}
|
|
@@ -224136,7 +224446,7 @@ var bake2 = async (args) => {
|
|
|
224136
224446
|
const outDir = resolve14(root, flagStr(args, "out") ?? "assets/nav");
|
|
224137
224447
|
const entryFlag = flagStr(args, "entry");
|
|
224138
224448
|
const entryFile = entryFlag ?? "main.ts";
|
|
224139
|
-
if (!
|
|
224449
|
+
if (!existsSync30(resolve14(root, entryFile))) {
|
|
224140
224450
|
throw new CliError(`No ${entryFile} in ${root} — pass --entry <file> (the file that builds the level: a scene file with env.navmesh, or code calling NavMesh.load).`);
|
|
224141
224451
|
}
|
|
224142
224452
|
const name = flagStr(args, "name") ?? guessName(root) ?? "scene";
|
|
@@ -224148,8 +224458,8 @@ var bake2 = async (args) => {
|
|
|
224148
224458
|
const keepGeometry = flagBool(args, "keep-geometry");
|
|
224149
224459
|
const obj = flagBool(args, "obj");
|
|
224150
224460
|
mkdirSync22(outDir, { recursive: true });
|
|
224151
|
-
const navmeshPath =
|
|
224152
|
-
if (!
|
|
224461
|
+
const navmeshPath = join32(outDir, `${name}.navmesh`);
|
|
224462
|
+
if (!existsSync30(navmeshPath))
|
|
224153
224463
|
writeFileSync23(navmeshPath, placeholderLnav());
|
|
224154
224464
|
const importPath = "./" + entryFile.replace(/\\/g, "/").replace(/\.tsx?$/, "");
|
|
224155
224465
|
const entryPath = "/.navmesh-entry.ts";
|
|
@@ -224164,8 +224474,8 @@ import ${JSON.stringify(importPath)}
|
|
|
224164
224474
|
extraEntries: [{ path: entryPath, type: "text", text: entryText }],
|
|
224165
224475
|
entryOverride: entryPath
|
|
224166
224476
|
});
|
|
224167
|
-
const scratch = mkdtempSync5(
|
|
224168
|
-
const outPng =
|
|
224477
|
+
const scratch = mkdtempSync5(join32(tmpdir5(), "lecodes-navmesh-"));
|
|
224478
|
+
const outPng = join32(scratch, "frame.png");
|
|
224169
224479
|
note(`Dumping the level's static collision geometry through the desktop host → ${relative5(root, outDir) || "."}/${name}.navgeo…`);
|
|
224170
224480
|
let output = "";
|
|
224171
224481
|
try {
|
|
@@ -224218,10 +224528,10 @@ import ${JSON.stringify(importPath)}
|
|
|
224218
224528
|
}
|
|
224219
224529
|
if (!config)
|
|
224220
224530
|
throw new CliError("The host reported a dump but no `[navmesh] config` line — SDK/host mismatch?");
|
|
224221
|
-
const geoPath =
|
|
224222
|
-
if (!
|
|
224531
|
+
const geoPath = join32(outDir, `${name}.navgeo`);
|
|
224532
|
+
if (!existsSync30(geoPath))
|
|
224223
224533
|
throw new CliError(`The host reported a dump but ${geoPath} is missing.`);
|
|
224224
|
-
const geo = readNgeo(new Uint8Array(
|
|
224534
|
+
const geo = readNgeo(new Uint8Array(readFileSync26(geoPath)));
|
|
224225
224535
|
const params = {
|
|
224226
224536
|
agentRadius: num2(args, "radius", config.agent.radius, 0.05, 10),
|
|
224227
224537
|
agentHeight: num2(args, "height", config.agent.height, 0.1, 20),
|
|
@@ -224269,18 +224579,18 @@ import ${JSON.stringify(importPath)}
|
|
|
224269
224579
|
}
|
|
224270
224580
|
writeFileSync23(navmeshPath, result.data);
|
|
224271
224581
|
if (obj) {
|
|
224272
|
-
const objPath =
|
|
224582
|
+
const objPath = join32(outDir, `${name}.navmesh.obj`);
|
|
224273
224583
|
writeObj(objPath, navMeshTriangles(mod, result.data));
|
|
224274
224584
|
logErr(c.dim(` wrote ${relative5(root, objPath)} (the polygon mesh, for inspection)`));
|
|
224275
224585
|
}
|
|
224276
224586
|
if (!keepGeometry)
|
|
224277
224587
|
unlinkSync2(geoPath);
|
|
224278
|
-
const kb = Math.round(
|
|
224588
|
+
const kb = Math.round(statSync12(navmeshPath).size / 1024);
|
|
224279
224589
|
const b = result.bounds;
|
|
224280
224590
|
logErr(c.dim(` ${result.tiles} tiles, ${result.polys} polygons, ${(b.max[0] - b.min[0]).toFixed(0)} × ${(b.max[2] - b.min[2]).toFixed(0)} m, ${result.time.toFixed(1)} s`));
|
|
224281
224591
|
logErr(c.green(`✓ baked → ${relative5(root, navmeshPath).replace(/\\/g, "/")} (${kb} KB)`));
|
|
224282
224592
|
if (!config.data) {
|
|
224283
|
-
logErr(c.dim(` load it with env.navmesh: { data: asset('<rel>/${
|
|
224593
|
+
logErr(c.dim(` load it with env.navmesh: { data: asset('<rel>/${basename17(navmeshPath)}') } in the scene file, or NavMesh.load(scene, { data: asset(...) })`));
|
|
224284
224594
|
}
|
|
224285
224595
|
};
|
|
224286
224596
|
var navmesh = async (args) => {
|
|
@@ -224307,7 +224617,7 @@ var login = async (args) => {
|
|
|
224307
224617
|
|
|
224308
224618
|
// src/commands/shaders.ts
|
|
224309
224619
|
init_manifest();
|
|
224310
|
-
import { readFileSync as
|
|
224620
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
224311
224621
|
init_util();
|
|
224312
224622
|
init_compile();
|
|
224313
224623
|
var collectShaders = () => {
|
|
@@ -224339,7 +224649,7 @@ var status2 = async () => {
|
|
|
224339
224649
|
if (matcId === null)
|
|
224340
224650
|
state = c.dim("unknown (matc not downloaded)");
|
|
224341
224651
|
else {
|
|
224342
|
-
const text =
|
|
224652
|
+
const text = readFileSync27(shader.absPath, "utf8");
|
|
224343
224653
|
if (shaderIsCompiled(root, text, matcId))
|
|
224344
224654
|
state = "compiled";
|
|
224345
224655
|
else {
|
|
@@ -224348,7 +224658,7 @@ var status2 = async () => {
|
|
|
224348
224658
|
}
|
|
224349
224659
|
}
|
|
224350
224660
|
log(` ${shader.path.padEnd(width)} ${state}`);
|
|
224351
|
-
const schema = parseShaderSchema(
|
|
224661
|
+
const schema = parseShaderSchema(readFileSync27(shader.absPath, "utf8"));
|
|
224352
224662
|
for (const p2 of schema.params) {
|
|
224353
224663
|
const range = p2.min !== undefined ? ` [${p2.min}..${p2.max}]` : "";
|
|
224354
224664
|
const def = p2.default !== null && p2.default !== undefined ? ` = ${JSON.stringify(p2.default)}` : "";
|
|
@@ -224391,7 +224701,7 @@ var compile3 = async (args) => {
|
|
|
224391
224701
|
}
|
|
224392
224702
|
const matcExe = await resolveMatcExe();
|
|
224393
224703
|
const matcId = matcIdentity(matcExe);
|
|
224394
|
-
const wasCompiled = new Map(shaders.map((s2) => [s2.path, shaderIsCompiled(root,
|
|
224704
|
+
const wasCompiled = new Map(shaders.map((s2) => [s2.path, shaderIsCompiled(root, readFileSync27(s2.absPath, "utf8"), matcId)]));
|
|
224395
224705
|
const errors2 = [];
|
|
224396
224706
|
for (const shader of shaders) {
|
|
224397
224707
|
try {
|
|
@@ -224425,8 +224735,8 @@ var shaders = async (args) => {
|
|
|
224425
224735
|
};
|
|
224426
224736
|
|
|
224427
224737
|
// src/commands/render.ts
|
|
224428
|
-
import { mkdirSync as mkdirSync23, readFileSync as
|
|
224429
|
-
import { dirname as
|
|
224738
|
+
import { mkdirSync as mkdirSync23, readFileSync as readFileSync29, writeFileSync as writeFileSync24 } from "node:fs";
|
|
224739
|
+
import { dirname as dirname16, resolve as resolve17 } from "node:path";
|
|
224430
224740
|
|
|
224431
224741
|
// src/compile/headlessBundle.ts
|
|
224432
224742
|
init_api();
|
|
@@ -224510,8 +224820,8 @@ var compileHeadlessBundle = async (args, opts = {}) => {
|
|
|
224510
224820
|
// src/compile/screenEntry.ts
|
|
224511
224821
|
init_designMeta();
|
|
224512
224822
|
init_util();
|
|
224513
|
-
import { existsSync as
|
|
224514
|
-
import { isAbsolute, join as
|
|
224823
|
+
import { existsSync as existsSync31, readFileSync as readFileSync28, statSync as statSync13 } from "node:fs";
|
|
224824
|
+
import { isAbsolute, join as join33, relative as relative6, resolve as resolve15 } from "node:path";
|
|
224515
224825
|
var SCREEN_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
224516
224826
|
var SCREEN_ENTRY_PATH = "/.screen-entry.ts";
|
|
224517
224827
|
var DEFAULT_DESIGN_DIR = "design";
|
|
@@ -224520,13 +224830,13 @@ var hasSeparator = (file) => file.includes("/") || file.includes("\\");
|
|
|
224520
224830
|
var findScreenFile = (root, file, dirFlag) => {
|
|
224521
224831
|
const candidates = [resolve15(process.cwd(), file)];
|
|
224522
224832
|
if (!hasSeparator(file)) {
|
|
224523
|
-
candidates.push(
|
|
224833
|
+
candidates.push(join33(root, (dirFlag ?? DEFAULT_DESIGN_DIR).replace(/[/\\]+$/, ""), "screens", file));
|
|
224524
224834
|
}
|
|
224525
224835
|
for (const base of candidates) {
|
|
224526
|
-
if (
|
|
224836
|
+
if (existsSync31(base) && statSync13(base).isFile())
|
|
224527
224837
|
return base;
|
|
224528
224838
|
for (const ext2 of SCREEN_EXTS)
|
|
224529
|
-
if (
|
|
224839
|
+
if (existsSync31(base + ext2))
|
|
224530
224840
|
return base + ext2;
|
|
224531
224841
|
}
|
|
224532
224842
|
throw new CliError(`No screen file at "${file}".` + (hasSeparator(file) ? "" : ` Pass a path, or a screen id that exists in ${dirFlag ?? DEFAULT_DESIGN_DIR}/screens/.`));
|
|
@@ -224535,8 +224845,8 @@ var designDirOf = (root, key) => {
|
|
|
224535
224845
|
const m = /^\/(.*)screens\/([^/]+)\.[^./]+$/.exec(key);
|
|
224536
224846
|
if (!m)
|
|
224537
224847
|
return null;
|
|
224538
|
-
const dir =
|
|
224539
|
-
return
|
|
224848
|
+
const dir = join33(root, m[1]);
|
|
224849
|
+
return existsSync31(join33(dir, "meta.json")) ? { dir, id: m[2] } : null;
|
|
224540
224850
|
};
|
|
224541
224851
|
var resolveScreenTarget = (root, file, opts = {}) => {
|
|
224542
224852
|
const abs = findScreenFile(root, file, opts.dir);
|
|
@@ -224545,7 +224855,7 @@ var resolveScreenTarget = (root, file, opts = {}) => {
|
|
|
224545
224855
|
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
224856
|
}
|
|
224547
224857
|
const key = toKey(rel);
|
|
224548
|
-
if (!/^\s*export\s+default\b/m.test(
|
|
224858
|
+
if (!/^\s*export\s+default\b/m.test(readFileSync28(abs, "utf8"))) {
|
|
224549
224859
|
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
224860
|
}
|
|
224551
224861
|
const invoke = opts.state !== undefined ? `screen(${JSON.stringify(opts.state)})` : "screen()";
|
|
@@ -224852,7 +225162,7 @@ var evaluateDesktopRun = (plan, output) => {
|
|
|
224852
225162
|
if (!error && st.expectLog !== undefined) {
|
|
224853
225163
|
const seen = consoleLines.slice(0, cutoff);
|
|
224854
225164
|
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(-
|
|
225165
|
+
const tail = seen.filter((l2) => l2.startsWith("[DEBUG]") || l2.startsWith("[INFO]") || l2.startsWith("[WARN]") || l2.startsWith("[ERROR]")).slice(-8);
|
|
224856
225166
|
error = `expected a console line containing "${st.expectLog}" — ${tail.length === 0 ? "the app logged nothing" : `last lines: ${tail.map((l2) => `"${l2}"`).join(", ")}`}`;
|
|
224857
225167
|
}
|
|
224858
225168
|
}
|
|
@@ -224895,7 +225205,7 @@ var requireRenderer = async () => {
|
|
|
224895
225205
|
var fileScenarioIO = (dir) => ({
|
|
224896
225206
|
write: (relPath, data) => {
|
|
224897
225207
|
const abs = resolve17(dir, relPath);
|
|
224898
|
-
mkdirSync23(
|
|
225208
|
+
mkdirSync23(dirname16(abs), { recursive: true });
|
|
224899
225209
|
writeFileSync24(abs, data);
|
|
224900
225210
|
}
|
|
224901
225211
|
});
|
|
@@ -224906,7 +225216,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
224906
225216
|
if (typeof value === "string") {
|
|
224907
225217
|
const abs = resolve17(baseDir, value);
|
|
224908
225218
|
try {
|
|
224909
|
-
map = JSON.parse(
|
|
225219
|
+
map = JSON.parse(readFileSync29(abs, "utf8"));
|
|
224910
225220
|
} catch (e2) {
|
|
224911
225221
|
throw new CliError(`Can't read fixtures "${value}": ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
224912
225222
|
}
|
|
@@ -224919,7 +225229,7 @@ var resolveFixtures = (value, baseDir) => {
|
|
|
224919
225229
|
var readScenarioFile = (path2) => {
|
|
224920
225230
|
let raw;
|
|
224921
225231
|
try {
|
|
224922
|
-
raw = JSON.parse(
|
|
225232
|
+
raw = JSON.parse(readFileSync29(resolve17(path2), "utf8"));
|
|
224923
225233
|
} catch (e2) {
|
|
224924
225234
|
throw new CliError(`Can't read scenario "${path2}": ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
224925
225235
|
}
|
|
@@ -224970,23 +225280,25 @@ var renderDesktop = async (args) => {
|
|
|
224970
225280
|
if ((camera || view) && scenario)
|
|
224971
225281
|
throw new CliError('--camera/--view apply to a plain render; in a --script run use a { "view": "iso" } or { "camera": { "at", "lookAt" } } step before the screenshot.');
|
|
224972
225282
|
const desktopRenderer = resolveDesktopRenderer(root, args);
|
|
225283
|
+
const { dirs: pluginDirs } = desktopPluginLibraries(root);
|
|
224973
225284
|
const { js, resources } = await buildBundle(args, undefined, {
|
|
224974
225285
|
localAssets: true,
|
|
224975
225286
|
desktopRenderer,
|
|
224976
225287
|
extraEntries: screen2 ? [screen2.entry] : undefined,
|
|
224977
225288
|
entryOverride: screen2?.entryPath
|
|
224978
225289
|
});
|
|
224979
|
-
mkdirSync23(
|
|
225290
|
+
mkdirSync23(dirname16(resolve17(pngFlag)), { recursive: true });
|
|
224980
225291
|
if (scenario) {
|
|
224981
225292
|
const outDir = flagStr(args, "out-dir") ?? ".";
|
|
224982
225293
|
const plan = translateScenario(scenario.steps, { outDir, headroomFrames: frames });
|
|
224983
225294
|
for (const st of plan.steps)
|
|
224984
225295
|
if (st.screenshot)
|
|
224985
|
-
mkdirSync23(
|
|
225296
|
+
mkdirSync23(dirname16(st.screenshot), { recursive: true });
|
|
224986
225297
|
const timeoutMs2 = Number(flagStr(args, "timeout")) || 60000 + plan.steps.length * 5000;
|
|
224987
225298
|
note(`Running ${plan.steps.length} step${plan.steps.length === 1 ? "" : "s"} (native)…`);
|
|
224988
225299
|
const { output } = await runDesktopRender(js, resources, {
|
|
224989
225300
|
renderer: desktopRenderer,
|
|
225301
|
+
pluginDirs,
|
|
224990
225302
|
width,
|
|
224991
225303
|
height,
|
|
224992
225304
|
frames: plan.frameCap,
|
|
@@ -225019,6 +225331,7 @@ var renderDesktop = async (args) => {
|
|
|
225019
225331
|
note(screen2 ? `Rendering ${screen2.label} (native)…` : "Rendering (native)…");
|
|
225020
225332
|
await runDesktopRender(js, resources, {
|
|
225021
225333
|
renderer: desktopRenderer,
|
|
225334
|
+
pluginDirs,
|
|
225022
225335
|
width,
|
|
225023
225336
|
height,
|
|
225024
225337
|
frames,
|
|
@@ -225086,7 +225399,7 @@ var render = async (args) => {
|
|
|
225086
225399
|
const settleStr = flagStr(args, "settle") ?? (scenario?.settle !== undefined ? String(scenario.settle) : undefined);
|
|
225087
225400
|
const timeStr = flagStr(args, "time");
|
|
225088
225401
|
const onConsole = flagBool(args, "logs") ? (level, text2) => logErr(`${c.dim(`[${level}]`)} ${text2}`) : undefined;
|
|
225089
|
-
const envelopeFixtures = resolveFixtures(scenario?.fixtures, scriptFlag !== undefined ?
|
|
225402
|
+
const envelopeFixtures = resolveFixtures(scenario?.fixtures, scriptFlag !== undefined ? dirname16(resolve17(scriptFlag)) : ".");
|
|
225090
225403
|
const flagFixtures = resolveFixtures(flagStr(args, "fixtures"), ".");
|
|
225091
225404
|
const fixtures = envelopeFixtures || flagFixtures ? { ...envelopeFixtures, ...flagFixtures } : undefined;
|
|
225092
225405
|
if (fixtures) {
|
|
@@ -225133,6 +225446,26 @@ var render = async (args) => {
|
|
|
225133
225446
|
session.dispose();
|
|
225134
225447
|
}
|
|
225135
225448
|
}
|
|
225449
|
+
const mapFlag = flagStr(args, "map") ?? (flagBool(args, "map") ? "map.png" : undefined);
|
|
225450
|
+
if (mapFlag !== undefined) {
|
|
225451
|
+
note(`Rendering map…`);
|
|
225452
|
+
const title = root.split(/[\\/]/).pop();
|
|
225453
|
+
const { png: png2, data, warnings: mapWarnings } = await renderer.renderToMap(js, {
|
|
225454
|
+
...timing,
|
|
225455
|
+
maxPx: Number(flagStr(args, "max-px")) || undefined,
|
|
225456
|
+
title,
|
|
225457
|
+
labelAll: flagBool(args, "label-all")
|
|
225458
|
+
});
|
|
225459
|
+
for (const w of [...warnings, ...mapWarnings])
|
|
225460
|
+
warnErr(w);
|
|
225461
|
+
const pngPath = mapFlag.endsWith(".png") ? mapFlag : mapFlag + ".png";
|
|
225462
|
+
mkdirSync23(dirname16(resolve17(pngPath)), { recursive: true });
|
|
225463
|
+
writeFileSync24(resolve17(pngPath), png2);
|
|
225464
|
+
const jsonPath = pngPath.slice(0, -4) + ".json";
|
|
225465
|
+
writeFileSync24(resolve17(jsonPath), JSON.stringify(data, null, 2));
|
|
225466
|
+
note(`Wrote ${pngPath} + ${jsonPath}`);
|
|
225467
|
+
return done((cb) => cb());
|
|
225468
|
+
}
|
|
225136
225469
|
const pngFlag = flagStr(args, "png") ?? (flagBool(args, "png") ? "screenshot.png" : undefined);
|
|
225137
225470
|
if (pngFlag !== undefined) {
|
|
225138
225471
|
note(screen2 ? `Rendering ${screen2.label} (PNG)…` : "Rendering PNG…");
|
|
@@ -225149,7 +225482,7 @@ var render = async (args) => {
|
|
|
225149
225482
|
if (isNullSink(pngFlag)) {
|
|
225150
225483
|
note(`Discarded PNG (${pngFlag})`);
|
|
225151
225484
|
} else {
|
|
225152
|
-
mkdirSync23(
|
|
225485
|
+
mkdirSync23(dirname16(resolve17(pngFlag)), { recursive: true });
|
|
225153
225486
|
writeFileSync24(resolve17(pngFlag), png2);
|
|
225154
225487
|
note(`Wrote ${pngFlag} (${png2.length} bytes, ${outW}x${outH}${clip !== undefined ? ", clipped" : ""})`);
|
|
225155
225488
|
}
|
|
@@ -225180,8 +225513,8 @@ init_api();
|
|
|
225180
225513
|
init_config();
|
|
225181
225514
|
init_manifest();
|
|
225182
225515
|
init_util();
|
|
225183
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
225184
|
-
import { join as
|
|
225516
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync32, readFileSync as readFileSync30, writeFileSync as writeFileSync25 } from "node:fs";
|
|
225517
|
+
import { join as join34 } from "node:path";
|
|
225185
225518
|
var ENV_VAR = "LECODES_PUSH_KEY";
|
|
225186
225519
|
var context = () => {
|
|
225187
225520
|
const root = findProjectRoot(process.cwd());
|
|
@@ -225325,9 +225658,9 @@ var pnKeysList = async (ctx) => {
|
|
|
225325
225658
|
};
|
|
225326
225659
|
var writeEnv = (root, key) => {
|
|
225327
225660
|
const touched = [];
|
|
225328
|
-
const envPath =
|
|
225661
|
+
const envPath = join34(root, ".env");
|
|
225329
225662
|
const line = `${ENV_VAR}=${key}`;
|
|
225330
|
-
const existing =
|
|
225663
|
+
const existing = existsSync32(envPath) ? readFileSync30(envPath, "utf8") : "";
|
|
225331
225664
|
if (new RegExp(`^${ENV_VAR}=`, "m").test(existing)) {
|
|
225332
225665
|
writeFileSync25(envPath, existing.replace(new RegExp(`^${ENV_VAR}=.*$`, "m"), line));
|
|
225333
225666
|
} else {
|
|
@@ -225338,8 +225671,8 @@ var writeEnv = (root, key) => {
|
|
|
225338
225671
|
`);
|
|
225339
225672
|
}
|
|
225340
225673
|
touched.push(".env");
|
|
225341
|
-
const ignorePath =
|
|
225342
|
-
const ignore =
|
|
225674
|
+
const ignorePath = join34(root, ".gitignore");
|
|
225675
|
+
const ignore = existsSync32(ignorePath) ? readFileSync30(ignorePath, "utf8") : "";
|
|
225343
225676
|
if (!ignore.split(`
|
|
225344
225677
|
`).some((l2) => l2.trim() === ".env")) {
|
|
225345
225678
|
const separator = !ignore || ignore.endsWith(`
|
|
@@ -225438,8 +225771,8 @@ var pn = async (args) => {
|
|
|
225438
225771
|
init_api();
|
|
225439
225772
|
init_config();
|
|
225440
225773
|
init_manifest();
|
|
225441
|
-
import { existsSync as
|
|
225442
|
-
import { dirname as
|
|
225774
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync24, rmSync as rmSync11, writeFileSync as writeFileSync26 } from "node:fs";
|
|
225775
|
+
import { dirname as dirname17, join as join35 } from "node:path";
|
|
225443
225776
|
init_types4();
|
|
225444
225777
|
init_localFiles();
|
|
225445
225778
|
init_util();
|
|
@@ -225462,8 +225795,8 @@ var pull = async (args) => {
|
|
|
225462
225795
|
const remotePaths = new Set([...buildPaths(project.assets).entries()].filter(([id]) => project.assets.find((a2) => a2.id === id)?.type !== "folder").map(([, path2]) => path2));
|
|
225463
225796
|
for (const path2 of Object.keys(manifest.files)) {
|
|
225464
225797
|
if (!remotePaths.has(path2)) {
|
|
225465
|
-
const abs =
|
|
225466
|
-
if (
|
|
225798
|
+
const abs = join35(root, ...path2.replace(/^\//, "").split("/"));
|
|
225799
|
+
if (existsSync33(abs))
|
|
225467
225800
|
rmSync11(abs);
|
|
225468
225801
|
}
|
|
225469
225802
|
}
|
|
@@ -225501,8 +225834,8 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
225501
225834
|
const files = { ...manifest.files };
|
|
225502
225835
|
for (const asset of targets) {
|
|
225503
225836
|
const key = pathById.get(asset.id);
|
|
225504
|
-
const abs =
|
|
225505
|
-
mkdirSync24(
|
|
225837
|
+
const abs = join35(root, ...key.replace(/^\//, "").split("/"));
|
|
225838
|
+
mkdirSync24(dirname17(abs), { recursive: true });
|
|
225506
225839
|
let sha;
|
|
225507
225840
|
if (asset.type === "file") {
|
|
225508
225841
|
if (!asset.file?.src)
|
|
@@ -225525,8 +225858,8 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
225525
225858
|
|
|
225526
225859
|
// src/commands/scene.ts
|
|
225527
225860
|
init_manifest();
|
|
225528
|
-
import { existsSync as
|
|
225529
|
-
import { basename as
|
|
225861
|
+
import { existsSync as existsSync35, readFileSync as readFileSync32, readdirSync as readdirSync16, statSync as statSync14, writeFileSync as writeFileSync28 } from "node:fs";
|
|
225862
|
+
import { basename as basename18, dirname as dirname18, join as join37, resolve as resolve18 } from "node:path";
|
|
225530
225863
|
|
|
225531
225864
|
// src/compile/sceneCompile.ts
|
|
225532
225865
|
init_localFiles();
|
|
@@ -225535,18 +225868,18 @@ init_distRoot();
|
|
|
225535
225868
|
init_util();
|
|
225536
225869
|
init_projectCompile();
|
|
225537
225870
|
import { createHash as createHash8 } from "node:crypto";
|
|
225538
|
-
import { existsSync as
|
|
225539
|
-
import { join as
|
|
225871
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync27 } from "node:fs";
|
|
225872
|
+
import { join as join36 } from "node:path";
|
|
225540
225873
|
var TEXT_EXT = /\.(ts|js|json|svg|txt|md)$/i;
|
|
225541
225874
|
var rel = (key) => key.replace(/^\//, "");
|
|
225542
225875
|
var resolveHarness = (loadSceneHarness2) => {
|
|
225543
|
-
const inRepo =
|
|
225876
|
+
const inRepo = join36(distRoot, "..", "projects", "src", "scene-editor");
|
|
225544
225877
|
try {
|
|
225545
|
-
return loadSceneHarness2(
|
|
225878
|
+
return loadSceneHarness2(existsSync34(inRepo) ? inRepo : undefined);
|
|
225546
225879
|
} catch {
|
|
225547
|
-
const vendored =
|
|
225548
|
-
if (
|
|
225549
|
-
return JSON.parse(
|
|
225880
|
+
const vendored = join36(distRoot, "runtime", "scene-harness.json");
|
|
225881
|
+
if (existsSync34(vendored))
|
|
225882
|
+
return JSON.parse(readFileSync31(vendored, "utf8"));
|
|
225550
225883
|
throw new CliError("scene-editor harness sources not found — reinstall the CLI or set LECODES_SCENE_HARNESS_DIR.");
|
|
225551
225884
|
}
|
|
225552
225885
|
};
|
|
@@ -225558,16 +225891,16 @@ var compileSceneEditor = async (opts) => {
|
|
|
225558
225891
|
for (const file of scan2.files) {
|
|
225559
225892
|
const path2 = "./" + rel(file.path);
|
|
225560
225893
|
if (TEXT_EXT.test(path2)) {
|
|
225561
|
-
entries.push({ path: path2, type: "text", text:
|
|
225894
|
+
entries.push({ path: path2, type: "text", text: readFileSync31(file.absPath, "utf8") });
|
|
225562
225895
|
} else if (/\.mat$/i.test(path2)) {
|
|
225563
|
-
entries.push({ path: path2, type: "shader", text:
|
|
225896
|
+
entries.push({ path: path2, type: "shader", text: readFileSync31(file.absPath, "utf8"), absPath: file.absPath });
|
|
225564
225897
|
} else {
|
|
225565
225898
|
entries.push({ path: path2, type: "resource", fileSrc: "/project/" + rel(file.path) });
|
|
225566
225899
|
}
|
|
225567
225900
|
}
|
|
225568
225901
|
const shaderEntries = entries.filter((e2) => e2.type === "shader");
|
|
225569
225902
|
if (shaderEntries.length > 0) {
|
|
225570
|
-
const { warnings } = await applyLocalShaders(shaderEntries, { root, srcPrefix: "/project/.lecodes/shaders", platforms: ["
|
|
225903
|
+
const { warnings } = await applyLocalShaders(shaderEntries, { root, srcPrefix: "/project/.lecodes/shaders", platforms: ["opengl", "webgl-lite"] });
|
|
225571
225904
|
for (const w of warnings)
|
|
225572
225905
|
warnErr(w);
|
|
225573
225906
|
const { buildLiteMaterialArtifact: buildLiteMaterialArtifact2 } = await Promise.resolve().then(() => (init_compile(), exports_compile));
|
|
@@ -225578,10 +225911,10 @@ var compileSceneEditor = async (opts) => {
|
|
|
225578
225911
|
const dir = shadersCacheDir(root);
|
|
225579
225912
|
mkdirSync25(dir, { recursive: true });
|
|
225580
225913
|
const liteName = `${hash}_webgl-lite.filamat`;
|
|
225581
|
-
if (!
|
|
225582
|
-
writeFileSync27(
|
|
225914
|
+
if (!existsSync34(join36(dir, liteName)))
|
|
225915
|
+
writeFileSync27(join36(dir, liteName), JSON.stringify(buildLiteMaterialArtifact2(e2.text ?? "")));
|
|
225583
225916
|
const src = `/project/.lecodes/shaders/${hash}_opengl.filamat`;
|
|
225584
|
-
e2.shaders = ["opengl", "webgl
|
|
225917
|
+
e2.shaders = ["opengl", "webgl-lite"].map((platform) => ({ platform, src }));
|
|
225585
225918
|
}
|
|
225586
225919
|
}
|
|
225587
225920
|
const scene = scenePath.startsWith("./") ? scenePath : "./" + rel(scenePath);
|
|
@@ -225613,14 +225946,21 @@ var DEFAULT_PORT3 = 4488;
|
|
|
225613
225946
|
var findAppRoot = (start) => {
|
|
225614
225947
|
let dir = start;
|
|
225615
225948
|
while (true) {
|
|
225616
|
-
if (
|
|
225949
|
+
if (existsSync35(join37(dir, "app.json")))
|
|
225617
225950
|
return dir;
|
|
225618
|
-
const parent =
|
|
225951
|
+
const parent = dirname18(dir);
|
|
225619
225952
|
if (parent === dir)
|
|
225620
225953
|
return null;
|
|
225621
225954
|
dir = parent;
|
|
225622
225955
|
}
|
|
225623
225956
|
};
|
|
225957
|
+
var projectRootOf = (dir) => {
|
|
225958
|
+
try {
|
|
225959
|
+
return findProjectRoot(dir);
|
|
225960
|
+
} catch {
|
|
225961
|
+
return findAppRoot(dir) ?? dir;
|
|
225962
|
+
}
|
|
225963
|
+
};
|
|
225624
225964
|
var getContext2 = (args) => {
|
|
225625
225965
|
let root;
|
|
225626
225966
|
let manifest;
|
|
@@ -225633,25 +225973,25 @@ var getContext2 = (args) => {
|
|
|
225633
225973
|
const pathArg = args._[0];
|
|
225634
225974
|
if (pathArg) {
|
|
225635
225975
|
const abs = resolve18(process.cwd(), pathArg);
|
|
225636
|
-
if (
|
|
225976
|
+
if (existsSync35(abs) && statSync14(abs).isDirectory())
|
|
225637
225977
|
root = abs;
|
|
225638
|
-
else if (abs.endsWith(".scene.ts") &&
|
|
225639
|
-
root = findAppRoot(
|
|
225978
|
+
else if (abs.endsWith(".scene.ts") && existsSync35(abs))
|
|
225979
|
+
root = findAppRoot(dirname18(abs)) ?? dirname18(abs);
|
|
225640
225980
|
else
|
|
225641
225981
|
throw new CliError(`No such folder or .scene.ts: ${pathArg}`);
|
|
225642
225982
|
} else {
|
|
225643
225983
|
root = findAppRoot(root) ?? root;
|
|
225644
225984
|
}
|
|
225645
225985
|
}
|
|
225646
|
-
return { root, manifest, name: manifest?.name ??
|
|
225986
|
+
return { root, manifest, name: manifest?.name ?? basename18(root) };
|
|
225647
225987
|
};
|
|
225648
225988
|
var writeMcpConfig2 = (root, port) => {
|
|
225649
|
-
const path2 =
|
|
225989
|
+
const path2 = join37(root, ".mcp.json");
|
|
225650
225990
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
225651
225991
|
let config = {};
|
|
225652
|
-
if (
|
|
225992
|
+
if (existsSync35(path2)) {
|
|
225653
225993
|
try {
|
|
225654
|
-
config = JSON.parse(
|
|
225994
|
+
config = JSON.parse(readFileSync32(path2, "utf8"));
|
|
225655
225995
|
} catch {
|
|
225656
225996
|
warnErr(".mcp.json exists but isn't valid JSON — left it untouched. Add the lecodes-scene server by hand.");
|
|
225657
225997
|
return;
|
|
@@ -225670,11 +226010,11 @@ var writeMcpConfig2 = (root, port) => {
|
|
|
225670
226010
|
};
|
|
225671
226011
|
var countScenes = (dir) => {
|
|
225672
226012
|
let n2 = 0;
|
|
225673
|
-
for (const name of
|
|
226013
|
+
for (const name of readdirSync16(dir)) {
|
|
225674
226014
|
if (name === "node_modules" || name.startsWith("."))
|
|
225675
226015
|
continue;
|
|
225676
|
-
const full =
|
|
225677
|
-
if (
|
|
226016
|
+
const full = join37(dir, name);
|
|
226017
|
+
if (statSync14(full).isDirectory())
|
|
225678
226018
|
n2 += countScenes(full);
|
|
225679
226019
|
else if (name.endsWith(".scene.ts"))
|
|
225680
226020
|
n2++;
|
|
@@ -225715,13 +226055,170 @@ var scene = async (args) => {
|
|
|
225715
226055
|
openBrowser(server2.url);
|
|
225716
226056
|
};
|
|
225717
226057
|
|
|
226058
|
+
// src/commands/thumbs.ts
|
|
226059
|
+
import { createRequire as createRequire6 } from "node:module";
|
|
226060
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
226061
|
+
import { existsSync as existsSync36, mkdtempSync as mkdtempSync6, readdirSync as readdirSync17, rmSync as rmSync12, statSync as statSync15 } from "node:fs";
|
|
226062
|
+
import { tmpdir as tmpdir6 } from "node:os";
|
|
226063
|
+
import { extname, join as join38, relative as relative7, resolve as resolve19 } from "node:path";
|
|
226064
|
+
init_util();
|
|
226065
|
+
var DEFAULT_SIZE = 256;
|
|
226066
|
+
var IMAGE_EXT = /\.(png|jpe?g|webp|bmp|gif|tiff?|ktx2)$/i;
|
|
226067
|
+
var RENDERED_EXT = /\.(glb|gltf|material\.ts|scene\.ts)$/i;
|
|
226068
|
+
var findKtx = () => {
|
|
226069
|
+
const exe = process.platform === "win32" ? "ktx.exe" : "ktx";
|
|
226070
|
+
const candidates = [
|
|
226071
|
+
process.env.LECODES_KTX,
|
|
226072
|
+
process.env.KTX_CLI,
|
|
226073
|
+
process.env.KTX_TOKTX?.replace(/toktx(\.exe)?$/i, exe),
|
|
226074
|
+
process.platform === "win32" ? join38(process.env.LOCALAPPDATA ?? "", "Programs", "KTX-Software", "bin", exe) : null,
|
|
226075
|
+
process.platform === "win32" ? join38(process.env.ProgramFiles ?? "", "KTX-Software", "bin", exe) : null,
|
|
226076
|
+
"/usr/local/bin/ktx",
|
|
226077
|
+
"/opt/homebrew/bin/ktx"
|
|
226078
|
+
].filter((p2) => !!p2);
|
|
226079
|
+
for (const path2 of candidates) {
|
|
226080
|
+
if (existsSync36(path2))
|
|
226081
|
+
return path2;
|
|
226082
|
+
}
|
|
226083
|
+
try {
|
|
226084
|
+
execFileSync7(exe, ["--version"], { stdio: "ignore" });
|
|
226085
|
+
return exe;
|
|
226086
|
+
} catch {
|
|
226087
|
+
return null;
|
|
226088
|
+
}
|
|
226089
|
+
};
|
|
226090
|
+
var sharpResizer = () => {
|
|
226091
|
+
try {
|
|
226092
|
+
const req = createRequire6(import.meta.url);
|
|
226093
|
+
const sharp = createRequire6(req.resolve("lecodes-assets/cli"))("sharp");
|
|
226094
|
+
return async (file, size) => sharp(file).resize({ width: size, height: size, fit: "inside", withoutEnlargement: true }).png().toBuffer();
|
|
226095
|
+
} catch {
|
|
226096
|
+
return null;
|
|
226097
|
+
}
|
|
226098
|
+
};
|
|
226099
|
+
var jimpResizer = () => async (file, size) => {
|
|
226100
|
+
const { Jimp: Jimp2 } = await Promise.resolve().then(() => (init_esm30(), exports_esm2));
|
|
226101
|
+
const img = await Jimp2.read(file);
|
|
226102
|
+
if (Math.max(img.width, img.height) > size)
|
|
226103
|
+
img.scaleToFit({ w: size, h: size });
|
|
226104
|
+
return await img.getBuffer("image/png");
|
|
226105
|
+
};
|
|
226106
|
+
var ktxToPng = (ktx, file, out) => {
|
|
226107
|
+
const run2 = (args) => execFileSync7(ktx, args, { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
|
|
226108
|
+
try {
|
|
226109
|
+
run2(["extract", "--transcode", "rgba8", "--level", "0", file, out]);
|
|
226110
|
+
} catch (e2) {
|
|
226111
|
+
run2(["extract", "--level", "0", file, out]);
|
|
226112
|
+
if (!existsSync36(out))
|
|
226113
|
+
throw e2;
|
|
226114
|
+
}
|
|
226115
|
+
};
|
|
226116
|
+
var collect = (dir) => {
|
|
226117
|
+
const out = [];
|
|
226118
|
+
for (const name of readdirSync17(dir)) {
|
|
226119
|
+
if (name === "node_modules" || name.startsWith("."))
|
|
226120
|
+
continue;
|
|
226121
|
+
const full = join38(dir, name);
|
|
226122
|
+
if (statSync15(full).isDirectory())
|
|
226123
|
+
out.push(...collect(full));
|
|
226124
|
+
else if (IMAGE_EXT.test(name))
|
|
226125
|
+
out.push(full);
|
|
226126
|
+
}
|
|
226127
|
+
return out;
|
|
226128
|
+
};
|
|
226129
|
+
var thumbs = async (args) => {
|
|
226130
|
+
const root = projectRootOf(process.cwd());
|
|
226131
|
+
let sceneServer;
|
|
226132
|
+
try {
|
|
226133
|
+
sceneServer = await import("lecodes-3d-editor/server");
|
|
226134
|
+
} catch {
|
|
226135
|
+
throw new CliError("The scene editor isn't installed (it owns the preview cache). Run: npm install -g lecodes-3d-editor");
|
|
226136
|
+
}
|
|
226137
|
+
const size = Number(flagStr(args, "size")) || DEFAULT_SIZE;
|
|
226138
|
+
const force = flagBool(args, "force");
|
|
226139
|
+
let files = [];
|
|
226140
|
+
const rendered = [];
|
|
226141
|
+
if (args._.length > 0) {
|
|
226142
|
+
for (const arg of args._) {
|
|
226143
|
+
const abs = resolve19(process.cwd(), arg);
|
|
226144
|
+
if (!existsSync36(abs))
|
|
226145
|
+
throw new CliError(`No such file or folder: ${arg}`);
|
|
226146
|
+
if (statSync15(abs).isDirectory())
|
|
226147
|
+
files.push(...collect(abs));
|
|
226148
|
+
else if (IMAGE_EXT.test(abs))
|
|
226149
|
+
files.push(abs);
|
|
226150
|
+
else if (RENDERED_EXT.test(abs))
|
|
226151
|
+
rendered.push(arg);
|
|
226152
|
+
else
|
|
226153
|
+
throw new CliError(`Not a previewable asset: ${arg}`);
|
|
226154
|
+
}
|
|
226155
|
+
} else {
|
|
226156
|
+
files = collect(root);
|
|
226157
|
+
}
|
|
226158
|
+
files = [...new Set(files)];
|
|
226159
|
+
if (files.length === 0 && rendered.length === 0) {
|
|
226160
|
+
log("No images to thumbnail.");
|
|
226161
|
+
return;
|
|
226162
|
+
}
|
|
226163
|
+
const ktx = files.some((f3) => f3.toLowerCase().endsWith(".ktx2")) ? findKtx() : null;
|
|
226164
|
+
const sharp = sharpResizer();
|
|
226165
|
+
const resize = sharp ?? jimpResizer();
|
|
226166
|
+
const tmp = mkdtempSync6(join38(tmpdir6(), "lecodes-thumbs-"));
|
|
226167
|
+
let made = 0, fresh = 0;
|
|
226168
|
+
const skipped = [];
|
|
226169
|
+
try {
|
|
226170
|
+
for (const [i2, file] of files.entries()) {
|
|
226171
|
+
const asset = "./" + toKey(relative7(root, file));
|
|
226172
|
+
progress(i2, files.length, asset);
|
|
226173
|
+
const hash = sceneServer.hashAsset(root, asset);
|
|
226174
|
+
if (!hash)
|
|
226175
|
+
continue;
|
|
226176
|
+
if (!force && sceneServer.previewIsCurrent(root, asset, hash)) {
|
|
226177
|
+
fresh++;
|
|
226178
|
+
continue;
|
|
226179
|
+
}
|
|
226180
|
+
const ext2 = extname(file).toLowerCase();
|
|
226181
|
+
if (ext2 === ".webp" && !sharp) {
|
|
226182
|
+
skipped.push(`${asset} (webp needs sharp — npm install -g lecodes-assets)`);
|
|
226183
|
+
continue;
|
|
226184
|
+
}
|
|
226185
|
+
try {
|
|
226186
|
+
let source = file;
|
|
226187
|
+
if (ext2 === ".ktx2") {
|
|
226188
|
+
if (!ktx) {
|
|
226189
|
+
skipped.push(`${asset} (KTX2 needs KTX-Software's \`ktx\` — set LECODES_KTX or put it on PATH)`);
|
|
226190
|
+
continue;
|
|
226191
|
+
}
|
|
226192
|
+
source = join38(tmp, `${i2}.png`);
|
|
226193
|
+
ktxToPng(ktx, file, source);
|
|
226194
|
+
}
|
|
226195
|
+
sceneServer.writePreviewFile(root, asset, await resize(source, size));
|
|
226196
|
+
made++;
|
|
226197
|
+
} catch (e2) {
|
|
226198
|
+
skipped.push(`${asset} (${(e2?.message ?? String(e2)).split(`
|
|
226199
|
+
`)[0]})`);
|
|
226200
|
+
}
|
|
226201
|
+
}
|
|
226202
|
+
} finally {
|
|
226203
|
+
endProgress();
|
|
226204
|
+
rmSync12(tmp, { recursive: true, force: true });
|
|
226205
|
+
}
|
|
226206
|
+
log(`${c.bold(String(made))} generated · ${fresh} already current${skipped.length > 0 ? ` · ${skipped.length} skipped` : ""}`);
|
|
226207
|
+
for (const s2 of skipped)
|
|
226208
|
+
warnErr(s2);
|
|
226209
|
+
if (rendered.length > 0) {
|
|
226210
|
+
warnErr(`Models, materials and prefabs are RENDERED, not decoded — the scene editor does those: ${rendered.join(", ")}`);
|
|
226211
|
+
}
|
|
226212
|
+
note(`Cache: ${join38(root, ".lecodes", "preview")} (re-runs skip everything unchanged)`);
|
|
226213
|
+
};
|
|
226214
|
+
|
|
225718
226215
|
// src/commands/assets.ts
|
|
225719
226216
|
init_util();
|
|
225720
226217
|
|
|
225721
226218
|
// src/cmgenTool.ts
|
|
225722
|
-
import { existsSync as
|
|
226219
|
+
import { existsSync as existsSync37, readdirSync as readdirSync18 } from "node:fs";
|
|
225723
226220
|
import { homedir as homedir8 } from "node:os";
|
|
225724
|
-
import { join as
|
|
226221
|
+
import { join as join39, resolve as resolve20 } from "node:path";
|
|
225725
226222
|
init_util();
|
|
225726
226223
|
var exeName2 = () => process.platform === "win32" ? "cmgen.exe" : "cmgen";
|
|
225727
226224
|
var platformKey3 = () => {
|
|
@@ -225731,10 +226228,10 @@ var platformKey3 = () => {
|
|
|
225731
226228
|
return "linux-x64";
|
|
225732
226229
|
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
226230
|
};
|
|
225734
|
-
var cacheRoot3 = () =>
|
|
226231
|
+
var cacheRoot3 = () => join39(homedir8(), ".lecodes", "cmgen");
|
|
225735
226232
|
var findCmgenIn = (dir) => {
|
|
225736
|
-
for (const entry of
|
|
225737
|
-
const p2 =
|
|
226233
|
+
for (const entry of readdirSync18(dir, { withFileTypes: true })) {
|
|
226234
|
+
const p2 = join39(dir, entry.name);
|
|
225738
226235
|
if (entry.isFile() && entry.name === exeName2())
|
|
225739
226236
|
return p2;
|
|
225740
226237
|
if (entry.isDirectory()) {
|
|
@@ -225747,7 +226244,7 @@ var findCmgenIn = (dir) => {
|
|
|
225747
226244
|
};
|
|
225748
226245
|
var installedCmgenVersions = () => {
|
|
225749
226246
|
try {
|
|
225750
|
-
return
|
|
226247
|
+
return readdirSync18(cacheRoot3(), { withFileTypes: true }).filter((e2) => e2.isDirectory() && e2.name.startsWith("cmgen-")).map((e2) => e2.name.slice("cmgen-".length)).filter((v) => findCmgenIn(join39(cacheRoot3(), `cmgen-${v}`)) !== null).sort(semverNewer);
|
|
225751
226248
|
} catch {
|
|
225752
226249
|
return [];
|
|
225753
226250
|
}
|
|
@@ -225769,19 +226266,19 @@ var downloadCmgen = async (version, versions, dest) => {
|
|
|
225769
226266
|
var resolveCmgenExeCached = () => {
|
|
225770
226267
|
const override = process.env.LECODES_CMGEN;
|
|
225771
226268
|
if (override) {
|
|
225772
|
-
if (!
|
|
226269
|
+
if (!existsSync37(override))
|
|
225773
226270
|
throw new CliError(`LECODES_CMGEN points at "${override}" which doesn't exist.`);
|
|
225774
|
-
return
|
|
226271
|
+
return resolve20(override);
|
|
225775
226272
|
}
|
|
225776
226273
|
const cached = installedCmgenVersions()[0];
|
|
225777
|
-
return cached ? findCmgenIn(
|
|
226274
|
+
return cached ? findCmgenIn(join39(cacheRoot3(), `cmgen-${cached}`)) : null;
|
|
225778
226275
|
};
|
|
225779
226276
|
var resolveCmgenExe = async () => {
|
|
225780
226277
|
const cached = resolveCmgenExeCached();
|
|
225781
226278
|
if (cached)
|
|
225782
226279
|
return cached;
|
|
225783
226280
|
const { latest, versions } = await fetchCmgenManifest();
|
|
225784
|
-
const dir =
|
|
226281
|
+
const dir = join39(cacheRoot3(), `cmgen-${latest}`);
|
|
225785
226282
|
await downloadCmgen(latest, versions, dir);
|
|
225786
226283
|
const exe = findCmgenIn(dir);
|
|
225787
226284
|
if (!exe)
|
|
@@ -225839,8 +226336,8 @@ var status3 = async (_args) => {
|
|
|
225839
226336
|
};
|
|
225840
226337
|
|
|
225841
226338
|
// src/commands/test.ts
|
|
225842
|
-
import { existsSync as
|
|
225843
|
-
import { dirname as
|
|
226339
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as readFileSync33, readdirSync as readdirSync19 } from "node:fs";
|
|
226340
|
+
import { dirname as dirname19, resolve as resolve21 } from "node:path";
|
|
225844
226341
|
init_manifest();
|
|
225845
226342
|
init_util();
|
|
225846
226343
|
var deriveDesignFlows = (meta, entryScreen) => {
|
|
@@ -225903,7 +226400,7 @@ var slug3 = (s2) => s2.replace(/[^a-zA-Z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").
|
|
|
225903
226400
|
var readFlowFile = (abs, displayName) => {
|
|
225904
226401
|
let raw;
|
|
225905
226402
|
try {
|
|
225906
|
-
raw = JSON.parse(
|
|
226403
|
+
raw = JSON.parse(readFileSync33(abs, "utf8"));
|
|
225907
226404
|
} catch (e2) {
|
|
225908
226405
|
throw new CliError(`Can't read "${displayName}": ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
225909
226406
|
}
|
|
@@ -225917,7 +226414,7 @@ var readFlowFile = (abs, displayName) => {
|
|
|
225917
226414
|
name: file.name ?? displayName,
|
|
225918
226415
|
kind: "file",
|
|
225919
226416
|
steps: file.steps,
|
|
225920
|
-
fixtures: resolveFixtures(file.fixtures,
|
|
226417
|
+
fixtures: resolveFixtures(file.fixtures, dirname19(abs)),
|
|
225921
226418
|
width: file.width,
|
|
225922
226419
|
height: file.height,
|
|
225923
226420
|
settle: file.settle,
|
|
@@ -225958,40 +226455,40 @@ var test = async (args) => {
|
|
|
225958
226455
|
if (!Number.isFinite(nativeFixedDt) || nativeFixedDt < 0 || nativeFixedDt > 1000)
|
|
225959
226456
|
throw new CliError(`--fixed-dt wants a number of ms (0 = wall clock, max 1000), got "${fixedDtFlag}".`);
|
|
225960
226457
|
const projectViewport = desktopDefaultViewport(root);
|
|
225961
|
-
const testsDir =
|
|
225962
|
-
const designMetaPath =
|
|
226458
|
+
const testsDir = resolve21(root, flagStr(args, "dir") ?? "tests");
|
|
226459
|
+
const designMetaPath = resolve21(root, flagStr(args, "design-dir") ?? "design", "meta.json");
|
|
225963
226460
|
const asJson = flagBool(args, "json");
|
|
225964
226461
|
const out = asJson ? logErr : log;
|
|
225965
226462
|
const cases = [];
|
|
225966
226463
|
if (args._.length > 0) {
|
|
225967
226464
|
for (const given of args._) {
|
|
225968
|
-
const candidates = [
|
|
225969
|
-
const abs = candidates.find((p2) =>
|
|
226465
|
+
const candidates = [resolve21(given), resolve21(testsDir, given), resolve21(testsDir, `${given}.flow.json`)];
|
|
226466
|
+
const abs = candidates.find((p2) => existsSync38(p2));
|
|
225970
226467
|
if (!abs)
|
|
225971
226468
|
throw new CliError(`No such test: "${given}" (looked in ${testsDir}).`);
|
|
225972
226469
|
cases.push(readFlowFile(abs, given));
|
|
225973
226470
|
}
|
|
225974
|
-
} else if (
|
|
225975
|
-
for (const f3 of
|
|
225976
|
-
cases.push(readFlowFile(
|
|
226471
|
+
} else if (existsSync38(testsDir)) {
|
|
226472
|
+
for (const f3 of readdirSync19(testsDir).filter((f4) => f4.endsWith(".flow.json")).sort()) {
|
|
226473
|
+
cases.push(readFlowFile(resolve21(testsDir, f3), f3));
|
|
225977
226474
|
}
|
|
225978
226475
|
}
|
|
225979
226476
|
const fixturesFlag = flagStr(args, "fixtures");
|
|
225980
|
-
const defaultPack =
|
|
225981
|
-
const flowFixtures = fixturesFlag !== undefined ? resolveFixtures(fixturesFlag, ".") :
|
|
226477
|
+
const defaultPack = resolve21(testsDir, "fixtures.json");
|
|
226478
|
+
const flowFixtures = fixturesFlag !== undefined ? resolveFixtures(fixturesFlag, ".") : existsSync38(defaultPack) ? resolveFixtures("fixtures.json", testsDir) : undefined;
|
|
225982
226479
|
const flowsOnly = flagBool(args, "flows");
|
|
225983
226480
|
const wantFlows = !flagBool(args, "no-flows") && args._.length === 0;
|
|
225984
226481
|
if (flowsOnly)
|
|
225985
226482
|
cases.length = 0;
|
|
225986
226483
|
let skipped = [];
|
|
225987
226484
|
let entryScreen = null;
|
|
225988
|
-
if (desktop2 && wantFlows &&
|
|
226485
|
+
if (desktop2 && wantFlows && existsSync38(designMetaPath)) {
|
|
225989
226486
|
note("Design-derived flows skipped with --desktop (they tap by name; run `lecodes test` headless for them).");
|
|
225990
226487
|
}
|
|
225991
|
-
if (!desktop2 && (wantFlows || flowsOnly) &&
|
|
226488
|
+
if (!desktop2 && (wantFlows || flowsOnly) && existsSync38(designMetaPath)) {
|
|
225992
226489
|
let meta;
|
|
225993
226490
|
try {
|
|
225994
|
-
meta = JSON.parse(
|
|
226491
|
+
meta = JSON.parse(readFileSync33(designMetaPath, "utf8"));
|
|
225995
226492
|
} catch (e2) {
|
|
225996
226493
|
throw new CliError(`Can't read ${designMetaPath}: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
225997
226494
|
}
|
|
@@ -226023,18 +226520,19 @@ var test = async (args) => {
|
|
|
226023
226520
|
}, timeoutMs);
|
|
226024
226521
|
killer.unref?.();
|
|
226025
226522
|
const onConsole = flagBool(args, "logs") ? (level, text) => logErr(`${c.dim(`[${level}]`)} ${text}`) : undefined;
|
|
226026
|
-
const artifactsRoot =
|
|
226523
|
+
const artifactsRoot = resolve21(root, flagStr(args, "artifacts") ?? resolve21(testsDir, ".artifacts"));
|
|
226027
226524
|
const results = [];
|
|
226028
226525
|
const runNativeCase = async (kase) => {
|
|
226029
|
-
const caseDir =
|
|
226526
|
+
const caseDir = resolve21(artifactsRoot, slug3(kase.name));
|
|
226030
226527
|
const plan = translateScenario(kase.steps, { outDir: caseDir, headroomFrames: nativeFrames });
|
|
226031
226528
|
for (const st of plan.steps)
|
|
226032
226529
|
if (st.screenshot)
|
|
226033
|
-
mkdirSync26(
|
|
226530
|
+
mkdirSync26(dirname19(st.screenshot), { recursive: true });
|
|
226034
226531
|
mkdirSync26(caseDir, { recursive: true });
|
|
226035
|
-
const finalPng =
|
|
226532
|
+
const finalPng = resolve21(caseDir, "final.png");
|
|
226036
226533
|
const { output } = await runDesktopRender(native.js, native.resources, {
|
|
226037
226534
|
renderer: desktopRenderer,
|
|
226535
|
+
pluginDirs: desktopPluginLibraries(root).dirs,
|
|
226038
226536
|
width: Number(flagStr(args, "width")) || kase.width || projectViewport?.width || 390,
|
|
226039
226537
|
height: Number(flagStr(args, "height")) || kase.height || projectViewport?.height || 844,
|
|
226040
226538
|
frames: plan.frameCap,
|
|
@@ -226084,14 +226582,14 @@ var test = async (args) => {
|
|
|
226084
226582
|
onConsole
|
|
226085
226583
|
});
|
|
226086
226584
|
try {
|
|
226087
|
-
const io = fileScenarioIO(
|
|
226585
|
+
const io = fileScenarioIO(resolve21(artifactsRoot, slug3(kase.name)));
|
|
226088
226586
|
const outcome = await renderer.runScenario(session, steps, io);
|
|
226089
226587
|
result = {
|
|
226090
226588
|
name: kase.name,
|
|
226091
226589
|
kind: kase.kind,
|
|
226092
226590
|
ok: outcome.ok,
|
|
226093
226591
|
steps: outcome.steps.map((s2) => ({ desc: s2.desc, ok: s2.ok, error: s2.error })),
|
|
226094
|
-
artifacts: outcome.failureArtifacts.map((p2) =>
|
|
226592
|
+
artifacts: outcome.failureArtifacts.map((p2) => resolve21(artifactsRoot, slug3(kase.name), p2))
|
|
226095
226593
|
};
|
|
226096
226594
|
} finally {
|
|
226097
226595
|
session.dispose();
|
|
@@ -226153,17 +226651,54 @@ var test = async (args) => {
|
|
|
226153
226651
|
process.exit(failed > 0 ? 1 : 0);
|
|
226154
226652
|
};
|
|
226155
226653
|
|
|
226654
|
+
// src/commands/update.ts
|
|
226655
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
226656
|
+
import { existsSync as existsSync40, readdirSync as readdirSync20 } from "node:fs";
|
|
226657
|
+
import { homedir as homedir9 } from "node:os";
|
|
226658
|
+
import { dirname as dirname21, join as join41, resolve as resolve23 } from "node:path";
|
|
226659
|
+
init_util();
|
|
226660
|
+
|
|
226661
|
+
// src/peers.ts
|
|
226662
|
+
import { existsSync as existsSync39, readFileSync as readFileSync34 } from "node:fs";
|
|
226663
|
+
import { createRequire as createRequire7 } from "node:module";
|
|
226664
|
+
import { dirname as dirname20, join as join40 } from "node:path";
|
|
226665
|
+
var OPTIONAL_PEERS = [
|
|
226666
|
+
["lecodes-renderer", "lecodes-renderer/headless"],
|
|
226667
|
+
["lecodes-design", "lecodes-design/server"],
|
|
226668
|
+
["lecodes-3d-editor", "lecodes-3d-editor/server"],
|
|
226669
|
+
["lecodes-assets", "lecodes-assets/cli"]
|
|
226670
|
+
];
|
|
226671
|
+
var peerVersion = (name, probe) => {
|
|
226672
|
+
try {
|
|
226673
|
+
const require2 = createRequire7(import.meta.url);
|
|
226674
|
+
let dir = dirname20(require2.resolve(probe));
|
|
226675
|
+
for (let depth = 0;depth < 16; depth++) {
|
|
226676
|
+
const manifest = join40(dir, "package.json");
|
|
226677
|
+
if (existsSync39(manifest)) {
|
|
226678
|
+
const parsed = JSON.parse(readFileSync34(manifest, "utf8"));
|
|
226679
|
+
if (parsed.name === name)
|
|
226680
|
+
return parsed.version ?? "unknown";
|
|
226681
|
+
}
|
|
226682
|
+
const parent = dirname20(dir);
|
|
226683
|
+
if (parent === dir)
|
|
226684
|
+
break;
|
|
226685
|
+
dir = parent;
|
|
226686
|
+
}
|
|
226687
|
+
} catch {}
|
|
226688
|
+
return null;
|
|
226689
|
+
};
|
|
226690
|
+
|
|
226156
226691
|
// src/commands/types.ts
|
|
226157
226692
|
init_api();
|
|
226158
226693
|
init_config();
|
|
226159
226694
|
init_manifest();
|
|
226160
226695
|
init_types4();
|
|
226161
226696
|
init_util();
|
|
226162
|
-
import { resolve as
|
|
226697
|
+
import { resolve as resolve22 } from "node:path";
|
|
226163
226698
|
var label = (bundle) => `${Object.keys(bundle).length} file(s)`;
|
|
226164
226699
|
var types4 = async (args) => {
|
|
226165
226700
|
const dirArg = args._[0];
|
|
226166
|
-
const root = dirArg ?
|
|
226701
|
+
const root = dirArg ? resolve22(dirArg) : (() => {
|
|
226167
226702
|
try {
|
|
226168
226703
|
return findProjectRoot(process.cwd());
|
|
226169
226704
|
} catch {
|
|
@@ -226198,9 +226733,9 @@ var types4 = async (args) => {
|
|
|
226198
226733
|
const same = bundleHash(onDisk) === bundleHash(bundle);
|
|
226199
226734
|
if (checkOnly) {
|
|
226200
226735
|
if (Object.keys(onDisk).length === 0)
|
|
226201
|
-
throw new CliError(`No types in ${LECODES_DIR}/types/ — run \`lecodes
|
|
226736
|
+
throw new CliError(`No types in ${LECODES_DIR}/types/ — run \`lecodes update\`.`);
|
|
226202
226737
|
if (!same)
|
|
226203
|
-
throw new CliError(`Types are out of date (${label(onDisk)} on disk) — run \`lecodes
|
|
226738
|
+
throw new CliError(`Types are out of date (${label(onDisk)} on disk) — run \`lecodes update\`.`);
|
|
226204
226739
|
success(`Types are up to date (${label(onDisk)}).`);
|
|
226205
226740
|
return;
|
|
226206
226741
|
}
|
|
@@ -226221,29 +226756,166 @@ var types4 = async (args) => {
|
|
|
226221
226756
|
note("Reload the TypeScript server in your editor to pick them up.");
|
|
226222
226757
|
};
|
|
226223
226758
|
|
|
226759
|
+
// src/commands/update.ts
|
|
226760
|
+
var findProjectDir = (start) => {
|
|
226761
|
+
const home = resolve23(homedir9());
|
|
226762
|
+
let dir = resolve23(start);
|
|
226763
|
+
while (true) {
|
|
226764
|
+
if (dir !== home && (existsSync40(join41(dir, "app.json")) || existsSync40(join41(dir, ".lecodes", "manifest.json")) || existsSync40(join41(dir, ".lecodes", "types"))))
|
|
226765
|
+
return dir;
|
|
226766
|
+
const parent = dirname21(dir);
|
|
226767
|
+
if (parent === dir)
|
|
226768
|
+
return null;
|
|
226769
|
+
dir = parent;
|
|
226770
|
+
}
|
|
226771
|
+
};
|
|
226772
|
+
var NPM = "https://registry.npmjs.org";
|
|
226773
|
+
var npmLatest = async (name) => {
|
|
226774
|
+
try {
|
|
226775
|
+
const res = await fetch(`${NPM}/${name}/latest`, { signal: AbortSignal.timeout(4000) });
|
|
226776
|
+
if (!res.ok)
|
|
226777
|
+
return null;
|
|
226778
|
+
const json = await res.json();
|
|
226779
|
+
return json.version ?? null;
|
|
226780
|
+
} catch {
|
|
226781
|
+
return null;
|
|
226782
|
+
}
|
|
226783
|
+
};
|
|
226784
|
+
var semverNewer2 = (a2, b) => {
|
|
226785
|
+
const pa = a2.split(/[.-]/).map(Number), pb = b.split(/[.-]/).map(Number);
|
|
226786
|
+
for (let i2 = 0;i2 < 3; i2++) {
|
|
226787
|
+
const d = (pa[i2] ?? 0) - (pb[i2] ?? 0);
|
|
226788
|
+
if (d)
|
|
226789
|
+
return d;
|
|
226790
|
+
}
|
|
226791
|
+
return 0;
|
|
226792
|
+
};
|
|
226793
|
+
var FROM_SOURCE = /[\\/]src[\\/]commands[\\/]/.test(import.meta.url);
|
|
226794
|
+
var STANDALONE = existsSync40(join41(dirname21(process.execPath), "runtime")) && existsSync40(join41(dirname21(process.execPath), process.platform === "win32" ? "chisel.exe" : "chisel"));
|
|
226795
|
+
var update = async (args) => {
|
|
226796
|
+
const steps = [];
|
|
226797
|
+
const heading = (name, what) => log(`
|
|
226798
|
+
${c.bold(name)} ${c.dim(what)}`);
|
|
226799
|
+
const run2 = async (name, what, fn) => {
|
|
226800
|
+
heading(name, what);
|
|
226801
|
+
try {
|
|
226802
|
+
const r2 = await fn();
|
|
226803
|
+
const [outcome, detail] = Array.isArray(r2) ? r2 : [r2, undefined];
|
|
226804
|
+
steps.push({ name, outcome, detail });
|
|
226805
|
+
if (outcome === "skipped" && detail)
|
|
226806
|
+
note(`skipped — ${detail}`);
|
|
226807
|
+
} catch (e2) {
|
|
226808
|
+
const msg = e2 instanceof CliError ? e2.message : e2 instanceof Error ? e2.message : String(e2);
|
|
226809
|
+
log(c.red("✗ ") + msg);
|
|
226810
|
+
steps.push({ name, outcome: "failed", detail: msg });
|
|
226811
|
+
}
|
|
226812
|
+
};
|
|
226813
|
+
const root = findProjectDir(process.cwd());
|
|
226814
|
+
await run2("desktop", "LeCodes Desktop host (desktop run / render --desktop)", async () => {
|
|
226815
|
+
if (process.env.LECODES_DESKTOP_EXE)
|
|
226816
|
+
return ["skipped", `LECODES_DESKTOP_EXE=${process.env.LECODES_DESKTOP_EXE} (a local build; \`lecodes desktop update\` refreshes the cache anyway)`];
|
|
226817
|
+
await updateDesktop();
|
|
226818
|
+
return "ok";
|
|
226819
|
+
});
|
|
226820
|
+
await run2("matc", "Filament material compiler for local shader compiles", async () => {
|
|
226821
|
+
if (process.env.LECODES_MATC)
|
|
226822
|
+
return ["skipped", `LECODES_MATC=${process.env.LECODES_MATC} (a local matc)`];
|
|
226823
|
+
await updateMatc();
|
|
226824
|
+
return "ok";
|
|
226825
|
+
});
|
|
226826
|
+
await run2("shaders", "recompile the project's .mat shaders with the current matc", async () => {
|
|
226827
|
+
if (!root)
|
|
226828
|
+
return ["skipped", "not inside a project"];
|
|
226829
|
+
await shaders({ _: ["compile"], flags: {} });
|
|
226830
|
+
return "ok";
|
|
226831
|
+
});
|
|
226832
|
+
await run2("types", flagBool(args, "local") ? "IDE types from the SDK bundled in this CLI" : "IDE types from the server", async () => {
|
|
226833
|
+
if (!root)
|
|
226834
|
+
return ["skipped", "not inside a project"];
|
|
226835
|
+
await types4({ _: [], flags: flagBool(args, "local") ? { local: true } : {} });
|
|
226836
|
+
return "ok";
|
|
226837
|
+
});
|
|
226838
|
+
await run2("shells", "ios/ + android/ pins → newest SDK release + plugin tags, then re-sync", async () => {
|
|
226839
|
+
if (!root)
|
|
226840
|
+
return ["skipped", "not inside a project"];
|
|
226841
|
+
if (flagBool(args, "no-shells"))
|
|
226842
|
+
return ["skipped", "--no-shells"];
|
|
226843
|
+
const present = ["ios", "android"].filter((d) => existsSync40(join41(root, d)) && readdirSync20(join41(root, d)).length > 0);
|
|
226844
|
+
if (present.length === 0)
|
|
226845
|
+
return ["skipped", "no ios/ or android/ shell in this project (`lecodes app init ios|android`)"];
|
|
226846
|
+
await app({ _: ["update"], flags: {} });
|
|
226847
|
+
return "ok";
|
|
226848
|
+
});
|
|
226849
|
+
await run2("cli", "lecodes-cli + its optional peers (global npm installs)", async () => {
|
|
226850
|
+
if (flagBool(args, "no-cli"))
|
|
226851
|
+
return ["skipped", "--no-cli"];
|
|
226852
|
+
if (FROM_SOURCE)
|
|
226853
|
+
return ["skipped", "running from the repo checkout — the CLI and its peers are the repo's own"];
|
|
226854
|
+
const rows = [];
|
|
226855
|
+
for (const [name, probe] of OPTIONAL_PEERS) {
|
|
226856
|
+
const installed = peerVersion(name, probe);
|
|
226857
|
+
rows.push({ name, installed, latest: installed ? await npmLatest(name) : null });
|
|
226858
|
+
}
|
|
226859
|
+
rows.push({ name: "lecodes-cli", installed: package_default.version, latest: await npmLatest("lecodes-cli") });
|
|
226860
|
+
if (rows.every((r3) => r3.latest === null))
|
|
226861
|
+
return ["skipped", "npm unreachable"];
|
|
226862
|
+
const behind = rows.filter((r3) => r3.installed && r3.latest && semverNewer2(r3.latest, r3.installed) > 0);
|
|
226863
|
+
for (const r3 of rows) {
|
|
226864
|
+
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)");
|
|
226865
|
+
log(" " + r3.name.padEnd(18) + " " + (r3.installed ?? "").padEnd(8) + " " + state);
|
|
226866
|
+
}
|
|
226867
|
+
if (behind.length === 0)
|
|
226868
|
+
return "ok";
|
|
226869
|
+
const specs = behind.map((r3) => r3.name + "@latest");
|
|
226870
|
+
if (flagBool(args, "check"))
|
|
226871
|
+
return ["updated", behind.length + " behind — run: npm install -g " + specs.join(" ")];
|
|
226872
|
+
if (STANDALONE && behind.some((r3) => r3.name === "lecodes-cli")) {
|
|
226873
|
+
note("this is the standalone build — the CLI updates by re-installing the release archive, not through npm; peers still go through npm");
|
|
226874
|
+
}
|
|
226875
|
+
const toInstall = STANDALONE ? specs.filter((s2) => !s2.startsWith("lecodes-cli@")) : specs;
|
|
226876
|
+
if (toInstall.length === 0)
|
|
226877
|
+
return ["skipped", "only the standalone CLI itself is behind — download the release"];
|
|
226878
|
+
log(" " + c.dim("$") + " npm install -g " + toInstall.join(" "));
|
|
226879
|
+
const r2 = spawnSync7("npm", ["install", "-g", ...toInstall], { stdio: "inherit", shell: true });
|
|
226880
|
+
if (r2.status !== 0)
|
|
226881
|
+
throw new CliError("npm install -g exited with " + (r2.status ?? "a signal"));
|
|
226882
|
+
const names3 = toInstall.map((s2) => s2.replace("@latest", "")).join(", ");
|
|
226883
|
+
const cliToo = toInstall.some((s2) => s2.startsWith("lecodes-cli@"));
|
|
226884
|
+
return ["updated", names3 + " → latest" + (cliToo ? " (the new CLI runs from your next command)" : "")];
|
|
226885
|
+
});
|
|
226886
|
+
log(`
|
|
226887
|
+
${c.bold("Summary")}`);
|
|
226888
|
+
const width = Math.max(...steps.map((s2) => s2.name.length));
|
|
226889
|
+
for (const s2 of steps) {
|
|
226890
|
+
const mark = s2.outcome === "failed" ? c.red("✗") : s2.outcome === "skipped" ? c.dim("–") : c.green("✓");
|
|
226891
|
+
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}`);
|
|
226892
|
+
}
|
|
226893
|
+
if (steps.some((s2) => s2.outcome === "failed"))
|
|
226894
|
+
process.exitCode = 1;
|
|
226895
|
+
};
|
|
226896
|
+
|
|
226224
226897
|
// src/index.ts
|
|
226225
|
-
import { existsSync as
|
|
226226
|
-
import {
|
|
226227
|
-
import { delimiter as delimiter2, dirname as dirname21, join as join40 } from "node:path";
|
|
226898
|
+
import { existsSync as existsSync43, realpathSync as realpathSync2 } from "node:fs";
|
|
226899
|
+
import { delimiter as delimiter3, dirname as dirname24, join as join44 } from "node:path";
|
|
226228
226900
|
|
|
226229
226901
|
// src/commands/install.ts
|
|
226230
226902
|
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
|
|
226903
|
+
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
226904
|
+
import { appendFileSync as appendFileSync3, chmodSync as chmodSync2, cpSync as cpSync5, existsSync as existsSync41, mkdirSync as mkdirSync27, readFileSync as readFileSync35, realpathSync, rmSync as rmSync13, symlinkSync as symlinkSync2 } from "node:fs";
|
|
226905
|
+
import { homedir as homedir10 } from "node:os";
|
|
226906
|
+
import { basename as basename19, delimiter as delimiter2, dirname as dirname22, join as join42, resolve as resolve24, sep as sep2 } from "node:path";
|
|
226235
226907
|
var isWin = process.platform === "win32";
|
|
226236
|
-
var HOME =
|
|
226908
|
+
var HOME = homedir10();
|
|
226237
226909
|
var safeRealpath = (p2) => {
|
|
226238
226910
|
try {
|
|
226239
226911
|
return realpathSync(p2);
|
|
226240
226912
|
} catch {
|
|
226241
|
-
return
|
|
226913
|
+
return resolve24(p2);
|
|
226242
226914
|
}
|
|
226243
226915
|
};
|
|
226244
226916
|
var onPath = (dir) => {
|
|
226245
226917
|
const want = safeRealpath(dir);
|
|
226246
|
-
return (process.env.PATH ?? "").split(
|
|
226918
|
+
return (process.env.PATH ?? "").split(delimiter2).some((p2) => {
|
|
226247
226919
|
if (!p2)
|
|
226248
226920
|
return false;
|
|
226249
226921
|
try {
|
|
@@ -226254,13 +226926,13 @@ var onPath = (dir) => {
|
|
|
226254
226926
|
});
|
|
226255
226927
|
};
|
|
226256
226928
|
var install = async (args) => {
|
|
226257
|
-
const bundle =
|
|
226258
|
-
const exeName3 =
|
|
226929
|
+
const bundle = dirname22(process.execPath);
|
|
226930
|
+
const exeName3 = basename19(process.execPath);
|
|
226259
226931
|
const chiselName = isWin ? "chisel.exe" : "chisel";
|
|
226260
|
-
if (!
|
|
226932
|
+
if (!existsSync41(join42(bundle, "runtime")) || !existsSync41(join42(bundle, chiselName))) {
|
|
226261
226933
|
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
226934
|
}
|
|
226263
|
-
const companions = [exeName3, chiselName, "runtime", "README.txt"].filter((f3) =>
|
|
226935
|
+
const companions = [exeName3, chiselName, "runtime", "README.txt"].filter((f3) => existsSync41(join42(bundle, f3)));
|
|
226264
226936
|
if (isWin)
|
|
226265
226937
|
return installWindows(args, bundle, companions);
|
|
226266
226938
|
return installUnix(args, bundle, companions);
|
|
@@ -226270,9 +226942,9 @@ var copyBundle = (bundle, target, companions) => {
|
|
|
226270
226942
|
if (safeRealpath(target) === safeRealpath(bundle))
|
|
226271
226943
|
return;
|
|
226272
226944
|
for (const f3 of companions) {
|
|
226273
|
-
const dest =
|
|
226274
|
-
|
|
226275
|
-
cpSync5(
|
|
226945
|
+
const dest = join42(target, f3);
|
|
226946
|
+
rmSync13(dest, { recursive: true, force: true });
|
|
226947
|
+
cpSync5(join42(bundle, f3), dest, { recursive: true });
|
|
226276
226948
|
}
|
|
226277
226949
|
};
|
|
226278
226950
|
var permError = (e2, dir, system) => {
|
|
@@ -226284,41 +226956,41 @@ var permError = (e2, dir, system) => {
|
|
|
226284
226956
|
};
|
|
226285
226957
|
var installUnix = (args, bundle, companions) => {
|
|
226286
226958
|
const system = flagBool(args, "system");
|
|
226287
|
-
const libDir =
|
|
226288
|
-
const binDir =
|
|
226289
|
-
const link2 =
|
|
226959
|
+
const libDir = resolve24(flagStr(args, "dir") ?? (system ? "/usr/local/lib/lecodes-cli" : join42(HOME, ".local", "lib", "lecodes-cli")));
|
|
226960
|
+
const binDir = resolve24(flagStr(args, "bin") ?? (system ? "/usr/local/bin" : join42(HOME, ".local", "bin")));
|
|
226961
|
+
const link2 = join42(binDir, "lecodes");
|
|
226290
226962
|
try {
|
|
226291
226963
|
copyBundle(bundle, libDir, companions);
|
|
226292
|
-
chmodSync2(
|
|
226293
|
-
chmodSync2(
|
|
226964
|
+
chmodSync2(join42(libDir, "lecodes"), 493);
|
|
226965
|
+
chmodSync2(join42(libDir, "chisel"), 493);
|
|
226294
226966
|
} catch (e2) {
|
|
226295
226967
|
throw permError(e2, libDir, system);
|
|
226296
226968
|
}
|
|
226297
226969
|
try {
|
|
226298
226970
|
mkdirSync27(binDir, { recursive: true });
|
|
226299
|
-
|
|
226300
|
-
|
|
226971
|
+
rmSync13(link2, { force: true });
|
|
226972
|
+
symlinkSync2(join42(libDir, "lecodes"), link2);
|
|
226301
226973
|
} catch (e2) {
|
|
226302
226974
|
throw permError(e2, binDir, system);
|
|
226303
226975
|
}
|
|
226304
226976
|
success(`Installed to ${c.bold(libDir)}`);
|
|
226305
|
-
log(` ${c.dim(link2 + " → " +
|
|
226977
|
+
log(` ${c.dim(link2 + " → " + join42(libDir, "lecodes"))}`);
|
|
226306
226978
|
finishPathUnix(args, binDir);
|
|
226307
226979
|
};
|
|
226308
226980
|
var shellRc = () => {
|
|
226309
|
-
const shell =
|
|
226981
|
+
const shell = basename19(process.env.SHELL ?? "");
|
|
226310
226982
|
if (shell === "zsh")
|
|
226311
|
-
return { file:
|
|
226983
|
+
return { file: join42(HOME, ".zshrc"), name: "~/.zshrc" };
|
|
226312
226984
|
if (shell === "bash")
|
|
226313
|
-
return { file:
|
|
226314
|
-
return { file:
|
|
226985
|
+
return { file: join42(HOME, ".bashrc"), name: "~/.bashrc" };
|
|
226986
|
+
return { file: join42(HOME, ".profile"), name: "~/.profile" };
|
|
226315
226987
|
};
|
|
226316
226988
|
var PATH_MARKER = "# Added by `lecodes install`";
|
|
226317
226989
|
var appendPathToShellRc = (binDir) => {
|
|
226318
226990
|
const { file, name } = shellRc();
|
|
226319
226991
|
const line = `export PATH="${binDir}:$PATH"`;
|
|
226320
226992
|
try {
|
|
226321
|
-
const existing =
|
|
226993
|
+
const existing = existsSync41(file) ? readFileSync35(file, "utf8") : "";
|
|
226322
226994
|
if (existing.includes(line))
|
|
226323
226995
|
return name;
|
|
226324
226996
|
appendFileSync3(file, `${existing && !existing.endsWith(`
|
|
@@ -226356,7 +227028,7 @@ var finishPathUnix = (args, binDir) => {
|
|
|
226356
227028
|
log(` • or install system-wide (no PATH edit): ${c.bold("sudo lecodes install --system")}`);
|
|
226357
227029
|
};
|
|
226358
227030
|
var installWindows = (args, bundle, companions) => {
|
|
226359
|
-
const target =
|
|
227031
|
+
const target = resolve24(flagStr(args, "dir") ?? join42(process.env.LOCALAPPDATA ?? join42(HOME, "AppData", "Local"), "Programs", "lecodes-cli"));
|
|
226360
227032
|
try {
|
|
226361
227033
|
copyBundle(bundle, target, companions);
|
|
226362
227034
|
} catch (e2) {
|
|
@@ -226384,7 +227056,7 @@ var installWindows = (args, bundle, companions) => {
|
|
|
226384
227056
|
var addToUserPathWindows = (dir) => {
|
|
226385
227057
|
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
227058
|
try {
|
|
226387
|
-
|
|
227059
|
+
execFileSync8("powershell", ["-NoProfile", "-NonInteractive", "-Command", script], { stdio: "ignore", env: { ...process.env, LECODES_INSTALL_DIR: dir } });
|
|
226388
227060
|
return true;
|
|
226389
227061
|
} catch {
|
|
226390
227062
|
return false;
|
|
@@ -226395,9 +227067,9 @@ var addToUserPathWindows = (dir) => {
|
|
|
226395
227067
|
init_util();
|
|
226396
227068
|
|
|
226397
227069
|
// src/projectEnv.ts
|
|
226398
|
-
import { existsSync as
|
|
226399
|
-
import { homedir as
|
|
226400
|
-
import { dirname as
|
|
227070
|
+
import { existsSync as existsSync42, readFileSync as readFileSync36 } from "node:fs";
|
|
227071
|
+
import { homedir as homedir11 } from "node:os";
|
|
227072
|
+
import { dirname as dirname23, join as join43, resolve as resolve25 } from "node:path";
|
|
226401
227073
|
var KEY_RE = /^(LECODES|CREATOR)_[A-Z0-9_]+$/;
|
|
226402
227074
|
var parseDotEnv = (text) => {
|
|
226403
227075
|
const out = {};
|
|
@@ -226432,19 +227104,19 @@ var applyDotEnv = (parsed, dir, env) => {
|
|
|
226432
227104
|
continue;
|
|
226433
227105
|
let value = raw;
|
|
226434
227106
|
if (value.startsWith("./") || value.startsWith("../"))
|
|
226435
|
-
value =
|
|
227107
|
+
value = resolve25(dir, value);
|
|
226436
227108
|
else if (value === "~" || value.startsWith("~/"))
|
|
226437
|
-
value =
|
|
227109
|
+
value = join43(homedir11(), value.slice(1));
|
|
226438
227110
|
out[key] = value;
|
|
226439
227111
|
}
|
|
226440
227112
|
return out;
|
|
226441
227113
|
};
|
|
226442
227114
|
var findEnvRoot = (start) => {
|
|
226443
|
-
let dir =
|
|
227115
|
+
let dir = resolve25(start);
|
|
226444
227116
|
while (true) {
|
|
226445
|
-
if (
|
|
227117
|
+
if (existsSync42(join43(dir, "app.json")) || existsSync42(join43(dir, ".lecodes")))
|
|
226446
227118
|
return dir;
|
|
226447
|
-
const parent =
|
|
227119
|
+
const parent = dirname23(dir);
|
|
226448
227120
|
if (parent === dir)
|
|
226449
227121
|
return null;
|
|
226450
227122
|
dir = parent;
|
|
@@ -226455,10 +227127,10 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
226455
227127
|
const root = findEnvRoot(cwd);
|
|
226456
227128
|
if (!root)
|
|
226457
227129
|
return [];
|
|
226458
|
-
const file =
|
|
226459
|
-
if (!
|
|
227130
|
+
const file = join43(root, ".env");
|
|
227131
|
+
if (!existsSync42(file))
|
|
226460
227132
|
return [];
|
|
226461
|
-
const added = applyDotEnv(parseDotEnv(
|
|
227133
|
+
const added = applyDotEnv(parseDotEnv(readFileSync36(file, "utf8")), root, process.env);
|
|
226462
227134
|
for (const [k, v] of Object.entries(added))
|
|
226463
227135
|
process.env[k] = v;
|
|
226464
227136
|
return Object.keys(added);
|
|
@@ -226468,12 +227140,12 @@ var loadProjectEnv = (cwd = process.cwd()) => {
|
|
|
226468
227140
|
};
|
|
226469
227141
|
|
|
226470
227142
|
// src/index.ts
|
|
226471
|
-
var
|
|
226472
|
-
const dir =
|
|
227143
|
+
var STANDALONE2 = (() => {
|
|
227144
|
+
const dir = dirname24(process.execPath);
|
|
226473
227145
|
const chisel = process.platform === "win32" ? "chisel.exe" : "chisel";
|
|
226474
|
-
return
|
|
227146
|
+
return existsSync43(join44(dir, "runtime")) && existsSync43(join44(dir, chisel));
|
|
226475
227147
|
})();
|
|
226476
|
-
var INSTALLED =
|
|
227148
|
+
var INSTALLED = STANDALONE2 && (() => {
|
|
226477
227149
|
const exe = process.platform === "win32" ? "lecodes.exe" : "lecodes";
|
|
226478
227150
|
const self2 = (() => {
|
|
226479
227151
|
try {
|
|
@@ -226482,18 +227154,18 @@ var INSTALLED = STANDALONE && (() => {
|
|
|
226482
227154
|
return process.execPath;
|
|
226483
227155
|
}
|
|
226484
227156
|
})();
|
|
226485
|
-
return (process.env.PATH ?? "").split(
|
|
227157
|
+
return (process.env.PATH ?? "").split(delimiter3).some((d) => {
|
|
226486
227158
|
if (!d)
|
|
226487
227159
|
return false;
|
|
226488
227160
|
try {
|
|
226489
|
-
const cand =
|
|
226490
|
-
return
|
|
227161
|
+
const cand = join44(d, exe);
|
|
227162
|
+
return existsSync43(cand) && realpathSync2(cand) === self2;
|
|
226491
227163
|
} catch {
|
|
226492
227164
|
return false;
|
|
226493
227165
|
}
|
|
226494
227166
|
});
|
|
226495
227167
|
})();
|
|
226496
|
-
var INSTALL_HELP =
|
|
227168
|
+
var INSTALL_HELP = STANDALONE2 && !INSTALLED ? `
|
|
226497
227169
|
install Install this standalone build so 'lecodes' is on your PATH
|
|
226498
227170
|
(copies the bundle to a library folder + a symlink/PATH entry).
|
|
226499
227171
|
--modify-path also add it to PATH (edits your shell rc / user PATH)
|
|
@@ -226555,6 +227227,9 @@ ${c.bold("Commands:")}
|
|
|
226555
227227
|
--host <ip> LAN address to advertise (default: auto-detect)
|
|
226556
227228
|
--entry <path> override the entrypoint
|
|
226557
227229
|
--no-qr don't render the QR code
|
|
227230
|
+
--web also open the app in the browser (Web Lite host:
|
|
227231
|
+
same bundle + hot reload, camera/map plugins
|
|
227232
|
+
have web twins; the /web/ URL is served always)
|
|
226558
227233
|
--desktop also open the app in the native desktop host
|
|
226559
227234
|
(same hot reload; window from app.json's
|
|
226560
227235
|
desktop block; closing it keeps the server)
|
|
@@ -226580,6 +227255,11 @@ ${c.bold("Commands:")}
|
|
|
226580
227255
|
-o, --out <file> write JSON to a file instead of stdout
|
|
226581
227256
|
--png [file] rasterize a PNG (default screenshot.png;
|
|
226582
227257
|
needs @napi-rs/canvas)
|
|
227258
|
+
--map [file] draw the 3D scene's annotated top-down map
|
|
227259
|
+
(grid + XZ footprints + named markers) as
|
|
227260
|
+
<file>.png + <file>.json world-space data
|
|
227261
|
+
(default map.png; --label-all, --max-px N;
|
|
227262
|
+
also a { "map": "f.png" } script step)
|
|
226583
227263
|
--script <file> drive the app through a step list (tap/type/
|
|
226584
227264
|
scroll/wait/expect/screenshot/json steps;
|
|
226585
227265
|
games: frames/drag/hold/key/keyDown/keyUp,
|
|
@@ -226643,13 +227323,22 @@ ${c.bold("Commands:")}
|
|
|
226643
227323
|
render --desktop
|
|
226644
227324
|
(+ the render timing flags: --width/--height, --settle,
|
|
226645
227325
|
--device, --safe-area, --wait-network, --logs, --entry)
|
|
226646
|
-
|
|
226647
|
-
|
|
226648
|
-
|
|
226649
|
-
|
|
226650
|
-
|
|
226651
|
-
|
|
226652
|
-
|
|
227326
|
+
update Move everything a project depends on to its newest published
|
|
227327
|
+
state, in dependency order: the desktop host ('desktop
|
|
227328
|
+
update'), matc ('shaders update'), the project's shader
|
|
227329
|
+
compiles, the IDE types (.lecodes/types/ + tsconfig.json,
|
|
227330
|
+
from the server — the former 'lecodes types'), the
|
|
227331
|
+
ios/android shell pins ('app update'), then the GLOBAL npm
|
|
227332
|
+
installs: every installed optional peer (lecodes-renderer,
|
|
227333
|
+
lecodes-design, lecodes-3d-editor, lecodes-assets) and this
|
|
227334
|
+
CLI that is behind npm's latest gets 'npm install -g'.
|
|
227335
|
+
Pinned tools are skipped, not overridden: LECODES_DESKTOP_EXE
|
|
227336
|
+
/ LECODES_MATC mean a local build. Keeps going when a step
|
|
227337
|
+
fails; the summary says which.
|
|
227338
|
+
--local types from the SDK bundled in this CLI
|
|
227339
|
+
--no-shells leave ios/android pins alone (no re-sync)
|
|
227340
|
+
--check npm step: report what's behind, install nothing
|
|
227341
|
+
--no-cli skip the npm step (offline)
|
|
226653
227342
|
design [serve] LeCodes Design — a live canvas of screens for AI-driven prototyping
|
|
226654
227343
|
(needs the optional 'lecodes-design' package; works inside a
|
|
226655
227344
|
cloned project or standalone in any folder)
|
|
@@ -226706,6 +227395,8 @@ ${c.bold("Commands:")}
|
|
|
226706
227395
|
--probe headless-render the staged folder to PNG
|
|
226707
227396
|
(macOS: a brief windowed run + snapshot)
|
|
226708
227397
|
--zip also pack the result for sending
|
|
227398
|
+
--dmg macOS: also build a drag-to-Applications
|
|
227399
|
+
disk image (signed + notarized too)
|
|
226709
227400
|
--sign <identity|adhoc> macOS codesign identity
|
|
226710
227401
|
--notarize <profile> / --no-notarize macOS
|
|
226711
227402
|
--zip <out>.zip, UTF-8/forward-slash entries
|
|
@@ -226743,6 +227434,13 @@ ${c.bold("Commands:")}
|
|
|
226743
227434
|
--port <n> editor-server port (default 4488)
|
|
226744
227435
|
--no-open don't open the browser
|
|
226745
227436
|
--no-mcp don't register the MCP server in .mcp.json
|
|
227437
|
+
thumbs [path…] Asset thumbnails for the scene editor, WITHOUT a browser: decodes
|
|
227438
|
+
the project's images (KTX2 too, via KTX-Software's ktx tool) into the
|
|
227439
|
+
editor's preview cache. Incremental — the cached name carries the
|
|
227440
|
+
asset's content hash, so unchanged files are skipped. Models,
|
|
227441
|
+
materials and prefabs are rendered by the editor, not here
|
|
227442
|
+
--force redo even the up-to-date ones
|
|
227443
|
+
--size <px> longest edge (default 256)
|
|
226746
227444
|
assets convert <model.fbx|.glb> [--clips a.fbx b.fbx …] [-o out.glb] [--drop-model-clips]
|
|
226747
227445
|
[--fix] [--ktx2|--ktx2-hq]
|
|
226748
227446
|
FBX → LeCodes-ready GLB: meters/Y-up, textures embedded, clips from
|
|
@@ -226841,35 +227539,10 @@ Config lives in ~/.lecodes/config.json (override with LECODES_API / LECODES_TOKE
|
|
|
226841
227539
|
A .env next to app.json is read at startup for LECODES_* / CREATOR_* keys (the shell's own
|
|
226842
227540
|
environment wins; ./ paths resolve against the project; the file is never pushed) — e.g.
|
|
226843
227541
|
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 (
|
|
227542
|
+
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 };
|
|
227543
|
+
if (STANDALONE2)
|
|
226846
227544
|
commands.install = install;
|
|
226847
227545
|
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
227546
|
var printVersion = () => {
|
|
226874
227547
|
const rows = [["lecodes-cli", readVersion()]];
|
|
226875
227548
|
for (const [name, probe] of OPTIONAL_PEERS) {
|