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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions