@rainbow-robotics/muscat-plugin-kit 1.10.2-dev.1 → 1.10.2-dev.2

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.
@@ -5,13 +5,13 @@ import { readFileSync, realpathSync } from "node:fs";
5
5
  import { resolve } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { spawnSync } from "node:child_process";
8
- import { color, kitVersion, log, resolveLocalCliBin } from "../src/util.mjs";
8
+ import { color, compareKitVersions, kitVersion, log, resolveLocalCliBin } from "../src/util.mjs";
9
9
  import { runNew } from "../src/new.mjs";
10
10
  import { runBuild } from "../src/build.mjs";
11
11
  import { runDevUi } from "../src/devUi.mjs";
12
12
  import { runDevBack } from "../src/devBack.mjs";
13
13
  import { runDev } from "../src/dev.mjs";
14
- import { runUpdate } from "../src/update.mjs";
14
+ import { runUpdate, runUpdateCheck } from "../src/update.mjs";
15
15
  import { runUninstall } from "../src/uninstall.mjs";
16
16
  import { runSdk } from "../src/sdk.mjs";
17
17
  import { runType } from "../src/type.mjs";
@@ -50,6 +50,13 @@ if (isBinaryMode && !process.env.MUSCAT_PK_VERSION) {
50
50
  // Say so — otherwise an outdated local copy silently answers instead, and
51
51
  // its missing/renamed subcommands look like the CLI is broken.
52
52
  const localVersion = readVersion(localBin);
53
+ // An older local copy can't update a project correctly — it doesn't know what changed since
54
+ // it was published. Run this CLI's update instead, still touching this project only.
55
+ if (process.argv[2] === "update" && localVersion && compareKitVersions(localVersion, kitVersion()) < 0) {
56
+ console.error(color.dim(`[muscat-pk] project's local install (v${localVersion}) is older — updating it with this CLI (v${kitVersion()})`));
57
+ process.env.MUSCAT_PK_UPDATE_PROJECT_ONLY = "1";
58
+ return;
59
+ }
53
60
  console.error(
54
61
  color.dim(`[muscat-pk] using this project's local install${localVersion ? ` (v${localVersion})` : ""}: ${localBin}`),
55
62
  );
@@ -121,6 +128,8 @@ async function main() {
121
128
  }
122
129
  case "update":
123
130
  return await runUpdate(args);
131
+ case "update:check": // internal: update runs it with the freshly installed local kit
132
+ return await runUpdateCheck(args);
124
133
  case "uninstall":
125
134
  return await runUninstall(args);
126
135
  case "sdk":
@@ -13,7 +13,10 @@
13
13
  import { execSync, spawn, spawnSync } from "node:child_process";
14
14
  import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
15
15
  import { join, relative, resolve } from "node:path";
16
- import { findPluginRoot, isLocalKitInstall, KIT_PUBLISHED_NAME, kitVersion, log, parseArgs, prompt } from "./util.mjs";
16
+ import {
17
+ compareKitVersions, findPluginRoot, isLocalKitInstall, KIT_PUBLISHED_NAME, kitVersion, log, parseArgs, prompt,
18
+ resolveLocalCliBin,
19
+ } from "./util.mjs";
17
20
 
18
21
  const PLUGIN_UI_PACKAGE = "@rainbow-robotics/plugin-ui";
19
22
  const PREVIEW_HOST_PACKAGE = "@rainbow-robotics/preview-host";
@@ -301,15 +304,53 @@ export function findLegacyUiUsage(root) {
301
304
  return found;
302
305
  }
303
306
 
304
- function reportLegacyUi(root) {
307
+ // The known-API list above only knows past changes. Type-checking against the plugin-ui that was
308
+ // just installed catches whatever a later release removes or reshapes, with no list to keep up.
309
+ function typeScriptErrors(root) {
310
+ const tsc = resolve(root, "node_modules/typescript/bin/tsc");
311
+ if (!existsSync(tsc) || !existsSync(resolve(root, "tsconfig.json"))) return [];
312
+ const runtime = isBinaryMode ? "node" : process.execPath;
313
+ const r = spawnSync(runtime, [tsc, "--noEmit", "-p", root, "--pretty", "false"], { cwd: root, encoding: "utf8" });
314
+ return `${r.stdout ?? ""}`
315
+ .split("\n")
316
+ .map((l) => /^(.+?)\((\d+),\d+\): error (TS\d+): (.*)$/.exec(l))
317
+ .filter(Boolean)
318
+ .map(([, file, line, code, text]) => ({ file: relative(root, resolve(root, file)), line: Number(line), text: `${code} ${text}` }));
319
+ }
320
+
321
+ function reportProject(root) {
305
322
  const found = findLegacyUiUsage(root);
306
- if (!found.length) return;
307
- log.warn("This project still uses the old plugin-ui API (removed in plugin-ui 1.x). Fix these before `muscat-pk dev` / `build`:");
323
+ const tsErrors = typeScriptErrors(root);
324
+ if (!found.length && !tsErrors.length) return;
325
+ log.warn("This project needs changes for the updated plugin-ui. Fix these before `muscat-pk dev` / `build`:");
308
326
  for (const f of found) log.info(` ${f.file}:${f.line} ${f.text}`);
309
- log.info(" Props changed too (e.g. RBSlider onValueChange(values[]), RBSwitch onCheckedChange(bool) instead of event.detail).");
327
+ if (tsErrors.length) {
328
+ log.info(" TypeScript (tsc --noEmit):");
329
+ for (const e of tsErrors) log.info(` ${e.file}:${e.line} ${e.text}`);
330
+ }
310
331
  log.info(" For working examples, generate a fresh project and read its ui/content.tsx: muscat-pk new <dir>");
311
332
  }
312
333
 
334
+ /** `muscat-pk update:check` — the post-update project check, run by the freshly installed kit. */
335
+ export async function runUpdateCheck() {
336
+ reportProject(findPluginRoot());
337
+ }
338
+
339
+ // Prefer the kit update just installed: it knows the plugin-ui it shipped with, this process may not.
340
+ function checkProjectAfterUpdate(root) {
341
+ const localBin = resolveLocalCliBin(root);
342
+ let localVersion = "";
343
+ try {
344
+ localVersion = JSON.parse(readFileSync(resolve(localBin, "../../../package.json"), "utf8")).version;
345
+ } catch { /* no local kit */ }
346
+ if (localBin && localVersion && compareKitVersions(localVersion, kitVersion()) >= 0) {
347
+ const runtime = isBinaryMode ? "node" : process.execPath;
348
+ const r = spawnSync(runtime, [localBin, "update:check"], { cwd: root, stdio: "inherit" });
349
+ if (!r.error && r.status === 0) return;
350
+ }
351
+ reportProject(root);
352
+ }
353
+
313
354
  // ── main ─────────────────────────────────────────────────────────────────────
314
355
 
315
356
  async function resolveTag(explicitTag) {
@@ -336,7 +377,7 @@ export async function runUpdate(args = []) {
336
377
 
337
378
  // 지금 도는 게 프로젝트의 로컬 설치면 그 프로젝트만 건드린다. 이 머신의 다른
338
379
  // 프로젝트들이 쓰는 글로벌 CLI까지 같이 올리려면 --global을 명시해야 한다.
339
- const runningLocal = isLocalKitInstall();
380
+ const runningLocal = isLocalKitInstall() || process.env.MUSCAT_PK_UPDATE_PROJECT_ONLY === "1";
340
381
 
341
382
  // 1. Update the CLI itself
342
383
  if (!runningLocal || opts.global) {
@@ -394,8 +435,8 @@ export async function runUpdate(args = []) {
394
435
  updateLocalDeps(root, tag);
395
436
 
396
437
  try {
397
- reportLegacyUi(root);
438
+ checkProjectAfterUpdate(root);
398
439
  } catch (err) {
399
- log.warn(`Legacy UI check failed: ${err.message}`);
440
+ log.warn(`Project check failed: ${err.message}`);
400
441
  }
401
442
  }
package/cli/src/util.mjs CHANGED
@@ -403,6 +403,18 @@ export function isNewer(a, b) {
403
403
  return a3 > b3;
404
404
  }
405
405
 
406
+ /** Compare "x.y.z[-dev.N]" including the dev number (a release sorts after its dev builds). <0, 0, >0. */
407
+ export function compareKitVersions(a, b) {
408
+ const parse = (v) => {
409
+ const [rel, pre] = String(v).split("-");
410
+ const nums = rel.split(".").map((n) => parseInt(n, 10) || 0);
411
+ return [...nums, pre === undefined ? Infinity : parseInt(pre.split(".").pop(), 10) || 0];
412
+ };
413
+ const pa = parse(a), pb = parse(b);
414
+ for (let i = 0; i < 4; i++) if (pa[i] !== pb[i]) return pa[i] > pb[i] ? 1 : -1;
415
+ return 0;
416
+ }
417
+
406
418
  /**
407
419
  * Non-blocking check for a newer published kit. Prints an update suggestion if
408
420
  * one exists. Fails silently when offline. Honors `RB_REGISTRY` and is skipped
@@ -1 +1 @@
1
- {"generatedAt":1792689204059,"userSince":1750997484097,"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":1792689973585,"userSince":1750997484097,"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.2-dev.1",
3
+ "version": "1.10.2-dev.2",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20"
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@modelcontextprotocol/sdk": "^1.29.0",
55
- "@rainbow-robotics/plugin-ui": "1.10.2-dev.1",
56
- "@rainbow-robotics/preview-host": "1.10.2-dev.1",
55
+ "@rainbow-robotics/plugin-ui": "1.10.2-dev.2",
56
+ "@rainbow-robotics/preview-host": "1.10.2-dev.2",
57
57
  "@types/react": "^19.0.10",
58
58
  "postcss": "^8.5.8",
59
59
  "typescript": "^5.8.0",