diff --git a/cli/src/commands/init/init.ts b/cli/src/commands/init/init.ts index 26f42d39f6..a8decb7a39 100644 --- a/cli/src/commands/init/init.ts +++ b/cli/src/commands/init/init.ts @@ -1,6 +1,6 @@ import { stat, writeFile, rm, readdir } from "node:fs/promises"; import { join } from "node:path"; -import { writeFileSync, mkdirSync } from "node:fs"; +import { writeFileSync, mkdirSync, existsSync } from "node:fs"; import { colors } from "@cliffy/ansi/colors"; import { Command } from "@cliffy/command"; import { Confirm } from "@cliffy/prompt/confirm"; @@ -274,6 +274,34 @@ async function initAction(opts: InitOptions) { } } + // Generate .claude/launch.json at the workspace root so Claude Code can launch + // `wmill dev` from there and land on the file picker (no --path → picker mode). + try { + const rootClaudeDir = join(".", ".claude"); + const rootLaunchPath = join(rootClaudeDir, "launch.json"); + if (existsSync(rootLaunchPath)) { + log.info(colors.gray(`Skipped ${rootLaunchPath} (already exists)`)); + } else { + const rootLaunchJson = JSON.stringify({ + version: "0.0.1", + configurations: [{ + name: "windmill", + runtimeExecutable: "bash", + runtimeArgs: ["-c", "wmill dev --proxy-port ${PORT:-4000} --no-open"], + port: 4000, + autoPort: true, + }], + }, null, 2) + "\n"; + mkdirSync(rootClaudeDir, { recursive: true }); + writeFileSync(rootLaunchPath, rootLaunchJson, "utf-8"); + log.info(colors.green(`Created ${rootLaunchPath}`)); + } + } catch (error) { + log.warn( + `Could not create root .claude/launch.json: ${error instanceof Error ? error.message : error}` + ); + } + // Generate .claude/launch.json for each flow folder try { const flowSuffix = nonDottedPaths ? "__flow" : ".flow";