From 133b0c79532e76e2633021a2fcfff2657e17768a Mon Sep 17 00:00:00 2001 From: stanlou Date: Mon, 9 Mar 2026 12:45:11 -0300 Subject: [PATCH 1/3] feat(cli): add explorer stop command --- .../cli/src/commands/explorer/explorer.ts | 2 + .../cli/src/commands/explorer/explorerStop.ts | 17 +++++++++ packages/cli/src/scripts/explorer/start.ts | 12 +++++- packages/cli/src/scripts/explorer/stop.ts | 37 +++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/commands/explorer/explorerStop.ts create mode 100644 packages/cli/src/scripts/explorer/stop.ts 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/scripts/explorer/start.ts b/packages/cli/src/scripts/explorer/start.ts index b84105c9..d843d427 100644 --- a/packages/cli/src/scripts/explorer/start.ts +++ b/packages/cli/src/scripts/explorer/start.ts @@ -35,8 +35,16 @@ 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..cc0c46aa --- /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; + } +} From 6c4994e32fec650b24f145ea8466e3618cc65dd1 Mon Sep 17 00:00:00 2001 From: stanlou Date: Mon, 9 Mar 2026 13:14:05 -0300 Subject: [PATCH 2/3] fix lint --- packages/cli/src/scripts/explorer/start.ts | 2 +- packages/cli/src/scripts/explorer/stop.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/scripts/explorer/start.ts b/packages/cli/src/scripts/explorer/start.ts index d843d427..a9e129ef 100644 --- a/packages/cli/src/scripts/explorer/start.ts +++ b/packages/cli/src/scripts/explorer/start.ts @@ -44,7 +44,7 @@ async function runDockerContainer(args: { "-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 index cc0c46aa..db229407 100644 --- a/packages/cli/src/scripts/explorer/stop.ts +++ b/packages/cli/src/scripts/explorer/stop.ts @@ -4,7 +4,7 @@ const CONTAINER_NAME = "protokit-explorer"; async function stopDockerContainer(): Promise { return await new Promise((resolve, reject) => { - console.log(`Stopping explorer container...`); + console.log("Stopping explorer container..."); const child = spawn("docker", ["stop", CONTAINER_NAME], { stdio: "inherit", }); From c9217e2837e2a90517c7bffe1963f001b462584c Mon Sep 17 00:00:00 2001 From: stanlou Date: Wed, 11 Mar 2026 00:14:22 -0300 Subject: [PATCH 3/3] feat(cli): add init command --- packages/cli/src/commands/init.ts | 24 ++++++++++++++++++ packages/cli/src/index.ts | 2 ++ packages/cli/src/scripts/init.ts | 42 +++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 packages/cli/src/commands/init.ts create mode 100644 packages/cli/src/scripts/init.ts 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/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(); + } + }); + }); +}