snow-ai 0.3.19 → 0.3.21

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.
@@ -454,6 +454,10 @@ export async function* createStreamingAnthropicCompletion(options, abortSignal,
454
454
  total_tokens: 0,
455
455
  };
456
456
  }
457
+ // Update prompt_tokens if present in message_delta
458
+ if (event.usage.input_tokens !== undefined) {
459
+ usageData.prompt_tokens = event.usage.input_tokens;
460
+ }
457
461
  usageData.completion_tokens = event.usage.output_tokens || 0;
458
462
  usageData.total_tokens =
459
463
  usageData.prompt_tokens + usageData.completion_tokens;
@@ -369,7 +369,10 @@ export class FilesystemMCPService {
369
369
  });
370
370
  }
371
371
  // Single file mode
372
- if (!searchContent || !replaceContent) {
372
+ if (searchContent === undefined ||
373
+ searchContent === null ||
374
+ replaceContent === undefined ||
375
+ replaceContent === null) {
373
376
  throw new Error('searchContent and replaceContent are required for single file mode');
374
377
  }
375
378
  return await this.editFileBySearchSingle(filePath, searchContent, replaceContent, occurrence, contextLines);
@@ -201,12 +201,20 @@ function formatTokens(tokens, compact = false) {
201
201
  }
202
202
  return String(tokens);
203
203
  }
204
- function renderStackedBarChart(stats, terminalWidth) {
204
+ function renderStackedBarChart(stats, terminalWidth, scrollOffset) {
205
205
  if (stats.models.size === 0) {
206
206
  return (React.createElement(Text, { color: "gray", dimColor: true }, "No data available"));
207
207
  }
208
208
  const sortedModels = Array.from(stats.models.entries()).sort((a, b) => b[1].total - a[1].total);
209
209
  const isNarrow = terminalWidth < 100;
210
+ // Show maximum 2 models at a time for better readability
211
+ const maxVisibleModels = 2;
212
+ // Calculate visible range
213
+ const startIdx = scrollOffset;
214
+ const endIdx = Math.min(startIdx + maxVisibleModels, sortedModels.length);
215
+ const visibleModels = sortedModels.slice(startIdx, endIdx);
216
+ const hasMoreAbove = startIdx > 0;
217
+ const hasMoreBelow = endIdx < sortedModels.length;
210
218
  // Calculate max total (including cache) for scaling
211
219
  const maxTotal = Math.max(...Array.from(stats.models.values()).map(s => s.total + s.cacheCreation + s.cacheRead));
212
220
  // Use almost full width for bars (leave some margin)
@@ -227,7 +235,12 @@ function renderStackedBarChart(stats, terminalWidth) {
227
235
  React.createElement(Text, { color: "gray", dimColor: true },
228
236
  ' ',
229
237
  "Cache Create")),
230
- sortedModels.map(([modelName, modelStats]) => {
238
+ hasMoreAbove && (React.createElement(Box, { marginBottom: 1 },
239
+ React.createElement(Text, { color: "yellow", dimColor: true },
240
+ "\u2191 ",
241
+ startIdx,
242
+ " more above (use \u2191 arrow)"))),
243
+ visibleModels.map(([modelName, modelStats]) => {
231
244
  const shortName = getModelShortName(modelName, 30);
232
245
  // Calculate segment lengths based on proportion
233
246
  // Ensure at least 1 character if value exists
@@ -298,7 +311,12 @@ function renderStackedBarChart(stats, terminalWidth) {
298
311
  React.createElement(Text, { color: "yellow", bold: true },
299
312
  "Create:",
300
313
  ' ',
301
- formatTokens(Array.from(stats.models.values()).reduce((sum, s) => sum + s.cacheCreation, 0))))))))));
314
+ formatTokens(Array.from(stats.models.values()).reduce((sum, s) => sum + s.cacheCreation, 0)))))))),
315
+ hasMoreBelow && (React.createElement(Box, { marginTop: 1 },
316
+ React.createElement(Text, { color: "yellow", dimColor: true },
317
+ "\u2193 ",
318
+ sortedModels.length - endIdx,
319
+ " more below (use \u2193 arrow)")))));
302
320
  }
303
321
  export default function UsagePanel() {
304
322
  const [granularity, setGranularity] = useState('week');
@@ -308,6 +326,7 @@ export default function UsagePanel() {
308
326
  });
309
327
  const [isLoading, setIsLoading] = useState(true);
310
328
  const [error, setError] = useState(null);
329
+ const [scrollOffset, setScrollOffset] = useState(0);
311
330
  const { columns: terminalWidth } = useTerminalSize();
312
331
  useEffect(() => {
313
332
  const load = async () => {
@@ -328,6 +347,10 @@ export default function UsagePanel() {
328
347
  };
329
348
  load();
330
349
  }, [granularity]);
350
+ // Reset scroll when changing granularity
351
+ useEffect(() => {
352
+ setScrollOffset(0);
353
+ }, [granularity]);
331
354
  useInput((_input, key) => {
332
355
  if (key.tab) {
333
356
  const granularities = ['hour', 'day', 'week', 'month'];
@@ -335,6 +358,17 @@ export default function UsagePanel() {
335
358
  const nextIdx = (currentIdx + 1) % granularities.length;
336
359
  setGranularity(granularities[nextIdx]);
337
360
  }
361
+ // Calculate available space for scrolling
362
+ const sortedModels = Array.from(stats.models.entries()).sort((a, b) => b[1].total - a[1].total);
363
+ const totalModels = sortedModels.length;
364
+ if (key.upArrow) {
365
+ setScrollOffset(prev => Math.max(0, prev - 1));
366
+ }
367
+ if (key.downArrow) {
368
+ // Reserve space for header, legend, total summary
369
+ const maxScroll = Math.max(0, totalModels - 1);
370
+ setScrollOffset(prev => Math.min(maxScroll, prev + 1));
371
+ }
338
372
  });
339
373
  if (isLoading) {
340
374
  return (React.createElement(Box, { borderColor: "cyan", borderStyle: "round", paddingX: 2, paddingY: 0 },
@@ -356,5 +390,5 @@ export default function UsagePanel() {
356
390
  React.createElement(Text, { color: "gray", dimColor: true },
357
391
  ' ',
358
392
  "- Tab to switch")),
359
- stats.models.size === 0 ? (React.createElement(Text, { color: "gray", dimColor: true }, "No usage data for this period")) : (renderStackedBarChart(stats, terminalWidth))));
393
+ stats.models.size === 0 ? (React.createElement(Text, { color: "gray", dimColor: true }, "No usage data for this period")) : (renderStackedBarChart(stats, terminalWidth, scrollOffset))));
360
394
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.3.19",
3
+ "version": "0.3.21",
4
4
  "description": "Intelligent Command Line Assistant powered by AI",
5
5
  "license": "MIT",
6
6
  "bin": {