pi-one-ui 0.1.1 → 0.2.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.
- package/README.md +66 -39
- package/extensions/{shell → app/commands}/settings-previews.ts +7 -7
- package/extensions/app/config/renderer.ts +13 -63
- package/extensions/app/config/shell.ts +24 -138
- package/extensions/app/config/store.ts +290 -0
- package/extensions/app/host/pi-extension-port.ts +25 -0
- package/extensions/app/host/pi-ui-port.ts +52 -0
- package/extensions/app/host/tui-capabilities.ts +27 -0
- package/extensions/app/overlay/input-router.ts +63 -0
- package/extensions/app/overlay/overlay-manager.ts +39 -0
- package/extensions/{shell → app/overlay}/selector-border.ts +3 -3
- package/extensions/app/overlay/selector-controller.ts +104 -0
- package/extensions/app/ownership/layout-registry.ts +65 -0
- package/extensions/app/ownership.ts +21 -7
- package/extensions/app/panel.ts +315 -143
- package/extensions/app/runtime/event-coordinator.ts +84 -0
- package/extensions/app/runtime/render-scheduler.ts +56 -0
- package/extensions/app/runtime/runtime-state.ts +83 -0
- package/extensions/app/runtime/tui-runtime.ts +546 -0
- package/extensions/features/{context.ts → context-inspector/index.ts} +30 -23
- package/extensions/features/{shell/flush-docked-bash.ts → flush-docked-bash.ts} +1 -4
- package/extensions/index.ts +2 -48
- package/extensions/layouts/context/index.ts +188 -0
- package/extensions/{shell → layouts/context/message}/user-message-styles.ts +2 -2
- package/extensions/{shell → layouts/context/message}/user-message.ts +2 -2
- package/extensions/{transcript → layouts/context}/renderer/compact-mode.ts +17 -13
- package/extensions/layouts/context/renderer/context-refresh.ts +79 -0
- package/extensions/{transcript → layouts/context}/renderer/default-mode.ts +3 -3
- package/extensions/{transcript → layouts/context}/renderer/index.ts +14 -14
- package/extensions/{transcript → layouts/context}/renderer/mouse/hover.ts +2 -2
- package/extensions/{transcript → layouts/context}/renderer/mouse/interaction.ts +26 -7
- package/extensions/{transcript → layouts/context}/renderer/mouse/layout.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/mouse/packets.ts +3 -3
- package/extensions/{transcript → layouts/context}/renderer/mouse/scroll.ts +12 -7
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-component.ts +2 -2
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-edit-render.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-highlight.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-layout.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-limits.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-palette.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-presentation.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-renderer.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-write-render.ts +1 -1
- package/extensions/{transcript → layouts/context}/renderer/tool/diff/index.ts +2 -2
- package/extensions/{transcript → layouts/context}/renderer/tool/grouping.ts +4 -4
- package/extensions/{transcript → layouts/context}/renderer/tool/message-display.ts +6 -4
- package/extensions/{transcript → layouts/context}/renderer/tool/names.ts +2 -2
- package/extensions/{transcript → layouts/context}/renderer/tool/result.ts +3 -3
- package/extensions/{features/agent-summary → layouts/context/summary}/core.ts +1 -1
- package/extensions/{features → layouts/context/thinking}/compact-thinking.ts +7 -7
- package/extensions/{shell → layouts/editor}/accent-rail-editor.ts +8 -8
- package/extensions/{shell → layouts/editor}/completion-menu.ts +3 -6
- package/extensions/layouts/editor/controller.ts +613 -0
- package/extensions/{shell → layouts/editor}/editor-metadata-format.ts +6 -3
- package/extensions/layouts/editor/factory.ts +159 -0
- package/extensions/layouts/editor/index.ts +16 -0
- package/extensions/{shell → layouts/editor}/minimalist-editor.ts +4 -4
- package/extensions/layouts/editor/ownership.ts +103 -0
- package/extensions/{shell → layouts/editor}/ui.ts +2 -2
- package/extensions/layouts/footer/controller.ts +392 -0
- package/extensions/layouts/footer/data.ts +41 -0
- package/extensions/{shell → layouts/footer}/extension-status.ts +2 -2
- package/extensions/{shell → layouts/footer}/footer-layout.ts +1 -1
- package/extensions/{shell → layouts/footer}/footer.ts +11 -8
- package/extensions/layouts/footer/index.ts +24 -0
- package/extensions/layouts/header/index.ts +5 -0
- package/extensions/{features/shell → layouts/header}/startup-header.ts +105 -19
- package/extensions/layouts/working-line/controller.ts +291 -0
- package/extensions/{shell → layouts/working-line}/interaction-summary.ts +3 -3
- package/extensions/{shell → layouts/working-line}/working-line-spinners.ts +1 -1
- package/extensions/{shell → layouts/working-line}/working-line.ts +4 -4
- package/extensions/{shell → services}/live-context.ts +29 -1
- package/extensions/services/project-refresh.ts +374 -0
- package/extensions/{shell → services}/project-state.ts +5 -5
- package/extensions/{shell/state.ts → services/session-state.ts} +75 -5
- package/extensions/{shell → shared}/format.ts +4 -4
- package/extensions/tools/component-tree.ts +6 -6
- package/package.json +12 -4
- package/extensions/shell/index.ts +0 -1659
- package/extensions/shell/project-refresh.ts +0 -130
- package/extensions/shell/settings-command.ts +0 -2144
- package/extensions/transcript/index.ts +0 -65
- package/extensions/transcript/renderer/transcript-refresh.ts +0 -79
- /package/extensions/{shell → app/ownership}/prototype-patch-registry.ts +0 -0
- /package/extensions/{shell → app/runtime}/session-lifecycle.ts +0 -0
- /package/extensions/features/{shell/aliases.ts → aliases.ts} +0 -0
- /package/extensions/features/{shell → legacy}/working-message.ts +0 -0
- /package/extensions/features/{reference → session-reference}/index.ts +0 -0
- /package/extensions/features/{reference → session-reference}/session.ts +0 -0
- /package/extensions/features/{reference/subagent.ts → subagent-autocomplete.ts} +0 -0
- /package/extensions/{shell → layouts/context/message}/user-message-osc.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/markdown-enhance.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/ATTRIBUTION.md +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/ansi-utils.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-header.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-inline.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-parse.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/diff-text.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/line-width-safety.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/shiki-highlight.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/diff/write-execution.ts +0 -0
- /package/extensions/{transcript → layouts/context}/renderer/tool/show-more-hint.ts +0 -0
- /package/extensions/{features/agent-summary → layouts/context/summary}/index.ts +0 -0
- /package/extensions/{shell → layouts/editor}/accent-rail-layout-patch.ts +0 -0
- /package/extensions/{shell → layouts/editor}/editor-transfer.ts +0 -0
- /package/extensions/{shell → layouts/footer}/footer-format.ts +0 -0
- /package/extensions/{shell → layouts/working-line}/working-line-messages.ts +0 -0
- /package/extensions/{shell/git.ts → services/git-data.ts} +0 -0
- /package/extensions/{shell/package-version.ts → services/package-data.ts} +0 -0
- /package/extensions/{shell/runtime.ts → services/runtime-data.ts} +0 -0
- /package/extensions/{shell → services}/telemetry.ts +0 -0
- /package/extensions/{shell → shared}/icons.ts +0 -0
- /package/extensions/{shell → shared}/style.ts +0 -0
package/extensions/app/panel.ts
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ExtensionCommandContext,
|
|
3
|
+
type ExtensionContext,
|
|
4
|
+
getSettingsListTheme,
|
|
5
|
+
} from "@earendil-works/pi-coding-agent";
|
|
2
6
|
import {
|
|
3
7
|
matchesKey,
|
|
4
8
|
type SettingItem,
|
|
5
9
|
SettingsList,
|
|
6
10
|
truncateToWidth,
|
|
7
11
|
} from "@earendil-works/pi-tui";
|
|
8
|
-
import type { ShellRuntimeController } from "../shell/index.ts";
|
|
9
12
|
import {
|
|
10
13
|
renderEditorSettingsPreview,
|
|
11
14
|
renderUserMessageSettingsPreview,
|
|
12
|
-
} from "
|
|
13
|
-
import type { TranscriptRuntimeController } from "../transcript/index.ts";
|
|
15
|
+
} from "./commands/settings-previews.ts";
|
|
14
16
|
import {
|
|
15
17
|
type CompactStyleMode,
|
|
18
|
+
type Config as ContextConfig,
|
|
16
19
|
DIFF_INDICATOR_MODES,
|
|
17
20
|
DIFF_VIEW_MODES,
|
|
18
|
-
type Config as RendererConfig,
|
|
19
21
|
config as rendererConfig,
|
|
20
|
-
updateConfig as
|
|
22
|
+
updateConfig as updateContextConfig,
|
|
21
23
|
} from "./config/renderer.ts";
|
|
22
24
|
import {
|
|
25
|
+
type EditorComponentConfig,
|
|
23
26
|
type EditorStyle,
|
|
27
|
+
type FooterComponentConfig,
|
|
24
28
|
type FooterStyle,
|
|
25
29
|
loadConfig as loadShellConfig,
|
|
26
30
|
saveEditorComponentPatch,
|
|
@@ -28,8 +32,11 @@ import {
|
|
|
28
32
|
saveUserMessagesComponentPatch,
|
|
29
33
|
saveWorkingLineComponentPatch,
|
|
30
34
|
type UserMessageStyle,
|
|
35
|
+
type UserMessagesComponentConfig,
|
|
36
|
+
type WorkingLineComponentPatch,
|
|
31
37
|
type WorkingLineSpinner,
|
|
32
38
|
} from "./config/shell.ts";
|
|
39
|
+
import { overlayManager } from "./overlay/overlay-manager.ts";
|
|
33
40
|
import { ownerFor } from "./ownership.ts";
|
|
34
41
|
import { applyPreset, PRESET_VALUES, type Preset } from "./presets.ts";
|
|
35
42
|
|
|
@@ -56,8 +63,11 @@ const WORKING_SPINNERS: WorkingLineSpinner[] = [
|
|
|
56
63
|
const PREVIEW_LINES = ["0", "1", "3", "5", "10"];
|
|
57
64
|
|
|
58
65
|
const SECTIONS = [
|
|
59
|
-
{ id: "
|
|
60
|
-
{ id: "
|
|
66
|
+
{ id: "header", label: "Header" },
|
|
67
|
+
{ id: "context", label: "Context" },
|
|
68
|
+
{ id: "workingLine", label: "WorkingLine" },
|
|
69
|
+
{ id: "editor", label: "Editor" },
|
|
70
|
+
{ id: "footer", label: "Footer" },
|
|
61
71
|
{ id: "features", label: "Features" },
|
|
62
72
|
{ id: "presets", label: "Presets" },
|
|
63
73
|
] as const;
|
|
@@ -75,12 +85,38 @@ function renderTabs(theme: any, active: number, width: number): string {
|
|
|
75
85
|
return truncateToWidth(text, Math.max(0, width));
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
/** Adds a stable chrome frame around the settings content. */
|
|
89
|
+
function renderPanelFrame(theme: any, width: number, rows: string[]): string[] {
|
|
90
|
+
const safeWidth = Math.max(1, width);
|
|
91
|
+
const border = (text: string) => theme.fg("border", text);
|
|
92
|
+
if (safeWidth === 1)
|
|
93
|
+
return [border("│"), ...rows.map(() => border("│")), border("│")];
|
|
94
|
+
|
|
95
|
+
const innerWidth = safeWidth - 2;
|
|
96
|
+
const content = rows.map(
|
|
97
|
+
(row) =>
|
|
98
|
+
`${border("│")}${truncateToWidth(row, innerWidth, "", true)}${border("│")}`,
|
|
99
|
+
);
|
|
100
|
+
if (safeWidth === 2) return [border("╭╮"), ...content, border("╰╯")];
|
|
101
|
+
return [
|
|
102
|
+
border(`╭${"─".repeat(innerWidth)}╮`),
|
|
103
|
+
...content,
|
|
104
|
+
border(`╰${"─".repeat(innerWidth)}╯`),
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
|
|
78
108
|
function sectionDescription(section: SectionId): string {
|
|
79
109
|
switch (section) {
|
|
80
|
-
case "
|
|
81
|
-
return
|
|
82
|
-
case "
|
|
83
|
-
return `${ownerFor("toolRenderer")} owns tool cards,
|
|
110
|
+
case "header":
|
|
111
|
+
return "Header owns startup branding and startup guidance.";
|
|
112
|
+
case "context":
|
|
113
|
+
return `${ownerFor("toolRenderer")} owns messages, tool cards, diffs, thinking, and summaries.`;
|
|
114
|
+
case "workingLine":
|
|
115
|
+
return "WorkingLine is the sole owner of Pi's unkeyed working row.";
|
|
116
|
+
case "editor":
|
|
117
|
+
return `${ownerFor("editor")} owns the input editor factory and its styles.`;
|
|
118
|
+
case "footer":
|
|
119
|
+
return `${ownerFor("footer")} owns footer rendering and project status segments.`;
|
|
84
120
|
case "features":
|
|
85
121
|
return "Feature switches are saved immediately and applied after /reload.";
|
|
86
122
|
case "presets":
|
|
@@ -88,13 +124,16 @@ function sectionDescription(section: SectionId): string {
|
|
|
88
124
|
}
|
|
89
125
|
}
|
|
90
126
|
|
|
91
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Builds settings owned by the Editor layout.
|
|
129
|
+
*/
|
|
130
|
+
function editorItems(): SettingItem[] {
|
|
92
131
|
const config = loadShellConfig();
|
|
93
132
|
return [
|
|
94
133
|
{
|
|
95
134
|
id: "editorEnabled",
|
|
96
135
|
label: "Editor",
|
|
97
|
-
description: "Enable
|
|
136
|
+
description: "Enable the custom input editor.",
|
|
98
137
|
currentValue: onOff(config.components.editor.enabled),
|
|
99
138
|
values: ["on", "off"],
|
|
100
139
|
},
|
|
@@ -105,24 +144,19 @@ function shellItems(): SettingItem[] {
|
|
|
105
144
|
currentValue: config.components.editor.style,
|
|
106
145
|
values: EDITOR_STYLES,
|
|
107
146
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
label: "Message style",
|
|
118
|
-
description: "Choose the previous user message treatment.",
|
|
119
|
-
currentValue: config.components.userMessages.style,
|
|
120
|
-
values: MESSAGE_STYLES,
|
|
121
|
-
},
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Builds settings owned by the WorkingLine layout.
|
|
152
|
+
*/
|
|
153
|
+
function workingLineItems(): SettingItem[] {
|
|
154
|
+
const config = loadShellConfig();
|
|
155
|
+
return [
|
|
122
156
|
{
|
|
123
157
|
id: "workingLineEnabled",
|
|
124
158
|
label: "Working line",
|
|
125
|
-
description: "
|
|
159
|
+
description: "Enable the sole owner of Pi's working row.",
|
|
126
160
|
currentValue: onOff(config.components.workingLine.enabled),
|
|
127
161
|
values: ["on", "off"],
|
|
128
162
|
},
|
|
@@ -133,6 +167,15 @@ function shellItems(): SettingItem[] {
|
|
|
133
167
|
currentValue: config.components.workingLine.spinner,
|
|
134
168
|
values: WORKING_SPINNERS,
|
|
135
169
|
},
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Builds settings owned by the Footer layout.
|
|
175
|
+
*/
|
|
176
|
+
function footerItems(): SettingItem[] {
|
|
177
|
+
const config = loadShellConfig();
|
|
178
|
+
return [
|
|
136
179
|
{
|
|
137
180
|
id: "footerStyle",
|
|
138
181
|
label: "Footer",
|
|
@@ -143,10 +186,28 @@ function shellItems(): SettingItem[] {
|
|
|
143
186
|
];
|
|
144
187
|
}
|
|
145
188
|
|
|
146
|
-
|
|
189
|
+
/**
|
|
190
|
+
* Builds settings owned by the Context layout.
|
|
191
|
+
*/
|
|
192
|
+
function contextItems(config: ContextConfig): SettingItem[] {
|
|
193
|
+
const shellConfig = loadShellConfig();
|
|
147
194
|
return [
|
|
148
195
|
{
|
|
149
|
-
id: "
|
|
196
|
+
id: "userMessagesEnabled",
|
|
197
|
+
label: "User messages",
|
|
198
|
+
description: "Enable custom rendering for previous user messages.",
|
|
199
|
+
currentValue: onOff(shellConfig.components.userMessages.enabled),
|
|
200
|
+
values: ["on", "off"],
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: "userMessagesStyle",
|
|
204
|
+
label: "Message style",
|
|
205
|
+
description: "Choose the previous user message treatment.",
|
|
206
|
+
currentValue: shellConfig.components.userMessages.style,
|
|
207
|
+
values: MESSAGE_STYLES,
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: "contextMode",
|
|
150
211
|
label: "Tool style",
|
|
151
212
|
description:
|
|
152
213
|
"on = rich cards, compact = one summary per assistant message, off = native.",
|
|
@@ -191,7 +252,25 @@ function rendererItems(config: RendererConfig): SettingItem[] {
|
|
|
191
252
|
];
|
|
192
253
|
}
|
|
193
254
|
|
|
194
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Builds settings owned by the Header layout.
|
|
257
|
+
*/
|
|
258
|
+
function headerItems(config: ContextConfig): SettingItem[] {
|
|
259
|
+
return [
|
|
260
|
+
{
|
|
261
|
+
id: "showStartupHeader",
|
|
262
|
+
label: "Startup header",
|
|
263
|
+
description: "Show the custom startup header on new sessions.",
|
|
264
|
+
currentValue: onOff(config.showStartupHeader),
|
|
265
|
+
values: ["on", "off"],
|
|
266
|
+
},
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Builds non-visual feature switches.
|
|
272
|
+
*/
|
|
273
|
+
function featureItems(config: ContextConfig): SettingItem[] {
|
|
195
274
|
return [
|
|
196
275
|
{
|
|
197
276
|
id: "enableSessionReference",
|
|
@@ -228,13 +307,6 @@ function featureItems(config: RendererConfig): SettingItem[] {
|
|
|
228
307
|
currentValue: onOff(config.enableAliases),
|
|
229
308
|
values: ["on", "off"],
|
|
230
309
|
},
|
|
231
|
-
{
|
|
232
|
-
id: "showStartupHeader",
|
|
233
|
-
label: "Startup header",
|
|
234
|
-
description: "Show CC Style's startup header on new sessions.",
|
|
235
|
-
currentValue: onOff(config.showStartupHeader),
|
|
236
|
-
values: ["on", "off"],
|
|
237
|
-
},
|
|
238
310
|
];
|
|
239
311
|
}
|
|
240
312
|
|
|
@@ -244,10 +316,10 @@ function presetItems(): SettingItem[] {
|
|
|
244
316
|
label: preset,
|
|
245
317
|
description:
|
|
246
318
|
preset === "balanced"
|
|
247
|
-
? "Zentui shell + rich CC Style
|
|
319
|
+
? "Zentui shell + rich CC Style context renderer."
|
|
248
320
|
: preset === "compact"
|
|
249
|
-
? "Zentui shell + compact CC Style
|
|
250
|
-
: "Disable custom shell and
|
|
321
|
+
? "Zentui shell + compact CC Style context."
|
|
322
|
+
: "Disable custom shell and context rendering.",
|
|
251
323
|
currentValue: "apply",
|
|
252
324
|
values: ["apply"],
|
|
253
325
|
}));
|
|
@@ -255,10 +327,16 @@ function presetItems(): SettingItem[] {
|
|
|
255
327
|
|
|
256
328
|
function itemsFor(section: SectionId): SettingItem[] {
|
|
257
329
|
switch (section) {
|
|
258
|
-
case "
|
|
259
|
-
return
|
|
260
|
-
case "
|
|
261
|
-
return
|
|
330
|
+
case "header":
|
|
331
|
+
return headerItems(rendererConfig);
|
|
332
|
+
case "context":
|
|
333
|
+
return contextItems(rendererConfig);
|
|
334
|
+
case "workingLine":
|
|
335
|
+
return workingLineItems();
|
|
336
|
+
case "editor":
|
|
337
|
+
return editorItems();
|
|
338
|
+
case "footer":
|
|
339
|
+
return footerItems();
|
|
262
340
|
case "features":
|
|
263
341
|
return featureItems(rendererConfig);
|
|
264
342
|
case "presets":
|
|
@@ -270,12 +348,38 @@ function isOn(value: string): boolean {
|
|
|
270
348
|
return value === "on";
|
|
271
349
|
}
|
|
272
350
|
|
|
351
|
+
export type TuiPanelRuntime = {
|
|
352
|
+
setEditorComponent: (
|
|
353
|
+
patch: Partial<EditorComponentConfig>,
|
|
354
|
+
ctx: ExtensionContext,
|
|
355
|
+
) => { applied: boolean; reason?: string };
|
|
356
|
+
setUserMessagesComponent: (
|
|
357
|
+
patch: Partial<UserMessagesComponentConfig>,
|
|
358
|
+
ctx: ExtensionContext,
|
|
359
|
+
) => void;
|
|
360
|
+
setWorkingLineComponent: (
|
|
361
|
+
patch: WorkingLineComponentPatch,
|
|
362
|
+
ctx: ExtensionContext,
|
|
363
|
+
) => { applied: boolean; reason?: string };
|
|
364
|
+
setFooterComponent: (
|
|
365
|
+
patch: Partial<FooterComponentConfig>,
|
|
366
|
+
ctx: ExtensionContext,
|
|
367
|
+
) => void;
|
|
368
|
+
setContextMode: (mode: CompactStyleMode, ctx: ExtensionContext) => void;
|
|
369
|
+
updateContextConfig: (
|
|
370
|
+
patch: Partial<ContextConfig>,
|
|
371
|
+
ctx: ExtensionContext,
|
|
372
|
+
) => void;
|
|
373
|
+
};
|
|
374
|
+
|
|
273
375
|
type UnifiedPanelDeps = {
|
|
274
|
-
|
|
275
|
-
renderer?: TranscriptRuntimeController;
|
|
376
|
+
runtime?: TuiPanelRuntime;
|
|
276
377
|
};
|
|
277
378
|
|
|
278
|
-
|
|
379
|
+
/**
|
|
380
|
+
* Renders the Editor layout preview for the settings panel.
|
|
381
|
+
*/
|
|
382
|
+
function renderEditorPreview(theme: any, width: number): string[] {
|
|
279
383
|
const config = loadShellConfig();
|
|
280
384
|
const previewWidth = Math.max(20, Math.min(72, width - 2));
|
|
281
385
|
return [
|
|
@@ -284,6 +388,16 @@ function renderShellPreview(theme: any, width: number): string[] {
|
|
|
284
388
|
...renderEditorSettingsPreview(config, theme, previewWidth).map(
|
|
285
389
|
(line) => ` ${line}`,
|
|
286
390
|
),
|
|
391
|
+
];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Renders the Context layout User Message preview for the settings panel.
|
|
396
|
+
*/
|
|
397
|
+
function renderContextPreview(theme: any, width: number): string[] {
|
|
398
|
+
const config = loadShellConfig();
|
|
399
|
+
const previewWidth = Math.max(20, Math.min(72, width - 2));
|
|
400
|
+
return [
|
|
287
401
|
"",
|
|
288
402
|
theme.fg("muted", " User message preview"),
|
|
289
403
|
...renderUserMessageSettingsPreview(config, theme, previewWidth).map(
|
|
@@ -299,6 +413,14 @@ function saveNotice(ctx: any, label: string, value: string): void {
|
|
|
299
413
|
);
|
|
300
414
|
}
|
|
301
415
|
|
|
416
|
+
/**
|
|
417
|
+
* Persists one panel setting and reconciles its owning runtime layout.
|
|
418
|
+
*
|
|
419
|
+
* @param id Stable settings item identifier.
|
|
420
|
+
* @param value Selected settings value.
|
|
421
|
+
* @param ctx Active Pi extension context.
|
|
422
|
+
* @param deps Live runtime controllers available to the panel.
|
|
423
|
+
*/
|
|
302
424
|
function updateSetting(
|
|
303
425
|
id: string,
|
|
304
426
|
value: string,
|
|
@@ -306,22 +428,22 @@ function updateSetting(
|
|
|
306
428
|
deps: UnifiedPanelDeps,
|
|
307
429
|
): void {
|
|
308
430
|
if (id === "editorEnabled") {
|
|
309
|
-
if (deps.
|
|
310
|
-
deps.
|
|
431
|
+
if (deps.runtime)
|
|
432
|
+
deps.runtime.setEditorComponent({ enabled: isOn(value) }, ctx);
|
|
311
433
|
else saveEditorComponentPatch({ enabled: isOn(value) });
|
|
312
434
|
saveNotice(ctx, "Editor", value);
|
|
313
435
|
return;
|
|
314
436
|
}
|
|
315
437
|
if (id === "editorStyle" && EDITOR_STYLES.includes(value as EditorStyle)) {
|
|
316
|
-
if (deps.
|
|
317
|
-
deps.
|
|
438
|
+
if (deps.runtime)
|
|
439
|
+
deps.runtime.setEditorComponent({ style: value as EditorStyle }, ctx);
|
|
318
440
|
else saveEditorComponentPatch({ style: value as EditorStyle });
|
|
319
441
|
saveNotice(ctx, "Editor style", value);
|
|
320
442
|
return;
|
|
321
443
|
}
|
|
322
444
|
if (id === "userMessagesEnabled") {
|
|
323
|
-
if (deps.
|
|
324
|
-
deps.
|
|
445
|
+
if (deps.runtime)
|
|
446
|
+
deps.runtime.setUserMessagesComponent({ enabled: isOn(value) }, ctx);
|
|
325
447
|
else saveUserMessagesComponentPatch({ enabled: isOn(value) });
|
|
326
448
|
saveNotice(ctx, "User messages", value);
|
|
327
449
|
return;
|
|
@@ -330,8 +452,8 @@ function updateSetting(
|
|
|
330
452
|
id === "userMessagesStyle" &&
|
|
331
453
|
MESSAGE_STYLES.includes(value as UserMessageStyle)
|
|
332
454
|
) {
|
|
333
|
-
if (deps.
|
|
334
|
-
deps.
|
|
455
|
+
if (deps.runtime)
|
|
456
|
+
deps.runtime.setUserMessagesComponent(
|
|
335
457
|
{ style: value as UserMessageStyle },
|
|
336
458
|
ctx,
|
|
337
459
|
);
|
|
@@ -340,8 +462,8 @@ function updateSetting(
|
|
|
340
462
|
return;
|
|
341
463
|
}
|
|
342
464
|
if (id === "workingLineEnabled") {
|
|
343
|
-
if (deps.
|
|
344
|
-
deps.
|
|
465
|
+
if (deps.runtime)
|
|
466
|
+
deps.runtime.setWorkingLineComponent({ enabled: isOn(value) }, ctx);
|
|
345
467
|
else saveWorkingLineComponentPatch({ enabled: isOn(value) });
|
|
346
468
|
saveNotice(ctx, "Working line", value);
|
|
347
469
|
return;
|
|
@@ -350,8 +472,8 @@ function updateSetting(
|
|
|
350
472
|
id === "workingLineSpinner" &&
|
|
351
473
|
WORKING_SPINNERS.includes(value as WorkingLineSpinner)
|
|
352
474
|
) {
|
|
353
|
-
if (deps.
|
|
354
|
-
deps.
|
|
475
|
+
if (deps.runtime)
|
|
476
|
+
deps.runtime.setWorkingLineComponent(
|
|
355
477
|
{ spinner: value as WorkingLineSpinner },
|
|
356
478
|
ctx,
|
|
357
479
|
);
|
|
@@ -361,22 +483,23 @@ function updateSetting(
|
|
|
361
483
|
return;
|
|
362
484
|
}
|
|
363
485
|
if (id === "footerStyle" && FOOTER_STYLES.includes(value as FooterStyle)) {
|
|
364
|
-
if (deps.
|
|
365
|
-
deps.
|
|
486
|
+
if (deps.runtime)
|
|
487
|
+
deps.runtime.setFooterComponent({ style: value as FooterStyle }, ctx);
|
|
366
488
|
else saveFooterComponentPatch({ style: value as FooterStyle });
|
|
367
489
|
saveNotice(ctx, "Footer", value);
|
|
368
490
|
return;
|
|
369
491
|
}
|
|
370
|
-
if (id === "
|
|
371
|
-
if (deps.
|
|
372
|
-
|
|
492
|
+
if (id === "contextMode") {
|
|
493
|
+
if (deps.runtime)
|
|
494
|
+
deps.runtime.setContextMode(value as CompactStyleMode, ctx);
|
|
495
|
+
else updateContextConfig({ mode: value as CompactStyleMode });
|
|
373
496
|
saveNotice(ctx, "Tool style", value);
|
|
374
497
|
return;
|
|
375
498
|
}
|
|
376
499
|
if (id === "diffViewMode" && DIFF_VIEW_MODES.includes(value as never)) {
|
|
377
|
-
const patch = { diffViewMode: value as
|
|
378
|
-
if (deps.
|
|
379
|
-
else
|
|
500
|
+
const patch = { diffViewMode: value as ContextConfig["diffViewMode"] };
|
|
501
|
+
if (deps.runtime) deps.runtime.updateContextConfig(patch, ctx);
|
|
502
|
+
else updateContextConfig(patch);
|
|
380
503
|
saveNotice(ctx, "Diff layout", value);
|
|
381
504
|
return;
|
|
382
505
|
}
|
|
@@ -385,31 +508,31 @@ function updateSetting(
|
|
|
385
508
|
DIFF_INDICATOR_MODES.includes(value as never)
|
|
386
509
|
) {
|
|
387
510
|
const patch = {
|
|
388
|
-
diffIndicatorMode: value as
|
|
511
|
+
diffIndicatorMode: value as ContextConfig["diffIndicatorMode"],
|
|
389
512
|
};
|
|
390
|
-
if (deps.
|
|
391
|
-
else
|
|
513
|
+
if (deps.runtime) deps.runtime.updateContextConfig(patch, ctx);
|
|
514
|
+
else updateContextConfig(patch);
|
|
392
515
|
saveNotice(ctx, "Diff indicator", value);
|
|
393
516
|
return;
|
|
394
517
|
}
|
|
395
518
|
if (id === "diffWordWrap") {
|
|
396
519
|
const patch = { diffWordWrap: isOn(value) };
|
|
397
|
-
if (deps.
|
|
398
|
-
else
|
|
520
|
+
if (deps.runtime) deps.runtime.updateContextConfig(patch, ctx);
|
|
521
|
+
else updateContextConfig(patch);
|
|
399
522
|
saveNotice(ctx, "Diff word wrap", value);
|
|
400
523
|
return;
|
|
401
524
|
}
|
|
402
525
|
if (id === "thinkingPreviewLines") {
|
|
403
526
|
const patch = { previewLines: Number(value) };
|
|
404
|
-
if (deps.
|
|
405
|
-
else
|
|
527
|
+
if (deps.runtime) deps.runtime.updateContextConfig(patch, ctx);
|
|
528
|
+
else updateContextConfig(patch);
|
|
406
529
|
saveNotice(ctx, "Thinking preview", value);
|
|
407
530
|
return;
|
|
408
531
|
}
|
|
409
532
|
if (id === "dimThinkingText") {
|
|
410
533
|
const patch = { dimThinkingText: isOn(value) };
|
|
411
|
-
if (deps.
|
|
412
|
-
else
|
|
534
|
+
if (deps.runtime) deps.runtime.updateContextConfig(patch, ctx);
|
|
535
|
+
else updateContextConfig(patch);
|
|
413
536
|
saveNotice(ctx, "Thinking text", value);
|
|
414
537
|
return;
|
|
415
538
|
}
|
|
@@ -421,9 +544,9 @@ function updateSetting(
|
|
|
421
544
|
id === "enableAliases" ||
|
|
422
545
|
id === "showStartupHeader"
|
|
423
546
|
) {
|
|
424
|
-
const patch = { [id]: isOn(value) } as Partial<
|
|
425
|
-
if (deps.
|
|
426
|
-
else
|
|
547
|
+
const patch = { [id]: isOn(value) } as Partial<ContextConfig>;
|
|
548
|
+
if (deps.runtime) deps.runtime.updateContextConfig(patch, ctx);
|
|
549
|
+
else updateContextConfig(patch);
|
|
427
550
|
saveNotice(ctx, id, value);
|
|
428
551
|
return;
|
|
429
552
|
}
|
|
@@ -431,8 +554,8 @@ function updateSetting(
|
|
|
431
554
|
const preset = id.slice("preset:".length);
|
|
432
555
|
if (PRESET_VALUES.includes(preset as Preset)) {
|
|
433
556
|
applyPreset(preset as Preset);
|
|
434
|
-
if (deps.
|
|
435
|
-
deps.
|
|
557
|
+
if (deps.runtime) {
|
|
558
|
+
deps.runtime.setContextMode(
|
|
436
559
|
preset === "compact" ? "compact" : preset === "native" ? "off" : "on",
|
|
437
560
|
ctx,
|
|
438
561
|
);
|
|
@@ -445,8 +568,14 @@ function updateSetting(
|
|
|
445
568
|
|
|
446
569
|
let unifiedPanelOpen = false;
|
|
447
570
|
|
|
571
|
+
/**
|
|
572
|
+
* Opens the unified settings panel as a managed overlay.
|
|
573
|
+
*
|
|
574
|
+
* @param ctx Active TUI extension context.
|
|
575
|
+
* @param deps Runtime controllers used for live updates.
|
|
576
|
+
*/
|
|
448
577
|
export async function showOneUiPanel(
|
|
449
|
-
ctx:
|
|
578
|
+
ctx: ExtensionCommandContext,
|
|
450
579
|
deps: UnifiedPanelDeps = {},
|
|
451
580
|
): Promise<void> {
|
|
452
581
|
if (
|
|
@@ -464,68 +593,111 @@ export async function showOneUiPanel(
|
|
|
464
593
|
|
|
465
594
|
unifiedPanelOpen = true;
|
|
466
595
|
try {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
list
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
596
|
+
let panelHandle: { focus: () => void } | undefined;
|
|
597
|
+
await overlayManager.run(() =>
|
|
598
|
+
ctx.ui.custom(
|
|
599
|
+
(tui, theme, _keybindings, done) => {
|
|
600
|
+
let activeIndex = 0;
|
|
601
|
+
let list: SettingsList;
|
|
602
|
+
const createList = () => {
|
|
603
|
+
list = new SettingsList(
|
|
604
|
+
itemsFor(SECTIONS[activeIndex].id),
|
|
605
|
+
10,
|
|
606
|
+
getSettingsListTheme(),
|
|
607
|
+
(id, value) => {
|
|
608
|
+
// Replacing Pi's editor synchronously moves focus away from
|
|
609
|
+
// this overlay. Restore the overlay handle after the editor
|
|
610
|
+
// has been reconciled so the panel remains interactive.
|
|
611
|
+
if (id === "editorEnabled") {
|
|
612
|
+
try {
|
|
613
|
+
updateSetting(id, value, ctx, deps);
|
|
614
|
+
list.updateValue(id, value);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
ctx.ui?.notify?.(
|
|
617
|
+
`Could not update Editor setting: ${error instanceof Error ? error.message : String(error)}`,
|
|
618
|
+
"error",
|
|
619
|
+
);
|
|
620
|
+
} finally {
|
|
621
|
+
panelHandle?.focus();
|
|
622
|
+
tui.requestRender();
|
|
623
|
+
}
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
updateSetting(id, value, ctx, deps);
|
|
627
|
+
list.updateValue(id, value);
|
|
628
|
+
tui.requestRender();
|
|
629
|
+
},
|
|
630
|
+
() => done(undefined),
|
|
631
|
+
);
|
|
632
|
+
};
|
|
489
633
|
createList();
|
|
490
|
-
tui.requestRender();
|
|
491
|
-
};
|
|
492
634
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
"
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
635
|
+
const switchSection = (delta: number) => {
|
|
636
|
+
activeIndex =
|
|
637
|
+
(activeIndex + delta + SECTIONS.length) % SECTIONS.length;
|
|
638
|
+
createList();
|
|
639
|
+
tui.requestRender();
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
return {
|
|
643
|
+
render: (width: number) => {
|
|
644
|
+
const contentWidth = Math.max(0, width - 2);
|
|
645
|
+
return renderPanelFrame(theme, width, [
|
|
646
|
+
renderTabs(theme, activeIndex, contentWidth),
|
|
647
|
+
theme.fg("dim", "─".repeat(contentWidth)),
|
|
648
|
+
theme.fg(
|
|
649
|
+
"muted",
|
|
650
|
+
` ${sectionDescription(SECTIONS[activeIndex].id)}`,
|
|
651
|
+
),
|
|
652
|
+
"",
|
|
653
|
+
...list.render(contentWidth),
|
|
654
|
+
...(SECTIONS[activeIndex].id === "editor"
|
|
655
|
+
? renderEditorPreview(theme, contentWidth)
|
|
656
|
+
: SECTIONS[activeIndex].id === "context"
|
|
657
|
+
? renderContextPreview(theme, contentWidth)
|
|
658
|
+
: []),
|
|
659
|
+
"",
|
|
660
|
+
truncateToWidth(
|
|
661
|
+
theme.fg(
|
|
662
|
+
"dim",
|
|
663
|
+
" Tab/Shift+Tab switch sections · Enter/Space change · Esc close",
|
|
664
|
+
),
|
|
665
|
+
contentWidth,
|
|
666
|
+
),
|
|
667
|
+
]);
|
|
668
|
+
},
|
|
669
|
+
invalidate: () => list.invalidate(),
|
|
670
|
+
handleInput: (data: string) => {
|
|
671
|
+
if (data === "\x1b[Z" || matchesKey(data, "shift+tab")) {
|
|
672
|
+
switchSection(-1);
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
if (matchesKey(data, "tab")) {
|
|
676
|
+
switchSection(1);
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
list.handleInput(data);
|
|
680
|
+
},
|
|
681
|
+
};
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
overlay: true,
|
|
685
|
+
overlayOptions: {
|
|
686
|
+
anchor: "top-center",
|
|
687
|
+
width: "85%",
|
|
688
|
+
maxHeight: "90%",
|
|
689
|
+
margin: {
|
|
690
|
+
top: 10,
|
|
691
|
+
right: 1,
|
|
692
|
+
bottom: 1,
|
|
693
|
+
left: 1,
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
onHandle: (handle: { focus: () => void }) => {
|
|
697
|
+
panelHandle = handle;
|
|
526
698
|
},
|
|
527
|
-
}
|
|
528
|
-
|
|
699
|
+
},
|
|
700
|
+
),
|
|
529
701
|
);
|
|
530
702
|
} finally {
|
|
531
703
|
unifiedPanelOpen = false;
|