sharkcode 0.3.6 → 0.3.8

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 (2) hide show
  1. package/dist/cli.mjs +88 -27
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -204,6 +204,23 @@ import { exec } from "child_process";
204
204
 
205
205
  // src/permission.ts
206
206
  import chalk from "chalk";
207
+
208
+ // src/spinnerState.ts
209
+ var _stop = null;
210
+ function registerToolSpinner(stop) {
211
+ _stop = stop;
212
+ }
213
+ function unregisterToolSpinner() {
214
+ _stop = null;
215
+ }
216
+ function stopToolSpinner() {
217
+ if (_stop) {
218
+ _stop();
219
+ _stop = null;
220
+ }
221
+ }
222
+
223
+ // src/permission.ts
207
224
  var PURPLE = chalk.hex("#a855f7");
208
225
  var GRAY = chalk.gray;
209
226
  var GREEN = chalk.green;
@@ -224,6 +241,7 @@ async function askPermission(command) {
224
241
  );
225
242
  return true;
226
243
  }
244
+ stopToolSpinner();
227
245
  const width = Math.min(72, process.stdout.columns ?? 80);
228
246
  const innerWidth = width - 4;
229
247
  const line = (s) => ` ${s}
@@ -315,28 +333,45 @@ function createProvider(config) {
315
333
 
316
334
  // src/agent.ts
317
335
  var PURPLE2 = chalk2.hex("#a855f7");
336
+ var PURPLE_DIM = chalk2.hex("#7c3aed");
318
337
  var TOOL_LABELS = {
319
- read_file: { icon: "\u{1F4D6}", verb: "reading file" },
320
- write_file: { icon: "\u270D\uFE0F ", verb: "writing file" },
321
- edit_file: { icon: "\u270F\uFE0F ", verb: "editing file" },
322
- bash: { icon: "\u2699\uFE0F ", verb: "running command" }
338
+ read_file: { icon: "\u{1F4D6}", verb: "reading" },
339
+ write_file: { icon: "\u270D\uFE0F ", verb: "writing" },
340
+ edit_file: { icon: "\u270F\uFE0F ", verb: "editing" },
341
+ bash: { icon: "\u2699\uFE0F ", verb: "running" }
323
342
  };
343
+ function playScanLine() {
344
+ return new Promise((resolve4) => {
345
+ const cols = Math.min(process.stdout.columns ?? 80, 72);
346
+ const steps = 12;
347
+ const chars = "\u258F\u258E\u258D\u258C\u258B\u258A\u2589\u2588\u2589\u258A\u258B\u258C\u258D\u258E\u258F";
348
+ let frame = 0;
349
+ const t = setInterval(() => {
350
+ const pos = Math.floor(frame / steps * cols);
351
+ const bar = PURPLE_DIM("\u2500".repeat(pos)) + PURPLE2(chars[frame % chars.length]) + chalk2.dim("\u2500".repeat(Math.max(0, cols - pos - 1)));
352
+ process.stdout.write(`\r${bar}`);
353
+ frame++;
354
+ if (frame >= steps) {
355
+ clearInterval(t);
356
+ process.stdout.write(`\r${PURPLE2("\u2500".repeat(cols))}
357
+ `);
358
+ resolve4();
359
+ }
360
+ }, 30);
361
+ });
362
+ }
324
363
  function createSpinner(label) {
325
364
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
326
365
  let i = 0;
327
366
  let timer = null;
328
367
  return {
329
368
  start() {
330
- process.stdout.write("\n");
331
369
  timer = setInterval(() => {
332
370
  process.stdout.write(
333
- `\r${PURPLE2(frames[i++ % frames.length])} ${chalk2.gray(label)}`
371
+ `\r ${PURPLE2(frames[i++ % frames.length])} ${chalk2.gray(label)}`
334
372
  );
335
373
  }, 80);
336
374
  },
337
- update(newLabel) {
338
- label = newLabel;
339
- },
340
375
  stop() {
341
376
  if (timer) {
342
377
  clearInterval(timer);
@@ -378,9 +413,24 @@ async function runAgent(messages, config) {
378
413
  let currentStep = 0;
379
414
  const thinkingSpinner = createSpinner("thinking...");
380
415
  let thinkingDone = false;
416
+ let trailingNL = 0;
417
+ function writeOut(text) {
418
+ if (!text) return;
419
+ process.stdout.write(text);
420
+ for (const ch of text) {
421
+ if (ch === "\n") trailingNL++;
422
+ else trailingNL = 0;
423
+ }
424
+ }
425
+ function collapseNL(keep = 1) {
426
+ if (trailingNL > keep) {
427
+ const remove = trailingNL - keep;
428
+ process.stdout.write(`\x1B[${remove}A\x1B[J`);
429
+ trailingNL = keep;
430
+ }
431
+ }
381
432
  let toolSpinner = null;
382
433
  let currentToolName = "";
383
- let currentToolArgs = null;
384
434
  thinkingSpinner.start();
385
435
  for await (const event of result.fullStream) {
386
436
  if (!thinkingDone && (event.type === "text-delta" || event.type === "tool-call" || event.type === "error")) {
@@ -389,43 +439,51 @@ async function runAgent(messages, config) {
389
439
  }
390
440
  switch (event.type) {
391
441
  case "text-delta":
392
- process.stdout.write(event.text);
442
+ if (trailingNL > 1 && event.text.trim() !== "") collapseNL(1);
443
+ writeOut(event.text);
393
444
  break;
394
445
  case "tool-call": {
395
446
  const meta = TOOL_LABELS[event.toolName] ?? { icon: "\u{1F527}", verb: "running" };
396
447
  currentToolName = event.toolName;
397
- currentToolArgs = event.input;
398
448
  const argHint = getArgHint(event.toolName, event.input);
399
- const spinLabel = `${meta.verb}${argHint ? ` \u203A ${argHint}` : ""}`;
449
+ if (trailingNL === 0) writeOut("\n");
450
+ collapseNL(1);
451
+ await playScanLine();
400
452
  process.stdout.write(
401
- "\n" + chalk2.cyan(`${meta.icon} ${event.toolName}`) + chalk2.gray(argHint ? ` ${argHint}` : "") + "\n"
453
+ ` ${meta.icon} ${PURPLE2(meta.verb)}${argHint ? chalk2.dim(" \u203A ") + chalk2.white(argHint) : ""}
454
+ `
402
455
  );
403
- toolSpinner = createSpinner(spinLabel);
456
+ toolSpinner = createSpinner(`${meta.verb}...`);
457
+ registerToolSpinner(() => toolSpinner?.stop());
404
458
  toolSpinner.start();
459
+ trailingNL = 0;
405
460
  break;
406
461
  }
407
462
  case "tool-result": {
408
463
  if (toolSpinner) {
409
464
  toolSpinner.stop();
410
465
  toolSpinner = null;
466
+ unregisterToolSpinner();
411
467
  }
412
- const meta = TOOL_LABELS[currentToolName] ?? { icon: "\u{1F527}", verb: "done" };
413
- const summary = truncate(String(event.output), 100);
468
+ const summary = truncate(String(event.output), 80);
414
469
  process.stdout.write(
415
- chalk2.green(` \u2713 done`) + chalk2.gray(` ${summary}`) + "\n\n"
470
+ ` ${chalk2.green("\u2713")} ${chalk2.dim(summary)}
471
+ `
416
472
  );
473
+ trailingNL = 1;
417
474
  break;
418
475
  }
419
476
  case "tool-error":
420
477
  if (toolSpinner) {
421
478
  toolSpinner.stop();
422
479
  toolSpinner = null;
480
+ unregisterToolSpinner();
423
481
  }
424
482
  process.stderr.write(
425
- chalk2.red(`
426
- \u2717 Tool error [${event.toolName}]: ${String(event.error)}
483
+ chalk2.red(` \u2717 [${event.toolName}] ${String(event.error)}
427
484
  `)
428
485
  );
486
+ trailingNL = 1;
429
487
  break;
430
488
  case "finish-step":
431
489
  currentStep++;
@@ -434,24 +492,27 @@ async function runAgent(messages, config) {
434
492
  if (toolSpinner) {
435
493
  toolSpinner.stop();
436
494
  toolSpinner = null;
495
+ unregisterToolSpinner();
437
496
  }
438
497
  thinkingSpinner.stop();
439
498
  process.stderr.write(chalk2.red(`
440
- \u274C Error: ${String(event.error)}
499
+ \u274C ${String(event.error)}
441
500
  `));
501
+ trailingNL = 1;
442
502
  break;
443
503
  }
444
504
  }
445
505
  thinkingSpinner.stop();
446
- if (toolSpinner) toolSpinner.stop();
447
- process.stdout.write("\n");
506
+ if (toolSpinner) {
507
+ toolSpinner.stop();
508
+ unregisterToolSpinner();
509
+ }
510
+ if (trailingNL === 0) process.stdout.write("\n");
448
511
  const usage = await result.totalUsage;
449
512
  if (usage) {
450
513
  process.stderr.write(
451
- chalk2.gray(
452
- `\u{1F4CA} ${usage.inputTokens} in / ${usage.outputTokens} out | steps: ${currentStep}
453
- `
454
- )
514
+ chalk2.dim(` \u{1F4CA} ${usage.inputTokens}\u2191 ${usage.outputTokens}\u2193 steps:${currentStep}
515
+ `)
455
516
  );
456
517
  }
457
518
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sharkcode",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Local First, open-source AI Coding Agent",
5
5
  "type": "module",
6
6
  "bin": {