@danypops/pi-papyrus 0.60.0 → 0.60.1
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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
1
2
|
import { TOOL_DETAILS_BODY_MAX_CHARACTERS } from "@danypops/papyrus";
|
|
2
3
|
import { boundedText, PAPYRUS_TOOL_DETAILS_SCHEMA, type ResultCompleteness, type ToolDetailsBase } from "./shared.ts";
|
|
3
4
|
|
|
@@ -8,8 +9,15 @@ export interface SemanticTextToolDetails extends ToolDetailsBase {
|
|
|
8
9
|
completeness: ResultCompleteness;
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
/** Preserves diagnostic text while removing terminal commands and normalizing line breaks and tabs. */
|
|
13
|
+
export function plainTerminalText(text: string): string {
|
|
14
|
+
return stripVTControlCharacters(text)
|
|
15
|
+
.replace(/\r\n?/g, "\n")
|
|
16
|
+
.replace(/\p{Cc}/gu, (character) => (character === "\n" ? "\n" : character === "\t" ? " " : ""));
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
export function createSemanticTextDetails(operation: string, text: string): SemanticTextToolDetails {
|
|
12
|
-
const bounded = boundedText(text, TOOL_DETAILS_BODY_MAX_CHARACTERS);
|
|
20
|
+
const bounded = boundedText(plainTerminalText(text), TOOL_DETAILS_BODY_MAX_CHARACTERS);
|
|
13
21
|
return {
|
|
14
22
|
schemaVersion: PAPYRUS_TOOL_DETAILS_SCHEMA,
|
|
15
23
|
kind: "semantic-text",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { TOOL_COLLAPSED_ROW_LIMIT } from "@danypops/papyrus";
|
|
2
|
+
import { expandHint } from "@danypops/vehicle-client-pi/expand-hint";
|
|
3
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { type Component, Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
5
|
+
import { createSemanticTextDetails, type SemanticTextToolDetails } from "./render-model/semantic-text.ts";
|
|
6
|
+
|
|
7
|
+
const MAX_EXPANDED_TEXT_ROWS = 200;
|
|
8
|
+
|
|
9
|
+
/** Renders diagnostic text with host-owned styles and bounded collapsed or expanded rows. */
|
|
10
|
+
export class SemanticTextCard implements Component {
|
|
11
|
+
private readonly details: SemanticTextToolDetails;
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
details: SemanticTextToolDetails,
|
|
15
|
+
private readonly theme: Theme,
|
|
16
|
+
private readonly expanded: boolean,
|
|
17
|
+
) {
|
|
18
|
+
const normalized = createSemanticTextDetails(details.operation, details.text);
|
|
19
|
+
this.details = { ...normalized, completeness: details.completeness.truncated ? details.completeness : normalized.completeness };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
render(width: number): string[] {
|
|
23
|
+
if (width < 1) return [];
|
|
24
|
+
const lines = new Text(this.details.text, 0, 0).render(width);
|
|
25
|
+
const limit = this.expanded ? MAX_EXPANDED_TEXT_ROWS : TOOL_COLLAPSED_ROW_LIMIT;
|
|
26
|
+
const visible = lines.slice(0, limit).map((line) => truncateToWidth(this.theme.fg("toolOutput", line), width));
|
|
27
|
+
const omitted = lines.length - visible.length;
|
|
28
|
+
if (omitted > 0) {
|
|
29
|
+
const hint = this.expanded ? `${omitted} more lines omitted · display limit` : `${omitted} more lines · ${expandHint()}`;
|
|
30
|
+
visible.push(truncateToWidth(this.theme.fg("dim", hint), width));
|
|
31
|
+
} else if (this.details.completeness.truncated) {
|
|
32
|
+
visible.push(truncateToWidth(this.theme.fg("dim", "Output truncated"), width));
|
|
33
|
+
}
|
|
34
|
+
return visible;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
invalidate(): void {}
|
|
38
|
+
}
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
type PapyrusToolDetails,
|
|
41
41
|
parsePapyrusToolDetails,
|
|
42
42
|
} from "../../tool-rendering/render-model.ts";
|
|
43
|
+
import { SemanticTextCard } from "../../tool-rendering/semantic-text.ts";
|
|
43
44
|
import { recordRenderDiagnostic, shapeFingerprint } from "../render-diagnostics.ts";
|
|
44
45
|
import { batchOutcomeSummary } from "./batch.ts";
|
|
45
46
|
import {
|
|
@@ -134,6 +135,9 @@ export function papyrusVehicleRenderers(descriptor: VehicleOperationDescriptor):
|
|
|
134
135
|
if (isTaskCompletion(output)) {
|
|
135
136
|
return renderTaskCompletion(output, theme, options.expanded);
|
|
136
137
|
}
|
|
138
|
+
if (isSemanticTextOutput(output)) {
|
|
139
|
+
return new SemanticTextCard(createSemanticTextDetails(descriptor.name, semanticText(output)), theme, options.expanded);
|
|
140
|
+
}
|
|
137
141
|
recordRenderDiagnostic({ event: "render-result-fell-through-to-generic", operation: descriptor.name });
|
|
138
142
|
}
|
|
139
143
|
return renderVehicleResult(descriptor, result, options, theme, context);
|
|
@@ -217,7 +221,7 @@ function renderFromPapyrusPresentation(
|
|
|
217
221
|
case "preview":
|
|
218
222
|
return new Text(theme.fg("toolOutput", presentation.content), 0, 0);
|
|
219
223
|
case "semantic-text":
|
|
220
|
-
return new
|
|
224
|
+
return new SemanticTextCard(presentation, theme, expanded);
|
|
221
225
|
case "transition":
|
|
222
226
|
case "graph":
|
|
223
227
|
case "gate-run":
|
package/package.json
CHANGED