create-basalt 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ <p align="center">
2
+ <a href="https://basaltkit-docs.pages.dev">
3
+ <img src="https://basaltkit-docs.pages.dev/social-card.png" alt="Basalt" width="440">
4
+ </a>
5
+ </p>
6
+
1
7
  # create-basalt
2
8
 
3
9
  Basalt project generator: a single command (`npm create basalt my-app`) creates a complete, ready-to-run SaaS application — typed API, authentication, multi-tenancy, and optionally billing, a web frontend, and the `basalt` CLI. It's the framework's starting point: use it whenever you want to start a new project.
@@ -249,6 +249,7 @@ import { buildApp } from '../src/app.js'
249
249
  // The dev tools (@basaltkit/generator; add @basaltkit/ai for ai:*) are imported
250
250
  // ONLY here \u2014 the runtime server (src/server.ts) never loads them, so the SaaS
251
251
  // runs without the codegen/AI layer.
252
+ // pnpm basalt dev \u2014 dev server: route table + watch (--worker for a queue worker)
252
253
  // pnpm basalt list \u2014 show available commands
253
254
  // pnpm basalt routes \u2014 list registered HTTP routes
254
255
  // pnpm basalt make:resource Project \u2014 generate a full resource vertical
@@ -302,7 +303,7 @@ function readme(options) {
302
303
  ];
303
304
  return `# ${options.name}
304
305
 
305
- A SaaS app scaffolded with [Basalt](https://github.com/Zebedeu/basalt).
306
+ A SaaS app scaffolded with [Basalt](https://github.com/basaltkit/basalt).
306
307
 
307
308
  Included: ${features.join(" \xB7 ")}.
308
309
 
package/dist/cli.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  #!/usr/bin/env node
2
+ export {};
package/dist/cli.js CHANGED
@@ -1,17 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- TargetNotEmptyError,
4
- WizardCancelledError,
5
- createProject,
6
- detectPackageManager,
7
- runWizard,
8
- ttyPrompter
9
- } from "./chunk-YJ7RXFTU.js";
10
-
11
- // src/cli.ts
12
- import { spawn } from "child_process";
13
- import { stdin, stdout } from "process";
14
- var USAGE = `Usage: npm create basalt <name> [options]
2
+ import { spawn } from 'node:child_process';
3
+ import { stdin, stdout } from 'node:process';
4
+ import { createProject, detectPackageManager, runWizard, ttyPrompter, TargetNotEmptyError, WizardCancelledError, } from './index.js';
5
+ const USAGE = `Usage: npm create basalt <name> [options]
15
6
 
16
7
  Options:
17
8
  --dir=<path> Target directory (default: ./<name>)
@@ -29,121 +20,138 @@ Options:
29
20
  Run with no name in a terminal to be prompted interactively.
30
21
  `;
31
22
  function parseArgs(argv) {
32
- const flags2 = {
33
- tenancy: true,
34
- auth: true,
35
- billing: false,
36
- ui: false,
37
- cli: false,
38
- install: false,
39
- git: false,
40
- yes: false
41
- };
42
- for (const token of argv) {
43
- if (token === "--no-tenancy") flags2.tenancy = false;
44
- else if (token === "--no-auth") flags2.auth = false;
45
- else if (token === "--billing") flags2.billing = true;
46
- else if (token === "--ui") flags2.ui = true;
47
- else if (token === "--cli") flags2.cli = true;
48
- else if (token === "--install") flags2.install = true;
49
- else if (token === "--git") flags2.git = true;
50
- else if (token === "-y" || token === "--yes") flags2.yes = true;
51
- else if (token.startsWith("--dir=")) flags2.dir = token.slice("--dir=".length);
52
- else if (token.startsWith("--pm=")) flags2.pm = token.slice("--pm=".length);
53
- else if (token === "--help" || token === "-h") {
54
- stdout.write(USAGE);
55
- process.exit(0);
56
- } else if (!token.startsWith("--") && flags2.name === void 0) flags2.name = token;
57
- }
58
- return flags2;
23
+ const flags = {
24
+ tenancy: true,
25
+ auth: true,
26
+ billing: false,
27
+ ui: false,
28
+ cli: false,
29
+ install: false,
30
+ git: false,
31
+ yes: false,
32
+ };
33
+ for (const token of argv) {
34
+ if (token === '--no-tenancy')
35
+ flags.tenancy = false;
36
+ else if (token === '--no-auth')
37
+ flags.auth = false;
38
+ else if (token === '--billing')
39
+ flags.billing = true;
40
+ else if (token === '--ui')
41
+ flags.ui = true;
42
+ else if (token === '--cli')
43
+ flags.cli = true;
44
+ else if (token === '--install')
45
+ flags.install = true;
46
+ else if (token === '--git')
47
+ flags.git = true;
48
+ else if (token === '-y' || token === '--yes')
49
+ flags.yes = true;
50
+ else if (token.startsWith('--dir='))
51
+ flags.dir = token.slice('--dir='.length);
52
+ else if (token.startsWith('--pm='))
53
+ flags.pm = token.slice('--pm='.length);
54
+ else if (token === '--help' || token === '-h') {
55
+ stdout.write(USAGE);
56
+ process.exit(0);
57
+ }
58
+ else if (!token.startsWith('--') && flags.name === undefined)
59
+ flags.name = token;
60
+ }
61
+ return flags;
59
62
  }
63
+ /** Runs a command inheriting stdio; resolves false on non-zero exit (never throws). */
60
64
  function run(command, args, cwd) {
61
- return new Promise((resolve) => {
62
- const child = spawn(command, args, {
63
- cwd,
64
- stdio: "inherit",
65
- shell: process.platform === "win32"
65
+ return new Promise((resolve) => {
66
+ const child = spawn(command, args, {
67
+ cwd,
68
+ stdio: 'inherit',
69
+ shell: process.platform === 'win32',
70
+ });
71
+ child.on('error', () => resolve(false));
72
+ child.on('close', (code) => resolve(code === 0));
66
73
  });
67
- child.on("error", () => resolve(false));
68
- child.on("close", (code) => resolve(code === 0));
69
- });
70
74
  }
75
+ /** Cleanly abort on Ctrl+C instead of dumping a Node AbortError stack trace. */
71
76
  function cancel() {
72
- stdout.write("\nCancelled.\n");
73
- process.exit(130);
77
+ stdout.write('\nCancelled.\n');
78
+ process.exit(130); // 128 + SIGINT
74
79
  }
75
- var flags = parseArgs(process.argv.slice(2));
76
- if (!flags.yes && flags.name === void 0 && stdin.isTTY) {
77
- try {
78
- const result = await runWizard(ttyPrompter(), {
79
- defaultPm: flags.pm ?? detectPackageManager()
80
- });
81
- flags.name = result.name;
82
- flags.tenancy = result.tenancy;
83
- flags.auth = result.auth;
84
- flags.billing = result.billing;
85
- flags.ui = result.ui;
86
- flags.cli = result.cli;
87
- flags.install = result.install;
88
- flags.git = result.git;
89
- flags.pm = result.pm;
90
- } catch (error) {
91
- if (error instanceof WizardCancelledError) cancel();
92
- throw error;
93
- }
80
+ const flags = parseArgs(process.argv.slice(2));
81
+ // Rich interactive wizard when nothing was specified in a terminal. CI, piped
82
+ // input, and `--yes` keep the flag-driven path.
83
+ if (!flags.yes && flags.name === undefined && stdin.isTTY) {
84
+ try {
85
+ const result = await runWizard(ttyPrompter(), {
86
+ defaultPm: flags.pm ?? detectPackageManager(),
87
+ });
88
+ flags.name = result.name;
89
+ flags.tenancy = result.tenancy;
90
+ flags.auth = result.auth;
91
+ flags.billing = result.billing;
92
+ flags.ui = result.ui;
93
+ flags.cli = result.cli;
94
+ flags.install = result.install;
95
+ flags.git = result.git;
96
+ flags.pm = result.pm;
97
+ }
98
+ catch (error) {
99
+ if (error instanceof WizardCancelledError)
100
+ cancel();
101
+ throw error;
102
+ }
94
103
  }
95
104
  if (!flags.name) {
96
- stdout.write(USAGE);
97
- process.exit(1);
105
+ stdout.write(USAGE);
106
+ process.exit(1);
98
107
  }
99
- var pm = flags.pm ?? detectPackageManager();
100
- if (flags.ui && pm !== "pnpm") {
101
- console.log(`Note: --ui projects are pnpm workspaces \u2014 using pnpm instead of ${pm}.`);
102
- pm = "pnpm";
108
+ let pm = flags.pm ?? detectPackageManager();
109
+ // The web/ frontend is a pnpm workspace member (pnpm-workspace.yaml); npm,
110
+ // yarn and bun can't install or run it, so --ui projects are pnpm-only.
111
+ if (flags.ui && pm !== 'pnpm') {
112
+ console.log(`Note: --ui projects are pnpm workspaces — using pnpm instead of ${pm}.`);
113
+ pm = 'pnpm';
103
114
  }
104
115
  try {
105
- const result = await createProject({
106
- name: flags.name,
107
- ...flags.dir ? { dir: flags.dir } : {},
108
- tenancy: flags.tenancy,
109
- auth: flags.auth,
110
- billing: flags.billing,
111
- ui: flags.ui,
112
- cli: flags.cli
113
- });
114
- console.log(`
115
- Created ${result.options.name} in ${result.dir}
116
- `);
117
- for (const file of result.files) console.log(` ${file}`);
118
- if (flags.git) {
119
- console.log("\nInitializing git repository\u2026");
120
- const ok = await run("git", ["init", "-q"], result.dir) && await run("git", ["add", "-A"], result.dir) && await run(
121
- "git",
122
- ["commit", "-q", "-m", "Initial commit from create-basalt"],
123
- result.dir
124
- );
125
- console.log(
126
- ok ? " git repository initialized." : " (skipped \u2014 git unavailable or already a repo)"
127
- );
128
- }
129
- if (flags.install) {
130
- console.log(`
131
- Installing dependencies with ${pm}\u2026`);
132
- const ok = await run(pm, ["install"], result.dir);
133
- if (!ok) console.log(` (install failed \u2014 run "${pm} install" yourself)`);
134
- }
135
- const steps = [`cd ${result.dir}`];
136
- if (!flags.install) steps.push(`${pm} install`);
137
- steps.push(`${pm} run dev${flags.ui ? " # API on :3000" : ""}`);
138
- if (flags.ui) steps.push(`pnpm --filter ${result.options.name}-web dev # UI on :5180`);
139
- console.log(`
140
- Next steps:
141
- ${steps.map((s) => ` ${s}`).join("\n")}
142
- `);
143
- } catch (error) {
144
- if (error instanceof TargetNotEmptyError) {
145
- console.error(error.message);
146
- process.exit(1);
147
- }
148
- throw error;
116
+ const result = await createProject({
117
+ name: flags.name,
118
+ ...(flags.dir ? { dir: flags.dir } : {}),
119
+ tenancy: flags.tenancy,
120
+ auth: flags.auth,
121
+ billing: flags.billing,
122
+ ui: flags.ui,
123
+ cli: flags.cli,
124
+ });
125
+ console.log(`\nCreated ${result.options.name} in ${result.dir}\n`);
126
+ for (const file of result.files)
127
+ console.log(` ${file}`);
128
+ if (flags.git) {
129
+ console.log('\nInitializing git repository…');
130
+ const ok = (await run('git', ['init', '-q'], result.dir)) &&
131
+ (await run('git', ['add', '-A'], result.dir)) &&
132
+ (await run('git', ['commit', '-q', '-m', 'Initial commit from create-basalt'], result.dir));
133
+ console.log(ok ? ' git repository initialized.' : ' (skipped — git unavailable or already a repo)');
134
+ }
135
+ if (flags.install) {
136
+ console.log(`\nInstalling dependencies with ${pm}…`);
137
+ const ok = await run(pm, ['install'], result.dir);
138
+ if (!ok)
139
+ console.log(` (install failed — run "${pm} install" yourself)`);
140
+ }
141
+ const steps = [`cd ${result.dir}`];
142
+ if (!flags.install)
143
+ steps.push(`${pm} install`);
144
+ steps.push(`${pm} run dev${flags.ui ? ' # API on :3000' : ''}`);
145
+ // `web` is wired as a pnpm workspace member (pnpm-workspace.yaml), so its dev
146
+ // server is launched with a pnpm filter regardless of the root package manager.
147
+ if (flags.ui)
148
+ steps.push(`pnpm --filter ${result.options.name}-web dev # UI on :5180`);
149
+ console.log(`\nNext steps:\n${steps.map((s) => ` ${s}`).join('\n')}\n`);
150
+ }
151
+ catch (error) {
152
+ if (error instanceof TargetNotEmptyError) {
153
+ console.error(error.message);
154
+ process.exit(1);
155
+ }
156
+ throw error;
149
157
  }
package/dist/index.d.ts CHANGED
@@ -1,110 +1,6 @@
1
- interface ProjectOptions {
2
- name: string;
3
- tenancy: boolean;
4
- auth: boolean;
5
- billing: boolean;
6
- /** Scaffold a web/ frontend (React + shadcn + SDK). */
7
- ui: boolean;
8
- /** Scaffold the `basalt` CLI entrypoint (code generators + built-in commands). */
9
- cli: boolean;
10
- }
11
-
12
- /** A selectable option. `value` is returned; `label`/`hint` are shown. */
13
- interface Choice<T> {
14
- value: T;
15
- label: string;
16
- hint?: string;
17
- }
18
- /**
19
- * The prompt surface the wizard talks to. Abstracted so the flow (`runWizard`)
20
- * is testable with a scripted implementation — the raw-mode TTY version is the
21
- * thin, untested I/O shell.
22
- */
23
- interface Prompter {
24
- intro(message: string): void;
25
- note(message: string): void;
26
- outro(message: string): void;
27
- text(opts: {
28
- message: string;
29
- placeholder?: string;
30
- initial?: string;
31
- validate?: (v: string) => string | undefined;
32
- }): Promise<string>;
33
- select<T>(opts: {
34
- message: string;
35
- choices: Choice<T>[];
36
- initial?: number;
37
- }): Promise<T>;
38
- multiselect<T>(opts: {
39
- message: string;
40
- choices: Choice<T>[];
41
- initial?: T[];
42
- }): Promise<T[]>;
43
- confirm(opts: {
44
- message: string;
45
- initial?: boolean;
46
- }): Promise<boolean>;
47
- }
48
- /** Thrown when the user aborts (Ctrl+C, or declines the final confirmation). */
49
- declare class WizardCancelledError extends Error {
50
- constructor();
51
- }
52
- /**
53
- * A rich, dependency-free terminal prompter: arrow-key `select`/`multiselect`
54
- * (raw mode), validated `text`, and `confirm`. Only usable in a TTY.
55
- */
56
- declare function ttyPrompter(): Prompter;
57
- /**
58
- * A scripted prompter for tests: each call dequeues the next answer of its kind.
59
- * `log` captures intro/note/outro lines so a test can assert the summary.
60
- */
61
- declare function scriptedPrompter(script: {
62
- text?: string[];
63
- select?: unknown[];
64
- multiselect?: unknown[][];
65
- confirm?: boolean[];
66
- }): Prompter & {
67
- log: string[];
68
- };
69
-
70
- type FeatureKey = 'tenancy' | 'auth' | 'billing' | 'ui' | 'cli';
71
- /** The feature toggles offered in the "custom" preset (and shown in the summary). */
72
- declare const FEATURES: Choice<FeatureKey>[];
73
- interface Preset {
74
- value: string;
75
- label: string;
76
- hint: string;
77
- /** null → let the user pick features (custom). */
78
- features: FeatureKey[] | null;
79
- }
80
- declare const PRESETS: Preset[];
81
- /** Validates a project name as an npm-installable package name. */
82
- declare function validateProjectName(name: string): string | undefined;
83
- interface WizardResult {
84
- name: string;
85
- tenancy: boolean;
86
- auth: boolean;
87
- billing: boolean;
88
- ui: boolean;
89
- cli: boolean;
90
- pm: PackageManager;
91
- install: boolean;
92
- git: boolean;
93
- }
94
- interface WizardOptions {
95
- /** Pre-filled name (from argv) — skips the name prompt when valid. */
96
- name?: string;
97
- /** Detected package manager, used as the default selection. */
98
- defaultPm?: PackageManager;
99
- }
100
- /**
101
- * The interactive scaffolding flow. Pure with respect to I/O — it drives the
102
- * injected {@link Prompter}, so tests script the answers and assert the result.
103
- * Throws {@link WizardCancelledError} if the user declines the final confirm.
104
- */
105
- declare function runWizard(prompter: Prompter, options?: WizardOptions): Promise<WizardResult>;
106
-
107
- interface CreateProjectInput {
1
+ import { type ProjectOptions } from './templates.js';
2
+ export type { ProjectOptions } from './templates.js';
3
+ export interface CreateProjectInput {
108
4
  name: string;
109
5
  /** Target directory. Default: ./<name> under cwd. */
110
6
  dir?: string;
@@ -116,21 +12,21 @@ interface CreateProjectInput {
116
12
  /** Scaffold the `basalt` CLI entrypoint (code generators + commands). Default: false. */
117
13
  cli?: boolean;
118
14
  }
119
- interface CreateProjectResult {
15
+ export interface CreateProjectResult {
120
16
  dir: string;
121
17
  files: string[];
122
18
  options: ProjectOptions;
123
19
  }
124
- declare class TargetNotEmptyError extends Error {
20
+ export declare class TargetNotEmptyError extends Error {
125
21
  constructor(dir: string);
126
22
  }
127
- type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
23
+ export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
128
24
  /**
129
25
  * Detects the package manager that invoked `npm create` / `npx`, via the
130
26
  * `npm_config_user_agent` env var npm/pnpm/yarn/bun all set. Falls back to npm.
131
27
  */
132
- declare function detectPackageManager(userAgent?: string | undefined): PackageManager;
28
+ export declare function detectPackageManager(userAgent?: string | undefined): PackageManager;
133
29
  /** Generates a ready-to-run Basalt app. Does not install dependencies. */
134
- declare function createProject(input: CreateProjectInput): Promise<CreateProjectResult>;
135
-
136
- export { type Choice, type CreateProjectInput, type CreateProjectResult, FEATURES, type FeatureKey, PRESETS, type PackageManager, type ProjectOptions, type Prompter, TargetNotEmptyError, WizardCancelledError, type WizardOptions, type WizardResult, createProject, detectPackageManager, runWizard, scriptedPrompter, ttyPrompter, validateProjectName };
30
+ export declare function createProject(input: CreateProjectInput): Promise<CreateProjectResult>;
31
+ export { runWizard, validateProjectName, PRESETS, FEATURES, type WizardResult, type WizardOptions, type FeatureKey } from './wizard.js';
32
+ export { ttyPrompter, scriptedPrompter, WizardCancelledError, type Prompter, type Choice } from './prompt.js';
package/dist/index.js CHANGED
@@ -1,24 +1,58 @@
1
- import {
2
- FEATURES,
3
- PRESETS,
4
- TargetNotEmptyError,
5
- WizardCancelledError,
6
- createProject,
7
- detectPackageManager,
8
- runWizard,
9
- scriptedPrompter,
10
- ttyPrompter,
11
- validateProjectName
12
- } from "./chunk-YJ7RXFTU.js";
13
- export {
14
- FEATURES,
15
- PRESETS,
16
- TargetNotEmptyError,
17
- WizardCancelledError,
18
- createProject,
19
- detectPackageManager,
20
- runWizard,
21
- scriptedPrompter,
22
- ttyPrompter,
23
- validateProjectName
24
- };
1
+ import { mkdir, readdir, writeFile } from 'node:fs/promises';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { appTest, appTs, envExample, envTs, gitignore, basaltBin, packageJson, pnpmWorkspaceYaml, readme, routesTs, serverTs, tsconfigJson, } from './templates.js';
4
+ import { uiFiles } from './templates-ui.js';
5
+ export class TargetNotEmptyError extends Error {
6
+ constructor(dir) {
7
+ super(`Target directory "${dir}" already exists and is not empty.`);
8
+ this.name = 'TargetNotEmptyError';
9
+ }
10
+ }
11
+ /**
12
+ * Detects the package manager that invoked `npm create` / `npx`, via the
13
+ * `npm_config_user_agent` env var npm/pnpm/yarn/bun all set. Falls back to npm.
14
+ */
15
+ export function detectPackageManager(userAgent = process.env['npm_config_user_agent']) {
16
+ const name = userAgent?.split(' ')[0]?.split('/')[0];
17
+ if (name === 'pnpm' || name === 'yarn' || name === 'bun')
18
+ return name;
19
+ return 'npm';
20
+ }
21
+ /** Generates a ready-to-run Basalt app. Does not install dependencies. */
22
+ export async function createProject(input) {
23
+ const options = {
24
+ name: input.name,
25
+ tenancy: input.tenancy ?? true,
26
+ auth: input.auth ?? true,
27
+ billing: input.billing ?? false,
28
+ ui: input.ui ?? false,
29
+ cli: input.cli ?? false,
30
+ };
31
+ const dir = resolve(input.dir ?? input.name);
32
+ const existing = await readdir(dir).catch(() => null);
33
+ if (existing && existing.length > 0)
34
+ throw new TargetNotEmptyError(dir);
35
+ const files = {
36
+ 'package.json': packageJson(options),
37
+ 'tsconfig.json': tsconfigJson(),
38
+ '.env.example': envExample(options),
39
+ '.gitignore': gitignore(),
40
+ 'README.md': readme(options),
41
+ 'pnpm-workspace.yaml': pnpmWorkspaceYaml(options),
42
+ 'src/env.ts': envTs(options),
43
+ 'src/app.ts': appTs(options),
44
+ 'src/routes.ts': routesTs(options),
45
+ 'src/server.ts': serverTs(),
46
+ 'tests/app.test.ts': appTest(options),
47
+ ...(options.cli ? { 'bin/basalt.ts': basaltBin() } : {}),
48
+ ...(options.ui ? uiFiles(options) : {}),
49
+ };
50
+ for (const [path, content] of Object.entries(files)) {
51
+ const target = join(dir, path);
52
+ await mkdir(dirname(target), { recursive: true });
53
+ await writeFile(target, content);
54
+ }
55
+ return { dir, files: Object.keys(files).sort(), options };
56
+ }
57
+ export { runWizard, validateProjectName, PRESETS, FEATURES } from './wizard.js';
58
+ export { ttyPrompter, scriptedPrompter, WizardCancelledError } from './prompt.js';
@@ -0,0 +1,57 @@
1
+ /** A selectable option. `value` is returned; `label`/`hint` are shown. */
2
+ export interface Choice<T> {
3
+ value: T;
4
+ label: string;
5
+ hint?: string;
6
+ }
7
+ /**
8
+ * The prompt surface the wizard talks to. Abstracted so the flow (`runWizard`)
9
+ * is testable with a scripted implementation — the raw-mode TTY version is the
10
+ * thin, untested I/O shell.
11
+ */
12
+ export interface Prompter {
13
+ intro(message: string): void;
14
+ note(message: string): void;
15
+ outro(message: string): void;
16
+ text(opts: {
17
+ message: string;
18
+ placeholder?: string;
19
+ initial?: string;
20
+ validate?: (v: string) => string | undefined;
21
+ }): Promise<string>;
22
+ select<T>(opts: {
23
+ message: string;
24
+ choices: Choice<T>[];
25
+ initial?: number;
26
+ }): Promise<T>;
27
+ multiselect<T>(opts: {
28
+ message: string;
29
+ choices: Choice<T>[];
30
+ initial?: T[];
31
+ }): Promise<T[]>;
32
+ confirm(opts: {
33
+ message: string;
34
+ initial?: boolean;
35
+ }): Promise<boolean>;
36
+ }
37
+ /** Thrown when the user aborts (Ctrl+C, or declines the final confirmation). */
38
+ export declare class WizardCancelledError extends Error {
39
+ constructor();
40
+ }
41
+ /**
42
+ * A rich, dependency-free terminal prompter: arrow-key `select`/`multiselect`
43
+ * (raw mode), validated `text`, and `confirm`. Only usable in a TTY.
44
+ */
45
+ export declare function ttyPrompter(): Prompter;
46
+ /**
47
+ * A scripted prompter for tests: each call dequeues the next answer of its kind.
48
+ * `log` captures intro/note/outro lines so a test can assert the summary.
49
+ */
50
+ export declare function scriptedPrompter(script: {
51
+ text?: string[];
52
+ select?: unknown[];
53
+ multiselect?: unknown[][];
54
+ confirm?: boolean[];
55
+ }): Prompter & {
56
+ log: string[];
57
+ };