wiggum-cli 0.7.8 → 0.8.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 (72) hide show
  1. package/dist/tui/app.d.ts +98 -0
  2. package/dist/tui/app.d.ts.map +1 -0
  3. package/dist/tui/app.js +70 -0
  4. package/dist/tui/app.js.map +1 -0
  5. package/dist/tui/components/ChatInput.d.ts +40 -0
  6. package/dist/tui/components/ChatInput.d.ts.map +1 -0
  7. package/dist/tui/components/ChatInput.js +61 -0
  8. package/dist/tui/components/ChatInput.js.map +1 -0
  9. package/dist/tui/components/MessageList.d.ts +79 -0
  10. package/dist/tui/components/MessageList.d.ts.map +1 -0
  11. package/dist/tui/components/MessageList.js +68 -0
  12. package/dist/tui/components/MessageList.js.map +1 -0
  13. package/dist/tui/components/PhaseHeader.d.ts +36 -0
  14. package/dist/tui/components/PhaseHeader.d.ts.map +1 -0
  15. package/dist/tui/components/PhaseHeader.js +31 -0
  16. package/dist/tui/components/PhaseHeader.js.map +1 -0
  17. package/dist/tui/components/StreamingText.d.ts +47 -0
  18. package/dist/tui/components/StreamingText.d.ts.map +1 -0
  19. package/dist/tui/components/StreamingText.js +38 -0
  20. package/dist/tui/components/StreamingText.js.map +1 -0
  21. package/dist/tui/components/ToolCallCard.d.ts +65 -0
  22. package/dist/tui/components/ToolCallCard.d.ts.map +1 -0
  23. package/dist/tui/components/ToolCallCard.js +100 -0
  24. package/dist/tui/components/ToolCallCard.js.map +1 -0
  25. package/dist/tui/components/WorkingIndicator.d.ts +45 -0
  26. package/dist/tui/components/WorkingIndicator.d.ts.map +1 -0
  27. package/dist/tui/components/WorkingIndicator.js +31 -0
  28. package/dist/tui/components/WorkingIndicator.js.map +1 -0
  29. package/dist/tui/components/index.d.ts +16 -0
  30. package/dist/tui/components/index.d.ts.map +1 -0
  31. package/dist/tui/components/index.js +10 -0
  32. package/dist/tui/components/index.js.map +1 -0
  33. package/dist/tui/hooks/index.d.ts +7 -0
  34. package/dist/tui/hooks/index.d.ts.map +1 -0
  35. package/dist/tui/hooks/index.js +6 -0
  36. package/dist/tui/hooks/index.js.map +1 -0
  37. package/dist/tui/hooks/useSpecGenerator.d.ts +168 -0
  38. package/dist/tui/hooks/useSpecGenerator.d.ts.map +1 -0
  39. package/dist/tui/hooks/useSpecGenerator.js +405 -0
  40. package/dist/tui/hooks/useSpecGenerator.js.map +1 -0
  41. package/dist/tui/index.d.ts +14 -0
  42. package/dist/tui/index.d.ts.map +1 -0
  43. package/dist/tui/index.js +18 -0
  44. package/dist/tui/index.js.map +1 -0
  45. package/dist/tui/screens/InterviewScreen.d.ts +55 -0
  46. package/dist/tui/screens/InterviewScreen.d.ts.map +1 -0
  47. package/dist/tui/screens/InterviewScreen.js +84 -0
  48. package/dist/tui/screens/InterviewScreen.js.map +1 -0
  49. package/dist/tui/screens/index.d.ts +6 -0
  50. package/dist/tui/screens/index.d.ts.map +1 -0
  51. package/dist/tui/screens/index.js +5 -0
  52. package/dist/tui/screens/index.js.map +1 -0
  53. package/dist/tui/theme.d.ts +62 -0
  54. package/dist/tui/theme.d.ts.map +1 -0
  55. package/dist/tui/theme.js +58 -0
  56. package/dist/tui/theme.js.map +1 -0
  57. package/package.json +6 -1
  58. package/src/tui/app.tsx +138 -0
  59. package/src/tui/components/ChatInput.tsx +105 -0
  60. package/src/tui/components/MessageList.tsx +186 -0
  61. package/src/tui/components/PhaseHeader.tsx +63 -0
  62. package/src/tui/components/StreamingText.tsx +69 -0
  63. package/src/tui/components/ToolCallCard.tsx +215 -0
  64. package/src/tui/components/WorkingIndicator.tsx +72 -0
  65. package/src/tui/components/index.ts +21 -0
  66. package/src/tui/hooks/index.ts +13 -0
  67. package/src/tui/hooks/useSpecGenerator.ts +589 -0
  68. package/src/tui/index.ts +23 -0
  69. package/src/tui/screens/InterviewScreen.tsx +164 -0
  70. package/src/tui/screens/index.ts +6 -0
  71. package/src/tui/theme.ts +72 -0
  72. package/tsconfig.json +2 -1
@@ -0,0 +1,69 @@
1
+ /**
2
+ * StreamingText - Renders AI response text with optional cursor
3
+ *
4
+ * Displays text as it streams in from the AI. The parent component
5
+ * is responsible for accumulating text chunks and passing them via
6
+ * the `text` prop. This component simply renders what it receives,
7
+ * optionally showing a cursor when streaming is in progress.
8
+ */
9
+
10
+ import React from 'react';
11
+ import { Text } from 'ink';
12
+ import { colors } from '../theme.js';
13
+
14
+ /**
15
+ * Block cursor character (U+2588 - Full Block)
16
+ */
17
+ const CURSOR_CHAR = '\u2588';
18
+
19
+ /**
20
+ * Props for the StreamingText component
21
+ */
22
+ export interface StreamingTextProps {
23
+ /** The accumulated text to display */
24
+ text: string;
25
+ /** Whether streaming is still in progress */
26
+ isStreaming: boolean;
27
+ /** Optional text color (defaults to white) */
28
+ color?: string;
29
+ /** Whether to show cursor when streaming (defaults to true) */
30
+ showCursor?: boolean;
31
+ }
32
+
33
+ /**
34
+ * StreamingText component
35
+ *
36
+ * Renders text with an optional cursor indicator when streaming.
37
+ * The cursor appears at the end of the text while `isStreaming` is true.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * // During streaming
42
+ * <StreamingText
43
+ * text="Hello, world"
44
+ * isStreaming={true}
45
+ * />
46
+ * // Renders: "Hello, world█"
47
+ *
48
+ * // After streaming completes
49
+ * <StreamingText
50
+ * text="Hello, world!"
51
+ * isStreaming={false}
52
+ * />
53
+ * // Renders: "Hello, world!"
54
+ * ```
55
+ */
56
+ export function StreamingText({
57
+ text,
58
+ isStreaming,
59
+ color = colors.white,
60
+ showCursor = true,
61
+ }: StreamingTextProps): React.ReactElement {
62
+ // Determine if cursor should be visible
63
+ const displayCursor = isStreaming && showCursor;
64
+
65
+ // Build the display text with optional cursor
66
+ const displayText = displayCursor ? `${text}${CURSOR_CHAR}` : text;
67
+
68
+ return <Text color={color}>{displayText}</Text>;
69
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ * ToolCallCard - Collapsible tool execution display
3
+ *
4
+ * Shows tool executions in a bordered card format, similar to Claude Code.
5
+ * Displays tool name, input, status indicator, and output/error.
6
+ */
7
+
8
+ import React from 'react';
9
+ import { Box, Text } from 'ink';
10
+ import { colors, box, phase } from '../theme.js';
11
+
12
+ /**
13
+ * Tool execution status
14
+ */
15
+ export type ToolCallStatus = 'pending' | 'running' | 'complete' | 'error';
16
+
17
+ /**
18
+ * Props for the ToolCallCard component
19
+ */
20
+ export interface ToolCallCardProps {
21
+ /** Name of the tool (e.g., "Read File", "Search Codebase") */
22
+ toolName: string;
23
+ /** Tool execution status */
24
+ status: ToolCallStatus;
25
+ /** Input passed to the tool (e.g., file path, search query) */
26
+ input: string;
27
+ /** Result summary when status is 'complete' */
28
+ output?: string;
29
+ /** Error message when status is 'error' */
30
+ error?: string;
31
+ /** Whether to show full details (default: false = collapsed) */
32
+ expanded?: boolean;
33
+ }
34
+
35
+ /**
36
+ * Maps status to phase indicator character
37
+ */
38
+ function getStatusIndicator(status: ToolCallStatus): string {
39
+ switch (status) {
40
+ case 'pending':
41
+ return phase.pending;
42
+ case 'running':
43
+ return phase.active;
44
+ case 'complete':
45
+ return phase.complete;
46
+ case 'error':
47
+ return phase.error;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Gets the color for the status indicator
53
+ */
54
+ function getStatusColor(status: ToolCallStatus): string {
55
+ switch (status) {
56
+ case 'pending':
57
+ return colors.brown;
58
+ case 'running':
59
+ return colors.yellow;
60
+ case 'complete':
61
+ return colors.yellow;
62
+ case 'error':
63
+ return colors.pink;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Gets human-readable status text
69
+ */
70
+ function getStatusText(status: ToolCallStatus): string {
71
+ switch (status) {
72
+ case 'pending':
73
+ return 'Pending';
74
+ case 'running':
75
+ return 'Running';
76
+ case 'complete':
77
+ return 'Complete';
78
+ case 'error':
79
+ return 'Error';
80
+ }
81
+ }
82
+
83
+ /**
84
+ * ToolCallCard component
85
+ *
86
+ * Displays a tool execution in a bordered card format.
87
+ *
88
+ * @example
89
+ * ```tsx
90
+ * // Collapsed (default)
91
+ * <ToolCallCard
92
+ * toolName="Read File"
93
+ * status="complete"
94
+ * input="src/utils/config.ts"
95
+ * output="45 lines read"
96
+ * />
97
+ * // Renders:
98
+ * // ┌─ Read File ────────────────────────────────┐
99
+ * // │ src/utils/config.ts ✓ 45 lines read │
100
+ * // └────────────────────────────────────────────┘
101
+ *
102
+ * // Expanded
103
+ * <ToolCallCard
104
+ * toolName="Read File"
105
+ * status="complete"
106
+ * input="src/utils/config.ts"
107
+ * output="45 lines read"
108
+ * expanded={true}
109
+ * />
110
+ * // Renders:
111
+ * // ┌─ Read File ────────────────────────────────┐
112
+ * // │ Input: src/utils/config.ts │
113
+ * // │ Status: Complete │
114
+ * // │ Result: 45 lines read │
115
+ * // └────────────────────────────────────────────┘
116
+ * ```
117
+ */
118
+ export function ToolCallCard({
119
+ toolName,
120
+ status,
121
+ input,
122
+ output,
123
+ error,
124
+ expanded = false,
125
+ }: ToolCallCardProps): React.ReactElement {
126
+ const statusIndicator = getStatusIndicator(status);
127
+ const statusColor = getStatusColor(status);
128
+ const statusText = getStatusText(status);
129
+
130
+ // Build the title with box drawing
131
+ const titlePadding = box.horizontal.repeat(3);
132
+ const title = `${box.horizontal} ${toolName} ${titlePadding}`;
133
+
134
+ // Determine result text
135
+ const resultText = status === 'error' ? error : output;
136
+
137
+ if (expanded) {
138
+ // Expanded layout: multiple lines with labels
139
+ return (
140
+ <Box flexDirection="column">
141
+ {/* Top border with title */}
142
+ <Box flexDirection="row">
143
+ <Text color={colors.brown}>{box.topLeft}</Text>
144
+ <Text color={colors.yellow}>{title}</Text>
145
+ </Box>
146
+
147
+ {/* Input line */}
148
+ <Box flexDirection="row">
149
+ <Text color={colors.brown}>{box.vertical} </Text>
150
+ <Text color={colors.brown}>Input: </Text>
151
+ <Text color={colors.white}>{input}</Text>
152
+ </Box>
153
+
154
+ {/* Status line */}
155
+ <Box flexDirection="row">
156
+ <Text color={colors.brown}>{box.vertical} </Text>
157
+ <Text color={colors.brown}>Status: </Text>
158
+ <Text color={statusColor}>
159
+ {statusIndicator} {statusText}
160
+ </Text>
161
+ </Box>
162
+
163
+ {/* Result/Error line (if present) */}
164
+ {resultText && (
165
+ <Box flexDirection="row">
166
+ <Text color={colors.brown}>{box.vertical} </Text>
167
+ <Text color={colors.brown}>{status === 'error' ? 'Error: ' : 'Result: '}</Text>
168
+ <Text color={status === 'error' ? colors.pink : colors.white}>{resultText}</Text>
169
+ </Box>
170
+ )}
171
+
172
+ {/* Bottom border */}
173
+ <Box flexDirection="row">
174
+ <Text color={colors.brown}>
175
+ {box.bottomLeft}
176
+ {box.horizontal.repeat(40)}
177
+ </Text>
178
+ </Box>
179
+ </Box>
180
+ );
181
+ }
182
+
183
+ // Collapsed layout: single content line
184
+ return (
185
+ <Box flexDirection="column">
186
+ {/* Top border with title */}
187
+ <Box flexDirection="row">
188
+ <Text color={colors.brown}>{box.topLeft}</Text>
189
+ <Text color={colors.yellow}>{title}</Text>
190
+ </Box>
191
+
192
+ {/* Content line: input + status + result */}
193
+ <Box flexDirection="row">
194
+ <Text color={colors.brown}>{box.vertical} </Text>
195
+ <Text color={colors.white}>{input}</Text>
196
+ <Text> </Text>
197
+ <Text color={statusColor}>{statusIndicator}</Text>
198
+ {resultText && (
199
+ <>
200
+ <Text> </Text>
201
+ <Text color={status === 'error' ? colors.pink : colors.white}>{resultText}</Text>
202
+ </>
203
+ )}
204
+ </Box>
205
+
206
+ {/* Bottom border */}
207
+ <Box flexDirection="row">
208
+ <Text color={colors.brown}>
209
+ {box.bottomLeft}
210
+ {box.horizontal.repeat(40)}
211
+ </Text>
212
+ </Box>
213
+ </Box>
214
+ );
215
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * WorkingIndicator - Spinner + status display during AI calls
3
+ *
4
+ * Displays an animated spinner with status text when the AI is processing.
5
+ * Similar to Claude Code's "Thinking..." indicator.
6
+ */
7
+
8
+ import React from 'react';
9
+ import { Box, Text } from 'ink';
10
+ import Spinner from 'ink-spinner';
11
+ import { colors } from '../theme.js';
12
+
13
+ /**
14
+ * Working state object describing the current processing state
15
+ */
16
+ export interface WorkingState {
17
+ /** Whether to show the indicator */
18
+ isWorking: boolean;
19
+ /** Status text (e.g., "Thinking...", "Reading files...", "Searching...") */
20
+ status: string;
21
+ /** Optional hint text (e.g., "esc to interrupt") */
22
+ hint?: string;
23
+ }
24
+
25
+ /**
26
+ * Props for the WorkingIndicator component
27
+ */
28
+ export interface WorkingIndicatorProps {
29
+ /** Working state object */
30
+ state: WorkingState;
31
+ }
32
+
33
+ /**
34
+ * WorkingIndicator component
35
+ *
36
+ * Displays a spinner with status text when AI is processing.
37
+ * Returns null when not working.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * <WorkingIndicator
42
+ * state={{
43
+ * isWorking: true,
44
+ * status: "Thinking...",
45
+ * hint: "esc to interrupt"
46
+ * }}
47
+ * />
48
+ * // Renders: ⠋ Thinking... (esc to interrupt)
49
+ * ```
50
+ */
51
+ export function WorkingIndicator({ state }: WorkingIndicatorProps): React.ReactElement | null {
52
+ const { isWorking, status, hint } = state;
53
+
54
+ // Don't render anything when not working
55
+ if (!isWorking) {
56
+ return null;
57
+ }
58
+
59
+ return (
60
+ <Box flexDirection="row" gap={1}>
61
+ <Text color={colors.yellow}>
62
+ <Spinner type="dots" />
63
+ </Text>
64
+ <Text color={colors.yellow}>{status}</Text>
65
+ {hint && (
66
+ <Text color={colors.brown} dimColor>
67
+ ({hint})
68
+ </Text>
69
+ )}
70
+ </Box>
71
+ );
72
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Reusable Ink components for the Wiggum TUI
3
+ */
4
+
5
+ export { WorkingIndicator } from './WorkingIndicator.js';
6
+ export type { WorkingIndicatorProps, WorkingState } from './WorkingIndicator.js';
7
+
8
+ export { PhaseHeader } from './PhaseHeader.js';
9
+ export type { PhaseHeaderProps } from './PhaseHeader.js';
10
+
11
+ export { StreamingText } from './StreamingText.js';
12
+ export type { StreamingTextProps } from './StreamingText.js';
13
+
14
+ export { ToolCallCard } from './ToolCallCard.js';
15
+ export type { ToolCallCardProps, ToolCallStatus } from './ToolCallCard.js';
16
+
17
+ export { MessageList } from './MessageList.js';
18
+ export type { MessageListProps, Message, ToolCall } from './MessageList.js';
19
+
20
+ export { ChatInput } from './ChatInput.js';
21
+ export type { ChatInputProps } from './ChatInput.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Custom React hooks for the Wiggum TUI
3
+ */
4
+
5
+ export { useSpecGenerator } from './useSpecGenerator.js';
6
+ export type {
7
+ GeneratorPhase,
8
+ PhaseConfig,
9
+ SpecGeneratorState,
10
+ SpecGeneratorOptions,
11
+ UseSpecGeneratorReturn,
12
+ } from './useSpecGenerator.js';
13
+ export { PHASE_CONFIGS, TOTAL_DISPLAY_PHASES } from './useSpecGenerator.js';