@herbertgao/pi-extensions 2026.9.20 → 2026.10.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 (282) hide show
  1. package/README.md +13 -8
  2. package/THIRD_PARTY_NOTICES.md +29 -3
  3. package/node_modules/@herbertgao/pi-bark/README.md +39 -3
  4. package/node_modules/@herbertgao/pi-bark/package.json +1 -1
  5. package/node_modules/@herbertgao/pi-bark/src/index.ts +275 -15
  6. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +50 -50
  7. package/node_modules/@herbertgao/pi-cc-extensions/README.md +7 -7
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +25 -2
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +24 -1
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -4
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +47 -5
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/mcp-chip.ts +136 -0
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +56 -11
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +36 -4
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +11 -2
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +303 -0
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +1 -1
  18. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +36 -0
  19. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +2 -2
  20. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +2 -2
  21. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +88 -34
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +6 -5
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +1 -1
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +31 -6
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/message-display.ts +3 -3
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +3 -0
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +173 -36
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +1 -0
  29. package/node_modules/@herbertgao/pi-cc-extensions/package.json +6 -4
  30. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  31. package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
  32. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +3 -2
  33. package/node_modules/@herbertgao/sol-pi/CONTRIBUTING.md +22 -0
  34. package/node_modules/@herbertgao/sol-pi/README.md +36 -17
  35. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +10 -6
  36. package/node_modules/@herbertgao/sol-pi/agents-install.md +15 -12
  37. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +24 -8
  38. package/node_modules/@herbertgao/sol-pi/docs/configuration.md +2 -2
  39. package/node_modules/@herbertgao/sol-pi/docs/star-history.md +18 -0
  40. package/node_modules/@herbertgao/sol-pi/package.json +4 -2
  41. package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +1 -1
  42. package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +1 -1
  43. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +23 -4
  44. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +32 -1
  45. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +3 -2
  46. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +1 -1
  47. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +27 -7
  48. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +137 -41
  49. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +1 -0
  50. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +2 -1
  51. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/projection.ts +58 -0
  52. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +28 -6
  53. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +2 -1
  54. package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +15 -2
  55. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  56. package/node_modules/@pi-plugins/fast-mode/README.md +7 -1
  57. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
  58. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +7 -1
  59. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  60. package/node_modules/@pi-plugins/fast-mode/package.json +5 -5
  61. package/node_modules/pi-antigravity/README.md +3 -0
  62. package/node_modules/pi-antigravity/package.json +8 -8
  63. package/node_modules/pi-antigravity/src/auth/oauth.ts +6 -3
  64. package/node_modules/pi-antigravity/src/index.ts +114 -110
  65. package/node_modules/pi-antigravity/src/stream/stream.ts +1 -1
  66. package/node_modules/pi-antigravity/src/utils/util.ts +18 -1
  67. package/node_modules/pi-multi-account/CHANGELOG.md +20 -0
  68. package/node_modules/pi-multi-account/README.md +46 -8
  69. package/node_modules/pi-multi-account/config-file-transaction.ts +42 -0
  70. package/node_modules/pi-multi-account/index.ts +255 -269
  71. package/node_modules/pi-multi-account/model-pins.ts +36 -0
  72. package/node_modules/pi-multi-account/package.json +9 -7
  73. package/node_modules/pi-multi-account/slot-proxy-auth.ts +12 -2
  74. package/node_modules/pi-multi-account/slot-proxy.ts +27 -5
  75. package/node_modules/pi-web-access/CHANGELOG.md +17 -0
  76. package/node_modules/pi-web-access/README.md +6 -3
  77. package/node_modules/pi-web-access/brave-rate-limit.ts +170 -0
  78. package/node_modules/pi-web-access/brave.ts +28 -11
  79. package/node_modules/pi-web-access/dist/index.js +202 -33
  80. package/node_modules/pi-web-access/gemini-search.ts +2 -5
  81. package/node_modules/pi-web-access/index.ts +13 -7
  82. package/node_modules/pi-web-access/openai-search.ts +24 -10
  83. package/node_modules/pi-web-access/package.json +1 -1
  84. package/node_modules/pi-web-access/summary-review.ts +8 -2
  85. package/node_modules/{@herbertgao/resume-from → resume-from}/README.md +16 -12
  86. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.d.ts +0 -5
  87. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.js +2 -3
  88. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.d.ts +2 -2
  89. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.d.ts +3 -0
  90. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.js +27 -15
  91. package/node_modules/{@herbertgao/resume-from/dist/adapters/pi → resume-from/dist/adapters/claude-code}/redaction.js +16 -3
  92. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.d.ts +2 -4
  93. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.js +1 -1
  94. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.d.ts +2 -4
  95. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.js +1 -2
  96. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/read.d.ts +16 -0
  97. package/node_modules/resume-from/dist/adapters/codex/read.js +723 -0
  98. package/node_modules/{@herbertgao/resume-from/dist/adapters/claude-code → resume-from/dist/adapters/codex}/redaction.js +16 -3
  99. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.d.ts +44 -4
  100. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.js +88 -4
  101. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.d.ts +2 -2
  102. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.js +2 -2
  103. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.d.ts +5 -1
  104. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.js +10 -6
  105. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.d.ts +2 -2
  106. package/node_modules/{@herbertgao/resume-from/dist/adapters/codex → resume-from/dist/adapters/pi}/redaction.js +16 -3
  107. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.d.ts +2 -4
  108. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.js +2 -2
  109. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.d.ts +1 -1
  110. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.js +4 -4
  111. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.js +2 -2
  112. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.d.ts +2 -2
  113. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.js +31 -8
  114. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.d.ts +1 -1
  115. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.js +1 -2
  116. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.d.ts +4 -1
  117. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.js +2 -2
  118. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.d.ts +8 -6
  119. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.d.ts +10 -5
  120. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/finder.d.ts +2 -1
  121. package/node_modules/resume-from/dist/import/discovery/finder.js +269 -0
  122. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.d.ts +3 -3
  123. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.js +3 -3
  124. package/node_modules/resume-from/dist/import/pipeline.d.ts +28 -0
  125. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/pipeline.js +31 -11
  126. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.d.ts +2 -2
  127. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.js +9 -5
  128. package/node_modules/resume-from/dist/import/preview/warnings.d.ts +14 -0
  129. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/warnings.js +26 -20
  130. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.js +12 -2
  131. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.d.ts +9 -3
  132. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.d.ts +4 -4
  133. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.js +7 -4
  134. package/node_modules/resume-from/dist/platform/repo/reader.d.ts +3 -0
  135. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/reader.js +60 -20
  136. package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.d.ts +8 -1
  137. package/node_modules/{@herbertgao/resume-from → resume-from}/package.json +19 -32
  138. package/node_modules/{@herbertgao/resume-from → resume-from}/shims/pi/extensions/resume-from.js +2 -2
  139. package/package.json +17 -17
  140. package/node_modules/@herbertgao/resume-from/dist/adapters/codex/read.js +0 -270
  141. package/node_modules/@herbertgao/resume-from/dist/import/discovery/finder.js +0 -129
  142. package/node_modules/@herbertgao/resume-from/dist/import/pipeline.d.ts +0 -17
  143. package/node_modules/@herbertgao/resume-from/dist/import/preview/warnings.d.ts +0 -11
  144. package/node_modules/@herbertgao/resume-from/dist/platform/repo/reader.d.ts +0 -8
  145. /package/node_modules/{@herbertgao/resume-from → resume-from}/LICENSE +0 -0
  146. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.js +0 -0
  147. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.d.ts +0 -0
  148. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.js +0 -0
  149. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.d.ts +0 -0
  150. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.js +0 -0
  151. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.d.ts +0 -0
  152. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.js +0 -0
  153. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.d.ts +0 -0
  154. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.js +0 -0
  155. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/redaction.d.ts +0 -0
  156. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.d.ts +0 -0
  157. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.js +0 -0
  158. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.js +0 -0
  159. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.d.ts +0 -0
  160. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.d.ts +0 -0
  161. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.js +0 -0
  162. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/redaction.d.ts +0 -0
  163. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.d.ts +0 -0
  164. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.js +0 -0
  165. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.js +0 -0
  166. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.d.ts +0 -0
  167. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.js +0 -0
  168. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.d.ts +0 -0
  169. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.js +0 -0
  170. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.d.ts +0 -0
  171. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.js +0 -0
  172. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.d.ts +0 -0
  173. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.js +0 -0
  174. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/redaction.d.ts +0 -0
  175. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.d.ts +0 -0
  176. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.js +0 -0
  177. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.d.ts +0 -0
  178. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.js +0 -0
  179. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.d.ts +0 -0
  180. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.js +0 -0
  181. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.d.ts +0 -0
  182. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.js +0 -0
  183. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.d.ts +0 -0
  184. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.js +0 -0
  185. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.d.ts +0 -0
  186. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.js +0 -0
  187. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.d.ts +0 -0
  188. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.js +0 -0
  189. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.d.ts +0 -0
  190. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.js +0 -0
  191. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.d.ts +0 -0
  192. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.js +0 -0
  193. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.d.ts +0 -0
  194. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.js +0 -0
  195. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.d.ts +0 -0
  196. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.js +0 -0
  197. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.d.ts +0 -0
  198. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.d.ts +0 -0
  199. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.js +0 -0
  200. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.d.ts +0 -0
  201. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.js +0 -0
  202. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.d.ts +0 -0
  203. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.js +0 -0
  204. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.d.ts +0 -0
  205. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.js +0 -0
  206. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.d.ts +0 -0
  207. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.js +0 -0
  208. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.d.ts +0 -0
  209. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.js +0 -0
  210. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.d.ts +0 -0
  211. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.js +0 -0
  212. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.d.ts +0 -0
  213. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.js +0 -0
  214. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.js +0 -0
  215. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.js +0 -0
  216. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.d.ts +0 -0
  217. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.js +0 -0
  218. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.d.ts +0 -0
  219. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.js +0 -0
  220. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.d.ts +0 -0
  221. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.js +0 -0
  222. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.d.ts +0 -0
  223. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.js +0 -0
  224. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.d.ts +0 -0
  225. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.js +0 -0
  226. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.d.ts +0 -0
  227. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.js +0 -0
  228. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.js +0 -0
  229. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.d.ts +0 -0
  230. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.js +0 -0
  231. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.d.ts +0 -0
  232. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.js +0 -0
  233. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.d.ts +0 -0
  234. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.js +0 -0
  235. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.d.ts +0 -0
  236. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.d.ts +0 -0
  237. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.js +0 -0
  238. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.d.ts +0 -0
  239. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.js +0 -0
  240. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.d.ts +0 -0
  241. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.js +0 -0
  242. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.d.ts +0 -0
  243. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.js +0 -0
  244. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.d.ts +0 -0
  245. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.js +0 -0
  246. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.d.ts +0 -0
  247. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.js +0 -0
  248. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.d.ts +0 -0
  249. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.js +0 -0
  250. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.d.ts +0 -0
  251. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.d.ts +0 -0
  252. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.js +0 -0
  253. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.d.ts +0 -0
  254. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.js +0 -0
  255. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.d.ts +0 -0
  256. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.js +0 -0
  257. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.d.ts +0 -0
  258. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.js +0 -0
  259. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.d.ts +0 -0
  260. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.js +0 -0
  261. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.d.ts +0 -0
  262. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.js +0 -0
  263. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.d.ts +0 -0
  264. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.js +0 -0
  265. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.d.ts +0 -0
  266. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.js +0 -0
  267. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.js +0 -0
  268. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.d.ts +0 -0
  269. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.js +0 -0
  270. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.d.ts +0 -0
  271. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.js +0 -0
  272. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.d.ts +0 -0
  273. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.js +0 -0
  274. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.d.ts +0 -0
  275. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.js +0 -0
  276. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.d.ts +0 -0
  277. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.js +0 -0
  278. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.d.ts +0 -0
  279. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.js +0 -0
  280. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.d.ts +0 -0
  281. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.js +0 -0
  282. /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.js +0 -0
@@ -338,16 +338,18 @@ function toolCardBgRow(
338
338
  const inset = (n: number) => (outerBg ? `${outerBg}${" ".repeat(n)}\x1b[49m` : " ".repeat(n));
339
339
  return `${inset(leftInset)}${bgAnsi}${stable}\x1b[49m${inset(rightInset)}`;
340
340
  }
341
- /** edit/write 展开卡:保持原样式(userMessageBg Box),不应用工具卡深色/间距改动。 */
341
+ /** edit/write 展开卡:保持原样式(展开卡背景 Box),不应用工具卡深色/间距改动。 */
342
342
  function editWriteExpandedCard(theme: any): any {
343
343
  return new Box(
344
344
  1,
345
345
  1,
346
- typeof theme.bg === "function" ? (text: string) => theme.bg("userMessageBg", text) : undefined,
346
+ typeof theme.bg === "function"
347
+ ? (text: string) => theme.bg(config.expandedCardBackground, text)
348
+ : undefined,
347
349
  );
348
350
  }
349
351
 
350
- /** compact 展开面板:外卡片保持 userMessageBg;展开的 thinking 另包一层更深的
352
+ /** compact 展开面板:外卡片保持展开卡背景;展开的 thinking 另包一层更深的
351
353
  * 内卡(自身 Box 背景与外卡同色,不区分会糊在一起),工具卡直接铺在外卡背景上。
352
354
  * 每个子卡前面补 1 行分隔(上一条已经是空行时不再补),子卡自带的首尾空行会被裁掉,
353
355
  * 避免与外卡/内卡 padding 叠出双空行。
@@ -364,7 +366,7 @@ function layoutExpandedToolCard(
364
366
  toolHits = false,
365
367
  live = false,
366
368
  ): { lines: string[]; hits: Array<{ child: any; start: number; end: number }> } {
367
- const slot = "userMessageBg";
369
+ const slot = config.expandedCardBackground;
368
370
  const toolBgAnsi = darkenBgAnsi(theme, slot);
369
371
  /** live 每行前面的标记宽度(首行 `↳ `,其余对齐空格)。 */
370
372
  const markerWidth = live ? 2 : 0;
@@ -471,6 +473,8 @@ function compactRoundCard(
471
473
  | {
472
474
  width: number;
473
475
  theme: unknown;
476
+ /** 背景槽位也是面板行的输入:改配置后不能复用旧底色的整卡。 */
477
+ bgSlot: string;
474
478
  paints: unknown[];
475
479
  lines: string[];
476
480
  hits: Array<{ child: any; start: number; end: number }>;
@@ -478,6 +482,7 @@ function compactRoundCard(
478
482
  | undefined;
479
483
  const layout = (width: number) => {
480
484
  const theme = themeOf();
485
+ const bgSlot = config.expandedCardBackground;
481
486
  const innerWidth = contentWidth(width);
482
487
  const paints = children.map((child) => {
483
488
  const lines = child.render?.(innerWidth);
@@ -487,6 +492,7 @@ function compactRoundCard(
487
492
  paint &&
488
493
  paint.width === width &&
489
494
  paint.theme === theme &&
495
+ paint.bgSlot === bgSlot &&
490
496
  paint.paints.length === paints.length &&
491
497
  paint.paints.every((item, index) => item === paints[index])
492
498
  ) {
@@ -496,6 +502,7 @@ function compactRoundCard(
496
502
  paint = {
497
503
  width,
498
504
  theme,
505
+ bgSlot,
499
506
  paints,
500
507
  lines: laid.lines,
501
508
  hits: laid.hits,
@@ -697,7 +704,7 @@ function compactEditWriteLine(
697
704
  const iconPart = `${options.flushLeft ? "" : " "}${theme.fg(iconColor, icon)} `;
698
705
  const namePart = theme.fg("toolTitle", name);
699
706
  const hintText =
700
- options.hint !== false && component.expanded !== true ? ` • ${showMoreHintText()}` : "";
707
+ options.hint !== false && component.expanded !== true ? ` · ${showMoreHintText()}` : "";
701
708
  const fixedWidth =
702
709
  visibleWidth(iconPart) +
703
710
  visibleWidth(namePart) +
@@ -719,6 +726,8 @@ const compactRichDiffCache = new WeakMap<
719
726
  type CompactEditPaintHit = {
720
727
  width: number;
721
728
  theme: unknown;
729
+ /** 展开卡的背景槽位同样参与命中判断。 */
730
+ bgSlot: string;
722
731
  expanded: boolean;
723
732
  result: unknown;
724
733
  isPartial: boolean;
@@ -756,6 +765,7 @@ function compactEditWriteLines(
756
765
  hit &&
757
766
  hit.width === width &&
758
767
  hit.theme === theme &&
768
+ hit.bgSlot === config.expandedCardBackground &&
759
769
  hit.expanded === expanded &&
760
770
  hit.result === component.result &&
761
771
  hit.isPartial === isPartial &&
@@ -771,6 +781,7 @@ function compactEditWriteLines(
771
781
  compactEditPaintCache.set(component, {
772
782
  width,
773
783
  theme,
784
+ bgSlot: config.expandedCardBackground,
774
785
  expanded,
775
786
  result: component.result,
776
787
  isPartial,
@@ -901,7 +912,7 @@ function compactAssistantLineComponent(
901
912
  const pad = Math.max(0, options.pad ?? (Number(self.outputPad) || 0));
902
913
  const available = Math.max(0, width - pad);
903
914
  const hint = options.hint !== false;
904
- const hintText = hint ? ` • ${showMoreHintText()}` : "";
915
+ const hintText = hint ? ` · ${showMoreHintText()}` : "";
905
916
  const summaryWidth = Math.max(0, available - visibleWidth(hintText));
906
917
  const resolved = typeof summary === "function" ? summary() : summary;
907
918
  const runningActive = resolved.startsWith("Running...");
@@ -975,7 +986,7 @@ function compactStopStatusLine(status: string, pad = 0): any {
975
986
 
976
987
  /**
977
988
  * 槽位卡内的展开入口:卡里是只读围观,展开走摘要行自己的 hint,卡内不再重复提示。
978
- * 提示有两处来源——我们的 showMoreHintText(`… +N more lines • click to show more`)与
989
+ * 提示有两处来源——我们的 showMoreHintText(`… +N more lines · click to show more`)与
979
990
  * pi 原生工具卡(`… (N earlier lines, ctrl+o to expand)`),所以按渲染结果收尾裁剪。
980
991
  * 只去掉动作词,`(N more lines)` 这类计数保留。
981
992
  */
@@ -987,7 +998,8 @@ const SLOT_HINT_PATTERNS: RegExp[] = [
987
998
  // 只去掉动作词,收尾括号与计数保留。
988
999
  new RegExp(String.raw`,\s*[^()]*?${EXPAND_ACTION}(?=\))`),
989
1000
  // 直接挂在行尾:整段去掉。
990
- new RegExp(String.raw`\s*(?:•\s*)?${EXPAND_ACTION}\s*$`),
1001
+ // 尾部分隔点:ccstyle 统一 `·`,同时兼容旧帧与 pi 原生的 `•`
1002
+ new RegExp(String.raw`\s*(?:[•·]\s*)?${EXPAND_ACTION}\s*$`),
991
1003
  ];
992
1004
 
993
1005
  function stripSlotHint(line: string): string {
@@ -1357,7 +1369,20 @@ export function installCompactMode(deps: CompactModeInstallDeps): CompactModeHoo
1357
1369
  const tail: MountedRoundTail = { host: undefined, container: undefined, parts: [], round };
1358
1370
  const host: any = {
1359
1371
  outputPad: Number(round.anchor?.outputPad) || 0,
1372
+ children: [],
1360
1373
  render: (width: number) => tail.parts.flatMap((part: any) => part?.render?.(width) ?? []),
1374
+ childAtRow(localRow: number, width: number) {
1375
+ let offset = 0;
1376
+ for (const part of tail.parts) {
1377
+ const lines = part?.render?.(width);
1378
+ const count = Array.isArray(lines) ? lines.length : 0;
1379
+ if (localRow < offset + count) {
1380
+ return part?.childAtRow?.(localRow - offset, width) ?? null;
1381
+ }
1382
+ offset += count;
1383
+ }
1384
+ return null;
1385
+ },
1361
1386
  invalidate: () => {
1362
1387
  for (const part of tail.parts) part?.invalidate?.();
1363
1388
  },
@@ -1373,6 +1398,10 @@ export function installCompactMode(deps: CompactModeInstallDeps): CompactModeHoo
1373
1398
  // 点击/悬停归属与 anchor 同一展开入口;toggle 每次 renderRound 重建,按值转发。
1374
1399
  // 经 tail.round 动态解引用:重建过户时 anchor 可能换成别的组件。
1375
1400
  ensureAssistantSetExpanded(host);
1401
+ Object.defineProperty(host, "roundAnchor", {
1402
+ configurable: true,
1403
+ get: () => tail.round?.anchor,
1404
+ });
1376
1405
  host[ASSISTANT_TOGGLE_ROUND_KEY] = (expanded: boolean) =>
1377
1406
  tail.round?.anchor?.[ASSISTANT_TOGGLE_ROUND_KEY]?.(expanded);
1378
1407
  tail.host = host;
@@ -1527,6 +1556,7 @@ export function installCompactMode(deps: CompactModeInstallDeps): CompactModeHoo
1527
1556
  }
1528
1557
  const tail = ensureTailHost(round);
1529
1558
  tail.parts = makeParts(tail.host);
1559
+ tail.host.children = tail.parts;
1530
1560
  syncTailPosition(round);
1531
1561
  };
1532
1562
 
@@ -1679,8 +1709,10 @@ export function installCompactMode(deps: CompactModeInstallDeps): CompactModeHoo
1679
1709
  }
1680
1710
 
1681
1711
  if (round.anchor.expanded === true) {
1682
- // 展开卡自带全部内容,尾行摘下(收起时在折叠分支重新挂载)。
1683
- unmountRoundTail(round);
1712
+ // 展开内容留在摘要行那个位置:回合最后一个成员(含 write/edit)之后。
1713
+ // 放进 anchor 内部会跳到回合起点,盖到中间的 write/edit 上面。
1714
+ // anchor 未挂进 transcript 时没有这个位置,退回 anchor 内部。
1715
+ const mounted = Boolean(tailContainerOf(round.anchor));
1684
1716
  const toolsById = new Map<string, any>();
1685
1717
  for (const tool of trackedToolComponents) {
1686
1718
  if (typeof tool?.toolCallId === "string") toolsById.set(tool.toolCallId, tool);
@@ -1790,7 +1822,20 @@ export function installCompactMode(deps: CompactModeInstallDeps): CompactModeHoo
1790
1822
  !explicitRoundToolIds.has(String(tool.toolCallId ?? "")),
1791
1823
  );
1792
1824
  flushPanel();
1793
- for (const child of anchorChildren) round.anchor.contentContainer.addChild(child);
1825
+ if (mounted) {
1826
+ // 正文留在各自的 assistant 消息上,面板挂回摘要行原位。
1827
+ const outside: any[] = [];
1828
+ const panel: any[] = [];
1829
+ for (const child of anchorChildren) {
1830
+ (typeof child?.childAtRow === "function" ? panel : outside).push(child);
1831
+ }
1832
+ for (const child of outside) round.anchor.contentContainer.addChild(child);
1833
+ if (panel.length > 0) mountRoundTail(round, () => panel);
1834
+ else unmountRoundTail(round);
1835
+ } else {
1836
+ unmountRoundTail(round);
1837
+ for (const child of anchorChildren) round.anchor.contentContainer.addChild(child);
1838
+ }
1794
1839
  // 展开卡内工具会显示 error,外层仍挂 abort/length,避免只藏在折叠工具里。
1795
1840
  appendStopStatus(round.anchor, stopStatus);
1796
1841
  return;
@@ -33,6 +33,11 @@ import {
33
33
  } from "./tool/result.ts";
34
34
  import { oneLine } from "../utils/format.ts";
35
35
  import { showMoreHintText } from "./tool/show-more-hint.ts";
36
+ import {
37
+ CODEMODE_TOOL_NAME,
38
+ codemodeExpandedBody,
39
+ createCodemodeResultComponent,
40
+ } from "./tool/codemode.ts";
36
41
  import { countWriteDiffStats } from "./tool/diff/diff-renderer.ts";
37
42
  import { renderRichToolResult, type WriteExecutionMetadataStore } from "./tool/diff/index.ts";
38
43
  import { getMessageDisplayTheme } from "./tool/message-display.ts";
@@ -157,7 +162,7 @@ function taskListSummary(tasks: ParsedTask[]): string {
157
162
  counts.completed ? `${counts.completed} completed` : "",
158
163
  ]
159
164
  .filter(Boolean)
160
- .join(" • ");
165
+ .join(" · ");
161
166
  }
162
167
 
163
168
  function renderExpandedTaskResult(
@@ -305,13 +310,38 @@ function createCcstyleTool(
305
310
  }
306
311
 
307
312
  const expanded = isToolExpanded(options, context);
313
+ const isError = Boolean(options?.isError || context?.isError);
314
+ // codemode:折叠态自己画子调用树,展开态给全部子调用与去掉脚本头的输出
315
+ if (toolName === CODEMODE_TOOL_NAME) {
316
+ if (!options?.isPartial) setToolVisualState(context, isError ? "error" : "success");
317
+ if (expanded) {
318
+ return renderExpandedToolResult(
319
+ codemodeExpandedBody(result),
320
+ theme,
321
+ isError,
322
+ context?.lastComponent,
323
+ context?.args,
324
+ context,
325
+ true,
326
+ );
327
+ }
328
+ // 折叠态不再复用展开视图,免得 hover/鼠标命中指向已隐藏的组件
329
+ if (context?.state) context.state.ccstyleIoView = undefined;
330
+ const toolCallId = context?.toolCallId;
331
+ return createCodemodeResultComponent({
332
+ result,
333
+ theme,
334
+ running: Boolean(options?.isPartial),
335
+ isError,
336
+ isHovered: () => isToolCallHovered(toolCallId),
337
+ });
338
+ }
308
339
  if (options?.isPartial) {
309
340
  // 展开态贴左(Box 提供 1 格 pad);折叠态保持 3 格对齐标题
310
341
  const pending = expanded ? "↳ Pending…" : " ↳ Pending…";
311
342
  return new Text(theme.fg("muted", pending), 0, 0);
312
343
  }
313
344
 
314
- const isError = options?.isError || context?.isError;
315
345
  setToolVisualState(context, isError ? "error" : "success");
316
346
  const toolCallId = context?.toolCallId;
317
347
  if (shouldRenderRichDiff(config.mode, toolName, Boolean(isError))) {
@@ -356,7 +386,7 @@ function createCcstyleTool(
356
386
  : "Done";
357
387
  const expandable = !expanded && (tasks.length > 0 || hasExpandableDetail(text, args));
358
388
  const hintText = showMoreHintText();
359
- const hintPrefix = expandable ? theme.fg("dim", " • ") : "";
389
+ const hintPrefix = expandable ? theme.fg("dim", " · ") : "";
360
390
  const hint = expandable ? hintPrefix + theme.fg("dim", hintText) : "";
361
391
  const hoveredHint = expandable ? hintPrefix + theme.fg("text", hintText) : "";
362
392
  if (expanded) {
@@ -669,7 +699,9 @@ export function installToolExpandedBackground(): () => void {
669
699
  if (box) {
670
700
  box.paddingX = 1;
671
701
  box.paddingY = 1;
672
- if (box.setBgFn) box.setBgFn((text: string) => theme.bg("userMessageBg", text));
702
+ if (box.setBgFn) {
703
+ box.setBgFn((text: string) => theme.bg(config.expandedCardBackground, text));
704
+ }
673
705
  }
674
706
  },
675
707
  original,
@@ -144,7 +144,10 @@ function tryOpenToolIoShowMore(region: InteractionRegion): boolean {
144
144
  }
145
145
  const title = section === "input" ? "Tool Input" : "Tool Output";
146
146
  const content = section === "input" ? ioView.getInputBody() : ioView.getOutputBody();
147
- void showTextPreview({ ui }, title, content || "(empty)");
147
+ // 整段就是代码时包一层围栏:弹框按 Markdown 渲染,围栏代码块才会着色
148
+ const fence = section === "input" ? ioView.getInputCodeFence() : undefined;
149
+ const preview = fence ? `\`\`\`${fence.language}\n${fence.code}\n\`\`\`` : content;
150
+ void showTextPreview({ ui }, title, preview || "(empty)");
148
151
  return true;
149
152
  }
150
153
 
@@ -433,7 +436,13 @@ function handleFullscreenToolClick(tui: any, packet: SgrMousePacket): boolean {
433
436
  for (const other of others) {
434
437
  if (other !== component && other.expanded) {
435
438
  // 展开 round 卡内 thinking/工具时,外层 compact 卡是它的容器,不能收起。
436
- if ((isThinking || isTool) && isCompactAssistantComponent(other)) continue;
439
+ // 面板挂在摘要行时,anchor 与摘要行是同一张外层卡,点内部工具不能收起它。
440
+ if (
441
+ (isThinking || isTool) &&
442
+ isCompactAssistantComponent(other) &&
443
+ (other === target.owner || other === target.owner?.roundAnchor)
444
+ )
445
+ continue;
437
446
  other.setExpanded(false);
438
447
  other.invalidate?.();
439
448
  }
@@ -0,0 +1,303 @@
1
+ /**
2
+ * codemode 的结果渲染:折叠态把子调用摊成工具组那样的树,最后一行用 └ 收尾。
3
+ *
4
+ * 数据来自 `result.details.calls`(CodemodeNestedCall[],partial 更新里也有),所以运行中就能
5
+ * 看到子调用进度。两个坑:
6
+ *
7
+ * - 子调用不会单独成行:pi 会跳过带 `parentToolCallId` 的 tool_execution_start,进度只能在这里显示。
8
+ * - 输出以 "Script completed\nWall time …\nOutput:\n" 开头(pi 原生也切掉),行数统计与展开正文都得去掉它,
9
+ * 否则折叠摘要会多算 3 行。
10
+ */
11
+ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
12
+ import { stripAnsi } from "../../utils/ansi-text.ts";
13
+ import { toolLoadingIcon } from "../../utils/tool-loading-icon.ts";
14
+ import { sanitizeToolResultText } from "../../utils/tool-result-sanitize.ts";
15
+ import { mcpToolTitle } from "./mcp-title.ts";
16
+ import {
17
+ type ToolCallSummary,
18
+ humanizeToolLabel,
19
+ renderToolSummary,
20
+ toolCallSummary,
21
+ } from "./names.ts";
22
+ import { showMoreHintText } from "./show-more-hint.ts";
23
+ import { headTruncateToWidth, toolViewportWidth } from "./result.ts";
24
+
25
+ export const CODEMODE_TOOL_NAME = "codemode";
26
+
27
+ /** 折叠态最多列几条子调用(与 pi 原生一致,更早的折叠成一行)。 */
28
+ const COLLAPSED_CALL_LIMIT = 8;
29
+ /** 折叠态正文缩进,与 ` ↳ …` 对齐。 */
30
+ const INDENT = " ";
31
+
32
+ /** 脚本结果头;只有整块正文恰好等于它时才算头。 */
33
+ const SCRIPT_HEADER = /^Script (completed|failed)\nWall time [\d.]+ seconds\nOutput:\n$/;
34
+
35
+ export type CodemodeNestedCall = {
36
+ name?: unknown;
37
+ /** 紧凑 JSON;过长时 pi 会截断,截断后 JSON.parse 会失败。 */
38
+ args?: unknown;
39
+ status?: unknown;
40
+ durationMs?: unknown;
41
+ error?: unknown;
42
+ cost?: unknown;
43
+ };
44
+
45
+ export function codemodeCalls(result: any): CodemodeNestedCall[] {
46
+ const calls = result?.details?.calls;
47
+ return Array.isArray(calls) ? calls : [];
48
+ }
49
+
50
+ /** 去掉脚本头之后的输出正文(已清理终端转义)。 */
51
+ export function codemodeOutputText(result: any): string {
52
+ const content = Array.isArray(result?.content) ? result.content : [];
53
+ const blocks = content
54
+ .filter((item: any) => item?.type === "text")
55
+ .map((item: any) => String(item?.text ?? ""));
56
+ if (blocks.length > 0 && SCRIPT_HEADER.test(blocks[0]!)) blocks.shift();
57
+ return sanitizeToolResultText(blocks.join("\n"), 16_384).trim();
58
+ }
59
+
60
+ export function codemodeOutputLineCount(result: any): number {
61
+ const text = codemodeOutputText(result).replace(/\n+$/, "");
62
+ return text ? text.split("\n").length : 0;
63
+ }
64
+
65
+ /** 汇总行片段(按重要度先后排列,渲染时从尾部丢以适配宽度)。 */
66
+ export function codemodeSummaryParts(
67
+ calls: readonly CodemodeNestedCall[],
68
+ outputLines: number,
69
+ running: boolean,
70
+ ): string[] {
71
+ const total = calls.length;
72
+ const failed = calls.filter((call) => call?.status === "error").length;
73
+ const runningCount = calls.filter((call) => !call?.status || call?.status === "running").length;
74
+ const parts: string[] = [];
75
+ if (running) {
76
+ if (runningCount)
77
+ parts.push(`${runningCount} ${runningCount === 1 ? "call" : "calls"} running`);
78
+ const done = total - runningCount;
79
+ if (done) parts.push(`${done} done`);
80
+ if (failed) parts.push(`${failed} failed`);
81
+ return parts.length ? parts : ["running…"];
82
+ }
83
+ if (total) parts.push(`${total} ${total === 1 ? "call" : "calls"}`);
84
+ if (failed) parts.push(`${failed} failed`);
85
+ if (outputLines) parts.push(`${outputLines} ${outputLines === 1 ? "line" : "lines"} output`);
86
+ return parts.length ? parts : ["Done"];
87
+ }
88
+
89
+ /** 宽度不够时从尾部丢片段(先丢输出行数,再丢条数),不断词。 */
90
+ function fitSummaryParts(parts: readonly string[], width: number): string {
91
+ const kept = [...parts];
92
+ while (kept.length > 1 && visibleWidth(kept.join(" · ")) > width) kept.pop();
93
+ const text = kept.join(" · ");
94
+ return visibleWidth(text) <= width ? text : headTruncateToWidth(text, width);
95
+ }
96
+
97
+ function formatDuration(ms: number): string {
98
+ return ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(1)}s`;
99
+ }
100
+
101
+ /** 与 pi 原生一致:不到 1 分显示两位有效数字。 */
102
+ function formatCost(cost: number): string {
103
+ return `$${cost >= 0.01 ? cost.toFixed(2) : cost.toPrecision(2)}`;
104
+ }
105
+
106
+ /** 单次子调用的耗时/费用(纯文本,着色由调用方决定)。 */
107
+ function callMeta(call: CodemodeNestedCall): string[] {
108
+ const out: string[] = [];
109
+ const duration = call?.durationMs;
110
+ if (typeof duration === "number" && Number.isFinite(duration) && duration >= 0) {
111
+ out.push(formatDuration(duration));
112
+ }
113
+ const cost = call?.cost;
114
+ if (typeof cost === "number" && Number.isFinite(cost) && cost > 0) out.push(formatCost(cost));
115
+ return out;
116
+ }
117
+
118
+ /** 截断的紧凑 JSON 里能恢复出的对象;complete 标记是否原本就完整。 */
119
+ type ParsedCallArgs = { args: Record<string, unknown>; complete: boolean };
120
+
121
+ /** 截断串尾部补闭合符号的候选:先试收字符串,再收数组与对象。 */
122
+ const REPAIR_CLOSERS = ['"}', '"}]}', '"}}', "}", "]}"];
123
+
124
+ /**
125
+ * 子调用参数:先直接解析;pi 从尾部截断过(超 200 字符)的串再补救一次——
126
+ * 逐字回退补上缺少的闭合符号,取最长能解析出的对象。截断保留的是开头字段,
127
+ * path/command/pattern 这类先出现的取得到;被切掉的尾部值本就无从恢复。
128
+ */
129
+ function parseCallArgs(raw: string): ParsedCallArgs | undefined {
130
+ try {
131
+ const parsed = JSON.parse(raw);
132
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
133
+ return { args: parsed, complete: true };
134
+ }
135
+ return undefined;
136
+ } catch {
137
+ // 截断串:走补救
138
+ }
139
+ const body = raw.endsWith("...") ? raw.slice(0, -3) : raw;
140
+ if (!body.startsWith("{")) return undefined;
141
+ for (let end = body.length; end > 0; end--) {
142
+ for (const closer of REPAIR_CLOSERS) {
143
+ try {
144
+ const parsed = JSON.parse(body.slice(0, end) + closer);
145
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
146
+ // 空对象等于没恢复出字段,再短也只会更空
147
+ if (Object.keys(parsed).length === 0) return undefined;
148
+ return { args: parsed, complete: false };
149
+ } catch {
150
+ // 试下一个闭合符号 / 下一个长度
151
+ }
152
+ }
153
+ }
154
+ return undefined;
155
+ }
156
+
157
+ /** 子调用参数:能解析就复用字段链摘要,认不出(截断后也不成形)就贴原文。 */
158
+ function callSummary(call: CodemodeNestedCall): ToolCallSummary {
159
+ const name = String(call?.name ?? "tool");
160
+ const title = mcpToolTitle({ toolName: name }) ?? humanizeToolLabel(name);
161
+ const raw = typeof call?.args === "string" ? call.args : "";
162
+ if (!raw) return { main: title, detail: "" };
163
+ const parsed = parseCallArgs(raw);
164
+ if (parsed) {
165
+ const summary = toolCallSummary(name, parsed.args, { title, variant: "default" });
166
+ // 截断串只恢复出部分字段:字段链认出来了才用,认不出仍旧贴原文,
167
+ // 免得把不完整的 JSON 当成完整入参摊开。
168
+ if (parsed.complete || summary.payload === undefined) return summary;
169
+ }
170
+ return { main: title, detail: "", payload: raw };
171
+ }
172
+
173
+ function statusIcon(status: unknown, theme: any): string {
174
+ switch (status) {
175
+ case "ok":
176
+ return theme.fg("success", "✓");
177
+ case "error":
178
+ return theme.fg("error", "✗");
179
+ case "cancelled":
180
+ return theme.fg("muted", "⊘");
181
+ default:
182
+ // 运行中:帧在 render() 内取,动画定时器只负责 requestRender
183
+ return theme.fg("accent", toolLoadingIcon());
184
+ }
185
+ }
186
+
187
+ function callRow(call: CodemodeNestedCall, theme: any, rowWidth: number): string {
188
+ const fg = theme.fg.bind(theme);
189
+ const prefix = `${INDENT}${fg("dim", "├")} ${statusIcon(call?.status, theme)} `;
190
+ // detail(read 的 offset/limit 等)与工具组行一样接在标题后
191
+ const summary = callSummary(call);
192
+ const detail = fg("dim", summary.detail);
193
+ const suffix = callMeta(call)
194
+ .map((text) => ` ${fg("dim", text)}`)
195
+ .join("");
196
+ const mainWidth = Math.max(
197
+ 0,
198
+ rowWidth - visibleWidth(prefix) - visibleWidth(detail) - visibleWidth(suffix),
199
+ );
200
+ const row = `${prefix}${renderToolSummary(summary, mainWidth, fg)}${detail}${suffix}`;
201
+ return truncateToWidth(row, rowWidth, "");
202
+ }
203
+
204
+ /**
205
+ * 折叠态(含运行中的 partial 更新)的行:子调用全用 ├,最后一行用 └ 收汇总,
206
+ * 与工具组的树一致。
207
+ */
208
+ export function codemodeCollapsedLines(options: {
209
+ result: any;
210
+ theme: any;
211
+ running: boolean;
212
+ isError: boolean;
213
+ width: number;
214
+ /** 鼠标悬停整卡时展开提示用 text 色,与其它折叠卡一致。 */
215
+ hovered?: boolean;
216
+ }): string[] {
217
+ const { result, theme, running, isError } = options;
218
+ const fg = theme.fg.bind(theme);
219
+ const calls = codemodeCalls(result);
220
+ const rowWidth = toolViewportWidth(options.width);
221
+ const shown = calls.slice(-COLLAPSED_CALL_LIMIT);
222
+ const lines: string[] = [];
223
+ if (shown.length < calls.length) {
224
+ const hidden = calls.length - shown.length;
225
+ lines.push(
226
+ truncateToWidth(
227
+ `${INDENT}${fg("dim", "├")} ${fg("dim", `… ${hidden} earlier ${hidden === 1 ? "call" : "calls"}`)}`,
228
+ rowWidth,
229
+ "",
230
+ ),
231
+ );
232
+ }
233
+ for (const call of shown) lines.push(callRow(call, theme, rowWidth));
234
+
235
+ const summary = codemodeSummaryParts(calls, codemodeOutputLineCount(result), running);
236
+ // 没有子调用时不画衔接符,避免孤零零一个 └
237
+ const prefix = shown.length > 0 ? `${INDENT}${fg("dim", "└")} ` : INDENT;
238
+ const hint = running ? "" : ` ${fg(options.hovered ? "text" : "dim", `· ${showMoreHintText()}`)}`;
239
+ const bodyWidth = Math.max(1, rowWidth - visibleWidth(prefix) - visibleWidth(hint));
240
+ const body = fg(isError ? "error" : "muted", fitSummaryParts(summary, bodyWidth));
241
+ lines.push(truncateToWidth(`${prefix}${body}${hint}`, rowWidth, ""));
242
+ return lines;
243
+ }
244
+
245
+ /** 展开态正文:全部子调用(含错误文本)+ 去掉脚本头的输出 + 全量输出路径。 */
246
+ export function codemodeExpandedBody(result: any): string {
247
+ const parts: string[] = [];
248
+ const calls = codemodeCalls(result);
249
+ if (calls.length > 0) {
250
+ parts.push(
251
+ calls
252
+ .map((call) => {
253
+ const name = String(call?.name ?? "tool");
254
+ const raw = typeof call?.args === "string" ? call.args : "";
255
+ const meta = callMeta(call);
256
+ const head = [name, raw, ...meta].filter(Boolean).join(" ");
257
+ const error =
258
+ typeof call?.error === "string" && call.error
259
+ ? `\n ${call.error.split("\n").join("\n ")}`
260
+ : "";
261
+ return `${head}${error}`;
262
+ })
263
+ .join("\n"),
264
+ );
265
+ }
266
+ const output = codemodeOutputText(result);
267
+ if (output) parts.push(output);
268
+ const full = result?.details?.fullOutputPath;
269
+ if (typeof full === "string" && full.trim()) parts.push(`Full output: ${full.trim()}`);
270
+ return parts.join("\n\n");
271
+ }
272
+
273
+ /**
274
+ * 折叠态结果组件。只有汇总行是展开入口,与 diff 卡一致;行本身很便宜,
275
+ * 不自己缓存(settled 卡另有整行 paint 缓存,运行中本就按帧重算)。hover 状态在
276
+ * render() 内取,才能跟鼠标 motion 的 requestRender 同步。
277
+ */
278
+ export function createCodemodeResultComponent(options: {
279
+ result: any;
280
+ theme: any;
281
+ running: boolean;
282
+ isError: boolean;
283
+ /** 折叠态 hover 查询,与 diff 卡同一套(mouse/hover)。 */
284
+ isHovered?: () => boolean;
285
+ }): any {
286
+ const { result, theme, running, isError } = options;
287
+ return {
288
+ render(width: number): string[] {
289
+ return codemodeCollapsedLines({
290
+ result,
291
+ theme,
292
+ running,
293
+ isError,
294
+ width,
295
+ hovered: options.isHovered?.() ?? false,
296
+ });
297
+ },
298
+ invalidate(): void {},
299
+ isCollapsedHintLine(plainLine: string): boolean {
300
+ return !running && /(click to show more|to show more)\s*$/.test(stripAnsi(plainLine));
301
+ },
302
+ };
303
+ }
@@ -81,7 +81,7 @@ export function renderHeaderRows(
81
81
 
82
82
  const summaryPieces = [...buildDiffSummaryBasePieces(stats, theme), theme.fg("muted", mode)];
83
83
 
84
- const summary = summaryPieces.join(mode === "split" ? " " : theme.fg("muted", " • "));
84
+ const summary = summaryPieces.join(mode === "split" ? " " : theme.fg("muted", " · "));
85
85
  const meter = renderDiffStatBar(stats, width, theme);
86
86
  if (!meter) {
87
87
  return [{ text: stabilizeBackgroundResets(truncateToWidth(summary, width)), hunkIndex: null }];
@@ -91,6 +91,42 @@ export function createCodeLineHighlighter(
91
91
  };
92
92
  }
93
93
 
94
+ /**
95
+ * 通用代码块着色(codemode 的 `code` 字段等):先用 pi 的同步 highlightCode 打底,
96
+ * 首帧就有颜色;再用 shiki 异步升级(与 diff 共用缓存与主题解析),落地后回调
97
+ * invalidate 重画。返回行数组,按源行一一对应;语言不识或未就绪时给打底结果。
98
+ */
99
+ export function createCodeBlockHighlighter(
100
+ code: string,
101
+ language: string | undefined,
102
+ theme: DiffTheme,
103
+ invalidate?: () => void,
104
+ ): () => string[] {
105
+ const cleanCode = sanitizeToolResultText(code).replace(/\r/g, "");
106
+ const cleanLines = cleanCode.split("\n").map(cleanCodeLine);
107
+ if (!language || !shouldHighlightCodeBlock(cleanCode)) {
108
+ return () => cleanLines.map(sanitizeAnsiForThemedOutput);
109
+ }
110
+ let fallback: string[];
111
+ try {
112
+ fallback = highlightCode(cleanCode, language).map(sanitizeAnsiForThemedOutput);
113
+ } catch {
114
+ fallback = cleanLines.map(sanitizeAnsiForThemedOutput);
115
+ }
116
+ const shikiTheme = resolveShikiTheme(theme);
117
+ let highlighted: string[] | undefined;
118
+ const resolve = () => {
119
+ if (highlighted) return;
120
+ const result = shikiHighlightCache.get(cleanCode, language, shikiTheme, fallback, invalidate);
121
+ if (result) highlighted = result.map(sanitizeAnsiForThemedOutput);
122
+ };
123
+ resolve();
124
+ return () => {
125
+ resolve();
126
+ return highlighted ?? fallback;
127
+ };
128
+ }
129
+
94
130
  export function highlightDiffLine(
95
131
  codeText: string,
96
132
  entry: DiffLineEntry,
@@ -52,8 +52,8 @@ export function buildDiffSummaryText(stats: DiffSummaryStats, width: number): st
52
52
  }
53
53
 
54
54
  const summaryCandidates = [
55
- `↳ diff +${stats.added} -${stats.removed} • ${stats.hunks} ${pluralize(stats.hunks, "hunk")} • ${stats.files} ${pluralize(stats.files, "file")}`,
56
- `↳ diff +${stats.added} -${stats.removed} • ${stats.hunks}h • ${stats.files}f`,
55
+ `↳ diff +${stats.added} -${stats.removed} · ${stats.hunks} ${pluralize(stats.hunks, "hunk")} · ${stats.files} ${pluralize(stats.files, "file")}`,
56
+ `↳ diff +${stats.added} -${stats.removed} · ${stats.hunks}h · ${stats.files}f`,
57
57
  `↳ diff +${stats.added} -${stats.removed}`,
58
58
  `+${stats.added} -${stats.removed}`,
59
59
  "diff",