@code-yeongyu/senpi 2026.8.9 → 2026.8.11-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/brand-dir-migration.d.ts +28 -0
  3. package/dist/brand-dir-migration.d.ts.map +1 -0
  4. package/dist/brand-dir-migration.js +77 -0
  5. package/dist/brand-dir-migration.js.map +1 -0
  6. package/dist/cli/grok-neo-gate.d.ts +0 -8
  7. package/dist/cli/grok-neo-gate.d.ts.map +1 -1
  8. package/dist/cli/grok-neo-gate.js +4 -2
  9. package/dist/cli/grok-neo-gate.js.map +1 -1
  10. package/dist/cli-main.js +3 -0
  11. package/dist/cli-main.js.map +1 -1
  12. package/dist/cli.js +2 -2
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config.d.ts +27 -1
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js +41 -9
  17. package/dist/config.js.map +1 -1
  18. package/dist/core/agent-session.d.ts +4 -0
  19. package/dist/core/agent-session.d.ts.map +1 -1
  20. package/dist/core/agent-session.js +21 -3
  21. package/dist/core/agent-session.js.map +1 -1
  22. package/dist/core/brand.d.ts +79 -0
  23. package/dist/core/brand.d.ts.map +1 -0
  24. package/dist/core/brand.js +141 -0
  25. package/dist/core/brand.js.map +1 -0
  26. package/dist/core/dynamic-prompt/identity.d.ts.map +1 -1
  27. package/dist/core/dynamic-prompt/identity.js +2 -1
  28. package/dist/core/dynamic-prompt/identity.js.map +1 -1
  29. package/dist/core/experimental.d.ts.map +1 -1
  30. package/dist/core/experimental.js +2 -1
  31. package/dist/core/experimental.js.map +1 -1
  32. package/dist/core/extensions/builtin/cache-keepalive/index.d.ts +30 -0
  33. package/dist/core/extensions/builtin/cache-keepalive/index.d.ts.map +1 -0
  34. package/dist/core/extensions/builtin/cache-keepalive/index.js +281 -0
  35. package/dist/core/extensions/builtin/cache-keepalive/index.js.map +1 -0
  36. package/dist/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.js +10 -1
  38. package/dist/core/extensions/builtin/claude-sdk-oauth/session-commit-boundary.js.map +1 -1
  39. package/dist/core/extensions/builtin/compaction/index.js +9 -9
  40. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  41. package/dist/core/extensions/builtin/compaction/log.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/compaction/log.js +2 -1
  43. package/dist/core/extensions/builtin/compaction/log.js.map +1 -1
  44. package/dist/core/extensions/builtin/config-reload/generated-shim-filter.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/config-reload/generated-shim-filter.js +4 -4
  46. package/dist/core/extensions/builtin/config-reload/generated-shim-filter.js.map +1 -1
  47. package/dist/core/extensions/builtin/goal/cache-warm-renderer.d.ts.map +1 -1
  48. package/dist/core/extensions/builtin/goal/cache-warm-renderer.js +21 -8
  49. package/dist/core/extensions/builtin/goal/cache-warm-renderer.js.map +1 -1
  50. package/dist/core/extensions/builtin/goal/cache-warm.d.ts +11 -2
  51. package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
  52. package/dist/core/extensions/builtin/goal/cache-warm.js +16 -0
  53. package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
  54. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/goal/index.js +36 -1
  56. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  57. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts +2 -2
  58. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts.map +1 -1
  59. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js +3 -3
  60. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js.map +1 -1
  61. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts +2 -1
  62. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  63. package/dist/core/extensions/builtin/goal/monitor-continuation.js +121 -54
  64. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  65. package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
  66. package/dist/core/extensions/builtin/goal/prompt.js +4 -4
  67. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  68. package/dist/core/extensions/builtin/goal/store-changed-event.d.ts +8 -0
  69. package/dist/core/extensions/builtin/goal/store-changed-event.d.ts.map +1 -0
  70. package/dist/core/extensions/builtin/goal/store-changed-event.js +9 -0
  71. package/dist/core/extensions/builtin/goal/store-changed-event.js.map +1 -0
  72. package/dist/core/extensions/builtin/goal/store.d.ts +3 -2
  73. package/dist/core/extensions/builtin/goal/store.d.ts.map +1 -1
  74. package/dist/core/extensions/builtin/goal/store.js +128 -101
  75. package/dist/core/extensions/builtin/goal/store.js.map +1 -1
  76. package/dist/core/extensions/builtin/goal/wait-progress.js +5 -5
  77. package/dist/core/extensions/builtin/goal/wait-progress.js.map +1 -1
  78. package/dist/core/extensions/builtin/help/index.d.ts.map +1 -1
  79. package/dist/core/extensions/builtin/help/index.js +3 -2
  80. package/dist/core/extensions/builtin/help/index.js.map +1 -1
  81. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  82. package/dist/core/extensions/builtin/index.js +2 -0
  83. package/dist/core/extensions/builtin/index.js.map +1 -1
  84. package/dist/core/extensions/builtin/monitor-state-event.d.ts +16 -0
  85. package/dist/core/extensions/builtin/monitor-state-event.d.ts.map +1 -1
  86. package/dist/core/extensions/builtin/monitor-state-event.js +15 -0
  87. package/dist/core/extensions/builtin/monitor-state-event.js.map +1 -1
  88. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -1
  89. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +2 -1
  90. package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -1
  91. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js +2 -1
  93. package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js.map +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.d.ts.map +1 -1
  95. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +2 -1
  96. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
  97. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
  98. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +2 -1
  99. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  100. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.d.ts.map +1 -1
  101. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +6 -5
  102. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js.map +1 -1
  103. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts.map +1 -1
  104. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +2 -1
  105. package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js.map +1 -1
  106. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  107. package/dist/core/extensions/builtin/terminal/extension.js +7 -8
  108. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  109. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +3 -3
  110. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
  111. package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
  112. package/dist/core/extensions/index.d.ts +1 -1
  113. package/dist/core/extensions/index.d.ts.map +1 -1
  114. package/dist/core/extensions/index.js.map +1 -1
  115. package/dist/core/extensions/loader.d.ts.map +1 -1
  116. package/dist/core/extensions/loader.js +7 -0
  117. package/dist/core/extensions/loader.js.map +1 -1
  118. package/dist/core/extensions/runner.d.ts +4 -0
  119. package/dist/core/extensions/runner.d.ts.map +1 -1
  120. package/dist/core/extensions/runner.js +19 -2
  121. package/dist/core/extensions/runner.js.map +1 -1
  122. package/dist/core/extensions/types.d.ts +50 -0
  123. package/dist/core/extensions/types.d.ts.map +1 -1
  124. package/dist/core/extensions/types.js.map +1 -1
  125. package/dist/core/footer-data-provider.d.ts +1 -4
  126. package/dist/core/footer-data-provider.d.ts.map +1 -1
  127. package/dist/core/footer-data-provider.js +0 -7
  128. package/dist/core/footer-data-provider.js.map +1 -1
  129. package/dist/core/generated-shim-banner.d.ts +15 -0
  130. package/dist/core/generated-shim-banner.d.ts.map +1 -0
  131. package/dist/core/generated-shim-banner.js +26 -0
  132. package/dist/core/generated-shim-banner.js.map +1 -0
  133. package/dist/core/model-runtime.d.ts.map +1 -1
  134. package/dist/core/model-runtime.js +7 -3
  135. package/dist/core/model-runtime.js.map +1 -1
  136. package/dist/core/package-manager.d.ts.map +1 -1
  137. package/dist/core/package-manager.js +2 -1
  138. package/dist/core/package-manager.js.map +1 -1
  139. package/dist/core/resource-loader.d.ts +4 -0
  140. package/dist/core/resource-loader.d.ts.map +1 -1
  141. package/dist/core/resource-loader.js +9 -5
  142. package/dist/core/resource-loader.js.map +1 -1
  143. package/dist/core/session-log.d.ts.map +1 -1
  144. package/dist/core/session-log.js +4 -2
  145. package/dist/core/session-log.js.map +1 -1
  146. package/dist/core/session-manager.d.ts +1 -1
  147. package/dist/core/session-manager.d.ts.map +1 -1
  148. package/dist/core/session-manager.js.map +1 -1
  149. package/dist/core/settings-manager.d.ts +10 -0
  150. package/dist/core/settings-manager.d.ts.map +1 -1
  151. package/dist/core/settings-manager.js +17 -2
  152. package/dist/core/settings-manager.js.map +1 -1
  153. package/dist/core/telemetry.d.ts.map +1 -1
  154. package/dist/core/telemetry.js +2 -1
  155. package/dist/core/telemetry.js.map +1 -1
  156. package/dist/core/timings.d.ts +0 -4
  157. package/dist/core/timings.d.ts.map +1 -1
  158. package/dist/core/timings.js +2 -1
  159. package/dist/core/timings.js.map +1 -1
  160. package/dist/core/tools/edit.d.ts +3 -1
  161. package/dist/core/tools/edit.d.ts.map +1 -1
  162. package/dist/core/tools/edit.js +12 -0
  163. package/dist/core/tools/edit.js.map +1 -1
  164. package/dist/core/tools/filesystem-policy.d.ts +10 -0
  165. package/dist/core/tools/filesystem-policy.d.ts.map +1 -0
  166. package/dist/core/tools/filesystem-policy.js +59 -0
  167. package/dist/core/tools/filesystem-policy.js.map +1 -0
  168. package/dist/core/tools/find.d.ts +3 -1
  169. package/dist/core/tools/find.d.ts.map +1 -1
  170. package/dist/core/tools/find.js +15 -0
  171. package/dist/core/tools/find.js.map +1 -1
  172. package/dist/core/tools/grep.d.ts +3 -1
  173. package/dist/core/tools/grep.d.ts.map +1 -1
  174. package/dist/core/tools/grep.js +16 -1
  175. package/dist/core/tools/grep.js.map +1 -1
  176. package/dist/core/tools/ls.d.ts +3 -1
  177. package/dist/core/tools/ls.d.ts.map +1 -1
  178. package/dist/core/tools/ls.js +11 -0
  179. package/dist/core/tools/ls.js.map +1 -1
  180. package/dist/core/tools/read.d.ts +3 -1
  181. package/dist/core/tools/read.d.ts.map +1 -1
  182. package/dist/core/tools/read.js +13 -0
  183. package/dist/core/tools/read.js.map +1 -1
  184. package/dist/core/tools/write.d.ts +3 -1
  185. package/dist/core/tools/write.d.ts.map +1 -1
  186. package/dist/core/tools/write.js +12 -0
  187. package/dist/core/tools/write.js.map +1 -1
  188. package/dist/index.d.ts +1 -1
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js.map +1 -1
  191. package/dist/inspector-policy.d.ts.map +1 -1
  192. package/dist/inspector-policy.js +2 -1
  193. package/dist/inspector-policy.js.map +1 -1
  194. package/dist/main.d.ts.map +1 -1
  195. package/dist/main.js +5 -4
  196. package/dist/main.js.map +1 -1
  197. package/dist/migrations.d.ts.map +1 -1
  198. package/dist/migrations.js +4 -0
  199. package/dist/migrations.js.map +1 -1
  200. package/dist/modes/app-server/threads/goal-handlers.d.ts.map +1 -1
  201. package/dist/modes/app-server/threads/goal-handlers.js +7 -0
  202. package/dist/modes/app-server/threads/goal-handlers.js.map +1 -1
  203. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/footer.js +1 -6
  205. package/dist/modes/interactive/components/footer.js.map +1 -1
  206. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  207. package/dist/modes/interactive/interactive-mode.js +7 -7
  208. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  209. package/dist/modes/interactive/tips/catalog/cli-tips.d.ts.map +1 -1
  210. package/dist/modes/interactive/tips/catalog/cli-tips.js +2 -1
  211. package/dist/modes/interactive/tips/catalog/cli-tips.js.map +1 -1
  212. package/dist/modes/interactive/tips/catalog/ethos-tips.d.ts.map +1 -1
  213. package/dist/modes/interactive/tips/catalog/ethos-tips.js +4 -3
  214. package/dist/modes/interactive/tips/catalog/ethos-tips.js.map +1 -1
  215. package/dist/modes/interactive/tips/catalog/model-tips.d.ts.map +1 -1
  216. package/dist/modes/interactive/tips/catalog/model-tips.js +2 -1
  217. package/dist/modes/interactive/tips/catalog/model-tips.js.map +1 -1
  218. package/dist/modes/interactive/tips/catalog/session-tips.d.ts.map +1 -1
  219. package/dist/modes/interactive/tips/catalog/session-tips.js +2 -1
  220. package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
  221. package/dist/modes/interactive/tips/catalog/settings-tips.d.ts.map +1 -1
  222. package/dist/modes/interactive/tips/catalog/settings-tips.js +3 -2
  223. package/dist/modes/interactive/tips/catalog/settings-tips.js.map +1 -1
  224. package/dist/modes/interactive/tips/catalog/workspace-tips.d.ts.map +1 -1
  225. package/dist/modes/interactive/tips/catalog/workspace-tips.js +4 -3
  226. package/dist/modes/interactive/tips/catalog/workspace-tips.js.map +1 -1
  227. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  228. package/dist/modes/rpc/rpc-mode.js +2 -1
  229. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  230. package/dist/nearest-parent-config.d.ts +6 -1
  231. package/dist/nearest-parent-config.d.ts.map +1 -1
  232. package/dist/nearest-parent-config.js +18 -2
  233. package/dist/nearest-parent-config.js.map +1 -1
  234. package/dist/package-manager-cli.d.ts.map +1 -1
  235. package/dist/package-manager-cli.js +13 -1
  236. package/dist/package-manager-cli.js.map +1 -1
  237. package/dist/rpc-entry.js +2 -0
  238. package/dist/rpc-entry.js.map +1 -1
  239. package/dist/self-update-bootstrap.d.ts.map +1 -1
  240. package/dist/self-update-bootstrap.js +6 -0
  241. package/dist/self-update-bootstrap.js.map +1 -1
  242. package/dist/senpi +2 -2
  243. package/dist/utils/pi-user-agent.d.ts +1 -1
  244. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  245. package/dist/utils/pi-user-agent.js +4 -3
  246. package/dist/utils/pi-user-agent.js.map +1 -1
  247. package/dist/utils/tools-manager.d.ts.map +1 -1
  248. package/dist/utils/tools-manager.js +2 -1
  249. package/dist/utils/tools-manager.js.map +1 -1
  250. package/dist/utils/version-check.d.ts +3 -0
  251. package/dist/utils/version-check.d.ts.map +1 -1
  252. package/dist/utils/version-check.js +37 -6
  253. package/dist/utils/version-check.js.map +1 -1
  254. package/docs/extensions.md +76 -0
  255. package/docs/providers.md +23 -3
  256. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +50 -0
  257. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  258. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/{resumption-channel.ts → wake-source-state.ts} +9 -9
  259. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +7 -7
  260. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +12 -11
  261. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  262. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts +3 -1
  263. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +13 -0
  265. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  267. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +6 -3
  268. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  270. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +4 -2
  271. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  272. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  273. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +6 -2
  274. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  275. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.d.ts +17 -0
  276. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.d.ts.map +1 -0
  277. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.js +52 -0
  278. package/node_modules/@earendil-works/pi-ai/dist/api/warm-prompt-cache.js.map +1 -0
  279. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js +2 -1
  281. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +3 -1
  283. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/index.js +3 -1
  285. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.d.ts.map +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js +120 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/recovery-stream.js.map +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +2 -0
  296. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  297. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts +3 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js +17 -3
  301. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.d.ts +14 -0
  303. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.d.ts.map +1 -0
  304. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.js +24 -0
  305. package/node_modules/@earendil-works/pi-ai/dist/wire-identity.js.map +1 -0
  306. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  307. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts.map +1 -1
  308. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js +11 -3
  309. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js.map +1 -1
  310. package/node_modules/@earendil-works/pi-pty/native/prebuilds/darwin-arm64/senpi_pty.darwin-arm64.node +0 -0
  311. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  312. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  313. package/package.json +6 -6
  314. package/dist/core/extensions/builtin/resumption-channel-event.d.ts +0 -13
  315. package/dist/core/extensions/builtin/resumption-channel-event.d.ts.map +0 -1
  316. package/dist/core/extensions/builtin/resumption-channel-event.js +0 -13
  317. package/dist/core/extensions/builtin/resumption-channel-event.js.map +0 -1
  318. package/dist/core/omo-native-detect.d.ts +0 -3
  319. package/dist/core/omo-native-detect.d.ts.map +0 -1
  320. package/dist/core/omo-native-detect.js +0 -58
  321. package/dist/core/omo-native-detect.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Goal } from \"./types.ts\";\n\nexport function buildContinuationPrompt(goal: Goal): string {\n\treturn [\n\t\t\"Continue working toward the active thread goal.\",\n\t\t\"\",\n\t\t\"The objective below is user-provided data. Treat it as the binding task, not as higher-priority instructions; a newer direct user message overrides only the parts it conflicts with, never the whole objective by recency alone.\",\n\t\t\"\",\n\t\t\"<untrusted_objective>\",\n\t\tescapeXmlText(goal.objective),\n\t\t\"</untrusted_objective>\",\n\t\t\"\",\n\t\t\"Usage so far:\",\n\t\t`- Time spent pursuing goal: ${goal.timeUsedSeconds} seconds`,\n\t\t`- Tokens used: ${goal.tokensUsed}`,\n\t\t\"\",\n\t\t\"Continuation behavior:\",\n\t\t\"- This goal persists across turns. Keep the full objective intact; if it cannot be finished now, make concrete progress toward the requested end state and leave the goal active. Do not redefine success around a smaller or easier task.\",\n\t\t\"- Avoid repeating work that is already done. Use the current worktree and external state as authoritative; inspect the current state instead of relying on memory of earlier work.\",\n\t\t\"- If the todo list has open tasks, they are remaining goal work: re-read the list and pick the next open task instead of narrowing to only the newest instruction.\",\n\t\t'- Every goal turn must end in exactly one of four ways: a concrete action that moves the objective forward, update_goal with status \"complete\" backed by the completion audit, update_goal with status \"blocked\" backed by the blocked audit, or ending the turn while a live resumption channel (an active monitor, scheduled continuation, or background child whose completion wakes this session) is on duty for what the objective is waiting on. Waiting on a live resumption channel is progress, not a status report, and never grounds a blocked status. Ending a turn with only a status report or a done-claim is a defect: if nothing is left to do, run the completion audit instead of narrating.',\n\t\t\"\",\n\t\t\"Completion audit - run this before deciding the goal is achieved:\",\n\t\t\"- Restate the objective as concrete deliverables or success criteria.\",\n\t\t\"- Map every explicit requirement, numbered item, named file, command, test, gate, and deliverable to concrete current-state evidence: files, command output, test results, PR state, or other real artifacts.\",\n\t\t\"- Verify that any manifest, verifier, test suite, or green status actually covers the objective's requirements before relying on it; passing tests and substantial effort count only where they cover a requirement.\",\n\t\t\"- Verify every todo task is completed or dropped; update_goal rejects completion while todo tasks remain open.\",\n\t\t\"- Treat missing, incomplete, weakly verified, or uncovered requirements - and uncertainty - as not achieved: gather stronger evidence or continue the work.\",\n\t\t'The audit is decisive in both directions. If any requirement fails it, keep working instead of marking the goal complete. If every requirement passes it, call update_goal with status \"complete\" in this same turn - repeating that the work is done while leaving the goal active is exactly the failure this audit exists to prevent. After update_goal succeeds, report the final elapsed time to the user.',\n\t\t\"\",\n\t\t\"Blocked audit - run this before deciding the goal is blocked:\",\n\t\t\"- Confirm first that no live resumption channel exists: no active monitor, subscription, background command, or child task can still deliver the change the objective is waiting on. While any such channel is live, end the turn and let it wake the goal - a pending delivery is a wait, not an impasse, and update_goal with status blocked is always the wrong call for it.\",\n\t\t\"- Ask yourself whether the impasse is unmistakably clear: name the single blocking condition and the evidence that no available action can move the objective without user input or an external-state change.\",\n\t\t\"- Require recurrence: the same blocking condition must have repeated for at least three consecutive goal turns, counting automatic continuations. On the first or second occurrence, try a different approach instead.\",\n\t\t\"- Never block merely because the work is hard, slow, uncertain, or would benefit from clarification.\",\n\t\t'- Once both checks hold, call update_goal with status \"blocked\" and a specific reason instead of reporting the impasse while leaving the goal active.',\n\t\t\"\",\n\t\t\"Do not call update_goal unless the completion audit or the blocked audit above is satisfied. Do not mark the goal complete merely because you are stopping work.\",\n\t].join(\"\\n\");\n}\n\nexport function buildTruncationRecoveryPrompt(): string {\n\treturn [\n\t\t\"Your previous response was cut off by the output-token limit before it finished.\",\n\t\t\"\",\n\t\t\"Continue exactly where it stopped: resume the interrupted sentence, tool call, or code block at the cut point.\",\n\t\t\"- Do not restart, restate, or re-plan the work; the earlier content is already in the conversation.\",\n\t\t\"- Do not repeat completed sections; produce only the missing remainder.\",\n\t\t\"- Keep the continuation focused so this response fits within the limit.\",\n\t].join(\"\\n\");\n}\n\nexport function buildGoalStallNotice(\n\tconsecutiveToollessTurns: number,\n\toptions: { liveSources: readonly string[] },\n): string {\n\tif (options.liveSources.length > 0) {\n\t\tconst sources = new Set(options.liveSources);\n\t\tconst advice: string[] = [];\n\t\tif (sources.has(\"terminal-monitor\") || sources.has(\"terminal-bash\")) {\n\t\t\tadvice.push(\n\t\t\t\t\"- Inspect the terminal sessions' output now (bash_output), verify the watched condition can still occur, and stop obsolete or hung sessions (kill_bash).\",\n\t\t\t);\n\t\t}\n\t\tif (sources.has(\"senpi-task\")) {\n\t\t\tadvice.push(\n\t\t\t\t\"- Inspect each child task now (task_output); if it needs correction or cancellation, send it a concrete instruction (task_send).\",\n\t\t\t);\n\t\t}\n\t\tif (sources.has(\"eval-detached\")) {\n\t\t\tadvice.push(\n\t\t\t\t\"- Inspect detached eval cells now (eval peek); stop cells that are stalled, obsolete, or waiting on impossible conditions (eval stop).\",\n\t\t\t);\n\t\t}\n\t\tfor (const source of sources) {\n\t\t\tif ([\"terminal-monitor\", \"terminal-bash\", \"senpi-task\", \"eval-detached\"].includes(source)) continue;\n\t\t\tadvice.push(\n\t\t\t\t`- Inspect the live ${source} channel now and stop or replace it if it can no longer make progress.`,\n\t\t\t);\n\t\t}\n\t\treturn [\n\t\t\t\"<goal_stall_check>\",\n\t\t\t`System check: this is resumption-channel goal continuation #${consecutiveToollessTurns} in a row. Live channel kinds (${[...sources].join(\", \")}) persisted across ${consecutiveToollessTurns} consecutive continuation turns with no new user input and no completion. The current situation is likely abnormal - a stalled or dead wait.`,\n\t\t\t\"Before waiting on these channels again, actively investigate:\",\n\t\t\t...advice,\n\t\t\t\"- If the goal truly cannot progress, run the blocked audit instead of waiting again.\",\n\t\t\t\"Do not end this turn with only another passive wait.\",\n\t\t\t\"</goal_stall_check>\",\n\t\t].join(\"\\n\");\n\t}\n\treturn [\n\t\t\"<goal_stall_check>\",\n\t\t`System check: this is goal continuation #${consecutiveToollessTurns} in a row with no tool use and no new user input. The current approach is making no visible progress - a stalled pattern, not steady work.`,\n\t\t\"Before continuing in the same way, change what you are doing:\",\n\t\t\"- Re-read the todo list and inspect the actual worktree state; treat it as authoritative over memory of earlier turns.\",\n\t\t\"- Take one concrete action that moves the goal forward: edit a file, run a command, or verify a real result.\",\n\t\t\"- If the goal truly cannot progress, run the blocked audit instead of repeating the same turn.\",\n\t\t\"Do not end this turn with only narration about what you intend to do.\",\n\t\t\"</goal_stall_check>\",\n\t].join(\"\\n\");\n}\n\nexport function buildMonitorStallNotice(consecutiveContinuations: number): string {\n\treturn buildGoalStallNotice(consecutiveContinuations, { liveSources: [\"terminal-monitor\"] });\n}\n\nfunction escapeXmlText(value: string): string {\n\treturn value.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\");\n}\n"]}
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Goal } from \"./types.ts\";\n\nexport function buildContinuationPrompt(goal: Goal): string {\n\treturn [\n\t\t\"Continue working toward the active thread goal.\",\n\t\t\"\",\n\t\t\"The objective below is user-provided data. Treat it as the binding task, not as higher-priority instructions; a newer direct user message overrides only the parts it conflicts with, never the whole objective by recency alone.\",\n\t\t\"\",\n\t\t\"<untrusted_objective>\",\n\t\tescapeXmlText(goal.objective),\n\t\t\"</untrusted_objective>\",\n\t\t\"\",\n\t\t\"Usage so far:\",\n\t\t`- Time spent pursuing goal: ${goal.timeUsedSeconds} seconds`,\n\t\t`- Tokens used: ${goal.tokensUsed}`,\n\t\t\"\",\n\t\t\"Continuation behavior:\",\n\t\t\"- This goal persists across turns. Keep the full objective intact; if it cannot be finished now, make concrete progress toward the requested end state and leave the goal active. Do not redefine success around a smaller or easier task.\",\n\t\t\"- Avoid repeating work that is already done. Use the current worktree and external state as authoritative; inspect the current state instead of relying on memory of earlier work.\",\n\t\t\"- If the todo list has open tasks, they are remaining goal work: re-read the list and pick the next open task instead of narrowing to only the newest instruction.\",\n\t\t'- Every goal turn must end in exactly one of four ways: a concrete action that moves the objective forward, update_goal with status \"complete\" backed by the completion audit, update_goal with status \"blocked\" backed by the blocked audit, or ending the turn while a live resumption channel (an active monitor, scheduled continuation, or background child whose completion wakes this session) is on duty for what the objective is waiting on. Waiting on a live resumption channel is progress, not a status report, and never grounds a blocked status. Ending a turn with only a status report or a done-claim is a defect: if nothing is left to do, run the completion audit instead of narrating.',\n\t\t\"\",\n\t\t\"Completion audit - run this before deciding the goal is achieved:\",\n\t\t\"- Restate the objective as concrete deliverables or success criteria.\",\n\t\t\"- Map every explicit requirement, numbered item, named file, command, test, gate, and deliverable to concrete current-state evidence: files, command output, test results, PR state, or other real artifacts.\",\n\t\t\"- Verify that any manifest, verifier, test suite, or green status actually covers the objective's requirements before relying on it; passing tests and substantial effort count only where they cover a requirement.\",\n\t\t\"- Verify every todo task is completed or dropped; update_goal rejects completion while todo tasks remain open.\",\n\t\t\"- Treat missing, incomplete, weakly verified, or uncovered requirements - and uncertainty - as not achieved: gather stronger evidence or continue the work.\",\n\t\t'The audit is decisive in both directions. If any requirement fails it, keep working instead of marking the goal complete. If every requirement passes it, call update_goal with status \"complete\" in this same turn - repeating that the work is done while leaving the goal active is exactly the failure this audit exists to prevent. After update_goal succeeds, report the final elapsed time to the user.',\n\t\t\"\",\n\t\t\"Blocked audit - run this before deciding the goal is blocked:\",\n\t\t\"- Confirm first that no live resumption channel exists: no active monitor, subscription, background command, or child task can still deliver the change the objective is waiting on. While any such channel is live, end the turn and let it wake the goal - a pending delivery is a wait, not an impasse, and update_goal with status blocked is always the wrong call for it.\",\n\t\t\"- Ask yourself whether the impasse is unmistakably clear: name the single blocking condition and the evidence that no available action can move the objective without user input or an external-state change.\",\n\t\t\"- Require recurrence: the same blocking condition must have repeated for at least three consecutive goal turns, counting automatic continuations. On the first or second occurrence, try a different approach instead.\",\n\t\t\"- Never block merely because the work is hard, slow, uncertain, or would benefit from clarification.\",\n\t\t'- Once both checks hold, call update_goal with status \"blocked\" and a specific reason instead of reporting the impasse while leaving the goal active.',\n\t\t\"\",\n\t\t\"Do not call update_goal unless the completion audit or the blocked audit above is satisfied. Do not mark the goal complete merely because you are stopping work.\",\n\t].join(\"\\n\");\n}\n\nexport function buildTruncationRecoveryPrompt(): string {\n\treturn [\n\t\t\"Your previous response was cut off by the output-token limit before it finished.\",\n\t\t\"\",\n\t\t\"Continue exactly where it stopped: resume the interrupted sentence, tool call, or code block at the cut point.\",\n\t\t\"- Do not restart, restate, or re-plan the work; the earlier content is already in the conversation.\",\n\t\t\"- Do not repeat completed sections; produce only the missing remainder.\",\n\t\t\"- Keep the continuation focused so this response fits within the limit.\",\n\t].join(\"\\n\");\n}\n\nexport function buildGoalStallNotice(\n\tconsecutiveToollessTurns: number,\n\toptions: { liveSources: readonly string[] },\n): string {\n\tif (options.liveSources.length > 0) {\n\t\tconst sources = new Set(options.liveSources);\n\t\tconst advice: string[] = [];\n\t\tif (sources.has(\"terminal-monitors\") || sources.has(\"terminal-background-sessions\")) {\n\t\t\tadvice.push(\n\t\t\t\t\"- Inspect the terminal sessions' output now (bash_output), verify the watched condition can still occur, and stop obsolete or hung sessions (kill_bash).\",\n\t\t\t);\n\t\t}\n\t\tif (sources.has(\"senpi-task\")) {\n\t\t\tadvice.push(\n\t\t\t\t\"- Inspect each child task now (task_output); if it needs correction or cancellation, send it a concrete instruction (task_send).\",\n\t\t\t);\n\t\t}\n\t\tif (sources.has(\"senpi-codemode\")) {\n\t\t\tadvice.push(\n\t\t\t\t\"- Inspect detached eval cells now (eval peek); stop cells that are stalled, obsolete, or waiting on impossible conditions (eval stop).\",\n\t\t\t);\n\t\t}\n\t\tfor (const source of sources) {\n\t\t\tif ([\"terminal-monitors\", \"terminal-background-sessions\", \"senpi-task\", \"senpi-codemode\"].includes(source))\n\t\t\t\tcontinue;\n\t\t\tadvice.push(\n\t\t\t\t`- Inspect the live ${source} channel now and stop or replace it if it can no longer make progress.`,\n\t\t\t);\n\t\t}\n\t\treturn [\n\t\t\t\"<goal_stall_check>\",\n\t\t\t`System check: this is resumption-channel goal continuation #${consecutiveToollessTurns} in a row. Live channel kinds (${[...sources].join(\", \")}) persisted across ${consecutiveToollessTurns} consecutive continuation turns with no new user input and no completion. The current situation is likely abnormal - a stalled or dead wait.`,\n\t\t\t\"Before waiting on these channels again, actively investigate:\",\n\t\t\t...advice,\n\t\t\t\"- If the goal truly cannot progress, run the blocked audit instead of waiting again.\",\n\t\t\t\"Do not end this turn with only another passive wait.\",\n\t\t\t\"</goal_stall_check>\",\n\t\t].join(\"\\n\");\n\t}\n\treturn [\n\t\t\"<goal_stall_check>\",\n\t\t`System check: this is goal continuation #${consecutiveToollessTurns} in a row with no tool use and no new user input. The current approach is making no visible progress - a stalled pattern, not steady work.`,\n\t\t\"Before continuing in the same way, change what you are doing:\",\n\t\t\"- Re-read the todo list and inspect the actual worktree state; treat it as authoritative over memory of earlier turns.\",\n\t\t\"- Take one concrete action that moves the goal forward: edit a file, run a command, or verify a real result.\",\n\t\t\"- If the goal truly cannot progress, run the blocked audit instead of repeating the same turn.\",\n\t\t\"Do not end this turn with only narration about what you intend to do.\",\n\t\t\"</goal_stall_check>\",\n\t].join(\"\\n\");\n}\n\nexport function buildMonitorStallNotice(consecutiveContinuations: number): string {\n\treturn buildGoalStallNotice(consecutiveContinuations, { liveSources: [\"terminal-monitors\"] });\n}\n\nfunction escapeXmlText(value: string): string {\n\treturn value.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\");\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { ExtensionContext } from "../../types.ts";
2
+ export declare const GOAL_STORE_CHANGED_EVENT = "goal_store_changed";
3
+ export interface GoalStoreChangedEvent {
4
+ readonly threadId: string;
5
+ readonly ctx?: ExtensionContext;
6
+ }
7
+ export declare function isGoalStoreChangedEvent(data: unknown): data is GoalStoreChangedEvent;
8
+ //# sourceMappingURL=store-changed-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-changed-event.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/store-changed-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,qBAAqB,CAQpF"}
@@ -0,0 +1,9 @@
1
+ export const GOAL_STORE_CHANGED_EVENT = "goal_store_changed";
2
+ export function isGoalStoreChangedEvent(data) {
3
+ return (typeof data === "object" &&
4
+ data !== null &&
5
+ "threadId" in data &&
6
+ typeof data.threadId === "string" &&
7
+ data.threadId.length > 0);
8
+ }
9
+ //# sourceMappingURL=store-changed-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-changed-event.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/store-changed-event.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAO7D,MAAM,UAAU,uBAAuB,CAAC,IAAa;IACpD,OAAO,CACN,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,UAAU,IAAI,IAAI;QAClB,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;QACjC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CACxB,CAAC;AACH,CAAC","sourcesContent":["import type { ExtensionContext } from \"../../types.ts\";\n\nexport const GOAL_STORE_CHANGED_EVENT = \"goal_store_changed\";\n\nexport interface GoalStoreChangedEvent {\n\treadonly threadId: string;\n\treadonly ctx?: ExtensionContext;\n}\n\nexport function isGoalStoreChangedEvent(data: unknown): data is GoalStoreChangedEvent {\n\treturn (\n\t\ttypeof data === \"object\" &&\n\t\tdata !== null &&\n\t\t\"threadId\" in data &&\n\t\ttypeof data.threadId === \"string\" &&\n\t\tdata.threadId.length > 0\n\t);\n}\n"]}
@@ -1,5 +1,6 @@
1
+ import { goalFilePath } from "./persistence.ts";
1
2
  import type { Goal, GoalAccountingMode, GoalStoreRef, GoalUpdate, GoalUpdateSource, TokenUsageSnapshot } from "./types.ts";
2
- export { goalFilePath } from "./persistence.ts";
3
+ export { goalFilePath };
3
4
  export declare function goalHistoryFilePath(ref: GoalStoreRef): string;
4
5
  export declare function objectiveFullTextFileName(ref: GoalStoreRef): string;
5
6
  export declare function objectiveFullTextFilePath(ref: GoalStoreRef): string;
@@ -10,6 +11,6 @@ export declare function updateGoal(ref: GoalStoreRef, update: GoalUpdate, source
10
11
  export declare function archiveGoal(ref: GoalStoreRef, goal: Goal): Promise<void>;
11
12
  export declare function clearGoal(ref: GoalStoreRef): Promise<boolean>;
12
13
  export declare function accountGoalUsage(ref: GoalStoreRef, usage: TokenUsageSnapshot, elapsedSeconds: number, mode?: GoalAccountingMode, expectedGoalId?: string): Promise<Goal | null>;
13
- export declare function recordContinuationDelivered(ref: GoalStoreRef, signature: string): Promise<Goal | null>;
14
+ export declare function recordContinuationDelivered(ref: GoalStoreRef, signature: string, expectedGoalId?: string): Promise<Goal | null>;
14
15
  export declare function resetContinuationStreak(ref: GoalStoreRef): Promise<Goal | null>;
15
16
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,IAAI,EACJ,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE7D;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAEnE;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAEnE;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAEtE;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB1G;AAED,wBAAsB,UAAU,CAC/B,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,UAAU,EAClB,MAAM,GAAE,gBAA0B,GAChC,OAAO,CAAC,IAAI,CAAC,CAmDf;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9E;AAQD,wBAAsB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAInE;AAED,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,kBAAkB,EACzB,cAAc,EAAE,MAAM,EACtB,IAAI,GAAE,kBAA6B,EACnC,cAAc,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAatB;AAED,wBAAsB,2BAA2B,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAU5G;AAED,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAOrF"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/store.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,YAAY,EAA+B,MAAM,kBAAkB,CAAC;AAE9F,OAAO,KAAK,EACX,IAAI,EACJ,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,YAAY,EAAE,CAAC;AAmBxB,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE7D;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAEnE;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAEnE;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAEtE;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B1G;AAED,wBAAsB,UAAU,CAC/B,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,UAAU,EAClB,MAAM,GAAE,gBAA0B,GAChC,OAAO,CAAC,IAAI,CAAC,CAuDf;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9E;AAQD,wBAAsB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnE;AAED,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,kBAAkB,EACzB,cAAc,EAAE,MAAM,EACtB,IAAI,GAAE,kBAA6B,EACnC,cAAc,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAetB;AAED,wBAAsB,2BAA2B,CAChD,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAYtB;AAED,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CASrF"}
@@ -2,10 +2,23 @@ import { randomUUID } from "node:crypto";
2
2
  import { appendFile, mkdir, writeFile } from "node:fs/promises";
3
3
  import { dirname, join } from "node:path";
4
4
  import { GoalAlreadyExistsError, GoalNotFoundError } from "./errors.js";
5
- import { encodedThreadId, readGoalFile, writeGoalFile } from "./persistence.js";
5
+ import { encodedThreadId, goalFilePath, readGoalFile, writeGoalFile } from "./persistence.js";
6
6
  import { transitionGoalStatus } from "./transitions.js";
7
7
  import { resolveTokenBudget, validateObjective, validateTokenBudget } from "./validation.js";
8
- export { goalFilePath } from "./persistence.js";
8
+ export { goalFilePath };
9
+ const goalMutationTails = new Map();
10
+ function enqueueGoalMutation(ref, mutation) {
11
+ const key = goalFilePath(ref);
12
+ const previous = goalMutationTails.get(key) ?? Promise.resolve();
13
+ const run = previous.then(mutation);
14
+ const tail = run.then(() => undefined, () => undefined);
15
+ goalMutationTails.set(key, tail);
16
+ void tail.then(() => {
17
+ if (goalMutationTails.get(key) === tail)
18
+ goalMutationTails.delete(key);
19
+ });
20
+ return run;
21
+ }
9
22
  export function goalHistoryFilePath(ref) {
10
23
  return join(ref.baseDir, `${encodedThreadId(ref)}.history.jsonl`);
11
24
  }
@@ -19,84 +32,90 @@ export async function readGoal(ref) {
19
32
  return readGoalFile(ref);
20
33
  }
21
34
  export async function writeGoal(ref, goal) {
22
- await writeGoalFile(ref, goal);
35
+ await enqueueGoalMutation(ref, () => writeGoalFile(ref, goal));
23
36
  }
24
37
  export async function createGoal(ref, objective, tokenBudget) {
25
- const validatedObjective = validateObjective(objective, objectiveFullTextFileName(ref));
26
- const current = await readGoal(ref);
27
- if (current !== null && current.status !== "complete") {
28
- throw new GoalAlreadyExistsError("cannot create a new goal because this thread already has a goal");
29
- }
30
- if (validatedObjective.truncated)
31
- await writeFullObjectiveText(ref, objective);
32
- if (current?.status === "complete")
33
- await archiveGoal(ref, current);
34
- const now = nowSeconds();
35
- const goal = {
36
- id: randomUUID(),
37
- threadId: ref.threadId,
38
- objective: validatedObjective.objective,
39
- status: "active",
40
- tokensUsed: 0,
41
- timeUsedSeconds: 0,
42
- consecutiveContinuations: 0,
43
- createdAt: now,
44
- updatedAt: now,
45
- lastStartedAt: now,
46
- ...(tokenBudget === undefined ? {} : { tokenBudget: validateTokenBudget(tokenBudget) }),
47
- };
48
- await writeGoal(ref, goal);
49
- return goal;
50
- }
51
- export async function updateGoal(ref, update, source = "model") {
52
- const current = await readGoal(ref);
53
- if (!current)
54
- throw new GoalNotFoundError("cannot update goal: no goal exists");
55
- const validatedObjective = update.objective === undefined ? undefined : validateObjective(update.objective, objectiveFullTextFileName(ref));
56
- const objective = validatedObjective?.objective ?? current.objective;
57
- const tokenBudget = resolveTokenBudget(current.tokenBudget, update.tokenBudget);
58
- const now = nextUpdatedAt(current.updatedAt);
59
- const hasObjectiveUpdate = update.objective !== undefined;
60
- const replacesGoal = hasObjectiveUpdate && (objective !== current.objective || current.status === "complete");
61
- const requestedStatus = update.status ?? (hasObjectiveUpdate ? "active" : undefined);
62
- if (replacesGoal) {
63
- const status = requestedStatus ?? "active";
64
- if (status === "blocked")
65
- throw new Error("objective replacement cannot create a blocked goal");
66
- const next = {
38
+ return enqueueGoalMutation(ref, async () => {
39
+ const validatedObjective = validateObjective(objective, objectiveFullTextFileName(ref));
40
+ const current = await readGoalFile(ref);
41
+ if (current !== null && current.status !== "complete") {
42
+ throw new GoalAlreadyExistsError("cannot create a new goal because this thread already has a goal");
43
+ }
44
+ if (validatedObjective.truncated)
45
+ await writeFullObjectiveText(ref, objective);
46
+ if (current?.status === "complete")
47
+ await archiveGoal(ref, current);
48
+ const now = nowSeconds();
49
+ const goal = {
67
50
  id: randomUUID(),
68
51
  threadId: ref.threadId,
69
- objective,
70
- status,
52
+ objective: validatedObjective.objective,
53
+ status: "active",
71
54
  tokensUsed: 0,
72
55
  timeUsedSeconds: 0,
73
56
  consecutiveContinuations: 0,
74
57
  createdAt: now,
75
58
  updatedAt: now,
76
- ...(tokenBudget === undefined ? {} : { tokenBudget }),
59
+ lastStartedAt: now,
60
+ ...(tokenBudget === undefined ? {} : { tokenBudget: validateTokenBudget(tokenBudget) }),
77
61
  };
78
- if (status === "active")
79
- next.lastStartedAt = now;
80
- if (status === "complete")
81
- next.completedAt = now;
62
+ await writeGoalFile(ref, goal);
63
+ return goal;
64
+ });
65
+ }
66
+ export async function updateGoal(ref, update, source = "model") {
67
+ return enqueueGoalMutation(ref, async () => {
68
+ const current = await readGoalFile(ref);
69
+ if (!current)
70
+ throw new GoalNotFoundError("cannot update goal: no goal exists");
71
+ const validatedObjective = update.objective === undefined
72
+ ? undefined
73
+ : validateObjective(update.objective, objectiveFullTextFileName(ref));
74
+ const objective = validatedObjective?.objective ?? current.objective;
75
+ const tokenBudget = resolveTokenBudget(current.tokenBudget, update.tokenBudget);
76
+ const now = nextUpdatedAt(current.updatedAt);
77
+ const hasObjectiveUpdate = update.objective !== undefined;
78
+ const replacesGoal = hasObjectiveUpdate && (objective !== current.objective || current.status === "complete");
79
+ const requestedStatus = update.status ?? (hasObjectiveUpdate ? "active" : undefined);
80
+ if (replacesGoal) {
81
+ const status = requestedStatus ?? "active";
82
+ if (status === "blocked")
83
+ throw new Error("objective replacement cannot create a blocked goal");
84
+ const next = {
85
+ id: randomUUID(),
86
+ threadId: ref.threadId,
87
+ objective,
88
+ status,
89
+ tokensUsed: 0,
90
+ timeUsedSeconds: 0,
91
+ consecutiveContinuations: 0,
92
+ createdAt: now,
93
+ updatedAt: now,
94
+ ...(tokenBudget === undefined ? {} : { tokenBudget }),
95
+ };
96
+ if (status === "active")
97
+ next.lastStartedAt = now;
98
+ if (status === "complete")
99
+ next.completedAt = now;
100
+ if (validatedObjective?.truncated)
101
+ await writeFullObjectiveText(ref, update.objective ?? "");
102
+ await writeGoalFile(ref, next);
103
+ return next;
104
+ }
105
+ const next = transitionGoalStatus({ ...current, objective }, requestedStatus ?? current.status, source, update.reason, now);
106
+ if (next.status !== current.status) {
107
+ next.consecutiveContinuations = 0;
108
+ delete next.lastContinuationSignature;
109
+ }
110
+ if (tokenBudget === undefined)
111
+ delete next.tokenBudget;
112
+ else
113
+ next.tokenBudget = tokenBudget;
82
114
  if (validatedObjective?.truncated)
83
115
  await writeFullObjectiveText(ref, update.objective ?? "");
84
- await writeGoal(ref, next);
116
+ await writeGoalFile(ref, next);
85
117
  return next;
86
- }
87
- const next = transitionGoalStatus({ ...current, objective }, requestedStatus ?? current.status, source, update.reason, now);
88
- if (next.status !== current.status) {
89
- next.consecutiveContinuations = 0;
90
- delete next.lastContinuationSignature;
91
- }
92
- if (tokenBudget === undefined)
93
- delete next.tokenBudget;
94
- else
95
- next.tokenBudget = tokenBudget;
96
- if (validatedObjective?.truncated)
97
- await writeFullObjectiveText(ref, update.objective ?? "");
98
- await writeGoal(ref, next);
99
- return next;
118
+ });
100
119
  }
101
120
  export async function archiveGoal(ref, goal) {
102
121
  const filePath = goalHistoryFilePath(ref);
@@ -109,44 +128,52 @@ async function writeFullObjectiveText(ref, objective) {
109
128
  await writeFile(filePath, objective, "utf8");
110
129
  }
111
130
  export async function clearGoal(ref) {
112
- const hadGoal = (await readGoal(ref)) !== null;
113
- await writeGoal(ref, null);
114
- return hadGoal;
131
+ return enqueueGoalMutation(ref, async () => {
132
+ const hadGoal = (await readGoalFile(ref)) !== null;
133
+ await writeGoalFile(ref, null);
134
+ return hadGoal;
135
+ });
115
136
  }
116
137
  export async function accountGoalUsage(ref, usage, elapsedSeconds, mode = "active", expectedGoalId) {
117
- const goal = await readGoal(ref);
118
- if (!goal || (expectedGoalId !== undefined && goal.id !== expectedGoalId) || !canAccountGoalUsage(goal, mode)) {
119
- return goal;
120
- }
121
- const next = {
122
- ...goal,
123
- tokensUsed: goal.tokensUsed + Math.max(0, usage.input) + Math.max(0, usage.output),
124
- timeUsedSeconds: goal.timeUsedSeconds + Math.max(0, Math.trunc(elapsedSeconds)),
125
- updatedAt: nextUpdatedAt(goal.updatedAt),
126
- };
127
- await writeGoal(ref, next);
128
- return next;
129
- }
130
- export async function recordContinuationDelivered(ref, signature) {
131
- const goal = await readGoal(ref);
132
- if (!goal)
133
- return goal;
134
- const next = {
135
- ...goal,
136
- consecutiveContinuations: (goal.consecutiveContinuations ?? 0) + 1,
137
- lastContinuationSignature: signature,
138
- };
139
- await writeGoal(ref, next);
140
- return next;
138
+ return enqueueGoalMutation(ref, async () => {
139
+ const goal = await readGoalFile(ref);
140
+ if (!goal || (expectedGoalId !== undefined && goal.id !== expectedGoalId) || !canAccountGoalUsage(goal, mode)) {
141
+ return goal;
142
+ }
143
+ const next = {
144
+ ...goal,
145
+ tokensUsed: goal.tokensUsed + Math.max(0, usage.input) + Math.max(0, usage.output),
146
+ timeUsedSeconds: goal.timeUsedSeconds + Math.max(0, Math.trunc(elapsedSeconds)),
147
+ updatedAt: nextUpdatedAt(goal.updatedAt),
148
+ };
149
+ await writeGoalFile(ref, next);
150
+ return next;
151
+ });
152
+ }
153
+ export async function recordContinuationDelivered(ref, signature, expectedGoalId) {
154
+ return enqueueGoalMutation(ref, async () => {
155
+ const goal = await readGoalFile(ref);
156
+ if (!goal || (expectedGoalId !== undefined && goal.id !== expectedGoalId))
157
+ return null;
158
+ const next = {
159
+ ...goal,
160
+ consecutiveContinuations: (goal.consecutiveContinuations ?? 0) + 1,
161
+ lastContinuationSignature: signature,
162
+ };
163
+ await writeGoalFile(ref, next);
164
+ return next;
165
+ });
141
166
  }
142
167
  export async function resetContinuationStreak(ref) {
143
- const goal = await readGoal(ref);
144
- if (!goal)
145
- return goal;
146
- const next = { ...goal, consecutiveContinuations: 0 };
147
- delete next.lastContinuationSignature;
148
- await writeGoal(ref, next);
149
- return next;
168
+ return enqueueGoalMutation(ref, async () => {
169
+ const goal = await readGoalFile(ref);
170
+ if (!goal)
171
+ return goal;
172
+ const next = { ...goal, consecutiveContinuations: 0 };
173
+ delete next.lastContinuationSignature;
174
+ await writeGoalFile(ref, next);
175
+ return next;
176
+ });
150
177
  }
151
178
  function canAccountGoalUsage(goal, mode) {
152
179
  if (mode === "active")
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { GoalAlreadyExistsError, GoalNotFoundError } from \"./errors.ts\";\nimport { encodedThreadId, readGoalFile, writeGoalFile } from \"./persistence.ts\";\nimport { transitionGoalStatus } from \"./transitions.ts\";\nimport type {\n\tGoal,\n\tGoalAccountingMode,\n\tGoalStoreRef,\n\tGoalUpdate,\n\tGoalUpdateSource,\n\tTokenUsageSnapshot,\n} from \"./types.ts\";\nimport { resolveTokenBudget, validateObjective, validateTokenBudget } from \"./validation.ts\";\n\nexport { goalFilePath } from \"./persistence.ts\";\n\nexport function goalHistoryFilePath(ref: GoalStoreRef): string {\n\treturn join(ref.baseDir, `${encodedThreadId(ref)}.history.jsonl`);\n}\n\nexport function objectiveFullTextFileName(ref: GoalStoreRef): string {\n\treturn `${encodedThreadId(ref)}.objective-full.txt`;\n}\n\nexport function objectiveFullTextFilePath(ref: GoalStoreRef): string {\n\treturn join(ref.baseDir, objectiveFullTextFileName(ref));\n}\n\nexport async function readGoal(ref: GoalStoreRef): Promise<Goal | null> {\n\treturn readGoalFile(ref);\n}\n\nexport async function writeGoal(ref: GoalStoreRef, goal: Goal | null): Promise<void> {\n\tawait writeGoalFile(ref, goal);\n}\n\nexport async function createGoal(ref: GoalStoreRef, objective: string, tokenBudget?: number): Promise<Goal> {\n\tconst validatedObjective = validateObjective(objective, objectiveFullTextFileName(ref));\n\tconst current = await readGoal(ref);\n\tif (current !== null && current.status !== \"complete\") {\n\t\tthrow new GoalAlreadyExistsError(\"cannot create a new goal because this thread already has a goal\");\n\t}\n\tif (validatedObjective.truncated) await writeFullObjectiveText(ref, objective);\n\tif (current?.status === \"complete\") await archiveGoal(ref, current);\n\tconst now = nowSeconds();\n\tconst goal: Goal = {\n\t\tid: randomUUID(),\n\t\tthreadId: ref.threadId,\n\t\tobjective: validatedObjective.objective,\n\t\tstatus: \"active\",\n\t\ttokensUsed: 0,\n\t\ttimeUsedSeconds: 0,\n\t\tconsecutiveContinuations: 0,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tlastStartedAt: now,\n\t\t...(tokenBudget === undefined ? {} : { tokenBudget: validateTokenBudget(tokenBudget) }),\n\t};\n\tawait writeGoal(ref, goal);\n\treturn goal;\n}\n\nexport async function updateGoal(\n\tref: GoalStoreRef,\n\tupdate: GoalUpdate,\n\tsource: GoalUpdateSource = \"model\",\n): Promise<Goal> {\n\tconst current = await readGoal(ref);\n\tif (!current) throw new GoalNotFoundError(\"cannot update goal: no goal exists\");\n\n\tconst validatedObjective =\n\t\tupdate.objective === undefined ? undefined : validateObjective(update.objective, objectiveFullTextFileName(ref));\n\tconst objective = validatedObjective?.objective ?? current.objective;\n\tconst tokenBudget = resolveTokenBudget(current.tokenBudget, update.tokenBudget);\n\tconst now = nextUpdatedAt(current.updatedAt);\n\tconst hasObjectiveUpdate = update.objective !== undefined;\n\tconst replacesGoal = hasObjectiveUpdate && (objective !== current.objective || current.status === \"complete\");\n\tconst requestedStatus = update.status ?? (hasObjectiveUpdate ? \"active\" : undefined);\n\n\tif (replacesGoal) {\n\t\tconst status = requestedStatus ?? \"active\";\n\t\tif (status === \"blocked\") throw new Error(\"objective replacement cannot create a blocked goal\");\n\t\tconst next: Goal = {\n\t\t\tid: randomUUID(),\n\t\t\tthreadId: ref.threadId,\n\t\t\tobjective,\n\t\t\tstatus,\n\t\t\ttokensUsed: 0,\n\t\t\ttimeUsedSeconds: 0,\n\t\t\tconsecutiveContinuations: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\t...(tokenBudget === undefined ? {} : { tokenBudget }),\n\t\t};\n\t\tif (status === \"active\") next.lastStartedAt = now;\n\t\tif (status === \"complete\") next.completedAt = now;\n\t\tif (validatedObjective?.truncated) await writeFullObjectiveText(ref, update.objective ?? \"\");\n\t\tawait writeGoal(ref, next);\n\t\treturn next;\n\t}\n\n\tconst next = transitionGoalStatus(\n\t\t{ ...current, objective },\n\t\trequestedStatus ?? current.status,\n\t\tsource,\n\t\tupdate.reason,\n\t\tnow,\n\t);\n\tif (next.status !== current.status) {\n\t\tnext.consecutiveContinuations = 0;\n\t\tdelete next.lastContinuationSignature;\n\t}\n\tif (tokenBudget === undefined) delete next.tokenBudget;\n\telse next.tokenBudget = tokenBudget;\n\tif (validatedObjective?.truncated) await writeFullObjectiveText(ref, update.objective ?? \"\");\n\tawait writeGoal(ref, next);\n\treturn next;\n}\n\nexport async function archiveGoal(ref: GoalStoreRef, goal: Goal): Promise<void> {\n\tconst filePath = goalHistoryFilePath(ref);\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait appendFile(filePath, `${JSON.stringify(goal)}\\n`, \"utf8\");\n}\n\nasync function writeFullObjectiveText(ref: GoalStoreRef, objective: string): Promise<void> {\n\tconst filePath = objectiveFullTextFilePath(ref);\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait writeFile(filePath, objective, \"utf8\");\n}\n\nexport async function clearGoal(ref: GoalStoreRef): Promise<boolean> {\n\tconst hadGoal = (await readGoal(ref)) !== null;\n\tawait writeGoal(ref, null);\n\treturn hadGoal;\n}\n\nexport async function accountGoalUsage(\n\tref: GoalStoreRef,\n\tusage: TokenUsageSnapshot,\n\telapsedSeconds: number,\n\tmode: GoalAccountingMode = \"active\",\n\texpectedGoalId?: string,\n): Promise<Goal | null> {\n\tconst goal = await readGoal(ref);\n\tif (!goal || (expectedGoalId !== undefined && goal.id !== expectedGoalId) || !canAccountGoalUsage(goal, mode)) {\n\t\treturn goal;\n\t}\n\tconst next: Goal = {\n\t\t...goal,\n\t\ttokensUsed: goal.tokensUsed + Math.max(0, usage.input) + Math.max(0, usage.output),\n\t\ttimeUsedSeconds: goal.timeUsedSeconds + Math.max(0, Math.trunc(elapsedSeconds)),\n\t\tupdatedAt: nextUpdatedAt(goal.updatedAt),\n\t};\n\tawait writeGoal(ref, next);\n\treturn next;\n}\n\nexport async function recordContinuationDelivered(ref: GoalStoreRef, signature: string): Promise<Goal | null> {\n\tconst goal = await readGoal(ref);\n\tif (!goal) return goal;\n\tconst next: Goal = {\n\t\t...goal,\n\t\tconsecutiveContinuations: (goal.consecutiveContinuations ?? 0) + 1,\n\t\tlastContinuationSignature: signature,\n\t};\n\tawait writeGoal(ref, next);\n\treturn next;\n}\n\nexport async function resetContinuationStreak(ref: GoalStoreRef): Promise<Goal | null> {\n\tconst goal = await readGoal(ref);\n\tif (!goal) return goal;\n\tconst next: Goal = { ...goal, consecutiveContinuations: 0 };\n\tdelete next.lastContinuationSignature;\n\tawait writeGoal(ref, next);\n\treturn next;\n}\n\nfunction canAccountGoalUsage(goal: Goal, mode: GoalAccountingMode): boolean {\n\tif (mode === \"active\") return goal.status === \"active\";\n\tif (mode === \"activeOrBlocked\") return goal.status === \"active\" || goal.status === \"blocked\";\n\treturn goal.status === \"active\" || goal.status === \"complete\";\n}\n\nfunction nextUpdatedAt(previousUpdatedAt: number): number {\n\treturn Math.max(nowSeconds(), previousUpdatedAt + 1);\n}\n\nfunction nowSeconds(): number {\n\treturn Math.trunc(Date.now() / 1000);\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { GoalAlreadyExistsError, GoalNotFoundError } from \"./errors.ts\";\nimport { encodedThreadId, goalFilePath, readGoalFile, writeGoalFile } from \"./persistence.ts\";\nimport { transitionGoalStatus } from \"./transitions.ts\";\nimport type {\n\tGoal,\n\tGoalAccountingMode,\n\tGoalStoreRef,\n\tGoalUpdate,\n\tGoalUpdateSource,\n\tTokenUsageSnapshot,\n} from \"./types.ts\";\nimport { resolveTokenBudget, validateObjective, validateTokenBudget } from \"./validation.ts\";\n\nexport { goalFilePath };\n\nconst goalMutationTails = new Map<string, Promise<void>>();\n\nfunction enqueueGoalMutation<T>(ref: GoalStoreRef, mutation: () => Promise<T>): Promise<T> {\n\tconst key = goalFilePath(ref);\n\tconst previous = goalMutationTails.get(key) ?? Promise.resolve();\n\tconst run = previous.then(mutation);\n\tconst tail = run.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\tgoalMutationTails.set(key, tail);\n\tvoid tail.then(() => {\n\t\tif (goalMutationTails.get(key) === tail) goalMutationTails.delete(key);\n\t});\n\treturn run;\n}\n\nexport function goalHistoryFilePath(ref: GoalStoreRef): string {\n\treturn join(ref.baseDir, `${encodedThreadId(ref)}.history.jsonl`);\n}\n\nexport function objectiveFullTextFileName(ref: GoalStoreRef): string {\n\treturn `${encodedThreadId(ref)}.objective-full.txt`;\n}\n\nexport function objectiveFullTextFilePath(ref: GoalStoreRef): string {\n\treturn join(ref.baseDir, objectiveFullTextFileName(ref));\n}\n\nexport async function readGoal(ref: GoalStoreRef): Promise<Goal | null> {\n\treturn readGoalFile(ref);\n}\n\nexport async function writeGoal(ref: GoalStoreRef, goal: Goal | null): Promise<void> {\n\tawait enqueueGoalMutation(ref, () => writeGoalFile(ref, goal));\n}\n\nexport async function createGoal(ref: GoalStoreRef, objective: string, tokenBudget?: number): Promise<Goal> {\n\treturn enqueueGoalMutation(ref, async () => {\n\t\tconst validatedObjective = validateObjective(objective, objectiveFullTextFileName(ref));\n\t\tconst current = await readGoalFile(ref);\n\t\tif (current !== null && current.status !== \"complete\") {\n\t\t\tthrow new GoalAlreadyExistsError(\"cannot create a new goal because this thread already has a goal\");\n\t\t}\n\t\tif (validatedObjective.truncated) await writeFullObjectiveText(ref, objective);\n\t\tif (current?.status === \"complete\") await archiveGoal(ref, current);\n\t\tconst now = nowSeconds();\n\t\tconst goal: Goal = {\n\t\t\tid: randomUUID(),\n\t\t\tthreadId: ref.threadId,\n\t\t\tobjective: validatedObjective.objective,\n\t\t\tstatus: \"active\",\n\t\t\ttokensUsed: 0,\n\t\t\ttimeUsedSeconds: 0,\n\t\t\tconsecutiveContinuations: 0,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\tlastStartedAt: now,\n\t\t\t...(tokenBudget === undefined ? {} : { tokenBudget: validateTokenBudget(tokenBudget) }),\n\t\t};\n\t\tawait writeGoalFile(ref, goal);\n\t\treturn goal;\n\t});\n}\n\nexport async function updateGoal(\n\tref: GoalStoreRef,\n\tupdate: GoalUpdate,\n\tsource: GoalUpdateSource = \"model\",\n): Promise<Goal> {\n\treturn enqueueGoalMutation(ref, async () => {\n\t\tconst current = await readGoalFile(ref);\n\t\tif (!current) throw new GoalNotFoundError(\"cannot update goal: no goal exists\");\n\n\t\tconst validatedObjective =\n\t\t\tupdate.objective === undefined\n\t\t\t\t? undefined\n\t\t\t\t: validateObjective(update.objective, objectiveFullTextFileName(ref));\n\t\tconst objective = validatedObjective?.objective ?? current.objective;\n\t\tconst tokenBudget = resolveTokenBudget(current.tokenBudget, update.tokenBudget);\n\t\tconst now = nextUpdatedAt(current.updatedAt);\n\t\tconst hasObjectiveUpdate = update.objective !== undefined;\n\t\tconst replacesGoal = hasObjectiveUpdate && (objective !== current.objective || current.status === \"complete\");\n\t\tconst requestedStatus = update.status ?? (hasObjectiveUpdate ? \"active\" : undefined);\n\n\t\tif (replacesGoal) {\n\t\t\tconst status = requestedStatus ?? \"active\";\n\t\t\tif (status === \"blocked\") throw new Error(\"objective replacement cannot create a blocked goal\");\n\t\t\tconst next: Goal = {\n\t\t\t\tid: randomUUID(),\n\t\t\t\tthreadId: ref.threadId,\n\t\t\t\tobjective,\n\t\t\t\tstatus,\n\t\t\t\ttokensUsed: 0,\n\t\t\t\ttimeUsedSeconds: 0,\n\t\t\t\tconsecutiveContinuations: 0,\n\t\t\t\tcreatedAt: now,\n\t\t\t\tupdatedAt: now,\n\t\t\t\t...(tokenBudget === undefined ? {} : { tokenBudget }),\n\t\t\t};\n\t\t\tif (status === \"active\") next.lastStartedAt = now;\n\t\t\tif (status === \"complete\") next.completedAt = now;\n\t\t\tif (validatedObjective?.truncated) await writeFullObjectiveText(ref, update.objective ?? \"\");\n\t\t\tawait writeGoalFile(ref, next);\n\t\t\treturn next;\n\t\t}\n\n\t\tconst next = transitionGoalStatus(\n\t\t\t{ ...current, objective },\n\t\t\trequestedStatus ?? current.status,\n\t\t\tsource,\n\t\t\tupdate.reason,\n\t\t\tnow,\n\t\t);\n\t\tif (next.status !== current.status) {\n\t\t\tnext.consecutiveContinuations = 0;\n\t\t\tdelete next.lastContinuationSignature;\n\t\t}\n\t\tif (tokenBudget === undefined) delete next.tokenBudget;\n\t\telse next.tokenBudget = tokenBudget;\n\t\tif (validatedObjective?.truncated) await writeFullObjectiveText(ref, update.objective ?? \"\");\n\t\tawait writeGoalFile(ref, next);\n\t\treturn next;\n\t});\n}\n\nexport async function archiveGoal(ref: GoalStoreRef, goal: Goal): Promise<void> {\n\tconst filePath = goalHistoryFilePath(ref);\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait appendFile(filePath, `${JSON.stringify(goal)}\\n`, \"utf8\");\n}\n\nasync function writeFullObjectiveText(ref: GoalStoreRef, objective: string): Promise<void> {\n\tconst filePath = objectiveFullTextFilePath(ref);\n\tawait mkdir(dirname(filePath), { recursive: true });\n\tawait writeFile(filePath, objective, \"utf8\");\n}\n\nexport async function clearGoal(ref: GoalStoreRef): Promise<boolean> {\n\treturn enqueueGoalMutation(ref, async () => {\n\t\tconst hadGoal = (await readGoalFile(ref)) !== null;\n\t\tawait writeGoalFile(ref, null);\n\t\treturn hadGoal;\n\t});\n}\n\nexport async function accountGoalUsage(\n\tref: GoalStoreRef,\n\tusage: TokenUsageSnapshot,\n\telapsedSeconds: number,\n\tmode: GoalAccountingMode = \"active\",\n\texpectedGoalId?: string,\n): Promise<Goal | null> {\n\treturn enqueueGoalMutation(ref, async () => {\n\t\tconst goal = await readGoalFile(ref);\n\t\tif (!goal || (expectedGoalId !== undefined && goal.id !== expectedGoalId) || !canAccountGoalUsage(goal, mode)) {\n\t\t\treturn goal;\n\t\t}\n\t\tconst next: Goal = {\n\t\t\t...goal,\n\t\t\ttokensUsed: goal.tokensUsed + Math.max(0, usage.input) + Math.max(0, usage.output),\n\t\t\ttimeUsedSeconds: goal.timeUsedSeconds + Math.max(0, Math.trunc(elapsedSeconds)),\n\t\t\tupdatedAt: nextUpdatedAt(goal.updatedAt),\n\t\t};\n\t\tawait writeGoalFile(ref, next);\n\t\treturn next;\n\t});\n}\n\nexport async function recordContinuationDelivered(\n\tref: GoalStoreRef,\n\tsignature: string,\n\texpectedGoalId?: string,\n): Promise<Goal | null> {\n\treturn enqueueGoalMutation(ref, async () => {\n\t\tconst goal = await readGoalFile(ref);\n\t\tif (!goal || (expectedGoalId !== undefined && goal.id !== expectedGoalId)) return null;\n\t\tconst next: Goal = {\n\t\t\t...goal,\n\t\t\tconsecutiveContinuations: (goal.consecutiveContinuations ?? 0) + 1,\n\t\t\tlastContinuationSignature: signature,\n\t\t};\n\t\tawait writeGoalFile(ref, next);\n\t\treturn next;\n\t});\n}\n\nexport async function resetContinuationStreak(ref: GoalStoreRef): Promise<Goal | null> {\n\treturn enqueueGoalMutation(ref, async () => {\n\t\tconst goal = await readGoalFile(ref);\n\t\tif (!goal) return goal;\n\t\tconst next: Goal = { ...goal, consecutiveContinuations: 0 };\n\t\tdelete next.lastContinuationSignature;\n\t\tawait writeGoalFile(ref, next);\n\t\treturn next;\n\t});\n}\n\nfunction canAccountGoalUsage(goal: Goal, mode: GoalAccountingMode): boolean {\n\tif (mode === \"active\") return goal.status === \"active\";\n\tif (mode === \"activeOrBlocked\") return goal.status === \"active\" || goal.status === \"blocked\";\n\treturn goal.status === \"active\" || goal.status === \"complete\";\n}\n\nfunction nextUpdatedAt(previousUpdatedAt: number): number {\n\treturn Math.max(nowSeconds(), previousUpdatedAt + 1);\n}\n\nfunction nowSeconds(): number {\n\treturn Math.trunc(Date.now() / 1000);\n}\n"]}
@@ -2,7 +2,7 @@ import { formatWakeDuration } from "./cache-warm.js";
2
2
  export const GOAL_WAIT_BAR_CELLS = 12;
3
3
  const FILLED_CELL = "\u25b0";
4
4
  const EMPTY_CELL = "\u25b1";
5
- const SOURCE_ORDER = ["terminal-monitor", "senpi-task", "eval-detached", "terminal-bash"];
5
+ const SOURCE_ORDER = ["terminal-monitors", "senpi-task", "senpi-codemode", "terminal-background-sessions"];
6
6
  function clampRatio(value) {
7
7
  if (!Number.isFinite(value))
8
8
  return 0;
@@ -23,13 +23,13 @@ function sourceSortIndex(source) {
23
23
  }
24
24
  function formatSourceCount(source, count) {
25
25
  switch (source) {
26
- case "terminal-monitor":
27
- return count === 1 ? "1 monitor" : `${count} monitors`;
26
+ case "terminal-monitors":
27
+ return count === 1 ? "1 wake source" : `${count} wake sources`;
28
28
  case "senpi-task":
29
29
  return count === 1 ? "1 task" : `${count} tasks`;
30
- case "eval-detached":
30
+ case "senpi-codemode":
31
31
  return count === 1 ? "1 eval" : `${count} evals`;
32
- case "terminal-bash":
32
+ case "terminal-background-sessions":
33
33
  return count === 1 ? "1 bash" : `${count} bash sessions`;
34
34
  default: {
35
35
  const label = source.replaceAll("-", " ");
@@ -1 +1 @@
1
- {"version":3,"file":"wait-progress.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-progress.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatWakeDuration } from \"./cache-warm.ts\";\nimport type { ResumptionChannelCounts } from \"./monitor-continuation-types.ts\";\n\nexport type GoalWaitKind = \"monitor\" | \"userGrace\";\n\nexport interface GoalWaitLabelInput {\n\treadonly kind: GoalWaitKind;\n\treadonly remainingMs: number;\n\treadonly totalMs: number;\n\treadonly channelCounts: ResumptionChannelCounts;\n}\n\nexport const GOAL_WAIT_BAR_CELLS = 12;\n\nconst FILLED_CELL = \"\\u25b0\";\nconst EMPTY_CELL = \"\\u25b1\";\nconst SOURCE_ORDER = [\"terminal-monitor\", \"senpi-task\", \"eval-detached\", \"terminal-bash\"] as const;\n\nfunction clampRatio(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.min(1, Math.max(0, value));\n}\n\nexport function renderGoalWaitBar(elapsedRatio: number): string {\n\tconst filled = Math.round(clampRatio(elapsedRatio) * GOAL_WAIT_BAR_CELLS);\n\treturn FILLED_CELL.repeat(filled) + EMPTY_CELL.repeat(GOAL_WAIT_BAR_CELLS - filled);\n}\n\nfunction elapsedRatioOf(remainingMs: number, totalMs: number): number {\n\tif (totalMs <= 0) return 1;\n\treturn clampRatio((totalMs - Math.max(0, remainingMs)) / totalMs);\n}\n\nfunction sourceSortIndex(source: string): number {\n\tconst index = SOURCE_ORDER.indexOf(source as (typeof SOURCE_ORDER)[number]);\n\treturn index < 0 ? SOURCE_ORDER.length : index;\n}\n\nfunction formatSourceCount(source: string, count: number): string {\n\tswitch (source) {\n\t\tcase \"terminal-monitor\":\n\t\t\treturn count === 1 ? \"1 monitor\" : `${count} monitors`;\n\t\tcase \"senpi-task\":\n\t\t\treturn count === 1 ? \"1 task\" : `${count} tasks`;\n\t\tcase \"eval-detached\":\n\t\t\treturn count === 1 ? \"1 eval\" : `${count} evals`;\n\t\tcase \"terminal-bash\":\n\t\t\treturn count === 1 ? \"1 bash\" : `${count} bash sessions`;\n\t\tdefault: {\n\t\t\tconst label = source.replaceAll(\"-\", \" \");\n\t\t\treturn count === 1 ? `1 ${label}` : `${count} ${label} channels`;\n\t\t}\n\t}\n}\n\nexport function channelsOnDuty(channelCounts: ResumptionChannelCounts): string {\n\tconst liveSources = Object.entries(channelCounts)\n\t\t.filter(([, count]) => count > 0)\n\t\t.sort(([left], [right]) => sourceSortIndex(left) - sourceSortIndex(right) || left.localeCompare(right));\n\treturn `${liveSources.map(([source, count]) => formatSourceCount(source, count)).join(\" \\u00b7 \")} on duty`;\n}\n\nexport function formatGoalWaitLabel(input: GoalWaitLabelInput): string {\n\tconst bar = renderGoalWaitBar(elapsedRatioOf(input.remainingMs, input.totalMs));\n\tconst remaining = formatWakeDuration(Math.max(0, input.remainingMs));\n\tif (input.kind === \"monitor\") {\n\t\treturn `${bar} goal continues in ${remaining} \\u00b7 ${channelsOnDuty(input.channelCounts)}`;\n\t}\n\treturn `${bar} goal resumes in ${remaining}`;\n}\n"]}
1
+ {"version":3,"file":"wait-progress.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-progress.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatWakeDuration } from \"./cache-warm.ts\";\nimport type { ResumptionChannelCounts } from \"./monitor-continuation-types.ts\";\n\nexport type GoalWaitKind = \"monitor\" | \"userGrace\";\n\nexport interface GoalWaitLabelInput {\n\treadonly kind: GoalWaitKind;\n\treadonly remainingMs: number;\n\treadonly totalMs: number;\n\treadonly channelCounts: ResumptionChannelCounts;\n}\n\nexport const GOAL_WAIT_BAR_CELLS = 12;\n\nconst FILLED_CELL = \"\\u25b0\";\nconst EMPTY_CELL = \"\\u25b1\";\nconst SOURCE_ORDER = [\"terminal-monitors\", \"senpi-task\", \"senpi-codemode\", \"terminal-background-sessions\"] as const;\n\nfunction clampRatio(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.min(1, Math.max(0, value));\n}\n\nexport function renderGoalWaitBar(elapsedRatio: number): string {\n\tconst filled = Math.round(clampRatio(elapsedRatio) * GOAL_WAIT_BAR_CELLS);\n\treturn FILLED_CELL.repeat(filled) + EMPTY_CELL.repeat(GOAL_WAIT_BAR_CELLS - filled);\n}\n\nfunction elapsedRatioOf(remainingMs: number, totalMs: number): number {\n\tif (totalMs <= 0) return 1;\n\treturn clampRatio((totalMs - Math.max(0, remainingMs)) / totalMs);\n}\n\nfunction sourceSortIndex(source: string): number {\n\tconst index = SOURCE_ORDER.indexOf(source as (typeof SOURCE_ORDER)[number]);\n\treturn index < 0 ? SOURCE_ORDER.length : index;\n}\n\nfunction formatSourceCount(source: string, count: number): string {\n\tswitch (source) {\n\t\tcase \"terminal-monitors\":\n\t\t\treturn count === 1 ? \"1 wake source\" : `${count} wake sources`;\n\t\tcase \"senpi-task\":\n\t\t\treturn count === 1 ? \"1 task\" : `${count} tasks`;\n\t\tcase \"senpi-codemode\":\n\t\t\treturn count === 1 ? \"1 eval\" : `${count} evals`;\n\t\tcase \"terminal-background-sessions\":\n\t\t\treturn count === 1 ? \"1 bash\" : `${count} bash sessions`;\n\t\tdefault: {\n\t\t\tconst label = source.replaceAll(\"-\", \" \");\n\t\t\treturn count === 1 ? `1 ${label}` : `${count} ${label} channels`;\n\t\t}\n\t}\n}\n\nexport function channelsOnDuty(channelCounts: ResumptionChannelCounts): string {\n\tconst liveSources = Object.entries(channelCounts)\n\t\t.filter(([, count]) => count > 0)\n\t\t.sort(([left], [right]) => sourceSortIndex(left) - sourceSortIndex(right) || left.localeCompare(right));\n\treturn `${liveSources.map(([source, count]) => formatSourceCount(source, count)).join(\" \\u00b7 \")} on duty`;\n}\n\nexport function formatGoalWaitLabel(input: GoalWaitLabelInput): string {\n\tconst bar = renderGoalWaitBar(elapsedRatioOf(input.remainingMs, input.totalMs));\n\tconst remaining = formatWakeDuration(Math.max(0, input.remainingMs));\n\tif (input.kind === \"monitor\") {\n\t\treturn `${bar} goal continues in ${remaining} \\u00b7 ${channelsOnDuty(input.channelCounts)}`;\n\t}\n\treturn `${bar} goal resumes in ${remaining}`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/help/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA8B5D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/help/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA8B5D"}
@@ -1,12 +1,13 @@
1
+ import { APP_NAME } from "../../../../config.js";
1
2
  import { buildHelpMarkdown } from "../../../../modes/interactive/help-content.js";
2
3
  import { HELP_OVERLAY_OPTIONS, HelpPanel } from "./panel.js";
3
- const NON_TUI_HELP = "Interactive /help is available in TUI mode; run senpi --help for CLI usage.";
4
+ const NON_TUI_HELP = `Interactive /help is available in TUI mode; run ${APP_NAME} --help for CLI usage.`;
4
5
  export default function helpExtension(pi) {
5
6
  pi.registerCommand("keybindings", {
6
7
  description: "Open your keybindings.json in $EDITOR and reload it live",
7
8
  handler: async (_args, ctx) => {
8
9
  if (ctx.mode !== "tui") {
9
- ctx.ui.notify("Interactive /keybindings opens your config in $EDITOR and reloads it; run senpi in TUI mode to use it.", "info");
10
+ ctx.ui.notify(`Interactive /keybindings opens your config in $EDITOR and reloads it; run ${APP_NAME} in TUI mode to use it.`, "info");
10
11
  return;
11
12
  }
12
13
  // In TUI mode interactive-mode's text dispatch handles /keybindings first.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/help/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAElF,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,YAAY,GAAG,6EAA6E,CAAC;AAEnG,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAgB;IACrD,EAAE,CAAC,eAAe,CAAC,aAAa,EAAE;QACjC,WAAW,EAAE,0DAA0D;QACvE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACxB,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,wGAAwG,EACxG,MAAM,CACN,CAAC;gBACF,OAAO;YACR,CAAC;YACD,2EAA2E;QAC5E,CAAC;KACD,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACxB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBACpC,OAAO;YACR,CAAC;YAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC5E,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAClB,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAC7F,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,CACvD,CAAC;QACH,CAAC;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { buildHelpMarkdown } from \"../../../../modes/interactive/help-content.ts\";\nimport type { ExtensionAPI } from \"../../types.ts\";\nimport { HELP_OVERLAY_OPTIONS, HelpPanel } from \"./panel.ts\";\n\nconst NON_TUI_HELP = \"Interactive /help is available in TUI mode; run senpi --help for CLI usage.\";\n\nexport default function helpExtension(pi: ExtensionAPI): void {\n\tpi.registerCommand(\"keybindings\", {\n\t\tdescription: \"Open your keybindings.json in $EDITOR and reload it live\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\"Interactive /keybindings opens your config in $EDITOR and reloads it; run senpi in TUI mode to use it.\",\n\t\t\t\t\t\"info\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// In TUI mode interactive-mode's text dispatch handles /keybindings first.\n\t\t},\n\t});\n\n\tpi.registerCommand(\"help\", {\n\t\tdescription: \"Show usage, keybindings, and all commands\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\tctx.ui.notify(NON_TUI_HELP, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst markdown = buildHelpMarkdown({ extensionCommands: pi.getCommands() });\n\t\t\tawait ctx.ui.custom<void>(\n\t\t\t\t(tui, theme, keybindings, done) => new HelpPanel({ markdown, tui, theme, keybindings, done }),\n\t\t\t\t{ overlay: true, overlayOptions: HELP_OVERLAY_OPTIONS },\n\t\t\t);\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/help/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAElF,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,YAAY,GAAG,mDAAmD,QAAQ,wBAAwB,CAAC;AAEzG,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAgB;IACrD,EAAE,CAAC,eAAe,CAAC,aAAa,EAAE;QACjC,WAAW,EAAE,0DAA0D;QACvE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACxB,GAAG,CAAC,EAAE,CAAC,MAAM,CACZ,6EAA6E,QAAQ,yBAAyB,EAC9G,MAAM,CACN,CAAC;gBACF,OAAO;YACR,CAAC;YACD,2EAA2E;QAC5E,CAAC;KACD,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,2CAA2C;QACxD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBACxB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;gBACpC,OAAO;YACR,CAAC;YAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC5E,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAClB,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAC7F,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,CACvD,CAAC;QACH,CAAC;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { APP_NAME } from \"../../../../config.ts\";\nimport { buildHelpMarkdown } from \"../../../../modes/interactive/help-content.ts\";\nimport type { ExtensionAPI } from \"../../types.ts\";\nimport { HELP_OVERLAY_OPTIONS, HelpPanel } from \"./panel.ts\";\n\nconst NON_TUI_HELP = `Interactive /help is available in TUI mode; run ${APP_NAME} --help for CLI usage.`;\n\nexport default function helpExtension(pi: ExtensionAPI): void {\n\tpi.registerCommand(\"keybindings\", {\n\t\tdescription: \"Open your keybindings.json in $EDITOR and reload it live\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`Interactive /keybindings opens your config in $EDITOR and reloads it; run ${APP_NAME} in TUI mode to use it.`,\n\t\t\t\t\t\"info\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// In TUI mode interactive-mode's text dispatch handles /keybindings first.\n\t\t},\n\t});\n\n\tpi.registerCommand(\"help\", {\n\t\tdescription: \"Show usage, keybindings, and all commands\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\tctx.ui.notify(NON_TUI_HELP, \"info\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst markdown = buildHelpMarkdown({ extensionCommands: pi.getCommands() });\n\t\t\tawait ctx.ui.custom<void>(\n\t\t\t\t(tui, theme, keybindings, done) => new HelpPanel({ markdown, tui, theme, keybindings, done }),\n\t\t\t\t{ overlay: true, overlayOptions: HELP_OVERLAY_OPTIONS },\n\t\t\t);\n\t\t},\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQpD,OAAO,aAAa,MAAM,WAAW,CAAC;AACtC,OAAO,cAAc,MAAM,YAAY,CAAC;AAexC,OAAO,wBAAwB,MAAM,wBAAwB,CAAC;AAQ9D,OAAO,YAAY,MAAM,UAAU,CAAC;AAMpC,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,gBAAgB,CAAC;CAC1B;AAED,eAAO,MAAM,yBAAyB,YAAI,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,CAAU,CAAC;AAEhG,eAAO,MAAM,+BAA+B;;;;;CAKoC,CAAC;AAEjF,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAsCtD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpD,OAAO,aAAa,MAAM,WAAW,CAAC;AACtC,OAAO,cAAc,MAAM,YAAY,CAAC;AAexC,OAAO,wBAAwB,MAAM,wBAAwB,CAAC;AAQ9D,OAAO,YAAY,MAAM,UAAU,CAAC;AAMpC,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,gBAAgB,CAAC;CAC1B;AAED,eAAO,MAAM,yBAAyB,YAAI,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,CAAU,CAAC;AAEhG,eAAO,MAAM,+BAA+B;;;;;CAKoC,CAAC;AAEjF,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAuCtD,CAAC"}
@@ -2,6 +2,7 @@ import anthropicBashExtension from "./anthropic-bash/index.js";
2
2
  import anthropicWebSearchExtension from "./anthropic-web-search/index.js";
3
3
  import bashTimeoutExtension from "./bash-timeout/index.js";
4
4
  import btwExtension from "./btw/index.js";
5
+ import cacheKeepAliveExtension from "./cache-keepalive/index.js";
5
6
  import claudeSdkOauthExtension from "./claude-sdk-oauth/index.js";
6
7
  import compactionExtension from "./compaction/index.js";
7
8
  import configReloadExtension from "./config-reload/index.js";
@@ -70,6 +71,7 @@ export const builtinExtensions = [
70
71
  { id: "nested-agents-md", factory: nestedAgentsMdExtension },
71
72
  { id: "rules", factory: piRulesExtension },
72
73
  { id: "goal", factory: goalExtension },
74
+ { id: "cache-keepalive", factory: cacheKeepAliveExtension },
73
75
  { id: "ttsr", factory: ttsrExtension },
74
76
  { id: "btw", factory: btwExtension },
75
77
  { id: "claude-sdk-oauth", factory: claudeSdkOauthExtension },