@oh-my-pi/pi-coding-agent 3.14.0 → 3.15.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.
Files changed (213) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/docs/theme.md +38 -5
  3. package/examples/sdk/11-sessions.ts +2 -2
  4. package/package.json +7 -4
  5. package/src/cli/file-processor.ts +51 -2
  6. package/src/cli/plugin-cli.ts +25 -19
  7. package/src/cli/update-cli.ts +4 -3
  8. package/src/core/agent-session.ts +31 -4
  9. package/src/core/compaction/branch-summarization.ts +4 -32
  10. package/src/core/compaction/compaction.ts +6 -84
  11. package/src/core/compaction/utils.ts +2 -3
  12. package/src/core/custom-tools/types.ts +2 -0
  13. package/src/core/export-html/index.ts +1 -1
  14. package/src/core/hooks/tool-wrapper.ts +0 -1
  15. package/src/core/hooks/types.ts +2 -2
  16. package/src/core/plugins/doctor.ts +9 -1
  17. package/src/core/sdk.ts +2 -1
  18. package/src/core/session-manager.ts +518 -40
  19. package/src/core/settings-manager.ts +174 -0
  20. package/src/core/system-prompt.ts +9 -14
  21. package/src/core/title-generator.ts +2 -8
  22. package/src/core/tools/ask.ts +19 -37
  23. package/src/core/tools/bash.ts +2 -37
  24. package/src/core/tools/edit.ts +2 -9
  25. package/src/core/tools/exa/render.ts +52 -48
  26. package/src/core/tools/find.ts +10 -8
  27. package/src/core/tools/grep.ts +45 -17
  28. package/src/core/tools/ls.ts +22 -2
  29. package/src/core/tools/lsp/clients/biome-client.ts +207 -0
  30. package/src/core/tools/lsp/clients/index.ts +49 -0
  31. package/src/core/tools/lsp/clients/lsp-linter-client.ts +98 -0
  32. package/src/core/tools/lsp/config.ts +3 -0
  33. package/src/core/tools/lsp/index.ts +107 -55
  34. package/src/core/tools/lsp/render.ts +192 -79
  35. package/src/core/tools/lsp/types.ts +27 -0
  36. package/src/core/tools/lsp/utils.ts +62 -22
  37. package/src/core/tools/notebook.ts +9 -1
  38. package/src/core/tools/output.ts +37 -14
  39. package/src/core/tools/read.ts +349 -34
  40. package/src/core/tools/renderers.ts +290 -89
  41. package/src/core/tools/review.ts +12 -5
  42. package/src/core/tools/task/agents.ts +5 -5
  43. package/src/core/tools/task/commands.ts +3 -3
  44. package/src/core/tools/task/executor.ts +33 -1
  45. package/src/core/tools/task/index.ts +93 -6
  46. package/src/core/tools/task/render.ts +147 -66
  47. package/src/core/tools/task/types.ts +14 -9
  48. package/src/core/tools/web-fetch.ts +242 -103
  49. package/src/core/tools/web-search/index.ts +64 -20
  50. package/src/core/tools/web-search/providers/exa.ts +68 -172
  51. package/src/core/tools/web-search/render.ts +264 -74
  52. package/src/core/tools/write.ts +2 -8
  53. package/src/main.ts +10 -6
  54. package/src/modes/cleanup.ts +23 -0
  55. package/src/modes/index.ts +9 -4
  56. package/src/modes/interactive/components/bash-execution.ts +6 -3
  57. package/src/modes/interactive/components/branch-summary-message.ts +1 -1
  58. package/src/modes/interactive/components/compaction-summary-message.ts +1 -1
  59. package/src/modes/interactive/components/dynamic-border.ts +1 -1
  60. package/src/modes/interactive/components/extensions/extension-dashboard.ts +4 -5
  61. package/src/modes/interactive/components/extensions/extension-list.ts +18 -16
  62. package/src/modes/interactive/components/extensions/inspector-panel.ts +8 -8
  63. package/src/modes/interactive/components/hook-editor.ts +1 -0
  64. package/src/modes/interactive/components/hook-message.ts +2 -2
  65. package/src/modes/interactive/components/hook-selector.ts +1 -1
  66. package/src/modes/interactive/components/model-selector.ts +22 -9
  67. package/src/modes/interactive/components/oauth-selector.ts +20 -4
  68. package/src/modes/interactive/components/plugin-settings.ts +4 -2
  69. package/src/modes/interactive/components/session-selector.ts +9 -6
  70. package/src/modes/interactive/components/settings-defs.ts +285 -1
  71. package/src/modes/interactive/components/settings-selector.ts +176 -3
  72. package/src/modes/interactive/components/status-line/index.ts +4 -0
  73. package/src/modes/interactive/components/status-line/presets.ts +94 -0
  74. package/src/modes/interactive/components/status-line/segments.ts +350 -0
  75. package/src/modes/interactive/components/status-line/separators.ts +55 -0
  76. package/src/modes/interactive/components/status-line/types.ts +81 -0
  77. package/src/modes/interactive/components/status-line-segment-editor.ts +357 -0
  78. package/src/modes/interactive/components/status-line.ts +172 -223
  79. package/src/modes/interactive/components/tool-execution.ts +446 -211
  80. package/src/modes/interactive/components/tree-selector.ts +17 -6
  81. package/src/modes/interactive/components/ttsr-notification.ts +4 -4
  82. package/src/modes/interactive/components/welcome.ts +27 -19
  83. package/src/modes/interactive/interactive-mode.ts +99 -13
  84. package/src/modes/interactive/theme/dark.json +3 -2
  85. package/src/modes/interactive/theme/defaults/alabaster.json +99 -0
  86. package/src/modes/interactive/theme/defaults/amethyst.json +103 -0
  87. package/src/modes/interactive/theme/defaults/anthracite.json +100 -0
  88. package/src/modes/interactive/theme/defaults/basalt.json +90 -0
  89. package/src/modes/interactive/theme/defaults/birch.json +101 -0
  90. package/src/modes/interactive/theme/defaults/dark-abyss.json +97 -0
  91. package/src/modes/interactive/theme/defaults/dark-arctic.json +111 -0
  92. package/src/modes/interactive/theme/defaults/dark-aurora.json +94 -0
  93. package/src/modes/interactive/theme/defaults/dark-catppuccin.json +106 -0
  94. package/src/modes/interactive/theme/defaults/dark-cavern.json +97 -0
  95. package/src/modes/interactive/theme/defaults/dark-copper.json +94 -0
  96. package/src/modes/interactive/theme/defaults/dark-cosmos.json +96 -0
  97. package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +109 -0
  98. package/src/modes/interactive/theme/defaults/dark-dracula.json +105 -0
  99. package/src/modes/interactive/theme/defaults/dark-eclipse.json +97 -0
  100. package/src/modes/interactive/theme/defaults/dark-ember.json +94 -0
  101. package/src/modes/interactive/theme/defaults/dark-equinox.json +96 -0
  102. package/src/modes/interactive/theme/defaults/dark-forest.json +103 -0
  103. package/src/modes/interactive/theme/defaults/dark-github.json +112 -0
  104. package/src/modes/interactive/theme/defaults/dark-gruvbox.json +119 -0
  105. package/src/modes/interactive/theme/defaults/dark-lavender.json +94 -0
  106. package/src/modes/interactive/theme/defaults/dark-lunar.json +95 -0
  107. package/src/modes/interactive/theme/defaults/dark-midnight.json +94 -0
  108. package/src/modes/interactive/theme/defaults/dark-monochrome.json +101 -0
  109. package/src/modes/interactive/theme/defaults/dark-monokai.json +105 -0
  110. package/src/modes/interactive/theme/defaults/dark-nebula.json +96 -0
  111. package/src/modes/interactive/theme/defaults/dark-nord.json +104 -0
  112. package/src/modes/interactive/theme/defaults/dark-ocean.json +108 -0
  113. package/src/modes/interactive/theme/defaults/dark-one.json +107 -0
  114. package/src/modes/interactive/theme/defaults/dark-rainforest.json +97 -0
  115. package/src/modes/interactive/theme/defaults/dark-reef.json +97 -0
  116. package/src/modes/interactive/theme/defaults/dark-retro.json +99 -0
  117. package/src/modes/interactive/theme/defaults/dark-rose-pine.json +95 -0
  118. package/src/modes/interactive/theme/defaults/dark-sakura.json +94 -0
  119. package/src/modes/interactive/theme/defaults/dark-slate.json +94 -0
  120. package/src/modes/interactive/theme/defaults/dark-solarized.json +96 -0
  121. package/src/modes/interactive/theme/defaults/dark-solstice.json +96 -0
  122. package/src/modes/interactive/theme/defaults/dark-starfall.json +97 -0
  123. package/src/modes/interactive/theme/defaults/dark-sunset.json +106 -0
  124. package/src/modes/interactive/theme/defaults/dark-swamp.json +96 -0
  125. package/src/modes/interactive/theme/defaults/dark-synthwave.json +102 -0
  126. package/src/modes/interactive/theme/defaults/dark-taiga.json +97 -0
  127. package/src/modes/interactive/theme/defaults/dark-terminal.json +94 -0
  128. package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +108 -0
  129. package/src/modes/interactive/theme/defaults/dark-tundra.json +97 -0
  130. package/src/modes/interactive/theme/defaults/dark-twilight.json +97 -0
  131. package/src/modes/interactive/theme/defaults/dark-volcanic.json +97 -0
  132. package/src/modes/interactive/theme/defaults/graphite.json +99 -0
  133. package/src/modes/interactive/theme/defaults/index.ts +195 -0
  134. package/src/modes/interactive/theme/defaults/light-arctic.json +106 -0
  135. package/src/modes/interactive/theme/defaults/light-aurora-day.json +97 -0
  136. package/src/modes/interactive/theme/defaults/light-canyon.json +97 -0
  137. package/src/modes/interactive/theme/defaults/light-catppuccin.json +105 -0
  138. package/src/modes/interactive/theme/defaults/light-cirrus.json +96 -0
  139. package/src/modes/interactive/theme/defaults/light-coral.json +94 -0
  140. package/src/modes/interactive/theme/defaults/light-cyberpunk.json +103 -0
  141. package/src/modes/interactive/theme/defaults/light-dawn.json +96 -0
  142. package/src/modes/interactive/theme/defaults/light-dunes.json +97 -0
  143. package/src/modes/interactive/theme/defaults/light-eucalyptus.json +94 -0
  144. package/src/modes/interactive/theme/defaults/light-forest.json +107 -0
  145. package/src/modes/interactive/theme/defaults/light-frost.json +94 -0
  146. package/src/modes/interactive/theme/defaults/light-github.json +114 -0
  147. package/src/modes/interactive/theme/defaults/light-glacier.json +97 -0
  148. package/src/modes/interactive/theme/defaults/light-gruvbox.json +115 -0
  149. package/src/modes/interactive/theme/defaults/light-haze.json +96 -0
  150. package/src/modes/interactive/theme/defaults/light-honeycomb.json +94 -0
  151. package/src/modes/interactive/theme/defaults/light-lagoon.json +97 -0
  152. package/src/modes/interactive/theme/defaults/light-lavender.json +94 -0
  153. package/src/modes/interactive/theme/defaults/light-meadow.json +97 -0
  154. package/src/modes/interactive/theme/defaults/light-mint.json +94 -0
  155. package/src/modes/interactive/theme/defaults/light-monochrome.json +100 -0
  156. package/src/modes/interactive/theme/defaults/light-ocean.json +106 -0
  157. package/src/modes/interactive/theme/defaults/light-one.json +105 -0
  158. package/src/modes/interactive/theme/defaults/light-opal.json +97 -0
  159. package/src/modes/interactive/theme/defaults/light-orchard.json +97 -0
  160. package/src/modes/interactive/theme/defaults/light-paper.json +94 -0
  161. package/src/modes/interactive/theme/defaults/light-prism.json +96 -0
  162. package/src/modes/interactive/theme/defaults/light-retro.json +105 -0
  163. package/src/modes/interactive/theme/defaults/light-sand.json +94 -0
  164. package/src/modes/interactive/theme/defaults/light-savanna.json +97 -0
  165. package/src/modes/interactive/theme/defaults/light-solarized.json +101 -0
  166. package/src/modes/interactive/theme/defaults/light-soleil.json +96 -0
  167. package/src/modes/interactive/theme/defaults/light-sunset.json +106 -0
  168. package/src/modes/interactive/theme/defaults/light-synthwave.json +105 -0
  169. package/src/modes/interactive/theme/defaults/light-tokyo-night.json +118 -0
  170. package/src/modes/interactive/theme/defaults/light-wetland.json +97 -0
  171. package/src/modes/interactive/theme/defaults/light-zenith.json +95 -0
  172. package/src/modes/interactive/theme/defaults/limestone.json +100 -0
  173. package/src/modes/interactive/theme/defaults/mahogany.json +104 -0
  174. package/src/modes/interactive/theme/defaults/marble.json +99 -0
  175. package/src/modes/interactive/theme/defaults/obsidian.json +90 -0
  176. package/src/modes/interactive/theme/defaults/onyx.json +90 -0
  177. package/src/modes/interactive/theme/defaults/pearl.json +99 -0
  178. package/src/modes/interactive/theme/defaults/porcelain.json +90 -0
  179. package/src/modes/interactive/theme/defaults/quartz.json +102 -0
  180. package/src/modes/interactive/theme/defaults/sandstone.json +101 -0
  181. package/src/modes/interactive/theme/defaults/titanium.json +89 -0
  182. package/src/modes/interactive/theme/light.json +3 -2
  183. package/src/modes/interactive/theme/theme-schema.json +120 -4
  184. package/src/modes/interactive/theme/theme.ts +1228 -14
  185. package/src/prompts/branch-summary-preamble.md +3 -0
  186. package/src/prompts/branch-summary.md +28 -0
  187. package/src/prompts/compaction-summary.md +34 -0
  188. package/src/prompts/compaction-turn-prefix.md +16 -0
  189. package/src/prompts/compaction-update-summary.md +41 -0
  190. package/src/prompts/init.md +30 -0
  191. package/src/{core/tools/task/bundled-agents → prompts}/reviewer.md +6 -0
  192. package/src/prompts/summarization-system.md +3 -0
  193. package/src/prompts/system-prompt.md +27 -0
  194. package/src/{core/tools/task/bundled-agents → prompts}/task.md +2 -0
  195. package/src/prompts/title-system.md +8 -0
  196. package/src/prompts/tools/ask.md +24 -0
  197. package/src/prompts/tools/bash.md +23 -0
  198. package/src/prompts/tools/edit.md +9 -0
  199. package/src/prompts/tools/find.md +6 -0
  200. package/src/prompts/tools/grep.md +12 -0
  201. package/src/prompts/tools/lsp.md +14 -0
  202. package/src/prompts/tools/output.md +23 -0
  203. package/src/prompts/tools/read.md +25 -0
  204. package/src/prompts/tools/web-fetch.md +8 -0
  205. package/src/prompts/tools/web-search.md +10 -0
  206. package/src/prompts/tools/write.md +10 -0
  207. package/src/commands/init.md +0 -20
  208. /package/src/{core/tools/task/bundled-commands → prompts}/architect-plan.md +0 -0
  209. /package/src/{core/tools/task/bundled-agents → prompts}/browser.md +0 -0
  210. /package/src/{core/tools/task/bundled-agents → prompts}/explore.md +0 -0
  211. /package/src/{core/tools/task/bundled-commands → prompts}/implement-with-critic.md +0 -0
  212. /package/src/{core/tools/task/bundled-commands → prompts}/implement.md +0 -0
  213. /package/src/{core/tools/task/bundled-agents → prompts}/plan.md +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,95 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.15.1] - 2026-01-05
6
+
7
+ ### Added
8
+
9
+ - Added 65 new built-in color themes including dark variants (abyss, aurora, cavern, copper, cosmos, eclipse, ember, equinox, lavender, lunar, midnight, nebula, rainforest, reef, sakura, slate, solstice, starfall, swamp, taiga, terminal, tundra, twilight, volcanic), light variants (aurora-day, canyon, cirrus, coral, dawn, dunes, eucalyptus, frost, glacier, haze, honeycomb, lagoon, lavender, meadow, mint, opal, orchard, paper, prism, sand, savanna, soleil, wetland, zenith), and material themes (alabaster, amethyst, anthracite, basalt, birch, graphite, limestone, mahogany, marble, obsidian, onyx, pearl, porcelain, quartz, sandstone, titanium)
10
+
11
+ ### Fixed
12
+
13
+ - Fixed status line end cap rendering to properly apply background colors and use correct powerline separator characters
14
+
15
+ ## [3.15.0] - 2026-01-05
16
+
17
+ ### Added
18
+
19
+ - Added spinner type variants (status and activity) with distinct animation frames per symbol preset
20
+ - Added animated spinner for task tool progress display during subagent execution
21
+ - Added language/file type icons for read tool output with support for 35+ file types
22
+ - Added async cleanup registry for graceful session flush on SIGINT, SIGTERM, and SIGHUP signals
23
+ - Added subagent token usage aggregation to session statistics and task tool results
24
+ - Added streaming NDJSON writer for session persistence with proper backpressure handling
25
+ - Added `flush()` method to SessionManager for explicit control over pending write completion
26
+ - Added `/exit` slash command to exit the application from interactive mode
27
+ - Added fuzzy path matching suggestions when read tool encounters file-not-found errors, showing closest matches using Levenshtein distance
28
+ - Added `status.shadowed` symbol for theme customization to properly indicate shadowed extension state
29
+ - Added Biome CLI-based linter client as alternative to LSP for more reliable diagnostics
30
+ - Added LinterClient interface for pluggable formatter/linter implementations
31
+ - Added status line segment editor for arranging and toggling status line components
32
+ - Added status line presets (default, minimal, compact, developer, balanced) for quick configuration
33
+ - Added status line separator styles (powerline, powerline-thin, arrow, slash, pipe, space)
34
+ - Added configurable status line segments including time, hostname, and subagent count
35
+ - Added symbol customization via theme overrides for icons, separators, and glyphs
36
+ - Added 30+ built-in color themes including Catppuccin, Dracula, Nord, Gruvbox, Tokyo Night, and more
37
+ - Added configurable status line with customizable segments, presets, and separators
38
+ - Added status line segment editor for arranging and toggling status line components
39
+ - Added symbol preset setting to switch between Unicode, Nerd Font, and ASCII glyphs
40
+ - Added file size limit (20MB) for image files to prevent memory issues during serialization
41
+
42
+ ### Changed
43
+
44
+ - Changed `isError` property in tool result events to be optional instead of required
45
+ - Changed `SessionManager.open()` and `SessionManager.continueRecent()` to async methods for proper initialization
46
+ - Changed session file writes to use atomic rename pattern with fsync for crash-safe persistence
47
+ - Changed read tool display to show file type icons and metadata inline with path
48
+ - Changed `AgentSession.dispose()` to async method that flushes pending writes before cleanup
49
+ - Changed read tool result display to hide content by default with expand hint, showing only metadata until expanded
50
+ - Changed diagnostics display to group messages by file with tree structure and severity icons
51
+ - Changed diff stats formatting to use colored +/- indicators with slash separators
52
+ - Changed session persistence to use streaming writes instead of synchronous file appends for better performance
53
+ - Changed read tool to automatically redirect to ls when given a directory path instead of a file
54
+ - Changed tool description prompts to be more concise with clearer usage guidelines and structured formatting
55
+ - Moved tool description prompts from inline strings to external markdown files in `src/prompts/tools/` directory for better maintainability
56
+ - Changed Exa web search provider from MCP protocol to direct REST API for simpler integration
57
+ - Changed web search result rendering to handle malformed response data with fallback text display
58
+ - Changed compaction prompts to preserve tool outputs, command results, and repository state in context summaries
59
+ - Changed init prompt to include runtime/tooling preferences section and improved formatting guidelines
60
+ - Changed reviewer prompt to require evidence-backed findings anchored to diff hunks with stricter suggestion block formatting
61
+ - Changed system prompt to include explicit core behavior guidelines for task completion and progress updates
62
+ - Changed task prompt to emphasize end-to-end task completion and tool verification
63
+ - Moved all prompt templates from inline strings to external markdown files in `src/prompts/` directory for better maintainability
64
+ - Changed tool result renderers to use structured tree layouts with consistent expand hints and truncation indicators
65
+ - Changed grep, find, and ls tools to show scope path and detailed truncation reasons in output
66
+ - Changed web search and web fetch result rendering to display structured metadata sections with bounded content previews
67
+ - Changed task/subagent progress rendering to use badge-style status labels and structured output sections
68
+ - Changed notebook tool to display cell content preview with line counts
69
+ - Changed ask tool result to show checkbox-style selection indicators
70
+ - Changed output tool to include provenance metadata and content previews for retrieved outputs
71
+ - Changed collapsed tool views to show consistent "Ctrl+O to expand" hints with remaining item counts
72
+ - Changed Biome integration to use CLI instead of LSP to avoid stale diagnostics issues
73
+ - Changed hardcoded UI symbols throughout codebase to use theme-configurable glyphs
74
+ - Changed tree drawing characters to use theme-defined box-drawing symbols
75
+ - Changed status line rendering to support left/right segment positioning with separators
76
+ - Changed hardcoded UI symbols to use theme-configurable glyphs throughout the interface
77
+ - Changed tree drawing characters to use theme-defined box-drawing symbols
78
+ - Changed CLI image attachments to resize if larger than 2048px (fit within 1920x1080) and convert >2MB images to JPEG
79
+
80
+ ### Removed
81
+
82
+ - Removed custom renderers for ls, find, and grep tools in favor of generic tool display
83
+
84
+ ### Fixed
85
+
86
+ - Fixed spinner animation crash when spinner frames array is empty by adding length check
87
+ - Fixed session persistence to properly await all queued writes before closing or switching sessions
88
+ - Fixed session persistence to truncate oversized content blocks before writing to prevent memory exhaustion
89
+ - Fixed extension list and inspector panel to use correct symbols for disabled and shadowed states instead of reusing unrelated status icons
90
+ - Fixed token counting for subagent progress to handle different usage object formats (camelCase and snake_case)
91
+ - Fixed image file handling by adding 20MB size limit to prevent memory issues during serialization
92
+ - Fixed session persistence to truncate oversized entries before writing JSONL to prevent out-of-memory errors
93
+
5
94
  ## [3.14.0] - 2026-01-04
6
95
  ### Added
7
96
 
package/docs/theme.md CHANGED
@@ -132,7 +132,7 @@ Themes are defined in JSON files with the following structure:
132
132
 
133
133
  ```json
134
134
  {
135
- "$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/theme-schema.json",
135
+ "$schema": "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/theme-schema.json",
136
136
  "name": "my-theme",
137
137
  "vars": {
138
138
  "blue": "#0066cc",
@@ -149,6 +149,39 @@ Themes are defined in JSON files with the following structure:
149
149
  }
150
150
  ```
151
151
 
152
+ ## Symbols
153
+
154
+ Themes can also customize specific UI symbols (icons, separators, bullets, etc.). Use `symbols.preset` to set a theme default (overridden by user settings), and `symbols.overrides` to override individual keys.
155
+
156
+ Example:
157
+
158
+ ```json
159
+ {
160
+ "symbols": {
161
+ "preset": "ascii",
162
+ "overrides": {
163
+ "icon.model": "[M]",
164
+ "sep.powerlineLeft": ">",
165
+ "sep.powerlineRight": "<"
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ Symbol keys by category:
172
+
173
+ - Status: `status.success`, `status.error`, `status.warning`, `status.info`, `status.pending`, `status.disabled`, `status.enabled`, `status.running`, `status.shadowed`, `status.aborted`
174
+ - Navigation: `nav.cursor`, `nav.selected`, `nav.expand`, `nav.collapse`, `nav.back`
175
+ - Tree: `tree.branch`, `tree.last`, `tree.vertical`, `tree.horizontal`, `tree.hook`
176
+ - Boxes (rounded): `boxRound.topLeft`, `boxRound.topRight`, `boxRound.bottomLeft`, `boxRound.bottomRight`, `boxRound.horizontal`, `boxRound.vertical`
177
+ - Boxes (sharp): `boxSharp.topLeft`, `boxSharp.topRight`, `boxSharp.bottomLeft`, `boxSharp.bottomRight`, `boxSharp.horizontal`, `boxSharp.vertical`, `boxSharp.cross`, `boxSharp.teeDown`, `boxSharp.teeUp`, `boxSharp.teeRight`, `boxSharp.teeLeft`
178
+ - Separators: `sep.powerline`, `sep.powerlineThin`, `sep.powerlineLeft`, `sep.powerlineRight`, `sep.powerlineThinLeft`, `sep.powerlineThinRight`, `sep.dot`, `sep.slash`, `sep.pipe`
179
+ - Icons: `icon.model`, `icon.folder`, `icon.file`, `icon.git`, `icon.branch`, `icon.tokens`, `icon.context`, `icon.cost`, `icon.time`, `icon.pi`, `icon.agents`, `icon.cache`, `icon.input`, `icon.output`, `icon.host`, `icon.session`, `icon.package`, `icon.warning`, `icon.rewind`, `icon.auto`, `icon.extensionSkill`, `icon.extensionTool`, `icon.extensionSlashCommand`, `icon.extensionMcp`, `icon.extensionRule`, `icon.extensionHook`, `icon.extensionPrompt`, `icon.extensionContextFile`, `icon.extensionInstruction`
180
+ - Thinking: `thinking.minimal`, `thinking.low`, `thinking.medium`, `thinking.high`, `thinking.xhigh`
181
+ - Checkboxes: `checkbox.checked`, `checkbox.unchecked`
182
+ - Formatting: `format.ellipsis`, `format.bullet`, `format.dash`
183
+ - Markdown: `md.quoteBorder`, `md.hrChar`, `md.bullet`
184
+
152
185
  ### Color Values
153
186
 
154
187
  Four formats are supported:
@@ -253,7 +286,7 @@ Custom themes are loaded from `~/.omp/agent/themes/*.json`.
253
286
 
254
287
  ```json
255
288
  {
256
- "$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/theme-schema.json",
289
+ "$schema": "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/theme-schema.json",
257
290
  "name": "my-theme",
258
291
  "vars": {
259
292
  "primary": "#00aaff",
@@ -448,14 +481,14 @@ Error loading theme 'my-theme':
448
481
  For editor support, the JSON schema is available at:
449
482
 
450
483
  ```
451
- https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/theme-schema.json
484
+ https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/theme-schema.json
452
485
  ```
453
486
 
454
487
  Add to your theme file for auto-completion and validation:
455
488
 
456
489
  ```json
457
490
  {
458
- "$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/theme-schema.json",
491
+ "$schema": "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/theme-schema.json",
459
492
  ...
460
493
  }
461
494
  ```
@@ -552,7 +585,7 @@ function getMarkdownTheme(): MarkdownTheme {
552
585
  }
553
586
 
554
587
  // Create markdown with theme
555
- const md = new Markdown(text, 1, 1, { bgColor: theme.bg("userMessageBg") }, getMarkdownTheme());
588
+ const md = new Markdown(text, 1, 1, getMarkdownTheme(), { bgColor: theme.bg("userMessageBg") });
556
589
  ```
557
590
 
558
591
  This approach:
@@ -20,7 +20,7 @@ console.log("New session file:", newSession.sessionFile);
20
20
 
21
21
  // Continue most recent session (or create new if none)
22
22
  const { session: continued, modelFallbackMessage } = await createAgentSession({
23
- sessionManager: SessionManager.continueRecent(process.cwd()),
23
+ sessionManager: await SessionManager.continueRecent(process.cwd()),
24
24
  });
25
25
  if (modelFallbackMessage) console.log("Note:", modelFallbackMessage);
26
26
  console.log("Continued session:", continued.sessionFile);
@@ -34,7 +34,7 @@ for (const info of sessions.slice(0, 3)) {
34
34
 
35
35
  if (sessions.length > 0) {
36
36
  const { session: opened } = await createAgentSession({
37
- sessionManager: SessionManager.open(sessions[0].path),
37
+ sessionManager: await SessionManager.open(sessions[0].path),
38
38
  });
39
39
  console.log(`\nOpened: ${opened.sessionId}`);
40
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "3.14.0",
3
+ "version": "3.15.1",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -39,9 +39,9 @@
39
39
  "prepublishOnly": "bun run generate-template && bun run clean && bun run build"
40
40
  },
41
41
  "dependencies": {
42
- "@oh-my-pi/pi-agent-core": "3.14.0",
43
- "@oh-my-pi/pi-ai": "3.14.0",
44
- "@oh-my-pi/pi-tui": "3.14.0",
42
+ "@oh-my-pi/pi-agent-core": "3.15.1",
43
+ "@oh-my-pi/pi-ai": "3.15.1",
44
+ "@oh-my-pi/pi-tui": "3.15.1",
45
45
  "@sinclair/typebox": "^0.34.46",
46
46
  "ajv": "^8.17.1",
47
47
  "chalk": "^5.5.0",
@@ -53,15 +53,18 @@
53
53
  "marked": "^15.0.12",
54
54
  "minimatch": "^10.1.1",
55
55
  "nanoid": "^5.1.6",
56
+ "ndjson": "^2.0.0",
56
57
  "node-html-parser": "^6.1.13",
57
58
  "smol-toml": "^1.6.0",
58
59
  "strip-ansi": "^7.1.2",
60
+ "sharp": "^0.34.2",
59
61
  "winston": "^3.17.0",
60
62
  "winston-daily-rotate-file": "^5.0.0",
61
63
  "yaml": "^2.8.2"
62
64
  },
63
65
  "devDependencies": {
64
66
  "@types/diff": "^7.0.2",
67
+ "@types/ndjson": "^2.0.4",
65
68
  "@types/node": "^24.3.0",
66
69
  "vitest": "^3.2.4"
67
70
  },
@@ -6,6 +6,7 @@ import { access, readFile, stat } from "node:fs/promises";
6
6
  import { resolve } from "node:path";
7
7
  import type { ImageContent } from "@oh-my-pi/pi-ai";
8
8
  import chalk from "chalk";
9
+ import sharp from "sharp";
9
10
  import { resolveReadPath } from "../core/tools/path-utils";
10
11
  import { detectSupportedImageMimeTypeFromFile } from "../utils/mime";
11
12
 
@@ -14,6 +15,53 @@ export interface ProcessedFiles {
14
15
  images: ImageContent[];
15
16
  }
16
17
 
18
+ const RESIZE_TRIGGER_MAX_DIMENSION = 2048;
19
+ const MAX_RESIZE_WIDTH = 1920;
20
+ const MAX_RESIZE_HEIGHT = 1080;
21
+ const JPEG_CONVERT_THRESHOLD_BYTES = 2 * 1024 * 1024;
22
+ const JPEG_QUALITY = 85;
23
+
24
+ async function processImageAttachment(buffer: Buffer, mimeType: string): Promise<{ buffer: Buffer; mimeType: string }> {
25
+ const metadata = await sharp(buffer, { failOnError: false }).metadata();
26
+ const width = metadata.width ?? 0;
27
+ const height = metadata.height ?? 0;
28
+ const maxDim = Math.max(width, height);
29
+ const shouldResize = width > 0 && height > 0 && maxDim > RESIZE_TRIGGER_MAX_DIMENSION;
30
+ const shouldConvertToJpeg = buffer.length > JPEG_CONVERT_THRESHOLD_BYTES;
31
+
32
+ if (!shouldResize && !shouldConvertToJpeg) {
33
+ return { buffer, mimeType };
34
+ }
35
+
36
+ let pipeline = sharp(buffer, { failOnError: false });
37
+ if (shouldResize) {
38
+ pipeline = pipeline.resize({
39
+ width: MAX_RESIZE_WIDTH,
40
+ height: MAX_RESIZE_HEIGHT,
41
+ fit: "inside",
42
+ withoutEnlargement: true,
43
+ });
44
+ }
45
+
46
+ if (shouldConvertToJpeg) {
47
+ pipeline = pipeline.jpeg({ quality: JPEG_QUALITY });
48
+ return { buffer: await pipeline.toBuffer(), mimeType: "image/jpeg" };
49
+ }
50
+
51
+ if (mimeType === "image/png") {
52
+ pipeline = pipeline.png();
53
+ } else if (mimeType === "image/webp") {
54
+ pipeline = pipeline.webp();
55
+ } else if (mimeType === "image/gif") {
56
+ pipeline = pipeline.gif();
57
+ } else {
58
+ pipeline = pipeline.jpeg({ quality: JPEG_QUALITY });
59
+ return { buffer: await pipeline.toBuffer(), mimeType: "image/jpeg" };
60
+ }
61
+
62
+ return { buffer: await pipeline.toBuffer(), mimeType };
63
+ }
64
+
17
65
  /** Process @file arguments into text content and image attachments */
18
66
  export async function processFileArguments(fileArgs: string[]): Promise<ProcessedFiles> {
19
67
  let text = "";
@@ -43,11 +91,12 @@ export async function processFileArguments(fileArgs: string[]): Promise<Processe
43
91
  if (mimeType) {
44
92
  // Handle image file
45
93
  const content = await readFile(absolutePath);
46
- const base64Content = content.toString("base64");
94
+ const processed = await processImageAttachment(content, mimeType);
95
+ const base64Content = processed.buffer.toString("base64");
47
96
 
48
97
  const attachment: ImageContent = {
49
98
  type: "image",
50
- mimeType,
99
+ mimeType: processed.mimeType,
51
100
  data: base64Content,
52
101
  };
53
102
 
@@ -7,6 +7,7 @@
7
7
  import chalk from "chalk";
8
8
  import { APP_NAME } from "../config";
9
9
  import { PluginManager, parseSettingValue, validateSetting } from "../core/plugins/index";
10
+ import { theme } from "../modes/interactive/theme/theme";
10
11
 
11
12
  // =============================================================================
12
13
  // Types
@@ -173,7 +174,7 @@ async function handleInstall(
173
174
  if (flags.dryRun) {
174
175
  console.log(chalk.dim(`[dry-run] Would install ${spec}`));
175
176
  } else {
176
- console.log(chalk.green(`✓ Installed ${result.name}@${result.version}`));
177
+ console.log(chalk.green(`${theme.status.success} Installed ${result.name}@${result.version}`));
177
178
  if (result.enabledFeatures && result.enabledFeatures.length > 0) {
178
179
  console.log(chalk.dim(` Features: ${result.enabledFeatures.join(", ")}`));
179
180
  }
@@ -183,7 +184,7 @@ async function handleInstall(
183
184
  }
184
185
  }
185
186
  } catch (err) {
186
- console.error(chalk.red(`✗ Failed to install ${spec}: ${err}`));
187
+ console.error(chalk.red(`${theme.status.error} Failed to install ${spec}: ${err}`));
187
188
  process.exit(1);
188
189
  }
189
190
  }
@@ -202,10 +203,10 @@ async function handleUninstall(manager: PluginManager, packages: string[], flags
202
203
  if (flags.json) {
203
204
  console.log(JSON.stringify({ uninstalled: name }));
204
205
  } else {
205
- console.log(chalk.green(`✓ Uninstalled ${name}`));
206
+ console.log(chalk.green(`${theme.status.success} Uninstalled ${name}`));
206
207
  }
207
208
  } catch (err) {
208
- console.error(chalk.red(`✗ Failed to uninstall ${name}: ${err}`));
209
+ console.error(chalk.red(`${theme.status.error} Failed to uninstall ${name}: ${err}`));
209
210
  process.exit(1);
210
211
  }
211
212
  }
@@ -226,8 +227,9 @@ async function handleList(manager: PluginManager, flags: { json?: boolean }): Pr
226
227
  }
227
228
 
228
229
  console.log(chalk.bold("Installed Plugins:\n"));
230
+
229
231
  for (const plugin of plugins) {
230
- const status = plugin.enabled ? chalk.green("●") : chalk.dim("○");
232
+ const status = plugin.enabled ? chalk.green(theme.status.enabled) : chalk.dim(theme.status.disabled);
231
233
  const nameVersion = `${plugin.name}@${plugin.version}`;
232
234
  console.log(`${status} ${nameVersion}`);
233
235
 
@@ -265,10 +267,10 @@ async function handleLink(manager: PluginManager, paths: string[], flags: { json
265
267
  if (flags.json) {
266
268
  console.log(JSON.stringify(result, null, 2));
267
269
  } else {
268
- console.log(chalk.green(`✓ Linked ${result.name} from ${paths[0]}`));
270
+ console.log(chalk.green(`${theme.status.success} Linked ${result.name} from ${paths[0]}`));
269
271
  }
270
272
  } catch (err) {
271
- console.error(chalk.red(`✗ Failed to link: ${err}`));
273
+ console.error(chalk.red(`${theme.status.error} Failed to link: ${err}`));
272
274
  process.exit(1);
273
275
  }
274
276
  }
@@ -285,10 +287,14 @@ async function handleDoctor(manager: PluginManager, flags: { json?: boolean; fix
285
287
 
286
288
  for (const check of checks) {
287
289
  const icon =
288
- check.status === "ok" ? chalk.green("✓") : check.status === "warning" ? chalk.yellow("!") : chalk.red("✗");
290
+ check.status === "ok"
291
+ ? chalk.green(theme.status.success)
292
+ : check.status === "warning"
293
+ ? chalk.yellow(theme.status.warning)
294
+ : chalk.red(theme.status.error);
289
295
  console.log(`${icon} ${check.name}: ${check.message}`);
290
296
  if (check.fixed) {
291
- console.log(chalk.dim(` Fixed`));
297
+ console.log(chalk.dim(` ${theme.nav.cursor} Fixed`));
292
298
  }
293
299
  }
294
300
 
@@ -361,7 +367,7 @@ async function handleFeatures(
361
367
  }
362
368
 
363
369
  await manager.setEnabledFeatures(pluginName, [...currentFeatures]);
364
- console.log(chalk.green(`✓ Updated features for ${pluginName}`));
370
+ console.log(chalk.green(`${theme.status.success} Updated features for ${pluginName}`));
365
371
  }
366
372
 
367
373
  // Display current state
@@ -392,7 +398,7 @@ async function handleFeatures(
392
398
  const enabledSet = new Set(updatedFeatures ?? []);
393
399
  for (const [name, feat] of Object.entries(plugin.manifest.features)) {
394
400
  const enabled = enabledSet.has(name);
395
- const icon = enabled ? chalk.green("●") : chalk.dim("○");
401
+ const icon = enabled ? chalk.green(theme.status.enabled) : chalk.dim(theme.status.disabled);
396
402
  const defaultLabel = feat.default ? chalk.dim(" (default)") : "";
397
403
  console.log(`${icon} ${name}${defaultLabel}`);
398
404
  if (feat.description) {
@@ -507,7 +513,7 @@ async function handleConfig(
507
513
  }
508
514
 
509
515
  manager.setPluginSetting(pluginName, key, value);
510
- console.log(chalk.green(`✓ Set ${key}`));
516
+ console.log(chalk.green(`${theme.status.success} Set ${key}`));
511
517
  break;
512
518
  }
513
519
 
@@ -518,7 +524,7 @@ async function handleConfig(
518
524
  }
519
525
 
520
526
  manager.deletePluginSetting(pluginName, key);
521
- console.log(chalk.green(`✓ Deleted ${key}`));
527
+ console.log(chalk.green(`${theme.status.success} Deleted ${key}`));
522
528
  break;
523
529
  }
524
530
 
@@ -554,10 +560,10 @@ async function handleConfigValidate(manager: PluginManager, flags: { json?: bool
554
560
  }
555
561
 
556
562
  if (results.length === 0) {
557
- console.log(chalk.green("✓ All settings valid"));
563
+ console.log(chalk.green(`${theme.status.success} All settings valid`));
558
564
  } else {
559
565
  for (const { plugin, key, error } of results) {
560
- console.log(chalk.red(`✗ ${plugin}.${key}: ${error}`));
566
+ console.log(chalk.red(`${theme.status.error} ${plugin}.${key}: ${error}`));
561
567
  }
562
568
  process.exit(1);
563
569
  }
@@ -576,10 +582,10 @@ async function handleEnable(manager: PluginManager, plugins: string[], flags: {
576
582
  if (flags.json) {
577
583
  console.log(JSON.stringify({ enabled: name }));
578
584
  } else {
579
- console.log(chalk.green(`✓ Enabled ${name}`));
585
+ console.log(chalk.green(`${theme.status.success} Enabled ${name}`));
580
586
  }
581
587
  } catch (err) {
582
- console.error(chalk.red(`✗ Failed to enable ${name}: ${err}`));
588
+ console.error(chalk.red(`${theme.status.error} Failed to enable ${name}: ${err}`));
583
589
  process.exit(1);
584
590
  }
585
591
  }
@@ -598,10 +604,10 @@ async function handleDisable(manager: PluginManager, plugins: string[], flags: {
598
604
  if (flags.json) {
599
605
  console.log(JSON.stringify({ disabled: name }));
600
606
  } else {
601
- console.log(chalk.green(`✓ Disabled ${name}`));
607
+ console.log(chalk.green(`${theme.status.success} Disabled ${name}`));
602
608
  }
603
609
  } catch (err) {
604
- console.error(chalk.red(`✗ Failed to disable ${name}: ${err}`));
610
+ console.error(chalk.red(`${theme.status.error} Failed to disable ${name}: ${err}`));
605
611
  process.exit(1);
606
612
  }
607
613
  }
@@ -12,6 +12,7 @@ import { Readable } from "node:stream";
12
12
  import { pipeline } from "node:stream/promises";
13
13
  import chalk from "chalk";
14
14
  import { APP_NAME, VERSION } from "../config";
15
+ import { theme } from "../modes/interactive/theme/theme";
15
16
 
16
17
  /**
17
18
  * Detect if we're running as a Bun compiled binary.
@@ -142,7 +143,7 @@ async function updateViaBun(): Promise<void> {
142
143
 
143
144
  try {
144
145
  execSync(`bun update -g ${PACKAGE}`, { stdio: "inherit" });
145
- console.log(chalk.green("\n Update complete"));
146
+ console.log(chalk.green(`\n${theme.status.success} Update complete`));
146
147
  } catch {
147
148
  throw new Error("bun update failed");
148
149
  }
@@ -192,7 +193,7 @@ async function updateViaBinary(release: ReleaseInfo): Promise<void> {
192
193
  // Clean up backup
193
194
  unlinkSync(backupPath);
194
195
 
195
- console.log(chalk.green(`\n Updated to ${release.version}`));
196
+ console.log(chalk.green(`\n${theme.status.success} Updated to ${release.version}`));
196
197
  console.log(chalk.dim(`Restart ${APP_NAME} to use the new version`));
197
198
  } catch (err) {
198
199
  // Restore from backup if possible
@@ -224,7 +225,7 @@ export async function runUpdateCommand(opts: { force: boolean; check: boolean })
224
225
  const comparison = compareVersions(release.version, VERSION);
225
226
 
226
227
  if (comparison <= 0 && !opts.force) {
227
- console.log(chalk.green("✓ Already up to date"));
228
+ console.log(chalk.green(`${theme.status.success} Already up to date`));
228
229
  return;
229
230
  }
230
231
 
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  import type { Agent, AgentEvent, AgentMessage, AgentState, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
17
- import type { AssistantMessage, ImageContent, Message, Model, TextContent } from "@oh-my-pi/pi-ai";
17
+ import type { AssistantMessage, ImageContent, Message, Model, TextContent, Usage } from "@oh-my-pi/pi-ai";
18
18
  import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@oh-my-pi/pi-ai";
19
19
  import type { Rule } from "../capability/rule";
20
20
  import { getAuthPath } from "../config";
@@ -479,10 +479,11 @@ export class AgentSession {
479
479
  }
480
480
 
481
481
  /**
482
- * Remove all listeners and disconnect from agent.
482
+ * Remove all listeners, flush pending writes, and disconnect from agent.
483
483
  * Call this when completely done with the session.
484
484
  */
485
- dispose(): void {
485
+ async dispose(): Promise<void> {
486
+ await this.sessionManager.flush();
486
487
  this._disconnectFromAgent();
487
488
  this._eventListeners = [];
488
489
  }
@@ -841,6 +842,7 @@ export class AgentSession {
841
842
  this._disconnectFromAgent();
842
843
  await this.abort();
843
844
  this.agent.reset();
845
+ await this.sessionManager.flush();
844
846
  this.sessionManager.newSession(options);
845
847
  this._queuedMessages = [];
846
848
  this._reconnectToAgent();
@@ -1636,8 +1638,11 @@ export class AgentSession {
1636
1638
  await this.abort();
1637
1639
  this._queuedMessages = [];
1638
1640
 
1641
+ // Flush pending writes before switching
1642
+ await this.sessionManager.flush();
1643
+
1639
1644
  // Set new session
1640
- this.sessionManager.setSessionFile(sessionPath);
1645
+ await this.sessionManager.setSessionFile(sessionPath);
1641
1646
 
1642
1647
  // Reload messages
1643
1648
  const sessionContext = this.sessionManager.buildSessionContext();
@@ -1714,6 +1719,9 @@ export class AgentSession {
1714
1719
  skipConversationRestore = result?.skipConversationRestore ?? false;
1715
1720
  }
1716
1721
 
1722
+ // Flush pending writes before branching
1723
+ await this.sessionManager.flush();
1724
+
1717
1725
  if (!selectedEntry.parentId) {
1718
1726
  this.sessionManager.newSession();
1719
1727
  } else {
@@ -1955,6 +1963,14 @@ export class AgentSession {
1955
1963
  let totalCacheWrite = 0;
1956
1964
  let totalCost = 0;
1957
1965
 
1966
+ const getTaskToolUsage = (details: unknown): Usage | undefined => {
1967
+ if (!details || typeof details !== "object") return undefined;
1968
+ const record = details as Record<string, unknown>;
1969
+ const usage = record.usage;
1970
+ if (!usage || typeof usage !== "object") return undefined;
1971
+ return usage as Usage;
1972
+ };
1973
+
1958
1974
  for (const message of state.messages) {
1959
1975
  if (message.role === "assistant") {
1960
1976
  const assistantMsg = message as AssistantMessage;
@@ -1965,6 +1981,17 @@ export class AgentSession {
1965
1981
  totalCacheWrite += assistantMsg.usage.cacheWrite;
1966
1982
  totalCost += assistantMsg.usage.cost.total;
1967
1983
  }
1984
+
1985
+ if (message.role === "toolResult" && message.toolName === "task") {
1986
+ const usage = getTaskToolUsage(message.details);
1987
+ if (usage) {
1988
+ totalInput += usage.input;
1989
+ totalOutput += usage.output;
1990
+ totalCacheRead += usage.cacheRead;
1991
+ totalCacheWrite += usage.cacheWrite;
1992
+ totalCost += usage.cost.total;
1993
+ }
1994
+ }
1968
1995
  }
1969
1996
 
1970
1997
  return {
@@ -8,6 +8,8 @@
8
8
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
9
9
  import type { Model } from "@oh-my-pi/pi-ai";
10
10
  import { completeSimple } from "@oh-my-pi/pi-ai";
11
+ import branchSummaryPrompt from "../../prompts/branch-summary.md" with { type: "text" };
12
+ import branchSummaryPreamble from "../../prompts/branch-summary-preamble.md" with { type: "text" };
11
13
  import {
12
14
  convertToLlm,
13
15
  createBranchSummaryMessage,
@@ -235,39 +237,9 @@ export function prepareBranchEntries(entries: SessionEntry[], tokenBudget: numbe
235
237
  // Summary Generation
236
238
  // ============================================================================
237
239
 
238
- const BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.
239
- Summary of that exploration:
240
+ const BRANCH_SUMMARY_PREAMBLE = branchSummaryPreamble;
240
241
 
241
- `;
242
-
243
- const BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.
244
-
245
- Use this EXACT format:
246
-
247
- ## Goal
248
- [What was the user trying to accomplish in this branch?]
249
-
250
- ## Constraints & Preferences
251
- - [Any constraints, preferences, or requirements mentioned]
252
- - [Or "(none)" if none were mentioned]
253
-
254
- ## Progress
255
- ### Done
256
- - [x] [Completed tasks/changes]
257
-
258
- ### In Progress
259
- - [ ] [Work that was started but not finished]
260
-
261
- ### Blocked
262
- - [Issues preventing progress, if any]
263
-
264
- ## Key Decisions
265
- - **[Decision]**: [Brief rationale]
266
-
267
- ## Next Steps
268
- 1. [What should happen next to continue this work]
269
-
270
- Keep each section concise. Preserve exact file paths, function names, and error messages.`;
242
+ const BRANCH_SUMMARY_PROMPT = branchSummaryPrompt;
271
243
 
272
244
  /**
273
245
  * Generate a summary of abandoned branch entries.