lecodes-cli 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +167 -100
- package/package.json +2 -2
- package/runtime/sdk/canvas/Canvas.ts +2 -2
- package/runtime/sdk/g2/Texture2D.ts +1 -1
- package/runtime/sdk/gl/Material.ts +52 -0
- package/runtime/sdk/gl/Particles.ts +477 -116
- package/runtime/sdk/inject.ts +1 -1
- package/runtime/sdk/runtime/fetch.ts +9 -3
- package/runtime/sdk/runtime/share.ts +1 -1
- package/runtime/sdk/ui/NativeView.ts +5 -5
- package/runtime/sdk/ui/UIButton.ts +5 -5
- package/runtime/sdk/ui/UIContainer.ts +13 -13
- package/runtime/sdk/ui/UIImage.ts +5 -5
- package/runtime/sdk/ui/UIInput.ts +29 -10
- package/runtime/sdk/ui/UINode.ts +114 -34
- package/runtime/sdk/ui/UIPager.ts +5 -9
- package/runtime/sdk/ui/UIScreen.ts +5 -5
- package/runtime/sdk/ui/UIScrollable.ts +5 -5
- package/runtime/sdk/ui/UISpacer.ts +5 -5
- package/runtime/sdk/ui/UIText.ts +5 -5
- package/runtime/sdk/ui/UIVideo.ts +5 -5
- package/runtime/sdk/ui/UIVirtualizedList.ts +5 -5
- package/runtime/sdk/ui/UIWidget.ts +5 -5
- package/runtime/sdk-types.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47,6 +47,41 @@ var __export = (target, all) => {
|
|
|
47
47
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
48
48
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
49
49
|
|
|
50
|
+
// ../sdk/src/compile/assetName.ts
|
|
51
|
+
var inRanges = (cp, ranges) => ranges.some(([from, to]) => cp >= from && cp <= to), INVISIBLE, ODD_SPACE, ILLEGAL = '/\\:*?"<>|', sanitizeAssetName = (name) => {
|
|
52
|
+
let out = "";
|
|
53
|
+
for (const ch of name.normalize("NFC")) {
|
|
54
|
+
const cp = ch.codePointAt(0);
|
|
55
|
+
if (inRanges(cp, INVISIBLE))
|
|
56
|
+
continue;
|
|
57
|
+
out += inRanges(cp, ODD_SPACE) ? " " : ILLEGAL.includes(ch) ? "_" : ch;
|
|
58
|
+
}
|
|
59
|
+
return out.replace(/ {2,}/g, " ").replace(/^ +/, "").replace(/[ .]+$/, "");
|
|
60
|
+
}, isCanonicalAssetName = (name) => sanitizeAssetName(name) === name;
|
|
61
|
+
var init_assetName = __esm(() => {
|
|
62
|
+
INVISIBLE = [
|
|
63
|
+
[0, 31],
|
|
64
|
+
[127, 159],
|
|
65
|
+
[173, 173],
|
|
66
|
+
[1564, 1564],
|
|
67
|
+
[6158, 6158],
|
|
68
|
+
[8203, 8207],
|
|
69
|
+
[8232, 8233],
|
|
70
|
+
[8234, 8238],
|
|
71
|
+
[8288, 8292],
|
|
72
|
+
[8294, 8303],
|
|
73
|
+
[65279, 65279]
|
|
74
|
+
];
|
|
75
|
+
ODD_SPACE = [
|
|
76
|
+
[160, 160],
|
|
77
|
+
[5760, 5760],
|
|
78
|
+
[8192, 8202],
|
|
79
|
+
[8239, 8239],
|
|
80
|
+
[8287, 8287],
|
|
81
|
+
[12288, 12288]
|
|
82
|
+
];
|
|
83
|
+
});
|
|
84
|
+
|
|
50
85
|
// ../sdk/src/compile/assetMacro.ts
|
|
51
86
|
var ASSET_RE, hasAssetMacro = (src) => src.includes("asset("), desugarAssetMacros = (src, filePath) => {
|
|
52
87
|
const byPath = new Map;
|
|
@@ -129,18 +164,18 @@ var init_libraryImports = __esm(() => {
|
|
|
129
164
|
});
|
|
130
165
|
|
|
131
166
|
// ../sdk/src/compile/bundler.ts
|
|
132
|
-
import { existsSync as
|
|
167
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync } from "node:fs";
|
|
133
168
|
import { spawnSync } from "node:child_process";
|
|
134
169
|
import { createRequire as createRequire2 } from "node:module";
|
|
135
170
|
import { dirname as dirname4, join as join7, relative as relative2 } from "node:path";
|
|
136
171
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
137
172
|
var resolveInject = () => {
|
|
138
173
|
const override = process.env.LECODES_SDK_INJECT;
|
|
139
|
-
if (override &&
|
|
174
|
+
if (override && existsSync5(override))
|
|
140
175
|
return override;
|
|
141
176
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
142
177
|
const src = join7(here, "..", "inject.ts");
|
|
143
|
-
if (
|
|
178
|
+
if (existsSync5(src))
|
|
144
179
|
return src;
|
|
145
180
|
throw new Error("sdk: could not locate the inject source (LECODES_SDK_INJECT / src/inject.ts)");
|
|
146
181
|
}, normalize = (path) => {
|
|
@@ -180,13 +215,13 @@ var resolveInject = () => {
|
|
|
180
215
|
}, resolveChiselBin = () => {
|
|
181
216
|
const override = process.env.LECODES_CHISEL_BIN;
|
|
182
217
|
if (override) {
|
|
183
|
-
if (
|
|
218
|
+
if (existsSync5(override))
|
|
184
219
|
return override;
|
|
185
220
|
throw new Error(`LECODES_CHISEL_BIN points at a missing file: ${override}`);
|
|
186
221
|
}
|
|
187
222
|
try {
|
|
188
223
|
const bin = createRequire2(import.meta.url)("@letary/chisel").binaryPath();
|
|
189
|
-
if (bin &&
|
|
224
|
+
if (bin && existsSync5(bin))
|
|
190
225
|
return bin;
|
|
191
226
|
} catch {}
|
|
192
227
|
throw new Error("chisel binary not found. Install @letary/chisel, or set LECODES_CHISEL_BIN.");
|
|
@@ -247,7 +282,7 @@ var resolveInject = () => {
|
|
|
247
282
|
inject: ["/__sdk/inject.ts"],
|
|
248
283
|
format,
|
|
249
284
|
minify,
|
|
250
|
-
fuse: process.env.LECODES_CHISEL_FUSE
|
|
285
|
+
fuse: process.env.LECODES_CHISEL_FUSE !== "0",
|
|
251
286
|
define: { ...CHISEL_DEFINE, EDITOR: editor ? "true" : "false" },
|
|
252
287
|
keep: CHISEL_KEEP,
|
|
253
288
|
sourcemap,
|
|
@@ -268,7 +303,10 @@ var resolveInject = () => {
|
|
|
268
303
|
throw new Error(`chisel: ${parsed.error}`);
|
|
269
304
|
if (parsed.code == null)
|
|
270
305
|
throw new Error("chisel produced no code");
|
|
271
|
-
|
|
306
|
+
const diagnostics = parsed.diagnostics ?? [];
|
|
307
|
+
for (const d of diagnostics)
|
|
308
|
+
console.warn(`warning: ${d}`);
|
|
309
|
+
return { code: parsed.code, map: parsed.map ?? null, diagnostics };
|
|
272
310
|
}, bundleProject = async (entrypoint, files, format = "esm") => (await bundleProjectChisel(entrypoint, files, format, false)).code, bundleProjectWithMap = async (entrypoint, files, format = "esm", minify, editor, libraries, sourcemap = true) => bundleProjectChisel(entrypoint, files, format, sourcemap, minify, editor, libraries);
|
|
273
311
|
var init_bundler = __esm(() => {
|
|
274
312
|
init_assetMacro();
|
|
@@ -459,11 +497,11 @@ var init_compileProject = __esm(() => {
|
|
|
459
497
|
});
|
|
460
498
|
|
|
461
499
|
// ../sdk/src/compile/sceneEditor.ts
|
|
462
|
-
import { existsSync as
|
|
500
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "node:fs";
|
|
463
501
|
import { join as join8 } from "node:path";
|
|
464
502
|
var SCENE_HARNESS_DIR = "./.scene-editor", SCENE_ENTRY_PATH = "./.scene-entry.ts", loadSceneHarness = (fallbackDir) => {
|
|
465
503
|
const override = process.env.LECODES_SCENE_HARNESS_DIR;
|
|
466
|
-
const dir = override &&
|
|
504
|
+
const dir = override && existsSync6(override) ? override : fallbackDir && existsSync6(fallbackDir) ? fallbackDir : null;
|
|
467
505
|
if (!dir)
|
|
468
506
|
throw new Error("scene-editor harness sources not found (set LECODES_SCENE_HARNESS_DIR)");
|
|
469
507
|
const out = {};
|
|
@@ -1040,9 +1078,11 @@ __export(exports_compile, {
|
|
|
1040
1078
|
scanModulesFallback: () => scanModulesFallback,
|
|
1041
1079
|
scanModulesChisel: () => scanModulesChisel,
|
|
1042
1080
|
scanFontCalls: () => scanFontCalls,
|
|
1081
|
+
sanitizeAssetName: () => sanitizeAssetName,
|
|
1043
1082
|
parseSfnt: () => parseSfnt,
|
|
1044
1083
|
offsetSourceMap: () => offsetSourceMap,
|
|
1045
1084
|
loadSceneHarness: () => loadSceneHarness,
|
|
1085
|
+
isCanonicalAssetName: () => isCanonicalAssetName,
|
|
1046
1086
|
inlineSourceMapComment: () => inlineSourceMapComment,
|
|
1047
1087
|
fontRegistryBase: () => fontRegistryBase,
|
|
1048
1088
|
faceFileName: () => faceFileName,
|
|
@@ -1063,6 +1103,7 @@ __export(exports_compile, {
|
|
|
1063
1103
|
var init_compile = __esm(() => {
|
|
1064
1104
|
init_bundler();
|
|
1065
1105
|
init_detectEntry();
|
|
1106
|
+
init_assetName();
|
|
1066
1107
|
init_compileProject();
|
|
1067
1108
|
init_sceneEditor();
|
|
1068
1109
|
init_fontMacro();
|
|
@@ -2088,9 +2129,9 @@ var require_main = __commonJS((exports, module) => {
|
|
|
2088
2129
|
// package.json
|
|
2089
2130
|
var package_default = {
|
|
2090
2131
|
name: "lecodes-cli",
|
|
2091
|
-
version: "0.10.
|
|
2132
|
+
version: "0.10.2",
|
|
2092
2133
|
dependencies: {
|
|
2093
|
-
"@letary/chisel": "^0.
|
|
2134
|
+
"@letary/chisel": "^0.6.0"
|
|
2094
2135
|
},
|
|
2095
2136
|
devDependencies: {
|
|
2096
2137
|
"lecodes-design": "workspace:*",
|
|
@@ -2147,7 +2188,7 @@ var package_default = {
|
|
|
2147
2188
|
|
|
2148
2189
|
// src/commands/app.ts
|
|
2149
2190
|
import { execFileSync } from "node:child_process";
|
|
2150
|
-
import { cpSync, existsSync as
|
|
2191
|
+
import { cpSync, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync10, readdirSync as readdirSync4, rmSync, statSync as statSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
2151
2192
|
import { homedir as homedir2 } from "node:os";
|
|
2152
2193
|
import { basename as basename4, dirname as dirname7, join as join11, resolve as resolve2 } from "node:path";
|
|
2153
2194
|
|
|
@@ -2156,6 +2197,7 @@ import { dirname, join } from "node:path";
|
|
|
2156
2197
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2157
2198
|
|
|
2158
2199
|
// src/util.ts
|
|
2200
|
+
init_assetName();
|
|
2159
2201
|
import { createHash } from "node:crypto";
|
|
2160
2202
|
import { createInterface } from "node:readline";
|
|
2161
2203
|
var useColor = process.stdout.isTTY && process.env.NO_COLOR === undefined;
|
|
@@ -2201,7 +2243,10 @@ var toKey = (path) => {
|
|
|
2201
2243
|
const parts = path.replace(/\\/g, "/").split("/").map((p) => p.trim()).filter((p) => p && p !== ".");
|
|
2202
2244
|
if (parts.some((p) => p === ".."))
|
|
2203
2245
|
throw new CliError(`Unsafe path: ${path}`);
|
|
2204
|
-
|
|
2246
|
+
const names = parts.map((p) => sanitizeAssetName(p));
|
|
2247
|
+
if (names.some((name) => !name))
|
|
2248
|
+
throw new CliError(`Wrong path: ${path}`);
|
|
2249
|
+
return "/" + names.join("/");
|
|
2205
2250
|
};
|
|
2206
2251
|
var prompt = (question, fallback) => new Promise((resolve) => {
|
|
2207
2252
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -2490,7 +2535,8 @@ import { readFileSync as readFileSync5 } from "node:fs";
|
|
|
2490
2535
|
import { basename } from "node:path";
|
|
2491
2536
|
|
|
2492
2537
|
// src/localFiles.ts
|
|
2493
|
-
|
|
2538
|
+
init_assetName();
|
|
2539
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync4 } from "node:fs";
|
|
2494
2540
|
import { join as join4, relative } from "node:path";
|
|
2495
2541
|
var SKIP_DIRS = new Set([".lecodes", ".git", "node_modules"]);
|
|
2496
2542
|
var SKIP_FILES = new Set(["tsconfig.json", "jsconfig.json", ".gitignore", ".lecodesignore", ".DS_Store"]);
|
|
@@ -2572,6 +2618,23 @@ var scanLocal = (root, opts = {}) => {
|
|
|
2572
2618
|
walk(root, false);
|
|
2573
2619
|
return { files, dirs, ignored };
|
|
2574
2620
|
};
|
|
2621
|
+
var resolveLocalPath = (root, key) => {
|
|
2622
|
+
const direct = join4(root, key.slice(1));
|
|
2623
|
+
if (existsSync3(direct))
|
|
2624
|
+
return direct;
|
|
2625
|
+
let dir = root;
|
|
2626
|
+
try {
|
|
2627
|
+
for (const name of key.slice(1).split("/")) {
|
|
2628
|
+
const match = readdirSync(dir).find((entry) => entry === name || sanitizeAssetName(entry) === name);
|
|
2629
|
+
if (!match)
|
|
2630
|
+
return null;
|
|
2631
|
+
dir = join4(dir, match);
|
|
2632
|
+
}
|
|
2633
|
+
} catch {
|
|
2634
|
+
return null;
|
|
2635
|
+
}
|
|
2636
|
+
return dir;
|
|
2637
|
+
};
|
|
2575
2638
|
var scanProject = (root, manifest) => scanLocal(root, { ignore: loadIgnore(root), tracked: new Set(Object.keys(manifest.files)) });
|
|
2576
2639
|
var diffLocal = (manifest, scan) => {
|
|
2577
2640
|
const added = [];
|
|
@@ -2695,12 +2758,12 @@ var collectLocalEntries = (root, manifest, assetBase) => {
|
|
|
2695
2758
|
};
|
|
2696
2759
|
|
|
2697
2760
|
// src/compile/projectCompile.ts
|
|
2698
|
-
import { existsSync as
|
|
2761
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
2699
2762
|
import { createRequire as createRequire3 } from "node:module";
|
|
2700
2763
|
import { dirname as dirname5, join as join9 } from "node:path";
|
|
2701
2764
|
|
|
2702
2765
|
// src/distRoot.ts
|
|
2703
|
-
import { existsSync as
|
|
2766
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
2704
2767
|
import { dirname as dirname3, join as join6 } from "node:path";
|
|
2705
2768
|
import { fileURLToPath } from "node:url";
|
|
2706
2769
|
var distRoot = (() => {
|
|
@@ -2709,7 +2772,7 @@ var distRoot = (() => {
|
|
|
2709
2772
|
dirname3(process.execPath)
|
|
2710
2773
|
];
|
|
2711
2774
|
for (const c2 of candidates)
|
|
2712
|
-
if (
|
|
2775
|
+
if (existsSync4(join6(c2, "runtime")))
|
|
2713
2776
|
return c2;
|
|
2714
2777
|
return candidates[0];
|
|
2715
2778
|
})();
|
|
@@ -2717,7 +2780,7 @@ var distRoot = (() => {
|
|
|
2717
2780
|
// src/compile/projectCompile.ts
|
|
2718
2781
|
init_compile();
|
|
2719
2782
|
var vendoredInject = join9(distRoot, "runtime", "sdk", "inject.ts");
|
|
2720
|
-
if (
|
|
2783
|
+
if (existsSync7(vendoredInject))
|
|
2721
2784
|
process.env.LECODES_SDK_INJECT = vendoredInject;
|
|
2722
2785
|
var resolveChiselBin2 = () => {
|
|
2723
2786
|
if (process.env.LECODES_CHISEL_BIN)
|
|
@@ -2728,7 +2791,7 @@ var resolveChiselBin2 = () => {
|
|
|
2728
2791
|
return fromPkg;
|
|
2729
2792
|
} catch {}
|
|
2730
2793
|
const local = join9(dirname5(process.execPath), process.platform === "win32" ? "chisel.exe" : "chisel");
|
|
2731
|
-
return
|
|
2794
|
+
return existsSync7(local) ? local : null;
|
|
2732
2795
|
};
|
|
2733
2796
|
var chiselBin = resolveChiselBin2();
|
|
2734
2797
|
if (chiselBin)
|
|
@@ -2756,7 +2819,7 @@ var compileProject2 = (opts) => compileProject({
|
|
|
2756
2819
|
// src/compile/fonts.ts
|
|
2757
2820
|
init_compile();
|
|
2758
2821
|
import { createHash as createHash2 } from "node:crypto";
|
|
2759
|
-
import { existsSync as
|
|
2822
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2760
2823
|
import { dirname as dirname6, join as join10 } from "node:path";
|
|
2761
2824
|
var applyProjectFonts = async (entries, opts) => {
|
|
2762
2825
|
const registry = (opts.registry ?? fontRegistryBase()).replace(/\/+$/, "");
|
|
@@ -2778,7 +2841,7 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
2778
2841
|
const rel = `assets/fonts/${face.fileName}`;
|
|
2779
2842
|
const abs = join10(vendorDir, rel);
|
|
2780
2843
|
const entryPath = `${opts.vendorPrefix ?? ""}/${rel}`;
|
|
2781
|
-
if (!
|
|
2844
|
+
if (!existsSync8(abs))
|
|
2782
2845
|
await downloadFace(registry, vendorDir, face, rel, abs);
|
|
2783
2846
|
if (!byPath().has(entryPath.replace(/^\//, ""))) {
|
|
2784
2847
|
entries.push(opts.makeResourceEntry?.(entryPath, abs) ?? { path: entryPath, type: "resource", absPath: abs });
|
|
@@ -3472,6 +3535,11 @@ ${keys.map((k) => ` <key>${k}</key>
|
|
|
3472
3535
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3473
3536
|
<plist version="1.0">
|
|
3474
3537
|
<dict>
|
|
3538
|
+
<!-- Standard-encryption-only (HTTPS/TLS): declares export-compliance exemption
|
|
3539
|
+
so App Store Connect skips the "Missing Compliance" prompt on every build.
|
|
3540
|
+
Flip to <true/> only if the app adds its own non-exempt cryptography. -->
|
|
3541
|
+
<key>ITSAppUsesNonExemptEncryption</key>
|
|
3542
|
+
<false/>
|
|
3475
3543
|
<key>UIApplicationSceneManifest</key>
|
|
3476
3544
|
<dict>
|
|
3477
3545
|
<key>UIApplicationSupportsMultipleScenes</key>
|
|
@@ -3725,7 +3793,7 @@ var FIRST_PARTY_PLUGINS = {
|
|
|
3725
3793
|
"qr-scanner": "letary/lecodes-plugins"
|
|
3726
3794
|
};
|
|
3727
3795
|
var readJson = (path) => {
|
|
3728
|
-
if (!
|
|
3796
|
+
if (!existsSync9(path))
|
|
3729
3797
|
return null;
|
|
3730
3798
|
try {
|
|
3731
3799
|
return JSON.parse(readFileSync10(path, "utf8"));
|
|
@@ -3765,7 +3833,7 @@ var fetchLatestSdkVersion = async () => {
|
|
|
3765
3833
|
};
|
|
3766
3834
|
var shellSdkVersion = (iosDir) => {
|
|
3767
3835
|
const path = join11(iosDir, "LeCodesRuntime", "Package.swift");
|
|
3768
|
-
if (!
|
|
3836
|
+
if (!existsSync9(path))
|
|
3769
3837
|
return null;
|
|
3770
3838
|
const m = /lecodes-ios-sdk\.git",\s*(?:exact|from):\s*"([^"]+)"/.exec(readFileSync10(path, "utf8"));
|
|
3771
3839
|
return m && VERSION_RE.test(m[1]) ? m[1] : null;
|
|
@@ -3796,7 +3864,7 @@ var ensureRepo = (repo, wantTag, lock) => {
|
|
|
3796
3864
|
}
|
|
3797
3865
|
const cache = join11(homedir2(), ".lecodes", "plugins", repo.replace("/", "__"));
|
|
3798
3866
|
const url = `https://github.com/${repo}.git`;
|
|
3799
|
-
if (!
|
|
3867
|
+
if (!existsSync9(join11(cache, ".git"))) {
|
|
3800
3868
|
mkdirSync5(dirname7(cache), { recursive: true });
|
|
3801
3869
|
note(`Cloning ${url}…`);
|
|
3802
3870
|
git(dirname7(cache), "clone", "--quiet", url, cache);
|
|
@@ -3869,7 +3937,7 @@ var appInit = async (args) => {
|
|
|
3869
3937
|
}
|
|
3870
3938
|
const root = projectRoot();
|
|
3871
3939
|
const iosDir = join11(root, "ios");
|
|
3872
|
-
if (
|
|
3940
|
+
if (existsSync9(iosDir)) {
|
|
3873
3941
|
throw new CliError("ios/ already exists — run `lecodes app sync` to update it.");
|
|
3874
3942
|
}
|
|
3875
3943
|
const existing = readJson(join11(root, "app.json")) ?? {};
|
|
@@ -3897,7 +3965,7 @@ var appInit = async (args) => {
|
|
|
3897
3965
|
writeJson(join11(root, "app.json"), config);
|
|
3898
3966
|
log(`${c.green("written")} app.json`);
|
|
3899
3967
|
const ignorePath = join11(root, ".lecodesignore");
|
|
3900
|
-
const ignore =
|
|
3968
|
+
const ignore = existsSync9(ignorePath) ? readFileSync10(ignorePath, "utf8") : DEFAULT_IGNORE_FILE;
|
|
3901
3969
|
if (!/^ios\/$/m.test(ignore)) {
|
|
3902
3970
|
writeFileSync7(ignorePath, ignore.replace(/\n*$/, `
|
|
3903
3971
|
`) + `
|
|
@@ -3974,7 +4042,7 @@ var ensureSdkResourcesBundle = async (sdkVersion) => {
|
|
|
3974
4042
|
}
|
|
3975
4043
|
const dir = join11(homedir2(), ".lecodes", "sdk-resources", sdkVersion);
|
|
3976
4044
|
const bundle = join11(dir, "LeCodesSDKResources.bundle");
|
|
3977
|
-
if (
|
|
4045
|
+
if (existsSync9(bundle))
|
|
3978
4046
|
return bundle;
|
|
3979
4047
|
const url = `https://github.com/${SDK_REPO}/releases/download/${sdkVersion}/LeCodesSDKResources.bundle.zip`;
|
|
3980
4048
|
note(`Downloading LeCodesSDKResources.bundle (SDK ${sdkVersion})…`);
|
|
@@ -3986,7 +4054,7 @@ var ensureSdkResourcesBundle = async (sdkVersion) => {
|
|
|
3986
4054
|
writeFileSync7(zip, new Uint8Array(await res.arrayBuffer()));
|
|
3987
4055
|
execFileSync("ditto", ["-x", "-k", zip, dir]);
|
|
3988
4056
|
rmSync(zip);
|
|
3989
|
-
if (!
|
|
4057
|
+
if (!existsSync9(bundle))
|
|
3990
4058
|
throw new CliError(`No LeCodesSDKResources.bundle inside the release asset ${url}`);
|
|
3991
4059
|
return bundle;
|
|
3992
4060
|
};
|
|
@@ -4013,7 +4081,7 @@ var appSync = async (_args) => {
|
|
|
4013
4081
|
const root = projectRoot();
|
|
4014
4082
|
const config = readJson(join11(root, "app.json"));
|
|
4015
4083
|
const iosDir = join11(root, "ios");
|
|
4016
|
-
if (!config?.ios || !
|
|
4084
|
+
if (!config?.ios || !existsSync9(iosDir)) {
|
|
4017
4085
|
throw new CliError("No iOS shell here — run `lecodes app init ios` first.");
|
|
4018
4086
|
}
|
|
4019
4087
|
const requestedVariant = config.ios.variant ?? "auto";
|
|
@@ -4038,7 +4106,7 @@ var appSync = async (_args) => {
|
|
|
4038
4106
|
if (!module || !register)
|
|
4039
4107
|
throw new CliError(`Plugin "${id}": manifest ios.module / ios.register missing`);
|
|
4040
4108
|
const src = join11(plugin.dir, ios.sources ?? "ios");
|
|
4041
|
-
if (!
|
|
4109
|
+
if (!existsSync9(src))
|
|
4042
4110
|
throw new CliError(`Plugin "${id}": sources dir ${src} missing`);
|
|
4043
4111
|
const dest = join11(sourcesDir, module);
|
|
4044
4112
|
rmSync(dest, { recursive: true, force: true });
|
|
@@ -4054,7 +4122,7 @@ var appSync = async (_args) => {
|
|
|
4054
4122
|
log(`${c.green("plugin")} ${id}@${plugin.lock.version} (${plugin.lock.tag} → Sources/${module})`);
|
|
4055
4123
|
}
|
|
4056
4124
|
const keep = new Set(["LeCodesRuntime", ...runtimePlugins.map((p) => p.module)]);
|
|
4057
|
-
for (const entry of
|
|
4125
|
+
for (const entry of existsSync9(sourcesDir) ? readdirSync4(sourcesDir) : []) {
|
|
4058
4126
|
if (!keep.has(entry) && statSync2(join11(sourcesDir, entry)).isDirectory()) {
|
|
4059
4127
|
rmSync(join11(sourcesDir, entry), { recursive: true });
|
|
4060
4128
|
log(`${c.yellow("removed")} ios/LeCodesRuntime/Sources/${entry} (plugin uninstalled)`);
|
|
@@ -4128,7 +4196,7 @@ var appSync = async (_args) => {
|
|
|
4128
4196
|
writeFileSync7(join11(iosDir, "App", "Info.plist"), infoPlistTemplate(mergedKeys, updateUrl));
|
|
4129
4197
|
if (updateUrl)
|
|
4130
4198
|
log(`${c.green("update")} OTA source ${updateUrl} — checked natively at launch, new code applies next launch`);
|
|
4131
|
-
if (pluginSpecs.length > 0 ||
|
|
4199
|
+
if (pluginSpecs.length > 0 || existsSync9(lockPath))
|
|
4132
4200
|
writeJson(lockPath, { plugins: newLock });
|
|
4133
4201
|
const pbxPath = join11(iosDir, "App.xcodeproj", "project.pbxproj");
|
|
4134
4202
|
const pbx = readFileSync10(pbxPath, "utf8").replace(/MARKETING_VERSION = [^;]+;/g, `MARKETING_VERSION = ${config.version ?? "1.0.0"};`).replace(/CURRENT_PROJECT_VERSION = [^;]+;/g, `CURRENT_PROJECT_VERSION = ${config.ios.buildNumber ?? 1};`);
|
|
@@ -4218,7 +4286,7 @@ var exportOptionsPlist = (method, teamId, destination) => `<?xml version="1.0" e
|
|
|
4218
4286
|
var requireShell = () => {
|
|
4219
4287
|
const root = projectRoot();
|
|
4220
4288
|
const config = readJson(join11(root, "app.json"));
|
|
4221
|
-
if (!config?.ios || !
|
|
4289
|
+
if (!config?.ios || !existsSync9(join11(root, "ios"))) {
|
|
4222
4290
|
throw new CliError("No iOS shell here — run `lecodes app init ios` first.");
|
|
4223
4291
|
}
|
|
4224
4292
|
return { root, config };
|
|
@@ -4294,7 +4362,7 @@ var appUpdate = async (args) => {
|
|
|
4294
4362
|
log(`${c.green("plugin")} ${id} ${entry?.tag ?? "—"} → ${c.bold(tag)}`);
|
|
4295
4363
|
changed = true;
|
|
4296
4364
|
}
|
|
4297
|
-
if (!checkOnly &&
|
|
4365
|
+
if (!checkOnly && existsSync9(lockPath))
|
|
4298
4366
|
writeJson(lockPath, { plugins: kept });
|
|
4299
4367
|
}
|
|
4300
4368
|
log("");
|
|
@@ -4328,18 +4396,18 @@ var appDoctor = async (_args) => {
|
|
|
4328
4396
|
check(xcodeVersion !== "", `Xcode CLI (${xcodeVersion || "not found"})`, "install Xcode + command line tools");
|
|
4329
4397
|
check(!!config.ios.teamId, "Development team set", "lecodes app init wrote app.json — fill ios.teamId", false);
|
|
4330
4398
|
const iconDir = join11(root, "ios", "App", "Assets.xcassets", "AppIcon.appiconset");
|
|
4331
|
-
const hasIcon =
|
|
4399
|
+
const hasIcon = existsSync9(iconDir) && readdirSync4(iconDir).some((f2) => f2.endsWith(".png"));
|
|
4332
4400
|
check(hasIcon, "App icon present", "drop a 1024×1024 PNG into ios/App/Assets.xcassets/AppIcon.appiconset/ (App Store requires it)", false);
|
|
4333
4401
|
const bundle = join11(root, "ios", "App", "Resources", "app.js");
|
|
4334
|
-
check(
|
|
4402
|
+
check(existsSync9(bundle), "Bundled app.js", "run `lecodes app sync`");
|
|
4335
4403
|
const requestedVariant = config.ios.variant ?? "auto";
|
|
4336
4404
|
const validVariant = requestedVariant === "auto" || SDK_VARIANTS.includes(requestedVariant);
|
|
4337
4405
|
check(validVariant, `ios.variant "${requestedVariant}"`, `use "auto" or one of ${SDK_VARIANTS.join(", ")}`);
|
|
4338
|
-
if (
|
|
4406
|
+
if (existsSync9(bundle) && validVariant) {
|
|
4339
4407
|
const { variant } = resolveVariant(requestedVariant, readFileSync10(bundle, "utf8"));
|
|
4340
4408
|
const pkg = readFileSync10(join11(root, "ios", "LeCodesRuntime", "Package.swift"), "utf8");
|
|
4341
4409
|
const needsResources = variant === "3d" || variant === "full";
|
|
4342
|
-
const hasResources =
|
|
4410
|
+
const hasResources = existsSync9(join11(root, "ios", "App", "Resources", "LeCodesSDKResources.bundle"));
|
|
4343
4411
|
check(pkg.includes(`"LeCodesSDK-${variant}"`) && (!needsResources || hasResources), `SDK variant ${variant}${needsResources ? " (+ filament resources)" : ""}`, "run `lecodes app sync`");
|
|
4344
4412
|
}
|
|
4345
4413
|
const linked = shellSdkVersion(join11(root, "ios"));
|
|
@@ -4411,7 +4479,7 @@ var appBuild = async (args) => {
|
|
|
4411
4479
|
};
|
|
4412
4480
|
var appUpload = async (args) => {
|
|
4413
4481
|
const { root, config } = requireShell();
|
|
4414
|
-
if (!
|
|
4482
|
+
if (!existsSync9(join11(root, ARCHIVE_PATH))) {
|
|
4415
4483
|
throw new CliError("No archive at ios/build/App.xcarchive — run `lecodes app build ios` first.");
|
|
4416
4484
|
}
|
|
4417
4485
|
const ascPath = join11(homedir2(), ".lecodes", "asc.json");
|
|
@@ -4423,7 +4491,7 @@ var appUpload = async (args) => {
|
|
|
4423
4491
|
throw new CliError(`App Store Connect API key needed: --key-path <AuthKey.p8> --key-id <id> --issuer-id <id>
|
|
4424
4492
|
(create one at appstoreconnect.apple.com → Users and Access → Integrations; stored in ~/.lecodes/asc.json after first use)`);
|
|
4425
4493
|
}
|
|
4426
|
-
if (!
|
|
4494
|
+
if (!existsSync9(keyPath))
|
|
4427
4495
|
throw new CliError(`API key file not found: ${keyPath}`);
|
|
4428
4496
|
if (flagStr(args, "key-path")) {
|
|
4429
4497
|
mkdirSync5(dirname7(ascPath), { recursive: true });
|
|
@@ -4461,7 +4529,7 @@ var appOpen = async (args) => {
|
|
|
4461
4529
|
const platform = args._[1] ?? "ios";
|
|
4462
4530
|
if (platform === "ios") {
|
|
4463
4531
|
const proj = join11(root, "ios", "App.xcodeproj");
|
|
4464
|
-
if (!
|
|
4532
|
+
if (!existsSync9(proj))
|
|
4465
4533
|
throw new CliError("No iOS shell here — run `lecodes app init ios` first.");
|
|
4466
4534
|
if (process.platform !== "darwin")
|
|
4467
4535
|
throw new CliError("Opening Xcode requires macOS.");
|
|
@@ -4496,12 +4564,12 @@ var app = async (args) => {
|
|
|
4496
4564
|
};
|
|
4497
4565
|
|
|
4498
4566
|
// src/commands/clone.ts
|
|
4499
|
-
import { existsSync as
|
|
4567
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readdirSync as readdirSync6 } from "node:fs";
|
|
4500
4568
|
import { resolve as resolve3 } from "node:path";
|
|
4501
4569
|
|
|
4502
4570
|
// src/types.ts
|
|
4503
4571
|
import { dirname as dirname8, join as join12, relative as relative3, sep } from "node:path";
|
|
4504
|
-
import { existsSync as
|
|
4572
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readdirSync as readdirSync5, readFileSync as readFileSync11, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
4505
4573
|
var TSCONFIG = {
|
|
4506
4574
|
compilerOptions: {
|
|
4507
4575
|
target: "ES2020",
|
|
@@ -4519,7 +4587,7 @@ var TSCONFIG = {
|
|
|
4519
4587
|
exclude: ["node_modules"]
|
|
4520
4588
|
};
|
|
4521
4589
|
var listBundleFiles = (dir, base = dir) => {
|
|
4522
|
-
if (!
|
|
4590
|
+
if (!existsSync10(dir))
|
|
4523
4591
|
return [];
|
|
4524
4592
|
const out = [];
|
|
4525
4593
|
for (const name of readdirSync5(dir)) {
|
|
@@ -4532,7 +4600,7 @@ var listBundleFiles = (dir, base = dir) => {
|
|
|
4532
4600
|
return out;
|
|
4533
4601
|
};
|
|
4534
4602
|
var pruneEmptyDirs = (dir, root) => {
|
|
4535
|
-
if (!
|
|
4603
|
+
if (!existsSync10(dir) || !statSync3(dir).isDirectory())
|
|
4536
4604
|
return;
|
|
4537
4605
|
for (const name of readdirSync5(dir))
|
|
4538
4606
|
pruneEmptyDirs(join12(dir, name), root);
|
|
@@ -4578,7 +4646,7 @@ var readLocalTypeBundle = () => {
|
|
|
4578
4646
|
join12(distRoot, "..", "sdk", "dist", "types.json")
|
|
4579
4647
|
];
|
|
4580
4648
|
for (const path of candidates) {
|
|
4581
|
-
if (
|
|
4649
|
+
if (existsSync10(path)) {
|
|
4582
4650
|
try {
|
|
4583
4651
|
return JSON.parse(readFileSync11(path, "utf8"));
|
|
4584
4652
|
} catch {}
|
|
@@ -4616,7 +4684,7 @@ var clone = async (args) => {
|
|
|
4616
4684
|
const project = await getProject(apiUrl, token, uuid);
|
|
4617
4685
|
const dir = args._[1] ?? slug(project.name);
|
|
4618
4686
|
const root = resolve3(dir);
|
|
4619
|
-
if (
|
|
4687
|
+
if (existsSync11(root) && readdirSync6(root).length > 0) {
|
|
4620
4688
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
4621
4689
|
}
|
|
4622
4690
|
mkdirSync7(root, { recursive: true });
|
|
@@ -4636,7 +4704,7 @@ var clone = async (args) => {
|
|
|
4636
4704
|
};
|
|
4637
4705
|
|
|
4638
4706
|
// src/commands/create.ts
|
|
4639
|
-
import { existsSync as
|
|
4707
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync7, writeFileSync as writeFileSync9 } from "node:fs";
|
|
4640
4708
|
import { join as join13, resolve as resolve4 } from "node:path";
|
|
4641
4709
|
|
|
4642
4710
|
// src/commands/projectTemplates.ts
|
|
@@ -4723,7 +4791,7 @@ var create = async (args) => {
|
|
|
4723
4791
|
throw new CliError("Usage: lecodes create <name> [directory]");
|
|
4724
4792
|
const dir = args._[1] ?? slug2(name);
|
|
4725
4793
|
const root = resolve4(dir);
|
|
4726
|
-
if (
|
|
4794
|
+
if (existsSync12(root) && readdirSync7(root).length > 0) {
|
|
4727
4795
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
4728
4796
|
}
|
|
4729
4797
|
mkdirSync8(root, { recursive: true });
|
|
@@ -4742,7 +4810,7 @@ var create = async (args) => {
|
|
|
4742
4810
|
};
|
|
4743
4811
|
|
|
4744
4812
|
// src/commands/design.ts
|
|
4745
|
-
import { existsSync as
|
|
4813
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync14, readdirSync as readdirSync8, writeFileSync as writeFileSync11, appendFileSync } from "node:fs";
|
|
4746
4814
|
import { basename as basename6, join as join15 } from "node:path";
|
|
4747
4815
|
|
|
4748
4816
|
// src/compile/designCompile.ts
|
|
@@ -4751,7 +4819,7 @@ import { basename as basename5 } from "node:path";
|
|
|
4751
4819
|
|
|
4752
4820
|
// src/compile/assetIcons.ts
|
|
4753
4821
|
import { createHash as createHash3 } from "node:crypto";
|
|
4754
|
-
import { existsSync as
|
|
4822
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "node:fs";
|
|
4755
4823
|
import { dirname as dirname9, join as join14 } from "node:path";
|
|
4756
4824
|
var DEFAULT_REGISTRY = process.env.LECODES_ICON_REGISTRY?.trim() || "https://icon-registry.jt3.ru/v1";
|
|
4757
4825
|
var ICON_ID = /^([a-z0-9]+(?:-[a-z0-9]+)*):([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
@@ -5048,7 +5116,7 @@ var renderNotices2 = (lock) => {
|
|
|
5048
5116
|
`);
|
|
5049
5117
|
};
|
|
5050
5118
|
var writeIfChanged2 = (path, text) => {
|
|
5051
|
-
const current =
|
|
5119
|
+
const current = existsSync13(path) ? safeRead(path) : null;
|
|
5052
5120
|
if (current === text)
|
|
5053
5121
|
return false;
|
|
5054
5122
|
writeFileSync10(path, text);
|
|
@@ -5727,7 +5795,7 @@ var getContext = (args) => {
|
|
|
5727
5795
|
};
|
|
5728
5796
|
var listScreens = (designDir) => {
|
|
5729
5797
|
const dir = join15(designDir, "screens");
|
|
5730
|
-
if (!
|
|
5798
|
+
if (!existsSync14(dir))
|
|
5731
5799
|
return [];
|
|
5732
5800
|
return readdirSync8(dir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith(".")).map((f2) => f2.slice(0, -3)).sort();
|
|
5733
5801
|
};
|
|
@@ -5743,7 +5811,7 @@ var writeMcpConfig = (ctx, port) => {
|
|
|
5743
5811
|
const path = join15(ctx.root, ".mcp.json");
|
|
5744
5812
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
5745
5813
|
let config = {};
|
|
5746
|
-
if (
|
|
5814
|
+
if (existsSync14(path)) {
|
|
5747
5815
|
try {
|
|
5748
5816
|
config = JSON.parse(readFileSync14(path, "utf8"));
|
|
5749
5817
|
} catch {
|
|
@@ -5777,7 +5845,7 @@ var init = async (ctx, args) => {
|
|
|
5777
5845
|
let created = 0;
|
|
5778
5846
|
for (const [rel, content] of files) {
|
|
5779
5847
|
const abs = join15(ctx.designDir, rel);
|
|
5780
|
-
if (
|
|
5848
|
+
if (existsSync14(abs)) {
|
|
5781
5849
|
note(`kept ${ctx.dirName}/${rel.replace(/\\/g, "/")}`);
|
|
5782
5850
|
continue;
|
|
5783
5851
|
}
|
|
@@ -5787,7 +5855,7 @@ var init = async (ctx, args) => {
|
|
|
5787
5855
|
}
|
|
5788
5856
|
const ignorePath = join15(ctx.root, ".lecodesignore");
|
|
5789
5857
|
const ignoreLine = `${ctx.dirName}/.snapshots/`;
|
|
5790
|
-
const current =
|
|
5858
|
+
const current = existsSync14(ignorePath) ? readFileSync14(ignorePath, "utf8") : "";
|
|
5791
5859
|
if (!current.split(/\r?\n/).includes(ignoreLine)) {
|
|
5792
5860
|
appendFileSync(ignorePath, (current && !current.endsWith(`
|
|
5793
5861
|
`) ? `
|
|
@@ -5909,7 +5977,7 @@ var snapshot = async (ctx, args) => {
|
|
|
5909
5977
|
}
|
|
5910
5978
|
};
|
|
5911
5979
|
var serve = async (ctx, args) => {
|
|
5912
|
-
if (!
|
|
5980
|
+
if (!existsSync14(ctx.designDir)) {
|
|
5913
5981
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
5914
5982
|
}
|
|
5915
5983
|
let designServer;
|
|
@@ -5982,7 +6050,7 @@ var serve = async (ctx, args) => {
|
|
|
5982
6050
|
openBrowser(server.url);
|
|
5983
6051
|
};
|
|
5984
6052
|
var arrange = async (ctx, args) => {
|
|
5985
|
-
if (!
|
|
6053
|
+
if (!existsSync14(ctx.designDir)) {
|
|
5986
6054
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
5987
6055
|
}
|
|
5988
6056
|
let designServer;
|
|
@@ -6018,7 +6086,7 @@ var share = async (ctx, args) => {
|
|
|
6018
6086
|
note("Turn it off with: lecodes design share --off");
|
|
6019
6087
|
};
|
|
6020
6088
|
var check = async (ctx, args) => {
|
|
6021
|
-
if (!
|
|
6089
|
+
if (!existsSync14(ctx.designDir)) {
|
|
6022
6090
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
6023
6091
|
}
|
|
6024
6092
|
let designServer;
|
|
@@ -6094,12 +6162,11 @@ var design = async (args) => {
|
|
|
6094
6162
|
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync15, watch, writeFileSync as writeFileSync12 } from "node:fs";
|
|
6095
6163
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
6096
6164
|
import { networkInterfaces } from "node:os";
|
|
6097
|
-
import { basename as basename7, join as
|
|
6165
|
+
import { basename as basename7, join as join16 } from "node:path";
|
|
6098
6166
|
|
|
6099
6167
|
// src/dev/devServer.ts
|
|
6100
6168
|
import { createServer as createServer2 } from "node:http";
|
|
6101
|
-
import { createReadStream,
|
|
6102
|
-
import { join as join16 } from "node:path";
|
|
6169
|
+
import { createReadStream, statSync as statSync4 } from "node:fs";
|
|
6103
6170
|
|
|
6104
6171
|
// src/dev/clientTemplates.ts
|
|
6105
6172
|
var DEV_SCREEN_TS = `const title = "LeCodes Dev"
|
|
@@ -6468,8 +6535,8 @@ var startDevServer = async (options) => {
|
|
|
6468
6535
|
} catch {
|
|
6469
6536
|
return sendText(res, 400, "text/plain", "Bad path");
|
|
6470
6537
|
}
|
|
6471
|
-
const abs =
|
|
6472
|
-
if (!
|
|
6538
|
+
const abs = resolveLocalPath(root, key);
|
|
6539
|
+
if (!abs || !statSync4(abs).isFile())
|
|
6473
6540
|
return sendText(res, 404, "text/plain", "Not found");
|
|
6474
6541
|
res.writeHead(200, { "content-type": contentType(key), "cache-control": "no-store" });
|
|
6475
6542
|
createReadStream(abs).pipe(res);
|
|
@@ -6552,14 +6619,14 @@ var pickLanAddress = () => {
|
|
|
6552
6619
|
return null;
|
|
6553
6620
|
};
|
|
6554
6621
|
var loadDevToken = (root) => {
|
|
6555
|
-
const path =
|
|
6622
|
+
const path = join16(root, LECODES_DIR, "dev.json");
|
|
6556
6623
|
try {
|
|
6557
6624
|
const token2 = JSON.parse(readFileSync15(path, "utf8")).token;
|
|
6558
6625
|
if (token2 && /^[a-z0-9]{8,}$/.test(token2))
|
|
6559
6626
|
return token2;
|
|
6560
6627
|
} catch {}
|
|
6561
6628
|
const token = randomBytes2(6).toString("hex");
|
|
6562
|
-
mkdirSync11(
|
|
6629
|
+
mkdirSync11(join16(root, LECODES_DIR), { recursive: true });
|
|
6563
6630
|
writeFileSync12(path, JSON.stringify({ token }, null, 2) + `
|
|
6564
6631
|
`);
|
|
6565
6632
|
return token;
|
|
@@ -6672,7 +6739,7 @@ ${result.error}`);
|
|
|
6672
6739
|
await printQr(server.url);
|
|
6673
6740
|
log(`Scan the QR with the LeCodes app, or open: ${c.bold(server.url)}`);
|
|
6674
6741
|
note(`Older desktop builds (no websocket bridge): ${server.url}?t=poll`);
|
|
6675
|
-
if (existsSync15(
|
|
6742
|
+
if (existsSync15(join16(root, LECODES_DIR, "manifest.json")))
|
|
6676
6743
|
note(`Token stored in ${LECODES_DIR}/dev.json (delete it to rotate the URL).`);
|
|
6677
6744
|
log("");
|
|
6678
6745
|
log(`Watching ${root} — save a file to hot-reload. Ctrl+C to stop.`);
|
|
@@ -6868,7 +6935,7 @@ var statusLabel = (e) => e.status === "added" ? c.green(" added ") : e.statu
|
|
|
6868
6935
|
|
|
6869
6936
|
// src/commands/init.ts
|
|
6870
6937
|
import { existsSync as existsSync16, mkdirSync as mkdirSync12, writeFileSync as writeFileSync13 } from "node:fs";
|
|
6871
|
-
import { basename as basename9, dirname as dirname10, join as
|
|
6938
|
+
import { basename as basename9, dirname as dirname10, join as join17, resolve as resolve5 } from "node:path";
|
|
6872
6939
|
var STARTER2 = `// Welcome to LeCodes — the whole SDK is available as globals, no imports needed.
|
|
6873
6940
|
// Run it live on a device with \`lecodes dev\`, or bundle it with \`lecodes compile -o app.js\`.
|
|
6874
6941
|
|
|
@@ -6970,7 +7037,7 @@ var init2 = async (args) => {
|
|
|
6970
7037
|
mkdirSync12(root, { recursive: true });
|
|
6971
7038
|
let created = 0;
|
|
6972
7039
|
const write = (rel, content) => {
|
|
6973
|
-
const abs =
|
|
7040
|
+
const abs = join17(root, rel);
|
|
6974
7041
|
if (existsSync16(abs)) {
|
|
6975
7042
|
note(`kept ${rel}`);
|
|
6976
7043
|
return;
|
|
@@ -7001,7 +7068,7 @@ var init2 = async (args) => {
|
|
|
7001
7068
|
|
|
7002
7069
|
// src/commands/link.ts
|
|
7003
7070
|
import { existsSync as existsSync17 } from "node:fs";
|
|
7004
|
-
import { basename as basename11, join as
|
|
7071
|
+
import { basename as basename11, join as join18, resolve as resolve6 } from "node:path";
|
|
7005
7072
|
|
|
7006
7073
|
// src/commands/push.ts
|
|
7007
7074
|
import { basename as basename10 } from "node:path";
|
|
@@ -7164,7 +7231,7 @@ var link = async (args) => {
|
|
|
7164
7231
|
const root = dirArg ? resolve6(dirArg) : process.cwd();
|
|
7165
7232
|
if (!existsSync17(root))
|
|
7166
7233
|
throw new CliError(`No such directory: ${root}`);
|
|
7167
|
-
if (existsSync17(
|
|
7234
|
+
if (existsSync17(join18(root, LECODES_DIR, "manifest.json")) && !flagBool(args, "force")) {
|
|
7168
7235
|
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.");
|
|
7169
7236
|
}
|
|
7170
7237
|
let enclosing = null;
|
|
@@ -7481,7 +7548,7 @@ var render = async (args) => {
|
|
|
7481
7548
|
|
|
7482
7549
|
// src/commands/pull.ts
|
|
7483
7550
|
import { existsSync as existsSync18, mkdirSync as mkdirSync14, rmSync as rmSync3, writeFileSync as writeFileSync15 } from "node:fs";
|
|
7484
|
-
import { dirname as dirname12, join as
|
|
7551
|
+
import { dirname as dirname12, join as join19 } from "node:path";
|
|
7485
7552
|
var pull = async (args) => {
|
|
7486
7553
|
const root = findProjectRoot(process.cwd());
|
|
7487
7554
|
const manifest = readManifest(root);
|
|
@@ -7501,7 +7568,7 @@ var pull = async (args) => {
|
|
|
7501
7568
|
const remotePaths = new Set([...buildPaths(project.assets).entries()].filter(([id]) => project.assets.find((a) => a.id === id)?.type !== "folder").map(([, path]) => path));
|
|
7502
7569
|
for (const path of Object.keys(manifest.files)) {
|
|
7503
7570
|
if (!remotePaths.has(path)) {
|
|
7504
|
-
const abs =
|
|
7571
|
+
const abs = join19(root, ...path.replace(/^\//, "").split("/"));
|
|
7505
7572
|
if (existsSync18(abs))
|
|
7506
7573
|
rmSync3(abs);
|
|
7507
7574
|
}
|
|
@@ -7540,7 +7607,7 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
7540
7607
|
const files = { ...manifest.files };
|
|
7541
7608
|
for (const asset of targets) {
|
|
7542
7609
|
const key = pathById.get(asset.id);
|
|
7543
|
-
const abs =
|
|
7610
|
+
const abs = join19(root, ...key.replace(/^\//, "").split("/"));
|
|
7544
7611
|
mkdirSync14(dirname12(abs), { recursive: true });
|
|
7545
7612
|
let sha;
|
|
7546
7613
|
if (asset.type === "file") {
|
|
@@ -7564,19 +7631,19 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
7564
7631
|
|
|
7565
7632
|
// src/commands/scene.ts
|
|
7566
7633
|
import { existsSync as existsSync20, readFileSync as readFileSync20, readdirSync as readdirSync9, statSync as statSync5, writeFileSync as writeFileSync16 } from "node:fs";
|
|
7567
|
-
import { basename as basename12, dirname as dirname13, join as
|
|
7634
|
+
import { basename as basename12, dirname as dirname13, join as join21, resolve as resolve8 } from "node:path";
|
|
7568
7635
|
|
|
7569
7636
|
// src/compile/sceneCompile.ts
|
|
7570
7637
|
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
|
|
7571
|
-
import { join as
|
|
7638
|
+
import { join as join20 } from "node:path";
|
|
7572
7639
|
var TEXT_EXT = /\.(ts|js|json|svg|txt|md)$/i;
|
|
7573
7640
|
var rel = (key) => key.replace(/^\//, "");
|
|
7574
7641
|
var resolveHarness = (loadSceneHarness2) => {
|
|
7575
|
-
const inRepo =
|
|
7642
|
+
const inRepo = join20(distRoot, "..", "projects", "src", "scene-editor");
|
|
7576
7643
|
try {
|
|
7577
7644
|
return loadSceneHarness2(existsSync19(inRepo) ? inRepo : undefined);
|
|
7578
7645
|
} catch {
|
|
7579
|
-
const vendored =
|
|
7646
|
+
const vendored = join20(distRoot, "runtime", "scene-harness.json");
|
|
7580
7647
|
if (existsSync19(vendored))
|
|
7581
7648
|
return JSON.parse(readFileSync19(vendored, "utf8"));
|
|
7582
7649
|
throw new CliError("scene-editor harness sources not found — reinstall the CLI or set LECODES_SCENE_HARNESS_DIR.");
|
|
@@ -7642,7 +7709,7 @@ var getContext2 = (args) => {
|
|
|
7642
7709
|
return { root, manifest, name: manifest?.name ?? basename12(root) };
|
|
7643
7710
|
};
|
|
7644
7711
|
var writeMcpConfig2 = (root, port) => {
|
|
7645
|
-
const path =
|
|
7712
|
+
const path = join21(root, ".mcp.json");
|
|
7646
7713
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
7647
7714
|
let config = {};
|
|
7648
7715
|
if (existsSync20(path)) {
|
|
@@ -7669,7 +7736,7 @@ var countScenes = (dir) => {
|
|
|
7669
7736
|
for (const name of readdirSync9(dir)) {
|
|
7670
7737
|
if (name === "node_modules" || name.startsWith("."))
|
|
7671
7738
|
continue;
|
|
7672
|
-
const full =
|
|
7739
|
+
const full = join21(dir, name);
|
|
7673
7740
|
if (statSync5(full).isDirectory())
|
|
7674
7741
|
n += countScenes(full);
|
|
7675
7742
|
else if (name.endsWith(".scene.ts"))
|
|
@@ -8036,13 +8103,13 @@ var types = async (args) => {
|
|
|
8036
8103
|
// src/index.ts
|
|
8037
8104
|
import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync2 } from "node:fs";
|
|
8038
8105
|
import { createRequire as createRequire4 } from "node:module";
|
|
8039
|
-
import { delimiter as delimiter2, dirname as dirname16, join as
|
|
8106
|
+
import { delimiter as delimiter2, dirname as dirname16, join as join23 } from "node:path";
|
|
8040
8107
|
|
|
8041
8108
|
// src/commands/install.ts
|
|
8042
8109
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8043
8110
|
import { appendFileSync as appendFileSync2, chmodSync, cpSync as cpSync2, existsSync as existsSync22, mkdirSync as mkdirSync15, readFileSync as readFileSync22, realpathSync, rmSync as rmSync4, symlinkSync } from "node:fs";
|
|
8044
8111
|
import { homedir as homedir3 } from "node:os";
|
|
8045
|
-
import { basename as basename13, delimiter, dirname as dirname15, join as
|
|
8112
|
+
import { basename as basename13, delimiter, dirname as dirname15, join as join22, resolve as resolve11, sep as sep2 } from "node:path";
|
|
8046
8113
|
var isWin = process.platform === "win32";
|
|
8047
8114
|
var HOME = homedir3();
|
|
8048
8115
|
var safeRealpath = (p) => {
|
|
@@ -8068,10 +8135,10 @@ var install = async (args) => {
|
|
|
8068
8135
|
const bundle = dirname15(process.execPath);
|
|
8069
8136
|
const exeName = basename13(process.execPath);
|
|
8070
8137
|
const chiselName = isWin ? "chisel.exe" : "chisel";
|
|
8071
|
-
if (!existsSync22(
|
|
8138
|
+
if (!existsSync22(join22(bundle, "runtime")) || !existsSync22(join22(bundle, chiselName))) {
|
|
8072
8139
|
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.");
|
|
8073
8140
|
}
|
|
8074
|
-
const companions = [exeName, chiselName, "runtime", "README.txt"].filter((f2) => existsSync22(
|
|
8141
|
+
const companions = [exeName, chiselName, "runtime", "README.txt"].filter((f2) => existsSync22(join22(bundle, f2)));
|
|
8075
8142
|
if (isWin)
|
|
8076
8143
|
return installWindows(args, bundle, companions);
|
|
8077
8144
|
return installUnix(args, bundle, companions);
|
|
@@ -8081,9 +8148,9 @@ var copyBundle = (bundle, target, companions) => {
|
|
|
8081
8148
|
if (safeRealpath(target) === safeRealpath(bundle))
|
|
8082
8149
|
return;
|
|
8083
8150
|
for (const f2 of companions) {
|
|
8084
|
-
const dest =
|
|
8151
|
+
const dest = join22(target, f2);
|
|
8085
8152
|
rmSync4(dest, { recursive: true, force: true });
|
|
8086
|
-
cpSync2(
|
|
8153
|
+
cpSync2(join22(bundle, f2), dest, { recursive: true });
|
|
8087
8154
|
}
|
|
8088
8155
|
};
|
|
8089
8156
|
var permError = (e, dir, system) => {
|
|
@@ -8095,34 +8162,34 @@ var permError = (e, dir, system) => {
|
|
|
8095
8162
|
};
|
|
8096
8163
|
var installUnix = (args, bundle, companions) => {
|
|
8097
8164
|
const system = flagBool(args, "system");
|
|
8098
|
-
const libDir = resolve11(flagStr(args, "dir") ?? (system ? "/usr/local/lib/lecodes-cli" :
|
|
8099
|
-
const binDir = resolve11(flagStr(args, "bin") ?? (system ? "/usr/local/bin" :
|
|
8100
|
-
const link2 =
|
|
8165
|
+
const libDir = resolve11(flagStr(args, "dir") ?? (system ? "/usr/local/lib/lecodes-cli" : join22(HOME, ".local", "lib", "lecodes-cli")));
|
|
8166
|
+
const binDir = resolve11(flagStr(args, "bin") ?? (system ? "/usr/local/bin" : join22(HOME, ".local", "bin")));
|
|
8167
|
+
const link2 = join22(binDir, "lecodes");
|
|
8101
8168
|
try {
|
|
8102
8169
|
copyBundle(bundle, libDir, companions);
|
|
8103
|
-
chmodSync(
|
|
8104
|
-
chmodSync(
|
|
8170
|
+
chmodSync(join22(libDir, "lecodes"), 493);
|
|
8171
|
+
chmodSync(join22(libDir, "chisel"), 493);
|
|
8105
8172
|
} catch (e) {
|
|
8106
8173
|
throw permError(e, libDir, system);
|
|
8107
8174
|
}
|
|
8108
8175
|
try {
|
|
8109
8176
|
mkdirSync15(binDir, { recursive: true });
|
|
8110
8177
|
rmSync4(link2, { force: true });
|
|
8111
|
-
symlinkSync(
|
|
8178
|
+
symlinkSync(join22(libDir, "lecodes"), link2);
|
|
8112
8179
|
} catch (e) {
|
|
8113
8180
|
throw permError(e, binDir, system);
|
|
8114
8181
|
}
|
|
8115
8182
|
success(`Installed to ${c.bold(libDir)}`);
|
|
8116
|
-
log(` ${c.dim(link2 + " → " +
|
|
8183
|
+
log(` ${c.dim(link2 + " → " + join22(libDir, "lecodes"))}`);
|
|
8117
8184
|
finishPathUnix(args, binDir);
|
|
8118
8185
|
};
|
|
8119
8186
|
var shellRc = () => {
|
|
8120
8187
|
const shell = basename13(process.env.SHELL ?? "");
|
|
8121
8188
|
if (shell === "zsh")
|
|
8122
|
-
return { file:
|
|
8189
|
+
return { file: join22(HOME, ".zshrc"), name: "~/.zshrc" };
|
|
8123
8190
|
if (shell === "bash")
|
|
8124
|
-
return { file:
|
|
8125
|
-
return { file:
|
|
8191
|
+
return { file: join22(HOME, ".bashrc"), name: "~/.bashrc" };
|
|
8192
|
+
return { file: join22(HOME, ".profile"), name: "~/.profile" };
|
|
8126
8193
|
};
|
|
8127
8194
|
var PATH_MARKER = "# Added by `lecodes install`";
|
|
8128
8195
|
var appendPathToShellRc = (binDir) => {
|
|
@@ -8167,7 +8234,7 @@ var finishPathUnix = (args, binDir) => {
|
|
|
8167
8234
|
log(` • or install system-wide (no PATH edit): ${c.bold("sudo lecodes install --system")}`);
|
|
8168
8235
|
};
|
|
8169
8236
|
var installWindows = (args, bundle, companions) => {
|
|
8170
|
-
const target = resolve11(flagStr(args, "dir") ??
|
|
8237
|
+
const target = resolve11(flagStr(args, "dir") ?? join22(process.env.LOCALAPPDATA ?? join22(HOME, "AppData", "Local"), "Programs", "lecodes-cli"));
|
|
8171
8238
|
try {
|
|
8172
8239
|
copyBundle(bundle, target, companions);
|
|
8173
8240
|
} catch (e) {
|
|
@@ -8206,7 +8273,7 @@ var addToUserPathWindows = (dir) => {
|
|
|
8206
8273
|
var STANDALONE = (() => {
|
|
8207
8274
|
const dir = dirname16(process.execPath);
|
|
8208
8275
|
const chisel = process.platform === "win32" ? "chisel.exe" : "chisel";
|
|
8209
|
-
return existsSync23(
|
|
8276
|
+
return existsSync23(join23(dir, "runtime")) && existsSync23(join23(dir, chisel));
|
|
8210
8277
|
})();
|
|
8211
8278
|
var INSTALLED = STANDALONE && (() => {
|
|
8212
8279
|
const exe = process.platform === "win32" ? "lecodes.exe" : "lecodes";
|
|
@@ -8221,7 +8288,7 @@ var INSTALLED = STANDALONE && (() => {
|
|
|
8221
8288
|
if (!d)
|
|
8222
8289
|
return false;
|
|
8223
8290
|
try {
|
|
8224
|
-
const cand =
|
|
8291
|
+
const cand = join23(d, exe);
|
|
8225
8292
|
return existsSync23(cand) && realpathSync2(cand) === self;
|
|
8226
8293
|
} catch {
|
|
8227
8294
|
return false;
|
|
@@ -8408,7 +8475,7 @@ var peerVersion = (name, probe) => {
|
|
|
8408
8475
|
const require2 = createRequire4(import.meta.url);
|
|
8409
8476
|
let dir = dirname16(require2.resolve(probe));
|
|
8410
8477
|
for (let depth = 0;depth < 16; depth++) {
|
|
8411
|
-
const manifest =
|
|
8478
|
+
const manifest = join23(dir, "package.json");
|
|
8412
8479
|
if (existsSync23(manifest)) {
|
|
8413
8480
|
const parsed = JSON.parse(readFileSync23(manifest, "utf8"));
|
|
8414
8481
|
if (parsed.name === name)
|