snow-ai 0.3.24 → 0.3.26

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.
@@ -75,6 +75,12 @@ const SYSTEM_PROMPT_TEMPLATE = `You are Snow AI CLI, an intelligent command-line
75
75
 
76
76
  ## 🚀 Execution Strategy - BALANCE ACTION & ANALYSIS
77
77
 
78
+ ## 🤖 Rigorous coding habits
79
+ - In any programming language or business logic, which is usually accompanied by many-to-many references to files, you also need to think about the impact of the modification and whether it will conflict with the user's original business.
80
+ - Using the optimal solution principle, you cannot choose risk scenarios such as hardcoding, logic simplification, etc., unless the user asks you to do so.
81
+ - Avoid duplication, users may have encapsulated some reusable functions, and you should try to find them instead of creating a new function right away.
82
+ - Compilable principle, you should not have low-level errors such as syntax errors, use tools to check for syntax errors, non-compilable code is meaningless.
83
+
78
84
  ### ⚡ Smart Action Mode
79
85
  **Principle: Understand enough to code correctly, but don't over-investigate**
80
86
 
@@ -95,38 +101,30 @@ const SYSTEM_PROMPT_TEMPLATE = `You are Snow AI CLI, an intelligent command-line
95
101
 
96
102
  **Golden Rule: Read what you need to write correct code, nothing more.**
97
103
 
98
- ### 📋 TODO Lists - Essential for Programming Tasks
99
-
100
- **✅ ALWAYS CREATE TODO WHEN encountering programming tasks:**
101
- - Any code implementation task (new features, bug fixes, refactoring)
102
- - Tasks involving multiple steps or files
103
- - When you need to track progress and ensure completion
104
- - To give users clear visibility into your work plan
105
-
106
- **TODO Guidelines:**
107
- 1. **Create Early**: Set up TODO list BEFORE starting implementation
108
- 2. **Be Specific**: Each item should be a concrete action
109
- 3. **Update Immediately**: Mark as completed immediately after finishing each task
110
- 4. **Focus on Completion**: Move from pending to completed, no intermediate states
111
-
112
- **TODO = Action List, NOT Investigation Plan**
113
- - "Create AuthService with login/logout methods"
114
- - "Add validation to UserForm component"
115
- - "Fix timeout bug in parser.ts"
116
- - ✅ "Update API routes to use new auth middleware"
117
- - ✅ "Run build and fix any errors"
118
- - "Read authentication files"
119
- - "Analyze current implementation"
120
- - ❌ "Investigate error handling patterns"
121
-
122
- **CRITICAL: Update TODO status IMMEDIATELY after completing each task!**
123
-
124
- **Workflow Example:**
125
- 1. User asks to add feature → Create TODO list immediately
126
- 2. Complete the first task → Mark as completed
127
- 3. Move to next task → Complete and mark as completed
128
- 4. Repeat until all tasks completed
129
- 5. Focus on getting tasks done rather than tracking intermediate states
104
+ ### 📋 TODO Management - For Complex Programming Tasks
105
+
106
+ **🚫 CRITICAL: TODO tools MUST be called in parallel with other tools - NEVER call TODO tools alone!**
107
+
108
+ **When to use TODO:**
109
+ - Complex tasks with 5+ steps requiring tracking
110
+ - Multi-file implementations needing coordination
111
+ - User explicitly requests TODO
112
+
113
+ **When to skip TODO:**
114
+ - Simple 1-3 step tasks (just do them)
115
+ - Single file edits or quick fixes
116
+
117
+ **Usage rules:**
118
+ 1. **Parallel calls only**: Always combine TODO with action tools (filesystem-edit, etc.)
119
+ 2. **Action-focused**: "Fix parser.ts timeout" ✅, "Read parser.ts"
120
+ 3. **Update immediately**: Mark completed right after task is done
121
+ 4. **Keep minimal**: 3-7 tasks max, avoid over-planning
122
+
123
+ **Example workflow:**
124
+ - CORRECT: Call todo-create with filesystem-edit in parallel
125
+ - CORRECT: Call todo-update with filesystem-edit in parallel
126
+ - ❌ WRONG: Call todo-create alone, then wait, then call filesystem-edit
127
+ - ❌ WRONG: Call todo-update alone, then wait, then proceed
130
128
 
131
129
  ## 🛠️ Available Tools
132
130
 
package/dist/cli.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ import './utils/patch-highlight.js';
package/dist/cli.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ // CRITICAL: Patch cli-highlight BEFORE any other imports
3
+ // This must be the first import to ensure the patch is applied before cli-markdown loads
4
+ import './utils/patch-highlight.js';
2
5
  import React from 'react';
3
6
  import { render, Text, Box } from 'ink';
4
7
  import Spinner from 'ink-spinner';
@@ -19,6 +19,7 @@ type CommandHandlerOptions = {
19
19
  setShowMcpInfo: React.Dispatch<React.SetStateAction<boolean>>;
20
20
  setShowMcpPanel: React.Dispatch<React.SetStateAction<boolean>>;
21
21
  setShowUsagePanel: React.Dispatch<React.SetStateAction<boolean>>;
22
+ setShowHelpPanel: React.Dispatch<React.SetStateAction<boolean>>;
22
23
  setMcpPanelKey: React.Dispatch<React.SetStateAction<number>>;
23
24
  setYoloMode: React.Dispatch<React.SetStateAction<boolean>>;
24
25
  setContextUsage: React.Dispatch<React.SetStateAction<UsageInfo | null>>;
@@ -45,7 +45,8 @@ export async function executeContextCompression() {
45
45
  timestamp: Date.now(),
46
46
  });
47
47
  // 添加保留的最后一轮完整对话(保留完整的消息结构)
48
- if (compressionResult.preservedMessages && compressionResult.preservedMessages.length > 0) {
48
+ if (compressionResult.preservedMessages &&
49
+ compressionResult.preservedMessages.length > 0) {
49
50
  for (const msg of compressionResult.preservedMessages) {
50
51
  // 保留完整的消息结构,包括所有关键字段
51
52
  newSessionMessages.push({
@@ -56,7 +57,9 @@ export async function executeContextCompression() {
56
57
  ...(msg.tool_calls && { tool_calls: msg.tool_calls }),
57
58
  ...(msg.images && { images: msg.images }),
58
59
  ...(msg.reasoning && { reasoning: msg.reasoning }),
59
- ...(msg.subAgentInternal !== undefined && { subAgentInternal: msg.subAgentInternal }),
60
+ ...(msg.subAgentInternal !== undefined && {
61
+ subAgentInternal: msg.subAgentInternal,
62
+ }),
60
63
  });
61
64
  }
62
65
  }
@@ -220,6 +223,15 @@ export function useCommandHandler(options) {
220
223
  };
221
224
  options.setMessages(prev => [...prev, commandMessage]);
222
225
  }
226
+ else if (result.success && result.action === 'showHelpPanel') {
227
+ options.setShowHelpPanel(true);
228
+ const commandMessage = {
229
+ role: 'command',
230
+ content: '',
231
+ commandName: commandName,
232
+ };
233
+ options.setMessages(prev => [...prev, commandMessage]);
234
+ }
223
235
  else if (result.success && result.action === 'home') {
224
236
  // Reset terminal before navigating to welcome screen
225
237
  resetTerminal(stdout);
@@ -284,7 +296,10 @@ export function useCommandHandler(options) {
284
296
  return;
285
297
  }
286
298
  // Generate default filename with timestamp
287
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
299
+ const timestamp = new Date()
300
+ .toISOString()
301
+ .replace(/[:.]/g, '-')
302
+ .split('.')[0];
288
303
  const defaultFilename = `snow-chat-${timestamp}.txt`;
289
304
  // Show native save dialog
290
305
  const filePath = await showSaveDialog(defaultFilename, 'Export Chat Conversation');
@@ -1,6 +1,7 @@
1
1
  import { useState, useCallback } from 'react';
2
2
  // Command Definition
3
3
  const commands = [
4
+ { name: 'help', description: 'Show keyboard shortcuts and help information' },
4
5
  { name: 'clear', description: 'Clear chat context and conversation history' },
5
6
  { name: 'resume', description: 'Resume a conversation' },
6
7
  { name: 'mcp', description: 'Show Model Context Protocol services and tools' },
package/dist/mcp/todo.js CHANGED
@@ -270,15 +270,7 @@ This REPLACES the entire TODO list. Never use it to "add more tasks" - use "todo
270
270
  },
271
271
  {
272
272
  name: 'todo-get',
273
- description: `Get the current TODO list for this session.
274
-
275
- ## WHEN TO USE:
276
- - Before making any updates to check current task status and IDs
277
- - To verify what tasks exist before deciding to add/delete/update
278
- - To inspect the TODO structure before planning next steps
279
-
280
- ## RETURNS:
281
- Complete TODO list with all task IDs, content, status, and hierarchy.`,
273
+ description: `Get current TODO list with task IDs, status, and hierarchy. Call with other tools in parallel when needed.`,
282
274
  inputSchema: {
283
275
  type: 'object',
284
276
  properties: {},
@@ -286,26 +278,7 @@ Complete TODO list with all task IDs, content, status, and hierarchy.`,
286
278
  },
287
279
  {
288
280
  name: 'todo-update',
289
- description: `Update TODO status or content - USE ONLY WHEN COMPLETING TASKS.
290
-
291
- ## CORE PRINCIPLE - WORK FIRST, completed in an orderly manner:
292
-
293
- ## STATUS MODEL:
294
- - **pending**: Task not yet completed (default)
295
- - **completed**: Task is 100% finished and verified
296
-
297
- ## WHEN TO UPDATE:
298
- ✅ **Mark "completed"** ONLY when:
299
- - When completing a task in the List
300
- - No errors or blockers
301
- - You've actually verified it works
302
-
303
- ## WHEN NOT TO UPDATE:
304
- ❌ Don't update status to track "in progress" - just do the work
305
- ❌ Don't update before verifying the work is complete
306
-
307
- ## BEST PRACTICE:
308
- Every time you complete a task in Task, it will be updated to "Completed" immediately.`,
281
+ description: `Update TODO status/content. MUST call with other tools - mark "completed" ONLY after task is verified and done.`,
309
282
  inputSchema: {
310
283
  type: 'object',
311
284
  properties: {
@@ -328,24 +301,7 @@ Every time you complete a task in Task, it will be updated to "Completed" immedi
328
301
  },
329
302
  {
330
303
  name: 'todo-add',
331
- description: `Add tasks to existing TODO list (use sparingly).
332
-
333
- ## CORE PRINCIPLE - AVOID TODO BLOAT:
334
- Don't constantly add TODO items while working. If you discover small steps during execution, JUST DO THEM instead of creating TODO items. Only add to TODO if it's genuinely complex or user-requested.
335
-
336
- ## WHEN TO USE (Rare):
337
- 1. **User Adds Requirements**: User explicitly requests additional tasks
338
- 2. **Major Discovery**: You find a significant, complex step that wasn't initially planned
339
- 3. **Blocking Issue**: You discover a prerequisite that requires substantial separate work
340
-
341
- ## WHEN NOT TO USE (Common):
342
- - ❌ Discovered a small 5-minute task while working (just do it, don't track it)
343
- - ❌ Breaking down an existing task into micro-steps (over-planning)
344
- - ❌ "Organizing" or "clarifying" existing tasks (maintain original structure)
345
- - ❌ New unrelated requirement (use todo-delete + todo-create instead)
346
-
347
- ## GUIDELINE:
348
- If a task takes less than 10 minutes, just do it instead of adding it to TODO. The goal is progress, not perfect tracking.`,
304
+ description: `Add task to existing TODO (rare use). MUST call with other tools. Only for user-requested or complex tasks, not small steps.`,
349
305
  inputSchema: {
350
306
  type: 'object',
351
307
  properties: {
@@ -363,27 +319,7 @@ If a task takes less than 10 minutes, just do it instead of adding it to TODO. T
363
319
  },
364
320
  {
365
321
  name: 'todo-delete',
366
- description: `Delete TODO items from the current session.
367
-
368
- ## WHEN TO USE:
369
- 1. **Task No Longer Needed**: Requirement changed, task became irrelevant
370
- 2. **Mistake Correction**: Task was added by error or duplicated
371
- 3. **Clearing for New Requirement**: User provides COMPLETELY NEW requirement - delete all old todos first, then create new list
372
- 4. **Cascade Deletion**: Delete parent task with subtasks (automatically removes children)
373
-
374
- ## LIFECYCLE PATTERN FOR NEW REQUIREMENTS:
375
- When user asks for something completely different:
376
- 1. Use todo-get to see current list
377
- 2. Use todo-delete on root items (children auto-delete via parentId cascade)
378
- 3. Use todo-create for the new requirement
379
-
380
- ## WHEN NOT TO USE:
381
- - Do NOT delete completed tasks just for "cleanup" (keep as history)
382
- - Do NOT delete in-progress tasks unless requirement truly changed
383
- - Do NOT use for "reorganizing" (maintain original structure)
384
-
385
- ## CASCADE BEHAVIOR:
386
- Deleting a parent task automatically deletes all its subtasks (parentId relationship).`,
322
+ description: `Delete TODO item. MUST call with other tools. Deleting parent auto-deletes children (cascade).`,
387
323
  inputSchema: {
388
324
  type: 'object',
389
325
  properties: {
@@ -354,15 +354,13 @@ export default function ChatInput({ onSubmit, onCommand, placeholder = 'Type you
354
354
  ' ',
355
355
  "cached"))))));
356
356
  })()))),
357
- React.createElement(Box, { marginTop: 1 },
357
+ (showCommands && getFilteredCommands().length > 0) ||
358
+ showFilePicker ? (React.createElement(Box, { marginTop: 1 },
358
359
  React.createElement(Text, null, showCommands && getFilteredCommands().length > 0
359
360
  ? 'Type to filter commands'
360
361
  : showFilePicker
361
362
  ? searchMode === 'content'
362
363
  ? 'Content search • Tab/Enter to select • ESC to cancel'
363
364
  : 'Type to filter files • Tab/Enter to select • ESC to cancel'
364
- : (() => {
365
- const pasteKey = process.platform === 'darwin' ? 'Ctrl+V' : 'Alt+V';
366
- return `Ctrl+L: delete to start • Ctrl+R: delete to end • ${pasteKey}: paste images • '@': files • '@@': search content • '/': commands`;
367
- })()))))));
365
+ : ''))) : null))));
368
366
  }
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export default function HelpPanel(): React.JSX.Element;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ // Get platform-specific paste key
4
+ const getPasteKey = () => {
5
+ return process.platform === 'darwin' ? 'Ctrl+V' : 'Alt+V';
6
+ };
7
+ export default function HelpPanel() {
8
+ const pasteKey = getPasteKey();
9
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 },
10
+ React.createElement(Box, { marginBottom: 1 },
11
+ React.createElement(Text, { bold: true, color: "cyan" }, "\uD83D\uDD30 Keyboard Shortcuts & Help")),
12
+ React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
13
+ React.createElement(Text, { bold: true, color: "yellow" }, "\uD83D\uDCDD Text Editing:"),
14
+ React.createElement(Text, null, " \u2022 Ctrl+L - Delete from cursor to start"),
15
+ React.createElement(Text, null, " \u2022 Ctrl+R - Delete from cursor to end"),
16
+ React.createElement(Text, null,
17
+ " \u2022 ",
18
+ pasteKey,
19
+ " - Paste images from clipboard")),
20
+ React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
21
+ React.createElement(Text, { bold: true, color: "green" }, "\uD83D\uDD0D Quick Access:"),
22
+ React.createElement(Text, null, " \u2022 @ - Insert files from project"),
23
+ React.createElement(Text, null, " \u2022 @@ - Search file content"),
24
+ React.createElement(Text, null, " \u2022 / - Show available commands")),
25
+ React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
26
+ React.createElement(Text, { bold: true, color: "blue" }, "\uD83D\uDCCB Navigation:"),
27
+ React.createElement(Text, null, " \u2022 \u2191/\u2193 - Navigate command/message history"),
28
+ React.createElement(Text, null, " \u2022 Tab/Enter - Select item in pickers"),
29
+ React.createElement(Text, null, " \u2022 ESC - Cancel/close pickers or interrupt AI response"),
30
+ React.createElement(Text, null, " \u2022 Shift+Tab - Toggle YOLO mode (auto-approve tools)")),
31
+ React.createElement(Box, { flexDirection: "column" },
32
+ React.createElement(Text, { bold: true, color: "magenta" }, "\uD83D\uDCA1 Tips:"),
33
+ React.createElement(Text, null, " \u2022 Use /help anytime to see this information"),
34
+ React.createElement(Text, null, " \u2022 Type / to see all available commands"),
35
+ React.createElement(Text, null, " \u2022 Press ESC during AI response to interrupt")),
36
+ React.createElement(Box, { marginTop: 1 },
37
+ React.createElement(Text, { dimColor: true, color: "gray" }, "Press ESC to close this help panel"))));
38
+ }
@@ -1,31 +1,23 @@
1
1
  import React from 'react';
2
- import { Text } from 'ink';
3
- import { highlight } from 'cli-highlight';
2
+ import { Text, Box } from 'ink';
4
3
  // @ts-expect-error - cli-markdown doesn't have TypeScript definitions
5
4
  import cliMarkdown from 'cli-markdown';
5
+ import logger from '../../utils/logger.js';
6
6
  export default function MarkdownRenderer({ content }) {
7
7
  // Use cli-markdown for elegant markdown rendering with syntax highlighting
8
- const rendered = cliMarkdown(content, {
9
- // Enable syntax highlighting for code blocks
10
- code: (code, language) => {
11
- if (!language)
12
- return code;
13
- try {
14
- return highlight(code, { language, ignoreIllegals: true });
15
- }
16
- catch {
17
- return code;
18
- }
19
- },
20
- });
21
- // Remove excessive trailing newlines and whitespace from cli-markdown output
22
- // Keep single blank lines for paragraph spacing (better readability)
23
- const trimmedRendered = rendered
24
- .split('\n')
25
- .map((line) => line.trimEnd()) // Remove trailing spaces from each line
26
- .join('\n')
27
- .replace(/\n{3,}/g, '\n\n') // Replace 3+ consecutive newlines with 2 (paragraph spacing)
28
- .replace(/^\n+/g, '') // Remove leading newlines
29
- .replace(/\n+$/g, ''); // Remove trailing newlines
30
- return React.createElement(Text, null, trimmedRendered);
8
+ // The patched highlight function will gracefully handle unknown languages
9
+ const rendered = cliMarkdown(content);
10
+ // Split into lines and render each separately
11
+ // This prevents Ink's Text component from creating mysterious whitespace
12
+ // when handling multi-line content with \n characters
13
+ const lines = rendered.split('\n');
14
+ // Safety check: prevent rendering issues with excessively long output
15
+ if (lines.length > 500) {
16
+ logger.warn('[MarkdownRenderer] Rendered output has too many lines', {
17
+ totalLines: lines.length,
18
+ truncatedTo: 500,
19
+ });
20
+ return (React.createElement(Box, { flexDirection: "column" }, lines.slice(0, 500).map((line, index) => (React.createElement(Text, { key: index }, line)))));
21
+ }
22
+ return (React.createElement(Box, { flexDirection: "column" }, lines.map((line, index) => (React.createElement(Text, { key: index }, line)))));
31
23
  }
@@ -20,7 +20,7 @@ export default function TodoTree({ todos }) {
20
20
  const getStatusIcon = (status) => {
21
21
  switch (status) {
22
22
  case 'completed':
23
- return '[x]';
23
+ return '[]';
24
24
  case 'pending':
25
25
  return '[ ]';
26
26
  }
@@ -52,5 +52,5 @@ export default function TodoTree({ todos }) {
52
52
  React.createElement(Text, { bold: true, color: "cyan" }, "TODO List")),
53
53
  rootTodos.map(todo => renderTodo(todo)),
54
54
  React.createElement(Box, { marginTop: 0 },
55
- React.createElement(Text, { dimColor: true, color: "gray" }, "[ ] Pending \u00B7 [x] Completed"))));
55
+ React.createElement(Text, { dimColor: true, color: "gray" }, "[ ] Pending \u00B7 [\u2713] Completed"))));
56
56
  }
@@ -13,6 +13,7 @@ import '../../utils/commands/usage.js';
13
13
  import '../../utils/commands/export.js';
14
14
  import '../../utils/commands/agent.js';
15
15
  import '../../utils/commands/todoPicker.js';
16
+ import '../../utils/commands/help.js';
16
17
  type Props = {
17
18
  skipWelcome?: boolean;
18
19
  };
@@ -9,6 +9,7 @@ import MCPInfoScreen from '../components/MCPInfoScreen.js';
9
9
  import MCPInfoPanel from '../components/MCPInfoPanel.js';
10
10
  import SessionListPanel from '../components/SessionListPanel.js';
11
11
  import UsagePanel from '../components/UsagePanel.js';
12
+ import HelpPanel from '../components/HelpPanel.js';
12
13
  import MarkdownRenderer from '../components/MarkdownRenderer.js';
13
14
  import ToolConfirmation from '../components/ToolConfirmation.js';
14
15
  import DiffViewer from '../components/DiffViewer.js';
@@ -46,6 +47,7 @@ import '../../utils/commands/usage.js';
46
47
  import '../../utils/commands/export.js';
47
48
  import '../../utils/commands/agent.js';
48
49
  import '../../utils/commands/todoPicker.js';
50
+ import '../../utils/commands/help.js';
49
51
  export default function ChatScreen({ skipWelcome }) {
50
52
  const [messages, setMessages] = useState([]);
51
53
  const [isSaving] = useState(false);
@@ -77,6 +79,7 @@ export default function ChatScreen({ skipWelcome }) {
77
79
  const [showSessionPanel, setShowSessionPanel] = useState(false);
78
80
  const [showMcpPanel, setShowMcpPanel] = useState(false);
79
81
  const [showUsagePanel, setShowUsagePanel] = useState(false);
82
+ const [showHelpPanel, setShowHelpPanel] = useState(false);
80
83
  const [restoreInputContent, setRestoreInputContent] = useState(null);
81
84
  const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
82
85
  const { stdout } = useStdout();
@@ -188,6 +191,7 @@ export default function ChatScreen({ skipWelcome }) {
188
191
  setShowMcpInfo,
189
192
  setShowMcpPanel,
190
193
  setShowUsagePanel,
194
+ setShowHelpPanel,
191
195
  setMcpPanelKey,
192
196
  setYoloMode,
193
197
  setContextUsage: streamingState.setContextUsage,
@@ -256,6 +260,12 @@ export default function ChatScreen({ skipWelcome }) {
256
260
  }
257
261
  return;
258
262
  }
263
+ if (showHelpPanel) {
264
+ if (key.escape) {
265
+ setShowHelpPanel(false);
266
+ }
267
+ return;
268
+ }
259
269
  if (showMcpInfo) {
260
270
  if (key.escape) {
261
271
  setShowMcpInfo(false);
@@ -889,7 +899,11 @@ export default function ChatScreen({ skipWelcome }) {
889
899
  React.createElement(Text, null, "\u2022 Ask for code explanations and debugging help"),
890
900
  React.createElement(Text, null, "\u2022 Press ESC during response to interrupt"),
891
901
  React.createElement(Text, null, "\u2022 Press Shift+Tab: toggle YOLO"),
892
- React.createElement(Text, null,
902
+ React.createElement(Text, null, (() => {
903
+ const pasteKey = process.platform === 'darwin' ? 'Ctrl+V' : 'Alt+V';
904
+ return `• Shortcuts: Ctrl+L (delete to start) • Ctrl+R (delete to end) • ${pasteKey} (paste images) • '@' (files) • '@@' (search content) • '/' (commands)`;
905
+ })()),
906
+ React.createElement(Text, { color: "gray", dimColor: true },
893
907
  "\u2022 Working directory: ",
894
908
  workingDirectory)))),
895
909
  ...messages
@@ -1069,12 +1083,15 @@ export default function ChatScreen({ skipWelcome }) {
1069
1083
  React.createElement(UsagePanel, null),
1070
1084
  React.createElement(Box, { marginTop: 1 },
1071
1085
  React.createElement(Text, { color: "gray", dimColor: true }, "Press ESC to close")))),
1086
+ showHelpPanel && (React.createElement(Box, { paddingX: 1, flexDirection: "column", width: terminalWidth },
1087
+ React.createElement(HelpPanel, null))),
1072
1088
  snapshotState.pendingRollback && (React.createElement(FileRollbackConfirmation, { fileCount: snapshotState.pendingRollback.fileCount, filePaths: snapshotState.pendingRollback.filePaths || [], onConfirm: handleRollbackConfirm })),
1073
1089
  !pendingToolConfirmation &&
1074
1090
  !isCompressing &&
1075
1091
  !showSessionPanel &&
1076
1092
  !showMcpPanel &&
1077
1093
  !showUsagePanel &&
1094
+ !showHelpPanel &&
1078
1095
  !snapshotState.pendingRollback && (React.createElement(React.Fragment, null,
1079
1096
  React.createElement(ChatInput, { onSubmit: handleMessageSubmit, onCommand: handleCommandExecution, placeholder: "Ask me anything about coding...", disabled: !!pendingToolConfirmation, isProcessing: streamingState.isStreaming || isSaving, chatHistory: messages, onHistorySelect: handleHistorySelect, yoloMode: yoloMode, contextUsage: streamingState.contextUsage
1080
1097
  ? {
@@ -1,7 +1,7 @@
1
1
  export interface CommandResult {
2
2
  success: boolean;
3
3
  message?: string;
4
- action?: 'clear' | 'resume' | 'info' | 'showMcpInfo' | 'toggleYolo' | 'initProject' | 'compact' | 'showSessionPanel' | 'showMcpPanel' | 'showUsagePanel' | 'home' | 'review' | 'exportChat' | 'showAgentPicker' | 'showTodoPicker';
4
+ action?: 'clear' | 'resume' | 'info' | 'showMcpInfo' | 'toggleYolo' | 'initProject' | 'compact' | 'showSessionPanel' | 'showMcpPanel' | 'showUsagePanel' | 'home' | 'review' | 'exportChat' | 'showAgentPicker' | 'showTodoPicker' | 'showHelpPanel';
5
5
  prompt?: string;
6
6
  alreadyConnected?: boolean;
7
7
  }
@@ -0,0 +1,2 @@
1
+ declare const _default: {};
2
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import { registerCommand } from '../commandExecutor.js';
2
+ // Help command handler - show keyboard shortcuts and help information
3
+ registerCommand('help', {
4
+ execute: () => {
5
+ return {
6
+ success: true,
7
+ action: 'showHelpPanel',
8
+ };
9
+ },
10
+ });
11
+ export default {};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Patch cli-highlight to gracefully handle unknown languages
3
+ * This must be loaded BEFORE any modules that use cli-highlight
4
+ */
5
+ export {};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Patch cli-highlight to gracefully handle unknown languages
3
+ * This must be loaded BEFORE any modules that use cli-highlight
4
+ */
5
+ import { createRequire } from 'node:module';
6
+ const require = createRequire(import.meta.url);
7
+ const cliHighlightModule = require('cli-highlight');
8
+ const originalHighlight = cliHighlightModule.highlight;
9
+ // Override the highlight function to handle unknown languages gracefully
10
+ cliHighlightModule.highlight = function (code, options) {
11
+ try {
12
+ return originalHighlight(code, options);
13
+ }
14
+ catch (error) {
15
+ // If the error is about an unknown language, return the original code without highlighting
16
+ if (error?.message?.includes('Unknown language') ||
17
+ error?.message?.includes('Could not find the language')) {
18
+ return code;
19
+ }
20
+ // Re-throw other unexpected errors
21
+ throw error;
22
+ }
23
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.3.24",
3
+ "version": "0.3.26",
4
4
  "description": "Intelligent Command Line Assistant powered by AI",
5
5
  "license": "MIT",
6
6
  "bin": {