@code-yeongyu/senpi 2026.9.23-5 → 2026.9.24-2

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 (315) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/bundle/chunks/{anthropic-messages-77YBORJ5.js → anthropic-messages-UPLQFNTT.js} +2 -2
  3. package/dist/bundle/chunks/{app-server-command-BGT65PGC.js → app-server-command-UHPJ2C4D.js} +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-PSESFNHN.js → azure-openai-responses-XAR2E66I.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-WXIRFRXY.js → chunk-2PLPSKHD.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-7PANH3NB.js → chunk-3WBSBDBX.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-BBOQ5H4W.js → chunk-6WBYI25N.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-RG3UEFSF.js → chunk-7DY7UYLL.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-VKBY4F76.js → chunk-BSOJHK4W.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-3XHWW7SQ.js → chunk-CLZVNQW3.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-ORCF262V.js → chunk-EJKCBRYK.js} +3 -3
  12. package/dist/bundle/chunks/chunk-J7IUURQ6.js +8 -0
  13. package/dist/bundle/chunks/{chunk-PSMTQDII.js → chunk-JRQSHZPP.js} +15 -9
  14. package/dist/bundle/chunks/{chunk-DUV3UFKX.js → chunk-MKAM7IRH.js} +1 -1
  15. package/dist/bundle/chunks/chunk-MO2U7YRX.js +11 -0
  16. package/dist/bundle/chunks/{chunk-ZEFQYQOU.js → chunk-NGHOUIPR.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-XDSQYM4F.js → chunk-NKVUDCGZ.js} +2 -2
  18. package/dist/bundle/chunks/{chunk-J3QXPP4T.js → chunk-ONR57UMO.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-TQDWU3ZQ.js → chunk-SYQVC7UM.js} +1 -1
  20. package/dist/bundle/chunks/chunk-TTHMOL5G.js +2 -0
  21. package/dist/bundle/chunks/{chunk-NNHFMZD5.js → chunk-UBPMXBOJ.js} +1 -1
  22. package/dist/bundle/chunks/chunk-WASCMT6Y.js +2 -0
  23. package/dist/bundle/chunks/{chunk-EN6KDFY2.js → chunk-WISJJQ4K.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-IVYZMSFY.js → chunk-WL5EQYNL.js} +1 -1
  25. package/dist/bundle/chunks/{chunk-LC6SZTVE.js → chunk-WTSAB6AE.js} +1 -1
  26. package/dist/bundle/chunks/{chunk-HKE42SWX.js → chunk-Y54V65MS.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-3RN6BFG2.js → chunk-YBC274GY.js} +4 -4
  28. package/dist/bundle/chunks/{chunk-RRSND33J.js → chunk-YKU45B65.js} +54 -54
  29. package/dist/bundle/chunks/{chunk-WUYBEF7C.js → chunk-YWO3OBYK.js} +1 -1
  30. package/dist/bundle/chunks/cli-main-O5Y3TBID.js +3 -0
  31. package/dist/bundle/chunks/{google-generative-ai-YJHSZAY5.js → google-generative-ai-B5QMFONL.js} +1 -1
  32. package/dist/bundle/chunks/{google-vertex-JTFWEDNJ.js → google-vertex-O2TGMVWF.js} +1 -1
  33. package/dist/bundle/chunks/{help-fast-path-QXVCHTP3.js → help-fast-path-Y33OIZBU.js} +1 -1
  34. package/dist/bundle/chunks/{host-command-3PUZYQOK.js → host-command-WJOL27Q7.js} +1 -1
  35. package/dist/bundle/chunks/{host-lifecycle-OHPSU5VU.js → host-lifecycle-YBFXYFZP.js} +1 -1
  36. package/dist/bundle/chunks/{interactive-host-runtime-57LEAJPU.js → interactive-host-runtime-XVTF3NUD.js} +1 -1
  37. package/dist/bundle/chunks/interactive-mode-OO3NGM4G.js +2 -0
  38. package/dist/bundle/chunks/{list-tips-Z62FXPOJ.js → list-tips-EBRNBPBM.js} +1 -1
  39. package/dist/bundle/chunks/{mistral-conversations-VJPMPQ5T.js → mistral-conversations-AS3SAWPA.js} +1 -1
  40. package/dist/bundle/chunks/{multi-session-host-GFSDQQUJ.js → multi-session-host-6MKBBOKF.js} +1 -1
  41. package/dist/bundle/chunks/{openai-codex-responses-IQ35QACK.js → openai-codex-responses-CK7T4WNM.js} +1 -1
  42. package/dist/bundle/chunks/{openai-completions-74OLE55U.js → openai-completions-OPQKN7FH.js} +3 -3
  43. package/dist/bundle/chunks/openai-responses-QHWM3KPO.js +2 -0
  44. package/dist/bundle/chunks/{openrouter-images-T4GY3JYM.js → openrouter-images-MW5TXV7L.js} +1 -1
  45. package/dist/bundle/chunks/{package-manager-cli-J7244EJE.js → package-manager-cli-BMEWLAI2.js} +1 -1
  46. package/dist/bundle/chunks/{rotation-stream-CZT4TRPD.js → rotation-stream-ZFA6ELXJ.js} +1 -1
  47. package/dist/bundle/chunks/{rpc-mode-75CRTY24.js → rpc-mode-5653CV65.js} +1 -1
  48. package/dist/bundle/chunks/{session-picker-ZIBANFBQ.js → session-picker-PPYK56TA.js} +1 -1
  49. package/dist/bundle/chunks/session-worker.js +265 -259
  50. package/dist/bundle/cli.js +1 -1
  51. package/dist/bundle/index.js +1 -1
  52. package/dist/bundle/rpc-entry.js +1 -1
  53. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  54. package/dist/core/agent-session-runtime.js +13 -0
  55. package/dist/core/agent-session-runtime.js.map +1 -1
  56. package/dist/core/agent-session.d.ts +28 -0
  57. package/dist/core/agent-session.d.ts.map +1 -1
  58. package/dist/core/agent-session.js +75 -12
  59. package/dist/core/agent-session.js.map +1 -1
  60. package/dist/core/dynamic-prompt/build.d.ts +6 -1
  61. package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
  62. package/dist/core/dynamic-prompt/build.js +0 -7
  63. package/dist/core/dynamic-prompt/build.js.map +1 -1
  64. package/dist/core/environment-context.d.ts +32 -0
  65. package/dist/core/environment-context.d.ts.map +1 -0
  66. package/dist/core/environment-context.js +63 -0
  67. package/dist/core/environment-context.js.map +1 -0
  68. package/dist/core/extensions/builtin/anthropic-subscription/session-sync.d.ts.map +1 -1
  69. package/dist/core/extensions/builtin/anthropic-subscription/session-sync.js +1 -15
  70. package/dist/core/extensions/builtin/anthropic-subscription/session-sync.js.map +1 -1
  71. package/dist/core/extensions/builtin/goal/cache-warm-renderer.js +3 -0
  72. package/dist/core/extensions/builtin/goal/cache-warm-renderer.js.map +1 -1
  73. package/dist/core/extensions/builtin/goal/cache-warm.d.ts +19 -2
  74. package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
  75. package/dist/core/extensions/builtin/goal/cache-warm.js +28 -2
  76. package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
  77. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  78. package/dist/core/extensions/builtin/goal/monitor-continuation.js +4 -2
  79. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  80. package/dist/core/extensions/builtin/goal/parked-wait.js +2 -0
  81. package/dist/core/extensions/builtin/goal/parked-wait.js.map +1 -1
  82. package/dist/core/extensions/builtin/goal/prompt.js +1 -1
  83. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  84. package/dist/core/extensions/builtin/herdr/herdr-state.d.ts +5 -0
  85. package/dist/core/extensions/builtin/herdr/herdr-state.d.ts.map +1 -1
  86. package/dist/core/extensions/builtin/herdr/herdr-state.js +28 -3
  87. package/dist/core/extensions/builtin/herdr/herdr-state.js.map +1 -1
  88. package/dist/core/extensions/builtin/herdr/index.d.ts.map +1 -1
  89. package/dist/core/extensions/builtin/herdr/index.js +7 -1
  90. package/dist/core/extensions/builtin/herdr/index.js.map +1 -1
  91. package/dist/core/extensions/builtin/hooks/index.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/hooks/index.js +3 -15
  93. package/dist/core/extensions/builtin/hooks/index.js.map +1 -1
  94. package/dist/core/extensions/builtin/hooks/stop-lifecycle.d.ts +26 -0
  95. package/dist/core/extensions/builtin/hooks/stop-lifecycle.d.ts.map +1 -0
  96. package/dist/core/extensions/builtin/hooks/stop-lifecycle.js +88 -0
  97. package/dist/core/extensions/builtin/hooks/stop-lifecycle.js.map +1 -0
  98. package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
  99. package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
  100. package/dist/core/extensions/builtin/recommended-models/index.js +28 -10
  101. package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
  102. package/dist/core/extensions/builtin/rules/commands.d.ts.map +1 -1
  103. package/dist/core/extensions/builtin/rules/commands.js +5 -1
  104. package/dist/core/extensions/builtin/rules/commands.js.map +1 -1
  105. package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
  106. package/dist/core/extensions/builtin/rules/index.js +25 -3
  107. package/dist/core/extensions/builtin/rules/index.js.map +1 -1
  108. package/dist/core/extensions/builtin/rules/rules/constants.d.ts.map +1 -1
  109. package/dist/core/extensions/builtin/rules/rules/constants.js +22 -14
  110. package/dist/core/extensions/builtin/rules/rules/constants.js.map +1 -1
  111. package/dist/core/extensions/builtin/rules/rules/engine.d.ts.map +1 -1
  112. package/dist/core/extensions/builtin/rules/rules/engine.js +39 -9
  113. package/dist/core/extensions/builtin/rules/rules/engine.js.map +1 -1
  114. package/dist/core/extensions/builtin/rules/rules/finder.js +3 -0
  115. package/dist/core/extensions/builtin/rules/rules/finder.js.map +1 -1
  116. package/dist/core/extensions/builtin/rules/rules/project-root.d.ts +17 -0
  117. package/dist/core/extensions/builtin/rules/rules/project-root.d.ts.map +1 -1
  118. package/dist/core/extensions/builtin/rules/rules/project-root.js +67 -5
  119. package/dist/core/extensions/builtin/rules/rules/project-root.js.map +1 -1
  120. package/dist/core/extensions/builtin/rules/rules/types.d.ts +2 -2
  121. package/dist/core/extensions/builtin/rules/rules/types.d.ts.map +1 -1
  122. package/dist/core/extensions/builtin/rules/rules/types.js.map +1 -1
  123. package/dist/core/extensions/builtin/rules/ui/rules-banner.d.ts +3 -1
  124. package/dist/core/extensions/builtin/rules/ui/rules-banner.d.ts.map +1 -1
  125. package/dist/core/extensions/builtin/rules/ui/rules-banner.js +1 -1
  126. package/dist/core/extensions/builtin/rules/ui/rules-banner.js.map +1 -1
  127. package/dist/core/extensions/builtin/todotools/todo-storage.d.ts.map +1 -1
  128. package/dist/core/extensions/builtin/todotools/todo-storage.js +10 -2
  129. package/dist/core/extensions/builtin/todotools/todo-storage.js.map +1 -1
  130. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -1
  131. package/dist/core/extensions/builtin/todotools/tools/todo.js +2 -1
  132. package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -1
  133. package/dist/core/extensions/builtin/websearch/websearch/config.d.ts.map +1 -1
  134. package/dist/core/extensions/builtin/websearch/websearch/config.js +2 -0
  135. package/dist/core/extensions/builtin/websearch/websearch/config.js.map +1 -1
  136. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.d.ts.map +1 -1
  137. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js +2 -0
  138. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js.map +1 -1
  139. package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.d.ts +3 -0
  140. package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.d.ts.map +1 -0
  141. package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.js +34 -0
  142. package/dist/core/extensions/builtin/websearch/websearch/providers/kagi.js.map +1 -0
  143. package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.d.ts +3 -0
  144. package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.d.ts.map +1 -0
  145. package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.js +22 -0
  146. package/dist/core/extensions/builtin/websearch/websearch/providers/serpdive.js.map +1 -0
  147. package/dist/core/extensions/builtin/websearch/websearch/providers.d.ts.map +1 -1
  148. package/dist/core/extensions/builtin/websearch/websearch/providers.js +4 -0
  149. package/dist/core/extensions/builtin/websearch/websearch/providers.js.map +1 -1
  150. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +1 -1
  151. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
  152. package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
  153. package/dist/core/session-discovery.d.ts +9 -3
  154. package/dist/core/session-discovery.d.ts.map +1 -1
  155. package/dist/core/session-discovery.js +19 -8
  156. package/dist/core/session-discovery.js.map +1 -1
  157. package/dist/core/session-manager.d.ts.map +1 -1
  158. package/dist/core/session-manager.js +8 -4
  159. package/dist/core/session-manager.js.map +1 -1
  160. package/dist/core/session-summary-cache.d.ts +16 -3
  161. package/dist/core/session-summary-cache.d.ts.map +1 -1
  162. package/dist/core/session-summary-cache.js +19 -3
  163. package/dist/core/session-summary-cache.js.map +1 -1
  164. package/dist/core/session-summary-index-file.d.ts +38 -0
  165. package/dist/core/session-summary-index-file.d.ts.map +1 -0
  166. package/dist/core/session-summary-index-file.js +119 -0
  167. package/dist/core/session-summary-index-file.js.map +1 -0
  168. package/dist/core/session-summary-index.d.ts +52 -0
  169. package/dist/core/session-summary-index.d.ts.map +1 -0
  170. package/dist/core/session-summary-index.js +157 -0
  171. package/dist/core/session-summary-index.js.map +1 -0
  172. package/dist/core/session-summary.d.ts +21 -2
  173. package/dist/core/session-summary.d.ts.map +1 -1
  174. package/dist/core/session-summary.js +53 -14
  175. package/dist/core/session-summary.js.map +1 -1
  176. package/dist/core/timings.d.ts +1 -1
  177. package/dist/core/timings.d.ts.map +1 -1
  178. package/dist/core/timings.js.map +1 -1
  179. package/dist/core/tools/renderers/read.d.ts.map +1 -1
  180. package/dist/core/tools/renderers/read.js +7 -2
  181. package/dist/core/tools/renderers/read.js.map +1 -1
  182. package/dist/core/tools/renderers/skill-read-path.d.ts +9 -0
  183. package/dist/core/tools/renderers/skill-read-path.d.ts.map +1 -0
  184. package/dist/core/tools/renderers/skill-read-path.js +49 -0
  185. package/dist/core/tools/renderers/skill-read-path.js.map +1 -0
  186. package/dist/main.d.ts.map +1 -1
  187. package/dist/main.js +7 -0
  188. package/dist/main.js.map +1 -1
  189. package/dist/modes/interactive/components/exploration-call.d.ts +1 -1
  190. package/dist/modes/interactive/components/exploration-call.d.ts.map +1 -1
  191. package/dist/modes/interactive/components/exploration-call.js +3 -1
  192. package/dist/modes/interactive/components/exploration-call.js.map +1 -1
  193. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  194. package/dist/modes/interactive/components/session-selector-search.js +32 -16
  195. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  196. package/dist/modes/interactive/components/session-selector-tree.d.ts +32 -0
  197. package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -0
  198. package/dist/modes/interactive/components/session-selector-tree.js +82 -0
  199. package/dist/modes/interactive/components/session-selector-tree.js.map +1 -0
  200. package/dist/modes/interactive/components/session-selector.d.ts +1 -0
  201. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/session-selector.js +6 -71
  203. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  204. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  205. package/dist/modes/interactive/interactive-mode.js +4 -1
  206. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  207. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +32 -0
  208. package/node_modules/@code-yeongyu/senpi-codemode/README.md +8 -4
  209. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  210. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/AGENTS.md +1 -0
  211. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/code-preview.ts +31 -0
  212. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-code.ts +34 -131
  213. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js-ast.ts +65 -0
  214. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js-layout.ts +90 -0
  215. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js-mask.ts +178 -0
  216. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-js.ts +100 -0
  217. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-python-script.ts +127 -0
  218. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/display-python.ts +150 -0
  219. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-request.ts +18 -4
  220. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +1 -1
  221. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +9 -25
  222. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +16 -9
  223. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts +1 -1
  224. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  225. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +22 -2
  226. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  227. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  228. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +3 -1
  229. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  230. package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.d.ts +6 -0
  231. package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.d.ts.map +1 -1
  232. package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.js +6 -19
  233. package/node_modules/@earendil-works/pi-agent-core/dist/tool-name-alias.js.map +1 -1
  234. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +8 -0
  235. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  236. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  237. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  238. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-references.d.ts.map +1 -1
  239. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-references.js +8 -35
  240. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-references.js.map +1 -1
  241. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  242. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +10 -6
  243. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  244. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
  245. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +4 -3
  246. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
  247. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  248. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +53 -1
  249. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js +1 -1
  251. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js.map +1 -1
  252. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +30 -0
  253. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  254. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +30 -0
  255. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  256. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +2 -1
  257. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/index.js +2 -1
  259. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  260. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +6 -0
  261. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
  262. package/node_modules/@earendil-works/pi-ai/dist/models.js +15 -0
  263. package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.d.ts +17 -0
  265. package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.d.ts.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.js +4 -1
  267. package/node_modules/@earendil-works/pi-ai/dist/openai-responses-compat.js.map +1 -1
  268. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  270. package/node_modules/@earendil-works/pi-ai/dist/providers/data/chatgpt-subscription.json +1 -1
  271. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  272. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  273. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
  274. package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax-cn.json +1 -1
  275. package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax.json +1 -1
  276. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json +1 -1
  277. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
  279. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  281. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  283. package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
  285. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +6 -0
  287. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts +30 -0
  290. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js +71 -14
  292. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js.map +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.d.ts +30 -0
  294. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.d.ts.map +1 -0
  295. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.js +71 -0
  296. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-name-match.js.map +1 -0
  297. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  298. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  299. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  300. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts +5 -0
  301. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.d.ts.map +1 -1
  302. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +7 -2
  303. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js.map +1 -1
  304. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
  305. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  306. package/node_modules/@earendil-works/pi-tui/dist/index.js +1 -1
  307. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  308. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  309. package/package.json +7 -7
  310. package/dist/bundle/chunks/chunk-KLDLZHHS.js +0 -11
  311. package/dist/bundle/chunks/chunk-LTIMMSDM.js +0 -8
  312. package/dist/bundle/chunks/chunk-XYM54ZWK.js +0 -2
  313. package/dist/bundle/chunks/cli-main-W55CWPEI.js +0 -3
  314. package/dist/bundle/chunks/interactive-mode-EDJZ4CSY.js +0 -2
  315. package/dist/bundle/chunks/openai-responses-7IGZSW33.js +0 -2
@@ -1,5 +1,5 @@
1
- import { createReadStream } from "fs";
2
- import { createInterface } from "readline";
1
+ import { open } from "fs/promises";
2
+ import { StringDecoder } from "string_decoder";
3
3
  import { parseEntryLine, sessionInfoName, visibleMessage } from "./session-record.js";
4
4
  function newAccumulator() {
5
5
  return {
@@ -49,32 +49,71 @@ function accumulateLine(accumulator, line) {
49
49
  }
50
50
  return true;
51
51
  }
52
+ const LINE_READ_BUFFER_SIZE = 1024 * 1024;
52
53
  /**
53
- * Stream one session file line by line and fold it into an exact summary.
54
+ * Read a file line by line through one reused 1 MiB buffer, handing each line
55
+ * (LF-split, a trailing CR dropped) to `onLine` until it returns false.
54
56
  *
55
- * Memory stays bounded by readline's buffer plus the transcript text the summary
57
+ * This replaces `readline`, whose per-line async iteration dominated summary
58
+ * cost (senpi#2087). Only the unfinished tail of a chunk is carried between
59
+ * reads, and the next newline search resumes where the carried tail ends, so a
60
+ * record larger than the buffer is not rescanned per chunk. Read errors throw.
61
+ */
62
+ export async function readFileLines(filePath, onLine) {
63
+ const handle = await open(filePath, "r");
64
+ try {
65
+ const decoder = new StringDecoder("utf8");
66
+ const buffer = Buffer.allocUnsafe(LINE_READ_BUFFER_SIZE);
67
+ let pending = "";
68
+ let bytes = 0;
69
+ let lastByte = -1;
70
+ const emit = (line) => onLine(line.endsWith("\r") ? line.slice(0, -1) : line);
71
+ while (true) {
72
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, null);
73
+ if (bytesRead === 0)
74
+ break;
75
+ bytes += bytesRead;
76
+ lastByte = buffer[bytesRead - 1] ?? -1;
77
+ const searchFrom = pending.length;
78
+ pending += decoder.write(buffer.subarray(0, bytesRead));
79
+ let lineStart = 0;
80
+ let newlineIndex = pending.indexOf("\n", searchFrom);
81
+ while (newlineIndex !== -1) {
82
+ if (!emit(pending.slice(lineStart, newlineIndex)))
83
+ return { completed: false, bytes, endsWithNewline: false };
84
+ lineStart = newlineIndex + 1;
85
+ newlineIndex = pending.indexOf("\n", lineStart);
86
+ }
87
+ pending = pending.slice(lineStart);
88
+ }
89
+ pending += decoder.end();
90
+ if (pending && !emit(pending))
91
+ return { completed: false, bytes, endsWithNewline: false };
92
+ return { completed: true, bytes, endsWithNewline: lastByte === 0x0a };
93
+ }
94
+ finally {
95
+ await handle.close();
96
+ }
97
+ }
98
+ /**
99
+ * Read one session file line by line and fold it into an exact summary.
100
+ *
101
+ * Memory stays bounded by one read buffer plus the transcript text the summary
56
102
  * contract requires; no full-file string is ever materialized. A file whose
57
103
  * first record is not a session header, or that cannot be read, yields null.
58
104
  */
59
105
  export async function readSessionSummary(filePath) {
60
106
  const accumulator = newAccumulator();
61
- const stream = createReadStream(filePath, { encoding: "utf8" });
62
- const lines = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
63
107
  try {
64
- for await (const line of lines) {
65
- if (!accumulateLine(accumulator, line))
66
- return null;
67
- }
108
+ const read = await readFileLines(filePath, (line) => accumulateLine(accumulator, line));
109
+ if (!read.completed)
110
+ return null;
68
111
  }
69
112
  catch (error) {
70
113
  if (error instanceof Error)
71
114
  return null;
72
115
  throw error;
73
116
  }
74
- finally {
75
- lines.close();
76
- stream.destroy();
77
- }
78
117
  const header = accumulator.header;
79
118
  if (!header)
80
119
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"session-summary.js","sourceRoot":"","sources":["../../src/core/session-summary.ts"],"names":[],"mappings":"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","sourcesContent":["import { createReadStream } from \"fs\";\nimport { createInterface } from \"readline\";\nimport type { SessionHeader } from \"./session-manager.ts\";\nimport { parseEntryLine, sessionInfoName, visibleMessage } from \"./session-record.ts\";\n\n/**\n * Everything a picker row needs from one session file, derived from every record\n * in the file. Exact by construction: no window, no marker heuristic, so a first\n * user message, a rename, or an out-of-order activity timestamp is found no\n * matter how deep in the transcript it sits.\n */\nexport type SessionSummary = {\n\treadonly header: SessionHeader;\n\t/** Latest `session_info` name anywhere in the file, including explicit clears. */\n\treadonly name: string | undefined;\n\t/** First visible user message text anywhere in the file. */\n\treadonly firstUserMessage: string;\n\t/** Count of records that parsed as `type: \"message\"`. */\n\treadonly messageCount: number;\n\t/** Max user/assistant activity time seen, regardless of record order. */\n\treadonly lastActivityTime: number | undefined;\n\t/** Full user/assistant transcript text in file order. */\n\treadonly allMessagesText: string;\n};\n\ntype SummaryAccumulator = {\n\theader: SessionHeader | null;\n\tname: string | undefined;\n\tfirstUserMessage: string;\n\tmessageCount: number;\n\tlastActivityTime: number | undefined;\n\treadonly texts: string[];\n};\n\nfunction newAccumulator(): SummaryAccumulator {\n\treturn {\n\t\theader: null,\n\t\tname: undefined,\n\t\tfirstUserMessage: \"\",\n\t\tmessageCount: 0,\n\t\tlastActivityTime: undefined,\n\t\ttexts: [],\n\t};\n}\n\n/**\n * Fold one JSONL line into the accumulator.\n *\n * Returns false when the file's first parsable record is not a session header,\n * which means the file is not a session and the caller stops reading.\n */\nfunction accumulateLine(accumulator: SummaryAccumulator, line: string): boolean {\n\tconst entry = parseEntryLine(line);\n\tif (!entry) return true;\n\n\tif (!accumulator.header) {\n\t\tif (entry.type !== \"session\" || typeof entry.id !== \"string\") return false;\n\t\taccumulator.header = entry;\n\t\treturn true;\n\t}\n\n\tconst infoName = sessionInfoName(entry);\n\tif (infoName !== null) {\n\t\taccumulator.name = infoName;\n\t\treturn true;\n\t}\n\n\tif (entry.type !== \"message\") return true;\n\taccumulator.messageCount++;\n\n\tconst visible = visibleMessage(entry);\n\tif (!visible) return true;\n\tif (typeof visible.time === \"number\") {\n\t\taccumulator.lastActivityTime = Math.max(accumulator.lastActivityTime ?? 0, visible.time);\n\t}\n\tif (!visible.text) return true;\n\taccumulator.texts.push(visible.text);\n\tif (!accumulator.firstUserMessage && visible.role === \"user\") {\n\t\taccumulator.firstUserMessage = visible.text;\n\t}\n\treturn true;\n}\n\n/**\n * Stream one session file line by line and fold it into an exact summary.\n *\n * Memory stays bounded by readline's buffer plus the transcript text the summary\n * contract requires; no full-file string is ever materialized. A file whose\n * first record is not a session header, or that cannot be read, yields null.\n */\nexport async function readSessionSummary(filePath: string): Promise<SessionSummary | null> {\n\tconst accumulator = newAccumulator();\n\tconst stream = createReadStream(filePath, { encoding: \"utf8\" });\n\tconst lines = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });\n\n\ttry {\n\t\tfor await (const line of lines) {\n\t\t\tif (!accumulateLine(accumulator, line)) return null;\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error) return null;\n\t\tthrow error;\n\t} finally {\n\t\tlines.close();\n\t\tstream.destroy();\n\t}\n\n\tconst header = accumulator.header;\n\tif (!header) return null;\n\n\treturn {\n\t\theader,\n\t\tname: accumulator.name,\n\t\tfirstUserMessage: accumulator.firstUserMessage,\n\t\tmessageCount: accumulator.messageCount,\n\t\tlastActivityTime: accumulator.lastActivityTime,\n\t\tallMessagesText: accumulator.texts.join(\" \"),\n\t};\n}\n"]}
1
+ {"version":3,"file":"session-summary.js","sourceRoot":"","sources":["../../src/core/session-summary.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from \"fs/promises\";\nimport { StringDecoder } from \"string_decoder\";\nimport type { SessionHeader } from \"./session-manager.ts\";\nimport { parseEntryLine, sessionInfoName, visibleMessage } from \"./session-record.ts\";\n\n/**\n * Everything a picker row needs from one session file, derived from every record\n * in the file. Exact by construction: no window, no marker heuristic, so a first\n * user message, a rename, or an out-of-order activity timestamp is found no\n * matter how deep in the transcript it sits.\n */\nexport type SessionSummary = {\n\treadonly header: SessionHeader;\n\t/** Latest `session_info` name anywhere in the file, including explicit clears. */\n\treadonly name: string | undefined;\n\t/** First visible user message text anywhere in the file. */\n\treadonly firstUserMessage: string;\n\t/** Count of records that parsed as `type: \"message\"`. */\n\treadonly messageCount: number;\n\t/** Max user/assistant activity time seen, regardless of record order. */\n\treadonly lastActivityTime: number | undefined;\n\t/** Full user/assistant transcript text in file order. */\n\treadonly allMessagesText: string;\n};\n\ntype SummaryAccumulator = {\n\theader: SessionHeader | null;\n\tname: string | undefined;\n\tfirstUserMessage: string;\n\tmessageCount: number;\n\tlastActivityTime: number | undefined;\n\treadonly texts: string[];\n};\n\nfunction newAccumulator(): SummaryAccumulator {\n\treturn {\n\t\theader: null,\n\t\tname: undefined,\n\t\tfirstUserMessage: \"\",\n\t\tmessageCount: 0,\n\t\tlastActivityTime: undefined,\n\t\ttexts: [],\n\t};\n}\n\n/**\n * Fold one JSONL line into the accumulator.\n *\n * Returns false when the file's first parsable record is not a session header,\n * which means the file is not a session and the caller stops reading.\n */\nfunction accumulateLine(accumulator: SummaryAccumulator, line: string): boolean {\n\tconst entry = parseEntryLine(line);\n\tif (!entry) return true;\n\n\tif (!accumulator.header) {\n\t\tif (entry.type !== \"session\" || typeof entry.id !== \"string\") return false;\n\t\taccumulator.header = entry;\n\t\treturn true;\n\t}\n\n\tconst infoName = sessionInfoName(entry);\n\tif (infoName !== null) {\n\t\taccumulator.name = infoName;\n\t\treturn true;\n\t}\n\n\tif (entry.type !== \"message\") return true;\n\taccumulator.messageCount++;\n\n\tconst visible = visibleMessage(entry);\n\tif (!visible) return true;\n\tif (typeof visible.time === \"number\") {\n\t\taccumulator.lastActivityTime = Math.max(accumulator.lastActivityTime ?? 0, visible.time);\n\t}\n\tif (!visible.text) return true;\n\taccumulator.texts.push(visible.text);\n\tif (!accumulator.firstUserMessage && visible.role === \"user\") {\n\t\taccumulator.firstUserMessage = visible.text;\n\t}\n\treturn true;\n}\n\nconst LINE_READ_BUFFER_SIZE = 1024 * 1024;\n\n/** What a completed {@link readFileLines} pass saw. */\nexport type FileLinesRead = {\n\t/** False when `onLine` stopped the pass early. */\n\treadonly completed: boolean;\n\t/** Bytes read from the file. */\n\treadonly bytes: number;\n\t/** Whether the last byte read was a newline (a torn tail has none). */\n\treadonly endsWithNewline: boolean;\n};\n\n/**\n * Read a file line by line through one reused 1 MiB buffer, handing each line\n * (LF-split, a trailing CR dropped) to `onLine` until it returns false.\n *\n * This replaces `readline`, whose per-line async iteration dominated summary\n * cost (senpi#2087). Only the unfinished tail of a chunk is carried between\n * reads, and the next newline search resumes where the carried tail ends, so a\n * record larger than the buffer is not rescanned per chunk. Read errors throw.\n */\nexport async function readFileLines(filePath: string, onLine: (line: string) => boolean): Promise<FileLinesRead> {\n\tconst handle = await open(filePath, \"r\");\n\ttry {\n\t\tconst decoder = new StringDecoder(\"utf8\");\n\t\tconst buffer = Buffer.allocUnsafe(LINE_READ_BUFFER_SIZE);\n\t\tlet pending = \"\";\n\t\tlet bytes = 0;\n\t\tlet lastByte = -1;\n\t\tconst emit = (line: string): boolean => onLine(line.endsWith(\"\\r\") ? line.slice(0, -1) : line);\n\n\t\twhile (true) {\n\t\t\tconst { bytesRead } = await handle.read(buffer, 0, buffer.length, null);\n\t\t\tif (bytesRead === 0) break;\n\t\t\tbytes += bytesRead;\n\t\t\tlastByte = buffer[bytesRead - 1] ?? -1;\n\n\t\t\tconst searchFrom = pending.length;\n\t\t\tpending += decoder.write(buffer.subarray(0, bytesRead));\n\t\t\tlet lineStart = 0;\n\t\t\tlet newlineIndex = pending.indexOf(\"\\n\", searchFrom);\n\t\t\twhile (newlineIndex !== -1) {\n\t\t\t\tif (!emit(pending.slice(lineStart, newlineIndex)))\n\t\t\t\t\treturn { completed: false, bytes, endsWithNewline: false };\n\t\t\t\tlineStart = newlineIndex + 1;\n\t\t\t\tnewlineIndex = pending.indexOf(\"\\n\", lineStart);\n\t\t\t}\n\t\t\tpending = pending.slice(lineStart);\n\t\t}\n\n\t\tpending += decoder.end();\n\t\tif (pending && !emit(pending)) return { completed: false, bytes, endsWithNewline: false };\n\t\treturn { completed: true, bytes, endsWithNewline: lastByte === 0x0a };\n\t} finally {\n\t\tawait handle.close();\n\t}\n}\n\n/**\n * Read one session file line by line and fold it into an exact summary.\n *\n * Memory stays bounded by one read buffer plus the transcript text the summary\n * contract requires; no full-file string is ever materialized. A file whose\n * first record is not a session header, or that cannot be read, yields null.\n */\nexport async function readSessionSummary(filePath: string): Promise<SessionSummary | null> {\n\tconst accumulator = newAccumulator();\n\n\ttry {\n\t\tconst read = await readFileLines(filePath, (line) => accumulateLine(accumulator, line));\n\t\tif (!read.completed) return null;\n\t} catch (error) {\n\t\tif (error instanceof Error) return null;\n\t\tthrow error;\n\t}\n\n\tconst header = accumulator.header;\n\tif (!header) return null;\n\n\treturn {\n\t\theader,\n\t\tname: accumulator.name,\n\t\tfirstUserMessage: accumulator.firstUserMessage,\n\t\tmessageCount: accumulator.messageCount,\n\t\tlastActivityTime: accumulator.lastActivityTime,\n\t\tallMessagesText: accumulator.texts.join(\" \"),\n\t};\n}\n"]}
@@ -2,7 +2,7 @@ export interface TimingEntry {
2
2
  label: string;
3
3
  ms: number;
4
4
  }
5
- export type TimingLabel = "main" | "extensions" | "reload" | "tui";
5
+ export type TimingLabel = "main" | "extensions" | "reload" | "tui" | "switch";
6
6
  export declare function resetTimings(namespace?: TimingLabel): void;
7
7
  export declare function time(label: string, namespace?: TimingLabel): void;
8
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"timings.d.ts","sourceRoot":"","sources":["../../src/core/timings.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACX;AAOD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,KAAK,CAAC;AAUnE,wBAAgB,YAAY,CAAC,SAAS,GAAE,WAAoB,GAAG,IAAI,CAGlE;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,WAAoB,GAAG,IAAI,CAWzE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,GAAE,WAAoB,GAAG,IAAI,CAK7F;AAaD,wBAAgB,UAAU,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,WAAW,EAAE,CAEzE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAMxE;AAED,wBAAgB,YAAY,IAAI,IAAI,CAKnC"}
1
+ {"version":3,"file":"timings.d.ts","sourceRoot":"","sources":["../../src/core/timings.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACX;AAOD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAC;AAU9E,wBAAgB,YAAY,CAAC,SAAS,GAAE,WAAoB,GAAG,IAAI,CAGlE;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,WAAoB,GAAG,IAAI,CAWzE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,GAAE,WAAoB,GAAG,IAAI,CAK7F;AAaD,wBAAgB,UAAU,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,WAAW,EAAE,CAEzE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAMxE;AAED,wBAAgB,YAAY,IAAI,IAAI,CAKnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"timings.js","sourceRoot":"","sources":["../../src/core/timings.ts"],"names":[],"mappings":"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","sourcesContent":["import { envValue } from \"./brand.ts\";\n\n/**\n * Central timing instrumentation for startup profiling.\n * Enable with PI_TIMING=1 environment variable.\n */\n\nconst ENABLED = envValue(\"TIMING\") === \"1\";\nexport interface TimingEntry {\n\tlabel: string;\n\tms: number;\n}\n\ninterface TimingNamespace {\n\ttimings: TimingEntry[];\n\tlastTime: number;\n}\n\nexport type TimingLabel = \"main\" | \"extensions\" | \"reload\" | \"tui\";\n\nconst timingNamespaces = new Map<TimingLabel, TimingNamespace>();\n\n// `performance.now()` rather than `Date.now()`: the phases now being hunted are 20-60ms, and a\n// whole-millisecond clock cannot tell a 20ms mark from a 29ms one. Rounding happens at print time.\nfunction now(): number {\n\treturn performance.now();\n}\n\nexport function resetTimings(namespace: TimingLabel = \"main\"): void {\n\tif (!ENABLED) return;\n\ttimingNamespaces.set(namespace, { timings: [], lastTime: now() });\n}\n\nexport function time(label: string, namespace: TimingLabel = \"main\"): void {\n\tif (!ENABLED) return;\n\tconst now = performance.now();\n\n\tif (!timingNamespaces.has(namespace)) {\n\t\tresetTimings(namespace);\n\t}\n\n\tconst timingNamespace = timingNamespaces.get(namespace)!;\n\ttimingNamespace.timings.push({ label, ms: now - timingNamespace.lastTime });\n\ttimingNamespace.lastTime = now;\n}\n\n/**\n * Record a phase this module could not measure itself - a duration derived from the process clock,\n * such as everything that happened before the first instrumented statement ran. The namespace's\n * cursor is left untouched, so the next `time()` call still measures from where it was.\n */\nexport function recordTiming(label: string, ms: number, namespace: TimingLabel = \"main\"): void {\n\tif (!ENABLED) return;\n\tconst timingNamespace = timingNamespaces.get(namespace) ?? { timings: [], lastTime: now() };\n\ttimingNamespaces.set(namespace, timingNamespace);\n\ttimingNamespace.timings.push({ label, ms });\n}\n\nfunction printTimingGroup(title: string, timings: TimingNamespace[\"timings\"]): void {\n\tconst printableTimings = timings.filter((timing) => timing.ms >= 0);\n\tif (printableTimings.length === 0) return;\n\tconsole.error(`\\n--- ${title} ---`);\n\tfor (const t of printableTimings) {\n\t\tconsole.error(` ${t.label}: ${Math.round(t.ms)}ms`);\n\t}\n\tconsole.error(` TOTAL: ${Math.round(printableTimings.reduce((a, b) => a + b.ms, 0))}ms`);\n\tconsole.error(`${\"-\".repeat(title.length + 8)}\\n`);\n}\n\nexport function getTimings(namespace: TimingLabel): readonly TimingEntry[] {\n\treturn timingNamespaces.get(namespace)?.timings ?? [];\n}\n\nexport function formatTimings(namespace: TimingLabel): string | undefined {\n\tconst entries = getTimings(namespace).filter((entry) => entry.ms >= 0);\n\tif (entries.length === 0) return undefined;\n\tconst total = entries.reduce((sum, entry) => sum + entry.ms, 0);\n\tconst parts = entries.map((entry) => `${entry.label} ${Math.round(entry.ms)}ms`).join(\" \");\n\treturn `${parts} | total ${Math.round(total)}ms`;\n}\n\nexport function printTimings(): void {\n\tif (!ENABLED) return;\n\tfor (const [namespace, timingNamespace] of timingNamespaces) {\n\t\tprintTimingGroup(`Startup Timings: ${namespace}`, timingNamespace.timings);\n\t}\n}\n"]}
1
+ {"version":3,"file":"timings.js","sourceRoot":"","sources":["../../src/core/timings.ts"],"names":[],"mappings":"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","sourcesContent":["import { envValue } from \"./brand.ts\";\n\n/**\n * Central timing instrumentation for startup profiling.\n * Enable with PI_TIMING=1 environment variable.\n */\n\nconst ENABLED = envValue(\"TIMING\") === \"1\";\nexport interface TimingEntry {\n\tlabel: string;\n\tms: number;\n}\n\ninterface TimingNamespace {\n\ttimings: TimingEntry[];\n\tlastTime: number;\n}\n\nexport type TimingLabel = \"main\" | \"extensions\" | \"reload\" | \"tui\" | \"switch\";\n\nconst timingNamespaces = new Map<TimingLabel, TimingNamespace>();\n\n// `performance.now()` rather than `Date.now()`: the phases now being hunted are 20-60ms, and a\n// whole-millisecond clock cannot tell a 20ms mark from a 29ms one. Rounding happens at print time.\nfunction now(): number {\n\treturn performance.now();\n}\n\nexport function resetTimings(namespace: TimingLabel = \"main\"): void {\n\tif (!ENABLED) return;\n\ttimingNamespaces.set(namespace, { timings: [], lastTime: now() });\n}\n\nexport function time(label: string, namespace: TimingLabel = \"main\"): void {\n\tif (!ENABLED) return;\n\tconst now = performance.now();\n\n\tif (!timingNamespaces.has(namespace)) {\n\t\tresetTimings(namespace);\n\t}\n\n\tconst timingNamespace = timingNamespaces.get(namespace)!;\n\ttimingNamespace.timings.push({ label, ms: now - timingNamespace.lastTime });\n\ttimingNamespace.lastTime = now;\n}\n\n/**\n * Record a phase this module could not measure itself - a duration derived from the process clock,\n * such as everything that happened before the first instrumented statement ran. The namespace's\n * cursor is left untouched, so the next `time()` call still measures from where it was.\n */\nexport function recordTiming(label: string, ms: number, namespace: TimingLabel = \"main\"): void {\n\tif (!ENABLED) return;\n\tconst timingNamespace = timingNamespaces.get(namespace) ?? { timings: [], lastTime: now() };\n\ttimingNamespaces.set(namespace, timingNamespace);\n\ttimingNamespace.timings.push({ label, ms });\n}\n\nfunction printTimingGroup(title: string, timings: TimingNamespace[\"timings\"]): void {\n\tconst printableTimings = timings.filter((timing) => timing.ms >= 0);\n\tif (printableTimings.length === 0) return;\n\tconsole.error(`\\n--- ${title} ---`);\n\tfor (const t of printableTimings) {\n\t\tconsole.error(` ${t.label}: ${Math.round(t.ms)}ms`);\n\t}\n\tconsole.error(` TOTAL: ${Math.round(printableTimings.reduce((a, b) => a + b.ms, 0))}ms`);\n\tconsole.error(`${\"-\".repeat(title.length + 8)}\\n`);\n}\n\nexport function getTimings(namespace: TimingLabel): readonly TimingEntry[] {\n\treturn timingNamespaces.get(namespace)?.timings ?? [];\n}\n\nexport function formatTimings(namespace: TimingLabel): string | undefined {\n\tconst entries = getTimings(namespace).filter((entry) => entry.ms >= 0);\n\tif (entries.length === 0) return undefined;\n\tconst total = entries.reduce((sum, entry) => sum + entry.ms, 0);\n\tconst parts = entries.map((entry) => `${entry.label} ${Math.round(entry.ms)}ms`).join(\" \");\n\treturn `${parts} | total ${Math.round(total)}ms`;\n}\n\nexport function printTimings(): void {\n\tif (!ENABLED) return;\n\tfor (const [namespace, timingNamespace] of timingNamespaces) {\n\t\tprintTimingGroup(`Startup Timings: ${namespace}`, timingNamespace.timings);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/renderers/read.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,2BAA2B,CAAC;AAEzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,KAAK,yBAAyB,EAAgB,MAAM,wBAAwB,CAAC;AAGtF;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,EAAE,yBAAyB,GAAG,SAAS,CAAC,CAAC;CAC5E;AAED,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAuCpG,2GAA2G;AAC3G,wBAAgB,4BAA4B,CAC3C,IAAI,EAAE,cAAc,GAAG,SAAS,EAChC,GAAG,EAAE,MAAM,GACT,yBAAyB,GAAG,SAAS,CAqBvC;AA+DD,eAAO,MAAM,aAAa,EAAE,IAAI,CAC/B,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,EACjE,YAAY,GAAG,cAAc,CAmC7B,CAAC"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/renderers/read.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,2BAA2B,CAAC;AAEzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,KAAK,yBAAyB,EAAgB,MAAM,wBAAwB,CAAC;AAItF;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,EAAE,yBAAyB,GAAG,SAAS,CAAC,CAAC;CAC5E;AAED,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AA4CpG,2GAA2G;AAC3G,wBAAgB,4BAA4B,CAC3C,IAAI,EAAE,cAAc,GAAG,SAAS,EAChC,GAAG,EAAE,MAAM,GACT,yBAAyB,GAAG,SAAS,CAqBvC;AA+DD,eAAO,MAAM,aAAa,EAAE,IAAI,CAC/B,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,EACjE,YAAY,GAAG,cAAc,CAmC7B,CAAC"}
@@ -13,7 +13,8 @@ import { getLanguageFromPath, highlightCode } from "../../../modes/interactive/t
13
13
  import { formatPathRelativeToCwdOrAbsolute } from "../../../utils/paths.js";
14
14
  import { resolveToCwd } from "../path-utils.js";
15
15
  import { classifyRead } from "../read-classifiers.js";
16
- import { getTextOutput, renderToolPath, replaceTabs, str } from "../render-utils.js";
16
+ import { getTextOutput, linkPath, renderToolPath, replaceTabs, str } from "../render-utils.js";
17
+ import { getSkillReadPath } from "./skill-read-path.js";
17
18
  const COMPACT_RESOURCE_FILE_NAMES = new Set(["AGENTS.override.md", "AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"]);
18
19
  function formatReadLineRange(args, theme) {
19
20
  if (args?.offset === undefined && args?.limit === undefined)
@@ -23,7 +24,11 @@ function formatReadLineRange(args, theme) {
23
24
  return theme.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
24
25
  }
25
26
  function formatReadCall(args, theme, cwd) {
26
- const pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme, cwd);
27
+ const rawPath = str(args?.file_path ?? args?.path);
28
+ const skillPath = rawPath ? getSkillReadPath(resolveToCwd(rawPath, cwd), cwd) : undefined;
29
+ const pathDisplay = rawPath && skillPath
30
+ ? linkPath(theme.fg("accent", skillPath), rawPath, cwd)
31
+ : renderToolPath(rawPath, theme, cwd);
27
32
  return `${theme.fg("toolTitle", theme.bold("read"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;
28
33
  }
29
34
  function trimTrailingEmptyLines(lines) {
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../src/core/tools/renderers/read.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Presentation for the read tool.\n *\n * Renderers live apart from the implementation so a process that only displays tool output does not\n * load the execution path or its typebox parameter schema. `read.ts` spreads these into its\n * definition, so the tool's public shape is unchanged.\n */\n\nimport { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from \"node:path\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { getReadmePath } from \"../../../config.ts\";\nimport { keyHint, keyText } from \"../../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport { formatPathRelativeToCwdOrAbsolute } from \"../../../utils/paths.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.ts\";\nimport { resolveToCwd } from \"../path-utils.ts\";\nimport type { ReadToolDetails } from \"../read.ts\";\nimport { type CompactReadClassification, classifyRead } from \"../read-classifiers.ts\";\nimport { getTextOutput, renderToolPath, replaceTabs, str } from \"../render-utils.ts\";\n\n/**\n * Classifications are memoized per tool call (unclaimed paths included) so a redraw or an\n * expand/collapse cannot pick a different headline for the same read.\n */\nexport interface ReadRenderState {\n\tclassifications?: Map<string | null, CompactReadClassification | undefined>;\n}\nconst COMPACT_RESOURCE_FILE_NAMES = new Set([\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\nexport type ReadRenderArgs = { path?: string; file_path?: string; offset?: number; limit?: number };\nfunction formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): string {\n\tif (args?.offset === undefined && args?.limit === undefined) return \"\";\n\tconst startLine = args.offset ?? 1;\n\tconst endLine = args.limit !== undefined ? startLine + args.limit - 1 : \"\";\n\treturn theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n}\nfunction formatReadCall(args: ReadRenderArgs | undefined, theme: Theme, cwd: string): string {\n\tconst pathDisplay = renderToolPath(str(args?.file_path ?? args?.path), theme, cwd);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;\n}\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\nfunction toPosixPath(filePath: string): string {\n\treturn filePath.split(sep).join(\"/\");\n}\nfunction getPiDocsClassification(absolutePath: string): CompactReadClassification | undefined {\n\tconst packageRoot = dirname(getReadmePath());\n\tconst relativePath = relative(resolvePath(packageRoot), resolvePath(absolutePath));\n\tif (\n\t\trelativePath === \"\" ||\n\t\trelativePath === \"..\" ||\n\t\trelativePath.startsWith(`..${sep}`) ||\n\t\tisAbsolute(relativePath)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst label = toPosixPath(relativePath);\n\tif (label === \"README.md\" || label.startsWith(\"docs/\") || label.startsWith(\"examples/\")) {\n\t\treturn { kind: \"docs\", label };\n\t}\n\treturn undefined;\n}\n/** The compact headline a collapsed read card shows for these args, or undefined for a plain file read. */\nexport function getCompactReadClassification(\n\targs: ReadRenderArgs | undefined,\n\tcwd: string,\n): CompactReadClassification | undefined {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tif (!rawPath) return undefined;\n\n\tconst absolutePath = resolveToCwd(rawPath, cwd);\n\tconst fileName = basename(absolutePath);\n\tif (fileName === \"SKILL.md\") {\n\t\treturn { kind: \"skill\", label: basename(dirname(absolutePath)) || fileName };\n\t}\n\n\tconst registeredClassification = classifyRead({ absolutePath, cwd });\n\tif (registeredClassification) return registeredClassification;\n\n\tconst docsClassification = getPiDocsClassification(absolutePath);\n\tif (docsClassification) return docsClassification;\n\n\tif (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n\t\treturn { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n\t}\n\n\treturn undefined;\n}\nfunction formatCompactReadCall(\n\tclassification: CompactReadClassification,\n\targs: ReadRenderArgs | undefined,\n\ttheme: Theme,\n): string {\n\tconst expandHint = theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\tif (classification.kind === \"skill\") {\n\t\treturn (\n\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\tif (classification.kind === \"memory\") {\n\t\treturn (\n\t\t\ttheme.fg(\"accent\", `\\x1b[1m✦ ${classification.headline ?? \"Recalled\"}\\x1b[22m`) +\n\t\t\t\" \" +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\treturn (\n\t\ttheme.fg(\"toolTitle\", theme.bold(`read ${classification.kind}`)) +\n\t\t\" \" +\n\t\ttheme.fg(\"accent\", classification.label) +\n\t\tformatReadLineRange(args, theme) +\n\t\texpandHint\n\t);\n}\nfunction formatReadResult(\n\targs: ReadRenderArgs | undefined,\n\tresult: { content: (TextContent | ImageContent)[]; details?: ReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n\t_cwd: string,\n\tisError: boolean,\n): string {\n\tif (!options.expanded && !isError) {\n\t\treturn \"\";\n\t}\n\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst output = getTextOutput(result, showImages);\n\tconst lang = !isError && rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tconst renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\tconst lines = trimTrailingEmptyLines(renderedLines);\n\tconst maxLines = options.expanded ? lines.length : 10;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t}\n\n\treturn text;\n}\n\nexport const readRenderers: Pick<\n\tToolDefinition<any, ReadToolDetails | undefined, ReadRenderState>,\n\t\"renderCall\" | \"renderResult\"\n> = {\n\trenderCall(rawArgs, theme, context) {\n\t\tconst args = rawArgs as ReadRenderArgs | undefined;\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\tlet classification: CompactReadClassification | undefined;\n\t\tif (!context.expanded) {\n\t\t\tconst rawPath = str(args?.file_path ?? args?.path);\n\t\t\tcontext.state.classifications ??= new Map();\n\t\t\tconst classifications = context.state.classifications;\n\t\t\tif (!classifications.has(rawPath)) {\n\t\t\t\tclassifications.set(rawPath, getCompactReadClassification(args, context.cwd));\n\t\t\t}\n\t\t\tclassification = classifications.get(rawPath);\n\t\t}\n\t\ttext.setText(\n\t\t\tclassification ? formatCompactReadCall(classification, args, theme) : formatReadCall(args, theme, context.cwd),\n\t\t);\n\t\treturn text;\n\t},\n\trenderResult(result, options, theme, context) {\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\ttext.setText(\n\t\t\tformatReadResult(\n\t\t\t\tcontext.args as ReadRenderArgs | undefined,\n\t\t\t\tresult,\n\t\t\t\toptions,\n\t\t\t\ttheme,\n\t\t\t\tcontext.showImages,\n\t\t\t\tcontext.cwd,\n\t\t\t\tcontext.isError,\n\t\t\t),\n\t\t);\n\t\treturn text;\n\t},\n};\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../src/core/tools/renderers/read.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Presentation for the read tool.\n *\n * Renderers live apart from the implementation so a process that only displays tool output does not\n * load the execution path or its typebox parameter schema. `read.ts` spreads these into its\n * definition, so the tool's public shape is unchanged.\n */\n\nimport { basename, dirname, isAbsolute, relative, resolve as resolvePath, sep } from \"node:path\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { getReadmePath } from \"../../../config.ts\";\nimport { keyHint, keyText } from \"../../../modes/interactive/components/keybinding-hints.ts\";\nimport { getLanguageFromPath, highlightCode, type Theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport { formatPathRelativeToCwdOrAbsolute } from \"../../../utils/paths.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../../extensions/types.ts\";\nimport { resolveToCwd } from \"../path-utils.ts\";\nimport type { ReadToolDetails } from \"../read.ts\";\nimport { type CompactReadClassification, classifyRead } from \"../read-classifiers.ts\";\nimport { getTextOutput, linkPath, renderToolPath, replaceTabs, str } from \"../render-utils.ts\";\nimport { getSkillReadPath } from \"./skill-read-path.ts\";\n\n/**\n * Classifications are memoized per tool call (unclaimed paths included) so a redraw or an\n * expand/collapse cannot pick a different headline for the same read.\n */\nexport interface ReadRenderState {\n\tclassifications?: Map<string | null, CompactReadClassification | undefined>;\n}\nconst COMPACT_RESOURCE_FILE_NAMES = new Set([\"AGENTS.override.md\", \"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\"]);\nexport type ReadRenderArgs = { path?: string; file_path?: string; offset?: number; limit?: number };\nfunction formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): string {\n\tif (args?.offset === undefined && args?.limit === undefined) return \"\";\n\tconst startLine = args.offset ?? 1;\n\tconst endLine = args.limit !== undefined ? startLine + args.limit - 1 : \"\";\n\treturn theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n}\nfunction formatReadCall(args: ReadRenderArgs | undefined, theme: Theme, cwd: string): string {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst skillPath = rawPath ? getSkillReadPath(resolveToCwd(rawPath, cwd), cwd) : undefined;\n\tconst pathDisplay =\n\t\trawPath && skillPath\n\t\t\t? linkPath(theme.fg(\"accent\", skillPath), rawPath, cwd)\n\t\t\t: renderToolPath(rawPath, theme, cwd);\n\treturn `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;\n}\nfunction trimTrailingEmptyLines(lines: string[]): string[] {\n\tlet end = lines.length;\n\twhile (end > 0 && lines[end - 1] === \"\") {\n\t\tend--;\n\t}\n\treturn lines.slice(0, end);\n}\nfunction toPosixPath(filePath: string): string {\n\treturn filePath.split(sep).join(\"/\");\n}\nfunction getPiDocsClassification(absolutePath: string): CompactReadClassification | undefined {\n\tconst packageRoot = dirname(getReadmePath());\n\tconst relativePath = relative(resolvePath(packageRoot), resolvePath(absolutePath));\n\tif (\n\t\trelativePath === \"\" ||\n\t\trelativePath === \"..\" ||\n\t\trelativePath.startsWith(`..${sep}`) ||\n\t\tisAbsolute(relativePath)\n\t) {\n\t\treturn undefined;\n\t}\n\n\tconst label = toPosixPath(relativePath);\n\tif (label === \"README.md\" || label.startsWith(\"docs/\") || label.startsWith(\"examples/\")) {\n\t\treturn { kind: \"docs\", label };\n\t}\n\treturn undefined;\n}\n/** The compact headline a collapsed read card shows for these args, or undefined for a plain file read. */\nexport function getCompactReadClassification(\n\targs: ReadRenderArgs | undefined,\n\tcwd: string,\n): CompactReadClassification | undefined {\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tif (!rawPath) return undefined;\n\n\tconst absolutePath = resolveToCwd(rawPath, cwd);\n\tconst fileName = basename(absolutePath);\n\tif (fileName === \"SKILL.md\") {\n\t\treturn { kind: \"skill\", label: basename(dirname(absolutePath)) || fileName };\n\t}\n\n\tconst registeredClassification = classifyRead({ absolutePath, cwd });\n\tif (registeredClassification) return registeredClassification;\n\n\tconst docsClassification = getPiDocsClassification(absolutePath);\n\tif (docsClassification) return docsClassification;\n\n\tif (COMPACT_RESOURCE_FILE_NAMES.has(fileName)) {\n\t\treturn { kind: \"resource\", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };\n\t}\n\n\treturn undefined;\n}\nfunction formatCompactReadCall(\n\tclassification: CompactReadClassification,\n\targs: ReadRenderArgs | undefined,\n\ttheme: Theme,\n): string {\n\tconst expandHint = theme.fg(\"dim\", ` (${keyText(\"app.tools.expand\")} to expand)`);\n\tif (classification.kind === \"skill\") {\n\t\treturn (\n\t\t\ttheme.fg(\"customMessageLabel\", `\\x1b[1m[skill]\\x1b[22m `) +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\tif (classification.kind === \"memory\") {\n\t\treturn (\n\t\t\ttheme.fg(\"accent\", `\\x1b[1m✦ ${classification.headline ?? \"Recalled\"}\\x1b[22m`) +\n\t\t\t\" \" +\n\t\t\ttheme.fg(\"customMessageText\", classification.label) +\n\t\t\tformatReadLineRange(args, theme) +\n\t\t\texpandHint\n\t\t);\n\t}\n\n\treturn (\n\t\ttheme.fg(\"toolTitle\", theme.bold(`read ${classification.kind}`)) +\n\t\t\" \" +\n\t\ttheme.fg(\"accent\", classification.label) +\n\t\tformatReadLineRange(args, theme) +\n\t\texpandHint\n\t);\n}\nfunction formatReadResult(\n\targs: ReadRenderArgs | undefined,\n\tresult: { content: (TextContent | ImageContent)[]; details?: ReadToolDetails },\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n\t_cwd: string,\n\tisError: boolean,\n): string {\n\tif (!options.expanded && !isError) {\n\t\treturn \"\";\n\t}\n\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst output = getTextOutput(result, showImages);\n\tconst lang = !isError && rawPath ? getLanguageFromPath(rawPath) : undefined;\n\tconst renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\tconst lines = trimTrailingEmptyLines(renderedLines);\n\tconst maxLines = options.expanded ? lines.length : 10;\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\tlet text = `\\n${displayLines.map((line) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line)))).join(\"\\n\")}`;\n\tif (remaining > 0) {\n\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t}\n\n\treturn text;\n}\n\nexport const readRenderers: Pick<\n\tToolDefinition<any, ReadToolDetails | undefined, ReadRenderState>,\n\t\"renderCall\" | \"renderResult\"\n> = {\n\trenderCall(rawArgs, theme, context) {\n\t\tconst args = rawArgs as ReadRenderArgs | undefined;\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\tlet classification: CompactReadClassification | undefined;\n\t\tif (!context.expanded) {\n\t\t\tconst rawPath = str(args?.file_path ?? args?.path);\n\t\t\tcontext.state.classifications ??= new Map();\n\t\t\tconst classifications = context.state.classifications;\n\t\t\tif (!classifications.has(rawPath)) {\n\t\t\t\tclassifications.set(rawPath, getCompactReadClassification(args, context.cwd));\n\t\t\t}\n\t\t\tclassification = classifications.get(rawPath);\n\t\t}\n\t\ttext.setText(\n\t\t\tclassification ? formatCompactReadCall(classification, args, theme) : formatReadCall(args, theme, context.cwd),\n\t\t);\n\t\treturn text;\n\t},\n\trenderResult(result, options, theme, context) {\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\ttext.setText(\n\t\t\tformatReadResult(\n\t\t\t\tcontext.args as ReadRenderArgs | undefined,\n\t\t\t\tresult,\n\t\t\t\toptions,\n\t\t\t\ttheme,\n\t\t\t\tcontext.showImages,\n\t\t\t\tcontext.cwd,\n\t\t\t\tcontext.isError,\n\t\t\t),\n\t\t);\n\t\treturn text;\n\t},\n};\n"]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Display path for a file that lives inside a skill directory: `<skill>/<path inside the skill>`.
3
+ *
4
+ * A skill directory is the nearest ancestor holding a `SKILL.md`. The search never considers the cwd or
5
+ * its ancestors (a session running inside a skill keeps its cwd-relative paths), the home directory, or
6
+ * the filesystem root.
7
+ */
8
+ export declare function getSkillReadPath(absolutePath: string, cwd: string): string | undefined;
9
+ //# sourceMappingURL=skill-read-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-read-path.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/renderers/skill-read-path.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsCH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAItF"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Display path for a file that lives inside a skill directory: `<skill>/<path inside the skill>`.
3
+ *
4
+ * A skill directory is the nearest ancestor holding a `SKILL.md`. The search never considers the cwd or
5
+ * its ancestors (a session running inside a skill keeps its cwd-relative paths), the home directory, or
6
+ * the filesystem root.
7
+ */
8
+ import { existsSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { basename, dirname, isAbsolute, join, relative, resolve as resolvePath, sep } from "node:path";
11
+ /** Transcript projection asks on every frame, so each directory is probed at most once per cwd. */
12
+ const skillRootByDirectory = new Map();
13
+ const SKILL_ROOT_CACHE_LIMIT = 2048;
14
+ function isSameOrInside(parent, child) {
15
+ const path = relative(parent, child);
16
+ return path === "" || (path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute(path));
17
+ }
18
+ function findSkillRoot(absolutePath, cwd) {
19
+ const home = homedir();
20
+ const visited = [];
21
+ let skillRoot = null;
22
+ for (let directory = dirname(absolutePath);; directory = dirname(directory)) {
23
+ const key = `${cwd}\0${directory}`;
24
+ const cached = skillRootByDirectory.get(key);
25
+ if (cached !== undefined) {
26
+ skillRoot = cached;
27
+ break;
28
+ }
29
+ if (directory === dirname(directory) || directory === home || isSameOrInside(directory, cwd))
30
+ break;
31
+ visited.push(key);
32
+ if (existsSync(join(directory, "SKILL.md"))) {
33
+ skillRoot = directory;
34
+ break;
35
+ }
36
+ }
37
+ if (skillRootByDirectory.size + visited.length > SKILL_ROOT_CACHE_LIMIT)
38
+ skillRootByDirectory.clear();
39
+ for (const key of visited)
40
+ skillRootByDirectory.set(key, skillRoot);
41
+ return skillRoot ?? undefined;
42
+ }
43
+ export function getSkillReadPath(absolutePath, cwd) {
44
+ const skillRoot = findSkillRoot(resolvePath(absolutePath), resolvePath(cwd));
45
+ if (skillRoot === undefined)
46
+ return undefined;
47
+ return [basename(skillRoot), ...relative(skillRoot, absolutePath).split(sep)].join("/");
48
+ }
49
+ //# sourceMappingURL=skill-read-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-read-path.js","sourceRoot":"","sources":["../../../../src/core/tools/renderers/skill-read-path.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,WAAW,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEvG,mGAAmG;AACnG,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAyB,CAAC;AAC9D,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAEpC,SAAS,cAAc,CAAC,MAAc,EAAE,KAAa;IACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,aAAa,CAAC,YAAoB,EAAE,GAAW;IACvD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,KAAK,IAAI,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,GAAI,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9E,MAAM,GAAG,GAAG,GAAG,GAAG,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,SAAS,GAAG,MAAM,CAAC;YACnB,MAAM;QACP,CAAC;QACD,IAAI,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,KAAK,IAAI,IAAI,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC;YAAE,MAAM;QACpG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;YAC7C,SAAS,GAAG,SAAS,CAAC;YACtB,MAAM;QACP,CAAC;IACF,CAAC;IACD,IAAI,oBAAoB,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,sBAAsB;QAAE,oBAAoB,CAAC,KAAK,EAAE,CAAC;IACtG,KAAK,MAAM,GAAG,IAAI,OAAO;QAAE,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACpE,OAAO,SAAS,IAAI,SAAS,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,YAAoB,EAAE,GAAW;IACjE,MAAM,SAAS,GAAG,aAAa,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzF,CAAC","sourcesContent":["/**\n * Display path for a file that lives inside a skill directory: `<skill>/<path inside the skill>`.\n *\n * A skill directory is the nearest ancestor holding a `SKILL.md`. The search never considers the cwd or\n * its ancestors (a session running inside a skill keeps its cwd-relative paths), the home directory, or\n * the filesystem root.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve as resolvePath, sep } from \"node:path\";\n\n/** Transcript projection asks on every frame, so each directory is probed at most once per cwd. */\nconst skillRootByDirectory = new Map<string, string | null>();\nconst SKILL_ROOT_CACHE_LIMIT = 2048;\n\nfunction isSameOrInside(parent: string, child: string): boolean {\n\tconst path = relative(parent, child);\n\treturn path === \"\" || (path !== \"..\" && !path.startsWith(`..${sep}`) && !isAbsolute(path));\n}\n\nfunction findSkillRoot(absolutePath: string, cwd: string): string | undefined {\n\tconst home = homedir();\n\tconst visited: string[] = [];\n\tlet skillRoot: string | null = null;\n\tfor (let directory = dirname(absolutePath); ; directory = dirname(directory)) {\n\t\tconst key = `${cwd}\\0${directory}`;\n\t\tconst cached = skillRootByDirectory.get(key);\n\t\tif (cached !== undefined) {\n\t\t\tskillRoot = cached;\n\t\t\tbreak;\n\t\t}\n\t\tif (directory === dirname(directory) || directory === home || isSameOrInside(directory, cwd)) break;\n\t\tvisited.push(key);\n\t\tif (existsSync(join(directory, \"SKILL.md\"))) {\n\t\t\tskillRoot = directory;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (skillRootByDirectory.size + visited.length > SKILL_ROOT_CACHE_LIMIT) skillRootByDirectory.clear();\n\tfor (const key of visited) skillRootByDirectory.set(key, skillRoot);\n\treturn skillRoot ?? undefined;\n}\n\nexport function getSkillReadPath(absolutePath: string, cwd: string): string | undefined {\n\tconst skillRoot = findSkillRoot(resolvePath(absolutePath), resolvePath(cwd));\n\tif (skillRoot === undefined) return undefined;\n\treturn [basename(skillRoot), ...relative(skillRoot, absolutePath).split(sep)].join(\"/\");\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAOH,OAAO,EAAE,KAAK,IAAI,EAAgF,MAAM,eAAe,CAAC;AA+BxH,OAAO,EACN,6BAA6B,EAG7B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,KAAK,gCAAgC,EAA6B,MAAM,iCAAiC,CAAC;AACnH,OAAO,EACN,KAAK,6BAA6B,EAGlC,MAAM,kCAAkC,CAAC;AAM1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAQlE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,KAAK,OAAO,EAAyB,MAAM,yBAAyB,CAAC;AAQ9E,OAAO,EAAwB,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEjF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AA8C7D,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAChD,6BAA6B,EAAE,CAKjC;AAuCD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,IAAI,EACZ,kBAAkB,EAAE,OAAO,EAC3B,kBAAkB,GAAE,SAAS,MAAM,EAAiE,EACpG,gBAAgB,CAAC,EAAE,OAAO,GACxB,OAAO,CAQT;AAsPD,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,IAAI,EACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,cAAc,CAAC,CAqGzB;AA0HD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAYhF;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,IAAI,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,kGAAkG;AAClG,wBAAgB,uBAAuB,CACtC,aAAa,EAAE,uBAAuB,EACtC,KAAK,GAAE;IACN,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;IACvC,sBAAsB,CAAC,EAAE,eAAe,CAAC;IACzC,uBAAuB,CAAC,EAAE,UAAU,CAAC,OAAO,6BAA6B,CAAC,CAAC;IAC3E;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CACvB,GACJ,gCAAgC,CA+LlC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,iBAke/D"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAOH,OAAO,EAAE,KAAK,IAAI,EAAgF,MAAM,eAAe,CAAC;AA+BxH,OAAO,EACN,6BAA6B,EAG7B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,KAAK,gCAAgC,EAA6B,MAAM,iCAAiC,CAAC;AACnH,OAAO,EACN,KAAK,6BAA6B,EAGlC,MAAM,kCAAkC,CAAC;AAM1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAQlE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,KAAK,OAAO,EAAyB,MAAM,yBAAyB,CAAC;AAQ9E,OAAO,EAAwB,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEjF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AA8C7D,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAChD,6BAA6B,EAAE,CAKjC;AAuCD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,IAAI,EACZ,kBAAkB,EAAE,OAAO,EAC3B,kBAAkB,GAAE,SAAS,MAAM,EAAiE,EACpG,gBAAgB,CAAC,EAAE,OAAO,GACxB,OAAO,CAQT;AAsPD,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,IAAI,EACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,cAAc,CAAC,CAqGzB;AA0HD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAYhF;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,IAAI,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,kGAAkG;AAClG,wBAAgB,uBAAuB,CACtC,aAAa,EAAE,uBAAuB,EACtC,KAAK,GAAE;IACN,kBAAkB,CAAC,EAAE,eAAe,EAAE,CAAC;IACvC,sBAAsB,CAAC,EAAE,eAAe,CAAC;IACzC,uBAAuB,CAAC,EAAE,UAAU,CAAC,OAAO,6BAA6B,CAAC,CAAC;IAC3E;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CACvB,GACJ,gCAAgC,CAqMlC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,iBAke/D"}
package/dist/main.js CHANGED
@@ -551,6 +551,10 @@ export function createCliRuntimeFactory(configuration, local = {}) {
551
551
  const resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);
552
552
  return async ({ cwd, agentDir, sessionManager, sessionStartEvent, projectTrustContext, launchProfile, mcpRegistry, }) => {
553
553
  const isInitialRuntime = sessionStartEvent === undefined;
554
+ const markSwitch = (label) => {
555
+ if (sessionStartEvent?.reason === "resume")
556
+ time(label, "switch");
557
+ };
554
558
  const projectTrustDiagnostics = [];
555
559
  const cachedProjectTrust = projectTrustByCwd.get(cwd);
556
560
  const hasTrustRequiringResources = hasTrustRequiringProjectResources(cwd);
@@ -616,6 +620,7 @@ export function createCliRuntimeFactory(configuration, local = {}) {
616
620
  extensionFactories,
617
621
  },
618
622
  });
623
+ markSwitch("services");
619
624
  const { settingsManager, modelRuntime, resourceLoader } = services;
620
625
  const diagnostics = [
621
626
  ...projectTrustDiagnostics,
@@ -663,6 +668,7 @@ export function createCliRuntimeFactory(configuration, local = {}) {
663
668
  if (isInitialRuntime) {
664
669
  startupLoadingIndicator.setPhase("opening session");
665
670
  }
671
+ markSwitch("sessionOptions");
666
672
  const created = await createAgentSessionFromServices({
667
673
  services,
668
674
  sessionManager,
@@ -677,6 +683,7 @@ export function createCliRuntimeFactory(configuration, local = {}) {
677
683
  customTools: sessionOptions.customTools,
678
684
  autoTitleSessions: resolveAutoTitleSessions(appMode, parsed, sessionManager.hasContextMessages(), parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")), launchProfile?.autoTitle),
679
685
  });
686
+ markSwitch("createSession");
680
687
  const cliThinkingOverride = runtimeParsed.thinking !== undefined || cliThinkingFromModel;
681
688
  if (created.session.model && cliThinkingOverride) {
682
689
  created.session.setThinkingLevel(created.session.thinkingLevel);