@code-yeongyu/senpi 2026.9.24-2 → 2026.9.24-3

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 (300) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/bundle/chunks/{anthropic-messages-UPLQFNTT.js → anthropic-messages-UYDVRFAS.js} +1 -1
  3. package/dist/bundle/chunks/{app-server-command-UHPJ2C4D.js → app-server-command-OTRHYRIB.js} +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-XAR2E66I.js → azure-openai-responses-DODWR4W6.js} +1 -1
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  6. package/dist/bundle/chunks/{chunk-WISJJQ4K.js → chunk-6Q6DGME2.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-YWO3OBYK.js → chunk-77ACEMYL.js} +1 -1
  8. package/dist/bundle/chunks/chunk-ELFCNCBY.js +11 -0
  9. package/dist/bundle/chunks/{chunk-WTSAB6AE.js → chunk-FD34HSJJ.js} +2 -2
  10. package/dist/bundle/chunks/{chunk-2PLPSKHD.js → chunk-HZAKOVHN.js} +1 -1
  11. package/dist/bundle/chunks/chunk-JBOV6VNK.js +8 -0
  12. package/dist/bundle/chunks/{chunk-YBC274GY.js → chunk-KMJXSXRX.js} +3 -3
  13. package/dist/bundle/chunks/{chunk-JRQSHZPP.js → chunk-OZCB6BP3.js} +4 -3
  14. package/dist/bundle/chunks/{chunk-NQAVM5XL.js → chunk-SFYHCFRO.js} +1 -1
  15. package/dist/bundle/chunks/{chunk-ONR57UMO.js → chunk-TTY5BHCG.js} +1 -1
  16. package/dist/bundle/chunks/{chunk-YKU45B65.js → chunk-UM43CBL4.js} +156 -98
  17. package/dist/bundle/chunks/{chunk-NGHOUIPR.js → chunk-WM5FVFAP.js} +2 -2
  18. package/dist/bundle/chunks/{chunk-NKVUDCGZ.js → chunk-ZKZAATFM.js} +1 -1
  19. package/dist/bundle/chunks/{cli-main-O5Y3TBID.js → cli-main-TX6I4X4F.js} +1 -1
  20. package/dist/bundle/chunks/{google-generative-ai-B5QMFONL.js → google-generative-ai-VIEFECKJ.js} +1 -1
  21. package/dist/bundle/chunks/{google-vertex-O2TGMVWF.js → google-vertex-Q64CKFID.js} +1 -1
  22. package/dist/bundle/chunks/{help-fast-path-Y33OIZBU.js → help-fast-path-ZGKPSDFO.js} +1 -1
  23. package/dist/bundle/chunks/{host-command-WJOL27Q7.js → host-command-BMHJ4YUD.js} +1 -1
  24. package/dist/bundle/chunks/{host-lifecycle-YBFXYFZP.js → host-lifecycle-2GZAGSGW.js} +1 -1
  25. package/dist/bundle/chunks/{interactive-host-runtime-XVTF3NUD.js → interactive-host-runtime-YI75GFD5.js} +1 -1
  26. package/dist/bundle/chunks/{interactive-mode-OO3NGM4G.js → interactive-mode-UI5Q6FGY.js} +1 -1
  27. package/dist/bundle/chunks/{multi-session-host-6MKBBOKF.js → multi-session-host-D6HMI3RQ.js} +1 -1
  28. package/dist/bundle/chunks/{openai-codex-responses-CK7T4WNM.js → openai-codex-responses-YSGZZDD5.js} +1 -1
  29. package/dist/bundle/chunks/{openai-completions-OPQKN7FH.js → openai-completions-4CLXDDHJ.js} +3 -3
  30. package/dist/bundle/chunks/openai-responses-IBFGBAJP.js +2 -0
  31. package/dist/bundle/chunks/{package-manager-cli-BMEWLAI2.js → package-manager-cli-3UWH3ZZS.js} +1 -1
  32. package/dist/bundle/chunks/{rotation-stream-ZFA6ELXJ.js → rotation-stream-NATO6IMN.js} +1 -1
  33. package/dist/bundle/chunks/{rpc-mode-5653CV65.js → rpc-mode-LXIZHJSJ.js} +1 -1
  34. package/dist/bundle/chunks/{session-picker-PPYK56TA.js → session-picker-BP7THCWF.js} +1 -1
  35. package/dist/bundle/chunks/session-worker.js +190 -131
  36. package/dist/bundle/cli.js +1 -1
  37. package/dist/bundle/index.js +1 -1
  38. package/dist/bundle/rpc-entry.js +1 -1
  39. package/dist/core/agent-session.d.ts +3 -0
  40. package/dist/core/agent-session.d.ts.map +1 -1
  41. package/dist/core/agent-session.js +42 -7
  42. package/dist/core/agent-session.js.map +1 -1
  43. package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
  44. package/dist/core/dynamic-prompt/build.js +3 -0
  45. package/dist/core/dynamic-prompt/build.js.map +1 -1
  46. package/dist/core/dynamic-prompt/handoff.d.ts +16 -0
  47. package/dist/core/dynamic-prompt/handoff.d.ts.map +1 -0
  48. package/dist/core/dynamic-prompt/handoff.js +16 -0
  49. package/dist/core/dynamic-prompt/handoff.js.map +1 -0
  50. package/dist/core/dynamic-prompt/index.d.ts +1 -0
  51. package/dist/core/dynamic-prompt/index.d.ts.map +1 -1
  52. package/dist/core/dynamic-prompt/index.js +1 -0
  53. package/dist/core/dynamic-prompt/index.js.map +1 -1
  54. package/dist/core/dynamic-prompt/policies.d.ts.map +1 -1
  55. package/dist/core/dynamic-prompt/policies.js +2 -1
  56. package/dist/core/dynamic-prompt/policies.js.map +1 -1
  57. package/dist/core/dynamic-prompt/style.js +2 -2
  58. package/dist/core/dynamic-prompt/style.js.map +1 -1
  59. package/dist/core/environment-context.d.ts +13 -0
  60. package/dist/core/environment-context.d.ts.map +1 -1
  61. package/dist/core/environment-context.js +31 -0
  62. package/dist/core/environment-context.js.map +1 -1
  63. package/dist/core/extensions/builtin/anthropic-bash/index.d.ts.map +1 -1
  64. package/dist/core/extensions/builtin/anthropic-bash/index.js +1 -1
  65. package/dist/core/extensions/builtin/anthropic-bash/index.js.map +1 -1
  66. package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts.map +1 -1
  67. package/dist/core/extensions/builtin/anthropic-web-search/index.js +1 -1
  68. package/dist/core/extensions/builtin/anthropic-web-search/index.js.map +1 -1
  69. package/dist/core/extensions/builtin/bash-timeout/index.d.ts.map +1 -1
  70. package/dist/core/extensions/builtin/bash-timeout/index.js +1 -1
  71. package/dist/core/extensions/builtin/bash-timeout/index.js.map +1 -1
  72. package/dist/core/extensions/builtin/cache-keepalive/index.d.ts +1 -0
  73. package/dist/core/extensions/builtin/cache-keepalive/index.d.ts.map +1 -1
  74. package/dist/core/extensions/builtin/cache-keepalive/index.js +4 -0
  75. package/dist/core/extensions/builtin/cache-keepalive/index.js.map +1 -1
  76. package/dist/core/extensions/builtin/cache-keepalive/prewarm-entry.d.ts +21 -0
  77. package/dist/core/extensions/builtin/cache-keepalive/prewarm-entry.d.ts.map +1 -0
  78. package/dist/core/extensions/builtin/cache-keepalive/prewarm-entry.js +23 -0
  79. package/dist/core/extensions/builtin/cache-keepalive/prewarm-entry.js.map +1 -0
  80. package/dist/core/extensions/builtin/cache-keepalive/session-prewarm.d.ts +25 -0
  81. package/dist/core/extensions/builtin/cache-keepalive/session-prewarm.d.ts.map +1 -0
  82. package/dist/core/extensions/builtin/cache-keepalive/session-prewarm.js +86 -0
  83. package/dist/core/extensions/builtin/cache-keepalive/session-prewarm.js.map +1 -0
  84. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  85. package/dist/core/extensions/builtin/compaction/index.js +6 -2
  86. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  87. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +3 -1
  88. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
  89. package/dist/core/extensions/builtin/compaction/todo-bridge.js +6 -3
  90. package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
  91. package/dist/core/extensions/builtin/goal/continuation.d.ts +1 -0
  92. package/dist/core/extensions/builtin/goal/continuation.d.ts.map +1 -1
  93. package/dist/core/extensions/builtin/goal/continuation.js +1 -1
  94. package/dist/core/extensions/builtin/goal/continuation.js.map +1 -1
  95. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.d.ts +2 -0
  96. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.d.ts.map +1 -1
  97. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.js +2 -0
  98. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.js.map +1 -1
  99. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  100. package/dist/core/extensions/builtin/goal/index.js +14 -0
  101. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  102. package/dist/core/extensions/builtin/goal/todo-owed-backstop.d.ts +47 -0
  103. package/dist/core/extensions/builtin/goal/todo-owed-backstop.d.ts.map +1 -0
  104. package/dist/core/extensions/builtin/goal/todo-owed-backstop.js +155 -0
  105. package/dist/core/extensions/builtin/goal/todo-owed-backstop.js.map +1 -0
  106. package/dist/core/extensions/builtin/hooks/index.d.ts.map +1 -1
  107. package/dist/core/extensions/builtin/hooks/index.js +6 -2
  108. package/dist/core/extensions/builtin/hooks/index.js.map +1 -1
  109. package/dist/core/extensions/builtin/imagegen/index.d.ts.map +1 -1
  110. package/dist/core/extensions/builtin/imagegen/index.js +1 -1
  111. package/dist/core/extensions/builtin/imagegen/index.js.map +1 -1
  112. package/dist/core/extensions/builtin/mcp/index.d.ts.map +1 -1
  113. package/dist/core/extensions/builtin/mcp/index.js +15 -6
  114. package/dist/core/extensions/builtin/mcp/index.js.map +1 -1
  115. package/dist/core/extensions/builtin/openai-image-gen/index.d.ts.map +1 -1
  116. package/dist/core/extensions/builtin/openai-image-gen/index.js +13 -3
  117. package/dist/core/extensions/builtin/openai-image-gen/index.js.map +1 -1
  118. package/dist/core/extensions/builtin/openai-web-search/index.d.ts.map +1 -1
  119. package/dist/core/extensions/builtin/openai-web-search/index.js +1 -1
  120. package/dist/core/extensions/builtin/openai-web-search/index.js.map +1 -1
  121. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts.map +1 -1
  122. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +12 -1
  123. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js.map +1 -1
  124. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -1
  125. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +13 -2
  126. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -1
  127. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5-5.d.ts.map +1 -1
  128. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5-5.js +13 -2
  129. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5-5.js.map +1 -1
  130. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.d.ts.map +1 -1
  131. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js +14 -3
  132. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js.map +1 -1
  133. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.d.ts.map +1 -1
  134. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +15 -1
  135. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
  136. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
  137. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +17 -5
  138. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  139. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +6 -2
  140. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
  141. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +11 -2
  142. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
  143. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.d.ts.map +1 -1
  144. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +10 -1
  145. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js.map +1 -1
  146. package/dist/core/extensions/builtin/prompt-preset/grok-4.6.d.ts.map +1 -1
  147. package/dist/core/extensions/builtin/prompt-preset/grok-4.6.js +12 -4
  148. package/dist/core/extensions/builtin/prompt-preset/grok-4.6.js.map +1 -1
  149. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.d.ts.map +1 -1
  150. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js +45 -31
  151. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js.map +1 -1
  152. package/dist/core/extensions/builtin/prompt-preset/index.d.ts.map +1 -1
  153. package/dist/core/extensions/builtin/prompt-preset/index.js +3 -2
  154. package/dist/core/extensions/builtin/prompt-preset/index.js.map +1 -1
  155. package/dist/core/extensions/builtin/prompt-preset/kimi-k2-code.js +1 -1
  156. package/dist/core/extensions/builtin/prompt-preset/kimi-k2-code.js.map +1 -1
  157. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts.map +1 -1
  158. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +13 -2
  159. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js.map +1 -1
  160. package/dist/core/extensions/builtin/prompt-url-widget.d.ts.map +1 -1
  161. package/dist/core/extensions/builtin/prompt-url-widget.js +4 -3
  162. package/dist/core/extensions/builtin/prompt-url-widget.js.map +1 -1
  163. package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
  164. package/dist/core/extensions/builtin/rules/index.js +15 -8
  165. package/dist/core/extensions/builtin/rules/index.js.map +1 -1
  166. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  167. package/dist/core/extensions/builtin/terminal/extension.js +1 -1
  168. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  169. package/dist/core/extensions/builtin/todotools/commands.d.ts +2 -1
  170. package/dist/core/extensions/builtin/todotools/commands.d.ts.map +1 -1
  171. package/dist/core/extensions/builtin/todotools/commands.js +6 -3
  172. package/dist/core/extensions/builtin/todotools/commands.js.map +1 -1
  173. package/dist/core/extensions/builtin/todotools/first-turn.d.ts +38 -0
  174. package/dist/core/extensions/builtin/todotools/first-turn.d.ts.map +1 -0
  175. package/dist/core/extensions/builtin/todotools/first-turn.js +83 -0
  176. package/dist/core/extensions/builtin/todotools/first-turn.js.map +1 -0
  177. package/dist/core/extensions/builtin/todotools/index.d.ts +1 -1
  178. package/dist/core/extensions/builtin/todotools/index.d.ts.map +1 -1
  179. package/dist/core/extensions/builtin/todotools/index.js +69 -14
  180. package/dist/core/extensions/builtin/todotools/index.js.map +1 -1
  181. package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -2
  182. package/dist/core/extensions/builtin/todotools/prompt.d.ts.map +1 -1
  183. package/dist/core/extensions/builtin/todotools/prompt.js +2 -3
  184. package/dist/core/extensions/builtin/todotools/prompt.js.map +1 -1
  185. package/dist/core/extensions/builtin/todotools/state.d.ts +4 -3
  186. package/dist/core/extensions/builtin/todotools/state.d.ts.map +1 -1
  187. package/dist/core/extensions/builtin/todotools/state.js +4 -3
  188. package/dist/core/extensions/builtin/todotools/state.js.map +1 -1
  189. package/dist/core/extensions/builtin/todotools/todo-ask.d.ts +13 -0
  190. package/dist/core/extensions/builtin/todotools/todo-ask.d.ts.map +1 -0
  191. package/dist/core/extensions/builtin/todotools/todo-ask.js +61 -0
  192. package/dist/core/extensions/builtin/todotools/todo-ask.js.map +1 -0
  193. package/dist/core/extensions/builtin/todotools/todo-format.d.ts +30 -2
  194. package/dist/core/extensions/builtin/todotools/todo-format.d.ts.map +1 -1
  195. package/dist/core/extensions/builtin/todotools/todo-format.js +58 -1
  196. package/dist/core/extensions/builtin/todotools/todo-format.js.map +1 -1
  197. package/dist/core/extensions/builtin/todotools/todo-storage.d.ts +5 -2
  198. package/dist/core/extensions/builtin/todotools/todo-storage.d.ts.map +1 -1
  199. package/dist/core/extensions/builtin/todotools/todo-storage.js +23 -12
  200. package/dist/core/extensions/builtin/todotools/todo-storage.js.map +1 -1
  201. package/dist/core/extensions/builtin/todotools/todo-types.d.ts +14 -0
  202. package/dist/core/extensions/builtin/todotools/todo-types.d.ts.map +1 -1
  203. package/dist/core/extensions/builtin/todotools/todo-types.js +2 -0
  204. package/dist/core/extensions/builtin/todotools/todo-types.js.map +1 -1
  205. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts +3 -1
  206. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -1
  207. package/dist/core/extensions/builtin/todotools/tools/todo.js +23 -8
  208. package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -1
  209. package/dist/core/extensions/loader.d.ts.map +1 -1
  210. package/dist/core/extensions/loader.js +5 -1
  211. package/dist/core/extensions/loader.js.map +1 -1
  212. package/dist/core/extensions/runner.d.ts +7 -1
  213. package/dist/core/extensions/runner.d.ts.map +1 -1
  214. package/dist/core/extensions/runner.js +27 -2
  215. package/dist/core/extensions/runner.js.map +1 -1
  216. package/dist/core/extensions/types.d.ts +53 -1
  217. package/dist/core/extensions/types.d.ts.map +1 -1
  218. package/dist/core/extensions/types.js.map +1 -1
  219. package/dist/core/messages.d.ts.map +1 -1
  220. package/dist/core/messages.js +10 -2
  221. package/dist/core/messages.js.map +1 -1
  222. package/dist/core/model-runtime.d.ts +11 -1
  223. package/dist/core/model-runtime.d.ts.map +1 -1
  224. package/dist/core/model-runtime.js +13 -0
  225. package/dist/core/model-runtime.js.map +1 -1
  226. package/dist/core/prompt-cache-prefix-request.d.ts +45 -0
  227. package/dist/core/prompt-cache-prefix-request.d.ts.map +1 -0
  228. package/dist/core/prompt-cache-prefix-request.js +134 -0
  229. package/dist/core/prompt-cache-prefix-request.js.map +1 -0
  230. package/dist/core/settings-manager.d.ts +4 -1
  231. package/dist/core/settings-manager.d.ts.map +1 -1
  232. package/dist/core/settings-manager.js +8 -0
  233. package/dist/core/settings-manager.js.map +1 -1
  234. package/dist/core/settings-shapes.d.ts +5 -0
  235. package/dist/core/settings-shapes.d.ts.map +1 -1
  236. package/dist/core/settings-shapes.js.map +1 -1
  237. package/dist/core/usage-totals.d.ts.map +1 -1
  238. package/dist/core/usage-totals.js +6 -0
  239. package/dist/core/usage-totals.js.map +1 -1
  240. package/docs/extensions.md +22 -0
  241. package/docs/settings.md +7 -0
  242. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  243. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  244. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  245. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +16 -3
  246. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  247. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.d.ts.map +1 -1
  248. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js +24 -17
  249. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  251. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +57 -3
  252. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-prompt-cache.d.ts +24 -0
  254. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-prompt-cache.d.ts.map +1 -0
  255. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-prompt-cache.js +62 -0
  256. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-prompt-cache.js.map +1 -0
  257. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts +6 -0
  258. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
  259. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +12 -4
  260. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
  261. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts +11 -1
  262. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  263. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +63 -9
  264. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  265. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.lazy.d.ts.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.lazy.js +5 -0
  267. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.lazy.js.map +1 -1
  268. package/node_modules/@earendil-works/pi-ai/dist/api/prompt-cache-warmers.d.ts +13 -0
  269. package/node_modules/@earendil-works/pi-ai/dist/api/prompt-cache-warmers.d.ts.map +1 -0
  270. package/node_modules/@earendil-works/pi-ai/dist/api/prompt-cache-warmers.js +8 -0
  271. package/node_modules/@earendil-works/pi-ai/dist/api/prompt-cache-warmers.js.map +1 -0
  272. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.d.ts +4 -2
  273. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.d.ts.map +1 -1
  274. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.js +22 -0
  275. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.js.map +1 -1
  276. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  277. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  279. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  281. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google-vertex.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/vercel-ai-gateway.json +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +13 -0
  285. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +8 -0
  289. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-choice-fallback.d.ts.map +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-choice-fallback.js +7 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/utils/tool-choice-fallback.js.map +1 -1
  293. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  294. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  295. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  296. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  297. package/package.json +7 -7
  298. package/dist/bundle/chunks/chunk-J7IUURQ6.js +0 -8
  299. package/dist/bundle/chunks/chunk-MO2U7YRX.js +0 -11
  300. package/dist/bundle/chunks/openai-responses-QHWM3KPO.js +0 -2
@@ -3,7 +3,64 @@
3
3
  // Copyright (c) 2025-2026 Can Bölük
4
4
  // https://github.com/can1357/oh-my-pi
5
5
  import { stripAnsi } from "../../../../utils/ansi.js";
6
- export function formatSummary(phases, errors, readOnly = false) {
6
+ import { nextActionableTask } from "./todo-query.js";
7
+ /**
8
+ * The three handoff anchors of a todo state: the captured user request, the task in
9
+ * progress, and the first pending task after it in phase order (it may sit in an earlier
10
+ * phase after an out-of-order start). Task labels are verbatim.
11
+ */
12
+ export function describeAskNowNext(state) {
13
+ const ask = state.ask?.text ?? "(no user request captured)";
14
+ const located = state.phases.flatMap((phase) => phase.tasks.map((task) => ({ task, phase: phase.name })));
15
+ if (located.length === 0)
16
+ return { ask, now: "none - no todo list", next: "none" };
17
+ const nowTask = nextActionableTask(state.phases);
18
+ const now = located.find((hit) => hit.task === nowTask);
19
+ const next = located.find((hit) => hit.task.status === "pending" && hit.task !== nowTask);
20
+ return {
21
+ ask,
22
+ now: now ? `${now.task.content} (${now.phase})` : "none - all tasks closed",
23
+ next: next ? `${next.task.content} (${next.phase})` : "none",
24
+ };
25
+ }
26
+ /**
27
+ * Which handoff moment a successful mutation produced, if any: the list was just created, the
28
+ * last open task of a phase closed, or the last open task of the whole list closed. The result
29
+ * carries the cue right before the model writes its next text, where a system-prompt rule alone
30
+ * proved unreliable on weaker models (senpi#2121 real-surface QA).
31
+ */
32
+ export function handoffMomentOf(before, after, createsList) {
33
+ const hasOpen = (tasks) => tasks.some((task) => !isTerminalTodoStatus(task.status));
34
+ const afterTasks = after.flatMap((phase) => phase.tasks);
35
+ if (afterTasks.length === 0)
36
+ return undefined;
37
+ if (createsList)
38
+ return "list-created";
39
+ if (!hasOpen(afterTasks))
40
+ return hasOpen(before.flatMap((phase) => phase.tasks)) ? "all-closed" : undefined;
41
+ const closedPhase = after.some((phase) => phase.tasks.length > 0 &&
42
+ !hasOpen(phase.tasks) &&
43
+ hasOpen(before.find((prior) => prior.name === phase.name)?.tasks ?? []));
44
+ return closedPhase ? "phase-closed" : undefined;
45
+ }
46
+ export const HANDOFF_CUES = {
47
+ "list-created": "Handoff due: the plan exists. Before your next tool call, write the Ask / For you / Now / Next block.",
48
+ "phase-closed": "Handoff due: a phase closed. Before your next tool call, write the Ask / For you / Now / Next block.",
49
+ "all-closed": "Handoff due: every task is closed - the final message is the Ask / For you / Now: none / Next: none block.",
50
+ };
51
+ /** The cue line appended to a todo result, or nothing when no handoff moment was reached. */
52
+ export function formatHandoffCue(moment) {
53
+ return moment ? `\n\n${HANDOFF_CUES[moment]}` : "";
54
+ }
55
+ /** `Ask:` / `Now:` / `Next:` lines plus a blank separator line. */
56
+ export function formatAskNowNextHeader(phases, ask) {
57
+ const anchors = describeAskNowNext({ phases, ask });
58
+ return `Ask: ${anchors.ask}\nNow: ${anchors.now}\nNext: ${anchors.next}\n\n`;
59
+ }
60
+ export function formatSummary(phases, errors, readOnly = false, ask) {
61
+ return `${formatAskNowNextHeader(phases, ask)}${formatListSummary(phases, errors, readOnly)}`;
62
+ }
63
+ function formatListSummary(phases, errors, readOnly) {
7
64
  const tasks = phases.flatMap((phase) => phase.tasks);
8
65
  if (tasks.length === 0) {
9
66
  if (errors.length > 0)
@@ -1 +1 @@
1
- {"version":3,"file":"todo-format.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-format.ts"],"names":[],"mappings":"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","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nimport { stripAnsi } from \"../../../../utils/ansi.ts\";\nimport type { TodoItem, TodoPhase } from \"./todo-types.ts\";\n\nexport function formatSummary(phases: readonly TodoPhase[], errors: readonly string[], readOnly = false): string {\n\tconst tasks = phases.flatMap((phase) => phase.tasks);\n\tif (tasks.length === 0) {\n\t\tif (errors.length > 0) return `Errors: ${errors.join(\"; \")}`;\n\t\treturn readOnly ? \"Todo list is empty.\" : \"Todo list cleared.\";\n\t}\n\n\tconst remainingByPhase = phases\n\t\t.map((phase) => ({\n\t\t\tname: phase.name,\n\t\t\ttasks: phase.tasks.filter((task) => task.status === \"pending\" || task.status === \"in_progress\"),\n\t\t}))\n\t\t.filter((phase) => phase.tasks.length > 0);\n\tconst remainingTasks = remainingByPhase.flatMap((phase) =>\n\t\tphase.tasks.map((task) => ({ ...task, phase: phase.name })),\n\t);\n\n\tlet currentIdx = phases.findIndex((phase) =>\n\t\tphase.tasks.some((task) => task.status === \"pending\" || task.status === \"in_progress\"),\n\t);\n\tif (currentIdx === -1) currentIdx = phases.length - 1;\n\tconst current = phases[currentIdx];\n\tconst done = current.tasks.filter((task) => task.status === \"completed\" || task.status === \"abandoned\").length;\n\n\tconst lines: string[] = [];\n\tif (errors.length > 0) lines.push(`Errors: ${errors.join(\"; \")}`);\n\tif (remainingTasks.length === 0) {\n\t\tlines.push(\"Remaining items: none.\");\n\t} else {\n\t\tlines.push(`Remaining items (${remainingTasks.length}):`);\n\t\tfor (const task of remainingTasks) lines.push(` - ${task.content} [${task.status}] (${task.phase})`);\n\t}\n\n\tconst closedAll = tasks.filter((task) => task.status === \"completed\" || task.status === \"abandoned\").length;\n\tconst workedAhead = phases.some(\n\t\t(phase, index) =>\n\t\t\tindex > currentIdx && phase.tasks.some((task) => task.status === \"completed\" || task.status === \"abandoned\"),\n\t);\n\tlines.push(`Overall: ${closedAll}/${tasks.length} done, ${remainingTasks.length} open.`);\n\tlines.push(\n\t\t`Active phase ${currentIdx + 1}/${phases.length} \"${current.name}\" (${done}/${current.tasks.length})${\n\t\t\tworkedAhead\n\t\t\t\t? \" — earliest phase with open tasks; the in-progress pointer auto-advances to the earliest open task on each completion, so it can sit behind out-of-order work (nothing was un-completed).\"\n\t\t\t\t: \".\"\n\t\t}`,\n\t);\n\tfor (const phase of phases) {\n\t\tlines.push(` ${phase.name}:`);\n\t\tfor (const task of phase.tasks) {\n\t\t\tconst checkbox = task.status === \"completed\" ? \"[X]\" : \"[ ]\";\n\t\t\tconst tag = task.status === \"in_progress\" ? \" (in progress)\" : task.status === \"abandoned\" ? \" (dropped)\" : \"\";\n\t\t\tlines.push(` - ${checkbox} ${task.content}${tag}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function sanitizeTodoText(text: string): string {\n\treturn stripAnsi(text)\n\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t.replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n}\n\nexport function isTerminalTodoStatus(status: string): boolean {\n\treturn status === \"completed\" || status === \"abandoned\" || status === \"cancelled\";\n}\n\nexport function isIncompleteTodo(todo: TodoItem): boolean {\n\treturn !isTerminalTodoStatus(todo.status);\n}\n\nexport function getTodoMarker(status: string): string {\n\tif (status === \"completed\") return \"[✓]\";\n\tif (status === \"in_progress\") return \"[•]\";\n\tif (status === \"abandoned\" || status === \"cancelled\") return \"[×]\";\n\treturn \"[ ]\";\n}\n\nexport function getTodoResultLines(phases: readonly TodoPhase[]): string[] {\n\tconst tasks = phases.flatMap((phase) => phase.tasks);\n\treturn [\n\t\t`${tasks.filter(isIncompleteTodo).length} todos`,\n\t\t...phases.flatMap((phase) => [\n\t\t\t`${sanitizeTodoText(phase.name)}:`,\n\t\t\t...phase.tasks.map((todo) => `${getTodoMarker(todo.status)} ${sanitizeTodoText(todo.content)}`),\n\t\t]),\n\t];\n}\n"]}
1
+ {"version":3,"file":"todo-format.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-format.ts"],"names":[],"mappings":"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","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nimport { stripAnsi } from \"../../../../utils/ansi.ts\";\nimport { nextActionableTask } from \"./todo-query.ts\";\nimport type { TodoAsk, TodoItem, TodoPhase } from \"./todo-types.ts\";\n\nexport type AskNowNext = { ask: string; now: string; next: string };\n\n/**\n * The three handoff anchors of a todo state: the captured user request, the task in\n * progress, and the first pending task after it in phase order (it may sit in an earlier\n * phase after an out-of-order start). Task labels are verbatim.\n */\nexport function describeAskNowNext(state: { phases: readonly TodoPhase[]; ask?: TodoAsk }): AskNowNext {\n\tconst ask = state.ask?.text ?? \"(no user request captured)\";\n\tconst located = state.phases.flatMap((phase) => phase.tasks.map((task) => ({ task, phase: phase.name })));\n\tif (located.length === 0) return { ask, now: \"none - no todo list\", next: \"none\" };\n\tconst nowTask = nextActionableTask(state.phases);\n\tconst now = located.find((hit) => hit.task === nowTask);\n\tconst next = located.find((hit) => hit.task.status === \"pending\" && hit.task !== nowTask);\n\treturn {\n\t\task,\n\t\tnow: now ? `${now.task.content} (${now.phase})` : \"none - all tasks closed\",\n\t\tnext: next ? `${next.task.content} (${next.phase})` : \"none\",\n\t};\n}\n\n/** The todo transitions at which the user is owed a handoff block (the prompts' `## Handoff` moments). */\nexport type HandoffMoment = \"list-created\" | \"phase-closed\" | \"all-closed\";\n\n/**\n * Which handoff moment a successful mutation produced, if any: the list was just created, the\n * last open task of a phase closed, or the last open task of the whole list closed. The result\n * carries the cue right before the model writes its next text, where a system-prompt rule alone\n * proved unreliable on weaker models (senpi#2121 real-surface QA).\n */\nexport function handoffMomentOf(\n\tbefore: readonly TodoPhase[],\n\tafter: readonly TodoPhase[],\n\tcreatesList: boolean,\n): HandoffMoment | undefined {\n\tconst hasOpen = (tasks: readonly TodoItem[]) => tasks.some((task) => !isTerminalTodoStatus(task.status));\n\tconst afterTasks = after.flatMap((phase) => phase.tasks);\n\tif (afterTasks.length === 0) return undefined;\n\tif (createsList) return \"list-created\";\n\tif (!hasOpen(afterTasks)) return hasOpen(before.flatMap((phase) => phase.tasks)) ? \"all-closed\" : undefined;\n\tconst closedPhase = after.some(\n\t\t(phase) =>\n\t\t\tphase.tasks.length > 0 &&\n\t\t\t!hasOpen(phase.tasks) &&\n\t\t\thasOpen(before.find((prior) => prior.name === phase.name)?.tasks ?? []),\n\t);\n\treturn closedPhase ? \"phase-closed\" : undefined;\n}\n\nexport const HANDOFF_CUES: Readonly<Record<HandoffMoment, string>> = {\n\t\"list-created\":\n\t\t\"Handoff due: the plan exists. Before your next tool call, write the Ask / For you / Now / Next block.\",\n\t\"phase-closed\":\n\t\t\"Handoff due: a phase closed. Before your next tool call, write the Ask / For you / Now / Next block.\",\n\t\"all-closed\":\n\t\t\"Handoff due: every task is closed - the final message is the Ask / For you / Now: none / Next: none block.\",\n};\n\n/** The cue line appended to a todo result, or nothing when no handoff moment was reached. */\nexport function formatHandoffCue(moment: HandoffMoment | undefined): string {\n\treturn moment ? `\\n\\n${HANDOFF_CUES[moment]}` : \"\";\n}\n\n/** `Ask:` / `Now:` / `Next:` lines plus a blank separator line. */\nexport function formatAskNowNextHeader(phases: readonly TodoPhase[], ask: TodoAsk | undefined): string {\n\tconst anchors = describeAskNowNext({ phases, ask });\n\treturn `Ask: ${anchors.ask}\\nNow: ${anchors.now}\\nNext: ${anchors.next}\\n\\n`;\n}\n\nexport function formatSummary(\n\tphases: readonly TodoPhase[],\n\terrors: readonly string[],\n\treadOnly = false,\n\task?: TodoAsk,\n): string {\n\treturn `${formatAskNowNextHeader(phases, ask)}${formatListSummary(phases, errors, readOnly)}`;\n}\n\nfunction formatListSummary(phases: readonly TodoPhase[], errors: readonly string[], readOnly: boolean): string {\n\tconst tasks = phases.flatMap((phase) => phase.tasks);\n\tif (tasks.length === 0) {\n\t\tif (errors.length > 0) return `Errors: ${errors.join(\"; \")}`;\n\t\treturn readOnly ? \"Todo list is empty.\" : \"Todo list cleared.\";\n\t}\n\n\tconst remainingByPhase = phases\n\t\t.map((phase) => ({\n\t\t\tname: phase.name,\n\t\t\ttasks: phase.tasks.filter((task) => task.status === \"pending\" || task.status === \"in_progress\"),\n\t\t}))\n\t\t.filter((phase) => phase.tasks.length > 0);\n\tconst remainingTasks = remainingByPhase.flatMap((phase) =>\n\t\tphase.tasks.map((task) => ({ ...task, phase: phase.name })),\n\t);\n\n\tlet currentIdx = phases.findIndex((phase) =>\n\t\tphase.tasks.some((task) => task.status === \"pending\" || task.status === \"in_progress\"),\n\t);\n\tif (currentIdx === -1) currentIdx = phases.length - 1;\n\tconst current = phases[currentIdx];\n\tconst done = current.tasks.filter((task) => task.status === \"completed\" || task.status === \"abandoned\").length;\n\n\tconst lines: string[] = [];\n\tif (errors.length > 0) lines.push(`Errors: ${errors.join(\"; \")}`);\n\tif (remainingTasks.length === 0) {\n\t\tlines.push(\"Remaining items: none.\");\n\t} else {\n\t\tlines.push(`Remaining items (${remainingTasks.length}):`);\n\t\tfor (const task of remainingTasks) lines.push(` - ${task.content} [${task.status}] (${task.phase})`);\n\t}\n\n\tconst closedAll = tasks.filter((task) => task.status === \"completed\" || task.status === \"abandoned\").length;\n\tconst workedAhead = phases.some(\n\t\t(phase, index) =>\n\t\t\tindex > currentIdx && phase.tasks.some((task) => task.status === \"completed\" || task.status === \"abandoned\"),\n\t);\n\tlines.push(`Overall: ${closedAll}/${tasks.length} done, ${remainingTasks.length} open.`);\n\tlines.push(\n\t\t`Active phase ${currentIdx + 1}/${phases.length} \"${current.name}\" (${done}/${current.tasks.length})${\n\t\t\tworkedAhead\n\t\t\t\t? \" — earliest phase with open tasks; the in-progress pointer auto-advances to the earliest open task on each completion, so it can sit behind out-of-order work (nothing was un-completed).\"\n\t\t\t\t: \".\"\n\t\t}`,\n\t);\n\tfor (const phase of phases) {\n\t\tlines.push(` ${phase.name}:`);\n\t\tfor (const task of phase.tasks) {\n\t\t\tconst checkbox = task.status === \"completed\" ? \"[X]\" : \"[ ]\";\n\t\t\tconst tag = task.status === \"in_progress\" ? \" (in progress)\" : task.status === \"abandoned\" ? \" (dropped)\" : \"\";\n\t\t\tlines.push(` - ${checkbox} ${task.content}${tag}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function sanitizeTodoText(text: string): string {\n\treturn stripAnsi(text)\n\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t.replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n}\n\nexport function isTerminalTodoStatus(status: string): boolean {\n\treturn status === \"completed\" || status === \"abandoned\" || status === \"cancelled\";\n}\n\nexport function isIncompleteTodo(todo: TodoItem): boolean {\n\treturn !isTerminalTodoStatus(todo.status);\n}\n\nexport function getTodoMarker(status: string): string {\n\tif (status === \"completed\") return \"[✓]\";\n\tif (status === \"in_progress\") return \"[•]\";\n\tif (status === \"abandoned\" || status === \"cancelled\") return \"[×]\";\n\treturn \"[ ]\";\n}\n\nexport function getTodoResultLines(phases: readonly TodoPhase[]): string[] {\n\tconst tasks = phases.flatMap((phase) => phase.tasks);\n\treturn [\n\t\t`${tasks.filter(isIncompleteTodo).length} todos`,\n\t\t...phases.flatMap((phase) => [\n\t\t\t`${sanitizeTodoText(phase.name)}:`,\n\t\t\t...phase.tasks.map((todo) => `${getTodoMarker(todo.status)} ${sanitizeTodoText(todo.content)}`),\n\t\t]),\n\t];\n}\n"]}
@@ -1,13 +1,16 @@
1
1
  import type { SessionEntry } from "../../../session-manager.ts";
2
- import { type TodoItem, type TodoPhase } from "./todo-types.ts";
2
+ import { type TodoAsk, type TodoItem, type TodoPhase, type TodoState } from "./todo-types.ts";
3
3
  type BranchEntry = SessionEntry;
4
+ export declare function isTodoAsk(value: unknown): value is TodoAsk;
4
5
  export declare function cloneTask(task: TodoItem): TodoItem;
5
6
  export declare function clonePhases(phases: readonly TodoPhase[]): TodoPhase[];
6
7
  export declare function isTodoItem(value: unknown): value is TodoItem;
7
8
  export declare function isTodoItemArray(value: unknown): value is TodoItem[];
8
9
  export declare function isTodoPhase(value: unknown): value is TodoPhase;
9
10
  export declare function isTodoPhaseArray(value: unknown): value is TodoPhase[];
10
- export declare function getLatestPhasesFromBranchEntries(entries: BranchEntry[]): TodoPhase[];
11
+ /** Latest todo list and its captured ask on the branch; the ask travels with the entry that wrote the list. */
12
+ export declare function getLatestTodoStateFromBranchEntries(entries: readonly BranchEntry[]): TodoState;
13
+ export declare function getLatestPhasesFromBranchEntries(entries: readonly BranchEntry[]): TodoPhase[];
11
14
  /** Compatibility reader for callers that still expect the old flat array. */
12
15
  export declare function getLatestTodosFromBranchEntries(entries: BranchEntry[]): TodoItem[];
13
16
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"todo-storage.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-storage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAGN,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,MAAM,iBAAiB,CAAC;AAEzB,KAAK,WAAW,GAAG,YAAY,CAAC;AAiEhC,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAElD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAErE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAO5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,EAAE,CAEnE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAG9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,EAAE,CAErE;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,SAAS,EAAE,CAmBpF;AAED,6EAA6E;AAC7E,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,QAAQ,EAAE,CAElF"}
1
+ {"version":3,"file":"todo-storage.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-storage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAGN,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,SAAS,EAEd,MAAM,iBAAiB,CAAC;AAEzB,KAAK,WAAW,GAAG,YAAY,CAAC;AAyDhC,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAO1D;AAcD,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAElD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAErE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAO5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,EAAE,CAEnE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAG9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,EAAE,CAErE;AAED,+GAA+G;AAC/G,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,CAmB9F;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,EAAE,CAE7F;AAED,6EAA6E;AAC7E,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,QAAQ,EAAE,CAElF"}
@@ -59,16 +59,23 @@ function parseLegacyTodos(value) {
59
59
  }
60
60
  return [{ name: DEFAULT_INIT_PHASE, tasks }];
61
61
  }
62
+ export function isTodoAsk(value) {
63
+ return (isRecord(value) &&
64
+ typeof value.entryId === "string" &&
65
+ typeof value.text === "string" &&
66
+ typeof value.capturedAt === "number");
67
+ }
62
68
  function readTodoPayload(value) {
63
69
  if (!isRecord(value))
64
70
  return undefined;
65
- if (value.schema === "v2")
66
- return parsePhases(value.phases);
67
- if (Array.isArray(value.phases))
68
- return parsePhases(value.phases);
69
- if (Array.isArray(value.todos))
70
- return parseLegacyTodos(value.todos);
71
- return undefined;
71
+ const phases = value.schema === "v2" || Array.isArray(value.phases)
72
+ ? parsePhases(value.phases)
73
+ : Array.isArray(value.todos)
74
+ ? parseLegacyTodos(value.todos)
75
+ : undefined;
76
+ if (!phases)
77
+ return undefined;
78
+ return { phases, ask: isTodoAsk(value.ask) ? { ...value.ask } : undefined };
72
79
  }
73
80
  export function cloneTask(task) {
74
81
  return { content: task.content, status: task.status };
@@ -96,13 +103,14 @@ export function isTodoPhase(value) {
96
103
  export function isTodoPhaseArray(value) {
97
104
  return Array.isArray(value) && value.every(isTodoPhase);
98
105
  }
99
- export function getLatestPhasesFromBranchEntries(entries) {
100
- let phases = [];
106
+ /** Latest todo list and its captured ask on the branch; the ask travels with the entry that wrote the list. */
107
+ export function getLatestTodoStateFromBranchEntries(entries) {
108
+ let state = { phases: [], ask: undefined };
101
109
  for (const entry of entries) {
102
110
  if (entry.type === "custom" && entry.customType === TODO_STATE_ENTRY_TYPE) {
103
111
  const parsed = readTodoPayload(entry.data);
104
112
  if (parsed)
105
- phases = clonePhases(parsed);
113
+ state = { phases: clonePhases(parsed.phases), ask: parsed.ask };
106
114
  continue;
107
115
  }
108
116
  if (entry.type !== "message" || !isRecord(entry.message))
@@ -113,9 +121,12 @@ export function getLatestPhasesFromBranchEntries(entries) {
113
121
  continue;
114
122
  const parsed = readTodoPayload(entry.message.details);
115
123
  if (parsed)
116
- phases = clonePhases(parsed);
124
+ state = { phases: clonePhases(parsed.phases), ask: parsed.ask };
117
125
  }
118
- return phases;
126
+ return state;
127
+ }
128
+ export function getLatestPhasesFromBranchEntries(entries) {
129
+ return getLatestTodoStateFromBranchEntries(entries).phases;
119
130
  }
120
131
  /** Compatibility reader for callers that still expect the old flat array. */
121
132
  export function getLatestTodosFromBranchEntries(entries) {
@@ -1 +1 @@
1
- {"version":3,"file":"todo-storage.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-storage.ts"],"names":[],"mappings":"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","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nimport type { SessionEntry } from \"../../../session-manager.ts\";\nimport {\n\tDEFAULT_INIT_PHASE,\n\tTODO_STATE_ENTRY_TYPE,\n\ttype TodoItem,\n\ttype TodoPhase,\n\ttype TodoStatus,\n} from \"./todo-types.ts\";\n\ntype BranchEntry = SessionEntry;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isTodoStatus(value: unknown): value is TodoStatus {\n\treturn value === \"pending\" || value === \"in_progress\" || value === \"completed\" || value === \"abandoned\";\n}\n\nfunction parseTodoStatus(value: unknown): TodoStatus | undefined {\n\tif (value === \"cancelled\") return \"abandoned\";\n\treturn isTodoStatus(value) ? value : undefined;\n}\n\nfunction parseTodoItem(value: unknown, options?: { lenient?: boolean }): TodoItem | undefined {\n\tif (!isRecord(value) || typeof value.content !== \"string\") return undefined;\n\tconst status = parseTodoStatus(value.status) ?? (options?.lenient ? \"pending\" : undefined);\n\treturn status ? { content: value.content, status } : undefined;\n}\n\nfunction parseTodoPhase(value: unknown): TodoPhase | undefined {\n\tif (!isRecord(value) || typeof value.name !== \"string\" || !Array.isArray(value.tasks)) return undefined;\n\tconst tasks: TodoItem[] = [];\n\tfor (const task of value.tasks) {\n\t\tconst parsed = parseTodoItem(task);\n\t\tif (!parsed) return undefined;\n\t\ttasks.push(parsed);\n\t}\n\treturn { name: value.name, tasks };\n}\n\nfunction parsePhases(value: unknown): TodoPhase[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst phases: TodoPhase[] = [];\n\tfor (const phase of value) {\n\t\tconst parsed = parseTodoPhase(phase);\n\t\tif (!parsed) return undefined;\n\t\tphases.push(parsed);\n\t}\n\treturn phases;\n}\n\nfunction parseLegacyTodos(value: unknown): TodoPhase[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst tasks: TodoItem[] = [];\n\tfor (const todo of value) {\n\t\t// Legacy todowrite persisted arbitrary status strings (e.g. \"blocked\").\n\t\t// Preserve those entries instead of dropping the whole list: unknown\n\t\t// statuses become \"pending\" so the task survives migration as open work.\n\t\tconst parsed = parseTodoItem(todo, { lenient: true });\n\t\tif (!parsed) return undefined;\n\t\ttasks.push(parsed);\n\t}\n\treturn [{ name: DEFAULT_INIT_PHASE, tasks }];\n}\n\nfunction readTodoPayload(value: unknown): TodoPhase[] | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (value.schema === \"v2\") return parsePhases(value.phases);\n\tif (Array.isArray(value.phases)) return parsePhases(value.phases);\n\tif (Array.isArray(value.todos)) return parseLegacyTodos(value.todos);\n\treturn undefined;\n}\n\nexport function cloneTask(task: TodoItem): TodoItem {\n\treturn { content: task.content, status: task.status };\n}\n\nexport function clonePhases(phases: readonly TodoPhase[]): TodoPhase[] {\n\treturn phases.map((phase) => ({ name: phase.name, tasks: phase.tasks.map(cloneTask) }));\n}\n\nexport function isTodoItem(value: unknown): value is TodoItem {\n\t// Strict guard: only the canonical TodoStatus values are accepted. Legacy\n\t// statuses like \"cancelled\" are migrated to \"abandoned\" by the parse path\n\t// (parseTodoItem/readTodoPayload), not by this guard, so a narrowed value's\n\t// status is always a sound TodoStatus rather than the unchanged input.\n\tif (!isRecord(value) || typeof value.content !== \"string\") return false;\n\treturn isTodoStatus(value.status);\n}\n\nexport function isTodoItemArray(value: unknown): value is TodoItem[] {\n\treturn Array.isArray(value) && value.every(isTodoItem);\n}\n\nexport function isTodoPhase(value: unknown): value is TodoPhase {\n\tif (!isRecord(value) || typeof value.name !== \"string\" || !Array.isArray(value.tasks)) return false;\n\treturn value.tasks.every(isTodoItem);\n}\n\nexport function isTodoPhaseArray(value: unknown): value is TodoPhase[] {\n\treturn Array.isArray(value) && value.every(isTodoPhase);\n}\n\nexport function getLatestPhasesFromBranchEntries(entries: BranchEntry[]): TodoPhase[] {\n\tlet phases: TodoPhase[] = [];\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"custom\" && entry.customType === TODO_STATE_ENTRY_TYPE) {\n\t\t\tconst parsed = readTodoPayload(entry.data);\n\t\t\tif (parsed) phases = clonePhases(parsed);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (entry.type !== \"message\" || !isRecord(entry.message)) continue;\n\t\tif (entry.message.role !== \"toolResult\") continue;\n\t\tif (entry.message.toolName !== \"todo\" && entry.message.toolName !== \"todowrite\") continue;\n\n\t\tconst parsed = readTodoPayload(entry.message.details);\n\t\tif (parsed) phases = clonePhases(parsed);\n\t}\n\n\treturn phases;\n}\n\n/** Compatibility reader for callers that still expect the old flat array. */\nexport function getLatestTodosFromBranchEntries(entries: BranchEntry[]): TodoItem[] {\n\treturn getLatestPhasesFromBranchEntries(entries).flatMap((phase) => phase.tasks.map(cloneTask));\n}\n"]}
1
+ {"version":3,"file":"todo-storage.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-storage.ts"],"names":[],"mappings":"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","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nimport type { SessionEntry } from \"../../../session-manager.ts\";\nimport {\n\tDEFAULT_INIT_PHASE,\n\tTODO_STATE_ENTRY_TYPE,\n\ttype TodoAsk,\n\ttype TodoItem,\n\ttype TodoPhase,\n\ttype TodoState,\n\ttype TodoStatus,\n} from \"./todo-types.ts\";\n\ntype BranchEntry = SessionEntry;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isTodoStatus(value: unknown): value is TodoStatus {\n\treturn value === \"pending\" || value === \"in_progress\" || value === \"completed\" || value === \"abandoned\";\n}\n\nfunction parseTodoStatus(value: unknown): TodoStatus | undefined {\n\tif (value === \"cancelled\") return \"abandoned\";\n\treturn isTodoStatus(value) ? value : undefined;\n}\n\nfunction parseTodoItem(value: unknown, options?: { lenient?: boolean }): TodoItem | undefined {\n\tif (!isRecord(value) || typeof value.content !== \"string\") return undefined;\n\tconst status = parseTodoStatus(value.status) ?? (options?.lenient ? \"pending\" : undefined);\n\treturn status ? { content: value.content, status } : undefined;\n}\n\nfunction parseTodoPhase(value: unknown): TodoPhase | undefined {\n\tif (!isRecord(value) || typeof value.name !== \"string\" || !Array.isArray(value.tasks)) return undefined;\n\tconst tasks: TodoItem[] = [];\n\tfor (const task of value.tasks) {\n\t\tconst parsed = parseTodoItem(task);\n\t\tif (!parsed) return undefined;\n\t\ttasks.push(parsed);\n\t}\n\treturn { name: value.name, tasks };\n}\n\nfunction parsePhases(value: unknown): TodoPhase[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst phases: TodoPhase[] = [];\n\tfor (const phase of value) {\n\t\tconst parsed = parseTodoPhase(phase);\n\t\tif (!parsed) return undefined;\n\t\tphases.push(parsed);\n\t}\n\treturn phases;\n}\n\nfunction parseLegacyTodos(value: unknown): TodoPhase[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst tasks: TodoItem[] = [];\n\tfor (const todo of value) {\n\t\t// Legacy todowrite persisted arbitrary status strings (e.g. \"blocked\").\n\t\t// Preserve those entries instead of dropping the whole list: unknown\n\t\t// statuses become \"pending\" so the task survives migration as open work.\n\t\tconst parsed = parseTodoItem(todo, { lenient: true });\n\t\tif (!parsed) return undefined;\n\t\ttasks.push(parsed);\n\t}\n\treturn [{ name: DEFAULT_INIT_PHASE, tasks }];\n}\n\nexport function isTodoAsk(value: unknown): value is TodoAsk {\n\treturn (\n\t\tisRecord(value) &&\n\t\ttypeof value.entryId === \"string\" &&\n\t\ttypeof value.text === \"string\" &&\n\t\ttypeof value.capturedAt === \"number\"\n\t);\n}\n\nfunction readTodoPayload(value: unknown): TodoState | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst phases =\n\t\tvalue.schema === \"v2\" || Array.isArray(value.phases)\n\t\t\t? parsePhases(value.phases)\n\t\t\t: Array.isArray(value.todos)\n\t\t\t\t? parseLegacyTodos(value.todos)\n\t\t\t\t: undefined;\n\tif (!phases) return undefined;\n\treturn { phases, ask: isTodoAsk(value.ask) ? { ...value.ask } : undefined };\n}\n\nexport function cloneTask(task: TodoItem): TodoItem {\n\treturn { content: task.content, status: task.status };\n}\n\nexport function clonePhases(phases: readonly TodoPhase[]): TodoPhase[] {\n\treturn phases.map((phase) => ({ name: phase.name, tasks: phase.tasks.map(cloneTask) }));\n}\n\nexport function isTodoItem(value: unknown): value is TodoItem {\n\t// Strict guard: only the canonical TodoStatus values are accepted. Legacy\n\t// statuses like \"cancelled\" are migrated to \"abandoned\" by the parse path\n\t// (parseTodoItem/readTodoPayload), not by this guard, so a narrowed value's\n\t// status is always a sound TodoStatus rather than the unchanged input.\n\tif (!isRecord(value) || typeof value.content !== \"string\") return false;\n\treturn isTodoStatus(value.status);\n}\n\nexport function isTodoItemArray(value: unknown): value is TodoItem[] {\n\treturn Array.isArray(value) && value.every(isTodoItem);\n}\n\nexport function isTodoPhase(value: unknown): value is TodoPhase {\n\tif (!isRecord(value) || typeof value.name !== \"string\" || !Array.isArray(value.tasks)) return false;\n\treturn value.tasks.every(isTodoItem);\n}\n\nexport function isTodoPhaseArray(value: unknown): value is TodoPhase[] {\n\treturn Array.isArray(value) && value.every(isTodoPhase);\n}\n\n/** Latest todo list and its captured ask on the branch; the ask travels with the entry that wrote the list. */\nexport function getLatestTodoStateFromBranchEntries(entries: readonly BranchEntry[]): TodoState {\n\tlet state: TodoState = { phases: [], ask: undefined };\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"custom\" && entry.customType === TODO_STATE_ENTRY_TYPE) {\n\t\t\tconst parsed = readTodoPayload(entry.data);\n\t\t\tif (parsed) state = { phases: clonePhases(parsed.phases), ask: parsed.ask };\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (entry.type !== \"message\" || !isRecord(entry.message)) continue;\n\t\tif (entry.message.role !== \"toolResult\") continue;\n\t\tif (entry.message.toolName !== \"todo\" && entry.message.toolName !== \"todowrite\") continue;\n\n\t\tconst parsed = readTodoPayload(entry.message.details);\n\t\tif (parsed) state = { phases: clonePhases(parsed.phases), ask: parsed.ask };\n\t}\n\n\treturn state;\n}\n\nexport function getLatestPhasesFromBranchEntries(entries: readonly BranchEntry[]): TodoPhase[] {\n\treturn getLatestTodoStateFromBranchEntries(entries).phases;\n}\n\n/** Compatibility reader for callers that still expect the old flat array. */\nexport function getLatestTodosFromBranchEntries(entries: BranchEntry[]): TodoItem[] {\n\treturn getLatestPhasesFromBranchEntries(entries).flatMap((phase) => phase.tasks.map(cloneTask));\n}\n"]}
@@ -12,18 +12,32 @@ export type TodoCompletionTransition = {
12
12
  phase: string;
13
13
  content: string;
14
14
  };
15
+ /** The user request a todo list serves, captured mechanically from the session branch. */
16
+ export type TodoAsk = {
17
+ entryId: string;
18
+ text: string;
19
+ capturedAt: number;
20
+ };
21
+ export type TodoState = {
22
+ phases: TodoPhase[];
23
+ ask: TodoAsk | undefined;
24
+ };
15
25
  export type TodoToolDetails = {
16
26
  op?: TodoOperation;
17
27
  phases: TodoPhase[];
18
28
  storage: "session" | "memory";
19
29
  corrections?: string[];
20
30
  completedTasks?: TodoCompletionTransition[];
31
+ ask?: TodoAsk;
21
32
  };
22
33
  export type TodoStateEntry = {
23
34
  schema: "v2";
24
35
  phases: TodoPhase[];
36
+ ask?: TodoAsk;
25
37
  };
26
38
  export declare const TODO_STATE_ENTRY_TYPE = "senpi.todo-state";
39
+ /** Hidden custom message the compaction bridge sends to rebuild a lost list (`compaction/todo-bridge.ts`). */
40
+ export declare const TODO_RESTORE_REQUEST_TYPE = "compaction.todo-restore-request";
27
41
  export declare const DEFAULT_INIT_PHASE = "Tasks";
28
42
  type TodoPhaseInput = {
29
43
  phase: string;
@@ -1 +1 @@
1
- {"version":3,"file":"todo-types.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-types.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;AAE/E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1F,MAAM,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C,KAAK,cAAc,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE,aAAa,CAAC;IAClB,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC"}
1
+ {"version":3,"file":"todo-types.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-types.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;AAE/E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1F,MAAM,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,0FAA0F;AAC1F,MAAM,MAAM,OAAO,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,8GAA8G;AAC9G,eAAO,MAAM,yBAAyB,oCAAoC,CAAC;AAC3E,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C,KAAK,cAAc,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE,aAAa,CAAC;IAClB,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC"}
@@ -3,5 +3,7 @@
3
3
  // Copyright (c) 2025-2026 Can Bölük
4
4
  // https://github.com/can1357/oh-my-pi
5
5
  export const TODO_STATE_ENTRY_TYPE = "senpi.todo-state";
6
+ /** Hidden custom message the compaction bridge sends to rebuild a lost list (`compaction/todo-bridge.ts`). */
7
+ export const TODO_RESTORE_REQUEST_TYPE = "compaction.todo-restore-request";
6
8
  export const DEFAULT_INIT_PHASE = "Tasks";
7
9
  //# sourceMappingURL=todo-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"todo-types.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-types.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,mCAAmC;AACnC,oCAAoC;AACpC,sCAAsC;AAkCtC,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACxD,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\" | \"abandoned\";\n\nexport type TodoOperation = \"init\" | \"start\" | \"done\" | \"rm\" | \"drop\" | \"append\" | \"view\";\n\nexport type TodoItem = {\n\tcontent: string;\n\tstatus: TodoStatus;\n};\n\nexport type TodoPhase = {\n\tname: string;\n\ttasks: TodoItem[];\n};\n\nexport type TodoCompletionTransition = {\n\tphase: string;\n\tcontent: string;\n};\n\nexport type TodoToolDetails = {\n\top?: TodoOperation;\n\tphases: TodoPhase[];\n\tstorage: \"session\" | \"memory\";\n\tcorrections?: string[];\n\tcompletedTasks?: TodoCompletionTransition[];\n};\n\nexport type TodoStateEntry = {\n\tschema: \"v2\";\n\tphases: TodoPhase[];\n};\n\nexport const TODO_STATE_ENTRY_TYPE = \"senpi.todo-state\";\nexport const DEFAULT_INIT_PHASE = \"Tasks\";\n\ntype TodoPhaseInput = {\n\tphase: string;\n\titems: string[];\n};\n\nexport type TodoOpEntry = {\n\top: TodoOperation;\n\tlist?: TodoPhaseInput[];\n\ttask?: string;\n\tphase?: string;\n\titems?: string[];\n};\n"]}
1
+ {"version":3,"file":"todo-types.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/todotools/todo-types.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,mCAAmC;AACnC,oCAAoC;AACpC,sCAAsC;AAgDtC,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACxD,8GAA8G;AAC9G,MAAM,CAAC,MAAM,yBAAyB,GAAG,iCAAiC,CAAC;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\" | \"abandoned\";\n\nexport type TodoOperation = \"init\" | \"start\" | \"done\" | \"rm\" | \"drop\" | \"append\" | \"view\";\n\nexport type TodoItem = {\n\tcontent: string;\n\tstatus: TodoStatus;\n};\n\nexport type TodoPhase = {\n\tname: string;\n\ttasks: TodoItem[];\n};\n\nexport type TodoCompletionTransition = {\n\tphase: string;\n\tcontent: string;\n};\n\n/** The user request a todo list serves, captured mechanically from the session branch. */\nexport type TodoAsk = {\n\tentryId: string;\n\ttext: string;\n\tcapturedAt: number;\n};\n\nexport type TodoState = {\n\tphases: TodoPhase[];\n\task: TodoAsk | undefined;\n};\n\nexport type TodoToolDetails = {\n\top?: TodoOperation;\n\tphases: TodoPhase[];\n\tstorage: \"session\" | \"memory\";\n\tcorrections?: string[];\n\tcompletedTasks?: TodoCompletionTransition[];\n\task?: TodoAsk;\n};\n\nexport type TodoStateEntry = {\n\tschema: \"v2\";\n\tphases: TodoPhase[];\n\task?: TodoAsk;\n};\n\nexport const TODO_STATE_ENTRY_TYPE = \"senpi.todo-state\";\n/** Hidden custom message the compaction bridge sends to rebuild a lost list (`compaction/todo-bridge.ts`). */\nexport const TODO_RESTORE_REQUEST_TYPE = \"compaction.todo-restore-request\";\nexport const DEFAULT_INIT_PHASE = \"Tasks\";\n\ntype TodoPhaseInput = {\n\tphase: string;\n\titems: string[];\n};\n\nexport type TodoOpEntry = {\n\top: TodoOperation;\n\tlist?: TodoPhaseInput[];\n\ttask?: string;\n\tphase?: string;\n\titems?: string[];\n};\n"]}
@@ -1,6 +1,6 @@
1
1
  import { Type } from "typebox";
2
2
  import type { ExtensionAPI, ExtensionContext } from "../../../types.ts";
3
- import { type TodoCompletionTransition, type TodoPhase } from "../state.ts";
3
+ import { type TodoAsk, type TodoCompletionTransition, type TodoPhase } from "../state.ts";
4
4
  export declare const TODO_PARAMS_SCHEMA: Type.TObject<{
5
5
  op: Type.TOptional<Type.TUnion<[Type.TLiteral<"init">, Type.TLiteral<"start">, Type.TLiteral<"done">, Type.TLiteral<"rm">, Type.TLiteral<"drop">, Type.TLiteral<"append">, Type.TLiteral<"view">]>>;
6
6
  list: Type.TOptional<Type.TArray<Type.TObject<{
@@ -14,6 +14,8 @@ export declare const TODO_PARAMS_SCHEMA: Type.TObject<{
14
14
  type TodoAccessors = {
15
15
  getCurrentPhases: () => TodoPhase[];
16
16
  setCurrentPhases: (phases: TodoPhase[]) => void;
17
+ getCurrentAsk: () => TodoAsk | undefined;
18
+ setCurrentAsk: (ask: TodoAsk | undefined) => void;
17
19
  syncWidget: (ctx: ExtensionContext, completedTasks?: readonly TodoCompletionTransition[]) => void;
18
20
  };
19
21
  export declare function phaseRomanNumeral(oneBasedIndex: number): string;
@@ -1 +1 @@
1
- {"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/todotools/tools/todo.ts"],"names":[],"mappings":"AAMA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAEX,YAAY,EACZ,gBAAgB,EAIhB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAUN,KAAK,wBAAwB,EAE7B,KAAK,SAAS,EAGd,MAAM,aAAa,CAAC;AAuBrB,eAAO,MAAM,kBAAkB;;;;;;;;;EAU7B,CAAC;AAIH,KAAK,aAAa,GAAG;IACpB,gBAAgB,EAAE,MAAM,SAAS,EAAE,CAAC;IACpC,gBAAgB,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;IAChD,UAAU,EAAE,CAAC,GAAG,EAAE,gBAAgB,EAAE,cAAc,CAAC,EAAE,SAAS,wBAAwB,EAAE,KAAK,IAAI,CAAC;CAClG,CAAC;AA4CF,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CA0B/D;AAyID,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,GAAG,IAAI,CA0EjF"}
1
+ {"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/todotools/tools/todo.ts"],"names":[],"mappings":"AAMA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAEX,YAAY,EACZ,gBAAgB,EAIhB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAaN,KAAK,OAAO,EACZ,KAAK,wBAAwB,EAE7B,KAAK,SAAS,EAGd,MAAM,aAAa,CAAC;AAuBrB,eAAO,MAAM,kBAAkB;;;;;;;;;EAU7B,CAAC;AAIH,KAAK,aAAa,GAAG;IACpB,gBAAgB,EAAE,MAAM,SAAS,EAAE,CAAC;IACpC,gBAAgB,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;IAChD,aAAa,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IACzC,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,UAAU,EAAE,CAAC,GAAG,EAAE,gBAAgB,EAAE,cAAc,CAAC,EAAE,SAAS,wBAAwB,EAAE,KAAK,IAAI,CAAC;CAClG,CAAC;AA4CF,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CA0B/D;AAyID,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,GAAG,IAAI,CA2FjF"}
@@ -7,7 +7,7 @@ import { Type } from "typebox";
7
7
  import { partialStrikethrough, strikeRevealCount } from "../../../../../modes/interactive/components/todo-strike.js";
8
8
  import { normalizeTodoParams } from "../normalize.js";
9
9
  import { TODO_TOOL_DESCRIPTION } from "../prompt.js";
10
- import { applyParams, clonePhases, findTaskByContent, formatSummary, getCompletionTransitions, getTodoMarker, nextActionableTask, sanitizeTodoText, TODO_STATE_ENTRY_TYPE, } from "../state.js";
10
+ import { applyParams, captureListAsk, clonePhases, findTaskByContent, formatHandoffCue, formatSummary, getCompletionTransitions, getTodoMarker, handoffMomentOf, nextActionableTask, sanitizeTodoText, TODO_STATE_ENTRY_TYPE, } from "../state.js";
11
11
  const TodoOperationSchema = Type.Union([
12
12
  Type.Literal("init"),
13
13
  Type.Literal("start"),
@@ -211,7 +211,7 @@ export function registerTodoTool(pi, accessors) {
211
211
  description: TODO_TOOL_DESCRIPTION,
212
212
  promptSnippet: "Track phased tasks with one op-based todo tool; reference tasks by their exact content.",
213
213
  promptGuidelines: [
214
- "Use one todo operation at a time; batch it with the real work rather than making a solo todo turn.",
214
+ "Use one todo operation at a time, batched with the real work; never end a turn with a todo call as its only tool call.",
215
215
  "Reference tasks and phases by their exact content/name; use view when the text is uncertain.",
216
216
  "Mark work done immediately and use drop for tasks that are no longer needed.",
217
217
  ],
@@ -219,10 +219,11 @@ export function registerTodoTool(pi, accessors) {
219
219
  executionMode: "sequential",
220
220
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
221
221
  const previousPhases = clonePhases(accessors.getCurrentPhases());
222
+ const previousAsk = accessors.getCurrentAsk();
222
223
  const normalized = normalizeTodoParams(params, previousPhases);
223
224
  if (normalized.error || !normalized.entry) {
224
225
  const error = normalized.error ?? 'Missing "op". Example: {"op":"init","list":[{"phase":"Setup","items":["..."]}]}';
225
- throw new Error(`${error}\n\n${formatSummary(previousPhases, [], true)}`);
226
+ throw new Error(`${error}\n\n${formatSummary(previousPhases, [], true, previousAsk)}`);
226
227
  }
227
228
  const entry = normalized.entry;
228
229
  const corrections = normalized.corrections;
@@ -231,15 +232,23 @@ export function registerTodoTool(pi, accessors) {
231
232
  const applied = readOnly
232
233
  ? { phases: previousPhases, errors }
233
234
  : applyParams(clonePhases(previousPhases), entry, corrections);
234
- if (applied.errors.length > 0)
235
- throw new Error(formatSummary(previousPhases, applied.errors, readOnly));
235
+ if (applied.errors.length > 0) {
236
+ throw new Error(formatSummary(previousPhases, applied.errors, readOnly, previousAsk));
237
+ }
236
238
  const completedTasks = readOnly ? [] : getCompletionTransitions(previousPhases, applied.phases);
239
+ // Only a list-creating call re-anchors the ask; every other op keeps it.
240
+ const createsList = entry.op === "init" || (entry.op === "append" && previousPhases.every((phase) => phase.tasks.length === 0));
241
+ const ask = createsList
242
+ ? (captureListAsk(ctx.sessionManager.getBranch(), Date.now()) ?? previousAsk)
243
+ : previousAsk;
237
244
  if (!readOnly) {
238
245
  pi.appendEntry(TODO_STATE_ENTRY_TYPE, {
239
246
  schema: "v2",
240
247
  phases: clonePhases(applied.phases),
248
+ ...(ask ? { ask } : {}),
241
249
  });
242
250
  accessors.setCurrentPhases(clonePhases(applied.phases));
251
+ accessors.setCurrentAsk(ask);
243
252
  accessors.syncWidget(ctx, completedTasks);
244
253
  }
245
254
  const details = {
@@ -247,11 +256,14 @@ export function registerTodoTool(pi, accessors) {
247
256
  phases: clonePhases(applied.phases),
248
257
  storage: ctx.sessionManager.getSessionFile() ? "session" : "memory",
249
258
  };
259
+ if (ask)
260
+ details.ask = ask;
250
261
  if (corrections.length > 0)
251
262
  details.corrections = corrections;
252
263
  if (completedTasks.length > 0)
253
264
  details.completedTasks = completedTasks;
254
- const summary = formatSummary(applied.phases, [], readOnly);
265
+ const cue = formatHandoffCue(readOnly ? undefined : handoffMomentOf(previousPhases, applied.phases, createsList));
266
+ const summary = `${formatSummary(applied.phases, [], readOnly, ask)}${cue}`;
255
267
  const text = corrections.length > 0 ? `${corrections.join("\n")}\n\n${summary}` : summary;
256
268
  return { content: [{ type: "text", text }], details };
257
269
  },
@@ -264,8 +276,11 @@ export function registerTodoTool(pi, accessors) {
264
276
  }
265
277
  const phases = result.details?.phases ?? [];
266
278
  const rendered = renderTodoPhases(phases, result.details?.completedTasks ?? [], options, context.args, result.details?.op, theme, context.spinnerFrame);
267
- const text = rendered || getTextContent(result) || "Todo list is empty.";
268
- return new Text(text, 0, 0);
279
+ if (!rendered)
280
+ return new Text(getTextContent(result) || "Todo list is empty.", 0, 0);
281
+ const ask = result.details?.ask;
282
+ // The in-progress row stays the bold Now line; a result without a captured ask renders as before.
283
+ return new Text(ask ? `${theme.fg("dim", `Ask: ${ask.text}`)}\n${rendered}` : rendered, 0, 0);
269
284
  },
270
285
  };
271
286
  pi.registerTool(tool);
@@ -1 +1 @@
1
- {"version":3,"file":"todo.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/todotools/tools/todo.ts"],"names":[],"mappings":"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","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { partialStrikethrough, strikeRevealCount } from \"../../../../../modes/interactive/components/todo-strike.ts\";\nimport type { Theme } from \"../../../../../modes/interactive/theme/theme.ts\";\nimport type {\n\tAgentToolResult,\n\tExtensionAPI,\n\tExtensionContext,\n\tToolDefinition,\n\tToolRenderContext,\n\tToolRenderResultOptions,\n} from \"../../../types.ts\";\nimport { normalizeTodoParams } from \"../normalize.ts\";\nimport { TODO_TOOL_DESCRIPTION } from \"../prompt.ts\";\nimport {\n\tapplyParams,\n\tclonePhases,\n\tfindTaskByContent,\n\tformatSummary,\n\tgetCompletionTransitions,\n\tgetTodoMarker,\n\tnextActionableTask,\n\tsanitizeTodoText,\n\tTODO_STATE_ENTRY_TYPE,\n\ttype TodoCompletionTransition,\n\ttype TodoOperation,\n\ttype TodoPhase,\n\ttype TodoStateEntry,\n\ttype TodoToolDetails,\n} from \"../state.ts\";\n\nconst TodoOperationSchema = Type.Union(\n\t[\n\t\tType.Literal(\"init\"),\n\t\tType.Literal(\"start\"),\n\t\tType.Literal(\"done\"),\n\t\tType.Literal(\"rm\"),\n\t\tType.Literal(\"drop\"),\n\t\tType.Literal(\"append\"),\n\t\tType.Literal(\"view\"),\n\t],\n\t{ description: \"Operation to perform. Required — always pass it explicitly.\" },\n);\n\nconst TodoPhaseInputSchema = Type.Object({\n\tphase: Type.String({ description: \"Phase name\" }),\n\titems: Type.Array(Type.String({ description: \"Task content\" }), {\n\t\tdescription: \"Tasks for this phase\",\n\t\tminItems: 1,\n\t}),\n});\n\nexport const TODO_PARAMS_SCHEMA = Type.Object({\n\top: Type.Optional(TodoOperationSchema),\n\tlist: Type.Optional(Type.Array(TodoPhaseInputSchema, { description: \"Phased task list for init\" })),\n\ttask: Type.Optional(Type.String({ description: \"Exact task text copied from the previous todo result\" })),\n\tphase: Type.Optional(Type.String({ description: \"Exact phase name copied from the previous todo result\" })),\n\t// Keep this unconstrained at the schema boundary. init and append return\n\t// operation-specific errors, while unrelated operations may ignore it.\n\titems: Type.Optional(\n\t\tType.Array(Type.String({ description: \"Task content\" }), { description: \"Task texts to append\" }),\n\t),\n});\n\ntype TodoParams = Static<typeof TODO_PARAMS_SCHEMA>;\n\ntype TodoAccessors = {\n\tgetCurrentPhases: () => TodoPhase[];\n\tsetCurrentPhases: (phases: TodoPhase[]) => void;\n\tsyncWidget: (ctx: ExtensionContext, completedTasks?: readonly TodoCompletionTransition[]) => void;\n};\n\nfunction countInitItems(params: TodoParams): { phases: number; tasks: number } {\n\tif (params.list) {\n\t\treturn {\n\t\t\tphases: params.list.length,\n\t\t\ttasks: params.list.reduce((total, phase) => total + phase.items.length, 0),\n\t\t};\n\t}\n\tif (params.items) return { phases: params.items.length > 0 ? 1 : 0, tasks: params.items.length };\n\treturn { phases: 0, tasks: 0 };\n}\n\nfunction countLabel(count: number, singular: string): string {\n\treturn `${count} ${singular}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction renderCallLabel(params: TodoParams): string {\n\tswitch (params.op) {\n\t\tcase \"init\": {\n\t\t\tconst counts = countInitItems(params);\n\t\t\treturn `todo init (${countLabel(counts.phases, \"phase\")}, ${countLabel(counts.tasks, \"task\")})`;\n\t\t}\n\t\tcase \"append\":\n\t\t\treturn `todo append: ${sanitizeTodoText(params.phase ?? \"\") || \"(missing phase)\"} (${countLabel(\n\t\t\t\tparams.items?.length ?? 0,\n\t\t\t\t\"item\",\n\t\t\t)})`;\n\t\tcase \"start\":\n\t\tcase \"done\":\n\t\tcase \"drop\":\n\t\t\treturn `todo ${params.op}: ${sanitizeTodoText(params.task ?? params.phase ?? \"\") || \"(missing target)\"}`;\n\t\tcase \"rm\":\n\t\t\treturn `todo rm: ${sanitizeTodoText(params.task ?? params.phase ?? \"all\") || \"all\"}`;\n\t\tcase \"view\":\n\t\t\treturn \"todo view\";\n\t\t// Normalization can rescue a call that omitted `op`; label it generically until\n\t\t// execute resolves the effective operation. Listing `undefined` explicitly (instead\n\t\t// of `default`) keeps this switch exhaustive, so a new TodoOperation fails typecheck.\n\t\tcase undefined:\n\t\t\treturn \"todo\";\n\t}\n}\n\nexport function phaseRomanNumeral(oneBasedIndex: number): string {\n\tif (oneBasedIndex <= 0) return \"\";\n\tconst pairs: ReadonlyArray<readonly [number, string]> = [\n\t\t[1000, \"M\"],\n\t\t[900, \"CM\"],\n\t\t[500, \"D\"],\n\t\t[400, \"CD\"],\n\t\t[100, \"C\"],\n\t\t[90, \"XC\"],\n\t\t[50, \"L\"],\n\t\t[40, \"XL\"],\n\t\t[10, \"X\"],\n\t\t[9, \"IX\"],\n\t\t[5, \"V\"],\n\t\t[4, \"IV\"],\n\t\t[1, \"I\"],\n\t];\n\tlet remaining = oneBasedIndex;\n\tlet output = \"\";\n\tfor (const [value, symbol] of pairs) {\n\t\twhile (remaining >= value) {\n\t\t\toutput += symbol;\n\t\t\tremaining -= value;\n\t\t}\n\t}\n\treturn output;\n}\n\nfunction formatPhaseHeader(name: string, index: number, theme: Theme): string {\n\treturn theme.fg(\"accent\", theme.bold(`${phaseRomanNumeral(index)}. ${sanitizeTodoText(name)}`));\n}\n\nfunction formatPhaseSummary(phase: TodoPhase, index: number, theme: Theme): string {\n\tconst closed = phase.tasks.filter((task) => task.status === \"completed\" || task.status === \"abandoned\").length;\n\treturn theme.fg(\n\t\t\"dim\",\n\t\t`${phaseRomanNumeral(index)}. ${sanitizeTodoText(phase.name)} — ${closed}/${phase.tasks.length} done`,\n\t);\n}\n\nfunction formatTaskLine(\n\ttask: TodoPhase[\"tasks\"][number],\n\ttheme: Theme,\n\tcompletionKeys: ReadonlySet<string>,\n\tframe: number | undefined,\n): string {\n\tconst content = sanitizeTodoText(task.content);\n\tconst line = `${getTodoMarker(task.status)} ${content}`;\n\tswitch (task.status) {\n\t\tcase \"completed\": {\n\t\t\tconst reveal = completionKeys.has(task.content) ? strikeRevealCount(line, frame) : undefined;\n\t\t\treturn reveal === undefined\n\t\t\t\t? theme.fg(\"dim\", theme.strikethrough(line))\n\t\t\t\t: theme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\tpartialStrikethrough(line, reveal, (text) => theme.strikethrough(text)),\n\t\t\t\t\t);\n\t\t}\n\t\tcase \"in_progress\":\n\t\t\treturn theme.fg(\"accent\", theme.bold(line));\n\t\tcase \"abandoned\":\n\t\t\treturn theme.fg(\"dim\", line);\n\t\tcase \"pending\":\n\t\t\treturn line;\n\t}\n}\n\nfunction computeTouchedPhases(\n\targs: TodoParams,\n\toperation: TodoOperation | undefined,\n\tphases: readonly TodoPhase[],\n\tcompletedTasks: readonly TodoCompletionTransition[],\n): Set<string> | null {\n\tconst touched = new Set<string>();\n\tconst activeTask = nextActionableTask(phases);\n\tif (activeTask) {\n\t\tconst activePhase = phases.find((phase) => phase.tasks.includes(activeTask));\n\t\tif (activePhase) touched.add(activePhase.name);\n\t}\n\tfor (const transition of completedTasks) touched.add(transition.phase);\n\t// Exhaustive over TodoOperation | undefined so adding an operation is a typecheck\n\t// failure here rather than a silent fall-through into target-scoped highlighting.\n\tswitch (operation) {\n\t\tcase \"init\":\n\t\t\tfor (const phase of phases) touched.add(phase.name);\n\t\t\tbreak;\n\t\tcase \"start\":\n\t\tcase \"done\":\n\t\tcase \"drop\":\n\t\tcase \"rm\":\n\t\tcase \"append\":\n\t\tcase \"view\":\n\t\tcase undefined: {\n\t\t\tif (args.phase) {\n\t\t\t\tconst phase = phases.find((candidate) => candidate.name === args.phase);\n\t\t\t\tif (phase) touched.add(phase.name);\n\t\t\t}\n\t\t\tif (args.task) {\n\t\t\t\tconst hit = findTaskByContent([...phases], args.task);\n\t\t\t\tif (hit) touched.add(hit.phase.name);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = operation;\n\t\t\treturn touched.size > 0 ? touched : null;\n\t\t}\n\t}\n\treturn touched.size > 0 ? touched : null;\n}\n\nconst EMPTY_SET: ReadonlySet<string> = new Set();\n\nfunction renderTodoPhases(\n\tphases: readonly TodoPhase[],\n\tcompletedTasks: readonly TodoCompletionTransition[],\n\toptions: ToolRenderResultOptions,\n\targs: TodoParams,\n\toperation: TodoOperation | undefined,\n\ttheme: Theme,\n\tframe: number | undefined,\n): string {\n\tconst visiblePhases = phases.filter((phase) => phase.tasks.length > 0);\n\tif (visiblePhases.length === 0) return \"\";\n\n\tconst touched =\n\t\toptions.expanded || visiblePhases.length === 1\n\t\t\t? null\n\t\t\t: computeTouchedPhases(args, operation, visiblePhases, completedTasks);\n\tconst completionKeysByPhase = new Map<string, Set<string>>();\n\tfor (const transition of completedTasks) {\n\t\tlet completionKeys = completionKeysByPhase.get(transition.phase);\n\t\tif (!completionKeys) {\n\t\t\tcompletionKeys = new Set();\n\t\t\tcompletionKeysByPhase.set(transition.phase, completionKeys);\n\t\t}\n\t\tcompletionKeys.add(transition.content);\n\t}\n\tconst lines: string[] = [];\n\tfor (let index = 0; index < visiblePhases.length; index += 1) {\n\t\tconst phase = visiblePhases[index];\n\t\tconst oneBasedIndex = index + 1;\n\t\tif (touched && !touched.has(phase.name)) {\n\t\t\tlines.push(formatPhaseSummary(phase, oneBasedIndex, theme));\n\t\t\tcontinue;\n\t\t}\n\t\tlines.push(formatPhaseHeader(phase.name, oneBasedIndex, theme));\n\t\tconst completionKeys = completionKeysByPhase.get(phase.name) ?? EMPTY_SET;\n\t\tfor (const task of phase.tasks) lines.push(` ${formatTaskLine(task, theme, completionKeys, frame)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction getTextContent(result: AgentToolResult<TodoToolDetails>): string {\n\treturn result.content\n\t\t.filter(\n\t\t\t(content): content is { type: \"text\"; text: string } =>\n\t\t\t\tcontent.type === \"text\" && typeof content.text === \"string\",\n\t\t)\n\t\t.map((content) => content.text)\n\t\t.join(\"\\n\");\n}\n\nexport function registerTodoTool(pi: ExtensionAPI, accessors: TodoAccessors): void {\n\tconst tool: ToolDefinition<typeof TODO_PARAMS_SCHEMA, TodoToolDetails, unknown> = {\n\t\tname: \"todo\",\n\t\tlabel: \"Todo\",\n\t\tdescription: TODO_TOOL_DESCRIPTION,\n\t\tpromptSnippet: \"Track phased tasks with one op-based todo tool; reference tasks by their exact content.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use one todo operation at a time; batch it with the real work rather than making a solo todo turn.\",\n\t\t\t\"Reference tasks and phases by their exact content/name; use view when the text is uncertain.\",\n\t\t\t\"Mark work done immediately and use drop for tasks that are no longer needed.\",\n\t\t],\n\t\tparameters: TODO_PARAMS_SCHEMA,\n\t\texecutionMode: \"sequential\",\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx): Promise<AgentToolResult<TodoToolDetails>> {\n\t\t\tconst previousPhases = clonePhases(accessors.getCurrentPhases());\n\t\t\tconst normalized = normalizeTodoParams(params as Record<string, unknown>, previousPhases);\n\t\t\tif (normalized.error || !normalized.entry) {\n\t\t\t\tconst error =\n\t\t\t\t\tnormalized.error ?? 'Missing \"op\". Example: {\"op\":\"init\",\"list\":[{\"phase\":\"Setup\",\"items\":[\"...\"]}]}';\n\t\t\t\tthrow new Error(`${error}\\n\\n${formatSummary(previousPhases, [], true)}`);\n\t\t\t}\n\t\t\tconst entry = normalized.entry;\n\t\t\tconst corrections = normalized.corrections;\n\t\t\tconst readOnly = entry.op === \"view\";\n\t\t\tconst errors: string[] = [];\n\t\t\tconst applied = readOnly\n\t\t\t\t? { phases: previousPhases, errors }\n\t\t\t\t: applyParams(clonePhases(previousPhases), entry, corrections);\n\t\t\tif (applied.errors.length > 0) throw new Error(formatSummary(previousPhases, applied.errors, readOnly));\n\t\t\tconst completedTasks = readOnly ? [] : getCompletionTransitions(previousPhases, applied.phases);\n\t\t\tif (!readOnly) {\n\t\t\t\tpi.appendEntry(TODO_STATE_ENTRY_TYPE, {\n\t\t\t\t\tschema: \"v2\",\n\t\t\t\t\tphases: clonePhases(applied.phases),\n\t\t\t\t} satisfies TodoStateEntry);\n\t\t\t\taccessors.setCurrentPhases(clonePhases(applied.phases));\n\t\t\t\taccessors.syncWidget(ctx, completedTasks);\n\t\t\t}\n\n\t\t\tconst details: TodoToolDetails = {\n\t\t\t\top: entry.op,\n\t\t\t\tphases: clonePhases(applied.phases),\n\t\t\t\tstorage: ctx.sessionManager.getSessionFile() ? \"session\" : \"memory\",\n\t\t\t};\n\t\t\tif (corrections.length > 0) details.corrections = corrections;\n\t\t\tif (completedTasks.length > 0) details.completedTasks = completedTasks;\n\t\t\tconst summary = formatSummary(applied.phases, [], readOnly);\n\t\t\tconst text = corrections.length > 0 ? `${corrections.join(\"\\n\")}\\n\\n${summary}` : summary;\n\n\t\t\treturn { content: [{ type: \"text\", text }], details };\n\t\t},\n\t\trenderCall(args, theme) {\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(renderCallLabel(args))), 0, 0);\n\t\t},\n\t\trenderResult(result, options, theme, context: ToolRenderContext<unknown, TodoParams>) {\n\t\t\tif (context.isError) {\n\t\t\t\treturn new Text(theme.fg(\"toolOutput\", getTextContent(result)), 0, 0);\n\t\t\t}\n\t\t\tconst phases = result.details?.phases ?? [];\n\t\t\tconst rendered = renderTodoPhases(\n\t\t\t\tphases,\n\t\t\t\tresult.details?.completedTasks ?? [],\n\t\t\t\toptions,\n\t\t\t\tcontext.args,\n\t\t\t\tresult.details?.op,\n\t\t\t\ttheme,\n\t\t\t\tcontext.spinnerFrame,\n\t\t\t);\n\t\t\tconst text = rendered || getTextContent(result) || \"Todo list is empty.\";\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t};\n\n\tpi.registerTool(tool);\n}\n"]}
1
+ {"version":3,"file":"todo.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/todotools/tools/todo.ts"],"names":[],"mappings":"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","sourcesContent":["// Ported and adapted from oh-my-pi's todo tool (MIT License).\n// Copyright (c) 2025 Mario Zechner\n// Copyright (c) 2025-2026 Can Bölük\n// https://github.com/can1357/oh-my-pi\n\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { partialStrikethrough, strikeRevealCount } from \"../../../../../modes/interactive/components/todo-strike.ts\";\nimport type { Theme } from \"../../../../../modes/interactive/theme/theme.ts\";\nimport type {\n\tAgentToolResult,\n\tExtensionAPI,\n\tExtensionContext,\n\tToolDefinition,\n\tToolRenderContext,\n\tToolRenderResultOptions,\n} from \"../../../types.ts\";\nimport { normalizeTodoParams } from \"../normalize.ts\";\nimport { TODO_TOOL_DESCRIPTION } from \"../prompt.ts\";\nimport {\n\tapplyParams,\n\tcaptureListAsk,\n\tclonePhases,\n\tfindTaskByContent,\n\tformatHandoffCue,\n\tformatSummary,\n\tgetCompletionTransitions,\n\tgetTodoMarker,\n\thandoffMomentOf,\n\tnextActionableTask,\n\tsanitizeTodoText,\n\tTODO_STATE_ENTRY_TYPE,\n\ttype TodoAsk,\n\ttype TodoCompletionTransition,\n\ttype TodoOperation,\n\ttype TodoPhase,\n\ttype TodoStateEntry,\n\ttype TodoToolDetails,\n} from \"../state.ts\";\n\nconst TodoOperationSchema = Type.Union(\n\t[\n\t\tType.Literal(\"init\"),\n\t\tType.Literal(\"start\"),\n\t\tType.Literal(\"done\"),\n\t\tType.Literal(\"rm\"),\n\t\tType.Literal(\"drop\"),\n\t\tType.Literal(\"append\"),\n\t\tType.Literal(\"view\"),\n\t],\n\t{ description: \"Operation to perform. Required — always pass it explicitly.\" },\n);\n\nconst TodoPhaseInputSchema = Type.Object({\n\tphase: Type.String({ description: \"Phase name\" }),\n\titems: Type.Array(Type.String({ description: \"Task content\" }), {\n\t\tdescription: \"Tasks for this phase\",\n\t\tminItems: 1,\n\t}),\n});\n\nexport const TODO_PARAMS_SCHEMA = Type.Object({\n\top: Type.Optional(TodoOperationSchema),\n\tlist: Type.Optional(Type.Array(TodoPhaseInputSchema, { description: \"Phased task list for init\" })),\n\ttask: Type.Optional(Type.String({ description: \"Exact task text copied from the previous todo result\" })),\n\tphase: Type.Optional(Type.String({ description: \"Exact phase name copied from the previous todo result\" })),\n\t// Keep this unconstrained at the schema boundary. init and append return\n\t// operation-specific errors, while unrelated operations may ignore it.\n\titems: Type.Optional(\n\t\tType.Array(Type.String({ description: \"Task content\" }), { description: \"Task texts to append\" }),\n\t),\n});\n\ntype TodoParams = Static<typeof TODO_PARAMS_SCHEMA>;\n\ntype TodoAccessors = {\n\tgetCurrentPhases: () => TodoPhase[];\n\tsetCurrentPhases: (phases: TodoPhase[]) => void;\n\tgetCurrentAsk: () => TodoAsk | undefined;\n\tsetCurrentAsk: (ask: TodoAsk | undefined) => void;\n\tsyncWidget: (ctx: ExtensionContext, completedTasks?: readonly TodoCompletionTransition[]) => void;\n};\n\nfunction countInitItems(params: TodoParams): { phases: number; tasks: number } {\n\tif (params.list) {\n\t\treturn {\n\t\t\tphases: params.list.length,\n\t\t\ttasks: params.list.reduce((total, phase) => total + phase.items.length, 0),\n\t\t};\n\t}\n\tif (params.items) return { phases: params.items.length > 0 ? 1 : 0, tasks: params.items.length };\n\treturn { phases: 0, tasks: 0 };\n}\n\nfunction countLabel(count: number, singular: string): string {\n\treturn `${count} ${singular}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction renderCallLabel(params: TodoParams): string {\n\tswitch (params.op) {\n\t\tcase \"init\": {\n\t\t\tconst counts = countInitItems(params);\n\t\t\treturn `todo init (${countLabel(counts.phases, \"phase\")}, ${countLabel(counts.tasks, \"task\")})`;\n\t\t}\n\t\tcase \"append\":\n\t\t\treturn `todo append: ${sanitizeTodoText(params.phase ?? \"\") || \"(missing phase)\"} (${countLabel(\n\t\t\t\tparams.items?.length ?? 0,\n\t\t\t\t\"item\",\n\t\t\t)})`;\n\t\tcase \"start\":\n\t\tcase \"done\":\n\t\tcase \"drop\":\n\t\t\treturn `todo ${params.op}: ${sanitizeTodoText(params.task ?? params.phase ?? \"\") || \"(missing target)\"}`;\n\t\tcase \"rm\":\n\t\t\treturn `todo rm: ${sanitizeTodoText(params.task ?? params.phase ?? \"all\") || \"all\"}`;\n\t\tcase \"view\":\n\t\t\treturn \"todo view\";\n\t\t// Normalization can rescue a call that omitted `op`; label it generically until\n\t\t// execute resolves the effective operation. Listing `undefined` explicitly (instead\n\t\t// of `default`) keeps this switch exhaustive, so a new TodoOperation fails typecheck.\n\t\tcase undefined:\n\t\t\treturn \"todo\";\n\t}\n}\n\nexport function phaseRomanNumeral(oneBasedIndex: number): string {\n\tif (oneBasedIndex <= 0) return \"\";\n\tconst pairs: ReadonlyArray<readonly [number, string]> = [\n\t\t[1000, \"M\"],\n\t\t[900, \"CM\"],\n\t\t[500, \"D\"],\n\t\t[400, \"CD\"],\n\t\t[100, \"C\"],\n\t\t[90, \"XC\"],\n\t\t[50, \"L\"],\n\t\t[40, \"XL\"],\n\t\t[10, \"X\"],\n\t\t[9, \"IX\"],\n\t\t[5, \"V\"],\n\t\t[4, \"IV\"],\n\t\t[1, \"I\"],\n\t];\n\tlet remaining = oneBasedIndex;\n\tlet output = \"\";\n\tfor (const [value, symbol] of pairs) {\n\t\twhile (remaining >= value) {\n\t\t\toutput += symbol;\n\t\t\tremaining -= value;\n\t\t}\n\t}\n\treturn output;\n}\n\nfunction formatPhaseHeader(name: string, index: number, theme: Theme): string {\n\treturn theme.fg(\"accent\", theme.bold(`${phaseRomanNumeral(index)}. ${sanitizeTodoText(name)}`));\n}\n\nfunction formatPhaseSummary(phase: TodoPhase, index: number, theme: Theme): string {\n\tconst closed = phase.tasks.filter((task) => task.status === \"completed\" || task.status === \"abandoned\").length;\n\treturn theme.fg(\n\t\t\"dim\",\n\t\t`${phaseRomanNumeral(index)}. ${sanitizeTodoText(phase.name)} — ${closed}/${phase.tasks.length} done`,\n\t);\n}\n\nfunction formatTaskLine(\n\ttask: TodoPhase[\"tasks\"][number],\n\ttheme: Theme,\n\tcompletionKeys: ReadonlySet<string>,\n\tframe: number | undefined,\n): string {\n\tconst content = sanitizeTodoText(task.content);\n\tconst line = `${getTodoMarker(task.status)} ${content}`;\n\tswitch (task.status) {\n\t\tcase \"completed\": {\n\t\t\tconst reveal = completionKeys.has(task.content) ? strikeRevealCount(line, frame) : undefined;\n\t\t\treturn reveal === undefined\n\t\t\t\t? theme.fg(\"dim\", theme.strikethrough(line))\n\t\t\t\t: theme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\tpartialStrikethrough(line, reveal, (text) => theme.strikethrough(text)),\n\t\t\t\t\t);\n\t\t}\n\t\tcase \"in_progress\":\n\t\t\treturn theme.fg(\"accent\", theme.bold(line));\n\t\tcase \"abandoned\":\n\t\t\treturn theme.fg(\"dim\", line);\n\t\tcase \"pending\":\n\t\t\treturn line;\n\t}\n}\n\nfunction computeTouchedPhases(\n\targs: TodoParams,\n\toperation: TodoOperation | undefined,\n\tphases: readonly TodoPhase[],\n\tcompletedTasks: readonly TodoCompletionTransition[],\n): Set<string> | null {\n\tconst touched = new Set<string>();\n\tconst activeTask = nextActionableTask(phases);\n\tif (activeTask) {\n\t\tconst activePhase = phases.find((phase) => phase.tasks.includes(activeTask));\n\t\tif (activePhase) touched.add(activePhase.name);\n\t}\n\tfor (const transition of completedTasks) touched.add(transition.phase);\n\t// Exhaustive over TodoOperation | undefined so adding an operation is a typecheck\n\t// failure here rather than a silent fall-through into target-scoped highlighting.\n\tswitch (operation) {\n\t\tcase \"init\":\n\t\t\tfor (const phase of phases) touched.add(phase.name);\n\t\t\tbreak;\n\t\tcase \"start\":\n\t\tcase \"done\":\n\t\tcase \"drop\":\n\t\tcase \"rm\":\n\t\tcase \"append\":\n\t\tcase \"view\":\n\t\tcase undefined: {\n\t\t\tif (args.phase) {\n\t\t\t\tconst phase = phases.find((candidate) => candidate.name === args.phase);\n\t\t\t\tif (phase) touched.add(phase.name);\n\t\t\t}\n\t\t\tif (args.task) {\n\t\t\t\tconst hit = findTaskByContent([...phases], args.task);\n\t\t\t\tif (hit) touched.add(hit.phase.name);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = operation;\n\t\t\treturn touched.size > 0 ? touched : null;\n\t\t}\n\t}\n\treturn touched.size > 0 ? touched : null;\n}\n\nconst EMPTY_SET: ReadonlySet<string> = new Set();\n\nfunction renderTodoPhases(\n\tphases: readonly TodoPhase[],\n\tcompletedTasks: readonly TodoCompletionTransition[],\n\toptions: ToolRenderResultOptions,\n\targs: TodoParams,\n\toperation: TodoOperation | undefined,\n\ttheme: Theme,\n\tframe: number | undefined,\n): string {\n\tconst visiblePhases = phases.filter((phase) => phase.tasks.length > 0);\n\tif (visiblePhases.length === 0) return \"\";\n\n\tconst touched =\n\t\toptions.expanded || visiblePhases.length === 1\n\t\t\t? null\n\t\t\t: computeTouchedPhases(args, operation, visiblePhases, completedTasks);\n\tconst completionKeysByPhase = new Map<string, Set<string>>();\n\tfor (const transition of completedTasks) {\n\t\tlet completionKeys = completionKeysByPhase.get(transition.phase);\n\t\tif (!completionKeys) {\n\t\t\tcompletionKeys = new Set();\n\t\t\tcompletionKeysByPhase.set(transition.phase, completionKeys);\n\t\t}\n\t\tcompletionKeys.add(transition.content);\n\t}\n\tconst lines: string[] = [];\n\tfor (let index = 0; index < visiblePhases.length; index += 1) {\n\t\tconst phase = visiblePhases[index];\n\t\tconst oneBasedIndex = index + 1;\n\t\tif (touched && !touched.has(phase.name)) {\n\t\t\tlines.push(formatPhaseSummary(phase, oneBasedIndex, theme));\n\t\t\tcontinue;\n\t\t}\n\t\tlines.push(formatPhaseHeader(phase.name, oneBasedIndex, theme));\n\t\tconst completionKeys = completionKeysByPhase.get(phase.name) ?? EMPTY_SET;\n\t\tfor (const task of phase.tasks) lines.push(` ${formatTaskLine(task, theme, completionKeys, frame)}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction getTextContent(result: AgentToolResult<TodoToolDetails>): string {\n\treturn result.content\n\t\t.filter(\n\t\t\t(content): content is { type: \"text\"; text: string } =>\n\t\t\t\tcontent.type === \"text\" && typeof content.text === \"string\",\n\t\t)\n\t\t.map((content) => content.text)\n\t\t.join(\"\\n\");\n}\n\nexport function registerTodoTool(pi: ExtensionAPI, accessors: TodoAccessors): void {\n\tconst tool: ToolDefinition<typeof TODO_PARAMS_SCHEMA, TodoToolDetails, unknown> = {\n\t\tname: \"todo\",\n\t\tlabel: \"Todo\",\n\t\tdescription: TODO_TOOL_DESCRIPTION,\n\t\tpromptSnippet: \"Track phased tasks with one op-based todo tool; reference tasks by their exact content.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use one todo operation at a time, batched with the real work; never end a turn with a todo call as its only tool call.\",\n\t\t\t\"Reference tasks and phases by their exact content/name; use view when the text is uncertain.\",\n\t\t\t\"Mark work done immediately and use drop for tasks that are no longer needed.\",\n\t\t],\n\t\tparameters: TODO_PARAMS_SCHEMA,\n\t\texecutionMode: \"sequential\",\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx): Promise<AgentToolResult<TodoToolDetails>> {\n\t\t\tconst previousPhases = clonePhases(accessors.getCurrentPhases());\n\t\t\tconst previousAsk = accessors.getCurrentAsk();\n\t\t\tconst normalized = normalizeTodoParams(params as Record<string, unknown>, previousPhases);\n\t\t\tif (normalized.error || !normalized.entry) {\n\t\t\t\tconst error =\n\t\t\t\t\tnormalized.error ?? 'Missing \"op\". Example: {\"op\":\"init\",\"list\":[{\"phase\":\"Setup\",\"items\":[\"...\"]}]}';\n\t\t\t\tthrow new Error(`${error}\\n\\n${formatSummary(previousPhases, [], true, previousAsk)}`);\n\t\t\t}\n\t\t\tconst entry = normalized.entry;\n\t\t\tconst corrections = normalized.corrections;\n\t\t\tconst readOnly = entry.op === \"view\";\n\t\t\tconst errors: string[] = [];\n\t\t\tconst applied = readOnly\n\t\t\t\t? { phases: previousPhases, errors }\n\t\t\t\t: applyParams(clonePhases(previousPhases), entry, corrections);\n\t\t\tif (applied.errors.length > 0) {\n\t\t\t\tthrow new Error(formatSummary(previousPhases, applied.errors, readOnly, previousAsk));\n\t\t\t}\n\t\t\tconst completedTasks = readOnly ? [] : getCompletionTransitions(previousPhases, applied.phases);\n\t\t\t// Only a list-creating call re-anchors the ask; every other op keeps it.\n\t\t\tconst createsList =\n\t\t\t\tentry.op === \"init\" || (entry.op === \"append\" && previousPhases.every((phase) => phase.tasks.length === 0));\n\t\t\tconst ask = createsList\n\t\t\t\t? (captureListAsk(ctx.sessionManager.getBranch(), Date.now()) ?? previousAsk)\n\t\t\t\t: previousAsk;\n\t\t\tif (!readOnly) {\n\t\t\t\tpi.appendEntry(TODO_STATE_ENTRY_TYPE, {\n\t\t\t\t\tschema: \"v2\",\n\t\t\t\t\tphases: clonePhases(applied.phases),\n\t\t\t\t\t...(ask ? { ask } : {}),\n\t\t\t\t} satisfies TodoStateEntry);\n\t\t\t\taccessors.setCurrentPhases(clonePhases(applied.phases));\n\t\t\t\taccessors.setCurrentAsk(ask);\n\t\t\t\taccessors.syncWidget(ctx, completedTasks);\n\t\t\t}\n\n\t\t\tconst details: TodoToolDetails = {\n\t\t\t\top: entry.op,\n\t\t\t\tphases: clonePhases(applied.phases),\n\t\t\t\tstorage: ctx.sessionManager.getSessionFile() ? \"session\" : \"memory\",\n\t\t\t};\n\t\t\tif (ask) details.ask = ask;\n\t\t\tif (corrections.length > 0) details.corrections = corrections;\n\t\t\tif (completedTasks.length > 0) details.completedTasks = completedTasks;\n\t\t\tconst cue = formatHandoffCue(\n\t\t\t\treadOnly ? undefined : handoffMomentOf(previousPhases, applied.phases, createsList),\n\t\t\t);\n\t\t\tconst summary = `${formatSummary(applied.phases, [], readOnly, ask)}${cue}`;\n\t\t\tconst text = corrections.length > 0 ? `${corrections.join(\"\\n\")}\\n\\n${summary}` : summary;\n\n\t\t\treturn { content: [{ type: \"text\", text }], details };\n\t\t},\n\t\trenderCall(args, theme) {\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(renderCallLabel(args))), 0, 0);\n\t\t},\n\t\trenderResult(result, options, theme, context: ToolRenderContext<unknown, TodoParams>) {\n\t\t\tif (context.isError) {\n\t\t\t\treturn new Text(theme.fg(\"toolOutput\", getTextContent(result)), 0, 0);\n\t\t\t}\n\t\t\tconst phases = result.details?.phases ?? [];\n\t\t\tconst rendered = renderTodoPhases(\n\t\t\t\tphases,\n\t\t\t\tresult.details?.completedTasks ?? [],\n\t\t\t\toptions,\n\t\t\t\tcontext.args,\n\t\t\t\tresult.details?.op,\n\t\t\t\ttheme,\n\t\t\t\tcontext.spinnerFrame,\n\t\t\t);\n\t\t\tif (!rendered) return new Text(getTextContent(result) || \"Todo list is empty.\", 0, 0);\n\t\t\tconst ask = result.details?.ask;\n\t\t\t// The in-progress row stays the bold Now line; a result without a captured ask renders as before.\n\t\t\treturn new Text(ask ? `${theme.fg(\"dim\", `Ask: ${ask.text}`)}\\n${rendered}` : rendered, 0, 0);\n\t\t},\n\t};\n\n\tpi.registerTool(tool);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AACA;;;GAGG;AAwBH,OAAO,EAAkB,KAAK,QAAQ,EAAuD,MAAM,iBAAiB,CAAC;AAcrH,OAAO,KAAK,EAGX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EAGvB,oBAAoB,EAGpB,2BAA2B,EAI3B,cAAc,EACd,WAAW,EAEX,MAAM,YAAY,CAAC;AAGpB,kGAAkG;AAClG,MAAM,WAAW,uBAAuB;IACvC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AA4JD,MAAM,MAAM,wBAAwB,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;AAMrH,OAAO,EAAE,mBAAmB,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAElG;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAuFzD;AAED;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,gBAAgB,GAAG,2BAA2B,EAAE,CAS1G;AA+dD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,EAC1B,OAAO,GAAE,uBAA2D,GAClE,OAAO,CAAC,SAAS,CAAC,CAGpB;AAiDD,wBAAsB,cAAc,CACnC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,uBAAuB,GAAG;IAAE,eAAe,CAAC,EAAE,wBAAwB,CAAA;CAAE,GAChF,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,oBAAoB,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AA2FD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA2C/B"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AACA;;;GAGG;AAwBH,OAAO,EAAkB,KAAK,QAAQ,EAAuD,MAAM,iBAAiB,CAAC;AAcrH,OAAO,KAAK,EAIX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EAGvB,oBAAoB,EAGpB,2BAA2B,EAI3B,cAAc,EACd,WAAW,EAEX,MAAM,YAAY,CAAC;AAGpB,kGAAkG;AAClG,MAAM,WAAW,uBAAuB;IACvC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AA4JD,MAAM,MAAM,wBAAwB,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;AAMrH,OAAO,EAAE,mBAAmB,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAElG;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAuFzD;AAED;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,gBAAgB,GAAG,2BAA2B,EAAE,CAS1G;AAmeD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,EAC1B,OAAO,GAAE,uBAA2D,GAClE,OAAO,CAAC,SAAS,CAAC,CAGpB;AAiDD,wBAAsB,cAAc,CACnC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,uBAAuB,GAAG;IAAE,eAAe,CAAC,EAAE,wBAAwB,CAAA;CAAE,GAChF,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,oBAAoB,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AA2FD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA2C/B"}