@leing2021/super-pi 0.23.10 → 0.23.11

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.
@@ -521,7 +521,10 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
521
521
  return renderSubagentCall(args, theme)
522
522
  },
523
523
  renderResult(result, renderContext, theme, _context) {
524
- return renderSubagentResult(result.details as SubagentLiveDetails, renderContext, theme)
524
+ // Handle partial updates where data is at top level (from onUpdate)
525
+ // rather than nested in .details (from final result return value)
526
+ const data = (result.details || result) as SubagentLiveDetails
527
+ return renderSubagentResult(data, renderContext, theme)
525
528
  },
526
529
  })
527
530
 
@@ -623,19 +626,29 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
623
626
  { onUpdate },
624
627
  )
625
628
 
626
- // Build summary content
629
+ // Build compact summary content for LLM consumption
627
630
  const successCount = result.results.filter(r => r.exitCode === 0).length
628
631
  const failCount = result.results.filter(r => isFailedResult(r)).length
629
- const summaries = result.results.map(r => {
632
+ const summaries = result.results.map((r, i) => {
633
+ const icon = isFailedResult(r) ? "✗" : "✓"
630
634
  const output = getFinalOutput(r.messages) || r.errorMessage || r.stderr || "(no output)"
631
- const status = isFailedResult(r) ? "failed" : "completed"
632
- return `### [${r.agent}] ${status}\n\n${output}`
635
+ // Compact: first non-empty line, stripped of markdown formatting
636
+ const summaryLine = output.split("\n").find((l: string) => l.trim().length > 0) || ""
637
+ const cleaned = summaryLine.replace(/^#+\s*/, "").replace(/\*\*/g, "").trim()
638
+ const oneLine = cleaned.length > 200 ? cleaned.slice(0, 199) + "…" : cleaned
639
+ return `${i + 1}. ${icon} ${r.agent} — ${oneLine}`
640
+ })
641
+
642
+ // Full outputs available in details for expanded view
643
+ const fullOutputs = result.results.map(r => {
644
+ const output = getFinalOutput(r.messages) || ""
645
+ return output
633
646
  })
634
647
 
635
648
  return {
636
649
  content: [{
637
650
  type: "text",
638
- text: `Parallel: ${successCount}/${result.results.length} succeeded${failCount > 0 ? `, ${failCount} failed` : ""}\n\n${summaries.join("\n\n---\n\n")}`,
651
+ text: `Parallel: ${successCount}/${result.results.length} succeeded${failCount > 0 ? `, ${failCount} failed` : ""}\n${summaries.join("\n")}`,
639
652
  }],
640
653
  details: result,
641
654
  }
@@ -644,7 +657,10 @@ export default function ceCoreExtension(pi: ExtensionAPI) {
644
657
  return renderSubagentCall(args, theme)
645
658
  },
646
659
  renderResult(result, renderContext, theme, _context) {
647
- return renderSubagentResult(result.details as SubagentLiveDetails, renderContext, theme)
660
+ // Handle partial updates where data is at top level (from onUpdate)
661
+ // rather than nested in .details (from final result return value)
662
+ const data = (result.details || result) as SubagentLiveDetails
663
+ return renderSubagentResult(data, renderContext, theme)
648
664
  },
649
665
  })
650
666
 
@@ -142,13 +142,14 @@ export function renderSubagentCall(
142
142
 
143
143
  if (args.tasks && args.tasks.length > 0) {
144
144
  let text =
145
- theme.fg("toolTitle", theme.bold("ce_parallel_subagent ")) +
146
- theme.fg("accent", `parallel (${args.tasks.length} tasks)`)
147
- for (const t of args.tasks.slice(0, 3)) {
148
- const preview = t.task.length > 40 ? `${t.task.slice(0, 40)}...` : t.task
149
- text += `\n ${theme.fg("accent", t.agent)}${theme.fg("dim", ` ${preview}`)}`
145
+ theme.fg("toolTitle", theme.bold(" parallel ")) +
146
+ theme.fg("accent", `${args.tasks.length} agents launching...`)
147
+ for (let i = 0; i < args.tasks.length; i++) {
148
+ const t = args.tasks[i]
149
+ const num = theme.fg("muted", `${i + 1}.`)
150
+ const preview = t.task.length > 50 ? `${t.task.slice(0, 50)}...` : t.task
151
+ text += `\n ${num} ${theme.fg("accent", t.agent)} ${theme.fg("dim", preview)}`
150
152
  }
151
- if (args.tasks.length > 3) text += `\n ${theme.fg("muted", `... +${args.tasks.length - 3} more`)}`
152
153
  return new Text(text, 0, 0)
153
154
  }
154
155
 
@@ -373,70 +374,94 @@ function renderParallelResult(
373
374
  const successCount = results.filter(r => r.exitCode !== -1 && !isFailedResult(r)).length
374
375
  const failCount = results.filter(r => r.exitCode !== -1 && isFailedResult(r)).length
375
376
  const isRunning = running > 0
376
- const icon = isRunning
377
- ? theme.fg("warning", "⏳")
378
- : failCount > 0
379
- ? theme.fg("warning", "◐")
380
- : theme.fg("success", "")
381
- const status = isRunning
382
- ? `${successCount + failCount}/${results.length} done, ${running} running`
383
- : `${successCount}/${results.length} tasks`
384
-
385
- if (context.expanded && !isRunning) {
377
+
378
+ if (isRunning) {
379
+ // --- Live progress: compact status line ---
380
+ const doneCount = successCount + failCount
381
+ const icon = theme.fg("warning", "")
382
+ const bar = renderProgressBar(doneCount, results.length, theme)
383
+ const doneLabel = failCount > 0
384
+ ? theme.fg("success", `${successCount}✓`) + " " + theme.fg("error", `${failCount}✗`)
385
+ : theme.fg("success", `${successCount}✓`)
386
+ const runningLabel = theme.fg("dim", `, ${running} running...`)
387
+ return new Text(`${icon} ${bar} ${doneLabel}${runningLabel}`, 0, 0)
388
+ }
389
+
390
+ // --- Completed: summary card layout ---
391
+ const allSuccess = failCount === 0
392
+ const headerIcon = allSuccess ? theme.fg("success", "✓") : theme.fg("warning", "◐")
393
+ const headerText = failCount > 0
394
+ ? `${successCount}/${results.length} succeeded, ${failCount} failed`
395
+ : `${successCount}/${results.length} succeeded`
396
+
397
+ if (context.expanded) {
398
+ // Expanded: header + per-task details with tool calls and output
386
399
  const container = new Container()
387
- container.addChild(new Text(`${icon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", status)}`, 0, 0))
400
+ container.addChild(new Text(`${headerIcon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", headerText)}`, 0, 0))
401
+ container.addChild(new Spacer(1))
388
402
 
389
403
  for (const r of results) {
390
404
  const rIcon = isFailedResult(r) ? theme.fg("error", "✗") : theme.fg("success", "✓")
391
- const displayItems = getDisplayItems(r.messages)
392
405
  const finalOutput = getFinalOutput(r.messages)
406
+ const summaryText = isFailedResult(r)
407
+ ? (r.errorMessage || r.stderr || "unknown error")
408
+ : (finalOutput ? summarizeText(finalOutput, 200) : "(no output)")
393
409
 
394
- container.addChild(new Spacer(1))
395
- container.addChild(new Text(`${theme.fg("muted", "─── ")}${theme.fg("accent", r.agent)} ${rIcon}`, 0, 0))
396
- container.addChild(new Text(theme.fg("muted", "Task: ") + theme.fg("dim", r.task), 0, 0))
397
- for (const item of displayItems) {
398
- if (item.type === "toolCall")
399
- container.addChild(new Text(theme.fg("muted", "→ ") + formatToolCall(item.name, item.args, theme.fg.bind(theme)), 0, 0))
400
- }
401
- if (finalOutput) {
402
- container.addChild(new Spacer(1))
410
+ container.addChild(new Text(`${rIcon} ${theme.fg("accent", r.agent)} — ${summaryText}`, 0, 0))
411
+
412
+ if (!isFailedResult(r) && finalOutput) {
403
413
  container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme))
404
414
  }
415
+
405
416
  const taskUsage = formatUsageStats(r.usage, r.model)
406
417
  if (taskUsage) container.addChild(new Text(theme.fg("dim", taskUsage), 0, 0))
418
+ container.addChild(new Spacer(1))
407
419
  }
408
420
 
409
421
  const usageStr = formatUsageStats(aggregateUsage(results))
410
422
  if (usageStr) {
411
- container.addChild(new Spacer(1))
412
423
  container.addChild(new Text(theme.fg("dim", `Total: ${usageStr}`), 0, 0))
413
424
  }
414
425
  return container
415
426
  }
416
427
 
417
- // Collapsed (or still running)
418
- let text = `${icon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", status)}`
428
+ // Collapsed: one-line summary per task
429
+ let text = `${headerIcon} ${theme.fg("toolTitle", theme.bold("parallel "))}${theme.fg("accent", headerText)}`
419
430
  for (const r of results) {
420
- const rIcon =
421
- r.exitCode === -1
422
- ? theme.fg("warning", "⏳")
423
- : isFailedResult(r)
424
- ? theme.fg("error", "")
425
- : theme.fg("success", "✓")
426
- const displayItems = getDisplayItems(r.messages)
427
- text += `\n\n${theme.fg("muted", "─── ")}${theme.fg("accent", r.agent)} ${rIcon}`
428
- if (displayItems.length === 0)
429
- text += `\n${theme.fg("muted", r.exitCode === -1 ? "(running...)" : "(no output)")}`
430
- else text += `\n${renderDisplayItems(displayItems, 5)}`
431
+ const rIcon = isFailedResult(r) ? theme.fg("error", "✗") : theme.fg("success", "✓")
432
+ const finalOutput = getFinalOutput(r.messages)
433
+ const summaryText = isFailedResult(r)
434
+ ? (r.errorMessage || r.stderr || "unknown error")
435
+ : (finalOutput ? summarizeText(finalOutput, 120) : "(no output)")
436
+ text += `\n ${rIcon} ${theme.fg("accent", r.agent)} — ${summaryText}`
431
437
  }
432
- if (!isRunning) {
433
- const usageStr = formatUsageStats(aggregateUsage(results))
434
- if (usageStr) text += `\n\n${theme.fg("dim", `Total: ${usageStr}`)}`
435
- }
436
- if (!context.expanded) text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`
438
+ const usageStr = formatUsageStats(aggregateUsage(results))
439
+ if (usageStr) text += `\n${theme.fg("dim", usageStr)}`
440
+ text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`
437
441
  return new Text(text, 0, 0)
438
442
  }
439
443
 
444
+ // ---------------------------------------------------------------------------
445
+ // Progress bar & text helpers
446
+ // ---------------------------------------------------------------------------
447
+
448
+ function renderProgressBar(done: number, total: number, theme: Theme): string {
449
+ const width = Math.min(total, 20)
450
+ const filled = Math.round((done / total) * width)
451
+ const empty = width - filled
452
+ const bar = theme.fg("success", "█".repeat(filled)) + theme.fg("dim", "░".repeat(empty))
453
+ return bar
454
+ }
455
+
456
+ function summarizeText(text: string, maxLen: number): string {
457
+ // Take first meaningful paragraph or line
458
+ const firstLine = text.split("\n").find(l => l.trim().length > 0) || ""
459
+ // Strip markdown headers and bold for summary
460
+ const cleaned = firstLine.replace(/^#+\s*/, "").replace(/\*\*/g, "").replace(/\[.*?\]\(.*?\)/g, "").trim()
461
+ if (cleaned.length <= maxLen) return cleaned
462
+ return cleaned.slice(0, maxLen - 1) + "…"
463
+ }
464
+
440
465
  // ---------------------------------------------------------------------------
441
466
  // Markdown theme helper
442
467
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leing2021/super-pi",
3
- "version": "0.23.10",
3
+ "version": "0.23.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Pi-native Compound Engineering package for iterative development workflows",