pi-one-ui 0.7.2 → 0.9.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 (45) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/README.en.md +5 -8
  3. package/README.md +6 -7
  4. package/extensions/app/config/footer.ts +21 -5
  5. package/extensions/app/config/renderer.ts +1 -12
  6. package/extensions/app/config/shell.ts +62 -60
  7. package/extensions/app/runtime/prototype-patch-registry.ts +13 -9
  8. package/extensions/app/runtime/tui-runtime.ts +19 -12
  9. package/extensions/app/settings/controller.ts +2 -2
  10. package/extensions/layouts/context/index.ts +2 -2
  11. package/extensions/layouts/context/message/user-message-osc.ts +1 -1
  12. package/extensions/layouts/context/message/user-message-styles.ts +9 -6
  13. package/extensions/layouts/context/message/user-message.ts +5 -5
  14. package/extensions/layouts/context/renderer/compact-mode.ts +2 -2
  15. package/extensions/layouts/context/renderer/default-mode.ts +10 -10
  16. package/extensions/layouts/context/renderer/index.ts +0 -1
  17. package/extensions/layouts/context/renderer/mouse/hover.ts +0 -4
  18. package/extensions/layouts/context/renderer/mouse/interaction.ts +106 -95
  19. package/extensions/layouts/context/renderer/mouse/layout.ts +0 -4
  20. package/extensions/layouts/context/renderer/mouse/scroll.ts +2 -183
  21. package/extensions/layouts/context/renderer/tool/diff/diff-edit-render.ts +1 -1
  22. package/extensions/layouts/context/renderer/tool/diff/index.ts +1 -1
  23. package/extensions/layouts/context/renderer/tool/grouping.ts +3 -3
  24. package/extensions/layouts/context/renderer/tool/message-display.ts +7 -7
  25. package/extensions/layouts/context/renderer/tool/result.ts +16 -16
  26. package/extensions/layouts/context/renderer/tool/toggle-render-cache.ts +9 -9
  27. package/extensions/layouts/editor/controller.ts +17 -17
  28. package/extensions/layouts/editor/editor-metadata-format.ts +5 -5
  29. package/extensions/layouts/editor/factory.ts +5 -5
  30. package/extensions/layouts/editor/minimalist-editor.ts +8 -8
  31. package/extensions/layouts/editor/ownership.ts +24 -20
  32. package/extensions/layouts/editor/ui.ts +10 -15
  33. package/extensions/layouts/footer/controller.ts +4 -4
  34. package/extensions/layouts/footer/data.ts +2 -2
  35. package/extensions/layouts/footer/extension-status.ts +4 -4
  36. package/extensions/layouts/footer/footer.ts +5 -2
  37. package/extensions/layouts/overlay/selector-border.ts +4 -4
  38. package/extensions/layouts/overlay/selector-controller.ts +1 -1
  39. package/extensions/layouts/overlay/settings-previews.ts +2 -2
  40. package/extensions/layouts/working-line/interaction-summary.ts +3 -1
  41. package/extensions/layouts/working-line/working-line.ts +4 -4
  42. package/extensions/services/package-data.ts +1 -1
  43. package/extensions/shared/style.ts +66 -56
  44. package/extensions/tools/patch-keys.ts +22 -25
  45. package/package.json +7 -7
@@ -1,5 +1,9 @@
1
- export const ZENTUI_PROTOTYPE_PATCH_REGISTRY = Symbol.for(
2
- "pi-zentui.prototype-patch-registry",
1
+ /**
2
+ * Global registry slot for prototype patches. The key is only shared by module
3
+ * instances of the same process, so it has to stay stable across `/reload`.
4
+ */
5
+ export const POLISHED_PROTOTYPE_PATCH_REGISTRY = Symbol.for(
6
+ "pi-one-ui.prototype-patch-registry",
3
7
  );
4
8
 
5
9
  type PrototypePatchAdapter =
@@ -35,7 +39,7 @@ type PatchRegistry = Map<PrototypePatchAdapter, PatchRecord>;
35
39
  type PatchTarget = Record<PropertyKey, unknown>;
36
40
 
37
41
  function existingRegistry(target: PatchTarget): PatchRegistry | undefined {
38
- const existing = target[ZENTUI_PROTOTYPE_PATCH_REGISTRY];
42
+ const existing = target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
39
43
  return existing instanceof Map ? (existing as PatchRegistry) : undefined;
40
44
  }
41
45
 
@@ -43,7 +47,7 @@ function registryFor(target: PatchTarget): PatchRegistry {
43
47
  const existing = existingRegistry(target);
44
48
  if (existing) return existing;
45
49
  const registry: PatchRegistry = new Map();
46
- Object.defineProperty(target, ZENTUI_PROTOTYPE_PATCH_REGISTRY, {
50
+ Object.defineProperty(target, POLISHED_PROTOTYPE_PATCH_REGISTRY, {
47
51
  value: registry,
48
52
  configurable: true,
49
53
  });
@@ -100,7 +104,7 @@ function createCleanup(
100
104
  if (current !== record) return;
101
105
  restorePredecessor(target, record);
102
106
  registry.delete(adapter);
103
- if (registry.size === 0) delete target[ZENTUI_PROTOTYPE_PATCH_REGISTRY];
107
+ if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
104
108
  };
105
109
  }
106
110
 
@@ -124,7 +128,7 @@ export function installPrototypePatch(
124
128
  );
125
129
  const predecessor = target[method];
126
130
  if (typeof predecessor !== "function") {
127
- if (registry.size === 0) delete target[ZENTUI_PROTOTYPE_PATCH_REGISTRY];
131
+ if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
128
132
  throw new TypeError(
129
133
  `Cannot patch ${method}: predecessor is not a function`,
130
134
  );
@@ -135,7 +139,7 @@ export function installPrototypePatch(
135
139
  predecessorDescriptor,
136
140
  wrapper: () => undefined,
137
141
  };
138
- const wrapper: PrototypeMethod = function zentuiPrototypeWrapper(
142
+ const wrapper: PrototypeMethod = function polishedPrototypeWrapper(
139
143
  this: unknown,
140
144
  ...args: unknown[]
141
145
  ): unknown {
@@ -152,7 +156,7 @@ export function installPrototypePatch(
152
156
  try {
153
157
  installWrapper(target, nextRecord);
154
158
  } catch (error) {
155
- if (registry.size === 0) delete target[ZENTUI_PROTOTYPE_PATCH_REGISTRY];
159
+ if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
156
160
  throw error;
157
161
  }
158
162
  record = nextRecord;
@@ -179,5 +183,5 @@ export function removePrototypePatch(
179
183
  deactivateRecord(record);
180
184
  restorePredecessor(target, record);
181
185
  registry.delete(adapter);
182
- if (registry.size === 0) delete target[ZENTUI_PROTOTYPE_PATCH_REGISTRY];
186
+ if (registry.size === 0) delete target[POLISHED_PROTOTYPE_PATCH_REGISTRY];
183
187
  }
@@ -20,6 +20,7 @@ import registerHeader, {
20
20
  import { SelectorController } from "../../layouts/overlay/selector-controller.ts";
21
21
  import { WorkingLineLayoutController } from "../../layouts/working-line/controller.ts";
22
22
  import {
23
+ LEGACY_TURN_SUMMARY_ENTRY_TYPE,
23
24
  renderTurnSummaryEntry,
24
25
  TURN_SUMMARY_ENTRY_TYPE,
25
26
  } from "../../layouts/working-line/interaction-summary.ts";
@@ -192,18 +193,24 @@ export function createLayoutRuntime(
192
193
  });
193
194
  const state = sessionState.state;
194
195
  if (typeof pi.registerEntryRenderer === "function") {
195
- pi.registerEntryRenderer(
196
- TURN_SUMMARY_ENTRY_TYPE,
197
- (entry, entryOptions, theme) =>
198
- renderTurnSummaryEntry(
199
- entry,
200
- {
201
- ...entryOptions,
202
- workingLineHigh: currentConfig.colors.workingLineHigh,
203
- },
204
- theme,
205
- ),
206
- );
196
+ const renderTurnSummary = (
197
+ entry: { data?: unknown },
198
+ entryOptions: unknown,
199
+ theme: Parameters<typeof renderTurnSummaryEntry>[2],
200
+ ) => {
201
+ const options = (entryOptions ?? {}) as Record<string, unknown>;
202
+ return renderTurnSummaryEntry(
203
+ entry,
204
+ {
205
+ ...options,
206
+ workingLineHigh: currentConfig.colors.workingLineHigh,
207
+ },
208
+ theme,
209
+ );
210
+ };
211
+ pi.registerEntryRenderer(TURN_SUMMARY_ENTRY_TYPE, renderTurnSummary);
212
+ // 旧 session 的摘要条目继续可渲染。
213
+ pi.registerEntryRenderer(LEGACY_TURN_SUMMARY_ENTRY_TYPE, renderTurnSummary);
207
214
  }
208
215
  const refresh = (): void => {
209
216
  if (sessionLifecycle.isCurrent()) {
@@ -6,7 +6,7 @@ import { type Config, normalizeConfig } from "../config/renderer.ts";
6
6
  import {
7
7
  mergeConfig,
8
8
  mutateComponentsRecord,
9
- type ZentuiConfig,
9
+ type PolishedTuiConfig,
10
10
  } from "../config/shell.ts";
11
11
  import {
12
12
  type ConfigRecord,
@@ -19,7 +19,7 @@ import { applyPresetRecord, isPreset } from "./presets.ts";
19
19
  export type SettingsChange = Readonly<{ id: string; value: string }>;
20
20
 
21
21
  export type SettingsSnapshot = Readonly<{
22
- shell: ZentuiConfig;
22
+ shell: PolishedTuiConfig;
23
23
  renderer: Config;
24
24
  panel: PanelOverlayConfig;
25
25
  }>;
@@ -6,7 +6,7 @@ import type {
6
6
  import { type Config, config } from "../../app/config/renderer.ts";
7
7
  import {
8
8
  hasUnsupportedComponentStyle,
9
- type ZentuiConfig,
9
+ type PolishedTuiConfig,
10
10
  } from "../../app/config/shell.ts";
11
11
  import { installUserMessageStyle } from "./message/user-message.ts";
12
12
  import registerContextRenderer, {
@@ -22,7 +22,7 @@ export type ContextRuntimeController = RendererRuntimeController & {
22
22
  applyConfig(ctx: ExtensionContext, previous: Config): void;
23
23
  };
24
24
  export type ContextExtensionOptions = {
25
- readonly getConfig: () => ZentuiConfig;
25
+ readonly getConfig: () => PolishedTuiConfig;
26
26
  readonly services?: RendererExtensionOptions["services"];
27
27
  };
28
28
 
@@ -192,7 +192,7 @@ function filterUserMessageTerminalText(
192
192
  }
193
193
 
194
194
  // Removing an unterminated introducer prevents it from consuming
195
- // Zentui's prompt markers. Preserve visible trailing payload, except
195
+ // pi-one-ui's prompt markers. Preserve visible trailing payload, except
196
196
  // for a recognized partial OSC 133 command prefix.
197
197
  const payloadEnd = boundary?.index ?? text.length;
198
198
  const payload = text.slice(payloadStart, payloadEnd);
@@ -5,7 +5,7 @@ import {
5
5
  truncateToWidth,
6
6
  visibleWidth,
7
7
  } from "@earendil-works/pi-tui";
8
- import type { ZentuiConfig } from "../../../app/config/shell.ts";
8
+ import type { PolishedTuiConfig } from "../../../app/config/shell.ts";
9
9
  import {
10
10
  EDITOR_ACCENT_FALLBACK,
11
11
  EDITOR_BORDER_FALLBACK,
@@ -17,7 +17,7 @@ export type UserMessageStyleRenderInput = {
17
17
  text: string;
18
18
  width: number;
19
19
  theme?: Theme;
20
- config: ZentuiConfig;
20
+ config: PolishedTuiConfig;
21
21
  };
22
22
 
23
23
  function themeFg(
@@ -70,7 +70,7 @@ function fillLine(content: string, width: number): string {
70
70
 
71
71
  function accent(
72
72
  theme: Theme | undefined,
73
- config: ZentuiConfig,
73
+ config: PolishedTuiConfig,
74
74
  text: string,
75
75
  ): string {
76
76
  return theme
@@ -85,7 +85,7 @@ function accent(
85
85
 
86
86
  function border(
87
87
  theme: Theme | undefined,
88
- config: ZentuiConfig,
88
+ config: PolishedTuiConfig,
89
89
  text: string,
90
90
  ): string {
91
91
  return theme
@@ -98,7 +98,10 @@ function border(
98
98
  : text;
99
99
  }
100
100
 
101
- function renderRail(theme: Theme | undefined, config: ZentuiConfig): string {
101
+ function renderRail(
102
+ theme: Theme | undefined,
103
+ config: PolishedTuiConfig,
104
+ ): string {
102
105
  return `${accent(theme, config, config.icons.rail)} `;
103
106
  }
104
107
 
@@ -202,7 +205,7 @@ function renderLabeled({
202
205
  return [top, ...body.map(side), bottom];
203
206
  }
204
207
 
205
- export function userMessageStyleCacheKey(config: ZentuiConfig): string {
208
+ export function userMessageStyleCacheKey(config: PolishedTuiConfig): string {
206
209
  const messages = config.components.userMessages;
207
210
  switch (messages.style) {
208
211
  case "framed":
@@ -3,7 +3,7 @@ import {
3
3
  UserMessageComponent,
4
4
  } from "@earendil-works/pi-coding-agent";
5
5
  import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
6
- import type { ZentuiConfig } from "../../../app/config/shell.ts";
6
+ import type { PolishedTuiConfig } from "../../../app/config/shell.ts";
7
7
  import {
8
8
  installPrototypePatch,
9
9
  removePrototypePatch,
@@ -79,11 +79,11 @@ function getCachedMarkdownText(instance: object): string | undefined {
79
79
  return text;
80
80
  }
81
81
 
82
- function renderZentuiUserMessage(
82
+ function renderPolishedUserMessage(
83
83
  instance: PatchableUserMessagePrototype,
84
84
  width: number,
85
85
  theme: Theme | undefined,
86
- config: ZentuiConfig,
86
+ config: PolishedTuiConfig,
87
87
  ): string[] | undefined {
88
88
  if (!isRecord(instance)) return undefined;
89
89
 
@@ -171,7 +171,7 @@ export function removeUserMessageStyle(): void {
171
171
 
172
172
  export function installUserMessageStyle(
173
173
  getTheme: () => Theme | undefined,
174
- getConfig: () => ZentuiConfig,
174
+ getConfig: () => PolishedTuiConfig,
175
175
  ): Cleanup {
176
176
  const prototype = UserMessageComponent.prototype;
177
177
  const cleanupInvalidate = installPrototypePatch(
@@ -195,7 +195,7 @@ export function installUserMessageStyle(
195
195
  const width = args[0];
196
196
  if (typeof width !== "number") return renderPredecessor();
197
197
  try {
198
- const lines = renderZentuiUserMessage(
198
+ const lines = renderPolishedUserMessage(
199
199
  receiver as PatchableUserMessagePrototype,
200
200
  width,
201
201
  getTheme(),
@@ -690,7 +690,7 @@ function compactEditWriteLines(
690
690
  outputText,
691
691
  theme,
692
692
  isError,
693
- state.ccstyleIoView,
693
+ state.oneuiIoView,
694
694
  component.args,
695
695
  component,
696
696
  true, // 外层 Box(1,1) 已 pad
@@ -1380,7 +1380,7 @@ export function installCompactMode(
1380
1380
  uiRef = ctx?.ui;
1381
1381
  resetRounds();
1382
1382
  // 始终保持补丁在链上:mode=on/off 走 passThrough,仍写入 lastMessage
1383
- // 与 tracked 集合,这样 /ccstyle 切回 compact 时不必 /reload。
1383
+ // 与 tracked 集合,这样 /oneui 切回 compact 时不必 /reload。
1384
1384
  patch.assertAssistantOwnership();
1385
1385
  if (config.mode === "compact") syncGlobalExpanded(ctx);
1386
1386
  else hoveredAssistantComponent = undefined;
@@ -236,8 +236,8 @@ function renderExpandedTaskResult(
236
236
  return formatted ? new Text(`↳ ${formatted}`, 0, 0) : undefined;
237
237
  }
238
238
 
239
- /** 用 ccstyle call/result 包装任意工具定义。 */
240
- function createCcstyleTool(
239
+ /** 用 pi-one-ui call/result 包装任意工具定义。 */
240
+ function createPolishedTool(
241
241
  originalTool: any,
242
242
  writeExecutionMetadata: WriteExecutionMetadataStore,
243
243
  ): any {
@@ -400,7 +400,7 @@ function createCcstyleTool(
400
400
  true, // mode=on:贴左,由外层 Box(1,1) 提供 1 格 padding
401
401
  );
402
402
  }
403
- if (context?.state) context.state.ccstyleIoView = undefined;
403
+ if (context?.state) context.state.oneuiIoView = undefined;
404
404
  let cachedWidth: number | undefined;
405
405
  let cachedLine: string | undefined;
406
406
  let cachedHoveredLine: string | undefined;
@@ -425,7 +425,7 @@ function createCcstyleTool(
425
425
  cachedWidth = undefined;
426
426
  cachedLine = undefined;
427
427
  cachedHoveredLine = undefined;
428
- context?.state?.ccstyleExpandedIoView?.invalidate?.();
428
+ context?.state?.oneuiExpandedIoView?.invalidate?.();
429
429
  },
430
430
  };
431
431
  },
@@ -465,7 +465,7 @@ function shouldGloballyStyleTool(
465
465
  const builtInDefinition = component.builtInToolDefinition;
466
466
  const definition = extensionDefinition ?? builtInDefinition;
467
467
  const toolName = String(component.toolName || definition?.name || "");
468
- const useCcstyle =
468
+ const usePolishedToolStyle =
469
469
  patch.mode() === "on" &&
470
470
  !DEDICATED_RENDERER_TOOLS.has(toolName) &&
471
471
  !preservesOriginalRenderer(
@@ -473,8 +473,8 @@ function shouldGloballyStyleTool(
473
473
  toolName,
474
474
  builtInDefinition,
475
475
  );
476
- component[COMPONENT_TOOL_RENDER_MODE] = useCcstyle;
477
- return useCcstyle;
476
+ component[COMPONENT_TOOL_RENDER_MODE] = usePolishedToolStyle;
477
+ return usePolishedToolStyle;
478
478
  }
479
479
 
480
480
  function getGloballyStyledTool(
@@ -607,7 +607,7 @@ function installGlobalToolRendering(
607
607
  active: true,
608
608
  enabled: () => config.mode === "on",
609
609
  mode: () => config.mode,
610
- wrap: (tool: any) => createCcstyleTool(tool, writeExecutionMetadata),
610
+ wrap: (tool: any) => createPolishedTool(tool, writeExecutionMetadata),
611
611
  byDefinition: new WeakMap(),
612
612
  byName: new Map(),
613
613
  downstream,
@@ -626,8 +626,8 @@ function installGlobalToolRendering(
626
626
  getRenderShell: function (this: any, ...args: any[]) {
627
627
  if (!patch.active)
628
628
  return patch.downstream.getRenderShell.apply(this, args);
629
- const useCcstyle = shouldGloballyStyleTool(this, patch);
630
- const shell = useCcstyle
629
+ const usePolishedToolStyle = shouldGloballyStyleTool(this, patch);
630
+ const shell = usePolishedToolStyle
631
631
  ? this.expanded
632
632
  ? "default"
633
633
  : "self"
@@ -243,7 +243,6 @@ export default function (
243
243
  hooks.toolGrouping.setTheme(ctx.ui.theme);
244
244
  hooks.toggleRenderCache.setTheme(ctx.ui.theme);
245
245
  setMessageDisplayTheme(ctx.ui.theme);
246
- ctx.ui.setStatus("ccstyle", undefined);
247
246
  // Collect the resumed context before syncing compact patches and expansion state.
248
247
  syncCompactMode(ctx);
249
248
  // compact-thinking 的 session_start 处理在本 handler 之后执行(在其之上再装
@@ -12,7 +12,6 @@ import {
12
12
  type ToolIoSection,
13
13
  } from "../tool/result.ts";
14
14
  import { type ComponentRowHit, componentAtLocalRow } from "./layout.ts";
15
- import { setScrollButtonHovered } from "./scroll.ts";
16
15
 
17
16
  type SharedToolHoverState = { toolCallId: string | null };
18
17
 
@@ -132,7 +131,6 @@ export function cachedFullscreenComponentAtRow(
132
131
 
133
132
  /** fullscreen 鼠标悬停目标。 */
134
133
  export type FullscreenHoverTarget =
135
- | { kind: "button" }
136
134
  | { kind: "group"; component: ToolGroupComponent }
137
135
  | { kind: "thinking"; component: ThinkingPreviewBlock }
138
136
  | { kind: "message"; component: any }
@@ -169,7 +167,5 @@ export function applyFullscreenHover(
169
167
  const nextView = target?.kind === "tool" ? target.view : null;
170
168
  const nextSection = target?.kind === "tool" ? target.section : null;
171
169
  if (setHoveredToolIo(nextView, nextSection)) changed = true;
172
- const nextButton = target?.kind === "button";
173
- if (setScrollButtonHovered(nextButton)) changed = true;
174
170
  if (changed) tui.requestRender?.();
175
171
  }