pi-cc-extensions 0.8.19 → 0.8.21
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,5 +1,4 @@
|
|
|
1
1
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { bottomDialogBounds, isDialogCloseClick } from "../../closable-dialog.ts";
|
|
3
2
|
import { getKeybindings, type Input } from "@earendil-works/pi-tui";
|
|
4
3
|
import type { QuestionData, QuestionnaireResult, QuestionParams } from "../tool/types.js";
|
|
5
4
|
import type { WrappingSelectItem } from "../view/components/wrapping-select.js";
|
|
@@ -94,26 +93,10 @@ export class QuestionnaireSession {
|
|
|
94
93
|
// so the transcript regains space while Ctrl+] can still expand the questionnaire.
|
|
95
94
|
const collapsedRender = (_width: number): string[] => [theme.fg("dim", ` ${COLLAPSED_HINT} `)];
|
|
96
95
|
|
|
97
|
-
let lastWidth = 0;
|
|
98
|
-
let lastHeight = 0;
|
|
99
96
|
this.component = {
|
|
100
|
-
render: (width) =>
|
|
101
|
-
const lines = this.state.collapsed ? collapsedRender(width) : built.render(width);
|
|
102
|
-
lastWidth = width;
|
|
103
|
-
lastHeight = lines.length;
|
|
104
|
-
return lines;
|
|
105
|
-
},
|
|
97
|
+
render: (width) => (this.state.collapsed ? collapsedRender(width) : built.render(width)),
|
|
106
98
|
invalidate: built.invalidate,
|
|
107
|
-
handleInput: (data) =>
|
|
108
|
-
if (
|
|
109
|
-
!this.state.collapsed &&
|
|
110
|
-
isDialogCloseClick(data, bottomDialogBounds(this.tui.terminal, lastWidth, lastHeight))
|
|
111
|
-
) {
|
|
112
|
-
this.dispatch("\x1b");
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
this.dispatch(data);
|
|
116
|
-
},
|
|
99
|
+
handleInput: (data) => this.dispatch(data),
|
|
117
100
|
};
|
|
118
101
|
|
|
119
102
|
this.viewAdapter.apply(this.state);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DynamicBorder, type Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { renderDialogHeader, renderDialogTopBorder } from "../../closable-dialog.ts";
|
|
3
2
|
import { type Component, Container, type Input, Spacer } from "@earendil-works/pi-tui";
|
|
4
3
|
import type { QuestionnaireState } from "../state/state.js";
|
|
5
4
|
import type { QuestionData } from "../tool/types.js";
|
|
@@ -134,24 +133,10 @@ export class DialogView implements StatefulView<DialogProps> {
|
|
|
134
133
|
// Render only the active tab's natural content; blank height equalization would
|
|
135
134
|
// unnecessarily consume transcript rows above this full-width editor component.
|
|
136
135
|
const natural = this.buildContainerFromStrategy(strategy, headingRowCache).render(width);
|
|
137
|
-
if (natural.length > 0) {
|
|
138
|
-
natural[0] = renderDialogTopBorder(width, (text) => this.config.theme.fg("accent", text));
|
|
139
|
-
natural.splice(
|
|
140
|
-
1,
|
|
141
|
-
0,
|
|
142
|
-
renderDialogHeader(
|
|
143
|
-
" Questions",
|
|
144
|
-
width,
|
|
145
|
-
(text) => this.config.theme.fg("accent", text),
|
|
146
|
-
(text) => this.config.theme.fg("toolTitle", text),
|
|
147
|
-
(text) => this.config.theme.fg("muted", text),
|
|
148
|
-
),
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
136
|
|
|
152
137
|
// Fixed region sizes (deterministic from structure).
|
|
153
138
|
// TabBar.render() returns [tabLine, ""] — always 2 rows.
|
|
154
|
-
const topFixed =
|
|
139
|
+
const topFixed = 1 + (this.config.isMulti && this.config.tabBar ? 2 : 0) + 1;
|
|
155
140
|
const bottomFixed = 1 + strategy.footerRowCount;
|
|
156
141
|
const middleRows = natural.length - topFixed - bottomFixed;
|
|
157
142
|
|
|
@@ -793,8 +793,8 @@ type ToolRenderHit = {
|
|
|
793
793
|
};
|
|
794
794
|
|
|
795
795
|
const TOOL_MOUSE_WIDGET_KEY = "ccstyle-tool-mouse";
|
|
796
|
-
const TOOL_MOUSE_ENABLE = "\x1b[?1000h\x1b[?1006h";
|
|
797
|
-
const TOOL_MOUSE_DISABLE = "\x1b[?1006l\x1b[?1000l";
|
|
796
|
+
const TOOL_MOUSE_ENABLE = "\x1b[?1000h\x1b[?1003h\x1b[?1006h";
|
|
797
|
+
const TOOL_MOUSE_DISABLE = "\x1b[?1006l\x1b[?1003l\x1b[?1000l";
|
|
798
798
|
const ZENTUI_PAGE_UP_INPUT = /^\x1b\[5;9(?::[12])?~$|^\x1b\[57421;9(?::[12])?u$|^\x1b\[1;6A$/;
|
|
799
799
|
const ZENTUI_PAGE_DOWN_INPUT = /^\x1b\[6;9(?::[12])?~$|^\x1b\[57422;9(?::[12])?u$|^\x1b\[1;6B$/;
|
|
800
800
|
const SCROLL_BOTTOM_SHORTCUT = "ctrl+end";
|
|
@@ -816,6 +816,7 @@ let pendingScrollMessages = 0;
|
|
|
816
816
|
let assistantMessageActive = false;
|
|
817
817
|
let scrollButtonSyncScheduled = false;
|
|
818
818
|
let sessionRenderTimer: ReturnType<typeof setTimeout> | null = null;
|
|
819
|
+
let hoveredToolCallId: string | null = null;
|
|
819
820
|
|
|
820
821
|
function parseSgrMousePackets(data: string): SgrMousePacket[] | null {
|
|
821
822
|
const pattern = /\x1b\[<(\d+);(\d+);(\d+)([Mm])/g;
|
|
@@ -938,8 +939,8 @@ function fixedEditorContextScore(
|
|
|
938
939
|
return score;
|
|
939
940
|
}
|
|
940
941
|
|
|
941
|
-
/**
|
|
942
|
-
const
|
|
942
|
+
/** Summary markers used by Pi and ccstyle; unlike the trailing hint, these survive truncation. */
|
|
943
|
+
const COLLAPSED_TOOL_SUMMARY = /^\s*(?:↳|└|⎿)/;
|
|
943
944
|
/** fixedEditorContextScore max ≈ 100 + 2*(5+4+3+2); stop once we hit a near-perfect match. */
|
|
944
945
|
const TOOL_CLICK_EARLY_EXIT_SCORE = 120;
|
|
945
946
|
|
|
@@ -956,12 +957,11 @@ function findToolAtFixedEditorRow(
|
|
|
956
957
|
|
|
957
958
|
const tools: any[] = [];
|
|
958
959
|
collectToolComponents(tui, tools);
|
|
959
|
-
|
|
960
|
-
// Skips re-rendering the opposite half of the transcript tools.
|
|
961
|
-
const wantExpanded = !COLLAPSED_TOOL_CLICK_HINT.test(clickedLine);
|
|
960
|
+
const clickedCollapsedSummary = COLLAPSED_TOOL_SUMMARY.test(clickedLine);
|
|
962
961
|
let best: { hit: ToolRenderHit; score: number } | null = null;
|
|
963
962
|
for (const component of tools) {
|
|
964
|
-
|
|
963
|
+
// Collapsed tools open only from their summary row; expanded tools collapse from any body row.
|
|
964
|
+
if (!component.expanded && !clickedCollapsedSummary) continue;
|
|
965
965
|
const renderedLines = renderComponentTree(component, width).map((line) =>
|
|
966
966
|
stripTerminalSequences(String(line)),
|
|
967
967
|
);
|
|
@@ -998,12 +998,11 @@ function findToolAtScreenRow(tui: any, screenRow: number): ToolRenderHit | null
|
|
|
998
998
|
collectToolRenderHits(tui, 0, width, hits, cache, new Set<object>());
|
|
999
999
|
|
|
1000
1000
|
const clickedLine = stripTerminalSequences(String(previousLines[bufferRow] ?? ""));
|
|
1001
|
-
const wantExpanded = !COLLAPSED_TOOL_CLICK_HINT.test(clickedLine);
|
|
1002
1001
|
for (const hit of hits) {
|
|
1003
1002
|
if (bufferRow < hit.start || bufferRow >= hit.end) continue;
|
|
1004
|
-
//
|
|
1005
|
-
//
|
|
1006
|
-
if (
|
|
1003
|
+
// The stable summary marker keeps the whole row clickable even when the
|
|
1004
|
+
// trailing keyboard/click hint was truncated (common for subagent output).
|
|
1005
|
+
if (!hit.component.expanded && !COLLAPSED_TOOL_SUMMARY.test(clickedLine)) continue;
|
|
1007
1006
|
return hit;
|
|
1008
1007
|
}
|
|
1009
1008
|
return null;
|
|
@@ -1445,6 +1444,15 @@ function tryOpenToolIoShowMore(tui: any, packet: SgrMousePacket, hit: ToolRender
|
|
|
1445
1444
|
return true;
|
|
1446
1445
|
}
|
|
1447
1446
|
|
|
1447
|
+
function updateToolSummaryHover(tui: any, packet: SgrMousePacket): void {
|
|
1448
|
+
if ((packet.code & 32) === 0 || packet.final !== "M") return;
|
|
1449
|
+
const hit = findToolAtScreenRow(tui, packet.row);
|
|
1450
|
+
const nextToolCallId = hit && !hit.component.expanded ? hit.component.toolCallId : null;
|
|
1451
|
+
if (nextToolCallId === hoveredToolCallId) return;
|
|
1452
|
+
hoveredToolCallId = nextToolCallId;
|
|
1453
|
+
tui.requestRender?.();
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1448
1456
|
function toggleToolAtMouseClick(tui: any, packet: SgrMousePacket): boolean {
|
|
1449
1457
|
const hit = findToolAtScreenRow(tui, packet.row);
|
|
1450
1458
|
if (!hit) return false;
|
|
@@ -1504,6 +1512,9 @@ function patchToolMouseInputCapture(tui: any): void {
|
|
|
1504
1512
|
const packets = parseSgrMousePackets(data);
|
|
1505
1513
|
if (packets) {
|
|
1506
1514
|
for (const packet of packets) {
|
|
1515
|
+
// Fixed-editor owners may consume motion before extension listeners run,
|
|
1516
|
+
// so hover must be handled at the root input boundary too.
|
|
1517
|
+
updateToolSummaryHover(this, packet);
|
|
1507
1518
|
if (!isSgrLeftPress(packet)) continue;
|
|
1508
1519
|
if (handleScrollButtonClick(this, packet) || toggleToolAtMouseClick(this, packet)) return;
|
|
1509
1520
|
}
|
|
@@ -1567,6 +1578,7 @@ function handleToolMouseInput(data: string): { consume: true } | undefined {
|
|
|
1567
1578
|
|
|
1568
1579
|
let consumed = false;
|
|
1569
1580
|
for (const packet of packets) {
|
|
1581
|
+
updateToolSummaryHover(toolMouseTui, packet);
|
|
1570
1582
|
if (!isSgrLeftPress(packet)) continue;
|
|
1571
1583
|
if (
|
|
1572
1584
|
handleScrollButtonClick(toolMouseTui, packet) ||
|
|
@@ -1589,6 +1601,7 @@ function teardownToolMouseInteraction(): void {
|
|
|
1589
1601
|
}
|
|
1590
1602
|
toolMouseInputUnsubscribe?.();
|
|
1591
1603
|
toolMouseInputUnsubscribe = null;
|
|
1604
|
+
hoveredToolCallId = null;
|
|
1592
1605
|
try {
|
|
1593
1606
|
toolMouseTui?.terminal?.write?.(TOOL_MOUSE_DISABLE);
|
|
1594
1607
|
} catch {
|
|
@@ -1626,10 +1639,9 @@ export function installToolMouseInteraction(
|
|
|
1626
1639
|
toolMouseFixedFeaturesEnabled = fixedEditorFeatures;
|
|
1627
1640
|
ctx.ui.setWidget(TOOL_MOUSE_WIDGET_KEY, (tui: any, theme: any) => {
|
|
1628
1641
|
toolMouseTui = tui;
|
|
1629
|
-
if (fixedEditorFeatures)
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
}
|
|
1642
|
+
if (fixedEditorFeatures) patchToolMouseInputCapture(tui);
|
|
1643
|
+
// Motion reporting is required for hover in both native and fixed-editor layouts.
|
|
1644
|
+
tui?.terminal?.write?.(fixedEditorFeatures ? TOOL_MOUSE_ENABLE : "\x1b[?1003h\x1b[?1006h");
|
|
1633
1645
|
const widget = {
|
|
1634
1646
|
render: (width: number) => renderScrollButton(width, theme),
|
|
1635
1647
|
invalidate() {},
|
|
@@ -2220,9 +2232,22 @@ function createCcstyleTool(
|
|
|
2220
2232
|
);
|
|
2221
2233
|
}
|
|
2222
2234
|
if (context?.state) context.state.ccstyleIoView = undefined;
|
|
2223
|
-
|
|
2224
|
-
|
|
2235
|
+
const toolCallId = context?.toolCallId;
|
|
2236
|
+
const summary = theme.fg(
|
|
2237
|
+
isError ? "error" : "muted",
|
|
2238
|
+
renderCollapsedToolResult(rendered, hint),
|
|
2225
2239
|
);
|
|
2240
|
+
return {
|
|
2241
|
+
render(width: number) {
|
|
2242
|
+
const line = truncateToWidth(summary, width, "…");
|
|
2243
|
+
if (!toolCallId || hoveredToolCallId !== toolCallId) return [line];
|
|
2244
|
+
const highlighted = line.replace(/\x1b\[0m/g, "\x1b[0;7m");
|
|
2245
|
+
return [
|
|
2246
|
+
`\x1b[7m${highlighted}${" ".repeat(Math.max(0, width - visibleWidth(line)))}\x1b[0m`,
|
|
2247
|
+
];
|
|
2248
|
+
},
|
|
2249
|
+
invalidate() {},
|
|
2250
|
+
};
|
|
2226
2251
|
},
|
|
2227
2252
|
};
|
|
2228
2253
|
}
|
package/package.json
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-cc-extensions",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "A Pi productivity suite with Claude Code-style UI, structured questionnaires, context inspection, and agent/session references",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"pi-package",
|
|
8
|
-
"pi-extension",
|
|
9
|
-
"pi-coding-agent",
|
|
10
|
-
"claude-code",
|
|
11
|
-
"questionnaire"
|
|
12
|
-
],
|
|
13
|
-
"homepage": "https://github.com/minuque/pi-cc-extensions#readme",
|
|
14
|
-
"repository": {
|
|
15
|
-
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/minuque/pi-cc-extensions.git"
|
|
17
|
-
},
|
|
18
|
-
"bugs": {
|
|
19
|
-
"url": "https://github.com/minuque/pi-cc-extensions/issues"
|
|
20
|
-
},
|
|
21
|
-
"files": [
|
|
22
|
-
"extensions",
|
|
23
|
-
"assets/readme",
|
|
24
|
-
"themes",
|
|
25
|
-
"README.md",
|
|
26
|
-
"README.en.md"
|
|
27
|
-
],
|
|
28
|
-
"pi": {
|
|
29
|
-
"extensions": [
|
|
30
|
-
"./extensions/pi-aliases.ts",
|
|
31
|
-
"./extensions/pi-startup-header.ts",
|
|
32
|
-
"./extensions/claude-code-style.ts",
|
|
33
|
-
"./extensions/context.ts",
|
|
34
|
-
"./extensions/session-reference.ts",
|
|
35
|
-
"./extensions/agent-autocomplete.ts",
|
|
36
|
-
"./extensions/ask-user-question/index.ts"
|
|
37
|
-
],
|
|
38
|
-
"themes": [
|
|
39
|
-
"./themes/github-dark-default.json"
|
|
40
|
-
],
|
|
41
|
-
"image": "https://raw.githubusercontent.com/minuque/pi-cc-extensions/main/assets/readme/welcome.webp"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"test": "node --test tests/**/*.test.ts",
|
|
45
|
-
"typecheck": "node scripts/typecheck.mjs",
|
|
46
|
-
"format": "biome format --write .",
|
|
47
|
-
"format:check": "biome format .",
|
|
48
|
-
"preversion": "npm run format:check && npm run typecheck && npm test",
|
|
49
|
-
"release": "npm version patch && npm publish",
|
|
50
|
-
"release:minor": "npm version minor && npm publish",
|
|
51
|
-
"release:major": "npm version major && npm publish"
|
|
52
|
-
},
|
|
53
|
-
"dependencies": {
|
|
54
|
-
"@juicesharp/rpiv-config": "^2.1.0",
|
|
55
|
-
"typebox": "^1.1.24"
|
|
56
|
-
},
|
|
57
|
-
"peerDependencies": {
|
|
58
|
-
"@earendil-works/pi-ai": "*",
|
|
59
|
-
"@earendil-works/pi-coding-agent": "*",
|
|
60
|
-
"@earendil-works/pi-tui": "*"
|
|
61
|
-
},
|
|
62
|
-
"engines": {
|
|
63
|
-
"node": ">=22.19.0"
|
|
64
|
-
},
|
|
65
|
-
"devDependencies": {
|
|
66
|
-
"@biomejs/biome": "2.5.5",
|
|
67
|
-
"@types/node": "^26.1.1"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-cc-extensions",
|
|
3
|
+
"version": "0.8.21",
|
|
4
|
+
"description": "A Pi productivity suite with Claude Code-style UI, structured questionnaires, context inspection, and agent/session references",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"pi-package",
|
|
8
|
+
"pi-extension",
|
|
9
|
+
"pi-coding-agent",
|
|
10
|
+
"claude-code",
|
|
11
|
+
"questionnaire"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/minuque/pi-cc-extensions#readme",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/minuque/pi-cc-extensions.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/minuque/pi-cc-extensions/issues"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"extensions",
|
|
23
|
+
"assets/readme",
|
|
24
|
+
"themes",
|
|
25
|
+
"README.md",
|
|
26
|
+
"README.en.md"
|
|
27
|
+
],
|
|
28
|
+
"pi": {
|
|
29
|
+
"extensions": [
|
|
30
|
+
"./extensions/pi-aliases.ts",
|
|
31
|
+
"./extensions/pi-startup-header.ts",
|
|
32
|
+
"./extensions/claude-code-style.ts",
|
|
33
|
+
"./extensions/context.ts",
|
|
34
|
+
"./extensions/session-reference.ts",
|
|
35
|
+
"./extensions/agent-autocomplete.ts",
|
|
36
|
+
"./extensions/ask-user-question/index.ts"
|
|
37
|
+
],
|
|
38
|
+
"themes": [
|
|
39
|
+
"./themes/github-dark-default.json"
|
|
40
|
+
],
|
|
41
|
+
"image": "https://raw.githubusercontent.com/minuque/pi-cc-extensions/main/assets/readme/welcome.webp"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "node --test tests/**/*.test.ts",
|
|
45
|
+
"typecheck": "node scripts/typecheck.mjs",
|
|
46
|
+
"format": "biome format --write .",
|
|
47
|
+
"format:check": "biome format .",
|
|
48
|
+
"preversion": "npm run format:check && npm run typecheck && npm test",
|
|
49
|
+
"release": "npm version patch && npm publish",
|
|
50
|
+
"release:minor": "npm version minor && npm publish",
|
|
51
|
+
"release:major": "npm version major && npm publish"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@juicesharp/rpiv-config": "^2.1.0",
|
|
55
|
+
"typebox": "^1.1.24"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@earendil-works/pi-ai": "*",
|
|
59
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
60
|
+
"@earendil-works/pi-tui": "*"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=22.19.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@biomejs/biome": "2.5.5",
|
|
67
|
+
"@types/node": "^26.1.1"
|
|
68
|
+
}
|
|
69
|
+
}
|