@hiai-gg/hiai-opencode 0.1.7 → 0.1.8

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 (1188) hide show
  1. package/AGENTS.md +35 -0
  2. package/ARCHITECTURE.md +39 -0
  3. package/README.md +28 -8
  4. package/dist/agents/coder/agent.d.ts +2 -2
  5. package/dist/agents/dynamic-agent-core-sections.d.ts +3 -1
  6. package/dist/agents/guard/agent.d.ts +4 -15
  7. package/dist/agents/prompt-library/index.d.ts +1 -0
  8. package/dist/agents/prompt-library/integration-map.d.ts +9 -0
  9. package/dist/agents/strategist/system-prompt.d.ts +5 -8
  10. package/dist/agents/sub/agent.d.ts +6 -8
  11. package/dist/agents/sub/index.d.ts +0 -4
  12. package/dist/hooks/keyword-detector/ultrawork/default.d.ts +1 -1
  13. package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +1 -1
  14. package/dist/hooks/keyword-detector/ultrawork/gpt.d.ts +1 -1
  15. package/dist/hooks/keyword-detector/ultrawork/intent-gate.d.ts +0 -0
  16. package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +1 -1
  17. package/dist/index.js +1442 -4098
  18. package/dist/shared/index.d.ts +1 -0
  19. package/dist/shared/learn-system.d.ts +18 -0
  20. package/hiai-opencode.json +4 -5
  21. package/package.json +3 -3
  22. package/dist/agents/bob/default.d.ts +0 -10
  23. package/dist/agents/bob/gemini.d.ts +0 -21
  24. package/dist/agents/bob/gpt-pro.d.ts +0 -27
  25. package/dist/agents/bob/index.d.ts +0 -11
  26. package/dist/agents/coder/gpt-codex.d.ts +0 -20
  27. package/dist/agents/coder/gpt-pro.d.ts +0 -25
  28. package/dist/agents/guard/gemini-prompt-sections.d.ts +0 -12
  29. package/dist/agents/guard/gemini.d.ts +0 -2
  30. package/dist/agents/guard/gpt-prompt-sections.d.ts +0 -12
  31. package/dist/agents/guard/gpt.d.ts +0 -2
  32. package/dist/agents/strategist/gemini.d.ts +0 -13
  33. package/dist/agents/strategist/gpt.d.ts +0 -12
  34. package/dist/agents/sub/gemini.d.ts +0 -10
  35. package/dist/agents/sub/gpt-codex.d.ts +0 -8
  36. package/dist/agents/sub/gpt-pro.d.ts +0 -11
  37. package/dist/agents/sub/gpt.d.ts +0 -9
  38. package/dist/skills/index.d.ts +0 -7
  39. package/dist/testing/module-mock-lifecycle.d.ts +0 -21
  40. package/src/AGENTS.md +0 -41
  41. package/src/agents/AGENTS.md +0 -74
  42. package/src/agents/agent-builder.ts +0 -50
  43. package/src/agents/agent-skills.ts +0 -70
  44. package/src/agents/bob/AGENTS.md +0 -29
  45. package/src/agents/bob/default.ts +0 -134
  46. package/src/agents/bob/gemini.ts +0 -238
  47. package/src/agents/bob/gpt-pro.ts +0 -432
  48. package/src/agents/bob/index.ts +0 -19
  49. package/src/agents/bob.ts +0 -531
  50. package/src/agents/brainstormer.ts +0 -72
  51. package/src/agents/builtin-agents/agent-overrides.ts +0 -75
  52. package/src/agents/builtin-agents/available-skills.ts +0 -35
  53. package/src/agents/builtin-agents/bob-agent.ts +0 -96
  54. package/src/agents/builtin-agents/coder-agent.ts +0 -98
  55. package/src/agents/builtin-agents/environment-context.ts +0 -16
  56. package/src/agents/builtin-agents/general-agents.ts +0 -122
  57. package/src/agents/builtin-agents/guard-agent.ts +0 -66
  58. package/src/agents/builtin-agents/model-resolution.ts +0 -31
  59. package/src/agents/builtin-agents/resolve-file-uri.ts +0 -42
  60. package/src/agents/builtin-agents.ts +0 -250
  61. package/src/agents/coder/AGENTS.md +0 -34
  62. package/src/agents/coder/agent.ts +0 -162
  63. package/src/agents/coder/gpt-codex.ts +0 -406
  64. package/src/agents/coder/gpt-pro.ts +0 -321
  65. package/src/agents/coder/gpt.ts +0 -255
  66. package/src/agents/coder/index.ts +0 -8
  67. package/src/agents/critic/agent.ts +0 -106
  68. package/src/agents/custom-agent-summaries.ts +0 -61
  69. package/src/agents/designer.ts +0 -70
  70. package/src/agents/dynamic-agent-category-skills-guide.ts +0 -144
  71. package/src/agents/dynamic-agent-core-sections.ts +0 -273
  72. package/src/agents/dynamic-agent-policy-sections.ts +0 -182
  73. package/src/agents/dynamic-agent-prompt-builder.ts +0 -32
  74. package/src/agents/dynamic-agent-prompt-types.ts +0 -24
  75. package/src/agents/dynamic-agent-tool-categorization.ts +0 -45
  76. package/src/agents/env-context.ts +0 -16
  77. package/src/agents/gpt-apply-patch-guard.ts +0 -7
  78. package/src/agents/guard/agent.ts +0 -146
  79. package/src/agents/guard/default-prompt-sections.ts +0 -305
  80. package/src/agents/guard/default.ts +0 -23
  81. package/src/agents/guard/gemini-prompt-sections.ts +0 -293
  82. package/src/agents/guard/gemini.ts +0 -23
  83. package/src/agents/guard/gpt-prompt-sections.ts +0 -296
  84. package/src/agents/guard/gpt.ts +0 -23
  85. package/src/agents/guard/index.ts +0 -2
  86. package/src/agents/guard/prompt-section-builder.ts +0 -104
  87. package/src/agents/guard/shared-prompt.ts +0 -172
  88. package/src/agents/index.ts +0 -5
  89. package/src/agents/platform-adapter.ts +0 -236
  90. package/src/agents/platform-manager.ts +0 -73
  91. package/src/agents/prompt-library/identity.ts +0 -14
  92. package/src/agents/prompt-library/index.ts +0 -7
  93. package/src/agents/prompt-library/intent-gate.ts +0 -149
  94. package/src/agents/prompt-library/orchestration.ts +0 -60
  95. package/src/agents/prompt-library/platform.ts +0 -70
  96. package/src/agents/prompt-library/specialized.ts +0 -39
  97. package/src/agents/prompt-library/strategy.ts +0 -80
  98. package/src/agents/prompt-library/todo-discipline.ts +0 -23
  99. package/src/agents/quality-guardian.ts +0 -76
  100. package/src/agents/researcher.ts +0 -74
  101. package/src/agents/strategist/AGENTS.md +0 -37
  102. package/src/agents/strategist/behavioral-summary.ts +0 -79
  103. package/src/agents/strategist/gemini.ts +0 -334
  104. package/src/agents/strategist/gpt.ts +0 -461
  105. package/src/agents/strategist/high-accuracy-mode.ts +0 -78
  106. package/src/agents/strategist/identity-constraints.ts +0 -336
  107. package/src/agents/strategist/index.ts +0 -6
  108. package/src/agents/strategist/interview-mode.ts +0 -335
  109. package/src/agents/strategist/plan-generation.ts +0 -213
  110. package/src/agents/strategist/plan-template.ts +0 -325
  111. package/src/agents/strategist/system-prompt.ts +0 -68
  112. package/src/agents/sub/agent.ts +0 -141
  113. package/src/agents/sub/default.ts +0 -52
  114. package/src/agents/sub/gemini.ts +0 -194
  115. package/src/agents/sub/gpt-codex.ts +0 -156
  116. package/src/agents/sub/gpt-pro.ts +0 -161
  117. package/src/agents/sub/gpt.ts +0 -157
  118. package/src/agents/sub/index.ts +0 -13
  119. package/src/agents/types.ts +0 -147
  120. package/src/agents/ui.ts +0 -59
  121. package/src/config/data/model-capabilities.json +0 -40690
  122. package/src/config/defaults.ts +0 -230
  123. package/src/config/hiai-opencode.schema.json +0 -12
  124. package/src/config/index.ts +0 -65
  125. package/src/config/loader.test.ts +0 -80
  126. package/src/config/loader.ts +0 -188
  127. package/src/config/model-slots-and-export.test.ts +0 -73
  128. package/src/config/platform-schema.ts +0 -242
  129. package/src/config/schema/agent-definitions.ts +0 -5
  130. package/src/config/schema/agent-names.ts +0 -66
  131. package/src/config/schema/agent-overrides.ts +0 -97
  132. package/src/config/schema/babysitting.ts +0 -7
  133. package/src/config/schema/background-task.ts +0 -29
  134. package/src/config/schema/bob-agent.ts +0 -11
  135. package/src/config/schema/bob.ts +0 -17
  136. package/src/config/schema/browser-automation.ts +0 -24
  137. package/src/config/schema/categories.ts +0 -45
  138. package/src/config/schema/claude-code.ts +0 -13
  139. package/src/config/schema/commands.ts +0 -16
  140. package/src/config/schema/comment-checker.ts +0 -8
  141. package/src/config/schema/dynamic-context-pruning.ts +0 -53
  142. package/src/config/schema/experimental.ts +0 -27
  143. package/src/config/schema/fallback-models.ts +0 -31
  144. package/src/config/schema/fast-apply.ts +0 -14
  145. package/src/config/schema/git-env-prefix.ts +0 -28
  146. package/src/config/schema/git-master.ts +0 -14
  147. package/src/config/schema/hooks.ts +0 -59
  148. package/src/config/schema/index.ts +0 -52
  149. package/src/config/schema/internal/permission.ts +0 -20
  150. package/src/config/schema/model-capabilities.ts +0 -10
  151. package/src/config/schema/notification.ts +0 -8
  152. package/src/config/schema/oh-my-opencode-config.ts +0 -88
  153. package/src/config/schema/openclaw.ts +0 -50
  154. package/src/config/schema/ralph-loop.ts +0 -11
  155. package/src/config/schema/runtime-fallback.ts +0 -18
  156. package/src/config/schema/skill-discovery.ts +0 -25
  157. package/src/config/schema/skills.ts +0 -39
  158. package/src/config/schema/start-work.ts +0 -7
  159. package/src/config/schema/tmux.ts +0 -28
  160. package/src/config/types.ts +0 -221
  161. package/src/create-hooks.ts +0 -93
  162. package/src/create-managers.ts +0 -116
  163. package/src/create-runtime-tmux-config.ts +0 -18
  164. package/src/create-tools.ts +0 -56
  165. package/src/features/background-agent/AGENTS.md +0 -56
  166. package/src/features/background-agent/abort-with-timeout.ts +0 -35
  167. package/src/features/background-agent/background-task-notification-template.ts +0 -74
  168. package/src/features/background-agent/compaction-aware-message-resolver.ts +0 -164
  169. package/src/features/background-agent/concurrency.ts +0 -137
  170. package/src/features/background-agent/constants.ts +0 -58
  171. package/src/features/background-agent/duration-formatter.ts +0 -14
  172. package/src/features/background-agent/error-classifier.ts +0 -83
  173. package/src/features/background-agent/fallback-retry-handler.ts +0 -134
  174. package/src/features/background-agent/index.ts +0 -2
  175. package/src/features/background-agent/loop-detector.ts +0 -102
  176. package/src/features/background-agent/manager.ts +0 -2220
  177. package/src/features/background-agent/opencode-client.ts +0 -3
  178. package/src/features/background-agent/process-cleanup.ts +0 -98
  179. package/src/features/background-agent/remove-task-toast-tracking.ts +0 -8
  180. package/src/features/background-agent/session-existence.ts +0 -57
  181. package/src/features/background-agent/session-idle-event-handler.ts +0 -93
  182. package/src/features/background-agent/session-status-classifier.ts +0 -20
  183. package/src/features/background-agent/spawner/parent-directory-resolver.ts +0 -24
  184. package/src/features/background-agent/spawner.ts +0 -327
  185. package/src/features/background-agent/state.ts +0 -199
  186. package/src/features/background-agent/subagent-spawn-limits.ts +0 -97
  187. package/src/features/background-agent/task-history.ts +0 -79
  188. package/src/features/background-agent/task-poller.ts +0 -225
  189. package/src/features/background-agent/types.ts +0 -100
  190. package/src/features/boulder-state/constants.ts +0 -13
  191. package/src/features/boulder-state/index.ts +0 -4
  192. package/src/features/boulder-state/storage.ts +0 -336
  193. package/src/features/boulder-state/top-level-task.ts +0 -78
  194. package/src/features/boulder-state/types.ts +0 -61
  195. package/src/features/builtin-commands/commands.ts +0 -157
  196. package/src/features/builtin-commands/index.ts +0 -2
  197. package/src/features/builtin-commands/templates/doctor.ts +0 -43
  198. package/src/features/builtin-commands/templates/handoff.ts +0 -177
  199. package/src/features/builtin-commands/templates/init-deep.ts +0 -305
  200. package/src/features/builtin-commands/templates/mcp-status.ts +0 -36
  201. package/src/features/builtin-commands/templates/ralph-loop.ts +0 -66
  202. package/src/features/builtin-commands/templates/refactor.ts +0 -619
  203. package/src/features/builtin-commands/templates/remove-ai-slops.ts +0 -96
  204. package/src/features/builtin-commands/templates/start-work.ts +0 -128
  205. package/src/features/builtin-commands/templates/stop-continuation.ts +0 -13
  206. package/src/features/builtin-commands/types.ts +0 -9
  207. package/src/features/builtin-skills/index.ts +0 -2
  208. package/src/features/builtin-skills/materialize.ts +0 -338
  209. package/src/features/builtin-skills/skills/ai-slop-remover.ts +0 -145
  210. package/src/features/builtin-skills/skills/dev-browser.ts +0 -221
  211. package/src/features/builtin-skills/skills/frontend-ui-ux.ts +0 -79
  212. package/src/features/builtin-skills/skills/git-master-sections/commit-workflow.ts +0 -509
  213. package/src/features/builtin-skills/skills/git-master-sections/history-search-workflow.ts +0 -229
  214. package/src/features/builtin-skills/skills/git-master-sections/overview.ts +0 -64
  215. package/src/features/builtin-skills/skills/git-master-sections/quick-reference.ts +0 -86
  216. package/src/features/builtin-skills/skills/git-master-sections/rebase-workflow.ts +0 -181
  217. package/src/features/builtin-skills/skills/git-master-skill-metadata.ts +0 -4
  218. package/src/features/builtin-skills/skills/git-master.ts +0 -28
  219. package/src/features/builtin-skills/skills/hiai-opencode-setup.ts +0 -69
  220. package/src/features/builtin-skills/skills/index.ts +0 -9
  221. package/src/features/builtin-skills/skills/playwright-cli.ts +0 -268
  222. package/src/features/builtin-skills/skills/playwright.ts +0 -488
  223. package/src/features/builtin-skills/skills/review-work.ts +0 -536
  224. package/src/features/builtin-skills/skills/website-copywriting.ts +0 -41
  225. package/src/features/builtin-skills/skills.test.ts +0 -8
  226. package/src/features/builtin-skills/skills.ts +0 -50
  227. package/src/features/builtin-skills/types.ts +0 -16
  228. package/src/features/claude-code-agent-loader/agent-definitions-loader.ts +0 -87
  229. package/src/features/claude-code-agent-loader/claude-model-mapper.ts +0 -53
  230. package/src/features/claude-code-agent-loader/index.ts +0 -5
  231. package/src/features/claude-code-agent-loader/json-agent-loader.ts +0 -53
  232. package/src/features/claude-code-agent-loader/loader.ts +0 -86
  233. package/src/features/claude-code-agent-loader/opencode-config-agents-reader.ts +0 -125
  234. package/src/features/claude-code-agent-loader/types.ts +0 -31
  235. package/src/features/claude-code-command-loader/index.ts +0 -2
  236. package/src/features/claude-code-command-loader/loader.ts +0 -169
  237. package/src/features/claude-code-command-loader/types.ts +0 -46
  238. package/src/features/claude-code-mcp-loader/configure-allowed-env-vars.ts +0 -48
  239. package/src/features/claude-code-mcp-loader/env-expander.ts +0 -51
  240. package/src/features/claude-code-mcp-loader/index.ts +0 -12
  241. package/src/features/claude-code-mcp-loader/loader.ts +0 -156
  242. package/src/features/claude-code-mcp-loader/scope-filter.ts +0 -17
  243. package/src/features/claude-code-mcp-loader/transformer.ts +0 -57
  244. package/src/features/claude-code-mcp-loader/types.ts +0 -51
  245. package/src/features/claude-code-plugin-loader/agent-loader.ts +0 -59
  246. package/src/features/claude-code-plugin-loader/command-loader.ts +0 -53
  247. package/src/features/claude-code-plugin-loader/discovery.ts +0 -251
  248. package/src/features/claude-code-plugin-loader/hook-loader.ts +0 -26
  249. package/src/features/claude-code-plugin-loader/index.ts +0 -10
  250. package/src/features/claude-code-plugin-loader/loader.ts +0 -134
  251. package/src/features/claude-code-plugin-loader/mcp-server-loader.ts +0 -59
  252. package/src/features/claude-code-plugin-loader/plugin-path-resolver.ts +0 -23
  253. package/src/features/claude-code-plugin-loader/scope-filter.ts +0 -29
  254. package/src/features/claude-code-plugin-loader/skill-loader.ts +0 -62
  255. package/src/features/claude-code-plugin-loader/types.ts +0 -255
  256. package/src/features/claude-code-session-state/index.ts +0 -1
  257. package/src/features/claude-code-session-state/state.ts +0 -154
  258. package/src/features/claude-tasks/session-storage.ts +0 -52
  259. package/src/features/claude-tasks/storage.ts +0 -169
  260. package/src/features/claude-tasks/types.ts +0 -20
  261. package/src/features/context-injector/collector.ts +0 -91
  262. package/src/features/context-injector/index.ts +0 -14
  263. package/src/features/context-injector/injector.ts +0 -167
  264. package/src/features/context-injector/types.ts +0 -91
  265. package/src/features/hook-message-injector/constants.ts +0 -1
  266. package/src/features/hook-message-injector/index.ts +0 -11
  267. package/src/features/hook-message-injector/injector.ts +0 -437
  268. package/src/features/hook-message-injector/types.ts +0 -49
  269. package/src/features/mcp-oauth/AGENTS.md +0 -54
  270. package/src/features/mcp-oauth/callback-server.ts +0 -106
  271. package/src/features/mcp-oauth/dcr.ts +0 -98
  272. package/src/features/mcp-oauth/discovery.ts +0 -134
  273. package/src/features/mcp-oauth/oauth-authorization-flow.ts +0 -150
  274. package/src/features/mcp-oauth/provider.ts +0 -215
  275. package/src/features/mcp-oauth/refresh-mutex.ts +0 -58
  276. package/src/features/mcp-oauth/resource-indicator.ts +0 -16
  277. package/src/features/mcp-oauth/schema.ts +0 -8
  278. package/src/features/mcp-oauth/step-up.ts +0 -79
  279. package/src/features/mcp-oauth/storage.ts +0 -155
  280. package/src/features/opencode-skill-loader/AGENTS.md +0 -59
  281. package/src/features/opencode-skill-loader/allowed-tools-parser.ts +0 -9
  282. package/src/features/opencode-skill-loader/async-loader.ts +0 -213
  283. package/src/features/opencode-skill-loader/blocking.ts +0 -62
  284. package/src/features/opencode-skill-loader/config-source-discovery.ts +0 -114
  285. package/src/features/opencode-skill-loader/discover-worker.ts +0 -56
  286. package/src/features/opencode-skill-loader/git-master-template-injection.ts +0 -150
  287. package/src/features/opencode-skill-loader/index.ts +0 -17
  288. package/src/features/opencode-skill-loader/loaded-skill-from-path.ts +0 -73
  289. package/src/features/opencode-skill-loader/loaded-skill-template-extractor.ts +0 -16
  290. package/src/features/opencode-skill-loader/loader.ts +0 -183
  291. package/src/features/opencode-skill-loader/merger/builtin-skill-converter.ts +0 -26
  292. package/src/features/opencode-skill-loader/merger/config-skill-entry-loader.ts +0 -117
  293. package/src/features/opencode-skill-loader/merger/scope-priority.ts +0 -10
  294. package/src/features/opencode-skill-loader/merger/skill-definition-merger.ts +0 -31
  295. package/src/features/opencode-skill-loader/merger/skills-config-normalizer.ts +0 -19
  296. package/src/features/opencode-skill-loader/merger.ts +0 -96
  297. package/src/features/opencode-skill-loader/skill-content.ts +0 -11
  298. package/src/features/opencode-skill-loader/skill-deduplication.ts +0 -13
  299. package/src/features/opencode-skill-loader/skill-definition-record.ts +0 -11
  300. package/src/features/opencode-skill-loader/skill-directory-loader.ts +0 -112
  301. package/src/features/opencode-skill-loader/skill-discovery.ts +0 -76
  302. package/src/features/opencode-skill-loader/skill-mcp-config.ts +0 -45
  303. package/src/features/opencode-skill-loader/skill-resolution-options.ts +0 -9
  304. package/src/features/opencode-skill-loader/skill-template-resolver.ts +0 -97
  305. package/src/features/opencode-skill-loader/types.ts +0 -38
  306. package/src/features/run-continuation-state/constants.ts +0 -1
  307. package/src/features/run-continuation-state/index.ts +0 -3
  308. package/src/features/run-continuation-state/storage.ts +0 -80
  309. package/src/features/run-continuation-state/types.ts +0 -15
  310. package/src/features/skill-mcp-manager/AGENTS.md +0 -111
  311. package/src/features/skill-mcp-manager/cleanup.ts +0 -153
  312. package/src/features/skill-mcp-manager/connection-type.ts +0 -26
  313. package/src/features/skill-mcp-manager/connection.ts +0 -146
  314. package/src/features/skill-mcp-manager/env-cleaner.ts +0 -59
  315. package/src/features/skill-mcp-manager/error-redaction.ts +0 -47
  316. package/src/features/skill-mcp-manager/http-client.ts +0 -126
  317. package/src/features/skill-mcp-manager/index.ts +0 -2
  318. package/src/features/skill-mcp-manager/manager.ts +0 -178
  319. package/src/features/skill-mcp-manager/oauth-handler.ts +0 -160
  320. package/src/features/skill-mcp-manager/stdio-client.ts +0 -112
  321. package/src/features/skill-mcp-manager/types.ts +0 -96
  322. package/src/features/task-toast-manager/index.ts +0 -2
  323. package/src/features/task-toast-manager/manager.ts +0 -251
  324. package/src/features/task-toast-manager/types.ts +0 -29
  325. package/src/features/tmux-subagent/action-executor-core.ts +0 -82
  326. package/src/features/tmux-subagent/action-executor.ts +0 -137
  327. package/src/features/tmux-subagent/cleanup.ts +0 -42
  328. package/src/features/tmux-subagent/decision-engine.ts +0 -22
  329. package/src/features/tmux-subagent/event-handlers.ts +0 -6
  330. package/src/features/tmux-subagent/grid-planning.ts +0 -137
  331. package/src/features/tmux-subagent/index.ts +0 -16
  332. package/src/features/tmux-subagent/manager.ts +0 -969
  333. package/src/features/tmux-subagent/oldest-agent-pane.ts +0 -37
  334. package/src/features/tmux-subagent/pane-split-availability.ts +0 -77
  335. package/src/features/tmux-subagent/pane-state-parser.ts +0 -135
  336. package/src/features/tmux-subagent/pane-state-querier.ts +0 -76
  337. package/src/features/tmux-subagent/polling-constants.ts +0 -6
  338. package/src/features/tmux-subagent/polling-manager.ts +0 -167
  339. package/src/features/tmux-subagent/polling.ts +0 -183
  340. package/src/features/tmux-subagent/session-created-event.ts +0 -44
  341. package/src/features/tmux-subagent/session-created-handler.ts +0 -175
  342. package/src/features/tmux-subagent/session-deleted-handler.ts +0 -50
  343. package/src/features/tmux-subagent/session-message-count.ts +0 -3
  344. package/src/features/tmux-subagent/session-ready-waiter.ts +0 -44
  345. package/src/features/tmux-subagent/session-status-parser.ts +0 -17
  346. package/src/features/tmux-subagent/spawn-action-decider.ts +0 -147
  347. package/src/features/tmux-subagent/spawn-target-finder.ts +0 -146
  348. package/src/features/tmux-subagent/tmux-grid-constants.ts +0 -57
  349. package/src/features/tmux-subagent/tracked-session-state.ts +0 -29
  350. package/src/features/tmux-subagent/types.ts +0 -54
  351. package/src/features/tool-metadata-store/index.ts +0 -7
  352. package/src/features/tool-metadata-store/store.ts +0 -84
  353. package/src/hooks/agent-usage-reminder/constants.ts +0 -52
  354. package/src/hooks/agent-usage-reminder/hook.ts +0 -134
  355. package/src/hooks/agent-usage-reminder/index.ts +0 -1
  356. package/src/hooks/agent-usage-reminder/storage.ts +0 -42
  357. package/src/hooks/agent-usage-reminder/types.ts +0 -6
  358. package/src/hooks/anthropic-context-window-limit-recovery/AGENTS.md +0 -49
  359. package/src/hooks/anthropic-context-window-limit-recovery/aggressive-truncation-strategy.ts +0 -87
  360. package/src/hooks/anthropic-context-window-limit-recovery/client.ts +0 -21
  361. package/src/hooks/anthropic-context-window-limit-recovery/deduplication-recovery.ts +0 -77
  362. package/src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.ts +0 -199
  363. package/src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery.ts +0 -149
  364. package/src/hooks/anthropic-context-window-limit-recovery/executor.ts +0 -83
  365. package/src/hooks/anthropic-context-window-limit-recovery/index.ts +0 -8
  366. package/src/hooks/anthropic-context-window-limit-recovery/message-builder.ts +0 -190
  367. package/src/hooks/anthropic-context-window-limit-recovery/message-storage-directory.ts +0 -40
  368. package/src/hooks/anthropic-context-window-limit-recovery/parser.ts +0 -209
  369. package/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts +0 -189
  370. package/src/hooks/anthropic-context-window-limit-recovery/pruning-tool-output-truncation.ts +0 -142
  371. package/src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts +0 -44
  372. package/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test-support.ts +0 -119
  373. package/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.ts +0 -193
  374. package/src/hooks/anthropic-context-window-limit-recovery/recovery-strategy.ts +0 -2
  375. package/src/hooks/anthropic-context-window-limit-recovery/session-timeout-map.ts +0 -20
  376. package/src/hooks/anthropic-context-window-limit-recovery/state.ts +0 -78
  377. package/src/hooks/anthropic-context-window-limit-recovery/storage-paths.ts +0 -6
  378. package/src/hooks/anthropic-context-window-limit-recovery/storage.ts +0 -18
  379. package/src/hooks/anthropic-context-window-limit-recovery/summarize-retry-strategy.ts +0 -218
  380. package/src/hooks/anthropic-context-window-limit-recovery/target-token-truncation.ts +0 -196
  381. package/src/hooks/anthropic-context-window-limit-recovery/tool-part-types.ts +0 -38
  382. package/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage-sdk.ts +0 -123
  383. package/src/hooks/anthropic-context-window-limit-recovery/tool-result-storage.ts +0 -119
  384. package/src/hooks/anthropic-context-window-limit-recovery/types.ts +0 -44
  385. package/src/hooks/anthropic-effort/hook.ts +0 -93
  386. package/src/hooks/anthropic-effort/index.ts +0 -1
  387. package/src/hooks/auto-slash-command/constants.ts +0 -12
  388. package/src/hooks/auto-slash-command/detector.ts +0 -88
  389. package/src/hooks/auto-slash-command/executor.ts +0 -165
  390. package/src/hooks/auto-slash-command/hook.ts +0 -238
  391. package/src/hooks/auto-slash-command/index.ts +0 -7
  392. package/src/hooks/auto-slash-command/processed-command-store.ts +0 -74
  393. package/src/hooks/auto-slash-command/types.ts +0 -42
  394. package/src/hooks/background-notification/hook.ts +0 -54
  395. package/src/hooks/background-notification/index.ts +0 -2
  396. package/src/hooks/background-notification/types.ts +0 -5
  397. package/src/hooks/bash-file-read-guard.ts +0 -44
  398. package/src/hooks/category-skill-reminder/formatter.ts +0 -37
  399. package/src/hooks/category-skill-reminder/hook.ts +0 -142
  400. package/src/hooks/category-skill-reminder/index.ts +0 -1
  401. package/src/hooks/claude-code-hooks/AGENTS.md +0 -41
  402. package/src/hooks/claude-code-hooks/claude-code-hooks-hook.ts +0 -28
  403. package/src/hooks/claude-code-hooks/config-loader.ts +0 -151
  404. package/src/hooks/claude-code-hooks/config.ts +0 -147
  405. package/src/hooks/claude-code-hooks/dispatch-hook.ts +0 -27
  406. package/src/hooks/claude-code-hooks/execute-http-hook.ts +0 -116
  407. package/src/hooks/claude-code-hooks/handlers/chat-message-handler.ts +0 -140
  408. package/src/hooks/claude-code-hooks/handlers/pre-compact-handler.ts +0 -41
  409. package/src/hooks/claude-code-hooks/handlers/session-event-handler.ts +0 -137
  410. package/src/hooks/claude-code-hooks/handlers/tool-execute-after-handler.ts +0 -160
  411. package/src/hooks/claude-code-hooks/handlers/tool-execute-before-handler.ts +0 -93
  412. package/src/hooks/claude-code-hooks/index.ts +0 -1
  413. package/src/hooks/claude-code-hooks/plugin-config.ts +0 -12
  414. package/src/hooks/claude-code-hooks/post-tool-use.ts +0 -195
  415. package/src/hooks/claude-code-hooks/pre-compact.ts +0 -105
  416. package/src/hooks/claude-code-hooks/pre-tool-use.ts +0 -168
  417. package/src/hooks/claude-code-hooks/session-hook-state.ts +0 -17
  418. package/src/hooks/claude-code-hooks/stop.ts +0 -118
  419. package/src/hooks/claude-code-hooks/todo.ts +0 -76
  420. package/src/hooks/claude-code-hooks/tool-input-cache.ts +0 -82
  421. package/src/hooks/claude-code-hooks/transcript.ts +0 -248
  422. package/src/hooks/claude-code-hooks/types.ts +0 -214
  423. package/src/hooks/claude-code-hooks/user-prompt-submit.ts +0 -121
  424. package/src/hooks/comment-checker/cli-runner.ts +0 -127
  425. package/src/hooks/comment-checker/cli.ts +0 -269
  426. package/src/hooks/comment-checker/downloader.ts +0 -170
  427. package/src/hooks/comment-checker/hook.ts +0 -192
  428. package/src/hooks/comment-checker/index.ts +0 -1
  429. package/src/hooks/comment-checker/pending-calls.ts +0 -45
  430. package/src/hooks/comment-checker/types.ts +0 -33
  431. package/src/hooks/compaction-context-injector/compaction-context-prompt.ts +0 -56
  432. package/src/hooks/compaction-context-injector/constants.ts +0 -5
  433. package/src/hooks/compaction-context-injector/hook.ts +0 -164
  434. package/src/hooks/compaction-context-injector/index.ts +0 -1
  435. package/src/hooks/compaction-context-injector/recovery-prompt-config.ts +0 -77
  436. package/src/hooks/compaction-context-injector/recovery.ts +0 -163
  437. package/src/hooks/compaction-context-injector/session-id.ts +0 -8
  438. package/src/hooks/compaction-context-injector/session-prompt-config-resolver.ts +0 -120
  439. package/src/hooks/compaction-context-injector/tail-monitor.ts +0 -52
  440. package/src/hooks/compaction-context-injector/types.ts +0 -25
  441. package/src/hooks/compaction-context-injector/validated-model.ts +0 -47
  442. package/src/hooks/compaction-todo-preserver/hook.ts +0 -127
  443. package/src/hooks/compaction-todo-preserver/index.ts +0 -2
  444. package/src/hooks/context-window-monitor.ts +0 -113
  445. package/src/hooks/delegate-task-retry/guidance.ts +0 -45
  446. package/src/hooks/delegate-task-retry/hook.ts +0 -22
  447. package/src/hooks/delegate-task-retry/index.ts +0 -4
  448. package/src/hooks/delegate-task-retry/patterns.ts +0 -77
  449. package/src/hooks/directory-agents-injector/constants.ts +0 -7
  450. package/src/hooks/directory-agents-injector/finder.ts +0 -38
  451. package/src/hooks/directory-agents-injector/hook.ts +0 -80
  452. package/src/hooks/directory-agents-injector/index.ts +0 -1
  453. package/src/hooks/directory-agents-injector/injector.ts +0 -59
  454. package/src/hooks/directory-agents-injector/storage.ts +0 -8
  455. package/src/hooks/directory-readme-injector/constants.ts +0 -7
  456. package/src/hooks/directory-readme-injector/finder.ts +0 -33
  457. package/src/hooks/directory-readme-injector/hook.ts +0 -80
  458. package/src/hooks/directory-readme-injector/index.ts +0 -1
  459. package/src/hooks/directory-readme-injector/injector.ts +0 -59
  460. package/src/hooks/directory-readme-injector/storage.ts +0 -8
  461. package/src/hooks/edit-error-recovery/hook.ts +0 -58
  462. package/src/hooks/edit-error-recovery/index.ts +0 -5
  463. package/src/hooks/empty-task-response-detector.ts +0 -27
  464. package/src/hooks/fast-apply/hook.ts +0 -11
  465. package/src/hooks/fast-apply/index.ts +0 -1
  466. package/src/hooks/fast-apply/ollama-client.ts +0 -53
  467. package/src/hooks/fast-apply/tool-execute-before-handler.ts +0 -86
  468. package/src/hooks/guard/AGENTS.md +0 -64
  469. package/src/hooks/guard/background-launch-session-tracking.ts +0 -97
  470. package/src/hooks/guard/bob-path.ts +0 -8
  471. package/src/hooks/guard/boulder-continuation-injector.ts +0 -109
  472. package/src/hooks/guard/boulder-session-lineage.ts +0 -44
  473. package/src/hooks/guard/event-handler.ts +0 -104
  474. package/src/hooks/guard/final-wave-approval-gate.ts +0 -47
  475. package/src/hooks/guard/final-wave-plan-state.ts +0 -60
  476. package/src/hooks/guard/guard-hook.ts +0 -27
  477. package/src/hooks/guard/hook-name.ts +0 -1
  478. package/src/hooks/guard/idle-event.ts +0 -341
  479. package/src/hooks/guard/index.ts +0 -3
  480. package/src/hooks/guard/is-abort-error.ts +0 -20
  481. package/src/hooks/guard/recent-model-resolver.ts +0 -89
  482. package/src/hooks/guard/resolve-active-boulder-session.ts +0 -29
  483. package/src/hooks/guard/session-last-agent.ts +0 -153
  484. package/src/hooks/guard/subagent-session-id.ts +0 -54
  485. package/src/hooks/guard/system-reminder-templates.ts +0 -249
  486. package/src/hooks/guard/task-context.ts +0 -45
  487. package/src/hooks/guard/tool-execute-after.ts +0 -209
  488. package/src/hooks/guard/tool-execute-before.ts +0 -102
  489. package/src/hooks/guard/tsconfig.json +0 -9
  490. package/src/hooks/guard/types.ts +0 -45
  491. package/src/hooks/guard/verification-reminders.ts +0 -197
  492. package/src/hooks/guard/write-edit-tool-policy.ts +0 -5
  493. package/src/hooks/hashline-edit-diff-enhancer/hook.ts +0 -106
  494. package/src/hooks/hashline-read-enhancer/hook.ts +0 -193
  495. package/src/hooks/hashline-read-enhancer/index.ts +0 -1
  496. package/src/hooks/index.ts +0 -56
  497. package/src/hooks/interactive-bash-session/constants.ts +0 -13
  498. package/src/hooks/interactive-bash-session/hook.ts +0 -125
  499. package/src/hooks/interactive-bash-session/index.ts +0 -3
  500. package/src/hooks/interactive-bash-session/interactive-bash-session-tracker.ts +0 -119
  501. package/src/hooks/interactive-bash-session/parser.ts +0 -118
  502. package/src/hooks/interactive-bash-session/state-manager.ts +0 -35
  503. package/src/hooks/interactive-bash-session/storage.ts +0 -59
  504. package/src/hooks/interactive-bash-session/tmux-command-parser.ts +0 -125
  505. package/src/hooks/interactive-bash-session/types.ts +0 -11
  506. package/src/hooks/json-error-recovery/hook.ts +0 -58
  507. package/src/hooks/json-error-recovery/index.ts +0 -6
  508. package/src/hooks/keyword-detector/AGENTS.md +0 -57
  509. package/src/hooks/keyword-detector/analyze/default.ts +0 -28
  510. package/src/hooks/keyword-detector/analyze/index.ts +0 -1
  511. package/src/hooks/keyword-detector/constants.ts +0 -45
  512. package/src/hooks/keyword-detector/detector.ts +0 -53
  513. package/src/hooks/keyword-detector/hook.ts +0 -143
  514. package/src/hooks/keyword-detector/index.ts +0 -5
  515. package/src/hooks/keyword-detector/search/default.ts +0 -20
  516. package/src/hooks/keyword-detector/search/index.ts +0 -1
  517. package/src/hooks/keyword-detector/types.ts +0 -4
  518. package/src/hooks/keyword-detector/ultrawork/default.ts +0 -302
  519. package/src/hooks/keyword-detector/ultrawork/gemini.ts +0 -290
  520. package/src/hooks/keyword-detector/ultrawork/gpt.ts +0 -171
  521. package/src/hooks/keyword-detector/ultrawork/index.ts +0 -56
  522. package/src/hooks/keyword-detector/ultrawork/planner.ts +0 -140
  523. package/src/hooks/keyword-detector/ultrawork/source-detector.ts +0 -65
  524. package/src/hooks/legacy-plugin-toast/auto-migrate-runner.ts +0 -2
  525. package/src/hooks/legacy-plugin-toast/auto-migrate.ts +0 -64
  526. package/src/hooks/legacy-plugin-toast/hook.ts +0 -68
  527. package/src/hooks/legacy-plugin-toast/index.ts +0 -1
  528. package/src/hooks/legacy-plugin-toast/plugin-entry-migrator.ts +0 -1
  529. package/src/hooks/model-fallback/chat-message-fallback-handler.ts +0 -74
  530. package/src/hooks/model-fallback/hook.ts +0 -201
  531. package/src/hooks/model-fallback/next-fallback.ts +0 -84
  532. package/src/hooks/non-interactive-env/constants.ts +0 -70
  533. package/src/hooks/non-interactive-env/detector.ts +0 -19
  534. package/src/hooks/non-interactive-env/index.ts +0 -5
  535. package/src/hooks/non-interactive-env/non-interactive-env-hook.ts +0 -73
  536. package/src/hooks/non-interactive-env/types.ts +0 -3
  537. package/src/hooks/preemptive-compaction-degradation-monitor.ts +0 -212
  538. package/src/hooks/preemptive-compaction-no-text-tail.ts +0 -70
  539. package/src/hooks/preemptive-compaction.ts +0 -218
  540. package/src/hooks/question-label-truncator/hook.ts +0 -62
  541. package/src/hooks/question-label-truncator/index.ts +0 -1
  542. package/src/hooks/ralph-loop/AGENTS.md +0 -62
  543. package/src/hooks/ralph-loop/command-arguments.ts +0 -30
  544. package/src/hooks/ralph-loop/completion-handler.ts +0 -65
  545. package/src/hooks/ralph-loop/completion-promise-detector-test-input.ts +0 -23
  546. package/src/hooks/ralph-loop/completion-promise-detector.ts +0 -165
  547. package/src/hooks/ralph-loop/constants.ts +0 -7
  548. package/src/hooks/ralph-loop/continuation-prompt-builder.ts +0 -77
  549. package/src/hooks/ralph-loop/continuation-prompt-injector.ts +0 -91
  550. package/src/hooks/ralph-loop/index.ts +0 -6
  551. package/src/hooks/ralph-loop/iteration-continuation.ts +0 -64
  552. package/src/hooks/ralph-loop/logician-verification-detector.ts +0 -88
  553. package/src/hooks/ralph-loop/loop-session-recovery.ts +0 -33
  554. package/src/hooks/ralph-loop/loop-state-controller.ts +0 -178
  555. package/src/hooks/ralph-loop/message-storage-directory.ts +0 -1
  556. package/src/hooks/ralph-loop/pending-verification-handler.ts +0 -152
  557. package/src/hooks/ralph-loop/ralph-loop-event-handler.ts +0 -231
  558. package/src/hooks/ralph-loop/ralph-loop-hook.ts +0 -90
  559. package/src/hooks/ralph-loop/session-event-handler.ts +0 -56
  560. package/src/hooks/ralph-loop/session-reset-strategy.ts +0 -69
  561. package/src/hooks/ralph-loop/storage.ts +0 -164
  562. package/src/hooks/ralph-loop/types.ts +0 -25
  563. package/src/hooks/ralph-loop/verification-failure-handler.ts +0 -103
  564. package/src/hooks/ralph-loop/with-timeout.ts +0 -20
  565. package/src/hooks/read-image-resizer/hook.ts +0 -209
  566. package/src/hooks/read-image-resizer/image-dimensions.ts +0 -191
  567. package/src/hooks/read-image-resizer/image-resizer.ts +0 -191
  568. package/src/hooks/read-image-resizer/index.ts +0 -1
  569. package/src/hooks/read-image-resizer/png-fallback-resizer.ts +0 -359
  570. package/src/hooks/read-image-resizer/types.ts +0 -16
  571. package/src/hooks/rules-injector/AGENTS.md +0 -53
  572. package/src/hooks/rules-injector/cache.ts +0 -27
  573. package/src/hooks/rules-injector/constants.ts +0 -31
  574. package/src/hooks/rules-injector/finder.ts +0 -3
  575. package/src/hooks/rules-injector/hook.ts +0 -94
  576. package/src/hooks/rules-injector/index.ts +0 -2
  577. package/src/hooks/rules-injector/injector.ts +0 -189
  578. package/src/hooks/rules-injector/matcher.ts +0 -63
  579. package/src/hooks/rules-injector/output-path.ts +0 -22
  580. package/src/hooks/rules-injector/parser.ts +0 -211
  581. package/src/hooks/rules-injector/project-root-finder.ts +0 -36
  582. package/src/hooks/rules-injector/rule-distance.ts +0 -53
  583. package/src/hooks/rules-injector/rule-file-finder.ts +0 -139
  584. package/src/hooks/rules-injector/rule-file-scanner.ts +0 -55
  585. package/src/hooks/rules-injector/storage.ts +0 -59
  586. package/src/hooks/rules-injector/types.ts +0 -57
  587. package/src/hooks/runtime-fallback/AGENTS.md +0 -102
  588. package/src/hooks/runtime-fallback/agent-resolver.ts +0 -50
  589. package/src/hooks/runtime-fallback/auto-retry-signal.ts +0 -32
  590. package/src/hooks/runtime-fallback/auto-retry.ts +0 -228
  591. package/src/hooks/runtime-fallback/chat-message-handler.ts +0 -62
  592. package/src/hooks/runtime-fallback/constants.ts +0 -47
  593. package/src/hooks/runtime-fallback/error-classifier.ts +0 -183
  594. package/src/hooks/runtime-fallback/event-handler.ts +0 -213
  595. package/src/hooks/runtime-fallback/fallback-bootstrap-model.ts +0 -63
  596. package/src/hooks/runtime-fallback/fallback-models.ts +0 -86
  597. package/src/hooks/runtime-fallback/fallback-retry-dispatcher.ts +0 -55
  598. package/src/hooks/runtime-fallback/fallback-state.ts +0 -74
  599. package/src/hooks/runtime-fallback/hook.ts +0 -87
  600. package/src/hooks/runtime-fallback/index.ts +0 -2
  601. package/src/hooks/runtime-fallback/last-user-retry-parts.ts +0 -20
  602. package/src/hooks/runtime-fallback/message-update-handler.ts +0 -168
  603. package/src/hooks/runtime-fallback/retry-model-payload.ts +0 -30
  604. package/src/hooks/runtime-fallback/session-messages.ts +0 -38
  605. package/src/hooks/runtime-fallback/session-status-handler.ts +0 -126
  606. package/src/hooks/runtime-fallback/types.ts +0 -77
  607. package/src/hooks/runtime-fallback/visible-assistant-response.ts +0 -80
  608. package/src/hooks/session-notification-content.ts +0 -145
  609. package/src/hooks/session-notification-formatting.ts +0 -25
  610. package/src/hooks/session-notification-scheduler.ts +0 -188
  611. package/src/hooks/session-notification-sender.ts +0 -117
  612. package/src/hooks/session-notification-utils.ts +0 -80
  613. package/src/hooks/session-notification.ts +0 -219
  614. package/src/hooks/session-recovery/AGENTS.md +0 -59
  615. package/src/hooks/session-recovery/constants.ts +0 -5
  616. package/src/hooks/session-recovery/detect-error-type.ts +0 -102
  617. package/src/hooks/session-recovery/hook.ts +0 -166
  618. package/src/hooks/session-recovery/index.ts +0 -7
  619. package/src/hooks/session-recovery/recover-empty-content-message-sdk.ts +0 -201
  620. package/src/hooks/session-recovery/recover-thinking-block-order.ts +0 -137
  621. package/src/hooks/session-recovery/recover-thinking-disabled-violation.ts +0 -75
  622. package/src/hooks/session-recovery/recover-tool-result-missing.ts +0 -108
  623. package/src/hooks/session-recovery/recover-unavailable-tool.ts +0 -108
  624. package/src/hooks/session-recovery/resume.ts +0 -49
  625. package/src/hooks/session-recovery/storage/empty-messages.ts +0 -47
  626. package/src/hooks/session-recovery/storage/empty-text.ts +0 -118
  627. package/src/hooks/session-recovery/storage/message-dir.ts +0 -1
  628. package/src/hooks/session-recovery/storage/messages-reader.ts +0 -83
  629. package/src/hooks/session-recovery/storage/orphan-thinking-search.ts +0 -43
  630. package/src/hooks/session-recovery/storage/part-content.ts +0 -28
  631. package/src/hooks/session-recovery/storage/part-id.ts +0 -5
  632. package/src/hooks/session-recovery/storage/parts-reader.ts +0 -56
  633. package/src/hooks/session-recovery/storage/text-part-injector.ts +0 -63
  634. package/src/hooks/session-recovery/storage/thinking-block-search.ts +0 -42
  635. package/src/hooks/session-recovery/storage/thinking-prepend.ts +0 -223
  636. package/src/hooks/session-recovery/storage/thinking-strip.ts +0 -67
  637. package/src/hooks/session-recovery/storage.ts +0 -34
  638. package/src/hooks/session-recovery/types.ts +0 -101
  639. package/src/hooks/session-todo-status.ts +0 -20
  640. package/src/hooks/shared/compaction-model-resolver.ts +0 -34
  641. package/src/hooks/shared/shared/compaction-model-resolver.ts +0 -34
  642. package/src/hooks/start-work/context-info-builder.ts +0 -319
  643. package/src/hooks/start-work/index.ts +0 -4
  644. package/src/hooks/start-work/parse-user-request.ts +0 -32
  645. package/src/hooks/start-work/start-work-hook.ts +0 -135
  646. package/src/hooks/start-work/worktree-block.ts +0 -11
  647. package/src/hooks/start-work/worktree-detector.ts +0 -77
  648. package/src/hooks/stop-continuation-guard/hook.ts +0 -122
  649. package/src/hooks/stop-continuation-guard/index.ts +0 -2
  650. package/src/hooks/strategist-md-only/agent-matcher.ts +0 -5
  651. package/src/hooks/strategist-md-only/agent-resolution.ts +0 -70
  652. package/src/hooks/strategist-md-only/constants.ts +0 -78
  653. package/src/hooks/strategist-md-only/hook.ts +0 -82
  654. package/src/hooks/strategist-md-only/index.ts +0 -2
  655. package/src/hooks/strategist-md-only/path-policy.ts +0 -41
  656. package/src/hooks/sub-notepad/constants.ts +0 -29
  657. package/src/hooks/sub-notepad/hook.ts +0 -44
  658. package/src/hooks/sub-notepad/index.ts +0 -3
  659. package/src/hooks/task-reminder/hook.ts +0 -59
  660. package/src/hooks/task-reminder/index.ts +0 -1
  661. package/src/hooks/task-resume-info/hook.ts +0 -39
  662. package/src/hooks/task-resume-info/index.ts +0 -1
  663. package/src/hooks/tasks-todowrite-disabler/constants.ts +0 -30
  664. package/src/hooks/tasks-todowrite-disabler/hook.ts +0 -34
  665. package/src/hooks/tasks-todowrite-disabler/index.ts +0 -2
  666. package/src/hooks/think-mode/detector.ts +0 -59
  667. package/src/hooks/think-mode/hook.ts +0 -76
  668. package/src/hooks/think-mode/index.ts +0 -5
  669. package/src/hooks/think-mode/switcher.ts +0 -100
  670. package/src/hooks/think-mode/types.ts +0 -16
  671. package/src/hooks/thinking-block-validator/hook.ts +0 -181
  672. package/src/hooks/thinking-block-validator/index.ts +0 -1
  673. package/src/hooks/todo-continuation-enforcer/AGENTS.md +0 -65
  674. package/src/hooks/todo-continuation-enforcer/abort-detection.ts +0 -17
  675. package/src/hooks/todo-continuation-enforcer/compaction-guard.ts +0 -39
  676. package/src/hooks/todo-continuation-enforcer/constants.ts +0 -25
  677. package/src/hooks/todo-continuation-enforcer/continuation-injection.ts +0 -222
  678. package/src/hooks/todo-continuation-enforcer/countdown.ts +0 -86
  679. package/src/hooks/todo-continuation-enforcer/handler.ts +0 -99
  680. package/src/hooks/todo-continuation-enforcer/idle-event.ts +0 -225
  681. package/src/hooks/todo-continuation-enforcer/index.ts +0 -59
  682. package/src/hooks/todo-continuation-enforcer/message-directory.ts +0 -1
  683. package/src/hooks/todo-continuation-enforcer/non-idle-events.ts +0 -107
  684. package/src/hooks/todo-continuation-enforcer/pending-question-detection.ts +0 -40
  685. package/src/hooks/todo-continuation-enforcer/resolve-message-info.ts +0 -48
  686. package/src/hooks/todo-continuation-enforcer/session-state.ts +0 -283
  687. package/src/hooks/todo-continuation-enforcer/stagnation-detection.ts +0 -36
  688. package/src/hooks/todo-continuation-enforcer/todo.ts +0 -11
  689. package/src/hooks/todo-continuation-enforcer/token-limit-detection.ts +0 -38
  690. package/src/hooks/todo-continuation-enforcer/types.ts +0 -74
  691. package/src/hooks/todo-description-override/description.ts +0 -28
  692. package/src/hooks/todo-description-override/hook.ts +0 -14
  693. package/src/hooks/todo-description-override/index.ts +0 -1
  694. package/src/hooks/tool-output-truncator.ts +0 -66
  695. package/src/hooks/tool-pair-validator/hook.ts +0 -184
  696. package/src/hooks/tool-pair-validator/index.ts +0 -1
  697. package/src/hooks/unstable-agent-babysitter/index.ts +0 -9
  698. package/src/hooks/unstable-agent-babysitter/task-message-analyzer.ts +0 -110
  699. package/src/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.ts +0 -238
  700. package/src/hooks/webfetch-redirect-guard/constants.ts +0 -11
  701. package/src/hooks/webfetch-redirect-guard/hook.ts +0 -123
  702. package/src/hooks/webfetch-redirect-guard/index.ts +0 -1
  703. package/src/hooks/webfetch-redirect-guard/redirect-resolution.ts +0 -89
  704. package/src/hooks/write-existing-file-guard/hook.ts +0 -108
  705. package/src/hooks/write-existing-file-guard/index.ts +0 -1
  706. package/src/hooks/write-existing-file-guard/session-read-permissions.ts +0 -36
  707. package/src/hooks/write-existing-file-guard/tool-execute-before-handler.ts +0 -176
  708. package/src/index.ts +0 -254
  709. package/src/internals/plugins/pty/LICENSE +0 -21
  710. package/src/internals/plugins/pty/constants.ts +0 -7
  711. package/src/internals/plugins/pty/plugin.ts +0 -28
  712. package/src/internals/plugins/pty/pty/buffer.ts +0 -75
  713. package/src/internals/plugins/pty/pty/formatters.ts +0 -22
  714. package/src/internals/plugins/pty/pty/manager.ts +0 -175
  715. package/src/internals/plugins/pty/pty/notification-manager.ts +0 -75
  716. package/src/internals/plugins/pty/pty/output-manager.ts +0 -29
  717. package/src/internals/plugins/pty/pty/permissions.ts +0 -115
  718. package/src/internals/plugins/pty/pty/session-lifecycle.ts +0 -161
  719. package/src/internals/plugins/pty/pty/tools/kill.ts +0 -41
  720. package/src/internals/plugins/pty/pty/tools/kill.txt +0 -25
  721. package/src/internals/plugins/pty/pty/tools/list.ts +0 -25
  722. package/src/internals/plugins/pty/pty/tools/list.txt +0 -22
  723. package/src/internals/plugins/pty/pty/tools/read.ts +0 -234
  724. package/src/internals/plugins/pty/pty/tools/read.txt +0 -39
  725. package/src/internals/plugins/pty/pty/tools/spawn.ts +0 -71
  726. package/src/internals/plugins/pty/pty/tools/spawn.txt +0 -47
  727. package/src/internals/plugins/pty/pty/tools/write.ts +0 -96
  728. package/src/internals/plugins/pty/pty/tools/write.txt +0 -28
  729. package/src/internals/plugins/pty/pty/types.ts +0 -67
  730. package/src/internals/plugins/pty/pty/utils.ts +0 -21
  731. package/src/internals/plugins/pty/pty/wildcard.ts +0 -62
  732. package/src/internals/plugins/pty/shared/constants.ts +0 -7
  733. package/src/internals/plugins/pty/types.ts +0 -7
  734. package/src/internals/plugins/subtask2/LICENSE +0 -128
  735. package/src/internals/plugins/subtask2/commands/index.ts +0 -7
  736. package/src/internals/plugins/subtask2/commands/loader.ts +0 -39
  737. package/src/internals/plugins/subtask2/commands/manifest.ts +0 -60
  738. package/src/internals/plugins/subtask2/commands/resolver.ts +0 -28
  739. package/src/internals/plugins/subtask2/core/plugin.ts +0 -52
  740. package/src/internals/plugins/subtask2/core/state.ts +0 -764
  741. package/src/internals/plugins/subtask2/features/auto.ts +0 -57
  742. package/src/internals/plugins/subtask2/features/index.ts +0 -9
  743. package/src/internals/plugins/subtask2/features/inline-subtasks.ts +0 -205
  744. package/src/internals/plugins/subtask2/features/parallel.ts +0 -148
  745. package/src/internals/plugins/subtask2/features/results.ts +0 -48
  746. package/src/internals/plugins/subtask2/features/returns.ts +0 -273
  747. package/src/internals/plugins/subtask2/features/turns.ts +0 -190
  748. package/src/internals/plugins/subtask2/hooks/command-hooks.ts +0 -283
  749. package/src/internals/plugins/subtask2/hooks/message-hooks.ts +0 -603
  750. package/src/internals/plugins/subtask2/hooks/session-idle-hook.ts +0 -358
  751. package/src/internals/plugins/subtask2/hooks/tool-hooks.ts +0 -309
  752. package/src/internals/plugins/subtask2/loop.ts +0 -122
  753. package/src/internals/plugins/subtask2/parsing/auto.ts +0 -33
  754. package/src/internals/plugins/subtask2/parsing/commands.ts +0 -154
  755. package/src/internals/plugins/subtask2/parsing/frontmatter.ts +0 -20
  756. package/src/internals/plugins/subtask2/parsing/index.ts +0 -10
  757. package/src/internals/plugins/subtask2/parsing/overrides.ts +0 -68
  758. package/src/internals/plugins/subtask2/parsing/parallel.ts +0 -91
  759. package/src/internals/plugins/subtask2/parsing/turns.ts +0 -78
  760. package/src/internals/plugins/subtask2/types.ts +0 -41
  761. package/src/internals/plugins/subtask2/utils/config.ts +0 -100
  762. package/src/internals/plugins/subtask2/utils/index.ts +0 -7
  763. package/src/internals/plugins/subtask2/utils/logger.ts +0 -67
  764. package/src/internals/plugins/subtask2/utils/prompts.ts +0 -117
  765. package/src/lsp/index.ts +0 -16
  766. package/src/mcp/context7.ts +0 -9
  767. package/src/mcp/index.ts +0 -53
  768. package/src/mcp/registry.ts +0 -164
  769. package/src/mcp/types.ts +0 -19
  770. package/src/permissions/index.ts +0 -25
  771. package/src/plugin/AGENTS.md +0 -54
  772. package/src/plugin/available-categories.ts +0 -24
  773. package/src/plugin/chat-headers.ts +0 -141
  774. package/src/plugin/chat-message.ts +0 -307
  775. package/src/plugin/chat-params.ts +0 -182
  776. package/src/plugin/command-execute-before.ts +0 -80
  777. package/src/plugin/event.ts +0 -639
  778. package/src/plugin/hooks/create-continuation-hooks.ts +0 -128
  779. package/src/plugin/hooks/create-core-hooks.ts +0 -47
  780. package/src/plugin/hooks/create-session-hooks.ts +0 -269
  781. package/src/plugin/hooks/create-skill-hooks.ts +0 -50
  782. package/src/plugin/hooks/create-tool-guard-hooks.ts +0 -159
  783. package/src/plugin/hooks/create-transform-hooks.ts +0 -85
  784. package/src/plugin/messages-transform.ts +0 -28
  785. package/src/plugin/normalize-tool-arg-schemas.ts +0 -75
  786. package/src/plugin/recent-synthetic-idles.ts +0 -20
  787. package/src/plugin/session-agent-resolver.ts +0 -37
  788. package/src/plugin/session-status-normalizer.ts +0 -22
  789. package/src/plugin/skill-context.ts +0 -150
  790. package/src/plugin/skill-discovery-config.ts +0 -32
  791. package/src/plugin/startup-diagnostics.ts +0 -27
  792. package/src/plugin/system-transform.ts +0 -6
  793. package/src/plugin/tool-execute-after.ts +0 -178
  794. package/src/plugin/tool-execute-before.ts +0 -222
  795. package/src/plugin/tool-registry.ts +0 -286
  796. package/src/plugin/types.ts +0 -26
  797. package/src/plugin/ultrawork-db-model-override.ts +0 -142
  798. package/src/plugin/ultrawork-model-override.ts +0 -196
  799. package/src/plugin/ultrawork-variant-availability.ts +0 -51
  800. package/src/plugin/unstable-agent-babysitter.ts +0 -41
  801. package/src/plugin-config.ts +0 -314
  802. package/src/plugin-dispose.ts +0 -51
  803. package/src/plugin-handlers/AGENTS.md +0 -92
  804. package/src/plugin-handlers/agent-config-handler.ts +0 -510
  805. package/src/plugin-handlers/agent-key-remapper.ts +0 -39
  806. package/src/plugin-handlers/agent-override-protection.ts +0 -38
  807. package/src/plugin-handlers/agent-priority-order.ts +0 -63
  808. package/src/plugin-handlers/category-config-resolver.ts +0 -9
  809. package/src/plugin-handlers/command-config-handler.ts +0 -115
  810. package/src/plugin-handlers/config-handler.ts +0 -61
  811. package/src/plugin-handlers/index.ts +0 -10
  812. package/src/plugin-handlers/mcp-config-handler.test.ts +0 -63
  813. package/src/plugin-handlers/mcp-config-handler.ts +0 -220
  814. package/src/plugin-handlers/plan-model-inheritance.ts +0 -27
  815. package/src/plugin-handlers/plugin-components-loader.ts +0 -70
  816. package/src/plugin-handlers/provider-config-handler.ts +0 -73
  817. package/src/plugin-handlers/strategist-agent-config-builder.ts +0 -128
  818. package/src/plugin-handlers/tool-config-handler.ts +0 -193
  819. package/src/plugin-interface.ts +0 -83
  820. package/src/plugin-state.ts +0 -18
  821. package/src/shared/AGENTS.md +0 -54
  822. package/src/shared/agent-display-names.test.ts +0 -9
  823. package/src/shared/agent-display-names.ts +0 -187
  824. package/src/shared/agent-tool-restrictions.ts +0 -80
  825. package/src/shared/agent-variant.ts +0 -101
  826. package/src/shared/agents-config-dir.ts +0 -23
  827. package/src/shared/archive-entry-validator.ts +0 -83
  828. package/src/shared/background-output-consumption.ts +0 -69
  829. package/src/shared/binary-downloader.ts +0 -127
  830. package/src/shared/claude-config-dir.ts +0 -16
  831. package/src/shared/closure-protocol.ts +0 -53
  832. package/src/shared/command-executor/embedded-commands.ts +0 -26
  833. package/src/shared/command-executor/execute-command.ts +0 -28
  834. package/src/shared/command-executor/execute-hook-command.ts +0 -129
  835. package/src/shared/command-executor/home-directory.ts +0 -5
  836. package/src/shared/command-executor/resolve-commands-in-text.ts +0 -49
  837. package/src/shared/command-executor/shell-path.ts +0 -27
  838. package/src/shared/command-executor.ts +0 -5
  839. package/src/shared/compaction-agent-config-checkpoint.ts +0 -42
  840. package/src/shared/compaction-marker.ts +0 -61
  841. package/src/shared/config-errors.ts +0 -18
  842. package/src/shared/connected-providers-cache.ts +0 -215
  843. package/src/shared/contains-path.ts +0 -50
  844. package/src/shared/context-limit-resolver.ts +0 -42
  845. package/src/shared/data-path.ts +0 -64
  846. package/src/shared/deep-merge.ts +0 -53
  847. package/src/shared/disabled-tools.ts +0 -19
  848. package/src/shared/dynamic-truncator.ts +0 -222
  849. package/src/shared/external-plugin-detector.ts +0 -139
  850. package/src/shared/fallback-chain-from-models.ts +0 -124
  851. package/src/shared/fallback-model-availability.ts +0 -102
  852. package/src/shared/file-reference-resolver.ts +0 -99
  853. package/src/shared/file-utils.ts +0 -34
  854. package/src/shared/first-message-variant.ts +0 -28
  855. package/src/shared/frontmatter.ts +0 -31
  856. package/src/shared/git-worktree/collect-git-diff-stats.ts +0 -56
  857. package/src/shared/git-worktree/format-file-changes.ts +0 -46
  858. package/src/shared/git-worktree/index.ts +0 -7
  859. package/src/shared/git-worktree/parse-diff-numstat.ts +0 -27
  860. package/src/shared/git-worktree/parse-status-porcelain-line.ts +0 -27
  861. package/src/shared/git-worktree/parse-status-porcelain.ts +0 -15
  862. package/src/shared/git-worktree/types.ts +0 -8
  863. package/src/shared/hook-disabled.ts +0 -22
  864. package/src/shared/index.ts +0 -80
  865. package/src/shared/internal-initiator-marker.ts +0 -18
  866. package/src/shared/is-abort-error.ts +0 -20
  867. package/src/shared/json-file-cache-store.ts +0 -98
  868. package/src/shared/jsonc-parser.ts +0 -98
  869. package/src/shared/known-variants.ts +0 -16
  870. package/src/shared/legacy-plugin-warning.ts +0 -68
  871. package/src/shared/load-opencode-plugins.ts +0 -60
  872. package/src/shared/log-legacy-plugin-startup-warning.ts +0 -44
  873. package/src/shared/logger.ts +0 -56
  874. package/src/shared/mcp-static-export.ts +0 -119
  875. package/src/shared/merge-categories.ts +0 -18
  876. package/src/shared/migrate-legacy-config-file.ts +0 -66
  877. package/src/shared/migrate-legacy-plugin-entry.ts +0 -75
  878. package/src/shared/migration/agent-category.ts +0 -60
  879. package/src/shared/migration/agent-names.ts +0 -108
  880. package/src/shared/migration/config-migration.ts +0 -210
  881. package/src/shared/migration/hook-names.ts +0 -40
  882. package/src/shared/migration/migrations-sidecar.ts +0 -92
  883. package/src/shared/migration/model-versions.ts +0 -50
  884. package/src/shared/migration.ts +0 -5
  885. package/src/shared/mode-routing.test.ts +0 -88
  886. package/src/shared/mode-routing.ts +0 -30
  887. package/src/shared/model-availability.ts +0 -294
  888. package/src/shared/model-capabilities/bundled-snapshot.ts +0 -15
  889. package/src/shared/model-capabilities/get-model-capabilities.ts +0 -140
  890. package/src/shared/model-capabilities/index.ts +0 -9
  891. package/src/shared/model-capabilities/runtime-model-readers.ts +0 -190
  892. package/src/shared/model-capabilities/types.ts +0 -80
  893. package/src/shared/model-capabilities-cache.ts +0 -213
  894. package/src/shared/model-capability-aliases.ts +0 -108
  895. package/src/shared/model-capability-guardrails.ts +0 -149
  896. package/src/shared/model-capability-heuristics.ts +0 -32
  897. package/src/shared/model-error-classifier.ts +0 -214
  898. package/src/shared/model-format-normalizer.ts +0 -20
  899. package/src/shared/model-normalization.ts +0 -8
  900. package/src/shared/model-requirements.ts +0 -26
  901. package/src/shared/model-resolution-pipeline.ts +0 -216
  902. package/src/shared/model-resolution-types.ts +0 -41
  903. package/src/shared/model-resolver.ts +0 -106
  904. package/src/shared/model-sanitizer.ts +0 -12
  905. package/src/shared/model-settings-compatibility.ts +0 -200
  906. package/src/shared/model-suggestion-retry.ts +0 -182
  907. package/src/shared/normalize-sdk-response.ts +0 -36
  908. package/src/shared/opencode-command-dirs.ts +0 -36
  909. package/src/shared/opencode-config-dir-types.ts +0 -15
  910. package/src/shared/opencode-config-dir.ts +0 -135
  911. package/src/shared/opencode-http-api.ts +0 -140
  912. package/src/shared/opencode-message-dir.ts +0 -29
  913. package/src/shared/opencode-server-auth.ts +0 -190
  914. package/src/shared/opencode-storage-detection.ts +0 -34
  915. package/src/shared/opencode-storage-paths.ts +0 -7
  916. package/src/shared/opencode-version.ts +0 -80
  917. package/src/shared/parse-tools-config.ts +0 -25
  918. package/src/shared/pattern-matcher.ts +0 -46
  919. package/src/shared/permission-compat.ts +0 -86
  920. package/src/shared/plugin-command-discovery.ts +0 -28
  921. package/src/shared/plugin-entry-migrator.ts +0 -21
  922. package/src/shared/plugin-identity.ts +0 -8
  923. package/src/shared/port-utils.ts +0 -48
  924. package/src/shared/project-discovery-dirs.ts +0 -101
  925. package/src/shared/prompt-timeout-context.ts +0 -49
  926. package/src/shared/prompt-tools.ts +0 -35
  927. package/src/shared/provider-model-id-transform.ts +0 -58
  928. package/src/shared/question-denied-session-permission.ts +0 -9
  929. package/src/shared/record-type-guard.ts +0 -3
  930. package/src/shared/resolve-agent-definition-paths.ts +0 -22
  931. package/src/shared/retry-status-utils.ts +0 -19
  932. package/src/shared/runtime-plugin-config.ts +0 -98
  933. package/src/shared/safe-create-hook.ts +0 -24
  934. package/src/shared/session-category-registry.ts +0 -27
  935. package/src/shared/session-cursor.ts +0 -108
  936. package/src/shared/session-directory-resolver.ts +0 -41
  937. package/src/shared/session-injected-paths.ts +0 -59
  938. package/src/shared/session-model-state.ts +0 -15
  939. package/src/shared/session-prompt-params-helpers.ts +0 -31
  940. package/src/shared/session-prompt-params-state.ts +0 -37
  941. package/src/shared/session-tools-store.ts +0 -18
  942. package/src/shared/session-utils.ts +0 -25
  943. package/src/shared/shell-env.ts +0 -175
  944. package/src/shared/skill-path-resolver.ts +0 -26
  945. package/src/shared/snake-case.ts +0 -44
  946. package/src/shared/spawn-with-windows-hide.ts +0 -84
  947. package/src/shared/startup-diagnostics.ts +0 -76
  948. package/src/shared/system-directive.ts +0 -67
  949. package/src/shared/task-system-enabled.ts +0 -9
  950. package/src/shared/tmux/constants.ts +0 -12
  951. package/src/shared/tmux/index.ts +0 -3
  952. package/src/shared/tmux/tmux-utils/environment.ts +0 -13
  953. package/src/shared/tmux/tmux-utils/layout.ts +0 -96
  954. package/src/shared/tmux/tmux-utils/pane-close.ts +0 -48
  955. package/src/shared/tmux/tmux-utils/pane-dimensions.ts +0 -28
  956. package/src/shared/tmux/tmux-utils/pane-replace.ts +0 -73
  957. package/src/shared/tmux/tmux-utils/pane-spawn.ts +0 -94
  958. package/src/shared/tmux/tmux-utils/server-health.ts +0 -62
  959. package/src/shared/tmux/tmux-utils/session-spawn.ts +0 -145
  960. package/src/shared/tmux/tmux-utils/window-spawn.ts +0 -93
  961. package/src/shared/tmux/tmux-utils.ts +0 -15
  962. package/src/shared/tmux/types.ts +0 -4
  963. package/src/shared/tool-name.ts +0 -27
  964. package/src/shared/truncate-description.ts +0 -11
  965. package/src/shared/vision-capable-models-cache.ts +0 -17
  966. package/src/shared/write-file-atomically.ts +0 -31
  967. package/src/shared/zip-entry-listing/powershell-zip-entry-listing.ts +0 -99
  968. package/src/shared/zip-entry-listing/python-zip-entry-listing.ts +0 -55
  969. package/src/shared/zip-entry-listing/read-zip-symlink-target.ts +0 -23
  970. package/src/shared/zip-entry-listing/tar-zip-entry-listing.ts +0 -93
  971. package/src/shared/zip-entry-listing/zipinfo-zip-entry-listing.ts +0 -72
  972. package/src/shared/zip-entry-listing.ts +0 -13
  973. package/src/shared/zip-extractor.ts +0 -118
  974. package/src/skills/index.ts +0 -56
  975. package/src/testing/module-mock-lifecycle.ts +0 -143
  976. package/src/tools/AGENTS.md +0 -108
  977. package/src/tools/ast-grep/cli-binary-path-resolution.ts +0 -60
  978. package/src/tools/ast-grep/cli.ts +0 -177
  979. package/src/tools/ast-grep/constants.ts +0 -5
  980. package/src/tools/ast-grep/downloader.ts +0 -119
  981. package/src/tools/ast-grep/environment-check.ts +0 -59
  982. package/src/tools/ast-grep/index.ts +0 -5
  983. package/src/tools/ast-grep/language-support.ts +0 -60
  984. package/src/tools/ast-grep/process-output-timeout.ts +0 -28
  985. package/src/tools/ast-grep/result-formatter.ts +0 -102
  986. package/src/tools/ast-grep/sg-cli-path.ts +0 -102
  987. package/src/tools/ast-grep/sg-compact-json-output.ts +0 -54
  988. package/src/tools/ast-grep/tools.ts +0 -117
  989. package/src/tools/ast-grep/types.ts +0 -60
  990. package/src/tools/background-task/AGENTS.md +0 -53
  991. package/src/tools/background-task/clients.ts +0 -32
  992. package/src/tools/background-task/constants.ts +0 -9
  993. package/src/tools/background-task/create-background-cancel.ts +0 -115
  994. package/src/tools/background-task/create-background-output.ts +0 -159
  995. package/src/tools/background-task/create-background-task.ts +0 -126
  996. package/src/tools/background-task/delay.ts +0 -3
  997. package/src/tools/background-task/full-session-format.ts +0 -148
  998. package/src/tools/background-task/index.ts +0 -8
  999. package/src/tools/background-task/message-dir.ts +0 -1
  1000. package/src/tools/background-task/session-messages.ts +0 -22
  1001. package/src/tools/background-task/task-result-format.ts +0 -113
  1002. package/src/tools/background-task/task-status-format.ts +0 -72
  1003. package/src/tools/background-task/time-format.ts +0 -30
  1004. package/src/tools/background-task/tools.ts +0 -11
  1005. package/src/tools/background-task/truncate-text.ts +0 -4
  1006. package/src/tools/background-task/types.ts +0 -72
  1007. package/src/tools/call-omo-agent/AGENTS.md +0 -51
  1008. package/src/tools/call-omo-agent/agent-resolver.ts +0 -64
  1009. package/src/tools/call-omo-agent/background-agent-executor.ts +0 -91
  1010. package/src/tools/call-omo-agent/background-executor.ts +0 -98
  1011. package/src/tools/call-omo-agent/completion-poller.ts +0 -65
  1012. package/src/tools/call-omo-agent/constants.ts +0 -23
  1013. package/src/tools/call-omo-agent/index.ts +0 -3
  1014. package/src/tools/call-omo-agent/message-dir.ts +0 -1
  1015. package/src/tools/call-omo-agent/message-processor.ts +0 -86
  1016. package/src/tools/call-omo-agent/message-storage-directory.ts +0 -1
  1017. package/src/tools/call-omo-agent/session-creator.ts +0 -70
  1018. package/src/tools/call-omo-agent/subagent-session-creator.ts +0 -74
  1019. package/src/tools/call-omo-agent/sync-executor.ts +0 -148
  1020. package/src/tools/call-omo-agent/tool-context-with-metadata.ts +0 -10
  1021. package/src/tools/call-omo-agent/tools.ts +0 -199
  1022. package/src/tools/call-omo-agent/types.ts +0 -34
  1023. package/src/tools/delegate-task/AGENTS.md +0 -58
  1024. package/src/tools/delegate-task/anthropic-categories.ts +0 -62
  1025. package/src/tools/delegate-task/available-models.ts +0 -64
  1026. package/src/tools/delegate-task/background-continuation.ts +0 -68
  1027. package/src/tools/delegate-task/background-task.ts +0 -165
  1028. package/src/tools/delegate-task/builtin-categories.ts +0 -35
  1029. package/src/tools/delegate-task/builtin-category-definition.ts +0 -8
  1030. package/src/tools/delegate-task/cancel-unstable-agent-task.ts +0 -19
  1031. package/src/tools/delegate-task/categories.test.ts +0 -87
  1032. package/src/tools/delegate-task/categories.ts +0 -77
  1033. package/src/tools/delegate-task/category-resolver.ts +0 -309
  1034. package/src/tools/delegate-task/constants.ts +0 -351
  1035. package/src/tools/delegate-task/delegated-model-config.ts +0 -20
  1036. package/src/tools/delegate-task/error-formatting.ts +0 -51
  1037. package/src/tools/delegate-task/executor-types.ts +0 -39
  1038. package/src/tools/delegate-task/executor.ts +0 -16
  1039. package/src/tools/delegate-task/fallback-entry-resolution.ts +0 -27
  1040. package/src/tools/delegate-task/fallback-entry-settings.ts +0 -20
  1041. package/src/tools/delegate-task/git-categories.ts +0 -30
  1042. package/src/tools/delegate-task/google-categories.ts +0 -130
  1043. package/src/tools/delegate-task/index.ts +0 -4
  1044. package/src/tools/delegate-task/kimi-categories.ts +0 -40
  1045. package/src/tools/delegate-task/model-selection.ts +0 -201
  1046. package/src/tools/delegate-task/model-string-parser.test.ts +0 -90
  1047. package/src/tools/delegate-task/model-string-parser.ts +0 -63
  1048. package/src/tools/delegate-task/openai-categories.ts +0 -132
  1049. package/src/tools/delegate-task/parent-context-resolver.ts +0 -47
  1050. package/src/tools/delegate-task/prompt-builder.ts +0 -107
  1051. package/src/tools/delegate-task/resolve-call-id.ts +0 -5
  1052. package/src/tools/delegate-task/skill-resolver.ts +0 -22
  1053. package/src/tools/delegate-task/sub-agent.ts +0 -80
  1054. package/src/tools/delegate-task/subagent-discovery.test.ts +0 -123
  1055. package/src/tools/delegate-task/subagent-discovery.ts +0 -152
  1056. package/src/tools/delegate-task/subagent-resolver.ts +0 -242
  1057. package/src/tools/delegate-task/sync-continuation-deps.ts +0 -9
  1058. package/src/tools/delegate-task/sync-continuation.ts +0 -149
  1059. package/src/tools/delegate-task/sync-prompt-sender.ts +0 -137
  1060. package/src/tools/delegate-task/sync-result-fetcher.ts +0 -60
  1061. package/src/tools/delegate-task/sync-session-creator.ts +0 -29
  1062. package/src/tools/delegate-task/sync-session-poller.ts +0 -188
  1063. package/src/tools/delegate-task/sync-task-deps.ts +0 -13
  1064. package/src/tools/delegate-task/sync-task-fallback.ts +0 -68
  1065. package/src/tools/delegate-task/sync-task.ts +0 -243
  1066. package/src/tools/delegate-task/time-formatter.ts +0 -13
  1067. package/src/tools/delegate-task/timing.ts +0 -46
  1068. package/src/tools/delegate-task/token-limiter.ts +0 -123
  1069. package/src/tools/delegate-task/tools.ts +0 -259
  1070. package/src/tools/delegate-task/types.ts +0 -89
  1071. package/src/tools/delegate-task/unstable-agent-task.ts +0 -243
  1072. package/src/tools/glob/cli.ts +0 -206
  1073. package/src/tools/glob/constants.ts +0 -12
  1074. package/src/tools/glob/index.ts +0 -1
  1075. package/src/tools/glob/result-formatter.ts +0 -26
  1076. package/src/tools/glob/tools.ts +0 -49
  1077. package/src/tools/glob/types.ts +0 -23
  1078. package/src/tools/grep/cli.ts +0 -279
  1079. package/src/tools/grep/constants.ts +0 -141
  1080. package/src/tools/grep/downloader.ts +0 -128
  1081. package/src/tools/grep/index.ts +0 -1
  1082. package/src/tools/grep/result-formatter.ts +0 -60
  1083. package/src/tools/grep/tools.ts +0 -75
  1084. package/src/tools/grep/types.ts +0 -42
  1085. package/src/tools/hashline-edit/AGENTS.md +0 -92
  1086. package/src/tools/hashline-edit/autocorrect-replacement-lines.ts +0 -179
  1087. package/src/tools/hashline-edit/constants.ts +0 -10
  1088. package/src/tools/hashline-edit/diff-utils.ts +0 -53
  1089. package/src/tools/hashline-edit/edit-deduplication.ts +0 -43
  1090. package/src/tools/hashline-edit/edit-operation-primitives.ts +0 -126
  1091. package/src/tools/hashline-edit/edit-operations.ts +0 -103
  1092. package/src/tools/hashline-edit/edit-ordering.ts +0 -56
  1093. package/src/tools/hashline-edit/edit-text-normalization.ts +0 -111
  1094. package/src/tools/hashline-edit/file-text-canonicalization.ts +0 -44
  1095. package/src/tools/hashline-edit/formatter-trigger.ts +0 -132
  1096. package/src/tools/hashline-edit/hash-computation.ts +0 -154
  1097. package/src/tools/hashline-edit/hashline-chunk-formatter.ts +0 -52
  1098. package/src/tools/hashline-edit/hashline-edit-diff.ts +0 -31
  1099. package/src/tools/hashline-edit/hashline-edit-executor.ts +0 -197
  1100. package/src/tools/hashline-edit/index.ts +0 -20
  1101. package/src/tools/hashline-edit/normalize-edits.ts +0 -95
  1102. package/src/tools/hashline-edit/tool-description.ts +0 -95
  1103. package/src/tools/hashline-edit/tools.ts +0 -42
  1104. package/src/tools/hashline-edit/types.ts +0 -20
  1105. package/src/tools/hashline-edit/validation.ts +0 -181
  1106. package/src/tools/index.ts +0 -64
  1107. package/src/tools/interactive-bash/constants.ts +0 -18
  1108. package/src/tools/interactive-bash/index.ts +0 -4
  1109. package/src/tools/interactive-bash/tmux-path-resolver.ts +0 -71
  1110. package/src/tools/interactive-bash/tools.ts +0 -136
  1111. package/src/tools/look-at/assistant-message-extractor.ts +0 -67
  1112. package/src/tools/look-at/constants.ts +0 -3
  1113. package/src/tools/look-at/image-converter.ts +0 -164
  1114. package/src/tools/look-at/index.ts +0 -3
  1115. package/src/tools/look-at/look-at-arguments.ts +0 -34
  1116. package/src/tools/look-at/mime-type-inference.ts +0 -94
  1117. package/src/tools/look-at/multimodal-agent-metadata.ts +0 -166
  1118. package/src/tools/look-at/multimodal-fallback-chain.ts +0 -66
  1119. package/src/tools/look-at/session-poller.ts +0 -42
  1120. package/src/tools/look-at/tools.ts +0 -245
  1121. package/src/tools/look-at/types.ts +0 -5
  1122. package/src/tools/lsp/AGENTS.md +0 -70
  1123. package/src/tools/lsp/client.ts +0 -3
  1124. package/src/tools/lsp/config.ts +0 -3
  1125. package/src/tools/lsp/constants.ts +0 -7
  1126. package/src/tools/lsp/diagnostics-tool.ts +0 -75
  1127. package/src/tools/lsp/directory-diagnostics.ts +0 -163
  1128. package/src/tools/lsp/find-references-tool.ts +0 -43
  1129. package/src/tools/lsp/goto-definition-tool.ts +0 -42
  1130. package/src/tools/lsp/index.ts +0 -9
  1131. package/src/tools/lsp/infer-extension.ts +0 -65
  1132. package/src/tools/lsp/language-config.ts +0 -5
  1133. package/src/tools/lsp/language-mappings.ts +0 -171
  1134. package/src/tools/lsp/lsp-client-connection.ts +0 -66
  1135. package/src/tools/lsp/lsp-client-transport.ts +0 -210
  1136. package/src/tools/lsp/lsp-client-wrapper.ts +0 -116
  1137. package/src/tools/lsp/lsp-client.ts +0 -129
  1138. package/src/tools/lsp/lsp-formatters.ts +0 -193
  1139. package/src/tools/lsp/lsp-manager-process-cleanup.ts +0 -83
  1140. package/src/tools/lsp/lsp-manager-temp-directory-cleanup.ts +0 -29
  1141. package/src/tools/lsp/lsp-process.ts +0 -158
  1142. package/src/tools/lsp/lsp-server.ts +0 -217
  1143. package/src/tools/lsp/rename-tools.ts +0 -53
  1144. package/src/tools/lsp/server-config-loader.ts +0 -116
  1145. package/src/tools/lsp/server-definitions.ts +0 -91
  1146. package/src/tools/lsp/server-installation.ts +0 -58
  1147. package/src/tools/lsp/server-path-bases.ts +0 -16
  1148. package/src/tools/lsp/server-resolution.ts +0 -109
  1149. package/src/tools/lsp/symbols-tool.ts +0 -76
  1150. package/src/tools/lsp/tools.ts +0 -5
  1151. package/src/tools/lsp/types.ts +0 -124
  1152. package/src/tools/lsp/workspace-edit.ts +0 -121
  1153. package/src/tools/session-manager/constants.ts +0 -93
  1154. package/src/tools/session-manager/file-storage.ts +0 -203
  1155. package/src/tools/session-manager/index.ts +0 -3
  1156. package/src/tools/session-manager/sdk-storage.ts +0 -135
  1157. package/src/tools/session-manager/sdk-unavailable.ts +0 -43
  1158. package/src/tools/session-manager/session-formatter.ts +0 -199
  1159. package/src/tools/session-manager/storage.ts +0 -161
  1160. package/src/tools/session-manager/tools.ts +0 -197
  1161. package/src/tools/session-manager/types.ts +0 -99
  1162. package/src/tools/shared/semaphore.ts +0 -32
  1163. package/src/tools/skill/constants.ts +0 -14
  1164. package/src/tools/skill/description-formatter.ts +0 -61
  1165. package/src/tools/skill/index.ts +0 -3
  1166. package/src/tools/skill/mcp-capability-formatter.ts +0 -97
  1167. package/src/tools/skill/native-skills.ts +0 -62
  1168. package/src/tools/skill/scope-priority.ts +0 -17
  1169. package/src/tools/skill/skill-body.ts +0 -26
  1170. package/src/tools/skill/skill-matcher.ts +0 -40
  1171. package/src/tools/skill/tools.ts +0 -196
  1172. package/src/tools/skill/types.ts +0 -48
  1173. package/src/tools/skill-mcp/constants.ts +0 -9
  1174. package/src/tools/skill-mcp/index.ts +0 -3
  1175. package/src/tools/skill-mcp/tools.test.ts +0 -44
  1176. package/src/tools/skill-mcp/tools.ts +0 -242
  1177. package/src/tools/skill-mcp/types.ts +0 -8
  1178. package/src/tools/slashcommand/command-discovery.ts +0 -161
  1179. package/src/tools/slashcommand/command-output-formatter.ts +0 -75
  1180. package/src/tools/slashcommand/index.ts +0 -2
  1181. package/src/tools/slashcommand/types.ts +0 -21
  1182. package/src/tools/task/index.ts +0 -7
  1183. package/src/tools/task/task-create.ts +0 -113
  1184. package/src/tools/task/task-get.ts +0 -47
  1185. package/src/tools/task/task-list.ts +0 -79
  1186. package/src/tools/task/task-update.ts +0 -152
  1187. package/src/tools/task/todo-sync.ts +0 -205
  1188. package/src/tools/task/types.ts +0 -77
@@ -1,2220 +0,0 @@
1
-
2
- import type { PluginInput } from "@opencode-ai/plugin"
3
- import { isAgentNotFoundError, FALLBACK_AGENT, buildFallbackBody } from "./spawner"
4
- import type {
5
- BackgroundTask,
6
- LaunchInput,
7
- ResumeInput,
8
- } from "./types"
9
- import { TaskHistory } from "./task-history"
10
- import {
11
- log,
12
- getAgentToolRestrictions,
13
- normalizePromptTools,
14
- normalizeSDKResponse,
15
- promptWithModelSuggestionRetry,
16
- resolveInheritedPromptTools,
17
- createInternalAgentTextPart,
18
- } from "../../shared"
19
- import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
20
- import { setSessionTools } from "../../shared/session-tools-store"
21
- import { SessionCategoryRegistry } from "../../shared/session-category-registry"
22
- import { ConcurrencyManager } from "./concurrency"
23
- import type { BackgroundTaskConfig, TmuxConfig } from "../../config/schema"
24
- import { isInsideTmux } from "../../shared/tmux"
25
- import {
26
- shouldRetryError,
27
- hasMoreFallbacks,
28
- } from "../../shared/model-error-classifier"
29
- import {
30
- POLLING_INTERVAL_MS,
31
- TASK_CLEANUP_DELAY_MS,
32
- TASK_TTL_MS,
33
- } from "./constants"
34
-
35
- import { subagentSessions } from "../claude-code-session-state"
36
- import { getTaskToastManager } from "../task-toast-manager"
37
- import { formatDuration } from "./duration-formatter"
38
- import {
39
- buildBackgroundTaskNotificationText,
40
- type BackgroundTaskNotificationTask,
41
- } from "./background-task-notification-template"
42
- import {
43
- isAbortedSessionError,
44
- extractErrorName,
45
- extractErrorMessage,
46
- getSessionErrorMessage,
47
- isRecord,
48
- } from "./error-classifier"
49
- import { tryFallbackRetry } from "./fallback-retry-handler"
50
- import { registerManagerForCleanup, unregisterManagerForCleanup } from "./process-cleanup"
51
- import {
52
- findNearestMessageExcludingCompaction,
53
- resolvePromptContextFromSessionMessages,
54
- } from "./compaction-aware-message-resolver"
55
- import { handleSessionIdleBackgroundEvent } from "./session-idle-event-handler"
56
- import { MESSAGE_STORAGE } from "../hook-message-injector"
57
- import { join } from "node:path"
58
- import { pruneStaleTasksAndNotifications } from "./task-poller"
59
- import { checkAndInterruptStaleTasks } from "./task-poller"
60
- import { removeTaskToastTracking } from "./remove-task-toast-tracking"
61
- import { abortWithTimeout } from "./abort-with-timeout"
62
- import {
63
- MIN_SESSION_GONE_POLLS,
64
- verifySessionExists as verifySessionStillExists,
65
- } from "./session-existence"
66
- import { isActiveSessionStatus, isTerminalSessionStatus } from "./session-status-classifier"
67
- import {
68
- detectRepetitiveToolUse,
69
- recordToolCall,
70
- resolveCircuitBreakerSettings,
71
- type CircuitBreakerSettings,
72
- } from "./loop-detector"
73
- import {
74
- createSubagentDepthLimitError,
75
- createSubagentDescendantLimitError,
76
- getMaxRootSessionSpawnBudget,
77
- getMaxSubagentDepth,
78
- resolveSubagentSpawnContext,
79
- type SubagentSpawnContext,
80
- } from "./subagent-spawn-limits"
81
-
82
- type OpencodeClient = PluginInput["client"]
83
-
84
-
85
- interface MessagePartInfo {
86
- id?: string
87
- sessionID?: string
88
- type?: string
89
- tool?: string
90
- state?: { status?: string; input?: Record<string, unknown> }
91
- }
92
-
93
- interface EventProperties {
94
- sessionID?: string
95
- info?: { id?: string }
96
- [key: string]: unknown
97
- }
98
-
99
- interface Event {
100
- type: string
101
- properties?: EventProperties
102
- }
103
-
104
- function resolveMessagePartInfo(properties: EventProperties | undefined): MessagePartInfo | undefined {
105
- if (!properties || typeof properties !== "object") {
106
- return undefined
107
- }
108
-
109
- const nestedPart = properties.part
110
- if (nestedPart && typeof nestedPart === "object") {
111
- return nestedPart as MessagePartInfo
112
- }
113
-
114
- return properties as MessagePartInfo
115
- }
116
-
117
- interface Todo {
118
- content: string
119
- status: string
120
- priority: string
121
- id: string
122
- }
123
-
124
- interface QueueItem {
125
- task: BackgroundTask
126
- input: LaunchInput
127
- }
128
-
129
- export interface SubagentSessionCreatedEvent {
130
- sessionID: string
131
- parentID: string
132
- title: string
133
- }
134
-
135
- export type OnSubagentSessionCreated = (event: SubagentSessionCreatedEvent) => Promise<void>
136
-
137
- const MAX_TASK_REMOVAL_RESCHEDULES = 6
138
-
139
- export class BackgroundManager {
140
-
141
-
142
- private tasks: Map<string, BackgroundTask>
143
- private notifications: Map<string, BackgroundTask[]>
144
- private pendingNotifications: Map<string, string[]>
145
- private pendingByParent: Map<string, Set<string>> // Track pending tasks per parent for batching
146
- private client: OpencodeClient
147
- private directory: string
148
- private pollingInterval?: ReturnType<typeof setInterval>
149
- private pollingInFlight = false
150
- private concurrencyManager: ConcurrencyManager
151
- private shutdownTriggered = false
152
- private config?: BackgroundTaskConfig
153
- private tmuxEnabled: boolean
154
- private onSubagentSessionCreated?: OnSubagentSessionCreated
155
- private onShutdown?: () => void | Promise<void>
156
-
157
- private queuesByKey: Map<string, QueueItem[]> = new Map()
158
- private processingKeys: Set<string> = new Set()
159
- private completionTimers: Map<string, ReturnType<typeof setTimeout>> = new Map()
160
- private completedTaskSummaries: Map<string, BackgroundTaskNotificationTask[]> = new Map()
161
- private idleDeferralTimers: Map<string, ReturnType<typeof setTimeout>> = new Map()
162
- private notificationQueueByParent: Map<string, Promise<void>> = new Map()
163
- private observedOutputSessions: Set<string> = new Set()
164
- private observedIncompleteTodosBySession: Map<string, boolean> = new Map()
165
- private rootDescendantCounts: Map<string, number>
166
- private preStartDescendantReservations: Set<string>
167
- private enableParentSessionNotifications: boolean
168
- readonly taskHistory = new TaskHistory()
169
- private cachedCircuitBreakerSettings?: CircuitBreakerSettings
170
-
171
- constructor(
172
- ctx: PluginInput,
173
- config?: BackgroundTaskConfig,
174
- options?: {
175
- tmuxConfig?: TmuxConfig
176
- onSubagentSessionCreated?: OnSubagentSessionCreated
177
- onShutdown?: () => void | Promise<void>
178
- enableParentSessionNotifications?: boolean
179
- }
180
- ) {
181
- this.tasks = new Map()
182
- this.notifications = new Map()
183
- this.pendingNotifications = new Map()
184
- this.pendingByParent = new Map()
185
- this.client = ctx.client
186
- this.directory = ctx.directory
187
- this.concurrencyManager = new ConcurrencyManager(config)
188
- this.config = config
189
- this.tmuxEnabled = options?.tmuxConfig?.enabled ?? false
190
- this.onSubagentSessionCreated = options?.onSubagentSessionCreated
191
- this.onShutdown = options?.onShutdown
192
- this.rootDescendantCounts = new Map()
193
- this.preStartDescendantReservations = new Set()
194
- this.enableParentSessionNotifications = options?.enableParentSessionNotifications ?? true
195
- this.registerProcessCleanup()
196
- }
197
-
198
- private async abortSessionWithLogging(sessionID: string, reason: string): Promise<void> {
199
- try {
200
- await abortWithTimeout(this.client, sessionID)
201
- } catch (error) {
202
- log(`[background-agent] Failed to abort session during ${reason}:`, {
203
- sessionID,
204
- error,
205
- })
206
- }
207
- }
208
-
209
- async assertCanSpawn(parentSessionID: string): Promise<SubagentSpawnContext> {
210
- const spawnContext = await resolveSubagentSpawnContext(this.client, parentSessionID, this.directory)
211
- const maxDepth = getMaxSubagentDepth(this.config)
212
- if (spawnContext.childDepth > maxDepth) {
213
- throw createSubagentDepthLimitError({
214
- childDepth: spawnContext.childDepth,
215
- maxDepth,
216
- parentSessionID,
217
- rootSessionID: spawnContext.rootSessionID,
218
- })
219
- }
220
-
221
- const maxRootSessionSpawnBudget = getMaxRootSessionSpawnBudget(this.config)
222
- const descendantCount = this.rootDescendantCounts.get(spawnContext.rootSessionID) ?? 0
223
- if (descendantCount >= maxRootSessionSpawnBudget) {
224
- throw createSubagentDescendantLimitError({
225
- rootSessionID: spawnContext.rootSessionID,
226
- descendantCount,
227
- maxDescendants: maxRootSessionSpawnBudget,
228
- })
229
- }
230
-
231
- return spawnContext
232
- }
233
-
234
- async reserveSubagentSpawn(parentSessionID: string): Promise<{
235
- spawnContext: SubagentSpawnContext
236
- descendantCount: number
237
- commit: () => number
238
- rollback: () => void
239
- }> {
240
- const spawnContext = await this.assertCanSpawn(parentSessionID)
241
- const descendantCount = this.registerRootDescendant(spawnContext.rootSessionID)
242
- let settled = false
243
-
244
- return {
245
- spawnContext,
246
- descendantCount,
247
- commit: () => {
248
- settled = true
249
- return descendantCount
250
- },
251
- rollback: () => {
252
- if (settled) return
253
- settled = true
254
- this.unregisterRootDescendant(spawnContext.rootSessionID)
255
- },
256
- }
257
- }
258
-
259
- private registerRootDescendant(rootSessionID: string): number {
260
- const nextCount = (this.rootDescendantCounts.get(rootSessionID) ?? 0) + 1
261
- this.rootDescendantCounts.set(rootSessionID, nextCount)
262
- return nextCount
263
- }
264
-
265
- private unregisterRootDescendant(rootSessionID: string): void {
266
- const currentCount = this.rootDescendantCounts.get(rootSessionID) ?? 0
267
- if (currentCount <= 1) {
268
- this.rootDescendantCounts.delete(rootSessionID)
269
- return
270
- }
271
-
272
- this.rootDescendantCounts.set(rootSessionID, currentCount - 1)
273
- }
274
-
275
- private markPreStartDescendantReservation(task: BackgroundTask): void {
276
- this.preStartDescendantReservations.add(task.id)
277
- }
278
-
279
- private settlePreStartDescendantReservation(task: BackgroundTask): void {
280
- this.preStartDescendantReservations.delete(task.id)
281
- }
282
-
283
- private rollbackPreStartDescendantReservation(task: BackgroundTask): void {
284
- if (!this.preStartDescendantReservations.delete(task.id)) {
285
- return
286
- }
287
-
288
- if (!task.rootSessionID) {
289
- return
290
- }
291
-
292
- this.unregisterRootDescendant(task.rootSessionID)
293
- }
294
-
295
- async launch(input: LaunchInput): Promise<BackgroundTask> {
296
- log("[background-agent] launch() called with:", {
297
- agent: input.agent,
298
- model: input.model,
299
- description: input.description,
300
- parentSessionID: input.parentSessionID,
301
- })
302
-
303
- if (!input.agent || input.agent.trim() === "") {
304
- throw new Error("Agent parameter is required")
305
- }
306
-
307
- const spawnReservation = await this.reserveSubagentSpawn(input.parentSessionID)
308
-
309
- try {
310
- log("[background-agent] spawn guard passed", {
311
- parentSessionID: input.parentSessionID,
312
- rootSessionID: spawnReservation.spawnContext.rootSessionID,
313
- childDepth: spawnReservation.spawnContext.childDepth,
314
- descendantCount: spawnReservation.descendantCount,
315
- })
316
-
317
- // Create task immediately with status="pending"
318
- const task: BackgroundTask = {
319
- id: `bg_${crypto.randomUUID().slice(0, 8)}`,
320
- status: "pending",
321
- queuedAt: new Date(),
322
- rootSessionID: spawnReservation.spawnContext.rootSessionID,
323
- // Do NOT set startedAt - will be set when running
324
- // Do NOT set sessionID - will be set when running
325
- description: input.description,
326
- prompt: input.prompt,
327
- agent: input.agent,
328
- spawnDepth: spawnReservation.spawnContext.childDepth,
329
- parentSessionID: input.parentSessionID,
330
- parentMessageID: input.parentMessageID,
331
- parentModel: input.parentModel,
332
- parentAgent: input.parentAgent,
333
- parentTools: input.parentTools,
334
- model: input.model,
335
- fallbackChain: input.fallbackChain,
336
- attemptCount: 0,
337
- category: input.category,
338
- }
339
-
340
- this.tasks.set(task.id, task)
341
- this.taskHistory.record(input.parentSessionID, { id: task.id, agent: input.agent, description: input.description, status: "pending", category: input.category })
342
-
343
- // Track for batched notifications immediately (pending state)
344
- if (input.parentSessionID) {
345
- const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set()
346
- pending.add(task.id)
347
- this.pendingByParent.set(input.parentSessionID, pending)
348
- }
349
-
350
- // Add to queue
351
- const key = this.getConcurrencyKeyFromInput(input)
352
- const queue = this.queuesByKey.get(key) ?? []
353
- queue.push({ task, input })
354
- this.queuesByKey.set(key, queue)
355
-
356
- log("[background-agent] Task queued:", { taskId: task.id, key, queueLength: queue.length })
357
-
358
- const toastManager = getTaskToastManager()
359
- if (toastManager) {
360
- toastManager.addTask({
361
- id: task.id,
362
- description: input.description,
363
- agent: input.agent,
364
- isBackground: true,
365
- status: "queued",
366
- skills: input.skills,
367
- })
368
- }
369
-
370
- spawnReservation.commit()
371
- this.markPreStartDescendantReservation(task)
372
-
373
- // Trigger processing (fire-and-forget)
374
- void this.processKey(key)
375
-
376
- return { ...task }
377
- } catch (error) {
378
- spawnReservation.rollback()
379
- throw error
380
- }
381
- }
382
-
383
- private async processKey(key: string): Promise<void> {
384
- if (this.processingKeys.has(key)) {
385
- return
386
- }
387
-
388
- this.processingKeys.add(key)
389
-
390
- try {
391
- const queue = this.queuesByKey.get(key)
392
- while (queue && queue.length > 0) {
393
- const item = queue.shift()
394
- if (!item) {
395
- continue
396
- }
397
-
398
- await this.concurrencyManager.acquire(key)
399
-
400
- if (item.task.status === "cancelled" || item.task.status === "error" || item.task.status === "interrupt") {
401
- this.rollbackPreStartDescendantReservation(item.task)
402
- this.concurrencyManager.release(key)
403
- continue
404
- }
405
-
406
- try {
407
- await this.startTask(item)
408
- } catch (error) {
409
- log("[background-agent] Error starting task:", error)
410
- this.rollbackPreStartDescendantReservation(item.task)
411
-
412
- // Mark task as error so the parent polling loop detects the failure
413
- // instead of leaving it in a zombie "running" state with no prompt sent
414
- item.task.status = "error"
415
- item.task.error = error instanceof Error ? error.message : String(error)
416
- item.task.completedAt = new Date()
417
-
418
- if (item.task.concurrencyKey) {
419
- this.concurrencyManager.release(item.task.concurrencyKey)
420
- item.task.concurrencyKey = undefined
421
- } else {
422
- this.concurrencyManager.release(key)
423
- }
424
-
425
- removeTaskToastTracking(item.task.id)
426
-
427
- // Abort the orphaned session if one was created before the error
428
- if (item.task.sessionID) {
429
- await this.abortSessionWithLogging(item.task.sessionID, "startTask error cleanup")
430
- }
431
-
432
- this.markForNotification(item.task)
433
- this.enqueueNotificationForParent(item.task.parentSessionID, () => this.notifyParentSession(item.task)).catch(err => {
434
- log("[background-agent] Failed to notify on startTask error:", err)
435
- })
436
- }
437
- }
438
- } finally {
439
- this.processingKeys.delete(key)
440
- }
441
- }
442
-
443
- private async startTask(item: QueueItem): Promise<void> {
444
- const { task, input } = item
445
-
446
- log("[background-agent] Starting task:", {
447
- taskId: task.id,
448
- agent: input.agent,
449
- model: input.model,
450
- })
451
-
452
- const concurrencyKey = this.getConcurrencyKeyFromInput(input)
453
-
454
- const parentSession = await this.client.session.get({
455
- path: { id: input.parentSessionID },
456
- query: { directory: this.directory },
457
- }).catch((err) => {
458
- log(`[background-agent] Failed to get parent session: ${err}`)
459
- return null
460
- })
461
- const parentDirectory = parentSession?.data?.directory ?? this.directory
462
- log(`[background-agent] Parent dir: ${parentSession?.data?.directory}, using: ${parentDirectory}`)
463
-
464
- const createResult = await this.client.session.create({
465
- body: {
466
- parentID: input.parentSessionID,
467
- title: `${input.description} (@${input.agent} subagent)`,
468
- ...(input.sessionPermission ? { permission: input.sessionPermission } : {}),
469
- } as Record<string, unknown>,
470
- query: {
471
- directory: parentDirectory,
472
- },
473
- })
474
-
475
- if (createResult.error) {
476
- throw new Error(`Failed to create background session: ${createResult.error}`)
477
- }
478
-
479
- if (!createResult.data?.id) {
480
- throw new Error("Failed to create background session: API returned no session ID")
481
- }
482
-
483
- const sessionID = createResult.data.id
484
-
485
- if (task.status === "cancelled") {
486
- await this.abortSessionWithLogging(sessionID, "cancelled pre-start cleanup")
487
- this.concurrencyManager.release(concurrencyKey)
488
- return
489
- }
490
-
491
- this.settlePreStartDescendantReservation(task)
492
- subagentSessions.add(sessionID)
493
-
494
- log("[background-agent] tmux callback check", {
495
- hasCallback: !!this.onSubagentSessionCreated,
496
- tmuxEnabled: this.tmuxEnabled,
497
- isInsideTmux: isInsideTmux(),
498
- sessionID,
499
- parentID: input.parentSessionID,
500
- })
501
-
502
- if (this.onSubagentSessionCreated && this.tmuxEnabled && isInsideTmux()) {
503
- log("[background-agent] Invoking tmux callback NOW", { sessionID })
504
- await this.onSubagentSessionCreated({
505
- sessionID,
506
- parentID: input.parentSessionID,
507
- title: input.description,
508
- }).catch((err) => {
509
- log("[background-agent] Failed to spawn tmux pane:", err)
510
- })
511
- log("[background-agent] tmux callback completed, waiting 200ms")
512
- await new Promise(r => setTimeout(r, 200))
513
- } else {
514
- log("[background-agent] SKIP tmux callback - conditions not met")
515
- }
516
-
517
- if (this.tasks.get(task.id)?.status === "cancelled") {
518
- await this.abortSessionWithLogging(sessionID, "cancelled during tmux setup")
519
- subagentSessions.delete(sessionID)
520
- if (task.rootSessionID) {
521
- this.unregisterRootDescendant(task.rootSessionID)
522
- }
523
- this.concurrencyManager.release(concurrencyKey)
524
- return
525
- }
526
-
527
- task.status = "running"
528
- task.startedAt = new Date()
529
- task.sessionID = sessionID
530
- task.progress = {
531
- toolCalls: 0,
532
- lastUpdate: new Date(),
533
- }
534
- task.concurrencyKey = concurrencyKey
535
- task.concurrencyGroup = concurrencyKey
536
-
537
- this.taskHistory.record(input.parentSessionID, { id: task.id, sessionID, agent: input.agent, description: input.description, status: "running", category: input.category, startedAt: task.startedAt })
538
- this.startPolling()
539
-
540
- log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent })
541
-
542
- const toastManager = getTaskToastManager()
543
- if (toastManager) {
544
- toastManager.updateTask(task.id, "running")
545
- }
546
-
547
- log("[background-agent] Calling prompt (fire-and-forget) for launch with:", {
548
- sessionID,
549
- agent: input.agent,
550
- model: input.model,
551
- hasSkillContent: !!input.skillContent,
552
- promptLength: input.prompt.length,
553
- })
554
-
555
- // Fire-and-forget prompt via promptAsync (no response body needed)
556
- // OpenCode prompt payload accepts model provider/model IDs and top-level variant only.
557
- // Temperature/topP and provider-specific options are applied through chat.params.
558
- const launchModel = input.model
559
- ? {
560
- providerID: input.model.providerID,
561
- modelID: input.model.modelID,
562
- }
563
- : undefined
564
- const launchVariant = input.model?.variant
565
-
566
- if (input.model) {
567
- applySessionPromptParams(sessionID, input.model)
568
- }
569
-
570
- const promptBody = {
571
- agent: input.agent,
572
- ...(launchModel ? { model: launchModel } : {}),
573
- ...(launchVariant ? { variant: launchVariant } : {}),
574
- system: input.skillContent,
575
- tools: (() => {
576
- const tools = {
577
- task: false,
578
- call_omo_agent: true,
579
- question: false,
580
- ...getAgentToolRestrictions(input.agent),
581
- }
582
- setSessionTools(sessionID, tools)
583
- return tools
584
- })(),
585
- parts: [createInternalAgentTextPart(input.prompt)],
586
- }
587
-
588
- promptWithModelSuggestionRetry(this.client, {
589
- path: { id: sessionID },
590
- body: promptBody,
591
- }).catch(async (error) => {
592
- // Retry with fallback agent if the original agent was unregistered (e.g., after a model switch)
593
- if (isAgentNotFoundError(error) && input.agent !== FALLBACK_AGENT) {
594
- log("[background-agent] Agent not found, retrying with fallback agent", {
595
- original: input.agent,
596
- fallback: FALLBACK_AGENT,
597
- taskId: task.id,
598
- })
599
- try {
600
- const fallbackBody = buildFallbackBody(promptBody, FALLBACK_AGENT)
601
- setSessionTools(sessionID, fallbackBody.tools as Record<string, boolean>)
602
- await promptWithModelSuggestionRetry(this.client, {
603
- path: { id: sessionID },
604
- body: fallbackBody,
605
- })
606
- task.agent = FALLBACK_AGENT
607
- return
608
- } catch (retryError) {
609
- log("[background-agent] Fallback agent also failed:", retryError)
610
- }
611
- }
612
-
613
- log("[background-agent] promptAsync error:", error)
614
- const existingTask = this.findBySession(sessionID)
615
- if (existingTask) {
616
- existingTask.status = "interrupt"
617
- const errorMessage = error instanceof Error ? error.message : String(error)
618
- if (errorMessage.includes("agent.name") || errorMessage.includes("undefined") || isAgentNotFoundError(error)) {
619
- existingTask.error = `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`
620
- } else {
621
- existingTask.error = errorMessage
622
- }
623
- existingTask.completedAt = new Date()
624
- if (existingTask.rootSessionID) {
625
- this.unregisterRootDescendant(existingTask.rootSessionID)
626
- }
627
- if (existingTask.concurrencyKey) {
628
- this.concurrencyManager.release(existingTask.concurrencyKey)
629
- existingTask.concurrencyKey = undefined
630
- }
631
-
632
- removeTaskToastTracking(existingTask.id)
633
-
634
- // Abort the session to prevent infinite polling hang
635
- // Awaited to prevent dangling promise during subagent teardown (Bun/WebKit SIGABRT)
636
- await this.abortSessionWithLogging(sessionID, "launch error cleanup")
637
-
638
- this.markForNotification(existingTask)
639
- this.enqueueNotificationForParent(existingTask.parentSessionID, () => this.notifyParentSession(existingTask)).catch(err => {
640
- log("[background-agent] Failed to notify on error:", err)
641
- })
642
- }
643
- })
644
- }
645
-
646
- getTask(id: string): BackgroundTask | undefined {
647
- return this.tasks.get(id)
648
- }
649
-
650
- getTasksByParentSession(sessionID: string): BackgroundTask[] {
651
- const result: BackgroundTask[] = []
652
- for (const task of this.tasks.values()) {
653
- if (task.parentSessionID === sessionID) {
654
- result.push(task)
655
- }
656
- }
657
- return result
658
- }
659
-
660
- getAllDescendantTasks(sessionID: string): BackgroundTask[] {
661
- const result: BackgroundTask[] = []
662
- const directChildren = this.getTasksByParentSession(sessionID)
663
-
664
- for (const child of directChildren) {
665
- result.push(child)
666
- if (child.sessionID) {
667
- const descendants = this.getAllDescendantTasks(child.sessionID)
668
- result.push(...descendants)
669
- }
670
- }
671
-
672
- return result
673
- }
674
-
675
- findBySession(sessionID: string): BackgroundTask | undefined {
676
- for (const task of this.tasks.values()) {
677
- if (task.sessionID === sessionID) {
678
- return task
679
- }
680
- }
681
- return undefined
682
- }
683
-
684
- private getConcurrencyKeyFromInput(input: LaunchInput): string {
685
- if (input.model) {
686
- return `${input.model.providerID}/${input.model.modelID}`
687
- }
688
- return input.agent
689
- }
690
-
691
- /**
692
- * Track a task created elsewhere (e.g., from task) for notification tracking.
693
- * This allows tasks created by other tools to receive the same toast/prompt notifications.
694
- */
695
- async trackTask(input: {
696
- taskId: string
697
- sessionID: string
698
- parentSessionID: string
699
- description: string
700
- agent?: string
701
- parentAgent?: string
702
- concurrencyKey?: string
703
- }): Promise<BackgroundTask> {
704
- const existingTask = this.tasks.get(input.taskId)
705
- if (existingTask) {
706
- // P2 fix: Clean up old parent's pending set BEFORE changing parent
707
- // Otherwise cleanupPendingByParent would use the new parent ID
708
- const parentChanged = input.parentSessionID !== existingTask.parentSessionID
709
- if (parentChanged) {
710
- this.cleanupPendingByParent(existingTask) // Clean from OLD parent
711
- existingTask.parentSessionID = input.parentSessionID
712
- }
713
- if (input.parentAgent !== undefined) {
714
- existingTask.parentAgent = input.parentAgent
715
- }
716
- if (!existingTask.concurrencyGroup) {
717
- existingTask.concurrencyGroup = input.concurrencyKey ?? existingTask.agent
718
- }
719
-
720
- if (existingTask.sessionID) {
721
- subagentSessions.add(existingTask.sessionID)
722
- }
723
- this.startPolling()
724
-
725
- // Track for batched notifications if task is pending or running
726
- if (existingTask.status === "pending" || existingTask.status === "running") {
727
- const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set()
728
- pending.add(existingTask.id)
729
- this.pendingByParent.set(input.parentSessionID, pending)
730
- } else if (!parentChanged) {
731
- // Only clean up if parent didn't change (already cleaned above if it did)
732
- this.cleanupPendingByParent(existingTask)
733
- }
734
-
735
- log("[background-agent] External task already registered:", { taskId: existingTask.id, sessionID: existingTask.sessionID, status: existingTask.status })
736
-
737
- return existingTask
738
- }
739
-
740
- const concurrencyGroup = input.concurrencyKey ?? input.agent ?? "task"
741
-
742
- // Acquire concurrency slot if a key is provided
743
- if (input.concurrencyKey) {
744
- await this.concurrencyManager.acquire(input.concurrencyKey)
745
- }
746
-
747
- const task: BackgroundTask = {
748
- id: input.taskId,
749
- sessionID: input.sessionID,
750
- parentSessionID: input.parentSessionID,
751
- parentMessageID: "",
752
- description: input.description,
753
- prompt: "",
754
- agent: input.agent || "task",
755
- status: "running",
756
- startedAt: new Date(),
757
- progress: {
758
- toolCalls: 0,
759
- lastUpdate: new Date(),
760
- },
761
- parentAgent: input.parentAgent,
762
- concurrencyKey: input.concurrencyKey,
763
- concurrencyGroup,
764
- }
765
-
766
- this.tasks.set(task.id, task)
767
- subagentSessions.add(input.sessionID)
768
- this.startPolling()
769
- this.taskHistory.record(input.parentSessionID, { id: task.id, sessionID: input.sessionID, agent: input.agent || "task", description: input.description, status: "running", startedAt: task.startedAt })
770
-
771
- if (input.parentSessionID) {
772
- const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set()
773
- pending.add(task.id)
774
- this.pendingByParent.set(input.parentSessionID, pending)
775
- }
776
-
777
- log("[background-agent] Registered external task:", { taskId: task.id, sessionID: input.sessionID })
778
-
779
- return task
780
- }
781
-
782
- async resume(input: ResumeInput): Promise<BackgroundTask> {
783
- const existingTask = this.findBySession(input.sessionId)
784
- if (!existingTask) {
785
- throw new Error(`Task not found for session: ${input.sessionId}`)
786
- }
787
-
788
- if (!existingTask.sessionID) {
789
- throw new Error(`Task has no sessionID: ${existingTask.id}`)
790
- }
791
-
792
- if (existingTask.status === "running") {
793
- log("[background-agent] Resume skipped - task already running:", {
794
- taskId: existingTask.id,
795
- sessionID: existingTask.sessionID,
796
- })
797
- return existingTask
798
- }
799
-
800
- const completionTimer = this.completionTimers.get(existingTask.id)
801
- if (completionTimer) {
802
- clearTimeout(completionTimer)
803
- this.completionTimers.delete(existingTask.id)
804
- }
805
-
806
- // Re-acquire concurrency using the persisted concurrency group
807
- const concurrencyKey = existingTask.concurrencyGroup ?? existingTask.agent
808
- await this.concurrencyManager.acquire(concurrencyKey)
809
- existingTask.concurrencyKey = concurrencyKey
810
- existingTask.concurrencyGroup = concurrencyKey
811
-
812
-
813
- existingTask.status = "running"
814
- existingTask.completedAt = undefined
815
- existingTask.error = undefined
816
- existingTask.parentSessionID = input.parentSessionID
817
- existingTask.parentMessageID = input.parentMessageID
818
- existingTask.parentModel = input.parentModel
819
- existingTask.parentAgent = input.parentAgent
820
- if (input.parentTools) {
821
- existingTask.parentTools = input.parentTools
822
- }
823
- // Reset startedAt on resume to prevent immediate completion
824
- // The MIN_IDLE_TIME_MS check uses startedAt, so resumed tasks need fresh timing
825
- existingTask.startedAt = new Date()
826
-
827
- existingTask.progress = {
828
- toolCalls: existingTask.progress?.toolCalls ?? 0,
829
- toolCallWindow: existingTask.progress?.toolCallWindow,
830
- countedToolPartIDs: existingTask.progress?.countedToolPartIDs,
831
- lastUpdate: new Date(),
832
- }
833
-
834
- this.startPolling()
835
- if (existingTask.sessionID) {
836
- subagentSessions.add(existingTask.sessionID)
837
- }
838
-
839
- if (input.parentSessionID) {
840
- const pending = this.pendingByParent.get(input.parentSessionID) ?? new Set()
841
- pending.add(existingTask.id)
842
- this.pendingByParent.set(input.parentSessionID, pending)
843
- }
844
-
845
- const toastManager = getTaskToastManager()
846
- if (toastManager) {
847
- toastManager.addTask({
848
- id: existingTask.id,
849
- description: existingTask.description,
850
- agent: existingTask.agent,
851
- isBackground: true,
852
- })
853
- }
854
-
855
- log("[background-agent] Resuming task:", { taskId: existingTask.id, sessionID: existingTask.sessionID })
856
-
857
- log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", {
858
- sessionID: existingTask.sessionID,
859
- agent: existingTask.agent,
860
- model: existingTask.model,
861
- promptLength: input.prompt.length,
862
- })
863
-
864
- // Fire-and-forget prompt via promptAsync (no response body needed)
865
- // Resume uses the same PromptInput contract as launch: model IDs plus top-level variant.
866
- const resumeModel = existingTask.model
867
- ? {
868
- providerID: existingTask.model.providerID,
869
- modelID: existingTask.model.modelID,
870
- }
871
- : undefined
872
- const resumeVariant = existingTask.model?.variant
873
-
874
- if (existingTask.model) {
875
- applySessionPromptParams(existingTask.sessionID!, existingTask.model)
876
- }
877
-
878
- this.client.session.promptAsync({
879
- path: { id: existingTask.sessionID },
880
- body: {
881
- agent: existingTask.agent,
882
- ...(resumeModel ? { model: resumeModel } : {}),
883
- ...(resumeVariant ? { variant: resumeVariant } : {}),
884
- tools: (() => {
885
- const tools = {
886
- task: false,
887
- call_omo_agent: true,
888
- question: false,
889
- ...getAgentToolRestrictions(existingTask.agent),
890
- }
891
- setSessionTools(existingTask.sessionID!, tools)
892
- return tools
893
- })(),
894
- parts: [createInternalAgentTextPart(input.prompt)],
895
- },
896
- }).catch(async (error) => {
897
- log("[background-agent] resume prompt error:", error)
898
- existingTask.status = "interrupt"
899
- const errorMessage = error instanceof Error ? error.message : String(error)
900
- existingTask.error = errorMessage
901
- existingTask.completedAt = new Date()
902
- if (existingTask.rootSessionID) {
903
- this.unregisterRootDescendant(existingTask.rootSessionID)
904
- }
905
-
906
- // Release concurrency on error to prevent slot leaks
907
- if (existingTask.concurrencyKey) {
908
- this.concurrencyManager.release(existingTask.concurrencyKey)
909
- existingTask.concurrencyKey = undefined
910
- }
911
-
912
- removeTaskToastTracking(existingTask.id)
913
-
914
- // Abort the session to prevent infinite polling hang
915
- // Awaited to prevent dangling promise during subagent teardown (Bun/WebKit SIGABRT)
916
- if (existingTask.sessionID) {
917
- await this.abortSessionWithLogging(existingTask.sessionID, "resume error cleanup")
918
- }
919
-
920
- this.markForNotification(existingTask)
921
- this.enqueueNotificationForParent(existingTask.parentSessionID, () => this.notifyParentSession(existingTask)).catch(err => {
922
- log("[background-agent] Failed to notify on resume error:", err)
923
- })
924
- })
925
-
926
- return existingTask
927
- }
928
-
929
- private async checkSessionTodos(sessionID: string): Promise<boolean> {
930
- const observedIncompleteTodos = this.observedIncompleteTodosBySession.get(sessionID)
931
- if (observedIncompleteTodos !== undefined) {
932
- return observedIncompleteTodos
933
- }
934
-
935
- try {
936
- const response = await this.client.session.todo({
937
- path: { id: sessionID },
938
- })
939
- const todos = normalizeSDKResponse(response, [] as Todo[], { preferResponseOnMissingData: true })
940
- if (!todos || todos.length === 0) {
941
- this.observedIncompleteTodosBySession.set(sessionID, false)
942
- return false
943
- }
944
-
945
- const incomplete = todos.filter(
946
- (t) => t.status !== "completed" && t.status !== "cancelled"
947
- )
948
- const hasIncompleteTodos = incomplete.length > 0
949
- this.observedIncompleteTodosBySession.set(sessionID, hasIncompleteTodos)
950
- return hasIncompleteTodos
951
- } catch (error) {
952
- log("[background-agent] Failed to check session todos:", {
953
- sessionID,
954
- error,
955
- })
956
- return false
957
- }
958
- }
959
-
960
- private markSessionOutputObserved(sessionID: string): void {
961
- this.observedOutputSessions.add(sessionID)
962
- }
963
-
964
- private clearSessionOutputObserved(sessionID: string): void {
965
- this.observedOutputSessions.delete(sessionID)
966
- }
967
-
968
- private clearSessionTodoObservation(sessionID: string): void {
969
- this.observedIncompleteTodosBySession.delete(sessionID)
970
- }
971
-
972
- private hasOutputSignalFromPart(partInfo: MessagePartInfo | undefined): boolean {
973
- if (!partInfo?.sessionID) return false
974
- if (partInfo.tool) return true
975
- if (partInfo.type === "tool" || partInfo.type === "tool_result") return true
976
- if (partInfo.type === "text" || partInfo.type === "reasoning") return true
977
-
978
- const field = typeof (partInfo as { field?: unknown }).field === "string"
979
- ? (partInfo as { field?: string }).field
980
- : undefined
981
- return field === "text" || field === "reasoning"
982
- }
983
-
984
- handleEvent(event: Event): void {
985
- const props = event.properties
986
-
987
- if (event.type === "message.updated") {
988
- const info = props?.info
989
- if (!info || typeof info !== "object") return
990
-
991
- const sessionID = (info as Record<string, unknown>)["sessionID"]
992
- const role = (info as Record<string, unknown>)["role"]
993
- if (typeof sessionID !== "string") return
994
-
995
- if (role === "tool") {
996
- this.markSessionOutputObserved(sessionID)
997
- }
998
-
999
- if (role !== "assistant") return
1000
-
1001
- const task = this.findBySession(sessionID)
1002
- if (!task || task.status !== "running") return
1003
-
1004
- const assistantError = (info as Record<string, unknown>)["error"]
1005
- if (!assistantError) return
1006
-
1007
- const errorInfo = {
1008
- name: extractErrorName(assistantError),
1009
- message: extractErrorMessage(assistantError),
1010
- }
1011
- void this.tryFallbackRetry(task, errorInfo, "message.updated").catch((error) => {
1012
- log("[background-agent] Error handling message.updated fallback retry:", {
1013
- error,
1014
- taskId: task.id,
1015
- })
1016
- })
1017
- }
1018
-
1019
- if (event.type === "message.part.updated" || event.type === "message.part.delta") {
1020
- const partInfo = resolveMessagePartInfo(props)
1021
- const sessionID = partInfo?.sessionID
1022
- if (!sessionID) return
1023
-
1024
- const task = this.findBySession(sessionID)
1025
- if (!task) return
1026
-
1027
- if (this.hasOutputSignalFromPart(partInfo)) {
1028
- this.markSessionOutputObserved(sessionID)
1029
- }
1030
-
1031
- // Clear any pending idle deferral timer since the task is still active
1032
- const existingTimer = this.idleDeferralTimers.get(task.id)
1033
- if (existingTimer) {
1034
- clearTimeout(existingTimer)
1035
- this.idleDeferralTimers.delete(task.id)
1036
- }
1037
-
1038
- if (!task.progress) {
1039
- task.progress = {
1040
- toolCalls: 0,
1041
- lastUpdate: new Date(),
1042
- }
1043
- }
1044
- task.progress.lastUpdate = new Date()
1045
-
1046
- if (partInfo?.type === "tool" || partInfo?.tool) {
1047
- const countedToolPartIDs = task.progress.countedToolPartIDs ?? new Set<string>()
1048
- const shouldCountToolCall =
1049
- !partInfo.id ||
1050
- partInfo.state?.status !== "running" ||
1051
- !countedToolPartIDs.has(partInfo.id)
1052
-
1053
- if (!shouldCountToolCall) {
1054
- return
1055
- }
1056
-
1057
- if (partInfo.id && partInfo.state?.status === "running") {
1058
- countedToolPartIDs.add(partInfo.id)
1059
- task.progress.countedToolPartIDs = countedToolPartIDs
1060
- }
1061
-
1062
- task.progress.toolCalls += 1
1063
- task.progress.lastTool = partInfo.tool
1064
- const circuitBreaker = this.cachedCircuitBreakerSettings ?? resolveCircuitBreakerSettings(this.config)
1065
- this.cachedCircuitBreakerSettings = circuitBreaker
1066
- if (partInfo.tool) {
1067
- task.progress.toolCallWindow = recordToolCall(
1068
- task.progress.toolCallWindow,
1069
- partInfo.tool,
1070
- circuitBreaker,
1071
- partInfo.state?.input
1072
- )
1073
-
1074
- if (circuitBreaker.enabled) {
1075
- const loopDetection = detectRepetitiveToolUse(task.progress.toolCallWindow)
1076
- if (loopDetection.triggered) {
1077
- log("[background-agent] Circuit breaker: consecutive tool usage detected", {
1078
- taskId: task.id,
1079
- agent: task.agent,
1080
- sessionID,
1081
- toolName: loopDetection.toolName,
1082
- repeatedCount: loopDetection.repeatedCount,
1083
- })
1084
- void this.cancelTask(task.id, {
1085
- source: "circuit-breaker",
1086
- reason: `Subagent called ${loopDetection.toolName} ${loopDetection.repeatedCount} consecutive times (threshold: ${circuitBreaker.consecutiveThreshold}). This usually indicates an infinite loop. The task was automatically cancelled to prevent excessive token usage.`,
1087
- })
1088
- return
1089
- }
1090
- }
1091
- }
1092
-
1093
- const maxToolCalls = circuitBreaker.maxToolCalls
1094
- if (task.progress.toolCalls >= maxToolCalls) {
1095
- log("[background-agent] Circuit breaker: tool call limit reached", {
1096
- taskId: task.id,
1097
- toolCalls: task.progress.toolCalls,
1098
- maxToolCalls,
1099
- agent: task.agent,
1100
- sessionID,
1101
- })
1102
- void this.cancelTask(task.id, {
1103
- source: "circuit-breaker",
1104
- reason: `Subagent exceeded maximum tool call limit (${maxToolCalls}). This usually indicates an infinite loop. The task was automatically cancelled to prevent excessive token usage.`,
1105
- })
1106
- }
1107
- }
1108
- }
1109
-
1110
- if (event.type === "todo.updated") {
1111
- const sessionID = typeof props?.sessionID === "string" ? props.sessionID : undefined
1112
- const todos = Array.isArray(props?.todos) ? props.todos : undefined
1113
- if (!sessionID || !todos) return
1114
-
1115
- const hasIncompleteTodos = todos.some((todo) => {
1116
- if (!todo || typeof todo !== "object") return false
1117
- const status = (todo as { status?: unknown }).status
1118
- return status !== "completed" && status !== "cancelled"
1119
- })
1120
- this.observedIncompleteTodosBySession.set(sessionID, hasIncompleteTodos)
1121
- return
1122
- }
1123
-
1124
- if (event.type === "session.idle") {
1125
- if (!props || typeof props !== "object") return
1126
- handleSessionIdleBackgroundEvent({
1127
- properties: props as Record<string, unknown>,
1128
- findBySession: (id) => this.findBySession(id),
1129
- idleDeferralTimers: this.idleDeferralTimers,
1130
- validateSessionHasOutput: (id) => this.validateSessionHasOutput(id),
1131
- checkSessionTodos: (id) => this.checkSessionTodos(id),
1132
- tryCompleteTask: (task, source) => this.tryCompleteTask(task, source),
1133
- emitIdleEvent: (sessionID) => this.handleEvent({ type: "session.idle", properties: { sessionID } }),
1134
- })
1135
- }
1136
-
1137
- if (event.type === "session.error") {
1138
- const sessionID = typeof props?.sessionID === "string" ? props.sessionID : undefined
1139
- if (!sessionID) return
1140
-
1141
- const task = this.findBySession(sessionID)
1142
- if (!task || task.status !== "running") return
1143
-
1144
- const errorObj = props?.error as { name?: string; message?: string } | undefined
1145
- const errorName = errorObj?.name
1146
- const errorMessage = props ? getSessionErrorMessage(props) : undefined
1147
-
1148
- const errorInfo = { name: errorName, message: errorMessage }
1149
- void this.handleSessionErrorEvent({
1150
- errorInfo,
1151
- errorMessage,
1152
- errorName,
1153
- task,
1154
- }).catch((error) => {
1155
- log("[background-agent] Error handling session.error event:", {
1156
- error,
1157
- taskId: task.id,
1158
- })
1159
- })
1160
- return
1161
- }
1162
-
1163
- if (event.type === "session.deleted") {
1164
- const info = props?.info
1165
- if (!info || typeof info.id !== "string") return
1166
- const sessionID = info.id
1167
- this.clearSessionOutputObserved(sessionID)
1168
- this.clearSessionTodoObservation(sessionID)
1169
-
1170
- const tasksToCancel = new Map<string, BackgroundTask>()
1171
- const directTask = this.findBySession(sessionID)
1172
- if (directTask) {
1173
- tasksToCancel.set(directTask.id, directTask)
1174
- }
1175
- for (const descendant of this.getAllDescendantTasks(sessionID)) {
1176
- tasksToCancel.set(descendant.id, descendant)
1177
- }
1178
-
1179
- this.pendingNotifications.delete(sessionID)
1180
-
1181
- if (tasksToCancel.size === 0) {
1182
- this.clearTaskHistoryWhenParentTasksGone(sessionID)
1183
- return
1184
- }
1185
-
1186
- const parentSessionsToClear = new Set<string>()
1187
-
1188
- const deletedSessionIDs = new Set<string>([sessionID])
1189
- for (const task of tasksToCancel.values()) {
1190
- if (task.sessionID) {
1191
- deletedSessionIDs.add(task.sessionID)
1192
- }
1193
- }
1194
-
1195
- for (const task of tasksToCancel.values()) {
1196
- parentSessionsToClear.add(task.parentSessionID)
1197
-
1198
- if (task.status === "running" || task.status === "pending") {
1199
- void this.cancelTask(task.id, {
1200
- source: "session.deleted",
1201
- reason: "Session deleted",
1202
- }).then(() => {
1203
- if (deletedSessionIDs.has(task.parentSessionID)) {
1204
- this.pendingNotifications.delete(task.parentSessionID)
1205
- }
1206
- }).catch(err => {
1207
- if (deletedSessionIDs.has(task.parentSessionID)) {
1208
- this.pendingNotifications.delete(task.parentSessionID)
1209
- }
1210
- log("[background-agent] Failed to cancel task on session.deleted:", { taskId: task.id, error: err })
1211
- })
1212
- }
1213
- }
1214
-
1215
- for (const parentSessionID of parentSessionsToClear) {
1216
- this.clearTaskHistoryWhenParentTasksGone(parentSessionID)
1217
- }
1218
-
1219
- this.rootDescendantCounts.delete(sessionID)
1220
- SessionCategoryRegistry.remove(sessionID)
1221
- }
1222
-
1223
- if (event.type === "session.status") {
1224
- const sessionID = props?.sessionID as string | undefined
1225
- const status = props?.status as { type?: string; message?: string } | undefined
1226
- if (!sessionID || status?.type !== "retry") return
1227
-
1228
- const task = this.findBySession(sessionID)
1229
- if (!task || task.status !== "running") return
1230
-
1231
- const errorMessage = typeof status.message === "string" ? status.message : undefined
1232
- const errorInfo = { name: "SessionRetry", message: errorMessage }
1233
- void this.tryFallbackRetry(task, errorInfo, "session.status").catch((error) => {
1234
- log("[background-agent] Error handling session.status fallback retry:", {
1235
- error,
1236
- taskId: task.id,
1237
- })
1238
- })
1239
- }
1240
- }
1241
-
1242
- private async handleSessionErrorEvent(args: {
1243
- task: BackgroundTask
1244
- errorInfo: { name?: string; message?: string }
1245
- errorName: string | undefined
1246
- errorMessage: string | undefined
1247
- }): Promise<void> {
1248
- const { task, errorInfo, errorMessage, errorName } = args
1249
-
1250
- // Agent-not-found errors are handled by the prompt catch block with agent fallback.
1251
- // Do not also trigger model fallback retry — that would race with the agent retry.
1252
- if (isAgentNotFoundError({ message: errorInfo.message } as Error)) {
1253
- log("[background-agent] Skipping session.error fallback for agent-not-found (handled by prompt catch)", {
1254
- taskId: task.id,
1255
- errorMessage: errorInfo.message?.slice(0, 100),
1256
- })
1257
- return
1258
- }
1259
-
1260
- if (await this.tryFallbackRetry(task, errorInfo, "session.error")) {
1261
- return
1262
- }
1263
-
1264
- const errorMsg = errorMessage ?? "Session error"
1265
- const canRetry =
1266
- shouldRetryError(errorInfo) &&
1267
- !!task.fallbackChain &&
1268
- hasMoreFallbacks(task.fallbackChain, task.attemptCount ?? 0)
1269
- log("[background-agent] Session error - no retry:", {
1270
- taskId: task.id,
1271
- errorName,
1272
- errorMessage: errorMsg?.slice(0, 100),
1273
- hasFallbackChain: !!task.fallbackChain,
1274
- canRetry,
1275
- })
1276
-
1277
- task.status = "error"
1278
- task.error = errorMsg
1279
- task.completedAt = new Date()
1280
- if (task.rootSessionID) {
1281
- this.unregisterRootDescendant(task.rootSessionID)
1282
- }
1283
- this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "error", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt })
1284
-
1285
- if (task.concurrencyKey) {
1286
- this.concurrencyManager.release(task.concurrencyKey)
1287
- task.concurrencyKey = undefined
1288
- }
1289
-
1290
- const completionTimer = this.completionTimers.get(task.id)
1291
- if (completionTimer) {
1292
- clearTimeout(completionTimer)
1293
- this.completionTimers.delete(task.id)
1294
- }
1295
-
1296
- const idleTimer = this.idleDeferralTimers.get(task.id)
1297
- if (idleTimer) {
1298
- clearTimeout(idleTimer)
1299
- this.idleDeferralTimers.delete(task.id)
1300
- }
1301
-
1302
- this.cleanupPendingByParent(task)
1303
- this.clearNotificationsForTask(task.id)
1304
- const toastManager = getTaskToastManager()
1305
- if (toastManager) {
1306
- toastManager.removeTask(task.id)
1307
- }
1308
- this.scheduleTaskRemoval(task.id)
1309
- if (task.sessionID) {
1310
- SessionCategoryRegistry.remove(task.sessionID)
1311
- }
1312
-
1313
- this.markForNotification(task)
1314
- this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task)).catch(err => {
1315
- log("[background-agent] Error in notifyParentSession for errored task:", { taskId: task.id, error: err })
1316
- })
1317
- }
1318
-
1319
- private tryFallbackRetry(
1320
- task: BackgroundTask,
1321
- errorInfo: { name?: string; message?: string },
1322
- source: string,
1323
- ): Promise<boolean> {
1324
- const previousSessionID = task.sessionID
1325
- const result = tryFallbackRetry({
1326
- task,
1327
- errorInfo,
1328
- source,
1329
- concurrencyManager: this.concurrencyManager,
1330
- client: this.client,
1331
- idleDeferralTimers: this.idleDeferralTimers,
1332
- queuesByKey: this.queuesByKey,
1333
- processKey: (key: string) => this.processKey(key),
1334
- })
1335
- return result.then((retried) => {
1336
- if (retried && previousSessionID) {
1337
- this.clearSessionOutputObserved(previousSessionID)
1338
- this.clearSessionTodoObservation(previousSessionID)
1339
- subagentSessions.delete(previousSessionID)
1340
- }
1341
- return retried
1342
- })
1343
- }
1344
-
1345
- markForNotification(task: BackgroundTask): void {
1346
- const queue = this.notifications.get(task.parentSessionID) ?? []
1347
- queue.push(task)
1348
- this.notifications.set(task.parentSessionID, queue)
1349
- }
1350
-
1351
- getPendingNotifications(sessionID: string): BackgroundTask[] {
1352
- return this.notifications.get(sessionID) ?? []
1353
- }
1354
-
1355
- clearNotifications(sessionID: string): void {
1356
- this.notifications.delete(sessionID)
1357
- }
1358
-
1359
- queuePendingNotification(sessionID: string | undefined, notification: string): void {
1360
- if (!sessionID) return
1361
- const existingNotifications = this.pendingNotifications.get(sessionID) ?? []
1362
- existingNotifications.push(notification)
1363
- this.pendingNotifications.set(sessionID, existingNotifications)
1364
- }
1365
-
1366
- injectPendingNotificationsIntoChatMessage(output: { parts: Array<{ type: string; text?: string; [key: string]: unknown }> }, sessionID: string): void {
1367
- const pendingNotifications = this.pendingNotifications.get(sessionID)
1368
- if (!pendingNotifications || pendingNotifications.length === 0) {
1369
- return
1370
- }
1371
-
1372
- this.pendingNotifications.delete(sessionID)
1373
- const notificationContent = pendingNotifications.join("\n\n")
1374
- const firstTextPartIndex = output.parts.findIndex((part) => part.type === "text")
1375
-
1376
- if (firstTextPartIndex === -1) {
1377
- output.parts.unshift(createInternalAgentTextPart(notificationContent))
1378
- return
1379
- }
1380
-
1381
- const originalText = output.parts[firstTextPartIndex].text ?? ""
1382
- output.parts[firstTextPartIndex].text = `${notificationContent}\n\n---\n\n${originalText}`
1383
- }
1384
-
1385
- /**
1386
- * Validates that a session has actual assistant/tool output before marking complete.
1387
- * Prevents premature completion when session.idle fires before agent responds.
1388
- */
1389
- private async validateSessionHasOutput(sessionID: string): Promise<boolean> {
1390
- if (this.observedOutputSessions.has(sessionID)) {
1391
- return true
1392
- }
1393
-
1394
- try {
1395
- const response = await this.client.session.messages({
1396
- path: { id: sessionID },
1397
- })
1398
-
1399
- const messages = normalizeSDKResponse(response, [] as Array<{ info?: { role?: string } }>, { preferResponseOnMissingData: true })
1400
-
1401
- // Check for at least one assistant or tool message
1402
- const hasAssistantOrToolMessage = messages.some(
1403
- (m: { info?: { role?: string } }) =>
1404
- m.info?.role === "assistant" || m.info?.role === "tool"
1405
- )
1406
-
1407
- if (!hasAssistantOrToolMessage) {
1408
- log("[background-agent] No assistant/tool messages found in session:", sessionID)
1409
- return false
1410
- }
1411
-
1412
- // OpenCode API uses different part types than Anthropic's API:
1413
- // - "reasoning" with .text property (thinking/reasoning content)
1414
- // - "tool" with .state.output property (tool call results)
1415
- // - "text" with .text property (final text output)
1416
- // - "step-start"/"step-finish" (metadata, no content)
1417
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1418
- const hasContent = messages.some((m: any) => {
1419
- if (m.info?.role !== "assistant" && m.info?.role !== "tool") return false
1420
- const parts = m.parts ?? []
1421
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1422
- return parts.some((p: any) =>
1423
- // Text content (final output)
1424
- (p.type === "text" && p.text && p.text.trim().length > 0) ||
1425
- // Reasoning content (thinking blocks)
1426
- (p.type === "reasoning" && p.text && p.text.trim().length > 0) ||
1427
- // Tool calls (indicates work was done)
1428
- p.type === "tool" ||
1429
- // Tool results (output from executed tools) - important for tool-only tasks
1430
- (p.type === "tool_result" && p.content &&
1431
- (typeof p.content === "string" ? p.content.trim().length > 0 : p.content.length > 0))
1432
- )
1433
- })
1434
-
1435
- if (!hasContent) {
1436
- log("[background-agent] Messages exist but no content found in session:", sessionID)
1437
- return false
1438
- }
1439
-
1440
- this.markSessionOutputObserved(sessionID)
1441
- return true
1442
- } catch (error) {
1443
- log("[background-agent] Error validating session output:", error)
1444
- // On error, allow completion to proceed (don't block indefinitely)
1445
- return true
1446
- }
1447
- }
1448
-
1449
- private clearNotificationsForTask(taskId: string): void {
1450
- for (const [sessionID, tasks] of this.notifications.entries()) {
1451
- const filtered = tasks.filter((t) => t.id !== taskId)
1452
- if (filtered.length === 0) {
1453
- this.notifications.delete(sessionID)
1454
- } else {
1455
- this.notifications.set(sessionID, filtered)
1456
- }
1457
- }
1458
- }
1459
-
1460
- /**
1461
- * Remove task from pending tracking for its parent session.
1462
- * Cleans up the parent entry if no pending tasks remain.
1463
- */
1464
- private cleanupPendingByParent(task: BackgroundTask): void {
1465
- if (!task.parentSessionID) return
1466
- const pending = this.pendingByParent.get(task.parentSessionID)
1467
- if (pending) {
1468
- pending.delete(task.id)
1469
- if (pending.size === 0) {
1470
- this.pendingByParent.delete(task.parentSessionID)
1471
- }
1472
- }
1473
- }
1474
-
1475
- private clearTaskHistoryWhenParentTasksGone(parentSessionID: string | undefined): void {
1476
- if (!parentSessionID) return
1477
- if (this.getTasksByParentSession(parentSessionID).length > 0) return
1478
- this.taskHistory.clearSession(parentSessionID)
1479
- this.completedTaskSummaries.delete(parentSessionID)
1480
- }
1481
-
1482
- private scheduleTaskRemoval(taskId: string, rescheduleCount = 0): void {
1483
- const existingTimer = this.completionTimers.get(taskId)
1484
- if (existingTimer) {
1485
- clearTimeout(existingTimer)
1486
- this.completionTimers.delete(taskId)
1487
- }
1488
-
1489
- const timer = setTimeout(() => {
1490
- this.completionTimers.delete(taskId)
1491
- const task = this.tasks.get(taskId)
1492
- if (!task) return
1493
-
1494
- if (task.parentSessionID) {
1495
- const siblings = this.getTasksByParentSession(task.parentSessionID)
1496
- const runningOrPendingSiblings = siblings.filter(
1497
- sibling => sibling.id !== taskId && (sibling.status === "running" || sibling.status === "pending"),
1498
- )
1499
- const completedAtTimestamp = task.completedAt?.getTime()
1500
- const reachedTaskTtl = completedAtTimestamp !== undefined && (Date.now() - completedAtTimestamp) >= TASK_TTL_MS
1501
- if (runningOrPendingSiblings.length > 0 && rescheduleCount < MAX_TASK_REMOVAL_RESCHEDULES && !reachedTaskTtl) {
1502
- this.scheduleTaskRemoval(taskId, rescheduleCount + 1)
1503
- return
1504
- }
1505
- }
1506
-
1507
- this.clearNotificationsForTask(taskId)
1508
- this.tasks.delete(taskId)
1509
- this.clearTaskHistoryWhenParentTasksGone(task.parentSessionID)
1510
- if (task.sessionID) {
1511
- subagentSessions.delete(task.sessionID)
1512
- SessionCategoryRegistry.remove(task.sessionID)
1513
- }
1514
- log("[background-agent] Removed completed task from memory:", taskId)
1515
- }, TASK_CLEANUP_DELAY_MS)
1516
-
1517
- this.completionTimers.set(taskId, timer)
1518
- }
1519
-
1520
- async cancelTask(
1521
- taskId: string,
1522
- options?: { source?: string; reason?: string; abortSession?: boolean; skipNotification?: boolean }
1523
- ): Promise<boolean> {
1524
- const task = this.tasks.get(taskId)
1525
- if (!task || (task.status !== "running" && task.status !== "pending")) {
1526
- return false
1527
- }
1528
-
1529
- const source = options?.source ?? "cancel"
1530
- const abortSession = options?.abortSession !== false
1531
- const reason = options?.reason
1532
-
1533
- if (task.status === "pending") {
1534
- const key = task.model
1535
- ? `${task.model.providerID}/${task.model.modelID}`
1536
- : task.agent
1537
- const queue = this.queuesByKey.get(key)
1538
- if (queue) {
1539
- const index = queue.findIndex(item => item.task.id === taskId)
1540
- if (index !== -1) {
1541
- queue.splice(index, 1)
1542
- if (queue.length === 0) {
1543
- this.queuesByKey.delete(key)
1544
- }
1545
- }
1546
- }
1547
- this.rollbackPreStartDescendantReservation(task)
1548
- log("[background-agent] Cancelled pending task:", { taskId, key })
1549
- }
1550
-
1551
- const wasRunning = task.status === "running"
1552
- task.status = "cancelled"
1553
- task.completedAt = new Date()
1554
- if (wasRunning && task.rootSessionID) {
1555
- this.unregisterRootDescendant(task.rootSessionID)
1556
- }
1557
- if (reason) {
1558
- task.error = reason
1559
- }
1560
- this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "cancelled", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt })
1561
-
1562
- if (task.concurrencyKey) {
1563
- this.concurrencyManager.release(task.concurrencyKey)
1564
- task.concurrencyKey = undefined
1565
- }
1566
-
1567
- const existingTimer = this.completionTimers.get(task.id)
1568
- if (existingTimer) {
1569
- clearTimeout(existingTimer)
1570
- this.completionTimers.delete(task.id)
1571
- }
1572
-
1573
- const idleTimer = this.idleDeferralTimers.get(task.id)
1574
- if (idleTimer) {
1575
- clearTimeout(idleTimer)
1576
- this.idleDeferralTimers.delete(task.id)
1577
- }
1578
-
1579
- if (abortSession && task.sessionID) {
1580
- // Awaited to prevent dangling promise during subagent teardown (Bun/WebKit SIGABRT)
1581
- await this.abortSessionWithLogging(task.sessionID, `task cancellation (${source})`)
1582
-
1583
- SessionCategoryRegistry.remove(task.sessionID)
1584
- }
1585
-
1586
- removeTaskToastTracking(task.id)
1587
-
1588
- if (options?.skipNotification) {
1589
- this.cleanupPendingByParent(task)
1590
- this.scheduleTaskRemoval(task.id)
1591
- log(`[background-agent] Task cancelled via ${source} (notification skipped):`, task.id)
1592
- return true
1593
- }
1594
-
1595
- this.markForNotification(task)
1596
-
1597
- try {
1598
- await this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task))
1599
- log(`[background-agent] Task cancelled via ${source}:`, task.id)
1600
- } catch (err) {
1601
- log("[background-agent] Error in notifyParentSession for cancelled task:", { taskId: task.id, error: err })
1602
- }
1603
-
1604
- return true
1605
- }
1606
-
1607
- /**
1608
- * Cancels a pending task by removing it from queue and marking as cancelled.
1609
- * Does NOT abort session (no session exists yet) or release concurrency slot (wasn't acquired).
1610
- */
1611
- cancelPendingTask(taskId: string): boolean {
1612
- const task = this.tasks.get(taskId)
1613
- if (!task || task.status !== "pending") {
1614
- return false
1615
- }
1616
-
1617
- void this.cancelTask(taskId, { source: "cancelPendingTask", abortSession: false })
1618
- return true
1619
- }
1620
-
1621
- private startPolling(): void {
1622
- if (this.pollingInterval) return
1623
-
1624
- this.pollingInterval = setInterval(() => {
1625
- this.pollRunningTasks()
1626
- }, POLLING_INTERVAL_MS)
1627
- this.pollingInterval.unref()
1628
- }
1629
-
1630
- private stopPolling(): void {
1631
- if (this.pollingInterval) {
1632
- clearInterval(this.pollingInterval)
1633
- this.pollingInterval = undefined
1634
- }
1635
- }
1636
-
1637
- private registerProcessCleanup(): void {
1638
- registerManagerForCleanup(this)
1639
- }
1640
-
1641
- private unregisterProcessCleanup(): void {
1642
- unregisterManagerForCleanup(this)
1643
- }
1644
-
1645
-
1646
- /**
1647
- * Get all running tasks (for compaction hook)
1648
- */
1649
- getRunningTasks(): BackgroundTask[] {
1650
- return Array.from(this.tasks.values()).filter(t => t.status === "running")
1651
- }
1652
-
1653
- /**
1654
- * Get all non-running tasks still in memory (for compaction hook)
1655
- */
1656
- getNonRunningTasks(): BackgroundTask[] {
1657
- return Array.from(this.tasks.values()).filter(t => t.status !== "running")
1658
- }
1659
-
1660
- /**
1661
- * Safely complete a task with race condition protection.
1662
- * Returns true if task was successfully completed, false if already completed by another path.
1663
- */
1664
- private async tryCompleteTask(task: BackgroundTask, source: string): Promise<boolean> {
1665
- // Guard: Check if task is still running (could have been completed by another path)
1666
- if (task.status !== "running") {
1667
- log("[background-agent] Task already completed, skipping:", { taskId: task.id, status: task.status, source })
1668
- return false
1669
- }
1670
-
1671
- // Atomically mark as completed to prevent race conditions
1672
- task.status = "completed"
1673
- task.completedAt = new Date()
1674
- this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "completed", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt })
1675
-
1676
- if (task.rootSessionID) {
1677
- this.unregisterRootDescendant(task.rootSessionID)
1678
- }
1679
-
1680
- removeTaskToastTracking(task.id)
1681
-
1682
- // Release concurrency BEFORE any async operations to prevent slot leaks
1683
- if (task.concurrencyKey) {
1684
- this.concurrencyManager.release(task.concurrencyKey)
1685
- task.concurrencyKey = undefined
1686
- }
1687
-
1688
- this.markForNotification(task)
1689
-
1690
- const idleTimer = this.idleDeferralTimers.get(task.id)
1691
- if (idleTimer) {
1692
- clearTimeout(idleTimer)
1693
- this.idleDeferralTimers.delete(task.id)
1694
- }
1695
-
1696
- if (task.sessionID) {
1697
- // Awaited to prevent dangling promise during subagent teardown (Bun/WebKit SIGABRT)
1698
- await this.abortSessionWithLogging(task.sessionID, `task completion (${source})`)
1699
-
1700
- SessionCategoryRegistry.remove(task.sessionID)
1701
- }
1702
-
1703
- try {
1704
- await this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task))
1705
- log(`[background-agent] Task completed via ${source}:`, task.id)
1706
- } catch (err) {
1707
- log("[background-agent] Error in notifyParentSession:", { taskId: task.id, error: err })
1708
- // Concurrency already released, notification failed but task is complete
1709
- }
1710
-
1711
- return true
1712
- }
1713
-
1714
- private async notifyParentSession(task: BackgroundTask): Promise<void> {
1715
- const duration = formatDuration(task.startedAt ?? new Date(), task.completedAt)
1716
-
1717
- log("[background-agent] notifyParentSession called for task:", task.id)
1718
-
1719
- // Show toast notification
1720
- const toastManager = getTaskToastManager()
1721
- if (toastManager) {
1722
- toastManager.showCompletionToast({
1723
- id: task.id,
1724
- description: task.description,
1725
- duration,
1726
- })
1727
- }
1728
-
1729
- if (!this.completedTaskSummaries.has(task.parentSessionID)) {
1730
- this.completedTaskSummaries.set(task.parentSessionID, [])
1731
- }
1732
- this.completedTaskSummaries.get(task.parentSessionID)!.push({
1733
- id: task.id,
1734
- description: task.description,
1735
- status: task.status,
1736
- error: task.error,
1737
- })
1738
-
1739
- // Update pending tracking and check if all tasks complete
1740
- const pendingSet = this.pendingByParent.get(task.parentSessionID)
1741
- let allComplete = false
1742
- let remainingCount = 0
1743
- if (pendingSet) {
1744
- pendingSet.delete(task.id)
1745
- remainingCount = pendingSet.size
1746
- allComplete = remainingCount === 0
1747
- if (allComplete) {
1748
- this.pendingByParent.delete(task.parentSessionID)
1749
- }
1750
- } else {
1751
- remainingCount = Array.from(this.tasks.values())
1752
- .filter(t => t.parentSessionID === task.parentSessionID && t.id !== task.id && (t.status === "running" || t.status === "pending"))
1753
- .length
1754
- allComplete = remainingCount === 0
1755
- }
1756
-
1757
- const completedTasks = allComplete
1758
- ? (this.completedTaskSummaries.get(task.parentSessionID) ?? [{ id: task.id, description: task.description, status: task.status, error: task.error }])
1759
- : []
1760
-
1761
- if (allComplete) {
1762
- this.completedTaskSummaries.delete(task.parentSessionID)
1763
- }
1764
-
1765
- const statusText = task.status === "completed"
1766
- ? "COMPLETED"
1767
- : task.status === "interrupt"
1768
- ? "INTERRUPTED"
1769
- : task.status === "error"
1770
- ? "ERROR"
1771
- : "CANCELLED"
1772
- const notification = buildBackgroundTaskNotificationText({
1773
- task,
1774
- duration,
1775
- statusText,
1776
- allComplete,
1777
- remainingCount,
1778
- completedTasks,
1779
- })
1780
-
1781
- let agent: string | undefined = task.parentAgent
1782
- let model: { providerID: string; modelID: string } | undefined
1783
- let tools: Record<string, boolean> | undefined = task.parentTools
1784
- let promptContext: ReturnType<typeof resolvePromptContextFromSessionMessages> = null
1785
-
1786
- if (this.enableParentSessionNotifications) {
1787
- try {
1788
- const messagesResp = await this.client.session.messages({ path: { id: task.parentSessionID } })
1789
- const messages = normalizeSDKResponse(messagesResp, [] as Array<{
1790
- info?: {
1791
- agent?: string
1792
- model?: { providerID: string; modelID: string }
1793
- modelID?: string
1794
- providerID?: string
1795
- tools?: Record<string, boolean | "allow" | "deny" | "ask">
1796
- }
1797
- }>)
1798
- promptContext = resolvePromptContextFromSessionMessages(
1799
- messages,
1800
- task.parentSessionID,
1801
- )
1802
- const normalizedTools = isRecord(promptContext?.tools)
1803
- ? normalizePromptTools(promptContext.tools)
1804
- : undefined
1805
-
1806
- if (promptContext?.agent || promptContext?.model || normalizedTools) {
1807
- agent = promptContext?.agent ?? task.parentAgent
1808
- model = promptContext?.model?.providerID && promptContext.model.modelID
1809
- ? { providerID: promptContext.model.providerID, modelID: promptContext.model.modelID }
1810
- : undefined
1811
- tools = normalizedTools ?? tools
1812
- }
1813
- } catch (error) {
1814
- if (isAbortedSessionError(error)) {
1815
- log("[background-agent] Parent session aborted while loading messages; using messageDir fallback:", {
1816
- taskId: task.id,
1817
- parentSessionID: task.parentSessionID,
1818
- })
1819
- }
1820
- const messageDir = join(MESSAGE_STORAGE, task.parentSessionID)
1821
- const currentMessage = messageDir
1822
- ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionID)
1823
- : null
1824
- agent = currentMessage?.agent ?? task.parentAgent
1825
- model = currentMessage?.model?.providerID && currentMessage?.model?.modelID
1826
- ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID }
1827
- : undefined
1828
- tools = normalizePromptTools(currentMessage?.tools) ?? tools
1829
- }
1830
-
1831
- const resolvedTools = resolveInheritedPromptTools(task.parentSessionID, tools)
1832
-
1833
- log("[background-agent] notifyParentSession context:", {
1834
- taskId: task.id,
1835
- resolvedAgent: agent,
1836
- resolvedModel: model,
1837
- })
1838
-
1839
- const isTaskFailure = task.status === "error" || task.status === "cancelled" || task.status === "interrupt"
1840
- const shouldReply = allComplete || isTaskFailure
1841
-
1842
- const variant = promptContext?.model?.variant
1843
-
1844
- try {
1845
- await this.client.session.promptAsync({
1846
- path: { id: task.parentSessionID },
1847
- body: {
1848
- noReply: !shouldReply,
1849
- ...(agent !== undefined ? { agent } : {}),
1850
- ...(model !== undefined ? { model } : {}),
1851
- ...(variant !== undefined ? { variant } : {}),
1852
- ...(resolvedTools ? { tools: resolvedTools } : {}),
1853
- parts: [createInternalAgentTextPart(notification)],
1854
- },
1855
- })
1856
- log("[background-agent] Sent notification to parent session:", {
1857
- taskId: task.id,
1858
- allComplete,
1859
- isTaskFailure,
1860
- noReply: !shouldReply,
1861
- })
1862
- } catch (error) {
1863
- if (isAbortedSessionError(error)) {
1864
- log("[background-agent] Parent session aborted while sending notification; continuing cleanup:", {
1865
- taskId: task.id,
1866
- parentSessionID: task.parentSessionID,
1867
- })
1868
- this.queuePendingNotification(task.parentSessionID, notification)
1869
- } else {
1870
- log("[background-agent] Failed to send notification:", error)
1871
- }
1872
- }
1873
- } else {
1874
- log("[background-agent] Parent session notifications disabled, skipping prompt injection:", {
1875
- taskId: task.id,
1876
- parentSessionID: task.parentSessionID,
1877
- })
1878
- }
1879
-
1880
- if (task.status !== "running" && task.status !== "pending") {
1881
- this.scheduleTaskRemoval(task.id)
1882
- }
1883
- }
1884
-
1885
- private hasRunningTasks(): boolean {
1886
- for (const task of this.tasks.values()) {
1887
- if (task.status === "running") return true
1888
- }
1889
- return false
1890
- }
1891
-
1892
- private pruneStaleTasksAndNotifications(): void {
1893
- pruneStaleTasksAndNotifications({
1894
- tasks: this.tasks,
1895
- notifications: this.notifications,
1896
- taskTtlMs: this.config?.taskTtlMs,
1897
- onTaskPruned: (taskId, task, errorMessage) => {
1898
- const wasPending = task.status === "pending"
1899
- log("[background-agent] Pruning stale task:", { taskId, status: task.status, age: Math.round(((wasPending ? task.queuedAt?.getTime() : task.startedAt?.getTime()) ? (Date.now() - (wasPending ? task.queuedAt!.getTime() : task.startedAt!.getTime())) : 0) / 1000) + "s" })
1900
- task.status = "error"
1901
- task.error = errorMessage
1902
- task.completedAt = new Date()
1903
- if (!wasPending && task.rootSessionID) {
1904
- this.unregisterRootDescendant(task.rootSessionID)
1905
- }
1906
- this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "error", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt })
1907
- if (task.concurrencyKey) {
1908
- this.concurrencyManager.release(task.concurrencyKey)
1909
- task.concurrencyKey = undefined
1910
- }
1911
- removeTaskToastTracking(task.id)
1912
- const existingTimer = this.completionTimers.get(taskId)
1913
- if (existingTimer) {
1914
- clearTimeout(existingTimer)
1915
- this.completionTimers.delete(taskId)
1916
- }
1917
- const idleTimer = this.idleDeferralTimers.get(taskId)
1918
- if (idleTimer) {
1919
- clearTimeout(idleTimer)
1920
- this.idleDeferralTimers.delete(taskId)
1921
- }
1922
- if (wasPending) {
1923
- const key = task.model
1924
- ? `${task.model.providerID}/${task.model.modelID}`
1925
- : task.agent
1926
- const queue = this.queuesByKey.get(key)
1927
- if (queue) {
1928
- const index = queue.findIndex((item) => item.task.id === taskId)
1929
- if (index !== -1) {
1930
- queue.splice(index, 1)
1931
- if (queue.length === 0) {
1932
- this.queuesByKey.delete(key)
1933
- }
1934
- }
1935
- }
1936
- }
1937
- this.cleanupPendingByParent(task)
1938
- this.markForNotification(task)
1939
- this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task)).catch(err => {
1940
- log("[background-agent] Error in notifyParentSession for stale-pruned task:", { taskId: task.id, error: err })
1941
- })
1942
- },
1943
- })
1944
- }
1945
-
1946
- private async checkAndInterruptStaleTasks(
1947
- allStatuses: Record<string, { type: string }> = {},
1948
- ): Promise<void> {
1949
- await checkAndInterruptStaleTasks({
1950
- tasks: this.tasks.values(),
1951
- client: this.client,
1952
- directory: this.directory,
1953
- config: this.config,
1954
- concurrencyManager: this.concurrencyManager,
1955
- notifyParentSession: (task) => this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task)),
1956
- sessionStatuses: allStatuses,
1957
- })
1958
- }
1959
-
1960
- private async verifySessionExists(sessionID: string): Promise<boolean> {
1961
- return verifySessionStillExists(this.client, sessionID, this.directory)
1962
- }
1963
-
1964
- private async failCrashedTask(task: BackgroundTask, errorMessage: string): Promise<void> {
1965
- task.status = "error"
1966
- task.error = errorMessage
1967
- task.completedAt = new Date()
1968
- if (task.rootSessionID) {
1969
- this.unregisterRootDescendant(task.rootSessionID)
1970
- }
1971
- this.taskHistory.record(task.parentSessionID, { id: task.id, sessionID: task.sessionID, agent: task.agent, description: task.description, status: "error", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt })
1972
- if (task.concurrencyKey) {
1973
- this.concurrencyManager.release(task.concurrencyKey)
1974
- task.concurrencyKey = undefined
1975
- }
1976
-
1977
- const completionTimer = this.completionTimers.get(task.id)
1978
- if (completionTimer) {
1979
- clearTimeout(completionTimer)
1980
- this.completionTimers.delete(task.id)
1981
- }
1982
- const idleTimer = this.idleDeferralTimers.get(task.id)
1983
- if (idleTimer) {
1984
- clearTimeout(idleTimer)
1985
- this.idleDeferralTimers.delete(task.id)
1986
- }
1987
-
1988
- this.cleanupPendingByParent(task)
1989
- this.clearNotificationsForTask(task.id)
1990
- removeTaskToastTracking(task.id)
1991
- this.scheduleTaskRemoval(task.id)
1992
- if (task.sessionID) {
1993
- SessionCategoryRegistry.remove(task.sessionID)
1994
- }
1995
-
1996
- this.markForNotification(task)
1997
- this.enqueueNotificationForParent(task.parentSessionID, () => this.notifyParentSession(task)).catch(err => {
1998
- log("[background-agent] Error in notifyParentSession for crashed task:", { taskId: task.id, error: err })
1999
- })
2000
- }
2001
-
2002
- private async pollRunningTasks(): Promise<void> {
2003
- if (this.pollingInFlight) return
2004
- this.pollingInFlight = true
2005
- try {
2006
- this.pruneStaleTasksAndNotifications()
2007
-
2008
- const statusResult = await this.client.session.status()
2009
- const allStatuses = normalizeSDKResponse(statusResult, {} as Record<string, { type: string }>)
2010
-
2011
- await this.checkAndInterruptStaleTasks(allStatuses)
2012
-
2013
- for (const task of this.tasks.values()) {
2014
- if (task.status !== "running") continue
2015
-
2016
- const sessionID = task.sessionID
2017
- if (!sessionID) continue
2018
-
2019
- try {
2020
- const sessionStatus = allStatuses[sessionID]
2021
- // Handle retry before checking running state
2022
- if (sessionStatus?.type === "retry") {
2023
- const retryMessage = typeof (sessionStatus as { message?: string }).message === "string"
2024
- ? (sessionStatus as { message?: string }).message
2025
- : undefined
2026
- const errorInfo = { name: "SessionRetry", message: retryMessage }
2027
- if (await this.tryFallbackRetry(task, errorInfo, "polling:session.status")) {
2028
- continue
2029
- }
2030
- }
2031
-
2032
- // Only skip completion when session status is actively running.
2033
- // Unknown or terminal statuses (like "interrupted") fall through to completion.
2034
- if (sessionStatus && isActiveSessionStatus(sessionStatus.type)) {
2035
- log("[background-agent] Session still running, relying on event-based progress:", {
2036
- taskId: task.id,
2037
- sessionID,
2038
- sessionStatus: sessionStatus.type,
2039
- toolCalls: task.progress?.toolCalls ?? 0,
2040
- })
2041
- continue
2042
- }
2043
-
2044
- if (sessionStatus && isTerminalSessionStatus(sessionStatus.type)) {
2045
- await this.tryCompleteTask(task, `polling (terminal session status: ${sessionStatus.type})`)
2046
- continue
2047
- }
2048
-
2049
- if (sessionStatus && sessionStatus.type !== "idle") {
2050
- log("[background-agent] Unknown session status, treating as potentially idle:", {
2051
- taskId: task.id,
2052
- sessionID,
2053
- sessionStatus: sessionStatus.type,
2054
- })
2055
- }
2056
-
2057
- // Session is idle or no longer in status response (completed/disappeared)
2058
- const sessionGoneFromStatus = !sessionStatus
2059
- const sessionGoneThresholdReached = sessionGoneFromStatus
2060
- && (task.consecutiveMissedPolls ?? 0) >= MIN_SESSION_GONE_POLLS
2061
- const completionSource = sessionStatus?.type === "idle"
2062
- ? "polling (idle status)"
2063
- : "polling (session gone from status)"
2064
- const hasValidOutput = await this.validateSessionHasOutput(sessionID)
2065
- if (!hasValidOutput) {
2066
- if (sessionGoneThresholdReached) {
2067
- const sessionExists = await this.verifySessionExists(sessionID)
2068
- if (!sessionExists) {
2069
- log("[background-agent] Session no longer exists (crashed), marking task as error:", task.id)
2070
- await this.failCrashedTask(task, "Subagent session no longer exists (process likely crashed). The session disappeared without producing any output.")
2071
- continue
2072
- }
2073
-
2074
- task.consecutiveMissedPolls = 0
2075
- }
2076
- log("[background-agent] Polling idle/gone but no valid output yet, waiting:", task.id)
2077
- continue
2078
- }
2079
-
2080
- // Re-check status after async operation
2081
- if (task.status !== "running") continue
2082
-
2083
- const hasIncompleteTodos = await this.checkSessionTodos(sessionID)
2084
- if (hasIncompleteTodos) {
2085
- log("[background-agent] Task has incomplete todos via polling, waiting:", task.id)
2086
- continue
2087
- }
2088
-
2089
- await this.tryCompleteTask(task, completionSource)
2090
- } catch (error) {
2091
- log("[background-agent] Poll error for task:", { taskId: task.id, error })
2092
- }
2093
- }
2094
-
2095
- if (!this.hasRunningTasks()) {
2096
- this.stopPolling()
2097
- }
2098
- } finally {
2099
- this.pollingInFlight = false
2100
- }
2101
- }
2102
-
2103
- /**
2104
- * Shutdown the manager gracefully.
2105
- * Cancels all pending concurrency waiters and clears timers.
2106
- * Should be called when the plugin is unloaded.
2107
- */
2108
- async shutdown(): Promise<void> {
2109
- if (this.shutdownTriggered) return
2110
- this.shutdownTriggered = true
2111
- log("[background-agent] Shutting down BackgroundManager")
2112
- this.stopPolling()
2113
- const trackedSessionIDs = new Set<string>()
2114
- const abortRequests: Array<{ sessionID: string; promise: Promise<unknown> }> = []
2115
-
2116
- // Abort all running sessions to prevent zombie processes (#1240)
2117
- for (const task of this.tasks.values()) {
2118
- if (task.sessionID) {
2119
- trackedSessionIDs.add(task.sessionID)
2120
- }
2121
-
2122
- if (task.status === "running" && task.sessionID) {
2123
- abortRequests.push({
2124
- sessionID: task.sessionID,
2125
- promise: abortWithTimeout(this.client, task.sessionID),
2126
- })
2127
- }
2128
- }
2129
-
2130
- if (abortRequests.length > 0) {
2131
- const abortResults = await Promise.allSettled(abortRequests.map((request) => request.promise))
2132
- for (const [index, abortResult] of abortResults.entries()) {
2133
- if (abortResult.status === "fulfilled") continue
2134
-
2135
- log("[background-agent] Error aborting session during shutdown:", {
2136
- error: abortResult.reason,
2137
- sessionID: abortRequests[index]?.sessionID,
2138
- })
2139
- }
2140
- }
2141
-
2142
- // Notify shutdown listeners (e.g., tmux cleanup)
2143
- if (this.onShutdown) {
2144
- try {
2145
- await this.onShutdown()
2146
- } catch (error) {
2147
- log("[background-agent] Error in onShutdown callback:", error)
2148
- }
2149
- }
2150
-
2151
- // Release concurrency for all running tasks
2152
- for (const task of this.tasks.values()) {
2153
- if (task.concurrencyKey) {
2154
- this.concurrencyManager.release(task.concurrencyKey)
2155
- task.concurrencyKey = undefined
2156
- }
2157
- }
2158
-
2159
- for (const timer of this.completionTimers.values()) {
2160
- clearTimeout(timer)
2161
- }
2162
- this.completionTimers.clear()
2163
-
2164
- for (const timer of this.idleDeferralTimers.values()) {
2165
- clearTimeout(timer)
2166
- }
2167
- this.idleDeferralTimers.clear()
2168
-
2169
- for (const sessionID of trackedSessionIDs) {
2170
- subagentSessions.delete(sessionID)
2171
- SessionCategoryRegistry.remove(sessionID)
2172
- }
2173
-
2174
- this.concurrencyManager.clear()
2175
- this.tasks.clear()
2176
- this.notifications.clear()
2177
- this.pendingNotifications.clear()
2178
- this.pendingByParent.clear()
2179
- this.notificationQueueByParent.clear()
2180
- this.rootDescendantCounts.clear()
2181
- this.queuesByKey.clear()
2182
- this.processingKeys.clear()
2183
- this.taskHistory.clearAll()
2184
- this.completedTaskSummaries.clear()
2185
- this.unregisterProcessCleanup()
2186
- log("[background-agent] Shutdown complete")
2187
-
2188
- }
2189
-
2190
- private enqueueNotificationForParent(
2191
- parentSessionID: string | undefined,
2192
- operation: () => Promise<void>
2193
- ): Promise<void> {
2194
- if (!parentSessionID) {
2195
- return operation()
2196
- }
2197
-
2198
- const previous = this.notificationQueueByParent.get(parentSessionID) ?? Promise.resolve()
2199
- const cleanupQueueEntry = (): void => {
2200
- if (this.notificationQueueByParent.get(parentSessionID) === current) {
2201
- this.notificationQueueByParent.delete(parentSessionID)
2202
- }
2203
- }
2204
-
2205
- const current = previous
2206
- .catch((error) => {
2207
- log("[background-agent] Continuing notification queue after previous failure:", {
2208
- parentSessionID,
2209
- error,
2210
- })
2211
- })
2212
- .then(operation)
2213
-
2214
- this.notificationQueueByParent.set(parentSessionID, current)
2215
-
2216
- void current.then(cleanupQueueEntry, cleanupQueueEntry)
2217
-
2218
- return current
2219
- }
2220
- }