@danypops/pi-papyrus 0.45.8 → 0.45.9
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,8 +1,21 @@
|
|
|
1
1
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { type Component, truncateToWidth } from "@earendil-works/pi-tui";
|
|
3
|
-
import { buildDetailLines, type DetailField, type DetailSection } from "malevich-tui-components";
|
|
3
|
+
import { buildDetailLines, type DetailField, type DetailSection, type DetailViewTheme } from "malevich-tui-components";
|
|
4
4
|
import type { ArtifactToolDetails } from "./render-model.ts";
|
|
5
5
|
|
|
6
|
+
/** Shared by every buildDetailLines caller in this extension (ArtifactCard, and
|
|
7
|
+
* vehicle-artifact-renderers.ts's discuss/tasks.complete renderers) -- one Theme -> DetailViewTheme
|
|
8
|
+
* mapping instead of the same four-field object literal re-typed at each call site. */
|
|
9
|
+
export function detailViewTheme(theme: Theme): DetailViewTheme {
|
|
10
|
+
return {
|
|
11
|
+
field: (s) => theme.fg("text", s),
|
|
12
|
+
heading: (s) => theme.fg("toolTitle", theme.bold(s)),
|
|
13
|
+
byline: (s) => theme.fg("muted", s),
|
|
14
|
+
body: (s) => theme.fg("text", s),
|
|
15
|
+
line: (s) => theme.fg("warning", s),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
const KIND_GLYPHS: Readonly<Record<string, string>> = {
|
|
7
20
|
task: "◇",
|
|
8
21
|
doc: "▤",
|
|
@@ -100,6 +113,7 @@ export class ArtifactCard implements Component {
|
|
|
100
113
|
const status = this.theme.fg(statusColor(artifact.status), `${statusGlyph(artifact.status)} ${artifact.status}`);
|
|
101
114
|
return [
|
|
102
115
|
{ label: "Title", value: artifact.title },
|
|
116
|
+
{ label: "Alias", value: artifact.alias ?? artifact.id },
|
|
103
117
|
{ label: "Kind", value: `${kindGlyph(artifact.kind)} ${artifact.kind}` },
|
|
104
118
|
{ label: "Status", value: status },
|
|
105
119
|
...(this.expanded ? [{ label: "ID", value: artifact.id }] : []),
|
|
@@ -128,13 +142,7 @@ export class ArtifactCard implements Component {
|
|
|
128
142
|
fields: this.fields(),
|
|
129
143
|
sections: this.sections(),
|
|
130
144
|
alignFields: true,
|
|
131
|
-
theme:
|
|
132
|
-
field: (s) => theme.fg("text", s),
|
|
133
|
-
heading: (s) => theme.fg("toolTitle", theme.bold(s)),
|
|
134
|
-
byline: (s) => theme.fg("muted", s),
|
|
135
|
-
body: (s) => theme.fg("text", s),
|
|
136
|
-
line: (s) => theme.fg("warning", s),
|
|
137
|
-
},
|
|
145
|
+
theme: detailViewTheme(theme),
|
|
138
146
|
});
|
|
139
147
|
|
|
140
148
|
if (this.details.focus) {
|
|
@@ -18,6 +18,8 @@ export interface ResultCompleteness {
|
|
|
18
18
|
|
|
19
19
|
export interface ToolArtifactSummary {
|
|
20
20
|
id: string;
|
|
21
|
+
/** Optional only for a detail object persisted before this field existed -- ArtifactCard falls back to id when absent. */
|
|
22
|
+
alias?: string;
|
|
21
23
|
kind: string;
|
|
22
24
|
title: string;
|
|
23
25
|
status: string;
|
|
@@ -154,6 +156,7 @@ function boundedText(value: string, maximum: number): { value: string; completen
|
|
|
154
156
|
function artifactSummary(artifact: Artifact): ToolArtifactSummary {
|
|
155
157
|
return {
|
|
156
158
|
id: artifact.id,
|
|
159
|
+
alias: artifact.alias,
|
|
157
160
|
kind: artifact.kind,
|
|
158
161
|
title: artifact.title,
|
|
159
162
|
status: artifact.status,
|
|
@@ -20,7 +20,7 @@ import type { VehicleOperationDescriptor } from "@danypops/vehicle-core";
|
|
|
20
20
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
21
21
|
import { type Component, Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
22
22
|
import { buildDetailLines, type DagEdge, type DagNode, DagView, type DetailField, type DetailSection } from "malevich-tui-components";
|
|
23
|
-
import { ArtifactCard, expandHint, statusColor, statusGlyph } from "./tool-rendering/artifact-card.ts";
|
|
23
|
+
import { ArtifactCard, detailViewTheme, expandHint, statusColor, statusGlyph } from "./tool-rendering/artifact-card.ts";
|
|
24
24
|
import { ArtifactListCard } from "./tool-rendering/artifact-list.ts";
|
|
25
25
|
import { type ArtifactFocusAnnotation, createArtifactDetails, createArtifactListDetails } from "./tool-rendering/render-model.ts";
|
|
26
26
|
|
|
@@ -261,13 +261,6 @@ function isDiscussionListOutput(value: unknown): value is DiscussionListOutput {
|
|
|
261
261
|
return isArtifactArray(row.discussions);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
const discussTheme = (theme: Theme) => ({
|
|
265
|
-
field: (s: string) => theme.fg("text", s),
|
|
266
|
-
heading: (s: string) => theme.fg("toolTitle", theme.bold(s)),
|
|
267
|
-
byline: (s: string) => theme.fg("muted", s),
|
|
268
|
-
body: (s: string) => theme.fg("text", s),
|
|
269
|
-
});
|
|
270
|
-
|
|
271
264
|
function roundsSection(rounds: readonly DiscussionRoundOutput[]): DetailSection {
|
|
272
265
|
return {
|
|
273
266
|
heading: `Rounds (${rounds.length}):`,
|
|
@@ -275,35 +268,35 @@ function roundsSection(rounds: readonly DiscussionRoundOutput[]): DetailSection
|
|
|
275
268
|
};
|
|
276
269
|
}
|
|
277
270
|
|
|
271
|
+
/** A one-shot render function with nothing to invalidate -- every buildDetailLines-based
|
|
272
|
+
* renderer in this file (unlike ArtifactCard/DagView) has no cache to clear. */
|
|
273
|
+
function statelessComponent(render: (width: number) => string[]): Component {
|
|
274
|
+
return { render, invalidate: () => {} };
|
|
275
|
+
}
|
|
276
|
+
|
|
278
277
|
function renderDiscussionAndRounds(output: DiscussionAndRoundsOutput, theme: Theme, expanded: boolean): Component {
|
|
279
278
|
const discussion = output.discussion;
|
|
280
|
-
return {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
},
|
|
295
|
-
invalidate: () => {},
|
|
296
|
-
};
|
|
279
|
+
return statelessComponent((width) => {
|
|
280
|
+
const safeWidth = Math.max(1, width);
|
|
281
|
+
const fields: DetailField[] = [
|
|
282
|
+
{ label: "Title", value: discussion.title },
|
|
283
|
+
{ label: "Status", value: theme.fg(statusColor(discussion.status), `${statusGlyph(discussion.status)} ${discussion.status}`) },
|
|
284
|
+
];
|
|
285
|
+
const sections: DetailSection[] = expanded && output.rounds.length > 0 ? [roundsSection(output.rounds)] : [];
|
|
286
|
+
const lines = buildDetailLines(safeWidth, { fields, sections, alignFields: true, theme: detailViewTheme(theme) });
|
|
287
|
+
if (!expanded && output.rounds.length > 0) {
|
|
288
|
+
const count = output.rounds.length;
|
|
289
|
+
lines.push(truncateToWidth(theme.fg("dim", `${count} round${count === 1 ? "" : "s"} · ${expandHint()}`), safeWidth));
|
|
290
|
+
}
|
|
291
|
+
return lines;
|
|
292
|
+
});
|
|
297
293
|
}
|
|
298
294
|
|
|
299
295
|
function renderDiscussionRoundsOnly(output: DiscussionRoundsOnlyOutput, theme: Theme): Component {
|
|
300
|
-
return {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
},
|
|
305
|
-
invalidate: () => {},
|
|
306
|
-
};
|
|
296
|
+
return statelessComponent((width) => {
|
|
297
|
+
const sections: DetailSection[] = output.rounds.length > 0 ? [roundsSection(output.rounds)] : [{ lines: ["No rounds."] }];
|
|
298
|
+
return buildDetailLines(Math.max(1, width), { sections, theme: detailViewTheme(theme) });
|
|
299
|
+
});
|
|
307
300
|
}
|
|
308
301
|
|
|
309
302
|
/** tasks.complete's own TaskCompletion shape -- a completed (or rejected) task plus its own
|
|
@@ -350,45 +343,42 @@ function isTaskCompletion(value: unknown): value is TaskCompletionOutput {
|
|
|
350
343
|
|
|
351
344
|
function renderTaskCompletion(result: TaskCompletionOutput, theme: Theme, expanded: boolean): Component {
|
|
352
345
|
const task = result.artifact;
|
|
353
|
-
return {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
`${entry.accepted ? "✓" : "✗"} ${entry.item}${entry.reason ? ` — ${entry.reason}` : ""}`,
|
|
374
|
-
),
|
|
346
|
+
return statelessComponent((width) => {
|
|
347
|
+
const safeWidth = Math.max(1, width);
|
|
348
|
+
const fields: DetailField[] = [
|
|
349
|
+
{ label: "Title", value: task.title },
|
|
350
|
+
{ label: "Status", value: theme.fg(statusColor(task.status), `${statusGlyph(task.status)} ${task.status}`) },
|
|
351
|
+
];
|
|
352
|
+
const sections: DetailSection[] = [];
|
|
353
|
+
if (result.gates.length > 0) {
|
|
354
|
+
sections.push({
|
|
355
|
+
heading: "Gates:",
|
|
356
|
+
lines: result.gates.map((gate) => theme.fg(gate.passed ? "success" : "error", `${gate.passed ? "✓" : "✗"} ${gate.output}`)),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
if (result.checklist.length > 0) {
|
|
360
|
+
sections.push({
|
|
361
|
+
heading: "Checklist:",
|
|
362
|
+
lines: result.checklist.map((entry) =>
|
|
363
|
+
theme.fg(
|
|
364
|
+
entry.accepted ? "success" : "error",
|
|
365
|
+
`${entry.accepted ? "✓" : "✗"} ${entry.item}${entry.reason ? ` — ${entry.reason}` : ""}`,
|
|
375
366
|
),
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
})
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
};
|
|
367
|
+
),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
if (result.blocked.length > 0) {
|
|
371
|
+
sections.push({
|
|
372
|
+
heading: "Still blocked:",
|
|
373
|
+
lines: result.blocked.map((entry) => theme.fg("warning", `◼ ${entry.artifact.title}`)),
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
const lines = buildDetailLines(safeWidth, { fields, sections, alignFields: true, theme: detailViewTheme(theme) });
|
|
377
|
+
if (result.focused && expanded) {
|
|
378
|
+
lines.push(truncateToWidth(theme.fg("accent", `▶ focus ${result.focused.title}`), safeWidth));
|
|
379
|
+
}
|
|
380
|
+
return lines;
|
|
381
|
+
});
|
|
392
382
|
}
|
|
393
383
|
|
|
394
384
|
export function papyrusVehicleRenderers(descriptor: VehicleOperationDescriptor): VehicleToolRenderers {
|
package/package.json
CHANGED