@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.49 → 0.1.2-dev.50

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.
@@ -75,7 +75,7 @@ export async function startBridge() {
75
75
  log.step("starting Socket.IO bridge container…");
76
76
  const up = spawnSync(
77
77
  "docker",
78
- ["run", "-d", "--name", BRIDGE_CONTAINER, "-p", `${BRIDGE_PORT}:${BRIDGE_PORT}`, BRIDGE_IMAGE],
78
+ ["run", "-d", "--name", BRIDGE_CONTAINER, "-p", `127.0.0.1:${BRIDGE_PORT}:${BRIDGE_PORT}`, BRIDGE_IMAGE],
79
79
  { stdio: "inherit" },
80
80
  );
81
81
  if (up.status !== 0) throw new Error("failed to start bridge container.");
package/cli/src/dev.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // muscat-pk dev — run the Socket.IO bridge (Docker), dev:ui, and dev:back together.
2
2
  import { runDevUi } from "./devUi.mjs";
3
- import { runDevBack } from "./devBack.mjs";
3
+ import { runDevBack, stopDevBackContainers } from "./devBack.mjs";
4
4
  import { startBridge, stopBridge, BRIDGE_CONTAINER, BRIDGE_PORT } from "./bridge.mjs";
5
5
  import { assertManifestPorts } from "./manifest.mjs";
6
6
  import { formatPortRanges } from "./ports.mjs";
@@ -31,7 +31,12 @@ export async function runDev(args = []) {
31
31
  process.env.MUSCAT_PK_BRIDGE_CONTAINER = BRIDGE_CONTAINER;
32
32
  }
33
33
 
34
- const cleanup = () => { if (bridgeStarted) stopBridge(); };
34
+ process.env.MUSCAT_PK_MANAGED_DEV = "1";
35
+
36
+ const cleanup = () => {
37
+ stopDevBackContainers();
38
+ if (bridgeStarted) stopBridge();
39
+ };
35
40
  process.once("SIGINT", cleanup);
36
41
  process.once("SIGTERM", cleanup);
37
42
  process.once("exit", cleanup);
@@ -34,6 +34,22 @@ import {
34
34
  ensureImage as cppEnsureImage,
35
35
  } from "./cpp.mjs";
36
36
 
37
+ const MANAGED_DEV_ENV = "MUSCAT_PK_MANAGED_DEV";
38
+
39
+ function exitAfterCleanup(code = 0) {
40
+ if (process.env[MANAGED_DEV_ENV] !== "1") process.exit(code ?? 0);
41
+ }
42
+
43
+ export function stopDevBackContainers() {
44
+ for (const container of [
45
+ `${PYTHON_DEV_IMAGE}-run`,
46
+ `${ROS2_DEV_IMAGE}-run`,
47
+ `${CPP_DEV_IMAGE}-run`,
48
+ ]) {
49
+ spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" });
50
+ }
51
+ }
52
+
37
53
  // ── IDE tooling venv (best-effort, non-blocking) ────────────────────────────
38
54
  // `muscat-pk new` already creates this up front (see new.mjs); this just
39
55
  // refreshes it on every `dev`/`dev:back` in case requirements.txt changed.
@@ -72,6 +88,9 @@ async function runPython(root, portRanges) {
72
88
  // bridge (set by `muscat-pk dev`). Standalone dev:back has no bridge to join.
73
89
  const bridgeContainer = process.env.MUSCAT_PK_BRIDGE_CONTAINER;
74
90
  const netFlags = bridgeContainer ? ["--network", `container:${bridgeContainer}`] : [];
91
+ const hostGatewayFlags = bridgeContainer
92
+ ? []
93
+ : ["--add-host", "host.docker.internal:host-gateway"];
75
94
  // Without the bridge's netns, this container is isolated — its own
76
95
  // 127.0.0.1 (rainbow.rb_sdk's gateway default) is itself, not the host, so
77
96
  // it can never see a gateway already running on the host (e.g. the user's
@@ -101,7 +120,7 @@ async function runPython(root, portRanges) {
101
120
  ["run", "-d", "--name", container, ...netFlags,
102
121
  // host.docker.internal is automatic on Docker Desktop (macOS/Windows);
103
122
  // this makes it resolve on Linux too, for the no-bridge gateway fallback above.
104
- "--add-host", "host.docker.internal:host-gateway",
123
+ ...hostGatewayFlags,
105
124
  "-e", "PIP_ROOT_USER_ACTION=ignore",
106
125
  "-v", `${root}:/plugin`, "-w", "/plugin", PYTHON_DEV_IMAGE, "sleep", "infinity"],
107
126
  { stdio: "inherit" },
@@ -130,16 +149,21 @@ async function runPython(root, portRanges) {
130
149
  }
131
150
  });
132
151
 
133
- const cleanup = () => {
152
+ let cleaned = false;
153
+ const cleanupResources = () => {
154
+ if (cleaned) return;
155
+ cleaned = true;
134
156
  stopPortMonitor();
135
- if (!child.killed) child.kill();
157
+ if (!child.killed && child.exitCode === null) child.kill();
136
158
  spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" });
137
- process.exit(0);
159
+ };
160
+ const cleanup = () => {
161
+ cleanupResources();
162
+ exitAfterCleanup(0);
138
163
  };
139
164
  child.on("exit", (code) => {
140
- stopPortMonitor();
141
- spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" });
142
- process.exit(code ?? 0);
165
+ cleanupResources();
166
+ exitAfterCleanup(code ?? 0);
143
167
  });
144
168
  process.once("SIGINT", cleanup);
145
169
  process.once("SIGTERM", cleanup);
@@ -228,7 +252,7 @@ async function runRos2(root, portRanges) {
228
252
  stopPortMonitor();
229
253
  if (child) child.kill();
230
254
  spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" });
231
- process.exit(0);
255
+ exitAfterCleanup(0);
232
256
  };
233
257
  process.on("SIGINT", cleanup);
234
258
  process.on("SIGTERM", cleanup);
@@ -304,7 +328,7 @@ async function runCpp(root, portRanges) {
304
328
  stopPortMonitor();
305
329
  if (child) child.kill();
306
330
  spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" });
307
- process.exit(0);
331
+ exitAfterCleanup(0);
308
332
  };
309
333
  process.on("SIGINT", cleanup);
310
334
  process.on("SIGTERM", cleanup);
package/cli/src/devUi.mjs CHANGED
@@ -211,13 +211,19 @@ export async function runDevUi(args = []) {
211
211
  { stdio: "inherit" },
212
212
  );
213
213
 
214
+ let cleaned = false;
214
215
  const cleanup = () => {
215
- if (viteProc && !viteProc.killed) viteProc.kill();
216
- if (!child.killed) child.kill();
216
+ if (cleaned) return;
217
+ cleaned = true;
218
+ if (viteProc && !viteProc.killed && viteProc.exitCode === null) viteProc.kill();
219
+ if (!child.killed && child.exitCode === null) child.kill();
217
220
  };
218
221
  process.once("SIGINT", cleanup);
219
222
  process.once("SIGTERM", cleanup);
220
- child.on("exit", (code) => process.exit(code ?? 0));
223
+ child.on("exit", (code) => {
224
+ cleanup();
225
+ process.exit(code ?? 0);
226
+ });
221
227
  }
222
228
 
223
229
  export { findPluginRoot, findPreviewHostRoot };
package/cli/src/new.mjs CHANGED
@@ -148,7 +148,7 @@ export async function runNew(args) {
148
148
 
149
149
  let type = opts.type;
150
150
  if (!type && !opts.yes) {
151
- console.log("\n플러그인 타입을 선택하세요:");
151
+ console.log("\nSelect the plugin type:");
152
152
  console.log(" 1) Python");
153
153
  console.log(" 2) C++");
154
154
  console.log(" 3) ROS2 (rclpy / Python)");
@@ -1 +1 @@
1
- {"generatedAt":1783637905594,"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":1783639482772,"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": "0.1.2-dev.49",
3
+ "version": "0.1.2-dev.50",
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": "0.1.2-dev.49",
57
- "@rainbow-robotics/preview-host": "0.1.2-dev.49",
56
+ "@rainbow-robotics/plugin-ui": "0.1.2-dev.50",
57
+ "@rainbow-robotics/preview-host": "0.1.2-dev.50",
58
58
  "postcss": "^8.5.8",
59
59
  "socket.io": "^4.8.1",
60
60
  "typescript": "^5.8.0",