pi-ultracode 0.10.1 → 0.10.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ultracode",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "Adaptive semantic-depth workflow orchestration for Pi, with focused, standard, and deep modes, isolated subagents, worktree delivery, structured output, and durable resume.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -50,13 +50,15 @@
50
50
  "typecheck": "tsc --noEmit"
51
51
  },
52
52
  "dependencies": {
53
- "acorn": "^8.11.0"
53
+ "acorn": "^8.11.0",
54
+ "js-beautify": "^2.0.3"
54
55
  },
55
56
  "devDependencies": {
56
57
  "@earendil-works/pi-agent-core": "^0.99.1",
57
58
  "@earendil-works/pi-ai": "^0.99.1",
58
59
  "@earendil-works/pi-coding-agent": "^0.99.1",
59
60
  "@earendil-works/pi-tui": "^0.99.1",
61
+ "@types/js-beautify": "^1.14.3",
60
62
  "@types/node": "^24.12.4",
61
63
  "typebox": "1.3.7",
62
64
  "typescript": "^5.9.3"
@@ -6,8 +6,9 @@
6
6
 
7
7
  import * as crypto from "node:crypto";
8
8
  import * as path from "node:path";
9
- import { defineTool, type ToolDefinition } from "@earendil-works/pi-coding-agent";
10
- import { Text } from "@earendil-works/pi-tui";
9
+ import { defineTool, highlightCode, type Theme, type ToolDefinition } from "@earendil-works/pi-coding-agent";
10
+ import { Box, Container, Spacer, Text } from "@earendil-works/pi-tui";
11
+ import beautify from "js-beautify";
11
12
  import { Type } from "typebox";
12
13
  import {
13
14
  WORKFLOW_GUIDELINES,
@@ -122,7 +123,10 @@ function nextRunId(): string {
122
123
 
123
124
  export function createWorkflowTool(deps: WorkflowToolDeps = {}): ToolDefinition<typeof workflowToolSchema, any> {
124
125
  const registry = deps.registry ?? new WorkflowRegistry();
126
+ // Status updates rerender the call; format each completed display source only once.
127
+ let formattedSource: { input: string; output: string } | undefined;
125
128
  return defineTool({
129
+ renderShell: "self",
126
130
  name: "workflow",
127
131
  exposure: "model-only",
128
132
  annotations: {
@@ -603,30 +607,68 @@ export function createWorkflowTool(deps: WorkflowToolDeps = {}): ToolDefinition<
603
607
  signal?.removeEventListener("abort", onOuterAbort);
604
608
  }
605
609
  },
606
- renderCall(args, theme) {
610
+ renderCall(args, theme, { argsComplete }) {
607
611
  const title = theme.fg("toolTitle", theme.bold("workflow"));
608
- // Arguments arrive incrementally; display source without parsing incomplete JavaScript.
609
612
  if (typeof args.script === "string" && args.script.length > 0) {
610
- return new Text(`${title}\n${theme.fg("toolOutput", safeTranscriptText(args.script, DISPLAY_INPUT_LIMIT))}`, 0, 0);
613
+ let source = safeTranscriptText(args.script, DISPLAY_INPUT_LIMIT);
614
+ // Never format an incomplete stream or change the script used for execution.
615
+ if (argsComplete) {
616
+ if (formattedSource?.input !== source) {
617
+ let output = source;
618
+ try {
619
+ output = beautify.js(source, { indent_size: 2, preserve_newlines: true, wrap_line_length: 100 });
620
+ } catch {
621
+ // A malformed or truncated display source can still be shown verbatim.
622
+ }
623
+ formattedSource = { input: source, output: safeTranscriptText(output, DISPLAY_INPUT_LIMIT) };
624
+ }
625
+ source = formattedSource.output;
626
+ }
627
+ const call = new Container();
628
+ call.addChild(new Text(title, 0, 0));
629
+ call.addChild(new Spacer(1));
630
+ call.addChild(workflowSection("Script · JavaScript", highlightCode(source, "javascript").join("\n"), theme, "toolPendingBg"));
631
+ return call;
611
632
  }
612
633
  const source = args.scriptPath || args.name;
613
634
  return new Text(source ? `${title} ${theme.fg("muted", safeDisplayText(source, 240))}` : title, 0, 0);
614
635
  },
615
- renderResult(result, { isPartial, expanded }, theme) {
636
+ renderResult(result, { isPartial, expanded }, theme, context) {
616
637
  const snapshot = result.details as WorkflowSnapshot | undefined;
638
+ const output = new Container();
639
+ output.addChild(new Spacer(1));
640
+ // Pi owns the pending/success/error background of the surrounding tool by
641
+ // default. With self framing, keep these states on the result panel only.
642
+ const background = isPartial ? "toolPendingBg"
643
+ : context.isError || snapshot?.status === "failed" || snapshot?.status === "aborted" ? "toolErrorBg" : "toolSuccessBg";
617
644
  if (snapshot?.name) {
618
- return new Text(renderWorkflowText(snapshot, {
645
+ output.addChild(workflowSection("Status", renderWorkflowText(snapshot, {
619
646
  maxAgentRows: expanded ? Number.MAX_SAFE_INTEGER : undefined,
620
647
  maxLogs: expanded ? 12 : undefined,
621
648
  showResultPreviews: expanded && !isPartial,
622
- }), 0, 0);
649
+ }), theme, background));
650
+ } else {
651
+ const text = result.content?.[0];
652
+ output.addChild(workflowSection("Result", text?.type === "text" ? text.text : "workflow", theme, background));
623
653
  }
624
- const text = result.content?.[0];
625
- return new Text(text?.type === "text" ? text.text : theme.fg("muted", "workflow"), 0, 0);
654
+ return output;
626
655
  },
627
656
  });
628
657
  }
629
658
 
659
+ function workflowSection(
660
+ heading: string,
661
+ content: string,
662
+ theme: Theme,
663
+ background: "toolPendingBg" | "toolSuccessBg" | "toolErrorBg",
664
+ ): Box {
665
+ const panel = new Box(1, 1, (text) => theme.bg(background, text));
666
+ panel.addChild(new Text(theme.fg("toolTitle", theme.bold(heading)), 0, 0));
667
+ panel.addChild(new Spacer(1));
668
+ panel.addChild(new Text(content, 0, 0));
669
+ return panel;
670
+ }
671
+
630
672
  function resolveScript(
631
673
  params: { script?: string; scriptPath?: string; name?: string },
632
674
  cwd: string,