@caupulican/pi-adaptative 0.81.37 → 0.81.39

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 (451) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +131 -0
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +196 -0
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +308 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +22 -2
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +585 -24
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  13. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +749 -27
  14. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
  15. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
  16. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
  17. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
  18. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
  19. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
  20. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
  21. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
  22. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
  23. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
  24. package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
  25. package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
  26. package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
  27. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
  28. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
  29. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
  30. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
  31. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +5 -5
  32. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
  33. package/dist/cli/args.d.ts +3 -0
  34. package/dist/cli/args.d.ts.map +1 -1
  35. package/dist/cli/args.js +15 -0
  36. package/dist/cli/args.js.map +1 -1
  37. package/dist/core/agent-paths.d.ts +49 -0
  38. package/dist/core/agent-paths.d.ts.map +1 -0
  39. package/dist/core/agent-paths.js +107 -0
  40. package/dist/core/agent-paths.js.map +1 -0
  41. package/dist/core/agent-session-services.d.ts.map +1 -1
  42. package/dist/core/agent-session-services.js +3 -3
  43. package/dist/core/agent-session-services.js.map +1 -1
  44. package/dist/core/agent-session.d.ts +234 -17
  45. package/dist/core/agent-session.d.ts.map +1 -1
  46. package/dist/core/agent-session.js +484 -62
  47. package/dist/core/agent-session.js.map +1 -1
  48. package/dist/core/autonomy/contracts.d.ts +9 -0
  49. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  50. package/dist/core/autonomy/contracts.js.map +1 -1
  51. package/dist/core/autonomy/lane-tracker.d.ts +10 -1
  52. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  53. package/dist/core/autonomy/lane-tracker.js +5 -1
  54. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  55. package/dist/core/background-lane-controller.d.ts +122 -6
  56. package/dist/core/background-lane-controller.d.ts.map +1 -1
  57. package/dist/core/background-lane-controller.js +447 -90
  58. package/dist/core/background-lane-controller.js.map +1 -1
  59. package/dist/core/bash-execution-controller.d.ts +4 -0
  60. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  61. package/dist/core/bash-execution-controller.js +7 -1
  62. package/dist/core/bash-execution-controller.js.map +1 -1
  63. package/dist/core/compaction-support.d.ts +13 -3
  64. package/dist/core/compaction-support.d.ts.map +1 -1
  65. package/dist/core/compaction-support.js +43 -7
  66. package/dist/core/compaction-support.js.map +1 -1
  67. package/dist/core/context/context-audit.d.ts +33 -1
  68. package/dist/core/context/context-audit.d.ts.map +1 -1
  69. package/dist/core/context/context-audit.js +31 -5
  70. package/dist/core/context/context-audit.js.map +1 -1
  71. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  72. package/dist/core/context/sqlite-runtime-index.js +13 -7
  73. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  74. package/dist/core/context-gc.d.ts.map +1 -1
  75. package/dist/core/context-gc.js +16 -1
  76. package/dist/core/context-gc.js.map +1 -1
  77. package/dist/core/context-pipeline.d.ts +26 -4
  78. package/dist/core/context-pipeline.d.ts.map +1 -1
  79. package/dist/core/context-pipeline.js +137 -14
  80. package/dist/core/context-pipeline.js.map +1 -1
  81. package/dist/core/cost-guard.d.ts +19 -3
  82. package/dist/core/cost-guard.d.ts.map +1 -1
  83. package/dist/core/cost-guard.js +18 -3
  84. package/dist/core/cost-guard.js.map +1 -1
  85. package/dist/core/delegation/session-worker-result.d.ts +34 -4
  86. package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
  87. package/dist/core/delegation/session-worker-result.js +64 -4
  88. package/dist/core/delegation/session-worker-result.js.map +1 -1
  89. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  90. package/dist/core/delegation/worker-actions.js +1 -1
  91. package/dist/core/delegation/worker-actions.js.map +1 -1
  92. package/dist/core/delegation/worker-result.d.ts +42 -1
  93. package/dist/core/delegation/worker-result.d.ts.map +1 -1
  94. package/dist/core/delegation/worker-result.js +68 -0
  95. package/dist/core/delegation/worker-result.js.map +1 -1
  96. package/dist/core/extensions/loader.d.ts.map +1 -1
  97. package/dist/core/extensions/loader.js +23 -7
  98. package/dist/core/extensions/loader.js.map +1 -1
  99. package/dist/core/extensions/runner.d.ts.map +1 -1
  100. package/dist/core/extensions/runner.js +1 -0
  101. package/dist/core/extensions/runner.js.map +1 -1
  102. package/dist/core/extensions/types.d.ts +51 -0
  103. package/dist/core/extensions/types.d.ts.map +1 -1
  104. package/dist/core/extensions/types.js.map +1 -1
  105. package/dist/core/goal-loop-controller.d.ts +17 -1
  106. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  107. package/dist/core/goal-loop-controller.js +79 -11
  108. package/dist/core/goal-loop-controller.js.map +1 -1
  109. package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
  110. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  111. package/dist/core/goals/goal-continuation-controller.js +77 -0
  112. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  113. package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
  114. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  115. package/dist/core/goals/goal-continuation-defaults.js +42 -0
  116. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  117. package/dist/core/goals/goal-continuation-prompt.d.ts +4 -0
  118. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  119. package/dist/core/goals/goal-continuation-prompt.js +51 -10
  120. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  121. package/dist/core/goals/goal-runtime-snapshot.d.ts +101 -2
  122. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  123. package/dist/core/goals/goal-runtime-snapshot.js +87 -4
  124. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  125. package/dist/core/goals/goal-state.d.ts +89 -1
  126. package/dist/core/goals/goal-state.d.ts.map +1 -1
  127. package/dist/core/goals/goal-state.js +71 -5
  128. package/dist/core/goals/goal-state.js.map +1 -1
  129. package/dist/core/goals/goal-tool-core.d.ts +56 -2
  130. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  131. package/dist/core/goals/goal-tool-core.js +111 -5
  132. package/dist/core/goals/goal-tool-core.js.map +1 -1
  133. package/dist/core/goals/session-goal-state.d.ts +11 -2
  134. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  135. package/dist/core/goals/session-goal-state.js +32 -17
  136. package/dist/core/goals/session-goal-state.js.map +1 -1
  137. package/dist/core/keybindings.d.ts +10 -0
  138. package/dist/core/keybindings.d.ts.map +1 -1
  139. package/dist/core/keybindings.js +10 -2
  140. package/dist/core/keybindings.js.map +1 -1
  141. package/dist/core/learning/observation-store.d.ts +12 -3
  142. package/dist/core/learning/observation-store.d.ts.map +1 -1
  143. package/dist/core/learning/observation-store.js +30 -15
  144. package/dist/core/learning/observation-store.js.map +1 -1
  145. package/dist/core/learning/skill-curator.d.ts +5 -1
  146. package/dist/core/learning/skill-curator.d.ts.map +1 -1
  147. package/dist/core/learning/skill-curator.js +21 -19
  148. package/dist/core/learning/skill-curator.js.map +1 -1
  149. package/dist/core/local-runtime-controller.d.ts +65 -3
  150. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  151. package/dist/core/local-runtime-controller.js +186 -26
  152. package/dist/core/local-runtime-controller.js.map +1 -1
  153. package/dist/core/memory/providers/file-store.d.ts +1 -1
  154. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  155. package/dist/core/memory/providers/file-store.js +6 -6
  156. package/dist/core/memory/providers/file-store.js.map +1 -1
  157. package/dist/core/model-capability.d.ts +34 -0
  158. package/dist/core/model-capability.d.ts.map +1 -1
  159. package/dist/core/model-capability.js +42 -1
  160. package/dist/core/model-capability.js.map +1 -1
  161. package/dist/core/model-router/tool-escalation.d.ts +15 -0
  162. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  163. package/dist/core/model-router/tool-escalation.js +23 -1
  164. package/dist/core/model-router/tool-escalation.js.map +1 -1
  165. package/dist/core/model-router-controller.d.ts +34 -7
  166. package/dist/core/model-router-controller.d.ts.map +1 -1
  167. package/dist/core/model-router-controller.js +95 -16
  168. package/dist/core/model-router-controller.js.map +1 -1
  169. package/dist/core/models/adaptation-store.d.ts +7 -0
  170. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  171. package/dist/core/models/adaptation-store.js +47 -11
  172. package/dist/core/models/adaptation-store.js.map +1 -1
  173. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  174. package/dist/core/models/default-model-suggestions.js +17 -0
  175. package/dist/core/models/default-model-suggestions.js.map +1 -1
  176. package/dist/core/models/fitness-store.d.ts +3 -0
  177. package/dist/core/models/fitness-store.d.ts.map +1 -1
  178. package/dist/core/models/fitness-store.js +11 -2
  179. package/dist/core/models/fitness-store.js.map +1 -1
  180. package/dist/core/models/llamacpp-runtime.d.ts +180 -0
  181. package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
  182. package/dist/core/models/llamacpp-runtime.js +475 -0
  183. package/dist/core/models/llamacpp-runtime.js.map +1 -0
  184. package/dist/core/models/local-registration.d.ts +40 -0
  185. package/dist/core/models/local-registration.d.ts.map +1 -1
  186. package/dist/core/models/local-registration.js +94 -5
  187. package/dist/core/models/local-registration.js.map +1 -1
  188. package/dist/core/models/local-runtime.d.ts.map +1 -1
  189. package/dist/core/models/local-runtime.js +9 -7
  190. package/dist/core/models/local-runtime.js.map +1 -1
  191. package/dist/core/models/model-ref.d.ts +7 -0
  192. package/dist/core/models/model-ref.d.ts.map +1 -1
  193. package/dist/core/models/model-ref.js +26 -0
  194. package/dist/core/models/model-ref.js.map +1 -1
  195. package/dist/core/models/needle-runtime.d.ts +257 -0
  196. package/dist/core/models/needle-runtime.d.ts.map +1 -0
  197. package/dist/core/models/needle-runtime.js +519 -0
  198. package/dist/core/models/needle-runtime.js.map +1 -0
  199. package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
  200. package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
  201. package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
  202. package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
  203. package/dist/core/package-manager.d.ts.map +1 -1
  204. package/dist/core/package-manager.js +11 -10
  205. package/dist/core/package-manager.js.map +1 -1
  206. package/dist/core/process-matrix/codes.d.ts +72 -0
  207. package/dist/core/process-matrix/codes.d.ts.map +1 -0
  208. package/dist/core/process-matrix/codes.js +15 -0
  209. package/dist/core/process-matrix/codes.js.map +1 -0
  210. package/dist/core/process-matrix/runtime.d.ts +63 -0
  211. package/dist/core/process-matrix/runtime.d.ts.map +1 -0
  212. package/dist/core/process-matrix/runtime.js +310 -0
  213. package/dist/core/process-matrix/runtime.js.map +1 -0
  214. package/dist/core/process-matrix/store.d.ts +22 -0
  215. package/dist/core/process-matrix/store.d.ts.map +1 -0
  216. package/dist/core/process-matrix/store.js +80 -0
  217. package/dist/core/process-matrix/store.js.map +1 -0
  218. package/dist/core/process-matrix/supervisor.d.ts +72 -0
  219. package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
  220. package/dist/core/process-matrix/supervisor.js +130 -0
  221. package/dist/core/process-matrix/supervisor.js.map +1 -0
  222. package/dist/core/profile-registry.d.ts +7 -0
  223. package/dist/core/profile-registry.d.ts.map +1 -1
  224. package/dist/core/profile-registry.js +20 -0
  225. package/dist/core/profile-registry.js.map +1 -1
  226. package/dist/core/python-runtime.d.ts.map +1 -1
  227. package/dist/core/python-runtime.js +3 -3
  228. package/dist/core/python-runtime.js.map +1 -1
  229. package/dist/core/reflection-controller.d.ts +29 -5
  230. package/dist/core/reflection-controller.d.ts.map +1 -1
  231. package/dist/core/reflection-controller.js +215 -126
  232. package/dist/core/reflection-controller.js.map +1 -1
  233. package/dist/core/reload-blockers.d.ts +36 -0
  234. package/dist/core/reload-blockers.d.ts.map +1 -1
  235. package/dist/core/reload-blockers.js +44 -0
  236. package/dist/core/reload-blockers.js.map +1 -1
  237. package/dist/core/resource-loader.d.ts.map +1 -1
  238. package/dist/core/resource-loader.js +8 -7
  239. package/dist/core/resource-loader.js.map +1 -1
  240. package/dist/core/runtime-builder.d.ts +58 -5
  241. package/dist/core/runtime-builder.d.ts.map +1 -1
  242. package/dist/core/runtime-builder.js +209 -25
  243. package/dist/core/runtime-builder.js.map +1 -1
  244. package/dist/core/scout-controller.d.ts +6 -0
  245. package/dist/core/scout-controller.d.ts.map +1 -1
  246. package/dist/core/scout-controller.js +66 -52
  247. package/dist/core/scout-controller.js.map +1 -1
  248. package/dist/core/sdk.d.ts.map +1 -1
  249. package/dist/core/sdk.js +3 -3
  250. package/dist/core/sdk.js.map +1 -1
  251. package/dist/core/session-role.d.ts +31 -0
  252. package/dist/core/session-role.d.ts.map +1 -0
  253. package/dist/core/session-role.js +52 -0
  254. package/dist/core/session-role.js.map +1 -0
  255. package/dist/core/settings-manager.d.ts +42 -3
  256. package/dist/core/settings-manager.d.ts.map +1 -1
  257. package/dist/core/settings-manager.js +94 -60
  258. package/dist/core/settings-manager.js.map +1 -1
  259. package/dist/core/system-prompt-builder.d.ts +12 -0
  260. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  261. package/dist/core/system-prompt-builder.js +6 -0
  262. package/dist/core/system-prompt-builder.js.map +1 -1
  263. package/dist/core/system-prompt.d.ts +14 -1
  264. package/dist/core/system-prompt.d.ts.map +1 -1
  265. package/dist/core/system-prompt.js +20 -3
  266. package/dist/core/system-prompt.js.map +1 -1
  267. package/dist/core/tasks/session-task-state.d.ts +11 -2
  268. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  269. package/dist/core/tasks/session-task-state.js +27 -11
  270. package/dist/core/tasks/session-task-state.js.map +1 -1
  271. package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
  272. package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
  273. package/dist/core/tasks/task-contract-monitor.js +56 -0
  274. package/dist/core/tasks/task-contract-monitor.js.map +1 -0
  275. package/dist/core/tasks/task-state.d.ts +8 -0
  276. package/dist/core/tasks/task-state.d.ts.map +1 -1
  277. package/dist/core/tasks/task-state.js +28 -1
  278. package/dist/core/tasks/task-state.js.map +1 -1
  279. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  280. package/dist/core/tool-gate-controller.js +5 -0
  281. package/dist/core/tool-gate-controller.js.map +1 -1
  282. package/dist/core/tool-recovery-log-records.d.ts +7 -0
  283. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  284. package/dist/core/tool-recovery-log-records.js +14 -6
  285. package/dist/core/tool-recovery-log-records.js.map +1 -1
  286. package/dist/core/tool-selection/promotion.d.ts +54 -0
  287. package/dist/core/tool-selection/promotion.d.ts.map +1 -0
  288. package/dist/core/tool-selection/promotion.js +81 -0
  289. package/dist/core/tool-selection/promotion.js.map +1 -0
  290. package/dist/core/tool-selection/tool-performance-store.d.ts +37 -0
  291. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  292. package/dist/core/tool-selection/tool-performance-store.js +87 -3
  293. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  294. package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
  295. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  296. package/dist/core/tool-selection/tool-selection-controller.js +96 -0
  297. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  298. package/dist/core/tools/bash.d.ts +18 -0
  299. package/dist/core/tools/bash.d.ts.map +1 -1
  300. package/dist/core/tools/bash.js +97 -18
  301. package/dist/core/tools/bash.js.map +1 -1
  302. package/dist/core/tools/delegate-status.d.ts +14 -0
  303. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  304. package/dist/core/tools/delegate-status.js +82 -7
  305. package/dist/core/tools/delegate-status.js.map +1 -1
  306. package/dist/core/tools/delegate.d.ts.map +1 -1
  307. package/dist/core/tools/delegate.js +25 -8
  308. package/dist/core/tools/delegate.js.map +1 -1
  309. package/dist/core/tools/find.d.ts.map +1 -1
  310. package/dist/core/tools/find.js +52 -44
  311. package/dist/core/tools/find.js.map +1 -1
  312. package/dist/core/tools/goal.d.ts +94 -3
  313. package/dist/core/tools/goal.d.ts.map +1 -1
  314. package/dist/core/tools/goal.js +165 -15
  315. package/dist/core/tools/goal.js.map +1 -1
  316. package/dist/core/tools/grep.d.ts.map +1 -1
  317. package/dist/core/tools/grep.js +5 -4
  318. package/dist/core/tools/grep.js.map +1 -1
  319. package/dist/core/tools/model-fitness.d.ts +7 -0
  320. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  321. package/dist/core/tools/model-fitness.js +2 -2
  322. package/dist/core/tools/model-fitness.js.map +1 -1
  323. package/dist/core/tools/render-utils.d.ts.map +1 -1
  324. package/dist/core/tools/render-utils.js +1 -1
  325. package/dist/core/tools/render-utils.js.map +1 -1
  326. package/dist/core/tools/shell-contract-router.d.ts +6 -1
  327. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  328. package/dist/core/tools/shell-contract-router.js +69 -13
  329. package/dist/core/tools/shell-contract-router.js.map +1 -1
  330. package/dist/core/tools/shell-session.d.ts +89 -0
  331. package/dist/core/tools/shell-session.d.ts.map +1 -0
  332. package/dist/core/tools/shell-session.js +432 -0
  333. package/dist/core/tools/shell-session.js.map +1 -0
  334. package/dist/core/tools/task-steps.d.ts +4 -0
  335. package/dist/core/tools/task-steps.d.ts.map +1 -1
  336. package/dist/core/tools/task-steps.js +63 -8
  337. package/dist/core/tools/task-steps.js.map +1 -1
  338. package/dist/core/tools/tmux-dispatch.d.ts +86 -0
  339. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
  340. package/dist/core/tools/tmux-dispatch.js +91 -0
  341. package/dist/core/tools/tmux-dispatch.js.map +1 -0
  342. package/dist/core/tools/windows-shell-engine.d.ts +42 -0
  343. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
  344. package/dist/core/tools/windows-shell-engine.js +153 -0
  345. package/dist/core/tools/windows-shell-engine.js.map +1 -0
  346. package/dist/core/tools/windows-shell-state.d.ts +40 -0
  347. package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
  348. package/dist/core/tools/windows-shell-state.js +59 -0
  349. package/dist/core/tools/windows-shell-state.js.map +1 -0
  350. package/dist/core/tools/worktree-sync.d.ts +24 -0
  351. package/dist/core/tools/worktree-sync.d.ts.map +1 -0
  352. package/dist/core/tools/worktree-sync.js +338 -0
  353. package/dist/core/tools/worktree-sync.js.map +1 -0
  354. package/dist/core/trust-manager.d.ts +4 -1
  355. package/dist/core/trust-manager.d.ts.map +1 -1
  356. package/dist/core/trust-manager.js +20 -2
  357. package/dist/core/trust-manager.js.map +1 -1
  358. package/dist/core/util/atomic-file.d.ts +55 -0
  359. package/dist/core/util/atomic-file.d.ts.map +1 -0
  360. package/dist/core/util/atomic-file.js +255 -0
  361. package/dist/core/util/atomic-file.js.map +1 -0
  362. package/dist/core/util/minimatch-cache.d.ts +33 -0
  363. package/dist/core/util/minimatch-cache.d.ts.map +1 -0
  364. package/dist/core/util/minimatch-cache.js +0 -0
  365. package/dist/core/util/minimatch-cache.js.map +1 -0
  366. package/dist/core/worktree-sync/codes.d.ts +227 -0
  367. package/dist/core/worktree-sync/codes.d.ts.map +1 -0
  368. package/dist/core/worktree-sync/codes.js +14 -0
  369. package/dist/core/worktree-sync/codes.js.map +1 -0
  370. package/dist/core/worktree-sync/git-engine.d.ts +156 -0
  371. package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
  372. package/dist/core/worktree-sync/git-engine.js +1191 -0
  373. package/dist/core/worktree-sync/git-engine.js.map +1 -0
  374. package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
  375. package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
  376. package/dist/core/worktree-sync/lane-gate.js +360 -0
  377. package/dist/core/worktree-sync/lane-gate.js.map +1 -0
  378. package/dist/core/worktree-sync/runtime.d.ts +47 -0
  379. package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
  380. package/dist/core/worktree-sync/runtime.js +96 -0
  381. package/dist/core/worktree-sync/runtime.js.map +1 -0
  382. package/dist/core/worktree-sync/store.d.ts +69 -0
  383. package/dist/core/worktree-sync/store.d.ts.map +1 -0
  384. package/dist/core/worktree-sync/store.js +247 -0
  385. package/dist/core/worktree-sync/store.js.map +1 -0
  386. package/dist/core/worktree-sync/watcher.d.ts +29 -0
  387. package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
  388. package/dist/core/worktree-sync/watcher.js +93 -0
  389. package/dist/core/worktree-sync/watcher.js.map +1 -0
  390. package/dist/main.d.ts.map +1 -1
  391. package/dist/main.js +94 -0
  392. package/dist/main.js.map +1 -1
  393. package/dist/migrations.d.ts +9 -0
  394. package/dist/migrations.d.ts.map +1 -1
  395. package/dist/migrations.js +38 -0
  396. package/dist/migrations.js.map +1 -1
  397. package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
  398. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  399. package/dist/modes/interactive/auto-learn-controller.js +50 -8
  400. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  401. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
  403. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  404. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  405. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  406. package/dist/modes/interactive/interactive-mode.js +4 -0
  407. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  408. package/dist/modes/interactive/local-model-commands.d.ts +43 -0
  409. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  410. package/dist/modes/interactive/local-model-commands.js +290 -3
  411. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  412. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  413. package/dist/modes/interactive/session-flow-commands.js +24 -4
  414. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  415. package/dist/utils/fs-watch.d.ts +11 -0
  416. package/dist/utils/fs-watch.d.ts.map +1 -1
  417. package/dist/utils/fs-watch.js +20 -2
  418. package/dist/utils/fs-watch.js.map +1 -1
  419. package/dist/utils/highlight-js-languages.d.ts +4 -0
  420. package/dist/utils/highlight-js-languages.d.ts.map +1 -0
  421. package/dist/utils/highlight-js-languages.js +573 -0
  422. package/dist/utils/highlight-js-languages.js.map +1 -0
  423. package/dist/utils/shell.d.ts +7 -1
  424. package/dist/utils/shell.d.ts.map +1 -1
  425. package/dist/utils/shell.js +39 -9
  426. package/dist/utils/shell.js.map +1 -1
  427. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  428. package/dist/utils/syntax-highlight.js +53 -5
  429. package/dist/utils/syntax-highlight.js.map +1 -1
  430. package/dist/utils/tools-manager.d.ts.map +1 -1
  431. package/dist/utils/tools-manager.js +112 -1
  432. package/dist/utils/tools-manager.js.map +1 -1
  433. package/docs/development.md +2 -0
  434. package/docs/packages.md +1 -1
  435. package/docs/process-matrix.md +120 -0
  436. package/docs/settings.md +5 -2
  437. package/docs/tmux-agent-manager.md +85 -2
  438. package/docs/windows.md +52 -3
  439. package/docs/work-directory.md +29 -0
  440. package/docs/worktree-sync.md +250 -0
  441. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  442. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  443. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  444. package/examples/extensions/sandbox/package-lock.json +2 -2
  445. package/examples/extensions/sandbox/package.json +1 -1
  446. package/examples/extensions/with-deps/package-lock.json +2 -2
  447. package/examples/extensions/with-deps/package.json +1 -1
  448. package/npm-shrinkwrap.json +12 -12
  449. package/package.json +10 -4
  450. package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
  451. package/docs/integration-sweep-resume-2026-07-09.md +0 -407
@@ -14,7 +14,9 @@
14
14
  * delegations; goal auto-continue itself only ever asks the session to `continueGoalLoop`, so this
15
15
  * controller never touches `prompt()`, the last-assistant-message, retry, or streaming state.
16
16
  */
17
+ import { createHash } from "node:crypto";
17
18
  import path from "node:path";
19
+ import { configFile, getWorkRoot, sessionsDir, stateDir } from "./agent-paths.js";
18
20
  import { createLaneToolSurface } from "./autonomy/lane-tool-surface.js";
19
21
  import { LaneTracker } from "./autonomy/lane-tracker.js";
20
22
  import { safeRealpathSync } from "./autonomy/path-scope.js";
@@ -22,30 +24,89 @@ import { appendLaneRecordSnapshot, getLaneRecordSnapshots } from "./autonomy/ses
22
24
  import { composeSubagentSystemPrompt } from "./autonomy/subagent-prompt.js";
23
25
  import { AUTONOMY_TELEMETRY_EVENT_TYPES } from "./autonomy/telemetry-events.js";
24
26
  import { applyWorkerActions } from "./delegation/worker-actions.js";
27
+ import { reviewManagedLaneChangedFiles } from "./delegation/worker-result.js";
25
28
  import { runWorker } from "./delegation/worker-runner.js";
26
29
  import { deriveModelCapabilityProfile, scaleContinuationBudgetsForCapability, } from "./model-capability.js";
27
30
  import { resolveCliModel } from "./model-resolver.js";
28
31
  import { FitnessStore } from "./models/fitness-store.js";
32
+ import { registerInFlightWork } from "./reload-blockers.js";
29
33
  import { runModelFitnessProbe } from "./research/model-fitness.js";
30
34
  import { runResearch } from "./research/research-runner.js";
31
35
  const WORKER_HANDOFF_TIMEOUT_MS = 30_000;
32
36
  export function clampLaneMaxUsd(settingsMaxUsd, foregroundMaxEstimatedUsd) {
33
37
  return Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);
34
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
+ }
35
49
  export function getPrivateLaneDeniedPaths(cwd, agentDir) {
36
50
  return [
37
- "auth.json",
38
- "MEMORY.md",
39
- "USER.md",
40
- "settings.json",
41
- "models.json",
42
- "trust.json",
43
- "sessions",
44
- "state",
45
- "work",
46
- ]
47
- .map((entry) => path.join(agentDir, entry))
48
- .concat(path.join(cwd, ".pi", "settings.json"));
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
+ }
49
110
  }
50
111
  export function isLocalExecutionModel(model) {
51
112
  if (model.provider === "ollama" || model.provider === "transformers" || model.provider === "llama-cpp") {
@@ -89,7 +150,35 @@ export class BackgroundLaneController {
89
150
  _workersCompletedSinceFlush = 0;
90
151
  _workersFailedSinceFlush = 0;
91
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();
92
171
  deps;
172
+ /** Emit a warning without ever throwing — used from disposal-adjacent persistence where a
173
+ * listener failure (or a bare test double missing `emit`) must never block or crash cleanup. */
174
+ _safeWarn(message) {
175
+ try {
176
+ this.deps.emit({ type: "warning", message });
177
+ }
178
+ catch {
179
+ // Dispose must never throw.
180
+ }
181
+ }
93
182
  _scheduleWorkerNotification() {
94
183
  if (this._disposed || this._workerNotificationScheduled)
95
184
  return;
@@ -174,28 +263,181 @@ export class BackgroundLaneController {
174
263
  getLaneRecords() {
175
264
  return this._laneTracker.getRecords();
176
265
  }
266
+ /**
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.
274
+ */
275
+ resolveManagedLaneId(callerLaneId) {
276
+ return this._managedLaneDispatches.get(callerLaneId)?.laneId;
277
+ }
177
278
  /** Live count of active lanes — the real source for AutonomyStatusSnapshot.activeLaneCount. */
178
279
  getActiveLaneCount() {
179
280
  return this._laneTracker.getActiveCount();
180
281
  }
282
+ /** Belt-and-braces guard: whether ANY queued/running lane is tagged with this goalId. */
283
+ _hasInFlightLaneForGoal(goalId) {
284
+ return this.getLaneRecords().some((record) => record.goalId === goalId && (record.status === "queued" || record.status === "running"));
285
+ }
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
+ */
317
+ 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
+ }
367
+ }
181
368
  /** Why the last idle research-lane evaluation skipped, for /autonomy diagnostics. */
182
369
  getLastResearchLaneSkipReason() {
183
370
  return this._lastResearchLaneSkipReason;
184
371
  }
185
- /** Abort any in-flight research pass or delegated worker (called on session dispose). */
372
+ /**
373
+ * Abort any in-flight research pass or delegated worker (called on session dispose).
374
+ *
375
+ * This synchronous body is the LAST provably-safe write window for canceled/in-flight work.
376
+ * `dispose()` (agent-session.ts) has already set the session's own disposed flag but has not yet
377
+ * returned — no successor session (e.g. a `/reload` adoption) can exist yet, so an append here
378
+ * cannot interleave with one; a post-await continuation resuming AFTER this method returns must
379
+ * not append (see the disposed branch in `runWorkerDelegationOnce`). Persist FIRST, then
380
+ * complete-in-memory, so a throw from one lane's persist cannot skip another's; each persist gets
381
+ * its own try/catch — dispose must never throw.
382
+ */
186
383
  abortInFlightLanes() {
187
384
  this._disposed = true;
188
385
  this._researchLaneAbort.abort();
189
386
  this._workerDelegationAbort.abort();
190
- this._queuedWorkers.clear();
191
387
  for (const record of this._laneTracker.getRecords()) {
192
- if (record.status === "queued" || record.status === "running") {
193
- this._laneTracker.complete(record.laneId, {
194
- status: "canceled",
195
- reasonCode: "session_disposed",
196
- });
388
+ if (record.status !== "queued" && record.status !== "running")
389
+ continue;
390
+ const canceled = this._laneTracker.complete(record.laneId, {
391
+ status: "canceled",
392
+ reasonCode: "session_disposed",
393
+ });
394
+ if (!canceled)
395
+ continue;
396
+ try {
397
+ appendLaneRecordSnapshot(this.deps.getSessionManager(), canceled);
398
+ }
399
+ catch (error) {
400
+ this._safeWarn(`Failed to persist canceled lane record ${canceled.laneId}: ${error instanceof Error ? error.message : String(error)}`);
401
+ }
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)}`);
197
433
  }
198
434
  }
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();
199
441
  this._workerNotificationScheduled = false;
200
442
  this._workerTerminalSinceFlush.length = 0;
201
443
  }
@@ -219,6 +461,14 @@ export class BackgroundLaneController {
219
461
  const snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });
220
462
  if (snapshot.continuation.action !== "continue")
221
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;
222
472
  this.clearGoalAutoContinueTimer();
223
473
  this._goalAutoContinueTimer = setTimeout(() => {
224
474
  this._goalAutoContinueTimer = undefined;
@@ -241,14 +491,16 @@ export class BackgroundLaneController {
241
491
  const snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns });
242
492
  if (snapshot.continuation.action !== "continue")
243
493
  return;
244
- // Lean-window models (16-32k) keep autosteer but at a reduced budget; full passes through.
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.
245
498
  const scaled = scaleContinuationBudgetsForCapability(this.deps.getModelCapabilityProfile(), {
246
499
  maxTurns: goalContinueTurns,
247
500
  maxWallClockMinutes: goalContinueMaxWallClockMinutes,
248
501
  });
249
- this._isGoalAutoContinuing = true;
250
502
  try {
251
- await this.deps.continueGoalLoop({
503
+ await this.continueGoalLoopExclusive({
252
504
  maxTurns: scaled.maxTurns,
253
505
  maxStallTurns,
254
506
  maxWallClockMinutes: scaled.maxWallClockMinutes,
@@ -258,10 +510,48 @@ export class BackgroundLaneController {
258
510
  const message = error instanceof Error ? error.message : String(error);
259
511
  this.deps.emit({ type: "warning", message: `Goal auto-continuation failed: ${message}` });
260
512
  }
513
+ }
514
+ /**
515
+ * Single-flight entry point for EVERY goal-continuation loop invocation — idle autosteer
516
+ * ({@link _runScheduledGoalAutoContinue}) AND the manual `/goal start` / `/goal-continue`
517
+ * commands (reached through `AgentSession.continueGoalLoop`). Both paths ultimately submit
518
+ * continuation prompts through the session's single `prompt()` path, so two loops racing throws
519
+ * "Agent is already processing" from whichever submits second. `_isGoalAutoContinuing` is the
520
+ * ONE owner of that mutex; `deps.continueGoalLoop` (the raw {@link GoalLoopController} loop)
521
+ * must never be called directly outside this method, or the guard is bypassed.
522
+ */
523
+ 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
+ }
261
538
  finally {
262
539
  this._isGoalAutoContinuing = false;
263
540
  }
264
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
+ };
554
+ }
265
555
  clearResearchLaneTimer() {
266
556
  if (this._researchLaneTimer !== undefined) {
267
557
  clearTimeout(this._researchLaneTimer);
@@ -482,6 +772,9 @@ export class BackgroundLaneController {
482
772
  this._seedLaneHistory();
483
773
  const startedRecord = this._laneTracker.start({ type: "research", goalId: demand.goalId });
484
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}`);
485
778
  try {
486
779
  let spentUsage;
487
780
  // Best-effort, pointer-first workspace evidence. Derives search terms from the goal/requirement
@@ -527,6 +820,9 @@ export class BackgroundLaneController {
527
820
  signal,
528
821
  // Core/soul/role are all static per configuration — the provider can cache the prefix.
529
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",
530
826
  });
531
827
  spentUsage = completion.usage;
532
828
  return {
@@ -536,7 +832,7 @@ export class BackgroundLaneController {
536
832
  };
537
833
  },
538
834
  });
539
- // Bug #21 pattern: if the session was disposed while the completion was in flight, do NOT
835
+ // If the session was disposed while the completion was in flight, do NOT
540
836
  // persist evidence/records/usage against the dead session.
541
837
  if (this.deps.isDisposed()) {
542
838
  const record = this._laneTracker.complete(startedRecord.laneId, {
@@ -563,7 +859,7 @@ export class BackgroundLaneController {
563
859
  });
564
860
  if (record) {
565
861
  appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
566
- // G3: a research lane's product is an evidence bundle, so its terminal record maps to
862
+ // A research lane's product is an evidence bundle, so its terminal record maps to
567
863
  // the evidence_bundle event. Lane outcome only (status/reasonCode/cost) — no findings text.
568
864
  this.deps.emitAutonomyTelemetry({
569
865
  type: AUTONOMY_TELEMETRY_EVENT_TYPES.evidenceBundle,
@@ -606,6 +902,7 @@ export class BackgroundLaneController {
606
902
  }
607
903
  finally {
608
904
  this._isResearchLaneRunning = false;
905
+ deregisterInFlight();
609
906
  }
610
907
  }
611
908
  /**
@@ -637,8 +934,11 @@ export class BackgroundLaneController {
637
934
  this._laneTracker.getActiveCount("worker") >= settings.maxConcurrent + 8) {
638
935
  return { started: false, skipReason: "worker_delegation_queue_full" };
639
936
  }
640
- const record = this._laneTracker.enqueue({ type: "worker" });
937
+ const record = this._laneTracker.enqueue({ type: "worker", goalId: this.deps.getGoalStateSnapshot()?.goalId });
641
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}`));
642
942
  this._scheduleWorkerNotification();
643
943
  return { started: true, record };
644
944
  }
@@ -689,7 +989,8 @@ export class BackgroundLaneController {
689
989
  return { started: false, skipReason: "model_delegation_unsupported" };
690
990
  }
691
991
  this._seedLaneHistory();
692
- const startedRecord = existingRecord ?? this._laneTracker.start({ type: "worker" });
992
+ const startedRecord = existingRecord ??
993
+ this._laneTracker.start({ type: "worker", goalId: this.deps.getGoalStateSnapshot()?.goalId });
693
994
  if (existingRecord)
694
995
  this._laneTracker.markRunning(existingRecord.laneId);
695
996
  onStarted?.(startedRecord);
@@ -737,7 +1038,7 @@ export class BackgroundLaneController {
737
1038
  maxEstimatedUsd: maxUsd,
738
1039
  createdAt: new Date().toISOString(),
739
1040
  };
740
- // G8: worker delegation START. Routing/scope codes + budget only — never the instructions text.
1041
+ // Worker delegation START. Routing/scope codes + budget only — never the instructions text.
741
1042
  this.deps.emitAutonomyTelemetry({
742
1043
  type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerRequest,
743
1044
  timestamp: new Date().toISOString(),
@@ -749,10 +1050,25 @@ export class BackgroundLaneController {
749
1050
  },
750
1051
  });
751
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}`);
752
1058
  try {
753
1059
  let spentUsage;
754
1060
  const toolChangedFiles = new Set();
755
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
+ });
756
1072
  const outcome = await runWorker({
757
1073
  request: workerRequest,
758
1074
  maxUsd,
@@ -762,7 +1078,7 @@ export class BackgroundLaneController {
762
1078
  signal: this._workerDelegationAbort.signal,
763
1079
  // Parent validation must use the same relative-path baseline the runner reports in.
764
1080
  cwd: this.deps.getCwd(),
765
- // Write lane (G2): runner-side action application through the envelope path scope.
1081
+ // Write lane: runner-side action application through the envelope path scope.
766
1082
  applyActions: workerRequest.envelope.capabilities.includes("write_files")
767
1083
  ? (actions) => {
768
1084
  const permitted = actions.filter((action) => allowedActionOps.has(action.op));
@@ -827,7 +1143,7 @@ export class BackgroundLaneController {
827
1143
  catch {
828
1144
  // Execution was attempted; preserve conservative accounting with the lexical path.
829
1145
  }
830
- toolChangedFiles.add(path.relative(this.deps.getCwd(), canonicalPath));
1146
+ toolChangedFiles.add(path.relative(this.deps.getCwd(), canonicalPath).split(path.sep).join("/"));
831
1147
  }
832
1148
  }
833
1149
  }
@@ -840,6 +1156,9 @@ export class BackgroundLaneController {
840
1156
  signal,
841
1157
  // Core/soul/role are all static per configuration — the provider can cache the prefix.
842
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",
843
1162
  });
844
1163
  spentUsage = completion.usage;
845
1164
  return {
@@ -851,7 +1170,11 @@ export class BackgroundLaneController {
851
1170
  };
852
1171
  },
853
1172
  });
854
- // Bug #21 pattern: never persist against a disposed session.
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.
855
1178
  if (this.deps.isDisposed()) {
856
1179
  const record = this._laneTracker.complete(startedRecord.laneId, {
857
1180
  status: "canceled",
@@ -873,7 +1196,7 @@ export class BackgroundLaneController {
873
1196
  if (record) {
874
1197
  this._recordWorkerTerminal(record);
875
1198
  appendLaneRecordSnapshot(this.deps.getSessionManager(), record);
876
- // G3: worker lane terminal record -> worker_result event. Lane outcome only
1199
+ // Worker lane terminal record -> worker_result event. Lane outcome only
877
1200
  // (status/reasonCode/cost) — never the worker's summary/changed-file text.
878
1201
  this.deps.emitAutonomyTelemetry({
879
1202
  type: AUTONOMY_TELEMETRY_EVENT_TYPES.workerResult,
@@ -915,6 +1238,8 @@ export class BackgroundLaneController {
915
1238
  return { started: true, record };
916
1239
  }
917
1240
  finally {
1241
+ this._inFlightWorkerLedgers.delete(startedRecord.laneId);
1242
+ deregisterInFlight();
918
1243
  }
919
1244
  }
920
1245
  /**
@@ -930,69 +1255,93 @@ export class BackgroundLaneController {
930
1255
  if (!resolved)
931
1256
  return { started: false, skipReason: "model_unresolved_or_unauthenticated" };
932
1257
  const capability = this._laneCapabilityProfile(resolved);
933
- const spent = {
934
- input: 0,
935
- output: 0,
936
- cacheRead: 0,
937
- cacheWrite: 0,
938
- totalTokens: 0,
939
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
940
- };
941
- const report = await runModelFitnessProbe({
942
- trials: args.trials,
943
- signal: this._researchLaneAbort.signal,
944
- capacityProbe: resolved.provider === "ollama" && resolved.contextWindow > 0
945
- ? { registeredContextWindow: resolved.contextWindow }
946
- : undefined,
947
- complete: async ({ systemPrompt, userPrompt, signal }) => {
948
- const callStarted = Date.now();
949
- const completion = await this.deps.runIsolatedCompletion({
950
- systemPrompt,
951
- messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
952
- model: resolved,
953
- thinkingLevel: "off",
954
- maxTokens: capability.laneMaxOutputTokens,
955
- signal,
956
- cacheRetention: "short",
957
- });
958
- const callMs = Date.now() - callStarted;
959
- spent.input += completion.usage.input;
960
- spent.output += completion.usage.output;
961
- spent.cacheRead += completion.usage.cacheRead;
962
- spent.cacheWrite += completion.usage.cacheWrite;
963
- spent.totalTokens += completion.usage.totalTokens;
964
- spent.cost.input += completion.usage.cost.input;
965
- spent.cost.output += completion.usage.cost.output;
966
- spent.cost.cacheRead += completion.usage.cost.cacheRead;
967
- spent.cost.cacheWrite += completion.usage.cost.cacheWrite;
968
- spent.cost.total += completion.usage.cost.total;
969
- return {
970
- text: completion.text,
971
- costUsd: completion.usage.cost.total,
972
- stopReason: String(completion.stopReason),
973
- // Wall-clock fallback for tok/s: providers don't expose pure eval time, so the
974
- // measured call time stands in — slightly conservative (includes network/queue).
975
- outputTokens: completion.usage.output,
976
- evalMs: callMs,
977
- };
978
- },
979
- });
980
- if (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {
981
- this.deps.addSpawnedUsage(spent, { label: "model-fitness" });
982
- }
983
- const modelRef = `${resolved.provider}/${resolved.id}`;
984
- // Fitness is a property of a model ON a host — persist the report host-keyed so role
985
- // assignments stay per-machine (a model can await better hardware without being forgotten).
986
- // Best-effort: a disk problem must not fail the probe itself.
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}`);
987
1263
  try {
988
- if (!this.deps.isDisposed()) {
989
- FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);
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 });
990
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 };
991
1341
  }
992
- catch {
993
- // best-effort persistence
1342
+ finally {
1343
+ deregisterInFlight();
994
1344
  }
995
- return { started: true, model: modelRef, report };
996
1345
  }
997
1346
  /** Start queued local workers at the owner session's foreground-idle boundary. */
998
1347
  drainQueuedWorkerDelegations() {
@@ -1001,11 +1350,19 @@ export class BackgroundLaneController {
1001
1350
  this.deps.getSettingsManager().getWorkerDelegationSettings().maxConcurrent)
1002
1351
  break;
1003
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);
1004
1359
  if (!record) {
1005
1360
  this._queuedWorkers.delete(laneId);
1361
+ deregisterQueued?.();
1006
1362
  continue;
1007
1363
  }
1008
1364
  this._queuedWorkers.delete(laneId);
1365
+ deregisterQueued?.();
1009
1366
  const promise = this.runWorkerDelegationOnce(request, undefined, record);
1010
1367
  this._workerPromises.set(laneId, promise);
1011
1368
  void promise.then((outcome) => {