@rainbow-robotics/muscat-plugin-kit 1.10.3-dev.4 → 1.10.4-dev.0

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/README.ko.md CHANGED
@@ -169,7 +169,7 @@ muscat-pk dev:back [--robot-ip <ip>] [--robot-token <token>] [--keep-id]
169
169
 
170
170
  | 명령 | 실행되는 것 |
171
171
  |---|---|
172
- | `dev` | 로봇이 없거나 로봇에 Muscat이 없으면 로컬 Muscat 런타임, 그리고 `dev:ui` + `dev:back` |
172
+ | `dev` | 먼저 dev 이미지와 백엔드를 빌드하고(빌드 실패는 경고만), 로봇이 없거나 로봇에 Muscat이 없으면 로컬 Muscat 런타임, 그리고 `dev:ui` + `dev:back` |
173
173
  | `dev:ui` | 플러그인 Vite 개발 서버 + preview-host `http://localhost:4180` (사용 중이면 다음 빈 포트). 브라우저로 엶 |
174
174
  | `dev:back` | 로봇 환경과 같은 Docker 컨테이너에서 백엔드 실행. Python은 `py/**/*.py`가 바뀌면 재시작 (watchfiles) |
175
175
 
@@ -201,12 +201,12 @@ muscat-pk dev --sim rby1-m_v1.2
201
201
 
202
202
  | `--sim` | 함께 뜨는 Muscat 서비스 | 시뮬레이터 |
203
203
  |---|---|---|
204
- | `500880`, `500920` | common, log, manipulate | `rainbowroboticsofficial/cobot-sim` 1개 |
204
+ | `500920` | common, log, manipulate | `rainbowroboticsofficial/cobot-sim` 1개 |
205
205
  | `RBY2` | common, log, manipulate | cobot-sim 3개 (C500880, C501880, C502880) |
206
206
  | `rby1-a`, `rby1-m`, `rby1-ub` (`rby1-m_v1.2`처럼 버전 지정 가능) | common, log, rby1 | `rainbowroboticsofficial/rby1-sim` + Xvfb (로컬 빌드) |
207
207
 
208
- - 시뮬레이터 기종이 로컬 Muscat의 로봇 모델로 등록됩니다(`500880`은 C500880, `500920`은 C500920, `rby1-m`은 m). UI는 mock 프리뷰가 아니라 실제 Muscat 화면(대시보드, 컴포넌트, Move, Log, Settings)으로 뜹니다.
209
- - 시뮬레이터는 `--sim`을 줄 때만 뜹니다. 그 밖의 값이면 `--sim takes one of: 500880, 500920, RBY2, rby1-a, rby1-m, rby1-ub (rby1 also takes rby1-m_v1.2)` 오류가 납니다. manifest의 `targetModels`에 없는 기종이면 경고만 합니다.
208
+ - 시뮬레이터 기종이 로컬 Muscat의 로봇 모델로 등록됩니다(`500920`은 C500920, `rby1-m`은 m). UI는 mock 프리뷰가 아니라 실제 Muscat 화면(대시보드, 컴포넌트, Move, Log, Settings)으로 뜹니다.
209
+ - 시뮬레이터는 `--sim`을 줄 때만 뜹니다. 그 밖의 값이면 `--sim takes one of: 500920, RBY2, rby1-a, rby1-m, rby1-ub (rby1 also takes rby1-m_v1.2)` 오류가 납니다. manifest의 `targetModels`에 없는 기종이면 경고만 합니다.
210
210
  - 시뮬레이터 이미지는 Docker Hub의 최신 태그를 씁니다 (rby1에 버전을 주면 그 버전 태그). 오프라인이면 이미 받아 둔 이미지를 씁니다.
211
211
  - rby1-sim은 화면을 계속 렌더링하므로 CPU를 1코어 정도 씁니다. 상한은 `MUSCAT_PK_RBY1_CPUS`(기본 1.5)입니다.
212
212
  - `muscat-dev` 같은 다른 Muscat이 떠 있으면 시뮬레이터를 붙이지 않습니다.
package/README.md CHANGED
@@ -169,7 +169,7 @@ muscat-pk dev:back [--robot-ip <ip>] [--robot-token <token>] [--keep-id]
169
169
 
170
170
  | Command | What runs |
171
171
  |---|---|
172
- | `dev` | a local Muscat runtime when no robot is given (or the robot runs no Muscat), then `dev:ui` and `dev:back` |
172
+ | `dev` | builds the dev image and backend first (a failed build only warns), then a local Muscat runtime when no robot is given (or the robot runs no Muscat), then `dev:ui` and `dev:back` |
173
173
  | `dev:ui` | the plugin's Vite dev server + preview-host at `http://localhost:4180` (next free port), opened in the browser |
174
174
  | `dev:back` | the backend in a Docker container matching the robot. Python restarts on `py/**/*.py` changes (watchfiles) |
175
175
 
@@ -201,12 +201,12 @@ muscat-pk dev --sim rby1-m_v1.2
201
201
 
202
202
  | `--sim` | Muscat services | Simulator |
203
203
  |---|---|---|
204
- | `500880`, `500920` | common, log, manipulate | one `rainbowroboticsofficial/cobot-sim` |
204
+ | `500920` | common, log, manipulate | one `rainbowroboticsofficial/cobot-sim` |
205
205
  | `RBY2` | common, log, manipulate | three cobot-sim (C500880, C501880, C502880) |
206
206
  | `rby1-a`, `rby1-m`, `rby1-ub` (or a version, e.g. `rby1-m_v1.2`) | common, log, rby1 | `rainbowroboticsofficial/rby1-sim` + Xvfb, built locally |
207
207
 
208
- - The simulated model is registered as the local Muscat's robot model (`500880` → C500880, `500920` → C500920, `rby1-m` → m). The UI is then the real Muscat UI (dashboard, components, Move, Log, Settings) instead of the mock preview.
209
- - A simulator runs only with `--sim`. Any other value fails with `--sim takes one of: 500880, 500920, RBY2, rby1-a, rby1-m, rby1-ub (rby1 also takes rby1-m_v1.2)`. A model missing from the manifest's `targetModels` only gets a warning.
208
+ - The simulated model is registered as the local Muscat's robot model (`500920` → C500920, `rby1-m` → m). The UI is then the real Muscat UI (dashboard, components, Move, Log, Settings) instead of the mock preview.
209
+ - A simulator runs only with `--sim`. Any other value fails with `--sim takes one of: 500920, RBY2, rby1-a, rby1-m, rby1-ub (rby1 also takes rby1-m_v1.2)`. A model missing from the manifest's `targetModels` only gets a warning.
210
210
  - Simulator images use the latest Docker Hub tag (an rby1 version picks the matching tag). Offline, an already pulled image is used.
211
211
  - rby1-sim keeps rendering, so it uses about one CPU core. The cap is `MUSCAT_PK_RBY1_CPUS` (default 1.5).
212
212
  - No simulator is attached while another Muscat such as `muscat-dev` is running.
@@ -88,7 +88,7 @@ function formatHelp() {
88
88
  commandRow("new [dir]", `Scaffold a new plugin project ${color.dim("(prompts: author, email, description, type, front-package-manager)")}`),
89
89
  commandRow("type change", `Switch backend type ${color.dim("(python | cpp | ros2-python | ros2-cpp)")}`),
90
90
  commandRow("build", `Build + lock deps + vendor wheels + zip ${color.dim(`(${option("--arch")} amd64|arm64|both)`)}`),
91
- commandRow("dev", `Run a local Muscat runtime, dev:ui, and dev:back together ${color.dim(`(${option("--sim")} 500880|500920|RBY2|rby1-a|rby1-m|rby1-ub)`)}`),
91
+ commandRow("dev", `Run a local Muscat runtime, dev:ui, and dev:back together ${color.dim(`(${option("--sim")} 500920|RBY2|rby1-a|rby1-m|rby1-ub)`)}`),
92
92
  commandRow("dev:ui", `Preview the plugin in a mini-Muscat ${color.dim("(preview-host)")}`),
93
93
  commandRow("dev:back", `Run the plugin back end ${color.dim("(python: watchfiles reload / ros2: Docker)")}`),
94
94
  commandRow("storybook", `Browse the bundled rb-components Storybook ${color.dim(`(${option("--port")} <n>, ${option("--rebuild")})`)}`),
package/cli/src/dev.mjs CHANGED
@@ -6,6 +6,7 @@ import { connect as netConnect } from "node:net";
6
6
  import { resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { runDevUi } from "./devUi.mjs";
9
+ import { prebuildBackend } from "./devBack.mjs";
9
10
  import { claimDevSession, stopDevBackContainers } from "./devSession.mjs";
10
11
  import { ensureLocalMuscat, GATEWAY_PORT, isPortInUse, MUSCAT_CONTAINER, robotHasMuscat } from "./muscatLocal.mjs";
11
12
  import { resolveSim, startSim, stopSims } from "./sim.mjs";
@@ -126,6 +127,7 @@ export async function runDev(args = []) {
126
127
  const remoteRobot = isRemoteRobot(robotIp);
127
128
  // Before dev:back is spawned: it inherits the id through the environment.
128
129
  devPluginId(readManifest(root).id, { robotIp, args });
130
+ await prebuildBackend(root);
129
131
  const hostAgent = await maybeStartHostAgent(root, { robotIp, robotToken });
130
132
  const proxyEndpoint = process.env.MUSCAT_PROXY_ENDPOINT || "";
131
133
  // No proxy (Linux, disabled, ...): fall back to the container reverse-dialing
@@ -30,12 +30,14 @@ import {
30
30
  import {
31
31
  ROS2_DEV_IMAGE,
32
32
  assertDockerReady,
33
+ colconBuild,
33
34
  ensureImage,
34
35
  ros2PackageName,
35
36
  } from "./ros2.mjs";
36
37
  import {
37
38
  CPP_DEV_IMAGE,
38
39
  assertDockerReady as cppAssertDockerReady,
40
+ cmakeBuild,
39
41
  ensureImage as cppEnsureImage,
40
42
  } from "./cpp.mjs";
41
43
 
@@ -683,6 +685,28 @@ async function runCpp(root, portRanges, robotGateway) {
683
685
  process.on("SIGHUP", cleanup);
684
686
  }
685
687
 
688
+ // `dev` builds the image and the backend first so the runtime and UI come up with it ready;
689
+ // dev:back's own build is then incremental. A failed build is left to dev:back's watcher.
690
+ export async function prebuildBackend(root) {
691
+ try {
692
+ const type = manifestRuntime(root);
693
+ if (type === "cpp") {
694
+ cppAssertDockerReady();
695
+ await cppEnsureImage();
696
+ cmakeBuild(root);
697
+ } else if (type === "ros2") {
698
+ assertDockerReady();
699
+ await ensureImage();
700
+ colconBuild(root, { symlink: true });
701
+ } else {
702
+ pyAssertDockerReady();
703
+ await pyEnsureImage();
704
+ }
705
+ } catch (e) {
706
+ log.warn(`backend build: ${e.message}`);
707
+ }
708
+ }
709
+
686
710
  function warnManifest(root) {
687
711
  const manifest = readManifest(root);
688
712
  if (!manifest || Object.keys(manifest).length === 0) return;
package/cli/src/sim.mjs CHANGED
@@ -14,7 +14,6 @@ const SIM_LABEL = "com.rainbow-robotics.muscat-pk.sim";
14
14
  // ponytail: model table in code; move to S3 version.json when sims are versioned with Muscat (amr: no sim yet)
15
15
  // sim name → coreSW RB_MODEL per component, and the Muscat robot model it registers as.
16
16
  const COBOT_MODELS = {
17
- "500880": { robotModel: "C500880", models: ["500880"] },
18
17
  "500920": { robotModel: "C500920", models: ["500920"] },
19
18
  RBY2: { robotModel: "RBY2", models: ["C500880", "C501880", "C502880"] },
20
19
  };
@@ -38,7 +37,7 @@ export function runSimList() {
38
37
  for (const t of RBY1_TYPES) console.log(`rby1-${t}\tRB-Y1 ${t.toUpperCase()}`);
39
38
  }
40
39
 
41
- /** "500880" | "RBY2" | "rby1-m" | "rby1-m_v1.2" → { services, env, ... } or null. */
40
+ /** "500920" | "RBY2" | "rby1-m" | "rby1-m_v1.2" → { services, env, ... } or null. */
42
41
  export function parseSim(name) {
43
42
  if (COBOT_MODELS[name]) return { name, kind: "cobot", services: ["log", "manipulate"], env: {}, ...COBOT_MODELS[name] };
44
43
  const m = /^rby1-(a|m|ub)(?:_(v[\d.]+))?$/.exec(name ?? "");
@@ -1 +1 @@
1
- {"generatedAt":1793152262101,"userSince":1750932757926,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"testPackages":{"@vitest/browser":"3.2.4","@vitest/coverage-v8":"3.2.4","playwright":"1.59.1","vitest":"3.2.4"},"hasRouterPackage":false,"monorepo":"Turborepo","packageManager":{"type":"yarn","version":"berry","agent":"yarn@berry"},"preview":{"usesGlobals":false},"framework":{"name":"@storybook/react-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/react","portableStoriesFileCount":0,"applicationFileCount":0,"storybookVersion":"8.6.18","storybookVersionSpecifier":"^8.6.4","language":"typescript","storybookPackages":{"@chromatic-com/storybook":{"version":"3.2.7"},"@storybook/addon-essentials":{"version":"8.6.18"},"@storybook/addon-links":{"version":"8.6.18"},"@storybook/addon-onboarding":{"version":"8.6.18"},"@storybook/addon-themes":{"version":"8.6.18"},"@storybook/blocks":{"version":"8.6.18"},"@storybook/experimental-addon-test":{"version":"8.6.18"},"@storybook/react":{"version":"8.6.18"},"@storybook/react-vite":{"version":"8.6.18"},"@storybook/test":{"version":"8.6.18"},"@storybook/theming":{"version":"8.6.18"},"eslint-plugin-storybook":{"version":"0.11.6"},"storybook":{"version":"8.6.18"},"storybook-addon-react-docgen":{"version":"1.2.44"}},"addons":{"$SNIP/node_modules/@storybook/addon-links":{"version":null},"$SNIP/node_modules/@storybook/addon-essentials":{"version":null},"$SNIP/node_modules/@chromatic-com/storybook":{"version":null},"$SNIP/node_modules/@storybook/addon-themes":{"version":null},"$SNIP/node_modules/@storybook/experimental-addon-test":{"version":null}}}
1
+ {"generatedAt":1793172604703,"userSince":1750932757926,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"testPackages":{"@vitest/browser":"3.2.4","@vitest/coverage-v8":"3.2.4","playwright":"1.59.1","vitest":"3.2.4"},"hasRouterPackage":false,"monorepo":"Turborepo","packageManager":{"type":"yarn","version":"berry","agent":"yarn@berry"},"preview":{"usesGlobals":false},"framework":{"name":"@storybook/react-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/react","portableStoriesFileCount":0,"applicationFileCount":0,"storybookVersion":"8.6.18","storybookVersionSpecifier":"^8.6.4","language":"typescript","storybookPackages":{"@chromatic-com/storybook":{"version":"3.2.7"},"@storybook/addon-essentials":{"version":"8.6.18"},"@storybook/addon-links":{"version":"8.6.18"},"@storybook/addon-onboarding":{"version":"8.6.18"},"@storybook/addon-themes":{"version":"8.6.18"},"@storybook/blocks":{"version":"8.6.18"},"@storybook/experimental-addon-test":{"version":"8.6.18"},"@storybook/react":{"version":"8.6.18"},"@storybook/react-vite":{"version":"8.6.18"},"@storybook/test":{"version":"8.6.18"},"@storybook/theming":{"version":"8.6.18"},"eslint-plugin-storybook":{"version":"0.11.6"},"storybook":{"version":"8.6.18"},"storybook-addon-react-docgen":{"version":"1.2.44"}},"addons":{"$SNIP/node_modules/@storybook/addon-links":{"version":null},"$SNIP/node_modules/@storybook/addon-essentials":{"version":null},"$SNIP/node_modules/@chromatic-com/storybook":{"version":null},"$SNIP/node_modules/@storybook/addon-themes":{"version":null},"$SNIP/node_modules/@storybook/experimental-addon-test":{"version":null}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-robotics/muscat-plugin-kit",
3
- "version": "1.10.3-dev.4",
3
+ "version": "1.10.4-dev.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20"
@@ -53,8 +53,8 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@modelcontextprotocol/sdk": "^1.29.0",
56
- "@rainbow-robotics/plugin-ui": "1.10.3-dev.4",
57
- "@rainbow-robotics/preview-host": "1.10.3-dev.4",
56
+ "@rainbow-robotics/plugin-ui": "1.10.4-dev.0",
57
+ "@rainbow-robotics/preview-host": "1.10.4-dev.0",
58
58
  "@types/react": "^19.0.10",
59
59
  "postcss": "^8.5.8",
60
60
  "typescript": "^5.8.0",