@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.39 → 0.1.2-dev.40
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/cli/bundle-templates.mjs +7 -7
- package/cli/src/build.mjs +36 -22
- package/cli/src/cpp.mjs +5 -11
- package/cli/src/devBack.mjs +9 -9
- package/cli/src/python.mjs +8 -13
- package/cli/src/ros2.mjs +4 -10
- package/cli/src/util.mjs +22 -3
- package/package.json +2 -2
package/cli/bundle-templates.mjs
CHANGED
|
@@ -6,19 +6,19 @@ import { resolve, relative } from "node:path";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
8
|
const root = resolve(fileURLToPath(import.meta.url), "..");
|
|
9
|
-
const templatesDir = resolve(root, "templates");
|
|
10
9
|
const out = resolve(root, "src/templates-embedded.mjs");
|
|
11
10
|
|
|
12
11
|
const files = {};
|
|
13
|
-
function walk(
|
|
14
|
-
for (const name of readdirSync(
|
|
15
|
-
const full = resolve(
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
function walk(baseDir, prefix) {
|
|
13
|
+
for (const name of readdirSync(baseDir)) {
|
|
14
|
+
const full = resolve(baseDir, name);
|
|
15
|
+
const key = prefix + name;
|
|
16
|
+
if (statSync(full).isDirectory()) { walk(full + "/", key + "/"); continue; }
|
|
18
17
|
files[key] = readFileSync(full, "base64");
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
|
-
walk(
|
|
20
|
+
walk(resolve(root, "templates") + "/", "");
|
|
21
|
+
walk(resolve(root, "docker") + "/", "docker/");
|
|
22
22
|
|
|
23
23
|
writeFileSync(out,
|
|
24
24
|
`// AUTO-GENERATED by cli/bundle-templates.mjs — do not edit.\n` +
|
package/cli/src/build.mjs
CHANGED
|
@@ -17,11 +17,13 @@ import { execSync, spawnSync } from "node:child_process";
|
|
|
17
17
|
import { ensureDocker, findPluginRoot, hasBin, humanSize, log, parseArgs } from "./util.mjs";
|
|
18
18
|
import { assertManifest, manifestRuntime } from "./manifest.mjs";
|
|
19
19
|
|
|
20
|
-
// Find a usable
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
// Find a usable JS runtime for running vite as a subprocess.
|
|
21
|
+
// In binary (Bun) mode, try `bun` first (it can run vite directly), then node.
|
|
22
|
+
// In node mode, use the current process.
|
|
23
|
+
function findJsRuntime() {
|
|
24
|
+
if (typeof Bun === "undefined") return { bin: process.execPath, isBun: false };
|
|
25
|
+
for (const c of ["bun", "node", "node20", "node18"]) {
|
|
26
|
+
if (hasBin(c)) return { bin: c, isBun: c === "bun" };
|
|
25
27
|
}
|
|
26
28
|
return null;
|
|
27
29
|
}
|
|
@@ -37,21 +39,30 @@ function findViteBin(pluginRoot) {
|
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
// Run vite build in the plugin project.
|
|
41
|
-
// Returns true on success, false if vite/node not available.
|
|
42
|
+
// Run vite build in the plugin project. Throws if runtime or vite not found.
|
|
42
43
|
function runViteBuild(pluginRoot, { mode = "production" } = {}) {
|
|
43
|
-
const
|
|
44
|
-
if (!
|
|
44
|
+
const runtime = findJsRuntime();
|
|
45
|
+
if (!runtime) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"Node.js 20+ (or Bun) is required to build the plugin UI.\n" +
|
|
48
|
+
" Install Node.js: https://nodejs.org\n" +
|
|
49
|
+
" Then run: npm install (inside the plugin directory)",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
45
52
|
const viteBin = findViteBin(pluginRoot);
|
|
46
|
-
if (!viteBin || !existsSync(viteBin))
|
|
53
|
+
if (!viteBin || !existsSync(viteBin)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
"vite not found in this plugin's node_modules.\n" +
|
|
56
|
+
` Run: npm install (inside ${pluginRoot})`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
47
59
|
|
|
48
60
|
log.step(`vite build (mode: ${mode})`);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
});
|
|
61
|
+
// bun can run vite directly; node needs the explicit bin path
|
|
62
|
+
const args = runtime.isBun ? ["run", viteBin, "build", "--mode", mode]
|
|
63
|
+
: [viteBin, "build", "--mode", mode];
|
|
64
|
+
const r = spawnSync(runtime.bin, args, { cwd: pluginRoot, stdio: "inherit" });
|
|
53
65
|
if (r.status !== 0) throw new Error("vite build failed");
|
|
54
|
-
return true;
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
function isMainBranch() {
|
|
@@ -82,13 +93,13 @@ export async function exportRos2Build(root, archs = ["amd64", "arm64"]) {
|
|
|
82
93
|
const dockerPlatform = ARCH_DOCKER_PLATFORM[arch];
|
|
83
94
|
if (!dockerPlatform) { log.warn(`unknown arch '${arch}' — skipped`); continue; }
|
|
84
95
|
const archImage = `${ROS2_DEV_IMAGE}-${arch}`;
|
|
85
|
-
ensureImage(archImage, { platform: dockerPlatform });
|
|
96
|
+
await ensureImage(archImage, { platform: dockerPlatform });
|
|
86
97
|
colconBuild(root, { symlink: false, arch });
|
|
87
98
|
log.ok(`dist/ros2_ws/install-${arch}/ ready`);
|
|
88
99
|
}
|
|
89
100
|
} else {
|
|
90
101
|
// rclpy / pure Python: arch-agnostic, build once
|
|
91
|
-
ensureImage();
|
|
102
|
+
await ensureImage();
|
|
92
103
|
colconBuild(root, { symlink: false });
|
|
93
104
|
log.ok("dist/ros2_ws/install/ ready");
|
|
94
105
|
}
|
|
@@ -119,7 +130,7 @@ export async function exportCppBuild(root, distDir, archs = ["amd64", "arm64"])
|
|
|
119
130
|
const dockerPlatform = ARCH_DOCKER_PLATFORM[arch];
|
|
120
131
|
if (!dockerPlatform) { log.warn(`unknown arch '${arch}' — skipped`); continue; }
|
|
121
132
|
const archImage = `${CPP_DEV_IMAGE}-${arch}`;
|
|
122
|
-
ensureImage(archImage, { platform: dockerPlatform });
|
|
133
|
+
await ensureImage(archImage, { platform: dockerPlatform });
|
|
123
134
|
cmakeBuild(root, { buildType: "Release", arch });
|
|
124
135
|
const buildDir = `cpp/build-${arch}`;
|
|
125
136
|
const built = resolve(root, buildDir, entry);
|
|
@@ -233,9 +244,12 @@ export async function buildPlugin({ root, minify = false } = {}) {
|
|
|
233
244
|
rmSync(distDir, { recursive: true, force: true });
|
|
234
245
|
mkdirSync(distDir, { recursive: true });
|
|
235
246
|
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
247
|
+
const manifest = JSON.parse(readFileSync(resolve(pluginRoot, "manifest.json"), "utf8"));
|
|
248
|
+
const contributesUi = (manifest.contributes ?? []).some((c) => c.ui);
|
|
249
|
+
const uiDir = resolve(pluginRoot, "ui");
|
|
250
|
+
const hasUiFiles = existsSync(uiDir) && readdirSync(uiDir).some((f) => /\.[tj]sx?$/.test(f));
|
|
251
|
+
if (contributesUi || hasUiFiles) {
|
|
252
|
+
runViteBuild(pluginRoot, { mode: minify ? "production" : "development" });
|
|
239
253
|
}
|
|
240
254
|
|
|
241
255
|
// Stage distribution files.
|
|
@@ -417,7 +431,7 @@ export async function runBuild(args) {
|
|
|
417
431
|
if (needsLock) {
|
|
418
432
|
const { lockAndVendor } = await import("./python.mjs");
|
|
419
433
|
try {
|
|
420
|
-
lockAndVendor(pluginRoot, archs);
|
|
434
|
+
await lockAndVendor(pluginRoot, archs);
|
|
421
435
|
} catch (e) {
|
|
422
436
|
log.warn(`python lock/vendor skipped: ${e.message}`);
|
|
423
437
|
}
|
package/cli/src/cpp.mjs
CHANGED
|
@@ -2,31 +2,25 @@
|
|
|
2
2
|
// Matches the robot OS so the compiled binary is relocatable to the robot.
|
|
3
3
|
// Used by dev:back (interactive dev loop) and build (export the binary into the ZIP).
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { hasBin, kitRoot, log, pruneMuskatImages } from "./util.mjs";
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
|
+
import { hasBin, log, pruneMuskatImages, resolveDockerfile } from "./util.mjs";
|
|
8
7
|
|
|
9
8
|
export const CPP_DEV_IMAGE = "muscat-pk-cpp-dev";
|
|
10
9
|
|
|
11
|
-
// Dockerfile lives inside the kit — plugin authors never see or edit it.
|
|
12
|
-
const DOCKERFILE = resolve(kitRoot, "cli/docker/Dockerfile.cpp");
|
|
13
|
-
|
|
14
10
|
export function assertDockerReady() {
|
|
15
11
|
if (!hasBin("docker")) {
|
|
16
12
|
throw new Error("Docker not found. C++ builds need Docker (Ubuntu 24.04 + cmake container).");
|
|
17
13
|
}
|
|
18
|
-
if (!existsSync(DOCKERFILE)) {
|
|
19
|
-
throw new Error(`kit Dockerfile missing at ${DOCKERFILE} (reinstall muscat-plugin-kit).`);
|
|
20
|
-
}
|
|
21
14
|
}
|
|
22
15
|
|
|
23
16
|
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
24
|
-
export function ensureImage(image = CPP_DEV_IMAGE, { platform = null } = {}) {
|
|
17
|
+
export async function ensureImage(image = CPP_DEV_IMAGE, { platform = null } = {}) {
|
|
18
|
+
const dockerfile = await resolveDockerfile("Dockerfile.cpp");
|
|
25
19
|
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
26
20
|
const platformFlags = platform ? ["--platform", platform] : [];
|
|
27
21
|
const r = spawnSync(
|
|
28
22
|
"docker",
|
|
29
|
-
["build", ...platformFlags, "-t", image, "-f",
|
|
23
|
+
["build", ...platformFlags, "-t", image, "-f", dockerfile, dirname(dockerfile)],
|
|
30
24
|
{ stdio: "inherit" },
|
|
31
25
|
);
|
|
32
26
|
if (r.status !== 0) throw new Error("docker build failed.");
|
package/cli/src/devBack.mjs
CHANGED
|
@@ -33,9 +33,9 @@ import {
|
|
|
33
33
|
// Runs in a warm Ubuntu 24.04 + Python 3.12 container (matches the robot).
|
|
34
34
|
// Under `muscat-pk dev`, it shares the bridge container's netns, so the SDK
|
|
35
35
|
// reaches the Socket.IO bridge at the default localhost:10000.
|
|
36
|
-
function runPython(root) {
|
|
36
|
+
async function runPython(root) {
|
|
37
37
|
pyAssertDockerReady();
|
|
38
|
-
pyEnsureImage();
|
|
38
|
+
await pyEnsureImage();
|
|
39
39
|
|
|
40
40
|
const manifest = readManifest(root);
|
|
41
41
|
const pluginId = manifest.id ?? "";
|
|
@@ -94,12 +94,12 @@ function runPython(root) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// ── ros2 ───────────────────────────────────────────────────────────────────────
|
|
97
|
-
function runRos2(root) {
|
|
97
|
+
async function runRos2(root) {
|
|
98
98
|
assertDockerReady();
|
|
99
99
|
const pkg = ros2PackageName(root);
|
|
100
100
|
if (!pkg) throw new Error("no ROS2 package found under ros2_ws/src.");
|
|
101
101
|
|
|
102
|
-
ensureImage();
|
|
102
|
+
await ensureImage();
|
|
103
103
|
|
|
104
104
|
const manifest = readManifest(root);
|
|
105
105
|
const pluginId = manifest.id ?? "";
|
|
@@ -167,13 +167,13 @@ function runRos2(root) {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// ── cpp ──────────────────────────────────────────────────────────────────────
|
|
170
|
-
function runCpp(root) {
|
|
170
|
+
async function runCpp(root) {
|
|
171
171
|
cppAssertDockerReady();
|
|
172
172
|
const manifest = readManifest(root);
|
|
173
173
|
const entry = manifest.runtime?.entry;
|
|
174
174
|
if (!entry) throw new Error("runtime.entry (the built executable name) is required for cpp.");
|
|
175
175
|
|
|
176
|
-
cppEnsureImage();
|
|
176
|
+
await cppEnsureImage();
|
|
177
177
|
|
|
178
178
|
const pluginId = manifest.id ?? "";
|
|
179
179
|
const container = `${CPP_DEV_IMAGE}-run`;
|
|
@@ -245,7 +245,7 @@ export async function runDevBack() {
|
|
|
245
245
|
const root = findPluginRoot();
|
|
246
246
|
warnManifest(root);
|
|
247
247
|
const type = manifestRuntime(root);
|
|
248
|
-
if (type === "ros2") return runRos2(root);
|
|
249
|
-
if (type === "cpp") return runCpp(root);
|
|
250
|
-
return runPython(root);
|
|
248
|
+
if (type === "ros2") return await runRos2(root);
|
|
249
|
+
if (type === "cpp") return await runCpp(root);
|
|
250
|
+
return await runPython(root);
|
|
251
251
|
}
|
package/cli/src/python.mjs
CHANGED
|
@@ -2,30 +2,25 @@
|
|
|
2
2
|
// Used by dev:back (hot-reload) and build (lock + wheel vendor).
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
|
-
import { dirname
|
|
6
|
-
import { hasBin,
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
|
+
import { hasBin, log, pruneMuskatImages, resolveDockerfile } from "./util.mjs";
|
|
7
7
|
|
|
8
8
|
export const PYTHON_DEV_IMAGE = "muscat-pk-python-dev";
|
|
9
9
|
|
|
10
|
-
// Dockerfile lives inside the kit — plugin authors never see or edit it.
|
|
11
|
-
const DOCKERFILE = resolve(kitRoot, "cli/docker/Dockerfile.python");
|
|
12
|
-
|
|
13
10
|
export function assertDockerReady() {
|
|
14
11
|
if (!hasBin("docker")) {
|
|
15
12
|
throw new Error("Docker not found. The Python backend runs in a container (Ubuntu 24.04 + Python 3.12).");
|
|
16
13
|
}
|
|
17
|
-
if (!existsSync(DOCKERFILE)) {
|
|
18
|
-
throw new Error(`kit Dockerfile missing at ${DOCKERFILE} (reinstall muscat-plugin-kit).`);
|
|
19
|
-
}
|
|
20
14
|
}
|
|
21
15
|
|
|
22
16
|
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
23
|
-
export function ensureImage(image = PYTHON_DEV_IMAGE, { platform = null } = {}) {
|
|
17
|
+
export async function ensureImage(image = PYTHON_DEV_IMAGE, { platform = null } = {}) {
|
|
18
|
+
const dockerfile = await resolveDockerfile("Dockerfile.python");
|
|
24
19
|
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
25
20
|
const platformFlags = platform ? ["--platform", platform] : [];
|
|
26
21
|
const r = spawnSync(
|
|
27
22
|
"docker",
|
|
28
|
-
["build", ...platformFlags, "-t", image, "-f",
|
|
23
|
+
["build", ...platformFlags, "-t", image, "-f", dockerfile, dirname(dockerfile)],
|
|
29
24
|
{ stdio: "inherit" },
|
|
30
25
|
);
|
|
31
26
|
if (r.status !== 0) throw new Error("docker build failed.");
|
|
@@ -47,14 +42,14 @@ const ARCH_DOCKER_PLATFORM = {
|
|
|
47
42
|
* none-any 휠은 pip이 두 번째 arch에서 자동 skip → 중복 없음.
|
|
48
43
|
* requirements.txt 없으면 조용히 건너뜀.
|
|
49
44
|
*/
|
|
50
|
-
export function lockAndVendor(pluginRoot, archs = ["x86_64", "aarch64"]) {
|
|
45
|
+
export async function lockAndVendor(pluginRoot, archs = ["x86_64", "aarch64"]) {
|
|
51
46
|
const reqTxt = resolve(pluginRoot, "requirements.txt");
|
|
52
47
|
if (!existsSync(reqTxt)) {
|
|
53
48
|
log.warn("requirements.txt not found — lock/vendor skipped");
|
|
54
49
|
return;
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
ensureImage();
|
|
52
|
+
await ensureImage();
|
|
58
53
|
|
|
59
54
|
log.step("generating lock (uv pip compile)…");
|
|
60
55
|
const lockResult = spawnSync(
|
|
@@ -82,7 +77,7 @@ export function lockAndVendor(pluginRoot, archs = ["x86_64", "aarch64"]) {
|
|
|
82
77
|
}
|
|
83
78
|
// arch별 이미지 빌드 (--platform 지정) → pip이 glibc+arch 자동 감지 → 올바른 휠 선택.
|
|
84
79
|
const archImage = `${PYTHON_DEV_IMAGE}-${arch}`;
|
|
85
|
-
ensureImage(archImage, { platform: dockerPlatform });
|
|
80
|
+
await ensureImage(archImage, { platform: dockerPlatform });
|
|
86
81
|
|
|
87
82
|
log.step(`vendoring wheels for ${arch} (${dockerPlatform})…`);
|
|
88
83
|
// 패키지별 개별 download로 private/미공개 패키지 실패 시에도 나머지 계속 진행.
|
package/cli/src/ros2.mjs
CHANGED
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { existsSync, readdirSync } from "node:fs";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
|
-
import { hasBin,
|
|
6
|
+
import { hasBin, log, pruneMuskatImages, resolveDockerfile } from "./util.mjs";
|
|
7
7
|
|
|
8
8
|
export const ROS2_DEV_IMAGE = "muscat-pk-ros2-dev";
|
|
9
9
|
|
|
10
|
-
// Dockerfile lives inside the kit — plugin authors never see or edit it.
|
|
11
|
-
// It has no COPY/ADD, so the build context is irrelevant (its own dir is used).
|
|
12
|
-
const DOCKERFILE = resolve(kitRoot, "cli/docker/Dockerfile.dev");
|
|
13
|
-
|
|
14
10
|
/** First package directory under ros2_ws/src (the colcon package name). */
|
|
15
11
|
export function ros2PackageName(root) {
|
|
16
12
|
const srcDir = resolve(root, "ros2_ws/src");
|
|
@@ -25,9 +21,6 @@ export function assertDockerReady() {
|
|
|
25
21
|
if (!hasBin("docker")) {
|
|
26
22
|
throw new Error("Docker not found. ROS2 needs Docker (Jazzy + Python 3.12 container).");
|
|
27
23
|
}
|
|
28
|
-
if (!existsSync(DOCKERFILE)) {
|
|
29
|
-
throw new Error(`kit Dockerfile missing at ${DOCKERFILE} (reinstall muscat-plugin-kit).`);
|
|
30
|
-
}
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
export const ARCH_DOCKER_PLATFORM = {
|
|
@@ -36,12 +29,13 @@ export const ARCH_DOCKER_PLATFORM = {
|
|
|
36
29
|
};
|
|
37
30
|
|
|
38
31
|
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
39
|
-
export function ensureImage(image = ROS2_DEV_IMAGE, { platform = null } = {}) {
|
|
32
|
+
export async function ensureImage(image = ROS2_DEV_IMAGE, { platform = null } = {}) {
|
|
33
|
+
const dockerfile = await resolveDockerfile("Dockerfile.dev");
|
|
40
34
|
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
41
35
|
const platformFlags = platform ? ["--platform", platform] : [];
|
|
42
36
|
const r = spawnSync(
|
|
43
37
|
"docker",
|
|
44
|
-
["build", ...platformFlags, "-t", image, "-f",
|
|
38
|
+
["build", ...platformFlags, "-t", image, "-f", dockerfile, dirname(dockerfile)],
|
|
45
39
|
{ stdio: "inherit" },
|
|
46
40
|
);
|
|
47
41
|
if (r.status !== 0) throw new Error("docker build failed.");
|
package/cli/src/util.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Shared helpers for muscat-pk.
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { createInterface } from "node:readline/promises";
|
|
7
8
|
|
|
@@ -129,6 +130,24 @@ export function humanSize(bytes) {
|
|
|
129
130
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
130
131
|
}
|
|
131
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Return the on-disk path of a bundled Dockerfile.
|
|
135
|
+
* In npm-install mode the real file exists under cli/docker/.
|
|
136
|
+
* In compiled-binary mode it doesn't — extract from the embedded snapshot to tmpdir.
|
|
137
|
+
*/
|
|
138
|
+
export async function resolveDockerfile(name) {
|
|
139
|
+
const real = resolve(kitRoot, "cli/docker", name);
|
|
140
|
+
if (existsSync(real)) return real;
|
|
141
|
+
const { TEMPLATES } = await import("./templates-embedded.mjs");
|
|
142
|
+
const b64 = TEMPLATES[`docker/${name}`];
|
|
143
|
+
if (!b64) throw new Error(`Embedded Dockerfile missing: docker/${name}. Reinstall muscat-plugin-kit.`);
|
|
144
|
+
const dir = resolve(tmpdir(), "muscat-pk-docker");
|
|
145
|
+
mkdirSync(dir, { recursive: true });
|
|
146
|
+
const tmp = resolve(dir, name);
|
|
147
|
+
writeFileSync(tmp, Buffer.from(b64, "base64"));
|
|
148
|
+
return tmp;
|
|
149
|
+
}
|
|
150
|
+
|
|
132
151
|
/** This kit's installed version (from its package.json). */
|
|
133
152
|
export function kitVersion() {
|
|
134
153
|
try {
|
|
@@ -178,8 +197,8 @@ export async function checkKitUpdate({ timeoutMs = 2000 } = {}) {
|
|
|
178
197
|
[
|
|
179
198
|
"",
|
|
180
199
|
line,
|
|
181
|
-
` muscat-plugin-kit
|
|
182
|
-
`
|
|
200
|
+
` muscat-plugin-kit update available: ${current} → ${latest}`,
|
|
201
|
+
` Update: muscat-pk update`,
|
|
183
202
|
line,
|
|
184
203
|
"",
|
|
185
204
|
].join("\n"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rainbow-robotics/muscat-plugin-kit",
|
|
3
|
-
"version": "0.1.2-dev.
|
|
3
|
+
"version": "0.1.2-dev.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@types/react-dom": "^19.0.4"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@rainbow-robotics/preview-host": "0.1.2-dev.
|
|
34
|
+
"@rainbow-robotics/preview-host": "0.1.2-dev.40",
|
|
35
35
|
"socket.io": "^4.8.1"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|