pi-ultracode 0.10.2 → 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.2",
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, highlightCode, 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,33 +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
- const source = safeTranscriptText(args.script, DISPLAY_INPUT_LIMIT);
611
- const heading = theme.fg("muted", "Script · JavaScript");
612
- return new Text(`${title}\n\n${heading}\n${highlightCode(source, "javascript").join("\n")}`, 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;
613
632
  }
614
633
  const source = args.scriptPath || args.name;
615
634
  return new Text(source ? `${title} ${theme.fg("muted", safeDisplayText(source, 240))}` : title, 0, 0);
616
635
  },
617
- renderResult(result, { isPartial, expanded }, theme) {
636
+ renderResult(result, { isPartial, expanded }, theme, context) {
618
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";
619
644
  if (snapshot?.name) {
620
- return new Text(`\n${theme.fg("toolTitle", theme.bold("Status"))}\n${renderWorkflowText(snapshot, {
645
+ output.addChild(workflowSection("Status", renderWorkflowText(snapshot, {
621
646
  maxAgentRows: expanded ? Number.MAX_SAFE_INTEGER : undefined,
622
647
  maxLogs: expanded ? 12 : undefined,
623
648
  showResultPreviews: expanded && !isPartial,
624
- })}`, 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));
625
653
  }
626
- const text = result.content?.[0];
627
- const heading = theme.fg("toolTitle", theme.bold("Result"));
628
- return new Text(`\n${heading}\n${text?.type === "text" ? text.text : theme.fg("muted", "workflow")}`, 0, 0);
654
+ return output;
629
655
  },
630
656
  });
631
657
  }
632
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
+
633
672
  function resolveScript(
634
673
  params: { script?: string; scriptPath?: string; name?: string },
635
674
  cwd: string,