@caupulican/pi-adaptative 0.81.38 → 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 (881) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +133 -0
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +198 -0
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +311 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +31 -2
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +823 -79
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  13. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +1043 -86
  14. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
  15. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
  16. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
  17. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
  18. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
  19. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
  20. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
  21. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
  22. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
  23. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
  24. package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
  25. package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
  26. package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
  27. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
  28. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
  29. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
  30. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
  31. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +7 -7
  32. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
  33. package/dist/cli/args.d.ts +5 -0
  34. package/dist/cli/args.d.ts.map +1 -1
  35. package/dist/cli/args.js +24 -0
  36. package/dist/cli/args.js.map +1 -1
  37. package/dist/core/agent-directory-layout.d.ts +15 -0
  38. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  39. package/dist/core/agent-directory-layout.js +72 -0
  40. package/dist/core/agent-directory-layout.js.map +1 -0
  41. package/dist/core/agent-paths.d.ts +66 -0
  42. package/dist/core/agent-paths.d.ts.map +1 -0
  43. package/dist/core/agent-paths.js +170 -0
  44. package/dist/core/agent-paths.js.map +1 -0
  45. package/dist/core/agent-session-runtime.d.ts +52 -8
  46. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  47. package/dist/core/agent-session-runtime.js +397 -79
  48. package/dist/core/agent-session-runtime.js.map +1 -1
  49. package/dist/core/agent-session-services.d.ts +1 -0
  50. package/dist/core/agent-session-services.d.ts.map +1 -1
  51. package/dist/core/agent-session-services.js +4 -3
  52. package/dist/core/agent-session-services.js.map +1 -1
  53. package/dist/core/agent-session.d.ts +255 -103
  54. package/dist/core/agent-session.d.ts.map +1 -1
  55. package/dist/core/agent-session.js +754 -1173
  56. package/dist/core/agent-session.js.map +1 -1
  57. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  58. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  59. package/dist/core/autonomy/approval-gate.js +6 -28
  60. package/dist/core/autonomy/approval-gate.js.map +1 -1
  61. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  62. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  63. package/dist/core/autonomy/bounded-completion.js +1 -1
  64. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  65. package/dist/core/autonomy/contracts.d.ts +26 -9
  66. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  67. package/dist/core/autonomy/contracts.js.map +1 -1
  68. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  69. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  70. package/dist/core/autonomy/foreground-envelope.js +8 -25
  71. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  72. package/dist/core/autonomy/gates.d.ts.map +1 -1
  73. package/dist/core/autonomy/gates.js +8 -10
  74. package/dist/core/autonomy/gates.js.map +1 -1
  75. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  76. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  77. package/dist/core/autonomy/lane-private-paths.js +16 -0
  78. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  79. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  80. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  81. package/dist/core/autonomy/lane-tool-surface.js +46 -8
  82. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  83. package/dist/core/autonomy/lane-tracker.d.ts +24 -1
  84. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  85. package/dist/core/autonomy/lane-tracker.js +43 -1
  86. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  87. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  88. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  89. package/dist/core/autonomy/risk-assessment.js +1 -123
  90. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  91. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  92. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  93. package/dist/core/autonomy/session-lane-record.js +16 -29
  94. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  95. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  96. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  97. package/dist/core/autonomy/telemetry-events.js +1 -1
  98. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  99. package/dist/core/autonomy-telemetry.d.ts +7 -7
  100. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  101. package/dist/core/autonomy-telemetry.js +9 -9
  102. package/dist/core/autonomy-telemetry.js.map +1 -1
  103. package/dist/core/background-lane-controller.d.ts +90 -156
  104. package/dist/core/background-lane-controller.d.ts.map +1 -1
  105. package/dist/core/background-lane-controller.js +192 -968
  106. package/dist/core/background-lane-controller.js.map +1 -1
  107. package/dist/core/bash-execution-controller.d.ts +4 -0
  108. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  109. package/dist/core/bash-execution-controller.js +7 -1
  110. package/dist/core/bash-execution-controller.js.map +1 -1
  111. package/dist/core/capability-contract.d.ts +4 -0
  112. package/dist/core/capability-contract.d.ts.map +1 -0
  113. package/dist/core/capability-contract.js +28 -0
  114. package/dist/core/capability-contract.js.map +1 -0
  115. package/dist/core/compaction-controller.d.ts +90 -0
  116. package/dist/core/compaction-controller.d.ts.map +1 -0
  117. package/dist/core/compaction-controller.js +452 -0
  118. package/dist/core/compaction-controller.js.map +1 -0
  119. package/dist/core/compaction-support.d.ts +24 -13
  120. package/dist/core/compaction-support.d.ts.map +1 -1
  121. package/dist/core/compaction-support.js +43 -7
  122. package/dist/core/compaction-support.js.map +1 -1
  123. package/dist/core/context/context-artifacts.d.ts +6 -2
  124. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  125. package/dist/core/context/context-artifacts.js +34 -2
  126. package/dist/core/context/context-artifacts.js.map +1 -1
  127. package/dist/core/context/context-audit.d.ts +33 -1
  128. package/dist/core/context/context-audit.d.ts.map +1 -1
  129. package/dist/core/context/context-audit.js +31 -5
  130. package/dist/core/context/context-audit.js.map +1 -1
  131. package/dist/core/context/context-store-retention.d.ts +8 -2
  132. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  133. package/dist/core/context/context-store-retention.js +158 -35
  134. package/dist/core/context/context-store-retention.js.map +1 -1
  135. package/dist/core/context/okf-memory.d.ts.map +1 -1
  136. package/dist/core/context/okf-memory.js +9 -11
  137. package/dist/core/context/okf-memory.js.map +1 -1
  138. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  139. package/dist/core/context/sqlite-runtime-index.js +6 -8
  140. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  141. package/dist/core/context-gc.d.ts +3 -0
  142. package/dist/core/context-gc.d.ts.map +1 -1
  143. package/dist/core/context-gc.js +26 -6
  144. package/dist/core/context-gc.js.map +1 -1
  145. package/dist/core/context-pipeline.d.ts +26 -4
  146. package/dist/core/context-pipeline.d.ts.map +1 -1
  147. package/dist/core/context-pipeline.js +146 -18
  148. package/dist/core/context-pipeline.js.map +1 -1
  149. package/dist/core/cost-guard.d.ts +19 -3
  150. package/dist/core/cost-guard.d.ts.map +1 -1
  151. package/dist/core/cost-guard.js +18 -3
  152. package/dist/core/cost-guard.js.map +1 -1
  153. package/dist/core/default-tool-surface.d.ts.map +1 -1
  154. package/dist/core/default-tool-surface.js +1 -0
  155. package/dist/core/default-tool-surface.js.map +1 -1
  156. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  157. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  158. package/dist/core/delegation/managed-lane-controller.js +217 -0
  159. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  160. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  161. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  162. package/dist/core/delegation/session-worker-claim.js +98 -0
  163. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  164. package/dist/core/delegation/worker-actions.d.ts +7 -5
  165. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  166. package/dist/core/delegation/worker-actions.js +20 -4
  167. package/dist/core/delegation/worker-actions.js.map +1 -1
  168. package/dist/core/delegation/worker-claim.d.ts +56 -0
  169. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  170. package/dist/core/delegation/worker-claim.js +239 -0
  171. package/dist/core/delegation/worker-claim.js.map +1 -0
  172. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  173. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  174. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  175. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  176. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  177. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  178. package/dist/core/delegation/worker-delegation-request.js +2 -0
  179. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  180. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  181. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  182. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  183. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  184. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  185. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  186. package/dist/core/delegation/worker-execution-policy.js +160 -0
  187. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  188. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  189. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  190. package/dist/core/delegation/worker-lane-projection.js +100 -0
  191. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  192. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  193. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  194. package/dist/core/delegation/worker-lifecycle.js +339 -0
  195. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  196. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  197. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  198. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  199. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  200. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  201. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  202. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  203. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  204. package/dist/core/delegation/worker-runner.d.ts +25 -14
  205. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  206. package/dist/core/delegation/worker-runner.js +122 -53
  207. package/dist/core/delegation/worker-runner.js.map +1 -1
  208. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  209. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  210. package/dist/core/delegation/worker-task-label.js +11 -0
  211. package/dist/core/delegation/worker-task-label.js.map +1 -0
  212. package/dist/core/doctor.d.ts +8 -0
  213. package/dist/core/doctor.d.ts.map +1 -1
  214. package/dist/core/doctor.js +32 -1
  215. package/dist/core/doctor.js.map +1 -1
  216. package/dist/core/extensions/index.d.ts +1 -1
  217. package/dist/core/extensions/index.d.ts.map +1 -1
  218. package/dist/core/extensions/index.js.map +1 -1
  219. package/dist/core/extensions/loader.d.ts +5 -1
  220. package/dist/core/extensions/loader.d.ts.map +1 -1
  221. package/dist/core/extensions/loader.js +68 -13
  222. package/dist/core/extensions/loader.js.map +1 -1
  223. package/dist/core/extensions/runner.d.ts.map +1 -1
  224. package/dist/core/extensions/runner.js +7 -0
  225. package/dist/core/extensions/runner.js.map +1 -1
  226. package/dist/core/extensions/storage.d.ts +8 -0
  227. package/dist/core/extensions/storage.d.ts.map +1 -0
  228. package/dist/core/extensions/storage.js +28 -0
  229. package/dist/core/extensions/storage.js.map +1 -0
  230. package/dist/core/extensions/types.d.ts +101 -1
  231. package/dist/core/extensions/types.d.ts.map +1 -1
  232. package/dist/core/extensions/types.js.map +1 -1
  233. package/dist/core/failure-corpus.d.ts +1 -15
  234. package/dist/core/failure-corpus.d.ts.map +1 -1
  235. package/dist/core/failure-corpus.js +9 -37
  236. package/dist/core/failure-corpus.js.map +1 -1
  237. package/dist/core/foreground-recovery-controller.d.ts +52 -0
  238. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  239. package/dist/core/foreground-recovery-controller.js +111 -0
  240. package/dist/core/foreground-recovery-controller.js.map +1 -0
  241. package/dist/core/gateways/channel-provider.d.ts +3 -0
  242. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  243. package/dist/core/gateways/channel-provider.js +31 -6
  244. package/dist/core/gateways/channel-provider.js.map +1 -1
  245. package/dist/core/goal-loop-controller.d.ts +17 -1
  246. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  247. package/dist/core/goal-loop-controller.js +79 -11
  248. package/dist/core/goal-loop-controller.js.map +1 -1
  249. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  250. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  251. package/dist/core/goals/goal-acceptance.js +25 -0
  252. package/dist/core/goals/goal-acceptance.js.map +1 -0
  253. package/dist/core/goals/goal-auto-continue-controller.d.ts +27 -0
  254. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  255. package/dist/core/goals/goal-auto-continue-controller.js +93 -0
  256. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  257. package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
  258. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  259. package/dist/core/goals/goal-continuation-controller.js +87 -0
  260. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  261. package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
  262. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  263. package/dist/core/goals/goal-continuation-defaults.js +42 -0
  264. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  265. package/dist/core/goals/goal-continuation-prompt.d.ts +5 -1
  266. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  267. package/dist/core/goals/goal-continuation-prompt.js +56 -15
  268. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  269. package/dist/core/goals/goal-lifecycle.d.ts +20 -0
  270. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  271. package/dist/core/goals/goal-lifecycle.js +17 -0
  272. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  273. package/dist/core/goals/goal-runtime-snapshot.d.ts +105 -4
  274. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  275. package/dist/core/goals/goal-runtime-snapshot.js +91 -6
  276. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  277. package/dist/core/goals/goal-state.d.ts +90 -1
  278. package/dist/core/goals/goal-state.d.ts.map +1 -1
  279. package/dist/core/goals/goal-state.js +78 -15
  280. package/dist/core/goals/goal-state.js.map +1 -1
  281. package/dist/core/goals/goal-tool-core.d.ts +58 -2
  282. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  283. package/dist/core/goals/goal-tool-core.js +82 -6
  284. package/dist/core/goals/goal-tool-core.js.map +1 -1
  285. package/dist/core/goals/session-goal-state.d.ts +13 -6
  286. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  287. package/dist/core/goals/session-goal-state.js +20 -28
  288. package/dist/core/goals/session-goal-state.js.map +1 -1
  289. package/dist/core/human-input.d.ts +100 -0
  290. package/dist/core/human-input.d.ts.map +1 -0
  291. package/dist/core/human-input.js +362 -0
  292. package/dist/core/human-input.js.map +1 -0
  293. package/dist/core/index.d.ts +9 -1
  294. package/dist/core/index.d.ts.map +1 -1
  295. package/dist/core/index.js +9 -1
  296. package/dist/core/index.js.map +1 -1
  297. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  298. package/dist/core/install-telemetry.d.ts.map +1 -0
  299. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  300. package/dist/core/install-telemetry.js.map +1 -0
  301. package/dist/core/keybindings.d.ts +27 -1
  302. package/dist/core/keybindings.d.ts.map +1 -1
  303. package/dist/core/keybindings.js +34 -8
  304. package/dist/core/keybindings.js.map +1 -1
  305. package/dist/core/learning/learning-audit.d.ts +2 -4
  306. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  307. package/dist/core/learning/learning-audit.js +9 -29
  308. package/dist/core/learning/learning-audit.js.map +1 -1
  309. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  310. package/dist/core/learning/learning-gate.js +1 -6
  311. package/dist/core/learning/learning-gate.js.map +1 -1
  312. package/dist/core/learning/observation-store.d.ts +12 -3
  313. package/dist/core/learning/observation-store.d.ts.map +1 -1
  314. package/dist/core/learning/observation-store.js +30 -15
  315. package/dist/core/learning/observation-store.js.map +1 -1
  316. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  317. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  318. package/dist/core/learning/session-learning-decision.js +9 -29
  319. package/dist/core/learning/session-learning-decision.js.map +1 -1
  320. package/dist/core/learning/skill-curator.d.ts +5 -1
  321. package/dist/core/learning/skill-curator.d.ts.map +1 -1
  322. package/dist/core/learning/skill-curator.js +21 -19
  323. package/dist/core/learning/skill-curator.js.map +1 -1
  324. package/dist/core/local-runtime-controller.d.ts +65 -3
  325. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  326. package/dist/core/local-runtime-controller.js +186 -26
  327. package/dist/core/local-runtime-controller.js.map +1 -1
  328. package/dist/core/memory/providers/file-store.d.ts +1 -1
  329. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  330. package/dist/core/memory/providers/file-store.js +6 -6
  331. package/dist/core/memory/providers/file-store.js.map +1 -1
  332. package/dist/core/memory-controller.d.ts.map +1 -1
  333. package/dist/core/memory-controller.js +4 -4
  334. package/dist/core/memory-controller.js.map +1 -1
  335. package/dist/core/model-capability.d.ts +34 -0
  336. package/dist/core/model-capability.d.ts.map +1 -1
  337. package/dist/core/model-capability.js +43 -1
  338. package/dist/core/model-capability.js.map +1 -1
  339. package/dist/core/model-resolver.d.ts +1 -1
  340. package/dist/core/model-resolver.d.ts.map +1 -1
  341. package/dist/core/model-resolver.js +6 -9
  342. package/dist/core/model-resolver.js.map +1 -1
  343. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  344. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  345. package/dist/core/model-router/intent-classifier.js +1 -156
  346. package/dist/core/model-router/intent-classifier.js.map +1 -1
  347. package/dist/core/model-router/tool-escalation.d.ts +15 -0
  348. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  349. package/dist/core/model-router/tool-escalation.js +23 -1
  350. package/dist/core/model-router/tool-escalation.js.map +1 -1
  351. package/dist/core/model-router-controller.d.ts +34 -7
  352. package/dist/core/model-router-controller.d.ts.map +1 -1
  353. package/dist/core/model-router-controller.js +95 -16
  354. package/dist/core/model-router-controller.js.map +1 -1
  355. package/dist/core/model-selection-controller.d.ts +4 -4
  356. package/dist/core/model-selection-controller.d.ts.map +1 -1
  357. package/dist/core/model-selection-controller.js.map +1 -1
  358. package/dist/core/model-tool-protocol.d.ts +23 -0
  359. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  360. package/dist/core/model-tool-protocol.js +43 -0
  361. package/dist/core/model-tool-protocol.js.map +1 -0
  362. package/dist/core/models/adaptation-store.d.ts +10 -5
  363. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  364. package/dist/core/models/adaptation-store.js +129 -81
  365. package/dist/core/models/adaptation-store.js.map +1 -1
  366. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  367. package/dist/core/models/default-model-suggestions.js +17 -0
  368. package/dist/core/models/default-model-suggestions.js.map +1 -1
  369. package/dist/core/models/fitness-store.d.ts +4 -11
  370. package/dist/core/models/fitness-store.d.ts.map +1 -1
  371. package/dist/core/models/fitness-store.js +87 -51
  372. package/dist/core/models/fitness-store.js.map +1 -1
  373. package/dist/core/models/host-state-store.d.ts +34 -0
  374. package/dist/core/models/host-state-store.d.ts.map +1 -0
  375. package/dist/core/models/host-state-store.js +86 -0
  376. package/dist/core/models/host-state-store.js.map +1 -0
  377. package/dist/core/models/llamacpp-runtime.d.ts +180 -0
  378. package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
  379. package/dist/core/models/llamacpp-runtime.js +475 -0
  380. package/dist/core/models/llamacpp-runtime.js.map +1 -0
  381. package/dist/core/models/local-registration.d.ts +40 -0
  382. package/dist/core/models/local-registration.d.ts.map +1 -1
  383. package/dist/core/models/local-registration.js +94 -5
  384. package/dist/core/models/local-registration.js.map +1 -1
  385. package/dist/core/models/local-runtime.d.ts.map +1 -1
  386. package/dist/core/models/local-runtime.js +6 -5
  387. package/dist/core/models/local-runtime.js.map +1 -1
  388. package/dist/core/models/model-ref.d.ts +7 -0
  389. package/dist/core/models/model-ref.d.ts.map +1 -1
  390. package/dist/core/models/model-ref.js +26 -0
  391. package/dist/core/models/model-ref.js.map +1 -1
  392. package/dist/core/models/needle-runtime.d.ts +257 -0
  393. package/dist/core/models/needle-runtime.d.ts.map +1 -0
  394. package/dist/core/models/needle-runtime.js +519 -0
  395. package/dist/core/models/needle-runtime.js.map +1 -0
  396. package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
  397. package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
  398. package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
  399. package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
  400. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  401. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  402. package/dist/core/orchestration/agent-resume.js +90 -0
  403. package/dist/core/orchestration/agent-resume.js.map +1 -0
  404. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  405. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  406. package/dist/core/orchestration/capability-gateway.js +152 -0
  407. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  408. package/dist/core/orchestration/contracts.d.ts +343 -0
  409. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  410. package/dist/core/orchestration/contracts.js +135 -0
  411. package/dist/core/orchestration/contracts.js.map +1 -0
  412. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  413. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  414. package/dist/core/orchestration/delegation-ledger.js +197 -0
  415. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  416. package/dist/core/orchestration/event-store.d.ts +83 -0
  417. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  418. package/dist/core/orchestration/event-store.js +560 -0
  419. package/dist/core/orchestration/event-store.js.map +1 -0
  420. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  421. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  422. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  423. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  424. package/dist/core/orchestration/model-binding.d.ts +15 -0
  425. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  426. package/dist/core/orchestration/model-binding.js +29 -0
  427. package/dist/core/orchestration/model-binding.js.map +1 -0
  428. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  429. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  430. package/dist/core/orchestration/policy-compiler.js +191 -0
  431. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  432. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  433. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  434. package/dist/core/orchestration/policy-gate.js +24 -0
  435. package/dist/core/orchestration/policy-gate.js.map +1 -0
  436. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  437. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  438. package/dist/core/orchestration/profile-registry.js +393 -0
  439. package/dist/core/orchestration/profile-registry.js.map +1 -0
  440. package/dist/core/orchestration/profile-store.d.ts +31 -0
  441. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  442. package/dist/core/orchestration/profile-store.js +136 -0
  443. package/dist/core/orchestration/profile-store.js.map +1 -0
  444. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  445. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  446. package/dist/core/orchestration/risk-budget.js +48 -0
  447. package/dist/core/orchestration/risk-budget.js.map +1 -0
  448. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  449. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  450. package/dist/core/orchestration/task-runtime.js +1600 -0
  451. package/dist/core/orchestration/task-runtime.js.map +1 -0
  452. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  453. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  454. package/dist/core/orchestration/work-state-projection.js +116 -0
  455. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  456. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  457. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  458. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  459. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  460. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  461. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  462. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  463. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  464. package/dist/core/package-manager.d.ts.map +1 -1
  465. package/dist/core/package-manager.js +11 -10
  466. package/dist/core/package-manager.js.map +1 -1
  467. package/dist/core/process-identity.d.ts +11 -0
  468. package/dist/core/process-identity.d.ts.map +1 -0
  469. package/dist/core/process-identity.js +26 -0
  470. package/dist/core/process-identity.js.map +1 -0
  471. package/dist/core/process-matrix/codes.d.ts +83 -0
  472. package/dist/core/process-matrix/codes.d.ts.map +1 -0
  473. package/dist/core/process-matrix/codes.js +15 -0
  474. package/dist/core/process-matrix/codes.js.map +1 -0
  475. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  476. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  477. package/dist/core/process-matrix/resume-launcher.js +62 -0
  478. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  479. package/dist/core/process-matrix/runtime.d.ts +78 -0
  480. package/dist/core/process-matrix/runtime.d.ts.map +1 -0
  481. package/dist/core/process-matrix/runtime.js +633 -0
  482. package/dist/core/process-matrix/runtime.js.map +1 -0
  483. package/dist/core/process-matrix/store.d.ts +25 -0
  484. package/dist/core/process-matrix/store.d.ts.map +1 -0
  485. package/dist/core/process-matrix/store.js +189 -0
  486. package/dist/core/process-matrix/store.js.map +1 -0
  487. package/dist/core/process-matrix/supervisor.d.ts +75 -0
  488. package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
  489. package/dist/core/process-matrix/supervisor.js +161 -0
  490. package/dist/core/process-matrix/supervisor.js.map +1 -0
  491. package/dist/core/profile-registry.d.ts +7 -0
  492. package/dist/core/profile-registry.d.ts.map +1 -1
  493. package/dist/core/profile-registry.js +25 -7
  494. package/dist/core/profile-registry.js.map +1 -1
  495. package/dist/core/python-runtime.d.ts.map +1 -1
  496. package/dist/core/python-runtime.js +3 -3
  497. package/dist/core/python-runtime.js.map +1 -1
  498. package/dist/core/reflection-controller.d.ts +33 -9
  499. package/dist/core/reflection-controller.d.ts.map +1 -1
  500. package/dist/core/reflection-controller.js +217 -127
  501. package/dist/core/reflection-controller.js.map +1 -1
  502. package/dist/core/reload-blockers.d.ts +36 -0
  503. package/dist/core/reload-blockers.d.ts.map +1 -1
  504. package/dist/core/reload-blockers.js +50 -8
  505. package/dist/core/reload-blockers.js.map +1 -1
  506. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  507. package/dist/core/research/evidence-bundle.js +1 -6
  508. package/dist/core/research/evidence-bundle.js.map +1 -1
  509. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  510. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  511. package/dist/core/research/lane-model-resolver.js +65 -0
  512. package/dist/core/research/lane-model-resolver.js.map +1 -0
  513. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  514. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  515. package/dist/core/research/model-fitness-controller.js +106 -0
  516. package/dist/core/research/model-fitness-controller.js.map +1 -0
  517. package/dist/core/research/model-fitness.d.ts +1 -1
  518. package/dist/core/research/model-fitness.d.ts.map +1 -1
  519. package/dist/core/research/model-fitness.js +4 -4
  520. package/dist/core/research/model-fitness.js.map +1 -1
  521. package/dist/core/research/research-gate.d.ts.map +1 -1
  522. package/dist/core/research/research-gate.js +7 -7
  523. package/dist/core/research/research-gate.js.map +1 -1
  524. package/dist/core/research/research-lane-controller.d.ts +62 -0
  525. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  526. package/dist/core/research/research-lane-controller.js +292 -0
  527. package/dist/core/research/research-lane-controller.js.map +1 -0
  528. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  529. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  530. package/dist/core/research/session-evidence-bundle.js +10 -46
  531. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  532. package/dist/core/resource-loader.d.ts.map +1 -1
  533. package/dist/core/resource-loader.js +15 -9
  534. package/dist/core/resource-loader.js.map +1 -1
  535. package/dist/core/risk-classifier.d.ts +6 -0
  536. package/dist/core/risk-classifier.d.ts.map +1 -0
  537. package/dist/core/risk-classifier.js +225 -0
  538. package/dist/core/risk-classifier.js.map +1 -0
  539. package/dist/core/runtime-builder.d.ts +76 -17
  540. package/dist/core/runtime-builder.d.ts.map +1 -1
  541. package/dist/core/runtime-builder.js +367 -124
  542. package/dist/core/runtime-builder.js.map +1 -1
  543. package/dist/core/scout-controller.d.ts +6 -0
  544. package/dist/core/scout-controller.d.ts.map +1 -1
  545. package/dist/core/scout-controller.js +66 -52
  546. package/dist/core/scout-controller.js.map +1 -1
  547. package/dist/core/sdk.d.ts +6 -3
  548. package/dist/core/sdk.d.ts.map +1 -1
  549. package/dist/core/sdk.js +64 -27
  550. package/dist/core/sdk.js.map +1 -1
  551. package/dist/core/session-analytics.d.ts.map +1 -1
  552. package/dist/core/session-analytics.js +28 -1
  553. package/dist/core/session-analytics.js.map +1 -1
  554. package/dist/core/session-image-store.d.ts +33 -0
  555. package/dist/core/session-image-store.d.ts.map +1 -0
  556. package/dist/core/session-image-store.js +283 -0
  557. package/dist/core/session-image-store.js.map +1 -0
  558. package/dist/core/session-role.d.ts +33 -0
  559. package/dist/core/session-role.d.ts.map +1 -0
  560. package/dist/core/session-role.js +58 -0
  561. package/dist/core/session-role.js.map +1 -0
  562. package/dist/core/session-snapshot.d.ts +34 -0
  563. package/dist/core/session-snapshot.d.ts.map +1 -0
  564. package/dist/core/session-snapshot.js +68 -0
  565. package/dist/core/session-snapshot.js.map +1 -0
  566. package/dist/core/session-supervision-runtime.d.ts +31 -0
  567. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  568. package/dist/core/session-supervision-runtime.js +97 -0
  569. package/dist/core/session-supervision-runtime.js.map +1 -0
  570. package/dist/core/settings-manager.d.ts +51 -7
  571. package/dist/core/settings-manager.d.ts.map +1 -1
  572. package/dist/core/settings-manager.js +168 -82
  573. package/dist/core/settings-manager.js.map +1 -1
  574. package/dist/core/system-prompt-builder.d.ts +12 -0
  575. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  576. package/dist/core/system-prompt-builder.js +6 -0
  577. package/dist/core/system-prompt-builder.js.map +1 -1
  578. package/dist/core/system-prompt.d.ts +14 -1
  579. package/dist/core/system-prompt.d.ts.map +1 -1
  580. package/dist/core/system-prompt.js +20 -3
  581. package/dist/core/system-prompt.js.map +1 -1
  582. package/dist/core/tasks/session-task-state.d.ts +13 -6
  583. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  584. package/dist/core/tasks/session-task-state.js +20 -22
  585. package/dist/core/tasks/session-task-state.js.map +1 -1
  586. package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
  587. package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
  588. package/dist/core/tasks/task-contract-monitor.js +56 -0
  589. package/dist/core/tasks/task-contract-monitor.js.map +1 -0
  590. package/dist/core/tasks/task-projection.d.ts +20 -0
  591. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  592. package/dist/core/tasks/task-projection.js +47 -0
  593. package/dist/core/tasks/task-projection.js.map +1 -0
  594. package/dist/core/tasks/task-state.d.ts +12 -0
  595. package/dist/core/tasks/task-state.d.ts.map +1 -1
  596. package/dist/core/tasks/task-state.js +56 -12
  597. package/dist/core/tasks/task-state.js.map +1 -1
  598. package/dist/core/tool-capability-policy.d.ts +13 -0
  599. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  600. package/dist/core/tool-capability-policy.js +85 -0
  601. package/dist/core/tool-capability-policy.js.map +1 -0
  602. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  603. package/dist/core/tool-gate-controller.js +5 -0
  604. package/dist/core/tool-gate-controller.js.map +1 -1
  605. package/dist/core/tool-protocol-controller.d.ts +91 -0
  606. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  607. package/dist/core/tool-protocol-controller.js +512 -0
  608. package/dist/core/tool-protocol-controller.js.map +1 -0
  609. package/dist/core/tool-recovery-log-records.d.ts +6 -0
  610. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  611. package/dist/core/tool-recovery-log-records.js +13 -31
  612. package/dist/core/tool-recovery-log-records.js.map +1 -1
  613. package/dist/core/tool-selection/promotion.d.ts +54 -0
  614. package/dist/core/tool-selection/promotion.d.ts.map +1 -0
  615. package/dist/core/tool-selection/promotion.js +81 -0
  616. package/dist/core/tool-selection/promotion.js.map +1 -0
  617. package/dist/core/tool-selection/tool-performance-store.d.ts +39 -6
  618. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  619. package/dist/core/tool-selection/tool-performance-store.js +153 -110
  620. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  621. package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
  622. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  623. package/dist/core/tool-selection/tool-selection-controller.js +96 -0
  624. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  625. package/dist/core/tools/ask-question.d.ts +124 -0
  626. package/dist/core/tools/ask-question.d.ts.map +1 -0
  627. package/dist/core/tools/ask-question.js +693 -0
  628. package/dist/core/tools/ask-question.js.map +1 -0
  629. package/dist/core/tools/bash.d.ts +18 -0
  630. package/dist/core/tools/bash.d.ts.map +1 -1
  631. package/dist/core/tools/bash.js +95 -16
  632. package/dist/core/tools/bash.js.map +1 -1
  633. package/dist/core/tools/delegate-status.d.ts +44 -2
  634. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  635. package/dist/core/tools/delegate-status.js +214 -19
  636. package/dist/core/tools/delegate-status.js.map +1 -1
  637. package/dist/core/tools/delegate.d.ts +15 -13
  638. package/dist/core/tools/delegate.d.ts.map +1 -1
  639. package/dist/core/tools/delegate.js +124 -22
  640. package/dist/core/tools/delegate.js.map +1 -1
  641. package/dist/core/tools/extensionify.d.ts.map +1 -1
  642. package/dist/core/tools/extensionify.js +1 -0
  643. package/dist/core/tools/extensionify.js.map +1 -1
  644. package/dist/core/tools/goal.d.ts +94 -3
  645. package/dist/core/tools/goal.d.ts.map +1 -1
  646. package/dist/core/tools/goal.js +165 -15
  647. package/dist/core/tools/goal.js.map +1 -1
  648. package/dist/core/tools/model-fitness.d.ts +7 -0
  649. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  650. package/dist/core/tools/model-fitness.js +4 -4
  651. package/dist/core/tools/model-fitness.js.map +1 -1
  652. package/dist/core/tools/orchestration-panel.d.ts +43 -0
  653. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  654. package/dist/core/tools/orchestration-panel.js +168 -0
  655. package/dist/core/tools/orchestration-panel.js.map +1 -0
  656. package/dist/core/tools/run-process.d.ts +26 -0
  657. package/dist/core/tools/run-process.d.ts.map +1 -0
  658. package/dist/core/tools/run-process.js +138 -0
  659. package/dist/core/tools/run-process.js.map +1 -0
  660. package/dist/core/tools/shell-contract-router.d.ts +6 -1
  661. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  662. package/dist/core/tools/shell-contract-router.js +23 -2
  663. package/dist/core/tools/shell-contract-router.js.map +1 -1
  664. package/dist/core/tools/shell-session.d.ts +89 -0
  665. package/dist/core/tools/shell-session.d.ts.map +1 -0
  666. package/dist/core/tools/shell-session.js +432 -0
  667. package/dist/core/tools/shell-session.js.map +1 -0
  668. package/dist/core/tools/task-steps.d.ts +6 -0
  669. package/dist/core/tools/task-steps.d.ts.map +1 -1
  670. package/dist/core/tools/task-steps.js +165 -8
  671. package/dist/core/tools/task-steps.js.map +1 -1
  672. package/dist/core/tools/tmux-dispatch.d.ts +84 -0
  673. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
  674. package/dist/core/tools/tmux-dispatch.js +91 -0
  675. package/dist/core/tools/tmux-dispatch.js.map +1 -0
  676. package/dist/core/tools/windows-shell-engine.d.ts +42 -0
  677. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
  678. package/dist/core/tools/windows-shell-engine.js +151 -0
  679. package/dist/core/tools/windows-shell-engine.js.map +1 -0
  680. package/dist/core/tools/windows-shell-state.d.ts +40 -0
  681. package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
  682. package/dist/core/tools/windows-shell-state.js +59 -0
  683. package/dist/core/tools/windows-shell-state.js.map +1 -0
  684. package/dist/core/tools/worktree-sync.d.ts +24 -0
  685. package/dist/core/tools/worktree-sync.d.ts.map +1 -0
  686. package/dist/core/tools/worktree-sync.js +338 -0
  687. package/dist/core/tools/worktree-sync.js.map +1 -0
  688. package/dist/core/trust-manager.d.ts +4 -1
  689. package/dist/core/trust-manager.d.ts.map +1 -1
  690. package/dist/core/trust-manager.js +20 -2
  691. package/dist/core/trust-manager.js.map +1 -1
  692. package/dist/core/util/atomic-file.d.ts +55 -0
  693. package/dist/core/util/atomic-file.d.ts.map +1 -0
  694. package/dist/core/util/atomic-file.js +255 -0
  695. package/dist/core/util/atomic-file.js.map +1 -0
  696. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  697. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  698. package/dist/core/util/bounded-jsonl.js +75 -0
  699. package/dist/core/util/bounded-jsonl.js.map +1 -0
  700. package/dist/core/util/minimatch-cache.d.ts +33 -0
  701. package/dist/core/util/minimatch-cache.d.ts.map +1 -0
  702. package/dist/core/util/minimatch-cache.js +0 -0
  703. package/dist/core/util/minimatch-cache.js.map +1 -0
  704. package/dist/core/util/value-guards.d.ts +5 -0
  705. package/dist/core/util/value-guards.d.ts.map +1 -0
  706. package/dist/core/util/value-guards.js +12 -0
  707. package/dist/core/util/value-guards.js.map +1 -0
  708. package/dist/core/worktree-sync/codes.d.ts +227 -0
  709. package/dist/core/worktree-sync/codes.d.ts.map +1 -0
  710. package/dist/core/worktree-sync/codes.js +14 -0
  711. package/dist/core/worktree-sync/codes.js.map +1 -0
  712. package/dist/core/worktree-sync/git-engine.d.ts +156 -0
  713. package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
  714. package/dist/core/worktree-sync/git-engine.js +1191 -0
  715. package/dist/core/worktree-sync/git-engine.js.map +1 -0
  716. package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
  717. package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
  718. package/dist/core/worktree-sync/lane-gate.js +360 -0
  719. package/dist/core/worktree-sync/lane-gate.js.map +1 -0
  720. package/dist/core/worktree-sync/runtime.d.ts +47 -0
  721. package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
  722. package/dist/core/worktree-sync/runtime.js +96 -0
  723. package/dist/core/worktree-sync/runtime.js.map +1 -0
  724. package/dist/core/worktree-sync/store.d.ts +69 -0
  725. package/dist/core/worktree-sync/store.d.ts.map +1 -0
  726. package/dist/core/worktree-sync/store.js +252 -0
  727. package/dist/core/worktree-sync/store.js.map +1 -0
  728. package/dist/core/worktree-sync/watcher.d.ts +29 -0
  729. package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
  730. package/dist/core/worktree-sync/watcher.js +93 -0
  731. package/dist/core/worktree-sync/watcher.js.map +1 -0
  732. package/dist/index.d.ts +13 -3
  733. package/dist/index.d.ts.map +1 -1
  734. package/dist/index.js +12 -2
  735. package/dist/index.js.map +1 -1
  736. package/dist/main.d.ts.map +1 -1
  737. package/dist/main.js +179 -1
  738. package/dist/main.js.map +1 -1
  739. package/dist/migrations.d.ts +7 -0
  740. package/dist/migrations.d.ts.map +1 -1
  741. package/dist/migrations.js +197 -1
  742. package/dist/migrations.js.map +1 -1
  743. package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
  744. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  745. package/dist/modes/interactive/auto-learn-controller.js +50 -8
  746. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  747. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  748. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  749. package/dist/modes/interactive/clipboard-input.js +44 -6
  750. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  751. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  752. package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
  753. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  754. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  755. package/dist/modes/interactive/components/settings-selector.js +2 -2
  756. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  757. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  758. package/dist/modes/interactive/config-backup.js +5 -4
  759. package/dist/modes/interactive/config-backup.js.map +1 -1
  760. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  761. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  762. package/dist/modes/interactive/extension-ui-host.js +76 -15
  763. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  764. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  765. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  766. package/dist/modes/interactive/interactive-mode.js +67 -1
  767. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  768. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  769. package/dist/modes/interactive/key-handlers.js +1 -1
  770. package/dist/modes/interactive/key-handlers.js.map +1 -1
  771. package/dist/modes/interactive/local-model-commands.d.ts +43 -0
  772. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  773. package/dist/modes/interactive/local-model-commands.js +290 -3
  774. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  775. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  776. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  777. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  778. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  779. package/dist/modes/interactive/report-commands.js +21 -0
  780. package/dist/modes/interactive/report-commands.js.map +1 -1
  781. package/dist/modes/interactive/session-flow-commands.d.ts +17 -2
  782. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  783. package/dist/modes/interactive/session-flow-commands.js +74 -21
  784. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  785. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  786. package/dist/modes/interactive/session-io-commands.js +16 -6
  787. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  788. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  789. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  790. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  791. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  792. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  793. package/dist/modes/interactive/startup-checks.js +1 -1
  794. package/dist/modes/interactive/startup-checks.js.map +1 -1
  795. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  796. package/dist/modes/rpc/rpc-mode.js +82 -23
  797. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  798. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  799. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  800. package/dist/modes/rpc/rpc-types.js +138 -1
  801. package/dist/modes/rpc/rpc-types.js.map +1 -1
  802. package/dist/utils/clipboard-image.d.ts.map +1 -1
  803. package/dist/utils/clipboard-image.js +2 -13
  804. package/dist/utils/clipboard-image.js.map +1 -1
  805. package/dist/utils/clipboard-native.d.ts +1 -0
  806. package/dist/utils/clipboard-native.d.ts.map +1 -1
  807. package/dist/utils/clipboard-native.js.map +1 -1
  808. package/dist/utils/clipboard.d.ts +1 -0
  809. package/dist/utils/clipboard.d.ts.map +1 -1
  810. package/dist/utils/clipboard.js +52 -1
  811. package/dist/utils/clipboard.js.map +1 -1
  812. package/dist/utils/fs-watch.d.ts +11 -0
  813. package/dist/utils/fs-watch.d.ts.map +1 -1
  814. package/dist/utils/fs-watch.js +20 -2
  815. package/dist/utils/fs-watch.js.map +1 -1
  816. package/dist/utils/highlight-js-languages.d.ts +4 -0
  817. package/dist/utils/highlight-js-languages.d.ts.map +1 -0
  818. package/dist/utils/highlight-js-languages.js +573 -0
  819. package/dist/utils/highlight-js-languages.js.map +1 -0
  820. package/dist/utils/platform.d.ts +3 -0
  821. package/dist/utils/platform.d.ts.map +1 -0
  822. package/dist/utils/platform.js +8 -0
  823. package/dist/utils/platform.js.map +1 -0
  824. package/dist/utils/shell.d.ts +7 -1
  825. package/dist/utils/shell.d.ts.map +1 -1
  826. package/dist/utils/shell.js +21 -6
  827. package/dist/utils/shell.js.map +1 -1
  828. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  829. package/dist/utils/syntax-highlight.js +53 -5
  830. package/dist/utils/syntax-highlight.js.map +1 -1
  831. package/dist/utils/tools-manager.d.ts.map +1 -1
  832. package/dist/utils/tools-manager.js +112 -1
  833. package/dist/utils/tools-manager.js.map +1 -1
  834. package/dist/utils/work-directory.d.ts +11 -0
  835. package/dist/utils/work-directory.d.ts.map +1 -1
  836. package/dist/utils/work-directory.js +30 -9
  837. package/dist/utils/work-directory.js.map +1 -1
  838. package/docs/UI_POLISH_ORCHESTRATION.md +44 -0
  839. package/docs/UI_QUALITY_ORCHESTRATION.md +30 -0
  840. package/docs/docs.json +4 -0
  841. package/docs/extensions.md +62 -2
  842. package/docs/harness-architecture.md +156 -0
  843. package/docs/keybindings.md +11 -1
  844. package/docs/process-matrix.md +153 -0
  845. package/docs/rpc.md +45 -2
  846. package/docs/sessions.md +15 -0
  847. package/docs/settings.md +128 -11
  848. package/docs/task-steps.md +8 -0
  849. package/docs/telemetry.md +19 -0
  850. package/docs/tmux-agent-manager.md +92 -2
  851. package/docs/ui-reference/README.md +9 -0
  852. package/docs/ui-reference/orchestration-after.txt +7 -0
  853. package/docs/ui-reference/orchestration-before.txt +7 -0
  854. package/docs/ui-reference/orchestration-reference.txt +6 -0
  855. package/docs/usage.md +14 -2
  856. package/docs/windows.md +52 -3
  857. package/docs/work-directory.md +42 -2
  858. package/docs/worktree-sync.md +250 -0
  859. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  860. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  861. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  862. package/examples/extensions/question.ts +34 -245
  863. package/examples/extensions/questionnaire.ts +41 -407
  864. package/examples/extensions/sandbox/package-lock.json +2 -2
  865. package/examples/extensions/sandbox/package.json +1 -1
  866. package/examples/extensions/with-deps/package-lock.json +2 -2
  867. package/examples/extensions/with-deps/package.json +1 -1
  868. package/npm-shrinkwrap.json +12 -12
  869. package/package.json +10 -4
  870. package/dist/core/delegation/session-worker-result.d.ts +0 -16
  871. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  872. package/dist/core/delegation/session-worker-result.js +0 -53
  873. package/dist/core/delegation/session-worker-result.js.map +0 -1
  874. package/dist/core/delegation/worker-result.d.ts +0 -15
  875. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  876. package/dist/core/delegation/worker-result.js +0 -161
  877. package/dist/core/delegation/worker-result.js.map +0 -1
  878. package/dist/core/telemetry.d.ts.map +0 -1
  879. package/dist/core/telemetry.js.map +0 -1
  880. package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
  881. package/docs/integration-sweep-resume-2026-07-09.md +0 -407
@@ -4,9 +4,117 @@ import * as fs from "node:fs";
4
4
  import { homedir } from "node:os";
5
5
  import * as path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
- import { getProcessWorkRun } from "@caupulican/pi-adaptative";
7
+ import { getProcessWorkRun, PI_ORCHESTRATION_AGENT_ID_ENV, } from "@caupulican/pi-adaptative";
8
8
  import { Type } from "typebox";
9
+ import { buildGrant, buildGrantUsageEntry, buildLaunchProfileFlags, buildTombstone, countGrantUsages, DEFAULT_READ_BIASED_TOOLS, decodeTmuxWorkerUsageClaim, describeGrant, GRANT_CUSTOM_TYPE, GRANT_USAGE_CUSTOM_TYPE, grantCovers, isTmuxDispatchGrant, isTmuxDispatchGrantTombstone, launchProfileSourceFromGrant, ONE_SHOT_LAUNCH_PROFILE_SOURCE, } from "./dispatch-grant.js";
9
10
  export const piConfig = { tools: ["tmux_agent_manager"] };
11
+ function agentLaneId(jobId, agentId) {
12
+ return `tmux:${jobId}:${agentId}`;
13
+ }
14
+ function managedDispatch(job, agent) {
15
+ const sequence = agent.currentTurn ?? 1;
16
+ const instructions = agent.dispatchInstructions ?? job.task;
17
+ const authorizationId = agent.dispatchAuthorizationId ?? `legacy-job:${job.id}:turn:${sequence}`;
18
+ return {
19
+ sequence,
20
+ instructions,
21
+ profileId: `tmux:${agent.provider}`,
22
+ provider: agent.provider,
23
+ authorizationId,
24
+ authorizationKind: agent.dispatchAuthorizationKind ?? "legacy-recovery",
25
+ allowedTools: agent.dispatchAllowedTools ?? DEFAULT_READ_BIASED_TOOLS,
26
+ writePaths: agent.dispatchWritePaths ?? [],
27
+ ...(agent.dispatchMaxCostUsd !== undefined ? { maxCostUsd: agent.dispatchMaxCostUsd } : {}),
28
+ leaseTtlMs: agent.dispatchLeaseTtlMs ?? job.deadlineSeconds * 1_000,
29
+ };
30
+ }
31
+ function managedAuthorization(grant, fallbackId) {
32
+ const launchSource = grant ? launchProfileSourceFromGrant(grant) : ONE_SHOT_LAUNCH_PROFILE_SOURCE;
33
+ return {
34
+ authorizationId: grant?.grantId ?? fallbackId,
35
+ authorizationKind: grant ? "standing-grant" : "one-shot-owner-approval",
36
+ launchSource,
37
+ allowedTools: [...(launchSource.allowedTools?.length ? launchSource.allowedTools : DEFAULT_READ_BIASED_TOOLS)],
38
+ writePaths: [...(launchSource.writePaths ?? [])],
39
+ ...(grant?.budget.maxUsdAdvisory !== undefined ? { maxCostUsd: grant.budget.maxUsdAdvisory } : {}),
40
+ };
41
+ }
42
+ function applyManagedAuthorization(agent, authorization, args) {
43
+ agent.dispatchAuthorizationId = authorization.authorizationId;
44
+ agent.dispatchAuthorizationKind = authorization.authorizationKind;
45
+ agent.dispatchAllowedTools = [...authorization.allowedTools];
46
+ agent.dispatchWritePaths = [...authorization.writePaths];
47
+ if (authorization.maxCostUsd !== undefined)
48
+ agent.dispatchMaxCostUsd = authorization.maxCostUsd;
49
+ else
50
+ delete agent.dispatchMaxCostUsd;
51
+ agent.dispatchInstructions = args.instructions;
52
+ agent.dispatchGoalId = args.goalId;
53
+ agent.dispatchLeaseTtlMs = args.leaseTtlMs;
54
+ }
55
+ function reportManagedDispatchReservations(bridge, job, agents) {
56
+ if (!bridge.reportManagedLane)
57
+ return;
58
+ const attemptedLaneIds = [];
59
+ try {
60
+ for (const agent of agents) {
61
+ const laneId = agentLaneId(job.id, agent.id);
62
+ attemptedLaneIds.push(laneId);
63
+ bridge.reportManagedLane({
64
+ laneId,
65
+ phase: "dispatch",
66
+ goalId: agent.dispatchGoalId,
67
+ worktreeLaneKey: agent.worktreeLane,
68
+ dispatch: managedDispatch(job, agent),
69
+ });
70
+ }
71
+ }
72
+ catch (error) {
73
+ for (const laneId of attemptedLaneIds) {
74
+ try {
75
+ bridge.reportManagedLane({
76
+ laneId,
77
+ phase: "terminal",
78
+ status: "failed",
79
+ reasonCode: "managed_process_launch_reservation_failed",
80
+ });
81
+ }
82
+ catch {
83
+ // Preserve the reservation error; durable leases fence any compensation failure.
84
+ }
85
+ }
86
+ throw error;
87
+ }
88
+ }
89
+ function reportManagedLaunchFailure(bridge, job, reasonCode) {
90
+ if (!bridge.reportManagedLane)
91
+ return;
92
+ for (const agent of job.agents) {
93
+ reportManagedAgentFailure(bridge, job.id, agent.id, reasonCode);
94
+ }
95
+ }
96
+ function reportManagedAgentFailure(bridge, jobId, agentId, reasonCode) {
97
+ if (!bridge.reportManagedLane)
98
+ return;
99
+ try {
100
+ bridge.reportManagedLane({
101
+ laneId: agentLaneId(jobId, agentId),
102
+ phase: "terminal",
103
+ status: "failed",
104
+ reasonCode,
105
+ });
106
+ }
107
+ catch {
108
+ // Preserve the launch failure; durable leases fence any terminal-report failure.
109
+ }
110
+ }
111
+ function sameStringValues(left, right) {
112
+ if (left.length !== right.length)
113
+ return false;
114
+ const sortedLeft = [...left].sort();
115
+ const sortedRight = [...right].sort();
116
+ return sortedLeft.every((value, index) => value === sortedRight[index]);
117
+ }
10
118
  const EXTENSION_ROOT = path.dirname(fileURLToPath(import.meta.url));
11
119
  export function getTmuxAgentManagerDataRoot() {
12
120
  const agentDir = process.env.PI_ADAPTATIVE_CODING_AGENT_DIR ||
@@ -161,6 +269,10 @@ function runTmux(args, timeoutMs = 5_000) {
161
269
  args: [tmux, ...args],
162
270
  };
163
271
  }
272
+ function requireTmuxRun(result, action) {
273
+ if (!result.ok)
274
+ throw new Error(`${action} failed: ${result.error || result.stderr || `exit ${result.status}`}`);
275
+ }
164
276
  function detectTmux() {
165
277
  const tmuxBin = process.env.PI_TMUX_MANAGER_TMUX_BIN || findExecutable("tmux");
166
278
  const errors = [];
@@ -343,7 +455,7 @@ function normalizeAgents(params) {
343
455
  throw new Error(`agent ${name} needs command when provider=custom`);
344
456
  const tools = Array.isArray(agent.tools) && agent.tools.length > 0 ? agent.tools : undefined;
345
457
  const command = tools ? `${baseCommand} --tools ${tools.join(",")}` : baseCommand;
346
- return { provider, name, command, cwd: agent.cwd, tools };
458
+ return { provider, name, command, cwd: agent.cwd, tools, worktreeLane: agent.worktreeLane };
347
459
  });
348
460
  }
349
461
  function defaultProviderInvocation(provider) {
@@ -543,6 +655,7 @@ function buildFireTaskPlan(ctx, params) {
543
655
  promptPath: path.join(jobDir, `${slug}.prompt.md`),
544
656
  logPath: path.join(jobDir, `${slug}.log`),
545
657
  resultPath: path.join(jobDir, `${slug}.result.json`),
658
+ worktreeLane: agent.worktreeLane,
546
659
  };
547
660
  });
548
661
  const job = {
@@ -613,9 +726,76 @@ function targetDisplayName(agent, index) {
613
726
  function tmuxSessionExists(name) {
614
727
  return runTmux(["has-session", "-t", name], 2_000).ok;
615
728
  }
729
+ function tmuxPaneExists(sessionName, paneId) {
730
+ const result = runTmux(["list-panes", "-t", sessionName, "-F", "#{pane_id}"], 2_000);
731
+ if (!result.ok)
732
+ return false;
733
+ return result.stdout
734
+ .split(/\s+/)
735
+ .map((line) => line.trim())
736
+ .includes(paneId);
737
+ }
738
+ /** True when tmux already has a pipe-pane consumer attached to this pane (tmux's own `#{pane_pipe}`
739
+ * format flag). Session-level reconcile MUST check this before re-arming: a pane that still has an
740
+ * active pipe already has a live watcher; replacing it would close that watcher's stdin and race its
741
+ * own EOF-triggered `finish(failed, pane-stream-ended)` against the real marker that may be about to
742
+ * arrive, possibly recording a false failure for a job that was about to succeed on its own. Re-arming
743
+ * is only safe (and only useful) when tmux reports no pipe is currently attached. */
744
+ function tmuxPaneHasPipe(paneId) {
745
+ const result = runTmux(["display-message", "-p", "-t", paneId, "#{pane_pipe}"], 2_000);
746
+ return result.ok && result.stdout.trim() === "1";
747
+ }
748
+ function turnMarkers(job, agent, turn) {
749
+ if (turn <= 1)
750
+ return { doneMarker: agent.doneMarker, blockedMarker: agent.blockedMarker };
751
+ const base = `TMUX_${crypto.createHash("sha1").update(`${job.id}:${agent.id}:${turn}`).digest("hex").slice(0, 10).toUpperCase()}`;
752
+ return { doneMarker: `${base}_DONE`, blockedMarker: `${base}_BLOCKED` };
753
+ }
754
+ function turnResultPath(jobDir, agentId, turn, baseResultPath) {
755
+ return turn <= 1 ? baseResultPath : path.join(jobDir, `${agentId}.turn-${turn}.result.json`);
756
+ }
757
+ function turnPromptPath(jobDir, agentId, turn, basePromptPath) {
758
+ return turn <= 1 ? basePromptPath : path.join(jobDir, `${agentId}.turn-${turn}.prompt.md`);
759
+ }
760
+ function turnWatcherPath(job, turn) {
761
+ return turn <= 1 ? job.watcherPath : path.join(job.jobDir, `pane-watcher.turn-${turn}.sh`);
762
+ }
763
+ /** The result-file path the CURRENT turn's watcher will write to for this agent (turn 1 keeps the
764
+ * fixed back-compat path). Stop handling must target this path, not the fixed one, or a stop signal
765
+ * issued mid-follow-up would land on a stale turn's file that nothing is watching anymore. */
766
+ function currentResultPath(job, agent) {
767
+ return turnResultPath(job.jobDir, agent.id, agent.currentTurn ?? 1, agent.resultPath);
768
+ }
769
+ function persistAgentTurnFailure(jobId, agentId, turn, reason) {
770
+ persistJobPatch(jobId, (current) => {
771
+ const agent = current.agents.find((entry) => entry.id === agentId);
772
+ if (!agent || agent.currentTurn !== turn)
773
+ return undefined;
774
+ const result = {
775
+ status: "failed",
776
+ detectedAt: new Date().toISOString(),
777
+ reason,
778
+ };
779
+ fs.writeFileSync(currentResultPath(current, agent), `${JSON.stringify(result, null, 2)}\n`, { mode: 0o600 });
780
+ agent.result = result;
781
+ delete agent.pendingTurn;
782
+ return current;
783
+ });
784
+ }
785
+ /** Atomically read-modify-write job.json, always from a FRESH read (never from a caller's possibly
786
+ * stale in-memory copy), mirroring the temp+rename pattern the original notify path used. */
787
+ function persistJobPatch(jobId, mutate) {
788
+ const jobPath = path.join(jobsRoot(), jobId, "job.json");
789
+ const current = JSON.parse(fs.readFileSync(jobPath, "utf8"));
790
+ const mutated = mutate(current) ?? current;
791
+ const temporaryPath = `${jobPath}.tmp-${process.pid}-${Date.now()}`;
792
+ fs.writeFileSync(temporaryPath, `${JSON.stringify(mutated, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
793
+ fs.renameSync(temporaryPath, jobPath);
794
+ return mutated;
795
+ }
616
796
  function sendCommandToPane(paneId, command) {
617
- runTmux(["send-keys", "-t", paneId, "-l", command]);
618
- runTmux(["send-keys", "-t", paneId, "Enter"]);
797
+ requireTmuxRun(runTmux(["send-keys", "-t", paneId, "-l", command]), `tmux command injection for ${paneId}`);
798
+ requireTmuxRun(runTmux(["send-keys", "-t", paneId, "Enter"]), `tmux command submit for ${paneId}`);
619
799
  }
620
800
  function launchTmuxSession(sessionName, cwd, panes) {
621
801
  if (tmuxSessionExists(sessionName))
@@ -627,33 +807,102 @@ function launchTmuxSession(sessionName, cwd, panes) {
627
807
  runs.push(create);
628
808
  if (!create.ok)
629
809
  throw new Error(`tmux new-session failed: ${create.error || create.stderr || `exit ${create.status}`}`);
630
- const firstPane = create.stdout.trim();
631
- paneIds.push(firstPane);
632
- sendCommandToPane(firstPane, first.command);
633
- for (const pane of panes.slice(1)) {
634
- const split = runTmux(["split-window", "-d", "-P", "-F", "#{pane_id}", "-t", `${sessionName}:0`, "-c", pane.cwd || cwd], 5_000);
635
- runs.push(split);
636
- if (!split.ok)
637
- throw new Error(`tmux split-window failed: ${split.error || split.stderr || `exit ${split.status}`}`);
638
- const paneId = split.stdout.trim();
639
- paneIds.push(paneId);
640
- sendCommandToPane(paneId, pane.command);
810
+ try {
811
+ const firstPane = create.stdout.trim();
812
+ paneIds.push(firstPane);
813
+ sendCommandToPane(firstPane, first.command);
814
+ for (const pane of panes.slice(1)) {
815
+ const split = runTmux(["split-window", "-d", "-P", "-F", "#{pane_id}", "-t", `${sessionName}:0`, "-c", pane.cwd || cwd], 5_000);
816
+ runs.push(split);
817
+ if (!split.ok)
818
+ throw new Error(`tmux split-window failed: ${split.error || split.stderr || `exit ${split.status}`}`);
819
+ const paneId = split.stdout.trim();
820
+ paneIds.push(paneId);
821
+ sendCommandToPane(paneId, pane.command);
822
+ }
823
+ runs.push(runTmux(["select-layout", "-t", `${sessionName}:0`, "tiled"], 3_000));
824
+ return { runs, paneIds };
825
+ }
826
+ catch (error) {
827
+ runTmux(["kill-session", "-t", sessionName], 5_000);
828
+ throw error;
641
829
  }
642
- runs.push(runTmux(["select-layout", "-t", `${sessionName}:0`, "tiled"], 3_000));
643
- return { runs, paneIds };
644
830
  }
645
831
  function injectPromptToPane(paneId, prompt, provider) {
646
832
  const text = interactivePromptText(prompt);
647
833
  if (provider === "claude") {
648
834
  const bufferName = `pi-tmux-${crypto.randomBytes(4).toString("hex")}`;
649
- runTmux(["set-buffer", "-b", bufferName, text], 10_000);
650
- runTmux(["paste-buffer", "-b", bufferName, "-t", paneId], 10_000);
651
- runTmux(["send-keys", "-t", paneId, "Enter"], 3_000);
652
- runTmux(["delete-buffer", "-b", bufferName], 3_000);
835
+ requireTmuxRun(runTmux(["set-buffer", "-b", bufferName, text], 10_000), "tmux prompt buffer creation");
836
+ try {
837
+ requireTmuxRun(runTmux(["paste-buffer", "-b", bufferName, "-t", paneId], 10_000), `tmux prompt injection for ${paneId}`);
838
+ requireTmuxRun(runTmux(["send-keys", "-t", paneId, "Enter"], 3_000), `tmux prompt submit for ${paneId}`);
839
+ }
840
+ finally {
841
+ runTmux(["delete-buffer", "-b", bufferName], 3_000);
842
+ }
653
843
  return;
654
844
  }
655
- runTmux(["send-keys", "-t", paneId, "-l", text], 10_000);
656
- runTmux(["send-keys", "-t", paneId, provider === "agy" ? "C-m" : "Enter"], 3_000);
845
+ requireTmuxRun(runTmux(["send-keys", "-t", paneId, "-l", text], 10_000), `tmux prompt injection for ${paneId}`);
846
+ requireTmuxRun(runTmux(["send-keys", "-t", paneId, provider === "agy" ? "C-m" : "Enter"], 3_000), `tmux prompt submit for ${paneId}`);
847
+ }
848
+ /** Write a fresh per-turn prompt + single-agent watcher script and arm `pipe-pane -O` for it. Used by
849
+ * send_followup to open a NEW turn on an already-live pane. Does not inject the prompt text into the
850
+ * pane itself — callers do that separately via injectPromptToPane, after this has armed the watcher,
851
+ * so the completion contract is listening before the worker can possibly reply. */
852
+ function dispatchAgentTurn(job, agent, turn, promptText) {
853
+ if (!agent.paneId)
854
+ throw new Error(`tmux agent ${agent.name} has no recorded pane id`);
855
+ const markers = turnMarkers(job, agent, turn);
856
+ const resultPath = turnResultPath(job.jobDir, agent.id, turn, agent.resultPath);
857
+ const promptPath = turnPromptPath(job.jobDir, agent.id, turn, agent.promptPath);
858
+ const watcherPath = turnWatcherPath(job, turn);
859
+ fs.writeFileSync(promptPath, `${promptText}\n`, { mode: 0o600 });
860
+ const turnSpec = {
861
+ id: job.id,
862
+ sessionName: job.sessionName,
863
+ deadlineSeconds: job.deadlineSeconds,
864
+ agents: [
865
+ { ...agent, doneMarker: markers.doneMarker, blockedMarker: markers.blockedMarker, resultPath, promptPath },
866
+ ],
867
+ };
868
+ fs.writeFileSync(watcherPath, makePaneWatcherScript(turnSpec), { mode: 0o700 });
869
+ fs.chmodSync(watcherPath, 0o700);
870
+ const armed = runTmux([
871
+ "pipe-pane",
872
+ "-O",
873
+ "-t",
874
+ agent.paneId,
875
+ `sh ${quoteShell(watcherPath)} ${quoteShell(agent.id)}`,
876
+ ]);
877
+ if (!armed.ok)
878
+ throw new Error(`Failed to arm completion watcher for turn ${turn}: ${armed.error || armed.stderr || armed.stdout}`);
879
+ return { promptPath, resultPath, watcherPath };
880
+ }
881
+ /** Session-level reconcile's resume step: re-arm `pipe-pane` for an agent whose current turn is still
882
+ * pending on a pane tmux confirms is alive AND has no pipe already attached (see tmuxPaneHasPipe). Only
883
+ * regenerates the watcher SCRIPT file if it is missing (e.g. this is the first reconcile after a reload
884
+ * whose disk state predates a crash) — the prompt was already injected once and is not re-sent. */
885
+ function rearmAgentWatcher(job, agent) {
886
+ if (!agent.paneId)
887
+ return;
888
+ const turn = agent.currentTurn ?? 1;
889
+ const markers = turnMarkers(job, agent, turn);
890
+ const resultPath = turnResultPath(job.jobDir, agent.id, turn, agent.resultPath);
891
+ const promptPath = turnPromptPath(job.jobDir, agent.id, turn, agent.promptPath);
892
+ const watcherPath = turnWatcherPath(job, turn);
893
+ if (!fs.existsSync(watcherPath)) {
894
+ const turnSpec = {
895
+ id: job.id,
896
+ sessionName: job.sessionName,
897
+ deadlineSeconds: job.deadlineSeconds,
898
+ agents: [
899
+ { ...agent, doneMarker: markers.doneMarker, blockedMarker: markers.blockedMarker, resultPath, promptPath },
900
+ ],
901
+ };
902
+ fs.writeFileSync(watcherPath, makePaneWatcherScript(turnSpec), { mode: 0o700 });
903
+ fs.chmodSync(watcherPath, 0o700);
904
+ }
905
+ runTmux(["pipe-pane", "-O", "-t", agent.paneId, `sh ${quoteShell(watcherPath)} ${quoteShell(agent.id)}`]);
657
906
  }
658
907
  function stopTmuxSession(sessionName, dryRun, confirm) {
659
908
  if (!sessionName)
@@ -675,10 +924,11 @@ function isAlreadyExistsError(error) {
675
924
  }
676
925
  function markStopRequested(job) {
677
926
  for (const agent of job.agents) {
678
- if (fs.existsSync(agent.resultPath))
927
+ const resultPath = currentResultPath(job, agent);
928
+ if (fs.existsSync(resultPath))
679
929
  continue;
680
930
  try {
681
- fs.writeFileSync(`${agent.resultPath}.stop-requested`, `${new Date().toISOString()}\n`, {
931
+ fs.writeFileSync(`${resultPath}.stop-requested`, `${new Date().toISOString()}\n`, {
682
932
  encoding: "utf8",
683
933
  mode: 0o600,
684
934
  flag: "wx",
@@ -692,11 +942,12 @@ function markStopRequested(job) {
692
942
  }
693
943
  function clearStopRequested(job) {
694
944
  for (const agent of job.agents)
695
- fs.rmSync(`${agent.resultPath}.stop-requested`, { force: true });
945
+ fs.rmSync(`${currentResultPath(job, agent)}.stop-requested`, { force: true });
696
946
  }
697
947
  function persistStoppedResults(job) {
698
948
  for (const agent of job.agents) {
699
- if (!fs.existsSync(agent.resultPath)) {
949
+ const resultPath = currentResultPath(job, agent);
950
+ if (!fs.existsSync(resultPath)) {
700
951
  const result = {
701
952
  jobId: job.id,
702
953
  agentId: agent.id,
@@ -709,7 +960,7 @@ function persistStoppedResults(job) {
709
960
  notifiedBy: "stop-action-event",
710
961
  };
711
962
  try {
712
- fs.writeFileSync(agent.resultPath, `${JSON.stringify(result, null, 2)}\n`, {
963
+ fs.writeFileSync(resultPath, `${JSON.stringify(result, null, 2)}\n`, {
713
964
  encoding: "utf8",
714
965
  mode: 0o600,
715
966
  flag: "wx",
@@ -720,7 +971,7 @@ function persistStoppedResults(job) {
720
971
  throw error;
721
972
  }
722
973
  }
723
- fs.rmSync(`${agent.resultPath}.stop-requested`, { force: true });
974
+ fs.rmSync(`${resultPath}.stop-requested`, { force: true });
724
975
  }
725
976
  }
726
977
  function stopTmuxSessionWithJobSignals(sessionName, jobs, dryRun, confirm) {
@@ -769,8 +1020,10 @@ function loadJob(id) {
769
1020
  if (!Array.isArray(parsed.agents))
770
1021
  throw new Error(`tmux job has invalid agents: ${id}`);
771
1022
  for (const agent of parsed.agents) {
1023
+ // Read from the CURRENT turn's result path (turn 1 is the fixed back-compat path) so a job
1024
+ // mid-follow-up is correctly seen as non-terminal until the NEW turn settles.
772
1025
  try {
773
- agent.result = JSON.parse(fs.readFileSync(agent.resultPath, "utf8"));
1026
+ agent.result = JSON.parse(fs.readFileSync(currentResultPath(parsed, agent), "utf8"));
774
1027
  }
775
1028
  catch {
776
1029
  delete agent.result;
@@ -815,7 +1068,13 @@ function listJobs() {
815
1068
  workspaceName: job.workspaceName,
816
1069
  sessionName: job.sessionName,
817
1070
  createdAt: job.createdAt,
818
- agents: job.agents.map((agent) => ({ name: agent.name, status: agent.result?.status || "pending" })),
1071
+ orphaned: Boolean(job.orphanedAt),
1072
+ dismissed: Boolean(job.dismissedAt),
1073
+ agents: job.agents.map((agent) => ({
1074
+ name: agent.name,
1075
+ status: agent.result?.status || "pending",
1076
+ turn: agent.currentTurn ?? 1,
1077
+ })),
819
1078
  };
820
1079
  }
821
1080
  catch (error) {
@@ -845,7 +1104,112 @@ function setVariable(jobId, name, value) {
845
1104
  fs.writeFileSync(job.varsPath, `${JSON.stringify(current, null, 2)}\n`, { mode: 0o600 });
846
1105
  return { varsPath: job.varsPath, variables: current.variables, updatedAt: current.updatedAt };
847
1106
  }
848
- async function executeTool(_toolCallId, params, _signal, _onUpdate, ctx) {
1107
+ // ---------------------------------------------------------------------------
1108
+ // STANDING GRANT — approval-gated tmux dispatch. The pure decode/decision logic lives in
1109
+ // dispatch-grant.ts; the functions below are the session-access GLUE: read the latest grant custom
1110
+ // entry (skipping past malformed payloads, but stopping DEAD on a tombstone — never resurrecting an
1111
+ // older grant beneath a revocation), count spend, and gate a real launch.
1112
+ // ---------------------------------------------------------------------------
1113
+ /** Most recent VALID `tmux-dispatch-grant` entry on the active branch, or undefined when there is
1114
+ * none, it was revoked (a tombstone is a hard stop — never skipped to find an older grant), or every
1115
+ * entry found fails to decode. Mirrors the branch-walk idiom used by goal/task session state. */
1116
+ function resolveLatestGrantEntry(ctx) {
1117
+ let fromId;
1118
+ for (;;) {
1119
+ const entry = ctx.sessionManager.getLatestCustomEntryOnBranch(GRANT_CUSTOM_TYPE, fromId);
1120
+ if (!entry)
1121
+ return undefined;
1122
+ if (isTmuxDispatchGrantTombstone(entry.data))
1123
+ return undefined;
1124
+ if (isTmuxDispatchGrant(entry.data))
1125
+ return entry.data;
1126
+ if (!entry.parentId)
1127
+ return undefined;
1128
+ fromId = entry.parentId;
1129
+ }
1130
+ }
1131
+ /** Decoded `data` payloads of every custom entry of `customType` on the active branch (root→leaf
1132
+ * order), for spend-counting — a single `getLatestCustomEntryOnBranch` call only ever returns ONE
1133
+ * entry, but budget spend requires ALL of them. */
1134
+ function collectCustomEntryData(ctx, customType) {
1135
+ const result = [];
1136
+ for (const entry of ctx.sessionManager.getBranch()) {
1137
+ const loose = entry;
1138
+ if (loose.type === "custom" && loose.customType === customType)
1139
+ result.push(loose.data);
1140
+ }
1141
+ return result;
1142
+ }
1143
+ /** Gate a REAL tmux dispatch (fire_task non-dryRun, send_followup) per the standing-grant doctrine:
1144
+ * a valid covering grant dispatches UNATTENDED (spending one usage); absent that, an
1145
+ * interactive host may approve a ONE-SHOT launch; absent BOTH, this REFUSES — never a silent launch.
1146
+ * Returns the covering grant when one authorized this launch (so the caller can derive launch-profile
1147
+ * flags from its envelope), or `{}` for a one-shot approval (no envelope to derive from — the caller
1148
+ * falls back to the conservative default profile). */
1149
+ async function authorizeLaunch(bridge, ctx, request) {
1150
+ if (request.agents.length === 0)
1151
+ throw new Error("tmux dispatch refused: launch has no agents");
1152
+ const grant = resolveLatestGrantEntry(ctx);
1153
+ // A standing grant names one provider. It must cover every child and spend one unit for every
1154
+ // child process; a matching first pane must never authorize an unrestricted mixed team.
1155
+ if (grant && request.agents.every((agent) => grantCovers(grant, { agent, goalId: request.goalId }))) {
1156
+ const used = countGrantUsages(grant.grantId, collectCustomEntryData(ctx, GRANT_USAGE_CUSTOM_TYPE));
1157
+ if (grant.budget.maxLaunches - used >= request.agents.length) {
1158
+ if (!bridge.appendEntry)
1159
+ throw new Error("this host does not support session custom entries; cannot spend the tmux dispatch grant.");
1160
+ for (let index = 0; index < request.agents.length; index++) {
1161
+ bridge.appendEntry(GRANT_USAGE_CUSTOM_TYPE, buildGrantUsageEntry(grant.grantId, `${request.jobId}:${index}`));
1162
+ }
1163
+ return { grant };
1164
+ }
1165
+ }
1166
+ if (ctx.hasUI) {
1167
+ const approved = await ctx.ui.confirm("tmux dispatch approval", [
1168
+ `No standing grant currently authorizes every child of: ${request.description}.`,
1169
+ `Agents: ${request.agents.join(", ")}${request.goalId ? `, goal: ${request.goalId}` : ""}.`,
1170
+ "Approve this ONE-SHOT launch? Run tmux_agent_manager action=grant_dispatch to authorize future launches without this prompt.",
1171
+ ].join("\n"));
1172
+ if (!approved)
1173
+ throw new Error(`tmux dispatch declined by the owner: ${request.description}`);
1174
+ return {};
1175
+ }
1176
+ throw new Error(`no standing grant for tmux dispatch; run grant_dispatch first: every child must be covered. ${request.description}. Refusing to launch without a grant or interactive approval.`);
1177
+ }
1178
+ /** Render grant/one-shot-derived launch-profile flags into a pi child's start command. Values
1179
+ * are shell-quoted; flags are not (they're fixed literals, never user input). */
1180
+ function appendLaunchProfileFlags(command, flags) {
1181
+ const rendered = flags.map((flag) => flag.value !== undefined ? `${flag.flag} ${quoteShell(flag.value)}` : flag.flag);
1182
+ return [command, ...rendered].join(" ");
1183
+ }
1184
+ /** Apply the launch profile to every provider="pi" agent in the job (fire_task only — send_followup
1185
+ * reuses an already-launched pane, so there is no new child command to configure). Non-pi agents are
1186
+ * bounded by the grant only at the launch layer (agent/budget/count); their internal tool-loop
1187
+ * enforcement is the target CLI's own responsibility (documented limitation, not a hidden gap). */
1188
+ function applyLaunchProfile(job, source) {
1189
+ for (const agent of job.agents) {
1190
+ if (agent.provider !== "pi")
1191
+ continue;
1192
+ // Per-agent flags: `worktreeLane` is a per-agent property (only a lane-first goal->tmux
1193
+ // dispatch sets it), so the shared `source` envelope is extended with it just for this agent's
1194
+ // flag build -- every other agent in a multi-agent team keeps the plain grant-derived profile.
1195
+ const flags = buildLaunchProfileFlags(agent.worktreeLane ? { ...source, worktreeLane: agent.worktreeLane } : source);
1196
+ const profiledCommand = appendLaunchProfileFlags(agent.command || defaultProviderInvocation(agent.provider), flags);
1197
+ agent.command = `env ${PI_ORCHESTRATION_AGENT_ID_ENV}=${quoteShell(agentLaneId(job.id, agent.id))} ${profiledCommand}`;
1198
+ }
1199
+ }
1200
+ /** Read an OPTIONAL, cooperative worker-reported usage claim for the turn that just went terminal (a
1201
+ * sibling `<result-path>.usage.json` file next to the watcher's own result file). Absent file ⇒ no
1202
+ * claim was offered ⇒ nothing is reported (never fabricated). */
1203
+ function readWorkerUsageClaim(job, agent) {
1204
+ const usagePath = `${currentResultPath(job, agent)}.usage.json`;
1205
+ try {
1206
+ return decodeTmuxWorkerUsageClaim(JSON.parse(fs.readFileSync(usagePath, "utf8")));
1207
+ }
1208
+ catch {
1209
+ return undefined;
1210
+ }
1211
+ }
1212
+ async function executeTool(_toolCallId, params, _signal, _onUpdate, ctx, bridge) {
849
1213
  const action = params.action || "status";
850
1214
  const detection = detectTmux();
851
1215
  if (action === "status")
@@ -901,6 +1265,62 @@ async function executeTool(_toolCallId, params, _signal, _onUpdate, ctx) {
901
1265
  details: { action, jobId: params.jobId, variableName: params.variableName, result },
902
1266
  };
903
1267
  }
1268
+ if (action === "grant_dispatch") {
1269
+ if (!params.agent)
1270
+ throw new Error("grant_dispatch requires agent");
1271
+ if (!Object.hasOwn(PROVIDER_COMMANDS, params.agent))
1272
+ throw new Error(`grant_dispatch: unsupported agent: ${params.agent}`);
1273
+ const grantParams = {
1274
+ agent: params.agent,
1275
+ goalId: params.goalId,
1276
+ allowedTools: params.allowedTools,
1277
+ resourceProfile: params.resourceProfile,
1278
+ writePaths: params.writePaths,
1279
+ maxLaunches: typeof params.maxLaunches === "number" ? params.maxLaunches : Number.NaN,
1280
+ expiresInMinutes: params.expiresInMinutes,
1281
+ maxUsdAdvisory: params.maxUsdAdvisory,
1282
+ };
1283
+ const grant = buildGrant(grantParams);
1284
+ const summary = describeGrant(grant);
1285
+ // OWNER-AUTHORIZED, NEVER SILENT: an interactive host must explicitly confirm the exact
1286
+ // grant details; a non-interactive host (print/rpc, or the unattended goal loop) has no confirm
1287
+ // surface, so it needs an explicit opt-in flag instead — absent either, refuse to create the grant.
1288
+ if (ctx.hasUI) {
1289
+ const approved = await ctx.ui.confirm("Authorize tmux dispatch grant", summary);
1290
+ if (!approved)
1291
+ throw new Error("grant_dispatch was declined by the owner.");
1292
+ }
1293
+ else if (bridge.getFlag?.("allow-tmux-dispatch") !== true) {
1294
+ throw new Error("grant_dispatch requires interactive approval; no UI is available in this mode. Pass --allow-tmux-dispatch to authorize grant creation non-interactively.");
1295
+ }
1296
+ if (!bridge.appendEntry)
1297
+ throw new Error("this host does not support session custom entries; cannot persist a tmux dispatch grant.");
1298
+ bridge.appendEntry(GRANT_CUSTOM_TYPE, grant);
1299
+ return {
1300
+ content: [{ type: "text", text: `Created tmux dispatch grant ${grant.grantId}.\n${summary}` }],
1301
+ details: { action, grant },
1302
+ };
1303
+ }
1304
+ if (action === "revoke_grant") {
1305
+ const activeGrant = resolveLatestGrantEntry(ctx);
1306
+ const targetGrantId = firstString(params.grantId) || activeGrant?.grantId;
1307
+ if (!targetGrantId)
1308
+ throw new Error("revoke_grant: no active tmux dispatch grant to revoke.");
1309
+ if (activeGrant && activeGrant.grantId !== targetGrantId)
1310
+ throw new Error(`revoke_grant: grantId ${targetGrantId} is not the active grant (active: ${activeGrant.grantId}).`);
1311
+ if (!bridge.appendEntry)
1312
+ throw new Error("this host does not support session custom entries; cannot revoke a tmux dispatch grant.");
1313
+ bridge.appendEntry(GRANT_CUSTOM_TYPE, buildTombstone(targetGrantId));
1314
+ return {
1315
+ content: [
1316
+ {
1317
+ type: "text",
1318
+ text: `Revoked tmux dispatch grant ${targetGrantId}. Future launches need a new grant_dispatch or interactive/opt-in approval.`,
1319
+ },
1320
+ ],
1321
+ details: { action, grantId: targetGrantId },
1322
+ };
1323
+ }
904
1324
  const guard = await guardTmux(ctx, detection, `tmux ${action}`);
905
1325
  if (!guard.allowed)
906
1326
  return { content: [{ type: "text", text: guard.text }], details: { action, detection, guard, skipped: true } };
@@ -965,40 +1385,222 @@ async function executeTool(_toolCallId, params, _signal, _onUpdate, ctx) {
965
1385
  };
966
1386
  if (tmuxSessionExists(job.sessionName))
967
1387
  throw new Error(`tmux session already exists: ${job.sessionName}. Use stop_job/stop_session first or choose a different workspaceName.`);
968
- const archivedJobDir = prepareJobDirForLaunch(job, params.force);
969
- const panes = job.agents.map((agent) => ({
970
- title: agent.name,
971
- cwd: agent.cwd,
972
- command: agent.command || defaultProviderInvocation(agent.provider),
973
- }));
974
- const launch = launchTmuxSession(job.sessionName, job.cwd, panes);
975
- job.agents.forEach((agent, index) => {
976
- agent.paneId = launch.paneIds[index];
1388
+ // APPROVAL-GATED LAUNCH: resolved before any tmux/FS side effect. A standing grant must
1389
+ // authorize every child provider and spend its budget per child process.
1390
+ const authorization = await authorizeLaunch(bridge, ctx, {
1391
+ agents: job.agents.map((agent) => agent.provider),
1392
+ goalId: params.goalId,
1393
+ jobId: job.id,
1394
+ description: `fire_task launch of job ${job.id} (${job.agents.length} child process${job.agents.length === 1 ? "" : "es"}: ${job.agents.map((agent) => `${agent.name}/${agent.provider}`).join(", ")})`,
977
1395
  });
978
- writeFireTaskFiles(job);
979
- const watcherPanes = startPaneWatchers(job);
1396
+ const managedAuthority = managedAuthorization(authorization.grant, `one-shot:${job.id}:turn:1`);
980
1397
  for (const agent of job.agents) {
981
- if (!agent.paneId)
982
- continue;
983
- injectPromptToPane(agent.paneId, fs.readFileSync(agent.promptPath, "utf8"), agent.provider);
1398
+ agent.currentTurn = 1;
1399
+ applyManagedAuthorization(agent, managedAuthority, {
1400
+ instructions: job.task,
1401
+ goalId: params.goalId,
1402
+ leaseTtlMs: job.deadlineSeconds * 1_000,
1403
+ });
1404
+ }
1405
+ applyLaunchProfile(job, {
1406
+ ...managedAuthority.launchSource,
1407
+ ...(params.goalId ? { taskRef: params.goalId } : {}),
1408
+ // Process-matrix parent identity: the dispatched child self-registers as a worker of THIS
1409
+ // session and winds down gracefully if this session disappears (see dispatch-grant.ts's
1410
+ // `LaunchProfileSource.parentPid`/`parentSession` doc).
1411
+ parentPid: process.pid,
1412
+ parentSession: ctx.sessionManager.getSessionId?.() ?? ctx.sessionManager.getSessionFile(),
1413
+ });
1414
+ // The host commits the full execution grant and starts the durable lease before any child
1415
+ // process, job artifact, watcher, or prompt side effect occurs.
1416
+ reportManagedDispatchReservations(bridge, job, job.agents);
1417
+ let sessionCreated = false;
1418
+ try {
1419
+ const archivedJobDir = prepareJobDirForLaunch(job, params.force);
1420
+ const panes = job.agents.map((agent) => ({
1421
+ title: agent.name,
1422
+ cwd: agent.cwd,
1423
+ command: agent.command || defaultProviderInvocation(agent.provider),
1424
+ }));
1425
+ const launch = launchTmuxSession(job.sessionName, job.cwd, panes);
1426
+ sessionCreated = true;
1427
+ job.agents.forEach((agent, index) => {
1428
+ agent.paneId = launch.paneIds[index];
1429
+ });
1430
+ writeFireTaskFiles(job);
1431
+ const watcherPanes = startPaneWatchers(job);
1432
+ for (const agent of job.agents) {
1433
+ if (!agent.paneId)
1434
+ continue;
1435
+ injectPromptToPane(agent.paneId, fs.readFileSync(agent.promptPath, "utf8"), agent.provider);
1436
+ }
1437
+ return {
1438
+ content: [
1439
+ {
1440
+ type: "text",
1441
+ text: [
1442
+ `Launched tmux interactive fire-and-forget job ${job.id}.`,
1443
+ `Session: ${job.sessionName}`,
1444
+ `Attach: tmux attach -t ${job.sessionName}`,
1445
+ `Job state: ${job.jobPath}`,
1446
+ archivedJobDir ? `Archived previous job dir: ${archivedJobDir}` : undefined,
1447
+ "Completion: event-driven pane output watchers armed (no polling).",
1448
+ ]
1449
+ .filter(Boolean)
1450
+ .join("\n"),
1451
+ },
1452
+ ],
1453
+ details: {
1454
+ action,
1455
+ detection,
1456
+ job,
1457
+ runs: launch.runs,
1458
+ paneIds: launch.paneIds,
1459
+ watcherPanes,
1460
+ archivedJobDir,
1461
+ },
1462
+ };
1463
+ }
1464
+ catch (error) {
1465
+ if (sessionCreated)
1466
+ runTmux(["kill-session", "-t", job.sessionName], 5_000);
1467
+ reportManagedLaunchFailure(bridge, job, "managed_process_launch_failed");
1468
+ throw error;
1469
+ }
1470
+ }
1471
+ if (action === "send_followup") {
1472
+ if (!params.jobId)
1473
+ throw new Error("send_followup requires jobId");
1474
+ const followupTask = firstString(params.task, params.body);
1475
+ if (!followupTask)
1476
+ throw new Error("send_followup requires task (or body) with the follow-up objective");
1477
+ const job = loadJob(params.jobId);
1478
+ if (job.dismissedAt)
1479
+ throw new Error(`tmux job ${job.id} was dismissed; use fire_task to relaunch instead of send_followup`);
1480
+ if (job.agents.length === 0)
1481
+ throw new Error(`tmux job has no agents: ${job.id}`);
1482
+ const targetAgent = params.agentId ? job.agents.find((agent) => agent.id === params.agentId) : job.agents[0];
1483
+ if (!targetAgent)
1484
+ throw new Error(`tmux job ${job.id} has no agent ${params.agentId}`);
1485
+ if (!targetAgent.paneId)
1486
+ throw new Error(`tmux agent ${targetAgent.name} has no recorded pane id; cannot send a follow-up`);
1487
+ if (targetAgent.pendingTurn !== undefined)
1488
+ throw new Error(`send_followup refused: turn ${targetAgent.pendingTurn} for ${targetAgent.id} is pending reconciliation; refusing to risk a duplicate prompt`);
1489
+ const turn = (targetAgent.currentTurn ?? 1) + 1;
1490
+ const markers = turnMarkers(job, targetAgent, turn);
1491
+ const promptText = managedPrompt(followupTask, job.id, targetAgent, markers.doneMarker, markers.blockedMarker, job.varsPath);
1492
+ if (params.dryRun === true)
1493
+ return {
1494
+ content: [
1495
+ {
1496
+ type: "text",
1497
+ text: `DRY RUN tmux send_followup\nJob: ${job.id}\nAgent: ${targetAgent.name}\nTurn: ${turn}`,
1498
+ },
1499
+ ],
1500
+ details: { action, detection, dryRun: true, jobId: job.id, agentId: targetAgent.id, turn },
1501
+ };
1502
+ if (!tmuxSessionExists(job.sessionName))
1503
+ throw new Error(`tmux session is gone: ${job.sessionName}. The worker pane cannot receive a follow-up; use fire_task to relaunch.`);
1504
+ if (!tmuxPaneExists(job.sessionName, targetAgent.paneId))
1505
+ throw new Error(`tmux pane ${targetAgent.paneId} for ${targetAgent.name} is gone. The worker cannot receive a follow-up; use fire_task to relaunch.`);
1506
+ // APPROVAL-GATED LAUNCH (doctrine-regression mandatory): a follow-up dispatches a fresh
1507
+ // turn into an already-running child, so there is no new child command to profile — only the
1508
+ // grant/one-shot authorization is resolved here (no applyLaunchProfile call).
1509
+ const authorization = await authorizeLaunch(bridge, ctx, {
1510
+ agents: [targetAgent.provider],
1511
+ goalId: params.goalId,
1512
+ jobId: `${job.id}:turn:${turn}`,
1513
+ description: `send_followup turn ${turn} to ${targetAgent.name} in job ${job.id}`,
1514
+ });
1515
+ const managedAuthority = managedAuthorization(authorization.grant, `one-shot:${job.id}:turn:${turn}`);
1516
+ const launchAllowedTools = targetAgent.dispatchAllowedTools ?? [...DEFAULT_READ_BIASED_TOOLS];
1517
+ const launchWritePaths = targetAgent.dispatchWritePaths ?? [];
1518
+ if (!sameStringValues(launchAllowedTools, managedAuthority.allowedTools) ||
1519
+ !sameStringValues(launchWritePaths, managedAuthority.writePaths)) {
1520
+ throw new Error(`send_followup refused: authorization scope differs from the already-running process for ${targetAgent.name}; relaunch the worker to apply a new tool or write-path scope.`);
1521
+ }
1522
+ // Reserve before watcher/prompt side effects. Reconcile re-arms a reserved turn but never
1523
+ // re-injects it, so crash recovery cannot duplicate a provider prompt.
1524
+ const reserved = persistJobPatch(job.id, (current) => {
1525
+ const agent = current.agents.find((entry) => entry.id === targetAgent.id);
1526
+ if (!agent || agent.pendingTurn !== undefined)
1527
+ return undefined;
1528
+ agent.currentTurn = turn;
1529
+ agent.pendingTurn = turn;
1530
+ agent.result = undefined;
1531
+ applyManagedAuthorization(agent, managedAuthority, {
1532
+ instructions: followupTask,
1533
+ goalId: params.goalId,
1534
+ leaseTtlMs: job.deadlineSeconds * 1_000,
1535
+ });
1536
+ current.currentTurn = turn;
1537
+ return current;
1538
+ });
1539
+ const reservedAgent = reserved.agents.find((agent) => agent.id === targetAgent.id);
1540
+ if (!reservedAgent || reservedAgent.pendingTurn !== turn)
1541
+ throw new Error(`send_followup refused: failed to reserve turn ${turn} for ${targetAgent.id}`);
1542
+ try {
1543
+ reportManagedDispatchReservations(bridge, reserved, [reservedAgent]);
1544
+ }
1545
+ catch (error) {
1546
+ persistAgentTurnFailure(job.id, reservedAgent.id, turn, "managed_process_launch_reservation_failed");
1547
+ throw error;
1548
+ }
1549
+ let written;
1550
+ try {
1551
+ written = dispatchAgentTurn(reserved, reservedAgent, turn, promptText);
1552
+ injectPromptToPane(reservedAgent.paneId, promptText, reservedAgent.provider);
1553
+ persistJobPatch(job.id, (current) => {
1554
+ const agent = current.agents.find((entry) => entry.id === reservedAgent.id);
1555
+ if (!agent || agent.pendingTurn !== turn)
1556
+ return undefined;
1557
+ delete agent.pendingTurn;
1558
+ return current;
1559
+ });
1560
+ }
1561
+ catch (error) {
1562
+ persistAgentTurnFailure(job.id, reservedAgent.id, turn, "managed_process_followup_failed");
1563
+ reportManagedAgentFailure(bridge, job.id, reservedAgent.id, "managed_process_followup_failed");
1564
+ throw error;
984
1565
  }
985
1566
  return {
986
1567
  content: [
987
1568
  {
988
1569
  type: "text",
989
1570
  text: [
990
- `Launched tmux interactive fire-and-forget job ${job.id}.`,
1571
+ `Sent follow-up turn ${turn} to ${targetAgent.name} in job ${job.id}.`,
991
1572
  `Session: ${job.sessionName}`,
992
- `Attach: tmux attach -t ${job.sessionName}`,
993
- `Job state: ${job.jobPath}`,
994
- archivedJobDir ? `Archived previous job dir: ${archivedJobDir}` : undefined,
995
- "Completion: event-driven pane output watchers armed (no polling).",
996
- ]
997
- .filter(Boolean)
998
- .join("\n"),
1573
+ `Prompt: ${written.promptPath}`,
1574
+ `Completion: event-driven pane watcher re-armed for turn ${turn} (no polling).`,
1575
+ ].join("\n"),
999
1576
  },
1000
1577
  ],
1001
- details: { action, detection, job, runs: launch.runs, paneIds: launch.paneIds, watcherPanes, archivedJobDir },
1578
+ details: { action, detection, jobId: job.id, agentId: targetAgent.id, turn, ...written },
1579
+ };
1580
+ }
1581
+ if (action === "dismiss") {
1582
+ if (!params.jobId)
1583
+ throw new Error("dismiss requires jobId");
1584
+ const job = loadJob(params.jobId);
1585
+ if (job.dismissedAt)
1586
+ return {
1587
+ content: [{ type: "text", text: `tmux job ${job.id} was already dismissed.` }],
1588
+ details: { action, jobId: job.id, alreadyDismissed: true },
1589
+ };
1590
+ persistJobPatch(job.id, (current) => {
1591
+ current.dismissedAt = new Date().toISOString();
1592
+ return current;
1593
+ });
1594
+ for (const agent of job.agents)
1595
+ bridge.reportManagedLane?.({ laneId: agentLaneId(job.id, agent.id), phase: "terminal", status: "dismissed" });
1596
+ return {
1597
+ content: [
1598
+ {
1599
+ type: "text",
1600
+ text: `Dismissed tmux job ${job.id}. Session '${job.sessionName}' left running (not killed); attach with: tmux attach -t ${job.sessionName}. Use stop_session/stop_job to terminate it.`,
1601
+ },
1602
+ ],
1603
+ details: { action, jobId: job.id, sessionName: job.sessionName },
1002
1604
  };
1003
1605
  }
1004
1606
  if (action === "notify") {
@@ -1082,18 +1684,73 @@ function formatFireTaskHandoff(job) {
1082
1684
  "This event woke the parent; do not poll. Continue safe scoped work from the bounded handoff and inspect terminal artifacts only if needed for a material claim.",
1083
1685
  ].join("\n");
1084
1686
  }
1085
- function markFireTaskNotified(job) {
1086
- const current = JSON.parse(fs.readFileSync(job.jobPath, "utf8"));
1087
- current.notifiedAt = new Date().toISOString();
1088
- const temporaryPath = `${job.jobPath}.tmp-${process.pid}-${Date.now()}`;
1089
- fs.writeFileSync(temporaryPath, `${JSON.stringify(current, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
1090
- fs.renameSync(temporaryPath, job.jobPath);
1091
- job.notifiedAt = current.notifiedAt;
1687
+ /** Diff live tmux sessions against this session's job records. Mirrors the invariant behind
1688
+ * `LocalRuntimeController.reconcile` (local-runtime-controller.ts): reconcile only ever OBSERVES —
1689
+ * it never kills a session it did not provably start. A job whose tmux session is gone is marked
1690
+ * orphaned (informational, one-shot); a job whose session is alive but current turn is still
1691
+ * pending is resumed by re-arming its watcher, but ONLY when tmux confirms no pipe is already
1692
+ * attached to that pane (see tmuxPaneHasPipe) — otherwise a live watcher would be raced and could
1693
+ * be made to report a false failure. */
1694
+ function reconcileTmuxSessions(ctx, bridge) {
1695
+ const sessionFile = ctx.sessionManager.getSessionFile();
1696
+ const jobs = loadJobPlans().filter((job) => job.parentSessionFile === sessionFile && !job.dismissedAt);
1697
+ if (jobs.length === 0)
1698
+ return;
1699
+ const detection = detectTmux();
1700
+ if (!detection.cliAvailable)
1701
+ return;
1702
+ const liveSessions = new Set(detection.sessions);
1703
+ for (const job of jobs) {
1704
+ if (!liveSessions.has(job.sessionName)) {
1705
+ if (!isFireTaskTerminal(job) && !job.orphanedAt) {
1706
+ persistJobPatch(job.id, (current) => {
1707
+ current.orphanedAt = new Date().toISOString();
1708
+ return current;
1709
+ });
1710
+ if (ctx.hasUI)
1711
+ ctx.ui.notify(`tmux job ${job.id} is orphaned: session '${job.sessionName}' is gone and the job never reached a terminal state. Nothing was killed; this is informational only.`, "warning");
1712
+ // Nothing is killed here — only the LANE record is released. A dead session means the
1713
+ // worker itself can no longer report its own terminal state, so a goal bound to it would
1714
+ // wait forever without this: release the managed lane per non-terminal agent so the goal's
1715
+ // continuation stops waiting on a worker that will never report back.
1716
+ for (const agent of job.agents) {
1717
+ if (agent.result !== undefined)
1718
+ continue;
1719
+ bridge.reportManagedLane?.({
1720
+ laneId: agentLaneId(job.id, agent.id),
1721
+ phase: "terminal",
1722
+ status: "orphaned",
1723
+ reasonCode: "tmux_session_orphaned",
1724
+ });
1725
+ }
1726
+ }
1727
+ continue;
1728
+ }
1729
+ if (isFireTaskTerminal(job))
1730
+ continue;
1731
+ for (const agent of job.agents) {
1732
+ if (agent.result !== undefined)
1733
+ continue;
1734
+ if (!agent.paneId || !tmuxPaneExists(job.sessionName, agent.paneId))
1735
+ continue;
1736
+ if (tmuxPaneHasPipe(agent.paneId))
1737
+ continue;
1738
+ reportManagedDispatchReservations(bridge, job, [agent]);
1739
+ rearmAgentWatcher(job, agent);
1740
+ }
1741
+ }
1092
1742
  }
1093
1743
  export default function tmuxAgentManagerExtension(pi) {
1094
1744
  let handoffContext;
1095
1745
  let handoffTail = Promise.resolve();
1096
1746
  const jobWatchers = new Map();
1747
+ const bridge = pi;
1748
+ // Non-interactive opt-in for grant_dispatch: optional-chained so a lightweight test double
1749
+ // that doesn't implement registerFlag still loads the extension; a real host always has it.
1750
+ bridge.registerFlag?.("allow-tmux-dispatch", {
1751
+ type: "boolean",
1752
+ description: "Authorize tmux_agent_manager grant_dispatch to create a standing tmux dispatch grant without interactive approval (print/rpc/non-interactive mode only).",
1753
+ });
1097
1754
  const closeJobWatchers = () => {
1098
1755
  for (const watcher of jobWatchers.values())
1099
1756
  watcher.close();
@@ -1101,21 +1758,61 @@ export default function tmuxAgentManagerExtension(pi) {
1101
1758
  };
1102
1759
  const refreshJobHandoffs = async (ctx) => {
1103
1760
  const sessionFile = ctx.sessionManager.getSessionFile();
1104
- const jobs = loadJobPlans().filter((job) => !job.parentSessionFile || job.parentSessionFile === sessionFile);
1761
+ const jobs = loadJobPlans().filter((job) => (!job.parentSessionFile || job.parentSessionFile === sessionFile) && !job.dismissedAt);
1105
1762
  for (const job of jobs) {
1106
- if (!isFireTaskTerminal(job) || job.notifiedAt)
1763
+ if (!isFireTaskTerminal(job))
1107
1764
  continue;
1108
- pi.sendMessage({
1109
- customType: "tmux-background-completion",
1110
- content: formatFireTaskHandoff(job),
1111
- display: true,
1112
- details: {
1113
- jobId: job.id,
1114
- sessionName: job.sessionName,
1115
- agents: job.agents.map((agent) => ({ id: agent.id, name: agent.name, status: agent.result?.status })),
1116
- },
1117
- }, { triggerTurn: true, deliverAs: "followUp" });
1118
- markFireTaskNotified(job);
1765
+ // Per-turn notify: a job is not permanently "closed" after its first terminal turn — a
1766
+ // follow-up reopens it, so the gate is per-agent (notifiedTurn < currentTurn), not a
1767
+ // single whole-job notifiedAt flag.
1768
+ const pendingAgents = job.agents.filter((agent) => (agent.notifiedTurn ?? 0) < (agent.currentTurn ?? 1));
1769
+ if (pendingAgents.length === 0)
1770
+ continue;
1771
+ for (const agent of pendingAgents) {
1772
+ // Advisory-only, and only ever reported when the worker itself chose to write the
1773
+ // claim file — never fabricated, never a hard cross-process cap.
1774
+ const usage = readWorkerUsageClaim(job, agent);
1775
+ bridge.reportManagedLane?.({
1776
+ laneId: agentLaneId(job.id, agent.id),
1777
+ phase: "terminal",
1778
+ status: agent.result?.status,
1779
+ usage,
1780
+ });
1781
+ if (usage) {
1782
+ bridge.reportSpawnedUsage?.(usage, {
1783
+ label: "tmux-worker",
1784
+ reportId: `tmux-worker:${job.sessionName}:${job.id}:${agent.currentTurn ?? 1}`,
1785
+ });
1786
+ }
1787
+ }
1788
+ // Production hosts own the sole durable wake path through reportManagedLane. The direct
1789
+ // message remains only for lightweight/standalone hosts that omit that bridge entirely.
1790
+ if (!bridge.reportManagedLane) {
1791
+ pi.sendMessage({
1792
+ customType: "tmux-background-completion",
1793
+ content: formatFireTaskHandoff(job),
1794
+ display: true,
1795
+ details: {
1796
+ jobId: job.id,
1797
+ sessionName: job.sessionName,
1798
+ agents: job.agents.map((agent) => ({
1799
+ id: agent.id,
1800
+ name: agent.name,
1801
+ status: agent.result?.status,
1802
+ })),
1803
+ },
1804
+ }, { triggerTurn: true, deliverAs: "followUp" });
1805
+ }
1806
+ // reportManagedLane persisted the terminal result + outbox synchronously before returning.
1807
+ // This marker only suppresses duplicate extension reports; it is not notification truth.
1808
+ persistJobPatch(job.id, (current) => {
1809
+ current.notifiedAt = new Date().toISOString();
1810
+ for (const agent of current.agents) {
1811
+ const inMemoryAgent = job.agents.find((entry) => entry.id === agent.id);
1812
+ agent.notifiedTurn = inMemoryAgent?.currentTurn ?? agent.currentTurn ?? 1;
1813
+ }
1814
+ return current;
1815
+ });
1119
1816
  if (ctx.hasUI)
1120
1817
  ctx.ui.notify(`tmux background task ${job.id} completed.`, "info");
1121
1818
  }
@@ -1163,6 +1860,7 @@ export default function tmuxAgentManagerExtension(pi) {
1163
1860
  pi.on("session_start", async (_event, ctx) => {
1164
1861
  handoffContext = ctx;
1165
1862
  closeJobWatchers();
1863
+ reconcileTmuxSessions(ctx, bridge);
1166
1864
  await queueJobHandoffRefresh(ctx);
1167
1865
  });
1168
1866
  pi.on("session_shutdown", async () => {
@@ -1180,9 +1878,14 @@ export default function tmuxAgentManagerExtension(pi) {
1180
1878
  "Prefer action=fire_task for interactive worker batches. It returns after event watchers and prompts are armed; do not wait, poll, or peek for completion.",
1181
1879
  "Use action=list_templates/show_template before assembling repeated teams; pass teamTemplate when a built-in team fits.",
1182
1880
  "Use action=workspace_plan before launch_workspace when designing a pane layout.",
1881
+ "Use action=send_followup to re-inject a new prompt into a live fire_task job's pane mid-run, without relaunching. It re-arms the completion watcher for a fresh turn and reuses the same event-driven handoff.",
1882
+ "Use action=dismiss to stop tracking a job without killing its tmux session; the pane keeps running and can still be attached to or stopped later with stop_job/stop_session.",
1183
1883
  "Use stop_job/stop_session dry-run first, then confirm=yes-tmux-stop for real cleanup.",
1184
1884
  "Do not put secrets in task text or command strings; prompts, commands, and logs persist under ~/.pi/agent/work/background/tmux-agent-manager/state/jobs.",
1185
1885
  "tmux display/status actions are metadata only; validate worker result/log files before claiming task completion.",
1886
+ "fire_task and send_followup are APPROVAL-GATED: a real (non-dryRun) dispatch needs either a standing grant (action=grant_dispatch, once per session/goal) or a one-shot interactive approval. With no grant and no UI available, the dispatch is refused, never silent — run grant_dispatch first.",
1887
+ "Use action=grant_dispatch to authorize repeated unattended dispatch: set agent, maxLaunches, and optionally goalId/allowedTools/resourceProfile/writePaths/expiresInMinutes. Requires interactive confirmation, or the --allow-tmux-dispatch flag when no UI is available. Use action=revoke_grant to end it early.",
1888
+ "A grant-covered pi child launches with a RESTRICTED profile (--tools/--resource-profile or --no-extensions --no-skills, plus a scoped --append-system-prompt naming the grant and its hard stops) — the envelope lives in the CHILD's own launch config, not an in-process sandbox. Non-pi agents (agy/claude/codex/opencode/custom) are bounded by the grant at launch only; their internal tool loop is that CLI's own responsibility.",
1186
1889
  ],
1187
1890
  parameters: Type.Object({
1188
1891
  action: Type.Optional(Type.Union([
@@ -1195,6 +1898,8 @@ export default function tmuxAgentManagerExtension(pi) {
1195
1898
  Type.Literal("workspace_plan"),
1196
1899
  Type.Literal("launch_workspace"),
1197
1900
  Type.Literal("fire_task"),
1901
+ Type.Literal("send_followup"),
1902
+ Type.Literal("dismiss"),
1198
1903
  Type.Literal("job_status"),
1199
1904
  Type.Literal("list_jobs"),
1200
1905
  Type.Literal("set_variable"),
@@ -1203,8 +1908,10 @@ export default function tmuxAgentManagerExtension(pi) {
1203
1908
  Type.Literal("show_template"),
1204
1909
  Type.Literal("stop_job"),
1205
1910
  Type.Literal("stop_session"),
1911
+ Type.Literal("grant_dispatch"),
1912
+ Type.Literal("revoke_grant"),
1206
1913
  ], {
1207
- description: "status, setup_help, guard, notify, set_status, clear_status, workspace_plan, launch_workspace, fire_task, job_status, list_jobs, set_variable, list_variables, list_templates, show_template, stop_job, or stop_session. Default status.",
1914
+ description: "status, setup_help, guard, notify, set_status, clear_status, workspace_plan, launch_workspace, fire_task, send_followup, dismiss, job_status, list_jobs, set_variable, list_variables, list_templates, show_template, stop_job, stop_session, grant_dispatch, or revoke_grant. Default status.",
1208
1915
  })),
1209
1916
  title: Type.Optional(Type.String({ description: "Notification title or workspace title context." })),
1210
1917
  body: Type.Optional(Type.String({ description: "Notification body/status text, or fallback task text for fire_task." })),
@@ -1225,10 +1932,13 @@ export default function tmuxAgentManagerExtension(pi) {
1225
1932
  description: "Built-in team template name for workspace/fire_task, or target for show_template. Use list_templates first. Current templates include provider-prompt-smoke, full-provider-review, builder-validator, plus JSON templates under templates/.",
1226
1933
  })),
1227
1934
  task: Type.Optional(Type.String({
1228
- description: "Fire-and-forget worker objective. Required for fire_task unless body is provided.",
1935
+ description: "Fire-and-forget worker objective. Required for fire_task unless body is provided. Also used as the follow-up objective for send_followup.",
1229
1936
  })),
1230
1937
  jobId: Type.Optional(Type.String({
1231
- description: "Job id for fire_task (optional), job_status/list_variables/set_variable (required).",
1938
+ description: "Job id for fire_task (optional), job_status/list_variables/set_variable/send_followup/dismiss (required).",
1939
+ })),
1940
+ agentId: Type.Optional(Type.String({
1941
+ description: "Target agent id for send_followup. Defaults to the job's first (primary) agent. Multi-agent-per-turn follow-up is not supported; only one agent's pane receives each follow-up.",
1232
1942
  })),
1233
1943
  variableName: Type.Optional(Type.String({
1234
1944
  description: "For set_variable: named condition/decision variable workers read only at the decision point.",
@@ -1261,9 +1971,43 @@ export default function tmuxAgentManagerExtension(pi) {
1261
1971
  description: "For fire_task only: archive an existing job directory with the same jobId before launch. Existing tmux sessions are still refused; stop them first.",
1262
1972
  })),
1263
1973
  confirm: Type.Optional(Type.String({ description: "Required for real stop_job/stop_session: yes-tmux-stop." })),
1974
+ goalId: Type.Optional(Type.String({
1975
+ description: "Goal this dispatch/grant is scoped to. For grant_dispatch: an unscoped grant (omitted) covers any goal; a scoped grant covers only launches naming the same goalId. For fire_task/send_followup: tags the request for grant-coverage matching.",
1976
+ })),
1977
+ agent: Type.Optional(Type.Union([
1978
+ Type.Literal("pi"),
1979
+ Type.Literal("codex"),
1980
+ Type.Literal("agy"),
1981
+ Type.Literal("claude"),
1982
+ Type.Literal("opencode"),
1983
+ Type.Literal("custom"),
1984
+ ], { description: "grant_dispatch: the provider this standing grant authorizes." })),
1985
+ allowedTools: Type.Optional(Type.Array(Type.String(), {
1986
+ description: "grant_dispatch: tool allowlist pushed into the child pi's own --tools flag. Defaults to a read-biased safe set (read, grep, find, ls) when omitted.",
1987
+ })),
1988
+ resourceProfile: Type.Optional(Type.String({
1989
+ description: "grant_dispatch: resource profile name pushed into the child pi's own --resource-profile flag. When omitted, the child launches with --no-extensions --no-skills instead.",
1990
+ })),
1991
+ writePaths: Type.Optional(Type.Array(Type.String(), {
1992
+ description: "grant_dispatch: write paths named in the child's scoped --append-system-prompt role text.",
1993
+ })),
1994
+ maxLaunches: Type.Optional(Type.Number({
1995
+ description: "grant_dispatch: number of real fire_task/send_followup dispatches this grant authorizes.",
1996
+ minimum: 1,
1997
+ })),
1998
+ expiresInMinutes: Type.Optional(Type.Number({
1999
+ description: "grant_dispatch: grant validity window from creation. Omit for a grant that never expires (until revoke_grant).",
2000
+ minimum: 1,
2001
+ })),
2002
+ maxUsdAdvisory: Type.Optional(Type.Number({
2003
+ description: "grant_dispatch: advisory USD ceiling. Never enforced across the process boundary (the child bills under its own auth) — a claim to review only.",
2004
+ })),
2005
+ grantId: Type.Optional(Type.String({
2006
+ description: "revoke_grant: grant id to revoke. Omit to revoke whichever grant is currently active.",
2007
+ })),
1264
2008
  }),
1265
2009
  async execute(toolCallId, params, signal, onUpdate, ctx) {
1266
- const result = await executeTool(toolCallId, params, signal, onUpdate, ctx);
2010
+ const result = await executeTool(toolCallId, params, signal, onUpdate, ctx, bridge);
1267
2011
  await queueJobHandoffRefresh(ctx);
1268
2012
  return result;
1269
2013
  },