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