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

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이 떠 있으면 시뮬레이터를 붙이지 않습니다.
@@ -577,7 +577,6 @@ if (await rb.confirm({ title: "실행", message: "백엔드 동작을 시작할
577
577
  | `rb.program.getSteps(scope?)` | Program 페이지에 열린 프로그램의 메인 스텝 트리 |
578
578
  | `rb.program.setSteps(steps, scope?)` | 메인 스텝 트리 교체. 저장되지 않은 편집으로 들어가고 사용자가 저장 |
579
579
  | `rb.program.getCatalog(scope?)` | 로드된 로봇의 명령 카탈로그 (이름, 기본 인자, 중첩 규칙) |
580
- | `rb.program.getCommandDefaults?(command, scope?)` | 기본값이 실제 로봇 상태를 읽는 명령(카탈로그 `rules.hasFactoryDataFn`)의 기본 step. 선택적이며 호스트에 따라 없을 수 있음 |
581
580
 
582
581
  ```ts
583
582
  type PluginProgramStep = {
@@ -1029,7 +1028,7 @@ sudo apt update && sudo apt install rainbow-rb-sdk-dev
1029
1028
 
1030
1029
  - 이미 `:10000`을 노출하는 컨테이너(`muscat`, `muscat-dev` 등)가 있으면 재사용합니다. kit이 띄우지 않은 컨테이너는 플러그인 포트를 노출하지 않습니다.
1031
1030
  - 컨테이너 없이 그 포트를 이미 쓰는 Muscat(로봇 PC, host networking)이 있으면 그대로 씁니다.
1032
- - 없으면 `muscat-pk-muscat`을 띄웁니다 — `common`(+ `--sim`에 필요한 서비스)과 MediaMTX(`8554`, `8889`, `8189`)를 돌리는 S3 런타임 이미지(`muscat-pk-runtime:<version>`, `version.json` 기준)이며 `~/.muscat-pk/muscat/`에 캐시됩니다. 노출할 플러그인 포트나 서비스가 바뀌면 다시 만들고, Muscat 새 버전이 나오면 이전 이미지를 교체합니다.
1031
+ - 없으면 `muscat-pk-muscat`을 띄웁니다 — `common`(+ `--sim`에 필요한 서비스)과 MediaMTX(`8554`, `8889`, `8189`)를 돌리는 S3 런타임 이미지(`muscat-pk-runtime:<version>`, `version.json` 기준)이며 `~/.muscat-pk/muscat/`에 캐시됩니다. 노출할 플러그인 포트나 서비스가 바뀌면 다시 만들고, Muscat 새 버전이 나오면 이전 이미지를 교체합니다. 데이터(DB, 로그, 프로그램)는 컨테이너 안에만 있어서 컨테이너를 새로 만들면 비어 있습니다.
1033
1032
  - `dev`는 종료할 때 자신이 띄운 `muscat-pk-muscat`을 지웁니다. `dev:ui` 단독으로 띄운 것은 계속 떠 있습니다.
1034
1033
  - 백엔드는 로컬 Muscat의 network namespace에 붙으므로 `execute`와 SDK가 로봇에서처럼 닿습니다.
1035
1034
 
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.
@@ -577,7 +577,6 @@ if (await rb.confirm({ title: "Run", message: "Start the backend action?" })) {
577
577
  | `rb.program.getSteps(scope?)` | main step tree of the program open on the Program page |
578
578
  | `rb.program.setSteps(steps, scope?)` | replace it — an unsaved edit the user then saves |
579
579
  | `rb.program.getCatalog(scope?)` | the loaded robot's command catalog (names, default args, nesting rules) |
580
- | `rb.program.getCommandDefaults?(command, scope?)` | default step of a command whose defaults read the live robot (catalog `rules.hasFactoryDataFn`); optional, host-dependent |
581
580
 
582
581
  ```ts
583
582
  type PluginProgramStep = {
@@ -1029,7 +1028,7 @@ Without a robot IP (or against a robot that runs no Muscat), `dev` / `dev:ui` ne
1029
1028
 
1030
1029
  - reuses any container already publishing `:10000` (`muscat`, `muscat-dev`, …). A container not started by the kit does not publish the plugin's ports;
1031
1030
  - uses a Muscat already listening on those ports without a container (robot PC, host networking);
1032
- - otherwise starts `muscat-pk-muscat` — the S3 runtime image (`muscat-pk-runtime:<version>`, from `version.json`) running `common` (plus the services `--sim` needs) and MediaMTX (`8554`, `8889`, `8189`), cached in `~/.muscat-pk/muscat/`. It is recreated when the published plugin ports or services change, and a new Muscat version replaces the old image.
1031
+ - otherwise starts `muscat-pk-muscat` — the S3 runtime image (`muscat-pk-runtime:<version>`, from `version.json`) running `common` (plus the services `--sim` needs) and MediaMTX (`8554`, `8889`, `8189`), cached in `~/.muscat-pk/muscat/`. It is recreated when the published plugin ports or services change, and a new Muscat version replaces the old image. Its data (DB, logs, programs) lives in the container only, so a new container starts empty.
1033
1032
  - `dev` removes its own `muscat-pk-muscat` on exit; started by `dev:ui` alone it keeps running.
1034
1033
  - The backend joins the local Muscat's network namespace, so `execute` and the SDK reach it like on the robot.
1035
1034
 
@@ -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;
@@ -140,11 +140,13 @@ function ensureNetwork() {
140
140
  // listen-endpoints file opens both to the network. Sims reach common as muscat-pk-muscat:7447, and
141
141
  // gossip has them dial each service back — on loopback only the sim that happened to connect first
142
142
  // answers manipulate's receive_one.
143
- function writeZenohListen(open) {
144
- const file = resolve(CACHE, "data", "zenoh_listen_endpoints.json5");
145
- if (!open) return rmSync(file, { force: true });
143
+ // Mounted as the only file of /app/data; the rest of the runtime's data stays in the container.
144
+ function zenohListenMount(open) {
145
+ if (!open) return [];
146
+ const file = resolve(CACHE, "zenoh_listen_endpoints.json5");
146
147
  mkdirSync(dirname(file), { recursive: true });
147
148
  writeFileSync(file, `{\n common: ["tcp/0.0.0.0:7447"],\n service: ["tcp/0.0.0.0:0"],\n}\n`);
149
+ return ["-v", `${file}:/app/data/zenoh_listen_endpoints.json5:ro`];
148
150
  }
149
151
 
150
152
  async function waitForApi(timeoutMs = 180_000) {
@@ -249,7 +251,8 @@ export async function ensureLocalMuscat({ pluginPorts = [], zenohPort = null, se
249
251
  const svcMounts = [];
250
252
  for (const s of svcs) svcMounts.push("-v", `${await ensureServiceBinary(s, versions.services[s].version)}:/app/services/${s}`);
251
253
  ensureNetwork();
252
- writeZenohListen(services.length > 0);
254
+ // Earlier kits kept DB, logs and programs here across runs.
255
+ rmSync(resolve(CACHE, "data"), { recursive: true, force: true });
253
256
 
254
257
  let media = true;
255
258
  for (const port of MEDIA_PORTS) if (await isPortInUse(port)) media = false;
@@ -270,7 +273,7 @@ export async function ensureLocalMuscat({ pluginPorts = [], zenohPort = null, se
270
273
  "-e", "RB_RUNTIME_ENABLE_ZENOH_BRIDGE=0",
271
274
  ...envFlags,
272
275
  ...svcMounts,
273
- "-v", `${resolve(CACHE, "data")}:/app/data`,
276
+ ...zenohListenMount(services.length > 0),
274
277
  "-p", `127.0.0.1:${API_PORT}:${API_PORT}`,
275
278
  "-p", `127.0.0.1:${GATEWAY_PORT}:${GATEWAY_PORT}`,
276
279
  ...(media ? mediaPortFlags() : []),
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":1793162376536,"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":1793173800402,"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",
3
+ "version": "1.10.4-dev.1",
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",
57
- "@rainbow-robotics/preview-host": "1.10.3",
56
+ "@rainbow-robotics/plugin-ui": "1.10.4-dev.1",
57
+ "@rainbow-robotics/preview-host": "1.10.4-dev.1",
58
58
  "@types/react": "^19.0.10",
59
59
  "postcss": "^8.5.8",
60
60
  "typescript": "^5.8.0",