@ponythewhite/base-context 1.0.0 → 1.0.2

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 (285) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/NOTICE +0 -5
  3. package/README.md +44 -27
  4. package/dist/NOTICE +0 -5
  5. package/dist/base-context-runtime/pyproject.toml +1 -1
  6. package/dist/base-context-runtime/src/rlm/__init__.py +7 -5
  7. package/dist/base-context-runtime/test/test_subagent_registry.py +28 -1
  8. package/dist/base-context-runtime/uv.lock +1 -1
  9. package/dist/build-info.json +1 -1
  10. package/dist/bundle/amazon-bedrock.js +21 -0
  11. package/dist/bundle/{anthropic-YY4S534V.js → anthropic-UV5GZDGU.js} +5 -5
  12. package/dist/bundle/{azure-openai-responses-JRP6MIM3.js → azure-openai-responses-WSNPXLYC.js} +6 -6
  13. package/dist/bundle/{bundled-modules-P5HARVZA.js → bundled-modules-PWOGKUQQ.js} +71 -16
  14. package/dist/bundle/chunk-27QCJ2AZ.js +2578 -0
  15. package/dist/bundle/{chunk-BYVP7LWV.js → chunk-44PEHPOG.js} +1916 -4689
  16. package/dist/bundle/{chunk-MZHTNNVA.js → chunk-4GXPNXOJ.js} +8 -0
  17. package/dist/bundle/{chunk-SC5KG5R4.js → chunk-DGNX7HQ3.js} +1 -7
  18. package/dist/bundle/{chunk-A53O363M.js → chunk-GRJFXLBM.js} +0 -1
  19. package/dist/bundle/chunk-HKINIBP4.js +29 -0
  20. package/dist/bundle/{chunk-73DCPU3D.js → chunk-IADCPVEI.js} +1019 -3427
  21. package/dist/bundle/{chunk-UDSW6FNG.js → chunk-KTNETTHI.js} +1 -1
  22. package/dist/bundle/{chunk-U7AUVG3B.js → chunk-VSIYFWYI.js} +24 -6
  23. package/dist/bundle/{chunk-IW77OXFS.js → chunk-W46VZFI6.js} +0 -2099
  24. package/dist/bundle/{cli-main-O4X7GFGY.js → cli-main-4DS7Y3PI.js} +8 -6
  25. package/dist/bundle/cli.js +2 -2
  26. package/dist/bundle/{google-AUTVGDGZ.js → google-T32FMD4G.js} +6 -6
  27. package/dist/bundle/{google-vertex-Q75D7RKS.js → google-vertex-56KP6I3B.js} +3 -3
  28. package/dist/bundle/{main-XKOW2BV6.js → main-SV7JLVEB.js} +7 -5
  29. package/dist/bundle/{mistral-7ESB7QUD.js → mistral-WGBMYIVU.js} +5 -5
  30. package/dist/bundle/{openai-codex-responses-LV3QRPN4.js → openai-codex-responses-PIV2RQ3G.js} +6 -6
  31. package/dist/bundle/{openai-completions-OJECLPXJ.js → openai-completions-64C3JPR4.js} +11 -22
  32. package/dist/bundle/{openai-responses-FN6HZMBC.js → openai-responses-UI7RSTDV.js} +6 -6
  33. package/dist/cli/args.d.ts.map +1 -1
  34. package/dist/cli/args.js +108 -59
  35. package/dist/cli/args.js.map +1 -1
  36. package/dist/cli/daemon-ps.d.ts +4 -3
  37. package/dist/cli/daemon-ps.d.ts.map +1 -1
  38. package/dist/cli/daemon-ps.js +6 -1
  39. package/dist/cli/daemon-ps.js.map +1 -1
  40. package/dist/cli/product-doctor.d.ts +0 -1
  41. package/dist/cli/product-doctor.d.ts.map +1 -1
  42. package/dist/cli/product-doctor.js +6 -3
  43. package/dist/cli/product-doctor.js.map +1 -1
  44. package/dist/config.d.ts +0 -3
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +0 -8
  47. package/dist/config.js.map +1 -1
  48. package/dist/core/agent-session-config.d.ts +1 -2
  49. package/dist/core/agent-session-config.d.ts.map +1 -1
  50. package/dist/core/agent-session-config.js +0 -3
  51. package/dist/core/agent-session-config.js.map +1 -1
  52. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  53. package/dist/core/agent-session-runtime.js +5 -4
  54. package/dist/core/agent-session-runtime.js.map +1 -1
  55. package/dist/core/agent-session-services.d.ts +5 -3
  56. package/dist/core/agent-session-services.d.ts.map +1 -1
  57. package/dist/core/agent-session-services.js +2 -27
  58. package/dist/core/agent-session-services.js.map +1 -1
  59. package/dist/core/agent-session.d.ts +10 -6
  60. package/dist/core/agent-session.d.ts.map +1 -1
  61. package/dist/core/agent-session.js +107 -107
  62. package/dist/core/agent-session.js.map +1 -1
  63. package/dist/core/auth-storage.d.ts +8 -35
  64. package/dist/core/auth-storage.d.ts.map +1 -1
  65. package/dist/core/auth-storage.js +33 -243
  66. package/dist/core/auth-storage.js.map +1 -1
  67. package/dist/core/cron-jobs.d.ts.map +1 -1
  68. package/dist/core/cron-jobs.js +7 -1
  69. package/dist/core/cron-jobs.js.map +1 -1
  70. package/dist/core/inference-coordinator.d.ts +6 -1
  71. package/dist/core/inference-coordinator.d.ts.map +1 -1
  72. package/dist/core/inference-coordinator.js +18 -2
  73. package/dist/core/inference-coordinator.js.map +1 -1
  74. package/dist/core/kernel/bootstrap.d.ts.map +1 -1
  75. package/dist/core/kernel/bootstrap.js +2 -2
  76. package/dist/core/kernel/bootstrap.js.map +1 -1
  77. package/dist/core/kernel/repl-manager.d.ts +2 -0
  78. package/dist/core/kernel/repl-manager.d.ts.map +1 -1
  79. package/dist/core/kernel/repl-manager.js +44 -1
  80. package/dist/core/kernel/repl-manager.js.map +1 -1
  81. package/dist/core/logging.d.ts +4 -3
  82. package/dist/core/logging.d.ts.map +1 -1
  83. package/dist/core/logging.js +6 -6
  84. package/dist/core/logging.js.map +1 -1
  85. package/dist/core/mcp/mcp-manager.d.ts.map +1 -1
  86. package/dist/core/mcp/mcp-manager.js +3 -3
  87. package/dist/core/mcp/mcp-manager.js.map +1 -1
  88. package/dist/core/model-registry.d.ts +1 -16
  89. package/dist/core/model-registry.d.ts.map +1 -1
  90. package/dist/core/model-registry.js +88 -196
  91. package/dist/core/model-registry.js.map +1 -1
  92. package/dist/core/model-resolver.d.ts +2 -19
  93. package/dist/core/model-resolver.d.ts.map +1 -1
  94. package/dist/core/model-resolver.js +36 -266
  95. package/dist/core/model-resolver.js.map +1 -1
  96. package/dist/core/provider-contracts.d.ts +5 -6
  97. package/dist/core/provider-contracts.d.ts.map +1 -1
  98. package/dist/core/provider-contracts.js +25 -36
  99. package/dist/core/provider-contracts.js.map +1 -1
  100. package/dist/core/provider-display-names.d.ts.map +1 -1
  101. package/dist/core/provider-display-names.js +0 -2
  102. package/dist/core/provider-display-names.js.map +1 -1
  103. package/dist/core/rlm-max-subagents.d.ts +32 -0
  104. package/dist/core/rlm-max-subagents.d.ts.map +1 -0
  105. package/dist/core/rlm-max-subagents.js +50 -0
  106. package/dist/core/rlm-max-subagents.js.map +1 -0
  107. package/dist/core/rlm-runtime.d.ts +3 -3
  108. package/dist/core/rlm-runtime.d.ts.map +1 -1
  109. package/dist/core/rlm-runtime.js.map +1 -1
  110. package/dist/core/sdk.d.ts +4 -3
  111. package/dist/core/sdk.d.ts.map +1 -1
  112. package/dist/core/sdk.js +27 -14
  113. package/dist/core/sdk.js.map +1 -1
  114. package/dist/core/settings-manager.d.ts +3 -16
  115. package/dist/core/settings-manager.d.ts.map +1 -1
  116. package/dist/core/settings-manager.js +12 -44
  117. package/dist/core/settings-manager.js.map +1 -1
  118. package/dist/core/slash-commands.d.ts.map +1 -1
  119. package/dist/core/slash-commands.js +6 -6
  120. package/dist/core/slash-commands.js.map +1 -1
  121. package/dist/index.d.ts +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js.map +1 -1
  124. package/dist/installer.mjs +2 -3
  125. package/dist/main.d.ts.map +1 -1
  126. package/dist/main.js +39 -34
  127. package/dist/main.js.map +1 -1
  128. package/dist/modes/acp/acp-mode.d.ts.map +1 -1
  129. package/dist/modes/acp/acp-mode.js +1 -1
  130. package/dist/modes/acp/acp-mode.js.map +1 -1
  131. package/dist/modes/agent-connection/daemon-agent-connection.d.ts +6 -2
  132. package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
  133. package/dist/modes/agent-connection/daemon-agent-connection.js +13 -2
  134. package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
  135. package/dist/modes/agent-connection/in-process-agent-connection.d.ts +2 -0
  136. package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
  137. package/dist/modes/agent-connection/in-process-agent-connection.js +6 -0
  138. package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
  139. package/dist/modes/agent-connection/types.d.ts +3 -0
  140. package/dist/modes/agent-connection/types.d.ts.map +1 -1
  141. package/dist/modes/agent-connection/types.js.map +1 -1
  142. package/dist/modes/agents-view/agents-view-mode.d.ts.map +1 -1
  143. package/dist/modes/agents-view/agents-view-mode.js +2 -19
  144. package/dist/modes/agents-view/agents-view-mode.js.map +1 -1
  145. package/dist/modes/daemon/daemon-mode.d.ts +5 -0
  146. package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
  147. package/dist/modes/daemon/daemon-mode.js +107 -12
  148. package/dist/modes/daemon/daemon-mode.js.map +1 -1
  149. package/dist/modes/daemon/daemon-protocol.d.ts +194 -165
  150. package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
  151. package/dist/modes/daemon/daemon-protocol.js +16 -11
  152. package/dist/modes/daemon/daemon-protocol.js.map +1 -1
  153. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.d.ts +19 -0
  154. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.d.ts.map +1 -0
  155. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.js +74 -0
  156. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.js.map +1 -0
  157. package/dist/modes/daemon/daemon-rlm-capacity.d.ts +19 -0
  158. package/dist/modes/daemon/daemon-rlm-capacity.d.ts.map +1 -0
  159. package/dist/modes/daemon/daemon-rlm-capacity.js +85 -0
  160. package/dist/modes/daemon/daemon-rlm-capacity.js.map +1 -0
  161. package/dist/modes/daemon/daemon-session-summarizer.d.ts +2 -3
  162. package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
  163. package/dist/modes/daemon/daemon-session-summarizer.js +32 -23
  164. package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
  165. package/dist/modes/daemon/daemon-state-root.d.ts +15 -0
  166. package/dist/modes/daemon/daemon-state-root.d.ts.map +1 -0
  167. package/dist/modes/daemon/daemon-state-root.js +40 -0
  168. package/dist/modes/daemon/daemon-state-root.js.map +1 -0
  169. package/dist/modes/daemon/daemon-supervisor-ownership.d.ts +2 -0
  170. package/dist/modes/daemon/daemon-supervisor-ownership.d.ts.map +1 -1
  171. package/dist/modes/daemon/daemon-supervisor-ownership.js +27 -0
  172. package/dist/modes/daemon/daemon-supervisor-ownership.js.map +1 -1
  173. package/dist/modes/daemon/daemon-supervisor.d.ts +10 -1
  174. package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
  175. package/dist/modes/daemon/daemon-supervisor.js +213 -20
  176. package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
  177. package/dist/modes/daemon/daemon-worker-protocol.d.ts +28 -1
  178. package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
  179. package/dist/modes/daemon/daemon-worker-protocol.js +16 -2
  180. package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
  181. package/dist/modes/daemon/saved-session-catalog.d.ts.map +1 -1
  182. package/dist/modes/daemon/saved-session-catalog.js +2 -0
  183. package/dist/modes/daemon/saved-session-catalog.js.map +1 -1
  184. package/dist/modes/interactive/auth-flows.d.ts +0 -6
  185. package/dist/modes/interactive/auth-flows.d.ts.map +1 -1
  186. package/dist/modes/interactive/auth-flows.js +6 -126
  187. package/dist/modes/interactive/auth-flows.js.map +1 -1
  188. package/dist/modes/interactive/components/configuration-menu.d.ts +3 -0
  189. package/dist/modes/interactive/components/configuration-menu.d.ts.map +1 -1
  190. package/dist/modes/interactive/components/configuration-menu.js +13 -2
  191. package/dist/modes/interactive/components/configuration-menu.js.map +1 -1
  192. package/dist/modes/interactive/components/footer.d.ts +1 -1
  193. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  194. package/dist/modes/interactive/components/footer.js +2 -2
  195. package/dist/modes/interactive/components/footer.js.map +1 -1
  196. package/dist/modes/interactive/components/index.d.ts +0 -1
  197. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/index.js +0 -1
  199. package/dist/modes/interactive/components/index.js.map +1 -1
  200. package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
  201. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/login-dialog.js +3 -40
  203. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  204. package/dist/modes/interactive/components/model-selector.d.ts +2 -0
  205. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  206. package/dist/modes/interactive/components/model-selector.js +13 -2
  207. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  208. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  209. package/dist/modes/interactive/components/oauth-selector.js +2 -11
  210. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  211. package/dist/modes/interactive/feature-hints.d.ts.map +1 -1
  212. package/dist/modes/interactive/feature-hints.js +0 -4
  213. package/dist/modes/interactive/feature-hints.js.map +1 -1
  214. package/dist/modes/interactive/interactive-mode.d.ts +3 -12
  215. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  216. package/dist/modes/interactive/interactive-mode.js +81 -507
  217. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  218. package/dist/modes/interactive/onboarding.d.ts +0 -3
  219. package/dist/modes/interactive/onboarding.d.ts.map +1 -1
  220. package/dist/modes/interactive/onboarding.js +0 -17
  221. package/dist/modes/interactive/onboarding.js.map +1 -1
  222. package/dist/modes/rpc/rpc-client.d.ts +4 -1
  223. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  224. package/dist/modes/rpc/rpc-client.js +82 -42
  225. package/dist/modes/rpc/rpc-client.js.map +1 -1
  226. package/dist/node/amazon-bedrock.d.ts +2 -0
  227. package/dist/node/amazon-bedrock.d.ts.map +1 -0
  228. package/dist/node/amazon-bedrock.js +6 -0
  229. package/dist/node/amazon-bedrock.js.map +1 -0
  230. package/dist/product-identity.d.ts +0 -1
  231. package/dist/product-identity.d.ts.map +1 -1
  232. package/dist/product-identity.js +0 -1
  233. package/dist/product-identity.js.map +1 -1
  234. package/docs/development.md +1 -1
  235. package/docs/fork-philosophy.md +4 -8
  236. package/docs/installation.md +83 -62
  237. package/docs/providers.md +23 -25
  238. package/docs/quickstart.md +19 -10
  239. package/docs/rlm-runtime.md +13 -5
  240. package/docs/rpc.md +4 -4
  241. package/docs/sdk.md +20 -11
  242. package/docs/sessions.md +0 -1
  243. package/docs/settings.md +9 -42
  244. package/docs/skills.md +0 -1
  245. package/docs/upstream-0.9.5.md +171 -0
  246. package/docs/usage.md +14 -10
  247. package/package.json +4 -4
  248. package/dist/core/agent-traces.d.ts +0 -149
  249. package/dist/core/agent-traces.d.ts.map +0 -1
  250. package/dist/core/agent-traces.js +0 -904
  251. package/dist/core/agent-traces.js.map +0 -1
  252. package/dist/core/prime-inference-auth.d.ts +0 -70
  253. package/dist/core/prime-inference-auth.d.ts.map +0 -1
  254. package/dist/core/prime-inference-auth.js +0 -352
  255. package/dist/core/prime-inference-auth.js.map +0 -1
  256. package/dist/core/prime-inference-model-selection.d.ts +0 -16
  257. package/dist/core/prime-inference-model-selection.d.ts.map +0 -1
  258. package/dist/core/prime-inference-model-selection.js +0 -16
  259. package/dist/core/prime-inference-model-selection.js.map +0 -1
  260. package/dist/core/prime-inference-models.d.ts +0 -6
  261. package/dist/core/prime-inference-models.d.ts.map +0 -1
  262. package/dist/core/prime-inference-models.js +0 -62
  263. package/dist/core/prime-inference-models.js.map +0 -1
  264. package/dist/core/telemetry.d.ts +0 -95
  265. package/dist/core/telemetry.d.ts.map +0 -1
  266. package/dist/core/telemetry.js +0 -637
  267. package/dist/core/telemetry.js.map +0 -1
  268. package/dist/modes/interactive/components/prime-onboarding-splash.d.ts +0 -39
  269. package/dist/modes/interactive/components/prime-onboarding-splash.d.ts.map +0 -1
  270. package/dist/modes/interactive/components/prime-onboarding-splash.js +0 -286
  271. package/dist/modes/interactive/components/prime-onboarding-splash.js.map +0 -1
  272. package/dist/modes/interactive/components/prime-team-selector.d.ts +0 -30
  273. package/dist/modes/interactive/components/prime-team-selector.d.ts.map +0 -1
  274. package/dist/modes/interactive/components/prime-team-selector.js +0 -166
  275. package/dist/modes/interactive/components/prime-team-selector.js.map +0 -1
  276. package/dist/skills/prime-intellect/SKILL.md +0 -87
  277. package/dist/skills/prime-intellect/references/compute.md +0 -45
  278. package/dist/skills/prime-intellect/references/environments.md +0 -73
  279. package/dist/skills/prime-intellect/references/inference.md +0 -47
  280. package/dist/skills/prime-intellect/references/sandboxes.md +0 -75
  281. package/skills/prime-intellect/SKILL.md +0 -87
  282. package/skills/prime-intellect/references/compute.md +0 -45
  283. package/skills/prime-intellect/references/environments.md +0 -73
  284. package/skills/prime-intellect/references/inference.md +0 -47
  285. package/skills/prime-intellect/references/sandboxes.md +0 -75
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAE,KAAK,IAAI,EAAwB,MAAM,eAAe,CAAC;AAuBhE,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAG9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEN,KAAK,gCAAgC,EAErC,MAAM,iCAAiC,CAAC;AAUzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAMnE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAS/D,OAAO,EAAqD,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAe9G,OAAO,EAuBN,KAAK,cAAc,EACnB,MAAM,kBAAkB,CAAC;AAsD1B,MAAM,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAC5C,0EAA0E;AAC1E,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE5C,wBAAgB,gCAAgC,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAE3G;AAED,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAEjH;AAyBD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAEzF;AAGD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,kBAAkB,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKtG;AAED,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,gCAAgC,GAAG,2BAA2B,CAAC;AAE3E,8EAA8E;AAC9E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAOxF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAInF;AAED,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,2BAA2B,GAAG;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iCAAiC,CAAC,EAAE,OAAO,CAAC;CAC5C,GACC,OAAO,CAET;AAED,wBAAgB,uCAAuC,CACtD,oBAAoB,EAAE,OAAO,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAET;AAED,MAAM,WAAW,yBAAyB;IACzC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,wCAAwC,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAWpG;AAED,MAAM,WAAW,uCAAuC;IACvD,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAgB,oDAAoD,CACnE,OAAO,EAAE,uCAAuC,GAC9C,OAAO,CAOT;AAED,MAAM,WAAW,iCAAiC;IACjD,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,2CAA2C,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAM/G;AAsJD,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,IAAI,EACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,OAAO,CAAC,cAAc,CAAC,CAkDzB;AA4LD,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,yBAAyB,GAAG,yBAAyB,CAE7G;AAED,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,yBAAyB,EACzC,qBAAqB,CAAC,EAAE,yBAAyB,GAC/C,yBAAyB,CAgC3B;AAED,mHAAmH;AACnH,wBAAgB,2BAA2B,CAC1C,2BAA2B,EAAE,yBAAyB,EACtD,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACrC,gCAAgC,CA8DlC;AAgOD,wBAAgB,4CAA4C,CAC3D,SAAS,EAAE,SAAS,cAAc,EAAE,EACpC,WAAW,EAAE,MAAM,GACjB,cAAc,GAAG,SAAS,CAQ5B;AAyFD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACxC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,sBAooB/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 { join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { type Api, type ImageContent, type Model, modelsAreEqual } from \"@ponythewhite/base-context-ai\";\nimport { registerBuiltinMcpOAuthProviders } from \"@ponythewhite/base-context-ai/mcp\";\nimport { ProcessTerminal, setKeybindings, TUI } from \"@ponythewhite/base-context-tui\";\nimport chalk from \"chalk\";\nimport { type Args, type Mode, parseArgs } from \"./cli/args.js\";\nimport { formatTopLevelHelp } from \"./cli/command-registry.js\";\nimport {\n\tensureInteractiveDaemonRunning,\n\tisDaemonSessionSummary,\n\tlistActiveDaemonSessionSummaries,\n\tprobeRunningDaemonSessions,\n\tStaleDaemonError,\n\tshutdownDaemonAndWait,\n} from \"./cli/daemon-launch.js\";\nimport { confirmDaemonSessionLoss, type DaemonSessionLossCopy, pluralizeSessions } from \"./cli/daemon-stop-confirm.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { buildInitialMessage } from \"./cli/initial-message.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { installOwnedSessionRecoveryTracking, isOwnedSessionWorkerProcess } from \"./cli/owned-session-worker.js\";\nimport { handlePublicCommand } from \"./cli/public-command.js\";\nimport {\n\tlooksLikeSessionPath,\n\tresolveSessionPath,\n\tSessionSelectorError,\n\tSessionSelectorNotFoundError,\n} from \"./cli/session-resolver.js\";\nimport { APP_NAME, expandTildePath, getAgentDir, getSessionDirEnvOverride, VERSION } from \"./config.js\";\nimport {\n\ttype AgentExecutionMode,\n\ttype AgentSessionRuntimeConfig,\n\tmergeAgentSessionRuntimeConfig,\n\tmergeAutonomousConfig,\n} from \"./core/agent-session-config.js\";\nimport {\n\ttype AgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\tcreateAgentSessionRuntime,\n} from \"./core/agent-session-runtime.js\";\nimport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./core/agent-session-services.js\";\nimport { formatNoModelsAvailableMessage } from \"./core/auth-guidance.js\";\nimport { AuthStorage } from \"./core/auth-storage.js\";\nimport { exportFromFile } from \"./core/export-html/index.js\";\nimport type { ExtensionFactory } from \"./core/extensions/types.js\";\nimport { KeybindingsManager } from \"./core/keybindings.js\";\nimport { installFileLogSink, setLogContext } from \"./core/logging.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\nimport { findInitialModel, resolveCliModel, resolveModelScope, type ScopedModel } from \"./core/model-resolver.js\";\nimport { restoreStdout, takeOverStdout } from \"./core/output-guard.js\";\nimport type { CreateAgentSessionOptions } from \"./core/sdk.js\";\nimport { readSessionBootstrap } from \"./core/session-bootstrap.js\";\nimport {\n\tformatMissingSessionCwdPrompt,\n\tgetMissingSessionCwdIssue,\n\tMissingSessionCwdError,\n\ttype SessionCwdIssue,\n} from \"./core/session-cwd.js\";\nimport { canonicalSessionPath, SessionAlreadyActiveError } from \"./core/session-lease.js\";\nimport { findMostRecentSessionForCwd, getDefaultSessionDir, SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { isTelemetryEnabled } from \"./core/telemetry.js\";\nimport { printTimings, resetTimings, time } from \"./core/timings.js\";\nimport { runMigrations, showDeprecationWarnings } from \"./migrations.js\";\nimport { isDaemonCatalogProcess, runDaemonCatalogProcess } from \"./modes/daemon/daemon-catalog-process.js\";\nimport { DaemonSessionCreateError, deserializeDaemonCreateError } from \"./modes/daemon/daemon-errors.js\";\nimport { collectDaemonClientEnv, collectDaemonLaunchEnv } from \"./modes/daemon/daemon-protocol.js\";\nimport {\n\tDAEMON_WORKER_ACTIVE_SESSION_ID_ENV,\n\tdaemonWorkerInstanceId,\n\tisDaemonWorkerProcess,\n\trequireDaemonWorkerAuthenticationToken,\n\twaitForDaemonWorkerStartupGate,\n} from \"./modes/daemon/daemon-worker-protocol.js\";\nimport {\n\ttype AgentConnection,\n\ttype AgentsViewScopeKey,\n\tClientPromptStashStore,\n\tcreateInteractiveModeLocalSessionHost,\n\tcreateInteractiveModeUiServicesFromServices,\n\tDaemonAgentConnection,\n\tDaemonCapabilityUnavailableError,\n\tDaemonClient,\n\tdefaultDaemonSocketPath,\n\tInProcessAgentConnection,\n\tInteractiveMode,\n\tnormalizeSocketPath,\n\tresolveAttachModelFallbackMessage,\n\trunAcpMode,\n\trunAcpModeWithConnection,\n\trunAgentsViewMode,\n\trunDaemonMode,\n\trunDaemonSupervisorMode,\n\trunPrintMode,\n\trunPrintModeWithConnection,\n\trunRpcMode,\n\trunRpcModeWithConnection,\n\ttype SessionSummary,\n} from \"./modes/index.js\";\nimport { ExtensionSelectorComponent } from \"./modes/interactive/components/extension-selector.js\";\nimport { shouldRunOnboarding } from \"./modes/interactive/onboarding.js\";\nimport { initTheme, preloadCodeHighlighter, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { handleConfigCommand } from \"./package-manager-cli.js\";\nimport { assertProductStatePath } from \"./runtime-paths.js\";\nimport { isLocalPath } from \"./utils/paths.js\";\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\nexport type ClientMode = AgentExecutionMode;\n/** Compatibility view of the CLI's internal daemon process entrypoint. */\nexport type AppMode = ClientMode | \"daemon\";\n\nexport function shouldRejectNonInteractiveAttach(attachAgent: string | undefined, appMode: AppMode): boolean {\n\treturn attachAgent !== undefined && appMode !== \"interactive\";\n}\n\nexport function shouldRejectNonInteractiveBareResume(resume: true | string | undefined, appMode: AppMode): boolean {\n\treturn resume === true && appMode !== \"interactive\";\n}\n\nfunction resolveAppMode(parsed: Args, stdinIsTTY: boolean): AppMode {\n\tif (parsed.mode === \"daemon\") {\n\t\treturn \"daemon\";\n\t}\n\tif (parsed.mode === \"rpc\") {\n\t\treturn \"rpc\";\n\t}\n\tif (parsed.mode === \"acp\") {\n\t\treturn \"acp\";\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\" | \"acp\" | \"daemon\"> {\n\treturn appMode === \"json\" ? \"json\" : \"text\";\n}\n\nexport function isClientOwnedDaemonSession(appMode: AppMode, noSession?: boolean): boolean {\n\treturn appMode !== \"acp\" || noSession === true;\n}\n\n// `prime-agent agents` opens the agents view directly.\nexport function parseAgentsViewCommand(args: string[]): { explicitAgentsView: boolean; args: string[] } {\n\tif (args[0] === \"agents\") {\n\t\treturn { explicitAgentsView: true, args: args.slice(1) };\n\t}\n\treturn { explicitAgentsView: false, args };\n}\n\nexport interface DaemonClientStartupDecision {\n\tappMode: AppMode;\n\tstartupBenchmark: boolean;\n\tnoSession?: boolean;\n\thelp?: boolean;\n\tlistModels?: string | true;\n}\n\nexport type InteractiveDaemonStartupDecision = DaemonClientStartupDecision;\n\n/** Retained for callers that only classify persistent interactive startup. */\nexport function shouldUseDaemonInteractive(options: DaemonClientStartupDecision): boolean {\n\treturn (\n\t\toptions.appMode === \"interactive\" &&\n\t\t!options.startupBenchmark &&\n\t\t!options.noSession &&\n\t\toptions.listModels === undefined\n\t);\n}\n\nexport function shouldUseDaemonClient(options: DaemonClientStartupDecision): boolean {\n\treturn (\n\t\toptions.appMode !== \"daemon\" && !options.startupBenchmark && !options.help && options.listModels === undefined\n\t);\n}\n\nexport function shouldUseDaemonClientRuntime(\n\toptions: DaemonClientStartupDecision & {\n\t\townedSessionWorker?: boolean;\n\t\thasProcessLocalExtensionFactories?: boolean;\n\t},\n): boolean {\n\treturn shouldUseDaemonClient(options) && !options.ownedSessionWorker && !options.hasProcessLocalExtensionFactories;\n}\n\nexport function shouldEnsureInteractiveDaemonForStartup(\n\tuseDaemonInteractive: boolean,\n\tattachAgent: string | undefined,\n): boolean {\n\treturn useDaemonInteractive && attachAgent === undefined;\n}\n\nexport interface AgentsViewStartupDecision {\n\tuseDaemonInteractive: boolean;\n\tneedsOnboarding: boolean;\n\texplicitAgentsView?: boolean;\n\tresume?: true | string;\n\tcontinue?: boolean;\n\tfork?: string;\n}\n\nexport function shouldOpenAgentsViewForDaemonInteractive(options: AgentsViewStartupDecision): boolean {\n\tconst bareResume = options.resume === true;\n\tconst requestsAgentsView = bareResume || (options.explicitAgentsView && !options.needsOnboarding);\n\treturn (\n\t\toptions.useDaemonInteractive &&\n\t\t// A selector, continuation, or fork must open its target directly rather than the agents view.\n\t\t!!requestsAgentsView &&\n\t\ttypeof options.resume !== \"string\" &&\n\t\t!options.continue &&\n\t\t!options.fork\n\t);\n}\n\nexport interface DaemonInteractiveSessionManagerDecision {\n\tresume?: true | string;\n\tcontinue?: boolean;\n\tfork?: string;\n\thasActiveDaemonSession?: boolean;\n}\n\nexport function shouldUseEphemeralSessionManagerForDaemonInteractive(\n\toptions: DaemonInteractiveSessionManagerDecision,\n): boolean {\n\treturn (\n\t\t!options.hasActiveDaemonSession &&\n\t\t(options.resume === undefined || options.resume === true) &&\n\t\t!options.continue &&\n\t\t!options.fork\n\t);\n}\n\nexport interface DaemonActiveSessionLookupDecision {\n\tuseDaemonInteractive: boolean;\n\tresumeSelector?: string;\n\texplicitAttach?: boolean;\n}\n\nexport function shouldEnsureDaemonBeforeActiveSessionLookup(options: DaemonActiveSessionLookupDecision): boolean {\n\treturn (\n\t\toptions.useDaemonInteractive &&\n\t\toptions.resumeSelector !== undefined &&\n\t\t(options.explicitAttach || !looksLikeSessionPath(options.resumeSelector))\n\t);\n}\n\ninterface ActiveDaemonSessionSummaryLookupOptions {\n\tfallbackOnError?: boolean;\n}\n\nasync function findActiveDaemonSessionSummaryForInteractiveStartup(\n\tsocketPath: string,\n\tselector: string,\n\toptions: ActiveDaemonSessionSummaryLookupOptions = {},\n): Promise<SessionSummary | undefined> {\n\ttry {\n\t\treturn await findActiveDaemonSessionSummary(socketPath, selector);\n\t} catch (error) {\n\t\tif (options.fallbackOnError === false) {\n\t\t\tthrow error;\n\t\t}\n\t\treturn undefined;\n\t}\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/** Prompt user for yes/no confirmation */\nasync function promptConfirm(message: string): Promise<boolean> {\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\trl.question(`${message} [y/N] `, (answer) => {\n\t\t\trl.close();\n\t\t\tresolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n\t\t});\n\t});\n}\n\n// Only busy sessions (streaming, compacting, or pending messages) lose work;\n// idle loaded sessions reload from disk on the fresh daemon.\nconst STARTUP_SESSION_LOSS_COPY: DaemonSessionLossCopy = {\n\tbusyDetail(count) {\n\t\tconst { noun, pronoun } = pluralizeSessions(count);\n\t\treturn `A background service from a different Base Context version is running with ${count} busy ${noun}. Stopping it will terminate ${pronoun}.`;\n\t},\n\tunlistableDetail:\n\t\t\"A background service from a different Base Context version is running and its sessions could not be listed. Stopping it may terminate active sessions.\",\n\tquestion: \"Stop it and continue?\",\n\tnonTtyHint: 'Run \"base-context shutdown\" to stop it, then retry.',\n};\n\n// The promise to keep after awaiting readiness. Wrapped in an object so it\n// survives `await` (which would otherwise flatten a returned Promise to void).\ntype DaemonReadyResult = { ready: Promise<void> | undefined };\n\n// A stale-version daemon couldn't be taken over automatically (busy or stuck).\n// Offer to stop it (default No) and start a fresh daemon, or exit. Returns the\n// fresh ready promise so callers stop re-handling the original rejection.\nasync function takeOverStaleDaemonOrExit(socketPath: string): Promise<DaemonReadyResult> {\n\tconst probe = await probeRunningDaemonSessions(socketPath);\n\tconst confirmed = await confirmDaemonSessionLoss(probe, { force: false, copy: STARTUP_SESSION_LOSS_COPY });\n\tif (!confirmed) {\n\t\t// Non-TTY already printed the reason; at a TTY the user declined.\n\t\tif (process.stdin.isTTY) {\n\t\t\tconsole.error(chalk.dim(\"Cancelled.\"));\n\t\t}\n\t\tprocess.exit(1);\n\t}\n\tif (!(await shutdownDaemonAndWait(socketPath))) {\n\t\tconsole.error(\n\t\t\tchalk.red(`Could not stop the background service on ${socketPath}. Run \"base-context shutdown\" and retry.`),\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\tconst ready = ensureInteractiveDaemonRunning(socketPath);\n\ttry {\n\t\tawait ready;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Could not start the background service: ${message}`));\n\t\tprocess.exit(1);\n\t}\n\treturn { ready };\n}\n\n// Resolves the daemon-ready promise, returning the promise to keep (the same\n// one on success, or the fresh one from a stale-daemon takeover) so repeat\n// calls don't re-handle the original rejection.\nasync function awaitDaemonReady(daemonReady: Promise<void> | undefined): Promise<DaemonReadyResult> {\n\tif (!daemonReady) {\n\t\treturn { ready: daemonReady };\n\t}\n\ttry {\n\t\tawait daemonReady;\n\t\treturn { ready: daemonReady };\n\t} catch (error) {\n\t\tif (error instanceof StaleDaemonError) {\n\t\t\treturn takeOverStaleDaemonOrExit(error.socketPath);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction validateForkFlags(parsed: Args): void {\n\tif (!parsed.fork) return;\n\n\tconst conflictingFlags = [\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\nasync function forkSessionOrExit(sourcePath: string, cwd: string, sessionDir?: string): Promise<SessionManager> {\n\ttry {\n\t\treturn await SessionManager.forkFrom(sourcePath, cwd, sessionDir);\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 getResumeSelector(parsed: Pick<Args, \"resume\">): string | undefined {\n\treturn typeof parsed.resume === \"string\" ? parsed.resume : undefined;\n}\n\nexport async function createSessionManager(\n\tparsed: Args,\n\tcwd: string,\n\tsessionDir: string | undefined,\n\toptions: { readOnlyExisting?: boolean } = {},\n): Promise<SessionManager> {\n\tconst explicitCwdOverride = parsed.cwd ? cwd : undefined;\n\n\tif (parsed.noSession) {\n\t\treturn SessionManager.inMemory();\n\t}\n\n\tif (parsed.fork) {\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);\n\t\t}\n\t}\n\n\tconst resumeSelector = getResumeSelector(parsed);\n\tif (resumeSelector) {\n\t\tconst resolved = await resolveSessionPath(resumeSelector, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\t\treturn options.readOnlyExisting\n\t\t\t\t\t? SessionManager.openReadOnly(resolved.path, sessionDir, explicitCwdOverride)\n\t\t\t\t\t: SessionManager.open(resolved.path, sessionDir, explicitCwdOverride);\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\t\t}\n\t}\n\n\tif (parsed.continue) {\n\t\tif (options.readOnlyExisting) {\n\t\t\tconst recent = findMostRecentSessionForCwd(sessionDir ?? getDefaultSessionDir(cwd), cwd);\n\t\t\treturn recent ? SessionManager.openReadOnly(recent, sessionDir, cwd) : SessionManager.create(cwd, sessionDir);\n\t\t}\n\t\treturn SessionManager.continueRecent(cwd, sessionDir);\n\t}\n\n\treturn SessionManager.create(cwd, sessionDir);\n}\n\nfunction buildSessionOptions(\n\tconfig: AgentSessionRuntimeConfig,\n\tscopedModels: ScopedModel[],\n\thasExistingSession: boolean,\n\tmodelRegistry: ModelRegistry,\n\tsettingsManager: SettingsManager,\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 --model <provider>/<pattern>\n\tif (config.model) {\n\t\tconst resolved = resolveCliModel({\n\t\t\tcliProvider: config.provider,\n\t\t\tcliModel: config.model,\n\t\t\tmodelRegistry,\n\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 (!config.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\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 (!config.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 (!config.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 (config.thinking) {\n\t\toptions.thinkingLevel = config.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 (config.noTools) {\n\t\toptions.noTools = \"all\";\n\t} else if (config.noBuiltinTools) {\n\t\toptions.noTools = \"builtin\";\n\t}\n\tif (config.tools) {\n\t\toptions.tools = [...config.tools];\n\t}\n\tif (config.autonomous) {\n\t\toptions.autonomous = mergeAutonomousConfig(undefined, config.autonomous);\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) ? resolve(cwd, value) : value));\n}\n\nfunction runtimeAutonomousConfigFromArgs(parsed: Args): AgentSessionRuntimeConfig[\"autonomous\"] {\n\tconst hasAutonomousOptions =\n\t\tparsed.autonomous === true ||\n\t\tparsed.autonomousGates !== undefined ||\n\t\tparsed.autonomousGateRetries !== undefined ||\n\t\tparsed.autonomousGateTimeoutMs !== undefined ||\n\t\tparsed.autonomousMaxContinuations !== undefined ||\n\t\tparsed.autonomousMaxTurns !== undefined ||\n\t\tparsed.autonomousMaxTokens !== undefined ||\n\t\tparsed.autonomousTimeoutMs !== undefined;\n\tif (!hasAutonomousOptions) {\n\t\treturn undefined;\n\t}\n\tconst hasGateOptions =\n\t\tparsed.autonomousGates !== undefined ||\n\t\tparsed.autonomousGateRetries !== undefined ||\n\t\tparsed.autonomousGateTimeoutMs !== undefined;\n\treturn {\n\t\tenabled: true,\n\t\tmaxContinuations: parsed.autonomousMaxContinuations,\n\t\tmaxTurns: parsed.autonomousMaxTurns,\n\t\tmaxTokens: parsed.autonomousMaxTokens,\n\t\ttimeoutMs: parsed.autonomousTimeoutMs,\n\t\tgates: hasGateOptions\n\t\t\t? {\n\t\t\t\t\tcommands: parsed.autonomousGates,\n\t\t\t\t\tmaxRetries: parsed.autonomousGateRetries,\n\t\t\t\t\ttimeoutMs: parsed.autonomousGateTimeoutMs,\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n}\n\nfunction runtimeConfigFromArgs(\n\tparsed: Args,\n\tcwd: string,\n\tagentDir: string,\n\tsessionDir: string | undefined,\n\tappMode: AppMode,\n\ttelemetryDisabled?: true,\n): AgentSessionRuntimeConfig {\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionDir,\n\t\tprovider: parsed.provider,\n\t\tmodel: parsed.model,\n\t\tapiKey: parsed.apiKey,\n\t\tsystemPrompt: parsed.systemPrompt,\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tthinking: parsed.thinking,\n\t\tmodels: parsed.models,\n\t\ttools: parsed.tools,\n\t\tnoTools: parsed.noTools,\n\t\tnoBuiltinTools: parsed.noBuiltinTools,\n\t\textensions: resolveCliPaths(cwd, parsed.extensions),\n\t\tnoExtensions: parsed.noExtensions,\n\t\tskills: resolveCliPaths(cwd, parsed.skills),\n\t\tnoSkills: parsed.noSkills,\n\t\tpromptTemplates: resolveCliPaths(cwd, parsed.promptTemplates),\n\t\tnoPromptTemplates: parsed.noPromptTemplates,\n\t\tthemes: resolveCliPaths(cwd, parsed.themes),\n\t\tnoThemes: parsed.noThemes,\n\t\tnoContextFiles: parsed.noContextFiles,\n\t\tautonomous: runtimeAutonomousConfigFromArgs(parsed),\n\t\textensionFlagValues: parsed.unknownFlags.size > 0 ? Object.fromEntries(parsed.unknownFlags.entries()) : undefined,\n\t\texecutionMode: appMode === \"daemon\" ? undefined : appMode,\n\t\ttelemetryDisabled,\n\t\t// Serialized refine for print/json/rpc: the client's appMode is NOT\n\t\t// \"daemon\" here — it's \"print\", \"json\", or \"rpc\". The daemon worker\n\t\t// receives this flag via AgentSessionRuntimeConfig and uses it\n\t\t// instead of its own appMode=\"daemon\".\n\t\tserializedRefine: appMode !== \"interactive\" && appMode !== \"daemon\",\n\t\tinitialGoal: parsed.goal ? { objective: parsed.goal, tokenBudget: parsed.goalTokenBudget } : undefined,\n\t};\n}\n\ninterface PreparedRuntimeServices {\n\tservices: AgentSessionServices;\n\tscopedModels: ScopedModel[];\n\tsessionOptions: CreateAgentSessionOptions;\n\tcliThinkingFromModel: boolean;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nexport function daemonServerDefaultSessionConfig(config: AgentSessionRuntimeConfig): AgentSessionRuntimeConfig {\n\treturn { ...config, initialGoal: undefined };\n}\n\nexport function resolveRuntimeSessionOptions(\n\tsessionOptions: CreateAgentSessionOptions,\n\truntimeSessionOptions?: CreateAgentSessionOptions,\n): CreateAgentSessionOptions {\n\treturn {\n\t\trequestTokenBudget: runtimeSessionOptions?.requestTokenBudget ?? sessionOptions.requestTokenBudget,\n\t\tcontextMode: runtimeSessionOptions?.contextMode ?? sessionOptions.contextMode,\n\t\tmodel: runtimeSessionOptions?.model ?? sessionOptions.model,\n\t\tthinkingLevel: runtimeSessionOptions?.thinkingLevel ?? sessionOptions.thinkingLevel,\n\t\tserviceTier: runtimeSessionOptions?.serviceTier ?? sessionOptions.serviceTier,\n\t\tscopedModels: runtimeSessionOptions?.scopedModels ?? sessionOptions.scopedModels,\n\t\ttools: runtimeSessionOptions?.tools ?? sessionOptions.tools,\n\t\tnoTools: runtimeSessionOptions?.noTools ?? sessionOptions.noTools,\n\t\tcustomTools: runtimeSessionOptions?.customTools ?? sessionOptions.customTools,\n\t\tinitialActiveToolNames: runtimeSessionOptions?.initialActiveToolNames,\n\t\tallowedToolNames: runtimeSessionOptions?.allowedToolNames,\n\t\tincludeGoals: runtimeSessionOptions?.includeGoals,\n\t\tincludeCompactSkill: runtimeSessionOptions?.includeCompactSkill,\n\t\trlmHeartbeatController: runtimeSessionOptions?.rlmHeartbeatController,\n\t\tagentMessageController: runtimeSessionOptions?.agentMessageController,\n\t\tagentObserveController: runtimeSessionOptions?.agentObserveController,\n\t\tautonomous:\n\t\t\t(runtimeSessionOptions?.rlmDepth ?? 0) > 0\n\t\t\t\t? mergeAutonomousConfig(sessionOptions.autonomous, { ...runtimeSessionOptions?.autonomous, enabled: false })\n\t\t\t\t: mergeAutonomousConfig(sessionOptions.autonomous, runtimeSessionOptions?.autonomous),\n\t\trlmDepth: runtimeSessionOptions?.rlmDepth,\n\t\trlmMaxDepth: runtimeSessionOptions?.rlmMaxDepth,\n\t\trlmSessionDir: runtimeSessionOptions?.rlmSessionDir,\n\t\trlmParentNodeId: runtimeSessionOptions?.rlmParentNodeId,\n\t\trlmParentAgent: runtimeSessionOptions?.rlmParentAgent,\n\t\trlmChildAdmission: runtimeSessionOptions?.rlmChildAdmission,\n\t\tsemanticParentSessionId: runtimeSessionOptions?.semanticParentSessionId,\n\t\tsemanticSpawnedByRequestId: runtimeSessionOptions?.semanticSpawnedByRequestId,\n\t\tsubagentRuntimeHost: runtimeSessionOptions?.subagentRuntimeHost,\n\t};\n}\n\n/** The production runtime factory: every daemon-hosted and runtime-hosted session is created through this path. */\nexport function createDefaultRuntimeFactory(\n\truntimeDefaultSessionConfig: AgentSessionRuntimeConfig,\n\textensionFactories?: ExtensionFactory[],\n): CreateAgentSessionRuntimeFactory {\n\treturn async ({\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t\tsessionConfig,\n\t\tsessionOptions: runtimeSessionOptions,\n\t}) => {\n\t\tif (runtimeSessionOptions)\n\t\t\truntimeSessionOptions = { ...runtimeSessionOptions, contextMode: runtimeSessionOptions.contextMode };\n\t\tif (runtimeSessionOptions?.requestTokenBudget) {\n\t\t\truntimeSessionOptions = {\n\t\t\t\t...runtimeSessionOptions,\n\t\t\t\trequestTokenBudget: structuredClone(runtimeSessionOptions.requestTokenBudget),\n\t\t\t};\n\t\t}\n\t\tconst config = mergeAgentSessionRuntimeConfig(runtimeDefaultSessionConfig, sessionConfig);\n\t\tconst prepared = await prepareRuntimeServices({\n\t\t\tconfig,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tsessionManager,\n\t\t\textensionFactories,\n\t\t\tsessionOptionsOverride: runtimeSessionOptions,\n\t\t});\n\t\tconst { services, sessionOptions, diagnostics } = prepared;\n\t\tconst resolvedSessionOptions = resolveRuntimeSessionOptions(sessionOptions, runtimeSessionOptions);\n\n\t\tconst created = await createAgentSessionFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t\tsessionStartEvent,\n\t\t\t...resolvedSessionOptions,\n\t\t\t// Main agents boot their kernel in the background at session creation;\n\t\t\t// subagent sessions (rlmDepth > 0) keep the lazy first-call start.\n\t\t\tprewarmIpythonKernel: true,\n\t\t\t// Read serializedRefine from the merged runtime config (passed\n\t\t\t// from the JSON/print client through AgentSessionRuntimeConfig)\n\t\t\t// so it survives the daemon worker's appMode=\"daemon\" context.\n\t\t\tserializedRefine: config.serializedRefine ?? false,\n\t\t\texecutionMode: config.executionMode,\n\t\t\ttelemetryDisabled: config.telemetryDisabled,\n\t\t\t// Only seed initial goal for top-level sessions (rlmDepth 0).\n\t\t\tinitialGoal: (runtimeSessionOptions?.rlmDepth ?? 0) === 0 ? config.initialGoal : undefined,\n\t\t});\n\t\ttry {\n\t\t\tconst cliThinkingOverride = config.thinking !== undefined || prepared.cliThinkingFromModel;\n\t\t\tif (created.session.model && cliThinkingOverride) {\n\t\t\t\tawait created.session.setThinkingLevel(created.session.thinkingLevel);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait created.session.disposeAsync().catch(() => undefined);\n\t\t\tthrow error;\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}\n\nasync function prepareRuntimeServices(options: {\n\tconfig: AgentSessionRuntimeConfig;\n\tcwd: string;\n\tagentDir: string;\n\tsessionManager: SessionManager;\n\textensionFactories?: ExtensionFactory[];\n\tsessionOptionsOverride?: CreateAgentSessionOptions;\n}): Promise<PreparedRuntimeServices> {\n\tconst { config, sessionManager } = options;\n\tconst effectiveAgentDir = config.agentDir ?? options.agentDir;\n\tconst authStorage = AuthStorage.create(join(effectiveAgentDir, \"auth.json\"), {\n\t\tusePrimeCliConfig: effectiveAgentDir === options.agentDir,\n\t});\n\tconst services = await createAgentSessionServices({\n\t\tcwd: options.cwd,\n\t\tagentDir: effectiveAgentDir,\n\t\tauthStorage,\n\t\textensionFlagValues: new Map(Object.entries(config.extensionFlagValues ?? {})),\n\t\t// Subagents share the parent's Herdr pane; their own reporter would race\n\t\t// the parent's and a subagent quit would release the still-active pane.\n\t\tnoBuiltinHerdrReporter: (options.sessionOptionsOverride?.rlmDepth ?? 0) > 0,\n\t\ttelemetryDisabled: config.telemetryDisabled,\n\t\tresourceLoaderOptions: {\n\t\t\tadditionalExtensionPaths: config.extensions,\n\t\t\tadditionalSkillPaths: config.skills,\n\t\t\tadditionalPromptTemplatePaths: config.promptTemplates,\n\t\t\tadditionalThemePaths: config.themes,\n\t\t\tnoExtensions: config.noExtensions,\n\t\t\tnoSkills: config.noSkills,\n\t\t\tnoPromptTemplates: config.noPromptTemplates,\n\t\t\tnoThemes: config.noThemes,\n\t\t\tnoContextFiles: config.noContextFiles,\n\t\t\tsystemPrompt: config.systemPrompt,\n\t\t\tappendSystemPrompt: config.appendSystemPrompt,\n\t\t\textensionFactories: options.extensionFactories,\n\t\t},\n\t});\n\tconst { settingsManager, modelRegistry, resourceLoader } = services;\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [\n\t\t...services.diagnostics,\n\t\t...collectSettingsDiagnostics(settingsManager, \"runtime creation\"),\n\t\t...resourceLoader.getExtensions().errors.map(({ path, error }) => ({\n\t\t\ttype: \"error\" as const,\n\t\t\tmessage: `Failed to load extension \"${path}\": ${error}`,\n\t\t})),\n\t];\n\n\tconst modelPatterns = config.models ?? settingsManager.getEnabledModels();\n\tconst scopedModels =\n\t\tmodelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];\n\tconst hasExistingSession = sessionManager.supportsCapturedHistoryReads()\n\t\t? await sessionManager.readBranchHistory(async (view) => (await view.branchBootstrap()).hasContextMessages)\n\t\t: (\n\t\t\t\tawait readSessionBootstrap(sessionManager, settingsManager.getCanonicalContextLimits(), {\n\t\t\t\t\tincludeMessages: false,\n\t\t\t\t})\n\t\t\t).hasExistingSession;\n\tconst {\n\t\toptions: sessionOptions,\n\t\tcliThinkingFromModel,\n\t\tdiagnostics: sessionOptionDiagnostics,\n\t} = buildSessionOptions(config, scopedModels, hasExistingSession, modelRegistry, settingsManager);\n\tdiagnostics.push(...sessionOptionDiagnostics);\n\n\tconst effectiveSessionModel = options.sessionOptionsOverride?.model ?? sessionOptions.model;\n\tif (config.apiKey) {\n\t\tif (!effectiveSessionModel) {\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: \"--api-key requires a model to be specified via --model, --provider/--model, or --models\",\n\t\t\t});\n\t\t} else {\n\t\t\tauthStorage.setRuntimeApiKey(effectiveSessionModel.provider, config.apiKey);\n\t\t}\n\t}\n\n\treturn {\n\t\tservices,\n\t\tscopedModels,\n\t\tsessionOptions,\n\t\tcliThinkingFromModel,\n\t\tdiagnostics,\n\t};\n}\n\nasync function resolvePreparedStartupModel(options: {\n\tprepared: PreparedRuntimeServices;\n\tsessionManager: SessionManager;\n}): Promise<{ model: Model<Api> | undefined; modelFallbackMessage: string | undefined }> {\n\tconst { prepared, sessionManager } = options;\n\tconst { modelRegistry, settingsManager } = prepared.services;\n\tconst { context: existingSession, hasExistingSession } = await readSessionBootstrap(\n\t\tsessionManager,\n\t\tsettingsManager.getCanonicalContextLimits(),\n\t\t{ includeMessages: false },\n\t);\n\n\tlet model = prepared.sessionOptions.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: prepared.scopedModels,\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\treturn { model, modelFallbackMessage };\n}\n\nasync function promptForMissingSessionCwd(\n\tissue: SessionCwdIssue,\n\tsettingsManager: SettingsManager,\n): Promise<string | undefined> {\n\tinitTheme(settingsManager.getTheme());\n\tsetKeybindings(KeybindingsManager.create());\n\n\treturn new Promise((resolve) => {\n\t\tconst ui = new TUI(\n\t\t\tnew ProcessTerminal(),\n\t\t\tsettingsManager.getShowHardwareCursor(),\n\t\t\tassertProductStatePath(join(getAgentDir(), \"tui\")),\n\t\t);\n\t\tui.setClearOnShrink(settingsManager.getClearOnShrink());\n\n\t\tlet settled = false;\n\t\tconst finish = (result: string | 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\tformatMissingSessionCwdPrompt(issue),\n\t\t\t[\"Continue\", \"Cancel\"],\n\t\t\t(option) => finish(option === \"Continue\" ? issue.fallbackCwd : undefined),\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\nfunction getDaemonSummaryActiveSessionId(summary: SessionSummary): string {\n\treturn summary.activeSessionId ?? summary.id;\n}\n\nfunction isUnknownActiveSessionError(message: string): boolean {\n\treturn message.startsWith(\"Unknown active session:\");\n}\n\nasync function findActiveDaemonSessionSummary(\n\tsocketPath: string,\n\tselector: string,\n): Promise<SessionSummary | undefined> {\n\tconst client = new DaemonClient(socketPath);\n\tawait client.connect(250);\n\n\ttry {\n\t\tconst response = await client.request({ type: \"get_state\", activeSessionId: selector }, 3000);\n\t\tif (!response.success) {\n\t\t\tif (isUnknownActiveSessionError(response.error)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tthrow new Error(response.error);\n\t\t}\n\t\tif (!isDaemonSessionSummary(response.data)) {\n\t\t\tthrow new Error(\"Daemon returned an invalid active session summary\");\n\t\t}\n\t\treturn response.data;\n\t} finally {\n\t\tclient.close();\n\t}\n}\n\nasync function createSessionManagerForActiveDaemonSummary(\n\tsummary: SessionSummary,\n\tfallbackCwd: string,\n): Promise<SessionManager> {\n\tconst cwd = summary.cwd || fallbackCwd;\n\tif (summary.sessionFile) {\n\t\ttry {\n\t\t\treturn await SessionManager.openReadOnly(summary.sessionFile, undefined, cwd);\n\t\t} catch {\n\t\t\treturn SessionManager.inMemory(cwd);\n\t\t}\n\t}\n\treturn SessionManager.inMemory(cwd);\n}\n\nfunction getInteractiveDaemonSessionPath(parsed: Args, sessionManager: SessionManager): string | undefined {\n\tif (!parsed.resume && !parsed.continue && !parsed.fork) {\n\t\treturn undefined;\n\t}\n\treturn sessionManager.getSessionFile();\n}\n\nexport function findActiveDaemonSessionSummaryForSessionFile(\n\tsummaries: readonly SessionSummary[],\n\tsessionPath: string,\n): SessionSummary | undefined {\n\tconst resolvedSessionPath = canonicalSessionPath(sessionPath);\n\treturn summaries.find(\n\t\t(summary) =>\n\t\t\tsummary.activeSessionId !== undefined &&\n\t\t\tsummary.sessionFile !== undefined &&\n\t\t\tcanonicalSessionPath(summary.sessionFile) === resolvedSessionPath,\n\t);\n}\n\nasync function createDaemonClientConnection(options: {\n\tsocketPath: string;\n\tconfig: AgentSessionRuntimeConfig;\n\tsessionPath?: string;\n\tcontinueRecent?: boolean;\n\tactiveSessionId?: string;\n\tclientOwned?: boolean;\n\tnoSession?: boolean;\n\tsupportsExtensionUi?: boolean;\n}): Promise<{ connection: DaemonAgentConnection; summary: SessionSummary }> {\n\t// Caller must have awaited ensureInteractiveDaemonRunning for this socket.\n\tconst client = new DaemonClient(options.socketPath);\n\tawait client.connect();\n\n\ttry {\n\t\tconst attach = async (summary: SessionSummary) => {\n\t\t\tconst connection = await DaemonAgentConnection.attach(client, getDaemonSummaryActiveSessionId(summary), {\n\t\t\t\tcloseClientOnDispose: true,\n\t\t\t\tsendClientEnv: true,\n\t\t\t\townedSession: options.clientOwned,\n\t\t\t\townedSessionRecoveryConfig: options.clientOwned ? options.config : undefined,\n\t\t\t\tsupportsExtensionUi: options.supportsExtensionUi,\n\t\t\t\trecoverDaemon: () => ensureInteractiveDaemonRunning(options.socketPath),\n\t\t\t\ttelemetryDisabled: options.config.telemetryDisabled,\n\t\t\t});\n\t\t\treturn { connection, summary };\n\t\t};\n\n\t\tif (options.activeSessionId) {\n\t\t\tconst summary = await findAttachedDaemonSessionSummary(client, options.activeSessionId);\n\t\t\treturn await attach(summary);\n\t\t}\n\n\t\tif (options.sessionPath && !options.clientOwned) {\n\t\t\tconst activeSummary = findActiveDaemonSessionSummaryForSessionFile(\n\t\t\t\tawait listActiveDaemonSessionSummaries(client),\n\t\t\t\toptions.sessionPath,\n\t\t\t);\n\t\t\tif (activeSummary && activeSummary.workerState !== \"failed\") {\n\t\t\t\treturn await attach(activeSummary);\n\t\t\t}\n\t\t}\n\t\tif (options.clientOwned) {\n\t\t\tawait client.waitForHello();\n\t\t\tif (!client.supportsServerCapability(\"client_owned_sessions\")) {\n\t\t\t\tthrow new DaemonCapabilityUnavailableError(\"create\", \"client_owned_sessions\");\n\t\t\t}\n\t\t}\n\n\t\tconst response = await client.request({\n\t\t\ttype: \"create\",\n\t\t\tconfig: options.config,\n\t\t\tsessionPath: options.sessionPath,\n\t\t\tcontinueRecent: options.continueRecent,\n\t\t\tnoSession: options.noSession,\n\t\t\tenv: collectDaemonClientEnv(),\n\t\t\tlifecycle: options.clientOwned ? \"client_owned\" : \"resident\",\n\t\t\tlaunchEnv: collectDaemonLaunchEnv(),\n\t\t});\n\t\tif (!response.success) {\n\t\t\tthrow deserializeDaemonCreateError(response);\n\t\t}\n\t\tif (!isDaemonSessionSummary(response.data)) {\n\t\t\tthrow new Error(\"Daemon returned an invalid create response\");\n\t\t}\n\t\tconst summary = response.data;\n\t\treturn await attach(summary);\n\t} catch (error) {\n\t\tclient.close();\n\t\tthrow error;\n\t}\n}\n\nasync function findAttachedDaemonSessionSummary(\n\tclient: DaemonClient,\n\tactiveSessionId: string,\n): Promise<SessionSummary> {\n\tconst response = await client.request({ type: \"get_state\", activeSessionId });\n\tif (!response.success) {\n\t\tthrow new Error(response.error);\n\t}\n\tif (!isDaemonSessionSummary(response.data)) {\n\t\tthrow new Error(\"Daemon returned an invalid active session summary\");\n\t}\n\treturn response.data;\n}\n\nexport interface MainOptions {\n\textensionFactories?: ExtensionFactory[];\n}\n\nexport async function main(args: string[], options?: MainOptions) {\n\tresetTimings();\n\tif (isDaemonWorkerProcess()) {\n\t\twaitForDaemonWorkerStartupGate();\n\t}\n\tinstallFileLogSink();\n\tif (isDaemonCatalogProcess()) {\n\t\tawait runDaemonCatalogProcess();\n\t\treturn;\n\t}\n\t// Client and daemon are separate processes; both need these in their registry.\n\tregisterBuiltinMcpOAuthProviders();\n\tconst offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag(process.env.BASE_CONTEXT_OFFLINE);\n\tif (offlineMode) {\n\t\tprocess.env.BASE_CONTEXT_OFFLINE = \"1\";\n\t\tprocess.env.BASE_CONTEXT_SKIP_VERSION_CHECK = \"1\";\n\t}\n\n\tconst publicCommand = await handlePublicCommand(args);\n\tif (publicCommand.handled) {\n\t\treturn;\n\t}\n\targs = publicCommand.args;\n\n\tif (await handleConfigCommand(args)) {\n\t\treturn;\n\t}\n\n\tconst explicitAgentsView = publicCommand.explicitAgentsView;\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\tconst appMode = resolveAppMode(parsed, process.stdin.isTTY);\n\n\tif (shouldRejectNonInteractiveAttach(publicCommand.attachAgent, appMode)) {\n\t\tconsole.error(chalk.red(\"Error: attach requires an interactive terminal\"));\n\t\tprocess.exit(1);\n\t}\n\tif (shouldRejectNonInteractiveBareResume(parsed.resume, appMode)) {\n\t\tconsole.error(chalk.red(\"Error: --resume without a session selector requires an interactive terminal\"));\n\t\tprocess.exit(1);\n\t}\n\tsetLogContext({ mode: appMode });\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\tif (parsed.help) {\n\t\tconsole.log(formatTopLevelHelp());\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.mode === \"daemon\") && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC or daemon mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tvalidateForkFlags(parsed);\n\n\tconst cwd = parsed.cwd ? resolve(expandTildePath(parsed.cwd)) : process.cwd();\n\tif (parsed.cwd) {\n\t\ttry {\n\t\t\tprocess.chdir(cwd);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(chalk.red(`Error: Cannot use cwd ${cwd}: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (parsed.daemonSocket) {\n\t\t// After --cwd so a relative socket path resolves against the requested directory.\n\t\tparsed.daemonSocket = normalizeSocketPath(parsed.daemonSocket);\n\t}\n\n\t// Run migrations (pass cwd for project-local migrations)\n\tconst { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);\n\ttime(\"runMigrations\");\n\n\tconst agentDir = getAgentDir();\n\tconst startupSettingsManager = SettingsManager.create(cwd, agentDir);\n\treportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n\tconst startupBenchmark = isTruthyEnvFlag(process.env.BASE_CONTEXT_STARTUP_BENCHMARK);\n\tif (startupBenchmark && appMode !== \"interactive\") {\n\t\tconsole.error(chalk.red(\"Error: BASE_CONTEXT_STARTUP_BENCHMARK only supports interactive mode\"));\n\t\tprocess.exit(1);\n\t}\n\t// Programmatic factories are process-local functions and cannot be serialized to a daemon worker.\n\tconst hasProcessLocalExtensionFactories = (options?.extensionFactories?.length ?? 0) > 0;\n\tconst useDaemonClient = shouldUseDaemonClientRuntime({\n\t\tappMode,\n\t\tstartupBenchmark,\n\t\tnoSession: parsed.noSession,\n\t\tlistModels: parsed.listModels,\n\t\townedSessionWorker: isOwnedSessionWorkerProcess(),\n\t\thasProcessLocalExtensionFactories,\n\t});\n\tconst useDaemonInteractive = useDaemonClient && appMode === \"interactive\";\n\n\t// Decide the final runtime cwd before creating cwd-bound runtime services.\n\t// --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 sessionDir =\n\t\t(parsed.sessionDir ? expandTildePath(parsed.sessionDir) : undefined) ??\n\t\tgetSessionDirEnvOverride() ??\n\t\tstartupSettingsManager.getSessionDir();\n\tconst daemonSocketPath = parsed.daemonSocket ?? defaultDaemonSocketPath();\n\t// Kick off daemon spawn/readiness immediately so it overlaps session-manager\n\t// and runtime-services preparation; attach only connects to an existing daemon.\n\tlet daemonReady = shouldEnsureInteractiveDaemonForStartup(useDaemonClient, publicCommand.attachAgent)\n\t\t? ensureInteractiveDaemonRunning(daemonSocketPath)\n\t\t: undefined;\n\t// Errors are rethrown at the await sites below; this only avoids an unhandled\n\t// rejection if startup exits before reaching them.\n\tdaemonReady?.catch(() => {});\n\tconst resumeSelector = getResumeSelector(parsed);\n\tconst shouldLookupDaemonActiveSession = shouldEnsureDaemonBeforeActiveSessionLookup({\n\t\tuseDaemonInteractive,\n\t\tresumeSelector,\n\t\texplicitAttach: publicCommand.attachAgent !== undefined,\n\t});\n\tif (shouldLookupDaemonActiveSession && daemonReady) {\n\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t}\n\tlet activeDaemonSessionSummary: SessionSummary | undefined;\n\tif (shouldLookupDaemonActiveSession && resumeSelector) {\n\t\ttry {\n\t\t\tactiveDaemonSessionSummary = await findActiveDaemonSessionSummaryForInteractiveStartup(\n\t\t\t\tdaemonSocketPath,\n\t\t\t\tresumeSelector,\n\t\t\t\t{ fallbackOnError: !publicCommand.attachAgent },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(chalk.red(`Error: Could not look up active agent '${resumeSelector}': ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (publicCommand.attachAgent && !activeDaemonSessionSummary) {\n\t\tconsole.error(chalk.red(`Error: No active agent found matching '${publicCommand.attachAgent}'`));\n\t\tprocess.exit(1);\n\t}\n\tlet sessionManager: SessionManager;\n\tif (activeDaemonSessionSummary) {\n\t\tsessionManager = await createSessionManagerForActiveDaemonSummary(activeDaemonSessionSummary, cwd);\n\t} else if (\n\t\t(useDaemonInteractive || (appMode === \"daemon\" && parsed.listModels === undefined)) &&\n\t\tshouldUseEphemeralSessionManagerForDaemonInteractive({\n\t\t\tresume: parsed.resume,\n\t\t\tcontinue: parsed.continue,\n\t\t\tfork: parsed.fork,\n\t\t})\n\t) {\n\t\tsessionManager = SessionManager.inMemory(cwd);\n\t} else {\n\t\ttry {\n\t\t\tsessionManager = await createSessionManager(parsed, cwd, sessionDir, {\n\t\t\t\treadOnlyExisting: useDaemonClient || (appMode === \"daemon\" && parsed.listModels === undefined),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof SessionSelectorError)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst suggestion =\n\t\t\t\terror instanceof SessionSelectorNotFoundError && error.suggestion\n\t\t\t\t\t? ` Did you mean '${error.suggestion}'?`\n\t\t\t\t\t: \"\";\n\t\t\tconsole.error(chalk.red(`Error: ${error.message}.${suggestion}`));\n\t\t\tconsole.error(chalk.dim(`Open ${APP_NAME} and press left-arrow to browse sessions.`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\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\tawait sessionManager.close();\n\t\t\tsessionManager = useDaemonClient\n\t\t\t\t? await SessionManager.openReadOnly(missingSessionCwdIssue.sessionFile!, sessionDir, selectedCwd)\n\t\t\t\t: await SessionManager.open(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\ttime(\"createSessionManager\");\n\n\tconst telemetrySettingsManager =\n\t\tsessionManager.getCwd() === cwd\n\t\t\t? startupSettingsManager\n\t\t\t: SettingsManager.create(sessionManager.getCwd(), agentDir);\n\tconst telemetryDisabled = isTelemetryEnabled(telemetrySettingsManager) ? undefined : true;\n\tconst defaultSessionConfig = runtimeConfigFromArgs(\n\t\tparsed,\n\t\tsessionManager.getCwd(),\n\t\tagentDir,\n\t\tsessionDir,\n\t\tappMode,\n\t\ttelemetryDisabled,\n\t);\n\t// Verifier/headless clients pass initialGoal in each create request. The long-lived\n\t// daemon fallback must not seed that goal into unrelated future sessions.\n\tconst daemonDefaultSessionConfig = daemonServerDefaultSessionConfig(defaultSessionConfig);\n\tconst runtimeDefaultSessionConfig = appMode === \"daemon\" ? daemonDefaultSessionConfig : defaultSessionConfig;\n\t// Daemon clients keep only local views; release the CLI writer before a worker opens this source.\n\tif (useDaemonClient || (appMode === \"daemon\" && parsed.listModels === undefined)) {\n\t\tawait sessionManager.close();\n\t}\n\tconst createRuntime = createDefaultRuntimeFactory(runtimeDefaultSessionConfig, options?.extensionFactories);\n\ttime(\"createRuntime\");\n\t// Daemon mode never uses the bootstrap runtime, so skip the heavy\n\t// createAgentSessionRuntime below and start listening immediately; sessions\n\t// are created on demand through the daemon protocol via createRuntime.\n\t// --list-models still takes the full path to print and exit.\n\tif (appMode === \"daemon\" && parsed.listModels === undefined) {\n\t\tprintTimings();\n\t\tif (isDaemonWorkerProcess()) {\n\t\t\tawait runDaemonMode({\n\t\t\t\tsocketPath: parsed.daemonSocket,\n\t\t\t\tdefaultSessionConfig: daemonDefaultSessionConfig,\n\t\t\t\tcreateRuntime,\n\t\t\t\tworker: {\n\t\t\t\t\tauthenticationToken: requireDaemonWorkerAuthenticationToken(),\n\t\t\t\t\tworkerInstanceId: daemonWorkerInstanceId(),\n\t\t\t\t\trestoreActiveSessionId: process.env[DAEMON_WORKER_ACTIVE_SESSION_ID_ENV],\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tawait runDaemonSupervisorMode({\n\t\t\t\tsocketPath: parsed.daemonSocket,\n\t\t\t\tdefaultSessionConfig: daemonDefaultSessionConfig,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\tif (useDaemonInteractive) {\n\t\tconst prepared = await prepareRuntimeServices({\n\t\t\tconfig: defaultSessionConfig,\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tagentDir,\n\t\t\tsessionManager,\n\t\t\textensionFactories: options?.extensionFactories,\n\t\t});\n\t\tconst { services, scopedModels } = prepared;\n\t\tconst { settingsManager } = services;\n\n\t\tconst startupModel = await resolvePreparedStartupModel({ prepared, sessionManager });\n\n\t\tconst stdinContent = await readPipedStdin();\n\t\ttime(\"readPipedStdin\");\n\n\t\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\t\tparsed,\n\t\t\tsettingsManager.getImageAutoResize(),\n\t\t\tstdinContent,\n\t\t);\n\t\ttime(\"prepareInitialMessage\");\n\t\tinitTheme(settingsManager.getTheme(), true);\n\t\ttime(\"initTheme\");\n\n\t\tif (deprecationWarnings.length > 0) {\n\t\t\tawait showDeprecationWarnings(deprecationWarnings);\n\t\t}\n\n\t\treportDiagnostics(prepared.diagnostics);\n\t\tif (prepared.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\t\tprocess.exit(1);\n\t\t}\n\t\ttime(\"prepareInteractiveServices\");\n\n\t\tif (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst promptStashStore = new ClientPromptStashStore();\n\t\tconst daemonUiServices = createInteractiveModeUiServicesFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t});\n\t\tconst launchAgentsView = async (initialSession?: SessionSummary, initialScopeKey?: AgentsViewScopeKey) => {\n\t\t\tawait runAgentsViewMode({\n\t\t\t\tsocketPath: daemonSocketPath,\n\t\t\t\tconfig: defaultSessionConfig,\n\t\t\t\tuiServices: daemonUiServices,\n\t\t\t\trecoverDaemon: () => ensureInteractiveDaemonRunning(daemonSocketPath),\n\t\t\t\tcreateUiServicesForSession: async (summary) => {\n\t\t\t\t\tconst attachedSessionManager = await createSessionManagerForActiveDaemonSummary(\n\t\t\t\t\t\tsummary,\n\t\t\t\t\t\tsessionManager.getCwd(),\n\t\t\t\t\t);\n\t\t\t\t\tconst attachedPrepared = await prepareRuntimeServices({\n\t\t\t\t\t\tconfig: mergeAgentSessionRuntimeConfig(defaultSessionConfig, {\n\t\t\t\t\t\t\tcwd: attachedSessionManager.getCwd(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tcwd: attachedSessionManager.getCwd(),\n\t\t\t\t\t\tagentDir,\n\t\t\t\t\t\tsessionManager: attachedSessionManager,\n\t\t\t\t\t\textensionFactories: options?.extensionFactories,\n\t\t\t\t\t});\n\t\t\t\t\treturn createInteractiveModeUiServicesFromServices({\n\t\t\t\t\t\tservices: attachedPrepared.services,\n\t\t\t\t\t\tsessionManager: attachedSessionManager,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tmigratedProviders,\n\t\t\t\tmodelFallbackMessage: startupModel.modelFallbackMessage,\n\t\t\t\tpromptStashStore,\n\t\t\t\tstartupModelId: startupModel.model?.id,\n\t\t\t\tinitialSession,\n\t\t\t\tinitialScopeKey,\n\t\t\t\tverbose: parsed.verbose,\n\t\t\t});\n\t\t};\n\t\tif (\n\t\t\tshouldOpenAgentsViewForDaemonInteractive({\n\t\t\t\tuseDaemonInteractive: useDaemonInteractive && !parsed.noSession,\n\t\t\t\texplicitAgentsView,\n\t\t\t\tneedsOnboarding: shouldRunOnboarding({\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\tmodelRegistry: services.modelRegistry,\n\t\t\t\t\tmodel: startupModel.model,\n\t\t\t\t}),\n\t\t\t\tresume: parsed.resume,\n\t\t\t\tcontinue: parsed.continue,\n\t\t\t\tfork: parsed.fork,\n\t\t\t})\n\t\t) {\n\t\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t\t\tawait preloadCodeHighlighter();\n\t\t\tprintTimings();\n\t\t\tawait launchAgentsView();\n\t\t\treturn;\n\t\t}\n\n\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t\t// A fresh default chat opens a real but message-less session; the lifecycle\n\t\t// axis treats it as a draft (hidden, discarded on detach if never used), so\n\t\t// no DeferredAgentConnection is needed to avoid creating it up front.\n\t\tconst isFreshDefaultSession =\n\t\t\t!activeDaemonSessionSummary && !getInteractiveDaemonSessionPath(parsed, sessionManager);\n\t\tlet connection: DaemonAgentConnection;\n\t\tlet summary: SessionSummary;\n\t\ttry {\n\t\t\t({ connection, summary } = await createDaemonClientConnection({\n\t\t\t\tsocketPath: daemonSocketPath,\n\t\t\t\tconfig: defaultSessionConfig,\n\t\t\t\tactiveSessionId: activeDaemonSessionSummary\n\t\t\t\t\t? getDaemonSummaryActiveSessionId(activeDaemonSessionSummary)\n\t\t\t\t\t: undefined,\n\t\t\t\tsessionPath: getInteractiveDaemonSessionPath(parsed, sessionManager),\n\t\t\t\tclientOwned: parsed.noSession,\n\t\t\t\tnoSession: parsed.noSession,\n\t\t\t\tsupportsExtensionUi: true,\n\t\t\t}));\n\t\t} catch (error) {\n\t\t\tif (error instanceof DaemonSessionCreateError) {\n\t\t\t\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst agentConnection: AgentConnection = connection;\n\t\tconst attachModelFallbackMessage = isFreshDefaultSession\n\t\t\t? startupModel.modelFallbackMessage\n\t\t\t: resolveAttachModelFallbackMessage(summary, startupModel.modelFallbackMessage);\n\n\t\tconst interactiveMode = new InteractiveMode({\n\t\t\tagentConnection,\n\t\t\tdaemonSocketPath,\n\t\t\tuiServices: daemonUiServices,\n\t\t\tpromptStashStore,\n\t\t\tpromptStashSessionId: summary.sessionId,\n\t\t\tbindLocalSessionExtensions: false,\n\t\t\tmigratedProviders,\n\t\t\tmodelFallbackMessage: attachModelFallbackMessage,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tverbose: parsed.verbose,\n\t\t\t// Resumed/attached daemon sessions are part of the same fleet; left\n\t\t\t// arrow takes them to the agents view like any other session. The agents\n\t\t\t// view was not rendered here, so we intentionally leave\n\t\t\t// agentsViewOwnsStartupNotices unset and let the in-session fallback run.\n\t\t\treturnToAgentsView: !parsed.noSession,\n\t\t\tsessionDepth: summary.rlmDepth,\n\t\t\t// Direct launch has only the attached summary; the live+passive+saved\n\t\t\t// unified catalog index is not built until the agents view opens. Retained\n\t\t\t// child snapshots augment this running-child fallback inside chat.\n\t\t\tsessionHasChildren: summary.hasRunningRlmChildren === true,\n\t\t});\n\n\t\tawait preloadCodeHighlighter();\n\t\tprintTimings();\n\t\tconst interactiveResult = await interactiveMode.run();\n\t\tif (parsed.noSession) {\n\t\t\treturn;\n\t\t}\n\t\tconst returnedSummary = {\n\t\t\t...summary,\n\t\t\t...interactiveResult.source,\n\t\t\tid: interactiveResult.source.activeSessionId ?? summary.id,\n\t\t};\n\t\tconst initialScopeKey =\n\t\t\tinteractiveResult.type === \"scoped_agents_view\"\n\t\t\t\t? {\n\t\t\t\t\t\tsessionId: interactiveResult.source.sessionId,\n\t\t\t\t\t\tactiveSessionId: interactiveResult.source.activeSessionId,\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\tawait launchAgentsView(returnedSummary, initialScopeKey);\n\t\treturn;\n\t}\n\tif (useDaemonClient) {\n\t\tconst settingsManager = SettingsManager.create(sessionManager.getCwd(), agentDir);\n\t\tlet stdinContent: string | undefined;\n\t\tif (appMode !== \"rpc\" && appMode !== \"acp\") {\n\t\t\tstdinContent = await readPipedStdin();\n\t\t}\n\t\ttime(\"readPipedStdin\");\n\t\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\t\tparsed,\n\t\t\tsettingsManager.getImageAutoResize(),\n\t\t\tstdinContent,\n\t\t);\n\t\ttime(\"prepareInitialMessage\");\n\t\tinitTheme(settingsManager.getTheme(), false);\n\t\ttime(\"initTheme\");\n\n\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t\tlet connection: DaemonAgentConnection;\n\t\tlet summary: SessionSummary;\n\t\ttry {\n\t\t\t({ connection, summary } = await createDaemonClientConnection({\n\t\t\t\tsocketPath: daemonSocketPath,\n\t\t\t\tconfig: defaultSessionConfig,\n\t\t\t\tsessionPath: parsed.noSession ? undefined : sessionManager.getSessionFile(),\n\t\t\t\tcontinueRecent: parsed.continue,\n\t\t\t\tclientOwned: isClientOwnedDaemonSession(appMode, parsed.noSession),\n\t\t\t\tnoSession: parsed.noSession,\n\t\t\t\tsupportsExtensionUi: appMode === \"rpc\",\n\t\t\t}));\n\t\t} catch (error) {\n\t\t\tif (error instanceof SessionAlreadyActiveError || error instanceof DaemonSessionCreateError) {\n\t\t\t\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst diagnostics = summary.diagnostics ?? [];\n\t\treportDiagnostics(diagnostics);\n\t\tif (diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\t\tawait connection.dispose();\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!summary.model) {\n\t\t\tconsole.error(chalk.red(summary.modelFallbackMessage ?? formatNoModelsAvailableMessage()));\n\t\t\tawait connection.dispose();\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tprintTimings();\n\t\tif (appMode === \"rpc\") {\n\t\t\treturn await runRpcModeWithConnection(connection, parsed.rpcProtocolVersion!);\n\t\t}\n\t\tif (appMode === \"acp\") {\n\t\t\treturn await runAcpModeWithConnection(connection);\n\t\t}\n\t\tconst exitCode = await runPrintModeWithConnection(connection, {\n\t\t\tmode: toPrintOutputMode(appMode),\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\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\tlet runtime: AgentSessionRuntime;\n\ttry {\n\t\truntime = await createAgentSessionRuntime(createRuntime, {\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tagentDir,\n\t\t\tsessionManager,\n\t\t\tsessionConfig: defaultSessionConfig,\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof SessionAlreadyActiveError) {\n\t\t\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tthrow error;\n\t}\n\tconst { services, session, modelFallbackMessage } = runtime;\n\tinstallOwnedSessionRecoveryTracking(runtime);\n\tconst { settingsManager, modelRegistry } = services;\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/daemon modes which use other transports\n\tlet stdinContent: string | undefined;\n\tif (appMode !== \"rpc\" && appMode !== \"acp\" && appMode !== \"daemon\") {\n\t\tstdinContent = await readPipedStdin();\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\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\tconst scopedModels = [...session.scopedModels];\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\" && appMode !== \"daemon\" && !session.model) {\n\t\tconsole.error(chalk.red(formatNoModelsAvailableMessage()));\n\t\tprocess.exit(1);\n\t}\n\n\tif (appMode === \"rpc\") {\n\t\tprintTimings();\n\t\tawait runRpcMode(runtime, parsed.rpcProtocolVersion!);\n\t} else if (appMode === \"acp\") {\n\t\tprintTimings();\n\t\tawait runAcpMode(runtime);\n\t} else if (appMode === \"interactive\") {\n\t\tif (explicitAgentsView || parsed.resume === true) {\n\t\t\tconsole.error(chalk.yellow(\"Warning: the agents view needs the daemon; opening a normal chat instead\"));\n\t\t}\n\t\tif (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst interactiveMode = new InteractiveMode({\n\t\t\tagentConnection: new InProcessAgentConnection(runtime),\n\t\t\tlocalSessionHost: createInteractiveModeLocalSessionHost(runtime),\n\t\t\tpromptStashStore: new ClientPromptStashStore(),\n\t\t\tpromptStashSessionId: session.sessionId,\n\t\t\tbindLocalSessionExtensions: true,\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\tawait preloadCodeHighlighter();\n\t\tprintTimings();\n\t\tawait interactiveMode.run();\n\t} else {\n\t\tprintTimings();\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});\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;AAQH,OAAO,EAAE,KAAK,IAAI,EAAwB,MAAM,eAAe,CAAC;AAuBhE,OAAO,EACN,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAG9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEN,KAAK,gCAAgC,EAErC,MAAM,iCAAiC,CAAC;AAUzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAMnE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAS/D,OAAO,EAAqD,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAc9G,OAAO,EAuBN,KAAK,cAAc,EACnB,MAAM,kBAAkB,CAAC;AAsD1B,MAAM,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAC5C,0EAA0E;AAC1E,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE5C,wBAAgB,gCAAgC,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAE3G;AAED,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAEjH;AAyBD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAEzF;AAGD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,kBAAkB,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAKtG;AAED,MAAM,WAAW,2BAA2B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,gCAAgC,GAAG,2BAA2B,CAAC;AAE3E,8EAA8E;AAC9E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAOxF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAInF;AAED,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,2BAA2B,GAAG;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iCAAiC,CAAC,EAAE,OAAO,CAAC;CAC5C,GACC,OAAO,CAET;AAED,wBAAgB,uCAAuC,CACtD,oBAAoB,EAAE,OAAO,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAET;AAED,MAAM,WAAW,yBAAyB;IACzC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,wCAAwC,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAWpG;AAED,MAAM,WAAW,uCAAuC;IACvD,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAgB,oDAAoD,CACnE,OAAO,EAAE,uCAAuC,GAC9C,OAAO,CAOT;AAED,MAAM,WAAW,iCAAiC;IACjD,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,2CAA2C,CAAC,OAAO,EAAE,iCAAiC,GAAG,OAAO,CAM/G;AAsJD,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,IAAI,EACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1C,OAAO,CAAC,cAAc,CAAC,CAkDzB;AAwLD,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,yBAAyB,GAAG,yBAAyB,CAE7G;AAED,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,yBAAyB,EACzC,qBAAqB,CAAC,EAAE,yBAAyB,GAC/C,yBAAyB,CAkC3B;AAED,mHAAmH;AACnH,wBAAgB,2BAA2B,CAC1C,2BAA2B,EAAE,yBAAyB,EACtD,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACrC,gCAAgC,CAoElC;AAyOD,wBAAgB,4CAA4C,CAC3D,SAAS,EAAE,SAAS,cAAc,EAAE,EACpC,WAAW,EAAE,MAAM,GACjB,cAAc,GAAG,SAAS,CAQ5B;AAwFD,MAAM,WAAW,WAAW;IAC3B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACxC;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,sBAwnB/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 { join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { type Api, type ImageContent, type Model, modelsAreEqual } from \"@ponythewhite/base-context-ai\";\nimport { registerBuiltinMcpOAuthProviders } from \"@ponythewhite/base-context-ai/mcp\";\nimport { ProcessTerminal, setKeybindings, TUI } from \"@ponythewhite/base-context-tui\";\nimport chalk from \"chalk\";\nimport { type Args, type Mode, parseArgs } from \"./cli/args.js\";\nimport { formatTopLevelHelp } from \"./cli/command-registry.js\";\nimport {\n\tensureInteractiveDaemonRunning,\n\tisDaemonSessionSummary,\n\tlistActiveDaemonSessionSummaries,\n\tprobeRunningDaemonSessions,\n\tStaleDaemonError,\n\tshutdownDaemonAndWait,\n} from \"./cli/daemon-launch.js\";\nimport { confirmDaemonSessionLoss, type DaemonSessionLossCopy, pluralizeSessions } from \"./cli/daemon-stop-confirm.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { buildInitialMessage } from \"./cli/initial-message.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { installOwnedSessionRecoveryTracking, isOwnedSessionWorkerProcess } from \"./cli/owned-session-worker.js\";\nimport { handlePublicCommand } from \"./cli/public-command.js\";\nimport {\n\tlooksLikeSessionPath,\n\tresolveSessionPath,\n\tSessionSelectorError,\n\tSessionSelectorNotFoundError,\n} from \"./cli/session-resolver.js\";\nimport { APP_NAME, expandTildePath, getAgentDir, getSessionDirEnvOverride, VERSION } from \"./config.js\";\nimport {\n\ttype AgentExecutionMode,\n\ttype AgentSessionRuntimeConfig,\n\tmergeAgentSessionRuntimeConfig,\n\tmergeAutonomousConfig,\n} from \"./core/agent-session-config.js\";\nimport {\n\ttype AgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\tcreateAgentSessionRuntime,\n} from \"./core/agent-session-runtime.js\";\nimport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./core/agent-session-services.js\";\nimport { formatNoModelsAvailableMessage } from \"./core/auth-guidance.js\";\nimport { AuthStorage } from \"./core/auth-storage.js\";\nimport { exportFromFile } from \"./core/export-html/index.js\";\nimport type { ExtensionFactory } from \"./core/extensions/types.js\";\nimport { KeybindingsManager } from \"./core/keybindings.js\";\nimport { installFileLogSink, setLogContext } from \"./core/logging.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\nimport { findInitialModel, resolveCliModel, resolveModelScope, type ScopedModel } from \"./core/model-resolver.js\";\nimport { restoreStdout, takeOverStdout } from \"./core/output-guard.js\";\nimport type { CreateAgentSessionOptions } from \"./core/sdk.js\";\nimport { readSessionBootstrap } from \"./core/session-bootstrap.js\";\nimport {\n\tformatMissingSessionCwdPrompt,\n\tgetMissingSessionCwdIssue,\n\tMissingSessionCwdError,\n\ttype SessionCwdIssue,\n} from \"./core/session-cwd.js\";\nimport { canonicalSessionPath, SessionAlreadyActiveError } from \"./core/session-lease.js\";\nimport { findMostRecentSessionForCwd, getDefaultSessionDir, SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { printTimings, resetTimings, time } from \"./core/timings.js\";\nimport { runMigrations, showDeprecationWarnings } from \"./migrations.js\";\nimport { isDaemonCatalogProcess, runDaemonCatalogProcess } from \"./modes/daemon/daemon-catalog-process.js\";\nimport { DaemonSessionCreateError, deserializeDaemonCreateError } from \"./modes/daemon/daemon-errors.js\";\nimport { collectDaemonClientEnv, collectDaemonLaunchEnv } from \"./modes/daemon/daemon-protocol.js\";\nimport {\n\tDAEMON_WORKER_ACTIVE_SESSION_ID_ENV,\n\tdaemonWorkerInstanceId,\n\tisDaemonWorkerProcess,\n\trequireDaemonWorkerAuthenticationToken,\n\twaitForDaemonWorkerStartupGate,\n} from \"./modes/daemon/daemon-worker-protocol.js\";\nimport {\n\ttype AgentConnection,\n\ttype AgentsViewScopeKey,\n\tClientPromptStashStore,\n\tcreateInteractiveModeLocalSessionHost,\n\tcreateInteractiveModeUiServicesFromServices,\n\tDaemonAgentConnection,\n\tDaemonCapabilityUnavailableError,\n\tDaemonClient,\n\tdefaultDaemonSocketPath,\n\tInProcessAgentConnection,\n\tInteractiveMode,\n\tnormalizeSocketPath,\n\tresolveAttachModelFallbackMessage,\n\trunAcpMode,\n\trunAcpModeWithConnection,\n\trunAgentsViewMode,\n\trunDaemonMode,\n\trunDaemonSupervisorMode,\n\trunPrintMode,\n\trunPrintModeWithConnection,\n\trunRpcMode,\n\trunRpcModeWithConnection,\n\ttype SessionSummary,\n} from \"./modes/index.js\";\nimport { ExtensionSelectorComponent } from \"./modes/interactive/components/extension-selector.js\";\nimport { shouldRunOnboarding } from \"./modes/interactive/onboarding.js\";\nimport { initTheme, preloadCodeHighlighter, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { handleConfigCommand } from \"./package-manager-cli.js\";\nimport { assertProductStatePath } from \"./runtime-paths.js\";\nimport { isLocalPath } from \"./utils/paths.js\";\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\nexport type ClientMode = AgentExecutionMode;\n/** Compatibility view of the CLI's internal daemon process entrypoint. */\nexport type AppMode = ClientMode | \"daemon\";\n\nexport function shouldRejectNonInteractiveAttach(attachAgent: string | undefined, appMode: AppMode): boolean {\n\treturn attachAgent !== undefined && appMode !== \"interactive\";\n}\n\nexport function shouldRejectNonInteractiveBareResume(resume: true | string | undefined, appMode: AppMode): boolean {\n\treturn resume === true && appMode !== \"interactive\";\n}\n\nfunction resolveAppMode(parsed: Args, stdinIsTTY: boolean): AppMode {\n\tif (parsed.mode === \"daemon\") {\n\t\treturn \"daemon\";\n\t}\n\tif (parsed.mode === \"rpc\") {\n\t\treturn \"rpc\";\n\t}\n\tif (parsed.mode === \"acp\") {\n\t\treturn \"acp\";\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\" | \"acp\" | \"daemon\"> {\n\treturn appMode === \"json\" ? \"json\" : \"text\";\n}\n\nexport function isClientOwnedDaemonSession(appMode: AppMode, noSession?: boolean): boolean {\n\treturn appMode !== \"acp\" || noSession === true;\n}\n\n// `prime-agent agents` opens the agents view directly.\nexport function parseAgentsViewCommand(args: string[]): { explicitAgentsView: boolean; args: string[] } {\n\tif (args[0] === \"agents\") {\n\t\treturn { explicitAgentsView: true, args: args.slice(1) };\n\t}\n\treturn { explicitAgentsView: false, args };\n}\n\nexport interface DaemonClientStartupDecision {\n\tappMode: AppMode;\n\tstartupBenchmark: boolean;\n\tnoSession?: boolean;\n\thelp?: boolean;\n\tlistModels?: string | true;\n}\n\nexport type InteractiveDaemonStartupDecision = DaemonClientStartupDecision;\n\n/** Retained for callers that only classify persistent interactive startup. */\nexport function shouldUseDaemonInteractive(options: DaemonClientStartupDecision): boolean {\n\treturn (\n\t\toptions.appMode === \"interactive\" &&\n\t\t!options.startupBenchmark &&\n\t\t!options.noSession &&\n\t\toptions.listModels === undefined\n\t);\n}\n\nexport function shouldUseDaemonClient(options: DaemonClientStartupDecision): boolean {\n\treturn (\n\t\toptions.appMode !== \"daemon\" && !options.startupBenchmark && !options.help && options.listModels === undefined\n\t);\n}\n\nexport function shouldUseDaemonClientRuntime(\n\toptions: DaemonClientStartupDecision & {\n\t\townedSessionWorker?: boolean;\n\t\thasProcessLocalExtensionFactories?: boolean;\n\t},\n): boolean {\n\treturn shouldUseDaemonClient(options) && !options.ownedSessionWorker && !options.hasProcessLocalExtensionFactories;\n}\n\nexport function shouldEnsureInteractiveDaemonForStartup(\n\tuseDaemonInteractive: boolean,\n\tattachAgent: string | undefined,\n): boolean {\n\treturn useDaemonInteractive && attachAgent === undefined;\n}\n\nexport interface AgentsViewStartupDecision {\n\tuseDaemonInteractive: boolean;\n\tneedsOnboarding: boolean;\n\texplicitAgentsView?: boolean;\n\tresume?: true | string;\n\tcontinue?: boolean;\n\tfork?: string;\n}\n\nexport function shouldOpenAgentsViewForDaemonInteractive(options: AgentsViewStartupDecision): boolean {\n\tconst bareResume = options.resume === true;\n\tconst requestsAgentsView = bareResume || (options.explicitAgentsView && !options.needsOnboarding);\n\treturn (\n\t\toptions.useDaemonInteractive &&\n\t\t// A selector, continuation, or fork must open its target directly rather than the agents view.\n\t\t!!requestsAgentsView &&\n\t\ttypeof options.resume !== \"string\" &&\n\t\t!options.continue &&\n\t\t!options.fork\n\t);\n}\n\nexport interface DaemonInteractiveSessionManagerDecision {\n\tresume?: true | string;\n\tcontinue?: boolean;\n\tfork?: string;\n\thasActiveDaemonSession?: boolean;\n}\n\nexport function shouldUseEphemeralSessionManagerForDaemonInteractive(\n\toptions: DaemonInteractiveSessionManagerDecision,\n): boolean {\n\treturn (\n\t\t!options.hasActiveDaemonSession &&\n\t\t(options.resume === undefined || options.resume === true) &&\n\t\t!options.continue &&\n\t\t!options.fork\n\t);\n}\n\nexport interface DaemonActiveSessionLookupDecision {\n\tuseDaemonInteractive: boolean;\n\tresumeSelector?: string;\n\texplicitAttach?: boolean;\n}\n\nexport function shouldEnsureDaemonBeforeActiveSessionLookup(options: DaemonActiveSessionLookupDecision): boolean {\n\treturn (\n\t\toptions.useDaemonInteractive &&\n\t\toptions.resumeSelector !== undefined &&\n\t\t(options.explicitAttach || !looksLikeSessionPath(options.resumeSelector))\n\t);\n}\n\ninterface ActiveDaemonSessionSummaryLookupOptions {\n\tfallbackOnError?: boolean;\n}\n\nasync function findActiveDaemonSessionSummaryForInteractiveStartup(\n\tsocketPath: string,\n\tselector: string,\n\toptions: ActiveDaemonSessionSummaryLookupOptions = {},\n): Promise<SessionSummary | undefined> {\n\ttry {\n\t\treturn await findActiveDaemonSessionSummary(socketPath, selector);\n\t} catch (error) {\n\t\tif (options.fallbackOnError === false) {\n\t\t\tthrow error;\n\t\t}\n\t\treturn undefined;\n\t}\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/** Prompt user for yes/no confirmation */\nasync function promptConfirm(message: string): Promise<boolean> {\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\trl.question(`${message} [y/N] `, (answer) => {\n\t\t\trl.close();\n\t\t\tresolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n\t\t});\n\t});\n}\n\n// Only busy sessions (streaming, compacting, or pending messages) lose work;\n// idle loaded sessions reload from disk on the fresh daemon.\nconst STARTUP_SESSION_LOSS_COPY: DaemonSessionLossCopy = {\n\tbusyDetail(count) {\n\t\tconst { noun, pronoun } = pluralizeSessions(count);\n\t\treturn `A background service from a different Base Context version is running with ${count} busy ${noun}. Stopping it will terminate ${pronoun}.`;\n\t},\n\tunlistableDetail:\n\t\t\"A background service from a different Base Context version is running and its sessions could not be listed. Stopping it may terminate active sessions.\",\n\tquestion: \"Stop it and continue?\",\n\tnonTtyHint: 'Run \"base-context shutdown\" to stop it, then retry.',\n};\n\n// The promise to keep after awaiting readiness. Wrapped in an object so it\n// survives `await` (which would otherwise flatten a returned Promise to void).\ntype DaemonReadyResult = { ready: Promise<void> | undefined };\n\n// A stale-version daemon couldn't be taken over automatically (busy or stuck).\n// Offer to stop it (default No) and start a fresh daemon, or exit. Returns the\n// fresh ready promise so callers stop re-handling the original rejection.\nasync function takeOverStaleDaemonOrExit(socketPath: string): Promise<DaemonReadyResult> {\n\tconst probe = await probeRunningDaemonSessions(socketPath);\n\tconst confirmed = await confirmDaemonSessionLoss(probe, { force: false, copy: STARTUP_SESSION_LOSS_COPY });\n\tif (!confirmed) {\n\t\t// Non-TTY already printed the reason; at a TTY the user declined.\n\t\tif (process.stdin.isTTY) {\n\t\t\tconsole.error(chalk.dim(\"Cancelled.\"));\n\t\t}\n\t\tprocess.exit(1);\n\t}\n\tif (!(await shutdownDaemonAndWait(socketPath))) {\n\t\tconsole.error(\n\t\t\tchalk.red(`Could not stop the background service on ${socketPath}. Run \"base-context shutdown\" and retry.`),\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\tconst ready = ensureInteractiveDaemonRunning(socketPath);\n\ttry {\n\t\tawait ready;\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tconsole.error(chalk.red(`Could not start the background service: ${message}`));\n\t\tprocess.exit(1);\n\t}\n\treturn { ready };\n}\n\n// Resolves the daemon-ready promise, returning the promise to keep (the same\n// one on success, or the fresh one from a stale-daemon takeover) so repeat\n// calls don't re-handle the original rejection.\nasync function awaitDaemonReady(daemonReady: Promise<void> | undefined): Promise<DaemonReadyResult> {\n\tif (!daemonReady) {\n\t\treturn { ready: daemonReady };\n\t}\n\ttry {\n\t\tawait daemonReady;\n\t\treturn { ready: daemonReady };\n\t} catch (error) {\n\t\tif (error instanceof StaleDaemonError) {\n\t\t\treturn takeOverStaleDaemonOrExit(error.socketPath);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction validateForkFlags(parsed: Args): void {\n\tif (!parsed.fork) return;\n\n\tconst conflictingFlags = [\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\nasync function forkSessionOrExit(sourcePath: string, cwd: string, sessionDir?: string): Promise<SessionManager> {\n\ttry {\n\t\treturn await SessionManager.forkFrom(sourcePath, cwd, sessionDir);\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 getResumeSelector(parsed: Pick<Args, \"resume\">): string | undefined {\n\treturn typeof parsed.resume === \"string\" ? parsed.resume : undefined;\n}\n\nexport async function createSessionManager(\n\tparsed: Args,\n\tcwd: string,\n\tsessionDir: string | undefined,\n\toptions: { readOnlyExisting?: boolean } = {},\n): Promise<SessionManager> {\n\tconst explicitCwdOverride = parsed.cwd ? cwd : undefined;\n\n\tif (parsed.noSession) {\n\t\treturn SessionManager.inMemory();\n\t}\n\n\tif (parsed.fork) {\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);\n\t\t}\n\t}\n\n\tconst resumeSelector = getResumeSelector(parsed);\n\tif (resumeSelector) {\n\t\tconst resolved = await resolveSessionPath(resumeSelector, cwd, sessionDir);\n\n\t\tswitch (resolved.type) {\n\t\t\tcase \"path\":\n\t\t\tcase \"local\":\n\t\t\t\treturn options.readOnlyExisting\n\t\t\t\t\t? SessionManager.openReadOnly(resolved.path, sessionDir, explicitCwdOverride)\n\t\t\t\t\t: SessionManager.open(resolved.path, sessionDir, explicitCwdOverride);\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\t\t}\n\t}\n\n\tif (parsed.continue) {\n\t\tif (options.readOnlyExisting) {\n\t\t\tconst recent = findMostRecentSessionForCwd(sessionDir ?? getDefaultSessionDir(cwd), cwd);\n\t\t\treturn recent ? SessionManager.openReadOnly(recent, sessionDir, cwd) : SessionManager.create(cwd, sessionDir);\n\t\t}\n\t\treturn SessionManager.continueRecent(cwd, sessionDir);\n\t}\n\n\treturn SessionManager.create(cwd, sessionDir);\n}\n\nfunction buildSessionOptions(\n\tconfig: AgentSessionRuntimeConfig,\n\tscopedModels: ScopedModel[],\n\thasExistingSession: boolean,\n\tmodelRegistry: ModelRegistry,\n\tsettingsManager: SettingsManager,\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 --model <provider>/<pattern>\n\tif (config.model) {\n\t\tconst resolved = resolveCliModel({\n\t\t\tcliProvider: config.provider,\n\t\t\tcliModel: config.model,\n\t\t\tmodelRegistry,\n\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 (!config.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\tif (!options.model && scopedModels.length > 0 && !hasExistingSession) {\n\t\t// A model scope constrains choices; only restore an explicit saved selection.\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 =\n\t\t\tsavedModel && (!config.provider || config.provider === savedModel.provider)\n\t\t\t\t? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel))\n\t\t\t\t: 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 (!config.thinking && savedInScope.thinkingLevel) {\n\t\t\t\toptions.thinkingLevel = savedInScope.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 (config.thinking) {\n\t\toptions.thinkingLevel = config.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 (config.noTools) {\n\t\toptions.noTools = \"all\";\n\t} else if (config.noBuiltinTools) {\n\t\toptions.noTools = \"builtin\";\n\t}\n\tif (config.tools) {\n\t\toptions.tools = [...config.tools];\n\t}\n\tif (config.autonomous) {\n\t\toptions.autonomous = mergeAutonomousConfig(undefined, config.autonomous);\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) ? resolve(cwd, value) : value));\n}\n\nfunction runtimeAutonomousConfigFromArgs(parsed: Args): AgentSessionRuntimeConfig[\"autonomous\"] {\n\tconst hasAutonomousOptions =\n\t\tparsed.autonomous === true ||\n\t\tparsed.autonomousGates !== undefined ||\n\t\tparsed.autonomousGateRetries !== undefined ||\n\t\tparsed.autonomousGateTimeoutMs !== undefined ||\n\t\tparsed.autonomousMaxContinuations !== undefined ||\n\t\tparsed.autonomousMaxTurns !== undefined ||\n\t\tparsed.autonomousMaxTokens !== undefined ||\n\t\tparsed.autonomousTimeoutMs !== undefined;\n\tif (!hasAutonomousOptions) {\n\t\treturn undefined;\n\t}\n\tconst hasGateOptions =\n\t\tparsed.autonomousGates !== undefined ||\n\t\tparsed.autonomousGateRetries !== undefined ||\n\t\tparsed.autonomousGateTimeoutMs !== undefined;\n\treturn {\n\t\tenabled: true,\n\t\tmaxContinuations: parsed.autonomousMaxContinuations,\n\t\tmaxTurns: parsed.autonomousMaxTurns,\n\t\tmaxTokens: parsed.autonomousMaxTokens,\n\t\ttimeoutMs: parsed.autonomousTimeoutMs,\n\t\tgates: hasGateOptions\n\t\t\t? {\n\t\t\t\t\tcommands: parsed.autonomousGates,\n\t\t\t\t\tmaxRetries: parsed.autonomousGateRetries,\n\t\t\t\t\ttimeoutMs: parsed.autonomousGateTimeoutMs,\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n}\n\nfunction runtimeConfigFromArgs(\n\tparsed: Args,\n\tcwd: string,\n\tagentDir: string,\n\tsessionDir: string | undefined,\n\tappMode: AppMode,\n): AgentSessionRuntimeConfig {\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionDir,\n\t\tprovider: parsed.provider,\n\t\tmodel: parsed.model,\n\t\tapiKey: parsed.apiKey,\n\t\tsystemPrompt: parsed.systemPrompt,\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tthinking: parsed.thinking,\n\t\tmodels: parsed.models,\n\t\ttools: parsed.tools,\n\t\tnoTools: parsed.noTools,\n\t\tnoBuiltinTools: parsed.noBuiltinTools,\n\t\textensions: resolveCliPaths(cwd, parsed.extensions),\n\t\tnoExtensions: parsed.noExtensions,\n\t\tskills: resolveCliPaths(cwd, parsed.skills),\n\t\tnoSkills: parsed.noSkills,\n\t\tpromptTemplates: resolveCliPaths(cwd, parsed.promptTemplates),\n\t\tnoPromptTemplates: parsed.noPromptTemplates,\n\t\tthemes: resolveCliPaths(cwd, parsed.themes),\n\t\tnoThemes: parsed.noThemes,\n\t\tnoContextFiles: parsed.noContextFiles,\n\t\tautonomous: runtimeAutonomousConfigFromArgs(parsed),\n\t\textensionFlagValues: parsed.unknownFlags.size > 0 ? Object.fromEntries(parsed.unknownFlags.entries()) : undefined,\n\t\texecutionMode: appMode === \"daemon\" ? undefined : appMode,\n\t\t// Serialized refine for print/json/rpc: the client's appMode is NOT\n\t\t// \"daemon\" here — it's \"print\", \"json\", or \"rpc\". The daemon worker\n\t\t// receives this flag via AgentSessionRuntimeConfig and uses it\n\t\t// instead of its own appMode=\"daemon\".\n\t\tserializedRefine: appMode !== \"interactive\" && appMode !== \"daemon\",\n\t\tinitialGoal: parsed.goal ? { objective: parsed.goal, tokenBudget: parsed.goalTokenBudget } : undefined,\n\t};\n}\n\ninterface PreparedRuntimeServices {\n\tservices: AgentSessionServices;\n\tscopedModels: ScopedModel[];\n\tsessionOptions: CreateAgentSessionOptions;\n\tcliProvider?: string;\n\tcliThinkingFromModel: boolean;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\nexport function daemonServerDefaultSessionConfig(config: AgentSessionRuntimeConfig): AgentSessionRuntimeConfig {\n\treturn { ...config, initialGoal: undefined };\n}\n\nexport function resolveRuntimeSessionOptions(\n\tsessionOptions: CreateAgentSessionOptions,\n\truntimeSessionOptions?: CreateAgentSessionOptions,\n): CreateAgentSessionOptions {\n\treturn {\n\t\trequestTokenBudget: runtimeSessionOptions?.requestTokenBudget ?? sessionOptions.requestTokenBudget,\n\t\tcontextMode: runtimeSessionOptions?.contextMode ?? sessionOptions.contextMode,\n\t\tmodel: runtimeSessionOptions?.model !== undefined ? runtimeSessionOptions.model : sessionOptions.model,\n\t\tthinkingLevel: runtimeSessionOptions?.thinkingLevel ?? sessionOptions.thinkingLevel,\n\t\tserviceTier: runtimeSessionOptions?.serviceTier ?? sessionOptions.serviceTier,\n\t\tscopedModels: runtimeSessionOptions?.scopedModels ?? sessionOptions.scopedModels,\n\t\ttools: runtimeSessionOptions?.tools ?? sessionOptions.tools,\n\t\tnoTools: runtimeSessionOptions?.noTools ?? sessionOptions.noTools,\n\t\tcustomTools: runtimeSessionOptions?.customTools ?? sessionOptions.customTools,\n\t\tinitialActiveToolNames: runtimeSessionOptions?.initialActiveToolNames,\n\t\tallowedToolNames: runtimeSessionOptions?.allowedToolNames,\n\t\tincludeGoals: runtimeSessionOptions?.includeGoals,\n\t\tincludeCompactSkill: runtimeSessionOptions?.includeCompactSkill,\n\t\trlmHeartbeatController: runtimeSessionOptions?.rlmHeartbeatController,\n\t\tagentMessageController: runtimeSessionOptions?.agentMessageController,\n\t\tagentObserveController: runtimeSessionOptions?.agentObserveController,\n\t\tautonomous:\n\t\t\t(runtimeSessionOptions?.rlmDepth ?? 0) > 0\n\t\t\t\t? mergeAutonomousConfig(sessionOptions.autonomous, { ...runtimeSessionOptions?.autonomous, enabled: false })\n\t\t\t\t: mergeAutonomousConfig(sessionOptions.autonomous, runtimeSessionOptions?.autonomous),\n\t\trlmDepth: runtimeSessionOptions?.rlmDepth,\n\t\trlmMaxDepth: runtimeSessionOptions?.rlmMaxDepth,\n\t\trlmSessionDir: runtimeSessionOptions?.rlmSessionDir,\n\t\trlmParentNodeId: runtimeSessionOptions?.rlmParentNodeId,\n\t\trlmParentAgent: runtimeSessionOptions?.rlmParentAgent,\n\t\trlmChildAdmission: runtimeSessionOptions?.rlmChildAdmission,\n\t\trlmSubagentCapacity: runtimeSessionOptions?.rlmSubagentCapacity,\n\t\trlmRootAdmission: runtimeSessionOptions?.rlmRootAdmission,\n\t\tsemanticParentSessionId: runtimeSessionOptions?.semanticParentSessionId,\n\t\tsemanticSpawnedByRequestId: runtimeSessionOptions?.semanticSpawnedByRequestId,\n\t\tsubagentRuntimeHost: runtimeSessionOptions?.subagentRuntimeHost,\n\t};\n}\n\n/** The production runtime factory: every daemon-hosted and runtime-hosted session is created through this path. */\nexport function createDefaultRuntimeFactory(\n\truntimeDefaultSessionConfig: AgentSessionRuntimeConfig,\n\textensionFactories?: ExtensionFactory[],\n): CreateAgentSessionRuntimeFactory {\n\treturn async ({\n\t\tcwd,\n\t\tagentDir,\n\t\tsessionManager,\n\t\tsessionStartEvent,\n\t\tsessionConfig,\n\t\tsessionOptions: runtimeSessionOptions,\n\t}) => {\n\t\tif (runtimeSessionOptions)\n\t\t\truntimeSessionOptions = { ...runtimeSessionOptions, contextMode: runtimeSessionOptions.contextMode };\n\t\tif (runtimeSessionOptions?.requestTokenBudget) {\n\t\t\truntimeSessionOptions = {\n\t\t\t\t...runtimeSessionOptions,\n\t\t\t\trequestTokenBudget: structuredClone(runtimeSessionOptions.requestTokenBudget),\n\t\t\t};\n\t\t}\n\t\tconst config = mergeAgentSessionRuntimeConfig(runtimeDefaultSessionConfig, sessionConfig);\n\t\tconst prepared = await prepareRuntimeServices({\n\t\t\tconfig,\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tsessionManager,\n\t\t\textensionFactories,\n\t\t\tsessionOptionsOverride: runtimeSessionOptions,\n\t\t});\n\t\tconst { services, sessionOptions, diagnostics } = prepared;\n\t\tconst resolvedSessionOptions = resolveRuntimeSessionOptions(sessionOptions, runtimeSessionOptions);\n\t\tlet modelFallbackMessage: string | undefined;\n\t\tif (resolvedSessionOptions.model === undefined) {\n\t\t\tconst startupModel = await resolvePreparedStartupModel({ prepared, sessionManager });\n\t\t\tresolvedSessionOptions.model = startupModel.model ?? null;\n\t\t\tmodelFallbackMessage = startupModel.modelFallbackMessage;\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\t...resolvedSessionOptions,\n\t\t\t// Main agents boot their kernel in the background at session creation;\n\t\t\t// subagent sessions (rlmDepth > 0) keep the lazy first-call start.\n\t\t\tprewarmIpythonKernel: true,\n\t\t\t// Read serializedRefine from the merged runtime config (passed\n\t\t\t// from the JSON/print client through AgentSessionRuntimeConfig)\n\t\t\t// so it survives the daemon worker's appMode=\"daemon\" context.\n\t\t\tserializedRefine: config.serializedRefine ?? false,\n\t\t\texecutionMode: config.executionMode,\n\t\t\t// Only seed initial goal for top-level sessions (rlmDepth 0).\n\t\t\tinitialGoal: (runtimeSessionOptions?.rlmDepth ?? 0) === 0 ? config.initialGoal : undefined,\n\t\t});\n\t\ttry {\n\t\t\tconst cliThinkingOverride = config.thinking !== undefined || prepared.cliThinkingFromModel;\n\t\t\tif (created.session.model && cliThinkingOverride) {\n\t\t\t\tawait created.session.setThinkingLevel(created.session.thinkingLevel);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait created.session.disposeAsync().catch(() => undefined);\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\t...created,\n\t\t\tmodelFallbackMessage: modelFallbackMessage ?? created.modelFallbackMessage,\n\t\t\tservices,\n\t\t\tdiagnostics,\n\t\t};\n\t};\n}\n\nasync function prepareRuntimeServices(options: {\n\tconfig: AgentSessionRuntimeConfig;\n\tcwd: string;\n\tagentDir: string;\n\tsessionManager: SessionManager;\n\textensionFactories?: ExtensionFactory[];\n\tsessionOptionsOverride?: CreateAgentSessionOptions;\n}): Promise<PreparedRuntimeServices> {\n\tconst { config, sessionManager } = options;\n\tconst effectiveAgentDir = config.agentDir ?? options.agentDir;\n\tconst authStorage = AuthStorage.create(join(effectiveAgentDir, \"auth.json\"));\n\tconst services = await createAgentSessionServices({\n\t\tcwd: options.cwd,\n\t\tagentDir: effectiveAgentDir,\n\t\tauthStorage,\n\t\textensionFlagValues: new Map(Object.entries(config.extensionFlagValues ?? {})),\n\t\t// Subagents share the parent's Herdr pane; their own reporter would race\n\t\t// the parent's and a subagent quit would release the still-active pane.\n\t\tnoBuiltinHerdrReporter: (options.sessionOptionsOverride?.rlmDepth ?? 0) > 0,\n\t\tresourceLoaderOptions: {\n\t\t\tadditionalExtensionPaths: config.extensions,\n\t\t\tadditionalSkillPaths: config.skills,\n\t\t\tadditionalPromptTemplatePaths: config.promptTemplates,\n\t\t\tadditionalThemePaths: config.themes,\n\t\t\tnoExtensions: config.noExtensions,\n\t\t\tnoSkills: config.noSkills,\n\t\t\tnoPromptTemplates: config.noPromptTemplates,\n\t\t\tnoThemes: config.noThemes,\n\t\t\tnoContextFiles: config.noContextFiles,\n\t\t\tsystemPrompt: config.systemPrompt,\n\t\t\tappendSystemPrompt: config.appendSystemPrompt,\n\t\t\textensionFactories: options.extensionFactories,\n\t\t},\n\t});\n\tconst { settingsManager, modelRegistry, resourceLoader } = services;\n\tconst diagnostics: AgentSessionRuntimeDiagnostic[] = [\n\t\t...services.diagnostics,\n\t\t...collectSettingsDiagnostics(settingsManager, \"runtime creation\"),\n\t\t...resourceLoader.getExtensions().errors.map(({ path, error }) => ({\n\t\t\ttype: \"error\" as const,\n\t\t\tmessage: `Failed to load extension \"${path}\": ${error}`,\n\t\t})),\n\t];\n\n\tconst modelPatterns = config.models ?? settingsManager.getEnabledModels();\n\tconst scopedModels =\n\t\tmodelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];\n\tconst hasExistingSession = sessionManager.supportsCapturedHistoryReads()\n\t\t? await sessionManager.readBranchHistory(async (view) => (await view.branchBootstrap()).hasContextMessages)\n\t\t: (\n\t\t\t\tawait readSessionBootstrap(sessionManager, settingsManager.getCanonicalContextLimits(), {\n\t\t\t\t\tincludeMessages: false,\n\t\t\t\t})\n\t\t\t).hasExistingSession;\n\tconst {\n\t\toptions: sessionOptions,\n\t\tcliThinkingFromModel,\n\t\tdiagnostics: sessionOptionDiagnostics,\n\t} = buildSessionOptions(config, scopedModels, hasExistingSession, modelRegistry, settingsManager);\n\tdiagnostics.push(...sessionOptionDiagnostics);\n\n\tconst effectiveSessionModel = options.sessionOptionsOverride?.model ?? sessionOptions.model;\n\tif (config.apiKey) {\n\t\tif (!effectiveSessionModel) {\n\t\t\tdiagnostics.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\tmessage: \"--api-key requires an explicit model via --model or --provider/--model\",\n\t\t\t});\n\t\t} else {\n\t\t\tauthStorage.setRuntimeApiKey(effectiveSessionModel.provider, config.apiKey);\n\t\t}\n\t}\n\n\treturn {\n\t\tservices,\n\t\tscopedModels,\n\t\tsessionOptions,\n\t\tcliProvider: config.provider,\n\t\tcliThinkingFromModel,\n\t\tdiagnostics,\n\t};\n}\n\nasync function resolvePreparedStartupModel(options: {\n\tprepared: PreparedRuntimeServices;\n\tsessionManager: SessionManager;\n}): Promise<{ model: Model<Api> | undefined; modelFallbackMessage: string | undefined }> {\n\tconst { prepared, sessionManager } = options;\n\tconst { modelRegistry, settingsManager } = prepared.services;\n\tconst { context: existingSession, hasExistingSession } = await readSessionBootstrap(\n\t\tsessionManager,\n\t\tsettingsManager.getCanonicalContextLimits(),\n\t\t{ includeMessages: false },\n\t);\n\n\tlet model = prepared.sessionOptions.model ?? undefined;\n\tconst cliProvider = prepared.cliProvider;\n\tlet modelFallbackMessage: string | undefined;\n\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tif (cliProvider && existingSession.model.provider !== cliProvider) {\n\t\t\treturn {\n\t\t\t\tmodel: undefined,\n\t\t\t\tmodelFallbackMessage: `Saved model ${existingSession.model.provider}/${existingSession.model.modelId} does not match provider ${cliProvider}. Select a model.`,\n\t\t\t};\n\t\t}\n\t\tmodel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}. Select a provider and model.`;\n\t\t} else if (!modelRegistry.hasConfiguredAuth(model)) {\n\t\t\tmodelFallbackMessage = `Model ${model.provider}/${model.id} needs authentication. Run /login.`;\n\t\t}\n\t\treturn { model, modelFallbackMessage };\n\t}\n\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tcliProvider,\n\t\t\tscopedModels: prepared.scopedModels,\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tconst savedProvider = settingsManager.getDefaultProvider();\n\t\t\tconst savedModelId = settingsManager.getDefaultModel();\n\t\t\tmodelFallbackMessage =\n\t\t\t\tsavedProvider && savedModelId\n\t\t\t\t\t? `Could not restore model ${savedProvider}/${savedModelId}. Select a provider and model.`\n\t\t\t\t\t: formatNoModelsAvailableMessage();\n\t\t}\n\t}\n\n\treturn { model, modelFallbackMessage };\n}\n\nasync function promptForMissingSessionCwd(\n\tissue: SessionCwdIssue,\n\tsettingsManager: SettingsManager,\n): Promise<string | undefined> {\n\tinitTheme(settingsManager.getTheme());\n\tsetKeybindings(KeybindingsManager.create());\n\n\treturn new Promise((resolve) => {\n\t\tconst ui = new TUI(\n\t\t\tnew ProcessTerminal(),\n\t\t\tsettingsManager.getShowHardwareCursor(),\n\t\t\tassertProductStatePath(join(getAgentDir(), \"tui\")),\n\t\t);\n\t\tui.setClearOnShrink(settingsManager.getClearOnShrink());\n\n\t\tlet settled = false;\n\t\tconst finish = (result: string | 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\tformatMissingSessionCwdPrompt(issue),\n\t\t\t[\"Continue\", \"Cancel\"],\n\t\t\t(option) => finish(option === \"Continue\" ? issue.fallbackCwd : undefined),\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\nfunction getDaemonSummaryActiveSessionId(summary: SessionSummary): string {\n\treturn summary.activeSessionId ?? summary.id;\n}\n\nfunction isUnknownActiveSessionError(message: string): boolean {\n\treturn message.startsWith(\"Unknown active session:\");\n}\n\nasync function findActiveDaemonSessionSummary(\n\tsocketPath: string,\n\tselector: string,\n): Promise<SessionSummary | undefined> {\n\tconst client = new DaemonClient(socketPath);\n\tawait client.connect(250);\n\n\ttry {\n\t\tconst response = await client.request({ type: \"get_state\", activeSessionId: selector }, 3000);\n\t\tif (!response.success) {\n\t\t\tif (isUnknownActiveSessionError(response.error)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tthrow new Error(response.error);\n\t\t}\n\t\tif (!isDaemonSessionSummary(response.data)) {\n\t\t\tthrow new Error(\"Daemon returned an invalid active session summary\");\n\t\t}\n\t\treturn response.data;\n\t} finally {\n\t\tclient.close();\n\t}\n}\n\nasync function createSessionManagerForActiveDaemonSummary(\n\tsummary: SessionSummary,\n\tfallbackCwd: string,\n): Promise<SessionManager> {\n\tconst cwd = summary.cwd || fallbackCwd;\n\tif (summary.sessionFile) {\n\t\ttry {\n\t\t\treturn await SessionManager.openReadOnly(summary.sessionFile, undefined, cwd);\n\t\t} catch {\n\t\t\treturn SessionManager.inMemory(cwd);\n\t\t}\n\t}\n\treturn SessionManager.inMemory(cwd);\n}\n\nfunction getInteractiveDaemonSessionPath(parsed: Args, sessionManager: SessionManager): string | undefined {\n\tif (!parsed.resume && !parsed.continue && !parsed.fork) {\n\t\treturn undefined;\n\t}\n\treturn sessionManager.getSessionFile();\n}\n\nexport function findActiveDaemonSessionSummaryForSessionFile(\n\tsummaries: readonly SessionSummary[],\n\tsessionPath: string,\n): SessionSummary | undefined {\n\tconst resolvedSessionPath = canonicalSessionPath(sessionPath);\n\treturn summaries.find(\n\t\t(summary) =>\n\t\t\tsummary.activeSessionId !== undefined &&\n\t\t\tsummary.sessionFile !== undefined &&\n\t\t\tcanonicalSessionPath(summary.sessionFile) === resolvedSessionPath,\n\t);\n}\n\nasync function createDaemonClientConnection(options: {\n\tsocketPath: string;\n\tconfig: AgentSessionRuntimeConfig;\n\tsessionPath?: string;\n\tcontinueRecent?: boolean;\n\tactiveSessionId?: string;\n\tclientOwned?: boolean;\n\tnoSession?: boolean;\n\tsupportsExtensionUi?: boolean;\n}): Promise<{ connection: DaemonAgentConnection; summary: SessionSummary }> {\n\t// Caller must have awaited ensureInteractiveDaemonRunning for this socket.\n\tconst client = new DaemonClient(options.socketPath);\n\tawait client.connect();\n\n\ttry {\n\t\tconst attach = async (summary: SessionSummary) => {\n\t\t\tconst connection = await DaemonAgentConnection.attach(client, getDaemonSummaryActiveSessionId(summary), {\n\t\t\t\tcloseClientOnDispose: true,\n\t\t\t\tsendClientEnv: true,\n\t\t\t\townedSession: options.clientOwned,\n\t\t\t\townedSessionRecoveryConfig: options.clientOwned ? options.config : undefined,\n\t\t\t\tsupportsExtensionUi: options.supportsExtensionUi,\n\t\t\t\trecoverDaemon: () => ensureInteractiveDaemonRunning(options.socketPath),\n\t\t\t});\n\t\t\treturn { connection, summary };\n\t\t};\n\n\t\tif (options.activeSessionId) {\n\t\t\tconst summary = await findAttachedDaemonSessionSummary(client, options.activeSessionId);\n\t\t\treturn await attach(summary);\n\t\t}\n\n\t\tif (options.sessionPath && !options.clientOwned) {\n\t\t\tconst activeSummary = findActiveDaemonSessionSummaryForSessionFile(\n\t\t\t\tawait listActiveDaemonSessionSummaries(client),\n\t\t\t\toptions.sessionPath,\n\t\t\t);\n\t\t\tif (activeSummary && activeSummary.workerState !== \"failed\") {\n\t\t\t\treturn await attach(activeSummary);\n\t\t\t}\n\t\t}\n\t\tif (options.clientOwned) {\n\t\t\tawait client.waitForHello();\n\t\t\tif (!client.supportsServerCapability(\"client_owned_sessions\")) {\n\t\t\t\tthrow new DaemonCapabilityUnavailableError(\"create\", \"client_owned_sessions\");\n\t\t\t}\n\t\t}\n\n\t\tconst response = await client.request({\n\t\t\ttype: \"create\",\n\t\t\tconfig: options.config,\n\t\t\tsessionPath: options.sessionPath,\n\t\t\tcontinueRecent: options.continueRecent,\n\t\t\tnoSession: options.noSession,\n\t\t\tenv: collectDaemonClientEnv(),\n\t\t\tlifecycle: options.clientOwned ? \"client_owned\" : \"resident\",\n\t\t\tlaunchEnv: collectDaemonLaunchEnv(),\n\t\t});\n\t\tif (!response.success) {\n\t\t\tthrow deserializeDaemonCreateError(response);\n\t\t}\n\t\tif (!isDaemonSessionSummary(response.data)) {\n\t\t\tthrow new Error(\"Daemon returned an invalid create response\");\n\t\t}\n\t\tconst summary = response.data;\n\t\treturn await attach(summary);\n\t} catch (error) {\n\t\tclient.close();\n\t\tthrow error;\n\t}\n}\n\nasync function findAttachedDaemonSessionSummary(\n\tclient: DaemonClient,\n\tactiveSessionId: string,\n): Promise<SessionSummary> {\n\tconst response = await client.request({ type: \"get_state\", activeSessionId });\n\tif (!response.success) {\n\t\tthrow new Error(response.error);\n\t}\n\tif (!isDaemonSessionSummary(response.data)) {\n\t\tthrow new Error(\"Daemon returned an invalid active session summary\");\n\t}\n\treturn response.data;\n}\n\nexport interface MainOptions {\n\textensionFactories?: ExtensionFactory[];\n}\n\nexport async function main(args: string[], options?: MainOptions) {\n\tresetTimings();\n\tif (isDaemonWorkerProcess()) {\n\t\twaitForDaemonWorkerStartupGate();\n\t}\n\tinstallFileLogSink();\n\tif (isDaemonCatalogProcess()) {\n\t\tawait runDaemonCatalogProcess();\n\t\treturn;\n\t}\n\t// Client and daemon are separate processes; both need these in their registry.\n\tregisterBuiltinMcpOAuthProviders();\n\tconst offlineMode = args.includes(\"--offline\") || isTruthyEnvFlag(process.env.BASE_CONTEXT_OFFLINE);\n\tif (offlineMode) {\n\t\tprocess.env.BASE_CONTEXT_OFFLINE = \"1\";\n\t\tprocess.env.BASE_CONTEXT_SKIP_VERSION_CHECK = \"1\";\n\t}\n\n\tconst publicCommand = await handlePublicCommand(args);\n\tif (publicCommand.handled) {\n\t\treturn;\n\t}\n\targs = publicCommand.args;\n\n\tif (await handleConfigCommand(args)) {\n\t\treturn;\n\t}\n\n\tconst explicitAgentsView = publicCommand.explicitAgentsView;\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\tconst appMode = resolveAppMode(parsed, process.stdin.isTTY);\n\n\tif (shouldRejectNonInteractiveAttach(publicCommand.attachAgent, appMode)) {\n\t\tconsole.error(chalk.red(\"Error: attach requires an interactive terminal\"));\n\t\tprocess.exit(1);\n\t}\n\tif (shouldRejectNonInteractiveBareResume(parsed.resume, appMode)) {\n\t\tconsole.error(chalk.red(\"Error: --resume without a session selector requires an interactive terminal\"));\n\t\tprocess.exit(1);\n\t}\n\tsetLogContext({ mode: appMode });\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\tif (parsed.help) {\n\t\tconsole.log(formatTopLevelHelp());\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.mode === \"daemon\") && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC or daemon mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\tvalidateForkFlags(parsed);\n\n\tconst cwd = parsed.cwd ? resolve(expandTildePath(parsed.cwd)) : process.cwd();\n\tif (parsed.cwd) {\n\t\ttry {\n\t\t\tprocess.chdir(cwd);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(chalk.red(`Error: Cannot use cwd ${cwd}: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (parsed.daemonSocket) {\n\t\t// After --cwd so a relative socket path resolves against the requested directory.\n\t\tparsed.daemonSocket = normalizeSocketPath(parsed.daemonSocket);\n\t}\n\n\t// Run migrations (pass cwd for project-local migrations)\n\tconst { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);\n\ttime(\"runMigrations\");\n\n\tconst agentDir = getAgentDir();\n\tconst startupSettingsManager = SettingsManager.create(cwd, agentDir);\n\treportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, \"startup session lookup\"));\n\tconst startupBenchmark = isTruthyEnvFlag(process.env.BASE_CONTEXT_STARTUP_BENCHMARK);\n\tif (startupBenchmark && appMode !== \"interactive\") {\n\t\tconsole.error(chalk.red(\"Error: BASE_CONTEXT_STARTUP_BENCHMARK only supports interactive mode\"));\n\t\tprocess.exit(1);\n\t}\n\t// Programmatic factories are process-local functions and cannot be serialized to a daemon worker.\n\tconst hasProcessLocalExtensionFactories = (options?.extensionFactories?.length ?? 0) > 0;\n\tconst useDaemonClient = shouldUseDaemonClientRuntime({\n\t\tappMode,\n\t\tstartupBenchmark,\n\t\tnoSession: parsed.noSession,\n\t\tlistModels: parsed.listModels,\n\t\townedSessionWorker: isOwnedSessionWorkerProcess(),\n\t\thasProcessLocalExtensionFactories,\n\t});\n\tconst useDaemonInteractive = useDaemonClient && appMode === \"interactive\";\n\n\t// Decide the final runtime cwd before creating cwd-bound runtime services.\n\t// --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 sessionDir =\n\t\t(parsed.sessionDir ? expandTildePath(parsed.sessionDir) : undefined) ??\n\t\tgetSessionDirEnvOverride() ??\n\t\tstartupSettingsManager.getSessionDir();\n\tconst daemonSocketPath = parsed.daemonSocket ?? defaultDaemonSocketPath();\n\t// Kick off daemon spawn/readiness immediately so it overlaps session-manager\n\t// and runtime-services preparation; attach only connects to an existing daemon.\n\tlet daemonReady = shouldEnsureInteractiveDaemonForStartup(useDaemonClient, publicCommand.attachAgent)\n\t\t? ensureInteractiveDaemonRunning(daemonSocketPath)\n\t\t: undefined;\n\t// Errors are rethrown at the await sites below; this only avoids an unhandled\n\t// rejection if startup exits before reaching them.\n\tdaemonReady?.catch(() => {});\n\tconst resumeSelector = getResumeSelector(parsed);\n\tconst shouldLookupDaemonActiveSession = shouldEnsureDaemonBeforeActiveSessionLookup({\n\t\tuseDaemonInteractive,\n\t\tresumeSelector,\n\t\texplicitAttach: publicCommand.attachAgent !== undefined,\n\t});\n\tif (shouldLookupDaemonActiveSession && daemonReady) {\n\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t}\n\tlet activeDaemonSessionSummary: SessionSummary | undefined;\n\tif (shouldLookupDaemonActiveSession && resumeSelector) {\n\t\ttry {\n\t\t\tactiveDaemonSessionSummary = await findActiveDaemonSessionSummaryForInteractiveStartup(\n\t\t\t\tdaemonSocketPath,\n\t\t\t\tresumeSelector,\n\t\t\t\t{ fallbackOnError: !publicCommand.attachAgent },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(chalk.red(`Error: Could not look up active agent '${resumeSelector}': ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\tif (publicCommand.attachAgent && !activeDaemonSessionSummary) {\n\t\tconsole.error(chalk.red(`Error: No active agent found matching '${publicCommand.attachAgent}'`));\n\t\tprocess.exit(1);\n\t}\n\tlet sessionManager: SessionManager;\n\tif (activeDaemonSessionSummary) {\n\t\tsessionManager = await createSessionManagerForActiveDaemonSummary(activeDaemonSessionSummary, cwd);\n\t} else if (\n\t\t(useDaemonInteractive || (appMode === \"daemon\" && parsed.listModels === undefined)) &&\n\t\tshouldUseEphemeralSessionManagerForDaemonInteractive({\n\t\t\tresume: parsed.resume,\n\t\t\tcontinue: parsed.continue,\n\t\t\tfork: parsed.fork,\n\t\t})\n\t) {\n\t\tsessionManager = SessionManager.inMemory(cwd);\n\t} else {\n\t\ttry {\n\t\t\tsessionManager = await createSessionManager(parsed, cwd, sessionDir, {\n\t\t\t\treadOnlyExisting: useDaemonClient || (appMode === \"daemon\" && parsed.listModels === undefined),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof SessionSelectorError)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst suggestion =\n\t\t\t\terror instanceof SessionSelectorNotFoundError && error.suggestion\n\t\t\t\t\t? ` Did you mean '${error.suggestion}'?`\n\t\t\t\t\t: \"\";\n\t\t\tconsole.error(chalk.red(`Error: ${error.message}.${suggestion}`));\n\t\t\tconsole.error(chalk.dim(`Open ${APP_NAME} and press left-arrow to browse sessions.`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\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\tawait sessionManager.close();\n\t\t\tsessionManager = useDaemonClient\n\t\t\t\t? await SessionManager.openReadOnly(missingSessionCwdIssue.sessionFile!, sessionDir, selectedCwd)\n\t\t\t\t: await SessionManager.open(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\ttime(\"createSessionManager\");\n\n\tconst defaultSessionConfig = runtimeConfigFromArgs(parsed, sessionManager.getCwd(), agentDir, sessionDir, appMode);\n\t// Verifier/headless clients pass initialGoal in each create request. The long-lived\n\t// daemon fallback must not seed that goal into unrelated future sessions.\n\tconst daemonDefaultSessionConfig = daemonServerDefaultSessionConfig(defaultSessionConfig);\n\tconst runtimeDefaultSessionConfig = appMode === \"daemon\" ? daemonDefaultSessionConfig : defaultSessionConfig;\n\t// Daemon clients keep only local views; release the CLI writer before a worker opens this source.\n\tif (useDaemonClient || (appMode === \"daemon\" && parsed.listModels === undefined)) {\n\t\tawait sessionManager.close();\n\t}\n\tconst createRuntime = createDefaultRuntimeFactory(runtimeDefaultSessionConfig, options?.extensionFactories);\n\ttime(\"createRuntime\");\n\t// Daemon mode never uses the bootstrap runtime, so skip the heavy\n\t// createAgentSessionRuntime below and start listening immediately; sessions\n\t// are created on demand through the daemon protocol via createRuntime.\n\t// --list-models still takes the full path to print and exit.\n\tif (appMode === \"daemon\" && parsed.listModels === undefined) {\n\t\tprintTimings();\n\t\tif (isDaemonWorkerProcess()) {\n\t\t\tawait runDaemonMode({\n\t\t\t\tsocketPath: parsed.daemonSocket,\n\t\t\t\tdefaultSessionConfig: daemonDefaultSessionConfig,\n\t\t\t\tcreateRuntime,\n\t\t\t\tworker: {\n\t\t\t\t\tauthenticationToken: requireDaemonWorkerAuthenticationToken(),\n\t\t\t\t\tworkerInstanceId: daemonWorkerInstanceId(),\n\t\t\t\t\trestoreActiveSessionId: process.env[DAEMON_WORKER_ACTIVE_SESSION_ID_ENV],\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\tawait runDaemonSupervisorMode({\n\t\t\t\tsocketPath: parsed.daemonSocket,\n\t\t\t\tdefaultSessionConfig: daemonDefaultSessionConfig,\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\tif (useDaemonInteractive) {\n\t\tconst prepared = await prepareRuntimeServices({\n\t\t\tconfig: defaultSessionConfig,\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tagentDir,\n\t\t\tsessionManager,\n\t\t\textensionFactories: options?.extensionFactories,\n\t\t});\n\t\tconst { services, scopedModels } = prepared;\n\t\tconst { settingsManager } = services;\n\n\t\tconst startupModel = await resolvePreparedStartupModel({ prepared, sessionManager });\n\n\t\tconst stdinContent = await readPipedStdin();\n\t\ttime(\"readPipedStdin\");\n\n\t\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\t\tparsed,\n\t\t\tsettingsManager.getImageAutoResize(),\n\t\t\tstdinContent,\n\t\t);\n\t\ttime(\"prepareInitialMessage\");\n\t\tinitTheme(settingsManager.getTheme(), true);\n\t\ttime(\"initTheme\");\n\n\t\tif (deprecationWarnings.length > 0) {\n\t\t\tawait showDeprecationWarnings(deprecationWarnings);\n\t\t}\n\n\t\treportDiagnostics(prepared.diagnostics);\n\t\tif (prepared.diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\t\tprocess.exit(1);\n\t\t}\n\t\ttime(\"prepareInteractiveServices\");\n\n\t\tif (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst promptStashStore = new ClientPromptStashStore();\n\t\tconst daemonUiServices = createInteractiveModeUiServicesFromServices({\n\t\t\tservices,\n\t\t\tsessionManager,\n\t\t});\n\t\tconst launchAgentsView = async (initialSession?: SessionSummary, initialScopeKey?: AgentsViewScopeKey) => {\n\t\t\tawait runAgentsViewMode({\n\t\t\t\tsocketPath: daemonSocketPath,\n\t\t\t\tconfig: defaultSessionConfig,\n\t\t\t\tuiServices: daemonUiServices,\n\t\t\t\trecoverDaemon: () => ensureInteractiveDaemonRunning(daemonSocketPath),\n\t\t\t\tcreateUiServicesForSession: async (summary) => {\n\t\t\t\t\tconst attachedSessionManager = await createSessionManagerForActiveDaemonSummary(\n\t\t\t\t\t\tsummary,\n\t\t\t\t\t\tsessionManager.getCwd(),\n\t\t\t\t\t);\n\t\t\t\t\tconst attachedPrepared = await prepareRuntimeServices({\n\t\t\t\t\t\tconfig: mergeAgentSessionRuntimeConfig(defaultSessionConfig, {\n\t\t\t\t\t\t\tcwd: attachedSessionManager.getCwd(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tcwd: attachedSessionManager.getCwd(),\n\t\t\t\t\t\tagentDir,\n\t\t\t\t\t\tsessionManager: attachedSessionManager,\n\t\t\t\t\t\textensionFactories: options?.extensionFactories,\n\t\t\t\t\t});\n\t\t\t\t\treturn createInteractiveModeUiServicesFromServices({\n\t\t\t\t\t\tservices: attachedPrepared.services,\n\t\t\t\t\t\tsessionManager: attachedSessionManager,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tmigratedProviders,\n\t\t\t\tmodelFallbackMessage: startupModel.modelFallbackMessage,\n\t\t\t\tpromptStashStore,\n\t\t\t\tstartupModelId: startupModel.model?.id,\n\t\t\t\tinitialSession,\n\t\t\t\tinitialScopeKey,\n\t\t\t\tverbose: parsed.verbose,\n\t\t\t});\n\t\t};\n\t\tif (\n\t\t\tshouldOpenAgentsViewForDaemonInteractive({\n\t\t\t\tuseDaemonInteractive: useDaemonInteractive && !parsed.noSession,\n\t\t\t\texplicitAgentsView,\n\t\t\t\tneedsOnboarding: shouldRunOnboarding({\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\tmodelRegistry: services.modelRegistry,\n\t\t\t\t\tmodel: startupModel.model,\n\t\t\t\t}),\n\t\t\t\tresume: parsed.resume,\n\t\t\t\tcontinue: parsed.continue,\n\t\t\t\tfork: parsed.fork,\n\t\t\t})\n\t\t) {\n\t\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t\t\tawait preloadCodeHighlighter();\n\t\t\tprintTimings();\n\t\t\tawait launchAgentsView();\n\t\t\treturn;\n\t\t}\n\n\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t\t// A fresh default chat opens a real but message-less session; the lifecycle\n\t\t// axis treats it as a draft (hidden, discarded on detach if never used), so\n\t\t// no DeferredAgentConnection is needed to avoid creating it up front.\n\t\tconst isFreshDefaultSession =\n\t\t\t!activeDaemonSessionSummary && !getInteractiveDaemonSessionPath(parsed, sessionManager);\n\t\tlet connection: DaemonAgentConnection;\n\t\tlet summary: SessionSummary;\n\t\ttry {\n\t\t\t({ connection, summary } = await createDaemonClientConnection({\n\t\t\t\tsocketPath: daemonSocketPath,\n\t\t\t\tconfig: defaultSessionConfig,\n\t\t\t\tactiveSessionId: activeDaemonSessionSummary\n\t\t\t\t\t? getDaemonSummaryActiveSessionId(activeDaemonSessionSummary)\n\t\t\t\t\t: undefined,\n\t\t\t\tsessionPath: getInteractiveDaemonSessionPath(parsed, sessionManager),\n\t\t\t\tclientOwned: parsed.noSession,\n\t\t\t\tnoSession: parsed.noSession,\n\t\t\t\tsupportsExtensionUi: true,\n\t\t\t}));\n\t\t} catch (error) {\n\t\t\tif (error instanceof DaemonSessionCreateError) {\n\t\t\t\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst agentConnection: AgentConnection = connection;\n\t\tconst attachModelFallbackMessage = isFreshDefaultSession\n\t\t\t? startupModel.modelFallbackMessage\n\t\t\t: resolveAttachModelFallbackMessage(summary, startupModel.modelFallbackMessage);\n\n\t\tconst interactiveMode = new InteractiveMode({\n\t\t\tagentConnection,\n\t\t\tdaemonSocketPath,\n\t\t\tuiServices: daemonUiServices,\n\t\t\tpromptStashStore,\n\t\t\tpromptStashSessionId: summary.sessionId,\n\t\t\tbindLocalSessionExtensions: false,\n\t\t\tmigratedProviders,\n\t\t\tmodelFallbackMessage: attachModelFallbackMessage,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tverbose: parsed.verbose,\n\t\t\t// Resumed/attached daemon sessions are part of the same fleet; left\n\t\t\t// arrow takes them to the agents view like any other session. The agents\n\t\t\t// view was not rendered here, so we intentionally leave\n\t\t\t// agentsViewOwnsStartupNotices unset and let the in-session fallback run.\n\t\t\treturnToAgentsView: !parsed.noSession,\n\t\t\tsessionDepth: summary.rlmDepth,\n\t\t\t// Direct launch has only the attached summary; the live+passive+saved\n\t\t\t// unified catalog index is not built until the agents view opens. Retained\n\t\t\t// child snapshots augment this running-child fallback inside chat.\n\t\t\tsessionHasChildren: summary.hasRunningRlmChildren === true,\n\t\t});\n\n\t\tawait preloadCodeHighlighter();\n\t\tprintTimings();\n\t\tconst interactiveResult = await interactiveMode.run();\n\t\tif (parsed.noSession) {\n\t\t\treturn;\n\t\t}\n\t\tconst returnedSummary = {\n\t\t\t...summary,\n\t\t\t...interactiveResult.source,\n\t\t\tid: interactiveResult.source.activeSessionId ?? summary.id,\n\t\t};\n\t\tconst initialScopeKey =\n\t\t\tinteractiveResult.type === \"scoped_agents_view\"\n\t\t\t\t? {\n\t\t\t\t\t\tsessionId: interactiveResult.source.sessionId,\n\t\t\t\t\t\tactiveSessionId: interactiveResult.source.activeSessionId,\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\tawait launchAgentsView(returnedSummary, initialScopeKey);\n\t\treturn;\n\t}\n\tif (useDaemonClient) {\n\t\tconst settingsManager = SettingsManager.create(sessionManager.getCwd(), agentDir);\n\t\tlet stdinContent: string | undefined;\n\t\tif (appMode !== \"rpc\" && appMode !== \"acp\") {\n\t\t\tstdinContent = await readPipedStdin();\n\t\t}\n\t\ttime(\"readPipedStdin\");\n\t\tconst { initialMessage, initialImages } = await prepareInitialMessage(\n\t\t\tparsed,\n\t\t\tsettingsManager.getImageAutoResize(),\n\t\t\tstdinContent,\n\t\t);\n\t\ttime(\"prepareInitialMessage\");\n\t\tinitTheme(settingsManager.getTheme(), false);\n\t\ttime(\"initTheme\");\n\n\t\tdaemonReady = (await awaitDaemonReady(daemonReady)).ready;\n\t\tlet connection: DaemonAgentConnection;\n\t\tlet summary: SessionSummary;\n\t\ttry {\n\t\t\t({ connection, summary } = await createDaemonClientConnection({\n\t\t\t\tsocketPath: daemonSocketPath,\n\t\t\t\tconfig: defaultSessionConfig,\n\t\t\t\tsessionPath: parsed.noSession ? undefined : sessionManager.getSessionFile(),\n\t\t\t\tcontinueRecent: parsed.continue,\n\t\t\t\tclientOwned: isClientOwnedDaemonSession(appMode, parsed.noSession),\n\t\t\t\tnoSession: parsed.noSession,\n\t\t\t\tsupportsExtensionUi: appMode === \"rpc\",\n\t\t\t}));\n\t\t} catch (error) {\n\t\t\tif (error instanceof SessionAlreadyActiveError || error instanceof DaemonSessionCreateError) {\n\t\t\t\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst diagnostics = summary.diagnostics ?? [];\n\t\treportDiagnostics(diagnostics);\n\t\tif (diagnostics.some((diagnostic) => diagnostic.type === \"error\")) {\n\t\t\tawait connection.dispose();\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!summary.model) {\n\t\t\tconsole.error(chalk.red(summary.modelFallbackMessage ?? formatNoModelsAvailableMessage()));\n\t\t\tawait connection.dispose();\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tprintTimings();\n\t\tif (appMode === \"rpc\") {\n\t\t\treturn await runRpcModeWithConnection(connection, parsed.rpcProtocolVersion!);\n\t\t}\n\t\tif (appMode === \"acp\") {\n\t\t\treturn await runAcpModeWithConnection(connection);\n\t\t}\n\t\tconst exitCode = await runPrintModeWithConnection(connection, {\n\t\t\tmode: toPrintOutputMode(appMode),\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialImages,\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\tlet runtime: AgentSessionRuntime;\n\ttry {\n\t\truntime = await createAgentSessionRuntime(createRuntime, {\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\tagentDir,\n\t\t\tsessionManager,\n\t\t\tsessionConfig: defaultSessionConfig,\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof SessionAlreadyActiveError) {\n\t\t\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tthrow error;\n\t}\n\tconst { services, session, modelFallbackMessage } = runtime;\n\tinstallOwnedSessionRecoveryTracking(runtime);\n\tconst { settingsManager, modelRegistry } = services;\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/daemon modes which use other transports\n\tlet stdinContent: string | undefined;\n\tif (appMode !== \"rpc\" && appMode !== \"acp\" && appMode !== \"daemon\") {\n\t\tstdinContent = await readPipedStdin();\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\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\tconst scopedModels = [...session.scopedModels];\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\" && appMode !== \"daemon\" && !session.model) {\n\t\tconsole.error(chalk.red(formatNoModelsAvailableMessage()));\n\t\tprocess.exit(1);\n\t}\n\n\tif (appMode === \"rpc\") {\n\t\tprintTimings();\n\t\tawait runRpcMode(runtime, parsed.rpcProtocolVersion!);\n\t} else if (appMode === \"acp\") {\n\t\tprintTimings();\n\t\tawait runAcpMode(runtime);\n\t} else if (appMode === \"interactive\") {\n\t\tif (explicitAgentsView || parsed.resume === true) {\n\t\t\tconsole.error(chalk.yellow(\"Warning: the agents view needs the daemon; opening a normal chat instead\"));\n\t\t}\n\t\tif (scopedModels.length > 0 && (parsed.verbose || !settingsManager.getQuietStartup())) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\tconst interactiveMode = new InteractiveMode({\n\t\t\tagentConnection: new InProcessAgentConnection(runtime),\n\t\t\tlocalSessionHost: createInteractiveModeLocalSessionHost(runtime),\n\t\t\tpromptStashStore: new ClientPromptStashStore(),\n\t\t\tpromptStashSessionId: session.sessionId,\n\t\t\tbindLocalSessionExtensions: true,\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\tawait preloadCodeHighlighter();\n\t\tprintTimings();\n\t\tawait interactiveMode.run();\n\t} else {\n\t\tprintTimings();\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});\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
@@ -36,7 +36,6 @@ import { formatMissingSessionCwdPrompt, getMissingSessionCwdIssue, MissingSessio
36
36
  import { canonicalSessionPath, SessionAlreadyActiveError } from "./core/session-lease.js";
37
37
  import { findMostRecentSessionForCwd, getDefaultSessionDir, SessionManager } from "./core/session-manager.js";
38
38
  import { SettingsManager } from "./core/settings-manager.js";
39
- import { isTelemetryEnabled } from "./core/telemetry.js";
40
39
  import { printTimings, resetTimings, time } from "./core/timings.js";
41
40
  import { runMigrations, showDeprecationWarnings } from "./migrations.js";
42
41
  import { isDaemonCatalogProcess, runDaemonCatalogProcess } from "./modes/daemon/daemon-catalog-process.js";
@@ -355,11 +354,13 @@ function buildSessionOptions(config, scopedModels, hasExistingSession, modelRegi
355
354
  }
356
355
  }
357
356
  if (!options.model && scopedModels.length > 0 && !hasExistingSession) {
358
- // Check if saved default is in scoped models - use it if so, otherwise first scoped model
357
+ // A model scope constrains choices; only restore an explicit saved selection.
359
358
  const savedProvider = settingsManager.getDefaultProvider();
360
359
  const savedModelId = settingsManager.getDefaultModel();
361
360
  const savedModel = savedProvider && savedModelId ? modelRegistry.find(savedProvider, savedModelId) : undefined;
362
- const savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : undefined;
361
+ const savedInScope = savedModel && (!config.provider || config.provider === savedModel.provider)
362
+ ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel))
363
+ : undefined;
363
364
  if (savedInScope) {
364
365
  options.model = savedInScope.model;
365
366
  // Use thinking level from scoped model config if explicitly set
@@ -367,13 +368,6 @@ function buildSessionOptions(config, scopedModels, hasExistingSession, modelRegi
367
368
  options.thinkingLevel = savedInScope.thinkingLevel;
368
369
  }
369
370
  }
370
- else {
371
- options.model = scopedModels[0].model;
372
- // Use thinking level from first scoped model if explicitly set
373
- if (!config.thinking && scopedModels[0].thinkingLevel) {
374
- options.thinkingLevel = scopedModels[0].thinkingLevel;
375
- }
376
- }
377
371
  }
378
372
  // Thinking level from CLI (takes precedence over scoped model thinking levels set above)
379
373
  if (config.thinking) {
@@ -438,7 +432,7 @@ function runtimeAutonomousConfigFromArgs(parsed) {
438
432
  : undefined,
439
433
  };
440
434
  }
441
- function runtimeConfigFromArgs(parsed, cwd, agentDir, sessionDir, appMode, telemetryDisabled) {
435
+ function runtimeConfigFromArgs(parsed, cwd, agentDir, sessionDir, appMode) {
442
436
  return {
443
437
  cwd,
444
438
  agentDir,
@@ -465,7 +459,6 @@ function runtimeConfigFromArgs(parsed, cwd, agentDir, sessionDir, appMode, telem
465
459
  autonomous: runtimeAutonomousConfigFromArgs(parsed),
466
460
  extensionFlagValues: parsed.unknownFlags.size > 0 ? Object.fromEntries(parsed.unknownFlags.entries()) : undefined,
467
461
  executionMode: appMode === "daemon" ? undefined : appMode,
468
- telemetryDisabled,
469
462
  // Serialized refine for print/json/rpc: the client's appMode is NOT
470
463
  // "daemon" here — it's "print", "json", or "rpc". The daemon worker
471
464
  // receives this flag via AgentSessionRuntimeConfig and uses it
@@ -481,7 +474,7 @@ export function resolveRuntimeSessionOptions(sessionOptions, runtimeSessionOptio
481
474
  return {
482
475
  requestTokenBudget: runtimeSessionOptions?.requestTokenBudget ?? sessionOptions.requestTokenBudget,
483
476
  contextMode: runtimeSessionOptions?.contextMode ?? sessionOptions.contextMode,
484
- model: runtimeSessionOptions?.model ?? sessionOptions.model,
477
+ model: runtimeSessionOptions?.model !== undefined ? runtimeSessionOptions.model : sessionOptions.model,
485
478
  thinkingLevel: runtimeSessionOptions?.thinkingLevel ?? sessionOptions.thinkingLevel,
486
479
  serviceTier: runtimeSessionOptions?.serviceTier ?? sessionOptions.serviceTier,
487
480
  scopedModels: runtimeSessionOptions?.scopedModels ?? sessionOptions.scopedModels,
@@ -504,6 +497,8 @@ export function resolveRuntimeSessionOptions(sessionOptions, runtimeSessionOptio
504
497
  rlmParentNodeId: runtimeSessionOptions?.rlmParentNodeId,
505
498
  rlmParentAgent: runtimeSessionOptions?.rlmParentAgent,
506
499
  rlmChildAdmission: runtimeSessionOptions?.rlmChildAdmission,
500
+ rlmSubagentCapacity: runtimeSessionOptions?.rlmSubagentCapacity,
501
+ rlmRootAdmission: runtimeSessionOptions?.rlmRootAdmission,
507
502
  semanticParentSessionId: runtimeSessionOptions?.semanticParentSessionId,
508
503
  semanticSpawnedByRequestId: runtimeSessionOptions?.semanticSpawnedByRequestId,
509
504
  subagentRuntimeHost: runtimeSessionOptions?.subagentRuntimeHost,
@@ -531,6 +526,12 @@ export function createDefaultRuntimeFactory(runtimeDefaultSessionConfig, extensi
531
526
  });
532
527
  const { services, sessionOptions, diagnostics } = prepared;
533
528
  const resolvedSessionOptions = resolveRuntimeSessionOptions(sessionOptions, runtimeSessionOptions);
529
+ let modelFallbackMessage;
530
+ if (resolvedSessionOptions.model === undefined) {
531
+ const startupModel = await resolvePreparedStartupModel({ prepared, sessionManager });
532
+ resolvedSessionOptions.model = startupModel.model ?? null;
533
+ modelFallbackMessage = startupModel.modelFallbackMessage;
534
+ }
534
535
  const created = await createAgentSessionFromServices({
535
536
  services,
536
537
  sessionManager,
@@ -544,7 +545,6 @@ export function createDefaultRuntimeFactory(runtimeDefaultSessionConfig, extensi
544
545
  // so it survives the daemon worker's appMode="daemon" context.
545
546
  serializedRefine: config.serializedRefine ?? false,
546
547
  executionMode: config.executionMode,
547
- telemetryDisabled: config.telemetryDisabled,
548
548
  // Only seed initial goal for top-level sessions (rlmDepth 0).
549
549
  initialGoal: (runtimeSessionOptions?.rlmDepth ?? 0) === 0 ? config.initialGoal : undefined,
550
550
  });
@@ -560,6 +560,7 @@ export function createDefaultRuntimeFactory(runtimeDefaultSessionConfig, extensi
560
560
  }
561
561
  return {
562
562
  ...created,
563
+ modelFallbackMessage: modelFallbackMessage ?? created.modelFallbackMessage,
563
564
  services,
564
565
  diagnostics,
565
566
  };
@@ -568,9 +569,7 @@ export function createDefaultRuntimeFactory(runtimeDefaultSessionConfig, extensi
568
569
  async function prepareRuntimeServices(options) {
569
570
  const { config, sessionManager } = options;
570
571
  const effectiveAgentDir = config.agentDir ?? options.agentDir;
571
- const authStorage = AuthStorage.create(join(effectiveAgentDir, "auth.json"), {
572
- usePrimeCliConfig: effectiveAgentDir === options.agentDir,
573
- });
572
+ const authStorage = AuthStorage.create(join(effectiveAgentDir, "auth.json"));
574
573
  const services = await createAgentSessionServices({
575
574
  cwd: options.cwd,
576
575
  agentDir: effectiveAgentDir,
@@ -579,7 +578,6 @@ async function prepareRuntimeServices(options) {
579
578
  // Subagents share the parent's Herdr pane; their own reporter would race
580
579
  // the parent's and a subagent quit would release the still-active pane.
581
580
  noBuiltinHerdrReporter: (options.sessionOptionsOverride?.rlmDepth ?? 0) > 0,
582
- telemetryDisabled: config.telemetryDisabled,
583
581
  resourceLoaderOptions: {
584
582
  additionalExtensionPaths: config.extensions,
585
583
  additionalSkillPaths: config.skills,
@@ -618,7 +616,7 @@ async function prepareRuntimeServices(options) {
618
616
  if (!effectiveSessionModel) {
619
617
  diagnostics.push({
620
618
  type: "error",
621
- message: "--api-key requires a model to be specified via --model, --provider/--model, or --models",
619
+ message: "--api-key requires an explicit model via --model or --provider/--model",
622
620
  });
623
621
  }
624
622
  else {
@@ -629,6 +627,7 @@ async function prepareRuntimeServices(options) {
629
627
  services,
630
628
  scopedModels,
631
629
  sessionOptions,
630
+ cliProvider: config.provider,
632
631
  cliThinkingFromModel,
633
632
  diagnostics,
634
633
  };
@@ -637,19 +636,28 @@ async function resolvePreparedStartupModel(options) {
637
636
  const { prepared, sessionManager } = options;
638
637
  const { modelRegistry, settingsManager } = prepared.services;
639
638
  const { context: existingSession, hasExistingSession } = await readSessionBootstrap(sessionManager, settingsManager.getCanonicalContextLimits(), { includeMessages: false });
640
- let model = prepared.sessionOptions.model;
639
+ let model = prepared.sessionOptions.model ?? undefined;
640
+ const cliProvider = prepared.cliProvider;
641
641
  let modelFallbackMessage;
642
642
  if (!model && hasExistingSession && existingSession.model) {
643
- const restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);
644
- if (restoredModel && modelRegistry.hasConfiguredAuth(restoredModel)) {
645
- model = restoredModel;
643
+ if (cliProvider && existingSession.model.provider !== cliProvider) {
644
+ return {
645
+ model: undefined,
646
+ modelFallbackMessage: `Saved model ${existingSession.model.provider}/${existingSession.model.modelId} does not match provider ${cliProvider}. Select a model.`,
647
+ };
646
648
  }
649
+ model = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);
647
650
  if (!model) {
648
- modelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;
651
+ modelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}. Select a provider and model.`;
649
652
  }
653
+ else if (!modelRegistry.hasConfiguredAuth(model)) {
654
+ modelFallbackMessage = `Model ${model.provider}/${model.id} needs authentication. Run /login.`;
655
+ }
656
+ return { model, modelFallbackMessage };
650
657
  }
651
658
  if (!model) {
652
659
  const result = await findInitialModel({
660
+ cliProvider,
653
661
  scopedModels: prepared.scopedModels,
654
662
  isContinuing: hasExistingSession,
655
663
  defaultProvider: settingsManager.getDefaultProvider(),
@@ -659,10 +667,12 @@ async function resolvePreparedStartupModel(options) {
659
667
  });
660
668
  model = result.model;
661
669
  if (!model) {
662
- modelFallbackMessage = formatNoModelsAvailableMessage();
663
- }
664
- else if (modelFallbackMessage) {
665
- modelFallbackMessage += `. Using ${model.provider}/${model.id}`;
670
+ const savedProvider = settingsManager.getDefaultProvider();
671
+ const savedModelId = settingsManager.getDefaultModel();
672
+ modelFallbackMessage =
673
+ savedProvider && savedModelId
674
+ ? `Could not restore model ${savedProvider}/${savedModelId}. Select a provider and model.`
675
+ : formatNoModelsAvailableMessage();
666
676
  }
667
677
  }
668
678
  return { model, modelFallbackMessage };
@@ -751,7 +761,6 @@ async function createDaemonClientConnection(options) {
751
761
  ownedSessionRecoveryConfig: options.clientOwned ? options.config : undefined,
752
762
  supportsExtensionUi: options.supportsExtensionUi,
753
763
  recoverDaemon: () => ensureInteractiveDaemonRunning(options.socketPath),
754
- telemetryDisabled: options.config.telemetryDisabled,
755
764
  });
756
765
  return { connection, summary };
757
766
  };
@@ -1009,11 +1018,7 @@ export async function main(args, options) {
1009
1018
  }
1010
1019
  }
1011
1020
  time("createSessionManager");
1012
- const telemetrySettingsManager = sessionManager.getCwd() === cwd
1013
- ? startupSettingsManager
1014
- : SettingsManager.create(sessionManager.getCwd(), agentDir);
1015
- const telemetryDisabled = isTelemetryEnabled(telemetrySettingsManager) ? undefined : true;
1016
- const defaultSessionConfig = runtimeConfigFromArgs(parsed, sessionManager.getCwd(), agentDir, sessionDir, appMode, telemetryDisabled);
1021
+ const defaultSessionConfig = runtimeConfigFromArgs(parsed, sessionManager.getCwd(), agentDir, sessionDir, appMode);
1017
1022
  // Verifier/headless clients pass initialGoal in each create request. The long-lived
1018
1023
  // daemon fallback must not seed that goal into unrelated future sessions.
1019
1024
  const daemonDefaultSessionConfig = daemonServerDefaultSessionConfig(defaultSessionConfig);