robodev 0.43.0 → 0.44.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robodev",
3
- "version": "0.43.0",
3
+ "version": "0.44.0",
4
4
  "description": "CLI for Robodev Starbase — create, auth, link, deploy, load, and run a project locally with robodev dev",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -489,7 +489,31 @@ async function assertCreatable(root: string): Promise<void> {
489
489
  }
490
490
  }
491
491
 
492
- async function npmInstallRobodevDeps(root: string): Promise<void> {
492
+ const CREATE_PNPM_VERSION = "10.14.0";
493
+
494
+ async function spawnInherit(command: string, args: string[], cwd?: string): Promise<void> {
495
+ await new Promise<void>((resolve, reject) => {
496
+ const child = spawn(command, args, { cwd, stdio: "inherit" });
497
+ child.on("error", reject);
498
+ child.on("exit", (code) => {
499
+ if (code === 0) resolve();
500
+ else reject(new Error(`${command} ${args.join(" ")} failed (${code})`));
501
+ });
502
+ });
503
+ }
504
+
505
+ async function ensurePnpm(): Promise<{ command: string; prefix: string[] }> {
506
+ if (await commandAvailable("pnpm")) return { command: "pnpm", prefix: [] };
507
+ if (!(await commandAvailable("corepack"))) {
508
+ throw new Error("pnpm is not available. Enable it with Corepack (Node 22) or install pnpm.");
509
+ }
510
+ await spawnInherit("corepack", ["enable"]);
511
+ await spawnInherit("corepack", ["prepare", `pnpm@${CREATE_PNPM_VERSION}`, "--activate"]);
512
+ if (await commandAvailable("pnpm")) return { command: "pnpm", prefix: [] };
513
+ return { command: "corepack", prefix: ["pnpm"] };
514
+ }
515
+
516
+ async function pnpmInstallRobodevDeps(root: string): Promise<void> {
493
517
  const pkgPath = join(root, "robodev", "package.json");
494
518
  let raw: string;
495
519
  try {
@@ -506,18 +530,19 @@ async function npmInstallRobodevDeps(root: string): Promise<void> {
506
530
  const deps = pkg.dependencies ?? {};
507
531
  const extra = Object.keys(deps).filter((name) => name !== "@robodev-ai/sdk");
508
532
  if (extra.length === 0) return;
509
- console.log("Installing robodev/ npm packages…");
510
- await npmInstall(join(root, "robodev"));
533
+ console.log("Installing robodev/ packages…");
534
+ await pnpmInstall(join(root, "robodev"));
511
535
  }
512
536
 
513
- async function npmInstall(root: string): Promise<void> {
514
- console.log("Installing npm packages…");
537
+ async function pnpmInstall(root: string): Promise<void> {
538
+ console.log("Installing packages…");
539
+ const pnpm = await ensurePnpm();
515
540
  await new Promise<void>((resolve, reject) => {
516
- const child = spawn("npm", ["install"], { cwd: root, stdio: "inherit" });
541
+ const child = spawn(pnpm.command, [...pnpm.prefix, "install"], { cwd: root, stdio: "inherit" });
517
542
  child.on("error", reject);
518
543
  child.on("exit", (code) => {
519
544
  if (code === 0) resolve();
520
- else reject(new Error(`npm install failed (${code})`));
545
+ else reject(new Error(`pnpm install failed (${code})`));
521
546
  });
522
547
  });
523
548
  }
@@ -607,20 +632,20 @@ async function runCreate(args: string[]): Promise<void> {
607
632
  const liveUrl = await runDeploy(false, { root, frontendFiles, skipFrontendBuild });
608
633
 
609
634
  try {
610
- await npmInstall(root);
611
- await npmInstallRobodevDeps(root);
635
+ await pnpmInstall(root);
636
+ await pnpmInstallRobodevDeps(root);
612
637
  } catch (error) {
613
638
  console.log(error instanceof Error ? error.message : error);
614
639
  if (starter.kind === "backend") {
615
640
  console.log(
616
- "npm install failed. Copy the API URL printed above into Lovable, Bolt, or v0 as VITE_API_URL.",
641
+ "pnpm install failed. Copy the API URL printed above into Lovable, Bolt, or v0 as VITE_API_URL.",
617
642
  );
618
643
  console.log("https://robodev.povio.dev/docs/frontend");
619
644
  } else if (await hasAppsFe(root)) {
620
- console.log("Run `npm install` in the project folder.");
645
+ console.log("Run `pnpm install` in the project folder.");
621
646
  console.log("bun is required for apps/fe. APIs are already deployed.");
622
647
  } else {
623
- console.log("Run `npm install` in the project folder, then `npm run dev`.");
648
+ console.log("Run `pnpm install` in the project folder, then `pnpm run dev`.");
624
649
  }
625
650
  if (liveUrl) {
626
651
  printLiveUrl(liveUrl);
@@ -650,7 +675,7 @@ async function runCreate(args: string[]): Promise<void> {
650
675
  console.log(" The project App URL serves the hosted Welcome page.");
651
676
  console.log(" Edit index.html and src/, then robodev deploy (or Code + Save).");
652
677
  console.log(" robodev dev # local APIs");
653
- console.log(" npm run dev:fe # optional local Vite");
678
+ console.log(" pnpm run dev:fe # optional local Vite");
654
679
  }
655
680
  if (liveUrl) {
656
681
  printLiveUrl(liveUrl);
@@ -4,13 +4,39 @@ import tailwindCSS from "@tailwindcss/vite";
4
4
  import { devtools } from "@tanstack/devtools-vite";
5
5
  import { tanstackRouter } from "@tanstack/router-plugin/vite";
6
6
  import viteReact from "@vitejs/plugin-react";
7
- import { readFileSync } from "node:fs";
7
+ import { copyFileSync, existsSync, readdirSync, readFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
- import { defineConfig as defineViteConfig, mergeConfig } from "vite";
9
+ import { defineConfig as defineViteConfig, mergeConfig, type Plugin } from "vite";
10
10
  import devtoolsJson from "vite-plugin-devtools-json";
11
11
  import { defineConfig as defineVitestConfig } from "vitest/config";
12
12
  import { reactIconsSprite } from "react-icons-sprite/vite";
13
13
 
14
+ /** react-icons-sprite maps Trash2 → trash2.mjs and MenuIcon → menu-icon.mjs; lucide ships trash-2.mjs / menu.mjs. */
15
+ function lucideSpriteIconAliases(): Plugin {
16
+ return {
17
+ name: "lucide-sprite-icon-aliases",
18
+ enforce: "pre",
19
+ apply: "build",
20
+ buildStart() {
21
+ const iconsDir = join(process.cwd(), "node_modules", "lucide-react", "dist", "esm", "icons");
22
+ if (!existsSync(iconsDir)) return;
23
+ for (const file of readdirSync(iconsDir)) {
24
+ if (!file.endsWith(".mjs")) continue;
25
+ const src = join(iconsDir, file);
26
+ const digit = /^(.+)-(\d+)\.mjs$/.exec(file);
27
+ if (digit) {
28
+ const dest = join(iconsDir, `${digit[1]}${digit[2]}.mjs`);
29
+ if (!existsSync(dest)) copyFileSync(src, dest);
30
+ }
31
+ if (!file.endsWith("-icon.mjs")) {
32
+ const dest = join(iconsDir, file.replace(/\.mjs$/, "-icon.mjs"));
33
+ if (!existsSync(dest)) copyFileSync(src, dest);
34
+ }
35
+ }
36
+ },
37
+ };
38
+ }
39
+
14
40
  const repoRoot = new URL("../..", import.meta.url).pathname;
15
41
 
16
42
  function readDotEnvKey(root: string, key: string): string | undefined {
@@ -71,6 +97,7 @@ const createViteConfig = (isDevServer: boolean) => ({
71
97
  devtools({
72
98
  eventBusConfig: { enabled: false },
73
99
  }),
100
+ lucideSpriteIconAliases(),
74
101
  iconsSpritePlugin,
75
102
  viteReact({
76
103
  babel: {
@@ -12,7 +12,7 @@
12
12
  "@robodev-ai/sdk": "^0.13.0"
13
13
  },
14
14
  "devDependencies": {
15
- "robodev": "^0.43.0",
15
+ "robodev": "^0.44.0",
16
16
  "rulesync": "^8.18.0",
17
17
  "typescript": "^5.9.2"
18
18
  }
@@ -11,7 +11,7 @@
11
11
  "@robodev-ai/sdk": "^0.13.0"
12
12
  },
13
13
  "devDependencies": {
14
- "robodev": "^0.43.0",
14
+ "robodev": "^0.44.0",
15
15
  "typescript": "^5.9.2"
16
16
  }
17
17
  }
@@ -7,7 +7,7 @@ The project App URL serves the hosted Welcome page. Edit `index.html` and `src/`
7
7
  ```bash
8
8
  robodev create my-app
9
9
  robodev dev # local APIs
10
- npm run dev:fe # optional local Vite
10
+ pnpm run dev:fe # optional local Vite
11
11
  ```
12
12
 
13
13
  `robodev create` (TTY and non-TTY) uses this starter by default. Pass `--template space` for Space. Lovable, Bolt, or v0 should use `--template backend`.
@@ -16,7 +16,7 @@
16
16
  "react-dom": "^18.3.1"
17
17
  },
18
18
  "devDependencies": {
19
- "robodev": "^0.43.0",
19
+ "robodev": "^0.44.0",
20
20
  "typescript": "^5.9.2",
21
21
  "vite": "^6.0.0"
22
22
  }
@@ -4,13 +4,39 @@ import tailwindCSS from "@tailwindcss/vite";
4
4
  import { devtools } from "@tanstack/devtools-vite";
5
5
  import { tanstackRouter } from "@tanstack/router-plugin/vite";
6
6
  import viteReact from "@vitejs/plugin-react";
7
- import { readFileSync } from "node:fs";
7
+ import { copyFileSync, existsSync, readdirSync, readFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
- import { defineConfig as defineViteConfig, mergeConfig } from "vite";
9
+ import { defineConfig as defineViteConfig, mergeConfig, type Plugin } from "vite";
10
10
  import devtoolsJson from "vite-plugin-devtools-json";
11
11
  import { defineConfig as defineVitestConfig } from "vitest/config";
12
12
  import { reactIconsSprite } from "react-icons-sprite/vite";
13
13
 
14
+ /** react-icons-sprite maps Trash2 → trash2.mjs and MenuIcon → menu-icon.mjs; lucide ships trash-2.mjs / menu.mjs. */
15
+ function lucideSpriteIconAliases(): Plugin {
16
+ return {
17
+ name: "lucide-sprite-icon-aliases",
18
+ enforce: "pre",
19
+ apply: "build",
20
+ buildStart() {
21
+ const iconsDir = join(process.cwd(), "node_modules", "lucide-react", "dist", "esm", "icons");
22
+ if (!existsSync(iconsDir)) return;
23
+ for (const file of readdirSync(iconsDir)) {
24
+ if (!file.endsWith(".mjs")) continue;
25
+ const src = join(iconsDir, file);
26
+ const digit = /^(.+)-(\d+)\.mjs$/.exec(file);
27
+ if (digit) {
28
+ const dest = join(iconsDir, `${digit[1]}${digit[2]}.mjs`);
29
+ if (!existsSync(dest)) copyFileSync(src, dest);
30
+ }
31
+ if (!file.endsWith("-icon.mjs")) {
32
+ const dest = join(iconsDir, file.replace(/\.mjs$/, "-icon.mjs"));
33
+ if (!existsSync(dest)) copyFileSync(src, dest);
34
+ }
35
+ }
36
+ },
37
+ };
38
+ }
39
+
14
40
  const repoRoot = new URL("../..", import.meta.url).pathname;
15
41
 
16
42
  function readDotEnvKey(root: string, key: string): string | undefined {
@@ -71,6 +97,7 @@ const createViteConfig = (isDevServer: boolean) => ({
71
97
  devtools({
72
98
  eventBusConfig: { enabled: false },
73
99
  }),
100
+ lucideSpriteIconAliases(),
74
101
  iconsSpritePlugin,
75
102
  viteReact({
76
103
  babel: {
@@ -12,7 +12,7 @@
12
12
  "@robodev-ai/sdk": "^0.13.0"
13
13
  },
14
14
  "devDependencies": {
15
- "robodev": "^0.43.0",
15
+ "robodev": "^0.44.0",
16
16
  "rulesync": "^8.18.0",
17
17
  "typescript": "^5.9.2"
18
18
  }
@@ -4,13 +4,39 @@ import tailwindCSS from "@tailwindcss/vite";
4
4
  import { devtools } from "@tanstack/devtools-vite";
5
5
  import { tanstackRouter } from "@tanstack/router-plugin/vite";
6
6
  import viteReact from "@vitejs/plugin-react";
7
- import { readFileSync } from "node:fs";
7
+ import { copyFileSync, existsSync, readdirSync, readFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
- import { defineConfig as defineViteConfig, mergeConfig } from "vite";
9
+ import { defineConfig as defineViteConfig, mergeConfig, type Plugin } from "vite";
10
10
  import devtoolsJson from "vite-plugin-devtools-json";
11
11
  import { defineConfig as defineVitestConfig } from "vitest/config";
12
12
  import { reactIconsSprite } from "react-icons-sprite/vite";
13
13
 
14
+ /** react-icons-sprite maps Trash2 → trash2.mjs and MenuIcon → menu-icon.mjs; lucide ships trash-2.mjs / menu.mjs. */
15
+ function lucideSpriteIconAliases(): Plugin {
16
+ return {
17
+ name: "lucide-sprite-icon-aliases",
18
+ enforce: "pre",
19
+ apply: "build",
20
+ buildStart() {
21
+ const iconsDir = join(process.cwd(), "node_modules", "lucide-react", "dist", "esm", "icons");
22
+ if (!existsSync(iconsDir)) return;
23
+ for (const file of readdirSync(iconsDir)) {
24
+ if (!file.endsWith(".mjs")) continue;
25
+ const src = join(iconsDir, file);
26
+ const digit = /^(.+)-(\d+)\.mjs$/.exec(file);
27
+ if (digit) {
28
+ const dest = join(iconsDir, `${digit[1]}${digit[2]}.mjs`);
29
+ if (!existsSync(dest)) copyFileSync(src, dest);
30
+ }
31
+ if (!file.endsWith("-icon.mjs")) {
32
+ const dest = join(iconsDir, file.replace(/\.mjs$/, "-icon.mjs"));
33
+ if (!existsSync(dest)) copyFileSync(src, dest);
34
+ }
35
+ }
36
+ },
37
+ };
38
+ }
39
+
14
40
  const repoRoot = new URL("../..", import.meta.url).pathname;
15
41
 
16
42
  function readDotEnvKey(root: string, key: string): string | undefined {
@@ -71,6 +97,7 @@ const createViteConfig = (isDevServer: boolean) => ({
71
97
  devtools({
72
98
  eventBusConfig: { enabled: false },
73
99
  }),
100
+ lucideSpriteIconAliases(),
74
101
  iconsSpritePlugin,
75
102
  viteReact({
76
103
  babel: {
@@ -12,7 +12,7 @@
12
12
  "@robodev-ai/sdk": "^0.13.0"
13
13
  },
14
14
  "devDependencies": {
15
- "robodev": "^0.43.0",
15
+ "robodev": "^0.44.0",
16
16
  "rulesync": "^8.18.0",
17
17
  "typescript": "^5.9.2"
18
18
  }