@herbertgao/pi-extensions 2026.9.19 → 2026.9.20

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 (186) hide show
  1. package/README.md +1 -8
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +76 -59
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +76 -59
  4. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/preview.webp +0 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +93 -34
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +346 -117
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +6 -36
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/index.ts +2 -2
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -29
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +330 -360
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/index.ts +56 -108
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/session.ts +97 -15
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/subagent.ts +80 -45
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/flush-docked-bash.ts +36 -0
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer-layout.ts +229 -0
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +479 -0
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/startup-header.ts +92 -61
  18. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/working-message.ts +58 -38
  19. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +19 -3
  20. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +1080 -229
  21. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +232 -259
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +38 -48
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +8 -2
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +2 -7
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +277 -113
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +15 -6
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +18 -72
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +61 -26
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts +25 -57
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-component.ts +125 -0
  31. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-edit-render.ts +227 -0
  32. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +136 -0
  33. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +115 -0
  34. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-inline.ts +324 -0
  35. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-layout.ts +762 -0
  36. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-limits.ts +152 -0
  37. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-palette.ts +410 -0
  38. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-parse.ts +535 -0
  39. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
  40. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +21 -3219
  41. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-text.ts +44 -0
  42. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +568 -0
  43. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +19 -18
  44. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +2 -2
  45. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -0
  46. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +142 -192
  47. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/mcp-title.ts +39 -0
  48. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{message-display.ts → tool/message-display.ts} +24 -90
  49. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +426 -0
  50. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +90 -132
  51. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{show-more-hint.ts → tool/show-more-hint.ts} +10 -0
  52. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +8 -26
  53. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-color.ts +44 -0
  54. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +76 -0
  55. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/component-tree.ts +34 -0
  56. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/format.ts +28 -0
  57. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +51 -0
  58. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/patch-keys.ts +124 -0
  59. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/sgr-mouse.ts +70 -0
  60. package/node_modules/@herbertgao/pi-cc-extensions/package.json +7 -7
  61. package/package.json +3 -7
  62. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +0 -101
  63. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.svg +0 -101
  64. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/welcome.webp +0 -0
  65. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/render-utils.ts +0 -5
  66. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +0 -30
  67. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +0 -12
  68. package/node_modules/pi-footer/CHANGELOG.md +0 -145
  69. package/node_modules/pi-footer/LICENSE +0 -21
  70. package/node_modules/pi-footer/README.md +0 -354
  71. package/node_modules/pi-footer/package.json +0 -68
  72. package/node_modules/pi-footer/src/cache.ts +0 -106
  73. package/node_modules/pi-footer/src/colors.ts +0 -237
  74. package/node_modules/pi-footer/src/config.ts +0 -202
  75. package/node_modules/pi-footer/src/event-widgets.ts +0 -41
  76. package/node_modules/pi-footer/src/extension-statuses.ts +0 -102
  77. package/node_modules/pi-footer/src/git.ts +0 -135
  78. package/node_modules/pi-footer/src/index.ts +0 -268
  79. package/node_modules/pi-footer/src/metrics.ts +0 -141
  80. package/node_modules/pi-footer/src/presets.ts +0 -383
  81. package/node_modules/pi-footer/src/render.ts +0 -114
  82. package/node_modules/pi-footer/src/separators.ts +0 -52
  83. package/node_modules/pi-footer/src/types.ts +0 -122
  84. package/node_modules/pi-footer/src/ui/color-level-confirm.ts +0 -22
  85. package/node_modules/pi-footer/src/ui/color-options.ts +0 -195
  86. package/node_modules/pi-footer/src/ui/config-lifecycle.ts +0 -61
  87. package/node_modules/pi-footer/src/ui/edit-colors.ts +0 -13
  88. package/node_modules/pi-footer/src/ui/events.ts +0 -35
  89. package/node_modules/pi-footer/src/ui/extension-status-picker.ts +0 -60
  90. package/node_modules/pi-footer/src/ui/extension-statuses.ts +0 -73
  91. package/node_modules/pi-footer/src/ui/fields.ts +0 -252
  92. package/node_modules/pi-footer/src/ui/global-menu.ts +0 -126
  93. package/node_modules/pi-footer/src/ui/helpers.ts +0 -44
  94. package/node_modules/pi-footer/src/ui/layout.ts +0 -17
  95. package/node_modules/pi-footer/src/ui/line-list.ts +0 -19
  96. package/node_modules/pi-footer/src/ui/model.ts +0 -64
  97. package/node_modules/pi-footer/src/ui/navigation.ts +0 -29
  98. package/node_modules/pi-footer/src/ui/option-edit.ts +0 -93
  99. package/node_modules/pi-footer/src/ui/overlay-render.ts +0 -103
  100. package/node_modules/pi-footer/src/ui/screen-context.ts +0 -18
  101. package/node_modules/pi-footer/src/ui/screen-controller.ts +0 -27
  102. package/node_modules/pi-footer/src/ui/screen-render.ts +0 -32
  103. package/node_modules/pi-footer/src/ui/screen-state.ts +0 -20
  104. package/node_modules/pi-footer/src/ui/screen.ts +0 -243
  105. package/node_modules/pi-footer/src/ui/screens/add-widget.ts +0 -92
  106. package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +0 -52
  107. package/node_modules/pi-footer/src/ui/screens/controller.ts +0 -12
  108. package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +0 -68
  109. package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +0 -115
  110. package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +0 -61
  111. package/node_modules/pi-footer/src/ui/screens/global.ts +0 -75
  112. package/node_modules/pi-footer/src/ui/screens/line-list.ts +0 -108
  113. package/node_modules/pi-footer/src/ui/screens/main.ts +0 -99
  114. package/node_modules/pi-footer/src/ui/screens/terminal.ts +0 -121
  115. package/node_modules/pi-footer/src/ui/screens/widget-list.ts +0 -154
  116. package/node_modules/pi-footer/src/ui/terminal-menu.ts +0 -32
  117. package/node_modules/pi-footer/src/ui/theme.ts +0 -48
  118. package/node_modules/pi-footer/src/ui/title-bar.ts +0 -100
  119. package/node_modules/pi-footer/src/ui/widget-actions.ts +0 -76
  120. package/node_modules/pi-footer/src/ui.ts +0 -66
  121. package/node_modules/pi-footer/src/widgets/context.ts +0 -28
  122. package/node_modules/pi-footer/src/widgets/core/active-tools.ts +0 -17
  123. package/node_modules/pi-footer/src/widgets/core/context-window.ts +0 -24
  124. package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +0 -19
  125. package/node_modules/pi-footer/src/widgets/core/cwd.ts +0 -108
  126. package/node_modules/pi-footer/src/widgets/core/event.ts +0 -34
  127. package/node_modules/pi-footer/src/widgets/core/external-status.ts +0 -102
  128. package/node_modules/pi-footer/src/widgets/core/model-provider.ts +0 -20
  129. package/node_modules/pi-footer/src/widgets/core/model.ts +0 -35
  130. package/node_modules/pi-footer/src/widgets/core/provider.ts +0 -17
  131. package/node_modules/pi-footer/src/widgets/core/session-name.ts +0 -17
  132. package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +0 -17
  133. package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +0 -17
  134. package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +0 -17
  135. package/node_modules/pi-footer/src/widgets/git/branch.ts +0 -81
  136. package/node_modules/pi-footer/src/widgets/git/clean.ts +0 -19
  137. package/node_modules/pi-footer/src/widgets/git/deletions.ts +0 -17
  138. package/node_modules/pi-footer/src/widgets/git/diff.ts +0 -38
  139. package/node_modules/pi-footer/src/widgets/git/insertions.ts +0 -17
  140. package/node_modules/pi-footer/src/widgets/git/remote.ts +0 -17
  141. package/node_modules/pi-footer/src/widgets/git/root.ts +0 -17
  142. package/node_modules/pi-footer/src/widgets/git/sha.ts +0 -17
  143. package/node_modules/pi-footer/src/widgets/git/staged.ts +0 -17
  144. package/node_modules/pi-footer/src/widgets/git/status.ts +0 -19
  145. package/node_modules/pi-footer/src/widgets/git/unstaged.ts +0 -17
  146. package/node_modules/pi-footer/src/widgets/git/untracked.ts +0 -17
  147. package/node_modules/pi-footer/src/widgets/instance.ts +0 -118
  148. package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +0 -18
  149. package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +0 -32
  150. package/node_modules/pi-footer/src/widgets/layout/separator.ts +0 -57
  151. package/node_modules/pi-footer/src/widgets/layout/spacer.ts +0 -31
  152. package/node_modules/pi-footer/src/widgets/options.ts +0 -122
  153. package/node_modules/pi-footer/src/widgets/project/runtime.ts +0 -361
  154. package/node_modules/pi-footer/src/widgets/registry.ts +0 -223
  155. package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +0 -17
  156. package/node_modules/pi-footer/src/widgets/session/compactions.ts +0 -17
  157. package/node_modules/pi-footer/src/widgets/session/elapsed.ts +0 -18
  158. package/node_modules/pi-footer/src/widgets/session/last-activity.ts +0 -18
  159. package/node_modules/pi-footer/src/widgets/session/messages.ts +0 -19
  160. package/node_modules/pi-footer/src/widgets/session/session-id.ts +0 -17
  161. package/node_modules/pi-footer/src/widgets/session/session-start.ts +0 -18
  162. package/node_modules/pi-footer/src/widgets/session/tool-results.ts +0 -17
  163. package/node_modules/pi-footer/src/widgets/session/total-messages.ts +0 -19
  164. package/node_modules/pi-footer/src/widgets/session/total-time.ts +0 -18
  165. package/node_modules/pi-footer/src/widgets/session/user-messages.ts +0 -17
  166. package/node_modules/pi-footer/src/widgets/store.ts +0 -26
  167. package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +0 -55
  168. package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +0 -18
  169. package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +0 -18
  170. package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +0 -108
  171. package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +0 -26
  172. package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +0 -29
  173. package/node_modules/pi-footer/src/widgets/tokens/context.ts +0 -29
  174. package/node_modules/pi-footer/src/widgets/tokens/cost.ts +0 -51
  175. package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +0 -25
  176. package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +0 -18
  177. package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +0 -25
  178. package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +0 -18
  179. package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +0 -20
  180. package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +0 -25
  181. package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +0 -18
  182. package/node_modules/pi-footer/src/widgets/types.ts +0 -181
  183. package/node_modules/pi-footer/src/widgets/utils/colors.ts +0 -11
  184. package/node_modules/pi-footer/src/widgets/utils/context.ts +0 -112
  185. package/node_modules/pi-footer/src/widgets/utils/session.ts +0 -19
  186. package/node_modules/pi-footer/src/widgets/utils/token-format.ts +0 -78
@@ -1,16 +1,48 @@
1
1
  import type { CompactThinkingConfig } from "../feature/compact-thinking.ts";
2
2
  import {
3
- DEFAULT_TOOL_DISPLAY_CONFIG,
4
- type DiffIndicatorMode,
5
- type DiffViewMode,
6
- type ToolDisplayConfig,
7
- } from "../renderer/tool/diff/index.ts";
8
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ DEFAULT_FOOTER_CHIP_LAYOUT,
4
+ formatFooterChipSummary,
5
+ normalizeFooterChipLayout,
6
+ } from "../feature/shell/footer-layout.ts";
7
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
9
8
  import { homedir } from "node:os";
10
9
  import { join } from "node:path";
11
10
 
12
11
  export type CompactStyleMode = "on" | "compact" | "off";
13
12
 
13
+ export type DiffViewMode = "auto" | "split" | "unified";
14
+ export type DiffIndicatorMode = "bars" | "classic" | "none";
15
+
16
+ export interface ToolDisplayConfig {
17
+ diffViewMode: DiffViewMode;
18
+ diffIndicatorMode: DiffIndicatorMode;
19
+ diffSplitMinWidth: number;
20
+ editDiffCollapsedLines: number;
21
+ /** Write-only collapsed body lines. 0 = `↳ created • click to show more`. */
22
+ writeDiffCollapsedLines: number;
23
+ diffWordWrap: boolean;
24
+ expandedPreviewMaxLines: number;
25
+ }
26
+
27
+ export const DEFAULT_TOOL_DISPLAY_CONFIG: ToolDisplayConfig = {
28
+ diffViewMode: "auto",
29
+ diffIndicatorMode: "bars",
30
+ diffSplitMinWidth: 120,
31
+ /** Collapsed edit/diff body: ~half a typical terminal after chrome. */
32
+ editDiffCollapsedLines: 24,
33
+ /**
34
+ * Write create/overwrite collapsed body.
35
+ * 0 = `↳ created • click to show more` (stats stay on the title).
36
+ */
37
+ writeDiffCollapsedLines: 0,
38
+ diffWordWrap: true,
39
+ /**
40
+ * Expanded TaskList body cap. Tool Input/Output and diffs use their own settings;
41
+ * an expanded diff always renders every line.
42
+ */
43
+ expandedPreviewMaxLines: 40,
44
+ };
45
+
14
46
  export type Config = {
15
47
  mode: CompactStyleMode;
16
48
  excludeRenderers: string[];
@@ -23,6 +55,7 @@ export type Config = {
23
55
  expandedPreviewMaxLines: number;
24
56
  expandedInputMaxLines: number;
25
57
  expandedOutputMaxLines: number;
58
+ inputClip: number;
26
59
  useSummaryTitlesAsThinkingTitle: boolean;
27
60
  previewLines: number;
28
61
  animationIntervalMs: number;
@@ -35,10 +68,17 @@ export type Config = {
35
68
  enableAgentSummary: boolean;
36
69
  enableWorkingMessage: boolean;
37
70
  enableAliases: boolean;
71
+ enableCustomFooter: boolean;
72
+ footerNerdIcons: boolean;
73
+ footerHiddenKeys: string[];
74
+ footerLine1Keys: string[];
75
+ footerLine2Keys: string[];
76
+ footerLine3Keys: string[];
38
77
  };
39
78
 
40
79
  const AGENT_DIR = process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent");
41
- const CONFIG_PATH = join(AGENT_DIR, "claude-code-style.json");
80
+ export const CONFIG_PATH = join(AGENT_DIR, "pi-cc-extensions.json");
81
+ const LEGACY_CONFIG_PATH = join(AGENT_DIR, "claude-code-style.json");
42
82
 
43
83
  export const DIFF_VIEW_MODES: DiffViewMode[] = ["auto", "split", "unified"];
44
84
  export const DIFF_INDICATOR_MODES: DiffIndicatorMode[] = ["bars", "classic", "none"];
@@ -48,8 +88,12 @@ export const DIFF_COLLAPSED_LINES_VALUES = ["12", "24", "36", "48", "80", "120"]
48
88
  export const WRITE_DIFF_COLLAPSED_LINES_VALUES = ["0", "4", "8", "12", "24", "36"];
49
89
  /** Presets for expanded body height — keep low options first so cycling stays TUI-friendly. */
50
90
  export const EXPANDED_PREVIEW_MAX_LINES_VALUES = ["40", "60", "80", "120", "200", "500", "2000"];
91
+ /** 展开工具卡 Input 可见行数预设。 */
51
92
  export const EXPANDED_INPUT_MAX_LINES_VALUES = ["5", "10", "20", "40", "80"];
93
+ /** 展开工具卡 Output 可见行数预设。 */
52
94
  export const EXPANDED_OUTPUT_MAX_LINES_VALUES = ["10", "20", "40", "80", "120"];
95
+ /** 工具摘要里 path/command 等输入的折叠字符数;0 = 只按可用宽度截断。 */
96
+ export const INPUT_CLIP_VALUES = ["0", "40", "60", "80", "100", "120", "160"];
53
97
  export const THINKING_PREVIEW_LINES_VALUES = ["0", "1", "3", "5", "10"];
54
98
  export const THINKING_ANIMATION_INTERVAL_VALUES = ["40", "60", "90", "120", "180"];
55
99
  /** fullscreen 滚轮步进行数预设。 */
@@ -57,6 +101,7 @@ export const SCROLL_STEP_LINES_VALUES = ["1", "2", "3", "5", "10"];
57
101
  /** Tools commonly toggled in excludeRenderers via the settings panel. */
58
102
  export const EXCLUDE_RENDERER_CANDIDATES = [
59
103
  "bash",
104
+ "powershell",
60
105
  "read",
61
106
  "edit",
62
107
  "write",
@@ -79,6 +124,7 @@ export const DEFAULT_CONFIG: Config = {
79
124
  expandedPreviewMaxLines: DEFAULT_TOOL_DISPLAY_CONFIG.expandedPreviewMaxLines,
80
125
  expandedInputMaxLines: 5,
81
126
  expandedOutputMaxLines: 10,
127
+ inputClip: 0,
82
128
  useSummaryTitlesAsThinkingTitle: true,
83
129
  previewLines: 3,
84
130
  animationIntervalMs: 90,
@@ -91,6 +137,9 @@ export const DEFAULT_CONFIG: Config = {
91
137
  enableAgentSummary: true,
92
138
  enableWorkingMessage: true,
93
139
  enableAliases: true,
140
+ enableCustomFooter: true,
141
+ footerNerdIcons: true,
142
+ ...DEFAULT_FOOTER_CHIP_LAYOUT,
94
143
  };
95
144
 
96
145
  function pickEnum<T extends string>(value: unknown, allowed: readonly T[], fallback: T): T {
@@ -105,6 +154,12 @@ export function pickPositiveInt(value: unknown, fallback: number, min = 1, max =
105
154
  return Math.min(max, Math.max(min, Math.floor(n)));
106
155
  }
107
156
 
157
+ /** inputClip:0 表示按宽度自适应,其余夹到 8..500。 */
158
+ export function pickInputClip(value: unknown): number {
159
+ const n = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
160
+ return n === 0 ? 0 : pickPositiveInt(value, DEFAULT_CONFIG.inputClip, 8, 500);
161
+ }
162
+
108
163
  export function pickPositiveNumber(value: unknown, fallback: number, min = 1): number {
109
164
  const n = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
110
165
  return Number.isFinite(n) ? Math.max(min, n) : fallback;
@@ -112,16 +167,7 @@ export function pickPositiveNumber(value: unknown, fallback: number, min = 1): n
112
167
 
113
168
  export function normalizeConfig(input: unknown): Config {
114
169
  const source = (input && typeof input === "object" ? input : {}) as Record<string, unknown>;
115
- const mode = source.mode;
116
- // 旧 `enabled: boolean` 配置迁移;compact 已恢复为受支持模式,不再回退 on。
117
- const migratedMode: CompactStyleMode =
118
- mode === "on" || mode === "compact" || mode === "off"
119
- ? mode
120
- : typeof source.enabled === "boolean"
121
- ? source.enabled
122
- ? "on"
123
- : "off"
124
- : "on";
170
+ const mode = pickEnum(source.mode, ["on", "compact", "off"], DEFAULT_CONFIG.mode);
125
171
  const excludeRenderers = Array.isArray(source.excludeRenderers)
126
172
  ? [
127
173
  ...new Set(
@@ -132,7 +178,7 @@ export function normalizeConfig(input: unknown): Config {
132
178
  ]
133
179
  : [];
134
180
  return {
135
- mode: migratedMode,
181
+ mode,
136
182
  excludeRenderers,
137
183
  diffViewMode: pickEnum(source.diffViewMode, DIFF_VIEW_MODES, DEFAULT_CONFIG.diffViewMode),
138
184
  diffIndicatorMode: pickEnum(
@@ -147,7 +193,7 @@ export function normalizeConfig(input: unknown): Config {
147
193
  300,
148
194
  ),
149
195
  editDiffCollapsedLines: pickPositiveInt(
150
- source.editDiffCollapsedLines ?? source.diffCollapsedLines,
196
+ source.editDiffCollapsedLines,
151
197
  DEFAULT_CONFIG.editDiffCollapsedLines,
152
198
  1,
153
199
  500,
@@ -177,6 +223,7 @@ export function normalizeConfig(input: unknown): Config {
177
223
  1,
178
224
  5_000,
179
225
  ),
226
+ inputClip: pickInputClip(source.inputClip),
180
227
  useSummaryTitlesAsThinkingTitle: source.useSummaryTitlesAsThinkingTitle !== false,
181
228
  previewLines: pickPositiveInt(
182
229
  source.previewLines,
@@ -197,6 +244,9 @@ export function normalizeConfig(input: unknown): Config {
197
244
  enableAgentSummary: source.enableAgentSummary !== false,
198
245
  enableWorkingMessage: source.enableWorkingMessage !== false,
199
246
  enableAliases: source.enableAliases !== false,
247
+ enableCustomFooter: source.enableCustomFooter !== false,
248
+ footerNerdIcons: source.footerNerdIcons !== false,
249
+ ...normalizeFooterChipLayout(source),
200
250
  };
201
251
  }
202
252
 
@@ -237,6 +287,7 @@ export function formatConfigStatus(source: Config = config): string {
237
287
  `expandedMax=${source.expandedPreviewMaxLines}`,
238
288
  `expandedInput=${source.expandedInputMaxLines}`,
239
289
  `expandedOutput=${source.expandedOutputMaxLines}`,
290
+ `inputClip=${source.inputClip}`,
240
291
  `thinkingTitle=${source.useSummaryTitlesAsThinkingTitle ? "summary" : "default"}`,
241
292
  `thinkingPreview=${source.previewLines}`,
242
293
  `thinkingAnimation=${source.animationIntervalMs}ms`,
@@ -249,30 +300,32 @@ export function formatConfigStatus(source: Config = config): string {
249
300
  `agentSummary=${source.enableAgentSummary ? "on" : "off"}`,
250
301
  `workingMsg=${source.enableWorkingMessage ? "on" : "off"}`,
251
302
  `aliases=${source.enableAliases ? "on" : "off"}`,
303
+ `footer=${source.enableCustomFooter ? "on" : "off"}`,
304
+ `footerIcons=${source.footerNerdIcons ? "nerd" : "plain"}`,
305
+ formatFooterChipSummary(source),
252
306
  ].join(" · ");
253
307
  }
254
308
 
255
- export let config: Config = loadConfig();
309
+ /** 进程内唯一的活动配置对象。读取直接用 `config.xxx`;写入必须走 `updateConfig`。 */
310
+ export const config: Config = loadConfig();
256
311
 
257
312
  function loadConfig(): Config {
258
313
  try {
259
- const source = existsSync(CONFIG_PATH)
260
- ? (JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as Record<string, unknown>)
314
+ const fromLegacy = !existsSync(CONFIG_PATH) && existsSync(LEGACY_CONFIG_PATH);
315
+ const rawPath = existsSync(CONFIG_PATH) ? CONFIG_PATH : fromLegacy ? LEGACY_CONFIG_PATH : null;
316
+ const source = rawPath
317
+ ? (JSON.parse(readFileSync(rawPath, "utf8")) as Record<string, unknown>)
261
318
  : {};
262
- const normalized = normalizeConfig(source);
263
- if (
264
- typeof source.enabled === "boolean" &&
265
- source.mode !== "on" &&
266
- source.mode !== "compact" &&
267
- source.mode !== "off"
268
- ) {
319
+ const next = normalizeConfig(source);
320
+ if (fromLegacy) {
269
321
  try {
270
- writeFileSync(CONFIG_PATH, JSON.stringify(normalized, null, 2));
322
+ writeFileSync(CONFIG_PATH, JSON.stringify(next, null, 2));
323
+ rmSync(LEGACY_CONFIG_PATH, { force: true });
271
324
  } catch {
272
- // A read-only config still uses the migrated in-memory value.
325
+ // 新路径写失败时仍使用已读到的旧配置,旧文件保留。
273
326
  }
274
327
  }
275
- return normalized;
328
+ return next;
276
329
  } catch {
277
330
  // Ignore bad config and fall back to defaults.
278
331
  }
@@ -283,7 +336,13 @@ export function saveConfig() {
283
336
  writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
284
337
  }
285
338
 
286
- /** 整体替换配置(default export 的 configOverride 注入路径;导入绑定不可重新赋值)。 */
339
+ /** 运行时配置写入的唯一入口:合并 + 规范化 + 持久化。 */
340
+ export function updateConfig(partial: Partial<Config>): void {
341
+ Object.assign(config, normalizeConfig({ ...config, ...partial }));
342
+ saveConfig();
343
+ }
344
+
345
+ /** 整体替换配置(default export 的 configOverride 注入路径;就地覆盖,不持久化)。 */
287
346
  export function setConfig(next: Config): void {
288
- config = next;
347
+ Object.assign(config, next);
289
348
  }