snow-ai 0.1.12 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/api/chat.d.ts +65 -2
  2. package/dist/api/chat.js +299 -16
  3. package/dist/api/responses.d.ts +52 -0
  4. package/dist/api/responses.js +541 -0
  5. package/dist/api/systemPrompt.d.ts +4 -0
  6. package/dist/api/systemPrompt.js +43 -0
  7. package/dist/app.js +15 -4
  8. package/dist/cli.js +38 -2
  9. package/dist/hooks/useConversation.d.ts +32 -0
  10. package/dist/hooks/useConversation.js +403 -0
  11. package/dist/hooks/useGlobalNavigation.d.ts +6 -0
  12. package/dist/hooks/useGlobalNavigation.js +15 -0
  13. package/dist/hooks/useSessionManagement.d.ts +10 -0
  14. package/dist/hooks/useSessionManagement.js +43 -0
  15. package/dist/hooks/useSessionSave.d.ts +8 -0
  16. package/dist/hooks/useSessionSave.js +52 -0
  17. package/dist/hooks/useToolConfirmation.d.ts +18 -0
  18. package/dist/hooks/useToolConfirmation.js +49 -0
  19. package/dist/mcp/bash.d.ts +57 -0
  20. package/dist/mcp/bash.js +138 -0
  21. package/dist/mcp/filesystem.d.ts +307 -0
  22. package/dist/mcp/filesystem.js +520 -0
  23. package/dist/mcp/todo.d.ts +55 -0
  24. package/dist/mcp/todo.js +329 -0
  25. package/dist/test/logger-test.d.ts +1 -0
  26. package/dist/test/logger-test.js +7 -0
  27. package/dist/types/index.d.ts +1 -1
  28. package/dist/ui/components/ChatInput.d.ts +15 -2
  29. package/dist/ui/components/ChatInput.js +445 -59
  30. package/dist/ui/components/CommandPanel.d.ts +2 -2
  31. package/dist/ui/components/CommandPanel.js +11 -7
  32. package/dist/ui/components/DiffViewer.d.ts +9 -0
  33. package/dist/ui/components/DiffViewer.js +93 -0
  34. package/dist/ui/components/FileList.d.ts +14 -0
  35. package/dist/ui/components/FileList.js +131 -0
  36. package/dist/ui/components/MCPInfoPanel.d.ts +2 -0
  37. package/dist/ui/components/MCPInfoPanel.js +74 -0
  38. package/dist/ui/components/MCPInfoScreen.d.ts +7 -0
  39. package/dist/ui/components/MCPInfoScreen.js +27 -0
  40. package/dist/ui/components/MarkdownRenderer.d.ts +7 -0
  41. package/dist/ui/components/MarkdownRenderer.js +110 -0
  42. package/dist/ui/components/Menu.d.ts +5 -2
  43. package/dist/ui/components/Menu.js +60 -9
  44. package/dist/ui/components/MessageList.d.ts +30 -2
  45. package/dist/ui/components/MessageList.js +64 -12
  46. package/dist/ui/components/PendingMessages.js +1 -1
  47. package/dist/ui/components/ScrollableSelectInput.d.ts +29 -0
  48. package/dist/ui/components/ScrollableSelectInput.js +157 -0
  49. package/dist/ui/components/SessionListScreen.d.ts +7 -0
  50. package/dist/ui/components/SessionListScreen.js +196 -0
  51. package/dist/ui/components/SessionListScreenWrapper.d.ts +7 -0
  52. package/dist/ui/components/SessionListScreenWrapper.js +14 -0
  53. package/dist/ui/components/TodoTree.d.ts +15 -0
  54. package/dist/ui/components/TodoTree.js +60 -0
  55. package/dist/ui/components/ToolConfirmation.d.ts +8 -0
  56. package/dist/ui/components/ToolConfirmation.js +38 -0
  57. package/dist/ui/components/ToolResultPreview.d.ts +12 -0
  58. package/dist/ui/components/ToolResultPreview.js +115 -0
  59. package/dist/ui/pages/ChatScreen.d.ts +4 -0
  60. package/dist/ui/pages/ChatScreen.js +385 -196
  61. package/dist/ui/pages/MCPConfigScreen.d.ts +6 -0
  62. package/dist/ui/pages/MCPConfigScreen.js +55 -0
  63. package/dist/ui/pages/ModelConfigScreen.js +73 -12
  64. package/dist/ui/pages/WelcomeScreen.js +17 -11
  65. package/dist/utils/apiConfig.d.ts +12 -0
  66. package/dist/utils/apiConfig.js +95 -9
  67. package/dist/utils/commandExecutor.d.ts +2 -1
  68. package/dist/utils/commands/init.d.ts +2 -0
  69. package/dist/utils/commands/init.js +93 -0
  70. package/dist/utils/commands/mcp.d.ts +2 -0
  71. package/dist/utils/commands/mcp.js +12 -0
  72. package/dist/utils/commands/resume.d.ts +2 -0
  73. package/dist/utils/commands/resume.js +12 -0
  74. package/dist/utils/commands/yolo.d.ts +2 -0
  75. package/dist/utils/commands/yolo.js +12 -0
  76. package/dist/utils/fileUtils.d.ts +44 -0
  77. package/dist/utils/fileUtils.js +222 -0
  78. package/dist/utils/index.d.ts +4 -0
  79. package/dist/utils/index.js +6 -0
  80. package/dist/utils/logger.d.ts +31 -0
  81. package/dist/utils/logger.js +97 -0
  82. package/dist/utils/mcpToolsManager.d.ts +47 -0
  83. package/dist/utils/mcpToolsManager.js +476 -0
  84. package/dist/utils/messageFormatter.d.ts +12 -0
  85. package/dist/utils/messageFormatter.js +32 -0
  86. package/dist/utils/sessionConverter.d.ts +6 -0
  87. package/dist/utils/sessionConverter.js +61 -0
  88. package/dist/utils/sessionManager.d.ts +39 -0
  89. package/dist/utils/sessionManager.js +141 -0
  90. package/dist/utils/textBuffer.d.ts +36 -7
  91. package/dist/utils/textBuffer.js +265 -179
  92. package/dist/utils/todoPreprocessor.d.ts +5 -0
  93. package/dist/utils/todoPreprocessor.js +19 -0
  94. package/dist/utils/toolExecutor.d.ts +21 -0
  95. package/dist/utils/toolExecutor.js +28 -0
  96. package/package.json +12 -3
  97. package/readme.md +2 -2
@@ -0,0 +1,329 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ /**
4
+ * TODO 管理服务 - 支持创建、查询、更新 TODO
5
+ */
6
+ export class TodoService {
7
+ constructor(baseDir, getCurrentSessionId) {
8
+ Object.defineProperty(this, "todoDir", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: void 0
13
+ });
14
+ Object.defineProperty(this, "getCurrentSessionId", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: void 0
19
+ });
20
+ this.todoDir = path.join(baseDir, 'todos');
21
+ this.getCurrentSessionId = getCurrentSessionId;
22
+ }
23
+ async initialize() {
24
+ await fs.mkdir(this.todoDir, { recursive: true });
25
+ }
26
+ getTodoPath(sessionId) {
27
+ return path.join(this.todoDir, `${sessionId}.json`);
28
+ }
29
+ /**
30
+ * 创建或更新会话的 TODO List
31
+ */
32
+ async saveTodoList(sessionId, todos) {
33
+ const todoPath = this.getTodoPath(sessionId);
34
+ let existingList;
35
+ try {
36
+ const content = await fs.readFile(todoPath, 'utf-8');
37
+ existingList = JSON.parse(content);
38
+ }
39
+ catch {
40
+ // 文件不存在,创建新的
41
+ }
42
+ const now = new Date().toISOString();
43
+ const todoList = {
44
+ sessionId,
45
+ todos,
46
+ createdAt: existingList?.createdAt ?? now,
47
+ updatedAt: now,
48
+ };
49
+ await fs.writeFile(todoPath, JSON.stringify(todoList, null, 2));
50
+ return todoList;
51
+ }
52
+ /**
53
+ * 获取会话的 TODO List
54
+ */
55
+ async getTodoList(sessionId) {
56
+ const todoPath = this.getTodoPath(sessionId);
57
+ try {
58
+ const content = await fs.readFile(todoPath, 'utf-8');
59
+ return JSON.parse(content);
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ /**
66
+ * 更新单个 TODO 项
67
+ */
68
+ async updateTodoItem(sessionId, todoId, updates) {
69
+ const todoList = await this.getTodoList(sessionId);
70
+ if (!todoList) {
71
+ return null;
72
+ }
73
+ const todoIndex = todoList.todos.findIndex(t => t.id === todoId);
74
+ if (todoIndex === -1) {
75
+ return null;
76
+ }
77
+ const existingTodo = todoList.todos[todoIndex];
78
+ todoList.todos[todoIndex] = {
79
+ ...existingTodo,
80
+ ...updates,
81
+ updatedAt: new Date().toISOString(),
82
+ };
83
+ return this.saveTodoList(sessionId, todoList.todos);
84
+ }
85
+ /**
86
+ * 添加 TODO 项
87
+ */
88
+ async addTodoItem(sessionId, content, parentId) {
89
+ const todoList = await this.getTodoList(sessionId);
90
+ const now = new Date().toISOString();
91
+ const newTodo = {
92
+ id: `todo_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
93
+ content,
94
+ status: 'pending',
95
+ createdAt: now,
96
+ updatedAt: now,
97
+ parentId,
98
+ };
99
+ const todos = todoList ? [...todoList.todos, newTodo] : [newTodo];
100
+ return this.saveTodoList(sessionId, todos);
101
+ }
102
+ /**
103
+ * 删除 TODO 项
104
+ */
105
+ async deleteTodoItem(sessionId, todoId) {
106
+ const todoList = await this.getTodoList(sessionId);
107
+ if (!todoList) {
108
+ return null;
109
+ }
110
+ const filteredTodos = todoList.todos.filter(t => t.id !== todoId && t.parentId !== todoId);
111
+ return this.saveTodoList(sessionId, filteredTodos);
112
+ }
113
+ /**
114
+ * 获取所有工具定义
115
+ */
116
+ getTools() {
117
+ return [
118
+ {
119
+ name: 'todo-create',
120
+ description: 'Create a TODO list for current session. CRITICAL FOR PROGRAMMING TASKS: You MUST use this tool at the start of ANY programming task (bug fixes, new features, refactoring, optimization, etc.) to break down the work into trackable steps. This ensures systematic execution and prevents missing critical steps. The TODO list helps maintain context and provides clear progress visibility to the user. WARNING: This tool creates/replaces the entire TODO list for the session - use it ONLY ONCE at the beginning. To add more tasks later, use "todo-add" instead.',
121
+ inputSchema: {
122
+ type: 'object',
123
+ properties: {
124
+ todos: {
125
+ type: 'array',
126
+ items: {
127
+ type: 'object',
128
+ properties: {
129
+ content: {
130
+ type: 'string',
131
+ description: 'TODO item description (be specific and actionable)',
132
+ },
133
+ parentId: {
134
+ type: 'string',
135
+ description: 'Parent TODO ID (optional, for creating subtasks)',
136
+ },
137
+ },
138
+ required: ['content'],
139
+ },
140
+ description: 'List of TODO items to create. For programming tasks, include steps like: analyze requirements, implement changes, test functionality, verify build, etc. The list can contain multiple tasks that will be tracked and executed sequentially.',
141
+ },
142
+ },
143
+ required: ['todos'],
144
+ },
145
+ },
146
+ {
147
+ name: 'todo-get',
148
+ description: 'Get the TODO list for current session. Use this to check existing tasks and their status before making updates.',
149
+ inputSchema: {
150
+ type: 'object',
151
+ properties: {},
152
+ },
153
+ },
154
+ {
155
+ name: 'todo-update',
156
+ description: 'Update TODO item status or content. IMPORTANT: Mark task as "in_progress" BEFORE starting work, and "completed" IMMEDIATELY after finishing. Keep exactly ONE task in "in_progress" status at any time. This provides real-time progress feedback to the user.',
157
+ inputSchema: {
158
+ type: 'object',
159
+ properties: {
160
+ todoId: {
161
+ type: 'string',
162
+ description: 'TODO item ID to update',
163
+ },
164
+ status: {
165
+ type: 'string',
166
+ enum: ['pending', 'in_progress', 'completed'],
167
+ description: 'New status: "in_progress" when starting, "completed" when done, "pending" for not started',
168
+ },
169
+ content: {
170
+ type: 'string',
171
+ description: 'Updated TODO content (optional)',
172
+ },
173
+ },
174
+ required: ['todoId'],
175
+ },
176
+ },
177
+ {
178
+ name: 'todo-add',
179
+ description: 'Add a new TODO item to current session. Use this when you discover additional steps during execution, or when breaking down complex tasks into smaller subtasks.',
180
+ inputSchema: {
181
+ type: 'object',
182
+ properties: {
183
+ content: {
184
+ type: 'string',
185
+ description: 'TODO item description (be specific and actionable)',
186
+ },
187
+ parentId: {
188
+ type: 'string',
189
+ description: 'Parent TODO ID (optional, for creating subtasks)',
190
+ },
191
+ },
192
+ required: ['content'],
193
+ },
194
+ },
195
+ {
196
+ name: 'todo-delete',
197
+ description: 'Delete a TODO item from current session. Use this to remove tasks that are no longer relevant or were created by mistake.',
198
+ inputSchema: {
199
+ type: 'object',
200
+ properties: {
201
+ todoId: {
202
+ type: 'string',
203
+ description: 'TODO item ID to delete',
204
+ },
205
+ },
206
+ required: ['todoId'],
207
+ },
208
+ },
209
+ ];
210
+ }
211
+ /**
212
+ * 执行工具调用
213
+ */
214
+ async executeTool(toolName, args) {
215
+ // 自动获取当前会话 ID
216
+ const sessionId = this.getCurrentSessionId();
217
+ if (!sessionId) {
218
+ return {
219
+ content: [
220
+ {
221
+ type: 'text',
222
+ text: 'Error: No active session found',
223
+ },
224
+ ],
225
+ isError: true,
226
+ };
227
+ }
228
+ try {
229
+ switch (toolName) {
230
+ case 'todo-create': {
231
+ const { todos } = args;
232
+ const todoItems = todos.map(t => {
233
+ const now = new Date().toISOString();
234
+ return {
235
+ id: `todo_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
236
+ content: t.content,
237
+ status: 'pending',
238
+ createdAt: now,
239
+ updatedAt: now,
240
+ parentId: t.parentId,
241
+ };
242
+ });
243
+ const result = await this.saveTodoList(sessionId, todoItems);
244
+ return {
245
+ content: [
246
+ {
247
+ type: 'text',
248
+ text: JSON.stringify(result, null, 2),
249
+ },
250
+ ],
251
+ };
252
+ }
253
+ case 'todo-get': {
254
+ const result = await this.getTodoList(sessionId);
255
+ return {
256
+ content: [
257
+ {
258
+ type: 'text',
259
+ text: result ? JSON.stringify(result, null, 2) : 'No TODO list found',
260
+ },
261
+ ],
262
+ };
263
+ }
264
+ case 'todo-update': {
265
+ const { todoId, status, content } = args;
266
+ const updates = {};
267
+ if (status)
268
+ updates.status = status;
269
+ if (content)
270
+ updates.content = content;
271
+ const result = await this.updateTodoItem(sessionId, todoId, updates);
272
+ return {
273
+ content: [
274
+ {
275
+ type: 'text',
276
+ text: result ? JSON.stringify(result, null, 2) : 'TODO item not found',
277
+ },
278
+ ],
279
+ };
280
+ }
281
+ case 'todo-add': {
282
+ const { content, parentId } = args;
283
+ const result = await this.addTodoItem(sessionId, content, parentId);
284
+ return {
285
+ content: [
286
+ {
287
+ type: 'text',
288
+ text: JSON.stringify(result, null, 2),
289
+ },
290
+ ],
291
+ };
292
+ }
293
+ case 'todo-delete': {
294
+ const { todoId } = args;
295
+ const result = await this.deleteTodoItem(sessionId, todoId);
296
+ return {
297
+ content: [
298
+ {
299
+ type: 'text',
300
+ text: result ? JSON.stringify(result, null, 2) : 'TODO item not found',
301
+ },
302
+ ],
303
+ };
304
+ }
305
+ default:
306
+ return {
307
+ content: [
308
+ {
309
+ type: 'text',
310
+ text: `Unknown tool: ${toolName}`,
311
+ },
312
+ ],
313
+ isError: true,
314
+ };
315
+ }
316
+ }
317
+ catch (error) {
318
+ return {
319
+ content: [
320
+ {
321
+ type: 'text',
322
+ text: `Error executing ${toolName}: ${error instanceof Error ? error.message : String(error)}`,
323
+ },
324
+ ],
325
+ isError: true,
326
+ };
327
+ }
328
+ }
329
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { logger } from '../utils/logger.js';
2
+ // Test the logger
3
+ logger.info('Logger service initialized successfully');
4
+ logger.error('Test error message', { errorCode: 500 });
5
+ logger.warn('Test warning message');
6
+ logger.debug('Debug information', { timestamp: Date.now() });
7
+ console.log('Logger test completed. Check ./snow/log directory for log files.');
@@ -1,4 +1,4 @@
1
- export interface AIBotConfig {
1
+ export interface SnowConfig {
2
2
  model?: string;
3
3
  apiKey?: string;
4
4
  maxTokens?: number;
@@ -1,9 +1,22 @@
1
1
  import React from 'react';
2
2
  type Props = {
3
- onSubmit: (message: string) => void;
3
+ onSubmit: (message: string, images?: Array<{
4
+ data: string;
5
+ mimeType: string;
6
+ }>) => void;
4
7
  onCommand?: (commandName: string, result: any) => void;
5
8
  placeholder?: string;
6
9
  disabled?: boolean;
10
+ chatHistory?: Array<{
11
+ role: string;
12
+ content: string;
13
+ }>;
14
+ onHistorySelect?: (selectedIndex: number, message: string) => void;
15
+ yoloMode?: boolean;
16
+ contextUsage?: {
17
+ inputTokens: number;
18
+ maxContextTokens: number;
19
+ };
7
20
  };
8
- export default function ChatInput({ onSubmit, onCommand, placeholder, disabled }: Props): React.JSX.Element;
21
+ export default function ChatInput({ onSubmit, onCommand, placeholder, disabled, chatHistory, onHistorySelect, yoloMode, contextUsage }: Props): React.JSX.Element;
9
22
  export {};