@code-yeongyu/senpi 2026.8.18-3 → 2026.8.19

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 (353) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +4 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +33 -4
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +293 -55
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  11. package/dist/core/compaction/branch-summarization.js +3 -0
  12. package/dist/core/compaction/branch-summarization.js.map +1 -1
  13. package/dist/core/compaction/compaction.d.ts +20 -3
  14. package/dist/core/compaction/compaction.d.ts.map +1 -1
  15. package/dist/core/compaction/compaction.js +182 -52
  16. package/dist/core/compaction/compaction.js.map +1 -1
  17. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts +3 -0
  18. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts.map +1 -1
  19. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js +18 -1
  20. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js.map +1 -1
  21. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.d.ts +1 -0
  22. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.d.ts.map +1 -1
  23. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.js +7 -1
  24. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.js.map +1 -1
  25. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts +8 -0
  26. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js +18 -0
  28. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js.map +1 -1
  29. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.d.ts +7 -0
  30. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.d.ts.map +1 -1
  31. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.js +10 -1
  32. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.js.map +1 -1
  33. package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js +12 -1
  35. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js.map +1 -1
  36. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts +12 -1
  37. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts.map +1 -1
  38. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js +20 -1
  39. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js.map +1 -1
  40. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts +11 -0
  41. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js +7 -2
  43. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js.map +1 -1
  44. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js +7 -2
  46. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js.map +1 -1
  47. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  48. package/dist/core/extensions/builtin/index.js +2 -0
  49. package/dist/core/extensions/builtin/index.js.map +1 -1
  50. package/dist/core/extensions/builtin/loop/command-registration.d.ts +7 -0
  51. package/dist/core/extensions/builtin/loop/command-registration.d.ts.map +1 -0
  52. package/dist/core/extensions/builtin/loop/command-registration.js +13 -0
  53. package/dist/core/extensions/builtin/loop/command-registration.js.map +1 -0
  54. package/dist/core/extensions/builtin/loop/command.d.ts +41 -0
  55. package/dist/core/extensions/builtin/loop/command.d.ts.map +1 -0
  56. package/dist/core/extensions/builtin/loop/command.js +281 -0
  57. package/dist/core/extensions/builtin/loop/command.js.map +1 -0
  58. package/dist/core/extensions/builtin/loop/cron-planner.d.ts +23 -0
  59. package/dist/core/extensions/builtin/loop/cron-planner.d.ts.map +1 -0
  60. package/dist/core/extensions/builtin/loop/cron-planner.js +88 -0
  61. package/dist/core/extensions/builtin/loop/cron-planner.js.map +1 -0
  62. package/dist/core/extensions/builtin/loop/index.d.ts +134 -0
  63. package/dist/core/extensions/builtin/loop/index.d.ts.map +1 -0
  64. package/dist/core/extensions/builtin/loop/index.js +742 -0
  65. package/dist/core/extensions/builtin/loop/index.js.map +1 -0
  66. package/dist/core/extensions/builtin/loop/loopfile.d.ts +40 -0
  67. package/dist/core/extensions/builtin/loop/loopfile.d.ts.map +1 -0
  68. package/dist/core/extensions/builtin/loop/loopfile.js +102 -0
  69. package/dist/core/extensions/builtin/loop/loopfile.js.map +1 -0
  70. package/dist/core/extensions/builtin/loop/parse.d.ts +45 -0
  71. package/dist/core/extensions/builtin/loop/parse.d.ts.map +1 -0
  72. package/dist/core/extensions/builtin/loop/parse.js +92 -0
  73. package/dist/core/extensions/builtin/loop/parse.js.map +1 -0
  74. package/dist/core/extensions/builtin/loop/scheduler.d.ts +225 -0
  75. package/dist/core/extensions/builtin/loop/scheduler.d.ts.map +1 -0
  76. package/dist/core/extensions/builtin/loop/scheduler.js +708 -0
  77. package/dist/core/extensions/builtin/loop/scheduler.js.map +1 -0
  78. package/dist/core/extensions/builtin/loop/status.d.ts +24 -0
  79. package/dist/core/extensions/builtin/loop/status.d.ts.map +1 -0
  80. package/dist/core/extensions/builtin/loop/status.js +113 -0
  81. package/dist/core/extensions/builtin/loop/status.js.map +1 -0
  82. package/dist/core/extensions/builtin/loop/store.d.ts +49 -0
  83. package/dist/core/extensions/builtin/loop/store.d.ts.map +1 -0
  84. package/dist/core/extensions/builtin/loop/store.js +424 -0
  85. package/dist/core/extensions/builtin/loop/store.js.map +1 -0
  86. package/dist/core/extensions/builtin/loop/tick-prompt.d.ts +64 -0
  87. package/dist/core/extensions/builtin/loop/tick-prompt.d.ts.map +1 -0
  88. package/dist/core/extensions/builtin/loop/tick-prompt.js +183 -0
  89. package/dist/core/extensions/builtin/loop/tick-prompt.js.map +1 -0
  90. package/dist/core/extensions/builtin/loop/tools.d.ts +122 -0
  91. package/dist/core/extensions/builtin/loop/tools.d.ts.map +1 -0
  92. package/dist/core/extensions/builtin/loop/tools.js +155 -0
  93. package/dist/core/extensions/builtin/loop/tools.js.map +1 -0
  94. package/dist/core/extensions/builtin/loop/types.d.ts +206 -0
  95. package/dist/core/extensions/builtin/loop/types.d.ts.map +1 -0
  96. package/dist/core/extensions/builtin/loop/types.js +37 -0
  97. package/dist/core/extensions/builtin/loop/types.js.map +1 -0
  98. package/dist/core/extensions/index.d.ts +1 -1
  99. package/dist/core/extensions/index.d.ts.map +1 -1
  100. package/dist/core/extensions/index.js.map +1 -1
  101. package/dist/core/extensions/loader.d.ts.map +1 -1
  102. package/dist/core/extensions/loader.js +10 -5
  103. package/dist/core/extensions/loader.js.map +1 -1
  104. package/dist/core/extensions/types.d.ts +30 -3
  105. package/dist/core/extensions/types.d.ts.map +1 -1
  106. package/dist/core/extensions/types.js.map +1 -1
  107. package/dist/core/footer-data-provider.d.ts.map +1 -1
  108. package/dist/core/footer-data-provider.js +5 -10
  109. package/dist/core/footer-data-provider.js.map +1 -1
  110. package/dist/core/model-registry.d.ts +2 -0
  111. package/dist/core/model-registry.d.ts.map +1 -1
  112. package/dist/core/model-registry.js +4 -0
  113. package/dist/core/model-registry.js.map +1 -1
  114. package/dist/core/model-runtime.d.ts +7 -0
  115. package/dist/core/model-runtime.d.ts.map +1 -1
  116. package/dist/core/model-runtime.js +17 -0
  117. package/dist/core/model-runtime.js.map +1 -1
  118. package/dist/core/package-manager.d.ts.map +1 -1
  119. package/dist/core/package-manager.js +8 -4
  120. package/dist/core/package-manager.js.map +1 -1
  121. package/dist/core/provider-composer.d.ts +8 -0
  122. package/dist/core/provider-composer.d.ts.map +1 -1
  123. package/dist/core/provider-composer.js.map +1 -1
  124. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  125. package/dist/core/remote-catalog-provider.js +2 -1
  126. package/dist/core/remote-catalog-provider.js.map +1 -1
  127. package/dist/core/retry-fallback/chains.d.ts +1 -0
  128. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  129. package/dist/core/retry-fallback/chains.js +3 -0
  130. package/dist/core/retry-fallback/chains.js.map +1 -1
  131. package/dist/core/retry-fallback/controller.d.ts +2 -0
  132. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  133. package/dist/core/retry-fallback/controller.js.map +1 -1
  134. package/dist/core/retry-fallback/expansion.d.ts +8 -0
  135. package/dist/core/retry-fallback/expansion.d.ts.map +1 -1
  136. package/dist/core/retry-fallback/expansion.js +2 -0
  137. package/dist/core/retry-fallback/expansion.js.map +1 -1
  138. package/dist/core/settings-manager.d.ts +1 -1
  139. package/dist/core/settings-manager.d.ts.map +1 -1
  140. package/dist/core/settings-manager.js +14 -3
  141. package/dist/core/settings-manager.js.map +1 -1
  142. package/dist/core/skills.d.ts.map +1 -1
  143. package/dist/core/skills.js +51 -33
  144. package/dist/core/skills.js.map +1 -1
  145. package/dist/core/tools/edit.d.ts.map +1 -1
  146. package/dist/core/tools/edit.js +17 -2
  147. package/dist/core/tools/edit.js.map +1 -1
  148. package/dist/extensions/llama/index.d.ts.map +1 -1
  149. package/dist/extensions/llama/index.js +2 -0
  150. package/dist/extensions/llama/index.js.map +1 -1
  151. package/dist/extensions/llama/provider.d.ts.map +1 -1
  152. package/dist/extensions/llama/provider.js +6 -6
  153. package/dist/extensions/llama/provider.js.map +1 -1
  154. package/dist/index.d.ts +1 -1
  155. package/dist/index.d.ts.map +1 -1
  156. package/dist/index.js.map +1 -1
  157. package/dist/main.d.ts +4 -0
  158. package/dist/main.d.ts.map +1 -1
  159. package/dist/main.js +4 -4
  160. package/dist/main.js.map +1 -1
  161. package/dist/modes/interactive/components/settings-selector.js +1 -1
  162. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  163. package/dist/modes/interactive/editor-paste-transfer.d.ts +10 -1
  164. package/dist/modes/interactive/editor-paste-transfer.d.ts.map +1 -1
  165. package/dist/modes/interactive/editor-paste-transfer.js +27 -2
  166. package/dist/modes/interactive/editor-paste-transfer.js.map +1 -1
  167. package/dist/modes/interactive/interactive-mode.d.ts +69 -1
  168. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/dist/modes/interactive/interactive-mode.js +434 -63
  170. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/dist/modes/interactive/tips/catalog/dag-tips.d.ts +7 -0
  172. package/dist/modes/interactive/tips/catalog/dag-tips.d.ts.map +1 -0
  173. package/dist/modes/interactive/tips/catalog/dag-tips.js +57 -0
  174. package/dist/modes/interactive/tips/catalog/dag-tips.js.map +1 -0
  175. package/dist/modes/interactive/tips/catalog/memory-tips.d.ts +7 -0
  176. package/dist/modes/interactive/tips/catalog/memory-tips.d.ts.map +1 -0
  177. package/dist/modes/interactive/tips/catalog/memory-tips.js +100 -0
  178. package/dist/modes/interactive/tips/catalog/memory-tips.js.map +1 -0
  179. package/dist/modes/interactive/tips/registry.d.ts.map +1 -1
  180. package/dist/modes/interactive/tips/registry.js +4 -0
  181. package/dist/modes/interactive/tips/registry.js.map +1 -1
  182. package/dist/utils/management-http.d.ts +5 -3
  183. package/dist/utils/management-http.d.ts.map +1 -1
  184. package/dist/utils/management-http.js +14 -10
  185. package/dist/utils/management-http.js.map +1 -1
  186. package/docs/compaction.md +17 -0
  187. package/docs/custom-provider.md +5 -2
  188. package/docs/extensions.md +11 -2
  189. package/docs/llama-cpp.md +2 -0
  190. package/docs/models.md +8 -2
  191. package/docs/providers.md +5 -3
  192. package/docs/settings.md +22 -2
  193. package/docs/skills.md +4 -3
  194. package/examples/extensions/border-status-editor.ts +1 -1
  195. package/examples/extensions/git-checkpoint.ts +2 -2
  196. package/examples/extensions/notify.ts +3 -1
  197. package/examples/extensions/subagent/index.ts +6 -1
  198. package/examples/extensions/titlebar-spinner.ts +1 -1
  199. package/examples/rpc-extension-ui.ts +1 -1
  200. package/examples/sdk/06-extensions.ts +1 -1
  201. package/examples/sdk/README.md +1 -1
  202. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  203. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  204. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts +3 -1
  205. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  206. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +51 -17
  207. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  208. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +4 -2
  209. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  210. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +5 -1
  211. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  212. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.d.ts +3 -2
  213. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  214. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.js +13 -3
  215. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.js.map +1 -1
  216. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.d.ts.map +1 -1
  217. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js +14 -1
  218. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js.map +1 -1
  219. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  220. package/node_modules/@earendil-works/pi-ai/README.md +5 -3
  221. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts +7 -1
  222. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  223. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +21 -4
  224. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  225. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts +2 -0
  226. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts.map +1 -1
  227. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +7 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js.map +1 -1
  229. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +39 -2
  231. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.d.ts +22 -1
  233. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.d.ts.map +1 -1
  234. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.js +1 -1
  235. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.js.map +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +1 -0
  237. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
  238. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +51 -2
  239. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
  240. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts +2 -2
  241. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts.map +1 -1
  242. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js +14 -11
  243. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js.map +1 -1
  244. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.d.ts +5 -2
  245. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.d.ts.map +1 -1
  246. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js +16 -0
  247. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js.map +1 -1
  248. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts +2 -2
  249. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js +13 -10
  251. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js.map +1 -1
  252. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.d.ts.map +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js +4 -1
  254. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js.map +1 -1
  255. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  256. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +4 -1
  257. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts +1 -1
  259. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  260. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +45 -29
  261. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -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 +8 -1
  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/pi-messages.js +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js.map +1 -1
  267. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.d.ts +4 -0
  268. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.d.ts.map +1 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js +18 -9
  270. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js.map +1 -1
  271. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.d.ts +1 -0
  272. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.d.ts.map +1 -1
  273. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.js +1 -1
  274. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.js.map +1 -1
  275. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  276. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js +22 -9
  277. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +2 -1
  279. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  281. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  283. package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
  285. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-individual.json +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xai.json +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi.json +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
  297. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.d.ts +1 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.js +1 -5
  301. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +28 -4
  303. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  305. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +15 -0
  307. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
  308. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.d.ts +2 -0
  309. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.d.ts.map +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js +7 -0
  311. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js.map +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts +2 -1
  313. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js +2 -0
  315. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js.map +1 -1
  316. package/node_modules/@earendil-works/pi-ai/package.json +2 -3
  317. package/node_modules/@earendil-works/pi-pty/dist/loader.d.ts +6 -0
  318. package/node_modules/@earendil-works/pi-pty/dist/loader.d.ts.map +1 -1
  319. package/node_modules/@earendil-works/pi-pty/dist/loader.js +11 -0
  320. package/node_modules/@earendil-works/pi-pty/dist/loader.js.map +1 -1
  321. package/node_modules/@earendil-works/pi-pty/dist/quarantine.d.ts +15 -0
  322. package/node_modules/@earendil-works/pi-pty/dist/quarantine.d.ts.map +1 -0
  323. package/node_modules/@earendil-works/pi-pty/dist/quarantine.js +27 -0
  324. package/node_modules/@earendil-works/pi-pty/dist/quarantine.js.map +1 -0
  325. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  326. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  327. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +73 -1
  328. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  329. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +173 -17
  330. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  331. package/node_modules/@earendil-works/pi-tui/dist/components/text.d.ts.map +1 -1
  332. package/node_modules/@earendil-works/pi-tui/dist/components/text.js +5 -4
  333. package/node_modules/@earendil-works/pi-tui/dist/components/text.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts +69 -0
  335. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts.map +1 -1
  336. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js.map +1 -1
  337. package/node_modules/@earendil-works/pi-tui/dist/image-markers.d.ts +46 -0
  338. package/node_modules/@earendil-works/pi-tui/dist/image-markers.d.ts.map +1 -0
  339. package/node_modules/@earendil-works/pi-tui/dist/image-markers.js +130 -0
  340. package/node_modules/@earendil-works/pi-tui/dist/image-markers.js.map +1 -0
  341. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -0
  342. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  343. package/node_modules/@earendil-works/pi-tui/dist/index.js +2 -0
  344. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  345. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.d.ts +3 -0
  346. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.d.ts.map +1 -1
  347. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.js +23 -7
  348. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.js.map +1 -1
  349. package/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.d.ts.map +1 -1
  350. package/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.js +5 -1
  351. package/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.js.map +1 -1
  352. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  353. package/package.json +7 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/loop/scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure state machine behind the `/loop` extension.\n *\n * Everything time-related or timer-related is injected: a {@link LoopClock} supplies\n * `now`, and a {@link LoopTimerPort} owns the single armed timeout per loop. This module\n * performs NO I/O, never calls `setTimeout`/`Date.now`, and never persists anything\n * itself — the caller mirrors {@link LoopScheduler.getState} into the sidecar store. That\n * keeps every invariant below testable with a fake clock and zero real waiting.\n *\n * The load-bearing invariants:\n * - At most ONE queued or running tick per loop. A fire that lands while one is in flight\n * sets `coalescedFirePending` instead of enqueuing a second delivery, so a sleeping\n * laptop or a long turn can never produce a tick storm.\n * - `nextFireAt` is ALWAYS recomputed from `now`, never from the stale due time, so all\n * occurrences missed during sleep collapse into exactly one catch-up tick.\n * - 7-day expiry from `createdAt` is checked at arm, fire, re-entry and restore, is never\n * extended by a new wakeup, and no tick fires at or after it.\n * - At most {@link MAX_ACTIVE_LOOPS} active loops; a further creation returns a typed\n * rejection and leaves existing loops armed.\n * - A dispatched-tick budget (default {@link DEFAULT_MAX_TICKS}) ends the loop with\n * `tick_budget_exhausted` so a forgotten fast loop cannot spend without bound.\n * - Keepalive is a two-strike device on dynamic loops only, and a user abort PAUSES a\n * loop instead of ending it (and is never counted as a keepalive omission).\n * - Shutdown SUSPENDS: every senpi shutdown reason leaves the session resumable, so there\n * is deliberately no `session_closed` terminal reason.\n * - A provider/turn error is never terminal.\n */\n\nimport type {\n\tCronEntry,\n\tDeliveryId,\n\tDynamicCronEntry,\n\tEffectiveInterval,\n\tEpochMs,\n\tFixedCronEntry,\n\tLoopEndReason,\n\tLoopEntryFields,\n\tLoopId,\n\tLoopPayload,\n\tLoopState,\n\tPendingWakeup,\n\tRequestedInterval,\n\tWakeupId,\n} from \"./types.ts\";\nimport { LOOP_STATE_VERSION } from \"./types.ts\";\n\n/** Absolute lifetime of a loop, measured from `createdAt`. */\nexport const LOOP_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** Hard cap on simultaneously active loops per session. */\nexport const MAX_ACTIVE_LOOPS = 5;\n\n/** Fallback wakeup length when a dynamic iteration forgets to reschedule. */\nexport const DEFAULT_KEEPALIVE_SECONDS = 1200;\nexport const MIN_KEEPALIVE_SECONDS = 60;\nexport const MAX_KEEPALIVE_SECONDS = 3600;\nexport const KEEPALIVE_SECONDS_ENV = \"SENPI_LOOP_KEEPALIVE_SECONDS\";\n\n/** Dispatched-tick budget per loop. */\nexport const DEFAULT_MAX_TICKS = 2000;\nexport const MIN_MAX_TICKS = 1;\nexport const MAX_TICKS_ENV = \"SENPI_LOOP_MAX_TICKS\";\n\nexport interface LoopClock {\n\tnow(): EpochMs;\n}\n\n/**\n * Owns the ONE live timeout per loop. Implementations must apply the generation-counter\n * discipline of `cache-keepalive/index.ts`: re-arming a key replaces its previous\n * callback, and a cancelled callback must never run.\n */\nexport interface LoopTimerPort {\n\tarm(key: string, dueAt: EpochMs, callback: () => void): void;\n\tcancel(key: string): void;\n\tcancelAll(): void;\n}\n\nexport interface LoopIdFactory {\n\tloopId(): LoopId;\n\twakeupId(): WakeupId;\n\tdeliveryId(): DeliveryId;\n}\n\nexport interface LoopSchedulerDeps {\n\treadonly sessionId: string;\n\treadonly clock: LoopClock;\n\treadonly timers: LoopTimerPort;\n\treadonly ids: LoopIdFactory;\n\t/** Defaults to `process.env`; injected so tests never mutate the real environment. */\n\treadonly env?: Record<string, string | undefined>;\n\t/** Previously persisted state, e.g. on session start. */\n\treadonly initialState?: LoopState;\n\t/** Called after every state revision so the caller can persist it. */\n\treadonly onStateChanged?: (state: LoopState) => void;\n\t/**\n\t * Invoked when an armed timer fires. The owner is expected to run the due decision AND its\n\t * side effects (persist + dispatch). Without it the scheduler only advances its own state,\n\t * which would deliver a loop's first tick and then silently never recur.\n\t */\n\treadonly onFire?: (loopId: LoopId) => void;\n}\n\nexport interface CreateFixedRequest {\n\treadonly originalArgs: string;\n\treadonly reentryPrompt: string;\n\treadonly payload: LoopPayload;\n\treadonly requestedInterval: RequestedInterval;\n\treadonly effectiveInterval: EffectiveInterval;\n\treadonly cronExpression: string;\n\treadonly intervalMs: number;\n}\n\nexport interface CreateDynamicRequest {\n\treadonly originalArgs: string;\n\treadonly reentryPrompt: string;\n\treadonly payload: LoopPayload;\n}\n\n/** One dispatchable delivery. The caller turns this into a message; ticks never steer. */\nexport interface LoopTick {\n\treadonly loopId: LoopId;\n\treadonly deliveryId: DeliveryId;\n\t/** Occurrence this delivery represents; equal to the `now` it was decided at. */\n\treadonly scheduledForAt: EpochMs;\n\treadonly deliverAs: \"followUp\";\n\t/** True when this delivery drains a coalesced or recovered occurrence. */\n\treadonly coalesced: boolean;\n}\n\nexport type CreateRejectionReason = \"active_loop_cap\";\n\nexport type CreateResult =\n\t| { readonly ok: true; readonly loopId: LoopId; readonly supersededLoopId?: LoopId }\n\t| {\n\t\t\treadonly ok: false;\n\t\t\treadonly reason: CreateRejectionReason;\n\t\t\treadonly cap: number;\n\t\t\treadonly activeLoopIds: readonly LoopId[];\n\t\t\treadonly message: string;\n\t };\n\nexport type DueResult =\n\t| { readonly action: \"dispatch\"; readonly tick: LoopTick }\n\t| { readonly action: \"coalesce\" }\n\t| { readonly action: \"expire\" };\n\nexport type TickOutcome = \"completed\" | \"error\" | \"retrying\";\n\nexport interface TickSettledInput {\n\treadonly loopId: LoopId;\n\treadonly deliveryId: DeliveryId;\n\treadonly outcome: TickOutcome;\n}\n\nexport type SettledResult =\n\t| { readonly action: \"dispatch\"; readonly tick: LoopTick }\n\t| { readonly action: \"coalesce\" }\n\t| { readonly action: \"expire\" }\n\t| { readonly action: \"idle\" }\n\t| { readonly action: \"in_progress\" }\n\t| { readonly action: \"ended\"; readonly endReason: LoopEndReason }\n\t| { readonly action: \"ignored\" };\n\nexport interface ScheduleWakeupInput {\n\treadonly loopId: LoopId;\n\t/** Already clamped to `[60, 3600]` by the tool executor. */\n\treadonly delaySeconds: number;\n\treadonly requestedDelaySeconds: number;\n\treadonly reason: string;\n\treadonly prompt: string;\n\treadonly noop: boolean;\n}\n\nexport type ScheduleWakeupResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly wakeupId: WakeupId;\n\t\t\treadonly replacedWakeupId?: WakeupId;\n\t\t\treadonly dueAt: EpochMs;\n\t\t\treadonly noopStreak: number;\n\t }\n\t| { readonly ok: false; readonly reason: \"unknown_loop\" | \"not_dynamic\" | \"ended\" | \"expired\" };\n\nexport type KeepaliveResult =\n\t| {\n\t\t\treadonly action: \"keepalive_armed\";\n\t\t\treadonly wakeupId: WakeupId;\n\t\t\treadonly delaySeconds: number;\n\t\t\treadonly dueAt: EpochMs;\n\t }\n\t| { readonly action: \"ended\"; readonly endReason: \"keepalive_exhausted\" | \"expired\" }\n\t| { readonly action: \"ignored\" };\n\nexport interface AbortResult {\n\treadonly action: \"paused\" | \"ignored\";\n}\n\nexport interface TargetedResult {\n\treadonly affectedLoopIds: readonly LoopId[];\n}\n\nexport interface ShutdownResult {\n\treadonly suspendedLoopIds: readonly LoopId[];\n}\n\nexport interface RestoreOptions {\n\t/**\n\t * Loops the caller knows the user paused explicitly, which must stay paused instead of\n\t * being re-armed. `phase: \"suspended\"` alone cannot express this: shutdown suspends too,\n\t * and the persisted state has no field distinguishing the two. Omit it and every\n\t * suspended loop is treated as shutdown-suspended and re-armed, per the plan's resume\n\t * rule.\n\t */\n\treadonly userPausedLoopIds?: readonly LoopId[];\n}\n\nexport interface RestoreResult {\n\treadonly recoveryTicks: readonly LoopTick[];\n\treadonly expiredLoopIds: readonly LoopId[];\n\treadonly rearmedLoopIds: readonly LoopId[];\n\t/** Loops left paused because {@link RestoreOptions.userPausedLoopIds} named them. */\n\treadonly stillPausedLoopIds: readonly LoopId[];\n}\n\nexport interface LoopScheduler {\n\tgetState(): LoopState;\n\t/** State revisions applied so far; lets callers assert atomic multi-entry mutations. */\n\treadonly mutationCount: number;\n\t/** Effective dispatched-tick budget after the env override and the minimum of 1. */\n\treadonly maxTicks: number;\n\t/** Effective keepalive fallback length in seconds after clamping. */\n\treadonly keepaliveSeconds: number;\n\t/** Delivery id of the queued/running tick of a loop, when one is in flight. */\n\tcurrentDeliveryId(loopId: LoopId): DeliveryId | undefined;\n\tcreateFixed(request: CreateFixedRequest): CreateResult;\n\tcreateDynamic(request: CreateDynamicRequest): CreateResult;\n\tonDue(loopId: LoopId, nowMs: EpochMs, sessionBusy: boolean): DueResult;\n\tonTickSettled(input: TickSettledInput): SettledResult;\n\tonScheduleWakeup(request: ScheduleWakeupInput): ScheduleWakeupResult;\n\tonTurnEndedWithoutSchedule(loopId: LoopId): KeepaliveResult;\n\tonUserAbort(loopId: LoopId): AbortResult;\n\tpause(target: LoopId | \"all\"): TargetedResult;\n\tresume(target: LoopId | \"all\"): TargetedResult;\n\tstop(target: LoopId | \"all\", detail: string): TargetedResult;\n\tonShutdown(): ShutdownResult;\n\trestore(nowMs: EpochMs, options?: RestoreOptions): RestoreResult;\n}\n\n/** Phases in which a loop already has a delivery in flight. */\nfunction isInFlight(entry: CronEntry): boolean {\n\treturn entry.phase === \"queued\" || entry.phase === \"running\";\n}\n\nfunction isActive(entry: CronEntry): boolean {\n\treturn entry.phase !== \"ended\";\n}\n\n/** Armed means the loop wants its timer running: not ended, not paused. */\nfunction isArmable(entry: CronEntry): boolean {\n\treturn entry.phase !== \"ended\" && entry.phase !== \"suspended\";\n}\n\n/**\n * THE coalescing rule: the next occurrence is always derived from the CURRENT time, never\n * from the stale due time. That is what makes every occurrence missed during laptop sleep,\n * a long turn, or a pause collapse into exactly one catch-up tick.\n */\nfunction nextOccurrenceAfter(nowMs: EpochMs, intervalMs: number): EpochMs {\n\treturn nowMs + intervalMs;\n}\n\ntype ActivePhase = Exclude<CronEntry[\"phase\"], \"ended\">;\n\n/** Fields any loop can carry into a non-terminal transition, regardless of kind. */\ntype SharedPatch = Partial<Omit<LoopEntryFields, \"id\" | \"createdAt\" | \"expiresAt\">>;\n\n/**\n * Rebuilds an entry in a non-terminal phase, dropping any terminal fields. Spreading an\n * `ended` entry and overriding `phase` would leave `endedAt`/`endReason` behind, which the\n * `LoopLifecycle` union forbids and the store parser rejects, so every non-terminal\n * transition goes through here.\n */\nfunction withPhase(entry: CronEntry, phase: ActivePhase, patch: SharedPatch = {}): CronEntry {\n\tconst { endedAt: _endedAt, endReason: _endReason, endDetail: _endDetail, ...rest } = entry;\n\treturn rest.kind === \"fixed\"\n\t\t? { ...rest, ...patch, kind: \"fixed\", phase }\n\t\t: { ...rest, ...patch, kind: \"dynamic\", phase };\n}\n\n/** Non-terminal transition of a fixed loop, including its recomputed next occurrence. */\nfunction fixedWithPhase(\n\tentry: FixedCronEntry,\n\tphase: ActivePhase,\n\tpatch: SharedPatch & { nextFireAt?: EpochMs } = {},\n): FixedCronEntry {\n\tconst { endedAt: _endedAt, endReason: _endReason, endDetail: _endDetail, ...rest } = entry;\n\treturn { ...rest, ...patch, kind: \"fixed\", phase };\n}\n\n/** Non-terminal transition of a dynamic loop, including its wakeup and keepalive fields. */\nfunction dynamicWithPhase(\n\tentry: DynamicCronEntry,\n\tphase: ActivePhase,\n\tpatch: SharedPatch & { pendingWakeup?: PendingWakeup | null; keepaliveCredit?: 0 | 1 } = {},\n): DynamicCronEntry {\n\tconst { endedAt: _endedAt, endReason: _endReason, endDetail: _endDetail, ...rest } = entry;\n\treturn { ...rest, ...patch, kind: \"dynamic\", phase };\n}\n\nfunction readIntEnv(\n\tenv: Record<string, string | undefined>,\n\tname: string,\n\tfallback: number,\n\tmin: number,\n\tmax: number,\n): number {\n\tconst raw = env[name];\n\tif (raw === undefined || raw.trim().length === 0) return fallback;\n\tconst parsed = Number(raw.trim());\n\tif (!Number.isInteger(parsed)) return fallback;\n\treturn Math.min(max, Math.max(min, parsed));\n}\n\nexport function createLoopScheduler(deps: LoopSchedulerDeps): LoopScheduler {\n\tconst env = deps.env ?? process.env;\n\tconst keepaliveSeconds = readIntEnv(\n\t\tenv,\n\t\tKEEPALIVE_SECONDS_ENV,\n\t\tDEFAULT_KEEPALIVE_SECONDS,\n\t\tMIN_KEEPALIVE_SECONDS,\n\t\tMAX_KEEPALIVE_SECONDS,\n\t);\n\tconst maxTicks = readIntEnv(env, MAX_TICKS_ENV, DEFAULT_MAX_TICKS, MIN_MAX_TICKS, Number.MAX_SAFE_INTEGER);\n\n\tlet state: LoopState = deps.initialState ?? {\n\t\tversion: LOOP_STATE_VERSION,\n\t\tsessionId: deps.sessionId,\n\t\tentries: {},\n\t\tactiveDynamicId: null,\n\t\tupdatedAt: 0,\n\t};\n\tlet mutationCount = 0;\n\n\t/** In-memory only: which delivery each loop currently has in flight. */\n\tconst inFlightDeliveries = new Map<LoopId, DeliveryId>();\n\n\t/**\n\t * Applies one atomic state revision. Every transition in this module funnels through\n\t * here, so a multi-entry change (e.g. supersede + create) is a single revision and the\n\t * persistence callback observes no intermediate state.\n\t */\n\tfunction commit(update: (entries: Record<LoopId, CronEntry>) => LoopId | null | undefined): void {\n\t\tconst entries: Record<LoopId, CronEntry> = { ...state.entries };\n\t\tconst nextDynamicId = update(entries);\n\t\tstate = {\n\t\t\tversion: LOOP_STATE_VERSION,\n\t\t\tsessionId: state.sessionId,\n\t\t\tentries,\n\t\t\tactiveDynamicId: nextDynamicId === undefined ? state.activeDynamicId : nextDynamicId,\n\t\t\tupdatedAt: deps.clock.now(),\n\t\t};\n\t\tmutationCount += 1;\n\t\tdeps.onStateChanged?.(state);\n\t}\n\n\tfunction entryOf(loopId: LoopId): CronEntry | undefined {\n\t\treturn state.entries[loopId];\n\t}\n\n\tfunction activeIds(): LoopId[] {\n\t\treturn Object.values(state.entries)\n\t\t\t.filter(isActive)\n\t\t\t.map((entry) => entry.id);\n\t}\n\n\t/** Cancels the timer and clears any pending wakeup, then marks the loop ended. */\n\tfunction endEntry(\n\t\tentries: Record<LoopId, CronEntry>,\n\t\tentry: CronEntry,\n\t\tnowMs: EpochMs,\n\t\tendReason: LoopEndReason,\n\t\tendDetail?: string,\n\t): void {\n\t\tdeps.timers.cancel(entry.id);\n\t\tinFlightDeliveries.delete(entry.id);\n\t\tconst terminal = {\n\t\t\tphase: \"ended\" as const,\n\t\t\tendedAt: nowMs,\n\t\t\tendReason,\n\t\t\t...(endDetail === undefined ? {} : { endDetail }),\n\t\t};\n\t\tentries[entry.id] =\n\t\t\tentry.kind === \"fixed\" ? { ...entry, ...terminal } : { ...entry, ...terminal, pendingWakeup: null };\n\t}\n\n\t/**\n\t * Re-arms a loop's single timer, or ends it as `expired` when the next occurrence would\n\t * land at or after expiry. Returns the reason the loop ended, if it did.\n\t */\n\tfunction armEntry(\n\t\tentries: Record<LoopId, CronEntry>,\n\t\tentry: CronEntry,\n\t\tnowMs: EpochMs,\n\t\tonFire: (loopId: LoopId) => void,\n\t): LoopEndReason | undefined {\n\t\tif (nowMs >= entry.expiresAt) {\n\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\treturn \"expired\";\n\t\t}\n\t\tconst dueAt = entry.kind === \"fixed\" ? entry.nextFireAt : entry.pendingWakeup?.dueAt;\n\t\tif (dueAt === undefined) {\n\t\t\tdeps.timers.cancel(entry.id);\n\t\t\treturn undefined;\n\t\t}\n\t\tif (dueAt >= entry.expiresAt) {\n\t\t\t// A tick may never fire at or after expiry, so retire the loop now rather than\n\t\t\t// arming a timer that could only produce an illegal delivery.\n\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\treturn \"expired\";\n\t\t}\n\t\tdeps.timers.arm(entry.id, dueAt, () => onFire(entry.id));\n\t\treturn undefined;\n\t}\n\n\t/** Fire callback the timer port invokes; the extension re-enters through `onDue`. */\n\tlet fireHandler: (loopId: LoopId) => void = () => {};\n\tfunction onFire(loopId: LoopId): void {\n\t\tfireHandler(loopId);\n\t}\n\n\tfunction baseFields(nowMs: EpochMs, id: LoopId, request: CreateFixedRequest | CreateDynamicRequest) {\n\t\treturn {\n\t\t\tid,\n\t\t\toriginalArgs: request.originalArgs,\n\t\t\treentryPrompt: request.reentryPrompt,\n\t\t\tpayload: request.payload,\n\t\t\tcreatedAt: nowMs,\n\t\t\tlastFiredAt: null,\n\t\t\texpiresAt: nowMs + LOOP_EXPIRY_MS,\n\t\t\tlastScheduledForAt: null,\n\t\t\tcoalescedFirePending: false,\n\t\t\tqueuedForAt: null,\n\t\t\tnoopStreak: 0,\n\t\t\ttickCount: 0,\n\t\t\tsentinelDelivery: {\n\t\t\t\tautonomousPreambleDelivered: false,\n\t\t\t\tlastLoopFileDelivered: null,\n\t\t\t\tforceFullDelivery: false,\n\t\t\t},\n\t\t\twakeSources: [],\n\t\t};\n\t}\n\n\tfunction capRejection(): CreateResult {\n\t\tconst active = activeIds();\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"active_loop_cap\",\n\t\t\tcap: MAX_ACTIVE_LOOPS,\n\t\t\tactiveLoopIds: active,\n\t\t\tmessage:\n\t\t\t\t`At most ${MAX_ACTIVE_LOOPS} loops can be active at once. Active: ${active.join(\", \")}. ` +\n\t\t\t\t\"Stop one with `/loop stop <id>` or `/loop stop all` first.\",\n\t\t};\n\t}\n\n\tfunction createFixed(request: CreateFixedRequest): CreateResult {\n\t\tif (activeIds().length >= MAX_ACTIVE_LOOPS) return capRejection();\n\t\tconst nowMs = deps.clock.now();\n\t\tconst id = deps.ids.loopId();\n\t\tcommit((entries) => {\n\t\t\tconst entry: FixedCronEntry = {\n\t\t\t\t...baseFields(nowMs, id, request),\n\t\t\t\tkind: \"fixed\",\n\t\t\t\tphase: \"waiting\",\n\t\t\t\trequestedInterval: request.requestedInterval,\n\t\t\t\teffectiveInterval: request.effectiveInterval,\n\t\t\t\tcronExpression: request.cronExpression,\n\t\t\t\tnextFireAt: nextOccurrenceAfter(nowMs, request.intervalMs),\n\t\t\t\tintervalMs: request.intervalMs,\n\t\t\t};\n\t\t\tentries[id] = entry;\n\t\t\t// Arm before the caller dispatches the immediate first tick, so a failing first\n\t\t\t// turn cannot silently lose the recurring schedule.\n\t\t\tarmEntry(entries, entry, nowMs, onFire);\n\t\t\treturn undefined;\n\t\t});\n\t\treturn { ok: true, loopId: id };\n\t}\n\n\tfunction createDynamic(request: CreateDynamicRequest): CreateResult {\n\t\tconst existingDynamicId = state.activeDynamicId;\n\t\tconst existing = existingDynamicId === null ? undefined : entryOf(existingDynamicId);\n\t\tconst supersedes = existing !== undefined && isActive(existing);\n\t\t// A superseded loop frees its slot, so it must not count against the cap.\n\t\tconst activeAfterSupersede = activeIds().filter((id) => !(supersedes && id === existingDynamicId));\n\t\tif (activeAfterSupersede.length >= MAX_ACTIVE_LOOPS) return capRejection();\n\n\t\tconst nowMs = deps.clock.now();\n\t\tconst id = deps.ids.loopId();\n\t\tcommit((entries) => {\n\t\t\tif (supersedes && existing !== undefined) {\n\t\t\t\tendEntry(entries, existing, nowMs, \"stopped\", \"superseded\");\n\t\t\t}\n\t\t\tconst entry: DynamicCronEntry = {\n\t\t\t\t...baseFields(nowMs, id, request),\n\t\t\t\tkind: \"dynamic\",\n\t\t\t\tphase: \"waiting\",\n\t\t\t\tpendingWakeup: null,\n\t\t\t\tkeepaliveCredit: 1,\n\t\t\t};\n\t\t\tentries[id] = entry;\n\t\t\treturn id;\n\t\t});\n\t\treturn supersedes && existingDynamicId !== null\n\t\t\t? { ok: true, loopId: id, supersededLoopId: existingDynamicId }\n\t\t\t: { ok: true, loopId: id };\n\t}\n\n\tfunction onDue(loopId: LoopId, nowMs: EpochMs, sessionBusy: boolean): DueResult {\n\t\tconst entry = entryOf(loopId);\n\t\tif (entry === undefined) return { action: \"coalesce\" };\n\n\t\tif (nowMs >= entry.expiresAt) {\n\t\t\tif (entry.phase === \"ended\") return { action: \"coalesce\" };\n\t\t\tcommit((entries) => {\n\t\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { action: \"expire\" };\n\t\t}\n\t\tif (entry.phase === \"ended\" || entry.phase === \"suspended\") return { action: \"coalesce\" };\n\t\tif (entry.tickCount >= maxTicks) return { action: \"coalesce\" };\n\n\t\tif (isInFlight(entry)) {\n\t\t\t// Invariant: one queued/running tick per loop. Extra occurrences collapse into a\n\t\t\t// single pending bit and the schedule still moves forward from `now`.\n\t\t\tcommit((entries) => {\n\t\t\t\tconst coalesced =\n\t\t\t\t\tentry.kind === \"fixed\"\n\t\t\t\t\t\t? fixedWithPhase(entry, entry.phase, {\n\t\t\t\t\t\t\t\tcoalescedFirePending: true,\n\t\t\t\t\t\t\t\tnextFireAt: nextOccurrenceAfter(nowMs, entry.intervalMs),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: dynamicWithPhase(entry, entry.phase, { coalescedFirePending: true });\n\t\t\t\tentries[loopId] = coalesced;\n\t\t\t\tarmEntry(entries, coalesced, nowMs, onFire);\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { action: \"coalesce\" };\n\t\t}\n\n\t\tconst deliveryId = deps.ids.deliveryId();\n\t\tconst tick: LoopTick = {\n\t\t\tloopId,\n\t\t\tdeliveryId,\n\t\t\tscheduledForAt: nowMs,\n\t\t\tdeliverAs: \"followUp\",\n\t\t\tcoalesced: entry.coalescedFirePending,\n\t\t};\n\t\tlet expired = false;\n\t\tcommit((entries) => {\n\t\t\tconst dispatched = {\n\t\t\t\tlastFiredAt: nowMs,\n\t\t\t\tlastScheduledForAt: nowMs,\n\t\t\t\tqueuedForAt: nowMs,\n\t\t\t\tcoalescedFirePending: false,\n\t\t\t\ttickCount: entry.tickCount + 1,\n\t\t\t};\n\t\t\tconst phase = sessionBusy ? (\"queued\" as const) : (\"running\" as const);\n\t\t\tconst next =\n\t\t\t\tentry.kind === \"fixed\"\n\t\t\t\t\t? fixedWithPhase(entry, phase, {\n\t\t\t\t\t\t\t...dispatched,\n\t\t\t\t\t\t\tnextFireAt: nextOccurrenceAfter(nowMs, entry.intervalMs),\n\t\t\t\t\t\t})\n\t\t\t\t\t: dynamicWithPhase(entry, phase, { ...dispatched, pendingWakeup: null });\n\t\t\tentries[loopId] = next;\n\t\t\t// A dynamic loop has no schedule of its own; its next timer comes from\n\t\t\t// schedule_wakeup or the keepalive fallback.\n\t\t\tif (next.kind === \"fixed\") {\n\t\t\t\texpired = armEntry(entries, next, nowMs, onFire) === \"expired\";\n\t\t\t} else {\n\t\t\t\tdeps.timers.cancel(loopId);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\t\tif (!expired) inFlightDeliveries.set(loopId, deliveryId);\n\t\treturn { action: \"dispatch\", tick };\n\t}\n\n\tfunction onTickSettled(input: TickSettledInput): SettledResult {\n\t\tconst entry = entryOf(input.loopId);\n\t\tif (entry === undefined) return { action: \"ignored\" };\n\t\tif (input.outcome === \"retrying\") return { action: \"in_progress\" };\n\t\tif (inFlightDeliveries.get(input.loopId) !== input.deliveryId) return { action: \"ignored\" };\n\t\tinFlightDeliveries.delete(input.loopId);\n\t\tif (entry.phase === \"ended\") return { action: \"ignored\" };\n\t\t// A user abort already paused this loop; settling must not resurrect it.\n\t\tif (entry.phase === \"suspended\") return { action: \"idle\" };\n\n\t\tconst nowMs = deps.clock.now();\n\n\t\tif (nowMs >= entry.expiresAt) {\n\t\t\tcommit((entries) => {\n\t\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { action: \"ended\", endReason: \"expired\" };\n\t\t}\n\n\t\tif (entry.tickCount >= maxTicks) {\n\t\t\t// The budget bounds spend, not wall clock: expiry alone would let a `/loop 1m`\n\t\t\t// job reach thousands of model turns.\n\t\t\tcommit((entries) => {\n\t\t\t\tendEntry(entries, entry, nowMs, \"tick_budget_exhausted\");\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { action: \"ended\", endReason: \"tick_budget_exhausted\" };\n\t\t}\n\n\t\tif (entry.coalescedFirePending) {\n\t\t\t// Exactly one delivery drains the coalesced occurrence, however many were missed.\n\t\t\tcommit((entries) => {\n\t\t\t\tentries[input.loopId] = withPhase(entry, \"waiting\", { coalescedFirePending: false, queuedForAt: null });\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn onDue(input.loopId, nowMs, false);\n\t\t}\n\n\t\tlet expired = false;\n\t\tcommit((entries) => {\n\t\t\tconst settled = withPhase(entry, \"waiting\", { queuedForAt: null });\n\t\t\tentries[input.loopId] = settled;\n\t\t\tif (settled.kind === \"fixed\") {\n\t\t\t\texpired = armEntry(entries, settled, nowMs, onFire) === \"expired\";\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\t\treturn expired ? { action: \"ended\", endReason: \"expired\" } : { action: \"idle\" };\n\t}\n\n\tfunction onScheduleWakeup(request: ScheduleWakeupInput): ScheduleWakeupResult {\n\t\tconst entry = entryOf(request.loopId);\n\t\tif (entry === undefined) return { ok: false, reason: \"unknown_loop\" };\n\t\tif (entry.kind !== \"dynamic\") return { ok: false, reason: \"not_dynamic\" };\n\t\tif (entry.phase === \"ended\") return { ok: false, reason: \"ended\" };\n\n\t\tconst nowMs = deps.clock.now();\n\t\tif (nowMs >= entry.expiresAt) {\n\t\t\tcommit((entries) => {\n\t\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { ok: false, reason: \"expired\" };\n\t\t}\n\n\t\tconst wakeupId = deps.ids.wakeupId();\n\t\tconst replacedWakeupId = entry.pendingWakeup?.id;\n\t\t// Expiry is absolute: a new wakeup never extends `expiresAt`.\n\t\tconst dueAt = nowMs + request.delaySeconds * 1000;\n\t\tconst wakeup: PendingWakeup = {\n\t\t\tid: wakeupId,\n\t\t\tloopId: entry.id,\n\t\t\tkind: \"dynamic\",\n\t\t\tsource: \"model\",\n\t\t\trequestedDelaySeconds: request.requestedDelaySeconds,\n\t\t\tdelaySeconds: request.delaySeconds,\n\t\t\tdueAt,\n\t\t\treason: request.reason,\n\t\t\tprompt: request.prompt,\n\t\t\tnoop: request.noop,\n\t\t\tcreatedAt: nowMs,\n\t\t};\n\t\tconst noopStreak = request.noop ? entry.noopStreak + 1 : 0;\n\t\tcommit((entries) => {\n\t\t\tconst scheduled = dynamicWithPhase(entry, \"waiting\", {\n\t\t\t\tqueuedForAt: null,\n\t\t\t\tpendingWakeup: wakeup,\n\t\t\t\t// A successful model schedule restores the one-omission recovery budget.\n\t\t\t\tkeepaliveCredit: 1,\n\t\t\t\tnoopStreak,\n\t\t\t});\n\t\t\tentries[entry.id] = scheduled;\n\t\t\tarmEntry(entries, scheduled, nowMs, onFire);\n\t\t\treturn undefined;\n\t\t});\n\t\treturn replacedWakeupId === undefined\n\t\t\t? { ok: true, wakeupId, dueAt, noopStreak }\n\t\t\t: { ok: true, wakeupId, replacedWakeupId, dueAt, noopStreak };\n\t}\n\n\tfunction onTurnEndedWithoutSchedule(loopId: LoopId): KeepaliveResult {\n\t\tconst entry = entryOf(loopId);\n\t\tif (entry === undefined || entry.kind !== \"dynamic\") return { action: \"ignored\" };\n\t\t// Fixed loops re-arm from their own schedule, and a paused or ended loop has no\n\t\t// liveness to protect. A user abort lands here as `suspended`, which is exactly why\n\t\t// an abort can never be converted into a keepalive omission.\n\t\tif (entry.phase === \"ended\" || entry.phase === \"suspended\") return { action: \"ignored\" };\n\n\t\tconst nowMs = deps.clock.now();\n\t\tif (nowMs >= entry.expiresAt) {\n\t\t\tcommit((entries) => {\n\t\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { action: \"ended\", endReason: \"expired\" };\n\t\t}\n\n\t\tif (entry.keepaliveCredit === 0) {\n\t\t\tcommit((entries) => {\n\t\t\t\tendEntry(entries, entry, nowMs, \"keepalive_exhausted\");\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\treturn { action: \"ended\", endReason: \"keepalive_exhausted\" };\n\t\t}\n\n\t\tconst wakeupId = deps.ids.wakeupId();\n\t\tconst dueAt = nowMs + keepaliveSeconds * 1000;\n\t\tconst wakeup: PendingWakeup = {\n\t\t\tid: wakeupId,\n\t\t\tloopId: entry.id,\n\t\t\tkind: \"dynamic\",\n\t\t\tsource: \"keepalive\",\n\t\t\trequestedDelaySeconds: keepaliveSeconds,\n\t\t\tdelaySeconds: keepaliveSeconds,\n\t\t\tdueAt,\n\t\t\treason: \"keepalive armed (model did not reschedule)\",\n\t\t\tprompt: entry.reentryPrompt,\n\t\t\tnoop: false,\n\t\t\tcreatedAt: nowMs,\n\t\t};\n\t\tlet expired = false;\n\t\tcommit((entries) => {\n\t\t\tconst armed = dynamicWithPhase(entry, \"waiting\", {\n\t\t\t\tqueuedForAt: null,\n\t\t\t\tpendingWakeup: wakeup,\n\t\t\t\tkeepaliveCredit: 0,\n\t\t\t});\n\t\t\tentries[entry.id] = armed;\n\t\t\texpired = armEntry(entries, armed, nowMs, onFire) === \"expired\";\n\t\t\treturn undefined;\n\t\t});\n\t\treturn expired\n\t\t\t? { action: \"ended\", endReason: \"expired\" }\n\t\t\t: { action: \"keepalive_armed\", wakeupId, delaySeconds: keepaliveSeconds, dueAt };\n\t}\n\n\tfunction pauseEntries(ids: readonly LoopId[]): LoopId[] {\n\t\tconst affected: LoopId[] = [];\n\t\tconst pausable = ids\n\t\t\t.map((id) => entryOf(id))\n\t\t\t.filter((entry): entry is CronEntry => entry !== undefined && isArmable(entry));\n\t\tif (pausable.length === 0) return affected;\n\t\tcommit((entries) => {\n\t\t\tfor (const entry of pausable) {\n\t\t\t\tdeps.timers.cancel(entry.id);\n\t\t\t\tinFlightDeliveries.delete(entry.id);\n\t\t\t\tentries[entry.id] = withPhase(entry, \"suspended\", { queuedForAt: null });\n\t\t\t\taffected.push(entry.id);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\t\treturn affected;\n\t}\n\n\tfunction resolveTargets(target: LoopId | \"all\"): LoopId[] {\n\t\tif (target !== \"all\") return [target];\n\t\treturn Object.values(state.entries).map((entry) => entry.id);\n\t}\n\n\tfunction pause(target: LoopId | \"all\"): TargetedResult {\n\t\treturn { affectedLoopIds: pauseEntries(resolveTargets(target)) };\n\t}\n\n\tfunction onUserAbort(loopId: LoopId): AbortResult {\n\t\t// Esc is also how a user interrupts to steer, so an abort PAUSES the loop; the\n\t\t// schedule survives for `/loop resume` and is never a terminal state.\n\t\tconst affected = pauseEntries([loopId]);\n\t\treturn { action: affected.length > 0 ? \"paused\" : \"ignored\" };\n\t}\n\n\tfunction resume(target: LoopId | \"all\"): TargetedResult {\n\t\tconst nowMs = deps.clock.now();\n\t\tconst resumable = resolveTargets(target)\n\t\t\t.map((id) => entryOf(id))\n\t\t\t.filter((entry): entry is CronEntry => entry !== undefined && entry.phase === \"suspended\");\n\t\tif (resumable.length === 0) return { affectedLoopIds: [] };\n\t\tconst affected: LoopId[] = [];\n\t\tcommit((entries) => {\n\t\t\tfor (const entry of resumable) {\n\t\t\t\t// The occurrence missed while paused is not replayed: the next fire is\n\t\t\t\t// recomputed from now, exactly as after a sleep.\n\t\t\t\tconst rearmed =\n\t\t\t\t\tentry.kind === \"fixed\"\n\t\t\t\t\t\t? fixedWithPhase(entry, \"waiting\", {\n\t\t\t\t\t\t\t\tqueuedForAt: null,\n\t\t\t\t\t\t\t\tnextFireAt: nextOccurrenceAfter(nowMs, entry.intervalMs),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: dynamicWithPhase(entry, \"waiting\", {\n\t\t\t\t\t\t\t\tqueuedForAt: null,\n\t\t\t\t\t\t\t\tpendingWakeup:\n\t\t\t\t\t\t\t\t\tentry.pendingWakeup === null\n\t\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t\t: { ...entry.pendingWakeup, dueAt: Math.max(entry.pendingWakeup.dueAt, nowMs) },\n\t\t\t\t\t\t\t});\n\t\t\t\tentries[entry.id] = rearmed;\n\t\t\t\tarmEntry(entries, rearmed, nowMs, onFire);\n\t\t\t\taffected.push(entry.id);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\t\treturn { affectedLoopIds: affected };\n\t}\n\n\tfunction stop(target: LoopId | \"all\", detail: string): TargetedResult {\n\t\tconst nowMs = deps.clock.now();\n\t\tconst stoppable = resolveTargets(target)\n\t\t\t.map((id) => entryOf(id))\n\t\t\t.filter((entry): entry is CronEntry => entry !== undefined && isActive(entry));\n\t\tif (stoppable.length === 0) return { affectedLoopIds: [] };\n\t\tconst affected: LoopId[] = [];\n\t\tlet clearDynamic = false;\n\t\tcommit((entries) => {\n\t\t\tfor (const entry of stoppable) {\n\t\t\t\tendEntry(entries, entry, nowMs, \"stopped\", detail);\n\t\t\t\tif (entry.id === state.activeDynamicId) clearDynamic = true;\n\t\t\t\taffected.push(entry.id);\n\t\t\t}\n\t\t\treturn clearDynamic ? null : undefined;\n\t\t});\n\t\treturn { affectedLoopIds: affected };\n\t}\n\n\tfunction onShutdown(): ShutdownResult {\n\t\t// Every senpi shutdown reason (quit|reload|new|resume|fork) leaves the session\n\t\t// resumable, so shutdown SUSPENDS and emits no terminal reason.\n\t\tconst suspendable = Object.values(state.entries).filter(isArmable);\n\t\tdeps.timers.cancelAll();\n\t\tif (suspendable.length === 0) return { suspendedLoopIds: [] };\n\t\tconst suspended: LoopId[] = [];\n\t\tcommit((entries) => {\n\t\t\tfor (const entry of suspendable) {\n\t\t\t\tentries[entry.id] = withPhase(entry, \"suspended\", { queuedForAt: null });\n\t\t\t\tsuspended.push(entry.id);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\t\tinFlightDeliveries.clear();\n\t\treturn { suspendedLoopIds: suspended };\n\t}\n\n\tfunction restore(nowMs: EpochMs, options: RestoreOptions = {}): RestoreResult {\n\t\tconst recoveryTicks: LoopTick[] = [];\n\t\tconst expiredLoopIds: LoopId[] = [];\n\t\tconst rearmedLoopIds: LoopId[] = [];\n\t\tconst stillPausedLoopIds: LoopId[] = [];\n\t\tconst userPaused = new Set(options.userPausedLoopIds ?? []);\n\t\t// A delivery this process still has in flight is NOT a crash remnant; only state\n\t\t// whose owning process is gone needs recovering.\n\t\tconst liveDeliveries = new Set(inFlightDeliveries.keys());\n\t\tdeps.timers.cancelAll();\n\n\t\tcommit((entries) => {\n\t\t\tfor (const entry of Object.values(state.entries)) {\n\t\t\t\tif (entry.phase === \"ended\") continue;\n\t\t\t\t// A delivery this process still owns is in flight, not a crash remnant: leave it\n\t\t\t\t// alone so restore can never duplicate a tick that is already running.\n\t\t\t\tif (liveDeliveries.has(entry.id)) continue;\n\t\t\t\tif (userPaused.has(entry.id)) {\n\t\t\t\t\t// An explicit `/loop pause` outlives a restart: no timer, no recovery tick.\n\t\t\t\t\tentries[entry.id] = withPhase(entry, \"suspended\", { queuedForAt: null });\n\t\t\t\t\tstillPausedLoopIds.push(entry.id);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (nowMs >= entry.expiresAt) {\n\t\t\t\t\tendEntry(entries, entry, nowMs, \"expired\");\n\t\t\t\t\texpiredLoopIds.push(entry.id);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// A crashed `starting`/`queued`/`running` remnant, a pending coalesced fire, and\n\t\t\t\t// an overdue occurrence all collapse into ONE recovery delivery per job.\n\t\t\t\tconst dueAt = entry.kind === \"fixed\" ? entry.nextFireAt : entry.pendingWakeup?.dueAt;\n\t\t\t\tconst overdue = dueAt !== undefined && dueAt <= nowMs;\n\t\t\t\tconst crashRemnant = isInFlight(entry) || entry.phase === \"starting\";\n\t\t\t\tconst needsRecovery = (overdue || crashRemnant || entry.coalescedFirePending) && entry.tickCount < maxTicks;\n\n\t\t\t\tconst recovered =\n\t\t\t\t\tentry.kind === \"fixed\"\n\t\t\t\t\t\t? fixedWithPhase(entry, \"waiting\", {\n\t\t\t\t\t\t\t\tqueuedForAt: null,\n\t\t\t\t\t\t\t\tcoalescedFirePending: false,\n\t\t\t\t\t\t\t\tnextFireAt: nextOccurrenceAfter(nowMs, entry.intervalMs),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: dynamicWithPhase(entry, \"waiting\", {\n\t\t\t\t\t\t\t\tqueuedForAt: null,\n\t\t\t\t\t\t\t\tcoalescedFirePending: false,\n\t\t\t\t\t\t\t\t// The one-shot wakeup is consumed by the recovery delivery.\n\t\t\t\t\t\t\t\tpendingWakeup: overdue ? null : entry.pendingWakeup,\n\t\t\t\t\t\t\t});\n\t\t\t\tentries[entry.id] = recovered;\n\t\t\t\tconst ended = armEntry(entries, recovered, nowMs, onFire);\n\t\t\t\tif (ended === \"expired\") {\n\t\t\t\t\texpiredLoopIds.push(entry.id);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (needsRecovery) {\n\t\t\t\t\tconst deliveryId = deps.ids.deliveryId();\n\t\t\t\t\trecoveryTicks.push({\n\t\t\t\t\t\tloopId: entry.id,\n\t\t\t\t\t\tdeliveryId,\n\t\t\t\t\t\tscheduledForAt: nowMs,\n\t\t\t\t\t\tdeliverAs: \"followUp\",\n\t\t\t\t\t\tcoalesced: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\trearmedLoopIds.push(entry.id);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\n\t\t// Recovery deliveries count as dispatched ticks and occupy the single in-flight slot.\n\t\t// One revision for all of them, so a persisting caller never sees a partial recovery.\n\t\tif (recoveryTicks.length > 0) {\n\t\t\tcommit((entries) => {\n\t\t\t\tfor (const tick of recoveryTicks) {\n\t\t\t\t\tconst entry = entries[tick.loopId];\n\t\t\t\t\tif (entry === undefined || entry.phase === \"ended\") continue;\n\t\t\t\t\tentries[tick.loopId] = withPhase(entry, \"queued\", {\n\t\t\t\t\t\tlastFiredAt: nowMs,\n\t\t\t\t\t\tlastScheduledForAt: nowMs,\n\t\t\t\t\t\tqueuedForAt: nowMs,\n\t\t\t\t\t\ttickCount: entry.tickCount + 1,\n\t\t\t\t\t});\n\t\t\t\t\tinFlightDeliveries.set(tick.loopId, tick.deliveryId);\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t}\n\n\t\treturn { recoveryTicks, expiredLoopIds, rearmedLoopIds, stillPausedLoopIds };\n\t}\n\n\tconst scheduler: LoopScheduler = {\n\t\tgetState: () => state,\n\t\tget mutationCount() {\n\t\t\treturn mutationCount;\n\t\t},\n\t\tmaxTicks,\n\t\tkeepaliveSeconds,\n\t\tcurrentDeliveryId: (loopId) => inFlightDeliveries.get(loopId),\n\t\tcreateFixed,\n\t\tcreateDynamic,\n\t\tonDue,\n\t\tonTickSettled,\n\t\tonScheduleWakeup,\n\t\tonTurnEndedWithoutSchedule,\n\t\tonUserAbort,\n\t\tpause,\n\t\tresume,\n\t\tstop,\n\t\tonShutdown,\n\t\trestore,\n\t};\n\n\t// The timer port fires with a loop id; the due decision is always re-derived from the\n\t// clock so a stale callback cannot dispatch a tick the state machine would refuse.\n\t// When an owner supplies `onFire` it performs the whole due step (persist + dispatch), so\n\t// calling `onDue` here as well would consume the occurrence and drop the delivery.\n\tfireHandler = (loopId) => {\n\t\tconst owner = deps.onFire;\n\t\tif (owner !== undefined) {\n\t\t\towner(loopId);\n\t\t\treturn;\n\t\t}\n\t\tscheduler.onDue(loopId, deps.clock.now(), false);\n\t};\n\n\treturn scheduler;\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import type { LoopState } from "./types.ts";
2
+ export declare const LOOP_STATUS_KEY = "loop";
3
+ export declare const LOOP_STATUS_TICK_INTERVAL_MS = 1000;
4
+ export type LoopStatusRender = (key: string, text: string | undefined) => void;
5
+ export interface LoopStatusTickerOptions {
6
+ readonly render: LoopStatusRender;
7
+ readonly now?: () => number;
8
+ }
9
+ export declare function formatLoopStatus(state: LoopState, nowMs: number): string | undefined;
10
+ export declare function formatNoopFold(noopStreak: number): string;
11
+ export declare class LoopStatusTicker {
12
+ private readonly render;
13
+ private readonly now;
14
+ private timeoutId;
15
+ private state;
16
+ private lastRendered;
17
+ constructor(options: LoopStatusTickerOptions);
18
+ get running(): boolean;
19
+ sync(state: LoopState): void;
20
+ dispose(): void;
21
+ private scheduleNext;
22
+ private tick;
23
+ }
24
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/loop/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;AAE/E,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAkCD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA4BpF;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,YAAY,CAAqB;gBAE7B,OAAO,EAAE,uBAAuB;IAK5C,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAO5B,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,IAAI;CAOZ"}
@@ -0,0 +1,113 @@
1
+ export const LOOP_STATUS_KEY = "loop";
2
+ export const LOOP_STATUS_TICK_INTERVAL_MS = 1000;
3
+ function isArmed(entry) {
4
+ return entry.phase !== "ended";
5
+ }
6
+ function formatDuration(ms) {
7
+ const totalSeconds = Math.max(0, Math.floor(ms / 1000));
8
+ if (totalSeconds < 60) {
9
+ return `${totalSeconds}s`;
10
+ }
11
+ const minutes = Math.floor(totalSeconds / 60);
12
+ if (minutes < 60) {
13
+ const seconds = totalSeconds % 60;
14
+ return seconds > 0 ? `${minutes}m${seconds}s` : `${minutes}m`;
15
+ }
16
+ const hours = Math.floor(minutes / 60);
17
+ if (hours < 24) {
18
+ const mins = minutes % 60;
19
+ return mins > 0 ? `${hours}h${mins}m` : `${hours}h`;
20
+ }
21
+ const days = Math.floor(hours / 24);
22
+ const hrs = hours % 24;
23
+ return hrs > 0 ? `${days}d${hrs}h` : `${days}d`;
24
+ }
25
+ function nextDueAt(entry) {
26
+ if (entry.phase === "suspended" || entry.phase === "ended")
27
+ return undefined;
28
+ if (entry.kind === "fixed") {
29
+ return entry.nextFireAt;
30
+ }
31
+ return entry.pendingWakeup?.dueAt;
32
+ }
33
+ export function formatLoopStatus(state, nowMs) {
34
+ const armed = Object.values(state.entries).filter(isArmed);
35
+ if (armed.length === 0) {
36
+ return undefined;
37
+ }
38
+ const paused = armed.some((entry) => entry.phase === "suspended");
39
+ if (paused) {
40
+ return "Loop paused - /loop resume or /loop stop";
41
+ }
42
+ let nearest;
43
+ for (const entry of armed) {
44
+ if (entry.phase === "suspended")
45
+ continue;
46
+ const dueAt = nextDueAt(entry);
47
+ if (dueAt === undefined)
48
+ continue;
49
+ if (nearest === undefined || dueAt < nearest.dueAt) {
50
+ nearest = { entry, dueAt };
51
+ }
52
+ }
53
+ if (nearest === undefined) {
54
+ return "Loop active - /loop stop";
55
+ }
56
+ const remainingMs = Math.max(0, nearest.dueAt - nowMs);
57
+ const mode = nearest.entry.kind === "fixed" ? "fixed" : "dynamic";
58
+ return `Loop (${mode}): next in ${formatDuration(remainingMs)} - /loop stop`;
59
+ }
60
+ export function formatNoopFold(noopStreak) {
61
+ if (noopStreak < 2) {
62
+ return "";
63
+ }
64
+ return `↻ ${noopStreak} loop ticks with no actionable change`;
65
+ }
66
+ export class LoopStatusTicker {
67
+ constructor(options) {
68
+ this.render = options.render;
69
+ this.now = options.now ?? Date.now;
70
+ }
71
+ get running() {
72
+ return this.timeoutId !== undefined;
73
+ }
74
+ sync(state) {
75
+ this.state = state;
76
+ this.lastRendered = undefined;
77
+ this.tick();
78
+ this.scheduleNext();
79
+ }
80
+ dispose() {
81
+ if (this.timeoutId !== undefined) {
82
+ clearTimeout(this.timeoutId);
83
+ this.timeoutId = undefined;
84
+ }
85
+ this.state = undefined;
86
+ this.lastRendered = undefined;
87
+ this.render(LOOP_STATUS_KEY, undefined);
88
+ }
89
+ scheduleNext() {
90
+ if (this.timeoutId !== undefined) {
91
+ clearTimeout(this.timeoutId);
92
+ }
93
+ const handle = setTimeout(() => {
94
+ this.timeoutId = undefined;
95
+ this.tick();
96
+ if (this.state !== undefined) {
97
+ this.scheduleNext();
98
+ }
99
+ }, LOOP_STATUS_TICK_INTERVAL_MS);
100
+ handle.unref();
101
+ this.timeoutId = handle;
102
+ }
103
+ tick() {
104
+ if (this.state === undefined)
105
+ return;
106
+ const text = formatLoopStatus(this.state, this.now());
107
+ if (text === this.lastRendered)
108
+ return;
109
+ this.lastRendered = text;
110
+ this.render(LOOP_STATUS_KEY, text);
111
+ }
112
+ }
113
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/loop/status.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CronEntry, LoopState } from \"./types.ts\";\n\nexport const LOOP_STATUS_KEY = \"loop\";\nexport const LOOP_STATUS_TICK_INTERVAL_MS = 1000;\n\nexport type LoopStatusRender = (key: string, text: string | undefined) => void;\n\nexport interface LoopStatusTickerOptions {\n\treadonly render: LoopStatusRender;\n\treadonly now?: () => number;\n}\n\nfunction isArmed(entry: CronEntry): boolean {\n\treturn entry.phase !== \"ended\";\n}\n\nfunction formatDuration(ms: number): string {\n\tconst totalSeconds = Math.max(0, Math.floor(ms / 1000));\n\tif (totalSeconds < 60) {\n\t\treturn `${totalSeconds}s`;\n\t}\n\tconst minutes = Math.floor(totalSeconds / 60);\n\tif (minutes < 60) {\n\t\tconst seconds = totalSeconds % 60;\n\t\treturn seconds > 0 ? `${minutes}m${seconds}s` : `${minutes}m`;\n\t}\n\tconst hours = Math.floor(minutes / 60);\n\tif (hours < 24) {\n\t\tconst mins = minutes % 60;\n\t\treturn mins > 0 ? `${hours}h${mins}m` : `${hours}h`;\n\t}\n\tconst days = Math.floor(hours / 24);\n\tconst hrs = hours % 24;\n\treturn hrs > 0 ? `${days}d${hrs}h` : `${days}d`;\n}\n\nfunction nextDueAt(entry: CronEntry): number | undefined {\n\tif (entry.phase === \"suspended\" || entry.phase === \"ended\") return undefined;\n\tif (entry.kind === \"fixed\") {\n\t\treturn entry.nextFireAt;\n\t}\n\treturn entry.pendingWakeup?.dueAt;\n}\n\nexport function formatLoopStatus(state: LoopState, nowMs: number): string | undefined {\n\tconst armed = Object.values(state.entries).filter(isArmed);\n\tif (armed.length === 0) {\n\t\treturn undefined;\n\t}\n\n\tconst paused = armed.some((entry) => entry.phase === \"suspended\");\n\tif (paused) {\n\t\treturn \"Loop paused - /loop resume or /loop stop\";\n\t}\n\n\tlet nearest: { entry: CronEntry; dueAt: number } | undefined;\n\tfor (const entry of armed) {\n\t\tif (entry.phase === \"suspended\") continue;\n\t\tconst dueAt = nextDueAt(entry);\n\t\tif (dueAt === undefined) continue;\n\t\tif (nearest === undefined || dueAt < nearest.dueAt) {\n\t\t\tnearest = { entry, dueAt };\n\t\t}\n\t}\n\n\tif (nearest === undefined) {\n\t\treturn \"Loop active - /loop stop\";\n\t}\n\n\tconst remainingMs = Math.max(0, nearest.dueAt - nowMs);\n\tconst mode = nearest.entry.kind === \"fixed\" ? \"fixed\" : \"dynamic\";\n\treturn `Loop (${mode}): next in ${formatDuration(remainingMs)} - /loop stop`;\n}\n\nexport function formatNoopFold(noopStreak: number): string {\n\tif (noopStreak < 2) {\n\t\treturn \"\";\n\t}\n\treturn `↻ ${noopStreak} loop ticks with no actionable change`;\n}\n\nexport class LoopStatusTicker {\n\tprivate readonly render: LoopStatusRender;\n\tprivate readonly now: () => number;\n\tprivate timeoutId: NodeJS.Timeout | undefined;\n\tprivate state: LoopState | undefined;\n\tprivate lastRendered: string | undefined;\n\n\tconstructor(options: LoopStatusTickerOptions) {\n\t\tthis.render = options.render;\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tget running(): boolean {\n\t\treturn this.timeoutId !== undefined;\n\t}\n\n\tsync(state: LoopState): void {\n\t\tthis.state = state;\n\t\tthis.lastRendered = undefined;\n\t\tthis.tick();\n\t\tthis.scheduleNext();\n\t}\n\n\tdispose(): void {\n\t\tif (this.timeoutId !== undefined) {\n\t\t\tclearTimeout(this.timeoutId);\n\t\t\tthis.timeoutId = undefined;\n\t\t}\n\t\tthis.state = undefined;\n\t\tthis.lastRendered = undefined;\n\t\tthis.render(LOOP_STATUS_KEY, undefined);\n\t}\n\n\tprivate scheduleNext(): void {\n\t\tif (this.timeoutId !== undefined) {\n\t\t\tclearTimeout(this.timeoutId);\n\t\t}\n\t\tconst handle = setTimeout(() => {\n\t\t\tthis.timeoutId = undefined;\n\t\t\tthis.tick();\n\t\t\tif (this.state !== undefined) {\n\t\t\t\tthis.scheduleNext();\n\t\t\t}\n\t\t}, LOOP_STATUS_TICK_INTERVAL_MS);\n\t\thandle.unref();\n\t\tthis.timeoutId = handle;\n\t}\n\n\tprivate tick(): void {\n\t\tif (this.state === undefined) return;\n\t\tconst text = formatLoopStatus(this.state, this.now());\n\t\tif (text === this.lastRendered) return;\n\t\tthis.lastRendered = text;\n\t\tthis.render(LOOP_STATUS_KEY, text);\n\t}\n}\n"]}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Atomic, versioned, per-session sidecar store for `/loop` state.
3
+ *
4
+ * Mirrors the goal store's persistence discipline (temp file + rename, per-file mutation
5
+ * serialization, strict versioned parsing) because scheduler state must never be half
6
+ * written or silently reset: a corrupt file arms nothing and surfaces a typed error so
7
+ * the extension can end affected loops with `error` instead of guessing.
8
+ *
9
+ * Session custom entries are deliberately NOT the authoritative store: they are branch
10
+ * nodes, so a globally scanned "latest" entry can come from an abandoned branch, while
11
+ * loop schedules are session-scoped.
12
+ */
13
+ import { type LoopState, type LoopStoreRef } from "./types.ts";
14
+ export declare class InvalidLoopStoreError extends Error {
15
+ constructor(message: string, options?: {
16
+ cause?: unknown;
17
+ });
18
+ }
19
+ export declare class UnsupportedLoopStoreVersionError extends Error {
20
+ constructor(message: string);
21
+ }
22
+ /** Mutation callback. May be async; its result becomes the next persisted state. */
23
+ export type LoopStateMutation = (current: LoopState) => LoopState | Promise<LoopState>;
24
+ export declare function encodedSessionId(ref: LoopStoreRef): string;
25
+ export declare function loopStateFilePath(ref: LoopStoreRef): string;
26
+ export declare function emptyLoopState(sessionId: string): LoopState;
27
+ /**
28
+ * Reads persisted state, or null when this session has never persisted any loop.
29
+ * Throws {@link InvalidLoopStoreError} / {@link UnsupportedLoopStoreVersionError} on
30
+ * unusable state so callers fail closed rather than resetting a user's schedule.
31
+ */
32
+ export declare function readLoopState(ref: LoopStoreRef): Promise<LoopState | null>;
33
+ /** Like {@link readLoopState}, but returns an empty state when nothing is persisted. */
34
+ export declare function loadLoopState(ref: LoopStoreRef): Promise<LoopState>;
35
+ /**
36
+ * Last successfully loaded or written state for this ref, for synchronous consumers
37
+ * (status line, tick attribution). Undefined until the store has been touched.
38
+ */
39
+ export declare function snapshotLoopState(ref: LoopStoreRef): LoopState | undefined;
40
+ /**
41
+ * Serializes read-modify-write cycles through a per-file promise tail so command,
42
+ * timer, tool, and lifecycle writes cannot interleave and lose an update.
43
+ */
44
+ export declare function mutateLoopState(ref: LoopStoreRef, mutation: LoopStateMutation): Promise<LoopState>;
45
+ /** Persists a complete state atomically. Prefer {@link mutateLoopState} for updates. */
46
+ export declare function writeLoopState(ref: LoopStoreRef, state: LoopState): Promise<void>;
47
+ /** Drops cached snapshots; used when a session ends or tests reset global state. */
48
+ export declare function clearLoopStateSnapshot(ref: LoopStoreRef): void;
49
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/loop/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAqBN,KAAK,SAAS,EACd,KAAK,YAAY,EAQjB,MAAM,YAAY,CAAC;AAEpB,qBAAa,qBAAsB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAI1D;AAED,qBAAa,gCAAiC,SAAQ,KAAK;gBAC9C,OAAO,EAAE,MAAM;CAI3B;AAED,oFAAoF;AACpF,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,SAAS,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAKvF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAE3D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAE3D;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAWhF;AAED,wFAAwF;AACxF,wBAAsB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAEzE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,CAE1E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAOlG;AAED,wFAAwF;AACxF,wBAAsB,cAAc,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAE9D"}