wiggum-cli 0.10.3 → 0.10.4

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.
@@ -1,10 +1,11 @@
1
1
  /**
2
- * ChatInput - Multi-line input with history for chat interactions
2
+ * ChatInput - Multi-line input with slash command support
3
3
  *
4
- * Displays a prompt character followed by a text input.
5
- * Handles submission on Enter and clears input after submit.
4
+ * Displays a `›` prompt character followed by a text input.
5
+ * Shows command dropdown when typing `/`.
6
6
  */
7
7
  import React from 'react';
8
+ import { type Command } from './CommandDropdown.js';
8
9
  /**
9
10
  * Props for the ChatInput component
10
11
  */
@@ -15,26 +16,28 @@ export interface ChatInputProps {
15
16
  placeholder?: string;
16
17
  /** Whether input is disabled (e.g., during AI processing) */
17
18
  disabled?: boolean;
18
- /** Prompt character/text shown before input (default "> ") */
19
- prompt?: string;
20
19
  /** Allow empty submissions (e.g., to continue/skip phases) */
21
20
  allowEmpty?: boolean;
21
+ /** Available slash commands (uses defaults if not provided) */
22
+ commands?: Command[];
23
+ /** Called when a slash command is selected */
24
+ onCommand?: (command: string) => void;
22
25
  }
23
26
  /**
24
27
  * ChatInput component
25
28
  *
26
- * Provides a text input with a prompt character for chat-style interactions.
27
- * Clears input after submission. Shows dimmed appearance when disabled.
29
+ * Provides a text input with `›` prompt for chat-style interactions.
30
+ * Shows command dropdown when input starts with `/`.
28
31
  *
29
32
  * @example
30
33
  * ```tsx
31
34
  * <ChatInput
32
35
  * onSubmit={(value) => console.log('User said:', value)}
33
- * placeholder="Type your response..."
36
+ * placeholder="Type your message..."
34
37
  * disabled={isProcessing}
35
38
  * />
36
- * // Renders: > Type your response...
39
+ * // Renders: Type your message...
37
40
  * ```
38
41
  */
39
- export declare function ChatInput({ onSubmit, placeholder, disabled, prompt, allowEmpty, }: ChatInputProps): React.ReactElement;
42
+ export declare function ChatInput({ onSubmit, placeholder, disabled, allowEmpty, commands, onCommand, }: ChatInputProps): React.ReactElement;
40
43
  //# sourceMappingURL=ChatInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInput.d.ts","sourceRoot":"","sources":["../../../src/tui/components/ChatInput.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAKxC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,WAAoC,EACpC,QAAgB,EAChB,MAAa,EACb,UAAkB,GACnB,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAsDrC"}
1
+ {"version":3,"file":"ChatInput.d.ts","sourceRoot":"","sources":["../../../src/tui/components/ChatInput.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAgC,MAAM,OAAO,CAAC;AAIrD,OAAO,EAAqC,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,WAAoC,EACpC,QAAgB,EAChB,UAAkB,EAClB,QAA2B,EAC3B,SAAS,GACV,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAqHrC"}
@@ -1,40 +1,52 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
- * ChatInput - Multi-line input with history for chat interactions
3
+ * ChatInput - Multi-line input with slash command support
4
4
  *
5
- * Displays a prompt character followed by a text input.
6
- * Handles submission on Enter and clears input after submit.
5
+ * Displays a `›` prompt character followed by a text input.
6
+ * Shows command dropdown when typing `/`.
7
7
  */
8
- import { useState } from 'react';
8
+ import { useState, useCallback } from 'react';
9
9
  import { Box, Text } from 'ink';
10
10
  import TextInput from 'ink-text-input';
11
11
  import { colors } from '../theme.js';
12
+ import { CommandDropdown, DEFAULT_COMMANDS } from './CommandDropdown.js';
12
13
  /**
13
14
  * ChatInput component
14
15
  *
15
- * Provides a text input with a prompt character for chat-style interactions.
16
- * Clears input after submission. Shows dimmed appearance when disabled.
16
+ * Provides a text input with `›` prompt for chat-style interactions.
17
+ * Shows command dropdown when input starts with `/`.
17
18
  *
18
19
  * @example
19
20
  * ```tsx
20
21
  * <ChatInput
21
22
  * onSubmit={(value) => console.log('User said:', value)}
22
- * placeholder="Type your response..."
23
+ * placeholder="Type your message..."
23
24
  * disabled={isProcessing}
24
25
  * />
25
- * // Renders: > Type your response...
26
+ * // Renders: Type your message...
26
27
  * ```
27
28
  */
28
- export function ChatInput({ onSubmit, placeholder = 'Type your message...', disabled = false, prompt = '> ', allowEmpty = false, }) {
29
+ export function ChatInput({ onSubmit, placeholder = 'Type your message...', disabled = false, allowEmpty = false, commands = DEFAULT_COMMANDS, onCommand, }) {
29
30
  const [value, setValue] = useState('');
31
+ const [showDropdown, setShowDropdown] = useState(false);
32
+ // Check if input is a slash command
33
+ const isSlashCommand = value.startsWith('/');
34
+ const commandFilter = isSlashCommand ? value.slice(1) : '';
30
35
  /**
31
36
  * Handle input submission
32
- * Calls onSubmit with current value and clears the input
33
37
  */
34
- const handleSubmit = (submittedValue) => {
35
- // Don't submit when disabled
36
- if (disabled) {
38
+ const handleSubmit = useCallback((submittedValue) => {
39
+ if (disabled)
37
40
  return;
41
+ // Handle slash commands
42
+ if (submittedValue.startsWith('/') && onCommand) {
43
+ const cmdName = submittedValue.slice(1).trim().split(' ')[0];
44
+ if (cmdName) {
45
+ onCommand(cmdName);
46
+ setValue('');
47
+ setShowDropdown(false);
48
+ return;
49
+ }
38
50
  }
39
51
  // Don't submit empty values unless allowEmpty is true
40
52
  if (!submittedValue.trim() && !allowEmpty) {
@@ -42,20 +54,47 @@ export function ChatInput({ onSubmit, placeholder = 'Type your message...', disa
42
54
  }
43
55
  onSubmit(submittedValue);
44
56
  setValue('');
45
- };
57
+ setShowDropdown(false);
58
+ }, [disabled, allowEmpty, onSubmit, onCommand]);
46
59
  /**
47
60
  * Handle value changes
48
- * Only update if not disabled
49
61
  */
50
- const handleChange = (newValue) => {
51
- if (!disabled) {
52
- setValue(newValue);
62
+ const handleChange = useCallback((newValue) => {
63
+ if (disabled)
64
+ return;
65
+ setValue(newValue);
66
+ // Show dropdown when typing /
67
+ if (newValue.startsWith('/')) {
68
+ setShowDropdown(true);
69
+ }
70
+ else {
71
+ setShowDropdown(false);
72
+ }
73
+ }, [disabled]);
74
+ /**
75
+ * Handle command selection from dropdown
76
+ */
77
+ const handleCommandSelect = useCallback((cmdName) => {
78
+ if (onCommand) {
79
+ onCommand(cmdName);
53
80
  }
54
- };
81
+ else {
82
+ // If no onCommand handler, just submit the command
83
+ onSubmit(`/${cmdName}`);
84
+ }
85
+ setValue('');
86
+ setShowDropdown(false);
87
+ }, [onCommand, onSubmit]);
88
+ /**
89
+ * Handle dropdown cancel
90
+ */
91
+ const handleDropdownCancel = useCallback(() => {
92
+ setShowDropdown(false);
93
+ }, []);
55
94
  // When disabled, show a waiting message
56
95
  if (disabled) {
57
- return (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { dimColor: true, color: colors.brown, children: [prompt, "[waiting for AI...]"] }) }));
96
+ return (_jsx(Box, { flexDirection: "row", children: _jsx(Text, { dimColor: true, color: colors.brown, children: "\u203A [waiting for AI...]" }) }));
58
97
  }
59
- return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: colors.yellow, children: prompt }), _jsx(TextInput, { value: value, onChange: handleChange, onSubmit: handleSubmit, placeholder: placeholder })] }));
98
+ return (_jsxs(Box, { flexDirection: "column", children: [showDropdown && isSlashCommand && (_jsx(CommandDropdown, { commands: commands, filter: commandFilter, onSelect: handleCommandSelect, onCancel: handleDropdownCancel })), _jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: colors.blue, bold: true, children: ["\u203A", ' '] }), _jsx(TextInput, { value: value, onChange: handleChange, onSubmit: handleSubmit, placeholder: placeholder })] })] }));
60
99
  }
61
100
  //# sourceMappingURL=ChatInput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInput.js","sourceRoot":"","sources":["../../../src/tui/components/ChatInput.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAkBrC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,QAAQ,EACR,WAAW,GAAG,sBAAsB,EACpC,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,IAAI,EACb,UAAU,GAAG,KAAK,GACH;IACf,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEvC;;;OAGG;IACH,MAAM,YAAY,GAAG,CAAC,cAAsB,EAAQ,EAAE;QACpD,6BAA6B;QAC7B,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,sDAAsD;QACtD,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,OAAO;QACT,CAAC;QAED,QAAQ,CAAC,cAAc,CAAC,CAAC;QACzB,QAAQ,CAAC,EAAE,CAAC,CAAC;IACf,CAAC,CAAC;IAEF;;;OAGG;IACH,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAQ,EAAE;QAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;IAEF,wCAAwC;IACxC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CACL,KAAC,GAAG,IAAC,aAAa,EAAC,KAAK,YACtB,MAAC,IAAI,IAAC,QAAQ,QAAC,KAAK,EAAE,MAAM,CAAC,KAAK,aAC/B,MAAM,2BACF,GACH,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,KAAK,aACtB,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,YAAG,MAAM,GAAQ,EAC3C,KAAC,SAAS,IACR,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,WAAW,GACxB,IACE,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ChatInput.js","sourceRoot":"","sources":["../../../src/tui/components/ChatInput.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * CommandDropdown - Slash command autocomplete dropdown
3
+ *
4
+ * Shows available commands when user types "/" in the input.
5
+ * Supports arrow key navigation and Enter to select.
6
+ */
7
+ import React from 'react';
8
+ /**
9
+ * Command definition
10
+ */
11
+ export interface Command {
12
+ /** Command name (without /) */
13
+ name: string;
14
+ /** Description shown next to command */
15
+ description: string;
16
+ }
17
+ /**
18
+ * Props for the CommandDropdown component
19
+ */
20
+ export interface CommandDropdownProps {
21
+ /** Available commands */
22
+ commands: Command[];
23
+ /** Filter string (what user typed after /) */
24
+ filter: string;
25
+ /** Called when a command is selected */
26
+ onSelect: (command: string) => void;
27
+ /** Called when dropdown is dismissed (Escape) */
28
+ onCancel: () => void;
29
+ }
30
+ /**
31
+ * CommandDropdown component
32
+ *
33
+ * Displays a filtered list of available slash commands.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * <CommandDropdown
38
+ * commands={[
39
+ * { name: 'init', description: 'Initialize a new CLAUDE.md file' },
40
+ * { name: 'new', description: 'Create a new feature spec' },
41
+ * ]}
42
+ * filter="in"
43
+ * onSelect={(cmd) => console.log('Selected:', cmd)}
44
+ * onCancel={() => setShowDropdown(false)}
45
+ * />
46
+ * ```
47
+ */
48
+ export declare function CommandDropdown({ commands, filter, onSelect, onCancel, }: CommandDropdownProps): React.ReactElement;
49
+ /**
50
+ * Default commands available in wiggum
51
+ */
52
+ export declare const DEFAULT_COMMANDS: Command[];
53
+ //# sourceMappingURL=CommandDropdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandDropdown.d.ts","sourceRoot":"","sources":["../../../src/tui/components/CommandDropdown.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yBAAyB;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,iDAAiD;IACjD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,QAAQ,GACT,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CA6D3C;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,EAOrC,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * CommandDropdown - Slash command autocomplete dropdown
4
+ *
5
+ * Shows available commands when user types "/" in the input.
6
+ * Supports arrow key navigation and Enter to select.
7
+ */
8
+ import React, { useState } from 'react';
9
+ import { Box, Text, useInput } from 'ink';
10
+ import { colors } from '../theme.js';
11
+ /**
12
+ * CommandDropdown component
13
+ *
14
+ * Displays a filtered list of available slash commands.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <CommandDropdown
19
+ * commands={[
20
+ * { name: 'init', description: 'Initialize a new CLAUDE.md file' },
21
+ * { name: 'new', description: 'Create a new feature spec' },
22
+ * ]}
23
+ * filter="in"
24
+ * onSelect={(cmd) => console.log('Selected:', cmd)}
25
+ * onCancel={() => setShowDropdown(false)}
26
+ * />
27
+ * ```
28
+ */
29
+ export function CommandDropdown({ commands, filter, onSelect, onCancel, }) {
30
+ const [selectedIndex, setSelectedIndex] = useState(0);
31
+ // Filter commands based on input
32
+ const filteredCommands = commands.filter((cmd) => cmd.name.toLowerCase().includes(filter.toLowerCase()));
33
+ // Handle keyboard input
34
+ useInput((input, key) => {
35
+ if (key.escape) {
36
+ onCancel();
37
+ return;
38
+ }
39
+ if (key.return && filteredCommands.length > 0) {
40
+ onSelect(filteredCommands[selectedIndex].name);
41
+ return;
42
+ }
43
+ if (key.upArrow) {
44
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
45
+ return;
46
+ }
47
+ if (key.downArrow) {
48
+ setSelectedIndex((prev) => Math.min(filteredCommands.length - 1, prev + 1));
49
+ return;
50
+ }
51
+ });
52
+ // Reset selection when filter changes
53
+ React.useEffect(() => {
54
+ setSelectedIndex(0);
55
+ }, [filter]);
56
+ if (filteredCommands.length === 0) {
57
+ return (_jsx(Box, { paddingLeft: 2, children: _jsx(Text, { dimColor: true, children: "No matching commands" }) }));
58
+ }
59
+ return (_jsx(Box, { flexDirection: "column", paddingLeft: 2, children: filteredCommands.map((cmd, index) => {
60
+ const isSelected = index === selectedIndex;
61
+ return (_jsxs(Box, { flexDirection: "row", gap: 2, children: [_jsxs(Text, { color: isSelected ? colors.blue : colors.yellow, children: ["/", cmd.name] }), _jsx(Text, { color: isSelected ? colors.white : undefined, dimColor: !isSelected, children: cmd.description })] }, cmd.name));
62
+ }) }));
63
+ }
64
+ /**
65
+ * Default commands available in wiggum
66
+ */
67
+ export const DEFAULT_COMMANDS = [
68
+ { name: 'init', description: 'Initialize project with CLAUDE.md' },
69
+ { name: 'new', description: 'Create a new feature specification' },
70
+ { name: 'run', description: 'Run a spec file with AI' },
71
+ { name: 'help', description: 'Show available commands' },
72
+ { name: 'clear', description: 'Clear conversation history' },
73
+ { name: 'exit', description: 'Exit wiggum' },
74
+ ];
75
+ //# sourceMappingURL=CommandDropdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandDropdown.js","sourceRoot":"","sources":["../../../src/tui/components/CommandDropdown.tsx"],"names":[],"mappings":"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"}
@@ -1,11 +1,10 @@
1
1
  /**
2
- * MessageList - Scrollable conversation history display
2
+ * MessageList - Conversation history display
3
3
  *
4
- * Displays the full conversation history including:
5
- * - User messages
6
- * - Assistant messages (with optional streaming)
7
- * - System messages
8
- * - Tool call cards inline with assistant messages
4
+ * Displays the full conversation history with clean formatting:
5
+ * - User messages: › prefix
6
+ * - Assistant messages: ● bullet with clean markdown-like styling
7
+ * - Tool calls: Inline action indicators
9
8
  */
10
9
  import React from 'react';
11
10
  import { type ToolCallStatus } from './ToolCallCard.js';
@@ -51,28 +50,22 @@ export interface MessageListProps {
51
50
  /**
52
51
  * MessageList component
53
52
  *
54
- * Displays the full conversation history. Each message type has
55
- * distinct styling:
56
- * - User messages: "You: " prefix in white
57
- * - Assistant messages: "AI: " prefix in yellow, with inline tool cards
58
- * - System messages: dimmed brown text
59
- *
60
- * For streaming messages, uses the StreamingText component to show
61
- * the cursor indicator.
53
+ * Displays the full conversation history with clean styling:
54
+ * - User messages: `› ` prefix in blue
55
+ * - Assistant messages: `● ` prefix in yellow, with inline tool cards
56
+ * - System messages: dimmed text
62
57
  *
63
58
  * @example
64
59
  * ```tsx
65
60
  * <MessageList
66
61
  * messages={[
67
- * { id: '1', role: 'system', content: 'Interview started' },
68
- * { id: '2', role: 'assistant', content: 'Hello! What would you like to build?' },
69
- * { id: '3', role: 'user', content: 'A todo app' },
70
- * { id: '4', role: 'assistant', content: 'Let me check...',
71
- * toolCalls: [{ toolName: 'Read File', status: 'running', input: 'package.json' }],
72
- * isStreaming: true
73
- * },
62
+ * { id: '1', role: 'user', content: 'Hello' },
63
+ * { id: '2', role: 'assistant', content: 'Hi! How can I help?' },
74
64
  * ]}
75
65
  * />
66
+ * // Renders:
67
+ * // › Hello
68
+ * // ● Hi! How can I help?
76
69
  * ```
77
70
  */
78
71
  export declare function MessageList({ messages, maxHeight }: MessageListProps): React.ReactElement;
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/tui/components/MessageList.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CA6BzF"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/tui/components/MessageList.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0ED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAyBzF"}
@@ -4,56 +4,45 @@ import { colors } from '../theme.js';
4
4
  import { StreamingText } from './StreamingText.js';
5
5
  import { ToolCallCard } from './ToolCallCard.js';
6
6
  /**
7
- * Renders a single user message
7
+ * Renders a single user message with › prefix
8
8
  */
9
9
  function UserMessage({ content }) {
10
- return (_jsxs(Box, { flexDirection: "row", marginY: 1, children: [_jsxs(Text, { color: colors.white, bold: true, children: ["You:", ' '] }), _jsx(Text, { color: colors.white, children: content })] }));
10
+ return (_jsxs(Box, { flexDirection: "row", marginY: 1, children: [_jsxs(Text, { color: colors.blue, bold: true, children: ["\u203A", ' '] }), _jsx(Text, { color: colors.white, children: content })] }));
11
11
  }
12
12
  /**
13
- * Renders a single assistant message with optional tool calls and streaming
13
+ * Renders a single assistant message with prefix and tool calls
14
14
  */
15
15
  function AssistantMessage({ content, toolCalls, isStreaming, }) {
16
- return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [toolCalls &&
17
- toolCalls.length > 0 &&
18
- toolCalls.map((toolCall, index) => (_jsx(Box, { marginBottom: 1, children: _jsx(ToolCallCard, { toolName: toolCall.toolName, status: toolCall.status, input: toolCall.input, output: toolCall.output, error: toolCall.error }) }, `tool-${index}`))), _jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: colors.yellow, bold: true, children: ["AI:", ' '] }), isStreaming ? (_jsx(StreamingText, { text: content, isStreaming: true, color: colors.yellow })) : (_jsx(Text, { color: colors.yellow, children: content }))] })] }));
16
+ return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [toolCalls && toolCalls.length > 0 && (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: toolCalls.map((toolCall, index) => (_jsx(ToolCallCard, { toolName: toolCall.toolName, status: toolCall.status, input: toolCall.input, output: toolCall.output, error: toolCall.error }, `tool-${index}`))) })), content && (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: colors.yellow, children: ["\u25CF", ' '] }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: isStreaming ? (_jsx(StreamingText, { text: content, isStreaming: true, color: colors.yellow })) : (_jsx(Text, { color: colors.yellow, children: content })) })] }))] }));
19
17
  }
20
18
  /**
21
- * Renders a system message (dimmed text)
19
+ * Renders a system message (dimmed, no prefix)
22
20
  */
23
21
  function SystemMessage({ content }) {
24
- return (_jsx(Box, { flexDirection: "row", marginY: 1, children: _jsx(Text, { color: colors.brown, dimColor: true, children: content }) }));
22
+ return (_jsx(Box, { marginY: 1, children: _jsx(Text, { dimColor: true, children: content }) }));
25
23
  }
26
24
  /**
27
25
  * MessageList component
28
26
  *
29
- * Displays the full conversation history. Each message type has
30
- * distinct styling:
31
- * - User messages: "You: " prefix in white
32
- * - Assistant messages: "AI: " prefix in yellow, with inline tool cards
33
- * - System messages: dimmed brown text
34
- *
35
- * For streaming messages, uses the StreamingText component to show
36
- * the cursor indicator.
27
+ * Displays the full conversation history with clean styling:
28
+ * - User messages: `› ` prefix in blue
29
+ * - Assistant messages: `● ` prefix in yellow, with inline tool cards
30
+ * - System messages: dimmed text
37
31
  *
38
32
  * @example
39
33
  * ```tsx
40
34
  * <MessageList
41
35
  * messages={[
42
- * { id: '1', role: 'system', content: 'Interview started' },
43
- * { id: '2', role: 'assistant', content: 'Hello! What would you like to build?' },
44
- * { id: '3', role: 'user', content: 'A todo app' },
45
- * { id: '4', role: 'assistant', content: 'Let me check...',
46
- * toolCalls: [{ toolName: 'Read File', status: 'running', input: 'package.json' }],
47
- * isStreaming: true
48
- * },
36
+ * { id: '1', role: 'user', content: 'Hello' },
37
+ * { id: '2', role: 'assistant', content: 'Hi! How can I help?' },
49
38
  * ]}
50
39
  * />
40
+ * // Renders:
41
+ * // › Hello
42
+ * // ● Hi! How can I help?
51
43
  * ```
52
44
  */
53
45
  export function MessageList({ messages, maxHeight }) {
54
- // Note: maxHeight is accepted for future scrolling support
55
- // Currently renders all messages - parent handles any scroll-like behavior
56
- // by controlling which messages are passed in
57
46
  return (_jsx(Box, { flexDirection: "column", ...(maxHeight ? { height: maxHeight } : {}), children: messages.map((message) => {
58
47
  switch (message.role) {
59
48
  case 'user':
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.js","sourceRoot":"","sources":["../../../src/tui/components/MessageList.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MessageList.js","sourceRoot":"","sources":["../../../src/tui/components/MessageList.tsx"],"names":[],"mappings":"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"}
@@ -13,6 +13,8 @@ export { MessageList } from './MessageList.js';
13
13
  export type { MessageListProps, Message, ToolCall } from './MessageList.js';
14
14
  export { ChatInput } from './ChatInput.js';
15
15
  export type { ChatInputProps } from './ChatInput.js';
16
+ export { CommandDropdown, DEFAULT_COMMANDS } from './CommandDropdown.js';
17
+ export type { CommandDropdownProps, Command } from './CommandDropdown.js';
16
18
  export { Select } from './Select.js';
17
19
  export type { SelectProps, SelectOption } from './Select.js';
18
20
  export { PasswordInput } from './PasswordInput.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tui/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tui/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACzE,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -7,6 +7,7 @@ export { StreamingText } from './StreamingText.js';
7
7
  export { ToolCallCard } from './ToolCallCard.js';
8
8
  export { MessageList } from './MessageList.js';
9
9
  export { ChatInput } from './ChatInput.js';
10
+ export { CommandDropdown, DEFAULT_COMMANDS } from './CommandDropdown.js';
10
11
  export { Select } from './Select.js';
11
12
  export { PasswordInput } from './PasswordInput.js';
12
13
  export { Confirm } from './Confirm.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tui/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tui/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGzE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
@@ -191,6 +191,6 @@ export function MainShell({ sessionState, onNavigate, }) {
191
191
  addSystemMessage('Use /exit to quit');
192
192
  }
193
193
  });
194
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: colors.yellow, bold: true, children: "Wiggum Interactive Mode" }), _jsx(Text, { dimColor: true, children: " \u2502 " }), sessionState.initialized ? (_jsx(Text, { color: colors.green, children: "Ready" })) : (_jsx(Text, { color: colors.orange, children: "Not initialized - run /init" }))] }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { dimColor: true, children: sessionState.provider ? `${sessionState.provider}/${sessionState.model}` : 'No provider configured' }), _jsx(Text, { dimColor: true, children: " \u2502 Type /help for commands" })] }), messages.length > 0 && (_jsx(Box, { marginY: 1, flexDirection: "column", children: _jsx(MessageList, { messages: messages }) })), _jsx(Box, { marginTop: 1, children: _jsx(ChatInput, { onSubmit: handleSubmit, disabled: false, placeholder: "Enter command or type /help...", prompt: "wiggum> " }) })] }));
194
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: colors.yellow, bold: true, children: "Wiggum Interactive Mode" }), _jsx(Text, { dimColor: true, children: " \u2502 " }), sessionState.initialized ? (_jsx(Text, { color: colors.green, children: "Ready" })) : (_jsx(Text, { color: colors.orange, children: "Not initialized - run /init" }))] }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { dimColor: true, children: sessionState.provider ? `${sessionState.provider}/${sessionState.model}` : 'No provider configured' }), _jsx(Text, { dimColor: true, children: " \u2502 Type /help for commands" })] }), messages.length > 0 && (_jsx(Box, { marginY: 1, flexDirection: "column", children: _jsx(MessageList, { messages: messages }) })), _jsx(Box, { marginTop: 1, children: _jsx(ChatInput, { onSubmit: handleSubmit, disabled: false, placeholder: "Enter command or type /help...", onCommand: (cmd) => handleSubmit(`/${cmd}`) }) })] }));
195
195
  }
196
196
  //# sourceMappingURL=MainShell.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MainShell.js","sourceRoot":"","sources":["../../../src/tui/screens/MainShell.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MainShell.js","sourceRoot":"","sources":["../../../src/tui/screens/MainShell.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiggum-cli",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "description": "AI-powered feature development loop CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,14 +1,15 @@
1
1
  /**
2
- * ChatInput - Multi-line input with history for chat interactions
2
+ * ChatInput - Multi-line input with slash command support
3
3
  *
4
- * Displays a prompt character followed by a text input.
5
- * Handles submission on Enter and clears input after submit.
4
+ * Displays a `›` prompt character followed by a text input.
5
+ * Shows command dropdown when typing `/`.
6
6
  */
7
7
 
8
- import React, { useState } from 'react';
9
- import { Box, Text } from 'ink';
8
+ import React, { useState, useCallback } from 'react';
9
+ import { Box, Text, useInput } from 'ink';
10
10
  import TextInput from 'ink-text-input';
11
11
  import { colors } from '../theme.js';
12
+ import { CommandDropdown, DEFAULT_COMMANDS, type Command } from './CommandDropdown.js';
12
13
 
13
14
  /**
14
15
  * Props for the ChatInput component
@@ -20,86 +21,152 @@ export interface ChatInputProps {
20
21
  placeholder?: string;
21
22
  /** Whether input is disabled (e.g., during AI processing) */
22
23
  disabled?: boolean;
23
- /** Prompt character/text shown before input (default "> ") */
24
- prompt?: string;
25
24
  /** Allow empty submissions (e.g., to continue/skip phases) */
26
25
  allowEmpty?: boolean;
26
+ /** Available slash commands (uses defaults if not provided) */
27
+ commands?: Command[];
28
+ /** Called when a slash command is selected */
29
+ onCommand?: (command: string) => void;
27
30
  }
28
31
 
29
32
  /**
30
33
  * ChatInput component
31
34
  *
32
- * Provides a text input with a prompt character for chat-style interactions.
33
- * Clears input after submission. Shows dimmed appearance when disabled.
35
+ * Provides a text input with `›` prompt for chat-style interactions.
36
+ * Shows command dropdown when input starts with `/`.
34
37
  *
35
38
  * @example
36
39
  * ```tsx
37
40
  * <ChatInput
38
41
  * onSubmit={(value) => console.log('User said:', value)}
39
- * placeholder="Type your response..."
42
+ * placeholder="Type your message..."
40
43
  * disabled={isProcessing}
41
44
  * />
42
- * // Renders: > Type your response...
45
+ * // Renders: Type your message...
43
46
  * ```
44
47
  */
45
48
  export function ChatInput({
46
49
  onSubmit,
47
50
  placeholder = 'Type your message...',
48
51
  disabled = false,
49
- prompt = '> ',
50
52
  allowEmpty = false,
53
+ commands = DEFAULT_COMMANDS,
54
+ onCommand,
51
55
  }: ChatInputProps): React.ReactElement {
52
56
  const [value, setValue] = useState('');
57
+ const [showDropdown, setShowDropdown] = useState(false);
58
+
59
+ // Check if input is a slash command
60
+ const isSlashCommand = value.startsWith('/');
61
+ const commandFilter = isSlashCommand ? value.slice(1) : '';
53
62
 
54
63
  /**
55
64
  * Handle input submission
56
- * Calls onSubmit with current value and clears the input
57
65
  */
58
- const handleSubmit = (submittedValue: string): void => {
59
- // Don't submit when disabled
60
- if (disabled) {
61
- return;
62
- }
66
+ const handleSubmit = useCallback(
67
+ (submittedValue: string): void => {
68
+ if (disabled) return;
69
+
70
+ // Handle slash commands
71
+ if (submittedValue.startsWith('/') && onCommand) {
72
+ const cmdName = submittedValue.slice(1).trim().split(' ')[0];
73
+ if (cmdName) {
74
+ onCommand(cmdName);
75
+ setValue('');
76
+ setShowDropdown(false);
77
+ return;
78
+ }
79
+ }
63
80
 
64
- // Don't submit empty values unless allowEmpty is true
65
- if (!submittedValue.trim() && !allowEmpty) {
66
- return;
67
- }
81
+ // Don't submit empty values unless allowEmpty is true
82
+ if (!submittedValue.trim() && !allowEmpty) {
83
+ return;
84
+ }
68
85
 
69
- onSubmit(submittedValue);
70
- setValue('');
71
- };
86
+ onSubmit(submittedValue);
87
+ setValue('');
88
+ setShowDropdown(false);
89
+ },
90
+ [disabled, allowEmpty, onSubmit, onCommand]
91
+ );
72
92
 
73
93
  /**
74
94
  * Handle value changes
75
- * Only update if not disabled
76
95
  */
77
- const handleChange = (newValue: string): void => {
78
- if (!disabled) {
96
+ const handleChange = useCallback(
97
+ (newValue: string): void => {
98
+ if (disabled) return;
79
99
  setValue(newValue);
80
- }
81
- };
100
+
101
+ // Show dropdown when typing /
102
+ if (newValue.startsWith('/')) {
103
+ setShowDropdown(true);
104
+ } else {
105
+ setShowDropdown(false);
106
+ }
107
+ },
108
+ [disabled]
109
+ );
110
+
111
+ /**
112
+ * Handle command selection from dropdown
113
+ */
114
+ const handleCommandSelect = useCallback(
115
+ (cmdName: string) => {
116
+ if (onCommand) {
117
+ onCommand(cmdName);
118
+ } else {
119
+ // If no onCommand handler, just submit the command
120
+ onSubmit(`/${cmdName}`);
121
+ }
122
+ setValue('');
123
+ setShowDropdown(false);
124
+ },
125
+ [onCommand, onSubmit]
126
+ );
127
+
128
+ /**
129
+ * Handle dropdown cancel
130
+ */
131
+ const handleDropdownCancel = useCallback(() => {
132
+ setShowDropdown(false);
133
+ }, []);
82
134
 
83
135
  // When disabled, show a waiting message
84
136
  if (disabled) {
85
137
  return (
86
138
  <Box flexDirection="row">
87
139
  <Text dimColor color={colors.brown}>
88
- {prompt}[waiting for AI...]
140
+ [waiting for AI...]
89
141
  </Text>
90
142
  </Box>
91
143
  );
92
144
  }
93
145
 
94
146
  return (
95
- <Box flexDirection="row">
96
- <Text color={colors.yellow}>{prompt}</Text>
97
- <TextInput
98
- value={value}
99
- onChange={handleChange}
100
- onSubmit={handleSubmit}
101
- placeholder={placeholder}
102
- />
147
+ <Box flexDirection="column">
148
+ {/* Command dropdown */}
149
+ {showDropdown && isSlashCommand && (
150
+ <CommandDropdown
151
+ commands={commands}
152
+ filter={commandFilter}
153
+ onSelect={handleCommandSelect}
154
+ onCancel={handleDropdownCancel}
155
+ />
156
+ )}
157
+
158
+ {/* Input line */}
159
+ <Box flexDirection="row">
160
+ <Text color={colors.blue} bold>
161
+ ›{' '}
162
+ </Text>
163
+ <TextInput
164
+ value={value}
165
+ onChange={handleChange}
166
+ onSubmit={handleSubmit}
167
+ placeholder={placeholder}
168
+ />
169
+ </Box>
103
170
  </Box>
104
171
  );
105
172
  }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * CommandDropdown - Slash command autocomplete dropdown
3
+ *
4
+ * Shows available commands when user types "/" in the input.
5
+ * Supports arrow key navigation and Enter to select.
6
+ */
7
+
8
+ import React, { useState } from 'react';
9
+ import { Box, Text, useInput } from 'ink';
10
+ import { colors } from '../theme.js';
11
+
12
+ /**
13
+ * Command definition
14
+ */
15
+ export interface Command {
16
+ /** Command name (without /) */
17
+ name: string;
18
+ /** Description shown next to command */
19
+ description: string;
20
+ }
21
+
22
+ /**
23
+ * Props for the CommandDropdown component
24
+ */
25
+ export interface CommandDropdownProps {
26
+ /** Available commands */
27
+ commands: Command[];
28
+ /** Filter string (what user typed after /) */
29
+ filter: string;
30
+ /** Called when a command is selected */
31
+ onSelect: (command: string) => void;
32
+ /** Called when dropdown is dismissed (Escape) */
33
+ onCancel: () => void;
34
+ }
35
+
36
+ /**
37
+ * CommandDropdown component
38
+ *
39
+ * Displays a filtered list of available slash commands.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <CommandDropdown
44
+ * commands={[
45
+ * { name: 'init', description: 'Initialize a new CLAUDE.md file' },
46
+ * { name: 'new', description: 'Create a new feature spec' },
47
+ * ]}
48
+ * filter="in"
49
+ * onSelect={(cmd) => console.log('Selected:', cmd)}
50
+ * onCancel={() => setShowDropdown(false)}
51
+ * />
52
+ * ```
53
+ */
54
+ export function CommandDropdown({
55
+ commands,
56
+ filter,
57
+ onSelect,
58
+ onCancel,
59
+ }: CommandDropdownProps): React.ReactElement {
60
+ const [selectedIndex, setSelectedIndex] = useState(0);
61
+
62
+ // Filter commands based on input
63
+ const filteredCommands = commands.filter((cmd) =>
64
+ cmd.name.toLowerCase().includes(filter.toLowerCase())
65
+ );
66
+
67
+ // Handle keyboard input
68
+ useInput((input, key) => {
69
+ if (key.escape) {
70
+ onCancel();
71
+ return;
72
+ }
73
+
74
+ if (key.return && filteredCommands.length > 0) {
75
+ onSelect(filteredCommands[selectedIndex].name);
76
+ return;
77
+ }
78
+
79
+ if (key.upArrow) {
80
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
81
+ return;
82
+ }
83
+
84
+ if (key.downArrow) {
85
+ setSelectedIndex((prev) => Math.min(filteredCommands.length - 1, prev + 1));
86
+ return;
87
+ }
88
+ });
89
+
90
+ // Reset selection when filter changes
91
+ React.useEffect(() => {
92
+ setSelectedIndex(0);
93
+ }, [filter]);
94
+
95
+ if (filteredCommands.length === 0) {
96
+ return (
97
+ <Box paddingLeft={2}>
98
+ <Text dimColor>No matching commands</Text>
99
+ </Box>
100
+ );
101
+ }
102
+
103
+ return (
104
+ <Box flexDirection="column" paddingLeft={2}>
105
+ {filteredCommands.map((cmd, index) => {
106
+ const isSelected = index === selectedIndex;
107
+ return (
108
+ <Box key={cmd.name} flexDirection="row" gap={2}>
109
+ <Text color={isSelected ? colors.blue : colors.yellow}>
110
+ /{cmd.name}
111
+ </Text>
112
+ <Text color={isSelected ? colors.white : undefined} dimColor={!isSelected}>
113
+ {cmd.description}
114
+ </Text>
115
+ </Box>
116
+ );
117
+ })}
118
+ </Box>
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Default commands available in wiggum
124
+ */
125
+ export const DEFAULT_COMMANDS: Command[] = [
126
+ { name: 'init', description: 'Initialize project with CLAUDE.md' },
127
+ { name: 'new', description: 'Create a new feature specification' },
128
+ { name: 'run', description: 'Run a spec file with AI' },
129
+ { name: 'help', description: 'Show available commands' },
130
+ { name: 'clear', description: 'Clear conversation history' },
131
+ { name: 'exit', description: 'Exit wiggum' },
132
+ ];
@@ -1,11 +1,10 @@
1
1
  /**
2
- * MessageList - Scrollable conversation history display
2
+ * MessageList - Conversation history display
3
3
  *
4
- * Displays the full conversation history including:
5
- * - User messages
6
- * - Assistant messages (with optional streaming)
7
- * - System messages
8
- * - Tool call cards inline with assistant messages
4
+ * Displays the full conversation history with clean formatting:
5
+ * - User messages: › prefix
6
+ * - Assistant messages: ● bullet with clean markdown-like styling
7
+ * - Tool calls: Inline action indicators
9
8
  */
10
9
 
11
10
  import React from 'react';
@@ -57,13 +56,13 @@ export interface MessageListProps {
57
56
  }
58
57
 
59
58
  /**
60
- * Renders a single user message
59
+ * Renders a single user message with › prefix
61
60
  */
62
61
  function UserMessage({ content }: { content: string }): React.ReactElement {
63
62
  return (
64
63
  <Box flexDirection="row" marginY={1}>
65
- <Text color={colors.white} bold>
66
- You:{' '}
64
+ <Text color={colors.blue} bold>
65
+ {' '}
67
66
  </Text>
68
67
  <Text color={colors.white}>{content}</Text>
69
68
  </Box>
@@ -71,7 +70,7 @@ function UserMessage({ content }: { content: string }): React.ReactElement {
71
70
  }
72
71
 
73
72
  /**
74
- * Renders a single assistant message with optional tool calls and streaming
73
+ * Renders a single assistant message with prefix and tool calls
75
74
  */
76
75
  function AssistantMessage({
77
76
  content,
@@ -84,45 +83,46 @@ function AssistantMessage({
84
83
  }): React.ReactElement {
85
84
  return (
86
85
  <Box flexDirection="column" marginY={1}>
87
- {/* Tool calls appear before the message content */}
88
- {toolCalls &&
89
- toolCalls.length > 0 &&
90
- toolCalls.map((toolCall, index) => (
91
- <Box key={`tool-${index}`} marginBottom={1}>
86
+ {/* Tool calls appear first */}
87
+ {toolCalls && toolCalls.length > 0 && (
88
+ <Box flexDirection="column" marginBottom={1}>
89
+ {toolCalls.map((toolCall, index) => (
92
90
  <ToolCallCard
91
+ key={`tool-${index}`}
93
92
  toolName={toolCall.toolName}
94
93
  status={toolCall.status}
95
94
  input={toolCall.input}
96
95
  output={toolCall.output}
97
96
  error={toolCall.error}
98
97
  />
99
- </Box>
100
- ))}
98
+ ))}
99
+ </Box>
100
+ )}
101
101
 
102
- {/* Message content with prefix */}
103
- <Box flexDirection="row">
104
- <Text color={colors.yellow} bold>
105
- AI:{' '}
106
- </Text>
107
- {isStreaming ? (
108
- <StreamingText text={content} isStreaming={true} color={colors.yellow} />
109
- ) : (
110
- <Text color={colors.yellow}>{content}</Text>
111
- )}
112
- </Box>
102
+ {/* Message content with bullet prefix */}
103
+ {content && (
104
+ <Box flexDirection="row">
105
+ <Text color={colors.yellow}>●{' '}</Text>
106
+ <Box flexDirection="column" flexGrow={1}>
107
+ {isStreaming ? (
108
+ <StreamingText text={content} isStreaming={true} color={colors.yellow} />
109
+ ) : (
110
+ <Text color={colors.yellow}>{content}</Text>
111
+ )}
112
+ </Box>
113
+ </Box>
114
+ )}
113
115
  </Box>
114
116
  );
115
117
  }
116
118
 
117
119
  /**
118
- * Renders a system message (dimmed text)
120
+ * Renders a system message (dimmed, no prefix)
119
121
  */
120
122
  function SystemMessage({ content }: { content: string }): React.ReactElement {
121
123
  return (
122
- <Box flexDirection="row" marginY={1}>
123
- <Text color={colors.brown} dimColor>
124
- {content}
125
- </Text>
124
+ <Box marginY={1}>
125
+ <Text dimColor>{content}</Text>
126
126
  </Box>
127
127
  );
128
128
  }
@@ -130,35 +130,25 @@ function SystemMessage({ content }: { content: string }): React.ReactElement {
130
130
  /**
131
131
  * MessageList component
132
132
  *
133
- * Displays the full conversation history. Each message type has
134
- * distinct styling:
135
- * - User messages: "You: " prefix in white
136
- * - Assistant messages: "AI: " prefix in yellow, with inline tool cards
137
- * - System messages: dimmed brown text
138
- *
139
- * For streaming messages, uses the StreamingText component to show
140
- * the cursor indicator.
133
+ * Displays the full conversation history with clean styling:
134
+ * - User messages: `› ` prefix in blue
135
+ * - Assistant messages: `● ` prefix in yellow, with inline tool cards
136
+ * - System messages: dimmed text
141
137
  *
142
138
  * @example
143
139
  * ```tsx
144
140
  * <MessageList
145
141
  * messages={[
146
- * { id: '1', role: 'system', content: 'Interview started' },
147
- * { id: '2', role: 'assistant', content: 'Hello! What would you like to build?' },
148
- * { id: '3', role: 'user', content: 'A todo app' },
149
- * { id: '4', role: 'assistant', content: 'Let me check...',
150
- * toolCalls: [{ toolName: 'Read File', status: 'running', input: 'package.json' }],
151
- * isStreaming: true
152
- * },
142
+ * { id: '1', role: 'user', content: 'Hello' },
143
+ * { id: '2', role: 'assistant', content: 'Hi! How can I help?' },
153
144
  * ]}
154
145
  * />
146
+ * // Renders:
147
+ * // › Hello
148
+ * // ● Hi! How can I help?
155
149
  * ```
156
150
  */
157
151
  export function MessageList({ messages, maxHeight }: MessageListProps): React.ReactElement {
158
- // Note: maxHeight is accepted for future scrolling support
159
- // Currently renders all messages - parent handles any scroll-like behavior
160
- // by controlling which messages are passed in
161
-
162
152
  return (
163
153
  <Box
164
154
  flexDirection="column"
@@ -20,6 +20,9 @@ export type { MessageListProps, Message, ToolCall } from './MessageList.js';
20
20
  export { ChatInput } from './ChatInput.js';
21
21
  export type { ChatInputProps } from './ChatInput.js';
22
22
 
23
+ export { CommandDropdown, DEFAULT_COMMANDS } from './CommandDropdown.js';
24
+ export type { CommandDropdownProps, Command } from './CommandDropdown.js';
25
+
23
26
  export { Select } from './Select.js';
24
27
  export type { SelectProps, SelectOption } from './Select.js';
25
28
 
@@ -282,7 +282,7 @@ export function MainShell({
282
282
  onSubmit={handleSubmit}
283
283
  disabled={false}
284
284
  placeholder="Enter command or type /help..."
285
- prompt="wiggum> "
285
+ onCommand={(cmd) => handleSubmit(`/${cmd}`)}
286
286
  />
287
287
  </Box>
288
288
  </Box>