ikie-cli 0.1.8 → 0.1.9

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/agent.js CHANGED
@@ -2,7 +2,7 @@ import chalk from 'chalk';
2
2
  import * as readline from 'node:readline';
3
3
  import { TOOL_DEFS, SAFE_TOOLS, PLAN_TOOLS, formatToolArgs, executeTool } from './tools.js';
4
4
  import { renderMarkdown, extractThinkTags } from './renderer.js';
5
- import { c, toolLine, permissionPrompt, toolSuccessLine, toolErrorLine, InlineSpinner } from './theme.js';
5
+ import { c, toolLine, permissionPrompt, toolSuccessLine, toolErrorLine, toolOutputBlock, toolDiffBlock, InlineSpinner } from './theme.js';
6
6
  export function estimateTokens(chars) {
7
7
  return Math.max(1, Math.round(chars / 4));
8
8
  }
@@ -474,8 +474,16 @@ export class Agent {
474
474
  const result = await executeTool(name, input);
475
475
  this.recordChangedFile(name, input, result);
476
476
  const ms = Date.now() - t0;
477
- const preview = result.split('\n')[0].slice(0, 80);
478
- process.stdout.write(`${this.indent}${toolSuccessLine(ms, preview)}\n`);
477
+ let block;
478
+ if ((name === 'edit_file' || name === 'write_file') && !result.startsWith('Error')) {
479
+ const oldStr = String(input.old_string ?? '');
480
+ const newStr = String(input.new_string ?? input.content ?? '');
481
+ block = toolDiffBlock(oldStr, newStr, ms);
482
+ }
483
+ else {
484
+ block = toolOutputBlock(result, ms);
485
+ }
486
+ process.stdout.write(`${this.indent}${block}\n`);
479
487
  return result;
480
488
  }
481
489
  catch (err) {
package/dist/theme.d.ts CHANGED
@@ -58,6 +58,10 @@ export declare class InlineSpinner {
58
58
  updateLabel(label: string): void;
59
59
  }
60
60
  export declare function toolLine(name: string, args: string): string;
61
+ /** Multi-line output block shown after a tool runs. */
62
+ export declare function toolOutputBlock(result: string, ms: number): string;
63
+ /** Colored diff block for edit_file / write_file. */
64
+ export declare function toolDiffBlock(oldStr: string, newStr: string, ms: number): string;
61
65
  export declare function toolSuccessLine(ms: number, preview?: string): string;
62
66
  export declare function toolErrorLine(msg: string): string;
63
67
  export declare function successLine(msg: string): string;
package/dist/theme.js CHANGED
@@ -330,31 +330,91 @@ export class InlineSpinner {
330
330
  this.draw();
331
331
  }
332
332
  }
333
- // Maps a tool name to a clean verb + a dot color reflecting its effect.
334
- // Read-only tools are calm (info), mutating tools warn, exec/agent stand out.
333
+ // Maps a tool name to a display name + dot color reflecting its effect.
335
334
  function toolMeta(rawName) {
336
335
  const base = rawName.split(/\s|×/)[0];
337
336
  switch (base) {
338
- case 'read_file': return { verb: 'read', tint: c.info };
339
- case 'write_file': return { verb: 'write', tint: c.warning };
340
- case 'edit_file': return { verb: 'edit', tint: c.warning };
341
- case 'bash': return { verb: 'run', tint: c.accent };
342
- case 'list_dir': return { verb: 'list', tint: c.info };
343
- case 'grep': return { verb: 'grep', tint: c.info };
344
- case 'search_files': return { verb: 'find', tint: c.info };
345
- case 'memory_write': return { verb: 'memory', tint: c.secondary };
346
- case 'spawn_agent': return { verb: 'agent', tint: c.secondary };
347
- case 'ask_user': return { verb: 'ask', tint: c.info };
337
+ case 'read_file': return { verb: 'Read', tint: c.info };
338
+ case 'write_file': return { verb: 'Write', tint: c.warning };
339
+ case 'edit_file': return { verb: 'Update', tint: c.warning };
340
+ case 'bash': return { verb: 'Bash', tint: c.accent };
341
+ case 'list_dir': return { verb: 'List', tint: c.info };
342
+ case 'grep': return { verb: 'Grep', tint: c.info };
343
+ case 'search_files': return { verb: 'Search', tint: c.info };
344
+ case 'memory_write': return { verb: 'Remember', tint: c.secondary };
345
+ case 'spawn_agent': return { verb: 'Agent', tint: c.secondary };
346
+ case 'ask_user': return { verb: 'Ask', tint: c.info };
347
+ case 'fetch_url': return { verb: 'Fetch', tint: c.info };
348
+ case 'web_search': return { verb: 'WebSearch', tint: c.info };
349
+ case 'git_status': return { verb: 'GitStatus', tint: c.info };
350
+ case 'git_diff': return { verb: 'GitDiff', tint: c.info };
351
+ case 'git_log': return { verb: 'GitLog', tint: c.info };
352
+ case 'git_commit': return { verb: 'Commit', tint: c.success };
353
+ case 'git_branch': return { verb: 'GitBranch', tint: c.info };
348
354
  default: return { verb: base, tint: c.primary };
349
355
  }
350
356
  }
357
+ function clampLine(s, max = 120) {
358
+ return s.length > max ? s.slice(0, max) + '…' : s;
359
+ }
351
360
  export function toolLine(name, args) {
352
361
  const { verb, tint } = toolMeta(name);
353
- // Surface a "×N" batch suffix as a subtle count badge.
354
362
  const countMatch = name.match(/×(\d+)/);
355
- const badge = countMatch ? ` ${c.muted(`×${countMatch[1]}`)}` : '';
356
- const label = c.white.bold(verb.padEnd(6));
357
- return `${tint('●')} ${label}${badge} ${c.dim(args)}`;
363
+ const badge = countMatch ? ` ×${countMatch[1]}` : '';
364
+ return `${tint('●')} ${c.white.bold(verb + badge)}${c.dim('(')}${c.muted(args)}${c.dim(')')}`;
365
+ }
366
+ /** Multi-line output block shown after a tool runs. */
367
+ export function toolOutputBlock(result, ms) {
368
+ const time = c.muted(formatDuration(ms));
369
+ const lines = result.split('\n').filter(l => l.trim() !== '');
370
+ if (!lines.length)
371
+ return ` ${c.muted('⎿')} ${time}`;
372
+ const MAX = 5;
373
+ const shown = lines.slice(0, MAX);
374
+ const hidden = lines.length - MAX;
375
+ const out = [];
376
+ out.push(` ${c.muted('⎿')} ${time} ${c.dim(clampLine(shown[0]))}`);
377
+ for (let i = 1; i < shown.length; i++) {
378
+ out.push(` ${c.dim(clampLine(shown[i]))}`);
379
+ }
380
+ if (hidden > 0) {
381
+ out.push(` ${c.muted(`… +${hidden} lines`)}`);
382
+ }
383
+ return out.join('\n');
384
+ }
385
+ /** Colored diff block for edit_file / write_file. */
386
+ export function toolDiffBlock(oldStr, newStr, ms) {
387
+ const time = c.muted(formatDuration(ms));
388
+ const removed = oldStr.split('\n');
389
+ const added = newStr.split('\n');
390
+ const nRemoved = removed.filter(l => l.trim()).length;
391
+ const nAdded = added.filter(l => l.trim()).length;
392
+ const parts = [];
393
+ if (nAdded)
394
+ parts.push(`Added ${nAdded} line${nAdded === 1 ? '' : 's'}`);
395
+ if (nRemoved)
396
+ parts.push(`removed ${nRemoved} line${nRemoved === 1 ? '' : 's'}`);
397
+ const summary = parts.join(', ') || 'no changes';
398
+ const out = [];
399
+ out.push(` ${c.muted('⎿')} ${time} ${c.dim(summary)}`);
400
+ const MAX = 10;
401
+ let shown = 0;
402
+ for (const line of removed) {
403
+ if (shown >= MAX)
404
+ break;
405
+ out.push(chalk.bgRed.white(` - ${clampLine(line, 116)}`));
406
+ shown++;
407
+ }
408
+ for (const line of added) {
409
+ if (shown >= MAX)
410
+ break;
411
+ out.push(chalk.bgGreen.black(` + ${clampLine(line, 116)}`));
412
+ shown++;
413
+ }
414
+ if (shown >= MAX && (removed.length + added.length > MAX)) {
415
+ out.push(` ${c.muted(`… +${removed.length + added.length - MAX} lines`)}`);
416
+ }
417
+ return out.join('\n');
358
418
  }
359
419
  export function toolSuccessLine(ms, preview) {
360
420
  const time = c.muted(formatDuration(ms));
@@ -362,7 +422,7 @@ export function toolSuccessLine(ms, preview) {
362
422
  return ` ${c.muted('⎿')} ${time}${tail}`;
363
423
  }
364
424
  export function toolErrorLine(msg) {
365
- return ` ${c.muted('⎿')} ${c.error('failed')} ${c.error(msg)}`;
425
+ return ` ${c.muted('⎿')} ${c.error('Error')} ${c.dim(msg)}`;
366
426
  }
367
427
  function formatDuration(ms) {
368
428
  if (ms < 1000)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ikie-cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Agentic coding CLI — your terminal AI pair programmer",
5
5
  "type": "module",
6
6
  "bin": {