@caupulican/pi-adaptative 0.81.37 → 0.81.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +131 -0
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +196 -0
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +308 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +22 -2
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +585 -24
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  13. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +749 -27
  14. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
  15. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
  16. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
  17. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
  18. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
  19. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
  20. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
  21. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
  22. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
  23. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
  24. package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
  25. package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
  26. package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
  27. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
  28. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
  29. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
  30. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
  31. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +5 -5
  32. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
  33. package/dist/cli/args.d.ts +3 -0
  34. package/dist/cli/args.d.ts.map +1 -1
  35. package/dist/cli/args.js +15 -0
  36. package/dist/cli/args.js.map +1 -1
  37. package/dist/core/agent-paths.d.ts +49 -0
  38. package/dist/core/agent-paths.d.ts.map +1 -0
  39. package/dist/core/agent-paths.js +107 -0
  40. package/dist/core/agent-paths.js.map +1 -0
  41. package/dist/core/agent-session-services.d.ts.map +1 -1
  42. package/dist/core/agent-session-services.js +3 -3
  43. package/dist/core/agent-session-services.js.map +1 -1
  44. package/dist/core/agent-session.d.ts +234 -17
  45. package/dist/core/agent-session.d.ts.map +1 -1
  46. package/dist/core/agent-session.js +484 -62
  47. package/dist/core/agent-session.js.map +1 -1
  48. package/dist/core/autonomy/contracts.d.ts +9 -0
  49. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  50. package/dist/core/autonomy/contracts.js.map +1 -1
  51. package/dist/core/autonomy/lane-tracker.d.ts +10 -1
  52. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  53. package/dist/core/autonomy/lane-tracker.js +5 -1
  54. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  55. package/dist/core/background-lane-controller.d.ts +122 -6
  56. package/dist/core/background-lane-controller.d.ts.map +1 -1
  57. package/dist/core/background-lane-controller.js +447 -90
  58. package/dist/core/background-lane-controller.js.map +1 -1
  59. package/dist/core/bash-execution-controller.d.ts +4 -0
  60. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  61. package/dist/core/bash-execution-controller.js +7 -1
  62. package/dist/core/bash-execution-controller.js.map +1 -1
  63. package/dist/core/compaction-support.d.ts +13 -3
  64. package/dist/core/compaction-support.d.ts.map +1 -1
  65. package/dist/core/compaction-support.js +43 -7
  66. package/dist/core/compaction-support.js.map +1 -1
  67. package/dist/core/context/context-audit.d.ts +33 -1
  68. package/dist/core/context/context-audit.d.ts.map +1 -1
  69. package/dist/core/context/context-audit.js +31 -5
  70. package/dist/core/context/context-audit.js.map +1 -1
  71. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  72. package/dist/core/context/sqlite-runtime-index.js +13 -7
  73. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  74. package/dist/core/context-gc.d.ts.map +1 -1
  75. package/dist/core/context-gc.js +16 -1
  76. package/dist/core/context-gc.js.map +1 -1
  77. package/dist/core/context-pipeline.d.ts +26 -4
  78. package/dist/core/context-pipeline.d.ts.map +1 -1
  79. package/dist/core/context-pipeline.js +137 -14
  80. package/dist/core/context-pipeline.js.map +1 -1
  81. package/dist/core/cost-guard.d.ts +19 -3
  82. package/dist/core/cost-guard.d.ts.map +1 -1
  83. package/dist/core/cost-guard.js +18 -3
  84. package/dist/core/cost-guard.js.map +1 -1
  85. package/dist/core/delegation/session-worker-result.d.ts +34 -4
  86. package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
  87. package/dist/core/delegation/session-worker-result.js +64 -4
  88. package/dist/core/delegation/session-worker-result.js.map +1 -1
  89. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  90. package/dist/core/delegation/worker-actions.js +1 -1
  91. package/dist/core/delegation/worker-actions.js.map +1 -1
  92. package/dist/core/delegation/worker-result.d.ts +42 -1
  93. package/dist/core/delegation/worker-result.d.ts.map +1 -1
  94. package/dist/core/delegation/worker-result.js +68 -0
  95. package/dist/core/delegation/worker-result.js.map +1 -1
  96. package/dist/core/extensions/loader.d.ts.map +1 -1
  97. package/dist/core/extensions/loader.js +23 -7
  98. package/dist/core/extensions/loader.js.map +1 -1
  99. package/dist/core/extensions/runner.d.ts.map +1 -1
  100. package/dist/core/extensions/runner.js +1 -0
  101. package/dist/core/extensions/runner.js.map +1 -1
  102. package/dist/core/extensions/types.d.ts +51 -0
  103. package/dist/core/extensions/types.d.ts.map +1 -1
  104. package/dist/core/extensions/types.js.map +1 -1
  105. package/dist/core/goal-loop-controller.d.ts +17 -1
  106. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  107. package/dist/core/goal-loop-controller.js +79 -11
  108. package/dist/core/goal-loop-controller.js.map +1 -1
  109. package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
  110. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  111. package/dist/core/goals/goal-continuation-controller.js +77 -0
  112. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  113. package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
  114. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  115. package/dist/core/goals/goal-continuation-defaults.js +42 -0
  116. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  117. package/dist/core/goals/goal-continuation-prompt.d.ts +4 -0
  118. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  119. package/dist/core/goals/goal-continuation-prompt.js +51 -10
  120. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  121. package/dist/core/goals/goal-runtime-snapshot.d.ts +101 -2
  122. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  123. package/dist/core/goals/goal-runtime-snapshot.js +87 -4
  124. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  125. package/dist/core/goals/goal-state.d.ts +89 -1
  126. package/dist/core/goals/goal-state.d.ts.map +1 -1
  127. package/dist/core/goals/goal-state.js +71 -5
  128. package/dist/core/goals/goal-state.js.map +1 -1
  129. package/dist/core/goals/goal-tool-core.d.ts +56 -2
  130. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  131. package/dist/core/goals/goal-tool-core.js +111 -5
  132. package/dist/core/goals/goal-tool-core.js.map +1 -1
  133. package/dist/core/goals/session-goal-state.d.ts +11 -2
  134. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  135. package/dist/core/goals/session-goal-state.js +32 -17
  136. package/dist/core/goals/session-goal-state.js.map +1 -1
  137. package/dist/core/keybindings.d.ts +10 -0
  138. package/dist/core/keybindings.d.ts.map +1 -1
  139. package/dist/core/keybindings.js +10 -2
  140. package/dist/core/keybindings.js.map +1 -1
  141. package/dist/core/learning/observation-store.d.ts +12 -3
  142. package/dist/core/learning/observation-store.d.ts.map +1 -1
  143. package/dist/core/learning/observation-store.js +30 -15
  144. package/dist/core/learning/observation-store.js.map +1 -1
  145. package/dist/core/learning/skill-curator.d.ts +5 -1
  146. package/dist/core/learning/skill-curator.d.ts.map +1 -1
  147. package/dist/core/learning/skill-curator.js +21 -19
  148. package/dist/core/learning/skill-curator.js.map +1 -1
  149. package/dist/core/local-runtime-controller.d.ts +65 -3
  150. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  151. package/dist/core/local-runtime-controller.js +186 -26
  152. package/dist/core/local-runtime-controller.js.map +1 -1
  153. package/dist/core/memory/providers/file-store.d.ts +1 -1
  154. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  155. package/dist/core/memory/providers/file-store.js +6 -6
  156. package/dist/core/memory/providers/file-store.js.map +1 -1
  157. package/dist/core/model-capability.d.ts +34 -0
  158. package/dist/core/model-capability.d.ts.map +1 -1
  159. package/dist/core/model-capability.js +42 -1
  160. package/dist/core/model-capability.js.map +1 -1
  161. package/dist/core/model-router/tool-escalation.d.ts +15 -0
  162. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  163. package/dist/core/model-router/tool-escalation.js +23 -1
  164. package/dist/core/model-router/tool-escalation.js.map +1 -1
  165. package/dist/core/model-router-controller.d.ts +34 -7
  166. package/dist/core/model-router-controller.d.ts.map +1 -1
  167. package/dist/core/model-router-controller.js +95 -16
  168. package/dist/core/model-router-controller.js.map +1 -1
  169. package/dist/core/models/adaptation-store.d.ts +7 -0
  170. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  171. package/dist/core/models/adaptation-store.js +47 -11
  172. package/dist/core/models/adaptation-store.js.map +1 -1
  173. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  174. package/dist/core/models/default-model-suggestions.js +17 -0
  175. package/dist/core/models/default-model-suggestions.js.map +1 -1
  176. package/dist/core/models/fitness-store.d.ts +3 -0
  177. package/dist/core/models/fitness-store.d.ts.map +1 -1
  178. package/dist/core/models/fitness-store.js +11 -2
  179. package/dist/core/models/fitness-store.js.map +1 -1
  180. package/dist/core/models/llamacpp-runtime.d.ts +180 -0
  181. package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
  182. package/dist/core/models/llamacpp-runtime.js +475 -0
  183. package/dist/core/models/llamacpp-runtime.js.map +1 -0
  184. package/dist/core/models/local-registration.d.ts +40 -0
  185. package/dist/core/models/local-registration.d.ts.map +1 -1
  186. package/dist/core/models/local-registration.js +94 -5
  187. package/dist/core/models/local-registration.js.map +1 -1
  188. package/dist/core/models/local-runtime.d.ts.map +1 -1
  189. package/dist/core/models/local-runtime.js +9 -7
  190. package/dist/core/models/local-runtime.js.map +1 -1
  191. package/dist/core/models/model-ref.d.ts +7 -0
  192. package/dist/core/models/model-ref.d.ts.map +1 -1
  193. package/dist/core/models/model-ref.js +26 -0
  194. package/dist/core/models/model-ref.js.map +1 -1
  195. package/dist/core/models/needle-runtime.d.ts +257 -0
  196. package/dist/core/models/needle-runtime.d.ts.map +1 -0
  197. package/dist/core/models/needle-runtime.js +519 -0
  198. package/dist/core/models/needle-runtime.js.map +1 -0
  199. package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
  200. package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
  201. package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
  202. package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
  203. package/dist/core/package-manager.d.ts.map +1 -1
  204. package/dist/core/package-manager.js +11 -10
  205. package/dist/core/package-manager.js.map +1 -1
  206. package/dist/core/process-matrix/codes.d.ts +72 -0
  207. package/dist/core/process-matrix/codes.d.ts.map +1 -0
  208. package/dist/core/process-matrix/codes.js +15 -0
  209. package/dist/core/process-matrix/codes.js.map +1 -0
  210. package/dist/core/process-matrix/runtime.d.ts +63 -0
  211. package/dist/core/process-matrix/runtime.d.ts.map +1 -0
  212. package/dist/core/process-matrix/runtime.js +310 -0
  213. package/dist/core/process-matrix/runtime.js.map +1 -0
  214. package/dist/core/process-matrix/store.d.ts +22 -0
  215. package/dist/core/process-matrix/store.d.ts.map +1 -0
  216. package/dist/core/process-matrix/store.js +80 -0
  217. package/dist/core/process-matrix/store.js.map +1 -0
  218. package/dist/core/process-matrix/supervisor.d.ts +72 -0
  219. package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
  220. package/dist/core/process-matrix/supervisor.js +130 -0
  221. package/dist/core/process-matrix/supervisor.js.map +1 -0
  222. package/dist/core/profile-registry.d.ts +7 -0
  223. package/dist/core/profile-registry.d.ts.map +1 -1
  224. package/dist/core/profile-registry.js +20 -0
  225. package/dist/core/profile-registry.js.map +1 -1
  226. package/dist/core/python-runtime.d.ts.map +1 -1
  227. package/dist/core/python-runtime.js +3 -3
  228. package/dist/core/python-runtime.js.map +1 -1
  229. package/dist/core/reflection-controller.d.ts +29 -5
  230. package/dist/core/reflection-controller.d.ts.map +1 -1
  231. package/dist/core/reflection-controller.js +215 -126
  232. package/dist/core/reflection-controller.js.map +1 -1
  233. package/dist/core/reload-blockers.d.ts +36 -0
  234. package/dist/core/reload-blockers.d.ts.map +1 -1
  235. package/dist/core/reload-blockers.js +44 -0
  236. package/dist/core/reload-blockers.js.map +1 -1
  237. package/dist/core/resource-loader.d.ts.map +1 -1
  238. package/dist/core/resource-loader.js +8 -7
  239. package/dist/core/resource-loader.js.map +1 -1
  240. package/dist/core/runtime-builder.d.ts +58 -5
  241. package/dist/core/runtime-builder.d.ts.map +1 -1
  242. package/dist/core/runtime-builder.js +209 -25
  243. package/dist/core/runtime-builder.js.map +1 -1
  244. package/dist/core/scout-controller.d.ts +6 -0
  245. package/dist/core/scout-controller.d.ts.map +1 -1
  246. package/dist/core/scout-controller.js +66 -52
  247. package/dist/core/scout-controller.js.map +1 -1
  248. package/dist/core/sdk.d.ts.map +1 -1
  249. package/dist/core/sdk.js +3 -3
  250. package/dist/core/sdk.js.map +1 -1
  251. package/dist/core/session-role.d.ts +31 -0
  252. package/dist/core/session-role.d.ts.map +1 -0
  253. package/dist/core/session-role.js +52 -0
  254. package/dist/core/session-role.js.map +1 -0
  255. package/dist/core/settings-manager.d.ts +42 -3
  256. package/dist/core/settings-manager.d.ts.map +1 -1
  257. package/dist/core/settings-manager.js +94 -60
  258. package/dist/core/settings-manager.js.map +1 -1
  259. package/dist/core/system-prompt-builder.d.ts +12 -0
  260. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  261. package/dist/core/system-prompt-builder.js +6 -0
  262. package/dist/core/system-prompt-builder.js.map +1 -1
  263. package/dist/core/system-prompt.d.ts +14 -1
  264. package/dist/core/system-prompt.d.ts.map +1 -1
  265. package/dist/core/system-prompt.js +20 -3
  266. package/dist/core/system-prompt.js.map +1 -1
  267. package/dist/core/tasks/session-task-state.d.ts +11 -2
  268. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  269. package/dist/core/tasks/session-task-state.js +27 -11
  270. package/dist/core/tasks/session-task-state.js.map +1 -1
  271. package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
  272. package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
  273. package/dist/core/tasks/task-contract-monitor.js +56 -0
  274. package/dist/core/tasks/task-contract-monitor.js.map +1 -0
  275. package/dist/core/tasks/task-state.d.ts +8 -0
  276. package/dist/core/tasks/task-state.d.ts.map +1 -1
  277. package/dist/core/tasks/task-state.js +28 -1
  278. package/dist/core/tasks/task-state.js.map +1 -1
  279. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  280. package/dist/core/tool-gate-controller.js +5 -0
  281. package/dist/core/tool-gate-controller.js.map +1 -1
  282. package/dist/core/tool-recovery-log-records.d.ts +7 -0
  283. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  284. package/dist/core/tool-recovery-log-records.js +14 -6
  285. package/dist/core/tool-recovery-log-records.js.map +1 -1
  286. package/dist/core/tool-selection/promotion.d.ts +54 -0
  287. package/dist/core/tool-selection/promotion.d.ts.map +1 -0
  288. package/dist/core/tool-selection/promotion.js +81 -0
  289. package/dist/core/tool-selection/promotion.js.map +1 -0
  290. package/dist/core/tool-selection/tool-performance-store.d.ts +37 -0
  291. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  292. package/dist/core/tool-selection/tool-performance-store.js +87 -3
  293. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  294. package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
  295. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  296. package/dist/core/tool-selection/tool-selection-controller.js +96 -0
  297. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  298. package/dist/core/tools/bash.d.ts +18 -0
  299. package/dist/core/tools/bash.d.ts.map +1 -1
  300. package/dist/core/tools/bash.js +97 -18
  301. package/dist/core/tools/bash.js.map +1 -1
  302. package/dist/core/tools/delegate-status.d.ts +14 -0
  303. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  304. package/dist/core/tools/delegate-status.js +82 -7
  305. package/dist/core/tools/delegate-status.js.map +1 -1
  306. package/dist/core/tools/delegate.d.ts.map +1 -1
  307. package/dist/core/tools/delegate.js +25 -8
  308. package/dist/core/tools/delegate.js.map +1 -1
  309. package/dist/core/tools/find.d.ts.map +1 -1
  310. package/dist/core/tools/find.js +52 -44
  311. package/dist/core/tools/find.js.map +1 -1
  312. package/dist/core/tools/goal.d.ts +94 -3
  313. package/dist/core/tools/goal.d.ts.map +1 -1
  314. package/dist/core/tools/goal.js +165 -15
  315. package/dist/core/tools/goal.js.map +1 -1
  316. package/dist/core/tools/grep.d.ts.map +1 -1
  317. package/dist/core/tools/grep.js +5 -4
  318. package/dist/core/tools/grep.js.map +1 -1
  319. package/dist/core/tools/model-fitness.d.ts +7 -0
  320. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  321. package/dist/core/tools/model-fitness.js +2 -2
  322. package/dist/core/tools/model-fitness.js.map +1 -1
  323. package/dist/core/tools/render-utils.d.ts.map +1 -1
  324. package/dist/core/tools/render-utils.js +1 -1
  325. package/dist/core/tools/render-utils.js.map +1 -1
  326. package/dist/core/tools/shell-contract-router.d.ts +6 -1
  327. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  328. package/dist/core/tools/shell-contract-router.js +69 -13
  329. package/dist/core/tools/shell-contract-router.js.map +1 -1
  330. package/dist/core/tools/shell-session.d.ts +89 -0
  331. package/dist/core/tools/shell-session.d.ts.map +1 -0
  332. package/dist/core/tools/shell-session.js +432 -0
  333. package/dist/core/tools/shell-session.js.map +1 -0
  334. package/dist/core/tools/task-steps.d.ts +4 -0
  335. package/dist/core/tools/task-steps.d.ts.map +1 -1
  336. package/dist/core/tools/task-steps.js +63 -8
  337. package/dist/core/tools/task-steps.js.map +1 -1
  338. package/dist/core/tools/tmux-dispatch.d.ts +86 -0
  339. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
  340. package/dist/core/tools/tmux-dispatch.js +91 -0
  341. package/dist/core/tools/tmux-dispatch.js.map +1 -0
  342. package/dist/core/tools/windows-shell-engine.d.ts +42 -0
  343. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
  344. package/dist/core/tools/windows-shell-engine.js +153 -0
  345. package/dist/core/tools/windows-shell-engine.js.map +1 -0
  346. package/dist/core/tools/windows-shell-state.d.ts +40 -0
  347. package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
  348. package/dist/core/tools/windows-shell-state.js +59 -0
  349. package/dist/core/tools/windows-shell-state.js.map +1 -0
  350. package/dist/core/tools/worktree-sync.d.ts +24 -0
  351. package/dist/core/tools/worktree-sync.d.ts.map +1 -0
  352. package/dist/core/tools/worktree-sync.js +338 -0
  353. package/dist/core/tools/worktree-sync.js.map +1 -0
  354. package/dist/core/trust-manager.d.ts +4 -1
  355. package/dist/core/trust-manager.d.ts.map +1 -1
  356. package/dist/core/trust-manager.js +20 -2
  357. package/dist/core/trust-manager.js.map +1 -1
  358. package/dist/core/util/atomic-file.d.ts +55 -0
  359. package/dist/core/util/atomic-file.d.ts.map +1 -0
  360. package/dist/core/util/atomic-file.js +255 -0
  361. package/dist/core/util/atomic-file.js.map +1 -0
  362. package/dist/core/util/minimatch-cache.d.ts +33 -0
  363. package/dist/core/util/minimatch-cache.d.ts.map +1 -0
  364. package/dist/core/util/minimatch-cache.js +0 -0
  365. package/dist/core/util/minimatch-cache.js.map +1 -0
  366. package/dist/core/worktree-sync/codes.d.ts +227 -0
  367. package/dist/core/worktree-sync/codes.d.ts.map +1 -0
  368. package/dist/core/worktree-sync/codes.js +14 -0
  369. package/dist/core/worktree-sync/codes.js.map +1 -0
  370. package/dist/core/worktree-sync/git-engine.d.ts +156 -0
  371. package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
  372. package/dist/core/worktree-sync/git-engine.js +1191 -0
  373. package/dist/core/worktree-sync/git-engine.js.map +1 -0
  374. package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
  375. package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
  376. package/dist/core/worktree-sync/lane-gate.js +360 -0
  377. package/dist/core/worktree-sync/lane-gate.js.map +1 -0
  378. package/dist/core/worktree-sync/runtime.d.ts +47 -0
  379. package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
  380. package/dist/core/worktree-sync/runtime.js +96 -0
  381. package/dist/core/worktree-sync/runtime.js.map +1 -0
  382. package/dist/core/worktree-sync/store.d.ts +69 -0
  383. package/dist/core/worktree-sync/store.d.ts.map +1 -0
  384. package/dist/core/worktree-sync/store.js +247 -0
  385. package/dist/core/worktree-sync/store.js.map +1 -0
  386. package/dist/core/worktree-sync/watcher.d.ts +29 -0
  387. package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
  388. package/dist/core/worktree-sync/watcher.js +93 -0
  389. package/dist/core/worktree-sync/watcher.js.map +1 -0
  390. package/dist/main.d.ts.map +1 -1
  391. package/dist/main.js +94 -0
  392. package/dist/main.js.map +1 -1
  393. package/dist/migrations.d.ts +9 -0
  394. package/dist/migrations.d.ts.map +1 -1
  395. package/dist/migrations.js +38 -0
  396. package/dist/migrations.js.map +1 -1
  397. package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
  398. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  399. package/dist/modes/interactive/auto-learn-controller.js +50 -8
  400. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  401. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
  403. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  404. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  405. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  406. package/dist/modes/interactive/interactive-mode.js +4 -0
  407. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  408. package/dist/modes/interactive/local-model-commands.d.ts +43 -0
  409. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  410. package/dist/modes/interactive/local-model-commands.js +290 -3
  411. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  412. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  413. package/dist/modes/interactive/session-flow-commands.js +24 -4
  414. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  415. package/dist/utils/fs-watch.d.ts +11 -0
  416. package/dist/utils/fs-watch.d.ts.map +1 -1
  417. package/dist/utils/fs-watch.js +20 -2
  418. package/dist/utils/fs-watch.js.map +1 -1
  419. package/dist/utils/highlight-js-languages.d.ts +4 -0
  420. package/dist/utils/highlight-js-languages.d.ts.map +1 -0
  421. package/dist/utils/highlight-js-languages.js +573 -0
  422. package/dist/utils/highlight-js-languages.js.map +1 -0
  423. package/dist/utils/shell.d.ts +7 -1
  424. package/dist/utils/shell.d.ts.map +1 -1
  425. package/dist/utils/shell.js +39 -9
  426. package/dist/utils/shell.js.map +1 -1
  427. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  428. package/dist/utils/syntax-highlight.js +53 -5
  429. package/dist/utils/syntax-highlight.js.map +1 -1
  430. package/dist/utils/tools-manager.d.ts.map +1 -1
  431. package/dist/utils/tools-manager.js +112 -1
  432. package/dist/utils/tools-manager.js.map +1 -1
  433. package/docs/development.md +2 -0
  434. package/docs/packages.md +1 -1
  435. package/docs/process-matrix.md +120 -0
  436. package/docs/settings.md +5 -2
  437. package/docs/tmux-agent-manager.md +85 -2
  438. package/docs/windows.md +52 -3
  439. package/docs/work-directory.md +29 -0
  440. package/docs/worktree-sync.md +250 -0
  441. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  442. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  443. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  444. package/examples/extensions/sandbox/package-lock.json +2 -2
  445. package/examples/extensions/sandbox/package.json +1 -1
  446. package/examples/extensions/with-deps/package-lock.json +2 -2
  447. package/examples/extensions/with-deps/package.json +1 -1
  448. package/npm-shrinkwrap.json +12 -12
  449. package/package.json +10 -4
  450. package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
  451. package/docs/integration-sweep-resume-2026-07-09.md +0 -407
@@ -0,0 +1,153 @@
1
+ /**
2
+ * The `python-engine` tier: per-command spawn of the bundled `pi-shell-engine` (D3 in the
3
+ * blueprint). Wires the frozen §1.2/§1.3 stdin-JSON-request / 0x1e-framed-stdout protocol into a
4
+ * `BashOperations`, threads `WindowsShellState` through both directions (D4), and degrades to a
5
+ * named, actionable error when the Python runtime is not ready — the PowerShell floor keeps
6
+ * working regardless (the router never routes simple commands here when the engine is off).
7
+ */
8
+ import { join } from "node:path";
9
+ import { getBundledResourcesDir } from "../../config.js";
10
+ import { spawnProcess, waitForChildProcessWithTermination } from "../../utils/child-process.js";
11
+ import { getShellEnv, trackDetachedChildPid, untrackDetachedChildPid } from "../../utils/shell.js";
12
+ import { ensurePythonRuntime } from "../python-runtime.js";
13
+ import { applyEngineFrame, getOrCreateWindowsShellState, mergeEffectiveEnv, resolveEffectiveCwd, } from "./windows-shell-state.js";
14
+ const ENGINE_FRAME_SENTINEL = 0x1e;
15
+ export class WindowsShellEngineFailure extends Error {
16
+ capturedOutput;
17
+ constructor(message, capturedOutput) {
18
+ super(message);
19
+ this.name = "WindowsShellEngineFailure";
20
+ this.capturedOutput = capturedOutput;
21
+ }
22
+ }
23
+ function resolveEngineScriptPath() {
24
+ return join(getBundledResourcesDir(), "runtimes", "pi-shell-engine", "main.py");
25
+ }
26
+ const MAX_CONTROL_FRAME_BYTES = 64 * 1024;
27
+ function isRecord(value) {
28
+ return typeof value === "object" && value !== null && !Array.isArray(value);
29
+ }
30
+ /** Parse the terminal frame from the dedicated control stream. Command output is never retained here. */
31
+ function parseControlFrame(buffer) {
32
+ if (buffer.length < 2 || buffer[buffer.length - 1] !== ENGINE_FRAME_SENTINEL)
33
+ return undefined;
34
+ const openIndex = buffer.lastIndexOf(ENGINE_FRAME_SENTINEL, buffer.length - 2);
35
+ if (openIndex === -1)
36
+ return undefined;
37
+ try {
38
+ const raw = JSON.parse(buffer.subarray(openIndex + 1, buffer.length - 1).toString("utf8"));
39
+ if (!isRecord(raw))
40
+ return undefined;
41
+ if (typeof raw.exitCode !== "number" || !Number.isInteger(raw.exitCode))
42
+ return undefined;
43
+ if (typeof raw.cwd !== "string" || !isRecord(raw.envDelta))
44
+ return undefined;
45
+ if (raw.unsupported !== null && !isRecord(raw.unsupported))
46
+ return undefined;
47
+ if (raw.unsupported !== null &&
48
+ (raw.unsupported.code !== "unsupported" ||
49
+ typeof raw.unsupported.construct !== "string" ||
50
+ typeof raw.unsupported.message !== "string"))
51
+ return undefined;
52
+ for (const value of Object.values(raw.envDelta)) {
53
+ if (value !== null && typeof value !== "string")
54
+ return undefined;
55
+ }
56
+ return raw;
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ }
62
+ function degradationError(outcome) {
63
+ return new Error(`The Windows shell engine (Python) is unavailable: ${outcome.reason} The simple-command PowerShell floor still works; fix the Python runtime (uv/network) to restore pipelines, redirection, expansion, and chaining.`);
64
+ }
65
+ /**
66
+ * Create the `python-engine` tier `BashOperations` for one bash-tool session. `exec`'s `command`
67
+ * argument is the RAW Bash source from the `python-engine` route (never PowerShell-translated).
68
+ */
69
+ export function createWindowsShellEngineOperations(sessionKey, options = {}) {
70
+ const resolveRuntime = options.resolveRuntime ?? (() => ensurePythonRuntime({ silent: true }));
71
+ const engineScriptPath = options.engineScriptPath ?? resolveEngineScriptPath();
72
+ const getState = options.getState ?? getOrCreateWindowsShellState;
73
+ const spawn = options.spawn ?? spawnProcess;
74
+ return {
75
+ async exec(command, cwd, { onData, signal, timeout, env }) {
76
+ const runtime = await resolveRuntime();
77
+ if (runtime.status !== "ready")
78
+ throw degradationError(runtime);
79
+ const state = getState(sessionKey);
80
+ const effectiveCwd = resolveEffectiveCwd(state, cwd);
81
+ const effectiveEnv = mergeEffectiveEnv(state, env ?? getShellEnv());
82
+ const timeoutMs = timeout !== undefined && timeout > 0 ? timeout * 1000 : undefined;
83
+ // The engine's own soft deadline must fire and emit its cooperative exit-124 frame (which
84
+ // preserves partial output) BEFORE the hard tree-kill backstop below, or the hard kill
85
+ // always wins the race and the soft path never gets to run. Give it a head start; the hard
86
+ // kill still bounds a hung engine that never reads its own deadline.
87
+ const requestTimeoutMs = timeoutMs !== undefined ? Math.max(timeoutMs - 500, 500) : undefined;
88
+ const request = {
89
+ command,
90
+ cwd: effectiveCwd,
91
+ env: effectiveEnv,
92
+ ...(requestTimeoutMs !== undefined ? { timeoutMs: requestTimeoutMs } : {}),
93
+ };
94
+ const child = spawn(runtime.pythonPath, ["-B", engineScriptPath], {
95
+ cwd: effectiveCwd,
96
+ env: {
97
+ ...effectiveEnv,
98
+ PYTHONDONTWRITEBYTECODE: "1",
99
+ PYTHONIOENCODING: "utf-8",
100
+ PYTHONUNBUFFERED: "1",
101
+ PYTHONUTF8: "1",
102
+ },
103
+ stdio: ["pipe", "pipe", "pipe"],
104
+ });
105
+ if (child.pid)
106
+ trackDetachedChildPid(child.pid);
107
+ let controlBuffer = Buffer.alloc(0);
108
+ let controlOverflow = false;
109
+ // Command output is the data stream: forward it immediately and never retain a
110
+ // second full copy merely to find the terminal frame.
111
+ child.stdout?.on("data", (chunk) => {
112
+ onData(chunk);
113
+ });
114
+ // stderr is the bounded control stream. The Python engine routes command stderr
115
+ // into stdout, so this channel contains only the terminal frame/diagnostics.
116
+ child.stderr?.on("data", (chunk) => {
117
+ if (controlOverflow)
118
+ return;
119
+ if (controlBuffer.length + chunk.length > MAX_CONTROL_FRAME_BYTES) {
120
+ controlOverflow = true;
121
+ return;
122
+ }
123
+ controlBuffer = Buffer.concat([controlBuffer, chunk]);
124
+ });
125
+ try {
126
+ child.stdin?.end(JSON.stringify(request), "utf8");
127
+ const terminal = await waitForChildProcessWithTermination(child, {
128
+ signal,
129
+ timeoutMs,
130
+ killGraceMs: 2_000,
131
+ });
132
+ if (signal?.aborted)
133
+ throw new Error("aborted");
134
+ const frame = controlOverflow ? undefined : parseControlFrame(controlBuffer);
135
+ if (!frame) {
136
+ const capturedOutput = controlOverflow
137
+ ? `control frame exceeded ${MAX_CONTROL_FRAME_BYTES} bytes`
138
+ : controlBuffer.toString("utf8");
139
+ throw new WindowsShellEngineFailure(`Windows shell engine failed (process exit ${terminal.code ?? "null"}) without a parseable control frame.\n${capturedOutput}`, capturedOutput);
140
+ }
141
+ applyEngineFrame(state, frame);
142
+ if (frame.unsupported)
143
+ throw new Error(frame.unsupported.message);
144
+ return { exitCode: frame.exitCode };
145
+ }
146
+ finally {
147
+ if (child.pid)
148
+ untrackDetachedChildPid(child.pid);
149
+ }
150
+ },
151
+ };
152
+ }
153
+ //# sourceMappingURL=windows-shell-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-shell-engine.js","sourceRoot":"","sources":["../../../src/core/tools/windows-shell-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `python-engine` tier: per-command spawn of the bundled `pi-shell-engine` (D3 in the\n * blueprint). Wires the frozen §1.2/§1.3 stdin-JSON-request / 0x1e-framed-stdout protocol into a\n * `BashOperations`, threads `WindowsShellState` through both directions (D4), and degrades to a\n * named, actionable error when the Python runtime is not ready — the PowerShell floor keeps\n * working regardless (the router never routes simple commands here when the engine is off).\n */\n\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { getBundledResourcesDir } from \"../../config.ts\";\nimport { spawnProcess, waitForChildProcessWithTermination } from \"../../utils/child-process.ts\";\nimport { getShellEnv, trackDetachedChildPid, untrackDetachedChildPid } from \"../../utils/shell.ts\";\nimport { ensurePythonRuntime, type PythonRuntimeOutcome } from \"../python-runtime.ts\";\nimport type { BashOperations } from \"./bash.ts\";\nimport {\n\tapplyEngineFrame,\n\tgetOrCreateWindowsShellState,\n\tmergeEffectiveEnv,\n\tresolveEffectiveCwd,\n\ttype WindowsShellState,\n} from \"./windows-shell-state.ts\";\n\nconst ENGINE_FRAME_SENTINEL = 0x1e;\n\n/** The full §1.3 control-frame shape. */\nexport interface WindowsShellEngineFrame {\n\texitCode: number;\n\tcwd: string;\n\tenvDelta: Record<string, string | null>;\n\tunsupported: { code: \"unsupported\"; construct: string; message: string } | null;\n}\n\nexport class WindowsShellEngineFailure extends Error {\n\treadonly capturedOutput: string;\n\n\tconstructor(message: string, capturedOutput: string) {\n\t\tsuper(message);\n\t\tthis.name = \"WindowsShellEngineFailure\";\n\t\tthis.capturedOutput = capturedOutput;\n\t}\n}\n\nfunction resolveEngineScriptPath(): string {\n\treturn join(getBundledResourcesDir(), \"runtimes\", \"pi-shell-engine\", \"main.py\");\n}\n\nconst MAX_CONTROL_FRAME_BYTES = 64 * 1024;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Parse the terminal frame from the dedicated control stream. Command output is never retained here. */\nfunction parseControlFrame(buffer: Buffer): WindowsShellEngineFrame | undefined {\n\tif (buffer.length < 2 || buffer[buffer.length - 1] !== ENGINE_FRAME_SENTINEL) return undefined;\n\tconst openIndex = buffer.lastIndexOf(ENGINE_FRAME_SENTINEL, buffer.length - 2);\n\tif (openIndex === -1) return undefined;\n\ttry {\n\t\tconst raw: unknown = JSON.parse(buffer.subarray(openIndex + 1, buffer.length - 1).toString(\"utf8\"));\n\t\tif (!isRecord(raw)) return undefined;\n\t\tif (typeof raw.exitCode !== \"number\" || !Number.isInteger(raw.exitCode)) return undefined;\n\t\tif (typeof raw.cwd !== \"string\" || !isRecord(raw.envDelta)) return undefined;\n\t\tif (raw.unsupported !== null && !isRecord(raw.unsupported)) return undefined;\n\t\tif (\n\t\t\traw.unsupported !== null &&\n\t\t\t(raw.unsupported.code !== \"unsupported\" ||\n\t\t\t\ttypeof raw.unsupported.construct !== \"string\" ||\n\t\t\t\ttypeof raw.unsupported.message !== \"string\")\n\t\t)\n\t\t\treturn undefined;\n\t\tfor (const value of Object.values(raw.envDelta)) {\n\t\t\tif (value !== null && typeof value !== \"string\") return undefined;\n\t\t}\n\t\treturn raw as unknown as WindowsShellEngineFrame;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport interface WindowsShellEngineOptions {\n\t/** Override for tests: resolves the Python runtime outcome. Default: `ensurePythonRuntime`. */\n\tresolveRuntime?: () => Promise<PythonRuntimeOutcome>;\n\t/** Override for tests: absolute path to the engine's `main.py`. Default: the bundled runtime. */\n\tengineScriptPath?: string;\n\t/** Override for tests: the per-session state store lookup. Default: the shared module store. */\n\tgetState?: (sessionKey: string) => WindowsShellState;\n\t/** Override for tests: spawns the engine child process. Default: `spawnProcess` (cross-spawn on win32). */\n\tspawn?: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n}\n\nfunction degradationError(\n\toutcome: Extract<PythonRuntimeOutcome, { status: \"offline\" | \"uv-unavailable\" | \"python-unavailable\" }>,\n) {\n\treturn new Error(\n\t\t`The Windows shell engine (Python) is unavailable: ${outcome.reason} The simple-command PowerShell floor still works; fix the Python runtime (uv/network) to restore pipelines, redirection, expansion, and chaining.`,\n\t);\n}\n\n/**\n * Create the `python-engine` tier `BashOperations` for one bash-tool session. `exec`'s `command`\n * argument is the RAW Bash source from the `python-engine` route (never PowerShell-translated).\n */\nexport function createWindowsShellEngineOperations(\n\tsessionKey: string,\n\toptions: WindowsShellEngineOptions = {},\n): BashOperations {\n\tconst resolveRuntime = options.resolveRuntime ?? (() => ensurePythonRuntime({ silent: true }));\n\tconst engineScriptPath = options.engineScriptPath ?? resolveEngineScriptPath();\n\tconst getState = options.getState ?? getOrCreateWindowsShellState;\n\tconst spawn = options.spawn ?? spawnProcess;\n\n\treturn {\n\t\tasync exec(command, cwd, { onData, signal, timeout, env }) {\n\t\t\tconst runtime = await resolveRuntime();\n\t\t\tif (runtime.status !== \"ready\") throw degradationError(runtime);\n\n\t\t\tconst state = getState(sessionKey);\n\t\t\tconst effectiveCwd = resolveEffectiveCwd(state, cwd);\n\t\t\tconst effectiveEnv = mergeEffectiveEnv(state, env ?? getShellEnv());\n\t\t\tconst timeoutMs = timeout !== undefined && timeout > 0 ? timeout * 1000 : undefined;\n\t\t\t// The engine's own soft deadline must fire and emit its cooperative exit-124 frame (which\n\t\t\t// preserves partial output) BEFORE the hard tree-kill backstop below, or the hard kill\n\t\t\t// always wins the race and the soft path never gets to run. Give it a head start; the hard\n\t\t\t// kill still bounds a hung engine that never reads its own deadline.\n\t\t\tconst requestTimeoutMs = timeoutMs !== undefined ? Math.max(timeoutMs - 500, 500) : undefined;\n\n\t\t\tconst request = {\n\t\t\t\tcommand,\n\t\t\t\tcwd: effectiveCwd,\n\t\t\t\tenv: effectiveEnv,\n\t\t\t\t...(requestTimeoutMs !== undefined ? { timeoutMs: requestTimeoutMs } : {}),\n\t\t\t};\n\n\t\t\tconst child = spawn(runtime.pythonPath, [\"-B\", engineScriptPath], {\n\t\t\t\tcwd: effectiveCwd,\n\t\t\t\tenv: {\n\t\t\t\t\t...effectiveEnv,\n\t\t\t\t\tPYTHONDONTWRITEBYTECODE: \"1\",\n\t\t\t\t\tPYTHONIOENCODING: \"utf-8\",\n\t\t\t\t\tPYTHONUNBUFFERED: \"1\",\n\t\t\t\t\tPYTHONUTF8: \"1\",\n\t\t\t\t},\n\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\n\t\t\tlet controlBuffer: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n\t\t\tlet controlOverflow = false;\n\n\t\t\t// Command output is the data stream: forward it immediately and never retain a\n\t\t\t// second full copy merely to find the terminal frame.\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tonData(chunk);\n\t\t\t});\n\t\t\t// stderr is the bounded control stream. The Python engine routes command stderr\n\t\t\t// into stdout, so this channel contains only the terminal frame/diagnostics.\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (controlOverflow) return;\n\t\t\t\tif (controlBuffer.length + chunk.length > MAX_CONTROL_FRAME_BYTES) {\n\t\t\t\t\tcontrolOverflow = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcontrolBuffer = Buffer.concat([controlBuffer, chunk]);\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tchild.stdin?.end(JSON.stringify(request), \"utf8\");\n\t\t\t\tconst terminal = await waitForChildProcessWithTermination(child, {\n\t\t\t\t\tsignal,\n\t\t\t\t\ttimeoutMs,\n\t\t\t\t\tkillGraceMs: 2_000,\n\t\t\t\t});\n\t\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\n\t\t\t\tconst frame = controlOverflow ? undefined : parseControlFrame(controlBuffer);\n\t\t\t\tif (!frame) {\n\t\t\t\t\tconst capturedOutput = controlOverflow\n\t\t\t\t\t\t? `control frame exceeded ${MAX_CONTROL_FRAME_BYTES} bytes`\n\t\t\t\t\t\t: controlBuffer.toString(\"utf8\");\n\t\t\t\t\tthrow new WindowsShellEngineFailure(\n\t\t\t\t\t\t`Windows shell engine failed (process exit ${terminal.code ?? \"null\"}) without a parseable control frame.\\n${capturedOutput}`,\n\t\t\t\t\t\tcapturedOutput,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tapplyEngineFrame(state, frame);\n\t\t\t\tif (frame.unsupported) throw new Error(frame.unsupported.message);\n\t\t\t\treturn { exitCode: frame.exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Per-session Windows shell-engine state (D4 — the engine is the sole state mutator).
3
+ *
4
+ * `cwd`/`envDelta` are threaded into every `python-engine` invocation and updated from the
5
+ * engine's control frame after each run; the PS tier consumes the same state through the
6
+ * EXISTING `shell-session.ts` seams (`lastRequestedCwd` re-entry, `shallowEnvEquals` respawn).
7
+ * This module owns no process/spawn logic — it is pure state carriage.
8
+ */
9
+ export interface WindowsShellState {
10
+ cwd: string;
11
+ /** Host-requested cwd used to detect an intentional caller cwd change. */
12
+ hostCwd?: string;
13
+ envDelta: Record<string, string | null>;
14
+ }
15
+ /** The engine control-frame shape this module consumes (subset of the full §1.3 frame). */
16
+ export interface EngineFrameState {
17
+ cwd: string;
18
+ envDelta: Record<string, string | null>;
19
+ }
20
+ /** Get or lazily create the per-session-key Windows shell state. */
21
+ export declare function getOrCreateWindowsShellState(sessionKey: string): WindowsShellState;
22
+ /** Drop a session's engine state (agent teardown). Safe to call for keys that never ran. */
23
+ export declare function disposeWindowsShellState(sessionKey: string): void;
24
+ /**
25
+ * Fold an engine control frame into the session state: `cwd` is set verbatim; `envDelta` entries
26
+ * apply string => set, `null` => delete (§1.3).
27
+ */
28
+ export declare function applyEngineFrame(state: WindowsShellState, frame: EngineFrameState): void;
29
+ /**
30
+ * The cwd a NEXT call (engine or PS tier) must use: the state-adjusted cwd once the engine has run
31
+ * at least one `cd`, otherwise the host-requested cwd. Both tiers call this with the SAME session
32
+ * state so a `cd` in the engine is observed by the very next PS-tier call.
33
+ */
34
+ export declare function resolveEffectiveCwd(state: WindowsShellState, requestedCwd: string): string;
35
+ /**
36
+ * The env a NEXT call (engine or PS tier) must use: the base env plus every `export`/`unset` the
37
+ * engine has applied so far.
38
+ */
39
+ export declare function mergeEffectiveEnv(state: WindowsShellState, baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
40
+ //# sourceMappingURL=windows-shell-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-shell-state.d.ts","sourceRoot":"","sources":["../../../src/core/tools/windows-shell-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACxC;AAED,4FAA2F;AAC3F,MAAM,WAAW,gBAAgB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACxC;AAID,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAOlF;AAED,4FAA4F;AAC5F,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAEjE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAKxF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAM1F;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAOzG","sourcesContent":["/**\n * Per-session Windows shell-engine state (D4 — the engine is the sole state mutator).\n *\n * `cwd`/`envDelta` are threaded into every `python-engine` invocation and updated from the\n * engine's control frame after each run; the PS tier consumes the same state through the\n * EXISTING `shell-session.ts` seams (`lastRequestedCwd` re-entry, `shallowEnvEquals` respawn).\n * This module owns no process/spawn logic — it is pure state carriage.\n */\n\nexport interface WindowsShellState {\n\tcwd: string;\n\t/** Host-requested cwd used to detect an intentional caller cwd change. */\n\thostCwd?: string;\n\tenvDelta: Record<string, string | null>;\n}\n\n/** The engine control-frame shape this module consumes (subset of the full §1.3 frame). */\nexport interface EngineFrameState {\n\tcwd: string;\n\tenvDelta: Record<string, string | null>;\n}\n\nconst windowsShellStates = new Map<string, WindowsShellState>();\n\n/** Get or lazily create the per-session-key Windows shell state. */\nexport function getOrCreateWindowsShellState(sessionKey: string): WindowsShellState {\n\tlet state = windowsShellStates.get(sessionKey);\n\tif (!state) {\n\t\tstate = { cwd: \"\", envDelta: {} };\n\t\twindowsShellStates.set(sessionKey, state);\n\t}\n\treturn state;\n}\n\n/** Drop a session's engine state (agent teardown). Safe to call for keys that never ran. */\nexport function disposeWindowsShellState(sessionKey: string): void {\n\twindowsShellStates.delete(sessionKey);\n}\n\n/**\n * Fold an engine control frame into the session state: `cwd` is set verbatim; `envDelta` entries\n * apply string => set, `null` => delete (§1.3).\n */\nexport function applyEngineFrame(state: WindowsShellState, frame: EngineFrameState): void {\n\tstate.cwd = frame.cwd;\n\tfor (const [key, value] of Object.entries(frame.envDelta)) {\n\t\tstate.envDelta[key] = value;\n\t}\n}\n\n/**\n * The cwd a NEXT call (engine or PS tier) must use: the state-adjusted cwd once the engine has run\n * at least one `cd`, otherwise the host-requested cwd. Both tiers call this with the SAME session\n * state so a `cd` in the engine is observed by the very next PS-tier call.\n */\nexport function resolveEffectiveCwd(state: WindowsShellState, requestedCwd: string): string {\n\tif (state.hostCwd !== requestedCwd) {\n\t\tstate.hostCwd = requestedCwd;\n\t\tstate.cwd = requestedCwd;\n\t}\n\treturn state.cwd;\n}\n\n/**\n * The env a NEXT call (engine or PS tier) must use: the base env plus every `export`/`unset` the\n * engine has applied so far.\n */\nexport function mergeEffectiveEnv(state: WindowsShellState, baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n\tconst merged: NodeJS.ProcessEnv = { ...baseEnv };\n\tfor (const [key, value] of Object.entries(state.envDelta)) {\n\t\tif (value === null) delete merged[key];\n\t\telse merged[key] = value;\n\t}\n\treturn merged;\n}\n"]}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Per-session Windows shell-engine state (D4 — the engine is the sole state mutator).
3
+ *
4
+ * `cwd`/`envDelta` are threaded into every `python-engine` invocation and updated from the
5
+ * engine's control frame after each run; the PS tier consumes the same state through the
6
+ * EXISTING `shell-session.ts` seams (`lastRequestedCwd` re-entry, `shallowEnvEquals` respawn).
7
+ * This module owns no process/spawn logic — it is pure state carriage.
8
+ */
9
+ const windowsShellStates = new Map();
10
+ /** Get or lazily create the per-session-key Windows shell state. */
11
+ export function getOrCreateWindowsShellState(sessionKey) {
12
+ let state = windowsShellStates.get(sessionKey);
13
+ if (!state) {
14
+ state = { cwd: "", envDelta: {} };
15
+ windowsShellStates.set(sessionKey, state);
16
+ }
17
+ return state;
18
+ }
19
+ /** Drop a session's engine state (agent teardown). Safe to call for keys that never ran. */
20
+ export function disposeWindowsShellState(sessionKey) {
21
+ windowsShellStates.delete(sessionKey);
22
+ }
23
+ /**
24
+ * Fold an engine control frame into the session state: `cwd` is set verbatim; `envDelta` entries
25
+ * apply string => set, `null` => delete (§1.3).
26
+ */
27
+ export function applyEngineFrame(state, frame) {
28
+ state.cwd = frame.cwd;
29
+ for (const [key, value] of Object.entries(frame.envDelta)) {
30
+ state.envDelta[key] = value;
31
+ }
32
+ }
33
+ /**
34
+ * The cwd a NEXT call (engine or PS tier) must use: the state-adjusted cwd once the engine has run
35
+ * at least one `cd`, otherwise the host-requested cwd. Both tiers call this with the SAME session
36
+ * state so a `cd` in the engine is observed by the very next PS-tier call.
37
+ */
38
+ export function resolveEffectiveCwd(state, requestedCwd) {
39
+ if (state.hostCwd !== requestedCwd) {
40
+ state.hostCwd = requestedCwd;
41
+ state.cwd = requestedCwd;
42
+ }
43
+ return state.cwd;
44
+ }
45
+ /**
46
+ * The env a NEXT call (engine or PS tier) must use: the base env plus every `export`/`unset` the
47
+ * engine has applied so far.
48
+ */
49
+ export function mergeEffectiveEnv(state, baseEnv) {
50
+ const merged = { ...baseEnv };
51
+ for (const [key, value] of Object.entries(state.envDelta)) {
52
+ if (value === null)
53
+ delete merged[key];
54
+ else
55
+ merged[key] = value;
56
+ }
57
+ return merged;
58
+ }
59
+ //# sourceMappingURL=windows-shell-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-shell-state.js","sourceRoot":"","sources":["../../../src/core/tools/windows-shell-state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAEhE,oEAAoE;AACpE,MAAM,UAAU,4BAA4B,CAAC,UAAkB,EAAqB;IACnF,IAAI,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,KAAK,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAClC,kBAAkB,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,4FAA4F;AAC5F,MAAM,UAAU,wBAAwB,CAAC,UAAkB,EAAQ;IAClE,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAAA,CACtC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAwB,EAAE,KAAuB,EAAQ;IACzF,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;IACtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC7B,CAAC;AAAA,CACD;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAwB,EAAE,YAAoB,EAAU;IAC3F,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;QACpC,KAAK,CAAC,OAAO,GAAG,YAAY,CAAC;QAC7B,KAAK,CAAC,GAAG,GAAG,YAAY,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC;AAAA,CACjB;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAwB,EAAE,OAA0B,EAAqB;IAC1G,MAAM,MAAM,GAAsB,EAAE,GAAG,OAAO,EAAE,CAAC;IACjD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;;YAClC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd","sourcesContent":["/**\n * Per-session Windows shell-engine state (D4 — the engine is the sole state mutator).\n *\n * `cwd`/`envDelta` are threaded into every `python-engine` invocation and updated from the\n * engine's control frame after each run; the PS tier consumes the same state through the\n * EXISTING `shell-session.ts` seams (`lastRequestedCwd` re-entry, `shallowEnvEquals` respawn).\n * This module owns no process/spawn logic — it is pure state carriage.\n */\n\nexport interface WindowsShellState {\n\tcwd: string;\n\t/** Host-requested cwd used to detect an intentional caller cwd change. */\n\thostCwd?: string;\n\tenvDelta: Record<string, string | null>;\n}\n\n/** The engine control-frame shape this module consumes (subset of the full §1.3 frame). */\nexport interface EngineFrameState {\n\tcwd: string;\n\tenvDelta: Record<string, string | null>;\n}\n\nconst windowsShellStates = new Map<string, WindowsShellState>();\n\n/** Get or lazily create the per-session-key Windows shell state. */\nexport function getOrCreateWindowsShellState(sessionKey: string): WindowsShellState {\n\tlet state = windowsShellStates.get(sessionKey);\n\tif (!state) {\n\t\tstate = { cwd: \"\", envDelta: {} };\n\t\twindowsShellStates.set(sessionKey, state);\n\t}\n\treturn state;\n}\n\n/** Drop a session's engine state (agent teardown). Safe to call for keys that never ran. */\nexport function disposeWindowsShellState(sessionKey: string): void {\n\twindowsShellStates.delete(sessionKey);\n}\n\n/**\n * Fold an engine control frame into the session state: `cwd` is set verbatim; `envDelta` entries\n * apply string => set, `null` => delete (§1.3).\n */\nexport function applyEngineFrame(state: WindowsShellState, frame: EngineFrameState): void {\n\tstate.cwd = frame.cwd;\n\tfor (const [key, value] of Object.entries(frame.envDelta)) {\n\t\tstate.envDelta[key] = value;\n\t}\n}\n\n/**\n * The cwd a NEXT call (engine or PS tier) must use: the state-adjusted cwd once the engine has run\n * at least one `cd`, otherwise the host-requested cwd. Both tiers call this with the SAME session\n * state so a `cd` in the engine is observed by the very next PS-tier call.\n */\nexport function resolveEffectiveCwd(state: WindowsShellState, requestedCwd: string): string {\n\tif (state.hostCwd !== requestedCwd) {\n\t\tstate.hostCwd = requestedCwd;\n\t\tstate.cwd = requestedCwd;\n\t}\n\treturn state.cwd;\n}\n\n/**\n * The env a NEXT call (engine or PS tier) must use: the base env plus every `export`/`unset` the\n * engine has applied so far.\n */\nexport function mergeEffectiveEnv(state: WindowsShellState, baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n\tconst merged: NodeJS.ProcessEnv = { ...baseEnv };\n\tfor (const [key, value] of Object.entries(state.envDelta)) {\n\t\tif (value === null) delete merged[key];\n\t\telse merged[key] = value;\n\t}\n\treturn merged;\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { type Static, Type } from "typebox";
2
+ import type { ToolDefinition } from "../extensions/types.ts";
3
+ import type { ResolvedWorktreeSyncSettings } from "../settings-manager.ts";
4
+ import { type WorktreeSyncEngineDeps } from "../worktree-sync/git-engine.ts";
5
+ declare const worktreeSyncSchema: Type.TObject<{
6
+ action: Type.TUnion<[Type.TLiteral<"status">, Type.TLiteral<"git_status">, Type.TLiteral<"git_diff">, Type.TLiteral<"git_add">, Type.TLiteral<"git_commit">, Type.TLiteral<"check">, Type.TLiteral<"create_lane">, Type.TLiteral<"sync">, Type.TLiteral<"continue">, Type.TLiteral<"abort_sync">, Type.TLiteral<"land">, Type.TLiteral<"release_lane">, Type.TLiteral<"reconcile">]>;
7
+ laneKey: Type.TOptional<Type.TString>;
8
+ goalId: Type.TOptional<Type.TString>;
9
+ requirementId: Type.TOptional<Type.TString>;
10
+ paths: Type.TOptional<Type.TArray<Type.TString>>;
11
+ message: Type.TOptional<Type.TString>;
12
+ confirm: Type.TOptional<Type.TString>;
13
+ }>;
14
+ export type WorktreeSyncToolInput = Static<typeof worktreeSyncSchema>;
15
+ export interface WorktreeSyncToolDeps {
16
+ engineDeps: () => WorktreeSyncEngineDeps;
17
+ settings: () => ResolvedWorktreeSyncSettings;
18
+ boundLaneKey: () => string | undefined;
19
+ /** True iff this is a worker session (see session-role.ts) -- narrows the action surface below. */
20
+ isWorker: () => boolean;
21
+ }
22
+ export declare function createWorktreeSyncToolDefinition(deps: WorktreeSyncToolDeps): ToolDefinition;
23
+ export {};
24
+ //# sourceMappingURL=worktree-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-sync.d.ts","sourceRoot":"","sources":["../../../src/core/tools/worktree-sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,EAUN,KAAK,sBAAsB,EAC3B,MAAM,gCAAgC,CAAC;AA8DxC,QAAA,MAAM,kBAAkB;;;;;;;;EAA6B,CAAC;AAEtD,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEtE,MAAM,WAAW,oBAAoB;IACpC,UAAU,EAAE,MAAM,sBAAsB,CAAC;IACzC,QAAQ,EAAE,MAAM,4BAA4B,CAAC;IAC7C,YAAY,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACvC,mGAAmG;IACnG,QAAQ,EAAE,MAAM,OAAO,CAAC;CACxB;AAgED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,oBAAoB,GAAG,cAAc,CAiQ3F","sourcesContent":["import { isAbsolute, relative } from \"node:path\";\nimport { type Static, Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport type { ResolvedWorktreeSyncSettings } from \"../settings-manager.ts\";\nimport type { ConflictWorklist, SyncStatus } from \"../worktree-sync/codes.ts\";\nimport {\n\tabortSync,\n\tbuildSyncStatus,\n\tcontinueSync,\n\tcreateLane,\n\tlandLane,\n\treconcile,\n\treleaseLane,\n\tresolveRepoContext,\n\tsyncLane,\n\ttype WorktreeSyncEngineDeps,\n} from \"../worktree-sync/git-engine.ts\";\nimport { resolveLaneMutationPath } from \"../worktree-sync/lane-gate.ts\";\nimport { readLane } from \"../worktree-sync/store.ts\";\n\n/**\n * `worktree_sync` -- the ENTIRE agent-facing surface of the worktree-per-lane workflow: a closed\n * action set over the engine (`core/worktree-sync/git-engine.ts`) so agents never improvise git\n * ceremony. Every outcome carries a tagged code in `details`; refusal text always names the exact\n * recovery step. See docs/worktree-sync.md for the workflow and the G1-G11 gate table.\n */\n\nfunction createWorktreeSyncSchema() {\n\treturn Type.Object(\n\t\t{\n\t\t\taction: Type.Union(\n\t\t\t\t[\n\t\t\t\t\tType.Literal(\"status\"),\n\t\t\t\t\tType.Literal(\"git_status\"),\n\t\t\t\t\tType.Literal(\"git_diff\"),\n\t\t\t\t\tType.Literal(\"git_add\"),\n\t\t\t\t\tType.Literal(\"git_commit\"),\n\t\t\t\t\tType.Literal(\"check\"),\n\t\t\t\t\tType.Literal(\"create_lane\"),\n\t\t\t\t\tType.Literal(\"sync\"),\n\t\t\t\t\tType.Literal(\"continue\"),\n\t\t\t\t\tType.Literal(\"abort_sync\"),\n\t\t\t\t\tType.Literal(\"land\"),\n\t\t\t\t\tType.Literal(\"release_lane\"),\n\t\t\t\t\tType.Literal(\"reconcile\"),\n\t\t\t\t],\n\t\t\t\t{\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"status: the deterministic full picture (epoch, hub, lock, per-lane freshness/staleness, advice). git_status/git_diff: read the bound lane with fixed argv. git_add: stage only explicitly validated paths inside the lane. git_commit: commit with a literal message. check: run only the owner-configured trusted check command. create_lane: new worktree+branch off main. sync: rebase current main into a lane (conflicts return a worklist and leave the rebase in progress). continue: verify resolved conflicts (zero markers, mechanically checked), stage, drive on. abort_sync: abort the in-progress rebase. land: the ONLY door to main -- serialized, freshness-checked, gate-command-verified, ff-only. release_lane: remove a fully-landed lane (discarding unlanded work needs confirm). reconcile: re-sync the registry with git reality.\",\n\t\t\t\t},\n\t\t\t),\n\t\t\tlaneKey: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Target lane. Defaults to this session's bound lane (PI_WORKTREE_LANE) for sync/continue/abort_sync/land.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t\tgoalId: Type.Optional(\n\t\t\t\tType.String({ description: \"create_lane: goal to scope the auto-allocated lane key by.\" }),\n\t\t\t),\n\t\t\trequirementId: Type.Optional(Type.String({ description: \"create_lane: requirement this lane will work.\" })),\n\t\t\tpaths: Type.Optional(\n\t\t\t\tType.Array(Type.String(), {\n\t\t\t\t\tdescription: \"git_diff/git_add: explicit relative paths inside the bound lane.\",\n\t\t\t\t}),\n\t\t\t),\n\t\t\tmessage: Type.Optional(Type.String({ description: \"git_commit: literal commit message.\" })),\n\t\t\tconfirm: Type.Optional(\n\t\t\t\tType.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'release_lane: pass exactly \"yes-discard-lane\" to release a lane that still has unlanded commits or dirty files (G11: never silent).',\n\t\t\t\t}),\n\t\t\t),\n\t\t},\n\t\t{ additionalProperties: false },\n\t);\n}\n\nconst worktreeSyncSchema = createWorktreeSyncSchema();\n\nexport type WorktreeSyncToolInput = Static<typeof worktreeSyncSchema>;\n\nexport interface WorktreeSyncToolDeps {\n\tengineDeps: () => WorktreeSyncEngineDeps;\n\tsettings: () => ResolvedWorktreeSyncSettings;\n\tboundLaneKey: () => string | undefined;\n\t/** True iff this is a worker session (see session-role.ts) -- narrows the action surface below. */\n\tisWorker: () => boolean;\n}\n\n/** Actions a worker session may run unconditionally -- read-only status plus the sync/conflict\n * cycle on its own bound lane. Everything else is refused as `role_forbidden`, EXCEPT `land`,\n * which is instead gated by the `worktreeSync.workerLand` setting (still subject to normal\n * ownership/freshness gating downstream when allowed). */\nconst WORKER_ALLOWED_ACTIONS: ReadonlySet<WorktreeSyncToolInput[\"action\"]> = new Set([\n\t\"status\",\n\t\"git_status\",\n\t\"git_diff\",\n\t\"git_add\",\n\t\"git_commit\",\n\t\"check\",\n\t\"sync\",\n\t\"continue\",\n\t\"abort_sync\",\n]);\n\nfunction formatWorklist(worklist: ConflictWorklist): string[] {\n\tconst lines = [\n\t\t`Conflicts at rebase step ${worklist.step}${worklist.stoppedAtCommit ? ` (replaying ${worklist.stoppedAtCommit.sha.slice(0, 12)}: ${worklist.stoppedAtCommit.subject})` : \"\"}:`,\n\t];\n\tfor (const file of worklist.files) {\n\t\tlines.push(`- ${file.path} [${file.kind}]`);\n\t}\n\tlines.push(\n\t\t'Resolve the zdiff3 hunks in exactly these files (base section included), save, then call {\"action\":\"continue\"}. Staging and marker verification are automatic.',\n\t);\n\treturn lines;\n}\n\nfunction formatStatus(status: SyncStatus): string[] {\n\tconst lines = [\n\t\t`epoch ${status.epoch} | main ${status.mainBranch}@${status.mainSha.slice(0, 12)}` +\n\t\t\t`${status.hub ? ` | hub ${status.hub.clean ? \"clean\" : \"has local changes\"}` : \" | hub: main not checked out\"}` +\n\t\t\t`${status.lock.held ? ` | LOCK held by pid ${status.lock.holder?.pid ?? \"?\"}` : \"\"}`,\n\t];\n\tfor (const lane of status.lanes) {\n\t\tconst flags = [\n\t\t\tlane.registrationStatus !== \"active\" ? lane.registrationStatus : undefined,\n\t\t\tlane.rebaseInProgress ? \"REBASE-IN-PROGRESS\" : undefined,\n\t\t\tlane.syncRequired ? \"SYNC-REQUIRED\" : lane.stale ? \"stale\" : \"fresh\",\n\t\t\tlane.dirty ? \"dirty\" : undefined,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\", \");\n\t\tlines.push(\n\t\t\t`- ${lane.laneKey} (${lane.branch}) +${lane.aheadOfMain}/-${lane.behindMain} [${flags}]` +\n\t\t\t\t`${lane.overlapWithLastLand.length > 0 ? ` overlap: ${lane.overlapWithLastLand.slice(0, 5).join(\", \")}` : \"\"}`,\n\t\t);\n\t}\n\tif (status.lanes.length === 0) lines.push(\"(no lanes)\");\n\tif (status.advice) lines.push(`advice: ${status.advice}`);\n\treturn lines;\n}\n\nconst WORKTREE_SYNC_PROMPT_GUIDELINES = [\n\t\"Work ONLY inside your lane worktree on your lane branch; never edit the hub checkout or touch main directly -- main moves exclusively through the land action.\",\n\t\"Commit your work on the lane branch, then land. Landing is refused while the lane is stale (G3): call sync first, resolve conflicts locally, then land.\",\n\t\"When a sync stops on conflicts, edit exactly the listed files, then call continue -- staging, marker verification, and rebase continuation are mechanical.\",\n\t\"After any other lane lands, your lane becomes stale; under the mandatory policy your file mutations are refused until you sync. git add/commit stay available to save WIP first.\",\n\t\"Check status when unsure -- it is the deterministic full picture; never infer sync state from raw git output.\",\n];\n\nexport function createWorktreeSyncToolDefinition(deps: WorktreeSyncToolDeps): ToolDefinition {\n\treturn {\n\t\tname: \"worktree_sync\",\n\t\tlabel: \"worktree_sync\",\n\t\tdescription:\n\t\t\t\"Hard-gated worktree-per-lane parallel work: each agent works in its own git worktree/branch; integration is always rebase-onto-main + ff-only land, serialized under one integration lock with the gate command verified at the exact landing tip. status/create_lane/sync/continue/abort_sync/land/release_lane/reconcile. Every outcome is a tagged code with the exact recovery step; landing while stale is structurally impossible.\",\n\t\tpromptSnippet: \"Coordinate parallel work: lane worktrees, rebase-onto-main sync, serialized gated landing.\",\n\t\tpromptGuidelines: WORKTREE_SYNC_PROMPT_GUIDELINES,\n\t\tparameters: worktreeSyncSchema,\n\t\texecutionMode: \"sequential\",\n\t\tasync execute(_toolCallId, input: WorktreeSyncToolInput, signal) {\n\t\t\tconst engineDeps: WorktreeSyncEngineDeps = { ...deps.engineDeps(), ...(signal ? { signal } : {}) };\n\t\t\tconst settings = deps.settings();\n\t\t\tconst laneKey = input.laneKey ?? deps.boundLaneKey();\n\n\t\t\tconst respond = (lines: string[], details: unknown) => ({\n\t\t\t\tcontent: [{ type: \"text\" as const, text: lines.join(\"\\n\") }],\n\t\t\t\tdetails: details as Record<string, unknown>,\n\t\t\t});\n\t\t\tconst needLane = (): string | undefined => {\n\t\t\t\tif (laneKey) return undefined;\n\t\t\t\treturn \"laneKey required: pass laneKey, or run inside a lane-bound session (PI_WORKTREE_LANE).\";\n\t\t\t};\n\n\t\t\tconst runTypedLaneAction = async (): Promise<ReturnType<typeof respond>> => {\n\t\t\t\tconst missingLane = needLane();\n\t\t\t\tif (missingLane) return respond([missingLane], { code: \"lane_not_found\", message: missingLane });\n\t\t\t\tconst context = await resolveRepoContext(engineDeps);\n\t\t\t\tif (\"code\" in context) return respond([`[${context.code}] ${context.message}`], context);\n\t\t\t\tconst lane = await readLane(context.paths, laneKey!);\n\t\t\t\tif (!lane || lane.status !== \"active\") {\n\t\t\t\t\tconst message = `active lane '${laneKey}' is not available`;\n\t\t\t\t\treturn respond([`[lane_not_found] ${message}`], { code: \"lane_not_found\", message });\n\t\t\t\t}\n\n\t\t\t\tconst requestedPaths = input.paths ?? [];\n\t\t\t\tconst gitPaths: string[] = [];\n\t\t\t\tfor (const requestedPath of requestedPaths) {\n\t\t\t\t\tif (!requestedPath || isAbsolute(requestedPath) || requestedPath.includes(\"\\0\")) {\n\t\t\t\t\t\tconst message = \"git path must be a non-empty relative path without NUL\";\n\t\t\t\t\t\treturn respond([`[path_outside_lane] ${message}`], { code: \"path_outside_lane\", message });\n\t\t\t\t\t}\n\t\t\t\t\tconst resolved = resolveLaneMutationPath(lane.worktreePath, requestedPath);\n\t\t\t\t\tif (!resolved) {\n\t\t\t\t\t\tconst message = `path '${requestedPath}' escapes the lane worktree`;\n\t\t\t\t\t\treturn respond([`[path_outside_lane] ${message}`], { code: \"path_outside_lane\", message });\n\t\t\t\t\t}\n\t\t\t\t\tgitPaths.push(relative(lane.worktreePath, resolved) || \".\");\n\t\t\t\t}\n\n\t\t\t\tlet command: string;\n\t\t\t\tlet args: string[];\n\t\t\t\tswitch (input.action) {\n\t\t\t\t\tcase \"git_status\":\n\t\t\t\t\t\tcommand = \"git\";\n\t\t\t\t\t\targs = [\"status\", \"--short\", \"--branch\"];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"git_diff\":\n\t\t\t\t\t\tcommand = \"git\";\n\t\t\t\t\t\targs = [\"diff\", \"--\", ...gitPaths];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"git_add\":\n\t\t\t\t\t\tif (gitPaths.length === 0) {\n\t\t\t\t\t\t\tconst message = \"git_add requires one or more explicit in-lane paths\";\n\t\t\t\t\t\t\treturn respond([`[path_outside_lane] ${message}`], { code: \"path_outside_lane\", message });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcommand = \"git\";\n\t\t\t\t\t\targs = [\"add\", \"--\", ...gitPaths];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"git_commit\":\n\t\t\t\t\t\tif (!input.message?.trim() || input.message.includes(\"\\0\")) {\n\t\t\t\t\t\t\tconst message = \"git_commit requires a non-empty literal message\";\n\t\t\t\t\t\t\treturn respond([`[git_failed] ${message}`], { code: \"git_failed\", message });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcommand = \"git\";\n\t\t\t\t\t\targs = [\"commit\", \"-m\", input.message];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"check\": {\n\t\t\t\t\t\tconst trustedCommand = settings.gateCommand?.trim();\n\t\t\t\t\t\tif (!trustedCommand) {\n\t\t\t\t\t\t\tconst message = \"no trusted worktree check is configured\";\n\t\t\t\t\t\t\treturn respond([`[gate_command_unset] ${message}`], { code: \"gate_command_unset\", message });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst shell = process.platform === \"win32\" ? \"cmd\" : \"sh\";\n\t\t\t\t\t\tconst shellFlag = process.platform === \"win32\" ? \"/c\" : \"-c\";\n\t\t\t\t\t\tconst result = await engineDeps.exec(shell, [shellFlag, trustedCommand], {\n\t\t\t\t\t\t\tcwd: lane.worktreePath,\n\t\t\t\t\t\t\ttimeout: 900_000,\n\t\t\t\t\t\t\tsignal: engineDeps.signal,\n\t\t\t\t\t\t\tmaxBuffer: 1024 * 1024,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst output = `${result.stdout}\\n${result.stderr}`.trim().slice(-8000);\n\t\t\t\t\t\tif (result.code !== 0) {\n\t\t\t\t\t\t\treturn respond([`[gate_failed] ${output || `trusted check exited ${result.code}`}`], {\n\t\t\t\t\t\t\t\tcode: \"gate_failed\",\n\t\t\t\t\t\t\t\texitCode: result.code,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn respond([output || \"trusted check passed\"], { code: \"ok\", action: input.action });\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn respond([\"typed lane action is unavailable for this request\"], { code: \"role_forbidden\" });\n\t\t\t\t}\n\n\t\t\t\tconst result = await engineDeps.exec(command, args, {\n\t\t\t\t\tcwd: lane.worktreePath,\n\t\t\t\t\ttimeout: 60_000,\n\t\t\t\t\tsignal: engineDeps.signal,\n\t\t\t\t\tmaxBuffer: 1024 * 1024,\n\t\t\t\t});\n\t\t\t\tconst output = `${result.stdout}\\n${result.stderr}`.trim().slice(-8000);\n\t\t\t\tif (result.code !== 0) {\n\t\t\t\t\treturn respond([`[git_failed] ${output || `${command} exited ${result.code}`}`], {\n\t\t\t\t\t\tcode: \"git_failed\",\n\t\t\t\t\t\taction: input.action,\n\t\t\t\t\t\texitCode: result.code,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn respond([output || `${input.action} completed`], { code: \"ok\", action: input.action });\n\t\t\t};\n\n\t\t\tif (deps.isWorker()) {\n\t\t\t\tconst bound = deps.boundLaneKey();\n\t\t\t\tif (input.laneKey !== undefined && input.laneKey !== bound) {\n\t\t\t\t\tconst message = \"workers may only target their bound lane\";\n\t\t\t\t\treturn respond([message], { code: \"role_forbidden\", message });\n\t\t\t\t}\n\t\t\t\tconst landAllowed = input.action === \"land\" && settings.workerLand === \"allow\";\n\t\t\t\tif (!WORKER_ALLOWED_ACTIONS.has(input.action) && !landAllowed) {\n\t\t\t\t\tconst message =\n\t\t\t\t\t\tinput.action === \"land\"\n\t\t\t\t\t\t\t? 'workers may not land (worktreeSync.workerLand is \"deny\")'\n\t\t\t\t\t\t\t: `workers may not run action \"${input.action}\"`;\n\t\t\t\t\treturn respond([message], { code: \"role_forbidden\", message });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch (input.action) {\n\t\t\t\tcase \"git_status\":\n\t\t\t\tcase \"git_diff\":\n\t\t\t\tcase \"git_add\":\n\t\t\t\tcase \"git_commit\":\n\t\t\t\tcase \"check\":\n\t\t\t\t\treturn runTypedLaneAction();\n\t\t\t\tcase \"status\": {\n\t\t\t\t\tconst status = await buildSyncStatus(engineDeps, { policy: settings.syncPolicy });\n\t\t\t\t\tif (status.code !== \"ok\") return respond([`[${status.code}] ${status.message}`], status);\n\t\t\t\t\treturn respond(formatStatus(status), status);\n\t\t\t\t}\n\t\t\t\tcase \"create_lane\": {\n\t\t\t\t\tconst created = await createLane(engineDeps, {\n\t\t\t\t\t\t...(input.laneKey !== undefined ? { laneKey: input.laneKey } : {}),\n\t\t\t\t\t\t...(input.goalId !== undefined ? { goalId: input.goalId } : {}),\n\t\t\t\t\t\t...(input.requirementId !== undefined ? { requirementId: input.requirementId } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tif (created.code !== \"ok\") return respond([`[${created.code}] ${created.message}`], created);\n\t\t\t\t\treturn respond(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t`lane '${created.lane.laneKey}' created: branch ${created.lane.branch}, checkout ${created.lane.worktreePath}`,\n\t\t\t\t\t\t],\n\t\t\t\t\t\tcreated,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcase \"sync\": {\n\t\t\t\t\tconst missing = needLane();\n\t\t\t\t\tif (missing) return respond([missing], { code: \"lane_not_found\", message: missing });\n\t\t\t\t\tconst synced = await syncLane(engineDeps, { laneKey: laneKey as string });\n\t\t\t\t\tif (synced.code === \"sync_clean\") {\n\t\t\t\t\t\treturn respond(\n\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\tsynced.alreadyFresh\n\t\t\t\t\t\t\t\t\t? `lane '${synced.laneKey}' already contains current main -- nothing to do`\n\t\t\t\t\t\t\t\t\t: `lane '${synced.laneKey}' rebased onto current main (auto-continued ${synced.autoContinued} step(s))`,\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tsynced,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (synced.code === \"sync_conflicts\") return respond(formatWorklist(synced.worklist), synced);\n\t\t\t\t\treturn respond(\n\t\t\t\t\t\t[`[${synced.code}] ${synced.message}${synced.paths ? `\\n${synced.paths.join(\"\\n\")}` : \"\"}`],\n\t\t\t\t\t\tsynced,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcase \"continue\": {\n\t\t\t\t\tconst missing = needLane();\n\t\t\t\t\tif (missing) return respond([missing], { code: \"lane_not_found\", message: missing });\n\t\t\t\t\tconst continued = await continueSync(engineDeps, { laneKey: laneKey as string });\n\t\t\t\t\tif (continued.code === \"sync_clean\") {\n\t\t\t\t\t\treturn respond(\n\t\t\t\t\t\t\t[`lane '${continued.laneKey}' rebase completed -- lane is fresh relative to the synced main`],\n\t\t\t\t\t\t\tcontinued,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (continued.code === \"sync_conflicts\") return respond(formatWorklist(continued.worklist), continued);\n\t\t\t\t\treturn respond(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t`[${continued.code}] ${continued.message}${continued.paths ? `\\n${continued.paths.join(\"\\n\")}` : \"\"}`,\n\t\t\t\t\t\t],\n\t\t\t\t\t\tcontinued,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcase \"abort_sync\": {\n\t\t\t\t\tconst missing = needLane();\n\t\t\t\t\tif (missing) return respond([missing], { code: \"lane_not_found\", message: missing });\n\t\t\t\t\tconst aborted = await abortSync(engineDeps, { laneKey: laneKey as string });\n\t\t\t\t\tif (aborted.code !== \"ok\") return respond([`[${aborted.code}] ${aborted.message}`], aborted);\n\t\t\t\t\treturn respond(\n\t\t\t\t\t\t[`lane '${aborted.laneKey}' rebase aborted -- back to its pre-sync tip (still stale)`],\n\t\t\t\t\t\taborted,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcase \"land\": {\n\t\t\t\t\tconst missing = needLane();\n\t\t\t\t\tif (missing) return respond([missing], { code: \"lane_not_found\", message: missing });\n\t\t\t\t\tconst landed = await landLane(engineDeps, {\n\t\t\t\t\t\tlaneKey: laneKey as string,\n\t\t\t\t\t\tgate: settings.gate,\n\t\t\t\t\t\t...(settings.gateCommand !== undefined ? { gateCommand: settings.gateCommand } : {}),\n\t\t\t\t\t\tgateTimeoutMs: settings.gateTimeoutMs,\n\t\t\t\t\t});\n\t\t\t\t\tif (landed.code !== \"ok\") {\n\t\t\t\t\t\treturn respond(\n\t\t\t\t\t\t\t[`[${landed.code}] ${landed.message}${landed.paths ? `\\n${landed.paths.join(\"\\n\")}` : \"\"}`],\n\t\t\t\t\t\t\tlanded,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn respond(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t`lane '${landed.laneKey}' LANDED: epoch ${landed.epoch}, main is now ${landed.mainSha.slice(0, 12)} (gate: ${landed.gate}). All other lanes must sync before their next land.`,\n\t\t\t\t\t\t],\n\t\t\t\t\t\tlanded,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcase \"release_lane\": {\n\t\t\t\t\tconst missing = needLane();\n\t\t\t\t\tif (missing) return respond([missing], { code: \"lane_not_found\", message: missing });\n\t\t\t\t\tconst released = await releaseLane(engineDeps, {\n\t\t\t\t\t\tlaneKey: laneKey as string,\n\t\t\t\t\t\t...(input.confirm !== undefined ? { confirm: input.confirm } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tif (released.code !== \"released\") return respond([`[${released.code}] ${released.message}`], released);\n\t\t\t\t\treturn respond([`lane '${released.laneKey}' released`], released);\n\t\t\t\t}\n\t\t\t\tcase \"reconcile\": {\n\t\t\t\t\tconst reconciled = await reconcile(engineDeps);\n\t\t\t\t\tif (reconciled.code !== \"reconciled\")\n\t\t\t\t\t\treturn respond([`[${reconciled.code}] ${reconciled.message}`], reconciled);\n\t\t\t\t\treturn respond(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t`reconciled: ${reconciled.orphanedLaneKeys.length} orphaned, ${reconciled.reRegisteredLaneKeys.length} re-registered, ${reconciled.ownerClearedLaneKeys.length} owners cleared${reconciled.staleLockReleased ? \", stale lock released\" : \"\"}`,\n\t\t\t\t\t\t],\n\t\t\t\t\t\treconciled,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n"]}