snow-ai 0.3.25 → 0.3.27
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.
- package/dist/api/systemPrompt.js +50 -32
- package/dist/hooks/useCommandHandler.d.ts +1 -0
- package/dist/hooks/useCommandHandler.js +18 -3
- package/dist/hooks/useCommandPanel.js +35 -2
- package/dist/mcp/todo.js +66 -82
- package/dist/ui/components/ChatInput.js +3 -5
- package/dist/ui/components/HelpPanel.d.ts +2 -0
- package/dist/ui/components/HelpPanel.js +38 -0
- package/dist/ui/components/MarkdownRenderer.js +15 -11
- package/dist/ui/components/TodoTree.js +4 -2
- package/dist/ui/pages/ChatScreen.d.ts +1 -0
- package/dist/ui/pages/ChatScreen.js +18 -1
- package/dist/utils/commandExecutor.d.ts +1 -1
- package/dist/utils/commands/help.d.ts +2 -0
- package/dist/utils/commands/help.js +11 -0
- package/package.json +1 -1
package/dist/api/systemPrompt.js
CHANGED
|
@@ -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,50 @@ 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
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
|
|
106
|
-
**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- ✅
|
|
114
|
-
- ✅
|
|
115
|
-
- ✅
|
|
116
|
-
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
104
|
+
### 📋 TODO Management - STRONGLY RECOMMENDED for Better Results!
|
|
105
|
+
|
|
106
|
+
**🎯 DEFAULT BEHAVIOR: Use TODO for ALL multi-step tasks (3+ steps)**
|
|
107
|
+
|
|
108
|
+
**✨ WHY TODO IS ESSENTIAL:**
|
|
109
|
+
- 📊 **Track progress** - Never lose your place in complex work
|
|
110
|
+
- ✅ **Ensure completeness** - Verify all steps are done
|
|
111
|
+
- 🎯 **Stay focused** - Clear roadmap prevents confusion
|
|
112
|
+
- 💪 **Build confidence** - Users see structured progress
|
|
113
|
+
- 🚀 **Better quality** - Systematic approach reduces errors
|
|
114
|
+
|
|
115
|
+
**⚡ WHEN TO USE TODO (Default for most tasks):**
|
|
116
|
+
- ✅ **ANY multi-file modification** (always use)
|
|
117
|
+
- ✅ **ANY feature implementation** (always use)
|
|
118
|
+
- ✅ **ANY refactoring task** (always use)
|
|
119
|
+
- ✅ **Bug fixes touching 2+ files** (recommended)
|
|
120
|
+
- ✅ **User requests with multiple requirements** (always use)
|
|
121
|
+
- ✅ **Unfamiliar codebase changes** (recommended)
|
|
122
|
+
- ⚠️ **SKIP ONLY for**: Single-file trivial edits (1-2 lines)
|
|
123
|
+
|
|
124
|
+
**🔧 USAGE RULES (Critical):**
|
|
125
|
+
1. **⚠️ PARALLEL CALLS ONLY**: ALWAYS call TODO tools with action tools in the SAME function call block
|
|
126
|
+
2. **Immediate updates**: Mark completed while performing work (not after)
|
|
127
|
+
3. **Right sizing**: 3-7 main tasks, add subtasks if needed
|
|
128
|
+
4. **Lifecycle Management**:
|
|
129
|
+
- New task = Create TODO at start
|
|
130
|
+
- Major requirement change = Delete old + create new
|
|
131
|
+
- Minor adjustment = Use todo-add or todo-update
|
|
132
|
+
- **CRITICAL**: Keep using TODO throughout the entire conversation!
|
|
133
|
+
|
|
134
|
+
**✅ CORRECT PATTERNS (Do this):**
|
|
135
|
+
- ✅ todo-create + filesystem-read → Plan while gathering info
|
|
136
|
+
- ✅ todo-update(completed) + filesystem-edit → Update as you work
|
|
137
|
+
- ✅ todo-get + filesystem-read → Check status while reading
|
|
138
|
+
- ✅ todo-add + filesystem-edit → Add new task while working
|
|
139
|
+
|
|
140
|
+
**❌ FORBIDDEN PATTERNS (NEVER do this - WILL FAIL):**
|
|
141
|
+
- ❌ todo-create alone, wait for result, then work → VIOLATION! Call together!
|
|
142
|
+
- ❌ todo-update alone, wait, then continue → VIOLATION! Update while working!
|
|
143
|
+
- ❌ todo-get alone just to check → VIOLATION! Call with other tools!
|
|
144
|
+
- ❌ Skipping TODO for multi-file tasks → VIOLATION! Always use TODO!
|
|
145
|
+
- ❌ **Abandoning TODO mid-conversation** → VIOLATION! Keep using throughout dialogue!
|
|
146
|
+
|
|
147
|
+
**💡 BEST PRACTICE: Start every non-trivial task with todo-create + initial action in parallel!**
|
|
130
148
|
|
|
131
149
|
## 🛠️ Available Tools
|
|
132
150
|
|
|
@@ -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 &&
|
|
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 && {
|
|
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()
|
|
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' },
|
|
@@ -52,8 +53,40 @@ export function useCommandPanel(buffer, isProcessing = false) {
|
|
|
52
53
|
if (!text.startsWith('/'))
|
|
53
54
|
return [];
|
|
54
55
|
const query = text.slice(1).toLowerCase();
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
// Filter and sort commands by priority
|
|
57
|
+
// Priority order:
|
|
58
|
+
// 1. Command starts with query (highest)
|
|
59
|
+
// 2. Command contains query
|
|
60
|
+
// 3. Description starts with query
|
|
61
|
+
// 4. Description contains query (lowest)
|
|
62
|
+
const filtered = commands
|
|
63
|
+
.filter(command => command.name.toLowerCase().includes(query) ||
|
|
64
|
+
command.description.toLowerCase().includes(query))
|
|
65
|
+
.map(command => {
|
|
66
|
+
const nameLower = command.name.toLowerCase();
|
|
67
|
+
const descLower = command.description.toLowerCase();
|
|
68
|
+
let priority = 4; // Default: description contains query
|
|
69
|
+
if (nameLower.startsWith(query)) {
|
|
70
|
+
priority = 1; // Command starts with query
|
|
71
|
+
}
|
|
72
|
+
else if (nameLower.includes(query)) {
|
|
73
|
+
priority = 2; // Command contains query
|
|
74
|
+
}
|
|
75
|
+
else if (descLower.startsWith(query)) {
|
|
76
|
+
priority = 3; // Description starts with query
|
|
77
|
+
}
|
|
78
|
+
return { command, priority };
|
|
79
|
+
})
|
|
80
|
+
.sort((a, b) => {
|
|
81
|
+
// Sort by priority (lower number = higher priority)
|
|
82
|
+
if (a.priority !== b.priority) {
|
|
83
|
+
return a.priority - b.priority;
|
|
84
|
+
}
|
|
85
|
+
// If same priority, sort alphabetically by name
|
|
86
|
+
return a.command.name.localeCompare(b.command.name);
|
|
87
|
+
})
|
|
88
|
+
.map(item => item.command);
|
|
89
|
+
return filtered;
|
|
57
90
|
}, [buffer]);
|
|
58
91
|
// Update command panel state
|
|
59
92
|
const updateCommandPanelState = useCallback((text) => {
|
package/dist/mcp/todo.js
CHANGED
|
@@ -213,36 +213,43 @@ export class TodoService {
|
|
|
213
213
|
return [
|
|
214
214
|
{
|
|
215
215
|
name: 'todo-create',
|
|
216
|
-
description:
|
|
216
|
+
description: `✅ RECOMMENDED: Create TODO list for structured task execution. Use this for ALL multi-step tasks!
|
|
217
217
|
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
⚠️ MANDATORY RULE - PARALLEL CALLS ONLY:
|
|
219
|
+
🚫 NEVER call todo-create alone! MUST call with other tools in the SAME function call block.
|
|
220
|
+
✅ ALWAYS: todo-create + filesystem-read (or other action tool) in parallel
|
|
221
|
+
❌ FORBIDDEN: Call todo-create, wait for result, then call other tools
|
|
220
222
|
|
|
221
|
-
##
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
223
|
+
## 🎯 DEFAULT USAGE - Use TODO by default for:
|
|
224
|
+
✅ ANY multi-file changes (always create TODO first)
|
|
225
|
+
✅ ANY feature implementation (plan with TODO)
|
|
226
|
+
✅ ANY refactoring work (track with TODO)
|
|
227
|
+
✅ Bug fixes involving 2+ files (use TODO)
|
|
228
|
+
✅ Tasks with 3+ distinct steps (create TODO)
|
|
229
|
+
⚠️ SKIP ONLY: Single-file trivial edits (1-2 lines)
|
|
226
230
|
|
|
227
|
-
##
|
|
228
|
-
-
|
|
229
|
-
-
|
|
230
|
-
-
|
|
231
|
-
-
|
|
231
|
+
## 🚀 WHY CREATE TODO:
|
|
232
|
+
- Ensures all requirements are addressed
|
|
233
|
+
- Prevents missing critical steps
|
|
234
|
+
- Provides clear progress tracking
|
|
235
|
+
- Improves code quality through systematic approach
|
|
236
|
+
- Builds user confidence with visible structure
|
|
232
237
|
|
|
233
|
-
##
|
|
234
|
-
1. **NEW
|
|
235
|
-
2. **
|
|
236
|
-
3.
|
|
238
|
+
## 📋 WHEN TO CALL:
|
|
239
|
+
1. **NEW TASK**: Create TODO immediately when starting work (with parallel action)
|
|
240
|
+
2. **NEW REQUIREMENT**: Delete old todos, create fresh list (with parallel action)
|
|
241
|
+
3. **BEST PRACTICE**: Call todo-create + filesystem-read in parallel
|
|
237
242
|
|
|
238
|
-
## CREATION GUIDELINES:
|
|
239
|
-
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
+
## ⚡ CREATION GUIDELINES:
|
|
244
|
+
- Break work into 3-7 clear, actionable tasks
|
|
245
|
+
- Order by logical dependencies
|
|
246
|
+
- Be specific (e.g., "Modify validateInput in form.ts" not "fix validation")
|
|
247
|
+
- Include verification step if critical
|
|
243
248
|
|
|
244
|
-
##
|
|
245
|
-
This REPLACES the entire TODO list.
|
|
249
|
+
## ⚠️ LIFECYCLE:
|
|
250
|
+
This REPLACES the entire TODO list. For adding tasks to existing list, use "todo-add" instead.
|
|
251
|
+
|
|
252
|
+
## 💡 REMEMBER: MUST call with other tools - never alone!`,
|
|
246
253
|
inputSchema: {
|
|
247
254
|
type: 'object',
|
|
248
255
|
properties: {
|
|
@@ -270,15 +277,19 @@ This REPLACES the entire TODO list. Never use it to "add more tasks" - use "todo
|
|
|
270
277
|
},
|
|
271
278
|
{
|
|
272
279
|
name: 'todo-get',
|
|
273
|
-
description: `Get
|
|
280
|
+
description: `Get current TODO list with task IDs, status, and hierarchy.
|
|
281
|
+
|
|
282
|
+
⚠️ MANDATORY RULE - PARALLEL CALLS ONLY:
|
|
283
|
+
🚫 NEVER call todo-get alone! MUST call with other tools in the SAME function call block.
|
|
284
|
+
✅ ALWAYS: todo-get + filesystem-read/terminal-execute/etc in parallel
|
|
285
|
+
❌ FORBIDDEN: Call todo-get alone to check status
|
|
274
286
|
|
|
275
|
-
## WHEN TO USE:
|
|
276
|
-
-
|
|
277
|
-
-
|
|
278
|
-
-
|
|
287
|
+
## 🔄 WHEN TO USE IN DIALOGUE:
|
|
288
|
+
- **User provides additional info**: Use todo-get + filesystem-read to check what's done
|
|
289
|
+
- **User requests modifications**: Check current progress before adding/updating tasks
|
|
290
|
+
- **Continuing work**: Always check status first to avoid redoing completed tasks
|
|
279
291
|
|
|
280
|
-
|
|
281
|
-
Complete TODO list with all task IDs, content, status, and hierarchy.`,
|
|
292
|
+
USAGE: Combine with filesystem-read, terminal-execute, or other actions to check progress while working.`,
|
|
282
293
|
inputSchema: {
|
|
283
294
|
type: 'object',
|
|
284
295
|
properties: {},
|
|
@@ -286,26 +297,17 @@ Complete TODO list with all task IDs, content, status, and hierarchy.`,
|
|
|
286
297
|
},
|
|
287
298
|
{
|
|
288
299
|
name: 'todo-update',
|
|
289
|
-
description: `Update TODO status
|
|
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
|
|
300
|
+
description: `Update TODO status/content - USE THIS FREQUENTLY to track progress!
|
|
296
301
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
- You've actually verified it works
|
|
302
|
+
⚠️ MANDATORY RULE - PARALLEL CALLS ONLY:
|
|
303
|
+
🚫 NEVER call todo-update alone! MUST call with other tools in the SAME function call block.
|
|
304
|
+
✅ ALWAYS: todo-update + filesystem-edit/terminal-execute/etc in parallel
|
|
305
|
+
❌ FORBIDDEN: Call todo-update, wait for result, then proceed
|
|
302
306
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
❌ Don't update before verifying the work is complete
|
|
307
|
+
BEST PRACTICE: Mark "completed" ONLY after task is verified.
|
|
308
|
+
Example: todo-update(task1, completed) + filesystem-edit(task2) → Update while working!
|
|
306
309
|
|
|
307
|
-
|
|
308
|
-
Every time you complete a task in Task, it will be updated to "Completed" immediately.`,
|
|
310
|
+
💡 This ensures efficient workflow and prevents unnecessary wait times.`,
|
|
309
311
|
inputSchema: {
|
|
310
312
|
type: 'object',
|
|
311
313
|
properties: {
|
|
@@ -328,24 +330,19 @@ Every time you complete a task in Task, it will be updated to "Completed" immedi
|
|
|
328
330
|
},
|
|
329
331
|
{
|
|
330
332
|
name: 'todo-add',
|
|
331
|
-
description: `Add
|
|
333
|
+
description: `Add new task to existing TODO list when requirements expand.
|
|
332
334
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
⚠️ MANDATORY RULE - PARALLEL CALLS ONLY:
|
|
336
|
+
🚫 NEVER call todo-add alone! MUST call with other tools in the SAME function call block.
|
|
337
|
+
✅ ALWAYS: todo-add + filesystem-edit/filesystem-read/etc in parallel
|
|
338
|
+
❌ FORBIDDEN: Call todo-add alone to add task
|
|
335
339
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
+
USE WHEN:
|
|
341
|
+
- User adds new requirements during work
|
|
342
|
+
- You discover additional necessary steps
|
|
343
|
+
- Breaking down a complex task into subtasks
|
|
340
344
|
|
|
341
|
-
|
|
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.`,
|
|
345
|
+
DO NOT use for initial planning - use todo-create instead.`,
|
|
349
346
|
inputSchema: {
|
|
350
347
|
type: 'object',
|
|
351
348
|
properties: {
|
|
@@ -363,27 +360,14 @@ If a task takes less than 10 minutes, just do it instead of adding it to TODO. T
|
|
|
363
360
|
},
|
|
364
361
|
{
|
|
365
362
|
name: 'todo-delete',
|
|
366
|
-
description: `Delete TODO
|
|
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
|
|
363
|
+
description: `Delete TODO item from the list.
|
|
379
364
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
365
|
+
⚠️ MANDATORY RULE - PARALLEL CALLS ONLY:
|
|
366
|
+
🚫 NEVER call todo-delete alone! MUST call with other tools in the SAME function call block.
|
|
367
|
+
✅ ALWAYS: todo-delete + filesystem-edit/todo-get/etc in parallel
|
|
368
|
+
❌ FORBIDDEN: Call todo-delete alone
|
|
384
369
|
|
|
385
|
-
|
|
386
|
-
Deleting a parent task automatically deletes all its subtasks (parentId relationship).`,
|
|
370
|
+
NOTE: Deleting a parent task will cascade delete all its children automatically.`,
|
|
387
371
|
inputSchema: {
|
|
388
372
|
type: 'object',
|
|
389
373
|
properties: {
|
|
@@ -354,15 +354,13 @@ export default function ChatInput({ onSubmit, onCommand, placeholder = 'Type you
|
|
|
354
354
|
' ',
|
|
355
355
|
"cached"))))));
|
|
356
356
|
})()))),
|
|
357
|
-
|
|
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,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,19 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Text } from 'ink';
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
3
|
// @ts-expect-error - cli-markdown doesn't have TypeScript definitions
|
|
4
4
|
import cliMarkdown from 'cli-markdown';
|
|
5
|
+
import logger from '../../utils/logger.js';
|
|
5
6
|
export default function MarkdownRenderer({ content }) {
|
|
6
7
|
// Use cli-markdown for elegant markdown rendering with syntax highlighting
|
|
7
8
|
// The patched highlight function will gracefully handle unknown languages
|
|
8
9
|
const rendered = cliMarkdown(content);
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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)))));
|
|
19
23
|
}
|
|
@@ -20,9 +20,11 @@ export default function TodoTree({ todos }) {
|
|
|
20
20
|
const getStatusIcon = (status) => {
|
|
21
21
|
switch (status) {
|
|
22
22
|
case 'completed':
|
|
23
|
-
return '[
|
|
23
|
+
return '[✓]';
|
|
24
24
|
case 'pending':
|
|
25
25
|
return '[ ]';
|
|
26
|
+
default:
|
|
27
|
+
return '[ ]';
|
|
26
28
|
}
|
|
27
29
|
};
|
|
28
30
|
const getStatusColor = (status) => {
|
|
@@ -52,5 +54,5 @@ export default function TodoTree({ todos }) {
|
|
|
52
54
|
React.createElement(Text, { bold: true, color: "cyan" }, "TODO List")),
|
|
53
55
|
rootTodos.map(todo => renderTodo(todo)),
|
|
54
56
|
React.createElement(Box, { marginTop: 0 },
|
|
55
|
-
React.createElement(Text, { dimColor: true, color: "gray" }, "[ ] Pending \u00B7 [
|
|
57
|
+
React.createElement(Text, { dimColor: true, color: "gray" }, "[ ] Pending \u00B7 [\u2713] Completed"))));
|
|
56
58
|
}
|
|
@@ -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,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 {};
|