diff --git a/packages/cli/src/commands/explorer/explorer.ts b/packages/cli/src/commands/explorer/explorer.ts index 037163de..4dd8c01f 100644 --- a/packages/cli/src/commands/explorer/explorer.ts +++ b/packages/cli/src/commands/explorer/explorer.ts @@ -5,9 +5,11 @@ export const explorerCommand: CommandModule = { describe: "Explorer commands", builder: async (yargs) => { const { explorerStartCommand } = await import("./explorerStart"); + const { explorerStopCommand } = await import("./explorerStop"); return yargs .command(explorerStartCommand) + .command(explorerStopCommand) .demandCommand( 1, "You must specify a subcommand. Use --help to see available options." diff --git a/packages/cli/src/commands/explorer/explorerStop.ts b/packages/cli/src/commands/explorer/explorerStop.ts new file mode 100644 index 00000000..3655e0cc --- /dev/null +++ b/packages/cli/src/commands/explorer/explorerStop.ts @@ -0,0 +1,17 @@ +import { CommandModule } from "yargs"; + +export const explorerStopCommand: CommandModule = { + command: "stop", + describe: "Stop the explorer UI", + handler: async () => { + try { + const { default: explorerStop } = + await import("../../scripts/explorer/stop"); + await explorerStop(); + process.exit(0); + } catch (error) { + console.error("Failed to stop explorer:", error); + process.exit(1); + } + }, +}; diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts new file mode 100644 index 00000000..0fcfba12 --- /dev/null +++ b/packages/cli/src/commands/init.ts @@ -0,0 +1,24 @@ +import { CommandModule } from "yargs"; + +import type { InitArgs } from "../scripts/init"; + +export const initCommand: CommandModule<{}, InitArgs> = { + command: "init [name]", + describe: "Create a new Protokit project from the starter-kit template", + builder: (yarg) => + yarg.positional("name", { + type: "string", + default: "starter-kit", + describe: "Directory name for the new project", + }), + handler: async (args) => { + try { + const { default: init } = await import("../scripts/init"); + await init({ name: args.name }); + process.exit(0); + } catch (error) { + console.error("Failed to initialize project:", error); + process.exit(1); + } + }, +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 7f60b14b..89793e55 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -10,6 +10,7 @@ import { wizardCommand } from "./commands/wizard"; import { settlementCommand } from "./commands/settlement/settlement"; import { lightnetCommand } from "./commands/lightnet/lightnet"; import { bridgeCommand } from "./commands/bridge/bridge"; +import { initCommand } from "./commands/init"; process.removeAllListeners("warning"); process.env.NODE_NO_WARNINGS = "1"; @@ -25,6 +26,7 @@ await yargs(hideBin(process.argv)) .command(settlementCommand) .command(lightnetCommand) .command(bridgeCommand) + .command(initCommand) .demandCommand( 1, "You must specify a command. Use --help to see available commands." diff --git a/packages/cli/src/scripts/explorer/start.ts b/packages/cli/src/scripts/explorer/start.ts index b84105c9..a9e129ef 100644 --- a/packages/cli/src/scripts/explorer/start.ts +++ b/packages/cli/src/scripts/explorer/start.ts @@ -35,7 +35,15 @@ async function runDockerContainer(args: { const { port = 5003, explorerImage } = args; console.log(`\nExplorer is running at http://localhost:${port}\n`); - const dockerArgs = ["run", "--rm", "-p", `${port}:3000`]; + const dockerArgs = [ + "run", + "-d", + "--rm", + "--name", + "protokit-explorer", + "-p", + `${port}:3000`, + ]; if (args.indexerUrl !== undefined) { dockerArgs.push("-e", `NEXT_PUBLIC_INDEXER_URL=${args.indexerUrl}`); diff --git a/packages/cli/src/scripts/explorer/stop.ts b/packages/cli/src/scripts/explorer/stop.ts new file mode 100644 index 00000000..db229407 --- /dev/null +++ b/packages/cli/src/scripts/explorer/stop.ts @@ -0,0 +1,37 @@ +import { spawn } from "child_process"; + +const CONTAINER_NAME = "protokit-explorer"; + +async function stopDockerContainer(): Promise { + return await new Promise((resolve, reject) => { + console.log("Stopping explorer container..."); + const child = spawn("docker", ["stop", CONTAINER_NAME], { + stdio: "inherit", + }); + + child.on("error", (error) => { + console.error("Failed to stop explorer container:", error); + reject(error); + }); + + child.on("exit", (code) => { + if (code !== null && code !== 0) { + reject( + new Error(`Failed to stop explorer container (exit code ${code})`) + ); + } else { + console.log("Explorer container stopped successfully"); + resolve(); + } + }); + }); +} + +export default async function (): Promise { + try { + await stopDockerContainer(); + } catch (error) { + console.error("Failed to stop explorer:", error); + throw error; + } +} diff --git a/packages/cli/src/scripts/init.ts b/packages/cli/src/scripts/init.ts new file mode 100644 index 00000000..bf5caeb7 --- /dev/null +++ b/packages/cli/src/scripts/init.ts @@ -0,0 +1,42 @@ +import { spawn } from "child_process"; + +const STARTER_KIT_REPO = "https://github.com/proto-kit/starter-kit.git"; + +export interface InitArgs { + name?: string; +} + +export default async function (args: InitArgs): Promise { + const targetDir = args.name ?? "starter-kit"; + + console.log(`\nCloning starter-kit into ./${targetDir}...\n`); + + return await new Promise((resolve, reject) => { + const child = spawn("git", ["clone", STARTER_KIT_REPO, targetDir], { + stdio: "inherit", + }); + + child.on("error", (error) => { + console.error("Failed to clone starter-kit:", error); + reject(error); + }); + + child.on("exit", (code) => { + if (code !== null && code !== 0) { + reject(new Error(`git clone failed with exit code ${code}`)); + } else { + console.log(`\nProject created at ./${targetDir}`); + console.log("\nNext steps:"); + console.log(` cd ${targetDir}`); + console.log(" pnpm install"); + console.log(" pnpm env:development prisma:generate"); + console.log(" pnpm env:inmemory dev"); + console.log(" ✨ You're all set. Enjoy coding! ✨"); + console.log( + "\nFor more details, see the README.md in the project directory.\n" + ); + resolve(); + } + }); + }); +}