Skip to content

refactor(init): replace @clack/prompts with consola #427

@BYK

Description

@BYK

Port sentry init to consola + output system

Goal

Replace all @clack/prompts usage in src/lib/init/ with consola equivalents.
Remove the @clack/prompts dependency entirely (or at least from init/).

@clack/prompts → consola mapping

@clack/prompts consola equivalent Notes
intro("text") logger.box("text") Box-styled intro
outro("text") logger.box("text") or logger.success("text") Outro styling
cancel("text") logger.error("text") Red cancel message
note(body, title) logger.box({ title, message: body }) Box with title
log.info(msg) logger.info(msg) Direct 1:1
log.warn(msg) logger.warn(msg) Direct 1:1
log.error(msg) logger.error(msg) Direct 1:1
spinner() logger.start(msg) / logger.success(msg) Consola spinner
confirm({ message }) logger.prompt(message, { type: "confirm" }) Returns boolean | Symbol
select({ message, options }) logger.prompt(message, { type: "select", options }) Options format differs
multiselect({ message, options }) logger.prompt(message, { type: "multiselect", options }) Same
isCancel(value) value === Symbol(clack:cancel) or strict !== true Consola uses same Symbol

Files to change (6 files, ~1826 lines total)

1. clack-utils.ts (96 lines) → rename to wizard-utils.ts

  • Remove @clack/prompts import
  • abortIfCancelled: use consola's cancel Symbol check
  • cancel()logger.error()
  • Keep feature info, labels, sorting (no clack dependency)

2. git.ts (93 lines)

  • confirmlogger.prompt(msg, { type: "confirm" })
  • isCancel → strict equality check (result !== true)
  • log.info/warnlogger.info/warn

3. interactive.ts (152 lines)

  • confirmlogger.prompt(msg, { type: "confirm" })
  • selectlogger.prompt(msg, { type: "select", options: [...] })
  • multiselectlogger.prompt(msg, { type: "multiselect", options: [...] })
  • log.info/errorlogger.info/error
  • consola select options: { label, value, hint? } (same as clack)

4. local-ops.ts (780 lines)

  • isCancel → Symbol check
  • selectlogger.prompt(msg, { type: "select", options })

5. formatters.ts (111 lines)

  • cancellogger.error
  • log.*logger.*
  • note(body, title)logger.box({ title, message: body })
  • outro(text)logger.success(text) or logger.box(text)

6. wizard-runner.ts (418 lines) — heaviest

  • cancellogger.error
  • confirmlogger.prompt
  • intrologger.box
  • log.*logger.*
  • spinner() → consola logger.start/logger.success/logger.fail
    • The spinner API differs: clack returns an object with .start()/.stop()/.message(),
      consola uses logger.start(msg) to start and logger.success(msg) to stop.
    • The suspend/resume loop uses spin.message("...") to update the spinner text.
      With consola, we can call logger.start(newMsg) to update.

Cancel handling

Consola's prompt() returns Symbol(clack:cancel) on Ctrl+C (it uses @clack/prompts internally).
isCancel() from @clack/prompts checks this Symbol. We can either:

  1. Import isCancel from consola (if exposed), or
  2. Check typeof result === "symbol" (simpler, more portable)

Spinner replacement

clack spinner API:

const spin = spinner();
spin.start("Loading...");
spin.message("Still loading...");
spin.stop("Done");
spin.stop("Failed", 1); // error

consola spinner API:

logger.start("Loading...");    // starts spinner
logger.start("Still loading..."); // updates message
logger.success("Done");        // stops with success
logger.fail("Failed");          // stops with failure

The key difference: clack's spinner is an object you pass around; consola's is
method calls on the logger instance. For the wizard runner, which passes the
spinner to handleSuspendedStep, we need to either:

  • Pass the logger instance instead
  • Create a wrapper that matches the old API

Execution order

  1. Create wizard-utils.ts from clack-utils.ts (rename, remove clack imports)
  2. Migrate git.ts
  3. Migrate interactive.ts
  4. Migrate local-ops.ts
  5. Migrate formatters.ts
  6. Migrate wizard-runner.ts (spinner is the hard part)
  7. Delete clack-utils.ts
  8. Remove @clack/prompts from package.json (if no other usage)
  9. Run tests, typecheck, lint

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions