@caupulican/pi-adaptative 0.81.39 → 0.81.41

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 (884) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +3 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +4 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
  13. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
  14. package/dist/cli/args.d.ts +4 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +31 -1
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-directory-layout.d.ts +15 -0
  19. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  20. package/dist/core/agent-directory-layout.js +72 -0
  21. package/dist/core/agent-directory-layout.js.map +1 -0
  22. package/dist/core/agent-paths.d.ts +25 -2
  23. package/dist/core/agent-paths.d.ts.map +1 -1
  24. package/dist/core/agent-paths.js +79 -4
  25. package/dist/core/agent-paths.js.map +1 -1
  26. package/dist/core/agent-session-contracts.d.ts +293 -0
  27. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  28. package/dist/core/agent-session-contracts.js +26 -0
  29. package/dist/core/agent-session-contracts.js.map +1 -0
  30. package/dist/core/agent-session-runtime.d.ts +52 -8
  31. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  32. package/dist/core/agent-session-runtime.js +400 -79
  33. package/dist/core/agent-session-runtime.js.map +1 -1
  34. package/dist/core/agent-session-services.d.ts +1 -0
  35. package/dist/core/agent-session-services.d.ts.map +1 -1
  36. package/dist/core/agent-session-services.js +1 -0
  37. package/dist/core/agent-session-services.js.map +1 -1
  38. package/dist/core/agent-session.d.ts +74 -518
  39. package/dist/core/agent-session.d.ts.map +1 -1
  40. package/dist/core/agent-session.js +370 -1432
  41. package/dist/core/agent-session.js.map +1 -1
  42. package/dist/core/auth-storage.d.ts.map +1 -1
  43. package/dist/core/auth-storage.js +3 -1
  44. package/dist/core/auth-storage.js.map +1 -1
  45. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  46. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  47. package/dist/core/autonomy/approval-gate.js +6 -28
  48. package/dist/core/autonomy/approval-gate.js.map +1 -1
  49. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  50. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  51. package/dist/core/autonomy/bounded-completion.js +1 -1
  52. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  53. package/dist/core/autonomy/contracts.d.ts +20 -12
  54. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  55. package/dist/core/autonomy/contracts.js.map +1 -1
  56. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  57. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  58. package/dist/core/autonomy/foreground-envelope.js +8 -25
  59. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  60. package/dist/core/autonomy/gates.d.ts.map +1 -1
  61. package/dist/core/autonomy/gates.js +8 -10
  62. package/dist/core/autonomy/gates.js.map +1 -1
  63. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  64. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  65. package/dist/core/autonomy/lane-private-paths.js +16 -0
  66. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  67. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  68. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  69. package/dist/core/autonomy/lane-tool-surface.js +48 -9
  70. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  71. package/dist/core/autonomy/lane-tracker.d.ts +14 -0
  72. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  73. package/dist/core/autonomy/lane-tracker.js +38 -0
  74. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  75. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  76. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  77. package/dist/core/autonomy/risk-assessment.js +1 -123
  78. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  79. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  80. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  81. package/dist/core/autonomy/session-lane-record.js +16 -29
  82. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  83. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  84. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  85. package/dist/core/autonomy/telemetry-events.js +1 -1
  86. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  87. package/dist/core/autonomy-telemetry.d.ts +7 -7
  88. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  89. package/dist/core/autonomy-telemetry.js +9 -9
  90. package/dist/core/autonomy-telemetry.js.map +1 -1
  91. package/dist/core/background-lane-controller.d.ts +56 -236
  92. package/dist/core/background-lane-controller.d.ts.map +1 -1
  93. package/dist/core/background-lane-controller.js +141 -1273
  94. package/dist/core/background-lane-controller.js.map +1 -1
  95. package/dist/core/bedrock-sso-login.d.ts +16 -0
  96. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  97. package/dist/core/bedrock-sso-login.js +98 -0
  98. package/dist/core/bedrock-sso-login.js.map +1 -0
  99. package/dist/core/capability-contract.d.ts +4 -0
  100. package/dist/core/capability-contract.d.ts.map +1 -0
  101. package/dist/core/capability-contract.js +28 -0
  102. package/dist/core/capability-contract.js.map +1 -0
  103. package/dist/core/compaction-controller.d.ts +90 -0
  104. package/dist/core/compaction-controller.d.ts.map +1 -0
  105. package/dist/core/compaction-controller.js +452 -0
  106. package/dist/core/compaction-controller.js.map +1 -0
  107. package/dist/core/compaction-support.d.ts +13 -17
  108. package/dist/core/compaction-support.d.ts.map +1 -1
  109. package/dist/core/compaction-support.js +3 -3
  110. package/dist/core/compaction-support.js.map +1 -1
  111. package/dist/core/context/context-artifacts.d.ts +6 -2
  112. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  113. package/dist/core/context/context-artifacts.js +34 -2
  114. package/dist/core/context/context-artifacts.js.map +1 -1
  115. package/dist/core/context/context-store-retention.d.ts +8 -2
  116. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  117. package/dist/core/context/context-store-retention.js +158 -35
  118. package/dist/core/context/context-store-retention.js.map +1 -1
  119. package/dist/core/context/okf-memory.d.ts.map +1 -1
  120. package/dist/core/context/okf-memory.js +9 -11
  121. package/dist/core/context/okf-memory.js.map +1 -1
  122. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  123. package/dist/core/context/sqlite-runtime-index.js +6 -8
  124. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  125. package/dist/core/context-gc.d.ts +3 -0
  126. package/dist/core/context-gc.d.ts.map +1 -1
  127. package/dist/core/context-gc.js +10 -5
  128. package/dist/core/context-gc.js.map +1 -1
  129. package/dist/core/context-pipeline.d.ts +1 -1
  130. package/dist/core/context-pipeline.d.ts.map +1 -1
  131. package/dist/core/context-pipeline.js +16 -37
  132. package/dist/core/context-pipeline.js.map +1 -1
  133. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  134. package/dist/core/cost/cost-summary.js +5 -3
  135. package/dist/core/cost/cost-summary.js.map +1 -1
  136. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  137. package/dist/core/cost/daily-usage.js +4 -5
  138. package/dist/core/cost/daily-usage.js.map +1 -1
  139. package/dist/core/default-tool-surface.d.ts.map +1 -1
  140. package/dist/core/default-tool-surface.js +2 -0
  141. package/dist/core/default-tool-surface.js.map +1 -1
  142. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  143. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  144. package/dist/core/delegation/managed-lane-controller.js +217 -0
  145. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  146. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  147. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-claim.js +98 -0
  149. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  150. package/dist/core/delegation/worker-actions.d.ts +7 -5
  151. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  152. package/dist/core/delegation/worker-actions.js +20 -4
  153. package/dist/core/delegation/worker-actions.js.map +1 -1
  154. package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
  155. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  156. package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
  157. package/dist/core/delegation/worker-claim.js.map +1 -0
  158. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  159. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  160. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  161. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  162. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  163. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  164. package/dist/core/delegation/worker-delegation-request.js +2 -0
  165. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  166. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  167. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  168. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  169. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  170. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  171. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  172. package/dist/core/delegation/worker-execution-policy.js +160 -0
  173. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  174. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  175. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  176. package/dist/core/delegation/worker-lane-projection.js +100 -0
  177. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  178. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  179. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  180. package/dist/core/delegation/worker-lifecycle.js +339 -0
  181. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  182. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  183. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  184. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  185. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  186. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  187. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  188. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  189. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  190. package/dist/core/delegation/worker-runner.d.ts +25 -14
  191. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  192. package/dist/core/delegation/worker-runner.js +122 -53
  193. package/dist/core/delegation/worker-runner.js.map +1 -1
  194. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  195. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  196. package/dist/core/delegation/worker-task-label.js +11 -0
  197. package/dist/core/delegation/worker-task-label.js.map +1 -0
  198. package/dist/core/doctor.d.ts +8 -0
  199. package/dist/core/doctor.d.ts.map +1 -1
  200. package/dist/core/doctor.js +32 -1
  201. package/dist/core/doctor.js.map +1 -1
  202. package/dist/core/extension-import-authority.d.ts +6 -0
  203. package/dist/core/extension-import-authority.d.ts.map +1 -0
  204. package/dist/core/extension-import-authority.js +10 -0
  205. package/dist/core/extension-import-authority.js.map +1 -0
  206. package/dist/core/extensions/index.d.ts +1 -1
  207. package/dist/core/extensions/index.d.ts.map +1 -1
  208. package/dist/core/extensions/index.js.map +1 -1
  209. package/dist/core/extensions/loader.d.ts +5 -1
  210. package/dist/core/extensions/loader.d.ts.map +1 -1
  211. package/dist/core/extensions/loader.js +52 -18
  212. package/dist/core/extensions/loader.js.map +1 -1
  213. package/dist/core/extensions/runner.d.ts +3 -0
  214. package/dist/core/extensions/runner.d.ts.map +1 -1
  215. package/dist/core/extensions/runner.js +20 -5
  216. package/dist/core/extensions/runner.js.map +1 -1
  217. package/dist/core/extensions/stale-context.d.ts +2 -0
  218. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  219. package/dist/core/extensions/stale-context.js +2 -0
  220. package/dist/core/extensions/stale-context.js.map +1 -0
  221. package/dist/core/extensions/storage.d.ts +8 -0
  222. package/dist/core/extensions/storage.d.ts.map +1 -0
  223. package/dist/core/extensions/storage.js +28 -0
  224. package/dist/core/extensions/storage.js.map +1 -0
  225. package/dist/core/extensions/types.d.ts +78 -21
  226. package/dist/core/extensions/types.d.ts.map +1 -1
  227. package/dist/core/extensions/types.js.map +1 -1
  228. package/dist/core/failure-corpus.d.ts +1 -15
  229. package/dist/core/failure-corpus.d.ts.map +1 -1
  230. package/dist/core/failure-corpus.js +9 -37
  231. package/dist/core/failure-corpus.js.map +1 -1
  232. package/dist/core/foreground-recovery-controller.d.ts +53 -0
  233. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  234. package/dist/core/foreground-recovery-controller.js +111 -0
  235. package/dist/core/foreground-recovery-controller.js.map +1 -0
  236. package/dist/core/gateways/channel-provider.d.ts +3 -0
  237. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  238. package/dist/core/gateways/channel-provider.js +31 -6
  239. package/dist/core/gateways/channel-provider.js.map +1 -1
  240. package/dist/core/goal-loop-controller.d.ts +14 -9
  241. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  242. package/dist/core/goal-loop-controller.js +47 -75
  243. package/dist/core/goal-loop-controller.js.map +1 -1
  244. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  245. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  246. package/dist/core/goals/compact-goal-context.js +59 -0
  247. package/dist/core/goals/compact-goal-context.js.map +1 -0
  248. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  249. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  250. package/dist/core/goals/goal-acceptance.js +27 -0
  251. package/dist/core/goals/goal-acceptance.js.map +1 -0
  252. package/dist/core/goals/goal-auto-continue-controller.d.ts +28 -0
  253. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  254. package/dist/core/goals/goal-auto-continue-controller.js +90 -0
  255. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  256. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  257. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  258. package/dist/core/goals/goal-continuation-controller.js +52 -11
  259. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  260. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  261. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  262. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  263. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  264. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  265. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  266. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  267. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  268. package/dist/core/goals/goal-lifecycle.d.ts +43 -0
  269. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  270. package/dist/core/goals/goal-lifecycle.js +102 -0
  271. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  272. package/dist/core/goals/goal-record.d.ts +17 -0
  273. package/dist/core/goals/goal-record.d.ts.map +1 -0
  274. package/dist/core/goals/goal-record.js +31 -0
  275. package/dist/core/goals/goal-record.js.map +1 -0
  276. package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
  277. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  278. package/dist/core/goals/goal-runtime-snapshot.js +10 -8
  279. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  280. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  281. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  282. package/dist/core/goals/goal-session-controller.js +128 -0
  283. package/dist/core/goals/goal-session-controller.js.map +1 -0
  284. package/dist/core/goals/goal-state.d.ts +46 -25
  285. package/dist/core/goals/goal-state.d.ts.map +1 -1
  286. package/dist/core/goals/goal-state.js +91 -24
  287. package/dist/core/goals/goal-state.js.map +1 -1
  288. package/dist/core/goals/goal-tool-core.d.ts +9 -10
  289. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  290. package/dist/core/goals/goal-tool-core.js +60 -75
  291. package/dist/core/goals/goal-tool-core.js.map +1 -1
  292. package/dist/core/goals/session-goal-state.d.ts +20 -12
  293. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  294. package/dist/core/goals/session-goal-state.js +133 -33
  295. package/dist/core/goals/session-goal-state.js.map +1 -1
  296. package/dist/core/human-input-controller.d.ts +47 -0
  297. package/dist/core/human-input-controller.d.ts.map +1 -0
  298. package/dist/core/human-input-controller.js +181 -0
  299. package/dist/core/human-input-controller.js.map +1 -0
  300. package/dist/core/human-input.d.ts +100 -0
  301. package/dist/core/human-input.d.ts.map +1 -0
  302. package/dist/core/human-input.js +362 -0
  303. package/dist/core/human-input.js.map +1 -0
  304. package/dist/core/index.d.ts +9 -1
  305. package/dist/core/index.d.ts.map +1 -1
  306. package/dist/core/index.js +9 -1
  307. package/dist/core/index.js.map +1 -1
  308. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  309. package/dist/core/install-telemetry.d.ts.map +1 -0
  310. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  311. package/dist/core/install-telemetry.js.map +1 -0
  312. package/dist/core/keybindings.d.ts +17 -1
  313. package/dist/core/keybindings.d.ts.map +1 -1
  314. package/dist/core/keybindings.js +24 -6
  315. package/dist/core/keybindings.js.map +1 -1
  316. package/dist/core/learning/learning-audit.d.ts +2 -4
  317. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  318. package/dist/core/learning/learning-audit.js +9 -29
  319. package/dist/core/learning/learning-audit.js.map +1 -1
  320. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  321. package/dist/core/learning/learning-gate.js +1 -6
  322. package/dist/core/learning/learning-gate.js.map +1 -1
  323. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  324. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  325. package/dist/core/learning/session-learning-decision.js +9 -29
  326. package/dist/core/learning/session-learning-decision.js.map +1 -1
  327. package/dist/core/local-runtime-controller.d.ts +1 -1
  328. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  329. package/dist/core/local-runtime-controller.js.map +1 -1
  330. package/dist/core/memory-controller.d.ts.map +1 -1
  331. package/dist/core/memory-controller.js +4 -4
  332. package/dist/core/memory-controller.js.map +1 -1
  333. package/dist/core/model-capability.d.ts +0 -19
  334. package/dist/core/model-capability.d.ts.map +1 -1
  335. package/dist/core/model-capability.js +1 -19
  336. package/dist/core/model-capability.js.map +1 -1
  337. package/dist/core/model-registry.d.ts +6 -1
  338. package/dist/core/model-registry.d.ts.map +1 -1
  339. package/dist/core/model-registry.js +13 -5
  340. package/dist/core/model-registry.js.map +1 -1
  341. package/dist/core/model-resolver.d.ts +17 -2
  342. package/dist/core/model-resolver.d.ts.map +1 -1
  343. package/dist/core/model-resolver.js +38 -25
  344. package/dist/core/model-resolver.js.map +1 -1
  345. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  346. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  347. package/dist/core/model-router/intent-classifier.js +1 -156
  348. package/dist/core/model-router/intent-classifier.js.map +1 -1
  349. package/dist/core/model-router-controller.d.ts +1 -1
  350. package/dist/core/model-router-controller.d.ts.map +1 -1
  351. package/dist/core/model-router-controller.js +2 -2
  352. package/dist/core/model-router-controller.js.map +1 -1
  353. package/dist/core/model-selection-controller.d.ts +5 -5
  354. package/dist/core/model-selection-controller.d.ts.map +1 -1
  355. package/dist/core/model-selection-controller.js.map +1 -1
  356. package/dist/core/model-tool-protocol.d.ts +23 -0
  357. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  358. package/dist/core/model-tool-protocol.js +43 -0
  359. package/dist/core/model-tool-protocol.js.map +1 -0
  360. package/dist/core/models/adaptation-store.d.ts +4 -6
  361. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  362. package/dist/core/models/adaptation-store.js +95 -83
  363. package/dist/core/models/adaptation-store.js.map +1 -1
  364. package/dist/core/models/fitness-store.d.ts +2 -12
  365. package/dist/core/models/fitness-store.d.ts.map +1 -1
  366. package/dist/core/models/fitness-store.js +84 -57
  367. package/dist/core/models/fitness-store.js.map +1 -1
  368. package/dist/core/models/host-state-store.d.ts +34 -0
  369. package/dist/core/models/host-state-store.d.ts.map +1 -0
  370. package/dist/core/models/host-state-store.js +86 -0
  371. package/dist/core/models/host-state-store.js.map +1 -0
  372. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  373. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  374. package/dist/core/orchestration/agent-resume.js +90 -0
  375. package/dist/core/orchestration/agent-resume.js.map +1 -0
  376. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  377. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  378. package/dist/core/orchestration/capability-gateway.js +152 -0
  379. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  380. package/dist/core/orchestration/contracts.d.ts +343 -0
  381. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  382. package/dist/core/orchestration/contracts.js +135 -0
  383. package/dist/core/orchestration/contracts.js.map +1 -0
  384. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  385. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  386. package/dist/core/orchestration/delegation-ledger.js +200 -0
  387. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  388. package/dist/core/orchestration/event-store.d.ts +83 -0
  389. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  390. package/dist/core/orchestration/event-store.js +560 -0
  391. package/dist/core/orchestration/event-store.js.map +1 -0
  392. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  393. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  394. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  395. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  396. package/dist/core/orchestration/model-binding.d.ts +15 -0
  397. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  398. package/dist/core/orchestration/model-binding.js +29 -0
  399. package/dist/core/orchestration/model-binding.js.map +1 -0
  400. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  401. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  402. package/dist/core/orchestration/policy-compiler.js +191 -0
  403. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  404. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  405. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  406. package/dist/core/orchestration/policy-gate.js +24 -0
  407. package/dist/core/orchestration/policy-gate.js.map +1 -0
  408. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  409. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  410. package/dist/core/orchestration/profile-registry.js +393 -0
  411. package/dist/core/orchestration/profile-registry.js.map +1 -0
  412. package/dist/core/orchestration/profile-store.d.ts +31 -0
  413. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  414. package/dist/core/orchestration/profile-store.js +136 -0
  415. package/dist/core/orchestration/profile-store.js.map +1 -0
  416. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  417. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  418. package/dist/core/orchestration/risk-budget.js +48 -0
  419. package/dist/core/orchestration/risk-budget.js.map +1 -0
  420. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  421. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  422. package/dist/core/orchestration/task-runtime.js +1600 -0
  423. package/dist/core/orchestration/task-runtime.js.map +1 -0
  424. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  425. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  426. package/dist/core/orchestration/work-state-projection.js +116 -0
  427. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  428. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  429. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  430. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  431. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  432. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  433. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  434. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  435. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  436. package/dist/core/package-manager.d.ts.map +1 -1
  437. package/dist/core/package-manager.js +20 -3
  438. package/dist/core/package-manager.js.map +1 -1
  439. package/dist/core/process-identity.d.ts +11 -0
  440. package/dist/core/process-identity.d.ts.map +1 -0
  441. package/dist/core/process-identity.js +26 -0
  442. package/dist/core/process-identity.js.map +1 -0
  443. package/dist/core/process-matrix/codes.d.ts +14 -3
  444. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  445. package/dist/core/process-matrix/codes.js.map +1 -1
  446. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  447. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  448. package/dist/core/process-matrix/resume-launcher.js +62 -0
  449. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  450. package/dist/core/process-matrix/runtime.d.ts +37 -22
  451. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  452. package/dist/core/process-matrix/runtime.js +399 -76
  453. package/dist/core/process-matrix/runtime.js.map +1 -1
  454. package/dist/core/process-matrix/store.d.ts +5 -2
  455. package/dist/core/process-matrix/store.d.ts.map +1 -1
  456. package/dist/core/process-matrix/store.js +123 -14
  457. package/dist/core/process-matrix/store.js.map +1 -1
  458. package/dist/core/process-matrix/supervisor.d.ts +10 -7
  459. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  460. package/dist/core/process-matrix/supervisor.js +45 -14
  461. package/dist/core/process-matrix/supervisor.js.map +1 -1
  462. package/dist/core/profile-filter-controller.d.ts +8 -1
  463. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  464. package/dist/core/profile-filter-controller.js +23 -5
  465. package/dist/core/profile-filter-controller.js.map +1 -1
  466. package/dist/core/profile-registry.d.ts.map +1 -1
  467. package/dist/core/profile-registry.js +6 -8
  468. package/dist/core/profile-registry.js.map +1 -1
  469. package/dist/core/prompt-templates.d.ts +1 -0
  470. package/dist/core/prompt-templates.d.ts.map +1 -1
  471. package/dist/core/prompt-templates.js +18 -29
  472. package/dist/core/prompt-templates.js.map +1 -1
  473. package/dist/core/reflection-controller.d.ts +5 -5
  474. package/dist/core/reflection-controller.d.ts.map +1 -1
  475. package/dist/core/reflection-controller.js +5 -2
  476. package/dist/core/reflection-controller.js.map +1 -1
  477. package/dist/core/reload-blockers.d.ts.map +1 -1
  478. package/dist/core/reload-blockers.js +6 -8
  479. package/dist/core/reload-blockers.js.map +1 -1
  480. package/dist/core/request-auth.d.ts +7 -0
  481. package/dist/core/request-auth.d.ts.map +1 -0
  482. package/dist/core/request-auth.js +8 -0
  483. package/dist/core/request-auth.js.map +1 -0
  484. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  485. package/dist/core/research/evidence-bundle.js +1 -6
  486. package/dist/core/research/evidence-bundle.js.map +1 -1
  487. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  488. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  489. package/dist/core/research/lane-model-resolver.js +65 -0
  490. package/dist/core/research/lane-model-resolver.js.map +1 -0
  491. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  492. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  493. package/dist/core/research/model-fitness-controller.js +106 -0
  494. package/dist/core/research/model-fitness-controller.js.map +1 -0
  495. package/dist/core/research/model-fitness.d.ts +1 -1
  496. package/dist/core/research/model-fitness.d.ts.map +1 -1
  497. package/dist/core/research/model-fitness.js +4 -4
  498. package/dist/core/research/model-fitness.js.map +1 -1
  499. package/dist/core/research/research-gate.d.ts.map +1 -1
  500. package/dist/core/research/research-gate.js +7 -7
  501. package/dist/core/research/research-gate.js.map +1 -1
  502. package/dist/core/research/research-lane-controller.d.ts +62 -0
  503. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  504. package/dist/core/research/research-lane-controller.js +292 -0
  505. package/dist/core/research/research-lane-controller.js.map +1 -0
  506. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  507. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  508. package/dist/core/research/session-evidence-bundle.js +10 -46
  509. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  510. package/dist/core/resource-loader.d.ts.map +1 -1
  511. package/dist/core/resource-loader.js +23 -8
  512. package/dist/core/resource-loader.js.map +1 -1
  513. package/dist/core/risk-classifier.d.ts +6 -0
  514. package/dist/core/risk-classifier.d.ts.map +1 -0
  515. package/dist/core/risk-classifier.js +233 -0
  516. package/dist/core/risk-classifier.js.map +1 -0
  517. package/dist/core/runtime-builder.d.ts +41 -23
  518. package/dist/core/runtime-builder.d.ts.map +1 -1
  519. package/dist/core/runtime-builder.js +365 -253
  520. package/dist/core/runtime-builder.js.map +1 -1
  521. package/dist/core/sdk.d.ts +6 -3
  522. package/dist/core/sdk.d.ts.map +1 -1
  523. package/dist/core/sdk.js +68 -25
  524. package/dist/core/sdk.js.map +1 -1
  525. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  526. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  527. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  528. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  529. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  530. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  531. package/dist/core/secrets/secret-dotenv.js +183 -0
  532. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  533. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  534. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  535. package/dist/core/secrets/secret-vault-format.js +397 -0
  536. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  537. package/dist/core/secrets/secret-vault.d.ts +72 -0
  538. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  539. package/dist/core/secrets/secret-vault.js +671 -0
  540. package/dist/core/secrets/secret-vault.js.map +1 -0
  541. package/dist/core/session-analytics.d.ts +4 -23
  542. package/dist/core/session-analytics.d.ts.map +1 -1
  543. package/dist/core/session-analytics.js +67 -70
  544. package/dist/core/session-analytics.js.map +1 -1
  545. package/dist/core/session-image-store.d.ts +33 -0
  546. package/dist/core/session-image-store.d.ts.map +1 -0
  547. package/dist/core/session-image-store.js +283 -0
  548. package/dist/core/session-image-store.js.map +1 -0
  549. package/dist/core/session-role.d.ts +11 -4
  550. package/dist/core/session-role.d.ts.map +1 -1
  551. package/dist/core/session-role.js +24 -5
  552. package/dist/core/session-role.js.map +1 -1
  553. package/dist/core/session-snapshot.d.ts +34 -0
  554. package/dist/core/session-snapshot.d.ts.map +1 -0
  555. package/dist/core/session-snapshot.js +68 -0
  556. package/dist/core/session-snapshot.js.map +1 -0
  557. package/dist/core/session-supervision-runtime.d.ts +31 -0
  558. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  559. package/dist/core/session-supervision-runtime.js +97 -0
  560. package/dist/core/session-supervision-runtime.js.map +1 -0
  561. package/dist/core/session-tree-navigator.d.ts +4 -6
  562. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  563. package/dist/core/session-tree-navigator.js +4 -1
  564. package/dist/core/session-tree-navigator.js.map +1 -1
  565. package/dist/core/settings-manager.d.ts +10 -5
  566. package/dist/core/settings-manager.d.ts.map +1 -1
  567. package/dist/core/settings-manager.js +81 -29
  568. package/dist/core/settings-manager.js.map +1 -1
  569. package/dist/core/slash-commands.d.ts.map +1 -1
  570. package/dist/core/slash-commands.js +2 -2
  571. package/dist/core/slash-commands.js.map +1 -1
  572. package/dist/core/tasks/session-task-state.d.ts +2 -4
  573. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  574. package/dist/core/tasks/session-task-state.js +10 -28
  575. package/dist/core/tasks/session-task-state.js.map +1 -1
  576. package/dist/core/tasks/task-projection.d.ts +20 -0
  577. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  578. package/dist/core/tasks/task-projection.js +47 -0
  579. package/dist/core/tasks/task-projection.js.map +1 -0
  580. package/dist/core/tasks/task-state.d.ts +4 -0
  581. package/dist/core/tasks/task-state.d.ts.map +1 -1
  582. package/dist/core/tasks/task-state.js +28 -11
  583. package/dist/core/tasks/task-state.js.map +1 -1
  584. package/dist/core/tool-capability-policy.d.ts +13 -0
  585. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  586. package/dist/core/tool-capability-policy.js +86 -0
  587. package/dist/core/tool-capability-policy.js.map +1 -0
  588. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  589. package/dist/core/tool-gate-controller.js +8 -2
  590. package/dist/core/tool-gate-controller.js.map +1 -1
  591. package/dist/core/tool-protocol-controller.d.ts +89 -0
  592. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  593. package/dist/core/tool-protocol-controller.js +512 -0
  594. package/dist/core/tool-protocol-controller.js.map +1 -0
  595. package/dist/core/tool-recovery-log-records.d.ts +2 -3
  596. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  597. package/dist/core/tool-recovery-log-records.js +9 -35
  598. package/dist/core/tool-recovery-log-records.js.map +1 -1
  599. package/dist/core/tool-recovery-stats.d.ts +21 -1
  600. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  601. package/dist/core/tool-recovery-stats.js.map +1 -1
  602. package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
  603. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  604. package/dist/core/tool-selection/tool-performance-store.js +97 -138
  605. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  606. package/dist/core/tools/ask-question.d.ts +124 -0
  607. package/dist/core/tools/ask-question.d.ts.map +1 -0
  608. package/dist/core/tools/ask-question.js +693 -0
  609. package/dist/core/tools/ask-question.js.map +1 -0
  610. package/dist/core/tools/bash.d.ts +5 -0
  611. package/dist/core/tools/bash.d.ts.map +1 -1
  612. package/dist/core/tools/bash.js +59 -5
  613. package/dist/core/tools/bash.js.map +1 -1
  614. package/dist/core/tools/delegate-status.d.ts +31 -3
  615. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  616. package/dist/core/tools/delegate-status.js +148 -29
  617. package/dist/core/tools/delegate-status.js.map +1 -1
  618. package/dist/core/tools/delegate.d.ts +15 -13
  619. package/dist/core/tools/delegate.d.ts.map +1 -1
  620. package/dist/core/tools/delegate.js +106 -23
  621. package/dist/core/tools/delegate.js.map +1 -1
  622. package/dist/core/tools/extensionify.d.ts.map +1 -1
  623. package/dist/core/tools/extensionify.js +1 -0
  624. package/dist/core/tools/extensionify.js.map +1 -1
  625. package/dist/core/tools/git-filter.d.ts +1 -8
  626. package/dist/core/tools/git-filter.d.ts.map +1 -1
  627. package/dist/core/tools/git-filter.js +2 -63
  628. package/dist/core/tools/git-filter.js.map +1 -1
  629. package/dist/core/tools/goal.d.ts +10 -8
  630. package/dist/core/tools/goal.d.ts.map +1 -1
  631. package/dist/core/tools/goal.js +106 -28
  632. package/dist/core/tools/goal.js.map +1 -1
  633. package/dist/core/tools/index.d.ts +1 -0
  634. package/dist/core/tools/index.d.ts.map +1 -1
  635. package/dist/core/tools/index.js +1 -0
  636. package/dist/core/tools/index.js.map +1 -1
  637. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  638. package/dist/core/tools/model-fitness.js +2 -2
  639. package/dist/core/tools/model-fitness.js.map +1 -1
  640. package/dist/core/tools/orchestration-panel.d.ts +40 -0
  641. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  642. package/dist/core/tools/orchestration-panel.js +124 -0
  643. package/dist/core/tools/orchestration-panel.js.map +1 -0
  644. package/dist/core/tools/output-accumulator.d.ts +11 -0
  645. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  646. package/dist/core/tools/output-accumulator.js +36 -3
  647. package/dist/core/tools/output-accumulator.js.map +1 -1
  648. package/dist/core/tools/python.d.ts +2 -0
  649. package/dist/core/tools/python.d.ts.map +1 -1
  650. package/dist/core/tools/python.js +3 -1
  651. package/dist/core/tools/python.js.map +1 -1
  652. package/dist/core/tools/read.d.ts.map +1 -1
  653. package/dist/core/tools/read.js +1 -1
  654. package/dist/core/tools/read.js.map +1 -1
  655. package/dist/core/tools/run-process.d.ts +26 -0
  656. package/dist/core/tools/run-process.d.ts.map +1 -0
  657. package/dist/core/tools/run-process.js +138 -0
  658. package/dist/core/tools/run-process.js.map +1 -0
  659. package/dist/core/tools/search-command-guard.d.ts +14 -0
  660. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  661. package/dist/core/tools/search-command-guard.js +333 -0
  662. package/dist/core/tools/search-command-guard.js.map +1 -0
  663. package/dist/core/tools/secret-store.d.ts +38 -0
  664. package/dist/core/tools/secret-store.d.ts.map +1 -0
  665. package/dist/core/tools/secret-store.js +412 -0
  666. package/dist/core/tools/secret-store.js.map +1 -0
  667. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  668. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  669. package/dist/core/tools/shell-command-parser.js +113 -0
  670. package/dist/core/tools/shell-command-parser.js.map +1 -0
  671. package/dist/core/tools/task-steps.d.ts +2 -0
  672. package/dist/core/tools/task-steps.d.ts.map +1 -1
  673. package/dist/core/tools/task-steps.js +99 -0
  674. package/dist/core/tools/task-steps.js.map +1 -1
  675. package/dist/core/tools/tmux-dispatch.d.ts +3 -5
  676. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  677. package/dist/core/tools/tmux-dispatch.js +4 -4
  678. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  679. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  680. package/dist/core/tools/windows-shell-engine.js +4 -6
  681. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  682. package/dist/core/util/atomic-file.d.ts +6 -2
  683. package/dist/core/util/atomic-file.d.ts.map +1 -1
  684. package/dist/core/util/atomic-file.js +4 -4
  685. package/dist/core/util/atomic-file.js.map +1 -1
  686. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  687. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  688. package/dist/core/util/bounded-jsonl.js +75 -0
  689. package/dist/core/util/bounded-jsonl.js.map +1 -0
  690. package/dist/core/util/value-guards.d.ts +5 -0
  691. package/dist/core/util/value-guards.d.ts.map +1 -0
  692. package/dist/core/util/value-guards.js +12 -0
  693. package/dist/core/util/value-guards.js.map +1 -0
  694. package/dist/core/worktree-sync/store.d.ts +3 -3
  695. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  696. package/dist/core/worktree-sync/store.js +10 -5
  697. package/dist/core/worktree-sync/store.js.map +1 -1
  698. package/dist/index.d.ts +15 -4
  699. package/dist/index.d.ts.map +1 -1
  700. package/dist/index.js +14 -3
  701. package/dist/index.js.map +1 -1
  702. package/dist/main.d.ts.map +1 -1
  703. package/dist/main.js +149 -51
  704. package/dist/main.js.map +1 -1
  705. package/dist/migrations.d.ts +4 -6
  706. package/dist/migrations.d.ts.map +1 -1
  707. package/dist/migrations.js +186 -28
  708. package/dist/migrations.js.map +1 -1
  709. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  710. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  711. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  712. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  713. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  714. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  715. package/dist/modes/interactive/clipboard-input.js +44 -6
  716. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  717. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  718. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  719. package/dist/modes/interactive/components/activity-lane.js +304 -0
  720. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  721. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  722. package/dist/modes/interactive/components/assistant-message.js +19 -10
  723. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  724. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  725. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  726. package/dist/modes/interactive/components/expandable-text.js +17 -0
  727. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  728. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  729. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  730. package/dist/modes/interactive/components/extension-editor.js +30 -21
  731. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  732. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  733. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  734. package/dist/modes/interactive/components/extension-input.js +6 -1
  735. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  736. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  737. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  738. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  739. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  740. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  741. package/dist/modes/interactive/components/settings-selector.js +6 -6
  742. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  743. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  744. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  745. package/dist/modes/interactive/components/tool-execution.js +53 -20
  746. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  747. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  748. package/dist/modes/interactive/components/tool-group.js +3 -0
  749. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  750. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  751. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  752. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  753. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  754. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  755. package/dist/modes/interactive/config-backup.js +5 -4
  756. package/dist/modes/interactive/config-backup.js.map +1 -1
  757. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  758. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  759. package/dist/modes/interactive/extension-ui-host.js +77 -15
  760. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  761. package/dist/modes/interactive/external-editor.d.ts +15 -0
  762. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  763. package/dist/modes/interactive/external-editor.js +27 -19
  764. package/dist/modes/interactive/external-editor.js.map +1 -1
  765. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  766. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  767. package/dist/modes/interactive/history-reload-math.js +10 -5
  768. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  769. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  770. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  771. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  772. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  773. package/dist/modes/interactive/interactive-mode.d.ts +22 -24
  774. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  775. package/dist/modes/interactive/interactive-mode.js +245 -595
  776. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  777. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  778. package/dist/modes/interactive/key-handlers.js +1 -1
  779. package/dist/modes/interactive/key-handlers.js.map +1 -1
  780. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  781. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  782. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  783. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  784. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  785. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  786. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  787. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  788. package/dist/modes/interactive/report-commands.js +21 -0
  789. package/dist/modes/interactive/report-commands.js.map +1 -1
  790. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  791. package/dist/modes/interactive/resource-display.js +8 -2
  792. package/dist/modes/interactive/resource-display.js.map +1 -1
  793. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  794. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  795. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  796. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  797. package/dist/modes/interactive/session-flow-commands.d.ts +27 -8
  798. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  799. package/dist/modes/interactive/session-flow-commands.js +150 -64
  800. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  801. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  802. package/dist/modes/interactive/session-io-commands.js +16 -6
  803. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  804. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  805. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  806. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  807. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  808. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  809. package/dist/modes/interactive/startup-checks.js +1 -1
  810. package/dist/modes/interactive/startup-checks.js.map +1 -1
  811. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  812. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  813. package/dist/modes/interactive/usage-commands.js +225 -0
  814. package/dist/modes/interactive/usage-commands.js.map +1 -0
  815. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  816. package/dist/modes/rpc/rpc-mode.js +82 -23
  817. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  818. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  819. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  820. package/dist/modes/rpc/rpc-types.js +138 -1
  821. package/dist/modes/rpc/rpc-types.js.map +1 -1
  822. package/dist/utils/clipboard-image.d.ts.map +1 -1
  823. package/dist/utils/clipboard-image.js +2 -13
  824. package/dist/utils/clipboard-image.js.map +1 -1
  825. package/dist/utils/clipboard-native.d.ts +1 -0
  826. package/dist/utils/clipboard-native.d.ts.map +1 -1
  827. package/dist/utils/clipboard-native.js.map +1 -1
  828. package/dist/utils/clipboard.d.ts +1 -0
  829. package/dist/utils/clipboard.d.ts.map +1 -1
  830. package/dist/utils/clipboard.js +52 -1
  831. package/dist/utils/clipboard.js.map +1 -1
  832. package/dist/utils/platform.d.ts +3 -0
  833. package/dist/utils/platform.d.ts.map +1 -0
  834. package/dist/utils/platform.js +8 -0
  835. package/dist/utils/platform.js.map +1 -0
  836. package/dist/utils/shell.d.ts.map +1 -1
  837. package/dist/utils/shell.js +5 -3
  838. package/dist/utils/shell.js.map +1 -1
  839. package/dist/utils/version-check.d.ts.map +1 -1
  840. package/dist/utils/version-check.js +3 -1
  841. package/dist/utils/version-check.js.map +1 -1
  842. package/dist/utils/work-directory.d.ts +11 -0
  843. package/dist/utils/work-directory.d.ts.map +1 -1
  844. package/dist/utils/work-directory.js +30 -9
  845. package/dist/utils/work-directory.js.map +1 -1
  846. package/docs/UI_POLISH_ORCHESTRATION.md +38 -0
  847. package/docs/UI_QUALITY_ORCHESTRATION.md +28 -0
  848. package/docs/docs.json +4 -0
  849. package/docs/extensions.md +62 -2
  850. package/docs/harness-architecture.md +156 -0
  851. package/docs/keybindings.md +11 -1
  852. package/docs/process-matrix.md +59 -26
  853. package/docs/providers.md +9 -1
  854. package/docs/rpc.md +45 -2
  855. package/docs/sessions.md +15 -0
  856. package/docs/settings.md +125 -11
  857. package/docs/task-steps.md +8 -0
  858. package/docs/telemetry.md +19 -0
  859. package/docs/tmux-agent-manager.md +10 -3
  860. package/docs/ui-reference/README.md +9 -0
  861. package/docs/ui-reference/orchestration-after.txt +14 -0
  862. package/docs/ui-reference/orchestration-before.txt +13 -0
  863. package/docs/ui-reference/orchestration-reference.txt +16 -0
  864. package/docs/usage.md +22 -2
  865. package/docs/work-directory.md +19 -8
  866. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  867. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  868. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  869. package/examples/extensions/question.ts +34 -245
  870. package/examples/extensions/questionnaire.ts +41 -407
  871. package/examples/extensions/sandbox/package-lock.json +2 -2
  872. package/examples/extensions/sandbox/package.json +1 -1
  873. package/examples/extensions/with-deps/package-lock.json +2 -2
  874. package/examples/extensions/with-deps/package.json +1 -1
  875. package/npm-shrinkwrap.json +13 -13
  876. package/package.json +4 -4
  877. package/dist/core/delegation/session-worker-result.d.ts +0 -46
  878. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  879. package/dist/core/delegation/session-worker-result.js +0 -113
  880. package/dist/core/delegation/session-worker-result.js.map +0 -1
  881. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  882. package/dist/core/delegation/worker-result.js.map +0 -1
  883. package/dist/core/telemetry.d.ts.map +0 -1
  884. package/dist/core/telemetry.js.map +0 -1
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Background-lane controller: goal auto-continue, the research lane, scout-worker delegation, and
3
- * the model-fitness probe.
2
+ * Execution-plane coordinator for goal continuation, research, managed lanes, worker delegation,
3
+ * and model fitness.
4
4
  *
5
- * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the lane timers, the
6
- * single-flight guards, the last research-lane skip reason, the live {@link LaneTracker}, and the
7
- * session-lifetime abort controllers for in-flight research/worker passes. Everything else it needs
5
+ * Coordination state is owned by focused controllers. This coordinator retains one AgentSession
6
+ * composition seam and a shared lane read model. Everything it needs
8
7
  * — the session manager, settings, model registry, live model, capability envelope, the goal
9
8
  * continuation LOOP, the isolated-completion primitive, spawned-usage accounting, and the telemetry
10
9
  * sink — is reached through narrow deps accessors rather than the whole AgentSession.
@@ -14,160 +13,34 @@
14
13
  * delegations; goal auto-continue itself only ever asks the session to `continueGoalLoop`, so this
15
14
  * controller never touches `prompt()`, the last-assistant-message, retry, or streaming state.
16
15
  */
17
- import { createHash } from "node:crypto";
18
- import path from "node:path";
19
- import { configFile, getWorkRoot, sessionsDir, stateDir } from "./agent-paths.js";
20
- import { createLaneToolSurface } from "./autonomy/lane-tool-surface.js";
21
16
  import { LaneTracker } from "./autonomy/lane-tracker.js";
22
- import { safeRealpathSync } from "./autonomy/path-scope.js";
23
- import { appendLaneRecordSnapshot, getLaneRecordSnapshots } from "./autonomy/session-lane-record.js";
24
- import { composeSubagentSystemPrompt } from "./autonomy/subagent-prompt.js";
25
- import { AUTONOMY_TELEMETRY_EVENT_TYPES } from "./autonomy/telemetry-events.js";
26
- import { applyWorkerActions } from "./delegation/worker-actions.js";
27
- import { reviewManagedLaneChangedFiles } from "./delegation/worker-result.js";
28
- import { runWorker } from "./delegation/worker-runner.js";
29
- import { deriveModelCapabilityProfile, scaleContinuationBudgetsForCapability, } from "./model-capability.js";
30
- import { resolveCliModel } from "./model-resolver.js";
31
- import { FitnessStore } from "./models/fitness-store.js";
32
- import { registerInFlightWork } from "./reload-blockers.js";
33
- import { runModelFitnessProbe } from "./research/model-fitness.js";
34
- import { runResearch } from "./research/research-runner.js";
35
- const WORKER_HANDOFF_TIMEOUT_MS = 30_000;
36
- export function clampLaneMaxUsd(settingsMaxUsd, foregroundMaxEstimatedUsd) {
37
- return Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);
38
- }
39
- /**
40
- * Deterministic `addSpawnedUsage` reportId: `kind` + session id + a content hash of `identity`
41
- * (never `Date.now`/random). Same identity on a retry of the same logical work unit yields the same
42
- * id, so the ledger's `seenSubagentReportIds` dedupe catches a duplicate report instead of
43
- * double-counting spend.
44
- */
45
- function deriveSpawnedUsageReportId(kind, sessionId, identity) {
46
- const digest = createHash("sha256").update(identity).digest("hex").slice(0, 16);
47
- return `${kind}:${sessionId}:${digest}`;
48
- }
49
- export function getPrivateLaneDeniedPaths(cwd, agentDir) {
50
- return [
51
- configFile(agentDir, "auth.json"),
52
- configFile(agentDir, "MEMORY.md"),
53
- configFile(agentDir, "USER.md"),
54
- configFile(agentDir, "settings.json"),
55
- configFile(agentDir, "models.json"),
56
- // trust.json now lives under state/ -- covered by the whole-state-dir
57
- // denial below instead of its own root-level entry.
58
- sessionsDir(agentDir),
59
- stateDir(agentDir),
60
- getWorkRoot(agentDir),
61
- ].concat(path.join(cwd, ".pi", "settings.json"));
62
- }
63
- const KNOWN_LANE_TERMINAL_STATUSES = new Set([
64
- "succeeded",
65
- "failed",
66
- "canceled",
67
- "timeout",
68
- "budget_exhausted",
69
- ]);
70
- /**
71
- * Resolves a managed lane's caller-reported terminal `status` (a free-form CLAIM — e.g. a tmux job's
72
- * own "done"/"blocked" completion marker, a lifecycle tag like "dismissed", or a raw
73
- * {@link WorkerResultStatus} spelling) onto the LaneTracker's {@link LaneTerminalStatus} vocabulary.
74
- * Mirrors the same success/blocked mapping direction `worker-runner.ts` already uses for in-process
75
- * workers ("completed"/"done" -> succeeded, "blocked" -> failed). An unrecognized or missing status is
76
- * conservatively reported as `"failed"` rather than silently assumed successful (claims-to-review).
77
- */
78
- export function resolveManagedLaneTerminalStatus(status) {
79
- if (status !== undefined && KNOWN_LANE_TERMINAL_STATUSES.has(status)) {
80
- return status;
81
- }
82
- switch (status) {
83
- case "done":
84
- case "completed":
85
- return "succeeded";
86
- case "blocked":
87
- return "failed";
88
- case "dismissed":
89
- case "cancelled":
90
- return "canceled";
91
- default:
92
- return "failed";
93
- }
94
- }
95
- /** Maps a LaneTracker terminal status onto the WorkerResult status vocabulary a managed-lane claim
96
- * snapshot is persisted under — the two enums use different spellings/values, never interchangeable
97
- * (e.g. `"canceled"` vs `"cancelled"`); `timeout`/`budget_exhausted` have no dedicated WorkerResult
98
- * counterpart and are conservatively reported as `"failed"`. */
99
- export function mapManagedLaneTerminalStatus(status) {
100
- switch (status) {
101
- case "succeeded":
102
- return "completed";
103
- case "canceled":
104
- return "cancelled";
105
- case "failed":
106
- case "timeout":
107
- case "budget_exhausted":
108
- return "failed";
109
- }
110
- }
111
- export function isLocalExecutionModel(model) {
112
- if (model.provider === "ollama" || model.provider === "transformers" || model.provider === "llama-cpp") {
113
- return true;
114
- }
115
- try {
116
- const hostname = new URL(model.baseUrl).hostname.toLowerCase();
117
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
118
- }
119
- catch {
120
- return false;
121
- }
122
- }
17
+ import { appendLaneRecordSnapshot, getLatestLaneRecordSnapshots } from "./autonomy/session-lane-record.js";
18
+ import { ManagedLaneController } from "./delegation/managed-lane-controller.js";
19
+ import { WorkerDelegationController, } from "./delegation/worker-delegation-controller.js";
20
+ import { WorkerLifecycle } from "./delegation/worker-lifecycle.js";
21
+ import { WorkerNotificationCoordinator } from "./delegation/worker-notification-coordinator.js";
22
+ import { GoalAutoContinueController } from "./goals/goal-auto-continue-controller.js";
23
+ import { LaneModelResolver } from "./research/lane-model-resolver.js";
24
+ import { ModelFitnessController } from "./research/model-fitness-controller.js";
25
+ import { ResearchLaneController } from "./research/research-lane-controller.js";
26
+ import { getActiveSessionBranchEntries } from "./session-snapshot.js";
27
+ export { isLocalExecutionModel } from "./delegation/worker-delegation-controller.js";
28
+ export { clampLaneMaxUsd } from "./research/lane-model-resolver.js";
123
29
  export class BackgroundLaneController {
124
- /** Pending idle timer that starts bounded goal continuation after the session becomes idle. */
125
- _goalAutoContinueTimer;
126
- /** Guards bounded idle autosteer so continuation prompts do not recursively trigger themselves. */
127
- _isGoalAutoContinuing = false;
128
- /** Pending idle timer that starts an autonomous research pass after the session becomes idle. */
129
- _researchLaneTimer;
130
- /** Single-flight guard: at most one research pass runs at a time per session. */
131
- _isResearchLaneRunning = false;
132
- /** Why the last idle research-lane evaluation skipped, for /autonomy diagnostics. */
133
- _lastResearchLaneSkipReason;
134
30
  /** Live lane registry — the real source for AutonomyStatusSnapshot.activeLaneCount. */
135
31
  _laneTracker = new LaneTracker();
136
- _laneHistorySeeded = false;
137
- _persistedResearchRunCount = 0;
138
- /** Session-lifetime abort for in-flight research passes (same pattern as _reflectionAbort). */
139
- _researchLaneAbort = new AbortController();
140
- /** Session-lifetime abort for in-flight delegated workers. */
141
- _workerDelegationAbort = new AbortController();
142
- /** Session-local de-duplication for fail-closed profile grants that cannot bind to lane tools. */
143
- _warnedUnboundLaneToolGrants = new Set();
144
- /** Every background execution is retained until its terminal result is observed. */
145
- _workerPromises = new Map();
146
- _queuedWorkers = new Map();
147
- _workerNotificationScheduled = false;
148
- _workerNotificationTail = Promise.resolve();
149
- _disposed = false;
150
- _workersCompletedSinceFlush = 0;
151
- _workersFailedSinceFlush = 0;
152
- _workerTerminalSinceFlush = [];
153
- /** Live per-lane mutation ledger for a RUNNING worker — the SAME `toolChangedFiles` Set its
154
- * `afterToolCall` hook mutates, plus a spend getter and the originating request. Read
155
- * synchronously by `abortInFlightLanes()`'s disposal cutoff, the only provably-safe write window
156
- * for a mid-flight cancellation (see that method); deleted there (consumed-ledger guard against
157
- * the post-await disposed branch re-persisting) or in the lane's own `finally` on a normal exit. */
158
- _inFlightWorkerLedgers = new Map();
159
- /** Reload-gate deregister function for a worker queued (not yet running) behind a
160
- * contending local-execution foreground model. Registered at enqueue so `/reload` waits for
161
- * queued work too, not just running work; deregistered exactly once, either on disposal
162
- * (`abortInFlightLanes`) or at the running handoff (`drainQueuedWorkerDelegations`). A laneId with
163
- * no entry here (e.g. seeded directly into `_queuedWorkers` by a test) is simply untracked —
164
- * deregistration is best-effort by design, never required. */
165
- _queuedWorkerDeregisters = new Map();
166
- /** Dispatch -> terminal correlation for out-of-process managed lanes (`pi.reportManagedLane`
167
- * host bridge), keyed by the CALLER's own `laneId` (e.g. a tmux job id) — distinct from the
168
- * internal `LaneTracker` id it maps to. Removed on the matching terminal report so a duplicate or
169
- * unmatched terminal call is a safe no-op instead of a double-deregister or an orphaned entry. */
170
- _managedLaneDispatches = new Map();
32
+ _laneModels;
33
+ _goalAutoContinue;
34
+ _research;
35
+ _fitness;
36
+ /** Lazily materialized only when managed-lane state is queried or reported. */
37
+ _managedLanes;
38
+ /** Lazily materialized so a UAC surface without `delegate` allocates no worker runtime state. */
39
+ _workers;
40
+ /** One durable lifecycle shared by every worker execution adapter. */
41
+ _workerLifecycle;
42
+ /** Shared terminal outbox for managed and in-process workers; lazy under UAC omission. */
43
+ _workerNotifications;
171
44
  deps;
172
45
  /** Emit a warning without ever throwing — used from disposal-adjacent persistence where a
173
46
  * listener failure (or a bare test double missing `emit`) must never block or crash cleanup. */
@@ -179,198 +52,121 @@ export class BackgroundLaneController {
179
52
  // Dispose must never throw.
180
53
  }
181
54
  }
182
- _scheduleWorkerNotification() {
183
- if (this._disposed || this._workerNotificationScheduled)
184
- return;
185
- this._workerNotificationScheduled = true;
186
- queueMicrotask(() => this._flushWorkerNotification());
55
+ _recordWorkerTerminal(record, durableNotificationId) {
56
+ this._getWorkerNotificationCoordinator().recordTerminal(record, durableNotificationId);
187
57
  }
188
- _flushWorkerNotification() {
189
- this._workerNotificationScheduled = false;
190
- if (this._disposed)
191
- return;
192
- const queued = this._laneTracker
193
- .getRecords()
194
- .filter((record) => record.type === "worker" && record.status === "queued").length;
195
- const running = this._laneTracker.getRunningCount("worker");
196
- const terminalSinceFlush = this._workerTerminalSinceFlush.splice(0);
197
- const completedSinceFlush = this._workersCompletedSinceFlush;
198
- const failedSinceFlush = this._workersFailedSinceFlush;
199
- this._workersCompletedSinceFlush = 0;
200
- this._workersFailedSinceFlush = 0;
201
- this.deps.emit({
202
- type: "delegate_workers",
203
- active: queued + running,
204
- queued,
205
- running,
206
- completedSinceFlush,
207
- failedSinceFlush,
208
- terminalSinceFlush,
209
- });
210
- if (terminalSinceFlush.length === 0)
211
- return;
212
- const delivery = this._workerNotificationTail.then(async () => {
213
- if (this._disposed)
214
- return;
215
- let timeout;
216
- try {
217
- await Promise.race([
218
- this.deps.notifyWorkerTerminalHandoff(terminalSinceFlush),
219
- new Promise((_resolve, reject) => {
220
- timeout = setTimeout(() => reject(new Error(`worker terminal handoff timed out after ${WORKER_HANDOFF_TIMEOUT_MS}ms`)), WORKER_HANDOFF_TIMEOUT_MS);
221
- timeout.unref();
222
- }),
223
- ]);
224
- }
225
- finally {
226
- if (timeout)
227
- clearTimeout(timeout);
228
- }
229
- });
230
- this._workerNotificationTail = delivery.catch((error) => {
231
- this.deps.emit({
232
- type: "warning",
233
- message: `Background worker handoff failed: ${error instanceof Error ? error.message : String(error)}`,
234
- });
58
+ constructor(deps) {
59
+ this.deps = deps;
60
+ this._laneModels = new LaneModelResolver(deps);
61
+ this._research = new ResearchLaneController(deps, this._laneTracker, this._laneModels);
62
+ this._fitness = new ModelFitnessController(deps, this._laneModels);
63
+ this._goalAutoContinue = new GoalAutoContinueController({
64
+ isDisposed: deps.isDisposed,
65
+ isGoalToolActive: deps.isGoalToolActive,
66
+ getSettingsManager: deps.getSettingsManager,
67
+ getModelCapabilityProfile: deps.getModelCapabilityProfile,
68
+ getGoalRuntimeSnapshot: deps.getGoalRuntimeSnapshot,
69
+ hasInFlightLaneForGoal: (goalId) => this._hasInFlightLaneForGoal(goalId),
70
+ continueGoalLoop: deps.continueGoalLoop,
71
+ markGoalToolUnavailable: deps.markGoalToolUnavailable,
72
+ emit: deps.emit,
235
73
  });
236
74
  }
237
- _recordWorkerTerminal(record) {
238
- if (record.status === "queued" || record.status === "running")
239
- return;
240
- if (record.status === "succeeded")
241
- this._workersCompletedSinceFlush++;
242
- else
243
- this._workersFailedSinceFlush++;
244
- this._workerTerminalSinceFlush.push({
245
- laneId: record.laneId,
246
- status: record.status,
247
- ...(record.reasonCode ? { reasonCode: record.reasonCode } : {}),
75
+ _getWorkerController() {
76
+ this._workers ??= new WorkerDelegationController(this.deps, this._getWorkerNotificationCoordinator(), this._getWorkerLifecycle());
77
+ return this._workers;
78
+ }
79
+ _getWorkerLifecycle() {
80
+ if (this._workerLifecycle)
81
+ return this._workerLifecycle;
82
+ const lifecycle = new WorkerLifecycle({
83
+ agentDir: this.deps.getAgentDir(),
84
+ sessionId: this.deps.getSessionId(),
248
85
  });
249
- this._scheduleWorkerNotification();
86
+ this._workerLifecycle = lifecycle;
87
+ for (const notification of lifecycle.getPendingTerminalNotifications()) {
88
+ this._getWorkerNotificationCoordinator().recordTerminal(notification.record, notification.notificationId);
89
+ }
90
+ return lifecycle;
91
+ }
92
+ _getWorkerNotificationCoordinator() {
93
+ this._workerNotifications ??= new WorkerNotificationCoordinator({
94
+ getWorkerRecords: () => this._workerLifecycle?.getAllRecords() ?? [],
95
+ emitStatus: (status) => {
96
+ try {
97
+ this.deps.emit({
98
+ type: "delegate_workers",
99
+ ...status,
100
+ terminalSinceFlush: [...status.terminalSinceFlush],
101
+ });
102
+ }
103
+ catch {
104
+ // A partial integration must not crash the event-driven terminal outbox.
105
+ }
106
+ },
107
+ notify: (records) => this.deps.notifyWorkerTerminalHandoff(records),
108
+ warn: (message) => this._safeWarn(message),
109
+ markDurableDelivered: (notificationIds) => this._workerLifecycle?.markNotificationsDelivered(notificationIds),
110
+ });
111
+ return this._workerNotifications;
250
112
  }
251
- constructor(deps) {
252
- this.deps = deps;
113
+ _getManagedLaneController() {
114
+ this._managedLanes ??= new ManagedLaneController(this.deps, this._getWorkerLifecycle(), (record, notificationId) => this._recordWorkerTerminal(record, notificationId));
115
+ return this._managedLanes;
253
116
  }
254
- _seedLaneHistory() {
255
- if (this._laneHistorySeeded)
117
+ _hydrateManagedLanes() {
118
+ if (this._managedLanes) {
119
+ this._managedLanes.ensureHydrated();
256
120
  return;
257
- const records = getLaneRecordSnapshots(this.deps.getSessionManager().getEntries());
258
- this._laneTracker.ensureCounterAtLeast(records.length + 1);
259
- this._persistedResearchRunCount = records.filter((record) => record.type === "research").length;
260
- this._laneHistorySeeded = true;
121
+ }
122
+ const hasPersistedActiveManagedLane = getLatestLaneRecordSnapshots(getActiveSessionBranchEntries(this.deps.getSessionManager())).some((record) => record.type === "tmux-worker" && (record.status === "queued" || record.status === "running"));
123
+ if (hasPersistedActiveManagedLane)
124
+ this._getManagedLaneController().ensureHydrated();
261
125
  }
262
126
  /** Live lane records tracked by this process (running and terminal). */
263
127
  getLaneRecords() {
264
- return this._laneTracker.getRecords();
128
+ this._hydrateManagedLanes();
129
+ const workerRecords = this._workers?.getRecords() ??
130
+ (this.deps.isDelegateToolActive?.() ? this._getWorkerController().getRecords() : []);
131
+ return [
132
+ ...this._laneTracker.getRecords(),
133
+ ...workerRecords,
134
+ ...(this._workerLifecycle?.getManagedRecords() ?? []),
135
+ ];
136
+ }
137
+ /** Does not materialize the worker controller when UAC omitted delegation. */
138
+ getTaskRuntimeSnapshot() {
139
+ return this._workerLifecycle?.getTaskRuntimeSnapshot();
140
+ }
141
+ /** Reconcile only when delegation has already been materialized; UAC omission stays zero-load. */
142
+ synchronizeGoalState(goal) {
143
+ this._workers?.synchronizeGoalState(goal);
265
144
  }
266
145
  /**
267
- * Resolve a tracked managed-lane dispatch's internal `LaneTracker` id from the CALLER's own
268
- * `laneId` (the id passed to `recordManagedLane`'s `phase: "dispatch"`, e.g. a reconstructed
269
- * `tmux:jobId:agentId`). A deterministic, non-racy keyed lookup against `_managedLaneDispatches` —
270
- * NOT a `getLaneRecords()` diff — for a caller (e.g. the goal-to-tmux dispatch adapter) that just
271
- * minted the dispatch and needs the internal id `Requirement.boundLaneId`/`inFlightGoalLaneIds`
272
- * actually match. `undefined` once the dispatch has gone terminal (removed from the map) or was
273
- * never tracked.
146
+ * Resolve a tracked managed-lane dispatch. The caller's stable id is also the canonical durable
147
+ * lane id, so this is an existence check rather than an id translation.
274
148
  */
275
149
  resolveManagedLaneId(callerLaneId) {
276
- return this._managedLaneDispatches.get(callerLaneId)?.laneId;
150
+ return this._getManagedLaneController().resolve(callerLaneId);
277
151
  }
278
152
  /** Live count of active lanes — the real source for AutonomyStatusSnapshot.activeLaneCount. */
279
153
  getActiveLaneCount() {
280
- return this._laneTracker.getActiveCount();
154
+ return this.getLaneRecords().filter((record) => record.status === "queued" || record.status === "running").length;
281
155
  }
282
156
  /** Belt-and-braces guard: whether ANY queued/running lane is tagged with this goalId. */
283
157
  _hasInFlightLaneForGoal(goalId) {
284
158
  return this.getLaneRecords().some((record) => record.goalId === goalId && (record.status === "queued" || record.status === "running"));
285
159
  }
286
- /**
287
- * Host-side bridge for `pi.reportManagedLane`: makes an out-of-process managed lane (e.g. a tmux
288
- * worker) a first-class lane in THIS process's LaneTracker. HONEST cross-process seam — the
289
- * extension only ever REPORTS a claim; this controller stays the lane-tracking SSOT (no in-process
290
- * sandboxing is implied by accepting the report).
291
- *
292
- * `phase: "dispatch"` mints a `tmux-worker` lane record (goalId-tagged) and registers exactly one
293
- * reload-quiesce unit for it. `phase: "terminal"` resolves the caller's free-form `status` claim
294
- * onto {@link LaneTerminalStatus} (see {@link resolveManagedLaneTerminalStatus}), completes that
295
- * same record, deregisters the quiesce unit (inside a `finally` — never left stuck regardless of
296
- * what persistence below does), and persists a bounded worker-result CLAIM snapshot from the
297
- * reported `changedFiles`. Host re-review: the reported `changedFiles` are re-checked against
298
- * the session's active capability envelope ({@link reviewManagedLaneChangedFiles}, reusing
299
- * `validateWorkerResult`'s symlink-safe scope check verbatim) and `parentReviewRequired` is
300
- * stamped on the persisted claim whenever that check does not cleanly "allow" -- an out-of-scope
301
- * (or no-scope-configured) path is flagged exactly like an in-scope one, since a tmux worker's
302
- * write never passed through this process's enforcement in the first place. This is the SESSION
303
- * envelope, not a per-launch tmux standing grant (that is a narrower, launch-specific scope;
304
- * documented follow-up, not yet implemented). `event.request` stays an unvalidated
305
- * caller-supplied bag (per its own doc comment) and is deliberately never read for scoping. A
306
- * terminal report for an unknown `laneId` (no matching dispatch tracked) and a duplicate dispatch
307
- * for an already-tracked `laneId` are both safe no-ops — never a double registration, a double
308
- * persisted claim, or a crash.
309
- *
310
- * Returns the minted (`phase: "dispatch"`) or completed (`phase: "terminal"`) LaneRecord for an
311
- * in-process caller that wants the record without a second `getLaneRecords()` read (e.g. a
312
- * faux-bridge test, or the goal-to-tmux dispatch adapter via `resolveManagedLaneId`); `undefined`
313
- * on every no-op path (disposed controller, duplicate dispatch, unknown-laneId terminal). The
314
- * extension-facing `ExtensionActions.reportManagedLane` TYPE stays `=> void` -- that call site is a
315
- * fire-and-forget statement and is unaffected by this return.
316
- */
160
+ /** Delegate the out-of-process dispatch/terminal claim to its single lifecycle owner. */
317
161
  recordManagedLane(event) {
318
- if (this.deps.isDisposed())
319
- return undefined;
320
- if (event.phase === "dispatch") {
321
- if (this._managedLaneDispatches.has(event.laneId))
322
- return undefined;
323
- this._seedLaneHistory();
324
- const record = this._laneTracker.start({
325
- type: "tmux-worker",
326
- goalId: event.goalId,
327
- worktreeLaneKey: event.worktreeLaneKey,
328
- });
329
- const deregister = registerInFlightWork(this.deps.getAgentDir(), "lane", `tmux:${record.laneId}`);
330
- this._managedLaneDispatches.set(event.laneId, { laneId: record.laneId, deregister });
331
- return record;
332
- }
333
- const dispatch = this._managedLaneDispatches.get(event.laneId);
334
- if (!dispatch)
335
- return undefined;
336
- this._managedLaneDispatches.delete(event.laneId);
337
- try {
338
- const resolvedStatus = resolveManagedLaneTerminalStatus(event.status);
339
- const record = this._laneTracker.complete(dispatch.laneId, {
340
- status: resolvedStatus,
341
- reasonCode: event.reasonCode,
342
- costUsd: event.usage?.cost.total,
343
- });
344
- if (!record)
345
- return undefined;
346
- appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
347
- const changedFiles = event.changedFiles ? [...event.changedFiles] : [];
348
- const review = reviewManagedLaneChangedFiles({
349
- changedFiles,
350
- envelope: this.deps.getCapabilityEnvelope() ?? {},
351
- cwd: this.deps.getCwd(),
352
- });
353
- const result = {
354
- requestId: dispatch.laneId,
355
- status: mapManagedLaneTerminalStatus(resolvedStatus),
356
- summary: `Managed tmux-worker lane ${dispatch.laneId} reported terminal status "${event.status ?? "unknown"}"${event.reasonCode ? ` (${event.reasonCode})` : ""}.${review.reviewRequired ? ` Changed files require parent review (${review.reasonCode}).` : ""}`,
357
- changedFiles,
358
- parentReviewRequired: review.reviewRequired,
359
- createdAt: new Date().toISOString(),
360
- };
361
- this.deps.saveWorkerResultSnapshot(result);
362
- return record;
363
- }
364
- finally {
365
- dispatch.deregister();
366
- }
162
+ return this._getManagedLaneController().record(event);
367
163
  }
368
164
  /** Why the last idle research-lane evaluation skipped, for /autonomy diagnostics. */
369
165
  getLastResearchLaneSkipReason() {
370
- return this._lastResearchLaneSkipReason;
166
+ return this._research.getLastSkipReason();
371
167
  }
372
168
  /**
373
- * Abort any in-flight research pass or delegated worker (called on session dispose).
169
+ * Abort in-flight research and delegate worker disposal to its single owning controller.
374
170
  *
375
171
  * This synchronous body is the LAST provably-safe write window for canceled/in-flight work.
376
172
  * `dispose()` (agent-session.ts) has already set the session's own disposed flag but has not yet
@@ -381,12 +177,14 @@ export class BackgroundLaneController {
381
177
  * its own try/catch — dispose must never throw.
382
178
  */
383
179
  abortInFlightLanes() {
384
- this._disposed = true;
385
- this._researchLaneAbort.abort();
386
- this._workerDelegationAbort.abort();
180
+ this._goalAutoContinue.clearTimer();
181
+ this._research.abort();
182
+ this._fitness.abort();
387
183
  for (const record of this._laneTracker.getRecords()) {
388
184
  if (record.status !== "queued" && record.status !== "running")
389
185
  continue;
186
+ if (record.type === "tmux-worker")
187
+ continue;
390
188
  const canceled = this._laneTracker.complete(record.laneId, {
391
189
  status: "canceled",
392
190
  reasonCode: "session_disposed",
@@ -399,117 +197,16 @@ export class BackgroundLaneController {
399
197
  catch (error) {
400
198
  this._safeWarn(`Failed to persist canceled lane record ${canceled.laneId}: ${error instanceof Error ? error.message : String(error)}`);
401
199
  }
402
- if (canceled.type !== "worker")
403
- continue;
404
- // Only a RUNNING worker ever registers a ledger (a queued-never-started worker has none;
405
- // its cancellation is already fully captured by the lane record above). Consumed
406
- // (deleted) here so the post-await disposed branch never re-persists it.
407
- const ledger = this._inFlightWorkerLedgers.get(record.laneId);
408
- if (!ledger)
409
- continue;
410
- this._inFlightWorkerLedgers.delete(record.laneId);
411
- try {
412
- const spend = ledger.getSpend();
413
- const reportId = `worker:${this.deps.getSessionId()}:${record.laneId}`;
414
- const result = {
415
- requestId: ledger.request.id,
416
- status: "cancelled",
417
- summary: "canceled on session dispose",
418
- changedFiles: [...ledger.changedFiles],
419
- usageReportId: reportId,
420
- createdAt: new Date().toISOString(),
421
- };
422
- // Bounded honesty: spend may be incomplete (it lands only when the isolated completion
423
- // returns, which a mid-flight abort preempts) — record what `getSpend()` knows. Same
424
- // deterministic reportId scheme as the normal path, so a later duplicate report (there
425
- // is none in practice here, since the lane is now terminal) stays idempotent.
426
- this.deps.saveWorkerResultSnapshot(result, ledger.request);
427
- if (spend && (spend.cost.total > 0 || spend.totalTokens > 0)) {
428
- this.deps.addSpawnedUsage(spend, { label: "worker-delegation", reportId });
429
- }
430
- }
431
- catch (error) {
432
- this._safeWarn(`Failed to persist canceled worker result ${record.laneId}: ${error instanceof Error ? error.message : String(error)}`);
433
- }
434
200
  }
435
- // A queued (never-started) worker's reload-gate registration ends here on cancellation;
436
- // the other end is the running handoff in `drainQueuedWorkerDelegations`.
437
- for (const deregister of this._queuedWorkerDeregisters.values())
438
- deregister();
439
- this._queuedWorkerDeregisters.clear();
440
- this._queuedWorkers.clear();
441
- this._workerNotificationScheduled = false;
442
- this._workerTerminalSinceFlush.length = 0;
201
+ this._managedLanes?.release();
202
+ this._workers?.abort();
203
+ this._workerNotifications?.dispose();
443
204
  }
444
205
  clearGoalAutoContinueTimer() {
445
- if (this._goalAutoContinueTimer !== undefined) {
446
- clearTimeout(this._goalAutoContinueTimer);
447
- this._goalAutoContinueTimer = undefined;
448
- }
206
+ this._goalAutoContinue.clearTimer();
449
207
  }
450
208
  scheduleGoalAutoContinueFromIdle(options) {
451
- if (options?.autoContinueGoal === false || this._isGoalAutoContinuing || this.deps.isDisposed())
452
- return;
453
- // Small-window models cannot afford multi-thousand-token continuation prompts per idle turn.
454
- if (!this.deps.getModelCapabilityProfile().backgroundLanesEnabled)
455
- return;
456
- const { maxStallTurns, goalAutoContinue, goalAutoContinueDelayMs } = this.deps
457
- .getSettingsManager()
458
- .getAutonomySettings();
459
- if (!goalAutoContinue)
460
- return;
461
- const snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });
462
- if (snapshot.continuation.action !== "continue")
463
- return;
464
- // Belt-and-braces: the snapshot above is already lane-aware (a bound in-flight worker
465
- // yields action:"waiting", already caught by the check above), so this direct lane check is
466
- // redundant in the normal case. It stays as an explicit second gate so a future change that
467
- // decouples the lane injection from THIS snapshot read can never silently reopen the idle
468
- // re-dispatch race this guard closes.
469
- const activeGoalId = snapshot.goalState?.goalId;
470
- if (activeGoalId !== undefined && this._hasInFlightLaneForGoal(activeGoalId))
471
- return;
472
- this.clearGoalAutoContinueTimer();
473
- this._goalAutoContinueTimer = setTimeout(() => {
474
- this._goalAutoContinueTimer = undefined;
475
- void this._runScheduledGoalAutoContinue();
476
- }, goalAutoContinueDelayMs);
477
- const timer = this._goalAutoContinueTimer;
478
- if (typeof timer === "object" && timer && "unref" in timer) {
479
- const { unref } = timer;
480
- unref?.call(timer);
481
- }
482
- }
483
- async _runScheduledGoalAutoContinue() {
484
- if (this._isGoalAutoContinuing || this.deps.isDisposed())
485
- return;
486
- const { maxStallTurns, goalContinueTurns, goalContinueMaxWallClockMinutes, goalAutoContinue } = this.deps
487
- .getSettingsManager()
488
- .getAutonomySettings();
489
- if (!goalAutoContinue)
490
- return;
491
- const snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });
492
- if (snapshot.continuation.action !== "continue")
493
- return;
494
- // Budget scaling by capability class; note that since the lean class stopped exposing the
495
- // goal tool at all, sub-full sessions are skipped outright by the goal_tool_unavailable
496
- // guard in continueGoalLoopExclusive -- the lean budget branch below only matters if that
497
- // blocklist is ever relaxed. Full passes through unchanged.
498
- const scaled = scaleContinuationBudgetsForCapability(this.deps.getModelCapabilityProfile(), {
499
- maxTurns: goalContinueTurns,
500
- maxWallClockMinutes: goalContinueMaxWallClockMinutes,
501
- });
502
- try {
503
- await this.continueGoalLoopExclusive({
504
- maxTurns: scaled.maxTurns,
505
- maxStallTurns,
506
- maxWallClockMinutes: scaled.maxWallClockMinutes,
507
- });
508
- }
509
- catch (error) {
510
- const message = error instanceof Error ? error.message : String(error);
511
- this.deps.emit({ type: "warning", message: `Goal auto-continuation failed: ${message}` });
512
- }
209
+ this._goalAutoContinue.scheduleFromIdle(options);
513
210
  }
514
211
  /**
515
212
  * Single-flight entry point for EVERY goal-continuation loop invocation — idle autosteer
@@ -521,221 +218,19 @@ export class BackgroundLaneController {
521
218
  * must never be called directly outside this method, or the guard is bypassed.
522
219
  */
523
220
  async continueGoalLoopExclusive(options) {
524
- if (this._isGoalAutoContinuing)
525
- return this._skippedGoalResult(options, "already_continuing");
526
- if (this.deps.isDisposed())
527
- return this._skippedGoalResult(options, "session_disposed");
528
- // Adaptative prevails: a session whose active surface lacks the goal tool cannot execute
529
- // continuation prompts -- driving the loop anyway would ENFORCE complex agentic work on a
530
- // model/role that cannot perform it. One gate here covers idle autosteer AND manual /goal
531
- // paths (both funnel through this single-flight guard).
532
- if (!this.deps.isGoalToolActive())
533
- return this._skippedGoalResult(options, "goal_tool_unavailable");
534
- this._isGoalAutoContinuing = true;
535
- try {
536
- return await this.deps.continueGoalLoop(options);
537
- }
538
- finally {
539
- this._isGoalAutoContinuing = false;
540
- }
541
- }
542
- /**
543
- * A full {@link GoalContinuationLoopResult} for a continuation request that never ran a pass
544
- * (another loop already owns the mutex, or the session is disposed). Keeps the skip path
545
- * type-identical to a real pass — no separate skip union — so every caller keeps reading
546
- * `result.stopReason`/`result.finalSnapshot` unchanged.
547
- */
548
- _skippedGoalResult(options, stopReason) {
549
- return {
550
- turnsSubmitted: 0,
551
- stopReason,
552
- finalSnapshot: this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns }),
553
- };
221
+ return this._goalAutoContinue.continueExclusive(options);
554
222
  }
555
223
  clearResearchLaneTimer() {
556
- if (this._researchLaneTimer !== undefined) {
557
- clearTimeout(this._researchLaneTimer);
558
- this._researchLaneTimer = undefined;
559
- }
224
+ this._research.clearTimer();
560
225
  }
561
- /**
562
- * Derive the research demand from durable goal state: an active goal with open requirements,
563
- * deduplicated against the latest persisted bundle so the same requirement set is never
564
- * researched twice (the query is deterministic, so dedupe survives session reload).
565
- */
566
- _buildResearchLaneDemand() {
567
- const goal = this.deps.getGoalStateSnapshot();
568
- if (!goal || goal.status !== "active") {
569
- this._lastResearchLaneSkipReason = "no_active_goal";
570
- return undefined;
571
- }
572
- const open = goal.requirements.filter((requirement) => requirement.status === "open");
573
- if (open.length === 0) {
574
- this._lastResearchLaneSkipReason = "no_open_requirements";
575
- return undefined;
576
- }
577
- const query = `goal:${goal.goalId} requirements:${open
578
- .map((requirement) => requirement.id)
579
- .sort()
580
- .join(",")}`;
581
- if (this.deps.getEvidenceBundleSnapshot()?.query === query) {
582
- this._lastResearchLaneSkipReason = "recent_evidence_sufficient";
583
- return undefined;
584
- }
585
- const context = [
586
- `Goal: ${goal.userGoal}`,
587
- "Open requirements:",
588
- ...open.slice(0, 20).map((requirement) => `- ${requirement.text}`),
589
- ].join("\n");
590
- return { query, context, goalId: goal.goalId };
591
- }
592
- /**
593
- * Idle trigger for the autonomous research lane (mirrors {@link scheduleGoalAutoContinueFromIdle}).
594
- * All skips are recorded in `_lastResearchLaneSkipReason` and surfaced via diagnostics — the lane
595
- * informs, it never prompts or blocks the foreground.
596
- */
597
226
  scheduleResearchLaneFromIdle() {
598
- if (this._isResearchLaneRunning || this.deps.isDisposed() || this.deps.isChildSession())
599
- return;
600
- const research = this.deps.getSettingsManager().getResearchLaneSettings();
601
- if (!research.enabled) {
602
- this._lastResearchLaneSkipReason = "research_lane_disabled";
603
- return;
604
- }
605
- const { mode } = this.deps.getSettingsManager().getAutonomySettings();
606
- if (mode === "off") {
607
- this._lastResearchLaneSkipReason = "autonomy_mode_off";
608
- return;
609
- }
610
- this._seedLaneHistory();
611
- if (this._persistedResearchRunCount >= research.maxRunsPerSession) {
612
- this._lastResearchLaneSkipReason = "max_runs_reached";
613
- return;
614
- }
615
- if (!this._buildResearchLaneDemand())
616
- return;
617
- const shipment = this._resolveLaneShipment(research, "no_research_model");
618
- if (!shipment.ok) {
619
- this._lastResearchLaneSkipReason = shipment.skipReason;
620
- return;
621
- }
622
- if (!this._laneCapabilityProfile(shipment.model).backgroundLanesEnabled) {
623
- this._lastResearchLaneSkipReason = "model_research_unsupported";
624
- return;
625
- }
626
- this.clearResearchLaneTimer();
627
- this._researchLaneTimer = setTimeout(() => {
628
- this._researchLaneTimer = undefined;
629
- void this._runScheduledResearchLane();
630
- }, research.idleDelayMs);
631
- const timer = this._researchLaneTimer;
632
- if (typeof timer === "object" && timer && "unref" in timer) {
633
- const { unref } = timer;
634
- unref?.call(timer);
635
- }
636
- }
637
- async _runScheduledResearchLane() {
638
- if (this._isResearchLaneRunning || this.deps.isDisposed())
639
- return;
640
- const research = this.deps.getSettingsManager().getResearchLaneSettings();
641
- const { mode } = this.deps.getSettingsManager().getAutonomySettings();
642
- if (!research.enabled || mode === "off")
643
- return;
644
- try {
645
- await this.runResearchLaneOnce();
646
- }
647
- catch (error) {
648
- const message = error instanceof Error ? error.message : String(error);
649
- this.deps.emit({ type: "warning", message: `Research lane failed: ${message}` });
650
- }
227
+ this._research.scheduleFromIdle();
651
228
  }
652
- /** Capability profile for a specific lane model (lane budgets scale to the lane model's window). */
653
- _laneCapabilityProfile(model) {
654
- return deriveModelCapabilityProfile({
655
- contextWindow: model.contextWindow,
656
- mode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,
657
- });
658
- }
659
- /**
660
- * Resolve the model for a background lane. Lanes are shipped BY this session, so they inherit
661
- * the session's own model unless a lane-specific model is explicitly configured — a single-model
662
- * setup (e.g. one local open model) runs its lanes on that same model. An explicitly configured
663
- * pattern that cannot resolve/authenticate is a visible skip, not a silent fallback.
664
- */
665
229
  resolveLaneModel(configuredPattern) {
666
- if (configuredPattern) {
667
- const resolved = resolveCliModel({ cliModel: configuredPattern, modelRegistry: this.deps.getModelRegistry() });
668
- if (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {
669
- return resolved.model;
670
- }
671
- return undefined;
672
- }
673
- return this.deps.getModel() ?? undefined;
674
- }
675
- /**
676
- * Resolve what a lane ships with. Precedence: explicit lane model setting, then the lane
677
- * profile's model (a shipped profile with a model MUST be obeyed — unresolvable is a visible
678
- * skip, never a fallback), then generic inheritance of the session model.
679
- */
680
- _resolveLaneShipment(laneSettings, missingModelReason) {
681
- let laneProfile;
682
- if (laneSettings.profile) {
683
- const profileRef = laneSettings.profile.trim();
684
- const registry = this.deps.getSettingsManager().getProfileRegistry();
685
- laneProfile =
686
- profileRef.startsWith("./") || profileRef.startsWith("../")
687
- ? registry.resolveProfileRef(profileRef, this.deps.getCwd())
688
- : registry.getProfile(profileRef);
689
- if (!laneProfile) {
690
- return { ok: false, skipReason: "lane_profile_not_found" };
691
- }
692
- }
693
- let model;
694
- if (laneSettings.model) {
695
- model = this.resolveLaneModel(laneSettings.model);
696
- if (!model)
697
- return { ok: false, skipReason: missingModelReason };
698
- }
699
- else if (laneProfile?.model) {
700
- model = this.resolveLaneModel(laneProfile.model);
701
- if (!model)
702
- return { ok: false, skipReason: "no_lane_profile_model" };
703
- }
704
- else {
705
- model = this.deps.getModel() ?? undefined;
706
- if (!model)
707
- return { ok: false, skipReason: missingModelReason };
708
- }
709
- if (this.deps.isModelExhausted(model)) {
710
- return { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };
711
- }
712
- return { ok: true, model, laneProfile };
713
- }
714
- _warnUnboundLaneToolGrants(laneProfile, surface) {
715
- if (!laneProfile || surface.unboundAllowPatterns.length === 0)
716
- return;
717
- const warningKey = `${laneProfile.name}\0${[...surface.unboundAllowPatterns].sort().join("\0")}`;
718
- if (this._warnedUnboundLaneToolGrants.has(warningKey))
719
- return;
720
- this._warnedUnboundLaneToolGrants.add(warningKey);
721
- this.deps.emit({
722
- type: "warning",
723
- message: `Lane profile '${laneProfile.name}' grants unavailable isolated-lane tools: ${surface.unboundAllowPatterns.join(", ")}. Only classified lane tools can execute.`,
724
- });
230
+ return this._laneModels.resolveModel(configuredPattern);
725
231
  }
726
- /** Stripped research envelope — never the foreground/architect envelope. */
727
- _buildResearchLaneEnvelope(maxUsd, laneProfile, surface) {
728
- return {
729
- id: `research-${this.deps.getSessionId()}-${Date.now()}`,
730
- profileId: laneProfile?.name,
731
- capabilities: ["research", "read_files", "memory_read"],
732
- allowedTools: [...surface.allowedTools],
733
- deniedTools: [...surface.deniedTools],
734
- allowedPaths: [this.deps.getCwd()],
735
- deniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),
736
- maxEstimatedUsd: clampLaneMaxUsd(maxUsd, this.deps.getCapabilityEnvelope()?.maxEstimatedUsd),
737
- createdAt: new Date().toISOString(),
738
- };
232
+ getOrchestrationProfileCatalog() {
233
+ return this._getWorkerController().getProfileCatalog();
739
234
  }
740
235
  /**
741
236
  * Run one bounded, read-only research pass and persist its results: evidence bundle snapshot,
@@ -744,503 +239,15 @@ export class BackgroundLaneController {
744
239
  * enabled/mode/dedupe gates the idle scheduler enforces; budget and capability gates always apply.
745
240
  */
746
241
  async runResearchLaneOnce(request) {
747
- if (this._isResearchLaneRunning) {
748
- return { started: false, skipReason: "research_lane_already_running" };
749
- }
750
- if (this.deps.isDisposed()) {
751
- return { started: false, skipReason: "session_disposed" };
752
- }
753
- const settings = this.deps.getSettingsManager().getResearchLaneSettings();
754
- const demand = request?.query
755
- ? { query: request.query, context: request.context ?? "", goalId: request.goalId }
756
- : this._buildResearchLaneDemand();
757
- if (!demand) {
758
- return { started: false, skipReason: this._lastResearchLaneSkipReason ?? "no_research_demand" };
759
- }
760
- const shipment = this._resolveLaneShipment(settings, "no_research_model");
761
- if (!shipment.ok) {
762
- this._lastResearchLaneSkipReason = shipment.skipReason;
763
- return { started: false, skipReason: shipment.skipReason };
764
- }
765
- const { model, laneProfile } = shipment;
766
- const laneCapability = this._laneCapabilityProfile(model);
767
- if (!laneCapability.backgroundLanesEnabled) {
768
- this._lastResearchLaneSkipReason = "model_research_unsupported";
769
- return { started: false, skipReason: "model_research_unsupported" };
770
- }
771
- this._isResearchLaneRunning = true;
772
- this._seedLaneHistory();
773
- const startedRecord = this._laneTracker.start({ type: "research", goalId: demand.goalId });
774
- this._persistedResearchRunCount++;
775
- // Registered for the lane's full run so the reload gate waits it out; deregistered in the
776
- // finally below no matter how this lane terminates (success, disposal, or a thrown error).
777
- const deregisterInFlight = registerInFlightWork(this.deps.getAgentDir(), "lane", `research:${startedRecord.laneId}`);
778
- try {
779
- let spentUsage;
780
- // Best-effort, pointer-first workspace evidence. Derives search terms from the goal/requirement
781
- // text (not the identity-key query) and is bounded + silent-on-failure: [] == today's behavior.
782
- const workspaceSources = await this.deps.collectWorkspaceSources({
783
- query: `${demand.context}\n${demand.query}`,
784
- cwd: this.deps.getCwd(),
785
- maxSources: settings.maxSources,
786
- });
787
- const maxUsd = clampLaneMaxUsd(settings.maxUsd, this.deps.getCapabilityEnvelope()?.maxEstimatedUsd);
788
- const toolSurface = createLaneToolSurface({
789
- cwd: this.deps.getCwd(),
790
- profile: laneProfile,
791
- deniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),
792
- });
793
- this._warnUnboundLaneToolGrants(laneProfile, toolSurface);
794
- const result = await runResearch({
795
- query: demand.query,
796
- context: demand.context,
797
- sources: workspaceSources,
798
- envelope: this._buildResearchLaneEnvelope(maxUsd, laneProfile, toolSurface),
799
- maxUsd,
800
- maxSources: settings.maxSources,
801
- maxFindings: settings.maxFindings,
802
- maxWallClockMs: settings.maxWallClockMs,
803
- signal: this._researchLaneAbort.signal,
804
- complete: async ({ systemPrompt, userPrompt, signal }) => {
805
- const completion = await this.deps.runIsolatedCompletion({
806
- // Level-0 core always survives; profile soul and role prompt are the replaceable
807
- // layers; a settings-provided prompt replaces everything above the core.
808
- systemPrompt: composeSubagentSystemPrompt({
809
- soul: laneProfile?.soul,
810
- rolePrompt: systemPrompt,
811
- override: settings.systemPrompt,
812
- }),
813
- messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
814
- model,
815
- thinkingLevel: laneProfile?.thinking ?? "off",
816
- maxTokens: laneCapability.laneMaxOutputTokens,
817
- tools: toolSurface.tools,
818
- maxTurns: 6,
819
- beforeToolCall: toolSurface.beforeToolCall,
820
- signal,
821
- // Core/soul/role are all static per configuration — the provider can cache the prefix.
822
- cacheRetention: "short",
823
- // Stable per-lane synthetic affinity key so repeat research calls route to the
824
- // same cache-warm backend without carrying the real session id.
825
- laneKind: "research",
826
- });
827
- spentUsage = completion.usage;
828
- return {
829
- text: completion.text,
830
- costUsd: completion.usage.cost.total,
831
- stopReason: String(completion.stopReason),
832
- };
833
- },
834
- });
835
- // If the session was disposed while the completion was in flight, do NOT
836
- // persist evidence/records/usage against the dead session.
837
- if (this.deps.isDisposed()) {
838
- const record = this._laneTracker.complete(startedRecord.laneId, {
839
- status: "canceled",
840
- reasonCode: "session_disposed",
841
- });
842
- return { started: true, record, result };
843
- }
844
- let evidenceEntryId;
845
- if (result.bundle) {
846
- evidenceEntryId = this.deps.saveEvidenceBundleSnapshot(result.bundle);
847
- }
848
- if (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {
849
- this.deps.addSpawnedUsage(spentUsage, {
850
- label: "research-lane",
851
- reportId: `research:${this.deps.getSessionId()}:${startedRecord.laneId}`,
852
- });
853
- }
854
- const record = this._laneTracker.complete(startedRecord.laneId, {
855
- status: result.status,
856
- reasonCode: result.reasonCode,
857
- costUsd: result.costUsd,
858
- evidenceEntryId,
859
- });
860
- if (record) {
861
- appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
862
- // A research lane's product is an evidence bundle, so its terminal record maps to
863
- // the evidence_bundle event. Lane outcome only (status/reasonCode/cost) — no findings text.
864
- this.deps.emitAutonomyTelemetry({
865
- type: AUTONOMY_TELEMETRY_EVENT_TYPES.evidenceBundle,
866
- timestamp: new Date().toISOString(),
867
- payload: {
868
- laneId: record.laneId,
869
- laneType: record.type,
870
- status: record.status,
871
- reasonCode: record.reasonCode ?? null,
872
- costUsd: record.costUsd ?? null,
873
- hasEvidence: record.evidenceEntryId !== undefined,
874
- },
875
- });
876
- }
877
- return { started: true, record, result };
878
- }
879
- catch (error) {
880
- const record = this._laneTracker.complete(startedRecord.laneId, {
881
- status: "failed",
882
- reasonCode: "research_lane_error",
883
- });
884
- if (record && !this.deps.isDisposed()) {
885
- appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
886
- this.deps.emitAutonomyTelemetry({
887
- type: AUTONOMY_TELEMETRY_EVENT_TYPES.evidenceBundle,
888
- timestamp: new Date().toISOString(),
889
- payload: {
890
- laneId: record.laneId,
891
- laneType: record.type,
892
- status: record.status,
893
- reasonCode: record.reasonCode ?? null,
894
- costUsd: record.costUsd ?? null,
895
- hasEvidence: record.evidenceEntryId !== undefined,
896
- },
897
- });
898
- }
899
- const message = error instanceof Error ? error.message : String(error);
900
- this.deps.emit({ type: "warning", message: `Research lane failed: ${message}` });
901
- return { started: true, record };
902
- }
903
- finally {
904
- this._isResearchLaneRunning = false;
905
- deregisterInFlight();
906
- }
242
+ return this._research.runOnce(request);
907
243
  }
908
- /**
909
- * Run one bounded scout-worker delegation: build a WorkerRequest with a stripped read-only
910
- * envelope, execute it as an isolated completion on a cheap lane, validate the result via
911
- * {@link validateWorkerResult} before acceptance, and persist result + lane record + spawned
912
- * usage (idempotent per-lane reportId). Consumed by the `delegate` tool.
913
- */
244
+ /** Start a durable, profile-bound worker delegation. */
914
245
  startWorkerDelegation(request) {
915
- const settings = this.deps.getSettingsManager().getWorkerDelegationSettings();
916
- if (this.deps.isDisposed())
917
- return { started: false, skipReason: "session_disposed" };
918
- if (request.instructions.trim().length === 0)
919
- return { started: false, skipReason: "missing_instructions" };
920
- if (!this.deps.isDelegateToolActive())
921
- return { started: false, skipReason: "delegate_tool_inactive" };
922
- if (!settings.enabled)
923
- return { started: false, skipReason: "worker_delegation_disabled" };
924
- const shipment = this._resolveLaneShipment(settings, "no_worker_model");
925
- if (!shipment.ok)
926
- return { started: false, skipReason: shipment.skipReason };
927
- if (!this._laneCapabilityProfile(shipment.model).backgroundLanesEnabled) {
928
- return { started: false, skipReason: "model_delegation_unsupported" };
929
- }
930
- const foreground = this.deps.getModel();
931
- const contendsWithLocalForeground = foreground !== undefined && isLocalExecutionModel(foreground) && isLocalExecutionModel(shipment.model);
932
- if (contendsWithLocalForeground) {
933
- if (this._queuedWorkers.size >= 8 ||
934
- this._laneTracker.getActiveCount("worker") >= settings.maxConcurrent + 8) {
935
- return { started: false, skipReason: "worker_delegation_queue_full" };
936
- }
937
- const record = this._laneTracker.enqueue({ type: "worker", goalId: this.deps.getGoalStateSnapshot()?.goalId });
938
- this._queuedWorkers.set(record.laneId, request);
939
- // Register the reload-gate quiesce unit at ENQUEUE (not at the later running handoff)
940
- // so `/reload` waits for queued-but-not-yet-started work too, matching running workers.
941
- this._queuedWorkerDeregisters.set(record.laneId, registerInFlightWork(this.deps.getAgentDir(), "lane", `worker-queued:${record.laneId}`));
942
- this._scheduleWorkerNotification();
943
- return { started: true, record };
944
- }
945
- if (this._laneTracker.getRunningCount("worker") >= settings.maxConcurrent) {
946
- return { started: false, skipReason: "worker_delegation_already_running" };
947
- }
948
- let startedRecord;
949
- const promise = this.runWorkerDelegationOnce(request, (record) => {
950
- startedRecord = record;
951
- });
952
- if (!startedRecord) {
953
- // Preparation is synchronous up to the first isolated completion await. A promise that
954
- // rejected before producing a lane is still observed below, so it cannot become unhandled.
955
- void promise.catch(() => undefined);
956
- return { started: false, skipReason: "worker_not_started" };
957
- }
958
- this._workerPromises.set(startedRecord.laneId, promise);
959
- void promise.then(() => this._workerPromises.delete(startedRecord?.laneId ?? ""), () => this._workerPromises.delete(startedRecord?.laneId ?? ""));
960
- return { started: true, record: startedRecord };
246
+ return this._getWorkerController().start(request);
961
247
  }
248
+ /** Run one worker immediately; used by focused integrations and tests. */
962
249
  async runWorkerDelegationOnce(request, onStarted, existingRecord) {
963
- const delegationSettings = this.deps.getSettingsManager().getWorkerDelegationSettings();
964
- const runningWorkers = this._laneTracker.getRunningCount("worker");
965
- if (runningWorkers >= delegationSettings.maxConcurrent) {
966
- return { started: false, skipReason: "worker_delegation_already_running" };
967
- }
968
- if (this.deps.isDisposed()) {
969
- return { started: false, skipReason: "session_disposed" };
970
- }
971
- const instructions = request.instructions.trim();
972
- if (instructions.length === 0) {
973
- return { started: false, skipReason: "missing_instructions" };
974
- }
975
- const settings = delegationSettings;
976
- if (!this.deps.isDelegateToolActive()) {
977
- return { started: false, skipReason: "delegate_tool_inactive" };
978
- }
979
- if (!settings.enabled) {
980
- return { started: false, skipReason: "worker_delegation_disabled" };
981
- }
982
- const shipment = this._resolveLaneShipment(settings, "no_worker_model");
983
- if (!shipment.ok) {
984
- return { started: false, skipReason: shipment.skipReason };
985
- }
986
- const { model, laneProfile } = shipment;
987
- const laneCapability = this._laneCapabilityProfile(model);
988
- if (!laneCapability.backgroundLanesEnabled) {
989
- return { started: false, skipReason: "model_delegation_unsupported" };
990
- }
991
- this._seedLaneHistory();
992
- const startedRecord = existingRecord ??
993
- this._laneTracker.start({ type: "worker", goalId: this.deps.getGoalStateSnapshot()?.goalId });
994
- if (existingRecord)
995
- this._laneTracker.markRunning(existingRecord.laneId);
996
- onStarted?.(startedRecord);
997
- const maxUsd = Math.min(settings.maxUsd, this.deps.getCapabilityEnvelope()?.maxEstimatedUsd ?? Number.POSITIVE_INFINITY);
998
- const writeEnabled = settings.writeEnabled && settings.writePaths.length > 0;
999
- const toolSurface = createLaneToolSurface({
1000
- cwd: this.deps.getCwd(),
1001
- profile: laneProfile,
1002
- deniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),
1003
- readMemory: request.memoryRead ? (query) => this.deps.readMemoryForLane(query) : undefined,
1004
- writeEnabled,
1005
- writePaths: settings.writePaths,
1006
- });
1007
- this._warnUnboundLaneToolGrants(laneProfile, toolSurface);
1008
- const allowedActionOps = new Set(toolSurface.allowedTools.filter((name) => name === "write" || name === "edit"));
1009
- const writeGranted = writeEnabled && allowedActionOps.size > 0;
1010
- const memoryReadGranted = request.memoryRead === true && toolSurface.allowedTools.includes("memory");
1011
- const workerRequest = {
1012
- id: startedRecord.laneId,
1013
- instructions,
1014
- route: {
1015
- tier: "cheap",
1016
- risk: writeGranted ? "scoped-write" : "read-only",
1017
- confidence: 1,
1018
- reasonCode: "scout_worker",
1019
- reasons: [writeGranted ? "Path-scoped worker delegation" : "Read-only scout delegation"],
1020
- },
1021
- envelope: {
1022
- id: `worker-${this.deps.getSessionId()}-${startedRecord.laneId}`,
1023
- profileId: laneProfile?.name,
1024
- // write_files requires BOTH the opt-in AND an explicit non-empty path scope —
1025
- // an unscoped write grant is refused here, not discovered at validation time.
1026
- capabilities: [
1027
- "read_files",
1028
- ...(memoryReadGranted ? ["memory_read"] : []),
1029
- ...(writeGranted ? ["write_files"] : []),
1030
- ],
1031
- ...(writeGranted ? { allowedPaths: [...settings.writePaths] } : {}),
1032
- deniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),
1033
- allowedTools: [...toolSurface.allowedTools],
1034
- deniedTools: [...toolSurface.deniedTools],
1035
- maxEstimatedUsd: maxUsd,
1036
- createdAt: new Date().toISOString(),
1037
- },
1038
- maxEstimatedUsd: maxUsd,
1039
- createdAt: new Date().toISOString(),
1040
- };
1041
- // Worker delegation START. Routing/scope codes + budget only — never the instructions text.
1042
- this.deps.emitAutonomyTelemetry({
1043
- type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerRequest,
1044
- timestamp: new Date().toISOString(),
1045
- payload: {
1046
- id: workerRequest.id,
1047
- tier: workerRequest.route.tier,
1048
- capabilities: [...workerRequest.envelope.capabilities],
1049
- maxEstimatedUsd: workerRequest.maxEstimatedUsd ?? null,
1050
- },
1051
- });
1052
- const usageReportId = `worker:${this.deps.getSessionId()}:${startedRecord.laneId}`;
1053
- // Registered for the lane's full run so the reload gate waits it out; deregistered in the
1054
- // finally below no matter how this lane terminates (success, disposal, or a thrown error).
1055
- // registerInFlightWork is a pure sync map op (cannot throw), so placing it as the last
1056
- // statement before `try` still guarantees the matching finally always runs.
1057
- const deregisterInFlight = registerInFlightWork(this.deps.getAgentDir(), "lane", `worker:${startedRecord.laneId}`);
1058
- try {
1059
- let spentUsage;
1060
- const toolChangedFiles = new Set();
1061
- const toolIssues = new Set();
1062
- // Register the live mutation ledger BEFORE the suspend point below so a synchronous
1063
- // disposal cutoff (`abortInFlightLanes`) can read a race-free snapshot of whatever this
1064
- // worker has already applied — the worker is suspended at the `await runWorker(...)` below
1065
- // whenever abort runs, and the abort signal stops further tool calls. Deleted in the
1066
- // `finally` on every exit path (normal completion, throw, or already consumed by abort).
1067
- this._inFlightWorkerLedgers.set(startedRecord.laneId, {
1068
- changedFiles: toolChangedFiles,
1069
- getSpend: () => spentUsage,
1070
- request: workerRequest,
1071
- });
1072
- const outcome = await runWorker({
1073
- request: workerRequest,
1074
- maxUsd,
1075
- maxWallClockMs: settings.maxWallClockMs,
1076
- usageReportId,
1077
- getChangedFiles: () => [...toolChangedFiles],
1078
- signal: this._workerDelegationAbort.signal,
1079
- // Parent validation must use the same relative-path baseline the runner reports in.
1080
- cwd: this.deps.getCwd(),
1081
- // Write lane: runner-side action application through the envelope path scope.
1082
- applyActions: workerRequest.envelope.capabilities.includes("write_files")
1083
- ? (actions) => {
1084
- const permitted = actions.filter((action) => allowedActionOps.has(action.op));
1085
- const applied = applyWorkerActions({
1086
- actions: permitted,
1087
- envelope: workerRequest.envelope,
1088
- cwd: this.deps.getCwd(),
1089
- });
1090
- return {
1091
- ...applied,
1092
- refused: [
1093
- ...actions
1094
- .filter((action) => !allowedActionOps.has(action.op))
1095
- .map((action) => ({
1096
- path: action.path,
1097
- reason: `${action.op} is not granted by the lane profile`,
1098
- })),
1099
- ...applied.refused,
1100
- ],
1101
- };
1102
- }
1103
- : undefined,
1104
- complete: async ({ systemPrompt, userPrompt, signal }) => {
1105
- const completion = await this.deps.runIsolatedCompletion({
1106
- // Level-0 core always survives. A model-provided prompt (delegate tool) is the most
1107
- // specific override, then the settings-level prompt, then profile soul + role prompt.
1108
- systemPrompt: composeSubagentSystemPrompt({
1109
- soul: laneProfile?.soul,
1110
- rolePrompt: systemPrompt,
1111
- override: request.systemPrompt ?? settings.systemPrompt,
1112
- }),
1113
- messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
1114
- model,
1115
- thinkingLevel: laneProfile?.thinking ?? "off",
1116
- maxTokens: laneCapability.laneMaxOutputTokens,
1117
- tools: toolSurface.tools,
1118
- maxTurns: 6,
1119
- finalTextPrompt: "The tool-turn budget is exhausted. Do not call more tools. Return the required worker-result JSON envelope now using only evidence already gathered. If the investigation is incomplete, say so in the summary or blockers instead of omitting the envelope.",
1120
- beforeToolCall: async (context, toolSignal) => {
1121
- const decision = await toolSurface.beforeToolCall(context, toolSignal);
1122
- if (decision?.block) {
1123
- toolIssues.add(`${context.toolCall.name} blocked: ${decision.reason ?? "capability denied"}`);
1124
- }
1125
- return decision;
1126
- },
1127
- afterToolCall: async ({ toolCall, args, isError }) => {
1128
- // This hook runs only for a validated, gate-approved tool that actually entered
1129
- // execution. Record a direct mutation target before inspecting `isError`: write/edit
1130
- // may have changed disk and then observed cancellation, timeout, or a late I/O error.
1131
- // Pre-gate/profile/path refusals never reach afterToolCall, so they remain unreported.
1132
- if (toolCall.name === "write" || toolCall.name === "edit") {
1133
- if (args && typeof args === "object" && !Array.isArray(args)) {
1134
- const rawPath = args.path;
1135
- if (typeof rawPath === "string" && rawPath.length > 0) {
1136
- const absolutePath = path.isAbsolute(rawPath)
1137
- ? path.resolve(rawPath)
1138
- : path.resolve(this.deps.getCwd(), rawPath);
1139
- let canonicalPath = absolutePath;
1140
- try {
1141
- canonicalPath = safeRealpathSync(absolutePath);
1142
- }
1143
- catch {
1144
- // Execution was attempted; preserve conservative accounting with the lexical path.
1145
- }
1146
- toolChangedFiles.add(path.relative(this.deps.getCwd(), canonicalPath).split(path.sep).join("/"));
1147
- }
1148
- }
1149
- }
1150
- if (isError) {
1151
- toolIssues.add(`${toolCall.name} failed during isolated execution`);
1152
- return undefined;
1153
- }
1154
- return undefined;
1155
- },
1156
- signal,
1157
- // Core/soul/role are all static per configuration — the provider can cache the prefix.
1158
- cacheRetention: "short",
1159
- // Stable per-lane synthetic affinity key so repeat worker-delegation calls route to
1160
- // the same cache-warm backend without carrying the real session id.
1161
- laneKind: "worker",
1162
- });
1163
- spentUsage = completion.usage;
1164
- return {
1165
- text: completion.text,
1166
- costUsd: completion.usage.cost.total,
1167
- stopReason: String(completion.stopReason),
1168
- changedFiles: [...toolChangedFiles],
1169
- blockers: [...toolIssues],
1170
- };
1171
- },
1172
- });
1173
- // Never persist against a disposed session. When disposal raced this
1174
- // await, `abortInFlightLanes()`'s synchronous cutoff already completed this lane, persisted
1175
- // its durable lane record + bounded WorkerResult, and consumed (deleted) the ledger —
1176
- // `.complete()` below is then a no-op (the lane is already terminal, so it returns
1177
- // undefined) and no double persistence or duplicate terminal notification can happen here.
1178
- if (this.deps.isDisposed()) {
1179
- const record = this._laneTracker.complete(startedRecord.laneId, {
1180
- status: "canceled",
1181
- reasonCode: "session_disposed",
1182
- });
1183
- if (record)
1184
- this._recordWorkerTerminal(record);
1185
- return { started: true, record, outcome };
1186
- }
1187
- this.deps.saveWorkerResultSnapshot(outcome.result, workerRequest);
1188
- if (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {
1189
- this.deps.addSpawnedUsage(spentUsage, { label: "worker-delegation", reportId: usageReportId });
1190
- }
1191
- const record = this._laneTracker.complete(startedRecord.laneId, {
1192
- status: outcome.laneStatus,
1193
- reasonCode: outcome.reasonCode,
1194
- costUsd: outcome.costUsd,
1195
- });
1196
- if (record) {
1197
- this._recordWorkerTerminal(record);
1198
- appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
1199
- // Worker lane terminal record -> worker_result event. Lane outcome only
1200
- // (status/reasonCode/cost) — never the worker's summary/changed-file text.
1201
- this.deps.emitAutonomyTelemetry({
1202
- type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerResult,
1203
- timestamp: new Date().toISOString(),
1204
- payload: {
1205
- laneId: record.laneId,
1206
- laneType: record.type,
1207
- status: record.status,
1208
- reasonCode: record.reasonCode ?? null,
1209
- costUsd: record.costUsd ?? null,
1210
- },
1211
- });
1212
- }
1213
- return { started: true, record, outcome };
1214
- }
1215
- catch (error) {
1216
- const record = this._laneTracker.complete(startedRecord.laneId, {
1217
- status: "failed",
1218
- reasonCode: "worker_delegation_error",
1219
- });
1220
- if (record)
1221
- this._recordWorkerTerminal(record);
1222
- if (record && !this.deps.isDisposed()) {
1223
- appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
1224
- this.deps.emitAutonomyTelemetry({
1225
- type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerResult,
1226
- timestamp: new Date().toISOString(),
1227
- payload: {
1228
- laneId: record.laneId,
1229
- laneType: record.type,
1230
- status: record.status,
1231
- reasonCode: record.reasonCode ?? null,
1232
- costUsd: record.costUsd ?? null,
1233
- },
1234
- });
1235
- }
1236
- const message = error instanceof Error ? error.message : String(error);
1237
- this.deps.emit({ type: "warning", message: `Worker delegation failed: ${message}` });
1238
- return { started: true, record };
1239
- }
1240
- finally {
1241
- this._inFlightWorkerLedgers.delete(startedRecord.laneId);
1242
- deregisterInFlight();
1243
- }
250
+ return this._getWorkerController().runOnce(request, onStarted, existingRecord);
1244
251
  }
1245
252
  /**
1246
253
  * Probe a candidate model against the subagent contracts (research/worker/judge/search/
@@ -1249,155 +256,16 @@ export class BackgroundLaneController {
1249
256
  * spend is reported through spawned-usage accounting.
1250
257
  */
1251
258
  async runModelFitness(args) {
1252
- if (this.deps.isDisposed())
1253
- return { started: false, skipReason: "session_disposed" };
1254
- const resolved = this.resolveLaneModel(args.model.trim() || undefined);
1255
- if (!resolved)
1256
- return { started: false, skipReason: "model_unresolved_or_unauthenticated" };
1257
- const capability = this._laneCapabilityProfile(resolved);
1258
- // Registered for the probe's full run (it can execute several isolated-completion trials)
1259
- // so the reload gate waits it out; deregistered in the finally below on any exit path. Unlike
1260
- // research/worker, a fitness probe is not tracked in `_laneTracker` (it has no persisted lane
1261
- // record), so this registry is its ONLY reload-gate visibility.
1262
- const deregisterInFlight = registerInFlightWork(this.deps.getAgentDir(), "lane", `fitness:${resolved.provider}/${resolved.id}`);
1263
- try {
1264
- const spent = {
1265
- input: 0,
1266
- output: 0,
1267
- cacheRead: 0,
1268
- cacheWrite: 0,
1269
- totalTokens: 0,
1270
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
1271
- };
1272
- const report = await runModelFitnessProbe({
1273
- trials: args.trials,
1274
- signal: this._researchLaneAbort.signal,
1275
- capacityProbe: resolved.provider === "ollama" && resolved.contextWindow > 0
1276
- ? { registeredContextWindow: resolved.contextWindow }
1277
- : undefined,
1278
- complete: async ({ systemPrompt, userPrompt, signal }) => {
1279
- const callStarted = Date.now();
1280
- const completion = await this.deps.runIsolatedCompletion({
1281
- systemPrompt,
1282
- messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
1283
- model: resolved,
1284
- thinkingLevel: "off",
1285
- maxTokens: capability.laneMaxOutputTokens,
1286
- signal,
1287
- cacheRetention: "short",
1288
- // Stable per-lane synthetic affinity key so repeat fitness-probe trials against the
1289
- // same candidate model route to the same cache-warm backend without carrying the real
1290
- // session id.
1291
- laneKind: "fitness",
1292
- });
1293
- const callMs = Date.now() - callStarted;
1294
- spent.input += completion.usage.input;
1295
- spent.output += completion.usage.output;
1296
- spent.cacheRead += completion.usage.cacheRead;
1297
- spent.cacheWrite += completion.usage.cacheWrite;
1298
- spent.totalTokens += completion.usage.totalTokens;
1299
- spent.cost.input += completion.usage.cost.input;
1300
- spent.cost.output += completion.usage.cost.output;
1301
- spent.cost.cacheRead += completion.usage.cost.cacheRead;
1302
- spent.cost.cacheWrite += completion.usage.cost.cacheWrite;
1303
- spent.cost.total += completion.usage.cost.total;
1304
- return {
1305
- text: completion.text,
1306
- costUsd: completion.usage.cost.total,
1307
- stopReason: String(completion.stopReason),
1308
- // Wall-clock fallback for tok/s: providers don't expose pure eval time, so the
1309
- // measured call time stands in — slightly conservative (includes network/queue).
1310
- outputTokens: completion.usage.output,
1311
- evalMs: callMs,
1312
- };
1313
- },
1314
- });
1315
- const modelRef = `${resolved.provider}/${resolved.id}`;
1316
- if (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {
1317
- // Prefer the LLM tool-call id as the idempotency token: it is assigned once per
1318
- // distinct model_fitness tool call, so two deliberately separate calls on the same
1319
- // (model, trials) get DISTINCT ids (both count) while a retry of the same tool call
1320
- // (same toolCallId) keeps the same id (deduped). Callers with no toolCallId (the manual
1321
- // /fitness command, the auto-probe-on-model-add flows in local-model-commands.ts) fall
1322
- // back to the (model, trials) identity, unchanged from before.
1323
- const identity = args.toolCallId
1324
- ? `toolcall:${args.toolCallId}`
1325
- : `${modelRef} ${args.trials ?? "default"}`;
1326
- const reportId = deriveSpawnedUsageReportId("model-fitness", this.deps.getSessionId(), identity);
1327
- this.deps.addSpawnedUsage(spent, { label: "model-fitness", reportId });
1328
- }
1329
- // Fitness is a property of a model ON a host — persist the report host-keyed so role
1330
- // assignments stay per-machine (a model can await better hardware without being forgotten).
1331
- // Best-effort: a disk problem must not fail the probe itself.
1332
- try {
1333
- if (!this.deps.isDisposed()) {
1334
- FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);
1335
- }
1336
- }
1337
- catch {
1338
- // best-effort persistence
1339
- }
1340
- return { started: true, model: modelRef, report };
1341
- }
1342
- finally {
1343
- deregisterInFlight();
1344
- }
259
+ return this._fitness.run(args);
1345
260
  }
1346
- /** Start queued local workers at the owner session's foreground-idle boundary. */
261
+ /** Start every capacity-eligible queued worker at the owner session's foreground-idle boundary. */
1347
262
  drainQueuedWorkerDelegations() {
1348
- for (const [laneId, request] of [...this._queuedWorkers]) {
1349
- if (this._laneTracker.getRunningCount("worker") >=
1350
- this.deps.getSettingsManager().getWorkerDelegationSettings().maxConcurrent)
1351
- break;
1352
- const record = this._laneTracker.getRecords().find((candidate) => candidate.laneId === laneId);
1353
- // The queued-phase reload-gate registration ends here, at the running handoff, no
1354
- // matter which branch below runs. `runWorkerDelegationOnce` registers its OWN "running"
1355
- // unit independently and synchronously (no `await` separates the two calls), so there is
1356
- // no window where this lane is invisible to the reload gate.
1357
- const deregisterQueued = this._queuedWorkerDeregisters.get(laneId);
1358
- this._queuedWorkerDeregisters.delete(laneId);
1359
- if (!record) {
1360
- this._queuedWorkers.delete(laneId);
1361
- deregisterQueued?.();
1362
- continue;
1363
- }
1364
- this._queuedWorkers.delete(laneId);
1365
- deregisterQueued?.();
1366
- const promise = this.runWorkerDelegationOnce(request, undefined, record);
1367
- this._workerPromises.set(laneId, promise);
1368
- void promise.then((outcome) => {
1369
- if (!outcome.started) {
1370
- const terminal = this._laneTracker.complete(laneId, {
1371
- status: "canceled",
1372
- reasonCode: outcome.skipReason,
1373
- });
1374
- if (terminal)
1375
- this._recordWorkerTerminal(terminal);
1376
- }
1377
- this._workerPromises.delete(laneId);
1378
- if (!this.deps.isDisposed())
1379
- this.drainQueuedWorkerDelegations();
1380
- }, () => {
1381
- const terminal = this._laneTracker.complete(laneId, {
1382
- status: "failed",
1383
- reasonCode: "worker_background_error",
1384
- });
1385
- if (terminal)
1386
- this._recordWorkerTerminal(terminal);
1387
- this._workerPromises.delete(laneId);
1388
- if (!this.deps.isDisposed())
1389
- this.drainQueuedWorkerDelegations();
1390
- });
1391
- }
263
+ if (this.deps.isDelegateToolActive?.())
264
+ this._getWorkerController().drain();
1392
265
  }
1393
266
  /** Fitness reports persisted for THIS host (measured evidence for architect/profile decisions). */
1394
267
  getStoredFitnessReports() {
1395
- try {
1396
- return FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();
1397
- }
1398
- catch {
1399
- return [];
1400
- }
268
+ return this._fitness.getStoredReports();
1401
269
  }
1402
270
  }
1403
271
  //# sourceMappingURL=background-lane-controller.js.map