Skip to content

Commit 957c257

Browse files
chore: automatic CLI rebuild on file change (#125)
* chore: automatic CLI rebuild on file change * feat(cli): Show running VMs in CLI dashboard (#129) * organize code and add view context to manage views * better types for views * add list of running VMs * Install chalk and date-fns packages * Update CLI tool look and feel a bit * Create custom components and show vms on dashboard
1 parent 62da4fe commit 957c257

File tree

14 files changed

+1275
-348
lines changed

14 files changed

+1275
-348
lines changed

package-lock.json

Lines changed: 373 additions & 85 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
},
3838
"types": "./dist/esm/index.d.ts",
3939
"scripts": {
40+
"dev:cli": "node scripts/dev-cli.cjs",
4041
"build": "npm run clean && npm run build:esbuild && npm run build:cjs:types && npm run build:esm:types && chmod +x dist/bin/codesandbox.mjs",
4142
"build:esbuild": "node esbuild.cjs",
4243
"build:cjs:types": "tsc -p ./tsconfig.build-cjs.json --emitDeclarationOnly",
@@ -69,6 +70,7 @@
6970
],
7071
"devDependencies": {
7172
"@hey-api/openapi-ts": "^0.63.2",
73+
"@parcel/watcher": "^2.5.1",
7274
"@types/blessed": "^0.1.25",
7375
"@types/node": "^22.15.30",
7476
"@types/react": "^19.1.5",
@@ -97,6 +99,8 @@
9799
"blessed": "^0.1.81",
98100
"blessed-contrib": "^4.11.0",
99101
"cli-table3": "^0.6.3",
102+
"chalk": "^5.4.1",
103+
"date-fns": "^4.1.0",
100104
"isbinaryfile": "^5.0.4",
101105
"isomorphic-ws": "^5.0.0",
102106
"ora": "^8.2.0",

scripts/dev-cli.cjs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env node
2+
3+
const watcher = require("@parcel/watcher");
4+
const { execSync } = require("child_process");
5+
const path = require("path");
6+
7+
console.log("🚀 Starting CLI development mode...");
8+
console.log("");
9+
10+
const buildCliOnly = () => {
11+
console.log("🔨 Building CLI...");
12+
console.log("");
13+
14+
const startTime = Date.now();
15+
16+
try {
17+
execSync("node esbuild.cjs", { stdio: "inherit" });
18+
execSync("chmod +x dist/bin/codesandbox.mjs", { stdio: "inherit" });
19+
20+
const duration = Date.now() - startTime;
21+
22+
console.log(`✅ CLI build completed in ${duration}ms`);
23+
console.log("");
24+
25+
return true;
26+
} catch (error) {
27+
console.error("❌ CLI build failed:", error.message);
28+
console.log("");
29+
30+
return false;
31+
}
32+
};
33+
34+
console.log("🔨 Initial build...");
35+
console.log("");
36+
37+
try {
38+
execSync("npm run build", { stdio: "inherit" });
39+
40+
console.log("✅ Initial build completed, watching for changes...");
41+
console.log("");
42+
} catch (error) {
43+
console.error("❌ Initial build failed:", error.message);
44+
process.exit(1);
45+
}
46+
47+
const startWatching = async () => {
48+
const watchPath = path.join(__dirname, "../src/bin");
49+
50+
try {
51+
let subscription = await watcher.subscribe(watchPath, (err, events) => {
52+
if (err) {
53+
console.error("❌ Watcher error:", err);
54+
return;
55+
}
56+
57+
// Filter out temporary files and directories
58+
const relevantEvents = events.filter((event) => {
59+
const filename = path.basename(event.path);
60+
const validExtensions = [".ts", ".tsx", ".js", ".jsx"];
61+
62+
return (
63+
!filename.startsWith(".") &&
64+
!filename.includes("node_modules") &&
65+
validExtensions.some(ext => filename.endsWith(ext))
66+
);
67+
});
68+
69+
if (relevantEvents.length === 0) {
70+
return;
71+
}
72+
73+
console.log(`📝 File${relevantEvents.length > 1 ? "s" : ""} changed:`);
74+
75+
relevantEvents.forEach((event) => {
76+
const relativePath = path.relative(process.cwd(), event.path);
77+
console.log(` ${event.type}: ${relativePath}`);
78+
});
79+
80+
console.log("");
81+
82+
const shouldRebuild = buildCliOnly();
83+
84+
if (!shouldRebuild) {
85+
console.log("🔄 Watching for changes...");
86+
console.log("");
87+
}
88+
});
89+
90+
// Handle graceful shutdown
91+
process.on("SIGINT", async () => {
92+
console.log("\n🛑 Stopping watcher...");
93+
await subscription.unsubscribe();
94+
process.exit(0);
95+
});
96+
} catch (error) {
97+
console.error("❌ Failed to start watcher:", error);
98+
process.exit(1);
99+
}
100+
};
101+
102+
startWatching();

src/bin/main.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ import { buildCommand } from "./commands/build";
66
import { sandboxesCommand } from "./commands/sandbox";
77
import { previewHostsCommand } from "./commands/previewHosts";
88
import { hostTokensCommand } from "./commands/hostTokens";
9-
import { Dashboard } from "./ui/Dashboard";
9+
import { App } from "./ui/App";
1010
import React from "react";
1111
import { SDKProvider } from "./ui/sdkContext";
1212
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
13+
import { ViewProvider } from "./ui/viewContext";
1314

1415
if (process.argv.length === 2) {
15-
// Clear the screen before rendering the dashboard
16+
// Clear the screen before rendering the App
1617
process.stdout.write("\x1Bc");
1718

1819
const queryClient = new QueryClient();
1920

2021
render(
2122
<QueryClientProvider client={queryClient}>
2223
<SDKProvider>
23-
<Dashboard />
24+
<ViewProvider>
25+
<App />
26+
</ViewProvider>
2427
</SDKProvider>
2528
</QueryClientProvider>,
2629
{

src/bin/ui/App.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { Box, Text } from "ink";
3+
import { Dashboard } from "./views/Dashboard";
4+
import { useView } from "./viewContext";
5+
import { Sandbox } from "./views/Sandbox";
6+
import { useTerminalSize } from "./hooks/useTerminalSize";
7+
8+
export function App() {
9+
const [stdoutWidth, stdoutHeight] = useTerminalSize();
10+
const { view } = useView();
11+
12+
return (
13+
<Box flexDirection="column" width={stdoutWidth} height={stdoutHeight} padding={1}>
14+
<Box marginBottom={1}>
15+
<Text bold>□ CodeSandbox SDK</Text>
16+
</Box>
17+
{view.name === "dashboard" && <Dashboard />}
18+
{view.name === "sandbox" && <Sandbox />}
19+
</Box>
20+
);
21+
}

0 commit comments

Comments
 (0)