pi-one-ui 0.3.0 → 0.4.0
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 +31 -1
- package/README.en.md +39 -35
- package/README.md +20 -16
- package/extensions/app/commands/settings-previews.ts +4 -16
- package/extensions/app/config/renderer.ts +7 -6
- package/extensions/app/config/shell.ts +15 -137
- package/extensions/app/overlay/selector-border.ts +5 -5
- package/extensions/app/ownership.ts +1 -1
- package/extensions/app/panel.ts +19 -25
- package/extensions/app/runtime/tui-runtime.ts +31 -56
- package/extensions/features/context-inspector/index.ts +3 -3
- package/extensions/features/session-reference/index.ts +5 -5
- package/extensions/features/subagent-autocomplete.ts +1 -1
- package/extensions/layouts/context/index.ts +9 -12
- package/extensions/layouts/context/renderer/compact-mode.ts +24 -24
- package/extensions/layouts/context/renderer/default-mode.ts +21 -16
- package/extensions/layouts/context/renderer/index.ts +24 -24
- package/extensions/layouts/context/renderer/mouse/hover.ts +6 -6
- package/extensions/layouts/context/renderer/mouse/interaction.ts +35 -35
- package/extensions/layouts/context/renderer/mouse/packets.ts +3 -2
- package/extensions/layouts/context/renderer/mouse/scroll.ts +2 -2
- package/extensions/layouts/context/renderer/tool/diff/diff-component.ts +2 -1
- package/extensions/layouts/context/renderer/tool/diff/diff-edit-render.ts +21 -21
- package/extensions/layouts/context/renderer/tool/diff/diff-header.ts +4 -4
- package/extensions/layouts/context/renderer/tool/diff/diff-highlight.ts +6 -6
- package/extensions/layouts/context/renderer/tool/diff/diff-inline.ts +1 -1
- package/extensions/layouts/context/renderer/tool/diff/diff-layout.ts +18 -18
- package/extensions/layouts/context/renderer/tool/diff/diff-limits.ts +5 -5
- package/extensions/layouts/context/renderer/tool/diff/diff-palette.ts +3 -3
- package/extensions/layouts/context/renderer/tool/diff/diff-presentation.ts +1 -1
- package/extensions/layouts/context/renderer/tool/diff/diff-renderer.ts +2 -1
- package/extensions/layouts/context/renderer/tool/diff/diff-write-render.ts +31 -31
- package/extensions/layouts/context/renderer/tool/diff/index.ts +4 -4
- package/extensions/layouts/context/renderer/tool/diff/line-width-safety.ts +1 -1
- package/extensions/layouts/context/renderer/tool/diff/write-execution.ts +1 -1
- package/extensions/layouts/context/renderer/tool/grouping.ts +12 -12
- package/extensions/layouts/context/renderer/tool/message-display.ts +2 -2
- package/extensions/layouts/context/renderer/tool/result.ts +199 -19
- package/extensions/layouts/context/summary/core.ts +1 -0
- package/extensions/layouts/context/summary/index.ts +3 -3
- package/extensions/layouts/context/thinking/compact-thinking.ts +12 -13
- package/extensions/layouts/editor/controller.ts +3 -57
- package/extensions/layouts/editor/editor-metadata-format.ts +4 -4
- package/extensions/layouts/editor/factory.ts +5 -23
- package/extensions/layouts/editor/index.ts +2 -8
- package/extensions/layouts/editor/minimalist-editor.ts +1 -52
- package/extensions/layouts/editor/ui.ts +23 -255
- package/extensions/layouts/footer/controller.ts +3 -3
- package/extensions/layouts/footer/footer.ts +21 -21
- package/extensions/layouts/footer/index.ts +8 -8
- package/extensions/layouts/header/index.ts +1 -1
- package/extensions/layouts/header/startup-header.ts +3 -2
- package/extensions/layouts/working-line/controller.ts +6 -6
- package/extensions/layouts/working-line/interaction-summary.ts +47 -7
- package/extensions/layouts/working-line/working-line.ts +24 -3
- package/extensions/services/project-refresh.ts +2 -2
- package/extensions/services/session-state.ts +1 -1
- package/extensions/shared/format.ts +2 -2
- package/extensions/shared/icons.ts +0 -4
- package/package.json +9 -12
- package/extensions/features/legacy/working-message.ts +0 -226
- package/extensions/layouts/editor/accent-rail-editor.ts +0 -112
- package/extensions/layouts/editor/accent-rail-layout-patch.ts +0 -530
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import { inspect } from "node:util";
|
|
1
2
|
import {
|
|
2
3
|
Text,
|
|
3
4
|
truncateToWidth,
|
|
4
5
|
visibleWidth,
|
|
5
6
|
wrapTextWithAnsi,
|
|
6
7
|
} from "@earendil-works/pi-tui";
|
|
7
|
-
import { inspect } from "node:util";
|
|
8
8
|
import { config } from "../../../../app/config/renderer.ts";
|
|
9
|
-
import { showMoreHintText } from "./show-more-hint.ts";
|
|
10
9
|
import {
|
|
11
10
|
TOOL_LOADING_INTERVAL_MS,
|
|
12
11
|
toolLoadingIcon,
|
|
13
12
|
} from "../../../../tools/tool-loading-icon.ts";
|
|
14
13
|
import { sanitizeToolResultText } from "../../../../tools/tool-result-sanitize.ts";
|
|
14
|
+
import { showMoreHintText } from "./show-more-hint.ts";
|
|
15
15
|
|
|
16
16
|
const TOOL_VIEWPORT_WIDTH_RATIO = 0.8;
|
|
17
17
|
|
|
@@ -43,21 +43,185 @@ function rawTextFromResult(result: any): string {
|
|
|
43
43
|
: "";
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const MAX_TOOL_DETAILS_DEPTH = 8;
|
|
47
|
+
const MAX_TOOL_DETAILS_ENTRIES = 64;
|
|
48
|
+
const MAX_TOOL_DETAILS_NODES = 512;
|
|
49
|
+
const MAX_TOOL_DETAILS_STRING_LENGTH = 4096;
|
|
50
|
+
const TOOL_DETAILS_TRUNCATED = "[truncated]";
|
|
51
|
+
|
|
52
|
+
type ToolDetailsProjectionState = {
|
|
53
|
+
remainingNodes: number;
|
|
54
|
+
readonly seen: WeakSet<object>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function projectToolDetailsDescriptor(
|
|
58
|
+
descriptor: PropertyDescriptor | undefined,
|
|
59
|
+
state: ToolDetailsProjectionState,
|
|
60
|
+
depth: number,
|
|
61
|
+
): unknown {
|
|
62
|
+
if (!descriptor) return "[empty]";
|
|
63
|
+
if ("value" in descriptor)
|
|
64
|
+
return projectToolDetailsValue(descriptor.value, state, depth);
|
|
65
|
+
if (descriptor.get && descriptor.set) return "[Getter/Setter]";
|
|
66
|
+
if (descriptor.get) return "[Getter]";
|
|
67
|
+
return "[Setter]";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function projectToolDetailsValue(
|
|
71
|
+
value: unknown,
|
|
72
|
+
state: ToolDetailsProjectionState,
|
|
73
|
+
depth = 0,
|
|
74
|
+
): unknown {
|
|
75
|
+
if (typeof value === "string")
|
|
76
|
+
return value.length > MAX_TOOL_DETAILS_STRING_LENGTH
|
|
77
|
+
? `${value.slice(0, MAX_TOOL_DETAILS_STRING_LENGTH)}…`
|
|
78
|
+
: value;
|
|
79
|
+
if (
|
|
80
|
+
value === null ||
|
|
81
|
+
(typeof value !== "object" && typeof value !== "function")
|
|
82
|
+
)
|
|
83
|
+
return value;
|
|
84
|
+
if (typeof value === "function")
|
|
85
|
+
return `[Function${value.name ? `: ${value.name}` : ""}]`;
|
|
86
|
+
if (state.seen.has(value)) return "[Circular]";
|
|
87
|
+
if (state.remainingNodes <= 0) return "[node budget exhausted]";
|
|
88
|
+
if (depth >= MAX_TOOL_DETAILS_DEPTH) return "[depth limit]";
|
|
89
|
+
|
|
90
|
+
state.remainingNodes--;
|
|
91
|
+
state.seen.add(value);
|
|
92
|
+
try {
|
|
93
|
+
if (Array.isArray(value)) {
|
|
94
|
+
const output: unknown[] = [];
|
|
95
|
+
const limit = Math.min(value.length, MAX_TOOL_DETAILS_ENTRIES);
|
|
96
|
+
let index = 0;
|
|
97
|
+
for (; index < limit && state.remainingNodes > 0; index++) {
|
|
98
|
+
output.push(
|
|
99
|
+
projectToolDetailsDescriptor(
|
|
100
|
+
Object.getOwnPropertyDescriptor(value, String(index)),
|
|
101
|
+
state,
|
|
102
|
+
depth + 1,
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (index < value.length)
|
|
107
|
+
output.push(`... ${value.length - index} more items`);
|
|
108
|
+
return output;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (value instanceof Map) {
|
|
112
|
+
const output: unknown[] = [];
|
|
113
|
+
let processed = 0;
|
|
114
|
+
for (const [key, entry] of value) {
|
|
115
|
+
if (processed === MAX_TOOL_DETAILS_ENTRIES || state.remainingNodes <= 0)
|
|
116
|
+
break;
|
|
117
|
+
output.push([
|
|
118
|
+
projectToolDetailsValue(key, state, depth + 1),
|
|
119
|
+
projectToolDetailsValue(entry, state, depth + 1),
|
|
120
|
+
]);
|
|
121
|
+
processed++;
|
|
122
|
+
}
|
|
123
|
+
if (processed < value.size)
|
|
124
|
+
output.push(`... ${value.size - processed} more entries`);
|
|
125
|
+
return { Map: output };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (value instanceof Set) {
|
|
129
|
+
const output: unknown[] = [];
|
|
130
|
+
let processed = 0;
|
|
131
|
+
for (const entry of value) {
|
|
132
|
+
if (processed === MAX_TOOL_DETAILS_ENTRIES || state.remainingNodes <= 0)
|
|
133
|
+
break;
|
|
134
|
+
output.push(projectToolDetailsValue(entry, state, depth + 1));
|
|
135
|
+
processed++;
|
|
136
|
+
}
|
|
137
|
+
if (processed < value.size)
|
|
138
|
+
output.push(`... ${value.size - processed} more entries`);
|
|
139
|
+
return { Set: output };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (ArrayBuffer.isView(value)) {
|
|
143
|
+
const length =
|
|
144
|
+
"length" in value && typeof value.length === "number"
|
|
145
|
+
? value.length
|
|
146
|
+
: 0;
|
|
147
|
+
const output: unknown[] = [];
|
|
148
|
+
const limit = Math.min(length, MAX_TOOL_DETAILS_ENTRIES);
|
|
149
|
+
for (let index = 0; index < limit; index++)
|
|
150
|
+
output.push(Reflect.get(value, index));
|
|
151
|
+
if (limit < length) output.push(`... ${length - limit} more items`);
|
|
152
|
+
return output;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (value instanceof Date || value instanceof RegExp) return value;
|
|
156
|
+
if (value instanceof Error) {
|
|
157
|
+
return {
|
|
158
|
+
name: value.name,
|
|
159
|
+
message: projectToolDetailsValue(value.message, state, depth + 1),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const output: Record<string, unknown> = {};
|
|
164
|
+
let processed = 0;
|
|
165
|
+
for (const key in value) {
|
|
166
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
167
|
+
if (processed === MAX_TOOL_DETAILS_ENTRIES || state.remainingNodes <= 0) {
|
|
168
|
+
Object.defineProperty(output, "... more properties", {
|
|
169
|
+
value: TOOL_DETAILS_TRUNCATED,
|
|
170
|
+
enumerable: true,
|
|
171
|
+
});
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
Object.defineProperty(output, key, {
|
|
175
|
+
value: projectToolDetailsDescriptor(
|
|
176
|
+
Object.getOwnPropertyDescriptor(value, key),
|
|
177
|
+
state,
|
|
178
|
+
depth + 1,
|
|
179
|
+
),
|
|
180
|
+
enumerable: true,
|
|
181
|
+
});
|
|
182
|
+
processed++;
|
|
183
|
+
}
|
|
184
|
+
return output;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
return `[uninspectable: ${error instanceof Error ? error.message : String(error)}]`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
46
190
|
function detailsFromResult(result: any): string {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
191
|
+
const rawDetails = result?.details;
|
|
192
|
+
if (rawDetails === undefined) return "";
|
|
193
|
+
if (typeof rawDetails === "string")
|
|
194
|
+
return sanitizeToolResultText(rawDetails, 16_384);
|
|
195
|
+
const projected = projectToolDetailsValue(rawDetails, {
|
|
196
|
+
remainingNodes: MAX_TOOL_DETAILS_NODES,
|
|
197
|
+
seen: new WeakSet(),
|
|
198
|
+
});
|
|
199
|
+
const details = inspect(projected, {
|
|
200
|
+
depth: MAX_TOOL_DETAILS_DEPTH,
|
|
201
|
+
breakLength: 100,
|
|
202
|
+
compact: false,
|
|
203
|
+
customInspect: false,
|
|
204
|
+
getters: false,
|
|
205
|
+
maxArrayLength: MAX_TOOL_DETAILS_ENTRIES + 1,
|
|
206
|
+
maxStringLength: MAX_TOOL_DETAILS_STRING_LENGTH,
|
|
207
|
+
});
|
|
52
208
|
return sanitizeToolResultText(details, 16_384);
|
|
53
209
|
}
|
|
54
210
|
|
|
55
211
|
export function textFromResult(result: any, expanded = false): string {
|
|
56
|
-
// Compact previews only need
|
|
212
|
+
// Compact previews only need visible text; avoid traversing large custom details.
|
|
57
213
|
const content = sanitizeToolResultText(rawTextFromResult(result), 16_384);
|
|
214
|
+
if (content && !expanded) {
|
|
215
|
+
return content;
|
|
216
|
+
}
|
|
217
|
+
|
|
58
218
|
const details = detailsFromResult(result);
|
|
59
|
-
if (!content)
|
|
60
|
-
|
|
219
|
+
if (!content) {
|
|
220
|
+
return details;
|
|
221
|
+
}
|
|
222
|
+
if (!details || details === content) {
|
|
223
|
+
return content;
|
|
224
|
+
}
|
|
61
225
|
return `${content}\nDetails:\n${details}`;
|
|
62
226
|
}
|
|
63
227
|
|
|
@@ -301,6 +465,14 @@ export class ExpandedToolIoView {
|
|
|
301
465
|
this.flushLeft = flushLeft;
|
|
302
466
|
}
|
|
303
467
|
|
|
468
|
+
setTheme(theme: any): void {
|
|
469
|
+
if (this.theme === theme) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
this.theme = theme;
|
|
473
|
+
this.invalidate();
|
|
474
|
+
}
|
|
475
|
+
|
|
304
476
|
setContent(
|
|
305
477
|
inputBody: string,
|
|
306
478
|
outputBody: string,
|
|
@@ -759,17 +931,12 @@ export function renderExpandedToolResult(
|
|
|
759
931
|
|
|
760
932
|
// Prefer structured Input/Output when we have args or non-empty output.
|
|
761
933
|
if (inputBody.trim() || outputBody.trim()) {
|
|
934
|
+
const cached = context?.state?.ccstyleExpandedIoView;
|
|
762
935
|
let view: ExpandedToolIoView;
|
|
763
936
|
if (isExpandedToolIoView(lastComponent)) {
|
|
764
|
-
lastComponent.setContent(
|
|
765
|
-
inputBody,
|
|
766
|
-
outputBody,
|
|
767
|
-
isError,
|
|
768
|
-
maxLines,
|
|
769
|
-
maxLines,
|
|
770
|
-
flushLeft,
|
|
771
|
-
);
|
|
772
937
|
view = lastComponent;
|
|
938
|
+
} else if (isExpandedToolIoView(cached)) {
|
|
939
|
+
view = cached;
|
|
773
940
|
} else {
|
|
774
941
|
view = new ExpandedToolIoView(
|
|
775
942
|
theme,
|
|
@@ -781,11 +948,23 @@ export function renderExpandedToolResult(
|
|
|
781
948
|
flushLeft,
|
|
782
949
|
);
|
|
783
950
|
}
|
|
951
|
+
view.setTheme(theme);
|
|
952
|
+
view.setContent(
|
|
953
|
+
inputBody,
|
|
954
|
+
outputBody,
|
|
955
|
+
isError,
|
|
956
|
+
maxLines,
|
|
957
|
+
maxLines,
|
|
958
|
+
flushLeft,
|
|
959
|
+
);
|
|
784
960
|
if (context) rememberIoView(context, view);
|
|
785
961
|
return view;
|
|
786
962
|
}
|
|
787
963
|
|
|
788
|
-
if (context?.state)
|
|
964
|
+
if (context?.state) {
|
|
965
|
+
context.state.ccstyleIoView = undefined;
|
|
966
|
+
context.state.ccstyleExpandedIoView = undefined;
|
|
967
|
+
}
|
|
789
968
|
const color = isError ? "error" : "muted";
|
|
790
969
|
return new Text(theme.fg(color, renderCollapsedToolResult("Done")), 0, 0);
|
|
791
970
|
}
|
|
@@ -901,6 +1080,7 @@ function rememberIoView(context: any, view: ExpandedToolIoView): void {
|
|
|
901
1080
|
}
|
|
902
1081
|
if (!context.state || typeof context.state !== "object") context.state = {};
|
|
903
1082
|
context.state.ccstyleIoView = view;
|
|
1083
|
+
context.state.ccstyleExpandedIoView = view;
|
|
904
1084
|
}
|
|
905
1085
|
|
|
906
1086
|
/** hover 状态变更后刷新上一个/下一个视图(context.invalidate 缓存于 ioViewInvalidators)。 */
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
* 引用块文字色取主题 mdQuote(cc 主题下为 muted 灰),内容用 *斜体* 语法。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { Markdown } from "@earendil-works/pi-tui";
|
|
11
|
-
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
12
10
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
12
|
+
import { Markdown } from "@earendil-works/pi-tui";
|
|
13
13
|
import {
|
|
14
|
+
type AgentSummaryData,
|
|
14
15
|
bindAgentSummary,
|
|
15
16
|
summaryMarkdown,
|
|
16
|
-
type AgentSummaryData,
|
|
17
17
|
} from "./core.ts";
|
|
18
18
|
|
|
19
19
|
export const AGENT_SUMMARY_ENTRY_TYPE = "agent-summary";
|
|
@@ -12,31 +12,30 @@ import {
|
|
|
12
12
|
type Theme,
|
|
13
13
|
} from "@earendil-works/pi-coding-agent";
|
|
14
14
|
import {
|
|
15
|
+
Box,
|
|
16
|
+
type Component,
|
|
15
17
|
getKeybindings,
|
|
18
|
+
Markdown,
|
|
19
|
+
Spacer,
|
|
20
|
+
Text,
|
|
16
21
|
truncateToWidth,
|
|
17
22
|
visibleWidth,
|
|
18
23
|
wrapTextWithAnsi,
|
|
19
24
|
} from "@earendil-works/pi-tui";
|
|
20
25
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from "@earendil-works/pi-tui";
|
|
27
|
-
import { isToolTuiFullscreen } from "../renderer/tool/show-more-hint.ts";
|
|
26
|
+
COMPACT_THINKING_OWNER,
|
|
27
|
+
COMPACT_THINKING_PATCH_KEY,
|
|
28
|
+
PROTOTYPE_ORIGINAL_KEY,
|
|
29
|
+
patchRegistry,
|
|
30
|
+
} from "../../../tools/patch-keys.ts";
|
|
28
31
|
import {
|
|
29
32
|
animateCompactThinkingText,
|
|
30
33
|
formatThoughtDuration,
|
|
31
34
|
styleCompactThinkingText,
|
|
32
35
|
} from "../renderer/compact-mode.ts";
|
|
33
36
|
import { refreshMountedContext } from "../renderer/context-refresh.ts";
|
|
34
|
-
import {
|
|
35
|
-
|
|
36
|
-
COMPACT_THINKING_PATCH_KEY,
|
|
37
|
-
patchRegistry,
|
|
38
|
-
PROTOTYPE_ORIGINAL_KEY,
|
|
39
|
-
} from "../../../tools/patch-keys.ts";
|
|
37
|
+
import { isToolTuiFullscreen } from "../renderer/tool/show-more-hint.ts";
|
|
38
|
+
|
|
40
39
|
// 保持导出兼容:渲染函数已并入 renderer/compact-mode.ts,这里 re-export。
|
|
41
40
|
export {
|
|
42
41
|
animateCompactThinkingText,
|
|
@@ -6,17 +6,12 @@ import {
|
|
|
6
6
|
hasUnsupportedComponentStyle,
|
|
7
7
|
type PolishedTuiConfig,
|
|
8
8
|
} from "../../app/config/shell.ts";
|
|
9
|
-
import { SessionLifecycle } from "../../app/runtime/session-lifecycle.ts";
|
|
10
9
|
import type { RenderScheduler } from "../../app/runtime/render-scheduler.ts";
|
|
10
|
+
import type { SessionLifecycle } from "../../app/runtime/session-lifecycle.ts";
|
|
11
11
|
import type { FooterState } from "../footer/index.ts";
|
|
12
12
|
import {
|
|
13
|
-
installHostAccentRailLayoutPatch,
|
|
14
|
-
retainAccentRailLayoutPatchInstallation,
|
|
15
|
-
type AccentRailLayoutPatchDiagnostic,
|
|
16
|
-
} from "./accent-rail-layout-patch.ts";
|
|
17
|
-
import {
|
|
18
|
-
replaceEditorComponentWithExpandedText,
|
|
19
13
|
type EditorTransferFailureReason,
|
|
14
|
+
replaceEditorComponentWithExpandedText,
|
|
20
15
|
} from "./editor-transfer.ts";
|
|
21
16
|
import {
|
|
22
17
|
createEditorFactory,
|
|
@@ -24,10 +19,10 @@ import {
|
|
|
24
19
|
type EditorFactoryRuntime,
|
|
25
20
|
} from "./factory.ts";
|
|
26
21
|
import {
|
|
22
|
+
type EditorFactory,
|
|
27
23
|
getZentuiEditorBaseFactory,
|
|
28
24
|
isOwnedEditorFactory,
|
|
29
25
|
isZentuiEditorFactory,
|
|
30
|
-
type EditorFactory,
|
|
31
26
|
} from "./ownership.ts";
|
|
32
27
|
|
|
33
28
|
export type EditorChangeResult = { ok: true } | { ok: false; reason: string };
|
|
@@ -41,8 +36,6 @@ export type EditorLayoutControllerContext = {
|
|
|
41
36
|
readonly sessionLifecycle: SessionLifecycle;
|
|
42
37
|
readonly render: Pick<RenderScheduler, "request">;
|
|
43
38
|
readonly getThinkingLevel: () => ReturnType<ExtensionAPI["getThinkingLevel"]>;
|
|
44
|
-
readonly getContextWindow: (ctx: ExtensionContext) => number | undefined;
|
|
45
|
-
readonly getContextPercent: (ctx: ExtensionContext) => number | undefined;
|
|
46
39
|
readonly getAgentDurationMs: () => number;
|
|
47
40
|
readonly isAgentActive: () => boolean;
|
|
48
41
|
readonly isAgentDurationActive: () => boolean;
|
|
@@ -50,10 +43,6 @@ export type EditorLayoutControllerContext = {
|
|
|
50
43
|
readonly getProjectRoot: () => string | undefined;
|
|
51
44
|
readonly onProjectRequirementChanged: () => void;
|
|
52
45
|
readonly onModelLabelChanged: (ctx: ExtensionContext) => void;
|
|
53
|
-
readonly recordLayoutDiagnostic: (
|
|
54
|
-
diagnostic: AccentRailLayoutPatchDiagnostic,
|
|
55
|
-
version?: string,
|
|
56
|
-
) => void;
|
|
57
46
|
};
|
|
58
47
|
|
|
59
48
|
type EditorInstallMode = "none" | "standalone" | "wrapper";
|
|
@@ -73,8 +62,6 @@ export class EditorLayoutController {
|
|
|
73
62
|
private minimalistDecorationActive = false;
|
|
74
63
|
private minimalistDurationUpdatesActive = false;
|
|
75
64
|
private stopMinimalistDurationUpdates: () => void = () => {};
|
|
76
|
-
private accentRailLayoutPatchCleanup: () => void = () => {};
|
|
77
|
-
private accentRailLayoutPatchInstallSerial = 0;
|
|
78
65
|
|
|
79
66
|
/**
|
|
80
67
|
* Creates an Editor controller with shared runtime selectors.
|
|
@@ -85,37 +72,6 @@ export class EditorLayoutController {
|
|
|
85
72
|
this.context = context;
|
|
86
73
|
}
|
|
87
74
|
|
|
88
|
-
/**
|
|
89
|
-
* Installs the host Accent Rail patch for a new session generation.
|
|
90
|
-
*
|
|
91
|
-
* @param ctx Active Pi extension context.
|
|
92
|
-
* @returns A promise that settles after patch retention is attempted.
|
|
93
|
-
*/
|
|
94
|
-
async startSession(ctx: ExtensionContext): Promise<void> {
|
|
95
|
-
const lifecycleGeneration =
|
|
96
|
-
this.context.sessionLifecycle.currentGeneration();
|
|
97
|
-
const installSerial = ++this.accentRailLayoutPatchInstallSerial;
|
|
98
|
-
this.accentRailLayoutPatchCleanup();
|
|
99
|
-
this.accentRailLayoutPatchCleanup = () => {};
|
|
100
|
-
if (!this.isTuiContext(ctx)) return;
|
|
101
|
-
|
|
102
|
-
const result = await retainAccentRailLayoutPatchInstallation(
|
|
103
|
-
() => installHostAccentRailLayoutPatch(this.ownerToken),
|
|
104
|
-
() =>
|
|
105
|
-
this.context.sessionLifecycle.isCurrent(lifecycleGeneration) &&
|
|
106
|
-
installSerial === this.accentRailLayoutPatchInstallSerial,
|
|
107
|
-
(layoutPatch) => {
|
|
108
|
-
this.accentRailLayoutPatchCleanup = layoutPatch.cleanup;
|
|
109
|
-
this.context.recordLayoutDiagnostic(
|
|
110
|
-
layoutPatch.diagnostic,
|
|
111
|
-
layoutPatch.version,
|
|
112
|
-
);
|
|
113
|
-
},
|
|
114
|
-
);
|
|
115
|
-
if (result === "failed")
|
|
116
|
-
this.context.recordLayoutDiagnostic("host-module-unavailable");
|
|
117
|
-
}
|
|
118
|
-
|
|
119
75
|
/**
|
|
120
76
|
* Installs or reconciles the configured Editor for an active session.
|
|
121
77
|
*
|
|
@@ -355,9 +311,6 @@ export class EditorLayoutController {
|
|
|
355
311
|
}
|
|
356
312
|
}
|
|
357
313
|
this.clearEditorOwnership();
|
|
358
|
-
++this.accentRailLayoutPatchInstallSerial;
|
|
359
|
-
this.accentRailLayoutPatchCleanup();
|
|
360
|
-
this.accentRailLayoutPatchCleanup = () => {};
|
|
361
314
|
this.activeTuiContext = undefined;
|
|
362
315
|
}
|
|
363
316
|
|
|
@@ -516,8 +469,6 @@ export class EditorLayoutController {
|
|
|
516
469
|
getConfig: this.context.getConfig,
|
|
517
470
|
getState: this.context.getState,
|
|
518
471
|
getThinkingLevel: this.context.getThinkingLevel,
|
|
519
|
-
getContextWindow: this.context.getContextWindow,
|
|
520
|
-
getContextPercent: this.context.getContextPercent,
|
|
521
472
|
getAgentDurationMs: this.context.getAgentDurationMs,
|
|
522
473
|
isAgentActive: this.context.isAgentActive,
|
|
523
474
|
getProjectRoot: this.context.getProjectRoot,
|
|
@@ -526,11 +477,6 @@ export class EditorLayoutController {
|
|
|
526
477
|
},
|
|
527
478
|
onDecorationActive: (active) =>
|
|
528
479
|
this.setMinimalistDecorationActive(active),
|
|
529
|
-
isAccentRailActive: () =>
|
|
530
|
-
this.context.sessionLifecycle.isCurrent() &&
|
|
531
|
-
this.ownsActiveFactory(ctx) &&
|
|
532
|
-
this.isEditorEnabled() &&
|
|
533
|
-
this.context.getConfig().components.editor.style === "accent-rail",
|
|
534
480
|
};
|
|
535
481
|
}
|
|
536
482
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { ZentuiConfig } from "../../app/config/shell.ts";
|
|
3
|
-
import {
|
|
4
|
-
type FormatToken,
|
|
5
|
-
parseFooterFormat,
|
|
6
|
-
} from "../footer/footer-format.ts";
|
|
7
3
|
import {
|
|
8
4
|
EDITOR_ACCENT_FALLBACK,
|
|
9
5
|
renderStyleForSourceOrFallback,
|
|
10
6
|
safeThemeFg,
|
|
11
7
|
} from "../../shared/style.ts";
|
|
8
|
+
import {
|
|
9
|
+
type FormatToken,
|
|
10
|
+
parseFooterFormat,
|
|
11
|
+
} from "../footer/footer-format.ts";
|
|
12
12
|
|
|
13
13
|
export type EditorMetadataValues = {
|
|
14
14
|
model: string;
|
|
@@ -6,15 +6,14 @@ import type {
|
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import type { EditorTheme, TUI } from "@earendil-works/pi-tui";
|
|
8
8
|
import type { PolishedTuiConfig } from "../../app/config/shell.ts";
|
|
9
|
-
import {
|
|
10
|
-
import { markAccentRailLayoutEditor } from "./accent-rail-layout-patch.ts";
|
|
11
|
-
import { PolishedEditor, WrappedPolishedEditor } from "./ui.ts";
|
|
9
|
+
import { type FooterState, modelLabelFor } from "../footer/index.ts";
|
|
12
10
|
import {
|
|
11
|
+
type EditorFactory,
|
|
13
12
|
markEditorFactory,
|
|
14
13
|
markWrappedEditorFactory,
|
|
15
|
-
type EditorFactory,
|
|
16
14
|
type ZentuiEditorFactory,
|
|
17
15
|
} from "./ownership.ts";
|
|
16
|
+
import { PolishedEditor, WrappedPolishedEditor } from "./ui.ts";
|
|
18
17
|
|
|
19
18
|
export type EditorFactoryRuntime = {
|
|
20
19
|
readonly ownerToken: symbol;
|
|
@@ -22,14 +21,11 @@ export type EditorFactoryRuntime = {
|
|
|
22
21
|
readonly getConfig: () => PolishedTuiConfig;
|
|
23
22
|
readonly getState: () => FooterState;
|
|
24
23
|
readonly getThinkingLevel: () => ReturnType<ExtensionAPI["getThinkingLevel"]>;
|
|
25
|
-
readonly getContextWindow: (ctx: ExtensionContext) => number | undefined;
|
|
26
|
-
readonly getContextPercent: (ctx: ExtensionContext) => number | undefined;
|
|
27
24
|
readonly getAgentDurationMs: () => number;
|
|
28
25
|
readonly isAgentActive: () => boolean;
|
|
29
26
|
readonly getProjectRoot: () => string | undefined;
|
|
30
27
|
readonly onRender: (requestRender: () => void) => void;
|
|
31
28
|
readonly onDecorationActive: (active: boolean) => void;
|
|
32
|
-
readonly isAccentRailActive: () => boolean;
|
|
33
29
|
};
|
|
34
30
|
|
|
35
31
|
/**
|
|
@@ -49,7 +45,7 @@ export function createEditorFactory(
|
|
|
49
45
|
keybindings: KeybindingsManager,
|
|
50
46
|
) => {
|
|
51
47
|
runtime.onRender(() => tui.requestRender());
|
|
52
|
-
|
|
48
|
+
return new PolishedEditor(
|
|
53
49
|
tui,
|
|
54
50
|
theme,
|
|
55
51
|
keybindings,
|
|
@@ -60,12 +56,6 @@ export function createEditorFactory(
|
|
|
60
56
|
() => editorDecoration(ctx, runtime),
|
|
61
57
|
runtime.onDecorationActive,
|
|
62
58
|
);
|
|
63
|
-
markAccentRailLayoutEditor(
|
|
64
|
-
editor,
|
|
65
|
-
runtime.ownerToken,
|
|
66
|
-
runtime.isAccentRailActive,
|
|
67
|
-
);
|
|
68
|
-
return editor;
|
|
69
59
|
}) as ZentuiEditorFactory;
|
|
70
60
|
return markEditorFactory(factory, runtime.ownerToken);
|
|
71
61
|
}
|
|
@@ -89,7 +79,7 @@ export function createWrappedEditorFactory(
|
|
|
89
79
|
keybindings: KeybindingsManager,
|
|
90
80
|
) => {
|
|
91
81
|
runtime.onRender(() => tui.requestRender());
|
|
92
|
-
|
|
82
|
+
return new WrappedPolishedEditor(
|
|
93
83
|
baseFactory(tui, theme, keybindings),
|
|
94
84
|
runtime.sessionTheme,
|
|
95
85
|
runtime.getConfig,
|
|
@@ -98,12 +88,6 @@ export function createWrappedEditorFactory(
|
|
|
98
88
|
() => editorDecoration(ctx, runtime),
|
|
99
89
|
runtime.onDecorationActive,
|
|
100
90
|
);
|
|
101
|
-
markAccentRailLayoutEditor(
|
|
102
|
-
editor,
|
|
103
|
-
runtime.ownerToken,
|
|
104
|
-
runtime.isAccentRailActive,
|
|
105
|
-
);
|
|
106
|
-
return editor;
|
|
107
91
|
}) as ZentuiEditorFactory;
|
|
108
92
|
return markWrappedEditorFactory(factory, baseFactory, runtime.ownerToken);
|
|
109
93
|
}
|
|
@@ -150,8 +134,6 @@ function editorDecoration(
|
|
|
150
134
|
costLabel: state.costLabel,
|
|
151
135
|
modelLabel: modelLabelFor(state, config.components.editor.modelLabel),
|
|
152
136
|
thinkingLevel: runtime.getThinkingLevel(),
|
|
153
|
-
contextPercent: runtime.getContextPercent(ctx),
|
|
154
|
-
contextWindow: runtime.getContextWindow(ctx),
|
|
155
137
|
sessionName: ctx.sessionManager.getSessionName() ?? "",
|
|
156
138
|
agentDurationMs: runtime.getAgentDurationMs(),
|
|
157
139
|
agentActive: runtime.isAgentActive(),
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
export {
|
|
2
|
-
EditorLayoutController,
|
|
3
2
|
type EditorChangeResult,
|
|
3
|
+
EditorLayoutController,
|
|
4
4
|
type EditorLayoutControllerContext,
|
|
5
5
|
} from "./controller.ts";
|
|
6
6
|
export {
|
|
7
|
-
installHostAccentRailLayoutPatch,
|
|
8
|
-
markAccentRailLayoutEditor,
|
|
9
|
-
retainAccentRailLayoutPatchInstallation,
|
|
10
|
-
type AccentRailLayoutPatchDiagnostic,
|
|
11
|
-
} from "./accent-rail-layout-patch.ts";
|
|
12
|
-
export {
|
|
13
|
-
replaceEditorComponentWithExpandedText,
|
|
14
7
|
type EditorTransferFailureReason,
|
|
8
|
+
replaceEditorComponentWithExpandedText,
|
|
15
9
|
} from "./editor-transfer.ts";
|
|
16
10
|
export { PolishedEditor, WrappedPolishedEditor } from "./ui.ts";
|
|
@@ -2,14 +2,8 @@ import { basename, isAbsolute, relative, sep } from "node:path";
|
|
|
2
2
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
4
|
import type { ZentuiConfig } from "../../app/config/shell.ts";
|
|
5
|
+
import { formatCwdLabel, formatElapsedDuration } from "../../shared/format.ts";
|
|
5
6
|
import { sanitizeEditorMetadataText } from "./editor-metadata-format.ts";
|
|
6
|
-
import {
|
|
7
|
-
buildContextGauge,
|
|
8
|
-
contextColorTier,
|
|
9
|
-
formatCount,
|
|
10
|
-
formatCwdLabel,
|
|
11
|
-
formatElapsedDuration,
|
|
12
|
-
} from "../../shared/format.ts";
|
|
13
7
|
|
|
14
8
|
export { formatElapsedDuration } from "../../shared/format.ts";
|
|
15
9
|
|
|
@@ -53,8 +47,6 @@ export type MinimalistEditorMetadata = {
|
|
|
53
47
|
costLabel?: string;
|
|
54
48
|
modelLabel?: string;
|
|
55
49
|
thinkingLevel?: string;
|
|
56
|
-
contextPercent?: number;
|
|
57
|
-
contextWindow?: number;
|
|
58
50
|
sessionName?: string;
|
|
59
51
|
agentDurationMs?: number;
|
|
60
52
|
agentActive?: boolean;
|
|
@@ -201,7 +193,6 @@ function renderTopRight(
|
|
|
201
193
|
metadata: MinimalistEditorMetadata,
|
|
202
194
|
uiTheme: Theme,
|
|
203
195
|
config: ZentuiConfig,
|
|
204
|
-
availableWidth: number,
|
|
205
196
|
renderBorder: (text: string) => string,
|
|
206
197
|
renderThinking: (text: string) => string,
|
|
207
198
|
): string {
|
|
@@ -235,46 +226,6 @@ function renderTopRight(
|
|
|
235
226
|
if (thinking && thinking.toLowerCase() !== "off") {
|
|
236
227
|
parts.push(renderThinking(thinking));
|
|
237
228
|
}
|
|
238
|
-
if (
|
|
239
|
-
metadata.contextPercent !== undefined &&
|
|
240
|
-
Number.isFinite(metadata.contextPercent)
|
|
241
|
-
) {
|
|
242
|
-
const percent = Math.round(
|
|
243
|
-
Math.max(0, Math.min(999, metadata.contextPercent)),
|
|
244
|
-
);
|
|
245
|
-
const tier = contextColorTier(
|
|
246
|
-
percent,
|
|
247
|
-
config.components.editor.styles.minimalist.contextThresholds,
|
|
248
|
-
);
|
|
249
|
-
const style =
|
|
250
|
-
tier === "error"
|
|
251
|
-
? config.colors.contextError
|
|
252
|
-
: tier === "warning"
|
|
253
|
-
? config.colors.contextWarning
|
|
254
|
-
: config.colors.contextNormal;
|
|
255
|
-
const total =
|
|
256
|
-
config.components.editor.styles.minimalist.contextFormat ===
|
|
257
|
-
"percent-total" &&
|
|
258
|
-
metadata.contextWindow !== undefined &&
|
|
259
|
-
Number.isFinite(metadata.contextWindow) &&
|
|
260
|
-
metadata.contextWindow > 0
|
|
261
|
-
? `/${formatCount(metadata.contextWindow)}`
|
|
262
|
-
: "";
|
|
263
|
-
const text = `${percent}%${total}`;
|
|
264
|
-
let context = renderStyleForSource(uiTheme, source, style, text);
|
|
265
|
-
if (config.components.editor.styles.minimalist.contextGauge) {
|
|
266
|
-
for (const gaugeWidth of [5, 3]) {
|
|
267
|
-
const gauge = `[${buildContextGauge(percent, gaugeWidth, config.icons.mode === "ascii")}] ${text}`;
|
|
268
|
-
const styledGauge = renderStyleForSource(uiTheme, source, style, gauge);
|
|
269
|
-
const candidate = joinParts([...parts, styledGauge]);
|
|
270
|
-
if (visibleWidth(candidate) <= availableWidth) {
|
|
271
|
-
context = styledGauge;
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
parts.push(context);
|
|
277
|
-
}
|
|
278
229
|
return joinParts(parts);
|
|
279
230
|
}
|
|
280
231
|
|
|
@@ -500,7 +451,6 @@ export function renderMinimalistFrame({
|
|
|
500
451
|
);
|
|
501
452
|
const topViewport = viewportLabel("above", viewport?.above);
|
|
502
453
|
const topLeft = joinStyled([topViewport, topMetadata], separator);
|
|
503
|
-
const topRightBudget = Math.max(0, width - 8 - visibleWidth(topLeft));
|
|
504
454
|
const topFallbacks = [
|
|
505
455
|
joinStyled([topViewport, topOperational], separator),
|
|
506
456
|
topOperational,
|
|
@@ -516,7 +466,6 @@ export function renderMinimalistFrame({
|
|
|
516
466
|
metadata,
|
|
517
467
|
uiTheme,
|
|
518
468
|
config,
|
|
519
|
-
topRightBudget,
|
|
520
469
|
renderBorder,
|
|
521
470
|
renderThinking,
|
|
522
471
|
),
|