saeeol 1.1.1 → 1.2.1

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 (379) hide show
  1. package/package.json +14 -14
  2. package/script/build.ts +1 -1
  3. package/src/addons/addon-analytics.ts +1 -1
  4. package/src/cli/cmd/tui/routes/session/suggest.tsx +1 -1
  5. package/src/cli/logo.ts +1 -1
  6. package/src/cli/ui.ts +1 -1
  7. package/src/config/config-loader.ts +1 -1
  8. package/src/config/config-schema.ts +1 -1
  9. package/src/config/config.ts +1 -1
  10. package/src/config/markdown.ts +1 -1
  11. package/src/index.ts +2 -2
  12. package/src/lsp/lsp.ts +1 -1
  13. package/src/lsp/server-web.ts +1 -1
  14. package/src/mcp/oauth-callback.ts +1 -1
  15. package/src/{saeeol → overlay}/encoding.ts +1 -1
  16. package/src/{saeeol → overlay}/text-stream.ts +1 -1
  17. package/src/{saeeol → overlay}/tool/encoded-io.ts +1 -1
  18. package/src/patch/patch-apply.ts +1 -1
  19. package/src/patch/patch-parse.ts +1 -1
  20. package/src/session/compaction-helpers.ts +1 -169
  21. package/src/session/compaction.ts +1 -712
  22. package/src/session/core/compaction/compaction-helpers.ts +169 -0
  23. package/src/session/core/compaction/compaction.ts +712 -0
  24. package/src/session/core/compaction/overflow.ts +28 -0
  25. package/src/session/core/instruction.ts +234 -0
  26. package/src/session/core/llm.ts +504 -0
  27. package/src/session/core/network.ts +392 -0
  28. package/src/session/core/processor.ts +731 -0
  29. package/src/session/core/projectors.ts +139 -0
  30. package/src/session/core/resolve-tools.ts +241 -0
  31. package/src/session/core/retry.ts +149 -0
  32. package/src/session/core/revert.ts +173 -0
  33. package/src/session/core/run-state.ts +110 -0
  34. package/src/session/core/schema.ts +35 -0
  35. package/src/session/core/session-types.ts +160 -0
  36. package/src/session/core/session.sql.ts +124 -0
  37. package/src/session/core/session.ts +948 -0
  38. package/src/session/core/shell-exec.ts +205 -0
  39. package/src/session/core/status.ts +100 -0
  40. package/src/session/core/subtask.ts +268 -0
  41. package/src/session/core/summary.ts +173 -0
  42. package/src/session/core/system.ts +114 -0
  43. package/src/session/core/todo.ts +86 -0
  44. package/src/session/core/user-part.ts +293 -0
  45. package/src/session/instruction.ts +1 -234
  46. package/src/session/llm.ts +1 -504
  47. package/src/session/message/message-errors.ts +83 -0
  48. package/src/session/message/message-parts.ts +89 -0
  49. package/src/session/message/message-query.ts +107 -0
  50. package/src/session/message/message-transform.ts +156 -0
  51. package/src/session/message/message-types.ts +68 -0
  52. package/src/session/message/message-v2.ts +73 -0
  53. package/src/session/message/message.ts +192 -0
  54. package/src/session/message-errors.ts +1 -83
  55. package/src/session/message-parts.ts +1 -89
  56. package/src/session/message-query.ts +1 -107
  57. package/src/session/message-transform.ts +1 -156
  58. package/src/session/message-types.ts +1 -68
  59. package/src/session/message-v2.ts +1 -73
  60. package/src/session/message.ts +1 -192
  61. package/src/session/network.ts +1 -392
  62. package/src/session/overflow.ts +1 -28
  63. package/src/session/processor.ts +1 -731
  64. package/src/session/projectors.ts +2 -139
  65. package/src/session/prompt/prompt-command.ts +93 -0
  66. package/src/session/prompt/prompt-loop.ts +299 -0
  67. package/src/session/prompt/prompt-model.ts +44 -0
  68. package/src/session/prompt/prompt-reminders.ts +120 -0
  69. package/src/session/prompt/prompt-resolve.ts +42 -0
  70. package/src/session/prompt/prompt-schemas.ts +128 -0
  71. package/src/session/prompt/prompt-title.ts +55 -0
  72. package/src/session/prompt/prompt-types.ts +47 -0
  73. package/src/session/prompt/prompt-user-msg.ts +80 -0
  74. package/src/session/prompt/prompt.ts +211 -0
  75. package/src/session/prompt-command.ts +1 -93
  76. package/src/session/prompt-loop.ts +1 -299
  77. package/src/session/prompt-model.ts +1 -44
  78. package/src/session/prompt-reminders.ts +1 -120
  79. package/src/session/prompt-resolve.ts +1 -42
  80. package/src/session/prompt-schemas.ts +1 -128
  81. package/src/session/prompt-title.ts +1 -55
  82. package/src/session/prompt-types.ts +1 -47
  83. package/src/session/prompt-user-msg.ts +1 -80
  84. package/src/session/prompt.ts +1 -211
  85. package/src/session/resolve-tools.ts +1 -241
  86. package/src/session/retry.ts +1 -149
  87. package/src/session/revert.ts +1 -173
  88. package/src/session/run-state.ts +1 -110
  89. package/src/session/schema.ts +1 -35
  90. package/src/session/session-types.ts +1 -160
  91. package/src/session/session.sql.ts +1 -124
  92. package/src/session/session.ts +1 -948
  93. package/src/session/shell-exec.ts +1 -205
  94. package/src/session/status.ts +1 -100
  95. package/src/session/subtask.ts +1 -268
  96. package/src/session/summary.ts +1 -173
  97. package/src/session/system.ts +1 -114
  98. package/src/session/todo.ts +1 -86
  99. package/src/session/user-part.ts +1 -293
  100. package/src/skill/index.ts +1 -1
  101. package/src/suggestion/index.ts +1 -1
  102. package/src/tool/apply_patch.ts +2 -2
  103. package/src/tool/edit.ts +2 -2
  104. package/src/tool/read.ts +2 -2
  105. package/src/tool/recall.ts +1 -1
  106. package/src/tool/registry.ts +2 -2
  107. package/src/tool/suggest.ts +1 -1
  108. package/src/tool/task.ts +3 -3
  109. package/src/tool/todo.ts +1 -1
  110. package/src/tool/write.ts +2 -2
  111. package/test/lsp/index.test.ts +1 -1
  112. package/test/saeeol/agent-manager-tool.test.ts +1 -1
  113. package/test/saeeol/ask-agent-permissions.test.ts +1 -1
  114. package/test/saeeol/bash-hierarchy.test.ts +1 -1
  115. package/test/saeeol/builtin-skills.test.ts +1 -1
  116. package/test/saeeol/cli/dev-setup.test.ts +1 -1
  117. package/test/saeeol/cli/roll-call.test.ts +1 -1
  118. package/test/saeeol/cli-run-auto-helper.test.ts +1 -1
  119. package/test/saeeol/codex-auth-refresh.test.ts +1 -1
  120. package/test/saeeol/commit-message/generate.test.ts +1 -1
  121. package/test/saeeol/commit-message/git-context.test.ts +1 -1
  122. package/test/saeeol/commit-message-windows.test.ts +1 -1
  123. package/test/saeeol/compaction-payload-recovery.test.ts +1 -1
  124. package/test/saeeol/config/config.test.ts +1 -1
  125. package/test/saeeol/config-injector.test.ts +1 -1
  126. package/test/saeeol/config-validation.test.ts +1 -1
  127. package/test/saeeol/cost-propagation.test.ts +1 -1
  128. package/test/saeeol/custom-provider-delete.test.ts +1 -1
  129. package/test/saeeol/diff-full.test.ts +1 -1
  130. package/test/saeeol/encoding.test.ts +1 -1
  131. package/test/saeeol/enhance-prompt.test.ts +1 -1
  132. package/test/saeeol/ensure-plan-dir.test.ts +1 -1
  133. package/test/saeeol/errors.test.ts +1 -1
  134. package/test/saeeol/help.test.ts +3 -3
  135. package/test/saeeol/ignore-migrator.test.ts +1 -1
  136. package/test/saeeol/indexing-auth.test.ts +1 -1
  137. package/test/saeeol/indexing-feature.test.ts +1 -1
  138. package/test/saeeol/indexing-label.test.ts +1 -1
  139. package/test/saeeol/indexing-startup.test.ts +1 -1
  140. package/test/saeeol/indexing-worktree.test.ts +1 -1
  141. package/test/saeeol/lancedb-runtime.test.ts +9 -9
  142. package/test/saeeol/logo.test.ts +1 -1
  143. package/test/saeeol/lsp-typescript-lightweight.test.ts +2 -2
  144. package/test/saeeol/mcp-migrator.test.ts +1 -1
  145. package/test/saeeol/model-info-panel-utils.test.ts +1 -1
  146. package/test/saeeol/modes-migrator.test.ts +1 -1
  147. package/test/saeeol/paths.test.ts +1 -1
  148. package/test/saeeol/permission/config-paths.test.ts +2 -2
  149. package/test/saeeol/permission/external-directory-allow.test.ts +1 -1
  150. package/test/saeeol/plan-exit-detection.test.ts +1 -1
  151. package/test/saeeol/plan-followup.test.ts +2 -2
  152. package/test/saeeol/project-id.test.ts +1 -1
  153. package/test/saeeol/question-dismiss-all.test.ts +1 -1
  154. package/test/saeeol/rules-migrator.test.ts +1 -1
  155. package/test/saeeol/semantic-search.test.ts +2 -2
  156. package/test/saeeol/session/platform-attribution.test.ts +1 -1
  157. package/test/saeeol/session-compaction-cap.test.ts +2 -2
  158. package/test/saeeol/session-compaction-chunks.test.ts +1 -1
  159. package/test/saeeol/session-compaction-safety.test.ts +1 -1
  160. package/test/saeeol/session-import-service.test.ts +1 -1
  161. package/test/saeeol/session-processor-empty-tool-calls.test.ts +1 -1
  162. package/test/saeeol/session-processor-review-telemetry.test.ts +1 -1
  163. package/test/saeeol/session-prompt-queue.test.ts +1 -1
  164. package/test/saeeol/sessions/remote-sender.test.ts +1 -1
  165. package/test/saeeol/snapshot-track-timeout.test.ts +1 -1
  166. package/test/saeeol/suggestion/auto-dismiss.test.ts +2 -2
  167. package/test/saeeol/suggestion/suggestion.test.ts +1 -1
  168. package/test/saeeol/suggestion/tool.test.ts +2 -2
  169. package/test/saeeol/system-prompt.test.ts +1 -1
  170. package/test/saeeol/todo-view.test.ts +1 -1
  171. package/test/saeeol/tool-registry-indexing.test.ts +3 -3
  172. package/test/saeeol/tui-diff.test.ts +1 -1
  173. package/test/saeeol/tui-sync.test.ts +1 -1
  174. package/test/saeeol/util/url.test.ts +1 -1
  175. package/test/saeeol/workflows-migrator.test.ts +1 -1
  176. package/test/saeeol/worktree-diff-summary.test.ts +1 -1
  177. package/tsconfig.json +1 -1
  178. /package/src/{saeeol → overlay}/agent/agent-remove.ts +0 -0
  179. /package/src/{saeeol → overlay}/agent/index.ts +0 -0
  180. /package/src/{saeeol → overlay}/agent/patch-agents.ts +0 -0
  181. /package/src/{saeeol → overlay}/agent/permissions.ts +0 -0
  182. /package/src/{saeeol → overlay}/agent-manager/event.ts +0 -0
  183. /package/src/{saeeol → overlay}/bash-hierarchy.ts +0 -0
  184. /package/src/{saeeol → overlay}/bell.ts +0 -0
  185. /package/src/{saeeol → overlay}/bootstrap.ts +0 -0
  186. /package/src/{saeeol → overlay}/claw/autocomplete-popup.tsx +0 -0
  187. /package/src/{saeeol → overlay}/claw/autocomplete-ref.ts +0 -0
  188. /package/src/{saeeol → overlay}/claw/autocomplete-types.ts +0 -0
  189. /package/src/{saeeol → overlay}/claw/autocomplete.tsx +0 -0
  190. /package/src/{saeeol → overlay}/claw/chat-client.ts +0 -0
  191. /package/src/{saeeol → overlay}/claw/chat.tsx +0 -0
  192. /package/src/{saeeol → overlay}/claw/client-events.ts +0 -0
  193. /package/src/{saeeol → overlay}/claw/client-helpers.ts +0 -0
  194. /package/src/{saeeol → overlay}/claw/client.ts +0 -0
  195. /package/src/{saeeol → overlay}/claw/dialog-conversation-list.tsx +0 -0
  196. /package/src/{saeeol → overlay}/claw/event-service-client-core.ts +0 -0
  197. /package/src/{saeeol → overlay}/claw/event-service-client-impl.ts +0 -0
  198. /package/src/{saeeol → overlay}/claw/event-service-client.ts +0 -0
  199. /package/src/{saeeol → overlay}/claw/hooks.ts +0 -0
  200. /package/src/{saeeol → overlay}/claw/sidebar.tsx +0 -0
  201. /package/src/{saeeol → overlay}/claw/types.ts +0 -0
  202. /package/src/{saeeol → overlay}/claw/view.tsx +0 -0
  203. /package/src/{saeeol → overlay}/cli/cmd/roll-call-call.ts +0 -0
  204. /package/src/{saeeol → overlay}/cli/cmd/roll-call-format.ts +0 -0
  205. /package/src/{saeeol → overlay}/cli/cmd/roll-call.ts +0 -0
  206. /package/src/{saeeol → overlay}/cli/cmd/tui/app.tsx +0 -0
  207. /package/src/{saeeol → overlay}/cli/cmd/tui/component/dialog-provider.tsx +0 -0
  208. /package/src/{saeeol → overlay}/cli/cmd/tui/feedback.ts +0 -0
  209. /package/src/{saeeol → overlay}/cli/cmd/tui/util/terminal.ts +0 -0
  210. /package/src/{saeeol → overlay}/cli/dev-setup-utils.ts +0 -0
  211. /package/src/{saeeol → overlay}/cli/dev-setup.ts +0 -0
  212. /package/src/{saeeol → overlay}/cli/heap-snapshot.ts +0 -0
  213. /package/src/{saeeol → overlay}/cli/logo.ts +0 -0
  214. /package/src/{saeeol → overlay}/cli/run-auto.ts +0 -0
  215. /package/src/{saeeol → overlay}/cli/saeeol-logo.ts +0 -0
  216. /package/src/{saeeol → overlay}/cloud-session.ts +0 -0
  217. /package/src/{saeeol → overlay}/commands-index.ts +0 -0
  218. /package/src/{saeeol → overlay}/commands.ts +0 -0
  219. /package/src/{saeeol → overlay}/commands.tsx +0 -0
  220. /package/src/{saeeol → overlay}/commit-message/generate.ts +0 -0
  221. /package/src/{saeeol → overlay}/commit-message/git-context.ts +0 -0
  222. /package/src/{saeeol → overlay}/commit-message/index.ts +0 -0
  223. /package/src/{saeeol → overlay}/commit-message/types.ts +0 -0
  224. /package/src/{saeeol → overlay}/components/dialog-auto-method.tsx +0 -0
  225. /package/src/{saeeol → overlay}/components/dialog-claw-setup.tsx +0 -0
  226. /package/src/{saeeol → overlay}/components/dialog-claw-upgrade.tsx +0 -0
  227. /package/src/{saeeol → overlay}/components/dialog-indexing-helpers.ts +0 -0
  228. /package/src/{saeeol → overlay}/components/dialog-indexing.tsx +0 -0
  229. /package/src/{saeeol → overlay}/components/dialog-notifications.tsx +0 -0
  230. /package/src/{saeeol → overlay}/components/dialog-organization.tsx +0 -0
  231. /package/src/{saeeol → overlay}/components/dialog-profile.tsx +0 -0
  232. /package/src/{saeeol → overlay}/components/dialog-provider-settings.tsx +0 -0
  233. /package/src/{saeeol → overlay}/components/dialog-team-select.tsx +0 -0
  234. /package/src/{saeeol → overlay}/components/dialog-tuning.tsx +0 -0
  235. /package/src/{saeeol → overlay}/components/dialog-vector-store.tsx +0 -0
  236. /package/src/{saeeol → overlay}/components/error-display.tsx +0 -0
  237. /package/src/{saeeol → overlay}/components/model-info-panel-utils.ts +0 -0
  238. /package/src/{saeeol → overlay}/components/model-info-panel.tsx +0 -0
  239. /package/src/{saeeol → overlay}/components/news.tsx +0 -0
  240. /package/src/{saeeol → overlay}/components/notification-banner.tsx +0 -0
  241. /package/src/{saeeol → overlay}/components/session-indexing.tsx +0 -0
  242. /package/src/{saeeol → overlay}/components/tips.tsx +0 -0
  243. /package/src/{saeeol → overlay}/config/config-core.ts +0 -0
  244. /package/src/{saeeol → overlay}/config/config-helpers.ts +0 -0
  245. /package/src/{saeeol → overlay}/config/config-legacy.ts +0 -0
  246. /package/src/{saeeol → overlay}/config/config.ts +0 -0
  247. /package/src/{saeeol → overlay}/config/default-plugins.ts +0 -0
  248. /package/src/{saeeol → overlay}/config/markdown.ts +0 -0
  249. /package/src/{saeeol → overlay}/config-injector.ts +0 -0
  250. /package/src/{saeeol → overlay}/config-validation.ts +0 -0
  251. /package/src/{saeeol → overlay}/const.ts +0 -0
  252. /package/src/{saeeol → overlay}/cost-tracker/format.ts +0 -0
  253. /package/src/{saeeol → overlay}/cost-tracker/index.ts +0 -0
  254. /package/src/{saeeol → overlay}/cost-tracker/state.ts +0 -0
  255. /package/src/{saeeol → overlay}/cost-tracker/types.ts +0 -0
  256. /package/src/{saeeol → overlay}/docs/migration.md +0 -0
  257. /package/src/{saeeol → overlay}/docs/rules-migration.md +0 -0
  258. /package/src/{saeeol → overlay}/editor-context.ts +0 -0
  259. /package/src/{saeeol → overlay}/enhance-prompt.ts +0 -0
  260. /package/src/{saeeol → overlay}/errors.ts +0 -0
  261. /package/src/{saeeol → overlay}/generate-cli-docs.ts +0 -0
  262. /package/src/{saeeol → overlay}/help-command.ts +0 -0
  263. /package/src/{saeeol → overlay}/help.ts +0 -0
  264. /package/src/{saeeol → overlay}/i18n/index.ts +0 -0
  265. /package/src/{saeeol → overlay}/ignore-migrator.ts +0 -0
  266. /package/src/{saeeol → overlay}/index.ts +0 -0
  267. /package/src/{saeeol → overlay}/indexing-auth.ts +0 -0
  268. /package/src/{saeeol → overlay}/indexing-feature.ts +0 -0
  269. /package/src/{saeeol → overlay}/indexing-helpers.ts +0 -0
  270. /package/src/{saeeol → overlay}/indexing-label.ts +0 -0
  271. /package/src/{saeeol → overlay}/indexing-state.ts +0 -0
  272. /package/src/{saeeol → overlay}/indexing-types.ts +0 -0
  273. /package/src/{saeeol → overlay}/indexing.ts +0 -0
  274. /package/src/{saeeol → overlay}/lancedb.ts +0 -0
  275. /package/src/{saeeol → overlay}/mcp-migrator.ts +0 -0
  276. /package/src/{saeeol → overlay}/mcp-oauth-callback.ts +0 -0
  277. /package/src/{saeeol → overlay}/memory/age.ts +0 -0
  278. /package/src/{saeeol → overlay}/memory/index.ts +0 -0
  279. /package/src/{saeeol → overlay}/memory/paths.ts +0 -0
  280. /package/src/{saeeol → overlay}/memory/scan.ts +0 -0
  281. /package/src/{saeeol → overlay}/memory/types.ts +0 -0
  282. /package/src/{saeeol → overlay}/model-match.ts +0 -0
  283. /package/src/{saeeol → overlay}/modes-migrator.ts +0 -0
  284. /package/src/{saeeol → overlay}/paths.ts +0 -0
  285. /package/src/{saeeol → overlay}/permission/config-paths.ts +0 -0
  286. /package/src/{saeeol → overlay}/permission/drain.ts +0 -0
  287. /package/src/{saeeol → overlay}/permission/external-directory.ts +0 -0
  288. /package/src/{saeeol → overlay}/permission/read.ts +0 -0
  289. /package/src/{saeeol → overlay}/permission/routes.ts +0 -0
  290. /package/src/{saeeol → overlay}/permission/rule.ts +0 -0
  291. /package/src/{saeeol → overlay}/plan-followup-handover.ts +0 -0
  292. /package/src/{saeeol → overlay}/plan-followup-runtime.ts +0 -0
  293. /package/src/{saeeol → overlay}/plan-followup-session.ts +0 -0
  294. /package/src/{saeeol → overlay}/plan-followup.ts +0 -0
  295. /package/src/{saeeol → overlay}/plugins/home-footer.tsx +0 -0
  296. /package/src/{saeeol → overlay}/plugins/home-news.tsx +0 -0
  297. /package/src/{saeeol → overlay}/plugins/home-onboarding.tsx +0 -0
  298. /package/src/{saeeol → overlay}/plugins/sidebar-footer.tsx +0 -0
  299. /package/src/{saeeol → overlay}/plugins/sidebar-pr.tsx +0 -0
  300. /package/src/{saeeol → overlay}/plugins/sidebar-usage.tsx +0 -0
  301. /package/src/{saeeol → overlay}/project-id.ts +0 -0
  302. /package/src/{saeeol → overlay}/provider/codex-refresh.ts +0 -0
  303. /package/src/{saeeol → overlay}/provider/provider.ts +0 -0
  304. /package/src/{saeeol → overlay}/provider-options.ts +0 -0
  305. /package/src/{saeeol → overlay}/question/index.ts +0 -0
  306. /package/src/{saeeol → overlay}/remote-tui.tsx +0 -0
  307. /package/src/{saeeol → overlay}/review/command.ts +0 -0
  308. /package/src/{saeeol → overlay}/review/diff.ts +0 -0
  309. /package/src/{saeeol → overlay}/review/prompt.ts +0 -0
  310. /package/src/{saeeol → overlay}/review/review.ts +0 -0
  311. /package/src/{saeeol → overlay}/review/types.ts +0 -0
  312. /package/src/{saeeol → overlay}/review/worktree-diff.ts +0 -0
  313. /package/src/{saeeol → overlay}/rules-migrator.ts +0 -0
  314. /package/src/{saeeol → overlay}/server/instance.ts +0 -0
  315. /package/src/{saeeol → overlay}/server/router.ts +0 -0
  316. /package/src/{saeeol → overlay}/server/routes/commit-message.ts +0 -0
  317. /package/src/{saeeol → overlay}/server/routes/indexing.ts +0 -0
  318. /package/src/{saeeol → overlay}/server/server.ts +0 -0
  319. /package/src/{saeeol → overlay}/session/compaction-chunks-core.ts +0 -0
  320. /package/src/{saeeol → overlay}/session/compaction-chunks-utils.ts +0 -0
  321. /package/src/{saeeol → overlay}/session/compaction-chunks.ts +0 -0
  322. /package/src/{saeeol → overlay}/session/compaction-payload-recovery.ts +0 -0
  323. /package/src/{saeeol → overlay}/session/cost-propagation.ts +0 -0
  324. /package/src/{saeeol → overlay}/session/digest-storage.ts +0 -0
  325. /package/src/{saeeol → overlay}/session/fork.ts +0 -0
  326. /package/src/{saeeol → overlay}/session/index.ts +0 -0
  327. /package/src/{saeeol → overlay}/session/instruction.ts +0 -0
  328. /package/src/{saeeol → overlay}/session/kg-compaction.ts +0 -0
  329. /package/src/{saeeol → overlay}/session/llm.ts +0 -0
  330. /package/src/{saeeol → overlay}/session/overflow.ts +0 -0
  331. /package/src/{saeeol → overlay}/session/platform.ts +0 -0
  332. /package/src/{saeeol → overlay}/session/processor.ts +0 -0
  333. /package/src/{saeeol → overlay}/session/prompt-context.ts +0 -0
  334. /package/src/{saeeol → overlay}/session/prompt-plan.ts +0 -0
  335. /package/src/{saeeol → overlay}/session/prompt-queue.ts +0 -0
  336. /package/src/{saeeol → overlay}/session/prompt.ts +0 -0
  337. /package/src/{saeeol → overlay}/session/queries.ts +0 -0
  338. /package/src/{saeeol → overlay}/session/tui-sync.ts +0 -0
  339. /package/src/{saeeol → overlay}/session-import/routes.ts +0 -0
  340. /package/src/{saeeol → overlay}/session-import/service.ts +0 -0
  341. /package/src/{saeeol → overlay}/session-import/types.ts +0 -0
  342. /package/src/{saeeol → overlay}/skills/builtin.ts +0 -0
  343. /package/src/{saeeol → overlay}/skills/config.md +0 -0
  344. /package/src/{saeeol → overlay}/snapshot/diff-full.ts +0 -0
  345. /package/src/{saeeol → overlay}/snapshot/index.ts +0 -0
  346. /package/src/{saeeol → overlay}/snapshot/track-hooks.ts +0 -0
  347. /package/src/{saeeol → overlay}/snapshot/track-types.ts +0 -0
  348. /package/src/{saeeol → overlay}/snapshot/track.ts +0 -0
  349. /package/src/{saeeol → overlay}/soul.txt +0 -0
  350. /package/src/{saeeol → overlay}/suggestion/index.ts +0 -0
  351. /package/src/{saeeol → overlay}/suggestion/routes.ts +0 -0
  352. /package/src/{saeeol → overlay}/suggestion/tool.ts +0 -0
  353. /package/src/{saeeol → overlay}/suggestion/tool.txt +0 -0
  354. /package/src/{saeeol → overlay}/suggestion/tui/bar.tsx +0 -0
  355. /package/src/{saeeol → overlay}/suggestion/tui/prompt.tsx +0 -0
  356. /package/src/{saeeol → overlay}/suggestion/tui/render.tsx +0 -0
  357. /package/src/{saeeol → overlay}/suggestion/tui/sync.ts +0 -0
  358. /package/src/{saeeol → overlay}/system-prompt.ts +0 -0
  359. /package/src/{saeeol → overlay}/todo-view.ts +0 -0
  360. /package/src/{saeeol → overlay}/tool/agent-manager.ts +0 -0
  361. /package/src/{saeeol → overlay}/tool/agent-manager.txt +0 -0
  362. /package/src/{saeeol → overlay}/tool/bash-security-patterns.ts +0 -0
  363. /package/src/{saeeol → overlay}/tool/bash-security.ts +0 -0
  364. /package/src/{saeeol → overlay}/tool/question.ts +0 -0
  365. /package/src/{saeeol → overlay}/tool/registry.ts +0 -0
  366. /package/src/{saeeol → overlay}/tool/semantic-search.ts +0 -0
  367. /package/src/{saeeol → overlay}/tool/semantic-search.txt +0 -0
  368. /package/src/{saeeol → overlay}/tool/task.ts +0 -0
  369. /package/src/{saeeol → overlay}/ts-check.ts +0 -0
  370. /package/src/{saeeol → overlay}/ts-client.ts +0 -0
  371. /package/src/{saeeol → overlay}/tui/diff.ts +0 -0
  372. /package/src/{saeeol → overlay}/util/url.ts +0 -0
  373. /package/src/{saeeol → overlay}/worker/index.ts +0 -0
  374. /package/src/{saeeol → overlay}/worker/pool.ts +0 -0
  375. /package/src/{saeeol → overlay}/worker/store.ts +0 -0
  376. /package/src/{saeeol → overlay}/worker/types.ts +0 -0
  377. /package/src/{saeeol → overlay}/workflows-migrator.ts +0 -0
  378. /package/src/{saeeol → overlay}/worktree-cleanup.ts +0 -0
  379. /package/src/{saeeol → overlay}/worktree-family.ts +0 -0
@@ -0,0 +1,139 @@
1
+ import { NotFoundError } from "@/storage/storage"
2
+ import { eq } from "drizzle-orm"
3
+ import { and } from "drizzle-orm"
4
+ import { SyncEvent } from "@/sync"
5
+ import * as Session from "./session"
6
+ import { MessageV2 } from "../message/message-v2"
7
+ import { SessionTable, MessageTable, PartTable } from "./session.sql"
8
+ import * as Log from "@saeeol/core/util/log"
9
+
10
+ const log = Log.create({ service: "session.projector" })
11
+
12
+ function foreign(err: unknown) {
13
+ if (typeof err !== "object" || err === null) return false
14
+ if ("code" in err && err.code === "SQLITE_CONSTRAINT_FOREIGNKEY") return true
15
+ return "message" in err && typeof err.message === "string" && err.message.includes("FOREIGN KEY constraint failed")
16
+ }
17
+
18
+ export type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> | null } : T
19
+
20
+ function grab<T extends object, K1 extends keyof T, X>(
21
+ obj: T,
22
+ field1: K1,
23
+ cb?: (val: NonNullable<T[K1]>) => X,
24
+ ): X | undefined {
25
+ if (obj == undefined || !(field1 in obj)) return undefined
26
+
27
+ const val = obj[field1]
28
+ if (val && typeof val === "object" && cb) {
29
+ return cb(val)
30
+ }
31
+ if (val === undefined) {
32
+ throw new Error(
33
+ "Session update failure: pass `null` to clear a field instead of `undefined`: " + JSON.stringify(obj),
34
+ )
35
+ }
36
+ return val as X | undefined
37
+ }
38
+
39
+ export function toPartialRow(info: DeepPartial<Session.Info>) {
40
+ const obj = {
41
+ id: grab(info, "id"),
42
+ project_id: grab(info, "projectID"),
43
+ workspace_id: grab(info, "workspaceID"),
44
+ parent_id: grab(info, "parentID"),
45
+ slug: grab(info, "slug"),
46
+ directory: grab(info, "directory"),
47
+ path: grab(info, "path"),
48
+ title: grab(info, "title"),
49
+ version: grab(info, "version"),
50
+ share_url: grab(info, "share", (v) => grab(v, "url")),
51
+ summary_additions: grab(info, "summary", (v) => grab(v, "additions")),
52
+ summary_deletions: grab(info, "summary", (v) => grab(v, "deletions")),
53
+ summary_files: grab(info, "summary", (v) => grab(v, "files")),
54
+ summary_diffs: grab(info, "summary", (v) => grab(v, "diffs")),
55
+ revert: grab(info, "revert"),
56
+ permission: grab(info, "permission"),
57
+ time_created: grab(info, "time", (v) => grab(v, "created")),
58
+ time_updated: grab(info, "time", (v) => grab(v, "updated")),
59
+ time_compacting: grab(info, "time", (v) => grab(v, "compacting")),
60
+ time_archived: grab(info, "time", (v) => grab(v, "archived")),
61
+ }
62
+
63
+ return Object.fromEntries(Object.entries(obj).filter(([_, val]) => val !== undefined))
64
+ }
65
+
66
+ export default [
67
+ SyncEvent.project(Session.Event.Created, (db, data) => {
68
+ db.insert(SessionTable)
69
+ .values(Session.toRow(data.info as Session.Info))
70
+ .run()
71
+ }),
72
+
73
+ SyncEvent.project(Session.Event.Updated, (db, data) => {
74
+ const info = data.info
75
+ const row = db
76
+ .update(SessionTable)
77
+ .set(toPartialRow(info as Session.Patch))
78
+ .where(eq(SessionTable.id, data.sessionID))
79
+ .returning()
80
+ .get()
81
+ if (!row) throw new NotFoundError({ message: `Session not found: ${data.sessionID}` })
82
+ }),
83
+
84
+ SyncEvent.project(Session.Event.Deleted, (db, data) => {
85
+ db.delete(SessionTable).where(eq(SessionTable.id, data.sessionID)).run()
86
+ }),
87
+
88
+ SyncEvent.project(MessageV2.Event.Updated, (db, data) => {
89
+ const time_created = data.info.time.created
90
+ const { id, sessionID, ...rest } = data.info
91
+
92
+ try {
93
+ db.insert(MessageTable)
94
+ .values({
95
+ id,
96
+ session_id: sessionID,
97
+ time_created,
98
+ data: rest,
99
+ })
100
+ .onConflictDoUpdate({ target: MessageTable.id, set: { data: rest } })
101
+ .run()
102
+ } catch (err) {
103
+ if (!foreign(err)) throw err
104
+ log.warn("ignored late message update", { messageID: id, sessionID })
105
+ }
106
+ }),
107
+
108
+ SyncEvent.project(MessageV2.Event.Removed, (db, data) => {
109
+ db.delete(MessageTable)
110
+ .where(and(eq(MessageTable.id, data.messageID), eq(MessageTable.session_id, data.sessionID)))
111
+ .run()
112
+ }),
113
+
114
+ SyncEvent.project(MessageV2.Event.PartRemoved, (db, data) => {
115
+ db.delete(PartTable)
116
+ .where(and(eq(PartTable.id, data.partID), eq(PartTable.session_id, data.sessionID)))
117
+ .run()
118
+ }),
119
+
120
+ SyncEvent.project(MessageV2.Event.PartUpdated, (db, data) => {
121
+ const { id, messageID, sessionID, ...rest } = data.part
122
+
123
+ try {
124
+ db.insert(PartTable)
125
+ .values({
126
+ id,
127
+ message_id: messageID,
128
+ session_id: sessionID,
129
+ time_created: data.time,
130
+ data: rest,
131
+ })
132
+ .onConflictDoUpdate({ target: PartTable.id, set: { data: rest } })
133
+ .run()
134
+ } catch (err) {
135
+ if (!foreign(err)) throw err
136
+ log.warn("ignored late part update", { partID: id, messageID, sessionID })
137
+ }
138
+ }),
139
+ ]
@@ -0,0 +1,241 @@
1
+ import { type Tool as AITool, tool, jsonSchema, type ToolExecutionOptions, asSchema } from "ai"
2
+ import { Effect, Context, Layer } from "effect"
3
+ import * as EffectZod from "@/util/effect-zod"
4
+ import { ModelID, ProviderID } from "../../provider/schema"
5
+ import { SessionID, PartID } from "./schema"
6
+ import { MessageV2 } from "../message/message-v2"
7
+ import * as Session from "./session"
8
+ import { Agent } from "../../agent/agent"
9
+ import { Provider } from "@/provider/provider"
10
+ import { ProviderTransform } from "@/provider/transform"
11
+ import { ToolRegistry } from "@/tool/registry"
12
+ import { MCP } from "../../mcp"
13
+ import { Plugin } from "../../plugin"
14
+ import { Permission } from "@/permission"
15
+ import { Truncate } from "@/tool/truncate"
16
+ import { SessionProcessor } from "./processor"
17
+ import { SaeeolSessionPrompt } from "@/saeeol/session/prompt"
18
+ import { EffectBridge } from "@/effect/bridge"
19
+ import { Tool } from "@/tool/tool"
20
+ import { type TaskPromptOps } from "@/tool/task"
21
+ import * as Log from "@saeeol/core/util/log"
22
+
23
+ const log = Log.create({ service: "session.resolve-tools" })
24
+
25
+ export interface ResolveToolsInput {
26
+ agent: Agent.Info
27
+ model: Provider.Model
28
+ session: Session.Info
29
+ tools?: Record<string, boolean>
30
+ processor: Pick<SessionProcessor.Handle, "message" | "updateToolCall" | "completeToolCall">
31
+ bypassAgentCheck: boolean
32
+ messages: MessageV2.WithParts[]
33
+ }
34
+
35
+ export interface Interface {
36
+ readonly resolve: (input: ResolveToolsInput) => Effect.Effect<Record<string, AITool>>
37
+ }
38
+
39
+ export class Service extends Context.Service<Service, Interface>()("@saeeol/SessionResolveTools") {}
40
+
41
+ export const layer = Layer.effect(
42
+ Service,
43
+ Effect.gen(function* () {
44
+ const registry = yield* ToolRegistry.Service
45
+ const plugin = yield* Plugin.Service
46
+ const permission = yield* Permission.Service
47
+ const mcp = yield* MCP.Service
48
+ const truncate = yield* Truncate.Service
49
+
50
+ const resolve = Effect.fn("SessionResolveTools.resolve")(function* (input: ResolveToolsInput) {
51
+ using _ = log.time("resolveTools")
52
+ const tools: Record<string, AITool> = {}
53
+ const bridge = yield* EffectBridge.make()
54
+ const promptOps: TaskPromptOps = {
55
+ cancel: (sessionID: SessionID) => Effect.void,
56
+ resolvePromptParts: (template: string) => Effect.succeed([{ type: "text" as const, text: template }]) as any,
57
+ prompt: (_input: any) => Effect.fail(new Error("not available")) as any,
58
+ }
59
+
60
+ const context = (args: any, options: ToolExecutionOptions): Tool.Context => ({
61
+ sessionID: input.session.id,
62
+ abort: options.abortSignal!,
63
+ messageID: input.processor.message.id,
64
+ callID: options.toolCallId,
65
+ extra: { model: input.model, bypassAgentCheck: input.bypassAgentCheck, promptOps },
66
+ agent: input.agent.name,
67
+ messages: input.messages,
68
+ metadata: (val: any) =>
69
+ input.processor.updateToolCall(options.toolCallId, (match) => {
70
+ if (!["running", "pending"].includes(match.state.status)) return match
71
+ return {
72
+ ...match,
73
+ state: {
74
+ title: val.title,
75
+ metadata: val.metadata,
76
+ status: "running",
77
+ input: args,
78
+ time: { start: Date.now() },
79
+ },
80
+ }
81
+ }),
82
+ ask: (req: any) =>
83
+ permission
84
+ .ask({
85
+ ...req,
86
+ sessionID: input.session.id,
87
+ tool: { messageID: input.processor.message.id, callID: options.toolCallId },
88
+ ruleset: Permission.merge(
89
+ input.agent.permission,
90
+ SaeeolSessionPrompt.guardPermissions({ agent: input.agent, session: input.session }),
91
+ ),
92
+ hardRuleset: SaeeolSessionPrompt.hardPermissions({ agent: input.agent }),
93
+ })
94
+ .pipe(Effect.orDie),
95
+ })
96
+
97
+ for (const item of yield* registry.tools({
98
+ modelID: ModelID.make(input.model.api.id),
99
+ providerID: input.model.providerID,
100
+ agent: input.agent,
101
+ })) {
102
+ const schema = ProviderTransform.schema(input.model, EffectZod.toJsonSchema(item.parameters))
103
+ tools[item.id] = tool({
104
+ description: item.description,
105
+ inputSchema: jsonSchema(schema),
106
+ execute(args, options) {
107
+ return bridge.promise(
108
+ Effect.gen(function* () {
109
+ const ctx = context(args, options)
110
+ yield* plugin.trigger(
111
+ "tool.execute.before",
112
+ { tool: item.id, sessionID: ctx.sessionID, callID: ctx.callID },
113
+ { args },
114
+ )
115
+ const result = yield* item.execute(args, ctx)
116
+ const output = {
117
+ ...result,
118
+ attachments: result.attachments?.map((attachment) => ({
119
+ ...attachment,
120
+ id: PartID.ascending(),
121
+ sessionID: ctx.sessionID,
122
+ messageID: input.processor.message.id,
123
+ })),
124
+ }
125
+ yield* plugin.trigger(
126
+ "tool.execute.after",
127
+ { tool: item.id, sessionID: ctx.sessionID, callID: ctx.callID, args },
128
+ output,
129
+ )
130
+ if (options.abortSignal?.aborted) {
131
+ yield* input.processor.completeToolCall(options.toolCallId, output)
132
+ }
133
+ return output
134
+ }),
135
+ )
136
+ },
137
+ })
138
+ }
139
+
140
+ for (const [key, item] of Object.entries(yield* mcp.tools())) {
141
+ const execute = item.execute
142
+ if (!execute) continue
143
+ const schema = yield* Effect.promise(() => Promise.resolve(asSchema(item.inputSchema).jsonSchema))
144
+ const transformed = ProviderTransform.schema(input.model, schema)
145
+ item.inputSchema = jsonSchema(transformed)
146
+ item.execute = (args, opts) =>
147
+ bridge.promise(
148
+ Effect.gen(function* () {
149
+ const ctx = context(args, opts)
150
+ yield* plugin.trigger(
151
+ "tool.execute.before",
152
+ { tool: key, sessionID: ctx.sessionID, callID: opts.toolCallId },
153
+ { args },
154
+ )
155
+ const result: Awaited<ReturnType<NonNullable<typeof execute>>> = yield* Effect.gen(function* () {
156
+ yield* ctx.ask({ permission: key, metadata: {}, patterns: ["*"], always: ["*"] })
157
+ return yield* Effect.promise(() => execute(args, opts))
158
+ }).pipe(
159
+ Effect.withSpan("Tool.execute", {
160
+ attributes: {
161
+ "tool.name": key,
162
+ "tool.call_id": opts.toolCallId,
163
+ "session.id": ctx.sessionID,
164
+ "message.id": input.processor.message.id,
165
+ },
166
+ }),
167
+ )
168
+ yield* plugin.trigger(
169
+ "tool.execute.after",
170
+ { tool: key, sessionID: ctx.sessionID, callID: opts.toolCallId, args },
171
+ result,
172
+ )
173
+
174
+ const textParts: string[] = []
175
+ const attachments: Omit<MessageV2.FilePart, "id" | "sessionID" | "messageID">[] = []
176
+ for (const contentItem of result.content) {
177
+ if (contentItem.type === "text") textParts.push(contentItem.text)
178
+ else if (contentItem.type === "image") {
179
+ attachments.push({
180
+ type: "file",
181
+ mime: contentItem.mimeType,
182
+ url: `data:${contentItem.mimeType};base64,${contentItem.data}`,
183
+ })
184
+ } else if (contentItem.type === "resource") {
185
+ const { resource } = contentItem
186
+ if (resource.text) textParts.push(resource.text)
187
+ if (resource.blob) {
188
+ attachments.push({
189
+ type: "file",
190
+ mime: resource.mimeType ?? "application/octet-stream",
191
+ url: `data:${resource.mimeType ?? "application/octet-stream"};base64,${resource.blob}`,
192
+ filename: resource.uri,
193
+ })
194
+ }
195
+ }
196
+ }
197
+
198
+ const truncated = yield* truncate.output(textParts.join("\n\n"), {}, input.agent)
199
+ const metadata = {
200
+ ...result.metadata,
201
+ truncated: truncated.truncated,
202
+ ...(truncated.truncated && { outputPath: truncated.outputPath }),
203
+ }
204
+ const output = {
205
+ title: "",
206
+ metadata,
207
+ output: truncated.content,
208
+ attachments: attachments.map((attachment) => ({
209
+ ...attachment,
210
+ id: PartID.ascending(),
211
+ sessionID: ctx.sessionID,
212
+ messageID: input.processor.message.id,
213
+ })),
214
+ content: result.content,
215
+ }
216
+ if (opts.abortSignal?.aborted) {
217
+ yield* input.processor.completeToolCall(opts.toolCallId, output)
218
+ }
219
+ return output
220
+ }),
221
+ )
222
+ tools[key] = item
223
+ }
224
+
225
+ return tools
226
+ })
227
+
228
+ return { resolve }
229
+ }),
230
+ )
231
+
232
+ export const defaultLayer = Layer.suspend(() =>
233
+ layer.pipe(
234
+ Layer.provide(ToolRegistry.defaultLayer),
235
+ Layer.provide(MCP.defaultLayer),
236
+ Layer.provide(Plugin.defaultLayer),
237
+ Layer.provide(Permission.defaultLayer),
238
+ Layer.provide(Truncate.defaultLayer),
239
+ Layer.provide(Provider.defaultLayer),
240
+ ),
241
+ )
@@ -0,0 +1,149 @@
1
+ import type { NamedError } from "@saeeol/core/util/error"
2
+ import { Cause, Clock, Duration, Effect, Schedule } from "effect"
3
+ import { MessageV2 } from "../message/message-v2"
4
+ import { isSaeeolError } from "@/saeeol/errors"
5
+ import { SessionNetwork } from "./network"
6
+ import { iife } from "@/util/iife"
7
+
8
+ export type Err = ReturnType<NamedError["toObject"]>
9
+
10
+ // This exported message is shared with the TUI upsell detector. Matching on a
11
+ // literal error string kind of sucks, but it is the simplest for now.
12
+ export const GO_UPSELL_MESSAGE = "Free usage exceeded, subscribe to Go https://saeeol.ai/go"
13
+
14
+ export const RETRY_INITIAL_DELAY = 2000
15
+ export const RETRY_BACKOFF_FACTOR = 2
16
+ export const RETRY_MAX_DELAY_NO_HEADERS = 30_000 // 30 seconds
17
+ export const RETRY_MAX_DELAY = 2_147_483_647 // max 32-bit signed integer for setTimeout
18
+
19
+ function cap(ms: number) {
20
+ return Math.min(ms, RETRY_MAX_DELAY)
21
+ }
22
+
23
+ export function delay(attempt: number, error?: MessageV2.APIError) {
24
+ if (error) {
25
+ const headers = error.data.responseHeaders
26
+ if (headers) {
27
+ const retryAfterMs = headers["retry-after-ms"]
28
+ if (retryAfterMs) {
29
+ const parsedMs = Number.parseFloat(retryAfterMs)
30
+ if (!Number.isNaN(parsedMs)) {
31
+ return cap(parsedMs)
32
+ }
33
+ }
34
+
35
+ const retryAfter = headers["retry-after"]
36
+ if (retryAfter) {
37
+ const parsedSeconds = Number.parseFloat(retryAfter)
38
+ if (!Number.isNaN(parsedSeconds)) {
39
+ // convert seconds to milliseconds
40
+ return cap(Math.ceil(parsedSeconds * 1000))
41
+ }
42
+ // Try parsing as HTTP date format
43
+ const parsed = Date.parse(retryAfter) - Date.now()
44
+ if (!Number.isNaN(parsed) && parsed > 0) {
45
+ return cap(Math.ceil(parsed))
46
+ }
47
+ }
48
+
49
+ return cap(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1))
50
+ }
51
+ }
52
+
53
+ return cap(Math.min(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1), RETRY_MAX_DELAY_NO_HEADERS))
54
+ }
55
+
56
+ export function retryable(error: Err) {
57
+ // context overflow errors should not be retried
58
+ if (MessageV2.ContextOverflowError.isInstance(error)) return undefined
59
+ if (MessageV2.APIError.isInstance(error)) {
60
+ const status = error.data.statusCode
61
+ if (isSaeeolError(error)) return undefined
62
+
63
+ // 5xx errors are transient server failures and should always be retried,
64
+ // even when the provider SDK doesn't explicitly mark them as retryable.
65
+ if (!error.data.isRetryable && !(status !== undefined && status >= 500)) return undefined
66
+ // capped model is futile and the backoff loop cannot be broken by switching
67
+ // models in the chat selector (the retry loop holds a stale model ref).
68
+ if (error.data.responseBody?.includes("FreeUsageLimitError")) return undefined
69
+ return error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message
70
+ }
71
+
72
+ // Check for rate limit patterns in plain text error messages
73
+ const msg = error.data?.message
74
+ if (typeof msg === "string") {
75
+ const lower = msg.toLowerCase()
76
+ if (
77
+ lower.includes("rate increased too quickly") ||
78
+ lower.includes("rate limit") ||
79
+ lower.includes("too many requests")
80
+ ) {
81
+ return msg
82
+ }
83
+ }
84
+
85
+ const json = iife(() => {
86
+ try {
87
+ if (typeof error.data?.message === "string") {
88
+ const parsed = JSON.parse(error.data.message)
89
+ return parsed
90
+ }
91
+
92
+ return JSON.parse(error.data.message)
93
+ } catch {
94
+ return undefined
95
+ }
96
+ })
97
+ if (!json || typeof json !== "object") return undefined
98
+ const code = typeof json.code === "string" ? json.code : ""
99
+
100
+ if (json.type === "error" && json.error?.type === "too_many_requests") {
101
+ return "Too Many Requests"
102
+ }
103
+ if (code.includes("exhausted") || code.includes("unavailable")) {
104
+ return "Provider is overloaded"
105
+ }
106
+ if (json.type === "error" && typeof json.error?.code === "string" && json.error.code.includes("rate_limit")) {
107
+ return "Rate Limited"
108
+ }
109
+ return undefined
110
+ }
111
+
112
+ export function policy(opts: {
113
+ parse: (error: unknown) => Err
114
+ set: (input: { attempt: number; message: string; next: number }) => Effect.Effect<void>
115
+ limit?: number
116
+ offline?: (input: { error: unknown; message: string }) => Effect.Effect<"retry" | "blocked" | "aborted">
117
+ }) {
118
+ return Schedule.fromStepWithMetadata(
119
+ Effect.succeed((meta: Schedule.InputMetadata<unknown>) => {
120
+ if (opts.limit !== undefined && meta.attempt > opts.limit) {
121
+ return Cause.done(meta.attempt)
122
+ }
123
+
124
+ const error = opts.parse(meta.input)
125
+ const message = retryable(error)
126
+ if (!message) return Cause.done(meta.attempt)
127
+ return Effect.gen(function* () {
128
+ if (opts.offline && SessionNetwork.disconnected(meta.input)) {
129
+ const result = yield* opts.offline({
130
+ error: meta.input,
131
+ message: SessionNetwork.message(meta.input),
132
+ })
133
+ if (result !== "retry") {
134
+ return yield* Cause.done(meta.attempt)
135
+ }
136
+ yield* opts.set({ attempt: 0, message: "Reconnected", next: Date.now() })
137
+ return [0, Duration.zero] as [number, Duration.Duration]
138
+ }
139
+
140
+ const wait = delay(meta.attempt, MessageV2.APIError.isInstance(error) ? error : undefined)
141
+ const now = yield* Clock.currentTimeMillis
142
+ yield* opts.set({ attempt: meta.attempt, message, next: now + wait })
143
+ return [meta.attempt, Duration.millis(wait)] as [number, Duration.Duration]
144
+ })
145
+ }),
146
+ )
147
+ }
148
+
149
+ export * as SessionRetry from "./retry"