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 +4 -2
- package/src/workflow/tool.ts +52 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ultracode",
|
|
3
|
-
"version": "0.10.
|
|
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"
|
package/src/workflow/tool.ts
CHANGED
|
@@ -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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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
|
-
|
|
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
|
-
})
|
|
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
|
-
|
|
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,
|