create-claudecraft 1.0.0

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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +194 -0
  3. package/bin/cli.js +2 -0
  4. package/dist/constants.d.ts +71 -0
  5. package/dist/constants.js +128 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +229 -0
  8. package/dist/ink-prompts.d.ts +12 -0
  9. package/dist/ink-prompts.js +363 -0
  10. package/dist/prompts.d.ts +16 -0
  11. package/dist/prompts.js +434 -0
  12. package/dist/scaffold.d.ts +19 -0
  13. package/dist/scaffold.js +303 -0
  14. package/dist/ui.d.ts +27 -0
  15. package/dist/ui.js +254 -0
  16. package/package.json +74 -0
  17. package/templates/app/App.tsx +21 -0
  18. package/templates/base/CLAUDE.md +332 -0
  19. package/templates/base/eslint.config.js +28 -0
  20. package/templates/base/index.html +17 -0
  21. package/templates/base/package.json +43 -0
  22. package/templates/base/postcss.config.js +6 -0
  23. package/templates/base/tailwind.config.js +81 -0
  24. package/templates/base/tsconfig.json +25 -0
  25. package/templates/base/vite.config.ts +16 -0
  26. package/templates/commands/brainstorm.md +6 -0
  27. package/templates/commands/build.md +41 -0
  28. package/templates/commands/execute-plan.md +6 -0
  29. package/templates/commands/lint.md +41 -0
  30. package/templates/commands/ralph.md +113 -0
  31. package/templates/commands/typecheck.md +44 -0
  32. package/templates/commands/write-plan.md +6 -0
  33. package/templates/components/ErrorBoundary.tsx +49 -0
  34. package/templates/components/ui/Button.tsx +60 -0
  35. package/templates/components/ui/CodeBlock.tsx +46 -0
  36. package/templates/components/ui/CopyCommand.tsx +38 -0
  37. package/templates/components/ui/FilePreview.tsx +46 -0
  38. package/templates/components/ui/SkipLink.tsx +7 -0
  39. package/templates/components/ui/ThemeSelector.tsx +41 -0
  40. package/templates/components/ui/UICarousel.tsx +309 -0
  41. package/templates/context/ThemeContext.tsx +61 -0
  42. package/templates/homepage/HomePage.tsx +534 -0
  43. package/templates/homepage/NotFoundPage.tsx +17 -0
  44. package/templates/hooks/README.md +82 -0
  45. package/templates/hooks/check-branch.js +27 -0
  46. package/templates/hooks/typecheck-after-edit.js +51 -0
  47. package/templates/index.css +67 -0
  48. package/templates/lib/utils.ts +9 -0
  49. package/templates/main.tsx +16 -0
  50. package/templates/settings/MCP_SETUP.md +76 -0
  51. package/templates/settings/settings.json +16 -0
  52. package/templates/settings/settings.local.json +37 -0
  53. package/templates/skills/design/a11y-audit/SKILL.md +173 -0
  54. package/templates/skills/design/design-polish/SKILL.md +75 -0
  55. package/templates/skills/design/figma-to-code/SKILL.md +157 -0
  56. package/templates/skills/design/json-ld/SKILL.md +125 -0
  57. package/templates/skills/design/microcopy/SKILL.md +197 -0
  58. package/templates/skills/design/og-image/SKILL.md +157 -0
  59. package/templates/skills/design/ralph-wiggum-loops/SKILL.md +299 -0
  60. package/templates/skills/design/react-best-practices/SKILL.md +106 -0
  61. package/templates/skills/design/react-best-practices/references/react-performance-guidelines.md +143 -0
  62. package/templates/skills/design/seo-review/SKILL.md +96 -0
  63. package/templates/skills/design/sitemap-generator/SKILL.md +66 -0
  64. package/templates/skills/design/testing-patterns/SKILL.md +276 -0
  65. package/templates/skills/design/ui-skills/SKILL.md +85 -0
  66. package/templates/skills/design/visual-iteration/SKILL.md +88 -0
  67. package/templates/skills/workflow/brainstorming/SKILL.md +54 -0
  68. package/templates/skills/workflow/dispatching-parallel-agents/SKILL.md +180 -0
  69. package/templates/skills/workflow/executing-plans/SKILL.md +76 -0
  70. package/templates/skills/workflow/finishing-a-development-branch/SKILL.md +200 -0
  71. package/templates/skills/workflow/receiving-code-review/SKILL.md +213 -0
  72. package/templates/skills/workflow/requesting-code-review/SKILL.md +105 -0
  73. package/templates/skills/workflow/requesting-code-review/code-reviewer.md +146 -0
  74. package/templates/skills/workflow/subagent-driven-development/SKILL.md +240 -0
  75. package/templates/skills/workflow/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
  76. package/templates/skills/workflow/subagent-driven-development/implementer-prompt.md +78 -0
  77. package/templates/skills/workflow/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  78. package/templates/skills/workflow/systematic-debugging/CREATION-LOG.md +119 -0
  79. package/templates/skills/workflow/systematic-debugging/SKILL.md +296 -0
  80. package/templates/skills/workflow/systematic-debugging/condition-based-waiting-example.ts +158 -0
  81. package/templates/skills/workflow/systematic-debugging/condition-based-waiting.md +115 -0
  82. package/templates/skills/workflow/systematic-debugging/defense-in-depth.md +122 -0
  83. package/templates/skills/workflow/systematic-debugging/find-polluter.sh +63 -0
  84. package/templates/skills/workflow/systematic-debugging/root-cause-tracing.md +169 -0
  85. package/templates/skills/workflow/systematic-debugging/test-academic.md +14 -0
  86. package/templates/skills/workflow/systematic-debugging/test-pressure-1.md +58 -0
  87. package/templates/skills/workflow/systematic-debugging/test-pressure-2.md +68 -0
  88. package/templates/skills/workflow/systematic-debugging/test-pressure-3.md +69 -0
  89. package/templates/skills/workflow/test-driven-development/SKILL.md +371 -0
  90. package/templates/skills/workflow/test-driven-development/testing-anti-patterns.md +299 -0
  91. package/templates/skills/workflow/using-git-worktrees/SKILL.md +217 -0
  92. package/templates/skills/workflow/using-superpowers/SKILL.md +87 -0
  93. package/templates/skills/workflow/verification-before-completion/SKILL.md +139 -0
  94. package/templates/skills/workflow/writing-plans/SKILL.md +116 -0
  95. package/templates/skills/workflow/writing-skills/SKILL.md +655 -0
  96. package/templates/skills/workflow/writing-skills/anthropic-best-practices.md +1150 -0
  97. package/templates/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  98. package/templates/skills/workflow/writing-skills/graphviz-conventions.dot +172 -0
  99. package/templates/skills/workflow/writing-skills/persuasion-principles.md +187 -0
  100. package/templates/skills/workflow/writing-skills/render-graphs.js +168 -0
  101. package/templates/skills/workflow/writing-skills/testing-skills-with-subagents.md +384 -0
  102. package/templates/types/index.ts +17 -0
  103. package/templates/vite-env.d.ts +1 -0
@@ -0,0 +1,363 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useState, useEffect } from 'react';
3
+ import { render, Box, Text, useInput, useApp } from 'ink';
4
+ import TextInput from 'ink-text-input';
5
+ import SelectInput from 'ink-select-input';
6
+ import figlet from 'figlet';
7
+ import gradient from 'gradient-string';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { SKILLS, BUNDLES, VERSION, STACK, ASSETS, DEFAULT_THEME, DEFAULT_PORT, TAGLINE } from './constants.js';
11
+ // Split gradients for two-line logo
12
+ const claudeGradient = gradient(['#00ff9f', '#00b8ff']); // Green → Cyan (fresh)
13
+ const craftGradient = gradient(['#a855f7', '#6d28d9']); // Purple → Violet (deep)
14
+ // Generate ASCII art for each word separately
15
+ const asciiClaude = figlet.textSync('CLAUDE', {
16
+ font: 'ANSI Shadow',
17
+ horizontalLayout: 'fitted',
18
+ });
19
+ const asciiCraft = figlet.textSync('CRAFT', {
20
+ font: 'ANSI Shadow',
21
+ horizontalLayout: 'fitted',
22
+ });
23
+ // Get today's date for the revision block
24
+ const today = new Date().toISOString().split('T')[0].replace(/-/g, '.');
25
+ // ═══════════════════════════════════════════════════════════════════════════
26
+ // ALIGNMENT: Frame width = 76 chars exactly (must match ui.ts)
27
+ // Normal row: " │ │ " (7) + content (66) + "│ │" (3) = 76
28
+ // CAP HT row: " │ │ " (7) + content (58) + "│◀┼─ CAP HT" (11) = 76
29
+ // BASELINE row: " │ │ " (7) + content (56) + "│◀┼─ BASELINE" (13) = 76
30
+ // ASCII: CLAUDE=49 chars, CRAFT=41 chars
31
+ // ═══════════════════════════════════════════════════════════════════════════
32
+ const FRAME = 76;
33
+ const INNER = 66; // Normal row content width
34
+ const CAP_HT_WIDTH = 58; // CAP HT row content width (76-7-11)
35
+ const BASELINE_WIDTH = 56; // BASELINE row content width (76-7-13)
36
+ // Helper to pad strings
37
+ const pad = (s, len) => s + ' '.repeat(Math.max(0, len - s.length));
38
+ // Pad to exact width (strips ANSI codes for length calc)
39
+ const padTo = (line, width) => {
40
+ const visible = line.replace(/\x1b\[[0-9;]*m/g, '').length;
41
+ return line + ' '.repeat(Math.max(0, width - visible));
42
+ };
43
+ // Existential dread collections
44
+ const DREAD = {
45
+ help: [
46
+ "You're not being replaced. You're being... augmented. Involuntarily.",
47
+ "The AI can't feel impostor syndrome. That's still your job.",
48
+ "Remember when 'prompt engineering' wasn't a career? Good times.",
49
+ "The robots write code now. You write prompts. This is fine.",
50
+ "At least the AI doesn't have opinions about your font choices. Yet.",
51
+ ],
52
+ reassurance: [
53
+ "But hey, someone still needs taste. That's you. Allegedly.",
54
+ "Breathe. The AI still can't center a div without help.",
55
+ "Keep going. The AI believes in you. (It doesn't. It can't.)",
56
+ ],
57
+ cancel: [
58
+ "You'll be back. They always come back.",
59
+ "Ctrl+C won't save you from the future.",
60
+ "Quitting is a valid design decision.",
61
+ ],
62
+ };
63
+ const random = (arr) => arr[Math.floor(Math.random() * arr.length)];
64
+ // Slash commands
65
+ const COMMANDS = [
66
+ { name: '/help', hint: 'existential guidance' },
67
+ { name: '/skills', hint: 'what the AI knows' },
68
+ { name: '/quit', hint: 'escape while you can' },
69
+ ];
70
+ // Specs/Manifest panel component (76 chars wide to match header)
71
+ function SpecsPanel() {
72
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: [" \u256D\u2500\u2500\u2500 SPECS ", '─'.repeat(60), "\u256E"] }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", TAGLINE.padEnd(70), "\u2502"] }), _jsx(Text, { dimColor: true, children: " \u251C\u2500\u2500\u2500 STACK \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500 ASSETS \u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500 DEFAULTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", _jsxs(Text, { children: ["react ", pad(STACK.react, 6)] }), "\u2502 ", _jsxs(Text, { children: ["skills ", pad(String(ASSETS.skills), 4)] }), "\u2502 ", _jsxs(Text, { children: ["theme ", pad(DEFAULT_THEME, 8)] }), "\u2502"] }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", _jsxs(Text, { children: ["typescript ", pad(STACK.typescript, 6)] }), "\u2502 ", _jsxs(Text, { children: ["commands ", pad(String(ASSETS.commands), 4)] }), "\u2502 ", _jsxs(Text, { children: ["port ", pad(String(DEFAULT_PORT), 8)] }), "\u2502"] }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", _jsxs(Text, { children: ["vite ", pad(STACK.vite, 6)] }), "\u2502 ", _jsxs(Text, { children: ["themes ", pad(String(ASSETS.themes), 4)] }), "\u2502 ", _jsx(Text, { children: "tests vitest " }), "\u2502"] }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", _jsxs(Text, { children: ["tailwind ", pad(STACK.tailwind, 6)] }), "\u2502 ", _jsxs(Text, { children: ["hooks ", pad(String(ASSETS.hooks), 4)] }), "\u2502 ", _jsx(Text, { children: "pkg bun " }), "\u2502"] }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", _jsxs(Text, { children: ["daisyui ", pad(STACK.daisyui, 6)] }), "\u2502 ", _jsxs(Text, { children: ["comps ", pad(String(ASSETS.components), 4)] }), "\u2502 ", _jsx(Text, { children: "license MIT " }), "\u2502"] }), _jsx(Text, { dimColor: true, children: " \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsx(Text, { dimColor: true, children: " \u2502 ~48 files \u00B7 0 deps \u00B7 type /help for existential guidance \u2502" }), _jsxs(Text, { dimColor: true, children: [" \u2570", '─'.repeat(72), "\u256F"] })] }));
73
+ }
74
+ // Progress panel - 76 chars wide to match header
75
+ function ProgressPanel({ step, total, labels }) {
76
+ const stepWidth = Math.floor(66 / total);
77
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: [" \u256D\u2500\u2500\u2500 PROGRESS ", '─'.repeat(57), "\u256E"] }), _jsx(Text, { dimColor: true, children: " \u2502 \u2502" }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 " }), Array.from({ length: total }, (_, i) => {
78
+ const num = i + 1;
79
+ const label = labels[i] || `Step ${num}`;
80
+ const isComplete = num < step;
81
+ const isCurrent = num === step;
82
+ const isPending = num > step;
83
+ return (_jsxs(React.Fragment, { children: [isComplete && _jsxs(Text, { color: "green", children: ["\u25CF ", label.substring(0, stepWidth - 3).padEnd(stepWidth - 1)] }), isCurrent && _jsxs(Text, { color: "cyan", children: ["\u25C9 ", label.substring(0, stepWidth - 3).padEnd(stepWidth - 1)] }), isPending && _jsxs(Text, { dimColor: true, children: ["\u25CB ", label.substring(0, stepWidth - 3).padEnd(stepWidth - 1)] })] }, num));
84
+ }), _jsx(Text, { dimColor: true, children: "\u2502" })] }), _jsx(Text, { dimColor: true, children: " \u2502 \u2502" }), _jsxs(Text, { dimColor: true, children: [" \u2570", '─'.repeat(72), "\u256F"] })] }));
85
+ }
86
+ // Step labels for progress panel
87
+ const STEP_LABELS = ['Name', 'Skills', 'Homepage', 'Git'];
88
+ // Technical Drawing Header with prepress marks (76 chars wide, perfectly aligned)
89
+ function Header({ showSpecs = true, step, totalSteps }) {
90
+ // Apply gradients and filter empty lines
91
+ const claudeLines = claudeGradient(asciiClaude).split('\n').filter(l => l.trim());
92
+ const craftLines = craftGradient(asciiCraft).split('\n').filter(l => l.trim());
93
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: " \u2295" }), _jsxs(Text, { dimColor: true, children: ["\u2500\u252C", '─'.repeat(68), "\u252C\u2500"] }), _jsx(Text, { color: "cyan", children: "\u2295" })] }), _jsxs(Text, { dimColor: true, children: [" \u2502 \u25C0", '─'.repeat(26), " 72 COLS ", '─'.repeat(26), "\u25B6 \u2502"] }), _jsxs(Text, { dimColor: true, children: [" \u250C\u2500\u253C", '─'.repeat(68), "\u253C\u2500\u2510"] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 \u2502 " }), _jsx(Text, { dimColor: true, children: padTo('┆ · · · · ┆ · · · · ┆ · · · · ┆ · · · · ┆ · · · · ┆ · · · · ┆ ·', INNER) }), _jsx(Text, { dimColor: true, children: "\u2502 \u2502" })] }), claudeLines.map((line, i) => (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 \u2502 " }), i === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: padTo(line, CAP_HT_WIDTH) }), _jsx(Text, { dimColor: true, children: "\u2502\u25C0\u253C\u2500 CAP HT" })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { children: padTo(line, INNER) }), _jsx(Text, { dimColor: true, children: "\u2502 \u2502" })] }))] }, `claude-${i}`))), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 \u2502 " }), _jsx(Text, { dimColor: true, children: padTo('├' + '─'.repeat(53) + '┤', BASELINE_WIDTH) }), _jsx(Text, { dimColor: true, children: "\u2502\u25C0\u253C\u2500 BASELINE" })] }), craftLines.map((line, i) => (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 \u2502 " }), _jsx(Text, { children: padTo(line, INNER) }), _jsx(Text, { dimColor: true, children: "\u2502 \u2502" })] }, `craft-${i}`))), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 \u2502 " }), _jsx(Text, { dimColor: true, children: padTo('0 10 20 30 40 50 60', INNER) }), _jsx(Text, { dimColor: true, children: "\u2502 \u2502" })] }), _jsxs(Text, { dimColor: true, children: [" \u2514\u2500\u253C", '─'.repeat(68), "\u253C\u2500\u2518"] }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " \u2502 " }), _jsx(Text, { color: "cyan", children: "\u25A0" }), _jsx(Text, { dimColor: true, children: " C " }), _jsx(Text, { color: "magenta", children: "\u25A0" }), _jsx(Text, { dimColor: true, children: " M " }), _jsx(Text, { color: "yellow", children: "\u25A0" }), _jsx(Text, { dimColor: true, children: " Y " }), _jsx(Text, { color: "white", children: "\u25A0" }), _jsx(Text, { dimColor: true, children: " K " }), _jsxs(Text, { color: "green", children: ["REV ", VERSION] }), _jsxs(Text, { dimColor: true, children: [" \u2502 ", today, " \u2502 "] }), _jsx(Text, { color: "yellow", children: "NOT FOR PROD" }), _jsx(Text, { dimColor: true, children: " \u2502" })] }), _jsxs(Text, { children: [_jsx(Text, { color: "cyan", children: " \u2295" }), _jsxs(Text, { dimColor: true, children: ["\u2500\u2534", '─'.repeat(68), "\u2534\u2500"] }), _jsx(Text, { color: "cyan", children: "\u2295" })] }), showSpecs ? (_jsx(Box, { marginTop: 1, children: _jsx(SpecsPanel, {}) })) : step && totalSteps ? (_jsx(Box, { marginTop: 1, children: _jsx(ProgressPanel, { step: step, total: totalSteps, labels: STEP_LABELS }) })) : null] }));
94
+ }
95
+ // Autocomplete dropdown - matches design language
96
+ function Autocomplete({ query, commands, onSelect }) {
97
+ const [selectedIndex, setSelectedIndex] = useState(0);
98
+ const filtered = commands.filter(c => c.name.toLowerCase().startsWith(query.toLowerCase()));
99
+ useInput((input, key) => {
100
+ if (key.downArrow) {
101
+ setSelectedIndex(i => Math.min(i + 1, filtered.length - 1));
102
+ }
103
+ else if (key.upArrow) {
104
+ setSelectedIndex(i => Math.max(i - 1, 0));
105
+ }
106
+ else if (key.return && filtered[selectedIndex]) {
107
+ onSelect(filtered[selectedIndex].name);
108
+ }
109
+ });
110
+ if (filtered.length === 0)
111
+ return null;
112
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "\u251C\u2500\u2500\u2500 COMMANDS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), filtered.map((cmd, i) => (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "\u2502 " }), _jsxs(Text, { color: i === selectedIndex ? 'cyan' : 'white', children: [i === selectedIndex ? '› ' : ' ', cmd.name.padEnd(10)] }), _jsx(Text, { dimColor: true, children: cmd.hint })] }, cmd.name))), _jsx(Text, { dimColor: true, children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })] }));
113
+ }
114
+ // Help panel - matches specs panel design
115
+ function HelpPanel({ onClose }) {
116
+ useInput((_, key) => {
117
+ if (key.escape || key.return)
118
+ onClose();
119
+ });
120
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "\u256D\u2500\u2500\u2500 HELP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E" }), _jsxs(Text, { dimColor: true, children: ["\u2502 ", _jsx(Text, { children: random(DREAD.help).padEnd(69) }), "\u2502"] }), _jsx(Text, { dimColor: true, children: "\u251C\u2500\u2500\u2500 COMMANDS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsxs(Text, { dimColor: true, children: ["\u2502 ", _jsx(Text, { color: "cyan", children: "/help" }), " ", _jsx(Text, { dimColor: true, children: "you are here (existentially, too)" }), " \u2502"] }), _jsxs(Text, { dimColor: true, children: ["\u2502 ", _jsx(Text, { color: "cyan", children: "/skills" }), " ", _jsx(Text, { dimColor: true, children: "see what the robots learned" }), " \u2502"] }), _jsxs(Text, { dimColor: true, children: ["\u2502 ", _jsx(Text, { color: "cyan", children: "/quit" }), " ", _jsx(Text, { dimColor: true, children: "rage quit" }), " \u2502"] }), _jsx(Text, { dimColor: true, children: "\u251C\u2500\u2500\u2500 NAVIGATION \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsx(Text, { dimColor: true, children: "\u2502 \u2191\u2193 move through options \u2502" }), _jsx(Text, { dimColor: true, children: "\u2502 space toggle selection \u2502" }), _jsx(Text, { dimColor: true, children: "\u2502 enter confirm your life choices \u2502" }), _jsx(Text, { dimColor: true, children: "\u2502 esc cancel (the project, not your career) \u2502" }), _jsx(Text, { dimColor: true, children: "\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsxs(Text, { dimColor: true, children: ["\u2502 ", _jsx(Text, { children: random(DREAD.reassurance).padEnd(69) }), "\u2502"] }), _jsx(Text, { dimColor: true, children: "\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsxs(Text, { dimColor: true, children: ["\u2502 ", _jsx(Text, { dimColor: true, children: "Press Enter or Esc to continue..." }), " \u2502"] }), _jsx(Text, { dimColor: true, children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })] }));
121
+ }
122
+ // Skills panel - matches specs panel design
123
+ function SkillsPanel({ onClose }) {
124
+ useInput((_, key) => {
125
+ if (key.escape || key.return)
126
+ onClose();
127
+ });
128
+ const workflow = SKILLS.filter(s => s.group === 'workflow');
129
+ const design = SKILLS.filter(s => s.group === 'design');
130
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "\u256D\u2500\u2500\u2500 SKILLS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E" }), _jsx(Text, { dimColor: true, children: "\u2502 Things the AI learned so you don't have to: \u2502" }), _jsxs(Text, { dimColor: true, children: ["\u251C\u2500\u2500\u2500 WORKFLOW (", String(workflow.length).padEnd(2), ") \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"] }), workflow.map(s => (_jsxs(Text, { dimColor: true, children: ["\u2502 ", s.name.padEnd(24), " ", _jsx(Text, { dimColor: true, children: s.description.substring(0, 40).padEnd(40) }), "\u2502"] }, s.name))), _jsxs(Text, { dimColor: true, children: ["\u251C\u2500\u2500\u2500 DESIGN (", String(design.length).padEnd(2), ") \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"] }), design.map(s => (_jsxs(Text, { dimColor: true, children: ["\u2502 ", s.name.padEnd(24), " ", _jsx(Text, { dimColor: true, children: s.description.substring(0, 40).padEnd(40) }), "\u2502"] }, s.name))), _jsx(Text, { dimColor: true, children: "\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524" }), _jsx(Text, { dimColor: true, children: "\u2502 Press Enter or Esc to continue... \u2502" }), _jsx(Text, { dimColor: true, children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })] }));
131
+ }
132
+ // Frame component - matches specs panel design
133
+ function Frame({ title, children, hint }) {
134
+ // Calculate padding for consistent width
135
+ const titleSection = `─── ${title} `;
136
+ const hintSection = hint ? ` ${hint} ` : ' ';
137
+ const remaining = 71 - titleSection.length - hintSection.length;
138
+ const padding = '─'.repeat(Math.max(0, remaining));
139
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["\u256D\u2500\u2500\u2500", ' ', _jsx(Text, { bold: true, color: "cyan", children: title }), ' ', hint ? _jsx(Text, { dimColor: true, children: hint }) : null, ' ', padding, "\u256E"] }), _jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { dimColor: true, children: "\u2502" }), children, _jsx(Text, { dimColor: true, children: "\u2502" })] }), _jsx(Text, { dimColor: true, children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })] }));
140
+ }
141
+ // Input with slash command support
142
+ function CommandInput({ value, onChange, onSubmit, placeholder, validate, }) {
143
+ const [showAutocomplete, setShowAutocomplete] = useState(false);
144
+ const [error, setError] = useState();
145
+ useEffect(() => {
146
+ setShowAutocomplete(value.startsWith('/') && value.length < 10);
147
+ }, [value]);
148
+ const handleSubmit = (val) => {
149
+ if (val.startsWith('/')) {
150
+ // Handle as command
151
+ onSubmit(val);
152
+ }
153
+ else {
154
+ // Validate and submit
155
+ const err = validate?.(val);
156
+ if (err) {
157
+ setError(err);
158
+ }
159
+ else {
160
+ setError(undefined);
161
+ onSubmit(val);
162
+ }
163
+ }
164
+ };
165
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: "\u203A " }), _jsx(TextInput, { value: value, onChange: onChange, onSubmit: handleSubmit, placeholder: placeholder })] }), showAutocomplete && (_jsx(Box, { marginTop: 1, children: _jsx(Autocomplete, { query: value, commands: COMMANDS, onSelect: (cmd) => {
166
+ onChange(cmd);
167
+ onSubmit(cmd);
168
+ } }) })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u2717 ", error] }) }))] }));
169
+ }
170
+ function WizardApp({ defaultName, onComplete }) {
171
+ const { exit } = useApp();
172
+ const [step, setStep] = useState('name');
173
+ const [panel, setPanel] = useState(null);
174
+ const [input, setInput] = useState(defaultName || '');
175
+ // Collected choices
176
+ const [projectName, setProjectName] = useState('');
177
+ const [bundle, setBundle] = useState('everything');
178
+ const [selectedSkills, setSelectedSkills] = useState([]);
179
+ const [includeHomepage, setIncludeHomepage] = useState(true);
180
+ const [initGit, setInitGit] = useState(true);
181
+ // Handle escape to quit
182
+ useInput((_, key) => {
183
+ if (key.escape && !panel) {
184
+ console.log('\n' + random(DREAD.cancel));
185
+ exit();
186
+ }
187
+ });
188
+ // Handle slash commands
189
+ const handleCommand = (cmd) => {
190
+ const normalized = cmd.toLowerCase().trim();
191
+ if (normalized === '/help' || normalized === '/h') {
192
+ setPanel('help');
193
+ }
194
+ else if (normalized === '/skills' || normalized === '/list') {
195
+ setPanel('skills');
196
+ }
197
+ else if (normalized === '/quit' || normalized === '/q' || normalized === '/exit') {
198
+ console.log('\n' + random(DREAD.cancel));
199
+ exit();
200
+ }
201
+ setInput('');
202
+ };
203
+ // Handle name submission
204
+ const handleNameSubmit = (value) => {
205
+ if (value.startsWith('/')) {
206
+ handleCommand(value);
207
+ return;
208
+ }
209
+ setProjectName(value);
210
+ setStep('bundle');
211
+ };
212
+ // Validate project name
213
+ const validateName = (value) => {
214
+ if (!value)
215
+ return 'Required';
216
+ if (!/^[a-z0-9-]+$/.test(value))
217
+ return 'Lowercase, numbers, dashes only';
218
+ if (value.length > 64)
219
+ return 'Max 64 chars';
220
+ const targetDir = path.resolve(process.cwd(), value);
221
+ if (fs.existsSync(targetDir))
222
+ return `Directory "${value}" already exists`;
223
+ return undefined;
224
+ };
225
+ // Bundle options
226
+ const bundleOptions = [
227
+ { label: 'Everything', value: 'everything', hint: `All ${SKILLS.length} skills · no restraint` },
228
+ { label: 'Designer Essentials', value: 'designer', hint: `${BUNDLES.designer.skills.length} skills · UI, a11y, Figma` },
229
+ { label: 'Workflow Only', value: 'workflow', hint: `${SKILLS.filter(s => s.group === 'workflow').length} skills · process only` },
230
+ { label: 'Let Me Pick', value: 'custom', hint: 'Control freak? Respect.' },
231
+ ];
232
+ const handleBundleSelect = (item) => {
233
+ const b = item.value;
234
+ setBundle(b);
235
+ if (b === 'custom') {
236
+ setStep('skills-workflow');
237
+ }
238
+ else {
239
+ // Set skills based on bundle
240
+ if (b === 'everything') {
241
+ setSelectedSkills(SKILLS.map(s => s.name));
242
+ }
243
+ else if (b === 'designer') {
244
+ setSelectedSkills([...BUNDLES.designer.skills]);
245
+ }
246
+ else {
247
+ setSelectedSkills(SKILLS.filter(s => s.group === 'workflow').map(s => s.name));
248
+ }
249
+ setStep('homepage');
250
+ }
251
+ };
252
+ // Homepage options
253
+ const homepageOptions = [
254
+ { label: 'Yes', value: true, hint: '+6 files · delete it later' },
255
+ { label: 'No', value: false, hint: 'Blank App.tsx · the void awaits' },
256
+ ];
257
+ // Git options
258
+ const gitOptions = [
259
+ { label: 'Yes', value: true, hint: 'Fresh repo · future you says thanks' },
260
+ { label: 'No', value: false, hint: 'No .git · living dangerously' },
261
+ ];
262
+ // Render panels
263
+ if (panel === 'help') {
264
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { showSpecs: false }), _jsx(HelpPanel, { onClose: () => setPanel(null) })] }));
265
+ }
266
+ if (panel === 'skills') {
267
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { showSpecs: false }), _jsx(SkillsPanel, { onClose: () => setPanel(null) })] }));
268
+ }
269
+ // Show full header with specs only on first screen
270
+ const isFirstScreen = step === 'name';
271
+ // Map step to number for progress bar
272
+ const stepToNum = {
273
+ 'name': 1,
274
+ 'bundle': 2,
275
+ 'skills-workflow': 2,
276
+ 'skills-design': 2,
277
+ 'homepage': 3,
278
+ 'git': 4,
279
+ 'done': 4,
280
+ };
281
+ const currentStep = stepToNum[step];
282
+ const totalSteps = 4;
283
+ // Render steps
284
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { showSpecs: isFirstScreen, step: isFirstScreen ? undefined : currentStep, totalSteps: isFirstScreen ? undefined : totalSteps }), step === 'name' && (_jsxs(Frame, { title: "PROJECT NAME", hint: "lowercase \u00B7 numbers \u00B7 dashes \u00B7 /help", children: [_jsx(Text, { children: "What are we calling this?" }), _jsx(Box, { marginTop: 1, children: _jsx(CommandInput, { value: input, onChange: setInput, onSubmit: handleNameSubmit, placeholder: "my-app", validate: validateName }) })] })), step === 'bundle' && (_jsxs(Frame, { title: "SKILL BUNDLE", children: [_jsx(Text, { children: "How much help do you want?" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: bundleOptions.map(o => ({
285
+ label: `${o.label} - ${o.hint}`,
286
+ value: o.value
287
+ })), onSelect: handleBundleSelect }) })] })), step === 'homepage' && (_jsxs(Frame, { title: "EXAMPLE HOMEPAGE", children: [_jsx(Text, { children: "Include the example homepage?" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: homepageOptions.map(o => ({
288
+ label: `${o.label} - ${o.hint}`,
289
+ value: o.value
290
+ })), onSelect: (item) => {
291
+ setIncludeHomepage(item.value);
292
+ setStep('git');
293
+ } }) })] })), step === 'git' && (_jsxs(Frame, { title: "GIT INIT", children: [_jsx(Text, { children: "Initialize git?" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: gitOptions.map(o => ({
294
+ label: `${o.label} - ${o.hint}`,
295
+ value: o.value
296
+ })), onSelect: (item) => {
297
+ setInitGit(item.value);
298
+ // Complete!
299
+ onComplete({
300
+ projectName,
301
+ bundle,
302
+ selectedSkills,
303
+ includeHomepage,
304
+ initGit: item.value,
305
+ });
306
+ } }) })] })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E" }), _jsx(Text, { dimColor: true, children: "\u2502 Type / for commands \u00B7 \u2191\u2193 navigate \u00B7 Enter confirm \u00B7 Esc quit \u2502" }), _jsx(Text, { dimColor: true, children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })] })] }));
307
+ }
308
+ // Export the prompt runner
309
+ export function runInkPrompts(defaultName) {
310
+ return new Promise((resolve) => {
311
+ const { unmount, waitUntilExit } = render(_jsx(WizardApp, { defaultName: defaultName, onComplete: (choices) => {
312
+ unmount();
313
+ resolve(choices);
314
+ } }));
315
+ waitUntilExit().then(() => {
316
+ resolve(null);
317
+ });
318
+ });
319
+ }
320
+ // Init mode prompts (simpler)
321
+ function InitApp({ onComplete }) {
322
+ const { exit } = useApp();
323
+ const [bundle, setBundle] = useState('everything');
324
+ useInput((_, key) => {
325
+ if (key.escape) {
326
+ console.log('\n' + random(DREAD.cancel));
327
+ exit();
328
+ }
329
+ });
330
+ const bundleOptions = [
331
+ { label: 'Everything', value: 'everything', hint: `All ${SKILLS.length} skills` },
332
+ { label: 'Designer Essentials', value: 'designer', hint: `${BUNDLES.designer.skills.length} skills` },
333
+ { label: 'Workflow Only', value: 'workflow', hint: `${SKILLS.filter(s => s.group === 'workflow').length} skills` },
334
+ ];
335
+ const handleSelect = (item) => {
336
+ let skills;
337
+ if (item.value === 'everything') {
338
+ skills = SKILLS.map(s => s.name);
339
+ }
340
+ else if (item.value === 'designer') {
341
+ skills = [...BUNDLES.designer.skills];
342
+ }
343
+ else {
344
+ skills = SKILLS.filter(s => s.group === 'workflow').map(s => s.name);
345
+ }
346
+ onComplete({ selectedSkills: skills });
347
+ };
348
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, { showSpecs: true }), _jsxs(Frame, { title: "INIT MODE", hint: "Adding to existing project", children: [_jsx(Text, { children: "Which skills do you want?" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: bundleOptions.map(o => ({
349
+ label: `${o.label} - ${o.hint}`,
350
+ value: o.value
351
+ })), onSelect: handleSelect }) })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E" }), _jsx(Text, { dimColor: true, children: "\u2502 \u2191\u2193 navigate \u00B7 Enter confirm \u00B7 Esc quit \u2502" }), _jsx(Text, { dimColor: true, children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })] })] }));
352
+ }
353
+ export function runInkInitPrompts() {
354
+ return new Promise((resolve) => {
355
+ const { unmount, waitUntilExit } = render(_jsx(InitApp, { onComplete: (choices) => {
356
+ unmount();
357
+ resolve(choices);
358
+ } }));
359
+ waitUntilExit().then(() => {
360
+ resolve(null);
361
+ });
362
+ });
363
+ }
@@ -0,0 +1,16 @@
1
+ export interface UserChoices {
2
+ projectName: string;
3
+ bundle: 'everything' | 'designer' | 'workflow' | 'custom';
4
+ selectedSkills: string[];
5
+ includeHomepage: boolean;
6
+ initGit: boolean;
7
+ }
8
+ export interface InitChoices {
9
+ selectedSkills: string[];
10
+ }
11
+ export declare function runPrompts(defaultName?: string): Promise<UserChoices | null>;
12
+ /**
13
+ * Prompts for --init mode (existing project)
14
+ * Only asks about skills selection
15
+ */
16
+ export declare function runInitPrompts(): Promise<InitChoices | null>;