@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.45 → 0.1.2-dev.47
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/devBack.mjs +17 -37
- package/cli/src/mcp.mjs +85 -29
- package/cli/src/new.mjs +16 -1
- package/cli/src/pluginDevServer.mjs +5 -6
- package/cli/src/util.mjs +26 -0
- package/cli/storybook-dist/project.json +1 -1
- package/cli/templates/common/package.json +2 -0
- package/package.json +3 -3
package/cli/src/devBack.mjs
CHANGED
|
@@ -10,15 +10,7 @@
|
|
|
10
10
|
import { spawn, spawnSync } from "node:child_process";
|
|
11
11
|
import { existsSync, watch } from "node:fs";
|
|
12
12
|
import { resolve } from "node:path";
|
|
13
|
-
import {
|
|
14
|
-
detectPythonCmd,
|
|
15
|
-
ensureDocker,
|
|
16
|
-
findPluginRoot,
|
|
17
|
-
hasBin,
|
|
18
|
-
log,
|
|
19
|
-
promptRobotConnection,
|
|
20
|
-
venvPython,
|
|
21
|
-
} from "./util.mjs";
|
|
13
|
+
import { ensureDocker, ensureIdeVenv, findPluginRoot, log, promptRobotConnection } from "./util.mjs";
|
|
22
14
|
import { assertManifestPorts, manifestRuntime, readManifest, validateManifest } from "./manifest.mjs";
|
|
23
15
|
import {
|
|
24
16
|
formatPortRanges,
|
|
@@ -43,33 +35,16 @@ import {
|
|
|
43
35
|
} from "./cpp.mjs";
|
|
44
36
|
|
|
45
37
|
// ── IDE tooling venv (best-effort, non-blocking) ────────────────────────────
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// Docker works fine with zero local Python.
|
|
38
|
+
// `muscat-pk new` already creates this up front (see new.mjs); this just
|
|
39
|
+
// refreshes it on every `dev`/`dev:back` in case requirements.txt changed.
|
|
40
|
+
// Docker remains the actual execution environment — this never affects it.
|
|
41
|
+
// Runs in the background so it never delays `dev:back` starting, and any
|
|
42
|
+
// failure here (no local Python toolchain, offline, ...) is silent.
|
|
52
43
|
function syncIdeVenv(root) {
|
|
53
|
-
const venvDir = resolve(root, ".venv");
|
|
54
|
-
const py = venvPython(venvDir);
|
|
55
|
-
|
|
56
44
|
setImmediate(() => {
|
|
57
45
|
try {
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
if (hasBin("uv")) {
|
|
61
|
-
created = spawnSync("uv", ["venv", venvDir, "--python", "3.12", "--seed"], { cwd: root, stdio: "ignore" });
|
|
62
|
-
} else {
|
|
63
|
-
const { cmd } = detectPythonCmd();
|
|
64
|
-
created = spawnSync(cmd[0], [...cmd.slice(1), "-m", "venv", venvDir], { cwd: root, stdio: "ignore" });
|
|
65
|
-
}
|
|
66
|
-
if (created.status !== 0 || !existsSync(py)) return;
|
|
67
|
-
}
|
|
68
|
-
const reqs = resolve(root, "requirements.txt");
|
|
69
|
-
const args = ["-m", "pip", "install", "-q"];
|
|
70
|
-
if (existsSync(reqs)) args.push("-r", reqs);
|
|
71
|
-
if (spawnSync(py, args, { cwd: root, stdio: "ignore" }).status === 0) {
|
|
72
|
-
log.info(`IDE venv ready → .venv (point your editor's Python interpreter there for pylint/pyright)`);
|
|
46
|
+
if (ensureIdeVenv(root)) {
|
|
47
|
+
log.info("IDE venv ready → .venv (point your editor's Python interpreter there for pylint/pyright)");
|
|
73
48
|
}
|
|
74
49
|
} catch {
|
|
75
50
|
/* best-effort only */
|
|
@@ -82,9 +57,11 @@ function syncIdeVenv(root) {
|
|
|
82
57
|
// Under `muscat-pk dev`, it shares the bridge container's netns, so the SDK
|
|
83
58
|
// reaches the Socket.IO bridge at the default localhost:10000.
|
|
84
59
|
async function runPython(root, portRanges) {
|
|
60
|
+
// Independent of Docker readiness — must still happen if Docker isn't
|
|
61
|
+
// installed/running, since that's exactly when local IDE tooling matters most.
|
|
62
|
+
syncIdeVenv(root);
|
|
85
63
|
pyAssertDockerReady();
|
|
86
64
|
await pyEnsureImage();
|
|
87
|
-
syncIdeVenv(root);
|
|
88
65
|
|
|
89
66
|
const manifest = readManifest(root);
|
|
90
67
|
const pluginId = manifest.id ?? "";
|
|
@@ -154,16 +131,19 @@ async function runPython(root, portRanges) {
|
|
|
154
131
|
|
|
155
132
|
// ── ros2 ───────────────────────────────────────────────────────────────────────
|
|
156
133
|
async function runRos2(root, portRanges) {
|
|
134
|
+
const manifest = readManifest(root);
|
|
135
|
+
const isRclcpp = manifest.runtime?.rosClient === "rclcpp";
|
|
136
|
+
// Independent of Docker readiness — must still happen if Docker isn't
|
|
137
|
+
// installed/running, since that's exactly when local IDE tooling matters most.
|
|
138
|
+
if (!isRclcpp) syncIdeVenv(root); // rclpy is plain Python — rclcpp is C++, no venv needed
|
|
139
|
+
|
|
157
140
|
assertDockerReady();
|
|
158
141
|
const pkg = ros2PackageName(root);
|
|
159
142
|
if (!pkg) throw new Error("no ROS2 package found under ros2_ws/src.");
|
|
160
143
|
|
|
161
144
|
await ensureImage();
|
|
162
145
|
|
|
163
|
-
const manifest = readManifest(root);
|
|
164
146
|
const pluginId = manifest.id ?? "";
|
|
165
|
-
const isRclcpp = manifest.runtime?.rosClient === "rclcpp";
|
|
166
|
-
if (!isRclcpp) syncIdeVenv(root); // rclpy is plain Python — rclcpp is C++, no venv needed
|
|
167
147
|
const container = `${ROS2_DEV_IMAGE}-run`;
|
|
168
148
|
const robotIp = process.env.MUSCAT_ROBOT_HOST ?? "";
|
|
169
149
|
const robotToken = process.env.MUSCAT_ROBOT_TOKEN ?? "";
|
package/cli/src/mcp.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// muscat-pk mcp — an MCP (Model Context Protocol) server
|
|
2
|
-
// coding agent (Claude Code, Codex, ...)
|
|
3
|
-
//
|
|
4
|
-
// node_modules for @rainbow-robotics/plugin-ui and @repo/rb-components:
|
|
1
|
+
// muscat-pk mcp — an MCP (Model Context Protocol) server exposing the Muscat
|
|
2
|
+
// plugin UI/SDK surface to an AI coding agent (Claude Code, Codex, ...) so it
|
|
3
|
+
// looks things up instead of guessing. Tools:
|
|
5
4
|
//
|
|
6
5
|
// Frontend UI (@rainbow-robotics/plugin-ui/react, via dist/react.d.ts):
|
|
7
6
|
// - list_components every exported component/hook/type.
|
|
@@ -42,11 +41,9 @@ const DESIGN_TOKENS_CSS = existsSync(SHIPPED_DESIGN_TOKENS)
|
|
|
42
41
|
|
|
43
42
|
let typesCache = null;
|
|
44
43
|
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
// @repo/rb-components separately, which wouldn't exist in an external install
|
|
49
|
-
// anyway).
|
|
44
|
+
// Parse plugin-ui/react's dist/react.d.ts. It's self-contained (rb-components
|
|
45
|
+
// types are inlined at build — see plugin-ui/build-dist.mjs), so this one file
|
|
46
|
+
// is enough even in an external install.
|
|
50
47
|
async function loadReactTypes() {
|
|
51
48
|
if (typesCache) return typesCache;
|
|
52
49
|
|
|
@@ -113,9 +110,7 @@ function findStorySource(name) {
|
|
|
113
110
|
/* README search */
|
|
114
111
|
/* -------------------------------------------------------------------------- */
|
|
115
112
|
|
|
116
|
-
//
|
|
117
|
-
// section — good enough for short-query lookups ("save form data", "toast",
|
|
118
|
-
// "manifest ui") without pulling in a real search dependency.
|
|
113
|
+
// Split the README on headings and keyword-score each section.
|
|
119
114
|
function searchReadme(query) {
|
|
120
115
|
if (!existsSync(TEMPLATE_README)) return [];
|
|
121
116
|
const text = readFileSync(TEMPLATE_README, "utf8");
|
|
@@ -200,9 +195,8 @@ function pythonCmd() {
|
|
|
200
195
|
return null;
|
|
201
196
|
}
|
|
202
197
|
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
// in a real plugin env it's importable; otherwise we return a clear hint.
|
|
198
|
+
// Run an introspection script against the installed rainbow.rb_sdk (a plugin's
|
|
199
|
+
// backend dependency). Returns a clear hint if it isn't importable.
|
|
206
200
|
function introspectRbSdk(script) {
|
|
207
201
|
const py = pythonCmd();
|
|
208
202
|
if (!py) {
|
|
@@ -305,16 +299,27 @@ export async function runMcp() {
|
|
|
305
299
|
"Get the real Storybook story source for a component (e.g. RBSlider) — actual working " +
|
|
306
300
|
"props, imports, and layout, not a guessed shape. Prefer this over get_component_props when " +
|
|
307
301
|
"you just need to know how to use a component, not its full type.",
|
|
308
|
-
|
|
302
|
+
// `component` accepted as an alias — agents often guess it over `name`.
|
|
303
|
+
inputSchema: {
|
|
304
|
+
name: z.string().optional().describe('Component name, e.g. "RBSlider"'),
|
|
305
|
+
component: z.string().optional().describe("Alias for `name`."),
|
|
306
|
+
},
|
|
309
307
|
},
|
|
310
|
-
async ({ name }) => {
|
|
311
|
-
const
|
|
308
|
+
async ({ name, component }) => {
|
|
309
|
+
const target = name ?? component;
|
|
310
|
+
if (!target) {
|
|
311
|
+
return {
|
|
312
|
+
isError: true,
|
|
313
|
+
content: [{ type: "text", text: 'Missing required argument: "name" (component name, e.g. "RBSlider").' }],
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const source = findStorySource(target);
|
|
312
317
|
if (!source) {
|
|
313
318
|
return {
|
|
314
319
|
content: [
|
|
315
320
|
{
|
|
316
321
|
type: "text",
|
|
317
|
-
text: `No Storybook example found for "${
|
|
322
|
+
text: `No Storybook example found for "${target}". Run "muscat-pk storybook" to browse all components live, or use get_component_props for its type.`,
|
|
318
323
|
},
|
|
319
324
|
],
|
|
320
325
|
};
|
|
@@ -467,20 +472,66 @@ print(json.dumps(out))
|
|
|
467
472
|
description:
|
|
468
473
|
"Get the signature(s) and docstring for a rainbow.rb_sdk class or function (e.g. " +
|
|
469
474
|
"'PluginProgramContext', 'RBManipulateSDK'). For a class, lists its public methods with " +
|
|
470
|
-
"signatures.
|
|
471
|
-
|
|
475
|
+
"signatures. To drill into ONE method of a class (e.g. RBManipulateSDK.call_move_j), pass " +
|
|
476
|
+
"`method` alongside `name` — do not put both in `name`. Requires rainbow-rb-sdk to be " +
|
|
477
|
+
"pip-installed.",
|
|
478
|
+
inputSchema: {
|
|
479
|
+
name: z.string().describe('Class or function name, e.g. "RBManipulateSDK"'),
|
|
480
|
+
method: z.string().optional().describe('Optional: a specific method on that class, e.g. "call_move_j"'),
|
|
481
|
+
},
|
|
472
482
|
},
|
|
473
|
-
async ({ name }) => {
|
|
483
|
+
async ({ name, method }) => {
|
|
484
|
+
// Tolerate a combined "ClassName method_name" in `name` (a common agent
|
|
485
|
+
// mistake) by splitting it ourselves instead of failing validation.
|
|
486
|
+
let className = name;
|
|
487
|
+
let methodName = method;
|
|
488
|
+
if (!methodName && /\s/.test(name.trim())) {
|
|
489
|
+
const parts = name.trim().split(/\s+/);
|
|
490
|
+
if (parts.length === 2) [className, methodName] = parts;
|
|
491
|
+
}
|
|
492
|
+
|
|
474
493
|
const { data, error } = introspectRbSdk(`
|
|
475
494
|
import inspect, json
|
|
476
495
|
mod = importlib.import_module("rainbow.rb_sdk")
|
|
477
|
-
name = ${JSON.stringify(
|
|
496
|
+
name = ${JSON.stringify(className)}
|
|
497
|
+
method = ${JSON.stringify(methodName ?? null)}
|
|
478
498
|
obj = getattr(mod, name, None)
|
|
479
499
|
if obj is None:
|
|
480
500
|
print(json.dumps({"__missing__": True})); raise SystemExit(0)
|
|
481
501
|
def sig(o):
|
|
482
502
|
try: return str(inspect.signature(o))
|
|
483
503
|
except Exception: return "(...)"
|
|
504
|
+
|
|
505
|
+
if method:
|
|
506
|
+
# Direct method on the class itself.
|
|
507
|
+
fn = getattr(obj, method, None) if inspect.isclass(obj) else None
|
|
508
|
+
# rb_sdk classes often group calls under a nested namespace set in
|
|
509
|
+
# __init__ (e.g. RBManipulateSDK().move.call_move_j) — that only exists on
|
|
510
|
+
# an INSTANCE, which we won't construct (side effects, needs a robot
|
|
511
|
+
# connection). Best-effort: search the class's own __init__ source text
|
|
512
|
+
# for self.<attr> = <NestedClass>(...) and check each nested class too.
|
|
513
|
+
owner = name
|
|
514
|
+
if fn is None and inspect.isclass(obj):
|
|
515
|
+
try:
|
|
516
|
+
src = inspect.getsource(obj.__init__)
|
|
517
|
+
except Exception:
|
|
518
|
+
src = ""
|
|
519
|
+
import re
|
|
520
|
+
for attr, nested_name in re.findall(r"self\\.(\\w+)\\s*=\\s*(\\w+)\\(", src):
|
|
521
|
+
nested = mod.__dict__.get(nested_name) or globals().get(nested_name)
|
|
522
|
+
cand = getattr(nested, method, None) if nested else None
|
|
523
|
+
if cand:
|
|
524
|
+
fn = cand
|
|
525
|
+
owner = f"{name}.{attr} ({nested_name})"
|
|
526
|
+
break
|
|
527
|
+
if fn is None:
|
|
528
|
+
print(json.dumps({"__missing__": True, "__method__": True})); raise SystemExit(0)
|
|
529
|
+
print(json.dumps({
|
|
530
|
+
"name": name, "kind": "method", "owner": owner,
|
|
531
|
+
"signature": method + sig(fn), "doc": inspect.getdoc(fn) or "",
|
|
532
|
+
}))
|
|
533
|
+
raise SystemExit(0)
|
|
534
|
+
|
|
484
535
|
res = {"name": name, "doc": inspect.getdoc(obj) or ""}
|
|
485
536
|
if inspect.isclass(obj):
|
|
486
537
|
res["kind"] = "class"
|
|
@@ -497,12 +548,17 @@ print(json.dumps(res))
|
|
|
497
548
|
`);
|
|
498
549
|
if (error) return { isError: true, content: [{ type: "text", text: error }] };
|
|
499
550
|
if (data.__missing__) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
};
|
|
551
|
+
const text = data.__method__
|
|
552
|
+
? `No method "${methodName}" found directly on "${className}" (nor in an obvious nested ` +
|
|
553
|
+
`namespace set in __init__). Call get_rb_sdk_api with just \`name: "${className}"\` to see ` +
|
|
554
|
+
`its full method list and constructor first.`
|
|
555
|
+
: `No "${className}" in rainbow.rb_sdk. Call list_rb_sdk for valid names.`;
|
|
556
|
+
return { isError: true, content: [{ type: "text", text }] };
|
|
557
|
+
}
|
|
558
|
+
if (data.kind === "method") {
|
|
559
|
+
const lines = [`# ${data.owner}.${data.signature.split("(")[0]}`, data.signature];
|
|
560
|
+
if (data.doc) lines.push("", data.doc);
|
|
561
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
506
562
|
}
|
|
507
563
|
const lines = [`# ${data.name} (${data.kind})`];
|
|
508
564
|
if (data.doc) lines.push(data.doc, "");
|
package/cli/src/new.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
writeFileSync,
|
|
13
13
|
} from "node:fs";
|
|
14
14
|
import { basename, dirname, resolve } from "node:path";
|
|
15
|
-
import { hasBin, kitVersion, parseArgs, prompt, templatesDir, log } from "./util.mjs";
|
|
15
|
+
import { ensureIdeVenv, hasBin, kitVersion, parseArgs, prompt, templatesDir, log } from "./util.mjs";
|
|
16
16
|
|
|
17
17
|
// Like cpSync(src, dst, {recursive:true}) but reads from the embedded snapshot
|
|
18
18
|
// when the templates dir doesn't exist on disk (compiled binary mode).
|
|
@@ -227,6 +227,21 @@ export async function runNew(args) {
|
|
|
227
227
|
} catch {
|
|
228
228
|
log.warn(`'${pm} install' failed; run it manually in ${targetName}`);
|
|
229
229
|
}
|
|
230
|
+
|
|
231
|
+
// Local .venv is for your editor/linter (pylint, pyright, ...) only — the
|
|
232
|
+
// backend actually RUNS in Docker (see README), this never affects that.
|
|
233
|
+
// rclcpp is C++, so no venv applies there.
|
|
234
|
+
const needsIdeVenv =
|
|
235
|
+
runtimeChoice.type === "python" ||
|
|
236
|
+
(runtimeChoice.type === "ros2" && runtimeChoice.rosClient === "rclpy");
|
|
237
|
+
if (needsIdeVenv) {
|
|
238
|
+
log.step("creating .venv for your editor (pylint/pyright)…");
|
|
239
|
+
if (ensureIdeVenv(target)) {
|
|
240
|
+
log.ok(".venv ready — point your editor's Python interpreter there.");
|
|
241
|
+
} else {
|
|
242
|
+
log.warn("Could not create .venv (no local Python/uv?) — skipping, Docker dev still works.");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
230
245
|
}
|
|
231
246
|
|
|
232
247
|
// The back end (python / cpp / ros2) runs in a Docker container that matches
|
|
@@ -46,12 +46,11 @@ import { setHostServices } from "@rainbow-robotics/plugin-ui/host-ui";
|
|
|
46
46
|
import { RbWs, createLazyRbSdk } from "@rainbow-robotics/plugin-ui/ws";
|
|
47
47
|
import App from ${entry};
|
|
48
48
|
|
|
49
|
-
// HMR
|
|
50
|
-
// static \`App\` import
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// root so live edits re-render it in place.
|
|
49
|
+
// HMR passes the new module to the accept callback but doesn't rebind the
|
|
50
|
+
// static \`App\` import, so we track the latest at module scope. Without this,
|
|
51
|
+
// navigating away and back (a fresh mount() on this cached module) renders the
|
|
52
|
+
// stale App from first import. \`activeRender\` points at the mounted root so
|
|
53
|
+
// live edits re-render in place.
|
|
55
54
|
let latestApp = App;
|
|
56
55
|
let activeRender = null;
|
|
57
56
|
if (import.meta.hot) {
|
package/cli/src/util.mjs
CHANGED
|
@@ -39,6 +39,32 @@ export function venvPython(venvDir) {
|
|
|
39
39
|
: resolve(venvDir, "bin", "python");
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Create/refresh a local `.venv` with requirements.txt installed, for the
|
|
44
|
+
* editor/linter only (the backend actually runs in Docker). Uses `uv` if
|
|
45
|
+
* present, else the system Python. Returns true if the venv is ready.
|
|
46
|
+
*/
|
|
47
|
+
export function ensureIdeVenv(root) {
|
|
48
|
+
const venvDir = resolve(root, ".venv");
|
|
49
|
+
const py = venvPython(venvDir);
|
|
50
|
+
|
|
51
|
+
if (!existsSync(py)) {
|
|
52
|
+
let created;
|
|
53
|
+
if (hasBin("uv")) {
|
|
54
|
+
created = spawnSync("uv", ["venv", venvDir, "--python", "3.12", "--seed"], { cwd: root, stdio: "ignore" });
|
|
55
|
+
} else {
|
|
56
|
+
const { cmd } = detectPythonCmd();
|
|
57
|
+
created = spawnSync(cmd[0], [...cmd.slice(1), "-m", "venv", venvDir], { cwd: root, stdio: "ignore" });
|
|
58
|
+
}
|
|
59
|
+
if (created.status !== 0 || !existsSync(py)) return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const reqs = resolve(root, "requirements.txt");
|
|
63
|
+
const args = ["-m", "pip", "install", "-q"];
|
|
64
|
+
if (existsSync(reqs)) args.push("-r", reqs);
|
|
65
|
+
return spawnSync(py, args, { cwd: root, stdio: "ignore" }).status === 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
42
68
|
/** Published install/CLI package name. Author imports use @rainbow-robotics/plugin-ui separately. */
|
|
43
69
|
export const KIT_PUBLISHED_NAME = "@rainbow-robotics/muscat-plugin-kit";
|
|
44
70
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"generatedAt":
|
|
1
|
+
{"generatedAt":1783624567446,"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}}}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
"@tailwindcss/vite": "^4.1.0",
|
|
11
11
|
"@rainbow-robotics/muscat-plugin-kit": "__RB_VERSION__",
|
|
12
12
|
"@rainbow-robotics/preview-host": "__RB_VERSION__",
|
|
13
|
+
"@types/react": "^19.0.10",
|
|
14
|
+
"@types/react-dom": "^19.0.4",
|
|
13
15
|
"@vitejs/plugin-react": "^4.0.0",
|
|
14
16
|
"tailwindcss": "^4.1.0",
|
|
15
17
|
"typescript": "^5.8.0",
|
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.47",
|
|
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.
|
|
57
|
-
"@rainbow-robotics/preview-host": "0.1.2-dev.
|
|
56
|
+
"@rainbow-robotics/plugin-ui": "0.1.2-dev.47",
|
|
57
|
+
"@rainbow-robotics/preview-host": "0.1.2-dev.47",
|
|
58
58
|
"postcss": "^8.5.8",
|
|
59
59
|
"socket.io": "^4.8.1",
|
|
60
60
|
"typescript": "^5.8.0",
|