@caupulican/pi-adaptative 0.81.39 → 0.81.40

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 (667) hide show
  1. package/CHANGELOG.md +52 -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 +2 -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 +3 -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 +2 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +9 -0
  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 +19 -2
  23. package/dist/core/agent-paths.d.ts.map +1 -1
  24. package/dist/core/agent-paths.js +67 -4
  25. package/dist/core/agent-paths.js.map +1 -1
  26. package/dist/core/agent-session-runtime.d.ts +52 -8
  27. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  28. package/dist/core/agent-session-runtime.js +397 -79
  29. package/dist/core/agent-session-runtime.js.map +1 -1
  30. package/dist/core/agent-session-services.d.ts +1 -0
  31. package/dist/core/agent-session-services.d.ts.map +1 -1
  32. package/dist/core/agent-session-services.js +1 -0
  33. package/dist/core/agent-session-services.js.map +1 -1
  34. package/dist/core/agent-session.d.ts +71 -136
  35. package/dist/core/agent-session.d.ts.map +1 -1
  36. package/dist/core/agent-session.js +477 -1318
  37. package/dist/core/agent-session.js.map +1 -1
  38. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  39. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  40. package/dist/core/autonomy/approval-gate.js +6 -28
  41. package/dist/core/autonomy/approval-gate.js.map +1 -1
  42. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  43. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  44. package/dist/core/autonomy/bounded-completion.js +1 -1
  45. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  46. package/dist/core/autonomy/contracts.d.ts +20 -12
  47. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  48. package/dist/core/autonomy/contracts.js.map +1 -1
  49. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  50. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  51. package/dist/core/autonomy/foreground-envelope.js +8 -25
  52. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  53. package/dist/core/autonomy/gates.d.ts.map +1 -1
  54. package/dist/core/autonomy/gates.js +8 -10
  55. package/dist/core/autonomy/gates.js.map +1 -1
  56. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  57. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  58. package/dist/core/autonomy/lane-private-paths.js +16 -0
  59. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  60. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  61. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  62. package/dist/core/autonomy/lane-tool-surface.js +46 -8
  63. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  64. package/dist/core/autonomy/lane-tracker.d.ts +14 -0
  65. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  66. package/dist/core/autonomy/lane-tracker.js +38 -0
  67. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  68. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  69. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  70. package/dist/core/autonomy/risk-assessment.js +1 -123
  71. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  72. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  73. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  74. package/dist/core/autonomy/session-lane-record.js +16 -29
  75. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  76. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  77. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  78. package/dist/core/autonomy/telemetry-events.js +1 -1
  79. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  80. package/dist/core/autonomy-telemetry.d.ts +7 -7
  81. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  82. package/dist/core/autonomy-telemetry.js +9 -9
  83. package/dist/core/autonomy-telemetry.js.map +1 -1
  84. package/dist/core/background-lane-controller.d.ts +54 -236
  85. package/dist/core/background-lane-controller.d.ts.map +1 -1
  86. package/dist/core/background-lane-controller.js +140 -1273
  87. package/dist/core/background-lane-controller.js.map +1 -1
  88. package/dist/core/capability-contract.d.ts +4 -0
  89. package/dist/core/capability-contract.d.ts.map +1 -0
  90. package/dist/core/capability-contract.js +28 -0
  91. package/dist/core/capability-contract.js.map +1 -0
  92. package/dist/core/compaction-controller.d.ts +90 -0
  93. package/dist/core/compaction-controller.d.ts.map +1 -0
  94. package/dist/core/compaction-controller.js +452 -0
  95. package/dist/core/compaction-controller.js.map +1 -0
  96. package/dist/core/compaction-support.d.ts +12 -11
  97. package/dist/core/compaction-support.d.ts.map +1 -1
  98. package/dist/core/compaction-support.js.map +1 -1
  99. package/dist/core/context/context-artifacts.d.ts +6 -2
  100. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  101. package/dist/core/context/context-artifacts.js +34 -2
  102. package/dist/core/context/context-artifacts.js.map +1 -1
  103. package/dist/core/context/context-store-retention.d.ts +8 -2
  104. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  105. package/dist/core/context/context-store-retention.js +158 -35
  106. package/dist/core/context/context-store-retention.js.map +1 -1
  107. package/dist/core/context/okf-memory.d.ts.map +1 -1
  108. package/dist/core/context/okf-memory.js +9 -11
  109. package/dist/core/context/okf-memory.js.map +1 -1
  110. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  111. package/dist/core/context/sqlite-runtime-index.js +6 -8
  112. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  113. package/dist/core/context-gc.d.ts +3 -0
  114. package/dist/core/context-gc.d.ts.map +1 -1
  115. package/dist/core/context-gc.js +10 -5
  116. package/dist/core/context-gc.js.map +1 -1
  117. package/dist/core/context-pipeline.d.ts.map +1 -1
  118. package/dist/core/context-pipeline.js +9 -4
  119. package/dist/core/context-pipeline.js.map +1 -1
  120. package/dist/core/default-tool-surface.d.ts.map +1 -1
  121. package/dist/core/default-tool-surface.js +1 -0
  122. package/dist/core/default-tool-surface.js.map +1 -1
  123. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  124. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  125. package/dist/core/delegation/managed-lane-controller.js +217 -0
  126. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  127. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  128. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  129. package/dist/core/delegation/session-worker-claim.js +98 -0
  130. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  131. package/dist/core/delegation/worker-actions.d.ts +7 -5
  132. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  133. package/dist/core/delegation/worker-actions.js +20 -4
  134. package/dist/core/delegation/worker-actions.js.map +1 -1
  135. package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
  136. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  137. package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
  138. package/dist/core/delegation/worker-claim.js.map +1 -0
  139. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  140. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  141. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  142. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  143. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  144. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  145. package/dist/core/delegation/worker-delegation-request.js +2 -0
  146. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  147. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  148. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  149. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  150. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  151. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  152. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  153. package/dist/core/delegation/worker-execution-policy.js +160 -0
  154. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  155. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  156. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  157. package/dist/core/delegation/worker-lane-projection.js +100 -0
  158. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  159. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  160. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  161. package/dist/core/delegation/worker-lifecycle.js +339 -0
  162. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  163. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  164. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  165. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  166. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  167. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  168. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  169. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  170. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  171. package/dist/core/delegation/worker-runner.d.ts +25 -14
  172. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  173. package/dist/core/delegation/worker-runner.js +122 -53
  174. package/dist/core/delegation/worker-runner.js.map +1 -1
  175. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  176. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  177. package/dist/core/delegation/worker-task-label.js +11 -0
  178. package/dist/core/delegation/worker-task-label.js.map +1 -0
  179. package/dist/core/doctor.d.ts +8 -0
  180. package/dist/core/doctor.d.ts.map +1 -1
  181. package/dist/core/doctor.js +32 -1
  182. package/dist/core/doctor.js.map +1 -1
  183. package/dist/core/extensions/index.d.ts +1 -1
  184. package/dist/core/extensions/index.d.ts.map +1 -1
  185. package/dist/core/extensions/index.js.map +1 -1
  186. package/dist/core/extensions/loader.d.ts +5 -1
  187. package/dist/core/extensions/loader.d.ts.map +1 -1
  188. package/dist/core/extensions/loader.js +50 -15
  189. package/dist/core/extensions/loader.js.map +1 -1
  190. package/dist/core/extensions/runner.d.ts.map +1 -1
  191. package/dist/core/extensions/runner.js +6 -0
  192. package/dist/core/extensions/runner.js.map +1 -1
  193. package/dist/core/extensions/storage.d.ts +8 -0
  194. package/dist/core/extensions/storage.d.ts.map +1 -0
  195. package/dist/core/extensions/storage.js +28 -0
  196. package/dist/core/extensions/storage.js.map +1 -0
  197. package/dist/core/extensions/types.d.ts +70 -21
  198. package/dist/core/extensions/types.d.ts.map +1 -1
  199. package/dist/core/extensions/types.js.map +1 -1
  200. package/dist/core/failure-corpus.d.ts +1 -15
  201. package/dist/core/failure-corpus.d.ts.map +1 -1
  202. package/dist/core/failure-corpus.js +9 -37
  203. package/dist/core/failure-corpus.js.map +1 -1
  204. package/dist/core/foreground-recovery-controller.d.ts +52 -0
  205. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  206. package/dist/core/foreground-recovery-controller.js +111 -0
  207. package/dist/core/foreground-recovery-controller.js.map +1 -0
  208. package/dist/core/gateways/channel-provider.d.ts +3 -0
  209. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  210. package/dist/core/gateways/channel-provider.js +31 -6
  211. package/dist/core/gateways/channel-provider.js.map +1 -1
  212. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  213. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  214. package/dist/core/goals/goal-acceptance.js +25 -0
  215. package/dist/core/goals/goal-acceptance.js.map +1 -0
  216. package/dist/core/goals/goal-auto-continue-controller.d.ts +27 -0
  217. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  218. package/dist/core/goals/goal-auto-continue-controller.js +93 -0
  219. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  220. package/dist/core/goals/goal-continuation-controller.d.ts +1 -1
  221. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  222. package/dist/core/goals/goal-continuation-controller.js +10 -0
  223. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  224. package/dist/core/goals/goal-continuation-prompt.d.ts +1 -1
  225. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  226. package/dist/core/goals/goal-continuation-prompt.js +6 -6
  227. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  228. package/dist/core/goals/goal-lifecycle.d.ts +20 -0
  229. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  230. package/dist/core/goals/goal-lifecycle.js +17 -0
  231. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  232. package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
  233. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  234. package/dist/core/goals/goal-runtime-snapshot.js +10 -8
  235. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  236. package/dist/core/goals/goal-state.d.ts +1 -0
  237. package/dist/core/goals/goal-state.d.ts.map +1 -1
  238. package/dist/core/goals/goal-state.js +7 -10
  239. package/dist/core/goals/goal-state.js.map +1 -1
  240. package/dist/core/goals/goal-tool-core.d.ts +8 -6
  241. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  242. package/dist/core/goals/goal-tool-core.js +11 -41
  243. package/dist/core/goals/goal-tool-core.js.map +1 -1
  244. package/dist/core/goals/session-goal-state.d.ts +2 -4
  245. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  246. package/dist/core/goals/session-goal-state.js +10 -33
  247. package/dist/core/goals/session-goal-state.js.map +1 -1
  248. package/dist/core/human-input.d.ts +100 -0
  249. package/dist/core/human-input.d.ts.map +1 -0
  250. package/dist/core/human-input.js +362 -0
  251. package/dist/core/human-input.js.map +1 -0
  252. package/dist/core/index.d.ts +9 -1
  253. package/dist/core/index.d.ts.map +1 -1
  254. package/dist/core/index.js +9 -1
  255. package/dist/core/index.js.map +1 -1
  256. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  257. package/dist/core/install-telemetry.d.ts.map +1 -0
  258. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  259. package/dist/core/install-telemetry.js.map +1 -0
  260. package/dist/core/keybindings.d.ts +17 -1
  261. package/dist/core/keybindings.d.ts.map +1 -1
  262. package/dist/core/keybindings.js +24 -6
  263. package/dist/core/keybindings.js.map +1 -1
  264. package/dist/core/learning/learning-audit.d.ts +2 -4
  265. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  266. package/dist/core/learning/learning-audit.js +9 -29
  267. package/dist/core/learning/learning-audit.js.map +1 -1
  268. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  269. package/dist/core/learning/learning-gate.js +1 -6
  270. package/dist/core/learning/learning-gate.js.map +1 -1
  271. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  272. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  273. package/dist/core/learning/session-learning-decision.js +9 -29
  274. package/dist/core/learning/session-learning-decision.js.map +1 -1
  275. package/dist/core/memory-controller.d.ts.map +1 -1
  276. package/dist/core/memory-controller.js +4 -4
  277. package/dist/core/memory-controller.js.map +1 -1
  278. package/dist/core/model-capability.d.ts.map +1 -1
  279. package/dist/core/model-capability.js +1 -0
  280. package/dist/core/model-capability.js.map +1 -1
  281. package/dist/core/model-resolver.d.ts +1 -1
  282. package/dist/core/model-resolver.d.ts.map +1 -1
  283. package/dist/core/model-resolver.js +6 -9
  284. package/dist/core/model-resolver.js.map +1 -1
  285. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  286. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  287. package/dist/core/model-router/intent-classifier.js +1 -156
  288. package/dist/core/model-router/intent-classifier.js.map +1 -1
  289. package/dist/core/model-router-controller.d.ts.map +1 -1
  290. package/dist/core/model-router-controller.js +2 -2
  291. package/dist/core/model-router-controller.js.map +1 -1
  292. package/dist/core/model-selection-controller.d.ts +4 -4
  293. package/dist/core/model-selection-controller.d.ts.map +1 -1
  294. package/dist/core/model-selection-controller.js.map +1 -1
  295. package/dist/core/model-tool-protocol.d.ts +23 -0
  296. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  297. package/dist/core/model-tool-protocol.js +43 -0
  298. package/dist/core/model-tool-protocol.js.map +1 -0
  299. package/dist/core/models/adaptation-store.d.ts +4 -6
  300. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  301. package/dist/core/models/adaptation-store.js +95 -83
  302. package/dist/core/models/adaptation-store.js.map +1 -1
  303. package/dist/core/models/fitness-store.d.ts +2 -12
  304. package/dist/core/models/fitness-store.d.ts.map +1 -1
  305. package/dist/core/models/fitness-store.js +84 -57
  306. package/dist/core/models/fitness-store.js.map +1 -1
  307. package/dist/core/models/host-state-store.d.ts +34 -0
  308. package/dist/core/models/host-state-store.d.ts.map +1 -0
  309. package/dist/core/models/host-state-store.js +86 -0
  310. package/dist/core/models/host-state-store.js.map +1 -0
  311. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  312. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  313. package/dist/core/orchestration/agent-resume.js +90 -0
  314. package/dist/core/orchestration/agent-resume.js.map +1 -0
  315. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  316. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  317. package/dist/core/orchestration/capability-gateway.js +152 -0
  318. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  319. package/dist/core/orchestration/contracts.d.ts +343 -0
  320. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  321. package/dist/core/orchestration/contracts.js +135 -0
  322. package/dist/core/orchestration/contracts.js.map +1 -0
  323. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  324. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  325. package/dist/core/orchestration/delegation-ledger.js +197 -0
  326. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  327. package/dist/core/orchestration/event-store.d.ts +83 -0
  328. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  329. package/dist/core/orchestration/event-store.js +560 -0
  330. package/dist/core/orchestration/event-store.js.map +1 -0
  331. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  332. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  333. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  334. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  335. package/dist/core/orchestration/model-binding.d.ts +15 -0
  336. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  337. package/dist/core/orchestration/model-binding.js +29 -0
  338. package/dist/core/orchestration/model-binding.js.map +1 -0
  339. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  340. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  341. package/dist/core/orchestration/policy-compiler.js +191 -0
  342. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  343. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  344. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  345. package/dist/core/orchestration/policy-gate.js +24 -0
  346. package/dist/core/orchestration/policy-gate.js.map +1 -0
  347. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  348. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  349. package/dist/core/orchestration/profile-registry.js +393 -0
  350. package/dist/core/orchestration/profile-registry.js.map +1 -0
  351. package/dist/core/orchestration/profile-store.d.ts +31 -0
  352. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  353. package/dist/core/orchestration/profile-store.js +136 -0
  354. package/dist/core/orchestration/profile-store.js.map +1 -0
  355. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  356. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  357. package/dist/core/orchestration/risk-budget.js +48 -0
  358. package/dist/core/orchestration/risk-budget.js.map +1 -0
  359. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  360. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  361. package/dist/core/orchestration/task-runtime.js +1600 -0
  362. package/dist/core/orchestration/task-runtime.js.map +1 -0
  363. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  364. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  365. package/dist/core/orchestration/work-state-projection.js +116 -0
  366. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  367. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  368. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  369. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  370. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  371. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  372. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  373. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  374. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  375. package/dist/core/process-identity.d.ts +11 -0
  376. package/dist/core/process-identity.d.ts.map +1 -0
  377. package/dist/core/process-identity.js +26 -0
  378. package/dist/core/process-identity.js.map +1 -0
  379. package/dist/core/process-matrix/codes.d.ts +14 -3
  380. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  381. package/dist/core/process-matrix/codes.js.map +1 -1
  382. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  383. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  384. package/dist/core/process-matrix/resume-launcher.js +62 -0
  385. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  386. package/dist/core/process-matrix/runtime.d.ts +37 -22
  387. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  388. package/dist/core/process-matrix/runtime.js +399 -76
  389. package/dist/core/process-matrix/runtime.js.map +1 -1
  390. package/dist/core/process-matrix/store.d.ts +5 -2
  391. package/dist/core/process-matrix/store.d.ts.map +1 -1
  392. package/dist/core/process-matrix/store.js +123 -14
  393. package/dist/core/process-matrix/store.js.map +1 -1
  394. package/dist/core/process-matrix/supervisor.d.ts +10 -7
  395. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  396. package/dist/core/process-matrix/supervisor.js +45 -14
  397. package/dist/core/process-matrix/supervisor.js.map +1 -1
  398. package/dist/core/profile-registry.d.ts.map +1 -1
  399. package/dist/core/profile-registry.js +6 -8
  400. package/dist/core/profile-registry.js.map +1 -1
  401. package/dist/core/reflection-controller.d.ts +4 -4
  402. package/dist/core/reflection-controller.d.ts.map +1 -1
  403. package/dist/core/reflection-controller.js +2 -1
  404. package/dist/core/reflection-controller.js.map +1 -1
  405. package/dist/core/reload-blockers.d.ts.map +1 -1
  406. package/dist/core/reload-blockers.js +6 -8
  407. package/dist/core/reload-blockers.js.map +1 -1
  408. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  409. package/dist/core/research/evidence-bundle.js +1 -6
  410. package/dist/core/research/evidence-bundle.js.map +1 -1
  411. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  412. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  413. package/dist/core/research/lane-model-resolver.js +65 -0
  414. package/dist/core/research/lane-model-resolver.js.map +1 -0
  415. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  416. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  417. package/dist/core/research/model-fitness-controller.js +106 -0
  418. package/dist/core/research/model-fitness-controller.js.map +1 -0
  419. package/dist/core/research/model-fitness.d.ts +1 -1
  420. package/dist/core/research/model-fitness.d.ts.map +1 -1
  421. package/dist/core/research/model-fitness.js +4 -4
  422. package/dist/core/research/model-fitness.js.map +1 -1
  423. package/dist/core/research/research-gate.d.ts.map +1 -1
  424. package/dist/core/research/research-gate.js +7 -7
  425. package/dist/core/research/research-gate.js.map +1 -1
  426. package/dist/core/research/research-lane-controller.d.ts +62 -0
  427. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  428. package/dist/core/research/research-lane-controller.js +292 -0
  429. package/dist/core/research/research-lane-controller.js.map +1 -0
  430. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  431. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  432. package/dist/core/research/session-evidence-bundle.js +10 -46
  433. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  434. package/dist/core/resource-loader.d.ts.map +1 -1
  435. package/dist/core/resource-loader.js +7 -2
  436. package/dist/core/resource-loader.js.map +1 -1
  437. package/dist/core/risk-classifier.d.ts +6 -0
  438. package/dist/core/risk-classifier.d.ts.map +1 -0
  439. package/dist/core/risk-classifier.js +225 -0
  440. package/dist/core/risk-classifier.js.map +1 -0
  441. package/dist/core/runtime-builder.d.ts +26 -20
  442. package/dist/core/runtime-builder.d.ts.map +1 -1
  443. package/dist/core/runtime-builder.js +237 -178
  444. package/dist/core/runtime-builder.js.map +1 -1
  445. package/dist/core/sdk.d.ts +6 -3
  446. package/dist/core/sdk.d.ts.map +1 -1
  447. package/dist/core/sdk.js +61 -24
  448. package/dist/core/sdk.js.map +1 -1
  449. package/dist/core/session-analytics.d.ts.map +1 -1
  450. package/dist/core/session-analytics.js +28 -1
  451. package/dist/core/session-analytics.js.map +1 -1
  452. package/dist/core/session-image-store.d.ts +33 -0
  453. package/dist/core/session-image-store.d.ts.map +1 -0
  454. package/dist/core/session-image-store.js +283 -0
  455. package/dist/core/session-image-store.js.map +1 -0
  456. package/dist/core/session-role.d.ts +6 -4
  457. package/dist/core/session-role.d.ts.map +1 -1
  458. package/dist/core/session-role.js +10 -4
  459. package/dist/core/session-role.js.map +1 -1
  460. package/dist/core/session-snapshot.d.ts +34 -0
  461. package/dist/core/session-snapshot.d.ts.map +1 -0
  462. package/dist/core/session-snapshot.js +68 -0
  463. package/dist/core/session-snapshot.js.map +1 -0
  464. package/dist/core/session-supervision-runtime.d.ts +31 -0
  465. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  466. package/dist/core/session-supervision-runtime.js +97 -0
  467. package/dist/core/session-supervision-runtime.js.map +1 -0
  468. package/dist/core/settings-manager.d.ts +9 -4
  469. package/dist/core/settings-manager.d.ts.map +1 -1
  470. package/dist/core/settings-manager.js +80 -28
  471. package/dist/core/settings-manager.js.map +1 -1
  472. package/dist/core/tasks/session-task-state.d.ts +2 -4
  473. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  474. package/dist/core/tasks/session-task-state.js +10 -28
  475. package/dist/core/tasks/session-task-state.js.map +1 -1
  476. package/dist/core/tasks/task-projection.d.ts +20 -0
  477. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  478. package/dist/core/tasks/task-projection.js +47 -0
  479. package/dist/core/tasks/task-projection.js.map +1 -0
  480. package/dist/core/tasks/task-state.d.ts +4 -0
  481. package/dist/core/tasks/task-state.d.ts.map +1 -1
  482. package/dist/core/tasks/task-state.js +28 -11
  483. package/dist/core/tasks/task-state.js.map +1 -1
  484. package/dist/core/tool-capability-policy.d.ts +13 -0
  485. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  486. package/dist/core/tool-capability-policy.js +85 -0
  487. package/dist/core/tool-capability-policy.js.map +1 -0
  488. package/dist/core/tool-protocol-controller.d.ts +91 -0
  489. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  490. package/dist/core/tool-protocol-controller.js +512 -0
  491. package/dist/core/tool-protocol-controller.js.map +1 -0
  492. package/dist/core/tool-recovery-log-records.d.ts +2 -3
  493. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  494. package/dist/core/tool-recovery-log-records.js +9 -35
  495. package/dist/core/tool-recovery-log-records.js.map +1 -1
  496. package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
  497. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  498. package/dist/core/tool-selection/tool-performance-store.js +97 -138
  499. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  500. package/dist/core/tools/ask-question.d.ts +124 -0
  501. package/dist/core/tools/ask-question.d.ts.map +1 -0
  502. package/dist/core/tools/ask-question.js +693 -0
  503. package/dist/core/tools/ask-question.js.map +1 -0
  504. package/dist/core/tools/delegate-status.d.ts +31 -3
  505. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  506. package/dist/core/tools/delegate-status.js +149 -29
  507. package/dist/core/tools/delegate-status.js.map +1 -1
  508. package/dist/core/tools/delegate.d.ts +15 -13
  509. package/dist/core/tools/delegate.d.ts.map +1 -1
  510. package/dist/core/tools/delegate.js +108 -23
  511. package/dist/core/tools/delegate.js.map +1 -1
  512. package/dist/core/tools/extensionify.d.ts.map +1 -1
  513. package/dist/core/tools/extensionify.js +1 -0
  514. package/dist/core/tools/extensionify.js.map +1 -1
  515. package/dist/core/tools/goal.d.ts +5 -5
  516. package/dist/core/tools/goal.d.ts.map +1 -1
  517. package/dist/core/tools/goal.js +10 -10
  518. package/dist/core/tools/goal.js.map +1 -1
  519. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  520. package/dist/core/tools/model-fitness.js +2 -2
  521. package/dist/core/tools/model-fitness.js.map +1 -1
  522. package/dist/core/tools/orchestration-panel.d.ts +43 -0
  523. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  524. package/dist/core/tools/orchestration-panel.js +168 -0
  525. package/dist/core/tools/orchestration-panel.js.map +1 -0
  526. package/dist/core/tools/run-process.d.ts +26 -0
  527. package/dist/core/tools/run-process.d.ts.map +1 -0
  528. package/dist/core/tools/run-process.js +138 -0
  529. package/dist/core/tools/run-process.js.map +1 -0
  530. package/dist/core/tools/task-steps.d.ts +2 -0
  531. package/dist/core/tools/task-steps.d.ts.map +1 -1
  532. package/dist/core/tools/task-steps.js +102 -0
  533. package/dist/core/tools/task-steps.js.map +1 -1
  534. package/dist/core/tools/tmux-dispatch.d.ts +3 -5
  535. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  536. package/dist/core/tools/tmux-dispatch.js +4 -4
  537. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  538. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  539. package/dist/core/tools/windows-shell-engine.js +4 -6
  540. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  541. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  542. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  543. package/dist/core/util/bounded-jsonl.js +75 -0
  544. package/dist/core/util/bounded-jsonl.js.map +1 -0
  545. package/dist/core/util/value-guards.d.ts +5 -0
  546. package/dist/core/util/value-guards.d.ts.map +1 -0
  547. package/dist/core/util/value-guards.js +12 -0
  548. package/dist/core/util/value-guards.js.map +1 -0
  549. package/dist/core/worktree-sync/store.d.ts +3 -3
  550. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  551. package/dist/core/worktree-sync/store.js +10 -5
  552. package/dist/core/worktree-sync/store.js.map +1 -1
  553. package/dist/index.d.ts +13 -3
  554. package/dist/index.d.ts.map +1 -1
  555. package/dist/index.js +12 -2
  556. package/dist/index.js.map +1 -1
  557. package/dist/main.d.ts.map +1 -1
  558. package/dist/main.js +128 -44
  559. package/dist/main.js.map +1 -1
  560. package/dist/migrations.d.ts +4 -6
  561. package/dist/migrations.d.ts.map +1 -1
  562. package/dist/migrations.js +186 -28
  563. package/dist/migrations.js.map +1 -1
  564. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  565. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  566. package/dist/modes/interactive/clipboard-input.js +44 -6
  567. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  568. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  569. package/dist/modes/interactive/components/settings-selector.js +2 -2
  570. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  571. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  572. package/dist/modes/interactive/config-backup.js +5 -4
  573. package/dist/modes/interactive/config-backup.js.map +1 -1
  574. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  575. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  576. package/dist/modes/interactive/extension-ui-host.js +76 -15
  577. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  578. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  579. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  580. package/dist/modes/interactive/interactive-mode.js +63 -1
  581. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  582. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  583. package/dist/modes/interactive/key-handlers.js +1 -1
  584. package/dist/modes/interactive/key-handlers.js.map +1 -1
  585. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  586. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  587. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  588. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  589. package/dist/modes/interactive/report-commands.js +21 -0
  590. package/dist/modes/interactive/report-commands.js.map +1 -1
  591. package/dist/modes/interactive/session-flow-commands.d.ts +17 -2
  592. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  593. package/dist/modes/interactive/session-flow-commands.js +50 -17
  594. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  595. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  596. package/dist/modes/interactive/session-io-commands.js +16 -6
  597. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  598. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  599. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  600. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  601. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  602. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  603. package/dist/modes/interactive/startup-checks.js +1 -1
  604. package/dist/modes/interactive/startup-checks.js.map +1 -1
  605. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  606. package/dist/modes/rpc/rpc-mode.js +82 -23
  607. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  608. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  609. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  610. package/dist/modes/rpc/rpc-types.js +138 -1
  611. package/dist/modes/rpc/rpc-types.js.map +1 -1
  612. package/dist/utils/clipboard-image.d.ts.map +1 -1
  613. package/dist/utils/clipboard-image.js +2 -13
  614. package/dist/utils/clipboard-image.js.map +1 -1
  615. package/dist/utils/clipboard-native.d.ts +1 -0
  616. package/dist/utils/clipboard-native.d.ts.map +1 -1
  617. package/dist/utils/clipboard-native.js.map +1 -1
  618. package/dist/utils/clipboard.d.ts +1 -0
  619. package/dist/utils/clipboard.d.ts.map +1 -1
  620. package/dist/utils/clipboard.js +52 -1
  621. package/dist/utils/clipboard.js.map +1 -1
  622. package/dist/utils/platform.d.ts +3 -0
  623. package/dist/utils/platform.d.ts.map +1 -0
  624. package/dist/utils/platform.js +8 -0
  625. package/dist/utils/platform.js.map +1 -0
  626. package/dist/utils/work-directory.d.ts +11 -0
  627. package/dist/utils/work-directory.d.ts.map +1 -1
  628. package/dist/utils/work-directory.js +30 -9
  629. package/dist/utils/work-directory.js.map +1 -1
  630. package/docs/UI_POLISH_ORCHESTRATION.md +44 -0
  631. package/docs/UI_QUALITY_ORCHESTRATION.md +30 -0
  632. package/docs/docs.json +4 -0
  633. package/docs/extensions.md +62 -2
  634. package/docs/harness-architecture.md +156 -0
  635. package/docs/keybindings.md +11 -1
  636. package/docs/process-matrix.md +59 -26
  637. package/docs/rpc.md +45 -2
  638. package/docs/sessions.md +15 -0
  639. package/docs/settings.md +125 -11
  640. package/docs/task-steps.md +8 -0
  641. package/docs/telemetry.md +19 -0
  642. package/docs/tmux-agent-manager.md +10 -3
  643. package/docs/ui-reference/README.md +9 -0
  644. package/docs/ui-reference/orchestration-after.txt +7 -0
  645. package/docs/ui-reference/orchestration-before.txt +7 -0
  646. package/docs/ui-reference/orchestration-reference.txt +6 -0
  647. package/docs/usage.md +14 -2
  648. package/docs/work-directory.md +19 -8
  649. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  650. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  651. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  652. package/examples/extensions/question.ts +34 -245
  653. package/examples/extensions/questionnaire.ts +41 -407
  654. package/examples/extensions/sandbox/package-lock.json +2 -2
  655. package/examples/extensions/sandbox/package.json +1 -1
  656. package/examples/extensions/with-deps/package-lock.json +2 -2
  657. package/examples/extensions/with-deps/package.json +1 -1
  658. package/npm-shrinkwrap.json +12 -12
  659. package/package.json +4 -4
  660. package/dist/core/delegation/session-worker-result.d.ts +0 -46
  661. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  662. package/dist/core/delegation/session-worker-result.js +0 -113
  663. package/dist/core/delegation/session-worker-result.js.map +0 -1
  664. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  665. package/dist/core/delegation/worker-result.js.map +0 -1
  666. package/dist/core/telemetry.d.ts.map +0 -1
  667. package/dist/core/telemetry.js.map +0 -1
@@ -9,14 +9,12 @@ import { existsSync, readFileSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { getAgentDir } from "../config.js";
11
11
  import { getProcessWorkRun } from "../utils/work-directory.js";
12
+ import { isRecordObject } from "./util/value-guards.js";
12
13
  export const ACTIVE_TURN_TTL_MS = 5 * 60_000;
13
14
  export const AUTO_RELOAD_COORDINATOR_TTL_MS = 10 * 60_000;
14
15
  export function getReloadCoordinationDir(agentDir = getAgentDir()) {
15
16
  return getProcessWorkRun(agentDir, "coordination", "reload", "state").path;
16
17
  }
17
- function isRecord(value) {
18
- return value !== null && typeof value === "object" && !Array.isArray(value);
19
- }
20
18
  function readJsonFile(file) {
21
19
  try {
22
20
  if (!existsSync(file))
@@ -39,7 +37,7 @@ function booleanValue(value) {
39
37
  return typeof value === "boolean" ? value : undefined;
40
38
  }
41
39
  function parseSession(value) {
42
- if (!isRecord(value))
40
+ if (!isRecordObject(value))
43
41
  return undefined;
44
42
  return {
45
43
  pid: numberValue(value.pid),
@@ -100,7 +98,7 @@ function activeTurnBlockers(options) {
100
98
  const ttl = options.activeTurnTtlMs ?? ACTIVE_TURN_TTL_MS;
101
99
  const isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;
102
100
  const registry = readJsonFile(join(getReloadCoordinationDir(agentDir), "active-turns.json"));
103
- if (!isRecord(registry) || !isRecord(registry.sessions))
101
+ if (!isRecordObject(registry) || !isRecordObject(registry.sessions))
104
102
  return [];
105
103
  const blockers = [];
106
104
  for (const [key, rawSession] of Object.entries(registry.sessions)) {
@@ -123,18 +121,18 @@ function coordinatorBlockers(options) {
123
121
  const ttl = options.coordinatorTtlMs ?? AUTO_RELOAD_COORDINATOR_TTL_MS;
124
122
  const isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;
125
123
  const coordinator = readJsonFile(join(getReloadCoordinationDir(agentDir), "auto-reload-state.json"));
126
- if (!isRecord(coordinator) || !isRecord(coordinator.changes))
124
+ if (!isRecordObject(coordinator) || !isRecordObject(coordinator.changes))
127
125
  return { blockers: [], reason: "" };
128
126
  const blockers = [];
129
127
  let reason = "";
130
128
  for (const rawChange of Object.values(coordinator.changes)) {
131
- if (!isRecord(rawChange))
129
+ if (!isRecordObject(rawChange))
132
130
  continue;
133
131
  const firstSeenAt = numberValue(rawChange.firstSeenAt);
134
132
  if (firstSeenAt === undefined || now - firstSeenAt > ttl)
135
133
  continue;
136
134
  reason ||= stringValue(rawChange.reason) ?? "";
137
- if (!isRecord(rawChange.sessions))
135
+ if (!isRecordObject(rawChange.sessions))
138
136
  continue;
139
137
  for (const [key, rawSession] of Object.entries(rawChange.sessions)) {
140
138
  const session = parseSession(rawSession);
@@ -1 +1 @@
1
- {"version":3,"file":"reload-blockers.js","sourceRoot":"","sources":["../../src/core/reload-blockers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reload/live-op blocker sources for THIS process's reload gate (`RuntimeBuilder`, see\n * runtime-builder.ts): cross-process peer/coordinator sessions (file-backed, below) AND the\n * in-process quiesce registry (`registerInFlightWork`/`getInFlightWorkUnits`) that tracks background\n * lanes, context-scout runs, and isolated completions running in THIS process. The gate reads both;\n * `getPendingReloadBlockers` (cross-process) also backs the `/autonomy` status text.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../config.ts\";\nimport { getProcessWorkRun } from \"../utils/work-directory.ts\";\n\nexport const ACTIVE_TURN_TTL_MS = 5 * 60_000;\nexport const AUTO_RELOAD_COORDINATOR_TTL_MS = 10 * 60_000;\n\nexport function getReloadCoordinationDir(agentDir: string = getAgentDir()): string {\n\treturn getProcessWorkRun(agentDir, \"coordination\", \"reload\", \"state\").path;\n}\n\nexport interface ReloadSessionRecord {\n\tkey: string;\n\tsource: \"active-turn\" | \"coordinator\";\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n\treason?: string;\n}\n\nexport interface PendingReloadBlockers {\n\tpending: boolean;\n\treason: string;\n\tblockers: ReloadSessionRecord[];\n\tdescriptions: string[];\n}\n\nexport interface ReloadBlockerOptions {\n\tagentDir?: string;\n\tnow?: number;\n\townKey?: string;\n\townPid?: number;\n\townSessionId?: string;\n\townSessionFile?: string;\n\tactiveTurnTtlMs?: number;\n\tcoordinatorTtlMs?: number;\n\t/** Auto Learn workers are memory-first, short-lived, and should not block foreground reload/adaptive work by default. */\n\tincludeAutoLearnSessions?: boolean;\n\tisProcessAlive?: (pid: number | undefined) => boolean;\n}\n\ninterface ParsedSession {\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction readJsonFile(file: string): unknown {\n\ttry {\n\t\tif (!existsSync(file)) return undefined;\n\t\treturn JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction numberValue(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\treturn undefined;\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n\treturn typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction parseSession(value: unknown): ParsedSession | undefined {\n\tif (!isRecord(value)) return undefined;\n\treturn {\n\t\tpid: numberValue(value.pid),\n\t\tsessionId: stringValue(value.sessionId),\n\t\tsessionFile: stringValue(value.sessionFile),\n\t\tcwd: stringValue(value.cwd),\n\t\tactive: booleanValue(value.active),\n\t\tupdatedAt: numberValue(value.updatedAt),\n\t\tseenAt: numberValue(value.seenAt),\n\t\treloadedAt: numberValue(value.reloadedAt),\n\t};\n}\n\nexport function isReloadSessionProcessAlive(pid: number | undefined): boolean {\n\tif (pid === undefined || !Number.isFinite(pid) || pid <= 0) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code =\n\t\t\terror && typeof error === \"object\" && \"code\" in error ? String((error as { code?: unknown }).code) : \"\";\n\t\treturn code === \"EPERM\";\n\t}\n}\n\nfunction isOwnSession(key: string, session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\tif (options.ownKey && key === options.ownKey) return true;\n\tif (options.ownPid !== undefined && session.pid === options.ownPid) return true;\n\tif (options.ownSessionId && session.sessionId === options.ownSessionId) return true;\n\tif (options.ownSessionFile && session.sessionFile === options.ownSessionFile) return true;\n\treturn false;\n}\n\nfunction isAutoLearnSession(session: ParsedSession): boolean {\n\treturn !!session.sessionId?.startsWith(\"auto-learn-\");\n}\n\nfunction shouldIgnoreSession(session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\treturn options.includeAutoLearnSessions !== true && isAutoLearnSession(session);\n}\n\nfunction addBlocker(blockers: Map<string, ReloadSessionRecord>, record: ReloadSessionRecord): void {\n\tconst identity = [\n\t\trecord.key,\n\t\trecord.pid ?? \"\",\n\t\trecord.sessionId ?? \"\",\n\t\trecord.sessionFile ?? \"\",\n\t\trecord.cwd ?? \"\",\n\t].join(\"\\0\");\n\tconst existing = blockers.get(identity);\n\tif (!existing || (existing.source === \"coordinator\" && record.source === \"active-turn\")) {\n\t\tblockers.set(identity, record);\n\t}\n}\n\nfunction activeTurnBlockers(options: ReloadBlockerOptions): ReloadSessionRecord[] {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.activeTurnTtlMs ?? ACTIVE_TURN_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst registry = readJsonFile(join(getReloadCoordinationDir(agentDir), \"active-turns.json\"));\n\tif (!isRecord(registry) || !isRecord(registry.sessions)) return [];\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tfor (const [key, rawSession] of Object.entries(registry.sessions)) {\n\t\tconst session = parseSession(rawSession);\n\t\tif (!session?.active) continue;\n\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\tif (session.updatedAt === undefined || now - session.updatedAt > ttl) continue;\n\t\tif (!isAlive(session.pid)) continue;\n\t\tblockers.push({ key, source: \"active-turn\", ...session });\n\t}\n\treturn blockers;\n}\n\nfunction coordinatorBlockers(options: ReloadBlockerOptions): { blockers: ReloadSessionRecord[]; reason: string } {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.coordinatorTtlMs ?? AUTO_RELOAD_COORDINATOR_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst coordinator = readJsonFile(join(getReloadCoordinationDir(agentDir), \"auto-reload-state.json\"));\n\tif (!isRecord(coordinator) || !isRecord(coordinator.changes)) return { blockers: [], reason: \"\" };\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tlet reason = \"\";\n\tfor (const rawChange of Object.values(coordinator.changes)) {\n\t\tif (!isRecord(rawChange)) continue;\n\t\tconst firstSeenAt = numberValue(rawChange.firstSeenAt);\n\t\tif (firstSeenAt === undefined || now - firstSeenAt > ttl) continue;\n\t\treason ||= stringValue(rawChange.reason) ?? \"\";\n\t\tif (!isRecord(rawChange.sessions)) continue;\n\t\tfor (const [key, rawSession] of Object.entries(rawChange.sessions)) {\n\t\t\tconst session = parseSession(rawSession);\n\t\t\tif (!session) continue;\n\t\t\tif (session.reloadedAt !== undefined) continue;\n\t\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\t\tif (!isAlive(session.pid)) continue;\n\t\t\tblockers.push({ key, source: \"coordinator\", reason: stringValue(rawChange.reason), ...session });\n\t\t}\n\t}\n\treturn { blockers, reason };\n}\n\nexport function describeReloadSession(\n\trecord: Pick<ReloadSessionRecord, \"key\" | \"pid\" | \"sessionId\" | \"sessionFile\" | \"cwd\">,\n): string {\n\tconst label = record.sessionId ?? record.sessionFile ?? record.cwd ?? String(record.pid ?? \"unknown\");\n\tconst parts = [`${record.key}:${label}`];\n\tif (record.pid !== undefined) parts.push(`pid=${record.pid}`);\n\tif (record.cwd) parts.push(`cwd=${record.cwd}`);\n\tif (record.sessionFile) parts.push(`file=${record.sessionFile}`);\n\treturn parts.join(\" \");\n}\n\nexport function getPendingReloadBlockers(options: ReloadBlockerOptions = {}): PendingReloadBlockers {\n\tconst byIdentity = new Map<string, ReloadSessionRecord>();\n\tfor (const blocker of activeTurnBlockers(options)) addBlocker(byIdentity, blocker);\n\tconst coordinator = coordinatorBlockers(options);\n\tfor (const blocker of coordinator.blockers) addBlocker(byIdentity, blocker);\n\tconst blockers = [...byIdentity.values()].sort((a, b) =>\n\t\tdescribeReloadSession(a).localeCompare(describeReloadSession(b)),\n\t);\n\treturn {\n\t\tpending: blockers.length > 0,\n\t\treason:\n\t\t\tcoordinator.reason ||\n\t\t\t(blockers.length ? \"Pi auto-reload is waiting for active peer/background session(s).\" : \"\"),\n\t\tblockers,\n\t\tdescriptions: blockers.map(describeReloadSession),\n\t};\n}\n\n/**\n * In-process quiesce registry: the reload gate's unified source of truth for background work\n * running IN THIS PROCESS that must finish before a `/reload`, profile switch, or live extension\n * load/unload/reconcile may proceed — background lanes (research/worker/model-fitness), the\n * context-scout's own Agent, and isolated completions (through their single choke point,\n * `ReflectionController.runIsolatedCompletion`) all register here. Foreground streaming/compaction\n * are NOT registered here — the host already exposes those via `RuntimeBuilderDeps.isStreaming`/`isCompacting`,\n * and the gate checks both alongside this registry instead of duplicating that state into a second tracker.\n *\n * Keyed by `agentDir`, matching every cross-process function above, so two sessions rooted at\n * different agent dirs (as every test harness in this repo constructs them) never see each other's\n * in-flight work.\n *\n * Registration is a plain in-memory counter, not file-backed — nothing here survives a process\n * restart, and nothing needs to: a crashed process cannot hold its own reload gate hostage. The\n * returned deregister function MUST be called from a `finally` block by every caller — an\n * un-deregistered unit would wedge the gate forever — so deregistering twice is a safe no-op rather\n * than a footgun for a caller that also deregisters on an early-return path.\n */\nexport type InFlightWorkKind = \"lane\" | \"scout\" | \"isolated-completion\";\n\nexport interface InFlightWorkUnit {\n\tid: number;\n\tkind: InFlightWorkKind;\n\tlabel: string;\n\tregisteredAt: number;\n}\n\nlet _nextInFlightWorkId = 1;\nconst _inFlightWorkByAgentDir = new Map<string, Map<number, InFlightWorkUnit>>();\n\n/** Registers one in-flight background work unit for `agentDir`. Returns its deregister function. */\nexport function registerInFlightWork(agentDir: string, kind: InFlightWorkKind, label: string): () => void {\n\tlet units = _inFlightWorkByAgentDir.get(agentDir);\n\tif (!units) {\n\t\tunits = new Map<number, InFlightWorkUnit>();\n\t\t_inFlightWorkByAgentDir.set(agentDir, units);\n\t}\n\tconst scopedUnits = units;\n\tconst id = _nextInFlightWorkId++;\n\tscopedUnits.set(id, { id, kind, label, registeredAt: Date.now() });\n\tlet deregistered = false;\n\treturn () => {\n\t\tif (deregistered) return;\n\t\tderegistered = true;\n\t\tscopedUnits.delete(id);\n\t\tif (scopedUnits.size === 0) _inFlightWorkByAgentDir.delete(agentDir);\n\t};\n}\n\n/** Live in-flight units for `agentDir`, oldest first. Empty when nothing is registered. */\nexport function getInFlightWorkUnits(agentDir: string): InFlightWorkUnit[] {\n\tconst units = _inFlightWorkByAgentDir.get(agentDir);\n\treturn units ? [...units.values()].sort((a, b) => a.id - b.id) : [];\n}\n\nexport function describeInFlightWorkUnit(unit: InFlightWorkUnit): string {\n\treturn `${unit.kind}:${unit.label}`;\n}\n\n/**\n * Test-only escape hatch: clears every agentDir's registry so one test's leaked registration cannot\n * block another's reload gate or status text.\n */\nexport function resetInFlightWorkRegistryForTests(): void {\n\t_inFlightWorkByAgentDir.clear();\n}\n"]}
1
+ {"version":3,"file":"reload-blockers.js","sourceRoot":"","sources":["../../src/core/reload-blockers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Reload/live-op blocker sources for THIS process's reload gate (`RuntimeBuilder`, see\n * runtime-builder.ts): cross-process peer/coordinator sessions (file-backed, below) AND the\n * in-process quiesce registry (`registerInFlightWork`/`getInFlightWorkUnits`) that tracks background\n * lanes, context-scout runs, and isolated completions running in THIS process. The gate reads both;\n * `getPendingReloadBlockers` (cross-process) also backs the `/autonomy` status text.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../config.ts\";\nimport { getProcessWorkRun } from \"../utils/work-directory.ts\";\nimport { isRecordObject } from \"./util/value-guards.ts\";\n\nexport const ACTIVE_TURN_TTL_MS = 5 * 60_000;\nexport const AUTO_RELOAD_COORDINATOR_TTL_MS = 10 * 60_000;\n\nexport function getReloadCoordinationDir(agentDir: string = getAgentDir()): string {\n\treturn getProcessWorkRun(agentDir, \"coordination\", \"reload\", \"state\").path;\n}\n\nexport interface ReloadSessionRecord {\n\tkey: string;\n\tsource: \"active-turn\" | \"coordinator\";\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n\treason?: string;\n}\n\nexport interface PendingReloadBlockers {\n\tpending: boolean;\n\treason: string;\n\tblockers: ReloadSessionRecord[];\n\tdescriptions: string[];\n}\n\nexport interface ReloadBlockerOptions {\n\tagentDir?: string;\n\tnow?: number;\n\townKey?: string;\n\townPid?: number;\n\townSessionId?: string;\n\townSessionFile?: string;\n\tactiveTurnTtlMs?: number;\n\tcoordinatorTtlMs?: number;\n\t/** Auto Learn workers are memory-first, short-lived, and should not block foreground reload/adaptive work by default. */\n\tincludeAutoLearnSessions?: boolean;\n\tisProcessAlive?: (pid: number | undefined) => boolean;\n}\n\ninterface ParsedSession {\n\tpid?: number;\n\tsessionId?: string;\n\tsessionFile?: string;\n\tcwd?: string;\n\tactive?: boolean;\n\tupdatedAt?: number;\n\tseenAt?: number;\n\treloadedAt?: number;\n}\n\nfunction readJsonFile(file: string): unknown {\n\ttry {\n\t\tif (!existsSync(file)) return undefined;\n\t\treturn JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction stringValue(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction numberValue(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\treturn undefined;\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n\treturn typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction parseSession(value: unknown): ParsedSession | undefined {\n\tif (!isRecordObject(value)) return undefined;\n\treturn {\n\t\tpid: numberValue(value.pid),\n\t\tsessionId: stringValue(value.sessionId),\n\t\tsessionFile: stringValue(value.sessionFile),\n\t\tcwd: stringValue(value.cwd),\n\t\tactive: booleanValue(value.active),\n\t\tupdatedAt: numberValue(value.updatedAt),\n\t\tseenAt: numberValue(value.seenAt),\n\t\treloadedAt: numberValue(value.reloadedAt),\n\t};\n}\n\nexport function isReloadSessionProcessAlive(pid: number | undefined): boolean {\n\tif (pid === undefined || !Number.isFinite(pid) || pid <= 0) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code =\n\t\t\terror && typeof error === \"object\" && \"code\" in error ? String((error as { code?: unknown }).code) : \"\";\n\t\treturn code === \"EPERM\";\n\t}\n}\n\nfunction isOwnSession(key: string, session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\tif (options.ownKey && key === options.ownKey) return true;\n\tif (options.ownPid !== undefined && session.pid === options.ownPid) return true;\n\tif (options.ownSessionId && session.sessionId === options.ownSessionId) return true;\n\tif (options.ownSessionFile && session.sessionFile === options.ownSessionFile) return true;\n\treturn false;\n}\n\nfunction isAutoLearnSession(session: ParsedSession): boolean {\n\treturn !!session.sessionId?.startsWith(\"auto-learn-\");\n}\n\nfunction shouldIgnoreSession(session: ParsedSession, options: ReloadBlockerOptions): boolean {\n\treturn options.includeAutoLearnSessions !== true && isAutoLearnSession(session);\n}\n\nfunction addBlocker(blockers: Map<string, ReloadSessionRecord>, record: ReloadSessionRecord): void {\n\tconst identity = [\n\t\trecord.key,\n\t\trecord.pid ?? \"\",\n\t\trecord.sessionId ?? \"\",\n\t\trecord.sessionFile ?? \"\",\n\t\trecord.cwd ?? \"\",\n\t].join(\"\\0\");\n\tconst existing = blockers.get(identity);\n\tif (!existing || (existing.source === \"coordinator\" && record.source === \"active-turn\")) {\n\t\tblockers.set(identity, record);\n\t}\n}\n\nfunction activeTurnBlockers(options: ReloadBlockerOptions): ReloadSessionRecord[] {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.activeTurnTtlMs ?? ACTIVE_TURN_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst registry = readJsonFile(join(getReloadCoordinationDir(agentDir), \"active-turns.json\"));\n\tif (!isRecordObject(registry) || !isRecordObject(registry.sessions)) return [];\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tfor (const [key, rawSession] of Object.entries(registry.sessions)) {\n\t\tconst session = parseSession(rawSession);\n\t\tif (!session?.active) continue;\n\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\tif (session.updatedAt === undefined || now - session.updatedAt > ttl) continue;\n\t\tif (!isAlive(session.pid)) continue;\n\t\tblockers.push({ key, source: \"active-turn\", ...session });\n\t}\n\treturn blockers;\n}\n\nfunction coordinatorBlockers(options: ReloadBlockerOptions): { blockers: ReloadSessionRecord[]; reason: string } {\n\tconst agentDir = options.agentDir ?? getAgentDir();\n\tconst now = options.now ?? Date.now();\n\tconst ttl = options.coordinatorTtlMs ?? AUTO_RELOAD_COORDINATOR_TTL_MS;\n\tconst isAlive = options.isProcessAlive ?? isReloadSessionProcessAlive;\n\tconst coordinator = readJsonFile(join(getReloadCoordinationDir(agentDir), \"auto-reload-state.json\"));\n\tif (!isRecordObject(coordinator) || !isRecordObject(coordinator.changes)) return { blockers: [], reason: \"\" };\n\n\tconst blockers: ReloadSessionRecord[] = [];\n\tlet reason = \"\";\n\tfor (const rawChange of Object.values(coordinator.changes)) {\n\t\tif (!isRecordObject(rawChange)) continue;\n\t\tconst firstSeenAt = numberValue(rawChange.firstSeenAt);\n\t\tif (firstSeenAt === undefined || now - firstSeenAt > ttl) continue;\n\t\treason ||= stringValue(rawChange.reason) ?? \"\";\n\t\tif (!isRecordObject(rawChange.sessions)) continue;\n\t\tfor (const [key, rawSession] of Object.entries(rawChange.sessions)) {\n\t\t\tconst session = parseSession(rawSession);\n\t\t\tif (!session) continue;\n\t\t\tif (session.reloadedAt !== undefined) continue;\n\t\t\tif (isOwnSession(key, session, options) || shouldIgnoreSession(session, options)) continue;\n\t\t\tif (!isAlive(session.pid)) continue;\n\t\t\tblockers.push({ key, source: \"coordinator\", reason: stringValue(rawChange.reason), ...session });\n\t\t}\n\t}\n\treturn { blockers, reason };\n}\n\nexport function describeReloadSession(\n\trecord: Pick<ReloadSessionRecord, \"key\" | \"pid\" | \"sessionId\" | \"sessionFile\" | \"cwd\">,\n): string {\n\tconst label = record.sessionId ?? record.sessionFile ?? record.cwd ?? String(record.pid ?? \"unknown\");\n\tconst parts = [`${record.key}:${label}`];\n\tif (record.pid !== undefined) parts.push(`pid=${record.pid}`);\n\tif (record.cwd) parts.push(`cwd=${record.cwd}`);\n\tif (record.sessionFile) parts.push(`file=${record.sessionFile}`);\n\treturn parts.join(\" \");\n}\n\nexport function getPendingReloadBlockers(options: ReloadBlockerOptions = {}): PendingReloadBlockers {\n\tconst byIdentity = new Map<string, ReloadSessionRecord>();\n\tfor (const blocker of activeTurnBlockers(options)) addBlocker(byIdentity, blocker);\n\tconst coordinator = coordinatorBlockers(options);\n\tfor (const blocker of coordinator.blockers) addBlocker(byIdentity, blocker);\n\tconst blockers = [...byIdentity.values()].sort((a, b) =>\n\t\tdescribeReloadSession(a).localeCompare(describeReloadSession(b)),\n\t);\n\treturn {\n\t\tpending: blockers.length > 0,\n\t\treason:\n\t\t\tcoordinator.reason ||\n\t\t\t(blockers.length ? \"Pi auto-reload is waiting for active peer/background session(s).\" : \"\"),\n\t\tblockers,\n\t\tdescriptions: blockers.map(describeReloadSession),\n\t};\n}\n\n/**\n * In-process quiesce registry: the reload gate's unified source of truth for background work\n * running IN THIS PROCESS that must finish before a `/reload`, profile switch, or live extension\n * load/unload/reconcile may proceed — background lanes (research/worker/model-fitness), the\n * context-scout's own Agent, and isolated completions (through their single choke point,\n * `ReflectionController.runIsolatedCompletion`) all register here. Foreground streaming/compaction\n * are NOT registered here — the host already exposes those via `RuntimeBuilderDeps.isStreaming`/`isCompacting`,\n * and the gate checks both alongside this registry instead of duplicating that state into a second tracker.\n *\n * Keyed by `agentDir`, matching every cross-process function above, so two sessions rooted at\n * different agent dirs (as every test harness in this repo constructs them) never see each other's\n * in-flight work.\n *\n * Registration is a plain in-memory counter, not file-backed — nothing here survives a process\n * restart, and nothing needs to: a crashed process cannot hold its own reload gate hostage. The\n * returned deregister function MUST be called from a `finally` block by every caller — an\n * un-deregistered unit would wedge the gate forever — so deregistering twice is a safe no-op rather\n * than a footgun for a caller that also deregisters on an early-return path.\n */\nexport type InFlightWorkKind = \"lane\" | \"scout\" | \"isolated-completion\";\n\nexport interface InFlightWorkUnit {\n\tid: number;\n\tkind: InFlightWorkKind;\n\tlabel: string;\n\tregisteredAt: number;\n}\n\nlet _nextInFlightWorkId = 1;\nconst _inFlightWorkByAgentDir = new Map<string, Map<number, InFlightWorkUnit>>();\n\n/** Registers one in-flight background work unit for `agentDir`. Returns its deregister function. */\nexport function registerInFlightWork(agentDir: string, kind: InFlightWorkKind, label: string): () => void {\n\tlet units = _inFlightWorkByAgentDir.get(agentDir);\n\tif (!units) {\n\t\tunits = new Map<number, InFlightWorkUnit>();\n\t\t_inFlightWorkByAgentDir.set(agentDir, units);\n\t}\n\tconst scopedUnits = units;\n\tconst id = _nextInFlightWorkId++;\n\tscopedUnits.set(id, { id, kind, label, registeredAt: Date.now() });\n\tlet deregistered = false;\n\treturn () => {\n\t\tif (deregistered) return;\n\t\tderegistered = true;\n\t\tscopedUnits.delete(id);\n\t\tif (scopedUnits.size === 0) _inFlightWorkByAgentDir.delete(agentDir);\n\t};\n}\n\n/** Live in-flight units for `agentDir`, oldest first. Empty when nothing is registered. */\nexport function getInFlightWorkUnits(agentDir: string): InFlightWorkUnit[] {\n\tconst units = _inFlightWorkByAgentDir.get(agentDir);\n\treturn units ? [...units.values()].sort((a, b) => a.id - b.id) : [];\n}\n\nexport function describeInFlightWorkUnit(unit: InFlightWorkUnit): string {\n\treturn `${unit.kind}:${unit.label}`;\n}\n\n/**\n * Test-only escape hatch: clears every agentDir's registry so one test's leaked registration cannot\n * block another's reload gate or status text.\n */\nexport function resetInFlightWorkRegistryForTests(): void {\n\t_inFlightWorkByAgentDir.clear();\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"evidence-bundle.d.ts","sourceRoot":"","sources":["../../../src/core/research/evidence-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAyB,MAAM,0BAA0B,CAAC;AA2D5G,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,cAAc,CAOjB;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAOpF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAqCxE","sourcesContent":["import type { EvidenceBundle, EvidenceRef, Finding, JsonObject, JsonValue } from \"../autonomy/contracts.ts\";\n\nfunction cloneJsonValue(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cloneJsonValue);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n\t}\n\treturn value;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n\t\treturn true;\n\t}\n\tif (typeof value === \"number\") {\n\t\treturn Number.isFinite(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isJsonValue);\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn isJsonObject(value);\n\t}\n\treturn false;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n\tif (!isPlainRecord(value)) {\n\t\treturn false;\n\t}\n\treturn Object.values(value).every(isJsonValue);\n}\n\nfunction cloneEvidenceRef(source: EvidenceRef): EvidenceRef {\n\treturn {\n\t\t...source,\n\t\tmetadata: source.metadata ? cloneJsonObject(source.metadata) : undefined,\n\t};\n}\n\nfunction cloneFinding(finding: Finding): Finding {\n\treturn {\n\t\t...finding,\n\t\tevidenceIds: [...finding.evidenceIds],\n\t};\n}\n\nexport function createEvidenceBundle(args: {\n\tquery: string;\n\tsources: readonly EvidenceRef[];\n\tfindings: readonly Finding[];\n\tnow?: string;\n}): EvidenceBundle {\n\treturn {\n\t\tquery: args.query,\n\t\tsources: args.sources.map(cloneEvidenceRef),\n\t\tfindings: args.findings.map(cloneFinding),\n\t\tcreatedAt: args.now,\n\t};\n}\n\nexport function cloneEvidenceBundleForStorage(bundle: EvidenceBundle): EvidenceBundle {\n\treturn {\n\t\tquery: bundle.query,\n\t\tsources: bundle.sources.map(cloneEvidenceRef),\n\t\tfindings: bundle.findings.map(cloneFinding),\n\t\tcreatedAt: bundle.createdAt,\n\t};\n}\n\nexport function isEvidenceBundle(value: unknown): value is EvidenceBundle {\n\tif (!isPlainRecord(value)) return false;\n\tconst bundle = value as Record<string, unknown>;\n\n\tif (typeof bundle.query !== \"string\") return false;\n\tif (bundle.createdAt !== undefined && typeof bundle.createdAt !== \"string\") return false;\n\n\tif (!Array.isArray(bundle.sources)) return false;\n\tfor (const source of bundle.sources) {\n\t\tif (!isPlainRecord(source)) return false;\n\t\tconst ref = source as Record<string, unknown>;\n\t\tif (typeof ref.id !== \"string\") return false;\n\t\tif (\n\t\t\ttypeof ref.kind !== \"string\" ||\n\t\t\t![\"workspace\", \"transcript\", \"automata\", \"web\", \"user\", \"tool\"].includes(ref.kind)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof ref.trusted !== \"boolean\") return false;\n\t\tif (ref.title !== undefined && typeof ref.title !== \"string\") return false;\n\t\tif (ref.uri !== undefined && typeof ref.uri !== \"string\") return false;\n\t\tif (ref.excerpt !== undefined && typeof ref.excerpt !== \"string\") return false;\n\t\tif (ref.metadata !== undefined && !isJsonObject(ref.metadata)) return false;\n\t}\n\n\tif (!Array.isArray(bundle.findings)) return false;\n\tfor (const finding of bundle.findings) {\n\t\tif (!isPlainRecord(finding)) return false;\n\t\tconst f = finding as Record<string, unknown>;\n\t\tif (typeof f.id !== \"string\") return false;\n\t\tif (typeof f.summary !== \"string\") return false;\n\t\tif (f.confidence !== undefined && (typeof f.confidence !== \"number\" || !Number.isFinite(f.confidence)))\n\t\t\treturn false;\n\t\tif (!Array.isArray(f.evidenceIds) || !f.evidenceIds.every((id) => typeof id === \"string\")) return false;\n\t}\n\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"evidence-bundle.d.ts","sourceRoot":"","sources":["../../../src/core/research/evidence-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAyB,MAAM,0BAA0B,CAAC;AAsD5G,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,cAAc,CAOjB;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAOpF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAqCxE","sourcesContent":["import type { EvidenceBundle, EvidenceRef, Finding, JsonObject, JsonValue } from \"../autonomy/contracts.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\n\nfunction cloneJsonValue(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cloneJsonValue);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n\t}\n\treturn value;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n\t\treturn true;\n\t}\n\tif (typeof value === \"number\") {\n\t\treturn Number.isFinite(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isJsonValue);\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn isJsonObject(value);\n\t}\n\treturn false;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n\tif (!isPlainRecord(value)) {\n\t\treturn false;\n\t}\n\treturn Object.values(value).every(isJsonValue);\n}\n\nfunction cloneEvidenceRef(source: EvidenceRef): EvidenceRef {\n\treturn {\n\t\t...source,\n\t\tmetadata: source.metadata ? cloneJsonObject(source.metadata) : undefined,\n\t};\n}\n\nfunction cloneFinding(finding: Finding): Finding {\n\treturn {\n\t\t...finding,\n\t\tevidenceIds: [...finding.evidenceIds],\n\t};\n}\n\nexport function createEvidenceBundle(args: {\n\tquery: string;\n\tsources: readonly EvidenceRef[];\n\tfindings: readonly Finding[];\n\tnow?: string;\n}): EvidenceBundle {\n\treturn {\n\t\tquery: args.query,\n\t\tsources: args.sources.map(cloneEvidenceRef),\n\t\tfindings: args.findings.map(cloneFinding),\n\t\tcreatedAt: args.now,\n\t};\n}\n\nexport function cloneEvidenceBundleForStorage(bundle: EvidenceBundle): EvidenceBundle {\n\treturn {\n\t\tquery: bundle.query,\n\t\tsources: bundle.sources.map(cloneEvidenceRef),\n\t\tfindings: bundle.findings.map(cloneFinding),\n\t\tcreatedAt: bundle.createdAt,\n\t};\n}\n\nexport function isEvidenceBundle(value: unknown): value is EvidenceBundle {\n\tif (!isPlainRecord(value)) return false;\n\tconst bundle = value as Record<string, unknown>;\n\n\tif (typeof bundle.query !== \"string\") return false;\n\tif (bundle.createdAt !== undefined && typeof bundle.createdAt !== \"string\") return false;\n\n\tif (!Array.isArray(bundle.sources)) return false;\n\tfor (const source of bundle.sources) {\n\t\tif (!isPlainRecord(source)) return false;\n\t\tconst ref = source as Record<string, unknown>;\n\t\tif (typeof ref.id !== \"string\") return false;\n\t\tif (\n\t\t\ttypeof ref.kind !== \"string\" ||\n\t\t\t![\"workspace\", \"transcript\", \"automata\", \"web\", \"user\", \"tool\"].includes(ref.kind)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof ref.trusted !== \"boolean\") return false;\n\t\tif (ref.title !== undefined && typeof ref.title !== \"string\") return false;\n\t\tif (ref.uri !== undefined && typeof ref.uri !== \"string\") return false;\n\t\tif (ref.excerpt !== undefined && typeof ref.excerpt !== \"string\") return false;\n\t\tif (ref.metadata !== undefined && !isJsonObject(ref.metadata)) return false;\n\t}\n\n\tif (!Array.isArray(bundle.findings)) return false;\n\tfor (const finding of bundle.findings) {\n\t\tif (!isPlainRecord(finding)) return false;\n\t\tconst f = finding as Record<string, unknown>;\n\t\tif (typeof f.id !== \"string\") return false;\n\t\tif (typeof f.summary !== \"string\") return false;\n\t\tif (f.confidence !== undefined && (typeof f.confidence !== \"number\" || !Number.isFinite(f.confidence)))\n\t\t\treturn false;\n\t\tif (!Array.isArray(f.evidenceIds) || !f.evidenceIds.every((id) => typeof id === \"string\")) return false;\n\t}\n\n\treturn true;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { isPlainRecord } from "../util/value-guards.js";
1
2
  function cloneJsonValue(value) {
2
3
  if (Array.isArray(value)) {
3
4
  return value.map(cloneJsonValue);
@@ -10,12 +11,6 @@ function cloneJsonValue(value) {
10
11
  function cloneJsonObject(value) {
11
12
  return Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));
12
13
  }
13
- function isPlainRecord(value) {
14
- if (!value || typeof value !== "object" || Array.isArray(value))
15
- return false;
16
- const prototype = Object.getPrototypeOf(value);
17
- return prototype === Object.prototype || prototype === null;
18
- }
19
14
  function isJsonValue(value) {
20
15
  if (value === null || typeof value === "string" || typeof value === "boolean") {
21
16
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"evidence-bundle.js","sourceRoot":"","sources":["../../../src/core/research/evidence-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EvidenceBundle, EvidenceRef, Finding, JsonObject, JsonValue } from \"../autonomy/contracts.ts\";\n\nfunction cloneJsonValue(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cloneJsonValue);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n\t}\n\treturn value;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n\t\treturn true;\n\t}\n\tif (typeof value === \"number\") {\n\t\treturn Number.isFinite(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isJsonValue);\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn isJsonObject(value);\n\t}\n\treturn false;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n\tif (!isPlainRecord(value)) {\n\t\treturn false;\n\t}\n\treturn Object.values(value).every(isJsonValue);\n}\n\nfunction cloneEvidenceRef(source: EvidenceRef): EvidenceRef {\n\treturn {\n\t\t...source,\n\t\tmetadata: source.metadata ? cloneJsonObject(source.metadata) : undefined,\n\t};\n}\n\nfunction cloneFinding(finding: Finding): Finding {\n\treturn {\n\t\t...finding,\n\t\tevidenceIds: [...finding.evidenceIds],\n\t};\n}\n\nexport function createEvidenceBundle(args: {\n\tquery: string;\n\tsources: readonly EvidenceRef[];\n\tfindings: readonly Finding[];\n\tnow?: string;\n}): EvidenceBundle {\n\treturn {\n\t\tquery: args.query,\n\t\tsources: args.sources.map(cloneEvidenceRef),\n\t\tfindings: args.findings.map(cloneFinding),\n\t\tcreatedAt: args.now,\n\t};\n}\n\nexport function cloneEvidenceBundleForStorage(bundle: EvidenceBundle): EvidenceBundle {\n\treturn {\n\t\tquery: bundle.query,\n\t\tsources: bundle.sources.map(cloneEvidenceRef),\n\t\tfindings: bundle.findings.map(cloneFinding),\n\t\tcreatedAt: bundle.createdAt,\n\t};\n}\n\nexport function isEvidenceBundle(value: unknown): value is EvidenceBundle {\n\tif (!isPlainRecord(value)) return false;\n\tconst bundle = value as Record<string, unknown>;\n\n\tif (typeof bundle.query !== \"string\") return false;\n\tif (bundle.createdAt !== undefined && typeof bundle.createdAt !== \"string\") return false;\n\n\tif (!Array.isArray(bundle.sources)) return false;\n\tfor (const source of bundle.sources) {\n\t\tif (!isPlainRecord(source)) return false;\n\t\tconst ref = source as Record<string, unknown>;\n\t\tif (typeof ref.id !== \"string\") return false;\n\t\tif (\n\t\t\ttypeof ref.kind !== \"string\" ||\n\t\t\t![\"workspace\", \"transcript\", \"automata\", \"web\", \"user\", \"tool\"].includes(ref.kind)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof ref.trusted !== \"boolean\") return false;\n\t\tif (ref.title !== undefined && typeof ref.title !== \"string\") return false;\n\t\tif (ref.uri !== undefined && typeof ref.uri !== \"string\") return false;\n\t\tif (ref.excerpt !== undefined && typeof ref.excerpt !== \"string\") return false;\n\t\tif (ref.metadata !== undefined && !isJsonObject(ref.metadata)) return false;\n\t}\n\n\tif (!Array.isArray(bundle.findings)) return false;\n\tfor (const finding of bundle.findings) {\n\t\tif (!isPlainRecord(finding)) return false;\n\t\tconst f = finding as Record<string, unknown>;\n\t\tif (typeof f.id !== \"string\") return false;\n\t\tif (typeof f.summary !== \"string\") return false;\n\t\tif (f.confidence !== undefined && (typeof f.confidence !== \"number\" || !Number.isFinite(f.confidence)))\n\t\t\treturn false;\n\t\tif (!Array.isArray(f.evidenceIds) || !f.evidenceIds.every((id) => typeof id === \"string\")) return false;\n\t}\n\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"evidence-bundle.js","sourceRoot":"","sources":["../../../src/core/research/evidence-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EvidenceBundle, EvidenceRef, Finding, JsonObject, JsonValue } from \"../autonomy/contracts.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\n\nfunction cloneJsonValue(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cloneJsonValue);\n\t}\n\tif (value !== null && typeof value === \"object\") {\n\t\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n\t}\n\treturn value;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n\treturn Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, cloneJsonValue(nested)]));\n}\n\nfunction isJsonValue(value: unknown): value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") {\n\t\treturn true;\n\t}\n\tif (typeof value === \"number\") {\n\t\treturn Number.isFinite(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.every(isJsonValue);\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn isJsonObject(value);\n\t}\n\treturn false;\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n\tif (!isPlainRecord(value)) {\n\t\treturn false;\n\t}\n\treturn Object.values(value).every(isJsonValue);\n}\n\nfunction cloneEvidenceRef(source: EvidenceRef): EvidenceRef {\n\treturn {\n\t\t...source,\n\t\tmetadata: source.metadata ? cloneJsonObject(source.metadata) : undefined,\n\t};\n}\n\nfunction cloneFinding(finding: Finding): Finding {\n\treturn {\n\t\t...finding,\n\t\tevidenceIds: [...finding.evidenceIds],\n\t};\n}\n\nexport function createEvidenceBundle(args: {\n\tquery: string;\n\tsources: readonly EvidenceRef[];\n\tfindings: readonly Finding[];\n\tnow?: string;\n}): EvidenceBundle {\n\treturn {\n\t\tquery: args.query,\n\t\tsources: args.sources.map(cloneEvidenceRef),\n\t\tfindings: args.findings.map(cloneFinding),\n\t\tcreatedAt: args.now,\n\t};\n}\n\nexport function cloneEvidenceBundleForStorage(bundle: EvidenceBundle): EvidenceBundle {\n\treturn {\n\t\tquery: bundle.query,\n\t\tsources: bundle.sources.map(cloneEvidenceRef),\n\t\tfindings: bundle.findings.map(cloneFinding),\n\t\tcreatedAt: bundle.createdAt,\n\t};\n}\n\nexport function isEvidenceBundle(value: unknown): value is EvidenceBundle {\n\tif (!isPlainRecord(value)) return false;\n\tconst bundle = value as Record<string, unknown>;\n\n\tif (typeof bundle.query !== \"string\") return false;\n\tif (bundle.createdAt !== undefined && typeof bundle.createdAt !== \"string\") return false;\n\n\tif (!Array.isArray(bundle.sources)) return false;\n\tfor (const source of bundle.sources) {\n\t\tif (!isPlainRecord(source)) return false;\n\t\tconst ref = source as Record<string, unknown>;\n\t\tif (typeof ref.id !== \"string\") return false;\n\t\tif (\n\t\t\ttypeof ref.kind !== \"string\" ||\n\t\t\t![\"workspace\", \"transcript\", \"automata\", \"web\", \"user\", \"tool\"].includes(ref.kind)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tif (typeof ref.trusted !== \"boolean\") return false;\n\t\tif (ref.title !== undefined && typeof ref.title !== \"string\") return false;\n\t\tif (ref.uri !== undefined && typeof ref.uri !== \"string\") return false;\n\t\tif (ref.excerpt !== undefined && typeof ref.excerpt !== \"string\") return false;\n\t\tif (ref.metadata !== undefined && !isJsonObject(ref.metadata)) return false;\n\t}\n\n\tif (!Array.isArray(bundle.findings)) return false;\n\tfor (const finding of bundle.findings) {\n\t\tif (!isPlainRecord(finding)) return false;\n\t\tconst f = finding as Record<string, unknown>;\n\t\tif (typeof f.id !== \"string\") return false;\n\t\tif (typeof f.summary !== \"string\") return false;\n\t\tif (f.confidence !== undefined && (typeof f.confidence !== \"number\" || !Number.isFinite(f.confidence)))\n\t\t\treturn false;\n\t\tif (!Array.isArray(f.evidenceIds) || !f.evidenceIds.every((id) => typeof id === \"string\")) return false;\n\t}\n\n\treturn true;\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import type { Api, Model } from "@caupulican/pi-ai";
2
+ import { type ModelCapabilityProfile } from "../model-capability.ts";
3
+ import type { ModelRegistry } from "../model-registry.ts";
4
+ import type { NormalizedProfile } from "../profile-registry.ts";
5
+ import type { SettingsManager } from "../settings-manager.ts";
6
+ export interface LaneModelResolverDeps {
7
+ getCwd(): string;
8
+ getModel(): Model<Api> | undefined;
9
+ getModelRegistry(): ModelRegistry;
10
+ getSettingsManager(): SettingsManager;
11
+ isModelExhausted(model: Model<Api>): boolean;
12
+ }
13
+ export type LaneShipment = {
14
+ ok: true;
15
+ model: Model<Api>;
16
+ laneProfile?: NormalizedProfile;
17
+ } | {
18
+ ok: false;
19
+ skipReason: string;
20
+ };
21
+ export declare function clampLaneMaxUsd(settingsMaxUsd: number, foregroundMaxEstimatedUsd?: number): number;
22
+ /** Shared provider-neutral model/profile resolution for research and fitness lanes. */
23
+ export declare class LaneModelResolver {
24
+ private readonly deps;
25
+ constructor(deps: LaneModelResolverDeps);
26
+ capabilityProfile(model: Model<Api>): ModelCapabilityProfile;
27
+ resolveModel(configuredPattern: string | undefined): Model<Api> | undefined;
28
+ resolveShipment(laneSettings: {
29
+ model?: string;
30
+ profile?: string;
31
+ }, missingModelReason: string): LaneShipment;
32
+ }
33
+ //# sourceMappingURL=lane-model-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane-model-resolver.d.ts","sourceRoot":"","sources":["../../../src/core/research/lane-model-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAgC,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACrC,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IACnC,gBAAgB,IAAI,aAAa,CAAC;IAClC,kBAAkB,IAAI,eAAe,CAAC;IACtC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;CAC7C;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAAC,WAAW,CAAC,EAAE,iBAAiB,CAAA;CAAE,GAChE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,yBAAyB,CAAC,EAAE,MAAM,GAAG,MAAM,CAElG;AAED,uFAAuF;AACvF,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAE7C,YAAY,IAAI,EAAE,qBAAqB,EAEtC;IAED,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,sBAAsB,CAK3D;IAED,YAAY,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAY1E;IAED,eAAe,CAAC,YAAY,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,kBAAkB,EAAE,MAAM,GAAG,YAAY,CA2B5G;CACD","sourcesContent":["import type { Api, Model } from \"@caupulican/pi-ai\";\nimport { deriveModelCapabilityProfile, type ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { ModelRegistry } from \"../model-registry.ts\";\nimport { resolveCliModel } from \"../model-resolver.ts\";\nimport type { NormalizedProfile } from \"../profile-registry.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\n\nexport interface LaneModelResolverDeps {\n\tgetCwd(): string;\n\tgetModel(): Model<Api> | undefined;\n\tgetModelRegistry(): ModelRegistry;\n\tgetSettingsManager(): SettingsManager;\n\tisModelExhausted(model: Model<Api>): boolean;\n}\n\nexport type LaneShipment =\n\t| { ok: true; model: Model<Api>; laneProfile?: NormalizedProfile }\n\t| { ok: false; skipReason: string };\n\nexport function clampLaneMaxUsd(settingsMaxUsd: number, foregroundMaxEstimatedUsd?: number): number {\n\treturn Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);\n}\n\n/** Shared provider-neutral model/profile resolution for research and fitness lanes. */\nexport class LaneModelResolver {\n\tprivate readonly deps: LaneModelResolverDeps;\n\n\tconstructor(deps: LaneModelResolverDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tcapabilityProfile(model: Model<Api>): ModelCapabilityProfile {\n\t\treturn deriveModelCapabilityProfile({\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t});\n\t}\n\n\tresolveModel(configuredPattern: string | undefined): Model<Api> | undefined {\n\t\tif (configuredPattern) {\n\t\t\tconst resolved = resolveCliModel({\n\t\t\t\tcliModel: configuredPattern,\n\t\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t\t});\n\t\t\tif (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\t\treturn resolved.model;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.deps.getModel() ?? undefined;\n\t}\n\n\tresolveShipment(laneSettings: { model?: string; profile?: string }, missingModelReason: string): LaneShipment {\n\t\tlet laneProfile: NormalizedProfile | undefined;\n\t\tif (laneSettings.profile) {\n\t\t\tconst profileRef = laneSettings.profile.trim();\n\t\t\tconst registry = this.deps.getSettingsManager().getProfileRegistry();\n\t\t\tlaneProfile =\n\t\t\t\tprofileRef.startsWith(\"./\") || profileRef.startsWith(\"../\")\n\t\t\t\t\t? registry.resolveProfileRef(profileRef, this.deps.getCwd())\n\t\t\t\t\t: registry.getProfile(profileRef);\n\t\t\tif (!laneProfile) return { ok: false, skipReason: \"lane_profile_not_found\" };\n\t\t}\n\n\t\tlet model: Model<Api> | undefined;\n\t\tif (laneSettings.model) {\n\t\t\tmodel = this.resolveModel(laneSettings.model);\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t} else if (laneProfile?.model) {\n\t\t\tmodel = this.resolveModel(laneProfile.model);\n\t\t\tif (!model) return { ok: false, skipReason: \"no_lane_profile_model\" };\n\t\t} else {\n\t\t\tmodel = this.deps.getModel() ?? undefined;\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t}\n\t\tif (this.deps.isModelExhausted(model)) {\n\t\t\treturn { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };\n\t\t}\n\t\treturn { ok: true, model, laneProfile };\n\t}\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import { deriveModelCapabilityProfile } from "../model-capability.js";
2
+ import { resolveCliModel } from "../model-resolver.js";
3
+ export function clampLaneMaxUsd(settingsMaxUsd, foregroundMaxEstimatedUsd) {
4
+ return Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);
5
+ }
6
+ /** Shared provider-neutral model/profile resolution for research and fitness lanes. */
7
+ export class LaneModelResolver {
8
+ deps;
9
+ constructor(deps) {
10
+ this.deps = deps;
11
+ }
12
+ capabilityProfile(model) {
13
+ return deriveModelCapabilityProfile({
14
+ contextWindow: model.contextWindow,
15
+ mode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,
16
+ });
17
+ }
18
+ resolveModel(configuredPattern) {
19
+ if (configuredPattern) {
20
+ const resolved = resolveCliModel({
21
+ cliModel: configuredPattern,
22
+ modelRegistry: this.deps.getModelRegistry(),
23
+ });
24
+ if (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {
25
+ return resolved.model;
26
+ }
27
+ return undefined;
28
+ }
29
+ return this.deps.getModel() ?? undefined;
30
+ }
31
+ resolveShipment(laneSettings, missingModelReason) {
32
+ let laneProfile;
33
+ if (laneSettings.profile) {
34
+ const profileRef = laneSettings.profile.trim();
35
+ const registry = this.deps.getSettingsManager().getProfileRegistry();
36
+ laneProfile =
37
+ profileRef.startsWith("./") || profileRef.startsWith("../")
38
+ ? registry.resolveProfileRef(profileRef, this.deps.getCwd())
39
+ : registry.getProfile(profileRef);
40
+ if (!laneProfile)
41
+ return { ok: false, skipReason: "lane_profile_not_found" };
42
+ }
43
+ let model;
44
+ if (laneSettings.model) {
45
+ model = this.resolveModel(laneSettings.model);
46
+ if (!model)
47
+ return { ok: false, skipReason: missingModelReason };
48
+ }
49
+ else if (laneProfile?.model) {
50
+ model = this.resolveModel(laneProfile.model);
51
+ if (!model)
52
+ return { ok: false, skipReason: "no_lane_profile_model" };
53
+ }
54
+ else {
55
+ model = this.deps.getModel() ?? undefined;
56
+ if (!model)
57
+ return { ok: false, skipReason: missingModelReason };
58
+ }
59
+ if (this.deps.isModelExhausted(model)) {
60
+ return { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };
61
+ }
62
+ return { ok: true, model, laneProfile };
63
+ }
64
+ }
65
+ //# sourceMappingURL=lane-model-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane-model-resolver.js","sourceRoot":"","sources":["../../../src/core/research/lane-model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, Model } from \"@caupulican/pi-ai\";\nimport { deriveModelCapabilityProfile, type ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { ModelRegistry } from \"../model-registry.ts\";\nimport { resolveCliModel } from \"../model-resolver.ts\";\nimport type { NormalizedProfile } from \"../profile-registry.ts\";\nimport type { SettingsManager } from \"../settings-manager.ts\";\n\nexport interface LaneModelResolverDeps {\n\tgetCwd(): string;\n\tgetModel(): Model<Api> | undefined;\n\tgetModelRegistry(): ModelRegistry;\n\tgetSettingsManager(): SettingsManager;\n\tisModelExhausted(model: Model<Api>): boolean;\n}\n\nexport type LaneShipment =\n\t| { ok: true; model: Model<Api>; laneProfile?: NormalizedProfile }\n\t| { ok: false; skipReason: string };\n\nexport function clampLaneMaxUsd(settingsMaxUsd: number, foregroundMaxEstimatedUsd?: number): number {\n\treturn Math.min(settingsMaxUsd, foregroundMaxEstimatedUsd ?? Number.POSITIVE_INFINITY);\n}\n\n/** Shared provider-neutral model/profile resolution for research and fitness lanes. */\nexport class LaneModelResolver {\n\tprivate readonly deps: LaneModelResolverDeps;\n\n\tconstructor(deps: LaneModelResolverDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tcapabilityProfile(model: Model<Api>): ModelCapabilityProfile {\n\t\treturn deriveModelCapabilityProfile({\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t});\n\t}\n\n\tresolveModel(configuredPattern: string | undefined): Model<Api> | undefined {\n\t\tif (configuredPattern) {\n\t\t\tconst resolved = resolveCliModel({\n\t\t\t\tcliModel: configuredPattern,\n\t\t\t\tmodelRegistry: this.deps.getModelRegistry(),\n\t\t\t});\n\t\t\tif (resolved.model && this.deps.getModelRegistry().hasConfiguredAuth(resolved.model)) {\n\t\t\t\treturn resolved.model;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.deps.getModel() ?? undefined;\n\t}\n\n\tresolveShipment(laneSettings: { model?: string; profile?: string }, missingModelReason: string): LaneShipment {\n\t\tlet laneProfile: NormalizedProfile | undefined;\n\t\tif (laneSettings.profile) {\n\t\t\tconst profileRef = laneSettings.profile.trim();\n\t\t\tconst registry = this.deps.getSettingsManager().getProfileRegistry();\n\t\t\tlaneProfile =\n\t\t\t\tprofileRef.startsWith(\"./\") || profileRef.startsWith(\"../\")\n\t\t\t\t\t? registry.resolveProfileRef(profileRef, this.deps.getCwd())\n\t\t\t\t\t: registry.getProfile(profileRef);\n\t\t\tif (!laneProfile) return { ok: false, skipReason: \"lane_profile_not_found\" };\n\t\t}\n\n\t\tlet model: Model<Api> | undefined;\n\t\tif (laneSettings.model) {\n\t\t\tmodel = this.resolveModel(laneSettings.model);\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t} else if (laneProfile?.model) {\n\t\t\tmodel = this.resolveModel(laneProfile.model);\n\t\t\tif (!model) return { ok: false, skipReason: \"no_lane_profile_model\" };\n\t\t} else {\n\t\t\tmodel = this.deps.getModel() ?? undefined;\n\t\t\tif (!model) return { ok: false, skipReason: missingModelReason };\n\t\t}\n\t\tif (this.deps.isModelExhausted(model)) {\n\t\t\treturn { ok: false, skipReason: `${model.provider}/${model.id} model exhausted: quota` };\n\t\t}\n\t\treturn { ok: true, model, laneProfile };\n\t}\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import type { Usage } from "@caupulican/pi-ai";
2
+ import type { IsolatedCompletionOptions, IsolatedCompletionResult } from "../agent-session.ts";
3
+ import { type StoredFitnessReport } from "../models/fitness-store.ts";
4
+ import type { LaneModelResolver } from "./lane-model-resolver.ts";
5
+ import { type ModelFitnessReport } from "./model-fitness.ts";
6
+ export interface ModelFitnessControllerDeps {
7
+ isDisposed(): boolean;
8
+ getSessionId(): string;
9
+ getAgentDir(): string;
10
+ addSpawnedUsage(usage: Usage, opts: {
11
+ label?: string;
12
+ sourceSessionId?: string;
13
+ reportId: string;
14
+ }): string | undefined;
15
+ runIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;
16
+ }
17
+ /** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */
18
+ export declare class ModelFitnessController {
19
+ private readonly abortController;
20
+ private readonly deps;
21
+ private readonly models;
22
+ constructor(deps: ModelFitnessControllerDeps, models: LaneModelResolver);
23
+ abort(): void;
24
+ run(args: {
25
+ model: string;
26
+ trials?: number;
27
+ toolCallId?: string;
28
+ }): Promise<{
29
+ started: true;
30
+ model: string;
31
+ report: ModelFitnessReport;
32
+ } | {
33
+ started: false;
34
+ skipReason: string;
35
+ }>;
36
+ getStoredReports(): StoredFitnessReport[];
37
+ }
38
+ //# sourceMappingURL=model-fitness-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-fitness-controller.d.ts","sourceRoot":"","sources":["../../../src/core/research/model-fitness-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/F,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,KAAK,kBAAkB,EAAwB,MAAM,oBAAoB,CAAC;AAEnF,MAAM,WAAW,0BAA0B;IAC1C,UAAU,IAAI,OAAO,CAAC;IACtB,YAAY,IAAI,MAAM,CAAC;IACvB,WAAW,IAAI,MAAM,CAAC;IACtB,eAAe,CACd,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAClE,MAAM,GAAG,SAAS,CAAC;IACtB,qBAAqB,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC1F;AAOD,0FAA0F;AAC1F,qBAAa,sBAAsB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;IACzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C,YAAY,IAAI,EAAE,0BAA0B,EAAE,MAAM,EAAE,iBAAiB,EAGtE;IAED,KAAK,IAAI,IAAI,CAEZ;IAEK,GAAG,CAAC,IAAI,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,kBAAkB,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CA2EjH;IAED,gBAAgB,IAAI,mBAAmB,EAAE,CAMxC;CACD","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\nimport type { IsolatedCompletionOptions, IsolatedCompletionResult } from \"../agent-session.ts\";\nimport { FitnessStore, type StoredFitnessReport } from \"../models/fitness-store.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport type { LaneModelResolver } from \"./lane-model-resolver.ts\";\nimport { type ModelFitnessReport, runModelFitnessProbe } from \"./model-fitness.ts\";\n\nexport interface ModelFitnessControllerDeps {\n\tisDisposed(): boolean;\n\tgetSessionId(): string;\n\tgetAgentDir(): string;\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts: { label?: string; sourceSessionId?: string; reportId: string },\n\t): string | undefined;\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\nfunction deriveSpawnedUsageReportId(kind: string, sessionId: string, identity: string): string {\n\tconst digest = createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 16);\n\treturn `${kind}:${sessionId}:${digest}`;\n}\n\n/** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */\nexport class ModelFitnessController {\n\tprivate readonly abortController = new AbortController();\n\tprivate readonly deps: ModelFitnessControllerDeps;\n\tprivate readonly models: LaneModelResolver;\n\n\tconstructor(deps: ModelFitnessControllerDeps, models: LaneModelResolver) {\n\t\tthis.deps = deps;\n\t\tthis.models = models;\n\t}\n\n\tabort(): void {\n\t\tthis.abortController.abort();\n\t}\n\n\tasync run(args: {\n\t\tmodel: string;\n\t\ttrials?: number;\n\t\ttoolCallId?: string;\n\t}): Promise<{ started: true; model: string; report: ModelFitnessReport } | { started: false; skipReason: string }> {\n\t\tif (this.deps.isDisposed()) return { started: false, skipReason: \"session_disposed\" };\n\t\tconst resolved = this.models.resolveModel(args.model.trim() || undefined);\n\t\tif (!resolved) return { started: false, skipReason: \"model_unresolved_or_unauthenticated\" };\n\t\tconst capability = this.models.capabilityProfile(resolved);\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"lane\",\n\t\t\t`fitness:${resolved.provider}/${resolved.id}`,\n\t\t);\n\t\ttry {\n\t\t\tconst spent: Usage = {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\tconst report = await runModelFitnessProbe({\n\t\t\t\ttrials: args.trials,\n\t\t\t\tsignal: this.abortController.signal,\n\t\t\t\tcapacityProbe:\n\t\t\t\t\tresolved.provider === \"ollama\" && resolved.contextWindow > 0\n\t\t\t\t\t\t? { registeredContextWindow: resolved.contextWindow }\n\t\t\t\t\t\t: undefined,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst callStarted = Date.now();\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel: resolved,\n\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\tmaxTokens: capability.laneMaxOutputTokens,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\tlaneKind: \"fitness\",\n\t\t\t\t\t});\n\t\t\t\t\tconst callMs = Date.now() - callStarted;\n\t\t\t\t\tspent.input += completion.usage.input;\n\t\t\t\t\tspent.output += completion.usage.output;\n\t\t\t\t\tspent.cacheRead += completion.usage.cacheRead;\n\t\t\t\t\tspent.cacheWrite += completion.usage.cacheWrite;\n\t\t\t\t\tspent.totalTokens += completion.usage.totalTokens;\n\t\t\t\t\tspent.cost.input += completion.usage.cost.input;\n\t\t\t\t\tspent.cost.output += completion.usage.cost.output;\n\t\t\t\t\tspent.cost.cacheRead += completion.usage.cost.cacheRead;\n\t\t\t\t\tspent.cost.cacheWrite += completion.usage.cost.cacheWrite;\n\t\t\t\t\tspent.cost.total += completion.usage.cost.total;\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\toutputTokens: completion.usage.output,\n\t\t\t\t\t\tevalMs: callMs,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst modelRef = `${resolved.provider}/${resolved.id}`;\n\t\t\tif (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {\n\t\t\t\tconst identity = args.toolCallId\n\t\t\t\t\t? `toolcall:${args.toolCallId}`\n\t\t\t\t\t: `${modelRef} ${args.trials ?? \"default\"}`;\n\t\t\t\tconst reportId = deriveSpawnedUsageReportId(\"model-fitness\", this.deps.getSessionId(), identity);\n\t\t\t\tthis.deps.addSpawnedUsage(spent, { label: \"model-fitness\", reportId });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (!this.deps.isDisposed()) FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);\n\t\t\t} catch {\n\t\t\t\t// Best-effort persistence must not fail the probe.\n\t\t\t}\n\t\t\treturn { started: true, model: modelRef, report };\n\t\t} finally {\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\tgetStoredReports(): StoredFitnessReport[] {\n\t\ttry {\n\t\t\treturn FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,106 @@
1
+ import { createHash } from "node:crypto";
2
+ import { FitnessStore } from "../models/fitness-store.js";
3
+ import { registerInFlightWork } from "../reload-blockers.js";
4
+ import { runModelFitnessProbe } from "./model-fitness.js";
5
+ function deriveSpawnedUsageReportId(kind, sessionId, identity) {
6
+ const digest = createHash("sha256").update(identity).digest("hex").slice(0, 16);
7
+ return `${kind}:${sessionId}:${digest}`;
8
+ }
9
+ /** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */
10
+ export class ModelFitnessController {
11
+ abortController = new AbortController();
12
+ deps;
13
+ models;
14
+ constructor(deps, models) {
15
+ this.deps = deps;
16
+ this.models = models;
17
+ }
18
+ abort() {
19
+ this.abortController.abort();
20
+ }
21
+ async run(args) {
22
+ if (this.deps.isDisposed())
23
+ return { started: false, skipReason: "session_disposed" };
24
+ const resolved = this.models.resolveModel(args.model.trim() || undefined);
25
+ if (!resolved)
26
+ return { started: false, skipReason: "model_unresolved_or_unauthenticated" };
27
+ const capability = this.models.capabilityProfile(resolved);
28
+ const deregisterInFlight = registerInFlightWork(this.deps.getAgentDir(), "lane", `fitness:${resolved.provider}/${resolved.id}`);
29
+ try {
30
+ const spent = {
31
+ input: 0,
32
+ output: 0,
33
+ cacheRead: 0,
34
+ cacheWrite: 0,
35
+ totalTokens: 0,
36
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
37
+ };
38
+ const report = await runModelFitnessProbe({
39
+ trials: args.trials,
40
+ signal: this.abortController.signal,
41
+ capacityProbe: resolved.provider === "ollama" && resolved.contextWindow > 0
42
+ ? { registeredContextWindow: resolved.contextWindow }
43
+ : undefined,
44
+ complete: async ({ systemPrompt, userPrompt, signal }) => {
45
+ const callStarted = Date.now();
46
+ const completion = await this.deps.runIsolatedCompletion({
47
+ systemPrompt,
48
+ messages: [{ role: "user", content: [{ type: "text", text: userPrompt }], timestamp: Date.now() }],
49
+ model: resolved,
50
+ thinkingLevel: "off",
51
+ maxTokens: capability.laneMaxOutputTokens,
52
+ signal,
53
+ cacheRetention: "short",
54
+ laneKind: "fitness",
55
+ });
56
+ const callMs = Date.now() - callStarted;
57
+ spent.input += completion.usage.input;
58
+ spent.output += completion.usage.output;
59
+ spent.cacheRead += completion.usage.cacheRead;
60
+ spent.cacheWrite += completion.usage.cacheWrite;
61
+ spent.totalTokens += completion.usage.totalTokens;
62
+ spent.cost.input += completion.usage.cost.input;
63
+ spent.cost.output += completion.usage.cost.output;
64
+ spent.cost.cacheRead += completion.usage.cost.cacheRead;
65
+ spent.cost.cacheWrite += completion.usage.cost.cacheWrite;
66
+ spent.cost.total += completion.usage.cost.total;
67
+ return {
68
+ text: completion.text,
69
+ costUsd: completion.usage.cost.total,
70
+ stopReason: String(completion.stopReason),
71
+ outputTokens: completion.usage.output,
72
+ evalMs: callMs,
73
+ };
74
+ },
75
+ });
76
+ const modelRef = `${resolved.provider}/${resolved.id}`;
77
+ if (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {
78
+ const identity = args.toolCallId
79
+ ? `toolcall:${args.toolCallId}`
80
+ : `${modelRef} ${args.trials ?? "default"}`;
81
+ const reportId = deriveSpawnedUsageReportId("model-fitness", this.deps.getSessionId(), identity);
82
+ this.deps.addSpawnedUsage(spent, { label: "model-fitness", reportId });
83
+ }
84
+ try {
85
+ if (!this.deps.isDisposed())
86
+ FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);
87
+ }
88
+ catch {
89
+ // Best-effort persistence must not fail the probe.
90
+ }
91
+ return { started: true, model: modelRef, report };
92
+ }
93
+ finally {
94
+ deregisterInFlight();
95
+ }
96
+ }
97
+ getStoredReports() {
98
+ try {
99
+ return FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();
100
+ }
101
+ catch {
102
+ return [];
103
+ }
104
+ }
105
+ }
106
+ //# sourceMappingURL=model-fitness-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-fitness-controller.js","sourceRoot":"","sources":["../../../src/core/research/model-fitness-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\nimport type { IsolatedCompletionOptions, IsolatedCompletionResult } from \"../agent-session.ts\";\nimport { FitnessStore, type StoredFitnessReport } from \"../models/fitness-store.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport type { LaneModelResolver } from \"./lane-model-resolver.ts\";\nimport { type ModelFitnessReport, runModelFitnessProbe } from \"./model-fitness.ts\";\n\nexport interface ModelFitnessControllerDeps {\n\tisDisposed(): boolean;\n\tgetSessionId(): string;\n\tgetAgentDir(): string;\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts: { label?: string; sourceSessionId?: string; reportId: string },\n\t): string | undefined;\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\nfunction deriveSpawnedUsageReportId(kind: string, sessionId: string, identity: string): string {\n\tconst digest = createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 16);\n\treturn `${kind}:${sessionId}:${digest}`;\n}\n\n/** Owns model-fitness execution, cancellation, accounting, and host-keyed persistence. */\nexport class ModelFitnessController {\n\tprivate readonly abortController = new AbortController();\n\tprivate readonly deps: ModelFitnessControllerDeps;\n\tprivate readonly models: LaneModelResolver;\n\n\tconstructor(deps: ModelFitnessControllerDeps, models: LaneModelResolver) {\n\t\tthis.deps = deps;\n\t\tthis.models = models;\n\t}\n\n\tabort(): void {\n\t\tthis.abortController.abort();\n\t}\n\n\tasync run(args: {\n\t\tmodel: string;\n\t\ttrials?: number;\n\t\ttoolCallId?: string;\n\t}): Promise<{ started: true; model: string; report: ModelFitnessReport } | { started: false; skipReason: string }> {\n\t\tif (this.deps.isDisposed()) return { started: false, skipReason: \"session_disposed\" };\n\t\tconst resolved = this.models.resolveModel(args.model.trim() || undefined);\n\t\tif (!resolved) return { started: false, skipReason: \"model_unresolved_or_unauthenticated\" };\n\t\tconst capability = this.models.capabilityProfile(resolved);\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"lane\",\n\t\t\t`fitness:${resolved.provider}/${resolved.id}`,\n\t\t);\n\t\ttry {\n\t\t\tconst spent: Usage = {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\tconst report = await runModelFitnessProbe({\n\t\t\t\ttrials: args.trials,\n\t\t\t\tsignal: this.abortController.signal,\n\t\t\t\tcapacityProbe:\n\t\t\t\t\tresolved.provider === \"ollama\" && resolved.contextWindow > 0\n\t\t\t\t\t\t? { registeredContextWindow: resolved.contextWindow }\n\t\t\t\t\t\t: undefined,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst callStarted = Date.now();\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\tsystemPrompt,\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel: resolved,\n\t\t\t\t\t\tthinkingLevel: \"off\",\n\t\t\t\t\t\tmaxTokens: capability.laneMaxOutputTokens,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\tlaneKind: \"fitness\",\n\t\t\t\t\t});\n\t\t\t\t\tconst callMs = Date.now() - callStarted;\n\t\t\t\t\tspent.input += completion.usage.input;\n\t\t\t\t\tspent.output += completion.usage.output;\n\t\t\t\t\tspent.cacheRead += completion.usage.cacheRead;\n\t\t\t\t\tspent.cacheWrite += completion.usage.cacheWrite;\n\t\t\t\t\tspent.totalTokens += completion.usage.totalTokens;\n\t\t\t\t\tspent.cost.input += completion.usage.cost.input;\n\t\t\t\t\tspent.cost.output += completion.usage.cost.output;\n\t\t\t\t\tspent.cost.cacheRead += completion.usage.cost.cacheRead;\n\t\t\t\t\tspent.cost.cacheWrite += completion.usage.cost.cacheWrite;\n\t\t\t\t\tspent.cost.total += completion.usage.cost.total;\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\toutputTokens: completion.usage.output,\n\t\t\t\t\t\tevalMs: callMs,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst modelRef = `${resolved.provider}/${resolved.id}`;\n\t\t\tif (!this.deps.isDisposed() && (spent.cost.total > 0 || spent.totalTokens > 0)) {\n\t\t\t\tconst identity = args.toolCallId\n\t\t\t\t\t? `toolcall:${args.toolCallId}`\n\t\t\t\t\t: `${modelRef} ${args.trials ?? \"default\"}`;\n\t\t\t\tconst reportId = deriveSpawnedUsageReportId(\"model-fitness\", this.deps.getSessionId(), identity);\n\t\t\t\tthis.deps.addSpawnedUsage(spent, { label: \"model-fitness\", reportId });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (!this.deps.isDisposed()) FitnessStore.forAgentDir(this.deps.getAgentDir()).save(modelRef, report);\n\t\t\t} catch {\n\t\t\t\t// Best-effort persistence must not fail the probe.\n\t\t\t}\n\t\t\treturn { started: true, model: modelRef, report };\n\t\t} finally {\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\tgetStoredReports(): StoredFitnessReport[] {\n\t\ttry {\n\t\t\treturn FitnessStore.forAgentDir(this.deps.getAgentDir()).getForHost();\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Model fitness probe: measures whether a candidate model can actually drive the harness's
3
- * subagent contracts — the research lane, the scout-worker lane, and the routing judge — by
3
+ * subagent contracts — the research lane, the delegated-worker lane, and the routing judge — by
4
4
  * running each real runner against the model and scoring parse/success rates plus judge
5
5
  * discrimination. Provider-free: the completion executor is injected, so this works against any
6
6
  * registered model (local Ollama models included) and against faux providers in tests.