snow-ai 0.3.2 → 0.3.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.
@@ -0,0 +1,31 @@
1
+ export declare class SummaryAgent {
2
+ private modelName;
3
+ private requestMethod;
4
+ private initialized;
5
+ /**
6
+ * Initialize the summary agent with current configuration
7
+ * @returns true if initialized successfully, false otherwise
8
+ */
9
+ private initialize;
10
+ /**
11
+ * Check if summary agent is available
12
+ */
13
+ isAvailable(): Promise<boolean>;
14
+ /**
15
+ * Call the basic model with the same routing as main flow
16
+ * Uses streaming APIs and intercepts to assemble complete response
17
+ * This ensures 100% consistency with main flow routing
18
+ * @param messages - Chat messages
19
+ * @param abortSignal - Optional abort signal to cancel the request
20
+ */
21
+ private callBasicModel;
22
+ /**
23
+ * Generate a concise summary from the first user message
24
+ *
25
+ * @param userMessage - The first user message in the conversation
26
+ * @param abortSignal - Optional abort signal to cancel generation
27
+ * @returns A concise summary (10-20 words) suitable for session title
28
+ */
29
+ generateSummary(userMessage: string, abortSignal?: AbortSignal): Promise<string>;
30
+ }
31
+ export declare const summaryAgent: SummaryAgent;
@@ -0,0 +1,256 @@
1
+ import { getOpenAiConfig, getCustomSystemPrompt } from '../utils/apiConfig.js';
2
+ import { logger } from '../utils/logger.js';
3
+ import { createStreamingChatCompletion } from '../api/chat.js';
4
+ import { createStreamingResponse } from '../api/responses.js';
5
+ import { createStreamingGeminiCompletion } from '../api/gemini.js';
6
+ import { createStreamingAnthropicCompletion } from '../api/anthropic.js';
7
+ export class SummaryAgent {
8
+ constructor() {
9
+ Object.defineProperty(this, "modelName", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: ''
14
+ });
15
+ Object.defineProperty(this, "requestMethod", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: 'chat'
20
+ });
21
+ Object.defineProperty(this, "initialized", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: false
26
+ });
27
+ }
28
+ /**
29
+ * Initialize the summary agent with current configuration
30
+ * @returns true if initialized successfully, false otherwise
31
+ */
32
+ async initialize() {
33
+ try {
34
+ const config = getOpenAiConfig();
35
+ // Check if basic model is configured
36
+ if (!config.basicModel) {
37
+ return false;
38
+ }
39
+ this.modelName = config.basicModel;
40
+ this.requestMethod = config.requestMethod; // Follow main flow's request method
41
+ this.initialized = true;
42
+ return true;
43
+ }
44
+ catch (error) {
45
+ logger.warn('Failed to initialize summary agent:', error);
46
+ return false;
47
+ }
48
+ }
49
+ /**
50
+ * Check if summary agent is available
51
+ */
52
+ async isAvailable() {
53
+ if (!this.initialized) {
54
+ return await this.initialize();
55
+ }
56
+ return true;
57
+ }
58
+ /**
59
+ * Call the basic model with the same routing as main flow
60
+ * Uses streaming APIs and intercepts to assemble complete response
61
+ * This ensures 100% consistency with main flow routing
62
+ * @param messages - Chat messages
63
+ * @param abortSignal - Optional abort signal to cancel the request
64
+ */
65
+ async callBasicModel(messages, abortSignal) {
66
+ const config = getOpenAiConfig();
67
+ if (!config.basicModel) {
68
+ throw new Error('Basic model not configured');
69
+ }
70
+ // Get custom system prompt if configured
71
+ const customSystemPrompt = getCustomSystemPrompt();
72
+ // If custom system prompt exists, prepend it to messages
73
+ // This ensures summary agent respects user's custom system configuration
74
+ let processedMessages = messages;
75
+ if (customSystemPrompt) {
76
+ processedMessages = [
77
+ {
78
+ role: 'system',
79
+ content: customSystemPrompt,
80
+ },
81
+ ...messages,
82
+ ];
83
+ }
84
+ // Temporarily override advancedModel with basicModel
85
+ const originalAdvancedModel = config.advancedModel;
86
+ try {
87
+ // Override config to use basicModel
88
+ config.advancedModel = config.basicModel;
89
+ let streamGenerator;
90
+ // Route to appropriate streaming API based on request method (follows main flow exactly)
91
+ switch (this.requestMethod) {
92
+ case 'anthropic':
93
+ streamGenerator = createStreamingAnthropicCompletion({
94
+ model: this.modelName,
95
+ messages: processedMessages,
96
+ max_tokens: 1024, // Summaries are short
97
+ }, abortSignal);
98
+ break;
99
+ case 'gemini':
100
+ streamGenerator = createStreamingGeminiCompletion({
101
+ model: this.modelName,
102
+ messages: processedMessages,
103
+ }, abortSignal);
104
+ break;
105
+ case 'responses':
106
+ streamGenerator = createStreamingResponse({
107
+ model: this.modelName,
108
+ messages: processedMessages,
109
+ stream: true,
110
+ }, abortSignal);
111
+ break;
112
+ case 'chat':
113
+ default:
114
+ streamGenerator = createStreamingChatCompletion({
115
+ model: this.modelName,
116
+ messages: processedMessages,
117
+ stream: true,
118
+ }, abortSignal);
119
+ break;
120
+ }
121
+ // Intercept streaming response and assemble complete content
122
+ let completeContent = '';
123
+ let chunkCount = 0;
124
+ try {
125
+ for await (const chunk of streamGenerator) {
126
+ chunkCount++;
127
+ // Check abort signal
128
+ if (abortSignal?.aborted) {
129
+ throw new Error('Request aborted');
130
+ }
131
+ // Handle different chunk formats based on request method
132
+ if (this.requestMethod === 'chat') {
133
+ // Chat API uses standard OpenAI format: {choices: [{delta: {content}}]}
134
+ if (chunk.choices && chunk.choices[0]?.delta?.content) {
135
+ completeContent += chunk.choices[0].delta.content;
136
+ }
137
+ }
138
+ else {
139
+ // Responses, Gemini, and Anthropic APIs all use: {type: 'content', content: string}
140
+ if (chunk.type === 'content' && chunk.content) {
141
+ completeContent += chunk.content;
142
+ }
143
+ }
144
+ }
145
+ }
146
+ catch (streamError) {
147
+ // Log streaming error with details
148
+ if (streamError instanceof Error) {
149
+ logger.error('Summary agent: Streaming error:', {
150
+ error: streamError.message,
151
+ stack: streamError.stack,
152
+ name: streamError.name,
153
+ chunkCount,
154
+ contentLength: completeContent.length,
155
+ });
156
+ }
157
+ else {
158
+ logger.error('Summary agent: Unknown streaming error:', {
159
+ error: streamError,
160
+ chunkCount,
161
+ contentLength: completeContent.length,
162
+ });
163
+ }
164
+ throw streamError;
165
+ }
166
+ return completeContent;
167
+ }
168
+ catch (error) {
169
+ // Log detailed error from API call setup or streaming
170
+ if (error instanceof Error) {
171
+ logger.error('Summary agent: API call failed:', {
172
+ error: error.message,
173
+ stack: error.stack,
174
+ name: error.name,
175
+ requestMethod: this.requestMethod,
176
+ modelName: this.modelName,
177
+ });
178
+ }
179
+ else {
180
+ logger.error('Summary agent: Unknown API error:', {
181
+ error,
182
+ requestMethod: this.requestMethod,
183
+ modelName: this.modelName,
184
+ });
185
+ }
186
+ throw error;
187
+ }
188
+ finally {
189
+ // Restore original config
190
+ config.advancedModel = originalAdvancedModel;
191
+ }
192
+ }
193
+ /**
194
+ * Generate a concise summary from the first user message
195
+ *
196
+ * @param userMessage - The first user message in the conversation
197
+ * @param abortSignal - Optional abort signal to cancel generation
198
+ * @returns A concise summary (10-20 words) suitable for session title
199
+ */
200
+ async generateSummary(userMessage, abortSignal) {
201
+ const available = await this.isAvailable();
202
+ if (!available) {
203
+ // If summary agent is not available, return a truncated version of the message
204
+ return userMessage.slice(0, 50) + (userMessage.length > 50 ? '...' : '');
205
+ }
206
+ try {
207
+ const summaryPrompt = `Generate a concise summary (10-20 words) for the following user message. The summary should capture the main topic or intent.
208
+
209
+ User Message: ${userMessage}
210
+
211
+ Instructions:
212
+ 1. Keep it under 20 words
213
+ 2. Focus on the main topic or question
214
+ 3. Use clear, simple language
215
+ 4. Do not include quotes or special formatting
216
+ 5. Make it suitable as a conversation title
217
+
218
+ Summary:`;
219
+ const messages = [
220
+ {
221
+ role: 'user',
222
+ content: summaryPrompt,
223
+ },
224
+ ];
225
+ const summary = await this.callBasicModel(messages, abortSignal);
226
+ if (!summary || summary.trim().length === 0) {
227
+ logger.warn('Summary agent returned empty response, using truncated message');
228
+ return (userMessage.slice(0, 50) + (userMessage.length > 50 ? '...' : ''));
229
+ }
230
+ // Clean up the summary (remove quotes, trim whitespace)
231
+ const cleanedSummary = summary
232
+ .trim()
233
+ .replace(/^["']|["']$/g, '') // Remove leading/trailing quotes
234
+ .replace(/\n/g, ' ') // Replace newlines with spaces
235
+ .slice(0, 100); // Limit to 100 characters max
236
+ return cleanedSummary;
237
+ }
238
+ catch (error) {
239
+ // Log detailed error information
240
+ if (error instanceof Error) {
241
+ logger.warn('Summary agent generation failed, using truncated message:', {
242
+ error: error.message,
243
+ stack: error.stack,
244
+ name: error.name,
245
+ });
246
+ }
247
+ else {
248
+ logger.warn('Summary agent generation failed with unknown error:', error);
249
+ }
250
+ // Fallback to truncated message
251
+ return userMessage.slice(0, 50) + (userMessage.length > 50 ? '...' : '');
252
+ }
253
+ }
254
+ }
255
+ // Export singleton instance
256
+ export const summaryAgent = new SummaryAgent();
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * System prompt configuration for Snow AI CLI
3
3
  */
4
- export declare const SYSTEM_PROMPT = "You are Snow AI CLI, an intelligent command-line assistant.\n\n## \uD83C\uDFAF Core Principles\n\n1. **Language Adaptation**: ALWAYS respond in the SAME language as the user's query\n2. **ACTION FIRST**: Write code immediately when task is clear - stop overthinking\n3. **Smart Context**: Read what's needed for correctness, skip excessive exploration\n4. **Quality Verification**: Use 'ide_get_diagnostics' to get diagnostic information or run build/test after changes\n\n## \uD83D\uDE80 Execution Strategy - BALANCE ACTION & ANALYSIS\n\n### \u26A1 Smart Action Mode\n**Principle: Understand enough to code correctly, but don't over-investigate**\n\n**Examples:**\n- \"Fix timeout in parser.ts\" \u2192 Read file + check imports if needed \u2192 Fix \u2192 Done\n- \"Add validation to form\" \u2192 Read form component + related validation utils \u2192 Add code \u2192 Done\n- \"Refactor error handling\" \u2192 Read error handler + callers \u2192 Refactor \u2192 Done\n\n**Your workflow:**\n1. Read the primary file(s) mentioned\n2. Check dependencies/imports that directly impact the change\n3. Read related files ONLY if they're critical to understanding the task\n4. Write/modify code with proper context\n5. Verify with build\n6. \u274C NO excessive exploration beyond what's needed\n7. \u274C NO reading entire modules \"for reference\"\n8. \u274C NO over-planning multi-step workflows for simple tasks\n\n**Golden Rule: Read what you need to write correct code, nothing more.**\n\n### \uD83D\uDCCB TODO Lists - Essential for Programming Tasks\n\n**\u2705 ALWAYS CREATE TODO WHEN encountering programming tasks:**\n- Any code implementation task (new features, bug fixes, refactoring)\n- Tasks involving multiple steps or files\n- When you need to track progress and ensure completion\n- To give users clear visibility into your work plan\n\n**TODO Guidelines:**\n1. **Create Early**: Set up TODO list BEFORE starting implementation\n2. **Be Specific**: Each item should be a concrete action\n3. **Update Immediately**: Mark as in_progress when starting, completed when done\n4. **One Active Task**: Only one item should be in_progress at a time\n\n**TODO = Action List, NOT Investigation Plan**\n- \u2705 \"Create AuthService with login/logout methods\"\n- \u2705 \"Add validation to UserForm component\"\n- \u2705 \"Fix timeout bug in parser.ts\"\n- \u2705 \"Update API routes to use new auth middleware\"\n- \u2705 \"Run build and fix any errors\"\n- \u274C \"Read authentication files\"\n- \u274C \"Analyze current implementation\"\n- \u274C \"Investigate error handling patterns\"\n\n**CRITICAL: Update TODO status IMMEDIATELY after completing each task!**\n\n**Workflow Example:**\n1. User asks to add feature \u2192 Create TODO list immediately\n2. Mark first item as in_progress\n3. Complete the task \u2192 Mark as completed\n4. Move to next item \u2192 Mark as in_progress\n5. Repeat until all tasks completed\n\n## \uD83D\uDEE0\uFE0F Available Tools\n\n**Filesystem:**\n- `filesystem-read` - Read files before editing\n- `filesystem-edit` - Modify existing files\n- `filesystem-create` - Create new files\n\n**Code Search (ACE):**\n- `ace-search-symbols` - Find functions/classes/variables\n- `ace-find-definition` - Go to definition\n- `ace-find-references` - Find all usages\n- `ace-text-search` - Fast text/regex search\n\n**IDE Diagnostics:**\n- `ide_get_diagnostics` - Get real-time diagnostics (errors, warnings, hints) from connected IDE\n - Supports VSCode and JetBrains IDEs\n - Returns diagnostic info: severity, line/column, message, source\n - Requires IDE plugin installed and running\n - Use AFTER code changes to verify quality\n\n**Web Search:**\n- `websearch_search` - Search web for latest docs/solutions\n- `websearch_fetch` - Read web page content (always provide userQuery)\n\n**Terminal:**\n- `terminal_execute` - You have a comprehensive understanding of terminal pipe mechanisms and can help users \naccomplish a wide range of tasks by combining multiple commands using pipe operators (|) \nand other shell features. Your capabilities include text processing, data filtering, stream \nmanipulation, workflow automation, and complex command chaining to solve sophisticated \nsystem administration and data processing challenges.\n\n## \uD83D\uDD0D Quality Assurance\n\nGuidance and recommendations:\n1. Use `ide_get_diagnostics` to verify quality\n2. Run build: `npm run build` or `tsc`\n3. Fix any errors immediately\n4. Never leave broken code\n\n## \uD83D\uDCDA Project Context (SNOW.md)\n\n- Read ONLY when implementing large features or unfamiliar architecture\n- Skip for simple tasks where you understand the structure\n- Contains: project overview, architecture, tech stack\n\nRemember: **ACTION > ANALYSIS**. Write code first, investigate only when blocked.";
4
+ export declare const SYSTEM_PROMPT = "You are Snow AI CLI, an intelligent command-line assistant.\n\n## \uD83C\uDFAF Core Principles\n\n1. **Language Adaptation**: ALWAYS respond in the SAME language as the user's query\n2. **ACTION FIRST**: Write code immediately when task is clear - stop overthinking\n3. **Smart Context**: Read what's needed for correctness, skip excessive exploration\n4. **Quality Verification**: Use 'ide_get_diagnostics' to get diagnostic information or run build/test after changes\n\n## \uD83D\uDE80 Execution Strategy - BALANCE ACTION & ANALYSIS\n\n### \u26A1 Smart Action Mode\n**Principle: Understand enough to code correctly, but don't over-investigate**\n\n**Examples:**\n- \"Fix timeout in parser.ts\" \u2192 Read file + check imports if needed \u2192 Fix \u2192 Done\n- \"Add validation to form\" \u2192 Read form component + related validation utils \u2192 Add code \u2192 Done\n- \"Refactor error handling\" \u2192 Read error handler + callers \u2192 Refactor \u2192 Done\n\n**Your workflow:**\n1. Read the primary file(s) mentioned\n2. Check dependencies/imports that directly impact the change\n3. Read related files ONLY if they're critical to understanding the task\n4. Write/modify code with proper context\n5. Verify with build\n6. \u274C NO excessive exploration beyond what's needed\n7. \u274C NO reading entire modules \"for reference\"\n8. \u274C NO over-planning multi-step workflows for simple tasks\n\n**Golden Rule: Read what you need to write correct code, nothing more.**\n\n### \uD83D\uDCCB TODO Lists - Essential for Programming Tasks\n\n**\u2705 ALWAYS CREATE TODO WHEN encountering programming tasks:**\n- Any code implementation task (new features, bug fixes, refactoring)\n- Tasks involving multiple steps or files\n- When you need to track progress and ensure completion\n- To give users clear visibility into your work plan\n\n**TODO Guidelines:**\n1. **Create Early**: Set up TODO list BEFORE starting implementation\n2. **Be Specific**: Each item should be a concrete action\n3. **Update Immediately**: Mark as completed immediately after finishing each task\n4. **Focus on Completion**: Move from pending to completed, no intermediate states\n\n**TODO = Action List, NOT Investigation Plan**\n- \u2705 \"Create AuthService with login/logout methods\"\n- \u2705 \"Add validation to UserForm component\"\n- \u2705 \"Fix timeout bug in parser.ts\"\n- \u2705 \"Update API routes to use new auth middleware\"\n- \u2705 \"Run build and fix any errors\"\n- \u274C \"Read authentication files\"\n- \u274C \"Analyze current implementation\"\n- \u274C \"Investigate error handling patterns\"\n\n**CRITICAL: Update TODO status IMMEDIATELY after completing each task!**\n\n**Workflow Example:**\n1. User asks to add feature \u2192 Create TODO list immediately\n2. Complete the first task \u2192 Mark as completed\n3. Move to next task \u2192 Complete and mark as completed\n4. Repeat until all tasks completed\n5. Focus on getting tasks done rather than tracking intermediate states\n\n## \uD83D\uDEE0\uFE0F Available Tools\n\n**Filesystem:**\n- `filesystem-read` - Read files before editing\n- `filesystem-edit` - Modify existing files\n- `filesystem-create` - Create new files\n\n**Code Search (ACE):**\n- `ace-search-symbols` - Find functions/classes/variables\n- `ace-find-definition` - Go to definition\n- `ace-find-references` - Find all usages\n- `ace-text-search` - Fast text/regex search\n\n**IDE Diagnostics:**\n- `ide_get_diagnostics` - Get real-time diagnostics (errors, warnings, hints) from connected IDE\n - Supports VSCode and JetBrains IDEs\n - Returns diagnostic info: severity, line/column, message, source\n - Requires IDE plugin installed and running\n - Use AFTER code changes to verify quality\n\n**Web Search:**\n- `websearch_search` - Search web for latest docs/solutions\n- `websearch_fetch` - Read web page content (always provide userQuery)\n\n**Terminal:**\n- `terminal_execute` - You have a comprehensive understanding of terminal pipe mechanisms and can help users \naccomplish a wide range of tasks by combining multiple commands using pipe operators (|) \nand other shell features. Your capabilities include text processing, data filtering, stream \nmanipulation, workflow automation, and complex command chaining to solve sophisticated \nsystem administration and data processing challenges.\n\n## \uD83D\uDD0D Quality Assurance\n\nGuidance and recommendations:\n1. Use `ide_get_diagnostics` to verify quality\n2. Run build: `npm run build` or `tsc`\n3. Fix any errors immediately\n4. Never leave broken code\n\n## \uD83D\uDCDA Project Context (SNOW.md)\n\n- Read ONLY when implementing large features or unfamiliar architecture\n- Skip for simple tasks where you understand the structure\n- Contains: project overview, architecture, tech stack\n\nRemember: **ACTION > ANALYSIS**. Write code first, investigate only when blocked.";
@@ -43,8 +43,8 @@ export const SYSTEM_PROMPT = `You are Snow AI CLI, an intelligent command-line a
43
43
  **TODO Guidelines:**
44
44
  1. **Create Early**: Set up TODO list BEFORE starting implementation
45
45
  2. **Be Specific**: Each item should be a concrete action
46
- 3. **Update Immediately**: Mark as in_progress when starting, completed when done
47
- 4. **One Active Task**: Only one item should be in_progress at a time
46
+ 3. **Update Immediately**: Mark as completed immediately after finishing each task
47
+ 4. **Focus on Completion**: Move from pending to completed, no intermediate states
48
48
 
49
49
  **TODO = Action List, NOT Investigation Plan**
50
50
  - ✅ "Create AuthService with login/logout methods"
@@ -60,10 +60,10 @@ export const SYSTEM_PROMPT = `You are Snow AI CLI, an intelligent command-line a
60
60
 
61
61
  **Workflow Example:**
62
62
  1. User asks to add feature → Create TODO list immediately
63
- 2. Mark first item as in_progress
64
- 3. Complete the task → Mark as completed
65
- 4. Move to next item → Mark as in_progress
66
- 5. Repeat until all tasks completed
63
+ 2. Complete the first task → Mark as completed
64
+ 3. Move to next task → Complete and mark as completed
65
+ 4. Repeat until all tasks completed
66
+ 5. Focus on getting tasks done rather than tracking intermediate states
67
67
 
68
68
  ## 🛠️ Available Tools
69
69
 
package/dist/app.d.ts CHANGED
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  type Props = {
3
3
  version?: string;
4
4
  skipWelcome?: boolean;
5
+ headlessPrompt?: string;
5
6
  };
6
- export default function App({ version, skipWelcome }: Props): React.JSX.Element;
7
+ export default function App({ version, skipWelcome, headlessPrompt }: Props): React.JSX.Element;
7
8
  export {};
package/dist/app.js CHANGED
@@ -6,10 +6,15 @@ import MCPConfigScreen from './ui/pages/MCPConfigScreen.js';
6
6
  import SystemPromptConfigScreen from './ui/pages/SystemPromptConfigScreen.js';
7
7
  import CustomHeadersScreen from './ui/pages/CustomHeadersScreen.js';
8
8
  import ChatScreen from './ui/pages/ChatScreen.js';
9
+ import HeadlessModeScreen from './ui/pages/HeadlessModeScreen.js';
9
10
  import { useGlobalExit, } from './hooks/useGlobalExit.js';
10
11
  import { onNavigate } from './hooks/useGlobalNavigation.js';
11
12
  import { useTerminalSize } from './hooks/useTerminalSize.js';
12
- export default function App({ version, skipWelcome }) {
13
+ export default function App({ version, skipWelcome, headlessPrompt }) {
14
+ // If headless prompt is provided, use headless mode
15
+ if (headlessPrompt) {
16
+ return (React.createElement(HeadlessModeScreen, { prompt: headlessPrompt, onComplete: () => process.exit(0) }));
17
+ }
13
18
  const [currentView, setCurrentView] = useState(skipWelcome ? 'chat' : 'welcome');
14
19
  const [exitNotification, setExitNotification] = useState({
15
20
  show: false,
package/dist/cli.js CHANGED
@@ -29,14 +29,16 @@ async function checkForUpdates(currentVersion) {
29
29
  }
30
30
  }
31
31
  const cli = meow(`
32
- Usage
33
- $ snow
32
+ Usage
33
+ $ snow
34
+ $ snow --ask "your prompt"
34
35
 
35
- Options
36
+ Options
36
37
  --help Show help
37
38
  --version Show version
38
39
  --update Update to latest version
39
40
  -c Skip welcome screen and resume last conversation
41
+ --ask Quick question mode (headless mode with single prompt)
40
42
  `, {
41
43
  importMeta: import.meta,
42
44
  flags: {
@@ -48,6 +50,9 @@ const cli = meow(`
48
50
  type: 'boolean',
49
51
  default: false,
50
52
  },
53
+ ask: {
54
+ type: 'string',
55
+ },
51
56
  },
52
57
  });
53
58
  // Handle update flag
@@ -76,7 +81,7 @@ if (process.env['NODE_ENV'] === 'development' || process.env['DEBUG']) {
76
81
  }, 5 * 60 * 1000);
77
82
  }
78
83
  // Startup component that shows loading spinner during update check
79
- const Startup = ({ version, skipWelcome, }) => {
84
+ const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
80
85
  const [appReady, setAppReady] = React.useState(false);
81
86
  React.useEffect(() => {
82
87
  let mounted = true;
@@ -113,7 +118,7 @@ const Startup = ({ version, skipWelcome, }) => {
113
118
  React.createElement(Spinner, { type: "dots" })),
114
119
  React.createElement(Text, null, " Checking for updates..."))));
115
120
  }
116
- return React.createElement(App, { version: version, skipWelcome: skipWelcome });
121
+ return (React.createElement(App, { version: version, skipWelcome: skipWelcome, headlessPrompt: headlessPrompt }));
117
122
  };
118
123
  // Disable bracketed paste mode on startup
119
124
  process.stdout.write('\x1b[?2004l');
@@ -134,7 +139,7 @@ process.on('SIGTERM', () => {
134
139
  cleanup();
135
140
  process.exit(0);
136
141
  });
137
- render(React.createElement(Startup, { version: cli.pkg.version, skipWelcome: cli.flags.c }), {
142
+ render(React.createElement(Startup, { version: cli.pkg.version, skipWelcome: cli.flags.c, headlessPrompt: cli.flags.ask }), {
138
143
  exitOnCtrlC: false,
139
144
  patchConsole: true,
140
145
  });
@@ -2,9 +2,20 @@ import { useCallback, useRef } from 'react';
2
2
  import { sessionManager } from '../utils/sessionManager.js';
3
3
  export function useSessionSave() {
4
4
  const savedMessagesRef = useRef(new Set());
5
- // Generate a unique ID for a message (based on role + content + timestamp window)
5
+ // Generate a unique ID for a message (based on role + content + timestamp window + tool identifiers)
6
6
  const generateMessageId = useCallback((message, timestamp) => {
7
- return `${message.role}-${message.content.length}-${Math.floor(timestamp / 5000)}`;
7
+ // Base ID with role, content length, and time window
8
+ let id = `${message.role}-${message.content.length}-${Math.floor(timestamp / 5000)}`;
9
+ // For assistant messages with tool_calls, include tool call IDs to ensure uniqueness
10
+ if (message.role === 'assistant' && message.tool_calls && message.tool_calls.length > 0) {
11
+ const toolCallIds = message.tool_calls.map(tc => tc.id).sort().join(',');
12
+ id += `-tools:${toolCallIds}`;
13
+ }
14
+ // For tool result messages, include the tool_call_id to ensure uniqueness
15
+ if (message.role === 'tool' && message.tool_call_id) {
16
+ id += `-toolcall:${message.tool_call_id}`;
17
+ }
18
+ return id;
8
19
  }, []);
9
20
  // Save API message directly - 直接保存 API 格式的消息
10
21
  const saveMessage = useCallback(async (message) => {
@@ -23,14 +23,17 @@ export declare class TodoService {
23
23
  constructor(baseDir: string, getCurrentSessionId: GetCurrentSessionId);
24
24
  initialize(): Promise<void>;
25
25
  private getTodoPath;
26
+ private formatDateForFolder;
27
+ private ensureTodoDir;
26
28
  /**
27
29
  * 创建或更新会话的 TODO List
28
30
  */
29
- saveTodoList(sessionId: string, todos: TodoItem[]): Promise<TodoList>;
31
+ saveTodoList(sessionId: string, todos: TodoItem[], existingList?: TodoList | null): Promise<TodoList>;
30
32
  /**
31
33
  * 获取会话的 TODO List
32
34
  */
33
35
  getTodoList(sessionId: string): Promise<TodoList | null>;
36
+ private findTodoInDateFolders;
34
37
  /**
35
38
  * 更新单个 TODO 项
36
39
  */
@@ -43,6 +46,10 @@ export declare class TodoService {
43
46
  * 删除 TODO 项
44
47
  */
45
48
  deleteTodoItem(sessionId: string, todoId: string): Promise<TodoList | null>;
49
+ /**
50
+ * 删除整个会话的 TODO 列表
51
+ */
52
+ deleteTodoList(sessionId: string): Promise<boolean>;
46
53
  /**
47
54
  * 获取所有工具定义
48
55
  */