lecodes-cli 0.10.1 → 0.10.3
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 +156 -97
- package/package.json +1 -1
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk/canvas/Canvas.ts +2 -2
- package/runtime/sdk/g2/Texture2D.ts +1 -1
- package/runtime/sdk/inject.ts +1 -0
- package/runtime/sdk/plugins/push.ts +132 -0
- package/runtime/sdk/runtime/app.ts +13 -0
- package/runtime/sdk/runtime/fetch.ts +9 -3
- package/runtime/sdk/runtime/share.ts +1 -1
- package/runtime/sdk/ui/UIInput.ts +20 -1
- package/runtime/sdk-types.json +1 -1
- package/runtime/sdk/compile/aspectMacro.ts +0 -42
- package/runtime/sdk/compile/assetMacro.ts +0 -45
- package/runtime/sdk/compile/bundler.ts +0 -239
- package/runtime/sdk/compile/compileProject.ts +0 -104
- package/runtime/sdk/compile/detectEntry.ts +0 -125
- package/runtime/sdk/compile/fontMacro.ts +0 -459
- package/runtime/sdk/compile/fontRegistry.ts +0 -78
- package/runtime/sdk/compile/header.ts +0 -51
- package/runtime/sdk/compile/index.ts +0 -38
- package/runtime/sdk/compile/libraryImports.ts +0 -52
- package/runtime/sdk/compile/sceneEditor.ts +0 -78
- package/runtime/sdk/compile/sfnt.ts +0 -98
- package/runtime/sdk/compile/sourcemap.ts +0 -25
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.");
|
|
@@ -462,11 +497,11 @@ var init_compileProject = __esm(() => {
|
|
|
462
497
|
});
|
|
463
498
|
|
|
464
499
|
// ../sdk/src/compile/sceneEditor.ts
|
|
465
|
-
import { existsSync as
|
|
500
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "node:fs";
|
|
466
501
|
import { join as join8 } from "node:path";
|
|
467
502
|
var SCENE_HARNESS_DIR = "./.scene-editor", SCENE_ENTRY_PATH = "./.scene-entry.ts", loadSceneHarness = (fallbackDir) => {
|
|
468
503
|
const override = process.env.LECODES_SCENE_HARNESS_DIR;
|
|
469
|
-
const dir = override &&
|
|
504
|
+
const dir = override && existsSync6(override) ? override : fallbackDir && existsSync6(fallbackDir) ? fallbackDir : null;
|
|
470
505
|
if (!dir)
|
|
471
506
|
throw new Error("scene-editor harness sources not found (set LECODES_SCENE_HARNESS_DIR)");
|
|
472
507
|
const out = {};
|
|
@@ -1043,9 +1078,11 @@ __export(exports_compile, {
|
|
|
1043
1078
|
scanModulesFallback: () => scanModulesFallback,
|
|
1044
1079
|
scanModulesChisel: () => scanModulesChisel,
|
|
1045
1080
|
scanFontCalls: () => scanFontCalls,
|
|
1081
|
+
sanitizeAssetName: () => sanitizeAssetName,
|
|
1046
1082
|
parseSfnt: () => parseSfnt,
|
|
1047
1083
|
offsetSourceMap: () => offsetSourceMap,
|
|
1048
1084
|
loadSceneHarness: () => loadSceneHarness,
|
|
1085
|
+
isCanonicalAssetName: () => isCanonicalAssetName,
|
|
1049
1086
|
inlineSourceMapComment: () => inlineSourceMapComment,
|
|
1050
1087
|
fontRegistryBase: () => fontRegistryBase,
|
|
1051
1088
|
faceFileName: () => faceFileName,
|
|
@@ -1066,6 +1103,7 @@ __export(exports_compile, {
|
|
|
1066
1103
|
var init_compile = __esm(() => {
|
|
1067
1104
|
init_bundler();
|
|
1068
1105
|
init_detectEntry();
|
|
1106
|
+
init_assetName();
|
|
1069
1107
|
init_compileProject();
|
|
1070
1108
|
init_sceneEditor();
|
|
1071
1109
|
init_fontMacro();
|
|
@@ -2091,7 +2129,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
2091
2129
|
// package.json
|
|
2092
2130
|
var package_default = {
|
|
2093
2131
|
name: "lecodes-cli",
|
|
2094
|
-
version: "0.10.
|
|
2132
|
+
version: "0.10.3",
|
|
2095
2133
|
dependencies: {
|
|
2096
2134
|
"@letary/chisel": "^0.6.0"
|
|
2097
2135
|
},
|
|
@@ -2150,7 +2188,7 @@ var package_default = {
|
|
|
2150
2188
|
|
|
2151
2189
|
// src/commands/app.ts
|
|
2152
2190
|
import { execFileSync } from "node:child_process";
|
|
2153
|
-
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";
|
|
2154
2192
|
import { homedir as homedir2 } from "node:os";
|
|
2155
2193
|
import { basename as basename4, dirname as dirname7, join as join11, resolve as resolve2 } from "node:path";
|
|
2156
2194
|
|
|
@@ -2159,6 +2197,7 @@ import { dirname, join } from "node:path";
|
|
|
2159
2197
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2160
2198
|
|
|
2161
2199
|
// src/util.ts
|
|
2200
|
+
init_assetName();
|
|
2162
2201
|
import { createHash } from "node:crypto";
|
|
2163
2202
|
import { createInterface } from "node:readline";
|
|
2164
2203
|
var useColor = process.stdout.isTTY && process.env.NO_COLOR === undefined;
|
|
@@ -2204,7 +2243,10 @@ var toKey = (path) => {
|
|
|
2204
2243
|
const parts = path.replace(/\\/g, "/").split("/").map((p) => p.trim()).filter((p) => p && p !== ".");
|
|
2205
2244
|
if (parts.some((p) => p === ".."))
|
|
2206
2245
|
throw new CliError(`Unsafe path: ${path}`);
|
|
2207
|
-
|
|
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("/");
|
|
2208
2250
|
};
|
|
2209
2251
|
var prompt = (question, fallback) => new Promise((resolve) => {
|
|
2210
2252
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -2493,7 +2535,8 @@ import { readFileSync as readFileSync5 } from "node:fs";
|
|
|
2493
2535
|
import { basename } from "node:path";
|
|
2494
2536
|
|
|
2495
2537
|
// src/localFiles.ts
|
|
2496
|
-
|
|
2538
|
+
init_assetName();
|
|
2539
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync4 } from "node:fs";
|
|
2497
2540
|
import { join as join4, relative } from "node:path";
|
|
2498
2541
|
var SKIP_DIRS = new Set([".lecodes", ".git", "node_modules"]);
|
|
2499
2542
|
var SKIP_FILES = new Set(["tsconfig.json", "jsconfig.json", ".gitignore", ".lecodesignore", ".DS_Store"]);
|
|
@@ -2575,6 +2618,23 @@ var scanLocal = (root, opts = {}) => {
|
|
|
2575
2618
|
walk(root, false);
|
|
2576
2619
|
return { files, dirs, ignored };
|
|
2577
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
|
+
};
|
|
2578
2638
|
var scanProject = (root, manifest) => scanLocal(root, { ignore: loadIgnore(root), tracked: new Set(Object.keys(manifest.files)) });
|
|
2579
2639
|
var diffLocal = (manifest, scan) => {
|
|
2580
2640
|
const added = [];
|
|
@@ -2698,12 +2758,12 @@ var collectLocalEntries = (root, manifest, assetBase) => {
|
|
|
2698
2758
|
};
|
|
2699
2759
|
|
|
2700
2760
|
// src/compile/projectCompile.ts
|
|
2701
|
-
import { existsSync as
|
|
2761
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
2702
2762
|
import { createRequire as createRequire3 } from "node:module";
|
|
2703
2763
|
import { dirname as dirname5, join as join9 } from "node:path";
|
|
2704
2764
|
|
|
2705
2765
|
// src/distRoot.ts
|
|
2706
|
-
import { existsSync as
|
|
2766
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
2707
2767
|
import { dirname as dirname3, join as join6 } from "node:path";
|
|
2708
2768
|
import { fileURLToPath } from "node:url";
|
|
2709
2769
|
var distRoot = (() => {
|
|
@@ -2712,7 +2772,7 @@ var distRoot = (() => {
|
|
|
2712
2772
|
dirname3(process.execPath)
|
|
2713
2773
|
];
|
|
2714
2774
|
for (const c2 of candidates)
|
|
2715
|
-
if (
|
|
2775
|
+
if (existsSync4(join6(c2, "runtime")))
|
|
2716
2776
|
return c2;
|
|
2717
2777
|
return candidates[0];
|
|
2718
2778
|
})();
|
|
@@ -2720,7 +2780,7 @@ var distRoot = (() => {
|
|
|
2720
2780
|
// src/compile/projectCompile.ts
|
|
2721
2781
|
init_compile();
|
|
2722
2782
|
var vendoredInject = join9(distRoot, "runtime", "sdk", "inject.ts");
|
|
2723
|
-
if (
|
|
2783
|
+
if (existsSync7(vendoredInject))
|
|
2724
2784
|
process.env.LECODES_SDK_INJECT = vendoredInject;
|
|
2725
2785
|
var resolveChiselBin2 = () => {
|
|
2726
2786
|
if (process.env.LECODES_CHISEL_BIN)
|
|
@@ -2731,7 +2791,7 @@ var resolveChiselBin2 = () => {
|
|
|
2731
2791
|
return fromPkg;
|
|
2732
2792
|
} catch {}
|
|
2733
2793
|
const local = join9(dirname5(process.execPath), process.platform === "win32" ? "chisel.exe" : "chisel");
|
|
2734
|
-
return
|
|
2794
|
+
return existsSync7(local) ? local : null;
|
|
2735
2795
|
};
|
|
2736
2796
|
var chiselBin = resolveChiselBin2();
|
|
2737
2797
|
if (chiselBin)
|
|
@@ -2759,7 +2819,7 @@ var compileProject2 = (opts) => compileProject({
|
|
|
2759
2819
|
// src/compile/fonts.ts
|
|
2760
2820
|
init_compile();
|
|
2761
2821
|
import { createHash as createHash2 } from "node:crypto";
|
|
2762
|
-
import { existsSync as
|
|
2822
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2763
2823
|
import { dirname as dirname6, join as join10 } from "node:path";
|
|
2764
2824
|
var applyProjectFonts = async (entries, opts) => {
|
|
2765
2825
|
const registry = (opts.registry ?? fontRegistryBase()).replace(/\/+$/, "");
|
|
@@ -2781,7 +2841,7 @@ var applyProjectFonts = async (entries, opts) => {
|
|
|
2781
2841
|
const rel = `assets/fonts/${face.fileName}`;
|
|
2782
2842
|
const abs = join10(vendorDir, rel);
|
|
2783
2843
|
const entryPath = `${opts.vendorPrefix ?? ""}/${rel}`;
|
|
2784
|
-
if (!
|
|
2844
|
+
if (!existsSync8(abs))
|
|
2785
2845
|
await downloadFace(registry, vendorDir, face, rel, abs);
|
|
2786
2846
|
if (!byPath().has(entryPath.replace(/^\//, ""))) {
|
|
2787
2847
|
entries.push(opts.makeResourceEntry?.(entryPath, abs) ?? { path: entryPath, type: "resource", absPath: abs });
|
|
@@ -3733,7 +3793,7 @@ var FIRST_PARTY_PLUGINS = {
|
|
|
3733
3793
|
"qr-scanner": "letary/lecodes-plugins"
|
|
3734
3794
|
};
|
|
3735
3795
|
var readJson = (path) => {
|
|
3736
|
-
if (!
|
|
3796
|
+
if (!existsSync9(path))
|
|
3737
3797
|
return null;
|
|
3738
3798
|
try {
|
|
3739
3799
|
return JSON.parse(readFileSync10(path, "utf8"));
|
|
@@ -3773,7 +3833,7 @@ var fetchLatestSdkVersion = async () => {
|
|
|
3773
3833
|
};
|
|
3774
3834
|
var shellSdkVersion = (iosDir) => {
|
|
3775
3835
|
const path = join11(iosDir, "LeCodesRuntime", "Package.swift");
|
|
3776
|
-
if (!
|
|
3836
|
+
if (!existsSync9(path))
|
|
3777
3837
|
return null;
|
|
3778
3838
|
const m = /lecodes-ios-sdk\.git",\s*(?:exact|from):\s*"([^"]+)"/.exec(readFileSync10(path, "utf8"));
|
|
3779
3839
|
return m && VERSION_RE.test(m[1]) ? m[1] : null;
|
|
@@ -3804,7 +3864,7 @@ var ensureRepo = (repo, wantTag, lock) => {
|
|
|
3804
3864
|
}
|
|
3805
3865
|
const cache = join11(homedir2(), ".lecodes", "plugins", repo.replace("/", "__"));
|
|
3806
3866
|
const url = `https://github.com/${repo}.git`;
|
|
3807
|
-
if (!
|
|
3867
|
+
if (!existsSync9(join11(cache, ".git"))) {
|
|
3808
3868
|
mkdirSync5(dirname7(cache), { recursive: true });
|
|
3809
3869
|
note(`Cloning ${url}…`);
|
|
3810
3870
|
git(dirname7(cache), "clone", "--quiet", url, cache);
|
|
@@ -3877,7 +3937,7 @@ var appInit = async (args) => {
|
|
|
3877
3937
|
}
|
|
3878
3938
|
const root = projectRoot();
|
|
3879
3939
|
const iosDir = join11(root, "ios");
|
|
3880
|
-
if (
|
|
3940
|
+
if (existsSync9(iosDir)) {
|
|
3881
3941
|
throw new CliError("ios/ already exists — run `lecodes app sync` to update it.");
|
|
3882
3942
|
}
|
|
3883
3943
|
const existing = readJson(join11(root, "app.json")) ?? {};
|
|
@@ -3905,7 +3965,7 @@ var appInit = async (args) => {
|
|
|
3905
3965
|
writeJson(join11(root, "app.json"), config);
|
|
3906
3966
|
log(`${c.green("written")} app.json`);
|
|
3907
3967
|
const ignorePath = join11(root, ".lecodesignore");
|
|
3908
|
-
const ignore =
|
|
3968
|
+
const ignore = existsSync9(ignorePath) ? readFileSync10(ignorePath, "utf8") : DEFAULT_IGNORE_FILE;
|
|
3909
3969
|
if (!/^ios\/$/m.test(ignore)) {
|
|
3910
3970
|
writeFileSync7(ignorePath, ignore.replace(/\n*$/, `
|
|
3911
3971
|
`) + `
|
|
@@ -3982,7 +4042,7 @@ var ensureSdkResourcesBundle = async (sdkVersion) => {
|
|
|
3982
4042
|
}
|
|
3983
4043
|
const dir = join11(homedir2(), ".lecodes", "sdk-resources", sdkVersion);
|
|
3984
4044
|
const bundle = join11(dir, "LeCodesSDKResources.bundle");
|
|
3985
|
-
if (
|
|
4045
|
+
if (existsSync9(bundle))
|
|
3986
4046
|
return bundle;
|
|
3987
4047
|
const url = `https://github.com/${SDK_REPO}/releases/download/${sdkVersion}/LeCodesSDKResources.bundle.zip`;
|
|
3988
4048
|
note(`Downloading LeCodesSDKResources.bundle (SDK ${sdkVersion})…`);
|
|
@@ -3994,7 +4054,7 @@ var ensureSdkResourcesBundle = async (sdkVersion) => {
|
|
|
3994
4054
|
writeFileSync7(zip, new Uint8Array(await res.arrayBuffer()));
|
|
3995
4055
|
execFileSync("ditto", ["-x", "-k", zip, dir]);
|
|
3996
4056
|
rmSync(zip);
|
|
3997
|
-
if (!
|
|
4057
|
+
if (!existsSync9(bundle))
|
|
3998
4058
|
throw new CliError(`No LeCodesSDKResources.bundle inside the release asset ${url}`);
|
|
3999
4059
|
return bundle;
|
|
4000
4060
|
};
|
|
@@ -4021,7 +4081,7 @@ var appSync = async (_args) => {
|
|
|
4021
4081
|
const root = projectRoot();
|
|
4022
4082
|
const config = readJson(join11(root, "app.json"));
|
|
4023
4083
|
const iosDir = join11(root, "ios");
|
|
4024
|
-
if (!config?.ios || !
|
|
4084
|
+
if (!config?.ios || !existsSync9(iosDir)) {
|
|
4025
4085
|
throw new CliError("No iOS shell here — run `lecodes app init ios` first.");
|
|
4026
4086
|
}
|
|
4027
4087
|
const requestedVariant = config.ios.variant ?? "auto";
|
|
@@ -4046,7 +4106,7 @@ var appSync = async (_args) => {
|
|
|
4046
4106
|
if (!module || !register)
|
|
4047
4107
|
throw new CliError(`Plugin "${id}": manifest ios.module / ios.register missing`);
|
|
4048
4108
|
const src = join11(plugin.dir, ios.sources ?? "ios");
|
|
4049
|
-
if (!
|
|
4109
|
+
if (!existsSync9(src))
|
|
4050
4110
|
throw new CliError(`Plugin "${id}": sources dir ${src} missing`);
|
|
4051
4111
|
const dest = join11(sourcesDir, module);
|
|
4052
4112
|
rmSync(dest, { recursive: true, force: true });
|
|
@@ -4062,7 +4122,7 @@ var appSync = async (_args) => {
|
|
|
4062
4122
|
log(`${c.green("plugin")} ${id}@${plugin.lock.version} (${plugin.lock.tag} → Sources/${module})`);
|
|
4063
4123
|
}
|
|
4064
4124
|
const keep = new Set(["LeCodesRuntime", ...runtimePlugins.map((p) => p.module)]);
|
|
4065
|
-
for (const entry of
|
|
4125
|
+
for (const entry of existsSync9(sourcesDir) ? readdirSync4(sourcesDir) : []) {
|
|
4066
4126
|
if (!keep.has(entry) && statSync2(join11(sourcesDir, entry)).isDirectory()) {
|
|
4067
4127
|
rmSync(join11(sourcesDir, entry), { recursive: true });
|
|
4068
4128
|
log(`${c.yellow("removed")} ios/LeCodesRuntime/Sources/${entry} (plugin uninstalled)`);
|
|
@@ -4136,7 +4196,7 @@ var appSync = async (_args) => {
|
|
|
4136
4196
|
writeFileSync7(join11(iosDir, "App", "Info.plist"), infoPlistTemplate(mergedKeys, updateUrl));
|
|
4137
4197
|
if (updateUrl)
|
|
4138
4198
|
log(`${c.green("update")} OTA source ${updateUrl} — checked natively at launch, new code applies next launch`);
|
|
4139
|
-
if (pluginSpecs.length > 0 ||
|
|
4199
|
+
if (pluginSpecs.length > 0 || existsSync9(lockPath))
|
|
4140
4200
|
writeJson(lockPath, { plugins: newLock });
|
|
4141
4201
|
const pbxPath = join11(iosDir, "App.xcodeproj", "project.pbxproj");
|
|
4142
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};`);
|
|
@@ -4226,7 +4286,7 @@ var exportOptionsPlist = (method, teamId, destination) => `<?xml version="1.0" e
|
|
|
4226
4286
|
var requireShell = () => {
|
|
4227
4287
|
const root = projectRoot();
|
|
4228
4288
|
const config = readJson(join11(root, "app.json"));
|
|
4229
|
-
if (!config?.ios || !
|
|
4289
|
+
if (!config?.ios || !existsSync9(join11(root, "ios"))) {
|
|
4230
4290
|
throw new CliError("No iOS shell here — run `lecodes app init ios` first.");
|
|
4231
4291
|
}
|
|
4232
4292
|
return { root, config };
|
|
@@ -4302,7 +4362,7 @@ var appUpdate = async (args) => {
|
|
|
4302
4362
|
log(`${c.green("plugin")} ${id} ${entry?.tag ?? "—"} → ${c.bold(tag)}`);
|
|
4303
4363
|
changed = true;
|
|
4304
4364
|
}
|
|
4305
|
-
if (!checkOnly &&
|
|
4365
|
+
if (!checkOnly && existsSync9(lockPath))
|
|
4306
4366
|
writeJson(lockPath, { plugins: kept });
|
|
4307
4367
|
}
|
|
4308
4368
|
log("");
|
|
@@ -4336,18 +4396,18 @@ var appDoctor = async (_args) => {
|
|
|
4336
4396
|
check(xcodeVersion !== "", `Xcode CLI (${xcodeVersion || "not found"})`, "install Xcode + command line tools");
|
|
4337
4397
|
check(!!config.ios.teamId, "Development team set", "lecodes app init wrote app.json — fill ios.teamId", false);
|
|
4338
4398
|
const iconDir = join11(root, "ios", "App", "Assets.xcassets", "AppIcon.appiconset");
|
|
4339
|
-
const hasIcon =
|
|
4399
|
+
const hasIcon = existsSync9(iconDir) && readdirSync4(iconDir).some((f2) => f2.endsWith(".png"));
|
|
4340
4400
|
check(hasIcon, "App icon present", "drop a 1024×1024 PNG into ios/App/Assets.xcassets/AppIcon.appiconset/ (App Store requires it)", false);
|
|
4341
4401
|
const bundle = join11(root, "ios", "App", "Resources", "app.js");
|
|
4342
|
-
check(
|
|
4402
|
+
check(existsSync9(bundle), "Bundled app.js", "run `lecodes app sync`");
|
|
4343
4403
|
const requestedVariant = config.ios.variant ?? "auto";
|
|
4344
4404
|
const validVariant = requestedVariant === "auto" || SDK_VARIANTS.includes(requestedVariant);
|
|
4345
4405
|
check(validVariant, `ios.variant "${requestedVariant}"`, `use "auto" or one of ${SDK_VARIANTS.join(", ")}`);
|
|
4346
|
-
if (
|
|
4406
|
+
if (existsSync9(bundle) && validVariant) {
|
|
4347
4407
|
const { variant } = resolveVariant(requestedVariant, readFileSync10(bundle, "utf8"));
|
|
4348
4408
|
const pkg = readFileSync10(join11(root, "ios", "LeCodesRuntime", "Package.swift"), "utf8");
|
|
4349
4409
|
const needsResources = variant === "3d" || variant === "full";
|
|
4350
|
-
const hasResources =
|
|
4410
|
+
const hasResources = existsSync9(join11(root, "ios", "App", "Resources", "LeCodesSDKResources.bundle"));
|
|
4351
4411
|
check(pkg.includes(`"LeCodesSDK-${variant}"`) && (!needsResources || hasResources), `SDK variant ${variant}${needsResources ? " (+ filament resources)" : ""}`, "run `lecodes app sync`");
|
|
4352
4412
|
}
|
|
4353
4413
|
const linked = shellSdkVersion(join11(root, "ios"));
|
|
@@ -4419,7 +4479,7 @@ var appBuild = async (args) => {
|
|
|
4419
4479
|
};
|
|
4420
4480
|
var appUpload = async (args) => {
|
|
4421
4481
|
const { root, config } = requireShell();
|
|
4422
|
-
if (!
|
|
4482
|
+
if (!existsSync9(join11(root, ARCHIVE_PATH))) {
|
|
4423
4483
|
throw new CliError("No archive at ios/build/App.xcarchive — run `lecodes app build ios` first.");
|
|
4424
4484
|
}
|
|
4425
4485
|
const ascPath = join11(homedir2(), ".lecodes", "asc.json");
|
|
@@ -4431,7 +4491,7 @@ var appUpload = async (args) => {
|
|
|
4431
4491
|
throw new CliError(`App Store Connect API key needed: --key-path <AuthKey.p8> --key-id <id> --issuer-id <id>
|
|
4432
4492
|
(create one at appstoreconnect.apple.com → Users and Access → Integrations; stored in ~/.lecodes/asc.json after first use)`);
|
|
4433
4493
|
}
|
|
4434
|
-
if (!
|
|
4494
|
+
if (!existsSync9(keyPath))
|
|
4435
4495
|
throw new CliError(`API key file not found: ${keyPath}`);
|
|
4436
4496
|
if (flagStr(args, "key-path")) {
|
|
4437
4497
|
mkdirSync5(dirname7(ascPath), { recursive: true });
|
|
@@ -4469,7 +4529,7 @@ var appOpen = async (args) => {
|
|
|
4469
4529
|
const platform = args._[1] ?? "ios";
|
|
4470
4530
|
if (platform === "ios") {
|
|
4471
4531
|
const proj = join11(root, "ios", "App.xcodeproj");
|
|
4472
|
-
if (!
|
|
4532
|
+
if (!existsSync9(proj))
|
|
4473
4533
|
throw new CliError("No iOS shell here — run `lecodes app init ios` first.");
|
|
4474
4534
|
if (process.platform !== "darwin")
|
|
4475
4535
|
throw new CliError("Opening Xcode requires macOS.");
|
|
@@ -4504,12 +4564,12 @@ var app = async (args) => {
|
|
|
4504
4564
|
};
|
|
4505
4565
|
|
|
4506
4566
|
// src/commands/clone.ts
|
|
4507
|
-
import { existsSync as
|
|
4567
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readdirSync as readdirSync6 } from "node:fs";
|
|
4508
4568
|
import { resolve as resolve3 } from "node:path";
|
|
4509
4569
|
|
|
4510
4570
|
// src/types.ts
|
|
4511
4571
|
import { dirname as dirname8, join as join12, relative as relative3, sep } from "node:path";
|
|
4512
|
-
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";
|
|
4513
4573
|
var TSCONFIG = {
|
|
4514
4574
|
compilerOptions: {
|
|
4515
4575
|
target: "ES2020",
|
|
@@ -4527,7 +4587,7 @@ var TSCONFIG = {
|
|
|
4527
4587
|
exclude: ["node_modules"]
|
|
4528
4588
|
};
|
|
4529
4589
|
var listBundleFiles = (dir, base = dir) => {
|
|
4530
|
-
if (!
|
|
4590
|
+
if (!existsSync10(dir))
|
|
4531
4591
|
return [];
|
|
4532
4592
|
const out = [];
|
|
4533
4593
|
for (const name of readdirSync5(dir)) {
|
|
@@ -4540,7 +4600,7 @@ var listBundleFiles = (dir, base = dir) => {
|
|
|
4540
4600
|
return out;
|
|
4541
4601
|
};
|
|
4542
4602
|
var pruneEmptyDirs = (dir, root) => {
|
|
4543
|
-
if (!
|
|
4603
|
+
if (!existsSync10(dir) || !statSync3(dir).isDirectory())
|
|
4544
4604
|
return;
|
|
4545
4605
|
for (const name of readdirSync5(dir))
|
|
4546
4606
|
pruneEmptyDirs(join12(dir, name), root);
|
|
@@ -4586,7 +4646,7 @@ var readLocalTypeBundle = () => {
|
|
|
4586
4646
|
join12(distRoot, "..", "sdk", "dist", "types.json")
|
|
4587
4647
|
];
|
|
4588
4648
|
for (const path of candidates) {
|
|
4589
|
-
if (
|
|
4649
|
+
if (existsSync10(path)) {
|
|
4590
4650
|
try {
|
|
4591
4651
|
return JSON.parse(readFileSync11(path, "utf8"));
|
|
4592
4652
|
} catch {}
|
|
@@ -4624,7 +4684,7 @@ var clone = async (args) => {
|
|
|
4624
4684
|
const project = await getProject(apiUrl, token, uuid);
|
|
4625
4685
|
const dir = args._[1] ?? slug(project.name);
|
|
4626
4686
|
const root = resolve3(dir);
|
|
4627
|
-
if (
|
|
4687
|
+
if (existsSync11(root) && readdirSync6(root).length > 0) {
|
|
4628
4688
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
4629
4689
|
}
|
|
4630
4690
|
mkdirSync7(root, { recursive: true });
|
|
@@ -4644,7 +4704,7 @@ var clone = async (args) => {
|
|
|
4644
4704
|
};
|
|
4645
4705
|
|
|
4646
4706
|
// src/commands/create.ts
|
|
4647
|
-
import { existsSync as
|
|
4707
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync7, writeFileSync as writeFileSync9 } from "node:fs";
|
|
4648
4708
|
import { join as join13, resolve as resolve4 } from "node:path";
|
|
4649
4709
|
|
|
4650
4710
|
// src/commands/projectTemplates.ts
|
|
@@ -4731,7 +4791,7 @@ var create = async (args) => {
|
|
|
4731
4791
|
throw new CliError("Usage: lecodes create <name> [directory]");
|
|
4732
4792
|
const dir = args._[1] ?? slug2(name);
|
|
4733
4793
|
const root = resolve4(dir);
|
|
4734
|
-
if (
|
|
4794
|
+
if (existsSync12(root) && readdirSync7(root).length > 0) {
|
|
4735
4795
|
throw new CliError(`Directory "${dir}" already exists and is not empty.`);
|
|
4736
4796
|
}
|
|
4737
4797
|
mkdirSync8(root, { recursive: true });
|
|
@@ -4750,7 +4810,7 @@ var create = async (args) => {
|
|
|
4750
4810
|
};
|
|
4751
4811
|
|
|
4752
4812
|
// src/commands/design.ts
|
|
4753
|
-
import { existsSync as
|
|
4813
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync14, readdirSync as readdirSync8, writeFileSync as writeFileSync11, appendFileSync } from "node:fs";
|
|
4754
4814
|
import { basename as basename6, join as join15 } from "node:path";
|
|
4755
4815
|
|
|
4756
4816
|
// src/compile/designCompile.ts
|
|
@@ -4759,7 +4819,7 @@ import { basename as basename5 } from "node:path";
|
|
|
4759
4819
|
|
|
4760
4820
|
// src/compile/assetIcons.ts
|
|
4761
4821
|
import { createHash as createHash3 } from "node:crypto";
|
|
4762
|
-
import { existsSync as
|
|
4822
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "node:fs";
|
|
4763
4823
|
import { dirname as dirname9, join as join14 } from "node:path";
|
|
4764
4824
|
var DEFAULT_REGISTRY = process.env.LECODES_ICON_REGISTRY?.trim() || "https://icon-registry.jt3.ru/v1";
|
|
4765
4825
|
var ICON_ID = /^([a-z0-9]+(?:-[a-z0-9]+)*):([a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
@@ -5056,7 +5116,7 @@ var renderNotices2 = (lock) => {
|
|
|
5056
5116
|
`);
|
|
5057
5117
|
};
|
|
5058
5118
|
var writeIfChanged2 = (path, text) => {
|
|
5059
|
-
const current =
|
|
5119
|
+
const current = existsSync13(path) ? safeRead(path) : null;
|
|
5060
5120
|
if (current === text)
|
|
5061
5121
|
return false;
|
|
5062
5122
|
writeFileSync10(path, text);
|
|
@@ -5735,7 +5795,7 @@ var getContext = (args) => {
|
|
|
5735
5795
|
};
|
|
5736
5796
|
var listScreens = (designDir) => {
|
|
5737
5797
|
const dir = join15(designDir, "screens");
|
|
5738
|
-
if (!
|
|
5798
|
+
if (!existsSync14(dir))
|
|
5739
5799
|
return [];
|
|
5740
5800
|
return readdirSync8(dir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith(".")).map((f2) => f2.slice(0, -3)).sort();
|
|
5741
5801
|
};
|
|
@@ -5751,7 +5811,7 @@ var writeMcpConfig = (ctx, port) => {
|
|
|
5751
5811
|
const path = join15(ctx.root, ".mcp.json");
|
|
5752
5812
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
5753
5813
|
let config = {};
|
|
5754
|
-
if (
|
|
5814
|
+
if (existsSync14(path)) {
|
|
5755
5815
|
try {
|
|
5756
5816
|
config = JSON.parse(readFileSync14(path, "utf8"));
|
|
5757
5817
|
} catch {
|
|
@@ -5785,7 +5845,7 @@ var init = async (ctx, args) => {
|
|
|
5785
5845
|
let created = 0;
|
|
5786
5846
|
for (const [rel, content] of files) {
|
|
5787
5847
|
const abs = join15(ctx.designDir, rel);
|
|
5788
|
-
if (
|
|
5848
|
+
if (existsSync14(abs)) {
|
|
5789
5849
|
note(`kept ${ctx.dirName}/${rel.replace(/\\/g, "/")}`);
|
|
5790
5850
|
continue;
|
|
5791
5851
|
}
|
|
@@ -5795,7 +5855,7 @@ var init = async (ctx, args) => {
|
|
|
5795
5855
|
}
|
|
5796
5856
|
const ignorePath = join15(ctx.root, ".lecodesignore");
|
|
5797
5857
|
const ignoreLine = `${ctx.dirName}/.snapshots/`;
|
|
5798
|
-
const current =
|
|
5858
|
+
const current = existsSync14(ignorePath) ? readFileSync14(ignorePath, "utf8") : "";
|
|
5799
5859
|
if (!current.split(/\r?\n/).includes(ignoreLine)) {
|
|
5800
5860
|
appendFileSync(ignorePath, (current && !current.endsWith(`
|
|
5801
5861
|
`) ? `
|
|
@@ -5917,7 +5977,7 @@ var snapshot = async (ctx, args) => {
|
|
|
5917
5977
|
}
|
|
5918
5978
|
};
|
|
5919
5979
|
var serve = async (ctx, args) => {
|
|
5920
|
-
if (!
|
|
5980
|
+
if (!existsSync14(ctx.designDir)) {
|
|
5921
5981
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
5922
5982
|
}
|
|
5923
5983
|
let designServer;
|
|
@@ -5990,7 +6050,7 @@ var serve = async (ctx, args) => {
|
|
|
5990
6050
|
openBrowser(server.url);
|
|
5991
6051
|
};
|
|
5992
6052
|
var arrange = async (ctx, args) => {
|
|
5993
|
-
if (!
|
|
6053
|
+
if (!existsSync14(ctx.designDir)) {
|
|
5994
6054
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
5995
6055
|
}
|
|
5996
6056
|
let designServer;
|
|
@@ -6026,7 +6086,7 @@ var share = async (ctx, args) => {
|
|
|
6026
6086
|
note("Turn it off with: lecodes design share --off");
|
|
6027
6087
|
};
|
|
6028
6088
|
var check = async (ctx, args) => {
|
|
6029
|
-
if (!
|
|
6089
|
+
if (!existsSync14(ctx.designDir)) {
|
|
6030
6090
|
throw new CliError(`No ${ctx.dirName}/ folder here. Run "lecodes design init" to scaffold it.`);
|
|
6031
6091
|
}
|
|
6032
6092
|
let designServer;
|
|
@@ -6102,12 +6162,11 @@ var design = async (args) => {
|
|
|
6102
6162
|
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync15, watch, writeFileSync as writeFileSync12 } from "node:fs";
|
|
6103
6163
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
6104
6164
|
import { networkInterfaces } from "node:os";
|
|
6105
|
-
import { basename as basename7, join as
|
|
6165
|
+
import { basename as basename7, join as join16 } from "node:path";
|
|
6106
6166
|
|
|
6107
6167
|
// src/dev/devServer.ts
|
|
6108
6168
|
import { createServer as createServer2 } from "node:http";
|
|
6109
|
-
import { createReadStream,
|
|
6110
|
-
import { join as join16 } from "node:path";
|
|
6169
|
+
import { createReadStream, statSync as statSync4 } from "node:fs";
|
|
6111
6170
|
|
|
6112
6171
|
// src/dev/clientTemplates.ts
|
|
6113
6172
|
var DEV_SCREEN_TS = `const title = "LeCodes Dev"
|
|
@@ -6476,8 +6535,8 @@ var startDevServer = async (options) => {
|
|
|
6476
6535
|
} catch {
|
|
6477
6536
|
return sendText(res, 400, "text/plain", "Bad path");
|
|
6478
6537
|
}
|
|
6479
|
-
const abs =
|
|
6480
|
-
if (!
|
|
6538
|
+
const abs = resolveLocalPath(root, key);
|
|
6539
|
+
if (!abs || !statSync4(abs).isFile())
|
|
6481
6540
|
return sendText(res, 404, "text/plain", "Not found");
|
|
6482
6541
|
res.writeHead(200, { "content-type": contentType(key), "cache-control": "no-store" });
|
|
6483
6542
|
createReadStream(abs).pipe(res);
|
|
@@ -6560,14 +6619,14 @@ var pickLanAddress = () => {
|
|
|
6560
6619
|
return null;
|
|
6561
6620
|
};
|
|
6562
6621
|
var loadDevToken = (root) => {
|
|
6563
|
-
const path =
|
|
6622
|
+
const path = join16(root, LECODES_DIR, "dev.json");
|
|
6564
6623
|
try {
|
|
6565
6624
|
const token2 = JSON.parse(readFileSync15(path, "utf8")).token;
|
|
6566
6625
|
if (token2 && /^[a-z0-9]{8,}$/.test(token2))
|
|
6567
6626
|
return token2;
|
|
6568
6627
|
} catch {}
|
|
6569
6628
|
const token = randomBytes2(6).toString("hex");
|
|
6570
|
-
mkdirSync11(
|
|
6629
|
+
mkdirSync11(join16(root, LECODES_DIR), { recursive: true });
|
|
6571
6630
|
writeFileSync12(path, JSON.stringify({ token }, null, 2) + `
|
|
6572
6631
|
`);
|
|
6573
6632
|
return token;
|
|
@@ -6680,7 +6739,7 @@ ${result.error}`);
|
|
|
6680
6739
|
await printQr(server.url);
|
|
6681
6740
|
log(`Scan the QR with the LeCodes app, or open: ${c.bold(server.url)}`);
|
|
6682
6741
|
note(`Older desktop builds (no websocket bridge): ${server.url}?t=poll`);
|
|
6683
|
-
if (existsSync15(
|
|
6742
|
+
if (existsSync15(join16(root, LECODES_DIR, "manifest.json")))
|
|
6684
6743
|
note(`Token stored in ${LECODES_DIR}/dev.json (delete it to rotate the URL).`);
|
|
6685
6744
|
log("");
|
|
6686
6745
|
log(`Watching ${root} — save a file to hot-reload. Ctrl+C to stop.`);
|
|
@@ -6876,7 +6935,7 @@ var statusLabel = (e) => e.status === "added" ? c.green(" added ") : e.statu
|
|
|
6876
6935
|
|
|
6877
6936
|
// src/commands/init.ts
|
|
6878
6937
|
import { existsSync as existsSync16, mkdirSync as mkdirSync12, writeFileSync as writeFileSync13 } from "node:fs";
|
|
6879
|
-
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";
|
|
6880
6939
|
var STARTER2 = `// Welcome to LeCodes — the whole SDK is available as globals, no imports needed.
|
|
6881
6940
|
// Run it live on a device with \`lecodes dev\`, or bundle it with \`lecodes compile -o app.js\`.
|
|
6882
6941
|
|
|
@@ -6978,7 +7037,7 @@ var init2 = async (args) => {
|
|
|
6978
7037
|
mkdirSync12(root, { recursive: true });
|
|
6979
7038
|
let created = 0;
|
|
6980
7039
|
const write = (rel, content) => {
|
|
6981
|
-
const abs =
|
|
7040
|
+
const abs = join17(root, rel);
|
|
6982
7041
|
if (existsSync16(abs)) {
|
|
6983
7042
|
note(`kept ${rel}`);
|
|
6984
7043
|
return;
|
|
@@ -7009,7 +7068,7 @@ var init2 = async (args) => {
|
|
|
7009
7068
|
|
|
7010
7069
|
// src/commands/link.ts
|
|
7011
7070
|
import { existsSync as existsSync17 } from "node:fs";
|
|
7012
|
-
import { basename as basename11, join as
|
|
7071
|
+
import { basename as basename11, join as join18, resolve as resolve6 } from "node:path";
|
|
7013
7072
|
|
|
7014
7073
|
// src/commands/push.ts
|
|
7015
7074
|
import { basename as basename10 } from "node:path";
|
|
@@ -7172,7 +7231,7 @@ var link = async (args) => {
|
|
|
7172
7231
|
const root = dirArg ? resolve6(dirArg) : process.cwd();
|
|
7173
7232
|
if (!existsSync17(root))
|
|
7174
7233
|
throw new CliError(`No such directory: ${root}`);
|
|
7175
|
-
if (existsSync17(
|
|
7234
|
+
if (existsSync17(join18(root, LECODES_DIR, "manifest.json")) && !flagBool(args, "force")) {
|
|
7176
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.");
|
|
7177
7236
|
}
|
|
7178
7237
|
let enclosing = null;
|
|
@@ -7489,7 +7548,7 @@ var render = async (args) => {
|
|
|
7489
7548
|
|
|
7490
7549
|
// src/commands/pull.ts
|
|
7491
7550
|
import { existsSync as existsSync18, mkdirSync as mkdirSync14, rmSync as rmSync3, writeFileSync as writeFileSync15 } from "node:fs";
|
|
7492
|
-
import { dirname as dirname12, join as
|
|
7551
|
+
import { dirname as dirname12, join as join19 } from "node:path";
|
|
7493
7552
|
var pull = async (args) => {
|
|
7494
7553
|
const root = findProjectRoot(process.cwd());
|
|
7495
7554
|
const manifest = readManifest(root);
|
|
@@ -7509,7 +7568,7 @@ var pull = async (args) => {
|
|
|
7509
7568
|
const remotePaths = new Set([...buildPaths(project.assets).entries()].filter(([id]) => project.assets.find((a) => a.id === id)?.type !== "folder").map(([, path]) => path));
|
|
7510
7569
|
for (const path of Object.keys(manifest.files)) {
|
|
7511
7570
|
if (!remotePaths.has(path)) {
|
|
7512
|
-
const abs =
|
|
7571
|
+
const abs = join19(root, ...path.replace(/^\//, "").split("/"));
|
|
7513
7572
|
if (existsSync18(abs))
|
|
7514
7573
|
rmSync3(abs);
|
|
7515
7574
|
}
|
|
@@ -7548,7 +7607,7 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
7548
7607
|
const files = { ...manifest.files };
|
|
7549
7608
|
for (const asset of targets) {
|
|
7550
7609
|
const key = pathById.get(asset.id);
|
|
7551
|
-
const abs =
|
|
7610
|
+
const abs = join19(root, ...key.replace(/^\//, "").split("/"));
|
|
7552
7611
|
mkdirSync14(dirname12(abs), { recursive: true });
|
|
7553
7612
|
let sha;
|
|
7554
7613
|
if (asset.type === "file") {
|
|
@@ -7572,19 +7631,19 @@ var pullPaths = async (root, manifest, project, paths, apiUrl, token) => {
|
|
|
7572
7631
|
|
|
7573
7632
|
// src/commands/scene.ts
|
|
7574
7633
|
import { existsSync as existsSync20, readFileSync as readFileSync20, readdirSync as readdirSync9, statSync as statSync5, writeFileSync as writeFileSync16 } from "node:fs";
|
|
7575
|
-
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";
|
|
7576
7635
|
|
|
7577
7636
|
// src/compile/sceneCompile.ts
|
|
7578
7637
|
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
|
|
7579
|
-
import { join as
|
|
7638
|
+
import { join as join20 } from "node:path";
|
|
7580
7639
|
var TEXT_EXT = /\.(ts|js|json|svg|txt|md)$/i;
|
|
7581
7640
|
var rel = (key) => key.replace(/^\//, "");
|
|
7582
7641
|
var resolveHarness = (loadSceneHarness2) => {
|
|
7583
|
-
const inRepo =
|
|
7642
|
+
const inRepo = join20(distRoot, "..", "projects", "src", "scene-editor");
|
|
7584
7643
|
try {
|
|
7585
7644
|
return loadSceneHarness2(existsSync19(inRepo) ? inRepo : undefined);
|
|
7586
7645
|
} catch {
|
|
7587
|
-
const vendored =
|
|
7646
|
+
const vendored = join20(distRoot, "runtime", "scene-harness.json");
|
|
7588
7647
|
if (existsSync19(vendored))
|
|
7589
7648
|
return JSON.parse(readFileSync19(vendored, "utf8"));
|
|
7590
7649
|
throw new CliError("scene-editor harness sources not found — reinstall the CLI or set LECODES_SCENE_HARNESS_DIR.");
|
|
@@ -7650,7 +7709,7 @@ var getContext2 = (args) => {
|
|
|
7650
7709
|
return { root, manifest, name: manifest?.name ?? basename12(root) };
|
|
7651
7710
|
};
|
|
7652
7711
|
var writeMcpConfig2 = (root, port) => {
|
|
7653
|
-
const path =
|
|
7712
|
+
const path = join21(root, ".mcp.json");
|
|
7654
7713
|
const entry = { type: "http", url: `http://localhost:${port}/mcp` };
|
|
7655
7714
|
let config = {};
|
|
7656
7715
|
if (existsSync20(path)) {
|
|
@@ -7677,7 +7736,7 @@ var countScenes = (dir) => {
|
|
|
7677
7736
|
for (const name of readdirSync9(dir)) {
|
|
7678
7737
|
if (name === "node_modules" || name.startsWith("."))
|
|
7679
7738
|
continue;
|
|
7680
|
-
const full =
|
|
7739
|
+
const full = join21(dir, name);
|
|
7681
7740
|
if (statSync5(full).isDirectory())
|
|
7682
7741
|
n += countScenes(full);
|
|
7683
7742
|
else if (name.endsWith(".scene.ts"))
|
|
@@ -8044,13 +8103,13 @@ var types = async (args) => {
|
|
|
8044
8103
|
// src/index.ts
|
|
8045
8104
|
import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync2 } from "node:fs";
|
|
8046
8105
|
import { createRequire as createRequire4 } from "node:module";
|
|
8047
|
-
import { delimiter as delimiter2, dirname as dirname16, join as
|
|
8106
|
+
import { delimiter as delimiter2, dirname as dirname16, join as join23 } from "node:path";
|
|
8048
8107
|
|
|
8049
8108
|
// src/commands/install.ts
|
|
8050
8109
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8051
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";
|
|
8052
8111
|
import { homedir as homedir3 } from "node:os";
|
|
8053
|
-
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";
|
|
8054
8113
|
var isWin = process.platform === "win32";
|
|
8055
8114
|
var HOME = homedir3();
|
|
8056
8115
|
var safeRealpath = (p) => {
|
|
@@ -8076,10 +8135,10 @@ var install = async (args) => {
|
|
|
8076
8135
|
const bundle = dirname15(process.execPath);
|
|
8077
8136
|
const exeName = basename13(process.execPath);
|
|
8078
8137
|
const chiselName = isWin ? "chisel.exe" : "chisel";
|
|
8079
|
-
if (!existsSync22(
|
|
8138
|
+
if (!existsSync22(join22(bundle, "runtime")) || !existsSync22(join22(bundle, chiselName))) {
|
|
8080
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.");
|
|
8081
8140
|
}
|
|
8082
|
-
const companions = [exeName, chiselName, "runtime", "README.txt"].filter((f2) => existsSync22(
|
|
8141
|
+
const companions = [exeName, chiselName, "runtime", "README.txt"].filter((f2) => existsSync22(join22(bundle, f2)));
|
|
8083
8142
|
if (isWin)
|
|
8084
8143
|
return installWindows(args, bundle, companions);
|
|
8085
8144
|
return installUnix(args, bundle, companions);
|
|
@@ -8089,9 +8148,9 @@ var copyBundle = (bundle, target, companions) => {
|
|
|
8089
8148
|
if (safeRealpath(target) === safeRealpath(bundle))
|
|
8090
8149
|
return;
|
|
8091
8150
|
for (const f2 of companions) {
|
|
8092
|
-
const dest =
|
|
8151
|
+
const dest = join22(target, f2);
|
|
8093
8152
|
rmSync4(dest, { recursive: true, force: true });
|
|
8094
|
-
cpSync2(
|
|
8153
|
+
cpSync2(join22(bundle, f2), dest, { recursive: true });
|
|
8095
8154
|
}
|
|
8096
8155
|
};
|
|
8097
8156
|
var permError = (e, dir, system) => {
|
|
@@ -8103,34 +8162,34 @@ var permError = (e, dir, system) => {
|
|
|
8103
8162
|
};
|
|
8104
8163
|
var installUnix = (args, bundle, companions) => {
|
|
8105
8164
|
const system = flagBool(args, "system");
|
|
8106
|
-
const libDir = resolve11(flagStr(args, "dir") ?? (system ? "/usr/local/lib/lecodes-cli" :
|
|
8107
|
-
const binDir = resolve11(flagStr(args, "bin") ?? (system ? "/usr/local/bin" :
|
|
8108
|
-
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");
|
|
8109
8168
|
try {
|
|
8110
8169
|
copyBundle(bundle, libDir, companions);
|
|
8111
|
-
chmodSync(
|
|
8112
|
-
chmodSync(
|
|
8170
|
+
chmodSync(join22(libDir, "lecodes"), 493);
|
|
8171
|
+
chmodSync(join22(libDir, "chisel"), 493);
|
|
8113
8172
|
} catch (e) {
|
|
8114
8173
|
throw permError(e, libDir, system);
|
|
8115
8174
|
}
|
|
8116
8175
|
try {
|
|
8117
8176
|
mkdirSync15(binDir, { recursive: true });
|
|
8118
8177
|
rmSync4(link2, { force: true });
|
|
8119
|
-
symlinkSync(
|
|
8178
|
+
symlinkSync(join22(libDir, "lecodes"), link2);
|
|
8120
8179
|
} catch (e) {
|
|
8121
8180
|
throw permError(e, binDir, system);
|
|
8122
8181
|
}
|
|
8123
8182
|
success(`Installed to ${c.bold(libDir)}`);
|
|
8124
|
-
log(` ${c.dim(link2 + " → " +
|
|
8183
|
+
log(` ${c.dim(link2 + " → " + join22(libDir, "lecodes"))}`);
|
|
8125
8184
|
finishPathUnix(args, binDir);
|
|
8126
8185
|
};
|
|
8127
8186
|
var shellRc = () => {
|
|
8128
8187
|
const shell = basename13(process.env.SHELL ?? "");
|
|
8129
8188
|
if (shell === "zsh")
|
|
8130
|
-
return { file:
|
|
8189
|
+
return { file: join22(HOME, ".zshrc"), name: "~/.zshrc" };
|
|
8131
8190
|
if (shell === "bash")
|
|
8132
|
-
return { file:
|
|
8133
|
-
return { file:
|
|
8191
|
+
return { file: join22(HOME, ".bashrc"), name: "~/.bashrc" };
|
|
8192
|
+
return { file: join22(HOME, ".profile"), name: "~/.profile" };
|
|
8134
8193
|
};
|
|
8135
8194
|
var PATH_MARKER = "# Added by `lecodes install`";
|
|
8136
8195
|
var appendPathToShellRc = (binDir) => {
|
|
@@ -8175,7 +8234,7 @@ var finishPathUnix = (args, binDir) => {
|
|
|
8175
8234
|
log(` • or install system-wide (no PATH edit): ${c.bold("sudo lecodes install --system")}`);
|
|
8176
8235
|
};
|
|
8177
8236
|
var installWindows = (args, bundle, companions) => {
|
|
8178
|
-
const target = resolve11(flagStr(args, "dir") ??
|
|
8237
|
+
const target = resolve11(flagStr(args, "dir") ?? join22(process.env.LOCALAPPDATA ?? join22(HOME, "AppData", "Local"), "Programs", "lecodes-cli"));
|
|
8179
8238
|
try {
|
|
8180
8239
|
copyBundle(bundle, target, companions);
|
|
8181
8240
|
} catch (e) {
|
|
@@ -8214,7 +8273,7 @@ var addToUserPathWindows = (dir) => {
|
|
|
8214
8273
|
var STANDALONE = (() => {
|
|
8215
8274
|
const dir = dirname16(process.execPath);
|
|
8216
8275
|
const chisel = process.platform === "win32" ? "chisel.exe" : "chisel";
|
|
8217
|
-
return existsSync23(
|
|
8276
|
+
return existsSync23(join23(dir, "runtime")) && existsSync23(join23(dir, chisel));
|
|
8218
8277
|
})();
|
|
8219
8278
|
var INSTALLED = STANDALONE && (() => {
|
|
8220
8279
|
const exe = process.platform === "win32" ? "lecodes.exe" : "lecodes";
|
|
@@ -8229,7 +8288,7 @@ var INSTALLED = STANDALONE && (() => {
|
|
|
8229
8288
|
if (!d)
|
|
8230
8289
|
return false;
|
|
8231
8290
|
try {
|
|
8232
|
-
const cand =
|
|
8291
|
+
const cand = join23(d, exe);
|
|
8233
8292
|
return existsSync23(cand) && realpathSync2(cand) === self;
|
|
8234
8293
|
} catch {
|
|
8235
8294
|
return false;
|
|
@@ -8416,7 +8475,7 @@ var peerVersion = (name, probe) => {
|
|
|
8416
8475
|
const require2 = createRequire4(import.meta.url);
|
|
8417
8476
|
let dir = dirname16(require2.resolve(probe));
|
|
8418
8477
|
for (let depth = 0;depth < 16; depth++) {
|
|
8419
|
-
const manifest =
|
|
8478
|
+
const manifest = join23(dir, "package.json");
|
|
8420
8479
|
if (existsSync23(manifest)) {
|
|
8421
8480
|
const parsed = JSON.parse(readFileSync23(manifest, "utf8"));
|
|
8422
8481
|
if (parsed.name === name)
|