create-quiver 0.14.1 → 0.15.1

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +35 -0
  3. package/README_FOR_AI.md +15 -4
  4. package/ROADMAP.md +13 -2
  5. package/docs/AI_CONTEXT.md.template +4 -0
  6. package/docs/AI_ONBOARDING_PROMPT.md.template +8 -0
  7. package/docs/CLI_UX_GUIDE.md +79 -4
  8. package/docs/COMMANDS.md.template +21 -5
  9. package/docs/TROUBLESHOOTING.md +70 -0
  10. package/docs/TROUBLESHOOTING.md.template +20 -0
  11. package/docs/getting-started/installation.md +86 -0
  12. package/docs/reference/commands.md +33 -1
  13. package/package.json +1 -1
  14. package/specs/quiver-v30-interactive-cli-ux-agent-selection/EVIDENCE_REPORT.md +213 -0
  15. package/specs/quiver-v30-interactive-cli-ux-agent-selection/EXECUTION_PLAN.md +85 -0
  16. package/specs/quiver-v30-interactive-cli-ux-agent-selection/SPEC.md +213 -0
  17. package/specs/quiver-v30-interactive-cli-ux-agent-selection/STATUS.md +31 -0
  18. package/specs/quiver-v30-interactive-cli-ux-agent-selection/pr.md +103 -0
  19. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +33 -0
  20. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +56 -0
  21. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-00-spec-foundation/slice.json +71 -0
  22. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-01-cli-ux-runtime-progress-engine/CLOSURE_BRIEF.md +31 -0
  23. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-01-cli-ux-runtime-progress-engine/EXECUTION_BRIEF.md +54 -0
  24. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-01-cli-ux-runtime-progress-engine/slice.json +69 -0
  25. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-02-agent-profile-selection-selectors/CLOSURE_BRIEF.md +33 -0
  26. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-02-agent-profile-selection-selectors/EXECUTION_BRIEF.md +56 -0
  27. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-02-agent-profile-selection-selectors/slice.json +81 -0
  28. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-03-provider-model-selection-contract/CLOSURE_BRIEF.md +32 -0
  29. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-03-provider-model-selection-contract/EXECUTION_BRIEF.md +54 -0
  30. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-03-provider-model-selection-contract/slice.json +75 -0
  31. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-04-planner-ia-progress-flows/CLOSURE_BRIEF.md +32 -0
  32. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-04-planner-ia-progress-flows/EXECUTION_BRIEF.md +57 -0
  33. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-04-planner-ia-progress-flows/slice.json +85 -0
  34. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-05-executor-pr-progress-flows/CLOSURE_BRIEF.md +33 -0
  35. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-05-executor-pr-progress-flows/EXECUTION_BRIEF.md +57 -0
  36. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-05-executor-pr-progress-flows/slice.json +85 -0
  37. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-06-doctor-visual-json-contract/CLOSURE_BRIEF.md +35 -0
  38. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-06-doctor-visual-json-contract/EXECUTION_BRIEF.md +55 -0
  39. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-06-doctor-visual-json-contract/slice.json +81 -0
  40. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-07-interactive-init-spec-create/CLOSURE_BRIEF.md +34 -0
  41. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-07-interactive-init-spec-create/EXECUTION_BRIEF.md +55 -0
  42. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-07-interactive-init-spec-create/slice.json +85 -0
  43. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-08-tests-docs-cross-platform-release/CLOSURE_BRIEF.md +34 -0
  44. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-08-tests-docs-cross-platform-release/EXECUTION_BRIEF.md +59 -0
  45. package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-08-tests-docs-cross-platform-release/slice.json +95 -0
  46. package/specs/quiver-v31-ai-model-catalog-agent-selection/EVIDENCE_REPORT.md +185 -0
  47. package/specs/quiver-v31-ai-model-catalog-agent-selection/EXECUTION_PLAN.md +85 -0
  48. package/specs/quiver-v31-ai-model-catalog-agent-selection/SPEC.md +337 -0
  49. package/specs/quiver-v31-ai-model-catalog-agent-selection/STATUS.md +30 -0
  50. package/specs/quiver-v31-ai-model-catalog-agent-selection/pr.md +98 -0
  51. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
  52. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +51 -0
  53. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-00-spec-foundation/slice.json +62 -0
  54. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-01-model-catalog-alias-normalization/CLOSURE_BRIEF.md +32 -0
  55. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-01-model-catalog-alias-normalization/EXECUTION_BRIEF.md +53 -0
  56. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-01-model-catalog-alias-normalization/slice.json +72 -0
  57. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-02-interactive-agent-set-selectors/CLOSURE_BRIEF.md +36 -0
  58. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-02-interactive-agent-set-selectors/EXECUTION_BRIEF.md +56 -0
  59. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-02-interactive-agent-set-selectors/slice.json +78 -0
  60. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-03-agent-doctor-repair/CLOSURE_BRIEF.md +36 -0
  61. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-03-agent-doctor-repair/EXECUTION_BRIEF.md +57 -0
  62. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-03-agent-doctor-repair/slice.json +77 -0
  63. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-04-shared-preflight-provider-errors/CLOSURE_BRIEF.md +35 -0
  64. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-04-shared-preflight-provider-errors/EXECUTION_BRIEF.md +55 -0
  65. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-04-shared-preflight-provider-errors/slice.json +84 -0
  66. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-05-ai-models-list/CLOSURE_BRIEF.md +32 -0
  67. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-05-ai-models-list/EXECUTION_BRIEF.md +52 -0
  68. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-05-ai-models-list/slice.json +72 -0
  69. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-06-docs-templates-alignment/CLOSURE_BRIEF.md +33 -0
  70. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-06-docs-templates-alignment/EXECUTION_BRIEF.md +58 -0
  71. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-06-docs-templates-alignment/slice.json +84 -0
  72. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-07-tests-smokes-release-readiness/CLOSURE_BRIEF.md +32 -0
  73. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-07-tests-smokes-release-readiness/EXECUTION_BRIEF.md +59 -0
  74. package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-07-tests-smokes-release-readiness/slice.json +94 -0
  75. package/specs/quiver-v32-npx-installation-guidance/EVIDENCE_REPORT.md +26 -0
  76. package/specs/quiver-v32-npx-installation-guidance/SPEC.md +55 -0
  77. package/specs/quiver-v32-npx-installation-guidance/STATUS.md +23 -0
  78. package/specs/quiver-v32-npx-installation-guidance/pr.md +72 -0
  79. package/specs/quiver-v32-npx-installation-guidance/slices/slice-00-installation-docs/CLOSURE_BRIEF.md +31 -0
  80. package/specs/quiver-v32-npx-installation-guidance/slices/slice-00-installation-docs/EXECUTION_BRIEF.md +56 -0
  81. package/specs/quiver-v32-npx-installation-guidance/slices/slice-00-installation-docs/slice.json +75 -0
  82. package/src/create-quiver/commands/ai.js +797 -99
  83. package/src/create-quiver/commands/flow.js +2 -2
  84. package/src/create-quiver/commands/spec.js +106 -6
  85. package/src/create-quiver/index.js +557 -78
  86. package/src/create-quiver/lib/agent-profiles.js +440 -11
  87. package/src/create-quiver/lib/ai/execution-plan.js +111 -8
  88. package/src/create-quiver/lib/ai/executor.js +291 -28
  89. package/src/create-quiver/lib/ai/model-catalog.js +333 -0
  90. package/src/create-quiver/lib/ai/providers.js +211 -2
  91. package/src/create-quiver/lib/cli/selectors.js +160 -0
  92. package/src/create-quiver/lib/cli/theme.js +5 -2
  93. package/src/create-quiver/lib/cli/ux-flags.js +18 -0
  94. package/src/create-quiver/lib/cli/ux.js +100 -5
@@ -0,0 +1,160 @@
1
+ const { resolveUxMode } = require('./ux');
2
+
3
+ function formatError(message) {
4
+ return `create-quiver: ${message}`;
5
+ }
6
+
7
+ function normalizeSelectorOptions(options = []) {
8
+ return options.map((option) => {
9
+ if (typeof option === 'string') {
10
+ return {
11
+ label: option,
12
+ value: option,
13
+ hint: '',
14
+ default: false,
15
+ };
16
+ }
17
+ return {
18
+ label: String(option.label || option.name || option.id || option.value || ''),
19
+ value: String(option.value || option.id || option.path || option.label || ''),
20
+ hint: option.hint || option.description || '',
21
+ default: option.default === true || option.recommended === true,
22
+ raw: option.raw || option,
23
+ };
24
+ }).filter((option) => option.label && option.value);
25
+ }
26
+
27
+ function findOption(options, value) {
28
+ const normalized = String(value || '').trim();
29
+ if (!normalized) return null;
30
+ return options.find((option) => option.value === normalized || option.label === normalized) || null;
31
+ }
32
+
33
+ function resolveDefaultOption(options, defaultValue) {
34
+ return findOption(options, defaultValue) || options.find((option) => option.default) || (options.length === 1 ? options[0] : null);
35
+ }
36
+
37
+ async function loadClack(injected) {
38
+ if (injected) return injected;
39
+ return import('@clack/prompts');
40
+ }
41
+
42
+ async function selectOption(message, rawOptions, options = {}) {
43
+ const normalizedOptions = normalizeSelectorOptions(rawOptions);
44
+ if (normalizedOptions.length === 0) {
45
+ throw new Error(formatError(`${options.name || 'selection'} has no available options.`));
46
+ }
47
+
48
+ const explicit = findOption(normalizedOptions, options.value);
49
+ if (explicit) return explicit;
50
+ if (options.value) {
51
+ throw new Error(formatError(`${options.name || 'selection'} option '${options.value}' was not found.`));
52
+ }
53
+
54
+ const mode = resolveUxMode({
55
+ interactive: options.interactive === true,
56
+ json: options.json,
57
+ noColor: options.noColor,
58
+ stdinIsTTY: options.stdinIsTTY,
59
+ stdoutIsTTY: options.stdoutIsTTY,
60
+ stderrIsTTY: options.stderrIsTTY,
61
+ }, options.env || process.env, {
62
+ input: options.input || process.stdin,
63
+ output: options.output || process.stdout,
64
+ error: options.error || process.stderr,
65
+ });
66
+
67
+ if (mode.usePrompts) {
68
+ if (typeof options.promptSelect === 'function') {
69
+ const selected = await options.promptSelect(message, normalizedOptions);
70
+ const match = findOption(normalizedOptions, selected);
71
+ if (!match) {
72
+ throw new Error(formatError(`${options.name || 'selection'} prompt returned unknown option '${selected}'.`));
73
+ }
74
+ return match;
75
+ }
76
+ const clack = await loadClack(options.prompts);
77
+ const selected = await clack.select({
78
+ message,
79
+ options: normalizedOptions.map((option) => ({
80
+ label: option.label,
81
+ value: option.value,
82
+ hint: option.hint || undefined,
83
+ })),
84
+ initialValue: resolveDefaultOption(normalizedOptions, options.defaultValue)?.value,
85
+ });
86
+ if (clack.isCancel && clack.isCancel(selected)) {
87
+ throw new Error(formatError(`${options.name || 'selection'} was canceled.`));
88
+ }
89
+ return findOption(normalizedOptions, selected);
90
+ }
91
+
92
+ const fallback = resolveDefaultOption(normalizedOptions, options.defaultValue);
93
+ if (fallback) return fallback;
94
+
95
+ const flag = options.flag || '--value';
96
+ const available = normalizedOptions.map((option) => option.value).join(', ');
97
+ throw new Error(formatError([
98
+ `${options.name || 'selection'} requires an explicit choice.`,
99
+ `Available options: ${available}.`,
100
+ `Use ${flag} <value> or rerun with --interactive.`,
101
+ ].join('\n')));
102
+ }
103
+
104
+ async function promptText(message, options = {}) {
105
+ const explicit = String(options.value || '').trim();
106
+ if (explicit) return explicit;
107
+
108
+ const mode = resolveUxMode({
109
+ interactive: options.interactive === true,
110
+ json: options.json,
111
+ noColor: options.noColor,
112
+ stdinIsTTY: options.stdinIsTTY,
113
+ stdoutIsTTY: options.stdoutIsTTY,
114
+ stderrIsTTY: options.stderrIsTTY,
115
+ }, options.env || process.env, {
116
+ input: options.input || process.stdin,
117
+ output: options.output || process.stdout,
118
+ error: options.error || process.stderr,
119
+ });
120
+
121
+ if (mode.usePrompts) {
122
+ if (typeof options.promptText === 'function') {
123
+ const value = await options.promptText(message, options);
124
+ const normalized = String(value || '').trim();
125
+ if (!normalized && options.required !== false) {
126
+ throw new Error(formatError(`${options.name || 'input'} is required.`));
127
+ }
128
+ return normalized;
129
+ }
130
+ const clack = await loadClack(options.prompts);
131
+ const value = await clack.text({
132
+ message,
133
+ placeholder: options.placeholder,
134
+ initialValue: options.initialValue,
135
+ validate: options.required === false
136
+ ? undefined
137
+ : (input) => (String(input || '').trim() ? undefined : 'Required'),
138
+ });
139
+ if (clack.isCancel && clack.isCancel(value)) {
140
+ throw new Error(formatError(`${options.name || 'input'} was canceled.`));
141
+ }
142
+ return String(value || '').trim();
143
+ }
144
+
145
+ if (options.defaultValue !== undefined && options.defaultValue !== null) {
146
+ return String(options.defaultValue).trim();
147
+ }
148
+
149
+ const flag = options.flag || '--value';
150
+ throw new Error(formatError([
151
+ `${options.name || 'input'} requires an explicit value.`,
152
+ `Use ${flag} <value> or rerun with --interactive.`,
153
+ ].join('\n')));
154
+ }
155
+
156
+ module.exports = {
157
+ normalizeSelectorOptions,
158
+ promptText,
159
+ selectOption,
160
+ };
@@ -9,8 +9,11 @@ const QUIVER_COLORS = Object.freeze({
9
9
  const STATUS_COLORS = Object.freeze({
10
10
  info: 'sky',
11
11
  command: 'blue',
12
+ success: 'blue',
12
13
  planner: 'violet',
13
14
  review: 'magenta',
15
+ warning: 'magenta',
16
+ error: 'magenta',
14
17
  risk: 'magenta',
15
18
  muted: 'periwinkle',
16
19
  });
@@ -70,8 +73,8 @@ function resolveTheme(options = {}, env = process.env, tty = {}) {
70
73
  const useColor = shouldUseColor(options, env, tty);
71
74
  const useUnicode = shouldUseUnicode(options, env, tty);
72
75
  const symbols = useUnicode
73
- ? { start: '◇', success: '✓', warning: '!', error: '✖', bullet: '•' }
74
- : { start: '*', success: 'OK', warning: 'WARN', error: 'ERR', bullet: '-' };
76
+ ? { start: '◇', section: '◆', success: '✓', warning: '!', error: '✖', bullet: '•' }
77
+ : { start: '*', section: '*', success: 'OK', warning: 'WARN', error: 'ERR', bullet: '-' };
75
78
  const theme = {
76
79
  colors: QUIVER_COLORS,
77
80
  statusColors: STATUS_COLORS,
@@ -5,6 +5,12 @@ const UX_FLAG_OPTIONS = Object.freeze({
5
5
  });
6
6
 
7
7
  const UX_FLAG_MATRIX = Object.freeze({
8
+ init: Object.freeze({
9
+ withPlanner: false,
10
+ interactive: true,
11
+ review: false,
12
+ note: 'guided project onboarding choices',
13
+ }),
8
14
  'ai prepare-context': Object.freeze({
9
15
  withPlanner: true,
10
16
  interactive: true,
@@ -29,6 +35,18 @@ const UX_FLAG_MATRIX = Object.freeze({
29
35
  review: true,
30
36
  note: 'PR body review and interactive PR inputs',
31
37
  }),
38
+ 'ai execute-slice': Object.freeze({
39
+ withPlanner: false,
40
+ interactive: true,
41
+ review: false,
42
+ note: 'executor profile and ready-slice selection',
43
+ }),
44
+ 'ai execute-plan': Object.freeze({
45
+ withPlanner: false,
46
+ interactive: true,
47
+ review: false,
48
+ note: 'execution strategy confirmation and future selectors',
49
+ }),
32
50
  });
33
51
 
34
52
  function formatError(message) {
@@ -49,6 +49,11 @@ function createUx(options = {}) {
49
49
  write(`${text}\n`);
50
50
  }
51
51
 
52
+ function formatStatus(status, text) {
53
+ const symbol = mode.theme.symbols[status] || mode.theme.symbols.bullet;
54
+ return mode.theme.status(status, `${symbol} ${text}`);
55
+ }
56
+
52
57
  function heading(text) {
53
58
  if (mode.json) return;
54
59
  if (!mode.decoration) {
@@ -59,15 +64,65 @@ function createUx(options = {}) {
59
64
  line(mode.theme.status('planner', `${prefix} ${text}`));
60
65
  }
61
66
 
67
+ function section(text) {
68
+ if (mode.json) return;
69
+ if (!mode.decoration) {
70
+ line(text);
71
+ return;
72
+ }
73
+ const prefix = mode.theme.symbols.section || mode.theme.symbols.start;
74
+ line(mode.theme.status('command', `${prefix} ${text}`));
75
+ }
76
+
62
77
  function writeStatus(status, text) {
63
78
  if (mode.json) return;
64
79
  if (!mode.decoration) {
65
80
  line(text);
66
81
  return;
67
82
  }
68
- const symbol = mode.theme.symbols[status] || mode.theme.symbols.bullet;
69
- const body = mode.theme.status(status, `${symbol} ${text}`);
70
- line(body);
83
+ line(formatStatus(status, text));
84
+ }
85
+
86
+ function check(text) {
87
+ writeStatus('success', text);
88
+ }
89
+
90
+ function warning(text) {
91
+ writeStatus('warning', text);
92
+ }
93
+
94
+ function error(text) {
95
+ writeStatus('error', text);
96
+ }
97
+
98
+ function info(text) {
99
+ writeStatus('info', text);
100
+ }
101
+
102
+ function summary(items = [], summaryOptions = {}) {
103
+ if (mode.json) return;
104
+ const title = summaryOptions.title || 'Summary';
105
+ section(title);
106
+ for (const item of items) {
107
+ if (typeof item === 'string') {
108
+ line(mode.decoration ? mode.theme.status('muted', ` ${mode.theme.symbols.bullet} ${item}`) : `- ${item}`);
109
+ continue;
110
+ }
111
+ if (item && typeof item === 'object') {
112
+ const label = item.label || item.key || '';
113
+ const value = item.value == null ? '' : String(item.value);
114
+ const text = label ? `${label}: ${value}` : value;
115
+ line(mode.decoration ? mode.theme.status(item.status || 'muted', ` ${mode.theme.symbols.bullet} ${text}`) : `- ${text}`);
116
+ }
117
+ }
118
+ }
119
+
120
+ function nextSteps(steps = [], stepOptions = {}) {
121
+ if (mode.json || !Array.isArray(steps) || steps.length === 0) return;
122
+ section(stepOptions.title || 'Next steps');
123
+ for (const step of steps) {
124
+ line(mode.decoration ? mode.theme.status('command', ` ${mode.theme.symbols.bullet} ${step}`) : `- ${step}`);
125
+ }
71
126
  }
72
127
 
73
128
  async function withSpinner(message, task, spinnerOptions = {}) {
@@ -84,17 +139,49 @@ function createUx(options = {}) {
84
139
 
85
140
  const clack = await loadClack(options.prompts);
86
141
  const spinner = clack.spinner();
142
+ let stopped = false;
143
+ function stop(message, code) {
144
+ if (stopped) return;
145
+ stopped = true;
146
+ spinner.stop(message, code);
147
+ }
87
148
  spinner.start(message);
88
149
  try {
89
150
  const result = await task();
90
- spinner.stop(spinnerOptions.successMessage || message);
151
+ stop(spinnerOptions.successMessage || message);
91
152
  return result;
92
153
  } catch (error) {
93
- spinner.stop(spinnerOptions.failureMessage || `Failed: ${message}`, 1);
154
+ stop(spinnerOptions.failureMessage || `Failed: ${message}`, 1);
94
155
  throw error;
95
156
  }
96
157
  }
97
158
 
159
+ async function taskGroup(title, stages = []) {
160
+ heading(title);
161
+ const results = [];
162
+ for (const stage of stages) {
163
+ const run = typeof stage === 'function' ? stage : stage.run;
164
+ const message = typeof stage === 'function' ? stage.name || 'Running task' : stage.message;
165
+ const successMessage = stage.successMessage || message;
166
+ const useSpinner = stage.spinner === true;
167
+ if (typeof run !== 'function') {
168
+ throw new Error('create-quiver: taskGroup stage requires a run function.');
169
+ }
170
+ const result = useSpinner
171
+ ? await withSpinner(message, run, {
172
+ successMessage,
173
+ failureMessage: stage.failureMessage,
174
+ echo: stage.echo,
175
+ })
176
+ : await run();
177
+ if (!useSpinner) {
178
+ check(successMessage);
179
+ }
180
+ results.push(result);
181
+ }
182
+ return results;
183
+ }
184
+
98
185
  async function promptConfirm(message, promptOptions = {}) {
99
186
  if (!mode.usePrompts) {
100
187
  throw new Error('create-quiver: interactive confirmation requires an interactive TTY. Pass the equivalent flags or rerun with --interactive.');
@@ -114,11 +201,19 @@ function createUx(options = {}) {
114
201
  }
115
202
 
116
203
  return {
204
+ check,
205
+ error,
117
206
  heading,
207
+ info,
118
208
  line,
119
209
  mode,
210
+ nextSteps,
120
211
  promptConfirm,
212
+ section,
213
+ summary,
214
+ taskGroup,
121
215
  theme: mode.theme,
216
+ warning,
122
217
  withSpinner,
123
218
  writeStatus,
124
219
  };