@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.14 → 0.1.2-dev.16
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 +13 -2
- package/cli/src/devBack.mjs +4 -6
- package/cli/src/pack.mjs +1 -4
- package/cli/src/update.mjs +95 -16
- package/cli/templates/common/manifest.json +0 -7
- package/cli/templates/common/requirements.txt +3 -3
- package/cli/templates/common/tsconfig.json +1 -1
- package/cli/templates/common/vite.config.ts +1 -1
- package/package.json +1 -1
- package/cli/templates/common/.vscode/settings.json +0 -3
- /package/cli/templates/common/{main.py → py/main.py} +0 -0
- /package/cli/templates/common/{src → ui}/content.tsx +0 -0
package/cli/src/build.mjs
CHANGED
|
@@ -147,7 +147,7 @@ const HOST_PROVIDED_EXTERNALS = [
|
|
|
147
147
|
|
|
148
148
|
export async function buildPlugin({ root, minify = false } = {}) {
|
|
149
149
|
const pluginRoot = root ?? findPluginRoot();
|
|
150
|
-
const entry = resolve(pluginRoot, "
|
|
150
|
+
const entry = resolve(pluginRoot, "ui/content.tsx");
|
|
151
151
|
if (!existsSync(entry)) {
|
|
152
152
|
throw new Error(`missing entry: ${entry}`);
|
|
153
153
|
}
|
|
@@ -155,7 +155,7 @@ export async function buildPlugin({ root, minify = false } = {}) {
|
|
|
155
155
|
rmSync(distDir, { recursive: true, force: true });
|
|
156
156
|
mkdirSync(distDir, { recursive: true });
|
|
157
157
|
|
|
158
|
-
log.step("bundling
|
|
158
|
+
log.step("bundling ui/content.tsx → dist/content.js");
|
|
159
159
|
await buildWithFallback({
|
|
160
160
|
entryPoints: [entry],
|
|
161
161
|
outfile: resolve(distDir, "content.js"),
|
|
@@ -176,11 +176,22 @@ export async function buildPlugin({ root, minify = false } = {}) {
|
|
|
176
176
|
// Generate sandbox.html — plugin authors don't manage this file.
|
|
177
177
|
writeFileSync(resolve(distDir, "sandbox.html"), SANDBOX_HTML, "utf8");
|
|
178
178
|
log.step("generated dist/sandbox.html");
|
|
179
|
+
|
|
179
180
|
const assetsSrc = resolve(pluginRoot, "assets");
|
|
180
181
|
if (existsSync(assetsSrc)) {
|
|
181
182
|
cpSync(assetsSrc, resolve(distDir, "assets"), { recursive: true });
|
|
182
183
|
}
|
|
183
184
|
|
|
185
|
+
// Backend runtime files — copy entire py/ into dist/, then requirements.txt from root.
|
|
186
|
+
const pySrc = resolve(pluginRoot, "py");
|
|
187
|
+
if (existsSync(pySrc)) {
|
|
188
|
+
cpSync(pySrc, distDir, { recursive: true });
|
|
189
|
+
}
|
|
190
|
+
const rootReqs = resolve(pluginRoot, "requirements.txt");
|
|
191
|
+
if (existsSync(rootReqs)) {
|
|
192
|
+
copyFileSync(rootReqs, resolve(distDir, "requirements.txt"));
|
|
193
|
+
}
|
|
194
|
+
|
|
184
195
|
log.ok(`built → ${distDir}`);
|
|
185
196
|
return { pluginRoot, distDir };
|
|
186
197
|
}
|
package/cli/src/devBack.mjs
CHANGED
|
@@ -31,6 +31,7 @@ function manifestRuntime(root) {
|
|
|
31
31
|
function runPython(root) {
|
|
32
32
|
const venv = resolve(root, ".venv");
|
|
33
33
|
const py = venvPython(venv);
|
|
34
|
+
const pyDir = resolve(root, "py");
|
|
34
35
|
|
|
35
36
|
if (!existsSync(py)) {
|
|
36
37
|
log.step("creating .venv…");
|
|
@@ -43,7 +44,7 @@ function runPython(root) {
|
|
|
43
44
|
if (!is312) log.warn("python3.12 not found; using fallback (robot targets 3.12).");
|
|
44
45
|
spawnSync(cmd[0], [...cmd.slice(1), "-m", "venv", venv], { cwd: root, stdio: "inherit" });
|
|
45
46
|
} else {
|
|
46
|
-
throw new Error("Python not found (uv / conda / python3 none available). Install Python 3.12 to run the
|
|
47
|
+
throw new Error("Python not found (uv / conda / python3 none available). Install Python 3.12 to run the py.");
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -53,9 +54,6 @@ function runPython(root) {
|
|
|
53
54
|
spawnSync(py, ["-m", "pip", "install", "-q", "-r", reqs], { cwd: root, stdio: "inherit" });
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
// watchfiles = uvicorn's reloader. --filter python watches every *.py in the
|
|
57
|
-
// project (and ignores .venv/__pycache__/node_modules), so interdependent
|
|
58
|
-
// modules trigger reloads — not just main.py.
|
|
59
57
|
log.step("pip install -q watchfiles (dev reloader)…");
|
|
60
58
|
spawnSync(py, ["-m", "pip", "install", "-q", "watchfiles"], { cwd: root, stdio: "inherit" });
|
|
61
59
|
|
|
@@ -63,10 +61,10 @@ function runPython(root) {
|
|
|
63
61
|
const backEnv = { ...process.env, ...(pluginId ? { RB_PLUGIN_ID: pluginId } : {}) };
|
|
64
62
|
if (pluginId) log.step(`RB_PLUGIN_ID=${pluginId}`);
|
|
65
63
|
|
|
66
|
-
log.step("watchfiles → python main.py (reload on any .py change)");
|
|
64
|
+
log.step("watchfiles → python py/main.py (reload on any .py change in py/)");
|
|
67
65
|
const child = spawn(
|
|
68
66
|
py,
|
|
69
|
-
["-m", "watchfiles", "--filter", "python", "--target-type", "command", "python main.py", "
|
|
67
|
+
["-m", "watchfiles", "--filter", "python", "--target-type", "command", "python py/main.py", "py"],
|
|
70
68
|
{ cwd: root, stdio: "inherit", env: backEnv },
|
|
71
69
|
);
|
|
72
70
|
const cleanup = () => { if (!child.killed) child.kill(); };
|
package/cli/src/pack.mjs
CHANGED
|
@@ -29,11 +29,8 @@ export async function runPack() {
|
|
|
29
29
|
const zipPath = resolve(pluginRoot, zipName);
|
|
30
30
|
rmSync(zipPath, { force: true });
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// dist/ already contains main.py, requirements.txt, manifest.json, assets/.
|
|
33
33
|
const entries = ["dist"];
|
|
34
|
-
for (const f of ["main.py", "requirements.txt"]) {
|
|
35
|
-
if (existsSync(resolve(pluginRoot, f))) entries.push(f);
|
|
36
|
-
}
|
|
37
34
|
if (existsSync(resolve(pluginRoot, "ros2_ws/install"))) {
|
|
38
35
|
entries.push("ros2_ws/install");
|
|
39
36
|
}
|
package/cli/src/update.mjs
CHANGED
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
// local : plugin project's node_modules (fallback)
|
|
9
9
|
// → <pm> add @rainbow-robotics/muscat-plugin-kit@<tag>
|
|
10
10
|
//
|
|
11
|
-
// After updating the CLI itself, also bumps the plugin project's local deps
|
|
11
|
+
// After updating the CLI itself, also bumps the plugin project's local deps
|
|
12
|
+
// and migrates the project structure if it's outdated (src/ → ui/, root main.py → py/).
|
|
13
|
+
import { createInterface } from "node:readline";
|
|
12
14
|
import { execSync, spawn } from "node:child_process";
|
|
13
|
-
import { chmodSync, copyFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
14
16
|
import { tmpdir } from "node:os";
|
|
15
17
|
import { join, resolve } from "node:path";
|
|
16
18
|
import { findPluginRoot, KIT_PUBLISHED_NAME, kitVersion, log, parseArgs } from "./util.mjs";
|
|
@@ -65,13 +67,13 @@ async function updateBinary(tag) {
|
|
|
65
67
|
const version = await resolveS3Version(tag);
|
|
66
68
|
const current = kitVersion();
|
|
67
69
|
if (version === current) {
|
|
68
|
-
log.ok(
|
|
70
|
+
log.ok(`Already up to date (v${current})`);
|
|
69
71
|
return;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
const binaryName = s3BinaryName();
|
|
73
75
|
const url = `${S3_BASE}/v${version}/${binaryName}`;
|
|
74
|
-
log.step(
|
|
76
|
+
log.step(`Downloading binary: v${current} → v${version}`);
|
|
75
77
|
|
|
76
78
|
const data = await fetchBinary(url);
|
|
77
79
|
const execPath = process.execPath;
|
|
@@ -88,14 +90,14 @@ async function updateBinary(tag) {
|
|
|
88
90
|
stdio: "ignore",
|
|
89
91
|
}).unref();
|
|
90
92
|
|
|
91
|
-
log.ok(`v${version}
|
|
93
|
+
log.ok(`v${version} downloaded. Will be applied on next run.`);
|
|
92
94
|
} else {
|
|
93
95
|
// macOS / Linux: can replace the file while it's mapped into memory
|
|
94
96
|
const tmp = join(tmpdir(), `muscat-pk-${version}`);
|
|
95
97
|
writeFileSync(tmp, data);
|
|
96
98
|
chmodSync(tmp, 0o755);
|
|
97
99
|
copyFileSync(tmp, execPath);
|
|
98
|
-
log.ok(`v${version}
|
|
100
|
+
log.ok(`Updated to v${version}.`);
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -104,7 +106,79 @@ async function updateBinary(tag) {
|
|
|
104
106
|
function updateNpmGlobal(tag) {
|
|
105
107
|
log.step(`npm install -g ${KIT_PUBLISHED_NAME}@${tag}`);
|
|
106
108
|
execSync(`npm install -g ${KIT_PUBLISHED_NAME}@${tag}`, { stdio: "inherit" });
|
|
107
|
-
log.ok("
|
|
109
|
+
log.ok("Global CLI updated.");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── project structure migration ───────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
function detectOldStructure(root) {
|
|
115
|
+
const issues = [];
|
|
116
|
+
if (existsSync(resolve(root, "src", "content.tsx")) && !existsSync(resolve(root, "ui"))) {
|
|
117
|
+
issues.push({ kind: "src→ui", desc: "src/content.tsx → ui/content.tsx" });
|
|
118
|
+
}
|
|
119
|
+
if (existsSync(resolve(root, "main.py")) && !existsSync(resolve(root, "py"))) {
|
|
120
|
+
issues.push({ kind: "main→py", desc: "main.py → py/main.py" });
|
|
121
|
+
}
|
|
122
|
+
if (existsSync(resolve(root, "backend"))) {
|
|
123
|
+
issues.push({ kind: "backend→py", desc: "backend/ → py/" });
|
|
124
|
+
}
|
|
125
|
+
return issues;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function prompt(question) {
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
131
|
+
rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); });
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function migrateStructure(root, issues) {
|
|
136
|
+
log.warn("This plugin project's structure is outdated:");
|
|
137
|
+
for (const issue of issues) log.info(" • " + issue.desc);
|
|
138
|
+
log.warn("Files will be moved and modified. Back up or commit your work before proceeding.");
|
|
139
|
+
|
|
140
|
+
const answer = await prompt("Migrate project structure? [y/N] ");
|
|
141
|
+
if (answer.toLowerCase() !== "y") {
|
|
142
|
+
log.info("Structure migration skipped.");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for (const issue of issues) {
|
|
147
|
+
if (issue.kind === "src→ui") {
|
|
148
|
+
renameSync(resolve(root, "src"), resolve(root, "ui"));
|
|
149
|
+
log.ok("src/ → ui/");
|
|
150
|
+
|
|
151
|
+
const vitePath = resolve(root, "vite.config.ts");
|
|
152
|
+
if (existsSync(vitePath)) {
|
|
153
|
+
writeFileSync(vitePath, readFileSync(vitePath, "utf8").replace(/["']src\/content\.tsx["']/g, '"ui/content.tsx"'));
|
|
154
|
+
log.ok("vite.config.ts entry updated");
|
|
155
|
+
}
|
|
156
|
+
const tscPath = resolve(root, "tsconfig.json");
|
|
157
|
+
if (existsSync(tscPath)) {
|
|
158
|
+
writeFileSync(tscPath, readFileSync(tscPath, "utf8").replace(/"src"/g, '"ui"'));
|
|
159
|
+
log.ok("tsconfig.json include updated");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (issue.kind === "main→py") {
|
|
164
|
+
mkdirSync(resolve(root, "py"), { recursive: true });
|
|
165
|
+
renameSync(resolve(root, "main.py"), resolve(root, "py", "main.py"));
|
|
166
|
+
log.ok("main.py → py/main.py");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (issue.kind === "backend→py") {
|
|
170
|
+
renameSync(resolve(root, "backend"), resolve(root, "py"));
|
|
171
|
+
log.ok("backend/ → py/");
|
|
172
|
+
const pyReqs = resolve(root, "py", "requirements.txt");
|
|
173
|
+
const rootReqs = resolve(root, "requirements.txt");
|
|
174
|
+
if (existsSync(pyReqs) && !existsSync(rootReqs)) {
|
|
175
|
+
renameSync(pyReqs, rootReqs);
|
|
176
|
+
log.ok("py/requirements.txt → requirements.txt (project root)");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
log.ok("Migration complete. Run `muscat-pk build` to verify.");
|
|
108
182
|
}
|
|
109
183
|
|
|
110
184
|
// ── plugin project local deps ─────────────────────────────────────────────────
|
|
@@ -117,12 +191,12 @@ function updateLocalDeps(root, tag) {
|
|
|
117
191
|
: pm === "yarn" ? `yarn add ${list.join(" ")}`
|
|
118
192
|
: `${pm} add ${list.join(" ")}`;
|
|
119
193
|
|
|
120
|
-
log.step(
|
|
194
|
+
log.step(`Updating plugin local deps (${pm}): ${list.join(", ")}`);
|
|
121
195
|
try {
|
|
122
196
|
execSync(cmd, { cwd: root, stdio: "inherit" });
|
|
123
|
-
log.ok("
|
|
197
|
+
log.ok("Local deps updated.");
|
|
124
198
|
} catch {
|
|
125
|
-
log.warn("
|
|
199
|
+
log.warn("Local deps update failed (offline?). Run manually:\n " + cmd);
|
|
126
200
|
}
|
|
127
201
|
}
|
|
128
202
|
|
|
@@ -134,14 +208,13 @@ export async function runUpdate(args = []) {
|
|
|
134
208
|
|
|
135
209
|
// 1. Update the CLI itself
|
|
136
210
|
if (isBinaryMode) {
|
|
137
|
-
log.step("
|
|
211
|
+
log.step("Updating binary…");
|
|
138
212
|
try {
|
|
139
213
|
await updateBinary(tag);
|
|
140
214
|
} catch (err) {
|
|
141
|
-
log.warn(
|
|
215
|
+
log.warn(`Binary update failed: ${err.message}`);
|
|
142
216
|
}
|
|
143
217
|
} else {
|
|
144
|
-
// Check if globally installed via npm (execPath's npm prefix contains this package)
|
|
145
218
|
const isGlobal = (() => {
|
|
146
219
|
try {
|
|
147
220
|
const prefix = execSync("npm prefix -g", { encoding: "utf8" }).trim();
|
|
@@ -155,16 +228,22 @@ export async function runUpdate(args = []) {
|
|
|
155
228
|
try {
|
|
156
229
|
updateNpmGlobal(tag);
|
|
157
230
|
} catch (err) {
|
|
158
|
-
log.warn(
|
|
231
|
+
log.warn(`Global CLI update failed: ${err.message}`);
|
|
159
232
|
}
|
|
160
233
|
}
|
|
161
234
|
}
|
|
162
235
|
|
|
163
|
-
// 2.
|
|
236
|
+
// 2. Plugin project: structure migration + local deps
|
|
164
237
|
try {
|
|
165
238
|
const root = findPluginRoot();
|
|
239
|
+
|
|
240
|
+
const structureIssues = detectOldStructure(root);
|
|
241
|
+
if (structureIssues.length > 0) {
|
|
242
|
+
await migrateStructure(root, structureIssues);
|
|
243
|
+
}
|
|
244
|
+
|
|
166
245
|
updateLocalDeps(root, tag);
|
|
167
246
|
} catch {
|
|
168
|
-
// Not inside a plugin project — skip
|
|
247
|
+
// Not inside a plugin project — skip silently
|
|
169
248
|
}
|
|
170
249
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
rainbow-rb-sdk
|
|
2
|
-
rainbow-rb-flat-buffers
|
|
3
|
-
|
|
1
|
+
rainbow-rb-sdk==0.0.9.dev40
|
|
2
|
+
rainbow-rb-flat-buffers==0.0.9.dev40
|
|
3
|
+
rainbow-rb-zenoh==0.0.9.dev40
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|