@pi-kaush/pi-tool-call-markers 0.3.1 → 0.3.2
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/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/index.ts +109 -15
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Restore Pi 0.85's click-to-expand under the custom collapsed rows. Pi routes
|
|
6
|
+
mouse clicks by per-child rendered line heights, and the grouping render
|
|
7
|
+
bypassed the native render that refreshes that cache, so clicks on anything
|
|
8
|
+
drawn after the first tool call landed nowhere (or one line off after a
|
|
9
|
+
resize). The grouped render now publishes the drawn accounting, and a
|
|
10
|
+
collapsed tool row toggles expansion on left-click like Pi's native result
|
|
11
|
+
region.
|
|
12
|
+
|
|
5
13
|
- Restyle subagent rows: the subagent marker is now `↪` (was `&`), and single
|
|
6
14
|
calls drop the `subagent` tool label — `↪ 🤖 [coder][c3po] Implement the…` —
|
|
7
15
|
with chain/parallel step lines reordered to emoji, profile badge, name badge
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -64,6 +64,8 @@ type ToolExecutionRow = {
|
|
|
64
64
|
imageSpacers?: unknown[];
|
|
65
65
|
getRenderShell?(): "default" | "self";
|
|
66
66
|
getTextOutput?(): string;
|
|
67
|
+
setExpanded?(expanded: boolean): void;
|
|
68
|
+
handleMouse?(event: unknown): unknown;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
type PresentationPatchState = {
|
|
@@ -76,8 +78,10 @@ type PresentationPatchState = {
|
|
|
76
78
|
rowGroups: WeakMap<ToolExecutionRow, ToolExecutionRow[]>;
|
|
77
79
|
originalRender: (width: number) => string[];
|
|
78
80
|
originalUpdateDisplay: () => void;
|
|
81
|
+
originalHandleMouse?: (this: ToolExecutionRow, event: unknown) => unknown;
|
|
79
82
|
patchedRender?: (width: number) => string[];
|
|
80
83
|
patchedUpdateDisplay?: () => void;
|
|
84
|
+
patchedHandleMouse?: (this: ToolExecutionRow, event: unknown) => unknown;
|
|
81
85
|
};
|
|
82
86
|
|
|
83
87
|
type GroupingPatchState = {
|
|
@@ -90,6 +94,10 @@ type GroupingPatchState = {
|
|
|
90
94
|
|
|
91
95
|
type GroupRenderCache = {
|
|
92
96
|
lines: string[];
|
|
97
|
+
// Per-member click-routing accounting for the group block: the first
|
|
98
|
+
// member absorbs the leading blank and the tool-name header, later
|
|
99
|
+
// members carry their own line (plus edit diffs).
|
|
100
|
+
heights: Array<{ component: ToolExecutionRow; height: number }>;
|
|
93
101
|
members: ToolExecutionRow[];
|
|
94
102
|
memberVersions: number[];
|
|
95
103
|
themeSample: string;
|
|
@@ -1278,10 +1286,11 @@ function renderGroupedCallLines(
|
|
|
1278
1286
|
rows: ToolExecutionRow[],
|
|
1279
1287
|
width: number,
|
|
1280
1288
|
theme: ThemeLike,
|
|
1281
|
-
): string[] {
|
|
1282
|
-
const lines: string[] = [];
|
|
1289
|
+
): Array<{ row: ToolExecutionRow; lines: string[] }> {
|
|
1290
|
+
const segments: Array<{ row: ToolExecutionRow; lines: string[] }> = [];
|
|
1283
1291
|
let previousToolName: string | undefined;
|
|
1284
1292
|
for (const row of rows) {
|
|
1293
|
+
const lines: string[] = [];
|
|
1285
1294
|
const toolName = row.toolName ?? "tool";
|
|
1286
1295
|
if (toolName !== previousToolName) {
|
|
1287
1296
|
lines.push(
|
|
@@ -1304,8 +1313,9 @@ function renderGroupedCallLines(
|
|
|
1304
1313
|
);
|
|
1305
1314
|
if (row.toolName === "edit")
|
|
1306
1315
|
lines.push(...renderedEditDiffLines(row, theme));
|
|
1316
|
+
segments.push({ row, lines });
|
|
1307
1317
|
}
|
|
1308
|
-
return
|
|
1318
|
+
return segments;
|
|
1309
1319
|
}
|
|
1310
1320
|
|
|
1311
1321
|
function sameMembers(
|
|
@@ -1331,14 +1341,24 @@ function sameMemberVersions(
|
|
|
1331
1341
|
);
|
|
1332
1342
|
}
|
|
1333
1343
|
|
|
1344
|
+
type GroupBlock = {
|
|
1345
|
+
lines: string[];
|
|
1346
|
+
// Click-routing accounting aligned with `lines`: one entry per drawn row
|
|
1347
|
+
// segment, so mouse events land on the member that owns the line.
|
|
1348
|
+
heights: Array<{ component: ToolExecutionRow; height: number }>;
|
|
1349
|
+
};
|
|
1350
|
+
|
|
1334
1351
|
function renderGroupedToolRows(
|
|
1335
1352
|
row: ToolExecutionRow,
|
|
1336
1353
|
rows: ToolExecutionRow[],
|
|
1337
1354
|
width: number,
|
|
1338
1355
|
state: PresentationPatchState,
|
|
1339
|
-
):
|
|
1356
|
+
): GroupBlock {
|
|
1340
1357
|
const theme = state.theme;
|
|
1341
|
-
if (!theme)
|
|
1358
|
+
if (!theme) {
|
|
1359
|
+
const lines = state.originalRender.call(row, width);
|
|
1360
|
+
return { lines, heights: [{ component: row, height: lines.length }] };
|
|
1361
|
+
}
|
|
1342
1362
|
const themeSample = themeSampleFor(theme);
|
|
1343
1363
|
const cached = state.groupCache.get(row);
|
|
1344
1364
|
const hasLiveMembers = rows.some(isLiveRow);
|
|
@@ -1350,32 +1370,52 @@ function renderGroupedToolRows(
|
|
|
1350
1370
|
sameMembers(cached.members, rows) &&
|
|
1351
1371
|
sameMemberVersions(rows, cached.memberVersions, state)
|
|
1352
1372
|
) {
|
|
1353
|
-
return cached.lines;
|
|
1373
|
+
return { lines: cached.lines, heights: cached.heights };
|
|
1354
1374
|
}
|
|
1355
1375
|
|
|
1356
1376
|
const layout = insetLayout(width);
|
|
1357
|
-
const
|
|
1358
|
-
const lines = [
|
|
1377
|
+
const segments = renderGroupedCallLines(rows, layout.contentWidth, theme);
|
|
1378
|
+
const lines = [
|
|
1379
|
+
"",
|
|
1380
|
+
...insetLines(
|
|
1381
|
+
segments.flatMap((s) => s.lines),
|
|
1382
|
+
width,
|
|
1383
|
+
),
|
|
1384
|
+
];
|
|
1385
|
+
// The leading blank and the first segment (tool-name header + call line)
|
|
1386
|
+
// both belong to the first member; every later member owns its lines.
|
|
1387
|
+
const heights = segments.map((segment, index) => ({
|
|
1388
|
+
component: segment.row,
|
|
1389
|
+
height: index === 0 ? segment.lines.length + 1 : segment.lines.length,
|
|
1390
|
+
}));
|
|
1359
1391
|
if (hasLiveMembers) {
|
|
1360
1392
|
state.groupCache.delete(row);
|
|
1361
1393
|
} else {
|
|
1362
1394
|
state.groupCache.set(row, {
|
|
1363
1395
|
lines,
|
|
1396
|
+
heights,
|
|
1364
1397
|
members: [...rows],
|
|
1365
1398
|
memberVersions: rows.map((member) => state.rowVersions.get(member) ?? 0),
|
|
1366
1399
|
themeSample,
|
|
1367
1400
|
width,
|
|
1368
1401
|
});
|
|
1369
1402
|
}
|
|
1370
|
-
return lines;
|
|
1403
|
+
return { lines, heights };
|
|
1371
1404
|
}
|
|
1372
1405
|
|
|
1406
|
+
type ContainerRender = {
|
|
1407
|
+
lines: string[];
|
|
1408
|
+
// Click-routing accounting aligned with `lines`.
|
|
1409
|
+
heights: Array<{ component: unknown; height: number }>;
|
|
1410
|
+
};
|
|
1411
|
+
|
|
1373
1412
|
function renderContainerWithToolGroups(
|
|
1374
1413
|
children: unknown[],
|
|
1375
1414
|
width: number,
|
|
1376
1415
|
presentation: PresentationPatchState,
|
|
1377
|
-
):
|
|
1416
|
+
): ContainerRender {
|
|
1378
1417
|
const lines: string[] = [];
|
|
1418
|
+
const heights: Array<{ component: unknown; height: number }> = [];
|
|
1379
1419
|
const rendered = new Map<number, string[]>();
|
|
1380
1420
|
const renderAt = (index: number): string[] => {
|
|
1381
1421
|
const cached = rendered.get(index);
|
|
@@ -1391,7 +1431,9 @@ function renderContainerWithToolGroups(
|
|
|
1391
1431
|
!isToolExecutionRow(child) ||
|
|
1392
1432
|
!isGroupableToolRow(child, children, index, renderAt, presentation)
|
|
1393
1433
|
) {
|
|
1394
|
-
|
|
1434
|
+
const drawn = renderAt(index);
|
|
1435
|
+
lines.push(...drawn);
|
|
1436
|
+
heights.push({ component: child, height: drawn.length });
|
|
1395
1437
|
continue;
|
|
1396
1438
|
}
|
|
1397
1439
|
|
|
@@ -1426,7 +1468,9 @@ function renderContainerWithToolGroups(
|
|
|
1426
1468
|
}
|
|
1427
1469
|
|
|
1428
1470
|
if (group.length === 1) {
|
|
1429
|
-
|
|
1471
|
+
const drawn = renderAt(index);
|
|
1472
|
+
lines.push(...drawn);
|
|
1473
|
+
heights.push({ component: child, height: drawn.length });
|
|
1430
1474
|
continue;
|
|
1431
1475
|
}
|
|
1432
1476
|
|
|
@@ -1434,11 +1478,13 @@ function renderContainerWithToolGroups(
|
|
|
1434
1478
|
// Use a live member while any call is pending, then the first member once
|
|
1435
1479
|
// settled. Either way, the grouped row keeps the same number of lines.
|
|
1436
1480
|
const shellRow = group.find(isLiveRow) ?? child;
|
|
1437
|
-
|
|
1481
|
+
const block = renderGroupedToolRows(shellRow, group, width, presentation);
|
|
1482
|
+
lines.push(...block.lines);
|
|
1483
|
+
heights.push(...block.heights);
|
|
1438
1484
|
index = lastMemberIndex;
|
|
1439
1485
|
}
|
|
1440
1486
|
|
|
1441
|
-
return lines;
|
|
1487
|
+
return { lines, heights };
|
|
1442
1488
|
}
|
|
1443
1489
|
|
|
1444
1490
|
// TODO: Replace prototype patching with a public Pi tool/transcript rendering API when available.
|
|
@@ -1483,11 +1529,20 @@ function installGroupingPatch(
|
|
|
1483
1529
|
// inset) decorate children through the shared hooks before grouping
|
|
1484
1530
|
// rewrites the rows; delegation alone cannot reach them from here.
|
|
1485
1531
|
restoreHooks = runChatContainerHooks(this, children, width);
|
|
1486
|
-
|
|
1532
|
+
const drawn = renderContainerWithToolGroups(
|
|
1487
1533
|
children,
|
|
1488
1534
|
width,
|
|
1489
1535
|
state.presentation,
|
|
1490
1536
|
);
|
|
1537
|
+
// The grouping path bypasses the native render that refreshes the
|
|
1538
|
+
// container's mouse-layout cache. Publish the drawn accounting so
|
|
1539
|
+
// click-to-expand (Pi routes by per-child line heights) keeps landing
|
|
1540
|
+
// on the row that actually owns the line, including grouped members.
|
|
1541
|
+
(this as { mouseLayout?: unknown }).mouseLayout = {
|
|
1542
|
+
width,
|
|
1543
|
+
children: drawn.heights,
|
|
1544
|
+
};
|
|
1545
|
+
return drawn.lines;
|
|
1491
1546
|
} catch {
|
|
1492
1547
|
return state.originalRender.call(this, width);
|
|
1493
1548
|
} finally {
|
|
@@ -1574,6 +1629,34 @@ function installPresentationPatch(): PresentationPatchState | undefined {
|
|
|
1574
1629
|
state.collapsedCache.delete(this);
|
|
1575
1630
|
state.originalUpdateDisplay.call(this);
|
|
1576
1631
|
};
|
|
1632
|
+
// Pi 0.85 wraps settled tool results in a click-to-expand MouseRegion.
|
|
1633
|
+
// The custom collapsed row replaces those lines with a single summary, so
|
|
1634
|
+
// the region never receives the click; toggle expansion here instead.
|
|
1635
|
+
let patchedHandleMouse:
|
|
1636
|
+
| ((this: ToolExecutionRow, event: unknown) => unknown)
|
|
1637
|
+
| undefined;
|
|
1638
|
+
if (typeof proto.handleMouse === "function") {
|
|
1639
|
+
state.originalHandleMouse = proto.handleMouse;
|
|
1640
|
+
patchedHandleMouse = function handleMouseWithCollapsedToggle(
|
|
1641
|
+
this: ToolExecutionRow,
|
|
1642
|
+
event: unknown,
|
|
1643
|
+
): unknown {
|
|
1644
|
+
const mouseEvent = event as { type?: unknown; button?: unknown };
|
|
1645
|
+
if (
|
|
1646
|
+
state.theme &&
|
|
1647
|
+
this.expanded === false &&
|
|
1648
|
+
!!this.result &&
|
|
1649
|
+
mouseEvent?.type === "click" &&
|
|
1650
|
+
mouseEvent.button === "left" &&
|
|
1651
|
+
typeof this.setExpanded === "function"
|
|
1652
|
+
) {
|
|
1653
|
+
this.setExpanded(true);
|
|
1654
|
+
return { handled: true };
|
|
1655
|
+
}
|
|
1656
|
+
return state.originalHandleMouse?.call(this, event);
|
|
1657
|
+
};
|
|
1658
|
+
proto.handleMouse = patchedHandleMouse;
|
|
1659
|
+
}
|
|
1577
1660
|
const patchedRender = function renderWithToolPresentation(
|
|
1578
1661
|
this: ToolExecutionRow,
|
|
1579
1662
|
width: number,
|
|
@@ -1680,6 +1763,7 @@ function uninstallPresentationPatch(
|
|
|
1680
1763
|
[PRESENTATION_PATCHED]?: PresentationPatchState;
|
|
1681
1764
|
render?: (width: number) => string[];
|
|
1682
1765
|
updateDisplay?: () => void;
|
|
1766
|
+
handleMouse?: (event: unknown) => unknown;
|
|
1683
1767
|
};
|
|
1684
1768
|
if (
|
|
1685
1769
|
proto[PRESENTATION_PATCHED] !== state ||
|
|
@@ -1690,6 +1774,16 @@ function uninstallPresentationPatch(
|
|
|
1690
1774
|
}
|
|
1691
1775
|
proto.render = state.originalRender;
|
|
1692
1776
|
proto.updateDisplay = state.originalUpdateDisplay;
|
|
1777
|
+
if (
|
|
1778
|
+
state.patchedHandleMouse &&
|
|
1779
|
+
proto.handleMouse === state.patchedHandleMouse
|
|
1780
|
+
) {
|
|
1781
|
+
if (state.originalHandleMouse) {
|
|
1782
|
+
proto.handleMouse = state.originalHandleMouse;
|
|
1783
|
+
} else {
|
|
1784
|
+
delete proto.handleMouse;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1693
1787
|
delete proto[PRESENTATION_PATCHED];
|
|
1694
1788
|
}
|
|
1695
1789
|
|