@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.35 → 0.1.2-dev.36
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/src/build.mjs +5 -26
- package/cli/src/check-package.mjs +8 -24
- package/cli/src/devBack.mjs +3 -15
- package/cli/src/manifest.mjs +4 -0
- package/cli/src/new.mjs +1 -10
- package/cli/src/type.mjs +1 -10
- package/cli/src/update.mjs +1 -9
- package/cli/src/util.mjs +10 -0
- package/package.json +2 -2
package/cli/src/build.mjs
CHANGED
|
@@ -14,8 +14,8 @@ import { createRequire } from "node:module";
|
|
|
14
14
|
import { basename, dirname, resolve } from "node:path";
|
|
15
15
|
import { createInterface } from "node:readline/promises";
|
|
16
16
|
import { execSync, spawnSync } from "node:child_process";
|
|
17
|
-
import { ensureDocker, findPluginRoot, hasBin, humanSize, log } from "./util.mjs";
|
|
18
|
-
import { assertManifest } from "./manifest.mjs";
|
|
17
|
+
import { ensureDocker, findPluginRoot, hasBin, humanSize, log, parseArgs } from "./util.mjs";
|
|
18
|
+
import { assertManifest, manifestRuntime } from "./manifest.mjs";
|
|
19
19
|
|
|
20
20
|
// Find a usable node binary (for running vite as subprocess).
|
|
21
21
|
function findNodeBin() {
|
|
@@ -60,14 +60,6 @@ function isMainBranch() {
|
|
|
60
60
|
return branch === "main" || branch === "master";
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
function manifestRuntime(root) {
|
|
64
|
-
try {
|
|
65
|
-
return JSON.parse(readFileSync(resolve(root, "manifest.json"), "utf8")).runtime?.type ?? "python";
|
|
66
|
-
} catch {
|
|
67
|
-
return "python";
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
63
|
// For ros2 plugins, compile the colcon workspace inside the Jazzy + Python 3.12 container.
|
|
72
64
|
// rclpy: arch-agnostic (pure Python) → dist/ros2_ws/install/ (built once)
|
|
73
65
|
// rclcpp: arch-specific C++ binaries → dist/ros2_ws/install-{arch}/ per arch
|
|
@@ -280,18 +272,7 @@ export async function buildPlugin({ root, minify = false } = {}) {
|
|
|
280
272
|
return { pluginRoot, distDir };
|
|
281
273
|
}
|
|
282
274
|
|
|
283
|
-
function dirSize(dir) {
|
|
284
|
-
let total = 0;
|
|
285
|
-
for (const entry of readdirSync(dir)) {
|
|
286
|
-
const full = resolve(dir, entry);
|
|
287
|
-
const st = statSync(full);
|
|
288
|
-
total += st.isDirectory() ? dirSize(full) : st.size;
|
|
289
|
-
}
|
|
290
|
-
return total;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Recursively sum directory size, skipping subdirs in `skip` list (by name).
|
|
294
|
-
function dirSizeExcluding(dir, skip = []) {
|
|
275
|
+
function dirSize(dir, skip = []) {
|
|
295
276
|
if (!existsSync(dir)) return 0;
|
|
296
277
|
let total = 0;
|
|
297
278
|
for (const entry of readdirSync(dir)) {
|
|
@@ -313,7 +294,7 @@ function dirSizeExcluding(dir, skip = []) {
|
|
|
313
294
|
function calcInstalledSize(pluginRoot) {
|
|
314
295
|
const distDir = resolve(pluginRoot, "dist");
|
|
315
296
|
|
|
316
|
-
const installedSize =
|
|
297
|
+
const installedSize = dirSize(distDir, ["wheels"]);
|
|
317
298
|
|
|
318
299
|
// Write to root manifest.json
|
|
319
300
|
const rootManifestPath = resolve(pluginRoot, "manifest.json");
|
|
@@ -369,9 +350,7 @@ function packZip(pluginRoot) {
|
|
|
369
350
|
* @returns {Promise<string[]>} e.g. ['amd64'] | ['arm64'] | ['amd64','arm64']
|
|
370
351
|
*/
|
|
371
352
|
async function promptArch(args = []) {
|
|
372
|
-
|
|
373
|
-
const archFlag = args.find((a) => a.startsWith("--arch="))?.slice(7)
|
|
374
|
-
?? (args.includes("--arch") ? args[args.indexOf("--arch") + 1] : null);
|
|
353
|
+
const archFlag = parseArgs(args).arch ?? null;
|
|
375
354
|
if (archFlag) {
|
|
376
355
|
if (archFlag === "both") return ["amd64", "arm64"];
|
|
377
356
|
if (archFlag === "amd64" || archFlag === "x86_64") return ["amd64"];
|
|
@@ -1,29 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
6
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (stat.isDirectory()) {
|
|
14
|
-
if (entry === "dist" || entry === "runtime" || entry === "templates") {
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
yield* mjsFiles(full);
|
|
18
|
-
} else if (entry.endsWith(".mjs")) {
|
|
19
|
-
yield full;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
for (const dir of roots) {
|
|
25
|
-
if (!existsSync(dir)) continue;
|
|
26
|
-
for (const file of mjsFiles(dir)) {
|
|
27
|
-
execFileSync(process.execPath, ["--check", file], { stdio: "inherit" });
|
|
28
|
-
}
|
|
7
|
+
for (const dir of ["cli", "preview-host"]) {
|
|
8
|
+
if (!existsSync(resolve(root, dir))) continue;
|
|
9
|
+
execSync(
|
|
10
|
+
`find ${dir} -name '*.mjs' ! -path '*/dist/*' ! -path '*/runtime/*' ! -path '*/templates/*' -exec node --check {} +`,
|
|
11
|
+
{ cwd: root, stdio: "inherit" },
|
|
12
|
+
);
|
|
29
13
|
}
|
package/cli/src/devBack.mjs
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
// ros2 : Jazzy + Python 3.12 container, colcon build, run the node, restart
|
|
9
9
|
// on source changes (rclcpp rebuilds on change).
|
|
10
10
|
import { spawn, spawnSync } from "node:child_process";
|
|
11
|
-
import { existsSync,
|
|
11
|
+
import { existsSync, watch } from "node:fs";
|
|
12
12
|
import { resolve } from "node:path";
|
|
13
13
|
import { ensureDocker, findPluginRoot, log } from "./util.mjs";
|
|
14
|
-
import { readManifest
|
|
14
|
+
import { manifestRuntime, readManifest, validateManifest } from "./manifest.mjs";
|
|
15
15
|
import {
|
|
16
16
|
PYTHON_DEV_IMAGE,
|
|
17
17
|
assertDockerReady as pyAssertDockerReady,
|
|
@@ -29,18 +29,6 @@ import {
|
|
|
29
29
|
ensureImage as cppEnsureImage,
|
|
30
30
|
} from "./cpp.mjs";
|
|
31
31
|
|
|
32
|
-
function readManifest(root) {
|
|
33
|
-
try {
|
|
34
|
-
return JSON.parse(readFileSync(resolve(root, "manifest.json"), "utf8"));
|
|
35
|
-
} catch {
|
|
36
|
-
return {};
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function manifestRuntime(root) {
|
|
41
|
-
return readManifest(root).runtime?.type ?? "python";
|
|
42
|
-
}
|
|
43
|
-
|
|
44
32
|
// ── python ────────────────────────────────────────────────────────────────────
|
|
45
33
|
// Runs in a warm Ubuntu 24.04 + Python 3.12 container (matches the robot).
|
|
46
34
|
// Under `muscat-pk dev`, it shares the bridge container's netns, so the SDK
|
|
@@ -245,7 +233,7 @@ function runCpp(root) {
|
|
|
245
233
|
}
|
|
246
234
|
|
|
247
235
|
function warnManifest(root) {
|
|
248
|
-
const manifest =
|
|
236
|
+
const manifest = readManifest(root);
|
|
249
237
|
if (!manifest || Object.keys(manifest).length === 0) return;
|
|
250
238
|
const errors = validateManifest(manifest);
|
|
251
239
|
for (const e of errors) log.warn(`manifest.json: ${e}`);
|
package/cli/src/manifest.mjs
CHANGED
|
@@ -36,6 +36,10 @@ export function readManifest(root) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
export function manifestRuntime(root) {
|
|
40
|
+
return readManifest(root)?.runtime?.type ?? "python";
|
|
41
|
+
}
|
|
42
|
+
|
|
39
43
|
function validateIcons(icons, errors) {
|
|
40
44
|
if (icons === undefined || icons === null) {
|
|
41
45
|
errors.push("icons is required");
|
package/cli/src/new.mjs
CHANGED
|
@@ -10,10 +10,9 @@ import {
|
|
|
10
10
|
statSync,
|
|
11
11
|
writeFileSync,
|
|
12
12
|
} from "node:fs";
|
|
13
|
-
import { createInterface } from "node:readline/promises";
|
|
14
13
|
import { basename, resolve } from "node:path";
|
|
15
14
|
import { rmSync } from "node:fs";
|
|
16
|
-
import { hasBin, kitVersion, parseArgs, templatesDir, log } from "./util.mjs";
|
|
15
|
+
import { hasBin, kitVersion, parseArgs, prompt, templatesDir, log } from "./util.mjs";
|
|
17
16
|
|
|
18
17
|
// `--type` values map to a runtime descriptor. ros2 has a python (rclpy) and a
|
|
19
18
|
// C++ (rclcpp) flavor; we expose them as distinct type choices for clarity.
|
|
@@ -41,14 +40,6 @@ export function runtimeForChoice(choice, slug) {
|
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
async function prompt(question, fallback) {
|
|
45
|
-
if (!process.stdin.isTTY) return fallback;
|
|
46
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
47
|
-
const answer = (await rl.question(question)).trim();
|
|
48
|
-
rl.close();
|
|
49
|
-
return answer || fallback;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
43
|
export function applyTokens(dir, tokens) {
|
|
53
44
|
for (const entry of readdirSync(dir)) {
|
|
54
45
|
const full = resolve(dir, entry);
|
package/cli/src/type.mjs
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
// Adds the matching backend overlay; never deletes existing user code
|
|
4
4
|
// (e.g. ros2_ws/ or cpp/ are left in place when switching away).
|
|
5
5
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { createInterface } from "node:readline/promises";
|
|
7
6
|
import { basename, resolve } from "node:path";
|
|
8
|
-
import { findPluginRoot, log } from "./util.mjs";
|
|
7
|
+
import { findPluginRoot, log, prompt } from "./util.mjs";
|
|
9
8
|
import {
|
|
10
9
|
TYPE_CHOICES,
|
|
11
10
|
applyTokens,
|
|
@@ -17,14 +16,6 @@ import {
|
|
|
17
16
|
|
|
18
17
|
const TYPES = Object.keys(TYPE_CHOICES);
|
|
19
18
|
|
|
20
|
-
async function prompt(question, fallback) {
|
|
21
|
-
if (!process.stdin.isTTY) return fallback;
|
|
22
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
23
|
-
const answer = (await rl.question(question)).trim();
|
|
24
|
-
rl.close();
|
|
25
|
-
return answer || fallback;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
19
|
function readManifest(root) {
|
|
29
20
|
const path = resolve(root, "manifest.json");
|
|
30
21
|
if (!existsSync(path)) throw new Error(`manifest.json not found in ${root}`);
|
package/cli/src/update.mjs
CHANGED
|
@@ -10,12 +10,11 @@
|
|
|
10
10
|
//
|
|
11
11
|
// After updating the CLI itself, also bumps the plugin project's local deps
|
|
12
12
|
// and migrates the project structure if it's outdated (src/ → ui/, root main.py → py/).
|
|
13
|
-
import { createInterface } from "node:readline";
|
|
14
13
|
import { execSync, spawn } from "node:child_process";
|
|
15
14
|
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
16
15
|
import { tmpdir } from "node:os";
|
|
17
16
|
import { join, resolve } from "node:path";
|
|
18
|
-
import { findPluginRoot, KIT_PUBLISHED_NAME, kitVersion, log, parseArgs } from "./util.mjs";
|
|
17
|
+
import { findPluginRoot, KIT_PUBLISHED_NAME, kitVersion, log, parseArgs, prompt } from "./util.mjs";
|
|
19
18
|
|
|
20
19
|
const PLUGIN_UI_PACKAGE = "@rainbow-robotics/plugin-ui";
|
|
21
20
|
const S3_BASE = "https://rainbow-deploy.s3.ap-northeast-2.amazonaws.com/muscat-plugin-kit";
|
|
@@ -135,13 +134,6 @@ function detectOldStructure(root) {
|
|
|
135
134
|
return issues;
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
function prompt(question) {
|
|
139
|
-
return new Promise((resolve) => {
|
|
140
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
141
|
-
rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); });
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
137
|
async function migrateStructure(root, issues) {
|
|
146
138
|
log.warn("This plugin project's structure is outdated:");
|
|
147
139
|
for (const issue of issues) log.info(" • " + issue.desc);
|
package/cli/src/util.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createInterface } from "node:readline/promises";
|
|
6
7
|
|
|
7
8
|
/** True if an executable is on PATH (cross-platform). */
|
|
8
9
|
export function hasBin(bin) {
|
|
@@ -65,6 +66,15 @@ export function parseArgs(args, { booleans = [] } = {}) {
|
|
|
65
66
|
return out;
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
/** Prompt user for input. Returns trimmed answer or fallback (non-TTY or empty). */
|
|
70
|
+
export async function prompt(question, fallback = "") {
|
|
71
|
+
if (!process.stdin.isTTY) return fallback;
|
|
72
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
73
|
+
const answer = (await rl.question(question)).trim();
|
|
74
|
+
rl.close();
|
|
75
|
+
return answer || fallback;
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
/** Walk up from cwd to find the plugin project root (has manifest.json). */
|
|
69
79
|
export function findPluginRoot(start = process.cwd()) {
|
|
70
80
|
let dir = resolve(start);
|
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.36",
|
|
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.36",
|
|
35
35
|
"socket.io": "^4.8.1"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|