@caupulican/pi-adaptative 0.81.39 → 0.81.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (884) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +3 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +4 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
  13. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
  14. package/dist/cli/args.d.ts +4 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +31 -1
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-directory-layout.d.ts +15 -0
  19. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  20. package/dist/core/agent-directory-layout.js +72 -0
  21. package/dist/core/agent-directory-layout.js.map +1 -0
  22. package/dist/core/agent-paths.d.ts +25 -2
  23. package/dist/core/agent-paths.d.ts.map +1 -1
  24. package/dist/core/agent-paths.js +79 -4
  25. package/dist/core/agent-paths.js.map +1 -1
  26. package/dist/core/agent-session-contracts.d.ts +293 -0
  27. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  28. package/dist/core/agent-session-contracts.js +26 -0
  29. package/dist/core/agent-session-contracts.js.map +1 -0
  30. package/dist/core/agent-session-runtime.d.ts +52 -8
  31. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  32. package/dist/core/agent-session-runtime.js +400 -79
  33. package/dist/core/agent-session-runtime.js.map +1 -1
  34. package/dist/core/agent-session-services.d.ts +1 -0
  35. package/dist/core/agent-session-services.d.ts.map +1 -1
  36. package/dist/core/agent-session-services.js +1 -0
  37. package/dist/core/agent-session-services.js.map +1 -1
  38. package/dist/core/agent-session.d.ts +74 -518
  39. package/dist/core/agent-session.d.ts.map +1 -1
  40. package/dist/core/agent-session.js +370 -1432
  41. package/dist/core/agent-session.js.map +1 -1
  42. package/dist/core/auth-storage.d.ts.map +1 -1
  43. package/dist/core/auth-storage.js +3 -1
  44. package/dist/core/auth-storage.js.map +1 -1
  45. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  46. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  47. package/dist/core/autonomy/approval-gate.js +6 -28
  48. package/dist/core/autonomy/approval-gate.js.map +1 -1
  49. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  50. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  51. package/dist/core/autonomy/bounded-completion.js +1 -1
  52. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  53. package/dist/core/autonomy/contracts.d.ts +20 -12
  54. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  55. package/dist/core/autonomy/contracts.js.map +1 -1
  56. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  57. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  58. package/dist/core/autonomy/foreground-envelope.js +8 -25
  59. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  60. package/dist/core/autonomy/gates.d.ts.map +1 -1
  61. package/dist/core/autonomy/gates.js +8 -10
  62. package/dist/core/autonomy/gates.js.map +1 -1
  63. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  64. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  65. package/dist/core/autonomy/lane-private-paths.js +16 -0
  66. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  67. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  68. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  69. package/dist/core/autonomy/lane-tool-surface.js +48 -9
  70. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  71. package/dist/core/autonomy/lane-tracker.d.ts +14 -0
  72. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  73. package/dist/core/autonomy/lane-tracker.js +38 -0
  74. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  75. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  76. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  77. package/dist/core/autonomy/risk-assessment.js +1 -123
  78. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  79. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  80. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  81. package/dist/core/autonomy/session-lane-record.js +16 -29
  82. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  83. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  84. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  85. package/dist/core/autonomy/telemetry-events.js +1 -1
  86. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  87. package/dist/core/autonomy-telemetry.d.ts +7 -7
  88. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  89. package/dist/core/autonomy-telemetry.js +9 -9
  90. package/dist/core/autonomy-telemetry.js.map +1 -1
  91. package/dist/core/background-lane-controller.d.ts +56 -236
  92. package/dist/core/background-lane-controller.d.ts.map +1 -1
  93. package/dist/core/background-lane-controller.js +141 -1273
  94. package/dist/core/background-lane-controller.js.map +1 -1
  95. package/dist/core/bedrock-sso-login.d.ts +16 -0
  96. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  97. package/dist/core/bedrock-sso-login.js +98 -0
  98. package/dist/core/bedrock-sso-login.js.map +1 -0
  99. package/dist/core/capability-contract.d.ts +4 -0
  100. package/dist/core/capability-contract.d.ts.map +1 -0
  101. package/dist/core/capability-contract.js +28 -0
  102. package/dist/core/capability-contract.js.map +1 -0
  103. package/dist/core/compaction-controller.d.ts +90 -0
  104. package/dist/core/compaction-controller.d.ts.map +1 -0
  105. package/dist/core/compaction-controller.js +452 -0
  106. package/dist/core/compaction-controller.js.map +1 -0
  107. package/dist/core/compaction-support.d.ts +13 -17
  108. package/dist/core/compaction-support.d.ts.map +1 -1
  109. package/dist/core/compaction-support.js +3 -3
  110. package/dist/core/compaction-support.js.map +1 -1
  111. package/dist/core/context/context-artifacts.d.ts +6 -2
  112. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  113. package/dist/core/context/context-artifacts.js +34 -2
  114. package/dist/core/context/context-artifacts.js.map +1 -1
  115. package/dist/core/context/context-store-retention.d.ts +8 -2
  116. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  117. package/dist/core/context/context-store-retention.js +158 -35
  118. package/dist/core/context/context-store-retention.js.map +1 -1
  119. package/dist/core/context/okf-memory.d.ts.map +1 -1
  120. package/dist/core/context/okf-memory.js +9 -11
  121. package/dist/core/context/okf-memory.js.map +1 -1
  122. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  123. package/dist/core/context/sqlite-runtime-index.js +6 -8
  124. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  125. package/dist/core/context-gc.d.ts +3 -0
  126. package/dist/core/context-gc.d.ts.map +1 -1
  127. package/dist/core/context-gc.js +10 -5
  128. package/dist/core/context-gc.js.map +1 -1
  129. package/dist/core/context-pipeline.d.ts +1 -1
  130. package/dist/core/context-pipeline.d.ts.map +1 -1
  131. package/dist/core/context-pipeline.js +16 -37
  132. package/dist/core/context-pipeline.js.map +1 -1
  133. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  134. package/dist/core/cost/cost-summary.js +5 -3
  135. package/dist/core/cost/cost-summary.js.map +1 -1
  136. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  137. package/dist/core/cost/daily-usage.js +4 -5
  138. package/dist/core/cost/daily-usage.js.map +1 -1
  139. package/dist/core/default-tool-surface.d.ts.map +1 -1
  140. package/dist/core/default-tool-surface.js +2 -0
  141. package/dist/core/default-tool-surface.js.map +1 -1
  142. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  143. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  144. package/dist/core/delegation/managed-lane-controller.js +217 -0
  145. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  146. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  147. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-claim.js +98 -0
  149. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  150. package/dist/core/delegation/worker-actions.d.ts +7 -5
  151. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  152. package/dist/core/delegation/worker-actions.js +20 -4
  153. package/dist/core/delegation/worker-actions.js.map +1 -1
  154. package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
  155. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  156. package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
  157. package/dist/core/delegation/worker-claim.js.map +1 -0
  158. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  159. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  160. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  161. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  162. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  163. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  164. package/dist/core/delegation/worker-delegation-request.js +2 -0
  165. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  166. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  167. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  168. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  169. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  170. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  171. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  172. package/dist/core/delegation/worker-execution-policy.js +160 -0
  173. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  174. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  175. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  176. package/dist/core/delegation/worker-lane-projection.js +100 -0
  177. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  178. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  179. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  180. package/dist/core/delegation/worker-lifecycle.js +339 -0
  181. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  182. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  183. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  184. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  185. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  186. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  187. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  188. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  189. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  190. package/dist/core/delegation/worker-runner.d.ts +25 -14
  191. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  192. package/dist/core/delegation/worker-runner.js +122 -53
  193. package/dist/core/delegation/worker-runner.js.map +1 -1
  194. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  195. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  196. package/dist/core/delegation/worker-task-label.js +11 -0
  197. package/dist/core/delegation/worker-task-label.js.map +1 -0
  198. package/dist/core/doctor.d.ts +8 -0
  199. package/dist/core/doctor.d.ts.map +1 -1
  200. package/dist/core/doctor.js +32 -1
  201. package/dist/core/doctor.js.map +1 -1
  202. package/dist/core/extension-import-authority.d.ts +6 -0
  203. package/dist/core/extension-import-authority.d.ts.map +1 -0
  204. package/dist/core/extension-import-authority.js +10 -0
  205. package/dist/core/extension-import-authority.js.map +1 -0
  206. package/dist/core/extensions/index.d.ts +1 -1
  207. package/dist/core/extensions/index.d.ts.map +1 -1
  208. package/dist/core/extensions/index.js.map +1 -1
  209. package/dist/core/extensions/loader.d.ts +5 -1
  210. package/dist/core/extensions/loader.d.ts.map +1 -1
  211. package/dist/core/extensions/loader.js +52 -18
  212. package/dist/core/extensions/loader.js.map +1 -1
  213. package/dist/core/extensions/runner.d.ts +3 -0
  214. package/dist/core/extensions/runner.d.ts.map +1 -1
  215. package/dist/core/extensions/runner.js +20 -5
  216. package/dist/core/extensions/runner.js.map +1 -1
  217. package/dist/core/extensions/stale-context.d.ts +2 -0
  218. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  219. package/dist/core/extensions/stale-context.js +2 -0
  220. package/dist/core/extensions/stale-context.js.map +1 -0
  221. package/dist/core/extensions/storage.d.ts +8 -0
  222. package/dist/core/extensions/storage.d.ts.map +1 -0
  223. package/dist/core/extensions/storage.js +28 -0
  224. package/dist/core/extensions/storage.js.map +1 -0
  225. package/dist/core/extensions/types.d.ts +78 -21
  226. package/dist/core/extensions/types.d.ts.map +1 -1
  227. package/dist/core/extensions/types.js.map +1 -1
  228. package/dist/core/failure-corpus.d.ts +1 -15
  229. package/dist/core/failure-corpus.d.ts.map +1 -1
  230. package/dist/core/failure-corpus.js +9 -37
  231. package/dist/core/failure-corpus.js.map +1 -1
  232. package/dist/core/foreground-recovery-controller.d.ts +53 -0
  233. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  234. package/dist/core/foreground-recovery-controller.js +111 -0
  235. package/dist/core/foreground-recovery-controller.js.map +1 -0
  236. package/dist/core/gateways/channel-provider.d.ts +3 -0
  237. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  238. package/dist/core/gateways/channel-provider.js +31 -6
  239. package/dist/core/gateways/channel-provider.js.map +1 -1
  240. package/dist/core/goal-loop-controller.d.ts +14 -9
  241. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  242. package/dist/core/goal-loop-controller.js +47 -75
  243. package/dist/core/goal-loop-controller.js.map +1 -1
  244. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  245. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  246. package/dist/core/goals/compact-goal-context.js +59 -0
  247. package/dist/core/goals/compact-goal-context.js.map +1 -0
  248. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  249. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  250. package/dist/core/goals/goal-acceptance.js +27 -0
  251. package/dist/core/goals/goal-acceptance.js.map +1 -0
  252. package/dist/core/goals/goal-auto-continue-controller.d.ts +28 -0
  253. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  254. package/dist/core/goals/goal-auto-continue-controller.js +90 -0
  255. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  256. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  257. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  258. package/dist/core/goals/goal-continuation-controller.js +52 -11
  259. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  260. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  261. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  262. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  263. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  264. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  265. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  266. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  267. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  268. package/dist/core/goals/goal-lifecycle.d.ts +43 -0
  269. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  270. package/dist/core/goals/goal-lifecycle.js +102 -0
  271. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  272. package/dist/core/goals/goal-record.d.ts +17 -0
  273. package/dist/core/goals/goal-record.d.ts.map +1 -0
  274. package/dist/core/goals/goal-record.js +31 -0
  275. package/dist/core/goals/goal-record.js.map +1 -0
  276. package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
  277. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  278. package/dist/core/goals/goal-runtime-snapshot.js +10 -8
  279. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  280. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  281. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  282. package/dist/core/goals/goal-session-controller.js +128 -0
  283. package/dist/core/goals/goal-session-controller.js.map +1 -0
  284. package/dist/core/goals/goal-state.d.ts +46 -25
  285. package/dist/core/goals/goal-state.d.ts.map +1 -1
  286. package/dist/core/goals/goal-state.js +91 -24
  287. package/dist/core/goals/goal-state.js.map +1 -1
  288. package/dist/core/goals/goal-tool-core.d.ts +9 -10
  289. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  290. package/dist/core/goals/goal-tool-core.js +60 -75
  291. package/dist/core/goals/goal-tool-core.js.map +1 -1
  292. package/dist/core/goals/session-goal-state.d.ts +20 -12
  293. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  294. package/dist/core/goals/session-goal-state.js +133 -33
  295. package/dist/core/goals/session-goal-state.js.map +1 -1
  296. package/dist/core/human-input-controller.d.ts +47 -0
  297. package/dist/core/human-input-controller.d.ts.map +1 -0
  298. package/dist/core/human-input-controller.js +181 -0
  299. package/dist/core/human-input-controller.js.map +1 -0
  300. package/dist/core/human-input.d.ts +100 -0
  301. package/dist/core/human-input.d.ts.map +1 -0
  302. package/dist/core/human-input.js +362 -0
  303. package/dist/core/human-input.js.map +1 -0
  304. package/dist/core/index.d.ts +9 -1
  305. package/dist/core/index.d.ts.map +1 -1
  306. package/dist/core/index.js +9 -1
  307. package/dist/core/index.js.map +1 -1
  308. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  309. package/dist/core/install-telemetry.d.ts.map +1 -0
  310. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  311. package/dist/core/install-telemetry.js.map +1 -0
  312. package/dist/core/keybindings.d.ts +17 -1
  313. package/dist/core/keybindings.d.ts.map +1 -1
  314. package/dist/core/keybindings.js +24 -6
  315. package/dist/core/keybindings.js.map +1 -1
  316. package/dist/core/learning/learning-audit.d.ts +2 -4
  317. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  318. package/dist/core/learning/learning-audit.js +9 -29
  319. package/dist/core/learning/learning-audit.js.map +1 -1
  320. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  321. package/dist/core/learning/learning-gate.js +1 -6
  322. package/dist/core/learning/learning-gate.js.map +1 -1
  323. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  324. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  325. package/dist/core/learning/session-learning-decision.js +9 -29
  326. package/dist/core/learning/session-learning-decision.js.map +1 -1
  327. package/dist/core/local-runtime-controller.d.ts +1 -1
  328. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  329. package/dist/core/local-runtime-controller.js.map +1 -1
  330. package/dist/core/memory-controller.d.ts.map +1 -1
  331. package/dist/core/memory-controller.js +4 -4
  332. package/dist/core/memory-controller.js.map +1 -1
  333. package/dist/core/model-capability.d.ts +0 -19
  334. package/dist/core/model-capability.d.ts.map +1 -1
  335. package/dist/core/model-capability.js +1 -19
  336. package/dist/core/model-capability.js.map +1 -1
  337. package/dist/core/model-registry.d.ts +6 -1
  338. package/dist/core/model-registry.d.ts.map +1 -1
  339. package/dist/core/model-registry.js +13 -5
  340. package/dist/core/model-registry.js.map +1 -1
  341. package/dist/core/model-resolver.d.ts +17 -2
  342. package/dist/core/model-resolver.d.ts.map +1 -1
  343. package/dist/core/model-resolver.js +38 -25
  344. package/dist/core/model-resolver.js.map +1 -1
  345. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  346. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  347. package/dist/core/model-router/intent-classifier.js +1 -156
  348. package/dist/core/model-router/intent-classifier.js.map +1 -1
  349. package/dist/core/model-router-controller.d.ts +1 -1
  350. package/dist/core/model-router-controller.d.ts.map +1 -1
  351. package/dist/core/model-router-controller.js +2 -2
  352. package/dist/core/model-router-controller.js.map +1 -1
  353. package/dist/core/model-selection-controller.d.ts +5 -5
  354. package/dist/core/model-selection-controller.d.ts.map +1 -1
  355. package/dist/core/model-selection-controller.js.map +1 -1
  356. package/dist/core/model-tool-protocol.d.ts +23 -0
  357. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  358. package/dist/core/model-tool-protocol.js +43 -0
  359. package/dist/core/model-tool-protocol.js.map +1 -0
  360. package/dist/core/models/adaptation-store.d.ts +4 -6
  361. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  362. package/dist/core/models/adaptation-store.js +95 -83
  363. package/dist/core/models/adaptation-store.js.map +1 -1
  364. package/dist/core/models/fitness-store.d.ts +2 -12
  365. package/dist/core/models/fitness-store.d.ts.map +1 -1
  366. package/dist/core/models/fitness-store.js +84 -57
  367. package/dist/core/models/fitness-store.js.map +1 -1
  368. package/dist/core/models/host-state-store.d.ts +34 -0
  369. package/dist/core/models/host-state-store.d.ts.map +1 -0
  370. package/dist/core/models/host-state-store.js +86 -0
  371. package/dist/core/models/host-state-store.js.map +1 -0
  372. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  373. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  374. package/dist/core/orchestration/agent-resume.js +90 -0
  375. package/dist/core/orchestration/agent-resume.js.map +1 -0
  376. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  377. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  378. package/dist/core/orchestration/capability-gateway.js +152 -0
  379. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  380. package/dist/core/orchestration/contracts.d.ts +343 -0
  381. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  382. package/dist/core/orchestration/contracts.js +135 -0
  383. package/dist/core/orchestration/contracts.js.map +1 -0
  384. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  385. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  386. package/dist/core/orchestration/delegation-ledger.js +200 -0
  387. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  388. package/dist/core/orchestration/event-store.d.ts +83 -0
  389. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  390. package/dist/core/orchestration/event-store.js +560 -0
  391. package/dist/core/orchestration/event-store.js.map +1 -0
  392. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  393. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  394. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  395. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  396. package/dist/core/orchestration/model-binding.d.ts +15 -0
  397. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  398. package/dist/core/orchestration/model-binding.js +29 -0
  399. package/dist/core/orchestration/model-binding.js.map +1 -0
  400. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  401. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  402. package/dist/core/orchestration/policy-compiler.js +191 -0
  403. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  404. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  405. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  406. package/dist/core/orchestration/policy-gate.js +24 -0
  407. package/dist/core/orchestration/policy-gate.js.map +1 -0
  408. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  409. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  410. package/dist/core/orchestration/profile-registry.js +393 -0
  411. package/dist/core/orchestration/profile-registry.js.map +1 -0
  412. package/dist/core/orchestration/profile-store.d.ts +31 -0
  413. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  414. package/dist/core/orchestration/profile-store.js +136 -0
  415. package/dist/core/orchestration/profile-store.js.map +1 -0
  416. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  417. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  418. package/dist/core/orchestration/risk-budget.js +48 -0
  419. package/dist/core/orchestration/risk-budget.js.map +1 -0
  420. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  421. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  422. package/dist/core/orchestration/task-runtime.js +1600 -0
  423. package/dist/core/orchestration/task-runtime.js.map +1 -0
  424. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  425. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  426. package/dist/core/orchestration/work-state-projection.js +116 -0
  427. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  428. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  429. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  430. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  431. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  432. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  433. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  434. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  435. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  436. package/dist/core/package-manager.d.ts.map +1 -1
  437. package/dist/core/package-manager.js +20 -3
  438. package/dist/core/package-manager.js.map +1 -1
  439. package/dist/core/process-identity.d.ts +11 -0
  440. package/dist/core/process-identity.d.ts.map +1 -0
  441. package/dist/core/process-identity.js +26 -0
  442. package/dist/core/process-identity.js.map +1 -0
  443. package/dist/core/process-matrix/codes.d.ts +14 -3
  444. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  445. package/dist/core/process-matrix/codes.js.map +1 -1
  446. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  447. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  448. package/dist/core/process-matrix/resume-launcher.js +62 -0
  449. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  450. package/dist/core/process-matrix/runtime.d.ts +37 -22
  451. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  452. package/dist/core/process-matrix/runtime.js +399 -76
  453. package/dist/core/process-matrix/runtime.js.map +1 -1
  454. package/dist/core/process-matrix/store.d.ts +5 -2
  455. package/dist/core/process-matrix/store.d.ts.map +1 -1
  456. package/dist/core/process-matrix/store.js +123 -14
  457. package/dist/core/process-matrix/store.js.map +1 -1
  458. package/dist/core/process-matrix/supervisor.d.ts +10 -7
  459. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  460. package/dist/core/process-matrix/supervisor.js +45 -14
  461. package/dist/core/process-matrix/supervisor.js.map +1 -1
  462. package/dist/core/profile-filter-controller.d.ts +8 -1
  463. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  464. package/dist/core/profile-filter-controller.js +23 -5
  465. package/dist/core/profile-filter-controller.js.map +1 -1
  466. package/dist/core/profile-registry.d.ts.map +1 -1
  467. package/dist/core/profile-registry.js +6 -8
  468. package/dist/core/profile-registry.js.map +1 -1
  469. package/dist/core/prompt-templates.d.ts +1 -0
  470. package/dist/core/prompt-templates.d.ts.map +1 -1
  471. package/dist/core/prompt-templates.js +18 -29
  472. package/dist/core/prompt-templates.js.map +1 -1
  473. package/dist/core/reflection-controller.d.ts +5 -5
  474. package/dist/core/reflection-controller.d.ts.map +1 -1
  475. package/dist/core/reflection-controller.js +5 -2
  476. package/dist/core/reflection-controller.js.map +1 -1
  477. package/dist/core/reload-blockers.d.ts.map +1 -1
  478. package/dist/core/reload-blockers.js +6 -8
  479. package/dist/core/reload-blockers.js.map +1 -1
  480. package/dist/core/request-auth.d.ts +7 -0
  481. package/dist/core/request-auth.d.ts.map +1 -0
  482. package/dist/core/request-auth.js +8 -0
  483. package/dist/core/request-auth.js.map +1 -0
  484. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  485. package/dist/core/research/evidence-bundle.js +1 -6
  486. package/dist/core/research/evidence-bundle.js.map +1 -1
  487. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  488. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  489. package/dist/core/research/lane-model-resolver.js +65 -0
  490. package/dist/core/research/lane-model-resolver.js.map +1 -0
  491. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  492. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  493. package/dist/core/research/model-fitness-controller.js +106 -0
  494. package/dist/core/research/model-fitness-controller.js.map +1 -0
  495. package/dist/core/research/model-fitness.d.ts +1 -1
  496. package/dist/core/research/model-fitness.d.ts.map +1 -1
  497. package/dist/core/research/model-fitness.js +4 -4
  498. package/dist/core/research/model-fitness.js.map +1 -1
  499. package/dist/core/research/research-gate.d.ts.map +1 -1
  500. package/dist/core/research/research-gate.js +7 -7
  501. package/dist/core/research/research-gate.js.map +1 -1
  502. package/dist/core/research/research-lane-controller.d.ts +62 -0
  503. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  504. package/dist/core/research/research-lane-controller.js +292 -0
  505. package/dist/core/research/research-lane-controller.js.map +1 -0
  506. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  507. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  508. package/dist/core/research/session-evidence-bundle.js +10 -46
  509. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  510. package/dist/core/resource-loader.d.ts.map +1 -1
  511. package/dist/core/resource-loader.js +23 -8
  512. package/dist/core/resource-loader.js.map +1 -1
  513. package/dist/core/risk-classifier.d.ts +6 -0
  514. package/dist/core/risk-classifier.d.ts.map +1 -0
  515. package/dist/core/risk-classifier.js +233 -0
  516. package/dist/core/risk-classifier.js.map +1 -0
  517. package/dist/core/runtime-builder.d.ts +41 -23
  518. package/dist/core/runtime-builder.d.ts.map +1 -1
  519. package/dist/core/runtime-builder.js +365 -253
  520. package/dist/core/runtime-builder.js.map +1 -1
  521. package/dist/core/sdk.d.ts +6 -3
  522. package/dist/core/sdk.d.ts.map +1 -1
  523. package/dist/core/sdk.js +68 -25
  524. package/dist/core/sdk.js.map +1 -1
  525. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  526. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  527. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  528. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  529. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  530. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  531. package/dist/core/secrets/secret-dotenv.js +183 -0
  532. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  533. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  534. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  535. package/dist/core/secrets/secret-vault-format.js +397 -0
  536. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  537. package/dist/core/secrets/secret-vault.d.ts +72 -0
  538. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  539. package/dist/core/secrets/secret-vault.js +671 -0
  540. package/dist/core/secrets/secret-vault.js.map +1 -0
  541. package/dist/core/session-analytics.d.ts +4 -23
  542. package/dist/core/session-analytics.d.ts.map +1 -1
  543. package/dist/core/session-analytics.js +67 -70
  544. package/dist/core/session-analytics.js.map +1 -1
  545. package/dist/core/session-image-store.d.ts +33 -0
  546. package/dist/core/session-image-store.d.ts.map +1 -0
  547. package/dist/core/session-image-store.js +283 -0
  548. package/dist/core/session-image-store.js.map +1 -0
  549. package/dist/core/session-role.d.ts +11 -4
  550. package/dist/core/session-role.d.ts.map +1 -1
  551. package/dist/core/session-role.js +24 -5
  552. package/dist/core/session-role.js.map +1 -1
  553. package/dist/core/session-snapshot.d.ts +34 -0
  554. package/dist/core/session-snapshot.d.ts.map +1 -0
  555. package/dist/core/session-snapshot.js +68 -0
  556. package/dist/core/session-snapshot.js.map +1 -0
  557. package/dist/core/session-supervision-runtime.d.ts +31 -0
  558. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  559. package/dist/core/session-supervision-runtime.js +97 -0
  560. package/dist/core/session-supervision-runtime.js.map +1 -0
  561. package/dist/core/session-tree-navigator.d.ts +4 -6
  562. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  563. package/dist/core/session-tree-navigator.js +4 -1
  564. package/dist/core/session-tree-navigator.js.map +1 -1
  565. package/dist/core/settings-manager.d.ts +10 -5
  566. package/dist/core/settings-manager.d.ts.map +1 -1
  567. package/dist/core/settings-manager.js +81 -29
  568. package/dist/core/settings-manager.js.map +1 -1
  569. package/dist/core/slash-commands.d.ts.map +1 -1
  570. package/dist/core/slash-commands.js +2 -2
  571. package/dist/core/slash-commands.js.map +1 -1
  572. package/dist/core/tasks/session-task-state.d.ts +2 -4
  573. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  574. package/dist/core/tasks/session-task-state.js +10 -28
  575. package/dist/core/tasks/session-task-state.js.map +1 -1
  576. package/dist/core/tasks/task-projection.d.ts +20 -0
  577. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  578. package/dist/core/tasks/task-projection.js +47 -0
  579. package/dist/core/tasks/task-projection.js.map +1 -0
  580. package/dist/core/tasks/task-state.d.ts +4 -0
  581. package/dist/core/tasks/task-state.d.ts.map +1 -1
  582. package/dist/core/tasks/task-state.js +28 -11
  583. package/dist/core/tasks/task-state.js.map +1 -1
  584. package/dist/core/tool-capability-policy.d.ts +13 -0
  585. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  586. package/dist/core/tool-capability-policy.js +86 -0
  587. package/dist/core/tool-capability-policy.js.map +1 -0
  588. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  589. package/dist/core/tool-gate-controller.js +8 -2
  590. package/dist/core/tool-gate-controller.js.map +1 -1
  591. package/dist/core/tool-protocol-controller.d.ts +89 -0
  592. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  593. package/dist/core/tool-protocol-controller.js +512 -0
  594. package/dist/core/tool-protocol-controller.js.map +1 -0
  595. package/dist/core/tool-recovery-log-records.d.ts +2 -3
  596. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  597. package/dist/core/tool-recovery-log-records.js +9 -35
  598. package/dist/core/tool-recovery-log-records.js.map +1 -1
  599. package/dist/core/tool-recovery-stats.d.ts +21 -1
  600. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  601. package/dist/core/tool-recovery-stats.js.map +1 -1
  602. package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
  603. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  604. package/dist/core/tool-selection/tool-performance-store.js +97 -138
  605. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  606. package/dist/core/tools/ask-question.d.ts +124 -0
  607. package/dist/core/tools/ask-question.d.ts.map +1 -0
  608. package/dist/core/tools/ask-question.js +693 -0
  609. package/dist/core/tools/ask-question.js.map +1 -0
  610. package/dist/core/tools/bash.d.ts +5 -0
  611. package/dist/core/tools/bash.d.ts.map +1 -1
  612. package/dist/core/tools/bash.js +59 -5
  613. package/dist/core/tools/bash.js.map +1 -1
  614. package/dist/core/tools/delegate-status.d.ts +31 -3
  615. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  616. package/dist/core/tools/delegate-status.js +148 -29
  617. package/dist/core/tools/delegate-status.js.map +1 -1
  618. package/dist/core/tools/delegate.d.ts +15 -13
  619. package/dist/core/tools/delegate.d.ts.map +1 -1
  620. package/dist/core/tools/delegate.js +106 -23
  621. package/dist/core/tools/delegate.js.map +1 -1
  622. package/dist/core/tools/extensionify.d.ts.map +1 -1
  623. package/dist/core/tools/extensionify.js +1 -0
  624. package/dist/core/tools/extensionify.js.map +1 -1
  625. package/dist/core/tools/git-filter.d.ts +1 -8
  626. package/dist/core/tools/git-filter.d.ts.map +1 -1
  627. package/dist/core/tools/git-filter.js +2 -63
  628. package/dist/core/tools/git-filter.js.map +1 -1
  629. package/dist/core/tools/goal.d.ts +10 -8
  630. package/dist/core/tools/goal.d.ts.map +1 -1
  631. package/dist/core/tools/goal.js +106 -28
  632. package/dist/core/tools/goal.js.map +1 -1
  633. package/dist/core/tools/index.d.ts +1 -0
  634. package/dist/core/tools/index.d.ts.map +1 -1
  635. package/dist/core/tools/index.js +1 -0
  636. package/dist/core/tools/index.js.map +1 -1
  637. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  638. package/dist/core/tools/model-fitness.js +2 -2
  639. package/dist/core/tools/model-fitness.js.map +1 -1
  640. package/dist/core/tools/orchestration-panel.d.ts +40 -0
  641. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  642. package/dist/core/tools/orchestration-panel.js +124 -0
  643. package/dist/core/tools/orchestration-panel.js.map +1 -0
  644. package/dist/core/tools/output-accumulator.d.ts +11 -0
  645. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  646. package/dist/core/tools/output-accumulator.js +36 -3
  647. package/dist/core/tools/output-accumulator.js.map +1 -1
  648. package/dist/core/tools/python.d.ts +2 -0
  649. package/dist/core/tools/python.d.ts.map +1 -1
  650. package/dist/core/tools/python.js +3 -1
  651. package/dist/core/tools/python.js.map +1 -1
  652. package/dist/core/tools/read.d.ts.map +1 -1
  653. package/dist/core/tools/read.js +1 -1
  654. package/dist/core/tools/read.js.map +1 -1
  655. package/dist/core/tools/run-process.d.ts +26 -0
  656. package/dist/core/tools/run-process.d.ts.map +1 -0
  657. package/dist/core/tools/run-process.js +138 -0
  658. package/dist/core/tools/run-process.js.map +1 -0
  659. package/dist/core/tools/search-command-guard.d.ts +14 -0
  660. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  661. package/dist/core/tools/search-command-guard.js +333 -0
  662. package/dist/core/tools/search-command-guard.js.map +1 -0
  663. package/dist/core/tools/secret-store.d.ts +38 -0
  664. package/dist/core/tools/secret-store.d.ts.map +1 -0
  665. package/dist/core/tools/secret-store.js +412 -0
  666. package/dist/core/tools/secret-store.js.map +1 -0
  667. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  668. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  669. package/dist/core/tools/shell-command-parser.js +113 -0
  670. package/dist/core/tools/shell-command-parser.js.map +1 -0
  671. package/dist/core/tools/task-steps.d.ts +2 -0
  672. package/dist/core/tools/task-steps.d.ts.map +1 -1
  673. package/dist/core/tools/task-steps.js +99 -0
  674. package/dist/core/tools/task-steps.js.map +1 -1
  675. package/dist/core/tools/tmux-dispatch.d.ts +3 -5
  676. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  677. package/dist/core/tools/tmux-dispatch.js +4 -4
  678. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  679. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  680. package/dist/core/tools/windows-shell-engine.js +4 -6
  681. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  682. package/dist/core/util/atomic-file.d.ts +6 -2
  683. package/dist/core/util/atomic-file.d.ts.map +1 -1
  684. package/dist/core/util/atomic-file.js +4 -4
  685. package/dist/core/util/atomic-file.js.map +1 -1
  686. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  687. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  688. package/dist/core/util/bounded-jsonl.js +75 -0
  689. package/dist/core/util/bounded-jsonl.js.map +1 -0
  690. package/dist/core/util/value-guards.d.ts +5 -0
  691. package/dist/core/util/value-guards.d.ts.map +1 -0
  692. package/dist/core/util/value-guards.js +12 -0
  693. package/dist/core/util/value-guards.js.map +1 -0
  694. package/dist/core/worktree-sync/store.d.ts +3 -3
  695. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  696. package/dist/core/worktree-sync/store.js +10 -5
  697. package/dist/core/worktree-sync/store.js.map +1 -1
  698. package/dist/index.d.ts +15 -4
  699. package/dist/index.d.ts.map +1 -1
  700. package/dist/index.js +14 -3
  701. package/dist/index.js.map +1 -1
  702. package/dist/main.d.ts.map +1 -1
  703. package/dist/main.js +149 -51
  704. package/dist/main.js.map +1 -1
  705. package/dist/migrations.d.ts +4 -6
  706. package/dist/migrations.d.ts.map +1 -1
  707. package/dist/migrations.js +186 -28
  708. package/dist/migrations.js.map +1 -1
  709. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  710. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  711. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  712. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  713. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  714. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  715. package/dist/modes/interactive/clipboard-input.js +44 -6
  716. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  717. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  718. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  719. package/dist/modes/interactive/components/activity-lane.js +304 -0
  720. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  721. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  722. package/dist/modes/interactive/components/assistant-message.js +19 -10
  723. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  724. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  725. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  726. package/dist/modes/interactive/components/expandable-text.js +17 -0
  727. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  728. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  729. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  730. package/dist/modes/interactive/components/extension-editor.js +30 -21
  731. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  732. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  733. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  734. package/dist/modes/interactive/components/extension-input.js +6 -1
  735. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  736. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  737. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  738. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  739. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  740. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  741. package/dist/modes/interactive/components/settings-selector.js +6 -6
  742. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  743. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  744. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  745. package/dist/modes/interactive/components/tool-execution.js +53 -20
  746. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  747. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  748. package/dist/modes/interactive/components/tool-group.js +3 -0
  749. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  750. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  751. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  752. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  753. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  754. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  755. package/dist/modes/interactive/config-backup.js +5 -4
  756. package/dist/modes/interactive/config-backup.js.map +1 -1
  757. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  758. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  759. package/dist/modes/interactive/extension-ui-host.js +77 -15
  760. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  761. package/dist/modes/interactive/external-editor.d.ts +15 -0
  762. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  763. package/dist/modes/interactive/external-editor.js +27 -19
  764. package/dist/modes/interactive/external-editor.js.map +1 -1
  765. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  766. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  767. package/dist/modes/interactive/history-reload-math.js +10 -5
  768. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  769. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  770. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  771. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  772. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  773. package/dist/modes/interactive/interactive-mode.d.ts +22 -24
  774. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  775. package/dist/modes/interactive/interactive-mode.js +245 -595
  776. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  777. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  778. package/dist/modes/interactive/key-handlers.js +1 -1
  779. package/dist/modes/interactive/key-handlers.js.map +1 -1
  780. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  781. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  782. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  783. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  784. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  785. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  786. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  787. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  788. package/dist/modes/interactive/report-commands.js +21 -0
  789. package/dist/modes/interactive/report-commands.js.map +1 -1
  790. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  791. package/dist/modes/interactive/resource-display.js +8 -2
  792. package/dist/modes/interactive/resource-display.js.map +1 -1
  793. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  794. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  795. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  796. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  797. package/dist/modes/interactive/session-flow-commands.d.ts +27 -8
  798. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  799. package/dist/modes/interactive/session-flow-commands.js +150 -64
  800. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  801. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  802. package/dist/modes/interactive/session-io-commands.js +16 -6
  803. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  804. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  805. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  806. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  807. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  808. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  809. package/dist/modes/interactive/startup-checks.js +1 -1
  810. package/dist/modes/interactive/startup-checks.js.map +1 -1
  811. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  812. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  813. package/dist/modes/interactive/usage-commands.js +225 -0
  814. package/dist/modes/interactive/usage-commands.js.map +1 -0
  815. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  816. package/dist/modes/rpc/rpc-mode.js +82 -23
  817. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  818. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  819. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  820. package/dist/modes/rpc/rpc-types.js +138 -1
  821. package/dist/modes/rpc/rpc-types.js.map +1 -1
  822. package/dist/utils/clipboard-image.d.ts.map +1 -1
  823. package/dist/utils/clipboard-image.js +2 -13
  824. package/dist/utils/clipboard-image.js.map +1 -1
  825. package/dist/utils/clipboard-native.d.ts +1 -0
  826. package/dist/utils/clipboard-native.d.ts.map +1 -1
  827. package/dist/utils/clipboard-native.js.map +1 -1
  828. package/dist/utils/clipboard.d.ts +1 -0
  829. package/dist/utils/clipboard.d.ts.map +1 -1
  830. package/dist/utils/clipboard.js +52 -1
  831. package/dist/utils/clipboard.js.map +1 -1
  832. package/dist/utils/platform.d.ts +3 -0
  833. package/dist/utils/platform.d.ts.map +1 -0
  834. package/dist/utils/platform.js +8 -0
  835. package/dist/utils/platform.js.map +1 -0
  836. package/dist/utils/shell.d.ts.map +1 -1
  837. package/dist/utils/shell.js +5 -3
  838. package/dist/utils/shell.js.map +1 -1
  839. package/dist/utils/version-check.d.ts.map +1 -1
  840. package/dist/utils/version-check.js +3 -1
  841. package/dist/utils/version-check.js.map +1 -1
  842. package/dist/utils/work-directory.d.ts +11 -0
  843. package/dist/utils/work-directory.d.ts.map +1 -1
  844. package/dist/utils/work-directory.js +30 -9
  845. package/dist/utils/work-directory.js.map +1 -1
  846. package/docs/UI_POLISH_ORCHESTRATION.md +38 -0
  847. package/docs/UI_QUALITY_ORCHESTRATION.md +28 -0
  848. package/docs/docs.json +4 -0
  849. package/docs/extensions.md +62 -2
  850. package/docs/harness-architecture.md +156 -0
  851. package/docs/keybindings.md +11 -1
  852. package/docs/process-matrix.md +59 -26
  853. package/docs/providers.md +9 -1
  854. package/docs/rpc.md +45 -2
  855. package/docs/sessions.md +15 -0
  856. package/docs/settings.md +125 -11
  857. package/docs/task-steps.md +8 -0
  858. package/docs/telemetry.md +19 -0
  859. package/docs/tmux-agent-manager.md +10 -3
  860. package/docs/ui-reference/README.md +9 -0
  861. package/docs/ui-reference/orchestration-after.txt +14 -0
  862. package/docs/ui-reference/orchestration-before.txt +13 -0
  863. package/docs/ui-reference/orchestration-reference.txt +16 -0
  864. package/docs/usage.md +22 -2
  865. package/docs/work-directory.md +19 -8
  866. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  867. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  868. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  869. package/examples/extensions/question.ts +34 -245
  870. package/examples/extensions/questionnaire.ts +41 -407
  871. package/examples/extensions/sandbox/package-lock.json +2 -2
  872. package/examples/extensions/sandbox/package.json +1 -1
  873. package/examples/extensions/with-deps/package-lock.json +2 -2
  874. package/examples/extensions/with-deps/package.json +1 -1
  875. package/npm-shrinkwrap.json +13 -13
  876. package/package.json +4 -4
  877. package/dist/core/delegation/session-worker-result.d.ts +0 -46
  878. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  879. package/dist/core/delegation/session-worker-result.js +0 -113
  880. package/dist/core/delegation/session-worker-result.js.map +0 -1
  881. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  882. package/dist/core/delegation/worker-result.js.map +0 -1
  883. package/dist/core/telemetry.d.ts.map +0 -1
  884. package/dist/core/telemetry.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAsLnE,4GAA4G;AAC5G,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBrE;AA+XD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACxC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,iBAme/D","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport { createInterface } from \"node:readline\";\nimport { assertValidSessionId, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport { type ImageContent, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport { ProcessTerminal, setKeybindings, TUI } from \"@caupulican/pi-tui\";\nimport chalk from \"chalk\";\nimport { type Args, type Mode, parseArgs, printHelp } from \"./cli/args.ts\";\nimport { processFileArguments } from \"./cli/file-processor.ts\";\nimport { buildInitialMessage } from \"./cli/initial-message.ts\";\nimport { listModels } from \"./cli/list-models.ts\";\nimport { selectSession } from \"./cli/session-picker.ts\";\nimport { ENV_SESSION_DIR, expandTildePath, getAgentDir, getPackageDir, VERSION } from \"./config.ts\";\nimport { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from \"./core/agent-session-runtime.ts\";\nimport {\n\ttype AgentSessionRuntimeDiagnostic,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./core/agent-session-services.ts\";\nimport { formatNoModelsAvailableMessage } from \"./core/auth-guidance.ts\";\nimport { AuthStorage } from \"./core/auth-storage.ts\";\nimport { formatDoctorReport, runDoctor, runUpdatePreflight } from \"./core/doctor.ts\";\nimport { exportFromFile } from \"./core/export-html/index.ts\";\nimport type { ExtensionFactory } from \"./core/extensions/types.ts\";\nimport { configureHttpDispatcher } from \"./core/http-dispatcher.ts\";\nimport { KeybindingsManager } from \"./core/keybindings.ts\";\nimport { formatLaneWorkerRefusal } from \"./core/model-capability.ts\";\nimport type { ModelRegistry } from \"./core/model-registry.ts\";\nimport {\n\tresolveCliModel,\n\tresolveCliProviderDefault,\n\tresolveModelScope,\n\tresolveProfileModelSettings,\n\ttype ScopedModel,\n} from \"./core/model-resolver.ts\";\nimport { collectModelRouterConfigDiagnostics } from \"./core/model-router/config-diagnostics.ts\";\nimport { restoreStdout, takeOverStdout } from \"./core/output-guard.ts\";\nimport { PI_PARENT_PID_ENV, PI_PARENT_SESSION_ENV, startProcessMatrixRuntime } from \"./core/process-matrix/runtime.ts\";\nimport { isReloadSessionProcessAlive } from \"./core/reload-blockers.ts\";\nimport { parseResourceProfileInput } from \"./core/resource-profile-blocks.ts\";\nimport type { CreateAgentSessionOptions } from \"./core/sdk.ts\";\nimport {\n\tformatMissingSessionCwdPrompt,\n\tgetMissingSessionCwdIssue,\n\tMissingSessionCwdError,\n\ttype SessionCwdIssue,\n} from \"./core/session-cwd.ts\";\nimport {\n\tcontinueRecentSession,\n\tcreateSession,\n\tforkSession,\n\tlistAllSessions,\n\tlistSessions,\n\topenSession,\n} from \"./core/session-manager-factory.ts\";\nimport { SettingsManager } from \"./core/settings-manager.ts\";\nimport { printTimings, resetTimings, time } from \"./core/timings.ts\";\nimport { hasProjectTrustInputs, ProjectTrustStore } from \"./core/trust-manager.ts\";\nimport {\n\tgetBoundWorktreeLaneKey,\n\tPI_WORKTREE_LANE_ENV,\n\tstartWorktreeSyncRuntime,\n} from \"./core/worktree-sync/runtime.ts\";\nimport { runMigrations, showDeprecationWarnings } from \"./migrations.ts\";\n\nimport { handleConfigCommand, handlePackageCommand } from \"./package-manager-cli.ts\";\nimport { isLocalPath, normalizePath, resolvePath } from \"./utils/paths.ts\";\nimport { cleanupWindowsSelfUpdateQuarantine } from \"./utils/windows-self-update.ts\";\nimport { getProcessWorkRun, getWorkRoot, PI_WORK_ROOT_ENV } from \"./utils/work-directory.ts\";\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY (interactive terminal).\n */\nasync function readPipedStdin(): Promise<string | undefined> {\n\t// If stdin is a TTY, we're running interactively - don't read stdin\n\tif (process.stdin.isTTY) {\n\t\treturn undefined;\n\t}\n\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => {\n\t\t\tresolve(data.trim() || undefined);\n\t\t});\n\t\tprocess.stdin.resume();\n\t});\n}\n\nfunction collectSettingsDiagnostics(\n\tsettingsManager: SettingsManager,\n\tcontext: string,\n): AgentSessionRuntimeDiagnostic[] {\n\treturn settingsManager.drainErrors().map(({ scope, error }) => ({\n\t\ttype: \"warning\",\n\t\tmessage: `(${context}, ${scope} settings) ${error.message}`,\n\t}));\n}\n\nfunction reportDiagnostics(diagnostics: readonly AgentSessionRuntimeDiagnostic[]): void {\n\tfor (const diagnostic of diagnostics) {\n\t\tconst color = diagnostic.type === \"error\" ? chalk.red : diagnostic.type === \"warning\" ? chalk.yellow : chalk.dim;\n\t\tconst prefix = diagnostic.type === \"error\" ? \"Error: \" : diagnostic.type === \"warning\" ? \"Warning: \" : \"\";\n\t\tconsole.error(color(`${prefix}${diagnostic.message}`));\n\t}\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ntype AppMode = \"interactive\" | \"print\" | \"json\" | \"rpc\";\n\nfunction resolveAppMode(parsed: Args, stdinIsTTY: boolean): AppMode {\n\tif (parsed.mode === \"rpc\") {\n\t\treturn \"rpc\";\n\t}\n\tif (parsed.mode === \"json\") {\n\t\treturn \"json\";\n\t}\n\tif (parsed.print || !stdinIsTTY) {\n\t\treturn \"print\";\n\t}\n\treturn \"interactive\";\n}\n\nfunction toPrintOutputMode(appMode: AppMode): Exclude<Mode, \"rpc\"> {\n\treturn appMode === \"json\" ? \"json\" : \"text\";\n}\n\nasync function prepareInitialMessage(\n\tparsed: Args,\n\tautoResizeImages: boolean,\n\tstdinContent?: string,\n): Promise<{\n\tinitialMessage?: string;\n\tinitialImages?: ImageContent[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn buildInitialMessage({ parsed, stdinContent });\n\t}\n\n\tconst { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages });\n\treturn buildInitialMessage({\n\t\tparsed,\n\t\tfileText: text,\n\t\tfileImages: images,\n\t\tstdinContent,\n\t});\n}\n\n/** Result from resolving a session argument */\ntype ResolvedSession =\n\t| { type: \"path\"; path: string } // Direct file path\n\t| { type: \"local\"; path: string } // Found in current project\n\t| { type: \"global\"; path: string; cwd: string } // Found in different project\n\t| { type: \"not_found\"; arg: string }; // Not found anywhere\n\n/**\n * Resolve a session argument to a file path.\n * If it looks like a path, use as-is. Otherwise try to match as session ID prefix.\n */\nasync function findLocalSessionByExactId(\n\tsessionId: string,\n\tcwd: string,\n\tsessionDir?: string,\n): Promise<{ type: \"local\"; path: string } | undefined> {\n\tconst localSessions = await listSessions(cwd, sessionDir);\n\tconst localMatch = localSessions.find((s) => s.id === sessionId);\n\treturn localMatch ? { type: \"local\", path: localMatch.path } : undefined;\n}\n\nasync function resolveSessionPath(sessionArg: string, cwd: string, sessionDir?: string): Promise<ResolvedSession> {\n\t// If it looks like a file path, resolve it before handing it to the session manager.\n\tif (sessionArg.includes(\"/\") || sessionArg.includes(\"\\\\\") || sessionArg.endsWith(\".jsonl\")) {\n\t\treturn { type: \"path\", path: resolvePath(sessionArg, cwd) };\n\t}\n\n\t// Try to match as session ID in current project first\n\tconst localSessions = await listSessions(cwd, sessionDir);\n\tconst localMatch =\n\t\tlocalSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (localMatch) {\n\t\treturn { type: \"local\", path: localMatch.path };\n\t}\n\n\t// Try global search across all projects\n\tconst allSessions = await listAllSessions(sessionDir);\n\tconst globalMatch =\n\t\tallSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (globalMatch) {\n\t\treturn { type: \"global\", path: globalMatch.path, cwd: globalMatch.cwd };\n\t}\n\n\t// Not found anywhere\n\treturn { type: \"not_found\", arg: sessionArg };\n}\n\n/** Prompt user for yes/no confirmation. Non-interactive callers fail closed instead of waiting on stdin. */\nexport async function promptConfirm(message: string): Promise<boolean> {\n\tif (!process.stdin.isTTY || !process.stdout.isTTY) return false;\n\treturn new Promise((resolve) => {\n\t\tconst rl = createInterface({\n\t\t\tinput: process.stdin,\n\t\t\toutput: process.stdout,\n\t\t});\n\t\tlet settled = false;\n\t\tconst finish = (confirmed: boolean) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\trl.removeListener(\"close\", onClose);\n\t\t\trl.close();\n\t\t\tresolve(confirmed);\n\t\t};\n\t\tconst onClose = () => finish(false);\n\t\trl.once(\"close\", onClose);\n\t\trl.question(`${message} [y/N] `, (answer) => {\n\t\t\tconst normalized = answer.trim().toLowerCase();\n\t\t\tfinish(normalized === \"y\" || normalized === \"yes\");\n\t\t});\n\t});\n}\n\nfunction validateForkFlags(parsed: Args): void {\n\tif (!parsed.fork) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t\tparsed.noSession ? \"--no-session\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --fork cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction validateSessionIdFlags(parsed: Args): void {\n\tif (parsed.sessionId === undefined) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t\tparsed.noSession ? \"--no-session\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n\n\ttry {\n\t\tassertValidSessionId(parsed.sessionId);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction forkSessionOrExit(sourcePath: string, cwd: string, sessionDir?: string, sessionId?: string): SessionManager {\n\ttry {\n\t\treturn forkSession(sourcePath, cwd, sessionDir, { id: sessionId });\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nasync function createSessionManager(\n\tparsed: Args,\n\tcwd: string,\n\tsessionDir: string | undefined,\n\tsettingsManager: SettingsManager,\n): Promise<SessionManager> {\n\tif (parsed.noSession || parsed.help || parsed.listModels !== undefined) {\n\t\treturn SessionManager.inMemory(cwd);\n\t}\n\n\tif (parsed.fork) {\n\t\tif (parsed.sessionId) {\n\t\t\tconst existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\t\tif (existingTarget) {\n\t\t\t\tconsole.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\tcase \"global\":\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.session) {\n\t\tconst resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\t\treturn openSession(resolved.path, sessionDir);\n\n\t\t\tcase \"global\": {\n\t\t\t\tconsole.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));\n\t\t\t\tconst shouldFork = await promptConfirm(\"Fork this session into current directory?\");\n\t\t\t\tif (!shouldFork) {\n\t\t\t\t\tconsole.log(chalk.dim(\"Aborted.\"));\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir);\n\t\t\t}\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.resume) {\n\t\tconst { initTheme, stopThemeWatcher } = await import(\"./modes/interactive/theme/theme.ts\");\n\t\tinitTheme(settingsManager.getTheme(), true);\n\t\ttry {\n\t\t\tconst selectedPath = await selectSession(\n\t\t\t\t(onProgress) => listSessions(cwd, sessionDir, onProgress),\n\t\t\t\t(onProgress) => listAllSessions(sessionDir, onProgress),\n\t\t\t);\n\t\t\tif (!selectedPath) {\n\t\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\treturn openSession(selectedPath, sessionDir);\n\t\t} finally {\n\t\t\tstopThemeWatcher();\n\t\t}\n\t}\n\n\tif (parsed.continue) {\n\t\treturn continueRecentSession(cwd, sessionDir);\n\t}\n\n\tif (parsed.sessionId) {\n\t\tconst existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\tif (existingSession) {\n\t\t\treturn openSession(existingSession.path, sessionDir);\n\t\t}\n\t}\n\n\treturn createSession(cwd, sessionDir, { id: parsed.sessionId });\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\thasExistingSession: boolean,\n\tmodelRegistry: ModelRegistry,\n\tsettingsManager: SettingsManager,\n\tcwd: string,\n): {\n\toptions: CreateAgentSessionOptions;\n\tcliThinkingFromModel: boolean;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n} {\n\tconst options: CreateAgentSessionOptions = {};\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tlet cliThinkingFromModel = false;\n\n\t// Model from CLI\n\t// - supports --provider <name> --model <pattern>\n\t// - supports --provider <name> to select that provider's default model\n\t// - supports --model <provider>/<pattern>\n\tif (parsed.model || parsed.provider) {\n\t\tconst resolved = parsed.model\n\t\t\t? resolveCliModel({\n\t\t\t\t\tcliProvider: parsed.provider,\n\t\t\t\t\tcliModel: parsed.model,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t})\n\t\t\t: resolveCliProviderDefault({\n\t\t\t\t\tcliProvider: parsed.provider,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t});\n\t\tif (resolved.warning) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: resolved.warning });\n\t\t}\n\t\tif (resolved.error) {\n\t\t\tdiagnostics.push({ type: \"error\", message: resolved.error });\n\t\t}\n\t\tif (resolved.model) {\n\t\t\toptions.model = resolved.model;\n\t\t\t// Allow \"--model <pattern>:<thinking>\" as a shorthand.\n\t\t\t// Explicit --thinking still takes precedence (applied later).\n\t\t\tif (parsed.model && !parsed.thinking && resolved.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = resolved.thinkingLevel;\n\t\t\t\tcliThinkingFromModel = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Record whether model/thinking came from an explicit CLI flag (before the profile fills them\n\t// in below), so AgentSession can re-apply profile model/thinking on reload without clobbering\n\t// an explicit --model/--thinking.\n\toptions.isExplicitModel = !!parsed.model;\n\toptions.isExplicitThinking = !!parsed.thinking || cliThinkingFromModel;\n\n\t// Model/Thinking from active profiles if not explicitly set via CLI flags\n\tconst activeProfileNames = settingsManager.getActiveResourceProfileNames();\n\tif (activeProfileNames.length > 0) {\n\t\tconst profileSettings = resolveProfileModelSettings({\n\t\t\tactiveProfileNames,\n\t\t\tregistry: settingsManager.getProfileRegistry(),\n\t\t\tmodelRegistry,\n\t\t\tcwd,\n\t\t});\n\t\tif (profileSettings.warning) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: profileSettings.warning });\n\t\t}\n\t\tif (profileSettings.error) {\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"warning\",\n\t\t\t\tmessage: `Active profile model resolution error: ${profileSettings.error}`,\n\t\t\t});\n\t\t}\n\t\tif (!options.model && profileSettings.model) {\n\t\t\toptions.model = profileSettings.model;\n\t\t}\n\t\tif (!parsed.thinking && profileSettings.thinkingLevel) {\n\t\t\toptions.thinkingLevel = profileSettings.thinkingLevel;\n\t\t}\n\t}\n\n\tif (!options.model && scopedModels.length > 0 && !hasExistingSession) {\n\t\t// Check if saved default is in scoped models - use it if so, otherwise first scoped model\n\t\tconst savedProvider = settingsManager.getDefaultProvider();\n\t\tconst savedModelId = settingsManager.getDefaultModel();\n\t\tconst savedModel = savedProvider && savedModelId ? modelRegistry.find(savedProvider, savedModelId) : undefined;\n\t\tconst savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : undefined;\n\n\t\tif (savedInScope) {\n\t\t\toptions.model = savedInScope.model;\n\t\t\t// Use thinking level from scoped model config if explicitly set\n\t\t\tif (!parsed.thinking && savedInScope.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = savedInScope.thinkingLevel;\n\t\t\t}\n\t\t} else {\n\t\t\toptions.model = scopedModels[0].model;\n\t\t\t// Use thinking level from first scoped model if explicitly set\n\t\t\tif (!parsed.thinking && scopedModels[0].thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Thinking level from CLI (takes precedence over scoped model thinking levels set above)\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\t// Keep thinking level undefined when not explicitly set in the model pattern.\n\t// Undefined means \"inherit current session thinking level\" during cycling.\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels.map((sm) => ({\n\t\t\tmodel: sm.model,\n\t\t\tthinkingLevel: sm.thinkingLevel,\n\t\t}));\n\t}\n\n\t// API key from CLI - set in authStorage\n\t// (handled by caller before createAgentSession)\n\n\t// Tools\n\tif (parsed.noTools) {\n\t\toptions.noTools = \"all\";\n\t} else if (parsed.noBuiltinTools) {\n\t\toptions.noTools = \"builtin\";\n\t}\n\tif (parsed.tools) {\n\t\toptions.tools = [...parsed.tools];\n\t}\n\tif (parsed.excludeTools) {\n\t\toptions.excludeTools = [...parsed.excludeTools];\n\t}\n\n\treturn { options, cliThinkingFromModel, diagnostics };\n}\n\nfunction resolveCliPaths(cwd: string, paths: string[] | undefined): string[] | undefined {\n\treturn paths?.map((value) => (isLocalPath(value) ? resolvePath(value, cwd) : value));\n}\n\nasync function showStartupSelector<T>(\n\tsettingsManager: SettingsManager,\n\ttitle: string,\n\toptions: Array<{ label: string; value: T }>,\n): Promise<T | undefined> {\n\tconst [{ ExtensionSelectorComponent }, { initTheme }] = await Promise.all([\n\t\timport(\"./modes/interactive/components/extension-selector.ts\"),\n\t\timport(\"./modes/interactive/theme/theme.ts\"),\n\t]);\n\tinitTheme(settingsManager.getTheme());\n\tsetKeybindings(KeybindingsManager.create());\n\n\treturn new Promise((resolve) => {\n\t\tconst ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());\n\t\tui.setClearOnShrink(settingsManager.getClearOnShrink());\n\n\t\tlet settled = false;\n\t\tconst finish = (result: T | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tui.stop();\n\t\t\tresolve(result);\n\t\t};\n\n\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\ttitle,\n\t\t\toptions.map((option) => option.label),\n\t\t\t(option) => finish(options.find((entry) => entry.label === option)?.value),\n\t\t\t() => finish(undefined),\n\t\t\t{ tui: ui },\n\t\t);\n\t\tui.addChild(selector);\n\t\tui.setFocus(selector);\n\t\tui.start();\n\t});\n}\n\nasync function promptForMissingSessionCwd(\n\tissue: SessionCwdIssue,\n\tsettingsManager: SettingsManager,\n): Promise<string | undefined> {\n\treturn showStartupSelector(settingsManager, formatMissingSessionCwdPrompt(issue), [\n\t\t{ label: \"Continue\", value: issue.fallbackCwd },\n\t\t{ label: \"Cancel\", value: undefined },\n\t]);\n}\n\ninterface ProjectTrustPromptResult {\n\ttrusted: boolean;\n\tremember: boolean;\n}\n\nasync function promptForProjectTrust(\n\tcwd: string,\n\tsettingsManager: SettingsManager,\n): Promise<ProjectTrustPromptResult | undefined> {\n\treturn showStartupSelector(\n\t\tsettingsManager,\n\t\t`Trust project folder?\\n${cwd}\\n\\nThis allows pi to read project instructions (AGENTS.md/CLAUDE.md/GEMINI.md), load .pi settings and resources, install missing project packages, and execute project extensions.`,\n\t\t[\n\t\t\t{ label: \"Trust\", value: { trusted: true, remember: true } },\n\t\t\t{ label: \"Trust (this session only)\", value: { trusted: true, remember: false } },\n\t\t\t{ label: \"Do not trust\", value: { trusted: false, remember: true } },\n\t\t\t{ label: \"Do not trust (this session only)\", value: { trusted: false, remember: false } },\n\t\t],\n\t);\n}\n\nasync function resolveProjectTrusted(options: {\n\tcwd: string;\n\ttrustStore: ProjectTrustStore;\n\ttrustOverride?: boolean;\n\tappMode: AppMode;\n\tsettingsManagerForPrompt: SettingsManager;\n}): Promise<boolean> {\n\tif (options.trustOverride !== undefined) {\n\t\treturn options.trustOverride;\n\t}\n\tif (!hasProjectTrustInputs(options.cwd)) {\n\t\treturn true;\n\t}\n\n\tconst decision = options.trustStore.get(options.cwd);\n\tif (decision !== null) {\n\t\treturn decision;\n\t}\n\tif (options.appMode !== \"interactive\") {\n\t\treturn false;\n\t}\n\n\tconst selected = await promptForProjectTrust(options.cwd, options.settingsManagerForPrompt);\n\tif (selected !== undefined) {\n\t\tif (selected.remember) {\n\t\t\toptions.trustStore.set(options.cwd, selected.trusted);\n\t\t}\n\t\treturn selected.trusted;\n\t}\n\treturn false;\n}\n\nexport interface MainOptions {\n\textensionFactories?: ExtensionFactory[];\n}\n\nexport async function main(args: string[], options?: MainOptions) {\n\tresetTimings();\n\tconst workAgentDir = getAgentDir();\n\tprocess.env[PI_WORK_ROOT_ENV] = getWorkRoot(workAgentDir);\n\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\tprocess.env.PI_TUI_WORK_DIR = getProcessWorkRun(workAgentDir, \"debug\", \"tui\").path;\n\t}\n\tconst offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag(process.env.PI_OFFLINE);\n\tif (offlineMode) {\n\t\tprocess.env.PI_OFFLINE = \"1\";\n\t\tprocess.env.PI_SKIP_VERSION_CHECK = \"1\";\n\t}\n\n\tif (process.platform === \"win32\") {\n\t\tcleanupWindowsSelfUpdateQuarantine(getPackageDir());\n\t}\n\n\tif (args[0] === \"doctor\") {\n\t\t// Interactive command: show fff-node install progress rather than a\n\t\t// silent multi-second gap (runUpdatePreflight's background run stays\n\t\t// quiet -- see the `{ silent: true }` default on runDoctor).\n\t\tconst report = await runDoctor(undefined, { silent: false });\n\t\tconsole.log(formatDoctorReport(report));\n\t\tprocess.exitCode = report.checks.some((check) => !check.present) ? 1 : 0;\n\t\treturn;\n\t}\n\n\tif (await handlePackageCommand(args)) {\n\t\t// Verify + provision required tooling right after an update, instead of\n\t\t// leaving it to lazy first-use (see doctor.ts's module doc). Best-effort\n\t\t// and non-fatal: runUpdatePreflight() never throws, so a broken\n\t\t// environment check can't turn a successful update into a failed one.\n\t\tif (args[0] === \"update\" && process.exitCode !== 1) {\n\t\t\tawait runUpdatePreflight();\n\t\t}\n\t\treturn;\n\t}\n\n\tif (await handleConfigCommand(args)) {\n\t\treturn;\n\t}\n\n\tconst parsed = parseArgs(args);\n\tif (parsed.diagnostics.length > 0) {\n\t\tfor (const d of parsed.diagnostics) {\n\t\t\tconst color = d.type === \"error\" ? chalk.red : chalk.yellow;\n\t\t\tconsole.error(color(`${d.type === \"error\" ? \"Error\" : \"Warning\"}: ${d.message}`));\n\t\t}\n\t\tif (parsed.diagnostics.some((d) => d.type === \"error\")) {\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\ttime(\"parseArgs\");\n\t// --worktree-lane is sugar over the cross-process env contract: setting the env here (before\n\t// any session/tool construction) makes the flag and a launcher-provided env byte-identical\n\t// downstream (RuntimeBuilder's lane gate, the epoch watcher, child processes).\n\tif (parsed.worktreeLane) {\n\t\tprocess.env[PI_WORKTREE_LANE_ENV] = parsed.worktreeLane;\n\t}\n\t// --parent-pid/--parent-session are the same CLI-sugar-over-env pattern as --worktree-lane:\n\t// setting the env here (before any session/tool construction) makes the flag and a\n\t// launcher-provided env byte-identical downstream (the process-matrix runtime's worker branch).\n\tif (parsed.parentPid !== undefined) {\n\t\tprocess.env[PI_PARENT_PID_ENV] = String(parsed.parentPid);\n\t}\n\tif (parsed.parentSession) {\n\t\tprocess.env[PI_PARENT_SESSION_ENV] = parsed.parentSession;\n\t}\n\tlet appMode = resolveAppMode(parsed, process.stdin.isTTY);\n\tconst shouldTakeOverStdout = appMode !== \"interactive\";\n\tif (shouldTakeOverStdout) {\n\t\ttakeOverStdout();\n\t}\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.export) {\n\t\tlet result: string;\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tresult = await exportFromFile(parsed.export, outputPath);\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconsole.log(`Exported to: ${result}`);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tvalidateForkFlags(parsed);\n\tvalidateSessionIdFlags(parsed);\n\n\t// Run migrations (pass cwd for project-local migrations)\n\tconst { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());\n\ttime(\"runMigrations\");\n\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst trustStore = new ProjectTrustStore(agentDir);\n\tconst startupProjectTrusted =\n\t\tparsed.projectTrustOverride ?? (!hasProjectTrustInputs(cwd) || trustStore.get(cwd) === true);\n\tconst startupSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: startupProjectTrusted });\n\treportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n\n\t// Decide the final runtime cwd before creating cwd-bound runtime services.\n\t// --session and --resume may select a session from another project, so project-local\n\t// settings, resources, provider registrations, and models must be resolved only after\n\t// the target session cwd is known. The startup-cwd settings manager is used only for\n\t// sessionDir lookup during session selection.\n\tconst envSessionDir = process.env[ENV_SESSION_DIR];\n\tconst sessionDir =\n\t\t(parsed.sessionDir ? normalizePath(parsed.sessionDir) : undefined) ??\n\t\t(envSessionDir ? expandTildePath(envSessionDir) : undefined) ??\n\t\tstartupSettingsManager.getSessionDir();\n\tlet sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager);\n\tconst missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);\n\tif (missingSessionCwdIssue) {\n\t\tif (appMode === \"interactive\") {\n\t\t\tconst selectedCwd = await promptForMissingSessionCwd(missingSessionCwdIssue, startupSettingsManager);\n\t\t\tif (!selectedCwd) {\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\tsessionManager = openSession(missingSessionCwdIssue.sessionFile!, sessionDir, selectedCwd);\n\t\t} else {\n\t\t\tconsole.error(chalk.red(new MissingSessionCwdError(missingSessionCwdIssue).message));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (parsed.name !== undefined) {\n\t\tconst name = parsed.name.trim();\n\t\tif (!name) {\n\t\t\tconsole.error(chalk.red(\"Error: --name requires a non-empty value\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsessionManager.appendSessionInfo(name);\n\t}\n\ttime(\"createSessionManager\");\n\n\tconst trustPromptMode: AppMode = parsed.help || parsed.listModels !== undefined ? \"print\" : appMode;\n\tconst projectTrustedForSession = await resolveProjectTrusted({\n\t\tcwd: sessionManager.getCwd(),\n\t\ttrustStore,\n\t\ttrustOverride: parsed.projectTrustOverride,\n\t\tappMode: trustPromptMode,\n\t\tsettingsManagerForPrompt: startupSettingsManager,\n\t});\n\n\tconst resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);\n\tconst resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);\n\tconst resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);\n\tconst resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);\n\tconst authStorage = AuthStorage.create();\n\tconst createRuntime: CreateAgentSessionRuntimeFactory = async ({\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t}) => {\n\t\tconst projectTrusted =\n\t\t\tcwd === sessionManager.getCwd()\n\t\t\t\t? projectTrustedForSession\n\t\t\t\t: (parsed.projectTrustOverride ?? (!hasProjectTrustInputs(cwd) || trustStore.get(cwd) === true));\n\t\tconst runtimeSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });\n\t\tif (parsed.resourceProfileJson) {\n\t\t\tfor (const profileInput of parsed.resourceProfileJson) {\n\t\t\t\tconst { profiles, errors } = parseResourceProfileInput(profileInput);\n\t\t\t\tif (errors.length > 0) {\n\t\t\t\t\treportDiagnostics(\n\t\t\t\t\t\terrors.map((message) => ({\n\t\t\t\t\t\t\ttype: \"warning\" as const,\n\t\t\t\t\t\t\tmessage: `--resource-profile-json ignored entry: ${message}`,\n\t\t\t\t\t\t})),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\truntimeSettingsManager.addInlineResourceProfileDefinitions(profiles);\n\t\t\t}\n\t\t}\n\t\tif (parsed.resourceProfiles && parsed.resourceProfiles.length > 0) {\n\t\t\truntimeSettingsManager.setRuntimeResourceProfiles(parsed.resourceProfiles);\n\t\t}\n\t\tconst services = await createAgentSessionServices({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tauthStorage,\n\t\t\tsettingsManager: runtimeSettingsManager,\n\t\t\textensionFlagValues: parsed.unknownFlags,\n\t\t\tresourceLoaderOptions: {\n\t\t\t\tadditionalExtensionPaths: resolvedExtensionPaths,\n\t\t\t\tadditionalSkillPaths: resolvedSkillPaths,\n\t\t\t\tadditionalPromptTemplatePaths: resolvedPromptTemplatePaths,\n\t\t\t\tadditionalThemePaths: resolvedThemePaths,\n\t\t\t\tnoExtensions: parsed.noExtensions,\n\t\t\t\tnoSkills: parsed.noSkills,\n\t\t\t\tnoPromptTemplates: parsed.noPromptTemplates,\n\t\t\t\tnoThemes: parsed.noThemes,\n\t\t\t\tnoContextFiles: parsed.noContextFiles,\n\t\t\t\tsystemPrompt: parsed.systemPrompt,\n\t\t\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\t\t\textensionFactories: options?.extensionFactories,\n\t\t\t},\n\t\t});\n\t\tconst { settingsManager, modelRegistry, resourceLoader } = services;\n\t\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [\n\t\t\t...services.diagnostics,\n\t\t\t...collectSettingsDiagnostics(settingsManager, \"runtime creation\"),\n\t\t\t...resourceLoader.getExtensions().errors.map(({ path, error }) => ({\n\t\t\t\ttype: \"warning\" as const,\n\t\t\t\tmessage: `Failed to load extension \"${path}\": ${error}`,\n\t\t\t})),\n\t\t];\n\n\t\tdiagnostics.push(\n\t\t\t...collectModelRouterConfigDiagnostics(settingsManager.getModelRouterSettings(), modelRegistry, agentDir).map(\n\t\t\t\t(message) => ({\n\t\t\t\t\ttype: \"warning\" as const,\n\t\t\t\t\tmessage,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\n\t\tconst modelPatterns = parsed.models ?? settingsManager.getEnabledModels();\n\t\tconst scopedModels =\n\t\t\tmodelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];\n\t\tconst {\n\t\t\toptions: sessionOptions,\n\t\t\tcliThinkingFromModel,\n\t\t\tdiagnostics: sessionOptionDiagnostics,\n\t\t} = buildSessionOptions(\n\t\t\tparsed,\n\t\t\tscopedModels,\n\t\t\tsessionManager.buildSessionContext().messages.length > 0,\n\t\t\tmodelRegistry,\n\t\t\tsettingsManager,\n\t\t\tcwd,\n\t\t);\n\t\tdiagnostics.push(...sessionOptionDiagnostics);\n\n\t\tif (parsed.apiKey) {\n\t\t\tif (!sessionOptions.model) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: \"--api-key requires a model to be specified via --model, --provider/--model, or --models\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tauthStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n\t\t\t}\n\t\t}\n\n\t\tconst created = await createAgentSessionFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent,\n\t\t\tmodel: sessionOptions.model,\n\t\t\tthinkingLevel: sessionOptions.thinkingLevel,\n\t\t\tisExplicitModel: sessionOptions.isExplicitModel,\n\t\t\tisExplicitThinking: sessionOptions.isExplicitThinking,\n\t\t\tscopedModels: sessionOptions.scopedModels,\n\t\t\ttools: sessionOptions.tools,\n\t\t\texcludeTools: sessionOptions.excludeTools,\n\t\t\tnoTools: sessionOptions.noTools,\n\t\t\ttoolProfileFilter: settingsManager.getResourceProfileFilter(\"tools\"),\n\t\t\tcustomTools: sessionOptions.customTools,\n\t\t});\n\t\tconst cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;\n\t\tif (created.session.model && cliThinkingOverride) {\n\t\t\tcreated.session.setThinkingLevel(created.session.thinkingLevel);\n\t\t}\n\n\t\treturn {\n\t\t\t...created,\n\t\t\tservices,\n\t\t\tdiagnostics,\n\t\t};\n\t};\n\ttime(\"createRuntime\");\n\tconst runtime = await createAgentSessionRuntime(createRuntime, {\n\t\tcwd: sessionManager.getCwd(),\n\t\tagentDir,\n\t\tsessionManager,\n\t});\n\ttime(\"createAgentSessionRuntime\");\n\tconst { services, session, modelFallbackMessage } = runtime;\n\tconst { settingsManager, modelRegistry, resourceLoader } = services;\n\tconfigureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());\n\n\t// A lane-bound session refuses AUTHORITATIVELY at its own startup when its model cannot reliably\n\t// drive the lane-gate/recovery surface unattended (full capability class, a declared context\n\t// window, an advertised native tool-call path, no graded /toolprobe demotion -- see\n\t// model-capability.ts's evaluateLaneWorkerRefusal). This is the authoritative check regardless of\n\t// how the lane binding arrived (--worktree-lane, PI_WORKTREE_LANE, or a launcher-set env): the\n\t// goal->tmux dispatch's own pre-check (tools/tmux-dispatch.ts) is the parent's best-effort guess\n\t// only and can race a model swap between dispatch and child startup. No silent unbinding -- an\n\t// ineligible model exits before the lane gate or epoch watcher ever start.\n\tconst boundWorktreeLaneKey = getBoundWorktreeLaneKey();\n\tif (boundWorktreeLaneKey) {\n\t\tconst laneWorkerRefusal = session.getLaneWorkerRefusal();\n\t\tif (laneWorkerRefusal) {\n\t\t\tconsole.error(chalk.red(formatLaneWorkerRefusal(laneWorkerRefusal, boundWorktreeLaneKey)));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// A read-only command (--help, --list-models) prints and exits without ever reserving a\n\t// session (see the createSessionManager in-memory-session gate above) -- for the same reason,\n\t// it must not fire either of the runtimes below. Both are launched with `void` (fire-and-\n\t// forget) and race the imminent `process.exit()` a few lines down in the --help/--list-models\n\t// branches: their first write (worktree-sync's reconcile pass, process-matrix's master-entry\n\t// writeEntry -- core/process-matrix/runtime.ts's startMasterBranch) can still be in flight on\n\t// the libuv threadpool when process.exit() forcibly tears the process down, which on Windows\n\t// can leave the just-written file's handle held by the OS a beat longer than the process\n\t// itself survives -- long enough for an immediately-following rmSync of the temp agent dir\n\t// (see test/session-id-readonly.test.ts) to observe EPERM. A read-only command has no session\n\t// and nothing to supervise, so the correct fix is not starting either runtime for it at all.\n\tconst isReadOnlyCommand = parsed.help || parsed.listModels !== undefined;\n\n\t// Worktree-sync session runtime (no-op unless enabled): one startup reconcile pass, plus --\n\t// for a lane-bound session -- the epoch watcher that injects a deterministic staleness notice\n\t// the moment another lane lands (steer mid-turn, its own turn when idle). Fire-and-forget:\n\t// a broken repo state must never block session startup.\n\tif (!isReadOnlyCommand) {\n\t\tvoid startWorktreeSyncRuntime({\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tagentDir,\n\t\t\tsettingsManager,\n\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\tnotify: (text) => {\n\t\t\t\tvoid session.sendCustomMessage(\n\t\t\t\t\t{ customType: \"worktree-sync-notice\", content: text, display: true },\n\t\t\t\t\t{ triggerTurn: true, deliverAs: \"steer\" },\n\t\t\t\t);\n\t\t\t},\n\t\t\tonDiagnostic: (message) => {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: ${message}`));\n\t\t\t},\n\t\t});\n\t}\n\n\t// Process-matrix runtime (no-op unless enabled): durable master/worker supervision surviving\n\t// restarts -- a master asks before touching any orphaned worker it finds on resume; a worker\n\t// winds down gracefully (never silently) when its parent disappears. Fire-and-forget, same as\n\t// worktree-sync above: a broken store must never block session startup.\n\tif (!isReadOnlyCommand) {\n\t\tvoid startProcessMatrixRuntime({\n\t\t\tagentDir,\n\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\thasUI: appMode === \"interactive\",\n\t\t\tsettings: settingsManager.getProcessMatrixSettings(),\n\t\t\tisProcessAlive: isReloadSessionProcessAlive,\n\t\t\tpromptConfirm,\n\t\t\tnotify: (text) => {\n\t\t\t\tvoid session.sendCustomMessage(\n\t\t\t\t\t{ customType: \"process-matrix-notice\", content: text, display: true },\n\t\t\t\t\t{ triggerTurn: true, deliverAs: \"steer\" },\n\t\t\t\t);\n\t\t\t},\n\t\t\tonDiagnostic: (message) => {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: ${message}`));\n\t\t\t},\n\t\t\trequestExit: () => {\n\t\t\t\ttry {\n\t\t\t\t\tsession.dispose();\n\t\t\t\t} catch {\n\t\t\t\t\t// Best-effort: exit must proceed even if dispose() itself throws.\n\t\t\t\t}\n\t\t\t\tprocess.exit(0);\n\t\t\t},\n\t\t});\n\t}\n\n\tif (parsed.help) {\n\t\tconst extensionFlags = resourceLoader\n\t\t\t.getExtensions()\n\t\t\t.extensions.flatMap((extension) => Array.from(extension.flags.values()));\n\t\tprintHelp(extensionFlags);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRegistry, searchPattern);\n\t\tprocess.exit(0);\n\t}\n\n\t// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC\n\tlet stdinContent: string | undefined;\n\tif (appMode !== \"rpc\") {\n\t\tstdinContent = await readPipedStdin();\n\t\tif (stdinContent !== undefined && appMode === \"interactive\") {\n\t\t\tappMode = \"print\";\n\t\t}\n\t}\n\ttime(\"readPipedStdin\");\n\n\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\tparsed,\n\t\tsettingsManager.getImageAutoResize(),\n\t\tstdinContent,\n\t);\n\ttime(\"prepareInitialMessage\");\n\tconst { initTheme, stopThemeWatcher } = await import(\"./modes/interactive/theme/theme.ts\");\n\tinitTheme(settingsManager.getTheme(), appMode === \"interactive\");\n\ttime(\"initTheme\");\n\n\t// Show deprecation warnings in interactive mode\n\tif (appMode === \"interactive\" && deprecationWarnings.length > 0) {\n\t\tawait showDeprecationWarnings(deprecationWarnings);\n\t}\n\n\ttime(\"resolveModelScope\");\n\treportDiagnostics(runtime.diagnostics);\n\tif (runtime.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\tprocess.exit(1);\n\t}\n\ttime(\"createAgentSession\");\n\n\tif (appMode !== \"interactive\" && !session.model) {\n\t\tconsole.error(chalk.red(formatNoModelsAvailableMessage()));\n\t\tprocess.exit(1);\n\t}\n\n\tconst startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);\n\tif (startupBenchmark && appMode !== \"interactive\") {\n\t\tconsole.error(chalk.red(\"Error: PI_STARTUP_BENCHMARK only supports interactive mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tif (appMode === \"rpc\") {\n\t\tprintTimings();\n\t\tconst { runRpcMode } = await import(\"./modes/rpc/rpc-mode.ts\");\n\t\tawait runRpcMode(runtime);\n\t} else if (appMode === \"interactive\") {\n\t\tconst { InteractiveMode } = await import(\"./modes/interactive/interactive-mode.ts\");\n\t\tconst interactiveMode = new InteractiveMode(runtime, {\n\t\t\tmigratedProviders,\n\t\t\tmodelFallbackMessage,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tverbose: parsed.verbose,\n\t\t});\n\t\tif (startupBenchmark) {\n\t\t\tawait interactiveMode.init();\n\t\t\ttime(\"interactiveMode.init\");\n\t\t\tprintTimings();\n\t\t\tinteractiveMode.stop();\n\t\t\tstopThemeWatcher();\n\t\t\tif (process.stdout.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t\t}\n\t\t\tif (process.stderr.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stderr.once(\"drain\", resolve));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tprintTimings();\n\t\tawait interactiveMode.run();\n\t} else {\n\t\tprintTimings();\n\t\tconst { runPrintMode } = await import(\"./modes/print-mode.ts\");\n\t\tconst exitCode = await runPrintMode(runtime, {\n\t\t\tmode: toPrintOutputMode(appMode),\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tprintUsage: parsed.printUsage,\n\t\t});\n\t\tstopThemeWatcher();\n\t\trestoreStdout();\n\t\tif (exitCode !== 0) {\n\t\t\tprocess.exitCode = exitCode;\n\t\t}\n\t\treturn;\n\t}\n}\n"]}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAqNnE,4GAA4G;AAC5G,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBrE;AAwYD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACxC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,iBAiiB/D","sourcesContent":["/**\n * Main entry point for the coding agent CLI.\n *\n * This file handles CLI argument parsing and translates them into\n * createAgentSession() options. The SDK does the heavy lifting.\n */\n\nimport { createInterface } from \"node:readline\";\nimport { assertValidSessionId, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport { type ImageContent, modelsAreEqual } from \"@caupulican/pi-ai\";\nimport { ProcessTerminal, setKeybindings, TUI } from \"@caupulican/pi-tui\";\nimport chalk from \"chalk\";\nimport { type Args, type Mode, parseArgs, printHelp } from \"./cli/args.ts\";\nimport { processFileArguments } from \"./cli/file-processor.ts\";\nimport { buildInitialMessage } from \"./cli/initial-message.ts\";\nimport { listModels } from \"./cli/list-models.ts\";\nimport { selectSession } from \"./cli/session-picker.ts\";\nimport { ENV_SESSION_DIR, expandTildePath, getAgentDir, getPackageDir, VERSION } from \"./config.ts\";\nimport { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from \"./core/agent-session-runtime.ts\";\nimport {\n\ttype AgentSessionRuntimeDiagnostic,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./core/agent-session-services.ts\";\nimport { formatNoModelsAvailableMessage } from \"./core/auth-guidance.ts\";\nimport { AuthStorage } from \"./core/auth-storage.ts\";\nimport { formatDoctorReport, runDoctor, runUpdatePreflight } from \"./core/doctor.ts\";\nimport { exportFromFile } from \"./core/export-html/index.ts\";\nimport type { ExtensionFactory } from \"./core/extensions/types.ts\";\nimport { configureHttpDispatcher } from \"./core/http-dispatcher.ts\";\nimport { KeybindingsManager } from \"./core/keybindings.ts\";\nimport { formatLaneWorkerRefusal } from \"./core/model-capability.ts\";\nimport type { ModelRegistry } from \"./core/model-registry.ts\";\nimport {\n\tresolveCliModel,\n\tresolveCliProviderDefault,\n\tresolveModelScope,\n\tresolveProfileModelSettings,\n\ttype ScopedModel,\n} from \"./core/model-resolver.ts\";\nimport { collectModelRouterConfigDiagnostics } from \"./core/model-router/config-diagnostics.ts\";\nimport type { OrchestrationProfile } from \"./core/orchestration/contracts.ts\";\nimport { resolveConfiguredOrchestrationModel } from \"./core/orchestration/model-binding.ts\";\nimport { OrchestrationProfileStore } from \"./core/orchestration/profile-store.ts\";\nimport { restoreStdout, takeOverStdout } from \"./core/output-guard.ts\";\nimport type { ResumablePayload } from \"./core/process-matrix/codes.ts\";\nimport { launchResumablePiAgent } from \"./core/process-matrix/resume-launcher.ts\";\nimport {\n\tPI_PARENT_PID_ENV,\n\tPI_PARENT_SESSION_ENV,\n\tPI_TASK_REF_ENV,\n\ttype ResumeWorkerLaunchOutcome,\n} from \"./core/process-matrix/runtime.ts\";\nimport { isReloadSessionProcessAlive } from \"./core/reload-blockers.ts\";\nimport { parseResourceProfileInput } from \"./core/resource-profile-blocks.ts\";\nimport type { CreateAgentSessionOptions } from \"./core/sdk.ts\";\nimport {\n\tformatMissingSessionCwdPrompt,\n\tgetMissingSessionCwdIssue,\n\tMissingSessionCwdError,\n\ttype SessionCwdIssue,\n} from \"./core/session-cwd.ts\";\nimport {\n\tcontinueRecentSession,\n\tcreateSession,\n\tforkSession,\n\tlistAllSessions,\n\tlistSessions,\n\topenSession,\n} from \"./core/session-manager-factory.ts\";\nimport { getSessionRole, setTerminalSessionMode } from \"./core/session-role.ts\";\nimport { SessionSupervisionRuntime } from \"./core/session-supervision-runtime.ts\";\nimport { SettingsManager } from \"./core/settings-manager.ts\";\nimport { printTimings, resetTimings, time } from \"./core/timings.ts\";\nimport { hasProjectTrustInputs, ProjectTrustStore } from \"./core/trust-manager.ts\";\nimport { getBoundWorktreeLaneKey, PI_WORKTREE_LANE_ENV } from \"./core/worktree-sync/runtime.ts\";\nimport { runMigrations, showDeprecationWarnings } from \"./migrations.ts\";\n\nimport { handleConfigCommand, handlePackageCommand } from \"./package-manager-cli.ts\";\nimport { isLocalPath, normalizePath, resolvePath } from \"./utils/paths.ts\";\nimport { cleanupWindowsSelfUpdateQuarantine } from \"./utils/windows-self-update.ts\";\nimport { getProcessWorkRun, getWorkRoot, PI_WORK_ROOT_ENV } from \"./utils/work-directory.ts\";\n\nfunction getSelfLaunchTarget(): { executable: string; argsPrefix: string[] } | undefined {\n\tconst executableName = process.execPath.split(/[\\\\/]/).at(-1)?.toLowerCase();\n\tconst isScriptRuntime = [\"node\", \"node.exe\", \"bun\", \"bun.exe\"].includes(executableName ?? \"\");\n\tif (!isScriptRuntime) return { executable: process.execPath, argsPrefix: [] };\n\tconst cliPath = process.argv[1];\n\treturn cliPath && !cliPath.startsWith(\"-\") ? { executable: process.execPath, argsPrefix: [cliPath] } : undefined;\n}\n\nasync function launchResumableWorker(\n\tpayload: ResumablePayload,\n\tparentSessionId: string,\n): Promise<ResumeWorkerLaunchOutcome> {\n\tconst target = getSelfLaunchTarget();\n\tif (!target) return { started: false, reason: \"The current Pi executable cannot be resolved.\" };\n\treturn launchResumablePiAgent({\n\t\tpayload,\n\t\ttarget,\n\t\tparentPid: process.pid,\n\t\tparentSessionId,\n\t\tenvironment: process.env,\n\t});\n}\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY (interactive terminal).\n */\nasync function readPipedStdin(): Promise<string | undefined> {\n\t// If stdin is a TTY, we're running interactively - don't read stdin\n\tif (process.stdin.isTTY) {\n\t\treturn undefined;\n\t}\n\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => {\n\t\t\tresolve(data.trim() || undefined);\n\t\t});\n\t\tprocess.stdin.resume();\n\t});\n}\n\nfunction collectSettingsDiagnostics(\n\tsettingsManager: SettingsManager,\n\tcontext: string,\n): AgentSessionRuntimeDiagnostic[] {\n\treturn settingsManager.drainErrors().map(({ scope, error }) => ({\n\t\ttype: \"warning\",\n\t\tmessage: `(${context}, ${scope} settings) ${error.message}`,\n\t}));\n}\n\nfunction reportDiagnostics(diagnostics: readonly AgentSessionRuntimeDiagnostic[]): void {\n\tfor (const diagnostic of diagnostics) {\n\t\tconst color = diagnostic.type === \"error\" ? chalk.red : diagnostic.type === \"warning\" ? chalk.yellow : chalk.dim;\n\t\tconst prefix = diagnostic.type === \"error\" ? \"Error: \" : diagnostic.type === \"warning\" ? \"Warning: \" : \"\";\n\t\tconsole.error(color(`${prefix}${diagnostic.message}`));\n\t}\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ntype AppMode = \"interactive\" | \"print\" | \"json\" | \"rpc\";\n\nfunction resolveAppMode(parsed: Args, stdinIsTTY: boolean): AppMode {\n\tif (parsed.mode === \"rpc\") {\n\t\treturn \"rpc\";\n\t}\n\tif (parsed.mode === \"json\") {\n\t\treturn \"json\";\n\t}\n\tif (parsed.print || !stdinIsTTY) {\n\t\treturn \"print\";\n\t}\n\treturn \"interactive\";\n}\n\nfunction toPrintOutputMode(appMode: AppMode): Exclude<Mode, \"rpc\"> {\n\treturn appMode === \"json\" ? \"json\" : \"text\";\n}\n\nasync function prepareInitialMessage(\n\tparsed: Args,\n\tautoResizeImages: boolean,\n\tstdinContent?: string,\n): Promise<{\n\tinitialMessage?: string;\n\tinitialImages?: ImageContent[];\n}> {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn buildInitialMessage({ parsed, stdinContent });\n\t}\n\n\tconst { text, images } = await processFileArguments(parsed.fileArgs, { autoResizeImages });\n\treturn buildInitialMessage({\n\t\tparsed,\n\t\tfileText: text,\n\t\tfileImages: images,\n\t\tstdinContent,\n\t});\n}\n\n/** Result from resolving a session argument */\ntype ResolvedSession =\n\t| { type: \"path\"; path: string } // Direct file path\n\t| { type: \"local\"; path: string } // Found in current project\n\t| { type: \"global\"; path: string; cwd: string } // Found in different project\n\t| { type: \"not_found\"; arg: string }; // Not found anywhere\n\n/**\n * Resolve a session argument to a file path.\n * If it looks like a path, use as-is. Otherwise try to match as session ID prefix.\n */\nasync function findLocalSessionByExactId(\n\tsessionId: string,\n\tcwd: string,\n\tsessionDir?: string,\n): Promise<{ type: \"local\"; path: string } | undefined> {\n\tconst localSessions = await listSessions(cwd, sessionDir);\n\tconst localMatch = localSessions.find((s) => s.id === sessionId);\n\treturn localMatch ? { type: \"local\", path: localMatch.path } : undefined;\n}\n\nasync function resolveSessionPath(sessionArg: string, cwd: string, sessionDir?: string): Promise<ResolvedSession> {\n\t// If it looks like a file path, resolve it before handing it to the session manager.\n\tif (sessionArg.includes(\"/\") || sessionArg.includes(\"\\\\\") || sessionArg.endsWith(\".jsonl\")) {\n\t\treturn { type: \"path\", path: resolvePath(sessionArg, cwd) };\n\t}\n\n\t// Try to match as session ID in current project first\n\tconst localSessions = await listSessions(cwd, sessionDir);\n\tconst localMatch =\n\t\tlocalSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (localMatch) {\n\t\treturn { type: \"local\", path: localMatch.path };\n\t}\n\n\t// Try global search across all projects\n\tconst allSessions = await listAllSessions(sessionDir);\n\tconst globalMatch =\n\t\tallSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));\n\n\tif (globalMatch) {\n\t\treturn { type: \"global\", path: globalMatch.path, cwd: globalMatch.cwd };\n\t}\n\n\t// Not found anywhere\n\treturn { type: \"not_found\", arg: sessionArg };\n}\n\n/** Prompt user for yes/no confirmation. Non-interactive callers fail closed instead of waiting on stdin. */\nexport async function promptConfirm(message: string): Promise<boolean> {\n\tif (!process.stdin.isTTY || !process.stdout.isTTY) return false;\n\treturn new Promise((resolve) => {\n\t\tconst rl = createInterface({\n\t\t\tinput: process.stdin,\n\t\t\toutput: process.stdout,\n\t\t});\n\t\tlet settled = false;\n\t\tconst finish = (confirmed: boolean) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\trl.removeListener(\"close\", onClose);\n\t\t\trl.close();\n\t\t\tresolve(confirmed);\n\t\t};\n\t\tconst onClose = () => finish(false);\n\t\trl.once(\"close\", onClose);\n\t\trl.question(`${message} [y/N] `, (answer) => {\n\t\t\tconst normalized = answer.trim().toLowerCase();\n\t\t\tfinish(normalized === \"y\" || normalized === \"yes\");\n\t\t});\n\t});\n}\n\nfunction validateForkFlags(parsed: Args): void {\n\tif (!parsed.fork) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t\tparsed.noSession ? \"--no-session\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --fork cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction validateSessionIdFlags(parsed: Args): void {\n\tif (parsed.sessionId === undefined) return;\n\n\tconst conflictingFlags = [\n\t\tparsed.session ? \"--session\" : undefined,\n\t\tparsed.continue ? \"--continue\" : undefined,\n\t\tparsed.resume ? \"--resume\" : undefined,\n\t\tparsed.noSession ? \"--no-session\" : undefined,\n\t].filter((flag): flag is string => flag !== undefined);\n\n\tif (conflictingFlags.length > 0) {\n\t\tconsole.error(chalk.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(\", \")}`));\n\t\tprocess.exit(1);\n\t}\n\n\ttry {\n\t\tassertValidSessionId(parsed.sessionId);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nfunction forkSessionOrExit(sourcePath: string, cwd: string, sessionDir?: string, sessionId?: string): SessionManager {\n\ttry {\n\t\treturn forkSession(sourcePath, cwd, sessionDir, { id: sessionId });\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\tprocess.exit(1);\n\t}\n}\n\nasync function createSessionManager(\n\tparsed: Args,\n\tcwd: string,\n\tsessionDir: string | undefined,\n\tsettingsManager: SettingsManager,\n\thasHumanUI: boolean,\n): Promise<SessionManager> {\n\tif (parsed.noSession || parsed.help || parsed.listModels !== undefined) {\n\t\treturn SessionManager.inMemory(cwd);\n\t}\n\n\tif (parsed.fork) {\n\t\tif (parsed.sessionId) {\n\t\t\tconst existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\t\tif (existingTarget) {\n\t\t\t\tconsole.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\tcase \"global\":\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.session) {\n\t\tconst resolved = await resolveSessionPath(parsed.session, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\t\treturn openSession(resolved.path, sessionDir);\n\n\t\t\tcase \"global\": {\n\t\t\t\tif (!hasHumanUI) {\n\t\t\t\t\tconsole.error(chalk.red(\"Cannot open a cross-project session without a user approval UI.\"));\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\t\t\t\tconsole.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));\n\t\t\t\tconst shouldFork = await promptConfirm(\"Fork this session into current directory?\");\n\t\t\t\tif (!shouldFork) {\n\t\t\t\t\tconsole.log(chalk.dim(\"Aborted.\"));\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\treturn forkSessionOrExit(resolved.path, cwd, sessionDir);\n\t\t\t}\n\n\t\t\tcase \"not_found\":\n\t\t\t\tconsole.error(chalk.red(`No session found matching '${resolved.arg}'`));\n\t\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tif (parsed.resume) {\n\t\tif (!hasHumanUI) {\n\t\t\tconsole.error(chalk.red(\"Error: --resume requires --session-mode user; use --session <id> for workers.\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconst { initTheme, stopThemeWatcher } = await import(\"./modes/interactive/theme/theme.ts\");\n\t\tinitTheme(settingsManager.getTheme(), true);\n\t\ttry {\n\t\t\tconst selectedPath = await selectSession(\n\t\t\t\t(onProgress) => listSessions(cwd, sessionDir, onProgress),\n\t\t\t\t(onProgress) => listAllSessions(sessionDir, onProgress),\n\t\t\t);\n\t\t\tif (!selectedPath) {\n\t\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\treturn openSession(selectedPath, sessionDir);\n\t\t} finally {\n\t\t\tstopThemeWatcher();\n\t\t}\n\t}\n\n\tif (parsed.continue) {\n\t\treturn continueRecentSession(cwd, sessionDir);\n\t}\n\n\tif (parsed.sessionId) {\n\t\tconst existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);\n\t\tif (existingSession) {\n\t\t\treturn openSession(existingSession.path, sessionDir);\n\t\t}\n\t}\n\n\treturn createSession(cwd, sessionDir, { id: parsed.sessionId });\n}\n\nfunction buildSessionOptions(\n\tparsed: Args,\n\tscopedModels: ScopedModel[],\n\thasExistingSession: boolean,\n\tmodelRegistry: ModelRegistry,\n\tsettingsManager: SettingsManager,\n\tcwd: string,\n): {\n\toptions: CreateAgentSessionOptions;\n\tcliThinkingFromModel: boolean;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n} {\n\tconst options: CreateAgentSessionOptions = {};\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\tlet cliThinkingFromModel = false;\n\n\t// Model from CLI\n\t// - supports --provider <name> --model <pattern>\n\t// - supports --provider <name> to select that provider's default model\n\t// - supports --model <provider>/<pattern>\n\tif (parsed.model || parsed.provider) {\n\t\tconst resolved = parsed.model\n\t\t\t? resolveCliModel({\n\t\t\t\t\tcliProvider: parsed.provider,\n\t\t\t\t\tcliModel: parsed.model,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t})\n\t\t\t: resolveCliProviderDefault({\n\t\t\t\t\tcliProvider: parsed.provider,\n\t\t\t\t\tmodelRegistry,\n\t\t\t\t});\n\t\tif (resolved.warning) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: resolved.warning });\n\t\t}\n\t\tif (resolved.error) {\n\t\t\tdiagnostics.push({ type: \"error\", message: resolved.error });\n\t\t}\n\t\tif (resolved.model) {\n\t\t\toptions.model = resolved.model;\n\t\t\t// Allow \"--model <pattern>:<thinking>\" as a shorthand.\n\t\t\t// Explicit --thinking still takes precedence (applied later).\n\t\t\tif (parsed.model && !parsed.thinking && resolved.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = resolved.thinkingLevel;\n\t\t\t\tcliThinkingFromModel = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Record whether model/thinking came from an explicit CLI flag (before the profile fills them\n\t// in below), so AgentSession can re-apply profile model/thinking on reload without clobbering\n\t// an explicit --model/--thinking.\n\toptions.isExplicitModel = !!parsed.model;\n\toptions.isExplicitThinking = !!parsed.thinking || cliThinkingFromModel;\n\n\t// Model/Thinking from active profiles if not explicitly set via CLI flags\n\tconst activeProfileNames = settingsManager.getActiveResourceProfileNames();\n\tif (activeProfileNames.length > 0) {\n\t\tconst profileSettings = resolveProfileModelSettings({\n\t\t\tactiveProfileNames,\n\t\t\tregistry: settingsManager.getProfileRegistry(),\n\t\t\tmodelRegistry,\n\t\t\tcwd,\n\t\t});\n\t\tif (profileSettings.warning) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: profileSettings.warning });\n\t\t}\n\t\tif (profileSettings.error) {\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"warning\",\n\t\t\t\tmessage: `Active profile model resolution error: ${profileSettings.error}`,\n\t\t\t});\n\t\t}\n\t\tif (!options.model && profileSettings.model) {\n\t\t\toptions.model = profileSettings.model;\n\t\t}\n\t\tif (!parsed.thinking && profileSettings.thinkingLevel) {\n\t\t\toptions.thinkingLevel = profileSettings.thinkingLevel;\n\t\t}\n\t}\n\n\tif (!options.model && scopedModels.length > 0 && !hasExistingSession) {\n\t\t// Check if saved default is in scoped models - use it if so, otherwise first scoped model\n\t\tconst savedProvider = settingsManager.getDefaultProvider();\n\t\tconst savedModelId = settingsManager.getDefaultModel();\n\t\tconst savedModel = savedProvider && savedModelId ? modelRegistry.find(savedProvider, savedModelId) : undefined;\n\t\tconst savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : undefined;\n\n\t\tif (savedInScope) {\n\t\t\toptions.model = savedInScope.model;\n\t\t\t// Use thinking level from scoped model config if explicitly set\n\t\t\tif (!parsed.thinking && savedInScope.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = savedInScope.thinkingLevel;\n\t\t\t}\n\t\t} else {\n\t\t\toptions.model = scopedModels[0].model;\n\t\t\t// Use thinking level from first scoped model if explicitly set\n\t\t\tif (!parsed.thinking && scopedModels[0].thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = scopedModels[0].thinkingLevel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Thinking level from CLI (takes precedence over scoped model thinking levels set above)\n\tif (parsed.thinking) {\n\t\toptions.thinkingLevel = parsed.thinking;\n\t}\n\n\t// Scoped models for Ctrl+P cycling\n\t// Keep thinking level undefined when not explicitly set in the model pattern.\n\t// Undefined means \"inherit current session thinking level\" during cycling.\n\tif (scopedModels.length > 0) {\n\t\toptions.scopedModels = scopedModels.map((sm) => ({\n\t\t\tmodel: sm.model,\n\t\t\tthinkingLevel: sm.thinkingLevel,\n\t\t}));\n\t}\n\n\t// API key from CLI - set in authStorage\n\t// (handled by caller before createAgentSession)\n\n\t// Tools\n\tif (parsed.noTools) {\n\t\toptions.noTools = \"all\";\n\t} else if (parsed.noBuiltinTools) {\n\t\toptions.noTools = \"builtin\";\n\t}\n\tif (parsed.tools) {\n\t\toptions.tools = [...parsed.tools];\n\t}\n\tif (parsed.excludeTools) {\n\t\toptions.excludeTools = [...parsed.excludeTools];\n\t}\n\n\treturn { options, cliThinkingFromModel, diagnostics };\n}\n\nfunction resolveCliPaths(cwd: string, paths: string[] | undefined): string[] | undefined {\n\treturn paths?.map((value) => (isLocalPath(value) ? resolvePath(value, cwd) : value));\n}\n\nasync function showStartupSelector<T>(\n\tsettingsManager: SettingsManager,\n\ttitle: string,\n\toptions: Array<{ label: string; value: T }>,\n): Promise<T | undefined> {\n\tconst [{ ExtensionSelectorComponent }, { initTheme }] = await Promise.all([\n\t\timport(\"./modes/interactive/components/extension-selector.ts\"),\n\t\timport(\"./modes/interactive/theme/theme.ts\"),\n\t]);\n\tinitTheme(settingsManager.getTheme());\n\tsetKeybindings(KeybindingsManager.create());\n\n\treturn new Promise((resolve) => {\n\t\tconst ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());\n\t\tui.setClearOnShrink(settingsManager.getClearOnShrink());\n\n\t\tlet settled = false;\n\t\tconst finish = (result: T | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tui.stop();\n\t\t\tresolve(result);\n\t\t};\n\n\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\ttitle,\n\t\t\toptions.map((option) => option.label),\n\t\t\t(option) => finish(options.find((entry) => entry.label === option)?.value),\n\t\t\t() => finish(undefined),\n\t\t\t{ tui: ui },\n\t\t);\n\t\tui.addChild(selector);\n\t\tui.setFocus(selector);\n\t\tui.start();\n\t});\n}\n\nasync function promptForMissingSessionCwd(\n\tissue: SessionCwdIssue,\n\tsettingsManager: SettingsManager,\n): Promise<string | undefined> {\n\treturn showStartupSelector(settingsManager, formatMissingSessionCwdPrompt(issue), [\n\t\t{ label: \"Continue\", value: issue.fallbackCwd },\n\t\t{ label: \"Cancel\", value: undefined },\n\t]);\n}\n\ninterface ProjectTrustPromptResult {\n\ttrusted: boolean;\n\tremember: boolean;\n}\n\nasync function promptForProjectTrust(\n\tcwd: string,\n\tsettingsManager: SettingsManager,\n): Promise<ProjectTrustPromptResult | undefined> {\n\treturn showStartupSelector(\n\t\tsettingsManager,\n\t\t`Trust project folder?\\n${cwd}\\n\\nThis allows pi to read project instructions (AGENTS.md/CLAUDE.md/GEMINI.md), load .pi settings and resources, install missing project packages, and execute project extensions.`,\n\t\t[\n\t\t\t{ label: \"Trust\", value: { trusted: true, remember: true } },\n\t\t\t{ label: \"Trust (this session only)\", value: { trusted: true, remember: false } },\n\t\t\t{ label: \"Do not trust\", value: { trusted: false, remember: true } },\n\t\t\t{ label: \"Do not trust (this session only)\", value: { trusted: false, remember: false } },\n\t\t],\n\t);\n}\n\nasync function resolveProjectTrusted(options: {\n\tcwd: string;\n\ttrustStore: ProjectTrustStore;\n\ttrustOverride?: boolean;\n\tappMode: AppMode;\n\tsettingsManagerForPrompt: SettingsManager;\n}): Promise<boolean> {\n\tif (options.trustOverride !== undefined) {\n\t\treturn options.trustOverride;\n\t}\n\tif (!hasProjectTrustInputs(options.cwd)) {\n\t\treturn true;\n\t}\n\n\tconst decision = options.trustStore.get(options.cwd);\n\tif (decision !== null) {\n\t\treturn decision;\n\t}\n\tif (options.appMode !== \"interactive\") {\n\t\treturn false;\n\t}\n\n\tconst selected = await promptForProjectTrust(options.cwd, options.settingsManagerForPrompt);\n\tif (selected !== undefined) {\n\t\tif (selected.remember) {\n\t\t\toptions.trustStore.set(options.cwd, selected.trusted);\n\t\t}\n\t\treturn selected.trusted;\n\t}\n\treturn false;\n}\n\nexport interface MainOptions {\n\textensionFactories?: ExtensionFactory[];\n}\n\nexport async function main(args: string[], options?: MainOptions) {\n\tresetTimings();\n\tconst workAgentDir = getAgentDir();\n\tprocess.env[PI_WORK_ROOT_ENV] = getWorkRoot(workAgentDir);\n\tif (process.env.PI_TUI_DEBUG === \"1\") {\n\t\tprocess.env.PI_TUI_WORK_DIR = getProcessWorkRun(workAgentDir, \"debug\", \"tui\").path;\n\t}\n\tconst offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag(process.env.PI_OFFLINE);\n\tif (offlineMode) {\n\t\tprocess.env.PI_OFFLINE = \"1\";\n\t\tprocess.env.PI_SKIP_VERSION_CHECK = \"1\";\n\t}\n\n\tif (process.platform === \"win32\") {\n\t\tcleanupWindowsSelfUpdateQuarantine(getPackageDir());\n\t}\n\n\tif (args[0] === \"doctor\") {\n\t\t// Interactive command: show fff-node install progress rather than a\n\t\t// silent multi-second gap (runUpdatePreflight's background run stays\n\t\t// quiet -- see the `{ silent: true }` default on runDoctor).\n\t\tconst report = await runDoctor(undefined, { silent: false });\n\t\tconsole.log(formatDoctorReport(report));\n\t\tprocess.exitCode = report.checks.some((check) => !check.present) ? 1 : 0;\n\t\treturn;\n\t}\n\n\tif (await handlePackageCommand(args)) {\n\t\t// Verify + provision required tooling right after an update, instead of\n\t\t// leaving it to lazy first-use (see doctor.ts's module doc). Best-effort\n\t\t// and non-fatal: runUpdatePreflight() never throws, so a broken\n\t\t// environment check can't turn a successful update into a failed one.\n\t\tif (args[0] === \"update\" && process.exitCode !== 1) {\n\t\t\tawait runUpdatePreflight();\n\t\t}\n\t\treturn;\n\t}\n\n\tif (await handleConfigCommand(args)) {\n\t\treturn;\n\t}\n\n\tconst parsed = parseArgs(args);\n\tif (parsed.diagnostics.length > 0) {\n\t\tfor (const d of parsed.diagnostics) {\n\t\t\tconst color = d.type === \"error\" ? chalk.red : chalk.yellow;\n\t\t\tconsole.error(color(`${d.type === \"error\" ? \"Error\" : \"Warning\"}: ${d.message}`));\n\t\t}\n\t\tif (parsed.diagnostics.some((d) => d.type === \"error\")) {\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\ttime(\"parseArgs\");\n\t// --worktree-lane is sugar over the cross-process env contract: setting the env here (before\n\t// any session/tool construction) makes the flag and a launcher-provided env byte-identical\n\t// downstream (RuntimeBuilder's lane gate, the epoch watcher, child processes).\n\tif (parsed.worktreeLane) {\n\t\tprocess.env[PI_WORKTREE_LANE_ENV] = parsed.worktreeLane;\n\t}\n\t// --parent-pid/--parent-session are the same CLI-sugar-over-env pattern as --worktree-lane:\n\t// setting the env here (before any session/tool construction) makes the flag and a\n\t// launcher-provided env byte-identical downstream (the process-matrix runtime's worker branch).\n\tif (parsed.parentPid !== undefined) {\n\t\tprocess.env[PI_PARENT_PID_ENV] = String(parsed.parentPid);\n\t}\n\tif (parsed.parentSession) {\n\t\tprocess.env[PI_PARENT_SESSION_ENV] = parsed.parentSession;\n\t}\n\tif (parsed.taskRef) {\n\t\tprocess.env[PI_TASK_REF_ENV] = parsed.taskRef;\n\t}\n\tif (parsed.sessionMode) {\n\t\tsetTerminalSessionMode(parsed.sessionMode);\n\t}\n\tlet appMode = resolveAppMode(parsed, process.stdin.isTTY);\n\tlet hasHumanUI = appMode === \"interactive\" && getSessionRole() === \"main\";\n\tconst shouldTakeOverStdout = appMode !== \"interactive\";\n\tif (shouldTakeOverStdout) {\n\t\ttakeOverStdout();\n\t}\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.export) {\n\t\tlet result: string;\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tresult = await exportFromFile(parsed.export, outputPath);\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tconsole.log(`Exported to: ${result}`);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tvalidateForkFlags(parsed);\n\tvalidateSessionIdFlags(parsed);\n\n\t// Run migrations (pass cwd for project-local migrations)\n\tconst { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());\n\ttime(\"runMigrations\");\n\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst trustStore = new ProjectTrustStore(agentDir);\n\tconst startupProjectTrusted =\n\t\tparsed.projectTrustOverride ?? (!hasProjectTrustInputs(cwd) || trustStore.get(cwd) === true);\n\tconst startupSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: startupProjectTrusted });\n\treportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n\n\t// Decide the final runtime cwd before creating cwd-bound runtime services.\n\t// --session and --resume may select a session from another project, so project-local\n\t// settings, resources, provider registrations, and models must be resolved only after\n\t// the target session cwd is known. The startup-cwd settings manager is used only for\n\t// sessionDir lookup during session selection.\n\tconst envSessionDir = process.env[ENV_SESSION_DIR];\n\tconst sessionDir =\n\t\t(parsed.sessionDir ? normalizePath(parsed.sessionDir) : undefined) ??\n\t\t(envSessionDir ? expandTildePath(envSessionDir) : undefined) ??\n\t\tstartupSettingsManager.getSessionDir();\n\tlet sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager, hasHumanUI);\n\tconst missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);\n\tif (missingSessionCwdIssue) {\n\t\tif (hasHumanUI) {\n\t\t\tconst selectedCwd = await promptForMissingSessionCwd(missingSessionCwdIssue, startupSettingsManager);\n\t\t\tif (!selectedCwd) {\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t\tsessionManager = openSession(missingSessionCwdIssue.sessionFile!, sessionDir, selectedCwd);\n\t\t} else {\n\t\t\tconsole.error(chalk.red(new MissingSessionCwdError(missingSessionCwdIssue).message));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (parsed.name !== undefined) {\n\t\tconst name = parsed.name.trim();\n\t\tif (!name) {\n\t\t\tconsole.error(chalk.red(\"Error: --name requires a non-empty value\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tsessionManager.appendSessionInfo(name);\n\t}\n\ttime(\"createSessionManager\");\n\n\tconst trustPromptMode: AppMode = parsed.help || parsed.listModels !== undefined || !hasHumanUI ? \"print\" : appMode;\n\tconst projectTrustedForSession = await resolveProjectTrusted({\n\t\tcwd: sessionManager.getCwd(),\n\t\ttrustStore,\n\t\ttrustOverride: parsed.projectTrustOverride,\n\t\tappMode: trustPromptMode,\n\t\tsettingsManagerForPrompt: startupSettingsManager,\n\t});\n\n\tconst resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);\n\tconst resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);\n\tconst resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);\n\tconst resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);\n\tconst authStorage = AuthStorage.create();\n\tconst createRuntime: CreateAgentSessionRuntimeFactory = async ({\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t}) => {\n\t\tconst projectTrusted =\n\t\t\tcwd === sessionManager.getCwd()\n\t\t\t\t? projectTrustedForSession\n\t\t\t\t: (parsed.projectTrustOverride ?? (!hasProjectTrustInputs(cwd) || trustStore.get(cwd) === true));\n\t\tconst runtimeSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });\n\t\tconst orchestrationDiagnostics: AgentSessionRuntimeDiagnostic[] = [];\n\t\tconst orchestrationProfileId =\n\t\t\tparsed.orchestrationProfile?.trim() || runtimeSettingsManager.getActiveOrchestrationProfile();\n\t\tlet orchestrationProfile: OrchestrationProfile | undefined;\n\t\tif (orchestrationProfileId) {\n\t\t\tconst loaded = new OrchestrationProfileStore({ agentDir, cwd, projectTrusted }).load();\n\t\t\torchestrationDiagnostics.push(\n\t\t\t\t...loaded.diagnostics.map((diagnostic) => ({\n\t\t\t\t\ttype: \"warning\" as const,\n\t\t\t\t\tmessage: `Orchestration profile ignored (${diagnostic.path}): ${diagnostic.message}`,\n\t\t\t\t})),\n\t\t\t);\n\t\t\torchestrationProfile = loaded.registry.get(orchestrationProfileId);\n\t\t\tif (!orchestrationProfile) {\n\t\t\t\torchestrationDiagnostics.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: `Orchestration profile '${orchestrationProfileId}' was not found.`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\truntimeSettingsManager.setRuntimeResourceProfiles([...orchestrationProfile.resourceProfileNames]);\n\t\t\t\tconst conflictingFlags = [\n\t\t\t\t\t...(parsed.model || parsed.provider ? [\"--model/--provider\"] : []),\n\t\t\t\t\t...(parsed.models ? [\"--models\"] : []),\n\t\t\t\t\t...(parsed.thinking ? [\"--thinking\"] : []),\n\t\t\t\t\t...(parsed.tools || parsed.excludeTools || parsed.noTools || parsed.noBuiltinTools\n\t\t\t\t\t\t? [\"--tools/--exclude-tools/--no-tools\"]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t...(parsed.resourceProfiles ? [\"--resource-profile\"] : []),\n\t\t\t\t];\n\t\t\t\tif (conflictingFlags.length > 0) {\n\t\t\t\t\torchestrationDiagnostics.push({\n\t\t\t\t\t\ttype: \"error\",\n\t\t\t\t\t\tmessage: `Orchestration profile '${orchestrationProfile.profileId}' owns model, thinking, tools, and resources; remove conflicting ${conflictingFlags.join(\", \")}.`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (parsed.resourceProfileJson) {\n\t\t\tfor (const profileInput of parsed.resourceProfileJson) {\n\t\t\t\tconst { profiles, errors } = parseResourceProfileInput(profileInput);\n\t\t\t\tif (errors.length > 0) {\n\t\t\t\t\treportDiagnostics(\n\t\t\t\t\t\terrors.map((message) => ({\n\t\t\t\t\t\t\ttype: \"warning\" as const,\n\t\t\t\t\t\t\tmessage: `--resource-profile-json ignored entry: ${message}`,\n\t\t\t\t\t\t})),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\truntimeSettingsManager.addInlineResourceProfileDefinitions(profiles);\n\t\t\t}\n\t\t}\n\t\tif (!orchestrationProfile && parsed.resourceProfiles && parsed.resourceProfiles.length > 0) {\n\t\t\truntimeSettingsManager.setRuntimeResourceProfiles(parsed.resourceProfiles);\n\t\t}\n\t\tconst services = await createAgentSessionServices({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tauthStorage,\n\t\t\tsettingsManager: runtimeSettingsManager,\n\t\t\textensionFlagValues: parsed.unknownFlags,\n\t\t\tresourceLoaderOptions: {\n\t\t\t\tadditionalExtensionPaths: resolvedExtensionPaths,\n\t\t\t\tadditionalSkillPaths: resolvedSkillPaths,\n\t\t\t\tadditionalPromptTemplatePaths: resolvedPromptTemplatePaths,\n\t\t\t\tadditionalThemePaths: resolvedThemePaths,\n\t\t\t\tnoExtensions: parsed.noExtensions,\n\t\t\t\tnoSkills: parsed.noSkills,\n\t\t\t\tnoPromptTemplates: parsed.noPromptTemplates,\n\t\t\t\tnoThemes: parsed.noThemes,\n\t\t\t\tnoContextFiles: parsed.noContextFiles,\n\t\t\t\tsystemPrompt: parsed.systemPrompt,\n\t\t\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\t\t\textensionFactories: options?.extensionFactories,\n\t\t\t},\n\t\t});\n\t\tconst { settingsManager, modelRegistry, resourceLoader } = services;\n\t\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [\n\t\t\t...services.diagnostics,\n\t\t\t...orchestrationDiagnostics,\n\t\t\t...collectSettingsDiagnostics(settingsManager, \"runtime creation\"),\n\t\t\t...resourceLoader.getExtensions().errors.map(({ path, error }) => ({\n\t\t\t\ttype: \"warning\" as const,\n\t\t\t\tmessage: `Failed to load extension \"${path}\": ${error}`,\n\t\t\t})),\n\t\t];\n\n\t\tdiagnostics.push(\n\t\t\t...collectModelRouterConfigDiagnostics(settingsManager.getModelRouterSettings(), modelRegistry, agentDir).map(\n\t\t\t\t(message) => ({\n\t\t\t\t\ttype: \"warning\" as const,\n\t\t\t\t\tmessage,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\n\t\tconst modelPatterns = parsed.models ?? settingsManager.getEnabledModels();\n\t\tconst scopedModels =\n\t\t\tmodelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];\n\t\tconst {\n\t\t\toptions: sessionOptions,\n\t\t\tcliThinkingFromModel,\n\t\t\tdiagnostics: sessionOptionDiagnostics,\n\t\t} = buildSessionOptions(\n\t\t\tparsed,\n\t\t\tscopedModels,\n\t\t\tsessionManager.buildSessionContext().messages.length > 0,\n\t\t\tmodelRegistry,\n\t\t\tsettingsManager,\n\t\t\tcwd,\n\t\t);\n\t\tdiagnostics.push(...sessionOptionDiagnostics);\n\t\tlet orchestrationModel: ReturnType<typeof resolveConfiguredOrchestrationModel>;\n\t\tif (orchestrationProfile) {\n\t\t\torchestrationModel = resolveConfiguredOrchestrationModel(orchestrationProfile, modelRegistry);\n\t\t\tif (!orchestrationModel) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: `Orchestration profile '${orchestrationProfile.profileId}' has no configured, authenticated model that supports its exact thinking level.`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tsessionOptions.model = orchestrationModel.model;\n\t\t\t\tsessionOptions.thinkingLevel = orchestrationModel.binding.thinkingLevel;\n\t\t\t\tsessionOptions.isExplicitModel = true;\n\t\t\t\tsessionOptions.isExplicitThinking = true;\n\t\t\t\tsessionOptions.scopedModels = [\n\t\t\t\t\t{ model: orchestrationModel.model, thinkingLevel: orchestrationModel.binding.thinkingLevel },\n\t\t\t\t];\n\t\t\t\tsessionOptions.tools = [...orchestrationProfile.toolNames];\n\t\t\t\tsessionOptions.excludeTools = undefined;\n\t\t\t\tsessionOptions.noTools = undefined;\n\t\t\t\tsessionOptions.orchestrationProfile = orchestrationProfile;\n\t\t\t}\n\t\t}\n\n\t\tif (parsed.apiKey) {\n\t\t\tif (!sessionOptions.model) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"error\",\n\t\t\t\t\tmessage: \"--api-key requires a model to be specified via --model, --provider/--model, or --models\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tauthStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);\n\t\t\t}\n\t\t}\n\n\t\tconst created = await createAgentSessionFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent,\n\t\t\tmodel: sessionOptions.model,\n\t\t\tthinkingLevel: sessionOptions.thinkingLevel,\n\t\t\tisExplicitModel: sessionOptions.isExplicitModel,\n\t\t\tisExplicitThinking: sessionOptions.isExplicitThinking,\n\t\t\tscopedModels: sessionOptions.scopedModels,\n\t\t\ttools: sessionOptions.tools,\n\t\t\texcludeTools: sessionOptions.excludeTools,\n\t\t\tnoTools: sessionOptions.noTools,\n\t\t\ttoolProfileFilter: settingsManager.getResourceProfileFilter(\"tools\"),\n\t\t\tcustomTools: sessionOptions.customTools,\n\t\t\torchestrationProfile: sessionOptions.orchestrationProfile,\n\t\t});\n\t\tconst cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;\n\t\tif (created.session.model && cliThinkingOverride) {\n\t\t\tcreated.session.setThinkingLevel(created.session.thinkingLevel);\n\t\t}\n\t\tif (orchestrationProfile && orchestrationModel) {\n\t\t\tconst capabilities = [...orchestrationProfile.capabilityCeiling];\n\t\t\tcreated.session.capabilityEnvelope = {\n\t\t\t\tid: `orchestration-profile:${orchestrationProfile.profileId}`,\n\t\t\t\tprofileId: orchestrationProfile.profileId,\n\t\t\t\tcapabilities,\n\t\t\t\tallowedTools: [...orchestrationProfile.toolNames],\n\t\t\t\t...(capabilities.some(\n\t\t\t\t\t(capability) =>\n\t\t\t\t\t\tcapability === \"filesystem.read\" ||\n\t\t\t\t\t\tcapability === \"filesystem.write\" ||\n\t\t\t\t\t\tcapability === \"worktree.read\" ||\n\t\t\t\t\t\tcapability === \"worktree.mutate\",\n\t\t\t\t)\n\t\t\t\t\t? { allowedPaths: [cwd] }\n\t\t\t\t\t: {}),\n\t\t\t\t...(orchestrationProfile.budget.maxCostUsd !== undefined\n\t\t\t\t\t? { maxEstimatedUsd: orchestrationProfile.budget.maxCostUsd }\n\t\t\t\t\t: {}),\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\t...created,\n\t\t\tservices,\n\t\t\tdiagnostics,\n\t\t};\n\t};\n\ttime(\"createRuntime\");\n\tconst runtime = await createAgentSessionRuntime(createRuntime, {\n\t\tcwd: sessionManager.getCwd(),\n\t\tagentDir,\n\t\tsessionManager,\n\t});\n\ttime(\"createAgentSessionRuntime\");\n\tconst { services, session, modelFallbackMessage } = runtime;\n\tconst { settingsManager, modelRegistry, resourceLoader } = services;\n\tconfigureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());\n\tif (parsed.resume || parsed.continue || parsed.session !== undefined) {\n\t\t// Restoring a session must not mutate owner intent. Active goals may resume their runtime;\n\t\t// paused/blocked/limited goals remain stopped until an explicit owner action.\n\t\tsession.restoreGoalRuntimeAfterResume();\n\t}\n\n\t// A lane-bound session refuses AUTHORITATIVELY at its own startup when its model cannot reliably\n\t// drive the lane-gate/recovery surface unattended (full capability class, a declared context\n\t// window, an advertised native tool-call path, no graded /toolprobe demotion -- see\n\t// model-capability.ts's evaluateLaneWorkerRefusal). This is the authoritative check regardless of\n\t// how the lane binding arrived (--worktree-lane, PI_WORKTREE_LANE, or a launcher-set env): the\n\t// goal->tmux dispatch's own pre-check (tools/tmux-dispatch.ts) is the parent's best-effort guess\n\t// only and can race a model swap between dispatch and child startup. No silent unbinding -- an\n\t// ineligible model exits before the lane gate or epoch watcher ever start.\n\tconst boundWorktreeLaneKey = getBoundWorktreeLaneKey();\n\tif (boundWorktreeLaneKey) {\n\t\tconst laneWorkerRefusal = session.getLaneWorkerRefusal();\n\t\tif (laneWorkerRefusal) {\n\t\t\tconsole.error(chalk.red(formatLaneWorkerRefusal(laneWorkerRefusal, boundWorktreeLaneKey)));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// A read-only command (--help, --list-models) uses an in-memory session and has nothing to\n\t// supervise. Do not start either runtime: even an awaited startup would create needless state\n\t// and violate the read-only zero-write contract.\n\tconst isReadOnlyCommand = parsed.help || parsed.listModels !== undefined;\n\n\t// Session-owned supervision is replaced with /new, /resume, and /fork. This keeps notices,\n\t// process identity, orphan recovery, and worktree watchers bound to the active session instead\n\t// of retaining the initial session after it has been disposed.\n\tif (!isReadOnlyCommand) {\n\t\tconst supervision = new SessionSupervisionRuntime({\n\t\t\tagentDir,\n\t\t\thasUI: hasHumanUI,\n\t\t\torchestrationProfileId: parsed.orchestrationProfile?.trim() || undefined,\n\t\t\tisProcessAlive: isReloadSessionProcessAlive,\n\t\t\tpromptConfirm,\n\t\t\tresumeWorker: launchResumableWorker,\n\t\t\tonDiagnostic: (message) => {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: ${message}`));\n\t\t\t},\n\t\t\trequestExit: (activeSession) => {\n\t\t\t\ttry {\n\t\t\t\t\tactiveSession.dispose();\n\t\t\t\t} catch {\n\t\t\t\t\t// Best-effort: exit must proceed even if dispose() itself throws.\n\t\t\t\t}\n\t\t\t\tprocess.exit(0);\n\t\t\t},\n\t\t});\n\t\tawait supervision.start(session);\n\t\truntime.registerSessionResource(supervision);\n\t}\n\n\tif (parsed.help) {\n\t\tconst extensionFlags = resourceLoader\n\t\t\t.getExtensions()\n\t\t\t.extensions.flatMap((extension) => Array.from(extension.flags.values()));\n\t\tprintHelp(extensionFlags);\n\t\tprocess.exit(0);\n\t}\n\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(modelRegistry, searchPattern);\n\t\tprocess.exit(0);\n\t}\n\n\t// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC\n\tlet stdinContent: string | undefined;\n\tif (appMode !== \"rpc\") {\n\t\tstdinContent = await readPipedStdin();\n\t\tif (stdinContent !== undefined && appMode === \"interactive\") {\n\t\t\tappMode = \"print\";\n\t\t\thasHumanUI = false;\n\t\t}\n\t}\n\ttime(\"readPipedStdin\");\n\n\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\tparsed,\n\t\tsettingsManager.getImageAutoResize(),\n\t\tstdinContent,\n\t);\n\ttime(\"prepareInitialMessage\");\n\tconst { initTheme, stopThemeWatcher } = await import(\"./modes/interactive/theme/theme.ts\");\n\tinitTheme(settingsManager.getTheme(), hasHumanUI);\n\ttime(\"initTheme\");\n\n\t// Show deprecation warnings in interactive mode\n\tif (hasHumanUI && deprecationWarnings.length > 0) {\n\t\tawait showDeprecationWarnings(deprecationWarnings);\n\t}\n\n\ttime(\"resolveModelScope\");\n\treportDiagnostics(runtime.diagnostics);\n\tif (runtime.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\tprocess.exit(1);\n\t}\n\ttime(\"createAgentSession\");\n\n\tif (appMode !== \"interactive\" && !session.model) {\n\t\tconsole.error(chalk.red(formatNoModelsAvailableMessage()));\n\t\tprocess.exit(1);\n\t}\n\n\tconst startupBenchmark = isTruthyEnvFlag(process.env.PI_STARTUP_BENCHMARK);\n\tif (startupBenchmark && appMode !== \"interactive\") {\n\t\tconsole.error(chalk.red(\"Error: PI_STARTUP_BENCHMARK only supports interactive mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tif (appMode === \"rpc\") {\n\t\tprintTimings();\n\t\tconst { runRpcMode } = await import(\"./modes/rpc/rpc-mode.ts\");\n\t\tawait runRpcMode(runtime);\n\t} else if (appMode === \"interactive\") {\n\t\tconst { InteractiveMode } = await import(\"./modes/interactive/interactive-mode.ts\");\n\t\tconst interactiveMode = new InteractiveMode(runtime, {\n\t\t\tmigratedProviders,\n\t\t\tmodelFallbackMessage,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tverbose: parsed.verbose,\n\t\t\thasHumanAudience: hasHumanUI,\n\t\t});\n\t\tif (startupBenchmark) {\n\t\t\tawait interactiveMode.init();\n\t\t\ttime(\"interactiveMode.init\");\n\t\t\tprintTimings();\n\t\t\tinteractiveMode.stop();\n\t\t\tstopThemeWatcher();\n\t\t\tif (process.stdout.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stdout.once(\"drain\", resolve));\n\t\t\t}\n\t\t\tif (process.stderr.writableLength > 0) {\n\t\t\t\tawait new Promise<void>((resolve) => process.stderr.once(\"drain\", resolve));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tprintTimings();\n\t\tawait interactiveMode.run();\n\t} else {\n\t\tprintTimings();\n\t\tconst { runPrintMode } = await import(\"./modes/print-mode.ts\");\n\t\tconst exitCode = await runPrintMode(runtime, {\n\t\t\tmode: toPrintOutputMode(appMode),\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tprintUsage: parsed.printUsage,\n\t\t});\n\t\tstopThemeWatcher();\n\t\trestoreStdout();\n\t\tif (exitCode !== 0) {\n\t\t\tprocess.exitCode = exitCode;\n\t\t}\n\t\treturn;\n\t}\n}\n"]}
package/dist/main.js CHANGED
@@ -26,21 +26,46 @@ import { KeybindingsManager } from "./core/keybindings.js";
26
26
  import { formatLaneWorkerRefusal } from "./core/model-capability.js";
27
27
  import { resolveCliModel, resolveCliProviderDefault, resolveModelScope, resolveProfileModelSettings, } from "./core/model-resolver.js";
28
28
  import { collectModelRouterConfigDiagnostics } from "./core/model-router/config-diagnostics.js";
29
+ import { resolveConfiguredOrchestrationModel } from "./core/orchestration/model-binding.js";
30
+ import { OrchestrationProfileStore } from "./core/orchestration/profile-store.js";
29
31
  import { restoreStdout, takeOverStdout } from "./core/output-guard.js";
30
- import { PI_PARENT_PID_ENV, PI_PARENT_SESSION_ENV, startProcessMatrixRuntime } from "./core/process-matrix/runtime.js";
32
+ import { launchResumablePiAgent } from "./core/process-matrix/resume-launcher.js";
33
+ import { PI_PARENT_PID_ENV, PI_PARENT_SESSION_ENV, PI_TASK_REF_ENV, } from "./core/process-matrix/runtime.js";
31
34
  import { isReloadSessionProcessAlive } from "./core/reload-blockers.js";
32
35
  import { parseResourceProfileInput } from "./core/resource-profile-blocks.js";
33
36
  import { formatMissingSessionCwdPrompt, getMissingSessionCwdIssue, MissingSessionCwdError, } from "./core/session-cwd.js";
34
37
  import { continueRecentSession, createSession, forkSession, listAllSessions, listSessions, openSession, } from "./core/session-manager-factory.js";
38
+ import { getSessionRole, setTerminalSessionMode } from "./core/session-role.js";
39
+ import { SessionSupervisionRuntime } from "./core/session-supervision-runtime.js";
35
40
  import { SettingsManager } from "./core/settings-manager.js";
36
41
  import { printTimings, resetTimings, time } from "./core/timings.js";
37
42
  import { hasProjectTrustInputs, ProjectTrustStore } from "./core/trust-manager.js";
38
- import { getBoundWorktreeLaneKey, PI_WORKTREE_LANE_ENV, startWorktreeSyncRuntime, } from "./core/worktree-sync/runtime.js";
43
+ import { getBoundWorktreeLaneKey, PI_WORKTREE_LANE_ENV } from "./core/worktree-sync/runtime.js";
39
44
  import { runMigrations, showDeprecationWarnings } from "./migrations.js";
40
45
  import { handleConfigCommand, handlePackageCommand } from "./package-manager-cli.js";
41
46
  import { isLocalPath, normalizePath, resolvePath } from "./utils/paths.js";
42
47
  import { cleanupWindowsSelfUpdateQuarantine } from "./utils/windows-self-update.js";
43
48
  import { getProcessWorkRun, getWorkRoot, PI_WORK_ROOT_ENV } from "./utils/work-directory.js";
49
+ function getSelfLaunchTarget() {
50
+ const executableName = process.execPath.split(/[\\/]/).at(-1)?.toLowerCase();
51
+ const isScriptRuntime = ["node", "node.exe", "bun", "bun.exe"].includes(executableName ?? "");
52
+ if (!isScriptRuntime)
53
+ return { executable: process.execPath, argsPrefix: [] };
54
+ const cliPath = process.argv[1];
55
+ return cliPath && !cliPath.startsWith("-") ? { executable: process.execPath, argsPrefix: [cliPath] } : undefined;
56
+ }
57
+ async function launchResumableWorker(payload, parentSessionId) {
58
+ const target = getSelfLaunchTarget();
59
+ if (!target)
60
+ return { started: false, reason: "The current Pi executable cannot be resolved." };
61
+ return launchResumablePiAgent({
62
+ payload,
63
+ target,
64
+ parentPid: process.pid,
65
+ parentSessionId,
66
+ environment: process.env,
67
+ });
68
+ }
44
69
  /**
45
70
  * Read all content from piped stdin.
46
71
  * Returns undefined if stdin is a TTY (interactive terminal).
@@ -208,7 +233,7 @@ function forkSessionOrExit(sourcePath, cwd, sessionDir, sessionId) {
208
233
  process.exit(1);
209
234
  }
210
235
  }
211
- async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
236
+ async function createSessionManager(parsed, cwd, sessionDir, settingsManager, hasHumanUI) {
212
237
  if (parsed.noSession || parsed.help || parsed.listModels !== undefined) {
213
238
  return SessionManager.inMemory(cwd);
214
239
  }
@@ -238,6 +263,10 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
238
263
  case "local":
239
264
  return openSession(resolved.path, sessionDir);
240
265
  case "global": {
266
+ if (!hasHumanUI) {
267
+ console.error(chalk.red("Cannot open a cross-project session without a user approval UI."));
268
+ process.exit(1);
269
+ }
241
270
  console.log(chalk.yellow(`Session found in different project: ${resolved.cwd}`));
242
271
  const shouldFork = await promptConfirm("Fork this session into current directory?");
243
272
  if (!shouldFork) {
@@ -252,6 +281,10 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
252
281
  }
253
282
  }
254
283
  if (parsed.resume) {
284
+ if (!hasHumanUI) {
285
+ console.error(chalk.red("Error: --resume requires --session-mode user; use --session <id> for workers."));
286
+ process.exit(1);
287
+ }
255
288
  const { initTheme, stopThemeWatcher } = await import("./modes/interactive/theme/theme.js");
256
289
  initTheme(settingsManager.getTheme(), true);
257
290
  try {
@@ -521,7 +554,14 @@ export async function main(args, options) {
521
554
  if (parsed.parentSession) {
522
555
  process.env[PI_PARENT_SESSION_ENV] = parsed.parentSession;
523
556
  }
557
+ if (parsed.taskRef) {
558
+ process.env[PI_TASK_REF_ENV] = parsed.taskRef;
559
+ }
560
+ if (parsed.sessionMode) {
561
+ setTerminalSessionMode(parsed.sessionMode);
562
+ }
524
563
  let appMode = resolveAppMode(parsed, process.stdin.isTTY);
564
+ let hasHumanUI = appMode === "interactive" && getSessionRole() === "main";
525
565
  const shouldTakeOverStdout = appMode !== "interactive";
526
566
  if (shouldTakeOverStdout) {
527
567
  takeOverStdout();
@@ -568,10 +608,10 @@ export async function main(args, options) {
568
608
  const sessionDir = (parsed.sessionDir ? normalizePath(parsed.sessionDir) : undefined) ??
569
609
  (envSessionDir ? expandTildePath(envSessionDir) : undefined) ??
570
610
  startupSettingsManager.getSessionDir();
571
- let sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager);
611
+ let sessionManager = await createSessionManager(parsed, cwd, sessionDir, startupSettingsManager, hasHumanUI);
572
612
  const missingSessionCwdIssue = getMissingSessionCwdIssue(sessionManager, cwd);
573
613
  if (missingSessionCwdIssue) {
574
- if (appMode === "interactive") {
614
+ if (hasHumanUI) {
575
615
  const selectedCwd = await promptForMissingSessionCwd(missingSessionCwdIssue, startupSettingsManager);
576
616
  if (!selectedCwd) {
577
617
  process.exit(0);
@@ -592,7 +632,7 @@ export async function main(args, options) {
592
632
  sessionManager.appendSessionInfo(name);
593
633
  }
594
634
  time("createSessionManager");
595
- const trustPromptMode = parsed.help || parsed.listModels !== undefined ? "print" : appMode;
635
+ const trustPromptMode = parsed.help || parsed.listModels !== undefined || !hasHumanUI ? "print" : appMode;
596
636
  const projectTrustedForSession = await resolveProjectTrusted({
597
637
  cwd: sessionManager.getCwd(),
598
638
  trustStore,
@@ -610,6 +650,41 @@ export async function main(args, options) {
610
650
  ? projectTrustedForSession
611
651
  : (parsed.projectTrustOverride ?? (!hasProjectTrustInputs(cwd) || trustStore.get(cwd) === true));
612
652
  const runtimeSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted });
653
+ const orchestrationDiagnostics = [];
654
+ const orchestrationProfileId = parsed.orchestrationProfile?.trim() || runtimeSettingsManager.getActiveOrchestrationProfile();
655
+ let orchestrationProfile;
656
+ if (orchestrationProfileId) {
657
+ const loaded = new OrchestrationProfileStore({ agentDir, cwd, projectTrusted }).load();
658
+ orchestrationDiagnostics.push(...loaded.diagnostics.map((diagnostic) => ({
659
+ type: "warning",
660
+ message: `Orchestration profile ignored (${diagnostic.path}): ${diagnostic.message}`,
661
+ })));
662
+ orchestrationProfile = loaded.registry.get(orchestrationProfileId);
663
+ if (!orchestrationProfile) {
664
+ orchestrationDiagnostics.push({
665
+ type: "error",
666
+ message: `Orchestration profile '${orchestrationProfileId}' was not found.`,
667
+ });
668
+ }
669
+ else {
670
+ runtimeSettingsManager.setRuntimeResourceProfiles([...orchestrationProfile.resourceProfileNames]);
671
+ const conflictingFlags = [
672
+ ...(parsed.model || parsed.provider ? ["--model/--provider"] : []),
673
+ ...(parsed.models ? ["--models"] : []),
674
+ ...(parsed.thinking ? ["--thinking"] : []),
675
+ ...(parsed.tools || parsed.excludeTools || parsed.noTools || parsed.noBuiltinTools
676
+ ? ["--tools/--exclude-tools/--no-tools"]
677
+ : []),
678
+ ...(parsed.resourceProfiles ? ["--resource-profile"] : []),
679
+ ];
680
+ if (conflictingFlags.length > 0) {
681
+ orchestrationDiagnostics.push({
682
+ type: "error",
683
+ message: `Orchestration profile '${orchestrationProfile.profileId}' owns model, thinking, tools, and resources; remove conflicting ${conflictingFlags.join(", ")}.`,
684
+ });
685
+ }
686
+ }
687
+ }
613
688
  if (parsed.resourceProfileJson) {
614
689
  for (const profileInput of parsed.resourceProfileJson) {
615
690
  const { profiles, errors } = parseResourceProfileInput(profileInput);
@@ -622,7 +697,7 @@ export async function main(args, options) {
622
697
  runtimeSettingsManager.addInlineResourceProfileDefinitions(profiles);
623
698
  }
624
699
  }
625
- if (parsed.resourceProfiles && parsed.resourceProfiles.length > 0) {
700
+ if (!orchestrationProfile && parsed.resourceProfiles && parsed.resourceProfiles.length > 0) {
626
701
  runtimeSettingsManager.setRuntimeResourceProfiles(parsed.resourceProfiles);
627
702
  }
628
703
  const services = await createAgentSessionServices({
@@ -649,6 +724,7 @@ export async function main(args, options) {
649
724
  const { settingsManager, modelRegistry, resourceLoader } = services;
650
725
  const diagnostics = [
651
726
  ...services.diagnostics,
727
+ ...orchestrationDiagnostics,
652
728
  ...collectSettingsDiagnostics(settingsManager, "runtime creation"),
653
729
  ...resourceLoader.getExtensions().errors.map(({ path, error }) => ({
654
730
  type: "warning",
@@ -663,6 +739,29 @@ export async function main(args, options) {
663
739
  const scopedModels = modelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];
664
740
  const { options: sessionOptions, cliThinkingFromModel, diagnostics: sessionOptionDiagnostics, } = buildSessionOptions(parsed, scopedModels, sessionManager.buildSessionContext().messages.length > 0, modelRegistry, settingsManager, cwd);
665
741
  diagnostics.push(...sessionOptionDiagnostics);
742
+ let orchestrationModel;
743
+ if (orchestrationProfile) {
744
+ orchestrationModel = resolveConfiguredOrchestrationModel(orchestrationProfile, modelRegistry);
745
+ if (!orchestrationModel) {
746
+ diagnostics.push({
747
+ type: "error",
748
+ message: `Orchestration profile '${orchestrationProfile.profileId}' has no configured, authenticated model that supports its exact thinking level.`,
749
+ });
750
+ }
751
+ else {
752
+ sessionOptions.model = orchestrationModel.model;
753
+ sessionOptions.thinkingLevel = orchestrationModel.binding.thinkingLevel;
754
+ sessionOptions.isExplicitModel = true;
755
+ sessionOptions.isExplicitThinking = true;
756
+ sessionOptions.scopedModels = [
757
+ { model: orchestrationModel.model, thinkingLevel: orchestrationModel.binding.thinkingLevel },
758
+ ];
759
+ sessionOptions.tools = [...orchestrationProfile.toolNames];
760
+ sessionOptions.excludeTools = undefined;
761
+ sessionOptions.noTools = undefined;
762
+ sessionOptions.orchestrationProfile = orchestrationProfile;
763
+ }
764
+ }
666
765
  if (parsed.apiKey) {
667
766
  if (!sessionOptions.model) {
668
767
  diagnostics.push({
@@ -688,11 +787,31 @@ export async function main(args, options) {
688
787
  noTools: sessionOptions.noTools,
689
788
  toolProfileFilter: settingsManager.getResourceProfileFilter("tools"),
690
789
  customTools: sessionOptions.customTools,
790
+ orchestrationProfile: sessionOptions.orchestrationProfile,
691
791
  });
692
792
  const cliThinkingOverride = parsed.thinking !== undefined || cliThinkingFromModel;
693
793
  if (created.session.model && cliThinkingOverride) {
694
794
  created.session.setThinkingLevel(created.session.thinkingLevel);
695
795
  }
796
+ if (orchestrationProfile && orchestrationModel) {
797
+ const capabilities = [...orchestrationProfile.capabilityCeiling];
798
+ created.session.capabilityEnvelope = {
799
+ id: `orchestration-profile:${orchestrationProfile.profileId}`,
800
+ profileId: orchestrationProfile.profileId,
801
+ capabilities,
802
+ allowedTools: [...orchestrationProfile.toolNames],
803
+ ...(capabilities.some((capability) => capability === "filesystem.read" ||
804
+ capability === "filesystem.write" ||
805
+ capability === "worktree.read" ||
806
+ capability === "worktree.mutate")
807
+ ? { allowedPaths: [cwd] }
808
+ : {}),
809
+ ...(orchestrationProfile.budget.maxCostUsd !== undefined
810
+ ? { maxEstimatedUsd: orchestrationProfile.budget.maxCostUsd }
811
+ : {}),
812
+ createdAt: new Date().toISOString(),
813
+ };
814
+ }
696
815
  return {
697
816
  ...created,
698
817
  services,
@@ -709,6 +828,11 @@ export async function main(args, options) {
709
828
  const { services, session, modelFallbackMessage } = runtime;
710
829
  const { settingsManager, modelRegistry, resourceLoader } = services;
711
830
  configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());
831
+ if (parsed.resume || parsed.continue || parsed.session !== undefined) {
832
+ // Restoring a session must not mutate owner intent. Active goals may resume their runtime;
833
+ // paused/blocked/limited goals remain stopped until an explicit owner action.
834
+ session.restoreGoalRuntimeAfterResume();
835
+ }
712
836
  // A lane-bound session refuses AUTHORITATIVELY at its own startup when its model cannot reliably
713
837
  // drive the lane-gate/recovery surface unattended (full capability class, a declared context
714
838
  // window, an advertised native tool-call path, no graded /toolprobe demotion -- see
@@ -725,57 +849,27 @@ export async function main(args, options) {
725
849
  process.exit(1);
726
850
  }
727
851
  }
728
- // A read-only command (--help, --list-models) prints and exits without ever reserving a
729
- // session (see the createSessionManager in-memory-session gate above) -- for the same reason,
730
- // it must not fire either of the runtimes below. Both are launched with `void` (fire-and-
731
- // forget) and race the imminent `process.exit()` a few lines down in the --help/--list-models
732
- // branches: their first write (worktree-sync's reconcile pass, process-matrix's master-entry
733
- // writeEntry -- core/process-matrix/runtime.ts's startMasterBranch) can still be in flight on
734
- // the libuv threadpool when process.exit() forcibly tears the process down, which on Windows
735
- // can leave the just-written file's handle held by the OS a beat longer than the process
736
- // itself survives -- long enough for an immediately-following rmSync of the temp agent dir
737
- // (see test/session-id-readonly.test.ts) to observe EPERM. A read-only command has no session
738
- // and nothing to supervise, so the correct fix is not starting either runtime for it at all.
852
+ // A read-only command (--help, --list-models) uses an in-memory session and has nothing to
853
+ // supervise. Do not start either runtime: even an awaited startup would create needless state
854
+ // and violate the read-only zero-write contract.
739
855
  const isReadOnlyCommand = parsed.help || parsed.listModels !== undefined;
740
- // Worktree-sync session runtime (no-op unless enabled): one startup reconcile pass, plus --
741
- // for a lane-bound session -- the epoch watcher that injects a deterministic staleness notice
742
- // the moment another lane lands (steer mid-turn, its own turn when idle). Fire-and-forget:
743
- // a broken repo state must never block session startup.
856
+ // Session-owned supervision is replaced with /new, /resume, and /fork. This keeps notices,
857
+ // process identity, orphan recovery, and worktree watchers bound to the active session instead
858
+ // of retaining the initial session after it has been disposed.
744
859
  if (!isReadOnlyCommand) {
745
- void startWorktreeSyncRuntime({
746
- cwd: sessionManager.getCwd(),
860
+ const supervision = new SessionSupervisionRuntime({
747
861
  agentDir,
748
- settingsManager,
749
- sessionId: sessionManager.getSessionId(),
750
- notify: (text) => {
751
- void session.sendCustomMessage({ customType: "worktree-sync-notice", content: text, display: true }, { triggerTurn: true, deliverAs: "steer" });
752
- },
753
- onDiagnostic: (message) => {
754
- console.error(chalk.yellow(`Warning: ${message}`));
755
- },
756
- });
757
- }
758
- // Process-matrix runtime (no-op unless enabled): durable master/worker supervision surviving
759
- // restarts -- a master asks before touching any orphaned worker it finds on resume; a worker
760
- // winds down gracefully (never silently) when its parent disappears. Fire-and-forget, same as
761
- // worktree-sync above: a broken store must never block session startup.
762
- if (!isReadOnlyCommand) {
763
- void startProcessMatrixRuntime({
764
- agentDir,
765
- sessionId: sessionManager.getSessionId(),
766
- hasUI: appMode === "interactive",
767
- settings: settingsManager.getProcessMatrixSettings(),
862
+ hasUI: hasHumanUI,
863
+ orchestrationProfileId: parsed.orchestrationProfile?.trim() || undefined,
768
864
  isProcessAlive: isReloadSessionProcessAlive,
769
865
  promptConfirm,
770
- notify: (text) => {
771
- void session.sendCustomMessage({ customType: "process-matrix-notice", content: text, display: true }, { triggerTurn: true, deliverAs: "steer" });
772
- },
866
+ resumeWorker: launchResumableWorker,
773
867
  onDiagnostic: (message) => {
774
868
  console.error(chalk.yellow(`Warning: ${message}`));
775
869
  },
776
- requestExit: () => {
870
+ requestExit: (activeSession) => {
777
871
  try {
778
- session.dispose();
872
+ activeSession.dispose();
779
873
  }
780
874
  catch {
781
875
  // Best-effort: exit must proceed even if dispose() itself throws.
@@ -783,6 +877,8 @@ export async function main(args, options) {
783
877
  process.exit(0);
784
878
  },
785
879
  });
880
+ await supervision.start(session);
881
+ runtime.registerSessionResource(supervision);
786
882
  }
787
883
  if (parsed.help) {
788
884
  const extensionFlags = resourceLoader
@@ -802,16 +898,17 @@ export async function main(args, options) {
802
898
  stdinContent = await readPipedStdin();
803
899
  if (stdinContent !== undefined && appMode === "interactive") {
804
900
  appMode = "print";
901
+ hasHumanUI = false;
805
902
  }
806
903
  }
807
904
  time("readPipedStdin");
808
905
  const { initialMessage, initialImages } = await prepareInitialMessage(parsed, settingsManager.getImageAutoResize(), stdinContent);
809
906
  time("prepareInitialMessage");
810
907
  const { initTheme, stopThemeWatcher } = await import("./modes/interactive/theme/theme.js");
811
- initTheme(settingsManager.getTheme(), appMode === "interactive");
908
+ initTheme(settingsManager.getTheme(), hasHumanUI);
812
909
  time("initTheme");
813
910
  // Show deprecation warnings in interactive mode
814
- if (appMode === "interactive" && deprecationWarnings.length > 0) {
911
+ if (hasHumanUI && deprecationWarnings.length > 0) {
815
912
  await showDeprecationWarnings(deprecationWarnings);
816
913
  }
817
914
  time("resolveModelScope");
@@ -843,6 +940,7 @@ export async function main(args, options) {
843
940
  initialImages,
844
941
  initialMessages: parsed.messages,
845
942
  verbose: parsed.verbose,
943
+ hasHumanAudience: hasHumanUI,
846
944
  });
847
945
  if (startupBenchmark) {
848
946
  await interactiveMode.init();