Skip to content

Commit 7a924c2

Browse files
cevianclaude
andcommitted
fix(cloud-dev): open /dev/ URL by default, restore background node_modules copy
- Append /dev/ to all URLs shown/opened in `crayon cloud run` - Restore background node_modules population in entrypoint.sh (reverts unintentional blocking change from d2162fd); dev server can start immediately via parent-directory lookup to /node_modules in image root - Improve entrypoint comments to clarify the flock/preinstall relationship and that the copy seeds the volume for fast subsequent npm installs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d2162fd commit 7a924c2

File tree

3 files changed

+38
-76
lines changed

3 files changed

+38
-76
lines changed

README.md

Lines changed: 22 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -15,93 +15,49 @@ This installs all dependencies (Node.js, Claude Code, Tiger CLI) and sets up the
1515
After installation, open a new terminal and run:
1616

1717
```bash
18-
crayon run
18+
crayon cloud run
1919
```
20-
___
21-
### Want to contribute? - Developer Guide
20+
Want to contribute? See [DEVELOPMENT.md](DEVELOPMENT.md).
2221

23-
To use the plugin from source:
22+
## Quick Start
2423

2524
```bash
26-
git clone https://github.com/timescale/crayon.git
27-
cd crayon
28-
pnpm install
29-
pnpm build
30-
npx tsx packages/core/src/cli/index.ts install --force
25+
crayon cloud run
3126
```
3227

33-
> **Note:** This outputs the `claude --plugin-dir <path>` command you need to run Claude Code with the local plugin.
34-
35-
## Quick Start
36-
37-
From an app directory (e.g., `examples/uptime-app`):
28+
This spins up a cloud sandbox and opens the dev environment in your browser. Describe what you want to automate — Claude will build, test, and iterate on your workflow automatically. Once ready, trigger it manually or connect it to a webhook.
3829

30+
Prefer working in your terminal?
3931
```bash
40-
# List available workflows
41-
pnpm crayon list
42-
43-
# Run a workflow
44-
pnpm crayon run url-check -i '{"url": "https://example.com"}'
45-
46-
# View run history
47-
pnpm crayon history
48-
49-
# Get details for a specific run (supports short IDs like git)
50-
pnpm crayon history bc44c8b1
32+
crayon cloud claude
5133
```
5234

35+
5336
## CLI Commands
5437

5538
| Command | Description |
5639
|---------|-------------|
57-
| `crayon list` | List all available workflows |
58-
| `crayon list --json` | Output as JSON |
59-
| `crayon run <workflow> -i <json>` | Run a workflow with JSON input |
60-
| `crayon run <workflow> --json` | Output result as JSON |
61-
| `crayon history` | List past workflow executions |
62-
| `crayon history -n 10` | Limit to N runs |
63-
| `crayon history -w <name>` | Filter by workflow name |
64-
| `crayon history <run-id>` | Get details of a specific run |
40+
| `crayon cloud run` | Start a new or existing workspace |
41+
| `crayon cloud claude` | Connect to a claude session on the sanbox |
42+
6543

6644
## Project Structure
6745

6846
```
6947
crayon/
7048
├── packages/
71-
│ ├── core/ # SDK + runtime (crayon)
72-
│ ├── cli/ # CLI tool (runcrayon)
73-
│ └── ui/ # UI components (@crayon/ui)
74-
── skills/ # Claude Code skills
75-
├── spec-author/
76-
├── compile-workflow/
77-
── validate-spec/
78-
── examples/
79-
└── uptime-app/ # Example application
49+
│ ├── core/ # SDK + CLI + MCP server + Dev UI (published as `crayon`)
50+
│ ├── ui/ # React UI components (@crayon/ui)
51+
│ └── auth-server/ # OAuth server (Nango-based)
52+
── skills/ # Claude Code skills
53+
├── create-workflow/
54+
├── compile-workflow/
55+
── refine-node/
56+
── integrations/
57+
└── deploy/
8058
```
8159

82-
## Testing Local Changes Against Cloud
83-
84-
To test local core changes on a cloud dev machine:
85-
86-
1. **Build & push a Docker image with your changes:**
87-
```bash
88-
cd packages/core/docker && ./build-dev.sh <tag>
89-
```
90-
91-
2. **Start the local auth server** (separate terminal):
92-
```bash
93-
cd packages/auth-server && pnpm dev
94-
```
95-
96-
3. **Create a new cloud machine using the local auth server:**
97-
```bash
98-
CRAYON_SERVER_URL=http://localhost:3000 pnpm --filter runcrayon exec node dist/cli/index.js cloud run
99-
```
100-
101-
4. **Open the dev UI** at `https://<fly-app-name>.fly.dev/dev/`
102-
10360
## Requirements
10461

105-
- Node.js 20+
106-
- PostgreSQL with TimescaleDB (or use Timescale Cloud)
107-
- `DATABASE_URL` environment variable
62+
- Node.js 22+
63+
- A Claude Subscription

packages/core/docker/entrypoint.sh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,13 @@ if [ ! -f "$APP_DIR/package.json" ]; then
7676
log " Running crayon init..."
7777
su -s /bin/bash "$DEV_USER" -c "cd '$APP_DIR' && "$CRAYON" init '$APP_NAME' --dir . --no-install"
7878

79-
# Copy pre-cached /node_modules onto the volume.
80-
# Runs before the dev server starts so Turbopack can resolve packages.
81-
log " Populating node_modules..."
79+
# Copy pre-cached /node_modules onto the volume in the background.
80+
# The dev server starts immediately — Node.js resolves packages via parent-directory
81+
# lookup to /node_modules in the image root. The copy seeds the volume so that later
82+
# `npm install <pkg>` only fetches the new package instead of reinstalling everything.
83+
# The app's preinstall hook (package.json) blocks on this same lock file, so any
84+
# `npm install` invoked before the copy finishes will wait rather than racing.
85+
log " Starting node_modules population in background..."
8286
touch /tmp/node_modules.lock
8387
(
8488
exec 9>/tmp/node_modules.lock
@@ -92,7 +96,7 @@ if [ ! -f "$APP_DIR/package.json" ]; then
9296
rm -rf "$APP_DIR/node_modules_temp"
9397
log " node_modules already exists, discarding temp copy"
9498
fi
95-
)
99+
) &
96100

97101
log " Scaffold complete"
98102
fi

packages/core/src/cli/cloud-dev.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ export async function runCloudRun(): Promise<void> {
122122
if (choice !== "__new__") {
123123
const existing = existingSandboxes.find((m) => m.app_name === choice);
124124
if (existing?.app_url) {
125-
p.log.info(`URL: ${pc.cyan(existing.app_url)}`);
126-
openInBrowser(existing.app_url);
125+
const devUrl = existing.app_url.replace(/\/$/, "") + "/dev/";
126+
p.log.info(`URL: ${pc.cyan(devUrl)}`);
127+
openInBrowser(devUrl);
127128
}
128129
p.log.info(`Status: ${pc.bold(existing?.fly_state ?? "unknown")}`);
129130
p.outro(pc.green("Sandbox ready."));
@@ -227,10 +228,11 @@ export async function runCloudRun(): Promise<void> {
227228
)) as { status: string; url?: string; error?: string };
228229

229230
if (statusResult.status === "running") {
230-
const url = statusResult.url ?? createResult.appUrl;
231+
const baseUrl = statusResult.url ?? createResult.appUrl;
232+
const devUrl = baseUrl.replace(/\/$/, "") + "/dev/";
231233
s.stop(pc.green("Sandbox is running!"));
232-
p.log.info(`URL: ${pc.cyan(url)}`);
233-
openInBrowser(url);
234+
p.log.info(`URL: ${pc.cyan(devUrl)}`);
235+
openInBrowser(devUrl);
234236
p.outro(pc.green("Cloud dev environment is ready!"));
235237
return;
236238
}
@@ -249,7 +251,7 @@ export async function runCloudRun(): Promise<void> {
249251
}
250252

251253
s.stop(pc.yellow("Sandbox is still starting"));
252-
p.log.info(`URL: ${pc.cyan(createResult.appUrl)}`);
254+
p.log.info(`URL: ${pc.cyan(createResult.appUrl.replace(/\/$/, "") + "/dev/")}`);
253255
p.log.info("Sandbox is taking longer than expected. Check status with:");
254256
p.log.info(" crayon cloud status");
255257
p.outro(pc.yellow("Cloud dev environment is starting..."));

0 commit comments

Comments
 (0)